Integrate CopilotKit (AG-UI)
Use this when your frontend uses CopilotKit and your backend is tirea-agentos-server AG-UI SSE.
Choose this path when you need frontend tools, shared state, canvas-style UX, or richer suspend/resume flows than a chat-only transport usually provides.
Best Fit
AG-UI/CopilotKit is usually the right choice when:
- you want shared agent state surfaced directly in the frontend
- some tools should execute in the browser instead of the backend
- you need human-in-the-loop approvals and resumable interactions
- the UI is more than a plain chat transcript
Prerequisites
tirea-agentos-serveris reachable (defaulthttp://localhost:8080).- AG-UI endpoint is enabled:
POST /v1/ag-ui/agents/:agent_id/runs. - Next.js frontend.
Minimum Architecture
Browser (CopilotKit components)
-> Next.js runtime route (/api/copilotkit)
-> AG-UI HttpAgent
-> Tirea AG-UI endpoint (/v1/ag-ui/agents/:agent_id/runs)
-> SSE AG-UI events back to browser
Thread hydration:
Browser / runtime
-> GET /v1/ag-ui/threads/:id/messages
-> backend returns AG-UI-encoded history
Steps
- Add frontend dependencies:
npm install @copilotkit/react-core @copilotkit/react-ui @copilotkit/runtime @ag-ui/client
- Create
lib/copilotkit-app.tsto connect CopilotKit runtime to AG-UI.
import {
CopilotRuntime,
ExperimentalEmptyAdapter,
copilotRuntimeNextJSAppRouterEndpoint,
} from "@copilotkit/runtime";
import { HttpAgent } from "@ag-ui/client";
const BACKEND_URL = process.env.BACKEND_URL ?? "http://localhost:8080";
const runtime = new CopilotRuntime({
agents: {
default: new HttpAgent({
url: `${BACKEND_URL}/v1/ag-ui/agents/default/runs`,
}) as any,
},
});
const { handleRequest } = copilotRuntimeNextJSAppRouterEndpoint({
runtime,
serviceAdapter: new ExperimentalEmptyAdapter(),
endpoint: "/api/copilotkit",
});
export { handleRequest };
- Create route handler
app/api/copilotkit/route.ts.
import { handleRequest } from "@/lib/copilotkit-app";
export const POST = handleRequest;
- Wrap app with
CopilotKitprovider inapp/layout.tsx.
"use client";
import { CopilotKit } from "@copilotkit/react-core";
import "@copilotkit/react-ui/styles.css";
export default function RootLayout({ children }: { children: React.ReactNode }) {
return (
<html lang="en">
<body>
<CopilotKit runtimeUrl="/api/copilotkit" agent="default">
{children}
</CopilotKit>
</body>
</html>
);
}
- Add chat UI in
app/page.tsxusingCopilotChatorCopilotSidebar.
Backend / Frontend Boundary
In the AG-UI path, backend and frontend can both participate in tool orchestration.
- backend remains the source of truth for thread history and durable agent state
- backend tools execute normally inside Tirea
- frontend tools are declared with
execute = "frontend"and are suspended by the backend - CopilotKit resolves those frontend interactions and resumes the run with a result or cancellation
This makes AG-UI the better fit for:
- browser-native tools
- UI approvals
- canvas updates
- generative UI surfaces
Frontend Tool Flow
When AG-UI frontend tools are enabled, the flow is:
- model selects a tool that is marked as frontend-executed
- backend does not run that tool locally
- backend emits a pending tool interaction via AG-UI
- frontend renders the tool UI or approval card
- frontend responds with
resumeorcancel - backend converts that decision into tool result semantics and continues the run
This behavior is implemented by the runtime-side pending plugin in:
crates/tirea-agentos-server/src/protocol/ag_ui/runtime.rs
Shared State Model
AG-UI works best when you treat backend thread state as authoritative and frontend state as a projection.
- backend persists thread state and messages
- frontend reads AG-UI events and history to render the current projection
- local UI state can exist, but should not replace durable agent state unless you intentionally send state overrides
Suspend / Resume And HITL
AG-UI is the stronger path for HITL flows.
Typical pattern:
- backend permission/plugin/tool logic suspends execution
- AG-UI emits a pending interaction event
- CopilotKit renders an approval or data-entry component
- user responds
- runtime sends the decision back to the backend
- backend resumes the original run using the supplied decision or tool result
Optional: parse tool-call-progress activity events
When reading raw AG-UI events, inspect ACTIVITY_SNAPSHOT /
ACTIVITY_DELTA with activityType = "tool-call-progress".
function onAgUiEvent(event: any) {
if (event?.type !== "ACTIVITY_SNAPSHOT") return;
if (event.activityType !== "tool-call-progress") return;
const node = event.content;
console.log("tool progress", node.node_id, node.status, node.progress);
}
Verify
POST /api/copilotkitstreams AG-UI events.- Chat UI receives assistant output in real time.
- Tool calls and shared state updates are reflected in the UI.
- Frontend-executed tools suspend and resume correctly.
- Persisted thread history can be rehydrated from
GET /v1/ag-ui/threads/:id/messages.
Common Errors
- Wrong AG-UI URL (
/v1/ag-ui/agents/:agent_id/runs) causes empty responses or 404. agentinCopilotKitprovider does not match runtimeagentskey.- Package version mismatch may require temporary
as anycast forHttpAgent.
Related Example
examples/copilotkit-starter/README.mdis the full-featured AG-UI + CopilotKit starterexamples/travel-ui/README.mdis the smaller travel-specific CopilotKit scenario demoexamples/research-ui/README.mdis the research-specific CopilotKit scenario demo
Key Files
examples/copilotkit-starter/lib/copilotkit-app.tsexamples/copilotkit-starter/lib/persisted-http-agent.tsexamples/travel-ui/lib/copilotkit-app.tsexamples/research-ui/lib/copilotkit-app.tsexamples/copilotkit-starter/app/api/copilotkit/route.ts
Related
- AG-UI Protocol
- Ecosystem Integrations
- Frontend Interaction and Approval Model
- HTTP API
examples/copilotkit-starter/README.mdexamples/copilotkit-starter/lib/copilotkit-app.ts