Building a TypeScript AI App with OpenModex SDK
A hands-on tutorial for building a production-ready TypeScript application using the OpenModex SDK, covering setup, streaming, error handling, and deployment.
David Liu
Senior Engineer

TypeScript is the dominant language for AI-powered web applications, and the OpenModex SDK is designed to make it a first-class experience. In this tutorial, we will build a complete AI-powered content generation service from scratch, covering everything from initial setup to production deployment.
Setting Up Your Project
Start by creating a new TypeScript project and installing the OpenModex SDK:
// Initialize project
// npm init -y && npm install @openmodex/sdk typescript @types/node tsx
import { OpenModex } from "@openmodex/sdk";
const client = new OpenModex({
apiKey: process.env.OPENMODEX_API_KEY!,
});The SDK ships with full TypeScript type definitions, so you get autocomplete and type checking out of the box. No @types package needed.
Basic Chat Completion
The simplest API call follows the familiar chat completions pattern:
async function generateContent(topic: string): Promise<string> {
const response = await client.chat.completions.create({
model: "auto", // Let smart routing choose the best model
messages: [
{
role: "system",
content: "You are a technical writer. Write clear, concise content.",
},
{
role: "user",
content: `Write a short paragraph about: ${topic}`,
},
],
temperature: 0.7,
max_tokens: 500,
});
return response.choices[0].message.content ?? "";
}The model: "auto" setting lets OpenModex's smart routing select the optimal model for each request. You can also specify exact models like "openai/gpt-4o" or "anthropic/claude-sonnet-4-5-20250929".
Streaming Responses
For real-time UI updates, use streaming to receive tokens as they are generated:
async function streamContent(topic: string): Promise<void> {
const stream = await client.chat.completions.create({
model: "auto",
messages: [
{ role: "user", content: `Explain ${topic} in detail` },
],
stream: true,
});
for await (const chunk of stream) {
const content = chunk.choices[0]?.delta?.content;
if (content) {
process.stdout.write(content);
}
}
}Streaming works identically across all providers. Whether the underlying model is from OpenAI, Anthropic, or Google, the stream format is normalized to a consistent interface.
Structured Output with Zod
For applications that need structured data, use the SDK's built-in schema validation:
import { z } from "zod";
const ArticleSchema = z.object({
title: z.string(),
summary: z.string(),
tags: z.array(z.string()),
readingTime: z.number(),
});
type Article = z.infer<typeof ArticleSchema>;
async function generateArticle(topic: string): Promise<Article> {
const response = await client.chat.completions.create({
model: "auto",
messages: [
{
role: "user",
content: `Generate an article outline about: ${topic}`,
},
],
response_format: {
type: "json_schema",
json_schema: {
name: "article",
schema: ArticleSchema,
},
},
});
return JSON.parse(response.choices[0].message.content ?? "{}");
}The SDK automatically selects a model that supports structured output and validates the response against your schema.
Error Handling and Retries
Production applications need robust error handling. The SDK provides typed errors and built-in retry logic:
import { OpenModex, APIError, RateLimitError, TimeoutError } from "@openmodex/sdk";
const client = new OpenModex({
apiKey: process.env.OPENMODEX_API_KEY!,
maxRetries: 3, // Retry failed requests up to 3 times
timeout: 30000, // 30 second timeout
});
async function safeGenerate(prompt: string): Promise<string | null> {
try {
const response = await client.chat.completions.create({
model: "auto",
messages: [{ role: "user", content: prompt }],
});
return response.choices[0].message.content;
} catch (error) {
if (error instanceof RateLimitError) {
console.error("Rate limited. Retry after:", error.retryAfter);
} else if (error instanceof TimeoutError) {
console.error("Request timed out");
} else if (error instanceof APIError) {
console.error("API error:", error.status, error.message);
}
return null;
}
}The SDK's built-in retry logic uses exponential backoff with jitter, so you do not need to implement retry logic yourself.
Building an Express API
Here is a complete Express server that exposes your AI functionality as an API:
import express from "express";
import { OpenModex } from "@openmodex/sdk";
const app = express();
const client = new OpenModex({ apiKey: process.env.OPENMODEX_API_KEY! });
app.use(express.json());
app.post("/api/generate", async (req, res) => {
const { prompt, stream: useStream } = req.body;
if (useStream) {
res.setHeader("Content-Type", "text/event-stream");
const stream = await client.chat.completions.create({
model: "auto",
messages: [{ role: "user", content: prompt }],
stream: true,
});
for await (const chunk of stream) {
const content = chunk.choices[0]?.delta?.content ?? "";
res.write(`data: ${JSON.stringify({ content })}\n\n`);
}
res.end();
} else {
const response = await client.chat.completions.create({
model: "auto",
messages: [{ role: "user", content: prompt }],
});
res.json({ content: response.choices[0].message.content });
}
});
app.listen(3000, () => console.log("Server running on port 3000"));What is Next
This tutorial covered the fundamentals. From here, explore the SDK's advanced features: function calling for tool use, embeddings for semantic search, batch processing for high-throughput workloads, and the analytics API for cost monitoring.
Full SDK documentation and additional examples are available at docs.openmodex.com/sdk/typescript.