Files
crewAI/docs/edge/en/guides/frontend/predictive-state-updates.mdx
Ran Shemtov 27083f4131
Some checks failed
CodeQL Advanced / Analyze (actions) (push) Has been cancelled
CodeQL Advanced / Analyze (python) (push) Has been cancelled
Vulnerability Scan / Detect changes (push) Has been cancelled
Vulnerability Scan / pip-audit (push) Has been cancelled
Check Documentation Broken Links / Check broken links (push) Has been cancelled
Nightly Canary Release / Check for new commits (push) Has been cancelled
Nightly Canary Release / Build nightly packages (push) Has been cancelled
Nightly Canary Release / Publish nightly to PyPI (push) Has been cancelled
docs: add Frontend guides (CopilotKit + AG-UI) (#6686)
* docs: add Frontend guides section (CopilotKit + AG-UI)

Add a Frontend sub-group under Guides documenting how to build user
interfaces for CrewAI Crews and Flows with CopilotKit over the AG-UI
protocol. Pages: overview, generative UI, tool-based generative UI,
agentic generative UI, human-in-the-loop, shared state, frontend
actions, predictive state updates, and channels.

* docs: mirror Frontend guides into v1.15.5 (Latest)

Also register the Frontend sub-group and pages under the default
v1.15.5 version so the section is visible without switching to Edge.

* docs(frontend): address audit — correct APIs and claims

- Use useRenderTool for display-only tool rendering (was useFrontendTool)
- Correct state 'auto-streams' claims: snapshot at step boundaries,
  document copilotkit_emit_state for mid-step progress
- Fix setState usage to spread full state (replace, not merge)
- Add tool description to the frontend-action example
- Rewrite Channels with the real @copilotkit/channels createBot API
  (Slack + Discord adapters); drop unsupported platform claims
- Note self-hosted vs managed CopilotKit paths and pin package versions

* docs(frontend): remove versions callout from overview

* docs(frontend): drop package-generation framing from emit_state note

* docs(frontend): add generative UI spectrum (A2UI, reasoning) + Conversational Flows

Rewrite generative-ui as the controlled/declarative/open-ended spectrum;
add A2UI (declarative), Reasoning (controlled), and a Conversational Flows
page; add a backend-tools section to tool-based; note the three execution
shapes in the overview.

* docs(frontend): address review — edge-only, attribute access, safe defaults

Remove the docs/v1.15.5 mirror (versioned snapshots are cut from edge by
the release tooling; the docs-snapshots CI guard rejects manual docs/v*
writes). Use attribute access on the LiteLLM message in shared-state,
guard setState against undefined agent/recipe, and use
Field(default_factory=list) for the agent-state list.
2026-08-12 10:01:16 -07:00

143 lines
5.8 KiB
Plaintext

---
title: Predictive State Updates
description: Stream an in-progress tool call's arguments into agent state so the UI updates optimistically while the agent is still generating.
icon: gauge-high
mode: "wide"
---
## Show the work as it happens
Normally a tool call is atomic from the UI's point of view: the agent decides what to write, and your interface only sees the result once the call finishes. For a tool that produces a large document that means a long pause followed by everything snapping into place at once.
Predictive state updates remove the wait. You project a streaming tool argument onto a field of the agent's state, so as the model generates the argument token by token, that state field fills in live. A document the agent is writing appears in the editor as it is typed, not after.
<Note>
Predictive state relies on a Flow with custom state (`Flow[AgentState]`). It projects a streaming tool argument onto a state field, so there is no equivalent for a bare Crew.
</Note>
## How it compares to Shared State
Both patterns read the agent's state from the frontend, but they solve different problems:
| Pattern | What it does |
| --- | --- |
| **Predictive state** | One-way. Streams an in-progress tool argument into a state field so the UI updates *during* generation, before the call completes. |
| **[Shared State](/en/guides/frontend/shared-state)** | Two-way. The UI reads *and writes* the agent's committed state, keeping app and agent in sync across turns. |
Reach for predictive state when you want an optimistic, in-flight preview of what the agent is producing. Reach for [Shared State](/en/guides/frontend/shared-state) when the user needs to edit that state back.
## Walkthrough
This assumes you already have a Crew or Flow served over AG-UI and a CopilotKit frontend wired up. If not, start with the [Frontend Overview](/en/guides/frontend/overview).
<Steps>
<Step title="Define a Flow with custom state">
Predictive state projects a tool argument onto a state field, so your Flow needs a typed state field to receive it. Add the field you want to stream into to your `CopilotKitState` subclass.
```python
from typing import Optional
from crewai.flow.flow import Flow, start, router, listen
from litellm import acompletion
from ag_ui_crewai.sdk import copilotkit_stream, copilotkit_predict_state, CopilotKitState
WRITE_DOCUMENT_TOOL = {
"type": "function",
"function": {
"name": "write_document",
"description": "Write the full document in markdown.",
"parameters": {
"type": "object",
"properties": {
"document": {"type": "string", "description": "The document to write"},
},
},
},
}
class AgentState(CopilotKitState):
document: Optional[str] = None
class DocumentFlow(Flow[AgentState]):
@start()
@listen("route_follow_up")
async def start_flow(self):
pass
```
</Step>
<Step title="Map a state field to a tool argument">
Call `copilotkit_predict_state` **before** you start streaming the completion. It tells the runtime to project the named tool argument onto the named state field: as the `write_document` call streams its `document` argument, the `document` state field updates live.
```python
@router(start_flow)
async def chat(self):
# Map the `document` state field to the `document` argument of write_document.
# As the tool call streams, the state field updates live.
await copilotkit_predict_state({
"document": {"tool_name": "write_document", "tool_argument": "document"},
})
response = await copilotkit_stream(
await acompletion(
model="openai/gpt-4o",
messages=[
{"role": "system", "content": "Write and edit the document with write_document."},
*self.state.messages,
],
tools=[*self.state.copilotkit.actions, WRITE_DOCUMENT_TOOL],
parallel_tool_calls=False,
stream=True,
)
)
message = response.choices[0].message
self.state.messages.append(message)
```
The key is `copilotkit_predict_state({ "<state_field>": {"tool_name": ..., "tool_argument": ...} })`. Without it, the frontend would only see `document` once the tool call completed. With it, the partial argument streams onto the field while the agent is still generating.
Serve the Flow with `add_crewai_flow_fastapi_endpoint(...)` as shown in the [Frontend Overview](/en/guides/frontend/overview).
</Step>
<Step title="Read the predicted state on the frontend">
On the frontend, read the field with `useAgent` and subscribe to state changes. Because the backend is projecting the streaming argument onto `document`, this component re-renders as the agent types.
```tsx
"use client";
import { useAgent, UseAgentUpdate } from "@copilotkit/react-core/v2";
function DocumentView() {
const { agent } = useAgent({
agentId: "document",
updates: [UseAgentUpdate.OnStateChanged],
});
const document = (agent?.state as { document?: string })?.document ?? "";
return <article>{document}</article>; // updates as the agent types
}
```
The `document` field fills in progressively as the agent generates the `write_document` call, so the editor updates in real time rather than snapping in at the end.
</Step>
</Steps>
## Related
<CardGroup cols={2}>
<Card title="Shared State" icon="arrows-rotate" href="/en/guides/frontend/shared-state">
Read and write the agent's state two-way.
</Card>
<Card title="Agentic Generative UI" icon="list-check" href="/en/guides/frontend/agentic-generative-ui">
Render live agent state as it changes.
</Card>
<Card title="Tool-Based Generative UI" icon="puzzle-piece" href="/en/guides/frontend/tool-based-generative-ui">
Map agent tool calls to components.
</Card>
</CardGroup>