Skip to content

fix(orchestrator): Skip blank subagent opening messages - #5456

Open
mwolson wants to merge 2 commits into
pingdotgg:t3code/codex-turn-mappingfrom
mwolson:fix/claude-subagent-empty-prompt-message
Open

fix(orchestrator): Skip blank subagent opening messages#5456
mwolson wants to merge 2 commits into
pingdotgg:t3code/codex-turn-mappingfrom
mwolson:fix/claude-subagent-empty-prompt-message

Conversation

@mwolson

@mwolson mwolson commented Aug 5, 2026

Copy link
Copy Markdown
Contributor

Carried from another PR

  • fix(orchestration): Preserve Claude subagent attribution after settle
    carried for #5388 claude-postsettle-attribution.
    Review it there, not here.
  • fix(orchestrator): Skip blank subagent opening messages — this PR.

Summary

  • Stop provider-native subagent child threads from opening with an empty or
    whitespace-only user message under the "Sent by another agent" label.
  • Gate every subagent opening message with a shared trim-aware check, and emit
    Claude's opening message the first time the task prompt has real text rather
    than on first registration.
  • One unique commit above fix(orchestration): Preserve Claude subagent attribution after settle #5388 claude-postsettle-attribution on
    t3code/codex-turn-mapping.

Problem and Fix

Problem and Why it Happened Fix
A Claude Agent launch whose prompt is whitespace-only still produced a child user message. The Agent tool accepts it, task_started carries it, and the emission site had no emptiness guard, so the web timeline rendered an empty bubble. Shared hasSubagentPromptText trims before deciding. Every makeSubagentConversationArtifacts caller with role: "user" goes through it (Claude, Codex, Cursor, ACP).
A task_progress frame can register a Claude subagent before any prompt-bearing frame. Registration fell back to prompt: input.prompt ?? "", and the opening message was tied to first registration, so it was emitted as "" and never rewritten when a later task_started supplied the real prompt. Claude emits the opening message when hasSubagentPromptText(task.prompt) && !hasSubagentPromptText(priorTask?.prompt), so a late prompt still opens the child exactly once and a prompt change from one non-empty value to another does not re-emit.
Codex only checked input.prompt.length > 0, which still admits whitespace. Cursor and ACP had no guard. Codex's length check is replaced by the shared predicate; Cursor and ACP pick up the same gate.

Validation

  • New replay fixture claude_subagent_empty_prompt covers both routes (whitespace Agent prompt and task_progress before task_started). Confirmed fail before the emission fix and pass after.
  • Replay suites (OrchestratorReplayFixtures.integration / .contract, ClaudeReplayFixtures.integration, CodexReplayFixtures.integration): 89 tests, 1 skipped.
  • Adapter and projection suites (Claude, Claude testkit, Codex, Cursor, Cursor testkit, ACP, ACP registry, Grok, SubagentProjection): 274 tests.
  • vp check: passed.
  • vp run typecheck: passed all 15 packages.
  • Isolated private serve live check against this branch: a whitespace Agent launch produced a completed subagent row with prompt: " " and a child thread with no user message; a sibling ordinary-prompt child held exactly one :prompt message. Zero trim-empty user-role projection messages in the isolated DB.

Checklist

  • This PR is small and focused
  • I explained what changed and why
  • I included before/after screenshots for any UI changes (not applicable: server-side projection only)
  • I included a video for animation/interaction changes (not applicable)

Note

Low Risk
Server-side projection-only change with a narrow guard; low risk to auth, data, or core runtime paths.

Overview
Subagent child threads no longer get an opening user message when the task prompt is empty or whitespace-only, avoiding empty “Sent by another agent” bubbles in the timeline.

A shared hasSubagentPromptText (trim-aware) gates makeSubagentConversationArtifacts for user-role opening messages across provider adapters. In this diff, ACP only emits message.updated / turn_item.updated for the :prompt item when update.prompt has real text after trim.

Related adapter behavior (same PR): Claude defers the opening message until the first frame with non-empty prompt (not first registration); Codex drops a raw length check in favor of the shared helper; Cursor and ACP gain the same guard.

Reviewed by Cursor Bugbot for commit 0e1b4fe. Bugbot is set up for automated code reviews on this repo. Configure here.

mwolson added 2 commits August 5, 2026 11:45
A provider-native subagent could open its child thread with an empty or
whitespace-only user message, which renders as an empty bubble under the
"Sent by another agent" label. The Claude adapter emitted the opening
prompt whenever the subagent was new, and a task_progress frame can
register a subagent before any frame carries its prompt, so the message
was emitted with the "" default and never rewritten when the real prompt
arrived on a later task_started.

A shared hasSubagentPromptText guard now gates every subagent opening
message. The Claude adapter emits it the first time the task prompt
actually has text rather than on first registration, so a late prompt
still opens the child thread exactly once. Codex's existing length check
becomes trim-aware, and Cursor and ACP pick up the same guard.
@coderabbitai

coderabbitai Bot commented Aug 5, 2026

Copy link
Copy Markdown

Important

Review skipped

Auto reviews are disabled on this repository. Please check the settings in the CodeRabbit UI or the .coderabbit.yaml file in this repository. To trigger a single review, invoke the @coderabbitai review command.

⚙️ Run configuration

Configuration used: Repository UI

Review profile: CHILL

Plan: Pro Plus

Run ID: 780c5d1e-0f63-4320-a3ce-9608ba6976d1

You can disable this status message by setting the reviews.review_status to false in the CodeRabbit configuration file.

Use the checkbox below for a quick retry:

  • 🔍 Trigger review

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@github-actions github-actions Bot added vouch:unvouched PR author is not yet trusted in the VOUCHED list. size:XXL 1,000+ changed lines (additions + deletions). labels Aug 5, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

size:XXL 1,000+ changed lines (additions + deletions). vouch:unvouched PR author is not yet trusted in the VOUCHED list.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant