@cortexkit/anthropic-auth-core 1.21.0 → 1.23.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.
Files changed (59) hide show
  1. package/README.md +1 -1
  2. package/dist/accounts.d.ts +100 -3
  3. package/dist/accounts.js +1099 -169
  4. package/dist/auth.js +6 -10
  5. package/dist/cachekeep.d.ts +18 -1
  6. package/dist/cachekeep.js +108 -82
  7. package/dist/cch.d.ts +23 -9
  8. package/dist/cch.js +104 -21
  9. package/dist/claude-code.d.ts +8 -3
  10. package/dist/claude-code.js +24 -7
  11. package/dist/claustrum-enrollment-registry.d.ts +17 -0
  12. package/dist/claustrum-enrollment-registry.js +194 -0
  13. package/dist/claustrum-enrollment.d.ts +70 -0
  14. package/dist/claustrum-enrollment.js +485 -0
  15. package/dist/claustrum-scoped-roster.d.ts +23 -0
  16. package/dist/claustrum-scoped-roster.js +194 -0
  17. package/dist/claustrum-scoped-runtime.d.ts +28 -0
  18. package/dist/claustrum-scoped-runtime.js +230 -0
  19. package/dist/claustrum-scoped.d.ts +39 -0
  20. package/dist/claustrum-scoped.js +193 -0
  21. package/dist/claustrum.d.ts +252 -0
  22. package/dist/claustrum.js +1471 -0
  23. package/dist/commands/account.d.ts +43 -11
  24. package/dist/commands/account.js +147 -4
  25. package/dist/constants.d.ts +5 -5
  26. package/dist/constants.js +5 -5
  27. package/dist/custom-headers.d.ts +3 -0
  28. package/dist/custom-headers.js +102 -0
  29. package/dist/dump.js +2 -1
  30. package/dist/fast.js +1 -1
  31. package/dist/index.d.ts +11 -0
  32. package/dist/index.js +11 -0
  33. package/dist/json.d.ts +1 -0
  34. package/dist/json.js +10 -0
  35. package/dist/logger.js +3 -1
  36. package/dist/mid-conversation-output-config.d.ts +13 -0
  37. package/dist/mid-conversation-output-config.js +89 -0
  38. package/dist/model-remap.d.ts +27 -0
  39. package/dist/model-remap.js +72 -0
  40. package/dist/models.d.ts +46 -1
  41. package/dist/models.js +87 -8
  42. package/dist/network-errors.d.ts +1 -0
  43. package/dist/network-errors.js +27 -0
  44. package/dist/oauth-profile.d.ts +2 -1
  45. package/dist/oauth-profile.js +6 -0
  46. package/dist/prime.d.ts +11 -3
  47. package/dist/prime.js +25 -7
  48. package/dist/quota-header-feed.d.ts +32 -7
  49. package/dist/quota-header-feed.js +93 -10
  50. package/dist/quota-headers.js +59 -6
  51. package/dist/quota-manager.d.ts +20 -2
  52. package/dist/quota-manager.js +101 -24
  53. package/dist/relay.d.ts +8 -0
  54. package/dist/relay.js +72 -12
  55. package/dist/sticky-routing.d.ts +2 -0
  56. package/dist/sticky-routing.js +19 -1
  57. package/dist/thinking-binding.d.ts +7 -0
  58. package/dist/thinking-binding.js +54 -0
  59. package/package.json +4 -1
