Skip to main content
The Corti Agent SDK is in alpha v2 private preview. The API may change between releases. Contact help@corti.ai to request access.
This page covers the core building blocks you use in every Agent SDK application.

CortiClient

The root client. You create one instance and pass it to every resource client. It handles authentication, base URL resolution, and the Tenant-Name and A2A-Version headers automatically.
The TypeScript client accepts a tokenProvider function instead of a static token for OAuth flows where the token expires. The client calls it before every request and uses the return value.
The client exposes typed resource clients:
The resource clients above are available in the TypeScript SDK. The Python SDK currently provides AgentsClient only; additional resource clients will be added in the v2 rebuild.
The TypeScript package also exposes a client.raw property: the underlying openapi-fetch client for direct API access when you need an endpoint the SDK does not wrap yet.

Agents

An agent is a reusable unit of behaviour: a name, a description, a system prompt, and a set of tools (connectors). You create agents via the agents resource client, which returns typed AgentHandle objects.

Create an agent

Fetching and listing

Updating

Only the fields you pass are sent. Passing connectors replaces the full set.

AgentHandle

An AgentHandle wraps an agent response and provides conversation helpers. In TypeScript, client.agents.create() returns a raw Agent object; you wrap it explicitly. In Python, AgentsClient.create() returns an AgentHandle directly.

Lifecycle: ephemeral vs persistent

Agents default to ephemeral, which means the server cleans them up automatically. Use persistent only when the agent must survive process restarts.
Lifecycle controls the agent definition (system prompt, connectors). Conversation threads (AgentContext) are always managed automatically regardless of lifecycle. You never need to create or delete threads manually.
Use ephemeral unless you have a specific reason not to. Persistent agents accumulate in your tenant if you forget to delete them.

Contexts and conversations

An AgentContext represents a single conversation thread. Contexts are lazy: no network call is made until the first message is sent, at which point the server creates the thread and returns a contextId that the SDK tracks automatically.

Multi-turn conversation

You do not need to manage context IDs yourself. Keep the context object in memory across turns. Only persist ctx.id if you need to resume the exact same thread after a process restart, and use handle.getContext(id) to do so.

One-shot helper

No context object needed for single-shot invocations:

Resuming a thread across sessions

If you need to continue a thread after a process restart, persist ctx.id (only available after the first turn) and use handle.getContext(id) / agent.get_context(id) next time.
This is the only valid way to pass a context ID. Do not construct AgentContext yourself or pass IDs to createContext().

sendText vs sendMessage vs streamMessage

All three live on AgentContext and send to the same thread (the contextId is shared). The only differences are the input shape and whether the response is buffered or streamed. sendText is a convenience wrapper for sendMessage:
When to reach for sendMessage over sendText:
streamMessage returns events incrementally; sendMessage waits for completed or failed and returns the final aggregate. Streaming has no buffered MessageResponse: assemble the text yourself by concatenating event.message.parts.

Connectors

Connector factories build typed connector definitions. You declare connectors at agent creation time in the connectors array. The agent can call them autonomously when its prompt suggests doing so.
The schema connector type is new in v2 and currently available in the TypeScript package only. The Python package will add it in the v2 rebuild.

Registry connectors

Typical registry connectors include: To see what connectors are available in your tenant, browse the registry connector reference.

Building a clinical orchestrator

Use multiple connectors together to build a well-rounded clinical orchestrator:

MessageResponse

Every non-streaming call returns a MessageResponse that promotes the fields you most often need to the top level.

Streaming

Streaming responses arrive as an async generator of StreamEvent objects. Each event is one of task, message, statusUpdate, or artifactUpdate.
streamMessage tracks the same contextId as sendMessage. You can freely mix streaming and non-streaming calls on a single context.

Connector auth

In the TypeScript v2 SDK, connector auth is configured on the connector itself at agent creation time, not forwarded as credentials at call time. Use the auth factory to specify the auth type:
The Python SDK (still on v1 architecture) uses a CredentialStore passed to create_context(). The credential key must match the connector’s name:
When an MCP connector requires auth, the agent may reply with status auth-required until you provide credentials. The Python SDK forwards credentials transparently and re-sends them if the agent asks again.