Skip to content

Repository files navigation

eliware.org

@eliware/openai npm versionlicensebuild status

A simple OpenAI API client wrapper for Node.js, with ESM and TypeScript support.


Table of Contents

Features

  • Minimal wrapper for the official OpenAI Node.js SDK
  • ESM-first and TypeScript-ready
  • Simple API key management (environment or parameter)
  • Full OpenAI SDK option passthrough, including endpoints, timeouts, retries, and custom fetch
  • Selectable HTTP or Responses WebSocket transport
  • Streaming and non-streaming Responses API calls
  • Bounded WebSocket queueing with explicit shutdown
  • Example usage and tests included

Requirements

  • Node.js 26 or newer
  • An OpenAI API key for OpenAI usage

Installation

npm install @eliware/openai

Usage

import { createOpenAI } from '@eliware/openai';

(async () => {
  // Optionally pass your API key, or set OPENAI_API_KEY in your environment
  const openai = createOpenAI();
  // Example: list models
  // const models = await openai.models.list();
  // console.log(models);
})();

API

createOpenAI(options?: string | OpenAIOptions): OpenAIClient

Creates and returns a new OpenAI client instance. Pass an API key string for compatibility, or an options object accepted by the official SDK. The API key defaults to OPENAI_API_KEY.

createOpenAI('sk-...');
createOpenAI({ apiKey: 'sk-...', baseURL: 'https://api.example.test/v1', timeout: 30_000, maxRetries: 3 });

WebSocket Responses transport

HTTP is the default. Select the Responses WebSocket transport when needed:

const openai = createOpenAI({
  apiKey: 'sk-...',
  transport: 'websocket',
});

const response = await openai.responses.create({ model: 'gpt-5.6-luna', input: 'Hello' });
const events = openai.responses.stream({ model: 'gpt-5.6-luna', input: 'Hello' });
for await (const event of events) console.log(event);

await openai.responses.close();

Version 2 supports one in-flight WebSocket response request per client. Concurrent requests reject explicitly to prevent response-event cross-talk.

The WebSocket adapter also exposes a transport-neutral event iterator. Use events() when you need protocol events without collecting a final response:

const events = openai.responses.events({ model: 'gpt-5.6-luna', input: 'Hello' }, { signal });
for await (const event of events) console.log(event);

create() and stream() accept { signal }. Completed responses resolve normally; failed, incomplete, socket-error, and premature-close events reject with ResponsesError, which preserves the original event and available error metadata. responses.close() is awaitable and bounded; use await responses.close({ timeout: 30_000 }) to control the shutdown deadline. On timeout it terminates the socket when supported and rejects with ResponsesError.

Callbacks are available through createWithEvents() (and the second argument to create()) without changing the normal event iterator API. AgentX-compatible lifecycle callbacks include onResponseCreated, onResponseProgress, onContentPartAdded, onContentPartDone, onTextDone, and onResponseCompleted:

await openai.responses.createWithEvents(request, {
  onEvent: (event, raw) => {},
  onResponseCreated: (response, event) => {},
  onResponseProgress: (response, event) => {},
  onContentPartAdded: (part, event) => {},
  onContentPartDone: (part, event) => {},
  onTextDelta: (delta, event) => {},
  onItemAdded: (item, event) => {},
  onItemDone: (item, event) => {},
  onTextDone: (text, event) => {},
  onCompleted: (response, event) => {},
  onResponseCompleted: (response, event) => {},
  onError: (error, event) => {},
});

For deterministic tests, createMockResponsesTransport(events) returns an injectable WebSocket implementation. It accepts optional { autoOpen, delay, events } options; the event list can include text, function/shell/MCP argument deltas, reasoning summaries, output items, terminal events, and arbitrary socket scenarios. The returned fake exposes push(), error(), sent, and instances for deterministic lifecycle tests.

For Node-compatible custom transports, provide WebSocketImpl and optionally url in the client options. The constructor receives (url, { headers }); browser-native WebSocket constructors are not supported directly. The adapter exposes await responses.ready(), responses.isOpen(), and responses.state (connecting, open, closing, or closed). Events include raw, responseId, and requestId when supplied by the server.

The WebSocket adapter also supports the familiar responses.stream() helper and preserves inputItems and inputTokens resources. The connection remains available while the client is retained. The WebSocket adapter continues to expose HTTP Responses helpers such as retrieve, delete, cancel, and parse. Call responses.close() during shutdown.

Both helpers throw clear errors when required configuration is missing.

Errors / Troubleshooting

createOpenAI requires an API key from apiKey or OPENAI_API_KEY. Transport, timeout, retry, abort, and WebSocket shutdown errors preserve available upstream context. Always await responses.close() for WebSocket clients.

Development

npm test
npm run test:gaps
npm run lint
npm run typecheck
npm run pack

Security

Treat API keys and endpoint credentials as secrets. Store them in environment variables or a secret manager; never commit .env files, log credentials, or expose keys in examples.

TypeScript

Type definitions are included:

import type OpenAI from 'openai';
import { createOpenAI } from '@eliware/openai';
const openai: import('@eliware/openai').OpenAIClient = createOpenAI();

Support

For help, questions, or to chat with the author and community, visit:

Discordeliware.org

eliware.org on Discord

License

MIT © 2025 Eli Sterling, eliware.org

Links

Tool and item streaming

The event iterator and callbacks preserve protocol event types. TypeScript consumers can use the exported ResponsesEvent union and narrow on event.type.

Handle these tool/event families in the iterator or onEvent callback:

  • response.output_item.added / response.output_item.done
  • response.function_call_arguments.delta / .done
  • response.shell_call_command.delta / .done
  • response.custom_tool_call_input.delta / .done
  • response.mcp_call_arguments.delta / .done
  • reasoning summary/text delta and done events
  • text delta/done events

Accumulate argument/input deltas by output-item ID. On the corresponding .done event, parse the completed arguments, execute or confirm the tool in the application, then submit its output with a new Responses request using previous_response_id. This library does not execute tools, handle confirmations, or persist tool state.

raw contains the original transport event. responseId and requestId are populated when supplied by the server. Error events preserve the original event and available code, type, status, parameter, requestId, and cause metadata. onError is called for protocol failures, socket failures, premature close, abort, and stream exhaustion.

Event and error contract

WebSocket lifecycle events (connecting, open, close, and error) are transport events. Reconnect is not performed by the 2.0 adapter; an interruption fails the active request. Response protocol events are yielded with their original type, plus raw, responseId, and requestId when available. ResponsesError preserves the originating event and exposes code, type, status, parameter, requestId, and cause where available. Always await responses.close() during shutdown.

About

A simple OpenAI API client wrapper for Node.js, with ESM and TypeScript support.

Topics

Resources

Stars

0 stars

Watchers

0 watching

Forks

Releases

Contributors

Languages