OpenAI SDK
Use the official OpenAI SDK for Python and TypeScript with this API.
The official OpenAI SDK works as it is. Point it at https://pinerouter.ai/v1 with your key, and chat completions, responses, streaming, tool calling and images all go through the same client. Every text model on Models answers in this format, not only OpenAI's.
Install
pip install openaiuv add openainpm install openaipnpm add openaibun add openaiConfigure API keys
API_KEY=sk-...Load it into the environment before you run the code (for example with python-dotenv, or node --env-file=.env). Keep the key out of your code.
Run
Text
import os
from openai import OpenAI
client = OpenAI(base_url="https://pinerouter.ai/v1", api_key=os.environ["API_KEY"])
r = client.chat.completions.create(
model="gpt-6-luna",
messages=[{"role": "user", "content": "Name three rivers in Europe."}],
)
print(r.choices[0].message.content)import OpenAI from "openai";
const client = new OpenAI({ baseURL: "https://pinerouter.ai/v1", apiKey: process.env.API_KEY });
const r = await client.chat.completions.create({
model: "gpt-6-luna",
messages: [{ role: "user", content: "Name three rivers in Europe." }],
});
console.log(r.choices[0].message.content);Stream
stream = client.chat.completions.create(
model="gpt-6-luna",
messages=[{"role": "user", "content": "Write a haiku about rivers."}],
stream=True,
)
for chunk in stream:
if chunk.choices and chunk.choices[0].delta.content:
print(chunk.choices[0].delta.content, end="", flush=True)
if chunk.usage:
print("\n", chunk.usage)const stream = await client.chat.completions.create({
model: "gpt-6-luna",
messages: [{ role: "user", content: "Write a haiku about rivers." }],
stream: true,
});
for await (const chunk of stream) {
process.stdout.write(chunk.choices[0]?.delta?.content ?? "");
if (chunk.usage) console.log("\n", chunk.usage);
}The last chunk carries usage and an empty choices list, so check choices before you read it. More in Streaming.
Tool calling
The model asks for a tool, you run it and send the result back.
import json
tools = [{
"type": "function",
"function": {
"name": "get_weather",
"description": "Current weather for a city",
"parameters": {"type": "object", "properties": {"city": {"type": "string"}}, "required": ["city"]},
},
}]
messages = [{"role": "user", "content": "What is the weather in Paris?"}]
r = client.chat.completions.create(model="gpt-6-luna", messages=messages, tools=tools)
msg = r.choices[0].message
if msg.tool_calls:
messages.append(msg.to_dict())
for call in msg.tool_calls:
city = json.loads(call.function.arguments)["city"]
messages.append({"role": "tool", "tool_call_id": call.id, "content": f"Sunny, 21 C in {city}"})
r = client.chat.completions.create(model="gpt-6-luna", messages=messages, tools=tools)
print(r.choices[0].message.content)import type { ChatCompletionMessageParam, ChatCompletionTool } from "openai/resources/chat/completions";
const tools: ChatCompletionTool[] = [{
type: "function",
function: {
name: "get_weather",
description: "Current weather for a city",
parameters: { type: "object", properties: { city: { type: "string" } }, required: ["city"] },
},
}];
const messages: ChatCompletionMessageParam[] = [{ role: "user", content: "What is the weather in Paris?" }];
let r = await client.chat.completions.create({ model: "gpt-6-luna", messages, tools });
const msg = r.choices[0].message;
if (msg.tool_calls?.length) {
messages.push(msg);
for (const call of msg.tool_calls) {
if (call.type !== "function") continue;
const { city } = JSON.parse(call.function.arguments);
messages.push({ role: "tool", tool_call_id: call.id, content: `Sunny, 21 C in ${city}` });
}
r = await client.chat.completions.create({ model: "gpt-6-luna", messages, tools });
}
console.log(r.choices[0].message.content);Images
img = client.images.generate(model="z-image", prompt="A red paper boat on a calm lake", size="1024x1024")
print(img.data[0].url)const img = await client.images.generate({ model: "z-image", prompt: "A red paper boat on a calm lake", size: "1024x1024" });
console.log(img.data?.[0]?.url);The call waits for the image; the SDK's default timeout of 10 minutes is enough. For video, music, speech or a model's own settings, use Jobs with the HTTP helper; the same key works.
Specifics
client.responses.create(...)(the Responses API) works too. See Responses.- The SDK also reads
OPENAI_BASE_URLandOPENAI_API_KEYfrom the environment, so you can set those instead of passing them in code. - It retries
429and5xxon its own, 2 times by default. Change it withmax_retries(Python) ormaxRetries(TypeScript). - Tool calling, JSON output and vision depend on the model. Test with the model you plan to use. See Text.
Next
- Streaming: events, usage and errors mid-stream
- Images and Jobs: media models
- Chat completions: every field
