Skip to content

Commit bb3fab9

Browse files
committed
fix(mastra): migrate approval details to interrupt sessions
1 parent 83ef321 commit bb3fab9

4 files changed

Lines changed: 12 additions & 10 deletions

File tree

apps/website/content/docs/runtimes/mastra/how-it-connects.mdx

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -18,13 +18,13 @@ This page records the AG-UI wire behavior measured for Mastra on 2026-08-31. It
1818

1919
The service refuses to boot without `AG_UI_INTERNAL_TOKEN`, rejects any non-health route without a matching header, and maps an error from the underlying observable to a `RUN_ERROR` frame rather than dropping the socket. Any route other than `/ok` that arrives without a matching header returns `401 {"detail":"unauthorized"}`; with a valid token, an unknown path or method returns `404 {"detail":"not found"}` and an unregistered topic returns `404 {"detail":"no such topic: <topic>"}`.
2020

21-
In your own application this is still an ordinary `provideAgent({ url: '/agent' })`; the example in this repository passes a factory only because it resolves its endpoint at runtime. The token is injected by the dev proxy in front of the app, never by the browser.
21+
In your own application this is still an ordinary `provideAgent({ url: '/agent', interruptTransport: 'mastra-command' })`; the example in this repository passes a factory only because it resolves its endpoint at runtime. The token is injected by the dev proxy in front of the app, never by the browser.
2222

2323
## Interrupts arrive by both conventions
2424

2525
Mastra is the only measured runtime that signals an interrupt twice: it emits a `CUSTOM` event named `on_interrupt` **and** finishes the run with the protocol-standard interrupt outcome.
2626

27-
AWS Strands and Microsoft Agent Framework emit only the outcome. The LangGraph bridge emits only `on_interrupt`. The adapter accepts either, and within a single run the first signal it sees wins, so a runtime that emits both is handled without special-casing.
27+
AWS Strands and Microsoft Agent Framework emit only the outcome. The LangGraph bridge emits only `on_interrupt`. The adapter retains both forms in one session. The native batch drives the display projection, while `interruptSession().legacy?.value` preserves the Mastra suspend details used by the approval card.
2828

2929
## Resume uses interruptEvent
3030

@@ -40,7 +40,7 @@ Mastra reads resume data from `forwardedProps.command.interruptEvent`, carrying
4040
}
4141
```
4242

43-
That is a third distinct shape. Strands and Microsoft Agent Framework read a top-level `resume` array; the LangGraph bridge reads `forwardedProps.command.resume`. Application code passes one neutral `submit({ resume })` and the adapter derives the wire shape from how the interrupt arrived.
43+
That is a third distinct shape. Strands and Microsoft Agent Framework read a top-level `resume` array; the LangGraph bridge reads `forwardedProps.command.resume`. Application code passes one neutral `submit({ resume })`. The Mastra provider selects `interruptTransport: 'mastra-command'` explicitly because this backend emits both compatibility and native interrupts, and `auto` otherwise selects the native wire shape.
4444

4545
## Suspend and resume require persistent storage
4646

apps/website/content/docs/runtimes/mastra/overview.mdx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -113,7 +113,7 @@ The class supplies that payload and maps the two actions onto resume calls.
113113

114114
<ExampleCode file="mastra.component.ts" region="approval-actions" title="mastra.component.ts — reading the interrupt and resuming" />
115115

116-
`agent.interrupt()` carries the parsed `CUSTOM on_interrupt` payload as its `value`, and because that payload carries a tool-call id, `submit({ resume })` goes back out as `forwardedProps.command = { resume, interruptEvent: { toolCallId, runId } }` — the shape the Mastra bridge reads to reopen the suspended run.
116+
`agent.interruptSession().legacy?.value` carries the parsed `CUSTOM on_interrupt` payload alongside the native interrupt batch. The provider selects `interruptTransport: 'mastra-command'`, so `submit({ resume })` goes back out as `forwardedProps.command = { resume, interruptEvent: { toolCallId, runId } }` — the shape the Mastra bridge reads to reopen the suspended run.
117117

118118
## What the integration demonstrates
119119

cockpit/runtimes/mastra/angular/src/app/app.config.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ export const appConfig: ApplicationConfig = {
1111
}
1212
return {
1313
url: connection.url,
14+
interruptTransport: 'mastra-command',
1415
};
1516
}),
1617
],

cockpit/runtimes/mastra/angular/src/app/mastra.component.ts

Lines changed: 7 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -50,8 +50,9 @@ interface PackingList {
5050
* packing list.
5151
* - A suspended tool (`reserve_campsite`) surfaces BOTH interrupt
5252
* conventions: CUSTOM `on_interrupt` (payload carrying toolCallId + runId)
53-
* and the protocol-standard RUN_FINISHED interrupt outcome. The reducer's
54-
* first-signal-wins rule keeps the Mastra-shaped payload, so
53+
* and the protocol-standard RUN_FINISHED interrupt outcome. The session
54+
* retains the Mastra payload alongside the native batch. The explicit
55+
* `mastra-command` transport in app.config.ts ensures
5556
* `submit({ resume })` goes out as
5657
* `forwardedProps.command = { resume, interruptEvent: { toolCallId, runId } }`
5758
* — exactly what the Mastra bridge requires to resume the suspended run.
@@ -251,13 +252,13 @@ export class MastraComponent {
251252

252253
// #region approval-actions
253254
/**
254-
* The pending Mastra suspend. The reducer stores the parsed CUSTOM
255+
* The pending Mastra suspend. The session retains the parsed CUSTOM
255256
* `on_interrupt` payload: `{ type: 'mastra_suspend', toolCallId, toolName,
256-
* suspendPayload, args, resumeSchema, runId }` (first-signal-wins over the
257-
* RUN_FINISHED outcome that follows it on the wire).
257+
* suspendPayload, args, resumeSchema, runId }` alongside the native
258+
* RUN_FINISHED outcome that follows it on the wire.
258259
*/
259260
private readonly suspendValue = computed(() => {
260-
return this.agent.interrupt?.()?.value as
261+
return this.agent.interruptSession().legacy?.value as
261262
| { toolName?: string; suspendPayload?: { site?: string; nights?: number; total_usd?: number } }
262263
| undefined;
263264
});

0 commit comments

Comments
 (0)