@shawnstack/quickforge 1.3.17 → 1.3.19
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 +10 -10
- package/bin/quickforge.mjs +258 -49
- package/dist/assets/anthropic-Bj3HAZgj.js +39 -0
- package/dist/assets/azure-openai-responses-IdZZrSrI.js +1 -0
- package/dist/assets/github-copilot-headers-CMb2BbzT.js +1 -0
- package/dist/assets/google-Brt_lS1J.js +1 -0
- package/dist/assets/{google-shared-XhYUKiGZ.js → google-shared-CLc4ziON.js} +3 -3
- package/dist/assets/google-vertex-B6HsoZ34.js +1 -0
- package/dist/assets/{index-Dm7aEWvT.js → index-D0CVLdX_.js} +525 -489
- package/dist/assets/index-D0W9hAl_.css +3 -0
- package/dist/assets/{mistral-DxhS4Wkn.js → mistral-CenXqwPz.js} +3 -3
- package/dist/assets/openai-codex-responses-D9ffGwbj.js +7 -0
- package/dist/assets/openai-completions-eWdeSGBG.js +5 -0
- package/dist/assets/openai-responses-Cavpmjeu.js +1 -0
- package/dist/assets/{openai-responses-shared-f_P3e1nz.js → openai-responses-shared-DF3ZGaUx.js} +5 -3
- package/dist/assets/transform-messages-CmnxG9RB.js +1 -0
- package/dist/index.html +2 -2
- package/node_modules/@anthropic-ai/sdk/CHANGELOG.md +34 -0
- package/node_modules/@anthropic-ai/sdk/bin/migration-config.json +185 -0
- package/node_modules/@anthropic-ai/sdk/package.json +1 -1
- package/node_modules/@anthropic-ai/sdk/resources/beta/beta.js +4 -0
- package/node_modules/@anthropic-ai/sdk/resources/beta/beta.mjs +4 -0
- package/node_modules/@anthropic-ai/sdk/resources/beta/files.js +5 -5
- package/node_modules/@anthropic-ai/sdk/resources/beta/files.mjs +5 -5
- package/node_modules/@anthropic-ai/sdk/resources/beta/index.js +11 -9
- package/node_modules/@anthropic-ai/sdk/resources/beta/index.mjs +1 -0
- package/node_modules/@anthropic-ai/sdk/resources/beta/memory-stores/index.js +11 -0
- package/node_modules/@anthropic-ai/sdk/resources/beta/memory-stores/index.mjs +5 -0
- package/node_modules/@anthropic-ai/sdk/resources/beta/memory-stores/memories.js +130 -0
- package/node_modules/@anthropic-ai/sdk/resources/beta/memory-stores/memories.mjs +126 -0
- package/node_modules/@anthropic-ai/sdk/resources/beta/memory-stores/memory-stores.js +145 -0
- package/node_modules/@anthropic-ai/sdk/resources/beta/memory-stores/memory-stores.mjs +140 -0
- package/node_modules/@anthropic-ai/sdk/resources/beta/memory-stores/memory-versions.js +81 -0
- package/node_modules/@anthropic-ai/sdk/resources/beta/memory-stores/memory-versions.mjs +77 -0
- package/node_modules/@anthropic-ai/sdk/resources/beta/memory-stores.js +6 -0
- package/node_modules/@anthropic-ai/sdk/resources/beta/memory-stores.mjs +3 -0
- package/node_modules/@anthropic-ai/sdk/tools/memory/node.js +12 -5
- package/node_modules/@anthropic-ai/sdk/tools/memory/node.mjs +12 -5
- package/node_modules/@anthropic-ai/sdk/version.js +1 -1
- package/node_modules/@anthropic-ai/sdk/version.mjs +1 -1
- package/node_modules/@aws-sdk/client-bedrock-runtime/package.json +5 -5
- package/node_modules/@aws-sdk/core/package.json +2 -2
- package/node_modules/@aws-sdk/credential-provider-env/package.json +2 -2
- package/node_modules/@aws-sdk/credential-provider-http/dist-cjs/fromHttp/fromHttp.js +12 -6
- package/node_modules/@aws-sdk/credential-provider-http/dist-es/fromHttp/fromHttp.js +12 -6
- package/node_modules/@aws-sdk/credential-provider-http/package.json +3 -2
- package/node_modules/@aws-sdk/credential-provider-ini/package.json +9 -9
- package/node_modules/@aws-sdk/credential-provider-login/package.json +3 -3
- package/node_modules/@aws-sdk/credential-provider-node/package.json +7 -7
- package/node_modules/@aws-sdk/credential-provider-process/package.json +2 -2
- package/node_modules/@aws-sdk/credential-provider-sso/package.json +4 -4
- package/node_modules/@aws-sdk/credential-provider-web-identity/package.json +3 -3
- package/node_modules/@aws-sdk/middleware-websocket/package.json +2 -2
- package/node_modules/@aws-sdk/nested-clients/dist-cjs/submodules/cognito-identity/index.js +1 -1
- package/node_modules/@aws-sdk/nested-clients/dist-cjs/submodules/signin/index.js +1 -1
- package/node_modules/@aws-sdk/nested-clients/dist-cjs/submodules/sso/index.js +1 -1
- package/node_modules/@aws-sdk/nested-clients/dist-cjs/submodules/sso-oidc/index.js +1 -1
- package/node_modules/@aws-sdk/nested-clients/dist-cjs/submodules/sts/index.js +1 -1
- package/node_modules/@aws-sdk/nested-clients/package.json +3 -3
- package/node_modules/@aws-sdk/signature-v4-multi-region/package.json +1 -2
- package/node_modules/@aws-sdk/token-providers/package.json +3 -3
- package/node_modules/@aws-sdk/xml-builder/package.json +2 -2
- package/node_modules/@mariozechner/pi-agent-core/README.md +14 -0
- package/node_modules/@mariozechner/pi-agent-core/dist/agent-loop.js +9 -0
- package/node_modules/@mariozechner/pi-agent-core/dist/agent.js +1 -1
- package/node_modules/@mariozechner/pi-agent-core/package.json +2 -2
- package/node_modules/@mariozechner/pi-ai/README.md +20 -31
- package/node_modules/@mariozechner/pi-ai/dist/env-api-keys.js +7 -0
- package/node_modules/@mariozechner/pi-ai/dist/index.js +2 -0
- package/node_modules/@mariozechner/pi-ai/dist/models.generated.js +2420 -1213
- package/node_modules/@mariozechner/pi-ai/dist/models.js +28 -20
- package/node_modules/@mariozechner/pi-ai/dist/providers/amazon-bedrock.js +11 -11
- package/node_modules/@mariozechner/pi-ai/dist/providers/anthropic.js +43 -26
- package/node_modules/@mariozechner/pi-ai/dist/providers/azure-openai-responses.js +12 -6
- package/node_modules/@mariozechner/pi-ai/dist/providers/cloudflare.js +10 -3
- package/node_modules/@mariozechner/pi-ai/dist/providers/google-shared.js +4 -13
- package/node_modules/@mariozechner/pi-ai/dist/providers/google-vertex.js +4 -3
- package/node_modules/@mariozechner/pi-ai/dist/providers/google.js +4 -3
- package/node_modules/@mariozechner/pi-ai/dist/providers/mistral.js +8 -7
- package/node_modules/@mariozechner/pi-ai/dist/providers/openai-codex-responses.js +296 -41
- package/node_modules/@mariozechner/pi-ai/dist/providers/openai-completions.js +169 -153
- package/node_modules/@mariozechner/pi-ai/dist/providers/openai-responses-shared.js +14 -1
- package/node_modules/@mariozechner/pi-ai/dist/providers/openai-responses.js +22 -8
- package/node_modules/@mariozechner/pi-ai/dist/providers/register-builtins.js +0 -18
- package/node_modules/@mariozechner/pi-ai/dist/providers/simple-options.js +1 -0
- package/node_modules/@mariozechner/pi-ai/dist/session-resources.js +22 -0
- package/node_modules/@mariozechner/pi-ai/dist/utils/diagnostics.js +25 -0
- package/node_modules/@mariozechner/pi-ai/dist/utils/oauth/index.js +0 -10
- package/node_modules/@mariozechner/pi-ai/dist/utils/oauth/openai-codex.js +25 -14
- package/node_modules/@mariozechner/pi-ai/dist/utils/overflow.js +14 -0
- package/node_modules/@mariozechner/pi-ai/package.json +2 -6
- package/package.json +3 -3
- package/server/agent-manager.mjs +279 -12
- package/server/auto-compaction.mjs +1 -2
- package/server/conversation-compaction.mjs +0 -5
- package/server/index.mjs +1 -0
- package/server/routes/static.mjs +1 -0
- package/server/routes/tools.mjs +3 -1
- package/server/session-utils.mjs +6 -1
- package/server/share-store.mjs +27 -4
- package/server/subagents.mjs +101 -0
- package/server/system-prompt.mjs +30 -1
- package/server/tools/definitions.mjs +20 -0
- package/server/tools/index.mjs +956 -726
- package/dist/assets/anthropic-Ck2DxOfr.js +0 -39
- package/dist/assets/azure-openai-responses-DIoz5q4Z.js +0 -1
- package/dist/assets/github-copilot-headers-CrI0CIJ7.js +0 -1
- package/dist/assets/google-Dau-4ve_.js +0 -1
- package/dist/assets/google-gemini-cli-DttMmbGb.js +0 -2
- package/dist/assets/google-vertex-BeukMl44.js +0 -1
- package/dist/assets/index-DgJVElbv.css +0 -3
- package/dist/assets/openai-codex-responses-X3sTzNAa.js +0 -7
- package/dist/assets/openai-completions-CRB9Vm0w.js +0 -5
- package/dist/assets/openai-responses-DXluu3oi.js +0 -1
- package/dist/assets/transform-messages-CV4kCtBB.js +0 -1
- package/node_modules/@aws-sdk/credential-provider-sso/node_modules/@aws-sdk/token-providers/LICENSE +0 -201
- package/node_modules/@aws-sdk/credential-provider-sso/node_modules/@aws-sdk/token-providers/README.md +0 -62
- package/node_modules/@aws-sdk/credential-provider-sso/node_modules/@aws-sdk/token-providers/dist-cjs/index.js +0 -156
- package/node_modules/@aws-sdk/credential-provider-sso/node_modules/@aws-sdk/token-providers/dist-es/constants.js +0 -2
- package/node_modules/@aws-sdk/credential-provider-sso/node_modules/@aws-sdk/token-providers/dist-es/fromEnvSigningName.js +0 -16
- package/node_modules/@aws-sdk/credential-provider-sso/node_modules/@aws-sdk/token-providers/dist-es/fromSso.js +0 -80
- package/node_modules/@aws-sdk/credential-provider-sso/node_modules/@aws-sdk/token-providers/dist-es/fromStatic.js +0 -8
- package/node_modules/@aws-sdk/credential-provider-sso/node_modules/@aws-sdk/token-providers/dist-es/getNewSsoOidcToken.js +0 -11
- package/node_modules/@aws-sdk/credential-provider-sso/node_modules/@aws-sdk/token-providers/dist-es/getSsoOidcClient.js +0 -10
- package/node_modules/@aws-sdk/credential-provider-sso/node_modules/@aws-sdk/token-providers/dist-es/index.js +0 -4
- package/node_modules/@aws-sdk/credential-provider-sso/node_modules/@aws-sdk/token-providers/dist-es/nodeProvider.js +0 -5
- package/node_modules/@aws-sdk/credential-provider-sso/node_modules/@aws-sdk/token-providers/dist-es/validateTokenExpiry.js +0 -7
- package/node_modules/@aws-sdk/credential-provider-sso/node_modules/@aws-sdk/token-providers/dist-es/validateTokenKey.js +0 -7
- package/node_modules/@aws-sdk/credential-provider-sso/node_modules/@aws-sdk/token-providers/dist-es/writeSSOTokenToFile.js +0 -8
- package/node_modules/@aws-sdk/credential-provider-sso/node_modules/@aws-sdk/token-providers/package.json +0 -69
- package/node_modules/@mariozechner/pi-ai/dist/providers/google-gemini-cli.js +0 -779
- package/node_modules/@mariozechner/pi-ai/dist/utils/oauth/google-antigravity.js +0 -377
- package/node_modules/@mariozechner/pi-ai/dist/utils/oauth/google-gemini-cli.js +0 -482
|
@@ -27,29 +27,37 @@ export function calculateCost(model, usage) {
|
|
|
27
27
|
usage.cost.total = usage.cost.input + usage.cost.output + usage.cost.cacheRead + usage.cost.cacheWrite;
|
|
28
28
|
return usage.cost;
|
|
29
29
|
}
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
model.id.includes("gpt-5.3") ||
|
|
41
|
-
model.id.includes("gpt-5.4") ||
|
|
42
|
-
model.id.includes("gpt-5.5") ||
|
|
43
|
-
model.id.includes("deepseek-v4-pro")) {
|
|
30
|
+
const EXTENDED_THINKING_LEVELS = ["off", "minimal", "low", "medium", "high", "xhigh"];
|
|
31
|
+
export function getSupportedThinkingLevels(model) {
|
|
32
|
+
if (!model.reasoning)
|
|
33
|
+
return ["off"];
|
|
34
|
+
return EXTENDED_THINKING_LEVELS.filter((level) => {
|
|
35
|
+
const mapped = model.thinkingLevelMap?.[level];
|
|
36
|
+
if (mapped === null)
|
|
37
|
+
return false;
|
|
38
|
+
if (level === "xhigh")
|
|
39
|
+
return mapped !== undefined;
|
|
44
40
|
return true;
|
|
41
|
+
});
|
|
42
|
+
}
|
|
43
|
+
export function clampThinkingLevel(model, level) {
|
|
44
|
+
const availableLevels = getSupportedThinkingLevels(model);
|
|
45
|
+
if (availableLevels.includes(level))
|
|
46
|
+
return level;
|
|
47
|
+
const requestedIndex = EXTENDED_THINKING_LEVELS.indexOf(level);
|
|
48
|
+
if (requestedIndex === -1)
|
|
49
|
+
return availableLevels[0] ?? "off";
|
|
50
|
+
for (let i = requestedIndex; i < EXTENDED_THINKING_LEVELS.length; i++) {
|
|
51
|
+
const candidate = EXTENDED_THINKING_LEVELS[i];
|
|
52
|
+
if (availableLevels.includes(candidate))
|
|
53
|
+
return candidate;
|
|
45
54
|
}
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
return true;
|
|
55
|
+
for (let i = requestedIndex - 1; i >= 0; i--) {
|
|
56
|
+
const candidate = EXTENDED_THINKING_LEVELS[i];
|
|
57
|
+
if (availableLevels.includes(candidate))
|
|
58
|
+
return candidate;
|
|
51
59
|
}
|
|
52
|
-
return
|
|
60
|
+
return availableLevels[0] ?? "off";
|
|
53
61
|
}
|
|
54
62
|
/**
|
|
55
63
|
* Check if two models are equal by comparing both their id and provider.
|
|
@@ -358,8 +358,16 @@ function supportsAdaptiveThinking(modelId, modelName) {
|
|
|
358
358
|
const candidates = getModelMatchCandidates(modelId, modelName);
|
|
359
359
|
return candidates.some((s) => s.includes("opus-4-6") || s.includes("opus-4-7") || s.includes("sonnet-4-6"));
|
|
360
360
|
}
|
|
361
|
-
function
|
|
362
|
-
const candidates = getModelMatchCandidates(
|
|
361
|
+
function supportsNativeXhighEffort(model) {
|
|
362
|
+
const candidates = getModelMatchCandidates(model.id, model.name);
|
|
363
|
+
return candidates.some((s) => s.includes("opus-4-7"));
|
|
364
|
+
}
|
|
365
|
+
function mapThinkingLevelToEffort(model, level) {
|
|
366
|
+
if (level === "xhigh" && supportsNativeXhighEffort(model))
|
|
367
|
+
return "xhigh";
|
|
368
|
+
const mapped = level ? model.thinkingLevelMap?.[level] : undefined;
|
|
369
|
+
if (typeof mapped === "string")
|
|
370
|
+
return mapped;
|
|
363
371
|
switch (level) {
|
|
364
372
|
case "minimal":
|
|
365
373
|
case "low":
|
|
@@ -368,14 +376,6 @@ function mapThinkingLevelToEffort(level, modelId, modelName) {
|
|
|
368
376
|
return "medium";
|
|
369
377
|
case "high":
|
|
370
378
|
return "high";
|
|
371
|
-
case "xhigh":
|
|
372
|
-
if (candidates.some((s) => s.includes("opus-4-6"))) {
|
|
373
|
-
return "max";
|
|
374
|
-
}
|
|
375
|
-
if (candidates.some((s) => s.includes("opus-4-7"))) {
|
|
376
|
-
return "xhigh";
|
|
377
|
-
}
|
|
378
|
-
return "high";
|
|
379
379
|
default:
|
|
380
380
|
return "high";
|
|
381
381
|
}
|
|
@@ -702,7 +702,7 @@ function buildAdditionalModelRequestFields(model, options) {
|
|
|
702
702
|
const result = supportsAdaptiveThinking(model.id, model.name)
|
|
703
703
|
? {
|
|
704
704
|
thinking: { type: "adaptive", ...(display !== undefined ? { display } : {}) },
|
|
705
|
-
output_config: { effort: mapThinkingLevelToEffort(
|
|
705
|
+
output_config: { effort: mapThinkingLevelToEffort(model, options.reasoning) },
|
|
706
706
|
}
|
|
707
707
|
: (() => {
|
|
708
708
|
const defaultBudgets = {
|
|
@@ -5,6 +5,7 @@ import { AssistantMessageEventStream } from "../utils/event-stream.js";
|
|
|
5
5
|
import { headersToRecord } from "../utils/headers.js";
|
|
6
6
|
import { parseJsonWithRepair, parseStreamingJson } from "../utils/json-parse.js";
|
|
7
7
|
import { sanitizeSurrogates } from "../utils/sanitize-unicode.js";
|
|
8
|
+
import { resolveCloudflareBaseUrl } from "./cloudflare.js";
|
|
8
9
|
import { buildCopilotDynamicHeaders, hasCopilotVisionInput } from "./github-copilot-headers.js";
|
|
9
10
|
import { adjustMaxTokensForThinking, buildBaseOptions } from "./simple-options.js";
|
|
10
11
|
import { transformMessages } from "./transform-messages.js";
|
|
@@ -244,6 +245,8 @@ async function* iterateAnthropicEvents(response, signal) {
|
|
|
244
245
|
if (!response.body) {
|
|
245
246
|
throw new Error("Attempted to iterate over an Anthropic response with no body");
|
|
246
247
|
}
|
|
248
|
+
let sawMessageStart = false;
|
|
249
|
+
let sawMessageEnd = false;
|
|
247
250
|
for await (const sse of iterateSseMessages(response.body, signal)) {
|
|
248
251
|
if (sse.event === "error") {
|
|
249
252
|
throw new Error(sse.data);
|
|
@@ -252,13 +255,23 @@ async function* iterateAnthropicEvents(response, signal) {
|
|
|
252
255
|
continue;
|
|
253
256
|
}
|
|
254
257
|
try {
|
|
255
|
-
|
|
258
|
+
const event = parseJsonWithRepair(sse.data);
|
|
259
|
+
if (event.type === "message_start") {
|
|
260
|
+
sawMessageStart = true;
|
|
261
|
+
}
|
|
262
|
+
else if (event.type === "message_stop") {
|
|
263
|
+
sawMessageEnd = true;
|
|
264
|
+
}
|
|
265
|
+
yield event;
|
|
256
266
|
}
|
|
257
267
|
catch (error) {
|
|
258
268
|
const message = error instanceof Error ? error.message : String(error);
|
|
259
269
|
throw new Error(`Could not parse Anthropic SSE event ${sse.event}: ${message}; data=${sse.data}; raw=${sse.raw.join("\\n")}`);
|
|
260
270
|
}
|
|
261
271
|
}
|
|
272
|
+
if (sawMessageStart && !sawMessageEnd) {
|
|
273
|
+
throw new Error("Anthropic stream ended before message_stop");
|
|
274
|
+
}
|
|
262
275
|
}
|
|
263
276
|
export const streamAnthropic = (model, context, options) => {
|
|
264
277
|
const stream = new AssistantMessageEventStream();
|
|
@@ -523,24 +536,18 @@ function supportsAdaptiveThinking(modelId) {
|
|
|
523
536
|
* Map ThinkingLevel to Anthropic effort levels for adaptive thinking.
|
|
524
537
|
* Note: effort "max" is only valid on Opus 4.6, while Opus 4.7 supports "xhigh".
|
|
525
538
|
*/
|
|
526
|
-
function mapThinkingLevelToEffort(
|
|
539
|
+
function mapThinkingLevelToEffort(model, level) {
|
|
540
|
+
const mapped = level ? model.thinkingLevelMap?.[level] : undefined;
|
|
541
|
+
if (typeof mapped === "string")
|
|
542
|
+
return mapped;
|
|
527
543
|
switch (level) {
|
|
528
544
|
case "minimal":
|
|
529
|
-
return "low";
|
|
530
545
|
case "low":
|
|
531
546
|
return "low";
|
|
532
547
|
case "medium":
|
|
533
548
|
return "medium";
|
|
534
549
|
case "high":
|
|
535
550
|
return "high";
|
|
536
|
-
case "xhigh":
|
|
537
|
-
if (modelId.includes("opus-4-6") || modelId.includes("opus-4.6")) {
|
|
538
|
-
return "max";
|
|
539
|
-
}
|
|
540
|
-
if (modelId.includes("opus-4-7") || modelId.includes("opus-4.7")) {
|
|
541
|
-
return "xhigh";
|
|
542
|
-
}
|
|
543
|
-
return "high";
|
|
544
551
|
default:
|
|
545
552
|
return "high";
|
|
546
553
|
}
|
|
@@ -557,7 +564,7 @@ export const streamSimpleAnthropic = (model, context, options) => {
|
|
|
557
564
|
// For Opus 4.6 and Sonnet 4.6: use adaptive thinking with effort level
|
|
558
565
|
// For older models: use budget-based thinking
|
|
559
566
|
if (supportsAdaptiveThinking(model.id)) {
|
|
560
|
-
const effort = mapThinkingLevelToEffort(options.reasoning
|
|
567
|
+
const effort = mapThinkingLevelToEffort(model, options.reasoning);
|
|
561
568
|
return streamAnthropic(model, context, {
|
|
562
569
|
...base,
|
|
563
570
|
thinkingEnabled: true,
|
|
@@ -579,15 +586,32 @@ function createClient(model, apiKey, interleavedThinking, useFineGrainedToolStre
|
|
|
579
586
|
// Adaptive thinking models (Opus 4.6, Sonnet 4.6) have interleaved thinking built-in.
|
|
580
587
|
// The beta header is deprecated on Opus 4.6 and redundant on Sonnet 4.6, so skip it.
|
|
581
588
|
const needsInterleavedBeta = interleavedThinking && !supportsAdaptiveThinking(model.id);
|
|
589
|
+
const betaFeatures = [];
|
|
590
|
+
if (useFineGrainedToolStreamingBeta) {
|
|
591
|
+
betaFeatures.push(FINE_GRAINED_TOOL_STREAMING_BETA);
|
|
592
|
+
}
|
|
593
|
+
if (needsInterleavedBeta) {
|
|
594
|
+
betaFeatures.push(INTERLEAVED_THINKING_BETA);
|
|
595
|
+
}
|
|
596
|
+
if (model.provider === "cloudflare-ai-gateway") {
|
|
597
|
+
const client = new Anthropic({
|
|
598
|
+
apiKey: null,
|
|
599
|
+
authToken: null,
|
|
600
|
+
baseURL: resolveCloudflareBaseUrl(model),
|
|
601
|
+
dangerouslyAllowBrowser: true,
|
|
602
|
+
defaultHeaders: mergeHeaders({
|
|
603
|
+
accept: "application/json",
|
|
604
|
+
"anthropic-dangerous-direct-browser-access": "true",
|
|
605
|
+
"cf-aig-authorization": `Bearer ${apiKey}`,
|
|
606
|
+
"x-api-key": null,
|
|
607
|
+
Authorization: null,
|
|
608
|
+
...(betaFeatures.length > 0 ? { "anthropic-beta": betaFeatures.join(",") } : {}),
|
|
609
|
+
}, model.headers, optionsHeaders),
|
|
610
|
+
});
|
|
611
|
+
return { client, isOAuthToken: false };
|
|
612
|
+
}
|
|
582
613
|
// Copilot: Bearer auth, selective betas.
|
|
583
614
|
if (model.provider === "github-copilot") {
|
|
584
|
-
const betaFeatures = [];
|
|
585
|
-
if (useFineGrainedToolStreamingBeta) {
|
|
586
|
-
betaFeatures.push(FINE_GRAINED_TOOL_STREAMING_BETA);
|
|
587
|
-
}
|
|
588
|
-
if (needsInterleavedBeta) {
|
|
589
|
-
betaFeatures.push(INTERLEAVED_THINKING_BETA);
|
|
590
|
-
}
|
|
591
615
|
const client = new Anthropic({
|
|
592
616
|
apiKey: null,
|
|
593
617
|
authToken: apiKey,
|
|
@@ -601,13 +625,6 @@ function createClient(model, apiKey, interleavedThinking, useFineGrainedToolStre
|
|
|
601
625
|
});
|
|
602
626
|
return { client, isOAuthToken: false };
|
|
603
627
|
}
|
|
604
|
-
const betaFeatures = [];
|
|
605
|
-
if (useFineGrainedToolStreamingBeta) {
|
|
606
|
-
betaFeatures.push(FINE_GRAINED_TOOL_STREAMING_BETA);
|
|
607
|
-
}
|
|
608
|
-
if (needsInterleavedBeta) {
|
|
609
|
-
betaFeatures.push(INTERLEAVED_THINKING_BETA);
|
|
610
|
-
}
|
|
611
628
|
// OAuth: Bearer auth, Claude Code identity headers
|
|
612
629
|
if (isOAuthToken(apiKey)) {
|
|
613
630
|
const client = new Anthropic({
|
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
import { AzureOpenAI } from "openai";
|
|
2
2
|
import { getEnvApiKey } from "../env-api-keys.js";
|
|
3
|
-
import {
|
|
3
|
+
import { clampThinkingLevel } from "../models.js";
|
|
4
4
|
import { AssistantMessageEventStream } from "../utils/event-stream.js";
|
|
5
5
|
import { headersToRecord } from "../utils/headers.js";
|
|
6
6
|
import { convertResponsesMessages, convertResponsesTools, processResponsesStream } from "./openai-responses-shared.js";
|
|
7
|
-
import { buildBaseOptions
|
|
7
|
+
import { buildBaseOptions } from "./simple-options.js";
|
|
8
8
|
const DEFAULT_AZURE_API_VERSION = "v1";
|
|
9
9
|
const AZURE_TOOL_CALL_PROVIDERS = new Set(["openai", "openai-codex", "opencode", "azure-openai-responses"]);
|
|
10
10
|
function parseDeploymentNameMap(value) {
|
|
@@ -101,7 +101,8 @@ export const streamSimpleAzureOpenAIResponses = (model, context, options) => {
|
|
|
101
101
|
throw new Error(`No API key for provider: ${model.provider}`);
|
|
102
102
|
}
|
|
103
103
|
const base = buildBaseOptions(model, options, apiKey);
|
|
104
|
-
const
|
|
104
|
+
const clampedReasoning = options?.reasoning ? clampThinkingLevel(model, options.reasoning) : undefined;
|
|
105
|
+
const reasoningEffort = clampedReasoning === "off" ? undefined : clampedReasoning;
|
|
105
106
|
return streamAzureOpenAIResponses(model, context, {
|
|
106
107
|
...base,
|
|
107
108
|
reasoningEffort,
|
|
@@ -187,14 +188,19 @@ function buildParams(model, context, options, deploymentName) {
|
|
|
187
188
|
}
|
|
188
189
|
if (model.reasoning) {
|
|
189
190
|
if (options?.reasoningEffort || options?.reasoningSummary) {
|
|
191
|
+
const effort = options?.reasoningEffort
|
|
192
|
+
? (model.thinkingLevelMap?.[options.reasoningEffort] ?? options.reasoningEffort)
|
|
193
|
+
: "medium";
|
|
190
194
|
params.reasoning = {
|
|
191
|
-
effort:
|
|
195
|
+
effort: effort,
|
|
192
196
|
summary: options?.reasoningSummary || "auto",
|
|
193
197
|
};
|
|
194
198
|
params.include = ["reasoning.encrypted_content"];
|
|
195
199
|
}
|
|
196
|
-
else {
|
|
197
|
-
params.reasoning = {
|
|
200
|
+
else if (model.thinkingLevelMap?.off !== null) {
|
|
201
|
+
params.reasoning = {
|
|
202
|
+
effort: (model.thinkingLevelMap?.off ?? "none"),
|
|
203
|
+
};
|
|
198
204
|
}
|
|
199
205
|
}
|
|
200
206
|
return params;
|
|
@@ -1,19 +1,26 @@
|
|
|
1
|
-
/** Workers AI endpoint.
|
|
1
|
+
/** Workers AI direct endpoint. */
|
|
2
2
|
export const CLOUDFLARE_WORKERS_AI_BASE_URL = "https://api.cloudflare.com/client/v4/accounts/{CLOUDFLARE_ACCOUNT_ID}/ai/v1";
|
|
3
|
+
/** AI Gateway Unified API. https://developers.cloudflare.com/ai-gateway/usage/unified-api/ */
|
|
4
|
+
export const CLOUDFLARE_AI_GATEWAY_COMPAT_BASE_URL = "https://gateway.ai.cloudflare.com/v1/{CLOUDFLARE_ACCOUNT_ID}/{CLOUDFLARE_GATEWAY_ID}/compat";
|
|
5
|
+
/** AI Gateway → OpenAI passthrough. Used until /compat supports /v1/responses. */
|
|
6
|
+
export const CLOUDFLARE_AI_GATEWAY_OPENAI_BASE_URL = "https://gateway.ai.cloudflare.com/v1/{CLOUDFLARE_ACCOUNT_ID}/{CLOUDFLARE_GATEWAY_ID}/openai";
|
|
7
|
+
/** AI Gateway → Anthropic passthrough. */
|
|
8
|
+
export const CLOUDFLARE_AI_GATEWAY_ANTHROPIC_BASE_URL = "https://gateway.ai.cloudflare.com/v1/{CLOUDFLARE_ACCOUNT_ID}/{CLOUDFLARE_GATEWAY_ID}/anthropic";
|
|
3
9
|
export function isCloudflareProvider(provider) {
|
|
4
|
-
return provider === "cloudflare-workers-ai";
|
|
10
|
+
return provider === "cloudflare-workers-ai" || provider === "cloudflare-ai-gateway";
|
|
5
11
|
}
|
|
6
12
|
/** Substitute `{VAR}` placeholders in a Cloudflare baseUrl from process.env. */
|
|
7
13
|
export function resolveCloudflareBaseUrl(model) {
|
|
8
14
|
const url = model.baseUrl;
|
|
9
15
|
if (!url.includes("{"))
|
|
10
16
|
return url;
|
|
11
|
-
|
|
17
|
+
const baseUrl = url.replace(/\{([A-Z_][A-Z0-9_]*)\}/g, (_match, name) => {
|
|
12
18
|
const value = process.env[name];
|
|
13
19
|
if (!value) {
|
|
14
20
|
throw new Error(`${name} is required for provider ${model.provider} but is not set.`);
|
|
15
21
|
}
|
|
16
22
|
return value;
|
|
17
23
|
});
|
|
24
|
+
return baseUrl;
|
|
18
25
|
}
|
|
19
26
|
//# sourceMappingURL=cloudflare.js.map
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* Shared utilities for Google Generative AI and Google
|
|
2
|
+
* Shared utilities for Google Generative AI and Google Vertex providers.
|
|
3
3
|
*/
|
|
4
4
|
import { FinishReason, FunctionCallingConfigMode } from "@google/genai";
|
|
5
5
|
import { sanitizeSurrogates } from "../utils/sanitize-unicode.js";
|
|
@@ -38,10 +38,6 @@ export function retainThoughtSignature(existing, incoming) {
|
|
|
38
38
|
}
|
|
39
39
|
// Thought signatures must be base64 for Google APIs (TYPE_BYTES).
|
|
40
40
|
const base64SignaturePattern = /^[A-Za-z0-9+/]+={0,2}$/;
|
|
41
|
-
// Sentinel value that tells the Gemini API to skip thought signature validation.
|
|
42
|
-
// Used for unsigned function call parts (e.g. replayed from providers without thought signatures).
|
|
43
|
-
// See: https://ai.google.dev/gemini-api/docs/thought-signatures
|
|
44
|
-
const SKIP_THOUGHT_SIGNATURE = "skip_thought_signature_validator";
|
|
45
41
|
function isValidThoughtSignature(signature) {
|
|
46
42
|
if (!signature)
|
|
47
43
|
return false;
|
|
@@ -121,7 +117,7 @@ export function convertMessages(model, context) {
|
|
|
121
117
|
const isSameProviderAndModel = msg.provider === model.provider && msg.model === model.id;
|
|
122
118
|
for (const block of msg.content) {
|
|
123
119
|
if (block.type === "text") {
|
|
124
|
-
// Skip empty text blocks
|
|
120
|
+
// Skip empty text blocks
|
|
125
121
|
if (!block.text || block.text.trim() === "")
|
|
126
122
|
continue;
|
|
127
123
|
const thoughtSignature = resolveThoughtSignature(isSameProviderAndModel, block.textSignature);
|
|
@@ -152,18 +148,13 @@ export function convertMessages(model, context) {
|
|
|
152
148
|
}
|
|
153
149
|
else if (block.type === "toolCall") {
|
|
154
150
|
const thoughtSignature = resolveThoughtSignature(isSameProviderAndModel, block.thoughtSignature);
|
|
155
|
-
// Gemini 3 requires thoughtSignature on all function calls when thinking mode is enabled.
|
|
156
|
-
// Use the skip_thought_signature_validator sentinel for unsigned function calls
|
|
157
|
-
// (e.g. replayed from providers without thought signatures like Claude via Antigravity).
|
|
158
|
-
const isGemini3 = model.id.toLowerCase().includes("gemini-3");
|
|
159
|
-
const effectiveSignature = thoughtSignature || (isGemini3 ? SKIP_THOUGHT_SIGNATURE : undefined);
|
|
160
151
|
const part = {
|
|
161
152
|
functionCall: {
|
|
162
153
|
name: block.name,
|
|
163
154
|
args: block.arguments ?? {},
|
|
164
155
|
...(requiresToolCallId(model.id) ? { id: block.id } : {}),
|
|
165
156
|
},
|
|
166
|
-
...(
|
|
157
|
+
...(thoughtSignature && { thoughtSignature }),
|
|
167
158
|
};
|
|
168
159
|
parts.push(part);
|
|
169
160
|
}
|
|
@@ -186,7 +177,7 @@ export function convertMessages(model, context) {
|
|
|
186
177
|
const hasImages = imageContent.length > 0;
|
|
187
178
|
// Gemini 3+ models support multimodal function responses with images nested inside
|
|
188
179
|
// functionResponse.parts. Claude and other non-Gemini models behind Cloud Code Assist /
|
|
189
|
-
//
|
|
180
|
+
// Gemini < 3 still needs a separate user image turn.
|
|
190
181
|
const modelSupportsMultimodalFunctionResponse = supportsMultimodalFunctionResponse(model.id);
|
|
191
182
|
// Use "output" key for success, "error" key for errors as per SDK documentation
|
|
192
183
|
const responseValue = hasText ? sanitizeSurrogates(textResult) : hasImages ? "(see attached image)" : "";
|
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
import { GoogleGenAI, ResourceScope, ThinkingLevel, } from "@google/genai";
|
|
2
|
-
import { calculateCost } from "../models.js";
|
|
2
|
+
import { calculateCost, clampThinkingLevel } from "../models.js";
|
|
3
3
|
import { AssistantMessageEventStream } from "../utils/event-stream.js";
|
|
4
4
|
import { sanitizeSurrogates } from "../utils/sanitize-unicode.js";
|
|
5
5
|
import { convertMessages, convertTools, isThinkingPart, mapStopReason, mapToolChoice, retainThoughtSignature, } from "./google-shared.js";
|
|
6
|
-
import { buildBaseOptions
|
|
6
|
+
import { buildBaseOptions } from "./simple-options.js";
|
|
7
7
|
const API_VERSION = "v1";
|
|
8
8
|
const GCP_VERTEX_CREDENTIALS_MARKER = "gcp-vertex-credentials";
|
|
9
9
|
const THINKING_LEVEL_MAP = {
|
|
@@ -231,7 +231,8 @@ export const streamSimpleGoogleVertex = (model, context, options) => {
|
|
|
231
231
|
thinking: { enabled: false },
|
|
232
232
|
});
|
|
233
233
|
}
|
|
234
|
-
const
|
|
234
|
+
const clampedReasoning = clampThinkingLevel(model, options.reasoning);
|
|
235
|
+
const effort = (clampedReasoning === "off" ? "high" : clampedReasoning);
|
|
235
236
|
const geminiModel = model;
|
|
236
237
|
if (isGemini3ProModel(geminiModel) || isGemini3FlashModel(geminiModel)) {
|
|
237
238
|
return streamGoogleVertex(model, context, {
|
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
import { GoogleGenAI, } from "@google/genai";
|
|
2
2
|
import { getEnvApiKey } from "../env-api-keys.js";
|
|
3
|
-
import { calculateCost } from "../models.js";
|
|
3
|
+
import { calculateCost, clampThinkingLevel } from "../models.js";
|
|
4
4
|
import { AssistantMessageEventStream } from "../utils/event-stream.js";
|
|
5
5
|
import { sanitizeSurrogates } from "../utils/sanitize-unicode.js";
|
|
6
6
|
import { convertMessages, convertTools, isThinkingPart, mapStopReason, mapToolChoice, retainThoughtSignature, } from "./google-shared.js";
|
|
7
|
-
import { buildBaseOptions
|
|
7
|
+
import { buildBaseOptions } from "./simple-options.js";
|
|
8
8
|
// Counter for generating unique tool call IDs
|
|
9
9
|
let toolCallCounter = 0;
|
|
10
10
|
export const streamGoogle = (model, context, options) => {
|
|
@@ -222,7 +222,8 @@ export const streamSimpleGoogle = (model, context, options) => {
|
|
|
222
222
|
if (!options?.reasoning) {
|
|
223
223
|
return streamGoogle(model, context, { ...base, thinking: { enabled: false } });
|
|
224
224
|
}
|
|
225
|
-
const
|
|
225
|
+
const clampedReasoning = clampThinkingLevel(model, options.reasoning);
|
|
226
|
+
const effort = (clampedReasoning === "off" ? "high" : clampedReasoning);
|
|
226
227
|
const googleModel = model;
|
|
227
228
|
if (isGemini3ProModel(googleModel) || isGemini3FlashModel(googleModel) || isGemma4Model(googleModel)) {
|
|
228
229
|
return streamGoogle(model, context, {
|
|
@@ -1,11 +1,11 @@
|
|
|
1
1
|
import { Mistral } from "@mistralai/mistralai";
|
|
2
2
|
import { getEnvApiKey } from "../env-api-keys.js";
|
|
3
|
-
import { calculateCost } from "../models.js";
|
|
3
|
+
import { calculateCost, clampThinkingLevel } from "../models.js";
|
|
4
4
|
import { AssistantMessageEventStream } from "../utils/event-stream.js";
|
|
5
5
|
import { shortHash } from "../utils/hash.js";
|
|
6
6
|
import { parseStreamingJson } from "../utils/json-parse.js";
|
|
7
7
|
import { sanitizeSurrogates } from "../utils/sanitize-unicode.js";
|
|
8
|
-
import { buildBaseOptions
|
|
8
|
+
import { buildBaseOptions } from "./simple-options.js";
|
|
9
9
|
import { transformMessages } from "./transform-messages.js";
|
|
10
10
|
const MISTRAL_TOOL_CALL_ID_LENGTH = 9;
|
|
11
11
|
const MAX_MISTRAL_ERROR_BODY_CHARS = 4000;
|
|
@@ -67,12 +67,13 @@ export const streamSimpleMistral = (model, context, options) => {
|
|
|
67
67
|
throw new Error(`No API key for provider: ${model.provider}`);
|
|
68
68
|
}
|
|
69
69
|
const base = buildBaseOptions(model, options, apiKey);
|
|
70
|
-
const
|
|
70
|
+
const clampedReasoning = options?.reasoning ? clampThinkingLevel(model, options.reasoning) : undefined;
|
|
71
|
+
const reasoning = clampedReasoning === "off" ? undefined : clampedReasoning;
|
|
71
72
|
const shouldUseReasoning = model.reasoning && reasoning !== undefined;
|
|
72
73
|
return streamMistral(model, context, {
|
|
73
74
|
...base,
|
|
74
75
|
promptMode: shouldUseReasoning && usesPromptModeReasoning(model) ? "reasoning" : undefined,
|
|
75
|
-
reasoningEffort: shouldUseReasoning && usesReasoningEffort(model) ? mapReasoningEffort(reasoning) : undefined,
|
|
76
|
+
reasoningEffort: shouldUseReasoning && usesReasoningEffort(model) ? mapReasoningEffort(model, reasoning) : undefined,
|
|
76
77
|
});
|
|
77
78
|
};
|
|
78
79
|
function createOutput(model) {
|
|
@@ -495,13 +496,13 @@ function buildToolResultText(text, hasImages, supportsImages, isError) {
|
|
|
495
496
|
return isError ? "[tool error] (no tool output)" : "(no tool output)";
|
|
496
497
|
}
|
|
497
498
|
function usesReasoningEffort(model) {
|
|
498
|
-
return model.id === "mistral-small-2603" || model.id === "mistral-small-latest";
|
|
499
|
+
return model.id === "mistral-small-2603" || model.id === "mistral-small-latest" || model.id === "mistral-medium-3.5";
|
|
499
500
|
}
|
|
500
501
|
function usesPromptModeReasoning(model) {
|
|
501
502
|
return model.reasoning && !usesReasoningEffort(model);
|
|
502
503
|
}
|
|
503
|
-
function mapReasoningEffort(
|
|
504
|
-
return "high";
|
|
504
|
+
function mapReasoningEffort(model, level) {
|
|
505
|
+
return (model.thinkingLevelMap?.[level] ?? "high");
|
|
505
506
|
}
|
|
506
507
|
function mapToolChoice(choice) {
|
|
507
508
|
if (!choice)
|