Skip to content

Migrate from the Google GenAI SDK

Moving from the official @google/genai package to ORXA: LLM-SDK is mechanical. You replace the client construction and the call site; your prompts, tools, and schemas stay the same — and the same code now also runs OpenAI, Anthropic, and xAI by changing one string.

Terminal window
npm install @combycode/llm-sdk

Before:

import { GoogleGenAI } from '@google/genai';
const ai = new GoogleGenAI({ apiKey: process.env.GEMINI_API_KEY });
const res = await ai.models.generateContent({
model: 'gemini-3.5-flash',
contents: 'Hello',
});
console.log(res.text);

After:

import { complete } from '@combycode/llm-sdk';
const { text } = await complete({
model: 'google/gemini-3.5-flash',
apiKey: process.env.GEMINI_API_KEY,
prompt: 'Hello',
});
console.log(text);

The model id becomes google/<model>. The response is { text, parsed?, response }; token counts are on response.usage (response.usage.inputTokens, response.usage.outputTokens) instead of res.usageMetadata.

Google takes the system text via config.systemInstruction; ORXA takes a top-level system:

Before:

const res = await ai.models.generateContent({
model: 'gemini-3.5-flash',
contents: 'Hello',
config: { systemInstruction: 'You are terse.' },
});

After:

const { text } = await complete({
model: 'google/gemini-3.5-flash',
system: 'You are terse.',
prompt: 'Hello',
});

Before, you build a contents array of { role, parts }. In ORXA, pass a Message[]:

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

Note ORXA uses assistant for the model turn (not Google’s model role) — it normalizes roles for you. See Multi-turn.

Before:

const stream = await ai.models.generateContentStream({
model: 'gemini-3.5-flash',
contents: 'Count to 5.',
});
for await (const chunk of stream) {
process.stdout.write(chunk.text ?? '');
}

After:

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

See Streaming.

Before — declare functionDeclarations, then read functionCalls, execute, append a functionResponse, and call again:

const res = await ai.models.generateContent({
model: 'gemini-3.5-flash',
contents: 'Weather in Paris?',
config: {
tools: [{
functionDeclarations: [{
name: 'get_weather',
description: 'Get weather for a city',
parameters: { type: 'object', properties: { city: { type: 'string' } }, required: ['city'] },
}],
}],
},
});
// ...read res.functionCalls, run them, append functionResponse, loop

After — defineTool carries the executor, complete() runs the loop:

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: 'google/gemini-3.5-flash',
prompt: 'Weather in Paris?',
tools: [getWeather],
});

See Single tool call and Multi-step loop.

Before, Google’s responseMimeType + responseSchema; in ORXA, the unified structured.schema option:

const { parsed } = await complete({
model: 'google/gemini-3.5-flash',
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 }

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

Google’s grounding maps to a built-in tool:

const { text } = await complete({
model: 'google/gemini-3.5-flash',
prompt: 'What launched this week?',
tools: [{ type: 'web_search' }],
});

See Web search.

Official SDKORXA
Model id'gemini-3.5-flash''google/gemini-3.5-flash'
System textconfig.systemInstructiontop-level system
Response textres.textresult.text
Token usageres.usageMetadataresponse.usage.inputTokens
Model turn role'model''assistant' (normalized)
Tool loopmanualrun by complete()
Switch providernew SDK + new shapeschange the model string

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