@copilotkit/aimock 1.45.1 → 1.47.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 +25 -1
- package/README.md +11 -2
- 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.cts.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/aws-event-stream.cjs +20 -23
- package/dist/aws-event-stream.cjs.map +1 -1
- package/dist/aws-event-stream.d.cts +0 -1
- package/dist/aws-event-stream.d.ts +0 -1
- package/dist/aws-event-stream.js +20 -24
- package/dist/aws-event-stream.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 +139 -161
- 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 +137 -159
- package/dist/bedrock-converse.js.map +1 -1
- package/dist/bedrock.cjs +175 -216
- 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 +172 -213
- 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 +107 -180
- 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 +106 -179
- 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 +140 -44
- 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 +141 -46
- 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 +113 -156
- 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 +113 -156
- package/dist/gemini-interactions.js.map +1 -1
- package/dist/gemini.cjs +295 -218
- 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 +295 -219
- 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 +411 -75
- package/dist/helpers.cjs.map +1 -1
- package/dist/helpers.d.cts +51 -1
- package/dist/helpers.d.cts.map +1 -1
- package/dist/helpers.d.ts +51 -1
- package/dist/helpers.d.ts.map +1 -1
- package/dist/helpers.js +402 -74
- 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.cjs +4 -2
- package/dist/index.d.cts +4 -4
- package/dist/index.d.ts +4 -4
- package/dist/index.js +4 -4
- 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 +7 -3
- package/dist/mcp-handler.cjs.map +1 -1
- package/dist/mcp-handler.js +7 -3
- 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 +235 -202
- 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 +234 -202
- 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/misbehavior.cjs +62 -3
- package/dist/misbehavior.cjs.map +1 -1
- package/dist/misbehavior.d.cts.map +1 -1
- package/dist/misbehavior.d.ts.map +1 -1
- package/dist/misbehavior.js +63 -4
- package/dist/misbehavior.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/ndjson-writer.cjs +21 -23
- package/dist/ndjson-writer.cjs.map +1 -1
- package/dist/ndjson-writer.d.cts +0 -1
- package/dist/ndjson-writer.d.cts.map +1 -1
- package/dist/ndjson-writer.d.ts +0 -1
- package/dist/ndjson-writer.d.ts.map +1 -1
- package/dist/ndjson-writer.js +21 -24
- package/dist/ndjson-writer.js.map +1 -1
- package/dist/ollama.cjs +276 -210
- 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 +273 -207
- 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 +51 -74
- 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 +37 -60
- package/dist/openrouter-video.js.map +1 -1
- package/dist/raw-validation.cjs +177 -0
- package/dist/raw-validation.cjs.map +1 -0
- package/dist/raw-validation.js +176 -0
- package/dist/raw-validation.js.map +1 -0
- 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/deliver.cjs +144 -0
- package/dist/response/deliver.cjs.map +1 -0
- package/dist/response/deliver.js +143 -0
- package/dist/response/deliver.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/frame-loop.cjs +102 -0
- package/dist/response/frame-loop.cjs.map +1 -0
- package/dist/response/frame-loop.js +100 -0
- package/dist/response/frame-loop.js.map +1 -0
- package/dist/response/lifecycle.cjs +223 -0
- package/dist/response/lifecycle.cjs.map +1 -0
- package/dist/response/lifecycle.js +211 -0
- package/dist/response/lifecycle.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/proxy.cjs +71 -0
- package/dist/response/proxy.cjs.map +1 -0
- package/dist/response/proxy.js +70 -0
- package/dist/response/proxy.js.map +1 -0
- package/dist/response/raw.cjs +228 -0
- package/dist/response/raw.cjs.map +1 -0
- package/dist/response/raw.js +227 -0
- package/dist/response/raw.js.map +1 -0
- package/dist/response/timing.cjs +157 -0
- package/dist/response/timing.cjs.map +1 -0
- package/dist/response/timing.js +150 -0
- package/dist/response/timing.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 +304 -196
- 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 +303 -195
- 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 +24 -4
- package/dist/router.cjs.map +1 -1
- package/dist/router.d.cts +7 -1
- package/dist/router.d.cts.map +1 -1
- package/dist/router.d.ts +7 -1
- package/dist/router.d.ts.map +1 -1
- package/dist/router.js +24 -5
- 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 +293 -248
- 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 +294 -249
- 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 +56 -30
- package/dist/sse-writer.cjs.map +1 -1
- package/dist/sse-writer.d.cts +0 -1
- package/dist/sse-writer.d.cts.map +1 -1
- package/dist/sse-writer.d.ts +0 -1
- package/dist/sse-writer.d.ts.map +1 -1
- package/dist/sse-writer.js +55 -31
- 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 +31 -43
- 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 +31 -43
- package/dist/transcription.js.map +1 -1
- package/dist/types.cjs.map +1 -1
- package/dist/types.d.cts +231 -9
- package/dist/types.d.cts.map +1 -1
- package/dist/types.d.ts +231 -9
- 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-framing.cjs +12 -6
- package/dist/ws-framing.cjs.map +1 -1
- package/dist/ws-framing.d.cts +2 -0
- package/dist/ws-framing.d.cts.map +1 -1
- package/dist/ws-framing.d.ts +2 -0
- package/dist/ws-framing.d.ts.map +1 -1
- package/dist/ws-framing.js +12 -6
- package/dist/ws-framing.js.map +1 -1
- package/dist/ws-gemini-live.cjs +131 -96
- 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 +130 -95
- 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 +108 -124
- 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 +105 -121
- package/dist/ws-realtime.js.map +1 -1
- package/dist/ws-responses.cjs +80 -59
- package/dist/ws-responses.cjs.map +1 -1
- package/dist/ws-responses.d.cts.map +1 -1
- package/dist/ws-responses.d.ts.map +1 -1
- package/dist/ws-responses.js +79 -58
- package/dist/ws-responses.js.map +1 -1
- package/package.json +4 -1
- package/skills/write-fixtures/SKILL.md +57 -16
package/dist/responses.js
CHANGED
|
@@ -1,11 +1,18 @@
|
|
|
1
|
+
import { renderError } from "./response/errors.js";
|
|
1
2
|
import { isReasoningModel } from "./model-utils.js";
|
|
2
|
-
import {
|
|
3
|
-
import {
|
|
3
|
+
import { resolveRequestDecisions, strictOverrideField } from "./response/policy.js";
|
|
4
|
+
import { UnsupportedGeneratedFileError, assertCustomToolCalls, assertResponsesToolCalls, extractOverrides, fixtureCitations, fixtureFiles, flattenHeaders, generateId, generateToolCallId, getContext, getTestId, isCombinedFixtureResponse, isErrorResponse, isJsonObject, isRawResponse, isTextResponse, isToolCallResponse, prepareOpenAIChatMisbehavior, resolveFixtureBlocks, resolveOpenAIChatMisbehaviorUsage, resolveReasoningForModel, resolveResponse, resolveServedBlockOutcome, serializeErrorResponse, servedToolCalls, strictNoMatchLogLine, strictNoMatchMessage, surrogateSafeChunks, toolCallFixtureBlock, withoutLegacyNamespaces } from "./helpers.js";
|
|
5
|
+
import { typedSseCodec, writeErrorResponse } from "./sse-writer.js";
|
|
4
6
|
import { applyChaosAsync } from "./chaos.js";
|
|
5
7
|
import { planMisbehavior, recordMisbehaviorOutcome } from "./misbehavior.js";
|
|
6
8
|
import { matchFixtureDiagnostic, recordMatchOptions, setResponsesOfferedTools } from "./router.js";
|
|
7
9
|
import { proxyAndRecord } from "./recorder.js";
|
|
8
|
-
import {
|
|
10
|
+
import { extendRecordedTimings, misbehaviorPayloadLength, nonStreamingTimingEnabled, responsesOutputFrames, responsesPayloadLength } from "./response/timing.js";
|
|
11
|
+
import { deliverJson, deliverStream } from "./response/deliver.js";
|
|
12
|
+
import { proxyInterruption, withHangUpDetection } from "./response/proxy.js";
|
|
13
|
+
import { serveRawResponse } from "./response/raw.js";
|
|
14
|
+
import { render } from "./response/usage/codecs/responses.js";
|
|
15
|
+
import { mapResponsesFinish } from "./response/finish.js";
|
|
9
16
|
import { randomBytes } from "node:crypto";
|
|
10
17
|
|
|
11
18
|
//#region src/responses.ts
|
|
@@ -310,25 +317,7 @@ function validateResponsesTools(tools) {
|
|
|
310
317
|
}
|
|
311
318
|
function responsesStatus(finishReason, defaultStatus) {
|
|
312
319
|
if (!finishReason) return defaultStatus;
|
|
313
|
-
|
|
314
|
-
if (finishReason === "tool_calls") return "completed";
|
|
315
|
-
if (finishReason === "length") return "incomplete";
|
|
316
|
-
if (finishReason === "content_filter") return "failed";
|
|
317
|
-
return finishReason;
|
|
318
|
-
}
|
|
319
|
-
function responsesUsage(overrides) {
|
|
320
|
-
if (!overrides?.usage) return {
|
|
321
|
-
input_tokens: 0,
|
|
322
|
-
output_tokens: 0,
|
|
323
|
-
total_tokens: 0
|
|
324
|
-
};
|
|
325
|
-
const input = overrides.usage.input_tokens ?? overrides.usage.prompt_tokens ?? 0;
|
|
326
|
-
const output = overrides.usage.output_tokens ?? overrides.usage.completion_tokens ?? 0;
|
|
327
|
-
return {
|
|
328
|
-
input_tokens: input,
|
|
329
|
-
output_tokens: output,
|
|
330
|
-
total_tokens: overrides.usage.total_tokens ?? input + output
|
|
331
|
-
};
|
|
320
|
+
return mapResponsesFinish(finishReason);
|
|
332
321
|
}
|
|
333
322
|
function responseId() {
|
|
334
323
|
return generateId("resp");
|
|
@@ -338,7 +327,7 @@ function itemId() {
|
|
|
338
327
|
}
|
|
339
328
|
function buildTextStreamEvents(content, model, chunkSize, reasoning, webSearches, overrides, emitEncryptedReasoning = false, synthesizeSummarylessReasoning = false) {
|
|
340
329
|
const { respId, created, events, prefixOutputItems, nextOutputIndex } = buildResponsePreamble(model, chunkSize, reasoning, webSearches, overrides, emitEncryptedReasoning, synthesizeSummarylessReasoning);
|
|
341
|
-
const { events: msgEvents, msgItem } = buildMessageOutputEvents(content, chunkSize, nextOutputIndex);
|
|
330
|
+
const { events: msgEvents, msgItem } = buildMessageOutputEvents(content, chunkSize, nextOutputIndex, overrides?.phase, buildAnnotations(content, overrides?.citations));
|
|
342
331
|
events.push(...msgEvents);
|
|
343
332
|
events.push({
|
|
344
333
|
type: "response.completed",
|
|
@@ -349,7 +338,7 @@ function buildTextStreamEvents(content, model, chunkSize, reasoning, webSearches
|
|
|
349
338
|
model: overrides?.model ?? model,
|
|
350
339
|
status: responsesStatus(overrides?.finishReason, "completed"),
|
|
351
340
|
output: [...prefixOutputItems, msgItem],
|
|
352
|
-
usage:
|
|
341
|
+
usage: render(overrides)
|
|
353
342
|
}
|
|
354
343
|
});
|
|
355
344
|
return events;
|
|
@@ -447,6 +436,7 @@ function buildToolCallStreamEvents(toolCalls, model, chunkSize, reasoning, webSe
|
|
|
447
436
|
}
|
|
448
437
|
function toolCallStreamEvents(toolCalls, model, chunkSize, reasoning, webSearches, overrides, emitEncryptedReasoning = false, synthesizeSummarylessReasoning = false) {
|
|
449
438
|
assertResponsesToolCalls(toolCalls);
|
|
439
|
+
fixtureCitations("", overrides?.citations);
|
|
450
440
|
const { respId, created, events, prefixOutputItems, nextOutputIndex } = buildResponsePreamble(model, chunkSize, reasoning, webSearches, overrides, emitEncryptedReasoning, synthesizeSummarylessReasoning);
|
|
451
441
|
const fcOutputItems = [];
|
|
452
442
|
for (let idx = 0; idx < toolCalls.length; idx++) {
|
|
@@ -463,7 +453,7 @@ function toolCallStreamEvents(toolCalls, model, chunkSize, reasoning, webSearche
|
|
|
463
453
|
model: overrides?.model ?? model,
|
|
464
454
|
status: responsesStatus(overrides?.finishReason, "completed"),
|
|
465
455
|
output: [...prefixOutputItems, ...fcOutputItems],
|
|
466
|
-
usage:
|
|
456
|
+
usage: render(overrides)
|
|
467
457
|
}
|
|
468
458
|
});
|
|
469
459
|
return events;
|
|
@@ -683,6 +673,79 @@ function buildWebSearchStreamEvents(queries, startOutputIndex) {
|
|
|
683
673
|
}
|
|
684
674
|
return events;
|
|
685
675
|
}
|
|
676
|
+
/**
|
|
677
|
+
* A Responses `image_generation_call` output item for one fixture file (see
|
|
678
|
+
* `ResponseOutputItem.ImageGenerationCall` in the openai SDK): `result` holds
|
|
679
|
+
* the base64 bytes once completed and is null while in progress.
|
|
680
|
+
*/
|
|
681
|
+
function imageGenerationCallItem(id, file, status) {
|
|
682
|
+
return {
|
|
683
|
+
type: "image_generation_call",
|
|
684
|
+
id,
|
|
685
|
+
status,
|
|
686
|
+
result: status === "completed" ? file.data : null
|
|
687
|
+
};
|
|
688
|
+
}
|
|
689
|
+
/**
|
|
690
|
+
* A fixture file that is not `image/*` reached the Responses API, which
|
|
691
|
+
* carries generated files only as `image_generation_call` items. Surfaces as
|
|
692
|
+
* the same coded 500 (`aimock_unsupported_generated_file`), naming `mimeType`.
|
|
693
|
+
*/
|
|
694
|
+
var NonImageGeneratedFileError = class extends UnsupportedGeneratedFileError {
|
|
695
|
+
constructor(mimeType) {
|
|
696
|
+
super("the OpenAI Responses API");
|
|
697
|
+
this.message = `aimock: fixture "files" on the OpenAI Responses API carry only image/* files (as image_generation_call items); got mimeType "${mimeType}"`;
|
|
698
|
+
}
|
|
699
|
+
};
|
|
700
|
+
/**
|
|
701
|
+
* Throw {@link NonImageGeneratedFileError} for the first fixture file whose
|
|
702
|
+
* `mimeType` is not `image/*`. Called before any output item is built, so
|
|
703
|
+
* nothing reaches the client.
|
|
704
|
+
*/
|
|
705
|
+
function requireImageFiles(files) {
|
|
706
|
+
const nonImage = files.find((f) => !f.mimeType.toLowerCase().startsWith("image/"));
|
|
707
|
+
if (nonImage) throw new NonImageGeneratedFileError(nonImage.mimeType);
|
|
708
|
+
}
|
|
709
|
+
/** Fixture `files` as completed `image_generation_call` items (non-streaming). */
|
|
710
|
+
function imageGenerationCallItems(files) {
|
|
711
|
+
const validated = fixtureFiles(files);
|
|
712
|
+
requireImageFiles(validated);
|
|
713
|
+
return validated.map((f) => imageGenerationCallItem(generateId("ig"), f, "completed"));
|
|
714
|
+
}
|
|
715
|
+
/**
|
|
716
|
+
* Streamed form of {@link imageGenerationCallItems}: per file, the item's
|
|
717
|
+
* `output_item.added`, the `image_generation_call` `in_progress`,
|
|
718
|
+
* `generating` and `completed` events, then `output_item.done` carrying the
|
|
719
|
+
* completed item.
|
|
720
|
+
*/
|
|
721
|
+
function buildImageGenerationStreamEvents(files, startOutputIndex) {
|
|
722
|
+
requireImageFiles(files);
|
|
723
|
+
const events = [];
|
|
724
|
+
files.forEach((file, i) => {
|
|
725
|
+
const id = generateId("ig");
|
|
726
|
+
const outputIndex = startOutputIndex + i;
|
|
727
|
+
events.push({
|
|
728
|
+
type: "response.output_item.added",
|
|
729
|
+
output_index: outputIndex,
|
|
730
|
+
item: imageGenerationCallItem(id, file, "in_progress")
|
|
731
|
+
});
|
|
732
|
+
for (const phase of [
|
|
733
|
+
"in_progress",
|
|
734
|
+
"generating",
|
|
735
|
+
"completed"
|
|
736
|
+
]) events.push({
|
|
737
|
+
type: `response.image_generation_call.${phase}`,
|
|
738
|
+
output_index: outputIndex,
|
|
739
|
+
item_id: id
|
|
740
|
+
});
|
|
741
|
+
events.push({
|
|
742
|
+
type: "response.output_item.done",
|
|
743
|
+
output_index: outputIndex,
|
|
744
|
+
item: imageGenerationCallItem(id, file, "completed")
|
|
745
|
+
});
|
|
746
|
+
});
|
|
747
|
+
return events;
|
|
748
|
+
}
|
|
686
749
|
function buildResponsePreamble(model, chunkSize, reasoning, webSearches, overrides, emitEncryptedReasoning = false, synthesizeSummarylessReasoning = false, forceReasoning = false) {
|
|
687
750
|
const respId = overrides?.id ?? responseId();
|
|
688
751
|
const created = overrides?.created ?? Math.floor(Date.now() / 1e3);
|
|
@@ -726,6 +789,13 @@ function buildResponsePreamble(model, chunkSize, reasoning, webSearches, overrid
|
|
|
726
789
|
for (const de of doneEvents) prefixOutputItems.push(de.item);
|
|
727
790
|
nextOutputIndex += webSearches.length;
|
|
728
791
|
}
|
|
792
|
+
const files = fixtureFiles(overrides?.files);
|
|
793
|
+
if (files.length > 0) {
|
|
794
|
+
const fileEvents = buildImageGenerationStreamEvents(files, nextOutputIndex);
|
|
795
|
+
events.push(...fileEvents);
|
|
796
|
+
for (const e of fileEvents) if (e.type === "response.output_item.done") prefixOutputItems.push(e.item);
|
|
797
|
+
nextOutputIndex += files.length;
|
|
798
|
+
}
|
|
729
799
|
return {
|
|
730
800
|
respId,
|
|
731
801
|
created,
|
|
@@ -734,7 +804,84 @@ function buildResponsePreamble(model, chunkSize, reasoning, webSearches, overrid
|
|
|
734
804
|
nextOutputIndex
|
|
735
805
|
};
|
|
736
806
|
}
|
|
737
|
-
|
|
807
|
+
/**
|
|
808
|
+
* Fixture `citations` as `output_text` annotations for each text in `texts`
|
|
809
|
+
* (one per message item), in fixture order: a URL citation becomes
|
|
810
|
+
* `url_citation`, a file citation (`type: "file"`) becomes `file_citation`
|
|
811
|
+
* (`file_id`, `filename`, `index`; see `ResponseOutputText.FileCitation` in
|
|
812
|
+
* the openai SDK). Offsets index the joined text of all texts, as on every
|
|
813
|
+
* other provider. A URL citation is a range and goes only to the text holding
|
|
814
|
+
* its `startIndex`. A file citation is a point after the cited text, so it
|
|
815
|
+
* goes to the last text starting before its `index`: an `index` equal to a
|
|
816
|
+
* text's end stays at the end of that text (not at 0 of the next text), and
|
|
817
|
+
* an `index` of 0 goes to the first text. Each citation is rebased onto its
|
|
818
|
+
* text since Responses offsets are per `output_text`, with `end_index`
|
|
819
|
+
* clamped to it. Anthropic and Gemini need no point rule: they have no file
|
|
820
|
+
* citation. Anthropic URL citations follow the same start-owns-range rule;
|
|
821
|
+
* Gemini does not, and splits a citation that spans several text parts into
|
|
822
|
+
* one grounding support per part (see geminiGroundingSupports).
|
|
823
|
+
* Missing offsets take the defaults `resolveCitations` applies: a URL
|
|
824
|
+
* citation starts at 0 and ends at the end of the joined text, so one without
|
|
825
|
+
* offsets goes on the first text and covers all of it; a file citation's
|
|
826
|
+
* `index` defaults to the end of the joined text (the last text).
|
|
827
|
+
*/
|
|
828
|
+
function blockAnnotations(texts, citations) {
|
|
829
|
+
const perText = texts.map(() => []);
|
|
830
|
+
if (texts.length === 0) {
|
|
831
|
+
fixtureCitations("", citations);
|
|
832
|
+
return perText;
|
|
833
|
+
}
|
|
834
|
+
const starts = [];
|
|
835
|
+
let offset = 0;
|
|
836
|
+
for (const text of texts) {
|
|
837
|
+
starts.push(offset);
|
|
838
|
+
offset += text.length;
|
|
839
|
+
}
|
|
840
|
+
const joinedLength = offset;
|
|
841
|
+
const ownerOf = (start) => {
|
|
842
|
+
let owner = 0;
|
|
843
|
+
for (let k = 1; k < starts.length; k++) if (starts[k] <= start) owner = k;
|
|
844
|
+
return owner;
|
|
845
|
+
};
|
|
846
|
+
const pointOwnerOf = (index) => {
|
|
847
|
+
let owner = 0;
|
|
848
|
+
for (let k = 1; k < starts.length; k++) if (starts[k] < index) owner = k;
|
|
849
|
+
return owner;
|
|
850
|
+
};
|
|
851
|
+
for (const c of fixtureCitations(texts.join(""), citations)) {
|
|
852
|
+
if (c.type === "file") {
|
|
853
|
+
const index = c.index ?? joinedLength;
|
|
854
|
+
const owner = pointOwnerOf(index);
|
|
855
|
+
perText[owner].push({
|
|
856
|
+
type: "file_citation",
|
|
857
|
+
file_id: c.fileId,
|
|
858
|
+
filename: c.filename,
|
|
859
|
+
index: index - starts[owner]
|
|
860
|
+
});
|
|
861
|
+
continue;
|
|
862
|
+
}
|
|
863
|
+
const start = c.startIndex ?? 0;
|
|
864
|
+
const end = c.endIndex ?? joinedLength;
|
|
865
|
+
const owner = ownerOf(start);
|
|
866
|
+
perText[owner].push({
|
|
867
|
+
type: "url_citation",
|
|
868
|
+
url: c.url,
|
|
869
|
+
title: c.title ?? c.url,
|
|
870
|
+
start_index: start - starts[owner],
|
|
871
|
+
end_index: Math.min(end - starts[owner], texts[owner].length)
|
|
872
|
+
});
|
|
873
|
+
}
|
|
874
|
+
return perText;
|
|
875
|
+
}
|
|
876
|
+
/** {@link blockAnnotations} for a turn with a single text. */
|
|
877
|
+
function buildAnnotations(content, citations) {
|
|
878
|
+
return blockAnnotations([content], citations)[0];
|
|
879
|
+
}
|
|
880
|
+
/** The annotations of each text block in `blocks`, in block order. */
|
|
881
|
+
function orderedBlockAnnotations(blocks, citations) {
|
|
882
|
+
return blockAnnotations(blocks.flatMap((b) => b.type === "text" ? [b.text] : []), citations);
|
|
883
|
+
}
|
|
884
|
+
function buildMessageOutputEvents(content, chunkSize, outputIndex, phase, annotations) {
|
|
738
885
|
const msgId = itemId();
|
|
739
886
|
const events = [];
|
|
740
887
|
events.push({
|
|
@@ -745,6 +892,7 @@ function buildMessageOutputEvents(content, chunkSize, outputIndex) {
|
|
|
745
892
|
id: msgId,
|
|
746
893
|
status: "in_progress",
|
|
747
894
|
role: "assistant",
|
|
895
|
+
...phase !== void 0 ? { phase } : {},
|
|
748
896
|
content: []
|
|
749
897
|
}
|
|
750
898
|
});
|
|
@@ -773,6 +921,16 @@ function buildMessageOutputEvents(content, chunkSize, outputIndex) {
|
|
|
773
921
|
content_index: 0,
|
|
774
922
|
text: content
|
|
775
923
|
});
|
|
924
|
+
annotations.forEach((annotation, annotationIndex) => {
|
|
925
|
+
events.push({
|
|
926
|
+
type: "response.output_text.annotation.added",
|
|
927
|
+
item_id: msgId,
|
|
928
|
+
output_index: outputIndex,
|
|
929
|
+
content_index: 0,
|
|
930
|
+
annotation_index: annotationIndex,
|
|
931
|
+
annotation
|
|
932
|
+
});
|
|
933
|
+
});
|
|
776
934
|
events.push({
|
|
777
935
|
type: "response.content_part.done",
|
|
778
936
|
item_id: msgId,
|
|
@@ -781,7 +939,7 @@ function buildMessageOutputEvents(content, chunkSize, outputIndex) {
|
|
|
781
939
|
part: {
|
|
782
940
|
type: "output_text",
|
|
783
941
|
text: content,
|
|
784
|
-
annotations
|
|
942
|
+
annotations
|
|
785
943
|
}
|
|
786
944
|
});
|
|
787
945
|
const msgItem = {
|
|
@@ -789,10 +947,11 @@ function buildMessageOutputEvents(content, chunkSize, outputIndex) {
|
|
|
789
947
|
id: msgId,
|
|
790
948
|
status: "completed",
|
|
791
949
|
role: "assistant",
|
|
950
|
+
...phase !== void 0 ? { phase } : {},
|
|
792
951
|
content: [{
|
|
793
952
|
type: "output_text",
|
|
794
953
|
text: content,
|
|
795
|
-
annotations
|
|
954
|
+
annotations
|
|
796
955
|
}]
|
|
797
956
|
};
|
|
798
957
|
events.push({
|
|
@@ -847,24 +1006,6 @@ function buildFunctionCallOutputEvents(toolCall, chunkSize, outputIndex) {
|
|
|
847
1006
|
};
|
|
848
1007
|
}
|
|
849
1008
|
/**
|
|
850
|
-
* `text` cut into slices of at most `chunkSize` UTF-16 units, never between
|
|
851
|
-
* the two halves of a surrogate pair: a cut that would land inside a pair
|
|
852
|
-
* moves back before it, or, when that would leave the slice empty
|
|
853
|
-
* (`chunkSize` 1), forward past it. The slices rejoin to `text` exactly.
|
|
854
|
-
*/
|
|
855
|
-
function surrogateSafeChunks(text, chunkSize) {
|
|
856
|
-
const chunks = [];
|
|
857
|
-
for (let i = 0; i < text.length;) {
|
|
858
|
-
let end = Math.min(i + chunkSize, text.length);
|
|
859
|
-
const high = text.charCodeAt(end - 1);
|
|
860
|
-
const low = text.charCodeAt(end);
|
|
861
|
-
if (high >= 55296 && high <= 56319 && low >= 56320 && low <= 57343) end = end - 1 > i ? end - 1 : end + 1;
|
|
862
|
-
chunks.push(text.slice(i, end));
|
|
863
|
-
i = end;
|
|
864
|
-
}
|
|
865
|
-
return chunks;
|
|
866
|
-
}
|
|
867
|
-
/**
|
|
868
1009
|
* Emit output_item.added → custom_tool_call_input.delta×N →
|
|
869
1010
|
* custom_tool_call_input.done → output_item.done for one `custom_tool_call` at
|
|
870
1011
|
* `outputIndex`, returning the completed item. An empty `input`
|
|
@@ -907,7 +1048,7 @@ function buildCustomToolCallOutputEvents(call, chunkSize, outputIndex) {
|
|
|
907
1048
|
function buildToolCallOutputEvents(call, chunkSize, outputIndex) {
|
|
908
1049
|
return isCustomEmittable(call) ? buildCustomToolCallOutputEvents(call, chunkSize, outputIndex) : buildFunctionCallOutputEvents(call, chunkSize, outputIndex);
|
|
909
1050
|
}
|
|
910
|
-
function buildOutputPrefix(content, model, reasoning, webSearches, emitEncryptedReasoning = false, synthesizeSummarylessReasoning = false) {
|
|
1051
|
+
function buildOutputPrefix(content, model, reasoning, webSearches, emitEncryptedReasoning = false, synthesizeSummarylessReasoning = false, phase, citations, files) {
|
|
911
1052
|
const output = [];
|
|
912
1053
|
if (reasoning || shouldSynthesizeBlobOnlyReasoning(reasoning, model, synthesizeSummarylessReasoning)) output.push(buildReasoningOutputItem(generateId("rs"), {
|
|
913
1054
|
summaryText: reasoning,
|
|
@@ -922,15 +1063,17 @@ function buildOutputPrefix(content, model, reasoning, webSearches, emitEncrypted
|
|
|
922
1063
|
query
|
|
923
1064
|
}
|
|
924
1065
|
});
|
|
1066
|
+
output.push(...imageGenerationCallItems(files));
|
|
925
1067
|
output.push({
|
|
926
1068
|
type: "message",
|
|
927
1069
|
id: itemId(),
|
|
928
1070
|
status: "completed",
|
|
929
1071
|
role: "assistant",
|
|
1072
|
+
...phase !== void 0 ? { phase } : {},
|
|
930
1073
|
content: [{
|
|
931
1074
|
type: "output_text",
|
|
932
1075
|
text: content,
|
|
933
|
-
annotations:
|
|
1076
|
+
annotations: buildAnnotations(content, citations)
|
|
934
1077
|
}]
|
|
935
1078
|
});
|
|
936
1079
|
return output;
|
|
@@ -943,14 +1086,15 @@ function buildResponseEnvelope(model, output, overrides) {
|
|
|
943
1086
|
model: overrides?.model ?? model,
|
|
944
1087
|
status: responsesStatus(overrides?.finishReason, "completed"),
|
|
945
1088
|
output,
|
|
946
|
-
usage:
|
|
1089
|
+
usage: render(overrides)
|
|
947
1090
|
};
|
|
948
1091
|
}
|
|
949
1092
|
function buildTextResponse(content, model, reasoning, webSearches, overrides, emitEncryptedReasoning = false, synthesizeSummarylessReasoning = false) {
|
|
950
|
-
return buildResponseEnvelope(model, buildOutputPrefix(content, model, reasoning, webSearches, emitEncryptedReasoning, synthesizeSummarylessReasoning), overrides);
|
|
1093
|
+
return buildResponseEnvelope(model, buildOutputPrefix(content, model, reasoning, webSearches, emitEncryptedReasoning, synthesizeSummarylessReasoning, overrides?.phase, overrides?.citations, overrides?.files), overrides);
|
|
951
1094
|
}
|
|
952
1095
|
function buildToolCallResponse(toolCalls, model, reasoning, webSearches, overrides, emitEncryptedReasoning = false, synthesizeSummarylessReasoning = false) {
|
|
953
1096
|
assertResponsesToolCalls(toolCalls);
|
|
1097
|
+
fixtureCitations("", overrides?.citations);
|
|
954
1098
|
const output = [];
|
|
955
1099
|
if (reasoning || shouldSynthesizeBlobOnlyReasoning(reasoning, model, synthesizeSummarylessReasoning)) output.push(buildReasoningOutputItem(generateId("rs"), {
|
|
956
1100
|
summaryText: reasoning,
|
|
@@ -965,6 +1109,7 @@ function buildToolCallResponse(toolCalls, model, reasoning, webSearches, overrid
|
|
|
965
1109
|
query
|
|
966
1110
|
}
|
|
967
1111
|
});
|
|
1112
|
+
output.push(...imageGenerationCallItems(overrides?.files));
|
|
968
1113
|
for (const tc of toolCalls) output.push(buildToolCallOutputItem(tc));
|
|
969
1114
|
return buildResponseEnvelope(model, output, overrides);
|
|
970
1115
|
}
|
|
@@ -982,9 +1127,11 @@ function contentWithToolCallsStreamEvents(content, toolCalls, model, chunkSize,
|
|
|
982
1127
|
const orderedOutputItems = [];
|
|
983
1128
|
if (ordered && ordered.length > 0) {
|
|
984
1129
|
let outputIndex = nextOutputIndex;
|
|
1130
|
+
const textAnnotations = orderedBlockAnnotations(ordered, overrides?.citations);
|
|
1131
|
+
let textPos = 0;
|
|
985
1132
|
for (const block of ordered) {
|
|
986
1133
|
if (block.type === "text") {
|
|
987
|
-
const { events: msgEvents, msgItem } = buildMessageOutputEvents(block.text, chunkSize, outputIndex);
|
|
1134
|
+
const { events: msgEvents, msgItem } = buildMessageOutputEvents(block.text, chunkSize, outputIndex, overrides?.phase, textAnnotations[textPos++]);
|
|
988
1135
|
events.push(...msgEvents);
|
|
989
1136
|
orderedOutputItems.push(msgItem);
|
|
990
1137
|
} else {
|
|
@@ -996,7 +1143,7 @@ function contentWithToolCallsStreamEvents(content, toolCalls, model, chunkSize,
|
|
|
996
1143
|
}
|
|
997
1144
|
} else {
|
|
998
1145
|
assertResponsesToolCalls(toolCalls);
|
|
999
|
-
const { events: msgEvents, msgItem } = buildMessageOutputEvents(content, chunkSize, nextOutputIndex);
|
|
1146
|
+
const { events: msgEvents, msgItem } = buildMessageOutputEvents(content, chunkSize, nextOutputIndex, overrides?.phase, buildAnnotations(content, overrides?.citations));
|
|
1000
1147
|
events.push(...msgEvents);
|
|
1001
1148
|
orderedOutputItems.push(msgItem);
|
|
1002
1149
|
for (let idx = 0; idx < toolCalls.length; idx++) {
|
|
@@ -1014,7 +1161,7 @@ function contentWithToolCallsStreamEvents(content, toolCalls, model, chunkSize,
|
|
|
1014
1161
|
model: overrides?.model ?? model,
|
|
1015
1162
|
status: responsesStatus(overrides?.finishReason, "completed"),
|
|
1016
1163
|
output: [...prefixOutputItems, ...orderedOutputItems],
|
|
1017
|
-
usage:
|
|
1164
|
+
usage: render(overrides)
|
|
1018
1165
|
}
|
|
1019
1166
|
});
|
|
1020
1167
|
return events;
|
|
@@ -1024,16 +1171,17 @@ function buildToolCallOutputItem(tc) {
|
|
|
1024
1171
|
if (isCustomEmittable(tc)) return customToolCallItem(tc, customToolCallItemId(), tc.id || generateToolCallId(), requireFixtureToolInput(tc.input), "completed");
|
|
1025
1172
|
return functionCallItem(tc, generateId("fc"), tc.id || generateToolCallId(), requireFixtureToolArguments(tc.arguments), "completed");
|
|
1026
1173
|
}
|
|
1027
|
-
function buildMessageOutputItem(content) {
|
|
1174
|
+
function buildMessageOutputItem(content, phase, annotations) {
|
|
1028
1175
|
return {
|
|
1029
1176
|
type: "message",
|
|
1030
1177
|
id: itemId(),
|
|
1031
1178
|
status: "completed",
|
|
1032
1179
|
role: "assistant",
|
|
1180
|
+
...phase !== void 0 ? { phase } : {},
|
|
1033
1181
|
content: [{
|
|
1034
1182
|
type: "output_text",
|
|
1035
1183
|
text: content,
|
|
1036
|
-
annotations
|
|
1184
|
+
annotations
|
|
1037
1185
|
}]
|
|
1038
1186
|
};
|
|
1039
1187
|
}
|
|
@@ -1053,40 +1201,18 @@ function buildContentWithToolCallsResponse(content, toolCalls, model, reasoning,
|
|
|
1053
1201
|
query
|
|
1054
1202
|
}
|
|
1055
1203
|
});
|
|
1056
|
-
|
|
1204
|
+
output.push(...imageGenerationCallItems(overrides?.files));
|
|
1205
|
+
const textAnnotations = orderedBlockAnnotations(ordered, overrides?.citations);
|
|
1206
|
+
let textPos = 0;
|
|
1207
|
+
for (const block of ordered) if (block.type === "text") output.push(buildMessageOutputItem(block.text, overrides?.phase, textAnnotations[textPos++]));
|
|
1057
1208
|
else output.push(buildToolCallOutputItem(block));
|
|
1058
1209
|
return buildResponseEnvelope(model, output, overrides);
|
|
1059
1210
|
}
|
|
1060
1211
|
assertResponsesToolCalls(toolCalls);
|
|
1061
|
-
const output = buildOutputPrefix(content, model, reasoning, webSearches, emitEncryptedReasoning, synthesizeSummarylessReasoning);
|
|
1212
|
+
const output = buildOutputPrefix(content, model, reasoning, webSearches, emitEncryptedReasoning, synthesizeSummarylessReasoning, overrides?.phase, overrides?.citations, overrides?.files);
|
|
1062
1213
|
for (const tc of toolCalls) output.push(buildToolCallOutputItem(tc));
|
|
1063
1214
|
return buildResponseEnvelope(model, output, overrides);
|
|
1064
1215
|
}
|
|
1065
|
-
async function writeResponsesSSEStream(res, events, optionsOrLatency) {
|
|
1066
|
-
const opts = typeof optionsOrLatency === "number" ? { latency: optionsOrLatency } : optionsOrLatency ?? {};
|
|
1067
|
-
const latency = opts.latency ?? 0;
|
|
1068
|
-
const profile = opts.streamingProfile;
|
|
1069
|
-
const { recordedTimings, replaySpeed } = opts;
|
|
1070
|
-
const signal = opts.signal;
|
|
1071
|
-
const onChunkSent = opts.onChunkSent;
|
|
1072
|
-
if (res.writableEnded) return true;
|
|
1073
|
-
res.setHeader("Content-Type", "text/event-stream");
|
|
1074
|
-
res.setHeader("Cache-Control", "no-cache");
|
|
1075
|
-
res.setHeader("Connection", "keep-alive");
|
|
1076
|
-
let chunkIndex = 0;
|
|
1077
|
-
for (const event of events) {
|
|
1078
|
-
const chunkDelay = calculateDelay(chunkIndex, profile, latency, recordedTimings, replaySpeed);
|
|
1079
|
-
if (chunkDelay > 0) await delay(chunkDelay, signal);
|
|
1080
|
-
if (signal?.aborted) return false;
|
|
1081
|
-
if (res.writableEnded) return true;
|
|
1082
|
-
res.write(`event: ${event.type}\ndata: ${JSON.stringify(event)}\n\n`);
|
|
1083
|
-
onChunkSent?.();
|
|
1084
|
-
if (signal?.aborted) return false;
|
|
1085
|
-
chunkIndex++;
|
|
1086
|
-
}
|
|
1087
|
-
if (!res.writableEnded) res.end();
|
|
1088
|
-
return true;
|
|
1089
|
-
}
|
|
1090
1216
|
async function handleResponses(req, res, raw, fixtures, journal, defaults, setCorsHeaders) {
|
|
1091
1217
|
setCorsHeaders(res);
|
|
1092
1218
|
let responsesReq;
|
|
@@ -1104,11 +1230,11 @@ async function handleResponses(req, res, raw, fixtures, journal, defaults, setCo
|
|
|
1104
1230
|
fixture: null
|
|
1105
1231
|
}
|
|
1106
1232
|
});
|
|
1107
|
-
writeErrorResponse(res, 400,
|
|
1233
|
+
writeErrorResponse(res, 400, renderError("openai", "validation", {
|
|
1108
1234
|
message: `Malformed JSON: ${detail}`,
|
|
1109
1235
|
type: "invalid_request_error",
|
|
1110
1236
|
code: "invalid_json"
|
|
1111
|
-
}
|
|
1237
|
+
}).body);
|
|
1112
1238
|
return;
|
|
1113
1239
|
}
|
|
1114
1240
|
if (!isJsonObject(responsesReq)) {
|
|
@@ -1122,10 +1248,10 @@ async function handleResponses(req, res, raw, fixtures, journal, defaults, setCo
|
|
|
1122
1248
|
fixture: null
|
|
1123
1249
|
}
|
|
1124
1250
|
});
|
|
1125
|
-
writeErrorResponse(res, 400,
|
|
1251
|
+
writeErrorResponse(res, 400, renderError("openai", "validation", {
|
|
1126
1252
|
message: "Request body must be a JSON object",
|
|
1127
1253
|
type: "invalid_request_error"
|
|
1128
|
-
}
|
|
1254
|
+
}).body);
|
|
1129
1255
|
return;
|
|
1130
1256
|
}
|
|
1131
1257
|
let inputError;
|
|
@@ -1152,10 +1278,10 @@ async function handleResponses(req, res, raw, fixtures, journal, defaults, setCo
|
|
|
1152
1278
|
fixture: null
|
|
1153
1279
|
}
|
|
1154
1280
|
});
|
|
1155
|
-
writeErrorResponse(res, 400,
|
|
1281
|
+
writeErrorResponse(res, 400, renderError("openai", "validation", {
|
|
1156
1282
|
message: validationError,
|
|
1157
1283
|
type: "invalid_request_error"
|
|
1158
|
-
}
|
|
1284
|
+
}).body);
|
|
1159
1285
|
return;
|
|
1160
1286
|
}
|
|
1161
1287
|
const extendedTools = defaults.responsesTools === "extended";
|
|
@@ -1168,7 +1294,10 @@ async function handleResponses(req, res, raw, fixtures, journal, defaults, setCo
|
|
|
1168
1294
|
const emitEncryptedReasoning = requestWantsEncryptedReasoning(responsesReq);
|
|
1169
1295
|
const synthesizeSummarylessReasoning = requestIncludesEncryptedReasoning(responsesReq);
|
|
1170
1296
|
const testId = getTestId(req);
|
|
1171
|
-
const { fixture, skippedBySequenceOrTurn } = matchFixtureDiagnostic(fixtures, completionReq, journal.getFixtureMatchCountsForTest(testId), defaults.requestTransform,
|
|
1297
|
+
const { fixture, skippedBySequenceOrTurn } = matchFixtureDiagnostic(fixtures, completionReq, journal.getFixtureMatchCountsForTest(testId), defaults.requestTransform, {
|
|
1298
|
+
...recordMatchOptions(!!defaults.record, defaults.logger),
|
|
1299
|
+
wire: "openai-responses"
|
|
1300
|
+
});
|
|
1172
1301
|
if (fixture) {
|
|
1173
1302
|
defaults.logger.debug(`Responses fixture matched for ${req.method ?? "POST"} ${req.url ?? "/v1/responses"}`);
|
|
1174
1303
|
journal.incrementFixtureMatchCount(fixture, fixtures, testId);
|
|
@@ -1180,7 +1309,7 @@ async function handleResponses(req, res, raw, fixtures, journal, defaults, setCo
|
|
|
1180
1309
|
body: completionReq
|
|
1181
1310
|
}, fixture ? "fixture" : "proxy", defaults.registry, defaults.logger)) return;
|
|
1182
1311
|
if (!fixture) {
|
|
1183
|
-
if (
|
|
1312
|
+
if (resolveRequestDecisions(defaults.strict, req.headers).fixtureMiss) {
|
|
1184
1313
|
const strictStatus = 503;
|
|
1185
1314
|
const strictMessage = strictNoMatchMessage(skippedBySequenceOrTurn);
|
|
1186
1315
|
defaults.logger.error(strictNoMatchLogLine(req.method ?? "POST", req.url ?? "/v1/responses", skippedBySequenceOrTurn));
|
|
@@ -1195,15 +1324,15 @@ async function handleResponses(req, res, raw, fixtures, journal, defaults, setCo
|
|
|
1195
1324
|
...strictOverrideField(defaults.strict, req.headers)
|
|
1196
1325
|
}
|
|
1197
1326
|
});
|
|
1198
|
-
writeErrorResponse(res, strictStatus,
|
|
1327
|
+
writeErrorResponse(res, strictStatus, renderError("openai", "strict-miss", {
|
|
1199
1328
|
message: strictMessage,
|
|
1200
1329
|
type: "invalid_request_error",
|
|
1201
1330
|
code: "no_fixture_match"
|
|
1202
|
-
}
|
|
1331
|
+
}).body);
|
|
1203
1332
|
return;
|
|
1204
1333
|
}
|
|
1205
1334
|
if (defaults.record) {
|
|
1206
|
-
const outcome = await proxyAndRecord(req, res, completionReq, "openai", req.url ?? "/v1/responses", fixtures, defaults, raw);
|
|
1335
|
+
const { outcome, clientHungUp } = await withHangUpDetection(req, res, () => proxyAndRecord(req, res, completionReq, "openai", req.url ?? "/v1/responses", fixtures, defaults, raw));
|
|
1207
1336
|
if (outcome === "handled_by_hook") return;
|
|
1208
1337
|
if (outcome !== "not_configured") {
|
|
1209
1338
|
journal.add({
|
|
@@ -1214,7 +1343,8 @@ async function handleResponses(req, res, raw, fixtures, journal, defaults, setCo
|
|
|
1214
1343
|
response: {
|
|
1215
1344
|
status: res.statusCode ?? 200,
|
|
1216
1345
|
fixture: null,
|
|
1217
|
-
source: "proxy"
|
|
1346
|
+
source: "proxy",
|
|
1347
|
+
...proxyInterruption(res, clientHungUp)
|
|
1218
1348
|
}
|
|
1219
1349
|
});
|
|
1220
1350
|
return;
|
|
@@ -1231,11 +1361,11 @@ async function handleResponses(req, res, raw, fixtures, journal, defaults, setCo
|
|
|
1231
1361
|
...strictOverrideField(defaults.strict, req.headers)
|
|
1232
1362
|
}
|
|
1233
1363
|
});
|
|
1234
|
-
writeErrorResponse(res, 404,
|
|
1364
|
+
writeErrorResponse(res, 404, renderError("openai", "fixture-miss", {
|
|
1235
1365
|
message: "No fixture matched",
|
|
1236
1366
|
type: "invalid_request_error",
|
|
1237
1367
|
code: "no_fixture_match"
|
|
1238
|
-
}
|
|
1368
|
+
}).body);
|
|
1239
1369
|
return;
|
|
1240
1370
|
}
|
|
1241
1371
|
const resolvedResponse = await resolveResponse(fixture, completionReq);
|
|
@@ -1268,20 +1398,34 @@ async function handleResponses(req, res, raw, fixtures, journal, defaults, setCo
|
|
|
1268
1398
|
testId
|
|
1269
1399
|
});
|
|
1270
1400
|
if (!misbehavior.summary?.evaluations.some((evaluation) => evaluation.outcome === "error")) defaults.logger.error(misbehavior.message);
|
|
1271
|
-
writeErrorResponse(res, misbehavior.status,
|
|
1401
|
+
writeErrorResponse(res, misbehavior.status, renderError("openai", "misbehavior", {
|
|
1272
1402
|
message: misbehavior.message,
|
|
1273
1403
|
type: "invalid_request_error",
|
|
1274
1404
|
code: misbehavior.code
|
|
1275
|
-
}
|
|
1405
|
+
}).body);
|
|
1276
1406
|
return;
|
|
1277
1407
|
}
|
|
1278
1408
|
const latency = fixture.latency ?? defaults.latency;
|
|
1279
1409
|
const chunkSize = Math.max(1, fixture.chunkSize ?? defaults.chunkSize);
|
|
1280
1410
|
const fixtureTimings = fixture.recordedTimings;
|
|
1281
1411
|
const effectiveReplaySpeed = fixture.replaySpeed ?? defaults.replaySpeed;
|
|
1412
|
+
const streamTiming = {
|
|
1413
|
+
latency,
|
|
1414
|
+
streamingProfile: fixture.streamingProfile,
|
|
1415
|
+
recordedTimings: fixtureTimings,
|
|
1416
|
+
replaySpeed: effectiveReplaySpeed
|
|
1417
|
+
};
|
|
1418
|
+
const timedJson = nonStreamingTimingEnabled(fixture, "other");
|
|
1419
|
+
const jsonPayloadLength = (r, reasoning) => responsesPayloadLength(r, reasoning) + responsesOutputFrames(r) * chunkSize;
|
|
1420
|
+
const jsonOpts = (payloadLength, duplicateId = false) => ({
|
|
1421
|
+
surface: "other",
|
|
1422
|
+
payloadLength: timedJson ? payloadLength() : 0,
|
|
1423
|
+
chunkSize,
|
|
1424
|
+
recordedTimings: fixtureTimings,
|
|
1425
|
+
duplicateId,
|
|
1426
|
+
replaySpeed: effectiveReplaySpeed
|
|
1427
|
+
});
|
|
1282
1428
|
if (misbehavior.kind === "applied") {
|
|
1283
|
-
const prepared = prepareResponsesMisbehavior(misbehavior);
|
|
1284
|
-
const output = buildResponsesMisbehavior(prepared, completionReq, chunkSize, emitEncryptedReasoning);
|
|
1285
1429
|
const entry = journal.add({
|
|
1286
1430
|
method: req.method ?? "POST",
|
|
1287
1431
|
path: req.url ?? "/v1/responses",
|
|
@@ -1292,41 +1436,50 @@ async function handleResponses(req, res, raw, fixtures, journal, defaults, setCo
|
|
|
1292
1436
|
fixture
|
|
1293
1437
|
}
|
|
1294
1438
|
});
|
|
1295
|
-
|
|
1439
|
+
const prepared = prepareResponsesMisbehavior(misbehavior);
|
|
1440
|
+
const build = () => buildResponsesMisbehavior(prepared, completionReq, chunkSize, emitEncryptedReasoning);
|
|
1441
|
+
const record = () => recordMisbehaviorOutcome({
|
|
1296
1442
|
entry,
|
|
1297
1443
|
summary: prepared.summary,
|
|
1298
1444
|
defaults,
|
|
1299
1445
|
testId
|
|
1300
1446
|
});
|
|
1447
|
+
const output = timedJson && responsesReq.stream !== true ? void 0 : build();
|
|
1448
|
+
if (output) record();
|
|
1301
1449
|
if (responsesReq.stream !== true) {
|
|
1302
|
-
|
|
1303
|
-
res
|
|
1450
|
+
const servedReasoning = prepared.reasoning ?? ("reasoning" in prepared.response ? prepared.response.reasoning : void 0);
|
|
1451
|
+
await deliverJson(res, entry, fixture, () => {
|
|
1452
|
+
if (output) return output.response;
|
|
1453
|
+
const built = build();
|
|
1454
|
+
record();
|
|
1455
|
+
return built.response;
|
|
1456
|
+
}, jsonOpts(() => misbehaviorPayloadLength(prepared, servedReasoning, jsonPayloadLength), !!prepared.duplicateId));
|
|
1304
1457
|
} else {
|
|
1305
|
-
const
|
|
1306
|
-
|
|
1307
|
-
|
|
1308
|
-
|
|
1309
|
-
|
|
1310
|
-
const lastGap = appliedTimings.interChunkDelaysMs.at(-1) ?? 0;
|
|
1311
|
-
while (appliedTimings.interChunkDelaysMs.length < output.events.length - 1) appliedTimings.interChunkDelaysMs.push(lastGap);
|
|
1312
|
-
}
|
|
1313
|
-
const interruption = createInterruptionSignal(fixture);
|
|
1314
|
-
if (!await writeResponsesSSEStream(res, output.events, {
|
|
1315
|
-
latency,
|
|
1316
|
-
streamingProfile: fixture.streamingProfile,
|
|
1317
|
-
recordedTimings: appliedTimings,
|
|
1318
|
-
replaySpeed: effectiveReplaySpeed,
|
|
1319
|
-
signal: interruption?.signal,
|
|
1320
|
-
onChunkSent: interruption?.tick
|
|
1321
|
-
})) {
|
|
1322
|
-
if (!res.writableEnded) res.destroy();
|
|
1323
|
-
entry.response.interrupted = true;
|
|
1324
|
-
entry.response.interruptReason = interruption?.reason();
|
|
1325
|
-
}
|
|
1326
|
-
interruption?.cleanup();
|
|
1458
|
+
const { events } = output ?? build();
|
|
1459
|
+
await deliverStream(res, entry, fixture, typedSseCodec(), events, {
|
|
1460
|
+
...streamTiming,
|
|
1461
|
+
recordedTimings: extendRecordedTimings(fixtureTimings, events.length, !!prepared.duplicateId)
|
|
1462
|
+
});
|
|
1327
1463
|
}
|
|
1328
1464
|
return;
|
|
1329
1465
|
}
|
|
1466
|
+
if (isRawResponse(response)) {
|
|
1467
|
+
await serveRawResponse({
|
|
1468
|
+
wire: "openai-responses",
|
|
1469
|
+
stream: responsesReq.stream === true,
|
|
1470
|
+
req,
|
|
1471
|
+
res,
|
|
1472
|
+
fixture,
|
|
1473
|
+
response,
|
|
1474
|
+
body: completionReq,
|
|
1475
|
+
journal,
|
|
1476
|
+
defaults,
|
|
1477
|
+
testId,
|
|
1478
|
+
misbehaviorSummary: misbehavior.summary,
|
|
1479
|
+
errorWire: "openai"
|
|
1480
|
+
});
|
|
1481
|
+
return;
|
|
1482
|
+
}
|
|
1330
1483
|
if (isErrorResponse(response)) {
|
|
1331
1484
|
const status = response.status ?? 500;
|
|
1332
1485
|
recordMisbehaviorOutcome({
|
|
@@ -1349,7 +1502,7 @@ async function handleResponses(req, res, raw, fixtures, journal, defaults, setCo
|
|
|
1349
1502
|
}
|
|
1350
1503
|
if (isCombinedFixtureResponse(response)) {
|
|
1351
1504
|
const overrides = extractOverrides(response);
|
|
1352
|
-
const effectiveStrict =
|
|
1505
|
+
const effectiveStrict = resolveRequestDecisions(defaults.strict, req.headers).reasoningSuppression;
|
|
1353
1506
|
const effReasoning = resolveReasoningForModel(response.reasoning, completionReq.model, effectiveStrict, defaults.logger);
|
|
1354
1507
|
const journalEntry = journal.add({
|
|
1355
1508
|
method: req.method ?? "POST",
|
|
@@ -1370,32 +1523,16 @@ async function handleResponses(req, res, raw, fixtures, journal, defaults, setCo
|
|
|
1370
1523
|
const ordered = resolveServedBlockOutcome(response)?.ordered;
|
|
1371
1524
|
if (!ordered) assertCustomToolCalls(response);
|
|
1372
1525
|
const toolCalls = servedToolCalls(response);
|
|
1373
|
-
if (responsesReq.stream !== true)
|
|
1374
|
-
|
|
1375
|
-
res.writeHead(200, { "Content-Type": "application/json" });
|
|
1376
|
-
res.end(JSON.stringify(body));
|
|
1377
|
-
} else {
|
|
1526
|
+
if (responsesReq.stream !== true) await deliverJson(res, journalEntry, fixture, () => buildContentWithToolCallsResponse(response.content ?? "", toolCalls, completionReq.model, effReasoning, response.webSearches, overrides, ordered, emitEncryptedReasoning, synthesizeSummarylessReasoning), jsonOpts(() => jsonPayloadLength(response, effReasoning)));
|
|
1527
|
+
else {
|
|
1378
1528
|
const events = contentWithToolCallsStreamEvents(response.content ?? "", toolCalls, completionReq.model, chunkSize, effReasoning, response.webSearches, overrides, ordered, emitEncryptedReasoning, synthesizeSummarylessReasoning);
|
|
1379
|
-
|
|
1380
|
-
if (!await writeResponsesSSEStream(res, events, {
|
|
1381
|
-
latency,
|
|
1382
|
-
streamingProfile: fixture.streamingProfile,
|
|
1383
|
-
recordedTimings: fixtureTimings,
|
|
1384
|
-
replaySpeed: effectiveReplaySpeed,
|
|
1385
|
-
signal: interruption?.signal,
|
|
1386
|
-
onChunkSent: interruption?.tick
|
|
1387
|
-
})) {
|
|
1388
|
-
if (!res.writableEnded) res.destroy();
|
|
1389
|
-
journalEntry.response.interrupted = true;
|
|
1390
|
-
journalEntry.response.interruptReason = interruption?.reason();
|
|
1391
|
-
}
|
|
1392
|
-
interruption?.cleanup();
|
|
1529
|
+
await deliverStream(res, journalEntry, fixture, typedSseCodec(), events, streamTiming);
|
|
1393
1530
|
}
|
|
1394
1531
|
return;
|
|
1395
1532
|
}
|
|
1396
1533
|
if (isTextResponse(response)) {
|
|
1397
1534
|
const overrides = extractOverrides(response);
|
|
1398
|
-
const effectiveStrict =
|
|
1535
|
+
const effectiveStrict = resolveRequestDecisions(defaults.strict, req.headers).reasoningSuppression;
|
|
1399
1536
|
const effReasoning = resolveReasoningForModel(response.reasoning, completionReq.model, effectiveStrict, defaults.logger);
|
|
1400
1537
|
const journalEntry = journal.add({
|
|
1401
1538
|
method: req.method ?? "POST",
|
|
@@ -1413,32 +1550,16 @@ async function handleResponses(req, res, raw, fixtures, journal, defaults, setCo
|
|
|
1413
1550
|
defaults,
|
|
1414
1551
|
testId
|
|
1415
1552
|
});
|
|
1416
|
-
if (responsesReq.stream !== true)
|
|
1417
|
-
|
|
1418
|
-
res.writeHead(200, { "Content-Type": "application/json" });
|
|
1419
|
-
res.end(JSON.stringify(body));
|
|
1420
|
-
} else {
|
|
1553
|
+
if (responsesReq.stream !== true) await deliverJson(res, journalEntry, fixture, () => buildTextResponse(response.content, completionReq.model, effReasoning, response.webSearches, overrides, emitEncryptedReasoning, synthesizeSummarylessReasoning), jsonOpts(() => jsonPayloadLength(response, effReasoning)));
|
|
1554
|
+
else {
|
|
1421
1555
|
const events = buildTextStreamEvents(response.content, completionReq.model, chunkSize, effReasoning, response.webSearches, overrides, emitEncryptedReasoning, synthesizeSummarylessReasoning);
|
|
1422
|
-
|
|
1423
|
-
if (!await writeResponsesSSEStream(res, events, {
|
|
1424
|
-
latency,
|
|
1425
|
-
streamingProfile: fixture.streamingProfile,
|
|
1426
|
-
recordedTimings: fixtureTimings,
|
|
1427
|
-
replaySpeed: effectiveReplaySpeed,
|
|
1428
|
-
signal: interruption?.signal,
|
|
1429
|
-
onChunkSent: interruption?.tick
|
|
1430
|
-
})) {
|
|
1431
|
-
if (!res.writableEnded) res.destroy();
|
|
1432
|
-
journalEntry.response.interrupted = true;
|
|
1433
|
-
journalEntry.response.interruptReason = interruption?.reason();
|
|
1434
|
-
}
|
|
1435
|
-
interruption?.cleanup();
|
|
1556
|
+
await deliverStream(res, journalEntry, fixture, typedSseCodec(), events, streamTiming);
|
|
1436
1557
|
}
|
|
1437
1558
|
return;
|
|
1438
1559
|
}
|
|
1439
1560
|
if (isToolCallResponse(response)) {
|
|
1440
1561
|
const overrides = extractOverrides(response);
|
|
1441
|
-
const effectiveStrict =
|
|
1562
|
+
const effectiveStrict = resolveRequestDecisions(defaults.strict, req.headers).reasoningSuppression;
|
|
1442
1563
|
const effReasoning = resolveReasoningForModel(response.reasoning, completionReq.model, effectiveStrict, defaults.logger);
|
|
1443
1564
|
const journalEntry = journal.add({
|
|
1444
1565
|
method: req.method ?? "POST",
|
|
@@ -1457,26 +1578,10 @@ async function handleResponses(req, res, raw, fixtures, journal, defaults, setCo
|
|
|
1457
1578
|
testId
|
|
1458
1579
|
});
|
|
1459
1580
|
assertCustomToolCalls(response);
|
|
1460
|
-
if (responsesReq.stream !== true)
|
|
1461
|
-
|
|
1462
|
-
res.writeHead(200, { "Content-Type": "application/json" });
|
|
1463
|
-
res.end(JSON.stringify(body));
|
|
1464
|
-
} else {
|
|
1581
|
+
if (responsesReq.stream !== true) await deliverJson(res, journalEntry, fixture, () => buildToolCallResponse(servedToolCalls(response), completionReq.model, effReasoning, response.webSearches, overrides, emitEncryptedReasoning, synthesizeSummarylessReasoning), jsonOpts(() => jsonPayloadLength(response, effReasoning)));
|
|
1582
|
+
else {
|
|
1465
1583
|
const events = toolCallStreamEvents(servedToolCalls(response), completionReq.model, chunkSize, effReasoning, response.webSearches, overrides, emitEncryptedReasoning, synthesizeSummarylessReasoning);
|
|
1466
|
-
|
|
1467
|
-
if (!await writeResponsesSSEStream(res, events, {
|
|
1468
|
-
latency,
|
|
1469
|
-
streamingProfile: fixture.streamingProfile,
|
|
1470
|
-
recordedTimings: fixtureTimings,
|
|
1471
|
-
replaySpeed: effectiveReplaySpeed,
|
|
1472
|
-
signal: interruption?.signal,
|
|
1473
|
-
onChunkSent: interruption?.tick
|
|
1474
|
-
})) {
|
|
1475
|
-
if (!res.writableEnded) res.destroy();
|
|
1476
|
-
journalEntry.response.interrupted = true;
|
|
1477
|
-
journalEntry.response.interruptReason = interruption?.reason();
|
|
1478
|
-
}
|
|
1479
|
-
interruption?.cleanup();
|
|
1584
|
+
await deliverStream(res, journalEntry, fixture, typedSseCodec(), events, streamTiming);
|
|
1480
1585
|
}
|
|
1481
1586
|
return;
|
|
1482
1587
|
}
|
|
@@ -1495,10 +1600,10 @@ async function handleResponses(req, res, raw, fixtures, journal, defaults, setCo
|
|
|
1495
1600
|
defaults,
|
|
1496
1601
|
testId
|
|
1497
1602
|
});
|
|
1498
|
-
writeErrorResponse(res, 500,
|
|
1603
|
+
writeErrorResponse(res, 500, renderError("openai", "unknown-response", {
|
|
1499
1604
|
message: "Fixture response did not match any known type",
|
|
1500
1605
|
type: "server_error"
|
|
1501
|
-
}
|
|
1606
|
+
}).body);
|
|
1502
1607
|
}
|
|
1503
1608
|
/** Prepare call IDs once, retaining the engine's effective blocks and exact served-call metadata. */
|
|
1504
1609
|
function prepareResponsesMisbehavior(plan) {
|
|
@@ -1511,7 +1616,11 @@ function buildResponsesMisbehavior(plan, request, chunkSize, emitEncryptedReason
|
|
|
1511
1616
|
const overrides = extractOverrides(response);
|
|
1512
1617
|
const reasoning = plan.reasoning ?? ("reasoning" in response ? response.reasoning : void 0);
|
|
1513
1618
|
const webSearches = "webSearches" in response ? response.webSearches : void 0;
|
|
1514
|
-
const
|
|
1619
|
+
const outputWithheld = plan.refusal !== void 0 || plan.summary.fault === "empty-response" || plan.stop === "content_filter" || plan.reasoning !== void 0;
|
|
1620
|
+
const { respId, created, events, prefixOutputItems, nextOutputIndex } = buildResponsePreamble(request.model, chunkSize, reasoning, webSearches, outputWithheld ? {
|
|
1621
|
+
...overrides,
|
|
1622
|
+
files: void 0
|
|
1623
|
+
} : overrides, emitEncryptedReasoning, false, plan.reasoning !== void 0);
|
|
1515
1624
|
const output = [...prefixOutputItems];
|
|
1516
1625
|
let outputIndex = nextOutputIndex;
|
|
1517
1626
|
const incomplete = plan.stop === "length" || plan.stop === "content_filter";
|
|
@@ -1526,6 +1635,7 @@ function buildResponsesMisbehavior(plan, request, chunkSize, emitEncryptedReason
|
|
|
1526
1635
|
type: "message",
|
|
1527
1636
|
role: "assistant",
|
|
1528
1637
|
status: "completed",
|
|
1638
|
+
...overrides.phase !== void 0 ? { phase: overrides.phase } : {},
|
|
1529
1639
|
content: [part]
|
|
1530
1640
|
};
|
|
1531
1641
|
const position = {
|
|
@@ -1568,16 +1678,18 @@ function buildResponsesMisbehavior(plan, request, chunkSize, emitEncryptedReason
|
|
|
1568
1678
|
item
|
|
1569
1679
|
});
|
|
1570
1680
|
output.push(item);
|
|
1571
|
-
} else if (
|
|
1681
|
+
} else if (!outputWithheld) {
|
|
1572
1682
|
const combined = isCombinedFixtureResponse(response);
|
|
1573
1683
|
const blocks = (combined ? resolveServedBlockOutcome(response) : void 0)?.ordered ?? [..."content" in response && typeof response.content === "string" ? [{
|
|
1574
1684
|
type: "text",
|
|
1575
1685
|
text: response.content
|
|
1576
1686
|
}] : [], ...combined || isToolCallResponse(response) ? servedToolCalls(response).map(toolCallFixtureBlock) : []];
|
|
1577
1687
|
let callIndex = 0;
|
|
1688
|
+
const textAnnotations = orderedBlockAnnotations(blocks, overrides.citations);
|
|
1689
|
+
let textPos = 0;
|
|
1578
1690
|
for (const block of blocks) {
|
|
1579
1691
|
if (block.type === "text") {
|
|
1580
|
-
const message = buildMessageOutputEvents(block.text, chunkSize, outputIndex);
|
|
1692
|
+
const message = buildMessageOutputEvents(block.text, chunkSize, outputIndex, overrides.phase, textAnnotations[textPos++]);
|
|
1581
1693
|
events.push(...message.events);
|
|
1582
1694
|
output.push(message.msgItem);
|
|
1583
1695
|
} else {
|
|
@@ -1606,11 +1718,7 @@ function buildResponsesMisbehavior(plan, request, chunkSize, emitEncryptedReason
|
|
|
1606
1718
|
status: incomplete ? "incomplete" : responsesStatus(overrides?.finishReason, "completed"),
|
|
1607
1719
|
...incomplete ? { incomplete_details: { reason: plan.stop === "content_filter" ? "content_filter" : "max_output_tokens" } } : {},
|
|
1608
1720
|
output,
|
|
1609
|
-
usage: {
|
|
1610
|
-
input_tokens: usage.prompt_tokens,
|
|
1611
|
-
output_tokens: usage.completion_tokens,
|
|
1612
|
-
total_tokens: usage.total_tokens
|
|
1613
|
-
}
|
|
1721
|
+
usage: render({ usage })
|
|
1614
1722
|
};
|
|
1615
1723
|
events.push({
|
|
1616
1724
|
type: incomplete ? "response.incomplete" : "response.completed",
|