Stream text from a server-side Node.js application using the OpenAI SDK. This is a configuration recipe, not a live-tested integration claim.
Install and run
Use a Node.js version supported by the installed SDK. Install the package and export your key:
npm install openai
export REDROUTER_API_KEY="your-redrouter-api-key"
Save as example.mjs:
import OpenAI from "openai";
const apiKey = process.env.REDROUTER_API_KEY;
if (!apiKey) throw new Error("Set REDROUTER_API_KEY");
const client = new OpenAI({
apiKey,
baseURL: "https://redrouter.org/v1",
timeout: 120_000,
maxRetries: 0,
});
try {
const stream = await client.chat.completions.create({
model: "red-cyber-1",
messages: [{ role: "user", content: "Explain an HTTP timeout in two sentences." }],
max_tokens: 512,
stream: true,
stream_options: { include_usage: true },
});
let finishReason = null;
try {
for await (const chunk of stream) {
for (const choice of chunk.choices) {
process.stdout.write(choice.delta.content ?? "");
if (choice.finish_reason != null) finishReason = choice.finish_reason;
}
if (chunk.usage) console.error(JSON.stringify(chunk.usage));
}
} finally {
stream.controller.abort();
}
if (finishReason !== "stop") throw new Error(`Incomplete text stream: ${finishReason}`);
process.stdout.write("\n");
} catch (error) {
if (error instanceof OpenAI.APIError) {
console.error(`RedRouter HTTP ${error.status ?? "unavailable"}`);
} else {
console.error("Request failed; check connectivity and configuration.");
}
process.exitCode = 1;
}
Run node example.mjs. Successful output arrives incrementally, followed by usage when reported. An empty choices array is valid on the final usage chunk. The finish-reason check catches missing or abnormal text completion, but SDK iteration alone does not establish receipt of [DONE]. For exact terminal-event handling, follow the raw SSE reader. An interrupted stream is incomplete even if it printed useful text.
Use a single response
With the same client, a non-streaming call uses:
const completion = await client.chat.completions.create({
model: "red-cyber-1",
messages: [{ role: "user", content: "Say hello." }],
max_tokens: 256,
});
if (completion.choices[0].finish_reason !== "stop") {
throw new Error("The request did not finish with a complete text answer.");
}
console.log(completion.choices[0].message.content);
Use the same error handling around this call. The SDK also exposes Responses; use RedRouter's Responses contract for its stateless history requirements.
Use the Anthropic SDK
Install the Messages client:
npm install @anthropic-ai/sdk
Save as messages-example.mjs and run node messages-example.mjs with the same REDROUTER_API_KEY environment variable:
import Anthropic from "@anthropic-ai/sdk";
const apiKey = process.env.REDROUTER_API_KEY;
if (!apiKey) throw new Error("Set REDROUTER_API_KEY");
const client = new Anthropic({
apiKey,
baseURL: "https://redrouter.org",
timeout: 120_000,
maxRetries: 0,
});
try {
const result = await client.messages.create({
model: "red-cyber-1",
max_tokens: 512,
messages: [{ role: "user", content: "Explain an HTTP timeout in two sentences." }],
});
if (result.stop_reason !== "end_turn") throw new Error("Incomplete text answer");
console.log(result.content.filter(block => block.type === "text").map(block => block.text).join(""));
console.error(result.usage);
} catch (error) {
console.error(`Messages request failed: HTTP ${error.status ?? "unavailable"}`);
process.exitCode = 1;
}
The Anthropic SDK uses the origin without /v1; it appends /v1/messages. This is RedRouter inference billed to your RedRouter account. See Messages for content-block, tool, and usage behavior; an SDK exposing a feature does not establish support for it.
Integrate into a service
Keep this client and key on the server. Authenticate your own users, cap prompt length and output, and propagate request cancellation when the caller disconnects. For streamed tool calls, accumulate argument deltas and validate complete arguments before execution; see streaming and tool calling.
Automatic retries are disabled in the example. Add retries at one layer with bounded backoff after reviewing production guidance. The red-cyber-1 model supports tools and structured output; it is text-only. Check compatibility before sending audio, images, or provider-specific SDK options.
References: OpenAI JavaScript SDK and Anthropic TypeScript SDK.