Skip to content

fix(web): suppress Task tool prompt text from leaking into chat#372

Open
hqhq1025 wants to merge 2 commits intotiann:mainfrom
hqhq1025:fix/task-prompt-text-leak
Open

fix(web): suppress Task tool prompt text from leaking into chat#372
hqhq1025 wants to merge 2 commits intotiann:mainfrom
hqhq1025:fix/task-prompt-text-leak

Conversation

@hqhq1025
Copy link
Copy Markdown
Contributor

Summary

  • When Claude calls the Task/Agent tool, it writes the prompt text as a regular text content block before the tool_use block in the same assistant message
  • This causes the prompt to appear twice: as a standalone rendered message AND inside the tool card
  • Fix: skip text blocks in agent messages that also contain a Task tool_use, since the prompt is already visible in the tool card

Before

The Agent tool's full prompt text (description + detailed instructions) renders as a standalone markdown message below the tool card, duplicating the content already shown inside the card.

After

Only the Agent tool card is shown. The prompt text is accessible by clicking the card to open the detail dialog.

Test plan

  • All 76 existing tests pass (no regression)
  • Manual: trigger an Agent/Task tool call and verify the prompt text only appears inside the tool card, not as a separate message

When Claude calls the Task/Agent tool, it often writes the prompt text
as a regular text block before the tool_use block in the same message.
This causes the prompt to appear twice: once as a standalone message
and once inside the tool card.

Skip text blocks in agent messages that contain a Task tool_use, since
the prompt is already visible in the tool card.
Copy link
Copy Markdown

@github-actions github-actions bot left a comment

Choose a reason for hiding this comment

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

Findings

  • [Major] Task tool-call suppresses all text blocks, not only the duplicated prompt — any non-prompt assistant text in the same message is dropped, losing user-visible content. Evidence web/src/chat/reducerTimeline.ts:76
    Suggested fix:
    const taskTool = msg.content.find(
        (content) => content.type === 'tool-call' && content.name === 'Task'
    )
    const promptText = taskTool
        && typeof taskTool.input === 'object'
        && taskTool.input !== null
        && 'prompt' in taskTool.input
        && typeof (taskTool.input as { prompt: unknown }).prompt === 'string'
        ? (taskTool.input as { prompt: string }).prompt
        : null
    
    if (promptText && c.text.trim() === promptText.trim()) continue

Summary
Review mode: initial. 1 issue. Potential loss of non-prompt text in Task tool-call messages.

Testing
Not run (automation). Suggested: manual Task tool-call that includes extra assistant text; verify only prompt suppressed.

for (let idx = 0; idx < msg.content.length; idx += 1) {
const c = msg.content[idx]
if (c.type === 'text') {
if (hasTaskToolUse) continue
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

[MAJOR] Any agent message that contains a Task tool-call will now drop all text blocks, not just the prompt text. That can hide non-prompt assistant content in the same message. Evidence web/src/chat/reducerTimeline.ts:76.

Suggested fix:

const taskTool = msg.content.find(
    (content) => content.type === 'tool-call' && content.name === 'Task'
)
const promptText = taskTool
    && typeof taskTool.input === 'object'
    && taskTool.input !== null
    && 'prompt' in taskTool.input
    && typeof (taskTool.input as { prompt: unknown }).prompt === 'string'
    ? (taskTool.input as { prompt: string }).prompt
    : null

if (promptText && c.text.trim() === promptText.trim()) continue

…ages

Task notifications, command caveats, and system reminders are logged as
type:'user' in the JSONL but are not text the human actually typed.
The CLI fix (279f758) changed the socket role to 'agent', but the web
normalizer still saw data.type='user' and created user-role messages.

Filter these out in normalizeUserOutput by checking for known XML tag
prefixes (<task-notification>, <command-name>, <system-reminder>, etc.)
Copy link
Copy Markdown

@github-actions github-actions bot left a comment

Choose a reason for hiding this comment

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

Review mode: initial

  • 1 major issue; see inline comment.
  • Testing not run (automation).

const trimmed = messageContent.trimStart()
if (
trimmed.startsWith('<task-notification>') ||
trimmed.startsWith('<command-name>') ||
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

[MAJOR] CLI output cards suppressed

normalizeUserOutput now drops messages starting with <command-name> / <local-command-caveat>, but those tags are what the CLI output renderer parses for terminal command cards. This removes command output from chat.

Suggested fix:

if (
    trimmed.startsWith('<task-notification>') ||
    trimmed.startsWith('<system-reminder>')
) {
    return null
}

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.

1 participant