Skip to content

fix(ai): emit TOOL_CALL_START/ARGS during continuation re-executions#372

Open
DiegoGBrisa wants to merge 6 commits intoTanStack:mainfrom
DiegoGBrisa:fix/continuation-chunk-emission
Open

fix(ai): emit TOOL_CALL_START/ARGS during continuation re-executions#372
DiegoGBrisa wants to merge 6 commits intoTanStack:mainfrom
DiegoGBrisa:fix/continuation-chunk-emission

Conversation

@DiegoGBrisa
Copy link
Copy Markdown
Contributor

@DiegoGBrisa DiegoGBrisa commented Mar 13, 2026

Summary

Continuation re-executions (pending tool calls resumed from message history) only emit TOOL_CALL_END, skipping TOOL_CALL_START and TOOL_CALL_ARGS. This causes clients to store tool calls with empty
arguments, leading to infinite re-execution loops.

  • buildToolResultChunks now accepts an optional argsMap parameter
  • When provided (from checkForPendingToolCalls), emits the full START → ARGS → END sequence per tool call using the arguments from the original ToolCall objects
  • Normal flow (processToolCalls) is unaffected — the adapter stream already emits START/ARGS

Test plan

  • Commit 1 adds failing tests reproducing the issue (tests-first format)
  • Commit 2 applies the fix, all tests pass
  • Single pending tool call emits full START → ARGS → END sequence
  • Batch of pending tool calls each emit full START → ARGS → END sequence
  • Chunk ordering verified: START < ARGS < END per tool call
  • Existing 30 tests unaffected

Summary by CodeRabbit

  • Bug Fixes

    • Pending tool calls now emit the full event sequence (start, arguments, end) during continuations, ensuring complete tool-call info and correct ordering.
  • Tests

    • Added unit and end-to-end tests covering single, sequential, and batched pending tool calls (mixed client/server) to validate event sequencing and preserved arguments.
    • Added a test helper to extract and normalize tool-call parts for assertions.
  • Chores

    • Added a changeset entry documenting the patch release.

@changeset-bot
Copy link
Copy Markdown

changeset-bot bot commented Mar 13, 2026

🦋 Changeset detected

Latest commit: ec66e30

The changes in this PR will be included in the next version bump.

This PR includes changesets to release 29 packages
Name Type
@tanstack/ai Patch
@tanstack/ai-anthropic Patch
@tanstack/ai-client Patch
@tanstack/ai-devtools-core Patch
@tanstack/ai-elevenlabs Patch
@tanstack/ai-event-client Patch
@tanstack/ai-fal Patch
@tanstack/ai-gemini Patch
@tanstack/ai-grok Patch
@tanstack/ai-groq Patch
@tanstack/ai-ollama Patch
@tanstack/ai-openai Patch
@tanstack/ai-openrouter Patch
@tanstack/ai-preact Patch
@tanstack/ai-react Patch
@tanstack/ai-solid Patch
@tanstack/ai-svelte Patch
@tanstack/ai-vue Patch
@tanstack/tests-adapters Patch
@tanstack/smoke-tests-e2e Patch
ts-svelte-chat Patch
ts-vue-chat Patch
@tanstack/ai-react-ui Patch
@tanstack/ai-solid-ui Patch
vanilla-chat Patch
@tanstack/preact-ai-devtools Patch
@tanstack/react-ai-devtools Patch
@tanstack/solid-ai-devtools Patch
@tanstack/ai-vue-ui Patch

Not sure what this means? Click here to learn what changesets are.

Click here if you're a maintainer who wants to add another changeset to this PR

@coderabbitai
Copy link
Copy Markdown
Contributor

coderabbitai bot commented Mar 13, 2026

Note

Reviews paused

It looks like this branch is under active development. To avoid overwhelming you with review comments due to an influx of new commits, CodeRabbit has automatically paused this review. You can configure this behavior by changing the reviews.auto_review.auto_pause_after_reviewed_commits setting.

Use the following commands to manage reviews:

  • @coderabbitai resume to resume automatic reviews.
  • @coderabbitai review to trigger a single review.

Use the checkboxes below for quick actions:

  • ▶️ Resume reviews
  • 🔍 Trigger review
📝 Walkthrough

Walkthrough

