Skip to content

fix(plugins): apply output text transforms to toolcall_delta and toolcall_end events#97769

Merged
steipete merged 9 commits into
openclaw:mainfrom
ZOOWH:fix/97761-toolcall-text-transforms
Jul 1, 2026
Merged

fix(plugins): apply output text transforms to toolcall_delta and toolcall_end events#97769
steipete merged 9 commits into
openclaw:mainfrom
ZOOWH:fix/97761-toolcall-text-transforms

Conversation

@ZOOWH

@ZOOWH ZOOWH commented Jun 29, 2026

Copy link
Copy Markdown
Contributor

Closes #97761

What Problem This Solves

Plugin textTransforms.output restored normal assistant text but skipped structured tool-call arguments. A model could therefore return a masked placeholder in a tool call and OpenClaw would execute or deliver that placeholder through Slack, Google Chat, email, or another external tool.

Why This Change Was Made

The existing provider stream text-transform wrapper is the narrow owner boundary. This change:

  • recursively restores string values inside structured ToolCall.arguments;
  • preserves tool names, ids, numeric values, and other non-text metadata;
  • leaves raw provider JSON delta fragments unchanged because replacement tokens can span chunks;
  • keeps input transforms at the provider boundary, then applies output transforms after malformed-argument repair and HTML-entity decoding so later wrappers cannot restore masked arguments.

This avoids the broader alternative of adding a new agent-loop finalizer API.

User Impact

Plugins that mask or rewrite provider-visible text can now rely on restored tool arguments before OpenClaw executes tools. Placeholder tokens should no longer leak into Slack messages, file paths, or other external tool inputs.

Evidence

Focused tests:

$ node scripts/run-vitest.mjs src/agents/plugin-text-transforms.test.ts src/agents/embedded-agent-runner/run/attempt.tool-call-argument-repair.test.ts
Test Files  2 passed (2)
Tests       32 passed (32)

The regression covers a placeholder split across two toolcall_delta chunks, reconstructed by the malformed-argument repair wrapper, and restored in the structured end/result arguments.

Documentation and formatting:

$ node scripts/check-docs-mdx.mjs docs/gateway/cli-backends.md
Docs MDX check passed (1 files)

$ node_modules/.bin/oxfmt --check src/agents/plugin-text-transforms.ts src/agents/plugin-text-transforms.test.ts src/agents/embedded-agent-runner/run/attempt.ts src/agents/embedded-agent-runner/run/attempt.tool-call-argument-repair.test.ts docs/gateway/cli-backends.md
All matched files use the correct format.

$ git diff --check origin/main...HEAD
(clean)

Fresh repository autoreview after the maintainer repair:

autoreview clean: no accepted/actionable findings reported
overall: patch is correct (0.95)

Contributor live proof used DeepSeek V4 Pro with "John Smith" masked to [MASKED]; the model returned a masked read tool call, the output transform restored John Smith.txt, and the file read succeeded.

Security Impact

  • New permissions: no
  • Secret handling changes: no
  • New network calls: no

@openclaw-barnacle openclaw-barnacle Bot added agents Agent runtime and tooling size: S labels Jun 29, 2026
@clawsweeper

clawsweeper Bot commented Jun 29, 2026

Copy link
Copy Markdown
Contributor

Codex review: needs maintainer review before merge. Reviewed June 30, 2026, 8:08 PM ET / 00:08 UTC.

Summary
This PR extends plugin output text transforms to structured tool-call argument data, moves output transforms after repair/HTML decoding in embedded runs, updates docs, and adds focused regression tests.

PR surface: Source +45, Tests +79. Total +124 across 2 files.

Reproducibility: yes. Current main source shows provider output transforms skip structured ToolCall.arguments, and the PR body/comments include live DeepSeek V4 Pro proof where a masked read-tool path is restored before execution.

Review metrics: 1 noteworthy metric.

  • Executable transform paths: 3 covered: partial, end, and result tool-call arguments. These are the behavior boundaries maintainers need to notice because the change reaches executable tool inputs, not only visible assistant text.