@@ -0,0 +1,89 @@
1
+ import { isClaudeFable51Model } from './models.js';
2
+ export const MID_CONVERSATION_OUTPUT_CONFIG_BETA = 'mid-conversation-output-config-2026-07-01';
3
+ function isRecord(value) {
4
+ return typeof value === 'object' && value !== null && !Array.isArray(value);
5
+ }
6
+ export function normalizeAdaptiveEffort(value) {
7
+ if (value === 'minimal')
8
+ return 'low';
9
+ if (value === 'low' ||
10
+ value === 'medium' ||
11
+ value === 'high' ||
12
+ value === 'xhigh' ||
13
+ value === 'max') {
14
+ return value;
15
+ }
16
+ return undefined;
17
+ }
18
+ export function usesMidConversationOutputConfig(body) {
19
+ return isClaudeFable51Model(body.model);
20
+ }
21
+ function compactTransitions(transitions) {
22
+ const compacted = [];
23
+ for (const transition of transitions) {
24
+ if (!Number.isSafeInteger(transition.afterAssistantMessages) ||
25
+ transition.afterAssistantMessages < 0 ||
26
+ !normalizeAdaptiveEffort(transition.effort)) {
27
+ continue;
28
+ }
29
+ const normalized = {
30
+ afterAssistantMessages: transition.afterAssistantMessages,
31
+ effort: transition.effort,
32
+ };
33
+ const previous = compacted.at(-1);
34
+ if (previous &&
35
+ previous.afterAssistantMessages === normalized.afterAssistantMessages) {
36
+ previous.effort = normalized.effort;
37
+ continue;
38
+ }
39
+ if (previous?.effort === normalized.effort)
40
+ continue;
41
+ compacted.push(normalized);
42
+ }
43
+ return compacted;
44
+ }
45
+ export function applyMidConversationOutputConfig(body, transitions) {
46
+ if (!usesMidConversationOutputConfig(body) || !Array.isArray(body.messages)) {
47
+ return { applied: false, inserted: 0 };
48
+ }
49
+ const compacted = compactTransitions(transitions);
50
+ const currentOutputConfig = isRecord(body.output_config)
51
+ ? body.output_config
52
+ : {};
53
+ const baseline = compacted[0]?.effort ??
54
+ normalizeAdaptiveEffort(currentOutputConfig.effort) ??
55
+ 'high';
56
+ body.output_config = { ...currentOutputConfig, effort: baseline };
57
+ if (compacted.length < 2)
58
+ return { applied: true, inserted: 0 };
59
+ const messages = body.messages;
60
+ const transitionsByBoundary = new Map();
61
+ for (const transition of compacted.slice(1)) {
62
+ transitionsByBoundary.set(transition.afterAssistantMessages, transition.effort);
63
+ }
64
+ let assistantMessages = 0;
65
+ let activeEffort = baseline;
66
+ let inserted = 0;
67
+ const rewritten = [];
68
+ for (const message of messages) {
69
+ if (isRecord(message) &&
70
+ message.role === 'user' &&
71
+ transitionsByBoundary.has(assistantMessages)) {
72
+ const effort = transitionsByBoundary.get(assistantMessages);
73
+ if (effort && effort !== activeEffort) {
74
+ rewritten.push({
75
+ role: 'system',
76
+ content: [],
77
+ output_config: { effort },
78
+ });
79
+ activeEffort = effort;
80
+ inserted++;
81
+ }
82
+ }
83
+ rewritten.push(message);
84
+ if (isRecord(message) && message.role === 'assistant')
85
+ assistantMessages++;
86
+ }
87
+ body.messages = rewritten;
88
+ return { applied: true, inserted };
89
+ }
@@ -0,0 +1,27 @@
1
+ /**
2
+ * Remap canonical Claude model IDs to proxy-compatible names
3
+ * using ANTHROPIC_DEFAULT_*_MODEL env vars.
4
+ *
5
+ * LiteLLM/proxy backends often use shorter model aliases
6
+ * (e.g. `claude-sonnet-4-6` instead of `claude-sonnet-4-20250514`).
7
+ * These proxy-route variables follow the Claude Code convention, except
8
+ * ANTHROPIC_DEFAULT_FABLE_MODEL, which is plugin-specific:
9
+ *
10
+ * ANTHROPIC_MODEL — default for any claude-* model
11
+ * ANTHROPIC_DEFAULT_SONNET_MODEL — models matching claude-sonnet-*
12
+ * ANTHROPIC_DEFAULT_OPUS_MODEL — models matching claude-opus-*
13
+ * ANTHROPIC_DEFAULT_HAIKU_MODEL — models matching claude-haiku-*
14
+ * ANTHROPIC_DEFAULT_FABLE_MODEL — models matching claude-fable / claude-mythos
15
+ *
16
+ * Tier-specific vars take precedence over the generic ANTHROPIC_MODEL.
17
+ */
18
+ /**
19
+ * Resolve a canonical model ID to its proxy-compatible alias.
20
+ * Returns the original model when no env override is configured.
21
+ */
22
+ export declare function remapModelId(model: string): string;
23
+ /**
24
+ * Remap the `model` field in a parsed request body in place.
25
+ * Returns true if the model was changed.
26
+ */
27
+ export declare function remapRequestBodyModel(parsed: Record<string, unknown>): boolean;
@@ -0,0 +1,72 @@
1
+ /**
2
+ * Remap canonical Claude model IDs to proxy-compatible names
3
+ * using ANTHROPIC_DEFAULT_*_MODEL env vars.
4
+ *
5
+ * LiteLLM/proxy backends often use shorter model aliases
6
+ * (e.g. `claude-sonnet-4-6` instead of `claude-sonnet-4-20250514`).
7
+ * These proxy-route variables follow the Claude Code convention, except
8
+ * ANTHROPIC_DEFAULT_FABLE_MODEL, which is plugin-specific:
9
+ *
10
+ * ANTHROPIC_MODEL — default for any claude-* model
11
+ * ANTHROPIC_DEFAULT_SONNET_MODEL — models matching claude-sonnet-*
12
+ * ANTHROPIC_DEFAULT_OPUS_MODEL — models matching claude-opus-*
13
+ * ANTHROPIC_DEFAULT_HAIKU_MODEL — models matching claude-haiku-*
14
+ * ANTHROPIC_DEFAULT_FABLE_MODEL — models matching claude-fable / claude-mythos
15
+ *
16
+ * Tier-specific vars take precedence over the generic ANTHROPIC_MODEL.
17
+ */
18
+ function getEnv(name) {
19
+ const value = process.env[name]?.trim();
20
+ return value || undefined;
21
+ }
22
+ function getModelTier(model) {
23
+ if (/^claude-sonnet(?:-|$)/.test(model))
24
+ return 'sonnet';
25
+ if (/^claude-opus(?:-|$)/.test(model))
26
+ return 'opus';
27
+ if (/^claude-haiku(?:-|$)/.test(model))
28
+ return 'haiku';
29
+ if (/^claude-(?:fable|mythos)(?:-|$)/.test(model))
30
+ return 'fable';
31
+ return null;
32
+ }
33
+ const TIER_ENV_MAP = {
34
+ sonnet: 'ANTHROPIC_DEFAULT_SONNET_MODEL',
35
+ opus: 'ANTHROPIC_DEFAULT_OPUS_MODEL',
36
+ haiku: 'ANTHROPIC_DEFAULT_HAIKU_MODEL',
37
+ fable: 'ANTHROPIC_DEFAULT_FABLE_MODEL',
38
+ };
39
+ /**
40
+ * Resolve a canonical model ID to its proxy-compatible alias.
41
+ * Returns the original model when no env override is configured.
42
+ */
43
+ export function remapModelId(model) {
44
+ if (typeof model !== 'string' || !model)
45
+ return model;
46
+ const tier = getModelTier(model);
47
+ if (tier) {
48
+ const tierModel = getEnv(TIER_ENV_MAP[tier]);
49
+ if (tierModel)
50
+ return tierModel;
51
+ }
52
+ // Generic fallback for any claude-* model
53
+ if (model.startsWith('claude-')) {
54
+ const defaultModel = getEnv('ANTHROPIC_MODEL');
55
+ if (defaultModel)
56
+ return defaultModel;
57
+ }
58
+ return model;
59
+ }
60
+ /**
61
+ * Remap the `model` field in a parsed request body in place.
62
+ * Returns true if the model was changed.
63
+ */
64
+ export function remapRequestBodyModel(parsed) {
65
+ if (typeof parsed.model !== 'string')
66
+ return false;
67
+ const remapped = remapModelId(parsed.model);
68
+ if (remapped === parsed.model)
69
+ return false;
70
+ parsed.model = remapped;
71
+ return true;
72
+ }
package/dist/models.d.ts CHANGED
@@ -1,5 +1,7 @@
1
1
  export declare const CLAUDE_FABLE_5_MODEL_ID = "claude-fable-5";
