Skip to content

Migrate from the OpenAI SDK

Moving from the official openai package to ORXA: LLM-SDK is mechanical. You replace the client construction and the call site; your prompts, tools, and schemas stay the same. Two paths:

  • Rewrite the call sites (this guide) — gets you the unified interface, per-call cost, observability, and agent governance.
  • Zero code changes — point your existing OpenAI client at ORXA’s OpenAI-compatible server and change only the baseURL.
Terminal window
npm install @combycode/llm-sdk

Before:

import OpenAI from 'openai';
const client = new OpenAI({ apiKey: process.env.OPENAI_API_KEY });
const res = await client.chat.completions.create({
model: 'gpt-5.5',
messages: [{ role: 'user', content: 'Hello' }],
});
console.log(res.choices[0].message.content);

After:

import { complete } from '@combycode/llm-sdk';
const { text } = await complete({
model: 'openai/gpt-5.5',
apiKey: process.env.OPENAI_API_KEY,
prompt: 'Hello',
});
console.log(text);

The model id becomes openai/<model>. The response is { text, parsed?, response } — no more reaching into choices[0].message.content. Token counts live on response.usage (response.usage.inputTokens, response.usage.outputTokens).

Before:

const res = await client.chat.completions.create({
model: 'gpt-5.5',
messages: [
{ role: 'system', content: 'You are terse.' },
{ role: 'user', content: 'Hello' },
],
});

After:

const { text } = await complete({
model: 'openai/gpt-5.5',
system: 'You are terse.',
prompt: 'Hello',
});

Pass a Message[] as the prompt:

const { text } = await complete({
model: 'openai/gpt-5.5',
prompt: [
{ role: 'user', content: 'Hi' },
{ role: 'assistant', content: 'Hello!' },
{ role: 'user', content: 'What did I just say?' },
],
});

For managed conversations (server-state, layered context), see Multi-turn and Conversation state.

Before:

const stream = await client.chat.completions.create({
model: 'gpt-5.5',
messages: [{ role: 'user', content: 'Count to 5.' }],
stream: true,
});
for await (const chunk of stream) {
process.stdout.write(chunk.choices[0]?.delta?.content ?? '');
}

After:

import { createLLM } from '@combycode/llm-sdk';
const llm = createLLM({ model: 'openai/gpt-5.5', apiKey: process.env.OPENAI_API_KEY });
for await (const ev of llm.stream('Count to 5.')) {
if (ev.type === 'text') process.stdout.write(ev.text);
}

Stream events are a discriminated union (text, thinking, usage, tool_call_start, done, …). See Streaming.

Before — you define a JSON schema, then manually parse tool_calls, execute, and loop:

const res = await client.chat.completions.create({
model: 'gpt-5.5',
messages: [{ role: 'user', content: 'Weather in Paris?' }],
tools: [{
type: 'function',
function: {
name: 'get_weather',
description: 'Get weather for a city',
parameters: { type: 'object', properties: { city: { type: 'string' } }, required: ['city'] },
},
}],
});
// ...read res.choices[0].message.tool_calls, run them, append results, call again

After — defineTool carries the executor, and complete() runs the tool loop for you:

import { complete, defineTool } from '@combycode/llm-sdk';
const getWeather = defineTool({
name: 'get_weather',
description: 'Get weather for a city',
params: { city: 'string' },
execute: async ({ city }) => `Sunny in ${city}`,
});
const { text } = await complete({
model: 'openai/gpt-5.5',
prompt: 'Weather in Paris?',
tools: [getWeather],
});

See Single tool call and Multi-step loop.

Before:

const res = await client.chat.completions.create({
model: 'gpt-5.5',
messages: [{ role: 'user', content: 'Extract name and age: John is 30' }],
response_format: { type: 'json_schema', json_schema: { name: 'person', schema: { /* ... */ } } },
});
const data = JSON.parse(res.choices[0].message.content ?? '{}');

After — pass a structured.schema; the parsed object comes back on parsed:

const { parsed } = await complete({
model: 'openai/gpt-5.5',
prompt: 'Extract name and age: John is 30',
structured: {
schema: {
type: 'object',
properties: { name: { type: 'string' }, age: { type: 'number' } },
required: ['name', 'age'],
},
},
});
console.log(parsed); // { name: 'John', age: 30 }

Note: if the model returns invalid JSON, complete() throws — wrap in try/catch to retry. See Structured output.

Built-in tools (web search, code interpreter)

Section titled “Built-in tools (web search, code interpreter)”

OpenAI’s built-ins pass through verbatim:

const { text } = await complete({
model: 'openai/gpt-5.5',
prompt: 'What launched this week?',
tools: [{ type: 'web_search' }],
});

See Web search and Server-side tools.

If you don’t want to touch your call sites at all, run ORXA’s OpenAI-compatible server and repoint your existing OpenAI client:

const client = new OpenAI({
apiKey: 'your-server-key',
baseURL: 'http://localhost:8787/v1', // ORXA server
});
// every existing chat.completions.create(...) call now flows through ORXA
Official SDKORXA
Model id'gpt-5.5''openai/gpt-5.5'
Response textchoices[0].message.contentresult.text
Token usageusage.prompt_tokensresponse.usage.inputTokens
Tool loopmanualrun by complete()
Switch providernew SDK + new shapeschange the model string

Next: Models & providers · Provider routing & fallback · Cost tracking.