Install & quickstart
Install
Section titled “Install”# bun (recommended)bun add @combycode/llm-sdk
# npmnpm install @combycode/llm-sdk
# pnpmpnpm add @combycode/llm-sdkZero runtime dependencies. The package ships a browser bundle at dist/index.browser.js.
Provide a key
Section titled “Provide a key”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:
| Provider | Typical env var |
|---|---|
| Anthropic | ANTHROPIC_API_KEY |
| OpenAI | OPENAI_API_KEY |
GOOGLE_API_KEY | |
| xAI | XAI_API_KEY |
| OpenRouter | OPENROUTER_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, },});Your first completion
Section titled “Your first completion”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. 14console.log(usage.outputTokens); // e.g. 2console.log(response.finishReason); // 'stop'Switch provider
Section titled “Switch provider”Change the model string. Your code stays the same.
// OpenAIconst { text } = await complete({ model: 'openai/gpt-4o', apiKey: process.env.OPENAI_API_KEY, prompt: 'Say hello in one sentence.',});
// Googleconst { 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.
See how it compares
Section titled “See how it compares”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.
Add streaming
Section titled “Add streaming”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 ?? '');}Track cost
Section titled “Track cost”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 callconsole.log(engine.cost.total); // cumulative spend for this engine instanceNext steps
Section titled “Next steps”- 4-layer architecture - understand the composable layer stack
- vs Official SDKs - see what makes ORXA different
- Open the Sandbox - try providers interactively with your own API keys