2
2
  export declare const CLAUDE_MYTHOS_5_MODEL_ID = "claude-mythos-5";
3
+ export declare const CLAUDE_FABLE_5_1_MODEL_ID = "claude-fable-5-1";
4
+ export declare const CLAUDE_MYTHOS_5_1_MODEL_ID = "claude-mythos-5-1";
3
5
  /**
4
6
  * Haiku 4.5 model identifier used by `/claude-prime` to start each OAuth
5
7
  * account's five-hour quota window with a minimal request. Usage is measured
@@ -7,6 +9,8 @@ export declare const CLAUDE_MYTHOS_5_MODEL_ID = "claude-mythos-5";
7
9
  * above so per-million-token cost estimation does not conflate families.
8
10
  */
9
11
  export declare const CLAUDE_HAIKU_4_5_MODEL_ID = "claude-haiku-4-5";
12
+ /** Remove OpenCode's context-window qualifier before model-family checks. */
13
+ export declare function normalizeAnthropicModelId(model: string): string;
10
14
  /**
11
15
  * Per-million-token USD pricing for Haiku 4.5. Used to project the cumulative
12
16
  * cost of prime requests from persisted usage counters — never persisted on
@@ -16,7 +20,8 @@ export declare const CLAUDE_HAIKU_4_5_PRICING: {
16
20
  readonly input: 1;
17
21
  readonly output: 5;
18
22
  };
19
- export declare const CLAUDE_FABLE_MYTHOS_5_MODEL_IDS: readonly ["claude-fable-5", "claude-mythos-5"];
23
+ export declare const CLAUDE_FABLE_MYTHOS_5_1_MODEL_IDS: readonly ["claude-fable-5-1", "claude-mythos-5-1"];
24
+ export declare const CLAUDE_FABLE_MYTHOS_5_MODEL_IDS: readonly ["claude-fable-5", "claude-mythos-5", "claude-fable-5-1", "claude-mythos-5-1"];
20
25
  export type ClaudeFableMythos5ModelId = (typeof CLAUDE_FABLE_MYTHOS_5_MODEL_IDS)[number];
21
26
  export declare const CLAUDE_FABLE_MYTHOS_5_SUMMARIZED_THINKING: {
22
27
  readonly type: 'adaptive';
@@ -29,15 +34,38 @@ export declare const CLAUDE_FABLE_MYTHOS_5_PRICING: {
29
34
  readonly cacheWrite5m: 12.5;
30
35
  readonly cacheWrite1h: 20;
31
36
  };
37
+ export declare const CLAUDE_FABLE_MYTHOS_5_1_PRICING: {
38
+ readonly input: 10;
39
+ readonly output: 50;
40
+ readonly cacheRead: 0.25;
41
+ readonly cacheWrite5m: 12.5;
42
+ readonly cacheWrite1h: 20;
43
+ };
32
44
  export declare const CLAUDE_FABLE_MYTHOS_5_CONTEXT_WINDOW = 1000000;
33
45
  export declare const CLAUDE_FABLE_MYTHOS_5_MAX_OUTPUT_TOKENS = 128000;
34
46
  export declare const CLAUDE_FABLE_MYTHOS_5_RELEASE_DATE = "2026-06-09";
47
+ export declare const CLAUDE_FABLE_MYTHOS_5_1_RELEASE_DATE = "2026-09-01";
35
48
  export declare const CLAUDE_FABLE_MYTHOS_5_MODEL_SPECS: Record<ClaudeFableMythos5ModelId, {
36
49
  id: ClaudeFableMythos5ModelId;
37
50
  name: string;
38
51
  limited?: boolean;
39
52
  }>;
53
+ export declare const CLAUDE_FABLE_MYTHOS_5_1_MODEL_SPECS: {
54
+ "claude-fable-5-1": {
55
+ id: ClaudeFableMythos5ModelId;
56
+ name: string;
57
+ limited?: boolean;
58
+ };
59
+ "claude-mythos-5-1": {
60
+ id: ClaudeFableMythos5ModelId;
61
+ name: string;
62
+ limited?: boolean;
63
+ };
64
+ };
40
65
  export declare function isClaudeFableOrMythos5Model(model: unknown): boolean;
66
+ export declare function isClaudeFableOrMythos51Model(model: unknown): boolean;
67
+ export declare function isClaudeFable51Model(model: unknown): boolean;
68
+ export declare function getClaudeFableMythos5ReleaseDate(model: unknown): "2026-06-09" | "2026-09-01";
41
69
  export declare const CLAUDE_SONNET_5_MODEL_ID = "claude-sonnet-5";
42
70
  /**
43
71
  * Sonnet 5 enables adaptive thinking by default but ships `display: "omitted"`,
@@ -64,4 +92,21 @@ export declare const CLAUDE_OPUS_5_ADAPTIVE_THINKING: {
64
92
  readonly display: 'summarized';
65
93
  };
66
94
  export declare function isClaudeOpus5Model(model: unknown): boolean;
95
+ export declare const CLAUDE_OPUS_5_5_MODEL_ID = "claude-opus-5-5";
96
+ export declare const CLAUDE_OPUS_5_5_RELEASE_DATE = "2026-09-18";
97
+ export declare const CLAUDE_OPUS_5_5_CONTEXT_WINDOW = 1000000;
98
+ export declare const CLAUDE_OPUS_5_5_MAX_OUTPUT_TOKENS = 128000;
99
+ export declare const CLAUDE_OPUS_5_5_PRICING: {
100
+ readonly input: 4;
101
+ readonly output: 20;
102
+ readonly cacheRead: 0.2;
103
+ readonly cacheWrite5m: 5;
104
+ readonly cacheWrite1h: 8;
105
+ };
106
+ export declare const CLAUDE_OPUS_5_5_ADAPTIVE_THINKING: {
107
+ readonly type: 'adaptive';
108
+ readonly display: 'summarized';
109
+ };
110
+ export declare function isClaudeOpus55Model(model: unknown): boolean;
111
+ export declare function isClaudeOpus5FamilyModel(model: unknown): boolean;
67
112
  export declare function isOpenAIReasoningSignature(value: unknown): boolean;
package/dist/models.js CHANGED
@@ -1,5 +1,7 @@
1
1
  export const CLAUDE_FABLE_5_MODEL_ID = 'claude-fable-5';
2
2
  export const CLAUDE_MYTHOS_5_MODEL_ID = 'claude-mythos-5';
3
+ export const CLAUDE_FABLE_5_1_MODEL_ID = 'claude-fable-5-1';
4
+ export const CLAUDE_MYTHOS_5_1_MODEL_ID = 'claude-mythos-5-1';
3
5
  /**
4
6
  * Haiku 4.5 model identifier used by `/claude-prime` to start each OAuth
5
7
  * account's five-hour quota window with a minimal request. Usage is measured
@@ -7,6 +9,10 @@ export const CLAUDE_MYTHOS_5_MODEL_ID = 'claude-mythos-5';
7
9
  * above so per-million-token cost estimation does not conflate families.
8
10
  */
