Repository navigation
Thread-aware tier routing and mid-turn escalation (#663) - #674
Open
rockfordlhotka wants to merge 1 commit into
Open
rockfordlhotka wants to merge 1 commit into
rockfordlhotka wants to merge 1 commit into
Conversation
) Production (2026-10-09): 22 of 26 user turns in a deck/research session went to Low, and those Low turns did the damage (answered research from prior knowledge, rewrote a file from a partial read). Keyword scoring saw only the message text. Thread-aware tier floor (KeywordTierSelector, user messages only): - Active-thread floor: on an established thread any non-trivial follow-up routes at least Balanced. The 30-char length gate (which a 34-char "figure out a way to update the doc" slipped past) and the matched-high-keyword gate are gone. - Inherited tier: a turn routes at least the highest tier the session's last 3 turns earned on their own (30-min recency). New SessionTierHistory singleton (bounded, expiring, thread-safe, in-memory) records each turn's IntrinsicTier so inheritance decays instead of perpetuating itself; mid-turn escalations raise the turn's entry; subagent results record Balanced; ClearContext resets. - Active-subagent floor: Balanced while the session has a running subagent. - Research-question floor: a question naming a technical subject (acronym, version, spec/protocol/API word) lifts Low to Balanced; trivia does not. - Pure acknowledgements/greetings ("thanks", "ok", "got it", emoji) are exempt from the floors and may stay Low (ConversationalSignals.IsTrivialAck). Low-signal research guard: "what is", "what's", "tell me about", "look up", "show me", "i think", "i was thinking" removed from the compiled low signals, and a compiled retired set filters them (plus "what are") from the merged list even when the hot-reloaded tier-selector.json names them, with a warning. Mid-turn escalation: AgentLoopRunner.RunAsync(allowTierEscalation) binds a per-run TierEscalationContext for Low runs. A side-effecting tool call (verb in the tool name, inner tool_name for mcp_invoke_tool; agent bookkeeping exempt — ToolSideEffects) or 2 tool errors escalates to Balanced. The text loop and outer native calls request EffectiveTier(tier); inside a native FICC loop that started on Low, TierEscalatingChatClient (wired under the Low tier's FICC) redirects the remaining iterations to the Balanced client. Logs "Tier escalated Low→Balanced mid-turn: <reason>". UserMessageHandler opts in unless LLM:FixedTier pins the tier. Explainable routing: TierClassification.Rule (TierRoutingRules), logged as rule= with recentMaxTier/activeSubagent; TierRoutingEntry gains RoutingRule, EscalatedTier, EscalationReason (additive, optional). routing-dream.md and docs/agent-host.md describe the new rules and the retired low signals. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This was referenced Oct 9, 2026
This branch has not been deployed
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Closes #663. Part of #671.
Problem
In a 30-minute interactive work session, 22 of 26 user turns went to Low (
gpt-5.4-mini). Two examples:The Low turns did the destructive work. High was never used.
Changes
KeywordTierSelector):ConversationalSignals.IsTrivialAck: "ok", "thanks", 👍…). The 30-character limit is gone.SessionTierHistory). The history stores each turn's own tier, so an inherited High fades.tier-selector.jsonat load, with a warning, so dream tuning can't bring them back.RunAsync(allowTierEscalation: true).ToolSideEffectsclassifies by the verb in the tool name, including the inner tool name ofmcp_invoke_tool) or 2 tool errors, the rest of the loop runs on Balanced. Native path:TierEscalatingChatClientwraps Low's inner client. Text path: the effective tier is chosen per iteration.Tier escalated Low→Balanced mid-turn: <reason>.rule=appears on the routing log line and is recorded inTierRoutingEntry(additive fields).routing-dream.mdanddocs/agent-host.mdare updated so the routing dream doesn't fight the thread rules.Deploy note
Copy the PVC file
/data/agent/routing-dream.mdover from the seed; init only seeds files that are missing. Notier-selector.jsonchange is needed.Tests
New:
ThreadAwareTierRoutingTests, which includes a replay of the production session's messages, plusConversationalSignalsTests,SessionTierHistoryTests,TierEscalationTestsandTierEscalationEndToEndTests(the realAgentLoopRunner, native and text paths). Some existingKeywordTierSelectorTestsrows were updated for the new rules. Full suite: 0 failures.🤖 Generated with Claude Code