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.
@@ -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
- const extraHeaders = dropConflictingExtraHeaders(input.extraHeaders);
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
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "opencode-anthropic-fix",
3
- "version": "0.5.0",
3
+ "version": "0.6.0",
4
4
  "license": "GPL-3.0-or-later",
5
5
  "repository": {
6
6
  "type": "git",