camelAI Documentation

API Reference

SDKs

The TypeScript and Python SDKs: Agents, upsert, run, stream, tools and the lower-level API

View as Markdown · Docs index for coding agents

The two SDKs have the same features, named in each language's style; their version numbers are their own and do not line up.

npm install @camelai/run   # Node 22+, Bun, Deno, Cloudflare Workers
TypeScript entry
@camelai/runEverything portable: Agents, tool, schema, the lower-level AgentRuntime and AgentClient, and the types
@camelai/run/nodeThe same for Node and Bun, plus local file paths as attachments and nodeListener
@camelai/run/serverserveTools, verifyRuntimeToken, runtimeAuth, runtimeIdentity, createAgentHandler
@camelai/run/watchwatchAgent, for reading an agent from a browser
@camelai/run/chatcreateAgentChat, the framework-free chat store
@camelai/run/ai-sdkAgentRuntimeChatTransport, for the AI SDK's useChat
@camelai/run/mcpfromMcpServer, for attaching an MCP SDK server
@camelai/run/testingtestRuntime, for signing identity tokens in tests

Agents

const agents = new Agents({ apiKey, url }); // or `await using agents = new Agents()`

The Python SDK is async-only: every call is awaited inside async def. From synchronous code (a script, a Django view, a Celery task), run it with asyncio.run(...). Its names are the TypeScript ones in snake_case (throw_on_error, run.tool_errors, part.is_error), as the tables below show.

  • apiKey defaults to CAMELAI_API_KEY, and url to CAMELAI_BASE_URL, else https://run.camelai.com.
  • agents.close() closes every agent's connection so the process can exit. Their runs go on in camelRun.
  • agents.runtime is the lower-level AgentRuntime: definitions, volumes, listAgents(), browserToken(agentId), inbox() and toolSources(agentId).

agents.upsert(key, config)

The agent for key, made if there's none and brought to config if it differs. Returns a connected Agent.

TypeScriptPython
modelmodel="provider/model-id" from GET /v1/models
instructionsinstructions=The system prompt
instructionsAppendinstructions_append=Text after the prompt, such as per-conversation context
toolstools=Tools served from this process: { name: tool({...}) }, or a list of @tool functions
builtinsbuiltins=web_search, web_fetch, schedule, ask_user
definitiondefinition=Make it from a definition
thinkingLevelthinking_level=off, minimal, low, medium, high, xhigh, max
subject, contextsubject=, context=Whom it acts for, and claims for its tools. Fixed at creation
keyScope, spendLimit, modelHeaderskey_scope=, spend_limit=, model_headers=See Models and keys
mounts, fileToolsmounts=, file_tools=Its volumes (fixed at creation), and whether it has file tools
namename=A label shown in the console
attachattach=false: declare tools without serving them
takeovertakeover=Replace the process serving the tools now
onEvent, onInput, onErroron_event=, on_input=, on_error=Callbacks for events, inputs as they're asked, and connection errors

agents.get(keyOrId, config)

The existing agent with this key (or id), as it is. upsert sets an agent to the config it's given; get changes nothing, so use it where a process only runs or reads agents that another process configures.

ts
const agent = await agents.get("support-triage");      // or its id
python
agent = await agents.get("support-triage")

It throws an AgentError with status 404 when no live agent has the key or id, and 409 AGENT_KEYLESS for an agent made without a key. It takes tools, the callbacks, attach and takeover as upsert does. Over REST, GET /v1/agents/{keyOrId}/credentials returns {id, token, expiresAt}. Available from @camelai/run 0.14.0 and camelai-run 0.10.0.

agent.fork(options)

A new agent made from this one: its configuration, a copy of its history and a fork of its workspace, each its own from then on.

ts
const fork = await agent.fork({ key: "support-b", atMessage: 5 });
await fork.run("Try the other approach");
python
fork = await agent.fork(key="support-b", at_message=5)

