opencode-anthropic-fix 0.0.36 → 0.0.38

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.
Files changed (3) hide show
  1. package/index.mjs +209 -29
  2. package/lib/config.mjs +14 -0
  3. package/package.json +1 -1
package/index.mjs CHANGED
@@ -158,6 +158,24 @@ export async function AnthropicAuthPlugin({ client, project, directory, worktree
158
158
  let willowLastRequestTime = Date.now();
159
159
  let willowLastSuggestionTime = 0;
160
160
 
161
+ // Beta header latching: once a beta is sent in a session, it stays on for
162
+ // the rest of the session to prevent cache key churn (~50-70K tokens per flip).
163
+ // Cleared on /clear or /compact if needed.
164
+ const betaLatchState = {
165
+ /** @type {Set<string>} betas that have been sent at least once this session */
166
+ sent: new Set(),
167
+ /** When true, a config change invalidated the latch and next request rebuilds. */
168
+ dirty: false,
169
+ /** @type {string | null} The last computed beta header string (for latching). */
170
+ lastHeader: null,
171
+ };
172
+
173
+ // Cache TTL session latching: latch the cache policy at session start
174
+ // so mid-session toggles don't bust the server-side prompt cache.
175
+ let sessionCachePolicyLatched = false;
176
+ /** @type {{ttl: string, ttl_supported: boolean, boundary_marker?: boolean} | null} */
177
+ let latchedCachePolicy = null;
178
+
161
179
  /**
162
180
  * Whether OPENCODE_ANTHROPIC_INITIAL_ACCOUNT env var pinned this session to a
163
181
  * specific account. When true, syncActiveIndexFromDisk is skipped and strategy
@@ -846,6 +864,43 @@ export async function AnthropicAuthPlugin({ client, project, directory, worktree
846
864
  adaptiveContextState.lastTransitionTurn = sessionMetrics.turns;
847
865
  }
848
866
  },
867
+ "token-efficient-tools": () => {
868
+ const enabled = value === "on" || value === "true" || value === "1";
869
+ const te = config.token_economy || {
870
+ token_efficient_tools: true,
871
+ redact_thinking: false,
872
+ connector_text_summarization: true,
873
+ };
874
+ te.token_efficient_tools = enabled;
875
+ saveConfig({ token_economy: te });
876
+ config.token_economy = te;
877
+ // Invalidate latched betas so the change takes effect next request
878
+ betaLatchState.dirty = true;
879
+ },
880
+ "redact-thinking": () => {
881
+ const enabled = value === "on" || value === "true" || value === "1";
882
+ const te = config.token_economy || {
883
+ token_efficient_tools: true,
884
+ redact_thinking: false,
885
+ connector_text_summarization: true,
886
+ };
887
+ te.redact_thinking = enabled;
888
+ saveConfig({ token_economy: te });
889
+ config.token_economy = te;
890
+ betaLatchState.dirty = true;
891
+ },
892
+ "connector-text": () => {
893
+ const enabled = value === "on" || value === "true" || value === "1";
894
+ const te = config.token_economy || {
895
+ token_efficient_tools: true,
896
+ redact_thinking: false,
897
+ connector_text_summarization: true,
898
+ };
899
+ te.connector_text_summarization = enabled;
900
+ saveConfig({ token_economy: te });
901
+ config.token_economy = te;
902
+ betaLatchState.dirty = true;
903
+ },
849
904
  };
850
905
 
851
906
  if (!key || !setters[key]) {
@@ -2397,7 +2452,10 @@ export async function AnthropicAuthPlugin({ client, project, directory, worktree
2397
2452
 
2398
2453
  const _adaptiveOverride = _adaptiveOverrideForRequest;
2399
2454
 
2400
- const computedBetaHeader = buildAnthropicBetaHeader(
2455
+ // Token economy config (resolved once, passed to beta builder)
2456
+ const _tokenEconomy = config.token_economy || {};
2457
+
2458
+ let computedBetaHeader = buildAnthropicBetaHeader(
2401
2459
  "",
2402
2460
  getSignatureEmulationEnabled(),
2403
2461
  _reqModel,
@@ -2407,8 +2465,43 @@ export async function AnthropicAuthPlugin({ client, project, directory, worktree
2407
2465
  requestUrl?.pathname,
2408
2466
  _reqHasFileRefs,
2409
2467
  _adaptiveOverride,
2468
+ _tokenEconomy,
2410
2469
  );
2411
2470
 
2471
+ // Beta header latching: once a beta has been sent in this session,
2472
+ // keep sending it to avoid server-side cache key churn (~50-70K tokens
2473
+ // per flip). The latch is sticky-on: new betas can be added but never
2474
+ // removed mid-session unless explicitly invalidated by config change.
2475
+ {
2476
+ const currentBetas = computedBetaHeader
2477
+ .split(",")
2478
+ .map((b) => b.trim())
2479
+ .filter(Boolean);
2480
+ // Add all current betas to the latch set
2481
+ for (const b of currentBetas) betaLatchState.sent.add(b);
2482
+ // If a config change dirtied the latch, rebuild from current (allow removal)
2483
+ if (betaLatchState.dirty) {
2484
+ betaLatchState.dirty = false;
2485
+ betaLatchState.sent = new Set(currentBetas);
2486
+ }
2487
+ // Merge latched betas that aren't in the current set
2488
+ const merged = new Set(currentBetas);
2489
+ for (const b of betaLatchState.sent) merged.add(b);
2490
+ computedBetaHeader = [...merged].join(",");
2491
+ betaLatchState.lastHeader = computedBetaHeader;
2492
+ }
2493
+
2494
+ // Cache TTL session latching: latch the cache policy at session start
2495
+ // so mid-session toggles don't bust the server-side prompt cache.
2496
+ if (!sessionCachePolicyLatched) {
2497
+ sessionCachePolicyLatched = true;
2498
+ latchedCachePolicy = config.cache_policy
2499
+ ? { ...config.cache_policy }
2500
+ : { ttl: "1h", ttl_supported: true };
2501
+ }
2502
+ const effectiveCachePolicy = latchedCachePolicy ||
2503
+ config.cache_policy || { ttl: "1h", ttl_supported: true };
2504
+
2412
2505
  let body = transformRequestBody(
2413
2506
  requestInit.body,
2414
2507
  {
@@ -2416,7 +2509,7 @@ export async function AnthropicAuthPlugin({ client, project, directory, worktree
2416
2509
  claudeCliVersion,
2417
2510
  promptCompactionMode: getPromptCompactionMode(),
2418
2511
  provider: _reqProvider,
2419
- cachePolicy: config.cache_policy || { ttl: "1h", ttl_supported: true },
2512
+ cachePolicy: effectiveCachePolicy,
2420
2513
  fastMode: config.fast_mode || false,
2421
2514
  strategy: getEffectiveStrategy(),
2422
2515
  },
@@ -2443,6 +2536,7 @@ export async function AnthropicAuthPlugin({ client, project, directory, worktree
2443
2536
  strategy: getEffectiveStrategy(),
2444
2537
  },
2445
2538
  _adaptiveOverride,
2539
+ _tokenEconomy,
2446
2540
  );
2447
2541
  // Execute the request
2448
2542
  let response;
@@ -2629,10 +2723,15 @@ export async function AnthropicAuthPlugin({ client, project, directory, worktree
2629
2723
  // Auto-escalate adaptive context on prompt_too_long so the retry
2630
2724
  // includes the 1M beta header (if model supports it).
2631
2725
  if (config.adaptive_context?.enabled) {
2632
- forceEscalateAdaptiveContext();
2633
- toast("⬡ 1M context force-activated (prompt too long)", "warning", {
2634
- debounceKey: "adaptive-ctx",
2635
- }).catch(() => {});
2726
+ const stateChanged = forceEscalateAdaptiveContext();
2727
+ if (stateChanged) {
2728
+ // Invalidate cached adaptive decision so the retry loop
2729
+ // re-evaluates with the new active=true state.
2730
+ _adaptiveDecisionMade = false;
2731
+ toast("⬡ 1M context force-activated (prompt too long)", "warning", {
2732
+ debounceKey: "adaptive-ctx",
2733
+ }).catch(() => {});
2734
+ }
2636
2735
  }
2637
2736
  try {
2638
2737
  const parsedBody = JSON.parse(body);
@@ -3215,7 +3314,7 @@ function estimatePromptTokens(bodyString) {
3215
3314
  * @returns {boolean}
3216
3315
  */
3217
3316
  function resolveAdaptiveContext(bodyString, model, adaptiveConfig) {
3218
- // Non-adaptive: use static check
3317
+ // Non-adaptive: use static check (only explicit "1m" models)
3219
3318
  if (!adaptiveConfig.enabled) {
3220
3319
  return hasOneMillionContext(model);
3221
3320
  }
@@ -3225,8 +3324,8 @@ function resolveAdaptiveContext(bodyString, model, adaptiveConfig) {
3225
3324
  return false;
3226
3325
  }
3227
3326
 
3228
- // Model must be eligible for 1M context at all
3229
- if (!hasOneMillionContext(model)) {
3327
+ // Model must be eligible for 1M context at all (includes Opus 4.6)
3328
+ if (!isEligibleFor1MContext(model)) {
3230
3329
  return false;
3231
3330
  }
3232
3331
 
@@ -3235,10 +3334,25 @@ function resolveAdaptiveContext(bodyString, model, adaptiveConfig) {
3235
3334
 
3236
3335
  if (adaptiveContextState.active) {
3237
3336
  // Currently active — consider de-escalation
3238
- // Don't de-escalate if error-escalated (sticky)
3337
+
3338
+ // Error-escalated: sticky for ERROR_STICKY_TURNS turns, then allow de-escalation
3339
+ // if prompt has dropped well below threshold (prevents permanent 1M lock-in).
3340
+ const ERROR_STICKY_TURNS = 5;
3239
3341
  if (adaptiveContextState.escalatedByError) {
3240
- return true;
3342
+ if (turnsSinceTransition < ERROR_STICKY_TURNS) {
3343
+ return true; // Still within sticky window
3344
+ }
3345
+ // Past sticky window: allow de-escalation if tokens dropped significantly
3346
+ // (below 75% of deescalation threshold to avoid flapping)
3347
+ if (estimatedTokens < adaptiveConfig.deescalation_threshold * 0.75) {
3348
+ adaptiveContextState.active = false;
3349
+ adaptiveContextState.escalatedByError = false;
3350
+ adaptiveContextState.lastTransitionTurn = sessionMetrics.turns;
3351
+ return false;
3352
+ }
3353
+ return true; // Still high enough to keep 1M
3241
3354
  }
3355
+
3242
3356
  // Hysteresis: require at least 2 turns before considering de-escalation
3243
3357
  if (turnsSinceTransition < 2) {
3244
3358
  return true;
@@ -3268,13 +3382,17 @@ function resolveAdaptiveContext(bodyString, model, adaptiveConfig) {
3268
3382
 
3269
3383
  /**
3270
3384
  * Force-escalate adaptive context (e.g. after prompt_too_long error).
3385
+ * Returns true so callers can invalidate cached decisions.
3386
+ * @returns {boolean}
3271
3387
  */
3272
3388
  function forceEscalateAdaptiveContext() {
3389
+ const wasActive = adaptiveContextState.active;
3273
3390
  if (!adaptiveContextState.active) {
3274
3391
  adaptiveContextState.active = true;
3275
3392
  adaptiveContextState.lastTransitionTurn = sessionMetrics.turns;
3276
3393
  }
3277
3394
  adaptiveContextState.escalatedByError = true;
3395
+ return !wasActive; // true if state actually changed
3278
3396
  }
3279
3397
 
3280
3398
  const MODEL_PRICING = {
@@ -3556,17 +3674,18 @@ process.once("beforeExit", () => {
3556
3674
  // Request building helpers (extracted from original fetch interceptor)
3557
3675
  // ---------------------------------------------------------------------------
3558
3676
 
3559
- const FALLBACK_CLAUDE_CLI_VERSION = "2.1.87";
3677
+ const FALLBACK_CLAUDE_CLI_VERSION = "2.1.88";
3560
3678
  const CLAUDE_CODE_NPM_LATEST_URL = "https://registry.npmjs.org/@anthropic-ai/claude-code/latest";
3561
- const CLAUDE_CODE_BUILD_TIME = "2026-03-29T02:16:58Z";
3679
+ const CLAUDE_CODE_BUILD_TIME = "2026-03-30T21:59:52Z";
3562
3680
 
3563
- // The @anthropic-ai/sdk version bundled with Claude Code v2.1.87.
3681
+ // The @anthropic-ai/sdk version bundled with Claude Code v2.1.88.
3564
3682
  // This is distinct from the CLI version and goes in X-Stainless-Package-Version.
3565
- // Verified by extracting VERSION="0.208.0" from the bundled cli.js of all versions .83-.87.
3683
+ // Verified by extracting VERSION="0.208.0" from the bundled cli.js of all versions .83-.88.
3566
3684
  const ANTHROPIC_SDK_VERSION = "0.208.0";
3567
3685
 
3568
3686
  // Map of CLI version → bundled SDK version (update when CLI version changes)
3569
3687
  const CLI_TO_SDK_VERSION = new Map([
3688
+ ["2.1.88", "0.208.0"],
3570
3689
  ["2.1.87", "0.208.0"],
3571
3690
  ["2.1.86", "0.208.0"],
3572
3691
  ["2.1.85", "0.208.0"],
@@ -3655,6 +3774,8 @@ const EXPERIMENTAL_BETA_FLAGS = new Set([
3655
3774
  "prompt-caching-scope-2026-01-05",
3656
3775
  "redact-thinking-2026-02-12",
3657
3776
  "structured-outputs-2025-12-15",
3777
+ "summarize-connector-text-2026-03-13",
3778
+ "token-efficient-tools-2026-03-28",
3658
3779
  "tool-examples-2025-10-29",
3659
3780
  "tool-search-tool-2025-10-19",
3660
3781
  "web-search-2025-03-05",
@@ -3668,6 +3789,11 @@ const BETA_SHORTCUTS = new Map([
3668
3789
  ["opus-fast", "fast-mode-2026-02-01"],
3669
3790
  ["task-budgets", "task-budgets-2026-03-13"],
3670
3791
  ["budgets", "task-budgets-2026-03-13"],
3792
+ ["efficient-tools", "token-efficient-tools-2026-03-28"],
3793
+ ["token-efficient", "token-efficient-tools-2026-03-28"],
3794
+ ["redact-thinking", "redact-thinking-2026-02-12"],
3795
+ ["connector-text", "summarize-connector-text-2026-03-13"],
3796
+ ["anti-distill", "summarize-connector-text-2026-03-13"],
3671
3797
  ]);
3672
3798
  const STAINLESS_HELPER_KEYS = [
3673
3799
  "x_stainless_helper",
@@ -3883,14 +4009,26 @@ function isAdaptiveThinkingModel(model) {
3883
4009
  }
3884
4010
 
3885
4011
  /**
3886
- * @param {string | undefined} body
4012
+ * Check if a model is eligible for 1M context (can receive context-1m beta).
4013
+ * This includes models with explicit "1m" in the name AND Opus 4.6.
4014
+ * @param {string} model
3887
4015
  * @returns {boolean}
3888
4016
  */
3889
- function hasOneMillionContext(model) {
3890
- // Models with explicit 1m suffix, or Opus 4.6 (1M by default since v2.1.75).
4017
+ function isEligibleFor1MContext(model) {
3891
4018
  return /(^|[-_ ])1m($|[-_ ])|context[-_]?1m/i.test(model) || isOpus46Model(model);
3892
4019
  }
3893
4020
 
4021
+ /**
4022
+ * Check if a model should ALWAYS use 1M context (static mode, no adaptive gating).
4023
+ * Only models with explicit "1m" in the name — NOT bare Opus 4.6.
4024
+ * When adaptive_context is enabled, Opus 4.6 uses the adaptive decision instead.
4025
+ * @param {string} model
4026
+ * @returns {boolean}
4027
+ */
4028
+ function hasOneMillionContext(model) {
4029
+ return /(^|[-_ ])1m($|[-_ ])|context[-_]?1m/i.test(model);
4030
+ }
4031
+
3894
4032
  /**
3895
4033
  * @param {string | undefined} body
3896
4034
  * @returns {boolean}
@@ -4323,6 +4461,7 @@ function buildAnthropicBetaHeader(
4323
4461
  requestPath,
4324
4462
  hasFileReferences,
4325
4463
  adaptiveOverride,
4464
+ tokenEconomy,
4326
4465
  ) {
4327
4466
  const incomingBetasList = incomingBeta
4328
4467
  .split(",")
@@ -4349,13 +4488,23 @@ function buildAnthropicBetaHeader(
4349
4488
  const nonInteractive = isNonInteractiveMode();
4350
4489
  const haiku = isHaikuModel(model);
4351
4490
  const isRoundRobin = strategy === "round-robin";
4491
+ const te = tokenEconomy || {};
4352
4492
 
4353
4493
  // === ALWAYS-ON BETAS (Claude Code v2.1.84 base set) ===
4354
4494
  // These are ALWAYS included regardless of env vars or feature flags.
4355
4495
  if (!haiku) {
4356
4496
  betas.push(CLAUDE_CODE_BETA_FLAG); // "claude-code-20250219"
4357
4497
  }
4358
- betas.push(ADVANCED_TOOL_USE_BETA_FLAG); // "advanced-tool-use-2025-11-20"
4498
+
4499
+ // Tool search: use provider-aware header.
4500
+ // 1P/Foundry → advanced-tool-use-2025-11-20 (enables broader tool capabilities)
4501
+ // Vertex/Bedrock → tool-search-tool-2025-10-19 (3P-compatible subset)
4502
+ if (provider === "vertex" || provider === "bedrock") {
4503
+ betas.push("tool-search-tool-2025-10-19");
4504
+ } else {
4505
+ betas.push(ADVANCED_TOOL_USE_BETA_FLAG); // "advanced-tool-use-2025-11-20"
4506
+ }
4507
+
4359
4508
  betas.push(FAST_MODE_BETA_FLAG); // "fast-mode-2026-02-01"
4360
4509
  betas.push(EFFORT_BETA_FLAG); // "effort-2025-11-24"
4361
4510
 
@@ -4385,8 +4534,14 @@ function buildAnthropicBetaHeader(
4385
4534
  // Context management — always-on in Claude Code (not env-gated)
4386
4535
  betas.push("context-management-2025-06-27");
4387
4536
 
4388
- // Structured outputs — always-on for capable models
4389
- if (supportsStructuredOutputs(model)) {
4537
+ // Structured outputs vs token-efficient-tools: mutually exclusive.
4538
+ // token-efficient-tools gives ~4.5% output token reduction (JSON FC v3).
4539
+ // When both are configured, token-efficient-tools wins (per CC source:
4540
+ // "strict wins" internally, but we prefer token savings for proxy users).
4541
+ if (te.token_efficient_tools && !disableExperimentalBetas) {
4542
+ betas.push("token-efficient-tools-2026-03-28");
4543
+ // Skip structured-outputs — API rejects both together
4544
+ } else if (supportsStructuredOutputs(model)) {
4390
4545
  betas.push("structured-outputs-2025-12-15");
4391
4546
  }
4392
4547
 
@@ -4395,9 +4550,6 @@ function buildAnthropicBetaHeader(
4395
4550
  betas.push("web-search-2025-03-05");
4396
4551
  }
4397
4552
 
4398
- // Tool search tool
4399
- betas.push("tool-search-tool-2025-10-19");
4400
-
4401
4553
  // Files API — scoped to file endpoints/references
4402
4554
  if (isFilesEndpoint || hasFileReferences) {
4403
4555
  betas.push("files-api-2025-04-14");
@@ -4408,10 +4560,20 @@ function buildAnthropicBetaHeader(
4408
4560
  betas.push(TOKEN_COUNTING_BETA_FLAG);
4409
4561
  }
4410
4562
 
4411
- // === OPTIONAL BETAS (env-gated, intentionally NOT always-on) ===
4563
+ // === TOKEN ECONOMY BETAS (config-controlled) ===
4564
+
4565
+ // redact-thinking: suppresses thinking summaries server-side.
4566
+ // When enabled, API returns redacted_thinking blocks instead of summaries.
4567
+ // Saves bandwidth and tokens for users who don't inspect thinking.
4568
+ if (te.redact_thinking && !disableExperimentalBetas) {
4569
+ betas.push("redact-thinking-2026-02-12");
4570
+ }
4412
4571
 
4413
- // redact-thinking — NOT auto-included (users benefit from seeing thinking blocks)
4414
- // Available via: /anthropic betas add redact-thinking-2026-02-12
4572
+ // summarize-connector-text: API summarizes assistant text between tool calls.
4573
+ // Anti-distillation measure — same mechanism as thinking blocks (summary + signature).
4574
+ if (te.connector_text_summarization && !disableExperimentalBetas) {
4575
+ betas.push("summarize-connector-text-2026-03-13");
4576
+ }
4415
4577
 
4416
4578
  // afk-mode — NOT auto-included (requires user opt-in)
4417
4579
  // Available via: /anthropic betas add afk-mode-2026-01-31
@@ -4558,7 +4720,16 @@ async function fetchLatestClaudeCodeVersion(timeoutMs = 1200) {
4558
4720
  * @param {{enabled: boolean, claudeCliVersion: string, strategy?: import('./lib/config.mjs').AccountSelectionStrategy, customBetas?: string[]}} signature
4559
4721
  * @returns {Headers}
4560
4722
  */
4561
- function buildRequestHeaders(input, requestInit, accessToken, requestBody, requestUrl, signature, adaptiveOverride) {
4723
+ function buildRequestHeaders(
4724
+ input,
4725
+ requestInit,
4726
+ accessToken,
4727
+ requestBody,
4728
+ requestUrl,
4729
+ signature,
4730
+ adaptiveOverride,
4731
+ tokenEconomy,
4732
+ ) {
4562
4733
  const requestHeaders = new Headers();
4563
4734
  if (input instanceof Request) {
4564
4735
  input.headers.forEach((value, key) => {
@@ -4599,6 +4770,7 @@ function buildRequestHeaders(input, requestInit, accessToken, requestBody, reque
4599
4770
  requestUrl?.pathname,
4600
4771
  hasFileReferences,
4601
4772
  adaptiveOverride,
4773
+ tokenEconomy,
4602
4774
  );
4603
4775
 
4604
4776
  const authTokenOverride = process.env.ANTHROPIC_AUTH_TOKEN?.trim();
@@ -4752,7 +4924,15 @@ function transformRequestBody(body, signature, runtime, betaHeader) {
4752
4924
  // Cache breakpoint optimization: add cache_control to the last content block
4753
4925
  // of each user/assistant message for maximum prefix caching.
4754
4926
  // Skip for round-robin strategy (cache defeated by account rotation).
4755
- if (signature.enabled && signature.cachePolicy?.ttl !== "off" && signature.cachePolicy?.ttl_supported !== false) {
4927
+ // Skip for title generators / fire-and-forget queries: these are one-shot
4928
+ // requests that don't benefit from caching and would pollute the cache pool.
4929
+ const isTitleGen = isTitleGeneratorSystemBlocks(parsed.system || []);
4930
+ if (
4931
+ signature.enabled &&
4932
+ signature.cachePolicy?.ttl !== "off" &&
4933
+ signature.cachePolicy?.ttl_supported !== false &&
4934
+ !isTitleGen
4935
+ ) {
4756
4936
  const strategy = signature.strategy || "sticky";
4757
4937
  if (strategy !== "round-robin" && Array.isArray(parsed.messages)) {
4758
4938
  const cacheControl = { type: "ephemeral", ttl: signature.cachePolicy?.ttl || "1h" };
package/lib/config.mjs CHANGED
@@ -166,6 +166,19 @@ export const DEFAULT_CONFIG = {
166
166
  * (no point suggesting reset at the start of a session). */
167
167
  min_turns_before_suggest: 3,
168
168
  },
169
+ /** Token economy optimizations. */
170
+ token_economy: {
171
+ /** Enable token-efficient-tools-2026-03-28 beta (~4.5% output token reduction).
172
+ * Mutually exclusive with structured-outputs — this flag takes precedence. */
173
+ token_efficient_tools: true,
174
+ /** Enable redact-thinking-2026-02-12 beta (suppresses thinking summaries
175
+ * server-side for lower bandwidth). Off by default — set to true if you
176
+ * don't need to inspect thinking blocks. */
177
+ redact_thinking: false,
178
+ /** Enable summarize-connector-text-2026-03-13 beta (API summarizes assistant
179
+ * text between tool calls — anti-distillation measure). */
180
+ connector_text_summarization: true,
181
+ },
169
182
  };
170
183
 
171
184
  export const VALID_STRATEGIES = ["sticky", "round-robin", "hybrid"];
@@ -194,6 +207,7 @@ function createDefaultConfig() {
194
207
  cc_credential_reuse: { ...DEFAULT_CONFIG.cc_credential_reuse },
195
208
  adaptive_context: { ...DEFAULT_CONFIG.adaptive_context },
196
209
  willow_mode: { ...DEFAULT_CONFIG.willow_mode },
210
+ token_economy: { ...DEFAULT_CONFIG.token_economy },
197
211
  };
198
212
  }
199
213
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "opencode-anthropic-fix",
3
- "version": "0.0.36",
3
+ "version": "0.0.38",
4
4
  "license": "GPL-3.0-or-later",
5
5
  "main": "./index.mjs",
6
6
  "files": [