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.
query() supports two input modes:
- Single-message query mode: submit one user message; the SDK closes the session after the current reply completes. See the Quickstart.
- Multi-message session mode: keep the session open and carry on a multi-turn conversation with the model.
Multi-message session
Define a sequence that yields user messages in order:
import { qodercliAuth, query, type SDKUserMessage } from '@qoder-ai/qoder-agent-sdk';
async function* messages(): AsyncGenerator<SDKUserMessage> {
yield {
type: 'user',
message: { role: 'user', content: [{ type: 'text', text: 'Analyze this codebase for security issues' }] },
parent_tool_use_id: null,
};
// You can wait for any external condition before yielding the next message
await new Promise((resolve) => setTimeout(resolve, 2000));
yield {
type: 'user',
message: { role: 'user', content: [{ type: 'text', text: 'Now write a short report' }] },
parent_tool_use_id: null,
};
}
for await (const msg of query({
prompt: messages(),
options: {
auth: qodercliAuth(),
allowedTools: ['Read', 'Grep'],
},
})) {
if (msg.type === 'result' && msg.subtype === 'success') {
console.log(msg.result);
}
}
The model replies once for each user message it receives. Once the message sequence finishes, the session closes automatically. For message field definitions see SDKUserMessage.
Managing the session lifecycle
In multi-message sessions, the lifecycle of the object returned by query() is owned by the caller. The SDK only closes the session as a side effect of the message sequence finishing on its own; in every other case the caller has to decide when to wrap up, otherwise the session keeps hanging.
Common scenarios where the caller needs to manage closure manually:
-
The message sequence itself doesn’t end, for example a generator that loops on external input:
async function* fromUserUI(): AsyncGenerator<SDKUserMessage> {
while (true) {
const text = await waitForUserInput(); // your UI's input source
yield {
type: 'user',
message: { role: 'user', content: [{ type: 'text', text }] },
parent_tool_use_id: null,
};
}
}
-
You want to terminate before the message sequence would end naturally: timeout, user cancellation, other business conditions.
Two ways to close:
Automatic management (recommended; Node 22+ or runtimes with explicit resource management)
Use this when the session’s lifetime aligns with a function or block scope — it’s released automatically when the scope ends.
{
await using q = query({ prompt: fromUserUI(), options: { auth: qodercliAuth() } });
for await (const msg of q) { /* ... */ }
} // Automatically closes when leaving scope
Manual close
Use this when the close trigger comes from outside: timeout, user cancellation, or other business conditions.
const q = query({ prompt: fromUserUI(), options: { auth: qodercliAuth() } });
setTimeout(() => q.close(), 30_000); // Force-close after 30 seconds
for await (const msg of q) { /* ... */ }