CoreSource SDK
Create and run complete AI agents from TypeScript. CoreSource manages execution, credentials, storage, and streaming; your application supplies the agent definition and prompt.
Install
npm install @coresourceai/sdk
export CORESOURCE_API_KEY='your-api-key'
Node.js 20 or newer is required.
The SDK uses https://api.coresource.ai/v1/ by default. For another deployment,
pass { baseUrl: 'https://api.example.com/v1/' } to createAgent() or
new CoreSource(), or set CORESOURCE_API_URL.
Create an agent
import { createAgent } from '@coresourceai/sdk';
const agent = createAgent({
// A saga plans and executes durable, multi-step research.
type: 'saga',
// The system prompt defines the agent's research method and quality bar.
systemPrompt: `You are a rigorous deep-research agent. Decompose the question,
search broadly, prioritize primary sources, cross-check important claims, and
resolve conflicting evidence. Cite every material claim, distinguish established
facts from inference, state uncertainty explicitly, and deliver a clear,
evidence-backed final report.`,
// Select the hosted model and use its highest reasoning-effort setting.
model: 'deepseek/deepseek-v4-flash',
effort: 'xhigh',
// Declare the artifact the agent should produce and persist with the run.
outputs: ['report.md']
});
try {
const result = await agent.run('Validate the invoice-management benchmarks.');
console.log(result.text);
const report = result.artifacts.find((artifact) => artifact.name === 'report.md');
if (report) console.log(await report.text());
} finally {
await agent.close();
}
createAgent() is synchronous and lazy. It makes its first network request when
you call run() or start().
Starting an agent or saga requires at least $1.00 in prepaid balance unless
the account is on an enterprise plan. A rejected start throws
InsufficientFundsError with code InsufficientFunds. One-shot requests do not
allocate a runtime; they use the normal metered inference balance check.
CoreSource has three agent types:
| Type | Use it for |
|---|---|
one-shot | One model response without tools |
agent | Iterative work with tools, skills, files, or MCP |
saga | Planned, durable multi-step work |
The same values are available as AgentType.OneShot, AgentType.Agent, and
AgentType.Saga.
One-shot
const answerer = createAgent({
type: 'one-shot',
systemPrompt: 'Answer clearly and concisely.',
model: 'deepseek/deepseek-v4-flash'
});
const result = await answerer.run('Explain three-way invoice matching.');
console.log(result.text);
One-shot agents are intentionally tool-free. run() makes one synchronous
request to the API gateway and returns that model response directly—there is no
managed runtime, bridge session, run polling, or $1 runtime floor. Use agent
or saga when the run needs tools, files, skills, MCP servers, streamed
progress, or artifacts.
Tools
Hosted capabilities such as web search and hosted MCP servers execute entirely on CoreSource. They do not need a callback into your application.
An SDK-hosted tool executes in your process. The model calls its ordinary tool name, and CoreSource transparently routes the call to the registered handler:
const agent = createAgent({
type: 'agent',
systemPrompt: 'Use the available business data.',
tools: [{
name: 'lookup_invoice',
description: 'Look up an invoice by ID.',
inputSchema: {
type: 'object',
properties: { id: { type: 'string' } },
required: ['id'],
additionalProperties: false
},
handler: async (input, { signal }) => {
signal.throwIfAborted();
return lookupInvoice(String(input.id), { signal });
}
}]
});
const result = await agent.run('Summarize invoice INV-123.');
No local tools are registered by default. When an agent needs your application's filesystem, command runner, or network context, add the base catalog explicitly before its first run:
const codingAgent = createAgent({ type: 'agent' });
codingAgent.registerRuntimeTools();
The catalog contains file_read, file_write, file_edit, glob, grep,
web_fetch, and execute. An explicitly supplied SDK tool wins an exact-name
collision. Hosted search remains available as web_search.
Image understanding
Enable the hosted understand_image(image, prompt) tool by selecting a
vision-capable one-shot model in the agent definition:
const visualAgent = createAgent({
type: 'agent',
systemPrompt: 'Inspect supplied images before drawing conclusions.',
model: 'deepseek/deepseek-v4-pro',
imageModel: 'makora/kimi-2.7-code'
});
const result = await visualAgent.run({
prompt: 'Read the attached chart and explain its largest change.',
files: ['./quarterly-chart.png']
});
The image model is fixed by configuration; it is not an argument the agent can change. The hosted runtime reads the run-local image and performs a separately metered one-shot request through CoreSource. The image never needs to be round-tripped through your SDK process.
Skills and MCP
Skill strings can be installed names, public owner/repository/path references,
or full GitHub tree URLs:
import { CoreSource, createAgent } from '@coresourceai/sdk';
const coresource = new CoreSource();
// Save the remote credential once. It is encrypted by CoreSource and never
// placed in the agent runtime or returned by a read/list API.
const researchMcp = await coresource.mcp.connect({
name: 'Research',
url: 'https://mcp.example.com/rpc',
auth: { type: 'bearer', token: process.env.RESEARCH_MCP_TOKEN! }
});
const researcher = createAgent({
type: 'saga',
systemPrompt: 'Prefer primary sources and retain direct URLs.',
skills: [
'deep-research',
'anthropics/skills/skills/pdf',
'https://github.com/owner/repository/tree/COMMIT_SHA/path/to/skill'
],
mcpServers: [{
connectionId: researchMcp.id,
alias: 'research'
}],
outputs: ['research.md']
});
Connections created with an API key are account-scoped by default. Connections created from an authenticated user session are private to that user by default; an organization owner can explicitly select organization scope.
Hosted MCP entries use opaque connection IDs. CoreSource injects the remote
credential only at its outbound relay; agent definitions, runs, events, and
runtime configuration never contain it. OAuth connections return an
authorizationUrl to open once. Rotate static credentials with
coresource.mcp.connections.rotateCredential(...) and restart OAuth with
coresource.mcp.connections.authorize(...).
For GitHub, use CoreSource's managed OAuth app with one field:
const github = await coresource.mcp.connect({
name: 'GitHub',
url: 'https://api.githubcopilot.com/mcp/',
auth: { type: 'oauth', provider: 'github' }
});
// Send the user to GitHub once, then use github.id in mcpServers after the
// callback changes the connection status to "connected".
console.log(github.authorizationUrl);
An organization can instead register its own GitHub App or OAuth App. Its
client secret is write-only and encrypted by CoreSource. Configure the returned
callbackUrl in GitHub, then select the app by ID when creating connections:
const app = await coresource.mcp.oauthApps.create({
name: 'Acme GitHub',
provider: 'github',
clientId: process.env.GITHUB_CLIENT_ID!,
clientSecret: process.env.GITHUB_CLIENT_SECRET!
});
console.log(`Set the GitHub callback URL to ${app.callbackUrl}`);
const github = await coresource.mcp.connect({
name: 'Acme GitHub',
url: 'https://api.githubcopilot.com/mcp/',
auth: { type: 'oauth', appId: app.id }
});
OAuth app profiles are organization-level resources and require owner access.
Rotating coresource.mcp.oauthApps.rotateCredential(...) updates the client
used by every referenced connection without copying that secret into runs.
To run an MCP client in your application instead, call
agent.registerMcpServer(...) before the first run. Local skill bundles are also
supported through { name, content, files } entries.
Files and artifacts
Pass local paths or in-memory files with a run:
const result = await agent.run({
prompt: 'Analyze the supplied invoices and write findings.md.',
files: [
'./invoices.csv',
{
name: 'policy.txt',
path: 'references/policy.txt',
data: 'Escalate invoices above EUR 50,000.',
mimeType: 'text/plain'
}
],
input: { country: 'DE', currency: 'EUR' }
});
for (const artifact of result.artifacts) {
console.log(artifact.name, await artifact.text());
}
File destinations are relative names within the run's managed input area. Storage locations and runtime filesystem roots are not part of the public API.
Streaming and cancellation
run() waits for the final result. start() returns immediately for agent and
saga:
const run = await agent.start('Validate the benchmarks.');
for await (const event of run.events()) {
console.log(event.type, event.data);
}
const result = await run.result();
// When needed:
await run.cancel();
The event stream includes state, progress, logs, messages, tool activity, usage,
outputs, and the terminal result event. Event IDs can be used to resume safely.
Result polling has no overall timeout by default, so long-horizon runs can continue
for days. Pass timeoutMs only when the caller intentionally wants a wait deadline;
it never cancels the run.
Human input
When an agent calls ask_user, the run pauses durably with status
awaiting_input. run.result() returns immediately with the question, and
run.resume() continues the same run from its checkpoint:
const run = await agent.start('Prepare the launch plan and ask before choosing a date.');
let result = await run.result();
while (result.status === 'awaiting_input') {
const action = result.requiredAction;
if (!action) throw new Error('The run paused without a question.');
console.log(action.question);
const answer = await readAnswerFromYourUser();
await run.resume(answer);
result = await run.result();
}
For request/response applications, agent.run() can handle every pause through
one callback:
const result = await agent.run('Prepare the launch plan.', {
onInputRequired: async ({ question }) => {
return readAnswerFromYourUser(question);
}
});
Without onInputRequired, agent.run() returns the paused result instead of
waiting indefinitely. A run may request input more than once; each answer is
submitted to that run and execution resumes from the same durable state.
Compose agents
Compose sequential stages with composeAgents; use normal promises for parallel
branches:
import { composeAgents } from '@coresourceai/sdk';
const pipeline = composeAgents(researcher, {
agent: createAgent({
type: 'agent',
systemPrompt: 'Turn the upstream evidence into an executive brief.',
outputs: ['brief.md']
}),
prompt: ({ previous }) => ({
prompt: `Write the brief from this upstream summary:\n\n${previous.text}`,
inputs: previous.artifacts.map((artifact) => ({
type: 'artifact',
runId: previous.id,
artifactId: artifact.id,
path: `upstream/${artifact.name ?? artifact.id}`
}))
})
});
const { result, steps } = await pipeline.run('Research invoice automation.');
const [eu, us] = await Promise.all([
euResearcher.run('Research EU benchmarks.'),
usResearcher.run('Research US benchmarks.')
]);
Artifact handoff remains server-side when possible. If a downstream agent uses SDK-hosted tools, the SDK transparently downloads and re-uploads the handoff into that agent's managed input set.
Saved agents
Use CoreSource when the definition should be reusable and versioned on the
server:
import { CoreSource } from '@coresourceai/sdk';
const coresource = new CoreSource();
const saved = await coresource.agents.create({
name: 'invoice-researcher',
type: 'saga',
systemPrompt: 'Validate claims using primary sources.',
model: 'openai/gpt-5',
skills: ['anthropics/skills/skills/pdf'],
outputs: ['report.md']
});
const result = await saved.run('Validate these invoice-management benchmarks.');
const updated = await saved.update({ description: 'Primary-source invoice analyst' });
const versions = await updated.versions();
Saved definitions support create, retrieve, list, update, delete, run, immutable
versions, and version-pinned runs. Function handlers and local skill bundles are
process-local and therefore cannot be saved; use createAgent() for those.
For direct HTTP examples and the complete request schema, see CoreSource HTTP API guide.