You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
fix(mcp): project a streamed Agent.Progress fallback to notifications/progress (#448) (#498)
* fix(mcp): project a streamed Agent.Progress fallback to notifications/progress (#448)
* chore: changeset PR number
* fix(cli): draw the TTY progress line from a streamed Agent.Progress fallback too (#448)
Project an `Agent.Progress` node streamed in a `Suspense` fallback (any `shell`/`replace` document) to `notifications/progress` when the MCP request carries `_meta.progressToken`, under the same monotonic `progress` rule as `progress.report()` so a re-streamed fallback or an explicit report of the same step is never duplicated; the rendered CLI's interactive TTY draws its in-place progress line from the same streamed node. A fallback alone is now enough on both surfaces; `announce()`-style shims that repeat the fallback message through `progress.report()` are unnecessary. Fixes #448. (#498)
Copy file name to clipboardExpand all lines: docs/framework-mode.md
+1Lines changed: 1 addition & 0 deletions
Display the source diff
Display the rich diff
Original file line number
Diff line number
Diff line change
@@ -210,6 +210,7 @@ The final Agent Document of a tool route lowers to one `CallToolResult`:
210
210
|`Agent.Image`, `Agent.Audio`, `Agent.Resource`| Native `image`, `audio`, and `resource_link` blocks; a host without that capability fails the projection closed unless a text fallback is selected. |
211
211
|`Agent.Result value`|`structuredContent` when the value is a JSON object; a non-object value emits none and is never wrapped. |
212
212
|`Agent.Result metadata`|`CallToolResult._meta`. It must be a JSON object (snapshotted through the same wire boundary as `structuredContent`); anything else fails the projection closed with `McpProjectionError('invalid-result-metadata')`. Listing-level `_meta` still comes from static `config._meta`, so the MCP Apps convention stamps `_meta.ui.resourceUri` on both halves. In `config._meta.ui.resourceUri`, reference the App route instead of repeating its `ui://` literal: `appResourceUri('dashboard')` from `agent-bundle/routes` resolves at compile time to that App route's `config.resourceUri`, and a `const` string literal imported from a relative sibling module (`import { DASHBOARD_URI } from '../constants'`) is accepted too and stays available at run time for the result half. |
213
+
|`Agent.Progress`| Never a `content` block. Streamed inside a `shell` or `replace` document — normally as a `Suspense` fallback — it projects to one `notifications/progress` (`progress` from `completed`, plus `message` and `total` when present) when the request carried `_meta.progressToken`; a request without a token gets none. The same monotonic rule applies as to `progress.report()`: each notification's `progress` must exceed the last, so a fallback re-streamed on the next chunk, or one an explicit report already announced with the same `completed`, is not repeated. A fallback alone is enough — an `announce()`-style helper that repeats the fallback message through `progress.report()` adds nothing (#448). A progress node in the final document is content only. The rendered CLI's interactive TTY draws its in-place progress line from the same streamed node (redrawn only when the fallback changes); piped Markdown, `--json`, and `--ndjson` never print it. |
213
214
|`Agent.Error code message`|`isError: true` plus one text block `[<code>] <message>`. The wire has no error-code field, so the code is deliberately kept in the text (the routed CLI prints the same `**[code]** message` form); choose codes that read well to the model. |
214
215
|`resultSchema`|`outputSchema` in `tools/list`**only when the schema describes an object** (`z.object`, `z.record`, a discriminated union of objects). The MCP specification requires every result of a tool that declares `outputSchema` to carry `structuredContent`, so a text-only route declares `resultSchema = z.undefined()` (or any non-object schema), advertises no `outputSchema`, and returns no `structuredContent`. An object schema keeps the SDK's fail-closed output validation on every call. |
0 commit comments