@psnext/slingcli 2.5.20260617-1 → 2.5.20260617-2
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/node_modules/@earendil-works/pi-agent-core/package.json +2 -2
- package/node_modules/@earendil-works/pi-ai/dist/env-api-keys.js +21 -57
- package/node_modules/@earendil-works/pi-ai/dist/models.generated.js +116 -155
- package/node_modules/@earendil-works/pi-ai/dist/models.js +4 -1
- package/node_modules/@earendil-works/pi-ai/dist/providers/amazon-bedrock.js +52 -34
- package/node_modules/@earendil-works/pi-ai/dist/providers/anthropic.js +11 -9
- package/node_modules/@earendil-works/pi-ai/dist/providers/azure-openai-responses.js +7 -4
- package/node_modules/@earendil-works/pi-ai/dist/providers/cloudflare.js +4 -3
- package/node_modules/@earendil-works/pi-ai/dist/providers/google-vertex.js +15 -5
- package/node_modules/@earendil-works/pi-ai/dist/providers/google.js +2 -1
- package/node_modules/@earendil-works/pi-ai/dist/providers/openai-codex-responses.js +18 -17
- package/node_modules/@earendil-works/pi-ai/dist/providers/openai-completions.js +21 -8
- package/node_modules/@earendil-works/pi-ai/dist/providers/openai-responses-shared.js +2 -1
- package/node_modules/@earendil-works/pi-ai/dist/providers/openai-responses.js +8 -7
- package/node_modules/@earendil-works/pi-ai/dist/providers/simple-options.js +1 -0
- package/node_modules/@earendil-works/pi-ai/dist/stream.js +1 -1
- package/node_modules/@earendil-works/pi-ai/dist/utils/node-http-proxy.js +17 -22
- package/node_modules/@earendil-works/pi-ai/dist/utils/oauth/anthropic.js +2 -1
- package/node_modules/@earendil-works/pi-ai/dist/utils/oauth/openai-codex.js +3 -2
- package/node_modules/@earendil-works/pi-ai/dist/utils/provider-env.js +44 -0
- package/node_modules/@earendil-works/pi-ai/package.json +1 -1
- package/node_modules/@earendil-works/pi-coding-agent/dist/bun/restore-sandbox-env.js +4 -0
- package/node_modules/@earendil-works/pi-coding-agent/dist/cli/args.js +1 -1
- package/node_modules/@earendil-works/pi-coding-agent/dist/core/agent-session.js +10 -7
- package/node_modules/@earendil-works/pi-coding-agent/dist/core/auth-storage.js +8 -1
- package/node_modules/@earendil-works/pi-coding-agent/dist/core/compaction/branch-summarization.js +2 -2
- package/node_modules/@earendil-works/pi-coding-agent/dist/core/compaction/compaction.js +10 -10
- package/node_modules/@earendil-works/pi-coding-agent/dist/core/export-html/vendor/marked.min.js +75 -3
- package/node_modules/@earendil-works/pi-coding-agent/dist/core/http-dispatcher.js +17 -1
- package/node_modules/@earendil-works/pi-coding-agent/dist/core/model-registry.js +8 -4
- package/node_modules/@earendil-works/pi-coding-agent/dist/core/project-trust.js +1 -1
- package/node_modules/@earendil-works/pi-coding-agent/dist/core/provider-attribution.js +10 -0
- package/node_modules/@earendil-works/pi-coding-agent/dist/core/resolve-config-value.js +19 -19
- package/node_modules/@earendil-works/pi-coding-agent/dist/core/sdk.js +2 -0
- package/node_modules/@earendil-works/pi-coding-agent/dist/core/system-prompt.js +6 -6
- package/node_modules/@earendil-works/pi-coding-agent/dist/core/tools/bash.js +4 -0
- package/node_modules/@earendil-works/pi-coding-agent/dist/main.js +17 -5
- package/node_modules/@earendil-works/pi-coding-agent/dist/modes/interactive/components/footer.js +4 -0
- package/node_modules/@earendil-works/pi-coding-agent/dist/modes/interactive/components/login-dialog.js +0 -1
- package/node_modules/@earendil-works/pi-coding-agent/dist/modes/interactive/components/session-selector.js +0 -5
- package/node_modules/@earendil-works/pi-coding-agent/dist/package-manager-cli.js +6 -6
- package/node_modules/@earendil-works/pi-coding-agent/dist/utils/child-process.js +23 -5
- package/node_modules/@earendil-works/pi-coding-agent/npm-shrinkwrap.json +17 -17
- package/node_modules/@earendil-works/pi-coding-agent/package.json +4 -4
- package/node_modules/@earendil-works/pi-tui/dist/components/editor.js +5 -1
- package/node_modules/@earendil-works/pi-tui/package.json +2 -2
- package/node_modules/marked/README.md +13 -4
- package/node_modules/marked/bin/main.js +16 -14
- package/node_modules/marked/bin/marked.js +2 -1
- package/node_modules/marked/lib/marked.d.ts +157 -125
- package/node_modules/marked/lib/marked.esm.js +67 -2179
- package/node_modules/marked/lib/marked.esm.js.map +3 -3
- package/node_modules/marked/lib/marked.umd.js +67 -2201
- package/node_modules/marked/lib/marked.umd.js.map +3 -3
- package/node_modules/marked/man/marked.1 +4 -2
- package/node_modules/marked/man/marked.1.md +2 -1
- package/node_modules/marked/package.json +27 -35
- package/package.json +6 -6
- package/slingshot/index.js +253 -253
- package/node_modules/marked/lib/marked.cjs +0 -2211
- package/node_modules/marked/lib/marked.cjs.map +0 -7
- package/node_modules/marked/lib/marked.d.cts +0 -728
- package/node_modules/marked/marked.min.js +0 -69
- /package/node_modules/marked/{LICENSE.md → LICENSE} +0 -0
|
@@ -20,10 +20,13 @@ export function getModels(provider) {
|
|
|
20
20
|
return models ? Array.from(models.values()) : [];
|
|
21
21
|
}
|
|
22
22
|
export function calculateCost(model, usage) {
|
|
23
|
+
// Anthropic charges 2x base input for 1h cache writes.
|
|
24
|
+
const longWrite = usage.cacheWrite1h ?? 0;
|
|
25
|
+
const shortWrite = usage.cacheWrite - longWrite;
|
|
23
26
|
usage.cost.input = (model.cost.input / 1000000) * usage.input;
|
|
24
27
|
usage.cost.output = (model.cost.output / 1000000) * usage.output;
|
|
25
28
|
usage.cost.cacheRead = (model.cost.cacheRead / 1000000) * usage.cacheRead;
|
|
26
|
-
usage.cost.cacheWrite = (model.cost.cacheWrite
|
|
29
|
+
usage.cost.cacheWrite = (model.cost.cacheWrite * shortWrite + model.cost.input * 2 * longWrite) / 1000000;
|
|
27
30
|
usage.cost.total = usage.cost.input + usage.cost.output + usage.cost.cacheRead + usage.cost.cacheWrite;
|
|
28
31
|
return usage.cost;
|
|
29
32
|
}
|
|
@@ -1,9 +1,12 @@
|
|
|
1
1
|
import { BedrockRuntimeClient, BedrockRuntimeServiceException, StopReason as BedrockStopReason, CachePointType, CacheTTL, ConversationRole, ConverseStreamCommand, ImageFormat, ToolResultStatus, } from "@aws-sdk/client-bedrock-runtime";
|
|
2
2
|
import { NodeHttpHandler } from "@smithy/node-http-handler";
|
|
3
|
+
import { HttpProxyAgent } from "http-proxy-agent";
|
|
4
|
+
import { HttpsProxyAgent } from "https-proxy-agent";
|
|
3
5
|
import { calculateCost } from "../models.js";
|
|
4
6
|
import { AssistantMessageEventStream } from "../utils/event-stream.js";
|
|
5
7
|
import { parseStreamingJson } from "../utils/json-parse.js";
|
|
6
|
-
import {
|
|
8
|
+
import { resolveHttpProxyUrlForTarget } from "../utils/node-http-proxy.js";
|
|
9
|
+
import { getProviderEnvValue } from "../utils/provider-env.js";
|
|
7
10
|
import { sanitizeSurrogates } from "../utils/sanitize-unicode.js";
|
|
8
11
|
import { adjustMaxTokensForThinking, buildBaseOptions, clampReasoning } from "./simple-options.js";
|
|
9
12
|
import { transformMessages } from "./transform-messages.js";
|
|
@@ -30,21 +33,22 @@ export const streamBedrock = (model, context, options = {}) => {
|
|
|
30
33
|
};
|
|
31
34
|
const blocks = output.content;
|
|
32
35
|
const config = {
|
|
33
|
-
profile: options.profile,
|
|
36
|
+
profile: options.profile || getProviderEnvValue("AWS_PROFILE", options.env),
|
|
34
37
|
};
|
|
35
38
|
const configuredRegion = getConfiguredBedrockRegion(options);
|
|
36
|
-
const
|
|
39
|
+
const hasAmbientConfiguredProfile = Boolean(getProviderEnvValue("AWS_PROFILE"));
|
|
37
40
|
const endpointRegion = getStandardBedrockEndpointRegion(model.baseUrl);
|
|
38
|
-
const useExplicitEndpoint = shouldUseExplicitBedrockEndpoint(model.baseUrl, configuredRegion,
|
|
39
|
-
// Only pin standard AWS Bedrock runtime endpoints when no region
|
|
41
|
+
const useExplicitEndpoint = shouldUseExplicitBedrockEndpoint(model.baseUrl, configuredRegion, hasAmbientConfiguredProfile);
|
|
42
|
+
// Only pin standard AWS Bedrock runtime endpoints when no region or ambient AWS_PROFILE is configured.
|
|
40
43
|
// This preserves custom endpoints (VPC/proxy) from #3402 without forcing built-in
|
|
41
44
|
// catalog defaults such as us-east-1 to override AWS_REGION/AWS_PROFILE.
|
|
42
45
|
if (useExplicitEndpoint) {
|
|
43
46
|
config.endpoint = model.baseUrl;
|
|
44
47
|
}
|
|
45
48
|
// Resolve bearer token for Bedrock API key auth.
|
|
46
|
-
const
|
|
47
|
-
const
|
|
49
|
+
const skipAuth = getProviderEnvValue("AWS_BEDROCK_SKIP_AUTH", options.env) === "1";
|
|
50
|
+
const bearerToken = options.bearerToken || getProviderEnvValue("AWS_BEARER_TOKEN_BEDROCK", options.env) || undefined;
|
|
51
|
+
const useBearerToken = bearerToken !== undefined && !skipAuth;
|
|
48
52
|
// in Node.js/Bun environment only
|
|
49
53
|
if (typeof process !== "undefined" && (process.versions?.node || process.versions?.bun)) {
|
|
50
54
|
// Region resolution: ARN-embedded > explicit option > env vars > SDK default chain.
|
|
@@ -60,24 +64,31 @@ export const streamBedrock = (model, context, options = {}) => {
|
|
|
60
64
|
else if (endpointRegion && useExplicitEndpoint) {
|
|
61
65
|
config.region = endpointRegion;
|
|
62
66
|
}
|
|
63
|
-
else if (!
|
|
67
|
+
else if (!hasAmbientConfiguredProfile) {
|
|
64
68
|
config.region = "us-east-1";
|
|
65
69
|
}
|
|
66
70
|
// Support proxies that don't need authentication
|
|
67
|
-
if (
|
|
71
|
+
if (skipAuth) {
|
|
68
72
|
config.credentials = {
|
|
69
73
|
accessKeyId: "dummy-access-key",
|
|
70
74
|
secretAccessKey: "dummy-secret-key",
|
|
71
75
|
};
|
|
72
76
|
}
|
|
73
|
-
const
|
|
74
|
-
if (
|
|
77
|
+
const credentials = getConfiguredBedrockCredentials(options.env);
|
|
78
|
+
if (!skipAuth && credentials) {
|
|
79
|
+
config.credentials = credentials;
|
|
80
|
+
}
|
|
81
|
+
const proxyUrl = resolveHttpProxyUrlForTarget(model.baseUrl, options.env);
|
|
82
|
+
if (proxyUrl) {
|
|
75
83
|
// Bedrock runtime uses NodeHttp2Handler by default since v3.798.0, which is based
|
|
76
84
|
// on `http2` module and has no support for http agent.
|
|
77
85
|
// Use NodeHttpHandler to support HTTP(S) proxy agents.
|
|
78
|
-
config.requestHandler = new NodeHttpHandler(
|
|
86
|
+
config.requestHandler = new NodeHttpHandler({
|
|
87
|
+
httpAgent: new HttpProxyAgent(proxyUrl),
|
|
88
|
+
httpsAgent: new HttpsProxyAgent(proxyUrl),
|
|
89
|
+
});
|
|
79
90
|
}
|
|
80
|
-
else if (
|
|
91
|
+
else if (getProviderEnvValue("AWS_BEDROCK_FORCE_HTTP1", options.env) === "1") {
|
|
81
92
|
// Some custom endpoints require HTTP/1.1 instead of HTTP/2
|
|
82
93
|
config.requestHandler = new NodeHttpHandler();
|
|
83
94
|
}
|
|
@@ -97,12 +108,12 @@ export const streamBedrock = (model, context, options = {}) => {
|
|
|
97
108
|
if (options.headers && Object.keys(options.headers).length > 0) {
|
|
98
109
|
addCustomHeadersMiddleware(client, options.headers);
|
|
99
110
|
}
|
|
100
|
-
const cacheRetention = resolveCacheRetention(options.cacheRetention);
|
|
111
|
+
const cacheRetention = resolveCacheRetention(options.cacheRetention, options.env);
|
|
101
112
|
const inferenceMaxTokens = options.maxTokens ?? (isAnthropicClaudeModel(model) ? model.maxTokens : undefined);
|
|
102
113
|
let commandInput = {
|
|
103
114
|
modelId: model.id,
|
|
104
|
-
messages: convertMessages(context, model, cacheRetention),
|
|
105
|
-
system: buildSystemPrompt(context.systemPrompt, model, cacheRetention),
|
|
115
|
+
messages: convertMessages(context, model, cacheRetention, options.env),
|
|
116
|
+
system: buildSystemPrompt(context.systemPrompt, model, cacheRetention, options.env),
|
|
106
117
|
inferenceConfig: {
|
|
107
118
|
...(inferenceMaxTokens !== undefined && { maxTokens: inferenceMaxTokens }),
|
|
108
119
|
...(options.temperature !== undefined && { temperature: options.temperature }),
|
|
@@ -432,11 +443,11 @@ function mapThinkingLevelToEffort(model, level) {
|
|
|
432
443
|
* Resolve cache retention preference.
|
|
433
444
|
* Defaults to "short" and uses PI_CACHE_RETENTION for backward compatibility.
|
|
434
445
|
*/
|
|
435
|
-
function resolveCacheRetention(cacheRetention) {
|
|
446
|
+
function resolveCacheRetention(cacheRetention, env) {
|
|
436
447
|
if (cacheRetention) {
|
|
437
448
|
return cacheRetention;
|
|
438
449
|
}
|
|
439
|
-
if (
|
|
450
|
+
if (getProviderEnvValue("PI_CACHE_RETENTION", env) === "long") {
|
|
440
451
|
return "long";
|
|
441
452
|
}
|
|
442
453
|
return "short";
|
|
@@ -467,13 +478,13 @@ function isAnthropicClaudeModel(model) {
|
|
|
467
478
|
* As a last resort, set AWS_BEDROCK_FORCE_CACHE=1 to enable cache points.
|
|
468
479
|
* Amazon Nova models have automatic caching and don't need explicit cache points.
|
|
469
480
|
*/
|
|
470
|
-
function supportsPromptCaching(model) {
|
|
481
|
+
function supportsPromptCaching(model, env) {
|
|
471
482
|
const candidates = getModelMatchCandidates(model.id, model.name);
|
|
472
483
|
const hasClaudeRef = candidates.some((s) => s.includes("claude"));
|
|
473
484
|
if (!hasClaudeRef) {
|
|
474
485
|
// Application inference profiles don't contain the model name in the ARN.
|
|
475
486
|
// Allow users to force cache points via environment variable.
|
|
476
|
-
if (
|
|
487
|
+
if (getProviderEnvValue("AWS_BEDROCK_FORCE_CACHE", env) === "1")
|
|
477
488
|
return true;
|
|
478
489
|
return false;
|
|
479
490
|
}
|
|
@@ -499,12 +510,12 @@ function supportsPromptCaching(model) {
|
|
|
499
510
|
function supportsThinkingSignature(model) {
|
|
500
511
|
return isAnthropicClaudeModel(model);
|
|
501
512
|
}
|
|
502
|
-
function buildSystemPrompt(systemPrompt, model, cacheRetention) {
|
|
513
|
+
function buildSystemPrompt(systemPrompt, model, cacheRetention, env) {
|
|
503
514
|
if (!systemPrompt)
|
|
504
515
|
return undefined;
|
|
505
516
|
const blocks = [{ text: sanitizeSurrogates(systemPrompt) }];
|
|
506
517
|
// Add cache point for supported Claude models when caching is enabled
|
|
507
|
-
if (cacheRetention !== "none" && supportsPromptCaching(model)) {
|
|
518
|
+
if (cacheRetention !== "none" && supportsPromptCaching(model, env)) {
|
|
508
519
|
blocks.push({
|
|
509
520
|
cachePoint: { type: CachePointType.DEFAULT, ...(cacheRetention === "long" ? { ttl: CacheTTL.ONE_HOUR } : {}) },
|
|
510
521
|
});
|
|
@@ -538,7 +549,7 @@ function convertToolResultContent(content) {
|
|
|
538
549
|
result.push({ text: EMPTY_TEXT_PLACEHOLDER });
|
|
539
550
|
return result;
|
|
540
551
|
}
|
|
541
|
-
function convertMessages(context, model, cacheRetention) {
|
|
552
|
+
function convertMessages(context, model, cacheRetention, env) {
|
|
542
553
|
const result = [];
|
|
543
554
|
const transformedMessages = transformMessages(context.messages, model, normalizeToolCallId);
|
|
544
555
|
for (let i = 0; i < transformedMessages.length; i++) {
|
|
@@ -683,7 +694,7 @@ function convertMessages(context, model, cacheRetention) {
|
|
|
683
694
|
}
|
|
684
695
|
}
|
|
685
696
|
// Add cache point to the last user message for supported Claude models when caching is enabled
|
|
686
|
-
if (cacheRetention !== "none" && supportsPromptCaching(model) && result.length > 0) {
|
|
697
|
+
if (cacheRetention !== "none" && supportsPromptCaching(model, env) && result.length > 0) {
|
|
687
698
|
const lastMessage = result[result.length - 1];
|
|
688
699
|
if (lastMessage.role === ConversationRole.USER && lastMessage.content) {
|
|
689
700
|
lastMessage.content.push({
|
|
@@ -736,16 +747,23 @@ function mapStopReason(reason) {
|
|
|
736
747
|
}
|
|
737
748
|
}
|
|
738
749
|
function getConfiguredBedrockRegion(options) {
|
|
739
|
-
|
|
740
|
-
|
|
741
|
-
|
|
742
|
-
|
|
750
|
+
return (options.region ||
|
|
751
|
+
getProviderEnvValue("AWS_REGION", options.env) ||
|
|
752
|
+
getProviderEnvValue("AWS_DEFAULT_REGION", options.env) ||
|
|
753
|
+
undefined);
|
|
743
754
|
}
|
|
744
|
-
function
|
|
745
|
-
|
|
746
|
-
|
|
755
|
+
function getConfiguredBedrockCredentials(env) {
|
|
756
|
+
const accessKeyId = getProviderEnvValue("AWS_ACCESS_KEY_ID", env);
|
|
757
|
+
const secretAccessKey = getProviderEnvValue("AWS_SECRET_ACCESS_KEY", env);
|
|
758
|
+
if (!accessKeyId || !secretAccessKey) {
|
|
759
|
+
return undefined;
|
|
747
760
|
}
|
|
748
|
-
|
|
761
|
+
const sessionToken = getProviderEnvValue("AWS_SESSION_TOKEN", env);
|
|
762
|
+
return {
|
|
763
|
+
accessKeyId,
|
|
764
|
+
secretAccessKey,
|
|
765
|
+
...(sessionToken ? { sessionToken } : {}),
|
|
766
|
+
};
|
|
749
767
|
}
|
|
750
768
|
function getStandardBedrockEndpointRegion(baseUrl) {
|
|
751
769
|
if (!baseUrl) {
|
|
@@ -760,12 +778,12 @@ function getStandardBedrockEndpointRegion(baseUrl) {
|
|
|
760
778
|
return undefined;
|
|
761
779
|
}
|
|
762
780
|
}
|
|
763
|
-
function shouldUseExplicitBedrockEndpoint(baseUrl, configuredRegion,
|
|
781
|
+
function shouldUseExplicitBedrockEndpoint(baseUrl, configuredRegion, hasAmbientConfiguredProfile) {
|
|
764
782
|
const endpointRegion = getStandardBedrockEndpointRegion(baseUrl);
|
|
765
783
|
if (!endpointRegion) {
|
|
766
784
|
return true;
|
|
767
785
|
}
|
|
768
|
-
return !configuredRegion && !
|
|
786
|
+
return !configuredRegion && !hasAmbientConfiguredProfile;
|
|
769
787
|
}
|
|
770
788
|
function isGovCloudBedrockTarget(model, options) {
|
|
771
789
|
const region = getConfiguredBedrockRegion(options);
|
|
@@ -3,6 +3,7 @@ import { calculateCost } from "../models.js";
|
|
|
3
3
|
import { AssistantMessageEventStream } from "../utils/event-stream.js";
|
|
4
4
|
import { headersToRecord } from "../utils/headers.js";
|
|
5
5
|
import { parseJsonWithRepair, parseStreamingJson } from "../utils/json-parse.js";
|
|
6
|
+
import { getProviderEnvValue } from "../utils/provider-env.js";
|
|
6
7
|
import { sanitizeSurrogates } from "../utils/sanitize-unicode.js";
|
|
7
8
|
import { resolveCloudflareBaseUrl } from "./cloudflare.js";
|
|
8
9
|
import { buildCopilotDynamicHeaders, hasCopilotVisionInput } from "./github-copilot-headers.js";
|
|
@@ -12,17 +13,17 @@ import { transformMessages } from "./transform-messages.js";
|
|
|
12
13
|
* Resolve cache retention preference.
|
|
13
14
|
* Defaults to "short" and uses PI_CACHE_RETENTION for backward compatibility.
|
|
14
15
|
*/
|
|
15
|
-
function resolveCacheRetention(cacheRetention) {
|
|
16
|
+
function resolveCacheRetention(cacheRetention, env) {
|
|
16
17
|
if (cacheRetention) {
|
|
17
18
|
return cacheRetention;
|
|
18
19
|
}
|
|
19
|
-
if (
|
|
20
|
+
if (getProviderEnvValue("PI_CACHE_RETENTION", env) === "long") {
|
|
20
21
|
return "long";
|
|
21
22
|
}
|
|
22
23
|
return "short";
|
|
23
24
|
}
|
|
24
|
-
function getCacheControl(model, cacheRetention) {
|
|
25
|
-
const retention = resolveCacheRetention(cacheRetention);
|
|
25
|
+
function getCacheControl(model, cacheRetention, env) {
|
|
26
|
+
const retention = resolveCacheRetention(cacheRetention, env);
|
|
26
27
|
if (retention === "none") {
|
|
27
28
|
return { retention };
|
|
28
29
|
}
|
|
@@ -319,9 +320,9 @@ export const streamAnthropic = (model, context, options) => {
|
|
|
319
320
|
hasImages,
|
|
320
321
|
});
|
|
321
322
|
}
|
|
322
|
-
const cacheRetention = options?.cacheRetention
|
|
323
|
+
const cacheRetention = resolveCacheRetention(options?.cacheRetention, options?.env);
|
|
323
324
|
const cacheSessionId = cacheRetention === "none" ? undefined : options?.sessionId;
|
|
324
|
-
const created = createClient(model, apiKey, options?.interleavedThinking ?? true, shouldUseFineGrainedToolStreamingBeta(model, context), options?.headers, copilotDynamicHeaders, cacheSessionId);
|
|
325
|
+
const created = createClient(model, apiKey, options?.interleavedThinking ?? true, shouldUseFineGrainedToolStreamingBeta(model, context), options?.headers, copilotDynamicHeaders, cacheSessionId, options?.env);
|
|
325
326
|
client = created.client;
|
|
326
327
|
isOAuth = created.isOAuthToken;
|
|
327
328
|
}
|
|
@@ -348,6 +349,7 @@ export const streamAnthropic = (model, context, options) => {
|
|
|
348
349
|
output.usage.output = event.message.usage.output_tokens || 0;
|
|
349
350
|
output.usage.cacheRead = event.message.usage.cache_read_input_tokens || 0;
|
|
350
351
|
output.usage.cacheWrite = event.message.usage.cache_creation_input_tokens || 0;
|
|
352
|
+
output.usage.cacheWrite1h = event.message.usage.cache_creation?.ephemeral_1h_input_tokens || 0;
|
|
351
353
|
// Anthropic doesn't provide total_tokens, compute from components
|
|
352
354
|
output.usage.totalTokens =
|
|
353
355
|
output.usage.input + output.usage.output + output.usage.cacheRead + output.usage.cacheWrite;
|
|
@@ -587,7 +589,7 @@ export const streamSimpleAnthropic = (model, context, options) => {
|
|
|
587
589
|
function isOAuthToken(apiKey) {
|
|
588
590
|
return apiKey.includes("sk-ant-oat");
|
|
589
591
|
}
|
|
590
|
-
function createClient(model, apiKey, interleavedThinking, useFineGrainedToolStreamingBeta, optionsHeaders, dynamicHeaders, sessionId) {
|
|
592
|
+
function createClient(model, apiKey, interleavedThinking, useFineGrainedToolStreamingBeta, optionsHeaders, dynamicHeaders, sessionId, env) {
|
|
591
593
|
// Adaptive thinking models have interleaved thinking built in, so skip the beta header.
|
|
592
594
|
const needsInterleavedBeta = interleavedThinking && model.compat?.forceAdaptiveThinking !== true;
|
|
593
595
|
const betaFeatures = [];
|
|
@@ -601,7 +603,7 @@ function createClient(model, apiKey, interleavedThinking, useFineGrainedToolStre
|
|
|
601
603
|
const client = new Anthropic({
|
|
602
604
|
apiKey: null,
|
|
603
605
|
authToken: null,
|
|
604
|
-
baseURL: resolveCloudflareBaseUrl(model),
|
|
606
|
+
baseURL: resolveCloudflareBaseUrl(model, env),
|
|
605
607
|
dangerouslyAllowBrowser: true,
|
|
606
608
|
defaultHeaders: mergeHeaders({
|
|
607
609
|
accept: "application/json",
|
|
@@ -662,7 +664,7 @@ function createClient(model, apiKey, interleavedThinking, useFineGrainedToolStre
|
|
|
662
664
|
return { client, isOAuthToken: false };
|
|
663
665
|
}
|
|
664
666
|
function buildParams(model, context, isOAuthToken, options) {
|
|
665
|
-
const { cacheControl } = getCacheControl(model, options?.cacheRetention);
|
|
667
|
+
const { cacheControl } = getCacheControl(model, options?.cacheRetention, options?.env);
|
|
666
668
|
const compat = getAnthropicCompat(model);
|
|
667
669
|
const params = {
|
|
668
670
|
model: model.id,
|
|
@@ -2,6 +2,7 @@ import { AzureOpenAI } from "openai";
|
|
|
2
2
|
import { clampThinkingLevel } from "../models.js";
|
|
3
3
|
import { AssistantMessageEventStream } from "../utils/event-stream.js";
|
|
4
4
|
import { headersToRecord } from "../utils/headers.js";
|
|
5
|
+
import { getProviderEnvValue } from "../utils/provider-env.js";
|
|
5
6
|
import { clampOpenAIPromptCacheKey } from "./openai-prompt-cache.js";
|
|
6
7
|
import { convertResponsesMessages, convertResponsesTools, processResponsesStream } from "./openai-responses-shared.js";
|
|
7
8
|
import { buildBaseOptions } from "./simple-options.js";
|
|
@@ -26,7 +27,7 @@ function resolveDeploymentName(model, options) {
|
|
|
26
27
|
if (options?.azureDeploymentName) {
|
|
27
28
|
return options.azureDeploymentName;
|
|
28
29
|
}
|
|
29
|
-
const mappedDeployment = parseDeploymentNameMap(
|
|
30
|
+
const mappedDeployment = parseDeploymentNameMap(getProviderEnvValue("AZURE_OPENAI_DEPLOYMENT_NAME_MAP", options?.env)).get(model.id);
|
|
30
31
|
return mappedDeployment || model.id;
|
|
31
32
|
}
|
|
32
33
|
function formatAzureOpenAIError(error) {
|
|
@@ -150,9 +151,11 @@ function buildDefaultBaseUrl(resourceName) {
|
|
|
150
151
|
return `https://${resourceName}.openai.azure.com/openai/v1`;
|
|
151
152
|
}
|
|
152
153
|
function resolveAzureConfig(model, options) {
|
|
153
|
-
const apiVersion = options?.azureApiVersion ||
|
|
154
|
-
|
|
155
|
-
|
|
154
|
+
const apiVersion = options?.azureApiVersion ||
|
|
155
|
+
getProviderEnvValue("AZURE_OPENAI_API_VERSION", options?.env) ||
|
|
156
|
+
DEFAULT_AZURE_API_VERSION;
|
|
157
|
+
const baseUrl = options?.azureBaseUrl?.trim() || getProviderEnvValue("AZURE_OPENAI_BASE_URL", options?.env)?.trim() || undefined;
|
|
158
|
+
const resourceName = options?.azureResourceName || getProviderEnvValue("AZURE_OPENAI_RESOURCE_NAME", options?.env);
|
|
156
159
|
let resolvedBaseUrl = baseUrl;
|
|
157
160
|
if (!resolvedBaseUrl && resourceName) {
|
|
158
161
|
resolvedBaseUrl = buildDefaultBaseUrl(resourceName);
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { getProviderEnvValue } from "../utils/provider-env.js";
|
|
1
2
|
/** Workers AI direct endpoint. */
|
|
2
3
|
export const CLOUDFLARE_WORKERS_AI_BASE_URL = "https://api.cloudflare.com/client/v4/accounts/{CLOUDFLARE_ACCOUNT_ID}/ai/v1";
|
|
3
4
|
/** AI Gateway Unified API. https://developers.cloudflare.com/ai-gateway/usage/unified-api/ */
|
|
@@ -9,13 +10,13 @@ export const CLOUDFLARE_AI_GATEWAY_ANTHROPIC_BASE_URL = "https://gateway.ai.clou
|
|
|
9
10
|
export function isCloudflareProvider(provider) {
|
|
10
11
|
return provider === "cloudflare-workers-ai" || provider === "cloudflare-ai-gateway";
|
|
11
12
|
}
|
|
12
|
-
/** Substitute `{VAR}` placeholders in a Cloudflare baseUrl from process.env. */
|
|
13
|
-
export function resolveCloudflareBaseUrl(model) {
|
|
13
|
+
/** Substitute `{VAR}` placeholders in a Cloudflare baseUrl from provider env or process.env. */
|
|
14
|
+
export function resolveCloudflareBaseUrl(model, env) {
|
|
14
15
|
const url = model.baseUrl;
|
|
15
16
|
if (!url.includes("{"))
|
|
16
17
|
return url;
|
|
17
18
|
const baseUrl = url.replace(/\{([A-Z_][A-Z0-9_]*)\}/g, (_match, name) => {
|
|
18
|
-
const value =
|
|
19
|
+
const value = getProviderEnvValue(name, env);
|
|
19
20
|
if (!value) {
|
|
20
21
|
throw new Error(`${name} is required for provider ${model.provider} but is not set.`);
|
|
21
22
|
}
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { GoogleGenAI, ResourceScope, ThinkingLevel, } from "@google/genai";
|
|
2
2
|
import { calculateCost, clampThinkingLevel } from "../models.js";
|
|
3
3
|
import { AssistantMessageEventStream } from "../utils/event-stream.js";
|
|
4
|
+
import { getProviderEnvValue } from "../utils/provider-env.js";
|
|
4
5
|
import { sanitizeSurrogates } from "../utils/sanitize-unicode.js";
|
|
5
6
|
import { convertMessages, convertTools, isThinkingPart, mapStopReason, mapToolChoice, retainThoughtSignature, } from "./google-shared.js";
|
|
6
7
|
import { buildBaseOptions } from "./simple-options.js";
|
|
@@ -40,7 +41,7 @@ export const streamGoogleVertex = (model, context, options) => {
|
|
|
40
41
|
// Create the client using either a Vertex API key, if provided, or ADC with project and location
|
|
41
42
|
const client = apiKey
|
|
42
43
|
? createClientWithApiKey(model, apiKey, options?.headers)
|
|
43
|
-
: createClient(model, resolveProject(options), resolveLocation(options), options?.headers);
|
|
44
|
+
: createClient(model, resolveProject(options), resolveLocation(options), options?.headers, options?.env);
|
|
44
45
|
let params = buildParams(model, context, options);
|
|
45
46
|
const nextParams = await options?.onPayload?.(params, model);
|
|
46
47
|
if (nextParams !== undefined) {
|
|
@@ -251,12 +252,14 @@ export const streamSimpleGoogleVertex = (model, context, options) => {
|
|
|
251
252
|
},
|
|
252
253
|
});
|
|
253
254
|
};
|
|
254
|
-
function createClient(model, project, location, optionsHeaders) {
|
|
255
|
+
function createClient(model, project, location, optionsHeaders, env) {
|
|
256
|
+
const googleAuthOptions = buildGoogleAuthOptions(env);
|
|
255
257
|
return new GoogleGenAI({
|
|
256
258
|
vertexai: true,
|
|
257
259
|
project,
|
|
258
260
|
location,
|
|
259
261
|
apiVersion: API_VERSION,
|
|
262
|
+
...(googleAuthOptions ? { googleAuthOptions } : {}),
|
|
260
263
|
httpOptions: buildHttpOptions(model, optionsHeaders),
|
|
261
264
|
});
|
|
262
265
|
}
|
|
@@ -299,6 +302,10 @@ function baseUrlIncludesApiVersion(baseUrl) {
|
|
|
299
302
|
return /(?:^|\/)v\d+(?:beta\d*)?(?:\/|$)/.test(baseUrl);
|
|
300
303
|
}
|
|
301
304
|
}
|
|
305
|
+
function buildGoogleAuthOptions(env) {
|
|
306
|
+
const keyFilename = getProviderEnvValue("GOOGLE_APPLICATION_CREDENTIALS", env);
|
|
307
|
+
return keyFilename ? { keyFilename } : undefined;
|
|
308
|
+
}
|
|
302
309
|
function resolveApiKey(options) {
|
|
303
310
|
const apiKey = options?.apiKey?.trim();
|
|
304
311
|
if (!apiKey || apiKey === GCP_VERTEX_CREDENTIALS_MARKER || isPlaceholderApiKey(apiKey)) {
|
|
@@ -310,14 +317,16 @@ function isPlaceholderApiKey(apiKey) {
|
|
|
310
317
|
return /^<[^>]+>$/.test(apiKey);
|
|
311
318
|
}
|
|
312
319
|
function resolveProject(options) {
|
|
313
|
-
const project = options?.project ||
|
|
320
|
+
const project = options?.project ||
|
|
321
|
+
getProviderEnvValue("GOOGLE_CLOUD_PROJECT", options?.env) ||
|
|
322
|
+
getProviderEnvValue("GCLOUD_PROJECT", options?.env);
|
|
314
323
|
if (!project) {
|
|
315
324
|
throw new Error("Vertex AI requires a project ID. Set GOOGLE_CLOUD_PROJECT/GCLOUD_PROJECT or pass project in options.");
|
|
316
325
|
}
|
|
317
326
|
return project;
|
|
318
327
|
}
|
|
319
328
|
function resolveLocation(options) {
|
|
320
|
-
const location = options?.location ||
|
|
329
|
+
const location = options?.location || getProviderEnvValue("GOOGLE_CLOUD_LOCATION", options?.env);
|
|
321
330
|
if (!location) {
|
|
322
331
|
throw new Error("Vertex AI requires a location. Set GOOGLE_CLOUD_LOCATION or pass location in options.");
|
|
323
332
|
}
|
|
@@ -377,7 +386,8 @@ function isGemini3ProModel(model) {
|
|
|
377
386
|
return /gemini-3(?:\.\d+)?-pro/.test(model.id.toLowerCase());
|
|
378
387
|
}
|
|
379
388
|
function isGemini3FlashModel(model) {
|
|
380
|
-
|
|
389
|
+
const id = model.id.toLowerCase();
|
|
390
|
+
return /gemini-3(?:\.\d+)?-flash/.test(id) || id === "gemini-flash-latest" || id === "gemini-flash-lite-latest";
|
|
381
391
|
}
|
|
382
392
|
function getDisabledThinkingConfig(model) {
|
|
383
393
|
// Google docs: Gemini 3.1 Pro cannot disable thinking, and Gemini 3 Flash / Flash-Lite
|
|
@@ -316,7 +316,8 @@ function isGemini3ProModel(model) {
|
|
|
316
316
|
return /gemini-3(?:\.\d+)?-pro/.test(model.id.toLowerCase());
|
|
317
317
|
}
|
|
318
318
|
function isGemini3FlashModel(model) {
|
|
319
|
-
|
|
319
|
+
const id = model.id.toLowerCase();
|
|
320
|
+
return /gemini-3(?:\.\d+)?-flash/.test(id) || id === "gemini-flash-latest" || id === "gemini-flash-lite-latest";
|
|
320
321
|
}
|
|
321
322
|
function getDisabledThinkingConfig(model) {
|
|
322
323
|
// Google docs: Gemini 3.1 Pro cannot disable thinking, and Gemini 3 Flash / Flash-Lite
|
|
@@ -21,6 +21,7 @@ import { combineAbortSignals } from "../utils/abort-signals.js";
|
|
|
21
21
|
import { appendAssistantMessageDiagnostic, createAssistantMessageDiagnostic, formatThrownValue, } from "../utils/diagnostics.js";
|
|
22
22
|
import { AssistantMessageEventStream } from "../utils/event-stream.js";
|
|
23
23
|
import { headersToRecord } from "../utils/headers.js";
|
|
24
|
+
import { resolveHttpProxyUrlForTarget } from "../utils/node-http-proxy.js";
|
|
24
25
|
import { clampOpenAIPromptCacheKey } from "./openai-prompt-cache.js";
|
|
25
26
|
import { convertResponsesMessages, convertResponsesTools, processResponsesStream } from "./openai-responses-shared.js";
|
|
26
27
|
import { buildBaseOptions } from "./simple-options.js";
|
|
@@ -598,16 +599,13 @@ function recordWebSocketFailure(sessionId, error) {
|
|
|
598
599
|
stats.websocketFallbackActive = true;
|
|
599
600
|
}
|
|
600
601
|
let _cachedWebsocket = null;
|
|
601
|
-
async function getWebSocketConstructor() {
|
|
602
|
-
if (_cachedWebsocket)
|
|
602
|
+
async function getWebSocketConstructor(env) {
|
|
603
|
+
if (!env && _cachedWebsocket)
|
|
603
604
|
return _cachedWebsocket;
|
|
604
605
|
// bun doesn't respect http proxy envs, ref: https://github.com/oven-sh/bun/issues/15489
|
|
605
606
|
// TODO: remove this when bun supports proxy envs in websocket.
|
|
606
|
-
if (process
|
|
607
|
-
|
|
608
|
-
const m = await dynamicImport("proxy-from-env");
|
|
609
|
-
const getProxyForUrl = m.getProxyForUrl;
|
|
610
|
-
_cachedWebsocket = class extends WebSocket {
|
|
607
|
+
if (typeof process !== "undefined" && process.versions?.bun) {
|
|
608
|
+
const WebSocketWithProxy = class extends WebSocket {
|
|
611
609
|
constructor(url, options) {
|
|
612
610
|
let _opts = {};
|
|
613
611
|
if (Array.isArray(options) || typeof options === "string") {
|
|
@@ -616,11 +614,14 @@ async function getWebSocketConstructor() {
|
|
|
616
614
|
else {
|
|
617
615
|
_opts = { ...options };
|
|
618
616
|
}
|
|
619
|
-
const
|
|
620
|
-
super(url, { ..._opts, ...(
|
|
617
|
+
const proxyUrl = resolveHttpProxyUrlForTarget(url.toString().replace(/^wss:/, "https:").replace(/^ws:/, "http:"), env);
|
|
618
|
+
super(url, { ..._opts, ...(proxyUrl ? { proxy: proxyUrl.toString() } : {}) });
|
|
621
619
|
}
|
|
622
620
|
};
|
|
623
|
-
|
|
621
|
+
if (!env) {
|
|
622
|
+
_cachedWebsocket = WebSocketWithProxy;
|
|
623
|
+
}
|
|
624
|
+
return WebSocketWithProxy;
|
|
624
625
|
}
|
|
625
626
|
const ctor = globalThis.WebSocket;
|
|
626
627
|
if (typeof ctor !== "function")
|
|
@@ -665,8 +666,8 @@ function scheduleSessionWebSocketExpiry(sessionId, entry) {
|
|
|
665
666
|
websocketSessionCache.delete(sessionId);
|
|
666
667
|
}, SESSION_WEBSOCKET_CACHE_TTL_MS);
|
|
667
668
|
}
|
|
668
|
-
async function connectWebSocket(url, headers, signal, connectTimeoutMs = DEFAULT_WEBSOCKET_CONNECT_TIMEOUT_MS) {
|
|
669
|
-
const WebSocketCtor = await getWebSocketConstructor();
|
|
669
|
+
async function connectWebSocket(url, headers, signal, connectTimeoutMs = DEFAULT_WEBSOCKET_CONNECT_TIMEOUT_MS, env) {
|
|
670
|
+
const WebSocketCtor = await getWebSocketConstructor(env);
|
|
670
671
|
if (!WebSocketCtor) {
|
|
671
672
|
throw new Error("WebSocket transport is not available in this runtime");
|
|
672
673
|
}
|
|
@@ -733,9 +734,9 @@ async function connectWebSocket(url, headers, signal, connectTimeoutMs = DEFAULT
|
|
|
733
734
|
}
|
|
734
735
|
});
|
|
735
736
|
}
|
|
736
|
-
async function acquireWebSocket(url, headers, sessionId, signal, connectTimeoutMs) {
|
|
737
|
+
async function acquireWebSocket(url, headers, sessionId, signal, connectTimeoutMs, env) {
|
|
737
738
|
if (!sessionId) {
|
|
738
|
-
const socket = await connectWebSocket(url, headers, signal, connectTimeoutMs);
|
|
739
|
+
const socket = await connectWebSocket(url, headers, signal, connectTimeoutMs, env);
|
|
739
740
|
return {
|
|
740
741
|
socket,
|
|
741
742
|
reused: false,
|
|
@@ -766,7 +767,7 @@ async function acquireWebSocket(url, headers, sessionId, signal, connectTimeoutM
|
|
|
766
767
|
};
|
|
767
768
|
}
|
|
768
769
|
if (cached.busy) {
|
|
769
|
-
const socket = await connectWebSocket(url, headers, signal, connectTimeoutMs);
|
|
770
|
+
const socket = await connectWebSocket(url, headers, signal, connectTimeoutMs, env);
|
|
770
771
|
return {
|
|
771
772
|
socket,
|
|
772
773
|
reused: false,
|
|
@@ -780,7 +781,7 @@ async function acquireWebSocket(url, headers, sessionId, signal, connectTimeoutM
|
|
|
780
781
|
websocketSessionCache.delete(sessionId);
|
|
781
782
|
}
|
|
782
783
|
}
|
|
783
|
-
const socket = await connectWebSocket(url, headers, signal, connectTimeoutMs);
|
|
784
|
+
const socket = await connectWebSocket(url, headers, signal, connectTimeoutMs, env);
|
|
784
785
|
const entry = { socket, busy: true };
|
|
785
786
|
websocketSessionCache.set(sessionId, entry);
|
|
786
787
|
return {
|
|
@@ -1020,7 +1021,7 @@ async function* startWebSocketOutputOnFirstEvent(events, output, stream, onStart
|
|
|
1020
1021
|
}
|
|
1021
1022
|
}
|
|
1022
1023
|
async function processWebSocketStream(url, body, headers, output, stream, model, onStart, idleTimeoutMs, websocketConnectTimeoutMs, options) {
|
|
1023
|
-
const { socket, entry, reused, release } = await acquireWebSocket(url, headers, options?.sessionId, options?.signal, websocketConnectTimeoutMs);
|
|
1024
|
+
const { socket, entry, reused, release } = await acquireWebSocket(url, headers, options?.sessionId, options?.signal, websocketConnectTimeoutMs, options?.env);
|
|
1024
1025
|
let keepConnection = true;
|
|
1025
1026
|
const useCachedContext = options?.transport === "websocket-cached" || options?.transport === "auto";
|
|
1026
1027
|
// ChatGPT Codex Responses rejects `store: true` ("Store must be set to false").
|
|
@@ -3,6 +3,7 @@ import { calculateCost, clampThinkingLevel } from "../models.js";
|
|
|
3
3
|
import { AssistantMessageEventStream } from "../utils/event-stream.js";
|
|
4
4
|
import { headersToRecord } from "../utils/headers.js";
|
|
5
5
|
import { parseStreamingJson } from "../utils/json-parse.js";
|
|
6
|
+
import { getProviderEnvValue } from "../utils/provider-env.js";
|
|
6
7
|
import { sanitizeSurrogates } from "../utils/sanitize-unicode.js";
|
|
7
8
|
import { isCloudflareProvider, resolveCloudflareBaseUrl } from "./cloudflare.js";
|
|
8
9
|
import { buildCopilotDynamicHeaders, hasCopilotVisionInput } from "./github-copilot-headers.js";
|
|
@@ -39,11 +40,11 @@ function isToolCallBlock(block) {
|
|
|
39
40
|
function isImageContentBlock(block) {
|
|
40
41
|
return block.type === "image";
|
|
41
42
|
}
|
|
42
|
-
function resolveCacheRetention(cacheRetention) {
|
|
43
|
+
function resolveCacheRetention(cacheRetention, env) {
|
|
43
44
|
if (cacheRetention) {
|
|
44
45
|
return cacheRetention;
|
|
45
46
|
}
|
|
46
|
-
if (
|
|
47
|
+
if (getProviderEnvValue("PI_CACHE_RETENTION", env) === "long") {
|
|
47
48
|
return "long";
|
|
48
49
|
}
|
|
49
50
|
return "short";
|
|
@@ -74,9 +75,9 @@ export const streamOpenAICompletions = (model, context, options) => {
|
|
|
74
75
|
throw new Error(`No API key for provider: ${model.provider}`);
|
|
75
76
|
}
|
|
76
77
|
const compat = getCompat(model);
|
|
77
|
-
const cacheRetention = resolveCacheRetention(options?.cacheRetention);
|
|
78
|
+
const cacheRetention = resolveCacheRetention(options?.cacheRetention, options?.env);
|
|
78
79
|
const cacheSessionId = cacheRetention === "none" ? undefined : options?.sessionId;
|
|
79
|
-
const client = createClient(model, context, apiKey, options?.headers, cacheSessionId, compat);
|
|
80
|
+
const client = createClient(model, context, apiKey, options?.headers, cacheSessionId, compat, options?.env);
|
|
80
81
|
let params = buildParams(model, context, options, compat, cacheRetention);
|
|
81
82
|
const nextParams = await options?.onPayload?.(params, model);
|
|
82
83
|
if (nextParams !== undefined) {
|
|
@@ -351,7 +352,7 @@ export const streamSimpleOpenAICompletions = (model, context, options) => {
|
|
|
351
352
|
toolChoice,
|
|
352
353
|
});
|
|
353
354
|
};
|
|
354
|
-
function createClient(model, context, apiKey, optionsHeaders, sessionId, compat = getCompat(model)) {
|
|
355
|
+
function createClient(model, context, apiKey, optionsHeaders, sessionId, compat = getCompat(model), env) {
|
|
355
356
|
const headers = { ...model.headers };
|
|
356
357
|
if (model.provider === "github-copilot") {
|
|
357
358
|
const hasImages = hasCopilotVisionInput(context.messages);
|
|
@@ -379,12 +380,12 @@ function createClient(model, context, apiKey, optionsHeaders, sessionId, compat
|
|
|
379
380
|
: headers;
|
|
380
381
|
return new OpenAI({
|
|
381
382
|
apiKey,
|
|
382
|
-
baseURL: isCloudflareProvider(model.provider) ? resolveCloudflareBaseUrl(model) : model.baseUrl,
|
|
383
|
+
baseURL: isCloudflareProvider(model.provider) ? resolveCloudflareBaseUrl(model, env) : model.baseUrl,
|
|
383
384
|
dangerouslyAllowBrowser: true,
|
|
384
385
|
defaultHeaders,
|
|
385
386
|
});
|
|
386
387
|
}
|
|
387
|
-
function buildParams(model, context, options, compat = getCompat(model), cacheRetention = resolveCacheRetention(options?.cacheRetention)) {
|
|
388
|
+
function buildParams(model, context, options, compat = getCompat(model), cacheRetention = resolveCacheRetention(options?.cacheRetention, options?.env)) {
|
|
388
389
|
const messages = convertMessages(model, context, compat);
|
|
389
390
|
const cacheControl = getCompatCacheControl(compat, cacheRetention);
|
|
390
391
|
const params = {
|
|
@@ -433,6 +434,13 @@ function buildParams(model, context, options, compat = getCompat(model), cacheRe
|
|
|
433
434
|
if (compat.thinkingFormat === "zai" && model.reasoning) {
|
|
434
435
|
const zaiParams = params;
|
|
435
436
|
zaiParams.thinking = { type: options?.reasoningEffort ? "enabled" : "disabled" };
|
|
437
|
+
if (options?.reasoningEffort && compat.supportsReasoningEffort) {
|
|
438
|
+
const mappedEffort = model.thinkingLevelMap?.[options.reasoningEffort];
|
|
439
|
+
const effort = mappedEffort === undefined ? options.reasoningEffort : mappedEffort;
|
|
440
|
+
if (typeof effort === "string") {
|
|
441
|
+
zaiParams.reasoning_effort = effort;
|
|
442
|
+
}
|
|
443
|
+
}
|
|
436
444
|
}
|
|
437
445
|
else if (compat.thinkingFormat === "qwen" && model.reasoning) {
|
|
438
446
|
params.enable_thinking = !!options?.reasoningEffort;
|
|
@@ -444,7 +452,12 @@ function buildParams(model, context, options, compat = getCompat(model), cacheRe
|
|
|
444
452
|
};
|
|
445
453
|
}
|
|
446
454
|
else if (compat.thinkingFormat === "deepseek" && model.reasoning) {
|
|
447
|
-
|
|
455
|
+
if (options?.reasoningEffort) {
|
|
456
|
+
params.thinking = { type: "enabled" };
|
|
457
|
+
}
|
|
458
|
+
else if (model.thinkingLevelMap?.off !== null) {
|
|
459
|
+
params.thinking = { type: "disabled" };
|
|
460
|
+
}
|
|
448
461
|
if (options?.reasoningEffort && compat.supportsReasoningEffort) {
|
|
449
462
|
params.reasoning_effort =
|
|
450
463
|
model.thinkingLevelMap?.[options.reasoningEffort] ?? options.reasoningEffort;
|
|
@@ -393,7 +393,8 @@ export async function processResponsesStream(openaiStream, output, stream, model
|
|
|
393
393
|
currentBlock = null;
|
|
394
394
|
}
|
|
395
395
|
else if (item.type === "message" && currentBlock?.type === "text") {
|
|
396
|
-
currentBlock.text =
|
|
396
|
+
currentBlock.text =
|
|
397
|
+
item.content?.map((c) => (c.type === "output_text" ? c.text : c.refusal)).join("") || "";
|
|
397
398
|
currentBlock.textSignature = encodeTextSignatureV1(item.id, item.phase ?? undefined);
|
|
398
399
|
stream.push({
|
|
399
400
|
type: "text_end",
|