@livekit/agents-plugin-openai 1.2.3 → 1.2.5
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/dist/index.cjs +1 -1
- package/dist/index.js +1 -1
- package/dist/realtime/realtime_model.cjs +73 -9
- package/dist/realtime/realtime_model.cjs.map +1 -1
- package/dist/realtime/realtime_model.d.ts.map +1 -1
- package/dist/realtime/realtime_model.js +73 -9
- package/dist/realtime/realtime_model.js.map +1 -1
- package/dist/realtime/realtime_model_beta.cjs +5 -1
- package/dist/realtime/realtime_model_beta.cjs.map +1 -1
- package/dist/realtime/realtime_model_beta.d.ts.map +1 -1
- package/dist/realtime/realtime_model_beta.js +5 -1
- package/dist/realtime/realtime_model_beta.js.map +1 -1
- package/dist/responses/llm.cjs +5 -1
- package/dist/responses/llm.cjs.map +1 -1
- package/dist/responses/llm.d.cts +2 -0
- package/dist/responses/llm.d.ts +2 -0
- package/dist/responses/llm.d.ts.map +1 -1
- package/dist/responses/llm.js +5 -1
- package/dist/responses/llm.js.map +1 -1
- package/dist/ws/llm.cjs +5 -1
- package/dist/ws/llm.cjs.map +1 -1
- package/dist/ws/llm.d.cts +2 -0
- package/dist/ws/llm.d.ts +2 -0
- package/dist/ws/llm.d.ts.map +1 -1
- package/dist/ws/llm.js +5 -1
- package/dist/ws/llm.js.map +1 -1
- package/dist/ws/types.cjs +1 -0
- package/dist/ws/types.cjs.map +1 -1
- package/dist/ws/types.d.cts +2 -0
- package/dist/ws/types.d.ts +2 -0
- package/dist/ws/types.d.ts.map +1 -1
- package/dist/ws/types.js +1 -0
- package/dist/ws/types.js.map +1 -1
- package/package.json +7 -7
- package/src/realtime/realtime_model.ts +80 -10
- package/src/realtime/realtime_model_beta.ts +4 -0
- package/src/responses/llm.ts +7 -0
- package/src/ws/llm.ts +7 -0
- package/src/ws/types.ts +1 -0
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../src/responses/llm.ts"],"sourcesContent":["// SPDX-FileCopyrightText: 2025 LiveKit, Inc.\n//\n// SPDX-License-Identifier: Apache-2.0\nimport type { APIConnectOptions } from '@livekit/agents';\nimport {\n APIConnectionError,\n APIStatusError,\n APITimeoutError,\n DEFAULT_API_CONNECT_OPTIONS,\n llm,\n log,\n toError,\n} from '@livekit/agents';\nimport OpenAI from 'openai';\nimport type { ChatModels } from '../models.js';\nimport { WSLLM } from '../ws/llm.js';\n\nexport interface LLMOptions {\n model: string | ChatModels;\n apiKey?: string;\n baseURL?: string;\n client?: OpenAI;\n temperature?: number;\n parallelToolCalls?: boolean;\n toolChoice?: llm.ToolChoice;\n store?: boolean;\n metadata?: Record<string, string>;\n strictToolSchema?: boolean;\n\n /**\n * Whether to use the WebSocket API.\n * @default true\n */\n useWebSocket?: boolean;\n}\n\ntype HttpLLMOptions = Omit<LLMOptions, 'useWebSocket'>;\n\nconst defaultLLMOptions: LLMOptions = {\n model: 'gpt-4.1',\n apiKey: process.env.OPENAI_API_KEY,\n strictToolSchema: true,\n useWebSocket: true,\n};\n\nclass ResponsesHttpLLM extends llm.LLM {\n #client: OpenAI;\n #opts: HttpLLMOptions;\n\n constructor(opts: Partial<HttpLLMOptions> = defaultLLMOptions) {\n super();\n\n this.#opts = { ...defaultLLMOptions, ...opts };\n if (this.#opts.apiKey === undefined && this.#opts.client === undefined) {\n throw new Error('OpenAI API key is required, whether as an argument or as $OPENAI_API_KEY');\n }\n\n this.#client =\n this.#opts.client ||\n new OpenAI({\n baseURL: this.#opts.baseURL,\n apiKey: this.#opts.apiKey,\n });\n }\n\n override label(): string {\n return 'openai.responses.LLM';\n }\n\n override get model(): string {\n return this.#opts.model;\n }\n\n override chat({\n chatCtx,\n toolCtx,\n connOptions = DEFAULT_API_CONNECT_OPTIONS,\n parallelToolCalls,\n toolChoice,\n extraKwargs,\n }: {\n chatCtx: llm.ChatContext;\n toolCtx?: llm.ToolContext;\n connOptions?: APIConnectOptions;\n parallelToolCalls?: boolean;\n toolChoice?: llm.ToolChoice;\n extraKwargs?: Record<string, unknown>;\n }): ResponsesHttpLLMStream {\n const modelOptions: Record<string, unknown> = { ...(extraKwargs || {}) };\n\n parallelToolCalls =\n parallelToolCalls !== undefined ? parallelToolCalls : this.#opts.parallelToolCalls;\n\n if (toolCtx && Object.keys(toolCtx).length > 0 && parallelToolCalls !== undefined) {\n modelOptions.parallel_tool_calls = parallelToolCalls;\n }\n\n toolChoice =\n toolChoice !== undefined ? toolChoice : (this.#opts.toolChoice as llm.ToolChoice | undefined);\n\n if (toolChoice) {\n modelOptions.tool_choice = toolChoice;\n }\n\n if (this.#opts.temperature !== undefined) {\n modelOptions.temperature = this.#opts.temperature;\n }\n\n if (this.#opts.store !== undefined) {\n modelOptions.store = this.#opts.store;\n }\n\n if (this.#opts.metadata) {\n modelOptions.metadata = this.#opts.metadata;\n }\n\n return new ResponsesHttpLLMStream(this, {\n model: this.#opts.model,\n client: this.#client,\n chatCtx,\n toolCtx,\n connOptions,\n modelOptions,\n strictToolSchema: this.#opts.strictToolSchema ?? true,\n });\n }\n}\n\nclass ResponsesHttpLLMStream extends llm.LLMStream {\n private model: string | ChatModels;\n private client: OpenAI;\n private modelOptions: Record<string, unknown>;\n private strictToolSchema: boolean;\n private responseId: string;\n\n constructor(\n llm: ResponsesHttpLLM,\n {\n model,\n client,\n chatCtx,\n toolCtx,\n connOptions,\n modelOptions,\n strictToolSchema,\n }: {\n model: string | ChatModels;\n client: OpenAI;\n chatCtx: llm.ChatContext;\n toolCtx?: llm.ToolContext;\n connOptions: APIConnectOptions;\n modelOptions: Record<string, unknown>;\n strictToolSchema: boolean;\n },\n ) {\n super(llm, { chatCtx, toolCtx, connOptions });\n this.model = model;\n this.client = client;\n this.modelOptions = modelOptions;\n this.strictToolSchema = strictToolSchema;\n this.responseId = '';\n }\n\n protected async run(): Promise<void> {\n let retryable = true;\n\n try {\n const messages = (await this.chatCtx.toProviderFormat(\n 'openai.responses',\n )) as OpenAI.Responses.ResponseInputItem[];\n\n const tools = this.toolCtx\n ? Object.entries(this.toolCtx).map(([name, func]) => {\n const oaiParams = {\n type: 'function' as const,\n name: name,\n description: func.description,\n parameters: llm.toJsonSchema(\n func.parameters,\n true,\n this.strictToolSchema,\n ) as unknown as OpenAI.Responses.FunctionTool['parameters'],\n } as OpenAI.Responses.FunctionTool;\n\n if (this.strictToolSchema) {\n oaiParams.strict = true;\n }\n\n return oaiParams;\n })\n : undefined;\n\n const requestOptions: Record<string, unknown> = { ...this.modelOptions };\n if (!tools) {\n delete requestOptions.tool_choice;\n }\n\n const stream = await this.client.responses.create(\n {\n model: this.model,\n input: messages,\n tools: tools,\n stream: true,\n ...requestOptions,\n },\n {\n timeout: this.connOptions.timeoutMs,\n },\n );\n\n for await (const event of stream) {\n retryable = false;\n let chunk: llm.ChatChunk | undefined;\n\n switch (event.type) {\n case 'error':\n this.handleError(event);\n break;\n case 'response.created':\n this.handleResponseCreated(event);\n break;\n case 'response.output_item.done':\n chunk = this.handleResponseOutputItemDone(event);\n break;\n case 'response.output_text.delta':\n chunk = this.handleResponseOutputTextDelta(event);\n break;\n case 'response.completed':\n chunk = this.handleResponseCompleted(event);\n break;\n case 'response.failed':\n this.handleResponseFailed(event);\n break;\n }\n\n if (chunk) {\n this.queue.put(chunk);\n }\n }\n } catch (error) {\n if (\n error instanceof APIStatusError ||\n error instanceof APITimeoutError ||\n error instanceof APIConnectionError\n ) {\n throw error;\n } else if (error instanceof OpenAI.APIConnectionTimeoutError) {\n throw new APITimeoutError({ options: { retryable } });\n } else if (error instanceof OpenAI.APIError) {\n throw new APIStatusError({\n message: error.message,\n options: {\n statusCode: error.status,\n body: error.error,\n requestId: error.requestID,\n retryable,\n },\n });\n } else {\n throw new APIConnectionError({\n message: toError(error).message,\n options: { retryable },\n });\n }\n }\n }\n\n private handleError(event: OpenAI.Responses.ResponseErrorEvent): void {\n throw new APIStatusError({\n message: event.message,\n options: {\n statusCode: -1,\n retryable: false,\n },\n });\n }\n\n private handleResponseFailed(event: OpenAI.Responses.ResponseFailedEvent): void {\n throw new APIStatusError({\n message: event.response.error?.message ?? 'Response failed',\n options: { statusCode: -1, retryable: false },\n });\n }\n\n private handleResponseCreated(event: OpenAI.Responses.ResponseCreatedEvent): void {\n this.responseId = event.response.id;\n }\n\n private handleResponseOutputItemDone(\n event: OpenAI.Responses.ResponseOutputItemDoneEvent,\n ): llm.ChatChunk | undefined {\n let chunk: llm.ChatChunk | undefined;\n\n if (event.item.type === 'function_call') {\n chunk = {\n id: this.responseId,\n delta: {\n role: 'assistant',\n content: undefined,\n toolCalls: [\n llm.FunctionCall.create({\n callId: event.item.call_id || '',\n name: event.item.name,\n args: event.item.arguments,\n }),\n ],\n },\n };\n }\n return chunk;\n }\n\n private handleResponseOutputTextDelta(\n event: OpenAI.Responses.ResponseTextDeltaEvent,\n ): llm.ChatChunk {\n return {\n id: this.responseId,\n delta: {\n role: 'assistant',\n content: event.delta,\n },\n };\n }\n\n private handleResponseCompleted(\n event: OpenAI.Responses.ResponseCompletedEvent,\n ): llm.ChatChunk | undefined {\n if (event.response.usage) {\n return {\n id: this.responseId,\n usage: {\n completionTokens: event.response.usage.output_tokens,\n promptTokens: event.response.usage.input_tokens,\n promptCachedTokens: event.response.usage.input_tokens_details.cached_tokens,\n totalTokens: event.response.usage.total_tokens,\n },\n };\n }\n return undefined;\n }\n}\n\nexport class LLM extends llm.LLM {\n #opts: LLMOptions;\n #llm: llm.LLM;\n #logger = log();\n\n /**\n * Create a new instance of OpenAI Responses LLM.\n *\n * @remarks\n * `apiKey` must be set to your OpenAI API key, either using the argument or by setting the\n * `OPENAI_API_KEY` environment variable.\n */\n constructor(opts: Partial<LLMOptions> = defaultLLMOptions) {\n super();\n\n this.#opts = { ...defaultLLMOptions, ...opts };\n const { useWebSocket, client, ...baseOpts } = this.#opts;\n\n if (useWebSocket) {\n if (client !== undefined) {\n this.#logger.warn(\n 'WebSocket mode does not support custom client; provided client will be ignored',\n );\n }\n this.#llm = new WSLLM(baseOpts);\n } else {\n this.#llm = new ResponsesHttpLLM({ ...baseOpts, client });\n }\n\n // Forward events from the inner delegate so consumers listening on this\n // wrapper instance (e.g. AgentActivity) receive them.\n this.#llm.on('metrics_collected', (metrics) => this.emit('metrics_collected', metrics));\n this.#llm.on('error', (error) => this.emit('error', error));\n }\n\n override label(): string {\n return this.#llm.label();\n }\n\n override get model(): string {\n return this.#llm.model;\n }\n\n override prewarm(): void {\n this.#llm.prewarm();\n }\n\n // Ref: python livekit-plugins/livekit-plugins-openai/livekit/plugins/openai/responses/llm.py - 229-233 lines\n override async aclose(): Promise<void> {\n await this.#llm.aclose();\n }\n\n async close(): Promise<void> {\n await this.aclose();\n }\n\n override chat({\n chatCtx,\n toolCtx,\n connOptions = DEFAULT_API_CONNECT_OPTIONS,\n parallelToolCalls,\n toolChoice,\n extraKwargs,\n }: {\n chatCtx: llm.ChatContext;\n toolCtx?: llm.ToolContext;\n connOptions?: APIConnectOptions;\n parallelToolCalls?: boolean;\n toolChoice?: llm.ToolChoice;\n extraKwargs?: Record<string, unknown>;\n }): llm.LLMStream {\n return this.#llm.chat({\n chatCtx,\n toolCtx,\n connOptions,\n parallelToolCalls,\n toolChoice,\n extraKwargs,\n });\n }\n}\n"],"mappings":"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","names":["llm"]}
|
|
1
|
+
{"version":3,"sources":["../../src/responses/llm.ts"],"sourcesContent":["// SPDX-FileCopyrightText: 2025 LiveKit, Inc.\n//\n// SPDX-License-Identifier: Apache-2.0\nimport type { APIConnectOptions } from '@livekit/agents';\nimport {\n APIConnectionError,\n APIStatusError,\n APITimeoutError,\n DEFAULT_API_CONNECT_OPTIONS,\n llm,\n log,\n toError,\n} from '@livekit/agents';\nimport OpenAI from 'openai';\nimport type { ChatModels } from '../models.js';\nimport { WSLLM } from '../ws/llm.js';\n\nexport interface LLMOptions {\n model: string | ChatModels;\n apiKey?: string;\n baseURL?: string;\n client?: OpenAI;\n temperature?: number;\n parallelToolCalls?: boolean;\n toolChoice?: llm.ToolChoice;\n store?: boolean;\n metadata?: Record<string, string>;\n strictToolSchema?: boolean;\n /** Specifies the processing tier (e.g. 'auto', 'default', 'priority', 'flex'). */\n serviceTier?: string;\n\n /**\n * Whether to use the WebSocket API.\n * @default true\n */\n useWebSocket?: boolean;\n}\n\ntype HttpLLMOptions = Omit<LLMOptions, 'useWebSocket'>;\n\nconst defaultLLMOptions: LLMOptions = {\n model: 'gpt-4.1',\n apiKey: process.env.OPENAI_API_KEY,\n strictToolSchema: true,\n useWebSocket: true,\n};\n\nclass ResponsesHttpLLM extends llm.LLM {\n #client: OpenAI;\n #opts: HttpLLMOptions;\n\n constructor(opts: Partial<HttpLLMOptions> = defaultLLMOptions) {\n super();\n\n this.#opts = { ...defaultLLMOptions, ...opts };\n if (this.#opts.apiKey === undefined && this.#opts.client === undefined) {\n throw new Error('OpenAI API key is required, whether as an argument or as $OPENAI_API_KEY');\n }\n\n this.#client =\n this.#opts.client ||\n new OpenAI({\n baseURL: this.#opts.baseURL,\n apiKey: this.#opts.apiKey,\n });\n }\n\n override label(): string {\n return 'openai.responses.LLM';\n }\n\n override get model(): string {\n return this.#opts.model;\n }\n\n override chat({\n chatCtx,\n toolCtx,\n connOptions = DEFAULT_API_CONNECT_OPTIONS,\n parallelToolCalls,\n toolChoice,\n extraKwargs,\n }: {\n chatCtx: llm.ChatContext;\n toolCtx?: llm.ToolContext;\n connOptions?: APIConnectOptions;\n parallelToolCalls?: boolean;\n toolChoice?: llm.ToolChoice;\n extraKwargs?: Record<string, unknown>;\n }): ResponsesHttpLLMStream {\n const modelOptions: Record<string, unknown> = { ...(extraKwargs || {}) };\n\n parallelToolCalls =\n parallelToolCalls !== undefined ? parallelToolCalls : this.#opts.parallelToolCalls;\n\n if (toolCtx && Object.keys(toolCtx).length > 0 && parallelToolCalls !== undefined) {\n modelOptions.parallel_tool_calls = parallelToolCalls;\n }\n\n toolChoice =\n toolChoice !== undefined ? toolChoice : (this.#opts.toolChoice as llm.ToolChoice | undefined);\n\n if (toolChoice) {\n modelOptions.tool_choice = toolChoice;\n }\n\n if (this.#opts.temperature !== undefined) {\n modelOptions.temperature = this.#opts.temperature;\n }\n\n if (this.#opts.store !== undefined) {\n modelOptions.store = this.#opts.store;\n }\n\n if (this.#opts.metadata) {\n modelOptions.metadata = this.#opts.metadata;\n }\n\n if (this.#opts.serviceTier) {\n modelOptions.service_tier = this.#opts.serviceTier;\n }\n\n return new ResponsesHttpLLMStream(this, {\n model: this.#opts.model,\n client: this.#client,\n chatCtx,\n toolCtx,\n connOptions,\n modelOptions,\n strictToolSchema: this.#opts.strictToolSchema ?? true,\n });\n }\n}\n\nclass ResponsesHttpLLMStream extends llm.LLMStream {\n private model: string | ChatModels;\n private client: OpenAI;\n private modelOptions: Record<string, unknown>;\n private strictToolSchema: boolean;\n private responseId: string;\n\n constructor(\n llm: ResponsesHttpLLM,\n {\n model,\n client,\n chatCtx,\n toolCtx,\n connOptions,\n modelOptions,\n strictToolSchema,\n }: {\n model: string | ChatModels;\n client: OpenAI;\n chatCtx: llm.ChatContext;\n toolCtx?: llm.ToolContext;\n connOptions: APIConnectOptions;\n modelOptions: Record<string, unknown>;\n strictToolSchema: boolean;\n },\n ) {\n super(llm, { chatCtx, toolCtx, connOptions });\n this.model = model;\n this.client = client;\n this.modelOptions = modelOptions;\n this.strictToolSchema = strictToolSchema;\n this.responseId = '';\n }\n\n protected async run(): Promise<void> {\n let retryable = true;\n\n try {\n const messages = (await this.chatCtx.toProviderFormat(\n 'openai.responses',\n )) as OpenAI.Responses.ResponseInputItem[];\n\n const tools = this.toolCtx\n ? Object.entries(this.toolCtx).map(([name, func]) => {\n const oaiParams = {\n type: 'function' as const,\n name: name,\n description: func.description,\n parameters: llm.toJsonSchema(\n func.parameters,\n true,\n this.strictToolSchema,\n ) as unknown as OpenAI.Responses.FunctionTool['parameters'],\n } as OpenAI.Responses.FunctionTool;\n\n if (this.strictToolSchema) {\n oaiParams.strict = true;\n }\n\n return oaiParams;\n })\n : undefined;\n\n const requestOptions: Record<string, unknown> = { ...this.modelOptions };\n if (!tools) {\n delete requestOptions.tool_choice;\n }\n\n const stream = await this.client.responses.create(\n {\n model: this.model,\n input: messages,\n tools: tools,\n stream: true,\n ...requestOptions,\n },\n {\n timeout: this.connOptions.timeoutMs,\n },\n );\n\n for await (const event of stream) {\n retryable = false;\n let chunk: llm.ChatChunk | undefined;\n\n switch (event.type) {\n case 'error':\n this.handleError(event);\n break;\n case 'response.created':\n this.handleResponseCreated(event);\n break;\n case 'response.output_item.done':\n chunk = this.handleResponseOutputItemDone(event);\n break;\n case 'response.output_text.delta':\n chunk = this.handleResponseOutputTextDelta(event);\n break;\n case 'response.completed':\n chunk = this.handleResponseCompleted(event);\n break;\n case 'response.failed':\n this.handleResponseFailed(event);\n break;\n }\n\n if (chunk) {\n this.queue.put(chunk);\n }\n }\n } catch (error) {\n if (\n error instanceof APIStatusError ||\n error instanceof APITimeoutError ||\n error instanceof APIConnectionError\n ) {\n throw error;\n } else if (error instanceof OpenAI.APIConnectionTimeoutError) {\n throw new APITimeoutError({ options: { retryable } });\n } else if (error instanceof OpenAI.APIError) {\n throw new APIStatusError({\n message: error.message,\n options: {\n statusCode: error.status,\n body: error.error,\n requestId: error.requestID,\n retryable,\n },\n });\n } else {\n throw new APIConnectionError({\n message: toError(error).message,\n options: { retryable },\n });\n }\n }\n }\n\n private handleError(event: OpenAI.Responses.ResponseErrorEvent): void {\n throw new APIStatusError({\n message: event.message,\n options: {\n statusCode: -1,\n retryable: false,\n },\n });\n }\n\n private handleResponseFailed(event: OpenAI.Responses.ResponseFailedEvent): void {\n throw new APIStatusError({\n message: event.response.error?.message ?? 'Response failed',\n options: { statusCode: -1, retryable: false },\n });\n }\n\n private handleResponseCreated(event: OpenAI.Responses.ResponseCreatedEvent): void {\n this.responseId = event.response.id;\n }\n\n private handleResponseOutputItemDone(\n event: OpenAI.Responses.ResponseOutputItemDoneEvent,\n ): llm.ChatChunk | undefined {\n let chunk: llm.ChatChunk | undefined;\n\n if (event.item.type === 'function_call') {\n chunk = {\n id: this.responseId,\n delta: {\n role: 'assistant',\n content: undefined,\n toolCalls: [\n llm.FunctionCall.create({\n callId: event.item.call_id || '',\n name: event.item.name,\n args: event.item.arguments,\n }),\n ],\n },\n };\n }\n return chunk;\n }\n\n private handleResponseOutputTextDelta(\n event: OpenAI.Responses.ResponseTextDeltaEvent,\n ): llm.ChatChunk {\n return {\n id: this.responseId,\n delta: {\n role: 'assistant',\n content: event.delta,\n },\n };\n }\n\n private handleResponseCompleted(\n event: OpenAI.Responses.ResponseCompletedEvent,\n ): llm.ChatChunk | undefined {\n if (event.response.usage) {\n return {\n id: this.responseId,\n usage: {\n completionTokens: event.response.usage.output_tokens,\n promptTokens: event.response.usage.input_tokens,\n promptCachedTokens: event.response.usage.input_tokens_details.cached_tokens,\n totalTokens: event.response.usage.total_tokens,\n serviceTier: event.response.service_tier ?? undefined,\n },\n };\n }\n return undefined;\n }\n}\n\nexport class LLM extends llm.LLM {\n #opts: LLMOptions;\n #llm: llm.LLM;\n #logger = log();\n\n /**\n * Create a new instance of OpenAI Responses LLM.\n *\n * @remarks\n * `apiKey` must be set to your OpenAI API key, either using the argument or by setting the\n * `OPENAI_API_KEY` environment variable.\n */\n constructor(opts: Partial<LLMOptions> = defaultLLMOptions) {\n super();\n\n this.#opts = { ...defaultLLMOptions, ...opts };\n const { useWebSocket, client, ...baseOpts } = this.#opts;\n\n if (useWebSocket) {\n if (client !== undefined) {\n this.#logger.warn(\n 'WebSocket mode does not support custom client; provided client will be ignored',\n );\n }\n this.#llm = new WSLLM(baseOpts);\n } else {\n this.#llm = new ResponsesHttpLLM({ ...baseOpts, client });\n }\n\n // Forward events from the inner delegate so consumers listening on this\n // wrapper instance (e.g. AgentActivity) receive them.\n this.#llm.on('metrics_collected', (metrics) => this.emit('metrics_collected', metrics));\n this.#llm.on('error', (error) => this.emit('error', error));\n }\n\n override label(): string {\n return this.#llm.label();\n }\n\n override get model(): string {\n return this.#llm.model;\n }\n\n override prewarm(): void {\n this.#llm.prewarm();\n }\n\n // Ref: python livekit-plugins/livekit-plugins-openai/livekit/plugins/openai/responses/llm.py - 229-233 lines\n override async aclose(): Promise<void> {\n await this.#llm.aclose();\n }\n\n async close(): Promise<void> {\n await this.aclose();\n }\n\n override chat({\n chatCtx,\n toolCtx,\n connOptions = DEFAULT_API_CONNECT_OPTIONS,\n parallelToolCalls,\n toolChoice,\n extraKwargs,\n }: {\n chatCtx: llm.ChatContext;\n toolCtx?: llm.ToolContext;\n connOptions?: APIConnectOptions;\n parallelToolCalls?: boolean;\n toolChoice?: llm.ToolChoice;\n extraKwargs?: Record<string, unknown>;\n }): llm.LLMStream {\n return this.#llm.chat({\n chatCtx,\n toolCtx,\n connOptions,\n parallelToolCalls,\n toolChoice,\n extraKwargs,\n });\n }\n}\n"],"mappings":"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","names":["llm"]}
|
package/dist/ws/llm.cjs
CHANGED
|
@@ -183,6 +183,9 @@ class WSLLM extends import_agents.llm.LLM {
|
|
|
183
183
|
if (this.#opts.metadata) {
|
|
184
184
|
modelOptions.metadata = this.#opts.metadata;
|
|
185
185
|
}
|
|
186
|
+
if (this.#opts.serviceTier) {
|
|
187
|
+
modelOptions.service_tier = this.#opts.serviceTier;
|
|
188
|
+
}
|
|
186
189
|
let inputChatCtx = chatCtx;
|
|
187
190
|
let prevResponseId;
|
|
188
191
|
const canUseStoredResponse = modelOptions.store !== false;
|
|
@@ -424,7 +427,8 @@ class WSLLMStream extends import_agents.llm.LLMStream {
|
|
|
424
427
|
completionTokens: event.response.usage.output_tokens,
|
|
425
428
|
promptTokens: event.response.usage.input_tokens,
|
|
426
429
|
promptCachedTokens: event.response.usage.input_tokens_details.cached_tokens,
|
|
427
|
-
totalTokens: event.response.usage.total_tokens
|
|
430
|
+
totalTokens: event.response.usage.total_tokens,
|
|
431
|
+
serviceTier: event.response.service_tier ?? void 0
|
|
428
432
|
}
|
|
429
433
|
};
|
|
430
434
|
}
|
package/dist/ws/llm.cjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../src/ws/llm.ts"],"sourcesContent":["// SPDX-FileCopyrightText: 2025 LiveKit, Inc.\n//\n// SPDX-License-Identifier: Apache-2.0\nimport type { APIConnectOptions } from '@livekit/agents';\nimport {\n APIConnectionError,\n APIStatusError,\n APITimeoutError,\n ConnectionPool,\n DEFAULT_API_CONNECT_OPTIONS,\n llm,\n stream,\n toError,\n} from '@livekit/agents';\nimport type OpenAI from 'openai';\nimport { WebSocket } from 'ws';\nimport type { ChatModels } from '../models.js';\nimport type {\n WsOutputItemDoneEvent,\n WsOutputTextDeltaEvent,\n WsResponseCompletedEvent,\n WsResponseCreateEvent,\n WsResponseCreatedEvent,\n WsResponseFailedEvent,\n WsServerEvent,\n} from './types.js';\nimport { wsServerEventSchema } from './types.js';\n\nconst OPENAI_RESPONSES_WS_URL = 'wss://api.openai.com/v1/responses';\n\n// OpenAI enforces a 60-minute maximum duration on Responses WebSocket connections.\nconst WS_MAX_SESSION_DURATION = 3_600_000;\n\n// ============================================================================\n// Internal: ResponsesWebSocket\n//\n// Wraps a single raw WebSocket connection. Maintains a FIFO queue of\n// StreamChannels — one per outstanding response.create request — and\n// dispatches every incoming server-event to the front of the queue.\n// A response is terminated (and its channel closed) when the service sends\n// response.completed, response.failed, or error.\n//\n// ============================================================================\n\nexport class ResponsesWebSocket {\n #ws: WebSocket;\n // FIFO queue: the front entry receives validated WsServerEvents for the in-flight response.\n #outputQueue: stream.StreamChannel<WsServerEvent>[] = [];\n\n constructor(ws: WebSocket) {\n this.#ws = ws;\n\n ws.on('message', (data: Buffer) => {\n const current = this.#outputQueue[0];\n if (!current) return;\n\n let raw: unknown;\n try {\n raw = JSON.parse(data.toString());\n } catch {\n return;\n }\n\n // Validate and type-narrow with Zod at write time so readers always\n // receive a fully-typed WsServerEvent.\n const parsed = wsServerEventSchema.safeParse(raw);\n if (!parsed.success) return;\n\n const event = parsed.data;\n void current.write(event);\n\n // Close and dequeue on any terminal event.\n if (\n event.type === 'response.completed' ||\n event.type === 'response.failed' ||\n event.type === 'error'\n ) {\n void current.close();\n this.#outputQueue.shift();\n }\n });\n\n ws.on('close', () => {\n // If the WebSocket closes while requests are still in flight, synthesise\n // a typed error event so all readers can handle it cleanly.\n for (const current of this.#outputQueue) {\n if (!current.closed) {\n const closeError: WsServerEvent = {\n type: 'error',\n error: {\n code: 'websocket_closed',\n message: 'OpenAI Responses WebSocket closed unexpectedly',\n },\n };\n void current.write(closeError).finally(() => current.close());\n }\n }\n this.#outputQueue = [];\n });\n }\n\n /**\n * Send a response.create event. Returns a typed `StreamChannel<WsServerEvent>`\n * that yields validated server events until the response terminates.\n */\n sendRequest(payload: WsResponseCreateEvent): stream.StreamChannel<WsServerEvent> {\n if (this.#ws.readyState !== WebSocket.OPEN) {\n throw new APIConnectionError({\n message: `OpenAI Responses WebSocket is not open (state ${getWebSocketStateLabel(this.#ws.readyState)})`,\n options: { retryable: true },\n });\n }\n\n const channel = stream.createStreamChannel<WsServerEvent>();\n this.#outputQueue.push(channel);\n this.#ws.send(JSON.stringify(payload));\n return channel;\n }\n\n close(): void {\n // Drain pending channels before closing the socket.\n for (const ch of this.#outputQueue) {\n void ch.close();\n }\n this.#outputQueue = [];\n this.#ws.close();\n }\n}\n\n// ============================================================================\n// LLMOptions\n// ============================================================================\n\nexport interface WSLLMOptions {\n model: string | ChatModels;\n apiKey?: string;\n baseURL?: string;\n temperature?: number;\n parallelToolCalls?: boolean;\n toolChoice?: llm.ToolChoice;\n store?: boolean;\n metadata?: Record<string, string>;\n strictToolSchema?: boolean;\n}\n\nconst defaultLLMOptions: WSLLMOptions = {\n model: 'gpt-4.1',\n apiKey: process.env.OPENAI_API_KEY,\n strictToolSchema: true,\n};\n\n// ============================================================================\n// LLM\n// ============================================================================\n\nexport class WSLLM extends llm.LLM {\n #opts: WSLLMOptions;\n #pool: ConnectionPool<ResponsesWebSocket>;\n #prevResponseId = '';\n #prevChatCtx: llm.ChatContext | null = null;\n #pendingToolCalls = new Set<string>();\n\n /**\n * Create a new instance of the OpenAI Responses API WebSocket LLM.\n *\n * @remarks\n * `apiKey` must be set to your OpenAI API key, either using the argument or\n * by setting the `OPENAI_API_KEY` environment variable.\n *\n * A persistent WebSocket connection to `/v1/responses` is maintained and\n * reused across turns, reducing per-turn continuation overhead for\n * tool-call-heavy workflows.\n */\n constructor(opts: Partial<WSLLMOptions> = defaultLLMOptions) {\n super();\n\n this.#opts = { ...defaultLLMOptions, ...opts };\n if (!this.#opts.apiKey) {\n throw new Error('OpenAI API key is required, whether as an argument or as $OPENAI_API_KEY');\n }\n\n this.#pool = new ConnectionPool<ResponsesWebSocket>({\n maxSessionDuration: WS_MAX_SESSION_DURATION,\n connectCb: async (timeoutMs: number) => {\n const wsUrl = this.#opts.baseURL\n ? `${this.#opts.baseURL.replace(/^https?/, 'wss').replace(/\\/+$/, '')}/responses`\n : OPENAI_RESPONSES_WS_URL;\n const ws = await connectWs(wsUrl, this.#opts.apiKey!, timeoutMs);\n return new ResponsesWebSocket(ws);\n },\n closeCb: async (conn: ResponsesWebSocket) => {\n conn.close();\n },\n });\n }\n\n label(): string {\n return 'openai.ws.LLM';\n }\n\n get model(): string {\n return this.#opts.model;\n }\n\n prewarm(): void {\n this.#pool.prewarm();\n }\n\n async close(): Promise<void> {\n await this.#pool.close();\n }\n\n override async aclose(): Promise<void> {\n await this.close();\n }\n\n /** Called by LLMStream once response.created fires to atomically persist both the\n * response ID and its corresponding chat context for the next turn's diff. */\n _onResponseCreated(responseId: string, chatCtx: llm.ChatContext): void {\n this.#prevResponseId = responseId;\n this.#prevChatCtx = chatCtx;\n }\n\n _setPendingToolCalls(callIds: Set<string>): void {\n this.#pendingToolCalls = callIds;\n }\n\n chat({\n chatCtx,\n toolCtx,\n connOptions = DEFAULT_API_CONNECT_OPTIONS,\n parallelToolCalls,\n toolChoice,\n extraKwargs,\n }: {\n chatCtx: llm.ChatContext;\n toolCtx?: llm.ToolContext;\n connOptions?: APIConnectOptions;\n parallelToolCalls?: boolean;\n toolChoice?: llm.ToolChoice;\n extraKwargs?: Record<string, unknown>;\n }): WSLLMStream {\n const modelOptions: Record<string, unknown> = { ...(extraKwargs ?? {}) };\n\n parallelToolCalls =\n parallelToolCalls !== undefined ? parallelToolCalls : this.#opts.parallelToolCalls;\n if (toolCtx && Object.keys(toolCtx).length > 0 && parallelToolCalls !== undefined) {\n modelOptions.parallel_tool_calls = parallelToolCalls;\n }\n\n toolChoice =\n toolChoice !== undefined ? toolChoice : (this.#opts.toolChoice as llm.ToolChoice | undefined);\n if (toolChoice) {\n modelOptions.tool_choice = toolChoice;\n }\n\n if (this.#opts.temperature !== undefined) {\n modelOptions.temperature = this.#opts.temperature;\n }\n\n if (this.#opts.store !== undefined) {\n modelOptions.store = this.#opts.store;\n }\n\n if (this.#opts.metadata) {\n modelOptions.metadata = this.#opts.metadata;\n }\n\n let inputChatCtx = chatCtx;\n let prevResponseId: string | undefined;\n const canUseStoredResponse = modelOptions.store !== false;\n\n if (canUseStoredResponse && this.#prevChatCtx && this.#prevResponseId) {\n const diff = llm.computeChatCtxDiff(this.#prevChatCtx, chatCtx);\n const lastPrevItemId = this.#prevChatCtx.items.at(-1)?.id ?? null;\n\n if (\n diff.toRemove.length === 0 &&\n diff.toCreate.length > 0 &&\n diff.toCreate[0]![0] === lastPrevItemId\n ) {\n // All new items are appended after the tail of the previous context —\n // safe to send only the incremental input with previous_response_id,\n // but only if all pending tool calls from the previous response have\n // their corresponding function_call_output in the new items.\n const newItemIds = new Set(diff.toCreate.map(([, id]) => id));\n const newItems = chatCtx.items.filter((item: llm.ChatItem) => newItemIds.has(item.id));\n const pendingToolCallsCompleted = this.#pendingToolCallsCompleted(newItems);\n if (pendingToolCallsCompleted) {\n inputChatCtx = new llm.ChatContext(newItems);\n prevResponseId = this.#prevResponseId;\n }\n }\n // Otherwise: items were removed or inserted mid-history — fall back to\n // sending the full context with no previous_response_id.\n }\n\n return new WSLLMStream(this, {\n pool: this.#pool,\n model: this.#opts.model,\n chatCtx: inputChatCtx,\n fullChatCtx: chatCtx,\n toolCtx,\n connOptions,\n modelOptions,\n prevResponseId,\n strictToolSchema: this.#opts.strictToolSchema ?? true,\n });\n }\n\n #pendingToolCallsCompleted(items: llm.ChatItem[]): boolean {\n if (this.#pendingToolCalls.size === 0) return true;\n const completedCallIds = new Set(\n items\n .filter((item): item is llm.FunctionCallOutput => item.type === 'function_call_output')\n .map((item) => item.callId),\n );\n return [...this.#pendingToolCalls].every((callId) => completedCallIds.has(callId));\n }\n}\n\n// ============================================================================\n// WsLLMStream\n// ============================================================================\n\nexport class WSLLMStream extends llm.LLMStream {\n #llm: WSLLM;\n #pool: ConnectionPool<ResponsesWebSocket>;\n #model: string | ChatModels;\n #modelOptions: Record<string, unknown>;\n #strictToolSchema: boolean;\n #prevResponseId?: string;\n /** Full chat context — used as fallback when previous_response_id is stale. */\n #fullChatCtx: llm.ChatContext;\n #responseId = '';\n #pendingToolCalls = new Set<string>();\n\n constructor(\n llm: WSLLM,\n {\n pool,\n model,\n chatCtx,\n fullChatCtx,\n toolCtx,\n connOptions,\n modelOptions,\n prevResponseId,\n strictToolSchema,\n }: {\n pool: ConnectionPool<ResponsesWebSocket>;\n model: string | ChatModels;\n chatCtx: llm.ChatContext;\n fullChatCtx: llm.ChatContext;\n toolCtx?: llm.ToolContext;\n connOptions: APIConnectOptions;\n modelOptions: Record<string, unknown>;\n prevResponseId?: string;\n strictToolSchema: boolean;\n },\n ) {\n super(llm, { chatCtx, toolCtx, connOptions });\n this.#llm = llm;\n this.#pool = pool;\n this.#model = model;\n this.#modelOptions = modelOptions;\n this.#strictToolSchema = strictToolSchema;\n this.#prevResponseId = prevResponseId;\n this.#fullChatCtx = fullChatCtx;\n }\n\n protected async run(): Promise<void> {\n let retryable = true;\n\n try {\n await this.#pool.withConnection(async (conn: ResponsesWebSocket) => {\n const needsRetry = await this.#runWithConn(conn, this.chatCtx, this.#prevResponseId);\n\n if (needsRetry) {\n // previous_response_id was evicted from the server-side cache.\n // Retry once on the same connection with the full context and no ID.\n retryable = true;\n await this.#runWithConn(conn, this.#fullChatCtx, undefined);\n }\n });\n } catch (error) {\n if (\n error instanceof APIStatusError ||\n error instanceof APITimeoutError ||\n error instanceof APIConnectionError\n ) {\n throw error;\n }\n throw new APIConnectionError({\n message: toError(error).message,\n options: { retryable },\n });\n }\n }\n\n /**\n * Execute a single response.create round-trip on the given connection.\n * Returns `true` when the caller should retry with the full chat context\n * (i.e. `previous_response_not_found`), `false` otherwise.\n */\n async #runWithConn(\n conn: ResponsesWebSocket,\n chatCtx: llm.ChatContext,\n prevResponseId: string | undefined,\n ): Promise<boolean> {\n const messages = (await chatCtx.toProviderFormat(\n 'openai.responses',\n )) as OpenAI.Responses.ResponseInputItem[];\n\n const tools = this.toolCtx\n ? Object.entries(this.toolCtx).map(([name, func]) => {\n const oaiParams = {\n type: 'function' as const,\n name,\n description: func.description,\n parameters: llm.toJsonSchema(\n func.parameters,\n true,\n this.#strictToolSchema,\n ) as unknown as OpenAI.Responses.FunctionTool['parameters'],\n } as OpenAI.Responses.FunctionTool;\n\n if (this.#strictToolSchema) {\n oaiParams.strict = true;\n }\n\n return oaiParams;\n })\n : undefined;\n\n const requestOptions: Record<string, unknown> = { ...this.#modelOptions };\n if (!tools) {\n delete requestOptions.tool_choice;\n }\n\n const payload: WsResponseCreateEvent = {\n type: 'response.create',\n model: this.#model as string,\n input: messages as unknown[],\n tools: (tools ?? []) as unknown[],\n ...(prevResponseId ? { previous_response_id: prevResponseId } : {}),\n ...requestOptions,\n };\n\n let channel: stream.StreamChannel<WsServerEvent>;\n try {\n channel = conn.sendRequest(payload);\n } catch (error) {\n if (error instanceof APIConnectionError) {\n conn.close();\n this.#pool.invalidate();\n }\n throw error;\n }\n const reader = channel.stream().getReader();\n\n // Events are already Zod-validated by ResponsesWebSocket before being\n // written to the channel, so no re-parsing is needed here.\n try {\n while (true) {\n const { done, value: event } = await reader.read();\n if (done) break;\n\n let chunk: llm.ChatChunk | undefined;\n\n switch (event.type) {\n case 'error': {\n const retry = this.#handleError(event, conn);\n if (retry) return true;\n break;\n }\n case 'response.created':\n this.#handleResponseCreated(event);\n break;\n case 'response.output_item.done':\n chunk = this.#handleOutputItemDone(event);\n break;\n case 'response.output_text.delta':\n chunk = this.#handleOutputTextDelta(event);\n break;\n case 'response.completed':\n chunk = this.#handleResponseCompleted(event);\n break;\n case 'response.failed':\n this.#handleResponseFailed(event);\n break;\n default:\n break;\n }\n\n if (chunk) {\n this.queue.put(chunk);\n }\n }\n } finally {\n reader.releaseLock();\n }\n\n return false;\n }\n\n /**\n * Returns `true` when the caller should retry with full context\n * (`previous_response_not_found`), throws for all other errors.\n */\n #handleError(event: WsServerEvent & { type: 'error' }, conn: ResponsesWebSocket): boolean {\n const code = event.error?.code;\n\n if (code === 'previous_response_not_found') {\n // The server-side in-memory cache was evicted (e.g. after a failed turn\n // or reconnect). Signal the caller to retry with the full context.\n return true;\n }\n\n if (code === 'websocket_connection_limit_reached' || code === 'websocket_closed') {\n // Transient connection issue (timeout, network drop, or 60-min limit).\n // Evict this connection so the pool opens a fresh one on retry.\n conn.close();\n this.#pool.invalidate();\n throw new APIConnectionError({\n message: event.error?.message ?? `WebSocket closed (${code})`,\n options: { retryable: true },\n });\n }\n\n throw new APIStatusError({\n message: event.error?.message ?? event.message ?? 'Unknown error from OpenAI Responses WS',\n options: {\n statusCode: event.status ?? -1,\n retryable: false,\n },\n });\n }\n\n #handleResponseCreated(event: WsResponseCreatedEvent): void {\n this.#responseId = event.response.id;\n this.#llm._onResponseCreated(event.response.id, this.#fullChatCtx);\n }\n\n #handleOutputItemDone(event: WsOutputItemDoneEvent): llm.ChatChunk | undefined {\n if (event.item.type === 'function_call') {\n this.#pendingToolCalls.add(event.item.call_id);\n return {\n id: this.#responseId,\n delta: {\n role: 'assistant',\n content: undefined,\n toolCalls: [\n llm.FunctionCall.create({\n callId: event.item.call_id,\n name: event.item.name,\n args: event.item.arguments,\n }),\n ],\n },\n };\n }\n return undefined;\n }\n\n #handleOutputTextDelta(event: WsOutputTextDeltaEvent): llm.ChatChunk {\n return {\n id: this.#responseId,\n delta: {\n role: 'assistant',\n content: event.delta,\n },\n };\n }\n\n #handleResponseCompleted(event: WsResponseCompletedEvent): llm.ChatChunk | undefined {\n this.#llm._setPendingToolCalls(this.#pendingToolCalls);\n\n if (event.response.usage) {\n return {\n id: this.#responseId,\n usage: {\n completionTokens: event.response.usage.output_tokens,\n promptTokens: event.response.usage.input_tokens,\n promptCachedTokens: event.response.usage.input_tokens_details.cached_tokens,\n totalTokens: event.response.usage.total_tokens,\n },\n };\n }\n return undefined;\n }\n\n #handleResponseFailed(event: WsResponseFailedEvent): void {\n throw new APIStatusError({\n message: event.response?.error?.message ?? 'Response failed',\n options: { statusCode: -1, retryable: false },\n });\n }\n}\n\n// ============================================================================\n// Internal helpers\n// ============================================================================\n\nasync function connectWs(url: string, apiKey: string, timeoutMs: number): Promise<WebSocket> {\n return new Promise<WebSocket>((resolve, reject) => {\n const ws = new WebSocket(url, {\n headers: { Authorization: `Bearer ${apiKey}` },\n });\n\n let settled = false;\n\n const timer = setTimeout(() => {\n settled = true;\n ws.close();\n reject(\n new APIConnectionError({ message: 'Timeout connecting to OpenAI Responses WebSocket' }),\n );\n }, timeoutMs);\n\n ws.once('open', () => {\n if (settled) return;\n settled = true;\n clearTimeout(timer);\n resolve(ws);\n });\n\n ws.once('error', (err) => {\n if (settled) return;\n settled = true;\n clearTimeout(timer);\n reject(\n new APIConnectionError({\n message: `Error connecting to OpenAI Responses WebSocket: ${err.message}`,\n }),\n );\n });\n\n ws.once('close', (code) => {\n if (settled) return;\n settled = true;\n clearTimeout(timer);\n reject(\n new APIConnectionError({\n message: `OpenAI Responses WebSocket closed unexpectedly during connect (code ${code})`,\n }),\n );\n });\n });\n}\n\nfunction getWebSocketStateLabel(readyState: number): string {\n switch (readyState) {\n case WebSocket.CONNECTING:\n return 'CONNECTING';\n case WebSocket.OPEN:\n return 'OPEN';\n case WebSocket.CLOSING:\n return 'CLOSING';\n case WebSocket.CLOSED:\n return 'CLOSED';\n default:\n return `UNKNOWN:${readyState}`;\n }\n}\n"],"mappings":"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","names":["llm"]}
|
|
1
|
+
{"version":3,"sources":["../../src/ws/llm.ts"],"sourcesContent":["// SPDX-FileCopyrightText: 2025 LiveKit, Inc.\n//\n// SPDX-License-Identifier: Apache-2.0\nimport type { APIConnectOptions } from '@livekit/agents';\nimport {\n APIConnectionError,\n APIStatusError,\n APITimeoutError,\n ConnectionPool,\n DEFAULT_API_CONNECT_OPTIONS,\n llm,\n stream,\n toError,\n} from '@livekit/agents';\nimport type OpenAI from 'openai';\nimport { WebSocket } from 'ws';\nimport type { ChatModels } from '../models.js';\nimport type {\n WsOutputItemDoneEvent,\n WsOutputTextDeltaEvent,\n WsResponseCompletedEvent,\n WsResponseCreateEvent,\n WsResponseCreatedEvent,\n WsResponseFailedEvent,\n WsServerEvent,\n} from './types.js';\nimport { wsServerEventSchema } from './types.js';\n\nconst OPENAI_RESPONSES_WS_URL = 'wss://api.openai.com/v1/responses';\n\n// OpenAI enforces a 60-minute maximum duration on Responses WebSocket connections.\nconst WS_MAX_SESSION_DURATION = 3_600_000;\n\n// ============================================================================\n// Internal: ResponsesWebSocket\n//\n// Wraps a single raw WebSocket connection. Maintains a FIFO queue of\n// StreamChannels — one per outstanding response.create request — and\n// dispatches every incoming server-event to the front of the queue.\n// A response is terminated (and its channel closed) when the service sends\n// response.completed, response.failed, or error.\n//\n// ============================================================================\n\nexport class ResponsesWebSocket {\n #ws: WebSocket;\n // FIFO queue: the front entry receives validated WsServerEvents for the in-flight response.\n #outputQueue: stream.StreamChannel<WsServerEvent>[] = [];\n\n constructor(ws: WebSocket) {\n this.#ws = ws;\n\n ws.on('message', (data: Buffer) => {\n const current = this.#outputQueue[0];\n if (!current) return;\n\n let raw: unknown;\n try {\n raw = JSON.parse(data.toString());\n } catch {\n return;\n }\n\n // Validate and type-narrow with Zod at write time so readers always\n // receive a fully-typed WsServerEvent.\n const parsed = wsServerEventSchema.safeParse(raw);\n if (!parsed.success) return;\n\n const event = parsed.data;\n void current.write(event);\n\n // Close and dequeue on any terminal event.\n if (\n event.type === 'response.completed' ||\n event.type === 'response.failed' ||\n event.type === 'error'\n ) {\n void current.close();\n this.#outputQueue.shift();\n }\n });\n\n ws.on('close', () => {\n // If the WebSocket closes while requests are still in flight, synthesise\n // a typed error event so all readers can handle it cleanly.\n for (const current of this.#outputQueue) {\n if (!current.closed) {\n const closeError: WsServerEvent = {\n type: 'error',\n error: {\n code: 'websocket_closed',\n message: 'OpenAI Responses WebSocket closed unexpectedly',\n },\n };\n void current.write(closeError).finally(() => current.close());\n }\n }\n this.#outputQueue = [];\n });\n }\n\n /**\n * Send a response.create event. Returns a typed `StreamChannel<WsServerEvent>`\n * that yields validated server events until the response terminates.\n */\n sendRequest(payload: WsResponseCreateEvent): stream.StreamChannel<WsServerEvent> {\n if (this.#ws.readyState !== WebSocket.OPEN) {\n throw new APIConnectionError({\n message: `OpenAI Responses WebSocket is not open (state ${getWebSocketStateLabel(this.#ws.readyState)})`,\n options: { retryable: true },\n });\n }\n\n const channel = stream.createStreamChannel<WsServerEvent>();\n this.#outputQueue.push(channel);\n this.#ws.send(JSON.stringify(payload));\n return channel;\n }\n\n close(): void {\n // Drain pending channels before closing the socket.\n for (const ch of this.#outputQueue) {\n void ch.close();\n }\n this.#outputQueue = [];\n this.#ws.close();\n }\n}\n\n// ============================================================================\n// LLMOptions\n// ============================================================================\n\nexport interface WSLLMOptions {\n model: string | ChatModels;\n apiKey?: string;\n baseURL?: string;\n temperature?: number;\n parallelToolCalls?: boolean;\n toolChoice?: llm.ToolChoice;\n store?: boolean;\n metadata?: Record<string, string>;\n strictToolSchema?: boolean;\n /** Specifies the processing tier (e.g. 'auto', 'default', 'priority', 'flex'). */\n serviceTier?: string;\n}\n\nconst defaultLLMOptions: WSLLMOptions = {\n model: 'gpt-4.1',\n apiKey: process.env.OPENAI_API_KEY,\n strictToolSchema: true,\n};\n\n// ============================================================================\n// LLM\n// ============================================================================\n\nexport class WSLLM extends llm.LLM {\n #opts: WSLLMOptions;\n #pool: ConnectionPool<ResponsesWebSocket>;\n #prevResponseId = '';\n #prevChatCtx: llm.ChatContext | null = null;\n #pendingToolCalls = new Set<string>();\n\n /**\n * Create a new instance of the OpenAI Responses API WebSocket LLM.\n *\n * @remarks\n * `apiKey` must be set to your OpenAI API key, either using the argument or\n * by setting the `OPENAI_API_KEY` environment variable.\n *\n * A persistent WebSocket connection to `/v1/responses` is maintained and\n * reused across turns, reducing per-turn continuation overhead for\n * tool-call-heavy workflows.\n */\n constructor(opts: Partial<WSLLMOptions> = defaultLLMOptions) {\n super();\n\n this.#opts = { ...defaultLLMOptions, ...opts };\n if (!this.#opts.apiKey) {\n throw new Error('OpenAI API key is required, whether as an argument or as $OPENAI_API_KEY');\n }\n\n this.#pool = new ConnectionPool<ResponsesWebSocket>({\n maxSessionDuration: WS_MAX_SESSION_DURATION,\n connectCb: async (timeoutMs: number) => {\n const wsUrl = this.#opts.baseURL\n ? `${this.#opts.baseURL.replace(/^https?/, 'wss').replace(/\\/+$/, '')}/responses`\n : OPENAI_RESPONSES_WS_URL;\n const ws = await connectWs(wsUrl, this.#opts.apiKey!, timeoutMs);\n return new ResponsesWebSocket(ws);\n },\n closeCb: async (conn: ResponsesWebSocket) => {\n conn.close();\n },\n });\n }\n\n label(): string {\n return 'openai.ws.LLM';\n }\n\n get model(): string {\n return this.#opts.model;\n }\n\n prewarm(): void {\n this.#pool.prewarm();\n }\n\n async close(): Promise<void> {\n await this.#pool.close();\n }\n\n override async aclose(): Promise<void> {\n await this.close();\n }\n\n /** Called by LLMStream once response.created fires to atomically persist both the\n * response ID and its corresponding chat context for the next turn's diff. */\n _onResponseCreated(responseId: string, chatCtx: llm.ChatContext): void {\n this.#prevResponseId = responseId;\n this.#prevChatCtx = chatCtx;\n }\n\n _setPendingToolCalls(callIds: Set<string>): void {\n this.#pendingToolCalls = callIds;\n }\n\n chat({\n chatCtx,\n toolCtx,\n connOptions = DEFAULT_API_CONNECT_OPTIONS,\n parallelToolCalls,\n toolChoice,\n extraKwargs,\n }: {\n chatCtx: llm.ChatContext;\n toolCtx?: llm.ToolContext;\n connOptions?: APIConnectOptions;\n parallelToolCalls?: boolean;\n toolChoice?: llm.ToolChoice;\n extraKwargs?: Record<string, unknown>;\n }): WSLLMStream {\n const modelOptions: Record<string, unknown> = { ...(extraKwargs ?? {}) };\n\n parallelToolCalls =\n parallelToolCalls !== undefined ? parallelToolCalls : this.#opts.parallelToolCalls;\n if (toolCtx && Object.keys(toolCtx).length > 0 && parallelToolCalls !== undefined) {\n modelOptions.parallel_tool_calls = parallelToolCalls;\n }\n\n toolChoice =\n toolChoice !== undefined ? toolChoice : (this.#opts.toolChoice as llm.ToolChoice | undefined);\n if (toolChoice) {\n modelOptions.tool_choice = toolChoice;\n }\n\n if (this.#opts.temperature !== undefined) {\n modelOptions.temperature = this.#opts.temperature;\n }\n\n if (this.#opts.store !== undefined) {\n modelOptions.store = this.#opts.store;\n }\n\n if (this.#opts.metadata) {\n modelOptions.metadata = this.#opts.metadata;\n }\n\n if (this.#opts.serviceTier) {\n modelOptions.service_tier = this.#opts.serviceTier;\n }\n\n let inputChatCtx = chatCtx;\n let prevResponseId: string | undefined;\n const canUseStoredResponse = modelOptions.store !== false;\n\n if (canUseStoredResponse && this.#prevChatCtx && this.#prevResponseId) {\n const diff = llm.computeChatCtxDiff(this.#prevChatCtx, chatCtx);\n const lastPrevItemId = this.#prevChatCtx.items.at(-1)?.id ?? null;\n\n if (\n diff.toRemove.length === 0 &&\n diff.toCreate.length > 0 &&\n diff.toCreate[0]![0] === lastPrevItemId\n ) {\n // All new items are appended after the tail of the previous context —\n // safe to send only the incremental input with previous_response_id,\n // but only if all pending tool calls from the previous response have\n // their corresponding function_call_output in the new items.\n const newItemIds = new Set(diff.toCreate.map(([, id]) => id));\n const newItems = chatCtx.items.filter((item: llm.ChatItem) => newItemIds.has(item.id));\n const pendingToolCallsCompleted = this.#pendingToolCallsCompleted(newItems);\n if (pendingToolCallsCompleted) {\n inputChatCtx = new llm.ChatContext(newItems);\n prevResponseId = this.#prevResponseId;\n }\n }\n // Otherwise: items were removed or inserted mid-history — fall back to\n // sending the full context with no previous_response_id.\n }\n\n return new WSLLMStream(this, {\n pool: this.#pool,\n model: this.#opts.model,\n chatCtx: inputChatCtx,\n fullChatCtx: chatCtx,\n toolCtx,\n connOptions,\n modelOptions,\n prevResponseId,\n strictToolSchema: this.#opts.strictToolSchema ?? true,\n });\n }\n\n #pendingToolCallsCompleted(items: llm.ChatItem[]): boolean {\n if (this.#pendingToolCalls.size === 0) return true;\n const completedCallIds = new Set(\n items\n .filter((item): item is llm.FunctionCallOutput => item.type === 'function_call_output')\n .map((item) => item.callId),\n );\n return [...this.#pendingToolCalls].every((callId) => completedCallIds.has(callId));\n }\n}\n\n// ============================================================================\n// WsLLMStream\n// ============================================================================\n\nexport class WSLLMStream extends llm.LLMStream {\n #llm: WSLLM;\n #pool: ConnectionPool<ResponsesWebSocket>;\n #model: string | ChatModels;\n #modelOptions: Record<string, unknown>;\n #strictToolSchema: boolean;\n #prevResponseId?: string;\n /** Full chat context — used as fallback when previous_response_id is stale. */\n #fullChatCtx: llm.ChatContext;\n #responseId = '';\n #pendingToolCalls = new Set<string>();\n\n constructor(\n llm: WSLLM,\n {\n pool,\n model,\n chatCtx,\n fullChatCtx,\n toolCtx,\n connOptions,\n modelOptions,\n prevResponseId,\n strictToolSchema,\n }: {\n pool: ConnectionPool<ResponsesWebSocket>;\n model: string | ChatModels;\n chatCtx: llm.ChatContext;\n fullChatCtx: llm.ChatContext;\n toolCtx?: llm.ToolContext;\n connOptions: APIConnectOptions;\n modelOptions: Record<string, unknown>;\n prevResponseId?: string;\n strictToolSchema: boolean;\n },\n ) {\n super(llm, { chatCtx, toolCtx, connOptions });\n this.#llm = llm;\n this.#pool = pool;\n this.#model = model;\n this.#modelOptions = modelOptions;\n this.#strictToolSchema = strictToolSchema;\n this.#prevResponseId = prevResponseId;\n this.#fullChatCtx = fullChatCtx;\n }\n\n protected async run(): Promise<void> {\n let retryable = true;\n\n try {\n await this.#pool.withConnection(async (conn: ResponsesWebSocket) => {\n const needsRetry = await this.#runWithConn(conn, this.chatCtx, this.#prevResponseId);\n\n if (needsRetry) {\n // previous_response_id was evicted from the server-side cache.\n // Retry once on the same connection with the full context and no ID.\n retryable = true;\n await this.#runWithConn(conn, this.#fullChatCtx, undefined);\n }\n });\n } catch (error) {\n if (\n error instanceof APIStatusError ||\n error instanceof APITimeoutError ||\n error instanceof APIConnectionError\n ) {\n throw error;\n }\n throw new APIConnectionError({\n message: toError(error).message,\n options: { retryable },\n });\n }\n }\n\n /**\n * Execute a single response.create round-trip on the given connection.\n * Returns `true` when the caller should retry with the full chat context\n * (i.e. `previous_response_not_found`), `false` otherwise.\n */\n async #runWithConn(\n conn: ResponsesWebSocket,\n chatCtx: llm.ChatContext,\n prevResponseId: string | undefined,\n ): Promise<boolean> {\n const messages = (await chatCtx.toProviderFormat(\n 'openai.responses',\n )) as OpenAI.Responses.ResponseInputItem[];\n\n const tools = this.toolCtx\n ? Object.entries(this.toolCtx).map(([name, func]) => {\n const oaiParams = {\n type: 'function' as const,\n name,\n description: func.description,\n parameters: llm.toJsonSchema(\n func.parameters,\n true,\n this.#strictToolSchema,\n ) as unknown as OpenAI.Responses.FunctionTool['parameters'],\n } as OpenAI.Responses.FunctionTool;\n\n if (this.#strictToolSchema) {\n oaiParams.strict = true;\n }\n\n return oaiParams;\n })\n : undefined;\n\n const requestOptions: Record<string, unknown> = { ...this.#modelOptions };\n if (!tools) {\n delete requestOptions.tool_choice;\n }\n\n const payload: WsResponseCreateEvent = {\n type: 'response.create',\n model: this.#model as string,\n input: messages as unknown[],\n tools: (tools ?? []) as unknown[],\n ...(prevResponseId ? { previous_response_id: prevResponseId } : {}),\n ...requestOptions,\n };\n\n let channel: stream.StreamChannel<WsServerEvent>;\n try {\n channel = conn.sendRequest(payload);\n } catch (error) {\n if (error instanceof APIConnectionError) {\n conn.close();\n this.#pool.invalidate();\n }\n throw error;\n }\n const reader = channel.stream().getReader();\n\n // Events are already Zod-validated by ResponsesWebSocket before being\n // written to the channel, so no re-parsing is needed here.\n try {\n while (true) {\n const { done, value: event } = await reader.read();\n if (done) break;\n\n let chunk: llm.ChatChunk | undefined;\n\n switch (event.type) {\n case 'error': {\n const retry = this.#handleError(event, conn);\n if (retry) return true;\n break;\n }\n case 'response.created':\n this.#handleResponseCreated(event);\n break;\n case 'response.output_item.done':\n chunk = this.#handleOutputItemDone(event);\n break;\n case 'response.output_text.delta':\n chunk = this.#handleOutputTextDelta(event);\n break;\n case 'response.completed':\n chunk = this.#handleResponseCompleted(event);\n break;\n case 'response.failed':\n this.#handleResponseFailed(event);\n break;\n default:\n break;\n }\n\n if (chunk) {\n this.queue.put(chunk);\n }\n }\n } finally {\n reader.releaseLock();\n }\n\n return false;\n }\n\n /**\n * Returns `true` when the caller should retry with full context\n * (`previous_response_not_found`), throws for all other errors.\n */\n #handleError(event: WsServerEvent & { type: 'error' }, conn: ResponsesWebSocket): boolean {\n const code = event.error?.code;\n\n if (code === 'previous_response_not_found') {\n // The server-side in-memory cache was evicted (e.g. after a failed turn\n // or reconnect). Signal the caller to retry with the full context.\n return true;\n }\n\n if (code === 'websocket_connection_limit_reached' || code === 'websocket_closed') {\n // Transient connection issue (timeout, network drop, or 60-min limit).\n // Evict this connection so the pool opens a fresh one on retry.\n conn.close();\n this.#pool.invalidate();\n throw new APIConnectionError({\n message: event.error?.message ?? `WebSocket closed (${code})`,\n options: { retryable: true },\n });\n }\n\n throw new APIStatusError({\n message: event.error?.message ?? event.message ?? 'Unknown error from OpenAI Responses WS',\n options: {\n statusCode: event.status ?? -1,\n retryable: false,\n },\n });\n }\n\n #handleResponseCreated(event: WsResponseCreatedEvent): void {\n this.#responseId = event.response.id;\n this.#llm._onResponseCreated(event.response.id, this.#fullChatCtx);\n }\n\n #handleOutputItemDone(event: WsOutputItemDoneEvent): llm.ChatChunk | undefined {\n if (event.item.type === 'function_call') {\n this.#pendingToolCalls.add(event.item.call_id);\n return {\n id: this.#responseId,\n delta: {\n role: 'assistant',\n content: undefined,\n toolCalls: [\n llm.FunctionCall.create({\n callId: event.item.call_id,\n name: event.item.name,\n args: event.item.arguments,\n }),\n ],\n },\n };\n }\n return undefined;\n }\n\n #handleOutputTextDelta(event: WsOutputTextDeltaEvent): llm.ChatChunk {\n return {\n id: this.#responseId,\n delta: {\n role: 'assistant',\n content: event.delta,\n },\n };\n }\n\n #handleResponseCompleted(event: WsResponseCompletedEvent): llm.ChatChunk | undefined {\n this.#llm._setPendingToolCalls(this.#pendingToolCalls);\n\n if (event.response.usage) {\n return {\n id: this.#responseId,\n usage: {\n completionTokens: event.response.usage.output_tokens,\n promptTokens: event.response.usage.input_tokens,\n promptCachedTokens: event.response.usage.input_tokens_details.cached_tokens,\n totalTokens: event.response.usage.total_tokens,\n serviceTier: event.response.service_tier ?? undefined,\n },\n };\n }\n return undefined;\n }\n\n #handleResponseFailed(event: WsResponseFailedEvent): void {\n throw new APIStatusError({\n message: event.response?.error?.message ?? 'Response failed',\n options: { statusCode: -1, retryable: false },\n });\n }\n}\n\n// ============================================================================\n// Internal helpers\n// ============================================================================\n\nasync function connectWs(url: string, apiKey: string, timeoutMs: number): Promise<WebSocket> {\n return new Promise<WebSocket>((resolve, reject) => {\n const ws = new WebSocket(url, {\n headers: { Authorization: `Bearer ${apiKey}` },\n });\n\n let settled = false;\n\n const timer = setTimeout(() => {\n settled = true;\n ws.close();\n reject(\n new APIConnectionError({ message: 'Timeout connecting to OpenAI Responses WebSocket' }),\n );\n }, timeoutMs);\n\n ws.once('open', () => {\n if (settled) return;\n settled = true;\n clearTimeout(timer);\n resolve(ws);\n });\n\n ws.once('error', (err) => {\n if (settled) return;\n settled = true;\n clearTimeout(timer);\n reject(\n new APIConnectionError({\n message: `Error connecting to OpenAI Responses WebSocket: ${err.message}`,\n }),\n );\n });\n\n ws.once('close', (code) => {\n if (settled) return;\n settled = true;\n clearTimeout(timer);\n reject(\n new APIConnectionError({\n message: `OpenAI Responses WebSocket closed unexpectedly during connect (code ${code})`,\n }),\n );\n });\n });\n}\n\nfunction getWebSocketStateLabel(readyState: number): string {\n switch (readyState) {\n case WebSocket.CONNECTING:\n return 'CONNECTING';\n case WebSocket.OPEN:\n return 'OPEN';\n case WebSocket.CLOSING:\n return 'CLOSING';\n case WebSocket.CLOSED:\n return 'CLOSED';\n default:\n return `UNKNOWN:${readyState}`;\n }\n}\n"],"mappings":"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","names":["llm"]}
|
package/dist/ws/llm.d.cts
CHANGED
|
@@ -23,6 +23,8 @@ export interface WSLLMOptions {
|
|
|
23
23
|
store?: boolean;
|
|
24
24
|
metadata?: Record<string, string>;
|
|
25
25
|
strictToolSchema?: boolean;
|
|
26
|
+
/** Specifies the processing tier (e.g. 'auto', 'default', 'priority', 'flex'). */
|
|
27
|
+
serviceTier?: string;
|
|
26
28
|
}
|
|
27
29
|
export declare class WSLLM extends llm.LLM {
|
|
28
30
|
#private;
|
package/dist/ws/llm.d.ts
CHANGED
|
@@ -23,6 +23,8 @@ export interface WSLLMOptions {
|
|
|
23
23
|
store?: boolean;
|
|
24
24
|
metadata?: Record<string, string>;
|
|
25
25
|
strictToolSchema?: boolean;
|
|
26
|
+
/** Specifies the processing tier (e.g. 'auto', 'default', 'priority', 'flex'). */
|
|
27
|
+
serviceTier?: string;
|
|
26
28
|
}
|
|
27
29
|
export declare class WSLLM extends llm.LLM {
|
|
28
30
|
#private;
|
package/dist/ws/llm.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"llm.d.ts","sourceRoot":"","sources":["../../src/ws/llm.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,iBAAiB,CAAC;AACzD,OAAO,EAIL,cAAc,EAEd,GAAG,EACH,MAAM,EAEP,MAAM,iBAAiB,CAAC;AAEzB,OAAO,EAAE,SAAS,EAAE,MAAM,IAAI,CAAC;AAC/B,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,cAAc,CAAC;AAC/C,OAAO,KAAK,EAIV,qBAAqB,EAGrB,aAAa,EACd,MAAM,YAAY,CAAC;AAmBpB,qBAAa,kBAAkB;;gBAKjB,EAAE,EAAE,SAAS;IAoDzB;;;OAGG;IACH,WAAW,CAAC,OAAO,EAAE,qBAAqB,GAAG,MAAM,CAAC,aAAa,CAAC,aAAa,CAAC;IAchF,KAAK,IAAI,IAAI;CAQd;AAMD,MAAM,WAAW,YAAY;IAC3B,KAAK,EAAE,MAAM,GAAG,UAAU,CAAC;IAC3B,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,iBAAiB,CAAC,EAAE,OAAO,CAAC;IAC5B,UAAU,CAAC,EAAE,GAAG,CAAC,UAAU,CAAC;IAC5B,KAAK,CAAC,EAAE,OAAO,CAAC;IAChB,QAAQ,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IAClC,gBAAgB,CAAC,EAAE,OAAO,CAAC;
|
|
1
|
+
{"version":3,"file":"llm.d.ts","sourceRoot":"","sources":["../../src/ws/llm.ts"],"names":[],"mappings":"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"}
|
package/dist/ws/llm.js
CHANGED
|
@@ -167,6 +167,9 @@ class WSLLM extends llm.LLM {
|
|
|
167
167
|
if (this.#opts.metadata) {
|
|
168
168
|
modelOptions.metadata = this.#opts.metadata;
|
|
169
169
|
}
|
|
170
|
+
if (this.#opts.serviceTier) {
|
|
171
|
+
modelOptions.service_tier = this.#opts.serviceTier;
|
|
172
|
+
}
|
|
170
173
|
let inputChatCtx = chatCtx;
|
|
171
174
|
let prevResponseId;
|
|
172
175
|
const canUseStoredResponse = modelOptions.store !== false;
|
|
@@ -408,7 +411,8 @@ class WSLLMStream extends llm.LLMStream {
|
|
|
408
411
|
completionTokens: event.response.usage.output_tokens,
|
|
409
412
|
promptTokens: event.response.usage.input_tokens,
|
|
410
413
|
promptCachedTokens: event.response.usage.input_tokens_details.cached_tokens,
|
|
411
|
-
totalTokens: event.response.usage.total_tokens
|
|
414
|
+
totalTokens: event.response.usage.total_tokens,
|
|
415
|
+
serviceTier: event.response.service_tier ?? void 0
|
|
412
416
|
}
|
|
413
417
|
};
|
|
414
418
|
}
|
package/dist/ws/llm.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../src/ws/llm.ts"],"sourcesContent":["// SPDX-FileCopyrightText: 2025 LiveKit, Inc.\n//\n// SPDX-License-Identifier: Apache-2.0\nimport type { APIConnectOptions } from '@livekit/agents';\nimport {\n APIConnectionError,\n APIStatusError,\n APITimeoutError,\n ConnectionPool,\n DEFAULT_API_CONNECT_OPTIONS,\n llm,\n stream,\n toError,\n} from '@livekit/agents';\nimport type OpenAI from 'openai';\nimport { WebSocket } from 'ws';\nimport type { ChatModels } from '../models.js';\nimport type {\n WsOutputItemDoneEvent,\n WsOutputTextDeltaEvent,\n WsResponseCompletedEvent,\n WsResponseCreateEvent,\n WsResponseCreatedEvent,\n WsResponseFailedEvent,\n WsServerEvent,\n} from './types.js';\nimport { wsServerEventSchema } from './types.js';\n\nconst OPENAI_RESPONSES_WS_URL = 'wss://api.openai.com/v1/responses';\n\n// OpenAI enforces a 60-minute maximum duration on Responses WebSocket connections.\nconst WS_MAX_SESSION_DURATION = 3_600_000;\n\n// ============================================================================\n// Internal: ResponsesWebSocket\n//\n// Wraps a single raw WebSocket connection. Maintains a FIFO queue of\n// StreamChannels — one per outstanding response.create request — and\n// dispatches every incoming server-event to the front of the queue.\n// A response is terminated (and its channel closed) when the service sends\n// response.completed, response.failed, or error.\n//\n// ============================================================================\n\nexport class ResponsesWebSocket {\n #ws: WebSocket;\n // FIFO queue: the front entry receives validated WsServerEvents for the in-flight response.\n #outputQueue: stream.StreamChannel<WsServerEvent>[] = [];\n\n constructor(ws: WebSocket) {\n this.#ws = ws;\n\n ws.on('message', (data: Buffer) => {\n const current = this.#outputQueue[0];\n if (!current) return;\n\n let raw: unknown;\n try {\n raw = JSON.parse(data.toString());\n } catch {\n return;\n }\n\n // Validate and type-narrow with Zod at write time so readers always\n // receive a fully-typed WsServerEvent.\n const parsed = wsServerEventSchema.safeParse(raw);\n if (!parsed.success) return;\n\n const event = parsed.data;\n void current.write(event);\n\n // Close and dequeue on any terminal event.\n if (\n event.type === 'response.completed' ||\n event.type === 'response.failed' ||\n event.type === 'error'\n ) {\n void current.close();\n this.#outputQueue.shift();\n }\n });\n\n ws.on('close', () => {\n // If the WebSocket closes while requests are still in flight, synthesise\n // a typed error event so all readers can handle it cleanly.\n for (const current of this.#outputQueue) {\n if (!current.closed) {\n const closeError: WsServerEvent = {\n type: 'error',\n error: {\n code: 'websocket_closed',\n message: 'OpenAI Responses WebSocket closed unexpectedly',\n },\n };\n void current.write(closeError).finally(() => current.close());\n }\n }\n this.#outputQueue = [];\n });\n }\n\n /**\n * Send a response.create event. Returns a typed `StreamChannel<WsServerEvent>`\n * that yields validated server events until the response terminates.\n */\n sendRequest(payload: WsResponseCreateEvent): stream.StreamChannel<WsServerEvent> {\n if (this.#ws.readyState !== WebSocket.OPEN) {\n throw new APIConnectionError({\n message: `OpenAI Responses WebSocket is not open (state ${getWebSocketStateLabel(this.#ws.readyState)})`,\n options: { retryable: true },\n });\n }\n\n const channel = stream.createStreamChannel<WsServerEvent>();\n this.#outputQueue.push(channel);\n this.#ws.send(JSON.stringify(payload));\n return channel;\n }\n\n close(): void {\n // Drain pending channels before closing the socket.\n for (const ch of this.#outputQueue) {\n void ch.close();\n }\n this.#outputQueue = [];\n this.#ws.close();\n }\n}\n\n// ============================================================================\n// LLMOptions\n// ============================================================================\n\nexport interface WSLLMOptions {\n model: string | ChatModels;\n apiKey?: string;\n baseURL?: string;\n temperature?: number;\n parallelToolCalls?: boolean;\n toolChoice?: llm.ToolChoice;\n store?: boolean;\n metadata?: Record<string, string>;\n strictToolSchema?: boolean;\n}\n\nconst defaultLLMOptions: WSLLMOptions = {\n model: 'gpt-4.1',\n apiKey: process.env.OPENAI_API_KEY,\n strictToolSchema: true,\n};\n\n// ============================================================================\n// LLM\n// ============================================================================\n\nexport class WSLLM extends llm.LLM {\n #opts: WSLLMOptions;\n #pool: ConnectionPool<ResponsesWebSocket>;\n #prevResponseId = '';\n #prevChatCtx: llm.ChatContext | null = null;\n #pendingToolCalls = new Set<string>();\n\n /**\n * Create a new instance of the OpenAI Responses API WebSocket LLM.\n *\n * @remarks\n * `apiKey` must be set to your OpenAI API key, either using the argument or\n * by setting the `OPENAI_API_KEY` environment variable.\n *\n * A persistent WebSocket connection to `/v1/responses` is maintained and\n * reused across turns, reducing per-turn continuation overhead for\n * tool-call-heavy workflows.\n */\n constructor(opts: Partial<WSLLMOptions> = defaultLLMOptions) {\n super();\n\n this.#opts = { ...defaultLLMOptions, ...opts };\n if (!this.#opts.apiKey) {\n throw new Error('OpenAI API key is required, whether as an argument or as $OPENAI_API_KEY');\n }\n\n this.#pool = new ConnectionPool<ResponsesWebSocket>({\n maxSessionDuration: WS_MAX_SESSION_DURATION,\n connectCb: async (timeoutMs: number) => {\n const wsUrl = this.#opts.baseURL\n ? `${this.#opts.baseURL.replace(/^https?/, 'wss').replace(/\\/+$/, '')}/responses`\n : OPENAI_RESPONSES_WS_URL;\n const ws = await connectWs(wsUrl, this.#opts.apiKey!, timeoutMs);\n return new ResponsesWebSocket(ws);\n },\n closeCb: async (conn: ResponsesWebSocket) => {\n conn.close();\n },\n });\n }\n\n label(): string {\n return 'openai.ws.LLM';\n }\n\n get model(): string {\n return this.#opts.model;\n }\n\n prewarm(): void {\n this.#pool.prewarm();\n }\n\n async close(): Promise<void> {\n await this.#pool.close();\n }\n\n override async aclose(): Promise<void> {\n await this.close();\n }\n\n /** Called by LLMStream once response.created fires to atomically persist both the\n * response ID and its corresponding chat context for the next turn's diff. */\n _onResponseCreated(responseId: string, chatCtx: llm.ChatContext): void {\n this.#prevResponseId = responseId;\n this.#prevChatCtx = chatCtx;\n }\n\n _setPendingToolCalls(callIds: Set<string>): void {\n this.#pendingToolCalls = callIds;\n }\n\n chat({\n chatCtx,\n toolCtx,\n connOptions = DEFAULT_API_CONNECT_OPTIONS,\n parallelToolCalls,\n toolChoice,\n extraKwargs,\n }: {\n chatCtx: llm.ChatContext;\n toolCtx?: llm.ToolContext;\n connOptions?: APIConnectOptions;\n parallelToolCalls?: boolean;\n toolChoice?: llm.ToolChoice;\n extraKwargs?: Record<string, unknown>;\n }): WSLLMStream {\n const modelOptions: Record<string, unknown> = { ...(extraKwargs ?? {}) };\n\n parallelToolCalls =\n parallelToolCalls !== undefined ? parallelToolCalls : this.#opts.parallelToolCalls;\n if (toolCtx && Object.keys(toolCtx).length > 0 && parallelToolCalls !== undefined) {\n modelOptions.parallel_tool_calls = parallelToolCalls;\n }\n\n toolChoice =\n toolChoice !== undefined ? toolChoice : (this.#opts.toolChoice as llm.ToolChoice | undefined);\n if (toolChoice) {\n modelOptions.tool_choice = toolChoice;\n }\n\n if (this.#opts.temperature !== undefined) {\n modelOptions.temperature = this.#opts.temperature;\n }\n\n if (this.#opts.store !== undefined) {\n modelOptions.store = this.#opts.store;\n }\n\n if (this.#opts.metadata) {\n modelOptions.metadata = this.#opts.metadata;\n }\n\n let inputChatCtx = chatCtx;\n let prevResponseId: string | undefined;\n const canUseStoredResponse = modelOptions.store !== false;\n\n if (canUseStoredResponse && this.#prevChatCtx && this.#prevResponseId) {\n const diff = llm.computeChatCtxDiff(this.#prevChatCtx, chatCtx);\n const lastPrevItemId = this.#prevChatCtx.items.at(-1)?.id ?? null;\n\n if (\n diff.toRemove.length === 0 &&\n diff.toCreate.length > 0 &&\n diff.toCreate[0]![0] === lastPrevItemId\n ) {\n // All new items are appended after the tail of the previous context —\n // safe to send only the incremental input with previous_response_id,\n // but only if all pending tool calls from the previous response have\n // their corresponding function_call_output in the new items.\n const newItemIds = new Set(diff.toCreate.map(([, id]) => id));\n const newItems = chatCtx.items.filter((item: llm.ChatItem) => newItemIds.has(item.id));\n const pendingToolCallsCompleted = this.#pendingToolCallsCompleted(newItems);\n if (pendingToolCallsCompleted) {\n inputChatCtx = new llm.ChatContext(newItems);\n prevResponseId = this.#prevResponseId;\n }\n }\n // Otherwise: items were removed or inserted mid-history — fall back to\n // sending the full context with no previous_response_id.\n }\n\n return new WSLLMStream(this, {\n pool: this.#pool,\n model: this.#opts.model,\n chatCtx: inputChatCtx,\n fullChatCtx: chatCtx,\n toolCtx,\n connOptions,\n modelOptions,\n prevResponseId,\n strictToolSchema: this.#opts.strictToolSchema ?? true,\n });\n }\n\n #pendingToolCallsCompleted(items: llm.ChatItem[]): boolean {\n if (this.#pendingToolCalls.size === 0) return true;\n const completedCallIds = new Set(\n items\n .filter((item): item is llm.FunctionCallOutput => item.type === 'function_call_output')\n .map((item) => item.callId),\n );\n return [...this.#pendingToolCalls].every((callId) => completedCallIds.has(callId));\n }\n}\n\n// ============================================================================\n// WsLLMStream\n// ============================================================================\n\nexport class WSLLMStream extends llm.LLMStream {\n #llm: WSLLM;\n #pool: ConnectionPool<ResponsesWebSocket>;\n #model: string | ChatModels;\n #modelOptions: Record<string, unknown>;\n #strictToolSchema: boolean;\n #prevResponseId?: string;\n /** Full chat context — used as fallback when previous_response_id is stale. */\n #fullChatCtx: llm.ChatContext;\n #responseId = '';\n #pendingToolCalls = new Set<string>();\n\n constructor(\n llm: WSLLM,\n {\n pool,\n model,\n chatCtx,\n fullChatCtx,\n toolCtx,\n connOptions,\n modelOptions,\n prevResponseId,\n strictToolSchema,\n }: {\n pool: ConnectionPool<ResponsesWebSocket>;\n model: string | ChatModels;\n chatCtx: llm.ChatContext;\n fullChatCtx: llm.ChatContext;\n toolCtx?: llm.ToolContext;\n connOptions: APIConnectOptions;\n modelOptions: Record<string, unknown>;\n prevResponseId?: string;\n strictToolSchema: boolean;\n },\n ) {\n super(llm, { chatCtx, toolCtx, connOptions });\n this.#llm = llm;\n this.#pool = pool;\n this.#model = model;\n this.#modelOptions = modelOptions;\n this.#strictToolSchema = strictToolSchema;\n this.#prevResponseId = prevResponseId;\n this.#fullChatCtx = fullChatCtx;\n }\n\n protected async run(): Promise<void> {\n let retryable = true;\n\n try {\n await this.#pool.withConnection(async (conn: ResponsesWebSocket) => {\n const needsRetry = await this.#runWithConn(conn, this.chatCtx, this.#prevResponseId);\n\n if (needsRetry) {\n // previous_response_id was evicted from the server-side cache.\n // Retry once on the same connection with the full context and no ID.\n retryable = true;\n await this.#runWithConn(conn, this.#fullChatCtx, undefined);\n }\n });\n } catch (error) {\n if (\n error instanceof APIStatusError ||\n error instanceof APITimeoutError ||\n error instanceof APIConnectionError\n ) {\n throw error;\n }\n throw new APIConnectionError({\n message: toError(error).message,\n options: { retryable },\n });\n }\n }\n\n /**\n * Execute a single response.create round-trip on the given connection.\n * Returns `true` when the caller should retry with the full chat context\n * (i.e. `previous_response_not_found`), `false` otherwise.\n */\n async #runWithConn(\n conn: ResponsesWebSocket,\n chatCtx: llm.ChatContext,\n prevResponseId: string | undefined,\n ): Promise<boolean> {\n const messages = (await chatCtx.toProviderFormat(\n 'openai.responses',\n )) as OpenAI.Responses.ResponseInputItem[];\n\n const tools = this.toolCtx\n ? Object.entries(this.toolCtx).map(([name, func]) => {\n const oaiParams = {\n type: 'function' as const,\n name,\n description: func.description,\n parameters: llm.toJsonSchema(\n func.parameters,\n true,\n this.#strictToolSchema,\n ) as unknown as OpenAI.Responses.FunctionTool['parameters'],\n } as OpenAI.Responses.FunctionTool;\n\n if (this.#strictToolSchema) {\n oaiParams.strict = true;\n }\n\n return oaiParams;\n })\n : undefined;\n\n const requestOptions: Record<string, unknown> = { ...this.#modelOptions };\n if (!tools) {\n delete requestOptions.tool_choice;\n }\n\n const payload: WsResponseCreateEvent = {\n type: 'response.create',\n model: this.#model as string,\n input: messages as unknown[],\n tools: (tools ?? []) as unknown[],\n ...(prevResponseId ? { previous_response_id: prevResponseId } : {}),\n ...requestOptions,\n };\n\n let channel: stream.StreamChannel<WsServerEvent>;\n try {\n channel = conn.sendRequest(payload);\n } catch (error) {\n if (error instanceof APIConnectionError) {\n conn.close();\n this.#pool.invalidate();\n }\n throw error;\n }\n const reader = channel.stream().getReader();\n\n // Events are already Zod-validated by ResponsesWebSocket before being\n // written to the channel, so no re-parsing is needed here.\n try {\n while (true) {\n const { done, value: event } = await reader.read();\n if (done) break;\n\n let chunk: llm.ChatChunk | undefined;\n\n switch (event.type) {\n case 'error': {\n const retry = this.#handleError(event, conn);\n if (retry) return true;\n break;\n }\n case 'response.created':\n this.#handleResponseCreated(event);\n break;\n case 'response.output_item.done':\n chunk = this.#handleOutputItemDone(event);\n break;\n case 'response.output_text.delta':\n chunk = this.#handleOutputTextDelta(event);\n break;\n case 'response.completed':\n chunk = this.#handleResponseCompleted(event);\n break;\n case 'response.failed':\n this.#handleResponseFailed(event);\n break;\n default:\n break;\n }\n\n if (chunk) {\n this.queue.put(chunk);\n }\n }\n } finally {\n reader.releaseLock();\n }\n\n return false;\n }\n\n /**\n * Returns `true` when the caller should retry with full context\n * (`previous_response_not_found`), throws for all other errors.\n */\n #handleError(event: WsServerEvent & { type: 'error' }, conn: ResponsesWebSocket): boolean {\n const code = event.error?.code;\n\n if (code === 'previous_response_not_found') {\n // The server-side in-memory cache was evicted (e.g. after a failed turn\n // or reconnect). Signal the caller to retry with the full context.\n return true;\n }\n\n if (code === 'websocket_connection_limit_reached' || code === 'websocket_closed') {\n // Transient connection issue (timeout, network drop, or 60-min limit).\n // Evict this connection so the pool opens a fresh one on retry.\n conn.close();\n this.#pool.invalidate();\n throw new APIConnectionError({\n message: event.error?.message ?? `WebSocket closed (${code})`,\n options: { retryable: true },\n });\n }\n\n throw new APIStatusError({\n message: event.error?.message ?? event.message ?? 'Unknown error from OpenAI Responses WS',\n options: {\n statusCode: event.status ?? -1,\n retryable: false,\n },\n });\n }\n\n #handleResponseCreated(event: WsResponseCreatedEvent): void {\n this.#responseId = event.response.id;\n this.#llm._onResponseCreated(event.response.id, this.#fullChatCtx);\n }\n\n #handleOutputItemDone(event: WsOutputItemDoneEvent): llm.ChatChunk | undefined {\n if (event.item.type === 'function_call') {\n this.#pendingToolCalls.add(event.item.call_id);\n return {\n id: this.#responseId,\n delta: {\n role: 'assistant',\n content: undefined,\n toolCalls: [\n llm.FunctionCall.create({\n callId: event.item.call_id,\n name: event.item.name,\n args: event.item.arguments,\n }),\n ],\n },\n };\n }\n return undefined;\n }\n\n #handleOutputTextDelta(event: WsOutputTextDeltaEvent): llm.ChatChunk {\n return {\n id: this.#responseId,\n delta: {\n role: 'assistant',\n content: event.delta,\n },\n };\n }\n\n #handleResponseCompleted(event: WsResponseCompletedEvent): llm.ChatChunk | undefined {\n this.#llm._setPendingToolCalls(this.#pendingToolCalls);\n\n if (event.response.usage) {\n return {\n id: this.#responseId,\n usage: {\n completionTokens: event.response.usage.output_tokens,\n promptTokens: event.response.usage.input_tokens,\n promptCachedTokens: event.response.usage.input_tokens_details.cached_tokens,\n totalTokens: event.response.usage.total_tokens,\n },\n };\n }\n return undefined;\n }\n\n #handleResponseFailed(event: WsResponseFailedEvent): void {\n throw new APIStatusError({\n message: event.response?.error?.message ?? 'Response failed',\n options: { statusCode: -1, retryable: false },\n });\n }\n}\n\n// ============================================================================\n// Internal helpers\n// ============================================================================\n\nasync function connectWs(url: string, apiKey: string, timeoutMs: number): Promise<WebSocket> {\n return new Promise<WebSocket>((resolve, reject) => {\n const ws = new WebSocket(url, {\n headers: { Authorization: `Bearer ${apiKey}` },\n });\n\n let settled = false;\n\n const timer = setTimeout(() => {\n settled = true;\n ws.close();\n reject(\n new APIConnectionError({ message: 'Timeout connecting to OpenAI Responses WebSocket' }),\n );\n }, timeoutMs);\n\n ws.once('open', () => {\n if (settled) return;\n settled = true;\n clearTimeout(timer);\n resolve(ws);\n });\n\n ws.once('error', (err) => {\n if (settled) return;\n settled = true;\n clearTimeout(timer);\n reject(\n new APIConnectionError({\n message: `Error connecting to OpenAI Responses WebSocket: ${err.message}`,\n }),\n );\n });\n\n ws.once('close', (code) => {\n if (settled) return;\n settled = true;\n clearTimeout(timer);\n reject(\n new APIConnectionError({\n message: `OpenAI Responses WebSocket closed unexpectedly during connect (code ${code})`,\n }),\n );\n });\n });\n}\n\nfunction getWebSocketStateLabel(readyState: number): string {\n switch (readyState) {\n case WebSocket.CONNECTING:\n return 'CONNECTING';\n case WebSocket.OPEN:\n return 'OPEN';\n case WebSocket.CLOSING:\n return 'CLOSING';\n case WebSocket.CLOSED:\n return 'CLOSED';\n default:\n return `UNKNOWN:${readyState}`;\n }\n}\n"],"mappings":"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","names":["llm"]}
|
|
1
|
+
{"version":3,"sources":["../../src/ws/llm.ts"],"sourcesContent":["// SPDX-FileCopyrightText: 2025 LiveKit, Inc.\n//\n// SPDX-License-Identifier: Apache-2.0\nimport type { APIConnectOptions } from '@livekit/agents';\nimport {\n APIConnectionError,\n APIStatusError,\n APITimeoutError,\n ConnectionPool,\n DEFAULT_API_CONNECT_OPTIONS,\n llm,\n stream,\n toError,\n} from '@livekit/agents';\nimport type OpenAI from 'openai';\nimport { WebSocket } from 'ws';\nimport type { ChatModels } from '../models.js';\nimport type {\n WsOutputItemDoneEvent,\n WsOutputTextDeltaEvent,\n WsResponseCompletedEvent,\n WsResponseCreateEvent,\n WsResponseCreatedEvent,\n WsResponseFailedEvent,\n WsServerEvent,\n} from './types.js';\nimport { wsServerEventSchema } from './types.js';\n\nconst OPENAI_RESPONSES_WS_URL = 'wss://api.openai.com/v1/responses';\n\n// OpenAI enforces a 60-minute maximum duration on Responses WebSocket connections.\nconst WS_MAX_SESSION_DURATION = 3_600_000;\n\n// ============================================================================\n// Internal: ResponsesWebSocket\n//\n// Wraps a single raw WebSocket connection. Maintains a FIFO queue of\n// StreamChannels — one per outstanding response.create request — and\n// dispatches every incoming server-event to the front of the queue.\n// A response is terminated (and its channel closed) when the service sends\n// response.completed, response.failed, or error.\n//\n// ============================================================================\n\nexport class ResponsesWebSocket {\n #ws: WebSocket;\n // FIFO queue: the front entry receives validated WsServerEvents for the in-flight response.\n #outputQueue: stream.StreamChannel<WsServerEvent>[] = [];\n\n constructor(ws: WebSocket) {\n this.#ws = ws;\n\n ws.on('message', (data: Buffer) => {\n const current = this.#outputQueue[0];\n if (!current) return;\n\n let raw: unknown;\n try {\n raw = JSON.parse(data.toString());\n } catch {\n return;\n }\n\n // Validate and type-narrow with Zod at write time so readers always\n // receive a fully-typed WsServerEvent.\n const parsed = wsServerEventSchema.safeParse(raw);\n if (!parsed.success) return;\n\n const event = parsed.data;\n void current.write(event);\n\n // Close and dequeue on any terminal event.\n if (\n event.type === 'response.completed' ||\n event.type === 'response.failed' ||\n event.type === 'error'\n ) {\n void current.close();\n this.#outputQueue.shift();\n }\n });\n\n ws.on('close', () => {\n // If the WebSocket closes while requests are still in flight, synthesise\n // a typed error event so all readers can handle it cleanly.\n for (const current of this.#outputQueue) {\n if (!current.closed) {\n const closeError: WsServerEvent = {\n type: 'error',\n error: {\n code: 'websocket_closed',\n message: 'OpenAI Responses WebSocket closed unexpectedly',\n },\n };\n void current.write(closeError).finally(() => current.close());\n }\n }\n this.#outputQueue = [];\n });\n }\n\n /**\n * Send a response.create event. Returns a typed `StreamChannel<WsServerEvent>`\n * that yields validated server events until the response terminates.\n */\n sendRequest(payload: WsResponseCreateEvent): stream.StreamChannel<WsServerEvent> {\n if (this.#ws.readyState !== WebSocket.OPEN) {\n throw new APIConnectionError({\n message: `OpenAI Responses WebSocket is not open (state ${getWebSocketStateLabel(this.#ws.readyState)})`,\n options: { retryable: true },\n });\n }\n\n const channel = stream.createStreamChannel<WsServerEvent>();\n this.#outputQueue.push(channel);\n this.#ws.send(JSON.stringify(payload));\n return channel;\n }\n\n close(): void {\n // Drain pending channels before closing the socket.\n for (const ch of this.#outputQueue) {\n void ch.close();\n }\n this.#outputQueue = [];\n this.#ws.close();\n }\n}\n\n// ============================================================================\n// LLMOptions\n// ============================================================================\n\nexport interface WSLLMOptions {\n model: string | ChatModels;\n apiKey?: string;\n baseURL?: string;\n temperature?: number;\n parallelToolCalls?: boolean;\n toolChoice?: llm.ToolChoice;\n store?: boolean;\n metadata?: Record<string, string>;\n strictToolSchema?: boolean;\n /** Specifies the processing tier (e.g. 'auto', 'default', 'priority', 'flex'). */\n serviceTier?: string;\n}\n\nconst defaultLLMOptions: WSLLMOptions = {\n model: 'gpt-4.1',\n apiKey: process.env.OPENAI_API_KEY,\n strictToolSchema: true,\n};\n\n// ============================================================================\n// LLM\n// ============================================================================\n\nexport class WSLLM extends llm.LLM {\n #opts: WSLLMOptions;\n #pool: ConnectionPool<ResponsesWebSocket>;\n #prevResponseId = '';\n #prevChatCtx: llm.ChatContext | null = null;\n #pendingToolCalls = new Set<string>();\n\n /**\n * Create a new instance of the OpenAI Responses API WebSocket LLM.\n *\n * @remarks\n * `apiKey` must be set to your OpenAI API key, either using the argument or\n * by setting the `OPENAI_API_KEY` environment variable.\n *\n * A persistent WebSocket connection to `/v1/responses` is maintained and\n * reused across turns, reducing per-turn continuation overhead for\n * tool-call-heavy workflows.\n */\n constructor(opts: Partial<WSLLMOptions> = defaultLLMOptions) {\n super();\n\n this.#opts = { ...defaultLLMOptions, ...opts };\n if (!this.#opts.apiKey) {\n throw new Error('OpenAI API key is required, whether as an argument or as $OPENAI_API_KEY');\n }\n\n this.#pool = new ConnectionPool<ResponsesWebSocket>({\n maxSessionDuration: WS_MAX_SESSION_DURATION,\n connectCb: async (timeoutMs: number) => {\n const wsUrl = this.#opts.baseURL\n ? `${this.#opts.baseURL.replace(/^https?/, 'wss').replace(/\\/+$/, '')}/responses`\n : OPENAI_RESPONSES_WS_URL;\n const ws = await connectWs(wsUrl, this.#opts.apiKey!, timeoutMs);\n return new ResponsesWebSocket(ws);\n },\n closeCb: async (conn: ResponsesWebSocket) => {\n conn.close();\n },\n });\n }\n\n label(): string {\n return 'openai.ws.LLM';\n }\n\n get model(): string {\n return this.#opts.model;\n }\n\n prewarm(): void {\n this.#pool.prewarm();\n }\n\n async close(): Promise<void> {\n await this.#pool.close();\n }\n\n override async aclose(): Promise<void> {\n await this.close();\n }\n\n /** Called by LLMStream once response.created fires to atomically persist both the\n * response ID and its corresponding chat context for the next turn's diff. */\n _onResponseCreated(responseId: string, chatCtx: llm.ChatContext): void {\n this.#prevResponseId = responseId;\n this.#prevChatCtx = chatCtx;\n }\n\n _setPendingToolCalls(callIds: Set<string>): void {\n this.#pendingToolCalls = callIds;\n }\n\n chat({\n chatCtx,\n toolCtx,\n connOptions = DEFAULT_API_CONNECT_OPTIONS,\n parallelToolCalls,\n toolChoice,\n extraKwargs,\n }: {\n chatCtx: llm.ChatContext;\n toolCtx?: llm.ToolContext;\n connOptions?: APIConnectOptions;\n parallelToolCalls?: boolean;\n toolChoice?: llm.ToolChoice;\n extraKwargs?: Record<string, unknown>;\n }): WSLLMStream {\n const modelOptions: Record<string, unknown> = { ...(extraKwargs ?? {}) };\n\n parallelToolCalls =\n parallelToolCalls !== undefined ? parallelToolCalls : this.#opts.parallelToolCalls;\n if (toolCtx && Object.keys(toolCtx).length > 0 && parallelToolCalls !== undefined) {\n modelOptions.parallel_tool_calls = parallelToolCalls;\n }\n\n toolChoice =\n toolChoice !== undefined ? toolChoice : (this.#opts.toolChoice as llm.ToolChoice | undefined);\n if (toolChoice) {\n modelOptions.tool_choice = toolChoice;\n }\n\n if (this.#opts.temperature !== undefined) {\n modelOptions.temperature = this.#opts.temperature;\n }\n\n if (this.#opts.store !== undefined) {\n modelOptions.store = this.#opts.store;\n }\n\n if (this.#opts.metadata) {\n modelOptions.metadata = this.#opts.metadata;\n }\n\n if (this.#opts.serviceTier) {\n modelOptions.service_tier = this.#opts.serviceTier;\n }\n\n let inputChatCtx = chatCtx;\n let prevResponseId: string | undefined;\n const canUseStoredResponse = modelOptions.store !== false;\n\n if (canUseStoredResponse && this.#prevChatCtx && this.#prevResponseId) {\n const diff = llm.computeChatCtxDiff(this.#prevChatCtx, chatCtx);\n const lastPrevItemId = this.#prevChatCtx.items.at(-1)?.id ?? null;\n\n if (\n diff.toRemove.length === 0 &&\n diff.toCreate.length > 0 &&\n diff.toCreate[0]![0] === lastPrevItemId\n ) {\n // All new items are appended after the tail of the previous context —\n // safe to send only the incremental input with previous_response_id,\n // but only if all pending tool calls from the previous response have\n // their corresponding function_call_output in the new items.\n const newItemIds = new Set(diff.toCreate.map(([, id]) => id));\n const newItems = chatCtx.items.filter((item: llm.ChatItem) => newItemIds.has(item.id));\n const pendingToolCallsCompleted = this.#pendingToolCallsCompleted(newItems);\n if (pendingToolCallsCompleted) {\n inputChatCtx = new llm.ChatContext(newItems);\n prevResponseId = this.#prevResponseId;\n }\n }\n // Otherwise: items were removed or inserted mid-history — fall back to\n // sending the full context with no previous_response_id.\n }\n\n return new WSLLMStream(this, {\n pool: this.#pool,\n model: this.#opts.model,\n chatCtx: inputChatCtx,\n fullChatCtx: chatCtx,\n toolCtx,\n connOptions,\n modelOptions,\n prevResponseId,\n strictToolSchema: this.#opts.strictToolSchema ?? true,\n });\n }\n\n #pendingToolCallsCompleted(items: llm.ChatItem[]): boolean {\n if (this.#pendingToolCalls.size === 0) return true;\n const completedCallIds = new Set(\n items\n .filter((item): item is llm.FunctionCallOutput => item.type === 'function_call_output')\n .map((item) => item.callId),\n );\n return [...this.#pendingToolCalls].every((callId) => completedCallIds.has(callId));\n }\n}\n\n// ============================================================================\n// WsLLMStream\n// ============================================================================\n\nexport class WSLLMStream extends llm.LLMStream {\n #llm: WSLLM;\n #pool: ConnectionPool<ResponsesWebSocket>;\n #model: string | ChatModels;\n #modelOptions: Record<string, unknown>;\n #strictToolSchema: boolean;\n #prevResponseId?: string;\n /** Full chat context — used as fallback when previous_response_id is stale. */\n #fullChatCtx: llm.ChatContext;\n #responseId = '';\n #pendingToolCalls = new Set<string>();\n\n constructor(\n llm: WSLLM,\n {\n pool,\n model,\n chatCtx,\n fullChatCtx,\n toolCtx,\n connOptions,\n modelOptions,\n prevResponseId,\n strictToolSchema,\n }: {\n pool: ConnectionPool<ResponsesWebSocket>;\n model: string | ChatModels;\n chatCtx: llm.ChatContext;\n fullChatCtx: llm.ChatContext;\n toolCtx?: llm.ToolContext;\n connOptions: APIConnectOptions;\n modelOptions: Record<string, unknown>;\n prevResponseId?: string;\n strictToolSchema: boolean;\n },\n ) {\n super(llm, { chatCtx, toolCtx, connOptions });\n this.#llm = llm;\n this.#pool = pool;\n this.#model = model;\n this.#modelOptions = modelOptions;\n this.#strictToolSchema = strictToolSchema;\n this.#prevResponseId = prevResponseId;\n this.#fullChatCtx = fullChatCtx;\n }\n\n protected async run(): Promise<void> {\n let retryable = true;\n\n try {\n await this.#pool.withConnection(async (conn: ResponsesWebSocket) => {\n const needsRetry = await this.#runWithConn(conn, this.chatCtx, this.#prevResponseId);\n\n if (needsRetry) {\n // previous_response_id was evicted from the server-side cache.\n // Retry once on the same connection with the full context and no ID.\n retryable = true;\n await this.#runWithConn(conn, this.#fullChatCtx, undefined);\n }\n });\n } catch (error) {\n if (\n error instanceof APIStatusError ||\n error instanceof APITimeoutError ||\n error instanceof APIConnectionError\n ) {\n throw error;\n }\n throw new APIConnectionError({\n message: toError(error).message,\n options: { retryable },\n });\n }\n }\n\n /**\n * Execute a single response.create round-trip on the given connection.\n * Returns `true` when the caller should retry with the full chat context\n * (i.e. `previous_response_not_found`), `false` otherwise.\n */\n async #runWithConn(\n conn: ResponsesWebSocket,\n chatCtx: llm.ChatContext,\n prevResponseId: string | undefined,\n ): Promise<boolean> {\n const messages = (await chatCtx.toProviderFormat(\n 'openai.responses',\n )) as OpenAI.Responses.ResponseInputItem[];\n\n const tools = this.toolCtx\n ? Object.entries(this.toolCtx).map(([name, func]) => {\n const oaiParams = {\n type: 'function' as const,\n name,\n description: func.description,\n parameters: llm.toJsonSchema(\n func.parameters,\n true,\n this.#strictToolSchema,\n ) as unknown as OpenAI.Responses.FunctionTool['parameters'],\n } as OpenAI.Responses.FunctionTool;\n\n if (this.#strictToolSchema) {\n oaiParams.strict = true;\n }\n\n return oaiParams;\n })\n : undefined;\n\n const requestOptions: Record<string, unknown> = { ...this.#modelOptions };\n if (!tools) {\n delete requestOptions.tool_choice;\n }\n\n const payload: WsResponseCreateEvent = {\n type: 'response.create',\n model: this.#model as string,\n input: messages as unknown[],\n tools: (tools ?? []) as unknown[],\n ...(prevResponseId ? { previous_response_id: prevResponseId } : {}),\n ...requestOptions,\n };\n\n let channel: stream.StreamChannel<WsServerEvent>;\n try {\n channel = conn.sendRequest(payload);\n } catch (error) {\n if (error instanceof APIConnectionError) {\n conn.close();\n this.#pool.invalidate();\n }\n throw error;\n }\n const reader = channel.stream().getReader();\n\n // Events are already Zod-validated by ResponsesWebSocket before being\n // written to the channel, so no re-parsing is needed here.\n try {\n while (true) {\n const { done, value: event } = await reader.read();\n if (done) break;\n\n let chunk: llm.ChatChunk | undefined;\n\n switch (event.type) {\n case 'error': {\n const retry = this.#handleError(event, conn);\n if (retry) return true;\n break;\n }\n case 'response.created':\n this.#handleResponseCreated(event);\n break;\n case 'response.output_item.done':\n chunk = this.#handleOutputItemDone(event);\n break;\n case 'response.output_text.delta':\n chunk = this.#handleOutputTextDelta(event);\n break;\n case 'response.completed':\n chunk = this.#handleResponseCompleted(event);\n break;\n case 'response.failed':\n this.#handleResponseFailed(event);\n break;\n default:\n break;\n }\n\n if (chunk) {\n this.queue.put(chunk);\n }\n }\n } finally {\n reader.releaseLock();\n }\n\n return false;\n }\n\n /**\n * Returns `true` when the caller should retry with full context\n * (`previous_response_not_found`), throws for all other errors.\n */\n #handleError(event: WsServerEvent & { type: 'error' }, conn: ResponsesWebSocket): boolean {\n const code = event.error?.code;\n\n if (code === 'previous_response_not_found') {\n // The server-side in-memory cache was evicted (e.g. after a failed turn\n // or reconnect). Signal the caller to retry with the full context.\n return true;\n }\n\n if (code === 'websocket_connection_limit_reached' || code === 'websocket_closed') {\n // Transient connection issue (timeout, network drop, or 60-min limit).\n // Evict this connection so the pool opens a fresh one on retry.\n conn.close();\n this.#pool.invalidate();\n throw new APIConnectionError({\n message: event.error?.message ?? `WebSocket closed (${code})`,\n options: { retryable: true },\n });\n }\n\n throw new APIStatusError({\n message: event.error?.message ?? event.message ?? 'Unknown error from OpenAI Responses WS',\n options: {\n statusCode: event.status ?? -1,\n retryable: false,\n },\n });\n }\n\n #handleResponseCreated(event: WsResponseCreatedEvent): void {\n this.#responseId = event.response.id;\n this.#llm._onResponseCreated(event.response.id, this.#fullChatCtx);\n }\n\n #handleOutputItemDone(event: WsOutputItemDoneEvent): llm.ChatChunk | undefined {\n if (event.item.type === 'function_call') {\n this.#pendingToolCalls.add(event.item.call_id);\n return {\n id: this.#responseId,\n delta: {\n role: 'assistant',\n content: undefined,\n toolCalls: [\n llm.FunctionCall.create({\n callId: event.item.call_id,\n name: event.item.name,\n args: event.item.arguments,\n }),\n ],\n },\n };\n }\n return undefined;\n }\n\n #handleOutputTextDelta(event: WsOutputTextDeltaEvent): llm.ChatChunk {\n return {\n id: this.#responseId,\n delta: {\n role: 'assistant',\n content: event.delta,\n },\n };\n }\n\n #handleResponseCompleted(event: WsResponseCompletedEvent): llm.ChatChunk | undefined {\n this.#llm._setPendingToolCalls(this.#pendingToolCalls);\n\n if (event.response.usage) {\n return {\n id: this.#responseId,\n usage: {\n completionTokens: event.response.usage.output_tokens,\n promptTokens: event.response.usage.input_tokens,\n promptCachedTokens: event.response.usage.input_tokens_details.cached_tokens,\n totalTokens: event.response.usage.total_tokens,\n serviceTier: event.response.service_tier ?? undefined,\n },\n };\n }\n return undefined;\n }\n\n #handleResponseFailed(event: WsResponseFailedEvent): void {\n throw new APIStatusError({\n message: event.response?.error?.message ?? 'Response failed',\n options: { statusCode: -1, retryable: false },\n });\n }\n}\n\n// ============================================================================\n// Internal helpers\n// ============================================================================\n\nasync function connectWs(url: string, apiKey: string, timeoutMs: number): Promise<WebSocket> {\n return new Promise<WebSocket>((resolve, reject) => {\n const ws = new WebSocket(url, {\n headers: { Authorization: `Bearer ${apiKey}` },\n });\n\n let settled = false;\n\n const timer = setTimeout(() => {\n settled = true;\n ws.close();\n reject(\n new APIConnectionError({ message: 'Timeout connecting to OpenAI Responses WebSocket' }),\n );\n }, timeoutMs);\n\n ws.once('open', () => {\n if (settled) return;\n settled = true;\n clearTimeout(timer);\n resolve(ws);\n });\n\n ws.once('error', (err) => {\n if (settled) return;\n settled = true;\n clearTimeout(timer);\n reject(\n new APIConnectionError({\n message: `Error connecting to OpenAI Responses WebSocket: ${err.message}`,\n }),\n );\n });\n\n ws.once('close', (code) => {\n if (settled) return;\n settled = true;\n clearTimeout(timer);\n reject(\n new APIConnectionError({\n message: `OpenAI Responses WebSocket closed unexpectedly during connect (code ${code})`,\n }),\n );\n });\n });\n}\n\nfunction getWebSocketStateLabel(readyState: number): string {\n switch (readyState) {\n case WebSocket.CONNECTING:\n return 'CONNECTING';\n case WebSocket.OPEN:\n return 'OPEN';\n case WebSocket.CLOSING:\n return 'CLOSING';\n case WebSocket.CLOSED:\n return 'CLOSED';\n default:\n return `UNKNOWN:${readyState}`;\n }\n}\n"],"mappings":"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","names":["llm"]}
|
package/dist/ws/types.cjs
CHANGED
|
@@ -73,6 +73,7 @@ const wsResponseCompletedEventSchema = import_zod.z.object({
|
|
|
73
73
|
type: import_zod.z.literal("response.completed"),
|
|
74
74
|
response: import_zod.z.object({
|
|
75
75
|
id: import_zod.z.string(),
|
|
76
|
+
service_tier: import_zod.z.string().nullable().optional(),
|
|
76
77
|
usage: import_zod.z.object({
|
|
77
78
|
output_tokens: import_zod.z.number(),
|
|
78
79
|
input_tokens: import_zod.z.number(),
|
package/dist/ws/types.cjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../src/ws/types.ts"],"sourcesContent":["// SPDX-FileCopyrightText: 2025 LiveKit, Inc.\n//\n// SPDX-License-Identifier: Apache-2.0\nimport { z } from 'zod';\n\n// ============================================================================\n// Client → Server events\n// ============================================================================\n\nexport const wsResponseCreateEventSchema = z\n .object({\n type: z.literal('response.create'),\n model: z.string(),\n input: z.array(z.unknown()),\n tools: z.array(z.unknown()).optional(),\n previous_response_id: z.string().nullable().optional(),\n store: z.boolean().optional(),\n temperature: z.number().optional(),\n metadata: z.record(z.string(), z.string()).optional(),\n })\n .passthrough();\n\nexport type WsResponseCreateEvent = z.infer<typeof wsResponseCreateEventSchema>;\n\n// ============================================================================\n// Server → Client events\n// ============================================================================\n\nexport const wsResponseCreatedEventSchema = z.object({\n type: z.literal('response.created'),\n response: z\n .object({\n id: z.string(),\n })\n .passthrough(),\n});\n\nexport const wsFunctionCallItemSchema = z.object({\n type: z.literal('function_call'),\n call_id: z.string(),\n name: z.string(),\n arguments: z.string(),\n});\n\nexport const wsOutputItemSchema = z.discriminatedUnion('type', [\n wsFunctionCallItemSchema,\n z.object({ type: z.literal('message') }).passthrough(),\n z.object({ type: z.literal('reasoning') }).passthrough(),\n z.object({ type: z.literal('file') }).passthrough(),\n z.object({ type: z.literal('computer_call') }).passthrough(),\n z.object({ type: z.literal('web_search_call') }).passthrough(),\n]);\n\nexport const wsOutputItemDoneEventSchema = z.object({\n type: z.literal('response.output_item.done'),\n item: wsOutputItemSchema,\n});\n\nexport const wsOutputTextDeltaEventSchema = z.object({\n type: z.literal('response.output_text.delta'),\n delta: z.string(),\n});\n\nexport const wsResponseCompletedEventSchema = z.object({\n type: z.literal('response.completed'),\n response: z\n .object({\n id: z.string(),\n usage: z\n .object({\n output_tokens: z.number(),\n input_tokens: z.number(),\n total_tokens: z.number(),\n input_tokens_details: z\n .object({\n cached_tokens: z.number(),\n })\n .passthrough(),\n })\n .optional(),\n })\n .passthrough(),\n});\n\nexport const wsResponseFailedEventSchema = z.object({\n type: z.literal('response.failed'),\n response: z\n .object({\n id: z.string().optional(),\n error: z\n .object({\n code: z.string().optional(),\n message: z.string().optional(),\n })\n .optional(),\n })\n .passthrough(),\n});\n\nexport const wsErrorEventSchema = z.object({\n type: z.literal('error'),\n status: z.number().optional(),\n error: z\n .object({\n type: z.string().optional(),\n code: z.string().optional(),\n message: z.string().optional(),\n param: z.string().optional(),\n })\n .optional(),\n message: z.string().optional(),\n});\n\nexport const wsServerEventSchema = z.discriminatedUnion('type', [\n wsResponseCreatedEventSchema,\n wsOutputItemDoneEventSchema,\n wsOutputTextDeltaEventSchema,\n wsResponseCompletedEventSchema,\n wsResponseFailedEventSchema,\n wsErrorEventSchema,\n]);\n\nexport type WsResponseCreatedEvent = z.infer<typeof wsResponseCreatedEventSchema>;\nexport type WsFunctionCallItem = z.infer<typeof wsFunctionCallItemSchema>;\nexport type WsOutputItem = z.infer<typeof wsOutputItemSchema>;\nexport type WsOutputItemDoneEvent = z.infer<typeof wsOutputItemDoneEventSchema>;\nexport type WsOutputTextDeltaEvent = z.infer<typeof wsOutputTextDeltaEventSchema>;\nexport type WsResponseCompletedEvent = z.infer<typeof wsResponseCompletedEventSchema>;\nexport type WsResponseFailedEvent = z.infer<typeof wsResponseFailedEventSchema>;\nexport type WsErrorEvent = z.infer<typeof wsErrorEventSchema>;\nexport type WsServerEvent = z.infer<typeof wsServerEventSchema>;\n"],"mappings":"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","names":[]}
|
|
1
|
+
{"version":3,"sources":["../../src/ws/types.ts"],"sourcesContent":["// SPDX-FileCopyrightText: 2025 LiveKit, Inc.\n//\n// SPDX-License-Identifier: Apache-2.0\nimport { z } from 'zod';\n\n// ============================================================================\n// Client → Server events\n// ============================================================================\n\nexport const wsResponseCreateEventSchema = z\n .object({\n type: z.literal('response.create'),\n model: z.string(),\n input: z.array(z.unknown()),\n tools: z.array(z.unknown()).optional(),\n previous_response_id: z.string().nullable().optional(),\n store: z.boolean().optional(),\n temperature: z.number().optional(),\n metadata: z.record(z.string(), z.string()).optional(),\n })\n .passthrough();\n\nexport type WsResponseCreateEvent = z.infer<typeof wsResponseCreateEventSchema>;\n\n// ============================================================================\n// Server → Client events\n// ============================================================================\n\nexport const wsResponseCreatedEventSchema = z.object({\n type: z.literal('response.created'),\n response: z\n .object({\n id: z.string(),\n })\n .passthrough(),\n});\n\nexport const wsFunctionCallItemSchema = z.object({\n type: z.literal('function_call'),\n call_id: z.string(),\n name: z.string(),\n arguments: z.string(),\n});\n\nexport const wsOutputItemSchema = z.discriminatedUnion('type', [\n wsFunctionCallItemSchema,\n z.object({ type: z.literal('message') }).passthrough(),\n z.object({ type: z.literal('reasoning') }).passthrough(),\n z.object({ type: z.literal('file') }).passthrough(),\n z.object({ type: z.literal('computer_call') }).passthrough(),\n z.object({ type: z.literal('web_search_call') }).passthrough(),\n]);\n\nexport const wsOutputItemDoneEventSchema = z.object({\n type: z.literal('response.output_item.done'),\n item: wsOutputItemSchema,\n});\n\nexport const wsOutputTextDeltaEventSchema = z.object({\n type: z.literal('response.output_text.delta'),\n delta: z.string(),\n});\n\nexport const wsResponseCompletedEventSchema = z.object({\n type: z.literal('response.completed'),\n response: z\n .object({\n id: z.string(),\n service_tier: z.string().nullable().optional(),\n usage: z\n .object({\n output_tokens: z.number(),\n input_tokens: z.number(),\n total_tokens: z.number(),\n input_tokens_details: z\n .object({\n cached_tokens: z.number(),\n })\n .passthrough(),\n })\n .optional(),\n })\n .passthrough(),\n});\n\nexport const wsResponseFailedEventSchema = z.object({\n type: z.literal('response.failed'),\n response: z\n .object({\n id: z.string().optional(),\n error: z\n .object({\n code: z.string().optional(),\n message: z.string().optional(),\n })\n .optional(),\n })\n .passthrough(),\n});\n\nexport const wsErrorEventSchema = z.object({\n type: z.literal('error'),\n status: z.number().optional(),\n error: z\n .object({\n type: z.string().optional(),\n code: z.string().optional(),\n message: z.string().optional(),\n param: z.string().optional(),\n })\n .optional(),\n message: z.string().optional(),\n});\n\nexport const wsServerEventSchema = z.discriminatedUnion('type', [\n wsResponseCreatedEventSchema,\n wsOutputItemDoneEventSchema,\n wsOutputTextDeltaEventSchema,\n wsResponseCompletedEventSchema,\n wsResponseFailedEventSchema,\n wsErrorEventSchema,\n]);\n\nexport type WsResponseCreatedEvent = z.infer<typeof wsResponseCreatedEventSchema>;\nexport type WsFunctionCallItem = z.infer<typeof wsFunctionCallItemSchema>;\nexport type WsOutputItem = z.infer<typeof wsOutputItemSchema>;\nexport type WsOutputItemDoneEvent = z.infer<typeof wsOutputItemDoneEventSchema>;\nexport type WsOutputTextDeltaEvent = z.infer<typeof wsOutputTextDeltaEventSchema>;\nexport type WsResponseCompletedEvent = z.infer<typeof wsResponseCompletedEventSchema>;\nexport type WsResponseFailedEvent = z.infer<typeof wsResponseFailedEventSchema>;\nexport type WsErrorEvent = z.infer<typeof wsErrorEventSchema>;\nexport type WsServerEvent = z.infer<typeof wsServerEventSchema>;\n"],"mappings":"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","names":[]}
|
package/dist/ws/types.d.cts
CHANGED
|
@@ -65,6 +65,7 @@ export declare const wsResponseCompletedEventSchema: z.ZodObject<{
|
|
|
65
65
|
type: z.ZodLiteral<"response.completed">;
|
|
66
66
|
response: z.ZodObject<{
|
|
67
67
|
id: z.ZodString;
|
|
68
|
+
service_tier: z.ZodOptional<z.ZodNullable<z.ZodString>>;
|
|
68
69
|
usage: z.ZodOptional<z.ZodObject<{
|
|
69
70
|
output_tokens: z.ZodNumber;
|
|
70
71
|
input_tokens: z.ZodNumber;
|
|
@@ -126,6 +127,7 @@ export declare const wsServerEventSchema: z.ZodDiscriminatedUnion<[z.ZodObject<{
|
|
|
126
127
|
type: z.ZodLiteral<"response.completed">;
|
|
127
128
|
response: z.ZodObject<{
|
|
128
129
|
id: z.ZodString;
|
|
130
|
+
service_tier: z.ZodOptional<z.ZodNullable<z.ZodString>>;
|
|
129
131
|
usage: z.ZodOptional<z.ZodObject<{
|
|
130
132
|
output_tokens: z.ZodNumber;
|
|
131
133
|
input_tokens: z.ZodNumber;
|
package/dist/ws/types.d.ts
CHANGED
|
@@ -65,6 +65,7 @@ export declare const wsResponseCompletedEventSchema: z.ZodObject<{
|
|
|
65
65
|
type: z.ZodLiteral<"response.completed">;
|
|
66
66
|
response: z.ZodObject<{
|
|
67
67
|
id: z.ZodString;
|
|
68
|
+
service_tier: z.ZodOptional<z.ZodNullable<z.ZodString>>;
|
|
68
69
|
usage: z.ZodOptional<z.ZodObject<{
|
|
69
70
|
output_tokens: z.ZodNumber;
|
|
70
71
|
input_tokens: z.ZodNumber;
|
|
@@ -126,6 +127,7 @@ export declare const wsServerEventSchema: z.ZodDiscriminatedUnion<[z.ZodObject<{
|
|
|
126
127
|
type: z.ZodLiteral<"response.completed">;
|
|
127
128
|
response: z.ZodObject<{
|
|
128
129
|
id: z.ZodString;
|
|
130
|
+
service_tier: z.ZodOptional<z.ZodNullable<z.ZodString>>;
|
|
129
131
|
usage: z.ZodOptional<z.ZodObject<{
|
|
130
132
|
output_tokens: z.ZodNumber;
|
|
131
133
|
input_tokens: z.ZodNumber;
|
package/dist/ws/types.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../src/ws/types.ts"],"names":[],"mappings":"AAGA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAMxB,eAAO,MAAM,2BAA2B;;;;;;;;;iBAWxB,CAAC;AAEjB,MAAM,MAAM,qBAAqB,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,2BAA2B,CAAC,CAAC;AAMhF,eAAO,MAAM,4BAA4B;;;;;iBAOvC,CAAC;AAEH,eAAO,MAAM,wBAAwB;;;;;iBAKnC,CAAC;AAEH,eAAO,MAAM,kBAAkB;;;;;;;;;;;;;;;2BAO7B,CAAC;AAEH,eAAO,MAAM,2BAA2B;;;;;;;;;;;;;;;;;;iBAGtC,CAAC;AAEH,eAAO,MAAM,4BAA4B;;;iBAGvC,CAAC;AAEH,eAAO,MAAM,8BAA8B
|
|
1
|
+
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../src/ws/types.ts"],"names":[],"mappings":"AAGA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAMxB,eAAO,MAAM,2BAA2B;;;;;;;;;iBAWxB,CAAC;AAEjB,MAAM,MAAM,qBAAqB,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,2BAA2B,CAAC,CAAC;AAMhF,eAAO,MAAM,4BAA4B;;;;;iBAOvC,CAAC;AAEH,eAAO,MAAM,wBAAwB;;;;;iBAKnC,CAAC;AAEH,eAAO,MAAM,kBAAkB;;;;;;;;;;;;;;;2BAO7B,CAAC;AAEH,eAAO,MAAM,2BAA2B;;;;;;;;;;;;;;;;;;iBAGtC,CAAC;AAEH,eAAO,MAAM,4BAA4B;;;iBAGvC,CAAC;AAEH,eAAO,MAAM,8BAA8B;;;;;;;;;;;;;;iBAoBzC,CAAC;AAEH,eAAO,MAAM,2BAA2B;;;;;;;;;iBAatC,CAAC;AAEH,eAAO,MAAM,kBAAkB;;;;;;;;;;iBAY7B,CAAC;AAEH,eAAO,MAAM,mBAAmB;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;2BAO9B,CAAC;AAEH,MAAM,MAAM,sBAAsB,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,4BAA4B,CAAC,CAAC;AAClF,MAAM,MAAM,kBAAkB,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,wBAAwB,CAAC,CAAC;AAC1E,MAAM,MAAM,YAAY,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,kBAAkB,CAAC,CAAC;AAC9D,MAAM,MAAM,qBAAqB,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,2BAA2B,CAAC,CAAC;AAChF,MAAM,MAAM,sBAAsB,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,4BAA4B,CAAC,CAAC;AAClF,MAAM,MAAM,wBAAwB,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,8BAA8B,CAAC,CAAC;AACtF,MAAM,MAAM,qBAAqB,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,2BAA2B,CAAC,CAAC;AAChF,MAAM,MAAM,YAAY,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,kBAAkB,CAAC,CAAC;AAC9D,MAAM,MAAM,aAAa,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,mBAAmB,CAAC,CAAC"}
|
package/dist/ws/types.js
CHANGED
|
@@ -41,6 +41,7 @@ const wsResponseCompletedEventSchema = z.object({
|
|
|
41
41
|
type: z.literal("response.completed"),
|
|
42
42
|
response: z.object({
|
|
43
43
|
id: z.string(),
|
|
44
|
+
service_tier: z.string().nullable().optional(),
|
|
44
45
|
usage: z.object({
|
|
45
46
|
output_tokens: z.number(),
|
|
46
47
|
input_tokens: z.number(),
|
package/dist/ws/types.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../src/ws/types.ts"],"sourcesContent":["// SPDX-FileCopyrightText: 2025 LiveKit, Inc.\n//\n// SPDX-License-Identifier: Apache-2.0\nimport { z } from 'zod';\n\n// ============================================================================\n// Client → Server events\n// ============================================================================\n\nexport const wsResponseCreateEventSchema = z\n .object({\n type: z.literal('response.create'),\n model: z.string(),\n input: z.array(z.unknown()),\n tools: z.array(z.unknown()).optional(),\n previous_response_id: z.string().nullable().optional(),\n store: z.boolean().optional(),\n temperature: z.number().optional(),\n metadata: z.record(z.string(), z.string()).optional(),\n })\n .passthrough();\n\nexport type WsResponseCreateEvent = z.infer<typeof wsResponseCreateEventSchema>;\n\n// ============================================================================\n// Server → Client events\n// ============================================================================\n\nexport const wsResponseCreatedEventSchema = z.object({\n type: z.literal('response.created'),\n response: z\n .object({\n id: z.string(),\n })\n .passthrough(),\n});\n\nexport const wsFunctionCallItemSchema = z.object({\n type: z.literal('function_call'),\n call_id: z.string(),\n name: z.string(),\n arguments: z.string(),\n});\n\nexport const wsOutputItemSchema = z.discriminatedUnion('type', [\n wsFunctionCallItemSchema,\n z.object({ type: z.literal('message') }).passthrough(),\n z.object({ type: z.literal('reasoning') }).passthrough(),\n z.object({ type: z.literal('file') }).passthrough(),\n z.object({ type: z.literal('computer_call') }).passthrough(),\n z.object({ type: z.literal('web_search_call') }).passthrough(),\n]);\n\nexport const wsOutputItemDoneEventSchema = z.object({\n type: z.literal('response.output_item.done'),\n item: wsOutputItemSchema,\n});\n\nexport const wsOutputTextDeltaEventSchema = z.object({\n type: z.literal('response.output_text.delta'),\n delta: z.string(),\n});\n\nexport const wsResponseCompletedEventSchema = z.object({\n type: z.literal('response.completed'),\n response: z\n .object({\n id: z.string(),\n usage: z\n .object({\n output_tokens: z.number(),\n input_tokens: z.number(),\n total_tokens: z.number(),\n input_tokens_details: z\n .object({\n cached_tokens: z.number(),\n })\n .passthrough(),\n })\n .optional(),\n })\n .passthrough(),\n});\n\nexport const wsResponseFailedEventSchema = z.object({\n type: z.literal('response.failed'),\n response: z\n .object({\n id: z.string().optional(),\n error: z\n .object({\n code: z.string().optional(),\n message: z.string().optional(),\n })\n .optional(),\n })\n .passthrough(),\n});\n\nexport const wsErrorEventSchema = z.object({\n type: z.literal('error'),\n status: z.number().optional(),\n error: z\n .object({\n type: z.string().optional(),\n code: z.string().optional(),\n message: z.string().optional(),\n param: z.string().optional(),\n })\n .optional(),\n message: z.string().optional(),\n});\n\nexport const wsServerEventSchema = z.discriminatedUnion('type', [\n wsResponseCreatedEventSchema,\n wsOutputItemDoneEventSchema,\n wsOutputTextDeltaEventSchema,\n wsResponseCompletedEventSchema,\n wsResponseFailedEventSchema,\n wsErrorEventSchema,\n]);\n\nexport type WsResponseCreatedEvent = z.infer<typeof wsResponseCreatedEventSchema>;\nexport type WsFunctionCallItem = z.infer<typeof wsFunctionCallItemSchema>;\nexport type WsOutputItem = z.infer<typeof wsOutputItemSchema>;\nexport type WsOutputItemDoneEvent = z.infer<typeof wsOutputItemDoneEventSchema>;\nexport type WsOutputTextDeltaEvent = z.infer<typeof wsOutputTextDeltaEventSchema>;\nexport type WsResponseCompletedEvent = z.infer<typeof wsResponseCompletedEventSchema>;\nexport type WsResponseFailedEvent = z.infer<typeof wsResponseFailedEventSchema>;\nexport type WsErrorEvent = z.infer<typeof wsErrorEventSchema>;\nexport type WsServerEvent = z.infer<typeof wsServerEventSchema>;\n"],"mappings":"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","names":[]}
|
|
1
|
+
{"version":3,"sources":["../../src/ws/types.ts"],"sourcesContent":["// SPDX-FileCopyrightText: 2025 LiveKit, Inc.\n//\n// SPDX-License-Identifier: Apache-2.0\nimport { z } from 'zod';\n\n// ============================================================================\n// Client → Server events\n// ============================================================================\n\nexport const wsResponseCreateEventSchema = z\n .object({\n type: z.literal('response.create'),\n model: z.string(),\n input: z.array(z.unknown()),\n tools: z.array(z.unknown()).optional(),\n previous_response_id: z.string().nullable().optional(),\n store: z.boolean().optional(),\n temperature: z.number().optional(),\n metadata: z.record(z.string(), z.string()).optional(),\n })\n .passthrough();\n\nexport type WsResponseCreateEvent = z.infer<typeof wsResponseCreateEventSchema>;\n\n// ============================================================================\n// Server → Client events\n// ============================================================================\n\nexport const wsResponseCreatedEventSchema = z.object({\n type: z.literal('response.created'),\n response: z\n .object({\n id: z.string(),\n })\n .passthrough(),\n});\n\nexport const wsFunctionCallItemSchema = z.object({\n type: z.literal('function_call'),\n call_id: z.string(),\n name: z.string(),\n arguments: z.string(),\n});\n\nexport const wsOutputItemSchema = z.discriminatedUnion('type', [\n wsFunctionCallItemSchema,\n z.object({ type: z.literal('message') }).passthrough(),\n z.object({ type: z.literal('reasoning') }).passthrough(),\n z.object({ type: z.literal('file') }).passthrough(),\n z.object({ type: z.literal('computer_call') }).passthrough(),\n z.object({ type: z.literal('web_search_call') }).passthrough(),\n]);\n\nexport const wsOutputItemDoneEventSchema = z.object({\n type: z.literal('response.output_item.done'),\n item: wsOutputItemSchema,\n});\n\nexport const wsOutputTextDeltaEventSchema = z.object({\n type: z.literal('response.output_text.delta'),\n delta: z.string(),\n});\n\nexport const wsResponseCompletedEventSchema = z.object({\n type: z.literal('response.completed'),\n response: z\n .object({\n id: z.string(),\n service_tier: z.string().nullable().optional(),\n usage: z\n .object({\n output_tokens: z.number(),\n input_tokens: z.number(),\n total_tokens: z.number(),\n input_tokens_details: z\n .object({\n cached_tokens: z.number(),\n })\n .passthrough(),\n })\n .optional(),\n })\n .passthrough(),\n});\n\nexport const wsResponseFailedEventSchema = z.object({\n type: z.literal('response.failed'),\n response: z\n .object({\n id: z.string().optional(),\n error: z\n .object({\n code: z.string().optional(),\n message: z.string().optional(),\n })\n .optional(),\n })\n .passthrough(),\n});\n\nexport const wsErrorEventSchema = z.object({\n type: z.literal('error'),\n status: z.number().optional(),\n error: z\n .object({\n type: z.string().optional(),\n code: z.string().optional(),\n message: z.string().optional(),\n param: z.string().optional(),\n })\n .optional(),\n message: z.string().optional(),\n});\n\nexport const wsServerEventSchema = z.discriminatedUnion('type', [\n wsResponseCreatedEventSchema,\n wsOutputItemDoneEventSchema,\n wsOutputTextDeltaEventSchema,\n wsResponseCompletedEventSchema,\n wsResponseFailedEventSchema,\n wsErrorEventSchema,\n]);\n\nexport type WsResponseCreatedEvent = z.infer<typeof wsResponseCreatedEventSchema>;\nexport type WsFunctionCallItem = z.infer<typeof wsFunctionCallItemSchema>;\nexport type WsOutputItem = z.infer<typeof wsOutputItemSchema>;\nexport type WsOutputItemDoneEvent = z.infer<typeof wsOutputItemDoneEventSchema>;\nexport type WsOutputTextDeltaEvent = z.infer<typeof wsOutputTextDeltaEventSchema>;\nexport type WsResponseCompletedEvent = z.infer<typeof wsResponseCompletedEventSchema>;\nexport type WsResponseFailedEvent = z.infer<typeof wsResponseFailedEventSchema>;\nexport type WsErrorEvent = z.infer<typeof wsErrorEventSchema>;\nexport type WsServerEvent = z.infer<typeof wsServerEventSchema>;\n"],"mappings":"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","names":[]}
|