atMessage ends the copied history at a history index (that message and the tool results that answer it) or a request id (that run's whole turn); by default it ends with the last turn that finished, never mid-turn. Forking again with the same key returns the same fork, and agents.get(key) finds it. Without a key the fork lives a day (ttlSeconds changes that). subject, context, instructionsAppend (instructions_append=) and modelHeaders (model_headers=) are the fork's own instead of the source's. fork.forkedFrom (forked_from) is {agentId, atMessage}, and agents.fork(id, options) forks an agent by id. Available from @camelai/run 0.14.0 and camelai-run 0.10.0.

Agent

TypeScriptPython
agent.idagent.idclient_..., safe to log and store
agent.run(text, options)await agent.run(text, ...)Send a message and wait for the Run
agent.stream(text, options)agent.stream(text, ...)The run as it happens: for await / async for over parts
agent.pendingInputs()pending_inputs()Inputs waiting on people, each with answer()
agent.history(), historyPage({ before, limit })history(), history_page(...)The whole history, or a page of whole turns
agent.steer(text)steer()Join the running turn, or start one
agent.configure({ model, instructions, thinkingLevel, tools })configure(...)Change it between runs
agent.schedule({ text, inSeconds, at, everySeconds })schedule(...)Wake it later; schedules(), unschedule(id)
agent.filesagent.fileslist, download, upload, link by the paths the agent sees
agent.abort()abort()Stop the running turn
agent.fork({ key, name, atMessage })fork(key=, name=, at_message=)A new agent with its configuration, a copy of its history and of its files. See Forking
agent.delete()delete()Delete it, its history and files
agent.close()close()Close this process's connection

Run options for run and stream:

TypeScriptPython
useruser=Who sent it: your user id, or { id, name, username }
filesfiles=Attachments. See Files
metadatametadata=Your own key-value data (16 strings); the model never sees it
idempotencyKeyidempotency_key=The run's id. The same key returns the same run
signaltimeout=Stop waiting; the run goes on
throwOnErrorthrow_on_error=false returns a failed run instead of throwing RunError
whileRunningwhile_running="queue" (default) or "steer"
spendLimitspend_limit={usd}: this run's own budget
allowDisconnectedallow_disconnected=Run even with nobody serving the agent's tools
outputoutput=Structured output: a zod, TypeBox or JSON Schema (Python: a pydantic model class, or a JSON Schema dict) for an object. The answer is run.output. See Structured output
traceparenttraceparent=A W3C trace context (00-<trace-id>-<span-id>-<flags>): with trace export set, the run's spans continue your trace under that span. Not part of the run's idempotency

Run and stream parts

A Run is { id, status, text, output?, inputs, error, usage, files, toolErrors, toolCalls, sourceErrors, raw } (Python: tool_errors, tool_calls, source_errors). toolCalls lists every tool call the run made, with ok or an error code, not their arguments or results (see Run outcomes). output is the answer of a run sent with output, typed by its schema (Python: an instance of the pydantic model). status is completed, input_required or failed. Each of run.inputs has answer(value, { from }) and decline({ from }) (Python: answer(value, from_=) and decline(from_=)), which resolve with the resumed run.

Part typeFields
texttext: reply text as it's written
tool_callid, name, arguments
tool_resultid, name, output, isError (Python is_error)
input_requiredinput, with answer()
donerun, always last

run.toolCalls names a call's tool tool and its id toolCallId. Stream parts carry the same values as name and id, and, from @camelai/run 0.14.0 and camelai-run 0.10.0, also as tool and toolCallId (Python tool_call_id). name and id stay.

Tools

tool({ description, input: schema.Object({ ... }), execute: (args, context) => result,
       timeoutMs?, needsApproval?, exposure? })
context (TypeScript)Python
idempotencyKeyidempotency_keyThe same for every attempt of this call
callIdcall_idThis attempt's id
identityidentityWho the call is for. See Identity
signal(task cancellation)Aborted when camelRun cancels the call
progress(message)progress(message, progress=, total=)Report progress; restarts the deadline
confirm, ask, requireUrlconfirm, ask, require_urlAsk the user. See Human input

With several processes (web workers, task queues, serverless), serve tools over HTTP: see Several processes, workers and deploys.

Errors

AgentError has status (HTTP, or 0), code (a stable name where camelRun gives one), requestId, uncertain and retryAfterMs (Python request_id, and retry_after in seconds). RunError is an AgentError for a failed run, with run.

The lower-level API

Agents and Agent are built on AgentRuntime and AgentClient, which stay available for code that needs the wire's shape: agents.runtime, agent.client, or new AgentRuntime({ url, apiKey }) directly.

TypeScriptPython
runtime.upsertAgent(key, options)upsert_agent(key, ...)Upsert, returning credentials without connecting
runtime.connectAgent(session, { tools, attach, takeover })connect_agent(...)Connect with stored credentials
runtime.me()me()Your tenant id and default model
runtime.upsertDefinition(key, input)upsert_definition(key, ...)Definitions; also createDefinition, updateDefinition, deleteDefinition
runtime.setProvider(name, config)set_provider(name, ...)A custom provider
runtime.createVolume, volume(id)create_volume, volume(id)Volumes
runtime.inbox(state)inbox(state=)Inputs across all agents
client.execute(code)execute(code)Run code in the sandbox with the agent's tools, outside its history
client.waitForRequest(id)wait_for_request(id)Wait for a request already sent, from any process
client.requestStatus(id, { wait })request_status(id, wait=)A request's record; wait (seconds, at most 25) waits for it to settle first, with no stream connected
runtime.telemetry.set({ endpoint, headers, protocol, sampleRate, include }), get(), test(), clear()await runtime.telemetry.set(endpoint, headers=, protocol=, sample_rate=, include_content=), get(), test(), clear()Trace export: set changes only what it is given; get shows header names, never values; test sends one span now
ts
await agents.runtime.telemetry.set({ endpoint: "https://api.smith.langchain.com/otel/v1/traces", headers: { "x-api-key": process.env.LANGSMITH_API_KEY! } });
const { ok, traceId } = await agents.runtime.telemetry.test();
python
await agents.runtime.telemetry.set("https://api.smith.langchain.com/otel/v1/traces", headers={"x-api-key": os.environ["LANGSMITH_API_KEY"]})
result = await agents.runtime.telemetry.test()

Examples

Both examples read CAMELAI_API_KEY: