@cortexkit/pi-anthropic-auth 1.20.0 → 1.21.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/dist/convert.js +55 -21
- package/dist/stream.js +121 -27
- package/package.json +2 -2
package/dist/convert.js
CHANGED
|
@@ -3,6 +3,10 @@ import { applyClaudeCodeMetadata, buildBillingHeaderValue, CLAUDE_CODE_ENTRYPOIN
|
|
|
3
3
|
// that Anthropic currently rejects in system[]. Unknown prompt shapes take the
|
|
4
4
|
// service-preserving fallback below instead of returning the full prompt there.
|
|
5
5
|
const PI_DOCS_ANCHOR = 'Pi documentation';
|
|
6
|
+
const ANTHROPIC_REPLAY_APIS = new Set([
|
|
7
|
+
'anthropic-messages',
|
|
8
|
+
'cortexkit-anthropic-messages',
|
|
9
|
+
]);
|
|
6
10
|
const CLAUDE_CODE_TOOLS = new Map([
|
|
7
11
|
'Read',
|
|
8
12
|
'Write',
|
|
@@ -105,7 +109,7 @@ function convertTextAndImages(content) {
|
|
|
105
109
|
}
|
|
106
110
|
return blocks;
|
|
107
111
|
}
|
|
108
|
-
function convertMessages(messages) {
|
|
112
|
+
function convertMessages(messages, targetModelId) {
|
|
109
113
|
const result = [];
|
|
110
114
|
for (let index = 0; index < messages.length; index++) {
|
|
111
115
|
const message = messages[index];
|
|
@@ -140,33 +144,63 @@ function convertMessages(messages) {
|
|
|
140
144
|
if (block.type === 'text' && block.text.trim()) {
|
|
141
145
|
blocks.push({ type: 'text', text: sanitize(block.text) });
|
|
142
146
|
}
|
|
143
|
-
else if (block.type === 'thinking'
|
|
147
|
+
else if (block.type === 'thinking') {
|
|
144
148
|
const thinking = block;
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
+
const signature = thinking.thinkingSignature;
|
|
150
|
+
const hasSignature = typeof signature === 'string' && signature.trim().length > 0;
|
|
151
|
+
const signatureBelongsToTarget = message.provider === 'anthropic' &&
|
|
152
|
+
ANTHROPIC_REPLAY_APIS.has(message.api) &&
|
|
153
|
+
message.model === targetModelId &&
|
|
154
|
+
!isOpenAIReasoningSignature(signature);
|
|
155
|
+
// Match Pi's built-in origin check: only replay signatures from the
|
|
156
|
+
// same Anthropic API/model. Preserve visible foreign reasoning as
|
|
157
|
+
// ordinary text, but drop opaque redacted/OpenAI encrypted state.
|
|
158
|
+
if (hasSignature && !signatureBelongsToTarget) {
|
|
159
|
+
if (!thinking.redacted &&
|
|
160
|
+
!isOpenAIReasoningSignature(signature) &&
|
|
161
|
+
thinking.thinking.trim()) {
|
|
162
|
+
blocks.push({ type: 'text', text: sanitize(thinking.thinking) });
|
|
163
|
+
}
|
|
149
164
|
continue;
|
|
150
165
|
}
|
|
151
|
-
if (thinking.
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
166
|
+
if (thinking.redacted) {
|
|
167
|
+
if (hasSignature) {
|
|
168
|
+
blocks.push({
|
|
169
|
+
type: 'redacted_thinking',
|
|
170
|
+
data: signature,
|
|
171
|
+
});
|
|
172
|
+
}
|
|
173
|
+
continue;
|
|
174
|
+
}
|
|
175
|
+
if (!hasSignature) {
|
|
176
|
+
// Anthropic rejects unsigned thinking blocks. Preserve readable
|
|
177
|
+
// output from interrupted streams as ordinary assistant text.
|
|
178
|
+
if (thinking.thinking.trim()) {
|
|
179
|
+
blocks.push({
|
|
180
|
+
type: 'text',
|
|
181
|
+
text: sanitize(thinking.thinking),
|
|
182
|
+
});
|
|
183
|
+
}
|
|
184
|
+
continue;
|
|
185
|
+
}
|
|
186
|
+
if (hasLoneSurrogate(thinking.thinking)) {
|
|
187
|
+
// Signature authenticates the thinking bytes exactly. Sanitizing the
|
|
188
|
+
// text would invalidate it, so downgrade malformed signed thinking
|
|
189
|
+
// to plain text and omit the signature instead.
|
|
190
|
+
if (thinking.thinking.trim()) {
|
|
191
|
+
blocks.push({
|
|
192
|
+
type: 'text',
|
|
193
|
+
text: sanitize(thinking.thinking),
|
|
194
|
+
});
|
|
195
|
+
}
|
|
196
|
+
}
|
|
197
|
+
else {
|
|
157
198
|
blocks.push({
|
|
158
199
|
type: 'thinking',
|
|
159
200
|
thinking: thinking.thinking,
|
|
160
|
-
signature
|
|
201
|
+
signature,
|
|
161
202
|
});
|
|
162
203
|
}
|
|
163
|
-
else {
|
|
164
|
-
// Either unsigned, or signed-but-contains a lone surrogate. In the
|
|
165
|
-
// latter case we cannot keep the signature: sanitizing breaks it and
|
|
166
|
-
// sending the raw lone surrogate is an invalid-UTF8 400. Drop the
|
|
167
|
-
// signature and downgrade to sanitized text.
|
|
168
|
-
blocks.push({ type: 'text', text: sanitize(thinking.thinking) });
|
|
169
|
-
}
|
|
170
204
|
}
|
|
171
205
|
else if (block.type === 'toolCall') {
|
|
172
206
|
blocks.push({
|
|
@@ -318,7 +352,7 @@ function applyCacheMode(body, enabled, mode) {
|
|
|
318
352
|
addTtl(body);
|
|
319
353
|
}
|
|
320
354
|
export async function buildAnthropicRequest(modelId, context, options, cache, fastModeEnabled = false, identity) {
|
|
321
|
-
const messages = convertMessages(context.messages);
|
|
355
|
+
const messages = convertMessages(context.messages, modelId);
|
|
322
356
|
// Strip trailing assistant messages — Anthropic rejects prefill on some models
|
|
323
357
|
while (messages.length &&
|
|
324
358
|
messages[messages.length - 1]?.role === 'assistant') {
|
package/dist/stream.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { applyClaudeCodeHeaders, CACHE_KEEP_EXTENDED_TTL_BETA, CacheKeepManager, CacheKeepSessionRegistry, createStickyNoRouteResponse, decideStickyQuotaFailure, dumpDirectRequest, FAST_MODE_BETA, FallbackAccountManager, getCache1hPersistentMode, getDefaultCacheKeepRegistryDirectory, getFallbackReauthLabels, getRelayConfig, getRoutingMode, getStickyRoutingStatePath, isApiKeyAccount, isCache1hPersistentlyEnabled, isCacheKeepHybridActive, isDumpPersistentlyEnabled, isFastModePersistentlyEnabled, isKillswitchEnabled, isOAuthAccount, isPermanentRefreshError, isValidApiBaseURL, killswitchPassesPolicy, loadAccounts, mergeAnthropicBetas, QuotaManager, quotaSnapshotModelScopeIsExhausted, quotaSnapshotPassesModelScope, quotaSnapshotPassesPolicy, resolveClaudeCodeIdentity, STICKY_ROUTING_MAIN_ACCOUNT_ID, StickySessionRouter, sendViaRelay, setDumpEnabled, shouldFallbackStatus, stickyQuotaSnapshotIsFresh, stickyRetryAfterWithJitter, stickyRouteFamilyForModel, } from '@cortexkit/anthropic-auth-core';
|
|
1
|
+
import { applyClaudeCodeHeaders, CACHE_KEEP_EXTENDED_TTL_BETA, CacheKeepManager, CacheKeepSessionRegistry, createStickyNoRouteResponse, decideStickyQuotaFailure, dumpDirectRequest, FAST_MODE_BETA, FallbackAccountManager, getCache1hPersistentMode, getDefaultCacheKeepRegistryDirectory, getFallbackReauthLabels, getOrCreateMainAccountId, getRelayConfig, getRoutingMode, getStickyRoutingStatePath, isApiKeyAccount, isCache1hPersistentlyEnabled, isCacheKeepHybridActive, isDumpPersistentlyEnabled, isFastModePersistentlyEnabled, isKillswitchEnabled, isOAuthAccount, isPermanentRefreshError, isValidApiBaseURL, killswitchPassesPolicy, loadAccounts, mergeAnthropicBetas, QuotaManager, quotaSnapshotHasStandardWindows, quotaSnapshotModelScopeIsExhausted, quotaSnapshotPassesModelScope, quotaSnapshotPassesPolicy, refreshBackoffActive, resolveClaudeCodeIdentity, STICKY_ROUTING_MAIN_ACCOUNT_ID, StickySessionRouter, sendViaRelay, 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 { getPiAccountStoragePath } from './paths.js';
|
|
@@ -10,6 +10,7 @@ let cacheKeepRegistryDirectory;
|
|
|
10
10
|
const stickyRouters = new Map();
|
|
11
11
|
const quotaManagers = new Map();
|
|
12
12
|
const fallbackManagers = new Map();
|
|
13
|
+
const mainAccountIdInitializations = new Map();
|
|
13
14
|
const PI_SERVICE_CACHE_LIMIT = 16;
|
|
14
15
|
function setBoundedService(map, key, value) {
|
|
15
16
|
map.delete(key);
|
|
@@ -21,6 +22,19 @@ function setBoundedService(map, key, value) {
|
|
|
21
22
|
map.delete(oldest);
|
|
22
23
|
}
|
|
23
24
|
}
|
|
25
|
+
function ensurePiMainAccountId(storagePath) {
|
|
26
|
+
let initialization = mainAccountIdInitializations.get(storagePath);
|
|
27
|
+
if (!initialization) {
|
|
28
|
+
initialization = getOrCreateMainAccountId(storagePath).catch((error) => {
|
|
29
|
+
if (mainAccountIdInitializations.get(storagePath) === initialization) {
|
|
30
|
+
mainAccountIdInitializations.delete(storagePath);
|
|
31
|
+
}
|
|
32
|
+
throw error;
|
|
33
|
+
});
|
|
34
|
+
setBoundedService(mainAccountIdInitializations, storagePath, initialization);
|
|
35
|
+
}
|
|
36
|
+
return initialization;
|
|
37
|
+
}
|
|
24
38
|
function getPiRoutingServices(storagePath, storage) {
|
|
25
39
|
let quotaManager = quotaManagers.get(storagePath);
|
|
26
40
|
let fallbackManager = fallbackManagers.get(storagePath);
|
|
@@ -71,7 +85,10 @@ const cacheKeepManager = new CacheKeepManager({
|
|
|
71
85
|
return headers;
|
|
72
86
|
try {
|
|
73
87
|
const body = JSON.parse(target.bodyText);
|
|
74
|
-
const
|
|
88
|
+
const storagePath = getPiAccountStoragePath();
|
|
89
|
+
await ensurePiMainAccountId(storagePath);
|
|
90
|
+
const storage = await loadAccounts(storagePath);
|
|
91
|
+
const identity = await resolveClaudeCodeIdentity(accessToken, typeof body.model === 'string' ? body.model : undefined, target.oauthAccountId ?? storage?.mainAccountId);
|
|
75
92
|
headers.delete('anthropic-beta');
|
|
76
93
|
applyClaudeCodeHeaders(headers, accessToken, { body, identity });
|
|
77
94
|
headers.set('anthropic-beta', mergeAnthropicBetas(headers.get('anthropic-beta'), [
|
|
@@ -201,10 +218,14 @@ export async function* parseSse(response) {
|
|
|
201
218
|
}
|
|
202
219
|
}
|
|
203
220
|
async function sendAnthropicRequest(options) {
|
|
221
|
+
await ensurePiMainAccountId(options.storagePath);
|
|
204
222
|
const storage = await loadAccounts(options.storagePath);
|
|
205
223
|
setDumpEnabled(isDumpPersistentlyEnabled(storage));
|
|
224
|
+
const accountIdentity = options.oauthAccountId === STICKY_ROUTING_MAIN_ACCOUNT_ID
|
|
225
|
+
? storage?.mainAccountId
|
|
226
|
+
: options.oauthAccountId;
|
|
206
227
|
const identity = options.accessToken
|
|
207
|
-
? await resolveClaudeCodeIdentity(options.accessToken, options.model.id)
|
|
228
|
+
? await resolveClaudeCodeIdentity(options.accessToken, options.model.id, accountIdentity)
|
|
208
229
|
: undefined;
|
|
209
230
|
const { body, bodyText } = await buildAnthropicRequest(options.model.id, options.context, options.streamOptions, {
|
|
210
231
|
enabled: isCache1hPersistentlyEnabled(storage),
|
|
@@ -307,16 +328,18 @@ async function firstStreamingError(response) {
|
|
|
307
328
|
return response;
|
|
308
329
|
}
|
|
309
330
|
async function executeWithFallback(options) {
|
|
331
|
+
await ensurePiMainAccountId(options.storagePath);
|
|
310
332
|
const storage = await loadAccounts(options.storagePath);
|
|
311
333
|
const { quotaManager, fallbackManager: manager } = getPiRoutingServices(options.storagePath, storage);
|
|
312
|
-
|
|
334
|
+
const mainAccountId = storage?.mainAccountId;
|
|
335
|
+
quotaManager.seedMainFromStorage(storage, mainAccountId);
|
|
313
336
|
quotaManager.seedFallbacksFromAccounts((storage?.accounts ?? []).filter(isOAuthAccount));
|
|
314
337
|
async function buildStickyRoutes(modelId) {
|
|
315
|
-
const mainEntry = quotaManager.getMain(
|
|
338
|
+
const mainEntry = quotaManager.getMain(mainAccountId);
|
|
316
339
|
let mainQuota = mainEntry?.quota;
|
|
317
340
|
if (!stickyQuotaSnapshotIsFresh(mainEntry?.quota, storage, Date.now(), modelId)) {
|
|
318
341
|
try {
|
|
319
|
-
mainQuota = await quotaManager.refreshMain(options.primaryAccessToken);
|
|
342
|
+
mainQuota = await quotaManager.refreshMain(mainAccountId, options.primaryAccessToken);
|
|
320
343
|
}
|
|
321
344
|
catch { }
|
|
322
345
|
}
|
|
@@ -339,11 +362,10 @@ async function executeWithFallback(options) {
|
|
|
339
362
|
const account = usableById.get(configured.id) ?? configured;
|
|
340
363
|
if (!account.access || isPermanentRefreshError(account.lastRefreshError))
|
|
341
364
|
continue;
|
|
342
|
-
let accountQuota = quotaManager.getFallback(account.id, account
|
|
343
|
-
account.quota;
|
|
365
|
+
let accountQuota = quotaManager.getFallback(account.id, account)?.quota ?? account.quota;
|
|
344
366
|
if (!stickyQuotaSnapshotIsFresh(accountQuota, storage, Date.now(), modelId)) {
|
|
345
367
|
try {
|
|
346
|
-
accountQuota = await quotaManager.refreshFallback(account.id, account.access);
|
|
368
|
+
accountQuota = await quotaManager.refreshFallback(account.id, account.access, account);
|
|
347
369
|
}
|
|
348
370
|
catch { }
|
|
349
371
|
}
|
|
@@ -374,19 +396,26 @@ async function executeWithFallback(options) {
|
|
|
374
396
|
}));
|
|
375
397
|
const usableIds = new Set(usableFallbacks.map((account) => account.id));
|
|
376
398
|
const candidates = allRoutes.flatMap((route) => {
|
|
377
|
-
|
|
378
|
-
|
|
399
|
+
const quota = quotaSnapshotHasStandardWindows(route.quota)
|
|
400
|
+
? route.quota
|
|
401
|
+
: undefined;
|
|
379
402
|
const accountId = route.id === STICKY_ROUTING_MAIN_ACCOUNT_ID ? undefined : route.id;
|
|
380
|
-
const
|
|
381
|
-
|
|
382
|
-
|
|
383
|
-
|
|
384
|
-
(
|
|
403
|
+
const quotaState = quota
|
|
404
|
+
? { kind: 'known', quota }
|
|
405
|
+
: { kind: 'unknown' };
|
|
406
|
+
const passesKillswitch = !isKillswitchEnabled(storage) ||
|
|
407
|
+
killswitchPassesPolicy(quotaState.kind === 'known' ? quotaState.quota : undefined, storage, accountId, modelId);
|
|
408
|
+
const passes = passesKillswitch &&
|
|
409
|
+
(quotaState.kind === 'unknown' ||
|
|
410
|
+
(quotaSnapshotPassesPolicy(quotaState.quota, storage) &&
|
|
411
|
+
quotaSnapshotPassesModelScope(quotaState.quota, modelId) &&
|
|
412
|
+
(route.id === STICKY_ROUTING_MAIN_ACCOUNT_ID ||
|
|
413
|
+
usableIds.has(route.id))));
|
|
385
414
|
return passes
|
|
386
415
|
? [
|
|
387
416
|
{
|
|
388
417
|
accountId: route.id,
|
|
389
|
-
quota:
|
|
418
|
+
quota: quotaState,
|
|
390
419
|
order: route.order,
|
|
391
420
|
},
|
|
392
421
|
]
|
|
@@ -396,8 +425,8 @@ async function executeWithFallback(options) {
|
|
|
396
425
|
}
|
|
397
426
|
async function primaryQuotaRefreshConfirmsExhausted() {
|
|
398
427
|
try {
|
|
399
|
-
const quota = await quotaManager.refreshMain(options.primaryAccessToken);
|
|
400
|
-
const entry = quotaManager.getMain(
|
|
428
|
+
const quota = await quotaManager.refreshMain(mainAccountId, options.primaryAccessToken);
|
|
429
|
+
const entry = quotaManager.getMain(mainAccountId);
|
|
401
430
|
return Boolean(entry &&
|
|
402
431
|
entry.refreshAfter > Date.now() &&
|
|
403
432
|
quotaSnapshotIsExhausted(quota));
|
|
@@ -408,8 +437,8 @@ async function executeWithFallback(options) {
|
|
|
408
437
|
}
|
|
409
438
|
async function primaryQuotaRefreshConfirmsModelScopeExhausted() {
|
|
410
439
|
try {
|
|
411
|
-
const quota = await quotaManager.refreshMain(options.primaryAccessToken);
|
|
412
|
-
const entry = quotaManager.getMain(
|
|
440
|
+
const quota = await quotaManager.refreshMain(mainAccountId, options.primaryAccessToken);
|
|
441
|
+
const entry = quotaManager.getMain(mainAccountId);
|
|
413
442
|
return Boolean(entry &&
|
|
414
443
|
entry.refreshAfter > Date.now() &&
|
|
415
444
|
quotaSnapshotModelScopeIsExhausted(quota, options.model.id));
|
|
@@ -419,12 +448,12 @@ async function executeWithFallback(options) {
|
|
|
419
448
|
}
|
|
420
449
|
}
|
|
421
450
|
function primaryCachedModelScopeExhausted() {
|
|
422
|
-
const entry = quotaManager.getMain(
|
|
451
|
+
const entry = quotaManager.getMain(mainAccountId);
|
|
423
452
|
return Boolean(entry &&
|
|
424
453
|
quotaSnapshotModelScopeIsExhausted(entry.quota, options.model.id));
|
|
425
454
|
}
|
|
426
455
|
function primaryFreshModelScopeExhausted() {
|
|
427
|
-
const entry = quotaManager.getMain(
|
|
456
|
+
const entry = quotaManager.getMain(mainAccountId);
|
|
428
457
|
return Boolean(entry &&
|
|
429
458
|
!quotaManager.isMainStale(options.model.id) &&
|
|
430
459
|
quotaSnapshotModelScopeIsExhausted(entry.quota, options.model.id));
|
|
@@ -436,17 +465,38 @@ async function executeWithFallback(options) {
|
|
|
436
465
|
const usableOAuthById = new Map(usableOAuth.map((account) => [account.id, account]));
|
|
437
466
|
for (const configured of storage?.accounts ?? []) {
|
|
438
467
|
let response = null;
|
|
439
|
-
|
|
468
|
+
let account = isOAuthAccount(configured)
|
|
440
469
|
? usableOAuthById.get(configured.id)
|
|
441
470
|
: configured;
|
|
442
|
-
if (!account)
|
|
471
|
+
if (!account) {
|
|
472
|
+
if (!isOAuthAccount(configured) ||
|
|
473
|
+
!configured.access ||
|
|
474
|
+
(configured.expires !== undefined &&
|
|
475
|
+
configured.expires <= Date.now()) ||
|
|
476
|
+
isPermanentRefreshError(configured.lastRefreshError) ||
|
|
477
|
+
refreshBackoffActive(configured.lastRefreshError, configured.id, Date.now()))
|
|
478
|
+
continue;
|
|
479
|
+
account = configured;
|
|
480
|
+
const quota = quotaManager.getFallback(configured.id, configured)?.quota ??
|
|
481
|
+
configured.quota;
|
|
482
|
+
if (quotaSnapshotHasStandardWindows(quota))
|
|
483
|
+
continue;
|
|
484
|
+
if (isKillswitchEnabled(storage) &&
|
|
485
|
+
!killswitchPassesPolicy(quota, storage, configured.id, options.model.id))
|
|
486
|
+
continue;
|
|
487
|
+
}
|
|
488
|
+
else if (isOAuthAccount(account) &&
|
|
489
|
+
isKillswitchEnabled(storage) &&
|
|
490
|
+
!killswitchPassesPolicy(quotaManager.getFallback(account.id, account)?.quota ?? account.quota, storage, account.id, options.model.id)) {
|
|
443
491
|
continue;
|
|
492
|
+
}
|
|
444
493
|
if (isOAuthAccount(account)) {
|
|
445
494
|
if (routeOptions.apiOnly === true || !account.access)
|
|
446
495
|
continue;
|
|
447
496
|
response = await sendAnthropicRequest({
|
|
448
497
|
...options,
|
|
449
498
|
accessToken: account.access,
|
|
499
|
+
oauthAccountId: account.id,
|
|
450
500
|
});
|
|
451
501
|
}
|
|
452
502
|
else if (routeOptions.includeApiRoutes === true &&
|
|
@@ -587,8 +637,8 @@ async function executeWithFallback(options) {
|
|
|
587
637
|
try {
|
|
588
638
|
quota =
|
|
589
639
|
route.id === STICKY_ROUTING_MAIN_ACCOUNT_ID
|
|
590
|
-
? await quotaManager.refreshMain(route.access)
|
|
591
|
-
: await quotaManager.refreshFallback(route.id, route.access);
|
|
640
|
+
? await quotaManager.refreshMain(mainAccountId, route.access)
|
|
641
|
+
: await quotaManager.refreshFallback(route.id, route.access, route.account);
|
|
592
642
|
}
|
|
593
643
|
catch {
|
|
594
644
|
// Retain affinity when the quota probe itself is unavailable.
|
|
@@ -680,9 +730,39 @@ async function executeWithFallback(options) {
|
|
|
680
730
|
if (fallback)
|
|
681
731
|
return fallback;
|
|
682
732
|
}
|
|
733
|
+
if (isKillswitchEnabled(storage)) {
|
|
734
|
+
let mainQuota = quotaManager.getMain(mainAccountId)?.quota;
|
|
735
|
+
if (!mainQuota || quotaManager.isMainStale(options.model.id)) {
|
|
736
|
+
try {
|
|
737
|
+
mainQuota = await quotaManager.refreshMain(mainAccountId, options.primaryAccessToken);
|
|
738
|
+
}
|
|
739
|
+
catch { }
|
|
740
|
+
}
|
|
741
|
+
if (!killswitchPassesPolicy(mainQuota, storage, undefined, options.model.id)) {
|
|
742
|
+
if (!fallbackFirst) {
|
|
743
|
+
const fallback = await tryFallbackAccounts();
|
|
744
|
+
if (fallback)
|
|
745
|
+
return fallback;
|
|
746
|
+
}
|
|
747
|
+
return new Response(JSON.stringify({
|
|
748
|
+
type: 'error',
|
|
749
|
+
error: {
|
|
750
|
+
type: 'rate_limit_error',
|
|
751
|
+
message: 'Killswitch blocked all OAuth routes',
|
|
752
|
+
},
|
|
753
|
+
}), {
|
|
754
|
+
status: 429,
|
|
755
|
+
headers: {
|
|
756
|
+
'content-type': 'application/json',
|
|
757
|
+
'retry-after': '60',
|
|
758
|
+
},
|
|
759
|
+
});
|
|
760
|
+
}
|
|
761
|
+
}
|
|
683
762
|
const primary = await sendAnthropicRequest({
|
|
684
763
|
...options,
|
|
685
764
|
accessToken: options.primaryAccessToken,
|
|
765
|
+
oauthAccountId: STICKY_ROUTING_MAIN_ACCOUNT_ID,
|
|
686
766
|
});
|
|
687
767
|
const primaryPreflight = await firstStreamingError(primary);
|
|
688
768
|
if (primaryPreflight instanceof Response) {
|
|
@@ -758,6 +838,20 @@ export function streamCortexKitAnthropic(model, context, options) {
|
|
|
758
838
|
partial: output,
|
|
759
839
|
});
|
|
760
840
|
}
|
|
841
|
+
else if (block?.type === 'redacted_thinking') {
|
|
842
|
+
output.content.push({
|
|
843
|
+
type: 'thinking',
|
|
844
|
+
thinking: '[Reasoning redacted]',
|
|
845
|
+
thinkingSignature: String(block.data ?? ''),
|
|
846
|
+
redacted: true,
|
|
847
|
+
index: event.index,
|
|
848
|
+
});
|
|
849
|
+
stream.push({
|
|
850
|
+
type: 'thinking_start',
|
|
851
|
+
contentIndex: output.content.length - 1,
|
|
852
|
+
partial: output,
|
|
853
|
+
});
|
|
854
|
+
}
|
|
761
855
|
else if (block?.type === 'tool_use') {
|
|
762
856
|
output.content.push({
|
|
763
857
|
type: 'toolCall',
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@cortexkit/pi-anthropic-auth",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.21.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": "1.
|
|
39
|
+
"@cortexkit/anthropic-auth-core": "1.21.0"
|
|
40
40
|
},
|
|
41
41
|
"peerDependencies": {
|
|
42
42
|
"@earendil-works/pi-ai": "*",
|