9
11
  export const CLAUDE_HAIKU_4_5_MODEL_ID = 'claude-haiku-4-5';
12
+ /** Remove OpenCode's context-window qualifier before model-family checks. */
13
+ export function normalizeAnthropicModelId(model) {
14
+ return model.endsWith('[1m]') ? model.slice(0, -4) : model;
15
+ }
10
16
  /**
11
17
  * Per-million-token USD pricing for Haiku 4.5. Used to project the cumulative
12
18
  * cost of prime requests from persisted usage counters — never persisted on
@@ -16,9 +22,14 @@ export const CLAUDE_HAIKU_4_5_PRICING = {
16
22
  input: 1,
17
23
  output: 5,
18
24
  };
25
+ export const CLAUDE_FABLE_MYTHOS_5_1_MODEL_IDS = [
26
+ CLAUDE_FABLE_5_1_MODEL_ID,
27
+ CLAUDE_MYTHOS_5_1_MODEL_ID,
28
+ ];
19
29
  export const CLAUDE_FABLE_MYTHOS_5_MODEL_IDS = [
20
30
  CLAUDE_FABLE_5_MODEL_ID,
21
31
  CLAUDE_MYTHOS_5_MODEL_ID,
32
+ ...CLAUDE_FABLE_MYTHOS_5_1_MODEL_IDS,
22
33
  ];
23
34
  export const CLAUDE_FABLE_MYTHOS_5_SUMMARIZED_THINKING = {
24
35
  type: 'adaptive',
@@ -31,9 +42,17 @@ export const CLAUDE_FABLE_MYTHOS_5_PRICING = {
31
42
  cacheWrite5m: 12.5,
32
43
  cacheWrite1h: 20,
33
44
  };
45
+ export const CLAUDE_FABLE_MYTHOS_5_1_PRICING = {
46
+ input: 10,
47
+ output: 50,
48
+ cacheRead: 0.25,
49
+ cacheWrite5m: 12.5,
50
+ cacheWrite1h: 20,
51
+ };
34
52
  export const CLAUDE_FABLE_MYTHOS_5_CONTEXT_WINDOW = 1_000_000;
35
53
  export const CLAUDE_FABLE_MYTHOS_5_MAX_OUTPUT_TOKENS = 128_000;
36
54
  export const CLAUDE_FABLE_MYTHOS_5_RELEASE_DATE = '2026-06-09';
55
+ export const CLAUDE_FABLE_MYTHOS_5_1_RELEASE_DATE = '2026-09-01';
37
56
  export const CLAUDE_FABLE_MYTHOS_5_MODEL_SPECS = {
38
57
  [CLAUDE_FABLE_5_MODEL_ID]: {
39
58
  id: CLAUDE_FABLE_5_MODEL_ID,
@@ -44,10 +63,43 @@ export const CLAUDE_FABLE_MYTHOS_5_MODEL_SPECS = {
44
63
  name: 'Claude Mythos 5',
45
64
  limited: true,
46
65
  },
66
+ [CLAUDE_FABLE_5_1_MODEL_ID]: {
67
+ id: CLAUDE_FABLE_5_1_MODEL_ID,
68
+ name: 'Claude Fable 5.1',
69
+ },
70
+ [CLAUDE_MYTHOS_5_1_MODEL_ID]: {
71
+ id: CLAUDE_MYTHOS_5_1_MODEL_ID,
72
+ name: 'Claude Mythos 5.1',
73
+ limited: true,
74
+ },
75
+ };
76
+ export const CLAUDE_FABLE_MYTHOS_5_1_MODEL_SPECS = {
77
+ [CLAUDE_FABLE_5_1_MODEL_ID]: CLAUDE_FABLE_MYTHOS_5_MODEL_SPECS[CLAUDE_FABLE_5_1_MODEL_ID],
78
+ [CLAUDE_MYTHOS_5_1_MODEL_ID]: CLAUDE_FABLE_MYTHOS_5_MODEL_SPECS[CLAUDE_MYTHOS_5_1_MODEL_ID],
47
79
  };
48
80
  export function isClaudeFableOrMythos5Model(model) {
49
- return (typeof model === 'string' &&
50
- CLAUDE_FABLE_MYTHOS_5_MODEL_IDS.some((id) => model === id || model.startsWith(`${id}-`)));
81
+ if (typeof model !== 'string')
82
+ return false;
83
+ const normalized = normalizeAnthropicModelId(model);
84
+ return CLAUDE_FABLE_MYTHOS_5_MODEL_IDS.some((id) => normalized === id || normalized.startsWith(`${id}-`));
85
+ }
86
+ export function isClaudeFableOrMythos51Model(model) {
87
+ if (typeof model !== 'string')
88
+ return false;
89
+ const normalized = normalizeAnthropicModelId(model);
90
+ return CLAUDE_FABLE_MYTHOS_5_1_MODEL_IDS.some((id) => normalized === id || normalized.startsWith(`${id}-`));
91
+ }
92
+ export function isClaudeFable51Model(model) {
93
+ if (typeof model !== 'string')
94
+ return false;
95
+ const normalized = normalizeAnthropicModelId(model);
96
+ return (normalized === CLAUDE_FABLE_5_1_MODEL_ID ||
97
+ normalized.startsWith(`${CLAUDE_FABLE_5_1_MODEL_ID}-`));
98
+ }
99
+ export function getClaudeFableMythos5ReleaseDate(model) {
100
+ return isClaudeFableOrMythos51Model(model)
101
+ ? CLAUDE_FABLE_MYTHOS_5_1_RELEASE_DATE
102
+ : CLAUDE_FABLE_MYTHOS_5_RELEASE_DATE;
51
103
  }
52
104
  export const CLAUDE_SONNET_5_MODEL_ID = 'claude-sonnet-5';
53
105
  /**
@@ -58,9 +110,11 @@ export const CLAUDE_SONNET_5_MODEL_ID = 'claude-sonnet-5';
58
110
  */
