Skip to content

fix: prevent system-injected content from becoming agent display name - #61

Merged
patoles merged 4 commits into
patoles:mainfrom
mirland:feat/fix-system-instruction-agent-name
Jul 11, 2026
Merged

fix: prevent system-injected content from becoming agent display name#61
patoles merged 4 commits into
patoles:mainfrom
mirland:feat/fix-system-instruction-agent-name

Conversation

@mirland

@mirland mirland commented Jul 7, 2026

Copy link
Copy Markdown
Contributor

Sessions starting with system-injected content (e.g. Conductor's <system_instruction>) had their agent node and session label set to the injected text instead of the actual user prompt.

Added <system_instruction>, <task-notification>, <local-command-stdout>, and <local-command-caveat> to SYSTEM_CONTENT_PREFIXES in extension/src/constants.ts. The extension-side isSystemInjectedContent already gates all message emission, so no web-side filtering was needed. Updated the doc comment to clarify that extractCodexUserText also consults this list.

mirland added 2 commits July 7, 2026 12:59
When Conductor injects <system_instruction> as the first user message,
the main agent node was renamed to '<system_inst...' instead of waiting
for the actual user prompt. Added system content prefix filtering to the
web rename logic and added <system_instruction> and <task-notification>
to the extension-side SYSTEM_CONTENT_PREFIXES list.

@patoles patoles left a comment

Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks for another one! Good catch on the root cause. The constants.ts change looks right to me; my comments are mostly about the web half and a couple of edge cases.

1. I'd drop the web-side hunk (or gate the whole message, not just the rename)

Once the extension list includes the new prefixes, a message starting with any of them can never reach handleMessage: every emit site in transcript-parser.ts (lines 163, 217, 532, 546) and codex-rollout-parser.ts:220 filters through isSystemInjectedContent first, the relay and standalone app bundle that same parser, and the webview ships inside the VSIX with the extension, so there's no version-skew window. The duplicated list guards an unreachable path, and the "keep in sync" comment becomes a permanent two-file chore that nothing enforces.

It's also only a partial guard as written: the check wraps the rename block, but the same content would still flow into the canvas bubble push and appendConversation a few lines down, plus the timeline label. So in the only hypothetical where the web check fires, you'd get a clean node name next to a giant <system_instruction> bubble.

My suggestion: make the PR extension-only. If you'd like web-side defense-in-depth anyway, an early return at the top of handleMessage (skipping the whole message) would be consistent with the extension's semantics of "this is not a real user message".

2. Two more prefixes would close the same bug class

I checked real transcripts on my machine: user entries starting with <local-command-stdout> and <local-command-caveat> exist at position 0 and aren't in the list. A session whose first user turn is a slash command (e.g. /model) still gets renamed to <local-command-stdout>Set mo..., which is the exact bug you're fixing. Since you're in this file already, adding those two entries would be great.

3. One side effect to confirm: task notifications disappear from the chat feed

Because isSystemInjectedContent gates emission entirely, <task-notification> user entries (background-task completion notices) will no longer appear in the conversation panel or catch-up replay at all, and their tokens stop counting in the live context breakdown. That's probably fine as noise reduction, but it goes beyond the display-name fix described in the PR, and it means the assistant's next turn can look unprompted in the feed. Just want to make sure that's intentional rather than incidental.

4. Two questions about the Conductor case

  • If Conductor wraps the real task inside <system_instruction> and never sends a bare user message, the session now keeps the generic Session <id> label and "orchestrator" node forever (before, the label was ugly but at least distinguishable). The Codex parser handles the analogous situation by extracting the real prompt from inside the wrapper (the ## My request for Codex: marker). Does Conductor put the user's task inside the block? If so, extracting it might serve better than skipping.
  • Could you paste a sample transcript line showing the tag? Nothing in the repo confirms the exact <system_instruction spelling (underscore, lowercase), and no test covers SYSTEM_CONTENT_PREFIXES at all. A small fixture-based test with your real sample would lock the fix in against future edits.

5. Tiny one

The doc comment above SYSTEM_CONTENT_PREFIXES says the list is "for Claude Code. Codex has its own extraction", but extractCodexUserText consults this list too, so additions widen Codex filtering as well (benign here). Worth a small comment update while you're there so the next person has the right mental model.


To be clear, item 1 plus the two extra prefixes are the only changes I'd ask for; the rest are confirmations and nice-to-haves. Thanks again!

mirland and others added 2 commits July 11, 2026 11:57
Reverted the web-side SYSTEM_CONTENT_PREFIXES in handle-message-events.ts
since extension-side isSystemInjectedContent already filters system
messages before they reach the web handler (unreachable code path).

Added <local-command-stdout> and <local-command-caveat> to the
extension-side SYSTEM_CONTENT_PREFIXES — these appear at position 0 in
transcripts when a session starts with a slash command.

Updated the doc comment to clarify that extractCodexUserText also
consults this list, so additions affect both runtimes.
@mirland

mirland commented Jul 11, 2026

Copy link
Copy Markdown
Contributor Author

It makes totally sense! Thanks for the review!

@patoles
patoles merged commit 259872f into patoles:main Jul 11, 2026
2 checks passed
@patoles

patoles commented Jul 11, 2026

Copy link
Copy Markdown
Owner

Merged, thanks for the quick turnaround and for going with the extension-only approach! This will ship with the next release.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants