Core concepts
The SDK has a small vocabulary. Five objects explain almost everything, and understanding how they relate will save you from most of the mistakes that are easy to make early.
Agents are definitions, runs are executions#
An agent is a definition: instructions, a model, the tools it may call, the files it should produce. It is inert. Creating one costs nothing and touches no network.
import { createAgent } from '@coresourceai/sdk';
// Nothing has happened yet. No request, no validation, no charge.
const agent = createAgent({
type: 'agent',
systemPrompt: 'Be methodical.',
outputs: ['report.md']
});A run is one execution of that definition against one prompt. Runs are where everything actually happens: they have an id, a status, a stream of events, and eventually a result.
import { createAgent } from '@coresourceai/sdk';
const agent = createAgent({ type: 'agent' });
// Two runs of one definition. Independent - no shared state between them.
const first = await agent.start('Audit the pricing page.');
const second = await agent.start('Audit the changelog.');
console.log(first.id, second.id);One definition, many runs. Runs do not implicitly share state; if you need work carried from one to the next, hand it over explicitly (see multi-agent orchestration).
Run status#
Every run ends in a terminal status, and result() gives you the run in whatever state it reached.
| Status | Meaning | Terminal |
|---|---|---|
queued | Accepted, not yet started | No |
provisioning | Preparing the managed runtime | No |
running | Executing | No |
retrying | Recovering from a recoverable failure | No |
awaiting_input | Paused, waiting on a human answer | No, resume it |
succeeded | Finished, goal met | Yes |
partial_success | Finished with some objectives unmet | Yes |
failed | Finished, goal not met | Yes |
cancelled | Stopped by cancel() | Yes |
expired | Expired before completion, including when an execution deadline is reached | Yes |
partial_success is the one that surprises people. A long run that produced four of five requested outputs did not fail, and treating it as failure throws away real work. Check status before you trust text.
import { createAgent } from '@coresourceai/sdk';
const agent = createAgent({ type: 'saga', outputs: ['report.md'] });
const result = await agent.run('Compile the quarterly summary.');
if (result.status === 'succeeded') {
console.log(result.text);
} else if (result.status === 'partial_success') {
console.warn('Incomplete - keeping what came back:', result.artifacts.length, 'artifacts');
} else {
console.error(`Run ${result.id} ended as ${result.status}`);
}
await agent.close();Durability#
A started run belongs to the platform, not to your process.
- Your process can exit and the managed run continues. The id returned by
createAgent().start()is a durable run id and can be retrieved, replayed, resumed, cancelled, or read from another process through/v1/runs/{id}. Use the HTTP API for cross-process access. - A run that needs a custom tool or local MCP server needs that SDK process to remain connected whenever it calls the local capability.
- The event stream can drop, especially across long quiet stretches, and the
run is unaffected. Reconnect, or skip straight to
result(). result()has no overall timeout by default, so a long-horizon run can be waited on for days. PasstimeoutMsonly when you want to stop waiting; it does not cancel the run.- To actually stop a run, call
cancel().
The practical consequence: never treat a dropped stream as a failed run.
import { createAgent } from '@coresourceai/sdk';
const agent = createAgent({ type: 'saga' });
const run = await agent.start('Migrate the reporting queries.');
try {
for await (const event of run.events()) {
console.log(event.type);
}
} catch {
// The stream dropped. The run did not. Fall through and ask for the result.
}
const result = await run.result();
console.log(result.status);
await agent.close();Events#
events() is an async iterable of events emitted by the run. Depending on the runtime and work, these may include state changes, progress, logs, messages, tool activity, usage, and output updates.
import type { AgentEvent } from '@coresourceai/sdk';
function describe(event: AgentEvent) {
return `${event.sequence ?? '-'} ${event.type} ${JSON.stringify(event.data)}`;
}Every event carries a type and a data object. id, occurredAt, and sequence are optional. When an event includes an id, persist it and pass it as after to resume after that event rather than replaying retained history from the beginning.
import { createAgent } from '@coresourceai/sdk';
const agent = createAgent({ type: 'agent' });
const run = await agent.start('Do the thing.');
let lastEventId: string | undefined;
for await (const event of run.events({ after: lastEventId })) {
lastEventId = event.id ?? lastEventId;
console.log(event.type);
}
await agent.close();Artifacts#
An artifact is a file the run produced. You ask for them with outputs in the agent config, and read them off the result.
import { createAgent } from '@coresourceai/sdk';
const agent = createAgent({
type: 'agent',
outputs: ['report.md', { path: 'data/summary.csv', mimeType: 'text/csv' }]
});
const result = await agent.run('Produce the report and the summary table.');
for (const artifact of result.artifacts) {
console.log(artifact.name, artifact.sizeBytes, artifact.mimeType);
// Text for small files...
const body = await artifact.text();
console.log(body.slice(0, 200));
// ...or a Response you can stream to disk for anything large.
const response = await artifact.download();
console.log(response.ok);
}
await agent.close();outputs entries are either a plain string path or an object with path, and optionally name and mimeType. Storage locations and the runtime's filesystem roots are deliberately not part of the public API. You address files by the relative names you declared.
Usage#
Every result carries what it cost.
import type { AgentResult } from '@coresourceai/sdk';
function logCost(result: AgentResult) {
const { inputTokens, outputTokens, totalTokens, costUsd } = result.usage;
console.log({ inputTokens, outputTokens, totalTokens, costUsd });
}All four fields are optional (a run that failed before doing any model work may report none of them) so treat them as number | undefined rather than assuming zero.
