Documentation Index
Fetch the complete documentation index at: https://docs.qoder.com/llms.txt
Use this file to discover all available pages before exploring further.
By default, query() launches the bundled qodercli locally. Pass options.experimentalCloudAgent and the SDK switches to the Qoder Cloud Agent runtime instead — the agent and session run in a Qoder Cloud container, while the local process only sends requests and consumes the SSE event stream.
Status: experimental / unstable. The API shape may change between minor versions; do not depend on unreleased fields in production code paths.
When to use
- You don’t want to manage qodercli, the bundled binary, or a local runtime
- You need a long-lived agent reused across machines (the agent is persisted in the Cloud)
- You want session context to live in the Cloud so multiple processes / hosts can resume it
Local-CLI-only capabilities — mcpServers / settings / hooks / plugins / local permissions / checkpoint — are not available under the Cloud runtime; passing any of them throws synchronously.
Prerequisites
- Personal Access Token (PAT): generated at qoder.com/account/integrations; see SDK Authentication. The Cloud runtime accepts only
accessToken() / accessTokenFromEnv(). Passing qodercliAuth() / jobToken() throws synchronously.
- Cloud
environment_id: required when creating a session. Get it from the Qoder console or the management API.
export QODER_PERSONAL_ACCESS_TOKEN="<your-pat>"
export QODER_CLOUD_AGENT_ENVIRONMENT_ID="<your-env-id>"
First call: create agent + create session
The most common entry path — create a new Cloud Agent and immediately open a session for it to run a prompt:
import { accessTokenFromEnv, query } from '@qoder-ai/qoder-agent-sdk';
const q = query({
prompt: 'Summarize this repository in one short paragraph.',
options: {
auth: accessTokenFromEnv(),
experimentalCloudAgent: {
agent: {
create: {
name: 'my-cloud-agent',
model: 'ultimate',
system: 'You are a concise code assistant.',
tools: [
{
type: 'agent_toolset_20260401',
enabled_tools: ['read', 'glob', 'grep'],
},
],
},
},
session: {
create: {
environment_id: process.env.QODER_CLOUD_AGENT_ENVIRONMENT_ID!,
title: 'first-cloud-session',
},
},
},
},
});
for await (const msg of q) {
if (msg.type === 'result') {
console.log('done:', msg.subtype, msg.result);
}
}
When the turn finishes, read session_id from the final result message — later turns use it to resume the same session (see Multi-turn: resuming a session).
tools[].enabled_tools currently supports: bash, write, glob, web_fetch, read, edit, grep, web_search. Omit tools to give the agent no tools.
Mounting files into a session
After uploading a file via the Files API, mount it into the session container with session.create.resources:
session: {
create: {
environment_id,
resources: [
{ type: 'file', file_id: 'file_abc123', path: '/workspace/data.json' },
],
},
}
Reusing an existing agent
If you already have an agent.id (created via the console or a previous call), pass agent: { id } and skip create:
experimentalCloudAgent: {
agent: { id: 'agent_xxx' },
session: { create: { environment_id } },
}
Multi-turn: resuming a session
Once you have a session_id from the first turn, the next call passes only session: { id } — do not include agent. The session already binds an agent, and combining the two throws synchronously.
// Turn 1: create agent + session
const first = query({
prompt: 'My favorite color is teal. Reply with: noted.',
options: {
auth: accessTokenFromEnv(),
experimentalCloudAgent: {
agent: { create: { name: 'demo', model: 'ultimate' } },
session: { create: { environment_id } },
},
},
});
let sessionId: string | undefined;
for await (const msg of first) {
if (msg.type === 'result') sessionId = msg.session_id;
}
// Turn 2: continue the same Cloud session
const second = query({
prompt: 'What is my favorite color?',
options: {
auth: accessTokenFromEnv(),
experimentalCloudAgent: {
session: { id: sessionId! },
},
},
});
for await (const msg of second) {
if (msg.type === 'result') console.log(msg.result); // → "teal"
}
Session context lives in the Cloud, so the script can restart or move between machines between turns — as long as you have the session_id, you can resume.
Consuming SSE events
The Cloud runtime streams session events back over SSE. The SDK wraps each event as a cloud_agent_event message:
for await (const msg of q) {
if (msg.type === 'cloud_agent_event') {
console.log(msg.event, msg.data); // e.g. "user.message", "agent.message", "session.status_idle"
} else if (msg.type === 'result') {
// SDK synthesizes a result after receiving session.status_idle for the current turn
console.log('turn end:', msg.subtype);
}
}
Event shape:
| Field | Description |
|---|
event | Cloud event name (e.g. user.message, agent.message, session.status_idle) |
id | Event ID in the SSE stream; usable as a replay anchor |
data | Cloud event payload (includes turn_id and other fields) |
session_id | Cloud session ID this event belongs to |
History replay isolation
When resuming an existing session, the SSE stream first replays history events. The SDK isolates by turn_id: only the current turn’s session.status_idle triggers the result terminal — historical events will not end your query early.
SSE tuning
experimentalCloudAgent: {
session: { id: sessionId },
stream: {
afterId: 'evt_xxx', // start replay after this event ID
deltaFlushIntervalMs: 250, // delta merge / flush interval (SDK default if omitted)
},
}
Abnormal close
If SSE disconnects before the current turn reaches a terminal event, the SDK synthesizes an error result (subtype !== 'success', is_error: true) so callers can handle it uniformly.
The result terminal
| Field | Description |
|---|
subtype | success or an error subtype |
is_error | Boolean; whether the turn ended abnormally |
session_id | Cloud session ID (backfilled by the SDK on the create branch) |
result | Agent’s text reply for the turn (multiple text blocks are concatenated) |
usage / modelUsage / total_cost_usd | Backfilled from the current turn’s span.model_request_end.usage |
Constraints at a glance
agent and session each have their own id / create union — they are mutually exclusive (enforced by the TypeScript types).
- When passing an existing
session.id, do not also pass agent.
session.create must include environment_id explicitly.
- The Cloud runtime rejects local-CLI-only top-level options:
model, agent, mcpServers, settings, hooks, plugins, permissionMode, etc. Passing any of them throws synchronously.
- The Cloud runtime does not support
q.setModel(), q.reloadPlugins(), MCP OAuth, etc. Only for await consumption and q.close() are guaranteed.
Error codes
| code | When it triggers |
|---|
cloud_agent_auth_requires_access_token | Non-PAT auth was used (e.g. qodercliAuth() / jobToken()) |
cloud_agent_api_error | Cloud OpenAPI returned non-2xx, or the SSE channel failed |