During continuation re-executions, pending tool calls now emit full call chunks: an argsMap captures tool-call arguments and buildToolResultChunks emits TOOL_CALL_START, TOOL_CALL_ARGS, then TOOL_CALL_END so clients can reconstruct pending tool calls.

Changes

Cohort / File(s) Summary
Changelog
\.changeset/fix-continuation-chunk-emission.md
Adds a changeset entry documenting that pending tool calls now emit TOOL_CALL_START and TOOL_CALL_ARGS during continuation re-executions.
Core Implementation
packages/typescript/ai/src/activities/chat/index.ts
Introduces an argsMap to collect pending tool-call arguments, threads it into buildToolResultChunks, and updates chunk emission to optionally emit TOOL_CALL_START and TOOL_CALL_ARGS before TOOL_CALL_END for continuation/pending executions.
Unit Tests
packages/typescript/ai/tests/chat.test.ts
Adds tests validating full TOOL_CALL_STARTTOOL_CALL_ARGSTOOL_CALL_END sequence and ordering for single and batched pending tool calls, including mixed server/client tool scenarios.
E2E Tests
testing/e2e/tests/tools-test/continuation-args.spec.ts, testing/e2e/tests/tools-test/helpers.ts
Adds Playwright E2E tests and a helper getToolCallParts to verify continuation re-execution preserves tool-call argument payloads across single, sequential, and parallel/batched scenarios; includes failure artifact capture and defensive parsing in helper.

Sequence Diagram(s)

sequenceDiagram
    participant Client
    participant TextEngine
    participant Tool
    Client->>TextEngine: Request continuation re-execution
    TextEngine->>Tool: (re)execute pending tool call
    Tool-->>TextEngine: Tool result
    TextEngine->>Client: STREAM: TOOL_CALL_START
    TextEngine->>Client: STREAM: TOOL_CALL_ARGS
    TextEngine->>Client: STREAM: TOOL_CALL_END
Loading

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~45 minutes

Poem

🐰 I nibble at streams where pauses once played,
START cracks a path, ARGS bright as braid,
END tucks the call in a tidy row —
Continuations hum, arguments glow,
A rabbit claps soft paws in merry aid.

🚥 Pre-merge checks | ✅ 2 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Description check ⚠️ Warning The pull request description provides comprehensive context: the problem statement, solution approach, test plan with verification steps, and impact on existing code. However, it does not follow the repository's template structure with required sections. Restructure the description to match the template: add '## 🎯 Changes' section, include the '## ✅ Checklist' with required items, and add '## 🚀 Release Impact' section to confirm changeset generation.
✅ Passed checks (2 passed)
Check name Status Explanation
Title check ✅ Passed The title accurately describes the main fix: emitting TOOL_CALL_START and TOOL_CALL_ARGS during continuation re-executions, which directly addresses the core issue.
Docstring Coverage ✅ Passed Docstring coverage is 100.00% which is sufficient. The required threshold is 80.00%.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests

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 and usage tips.

@nx-cloud
Copy link
Copy Markdown

nx-cloud bot commented Mar 13, 2026

View your CI Pipeline Execution ↗ for commit 94cc2d4