Root-cause cluster
Relationship: fixed_by_candidate
Canonical: #97761
Summary: The canonical remaining work is the open issue about plugin output transforms skipping tool-call payloads; this PR and the open sibling are competing candidate fixes, while the earlier partial PR is already closed as superseded.

Members:

Proposal only: this assessment does not dispatch repair, suppress jobs, mutate sibling items, close, or merge anything.

Merge readiness
Overall: 🐚 platinum hermit
Proof: 🦞 diamond lobster
Patch quality: 🐚 platinum hermit
Result: ready for maintainer review.

Overall follows the weaker of proof and patch quality, so missing proof can cap an otherwise strong patch.

Rank-up moves:

Risk before merge

  • [P1] Merging broadens plugin textTransforms.output from visible assistant text into executable tool-call argument strings, so maintainers should accept that compatibility-sensitive behavior explicitly.
  • [P1] A wrong or non-idempotent output transform can alter tool inputs that feed external message delivery, file paths, or other side effects.
  • [P1] fix: apply text transforms to tool calls #97775 remains an open same-root-cause candidate, so maintainers should land exactly one implementation and close or rebase the other branch.

Maintainer options:

  1. Accept this narrow behavior expansion
    Maintainers can land this PR as the canonical branch if they accept existing output transforms applying to executable tool-call argument strings after repair.
  2. Use the broader sibling instead
    If maintainers prefer the broader approach in fix: apply text transforms to tool calls #97775, they should pause or close this PR after selecting that branch.
  3. Close duplicate candidates after one lands
    After one implementation lands for [Feature] textTransforms should apply output replacements to toolcall_delta / toolcall_end events #97761, the remaining same-root-cause PR should be closed or rebased away from already-landed behavior.

Next step before merge

  • No automated repair is queued because the remaining action is maintainer selection of the canonical same-root-cause branch and explicit acceptance of the compatibility/message-delivery risk.

Security
Cleared: No concrete security or supply-chain concern found; the diff changes TypeScript agent transform code, focused tests, and docs without dependencies, workflows, permissions, package metadata, or secret handling.

Review details

Best possible solution:

Land one canonical repair that restores tool-call argument text after repair and before execution without rewriting tool names; this PR is the narrower viable candidate if maintainers accept the behavior scope.

Do we have a high-confidence way to reproduce the issue?

Yes. Current main source shows provider output transforms skip structured ToolCall.arguments, and the PR body/comments include live DeepSeek V4 Pro proof where a masked read-tool path is restored before execution.

Is this the best way to solve the issue?

Yes, with maintainer acceptance of the compatibility-sensitive scope. The existing stream text-transform wrapper plus post-repair output placement is the narrowest maintainable fix; the broader sibling PR remains an alternative to choose or close.

AGENTS.md: found and applied where relevant.

Codex review notes: model internal, reasoning high; reviewed against 5e572dcf781a.

Label changes

Label justifications:

  • P2: This is a bounded agent/provider plugin bug fix with real external-tool/message impact but limited implementation scope.
  • merge-risk: 🚨 compatibility: The PR changes existing textTransforms.output behavior by applying replacements to executable tool-call arguments, not only assistant-visible text.
  • merge-risk: 🚨 message-delivery: Tool-call arguments can drive external message sends, so a bad transform could deliver altered or placeholder content.
  • rating: 🐚 platinum hermit: Overall readiness is 🐚 platinum hermit; proof is 🦞 diamond lobster and patch quality is 🐚 platinum hermit.
  • status: 👀 ready for maintainer look: ClawSweeper has no concrete contributor-facing blocker left for this PR. Sufficient (live_output): Sufficient: the PR body/comments include after-fix live DeepSeek V4 Pro output showing input masking, a masked tool call, restored structured arguments, and a successful file read with the restored path.
  • proof: sufficient: Contributor real behavior proof is sufficient. Sufficient: the PR body/comments include after-fix live DeepSeek V4 Pro output showing input masking, a masked tool call, restored structured arguments, and a successful file read with the restored path.
