Skip to content
This repository was archived by the owner on Apr 17, 2026. It is now read-only.

feat(harness): store and serialize per-tool args/result in subagent execution#8

Merged
Kitenite merged 5 commits into
superset-sh:mainfrom
michalkopanski:mk/subagent-tool-args-result
Mar 31, 2026
Merged

feat(harness): store and serialize per-tool args/result in subagent execution#8
Kitenite merged 5 commits into
superset-sh:mainfrom
michalkopanski:mk/subagent-tool-args-result

Conversation

@michalkopanski
Copy link
Copy Markdown

@michalkopanski michalkopanski commented Mar 30, 2026

Summary

Subagent tool calls now carry their input args and output result through the full pipeline so UIs can render them as proper collapsible tool rows (e.g. BashTool showing the command + stdout) instead of a cloud of name badges.

Related PRs

  • Chat UX Enhancements superset#3039 — Companion UI PR: consumes this data via parseSubagentToolResult.ts and SubagentInnerToolCall to render full per-tool detail in the chat interface.

Changes

  • toolCallLog entries now store args (from tool-call chunk) and result (from tool-result chunk)
  • buildSubagentMeta emits a <subagent-tool-calls> JSON block before the existing <subagent-meta> tag; results are truncated at 2 000 chars to keep the stored string bounded
  • parseSubagentMeta reads the new block when present, falls back to the legacy name:status list — fully backward compatible
  • ActiveSubagentState.toolCalls entries now include args and result so the live (streaming) view is equally rich
  • subagent_tool_start handler stores subToolArgs on the live entry
  • subagent_tool_end handler stores subToolResult, matched by name + null result (correctly handles the same tool being called multiple times)

Summary by CodeRabbit

  • New Features

    • Subagent tool-call metadata now includes per-call IDs, arguments, and serialized results so UIs can show distinct repeated calls and their inputs/outputs.
    • Metadata now includes a detailed encoded block with bounded/truncated args and results.
  • Bug Fixes

    • Improved matching of tool-result events to the correct prior call to ensure results attach to the right invocation.
  • Tests

    • Added tests for matching, truncation, parsing fallback, and unsafe-result serialization.
  • Documentation

    • Added a changeset describing the new metadata exposure.

…xecution

Subagent tool calls now carry their input args and output result through
the full pipeline so UIs can render them as proper collapsible tool rows
instead of a cloud of name badges.

Changes:
- `toolCallLog` entries now store `args` (from tool-call chunk) and
  `result` (from tool-result chunk)
- `buildSubagentMeta` emits a `<subagent-tool-calls>` JSON block before
  the existing `<subagent-meta>` tag; results are truncated at 2000 chars
- `parseSubagentMeta` reads the new block when present, falls back to
  the legacy `name:status` list for backward compatibility
- `ActiveSubagentState.toolCalls` entries now include `args` and `result`
  so live (streaming) state is equally rich
- `subagent_tool_start` handler stores `subToolArgs` on the live entry
- `subagent_tool_end` handler stores `subToolResult` on the live entry,
  matched by name + null result (handles same-tool repeated calls)
@coderabbitai
Copy link
Copy Markdown

coderabbitai Bot commented Mar 30, 2026

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Run ID: 7bb396d1-152f-43c3-99a7-37cd4fc27fe4

📥 Commits

Reviewing files that changed from the base of the PR and between f1e6a5c and 9b57615.

📒 Files selected for processing (6)
  • .changeset/subagent-tool-call-details.md
  • packages/core/src/harness/display-state.test.ts
  • packages/core/src/harness/harness.ts
  • packages/core/src/harness/subagent-tool.test.ts
  • packages/core/src/harness/tools.ts
  • packages/core/src/harness/types.ts
✅ Files skipped from review due to trivial changes (1)
  • .changeset/subagent-tool-call-details.md
🚧 Files skipped from review as they are similar to previous changes (1)
  • packages/core/src/harness/types.ts

Walkthrough

Subagent tool-call tracking was expanded: tool-call records now include toolCallId, args, and result; lifecycle events carry optional subToolCallId; metadata gained a base64-encoded <subagent-tool-calls> JSON block; parsing and serialization logic updated, plus related tests and types adjusted.

Changes

Cohort / File(s) Summary
Harness runtime update
packages/core/src/harness/harness.ts
Populate tool-call entries with toolCallId (nullable), args (nullable) and initialize result: null. Match subagent_tool_end to entries preferring same subToolCallId or the last pending entry; serialize subToolResult into result and set isError. Added serializeSubagentToolResult helper.
Metadata, serialization & parsing
packages/core/src/harness/tools.ts
Emit subagent_tool_start/subagent_tool_end with optional subToolCallId and richer payloads; add <subagent-tool-calls encoding="base64"> JSON block with per-call toolCallId, name, isError, args, result; add truncation/sanitization and base64 helpers; preserve legacy <subagent-meta .../> fallback and update parseSubagentMeta to prefer the new block.
Types
packages/core/src/harness/types.ts
Added exported HarnessSubagentToolCall interface (toolCallId, name, isError, args, result); changed ActiveSubagentState.toolCalls to HarnessSubagentToolCall[]; added optional subToolCallId?: string to subagent_tool_start / subagent_tool_end event payload types.
Tests
packages/core/src/harness/display-state.test.ts, packages/core/src/harness/subagent-tool.test.ts
Updated tests to assert new subToolCallId, full tool-call objects (toolCallId, name, isError, args, result), added cases for multiple sub-tool calls matching by subToolCallId, non-JSON-serializable results fallback, metadata truncation behavior, and base64/legacy parsing robustness.
Release metadata
.changeset/subagent-tool-call-details.md
New changeset documenting the minor version bump and summary of added subagent tool-call details in metadata and display state.

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~45 minutes