59
111
  export const CLAUDE_SONNET_5_ADAPTIVE_THINKING = CLAUDE_FABLE_MYTHOS_5_SUMMARIZED_THINKING;
60
112
  export function isClaudeSonnet5Model(model) {
61
- return (typeof model === 'string' &&
62
- (model === CLAUDE_SONNET_5_MODEL_ID ||
63
- model.startsWith(`${CLAUDE_SONNET_5_MODEL_ID}-`)));
113
+ if (typeof model !== 'string')
114
+ return false;
115
+ const normalized = normalizeAnthropicModelId(model);
116
+ return (normalized === CLAUDE_SONNET_5_MODEL_ID ||
117
+ normalized.startsWith(`${CLAUDE_SONNET_5_MODEL_ID}-`));
64
118
  }
65
119
  export const CLAUDE_OPUS_5_MODEL_ID = 'claude-opus-5';
66
120
  /**
@@ -73,9 +127,34 @@ export const CLAUDE_OPUS_5_MODEL_ID = 'claude-opus-5';
73
127
  */
74
128
  export const CLAUDE_OPUS_5_ADAPTIVE_THINKING = CLAUDE_FABLE_MYTHOS_5_SUMMARIZED_THINKING;
75
129
  export function isClaudeOpus5Model(model) {
76
- return (typeof model === 'string' &&
77
- (model === CLAUDE_OPUS_5_MODEL_ID ||
78
- model.startsWith(`${CLAUDE_OPUS_5_MODEL_ID}-`)));
130
+ if (typeof model !== 'string')
131
+ return false;
132
+ const normalized = normalizeAnthropicModelId(model);
133
+ return (!isClaudeOpus55Model(normalized) &&
134
+ (normalized === CLAUDE_OPUS_5_MODEL_ID ||
135
+ normalized.startsWith(`${CLAUDE_OPUS_5_MODEL_ID}-`)));
136
+ }
137
+ export const CLAUDE_OPUS_5_5_MODEL_ID = 'claude-opus-5-5';
138
+ export const CLAUDE_OPUS_5_5_RELEASE_DATE = '2026-09-18';
139
+ export const CLAUDE_OPUS_5_5_CONTEXT_WINDOW = 1_000_000;
140
+ export const CLAUDE_OPUS_5_5_MAX_OUTPUT_TOKENS = 128_000;
141
+ export const CLAUDE_OPUS_5_5_PRICING = {
142
+ input: 4,
143
+ output: 20,
144
+ cacheRead: 0.2,
145
+ cacheWrite5m: 5,
146
+ cacheWrite1h: 8,
147
+ };
148
+ export const CLAUDE_OPUS_5_5_ADAPTIVE_THINKING = CLAUDE_FABLE_MYTHOS_5_SUMMARIZED_THINKING;
149
+ export function isClaudeOpus55Model(model) {
150
+ if (typeof model !== 'string')
151
+ return false;
152
+ const normalized = normalizeAnthropicModelId(model);
153
+ return (normalized === CLAUDE_OPUS_5_5_MODEL_ID ||
154
+ normalized.startsWith(`${CLAUDE_OPUS_5_5_MODEL_ID}-`));
155
+ }
156
+ export function isClaudeOpus5FamilyModel(model) {
157
+ return isClaudeOpus5Model(model) || isClaudeOpus55Model(model);
79
158
  }