Evidence reviewed

PR surface:

Source +45, Tests +79. Total +124 across 2 files.

View PR surface stats
Area Files Added Removed Net
Source 1 46 1 +45
Tests 1 79 0 +79
Docs 0 0 0 0
Config 0 0 0 0
Generated 0 0 0 0
Other 0 0 0 0
Total 2 125 1 +124

What I checked:

  • Current main transform gap: Current main transforms text content, partial/message/error fields, and stream results, but transformContentText has no tool-call argument branch, so final tool-call arguments are not restored. (src/agents/plugin-text-transforms.ts:48, 5e572dcf781a)
  • Current event contract: The current stream protocol carries toolcall_delta.delta and toolcall_end.toolCall, with ToolCall.arguments as structured data; the PR targets the current typed payload shape rather than the issue body's older suggested field names. (packages/llm-core/src/types.ts:369, 5e572dcf781a)
  • PR transforms structured argument strings: The PR head recursively rewrites string leaves inside tool-call arguments, transforms toolCall content blocks in results, and preserves tool names as routing identifiers. (src/agents/plugin-text-transforms.ts:65, 317e4ac60557)
  • PR restores after repair/decoding: The PR moves provider output transforms to run after malformed tool-call argument repair and xAI HTML-entity decoding, which matches the PR's proof case for split replacement tokens. (src/agents/embedded-agent-runner/run/attempt.ts:3103, 317e4ac60557)
  • Regression coverage: The PR adds focused coverage for structured tool-call arguments and a split-token repair case where raw JSON fragments remain unchanged while structured end/result arguments are restored. (src/agents/embedded-agent-runner/run/attempt.tool-call-argument-repair.test.ts:217, 317e4ac60557)
  • Related item search: Live GitHub search found the canonical issue, this PR, one closed partial sibling, and one open broader sibling for the same textTransforms/tool-call problem.

Likely related people:

  • steipete: History ties Peter Steinberger to the original plugin text-transform helper and to the latest maintainer repair commits on this PR that narrowed the transform boundary and wrapper order. (role: feature introducer and recent repair author; confidence: high; commits: 202f80792ed1, 4e2541e5fbbf, 7dafbaf8383a; files: src/agents/plugin-text-transforms.ts, src/agents/plugin-text-transforms.test.ts, src/agents/embedded-agent-runner/run/attempt.ts)
  • vincentkoc: Recent provider/runtime history shows adjacent provider hook seam work that the text-transform wrapper depends on. (role: recent adjacent contributor; confidence: medium; commits: a7436c8b4a93, 7198a9f0eeed; files: src/plugins/provider-runtime.ts, src/agents/embedded-agent-runner/run/attempt.ts, src/agents/cli-backends.ts)
  • Masato Hoshino: Current checkout blame attributes the inspected transform and embedded-runner lines to a broad recent grafted commit, so this is only weak routing context rather than feature ownership. (role: current-line provenance; confidence: low; commits: a75431c586; files: src/agents/plugin-text-transforms.ts, src/agents/embedded-agent-runner/run/attempt.ts)
What the crustacean ranks mean
  • 🦀 challenger crab: rare, exceptional readiness with strong proof, clean implementation, and convincing validation.
  • 🦞 diamond lobster: very strong readiness with only minor maintainer review expected.
  • 🐚 platinum hermit: good normal PR, likely mergeable with ordinary maintainer review.
  • 🦐 gold shrimp: useful signal, but proof or patch confidence is still limited.
  • 🦪 silver shellfish: thin signal; proof, validation, or implementation needs work.
  • 🧂 unranked krab: not merge-ready because proof is missing/unusable or there are serious correctness or safety concerns.
  • 🌊 off-meta tidepool: rating does not apply to this item.