Command Status Duration Result
nx affected --targets=test:sherif,test:knip,tes... ✅ Succeeded 4m 51s View ↗
nx run-many --targets=build --exclude=examples/** ✅ Succeeded 1m 36s View ↗

☁️ Nx Cloud last updated this comment at 2026-04-10 19:47:22 UTC

@pkg-pr-new
Copy link
Copy Markdown

pkg-pr-new bot commented Mar 13, 2026

Open in StackBlitz

@tanstack/ai

npm i https://pkg.pr.new/@tanstack/ai@372

@tanstack/ai-anthropic

npm i https://pkg.pr.new/@tanstack/ai-anthropic@372

@tanstack/ai-client

npm i https://pkg.pr.new/@tanstack/ai-client@372

@tanstack/ai-code-mode

npm i https://pkg.pr.new/@tanstack/ai-code-mode@372

@tanstack/ai-code-mode-skills

npm i https://pkg.pr.new/@tanstack/ai-code-mode-skills@372

@tanstack/ai-devtools-core

npm i https://pkg.pr.new/@tanstack/ai-devtools-core@372

@tanstack/ai-elevenlabs

npm i https://pkg.pr.new/@tanstack/ai-elevenlabs@372

@tanstack/ai-event-client

npm i https://pkg.pr.new/@tanstack/ai-event-client@372

@tanstack/ai-fal

npm i https://pkg.pr.new/@tanstack/ai-fal@372

@tanstack/ai-gemini

npm i https://pkg.pr.new/@tanstack/ai-gemini@372

@tanstack/ai-grok

npm i https://pkg.pr.new/@tanstack/ai-grok@372

@tanstack/ai-groq

npm i https://pkg.pr.new/@tanstack/ai-groq@372

@tanstack/ai-isolate-cloudflare

npm i https://pkg.pr.new/@tanstack/ai-isolate-cloudflare@372

@tanstack/ai-isolate-node

npm i https://pkg.pr.new/@tanstack/ai-isolate-node@372

@tanstack/ai-isolate-quickjs

npm i https://pkg.pr.new/@tanstack/ai-isolate-quickjs@372

@tanstack/ai-ollama

npm i https://pkg.pr.new/@tanstack/ai-ollama@372

@tanstack/ai-openai

npm i https://pkg.pr.new/@tanstack/ai-openai@372

@tanstack/ai-openrouter

npm i https://pkg.pr.new/@tanstack/ai-openrouter@372

@tanstack/ai-preact

npm i https://pkg.pr.new/@tanstack/ai-preact@372

@tanstack/ai-react

npm i https://pkg.pr.new/@tanstack/ai-react@372

@tanstack/ai-react-ui

npm i https://pkg.pr.new/@tanstack/ai-react-ui@372

@tanstack/ai-solid

npm i https://pkg.pr.new/@tanstack/ai-solid@372

@tanstack/ai-solid-ui

npm i https://pkg.pr.new/@tanstack/ai-solid-ui@372

@tanstack/ai-svelte

npm i https://pkg.pr.new/@tanstack/ai-svelte@372

@tanstack/ai-vue

npm i https://pkg.pr.new/@tanstack/ai-vue@372

@tanstack/ai-vue-ui

npm i https://pkg.pr.new/@tanstack/ai-vue-ui@372

@tanstack/preact-ai-devtools

npm i https://pkg.pr.new/@tanstack/preact-ai-devtools@372

@tanstack/react-ai-devtools

npm i https://pkg.pr.new/@tanstack/react-ai-devtools@372

@tanstack/solid-ai-devtools

npm i https://pkg.pr.new/@tanstack/solid-ai-devtools@372

commit: 94cc2d4

Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

🧹 Nitpick comments (2)
packages/typescript/ai/src/activities/chat/index.ts (1)

1027-1034: Populate args on the synthetic TOOL_CALL_ARGS chunk.

At continuation time you already have the full serialized arguments, so emitting only delta makes these synthetic chunks a little less expressive than the adapter-emitted ones. Setting args too keeps raw stream consumers from needing a continuation-only code path.

💡 Suggested change
         const args = argsMap.get(result.toolCallId) ?? '{}'
         chunks.push({
           type: 'TOOL_CALL_ARGS',
           timestamp: Date.now(),
           model: finishEvent.model,
           toolCallId: result.toolCallId,
           delta: args,
+          args,
         })
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@packages/typescript/ai/src/activities/chat/index.ts` around lines 1027 -
1034, The synthetic TOOL_CALL_ARGS chunk currently only sets delta and omits the
full args; update the chunk created in the continuation path (the block using
argsMap.get(result.toolCallId) and pushing into chunks) to also set an args
property with the serialized arguments (the same value you pull from argsMap,
e.g., args or parsed equivalent) so consumers see the full arguments on the
synthetic chunk alongside delta, model, toolCallId, and timestamp.
packages/typescript/ai/tests/chat.test.ts (1)

722-801: Add one regression for the mixed pending/wait branch too.

These cases cover the path where pending server tools finish and the engine proceeds to the next model call. The new argsMap plumbing is also used when continuation pauses again for needsClientExecution or needsApproval, so I’d add one assertion there that TOOL_CALL_START and TOOL_CALL_ARGS are still emitted for the completed server tool.

🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Nitpick comments:
In `@packages/typescript/ai/src/activities/chat/index.ts`:
- Around line 1027-1034: The synthetic TOOL_CALL_ARGS chunk currently only sets
delta and omits the full args; update the chunk created in the continuation path
(the block using argsMap.get(result.toolCallId) and pushing into chunks) to also
set an args property with the serialized arguments (the same value you pull from
argsMap, e.g., args or parsed equivalent) so consumers see the full arguments on
the synthetic chunk alongside delta, model, toolCallId, and timestamp.

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: 09507dd7-efca-4f4a-8822-f6c0d6ef6b33

📥 Commits

Reviewing files that changed from the base of the PR and between 570c9f6 and c2522b6.

📒 Files selected for processing (3)
  • .changeset/fix-continuation-chunk-emission.md
  • packages/typescript/ai/src/activities/chat/index.ts
  • packages/typescript/ai/tests/chat.test.ts

@DiegoGBrisa
Copy link
Copy Markdown
Contributor Author

🧹 Nitpick comments (2)

packages/typescript/ai/src/activities/chat/index.ts (1)> 1027-1034: Populate args on the synthetic TOOL_CALL_ARGS chunk.

At continuation time you already have the full serialized arguments, so emitting only delta makes these synthetic chunks a little less expressive than the adapter-emitted ones. Setting args too keeps raw stream consumers from needing a continuation-only code path.

💡 Suggested change

         const args = argsMap.get(result.toolCallId) ?? '{}'
         chunks.push({
           type: 'TOOL_CALL_ARGS',
           timestamp: Date.now(),
           model: finishEvent.model,
           toolCallId: result.toolCallId,
           delta: args,
+          args,
         })

🤖 Prompt for AI Agents

Verify each finding against the current code and only fix it if needed.

In `@packages/typescript/ai/src/activities/chat/index.ts` around lines 1027 -
1034, The synthetic TOOL_CALL_ARGS chunk currently only sets delta and omits the
full args; update the chunk created in the continuation path (the block using
argsMap.get(result.toolCallId) and pushing into chunks) to also set an args
property with the serialized arguments (the same value you pull from argsMap,
e.g., args or parsed equivalent) so consumers see the full arguments on the
synthetic chunk alongside delta, model, toolCallId, and timestamp.

packages/typescript/ai/tests/chat.test.ts (1)> 722-801: Add one regression for the mixed pending/wait branch too.

These cases cover the path where pending server tools finish and the engine proceeds to the next model call. The new argsMap plumbing is also used when continuation pauses again for needsClientExecution or needsApproval, so I’d add one assertion there that TOOL_CALL_START and TOOL_CALL_ARGS are still emitted for the completed server tool.

🤖 Prompt for all review comments with AI agents

Verify each finding against the current code and only fix it if needed.

Nitpick comments:
In `@packages/typescript/ai/src/activities/chat/index.ts`:
- Around line 1027-1034: The synthetic TOOL_CALL_ARGS chunk currently only sets
delta and omits the full args; update the chunk created in the continuation path
(the block using argsMap.get(result.toolCallId) and pushing into chunks) to also
set an args property with the serialized arguments (the same value you pull from
argsMap, e.g., args or parsed equivalent) so consumers see the full arguments on
the synthetic chunk alongside delta, model, toolCallId, and timestamp.

ℹ️ Review info

Intentionally omitting args — adapter-emitted TOOL_CALL_ARGS chunks only use delta, so the synthetic chunks match the same shape. Adding a non-standard field would require consumers to handle continuation chunks differently from regular ones.

@AlemTuzlak AlemTuzlak requested a review from jherr March 13, 2026 09:34
DiegoGBrisa and others added 5 commits April 10, 2026 20:31
  Continuation re-executions (pending tool calls from message history) only
  emit TOOL_CALL_END, skipping TOOL_CALL_START and TOOL_CALL_ARGS. This
  causes clients to store tool calls with empty arguments, leading to
  infinite re-execution loops.

  Two tests added:
  - Single pending tool call emits full START → ARGS → END sequence
  - Batch of pending tool calls each emit full START → ARGS → END sequence
…re-executions

  Pending tool calls resumed from message history only emit TOOL_CALL_END,
  causing clients to store empty arguments and triggering infinite
  re-execution loops. Emit the full START → ARGS → END sequence using the
  arguments from the original ToolCall objects.
@DiegoGBrisa DiegoGBrisa force-pushed the fix/continuation-chunk-emission branch 2 times, most recently from 8974a32 to 654fb57 Compare April 10, 2026 18:50
Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

🧹 Nitpick comments (2)
testing/e2e/tests/tools-test/continuation-args.spec.ts (2)

162-167: Prefer Playwright output paths over raw title-derived filenames.

Using testInfo.title directly in path can produce brittle filenames. testInfo.outputPath(...) is safer and keeps artifacts scoped per test run.

Suggested change
-      await page.screenshot({
-        path: `test-results/continuation-args-failure-${testInfo.title.replace(/\s+/g, '-')}.png`,
-        fullPage: true,
-      })
+      await page.screenshot({
+        path: testInfo.outputPath(
+          `continuation-args-failure-${testInfo.title.replace(/[^a-z0-9-]/gi, '-')}.png`,
+        ),
+        fullPage: true,
+      })
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@testing/e2e/tests/tools-test/continuation-args.spec.ts` around lines 162 -
167, The failure screenshot path uses a brittle filename derived from
testInfo.title inside the test.afterEach hook; replace constructing the path
manually with Playwright's testInfo.outputPath to generate the artifact path
(e.g., call testInfo.outputPath('continuation-args-failure.png') or include a
safe suffix) and use that value for page.screenshot so artifacts are scoped and
safely named; update the screenshot path usage in the test.afterEach callback
where testInfo.title is currently used.

50-159: Add an explicit mixed pending/wait continuation scenario.

Current coverage validates single/sequential/parallel client-tool continuations, but I don’t see an explicit case where completed server-tool results are emitted and the same continuation still pauses for needsClientExecution or needsApproval. That mixed branch is where this regression is easiest to miss again.

As per coding guidelines, testing/e2e/**/*.spec.ts: "Add E2E test coverage for every feature, bug fix, or behavior change in the testing/e2e directory".

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@testing/e2e/tests/tools-test/continuation-args.spec.ts` around lines 50 -
159, Add a new E2E test in continuation-args.spec.ts that covers the mixed
pending/server-complete continuation branch by selecting a scenario (e.g.,
'mixed-client-server-tools') via selectScenario(page, ...), calling
runTest(page) and waitForTestComplete(page, timeout, expectedCount) as other
tests do, then use getMetadata(page) and getToolCallParts(page) to assert that a
server-side tool call completed (exists in toolCallParts with expected
arguments), that a client-side continuation remained pending
(execution-complete-count or metadata shows remaining
needsClientExecution/needsApproval), and that no tool call has empty arguments;
reuse existing helpers (selectScenario, runTest, waitForTestComplete,
getToolCallParts, getMetadata) and mirror assertion patterns from the
'sequential client tool' and 'parallel client tool' tests to validate both
completed server results and the paused client continuation.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Nitpick comments:
In `@testing/e2e/tests/tools-test/continuation-args.spec.ts`:
- Around line 162-167: The failure screenshot path uses a brittle filename
derived from testInfo.title inside the test.afterEach hook; replace constructing
the path manually with Playwright's testInfo.outputPath to generate the artifact
path (e.g., call testInfo.outputPath('continuation-args-failure.png') or include
a safe suffix) and use that value for page.screenshot so artifacts are scoped
and safely named; update the screenshot path usage in the test.afterEach
callback where testInfo.title is currently used.
- Around line 50-159: Add a new E2E test in continuation-args.spec.ts that
covers the mixed pending/server-complete continuation branch by selecting a
scenario (e.g., 'mixed-client-server-tools') via selectScenario(page, ...),
calling runTest(page) and waitForTestComplete(page, timeout, expectedCount) as
other tests do, then use getMetadata(page) and getToolCallParts(page) to assert
that a server-side tool call completed (exists in toolCallParts with expected
arguments), that a client-side continuation remained pending
(execution-complete-count or metadata shows remaining
needsClientExecution/needsApproval), and that no tool call has empty arguments;
reuse existing helpers (selectScenario, runTest, waitForTestComplete,
getToolCallParts, getMetadata) and mirror assertion patterns from the
'sequential client tool' and 'parallel client tool' tests to validate both
completed server results and the paused client continuation.

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: 7cf5bcd7-44a3-4c4d-98d5-66b0663825dc

📥 Commits

Reviewing files that changed from the base of the PR and between 8974a32 and 654fb57.

📒 Files selected for processing (1)
  • testing/e2e/tests/tools-test/continuation-args.spec.ts

@DiegoGBrisa DiegoGBrisa force-pushed the fix/continuation-chunk-emission branch from 654fb57 to 41a47c7 Compare April 10, 2026 18:59
Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

🧹 Nitpick comments (1)
testing/e2e/tests/tools-test/helpers.ts (1)

193-211: Avoid all-or-nothing failure when one tool-call argument is malformed.

At Line 203, a single bad part.arguments JSON currently falls into the outer catch and returns [], which hides other valid tool-call parts. Prefer per-part parsing with a safe {} fallback.

Proposed refactor
-    try {
-      const messages = JSON.parse(el.textContent || '[]')
+    try {
+      const messages = JSON.parse(el.textContent || '[]')
       const parts: Array<{ name: string; arguments: Record<string, unknown> }> =
         []
-      for (const msg of messages) {
-        for (const part of msg.parts || []) {
+      for (const msg of Array.isArray(messages) ? messages : []) {
+        for (const part of msg?.parts || []) {
           if (part.type === 'tool-call') {
+            let parsedArgs: Record<string, unknown> = {}
+            if (typeof part.arguments === 'string') {
+              try {
+                const value = JSON.parse(part.arguments)
+                if (value && typeof value === 'object' && !Array.isArray(value)) {
+                  parsedArgs = value as Record<string, unknown>
+                }
+              } catch {
+                parsedArgs = {}
+              }
+            } else if (
+              part.arguments &&
+              typeof part.arguments === 'object' &&
+              !Array.isArray(part.arguments)
+            ) {
+              parsedArgs = part.arguments as Record<string, unknown>
+            }
             parts.push({
               name: part.name,
-              arguments:
-                typeof part.arguments === 'string'
-                  ? JSON.parse(part.arguments)
-                  : part.arguments,
+              arguments: parsedArgs,
             })
           }
         }
       }
       return parts
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@testing/e2e/tests/tools-test/helpers.ts` around lines 193 - 211, The current
loop that builds parts treats any JSON.parse error on one part.arguments as
fatal (the outer catch returns []), so change the per-part parsing to be
resilient: inside the loop over messages and msg.parts, when part.type ===
'tool-call' parse part.arguments with a small try/catch (e.g., let args = typeof
part.arguments === 'string' ? try JSON.parse(part.arguments) catch { {} } :
part.arguments) and push { name: part.name, arguments: args } so a single
malformed argument falls back to {} and other tool-call parts are preserved;
keep the outer try/catch only for the initial JSON.parse(el.textContent || '[]')
error.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Nitpick comments:
In `@testing/e2e/tests/tools-test/helpers.ts`:
- Around line 193-211: The current loop that builds parts treats any JSON.parse
error on one part.arguments as fatal (the outer catch returns []), so change the
per-part parsing to be resilient: inside the loop over messages and msg.parts,
when part.type === 'tool-call' parse part.arguments with a small try/catch
(e.g., let args = typeof part.arguments === 'string' ? try
JSON.parse(part.arguments) catch { {} } : part.arguments) and push { name:
part.name, arguments: args } so a single malformed argument falls back to {} and
other tool-call parts are preserved; keep the outer try/catch only for the
initial JSON.parse(el.textContent || '[]') error.

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: c655db9c-0cc8-41a8-9ab2-720a5f291ce4

📥 Commits

Reviewing files that changed from the base of the PR and between 654fb57 and 41a47c7.

📒 Files selected for processing (2)
  • testing/e2e/tests/tools-test/continuation-args.spec.ts
  • testing/e2e/tests/tools-test/helpers.ts

Add 4 E2E tests verifying tool call arguments are preserved during
continuation re-executions. Without TOOL_CALL_START/ARGS emission,
clients store tool calls with empty {} arguments.

Tests:
- Single client tool args preserved after continuation
- Sequential client tool args preserved across multiple continuations
- Parallel client tool args preserved in batch continuation
- Mixed server+client tool args preserved in sequence

Also populate the `args` field on synthetic TOOL_CALL_ARGS chunks
emitted during continuation, matching adapter-emitted chunks.
@DiegoGBrisa DiegoGBrisa force-pushed the fix/continuation-chunk-emission branch from 41a47c7 to 94cc2d4 Compare April 10, 2026 19:36
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