Skip to main content

OpenAI Adapter

@accordkit/provider-openai decorates the official OpenAI JavaScript SDK. It emits normalized AccordKit events (message, tool_call, usage, tool_result, span) without changing how you call chat.completions.create or the newer beta namespaces.

Install​

pnpm add @accordkit/tracer @accordkit/provider-openai openai

Wrap the client​

src/openai.ts
import OpenAI from 'openai';
import { FileSink, Tracer } from '@accordkit/tracer';
import { withOpenAI } from '@accordkit/provider-openai';

const tracer = new Tracer({ sink: new FileSink() });

const client = withOpenAI(
new OpenAI({ apiKey: process.env.OPENAI_API_KEY }),
tracer,
);

withOpenAI returns a proxy that mirrors the SDK. Re-wrapping the same client is idempotent—the adapter remembers the proxy and returns it.

Emitted events​

EventWhen it firesKey fields
messagePrompts (before the request) and assistant completionsrole, content, model, requestId
tool_callAssistant requests a function/tooltool, parsed input, $ext.id
usageOpenAI reports token accountinginputTokens, outputTokens, $ext.totalTokens
tool_resultRequest completes (success or error)ok, latencyMs, output summary
spanSurrounds each API invocationoperation, durationMs, status, attrs.model

All events share the same trace context so downstream tooling can correlate them easily.

Options​

Adapter options
withOpenAI(client, tracer, {
enableResponsesApi: true,
enableImagesApi: true,
enableAudioApi: false,
provider: 'openai',
operationName: 'my-app.chat',
emitPrompts: true,
emitResponses: true,
emitToolCalls: true,
emitUsage: true,
emitToolResults: true,
emitSpan: true,
});
OptionDefaultEffect
enableResponsesApifalseWrap the beta responses namespace so responses.create emits AccordKit events.
enableImagesApifalseInstrument images.generate to emit tool_result and span events (no binary payloads).
enableAudioApifalseInstrument audio.speech/transcriptions/translations.
provider'openai'Provider label attached to every emitted event.
operationName'openai.chat.completions.create'Name recorded on tool_result and span events.
emitPromptstrueEmit message events for system/user prompts.
emitResponsestrueEmit message events for assistant replies.
emitToolCallstrueEmit tool_call events for tool/function requests.
emitUsagetrueEmit usage events when the SDK returns usage.
emitToolResultstrueEmit tool_result events summarising success/error and latency.
emitSpantrueEmit a span around every request.

Streaming behaviour​

Streaming responses are detected automatically. The adapter waits for finalChatCompletion() (or an equivalent helper) and then emits the same completion, usage, tool result, and span events you get for non-streaming calls. Intermediate deltas are not emitted individually yet, so the stream API remains unchanged for your application.

Redacting sensitive fields​

Use tracer middleware to scrub content before it leaves your process.

src/redaction.ts
import { HttpSink, Tracer, type TraceMiddleware } from '@accordkit/tracer';

const redactEmails: TraceMiddleware = (event) => {
if (event.type === 'message' && typeof event.content === 'string') {
event.content = event.content.replace(/\S+@\S+/g, '[redacted]');
}
return event;
};

const tracer = new Tracer({
sink: new HttpSink({ endpoint: 'https://example.com/ingest' }),
middlewares: [redactEmails],
});

Middleware runs on every emitted event, regardless of whether it originated from your code or the adapter.

Next steps​