Shiny media proof means a screenshot, video, or linked artifact directly shows the changed behavior. Runtime, network, CSP, and security claims still need visible diagnostics.

How this review workflow works
  • ClawSweeper keeps one durable marker-backed review comment per issue or PR.
  • Re-runs edit this comment so the latest verdict, findings, and automation markers stay together instead of adding duplicate bot comments.
  • A fresh review can be triggered by eligible @clawsweeper re-review comments, exact-item GitHub events, scheduled/background review runs, or manual workflow dispatch.
  • PR/issue authors and users with repository write access can comment @clawsweeper re-review or @clawsweeper re-run on an open PR or issue to request a fresh review only.
  • Maintainers can also comment @clawsweeper review to request a fresh review only.
  • Fresh-review commands do not start repair, autofix, rebase, CI repair, or automerge.
  • Maintainer-only repair and merge flows require explicit commands such as @clawsweeper autofix, @clawsweeper automerge, @clawsweeper fix ci, or @clawsweeper address review.
  • Maintainers can comment @clawsweeper explain to ask for more context, or @clawsweeper stop to stop active automation.

@clawsweeper clawsweeper Bot added rating: 🧂 unranked krab Not merge-ready due to missing proof or serious correctness/safety concerns. status: 📣 needs proof The PR needs real behavior proof before ClawSweeper can clear the contributor ask. P2 Normal backlog priority with limited blast radius. merge-risk: 🚨 message-delivery 🚨 May drop, duplicate, misroute, suppress, or wrongly target messages. merge-risk: 🚨 compatibility 🚨 May break existing users, config, migrations, defaults, or upgrade paths. labels Jun 29, 2026
@ZOOWH

ZOOWH commented Jun 30, 2026

Copy link
Copy Markdown
Contributor Author

@clawsweeper re-review

Fixed both P1s:

  • Removed tool name transformation (preserves tool routing)
  • Added arguments transform to stream.result()/done.message path via transformContentText
  • Added runtime proof with node --import tsx showing all 3 paths pass

@clawsweeper

clawsweeper Bot commented Jun 30, 2026

Copy link
Copy Markdown
Contributor

🦞🧹
ClawSweeper re-review requested.

I asked ClawSweeper to review this item again.
Action: item re-review queued (workflow sweep.yml, event repository_dispatch).
Result: the existing ClawSweeper review comment will be edited in place when the review finishes.

@clawsweeper clawsweeper Bot added rating: 🦪 silver shellfish Thin PR readiness signal; proof, validation, or implementation needs work. rating: 🧂 unranked krab Not merge-ready due to missing proof or serious correctness/safety concerns. and removed rating: 🧂 unranked krab Not merge-ready due to missing proof or serious correctness/safety concerns. merge-risk: 🚨 compatibility 🚨 May break existing users, config, migrations, defaults, or upgrade paths. rating: 🦪 silver shellfish Thin PR readiness signal; proof, validation, or implementation needs work. labels Jun 30, 2026
@ZOOWH

ZOOWH commented Jun 30, 2026

Copy link
Copy Markdown
Contributor Author

@clawsweeper re-review

Fixed P1: result-path test fixture now contains an actual masked toolCall content block. The assertion previously tested against a plain text message that never contained toolCall blocks.

@clawsweeper

clawsweeper Bot commented Jun 30, 2026

Copy link
Copy Markdown
Contributor

🦞🧹
ClawSweeper re-review requested.

I asked ClawSweeper to review this item again.
Action: item re-review queued (workflow sweep.yml, event repository_dispatch).
Result: the existing ClawSweeper review comment will be edited in place when the review finishes.

@clawsweeper clawsweeper Bot added rating: 🦪 silver shellfish Thin PR readiness signal; proof, validation, or implementation needs work. and removed rating: 🧂 unranked krab Not merge-ready due to missing proof or serious correctness/safety concerns. labels Jun 30, 2026
@ZOOWH

ZOOWH commented Jun 30, 2026

