Router accepts mismatched subagent model tags and strips user text
Nobody has claimed this yet.
- Dominant language
- TypeScript
- Stars
- 4k
- Forks
- 453
- Avg merge
- 12h 30m
- Merged PRs (30d)
- 46
Description
Summary
The router subagent tag parser accepts malformed tags whose opening and closing tag families do not match. For example, <ccr-subagent-model>...</pilotdeck-subagent-model> is currently treated as a valid control tag.
This can silently turn ordinary user-provided text into router control input: detectSubagent marks the request as a subagent request and extracts a model hint, while stripSubagentTagFromMessages removes the malformed text from the user message.
Code path
src/router/scenario/subagentDetector.ts:3definesSUBAGENT_TAG_PATTERNwith independent alternations for the opening and closing tag families.src/router/scenario/subagentDetector.ts:17uses the regex indetectSubagentand setstaggedInUserMessage,modelHint, andisSubagent.src/router/scenario/subagentDetector.ts:53uses the same regex instripSubagentTagFromMessagesand removes the matched text.src/router/scenario/decideScenario.ts:26consumes the detection result for router scenario selection.src/router/RouterRuntime.ts:510enables subagent tag stripping when the decision is considered a subagent request.
Steps to reproduce
Tested against local HEAD dbb2b416.
From the repository root:
node --import tsx --input-type=module <<'NODE'
import {
detectSubagent,
stripSubagentTagFromMessages,
} from './src/router/scenario/subagentDetector.ts';
const messages = [
{
role: 'user',
content: [
{
type: 'text',
text: '<ccr-subagent-model>openai/gpt-4o</pilotdeck-subagent-model> explain this markup',
},
],
},
];
const tools = [{ name: 'agent', inputSchema: {} }];
console.log(JSON.stringify(detectSubagent(messages, tools, true)));
console.log(JSON.stringify(stripSubagentTagFromMessages(messages)[0].content[0].text));
NODE
Current output:
{"isSubagent":true,"modelHint":"openai/gpt-4o","missingAgentTool":false,"taggedInUserMessage":true}
" explain this markup"
Expected behavior
Only same-family tag pairs should be accepted as router control tags, for example:
<pilotdeck-subagent-model>...</pilotdeck-subagent-model>
<ccr-subagent-model>...</ccr-subagent-model>
A cross-family pair should be ignored by detectSubagent and preserved by stripSubagentTagFromMessages:
<ccr-subagent-model>...</pilotdeck-subagent-model>
Actual behavior
The cross-family pair is accepted as valid. This causes:
detectSubagentto returnisSubagent: trueandtaggedInUserMessage: truefor malformed user text;modelHintto be extracted from the malformed tag body;stripSubagentTagFromMessagesto delete text that was not a valid control tag.
Existing coverage
I searched existing issues for subagentDetector, subagent-model, cross-family, and malformed subagent. The only nearby matches were subagent configuration issues (#247 and #248), which do not cover this tag parser behavior.
Suggested fix
Bind the closing tag family to the opening tag family, for example with a backreference:
const SUBAGENT_TAG_PATTERN =
/<(pilotdeck|ccr)-subagent-model>([\s\S]+?)<\/\1-subagent-model>/i;
With that shape, the model hint capture would move from match[1] to match[2].
Suggested tests
- same-family
pilotdecktags are detected and stripped; - same-family
ccrtags are detected and stripped; - cross-family tags are not detected as subagent control tags;
- cross-family tags are preserved by
stripSubagentTagFromMessages; - ordinary user text containing malformed XML-like snippets is not silently removed.
Submitted with Codex.
Contributor guide
No contributing guide indexed for this repository
First steps
- Read the whole issue, then the project's contributing guide.
- Comment on the issue to say you are picking it up — it saves two people doing the same work.
- Fork the repository and make your change on a branch.
- Open a pull request that references the issue number.
Research direction
Start in src/router/scenario/subagentDetector.ts, especially SUBAGENT_TAG_PATTERN and the detectSubagent and stripSubagentTagFromMessages call sites. Run the reproduction from the issue, then add coverage for same-family detection and stripping, cross-family rejection and preservation, and malformed XML-like text. Done means only matching tag families affect router control input.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- typescript
- Domain
- backend
- Issue type
- Bug
- Difficulty
- 2/5
- Estimated time
- 1-3 hours
- Activity status
- Quiet
- Clarity
- Clearly specified
- Newbie friendliness
- 84/100