@cortexkit/pi-anthropic-auth 1.23.0 → 2.0.1
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 +50 -58
- package/dist/commands.d.ts +23 -3
- package/dist/commands.js +58 -252
- package/dist/convert.d.ts +4 -0
- package/dist/convert.js +36 -19
- package/dist/custody.d.ts +2 -6
- package/dist/custody.js +5 -38
- package/dist/index.d.ts +2 -3
- package/dist/index.js +124 -68
- package/dist/native-commands.d.ts +2 -0
- package/dist/native-commands.js +334 -0
- package/dist/native.d.ts +72 -0
- package/dist/native.js +308 -0
- package/dist/paths.d.ts +2 -0
- package/dist/paths.js +6 -0
- package/dist/stream.d.ts +17 -3
- package/dist/stream.js +544 -427
- package/dist/transcript.d.ts +19 -0
- package/dist/transcript.js +122 -0
- package/dist/transport.d.ts +5 -0
- package/dist/transport.js +30 -0
- package/package.json +2 -2
package/dist/convert.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import { applyClaudeCodeMetadata, applyMidConversationOutputConfig, applyThinkingBindingControls, buildBillingHeaderValue, CLAUDE_CODE_ENTRYPOINT, CLAUDE_CODE_IDENTITY, CLAUDE_FABLE_MYTHOS_5_SUMMARIZED_THINKING, CLAUDE_OPUS_5_5_ADAPTIVE_THINKING, CLAUDE_OPUS_5_ADAPTIVE_THINKING, CLAUDE_SONNET_5_ADAPTIVE_THINKING, ClaudeCodeFirstUserTextTracker, isClaudeFableOrMythos5Model, isClaudeOpus5Model, isClaudeOpus55Model, isClaudeSonnet5Model, isFastModeSupportedModel, isOpenAIReasoningSignature, orderClaudeCodeBody, signRequestBody, } from '@cortexkit/anthropic-auth-core';
|
|
2
|
-
import { collapseSystemMessages, getCurrentSystemPrompt, getCurrentTools, normalizeContext, } from '
|
|
1
|
+
import { applyClaudeCodeMetadata, applyMidConversationOutputConfig, applyThinkingBindingControls, assertNoMeaningfulTrailingAssistant, buildBillingHeaderValue, CLAUDE_CODE_ENTRYPOINT, CLAUDE_CODE_IDENTITY, CLAUDE_FABLE_MYTHOS_5_SUMMARIZED_THINKING, CLAUDE_HAIKU_5_5_ADAPTIVE_THINKING, CLAUDE_OPUS_5_5_ADAPTIVE_THINKING, CLAUDE_OPUS_5_ADAPTIVE_THINKING, CLAUDE_SONNET_5_5_ADAPTIVE_THINKING, CLAUDE_SONNET_5_ADAPTIVE_THINKING, ClaudeCodeFirstUserTextTracker, isClaudeFableOrMythos5Model, isClaudeHaiku55Model, isClaudeOpus5Model, isClaudeOpus55Model, isClaudeSonnet5Model, isClaudeSonnet55Model, isFastModeSupportedModel, isOpenAIReasoningSignature, orderClaudeCodeBody, signRequestBody, stripEmptyTrailingAssistantMessages, } from '@cortexkit/anthropic-auth-core';
|
|
2
|
+
import { collapseSystemMessages, getCurrentSystemPrompt, getCurrentTools, normalizeContext, } from './transcript.js';
|
|
3
3
|
// Anchor identifying Pi's documentation paragraph — the only part of the prompt
|
|
4
4
|
// that Anthropic currently rejects in system[]. Unknown prompt shapes take the
|
|
5
5
|
// service-preserving fallback below instead of returning the full prompt there.
|
|
@@ -433,9 +433,10 @@ function applyCacheMode(body, enabled, mode) {
|
|
|
433
433
|
});
|
|
434
434
|
}
|
|
435
435
|
export async function buildAnthropicRequest(modelId, context, options, cache, fastModeEnabled = false, identity, controls = {}) {
|
|
436
|
-
// Pi 0.86 passes a normalized transcript to providers
|
|
437
|
-
//
|
|
438
|
-
// prompts (including ordered OMP
|
|
436
|
+
// Pi 0.86 passes a normalized transcript to providers, and later system
|
|
437
|
+
// messages can change the prompt, its named sections and the tool set. Resolve
|
|
438
|
+
// them through the local replay port; raw host prompts (including ordered OMP
|
|
439
|
+
// blocks) still enter through normalization.
|
|
439
440
|
const transcript = collapseSystemMessages(normalizeContext({
|
|
440
441
|
...context,
|
|
441
442
|
systemPrompt: systemPromptText(context.systemPrompt),
|
|
@@ -445,12 +446,12 @@ export async function buildAnthropicRequest(modelId, context, options, cache, fa
|
|
|
445
446
|
systemPrompt: getCurrentSystemPrompt(transcript.messages),
|
|
446
447
|
tools: getCurrentTools(transcript.messages),
|
|
447
448
|
};
|
|
449
|
+
// Conversion can discard opaque or incomplete blocks. Check context.messages
|
|
450
|
+
// first so those losses cannot hide a meaningful final assistant turn. Check
|
|
451
|
+
// the Anthropic messages again after conversion removes empty user messages.
|
|
452
|
+
assertNoMeaningfulTrailingAssistant(context.messages);
|
|
448
453
|
const messages = convertMessages(context.messages, modelId);
|
|
449
|
-
|
|
450
|
-
while (messages.length &&
|
|
451
|
-
messages[messages.length - 1]?.role === 'assistant') {
|
|
452
|
-
messages.pop();
|
|
453
|
-
}
|
|
454
|
+
stripEmptyTrailingAssistantMessages(messages);
|
|
454
455
|
const system = [
|
|
455
456
|
{
|
|
456
457
|
type: 'text',
|
|
@@ -507,18 +508,23 @@ export async function buildAnthropicRequest(modelId, context, options, cache, fa
|
|
|
507
508
|
}
|
|
508
509
|
const isFableOrMythos5 = isClaudeFableOrMythos5Model(modelId);
|
|
509
510
|
const isSonnet5 = isClaudeSonnet5Model(modelId);
|
|
511
|
+
const isSonnet55 = isClaudeSonnet55Model(modelId);
|
|
512
|
+
const isHaiku55 = isClaudeHaiku55Model(modelId);
|
|
510
513
|
const isOpus5 = isClaudeOpus5Model(modelId);
|
|
511
514
|
const isOpus55 = isClaudeOpus55Model(modelId);
|
|
512
|
-
//
|
|
513
|
-
//
|
|
514
|
-
//
|
|
515
|
-
//
|
|
516
|
-
// the raw-body path). Each model refs its own per-family constant —
|
|
517
|
-
// families can diverge, so the constant rather than a shared alias keeps
|
|
518
|
-
// the call sites explicit.
|
|
515
|
+
// Request summaries so the host can display adaptive reasoning.
|
|
516
|
+
// Pi's typed options cannot express the disabled-thinking setting;
|
|
517
|
+
// OpenCode handles it by transforming the raw request body. Separate model
|
|
518
|
+
// constants let each model's thinking configuration change independently.
|
|
519
519
|
if (isFableOrMythos5) {
|
|
520
520
|
body.thinking = { ...CLAUDE_FABLE_MYTHOS_5_SUMMARIZED_THINKING };
|
|
521
521
|
}
|
|
522
|
+
else if (isHaiku55) {
|
|
523
|
+
body.thinking = { ...CLAUDE_HAIKU_5_5_ADAPTIVE_THINKING };
|
|
524
|
+
}
|
|
525
|
+
else if (isSonnet55) {
|
|
526
|
+
body.thinking = { ...CLAUDE_SONNET_5_5_ADAPTIVE_THINKING };
|
|
527
|
+
}
|
|
522
528
|
else if (isSonnet5) {
|
|
523
529
|
body.thinking = { ...CLAUDE_SONNET_5_ADAPTIVE_THINKING };
|
|
524
530
|
}
|
|
@@ -529,7 +535,15 @@ export async function buildAnthropicRequest(modelId, context, options, cache, fa
|
|
|
529
535
|
body.thinking = { ...CLAUDE_OPUS_5_ADAPTIVE_THINKING };
|
|
530
536
|
}
|
|
531
537
|
if (options?.reasoning) {
|
|
532
|
-
if (
|
|
538
|
+
if ((isSonnet55 || isHaiku55) && options.reasoning === 'minimal') {
|
|
539
|
+
throw new Error(`${isHaiku55 ? 'Claude Haiku 5.5' : 'Claude Sonnet 5.5'} does not support minimal effort`);
|
|
540
|
+
}
|
|
541
|
+
if (isFableOrMythos5 ||
|
|
542
|
+
isSonnet5 ||
|
|
543
|
+
isSonnet55 ||
|
|
544
|
+
isHaiku55 ||
|
|
545
|
+
isOpus5 ||
|
|
546
|
+
isOpus55) {
|
|
533
547
|
body.output_config = { effort: options.reasoning };
|
|
534
548
|
}
|
|
535
549
|
else {
|
|
@@ -557,5 +571,8 @@ export async function buildAnthropicRequest(modelId, context, options, cache, fa
|
|
|
557
571
|
}
|
|
558
572
|
const unsigned = JSON.stringify(orderClaudeCodeBody(body));
|
|
559
573
|
const bodyText = await signRequestBody(unsigned);
|
|
560
|
-
|
|
574
|
+
// The stream decoder must use the exact tool set that produced this body.
|
|
575
|
+
// Pi 0.86's transcript has no top-level context.tools, and normalizing it
|
|
576
|
+
// again after dispatch would duplicate work and risk a different mapping.
|
|
577
|
+
return { body, bodyText, hostTools: context.tools ?? [] };
|
|
561
578
|
}
|
package/dist/custody.d.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { type AccountCommandResult, type ClaustrumEnrollmentStatus, type ClaustrumMode
|
|
1
|
+
import { type AccountCommandResult, type ClaustrumEnrollmentStatus, type ClaustrumMode } from '@cortexkit/anthropic-auth-core';
|
|
2
2
|
export declare function requirePiEnrollment(): Promise<{
|
|
3
3
|
state: 'approved';
|
|
4
4
|
proposedName: string;
|
|
@@ -10,8 +10,4 @@ export interface PiCustodyCommands {
|
|
|
10
10
|
status(): Promise<ClaustrumEnrollmentStatus>;
|
|
11
11
|
reset(): Promise<AccountCommandResult>;
|
|
12
12
|
}
|
|
13
|
-
export declare function createPiCustodyCommands(
|
|
14
|
-
reconfigure: () => Promise<void>;
|
|
15
|
-
storagePath?: string;
|
|
16
|
-
connect?: () => Promise<ClaustrumScopedClient>;
|
|
17
|
-
}): PiCustodyCommands;
|
|
13
|
+
export declare function createPiCustodyCommands(): PiCustodyCommands;
|
package/dist/custody.js
CHANGED
|
@@ -1,5 +1,4 @@
|
|
|
1
|
-
import { CLAUSTRUM_PI_ENROLLMENT_NAME,
|
|
2
|
-
import { getPiAccountStoragePath, getPiClaustrumConnectionOptions, hasPiLocalAnthropicOAuth, } from './paths.js';
|
|
1
|
+
import { CLAUSTRUM_PI_ENROLLMENT_NAME, getHostClaustrumEnrollmentPaths, readClaustrumEnrollmentStatus, resetClaustrumEnrollmentState, } from '@cortexkit/anthropic-auth-core';
|
|
3
2
|
export async function requirePiEnrollment() {
|
|
4
3
|
const status = await readClaustrumEnrollmentStatus(getHostClaustrumEnrollmentPaths('pi'), CLAUSTRUM_PI_ENROLLMENT_NAME);
|
|
5
4
|
if (status.state !== 'approved' ||
|
|
@@ -8,8 +7,7 @@ export async function requirePiEnrollment() {
|
|
|
8
7
|
}
|
|
9
8
|
return status;
|
|
10
9
|
}
|
|
11
|
-
export function createPiCustodyCommands(
|
|
12
|
-
const storagePath = options.storagePath ?? getPiAccountStoragePath();
|
|
10
|
+
export function createPiCustodyCommands() {
|
|
13
11
|
const paths = () => getHostClaustrumEnrollmentPaths('pi');
|
|
14
12
|
return {
|
|
15
13
|
status: () => readClaustrumEnrollmentStatus(paths(), CLAUSTRUM_PI_ENROLLMENT_NAME),
|
|
@@ -25,41 +23,10 @@ export function createPiCustodyCommands(options) {
|
|
|
25
23
|
return { text: messages[result] };
|
|
26
24
|
},
|
|
27
25
|
async transition(mode) {
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
return {
|
|
31
|
-
text: 'Refused: Pi still has a local Anthropic OAuth credential. Run `bunx @cortexkit/opencode-anthropic-auth setup` to approve its removal and enable Claustrum.',
|
|
32
|
-
};
|
|
33
|
-
}
|
|
34
|
-
// A slash command never invokes the administrative CLI or approves itself.
|
|
35
|
-
// Existing enrollment and grants must be verified before committing mode.
|
|
36
|
-
await requirePiEnrollment();
|
|
37
|
-
const client = await (options.connect?.() ??
|
|
38
|
-
connectClaustrumScopedClient(getPiClaustrumConnectionOptions(storagePath)));
|
|
39
|
-
const custody = new ClaustrumScopedCustody({
|
|
40
|
-
client,
|
|
41
|
-
tokenPath: paths().tokenPath,
|
|
42
|
-
});
|
|
43
|
-
try {
|
|
44
|
-
const inventory = await custody.discover();
|
|
45
|
-
const active = inventory.accounts.filter((account) => account.state === 'active');
|
|
46
|
-
if (!active.length)
|
|
47
|
-
return {
|
|
48
|
-
text: 'Refused: Claustrum has no accessible active Anthropic accounts.',
|
|
49
|
-
};
|
|
50
|
-
for (const account of active)
|
|
51
|
-
await custody.authorize(account);
|
|
52
|
-
}
|
|
53
|
-
finally {
|
|
54
|
-
custody.close();
|
|
55
|
-
}
|
|
56
|
-
}
|
|
57
|
-
await setClaustrumModePersistent(mode, storagePath);
|
|
58
|
-
await options.reconfigure();
|
|
26
|
+
// Mode changes can remove host credentials and require offline consent.
|
|
27
|
+
// A menu never enrolls, grants custody or writes the authority journal.
|
|
59
28
|
return {
|
|
60
|
-
text: mode
|
|
61
|
-
? 'Pi now uses Claustrum for Anthropic authentication.'
|
|
62
|
-
: 'Pi now uses local Anthropic authentication. Use /login anthropic if needed.',
|
|
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.`,
|
|
63
30
|
};
|
|
64
31
|
},
|
|
65
32
|
};
|
package/dist/index.d.ts
CHANGED
|
@@ -1,6 +1,5 @@
|
|
|
1
|
-
import { type
|
|
1
|
+
import { type NativeCustodyClient } from '@cortexkit/anthropic-auth-core';
|
|
2
2
|
import type { ExtensionAPI } from '@earendil-works/pi-coding-agent';
|
|
3
3
|
export default function cortexKitPiAnthropicAuth(pi: ExtensionAPI, options?: {
|
|
4
|
-
connectScoped?: () => Promise<
|
|
5
|
-
pollIntervalMs?: number;
|
|
4
|
+
connectScoped?: () => Promise<NativeCustodyClient>;
|
|
6
5
|
}): Promise<void>;
|
package/dist/index.js
CHANGED
|
@@ -1,54 +1,43 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { 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, CLAUDE_HAIKU_5_5_CONTEXT_WINDOW, CLAUDE_HAIKU_5_5_LONG_CONTEXT_PRICING, CLAUDE_HAIKU_5_5_LONG_CONTEXT_THRESHOLD, CLAUDE_HAIKU_5_5_MAX_OUTPUT_TOKENS, CLAUDE_HAIKU_5_5_MODEL_ID, CLAUDE_HAIKU_5_5_PRICING, CLAUDE_SONNET_5_5_CONTEXT_WINDOW, CLAUDE_SONNET_5_5_MAX_OUTPUT_TOKENS, CLAUDE_SONNET_5_5_MODEL_ID, CLAUDE_SONNET_5_5_PRICING, isClaudeFableOrMythos51Model, readNativeEnrollmentMode, } from '@cortexkit/anthropic-auth-core';
|
|
2
2
|
import { registerCommands } from './commands.js';
|
|
3
|
-
import { createPiCustodyCommands, requirePiEnrollment } from './custody.js';
|
|
4
3
|
import { collectPiEffortHistory, deriveContextEntries, } from './effort-history.js';
|
|
5
|
-
import {
|
|
6
|
-
import {
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
'claustrum') {
|
|
10
|
-
throw new Error('Local Anthropic login and refresh are disabled while Claustrum custody is active');
|
|
11
|
-
}
|
|
12
|
-
}
|
|
13
|
-
async function loginAnthropic(callbacks) {
|
|
14
|
-
await assertLocalAuthentication();
|
|
15
|
-
const auth = await authorize('max');
|
|
16
|
-
callbacks.onAuth({ url: auth.url });
|
|
17
|
-
const callback = await callbacks.onPrompt({
|
|
18
|
-
message: 'Paste the Claude OAuth callback URL or code:',
|
|
19
|
-
});
|
|
20
|
-
const result = await exchange(callback, auth.verifier, auth.redirectUri, auth.state);
|
|
21
|
-
if (result.type !== 'success') {
|
|
22
|
-
throw new Error('Anthropic OAuth exchange failed');
|
|
23
|
-
}
|
|
24
|
-
await assertLocalAuthentication();
|
|
25
|
-
return {
|
|
26
|
-
refresh: result.refresh,
|
|
27
|
-
access: result.access,
|
|
28
|
-
expires: result.expires,
|
|
29
|
-
};
|
|
30
|
-
}
|
|
4
|
+
import { closePiNativeRuntime, getPiNativeRuntime, isNativeMigrationRequired, } from './native.js';
|
|
5
|
+
import { createPiNativeCommands } from './native-commands.js';
|
|
6
|
+
import { getPiAccountStoragePath, requirePiNativeHostAuth } from './paths.js';
|
|
7
|
+
import { streamCortexKitAnthropic } from './stream.js';
|
|
31
8
|
function textImageInput() {
|
|
32
9
|
return ['text', 'image'];
|
|
33
10
|
}
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
11
|
+
/**
|
|
12
|
+
* Refuses every Anthropic prompt with Core's migration message. Registered
|
|
13
|
+
* only when startup found an install that offline setup has never migrated.
|
|
14
|
+
* Pi checks a prompt's credentials after its input handlers run. Handling the
|
|
15
|
+
* input here stops it before that check, which would otherwise answer with
|
|
16
|
+
* Pi's generic missing-key text for a 1.x install whose Pi login is still
|
|
17
|
+
* stored. Extension commands such as /claude run before input handlers, so
|
|
18
|
+
* they stay reachable.
|
|
19
|
+
*/
|
|
20
|
+
function refuseUnmigratedPrompts(pi, storagePath) {
|
|
21
|
+
pi.on('input', async (_event, ctx) => {
|
|
22
|
+
// Prompts for other providers do not use this install's accounts.
|
|
23
|
+
if (ctx.model?.provider !== 'anthropic')
|
|
24
|
+
return { action: 'continue' };
|
|
25
|
+
const refusal = await getPiNativeRuntime(storagePath).migrationRefusal();
|
|
26
|
+
if (!refusal)
|
|
27
|
+
return { action: 'continue' };
|
|
28
|
+
if (ctx.hasUI)
|
|
29
|
+
ctx.ui.notify(refusal.message, 'error');
|
|
30
|
+
else
|
|
31
|
+
process.stderr.write(`${refusal.message}\n`);
|
|
32
|
+
return { action: 'handled' };
|
|
38
33
|
});
|
|
39
|
-
return {
|
|
40
|
-
refresh: refreshed.refresh,
|
|
41
|
-
access: refreshed.access,
|
|
42
|
-
expires: refreshed.expires,
|
|
43
|
-
};
|
|
44
34
|
}
|
|
45
35
|
export default async function cortexKitPiAnthropicAuth(pi, options = {}) {
|
|
46
36
|
const storagePath = getPiAccountStoragePath();
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
}));
|
|
37
|
+
getPiNativeRuntime(storagePath, {
|
|
38
|
+
...(options.connectScoped && { connect: options.connectScoped }),
|
|
39
|
+
});
|
|
40
|
+
registerCommands(pi, createPiNativeCommands(storagePath));
|
|
52
41
|
const effortHistoryBySession = new Map();
|
|
53
42
|
pi.on('turn_start', async (_event, ctx) => {
|
|
54
43
|
const sessionId = ctx.sessionManager.getSessionId();
|
|
@@ -86,7 +75,7 @@ export default async function cortexKitPiAnthropicAuth(pi, options = {}) {
|
|
|
86
75
|
const sessionId = ctx.sessionManager.getSessionId();
|
|
87
76
|
if (sessionId)
|
|
88
77
|
effortHistoryBySession.delete(sessionId);
|
|
89
|
-
|
|
78
|
+
await closePiNativeRuntime(storagePath);
|
|
90
79
|
});
|
|
91
80
|
const configuration = {
|
|
92
81
|
name: 'Anthropic (CortexKit OAuth)',
|
|
@@ -166,47 +155,120 @@ export default async function cortexKitPiAnthropicAuth(pi, options = {}) {
|
|
|
166
155
|
contextWindow: 1_000_000,
|
|
167
156
|
maxTokens: 128_000,
|
|
168
157
|
},
|
|
158
|
+
{
|
|
159
|
+
id: CLAUDE_HAIKU_5_5_MODEL_ID,
|
|
160
|
+
name: 'Claude Haiku 5.5',
|
|
161
|
+
reasoning: true,
|
|
162
|
+
thinkingLevelMap: {
|
|
163
|
+
off: null,
|
|
164
|
+
minimal: null,
|
|
165
|
+
xhigh: 'xhigh',
|
|
166
|
+
max: 'max',
|
|
167
|
+
},
|
|
168
|
+
input: textImageInput(),
|
|
169
|
+
cost: {
|
|
170
|
+
input: CLAUDE_HAIKU_5_5_PRICING.input,
|
|
171
|
+
output: CLAUDE_HAIKU_5_5_PRICING.output,
|
|
172
|
+
cacheRead: CLAUDE_HAIKU_5_5_PRICING.cacheRead,
|
|
173
|
+
cacheWrite: CLAUDE_HAIKU_5_5_PRICING.cacheWrite5m,
|
|
174
|
+
tiers: [
|
|
175
|
+
{
|
|
176
|
+
inputTokensAbove: CLAUDE_HAIKU_5_5_LONG_CONTEXT_THRESHOLD,
|
|
177
|
+
input: CLAUDE_HAIKU_5_5_LONG_CONTEXT_PRICING.input,
|
|
178
|
+
output: CLAUDE_HAIKU_5_5_LONG_CONTEXT_PRICING.output,
|
|
179
|
+
cacheRead: CLAUDE_HAIKU_5_5_LONG_CONTEXT_PRICING.cacheRead,
|
|
180
|
+
cacheWrite: CLAUDE_HAIKU_5_5_LONG_CONTEXT_PRICING.cacheWrite5m,
|
|
181
|
+
},
|
|
182
|
+
],
|
|
183
|
+
},
|
|
184
|
+
contextWindow: CLAUDE_HAIKU_5_5_CONTEXT_WINDOW,
|
|
185
|
+
maxTokens: CLAUDE_HAIKU_5_5_MAX_OUTPUT_TOKENS,
|
|
186
|
+
},
|
|
187
|
+
{
|
|
188
|
+
id: CLAUDE_SONNET_5_5_MODEL_ID,
|
|
189
|
+
name: 'Claude Sonnet 5.5',
|
|
190
|
+
reasoning: true,
|
|
191
|
+
thinkingLevelMap: {
|
|
192
|
+
off: null,
|
|
193
|
+
minimal: null,
|
|
194
|
+
xhigh: 'xhigh',
|
|
195
|
+
max: 'max',
|
|
196
|
+
},
|
|
197
|
+
input: textImageInput(),
|
|
198
|
+
cost: {
|
|
199
|
+
input: CLAUDE_SONNET_5_5_PRICING.input,
|
|
200
|
+
output: CLAUDE_SONNET_5_5_PRICING.output,
|
|
201
|
+
cacheRead: CLAUDE_SONNET_5_5_PRICING.cacheRead,
|
|
202
|
+
cacheWrite: CLAUDE_SONNET_5_5_PRICING.cacheWrite5m,
|
|
203
|
+
},
|
|
204
|
+
contextWindow: CLAUDE_SONNET_5_5_CONTEXT_WINDOW,
|
|
205
|
+
maxTokens: CLAUDE_SONNET_5_5_MAX_OUTPUT_TOKENS,
|
|
206
|
+
},
|
|
169
207
|
],
|
|
170
|
-
oauth: {
|
|
171
|
-
name: 'Anthropic Claude Pro/Max (CortexKit)',
|
|
172
|
-
login: loginAnthropic,
|
|
173
|
-
refreshToken: refreshAnthropicToken,
|
|
174
|
-
getApiKey: (credentials) => credentials.access,
|
|
175
|
-
},
|
|
176
208
|
streamSimple: (model, context, options) => streamCortexKitAnthropic(model, context, options, options?.sessionId
|
|
177
209
|
? effortHistoryBySession.get(options.sessionId)
|
|
178
210
|
: undefined),
|
|
179
211
|
};
|
|
180
212
|
async function configureProvider() {
|
|
181
|
-
if (getClaustrumMode(await loadAccounts(storagePath)) !== 'claustrum') {
|
|
182
|
-
closePiScopedRuntime(storagePath);
|
|
183
|
-
pi.registerProvider('anthropic', configuration);
|
|
184
|
-
return;
|
|
185
|
-
}
|
|
186
213
|
const streamSimple = configuration.streamSimple;
|
|
187
214
|
if (!streamSimple)
|
|
188
215
|
throw new Error('Anthropic stream implementation is unavailable');
|
|
216
|
+
// Register vault-backed models even if no account can serve yet, so a
|
|
217
|
+
// repaired enrollment or re-login takes effect on the next request. Local
|
|
218
|
+
// credentials still require completed offline migration before serving.
|
|
219
|
+
const startupMode = await readNativeEnrollmentMode('pi').catch(() => undefined);
|
|
220
|
+
try {
|
|
221
|
+
if (startupMode === 'local')
|
|
222
|
+
await getPiNativeRuntime(storagePath).view();
|
|
223
|
+
}
|
|
224
|
+
catch (error) {
|
|
225
|
+
// An install that offline setup has never migrated, such as a 1.x
|
|
226
|
+
// install upgraded in place, must still load: a failed load drops the
|
|
227
|
+
// /claude menu and Pi exits at startup. Its prompts are refused instead.
|
|
228
|
+
// Any other failure stops the load as before.
|
|
229
|
+
const refusal = await getPiNativeRuntime(storagePath).migrationRefusal();
|
|
230
|
+
if (!refusal)
|
|
231
|
+
throw error;
|
|
232
|
+
refuseUnmigratedPrompts(pi, storagePath);
|
|
233
|
+
}
|
|
189
234
|
const configured = async () => {
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
235
|
+
const mode = await readNativeEnrollmentMode('pi').catch(() => undefined);
|
|
236
|
+
if (mode !== 'local')
|
|
237
|
+
return true;
|
|
238
|
+
await requirePiNativeHostAuth();
|
|
239
|
+
let snapshot;
|
|
240
|
+
try {
|
|
241
|
+
snapshot = await (await getPiNativeRuntime(storagePath).service()).read();
|
|
242
|
+
}
|
|
243
|
+
catch (error) {
|
|
244
|
+
// An unmigrated install still reports the provider as configured, so
|
|
245
|
+
// Pi keeps its Anthropic models selectable and its prompts reach the
|
|
246
|
+
// refusal above (or, from any other caller, the stream, which refuses
|
|
247
|
+
// with the same Core message). If this check threw instead, Pi would
|
|
248
|
+
// record the refusal as a startup availability error.
|
|
249
|
+
if (isNativeMigrationRequired(error))
|
|
250
|
+
return true;
|
|
251
|
+
throw error;
|
|
252
|
+
}
|
|
253
|
+
return snapshot.accounts.some((account) => account.type === 'oauth' &&
|
|
254
|
+
account.enabled &&
|
|
255
|
+
(account.source !== 'vault' || account.state === 'active'));
|
|
194
256
|
};
|
|
195
257
|
const provider = {
|
|
196
258
|
id: 'anthropic',
|
|
197
|
-
name: 'Anthropic (
|
|
259
|
+
name: 'Anthropic (CortexKit Native)',
|
|
198
260
|
baseUrl: 'https://api.anthropic.com',
|
|
199
261
|
auth: {
|
|
200
262
|
// Native ambient auth avoids fake keys and local OAuth refresh. Pi refuses
|
|
201
263
|
// a leftover stored OAuth credential because this provider has no OAuth
|
|
202
264
|
// handler; setup must obtain consent before removing that local entry.
|
|
203
265
|
apiKey: {
|
|
204
|
-
name: '
|
|
266
|
+
name: 'CortexKit Native',
|
|
205
267
|
check: async () => (await configured())
|
|
206
|
-
? { type: 'api_key', source: '
|
|
268
|
+
? { type: 'api_key', source: 'CortexKit Native' }
|
|
207
269
|
: undefined,
|
|
208
270
|
resolve: async () => (await configured())
|
|
209
|
-
? { auth: {}, source: '
|
|
271
|
+
? { auth: {}, source: 'CortexKit Native' }
|
|
210
272
|
: undefined,
|
|
211
273
|
},
|
|
212
274
|
},
|
|
@@ -221,12 +283,6 @@ export default async function cortexKitPiAnthropicAuth(pi, options = {}) {
|
|
|
221
283
|
streamSimple,
|
|
222
284
|
};
|
|
223
285
|
pi.registerProvider(provider);
|
|
224
|
-
getPiScopedRuntime(storagePath, {
|
|
225
|
-
...(options.connectScoped && { connect: options.connectScoped }),
|
|
226
|
-
...(options.pollIntervalMs !== undefined && {
|
|
227
|
-
pollIntervalMs: options.pollIntervalMs,
|
|
228
|
-
}),
|
|
229
|
-
}).start();
|
|
230
286
|
}
|
|
231
287
|
await configureProvider();
|
|
232
288
|
}
|