The Corti Agent SDK is in alpha v2 private preview. The API may change between releases. Contact help@corti.ai to request access.
AgentsClient and AgentsResource
In TypeScript, agent CRUD lives onclient.agents (AgentsResource). In Python, it lives on AgentsClient(client).
| Method | Returns | Description |
|---|---|---|
create(body) / create(...) | Agent (TS) / AgentHandle (Python) | Create a new agent |
get(agentId) / get(agent_id) | Agent (TS) / AgentHandle (Python) | Fetch an existing agent by ID |
list(params?) / list() | AgentListResponse (TS) / list[AgentHandle] (Python) | List agents in the tenant |
update(agentId, body) / update(...) | Agent (TS) / AgentHandle (Python) | Partial update via JSON Merge Patch |
delete(agentId) / delete() | void | Delete an agent |
wrap(agent) (Python only) | AgentHandle | Wrap a raw API dict without a network call |
create() and get() return raw Agent objects. Wrap them with new AgentHandle(agent, client) to get conversation helpers.
AgentHandle
| Member | Type | Description |
|---|---|---|
id | string | Agent ID (server-assigned) |
name | string | Agent name |
description | string | undefined | Agent description |
systemPrompt / system_prompt | string | undefined | System prompt |
model | string | undefined (TS only) | Model the agent uses |
visibility | string | private, unlisted, or public |
lifecycle | string | ephemeral or persistent |
connectors | Connector[] | Attached connectors |
labels | Record<string, string> (TS only) | Free-form labels |
raw | Agent / Dict | Underlying API response object |
createContext(opts?) / create_context(...) | AgentContext | Open a new conversation thread (lazy) |
getContext(id, opts?) / get_context(id, ...) | AgentContext | Resume an existing thread by ID |
run(input, opts?) | Promise<MessageResponse> | One-shot invoke: create context, send, return reply |
stream(input, opts?) (TS only) | AsyncGenerator<StreamResponse> | One-shot streaming invoke |
update(patch) / update(...) | Promise<AgentHandle> | Partially update the agent, returns a new handle |
refresh() | Promise<AgentHandle> | Re-fetch the agent from the API |
delete() | Promise<void> | Delete the agent |
AgentContext
| Member | Type | Description |
|---|---|---|
id | string | undefined | Thread ID, undefined / None until the first turn completes |
sendText(text, opts?) / send_text(text, ...) | Promise<MessageResponse> | Send plain text |
sendMessage(parts, opts?) / send_message(parts, ...) | Promise<MessageResponse> | Send arbitrary Part[] (text, data, file) |
streamMessage(parts, opts?) / stream_message(parts) | AsyncGenerator<StreamResponse> | Stream incremental events for the reply |
getTask(taskId, opts?) / get_task(task_id, ...) (TS only) | Promise<Task> | Fetch a task by ID |
cancelTask(taskId, opts?) / cancel_task(task_id, ...) (TS only) | Promise<Task> | Cancel a running task |
SendMessageOptions
| Field | Type | Description |
|---|---|---|
historyLength | number | Number of history messages to include |
blocking | boolean | Wait for task completion before returning |
acceptedOutputModes | string[] | Output modes the client accepts |
metadata | Record<string, unknown> | Free-form metadata |
timeoutInSeconds / timeout_in_seconds | number | Per-request timeout override (default 60) |
abortSignal (TS only) | AbortSignal | Abort the request |
credentials (Python only) | CredentialStore | MCP auth credentials |
MessageResponse
| Member | Type | Description |
|---|---|---|
text | string | null | All text parts from the agent reply, joined |
status | string | Task state: completed, failed, working, submitted, canceled, input-required |
state (TS only) | TaskState | Raw task state enum value |
message (TS only) | Message | undefined | The agent’s reply message |
task (TS only) | Task | undefined | The full A2A task object |
taskId / task_id | string | undefined | Task ID for this invocation |
contextId / context_id | string | undefined | Thread ID, set after the first turn |
artifacts | Artifact[] | Structured outputs, deduplicated by parts content |
raw | SendMessageResponse / Dict | Full, unmodified API response |
Composition primitives
| Function | Returns | Description |
|---|---|---|
workflow(steps) | Workflow | Build a deterministic pipeline |
Workflow.run(input) | Promise<WorkflowResult> | Execute the pipeline |
parallel(steps) | Parallel | Build a fan-out block |
Parallel.run(input) | Promise<ParallelResult> | Run all steps concurrently |
stateGraph<TState>() / stateGraph() | StateGraph<TState> | Build a graph with cycles and typed shared state |
StateGraph.addNode(name, nodeFn) / add_node(...) | StateGraph | Register a node. Use agentNode() for agent-backed nodes |
StateGraph.addEdge(from, to) / add_edge(...) | StateGraph | to may be a node name, END, or an EdgeRouter |
StateGraph.run(start, state, opts?) | Promise<StateGraphResult> | Execute. opts.maxIterations bounds cycles (default 25) |
agentNode(agent, inputFn, mergeFn) / agent_node(...) | NodeFn<TState> | Wrap an agent as a graph node |
END | EndType | Sentinel to terminate a StateGraph run |
Connector helpers
TypeScript
| Helper | Returns | Description |
|---|---|---|
connectors.registry(name, opts?) | RegistryConnectorCreate | Use a published Corti registry connector |
connectors.mcp({ name, url, auth? }) | McpConnectorCreate | Attach an MCP server |
connectors.agent(agentId, opts?) | AgentConnectorCreate | Wire another Corti agent as a sub-agent |
connectors.a2a(url, opts?) | A2AConnectorCreate | Connect to a remote A2A agent |
connectors.schema({ name, schema, ... }) | SchemaConnectorCreate | Define a JSON Schema tool for structured output |
Python
| Helper | Returns | Description |
|---|---|---|
connectors.registry(name, *, system_prompt?) | RegistryConnector | Use a named expert from the registry |
connectors.mcp(mcp_url, *, name?, transport?, auth_type?, token?) | McpConnector | Attach an MCP server |
connectors.from_agent(agent_id) | CortiAgentConnector | Reference another Corti agent as a sub-agent |
connectors.a2a(a2a_url) | A2AConnector | A2A protocol (reserved, not yet supported) |
Auth helpers (TypeScript only)
| Helper | Returns | Description |
|---|---|---|
auth.none() | ConnectorAuth | No auth required |
auth.bearer() | ConnectorAuth | Bearer token auth |
auth.apiKey(ref?) | ConnectorAuth | API key auth, optionally with a stored secret reference |
auth.oauth2({ scope?, redirectUrl?, ref? }) | ConnectorAuth | OAuth2 auth |
Types
Parts
| Type | Shape | Notes |
|---|---|---|
Part | TextPart | DataPart | FilePart | Message content |
TextPart | { text: string } | Plain text |
DataPart | { data: unknown } | Structured payload |
FilePart | { file: { name?, mimeType?, bytes?, uri? } } | Send bytes (base64) or uri |
Tasks and messages
| Type | Shape | Notes |
|---|---|---|
Task | Full A2A task object | Exposed via MessageResponse.task / MessageResponse.raw |
Message | { role, parts, messageId, contextId?, taskId? } | An A2A message |
Artifact | { artifactId, name?, parts } | Structured output from the agent |
TaskState | submitted | working | input-required | completed | canceled | failed | Returned in MessageResponse.status |
Composition types
| Type | Shape | Notes |
|---|---|---|
Runnable | { run(input): Promise<MessageResponse> } | What workflow/parallel accept besides AgentHandle |
WorkflowStep | AgentHandle | Parallel | { agent, when?, transform?, retries?, retryDelay? } | A workflow step |
WorkflowResult | { output, steps, stoppedEarly } | Result of Workflow.run() |
ParallelStep | AgentHandle | { agent, input?, credentials? } | A parallel step |
ParallelResult | { results, fulfilled, rejected } | Result of Parallel.run() |
EdgeRouter<TState> | (state: S) => string | END | Function form of addEdge |
NodeFn<TState> | (state: S) => Promise<Partial<S>> | Partial<S> | Custom graph node function |
StateGraphStep<TState> | { node: string, delta: Partial<S> } | Per-step trace entry |
StateGraphResult<TState> | { state, steps, iterations, terminatedBy } | Result of StateGraph.run() |
Error types
| Type | Description |
|---|---|
CortiError | Base class for all SDK errors |
ManagementError | Management-plane error (agent CRUD, connectors, etc.) |
A2AError | A2A-plane error (message send, stream, task operations) |
HttpError | HTTP error when the response body cannot be parsed as a known error shape |
TypeScript vs Python naming
The wire format (A2A JSON-RPC) is identical: both SDKs talk to the same API. The naming conventions differ:| TypeScript | Python |
|---|---|
new CortiClient({...}) | async with CortiClient(...) as client: |
sendText() | await send_text() |
sendMessage() | await send_message() |
streamMessage() | stream_message() |
createContext() | create_context() |
getContext(id) | get_context(id) |
systemPrompt | system_prompt |
timeoutInSeconds | timeout_in_seconds= (keyword-only) |
connectors.agent(agentId) | connectors.from_agent(agent_id) |
connectors.mcp({ url }) | connectors.mcp(mcp_url=...) |
agentNode() | agent_node() |
stateGraph() | stateGraph() (same: Python also exports camelCase) |
terminatedBy | terminated_by |
stoppedEarly | stopped_early |
retryDelay | retry_delay |