From f57d0e2c817bb6a6a14680e70f423a7519d95932 Mon Sep 17 00:00:00 2001 From: Anthony Stirling <77850077+Frooodle@users.noreply.github.com> Date: Wed, 2 Sep 2026 09:57:53 +0100 Subject: [PATCH] fix(engine): teach the router with examples and pin its sampling --- engine/.env | 2 +- engine/src/stirling/agents/orchestrator.py | 29 ++++++++++++++++++++-- 2 files changed, 28 insertions(+), 3 deletions(-) diff --git a/engine/.env b/engine/.env index 1a90ad8c18..e2c07b9e14 100644 --- a/engine/.env +++ b/engine/.env @@ -12,7 +12,7 @@ STIRLING_FAST_MODEL=anthropic:claude-haiku-4-5 # Default output token limits applied by the engine for each model tier. STIRLING_SMART_MODEL_MAX_TOKENS=8192 -STIRLING_FAST_MODEL_MAX_TOKENS=2048 +STIRLING_FAST_MODEL_MAX_TOKENS=4096 # Process-wide cap on concurrent model API calls, shared by both model tiers. # Per-request fan-outs (chunked reasoner workers, contradiction detection) are diff --git a/engine/src/stirling/agents/orchestrator.py b/engine/src/stirling/agents/orchestrator.py index bb7f2682df..684e0a37da 100644 --- a/engine/src/stirling/agents/orchestrator.py +++ b/engine/src/stirling/agents/orchestrator.py @@ -7,6 +7,7 @@ from typing import Literal, assert_never from pydantic import ConfigDict, Field from pydantic_ai import Agent from pydantic_ai.output import NativeOutput, ToolOutput +from pydantic_ai.settings import ModelSettings from pydantic_ai.tools import RunContext from stirling.agents.output_mode import output_retries, uses_tool_output @@ -65,10 +66,34 @@ _ROUTER_SYSTEM_PROMPT = ( "- pdf_create: generate a NEW document from scratch (invoice, report, letter) - no input file.\n" "- unsupported: none of the above fit, or the user asks about the assistant itself; put a " "helpful message in 'message'.\n" - "Respond with the capability and (only for unsupported) a message." + "Respond with the capability and (only for unsupported) a message.\n" + "\n" + "Decide by what the user wants BACK, not by which PDF words appear in the message. " + "Wanting an answer, or information read out of the document, is pdf_question. Wanting a " + "changed file handed back is pdf_edit. A document being mentioned is not a request to act " + "on it.\n" + "\n" + "Examples:\n" + ' "How long is the notice period?" -> pdf_question\n' + ' "Shorten the notice period to 30 days" -> pdf_edit\n' + ' "Is there a table of contents?" -> pdf_question\n' + ' "Add a table of contents" -> pdf_edit\n' + ' "Does it say anything about encryption?" -> pdf_question\n' + ' "Encrypt this file" -> pdf_edit\n' + ' "What sections cover the merger?" -> pdf_question\n' + ' "Combine these into one file" -> pdf_edit\n' + ' "Tell me if the numbers add up" -> pdf_question\n' + ' "Put a note on every paragraph that needs work" -> pdf_review\n' + ' "Build me a purchase order from scratch" -> pdf_create\n' + ' "Make a rule that stamps every upload" -> user_spec\n' + ' "Which version of the app is this?" -> unsupported' ) +def _router_model_settings(runtime: AppRuntime) -> ModelSettings: + return {**runtime.fast_model_settings, "temperature": 0.0} + + class OrchestratorAgent: def __init__(self, runtime: AppRuntime) -> None: self.runtime = runtime @@ -146,7 +171,7 @@ class OrchestratorAgent: output_type=NativeOutput([_RouteDecision]), retries=output_retries(runtime.settings.chat_provider), system_prompt=_ROUTER_SYSTEM_PROMPT, - model_settings=runtime.fast_model_settings, + model_settings=_router_model_settings(runtime), ) if self._route_via_enum else None