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.

TypeScript
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.

TypeScript
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.

StatusMeaningTerminal
queuedAccepted, not yet startedNo
provisioningPreparing the managed runtimeNo
runningExecutingNo
retryingRecovering from a recoverable failureNo
awaiting_inputPaused, waiting on a human answerNo, resume it
succeededFinished, goal metYes
partial_successFinished with some objectives unmetYes
failedFinished, goal not metYes
cancelledStopped by cancel()Yes
expiredExpired before completion, including when an execution deadline is reachedYes

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.

TypeScript
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. Pass timeoutMs only 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.

TypeScript
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.

TypeScript
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.

TypeScript
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.

TypeScript
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.

TypeScript
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.