Skip to content

Install & quickstart

Terminal window
# bun (recommended)
bun add @combycode/llm-sdk
# npm
npm install @combycode/llm-sdk
# pnpm
pnpm add @combycode/llm-sdk

Zero runtime dependencies. The package ships a browser bundle at dist/index.browser.js.

Pass your API key as the apiKey option on any complete() call:

import { complete } from '@combycode/llm-sdk';
const { text } = await complete({
model: 'anthropic/claude-haiku-4-5',
apiKey: process.env.ANTHROPIC_API_KEY, // read from environment
prompt: 'Say hello in one sentence.',
});

The apiKey option falls back to the engine’s global key map when omitted (see below). Read keys from the environment — never hard-code them in source files.

Environment variable names by provider:

ProviderTypical env var
AnthropicANTHROPIC_API_KEY
OpenAIOPENAI_API_KEY
GoogleGOOGLE_API_KEY
xAIXAI_API_KEY
OpenRouterOPENROUTER_API_KEY

For scripts with a single provider, pass apiKey inline as shown above. For multi-model applications, configure once at startup so every complete() call resolves keys from the engine and apiKey can be omitted:

import { createEngine } from '@combycode/llm-sdk';
createEngine({
apiKeys: {
anthropic: process.env.ANTHROPIC_API_KEY,
openai: process.env.OPENAI_API_KEY,
},
});
import { complete } from '@combycode/llm-sdk';
const { text } = await complete({
model: 'anthropic/claude-haiku-4-5',
apiKey: process.env.ANTHROPIC_API_KEY,
prompt: 'Say hello in one sentence.',
});
console.log(text);

That’s it. One import, one call, text back.

complete() also returns usage (normalized token counts) and the raw response:

const { text, usage, response } = await complete({
model: 'anthropic/claude-haiku-4-5',
apiKey: process.env.ANTHROPIC_API_KEY,
prompt: 'Reply with exactly: OK',
});
console.log(text); // 'OK'
console.log(usage.inputTokens); // e.g. 14
console.log(usage.outputTokens); // e.g. 2
console.log(response.finishReason); // 'stop'

Change the model string. Your code stays the same.

// OpenAI
const { text } = await complete({
model: 'openai/gpt-4o',
apiKey: process.env.OPENAI_API_KEY,
prompt: 'Say hello in one sentence.',
});
// Google
const { text: text2 } = await complete({
model: 'google/gemini-2-0-flash',
apiKey: process.env.GOOGLE_API_KEY,
prompt: 'Say hello in one sentence.',
});

The model string format is always provider/model-slug. This is how the SDK routes to the right provider without any extra configuration.

The text field is always a plain string regardless of provider. Official SDKs return nested, provider-specific shapes: OpenAI’s response has output[0].content[0].text; Anthropic’s has content[0].text. ORXA resolves all of that into one field and normalises usage to the same shape.

import { complete } from '@combycode/llm-sdk';

const t0 = performance.now();
const { text } = await complete({
  model: process.env.LLM_MODEL!,
  apiKey: process.env.LLM_API_KEY,
  prompt: 'Reply with exactly: OK',
  maxTokens: 16,
});

console.log(JSON.stringify({ result: text.trim(), ms: Math.round(performance.now() - t0) }));
import { stream } from '@combycode/llm-sdk';
for await (const chunk of stream({
model: 'anthropic/claude-haiku-4-5',
apiKey: process.env.ANTHROPIC_API_KEY,
prompt: 'Count to 5.',
})) {
process.stdout.write(chunk.delta ?? '');
}
import { complete, createEngine } from '@combycode/llm-sdk';
const engine = createEngine();
const { text, usage } = await complete({
model: 'openai/gpt-4o',
apiKey: process.env.OPENAI_API_KEY,
prompt: 'Short summary of TypeScript.',
engine,
});
console.log(usage.cost); // USD cost of this call
console.log(engine.cost.total); // cumulative spend for this engine instance