showcase/shell-docs/src/content/docs/backend/agent-runner.mdx
Every CopilotKit runtime delegates agent execution and persistence to an
AgentRunner. The runner turns POST /agent/:id/run into a live stream of
AG-UI events, remembers a thread so POST /agent/:id/connect can attach to it,
and stops a run on demand. Pick or subclass a runner when you need to control
where conversation state lives.
AgentRunner is an abstract class with four methods, mirroring the runtime's
HTTP routes:
import type { Observable } from "rxjs";
import type { BaseEvent } from "@ag-ui/client";
abstract class AgentRunner {
// Start a run; returns the stream of AG-UI events.
abstract run(request: AgentRunnerRunRequest): Observable<BaseEvent>;
// Re-attach to an existing thread's stream (reconnect / refresh).
abstract connect(request: AgentRunnerConnectRequest): Observable<BaseEvent>;
// Is a run currently active on this thread?
abstract isRunning(request: AgentRunnerIsRunningRequest): Promise<boolean>;
// Stop the active run on this thread.
abstract stop(request: AgentRunnerStopRequest): Promise<boolean | undefined>;
}
run receives the threadId, the cloned agent, the AG-UI RunAgentInput, and
any persistedInputMessages. connect receives the threadId (plus optional
headers and a joinCode). The runner owns whatever storage backs those threads.
| Runner | Import | Use it for |
|---|---|---|
InMemoryAgentRunner | @copilotkit/runtime/v2 | The default v2 runner. Stores thread runs in process memory. Use it for local development, single-instance deployments, or as a base class to extend. |
IntelligenceAgentRunner | @copilotkit/runtime/v2 | Backs the Intelligence Platform with durable threads, cross-instance persistence, and threads/history features. Used automatically on an Intelligence runtime. |
TelemetryAgentRunner | @copilotkit/runtime | Legacy wrapper behavior. The root runtime composes telemetry around a runner when telemetry is enabled; @copilotkit/runtime/v2 does not. |
If you don't pass a runner, the runtime uses InMemoryAgentRunner. Because it
holds threads in process memory, history is lost on restart and is not shared
across instances. For a horizontally scaled or restart-resilient deployment,
move to the Intelligence Platform's IntelligenceAgentRunner or supply your own
runner backed by your datastore.
import { CopilotRuntime, BuiltInAgent, InMemoryAgentRunner } from "@copilotkit/runtime/v2";
const runtime = new CopilotRuntime({
agents: { default: new BuiltInAgent({ model: "openai/gpt-4o-mini" }) },
// Explicit, but this is also the default if omitted:
runner: new InMemoryAgentRunner(),
});
The most common customization is subclassing InMemoryAgentRunner to layer
your own persistence (or to reconcile history replayed by an external memory
layer). Override only the methods you need and call super for the rest:
import { InMemoryAgentRunner } from "@copilotkit/runtime/v2";
export class MyRunner extends InMemoryAgentRunner {
override run(request: Parameters<InMemoryAgentRunner["run"]>[0]) {
// persist request.threadId / input here, then delegate
return super.run(request);
}
override connect(request: Parameters<InMemoryAgentRunner["connect"]>[0]) {
// re-hydrate the thread from your store before re-attaching
return super.connect(request);
}
}
For a complete production example, see the
AWS AgentCore integration. It extends
InMemoryAgentRunner into an AgentCoreRunner, handles a connect() that
arrives before any run() for a thread, and synthesizes missing tool-call
results from a replayed history.
runner.IntelligenceAgentRunner backend.