Copy link
Copy Markdown
Contributor Author

@clawsweeper re-review

@clawsweeper

clawsweeper Bot commented Jun 30, 2026

Copy link
Copy Markdown
Contributor

🦞🧹
ClawSweeper re-review requested.

I asked ClawSweeper to review this item again.
Action: item re-review queued (workflow sweep.yml, event repository_dispatch).
Result: the existing ClawSweeper review comment will be edited in place when the review finishes.

@ZOOWH

ZOOWH commented Jun 30, 2026

Copy link
Copy Markdown
Contributor Author

@clawsweeper re-review

Added:

  1. Project-standard test runner output (node scripts/run-vitest.mjs)
  2. Production code verification — patched compiled dist artifacts from openclaw@2026.6.10, all 3 paths pass
  3. Formatting + whitespace checks (oxfmt + git diff --check)

@ZOOWH

ZOOWH commented Jun 30, 2026

Copy link
Copy Markdown
Contributor Author

@clawsweeper re-review

Added real behavior proof: DeepSeek V4 Pro API call demonstrates the complete end-to-end pipeline:

  1. Input transform masks "John Smith" → "[MASKED]"
  2. LLM returns tool_use("[MASKED].txt")
  3. Output transform (our fix) restores → "John Smith.txt" in all 3 paths (delta/end/result)
  4. File read succeeds

@clawsweeper clawsweeper Bot added proof: sufficient ClawSweeper judged the real behavior proof convincing. rating: 🐚 platinum hermit Good normal PR readiness with ordinary maintainer review expected. status: 👀 ready for maintainer look ClawSweeper has no concrete contributor-facing blocker left for this PR. merge-risk: 🚨 compatibility 🚨 May break existing users, config, migrations, defaults, or upgrade paths. and removed rating: 🦪 silver shellfish Thin PR readiness signal; proof, validation, or implementation needs work. status: 📣 needs proof The PR needs real behavior proof before ClawSweeper can clear the contributor ask. labels Jun 30, 2026
ZOOWH and others added 9 commits June 30, 2026 17:04
…call_end events

toolcall_delta and toolcall_end events bypassed the output replacement
pipeline, leaking masked tokens (e.g. PII placeholders) into tool call
arguments and external systems.

Closes openclaw#97761
…ents

Add recursive transformToolCallArgumentText to handle strings, arrays,
and nested objects in tool call arguments, not just the name field.
- Remove toolCall.name transformation to prevent breaking tool routing
- Add arguments transform to stream.result()/done.message via
  transformContentText for tool-call content blocks
Only transform arguments on content blocks with type=toolCall to avoid
touching non-tool-call blocks that happen to have an arguments field.
…lock

The previous fixture used makeAssistantMessage('final') which produces
a plain text content block, not a toolCall block. The stream.result()
assertion was vacuously passing.
@steipete steipete force-pushed the fix/97761-toolcall-text-transforms branch from ff462d3 to 317e4ac Compare July 1, 2026 00:04
@openclaw-barnacle openclaw-barnacle Bot added docs Improvements or additions to documentation gateway Gateway runtime labels Jul 1, 2026
@steipete

steipete commented Jul 1, 2026

Copy link
Copy Markdown
Contributor

Maintainer repair and pre-merge proof are complete on exact head 317e4ac6055775834f8398b0c6c287ac6b222a05.

What changed during prepare:

  • moved provider output transforms after malformed-argument repair and HTML-entity decoding;
  • stopped rewriting raw toolcall_delta JSON fragments, which can split replacement tokens across chunks;
  • added a split-token regression proving reconstructed structured arguments are restored before execution;
  • documented the structured tool-call argument contract.

