Overview
The OpenAI harness provides direct integration with OpenAI’s Responses API. It supports reasoning models like o1 and o3 with native reasoning content streaming.
Import
import { createGeneratorHarness, openAiHarness } from "@llm-gateway/ai/harness/providers/openai";
Function Signature
function createGeneratorHarness(
apiKeyOrOptions?: string | OpenAIHarnessOptions
): GeneratorHarnessModule
Parameters
apiKeyOrOptions
string | OpenAIHarnessOptions
API key string or configuration objectOpenAI API key. Falls back to OPENAI_API_KEY environment variable
Default model to use if not specified at invoke time
Returns
A harness module with invoke() and supportedModels() methods
What It Does
The OpenAI harness makes single LLM API calls and yields events for:
- reasoning: Streamed reasoning text from o1/o3 models
- text: Streamed output text content
- tool_call: Function calls from the model
- error: Any errors that occur
It does NOT:
- Execute tools (that’s the agent wrapper’s job)
- Handle permissions (that’s the agent wrapper’s job)
- Loop after tool calls (that’s the agent wrapper’s job)
Basic Example
import { createGeneratorHarness } from "@llm-gateway/ai/harness/providers/openai";
// Create with API key
const harness = createGeneratorHarness({
apiKey: process.env.OPENAI_API_KEY,
model: "gpt-4o",
});
// Make a single LLM call
for await (const event of harness.invoke({
model: "gpt-4o",
messages: [{ role: "user", content: "Hello!" }],
})) {
if (event.type === "text") {
console.log(event.content);
}
}
Using the Singleton
import { openAiHarness } from "@llm-gateway/ai/harness/providers/openai";
// Use pre-configured singleton (reads OPENAI_API_KEY from env)
for await (const event of openAiHarness.invoke({
model: "o1",
messages: [{ role: "user", content: "Solve this problem..." }],
})) {
if (event.type === "text") {
console.log(event.content);
}
}
Reasoning Models
O1 and O3 models support native reasoning content:
for await (const event of harness.invoke({
model: "o1",
messages: [{ role: "user", content: "Solve this complex math problem..." }],
})) {
if (event.type === "reasoning") {
console.log("[Reasoning]", event.content);
}
if (event.type === "text") {
console.log("[Answer]", event.content);
}
}
import { z } from "zod";
const tools = [
{
name: "calculator",
description: "Perform mathematical calculations",
schema: z.object({
expression: z.string(),
}),
},
];
for await (const event of harness.invoke({
model: "gpt-4o",
messages: [{ role: "user", content: "Calculate 15 * 23" }],
tools,
})) {
if (event.type === "tool_call") {
console.log(`Tool: ${event.name}`);
console.log(`Input:`, event.input);
}
}
All tools are created with strict: true for structured output enforcement.
The OpenAI harness uses the Responses API, which has a different structure than Chat Completions:
// System messages become instructions
// Tool results are function_call_output items
for await (const event of harness.invoke({
model: "gpt-4o",
messages: [
{ role: "system", content: "You are a helpful assistant" },
{ role: "user", content: "Hello" },
{ role: "assistant", tool_calls: [{ id: "1", name: "search", arguments: {...} }] },
{ role: "tool", tool_call_id: "1", content: "Results..." },
],
})) {
console.log(event);
}
Multimodal Support
Supports images and files:
for await (const event of harness.invoke({
model: "gpt-4o",
messages: [
{
role: "user",
content: [
{ type: "text", text: "Analyze this image" },
{
type: "image",
mediaType: "image/png",
data: base64ImageData,
},
],
},
],
})) {
if (event.type === "text") {
console.log(event.content);
}
}
Supported Models
Automatically filters for chat models:
const models = await harness.supportedModels();
console.log("Available models:", models);
// Returns models containing: gpt, o1, o3, or chatgpt
Wrapping with Agent Harness
import { createAgentHarness } from "@llm-gateway/ai/harness/agent";
import { createGeneratorHarness } from "@llm-gateway/ai/harness/providers/openai";
// Wrap OpenAI provider with agent capabilities
const agent = createAgentHarness({
harness: createGeneratorHarness(),
maxIterations: 10,
});
// Now supports tool execution and looping
for await (const event of agent.invoke({
model: "gpt-4o",
messages: [{ role: "user", content: "Search and summarize results" }],
tools: [searchTool, readTool],
})) {
console.log(event);
}
Event Types
Reasoning Text Delta
if (event.type === "reasoning") {
// event.content: string - reasoning content chunk
// event.id: string - stable ID for this reasoning stream
// event.runId: string - provider call ID
}
Output Text Delta
if (event.type === "text") {
// event.content: string - output text chunk
// event.id: string - stable ID for this text stream
// event.runId: string - provider call ID
}
if (event.type === "tool_call") {
// event.name: string - function name
// event.input: unknown - parsed arguments
// event.id: string - call_id from Responses API
}
Error Handling
for await (const event of harness.invoke({
model: "gpt-4o",
messages: [{ role: "user", content: "Hello!" }],
})) {
if (event.type === "error") {
console.error("Error:", event.error.message);
}
}
Architecture Notes
- Uses OpenAI SDK for streaming
- Tracks tool calls by output_index
- Handles reasoning_text.delta and output_text.delta separately
- Converts message format from OpenAI chat to Responses API
- Single iteration only - compose with agent harness for loops