OpenAI Responses
OpenAI's Responses API with OpenAIResponsesLLMService (WebSocket) and OpenAIResponsesHttpLLMService (HTTP), including reasoning models.
Overview
The Responses API is OpenAI's newer interface for text generation, tools and reasoning models. pipedog ports both of Pipecat's Responses services:
OpenAIResponsesLLMService: keeps a WebSocket open towss://api.openai.com/v1/responses. It sends only the new input items withprevious_response_idwhen it can, which lowers latency in long, tool-heavy conversations. This is the recommended variant for voice.OpenAIResponsesHttpLLMService: the same service over HTTP streaming, through the OpenAI SDK. It sends the full context on every turn.
Both store nothing on OpenAI's side (store: false). For Chat Completions, see
OpenAI.
Upstream page
Pipecat's documentation for the same services.
Source
packages/openai/src/responses/llm.ts.
OpenAI docs
The Responses API reference.
Installation
bun add @pipedog/openaiimport {
OpenAIResponsesHttpLLMService,
OpenAIResponsesLLMService,
OpenAIResponsesReasoningConfig,
} from "@pipedog/openai/responses/llm";Prerequisites
- An OpenAI account and an API key from the OpenAI dashboard.
- Pass the key as
apiKey. If you leave it out, both services readOPENAI_API_KEY. The examples read it fromOPENAI_API_KEY.
OpenAIResponsesLLMService
Configuration
Prop
Type
Settings
Runtime-updatable settings, passed as settings: new OpenAIResponsesLLMService.Settings({...})
(OpenAIResponsesLLMSettings). Both services share them. Any setting you leave out keeps the
default below. Fields marked "not sent" are left out of the request, so OpenAI's own default
applies.
| Setting | Type | Default | Description |
|---|---|---|---|
model | string | "gpt-4.1" | Model. |
systemInstruction | string | null | null | Sent as instructions. |
temperature | number | not sent | Sampling temperature. |
topP | number | not sent | Nucleus sampling. |
maxCompletionTokens | number | not sent | Sent as max_output_tokens. |
reasoning | OpenAIResponsesReasoningConfig | null | null | Reasoning config, for reasoning models. See below. |
frequencyPenalty, presencePenalty, seed, topK, maxTokens | number | null | null | Not part of the Responses request. |
filterIncompleteUserTurns | boolean | false | Filter incomplete user turns. |
userTurnCompletionConfig | UserTurnCompletionConfig | null | null | Turn completion config used with filterIncompleteUserTurns. |
extra | Record<string, unknown> | {} | Extra request fields, merged in after the fields above. |
OpenAIResponsesReasoningConfig (also OpenAIResponsesLLMService.ReasoningConfig) takes:
| Field | Type | Default | Description |
|---|---|---|---|
effort | "none" | "minimal" | "low" | "medium" | "high" | "xhigh" | "max" | string | null | null | Reasoning effort. null leaves it to the model. |
summary | "auto" | "concise" | "detailed" | string | null | null | Reasoning summary to return. null asks for none. |
mode | "standard" | "pro" | string | null | null | Reasoning mode, for models that have one. |
Usage
import {
OpenAIResponsesHttpLLMService,
OpenAIResponsesLLMService,
OpenAIResponsesReasoningConfig,
} from "@pipedog/openai/responses/llm";
const llm = new OpenAIResponsesLLMService({
apiKey: process.env.OPENAI_API_KEY ?? "",
settings: new OpenAIResponsesLLMService.Settings({
model: "gpt-4.1",
systemInstruction: "You are a helpful assistant in a voice conversation.",
}),
});A reasoning model, with a reasoning summary:
const reasoning = new OpenAIResponsesLLMService({
apiKey: process.env.OPENAI_API_KEY ?? "",
settings: new OpenAIResponsesLLMService.Settings({
model: "gpt-5.4-mini",
reasoning: new OpenAIResponsesReasoningConfig({ effort: "low", summary: "auto" }),
}),
});Event handlers
| Event | Description |
|---|---|
on_completion_timeout | A completion timed out. |
on_function_calls_started | The model asked for one or more function calls. |
on_function_calls_cancelled | Function calls were cancelled. |
on_connection_error | The WebSocket failed (WebSocket variant only). |
These come from the LLMService and WebsocketLLMService base classes.
Notes
- Runs a response for each
LLMContextFrame, between anLLMFullResponseStartFrameand anLLMFullResponseEndFrame, and streams the reply asLLMTextFrames. wsUrlsets the WebSocket endpoint.baseUrlonly affects the HTTP client the service uses forrunInference.- When the context still starts with what was sent last time, only the new items go out, with
previous_response_id. After a reconnect, or when the server no longer has the previous response, the service sends the full context again. It also reconnects and retries when it hits OpenAI's 60 minute connection limit. - With
reasoningleftnull, the service sends the lowest effort OpenAI documents for a known reasoning model (for example"none"forgpt-5.4andgpt-6.1-terra,"low"foro3), for the fastest replies, and logs what it sent. SetuseProviderThinkingDefaultto keep OpenAI's default.gpt-4.1, the default model, does not reason. - Reasoning summaries come out as
LLMThoughtStartFrame,LLMThoughtTextFrameandLLMThoughtEndFrame(the assistant aggregator'son_assistant_thoughtevent). The encrypted reasoning is kept in the context and sent back on later turns. serviceTieraccepts"auto","default","flex","scale","fast","priority"and"ultrafast".
OpenAIResponsesHttpLLMService
Configuration
Prop
Type
Settings
Same as OpenAIResponsesLLMService above.
Usage
const http = new OpenAIResponsesHttpLLMService({
apiKey: process.env.OPENAI_API_KEY ?? "",
settings: new OpenAIResponsesHttpLLMService.Settings({
model: "gpt-4.1",
systemInstruction: "You are a helpful assistant.",
}),
});Notes
- Each turn sends the whole context. Over HTTP,
previous_response_idneedsstore: true, which turns on OpenAI-side conversation storage, so this variant doesn't use it. retryOnTimeoutandretryTimeoutSecswork as in OpenAI: one re-issue when the first attempt produces nothing in time.
Runtime notes
| Runtime | Works | What it needs |
|---|---|---|
| Bun | ✅ yes | Nothing. |
| Node.js | ✅ yes | Nothing. |
| Deno | ✅ yes | Nothing. |
| Cloudflare Workers | ✅ yes | Nothing. |
Generated from pipecat.runtimes and pipecat.compat in packages/openai/package.json: ✅ means the compat smoke test passes on that runtime.
OpenAIResponsesHttpLLMServiceuses theopenaiJS SDK overfetch, which works on Bun, Node, Deno and Cloudflare Workers.OpenAIResponsesLLMServicesends the key as anAuthorizationheader on the WebSocket handshake. Bun, Node and Deno send it from the globalWebSocket; on Cloudflare Workers core opens the socket throughfetch.- Upstream's mixin base
_BaseOpenAIResponsesLLMServiceis a class-factory mixin here (BaseOpenAIResponsesLLMServiceMixin).instanceof _BaseOpenAIResponsesLLMServiceholds for both services.
pipedog is an unofficial community TypeScript port of Pipecat. It is not affiliated with or endorsed by Daily or the Pipecat project.
Portions adapted from the Pipecat documentation, Copyright (c) 2024–2025 Daily, BSD-2-Clause (see apps/docs/LICENSE-pipecat-docs).