Commit 19a8658
fix(signals): add subscription-native tool approval (#17311)
## Summary
- Add subscription-native approve/decline routes and client helpers for
tool approvals.
- Wire React `useChat()` to use the JSON subscription approval path when
subscribed.
- Restore suspended memory thread/resource in `resumeStream()` so
resumed approval chunks register to the active thread subscription.
- Document subscription-native approval in signals, client-js, and
server route docs.
## Stack navigation
Stack position: 3/5.
- Previous: #17310
- Next: #17312
## Test plan
- `pnpm --filter @mastra/core test
src/agent/__tests__/agent-signals.test.ts
src/agent/__tests__/resume-span-tracing.test.ts --bail 1 --reporter=dot`
- `pnpm --filter ./packages/server test
src/server/handlers/agents.test.ts --bail 1 --reporter=dot`
- `pnpm --filter @mastra/client-js test src/resources/agent.test.ts
--bail 1 --reporter=dot`
- `pnpm --filter @mastra/react test src/agent/hooks.test.ts --bail 1
--reporter=dot`
- `pnpm --filter @mastra/core build:lib`
- `pnpm --filter @mastra/client-js build:lib`
- `pnpm --filter @mastra/react build:js`
- `pnpm --filter @mastra/server build:lib`
- `pnpm --filter ./packages/playground build`
- `pnpm --filter ./packages/server check:permissions`
- `pnpm --filter ./packages/server check:core-imports`
- `pnpm run prettier:changed`
<!-- This is an auto-generated comment: release notes by coderabbit.ai
-->
## ELI5 (Explain Like I'm 5)
If a paused AI needs permission to continue, you can now approve or
decline it directly in the same chat subscription and the AI will resume
speaking in that same conversation; you immediately get a small JSON
confirmation that the approval was received.
## Overview
Implements subscription-native tool approval/decline so paused tool
calls are acknowledged with a JSON response and resumed output is
delivered through the existing thread subscription (no separate
continuation stream). Changes span server routes and schemas, core agent
runtime and APIs, client-js SDK, React hook integration, tests,
playground helpers, and documentation. Also ensures suspended-run
memory/thread context is preserved on resume so resumed chunks attach to
the active subscription.
## Key changes
- Server (packages/server)
- Add POST endpoints for subscription-native approvals:
- POST /agents/:agentId/approve-tool-call-for-thread
- POST /agents/:agentId/decline-tool-call-for-thread
- Add Zod schemas (toolCallSubscriptionBodySchema,
toolCallSubscriptionResponseSchema).
- Handlers validate effective thread access, merge requestContext
safely, sanitize body, and call the core agent thread-scoped approval
helpers.
- Thread ownership validation was added in review to prevent
cross-thread approvals.
- Core (packages/core)
- Add getActiveThreadRunId() to look up an active runId for a (threadId,
resourceId) scope (treating suspended runs as active).
- resumeStream(): restore memory.thread/resource from suspended-run
snapshot when resuming (without overwriting caller-provided memory).
- Add approveToolCallForThread and declineToolCallForThread helpers
which require an active thread-scoped run, default memory keys from
thread/resource, call the generic approve/decline flow, and return {
accepted: true; runId; toolCallId? }.
- Thread-stream runtime: publish run-suspended, keep reservation records
for suspended runs, treat suspended as active for queuing and resume,
and centralize active-run lookup.
- Client SDKs
- client-js: add Agent methods approveToolCallForThread /
declineToolCallForThread and generated route types / CLI metadata for
the new endpoints.
- react: useChat now tracks pending tool-approval IDs, exposes
isAwaitingToolApproval, treats tool-call-approval and
tool-call-suspended chunks as non-running, and routes approve/decline to
thread-native APIs when subscribed.
- Playground / runtime state
- Add getCanSendWhileStreaming helper and use it in
MastraRuntimeProvider.
- MastraRuntimeProvider updated to include isAwaitingToolApproval
gating.
- Tests
- Core: resumed-run delivery and queuing-behind-suspended-run tests;
end-to-end subscription-native approval test covering memory restore.
- Server: schema and handler tests for the new routes and authorization.
- client-js: tests for new Agent methods calling the new endpoints.
- react: extensive useChat tests for subscription approval flows and
routing to thread-native approvals.
- playground: tests updated to include isAwaitingToolApproval.
- Docs
- New and updated docs describing subscription-native approve/decline
(JSON ack + resumed chunks via thread subscription) and guidance
distinguishing for-thread APIs vs legacy continuation-stream APIs.
- client-js and server route references updated with examples and route
metadata.
## CI / Review notes (actionable)
- CI blocker: the shared server-adapter integration tests
(express/fastify/hono/koa) fail with 500s for the two new routes because
the shared test-helpers do not mock the new agent thread-approval
methods; the real implementations run in the synthetic test context and
getActiveThreadRunId() can throw when no active run exists.
- Immediate test fix: add the thread-approval spies to the central mock
setup (server-adapters/_test-utils/src/test-helpers.ts). Example mocks
to add:
- vi.spyOn(agent, 'approveToolCallForThread' /* or
approveToolCallAndSubscribe if that helper is present
*/).mockResolvedValue({ accepted: true, runId: 'test-run', toolCallId:
'test-tool-call' } as any);
- vi.spyOn(agent, 'declineToolCallForThread' /* or
declineToolCallAndSubscribe */).mockResolvedValue({ accepted: true,
runId: 'test-run', toolCallId: 'test-tool-call' } as any);
- Adding these spies alongside existing tool-call mocks in the shared
test-helpers will unblock adapter tests.
- Security / ownership
- Review feedback to validate thread ownership was applied in the
subscription route handlers; the author addressed this in follow-up
changes. Verify handlers call the same validateThreadOwnership check
used by abort-thread routes before delegating.
## Test plan
Run the package-scoped tests/build/checks listed in the PR (package
filter/test commands included in the PR) and the server
permission/core-import checks, then run prettier on changed files.
## Status / Next steps
- Add the two mock spies to
server-adapters/_test-utils/src/test-helpers.ts to make adapter tests
green (CI blocker).
- Confirm thread-ownership validation is present and correct in the
subscription routes (review indicates it was added).
- Once CI passes and ownership validation is confirmed, this is ready to
merge.
<!-- end of auto-generated comment: release notes by coderabbit.ai -->
---------
Co-authored-by: Mastra Code (openai/gpt-5.5) <noreply@mastra.ai>1 parent b0771a4 commit 19a8658
23 files changed
Lines changed: 1322 additions & 39 deletions
File tree
- .changeset
- client-sdks
- client-js/src
- resources
- react/src/agent
- docs/src/content/en
- docs/agents
- reference
- client-js
- server
- packages
- cli/src/commands/api
- core/src/agent
- __tests__
- playground/src/services
- __tests__
- server/src/server
- handlers
- schemas
- server-adapter/routes
- server-adapters/_test-utils/src
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
| 1 | + | |
| 2 | + | |
| 3 | + | |
| 4 | + | |
| 5 | + | |
| 6 | + | |
| 7 | + | |
| 8 | + | |
| 9 | + | |
| 10 | + | |
| 11 | + | |
| 12 | + | |
| 13 | + | |
| 14 | + | |
| 15 | + | |
| 16 | + | |
| 17 | + | |
| 18 | + | |
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
89 | 89 | | |
90 | 90 | | |
91 | 91 | | |
| 92 | + | |
| 93 | + | |
| 94 | + | |
| 95 | + | |
| 96 | + | |
| 97 | + | |
| 98 | + | |
| 99 | + | |
| 100 | + | |
| 101 | + | |
| 102 | + | |
| 103 | + | |
| 104 | + | |
| 105 | + | |
| 106 | + | |
| 107 | + | |
| 108 | + | |
| 109 | + | |
| 110 | + | |
| 111 | + | |
| 112 | + | |
| 113 | + | |
| 114 | + | |
| 115 | + | |
| 116 | + | |
| 117 | + | |
| 118 | + | |
| 119 | + | |
| 120 | + | |
| 121 | + | |
| 122 | + | |
| 123 | + | |
| 124 | + | |
| 125 | + | |
| 126 | + | |
| 127 | + | |
| 128 | + | |
| 129 | + | |
| 130 | + | |
| 131 | + | |
| 132 | + | |
| 133 | + | |
| 134 | + | |
| 135 | + | |
| 136 | + | |
| 137 | + | |
| 138 | + | |
| 139 | + | |
| 140 | + | |
| 141 | + | |
| 142 | + | |
| 143 | + | |
92 | 144 | | |
93 | 145 | | |
94 | 146 | | |
| |||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
2717 | 2717 | | |
2718 | 2718 | | |
2719 | 2719 | | |
| 2720 | + | |
| 2721 | + | |
| 2722 | + | |
| 2723 | + | |
| 2724 | + | |
| 2725 | + | |
| 2726 | + | |
| 2727 | + | |
| 2728 | + | |
| 2729 | + | |
| 2730 | + | |
| 2731 | + | |
| 2732 | + | |
| 2733 | + | |
| 2734 | + | |
| 2735 | + | |
| 2736 | + | |
2720 | 2737 | | |
2721 | 2738 | | |
2722 | 2739 | | |
| |||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
6942 | 6942 | | |
6943 | 6943 | | |
6944 | 6944 | | |
| 6945 | + | |
| 6946 | + | |
| 6947 | + | |
| 6948 | + | |
| 6949 | + | |
| 6950 | + | |
| 6951 | + | |
| 6952 | + | |
| 6953 | + | |
| 6954 | + | |
| 6955 | + | |
| 6956 | + | |
| 6957 | + | |
| 6958 | + | |
| 6959 | + | |
| 6960 | + | |
| 6961 | + | |
| 6962 | + | |
| 6963 | + | |
| 6964 | + | |
| 6965 | + | |
| 6966 | + | |
| 6967 | + | |
| 6968 | + | |
| 6969 | + | |
| 6970 | + | |
| 6971 | + | |
| 6972 | + | |
| 6973 | + | |
| 6974 | + | |
| 6975 | + | |
| 6976 | + | |
| 6977 | + | |
| 6978 | + | |
| 6979 | + | |
| 6980 | + | |
| 6981 | + | |
| 6982 | + | |
| 6983 | + | |
| 6984 | + | |
| 6985 | + | |
| 6986 | + | |
| 6987 | + | |
| 6988 | + | |
| 6989 | + | |
| 6990 | + | |
| 6991 | + | |
| 6992 | + | |
6945 | 6993 | | |
6946 | 6994 | | |
6947 | 6995 | | |
| |||
84754 | 84802 | | |
84755 | 84803 | | |
84756 | 84804 | | |
| 84805 | + | |
84757 | 84806 | | |
84758 | 84807 | | |
84759 | 84808 | | |
| |||
85221 | 85270 | | |
85222 | 85271 | | |
85223 | 85272 | | |
| 85273 | + | |
| 85274 | + | |
| 85275 | + | |
85224 | 85276 | | |
85225 | 85277 | | |
85226 | 85278 | | |
| |||
0 commit comments