@copilotkit/aimock 1.45.0 → 1.46.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.claude-plugin/marketplace.json +1 -1
- package/.claude-plugin/plugin.json +1 -1
- package/CHANGELOG.md +24 -0
- package/README.md +7 -1
- package/dist/agui-mock.cjs +25 -25
- package/dist/agui-mock.cjs.map +1 -1
- package/dist/agui-mock.d.cts.map +1 -1
- package/dist/agui-mock.d.ts.map +1 -1
- package/dist/agui-mock.js +25 -25
- package/dist/agui-mock.js.map +1 -1
- package/dist/agui-types.d.ts.map +1 -1
- package/dist/aimock-cli.cjs +15 -1
- package/dist/aimock-cli.cjs.map +1 -1
- package/dist/aimock-cli.d.cts.map +1 -1
- package/dist/aimock-cli.d.ts.map +1 -1
- package/dist/aimock-cli.js +16 -2
- package/dist/aimock-cli.js.map +1 -1
- package/dist/api-key-auth.cjs +10 -9
- package/dist/api-key-auth.cjs.map +1 -1
- package/dist/api-key-auth.d.cts.map +1 -1
- package/dist/api-key-auth.d.ts.map +1 -1
- package/dist/api-key-auth.js +11 -10
- package/dist/api-key-auth.js.map +1 -1
- package/dist/batches.cjs +2 -4
- package/dist/batches.cjs.map +1 -1
- package/dist/batches.d.cts.map +1 -1
- package/dist/batches.d.ts.map +1 -1
- package/dist/batches.js +2 -4
- package/dist/batches.js.map +1 -1
- package/dist/bedrock-converse.cjs +61 -80
- package/dist/bedrock-converse.cjs.map +1 -1
- package/dist/bedrock-converse.d.cts.map +1 -1
- package/dist/bedrock-converse.d.ts.map +1 -1
- package/dist/bedrock-converse.js +58 -77
- package/dist/bedrock-converse.js.map +1 -1
- package/dist/bedrock.cjs +65 -97
- package/dist/bedrock.cjs.map +1 -1
- package/dist/bedrock.d.cts.map +1 -1
- package/dist/bedrock.d.ts.map +1 -1
- package/dist/bedrock.js +62 -94
- package/dist/bedrock.js.map +1 -1
- package/dist/byteplus-video.cjs +11 -10
- package/dist/byteplus-video.cjs.map +1 -1
- package/dist/byteplus-video.d.cts.map +1 -1
- package/dist/byteplus-video.d.ts.map +1 -1
- package/dist/byteplus-video.js +5 -4
- package/dist/byteplus-video.js.map +1 -1
- package/dist/chaos.cjs +5 -4
- package/dist/chaos.cjs.map +1 -1
- package/dist/chaos.d.cts.map +1 -1
- package/dist/chaos.d.ts.map +1 -1
- package/dist/chaos.js +5 -4
- package/dist/chaos.js.map +1 -1
- package/dist/cli.cjs +15 -0
- package/dist/cli.cjs.map +1 -1
- package/dist/cli.js +15 -0
- package/dist/cli.js.map +1 -1
- package/dist/cohere.cjs +49 -74
- package/dist/cohere.cjs.map +1 -1
- package/dist/cohere.d.cts.map +1 -1
- package/dist/cohere.d.ts.map +1 -1
- package/dist/cohere.js +47 -72
- package/dist/cohere.js.map +1 -1
- package/dist/config-loader.cjs +29 -1
- package/dist/config-loader.cjs.map +1 -1
- package/dist/config-loader.d.cts +7 -1
- package/dist/config-loader.d.cts.map +1 -1
- package/dist/config-loader.d.ts +7 -1
- package/dist/config-loader.d.ts.map +1 -1
- package/dist/config-loader.js +29 -2
- package/dist/config-loader.js.map +1 -1
- package/dist/count-tokens.cjs +146 -0
- package/dist/count-tokens.cjs.map +1 -0
- package/dist/count-tokens.js +146 -0
- package/dist/count-tokens.js.map +1 -0
- package/dist/elevenlabs-audio.cjs +36 -34
- package/dist/elevenlabs-audio.cjs.map +1 -1
- package/dist/elevenlabs-audio.d.cts.map +1 -1
- package/dist/elevenlabs-audio.d.ts.map +1 -1
- package/dist/elevenlabs-audio.js +33 -31
- package/dist/elevenlabs-audio.js.map +1 -1
- package/dist/elevenlabs-voice.cjs +38 -37
- package/dist/elevenlabs-voice.cjs.map +1 -1
- package/dist/elevenlabs-voice.d.cts.map +1 -1
- package/dist/elevenlabs-voice.d.ts.map +1 -1
- package/dist/elevenlabs-voice.js +33 -32
- package/dist/elevenlabs-voice.js.map +1 -1
- package/dist/embedding-request.cjs +16 -0
- package/dist/embedding-request.cjs.map +1 -0
- package/dist/embedding-request.js +14 -0
- package/dist/embedding-request.js.map +1 -0
- package/dist/embeddings.cjs +30 -20
- package/dist/embeddings.cjs.map +1 -1
- package/dist/embeddings.d.cts.map +1 -1
- package/dist/embeddings.d.ts.map +1 -1
- package/dist/embeddings.js +30 -20
- package/dist/embeddings.js.map +1 -1
- package/dist/fal-audio.cjs +45 -43
- package/dist/fal-audio.cjs.map +1 -1
- package/dist/fal-audio.d.cts.map +1 -1
- package/dist/fal-audio.d.ts.map +1 -1
- package/dist/fal-audio.js +42 -40
- package/dist/fal-audio.js.map +1 -1
- package/dist/fal.cjs +17 -15
- package/dist/fal.cjs.map +1 -1
- package/dist/fal.js +16 -14
- package/dist/fal.js.map +1 -1
- package/dist/files.cjs +2 -4
- package/dist/files.cjs.map +1 -1
- package/dist/files.d.cts.map +1 -1
- package/dist/files.d.ts.map +1 -1
- package/dist/files.js +2 -4
- package/dist/files.js.map +1 -1
- package/dist/fine-tuning.cjs +2 -4
- package/dist/fine-tuning.cjs.map +1 -1
- package/dist/fine-tuning.d.cts.map +1 -1
- package/dist/fine-tuning.d.ts.map +1 -1
- package/dist/fine-tuning.js +2 -4
- package/dist/fine-tuning.js.map +1 -1
- package/dist/fixture-loader.cjs +37 -42
- package/dist/fixture-loader.cjs.map +1 -1
- package/dist/fixture-loader.d.cts.map +1 -1
- package/dist/fixture-loader.d.ts.map +1 -1
- package/dist/fixture-loader.js +37 -42
- package/dist/fixture-loader.js.map +1 -1
- package/dist/gemini-embeddings.cjs +26 -24
- package/dist/gemini-embeddings.cjs.map +1 -1
- package/dist/gemini-embeddings.js +26 -24
- package/dist/gemini-embeddings.js.map +1 -1
- package/dist/gemini-interactions.cjs +50 -35
- package/dist/gemini-interactions.cjs.map +1 -1
- package/dist/gemini-interactions.d.cts +0 -1
- package/dist/gemini-interactions.d.cts.map +1 -1
- package/dist/gemini-interactions.d.ts +0 -1
- package/dist/gemini-interactions.d.ts.map +1 -1
- package/dist/gemini-interactions.js +49 -34
- package/dist/gemini-interactions.js.map +1 -1
- package/dist/gemini.cjs +57 -67
- package/dist/gemini.cjs.map +1 -1
- package/dist/gemini.d.cts.map +1 -1
- package/dist/gemini.d.ts.map +1 -1
- package/dist/gemini.js +56 -67
- package/dist/gemini.js.map +1 -1
- package/dist/grok-video.cjs +14 -12
- package/dist/grok-video.cjs.map +1 -1
- package/dist/grok-video.d.cts.map +1 -1
- package/dist/grok-video.d.ts.map +1 -1
- package/dist/grok-video.js +8 -6
- package/dist/grok-video.js.map +1 -1
- package/dist/helpers.cjs +11 -68
- package/dist/helpers.cjs.map +1 -1
- package/dist/helpers.d.cts.map +1 -1
- package/dist/helpers.d.ts.map +1 -1
- package/dist/helpers.js +12 -67
- package/dist/helpers.js.map +1 -1
- package/dist/images.cjs +30 -28
- package/dist/images.cjs.map +1 -1
- package/dist/images.d.cts.map +1 -1
- package/dist/images.d.ts.map +1 -1
- package/dist/images.js +27 -25
- package/dist/images.js.map +1 -1
- package/dist/index.d.cts +2 -2
- package/dist/index.d.ts +2 -2
- package/dist/journal.cjs +3 -1
- package/dist/journal.cjs.map +1 -1
- package/dist/journal.d.cts.map +1 -1
- package/dist/journal.d.ts.map +1 -1
- package/dist/journal.js +2 -1
- package/dist/journal.js.map +1 -1
- package/dist/llmock.cjs +3 -0
- package/dist/llmock.cjs.map +1 -1
- package/dist/llmock.d.cts.map +1 -1
- package/dist/llmock.d.ts.map +1 -1
- package/dist/llmock.js +3 -0
- package/dist/llmock.js.map +1 -1
- package/dist/mcp-fakes.d.cts.map +1 -1
- package/dist/mcp-handler.cjs +14 -4
- package/dist/mcp-handler.cjs.map +1 -1
- package/dist/mcp-handler.js +14 -4
- package/dist/mcp-handler.js.map +1 -1
- package/dist/mcp-recorder.cjs +2 -1
- package/dist/mcp-recorder.cjs.map +1 -1
- package/dist/mcp-recorder.js +3 -2
- package/dist/mcp-recorder.js.map +1 -1
- package/dist/messages.cjs +111 -96
- package/dist/messages.cjs.map +1 -1
- package/dist/messages.d.cts.map +1 -1
- package/dist/messages.d.ts.map +1 -1
- package/dist/messages.js +109 -95
- package/dist/messages.js.map +1 -1
- package/dist/metrics.cjs +5 -2
- package/dist/metrics.cjs.map +1 -1
- package/dist/metrics.d.cts.map +1 -1
- package/dist/metrics.d.ts.map +1 -1
- package/dist/metrics.js +6 -3
- package/dist/metrics.js.map +1 -1
- package/dist/model-utils.cjs +1 -0
- package/dist/model-utils.cjs.map +1 -1
- package/dist/model-utils.js +1 -1
- package/dist/model-utils.js.map +1 -1
- package/dist/moderation.cjs +15 -12
- package/dist/moderation.cjs.map +1 -1
- package/dist/moderation.js +14 -11
- package/dist/moderation.js.map +1 -1
- package/dist/ollama.cjs +128 -68
- package/dist/ollama.cjs.map +1 -1
- package/dist/ollama.d.cts.map +1 -1
- package/dist/ollama.d.ts.map +1 -1
- package/dist/ollama.js +124 -64
- package/dist/ollama.js.map +1 -1
- package/dist/openapi.cjs +323 -3
- package/dist/openapi.cjs.map +1 -1
- package/dist/openapi.d.cts.map +1 -1
- package/dist/openapi.d.ts.map +1 -1
- package/dist/openapi.js +324 -4
- package/dist/openapi.js.map +1 -1
- package/dist/openrouter-chat.cjs +11 -155
- package/dist/openrouter-chat.cjs.map +1 -1
- package/dist/openrouter-chat.js +11 -155
- package/dist/openrouter-chat.js.map +1 -1
- package/dist/openrouter-video.cjs +76 -71
- package/dist/openrouter-video.cjs.map +1 -1
- package/dist/openrouter-video.d.cts.map +1 -1
- package/dist/openrouter-video.d.ts.map +1 -1
- package/dist/openrouter-video.js +63 -58
- package/dist/openrouter-video.js.map +1 -1
- package/dist/recorder.cjs +176 -95
- package/dist/recorder.cjs.map +1 -1
- package/dist/recorder.d.cts.map +1 -1
- package/dist/recorder.d.ts.map +1 -1
- package/dist/recorder.js +176 -95
- package/dist/recorder.js.map +1 -1
- package/dist/rerank.cjs +13 -11
- package/dist/rerank.cjs.map +1 -1
- package/dist/rerank.js +12 -10
- package/dist/rerank.js.map +1 -1
- package/dist/response/catalog/anthropic-page.cjs +39 -0
- package/dist/response/catalog/anthropic-page.cjs.map +1 -0
- package/dist/response/catalog/anthropic-page.js +38 -0
- package/dist/response/catalog/anthropic-page.js.map +1 -0
- package/dist/response/catalog/collect.cjs +61 -0
- package/dist/response/catalog/collect.cjs.map +1 -0
- package/dist/response/catalog/collect.js +59 -0
- package/dist/response/catalog/collect.js.map +1 -0
- package/dist/response/catalog/gemini-page.cjs +25 -0
- package/dist/response/catalog/gemini-page.cjs.map +1 -0
- package/dist/response/catalog/gemini-page.js +24 -0
- package/dist/response/catalog/gemini-page.js.map +1 -0
- package/dist/response/catalog/render.cjs +182 -0
- package/dist/response/catalog/render.cjs.map +1 -0
- package/dist/response/catalog/render.js +171 -0
- package/dist/response/catalog/render.js.map +1 -0
- package/dist/response/errors.cjs +225 -0
- package/dist/response/errors.cjs.map +1 -0
- package/dist/response/errors.js +224 -0
- package/dist/response/errors.js.map +1 -0
- package/dist/response/finish.cjs +39 -0
- package/dist/response/finish.cjs.map +1 -0
- package/dist/response/finish.js +35 -0
- package/dist/response/finish.js.map +1 -0
- package/dist/response/policy.cjs +126 -0
- package/dist/response/policy.cjs.map +1 -0
- package/dist/response/policy.js +120 -0
- package/dist/response/policy.js.map +1 -0
- package/dist/response/profiles.cjs +69 -0
- package/dist/response/profiles.cjs.map +1 -0
- package/dist/response/profiles.js +65 -0
- package/dist/response/profiles.js.map +1 -0
- package/dist/response/usage/codecs/anthropic.cjs +52 -0
- package/dist/response/usage/codecs/anthropic.cjs.map +1 -0
- package/dist/response/usage/codecs/anthropic.js +50 -0
- package/dist/response/usage/codecs/anthropic.js.map +1 -0
- package/dist/response/usage/codecs/cohere.cjs +36 -0
- package/dist/response/usage/codecs/cohere.cjs.map +1 -0
- package/dist/response/usage/codecs/cohere.js +35 -0
- package/dist/response/usage/codecs/cohere.js.map +1 -0
- package/dist/response/usage/codecs/converse.cjs +16 -0
- package/dist/response/usage/codecs/converse.cjs.map +1 -0
- package/dist/response/usage/codecs/converse.js +15 -0
- package/dist/response/usage/codecs/converse.js.map +1 -0
- package/dist/response/usage/codecs/gemini.cjs +31 -0
- package/dist/response/usage/codecs/gemini.cjs.map +1 -0
- package/dist/response/usage/codecs/gemini.js +31 -0
- package/dist/response/usage/codecs/gemini.js.map +1 -0
- package/dist/response/usage/codecs/interactions.cjs +22 -0
- package/dist/response/usage/codecs/interactions.cjs.map +1 -0
- package/dist/response/usage/codecs/interactions.js +21 -0
- package/dist/response/usage/codecs/interactions.js.map +1 -0
- package/dist/response/usage/codecs/ollama.cjs +17 -0
- package/dist/response/usage/codecs/ollama.cjs.map +1 -0
- package/dist/response/usage/codecs/ollama.js +17 -0
- package/dist/response/usage/codecs/ollama.js.map +1 -0
- package/dist/response/usage/codecs/openai.cjs +52 -0
- package/dist/response/usage/codecs/openai.cjs.map +1 -0
- package/dist/response/usage/codecs/openai.js +50 -0
- package/dist/response/usage/codecs/openai.js.map +1 -0
- package/dist/response/usage/codecs/openrouter.cjs +68 -0
- package/dist/response/usage/codecs/openrouter.cjs.map +1 -0
- package/dist/response/usage/codecs/openrouter.js +67 -0
- package/dist/response/usage/codecs/openrouter.js.map +1 -0
- package/dist/response/usage/codecs/realtime.cjs +19 -0
- package/dist/response/usage/codecs/realtime.cjs.map +1 -0
- package/dist/response/usage/codecs/realtime.js +18 -0
- package/dist/response/usage/codecs/realtime.js.map +1 -0
- package/dist/response/usage/codecs/responses.cjs +21 -0
- package/dist/response/usage/codecs/responses.cjs.map +1 -0
- package/dist/response/usage/codecs/responses.js +20 -0
- package/dist/response/usage/codecs/responses.js.map +1 -0
- package/dist/response/usage/estimate.cjs +23 -0
- package/dist/response/usage/estimate.cjs.map +1 -0
- package/dist/response/usage/estimate.js +21 -0
- package/dist/response/usage/estimate.js.map +1 -0
- package/dist/response/usage/fields.cjs +72 -0
- package/dist/response/usage/fields.cjs.map +1 -0
- package/dist/response/usage/fields.js +70 -0
- package/dist/response/usage/fields.js.map +1 -0
- package/dist/response/usage/recording.cjs +52 -0
- package/dist/response/usage/recording.cjs.map +1 -0
- package/dist/response/usage/recording.js +52 -0
- package/dist/response/usage/recording.js.map +1 -0
- package/dist/responses.cjs +45 -58
- package/dist/responses.cjs.map +1 -1
- package/dist/responses.d.cts.map +1 -1
- package/dist/responses.d.ts.map +1 -1
- package/dist/responses.js +44 -57
- package/dist/responses.js.map +1 -1
- package/dist/route-registry.cjs +45 -0
- package/dist/route-registry.cjs.map +1 -1
- package/dist/route-registry.d.cts.map +1 -1
- package/dist/route-registry.d.ts.map +1 -1
- package/dist/route-registry.js +41 -1
- package/dist/route-registry.js.map +1 -1
- package/dist/router.cjs +4 -0
- package/dist/router.cjs.map +1 -1
- package/dist/router.d.cts.map +1 -1
- package/dist/router.d.ts.map +1 -1
- package/dist/router.js +3 -0
- package/dist/router.js.map +1 -1
- package/dist/search.cjs +13 -11
- package/dist/search.cjs.map +1 -1
- package/dist/search.js +12 -10
- package/dist/search.js.map +1 -1
- package/dist/server.cjs +222 -146
- package/dist/server.cjs.map +1 -1
- package/dist/server.d.cts.map +1 -1
- package/dist/server.d.ts.map +1 -1
- package/dist/server.js +223 -147
- package/dist/server.js.map +1 -1
- package/dist/speech.cjs +20 -18
- package/dist/speech.cjs.map +1 -1
- package/dist/speech.d.cts.map +1 -1
- package/dist/speech.d.ts.map +1 -1
- package/dist/speech.js +19 -17
- package/dist/speech.js.map +1 -1
- package/dist/sse-writer.cjs +7 -0
- package/dist/sse-writer.cjs.map +1 -1
- package/dist/sse-writer.d.cts.map +1 -1
- package/dist/sse-writer.d.ts.map +1 -1
- package/dist/sse-writer.js +7 -1
- package/dist/sse-writer.js.map +1 -1
- package/dist/stream-collapse.cjs +118 -11
- package/dist/stream-collapse.cjs.map +1 -1
- package/dist/stream-collapse.d.cts +10 -9
- package/dist/stream-collapse.d.cts.map +1 -1
- package/dist/stream-collapse.d.ts +10 -9
- package/dist/stream-collapse.d.ts.map +1 -1
- package/dist/stream-collapse.js +118 -11
- package/dist/stream-collapse.js.map +1 -1
- package/dist/transcription.cjs +12 -10
- package/dist/transcription.cjs.map +1 -1
- package/dist/transcription.d.cts.map +1 -1
- package/dist/transcription.d.ts.map +1 -1
- package/dist/transcription.js +11 -9
- package/dist/transcription.js.map +1 -1
- package/dist/types.cjs.map +1 -1
- package/dist/types.d.cts +62 -3
- package/dist/types.d.cts.map +1 -1
- package/dist/types.d.ts +62 -3
- package/dist/types.d.ts.map +1 -1
- package/dist/types.js.map +1 -1
- package/dist/vector-mock.cjs +3 -8
- package/dist/vector-mock.cjs.map +1 -1
- package/dist/vector-mock.d.cts.map +1 -1
- package/dist/vector-mock.d.ts.map +1 -1
- package/dist/vector-mock.js +3 -8
- package/dist/vector-mock.js.map +1 -1
- package/dist/vector-stores.cjs +2 -4
- package/dist/vector-stores.cjs.map +1 -1
- package/dist/vector-stores.d.cts.map +1 -1
- package/dist/vector-stores.d.ts.map +1 -1
- package/dist/vector-stores.js +2 -4
- package/dist/vector-stores.js.map +1 -1
- package/dist/veo-video.cjs +16 -14
- package/dist/veo-video.cjs.map +1 -1
- package/dist/veo-video.js +10 -8
- package/dist/veo-video.js.map +1 -1
- package/dist/video.cjs +21 -19
- package/dist/video.cjs.map +1 -1
- package/dist/video.d.cts.map +1 -1
- package/dist/video.d.ts.map +1 -1
- package/dist/video.js +20 -18
- package/dist/video.js.map +1 -1
- package/dist/ws-gemini-live.cjs +11 -3
- package/dist/ws-gemini-live.cjs.map +1 -1
- package/dist/ws-gemini-live.d.cts +0 -1
- package/dist/ws-gemini-live.d.cts.map +1 -1
- package/dist/ws-gemini-live.d.ts +0 -1
- package/dist/ws-gemini-live.d.ts.map +1 -1
- package/dist/ws-gemini-live.js +10 -2
- package/dist/ws-gemini-live.js.map +1 -1
- package/dist/ws-live.cjs +6 -5
- package/dist/ws-live.cjs.map +1 -1
- package/dist/ws-live.js +5 -4
- package/dist/ws-live.js.map +1 -1
- package/dist/ws-realtime.cjs +28 -54
- package/dist/ws-realtime.cjs.map +1 -1
- package/dist/ws-realtime.d.cts.map +1 -1
- package/dist/ws-realtime.d.ts.map +1 -1
- package/dist/ws-realtime.js +25 -51
- package/dist/ws-realtime.js.map +1 -1
- package/dist/ws-responses.cjs +8 -6
- package/dist/ws-responses.cjs.map +1 -1
- package/dist/ws-responses.js +7 -5
- package/dist/ws-responses.js.map +1 -1
- package/package.json +4 -1
- package/skills/write-fixtures/SKILL.md +25 -16
package/dist/ws-live.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"ws-live.js","names":[],"sources":["../src/ws-live.ts"],"sourcesContent":["import { performance } from \"node:perf_hooks\";\nimport type { IncomingHttpHeaders } from \"node:http\";\nimport {\n flattenHeaders,\n isLiveResponse,\n resolveResponse,\n resolveStrictMode,\n strictNoMatchLogLine,\n strictNoMatchMessage,\n strictOverrideField,\n wouldProxyMiss,\n} from \"./helpers.js\";\nimport { normalizeLiveFixture, validateLiveClientEvent } from \"./live-fixture.js\";\nimport { createLiveRecorder, LiveRecorderError } from \"./live-recorder.js\";\nimport { applyProviderAuth } from \"./provider-auth.js\";\nimport { connectUpstreamWebSocket } from \"./ws-upstream.js\";\nimport { resolveUpstreamUrl } from \"./url.js\";\nimport {\n clampTimeout,\n DEFAULT_MAX_PROXY_BUFFER_BYTES,\n DEFAULT_MAX_PROXY_BUFFER_FRAMES,\n} from \"./recorder.js\";\nimport { createLiveReplay } from \"./live-replay.js\";\nimport type {\n LiveFailureCategory,\n LiveJson,\n LiveMode,\n LiveObject,\n LiveOptions,\n} from \"./live-types.js\";\nimport type { Journal } from \"./journal.js\";\nimport { matchFixtureDiagnostic } from \"./router.js\";\nimport type {\n ChatCompletionRequest,\n Fixture,\n FixtureResponse,\n HandlerDefaults,\n JournalEntry,\n} from \"./types.js\";\nimport type { WebSocketConnection } from \"./ws-framing.js\";\n\nexport interface LiveSessionOptions {\n defaults: HandlerDefaults;\n limits: Required<LiveOptions>;\n testId: string;\n headers: IncomingHttpHeaders;\n localApiKeys?: readonly string[];\n onDispose: () => void;\n}\nfunction object(value: LiveJson | undefined): LiveObject | undefined {\n return value !== null && typeof value === \"object\" && !Array.isArray(value) ? value : undefined;\n}\n\n/** Node otherwise turns an overflowing delay into a one-millisecond timeout. */\nfunction scheduleLiveTimeout(callback: () => void, timeoutMs: number): () => void {\n const started = performance.now();\n const onTimeout = () => {\n const remaining = timeoutMs - (performance.now() - started);\n if (remaining > 0) timer = setTimeout(onTimeout, Math.min(remaining, 2_147_483_647));\n else callback();\n };\n let timer = setTimeout(onTimeout, Math.min(timeoutMs, 2_147_483_647));\n return () => clearTimeout(timer);\n}\n\n/** Diagnostic copies never retain executable members or mutate replay operands. */\nfunction liveJournalSnapshot(\n entry: Omit<JournalEntry, \"id\" | \"timestamp\">,\n secretValues: readonly string[],\n): Omit<JournalEntry, \"id\" | \"timestamp\"> {\n const secrets = secretValues.filter((secret) => secret.length > 0);\n if (!secrets.length) return entry;\n const containsSecret = (value: string) => secrets.some((secret) => value.includes(secret));\n // Whole-field redaction avoids creating another secret by joining substrings.\n const marker = containsSecret(\"[REDACTED]\") ? \"\" : \"[REDACTED]\";\n const redact = (value: string) => (containsSecret(value) ? marker : value);\n const ancestors = new Set<object>();\n const copy = (value: unknown): unknown => {\n if (typeof value === \"string\") return redact(value);\n if (typeof value === \"function\" || typeof value === \"symbol\") return undefined;\n if (value === null || typeof value !== \"object\") return value;\n if (ancestors.has(value)) return undefined;\n ancestors.add(value);\n try {\n if (Array.isArray(value)) return value.map(copy);\n // Diagnostics contain data only; omit getters and non-JSON objects.\n if (\n Object.getPrototypeOf(value) !== Object.prototype &&\n Object.getPrototypeOf(value) !== null\n )\n return undefined;\n return Object.fromEntries(\n Object.entries(Object.getOwnPropertyDescriptors(value))\n .filter(([, descriptor]) => descriptor.enumerable && \"value\" in descriptor)\n .map(([key, descriptor]) => [redact(key), copy(descriptor.value)]),\n );\n } finally {\n ancestors.delete(value);\n }\n };\n // Preserve the journal schema; copied operands are diagnostics, never replay inputs.\n return {\n ...entry,\n headers: copy(entry.headers) as JournalEntry[\"headers\"],\n body: copy(entry.body) as JournalEntry[\"body\"],\n response: { ...entry.response, fixture: copy(entry.response.fixture) as Fixture | null },\n };\n}\n\n/** Owns a single transport, replay cursor and every cancellation deadline. */\nexport function handleLiveSession(\n ws: WebSocketConnection,\n fixtures: Fixture[],\n journal: Journal,\n options: LiveSessionOptions,\n): () => void {\n const { defaults, limits, testId } = options;\n // HTTP accepts positive finite milliseconds; the connector requires whole safe milliseconds.\n const normalizeRecordTimeout = (value: number | undefined) =>\n Math.min(Number.MAX_SAFE_INTEGER, Math.ceil(clampTimeout(value, 30_000)));\n const upstreamTimeoutMs = normalizeRecordTimeout(defaults.record?.upstreamTimeoutMs);\n const bodyTimeoutMs = normalizeRecordTimeout(defaults.record?.bodyTimeoutMs);\n const controller = new AbortController();\n let state: \"awaiting-start\" | \"active\" | \"closing\" | \"closed\" = \"awaiting-start\";\n let mode: LiveMode | undefined;\n let starting = false;\n const pending: LiveObject[] = [];\n let pendingBytes = 0;\n const maxPendingBytes = Math.min(\n limits.maxBufferedBytes,\n defaults.record?.maxProxyBufferBytes ?? DEFAULT_MAX_PROXY_BUFFER_BYTES,\n );\n const maxPendingFrames = defaults.record?.maxProxyBufferFrames ?? DEFAULT_MAX_PROXY_BUFFER_FRAMES;\n let upstream: WebSocketConnection | undefined;\n let recorder: ReturnType<typeof createLiveRecorder> | undefined;\n let recordingSecrets: string[] = [];\n let terminalReceived = false;\n let captureStarted: number | undefined;\n let recordingJournaled = false;\n let upstreamIdle: (() => void) | undefined;\n let replay: ReturnType<typeof createLiveReplay> | undefined;\n const deadline = scheduleLiveTimeout(\n () => fail(\"timeout\", \"Live session duration exceeded\"),\n limits.maxDurationMs,\n );\n const startup = scheduleLiveTimeout(\n () => fail(\"timeout\", \"Live startup deadline exceeded\"),\n defaults.record ? upstreamTimeoutMs : limits.idleTimeoutMs,\n );\n\n function recordJournal(category?: LiveFailureCategory) {\n if (recordingJournaled || !recorder) return;\n recordingJournaled = true;\n journal.add(\n liveJournalSnapshot(\n {\n method: \"WS\",\n path: \"/v1/live/sessions\",\n headers: { \"x-test-id\": testId },\n body: { model: \"gpt-live-1\", messages: [] },\n response: {\n status: category ? 502 : 200,\n fixture: null,\n source: \"proxy\",\n ...strictOverrideField(defaults.strict, options.headers),\n ...(category ? { error: category } : {}),\n },\n },\n [...limits.secretValues, ...recordingSecrets],\n ),\n );\n }\n function cleanup() {\n if (state === \"closed\") return;\n state = \"closed\";\n deadline();\n startup();\n upstreamIdle?.();\n recordJournal(\"incomplete-capture\");\n recorder?.abort();\n upstream?.destroy();\n pending.length = 0;\n pendingBytes = 0;\n replay?.close();\n controller.abort();\n ws.removeListener(\"message\", receive);\n ws.removeListener(\"close\", cleanup);\n ws.removeListener(\"error\", cleanup);\n options.onDispose();\n }\n function dispose() {\n if (state === \"closed\") return;\n ws.close(1001, \"Live session disposed\");\n cleanup();\n }\n function fail(category: LiveFailureCategory, message: string) {\n if (state === \"closed\" || state === \"closing\") return;\n state = \"closing\";\n recorder?.abort(category);\n recordJournal(category);\n // The safe diagnostic contains no caller payload, fixture data or credential.\n ws.send(JSON.stringify({ type: \"aimock.error\", error: { category, message } }));\n ws.close(category === \"resource-limit\" ? 1009 : 1008, \"Live session failed\");\n cleanup();\n }\n function receive(data: string) {\n if (state === \"closed\" || state === \"closing\") return;\n let event: LiveObject;\n try {\n event = validateLiveClientEvent(JSON.parse(data), limits);\n } catch {\n fail(\"invalid-client\", \"Invalid Live client command\");\n return;\n }\n if (starting) {\n if (event.type === \"session.start\") {\n fail(\"invalid-client\", \"Live session has already started\");\n return;\n }\n const bytes = Buffer.byteLength(data);\n if (bytes > maxPendingBytes - pendingBytes || pending.length >= maxPendingFrames) {\n fail(\"resource-limit\", \"Live startup input queue exceeded\");\n return;\n }\n pendingBytes += bytes;\n pending.push(event);\n return;\n }\n accept(event);\n }\n function recordingError(error: unknown) {\n fail(\n error instanceof LiveRecorderError\n ? error.category\n : error instanceof Error && error.message === \"WebSocket write limit exceeded\"\n ? \"resource-limit\"\n : \"upstream-connect\",\n \"Live recording failed\",\n );\n }\n function touchUpstream() {\n upstreamIdle?.();\n upstreamIdle = scheduleLiveTimeout(\n () => fail(\"timeout\", \"Live upstream idle deadline exceeded\"),\n bodyTimeoutMs,\n );\n }\n function forward(event: LiveObject) {\n if (!upstream || !recorder || terminalReceived) return;\n try {\n const raw = JSON.stringify(event);\n const now = performance.now();\n captureStarted ??= now;\n recorder.acceptClient(raw, Math.floor(now - captureStarted));\n void upstream.sendAsync(raw, controller.signal).catch(recordingError);\n } catch (error) {\n recordingError(error);\n }\n }\n async function startRecording(first: LiveObject) {\n const record = defaults.record;\n if (!record?.providers.openai) {\n fail(\"fixture-mismatch\", \"No matching Live fixture\");\n return;\n }\n starting = true;\n try {\n const base = new URL(record.providers.openai);\n if (base.username || base.password || base.search || base.hash)\n throw new Error(\"Invalid URL\");\n base.pathname = base.pathname.replace(/\\/v1\\/?$/, \"/\");\n const target = resolveUpstreamUrl(base.href, \"/v1/live/sessions\");\n const headers: Record<string, string> = {};\n const incoming = options.headers.authorization;\n const credential = incoming?.match(/^\\s*(?:Bearer|Key)\\s+(.+)$/i)?.[1].trim();\n if (incoming && !options.localApiKeys?.includes(credential ?? \"\"))\n headers.Authorization = incoming;\n applyProviderAuth(headers, target, \"openai\", record.providerKeys?.openai);\n const selected = headers.Authorization?.replace(/^\\s*(?:Bearer|Key)\\s+/i, \"\").trim();\n recordingSecrets = [...(selected ? [selected] : []), ...(options.localApiKeys ?? [])];\n recorder = createLiveRecorder({\n record,\n fixtures,\n logger: defaults.logger,\n testId,\n live: limits,\n secretValues: recordingSecrets,\n provenance: {\n host: target.host,\n path: \"/v1/live/sessions\",\n observedAt: new Date().toISOString(),\n referenceVersion: \"gpt-live-1-observed-v3\",\n sanitationVersion: 1,\n },\n });\n upstream = await connectUpstreamWebSocket(\n target,\n headers,\n limits,\n controller.signal,\n upstreamTimeoutMs,\n );\n if (controller.signal.aborted) {\n upstream.destroy();\n return;\n }\n upstream.on(\"activity\", touchUpstream);\n upstream.on(\"message\", (raw: string) => {\n if (controller.signal.aborted) return;\n touchUpstream();\n try {\n // Capture at provider arrival, before downstream backpressure settles.\n recorder!.acceptServer(\n raw,\n captureStarted === undefined ? 0 : Math.floor(performance.now() - captureStarted),\n );\n const output: unknown = JSON.parse(raw);\n if (!output || typeof output !== \"object\" || !(\"type\" in output))\n throw new Error(\"Invalid event\");\n if (output.type === \"session.started\") {\n startup();\n starting = false;\n state = \"active\";\n const queued = pending.splice(0);\n pendingBytes = 0;\n for (const event of queued) {\n if (controller.signal.aborted) break;\n accept(event);\n }\n }\n const terminal = output.type === \"session.closed\";\n if (terminal) terminalReceived = true;\n void ws.sendAsync(raw, controller.signal).then(() => {\n if (!terminal || controller.signal.aborted) return;\n const result = recorder!.finish();\n if (result.kind === \"failed\") {\n fail(result.category, \"Live capture export failed\");\n return;\n }\n recordJournal();\n ws.close(1000, \"Live session complete\");\n cleanup();\n }, recordingError);\n } catch (error) {\n recordingError(error);\n }\n });\n upstream.on(\"error\", () => fail(\"upstream-connect\", \"Live upstream connection failed\"));\n upstream.on(\"close\", (code: number) => {\n if (!terminalReceived)\n fail(\n code === 1009 ? \"resource-limit\" : \"incomplete-capture\",\n \"Live upstream closed before completion\",\n );\n });\n touchUpstream();\n // Only startup is forwarded until the provider acknowledges the session.\n // The bounded queue retains commands that the caller pipelined meanwhile.\n forward(first);\n } catch (error) {\n const message = error instanceof Error ? error.message : \"\";\n if (/HTTP 401/.test(message)) fail(\"upstream-auth\", \"Live upstream authentication refused\");\n else if (/HTTP (403|404|429)/.test(message))\n fail(\"upstream-access\", \"Live upstream access refused\");\n else recordingError(error);\n }\n }\n function startReplay(\n fixture: Fixture,\n request: ChatCompletionRequest,\n first: LiveObject,\n raw: FixtureResponse,\n ) {\n if (state === \"closed\" || state === \"closing\") return;\n try {\n if (!isLiveResponse(raw)) throw new Error(\"not a Live fixture\");\n const response = normalizeLiveFixture(raw, limits);\n replay = createLiveReplay(response.live, {\n limits,\n signal: controller.signal,\n timing: response.liveTiming ?? \"recorded\",\n replaySpeed: fixture.replaySpeed ?? defaults.replaySpeed,\n fail,\n send: async (output) => {\n await ws.sendAsync(JSON.stringify(output), controller.signal);\n if (output.type === \"session.closed\" && !controller.signal.aborted) {\n ws.close(1000, \"Live session complete\");\n cleanup();\n }\n },\n });\n } catch {\n fail(\"protocol-divergence\", \"Invalid Live replay configuration\");\n return;\n }\n journal.add(\n liveJournalSnapshot(\n {\n method: \"WS\",\n path: \"/v1/live/sessions\",\n headers: { ...flattenHeaders(options.headers), \"x-test-id\": testId },\n body: request,\n response: { status: 200, fixture },\n },\n limits.secretValues,\n ),\n fixture,\n );\n startup();\n starting = false;\n state = \"active\";\n replay.accept(first);\n const queued = pending.splice(0);\n pendingBytes = 0;\n for (const event of queued) {\n if (controller.signal.aborted) break;\n accept(event);\n }\n }\n function accept(event: LiveObject) {\n if (state === \"closed\" || state === \"closing\") return;\n if (state === \"awaiting-start\") {\n const session = object(event.session);\n const audio = object(session?.audio);\n const format = object(audio?.format);\n const delegation = object(session?.delegation);\n if (\n event.type !== \"session.start\" ||\n session?.model !== \"gpt-live-1\" ||\n format?.type !== \"audio/pcm\" ||\n format.rate !== 24000 ||\n (delegation?.type !== \"client\" && delegation?.type !== \"responses\")\n ) {\n fail(\n \"invalid-client\",\n \"Live requires session.start with explicit model, PCM24 audio and delegation\",\n );\n return;\n }\n mode = delegation.type === \"client\" ? \"client\" : \"managed\";\n const request: ChatCompletionRequest = {\n model: session.model,\n messages: [],\n _endpointType: \"openai-live\",\n session: structuredClone(session),\n };\n let fixture: Fixture | null;\n let skippedBySequenceOrTurn: number;\n try {\n ({ fixture, skippedBySequenceOrTurn } = matchFixtureDiagnostic(\n fixtures,\n request,\n journal.getFixtureMatchCountsForTest(testId),\n defaults.requestTransform,\n ));\n } catch {\n fail(\"protocol-divergence\", \"Live fixture selection failed\");\n return;\n }\n if (!fixture) {\n const strict = resolveStrictMode(defaults.strict, options.headers);\n if (strict) {\n const message = strictNoMatchMessage(skippedBySequenceOrTurn);\n defaults.logger.error(\n strictNoMatchLogLine(\"WS\", \"/v1/live/sessions\", skippedBySequenceOrTurn),\n );\n // A rejected startup is diagnostic only: retain test ownership, never\n // caller authorization or session content, and do not create a recorder.\n journal.add(\n liveJournalSnapshot(\n {\n method: \"WS\",\n path: \"/v1/live/sessions\",\n headers: { \"x-test-id\": testId },\n body: { model: request.model, messages: [] },\n response: {\n status: 503,\n fixture: null,\n ...strictOverrideField(defaults.strict, options.headers),\n },\n },\n limits.secretValues,\n ),\n );\n fail(\"fixture-mismatch\", message);\n } else if (wouldProxyMiss(strict, defaults.record, \"openai\")) {\n void startRecording(event);\n } else {\n fail(\"fixture-mismatch\", \"No matching Live fixture\");\n }\n return;\n }\n journal.incrementFixtureMatchCount(fixture, fixtures, testId);\n if (typeof fixture.response === \"function\") {\n starting = true;\n const selected = fixture;\n void resolveResponse(selected, request).then(\n (response) => startReplay(selected, request, event, response),\n () => fail(\"protocol-divergence\", \"Live response factory failed\"),\n );\n } else startReplay(fixture, request, event, fixture.response);\n return;\n } else if (event.type === \"session.start\") {\n fail(\"invalid-client\", \"Live session has already started\");\n return;\n }\n if (event.type === \"session.update\") {\n const patch = object(event.session);\n const delegation = object(patch?.delegation);\n const backend = object(delegation?.responses);\n if (\n mode !== \"managed\" ||\n !patch ||\n !delegation ||\n !backend ||\n Object.keys(patch).some((key) => key !== \"delegation\") ||\n Object.keys(delegation).some((key) => key !== \"type\" && key !== \"responses\") ||\n (delegation.type !== undefined && delegation.type !== \"responses\") ||\n Object.keys(backend).some((key) => key !== \"instructions\") ||\n !Object.hasOwn(backend, \"instructions\")\n ) {\n fail(\"invalid-client\", \"Only managed backend instructions can be updated\");\n return;\n }\n }\n // Input acceptance is synchronous; output pressure never serializes duplex input.\n if (upstream) forward(event);\n else replay?.accept(event);\n }\n ws.on(\"message\", receive);\n ws.on(\"close\", cleanup);\n ws.on(\"error\", cleanup);\n return dispose;\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"ws-live.js","names":[],"sources":["../src/ws-live.ts"],"sourcesContent":["import { performance } from \"node:perf_hooks\";\nimport type { IncomingHttpHeaders } from \"node:http\";\nimport { resolveRequestDecisions, strictOverrideField } from \"./response/policy.js\";\nimport {\n flattenHeaders,\n isLiveResponse,\n resolveResponse,\n strictNoMatchLogLine,\n strictNoMatchMessage,\n wouldProxyMiss,\n} from \"./helpers.js\";\nimport { normalizeLiveFixture, validateLiveClientEvent } from \"./live-fixture.js\";\nimport { createLiveRecorder, LiveRecorderError } from \"./live-recorder.js\";\nimport { applyProviderAuth } from \"./provider-auth.js\";\nimport { connectUpstreamWebSocket } from \"./ws-upstream.js\";\nimport { resolveUpstreamUrl } from \"./url.js\";\nimport {\n clampTimeout,\n DEFAULT_MAX_PROXY_BUFFER_BYTES,\n DEFAULT_MAX_PROXY_BUFFER_FRAMES,\n} from \"./recorder.js\";\nimport { createLiveReplay } from \"./live-replay.js\";\nimport type {\n LiveFailureCategory,\n LiveJson,\n LiveMode,\n LiveObject,\n LiveOptions,\n} from \"./live-types.js\";\nimport type { Journal } from \"./journal.js\";\nimport { matchFixtureDiagnostic } from \"./router.js\";\nimport type {\n ChatCompletionRequest,\n Fixture,\n FixtureResponse,\n HandlerDefaults,\n JournalEntry,\n} from \"./types.js\";\nimport type { WebSocketConnection } from \"./ws-framing.js\";\n\nexport interface LiveSessionOptions {\n defaults: HandlerDefaults;\n limits: Required<LiveOptions>;\n testId: string;\n headers: IncomingHttpHeaders;\n localApiKeys?: readonly string[];\n onDispose: () => void;\n}\nfunction object(value: LiveJson | undefined): LiveObject | undefined {\n return value !== null && typeof value === \"object\" && !Array.isArray(value) ? value : undefined;\n}\n\n/** Node otherwise turns an overflowing delay into a one-millisecond timeout. */\nfunction scheduleLiveTimeout(callback: () => void, timeoutMs: number): () => void {\n const started = performance.now();\n const onTimeout = () => {\n const remaining = timeoutMs - (performance.now() - started);\n if (remaining > 0) timer = setTimeout(onTimeout, Math.min(remaining, 2_147_483_647));\n else callback();\n };\n let timer = setTimeout(onTimeout, Math.min(timeoutMs, 2_147_483_647));\n return () => clearTimeout(timer);\n}\n\n/** Diagnostic copies never retain executable members or mutate replay operands. */\nfunction liveJournalSnapshot(\n entry: Omit<JournalEntry, \"id\" | \"timestamp\">,\n secretValues: readonly string[],\n): Omit<JournalEntry, \"id\" | \"timestamp\"> {\n const secrets = secretValues.filter((secret) => secret.length > 0);\n if (!secrets.length) return entry;\n const containsSecret = (value: string) => secrets.some((secret) => value.includes(secret));\n // Whole-field redaction avoids creating another secret by joining substrings.\n const marker = containsSecret(\"[REDACTED]\") ? \"\" : \"[REDACTED]\";\n const redact = (value: string) => (containsSecret(value) ? marker : value);\n const ancestors = new Set<object>();\n const copy = (value: unknown): unknown => {\n if (typeof value === \"string\") return redact(value);\n if (typeof value === \"function\" || typeof value === \"symbol\") return undefined;\n if (value === null || typeof value !== \"object\") return value;\n if (ancestors.has(value)) return undefined;\n ancestors.add(value);\n try {\n if (Array.isArray(value)) return value.map(copy);\n // Diagnostics contain data only; omit getters and non-JSON objects.\n if (\n Object.getPrototypeOf(value) !== Object.prototype &&\n Object.getPrototypeOf(value) !== null\n )\n return undefined;\n return Object.fromEntries(\n Object.entries(Object.getOwnPropertyDescriptors(value))\n .filter(([, descriptor]) => descriptor.enumerable && \"value\" in descriptor)\n .map(([key, descriptor]) => [redact(key), copy(descriptor.value)]),\n );\n } finally {\n ancestors.delete(value);\n }\n };\n // Preserve the journal schema; copied operands are diagnostics, never replay inputs.\n return {\n ...entry,\n headers: copy(entry.headers) as JournalEntry[\"headers\"],\n body: copy(entry.body) as JournalEntry[\"body\"],\n response: { ...entry.response, fixture: copy(entry.response.fixture) as Fixture | null },\n };\n}\n\n/** Owns a single transport, replay cursor and every cancellation deadline. */\nexport function handleLiveSession(\n ws: WebSocketConnection,\n fixtures: Fixture[],\n journal: Journal,\n options: LiveSessionOptions,\n): () => void {\n const { defaults, limits, testId } = options;\n // HTTP accepts positive finite milliseconds; the connector requires whole safe milliseconds.\n const normalizeRecordTimeout = (value: number | undefined) =>\n Math.min(Number.MAX_SAFE_INTEGER, Math.ceil(clampTimeout(value, 30_000)));\n const upstreamTimeoutMs = normalizeRecordTimeout(defaults.record?.upstreamTimeoutMs);\n const bodyTimeoutMs = normalizeRecordTimeout(defaults.record?.bodyTimeoutMs);\n const controller = new AbortController();\n let state: \"awaiting-start\" | \"active\" | \"closing\" | \"closed\" = \"awaiting-start\";\n let mode: LiveMode | undefined;\n let starting = false;\n const pending: LiveObject[] = [];\n let pendingBytes = 0;\n const maxPendingBytes = Math.min(\n limits.maxBufferedBytes,\n defaults.record?.maxProxyBufferBytes ?? DEFAULT_MAX_PROXY_BUFFER_BYTES,\n );\n const maxPendingFrames = defaults.record?.maxProxyBufferFrames ?? DEFAULT_MAX_PROXY_BUFFER_FRAMES;\n let upstream: WebSocketConnection | undefined;\n let recorder: ReturnType<typeof createLiveRecorder> | undefined;\n let recordingSecrets: string[] = [];\n let terminalReceived = false;\n let captureStarted: number | undefined;\n let recordingJournaled = false;\n let upstreamIdle: (() => void) | undefined;\n let replay: ReturnType<typeof createLiveReplay> | undefined;\n const deadline = scheduleLiveTimeout(\n () => fail(\"timeout\", \"Live session duration exceeded\"),\n limits.maxDurationMs,\n );\n const startup = scheduleLiveTimeout(\n () => fail(\"timeout\", \"Live startup deadline exceeded\"),\n defaults.record ? upstreamTimeoutMs : limits.idleTimeoutMs,\n );\n\n function recordJournal(category?: LiveFailureCategory) {\n if (recordingJournaled || !recorder) return;\n recordingJournaled = true;\n journal.add(\n liveJournalSnapshot(\n {\n method: \"WS\",\n path: \"/v1/live/sessions\",\n headers: { \"x-test-id\": testId },\n body: { model: \"gpt-live-1\", messages: [] },\n response: {\n status: category ? 502 : 200,\n fixture: null,\n source: \"proxy\",\n ...strictOverrideField(defaults.strict, options.headers),\n ...(category ? { error: category } : {}),\n },\n },\n [...limits.secretValues, ...recordingSecrets],\n ),\n );\n }\n function cleanup() {\n if (state === \"closed\") return;\n state = \"closed\";\n deadline();\n startup();\n upstreamIdle?.();\n recordJournal(\"incomplete-capture\");\n recorder?.abort();\n upstream?.destroy();\n pending.length = 0;\n pendingBytes = 0;\n replay?.close();\n controller.abort();\n ws.removeListener(\"message\", receive);\n ws.removeListener(\"close\", cleanup);\n ws.removeListener(\"error\", cleanup);\n options.onDispose();\n }\n function dispose() {\n if (state === \"closed\") return;\n ws.close(1001, \"Live session disposed\");\n cleanup();\n }\n function fail(category: LiveFailureCategory, message: string) {\n if (state === \"closed\" || state === \"closing\") return;\n state = \"closing\";\n recorder?.abort(category);\n recordJournal(category);\n // The safe diagnostic contains no caller payload, fixture data or credential.\n ws.send(JSON.stringify({ type: \"aimock.error\", error: { category, message } }));\n ws.close(category === \"resource-limit\" ? 1009 : 1008, \"Live session failed\");\n cleanup();\n }\n function receive(data: string) {\n if (state === \"closed\" || state === \"closing\") return;\n let event: LiveObject;\n try {\n event = validateLiveClientEvent(JSON.parse(data), limits);\n } catch {\n fail(\"invalid-client\", \"Invalid Live client command\");\n return;\n }\n if (starting) {\n if (event.type === \"session.start\") {\n fail(\"invalid-client\", \"Live session has already started\");\n return;\n }\n const bytes = Buffer.byteLength(data);\n if (bytes > maxPendingBytes - pendingBytes || pending.length >= maxPendingFrames) {\n fail(\"resource-limit\", \"Live startup input queue exceeded\");\n return;\n }\n pendingBytes += bytes;\n pending.push(event);\n return;\n }\n accept(event);\n }\n function recordingError(error: unknown) {\n fail(\n error instanceof LiveRecorderError\n ? error.category\n : error instanceof Error && error.message === \"WebSocket write limit exceeded\"\n ? \"resource-limit\"\n : \"upstream-connect\",\n \"Live recording failed\",\n );\n }\n function touchUpstream() {\n upstreamIdle?.();\n upstreamIdle = scheduleLiveTimeout(\n () => fail(\"timeout\", \"Live upstream idle deadline exceeded\"),\n bodyTimeoutMs,\n );\n }\n function forward(event: LiveObject) {\n if (!upstream || !recorder || terminalReceived) return;\n try {\n const raw = JSON.stringify(event);\n const now = performance.now();\n captureStarted ??= now;\n recorder.acceptClient(raw, Math.floor(now - captureStarted));\n void upstream.sendAsync(raw, controller.signal).catch(recordingError);\n } catch (error) {\n recordingError(error);\n }\n }\n async function startRecording(first: LiveObject) {\n const record = defaults.record;\n if (!record?.providers.openai) {\n fail(\"fixture-mismatch\", \"No matching Live fixture\");\n return;\n }\n starting = true;\n try {\n const base = new URL(record.providers.openai);\n if (base.username || base.password || base.search || base.hash)\n throw new Error(\"Invalid URL\");\n base.pathname = base.pathname.replace(/\\/v1\\/?$/, \"/\");\n const target = resolveUpstreamUrl(base.href, \"/v1/live/sessions\");\n const headers: Record<string, string> = {};\n const incoming = options.headers.authorization;\n const credential = incoming?.match(/^\\s*(?:Bearer|Key)\\s+(.+)$/i)?.[1].trim();\n if (incoming && !options.localApiKeys?.includes(credential ?? \"\"))\n headers.Authorization = incoming;\n applyProviderAuth(headers, target, \"openai\", record.providerKeys?.openai);\n const selected = headers.Authorization?.replace(/^\\s*(?:Bearer|Key)\\s+/i, \"\").trim();\n recordingSecrets = [...(selected ? [selected] : []), ...(options.localApiKeys ?? [])];\n recorder = createLiveRecorder({\n record,\n fixtures,\n logger: defaults.logger,\n testId,\n live: limits,\n secretValues: recordingSecrets,\n provenance: {\n host: target.host,\n path: \"/v1/live/sessions\",\n observedAt: new Date().toISOString(),\n referenceVersion: \"gpt-live-1-observed-v3\",\n sanitationVersion: 1,\n },\n });\n upstream = await connectUpstreamWebSocket(\n target,\n headers,\n limits,\n controller.signal,\n upstreamTimeoutMs,\n );\n if (controller.signal.aborted) {\n upstream.destroy();\n return;\n }\n upstream.on(\"activity\", touchUpstream);\n upstream.on(\"message\", (raw: string) => {\n if (controller.signal.aborted) return;\n touchUpstream();\n try {\n // Capture at provider arrival, before downstream backpressure settles.\n recorder!.acceptServer(\n raw,\n captureStarted === undefined ? 0 : Math.floor(performance.now() - captureStarted),\n );\n const output: unknown = JSON.parse(raw);\n if (!output || typeof output !== \"object\" || !(\"type\" in output))\n throw new Error(\"Invalid event\");\n if (output.type === \"session.started\") {\n startup();\n starting = false;\n state = \"active\";\n const queued = pending.splice(0);\n pendingBytes = 0;\n for (const event of queued) {\n if (controller.signal.aborted) break;\n accept(event);\n }\n }\n const terminal = output.type === \"session.closed\";\n if (terminal) terminalReceived = true;\n void ws.sendAsync(raw, controller.signal).then(() => {\n if (!terminal || controller.signal.aborted) return;\n const result = recorder!.finish();\n if (result.kind === \"failed\") {\n fail(result.category, \"Live capture export failed\");\n return;\n }\n recordJournal();\n ws.close(1000, \"Live session complete\");\n cleanup();\n }, recordingError);\n } catch (error) {\n recordingError(error);\n }\n });\n upstream.on(\"error\", () => fail(\"upstream-connect\", \"Live upstream connection failed\"));\n upstream.on(\"close\", (code: number) => {\n if (!terminalReceived)\n fail(\n code === 1009 ? \"resource-limit\" : \"incomplete-capture\",\n \"Live upstream closed before completion\",\n );\n });\n touchUpstream();\n // Only startup is forwarded until the provider acknowledges the session.\n // The bounded queue retains commands that the caller pipelined meanwhile.\n forward(first);\n } catch (error) {\n const message = error instanceof Error ? error.message : \"\";\n if (/HTTP 401/.test(message)) fail(\"upstream-auth\", \"Live upstream authentication refused\");\n else if (/HTTP (403|404|429)/.test(message))\n fail(\"upstream-access\", \"Live upstream access refused\");\n else recordingError(error);\n }\n }\n function startReplay(\n fixture: Fixture,\n request: ChatCompletionRequest,\n first: LiveObject,\n raw: FixtureResponse,\n ) {\n if (state === \"closed\" || state === \"closing\") return;\n try {\n if (!isLiveResponse(raw)) throw new Error(\"not a Live fixture\");\n const response = normalizeLiveFixture(raw, limits);\n replay = createLiveReplay(response.live, {\n limits,\n signal: controller.signal,\n timing: response.liveTiming ?? \"recorded\",\n replaySpeed: fixture.replaySpeed ?? defaults.replaySpeed,\n fail,\n send: async (output) => {\n await ws.sendAsync(JSON.stringify(output), controller.signal);\n if (output.type === \"session.closed\" && !controller.signal.aborted) {\n ws.close(1000, \"Live session complete\");\n cleanup();\n }\n },\n });\n } catch {\n fail(\"protocol-divergence\", \"Invalid Live replay configuration\");\n return;\n }\n journal.add(\n liveJournalSnapshot(\n {\n method: \"WS\",\n path: \"/v1/live/sessions\",\n headers: { ...flattenHeaders(options.headers), \"x-test-id\": testId },\n body: request,\n response: { status: 200, fixture },\n },\n limits.secretValues,\n ),\n fixture,\n );\n startup();\n starting = false;\n state = \"active\";\n replay.accept(first);\n const queued = pending.splice(0);\n pendingBytes = 0;\n for (const event of queued) {\n if (controller.signal.aborted) break;\n accept(event);\n }\n }\n function accept(event: LiveObject) {\n if (state === \"closed\" || state === \"closing\") return;\n if (state === \"awaiting-start\") {\n const session = object(event.session);\n const audio = object(session?.audio);\n const format = object(audio?.format);\n const delegation = object(session?.delegation);\n if (\n event.type !== \"session.start\" ||\n session?.model !== \"gpt-live-1\" ||\n format?.type !== \"audio/pcm\" ||\n format.rate !== 24000 ||\n (delegation?.type !== \"client\" && delegation?.type !== \"responses\")\n ) {\n fail(\n \"invalid-client\",\n \"Live requires session.start with explicit model, PCM24 audio and delegation\",\n );\n return;\n }\n mode = delegation.type === \"client\" ? \"client\" : \"managed\";\n const request: ChatCompletionRequest = {\n model: session.model,\n messages: [],\n _endpointType: \"openai-live\",\n session: structuredClone(session),\n };\n let fixture: Fixture | null;\n let skippedBySequenceOrTurn: number;\n try {\n ({ fixture, skippedBySequenceOrTurn } = matchFixtureDiagnostic(\n fixtures,\n request,\n journal.getFixtureMatchCountsForTest(testId),\n defaults.requestTransform,\n ));\n } catch {\n fail(\"protocol-divergence\", \"Live fixture selection failed\");\n return;\n }\n if (!fixture) {\n const decisions = resolveRequestDecisions(defaults.strict, options.headers);\n if (decisions.fixtureMiss) {\n const message = strictNoMatchMessage(skippedBySequenceOrTurn);\n defaults.logger.error(\n strictNoMatchLogLine(\"WS\", \"/v1/live/sessions\", skippedBySequenceOrTurn),\n );\n // A rejected startup is diagnostic only: retain test ownership, never\n // caller authorization or session content, and do not create a recorder.\n journal.add(\n liveJournalSnapshot(\n {\n method: \"WS\",\n path: \"/v1/live/sessions\",\n headers: { \"x-test-id\": testId },\n body: { model: request.model, messages: [] },\n response: {\n status: 503,\n fixture: null,\n ...strictOverrideField(defaults.strict, options.headers),\n },\n },\n limits.secretValues,\n ),\n );\n fail(\"fixture-mismatch\", message);\n } else if (wouldProxyMiss(!decisions.upstream, defaults.record, \"openai\")) {\n void startRecording(event);\n } else {\n fail(\"fixture-mismatch\", \"No matching Live fixture\");\n }\n return;\n }\n journal.incrementFixtureMatchCount(fixture, fixtures, testId);\n if (typeof fixture.response === \"function\") {\n starting = true;\n const selected = fixture;\n void resolveResponse(selected, request).then(\n (response) => startReplay(selected, request, event, response),\n () => fail(\"protocol-divergence\", \"Live response factory failed\"),\n );\n } else startReplay(fixture, request, event, fixture.response);\n return;\n } else if (event.type === \"session.start\") {\n fail(\"invalid-client\", \"Live session has already started\");\n return;\n }\n if (event.type === \"session.update\") {\n const patch = object(event.session);\n const delegation = object(patch?.delegation);\n const backend = object(delegation?.responses);\n if (\n mode !== \"managed\" ||\n !patch ||\n !delegation ||\n !backend ||\n Object.keys(patch).some((key) => key !== \"delegation\") ||\n Object.keys(delegation).some((key) => key !== \"type\" && key !== \"responses\") ||\n (delegation.type !== undefined && delegation.type !== \"responses\") ||\n Object.keys(backend).some((key) => key !== \"instructions\") ||\n !Object.hasOwn(backend, \"instructions\")\n ) {\n fail(\"invalid-client\", \"Only managed backend instructions can be updated\");\n return;\n }\n }\n // Input acceptance is synchronous; output pressure never serializes duplex input.\n if (upstream) forward(event);\n else replay?.accept(event);\n }\n ws.on(\"message\", receive);\n ws.on(\"close\", cleanup);\n ws.on(\"error\", cleanup);\n return dispose;\n}\n"],"mappings":"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"}
|
package/dist/ws-realtime.cjs
CHANGED
|
@@ -1,11 +1,14 @@
|
|
|
1
1
|
const require_runtime = require('./_virtual/_rolldown/runtime.cjs');
|
|
2
|
+
const require_errors = require('./response/errors.cjs');
|
|
2
3
|
const require_constants = require('./constants.cjs');
|
|
4
|
+
const require_policy = require('./response/policy.cjs');
|
|
3
5
|
const require_helpers = require('./helpers.cjs');
|
|
4
6
|
const require_sse_writer = require('./sse-writer.cjs');
|
|
5
7
|
const require_misbehavior = require('./misbehavior.cjs');
|
|
6
8
|
const require_router = require('./router.cjs');
|
|
7
9
|
require('./journal.cjs');
|
|
8
10
|
const require_interruption = require('./interruption.cjs');
|
|
11
|
+
const require_realtime = require('./response/usage/codecs/realtime.cjs');
|
|
9
12
|
let node_crypto = require("node:crypto");
|
|
10
13
|
|
|
11
14
|
//#region src/ws-realtime.ts
|
|
@@ -316,11 +319,11 @@ function sendEvent(ws, event, isBeta) {
|
|
|
316
319
|
function buildErrorRealtimeEvent(ws, message, isBeta, type = "invalid_request_error", code) {
|
|
317
320
|
sendEvent(ws, {
|
|
318
321
|
type: "error",
|
|
319
|
-
error: {
|
|
322
|
+
error: require_errors.buildOpenAIError({
|
|
320
323
|
message,
|
|
321
324
|
type,
|
|
322
325
|
code
|
|
323
|
-
}
|
|
326
|
+
})
|
|
324
327
|
}, isBeta);
|
|
325
328
|
}
|
|
326
329
|
/**
|
|
@@ -436,11 +439,11 @@ async function processMessage(raw, ws, fixtures, journal, defaults, session, con
|
|
|
436
439
|
if (!validTypes.has(s.type)) {
|
|
437
440
|
sendEvent(ws, {
|
|
438
441
|
type: "error",
|
|
439
|
-
error: {
|
|
442
|
+
error: require_errors.buildOpenAIError({
|
|
440
443
|
message: `Invalid session type: ${s.type}`,
|
|
441
444
|
type: "invalid_request_error",
|
|
442
445
|
code: "invalid_session_config"
|
|
443
|
-
}
|
|
446
|
+
})
|
|
444
447
|
}, isBeta);
|
|
445
448
|
return;
|
|
446
449
|
}
|
|
@@ -495,11 +498,11 @@ async function processMessage(raw, ws, fixtures, journal, defaults, session, con
|
|
|
495
498
|
Object.assign(session, prevSession);
|
|
496
499
|
sendEvent(ws, {
|
|
497
500
|
type: "error",
|
|
498
|
-
error: {
|
|
501
|
+
error: require_errors.buildOpenAIError({
|
|
499
502
|
message: `Model ${candidateTranscriptionModel} does not support session type transcription`,
|
|
500
503
|
type: "invalid_request_error",
|
|
501
504
|
code: "invalid_session_config"
|
|
502
|
-
}
|
|
505
|
+
})
|
|
503
506
|
}, isBeta);
|
|
504
507
|
return;
|
|
505
508
|
}
|
|
@@ -507,11 +510,11 @@ async function processMessage(raw, ws, fixtures, journal, defaults, session, con
|
|
|
507
510
|
Object.assign(session, prevSession);
|
|
508
511
|
sendEvent(ws, {
|
|
509
512
|
type: "error",
|
|
510
|
-
error: {
|
|
513
|
+
error: require_errors.buildOpenAIError({
|
|
511
514
|
message: `Model ${s.model ?? prevSession.model} does not support session type translation`,
|
|
512
515
|
type: "invalid_request_error",
|
|
513
516
|
code: "invalid_session_config"
|
|
514
|
-
}
|
|
517
|
+
})
|
|
515
518
|
}, isBeta);
|
|
516
519
|
return;
|
|
517
520
|
}
|
|
@@ -586,7 +589,7 @@ async function emitLiveTranscriptionEvents(ws, fixtures, journal, defaults, sess
|
|
|
586
589
|
const { fixture, skippedBySequenceOrTurn } = require_router.matchFixtureDiagnostic(fixtures, request, journal.getFixtureMatchCountsForTest(testId), defaults.requestTransform);
|
|
587
590
|
const itemId = audioItem.id ?? realtimeId("item");
|
|
588
591
|
if (!fixture) {
|
|
589
|
-
if (
|
|
592
|
+
if (require_policy.resolveRequestDecisions(defaults.strict, defaults.upgradeHeaders).fixtureMiss) {
|
|
590
593
|
const strictMessage = require_helpers.strictNoMatchMessage(skippedBySequenceOrTurn);
|
|
591
594
|
defaults.logger.error(require_helpers.strictNoMatchLogLine("WS", "/v1/realtime", skippedBySequenceOrTurn));
|
|
592
595
|
journal.add({
|
|
@@ -597,7 +600,7 @@ async function emitLiveTranscriptionEvents(ws, fixtures, journal, defaults, sess
|
|
|
597
600
|
response: {
|
|
598
601
|
status: 503,
|
|
599
602
|
fixture: null,
|
|
600
|
-
...
|
|
603
|
+
...require_policy.strictOverrideField(defaults.strict, defaults.upgradeHeaders)
|
|
601
604
|
}
|
|
602
605
|
});
|
|
603
606
|
ws.close(1008, strictMessage);
|
|
@@ -611,7 +614,7 @@ async function emitLiveTranscriptionEvents(ws, fixtures, journal, defaults, sess
|
|
|
611
614
|
response: {
|
|
612
615
|
status: 404,
|
|
613
616
|
fixture: null,
|
|
614
|
-
...
|
|
617
|
+
...require_policy.strictOverrideField(defaults.strict, defaults.upgradeHeaders)
|
|
615
618
|
}
|
|
616
619
|
});
|
|
617
620
|
sendLiveTranscriptionFailure(ws, itemId, {
|
|
@@ -763,11 +766,7 @@ function checkRealtimeFixtureToolCalls(ws, journalEntry, responseId, isBeta, log
|
|
|
763
766
|
code: require_helpers.fixtureToolCallErrorCode(err)
|
|
764
767
|
}
|
|
765
768
|
},
|
|
766
|
-
usage: {
|
|
767
|
-
total_tokens: 0,
|
|
768
|
-
input_tokens: 0,
|
|
769
|
-
output_tokens: 0
|
|
770
|
-
}
|
|
769
|
+
usage: require_realtime.render({ kind: "ordinary-zero" })
|
|
771
770
|
}
|
|
772
771
|
}, isBeta);
|
|
773
772
|
return;
|
|
@@ -795,7 +794,7 @@ async function handleResponseCreate(ws, fixtures, journal, defaults, session, co
|
|
|
795
794
|
const responseId = realtimeId("resp");
|
|
796
795
|
if (fixture) journal.incrementFixtureMatchCount(fixture, fixtures, testId);
|
|
797
796
|
if (!fixture) {
|
|
798
|
-
if (
|
|
797
|
+
if (require_policy.resolveRequestDecisions(defaults.strict, defaults.upgradeHeaders).fixtureMiss) {
|
|
799
798
|
const strictMessage = require_helpers.strictNoMatchMessage(skippedBySequenceOrTurn);
|
|
800
799
|
defaults.logger.error(require_helpers.strictNoMatchLogLine("WS", "/v1/realtime", skippedBySequenceOrTurn));
|
|
801
800
|
journal.add({
|
|
@@ -806,7 +805,7 @@ async function handleResponseCreate(ws, fixtures, journal, defaults, session, co
|
|
|
806
805
|
response: {
|
|
807
806
|
status: 503,
|
|
808
807
|
fixture: null,
|
|
809
|
-
...
|
|
808
|
+
...require_policy.strictOverrideField(defaults.strict, defaults.upgradeHeaders)
|
|
810
809
|
}
|
|
811
810
|
});
|
|
812
811
|
ws.close(1008, strictMessage);
|
|
@@ -820,7 +819,7 @@ async function handleResponseCreate(ws, fixtures, journal, defaults, session, co
|
|
|
820
819
|
response: {
|
|
821
820
|
status: 404,
|
|
822
821
|
fixture: null,
|
|
823
|
-
...
|
|
822
|
+
...require_policy.strictOverrideField(defaults.strict, defaults.upgradeHeaders)
|
|
824
823
|
}
|
|
825
824
|
});
|
|
826
825
|
sendEvent(ws, {
|
|
@@ -849,11 +848,7 @@ async function handleResponseCreate(ws, fixtures, journal, defaults, session, co
|
|
|
849
848
|
code: "no_fixture_match"
|
|
850
849
|
}
|
|
851
850
|
},
|
|
852
|
-
usage: {
|
|
853
|
-
total_tokens: 0,
|
|
854
|
-
input_tokens: 0,
|
|
855
|
-
output_tokens: 0
|
|
856
|
-
}
|
|
851
|
+
usage: require_realtime.render({ kind: "ordinary-zero" })
|
|
857
852
|
}
|
|
858
853
|
}, isBeta);
|
|
859
854
|
return;
|
|
@@ -917,11 +912,10 @@ async function handleResponseCreate(ws, fixtures, journal, defaults, session, co
|
|
|
917
912
|
const usage = require_helpers.resolveOpenAIChatMisbehaviorUsage(misbehavior, completionReq, false);
|
|
918
913
|
await streamRealtimeBlocks(ws, blocks, responseId, fixture, defaults, latency, chunkSize, isBeta, conversationItems, journalEntry, {
|
|
919
914
|
stop: misbehavior.stop,
|
|
920
|
-
usage: {
|
|
921
|
-
|
|
922
|
-
|
|
923
|
-
|
|
924
|
-
}
|
|
915
|
+
usage: require_realtime.render({
|
|
916
|
+
kind: "applied-misbehavior",
|
|
917
|
+
usage
|
|
918
|
+
})
|
|
925
919
|
});
|
|
926
920
|
return;
|
|
927
921
|
}
|
|
@@ -953,11 +947,7 @@ async function handleResponseCreate(ws, fixtures, journal, defaults, session, co
|
|
|
953
947
|
code: response.error.code
|
|
954
948
|
}
|
|
955
949
|
},
|
|
956
|
-
usage: {
|
|
957
|
-
total_tokens: 0,
|
|
958
|
-
input_tokens: 0,
|
|
959
|
-
output_tokens: 0
|
|
960
|
-
}
|
|
950
|
+
usage: require_realtime.render({ kind: "ordinary-zero" })
|
|
961
951
|
}
|
|
962
952
|
}, isBeta);
|
|
963
953
|
return;
|
|
@@ -1235,11 +1225,7 @@ async function handleResponseCreate(ws, fixtures, journal, defaults, session, co
|
|
|
1235
1225
|
object: "realtime.response",
|
|
1236
1226
|
status: "completed",
|
|
1237
1227
|
output: allOutputItems,
|
|
1238
|
-
usage: {
|
|
1239
|
-
total_tokens: 0,
|
|
1240
|
-
input_tokens: 0,
|
|
1241
|
-
output_tokens: 0
|
|
1242
|
-
}
|
|
1228
|
+
usage: require_realtime.render({ kind: "ordinary-zero" })
|
|
1243
1229
|
}
|
|
1244
1230
|
}, isBeta);
|
|
1245
1231
|
conversationItems.push({
|
|
@@ -1395,11 +1381,7 @@ async function handleResponseCreate(ws, fixtures, journal, defaults, session, co
|
|
|
1395
1381
|
object: "realtime.response",
|
|
1396
1382
|
status: "completed",
|
|
1397
1383
|
output: [outputItem],
|
|
1398
|
-
usage: {
|
|
1399
|
-
total_tokens: 0,
|
|
1400
|
-
input_tokens: 0,
|
|
1401
|
-
output_tokens: 0
|
|
1402
|
-
}
|
|
1384
|
+
usage: require_realtime.render({ kind: "ordinary-zero" })
|
|
1403
1385
|
}
|
|
1404
1386
|
}, isBeta);
|
|
1405
1387
|
conversationItems.push({
|
|
@@ -1540,11 +1522,7 @@ async function handleResponseCreate(ws, fixtures, journal, defaults, session, co
|
|
|
1540
1522
|
object: "realtime.response",
|
|
1541
1523
|
status: "completed",
|
|
1542
1524
|
output: outputItems,
|
|
1543
|
-
usage: {
|
|
1544
|
-
total_tokens: 0,
|
|
1545
|
-
input_tokens: 0,
|
|
1546
|
-
output_tokens: 0
|
|
1547
|
-
}
|
|
1525
|
+
usage: require_realtime.render({ kind: "ordinary-zero" })
|
|
1548
1526
|
}
|
|
1549
1527
|
}, isBeta);
|
|
1550
1528
|
for (const item of outputItems) conversationItems.push(item);
|
|
@@ -1809,11 +1787,7 @@ async function streamRealtimeBlocks(ws, blocks, responseId, fixture, defaults, l
|
|
|
1809
1787
|
reason: fault.stop === "length" ? "max_output_tokens" : "content_filter"
|
|
1810
1788
|
} } : {},
|
|
1811
1789
|
output: allOutputItems,
|
|
1812
|
-
usage: fault?.usage ?? {
|
|
1813
|
-
total_tokens: 0,
|
|
1814
|
-
input_tokens: 0,
|
|
1815
|
-
output_tokens: 0
|
|
1816
|
-
}
|
|
1790
|
+
usage: fault?.usage ?? require_realtime.render({ kind: "ordinary-zero" })
|
|
1817
1791
|
}
|
|
1818
1792
|
}, isBeta);
|
|
1819
1793
|
for (const item of allOutputItems) {
|