@cortexkit/pi-anthropic-auth 2.4.10 → 2.4.12
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/dist/native.d.ts +3 -0
- package/dist/native.js +19 -2
- package/dist/stream.d.ts +18 -2
- package/dist/stream.js +21 -10
- package/package.json +2 -2
package/dist/native.d.ts
CHANGED
|
@@ -27,6 +27,9 @@ export interface PiVaultPollOptions {
|
|
|
27
27
|
clearInterval?: typeof globalThis.clearInterval;
|
|
28
28
|
}
|
|
29
29
|
export declare class PiNativeRuntime {
|
|
30
|
+
private readonly pendingReports;
|
|
31
|
+
/** Join started failure reports, never model sends waiting for headers. */
|
|
32
|
+
drainReports(): Promise<void>;
|
|
30
33
|
private readonly paths;
|
|
31
34
|
private readonly holderRegistration;
|
|
32
35
|
private readonly initialization;
|
package/dist/native.js
CHANGED
|
@@ -71,6 +71,12 @@ export function isNativeMigrationRequired(error) {
|
|
|
71
71
|
/** How often Pi asks the vault for account changes, matching OpenCode's default. Model requests no longer rediscover a healthy roster, so this poll is how Pi notices a re-login or a newly added account. */
|
|
72
72
|
export const PI_VAULT_POLL_INTERVAL_MS = 2000;
|
|
73
73
|
export class PiNativeRuntime {
|
|
74
|
+
pendingReports = new Set();
|
|
75
|
+
/** Join started failure reports, never model sends waiting for headers. */
|
|
76
|
+
async drainReports() {
|
|
77
|
+
while (this.pendingReports.size)
|
|
78
|
+
await Promise.allSettled([...this.pendingReports]);
|
|
79
|
+
}
|
|
74
80
|
paths;
|
|
75
81
|
holderRegistration;
|
|
76
82
|
initialization;
|
|
@@ -328,8 +334,18 @@ export class PiNativeRuntime {
|
|
|
328
334
|
};
|
|
329
335
|
}
|
|
330
336
|
async report(served, status, source) {
|
|
331
|
-
if (served.source === 'vault' && status === 401)
|
|
332
|
-
|
|
337
|
+
if (served.source === 'vault' && status === 401) {
|
|
338
|
+
// An already-served receipt can be reported while shutdown drains it.
|
|
339
|
+
// Do not re-enter service admission after close has blocked new sends.
|
|
340
|
+
const pending = this.initialization.then((runtime) => runtime.vault.reportFailure(served.receipt, status, source));
|
|
341
|
+
this.pendingReports.add(pending);
|
|
342
|
+
try {
|
|
343
|
+
await pending;
|
|
344
|
+
}
|
|
345
|
+
finally {
|
|
346
|
+
this.pendingReports.delete(pending);
|
|
347
|
+
}
|
|
348
|
+
}
|
|
333
349
|
}
|
|
334
350
|
async markUsed(served, servingRuntime) {
|
|
335
351
|
const runtime = servingRuntime ?? (await this.service());
|
|
@@ -350,6 +366,7 @@ export class PiNativeRuntime {
|
|
|
350
366
|
await this.initialization.then(async (runtime) => {
|
|
351
367
|
await runtime.drainQuotaPublications();
|
|
352
368
|
await runtime.drainRoutingPublications();
|
|
369
|
+
await this.drainReports();
|
|
353
370
|
await runtime.close();
|
|
354
371
|
}, () => { });
|
|
355
372
|
})();
|
package/dist/stream.d.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import { type ApiKeyAccount, CacheKeepManager, type MidConversationEffortTransition, type QuotaManagerOptions } from '@cortexkit/anthropic-auth-core';
|
|
2
|
-
import { type Api, type AssistantMessageEventStream, type Context, type Model, type SimpleStreamOptions } from '@earendil-works/pi-ai';
|
|
1
|
+
import { type ApiKeyAccount, CacheKeepManager, type MidConversationEffortTransition, type NativeAccountView, type QuotaManagerOptions } from '@cortexkit/anthropic-auth-core';
|
|
2
|
+
import { type Api, type AssistantMessageEventStream, type Context, type Model, type SimpleStreamOptions, type Tool } from '@earendil-works/pi-ai';
|
|
3
3
|
/** Set or clear the test replacement for the wait between quota usage polls. */
|
|
4
4
|
export declare function __setPiQuotaCallPauseForTest(pause: QuotaManagerOptions['pauseBetweenQuotaCalls']): void;
|
|
5
5
|
export declare function clearPiStickyRoutingSession(storagePath: string, sessionId: string): Promise<void>;
|
|
@@ -20,6 +20,22 @@ type AnthropicEvent = {
|
|
|
20
20
|
export declare function buildExplicitBaseMessagesUrl(baseURL: string): URL;
|
|
21
21
|
export declare function configureApiRouteHeaders(account: ApiKeyAccount, fastMode: boolean): Headers;
|
|
22
22
|
export declare function parseSse(response: Response): AsyncGenerator<AnthropicEvent>;
|
|
23
|
+
declare function sendAnthropicRequest(options: {
|
|
24
|
+
model: Model<Api>;
|
|
25
|
+
context: Context;
|
|
26
|
+
streamOptions?: SimpleStreamOptions;
|
|
27
|
+
apiAccount?: NativeAccountView;
|
|
28
|
+
storagePath: string;
|
|
29
|
+
oauthAccountId?: string;
|
|
30
|
+
route?: string;
|
|
31
|
+
effortTransitions?: readonly MidConversationEffortTransition[];
|
|
32
|
+
onResolvedTools?: (tools: Tool[]) => void;
|
|
33
|
+
}, deps?: {
|
|
34
|
+
fetch?: typeof fetch;
|
|
35
|
+
cacheKeep?: CacheKeepManager;
|
|
36
|
+
}): Promise<Response>;
|
|
37
|
+
/** Exercise one native send with isolated transport and scheduling in tests. */
|
|
38
|
+
export declare const __sendPiAnthropicRequestForTest: typeof sendAnthropicRequest;
|
|
23
39
|
export declare function primaryResponseAllowsApiFallback(preflight: Response | string): boolean;
|
|
24
40
|
/**
|
|
25
41
|
* Classify a successful stream by its first event without a tee: the bytes
|
package/dist/stream.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { applyClaudeCodeHeaders, applyCustomHeaders, CACHE_KEEP_EXTENDED_TTL_BETA, CacheKeepManager, CacheKeepSessionRegistry, createNativeVaultNoRouteResponse, 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, NativeAccountRefusal, nativeAccountCanServe, parseSseFrame, QuotaManager, quotaBackoffActive, quotaExhaustionFromHeaders, quotaSnapshotHasStandardWindows, quotaSnapshotModelScopeIsExhausted, quotaSnapshotPassesModelScope, quotaSnapshotPassesPolicy, STICKY_ROUTING_MAIN_ACCOUNT_ID, StickySessionRouter, sendViaRelay, sendWithRequestGzip, setDumpEnabled, shouldFallbackStatus, stickyQuotaSnapshotIsFresh, stickyRetryAfterWithJitter, stickyRouteFamilyForModel, } from '@cortexkit/anthropic-auth-core';
|
|
1
|
+
import { applyClaudeCodeHeaders, applyCustomHeaders, CACHE_KEEP_EXTENDED_TTL_BETA, CacheKeepManager, CacheKeepSessionRegistry, createNativeVaultNoRouteResponse, 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, NativeAccountRefusal, nativeAccountCanServe, parseSseFrame, QuotaManager, quotaBackoffActive, quotaExhaustionFromHeaders, quotaSnapshotHasStandardWindows, quotaSnapshotModelScopeIsExhausted, quotaSnapshotPassesModelScope, quotaSnapshotPassesPolicy, runWithRequestSignal, 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';
|
|
@@ -335,7 +335,9 @@ export async function* parseSse(response) {
|
|
|
335
335
|
reader.releaseLock();
|
|
336
336
|
}
|
|
337
337
|
}
|
|
338
|
-
async function sendAnthropicRequest(options) {
|
|
338
|
+
async function sendAnthropicRequest(options, deps = {}) {
|
|
339
|
+
const fetchImpl = deps.fetch ?? globalThis.fetch;
|
|
340
|
+
const keep = deps.cacheKeep ?? cacheKeepManager;
|
|
339
341
|
const native = getPiNativeRuntime(options.storagePath);
|
|
340
342
|
// Capture the serving service while authorization is open. Shutdown rejects
|
|
341
343
|
// new serving work immediately but drains writes for already-served attempts.
|
|
@@ -385,8 +387,10 @@ async function sendAnthropicRequest(options) {
|
|
|
385
387
|
signal: options.streamOptions?.signal,
|
|
386
388
|
...(!options.apiAccount && { redirect: 'error' }),
|
|
387
389
|
};
|
|
388
|
-
|
|
389
|
-
|
|
390
|
+
const trackAcceptedRequest = () => {
|
|
391
|
+
if (options.apiAccount || init.signal?.aborted)
|
|
392
|
+
return;
|
|
393
|
+
keep.track({
|
|
390
394
|
sessionId: relayAffinity,
|
|
391
395
|
url: input.toString(),
|
|
392
396
|
headers,
|
|
@@ -397,6 +401,7 @@ async function sendAnthropicRequest(options) {
|
|
|
397
401
|
oauthAccountIdentity: verifiedUuid,
|
|
398
402
|
accountStoragePath: options.storagePath,
|
|
399
403
|
});
|
|
404
|
+
};
|
|
400
405
|
const reported = new Set();
|
|
401
406
|
let retried401 = false;
|
|
402
407
|
let lastTransport;
|
|
@@ -455,13 +460,13 @@ async function sendAnthropicRequest(options) {
|
|
|
455
460
|
// OAuth bodies go gzipped as Claude Code sends them; `bodyText` stays
|
|
456
461
|
// the signed identity text for dumps and CacheKeep.
|
|
457
462
|
if (options.apiAccount || typeof init.body !== 'string')
|
|
458
|
-
return scope.redactResponse(await
|
|
463
|
+
return scope.redactResponse(await fetchImpl(input, init));
|
|
459
464
|
return scope.redactResponse(await sendWithRequestGzip({
|
|
460
465
|
url: input,
|
|
461
466
|
body: init.body,
|
|
462
467
|
headers,
|
|
463
468
|
latch: getRequestGzipLatch(getRequestGzipLatchPath(options.storagePath)),
|
|
464
|
-
send: (wireBody, wireHeaders) =>
|
|
469
|
+
send: (wireBody, wireHeaders) => fetchImpl(input, { ...init, body: wireBody, headers: wireHeaders }),
|
|
465
470
|
}));
|
|
466
471
|
};
|
|
467
472
|
let response;
|
|
@@ -537,8 +542,10 @@ async function sendAnthropicRequest(options) {
|
|
|
537
542
|
const subject = apiSubject;
|
|
538
543
|
native.usagePublications.publish(() => servingRuntime.publishApi(subject, { lastUsed: Date.now() }));
|
|
539
544
|
}
|
|
540
|
-
if (attempt && response.ok)
|
|
545
|
+
if (attempt && response.ok) {
|
|
546
|
+
trackAcceptedRequest();
|
|
541
547
|
markServed(attempt);
|
|
548
|
+
}
|
|
542
549
|
return response;
|
|
543
550
|
};
|
|
544
551
|
if (options.apiAccount)
|
|
@@ -601,10 +608,14 @@ async function sendAnthropicRequest(options) {
|
|
|
601
608
|
// If the request was cancelled since, end it as cancelled here.
|
|
602
609
|
if (relay401Attempt && response.status === 401)
|
|
603
610
|
await endIfCancelled(response, init.signal);
|
|
604
|
-
if (response.ok && lastTransport === 'relay' && relayAttempt)
|
|
611
|
+
if (response.ok && lastTransport === 'relay' && relayAttempt) {
|
|
612
|
+
trackAcceptedRequest();
|
|
605
613
|
markServed(relayAttempt);
|
|
614
|
+
}
|
|
606
615
|
return response;
|
|
607
616
|
}
|
|
617
|
+
/** Exercise one native send with isolated transport and scheduling in tests. */
|
|
618
|
+
export const __sendPiAnthropicRequestForTest = sendAnthropicRequest;
|
|
608
619
|
/**
|
|
609
620
|
* If the request's signal is aborted, cancels the response body and throws the
|
|
610
621
|
* signal's abort error; otherwise does nothing. Call it before a rejected
|
|
@@ -1242,7 +1253,7 @@ export function streamCortexKitAnthropic(model, context, options, effortTransiti
|
|
|
1242
1253
|
buildPiOAuthMessagesUrl(model.baseUrl);
|
|
1243
1254
|
const storagePath = getPiAccountStoragePath();
|
|
1244
1255
|
let hostTools = [];
|
|
1245
|
-
const response = await executeWithFallback({
|
|
1256
|
+
const response = await runWithRequestSignal(options?.signal, () => executeWithFallback({
|
|
1246
1257
|
model,
|
|
1247
1258
|
context,
|
|
1248
1259
|
streamOptions: options,
|
|
@@ -1251,7 +1262,7 @@ export function streamCortexKitAnthropic(model, context, options, effortTransiti
|
|
|
1251
1262
|
onResolvedTools: (tools) => {
|
|
1252
1263
|
hostTools = tools;
|
|
1253
1264
|
},
|
|
1254
|
-
});
|
|
1265
|
+
}));
|
|
1255
1266
|
if (!response.ok) {
|
|
1256
1267
|
throw new Error(`Anthropic request failed: HTTP ${response.status} ${await response.text()}`);
|
|
1257
1268
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@cortexkit/pi-anthropic-auth",
|
|
3
|
-
"version": "2.4.
|
|
3
|
+
"version": "2.4.12",
|
|
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.4.
|
|
39
|
+
"@cortexkit/anthropic-auth-core": "2.4.12"
|
|
40
40
|
},
|
|
41
41
|
"peerDependencies": {
|
|
42
42
|
"@earendil-works/pi-ai": ">=0.86.1 <2",
|