opencode-anthropic-fix 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/lib/mimicry/wire-compat.mjs +15 -85
- package/package.json +1 -1
|
@@ -314,90 +314,9 @@ const COUNT_TOKENS_INPUT_FIELDS = new Set([
|
|
|
314
314
|
"clientApp",
|
|
315
315
|
"anthropicAdditionalProtection",
|
|
316
316
|
"extraHeaders",
|
|
317
|
+
"extraHeaderPolicy",
|
|
317
318
|
]);
|
|
318
319
|
|
|
319
|
-
/**
|
|
320
|
-
* The header names the package composes itself, mirrored from `HEADER_NAMES`
|
|
321
|
-
* (src/headers.ts). Exported so `wire-compat.test.mjs` can pin the mirror
|
|
322
|
-
* against the package's real behaviour rather than trusting this copy.
|
|
323
|
-
*/
|
|
324
|
-
export const PACKAGE_CANONICAL_HEADER_NAMES = new Set([
|
|
325
|
-
"anthropic-beta",
|
|
326
|
-
"anthropic-dangerous-direct-browser-access",
|
|
327
|
-
"anthropic-version",
|
|
328
|
-
"authorization",
|
|
329
|
-
"content-type",
|
|
330
|
-
"user-agent",
|
|
331
|
-
"x-app",
|
|
332
|
-
"x-claude-code-session-id",
|
|
333
|
-
"x-client-request-id",
|
|
334
|
-
"x-stainless-arch",
|
|
335
|
-
"x-stainless-lang",
|
|
336
|
-
"x-stainless-os",
|
|
337
|
-
"x-stainless-package-version",
|
|
338
|
-
"x-stainless-retry-count",
|
|
339
|
-
"x-stainless-runtime",
|
|
340
|
-
"x-stainless-runtime-version",
|
|
341
|
-
"x-stainless-timeout",
|
|
342
|
-
"x-stainless-helper",
|
|
343
|
-
"x-claude-remote-container-id",
|
|
344
|
-
"x-claude-remote-session-id",
|
|
345
|
-
"x-client-app",
|
|
346
|
-
"x-anthropic-additional-protection",
|
|
347
|
-
]);
|
|
348
|
-
|
|
349
|
-
/** Mirror of the package's `FORBIDDEN_HEADER_NAMES` (src/headers.ts). */
|
|
350
|
-
export const PACKAGE_FORBIDDEN_HEADER_NAMES = new Set([
|
|
351
|
-
"x-api-key",
|
|
352
|
-
"cookie",
|
|
353
|
-
"set-cookie",
|
|
354
|
-
"forwarded",
|
|
355
|
-
"content-length",
|
|
356
|
-
"host",
|
|
357
|
-
"connection",
|
|
358
|
-
"transfer-encoding",
|
|
359
|
-
"te",
|
|
360
|
-
"upgrade",
|
|
361
|
-
"keep-alive",
|
|
362
|
-
]);
|
|
363
|
-
|
|
364
|
-
/** Mirror of the package's `isForbiddenHeader` prefix rules. */
|
|
365
|
-
export const PACKAGE_FORBIDDEN_HEADER_PREFIXES = Object.freeze(["proxy-", "x-forwarded-"]);
|
|
366
|
-
|
|
367
|
-
/**
|
|
368
|
-
* Apply the package's `dropConflicting` extra-header policy PLUGIN-SIDE.
|
|
369
|
-
*
|
|
370
|
-
* WHY THIS EXISTS. `extraHeaderPolicy` is not one of the sixteen keys
|
|
371
|
-
* `ClaudeCodeCountTokensInput` picks, and `validateCountTokensInput` runs
|
|
372
|
-
* `assertExactKeys`, so passing it is `INVALID_INPUT` rather than a no-op. The
|
|
373
|
-
* count surface therefore always resolves extra headers under `strict`, where
|
|
374
|
-
* the FIRST host header the package owns raises `DUPLICATE_HEADER` (canonical
|
|
375
|
-
* name) or `FORBIDDEN_HEADER` (hop-by-hop / credential name) and nothing
|
|
376
|
-
* reaches the wire. The plugin forwards a heterogeneous host header map — the
|
|
377
|
-
* opencode SDK alone sends `content-type` and `accept` — so without this filter
|
|
378
|
-
* every count turn would throw and fall back to nothing at all.
|
|
379
|
-
*
|
|
380
|
-
* The main turn gets the same outcome for free through
|
|
381
|
-
* `extraHeaderPolicy: "dropConflicting"` on the transport, which the count pick
|
|
382
|
-
* discards; this reproduces it. Only OWNERSHIP conflicts are dropped, exactly
|
|
383
|
-
* as the package does: header syntax is still validated package-side and a
|
|
384
|
-
* caller duplicating one of its OWN extra headers still raises
|
|
385
|
-
* `DUPLICATE_HEADER`, because that is a caller bug and not ours to paper over.
|
|
386
|
-
*
|
|
387
|
-
* @param {readonly (readonly [string, string])[] | undefined} extraHeaders
|
|
388
|
-
* @returns {readonly (readonly [string, string])[] | undefined}
|
|
389
|
-
*/
|
|
390
|
-
function dropConflictingExtraHeaders(extraHeaders) {
|
|
391
|
-
if (extraHeaders === undefined) return undefined;
|
|
392
|
-
const kept = extraHeaders.filter(([name]) => {
|
|
393
|
-
const normalized = String(name).toLowerCase();
|
|
394
|
-
if (PACKAGE_CANONICAL_HEADER_NAMES.has(normalized)) return false;
|
|
395
|
-
if (PACKAGE_FORBIDDEN_HEADER_NAMES.has(normalized)) return false;
|
|
396
|
-
return !PACKAGE_FORBIDDEN_HEADER_PREFIXES.some((prefix) => normalized.startsWith(prefix));
|
|
397
|
-
});
|
|
398
|
-
return kept.length > 0 ? kept : undefined;
|
|
399
|
-
}
|
|
400
|
-
|
|
401
320
|
/**
|
|
402
321
|
* Map the host body to the shared package's count-tokens input.
|
|
403
322
|
*
|
|
@@ -418,6 +337,19 @@ function dropConflictingExtraHeaders(extraHeaders) {
|
|
|
418
337
|
* malformed value and a field that is contractually absent from the count body
|
|
419
338
|
* must not be able to fail the build.
|
|
420
339
|
*
|
|
340
|
+
* EXTRA HEADERS. The count surface takes `extraHeaderPolicy` since wire-compat
|
|
341
|
+
* 0.4.0, so the policy is set here exactly as the main turn sets it on the
|
|
342
|
+
* transport (`buildAdapterTransport`). Under the package default (`strict`) the
|
|
343
|
+
* first host header the package owns raises `DUPLICATE_HEADER` (canonical name)
|
|
344
|
+
* or `FORBIDDEN_HEADER` (hop-by-hop / credential name) and nothing reaches the
|
|
345
|
+
* wire — and the plugin forwards a heterogeneous host header map, the opencode
|
|
346
|
+
* SDK alone sending `content-type` and `accept`. `dropConflicting` drops only
|
|
347
|
+
* OWNERSHIP conflicts: header syntax is still validated package-side and a
|
|
348
|
+
* caller duplicating one of its OWN extra headers still raises
|
|
349
|
+
* `DUPLICATE_HEADER`, because that is a caller bug and not ours to paper over.
|
|
350
|
+
* The names the package drops are reported back as
|
|
351
|
+
* `evidence.droppedExtraHeaderNames`.
|
|
352
|
+
*
|
|
421
353
|
* @param {Record<string, import('@tormentalabs/claude-code-wire-compat').JsonValue>} body
|
|
422
354
|
* @param {{
|
|
423
355
|
* accessToken: string,
|
|
@@ -440,9 +372,7 @@ export function toClaudeCodeCountTokensInput(body, transport) {
|
|
|
440
372
|
const { system: _system, ...bodyWithoutSystem } = body;
|
|
441
373
|
const full = toClaudeCodeRequestInput(bodyWithoutSystem, transport);
|
|
442
374
|
const input = Object.fromEntries(Object.entries(full).filter(([name]) => COUNT_TOKENS_INPUT_FIELDS.has(name)));
|
|
443
|
-
|
|
444
|
-
if (extraHeaders === undefined) delete input.extraHeaders;
|
|
445
|
-
else input.extraHeaders = extraHeaders;
|
|
375
|
+
input.extraHeaderPolicy = "dropConflicting";
|
|
446
376
|
if (transport.crypto !== undefined) input.crypto = transport.crypto;
|
|
447
377
|
return input;
|
|
448
378
|
}
|