@pipedog/openai 0.0.0 → 0.4.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/LICENSE ADDED
@@ -0,0 +1,25 @@
1
+ BSD 2-Clause License
2
+
3
+ Copyright (c) 2024–2026, Daily
4
+ Copyright (c) 2026, pipedog contributors
5
+
6
+ Redistribution and use in source and binary forms, with or without
7
+ modification, are permitted provided that the following conditions are met:
8
+
9
+ 1. Redistributions of source code must retain the above copyright notice, this
10
+ list of conditions and the following disclaimer.
11
+
12
+ 2. Redistributions in binary form must reproduce the above copyright notice,
13
+ this list of conditions and the following disclaimer in the documentation
14
+ and/or other materials provided with the distribution.
15
+
16
+ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
17
+ AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
18
+ IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
19
+ DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
20
+ FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
21
+ DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
22
+ SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
23
+ CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
24
+ OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
25
+ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
package/NOTICE ADDED
@@ -0,0 +1,9 @@
1
+ pipedog is an unofficial TypeScript port of Pipecat (https://github.com/pipecat-ai/pipecat),
2
+ a framework for voice and multimodal conversational AI created by Daily.
3
+
4
+ It is not affiliated with or endorsed by Daily. Pipecat is distributed under
5
+ the BSD 2-Clause License, Copyright (c) 2024–2026, Daily; that copyright notice
6
+ and license are retained in LICENSE, and every ported source file carries a
7
+ header naming the upstream file it was derived from.
8
+
9
+ The upstream commit each file was ported from is recorded in porting/manifest.json.
@@ -0,0 +1,4 @@
1
+ /** Internal constants for OpenAI service integrations. */
2
+ export declare const OPENAI_SAMPLE_RATE = 24000;
3
+ export declare const OPENAI_REALTIME_WHISPER_MODEL = "gpt-realtime-whisper";
4
+ //# sourceMappingURL=_constants.d.ts.map
@@ -0,0 +1,9 @@
1
+ // Copyright (c) 2024-2026, Daily
2
+ // Copyright (c) 2026, pipedog contributors
3
+ // SPDX-License-Identifier: BSD-2-Clause
4
+ //
5
+ // Ported from pipecat: src/pipecat/services/openai/_constants.py
6
+ /** Internal constants for OpenAI service integrations. */
7
+ export const OPENAI_SAMPLE_RATE = 24000;
8
+ export const OPENAI_REALTIME_WHISPER_MODEL = "gpt-realtime-whisper";
9
+ //# sourceMappingURL=_constants.js.map
@@ -0,0 +1,272 @@
1
+ import { type BaseLLMAdapter } from "@pipedog/core/adapters/base_llm_adapter";
2
+ import { type OpenAILLMAdapter, type OpenAILLMInvocationParams, type OpenAINotGiven } from "@pipedog/core/adapters/services/open_ai_adapter";
3
+ import { type Frame } from "@pipedog/core/frames/frames";
4
+ import { LLMTokenUsage } from "@pipedog/core/metrics/metrics";
5
+ import type { LLMContext } from "@pipedog/core/processors/aggregators/llm_context";
6
+ import type { FrameDirection } from "@pipedog/core/processors/frame_processor";
7
+ import { LLMService, type LLMServiceOptions } from "@pipedog/core/services/llm_service";
8
+ import { LLMSettings, type LLMSettingsOptions } from "@pipedog/core/services/settings";
9
+ import { type NotGiven } from "@pipedog/core/utils/types";
10
+ import OpenAI from "openai";
11
+ /** A streamed chat completion chunk (`openai.types.chat.ChatCompletionChunk`). */
12
+ export type ChatCompletionChunk = OpenAI.Chat.Completions.ChatCompletionChunk;
13
+ /** A chat completion's usage (`openai.types.CompletionUsage`). */
14
+ export type CompletionUsage = OpenAI.CompletionUsage;
15
+ /** The async stream of chunks returned by a streaming chat completion. */
16
+ export type ChatCompletionStream = AsyncIterable<ChatCompletionChunk> & {
17
+ controller?: AbortController;
18
+ };
19
+ export interface OpenAILLMSettingsOptions extends LLMSettingsOptions {
20
+ /** Maximum completion tokens to generate. */
21
+ maxCompletionTokens?: number | null | NotGiven | OpenAINotGiven;
22
+ }
23
+ /**
24
+ * Settings for BaseOpenAILLMService.
25
+ *
26
+ * - `maxCompletionTokens`: maximum completion tokens to generate.
27
+ *
28
+ * Upstream overrides the inherited sampling fields (`frequencyPenalty`,
29
+ * `presencePenalty`, `seed`, `temperature`, `topP`, `maxTokens`) to also
30
+ * accept the OpenAI SDK's sentinel, which the service stores there so those
31
+ * fields can be passed through unchanged to the client. The SDK's sentinel is
32
+ * `undefined` here, which TypeScript can't add to an inherited field's type;
33
+ * the service writes it with `setOpenAINotGiven()`.
34
+ */
35
+ export declare class OpenAILLMSettings extends LLMSettings {
36
+ maxCompletionTokens: number | null | NotGiven | OpenAINotGiven;
37
+ constructor(options?: OpenAILLMSettingsOptions);
38
+ }
39
+ /** The settings fields that hold the OpenAI SDK's sentinel when unset. */
40
+ declare const OPENAI_SENTINEL_FIELDS: readonly ["frequencyPenalty", "presencePenalty", "seed", "temperature", "topP", "maxTokens", "maxCompletionTokens"];
41
+ /**
42
+ * Store the OpenAI SDK's "not given" sentinel (`OPENAI_NOT_GIVEN`) in the
43
+ * given settings fields, so they are left out of requests.
44
+ *
45
+ * Options objects can't carry it (an `undefined` option means "not given" to
46
+ * Pipecat), so services set it after building their default settings.
47
+ *
48
+ * @param settings Store-mode settings to update in place.
49
+ * @param fields The fields to set. Defaults to every OpenAI sampling field.
50
+ */
51
+ export declare function setOpenAINotGiven(settings: OpenAILLMSettings, fields?: readonly (typeof OPENAI_SENTINEL_FIELDS)[number][]): void;
52
+ /**
53
+ * OpenAI models that predate strict JSON schema replies: gpt-3.5, gpt-4 and
54
+ * gpt-4-turbo, the first gpt-4o snapshot, chatgpt-4o and the o1 previews.
55
+ */
56
+ export declare const OPENAI_MODEL_WITHOUT_RESPONSE_SCHEMA: RegExp;
57
+ /** Options for `BaseOpenAILLMService.createClient()`. */
58
+ export interface OpenAIClientOptions {
59
+ /** OpenAI API key. If null, the SDK reads `OPENAI_API_KEY`. */
60
+ apiKey?: string | null;
61
+ /** Custom base URL for the API. */
62
+ baseUrl?: string | null;
63
+ /** OpenAI organization ID. */
64
+ organization?: string | null;
65
+ /** OpenAI project ID. */
66
+ project?: string | null;
67
+ /** Additional HTTP headers. */
68
+ defaultHeaders?: Record<string, string> | null;
69
+ }
70
+ export interface BaseOpenAILLMServiceOptions extends LLMServiceOptions, OpenAIClientOptions {
71
+ /** Service tier to use (e.g., "auto", "flex", "priority"). */
72
+ serviceTier?: string | null;
73
+ /**
74
+ * Runtime-updatable settings. When provided, its given fields override the
75
+ * service's defaults.
76
+ */
77
+ settings?: OpenAILLMSettings | null;
78
+ /**
79
+ * How long an inference may go without producing output before it is
80
+ * abandoned and re-issued, when `retryOnTimeout` is set. Defaults to 5.0
81
+ * seconds.
82
+ */
83
+ retryTimeoutSecs?: number | null;
84
+ /**
85
+ * Whether to re-issue the request once if the first attempt produces no
86
+ * output within `retryTimeoutSecs`. The retry is unbounded.
87
+ */
88
+ retryOnTimeout?: boolean | null;
89
+ }
90
+ /**
91
+ * Base class for all services that use the AsyncOpenAI client.
92
+ *
93
+ * This service consumes LLMContextFrame frames, which contain a reference to
94
+ * an LLMContext object. The context defines what is sent to the LLM for
95
+ * completion, including user, assistant, and system messages, as well as tool
96
+ * choices and function call configurations.
97
+ */
98
+ type OpenAIAdapter = OpenAILLMAdapter & BaseLLMAdapter;
99
+ export declare class BaseOpenAILLMService extends LLMService<OpenAIAdapter> {
100
+ static Settings: typeof OpenAILLMSettings;
101
+ protected _settings: OpenAILLMSettings;
102
+ /**
103
+ * Set by services for providers other than OpenAI. Without a key the OpenAI
104
+ * client falls back to OPENAI_API_KEY and would send it to that provider.
105
+ */
106
+ static _requiresApiKey: boolean;
107
+ /**
108
+ * Whether this service's API supports the "developer" message role.
109
+ *
110
+ * OpenAI's native API supports it, but some OpenAI-compatible services
111
+ * (e.g. Cerebras) do not. Subclasses that don't support it should set this
112
+ * to `false`, which causes the adapter to convert "developer" messages to
113
+ * "user" messages before sending them to the API.
114
+ */
115
+ static supportsDeveloperRole: boolean;
116
+ /**
117
+ * Whether the API can enforce a response schema. OpenAI-compatible services
118
+ * whose API cannot should set this to `false`.
119
+ */
120
+ static supportsResponseSchema: boolean;
121
+ protected _serviceTier: string | null;
122
+ protected _retryTimeoutSecs: number | null;
123
+ protected _retryOnTimeout: boolean | null;
124
+ protected _fullModelName: string;
125
+ protected _client: OpenAI;
126
+ /**
127
+ * Initialize the BaseOpenAILLMService.
128
+ *
129
+ * @param options.apiKey OpenAI API key. If null, uses environment variable.
130
+ * @param options.baseUrl Custom base URL for OpenAI API. If null, uses default.
131
+ * @param options.organization OpenAI organization ID.
132
+ * @param options.project OpenAI project ID.
133
+ * @param options.defaultHeaders Additional HTTP headers to include in requests.
134
+ * @param options.serviceTier Service tier to use (e.g., "auto", "flex", "priority").
135
+ * @param options.settings Runtime-updatable settings.
136
+ * @param options.retryTimeoutSecs How long an inference may go without
137
+ * producing output before it is abandoned and re-issued, when
138
+ * `retryOnTimeout` is set. Defaults to 5.0 seconds.
139
+ * @param options.retryOnTimeout Whether to re-issue the request once if the
140
+ * first attempt produces no output within `retryTimeoutSecs`. The retry
141
+ * is unbounded.
142
+ * Other options are passed to the parent LLMService.
143
+ * @throws Error If the service is for a provider other than OpenAI and
144
+ * `apiKey` is empty (upstream: ValueError).
145
+ */
146
+ constructor(options?: BaseOpenAILLMServiceOptions);
147
+ /**
148
+ * Create an AsyncOpenAI client instance.
149
+ *
150
+ * @param options.apiKey OpenAI API key.
151
+ * @param options.baseUrl Custom base URL for the API.
152
+ * @param options.organization OpenAI organization ID.
153
+ * @param options.project OpenAI project ID.
154
+ * @param options.defaultHeaders Additional HTTP headers.
155
+ * Other options are the service's constructor options, which subclasses
156
+ * may read.
157
+ * @returns Configured AsyncOpenAI client instance.
158
+ */
159
+ createClient(options?: OpenAIClientOptions): OpenAI;
160
+ /**
161
+ * Check if this service can generate processing metrics.
162
+ *
163
+ * @returns True, as OpenAI service supports metrics generation.
164
+ */
165
+ canGenerateMetrics(): boolean;
166
+ /**
167
+ * Set the full AI model name.
168
+ *
169
+ * @param fullModelName The full name of the AI model to use.
170
+ */
171
+ setFullModelName(fullModelName: string): void;
172
+ /**
173
+ * Get the current full model name.
174
+ *
175
+ * @returns The full name of the AI model being used.
176
+ */
177
+ getFullModelName(): string;
178
+ /** Whether this service's API supports the "developer" message role. */
179
+ get supportsDeveloperRole(): boolean;
180
+ /**
181
+ * Turn request parameters into the JSON body to send: `extra_body` is
182
+ * merged in over the other fields, as the Python client does.
183
+ */
184
+ protected _requestBody(params: Record<string, any>): Record<string, any>;
185
+ /**
186
+ * Get streaming chat completions from OpenAI API with optional timeout and retry.
187
+ *
188
+ * @param context Context to use for the chat completion. Contains messages,
189
+ * tools, and tool choice.
190
+ * @returns Async stream of chat completion chunks.
191
+ */
192
+ getChatCompletions(context: LLMContext): Promise<ChatCompletionStream>;
193
+ /**
194
+ * Build parameters for chat completion request.
195
+ *
196
+ * Subclasses can override this to customize parameters for different
197
+ * providers.
198
+ *
199
+ * @param paramsFromContext Parameters, derived from the LLM context, to use
200
+ * for the chat completion. Contains messages, tools, and tool choice.
201
+ * @returns Dictionary of parameters for the chat completion request.
202
+ */
203
+ buildChatCompletionParams(paramsFromContext: OpenAILLMInvocationParams): Record<string, any>;
204
+ /**
205
+ * Add provider-specific fields to a request's `extra_body`.
206
+ *
207
+ * The OpenAI client rejects keyword arguments it doesn't know, so fields
208
+ * specific to an OpenAI-compatible provider travel in `extra_body`, which
209
+ * the client merges into the request JSON as-is.
210
+ *
211
+ * @param params Request parameters, updated in place. An `extra_body`
212
+ * already there, supplied through `Settings.extra`, wins key by key,
213
+ * matching how `extra` overrides every other request parameter. It is
214
+ * copied rather than modified.
215
+ * @param fields Fields to add. Unset and null values are omitted.
216
+ */
217
+ static _mergeExtraBody(params: Record<string, any>, fields: Record<string, unknown>): void;
218
+ /**
219
+ * Whether a model can enforce a response schema.
220
+ *
221
+ * OpenAI models before gpt-4o-mini and gpt-4o-2024-08-06 cannot.
222
+ *
223
+ * @param model The model name.
224
+ */
225
+ static modelSupportsResponseSchema(model: string): boolean;
226
+ /**
227
+ * Run a one-shot, out-of-band (i.e. out-of-pipeline) inference with the
228
+ * given LLM context.
229
+ *
230
+ * @param context The LLM context containing conversation history.
231
+ * @param options.maxTokens Optional maximum number of tokens to generate. If
232
+ * provided, overrides the service's default max_tokens /
233
+ * max_completion_tokens setting.
234
+ * @param options.systemInstruction Optional system instruction to use for
235
+ * this inference. If provided, overrides any system instruction in the
236
+ * context.
237
+ * @param options.responseSchema Optional JSON schema the reply must follow.
238
+ * The service asks the provider to enforce it, so the reply is JSON text
239
+ * matching the schema.
240
+ * @returns The LLM's response as a string, or null if no response is
241
+ * generated.
242
+ */
243
+ runInference(context: LLMContext, options?: {
244
+ maxTokens?: number | null;
245
+ systemInstruction?: string | null;
246
+ responseSchema?: Record<string, unknown> | null;
247
+ }): Promise<string | null>;
248
+ /**
249
+ * Convert a chat completion's usage into Pipecat's token usage.
250
+ *
251
+ * Follows OpenAI's convention, where `completion_tokens` includes the
252
+ * reasoning tokens reported in `completion_tokens_details`. Providers that
253
+ * report reasoning elsewhere, or apart from `completion_tokens`, override
254
+ * this.
255
+ *
256
+ * @param usage The usage reported with the completion.
257
+ * @returns The token usage to report.
258
+ */
259
+ protected _tokenUsage(usage: CompletionUsage): LLMTokenUsage;
260
+ protected _processContext(context: LLMContext): Promise<void>;
261
+ /**
262
+ * Process frames for LLM completion requests.
263
+ *
264
+ * Handles LLMContextFrame to trigger LLM completions.
265
+ *
266
+ * @param frame The frame to process.
267
+ * @param direction The direction of frame processing.
268
+ */
269
+ processFrame(frame: Frame, direction: FrameDirection): Promise<void>;
270
+ }
271
+ export {};
272
+ //# sourceMappingURL=base_llm.d.ts.map