80
159
  export function isOpenAIReasoningSignature(value) {
81
160
  if (typeof value !== 'string')
@@ -0,0 +1 @@
1
+ export declare function isTransientNetworkError(error: unknown): boolean;
@@ -0,0 +1,27 @@
1
+ const TRANSIENT_NETWORK_ERROR_CODES = new Set([
2
+ 'EAI_AGAIN',
3
+ 'ECONNREFUSED',
4
+ 'ECONNRESET',
5
+ 'EHOSTUNREACH',
6
+ 'ENETUNREACH',
7
+ 'ENOTFOUND',
8
+ 'ETIMEDOUT',
9
+ 'UND_ERR_CONNECT_TIMEOUT',
10
+ ]);
11
+ function errorField(error, field) {
12
+ if (!error || typeof error !== 'object')
13
+ return undefined;
14
+ const value = error[field];
15
+ return typeof value === 'string' ? value : undefined;
16
+ }
17
+ export function isTransientNetworkError(error) {
18
+ const code = errorField(error, 'code');
19
+ if (code && TRANSIENT_NETWORK_ERROR_CODES.has(code))
20
+ return true;
21
+ const message = error instanceof Error
22
+ ? error.message
23
+ : (errorField(error, 'message') ?? String(error));
24
+ if (message.includes('fetch failed'))
25
+ return true;
26
+ return [...TRANSIENT_NETWORK_ERROR_CODES].some((candidate) => message.includes(candidate));
27
+ }
@@ -1,8 +1,9 @@
1
- import type { OAuthAccountProfile } from './accounts.ts';
1
+ import type { OAuthAccountProfile, ProviderAccountUuid } from './accounts.ts';
2
2
  export declare const PROFILE_TTL_MS: number;
3
3
  export declare function fetchOAuthAccountProfile(input: {
4
4
  accessToken: string;
5
5
  accountIdentity?: string;
6
+ providerAccountUuid?: ProviderAccountUuid;
6
7
  fetchImpl?: typeof fetch;
7
8
  now?: () => number;
8
9
  signal?: AbortSignal;
@@ -1,6 +1,9 @@
1
+ import { assertNotCustodyTombstone } from './claustrum.js';
1
2
  const PROFILE_URL = 'https://api.anthropic.com/api/oauth/profile';
2
3
  export const PROFILE_TTL_MS = 7 * 24 * 60 * 60 * 1000;
3
4
  export async function fetchOAuthAccountProfile(input) {
5
+ // The bearer value is guarded where it becomes a header, like every other builder.
6
+ assertNotCustodyTombstone(input.accessToken, 'anthropic');
4
7
  const response = await (input.fetchImpl ?? fetch)(PROFILE_URL, {
5
8
  method: 'GET',
6
9
  signal: input.signal,
@@ -29,6 +32,9 @@ export async function fetchOAuthAccountProfile(input) {
29
32
  ...(input.accountIdentity !== undefined && {
30
33
  accountIdentity: input.accountIdentity,
31
34
  }),
35
+ ...(input.providerAccountUuid !== undefined && {
36
+ providerAccountUuid: input.providerAccountUuid,
37
+ }),
32
38
  };
33
39
  }
34
40
  export function oauthProfileMatchesIdentity(profile, accountIdentity) {
package/dist/prime.d.ts CHANGED
@@ -30,7 +30,7 @@ export type PrimeAccountStatus = {
30
30
  label: string;
31
31
  nextDueAt?: number;
32
32
  lastPrimedAt?: number | null;
33
- lastResult?: 'ok' | 'error';
33
+ lastResult?: 'ok' | 'error' | 'skipped';
34
34
  usage?: import('./accounts.ts').PrimeUsageCounters;
35
35
  estimatedCostUsd?: number;
36
36
  };
@@ -47,7 +47,7 @@ export type PrimeSendResult = {
47
47
  status?: number;
48
48
  ms?: number;
49
49
  error: string;
50
- reason?: 'token-refresh' | 'send';
50
+ reason?: 'token-refresh' | 'vault-cold' | 'send';
51
51
  };
52
52
  /**
53
53
  * Pure command parser — accepts `''` / `on` / `off` and treats anything else
@@ -72,7 +72,7 @@ export declare function buildPrimeAccountStatuses(storage: AccountStorage | null
72
72
  now?: number;
73
73
  transient?: ReadonlyMap<string, {
74
74
  lastPrimedAt?: number;
75
- lastResult?: 'ok' | 'error';
75
+ lastResult?: 'ok' | 'error' | 'skipped';
76
76
  }>;
77
77
  }): PrimeAccountStatus[];
78
78
  /**
@@ -182,9 +182,17 @@ export type PrimeManagerOptions = {
182
182
  now?: () => number;
183
183
  markerDir?: string;
184
184
  storagePath: string;
185
+ setIntervalImpl?: typeof globalThis.setInterval;
186
+ clearIntervalImpl?: typeof globalThis.clearInterval;
187
+ setTimeoutImpl?: typeof globalThis.setTimeout;
188
+ clearTimeoutImpl?: typeof globalThis.clearTimeout;
185
189
  };
186
190
  export declare class PrimeManager {
187
191
  private timer;
192
+ private readonly setIntervalImpl;
193
+ private readonly clearIntervalImpl;
194
+ private readonly setTimeoutImpl;
195
+ private readonly clearTimeoutImpl;
188
196
  private postFireRefreshTimers;
189
197
  private lastForcedCheck;
190
198
  private stopped;
package/dist/prime.js CHANGED
@@ -155,6 +155,8 @@ function formatPrimed(lastPrimedAt, lastResult) {
155
155
  });
156
156
  if (lastResult === 'error')
157
157
  return `primed ${time} err`;
158
+ if (lastResult === 'skipped')
159
+ return `primed ${time} skipped`;
158
160
  return `primed ${time} \u2713`;
159
161
  }
160
162
  function formatUsd(value) {
@@ -346,6 +348,10 @@ function storedResetMs(window) {
346
348
  }
347
349
  export class PrimeManager {
348
350
  timer = null;
351
+ setIntervalImpl;
352
+ clearIntervalImpl;
353
+ setTimeoutImpl;
354
+ clearTimeoutImpl;
349
355
  postFireRefreshTimers = new Set();
350
356
  lastForcedCheck = new Map();
351
357
  // Set true by `stop()` so a tick already in flight can short-circuit
@@ -373,6 +379,11 @@ export class PrimeManager {
373
379
  windowActive = new Map();
374
380
  constructor(options) {
375
381
  this.options = options;
382
+ this.setIntervalImpl = options.setIntervalImpl ?? globalThis.setInterval;
383
+ this.clearIntervalImpl =
384
+ options.clearIntervalImpl ?? globalThis.clearInterval;
385
+ this.setTimeoutImpl = options.setTimeoutImpl ?? globalThis.setTimeout;
386
+ this.clearTimeoutImpl = options.clearTimeoutImpl ?? globalThis.clearTimeout;
376
387
  }
377
388
  updateOptions(options) {
378
389
  this.options = options;
@@ -382,7 +393,7 @@ export class PrimeManager {
382
393
  return;
383
394
  this.stopped = false;
384
395
  logger.trace('prime', 'manager started');
385
- this.timer = setInterval(() => {
396
+ this.timer = this.setIntervalImpl(() => {
386
397
  void this.tick().catch((error) => {
387
398
  logger.warn('prime', 'tick failed', {
388
399
  error: error instanceof Error ? error.message : String(error),
@@ -399,11 +410,12 @@ export class PrimeManager {
399
410
  const hadPostFireRefresh = this.postFireRefreshTimers.size > 0;
400
411
  this.stopped = true;
401
412
  if (this.timer) {
402
- clearInterval(this.timer);
413
+ this.clearIntervalImpl(this.timer);
403
414
  this.timer = null;
404
415
  }
405
- for (const timer of this.postFireRefreshTimers)
406
- clearTimeout(timer);
416
+ for (const timer of this.postFireRefreshTimers) {
417
+ this.clearTimeoutImpl(timer);
418
+ }
407
419
  this.postFireRefreshTimers.clear();
408
420
  this.lastForcedCheck.clear();
409
421
  if (!hadTimer && !hadPostFireRefresh)
@@ -687,7 +699,7 @@ export class PrimeManager {
687
699
  if (this.stopped)
688
700
  return;
689
701
  if (!result.ok) {
690
- // Spec Logging table: two distinct warn events.
702
+ // `vault-cold` is a cache-warm skip; it is not a provider failure.
691
703
  // - `prime token refresh failed` — token-refresh failure
692
704
  // before the request fires (reason: 'token-refresh').
693
705
  // - `prime fire failed` — HTTP error / fetch throw /
@@ -698,6 +710,12 @@ export class PrimeManager {
698
710
  error: result.error,
699
711
  });
700
712
  }
713
+ else if (result.reason === 'vault-cold') {
714
+ logger.debug('prime', 'prime vault credential cold', {
715
+ account: evaluation.label,
716
+ reason: result.reason,
717
+ });
718
+ }
701
719
  else {
702
720
  logger.warn('prime', 'prime fire failed', {
703
721
  account: evaluation.label,
@@ -707,7 +725,7 @@ export class PrimeManager {
707
725
  }
708
726
  this.transient.set(evaluation.id, {
709
727
  lastPrimedAt: now,
710
- lastResult: 'error',
728
+ lastResult: result.reason === 'vault-cold' ? 'skipped' : 'error',
711
729
  });
712
730
  return;
713
731
  }
@@ -757,7 +775,7 @@ export class PrimeManager {
757
775
  // Unified fire-response headers can arm the window instantly on newer
758
776
  // trees. This branch predates header harvesting, so a delayed poll captures
759
777
  // the reset after the usage API's observed propagation lag.
760
- const timer = setTimeout(() => {
778
+ const timer = this.setTimeoutImpl(() => {
761
779
  this.postFireRefreshTimers.delete(timer);
762
780
  if (this.stopped)
763
781
  return;