@cortexkit/pi-anthropic-auth 2.0.3 → 2.1.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/README.md CHANGED
@@ -16,7 +16,7 @@ This project is not affiliated with or endorsed by Anthropic. Using Claude subsc
16
16
  ## Install
17
17
 
18
18
  ```bash
19
- bunx @cortexkit/opencode-anthropic-auth setup
19
+ npx @cortexkit/opencode-anthropic-auth setup
20
20
  ```
21
21
 
22
22
  After setup:
package/dist/custody.js CHANGED
@@ -26,7 +26,7 @@ export function createPiCustodyCommands() {
26
26
  // Mode changes can remove host credentials and require offline consent.
27
27
  // A menu never enrolls, grants custody or writes the authority journal.
28
28
  return {
29
- text: `Refused: Changing Pi authentication to ${mode} requires offline setup. Run \`bunx @cortexkit/opencode-anthropic-auth setup\` and review the migration and host OAuth removal consent.`,
29
+ text: `Refused: Changing Pi authentication to ${mode} requires offline setup. Run \`npx @cortexkit/opencode-anthropic-auth setup\` and review the migration and host OAuth removal consent.`,
30
30
  };
31
31
  },
32
32
  };
package/dist/stream.d.ts CHANGED
@@ -1,5 +1,7 @@
1
- import { type ApiKeyAccount, CacheKeepManager, type MidConversationEffortTransition } from '@cortexkit/anthropic-auth-core';
1
+ import { type ApiKeyAccount, CacheKeepManager, type MidConversationEffortTransition, type QuotaManagerOptions } from '@cortexkit/anthropic-auth-core';
2
2
  import { type Api, type AssistantMessageEventStream, type Context, type Model, type SimpleStreamOptions } from '@earendil-works/pi-ai';
3
+ /** Set or clear the test replacement for the wait between quota usage polls. */
4
+ export declare function __setPiQuotaCallPauseForTest(pause: QuotaManagerOptions['pauseBetweenQuotaCalls']): void;
3
5
  export declare function clearPiStickyRoutingSession(storagePath: string, sessionId: string): Promise<void>;
4
6
  export declare function getPiTrackedCacheKeepSessions(): Promise<import("@cortexkit/anthropic-auth-core").CacheKeepTrackedSession[]>;
5
7
  /** Call prewarmNow directly to exercise its provider request without clock or timer mocks. */
package/dist/stream.js CHANGED
@@ -1,4 +1,4 @@
1
- import { applyClaudeCodeHeaders, applyCustomHeaders, CACHE_KEEP_EXTENDED_TTL_BETA, CacheKeepManager, CacheKeepSessionRegistry, createProviderErrorResponseScope, createSseFramer, createStickyNoRouteResponse, decideStickyQuotaFailure, decodeSseFrame, dumpDirectRequest, FAST_MODE_BETA, getCache1hPersistentMode, getClaudeCodeIdentityForVerifiedAccount, getDefaultCacheKeepRegistryDirectory, getFallbackReauthLabels, getQuotaCheckIntervalMs, getRoutingMode, getScopedQuotaWindowForModel, getThinkingPrefixMismatchBehavior, hasThinkingBindingControls, isCache1hPersistentlyEnabled, isCacheKeepHybridActive, isDumpPersistentlyEnabled, isFastModePersistentlyEnabled, isKillswitchEnabled, isNativeTransientAccountError, isOAuthAccount, isPermanentRefreshError, isValidApiBaseURL, killswitchPassesPolicy, logger, MID_CONVERSATION_OUTPUT_CONFIG_BETA, mergeAnthropicBetas, NativeVaultNoAccountError, nativeAccountCanServe, parseSseFrame, QuotaManager, quotaBackoffActive, quotaSnapshotHasStandardWindows, quotaSnapshotModelScopeIsExhausted, quotaSnapshotPassesModelScope, quotaSnapshotPassesPolicy, STICKY_ROUTING_MAIN_ACCOUNT_ID, StickySessionRouter, sendViaRelay, setDumpEnabled, shouldFallbackStatus, stickyQuotaSnapshotIsFresh, stickyRetryAfterWithJitter, stickyRouteFamilyForModel, THINKING_BINDING_CONTROLS_BETA, usesMidConversationOutputConfig, } from '@cortexkit/anthropic-auth-core';
1
+ import { applyClaudeCodeHeaders, applyCustomHeaders, CACHE_KEEP_EXTENDED_TTL_BETA, CacheKeepManager, CacheKeepSessionRegistry, createProviderErrorResponseScope, createSseFramer, createStickyNoRouteResponse, decideStickyQuotaFailure, decodeSseFrame, dumpDirectRequest, FAST_MODE_BETA, getCache1hPersistentMode, getClaudeCodeIdentityForVerifiedAccount, getDefaultCacheKeepRegistryDirectory, getFallbackReauthLabels, getQuotaCheckIntervalMs, getRequestGzipLatch, getRequestGzipLatchPath, getRoutingMode, getScopedQuotaWindowForModel, getThinkingPrefixMismatchBehavior, isCache1hPersistentlyEnabled, isCacheKeepHybridActive, isDumpPersistentlyEnabled, isFastModePersistentlyEnabled, isKillswitchEnabled, isNativeTransientAccountError, isOAuthAccount, isPermanentRefreshError, isValidApiBaseURL, killswitchPassesPolicy, logger, mergeAnthropicBetas, NativeVaultNoAccountError, nativeAccountCanServe, parseSseFrame, QuotaManager, quotaBackoffActive, quotaSnapshotHasStandardWindows, quotaSnapshotModelScopeIsExhausted, quotaSnapshotPassesModelScope, quotaSnapshotPassesPolicy, STICKY_ROUTING_MAIN_ACCOUNT_ID, StickySessionRouter, sendViaRelay, sendWithRequestGzip, setDumpEnabled, shouldFallbackStatus, stickyQuotaSnapshotIsFresh, stickyRetryAfterWithJitter, stickyRouteFamilyForModel, } from '@cortexkit/anthropic-auth-core';
2
2
  import { calculateCost, createAssistantMessageEventStream, } from '@earendil-works/pi-ai';