Proof:

  • node scripts/run-vitest.mjs src/agents/plugin-text-transforms.test.ts src/agents/embedded-agent-runner/run/attempt.tool-call-argument-repair.test.ts — 2 files / 32 tests passed.
  • node scripts/check-docs-mdx.mjs docs/gateway/cli-backends.md — passed.
  • node_modules/.bin/oxfmt --check ... and git diff --check origin/main...HEAD — passed.
  • Fresh autoreview — clean, patch correct (0.95).
  • Blacksmith Testbox via Crabbox — tbx_01kwdfxwxtsjz86x6ctvyc94bz, changed gates passed: https://github.com/openclaw/openclaw/actions/runs/28484039035
  • Exact-head hosted CI — all 67 checks passed: https://github.com/openclaw/openclaw/actions/runs/28483994373

Maintainer judgment: the compatibility-sensitive expansion is intentional and bounded to structured tool-call argument string values. Contributor live DeepSeek proof covers the external execution path; I did not repeat that credentialed provider run locally.

@steipete steipete merged commit 5a73361 into openclaw:main Jul 1, 2026
111 of 113 checks passed
@steipete

steipete commented Jul 1, 2026

Copy link
Copy Markdown
Contributor

Merged via squash.

github-actions Bot pushed a commit to Desicool/openclaw that referenced this pull request Jul 1, 2026
…call_end events (openclaw#97769)

* fix(plugins): apply output text transforms to toolcall_delta and toolcall_end events

toolcall_delta and toolcall_end events bypassed the output replacement
pipeline, leaking masked tokens (e.g. PII placeholders) into tool call
arguments and external systems.

Closes openclaw#97761

* fix(plugins): transform nested tool call arguments in output replacements

Add recursive transformToolCallArgumentText to handle strings, arrays,
and nested objects in tool call arguments, not just the name field.

* fix(plugins): keep tool names unchanged and cover result path

- Remove toolCall.name transformation to prevent breaking tool routing
- Add arguments transform to stream.result()/done.message via
  transformContentText for tool-call content blocks

* fix(plugins): narrow argument transform to toolCall content blocks only

Only transform arguments on content blocks with type=toolCall to avoid
touching non-tool-call blocks that happen to have an arguments field.

* test(plugins): assert stream.result() tool-call content block is transformed

* test(plugins): fix result-path fixture to actually contain toolCall block

The previous fixture used makeAssistantMessage('final') which produces
a plain text content block, not a toolCall block. The stream.result()
assertion was vacuously passing.

* style(plugins): fix type cast in result-path test assertion

* fix(agents): preserve tool argument transforms after repair

* refactor(agents): keep tool transform boundary narrow

---------

Co-authored-by: Peter Steinberger <steipete@golden-gate.local>
QiuYuang pushed a commit to QiuYuang/openclaw that referenced this pull request Jul 1, 2026
…call_end events (openclaw#97769)

* fix(plugins): apply output text transforms to toolcall_delta and toolcall_end events

toolcall_delta and toolcall_end events bypassed the output replacement
pipeline, leaking masked tokens (e.g. PII placeholders) into tool call
arguments and external systems.

Closes openclaw#97761

* fix(plugins): transform nested tool call arguments in output replacements

Add recursive transformToolCallArgumentText to handle strings, arrays,
and nested objects in tool call arguments, not just the name field.

* fix(plugins): keep tool names unchanged and cover result path

- Remove toolCall.name transformation to prevent breaking tool routing
- Add arguments transform to stream.result()/done.message via
  transformContentText for tool-call content blocks

* fix(plugins): narrow argument transform to toolCall content blocks only

Only transform arguments on content blocks with type=toolCall to avoid
touching non-tool-call blocks that happen to have an arguments field.

* test(plugins): assert stream.result() tool-call content block is transformed

* test(plugins): fix result-path fixture to actually contain toolCall block

The previous fixture used makeAssistantMessage('final') which produces
a plain text content block, not a toolCall block. The stream.result()
assertion was vacuously passing.

* style(plugins): fix type cast in result-path test assertion

* fix(agents): preserve tool argument transforms after repair

* refactor(agents): keep tool transform boundary narrow

---------

Co-authored-by: Peter Steinberger <steipete@golden-gate.local>
chenyangjun-xy pushed a commit to chenyangjun-xy/openclaw that referenced this pull request Jul 1, 2026
…call_end events (openclaw#97769)

* fix(plugins): apply output text transforms to toolcall_delta and toolcall_end events

toolcall_delta and toolcall_end events bypassed the output replacement
pipeline, leaking masked tokens (e.g. PII placeholders) into tool call
arguments and external systems.

Closes openclaw#97761

* fix(plugins): transform nested tool call arguments in output replacements

Add recursive transformToolCallArgumentText to handle strings, arrays,
and nested objects in tool call arguments, not just the name field.

* fix(plugins): keep tool names unchanged and cover result path

- Remove toolCall.name transformation to prevent breaking tool routing
- Add arguments transform to stream.result()/done.message via
  transformContentText for tool-call content blocks

* fix(plugins): narrow argument transform to toolCall content blocks only

Only transform arguments on content blocks with type=toolCall to avoid
touching non-tool-call blocks that happen to have an arguments field.

* test(plugins): assert stream.result() tool-call content block is transformed

* test(plugins): fix result-path fixture to actually contain toolCall block

The previous fixture used makeAssistantMessage('final') which produces
a plain text content block, not a toolCall block. The stream.result()
assertion was vacuously passing.

* style(plugins): fix type cast in result-path test assertion

* fix(agents): preserve tool argument transforms after repair

* refactor(agents): keep tool transform boundary narrow

---------

Co-authored-by: Peter Steinberger <steipete@golden-gate.local>
chenyangjun-xy pushed a commit to chenyangjun-xy/openclaw that referenced this pull request Jul 3, 2026
…call_end events (openclaw#97769)

* fix(plugins): apply output text transforms to toolcall_delta and toolcall_end events

toolcall_delta and toolcall_end events bypassed the output replacement
pipeline, leaking masked tokens (e.g. PII placeholders) into tool call
arguments and external systems.

Closes openclaw#97761

* fix(plugins): transform nested tool call arguments in output replacements

Add recursive transformToolCallArgumentText to handle strings, arrays,
and nested objects in tool call arguments, not just the name field.

* fix(plugins): keep tool names unchanged and cover result path

- Remove toolCall.name transformation to prevent breaking tool routing
- Add arguments transform to stream.result()/done.message via
  transformContentText for tool-call content blocks

* fix(plugins): narrow argument transform to toolCall content blocks only

Only transform arguments on content blocks with type=toolCall to avoid
touching non-tool-call blocks that happen to have an arguments field.

* test(plugins): assert stream.result() tool-call content block is transformed

* test(plugins): fix result-path fixture to actually contain toolCall block

The previous fixture used makeAssistantMessage('final') which produces
a plain text content block, not a toolCall block. The stream.result()
assertion was vacuously passing.

* style(plugins): fix type cast in result-path test assertion

* fix(agents): preserve tool argument transforms after repair

* refactor(agents): keep tool transform boundary narrow

---------

Co-authored-by: Peter Steinberger <steipete@golden-gate.local>
@ZOOWH ZOOWH deleted the fix/97761-toolcall-text-transforms branch July 7, 2026 00:41
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

agents Agent runtime and tooling docs Improvements or additions to documentation gateway Gateway runtime merge-risk: 🚨 compatibility 🚨 May break existing users, config, migrations, defaults, or upgrade paths. merge-risk: 🚨 message-delivery 🚨 May drop, duplicate, misroute, suppress, or wrongly target messages. P2 Normal backlog priority with limited blast radius. proof: sufficient ClawSweeper judged the real behavior proof convincing. rating: 🐚 platinum hermit Good normal PR readiness with ordinary maintainer review expected. size: S status: 👀 ready for maintainer look ClawSweeper has no concrete contributor-facing blocker left for this PR.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[Feature] textTransforms should apply output replacements to toolcall_delta / toolcall_end events

2 participants