@f5-sales-demo/pi-ai 21.29.4 → 21.30.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/CHANGELOG.md +6 -0
- package/package.json +2 -2
- package/src/model-thinking.ts +20 -4
- package/src/models.json +100 -0
- package/src/providers/anthropic.ts +59 -20
- package/src/providers/google-gemini-cli.ts +1 -1
- package/src/stream.ts +7 -4
package/CHANGELOG.md
CHANGED
|
@@ -4,6 +4,12 @@
|
|
|
4
4
|
|
|
5
5
|
## Unreleased
|
|
6
6
|
|
|
7
|
+
### Added
|
|
8
|
+
|
|
9
|
+
- Added native Anthropic Claude Fable 5 and 5.1 catalog and transport support, including always-on
|
|
10
|
+
adaptive thinking, accurate limits and pricing, strict-tool compatibility, and permanent
|
|
11
|
+
entitlement/client-version error handling.
|
|
12
|
+
|
|
7
13
|
### Changed
|
|
8
14
|
|
|
9
15
|
- Replaced the bundled Vertex Gemini 3.7 Flash model and provider default with GA Gemini 3.8 Flash,
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"type": "module",
|
|
3
3
|
"name": "@f5-sales-demo/pi-ai",
|
|
4
|
-
"version": "21.
|
|
4
|
+
"version": "21.30.1",
|
|
5
5
|
"description": "Unified LLM API with automatic model discovery and provider configuration",
|
|
6
6
|
"homepage": "https://github.com/f5-sales-demo/xcsh",
|
|
7
7
|
"author": "Can Boluk",
|
|
@@ -46,7 +46,7 @@
|
|
|
46
46
|
"@anthropic-ai/sdk": "0.123.0",
|
|
47
47
|
"@aws-sdk/client-bedrock-runtime": "3.1126.0",
|
|
48
48
|
"@bufbuild/protobuf": "2.14.1",
|
|
49
|
-
"@f5-sales-demo/pi-utils": "21.
|
|
49
|
+
"@f5-sales-demo/pi-utils": "21.30.1",
|
|
50
50
|
"@google/genai": "2.21.0",
|
|
51
51
|
"@sinclair/typebox": "0.34.52",
|
|
52
52
|
"@smithy/node-http-handler": "4.12.1",
|
package/src/model-thinking.ts
CHANGED
|
@@ -120,7 +120,12 @@ const ANTHROPIC_ADAPTIVE_EFFORTS: readonly Effort[] = [
|
|
|
120
120
|
* Adding a version here without a probe is the defect this set exists to
|
|
121
121
|
* prevent: an unprobed model must fail closed to DEFAULT_REASONING_EFFORTS.
|
|
122
122
|
*/
|
|
123
|
-
const
|
|
123
|
+
const ANTHROPIC_EXTENDED_EFFORT_MODELS: ReadonlySet<string> = new Set([
|
|
124
|
+
"fable-5.0",
|
|
125
|
+
"fable-5.1",
|
|
126
|
+
"opus-5.0",
|
|
127
|
+
"sonnet-5.0",
|
|
128
|
+
]);
|
|
124
129
|
|
|
125
130
|
const GEMINI_3_PRO_EFFORTS: readonly Effort[] = [Effort.Low, Effort.Medium, Effort.High];
|
|
126
131
|
const GEMINI_3_FLASH_EFFORTS: readonly Effort[] = [Effort.Minimal, Effort.Low, Effort.Medium, Effort.High];
|
|
@@ -135,7 +140,7 @@ type SemVer = {
|
|
|
135
140
|
};
|
|
136
141
|
|
|
137
142
|
type GeminiKind = "pro" | "flash";
|
|
138
|
-
type AnthropicKind = "opus" | "sonnet";
|
|
143
|
+
type AnthropicKind = "fable" | "opus" | "sonnet";
|
|
139
144
|
type OpenAIVariant = "base" | "codex" | "codex-max" | "codex-mini" | "codex-spark" | "mini" | "max" | "nano";
|
|
140
145
|
|
|
141
146
|
const CODEX_GPT_5_4_PRIORITY_BY_VARIANT: Partial<Record<OpenAIVariant, number>> = {
|
|
@@ -453,6 +458,9 @@ function inferModelThinking<TApi extends Api>(model: ApiModel<TApi>): ThinkingCo
|
|
|
453
458
|
supportedLevels: efforts.map(effort => ({ effort, description: EFFORT_DESCRIPTIONS[effort] })),
|
|
454
459
|
defaultLevel: efforts.includes(ReasoningEffort.Medium) ? ReasoningEffort.Medium : efforts[0]!,
|
|
455
460
|
};
|
|
461
|
+
if (parsedModel.family === "anthropic" && parsedModel.kind === "fable") {
|
|
462
|
+
thinking.defaultLevel = Effort.High;
|
|
463
|
+
}
|
|
456
464
|
if (
|
|
457
465
|
model.provider === "google-vertex" &&
|
|
458
466
|
parsedModel.family === "gemini" &&
|
|
@@ -572,7 +580,9 @@ function inferAnthropicSupportedEfforts<TApi extends Api>(
|
|
|
572
580
|
// every future Claude the moment it lands in the catalog — the same
|
|
573
581
|
// open-ended grant that caused this bug. Unprobed versions fail closed to
|
|
574
582
|
// the conservative range; add one here only with a probe to back it.
|
|
575
|
-
return
|
|
583
|
+
return ANTHROPIC_EXTENDED_EFFORT_MODELS.has(
|
|
584
|
+
`${parsedModel.kind}-${parsedModel.version.major}.${parsedModel.version.minor}`,
|
|
585
|
+
)
|
|
576
586
|
? ANTHROPIC_ADAPTIVE_EFFORTS
|
|
577
587
|
: DEFAULT_REASONING_EFFORTS;
|
|
578
588
|
}
|
|
@@ -667,7 +677,7 @@ function parseGeminiModel(modelId: string): GeminiModel | null {
|
|
|
667
677
|
}
|
|
668
678
|
|
|
669
679
|
function parseAnthropicModel(modelId: string): AnthropicModel | null {
|
|
670
|
-
const match = /claude-(opus|sonnet)-(\d{1,2}(?:[.-]\d{1,2}){0,2})\b/.exec(modelId);
|
|
680
|
+
const match = /claude-(fable|opus|sonnet)-(\d{1,2}(?:[.-]\d{1,2}){0,2})\b/.exec(modelId);
|
|
671
681
|
if (!match) {
|
|
672
682
|
return null;
|
|
673
683
|
}
|
|
@@ -678,6 +688,12 @@ function parseAnthropicModel(modelId: string): AnthropicModel | null {
|
|
|
678
688
|
return { family: "anthropic", kind: match[1] as AnthropicKind, version };
|
|
679
689
|
}
|
|
680
690
|
|
|
691
|
+
/** Whether the model requires adaptive thinking on every request. */
|
|
692
|
+
export function isAnthropicAlwaysThinkingModel<TApi extends Api>(model: ApiModel<TApi>): boolean {
|
|
693
|
+
const parsed = parseKnownModel(model.id);
|
|
694
|
+
return model.api === "anthropic-messages" && parsed.family === "anthropic" && parsed.kind === "fable";
|
|
695
|
+
}
|
|
696
|
+
|
|
681
697
|
function parseOpenAIModel(modelId: string): OpenAIModel | null {
|
|
682
698
|
const match = /gpt-(\d+(?:\.\d+){0,2})(?:-(codex-spark|codex-mini|codex-max|codex|mini|max|nano))?\b/.exec(modelId);
|
|
683
699
|
if (!match) {
|
package/src/models.json
CHANGED
|
@@ -3158,6 +3158,106 @@
|
|
|
3158
3158
|
}
|
|
3159
3159
|
},
|
|
3160
3160
|
"anthropic": {
|
|
3161
|
+
"claude-fable-5": {
|
|
3162
|
+
"id": "claude-fable-5",
|
|
3163
|
+
"name": "Claude Fable 5",
|
|
3164
|
+
"api": "anthropic-messages",
|
|
3165
|
+
"provider": "anthropic",
|
|
3166
|
+
"baseUrl": "https://api.anthropic.com",
|
|
3167
|
+
"reasoning": true,
|
|
3168
|
+
"input": [
|
|
3169
|
+
"text",
|
|
3170
|
+
"image"
|
|
3171
|
+
],
|
|
3172
|
+
"cost": {
|
|
3173
|
+
"input": 10,
|
|
3174
|
+
"output": 50,
|
|
3175
|
+
"cacheRead": 1,
|
|
3176
|
+
"cacheWrite": 12.5
|
|
3177
|
+
},
|
|
3178
|
+
"contextWindow": 1000000,
|
|
3179
|
+
"maxTokens": 128000,
|
|
3180
|
+
"thinking": {
|
|
3181
|
+
"mode": "anthropic-adaptive",
|
|
3182
|
+
"supportedLevels": [
|
|
3183
|
+
{
|
|
3184
|
+
"effort": "minimal",
|
|
3185
|
+
"description": "Very brief reasoning"
|
|
3186
|
+
},
|
|
3187
|
+
{
|
|
3188
|
+
"effort": "low",
|
|
3189
|
+
"description": "Light reasoning"
|
|
3190
|
+
},
|
|
3191
|
+
{
|
|
3192
|
+
"effort": "medium",
|
|
3193
|
+
"description": "Balanced reasoning"
|
|
3194
|
+
},
|
|
3195
|
+
{
|
|
3196
|
+
"effort": "high",
|
|
3197
|
+
"description": "Deep reasoning"
|
|
3198
|
+
},
|
|
3199
|
+
{
|
|
3200
|
+
"effort": "xhigh",
|
|
3201
|
+
"description": "Very deep reasoning"
|
|
3202
|
+
},
|
|
3203
|
+
{
|
|
3204
|
+
"effort": "max",
|
|
3205
|
+
"description": "Maximum reasoning"
|
|
3206
|
+
}
|
|
3207
|
+
],
|
|
3208
|
+
"defaultLevel": "high"
|
|
3209
|
+
}
|
|
3210
|
+
},
|
|
3211
|
+
"claude-fable-5-1": {
|
|
3212
|
+
"id": "claude-fable-5-1",
|
|
3213
|
+
"name": "Claude Fable 5.1",
|
|
3214
|
+
"api": "anthropic-messages",
|
|
3215
|
+
"provider": "anthropic",
|
|
3216
|
+
"baseUrl": "https://api.anthropic.com",
|
|
3217
|
+
"reasoning": true,
|
|
3218
|
+
"input": [
|
|
3219
|
+
"text",
|
|
3220
|
+
"image"
|
|
3221
|
+
],
|
|
3222
|
+
"cost": {
|
|
3223
|
+
"input": 10,
|
|
3224
|
+
"output": 50,
|
|
3225
|
+
"cacheRead": 0.25,
|
|
3226
|
+
"cacheWrite": 12.5
|
|
3227
|
+
},
|
|
3228
|
+
"contextWindow": 1000000,
|
|
3229
|
+
"maxTokens": 128000,
|
|
3230
|
+
"thinking": {
|
|
3231
|
+
"mode": "anthropic-adaptive",
|
|
3232
|
+
"supportedLevels": [
|
|
3233
|
+
{
|
|
3234
|
+
"effort": "minimal",
|
|
3235
|
+
"description": "Very brief reasoning"
|
|
3236
|
+
},
|
|
3237
|
+
{
|
|
3238
|
+
"effort": "low",
|
|
3239
|
+
"description": "Light reasoning"
|
|
3240
|
+
},
|
|
3241
|
+
{
|
|
3242
|
+
"effort": "medium",
|
|
3243
|
+
"description": "Balanced reasoning"
|
|
3244
|
+
},
|
|
3245
|
+
{
|
|
3246
|
+
"effort": "high",
|
|
3247
|
+
"description": "Deep reasoning"
|
|
3248
|
+
},
|
|
3249
|
+
{
|
|
3250
|
+
"effort": "xhigh",
|
|
3251
|
+
"description": "Very deep reasoning"
|
|
3252
|
+
},
|
|
3253
|
+
{
|
|
3254
|
+
"effort": "max",
|
|
3255
|
+
"description": "Maximum reasoning"
|
|
3256
|
+
}
|
|
3257
|
+
],
|
|
3258
|
+
"defaultLevel": "high"
|
|
3259
|
+
}
|
|
3260
|
+
},
|
|
3161
3261
|
"claude-3-5-sonnet-20240620": {
|
|
3162
3262
|
"id": "claude-3-5-sonnet-20240620",
|
|
3163
3263
|
"name": "Claude Sonnet 3.5",
|
|
@@ -9,7 +9,12 @@ import type {
|
|
|
9
9
|
MessageParam,
|
|
10
10
|
} from "@anthropic-ai/sdk/resources/messages";
|
|
11
11
|
import { $env, abortableSleep, isEnoent } from "@f5-sales-demo/pi-utils";
|
|
12
|
-
import {
|
|
12
|
+
import {
|
|
13
|
+
type AnthropicAdaptiveEffort,
|
|
14
|
+
Effort,
|
|
15
|
+
isAnthropicAlwaysThinkingModel,
|
|
16
|
+
mapEffortToAnthropicAdaptiveEffort,
|
|
17
|
+
} from "../model-thinking";
|
|
13
18
|
import { calculateCost } from "../models";
|
|
14
19
|
import { getEnvApiKey, OUTPUT_FALLBACK_BUFFER } from "../stream";
|
|
15
20
|
import type {
|
|
@@ -186,7 +191,7 @@ function getCacheControl(
|
|
|
186
191
|
}
|
|
187
192
|
|
|
188
193
|
// Stealth mode: Mimic Claude Code headers and tool prefixing.
|
|
189
|
-
export const claudeCodeVersion = "2.1.
|
|
194
|
+
export const claudeCodeVersion = "2.1.274";
|
|
190
195
|
export const claudeToolPrefix: string = "proxy_";
|
|
191
196
|
export const claudeCodeSystemInstruction = "You are a Claude agent, built on Anthropic's Claude Agent SDK.";
|
|
192
197
|
|
|
@@ -624,6 +629,7 @@ function isProviderRetryableStreamEnvelopeError(error: unknown): boolean {
|
|
|
624
629
|
export function isProviderRetryableError(error: unknown): boolean {
|
|
625
630
|
if (!(error instanceof Error)) return false;
|
|
626
631
|
const msg = error.message.toLowerCase();
|
|
632
|
+
if (isAnthropicPermanentErrorMessage(msg)) return false;
|
|
627
633
|
return (
|
|
628
634
|
/rate.?limit|too many requests|overloaded|service.?unavailable|internal_error|stream error.*received from peer|1302|timed?\s*out while waiting for the first event|timeout waiting for first/i.test(
|
|
629
635
|
msg,
|
|
@@ -633,6 +639,26 @@ export function isProviderRetryableError(error: unknown): boolean {
|
|
|
633
639
|
);
|
|
634
640
|
}
|
|
635
641
|
|
|
642
|
+
export function isAnthropicPermanentErrorMessage(message: string): boolean {
|
|
643
|
+
return /credits_required|obsolete[_ -]?client|client[_ -]?(?:is[_ -]?)?too[_ -]?old|version of (?:claude code|the client) is no longer supported/i.test(
|
|
644
|
+
message,
|
|
645
|
+
);
|
|
646
|
+
}
|
|
647
|
+
|
|
648
|
+
export function rewriteAnthropicPermanentError(errorMessage: string): string {
|
|
649
|
+
if (/credits_required/i.test(errorMessage)) {
|
|
650
|
+
return "Anthropic access requires credits for this model. Check the account's Claude subscription or API billing entitlement, then retry.";
|
|
651
|
+
}
|
|
652
|
+
if (
|
|
653
|
+
/obsolete[_ -]?client|client[_ -]?(?:is[_ -]?)?too[_ -]?old|version of (?:claude code|the client) is no longer supported/i.test(
|
|
654
|
+
errorMessage,
|
|
655
|
+
)
|
|
656
|
+
) {
|
|
657
|
+
return "Anthropic rejected this xcsh client version. Upgrade xcsh to the latest release, then retry.";
|
|
658
|
+
}
|
|
659
|
+
return errorMessage;
|
|
660
|
+
}
|
|
661
|
+
|
|
636
662
|
/**
|
|
637
663
|
* Map an Anthropic `citations_delta` citation to a `WebCitation`.
|
|
638
664
|
*
|
|
@@ -1114,6 +1140,9 @@ export const streamAnthropic: StreamFunction<"anthropic-messages"> = (
|
|
|
1114
1140
|
output.stopReason = activeAbortTracker.wasCallerAbort() ? "aborted" : "error";
|
|
1115
1141
|
output.errorMessage = firstEventTimeoutError?.message ?? (await finalizeErrorMessage(error, rawRequestDump));
|
|
1116
1142
|
output.errorMessage = rewriteCopilotAuthError(output.errorMessage, error, model.provider);
|
|
1143
|
+
if (model.provider === "anthropic") {
|
|
1144
|
+
output.errorMessage = rewriteAnthropicPermanentError(output.errorMessage);
|
|
1145
|
+
}
|
|
1117
1146
|
output.duration = Date.now() - startTime;
|
|
1118
1147
|
if (firstTokenTime) output.ttft = firstTokenTime - startTime;
|
|
1119
1148
|
stream.push({ type: "error", reason: output.stopReason, error: output });
|
|
@@ -1250,7 +1279,7 @@ export function buildAnthropicClientOptions(args: AnthropicClientOptionsArgs): A
|
|
|
1250
1279
|
apiKey: oauthToken ? null : apiKey,
|
|
1251
1280
|
authToken: oauthToken ? apiKey : undefined,
|
|
1252
1281
|
baseURL: baseUrl,
|
|
1253
|
-
maxRetries:
|
|
1282
|
+
maxRetries: 0,
|
|
1254
1283
|
dangerouslyAllowBrowser: true,
|
|
1255
1284
|
defaultHeaders,
|
|
1256
1285
|
logLevel: ANTHROPIC_SDK_LOG_LEVEL,
|
|
@@ -1529,6 +1558,12 @@ function buildParams(
|
|
|
1529
1558
|
options?: AnthropicOptions,
|
|
1530
1559
|
): MessageCreateParamsStreaming {
|
|
1531
1560
|
const { cacheControl } = getCacheControl(baseUrl, options?.cacheRetention);
|
|
1561
|
+
const alwaysThinking = isAnthropicAlwaysThinkingModel(model);
|
|
1562
|
+
const toolChoice =
|
|
1563
|
+
alwaysThinking &&
|
|
1564
|
+
(options?.toolChoice === "any" || (typeof options?.toolChoice === "object" && options.toolChoice.type === "tool"))
|
|
1565
|
+
? "auto"
|
|
1566
|
+
: options?.toolChoice;
|
|
1532
1567
|
const params: AnthropicSamplingParams = {
|
|
1533
1568
|
model: model.id,
|
|
1534
1569
|
messages: convertAnthropicMessages(context.messages, model, isOAuthToken),
|
|
@@ -1536,7 +1571,7 @@ function buildParams(
|
|
|
1536
1571
|
stream: true,
|
|
1537
1572
|
};
|
|
1538
1573
|
|
|
1539
|
-
if (options?.temperature !== undefined) {
|
|
1574
|
+
if (!alwaysThinking && options?.temperature !== undefined) {
|
|
1540
1575
|
params.temperature = options.temperature;
|
|
1541
1576
|
}
|
|
1542
1577
|
if (options?.topP !== undefined) {
|
|
@@ -1547,22 +1582,26 @@ function buildParams(
|
|
|
1547
1582
|
}
|
|
1548
1583
|
|
|
1549
1584
|
if (context.tools) {
|
|
1550
|
-
const toolChoice = options?.toolChoice;
|
|
1551
1585
|
const forcedToolName =
|
|
1552
1586
|
model.provider === "anthropic" &&
|
|
1553
1587
|
supportsAnthropicStrictToolUse(model.id) &&
|
|
1554
|
-
typeof toolChoice === "object" &&
|
|
1555
|
-
toolChoice.type === "tool"
|
|
1556
|
-
? toolChoice.name
|
|
1588
|
+
typeof options?.toolChoice === "object" &&
|
|
1589
|
+
options.toolChoice.type === "tool"
|
|
1590
|
+
? options.toolChoice.name
|
|
1557
1591
|
: undefined;
|
|
1558
1592
|
params.tools = convertTools(context.tools, isOAuthToken, forcedToolName);
|
|
1559
1593
|
}
|
|
1560
1594
|
|
|
1561
|
-
if (options?.thinkingEnabled && model.reasoning) {
|
|
1595
|
+
if ((options?.thinkingEnabled || alwaysThinking) && model.reasoning) {
|
|
1562
1596
|
const mode = model.thinking?.mode;
|
|
1563
|
-
const requestedEffort = options
|
|
1597
|
+
const requestedEffort = options?.reasoning;
|
|
1564
1598
|
const effort =
|
|
1565
|
-
options
|
|
1599
|
+
options?.effort ??
|
|
1600
|
+
(requestedEffort
|
|
1601
|
+
? mapEffortToAnthropicAdaptiveEffort(model, requestedEffort)
|
|
1602
|
+
: alwaysThinking
|
|
1603
|
+
? mapEffortToAnthropicAdaptiveEffort(model, Effort.High)
|
|
1604
|
+
: undefined);
|
|
1566
1605
|
|
|
1567
1606
|
if (mode === "anthropic-adaptive") {
|
|
1568
1607
|
params.thinking = { type: "adaptive" };
|
|
@@ -1572,7 +1611,7 @@ function buildParams(
|
|
|
1572
1611
|
} else {
|
|
1573
1612
|
params.thinking = {
|
|
1574
1613
|
type: "enabled",
|
|
1575
|
-
budget_tokens: options
|
|
1614
|
+
budget_tokens: options?.thinkingBudgetTokens || 1024,
|
|
1576
1615
|
};
|
|
1577
1616
|
if (mode === "anthropic-budget-effort" && effort) {
|
|
1578
1617
|
params.output_config = { effort };
|
|
@@ -1580,7 +1619,7 @@ function buildParams(
|
|
|
1580
1619
|
}
|
|
1581
1620
|
// Anthropic requires temperature=1 when thinking is enabled; override any
|
|
1582
1621
|
// caller-supplied value (e.g. temperature=0 set for deterministic non-interactive mode).
|
|
1583
|
-
params.temperature = 1;
|
|
1622
|
+
if (!alwaysThinking) params.temperature = 1;
|
|
1584
1623
|
}
|
|
1585
1624
|
|
|
1586
1625
|
const metadataUserId = resolveAnthropicMetadataUserId(options?.metadata?.user_id, isOAuthToken);
|
|
@@ -1588,16 +1627,16 @@ function buildParams(
|
|
|
1588
1627
|
params.metadata = { user_id: metadataUserId };
|
|
1589
1628
|
}
|
|
1590
1629
|
|
|
1591
|
-
if (
|
|
1592
|
-
if (typeof
|
|
1593
|
-
params.tool_choice = { type:
|
|
1594
|
-
} else if (isOAuthToken &&
|
|
1630
|
+
if (toolChoice) {
|
|
1631
|
+
if (typeof toolChoice === "string") {
|
|
1632
|
+
params.tool_choice = { type: toolChoice };
|
|
1633
|
+
} else if (isOAuthToken && toolChoice.name) {
|
|
1595
1634
|
params.tool_choice = {
|
|
1596
|
-
...
|
|
1597
|
-
name: applyClaudeToolPrefix(
|
|
1635
|
+
...toolChoice,
|
|
1636
|
+
name: applyClaudeToolPrefix(toolChoice.name),
|
|
1598
1637
|
};
|
|
1599
1638
|
} else {
|
|
1600
|
-
params.tool_choice =
|
|
1639
|
+
params.tool_choice = toolChoice;
|
|
1601
1640
|
}
|
|
1602
1641
|
}
|
|
1603
1642
|
|
|
@@ -79,7 +79,7 @@ export function resolveAntigravityServingModelId(requestedModelId: string): stri
|
|
|
79
79
|
* GeminiCLI/VERSION/MODEL (PLATFORM; ARCH; SURFACE)
|
|
80
80
|
*/
|
|
81
81
|
export function getGeminiCliUserAgent(modelId = "gemini-3.1-pro-preview"): string {
|
|
82
|
-
const version = process.env.PI_AI_GEMINI_CLI_VERSION || "0.
|
|
82
|
+
const version = process.env.PI_AI_GEMINI_CLI_VERSION || "0.60.0";
|
|
83
83
|
const platform = process.platform === "win32" ? "win32" : process.platform;
|
|
84
84
|
const arch = process.arch === "x64" ? "x64" : process.arch;
|
|
85
85
|
return `GeminiCLI/${version}/${modelId} (${platform}; ${arch}; terminal)`;
|
package/src/stream.ts
CHANGED
|
@@ -1,11 +1,13 @@
|
|
|
1
1
|
import { $env, $pickenv } from "@f5-sales-demo/pi-utils";
|
|
2
2
|
import { getCustomApi } from "./api-registry";
|
|
3
|
-
import type { Effort, ReasoningEffort } from "./model-thinking";
|
|
4
3
|
import {
|
|
5
4
|
clampEffortThroughXHigh,
|
|
5
|
+
Effort,
|
|
6
6
|
type EffortThroughXHigh,
|
|
7
|
+
isAnthropicAlwaysThinkingModel,
|
|
7
8
|
mapEffortToAnthropicAdaptiveEffort,
|
|
8
9
|
mapEffortToGoogleThinkingLevel,
|
|
10
|
+
type ReasoningEffort,
|
|
9
11
|
requireSupportedEffort,
|
|
10
12
|
requireSupportedReasoningEffort,
|
|
11
13
|
} from "./model-thinking";
|
|
@@ -428,8 +430,9 @@ export function mapOptionsForApi<TApi extends Api>(
|
|
|
428
430
|
|
|
429
431
|
switch (model.api) {
|
|
430
432
|
case "anthropic-messages": {
|
|
431
|
-
//
|
|
432
|
-
|
|
433
|
+
// Fable requires adaptive thinking on every request. Other Anthropic models
|
|
434
|
+
// retain the caller-controlled behavior.
|
|
435
|
+
const reasoning = options?.reasoning ?? (isAnthropicAlwaysThinkingModel(model) ? Effort.High : undefined);
|
|
433
436
|
if (!reasoning || !model.reasoning) {
|
|
434
437
|
return castApi<"anthropic-messages">({
|
|
435
438
|
...base,
|
|
@@ -438,7 +441,7 @@ export function mapOptionsForApi<TApi extends Api>(
|
|
|
438
441
|
});
|
|
439
442
|
}
|
|
440
443
|
|
|
441
|
-
let thinkingBudget = options
|
|
444
|
+
let thinkingBudget = options?.thinkingBudgets?.[reasoning] ?? ANTHROPIC_THINKING[reasoning];
|
|
442
445
|
if (thinkingBudget <= 0) {
|
|
443
446
|
return castApi<"anthropic-messages">({
|
|
444
447
|
...base,
|