showcase/shell-docs/src/content/docs/integrations/mastra/shared-state/predictive-state-updates.mdx
import RunAndConnect from "@/snippets/integrations/mastra/run-and-connect.mdx" import { IframeSwitcher } from "@/components/content"
<IframeSwitcher id="mastra-state-streaming-example" exampleUrl="https://feature-viewer.copilotkit.ai/mastra/feature/shared_state?sidebar=false&chatDefaultOpen=false" codeUrl="https://feature-viewer.copilotkit.ai/mastra/feature/shared_state?view=code&sidebar=false&codeLayout=tabs" exampleLabel="Demo" codeLabel="Code" height="700px" />
<Callout type="info"> This example demonstrates streaming shared state in the [CopilotKit Feature Viewer](https://feature-viewer.copilotkit.ai/mastra/feature/shared_state). </Callout>An agent's working memory usually surfaces to the UI once, when a run finishes. But a single run can take many seconds and write a lot of content — a drafted document, a plan, a summary — that the user would rather watch appear as it is generated.
Agent-native applications reflect what the agent is doing to the end-user as continuously as possible. CopilotKit enables this for Mastra by streaming working-memory updates to the frontend token-by-token, so agent.state grows live during the run instead of jumping to the final value at the end.
Use this when you want to give the user real-time feedback about what your agent is producing, specifically to:
Mastra injects a built-in updateWorkingMemory tool whenever working memory is enabled. When the agent calls it during a run, CopilotKit's Mastra integration intercepts the tool call's streaming arguments, parses the growing payload, and emits an initial STATE_SNAPSHOT followed by incremental STATE_DELTA updates against the working-memory schema. The frontend's useAgent subscription re-renders on every delta.
const runtime = new CopilotRuntime({
agents: MastraAgent.getLocalAgents({ mastra }),
});
```ts title="mastra/agents/streaming-agent.ts"
import { openai } from "@ai-sdk/openai";
import { Agent } from "@mastra/core/agent";
import { LibSQLStore } from "@mastra/libsql";
import { Memory } from "@mastra/memory";
import { z } from "zod";
// 1. Define the streamed state schema
export const StreamingAgentState = z.object({
document: z.string().default(""),
});
// 2. Create the agent with working memory enabled
export const streamingAgent = new Agent({
name: "Streaming Agent",
model: openai("gpt-4o"),
// The prompt drives the model to write the full document straight into
// working memory via the built-in updateWorkingMemory tool, rather than
// pasting it into a chat message.
instructions: `You are a collaborative writing assistant. Whenever the user asks you to write, draft, or revise anything, call the \`updateWorkingMemory\` tool with the FULL content under the \`document\` field. Never paste the document into a chat message — it belongs in shared state, and the UI renders it live as you stream it.`,
memory: new Memory({
storage: new LibSQLStore({ id: "mastra-storage", url: ":memory:" }),
options: {
workingMemory: {
enabled: true, // [!code highlight]
schema: StreamingAgentState, // [!code highlight]
},
},
}),
});
```
```tsx title="ui/app/page.tsx"
import { useAgent, UseAgentUpdate } from "@copilotkit/react-core"; // [!code highlight]
const YourMainContent = () => {
// [!code highlight:4]
const { agent } = useAgent({
agentId: "streamingAgent",
updates: [UseAgentUpdate.OnStateChanged, UseAgentUpdate.OnRunStatusChanged],
});
const document = (agent.state as { document?: string })?.document ?? "";
return (
<div>
<h1>Document {agent.isRunning && <span>· LIVE</span>}</h1>
<pre>{document || "Ask the agent to write something…"}</pre>
</div>
);
};
```