fix(ai-orchestrator): ensure /query re-routes via mesh router before active persona#141
Merged
Merged
Conversation
…active persona - Replace START → routeByRecipient conditional edge with a deterministic START → mesh_router edge in the LangGraph topology. Every graph entry now passes through mesh_router first, so /query commands are classified before any persona executes. - Add pause_context: null to graph.invoke() in handleQuery so a mesh_stalemate (or any other pause) is cleared when a new question arrives, preventing the graph from routing immediately to __pause__. - Update query.spec.ts to assert the new behaviour: pause_context is always explicitly null in the invoke payload. - Add graph.spec.ts topology test: START → mesh_router reclassifies next_recipient before persona executes (qa → po scenario). Closes #140
|
The latest updates on your projects. Learn more about Vercel for GitHub. 1 Skipped Deployment
|
Contributor
There was a problem hiding this comment.
Pull request overview
Refactors the LangGraph topology in libs/ai-orchestrator so every graph entry deterministically flows through mesh_router first, aiming to prevent /query executions from dispatching directly to the currently-active persona and to avoid the reported Anthropic “assistant prefill” error patterns.
Changes:
- Updates the orchestrator graph topology to route
START → mesh_routerdeterministically before any persona dispatch. - Updates
/queryto explicitly clearpause_contextin thegraph.invoke()payload so paused threads don’t immediately route to__pause__. - Adds/updates unit tests to validate the new start-routing topology and the new
/queryinvocation payload behavior.
Reviewed changes
Copilot reviewed 4 out of 20 changed files in this pull request and generated 2 comments.
Show a summary per file
| File | Description |
|---|---|
| libs/ai-orchestrator/src/orchestrator/langgraph.ts | Changes graph topology to ensure START always routes through mesh_router before dispatch. |
| libs/ai-orchestrator/src/tests/graph.spec.ts | Adds a topology test intended to ensure mesh_router executes before persona dispatch on entry. |
| apps/webhook-listener/src/commands/query.ts | Passes pause_context: null when invoking the graph for /query, intending to force re-routing via mesh_router. |
| apps/webhook-listener/src/commands/query.spec.ts | Updates tests to assert /query always passes pause_context: null. |
| logs/webhook-listener-out-0.log | Log artifact included in PR metadata (cleanup/untracking implied). |
| logs/webhook-listener-out-1.log | Log artifact included in PR metadata (cleanup/untracking implied). |
| logs/webhook-listener-out-2.log | Log artifact included in PR metadata (cleanup/untracking implied). |
| logs/webhook-listener-out-3.log | Log artifact included in PR metadata (cleanup/untracking implied). |
| logs/webhook-listener-out-4.log | Log artifact included in PR metadata (cleanup/untracking implied). |
| logs/webhook-listener-out-5.log | Log artifact included in PR metadata (cleanup/untracking implied). |
| logs/webhook-listener-out-6.log | Log artifact included in PR metadata (cleanup/untracking implied). |
| logs/webhook-listener-out-7.log | Log artifact included in PR metadata (cleanup/untracking implied). |
| logs/webhook-listener-error-0.log | Removes tracked error log contents (cleanup). |
| logs/webhook-listener-error-1.log | Removes tracked error log contents (cleanup). |
| logs/webhook-listener-error-2.log | Removes tracked error log contents (cleanup). |
| logs/webhook-listener-error-3.log | Removes tracked error log contents (cleanup). |
| logs/webhook-listener-error-4.log | Removes tracked error log contents (cleanup). |
| logs/webhook-listener-error-5.log | Removes tracked error log contents (cleanup). |
| logs/webhook-listener-error-6.log | Removes tracked error log contents (cleanup). |
| logs/webhook-listener-error-7.log | Removes tracked error log contents (cleanup). |
…est title - Update query.ts comment to acknowledge that mesh_router currently returns null for generic queries (only classified when directed at specific persona). Add note about future improvement: update MESH_SYSTEM_PROMPT to classify generic queries to most appropriate persona. - Rename graph.spec.ts test title from 'on invoke' to 'on run' to accurately reflect which API the test uses. Clarify why run() is needed (vs invoke()).
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.
Summary
Fixes routing bias and Anthropic 400 prefill errors caused by
/querycommands bypassing the mesh router entirely.Previously,
STARTused a conditional edge that dispatched directly tonext_recipient(the currently active persona). If that persona wasa11y(Claude 4.6), it would answer the question before the mesh router had a chance to reclassify it — and the assistant-prefill error would fire because the last message in history was from a previous mesh router run.This PR refactors the graph topology to route
START → mesh_routerdeterministically. Every graph entry now passes through query classification first. The mesh router's heuristic gate (skips LLM when no?or@isolate-in message) keeps the performance cost negligible for routine linear workflows.Closes #140
Changes
libs/ai-orchestrator/src/orchestrator/langgraph.ts: ReplaceaddConditionalEdges(START, routeByRecipient, routeMap)withaddEdge(START, 'mesh_router'). The existingmesh_router → routeByRecipientconditional edge remains unchanged, so post-persona routing is unaffected.apps/webhook-listener/src/commands/query.ts: Addpause_context: nullto thegraph.invoke()payload inhandleQuery. This clears any active stalemate pause so the graph routes through mesh_router instead of immediately hitting__pause__.libs/ai-orchestrator/src/__tests__/graph.spec.ts: New topology test — start withnext_recipient: 'qa'and a query message; mock LLM reclassifies to'po'; assertqais never visited (proves mesh_router ran before dispatch).apps/webhook-listener/src/commands/query.spec.ts: Replace two stale tests that assertedpause_contextis NOT cleared with updated tests that assert the new behaviour (pause_context: nullis always passed explicitly).Copilot Review Triage
Before opening the PR, confirm each tier has been addressed:
run()vsinvoke()architectural distinction documented in the new test comment. No regressions in existing mesh router, persona, or checkpoint tests.query.spec.tstests replaced with tests that capture the correct new behaviour and reference issue fix: ensure /query re-routes via mesh router before executing currently active persona #140.Deferred follow-ups
None