- Pass recent history to classify_query for context-aware routing
- Add multi-turn continuation rules to ROUTER_PROMPT
- Add deterministic _rescue_classification guardrail for active sessions
- Increase max_tokens in router (1500) and agent loop (3500) to prevent thinking tag cutoffs
- Add unit test coverage for multi-turn and continuation classification
feat(alerts): add Pulse AI double opt-in alert subscriptions system
- Add 10 alert criteria types with RPC-based evaluation and 24h rolling cooldown
- Implement pluggable email service with Gmail SMTP and unsubscribe links
- Add ALERT_SUBSCRIPTION query classification and isolated 2-tool resolution
- Add confirmation, unsubscribe, and internal evaluate API routes
- Add background evaluator, digest sender, and cleanup workers
- Add comprehensive test suite with 45 unit tests and 44 simulated tool tests
refactor(core): reduce cyclomatic complexity to <=10, enforce <=500 lines per file, apply comment discipline, and add 22-tool test suite
- Added explicit anti-repetition constraint in Rule 5 of services/prompts.py.
- Updated services/tool_executor.py suggest_actions return message to instruct model not to write manual links.
- Added _clean_reply_text() sanitizer in services/agent_loop.py to strip any stray dummy action links from synthesized text.
1. Supabase RPC 1:1 Parameter Alignments:
- Aligned all tool schemas in services/tools.py to match exact SQL DDL signatures from all_rpcs.sql.
- Added robust parameter normalization and unknown-parameter stripping in services/supabase_service.py to eliminate PGRST202 schema errors.
2. Context-Enriched Semantic Discovery:
- Enhanced discover_tools() for short queries (e.g. 'Miami') to include previous conversation turn context, accurately retrieving get_market_snapshot.
3. Conversational Tool Carryover:
- Updated forced synthesis to prompt the LLM to invoke suggest_actions for any uncompleted multi-step workflows (e.g. export reports, property comparisons, deep volatility dives).
1. Model Tier Mapping:
- Configured GROQ_ROUTE_MODEL='openai/gpt-oss-20b' and GROQ_FALLBACK_ROUTE_MODEL='groq/compound-mini'.
- Configured GROQ_SYNTHESIS_MODEL='openai/gpt-oss-120b' and GROQ_FALLBACK_SYNTHESIS_MODEL='qwen/qwen3.6-27b'.
2. Router Category Gating:
- Updated ROUTER_PROMPT to output 'tool_categories' alongside route classification.
- Wired classify_query() to return (classification, tool_categories) and passed categories into discover_tools().
3. Universal suggest_actions across ALL Routes:
- Attached SUGGEST_ACTIONS_TOOL to PATH_B and all active routes.
- Tested live PATH_B execution: zero JSON code fences leaked, suggest_actions invoked natively.
1. Tool-Set Pruning:
- Replaced full 18-tool array (~3,130 tokens) on every call with intent-based subsets (5-7 tools = ~700-900 tokens).
- Added select_tools(query) covering MARKET_TOOLS, ANOMALY_TOOLS, PROPERTY_TOOLS, and GEO_TOOLS.
- All subsets include generate_data_export.
2. Synthesis Tool Stripping & Dynamic Token Budget:
- Tool-call rounds send selected tools with max_tokens=300 (tool JSONs are small).
- Synthesis round strips all tools completely (saving 3,130 tokens on final generation) and raises max_tokens to 2,000 to prevent report truncation (resolves finish_reason='length').
3. Session History Fact Compression:
- Implemented _compress_for_history() to store factual text summaries in session history while delivering full rich markdown tables to users.
- Saves ~85% history tokens per turn.
4. Hard Cap on Tool Result Payloads:
- Lowered max returned rows from 50 to 30 and enforced a 2,000-character ceiling per tool result in compress_tool_output()…
fix: router - remove response_format for Qwen thinking model compatibility
qwen/qwen3.6-27b rejects response_format={'type':'json_object'} with
a 400 json_validate_failed error, causing both primary and fallback
router calls to fail and always defaulting to PATH_A.
Fixes:
- Remove response_format from groq_call in classify_query()
- Add _extract_json_from_text() to handle:
* <think>...</think> blocks that Qwen prepends to output
* Regex fallback extraction if json.loads fails
- Increase router max_tokens 80 -> 500 to allow full thinking output
- Add _VALID_CLASSIFICATIONS guard to catch garbage model outputs
- Config: qwen/qwen3.6-27b set as route model (user preference)
- Restructured repository to clean production FastAPI package layout
- Moved research docs, scratch scripts, and legacy routes to misc/
- Added COMMERCIAL_TOOLS with generate_contact_buttons for dynamic handoffs
- Configured direct file downloads (/download endpoint) in Appwrite storage
- Fixed middleware compression to preserve tool payload output for python tools
- Updated requirements.txt and verified test suite