@cortexkit/pi-anthropic-auth 1.21.0 → 1.22.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 +6 -3
- package/dist/commands.js +28 -1
- package/dist/convert.d.ts +5 -2
- package/dist/convert.js +10 -4
- package/dist/effort-history.d.ts +12 -0
- package/dist/effort-history.js +63 -0
- package/dist/index.js +45 -16
- package/dist/stream.d.ts +2 -2
- package/dist/stream.js +28 -8
- package/package.json +2 -2
package/README.md
CHANGED
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
|
|
3
3
|
Pi package for CortexKit Anthropic OAuth support. It overrides Pi's built-in `anthropic` provider with a CortexKit provider extension backed by the shared `@cortexkit/anthropic-auth-core` package.
|
|
4
4
|
|
|
5
|
-
The Pi provider catalog includes Claude Fable 5 (`claude-fable-5`), limited-access Claude Mythos 5 (`claude-mythos-5`), Claude Opus 5 (`claude-opus-5`), Claude Opus 4.8, Claude Opus 4.5, Claude Sonnet 4.5, and Claude Sonnet 5 (`claude-sonnet-5`). Fable/Mythos reasoning uses Anthropic adaptive thinking with `thinking.display: "summarized"` and `output_config.effort`; the package does not send rejected manual `thinking.budget_tokens` for those models.
|
|
5
|
+
The Pi provider catalog includes Claude Fable 5 (`claude-fable-5`) and 5.1 (`claude-fable-5-1`), limited-access Claude Mythos 5 (`claude-mythos-5`) and 5.1 (`claude-mythos-5-1`), Claude Opus 5 (`claude-opus-5`), Claude Opus 4.8, Claude Opus 4.5, Claude Sonnet 4.5, and Claude Sonnet 5 (`claude-sonnet-5`). Fable/Mythos reasoning uses Anthropic adaptive thinking with `thinking.display: "summarized"` and `output_config.effort`; the package does not send rejected manual `thinking.budget_tokens` for those models. OAuth Fable 5.1 sessions preserve Pi thinking-level changes as mid-conversation effort markers, so switching effort does not rewrite the cached prefix. Replayed signed/redacted thinking follows the configured prefix-mismatch behavior.
|
|
6
6
|
|
|
7
7
|
This package is part of the CortexKit Anthropic Auth monorepo, which supports both OpenCode (`@cortexkit/opencode-anthropic-auth`) and Pi (`@cortexkit/pi-anthropic-auth`) through the same shared core logic.
|
|
8
8
|
|
|
@@ -42,7 +42,7 @@ Pi state is stored separately from OpenCode at:
|
|
|
42
42
|
|
|
43
43
|
Override the path with `PI_ANTHROPIC_AUTH_FILE`. The package also respects `PI_AGENT_DIR` when deriving the default sidecar path.
|
|
44
44
|
|
|
45
|
-
The sidecar uses the same JSON shape as the OpenCode package, including `routing`, `claudeCache`, `cacheKeep`, `prime`, `claudeFast`, `dump`, `relay`, and fallback `accounts` blocks. Runtime OAuth/quota state is stored in `anthropic-auth-state.json`; sticky session assignments are stored separately in `anthropic-auth-routing-state.json` with SHA-256-hashed session IDs.
|
|
45
|
+
The sidecar uses the same JSON shape as the OpenCode package, including `routing`, `claudeCache`, `cacheKeep`, `prime`, `claudeFast`, `thinkingBinding`, `dump`, `relay`, and fallback `accounts` blocks. `thinkingBinding.prefixMismatchBehavior` accepts `account-default` (default), `error`, or `drop_block` for OAuth Fable 5.1 replay. Runtime OAuth/quota state is stored in `anthropic-auth-state.json`; sticky session assignments are stored separately in `anthropic-auth-routing-state.json` with SHA-256-hashed session IDs.
|
|
46
46
|
|
|
47
47
|
## Commands
|
|
48
48
|
|
|
@@ -77,10 +77,13 @@ The sidecar uses the same JSON shape as the OpenCode package, including `routing
|
|
|
77
77
|
/claude-routing sticky-balanced
|
|
78
78
|
/claude-routing reset
|
|
79
79
|
|
|
80
|
+
/claude-account
|
|
81
|
+
/claude-account reset-backoff
|
|
82
|
+
|
|
80
83
|
/claude-quota
|
|
81
84
|
```
|
|
82
85
|
|
|
83
|
-
`/claude-quota` reports sidecar OAuth fallback quota state from `~/.pi/agent/anthropic-auth.json`. `/claude-routing fallback-first` prefers usable OAuth fallback accounts before the main account; `/claude-routing main-first` restores the default. `/claude-routing sticky-balanced` assigns each Pi session to an OAuth account according to current 5-hour, 7-day, and matching model-scoped quota headroom, then persists that assignment across transient failures and process restarts. `/claude-routing reset` clears the current Pi session's assignment. Direct Opus sessions prefer usable accounts whose Fable quota is exhausted. API-key routes use the same sidecar shape as OpenCode and are sent directly to their configured Anthropic-compatible base URL, such as Kie's `https://api.kie.ai/claude`, but Pi only uses them after the main OAuth model response reports HTTP 429 or a streaming rate-limit error and a live quota check confirms 0% remaining. `/claude-cachekeep always` keeps active hybrid caches warm while Pi remains open; `/claude-cachekeep HH-HH` limits prewarms to a local time window. Both send `max_tokens: 0` pre-warm requests about five minutes before the 1-hour TTL expires. Running `/claude-cachekeep` without arguments lists live tracked sessions across Pi processes through a temporary lease registry that stores only session IDs and cache timing. `/claude-fast on` adds Anthropic `speed: "fast"` plus the `fast-mode-2026-02-01` beta header for supported Opus models (`claude-opus-4-6`, `claude-opus-4-7`, `claude-opus-4-8`, and `claude-opus-5`).
|
|
86
|
+
`/claude-account reset-backoff` clears the main OAuth refresh backoff and its matching quota backoff. Persisted refresh backoffs are bound to the refresh token that produced them, so replacing a rejected credential immediately escapes its stale latch. `/claude-quota` reports sidecar OAuth fallback quota state from `~/.pi/agent/anthropic-auth.json`. `/claude-routing fallback-first` prefers usable OAuth fallback accounts before the main account; `/claude-routing main-first` restores the default. `/claude-routing sticky-balanced` assigns each Pi session to an OAuth account according to current 5-hour, 7-day, and matching model-scoped quota headroom, then persists that assignment across transient failures and process restarts. `/claude-routing reset` clears the current Pi session's assignment. Direct Opus sessions prefer usable accounts whose Fable quota is exhausted. API-key routes use the same sidecar shape as OpenCode and are sent directly to their configured Anthropic-compatible base URL, such as Kie's `https://api.kie.ai/claude`, but Pi only uses them after the main OAuth model response reports HTTP 429 or a streaming rate-limit error and a live quota check confirms 0% remaining. `/claude-cachekeep always` keeps active hybrid caches warm while Pi remains open; `/claude-cachekeep HH-HH` limits prewarms to a local time window. Both send `max_tokens: 0` pre-warm requests about five minutes before the 1-hour TTL expires. Running `/claude-cachekeep` without arguments lists live tracked sessions across Pi processes through a temporary lease registry that stores only session IDs and cache timing. `/claude-fast on` adds Anthropic `speed: "fast"` plus the `fast-mode-2026-02-01` beta header for supported Opus models (`claude-opus-4-6`, `claude-opus-4-7`, `claude-opus-4-8`, and `claude-opus-5`).
|
|
84
87
|
|
|
85
88
|
### Claude quota window priming
|
|
86
89
|
|
package/dist/commands.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { buildClaudeQuotaSummary, buildFallbackQuotaSummaries, buildPrimeAccountStatuses, CLAUDE_ACCOUNT_COMMAND_NAME, CLAUDE_CACHE_KEEP_COMMAND_NAME, CLAUDE_PRIME_COMMAND_NAME, CLAUDE_ROUTING_COMMAND_NAME, createEmptyStorage, executeAccountCommand, executeCache1hCommand, executeCacheKeepCommand, executeDumpCommand, executeFastModeCommand, executeLoggingCommand, executePrimeCommand, executeRoutingCommand, getCache1hPersistentMode, getCacheKeepWindow, getPersistedLogLevel, getRoutingMode, isCache1hPersistentlyEnabled, isCacheKeepAlways, isCacheKeepHybridActive, isCacheKeepPersistentlyEnabled, isDumpPersistentlyEnabled, isFastModePersistentlyEnabled, isPrimePersistentlyEnabled, loadAccounts, parseCache1hCommandAction, parseCacheKeepCommandAction, parseDumpCommandAction, parseFastModeCommandAction, parseLoggingCommandAction, parseRoutingCommandAction, removeAccountPersistent, reorderAccountsPersistent, setAccountEnabledPersistent, setCache1hPersistentEnabled, setCache1hPersistentMode, setCacheKeepPersistentAlways, setCacheKeepPersistentEnabled, setCacheKeepPersistentWindow, setCacheKeepSubagentsEnabled, setDumpEnabled, setDumpPersistentEnabled, setFastModePersistentEnabled, setLogLevelPersistent, setRoutingMode, } from '@cortexkit/anthropic-auth-core';
|
|
1
|
+
import { buildClaudeQuotaSummary, buildFallbackQuotaSummaries, buildPrimeAccountStatuses, CLAUDE_ACCOUNT_COMMAND_NAME, CLAUDE_CACHE_KEEP_COMMAND_NAME, CLAUDE_PRIME_COMMAND_NAME, CLAUDE_ROUTING_COMMAND_NAME, createEmptyStorage, detectClaustrumConnection, executeAccountCommand, executeCache1hCommand, executeCacheKeepCommand, executeDumpCommand, executeFastModeCommand, executeLoggingCommand, executePrimeCommand, executeRoutingCommand, getCache1hPersistentMode, getCacheKeepWindow, getPersistedLogLevel, getRoutingMode, isCache1hPersistentlyEnabled, isCacheKeepAlways, isCacheKeepHybridActive, isCacheKeepPersistentlyEnabled, isDumpPersistentlyEnabled, isFastModePersistentlyEnabled, isPrimePersistentlyEnabled, loadAccounts, mergeMainQuotaErrorClearedAt, mergeMainRefreshErrorClearedAt, parseAccountCommandAction, parseCache1hCommandAction, parseCacheKeepCommandAction, parseDumpCommandAction, parseFastModeCommandAction, parseLoggingCommandAction, parseRoutingCommandAction, removeAccountPersistent, reorderAccountsPersistent, saveAccountState, setAccountEnabledPersistent, setCache1hPersistentEnabled, setCache1hPersistentMode, setCacheKeepPersistentAlways, setCacheKeepPersistentEnabled, setCacheKeepPersistentWindow, setCacheKeepSubagentsEnabled, setDumpEnabled, setDumpPersistentEnabled, setFastModePersistentEnabled, setLogLevelPersistent, setRoutingMode, } from '@cortexkit/anthropic-auth-core';
|
|
2
2
|
import { getPiAccountStoragePath } from './paths.js';
|
|
3
3
|
import { clearPiStickyRoutingSession, getPiTrackedCacheKeepSessions, } from './stream.js';
|
|
4
4
|
function notify(ctx, message, kind = 'info') {
|
|
@@ -152,9 +152,13 @@ export function registerCommands(pi) {
|
|
|
152
152
|
handler: async (args, ctx) => {
|
|
153
153
|
const path = getPiAccountStoragePath();
|
|
154
154
|
const storage = await loadAccounts(path);
|
|
155
|
+
const action = parseAccountCommandAction(args ?? '');
|
|
155
156
|
const result = executeAccountCommand({
|
|
156
157
|
argumentsText: args ?? '',
|
|
157
158
|
storage: storage ?? createEmptyStorage(),
|
|
159
|
+
claustrum: action.type === 'status'
|
|
160
|
+
? await detectClaustrumConnection()
|
|
161
|
+
: undefined,
|
|
158
162
|
});
|
|
159
163
|
if (!result.updated) {
|
|
160
164
|
notify(ctx, result.text);
|
|
@@ -181,6 +185,29 @@ export function registerCommands(pi) {
|
|
|
181
185
|
await reorderAccountsPersistent(newOrder, path);
|
|
182
186
|
}
|
|
183
187
|
}
|
|
188
|
+
else if (mutationAction === 'reset-backoff') {
|
|
189
|
+
const nextStorage = storage ?? createEmptyStorage();
|
|
190
|
+
nextStorage.refresh = nextStorage.refresh ?? {};
|
|
191
|
+
nextStorage.refresh.mainLastRefreshError = undefined;
|
|
192
|
+
nextStorage.refresh.mainRefreshErrorClearedAt =
|
|
193
|
+
mergeMainRefreshErrorClearedAt(nextStorage.refresh.mainRefreshErrorClearedAt, Date.now());
|
|
194
|
+
const mainIdentity = nextStorage.mainAccountId;
|
|
195
|
+
const quotaError = nextStorage.quota?.mainLastQuotaApiError;
|
|
196
|
+
if (!quotaError?.accountIdentity ||
|
|
197
|
+
!mainIdentity ||
|
|
198
|
+
quotaError.accountIdentity === mainIdentity) {
|
|
199
|
+
nextStorage.quota = nextStorage.quota ?? {};
|
|
200
|
+
nextStorage.quota.mainLastQuotaApiError = undefined;
|
|
201
|
+
const nextQuotaErrorGeneration = (nextStorage.quota.mainQuotaErrorGeneration ?? 0) + 1;
|
|
202
|
+
nextStorage.quota.mainQuotaErrorGeneration = Math.max(nextStorage.quota.mainQuotaErrorGeneration ?? 0, nextQuotaErrorGeneration);
|
|
203
|
+
nextStorage.quota.mainQuotaErrorClearedAt =
|
|
204
|
+
mergeMainQuotaErrorClearedAt(nextStorage.quota.mainQuotaErrorClearedAt, Date.now());
|
|
205
|
+
}
|
|
206
|
+
await saveAccountState(nextStorage, path, {
|
|
207
|
+
mainRefresh: true,
|
|
208
|
+
mainQuota: true,
|
|
209
|
+
});
|
|
210
|
+
}
|
|
184
211
|
notify(ctx, result.text);
|
|
185
212
|
},
|
|
186
213
|
});
|
package/dist/convert.d.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { type Cache1hMode, type ClaudeCodeIdentity } from '@cortexkit/anthropic-auth-core';
|
|
1
|
+
import { type Cache1hMode, type ClaudeCodeIdentity, type MidConversationEffortTransition, type ThinkingPrefixMismatchBehavior } from '@cortexkit/anthropic-auth-core';
|
|
2
2
|
import type { Context, SimpleStreamOptions, Tool } from '@earendil-works/pi-ai';
|
|
3
3
|
export type AnthropicRequestBody = {
|
|
4
4
|
model: string;
|
|
@@ -26,7 +26,10 @@ export declare function fromClaudeCodeToolName(name: string, tools?: Tool[]): st
|
|
|
26
26
|
export declare function buildAnthropicRequest(modelId: string, context: Context, options: SimpleStreamOptions | undefined, cache: {
|
|
27
27
|
enabled: boolean;
|
|
28
28
|
mode: Cache1hMode;
|
|
29
|
-
}, fastModeEnabled?: boolean, identity?: ClaudeCodeIdentity
|
|
29
|
+
}, fastModeEnabled?: boolean, identity?: ClaudeCodeIdentity, controls?: {
|
|
30
|
+
effortTransitions?: readonly MidConversationEffortTransition[];
|
|
31
|
+
thinkingPrefixMismatchBehavior?: ThinkingPrefixMismatchBehavior;
|
|
32
|
+
}): Promise<{
|
|
30
33
|
body: AnthropicRequestBody;
|
|
31
34
|
bodyText: string;
|
|
32
35
|
}>;
|
package/dist/convert.js
CHANGED
|
@@ -1,8 +1,9 @@
|
|
|
1
|
-
import { applyClaudeCodeMetadata, buildBillingHeaderValue, CLAUDE_CODE_ENTRYPOINT, CLAUDE_CODE_IDENTITY, CLAUDE_FABLE_MYTHOS_5_SUMMARIZED_THINKING, CLAUDE_OPUS_5_ADAPTIVE_THINKING, CLAUDE_SONNET_5_ADAPTIVE_THINKING, isClaudeFableOrMythos5Model, isClaudeOpus5Model, isClaudeSonnet5Model, isFastModeSupportedModel, isOpenAIReasoningSignature, orderClaudeCodeBody, signRequestBody, } from '@cortexkit/anthropic-auth-core';
|
|
1
|
+
import { applyClaudeCodeMetadata, applyMidConversationOutputConfig, applyThinkingBindingControls, buildBillingHeaderValue, CLAUDE_CODE_ENTRYPOINT, CLAUDE_CODE_IDENTITY, CLAUDE_FABLE_MYTHOS_5_SUMMARIZED_THINKING, CLAUDE_OPUS_5_ADAPTIVE_THINKING, CLAUDE_SONNET_5_ADAPTIVE_THINKING, ClaudeCodeFirstUserTextTracker, isClaudeFableOrMythos5Model, isClaudeOpus5Model, isClaudeSonnet5Model, isFastModeSupportedModel, isOpenAIReasoningSignature, orderClaudeCodeBody, signRequestBody, } from '@cortexkit/anthropic-auth-core';
|
|
2
2
|
// Anchor identifying Pi's documentation paragraph — the only part of the prompt
|
|
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 firstUserTextTracker = new ClaudeCodeFirstUserTextTracker();
|
|
6
7
|
const ANTHROPIC_REPLAY_APIS = new Set([
|
|
7
8
|
'anthropic-messages',
|
|
8
9
|
'cortexkit-anthropic-messages',
|
|
@@ -351,7 +352,7 @@ function applyCacheMode(body, enabled, mode) {
|
|
|
351
352
|
body.cache_control = { type: 'ephemeral' };
|
|
352
353
|
addTtl(body);
|
|
353
354
|
}
|
|
354
|
-
export async function buildAnthropicRequest(modelId, context, options, cache, fastModeEnabled = false, identity) {
|
|
355
|
+
export async function buildAnthropicRequest(modelId, context, options, cache, fastModeEnabled = false, identity, controls = {}) {
|
|
355
356
|
const messages = convertMessages(context.messages, modelId);
|
|
356
357
|
// Strip trailing assistant messages — Anthropic rejects prefill on some models
|
|
357
358
|
while (messages.length &&
|
|
@@ -361,7 +362,9 @@ export async function buildAnthropicRequest(modelId, context, options, cache, fa
|
|
|
361
362
|
const system = [
|
|
362
363
|
{
|
|
363
364
|
type: 'text',
|
|
364
|
-
text: buildBillingHeaderValue(messages, undefined, CLAUDE_CODE_ENTRYPOINT
|
|
365
|
+
text: buildBillingHeaderValue(messages, undefined, CLAUDE_CODE_ENTRYPOINT, options?.sessionId
|
|
366
|
+
? firstUserTextTracker.resolve(options.sessionId, messages)
|
|
367
|
+
: undefined),
|
|
365
368
|
},
|
|
366
369
|
{ type: 'text', text: CLAUDE_CODE_IDENTITY },
|
|
367
370
|
];
|
|
@@ -448,10 +451,13 @@ export async function buildAnthropicRequest(modelId, context, options, cache, fa
|
|
|
448
451
|
};
|
|
449
452
|
}
|
|
450
453
|
}
|
|
454
|
+
applyMidConversationOutputConfig(body, controls.effortTransitions ?? []);
|
|
451
455
|
addEphemeralCacheControl(body);
|
|
452
456
|
applyCacheMode(body, cache.enabled, cache.mode);
|
|
453
|
-
if (identity)
|
|
457
|
+
if (identity) {
|
|
458
|
+
applyThinkingBindingControls(body, controls.thinkingPrefixMismatchBehavior ?? 'account-default');
|
|
454
459
|
applyClaudeCodeMetadata(body, identity);
|
|
460
|
+
}
|
|
455
461
|
const unsigned = JSON.stringify(orderClaudeCodeBody(body));
|
|
456
462
|
const bodyText = await signRequestBody(unsigned);
|
|
457
463
|
return { body, bodyText };
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import { type MidConversationEffortTransition } from '@cortexkit/anthropic-auth-core';
|
|
2
|
+
type SessionEntryLike = {
|
|
3
|
+
id?: unknown;
|
|
4
|
+
type?: unknown;
|
|
5
|
+
thinkingLevel?: unknown;
|
|
6
|
+
message?: {
|
|
7
|
+
role?: unknown;
|
|
8
|
+
};
|
|
9
|
+
};
|
|
10
|
+
/** Build Pi's active, compaction-aware Fable 5.1 effort timeline. */
|
|
11
|
+
export declare function collectPiEffortHistory(contextEntries: readonly SessionEntryLike[], fullBranch: readonly SessionEntryLike[]): MidConversationEffortTransition[];
|
|
12
|
+
export {};
|
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
import { normalizeAdaptiveEffort, } from '@cortexkit/anthropic-auth-core';
|
|
2
|
+
function entryRole(entry) {
|
|
3
|
+
if (entry.type === 'compaction' || entry.type === 'branch_summary') {
|
|
4
|
+
return 'user';
|
|
5
|
+
}
|
|
6
|
+
if (entry.type === 'custom_message')
|
|
7
|
+
return 'user';
|
|
8
|
+
return entry.type === 'message' ? entry.message?.role : undefined;
|
|
9
|
+
}
|
|
10
|
+
function appendTransition(transitions, afterAssistantMessages, effort) {
|
|
11
|
+
const previous = transitions.at(-1);
|
|
12
|
+
if (previous?.effort === effort)
|
|
13
|
+
return;
|
|
14
|
+
if (previous?.afterAssistantMessages === afterAssistantMessages) {
|
|
15
|
+
previous.effort = effort;
|
|
16
|
+
return;
|
|
17
|
+
}
|
|
18
|
+
transitions.push({ afterAssistantMessages, effort });
|
|
19
|
+
}
|
|
20
|
+
/** Build Pi's active, compaction-aware Fable 5.1 effort timeline. */
|
|
21
|
+
export function collectPiEffortHistory(contextEntries, fullBranch) {
|
|
22
|
+
let activeEffort = 'high';
|
|
23
|
+
let assistantMessages = 0;
|
|
24
|
+
const transitions = [];
|
|
25
|
+
const first = contextEntries[0];
|
|
26
|
+
const compactionIndex = first?.type === 'compaction'
|
|
27
|
+
? fullBranch.findIndex((entry) => entry.id === first.id)
|
|
28
|
+
: -1;
|
|
29
|
+
if (compactionIndex >= 0) {
|
|
30
|
+
for (let index = 0; index <= compactionIndex; index++) {
|
|
31
|
+
const entry = fullBranch[index];
|
|
32
|
+
if (entry?.type !== 'thinking_level_change')
|
|
33
|
+
continue;
|
|
34
|
+
activeEffort = normalizeAdaptiveEffort(entry.thinkingLevel) ?? 'high';
|
|
35
|
+
}
|
|
36
|
+
appendTransition(transitions, 0, activeEffort);
|
|
37
|
+
}
|
|
38
|
+
const branchIndexById = new Map(fullBranch.map((entry, index) => [entry.id, index]));
|
|
39
|
+
for (const entry of contextEntries) {
|
|
40
|
+
if (entry === first && entry.type === 'compaction')
|
|
41
|
+
continue;
|
|
42
|
+
const branchIndex = branchIndexById.get(entry.id);
|
|
43
|
+
const retainedBeforeCompaction = compactionIndex >= 0 &&
|
|
44
|
+
typeof branchIndex === 'number' &&
|
|
45
|
+
branchIndex < compactionIndex;
|
|
46
|
+
if (entry.type === 'thinking_level_change') {
|
|
47
|
+
if (!retainedBeforeCompaction) {
|
|
48
|
+
activeEffort = normalizeAdaptiveEffort(entry.thinkingLevel) ?? 'high';
|
|
49
|
+
}
|
|
50
|
+
continue;
|
|
51
|
+
}
|
|
52
|
+
const role = entryRole(entry);
|
|
53
|
+
if (role === 'assistant') {
|
|
54
|
+
assistantMessages++;
|
|
55
|
+
}
|
|
56
|
+
else if (role === 'user' ||
|
|
57
|
+
role === 'toolResult' ||
|
|
58
|
+
role === 'tool_result') {
|
|
59
|
+
appendTransition(transitions, assistantMessages, activeEffort);
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
return transitions;
|
|
63
|
+
}
|
package/dist/index.js
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
|
-
import { authorize, CLAUDE_FABLE_MYTHOS_5_CONTEXT_WINDOW, CLAUDE_FABLE_MYTHOS_5_MAX_OUTPUT_TOKENS, CLAUDE_FABLE_MYTHOS_5_MODEL_SPECS, CLAUDE_FABLE_MYTHOS_5_PRICING, exchange, refreshClaudeOAuthToken, } from '@cortexkit/anthropic-auth-core';
|
|
1
|
+
import { authorize, CLAUDE_FABLE_MYTHOS_5_1_PRICING, CLAUDE_FABLE_MYTHOS_5_CONTEXT_WINDOW, CLAUDE_FABLE_MYTHOS_5_MAX_OUTPUT_TOKENS, CLAUDE_FABLE_MYTHOS_5_MODEL_SPECS, CLAUDE_FABLE_MYTHOS_5_PRICING, exchange, isClaudeFableOrMythos51Model, refreshClaudeOAuthToken, } from '@cortexkit/anthropic-auth-core';
|
|
2
2
|
import { registerCommands } from './commands.js';
|
|
3
|
+
import { collectPiEffortHistory } from './effort-history.js';
|
|
3
4
|
import { streamCortexKitAnthropic } from './stream.js';
|
|
4
5
|
async function loginAnthropic(callbacks) {
|
|
5
6
|
const auth = await authorize('max');
|
|
@@ -32,25 +33,51 @@ async function refreshAnthropicToken(credentials) {
|
|
|
32
33
|
}
|
|
33
34
|
export default function cortexKitPiAnthropicAuth(pi) {
|
|
34
35
|
registerCommands(pi);
|
|
36
|
+
const effortHistoryBySession = new Map();
|
|
37
|
+
pi.on('turn_start', async (_event, ctx) => {
|
|
38
|
+
const sessionId = ctx.sessionManager.getSessionId();
|
|
39
|
+
if (!sessionId)
|
|
40
|
+
return;
|
|
41
|
+
const transitions = collectPiEffortHistory(ctx.sessionManager.buildContextEntries(), ctx.sessionManager.getBranch());
|
|
42
|
+
effortHistoryBySession.delete(sessionId);
|
|
43
|
+
effortHistoryBySession.set(sessionId, transitions);
|
|
44
|
+
while (effortHistoryBySession.size > 128) {
|
|
45
|
+
const oldest = effortHistoryBySession.keys().next().value;
|
|
46
|
+
if (oldest)
|
|
47
|
+
effortHistoryBySession.delete(oldest);
|
|
48
|
+
else
|
|
49
|
+
break;
|
|
50
|
+
}
|
|
51
|
+
});
|
|
52
|
+
pi.on('session_shutdown', async (_event, ctx) => {
|
|
53
|
+
const sessionId = ctx.sessionManager.getSessionId();
|
|
54
|
+
if (sessionId)
|
|
55
|
+
effortHistoryBySession.delete(sessionId);
|
|
56
|
+
});
|
|
35
57
|
pi.registerProvider('anthropic', {
|
|
36
58
|
name: 'Anthropic (CortexKit OAuth)',
|
|
37
59
|
baseUrl: 'https://api.anthropic.com',
|
|
38
60
|
api: 'cortexkit-anthropic-messages',
|
|
39
61
|
models: [
|
|
40
|
-
...Object.values(CLAUDE_FABLE_MYTHOS_5_MODEL_SPECS).map((model) =>
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
62
|
+
...Object.values(CLAUDE_FABLE_MYTHOS_5_MODEL_SPECS).map((model) => {
|
|
63
|
+
const pricing = isClaudeFableOrMythos51Model(model.id)
|
|
64
|
+
? CLAUDE_FABLE_MYTHOS_5_1_PRICING
|
|
65
|
+
: CLAUDE_FABLE_MYTHOS_5_PRICING;
|
|
66
|
+
return {
|
|
67
|
+
id: model.id,
|
|
68
|
+
name: model.name,
|
|
69
|
+
reasoning: true,
|
|
70
|
+
input: textImageInput(),
|
|
71
|
+
cost: {
|
|
72
|
+
input: pricing.input,
|
|
73
|
+
output: pricing.output,
|
|
74
|
+
cacheRead: pricing.cacheRead,
|
|
75
|
+
cacheWrite: pricing.cacheWrite5m,
|
|
76
|
+
},
|
|
77
|
+
contextWindow: CLAUDE_FABLE_MYTHOS_5_CONTEXT_WINDOW,
|
|
78
|
+
maxTokens: CLAUDE_FABLE_MYTHOS_5_MAX_OUTPUT_TOKENS,
|
|
79
|
+
};
|
|
80
|
+
}),
|
|
54
81
|
{
|
|
55
82
|
id: 'claude-opus-5',
|
|
56
83
|
name: 'Claude Opus 5',
|
|
@@ -103,6 +130,8 @@ export default function cortexKitPiAnthropicAuth(pi) {
|
|
|
103
130
|
refreshToken: refreshAnthropicToken,
|
|
104
131
|
getApiKey: (credentials) => credentials.access,
|
|
105
132
|
},
|
|
106
|
-
streamSimple: streamCortexKitAnthropic,
|
|
133
|
+
streamSimple: (model, context, options) => streamCortexKitAnthropic(model, context, options, options?.sessionId
|
|
134
|
+
? effortHistoryBySession.get(options.sessionId)
|
|
135
|
+
: undefined),
|
|
107
136
|
});
|
|
108
137
|
}
|
package/dist/stream.d.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { type ApiKeyAccount } from '@cortexkit/anthropic-auth-core';
|
|
1
|
+
import { type ApiKeyAccount, type MidConversationEffortTransition } from '@cortexkit/anthropic-auth-core';
|
|
2
2
|
import { type Api, type AssistantMessageEventStream, type Context, type Model, type SimpleStreamOptions } from '@earendil-works/pi-ai';
|
|
3
3
|
export declare function clearPiStickyRoutingSession(storagePath: string, sessionId: string): Promise<void>;
|
|
4
4
|
export declare function getPiTrackedCacheKeepSessions(): Promise<import("@cortexkit/anthropic-auth-core").CacheKeepTrackedSession[]>;
|
|
@@ -16,5 +16,5 @@ export declare function buildExplicitBaseMessagesUrl(baseURL: string): URL;
|
|
|
16
16
|
export declare function configureApiRouteHeaders(account: ApiKeyAccount, fastMode: boolean): Headers;
|
|
17
17
|
export declare function parseSse(response: Response): AsyncGenerator<AnthropicEvent>;
|
|
18
18
|
export declare function primaryResponseAllowsApiFallback(preflight: Response | string): boolean;
|
|
19
|
-
export declare function streamCortexKitAnthropic(model: Model<Api>, context: Context, options?: SimpleStreamOptions): AssistantMessageEventStream;
|
|
19
|
+
export declare function streamCortexKitAnthropic(model: Model<Api>, context: Context, options?: SimpleStreamOptions, effortTransitions?: readonly MidConversationEffortTransition[]): AssistantMessageEventStream;
|
|
20
20
|
export {};
|
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, 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';
|
|
1
|
+
import { applyClaudeCodeHeaders, CACHE_KEEP_EXTENDED_TTL_BETA, CacheKeepManager, CacheKeepSessionRegistry, createStickyNoRouteResponse, decideStickyQuotaFailure, dumpDirectRequest, FAST_MODE_BETA, FallbackAccountManager, getCache1hPersistentMode, getDefaultCacheKeepRegistryDirectory, getFallbackReauthLabels, getOrCreateMainAccountId, getRelayConfig, getRoutingMode, getStickyRoutingStatePath, getThinkingPrefixMismatchBehavior, hasThinkingBindingControls, isApiKeyAccount, isCache1hPersistentlyEnabled, isCacheKeepHybridActive, isDumpPersistentlyEnabled, isFastModePersistentlyEnabled, isKillswitchEnabled, isOAuthAccount, isPermanentRefreshError, isValidApiBaseURL, killswitchPassesPolicy, loadAccounts, MID_CONVERSATION_OUTPUT_CONFIG_BETA, mergeAnthropicBetas, QuotaManager, quotaSnapshotHasStandardWindows, quotaSnapshotModelScopeIsExhausted, quotaSnapshotPassesModelScope, quotaSnapshotPassesPolicy, refreshBackoffActive, resolveClaudeCodeIdentity, STICKY_ROUTING_MAIN_ACCOUNT_ID, StickySessionRouter, sendViaRelay, setDumpEnabled, shouldFallbackStatus, stickyQuotaSnapshotIsFresh, stickyRetryAfterWithJitter, stickyRouteFamilyForModel, THINKING_BINDING_CONTROLS_BETA, tokenFingerprint, usesMidConversationOutputConfig, } 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';
|
|
@@ -90,10 +90,16 @@ const cacheKeepManager = new CacheKeepManager({
|
|
|
90
90
|
const storage = await loadAccounts(storagePath);
|
|
91
91
|
const identity = await resolveClaudeCodeIdentity(accessToken, typeof body.model === 'string' ? body.model : undefined, target.oauthAccountId ?? storage?.mainAccountId);
|
|
92
92
|
headers.delete('anthropic-beta');
|
|
93
|
-
applyClaudeCodeHeaders(headers, accessToken, {
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
93
|
+
applyClaudeCodeHeaders(headers, accessToken, {
|
|
94
|
+
body,
|
|
95
|
+
identity,
|
|
96
|
+
extraBetas: [
|
|
97
|
+
CACHE_KEEP_EXTENDED_TTL_BETA,
|
|
98
|
+
...(hasThinkingBindingControls(body)
|
|
99
|
+
? [THINKING_BINDING_CONTROLS_BETA]
|
|
100
|
+
: []),
|
|
101
|
+
],
|
|
102
|
+
});
|
|
97
103
|
if (body.speed === 'fast') {
|
|
98
104
|
headers.set('anthropic-beta', mergeAnthropicBetas(headers.get('anthropic-beta'), [FAST_MODE_BETA]));
|
|
99
105
|
}
|
|
@@ -230,13 +236,26 @@ async function sendAnthropicRequest(options) {
|
|
|
230
236
|
const { body, bodyText } = await buildAnthropicRequest(options.model.id, options.context, options.streamOptions, {
|
|
231
237
|
enabled: isCache1hPersistentlyEnabled(storage),
|
|
232
238
|
mode: getCache1hPersistentMode(storage),
|
|
233
|
-
}, isFastModePersistentlyEnabled(storage), identity
|
|
239
|
+
}, isFastModePersistentlyEnabled(storage), identity, {
|
|
240
|
+
effortTransitions: options.apiAccount ? [] : options.effortTransitions,
|
|
241
|
+
thinkingPrefixMismatchBehavior: options.apiAccount
|
|
242
|
+
? 'account-default'
|
|
243
|
+
: getThinkingPrefixMismatchBehavior(storage),
|
|
244
|
+
});
|
|
234
245
|
const fastMode = body.speed === 'fast';
|
|
235
246
|
const headers = options.apiAccount
|
|
236
247
|
? configureApiRouteHeaders(options.apiAccount, fastMode)
|
|
237
248
|
: applyClaudeCodeHeaders(new Headers(), options.accessToken ?? '', {
|
|
238
249
|
body,
|
|
239
250
|
identity,
|
|
251
|
+
extraBetas: [
|
|
252
|
+
...(hasThinkingBindingControls(body)
|
|
253
|
+
? [THINKING_BINDING_CONTROLS_BETA]
|
|
254
|
+
: []),
|
|
255
|
+
...(usesMidConversationOutputConfig(body)
|
|
256
|
+
? [MID_CONVERSATION_OUTPUT_CONFIG_BETA]
|
|
257
|
+
: []),
|
|
258
|
+
],
|
|
240
259
|
});
|
|
241
260
|
if (!options.apiAccount && fastMode) {
|
|
242
261
|
headers.set('anthropic-beta', mergeAnthropicBetas(headers.get('anthropic-beta'), [FAST_MODE_BETA]));
|
|
@@ -474,7 +493,7 @@ async function executeWithFallback(options) {
|
|
|
474
493
|
(configured.expires !== undefined &&
|
|
475
494
|
configured.expires <= Date.now()) ||
|
|
476
495
|
isPermanentRefreshError(configured.lastRefreshError) ||
|
|
477
|
-
refreshBackoffActive(configured.lastRefreshError, configured.id, Date.now()))
|
|
496
|
+
refreshBackoffActive(configured.lastRefreshError, configured.id, Date.now(), tokenFingerprint(configured.refresh)))
|
|
478
497
|
continue;
|
|
479
498
|
account = configured;
|
|
480
499
|
const quota = quotaManager.getFallback(configured.id, configured)?.quota ??
|
|
@@ -786,7 +805,7 @@ async function executeWithFallback(options) {
|
|
|
786
805
|
}
|
|
787
806
|
return primaryPreflight instanceof Response ? primaryPreflight : primary;
|
|
788
807
|
}
|
|
789
|
-
export function streamCortexKitAnthropic(model, context, options) {
|
|
808
|
+
export function streamCortexKitAnthropic(model, context, options, effortTransitions) {
|
|
790
809
|
const stream = createAssistantMessageEventStream();
|
|
791
810
|
void (async () => {
|
|
792
811
|
const output = createOutput(model);
|
|
@@ -802,6 +821,7 @@ export function streamCortexKitAnthropic(model, context, options) {
|
|
|
802
821
|
streamOptions: options,
|
|
803
822
|
primaryAccessToken: accessToken,
|
|
804
823
|
storagePath,
|
|
824
|
+
effortTransitions,
|
|
805
825
|
});
|
|
806
826
|
if (!response.ok) {
|
|
807
827
|
throw new Error(`Anthropic request failed: HTTP ${response.status} ${await response.text()}`);
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@cortexkit/pi-anthropic-auth",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.22.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.22.0"
|
|
40
40
|
},
|
|
41
41
|
"peerDependencies": {
|
|
42
42
|
"@earendil-works/pi-ai": "*",
|