@tormentalabs/claude-code-wire-compat 0.1.0-rc.10
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/CHANGELOG.md +312 -0
- package/LICENSE +674 -0
- package/NOTICE +16 -0
- package/README.md +39 -0
- package/dist/anti-verbosity.d.ts +58 -0
- package/dist/anti-verbosity.d.ts.map +1 -0
- package/dist/anti-verbosity.js +174 -0
- package/dist/anti-verbosity.js.map +1 -0
- package/dist/beta-registry.d.ts +119 -0
- package/dist/beta-registry.d.ts.map +1 -0
- package/dist/beta-registry.js +125 -0
- package/dist/beta-registry.js.map +1 -0
- package/dist/betas.d.ts +11 -0
- package/dist/betas.d.ts.map +1 -0
- package/dist/betas.js +68 -0
- package/dist/betas.js.map +1 -0
- package/dist/build-request.d.ts +24 -0
- package/dist/build-request.d.ts.map +1 -0
- package/dist/build-request.js +1008 -0
- package/dist/build-request.js.map +1 -0
- package/dist/contracts.d.ts +717 -0
- package/dist/contracts.d.ts.map +1 -0
- package/dist/contracts.js +36 -0
- package/dist/contracts.js.map +1 -0
- package/dist/count-tokens.d.ts +42 -0
- package/dist/count-tokens.d.ts.map +1 -0
- package/dist/count-tokens.js +61 -0
- package/dist/count-tokens.js.map +1 -0
- package/dist/fingerprint.d.ts +4 -0
- package/dist/fingerprint.d.ts.map +1 -0
- package/dist/fingerprint.js +59 -0
- package/dist/fingerprint.js.map +1 -0
- package/dist/headers.d.ts +4 -0
- package/dist/headers.d.ts.map +1 -0
- package/dist/headers.js +255 -0
- package/dist/headers.js.map +1 -0
- package/dist/index.d.ts +17 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +6 -0
- package/dist/index.js.map +1 -0
- package/dist/metadata.d.ts +4 -0
- package/dist/metadata.d.ts.map +1 -0
- package/dist/metadata.js +192 -0
- package/dist/metadata.js.map +1 -0
- package/dist/model-capabilities.d.ts +103 -0
- package/dist/model-capabilities.d.ts.map +1 -0
- package/dist/model-capabilities.js +263 -0
- package/dist/model-capabilities.js.map +1 -0
- package/dist/model-identity.d.ts +11 -0
- package/dist/model-identity.d.ts.map +1 -0
- package/dist/model-identity.js +64 -0
- package/dist/model-identity.js.map +1 -0
- package/dist/models.d.ts +9 -0
- package/dist/models.d.ts.map +1 -0
- package/dist/models.js +25 -0
- package/dist/models.js.map +1 -0
- package/dist/profiles/claude-code-2.1.195.d.ts +3 -0
- package/dist/profiles/claude-code-2.1.195.d.ts.map +1 -0
- package/dist/profiles/claude-code-2.1.195.js +150 -0
- package/dist/profiles/claude-code-2.1.195.js.map +1 -0
- package/dist/redaction.d.ts +16 -0
- package/dist/redaction.d.ts.map +1 -0
- package/dist/redaction.js +364 -0
- package/dist/redaction.js.map +1 -0
- package/dist/request-body.d.ts +19 -0
- package/dist/request-body.d.ts.map +1 -0
- package/dist/request-body.js +1658 -0
- package/dist/request-body.js.map +1 -0
- package/dist/sha256.d.ts +9 -0
- package/dist/sha256.d.ts.map +1 -0
- package/dist/sha256.js +104 -0
- package/dist/sha256.js.map +1 -0
- package/dist/system-prompt.d.ts +4 -0
- package/dist/system-prompt.d.ts.map +1 -0
- package/dist/system-prompt.js +157 -0
- package/dist/system-prompt.js.map +1 -0
- package/dist/thinking.d.ts +91 -0
- package/dist/thinking.d.ts.map +1 -0
- package/dist/thinking.js +132 -0
- package/dist/thinking.js.map +1 -0
- package/dist/unicode.d.ts +10 -0
- package/dist/unicode.d.ts.map +1 -0
- package/dist/unicode.js +19 -0
- package/dist/unicode.js.map +1 -0
- package/package.json +72 -0
|
@@ -0,0 +1,1658 @@
|
|
|
1
|
+
// SPDX-License-Identifier: GPL-3.0-or-later
|
|
2
|
+
import { CLAUDE_CODE_2_1_195_PROFILE } from "./profiles/claude-code-2.1.195.js";
|
|
3
|
+
import { resolveThinking } from "./thinking.js";
|
|
4
|
+
import { ClaudeCodeWireError } from "./contracts.js";
|
|
5
|
+
import { deriveCapabilities } from "./model-capabilities.js";
|
|
6
|
+
import { stripModelMarkers } from "./model-identity.js";
|
|
7
|
+
import { classifySurrogateAt } from "./unicode.js";
|
|
8
|
+
const MAX_DEPTH = 100;
|
|
9
|
+
const MAX_ITEMS = 100_000;
|
|
10
|
+
const MAX_SIZE = 1_000_000;
|
|
11
|
+
const FORBIDDEN_KEYS = new Set(["__proto__", "prototype", "constructor"]);
|
|
12
|
+
const MESSAGE_KEYS = new Set(["role", "content"]);
|
|
13
|
+
const CACHE_CONTROL_KEYS = new Set(["type", "ttl"]);
|
|
14
|
+
const LEGACY_TEXT_CACHE_CONTROL_KEYS = new Set(["type", "ttl", "scope"]);
|
|
15
|
+
const CITATIONS_CONFIG_KEYS = new Set(["enabled"]);
|
|
16
|
+
const TEXT_KEYS = new Set(["text", "type", "cache_control", "citations"]);
|
|
17
|
+
const TOOL_USE_KEYS = new Set([
|
|
18
|
+
"id",
|
|
19
|
+
"input",
|
|
20
|
+
"name",
|
|
21
|
+
"type",
|
|
22
|
+
"cache_control",
|
|
23
|
+
"caller",
|
|
24
|
+
]);
|
|
25
|
+
const TOOL_RESULT_KEYS = new Set([
|
|
26
|
+
"tool_use_id",
|
|
27
|
+
"type",
|
|
28
|
+
"cache_control",
|
|
29
|
+
"content",
|
|
30
|
+
"is_error",
|
|
31
|
+
]);
|
|
32
|
+
const THINKING_BLOCK_KEYS = new Set(["signature", "thinking", "type"]);
|
|
33
|
+
const REDACTED_THINKING_BLOCK_KEYS = new Set(["data", "type"]);
|
|
34
|
+
const IMAGE_BLOCK_KEYS = new Set(["source", "type", "cache_control"]);
|
|
35
|
+
const BASE64_IMAGE_SOURCE_KEYS = new Set(["data", "media_type", "type"]);
|
|
36
|
+
const FILE_IMAGE_SOURCE_KEYS = new Set(["file_id", "type"]);
|
|
37
|
+
const URL_IMAGE_SOURCE_KEYS = new Set(["type", "url"]);
|
|
38
|
+
const DOCUMENT_BLOCK_KEYS = new Set([
|
|
39
|
+
"source",
|
|
40
|
+
"type",
|
|
41
|
+
"cache_control",
|
|
42
|
+
"citations",
|
|
43
|
+
"context",
|
|
44
|
+
"title",
|
|
45
|
+
]);
|
|
46
|
+
const BASE64_PDF_SOURCE_KEYS = new Set(["data", "media_type", "type"]);
|
|
47
|
+
const CONTENT_BLOCK_SOURCE_KEYS = new Set(["content", "type"]);
|
|
48
|
+
const FILE_DOCUMENT_SOURCE_KEYS = new Set(["file_id", "type"]);
|
|
49
|
+
const PLAIN_TEXT_SOURCE_KEYS = new Set(["data", "media_type", "type"]);
|
|
50
|
+
const URL_PDF_SOURCE_KEYS = new Set(["type", "url"]);
|
|
51
|
+
const SEARCH_RESULT_KEYS = new Set([
|
|
52
|
+
"content",
|
|
53
|
+
"source",
|
|
54
|
+
"title",
|
|
55
|
+
"type",
|
|
56
|
+
"cache_control",
|
|
57
|
+
"citations",
|
|
58
|
+
]);
|
|
59
|
+
const TOOL_REFERENCE_KEYS = new Set(["tool_name", "type", "cache_control"]);
|
|
60
|
+
const DIRECT_CALLER_KEYS = new Set(["type"]);
|
|
61
|
+
const SERVER_TOOL_CALLER_KEYS = new Set(["tool_id", "type"]);
|
|
62
|
+
const CITATION_CHAR_KEYS = new Set([
|
|
63
|
+
"cited_text",
|
|
64
|
+
"document_index",
|
|
65
|
+
"document_title",
|
|
66
|
+
"end_char_index",
|
|
67
|
+
"start_char_index",
|
|
68
|
+
"type",
|
|
69
|
+
]);
|
|
70
|
+
const CITATION_CONTENT_BLOCK_KEYS = new Set([
|
|
71
|
+
"cited_text",
|
|
72
|
+
"document_index",
|
|
73
|
+
"document_title",
|
|
74
|
+
"end_block_index",
|
|
75
|
+
"start_block_index",
|
|
76
|
+
"type",
|
|
77
|
+
]);
|
|
78
|
+
const CITATION_PAGE_KEYS = new Set([
|
|
79
|
+
"cited_text",
|
|
80
|
+
"document_index",
|
|
81
|
+
"document_title",
|
|
82
|
+
"end_page_number",
|
|
83
|
+
"start_page_number",
|
|
84
|
+
"type",
|
|
85
|
+
]);
|
|
86
|
+
const CITATION_SEARCH_RESULT_KEYS = new Set([
|
|
87
|
+
"cited_text",
|
|
88
|
+
"end_block_index",
|
|
89
|
+
"search_result_index",
|
|
90
|
+
"source",
|
|
91
|
+
"start_block_index",
|
|
92
|
+
"title",
|
|
93
|
+
"type",
|
|
94
|
+
]);
|
|
95
|
+
const CITATION_WEB_SEARCH_KEYS = new Set([
|
|
96
|
+
"cited_text",
|
|
97
|
+
"encrypted_index",
|
|
98
|
+
"title",
|
|
99
|
+
"type",
|
|
100
|
+
"url",
|
|
101
|
+
]);
|
|
102
|
+
const CUSTOM_TOOL_KEYS = new Set([
|
|
103
|
+
"input_schema",
|
|
104
|
+
"name",
|
|
105
|
+
"allowed_callers",
|
|
106
|
+
"cache_control",
|
|
107
|
+
"defer_loading",
|
|
108
|
+
"description",
|
|
109
|
+
"eager_input_streaming",
|
|
110
|
+
"input_examples",
|
|
111
|
+
"strict",
|
|
112
|
+
]);
|
|
113
|
+
const BASH_TOOL_KEYS = new Set([
|
|
114
|
+
"name",
|
|
115
|
+
"type",
|
|
116
|
+
"allowed_callers",
|
|
117
|
+
"cache_control",
|
|
118
|
+
"defer_loading",
|
|
119
|
+
"input_examples",
|
|
120
|
+
"strict",
|
|
121
|
+
]);
|
|
122
|
+
const CODE_EXECUTION_TOOL_KEYS = new Set([
|
|
123
|
+
"name",
|
|
124
|
+
"type",
|
|
125
|
+
"allowed_callers",
|
|
126
|
+
"cache_control",
|
|
127
|
+
"defer_loading",
|
|
128
|
+
"strict",
|
|
129
|
+
]);
|
|
130
|
+
const COMPUTER_TOOL_KEYS = new Set([
|
|
131
|
+
"display_height_px",
|
|
132
|
+
"display_width_px",
|
|
133
|
+
"name",
|
|
134
|
+
"type",
|
|
135
|
+
"allowed_callers",
|
|
136
|
+
"cache_control",
|
|
137
|
+
"defer_loading",
|
|
138
|
+
"display_number",
|
|
139
|
+
"input_examples",
|
|
140
|
+
"strict",
|
|
141
|
+
]);
|
|
142
|
+
const COMPUTER_ZOOM_TOOL_KEYS = new Set([...COMPUTER_TOOL_KEYS, "enable_zoom"]);
|
|
143
|
+
const MEMORY_TOOL_KEYS = new Set([
|
|
144
|
+
"name",
|
|
145
|
+
"type",
|
|
146
|
+
"allowed_callers",
|
|
147
|
+
"cache_control",
|
|
148
|
+
"defer_loading",
|
|
149
|
+
"input_examples",
|
|
150
|
+
"strict",
|
|
151
|
+
]);
|
|
152
|
+
const TEXT_EDITOR_TOOL_KEYS = new Set([
|
|
153
|
+
"name",
|
|
154
|
+
"type",
|
|
155
|
+
"allowed_callers",
|
|
156
|
+
"cache_control",
|
|
157
|
+
"defer_loading",
|
|
158
|
+
"input_examples",
|
|
159
|
+
"strict",
|
|
160
|
+
]);
|
|
161
|
+
const TEXT_EDITOR_MAX_TOOL_KEYS = new Set([
|
|
162
|
+
...TEXT_EDITOR_TOOL_KEYS,
|
|
163
|
+
"max_characters",
|
|
164
|
+
]);
|
|
165
|
+
const WEB_SEARCH_TOOL_KEYS = new Set([
|
|
166
|
+
"name",
|
|
167
|
+
"type",
|
|
168
|
+
"allowed_callers",
|
|
169
|
+
"allowed_domains",
|
|
170
|
+
"blocked_domains",
|
|
171
|
+
"cache_control",
|
|
172
|
+
"defer_loading",
|
|
173
|
+
"max_uses",
|
|
174
|
+
"strict",
|
|
175
|
+
"user_location",
|
|
176
|
+
]);
|
|
177
|
+
const USER_LOCATION_KEYS = new Set([
|
|
178
|
+
"type",
|
|
179
|
+
"city",
|
|
180
|
+
"country",
|
|
181
|
+
"region",
|
|
182
|
+
"timezone",
|
|
183
|
+
]);
|
|
184
|
+
const WEB_FETCH_TOOL_KEYS = new Set([
|
|
185
|
+
"name",
|
|
186
|
+
"type",
|
|
187
|
+
"allowed_callers",
|
|
188
|
+
"allowed_domains",
|
|
189
|
+
"blocked_domains",
|
|
190
|
+
"cache_control",
|
|
191
|
+
"citations",
|
|
192
|
+
"defer_loading",
|
|
193
|
+
"max_content_tokens",
|
|
194
|
+
"max_uses",
|
|
195
|
+
"strict",
|
|
196
|
+
]);
|
|
197
|
+
const WEB_FETCH_CACHE_TOOL_KEYS = new Set([
|
|
198
|
+
...WEB_FETCH_TOOL_KEYS,
|
|
199
|
+
"use_cache",
|
|
200
|
+
]);
|
|
201
|
+
const ADVISOR_TOOL_KEYS = new Set([
|
|
202
|
+
"model",
|
|
203
|
+
"name",
|
|
204
|
+
"type",
|
|
205
|
+
"allowed_callers",
|
|
206
|
+
"cache_control",
|
|
207
|
+
"caching",
|
|
208
|
+
"defer_loading",
|
|
209
|
+
"max_uses",
|
|
210
|
+
"strict",
|
|
211
|
+
]);
|
|
212
|
+
const TOOL_SEARCH_KEYS = new Set([
|
|
213
|
+
"name",
|
|
214
|
+
"type",
|
|
215
|
+
"allowed_callers",
|
|
216
|
+
"cache_control",
|
|
217
|
+
"defer_loading",
|
|
218
|
+
"strict",
|
|
219
|
+
]);
|
|
220
|
+
const MCP_TOOLSET_KEYS = new Set([
|
|
221
|
+
"mcp_server_name",
|
|
222
|
+
"type",
|
|
223
|
+
"cache_control",
|
|
224
|
+
"configs",
|
|
225
|
+
"default_config",
|
|
226
|
+
]);
|
|
227
|
+
const MCP_TOOL_CONFIG_KEYS = new Set(["defer_loading", "enabled"]);
|
|
228
|
+
const CONTEXT_CONFIG_KEYS = new Set(["edits"]);
|
|
229
|
+
const CLEAR_THINKING_KEYS = new Set(["type", "keep"]);
|
|
230
|
+
const ALL_THINKING_KEYS = new Set(["type"]);
|
|
231
|
+
const TYPED_NUMBER_KEYS = new Set(["type", "value"]);
|
|
232
|
+
const CLEAR_TOOL_USES_KEYS = new Set([
|
|
233
|
+
"type",
|
|
234
|
+
"clear_at_least",
|
|
235
|
+
"clear_tool_inputs",
|
|
236
|
+
"exclude_tools",
|
|
237
|
+
"keep",
|
|
238
|
+
"trigger",
|
|
239
|
+
]);
|
|
240
|
+
const COMPACT_KEYS = new Set([
|
|
241
|
+
"type",
|
|
242
|
+
"instructions",
|
|
243
|
+
"pause_after_compaction",
|
|
244
|
+
"trigger",
|
|
245
|
+
]);
|
|
246
|
+
const OUTPUT_CONFIG_KEYS = new Set(["effort", "maxOutputTokens"]);
|
|
247
|
+
const CACHE_CONTROL_INPUT_KEYS = new Set([
|
|
248
|
+
"enabled",
|
|
249
|
+
"ttl",
|
|
250
|
+
"systemBreakpoint",
|
|
251
|
+
"toolBreakpoint",
|
|
252
|
+
"messageBreakpoint",
|
|
253
|
+
]);
|
|
254
|
+
const JSON_OUTPUT_FORMAT_KEYS = new Set(["schema", "type"]);
|
|
255
|
+
const TOOL_CHOICE_PARALLEL_KEYS = new Set([
|
|
256
|
+
"type",
|
|
257
|
+
"disable_parallel_tool_use",
|
|
258
|
+
]);
|
|
259
|
+
const TOOL_CHOICE_NONE_KEYS = new Set(["type"]);
|
|
260
|
+
const TOOL_CHOICE_NAMED_KEYS = new Set([
|
|
261
|
+
"name",
|
|
262
|
+
"type",
|
|
263
|
+
"disable_parallel_tool_use",
|
|
264
|
+
]);
|
|
265
|
+
const INPUT_KEYS = [
|
|
266
|
+
"accessToken",
|
|
267
|
+
"model",
|
|
268
|
+
"maxTokens",
|
|
269
|
+
"messages",
|
|
270
|
+
"system",
|
|
271
|
+
"tools",
|
|
272
|
+
"cacheControl",
|
|
273
|
+
"runtime",
|
|
274
|
+
"capabilities",
|
|
275
|
+
"thinking",
|
|
276
|
+
"effort",
|
|
277
|
+
"metadata",
|
|
278
|
+
"experimentalBodyFields",
|
|
279
|
+
"contextManagement",
|
|
280
|
+
"outputConfig",
|
|
281
|
+
"speed",
|
|
282
|
+
"serviceTier",
|
|
283
|
+
"outputFormat",
|
|
284
|
+
"toolChoice",
|
|
285
|
+
"topP",
|
|
286
|
+
"topK",
|
|
287
|
+
"stopSequences",
|
|
288
|
+
"stream",
|
|
289
|
+
"temperature",
|
|
290
|
+
];
|
|
291
|
+
const INPUT_KEY_SET = new Set(INPUT_KEYS);
|
|
292
|
+
function fail(code) {
|
|
293
|
+
throw new ClaudeCodeWireError(code);
|
|
294
|
+
}
|
|
295
|
+
function isRecord(value) {
|
|
296
|
+
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
297
|
+
}
|
|
298
|
+
function hasOwn(value, key) {
|
|
299
|
+
return Object.prototype.hasOwnProperty.call(value, key);
|
|
300
|
+
}
|
|
301
|
+
function inspectString(value, state, validateString) {
|
|
302
|
+
state.size += value.length;
|
|
303
|
+
if (state.size > MAX_SIZE)
|
|
304
|
+
fail("INPUT_TOO_LARGE");
|
|
305
|
+
validateString?.(value);
|
|
306
|
+
for (let index = 0; index < value.length; index += 1) {
|
|
307
|
+
const unit = value.charCodeAt(index);
|
|
308
|
+
if (unit <= 0x08 ||
|
|
309
|
+
unit === 0x0b ||
|
|
310
|
+
unit === 0x0c ||
|
|
311
|
+
(unit >= 0x0e && unit <= 0x1f) ||
|
|
312
|
+
unit === 0x7f) {
|
|
313
|
+
fail("INVALID_INPUT");
|
|
314
|
+
}
|
|
315
|
+
const classification = classifySurrogateAt(value, index);
|
|
316
|
+
if (classification === "loneSurrogate")
|
|
317
|
+
fail("INVALID_UNICODE");
|
|
318
|
+
if (classification === "surrogatePair")
|
|
319
|
+
index += 1;
|
|
320
|
+
}
|
|
321
|
+
}
|
|
322
|
+
function inspect(value, depth, state, validateString) {
|
|
323
|
+
if (depth > MAX_DEPTH)
|
|
324
|
+
fail("INPUT_TOO_DEEP");
|
|
325
|
+
if (value === null || typeof value === "boolean")
|
|
326
|
+
return;
|
|
327
|
+
if (typeof value === "string") {
|
|
328
|
+
inspectString(value, state, validateString);
|
|
329
|
+
return;
|
|
330
|
+
}
|
|
331
|
+
if (typeof value === "number") {
|
|
332
|
+
if (!Number.isFinite(value))
|
|
333
|
+
fail("INVALID_INPUT");
|
|
334
|
+
return;
|
|
335
|
+
}
|
|
336
|
+
if (typeof value !== "object")
|
|
337
|
+
fail("INVALID_INPUT");
|
|
338
|
+
if (state.active.has(value))
|
|
339
|
+
fail("CYCLIC_INPUT");
|
|
340
|
+
state.active.add(value);
|
|
341
|
+
state.items += 1;
|
|
342
|
+
if (state.items > MAX_ITEMS)
|
|
343
|
+
fail("INPUT_TOO_LARGE");
|
|
344
|
+
if (Array.isArray(value)) {
|
|
345
|
+
state.size += value.length;
|
|
346
|
+
if (state.size > MAX_SIZE)
|
|
347
|
+
fail("INPUT_TOO_LARGE");
|
|
348
|
+
for (let index = 0; index < value.length; index += 1) {
|
|
349
|
+
if (!hasOwn(value, String(index)))
|
|
350
|
+
fail("INVALID_INPUT");
|
|
351
|
+
inspect(value[index], depth + 1, state, validateString);
|
|
352
|
+
}
|
|
353
|
+
}
|
|
354
|
+
else {
|
|
355
|
+
const prototype = Reflect.getPrototypeOf(value);
|
|
356
|
+
if (prototype !== Object.prototype && prototype !== null) {
|
|
357
|
+
fail("INVALID_INPUT");
|
|
358
|
+
}
|
|
359
|
+
for (const key of Reflect.ownKeys(value)) {
|
|
360
|
+
if (typeof key !== "string" || FORBIDDEN_KEYS.has(key)) {
|
|
361
|
+
fail("INVALID_INPUT");
|
|
362
|
+
}
|
|
363
|
+
inspectString(key, state, validateString);
|
|
364
|
+
const descriptor = Object.getOwnPropertyDescriptor(value, key);
|
|
365
|
+
if (descriptor === undefined || !("value" in descriptor)) {
|
|
366
|
+
fail("INVALID_INPUT");
|
|
367
|
+
}
|
|
368
|
+
inspect(descriptor.value, depth + 1, state, validateString);
|
|
369
|
+
}
|
|
370
|
+
}
|
|
371
|
+
state.active.delete(value);
|
|
372
|
+
}
|
|
373
|
+
export function inspectJsonInputs(values, validateString) {
|
|
374
|
+
const state = {
|
|
375
|
+
active: new WeakSet(),
|
|
376
|
+
items: 0,
|
|
377
|
+
size: 0,
|
|
378
|
+
};
|
|
379
|
+
for (const value of values)
|
|
380
|
+
inspect(value, 0, state, validateString);
|
|
381
|
+
}
|
|
382
|
+
function requireRecord(value) {
|
|
383
|
+
if (!isRecord(value))
|
|
384
|
+
fail("INVALID_INPUT");
|
|
385
|
+
return value;
|
|
386
|
+
}
|
|
387
|
+
function assertExactKeys(value, allowed) {
|
|
388
|
+
for (const key of Reflect.ownKeys(value)) {
|
|
389
|
+
if (typeof key !== "string" || !allowed.has(key))
|
|
390
|
+
fail("INVALID_INPUT");
|
|
391
|
+
}
|
|
392
|
+
}
|
|
393
|
+
function requireString(value) {
|
|
394
|
+
if (typeof value !== "string")
|
|
395
|
+
fail("INVALID_INPUT");
|
|
396
|
+
return value;
|
|
397
|
+
}
|
|
398
|
+
function requirePositiveInteger(value) {
|
|
399
|
+
if (!Number.isSafeInteger(value) || typeof value !== "number" || value <= 0) {
|
|
400
|
+
fail("INVALID_INPUT");
|
|
401
|
+
}
|
|
402
|
+
return value;
|
|
403
|
+
}
|
|
404
|
+
export function validatedJsonObject(value) {
|
|
405
|
+
const record = requireRecord(value);
|
|
406
|
+
const entries = [];
|
|
407
|
+
for (const key of Object.keys(record)) {
|
|
408
|
+
entries.push([key, validatedJson(record[key])]);
|
|
409
|
+
}
|
|
410
|
+
return Object.fromEntries(entries);
|
|
411
|
+
}
|
|
412
|
+
export function validatedJson(value) {
|
|
413
|
+
if (value === null ||
|
|
414
|
+
typeof value === "string" ||
|
|
415
|
+
typeof value === "number" ||
|
|
416
|
+
typeof value === "boolean") {
|
|
417
|
+
return value;
|
|
418
|
+
}
|
|
419
|
+
if (Array.isArray(value))
|
|
420
|
+
return value.map((item) => validatedJson(item));
|
|
421
|
+
return validatedJsonObject(value);
|
|
422
|
+
}
|
|
423
|
+
function requireNumber(value) {
|
|
424
|
+
if (typeof value !== "number" || !Number.isFinite(value))
|
|
425
|
+
fail("INVALID_INPUT");
|
|
426
|
+
return value;
|
|
427
|
+
}
|
|
428
|
+
function requireBoolean(value) {
|
|
429
|
+
if (typeof value !== "boolean")
|
|
430
|
+
fail("INVALID_INPUT");
|
|
431
|
+
return value;
|
|
432
|
+
}
|
|
433
|
+
function requireKeys(record, required) {
|
|
434
|
+
for (const key of required) {
|
|
435
|
+
if (!hasOwn(record, key))
|
|
436
|
+
fail("INVALID_INPUT");
|
|
437
|
+
}
|
|
438
|
+
}
|
|
439
|
+
function nullable(value, validate) {
|
|
440
|
+
return value === null ? null : validate(value);
|
|
441
|
+
}
|
|
442
|
+
function cacheControl(value, allowScope = false) {
|
|
443
|
+
const record = requireRecord(value);
|
|
444
|
+
assertExactKeys(record, allowScope ? LEGACY_TEXT_CACHE_CONTROL_KEYS : CACHE_CONTROL_KEYS);
|
|
445
|
+
requireKeys(record, ["type"]);
|
|
446
|
+
const entries = [];
|
|
447
|
+
for (const key of Object.keys(record)) {
|
|
448
|
+
const item = record[key];
|
|
449
|
+
if (key === "type") {
|
|
450
|
+
if (item !== "ephemeral")
|
|
451
|
+
fail("INVALID_INPUT");
|
|
452
|
+
entries.push([key, item]);
|
|
453
|
+
}
|
|
454
|
+
else if (key === "ttl") {
|
|
455
|
+
if (item !== "5m" && item !== "1h")
|
|
456
|
+
fail("INVALID_INPUT");
|
|
457
|
+
entries.push([key, item]);
|
|
458
|
+
}
|
|
459
|
+
else {
|
|
460
|
+
if (item !== "global")
|
|
461
|
+
fail("INVALID_INPUT");
|
|
462
|
+
entries.push([key, item]);
|
|
463
|
+
}
|
|
464
|
+
}
|
|
465
|
+
return Object.fromEntries(entries);
|
|
466
|
+
}
|
|
467
|
+
function cacheControlInput(value) {
|
|
468
|
+
const record = requireRecord(value);
|
|
469
|
+
assertExactKeys(record, CACHE_CONTROL_INPUT_KEYS);
|
|
470
|
+
const entries = [];
|
|
471
|
+
for (const key of Object.keys(record)) {
|
|
472
|
+
const item = record[key];
|
|
473
|
+
if (key === "ttl") {
|
|
474
|
+
if (item !== null && item !== "5m" && item !== "1h") {
|
|
475
|
+
fail("INVALID_INPUT");
|
|
476
|
+
}
|
|
477
|
+
entries.push([key, item]);
|
|
478
|
+
}
|
|
479
|
+
else {
|
|
480
|
+
entries.push([key, item === null ? null : requireBoolean(item)]);
|
|
481
|
+
}
|
|
482
|
+
}
|
|
483
|
+
return Object.fromEntries(entries);
|
|
484
|
+
}
|
|
485
|
+
function breakpoint(input) {
|
|
486
|
+
return input.ttl === undefined || input.ttl === null
|
|
487
|
+
? { type: "ephemeral" }
|
|
488
|
+
: { type: "ephemeral", ttl: input.ttl };
|
|
489
|
+
}
|
|
490
|
+
function withoutCacheControl(value) {
|
|
491
|
+
if (!isRecord(value))
|
|
492
|
+
fail("INVALID_INPUT");
|
|
493
|
+
return Object.fromEntries(Object.entries(value).filter(([key]) => key !== "cache_control"));
|
|
494
|
+
}
|
|
495
|
+
function withBreakpoint(value, marker) {
|
|
496
|
+
if (!isRecord(value))
|
|
497
|
+
fail("INVALID_INPUT");
|
|
498
|
+
return Object.fromEntries([
|
|
499
|
+
...Object.entries(value).filter(([key]) => key !== "cache_control"),
|
|
500
|
+
["cache_control", marker],
|
|
501
|
+
]);
|
|
502
|
+
}
|
|
503
|
+
function applySystemCacheControl(value, input) {
|
|
504
|
+
const result = value.map((block, index) => index === 1 ? withBreakpoint(block, breakpoint(input)) : block);
|
|
505
|
+
if (input.enabled === true &&
|
|
506
|
+
input.systemBreakpoint === true &&
|
|
507
|
+
result.length > 2) {
|
|
508
|
+
const index = result.length - 1;
|
|
509
|
+
const block = result[index];
|
|
510
|
+
if (block !== undefined)
|
|
511
|
+
result[index] = withBreakpoint(block, breakpoint(input));
|
|
512
|
+
}
|
|
513
|
+
return result;
|
|
514
|
+
}
|
|
515
|
+
function applyToolCacheControl(value, input) {
|
|
516
|
+
const result = value.map((tool) => withoutCacheControl(tool));
|
|
517
|
+
if (input.enabled === true &&
|
|
518
|
+
input.toolBreakpoint === true &&
|
|
519
|
+
result.length > 0) {
|
|
520
|
+
const index = result.length - 1;
|
|
521
|
+
const tool = result[index];
|
|
522
|
+
if (tool !== undefined)
|
|
523
|
+
result[index] = withBreakpoint(tool, breakpoint(input));
|
|
524
|
+
}
|
|
525
|
+
return result;
|
|
526
|
+
}
|
|
527
|
+
function applyMessageCacheControl(value, input) {
|
|
528
|
+
const result = value.map((message) => ({
|
|
529
|
+
role: message.role,
|
|
530
|
+
content: typeof message.content === "string"
|
|
531
|
+
? message.content
|
|
532
|
+
: message.content.map((block) => block.type === "thinking" || block.type === "redacted_thinking"
|
|
533
|
+
? block
|
|
534
|
+
: withoutCacheControl(block)),
|
|
535
|
+
}));
|
|
536
|
+
if (input.enabled !== true || input.messageBreakpoint !== true)
|
|
537
|
+
return result;
|
|
538
|
+
for (let index = result.length - 1; index >= 0; index -= 1) {
|
|
539
|
+
const message = result[index];
|
|
540
|
+
if (message?.role !== "user")
|
|
541
|
+
continue;
|
|
542
|
+
if (typeof message.content === "string" || message.content.length === 0) {
|
|
543
|
+
return result;
|
|
544
|
+
}
|
|
545
|
+
const content = [...message.content];
|
|
546
|
+
const blockIndex = content.length - 1;
|
|
547
|
+
const block = content[blockIndex];
|
|
548
|
+
if (block !== undefined &&
|
|
549
|
+
block.type !== "thinking" &&
|
|
550
|
+
block.type !== "redacted_thinking") {
|
|
551
|
+
content[blockIndex] = withBreakpoint(block, breakpoint(input));
|
|
552
|
+
result[index] = { role: message.role, content };
|
|
553
|
+
}
|
|
554
|
+
return result;
|
|
555
|
+
}
|
|
556
|
+
return result;
|
|
557
|
+
}
|
|
558
|
+
function citationsConfig(value) {
|
|
559
|
+
const record = requireRecord(value);
|
|
560
|
+
assertExactKeys(record, CITATIONS_CONFIG_KEYS);
|
|
561
|
+
requireKeys(record, []);
|
|
562
|
+
return Object.fromEntries(Object.keys(record).map((key) => [key, requireBoolean(record[key])]));
|
|
563
|
+
}
|
|
564
|
+
function textCitation(value) {
|
|
565
|
+
const record = requireRecord(value);
|
|
566
|
+
const type = record["type"];
|
|
567
|
+
let allowed;
|
|
568
|
+
let numbers;
|
|
569
|
+
let nullableStrings;
|
|
570
|
+
if (type === "char_location") {
|
|
571
|
+
allowed = CITATION_CHAR_KEYS;
|
|
572
|
+
numbers = ["document_index", "end_char_index", "start_char_index"];
|
|
573
|
+
nullableStrings = ["document_title"];
|
|
574
|
+
}
|
|
575
|
+
else if (type === "content_block_location") {
|
|
576
|
+
allowed = CITATION_CONTENT_BLOCK_KEYS;
|
|
577
|
+
numbers = ["document_index", "end_block_index", "start_block_index"];
|
|
578
|
+
nullableStrings = ["document_title"];
|
|
579
|
+
}
|
|
580
|
+
else if (type === "page_location") {
|
|
581
|
+
allowed = CITATION_PAGE_KEYS;
|
|
582
|
+
numbers = ["document_index", "end_page_number", "start_page_number"];
|
|
583
|
+
nullableStrings = ["document_title"];
|
|
584
|
+
}
|
|
585
|
+
else if (type === "search_result_location") {
|
|
586
|
+
allowed = CITATION_SEARCH_RESULT_KEYS;
|
|
587
|
+
numbers = ["end_block_index", "search_result_index", "start_block_index"];
|
|
588
|
+
nullableStrings = ["title"];
|
|
589
|
+
}
|
|
590
|
+
else if (type === "web_search_result_location") {
|
|
591
|
+
allowed = CITATION_WEB_SEARCH_KEYS;
|
|
592
|
+
numbers = [];
|
|
593
|
+
nullableStrings = ["title"];
|
|
594
|
+
}
|
|
595
|
+
else {
|
|
596
|
+
return fail("INVALID_INPUT");
|
|
597
|
+
}
|
|
598
|
+
assertExactKeys(record, allowed);
|
|
599
|
+
requireKeys(record, [...allowed]);
|
|
600
|
+
const entries = [];
|
|
601
|
+
for (const key of Object.keys(record)) {
|
|
602
|
+
const item = record[key];
|
|
603
|
+
if (key === "type")
|
|
604
|
+
entries.push([key, type]);
|
|
605
|
+
else if (numbers.includes(key))
|
|
606
|
+
entries.push([key, requireNumber(item)]);
|
|
607
|
+
else if (nullableStrings.includes(key))
|
|
608
|
+
entries.push([key, nullable(item, requireString)]);
|
|
609
|
+
else
|
|
610
|
+
entries.push([key, requireString(item)]);
|
|
611
|
+
}
|
|
612
|
+
return Object.fromEntries(entries);
|
|
613
|
+
}
|
|
614
|
+
function textBlock(value) {
|
|
615
|
+
const record = requireRecord(value);
|
|
616
|
+
assertExactKeys(record, TEXT_KEYS);
|
|
617
|
+
requireKeys(record, ["text", "type"]);
|
|
618
|
+
if (record["type"] !== "text")
|
|
619
|
+
fail("INVALID_INPUT");
|
|
620
|
+
const entries = [];
|
|
621
|
+
for (const key of Object.keys(record)) {
|
|
622
|
+
const item = record[key];
|
|
623
|
+
if (key === "text")
|
|
624
|
+
entries.push([key, requireString(item)]);
|
|
625
|
+
else if (key === "type")
|
|
626
|
+
entries.push([key, "text"]);
|
|
627
|
+
else if (key === "cache_control")
|
|
628
|
+
entries.push([key, nullable(item, (raw) => cacheControl(raw, true))]);
|
|
629
|
+
else {
|
|
630
|
+
if (item === null)
|
|
631
|
+
entries.push([key, null]);
|
|
632
|
+
else {
|
|
633
|
+
if (!Array.isArray(item))
|
|
634
|
+
fail("INVALID_INPUT");
|
|
635
|
+
entries.push([key, item.map((citation) => textCitation(citation))]);
|
|
636
|
+
}
|
|
637
|
+
}
|
|
638
|
+
}
|
|
639
|
+
return Object.fromEntries(entries);
|
|
640
|
+
}
|
|
641
|
+
function imageBlock(value) {
|
|
642
|
+
const record = requireRecord(value);
|
|
643
|
+
assertExactKeys(record, IMAGE_BLOCK_KEYS);
|
|
644
|
+
requireKeys(record, ["source", "type"]);
|
|
645
|
+
if (record["type"] !== "image")
|
|
646
|
+
fail("INVALID_INPUT");
|
|
647
|
+
const entries = [];
|
|
648
|
+
for (const key of Object.keys(record)) {
|
|
649
|
+
const item = record[key];
|
|
650
|
+
if (key === "type")
|
|
651
|
+
entries.push([key, "image"]);
|
|
652
|
+
else if (key === "cache_control")
|
|
653
|
+
entries.push([key, nullable(item, cacheControl)]);
|
|
654
|
+
else
|
|
655
|
+
entries.push([key, imageSource(item)]);
|
|
656
|
+
}
|
|
657
|
+
return Object.fromEntries(entries);
|
|
658
|
+
}
|
|
659
|
+
function imageSource(value) {
|
|
660
|
+
const record = requireRecord(value);
|
|
661
|
+
const type = record["type"];
|
|
662
|
+
const allowed = type === "base64"
|
|
663
|
+
? BASE64_IMAGE_SOURCE_KEYS
|
|
664
|
+
: type === "file"
|
|
665
|
+
? FILE_IMAGE_SOURCE_KEYS
|
|
666
|
+
: type === "url"
|
|
667
|
+
? URL_IMAGE_SOURCE_KEYS
|
|
668
|
+
: fail("INVALID_INPUT");
|
|
669
|
+
assertExactKeys(record, allowed);
|
|
670
|
+
requireKeys(record, [...allowed]);
|
|
671
|
+
const entries = [];
|
|
672
|
+
for (const key of Object.keys(record)) {
|
|
673
|
+
const item = record[key];
|
|
674
|
+
if (key === "type")
|
|
675
|
+
entries.push([key, type]);
|
|
676
|
+
else if (key === "media_type") {
|
|
677
|
+
if (item !== "image/jpeg" &&
|
|
678
|
+
item !== "image/png" &&
|
|
679
|
+
item !== "image/gif" &&
|
|
680
|
+
item !== "image/webp")
|
|
681
|
+
fail("INVALID_INPUT");
|
|
682
|
+
entries.push([key, item]);
|
|
683
|
+
}
|
|
684
|
+
else
|
|
685
|
+
entries.push([key, requireString(item)]);
|
|
686
|
+
}
|
|
687
|
+
return Object.fromEntries(entries);
|
|
688
|
+
}
|
|
689
|
+
function documentBlock(value) {
|
|
690
|
+
const record = requireRecord(value);
|
|
691
|
+
assertExactKeys(record, DOCUMENT_BLOCK_KEYS);
|
|
692
|
+
requireKeys(record, ["source", "type"]);
|
|
693
|
+
if (record["type"] !== "document")
|
|
694
|
+
fail("INVALID_INPUT");
|
|
695
|
+
const entries = [];
|
|
696
|
+
for (const key of Object.keys(record)) {
|
|
697
|
+
const item = record[key];
|
|
698
|
+
if (key === "source")
|
|
699
|
+
entries.push([key, documentSource(item)]);
|
|
700
|
+
else if (key === "type")
|
|
701
|
+
entries.push([key, "document"]);
|
|
702
|
+
else if (key === "cache_control")
|
|
703
|
+
entries.push([key, nullable(item, cacheControl)]);
|
|
704
|
+
else if (key === "citations")
|
|
705
|
+
entries.push([key, nullable(item, citationsConfig)]);
|
|
706
|
+
else
|
|
707
|
+
entries.push([key, nullable(item, requireString)]);
|
|
708
|
+
}
|
|
709
|
+
return Object.fromEntries(entries);
|
|
710
|
+
}
|
|
711
|
+
function documentSource(value) {
|
|
712
|
+
const record = requireRecord(value);
|
|
713
|
+
const type = record["type"];
|
|
714
|
+
let allowed;
|
|
715
|
+
if (type === "base64")
|
|
716
|
+
allowed = BASE64_PDF_SOURCE_KEYS;
|
|
717
|
+
else if (type === "text")
|
|
718
|
+
allowed = PLAIN_TEXT_SOURCE_KEYS;
|
|
719
|
+
else if (type === "content")
|
|
720
|
+
allowed = CONTENT_BLOCK_SOURCE_KEYS;
|
|
721
|
+
else if (type === "url")
|
|
722
|
+
allowed = URL_PDF_SOURCE_KEYS;
|
|
723
|
+
else if (type === "file")
|
|
724
|
+
allowed = FILE_DOCUMENT_SOURCE_KEYS;
|
|
725
|
+
else
|
|
726
|
+
return fail("INVALID_INPUT");
|
|
727
|
+
assertExactKeys(record, allowed);
|
|
728
|
+
requireKeys(record, [...allowed]);
|
|
729
|
+
const entries = [];
|
|
730
|
+
for (const key of Object.keys(record)) {
|
|
731
|
+
const item = record[key];
|
|
732
|
+
if (key === "type")
|
|
733
|
+
entries.push([key, type]);
|
|
734
|
+
else if (key === "media_type") {
|
|
735
|
+
if ((type === "base64" && item !== "application/pdf") ||
|
|
736
|
+
(type === "text" && item !== "text/plain"))
|
|
737
|
+
fail("INVALID_INPUT");
|
|
738
|
+
entries.push([key, item]);
|
|
739
|
+
}
|
|
740
|
+
else if (key === "content") {
|
|
741
|
+
if (typeof item === "string")
|
|
742
|
+
entries.push([key, item]);
|
|
743
|
+
else {
|
|
744
|
+
if (!Array.isArray(item))
|
|
745
|
+
fail("INVALID_INPUT");
|
|
746
|
+
entries.push([
|
|
747
|
+
key,
|
|
748
|
+
item.map((block) => {
|
|
749
|
+
const blockRecord = requireRecord(block);
|
|
750
|
+
if (blockRecord["type"] === "text")
|
|
751
|
+
return textBlock(blockRecord);
|
|
752
|
+
if (blockRecord["type"] === "image")
|
|
753
|
+
return imageBlock(blockRecord);
|
|
754
|
+
return fail("INVALID_INPUT");
|
|
755
|
+
}),
|
|
756
|
+
]);
|
|
757
|
+
}
|
|
758
|
+
}
|
|
759
|
+
else
|
|
760
|
+
entries.push([key, requireString(item)]);
|
|
761
|
+
}
|
|
762
|
+
return Object.fromEntries(entries);
|
|
763
|
+
}
|
|
764
|
+
function thinkingBlock(value) {
|
|
765
|
+
const record = requireRecord(value);
|
|
766
|
+
assertExactKeys(record, THINKING_BLOCK_KEYS);
|
|
767
|
+
requireKeys(record, ["signature", "thinking", "type"]);
|
|
768
|
+
if (record["type"] !== "thinking")
|
|
769
|
+
fail("INVALID_INPUT");
|
|
770
|
+
return Object.fromEntries(Object.keys(record).map((key) => [
|
|
771
|
+
key,
|
|
772
|
+
key === "type" ? "thinking" : requireString(record[key]),
|
|
773
|
+
]));
|
|
774
|
+
}
|
|
775
|
+
function redactedThinkingBlock(value) {
|
|
776
|
+
const record = requireRecord(value);
|
|
777
|
+
assertExactKeys(record, REDACTED_THINKING_BLOCK_KEYS);
|
|
778
|
+
requireKeys(record, ["data", "type"]);
|
|
779
|
+
if (record["type"] !== "redacted_thinking")
|
|
780
|
+
fail("INVALID_INPUT");
|
|
781
|
+
return Object.fromEntries(Object.keys(record).map((key) => [
|
|
782
|
+
key,
|
|
783
|
+
key === "type" ? "redacted_thinking" : requireString(record[key]),
|
|
784
|
+
]));
|
|
785
|
+
}
|
|
786
|
+
function searchResultBlock(value) {
|
|
787
|
+
const record = requireRecord(value);
|
|
788
|
+
assertExactKeys(record, SEARCH_RESULT_KEYS);
|
|
789
|
+
requireKeys(record, ["content", "source", "title", "type"]);
|
|
790
|
+
if (record["type"] !== "search_result")
|
|
791
|
+
fail("INVALID_INPUT");
|
|
792
|
+
const entries = [];
|
|
793
|
+
for (const key of Object.keys(record)) {
|
|
794
|
+
const item = record[key];
|
|
795
|
+
if (key === "content") {
|
|
796
|
+
if (!Array.isArray(item))
|
|
797
|
+
fail("INVALID_INPUT");
|
|
798
|
+
entries.push([key, item.map((block) => textBlock(block))]);
|
|
799
|
+
}
|
|
800
|
+
else if (key === "source" || key === "title")
|
|
801
|
+
entries.push([key, requireString(item)]);
|
|
802
|
+
else if (key === "type")
|
|
803
|
+
entries.push([key, "search_result"]);
|
|
804
|
+
else if (key === "cache_control")
|
|
805
|
+
entries.push([key, nullable(item, cacheControl)]);
|
|
806
|
+
else
|
|
807
|
+
entries.push([key, citationsConfig(item)]);
|
|
808
|
+
}
|
|
809
|
+
return Object.fromEntries(entries);
|
|
810
|
+
}
|
|
811
|
+
function toolReferenceBlock(value) {
|
|
812
|
+
const record = requireRecord(value);
|
|
813
|
+
assertExactKeys(record, TOOL_REFERENCE_KEYS);
|
|
814
|
+
requireKeys(record, ["tool_name", "type"]);
|
|
815
|
+
if (record["type"] !== "tool_reference")
|
|
816
|
+
fail("INVALID_INPUT");
|
|
817
|
+
const entries = [];
|
|
818
|
+
for (const key of Object.keys(record)) {
|
|
819
|
+
const item = record[key];
|
|
820
|
+
if (key === "tool_name")
|
|
821
|
+
entries.push([key, requireString(item)]);
|
|
822
|
+
else if (key === "type")
|
|
823
|
+
entries.push([key, "tool_reference"]);
|
|
824
|
+
else
|
|
825
|
+
entries.push([key, nullable(item, cacheControl)]);
|
|
826
|
+
}
|
|
827
|
+
return Object.fromEntries(entries);
|
|
828
|
+
}
|
|
829
|
+
function toolUseBlock(value) {
|
|
830
|
+
const record = requireRecord(value);
|
|
831
|
+
assertExactKeys(record, TOOL_USE_KEYS);
|
|
832
|
+
requireKeys(record, ["id", "input", "name", "type"]);
|
|
833
|
+
if (record["type"] !== "tool_use")
|
|
834
|
+
fail("INVALID_INPUT");
|
|
835
|
+
const entries = [];
|
|
836
|
+
for (const key of Object.keys(record)) {
|
|
837
|
+
const item = record[key];
|
|
838
|
+
if (key === "id" || key === "name")
|
|
839
|
+
entries.push([key, requireString(item)]);
|
|
840
|
+
else if (key === "input")
|
|
841
|
+
entries.push([key, validatedJson(item)]);
|
|
842
|
+
else if (key === "type")
|
|
843
|
+
entries.push([key, "tool_use"]);
|
|
844
|
+
else if (key === "cache_control")
|
|
845
|
+
entries.push([key, nullable(item, cacheControl)]);
|
|
846
|
+
else
|
|
847
|
+
entries.push([key, toolCaller(item)]);
|
|
848
|
+
}
|
|
849
|
+
return Object.fromEntries(entries);
|
|
850
|
+
}
|
|
851
|
+
function toolCaller(value) {
|
|
852
|
+
const record = requireRecord(value);
|
|
853
|
+
const type = record["type"];
|
|
854
|
+
if (type === "direct") {
|
|
855
|
+
assertExactKeys(record, DIRECT_CALLER_KEYS);
|
|
856
|
+
requireKeys(record, ["type"]);
|
|
857
|
+
return { type };
|
|
858
|
+
}
|
|
859
|
+
if (type !== "code_execution_20250825" && type !== "code_execution_20260120")
|
|
860
|
+
return fail("INVALID_INPUT");
|
|
861
|
+
assertExactKeys(record, SERVER_TOOL_CALLER_KEYS);
|
|
862
|
+
requireKeys(record, ["tool_id", "type"]);
|
|
863
|
+
return Object.fromEntries(Object.keys(record).map((key) => [
|
|
864
|
+
key,
|
|
865
|
+
key === "type" ? type : requireString(record[key]),
|
|
866
|
+
]));
|
|
867
|
+
}
|
|
868
|
+
function toolResultContentBlock(value) {
|
|
869
|
+
const record = requireRecord(value);
|
|
870
|
+
if (record["type"] === "text")
|
|
871
|
+
return textBlock(record);
|
|
872
|
+
if (record["type"] === "image")
|
|
873
|
+
return imageBlock(record);
|
|
874
|
+
if (record["type"] === "search_result")
|
|
875
|
+
return searchResultBlock(record);
|
|
876
|
+
if (record["type"] === "document")
|
|
877
|
+
return documentBlock(record);
|
|
878
|
+
if (record["type"] === "tool_reference")
|
|
879
|
+
return toolReferenceBlock(record);
|
|
880
|
+
return fail("INVALID_INPUT");
|
|
881
|
+
}
|
|
882
|
+
function toolResultBlock(value) {
|
|
883
|
+
const record = requireRecord(value);
|
|
884
|
+
assertExactKeys(record, TOOL_RESULT_KEYS);
|
|
885
|
+
requireKeys(record, ["tool_use_id", "type"]);
|
|
886
|
+
if (record["type"] !== "tool_result")
|
|
887
|
+
fail("INVALID_INPUT");
|
|
888
|
+
const entries = [];
|
|
889
|
+
for (const key of Object.keys(record)) {
|
|
890
|
+
const item = record[key];
|
|
891
|
+
if (key === "tool_use_id")
|
|
892
|
+
entries.push([key, requireString(item)]);
|
|
893
|
+
else if (key === "type")
|
|
894
|
+
entries.push([key, "tool_result"]);
|
|
895
|
+
else if (key === "cache_control")
|
|
896
|
+
entries.push([key, nullable(item, cacheControl)]);
|
|
897
|
+
else if (key === "content") {
|
|
898
|
+
if (typeof item === "string")
|
|
899
|
+
entries.push([key, item]);
|
|
900
|
+
else {
|
|
901
|
+
if (!Array.isArray(item))
|
|
902
|
+
fail("INVALID_INPUT");
|
|
903
|
+
entries.push([key, item.map((block) => toolResultContentBlock(block))]);
|
|
904
|
+
}
|
|
905
|
+
}
|
|
906
|
+
else
|
|
907
|
+
entries.push([key, requireBoolean(item)]);
|
|
908
|
+
}
|
|
909
|
+
return Object.fromEntries(entries);
|
|
910
|
+
}
|
|
911
|
+
function messageContentBlock(value) {
|
|
912
|
+
const record = requireRecord(value);
|
|
913
|
+
if (record["type"] === "text")
|
|
914
|
+
return textBlock(record);
|
|
915
|
+
if (record["type"] === "image")
|
|
916
|
+
return imageBlock(record);
|
|
917
|
+
if (record["type"] === "document")
|
|
918
|
+
return documentBlock(record);
|
|
919
|
+
if (record["type"] === "search_result")
|
|
920
|
+
return searchResultBlock(record);
|
|
921
|
+
if (record["type"] === "thinking")
|
|
922
|
+
return thinkingBlock(record);
|
|
923
|
+
if (record["type"] === "redacted_thinking")
|
|
924
|
+
return redactedThinkingBlock(record);
|
|
925
|
+
return fail("INVALID_INPUT");
|
|
926
|
+
}
|
|
927
|
+
function messages(value) {
|
|
928
|
+
if (!Array.isArray(value))
|
|
929
|
+
fail("INVALID_INPUT");
|
|
930
|
+
const useIds = new Set();
|
|
931
|
+
const resultIds = [];
|
|
932
|
+
const result = value.map((item) => {
|
|
933
|
+
const record = requireRecord(item);
|
|
934
|
+
assertExactKeys(record, MESSAGE_KEYS);
|
|
935
|
+
const role = record["role"];
|
|
936
|
+
if (role !== "user" && role !== "assistant")
|
|
937
|
+
fail("INVALID_INPUT");
|
|
938
|
+
const rawContent = record["content"];
|
|
939
|
+
if (typeof rawContent === "string")
|
|
940
|
+
return { role, content: rawContent };
|
|
941
|
+
if (!Array.isArray(rawContent))
|
|
942
|
+
fail("INVALID_INPUT");
|
|
943
|
+
const content = rawContent.map((block) => {
|
|
944
|
+
const blockRecord = requireRecord(block);
|
|
945
|
+
if (blockRecord["type"] === "text")
|
|
946
|
+
return textBlock(blockRecord);
|
|
947
|
+
if (blockRecord["type"] === "tool_use") {
|
|
948
|
+
const parsed = toolUseBlock(blockRecord);
|
|
949
|
+
if (useIds.has(parsed.id))
|
|
950
|
+
fail("INVALID_INPUT");
|
|
951
|
+
useIds.add(parsed.id);
|
|
952
|
+
return parsed;
|
|
953
|
+
}
|
|
954
|
+
if (blockRecord["type"] === "tool_result") {
|
|
955
|
+
const parsed = toolResultBlock(blockRecord);
|
|
956
|
+
resultIds.push(parsed.tool_use_id);
|
|
957
|
+
return parsed;
|
|
958
|
+
}
|
|
959
|
+
return messageContentBlock(blockRecord);
|
|
960
|
+
});
|
|
961
|
+
return { role, content };
|
|
962
|
+
});
|
|
963
|
+
for (const id of resultIds) {
|
|
964
|
+
if (!useIds.has(id))
|
|
965
|
+
fail("INVALID_INPUT");
|
|
966
|
+
}
|
|
967
|
+
return result;
|
|
968
|
+
}
|
|
969
|
+
function system(value) {
|
|
970
|
+
if (!Array.isArray(value))
|
|
971
|
+
fail("INVALID_INPUT");
|
|
972
|
+
return value.map((item) => typeof item === "string" ? { type: "text", text: item } : textBlock(item));
|
|
973
|
+
}
|
|
974
|
+
function stringArray(value) {
|
|
975
|
+
if (!Array.isArray(value))
|
|
976
|
+
fail("INVALID_INPUT");
|
|
977
|
+
return value.map((item) => requireString(item));
|
|
978
|
+
}
|
|
979
|
+
function allowedCallers(value) {
|
|
980
|
+
const callers = stringArray(value);
|
|
981
|
+
for (const caller of callers) {
|
|
982
|
+
if (caller !== "direct" &&
|
|
983
|
+
caller !== "code_execution_20250825" &&
|
|
984
|
+
caller !== "code_execution_20260120") {
|
|
985
|
+
fail("INVALID_INPUT");
|
|
986
|
+
}
|
|
987
|
+
}
|
|
988
|
+
return callers;
|
|
989
|
+
}
|
|
990
|
+
function inputExamples(value) {
|
|
991
|
+
if (!Array.isArray(value))
|
|
992
|
+
fail("INVALID_INPUT");
|
|
993
|
+
return value.map((example) => validatedJsonObject(example));
|
|
994
|
+
}
|
|
995
|
+
function toolInputSchema(value) {
|
|
996
|
+
const record = requireRecord(value);
|
|
997
|
+
if (hasOwn(record, "type") && record["type"] !== "object")
|
|
998
|
+
fail("INVALID_INPUT");
|
|
999
|
+
const entries = [];
|
|
1000
|
+
for (const key of Object.keys(record)) {
|
|
1001
|
+
const item = record[key];
|
|
1002
|
+
if (key === "type")
|
|
1003
|
+
entries.push([key, "object"]);
|
|
1004
|
+
else if (key === "required")
|
|
1005
|
+
entries.push([key, nullable(item, stringArray)]);
|
|
1006
|
+
else
|
|
1007
|
+
entries.push([key, validatedJson(item)]);
|
|
1008
|
+
}
|
|
1009
|
+
return Object.fromEntries(entries);
|
|
1010
|
+
}
|
|
1011
|
+
function userLocation(value) {
|
|
1012
|
+
const record = requireRecord(value);
|
|
1013
|
+
assertExactKeys(record, USER_LOCATION_KEYS);
|
|
1014
|
+
requireKeys(record, ["type"]);
|
|
1015
|
+
if (record["type"] !== "approximate")
|
|
1016
|
+
fail("INVALID_INPUT");
|
|
1017
|
+
const entries = [];
|
|
1018
|
+
for (const key of Object.keys(record)) {
|
|
1019
|
+
entries.push([
|
|
1020
|
+
key,
|
|
1021
|
+
key === "type" ? "approximate" : nullable(record[key], requireString),
|
|
1022
|
+
]);
|
|
1023
|
+
}
|
|
1024
|
+
return Object.fromEntries(entries);
|
|
1025
|
+
}
|
|
1026
|
+
function mcpToolConfig(value) {
|
|
1027
|
+
const record = requireRecord(value);
|
|
1028
|
+
assertExactKeys(record, MCP_TOOL_CONFIG_KEYS);
|
|
1029
|
+
requireKeys(record, []);
|
|
1030
|
+
return Object.fromEntries(Object.keys(record).map((key) => [key, requireBoolean(record[key])]));
|
|
1031
|
+
}
|
|
1032
|
+
function mcpConfigs(value) {
|
|
1033
|
+
const record = requireRecord(value);
|
|
1034
|
+
return Object.fromEntries(Object.keys(record).map((key) => [key, mcpToolConfig(record[key])]));
|
|
1035
|
+
}
|
|
1036
|
+
function builtInToolSpec(type) {
|
|
1037
|
+
if (type === "bash_20241022" || type === "bash_20250124") {
|
|
1038
|
+
return {
|
|
1039
|
+
name: "bash",
|
|
1040
|
+
allowed: BASH_TOOL_KEYS,
|
|
1041
|
+
required: ["name", "type"],
|
|
1042
|
+
};
|
|
1043
|
+
}
|
|
1044
|
+
if (type === "code_execution_20250522" ||
|
|
1045
|
+
type === "code_execution_20250825" ||
|
|
1046
|
+
type === "code_execution_20260120") {
|
|
1047
|
+
return {
|
|
1048
|
+
name: "code_execution",
|
|
1049
|
+
allowed: CODE_EXECUTION_TOOL_KEYS,
|
|
1050
|
+
required: ["name", "type"],
|
|
1051
|
+
};
|
|
1052
|
+
}
|
|
1053
|
+
if (type === "computer_20241022" ||
|
|
1054
|
+
type === "computer_20250124" ||
|
|
1055
|
+
type === "computer_20251124") {
|
|
1056
|
+
return {
|
|
1057
|
+
name: "computer",
|
|
1058
|
+
allowed: type === "computer_20251124"
|
|
1059
|
+
? COMPUTER_ZOOM_TOOL_KEYS
|
|
1060
|
+
: COMPUTER_TOOL_KEYS,
|
|
1061
|
+
required: ["display_height_px", "display_width_px", "name", "type"],
|
|
1062
|
+
};
|
|
1063
|
+
}
|
|
1064
|
+
if (type === "memory_20250818") {
|
|
1065
|
+
return {
|
|
1066
|
+
name: "memory",
|
|
1067
|
+
allowed: MEMORY_TOOL_KEYS,
|
|
1068
|
+
required: ["name", "type"],
|
|
1069
|
+
};
|
|
1070
|
+
}
|
|
1071
|
+
if (type === "text_editor_20241022" ||
|
|
1072
|
+
type === "text_editor_20250124" ||
|
|
1073
|
+
type === "text_editor_20250429" ||
|
|
1074
|
+
type === "text_editor_20250728") {
|
|
1075
|
+
return {
|
|
1076
|
+
name: type === "text_editor_20241022" || type === "text_editor_20250124"
|
|
1077
|
+
? "str_replace_editor"
|
|
1078
|
+
: "str_replace_based_edit_tool",
|
|
1079
|
+
allowed: type === "text_editor_20250728"
|
|
1080
|
+
? TEXT_EDITOR_MAX_TOOL_KEYS
|
|
1081
|
+
: TEXT_EDITOR_TOOL_KEYS,
|
|
1082
|
+
required: ["name", "type"],
|
|
1083
|
+
};
|
|
1084
|
+
}
|
|
1085
|
+
if (type === "web_search_20250305" || type === "web_search_20260209") {
|
|
1086
|
+
return {
|
|
1087
|
+
name: "web_search",
|
|
1088
|
+
allowed: WEB_SEARCH_TOOL_KEYS,
|
|
1089
|
+
required: ["name", "type"],
|
|
1090
|
+
};
|
|
1091
|
+
}
|
|
1092
|
+
if (type === "web_fetch_20250910" ||
|
|
1093
|
+
type === "web_fetch_20260209" ||
|
|
1094
|
+
type === "web_fetch_20260309") {
|
|
1095
|
+
return {
|
|
1096
|
+
name: "web_fetch",
|
|
1097
|
+
allowed: type === "web_fetch_20260309"
|
|
1098
|
+
? WEB_FETCH_CACHE_TOOL_KEYS
|
|
1099
|
+
: WEB_FETCH_TOOL_KEYS,
|
|
1100
|
+
required: ["name", "type"],
|
|
1101
|
+
};
|
|
1102
|
+
}
|
|
1103
|
+
if (type === "advisor_20260301") {
|
|
1104
|
+
return {
|
|
1105
|
+
name: "advisor",
|
|
1106
|
+
allowed: ADVISOR_TOOL_KEYS,
|
|
1107
|
+
required: ["model", "name", "type"],
|
|
1108
|
+
};
|
|
1109
|
+
}
|
|
1110
|
+
if (type === "tool_search_tool_bm25_20251119" ||
|
|
1111
|
+
type === "tool_search_tool_bm25") {
|
|
1112
|
+
return {
|
|
1113
|
+
name: "tool_search_tool_bm25",
|
|
1114
|
+
allowed: TOOL_SEARCH_KEYS,
|
|
1115
|
+
required: ["name", "type"],
|
|
1116
|
+
};
|
|
1117
|
+
}
|
|
1118
|
+
if (type === "tool_search_tool_regex_20251119" ||
|
|
1119
|
+
type === "tool_search_tool_regex") {
|
|
1120
|
+
return {
|
|
1121
|
+
name: "tool_search_tool_regex",
|
|
1122
|
+
allowed: TOOL_SEARCH_KEYS,
|
|
1123
|
+
required: ["name", "type"],
|
|
1124
|
+
};
|
|
1125
|
+
}
|
|
1126
|
+
if (type === "mcp_toolset") {
|
|
1127
|
+
return {
|
|
1128
|
+
allowed: MCP_TOOLSET_KEYS,
|
|
1129
|
+
required: ["mcp_server_name", "type"],
|
|
1130
|
+
};
|
|
1131
|
+
}
|
|
1132
|
+
return fail("INVALID_INPUT");
|
|
1133
|
+
}
|
|
1134
|
+
function customToolDefinition(record) {
|
|
1135
|
+
assertExactKeys(record, CUSTOM_TOOL_KEYS);
|
|
1136
|
+
requireKeys(record, ["input_schema", "name"]);
|
|
1137
|
+
const entries = [];
|
|
1138
|
+
for (const key of Object.keys(record)) {
|
|
1139
|
+
const item = record[key];
|
|
1140
|
+
if (key === "input_schema")
|
|
1141
|
+
entries.push([key, toolInputSchema(item)]);
|
|
1142
|
+
else if (key === "name" || key === "description")
|
|
1143
|
+
entries.push([key, requireString(item)]);
|
|
1144
|
+
else if (key === "allowed_callers")
|
|
1145
|
+
entries.push([key, allowedCallers(item)]);
|
|
1146
|
+
else if (key === "cache_control")
|
|
1147
|
+
entries.push([key, nullable(item, (raw) => cacheControl(raw, true))]);
|
|
1148
|
+
else if (key === "defer_loading" || key === "strict")
|
|
1149
|
+
entries.push([key, requireBoolean(item)]);
|
|
1150
|
+
else if (key === "eager_input_streaming")
|
|
1151
|
+
entries.push([key, nullable(item, requireBoolean)]);
|
|
1152
|
+
else
|
|
1153
|
+
entries.push([key, inputExamples(item)]);
|
|
1154
|
+
}
|
|
1155
|
+
return Object.fromEntries(entries);
|
|
1156
|
+
}
|
|
1157
|
+
function builtInToolDefinition(record) {
|
|
1158
|
+
const type = record["type"];
|
|
1159
|
+
const spec = builtInToolSpec(type);
|
|
1160
|
+
assertExactKeys(record, spec.allowed);
|
|
1161
|
+
requireKeys(record, spec.required);
|
|
1162
|
+
const entries = [];
|
|
1163
|
+
for (const key of Object.keys(record)) {
|
|
1164
|
+
const item = record[key];
|
|
1165
|
+
if (key === "type")
|
|
1166
|
+
entries.push([key, type]);
|
|
1167
|
+
else if (key === "name") {
|
|
1168
|
+
if (item !== spec.name)
|
|
1169
|
+
fail("INVALID_INPUT");
|
|
1170
|
+
entries.push([key, item]);
|
|
1171
|
+
}
|
|
1172
|
+
else if (key === "mcp_server_name" || key === "model")
|
|
1173
|
+
entries.push([key, requireString(item)]);
|
|
1174
|
+
else if (key === "allowed_callers")
|
|
1175
|
+
entries.push([key, allowedCallers(item)]);
|
|
1176
|
+
else if (key === "cache_control" || key === "caching")
|
|
1177
|
+
entries.push([key, nullable(item, cacheControl)]);
|
|
1178
|
+
else if (key === "defer_loading" ||
|
|
1179
|
+
key === "strict" ||
|
|
1180
|
+
key === "enable_zoom" ||
|
|
1181
|
+
key === "use_cache")
|
|
1182
|
+
entries.push([key, requireBoolean(item)]);
|
|
1183
|
+
else if (key === "input_examples")
|
|
1184
|
+
entries.push([key, inputExamples(item)]);
|
|
1185
|
+
else if (key === "display_height_px" || key === "display_width_px")
|
|
1186
|
+
entries.push([key, requireNumber(item)]);
|
|
1187
|
+
else if (key === "display_number" ||
|
|
1188
|
+
key === "max_characters" ||
|
|
1189
|
+
key === "max_content_tokens" ||
|
|
1190
|
+
key === "max_uses")
|
|
1191
|
+
entries.push([key, nullable(item, requireNumber)]);
|
|
1192
|
+
else if (key === "allowed_domains" || key === "blocked_domains")
|
|
1193
|
+
entries.push([key, nullable(item, stringArray)]);
|
|
1194
|
+
else if (key === "citations")
|
|
1195
|
+
entries.push([key, nullable(item, citationsConfig)]);
|
|
1196
|
+
else if (key === "user_location")
|
|
1197
|
+
entries.push([key, nullable(item, userLocation)]);
|
|
1198
|
+
else if (key === "configs")
|
|
1199
|
+
entries.push([key, nullable(item, mcpConfigs)]);
|
|
1200
|
+
else if (key === "default_config")
|
|
1201
|
+
entries.push([key, mcpToolConfig(item)]);
|
|
1202
|
+
else
|
|
1203
|
+
fail("INVALID_INPUT");
|
|
1204
|
+
}
|
|
1205
|
+
return Object.fromEntries(entries);
|
|
1206
|
+
}
|
|
1207
|
+
function tools(value) {
|
|
1208
|
+
if (!Array.isArray(value))
|
|
1209
|
+
fail("INVALID_INPUT");
|
|
1210
|
+
const names = new Set();
|
|
1211
|
+
return value.map((item) => {
|
|
1212
|
+
const record = requireRecord(item);
|
|
1213
|
+
const result = hasOwn(record, "type")
|
|
1214
|
+
? builtInToolDefinition(record)
|
|
1215
|
+
: customToolDefinition(record);
|
|
1216
|
+
if (hasOwn(record, "name")) {
|
|
1217
|
+
const name = requireString(record["name"]);
|
|
1218
|
+
if (names.has(name))
|
|
1219
|
+
fail("INVALID_INPUT");
|
|
1220
|
+
names.add(name);
|
|
1221
|
+
}
|
|
1222
|
+
return result;
|
|
1223
|
+
});
|
|
1224
|
+
}
|
|
1225
|
+
function capabilityBoolean(value, fallback) {
|
|
1226
|
+
if (value === undefined)
|
|
1227
|
+
return fallback;
|
|
1228
|
+
if (typeof value !== "boolean")
|
|
1229
|
+
fail("INVALID_INPUT");
|
|
1230
|
+
return value;
|
|
1231
|
+
}
|
|
1232
|
+
function modelResolution(value) {
|
|
1233
|
+
const record = requireRecord(value);
|
|
1234
|
+
const capabilityValue = record["capabilities"];
|
|
1235
|
+
// A catalogue-shaped capability array is accepted at this boundary, but it
|
|
1236
|
+
// never affects derivation: on first party every predicate depends only on
|
|
1237
|
+
// the normalized id. See the header of `model-capabilities.ts`. The elements
|
|
1238
|
+
// are still validated so that malformed input fails closed.
|
|
1239
|
+
if (Array.isArray(capabilityValue)) {
|
|
1240
|
+
for (const capability of capabilityValue) {
|
|
1241
|
+
if (typeof capability !== "string")
|
|
1242
|
+
fail("INVALID_INPUT");
|
|
1243
|
+
}
|
|
1244
|
+
}
|
|
1245
|
+
const capabilities = Array.isArray(capabilityValue)
|
|
1246
|
+
? deriveCapabilities(String(record["id"]))
|
|
1247
|
+
: requireRecord(capabilityValue);
|
|
1248
|
+
const derived = deriveCapabilities(String(record["id"]));
|
|
1249
|
+
if ((capabilities.thinking !== undefined &&
|
|
1250
|
+
typeof capabilities.thinking !== "boolean") ||
|
|
1251
|
+
(capabilities.adaptiveThinking !== undefined &&
|
|
1252
|
+
typeof capabilities.adaptiveThinking !== "boolean") ||
|
|
1253
|
+
(capabilities.interleavedThinking !== undefined &&
|
|
1254
|
+
typeof capabilities.interleavedThinking !== "boolean") ||
|
|
1255
|
+
(capabilities.effort !== undefined &&
|
|
1256
|
+
typeof capabilities.effort !== "boolean") ||
|
|
1257
|
+
(capabilities.maxEffort !== undefined &&
|
|
1258
|
+
typeof capabilities.maxEffort !== "boolean") ||
|
|
1259
|
+
(capabilities.xhighEffort !== undefined &&
|
|
1260
|
+
typeof capabilities.xhighEffort !== "boolean") ||
|
|
1261
|
+
(capabilities.contextManagement !== undefined &&
|
|
1262
|
+
typeof capabilities.contextManagement !== "boolean") ||
|
|
1263
|
+
(capabilities.temperature !== undefined &&
|
|
1264
|
+
typeof capabilities.temperature !== "boolean") ||
|
|
1265
|
+
(capabilities.rejectsDisabledThinking !== undefined &&
|
|
1266
|
+
typeof capabilities.rejectsDisabledThinking !== "boolean")) {
|
|
1267
|
+
fail("INVALID_INPUT");
|
|
1268
|
+
}
|
|
1269
|
+
return {
|
|
1270
|
+
id: requireString(record["id"]),
|
|
1271
|
+
wireId: requireString(record["wireId"]),
|
|
1272
|
+
capabilities: {
|
|
1273
|
+
thinking: capabilityBoolean(capabilities.thinking, derived.thinking),
|
|
1274
|
+
adaptiveThinking: capabilityBoolean(capabilities.adaptiveThinking, derived.adaptiveThinking),
|
|
1275
|
+
interleavedThinking: capabilityBoolean(capabilities.interleavedThinking, derived.interleavedThinking),
|
|
1276
|
+
effort: capabilityBoolean(capabilities.effort, derived.effort),
|
|
1277
|
+
maxEffort: capabilityBoolean(capabilities.maxEffort, derived.maxEffort),
|
|
1278
|
+
xhighEffort: capabilityBoolean(capabilities.xhighEffort, derived.xhighEffort),
|
|
1279
|
+
contextManagement: capabilityBoolean(capabilities.contextManagement, derived.contextManagement),
|
|
1280
|
+
temperature: capabilityBoolean(capabilities.temperature, derived.temperature),
|
|
1281
|
+
rejectsDisabledThinking: capabilityBoolean(capabilities.rejectsDisabledThinking, derived.rejectsDisabledThinking),
|
|
1282
|
+
},
|
|
1283
|
+
};
|
|
1284
|
+
}
|
|
1285
|
+
function metadata(value) {
|
|
1286
|
+
const record = requireRecord(value);
|
|
1287
|
+
if (hasOwn(record, "user_id") &&
|
|
1288
|
+
record["user_id"] !== null &&
|
|
1289
|
+
typeof record["user_id"] !== "string") {
|
|
1290
|
+
fail("INVALID_INPUT");
|
|
1291
|
+
}
|
|
1292
|
+
// validatedJsonObject returns a record by construction.
|
|
1293
|
+
return validatedJsonObject(record);
|
|
1294
|
+
}
|
|
1295
|
+
function typedNumberObject(value, allowedTypes) {
|
|
1296
|
+
const record = requireRecord(value);
|
|
1297
|
+
assertExactKeys(record, TYPED_NUMBER_KEYS);
|
|
1298
|
+
requireKeys(record, ["type", "value"]);
|
|
1299
|
+
const type = record["type"];
|
|
1300
|
+
if (typeof type !== "string" || !allowedTypes.includes(type))
|
|
1301
|
+
fail("INVALID_INPUT");
|
|
1302
|
+
const entries = [];
|
|
1303
|
+
for (const key of Object.keys(record)) {
|
|
1304
|
+
entries.push([key, key === "type" ? type : requireNumber(record[key])]);
|
|
1305
|
+
}
|
|
1306
|
+
return Object.fromEntries(entries);
|
|
1307
|
+
}
|
|
1308
|
+
function clearThinkingKeep(value) {
|
|
1309
|
+
if (value === "all")
|
|
1310
|
+
return value;
|
|
1311
|
+
const record = requireRecord(value);
|
|
1312
|
+
if (record["type"] === "all") {
|
|
1313
|
+
assertExactKeys(record, ALL_THINKING_KEYS);
|
|
1314
|
+
requireKeys(record, ["type"]);
|
|
1315
|
+
return { type: "all" };
|
|
1316
|
+
}
|
|
1317
|
+
return typedNumberObject(record, ["thinking_turns"]);
|
|
1318
|
+
}
|
|
1319
|
+
function contextManagementEdit(value) {
|
|
1320
|
+
const record = requireRecord(value);
|
|
1321
|
+
const type = record["type"];
|
|
1322
|
+
let allowed;
|
|
1323
|
+
if (type === "clear_thinking_20251015") {
|
|
1324
|
+
allowed = CLEAR_THINKING_KEYS;
|
|
1325
|
+
}
|
|
1326
|
+
else if (type === "clear_tool_uses_20250919") {
|
|
1327
|
+
allowed = CLEAR_TOOL_USES_KEYS;
|
|
1328
|
+
}
|
|
1329
|
+
else if (type === "compact_20260112") {
|
|
1330
|
+
allowed = COMPACT_KEYS;
|
|
1331
|
+
}
|
|
1332
|
+
else {
|
|
1333
|
+
return fail("INVALID_INPUT");
|
|
1334
|
+
}
|
|
1335
|
+
assertExactKeys(record, allowed);
|
|
1336
|
+
requireKeys(record, ["type"]);
|
|
1337
|
+
const entries = [];
|
|
1338
|
+
for (const key of Object.keys(record)) {
|
|
1339
|
+
const item = record[key];
|
|
1340
|
+
if (key === "type")
|
|
1341
|
+
entries.push([key, type]);
|
|
1342
|
+
else if (type === "clear_thinking_20251015") {
|
|
1343
|
+
entries.push([key, clearThinkingKeep(item)]);
|
|
1344
|
+
}
|
|
1345
|
+
else if (type === "clear_tool_uses_20250919") {
|
|
1346
|
+
if (key === "clear_at_least")
|
|
1347
|
+
entries.push([
|
|
1348
|
+
key,
|
|
1349
|
+
nullable(item, (raw) => typedNumberObject(raw, ["input_tokens"])),
|
|
1350
|
+
]);
|
|
1351
|
+
else if (key === "clear_tool_inputs")
|
|
1352
|
+
entries.push([
|
|
1353
|
+
key,
|
|
1354
|
+
nullable(item, (raw) => typeof raw === "boolean" ? raw : stringArray(raw)),
|
|
1355
|
+
]);
|
|
1356
|
+
else if (key === "exclude_tools")
|
|
1357
|
+
entries.push([key, nullable(item, stringArray)]);
|
|
1358
|
+
else if (key === "keep")
|
|
1359
|
+
entries.push([key, typedNumberObject(item, ["tool_uses"])]);
|
|
1360
|
+
else
|
|
1361
|
+
entries.push([
|
|
1362
|
+
key,
|
|
1363
|
+
typedNumberObject(item, ["input_tokens", "tool_uses"]),
|
|
1364
|
+
]);
|
|
1365
|
+
}
|
|
1366
|
+
else if (key === "instructions")
|
|
1367
|
+
entries.push([key, nullable(item, requireString)]);
|
|
1368
|
+
else if (key === "pause_after_compaction")
|
|
1369
|
+
entries.push([key, requireBoolean(item)]);
|
|
1370
|
+
else
|
|
1371
|
+
entries.push([
|
|
1372
|
+
key,
|
|
1373
|
+
nullable(item, (raw) => typedNumberObject(raw, ["input_tokens"])),
|
|
1374
|
+
]);
|
|
1375
|
+
}
|
|
1376
|
+
return Object.fromEntries(entries);
|
|
1377
|
+
}
|
|
1378
|
+
function contextManagement(value) {
|
|
1379
|
+
const record = requireRecord(value);
|
|
1380
|
+
assertExactKeys(record, CONTEXT_CONFIG_KEYS);
|
|
1381
|
+
requireKeys(record, []);
|
|
1382
|
+
const entries = [];
|
|
1383
|
+
for (const key of Object.keys(record)) {
|
|
1384
|
+
const item = record[key];
|
|
1385
|
+
if (!Array.isArray(item))
|
|
1386
|
+
fail("INVALID_INPUT");
|
|
1387
|
+
entries.push([key, item.map((edit) => contextManagementEdit(edit))]);
|
|
1388
|
+
}
|
|
1389
|
+
return Object.fromEntries(entries);
|
|
1390
|
+
}
|
|
1391
|
+
function outputFormat(value) {
|
|
1392
|
+
const record = requireRecord(value);
|
|
1393
|
+
assertExactKeys(record, JSON_OUTPUT_FORMAT_KEYS);
|
|
1394
|
+
requireKeys(record, ["schema", "type"]);
|
|
1395
|
+
if (record["type"] !== "json_schema")
|
|
1396
|
+
fail("INVALID_INPUT");
|
|
1397
|
+
const entries = [];
|
|
1398
|
+
for (const key of Object.keys(record)) {
|
|
1399
|
+
entries.push([
|
|
1400
|
+
key,
|
|
1401
|
+
key === "type" ? "json_schema" : validatedJsonObject(record[key]),
|
|
1402
|
+
]);
|
|
1403
|
+
}
|
|
1404
|
+
return Object.fromEntries(entries);
|
|
1405
|
+
}
|
|
1406
|
+
function toolChoice(value) {
|
|
1407
|
+
const record = requireRecord(value);
|
|
1408
|
+
const type = record["type"];
|
|
1409
|
+
const allowed = type === "none"
|
|
1410
|
+
? TOOL_CHOICE_NONE_KEYS
|
|
1411
|
+
: type === "auto" || type === "any"
|
|
1412
|
+
? TOOL_CHOICE_PARALLEL_KEYS
|
|
1413
|
+
: type === "tool"
|
|
1414
|
+
? TOOL_CHOICE_NAMED_KEYS
|
|
1415
|
+
: fail("INVALID_INPUT");
|
|
1416
|
+
assertExactKeys(record, allowed);
|
|
1417
|
+
requireKeys(record, type === "tool" ? ["name", "type"] : ["type"]);
|
|
1418
|
+
const entries = [];
|
|
1419
|
+
for (const key of Object.keys(record)) {
|
|
1420
|
+
if (key === "type")
|
|
1421
|
+
entries.push([key, type]);
|
|
1422
|
+
else if (key === "name")
|
|
1423
|
+
entries.push([key, requireString(record[key])]);
|
|
1424
|
+
else
|
|
1425
|
+
entries.push([key, requireBoolean(record[key])]);
|
|
1426
|
+
}
|
|
1427
|
+
return Object.fromEntries(entries);
|
|
1428
|
+
}
|
|
1429
|
+
function betaEnabled(profile) {
|
|
1430
|
+
return profile?.betaPolicy.experimentalBetasEnabled === true;
|
|
1431
|
+
}
|
|
1432
|
+
function outputConfig(value, profile, adapterEffort, adapterEffortActive) {
|
|
1433
|
+
const record = requireRecord(value);
|
|
1434
|
+
assertExactKeys(record, OUTPUT_CONFIG_KEYS);
|
|
1435
|
+
requireKeys(record, []);
|
|
1436
|
+
if (hasOwn(record, "effort") &&
|
|
1437
|
+
adapterEffort !== undefined &&
|
|
1438
|
+
record["effort"] !== adapterEffort) {
|
|
1439
|
+
fail("INVALID_INPUT");
|
|
1440
|
+
}
|
|
1441
|
+
const entries = [];
|
|
1442
|
+
for (const key of Object.keys(record)) {
|
|
1443
|
+
const item = record[key];
|
|
1444
|
+
if (key === "effort") {
|
|
1445
|
+
if (item !== null &&
|
|
1446
|
+
item !== "low" &&
|
|
1447
|
+
item !== "medium" &&
|
|
1448
|
+
item !== "high" &&
|
|
1449
|
+
item !== "xhigh" &&
|
|
1450
|
+
item !== "max") {
|
|
1451
|
+
fail("INVALID_INPUT");
|
|
1452
|
+
}
|
|
1453
|
+
entries.push([key, item]);
|
|
1454
|
+
}
|
|
1455
|
+
else {
|
|
1456
|
+
if (!betaEnabled(profile))
|
|
1457
|
+
fail("UNSUPPORTED_CAPABILITY");
|
|
1458
|
+
entries.push([
|
|
1459
|
+
"max_output_tokens",
|
|
1460
|
+
item === null ? null : requirePositiveInteger(item),
|
|
1461
|
+
]);
|
|
1462
|
+
}
|
|
1463
|
+
}
|
|
1464
|
+
if (adapterEffortActive && !hasOwn(record, "effort")) {
|
|
1465
|
+
entries.push(["effort", adapterEffort]);
|
|
1466
|
+
}
|
|
1467
|
+
return Object.fromEntries(entries);
|
|
1468
|
+
}
|
|
1469
|
+
function deepFreeze(value) {
|
|
1470
|
+
if (value !== null && typeof value === "object" && !Object.isFrozen(value)) {
|
|
1471
|
+
for (const key of Reflect.ownKeys(value))
|
|
1472
|
+
deepFreeze(Reflect.get(value, key));
|
|
1473
|
+
Object.freeze(value);
|
|
1474
|
+
}
|
|
1475
|
+
return value;
|
|
1476
|
+
}
|
|
1477
|
+
function contextHintEnabled(profile) {
|
|
1478
|
+
return isRecord(profile) && profile["contextHintEnabled"] === true;
|
|
1479
|
+
}
|
|
1480
|
+
/**
|
|
1481
|
+
* Canonicalises the message and tool lists for the count-tokens endpoint.
|
|
1482
|
+
*
|
|
1483
|
+
* The count-tokens body shares no other field with the messages body, but it
|
|
1484
|
+
* MUST share these two canonicalisers. Reimplementing them would give the two
|
|
1485
|
+
* public entry points different fail-closed guarantees for the same caller
|
|
1486
|
+
* input, which is precisely the class of divergence this package exists to
|
|
1487
|
+
* prevent.
|
|
1488
|
+
*/
|
|
1489
|
+
export function canonicalCountTokensLists(rawMessages, rawTools) {
|
|
1490
|
+
return {
|
|
1491
|
+
messages: messages(rawMessages),
|
|
1492
|
+
tools: rawTools === undefined ? Object.freeze([]) : tools(rawTools),
|
|
1493
|
+
};
|
|
1494
|
+
}
|
|
1495
|
+
export function buildCanonicalBody(rawInput, rawResolvedModel, rawSystemBlocks, rawMetadata, profile) {
|
|
1496
|
+
inspectJsonInputs([
|
|
1497
|
+
rawInput,
|
|
1498
|
+
rawResolvedModel,
|
|
1499
|
+
rawSystemBlocks,
|
|
1500
|
+
rawMetadata,
|
|
1501
|
+
...(profile === undefined ? [] : [profile]),
|
|
1502
|
+
]);
|
|
1503
|
+
const input = requireRecord(rawInput);
|
|
1504
|
+
assertExactKeys(input, INPUT_KEY_SET);
|
|
1505
|
+
requireKeys(input, ["maxTokens", "messages"]);
|
|
1506
|
+
const resolvedModel = modelResolution(rawResolvedModel);
|
|
1507
|
+
if (hasOwn(input, "model") &&
|
|
1508
|
+
(typeof input["model"] !== "string" ||
|
|
1509
|
+
stripModelMarkers(input["model"]) !== resolvedModel.wireId)) {
|
|
1510
|
+
fail("INVALID_INPUT");
|
|
1511
|
+
}
|
|
1512
|
+
const cacheOverride = hasOwn(input, "cacheControl")
|
|
1513
|
+
? nullable(input["cacheControl"], cacheControlInput)
|
|
1514
|
+
: undefined;
|
|
1515
|
+
let systemBlocks = system(rawSystemBlocks);
|
|
1516
|
+
let messageList = messages(input["messages"]);
|
|
1517
|
+
let toolList = hasOwn(input, "tools") ? tools(input["tools"]) : undefined;
|
|
1518
|
+
if (cacheOverride !== undefined && cacheOverride !== null) {
|
|
1519
|
+
systemBlocks = applySystemCacheControl(systemBlocks, cacheOverride);
|
|
1520
|
+
messageList = applyMessageCacheControl(messageList, cacheOverride);
|
|
1521
|
+
if (toolList !== undefined) {
|
|
1522
|
+
toolList = applyToolCacheControl(toolList, cacheOverride);
|
|
1523
|
+
}
|
|
1524
|
+
}
|
|
1525
|
+
const maxTokens = requirePositiveInteger(input["maxTokens"]);
|
|
1526
|
+
const result = {
|
|
1527
|
+
model: resolvedModel.wireId,
|
|
1528
|
+
max_tokens: maxTokens,
|
|
1529
|
+
system: systemBlocks,
|
|
1530
|
+
messages: messageList,
|
|
1531
|
+
};
|
|
1532
|
+
if (toolList !== undefined)
|
|
1533
|
+
result["tools"] = toolList;
|
|
1534
|
+
let thinkingRequest;
|
|
1535
|
+
if (hasOwn(input, "thinking")) {
|
|
1536
|
+
const rawThinking = input["thinking"];
|
|
1537
|
+
if (!isRecord(rawThinking) || Array.isArray(rawThinking)) {
|
|
1538
|
+
fail("INVALID_THINKING");
|
|
1539
|
+
}
|
|
1540
|
+
for (const key of Reflect.ownKeys(rawThinking)) {
|
|
1541
|
+
if (key !== "type" && key !== "budgetTokens" && key !== "display") {
|
|
1542
|
+
fail("INVALID_THINKING");
|
|
1543
|
+
}
|
|
1544
|
+
}
|
|
1545
|
+
const type = rawThinking["type"];
|
|
1546
|
+
if (type !== "enabled" && type !== "adaptive" && type !== "disabled") {
|
|
1547
|
+
fail("INVALID_THINKING");
|
|
1548
|
+
}
|
|
1549
|
+
let budgetTokens;
|
|
1550
|
+
if (hasOwn(rawThinking, "budgetTokens")) {
|
|
1551
|
+
const raw = rawThinking["budgetTokens"];
|
|
1552
|
+
if (typeof raw !== "number" || !Number.isSafeInteger(raw) || raw <= 0) {
|
|
1553
|
+
fail("INVALID_THINKING");
|
|
1554
|
+
}
|
|
1555
|
+
budgetTokens = raw;
|
|
1556
|
+
}
|
|
1557
|
+
let display;
|
|
1558
|
+
if (hasOwn(rawThinking, "display")) {
|
|
1559
|
+
const raw = rawThinking["display"];
|
|
1560
|
+
if (raw !== "summarized" && raw !== "omitted")
|
|
1561
|
+
fail("INVALID_THINKING");
|
|
1562
|
+
// Upstream's schema attaches `display` to the enabled and adaptive
|
|
1563
|
+
// variants only; the disabled variant declares no such property.
|
|
1564
|
+
if (type === "disabled")
|
|
1565
|
+
fail("INVALID_THINKING");
|
|
1566
|
+
display = raw;
|
|
1567
|
+
}
|
|
1568
|
+
thinkingRequest = {
|
|
1569
|
+
type,
|
|
1570
|
+
...(budgetTokens === undefined ? {} : { budgetTokens }),
|
|
1571
|
+
...(display === undefined ? {} : { display }),
|
|
1572
|
+
};
|
|
1573
|
+
}
|
|
1574
|
+
const resolved = resolveThinking(thinkingRequest, resolvedModel.id, resolvedModel.capabilities, (profile ?? CLAUDE_CODE_2_1_195_PROFILE).betaPolicy, maxTokens);
|
|
1575
|
+
if (resolved.emitted !== undefined)
|
|
1576
|
+
result["thinking"] = resolved.emitted;
|
|
1577
|
+
if (!resolved.requestActive && resolvedModel.capabilities.temperature) {
|
|
1578
|
+
result["temperature"] = hasOwn(input, "temperature")
|
|
1579
|
+
? requireNumber(input["temperature"])
|
|
1580
|
+
: 1;
|
|
1581
|
+
}
|
|
1582
|
+
let adapterEffort;
|
|
1583
|
+
let adapterEffortActive = false;
|
|
1584
|
+
if (hasOwn(input, "effort")) {
|
|
1585
|
+
const effort = input["effort"];
|
|
1586
|
+
if (!resolvedModel.capabilities.effort ||
|
|
1587
|
+
(effort !== "low" &&
|
|
1588
|
+
effort !== "medium" &&
|
|
1589
|
+
effort !== "high" &&
|
|
1590
|
+
effort !== "xhigh" &&
|
|
1591
|
+
effort !== "max")) {
|
|
1592
|
+
fail("INVALID_EFFORT");
|
|
1593
|
+
}
|
|
1594
|
+
if ((effort === "max" && !resolvedModel.capabilities.maxEffort) ||
|
|
1595
|
+
(effort === "xhigh" && !resolvedModel.capabilities.xhighEffort)) {
|
|
1596
|
+
fail("INVALID_EFFORT");
|
|
1597
|
+
}
|
|
1598
|
+
adapterEffort = effort;
|
|
1599
|
+
if (isRecord(result["thinking"]) &&
|
|
1600
|
+
result["thinking"]["type"] === "adaptive") {
|
|
1601
|
+
adapterEffortActive = true;
|
|
1602
|
+
if (!hasOwn(input, "outputConfig")) {
|
|
1603
|
+
result["output_config"] = { effort };
|
|
1604
|
+
}
|
|
1605
|
+
}
|
|
1606
|
+
}
|
|
1607
|
+
for (const key of Object.keys(input)) {
|
|
1608
|
+
const item = input[key];
|
|
1609
|
+
if (key === "contextManagement")
|
|
1610
|
+
result["context_management"] = nullable(item, contextManagement);
|
|
1611
|
+
else if (key === "outputConfig")
|
|
1612
|
+
result["output_config"] = outputConfig(item, profile, adapterEffort, adapterEffortActive);
|
|
1613
|
+
else if (key === "speed") {
|
|
1614
|
+
if (item !== null && item !== "standard" && item !== "fast")
|
|
1615
|
+
fail("INVALID_INPUT");
|
|
1616
|
+
if (item === "fast" && !betaEnabled(profile))
|
|
1617
|
+
fail("UNSUPPORTED_CAPABILITY");
|
|
1618
|
+
result["speed"] = item;
|
|
1619
|
+
}
|
|
1620
|
+
else if (key === "serviceTier") {
|
|
1621
|
+
if (item !== "auto" && item !== "standard_only")
|
|
1622
|
+
fail("INVALID_INPUT");
|
|
1623
|
+
result["service_tier"] = item;
|
|
1624
|
+
}
|
|
1625
|
+
else if (key === "outputFormat")
|
|
1626
|
+
result["output_format"] = nullable(item, outputFormat);
|
|
1627
|
+
else if (key === "toolChoice") {
|
|
1628
|
+
const validatedToolChoice = toolChoice(item);
|
|
1629
|
+
result["tool_choice"] =
|
|
1630
|
+
validatedToolChoice["type"] === "tool" &&
|
|
1631
|
+
resolved.extendedThinkingActive
|
|
1632
|
+
? { type: "auto" }
|
|
1633
|
+
: validatedToolChoice;
|
|
1634
|
+
}
|
|
1635
|
+
else if (key === "topP")
|
|
1636
|
+
result["top_p"] = requireNumber(item);
|
|
1637
|
+
else if (key === "topK")
|
|
1638
|
+
result["top_k"] = requireNumber(item);
|
|
1639
|
+
else if (key === "stopSequences")
|
|
1640
|
+
result["stop_sequences"] = stringArray(item);
|
|
1641
|
+
else if (key === "stream")
|
|
1642
|
+
result["stream"] = requireBoolean(item);
|
|
1643
|
+
}
|
|
1644
|
+
if (contextHintEnabled(profile)) {
|
|
1645
|
+
result["context_hint"] = { enabled: true };
|
|
1646
|
+
}
|
|
1647
|
+
result["metadata"] = metadata(rawMetadata);
|
|
1648
|
+
if (hasOwn(input, "experimentalBodyFields")) {
|
|
1649
|
+
const experimentalBodyFields = validatedJsonObject(input["experimentalBodyFields"]);
|
|
1650
|
+
for (const key of Object.keys(experimentalBodyFields)) {
|
|
1651
|
+
if (hasOwn(result, key))
|
|
1652
|
+
fail("INVALID_INPUT");
|
|
1653
|
+
result[key] = experimentalBodyFields[key];
|
|
1654
|
+
}
|
|
1655
|
+
}
|
|
1656
|
+
return deepFreeze(result);
|
|
1657
|
+
}
|
|
1658
|
+
//# sourceMappingURL=request-body.js.map
|