🚥 Pre-merge checks | ✅ 2 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 33.33% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (2 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title clearly summarizes the main change: storing and serializing per-tool args/result in subagent execution, which aligns with the changeset.

✏️ 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.

@Kitenite Kitenite marked this pull request as ready for review March 31, 2026 05:08
Copy link
Copy Markdown

@cubic-dev-ai cubic-dev-ai Bot left a comment

Choose a reason for hiding this comment

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

3 issues found across 3 files

Prompt for AI agents (unresolved issues)

Check if these issues are valid — if so, understand the root cause of each and fix them. If appropriate, use sub-agents to investigate and fix each issue separately.


<file name="packages/core/src/harness/tools.ts">

<violation number="1" location="packages/core/src/harness/tools.ts:579">
P2: Tool-call metadata size is not bounded because `args` is serialized without truncation while only `result` is capped.</violation>

<violation number="2" location="packages/core/src/harness/tools.ts:601">
P2: Tag-delimited JSON parsing is unsafe: embedded `</subagent-tool-calls>` in tool result content truncates the capture and breaks `JSON.parse`.</violation>

<violation number="3" location="packages/core/src/harness/tools.ts:622">
P2: `parseSubagentMeta` now strips `<subagent-tool-calls>` content even when parsing/metadata validation fails, causing silent loss of legitimate result text.</violation>
</file>

Reply with feedback, questions, or to request a fix. Tag @cubic-dev-ai to re-run a review.

Comment thread packages/core/src/harness/tools.ts Outdated
Comment thread packages/core/src/harness/tools.ts Outdated
Comment thread packages/core/src/harness/tools.ts Outdated
Copy link
Copy Markdown

@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.

Actionable comments posted: 3

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

Inline comments:
In `@packages/core/src/harness/harness.ts`:
- Around line 2659-2664: The assignment to tc.result uses JSON.stringify on
event.subToolResult (unknown) which can throw (e.g., BigInt or circular), and
because this occurs inside applyDisplayStateUpdate() called from emit() without
error handling it can abort before dispatchToListeners(); wrap the stringify in
a safe guard: detect if subToolResult is a string and keep it, otherwise attempt
JSON.stringify in a try/catch and on error fall back to a safe representation
(e.g., String(event.subToolResult) or a sentinel like "[unserializable]" or
null) so tc.result never throws; update the logic around tc.result and the
handling of event.subToolResult in applyDisplayStateUpdate() to use this guarded
conversion.

In `@packages/core/src/harness/tools.ts`:
- Around line 575-586: The embedded JSON in the <subagent-tool-calls> tag can
contain the sentinel sequence and break the non‑greedy parser; instead serialize
the toolCalls payload (the logic that builds toolDetails using truncateToolData
and tc entries), base64‑encode that JSON, and emit it as <subagent-tool-calls
encoding="base64">BASE64_PAYLOAD</subagent-tool-calls> (keep the surrounding
meta emission that includes modelId, durationMs, tools unchanged). Also update
parseSubagentMeta() to detect encoding="base64", base64‑decode the tag content
before calling JSON.parse, and apply the same change to the other similar block
around the tool serialization (the second occurrence near the 601–617 region).
Ensure you still set isError defaulting via tc.isError ?? false and preserve
existing truncation via truncateToolData when creating the JSON prior to
encoding.

In `@packages/core/src/harness/types.ts`:
- Line 468: The toolCalls entry type needs a stable per-invocation ID: add a
string property (e.g., subToolCallId) to the toolCalls array item type in
types.ts and update any code that constructs these entries so it populates
subToolCallId from the stream events. Carry subToolCallId through the
subagent_tool_start and subagent_tool_end event handlers (the places that
emit/consume these events in tools.ts and harness.ts) and update the matching
logic in harness.ts (the routine that currently guesses by name and args) to
match on subToolCallId instead of only name/args so repeated same-name calls are
unambiguous.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Run ID: fc027137-27df-4535-9d57-f29b71200493

📥 Commits

Reviewing files that changed from the base of the PR and between ab2b6f5 and f1e6a5c.

📒 Files selected for processing (3)
  • packages/core/src/harness/harness.ts
  • packages/core/src/harness/tools.ts
  • packages/core/src/harness/types.ts

Comment thread packages/core/src/harness/harness.ts Outdated
Comment thread packages/core/src/harness/tools.ts Outdated
Comment thread packages/core/src/harness/types.ts Outdated
@Kitenite Kitenite merged commit 06fc880 into superset-sh:main Mar 31, 2026
19 of 22 checks passed
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants