@yolk-sdk/emulators 0.1.0-canary.96
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +21 -0
- package/README.md +2135 -0
- package/dist/anthropic.d.mts +269 -0
- package/dist/anthropic.d.mts.map +1 -0
- package/dist/anthropic.mjs +177 -0
- package/dist/anthropic.mjs.map +1 -0
- package/dist/chat-completions.d.mts +288 -0
- package/dist/chat-completions.d.mts.map +1 -0
- package/dist/chat-completions.mjs +451 -0
- package/dist/chat-completions.mjs.map +1 -0
- package/dist/codex.d.mts +265 -0
- package/dist/codex.d.mts.map +1 -0
- package/dist/codex.mjs +199 -0
- package/dist/codex.mjs.map +1 -0
- package/dist/dropbox/api.d.mts +63 -0
- package/dist/dropbox/api.d.mts.map +1 -0
- package/dist/dropbox/api.mjs +565 -0
- package/dist/dropbox/api.mjs.map +1 -0
- package/dist/dropbox/state.d.mts +136 -0
- package/dist/dropbox/state.d.mts.map +1 -0
- package/dist/dropbox/state.mjs +209 -0
- package/dist/dropbox/state.mjs.map +1 -0
- package/dist/dropbox.d.mts +79 -0
- package/dist/dropbox.d.mts.map +1 -0
- package/dist/dropbox.mjs +124 -0
- package/dist/dropbox.mjs.map +1 -0
- package/dist/email-fixtures.d.mts +36 -0
- package/dist/email-fixtures.d.mts.map +1 -0
- package/dist/email-fixtures.mjs +1080 -0
- package/dist/email-fixtures.mjs.map +1 -0
- package/dist/email.d.mts +160 -0
- package/dist/email.d.mts.map +1 -0
- package/dist/email.mjs +608 -0
- package/dist/email.mjs.map +1 -0
- package/dist/emulator-compose.d.mts +40 -0
- package/dist/emulator-compose.d.mts.map +1 -0
- package/dist/emulator-compose.mjs +91 -0
- package/dist/emulator-compose.mjs.map +1 -0
- package/dist/emulator-http.d.mts +53 -0
- package/dist/emulator-http.d.mts.map +1 -0
- package/dist/emulator-http.mjs +117 -0
- package/dist/emulator-http.mjs.map +1 -0
- package/dist/emulator-kernel.d.mts +176 -0
- package/dist/emulator-kernel.d.mts.map +1 -0
- package/dist/emulator-kernel.mjs +413 -0
- package/dist/emulator-kernel.mjs.map +1 -0
- package/dist/fixture-route.d.mts +129 -0
- package/dist/fixture-route.d.mts.map +1 -0
- package/dist/fixture-route.mjs +257 -0
- package/dist/fixture-route.mjs.map +1 -0
- package/dist/fortnox/api.d.mts +92 -0
- package/dist/fortnox/api.d.mts.map +1 -0
- package/dist/fortnox/api.mjs +750 -0
- package/dist/fortnox/api.mjs.map +1 -0
- package/dist/fortnox/state.d.mts +533 -0
- package/dist/fortnox/state.d.mts.map +1 -0
- package/dist/fortnox/state.mjs +612 -0
- package/dist/fortnox/state.mjs.map +1 -0
- package/dist/fortnox.d.mts +128 -0
- package/dist/fortnox.d.mts.map +1 -0
- package/dist/fortnox.mjs +403 -0
- package/dist/fortnox.mjs.map +1 -0
- package/dist/gateway-evaluate-recordings.d.mts +12 -0
- package/dist/gateway-evaluate-recordings.d.mts.map +1 -0
- package/dist/gateway-evaluate-recordings.mjs +128 -0
- package/dist/gateway-evaluate-recordings.mjs.map +1 -0
- package/dist/gateway.d.mts +272 -0
- package/dist/gateway.d.mts.map +1 -0
- package/dist/gateway.mjs +400 -0
- package/dist/gateway.mjs.map +1 -0
- package/dist/github/api.d.mts +63 -0
- package/dist/github/api.d.mts.map +1 -0
- package/dist/github/api.mjs +527 -0
- package/dist/github/api.mjs.map +1 -0
- package/dist/github/state.d.mts +272 -0
- package/dist/github/state.d.mts.map +1 -0
- package/dist/github/state.mjs +303 -0
- package/dist/github/state.mjs.map +1 -0
- package/dist/github.d.mts +77 -0
- package/dist/github.d.mts.map +1 -0
- package/dist/github.mjs +180 -0
- package/dist/github.mjs.map +1 -0
- package/dist/google/calendar.d.mts +10 -0
- package/dist/google/calendar.d.mts.map +1 -0
- package/dist/google/calendar.mjs +252 -0
- package/dist/google/calendar.mjs.map +1 -0
- package/dist/google/drive.d.mts +8 -0
- package/dist/google/drive.d.mts.map +1 -0
- package/dist/google/drive.mjs +252 -0
- package/dist/google/drive.mjs.map +1 -0
- package/dist/google/gmail.d.mts +10 -0
- package/dist/google/gmail.d.mts.map +1 -0
- package/dist/google/gmail.mjs +591 -0
- package/dist/google/gmail.mjs.map +1 -0
- package/dist/google/shared.d.mts +107 -0
- package/dist/google/shared.d.mts.map +1 -0
- package/dist/google/shared.mjs +146 -0
- package/dist/google/shared.mjs.map +1 -0
- package/dist/google/state.d.mts +385 -0
- package/dist/google/state.d.mts.map +1 -0
- package/dist/google/state.mjs +496 -0
- package/dist/google/state.mjs.map +1 -0
- package/dist/google.d.mts +75 -0
- package/dist/google.d.mts.map +1 -0
- package/dist/google.mjs +210 -0
- package/dist/google.mjs.map +1 -0
- package/dist/linkedin-search/api.d.mts +45 -0
- package/dist/linkedin-search/api.d.mts.map +1 -0
- package/dist/linkedin-search/api.mjs +181 -0
- package/dist/linkedin-search/api.mjs.map +1 -0
- package/dist/linkedin-search/state.d.mts +123 -0
- package/dist/linkedin-search/state.d.mts.map +1 -0
- package/dist/linkedin-search/state.mjs +261 -0
- package/dist/linkedin-search/state.mjs.map +1 -0
- package/dist/linkedin-search.d.mts +69 -0
- package/dist/linkedin-search.d.mts.map +1 -0
- package/dist/linkedin-search.mjs +158 -0
- package/dist/linkedin-search.mjs.map +1 -0
- package/dist/mcp/api.d.mts +44 -0
- package/dist/mcp/api.d.mts.map +1 -0
- package/dist/mcp/api.mjs +557 -0
- package/dist/mcp/api.mjs.map +1 -0
- package/dist/mcp/recordings.d.mts +40 -0
- package/dist/mcp/recordings.d.mts.map +1 -0
- package/dist/mcp/recordings.mjs +2390 -0
- package/dist/mcp/recordings.mjs.map +1 -0
- package/dist/mcp/state.d.mts +71 -0
- package/dist/mcp/state.d.mts.map +1 -0
- package/dist/mcp/state.mjs +83 -0
- package/dist/mcp/state.mjs.map +1 -0
- package/dist/mcp.d.mts +84 -0
- package/dist/mcp.d.mts.map +1 -0
- package/dist/mcp.mjs +241 -0
- package/dist/mcp.mjs.map +1 -0
- package/dist/messages.d.mts +183 -0
- package/dist/messages.d.mts.map +1 -0
- package/dist/messages.mjs +532 -0
- package/dist/messages.mjs.map +1 -0
- package/dist/microsoft/api.d.mts +47 -0
- package/dist/microsoft/api.d.mts.map +1 -0
- package/dist/microsoft/api.mjs +178 -0
- package/dist/microsoft/api.mjs.map +1 -0
- package/dist/microsoft/calendar.d.mts +30 -0
- package/dist/microsoft/calendar.d.mts.map +1 -0
- package/dist/microsoft/calendar.mjs +271 -0
- package/dist/microsoft/calendar.mjs.map +1 -0
- package/dist/microsoft/drive.d.mts +36 -0
- package/dist/microsoft/drive.d.mts.map +1 -0
- package/dist/microsoft/drive.mjs +298 -0
- package/dist/microsoft/drive.mjs.map +1 -0
- package/dist/microsoft/graph.d.mts +198 -0
- package/dist/microsoft/graph.d.mts.map +1 -0
- package/dist/microsoft/graph.mjs +264 -0
- package/dist/microsoft/graph.mjs.map +1 -0
- package/dist/microsoft/mail.d.mts +48 -0
- package/dist/microsoft/mail.d.mts.map +1 -0
- package/dist/microsoft/mail.mjs +488 -0
- package/dist/microsoft/mail.mjs.map +1 -0
- package/dist/microsoft/state.d.mts +480 -0
- package/dist/microsoft/state.d.mts.map +1 -0
- package/dist/microsoft/state.mjs +625 -0
- package/dist/microsoft/state.mjs.map +1 -0
- package/dist/microsoft.d.mts +168 -0
- package/dist/microsoft.d.mts.map +1 -0
- package/dist/microsoft.mjs +483 -0
- package/dist/microsoft.mjs.map +1 -0
- package/dist/node.d.mts +47 -0
- package/dist/node.d.mts.map +1 -0
- package/dist/node.mjs +178 -0
- package/dist/node.mjs.map +1 -0
- package/dist/notion/api.d.mts +51 -0
- package/dist/notion/api.d.mts.map +1 -0
- package/dist/notion/api.mjs +507 -0
- package/dist/notion/api.mjs.map +1 -0
- package/dist/notion/state.d.mts +329 -0
- package/dist/notion/state.d.mts.map +1 -0
- package/dist/notion/state.mjs +432 -0
- package/dist/notion/state.mjs.map +1 -0
- package/dist/notion.d.mts +72 -0
- package/dist/notion.d.mts.map +1 -0
- package/dist/notion.mjs +127 -0
- package/dist/notion.mjs.map +1 -0
- package/dist/openai.d.mts +165 -0
- package/dist/openai.d.mts.map +1 -0
- package/dist/openai.mjs +141 -0
- package/dist/openai.mjs.map +1 -0
- package/dist/opencode-recordings.d.mts +7 -0
- package/dist/opencode-recordings.d.mts.map +1 -0
- package/dist/opencode-recordings.mjs +222 -0
- package/dist/opencode-recordings.mjs.map +1 -0
- package/dist/opencode.d.mts +70 -0
- package/dist/opencode.d.mts.map +1 -0
- package/dist/opencode.mjs +217 -0
- package/dist/opencode.mjs.map +1 -0
- package/dist/r2-fixtures.d.mts +36 -0
- package/dist/r2-fixtures.d.mts.map +1 -0
- package/dist/r2-fixtures.mjs +245 -0
- package/dist/r2-fixtures.mjs.map +1 -0
- package/dist/r2-guard.d.mts +43 -0
- package/dist/r2-guard.d.mts.map +1 -0
- package/dist/r2-guard.mjs +215 -0
- package/dist/r2-guard.mjs.map +1 -0
- package/dist/r2.d.mts +166 -0
- package/dist/r2.d.mts.map +1 -0
- package/dist/r2.mjs +517 -0
- package/dist/r2.mjs.map +1 -0
- package/dist/responses.d.mts +231 -0
- package/dist/responses.d.mts.map +1 -0
- package/dist/responses.mjs +556 -0
- package/dist/responses.mjs.map +1 -0
- package/dist/route-evidence.d.mts +45 -0
- package/dist/route-evidence.d.mts.map +1 -0
- package/dist/route-evidence.mjs +56 -0
- package/dist/route-evidence.mjs.map +1 -0
- package/dist/router.d.mts +93 -0
- package/dist/router.d.mts.map +1 -0
- package/dist/router.mjs +259 -0
- package/dist/router.mjs.map +1 -0
- package/dist/stateful-core.d.mts +17 -0
- package/dist/stateful-core.d.mts.map +1 -0
- package/dist/stateful-core.mjs +41 -0
- package/dist/stateful-core.mjs.map +1 -0
- package/dist/stateful-emulator.d.mts +565 -0
- package/dist/stateful-emulator.d.mts.map +1 -0
- package/dist/stateful-emulator.mjs +1228 -0
- package/dist/stateful-emulator.mjs.map +1 -0
- package/dist/stateful-secrets.d.mts +84 -0
- package/dist/stateful-secrets.d.mts.map +1 -0
- package/dist/stateful-secrets.mjs +216 -0
- package/dist/stateful-secrets.mjs.map +1 -0
- package/dist/subscription-usage-recordings.d.mts +9 -0
- package/dist/subscription-usage-recordings.d.mts.map +1 -0
- package/dist/subscription-usage-recordings.mjs +53 -0
- package/dist/subscription-usage-recordings.mjs.map +1 -0
- package/dist/subscription-usage.d.mts +53 -0
- package/dist/subscription-usage.d.mts.map +1 -0
- package/dist/subscription-usage.mjs +21 -0
- package/dist/subscription-usage.mjs.map +1 -0
- package/dist/telegram/api.d.mts +34 -0
- package/dist/telegram/api.d.mts.map +1 -0
- package/dist/telegram/api.mjs +257 -0
- package/dist/telegram/api.mjs.map +1 -0
- package/dist/telegram/state.d.mts +128 -0
- package/dist/telegram/state.d.mts.map +1 -0
- package/dist/telegram/state.mjs +154 -0
- package/dist/telegram/state.mjs.map +1 -0
- package/dist/telegram.d.mts +62 -0
- package/dist/telegram.d.mts.map +1 -0
- package/dist/telegram.mjs +127 -0
- package/dist/telegram.mjs.map +1 -0
- package/dist/todoist/api.d.mts +55 -0
- package/dist/todoist/api.d.mts.map +1 -0
- package/dist/todoist/api.mjs +415 -0
- package/dist/todoist/api.mjs.map +1 -0
- package/dist/todoist/state.d.mts +275 -0
- package/dist/todoist/state.d.mts.map +1 -0
- package/dist/todoist/state.mjs +345 -0
- package/dist/todoist/state.mjs.map +1 -0
- package/dist/todoist.d.mts +68 -0
- package/dist/todoist.d.mts.map +1 -0
- package/dist/todoist.mjs +181 -0
- package/dist/todoist.mjs.map +1 -0
- package/dist/xai.d.mts +267 -0
- package/dist/xai.d.mts.map +1 -0
- package/dist/xai.mjs +252 -0
- package/dist/xai.mjs.map +1 -0
- package/package.json +157 -0
- package/src/anthropic.ts +289 -0
- package/src/chat-completions.ts +924 -0
- package/src/codex.ts +296 -0
- package/src/dropbox/api.ts +1084 -0
- package/src/dropbox/state.ts +364 -0
- package/src/dropbox.ts +203 -0
- package/src/email-fixtures.ts +1297 -0
- package/src/email.ts +1108 -0
- package/src/emulator-compose.ts +147 -0
- package/src/emulator-http.ts +184 -0
- package/src/emulator-kernel.ts +844 -0
- package/src/fixture-route.ts +561 -0
- package/src/fortnox/api.ts +1352 -0
- package/src/fortnox/state.ts +798 -0
- package/src/fortnox.ts +801 -0
- package/src/gateway-evaluate-recordings.ts +153 -0
- package/src/gateway.ts +530 -0
- package/src/github/api.ts +986 -0
- package/src/github/state.ts +439 -0
- package/src/github.ts +271 -0
- package/src/google/calendar.ts +486 -0
- package/src/google/drive.ts +471 -0
- package/src/google/gmail.ts +1011 -0
- package/src/google/shared.ts +321 -0
- package/src/google/state.ts +686 -0
- package/src/google.ts +298 -0
- package/src/linkedin-search/api.ts +363 -0
- package/src/linkedin-search/state.ts +373 -0
- package/src/linkedin-search.ts +241 -0
- package/src/mcp/api.ts +995 -0
- package/src/mcp/recordings.ts +2665 -0
- package/src/mcp/state.ts +125 -0
- package/src/mcp.ts +319 -0
- package/src/messages.ts +844 -0
- package/src/microsoft/api.ts +426 -0
- package/src/microsoft/calendar.ts +491 -0
- package/src/microsoft/drive.ts +541 -0
- package/src/microsoft/graph.ts +550 -0
- package/src/microsoft/mail.ts +833 -0
- package/src/microsoft/state.ts +822 -0
- package/src/microsoft.ts +982 -0
- package/src/node.ts +293 -0
- package/src/notion/api.ts +976 -0
- package/src/notion/state.ts +512 -0
- package/src/notion.ts +210 -0
- package/src/openai.ts +198 -0
- package/src/opencode-recordings.ts +257 -0
- package/src/opencode.ts +271 -0
- package/src/r2-fixtures.ts +295 -0
- package/src/r2-guard.ts +323 -0
- package/src/r2.ts +890 -0
- package/src/responses.ts +901 -0
- package/src/route-evidence.ts +90 -0
- package/src/router.ts +490 -0
- package/src/stateful-core.ts +70 -0
- package/src/stateful-emulator.ts +2571 -0
- package/src/stateful-secrets.ts +299 -0
- package/src/subscription-usage-recordings.ts +77 -0
- package/src/subscription-usage.ts +68 -0
- package/src/telegram/api.ts +437 -0
- package/src/telegram/state.ts +229 -0
- package/src/telegram.ts +227 -0
- package/src/todoist/api.ts +736 -0
- package/src/todoist/state.ts +456 -0
- package/src/todoist.ts +316 -0
- package/src/xai.ts +341 -0
|
@@ -0,0 +1,556 @@
|
|
|
1
|
+
import { emulatorRouteKey } from "./route-evidence.mjs";
|
|
2
|
+
import { ChunkCount, EmulatorErrorAfterChunksFault, EmulatorScriptedError, EmulatorStatusFault, EmulatorTruncateAfterChunksFault, approximateTokens, controlError, emulatorFaultFields, isJsonObject, jsonField, jsonResponse, makeEmulatorKernel, parseJson, readText, splitFragments, stringField, synthesizeValue } from "./emulator-kernel.mjs";
|
|
3
|
+
import { Predicate, Result } from "effect";
|
|
4
|
+
import * as Schema from "effect/Schema";
|
|
5
|
+
//#region src/responses.ts
|
|
6
|
+
/**
|
|
7
|
+
* OpenAI Responses emulator core (internal; not a package export).
|
|
8
|
+
*
|
|
9
|
+
* One `POST .../responses` route with request parsing (`model`, `input`, `instructions`, `tools`,
|
|
10
|
+
* `tool_choice`, `reasoning`, `stream`, `store`, `max_output_tokens`), Responses SSE with typed
|
|
11
|
+
* `event:` names in the order the API sends them, the non-streamed `response` JSON body, scripted
|
|
12
|
+
* turns, and a JSON error envelope chosen by each subpath. Faults, the request ledger, the
|
|
13
|
+
* `/_emulate/*` control plane, evidence tagging, and route binding come from the shared kernel
|
|
14
|
+
* (`emulator-kernel.ts`).
|
|
15
|
+
*
|
|
16
|
+
* Streamed responses: `response.created` and `response.in_progress`, then per output item
|
|
17
|
+
* `response.output_item.added`, its parts and deltas, and `response.output_item.done`, then
|
|
18
|
+
* `response.completed` with the full `response` (output items and usage). Output items:
|
|
19
|
+
* `reasoning` (one summary part: `response.reasoning_summary_part.added`,
|
|
20
|
+
* `response.reasoning_summary_text.delta` / `.done`, `response.reasoning_summary_part.done`) when
|
|
21
|
+
* the request asks for a reasoning summary, `message` (`response.content_part.added`,
|
|
22
|
+
* `response.output_text.delta` / `.done`, `response.content_part.done`), and `function_call`
|
|
23
|
+
* (`response.function_call_arguments.delta` / `.done`). Every event carries a `sequence_number`.
|
|
24
|
+
*
|
|
25
|
+
* Each subpath supplies its path and manifest, model list, error envelope and unknown-model
|
|
26
|
+
* status, the 401 error for a missing bearer credential, extra header rules (required headers
|
|
27
|
+
* with their status and error, and which non-credential header values the ledger records),
|
|
28
|
+
* whether `max_output_tokens` is accepted, and its input-invalid error. Bearer values are never
|
|
29
|
+
* checked or stored.
|
|
30
|
+
*
|
|
31
|
+
* Runtime-portable Web APIs only (`Request`, `Response`, `ReadableStream`, `TextEncoder`, `URL`);
|
|
32
|
+
* no Node builtins and no SDK imports.
|
|
33
|
+
*/
|
|
34
|
+
/** A mid-stream Responses error: a machine `code` and a message. */
|
|
35
|
+
const ResponsesStreamError = Schema.Struct({
|
|
36
|
+
code: Schema.NonEmptyString,
|
|
37
|
+
message: Schema.String
|
|
38
|
+
});
|
|
39
|
+
/**
|
|
40
|
+
* Send `chunks` SSE events, then one error event and close without `response.completed`:
|
|
41
|
+
* `event: 'error'` (the default) sends `{ type: 'error', code, message }`, and
|
|
42
|
+
* `event: 'response.failed'` sends a `response.failed` event whose `response.error` carries the
|
|
43
|
+
* code and message. The error defaults to `server_error`. Streamed responses only; it must come
|
|
44
|
+
* before `response.completed`.
|
|
45
|
+
*/
|
|
46
|
+
const ResponsesErrorEventFault = Schema.Struct({
|
|
47
|
+
kind: Schema.Literal("error-event-after-chunks"),
|
|
48
|
+
chunks: ChunkCount,
|
|
49
|
+
event: Schema.optionalKey(Schema.Literals(["error", "response.failed"])),
|
|
50
|
+
error: Schema.optionalKey(ResponsesStreamError),
|
|
51
|
+
...emulatorFaultFields
|
|
52
|
+
});
|
|
53
|
+
/**
|
|
54
|
+
* Wire faults: `status` (the body defaults to the subpath's error envelope for the status),
|
|
55
|
+
* `error-after-chunks` (a dropped connection), `truncate-after-chunks` (a clean close, for example
|
|
56
|
+
* before `response.completed`), and `error-event-after-chunks` (a mid-stream `error` or
|
|
57
|
+
* `response.failed` event).
|
|
58
|
+
*/
|
|
59
|
+
const ResponsesFault = Schema.Union([
|
|
60
|
+
EmulatorStatusFault,
|
|
61
|
+
EmulatorErrorAfterChunksFault,
|
|
62
|
+
EmulatorTruncateAfterChunksFault,
|
|
63
|
+
ResponsesErrorEventFault
|
|
64
|
+
]);
|
|
65
|
+
const TokenCount = Schema.Int.check(Schema.isGreaterThanOrEqualTo(0));
|
|
66
|
+
/** Usage for a scripted turn (sent in `response.completed` or the JSON body). */
|
|
67
|
+
const ResponsesScriptedUsage = Schema.Struct({
|
|
68
|
+
inputTokens: TokenCount,
|
|
69
|
+
outputTokens: TokenCount,
|
|
70
|
+
reasoningTokens: Schema.optionalKey(TokenCount)
|
|
71
|
+
});
|
|
72
|
+
/** One scripted `function_call` item; its arguments stream as these fragments. */
|
|
73
|
+
const ResponsesScriptedFunctionCall = Schema.Struct({
|
|
74
|
+
name: Schema.NonEmptyString,
|
|
75
|
+
argumentFragments: Schema.Array(Schema.String),
|
|
76
|
+
callId: Schema.optionalKey(Schema.NonEmptyString)
|
|
77
|
+
});
|
|
78
|
+
/**
|
|
79
|
+
* A scripted response. Every field is exact (nothing is filled in) except: an item is sent only
|
|
80
|
+
* when its field is present (`reasoning` is one summary part, `text` one message); `usage`
|
|
81
|
+
* omitted is synthesized and `null` drops `usage` from the wire; `order` defaults to
|
|
82
|
+
* `reasoning-first` (`text-first` sends the reasoning item after the message); `format` defaults
|
|
83
|
+
* to the request's `stream` (`sse` streams even for `stream: false`, `json` answers one JSON body
|
|
84
|
+
* even for `stream: true`, as the JSON fallback some endpoints use).
|
|
85
|
+
*/
|
|
86
|
+
const ResponsesScriptedResponse = Schema.Struct({
|
|
87
|
+
reasoning: Schema.optionalKey(Schema.Array(Schema.String)),
|
|
88
|
+
text: Schema.optionalKey(Schema.Array(Schema.String)),
|
|
89
|
+
functionCalls: Schema.optionalKey(Schema.Array(ResponsesScriptedFunctionCall)),
|
|
90
|
+
order: Schema.optionalKey(Schema.Literals(["reasoning-first", "text-first"])),
|
|
91
|
+
usage: Schema.optionalKey(Schema.NullOr(ResponsesScriptedUsage)),
|
|
92
|
+
format: Schema.optionalKey(Schema.Literals(["sse", "json"]))
|
|
93
|
+
});
|
|
94
|
+
/** A turn queued for the next Responses request. */
|
|
95
|
+
const ResponsesScriptedTurn = Schema.Union([EmulatorScriptedError, ResponsesScriptedResponse]);
|
|
96
|
+
const ResponsesTool = Schema.Struct({
|
|
97
|
+
type: Schema.optionalKey(Schema.String),
|
|
98
|
+
name: Schema.optionalKey(Schema.String),
|
|
99
|
+
description: Schema.optionalKey(Schema.NullOr(Schema.String)),
|
|
100
|
+
parameters: Schema.optionalKey(Schema.Json)
|
|
101
|
+
});
|
|
102
|
+
const ResponsesRequest = Schema.Struct({
|
|
103
|
+
model: Schema.optionalKey(Schema.String),
|
|
104
|
+
input: Schema.Union([Schema.String, Schema.Array(Schema.Json)]),
|
|
105
|
+
instructions: Schema.optionalKey(Schema.NullOr(Schema.String)),
|
|
106
|
+
tools: Schema.optionalKey(Schema.NullOr(Schema.Array(ResponsesTool))),
|
|
107
|
+
tool_choice: Schema.optionalKey(Schema.Json),
|
|
108
|
+
reasoning: Schema.optionalKey(Schema.Json),
|
|
109
|
+
stream: Schema.optionalKey(Schema.NullOr(Schema.Boolean)),
|
|
110
|
+
store: Schema.optionalKey(Schema.NullOr(Schema.Boolean)),
|
|
111
|
+
max_output_tokens: Schema.optionalKey(Schema.Json)
|
|
112
|
+
});
|
|
113
|
+
const decodeResponsesRequest = Schema.decodeUnknownResult(ResponsesRequest);
|
|
114
|
+
const syntheticCreated = 179e7;
|
|
115
|
+
const bearerPattern = /^bearer\s+\S+/i;
|
|
116
|
+
const defaultReasoning = ["The user wants a short reply.", " Keep it brief."];
|
|
117
|
+
const defaultStreamError = {
|
|
118
|
+
code: "server_error",
|
|
119
|
+
message: "Synthetic: the server had an error while processing the request."
|
|
120
|
+
};
|
|
121
|
+
/** A reasoning summary is streamed when the request's `reasoning` asks for one. */
|
|
122
|
+
const summaryRequested = (request) => {
|
|
123
|
+
const summary = stringField(request.reasoning, "summary");
|
|
124
|
+
return summary !== void 0 && summary.length > 0;
|
|
125
|
+
};
|
|
126
|
+
const functionTools = (request) => (request.tools ?? []).flatMap((tool) => (tool.type === void 0 || tool.type === "function") && tool.name !== void 0 ? [{
|
|
127
|
+
name: tool.name,
|
|
128
|
+
parameters: tool.parameters
|
|
129
|
+
}] : []);
|
|
130
|
+
const chosenTool = (request) => {
|
|
131
|
+
const tools = functionTools(request);
|
|
132
|
+
if (tools.length === 0 || request.tool_choice === "none") return;
|
|
133
|
+
const forced = stringField(request.tool_choice, "type") === "function" ? stringField(request.tool_choice, "name") : void 0;
|
|
134
|
+
return tools.find((tool) => tool.name === forced) ?? tools[0];
|
|
135
|
+
};
|
|
136
|
+
const defaultPlan = (request, seq, defaultText) => {
|
|
137
|
+
const reasoning = summaryRequested(request) ? [{
|
|
138
|
+
type: "reasoning",
|
|
139
|
+
id: `rs_synthetic_${seq}_0`,
|
|
140
|
+
fragments: defaultReasoning
|
|
141
|
+
}] : [];
|
|
142
|
+
const tool = chosenTool(request);
|
|
143
|
+
if (tool === void 0) return {
|
|
144
|
+
items: [...reasoning, {
|
|
145
|
+
type: "message",
|
|
146
|
+
id: `msg_synthetic_${seq}_0`,
|
|
147
|
+
fragments: defaultText
|
|
148
|
+
}],
|
|
149
|
+
usage: void 0,
|
|
150
|
+
format: void 0
|
|
151
|
+
};
|
|
152
|
+
const argumentsText = JSON.stringify(synthesizeValue(tool.parameters ?? { type: "object" }, tool.name, 0));
|
|
153
|
+
return {
|
|
154
|
+
items: [...reasoning, {
|
|
155
|
+
type: "function_call",
|
|
156
|
+
id: `fc_synthetic_${seq}_0`,
|
|
157
|
+
callId: `call_synthetic_${seq}_0`,
|
|
158
|
+
name: tool.name,
|
|
159
|
+
fragments: splitFragments(argumentsText, 3)
|
|
160
|
+
}],
|
|
161
|
+
usage: void 0,
|
|
162
|
+
format: void 0
|
|
163
|
+
};
|
|
164
|
+
};
|
|
165
|
+
const scriptedPlan = (turn, seq) => {
|
|
166
|
+
const reasoning = turn.reasoning === void 0 ? [] : [{
|
|
167
|
+
type: "reasoning",
|
|
168
|
+
id: `rs_synthetic_${seq}_0`,
|
|
169
|
+
fragments: turn.reasoning
|
|
170
|
+
}];
|
|
171
|
+
const message = turn.text === void 0 ? [] : [{
|
|
172
|
+
type: "message",
|
|
173
|
+
id: `msg_synthetic_${seq}_0`,
|
|
174
|
+
fragments: turn.text
|
|
175
|
+
}];
|
|
176
|
+
const calls = (turn.functionCalls ?? []).map((call, index) => ({
|
|
177
|
+
type: "function_call",
|
|
178
|
+
id: `fc_synthetic_${seq}_${index}`,
|
|
179
|
+
callId: call.callId ?? `call_synthetic_${seq}_${index}`,
|
|
180
|
+
name: call.name,
|
|
181
|
+
fragments: call.argumentFragments
|
|
182
|
+
}));
|
|
183
|
+
return {
|
|
184
|
+
items: turn.order === "text-first" ? [
|
|
185
|
+
...message,
|
|
186
|
+
...reasoning,
|
|
187
|
+
...calls
|
|
188
|
+
] : [
|
|
189
|
+
...reasoning,
|
|
190
|
+
...message,
|
|
191
|
+
...calls
|
|
192
|
+
],
|
|
193
|
+
usage: turn.usage,
|
|
194
|
+
format: turn.format
|
|
195
|
+
};
|
|
196
|
+
};
|
|
197
|
+
const planUsage = (plan, requestText) => {
|
|
198
|
+
if (plan.usage === null) return;
|
|
199
|
+
const reasoningText = plan.items.flatMap((item) => item.type === "reasoning" ? item.fragments : []).join("");
|
|
200
|
+
const usage = plan.usage ?? {
|
|
201
|
+
inputTokens: approximateTokens(requestText),
|
|
202
|
+
outputTokens: approximateTokens(plan.items.flatMap((item) => item.fragments).join("")),
|
|
203
|
+
reasoningTokens: reasoningText.length > 0 ? approximateTokens(reasoningText) : 0
|
|
204
|
+
};
|
|
205
|
+
return {
|
|
206
|
+
input_tokens: usage.inputTokens,
|
|
207
|
+
input_tokens_details: { cached_tokens: 0 },
|
|
208
|
+
output_tokens: usage.outputTokens,
|
|
209
|
+
output_tokens_details: { reasoning_tokens: usage.reasoningTokens ?? 0 },
|
|
210
|
+
total_tokens: usage.inputTokens + usage.outputTokens
|
|
211
|
+
};
|
|
212
|
+
};
|
|
213
|
+
const responseObject = (identity, status, output) => ({
|
|
214
|
+
id: identity.id,
|
|
215
|
+
object: "response",
|
|
216
|
+
created_at: syntheticCreated,
|
|
217
|
+
status,
|
|
218
|
+
error: null,
|
|
219
|
+
incomplete_details: null,
|
|
220
|
+
model: identity.model,
|
|
221
|
+
output
|
|
222
|
+
});
|
|
223
|
+
const outputText = (text) => ({
|
|
224
|
+
type: "output_text",
|
|
225
|
+
text,
|
|
226
|
+
annotations: []
|
|
227
|
+
});
|
|
228
|
+
const summaryText = (text) => ({
|
|
229
|
+
type: "summary_text",
|
|
230
|
+
text
|
|
231
|
+
});
|
|
232
|
+
/** The complete wire item (as in `response.output_item.done` and the final `output`). */
|
|
233
|
+
const completeItem = (item) => {
|
|
234
|
+
const text = item.fragments.join("");
|
|
235
|
+
switch (item.type) {
|
|
236
|
+
case "reasoning": return {
|
|
237
|
+
id: item.id,
|
|
238
|
+
type: "reasoning",
|
|
239
|
+
summary: item.fragments.length === 0 ? [] : [summaryText(text)]
|
|
240
|
+
};
|
|
241
|
+
case "message": return {
|
|
242
|
+
id: item.id,
|
|
243
|
+
type: "message",
|
|
244
|
+
status: "completed",
|
|
245
|
+
role: "assistant",
|
|
246
|
+
content: [outputText(text)]
|
|
247
|
+
};
|
|
248
|
+
case "function_call": return {
|
|
249
|
+
id: item.id,
|
|
250
|
+
type: "function_call",
|
|
251
|
+
status: "completed",
|
|
252
|
+
call_id: item.callId,
|
|
253
|
+
name: item.name,
|
|
254
|
+
arguments: text
|
|
255
|
+
};
|
|
256
|
+
}
|
|
257
|
+
};
|
|
258
|
+
/** The item as first announced in `response.output_item.added`. */
|
|
259
|
+
const addedItem = (item) => {
|
|
260
|
+
switch (item.type) {
|
|
261
|
+
case "reasoning": return {
|
|
262
|
+
id: item.id,
|
|
263
|
+
type: "reasoning",
|
|
264
|
+
summary: []
|
|
265
|
+
};
|
|
266
|
+
case "message": return {
|
|
267
|
+
id: item.id,
|
|
268
|
+
type: "message",
|
|
269
|
+
status: "in_progress",
|
|
270
|
+
role: "assistant",
|
|
271
|
+
content: []
|
|
272
|
+
};
|
|
273
|
+
case "function_call": return {
|
|
274
|
+
id: item.id,
|
|
275
|
+
type: "function_call",
|
|
276
|
+
status: "in_progress",
|
|
277
|
+
call_id: item.callId,
|
|
278
|
+
name: item.name,
|
|
279
|
+
arguments: ""
|
|
280
|
+
};
|
|
281
|
+
}
|
|
282
|
+
};
|
|
283
|
+
const sseEvent = (type, sequence, payload) => `event: ${type}\ndata: ${JSON.stringify({
|
|
284
|
+
type,
|
|
285
|
+
sequence_number: sequence,
|
|
286
|
+
...payload
|
|
287
|
+
})}\n\n`;
|
|
288
|
+
/** Builds SSE events with increasing `sequence_number`s, one network chunk each. */
|
|
289
|
+
const makeEventWriter = () => {
|
|
290
|
+
const events = [];
|
|
291
|
+
return {
|
|
292
|
+
events,
|
|
293
|
+
push: (type, payload) => {
|
|
294
|
+
events.push(sseEvent(type, events.length, payload));
|
|
295
|
+
}
|
|
296
|
+
};
|
|
297
|
+
};
|
|
298
|
+
const itemEvents = (writer, item, outputIndex) => {
|
|
299
|
+
const text = item.fragments.join("");
|
|
300
|
+
const ids = {
|
|
301
|
+
item_id: item.id,
|
|
302
|
+
output_index: outputIndex
|
|
303
|
+
};
|
|
304
|
+
writer.push("response.output_item.added", {
|
|
305
|
+
output_index: outputIndex,
|
|
306
|
+
item: addedItem(item)
|
|
307
|
+
});
|
|
308
|
+
switch (item.type) {
|
|
309
|
+
case "reasoning":
|
|
310
|
+
if (item.fragments.length > 0) {
|
|
311
|
+
const part = {
|
|
312
|
+
...ids,
|
|
313
|
+
summary_index: 0
|
|
314
|
+
};
|
|
315
|
+
writer.push("response.reasoning_summary_part.added", {
|
|
316
|
+
...part,
|
|
317
|
+
part: summaryText("")
|
|
318
|
+
});
|
|
319
|
+
for (const fragment of item.fragments) writer.push("response.reasoning_summary_text.delta", {
|
|
320
|
+
...part,
|
|
321
|
+
delta: fragment
|
|
322
|
+
});
|
|
323
|
+
writer.push("response.reasoning_summary_text.done", {
|
|
324
|
+
...part,
|
|
325
|
+
text
|
|
326
|
+
});
|
|
327
|
+
writer.push("response.reasoning_summary_part.done", {
|
|
328
|
+
...part,
|
|
329
|
+
part: summaryText(text)
|
|
330
|
+
});
|
|
331
|
+
}
|
|
332
|
+
break;
|
|
333
|
+
case "message": {
|
|
334
|
+
const part = {
|
|
335
|
+
...ids,
|
|
336
|
+
content_index: 0
|
|
337
|
+
};
|
|
338
|
+
writer.push("response.content_part.added", {
|
|
339
|
+
...part,
|
|
340
|
+
part: outputText("")
|
|
341
|
+
});
|
|
342
|
+
for (const fragment of item.fragments) writer.push("response.output_text.delta", {
|
|
343
|
+
...part,
|
|
344
|
+
delta: fragment
|
|
345
|
+
});
|
|
346
|
+
writer.push("response.output_text.done", {
|
|
347
|
+
...part,
|
|
348
|
+
text
|
|
349
|
+
});
|
|
350
|
+
writer.push("response.content_part.done", {
|
|
351
|
+
...part,
|
|
352
|
+
part: outputText(text)
|
|
353
|
+
});
|
|
354
|
+
break;
|
|
355
|
+
}
|
|
356
|
+
case "function_call":
|
|
357
|
+
for (const fragment of item.fragments) writer.push("response.function_call_arguments.delta", {
|
|
358
|
+
...ids,
|
|
359
|
+
delta: fragment
|
|
360
|
+
});
|
|
361
|
+
writer.push("response.function_call_arguments.done", {
|
|
362
|
+
...ids,
|
|
363
|
+
arguments: text
|
|
364
|
+
});
|
|
365
|
+
break;
|
|
366
|
+
}
|
|
367
|
+
writer.push("response.output_item.done", {
|
|
368
|
+
output_index: outputIndex,
|
|
369
|
+
item: completeItem(item)
|
|
370
|
+
});
|
|
371
|
+
};
|
|
372
|
+
/** The completed `response` object (for `response.completed` and the JSON body). */
|
|
373
|
+
const completedResponse = (plan, identity, usage) => {
|
|
374
|
+
const response = responseObject(identity, "completed", plan.items.map(completeItem));
|
|
375
|
+
if (usage !== void 0) response.usage = usage;
|
|
376
|
+
return response;
|
|
377
|
+
};
|
|
378
|
+
/** SSE events for a streamed response, one network chunk each, in the API's order. */
|
|
379
|
+
const streamEvents = (plan, identity, usage) => {
|
|
380
|
+
const writer = makeEventWriter();
|
|
381
|
+
const inProgress = {
|
|
382
|
+
...responseObject(identity, "in_progress", []),
|
|
383
|
+
usage: null
|
|
384
|
+
};
|
|
385
|
+
writer.push("response.created", { response: inProgress });
|
|
386
|
+
writer.push("response.in_progress", { response: inProgress });
|
|
387
|
+
plan.items.forEach((item, index) => itemEvents(writer, item, index));
|
|
388
|
+
writer.push("response.completed", { response: completedResponse(plan, identity, usage) });
|
|
389
|
+
return writer.events;
|
|
390
|
+
};
|
|
391
|
+
/** The mid-stream error event of an `error-event-after-chunks` fault. */
|
|
392
|
+
const errorEvent = (fault, identity, sequence) => {
|
|
393
|
+
const error = fault.error ?? defaultStreamError;
|
|
394
|
+
if (fault.event === "response.failed") return sseEvent("response.failed", sequence, { response: {
|
|
395
|
+
...responseObject(identity, "failed", []),
|
|
396
|
+
error: {
|
|
397
|
+
code: error.code,
|
|
398
|
+
message: error.message
|
|
399
|
+
},
|
|
400
|
+
usage: null
|
|
401
|
+
} });
|
|
402
|
+
return sseEvent("error", sequence, {
|
|
403
|
+
code: error.code,
|
|
404
|
+
message: error.message,
|
|
405
|
+
param: null
|
|
406
|
+
});
|
|
407
|
+
};
|
|
408
|
+
const isPositiveInteger = (value) => Predicate.isNumber(value) && Number.isSafeInteger(value) && value > 0;
|
|
409
|
+
/**
|
|
410
|
+
* Create a Responses emulator from its config. Each call has independent ledger, fault, and
|
|
411
|
+
* script state.
|
|
412
|
+
*
|
|
413
|
+
* Precedence per request: the bearer credential, the header rules in order, JSON and request
|
|
414
|
+
* validation (an `input` string or array, and the `max_output_tokens` policy), then the first
|
|
415
|
+
* matching fault if it is a `status` fault, then the next scripted turn, then model validation and
|
|
416
|
+
* defaults; a first matching body fault then shapes the body. Only the first matching fault (in
|
|
417
|
+
* insertion order) applies. Credential headers are never recorded, and credential values are
|
|
418
|
+
* never checked or stored.
|
|
419
|
+
*/
|
|
420
|
+
const makeResponsesEmulator = (config) => {
|
|
421
|
+
const knownModels = [...config.knownModels];
|
|
422
|
+
const errorResponse = (status, error) => jsonResponse(status, config.errorEnvelope(error));
|
|
423
|
+
const invalidRequest = (message, code, param) => errorResponse(400, param === void 0 ? {
|
|
424
|
+
message,
|
|
425
|
+
type: "invalid_request_error",
|
|
426
|
+
code
|
|
427
|
+
} : {
|
|
428
|
+
message,
|
|
429
|
+
type: "invalid_request_error",
|
|
430
|
+
code,
|
|
431
|
+
param
|
|
432
|
+
});
|
|
433
|
+
const defaultFaultBody = (status) => status === 429 ? config.errorEnvelope({
|
|
434
|
+
message: "Synthetic rate limit: too many requests.",
|
|
435
|
+
type: "rate_limit_exceeded",
|
|
436
|
+
code: "rate_limit_exceeded"
|
|
437
|
+
}) : config.errorEnvelope({
|
|
438
|
+
message: `Synthetic upstream error (${status}).`,
|
|
439
|
+
type: status >= 500 ? "server_error" : "api_error",
|
|
440
|
+
code: status >= 500 ? "server_error" : "upstream_error"
|
|
441
|
+
});
|
|
442
|
+
const kernel = makeEmulatorKernel({
|
|
443
|
+
routes: config.routes,
|
|
444
|
+
faultSchema: ResponsesFault,
|
|
445
|
+
turnSchema: ResponsesScriptedTurn,
|
|
446
|
+
newEntry: (base) => ({
|
|
447
|
+
...base,
|
|
448
|
+
toolNames: [],
|
|
449
|
+
headers: {}
|
|
450
|
+
}),
|
|
451
|
+
snapshotEntry: (entry) => ({
|
|
452
|
+
...entry,
|
|
453
|
+
toolNames: [...entry.toolNames],
|
|
454
|
+
headers: { ...entry.headers }
|
|
455
|
+
}),
|
|
456
|
+
unknownRoute: () => errorResponse(404, {
|
|
457
|
+
message: "Synthetic: no emulated route.",
|
|
458
|
+
type: "invalid_request_error",
|
|
459
|
+
code: "not_found"
|
|
460
|
+
}),
|
|
461
|
+
stateFields: () => ({ knownModels }),
|
|
462
|
+
inputInvalid: config.inputInvalid
|
|
463
|
+
});
|
|
464
|
+
const responses = async (request, entry, path) => {
|
|
465
|
+
for (const rule of config.headers) {
|
|
466
|
+
const value = request.headers.get(rule.name);
|
|
467
|
+
if (rule.record && value !== null) entry.headers[rule.name] = value;
|
|
468
|
+
}
|
|
469
|
+
if (!bearerPattern.test(request.headers.get("authorization") ?? "")) {
|
|
470
|
+
entry.status = 401;
|
|
471
|
+
return errorResponse(401, config.unauthorized);
|
|
472
|
+
}
|
|
473
|
+
for (const rule of config.headers) if (rule.required !== void 0 && (request.headers.get(rule.name) ?? "").trim().length === 0) {
|
|
474
|
+
entry.status = rule.required.status;
|
|
475
|
+
return errorResponse(rule.required.status, rule.required.error);
|
|
476
|
+
}
|
|
477
|
+
const text = await readText(request);
|
|
478
|
+
const json = text === void 0 ? void 0 : parseJson(text);
|
|
479
|
+
if (text === void 0 || json === void 0) {
|
|
480
|
+
entry.status = 400;
|
|
481
|
+
return invalidRequest("Synthetic: the request body is not valid JSON.", "invalid_json");
|
|
482
|
+
}
|
|
483
|
+
entry.body = json;
|
|
484
|
+
const decoded = decodeResponsesRequest(json);
|
|
485
|
+
if (Result.isFailure(decoded) || !isJsonObject(json)) {
|
|
486
|
+
entry.status = 400;
|
|
487
|
+
return invalidRequest("Synthetic: the request body is not a Responses request (`input` is required).", "invalid_request");
|
|
488
|
+
}
|
|
489
|
+
const body = decoded.success;
|
|
490
|
+
const seq = entry.seq;
|
|
491
|
+
if (body.model !== void 0) entry.model = body.model;
|
|
492
|
+
entry.stream = body.stream === true;
|
|
493
|
+
if (Predicate.isBoolean(body.store)) entry.store = body.store;
|
|
494
|
+
if (body.reasoning !== void 0) entry.reasoning = body.reasoning;
|
|
495
|
+
if (body.tool_choice !== void 0) entry.toolChoice = body.tool_choice;
|
|
496
|
+
entry.toolNames = functionTools(body).map((tool) => tool.name);
|
|
497
|
+
const outputLimit = jsonField(json, "max_output_tokens");
|
|
498
|
+
if (Predicate.isNumber(outputLimit)) entry.maxOutputTokens = outputLimit;
|
|
499
|
+
if (config.outputTokenLimit === "rejected" && outputLimit !== void 0) {
|
|
500
|
+
entry.status = 400;
|
|
501
|
+
return invalidRequest("Synthetic: unsupported parameter: max_output_tokens.", "unsupported_parameter", "max_output_tokens");
|
|
502
|
+
}
|
|
503
|
+
if (outputLimit !== void 0 && outputLimit !== null && !isPositiveInteger(outputLimit)) {
|
|
504
|
+
entry.status = 400;
|
|
505
|
+
return invalidRequest("Synthetic: max_output_tokens must be a positive integer.", "invalid_value", "max_output_tokens");
|
|
506
|
+
}
|
|
507
|
+
const fault = kernel.takeFault(path, body.model);
|
|
508
|
+
if (fault !== void 0 && fault.fault.kind === "status") return kernel.respondWithStatusFault(entry, fault, fault.fault, defaultFaultBody);
|
|
509
|
+
const errorEventFault = fault !== void 0 && fault.fault.kind === "error-event-after-chunks" ? {
|
|
510
|
+
state: fault,
|
|
511
|
+
fault: fault.fault
|
|
512
|
+
} : void 0;
|
|
513
|
+
const cannotApply = (problem) => {
|
|
514
|
+
entry.faultError = problem;
|
|
515
|
+
entry.status = 500;
|
|
516
|
+
return controlError(500, `emulator fault cannot apply: ${problem}`);
|
|
517
|
+
};
|
|
518
|
+
const turn = kernel.nextTurn();
|
|
519
|
+
if (turn !== void 0 && "error" in turn) {
|
|
520
|
+
entry.scripted = "error";
|
|
521
|
+
if (errorEventFault !== void 0) return cannotApply("error-event-after-chunks cannot apply to a scripted error");
|
|
522
|
+
return kernel.respondWithScriptedError(entry, turn.error, fault);
|
|
523
|
+
}
|
|
524
|
+
if (turn === void 0 && (body.model === void 0 || !knownModels.includes(body.model))) {
|
|
525
|
+
entry.status = config.unknownModel.status;
|
|
526
|
+
return errorResponse(config.unknownModel.status, config.unknownModel.error);
|
|
527
|
+
}
|
|
528
|
+
if (turn !== void 0) entry.scripted = "response";
|
|
529
|
+
const plan = turn === void 0 ? defaultPlan(body, seq, config.defaultText) : scriptedPlan(turn, seq);
|
|
530
|
+
const identity = {
|
|
531
|
+
id: `resp_synthetic_${seq}`,
|
|
532
|
+
model: body.model ?? "unknown"
|
|
533
|
+
};
|
|
534
|
+
const usage = planUsage(plan, text);
|
|
535
|
+
if ((plan.format ?? (body.stream === true ? "sse" : "json")) === "json") {
|
|
536
|
+
if (errorEventFault !== void 0) return cannotApply("error-event-after-chunks cannot apply to a JSON response");
|
|
537
|
+
return kernel.respondWithBody(entry, 200, { "content-type": "application/json" }, [JSON.stringify(completedResponse(plan, identity, usage))], fault);
|
|
538
|
+
}
|
|
539
|
+
const events = streamEvents(plan, identity, usage);
|
|
540
|
+
const headers = {
|
|
541
|
+
"content-type": "text/event-stream",
|
|
542
|
+
"cache-control": "no-cache"
|
|
543
|
+
};
|
|
544
|
+
if (errorEventFault === void 0) return kernel.respondWithBody(entry, 200, headers, events, fault);
|
|
545
|
+
const after = errorEventFault.fault.chunks;
|
|
546
|
+
if (after >= events.length) return cannotApply(`error-event-after-chunks after ${after} chunk(s) cannot apply to a response with ${events.length} chunk(s)`);
|
|
547
|
+
const response = kernel.respondWithBody(entry, 200, headers, [...events.slice(0, after), errorEvent(errorEventFault.fault, identity, after)], void 0);
|
|
548
|
+
kernel.consumeFault(errorEventFault.state, entry);
|
|
549
|
+
return response;
|
|
550
|
+
};
|
|
551
|
+
return kernel.serve(new Map([[emulatorRouteKey("POST", config.path), responses]]));
|
|
552
|
+
};
|
|
553
|
+
//#endregion
|
|
554
|
+
export { ResponsesErrorEventFault, ResponsesFault, ResponsesScriptedFunctionCall, ResponsesScriptedResponse, ResponsesScriptedTurn, ResponsesScriptedUsage, ResponsesStreamError, makeResponsesEmulator };
|
|
555
|
+
|
|
556
|
+
//# sourceMappingURL=responses.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"responses.mjs","names":[],"sources":["../src/responses.ts"],"sourcesContent":["/**\n * OpenAI Responses emulator core (internal; not a package export).\n *\n * One `POST .../responses` route with request parsing (`model`, `input`, `instructions`, `tools`,\n * `tool_choice`, `reasoning`, `stream`, `store`, `max_output_tokens`), Responses SSE with typed\n * `event:` names in the order the API sends them, the non-streamed `response` JSON body, scripted\n * turns, and a JSON error envelope chosen by each subpath. Faults, the request ledger, the\n * `/_emulate/*` control plane, evidence tagging, and route binding come from the shared kernel\n * (`emulator-kernel.ts`).\n *\n * Streamed responses: `response.created` and `response.in_progress`, then per output item\n * `response.output_item.added`, its parts and deltas, and `response.output_item.done`, then\n * `response.completed` with the full `response` (output items and usage). Output items:\n * `reasoning` (one summary part: `response.reasoning_summary_part.added`,\n * `response.reasoning_summary_text.delta` / `.done`, `response.reasoning_summary_part.done`) when\n * the request asks for a reasoning summary, `message` (`response.content_part.added`,\n * `response.output_text.delta` / `.done`, `response.content_part.done`), and `function_call`\n * (`response.function_call_arguments.delta` / `.done`). Every event carries a `sequence_number`.\n *\n * Each subpath supplies its path and manifest, model list, error envelope and unknown-model\n * status, the 401 error for a missing bearer credential, extra header rules (required headers\n * with their status and error, and which non-credential header values the ledger records),\n * whether `max_output_tokens` is accepted, and its input-invalid error. Bearer values are never\n * checked or stored.\n *\n * Runtime-portable Web APIs only (`Request`, `Response`, `ReadableStream`, `TextEncoder`, `URL`);\n * no Node builtins and no SDK imports.\n */\nimport { Predicate, Result } from 'effect'\nimport * as Schema from 'effect/Schema'\nimport {\n approximateTokens,\n ChunkCount,\n controlError,\n EmulatorErrorAfterChunksFault,\n emulatorFaultFields,\n EmulatorScriptedError,\n EmulatorStatusFault,\n EmulatorTruncateAfterChunksFault,\n isJsonObject,\n jsonField,\n jsonResponse,\n makeEmulatorKernel,\n parseJson,\n readText,\n splitFragments,\n stringField,\n synthesizeValue,\n type EmulatorApi,\n type KernelLedgerEntry\n} from './emulator-kernel.ts'\nimport {\n emulatorRouteKey,\n type EmulatorEvidence,\n type EmulatorRouteEvidence\n} from './route-evidence.ts'\n\n/** A mid-stream Responses error: a machine `code` and a message. */\nexport const ResponsesStreamError = Schema.Struct({\n code: Schema.NonEmptyString,\n message: Schema.String\n})\n\nexport type ResponsesStreamError = typeof ResponsesStreamError.Type\n\n/**\n * Send `chunks` SSE events, then one error event and close without `response.completed`:\n * `event: 'error'` (the default) sends `{ type: 'error', code, message }`, and\n * `event: 'response.failed'` sends a `response.failed` event whose `response.error` carries the\n * code and message. The error defaults to `server_error`. Streamed responses only; it must come\n * before `response.completed`.\n */\nexport const ResponsesErrorEventFault = Schema.Struct({\n kind: Schema.Literal('error-event-after-chunks'),\n chunks: ChunkCount,\n event: Schema.optionalKey(Schema.Literals(['error', 'response.failed'])),\n error: Schema.optionalKey(ResponsesStreamError),\n ...emulatorFaultFields\n})\n\n/**\n * Wire faults: `status` (the body defaults to the subpath's error envelope for the status),\n * `error-after-chunks` (a dropped connection), `truncate-after-chunks` (a clean close, for example\n * before `response.completed`), and `error-event-after-chunks` (a mid-stream `error` or\n * `response.failed` event).\n */\nexport const ResponsesFault = Schema.Union([\n EmulatorStatusFault,\n EmulatorErrorAfterChunksFault,\n EmulatorTruncateAfterChunksFault,\n ResponsesErrorEventFault\n])\n\nexport type ResponsesFault = typeof ResponsesFault.Type\n\nexport type ResponsesFaultKind = ResponsesFault['kind']\n\nconst TokenCount = Schema.Int.check(Schema.isGreaterThanOrEqualTo(0))\n\n/** Usage for a scripted turn (sent in `response.completed` or the JSON body). */\nexport const ResponsesScriptedUsage = Schema.Struct({\n inputTokens: TokenCount,\n outputTokens: TokenCount,\n reasoningTokens: Schema.optionalKey(TokenCount)\n})\n\nexport type ResponsesScriptedUsage = typeof ResponsesScriptedUsage.Type\n\n/** One scripted `function_call` item; its arguments stream as these fragments. */\nexport const ResponsesScriptedFunctionCall = Schema.Struct({\n name: Schema.NonEmptyString,\n argumentFragments: Schema.Array(Schema.String),\n callId: Schema.optionalKey(Schema.NonEmptyString)\n})\n\nexport type ResponsesScriptedFunctionCall = typeof ResponsesScriptedFunctionCall.Type\n\n/**\n * A scripted response. Every field is exact (nothing is filled in) except: an item is sent only\n * when its field is present (`reasoning` is one summary part, `text` one message); `usage`\n * omitted is synthesized and `null` drops `usage` from the wire; `order` defaults to\n * `reasoning-first` (`text-first` sends the reasoning item after the message); `format` defaults\n * to the request's `stream` (`sse` streams even for `stream: false`, `json` answers one JSON body\n * even for `stream: true`, as the JSON fallback some endpoints use).\n */\nexport const ResponsesScriptedResponse = Schema.Struct({\n reasoning: Schema.optionalKey(Schema.Array(Schema.String)),\n text: Schema.optionalKey(Schema.Array(Schema.String)),\n functionCalls: Schema.optionalKey(Schema.Array(ResponsesScriptedFunctionCall)),\n order: Schema.optionalKey(Schema.Literals(['reasoning-first', 'text-first'])),\n usage: Schema.optionalKey(Schema.NullOr(ResponsesScriptedUsage)),\n format: Schema.optionalKey(Schema.Literals(['sse', 'json']))\n})\n\nexport type ResponsesScriptedResponse = typeof ResponsesScriptedResponse.Type\n\n/** A turn queued for the next Responses request. */\nexport const ResponsesScriptedTurn = Schema.Union([\n EmulatorScriptedError,\n ResponsesScriptedResponse\n])\n\nexport type ResponsesScriptedTurn = typeof ResponsesScriptedTurn.Type\n\nexport type ResponsesLedgerEntry = {\n /** 1-based arrival order since the last ledger clear or reset. */\n readonly seq: number\n readonly method: string\n readonly path: string\n /** Parsed JSON request body, when it was valid JSON. */\n readonly body?: Schema.Json\n readonly model?: string\n readonly stream?: boolean\n readonly store?: boolean\n /** The request's `max_output_tokens`, when it is a number. */\n readonly maxOutputTokens?: number\n readonly reasoning?: Schema.Json\n readonly toolChoice?: Schema.Json\n /** Names of the offered `function` tools. */\n readonly toolNames: ReadonlyArray<string>\n /** Values of the non-credential headers the subpath records (lower-case names). */\n readonly headers: Readonly<Record<string, string>>\n /** Kind of the fault that shaped the response. */\n readonly fault?: ResponsesFaultKind\n /** Why a matching fault could not take effect (the response was a 500 emulator error). */\n readonly faultError?: string\n /**\n * Set when the emulator could not build the planned response; the request was answered with a\n * 500 emulator error (still evidence-tagged) and no fault was used up.\n */\n readonly responseError?: string\n /** Set when a scripted turn answered the request. */\n readonly scripted?: 'response' | 'error'\n /** Evidence of the matched route; `unknown-route` for requests that failed closed. */\n readonly evidence: EmulatorEvidence | 'unknown-route'\n readonly status: number\n /** Body chunks handed to the transport so far (each produced when pulled). */\n readonly bodyChunks: number\n}\n\nexport type ResponsesEmulator = EmulatorApi<\n ResponsesScriptedTurn,\n ResponsesFault,\n ResponsesLedgerEntry\n>\n\n/** A Responses wire error, rendered by the subpath's `errorEnvelope`. */\nexport type ResponsesWireError = {\n readonly message: string\n readonly type: string\n readonly code: string\n readonly param?: string\n}\n\n/**\n * One request header rule. `record` keeps the header value in the ledger `headers` (never set it\n * for credential headers); `required` answers a request without a non-empty value with that\n * status and error (the value itself is never checked).\n */\nexport type ResponsesHeaderRule = {\n /** Lower-case header name. */\n readonly name: string\n readonly record: boolean\n readonly required?: { readonly status: number; readonly error: ResponsesWireError }\n}\n\n/**\n * What differs between Responses emulators. The core owns everything else (framing, faults,\n * scripting, ledger, control plane, evidence).\n */\nexport type ResponsesEmulatorConfig = {\n /** The Responses path, for example `/v1/responses`. */\n readonly path: string\n /** Route evidence manifest; must list exactly the Responses route. */\n readonly routes: ReadonlyArray<EmulatorRouteEvidence>\n readonly knownModels: ReadonlyArray<string>\n /** Renders a wire error as the service's JSON error envelope. */\n readonly errorEnvelope: (error: ResponsesWireError) => Schema.Json\n /** Status and error for an unknown model id. */\n readonly unknownModel: { readonly status: number; readonly error: ResponsesWireError }\n /**\n * Requests authenticate with a non-empty `Authorization: Bearer` credential, never checked or\n * stored; anything else answers 401 with `unauthorized`.\n */\n readonly unauthorized: ResponsesWireError\n /** Extra header rules, checked in order after the bearer credential. */\n readonly headers: ReadonlyArray<ResponsesHeaderRule>\n /**\n * `optional`: `max_output_tokens` may be sent (a positive integer, or 400) and is recorded, not\n * enforced; `rejected`: any `max_output_tokens` answers 400 `unsupported_parameter`.\n */\n readonly outputTokenLimit: 'optional' | 'rejected'\n /** Default answer text deltas. */\n readonly defaultText: ReadonlyArray<string>\n /** Builds the error thrown by the JS API (`faults.add`, `script.enqueue`) for invalid input. */\n readonly inputInvalid: (input: 'fault' | 'turn', reason: string) => Error\n}\n\nconst ResponsesTool = Schema.Struct({\n type: Schema.optionalKey(Schema.String),\n name: Schema.optionalKey(Schema.String),\n description: Schema.optionalKey(Schema.NullOr(Schema.String)),\n parameters: Schema.optionalKey(Schema.Json)\n})\n\nconst ResponsesRequest = Schema.Struct({\n model: Schema.optionalKey(Schema.String),\n input: Schema.Union([Schema.String, Schema.Array(Schema.Json)]),\n instructions: Schema.optionalKey(Schema.NullOr(Schema.String)),\n tools: Schema.optionalKey(Schema.NullOr(Schema.Array(ResponsesTool))),\n tool_choice: Schema.optionalKey(Schema.Json),\n reasoning: Schema.optionalKey(Schema.Json),\n stream: Schema.optionalKey(Schema.NullOr(Schema.Boolean)),\n store: Schema.optionalKey(Schema.NullOr(Schema.Boolean)),\n max_output_tokens: Schema.optionalKey(Schema.Json)\n})\n\ntype ResponsesRequest = typeof ResponsesRequest.Type\n\nconst decodeResponsesRequest = Schema.decodeUnknownResult(ResponsesRequest)\n\n// Synthetic creation time shared by every emulated response (deterministic output).\nconst syntheticCreated = 1790000000\n\n// A non-empty bearer credential. The value is never checked or stored.\nconst bearerPattern = /^bearer\\s+\\S+/i\n\nconst defaultReasoning = ['The user wants a short reply.', ' Keep it brief.']\n\nconst defaultStreamError: ResponsesStreamError = {\n code: 'server_error',\n message: 'Synthetic: the server had an error while processing the request.'\n}\n\ntype ItemPlan =\n | { readonly type: 'reasoning'; readonly id: string; readonly fragments: ReadonlyArray<string> }\n | { readonly type: 'message'; readonly id: string; readonly fragments: ReadonlyArray<string> }\n | {\n readonly type: 'function_call'\n readonly id: string\n readonly callId: string\n readonly name: string\n readonly fragments: ReadonlyArray<string>\n }\n\ntype ResponsePlan = {\n readonly items: ReadonlyArray<ItemPlan>\n /** `null`: never send usage; `undefined`: synthesize. */\n readonly usage: ResponsesScriptedUsage | null | undefined\n /** `undefined`: follow the request's `stream`. */\n readonly format: 'sse' | 'json' | undefined\n}\n\n/** A reasoning summary is streamed when the request's `reasoning` asks for one. */\nconst summaryRequested = (request: ResponsesRequest): boolean => {\n const summary = stringField(request.reasoning, 'summary')\n\n return summary !== undefined && summary.length > 0\n}\n\nconst functionTools = (request: ResponsesRequest) =>\n (request.tools ?? []).flatMap(tool =>\n (tool.type === undefined || tool.type === 'function') && tool.name !== undefined\n ? [{ name: tool.name, parameters: tool.parameters }]\n : []\n )\n\nconst chosenTool = (request: ResponsesRequest) => {\n const tools = functionTools(request)\n\n if (tools.length === 0 || request.tool_choice === 'none') {\n return undefined\n }\n\n const forced =\n stringField(request.tool_choice, 'type') === 'function'\n ? stringField(request.tool_choice, 'name')\n : undefined\n\n return tools.find(tool => tool.name === forced) ?? tools[0]\n}\n\nconst defaultPlan = (\n request: ResponsesRequest,\n seq: number,\n defaultText: ReadonlyArray<string>\n): ResponsePlan => {\n const reasoning: ReadonlyArray<ItemPlan> = summaryRequested(request)\n ? [{ type: 'reasoning', id: `rs_synthetic_${seq}_0`, fragments: defaultReasoning }]\n : []\n\n const tool = chosenTool(request)\n\n if (tool === undefined) {\n return {\n items: [\n ...reasoning,\n { type: 'message', id: `msg_synthetic_${seq}_0`, fragments: defaultText }\n ],\n usage: undefined,\n format: undefined\n }\n }\n\n const argumentsText = JSON.stringify(\n synthesizeValue(tool.parameters ?? { type: 'object' }, tool.name, 0)\n )\n\n return {\n items: [\n ...reasoning,\n {\n type: 'function_call',\n id: `fc_synthetic_${seq}_0`,\n callId: `call_synthetic_${seq}_0`,\n name: tool.name,\n fragments: splitFragments(argumentsText, 3)\n }\n ],\n usage: undefined,\n format: undefined\n }\n}\n\nconst scriptedPlan = (turn: ResponsesScriptedResponse, seq: number): ResponsePlan => {\n const reasoning: ReadonlyArray<ItemPlan> =\n turn.reasoning === undefined\n ? []\n : [{ type: 'reasoning', id: `rs_synthetic_${seq}_0`, fragments: turn.reasoning }]\n\n const message: ReadonlyArray<ItemPlan> =\n turn.text === undefined\n ? []\n : [{ type: 'message', id: `msg_synthetic_${seq}_0`, fragments: turn.text }]\n\n const calls = (turn.functionCalls ?? []).map((call, index): ItemPlan => ({\n type: 'function_call',\n id: `fc_synthetic_${seq}_${index}`,\n callId: call.callId ?? `call_synthetic_${seq}_${index}`,\n name: call.name,\n fragments: call.argumentFragments\n }))\n\n return {\n items:\n turn.order === 'text-first'\n ? [...message, ...reasoning, ...calls]\n : [...reasoning, ...message, ...calls],\n usage: turn.usage,\n format: turn.format\n }\n}\n\ntype WireUsage = {\n readonly input_tokens: number\n readonly input_tokens_details: { readonly cached_tokens: number }\n readonly output_tokens: number\n readonly output_tokens_details: { readonly reasoning_tokens: number }\n readonly total_tokens: number\n}\n\ntype WireResponse = {\n readonly id: string\n readonly object: 'response'\n readonly created_at: number\n readonly status: 'in_progress' | 'completed' | 'failed'\n readonly error: Schema.JsonObject | null\n readonly incomplete_details: null\n readonly model: string\n readonly output: ReadonlyArray<Schema.JsonObject>\n usage?: WireUsage | null\n}\n\nconst planUsage = (plan: ResponsePlan, requestText: string): WireUsage | undefined => {\n if (plan.usage === null) {\n return undefined\n }\n\n const reasoningText = plan.items\n .flatMap(item => (item.type === 'reasoning' ? item.fragments : []))\n .join('')\n\n const usage = plan.usage ?? {\n inputTokens: approximateTokens(requestText),\n outputTokens: approximateTokens(plan.items.flatMap(item => item.fragments).join('')),\n reasoningTokens: reasoningText.length > 0 ? approximateTokens(reasoningText) : 0\n }\n\n return {\n input_tokens: usage.inputTokens,\n input_tokens_details: { cached_tokens: 0 },\n output_tokens: usage.outputTokens,\n output_tokens_details: { reasoning_tokens: usage.reasoningTokens ?? 0 },\n total_tokens: usage.inputTokens + usage.outputTokens\n }\n}\n\ntype ResponseIdentity = { readonly id: string; readonly model: string }\n\nconst responseObject = (\n identity: ResponseIdentity,\n status: WireResponse['status'],\n output: ReadonlyArray<Schema.JsonObject>\n): WireResponse => ({\n id: identity.id,\n object: 'response',\n created_at: syntheticCreated,\n status,\n error: null,\n incomplete_details: null,\n model: identity.model,\n output\n})\n\nconst outputText = (text: string): Schema.JsonObject => ({\n type: 'output_text',\n text,\n annotations: []\n})\n\nconst summaryText = (text: string): Schema.JsonObject => ({ type: 'summary_text', text })\n\n/** The complete wire item (as in `response.output_item.done` and the final `output`). */\nconst completeItem = (item: ItemPlan): Schema.JsonObject => {\n const text = item.fragments.join('')\n\n switch (item.type) {\n case 'reasoning':\n return {\n id: item.id,\n type: 'reasoning',\n summary: item.fragments.length === 0 ? [] : [summaryText(text)]\n }\n case 'message':\n return {\n id: item.id,\n type: 'message',\n status: 'completed',\n role: 'assistant',\n content: [outputText(text)]\n }\n case 'function_call':\n return {\n id: item.id,\n type: 'function_call',\n status: 'completed',\n call_id: item.callId,\n name: item.name,\n arguments: text\n }\n }\n}\n\n/** The item as first announced in `response.output_item.added`. */\nconst addedItem = (item: ItemPlan): Schema.JsonObject => {\n switch (item.type) {\n case 'reasoning':\n return { id: item.id, type: 'reasoning', summary: [] }\n case 'message':\n return {\n id: item.id,\n type: 'message',\n status: 'in_progress',\n role: 'assistant',\n content: []\n }\n case 'function_call':\n return {\n id: item.id,\n type: 'function_call',\n status: 'in_progress',\n call_id: item.callId,\n name: item.name,\n arguments: ''\n }\n }\n}\n\nconst sseEvent = (type: string, sequence: number, payload: object): string =>\n `event: ${type}\\ndata: ${JSON.stringify({ type, sequence_number: sequence, ...payload })}\\n\\n`\n\ntype EventWriter = {\n readonly events: Array<string>\n readonly push: (type: string, payload: object) => void\n}\n\n/** Builds SSE events with increasing `sequence_number`s, one network chunk each. */\nconst makeEventWriter = (): EventWriter => {\n const events: Array<string> = []\n\n return {\n events,\n push: (type, payload) => {\n events.push(sseEvent(type, events.length, payload))\n }\n }\n}\n\nconst itemEvents = (writer: EventWriter, item: ItemPlan, outputIndex: number) => {\n const text = item.fragments.join('')\n const ids = { item_id: item.id, output_index: outputIndex }\n\n writer.push('response.output_item.added', { output_index: outputIndex, item: addedItem(item) })\n\n switch (item.type) {\n case 'reasoning': {\n if (item.fragments.length > 0) {\n const part = { ...ids, summary_index: 0 }\n\n writer.push('response.reasoning_summary_part.added', { ...part, part: summaryText('') })\n\n for (const fragment of item.fragments) {\n writer.push('response.reasoning_summary_text.delta', { ...part, delta: fragment })\n }\n\n writer.push('response.reasoning_summary_text.done', { ...part, text })\n writer.push('response.reasoning_summary_part.done', { ...part, part: summaryText(text) })\n }\n\n break\n }\n\n case 'message': {\n const part = { ...ids, content_index: 0 }\n\n writer.push('response.content_part.added', { ...part, part: outputText('') })\n\n for (const fragment of item.fragments) {\n writer.push('response.output_text.delta', { ...part, delta: fragment })\n }\n\n writer.push('response.output_text.done', { ...part, text })\n writer.push('response.content_part.done', { ...part, part: outputText(text) })\n break\n }\n\n case 'function_call': {\n for (const fragment of item.fragments) {\n writer.push('response.function_call_arguments.delta', { ...ids, delta: fragment })\n }\n\n writer.push('response.function_call_arguments.done', { ...ids, arguments: text })\n break\n }\n }\n\n writer.push('response.output_item.done', { output_index: outputIndex, item: completeItem(item) })\n}\n\n/** The completed `response` object (for `response.completed` and the JSON body). */\nconst completedResponse = (\n plan: ResponsePlan,\n identity: ResponseIdentity,\n usage: WireUsage | undefined\n): WireResponse => {\n const response = responseObject(identity, 'completed', plan.items.map(completeItem))\n\n if (usage !== undefined) {\n response.usage = usage\n }\n\n return response\n}\n\n/** SSE events for a streamed response, one network chunk each, in the API's order. */\nconst streamEvents = (\n plan: ResponsePlan,\n identity: ResponseIdentity,\n usage: WireUsage | undefined\n): ReadonlyArray<string> => {\n const writer = makeEventWriter()\n const inProgress: WireResponse = { ...responseObject(identity, 'in_progress', []), usage: null }\n\n writer.push('response.created', { response: inProgress })\n writer.push('response.in_progress', { response: inProgress })\n\n plan.items.forEach((item, index) => itemEvents(writer, item, index))\n\n writer.push('response.completed', { response: completedResponse(plan, identity, usage) })\n\n return writer.events\n}\n\n/** The mid-stream error event of an `error-event-after-chunks` fault. */\nconst errorEvent = (\n fault: typeof ResponsesErrorEventFault.Type,\n identity: ResponseIdentity,\n sequence: number\n): string => {\n const error = fault.error ?? defaultStreamError\n\n if (fault.event === 'response.failed') {\n return sseEvent('response.failed', sequence, {\n response: {\n ...responseObject(identity, 'failed', []),\n error: { code: error.code, message: error.message },\n usage: null\n }\n })\n }\n\n return sseEvent('error', sequence, { code: error.code, message: error.message, param: null })\n}\n\ntype MutableLedgerEntry = KernelLedgerEntry<ResponsesFaultKind> & {\n body?: Schema.Json\n model?: string\n stream?: boolean\n store?: boolean\n maxOutputTokens?: number\n reasoning?: Schema.Json\n toolChoice?: Schema.Json\n toolNames: ReadonlyArray<string>\n headers: Record<string, string>\n scripted?: 'response' | 'error'\n}\n\nconst isPositiveInteger = (value: Schema.Json | undefined): value is number =>\n Predicate.isNumber(value) && Number.isSafeInteger(value) && value > 0\n\n/**\n * Create a Responses emulator from its config. Each call has independent ledger, fault, and\n * script state.\n *\n * Precedence per request: the bearer credential, the header rules in order, JSON and request\n * validation (an `input` string or array, and the `max_output_tokens` policy), then the first\n * matching fault if it is a `status` fault, then the next scripted turn, then model validation and\n * defaults; a first matching body fault then shapes the body. Only the first matching fault (in\n * insertion order) applies. Credential headers are never recorded, and credential values are\n * never checked or stored.\n */\nexport const makeResponsesEmulator = (config: ResponsesEmulatorConfig): ResponsesEmulator => {\n const knownModels = [...config.knownModels]\n\n const errorResponse = (status: number, error: ResponsesWireError): Response =>\n jsonResponse(status, config.errorEnvelope(error))\n\n const invalidRequest = (message: string, code: string, param?: string): Response =>\n errorResponse(\n 400,\n param === undefined\n ? { message, type: 'invalid_request_error', code }\n : { message, type: 'invalid_request_error', code, param }\n )\n\n const defaultFaultBody = (status: number): Schema.Json =>\n status === 429\n ? config.errorEnvelope({\n message: 'Synthetic rate limit: too many requests.',\n type: 'rate_limit_exceeded',\n code: 'rate_limit_exceeded'\n })\n : config.errorEnvelope({\n message: `Synthetic upstream error (${status}).`,\n type: status >= 500 ? 'server_error' : 'api_error',\n code: status >= 500 ? 'server_error' : 'upstream_error'\n })\n\n const kernel = makeEmulatorKernel({\n routes: config.routes,\n faultSchema: ResponsesFault,\n turnSchema: ResponsesScriptedTurn,\n newEntry: (base): MutableLedgerEntry => ({ ...base, toolNames: [], headers: {} }),\n snapshotEntry: (entry): ResponsesLedgerEntry => ({\n ...entry,\n toolNames: [...entry.toolNames],\n headers: { ...entry.headers }\n }),\n unknownRoute: () =>\n errorResponse(404, {\n message: 'Synthetic: no emulated route.',\n type: 'invalid_request_error',\n code: 'not_found'\n }),\n stateFields: () => ({ knownModels }),\n inputInvalid: config.inputInvalid\n })\n\n const responses = async (\n request: Request,\n entry: MutableLedgerEntry,\n path: string\n ): Promise<Response> => {\n for (const rule of config.headers) {\n const value = request.headers.get(rule.name)\n\n if (rule.record && value !== null) entry.headers[rule.name] = value\n }\n\n if (!bearerPattern.test(request.headers.get('authorization') ?? '')) {\n entry.status = 401\n\n return errorResponse(401, config.unauthorized)\n }\n\n for (const rule of config.headers) {\n if (\n rule.required !== undefined &&\n (request.headers.get(rule.name) ?? '').trim().length === 0\n ) {\n entry.status = rule.required.status\n\n return errorResponse(rule.required.status, rule.required.error)\n }\n }\n\n const text = await readText(request)\n const json = text === undefined ? undefined : parseJson(text)\n\n if (text === undefined || json === undefined) {\n entry.status = 400\n\n return invalidRequest('Synthetic: the request body is not valid JSON.', 'invalid_json')\n }\n\n entry.body = json\n\n const decoded = decodeResponsesRequest(json)\n\n if (Result.isFailure(decoded) || !isJsonObject(json)) {\n entry.status = 400\n\n return invalidRequest(\n 'Synthetic: the request body is not a Responses request (`input` is required).',\n 'invalid_request'\n )\n }\n\n const body = decoded.success\n const seq = entry.seq\n\n if (body.model !== undefined) entry.model = body.model\n\n entry.stream = body.stream === true\n\n if (Predicate.isBoolean(body.store)) entry.store = body.store\n\n if (body.reasoning !== undefined) entry.reasoning = body.reasoning\n\n if (body.tool_choice !== undefined) entry.toolChoice = body.tool_choice\n\n entry.toolNames = functionTools(body).map(tool => tool.name)\n\n const outputLimit = jsonField(json, 'max_output_tokens')\n\n if (Predicate.isNumber(outputLimit)) entry.maxOutputTokens = outputLimit\n\n if (config.outputTokenLimit === 'rejected' && outputLimit !== undefined) {\n entry.status = 400\n\n return invalidRequest(\n 'Synthetic: unsupported parameter: max_output_tokens.',\n 'unsupported_parameter',\n 'max_output_tokens'\n )\n }\n\n if (outputLimit !== undefined && outputLimit !== null && !isPositiveInteger(outputLimit)) {\n entry.status = 400\n\n return invalidRequest(\n 'Synthetic: max_output_tokens must be a positive integer.',\n 'invalid_value',\n 'max_output_tokens'\n )\n }\n\n const fault = kernel.takeFault(path, body.model)\n\n if (fault !== undefined && fault.fault.kind === 'status') {\n return kernel.respondWithStatusFault(entry, fault, fault.fault, defaultFaultBody)\n }\n\n const errorEventFault =\n fault !== undefined && fault.fault.kind === 'error-event-after-chunks'\n ? { state: fault, fault: fault.fault }\n : undefined\n\n const cannotApply = (problem: string): Response => {\n entry.faultError = problem\n entry.status = 500\n\n return controlError(500, `emulator fault cannot apply: ${problem}`)\n }\n\n // A scripted turn is used up when its request arrives. Header and status validation at\n // `script.enqueue` time means its response can always be built.\n const turn = kernel.nextTurn()\n\n if (turn !== undefined && 'error' in turn) {\n entry.scripted = 'error'\n\n if (errorEventFault !== undefined) {\n return cannotApply('error-event-after-chunks cannot apply to a scripted error')\n }\n\n return kernel.respondWithScriptedError(entry, turn.error, fault)\n }\n\n if (turn === undefined && (body.model === undefined || !knownModels.includes(body.model))) {\n entry.status = config.unknownModel.status\n\n return errorResponse(config.unknownModel.status, config.unknownModel.error)\n }\n\n if (turn !== undefined) entry.scripted = 'response'\n\n const plan =\n turn === undefined ? defaultPlan(body, seq, config.defaultText) : scriptedPlan(turn, seq)\n\n const identity = { id: `resp_synthetic_${seq}`, model: body.model ?? 'unknown' }\n const usage = planUsage(plan, text)\n const format = plan.format ?? (body.stream === true ? 'sse' : 'json')\n\n if (format === 'json') {\n if (errorEventFault !== undefined) {\n return cannotApply('error-event-after-chunks cannot apply to a JSON response')\n }\n\n return kernel.respondWithBody(\n entry,\n 200,\n { 'content-type': 'application/json' },\n [JSON.stringify(completedResponse(plan, identity, usage))],\n fault\n )\n }\n\n const events = streamEvents(plan, identity, usage)\n const headers = { 'content-type': 'text/event-stream', 'cache-control': 'no-cache' }\n\n if (errorEventFault === undefined) {\n return kernel.respondWithBody(entry, 200, headers, events, fault)\n }\n\n const after = errorEventFault.fault.chunks\n\n // The error must arrive before `response.completed`, or a client rightly ignores it.\n if (after >= events.length) {\n return cannotApply(\n `error-event-after-chunks after ${after} chunk(s) cannot apply to a response with ${events.length} chunk(s)`\n )\n }\n\n const response = kernel.respondWithBody(\n entry,\n 200,\n headers,\n [...events.slice(0, after), errorEvent(errorEventFault.fault, identity, after)],\n undefined\n )\n\n kernel.consumeFault(errorEventFault.state, entry)\n\n return response\n }\n\n // Every manifest route maps to its own handler; construction throws `EmulatorRouteUnmapped`\n // when a manifest route has no handler (or a handler has no manifest route).\n return kernel.serve(new Map([[emulatorRouteKey('POST', config.path), responses]]))\n}\n"],"mappings":"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"}
|