@tormentalabs/claude-code-wire-compat 0.5.0 → 0.6.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +167 -0
- package/README.md +19 -7
- package/dist/betas.d.ts +65 -7
- package/dist/betas.d.ts.map +1 -1
- package/dist/betas.js +143 -2
- package/dist/betas.js.map +1 -1
- package/dist/build-request.d.ts +12 -6
- package/dist/build-request.d.ts.map +1 -1
- package/dist/build-request.js +44 -15
- package/dist/build-request.js.map +1 -1
- package/dist/contracts.d.ts +7 -2
- package/dist/contracts.d.ts.map +1 -1
- package/dist/contracts.js.map +1 -1
- package/dist/fingerprint.d.ts.map +1 -1
- package/dist/fingerprint.js +5 -0
- package/dist/fingerprint.js.map +1 -1
- package/dist/headers.d.ts.map +1 -1
- package/dist/headers.js +5 -2
- package/dist/headers.js.map +1 -1
- package/dist/index.d.ts +2 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +2 -0
- package/dist/index.js.map +1 -1
- package/dist/model-capabilities.d.ts +3 -3
- package/dist/model-capabilities.d.ts.map +1 -1
- package/dist/model-capabilities.js +55 -19
- package/dist/model-capabilities.js.map +1 -1
- package/dist/model-identity.d.ts +9 -1
- package/dist/model-identity.d.ts.map +1 -1
- package/dist/model-identity.js +19 -1
- package/dist/model-identity.js.map +1 -1
- package/dist/model-queries.d.ts +17 -5
- package/dist/model-queries.d.ts.map +1 -1
- package/dist/model-queries.js +33 -6
- package/dist/model-queries.js.map +1 -1
- package/dist/models.js +1 -1
- package/dist/models.js.map +1 -1
- package/dist/profiles/beta-registry-2.1.280.d.ts +211 -0
- package/dist/profiles/beta-registry-2.1.280.d.ts.map +1 -0
- package/dist/profiles/beta-registry-2.1.280.js +292 -0
- package/dist/profiles/beta-registry-2.1.280.js.map +1 -0
- package/dist/profiles/claude-code-2.1.280.d.ts +3 -0
- package/dist/profiles/claude-code-2.1.280.d.ts.map +1 -0
- package/dist/profiles/claude-code-2.1.280.js +359 -0
- package/dist/profiles/claude-code-2.1.280.js.map +1 -0
- package/dist/redaction.d.ts.map +1 -1
- package/dist/redaction.js +3 -0
- package/dist/redaction.js.map +1 -1
- package/dist/request-body.d.ts +1 -1
- package/dist/request-body.d.ts.map +1 -1
- package/dist/request-body.js +16 -5
- package/dist/request-body.js.map +1 -1
- package/dist/thinking.d.ts +53 -2
- package/dist/thinking.d.ts.map +1 -1
- package/dist/thinking.js +124 -26
- package/dist/thinking.js.map +1 -1
- package/package.json +6 -2
- package/src/betas.ts +208 -9
- package/src/build-request.ts +54 -21
- package/src/contracts.ts +7 -2
- package/src/fingerprint.ts +5 -0
- package/src/headers.ts +4 -2
- package/src/index.ts +2 -0
- package/src/model-capabilities.ts +55 -19
- package/src/model-identity.ts +14 -1
- package/src/model-queries.ts +38 -6
- package/src/models.ts +1 -1
- package/src/profiles/beta-registry-2.1.280.ts +309 -0
- package/src/profiles/claude-code-2.1.280.ts +364 -0
- package/src/redaction.ts +3 -0
- package/src/request-body.ts +25 -3
- package/src/thinking.ts +148 -26
|
@@ -9,20 +9,20 @@ import { profileBehaviors } from "./profile-behaviors.js";
|
|
|
9
9
|
import { CLAUDE_CODE_2_1_195_PROFILE } from "./profiles/claude-code-2.1.195.js";
|
|
10
10
|
|
|
11
11
|
/*
|
|
12
|
-
* Capability derivation, ported from the genuine client's
|
|
13
|
-
* predicates.
|
|
12
|
+
* Capability derivation, ported from the genuine client's capability
|
|
13
|
+
* predicates and, since 2.1.280, from catalogue strings that have no predicate
|
|
14
|
+
* upstream at all.
|
|
14
15
|
*
|
|
15
16
|
* READ THIS FIRST -- there are two derivation paths and they are not
|
|
16
17
|
* interchangeable:
|
|
17
18
|
*
|
|
18
19
|
* 1. Catalogue path (`deriveCapabilitiesFromCatalogue`), taken for every id
|
|
19
|
-
* present in the
|
|
20
|
-
* verbatim upstream string in
|
|
21
|
-
*
|
|
22
|
-
*
|
|
23
|
-
*
|
|
24
|
-
*
|
|
25
|
-
* predicate-derived.
|
|
20
|
+
* present in the catalogue. The fields listed in
|
|
21
|
+
* `CATALOGUE_BACKED_CAPABILITIES` have a verbatim upstream string in
|
|
22
|
+
* `ClaudeCodeCatalogueEntry.capabilities` and are read from there; that
|
|
23
|
+
* map is the enumeration, so this comment does not repeat it. The rest
|
|
24
|
+
* (`thinking`, `interleavedThinking`, `temperature`) have NO catalogue
|
|
25
|
+
* string in any client version and stay predicate-derived.
|
|
26
26
|
* 2. Predicate fallback (`deriveCapabilitiesFromPredicates`), taken for ids
|
|
27
27
|
* with no catalogue entry -- `claude-mythos-5` (absent by product
|
|
28
28
|
* decision D-1), ids from a newer client, and anything that escaped
|
|
@@ -39,7 +39,7 @@ import { CLAUDE_CODE_2_1_195_PROFILE } from "./profiles/claude-code-2.1.195.js";
|
|
|
39
39
|
* surprising:
|
|
40
40
|
*
|
|
41
41
|
* On the first-party provider -- the only provider this package targets --
|
|
42
|
-
* every one of these
|
|
42
|
+
* every one of these predicates reduces to a pure function of the
|
|
43
43
|
* normalized model id.
|
|
44
44
|
*
|
|
45
45
|
* Why. Upstream, each predicate has the shape
|
|
@@ -87,7 +87,7 @@ import { CLAUDE_CODE_2_1_195_PROFILE } from "./profiles/claude-code-2.1.195.js";
|
|
|
87
87
|
* `claude-mythos-5` has no catalogue entry by product decision D-1. Upstream
|
|
88
88
|
* special-cases it by name in `Kw`, `Hke`, `Yte` and `Uot`; this port subsumes
|
|
89
89
|
* those clauses into the first-party fallback, which yields an identical
|
|
90
|
-
* result. The explicit D-1 test asserting its full
|
|
90
|
+
* result. The explicit D-1 test asserting its full capability row is the
|
|
91
91
|
* guard for that equivalence.
|
|
92
92
|
*
|
|
93
93
|
* Model ids reaching these functions have already been normalized by
|
|
@@ -337,11 +337,19 @@ export function rejectsDisabledThinking(normalizedId: string): boolean {
|
|
|
337
337
|
}
|
|
338
338
|
|
|
339
339
|
/**
|
|
340
|
-
* The
|
|
341
|
-
*
|
|
342
|
-
* `thinking`, `interleavedThinking
|
|
343
|
-
* string in any client version and
|
|
344
|
-
* paths.
|
|
340
|
+
* The `ClaudeCodeCapabilities` fields the catalogue represents, paired with
|
|
341
|
+
* their verbatim upstream capability string. Whatever is not a key here --
|
|
342
|
+
* `thinking`, `interleavedThinking` and `temperature` today -- has no
|
|
343
|
+
* catalogue string in any client version and is derived from its predicate on
|
|
344
|
+
* both paths. The literal below is the enumeration; no count is restated in
|
|
345
|
+
* prose, because a count beside the thing it counts goes stale on the next
|
|
346
|
+
* port.
|
|
347
|
+
*
|
|
348
|
+
* `per_turn_timing` is deliberately NOT mapped. It is a real 2.1.280
|
|
349
|
+
* catalogue string carried by three models, but the beta it would gate,
|
|
350
|
+
* `timing-2026-09-09`, is environment-gated off on the default path, so a
|
|
351
|
+
* field here would be a capability nothing reads. Mapping it would invent a
|
|
352
|
+
* derived value with no emission behind it.
|
|
345
353
|
*/
|
|
346
354
|
const CATALOGUE_BACKED_CAPABILITIES = {
|
|
347
355
|
effort: "effort",
|
|
@@ -350,12 +358,14 @@ const CATALOGUE_BACKED_CAPABILITIES = {
|
|
|
350
358
|
adaptiveThinking: "adaptive_thinking",
|
|
351
359
|
contextManagement: "context_management",
|
|
352
360
|
rejectsDisabledThinking: "rejects_disabled_thinking",
|
|
361
|
+
midConvToolChange: "mid_conv_tool_change",
|
|
362
|
+
perTurnEffort: "per_turn_effort",
|
|
353
363
|
} as const;
|
|
354
364
|
|
|
355
365
|
/**
|
|
356
|
-
* Pure catalogue -> capabilities mapping. Reads nothing but `entry` for
|
|
357
|
-
*
|
|
358
|
-
*
|
|
366
|
+
* Pure catalogue -> capabilities mapping. Reads nothing but `entry` for every
|
|
367
|
+
* catalogue-backed field; `normalizedId` is used only for the fields the
|
|
368
|
+
* catalogue does not represent.
|
|
359
369
|
*
|
|
360
370
|
* This function applies no exceptions and no id special cases. The one cell
|
|
361
371
|
* where the 2.1.195 catalogue disagrees with the wire is corrected by the
|
|
@@ -381,6 +391,8 @@ export function deriveCapabilitiesFromCatalogue(
|
|
|
381
391
|
rejectsDisabledThinking: has(
|
|
382
392
|
CATALOGUE_BACKED_CAPABILITIES.rejectsDisabledThinking,
|
|
383
393
|
),
|
|
394
|
+
midConvToolChange: has(CATALOGUE_BACKED_CAPABILITIES.midConvToolChange),
|
|
395
|
+
perTurnEffort: has(CATALOGUE_BACKED_CAPABILITIES.perTurnEffort),
|
|
384
396
|
});
|
|
385
397
|
}
|
|
386
398
|
|
|
@@ -408,6 +420,30 @@ function deriveCapabilitiesFromPredicates(
|
|
|
408
420
|
contextManagement: supportsContextManagement(normalizedId),
|
|
409
421
|
temperature: supportsTemperature(normalizedId),
|
|
410
422
|
rejectsDisabledThinking: rejectsDisabledThinking(normalizedId),
|
|
423
|
+
/*
|
|
424
|
+
* Both are FALSE here, and this is the one place where the two derivation
|
|
425
|
+
* paths stop agreeing in kind: the six older catalogue-backed fields above
|
|
426
|
+
* resolve maximally permissive for an uncatalogued id, these two resolve
|
|
427
|
+
* restrictive. That asymmetry is deliberate, and the reason differs per
|
|
428
|
+
* field.
|
|
429
|
+
*
|
|
430
|
+
* `perTurnEffort: false` MATCHES upstream. Its lookup consults the static
|
|
431
|
+
* catalogue and, at default settings, the remote client-data path that
|
|
432
|
+
* could override it is empty, so an id with no entry yields false there
|
|
433
|
+
* too.
|
|
434
|
+
*
|
|
435
|
+
* `midConvToolChange: false` DIVERGES from upstream, which still sends
|
|
436
|
+
* `mid-conversation-tool-changes-2026-07-01` for a model it has no
|
|
437
|
+
* catalogue entry for. The analysis document records that as a divergence
|
|
438
|
+
* recorded but not ported, for the same reason the package declines the
|
|
439
|
+
* neighbouring permissive tail: a capability granted to an unknown id is a
|
|
440
|
+
* guess about a model this package knows nothing about.
|
|
441
|
+
*
|
|
442
|
+
* Neither field has an upstream predicate to fall back on -- both exist
|
|
443
|
+
* only as catalogue strings -- so there is no third option here.
|
|
444
|
+
*/
|
|
445
|
+
midConvToolChange: false,
|
|
446
|
+
perTurnEffort: false,
|
|
411
447
|
});
|
|
412
448
|
}
|
|
413
449
|
|
package/src/model-identity.ts
CHANGED
|
@@ -21,17 +21,30 @@ function dottedToDashedVersion(model: string): string {
|
|
|
21
21
|
return model.replace(/(\d)\.(\d)/g, "$1-$2");
|
|
22
22
|
}
|
|
23
23
|
|
|
24
|
-
/**
|
|
24
|
+
/**
|
|
25
|
+
* Ports upstream `$_` (binary offset 226639025); in the 2.1.280 bundle the
|
|
26
|
+
* function is `GF` at byte offset 7413751. The two offsets are in different
|
|
27
|
+
* address spaces: the first indexes the 2.1.195 platform binary, the second
|
|
28
|
+
* the carved 2.1.280 JavaScript bundle, so neither can be found in the other.
|
|
29
|
+
*
|
|
30
|
+
* Rung order is load-bearing: each test is a substring test, so a longer id
|
|
31
|
+
* must precede the shorter id it contains or the shorter rung swallows it.
|
|
32
|
+
*/
|
|
25
33
|
export function normalizeModelId(model: string): string {
|
|
26
34
|
model = dottedToDashedVersion(model.toLowerCase());
|
|
35
|
+
if (model.includes("claude-fable-5-1")) return "claude-fable-5-1";
|
|
27
36
|
if (model.includes("claude-fable-5")) return "claude-fable-5";
|
|
37
|
+
if (model.includes("claude-mythos-5-1")) return "claude-mythos-5-1";
|
|
28
38
|
if (model.includes("claude-mythos-5")) return "claude-mythos-5";
|
|
39
|
+
if (model.includes("claude-opus-5-5")) return "claude-opus-5-5";
|
|
40
|
+
if (model.includes("claude-opus-5")) return "claude-opus-5";
|
|
29
41
|
if (model.includes("claude-opus-4-8")) return "claude-opus-4-8";
|
|
30
42
|
if (model.includes("claude-opus-4-7")) return "claude-opus-4-7";
|
|
31
43
|
if (model.includes("claude-opus-4-6")) return "claude-opus-4-6";
|
|
32
44
|
if (model.includes("claude-opus-4-5")) return "claude-opus-4-5";
|
|
33
45
|
if (model.includes("claude-opus-4-1")) return "claude-opus-4-1";
|
|
34
46
|
if (/claude-opus-4(?!-\d(?!\d))/.test(model)) return "claude-opus-4-0";
|
|
47
|
+
if (model.includes("claude-sonnet-5")) return "claude-sonnet-5";
|
|
35
48
|
if (model.includes("claude-sonnet-4-6")) return "claude-sonnet-4-6";
|
|
36
49
|
if (model.includes("claude-sonnet-4-5")) return "claude-sonnet-4-5";
|
|
37
50
|
if (/claude-sonnet-4(?!-\d(?!\d))/.test(model)) return "claude-sonnet-4-0";
|
package/src/model-queries.ts
CHANGED
|
@@ -120,21 +120,46 @@ export function isOpus48Model(model: string): boolean {
|
|
|
120
120
|
return normalizedOrNull(model) === "claude-opus-4-8";
|
|
121
121
|
}
|
|
122
122
|
|
|
123
|
+
/** Whether `model` normalizes to `claude-opus-5`. */
|
|
124
|
+
export function isOpus5Model(model: string): boolean {
|
|
125
|
+
return normalizedOrNull(model) === "claude-opus-5";
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
/** Whether `model` normalizes to `claude-opus-5-5`. */
|
|
129
|
+
export function isOpus55Model(model: string): boolean {
|
|
130
|
+
return normalizedOrNull(model) === "claude-opus-5-5";
|
|
131
|
+
}
|
|
132
|
+
|
|
123
133
|
/** Whether `model` normalizes to `claude-sonnet-4-6`. */
|
|
124
134
|
export function isSonnet46Model(model: string): boolean {
|
|
125
135
|
return normalizedOrNull(model) === "claude-sonnet-4-6";
|
|
126
136
|
}
|
|
127
137
|
|
|
138
|
+
/** Whether `model` normalizes to `claude-sonnet-5`. */
|
|
139
|
+
export function isSonnet5Model(model: string): boolean {
|
|
140
|
+
return normalizedOrNull(model) === "claude-sonnet-5";
|
|
141
|
+
}
|
|
142
|
+
|
|
128
143
|
/** Whether `model` normalizes to `claude-fable-5`. */
|
|
129
144
|
export function isFable5Model(model: string): boolean {
|
|
130
145
|
return normalizedOrNull(model) === "claude-fable-5";
|
|
131
146
|
}
|
|
132
147
|
|
|
148
|
+
/** Whether `model` normalizes to `claude-fable-5-1`. */
|
|
149
|
+
export function isFable51Model(model: string): boolean {
|
|
150
|
+
return normalizedOrNull(model) === "claude-fable-5-1";
|
|
151
|
+
}
|
|
152
|
+
|
|
133
153
|
/** Whether `model` normalizes to `claude-mythos-5`. */
|
|
134
154
|
export function isMythos5Model(model: string): boolean {
|
|
135
155
|
return normalizedOrNull(model) === "claude-mythos-5";
|
|
136
156
|
}
|
|
137
157
|
|
|
158
|
+
/** Whether `model` normalizes to `claude-mythos-5-1`. */
|
|
159
|
+
export function isMythos51Model(model: string): boolean {
|
|
160
|
+
return normalizedOrNull(model) === "claude-mythos-5-1";
|
|
161
|
+
}
|
|
162
|
+
|
|
138
163
|
/**
|
|
139
164
|
* Whether `model` belongs to the haiku family.
|
|
140
165
|
*
|
|
@@ -223,19 +248,26 @@ export function supportsWebSearch(model: string): boolean {
|
|
|
223
248
|
* Whether `model` uses adaptive thinking (`{type: "adaptive"}`) instead of a
|
|
224
249
|
* manual `budget_tokens`.
|
|
225
250
|
*
|
|
226
|
-
* The union of the named
|
|
227
|
-
* the shape of the emitted `thinking` block, and an uncatalogued id must
|
|
228
|
-
* inherit adaptive thinking from the permissive capability fallback.
|
|
229
|
-
*
|
|
230
|
-
*
|
|
251
|
+
* The union of the named per-model predicates, not a catalogue read: this
|
|
252
|
+
* gates the shape of the emitted `thinking` block, and an uncatalogued id must
|
|
253
|
+
* not inherit adaptive thinking from the permissive capability fallback. The
|
|
254
|
+
* union covers every id any pinned profile's catalogue marks
|
|
255
|
+
* `adaptive_thinking` (the 2.1.280 catalogue is the widest). Ask
|
|
256
|
+
* `modelCapability(model, "adaptive_thinking", profile)` for a specific
|
|
257
|
+
* profile's answer.
|
|
231
258
|
*/
|
|
232
259
|
export function isAdaptiveThinkingModel(model: string): boolean {
|
|
233
260
|
return (
|
|
234
261
|
isOpus46Model(model) ||
|
|
235
262
|
isOpus47Model(model) ||
|
|
236
263
|
isOpus48Model(model) ||
|
|
264
|
+
isOpus5Model(model) ||
|
|
265
|
+
isOpus55Model(model) ||
|
|
237
266
|
isSonnet46Model(model) ||
|
|
267
|
+
isSonnet5Model(model) ||
|
|
238
268
|
isFable5Model(model) ||
|
|
239
|
-
|
|
269
|
+
isFable51Model(model) ||
|
|
270
|
+
isMythos5Model(model) ||
|
|
271
|
+
isMythos51Model(model)
|
|
240
272
|
);
|
|
241
273
|
}
|
package/src/models.ts
CHANGED
|
@@ -38,7 +38,7 @@ export function resolveModel(
|
|
|
38
38
|
id,
|
|
39
39
|
wireId,
|
|
40
40
|
// The catalogue supplies the family here, and -- since T1.1.2 -- also
|
|
41
|
-
// supplies the
|
|
41
|
+
// supplies the catalogue-backed capabilities. Both now honour THIS
|
|
42
42
|
// profile: `deriveCapabilities` takes the active profile, so a request
|
|
43
43
|
// built against a non-pinned profile derives from that profile's
|
|
44
44
|
// catalogue rather than from 2.1.195's. Ids with no catalogue entry fall
|
|
@@ -0,0 +1,309 @@
|
|
|
1
|
+
// SPDX-License-Identifier: GPL-3.0-or-later
|
|
2
|
+
|
|
3
|
+
interface BetaRegistryEntry {
|
|
4
|
+
readonly featureKey: string;
|
|
5
|
+
readonly header: string;
|
|
6
|
+
}
|
|
7
|
+
|
|
8
|
+
/*
|
|
9
|
+
* `deepFreeze` is duplicated from `src/beta-registry.ts` rather than imported,
|
|
10
|
+
* for the same reason the 2.1.233 registry duplicates it: a shared helper
|
|
11
|
+
* module would make every registry import-coupled for four lines of code, and
|
|
12
|
+
* keeping each registry a leaf keeps a version bump from rippling.
|
|
13
|
+
*/
|
|
14
|
+
function deepFreeze<T>(value: T): T {
|
|
15
|
+
if (value !== null && typeof value === "object") {
|
|
16
|
+
for (const key of Reflect.ownKeys(value)) {
|
|
17
|
+
deepFreeze(Reflect.get(value, key));
|
|
18
|
+
}
|
|
19
|
+
Object.freeze(value);
|
|
20
|
+
}
|
|
21
|
+
return value;
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
/**
|
|
25
|
+
* Genuine-client beta registry as of 2.1.280, upstream factory chain at byte
|
|
26
|
+
* offset 6277485 and ordered array `oy` immediately after it.
|
|
27
|
+
*
|
|
28
|
+
* KEY ORDER IS LOAD-BEARING, and for 2.1.280 it is load-bearing in a way it was
|
|
29
|
+
* not before: upstream's array is NOT append-only. `thinking_resumption` is
|
|
30
|
+
* inserted at position 17, and `per_turn_timing`, `mid_conv_tool_change` and
|
|
31
|
+
* `inline_tools` are inserted at 29-31, ahead of four entries that already
|
|
32
|
+
* existed. A diff that assumes new identifiers only ever land at the end will
|
|
33
|
+
* mis-align fifteen entries: 2.1.233 positions 17-27 shift by one and 28-31
|
|
34
|
+
* shift by four. See
|
|
35
|
+
* `docs/protocol/versions/claude-code-2.1.280-analysis.md` section 4.2.
|
|
36
|
+
*
|
|
37
|
+
* The upstream array carries 42 slots with two explicit `null`s (indices 34 and
|
|
38
|
+
* 37, `kAt` at byte 6279405 and `hZt` at byte 6279537) which `.filter(e => e
|
|
39
|
+
* !== null)` removes, leaving the forty entries below. Both slots are null IN
|
|
40
|
+
* THIS BUILD, which is all the bytes establish: upstream treats registry
|
|
41
|
+
* members as nullable per build -- `Dg` carries `...BR ? [BR] : []` and `hRr`
|
|
42
|
+
* guards on `kAt === null` -- so a compile-time feature gate fits the evidence
|
|
43
|
+
* as well as a removal does, and this file claims neither. `kAt` still has two
|
|
44
|
+
* consumers at byte 14167580: `hRr`, short-circuited by that null check, and
|
|
45
|
+
* `yRr`, which reads `kAt.name` with no null guard and so is either unreachable
|
|
46
|
+
* or a throw path. Neither says WHICH beta the slot held; see the note above
|
|
47
|
+
* `AUTO_MODE_CLASSIFIER`. Neither null slot is transcribed here; a null is not
|
|
48
|
+
* an entry.
|
|
49
|
+
*
|
|
50
|
+
* Two further registry members are deliberately absent:
|
|
51
|
+
* `mid_conv_cache_promotion_latch` and `mid_conv_cache_promotion_ok_latch`
|
|
52
|
+
* (`x-cc-internal-mid-conv-cache-promotion` and its `-ok` sibling). Upstream
|
|
53
|
+
* declares them through the same factory but excludes them from the ordered
|
|
54
|
+
* array, and their "header" values are internal `x-cc-*` names, not beta
|
|
55
|
+
* identifiers. Transcribing them would corrupt the registry.
|
|
56
|
+
*
|
|
57
|
+
* Every one of the nine entries new since 2.1.233 was confirmed against its own
|
|
58
|
+
* `N(alias, header)` declaration in the carved dump rather than against the
|
|
59
|
+
* analysis document alone, so no new header rests on a single reading:
|
|
60
|
+
* `rrt` 6278299, `w$` 6278910, `j_` 6278959, `W_` 6279023, and `qk`, `Aoe`,
|
|
61
|
+
* `cD`, `V1`, `lD` in the window at 6279405.
|
|
62
|
+
*
|
|
63
|
+
* `oauth_auth` is the one entry whose header is NOT a string literal upstream:
|
|
64
|
+
* the declaration reads `swe=N("oauth_auth",Ru)`. `Ru` is an imported binding,
|
|
65
|
+
* re-exported as `OAUTH_BETA_HEADER` at byte 25341943, and the only beta-shaped
|
|
66
|
+
* `oauth-*` literal in the bundle is `"oauth-2025-04-20"` at byte 4418398.
|
|
67
|
+
* Resolved by that binding, not by name similarity.
|
|
68
|
+
*/
|
|
69
|
+
export const BETA_REGISTRY_2_1_280 = deepFreeze({
|
|
70
|
+
CLAUDE_CODE: { featureKey: "claude_code", header: "claude-code-20250219" },
|
|
71
|
+
OAUTH_AUTH: { featureKey: "oauth_auth", header: "oauth-2025-04-20" },
|
|
72
|
+
INTERLEAVED_THINKING: {
|
|
73
|
+
featureKey: "interleaved_thinking",
|
|
74
|
+
header: "interleaved-thinking-2025-05-14",
|
|
75
|
+
},
|
|
76
|
+
LONG_CONTEXT: { featureKey: "long_context", header: "context-1m-2025-08-07" },
|
|
77
|
+
CONTEXT_MANAGEMENT: {
|
|
78
|
+
featureKey: "context_management",
|
|
79
|
+
header: "context-management-2025-06-27",
|
|
80
|
+
},
|
|
81
|
+
STRUCTURED_OUTPUTS: {
|
|
82
|
+
featureKey: "structured_outputs",
|
|
83
|
+
header: "structured-outputs-2025-12-15",
|
|
84
|
+
},
|
|
85
|
+
WEB_SEARCH: { featureKey: "web_search", header: "web-search-2025-03-05" },
|
|
86
|
+
ADVANCED_TOOL_USE: {
|
|
87
|
+
featureKey: "tool_search",
|
|
88
|
+
header: "advanced-tool-use-2025-11-20",
|
|
89
|
+
},
|
|
90
|
+
TOOL_SEARCH: {
|
|
91
|
+
featureKey: "tool_search",
|
|
92
|
+
header: "tool-search-tool-2025-10-19",
|
|
93
|
+
},
|
|
94
|
+
EFFORT: { featureKey: "effort", header: "effort-2025-11-24" },
|
|
95
|
+
TASK_BUDGETS: {
|
|
96
|
+
featureKey: "task_budgets",
|
|
97
|
+
header: "task-budgets-2026-03-13",
|
|
98
|
+
},
|
|
99
|
+
PROMPT_CACHING_SCOPE: {
|
|
100
|
+
featureKey: "prompt_caching_scope",
|
|
101
|
+
header: "prompt-caching-scope-2026-01-05",
|
|
102
|
+
},
|
|
103
|
+
PROMPT_CACHING_EVICT: {
|
|
104
|
+
featureKey: "prompt_caching_evict",
|
|
105
|
+
header: "prompt-caching-evict-2026-05-12",
|
|
106
|
+
},
|
|
107
|
+
EXTENDED_CACHE_TTL: {
|
|
108
|
+
featureKey: "extended_cache_ttl",
|
|
109
|
+
header: "extended-cache-ttl-2025-04-11",
|
|
110
|
+
},
|
|
111
|
+
SPEED: { featureKey: "speed", header: "fast-mode-2026-02-01" },
|
|
112
|
+
REDACT_THINKING: {
|
|
113
|
+
featureKey: "redact_thinking",
|
|
114
|
+
header: "redact-thinking-2026-02-12",
|
|
115
|
+
},
|
|
116
|
+
// New at 2.1.280, and inserted HERE rather than appended. Every entry below
|
|
117
|
+
// this point sat one slot lower in 2.1.233.
|
|
118
|
+
THINKING_RESUMPTION: {
|
|
119
|
+
featureKey: "thinking_resumption",
|
|
120
|
+
header: "thinking-resumption-2026-07-17",
|
|
121
|
+
},
|
|
122
|
+
THINKING_TOKEN_COUNT: {
|
|
123
|
+
featureKey: "thinking_token_count",
|
|
124
|
+
header: "thinking-token-count-2026-05-13",
|
|
125
|
+
},
|
|
126
|
+
AFK_MODE: { featureKey: "afk_mode", header: "afk-mode-2026-01-31" },
|
|
127
|
+
ADVISOR_TOOL: {
|
|
128
|
+
featureKey: "advisor_tool",
|
|
129
|
+
header: "advisor-tool-2026-03-01",
|
|
130
|
+
},
|
|
131
|
+
CACHE_DIAGNOSIS: {
|
|
132
|
+
featureKey: "cache_diagnosis",
|
|
133
|
+
header: "cache-diagnosis-2026-04-07",
|
|
134
|
+
},
|
|
135
|
+
CONTEXT_HINT: {
|
|
136
|
+
featureKey: "context_hint",
|
|
137
|
+
header: "context-hint-2026-04-09",
|
|
138
|
+
},
|
|
139
|
+
MCP_SERVERS: { featureKey: "mcp_servers", header: "mcp-servers-2025-12-04" },
|
|
140
|
+
FILES_API: { featureKey: "files_api", header: "files-api-2025-04-14" },
|
|
141
|
+
ENVIRONMENTS: {
|
|
142
|
+
featureKey: "environments",
|
|
143
|
+
header: "environments-2025-11-01",
|
|
144
|
+
},
|
|
145
|
+
CCR_BYOC: { featureKey: "ccr_byoc", header: "ccr-byoc-2025-07-29" },
|
|
146
|
+
MID_CONVERSATION_SYSTEM: {
|
|
147
|
+
featureKey: "mid_conversation_system",
|
|
148
|
+
header: "mid-conversation-system-2026-04-07",
|
|
149
|
+
},
|
|
150
|
+
PER_MESSAGE_EFFORT: {
|
|
151
|
+
featureKey: "per_message_effort",
|
|
152
|
+
header: "per-turn-control-2026-07-01",
|
|
153
|
+
},
|
|
154
|
+
// New at 2.1.280. Also inserted rather than appended: the four entries below
|
|
155
|
+
// `INLINE_TOOLS` all predate this release.
|
|
156
|
+
PER_TURN_TIMING: {
|
|
157
|
+
featureKey: "per_turn_timing",
|
|
158
|
+
header: "timing-2026-09-09",
|
|
159
|
+
},
|
|
160
|
+
MID_CONV_TOOL_CHANGE: {
|
|
161
|
+
featureKey: "mid_conv_tool_change",
|
|
162
|
+
header: "mid-conversation-tool-changes-2026-07-01",
|
|
163
|
+
},
|
|
164
|
+
INLINE_TOOLS: {
|
|
165
|
+
featureKey: "inline_tools",
|
|
166
|
+
header: "inline-tools-2026-09-15",
|
|
167
|
+
},
|
|
168
|
+
SERVER_SIDE_FALLBACK: {
|
|
169
|
+
featureKey: "server_side_fallback",
|
|
170
|
+
header: "server-side-fallback-2026-06-01",
|
|
171
|
+
},
|
|
172
|
+
SERVER_SIDE_FALLBACK_CATEGORY: {
|
|
173
|
+
featureKey: "server_side_fallback_category",
|
|
174
|
+
header: "server-side-fallback-2026-07-01",
|
|
175
|
+
},
|
|
176
|
+
FALLBACK_CREDIT: {
|
|
177
|
+
featureKey: "fallback_credit",
|
|
178
|
+
header: "fallback-credit-2026-06-01",
|
|
179
|
+
},
|
|
180
|
+
/*
|
|
181
|
+
* NARRATION_SUMMARIES IS DELIBERATELY ABSENT, exactly as in the 2.1.233
|
|
182
|
+
* registry, and re-adding it would reintroduce a header the genuine client no
|
|
183
|
+
* longer sends. Do not "fix" it.
|
|
184
|
+
*
|
|
185
|
+
* This position -- between `FALLBACK_CREDIT` and `AUTO_MODE_CLASSIFIER` -- is
|
|
186
|
+
* where the 2.1.233 registry records the removal, and it is also where array
|
|
187
|
+
* index 34 (`kAt`, null) falls. That correspondence is suggestive and NOT
|
|
188
|
+
* EVIDENCED: the `summarize-connector-text-2026-03-13` header string appears
|
|
189
|
+
* nowhere in the 2.1.280 bundle, so nothing ties it to `kAt` rather than to
|
|
190
|
+
* `hZt`, and `kAt`'s surviving consumer at byte 14167580 reports rejections
|
|
191
|
+
* under an "Auto mode classifier" label, which points the other way. The
|
|
192
|
+
* analysis document asserts only that two slots are null and this file
|
|
193
|
+
* asserts no more. See section 4.2 of
|
|
194
|
+
* `docs/protocol/versions/claude-code-2.1.280-analysis.md`.
|
|
195
|
+
*/
|
|
196
|
+
AUTO_MODE_CLASSIFIER: {
|
|
197
|
+
featureKey: "auto_mode_classifier",
|
|
198
|
+
header: "auto-mode-classifier-2026-07-16",
|
|
199
|
+
},
|
|
200
|
+
// New at 2.1.280.
|
|
201
|
+
DANGEROUS_TOOL_USE: {
|
|
202
|
+
featureKey: "dangerous_tool_use",
|
|
203
|
+
header: "dangerous-tool-use-2026-09-03",
|
|
204
|
+
},
|
|
205
|
+
/*
|
|
206
|
+
* The SECOND null slot (`hZt`, upstream index 37) belongs here. As with the
|
|
207
|
+
* first, what it once held -- if anything -- is unknown: no header string in
|
|
208
|
+
* any analysed release is tied to it by evidence. It is recorded rather than
|
|
209
|
+
* silently closed up, because a future build may reuse the slot.
|
|
210
|
+
*/
|
|
211
|
+
// New at 2.1.280.
|
|
212
|
+
THINKING_DISPLAY_UPDATES: {
|
|
213
|
+
featureKey: "thinking_display_updates",
|
|
214
|
+
header: "thinking-display-updates-2026-08-18",
|
|
215
|
+
},
|
|
216
|
+
MESSAGE_THREADS: {
|
|
217
|
+
featureKey: "message_threads",
|
|
218
|
+
header: "message-threads-2026-08-12",
|
|
219
|
+
},
|
|
220
|
+
MID_CONVERSATION_SYSTEM_CLEAR_AT: {
|
|
221
|
+
featureKey: "mid_conversation_system_clear_at",
|
|
222
|
+
header: "mid-conversation-system-clear-at-2026-08-21",
|
|
223
|
+
},
|
|
224
|
+
/*
|
|
225
|
+
* LAST in the array, though upstream DECLARES it alongside
|
|
226
|
+
* `thinking_display_updates` and `message_threads`. Declaration order and
|
|
227
|
+
* array order differ here and the array is what this transcription follows.
|
|
228
|
+
*/
|
|
229
|
+
THINKING_BINDING_CONTROLS: {
|
|
230
|
+
featureKey: "thinking_binding_controls",
|
|
231
|
+
header: "thinking-binding-controls-2026-08-01",
|
|
232
|
+
},
|
|
233
|
+
} satisfies Record<string, BetaRegistryEntry>);
|
|
234
|
+
|
|
235
|
+
/*
|
|
236
|
+
* Third-party filtering as of 2.1.280, upstream `Dg` at byte 7029997, consumed
|
|
237
|
+
* by `DDn(e) { if (iwe()) return e; return e.filter(n => Dg.has(n)) }` in the
|
|
238
|
+
* same run -- that is, the set is applied only when the request is NOT
|
|
239
|
+
* first-party, which is how it was identified: by call site, not by resemblance
|
|
240
|
+
* to the 2.1.233 set.
|
|
241
|
+
*
|
|
242
|
+
* Upstream writes one member as a conditional spread, `...BR ? [BR] : []`. That
|
|
243
|
+
* is why the extractor reported this set `unresolved` ("a member is neither a
|
|
244
|
+
* string literal nor a single property read"). `BR` is unconditionally defined
|
|
245
|
+
* at byte 6278332 in this build, so the spread always contributes and the set
|
|
246
|
+
* has fourteen members.
|
|
247
|
+
*
|
|
248
|
+
* Delta against the 2.1.233 set: `dangerous_tool_use`, `thinking_token_count`
|
|
249
|
+
* and `thinking_binding_controls` were ADDED; nothing was removed. Order below
|
|
250
|
+
* follows upstream's literal.
|
|
251
|
+
*/
|
|
252
|
+
export const THIRD_PARTY_ALLOWED_BETAS_2_1_280: ReadonlySet<string> =
|
|
253
|
+
Object.freeze(
|
|
254
|
+
new Set([
|
|
255
|
+
BETA_REGISTRY_2_1_280.CLAUDE_CODE.header,
|
|
256
|
+
BETA_REGISTRY_2_1_280.INTERLEAVED_THINKING.header,
|
|
257
|
+
BETA_REGISTRY_2_1_280.LONG_CONTEXT.header,
|
|
258
|
+
BETA_REGISTRY_2_1_280.CONTEXT_MANAGEMENT.header,
|
|
259
|
+
BETA_REGISTRY_2_1_280.STRUCTURED_OUTPUTS.header,
|
|
260
|
+
BETA_REGISTRY_2_1_280.WEB_SEARCH.header,
|
|
261
|
+
BETA_REGISTRY_2_1_280.EFFORT.header,
|
|
262
|
+
BETA_REGISTRY_2_1_280.TOOL_SEARCH.header,
|
|
263
|
+
BETA_REGISTRY_2_1_280.AFK_MODE.header,
|
|
264
|
+
BETA_REGISTRY_2_1_280.DANGEROUS_TOOL_USE.header,
|
|
265
|
+
BETA_REGISTRY_2_1_280.FALLBACK_CREDIT.header,
|
|
266
|
+
BETA_REGISTRY_2_1_280.MID_CONVERSATION_SYSTEM.header,
|
|
267
|
+
BETA_REGISTRY_2_1_280.THINKING_TOKEN_COUNT.header,
|
|
268
|
+
BETA_REGISTRY_2_1_280.THINKING_BINDING_CONTROLS.header,
|
|
269
|
+
]),
|
|
270
|
+
);
|
|
271
|
+
|
|
272
|
+
/*
|
|
273
|
+
* Provider filtering as of 2.1.280, upstream `qbr` at byte 6280270.
|
|
274
|
+
*
|
|
275
|
+
* Identified by behaviour rather than by shape: `Y5` at byte 7029210 reads
|
|
276
|
+
* `if (sc(e) === "bedrock") return n.filter(r => !qbr.has(r))`, and the
|
|
277
|
+
* complementary `lco` at the same site keeps exactly this set as bedrock
|
|
278
|
+
* extra-body parameters. Byte-identical to the 2.1.233 set.
|
|
279
|
+
*
|
|
280
|
+
* A DIFFERENT `qbr` exists at byte 13922760 in another module -- a set of grep
|
|
281
|
+
* flags. Minified names are module-scoped; this entry is the one the beta
|
|
282
|
+
* pipeline consumes.
|
|
283
|
+
*
|
|
284
|
+
* Static reference data with no call site in `src/`, exactly like its 2.1.233
|
|
285
|
+
* counterpart. See `test/governance/provider-scope.test.ts`.
|
|
286
|
+
*/
|
|
287
|
+
export const BEDROCK_UNSUPPORTED_BETAS_2_1_280: ReadonlySet<string> =
|
|
288
|
+
Object.freeze(
|
|
289
|
+
new Set([
|
|
290
|
+
BETA_REGISTRY_2_1_280.INTERLEAVED_THINKING.header,
|
|
291
|
+
BETA_REGISTRY_2_1_280.LONG_CONTEXT.header,
|
|
292
|
+
BETA_REGISTRY_2_1_280.TOOL_SEARCH.header,
|
|
293
|
+
]),
|
|
294
|
+
);
|
|
295
|
+
|
|
296
|
+
/*
|
|
297
|
+
* Count-tokens selection as of 2.1.280, upstream `iNn` at byte 6280282,
|
|
298
|
+
* consumed as `betas: y.filter(he => iNn.has(he))` inside
|
|
299
|
+
* `beta.messages.countTokens` at bytes 12304007, 12304164 and 12305087.
|
|
300
|
+
* Byte-identical to the 2.1.233 set.
|
|
301
|
+
*/
|
|
302
|
+
export const COUNT_TOKENS_BETAS_2_1_280: ReadonlySet<string> = Object.freeze(
|
|
303
|
+
new Set([
|
|
304
|
+
BETA_REGISTRY_2_1_280.CLAUDE_CODE.header,
|
|
305
|
+
BETA_REGISTRY_2_1_280.INTERLEAVED_THINKING.header,
|
|
306
|
+
BETA_REGISTRY_2_1_280.CONTEXT_MANAGEMENT.header,
|
|
307
|
+
BETA_REGISTRY_2_1_280.OAUTH_AUTH.header,
|
|
308
|
+
]),
|
|
309
|
+
);
|