Skip to content

fix(session): preserve tool metadata across pending→running transition#20210

Open
rmk40 wants to merge 2 commits intoanomalyco:devfrom
rmk40:test/subagent-click-metadata-race
Open

fix(session): preserve tool metadata across pending→running transition#20210
rmk40 wants to merge 2 commits intoanomalyco:devfrom
rmk40:test/subagent-click-metadata-race

Conversation

@rmk40
Copy link
Copy Markdown
Contributor

@rmk40 rmk40 commented Mar 31, 2026

Issue for this PR

Closes #20184

Type of change

  • Bug fix
  • New feature
  • Refactor / code improvement
  • Documentation

What does this PR do?

The AI SDK fires tool execute() as a detached promise before the processor handles the tool-call stream event. When execute() calls ctx.metadata({sessionId}), the processor's tool-call handler overwrites the DB with a fresh {status: "running", input, time} state that drops the metadata. This makes subagent sessions unclickable in the TUI because the TUI reads state.metadata.sessionId for navigation.

The fix adds a synchronous toolMetadata map on the processor context. setToolMetadata() on the Handle writes to this map immediately when the metadata callback fires. The tool-call handler then reads from the map and merges title/metadata into the running state. prompt.ts's metadata callback calls setToolMetadata() synchronously before its existing async DB update, so metadata is captured regardless of event ordering.

Depends on #20208 for the test fixtures.

Related: #20183

How did you verify your code works?

  • E2E regression test (test/session/metadata-race.test.ts) that goes through the full production path: ToolRegistry.registerSessionPrompt.loopresolveToolsctx.metadata()setToolMetadata → processor tool-call handler. Uses the shared Anthropic server fixture from test: add reusable fixtures for E2E testing with real AI SDK pipeline #20208 with real AI SDK streamText. Asserts metadata.sessionId is present on the running tool part in the DB.
  • Test passes 3/3 consistently (~1s each), no flakiness.
  • Test does not compile without the fix (setToolMetadata missing from Handle), confirming it catches the regression.
  • Existing prompt-effect.test.ts (23 tests) and processor-effect.test.ts (10 tests) still pass.
  • Manual testing confirmed subagent sessions are clickable again.

Screenshots / recordings

N/A — data layer fix, not UI change.

Checklist

  • I have tested my changes locally
  • I have not included unrelated changes in this PR

@github-actions
Copy link
Copy Markdown
Contributor

The following comment was made by an LLM, it may be inaccurate:

Based on my search, I found a related PR:

#20183 - "fix(session): preserve metadata in tool-call handler for subagent click navigation"

This PR is related to your current PR (#20210) because both address the same issue with preserving tool metadata for subagent navigation in the TUI. Your PR (#20210) is actually listed as "Related: #20183" in its description, indicating they're addressing the same root problem but may have different approaches or this PR might be a refinement/follow-up.

rmk40 added 2 commits March 31, 2026 00:12
Add two shared test fixtures that enable E2E tests through the real
AI SDK streamText pipeline without mocking:

- test/fixture/anthropic.ts: fake Anthropic HTTP server with SSE
  response helpers (toolResponse, textResponse, waitRequest, deferred)
- test/fixture/prompt-layers.ts: full SessionPrompt Effect layer stack
  with real LLM.defaultLayer and no-op stubs for MCP/LSP/FileTime

These fixtures reduce boilerplate for tests that need to exercise the
complete prompt pipeline (tool registration, resolveTools, processor
event handling) against a fake provider.

Closes anomalyco#20206
The AI SDK fires tool execute() as a detached promise before the
processor handles the tool-call stream event. When execute() calls
ctx.metadata({sessionId}), the processor's tool-call handler
overwrites the DB with a fresh running state that has no metadata,
making subagent sessions unclickable in the TUI.

- Add synchronous toolMetadata side-channel on processor context
- setToolMetadata() on Handle writes to the map immediately
- tool-call handler reads and merges metadata from the side-channel
- prompt.ts metadata callback calls setToolMetadata() before the
  async DB update, ensuring metadata is captured regardless of
  event ordering
- Add E2E regression test using fake Anthropic HTTP server through
  the real AI SDK streamText pipeline with gate-based assertion of
  running-state metadata

Closes anomalyco#20184
@rmk40 rmk40 force-pushed the test/subagent-click-metadata-race branch from 86cd7c6 to eb71403 Compare March 31, 2026 07:14
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Clicking on subagent labels in TUI does not navigate to subagent session

1 participant