3
3
  import { buildAnthropicRequest, fromClaudeCodeToolName } from './convert.js';
4
4
  import { getPiNativeRuntime, piAttemptAccessToken, } from './native.js';
@@ -11,6 +11,15 @@ let cacheKeepRegistryDirectory;
11
11
  const stickyRouters = new Map();
12
12
  const quotaManagers = new Map();
13
13
  const PI_SERVICE_CACHE_LIMIT = 16;
14
+ /**
15
+ * Tests only: replaces the real-time wait between quota usage polls in quota
16
+ * managers created after it is set. Unset, managers keep Core's real timer.
17
+ */
18
+ let quotaCallPauseForTest;
19
+ /** Set or clear the test replacement for the wait between quota usage polls. */
20
+ export function __setPiQuotaCallPauseForTest(pause) {
21
+ quotaCallPauseForTest = pause;
22
+ }
14
23
  function setBoundedService(map, key, value) {
15
24
  map.delete(key);
16
25
  map.set(key, value);
@@ -37,11 +46,12 @@ function getPiRoutingServices(storagePath, snapshot) {
37
46
  if (!quotaManager) {
38
47
  quotaManager = new QuotaManager({
39
48
  storage,
49
+ pauseBetweenQuotaCalls: quotaCallPauseForTest,
40
50
  fetchQuotaSnapshot: async (request, dispatch) => {
41
51
  const id = request.kind === 'main' ? 'main' : request.accountId;
42
52
  if (!id)
43
53
  throw new Error('Native quota request has no account identity');
44
- return (await native.service()).fetchQuota(id, fetchPiOAuth, undefined, dispatch);
54
+ return (await native.service()).fetchQuota(id, fetchPiOAuth, undefined, dispatch, request.purpose);
45
55
  },
46
56
  });
47
57
  setBoundedService(quotaManagers, storagePath, {
@@ -74,7 +84,7 @@ function getPiRoutingServices(storagePath, snapshot) {
74
84
  quotas.isFallbackStale(account.id, undefined, options.modelId, account) &&
75
85
  !quotaBackoffActive(account.lastQuotaRefreshError, Date.now())) {
76
86
  try {
77
- await quotas.refreshFallback(account.id, '', account);
87
+ await quotas.refreshFallback(account.id, '', account, 'admission');
78
88
  }
79
89
  catch (error) {
80
90
  // A transient account error means another writer is still saving
@@ -122,23 +132,15 @@ function getPiCacheKeepRegistry() {
122
132
  * betas this body needs. Model requests and CacheKeep prewarms both call it:
123
133
  * a prewarm replays a model request's body, and Anthropic needs the same
124
134
  * betas to accept it (for example, the effort beta for the empty
125
- * `role: "system"` effort markers in a Fable 5.1 body). `leadingBetas` are
126
- * placed before the body's betas.
135
+ * `role: "system"` effort markers in a Fable 5.1 body). `leadingBetas` appends
136
+ * adapter-requested feature betas without changing Core's model-beta selection.
127
137
  */
128
138
  function applyPiOAuthRequestHeaders(headers, accessToken, options) {
129
139
  const { body } = options;
130
140
  applyClaudeCodeHeaders(headers, accessToken, {
131
141
  body,
132
142
  identity: options.identity,
133
- extraBetas: [
134
- ...(options.leadingBetas ?? []),
135
- ...(hasThinkingBindingControls(body)
136
- ? [THINKING_BINDING_CONTROLS_BETA]
137
- : []),
138
- ...(usesMidConversationOutputConfig(body)
139
- ? [MID_CONVERSATION_OUTPUT_CONFIG_BETA]
140
- : []),
141
- ],
143
+ extraBetas: options.leadingBetas,
142
144
  });
143
145
  if (body.speed === 'fast')
144
146
  headers.set('anthropic-beta', mergeAnthropicBetas(headers.get('anthropic-beta'), [FAST_MODE_BETA]));
@@ -442,7 +444,17 @@ async function sendAnthropicRequest(options) {
442
444
  const send = async () => {
443
445
  const scope = createProviderErrorResponseScope([secret], 'event-stream');
444
446
  physical.scope = scope;
445
- return scope.redactResponse(await fetch(input, init));
447
+ // OAuth bodies go gzipped as Claude Code sends them; `bodyText` stays
448
+ // the signed identity text for dumps and CacheKeep.
449
+ if (options.apiAccount || typeof init.body !== 'string')
450
+ return scope.redactResponse(await fetch(input, init));
451
+ return scope.redactResponse(await sendWithRequestGzip({
452
+ url: input,
453
+ body: init.body,
454
+ headers,
455
+ latch: getRequestGzipLatch(getRequestGzipLatchPath(options.storagePath)),
456
+ send: (wireBody, wireHeaders) => fetch(input, { ...init, body: wireBody, headers: wireHeaders }),
457
+ }));
446
458
  };
447
459
  let response;
448
460
  try {
@@ -778,7 +790,7 @@ async function executeWithFallback(options) {
778
790
  if (primaryAvailable() &&
779
791
  !stickyQuotaSnapshotIsFresh(mainEntry?.quota, storage, Date.now(), modelId)) {
780
792
  try {
781
- mainQuota = await quotaManager.refreshMain(mainAccountId, '');
793
+ mainQuota = await quotaManager.refreshMain(mainAccountId, '', undefined, 'admission');
782
794
  }
783
795
  catch { }
784
796
  }
@@ -803,7 +815,7 @@ async function executeWithFallback(options) {
803
815
  let accountQuota = quotaManager.getFallback(account.id, account)?.quota ?? account.quota;
804
816
  if (!stickyQuotaSnapshotIsFresh(accountQuota, storage, Date.now(), modelId)) {
805
817
  try {
806
- accountQuota = await quotaManager.refreshFallback(account.id, '', account);
818
+ accountQuota = await quotaManager.refreshFallback(account.id, '', account, 'admission');
807
819
  }
808
820
  catch { }
809
821
  }
@@ -1150,7 +1162,7 @@ async function executeWithFallback(options) {
1150
1162
  let mainQuota = quotaManager.getMain(mainAccountId)?.quota;
1151
1163
  if (!mainQuota || quotaManager.isMainStale(options.model.id)) {
1152
1164
  try {
1153
- mainQuota = await quotaManager.refreshMain(mainAccountId, '');
1165
+ mainQuota = await quotaManager.refreshMain(mainAccountId, '', undefined, 'admission');
1154
1166
  }
1155
1167
  catch { }
1156
1168
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@cortexkit/pi-anthropic-auth",
3
- "version": "2.0.3",
3
+ "version": "2.1.0",
4
4
  "type": "module",
5
5
  "repository": {
6
6
  "type": "git",
@@ -36,7 +36,7 @@
36
36
  "prepublishOnly": "bun run build"
37
37
  },
38
38
  "dependencies": {
39
- "@cortexkit/anthropic-auth-core": "2.0.3"
39
+ "@cortexkit/anthropic-auth-core": "2.1.0"
40
40
  },
41
41
  "peerDependencies": {
42
42
  "@earendil-works/pi-ai": ">=0.86.1 <2",