@askalf/dario 2.4.2 → 2.5.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.
Files changed (2) hide show
  1. package/dist/proxy.js +35 -13
  2. package/package.json +1 -1
package/dist/proxy.js CHANGED
@@ -90,12 +90,12 @@ const MODEL_ALIASES = {
90
90
  'sonnet1m': 'claude-sonnet-4-6[1m]',
91
91
  'haiku': 'claude-haiku-4-5',
92
92
  };
93
- // Beta prefixes that trigger Extra Usage billing on Max subscriptions.
94
- // Stripping these prevents surprise charges while keeping caching/thinking/1M active.
93
+ // Beta prefixes that require Extra Usage to be ENABLED on the account.
94
+ // context-management and prompt-caching-scope are safe billing is determined
95
+ // solely by the OAuth token's subscription type, not by beta flags.
96
+ // Only extended-cache-ttl actually requires Extra Usage availability.
95
97
  const BILLABLE_BETA_PREFIXES = [
96
- 'extended-cache-ttl-', // Extended cache TTLs beyond default
97
- 'context-management-', // Auto-compaction / context management
98
- 'prompt-caching-scope-', // Extended prompt caching scope
98
+ 'extended-cache-ttl-', // Extended cache TTLs requires Extra Usage enabled
99
99
  ];
100
100
  /** Filter out billable betas from client-provided beta header. */
101
101
  function filterBillableBetas(betas) {
@@ -553,9 +553,10 @@ export async function startProxy(opts = {}) {
553
553
  parsed.model = modelOverride.replace('[1m]', '');
554
554
  }
555
555
  const result = isOpenAI ? openaiToAnthropic(parsed, modelOverride) : (modelOverride ? { ...parsed, model: modelOverride } : parsed);
556
- // Inject device identity metadata — required for Max plan billing classification
557
- if (identity.deviceId && typeof result === 'object' && result !== null) {
558
- result.metadata = {
556
+ const r = result;
557
+ // Inject device identity metadata for session tracking
558
+ if (identity.deviceId) {
559
+ r.metadata = {
559
560
  user_id: JSON.stringify({
560
561
  device_id: identity.deviceId,
561
562
  account_uuid: identity.accountUuid,
@@ -563,7 +564,19 @@ export async function startProxy(opts = {}) {
563
564
  }),
564
565
  };
565
566
  }
566
- finalBody = Buffer.from(JSON.stringify(result));
567
+ // Enable extended thinking (matches Claude Code default)
568
+ // budget_tokens must be >= 1024, and max_tokens must accommodate it
569
+ if (!r.thinking) {
570
+ const clientMax = r.max_tokens || 8192;
571
+ const maxTokens = Math.max(clientMax, 16000);
572
+ r.max_tokens = maxTokens;
573
+ r.thinking = { budget_tokens: maxTokens - 1, type: 'enabled' };
574
+ }
575
+ // Enable context management (matches Claude Code default)
576
+ if (!r.context_management) {
577
+ r.context_management = { edits: [{ type: 'clear_thinking_20251015', keep: 'all' }] };
578
+ }
579
+ finalBody = Buffer.from(JSON.stringify(r));
567
580
  }
568
581
  catch { /* not JSON, send as-is */ }
569
582
  }
@@ -571,11 +584,11 @@ export async function startProxy(opts = {}) {
571
584
  const modelInfo = modelOverride ? ` (model: ${modelOverride})` : '';
572
585
  console.log(`[dario] #${requestCount} ${req.method} ${urlPath}${modelInfo}`);
573
586
  }
574
- // Conservative beta defaults — only betas confirmed safe for Max plans.
575
- // context-management and prompt-caching-scope stripped: even with metadata.user_id,
576
- // these may independently trigger Extra Usage billing (reported by @belangertrading).
587
+ // Beta defaults — matches native Claude Code v2.1.98 headers exactly.
588
+ // Billing classification is determined by the OAuth token alone, not beta flags.
589
+ // context-management and prompt-caching-scope are safe for all subscription types.
577
590
  const clientBeta = req.headers['anthropic-beta'];
578
- let beta = 'oauth-2025-04-20,interleaved-thinking-2025-05-14,claude-code-20250219,advisor-tool-2026-03-01';
591
+ let beta = 'oauth-2025-04-20,interleaved-thinking-2025-05-14,context-management-2025-06-27,prompt-caching-scope-2026-01-05,claude-code-20250219,advisor-tool-2026-03-01';
579
592
  if (clientBeta) {
580
593
  const filtered = filterBillableBetas(clientBeta);
581
594
  if (filtered)
@@ -610,6 +623,15 @@ export async function startProxy(opts = {}) {
610
623
  }
611
624
  }
612
625
  requestCount++;
626
+ // Log billing classification on first request or in verbose mode
627
+ const billingClaim = upstream.headers.get('anthropic-ratelimit-unified-representative-claim');
628
+ const overageUtil = upstream.headers.get('anthropic-ratelimit-unified-overage-utilization');
629
+ if (requestCount === 1 || verbose) {
630
+ if (billingClaim) {
631
+ const overagePct = overageUtil ? `${Math.round(parseFloat(overageUtil) * 100)}%` : '?';
632
+ console.log(`[dario] #${requestCount} billing: ${billingClaim} (overage: ${overagePct})`);
633
+ }
634
+ }
613
635
  res.writeHead(upstream.status, responseHeaders);
614
636
  if (isStream && upstream.body) {
615
637
  // Stream SSE chunks through
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@askalf/dario",
3
- "version": "2.4.2",
3
+ "version": "2.5.0",
4
4
  "description": "Use your Claude subscription as an API. No API key needed. Local proxy for Claude Max/Pro subscriptions.",
5
5
  "type": "module",
6
6
  "bin": {