@cognipeer/agent-sdk 0.10.6 → 0.12.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +28 -3
- package/dist/index.cjs +1069 -235
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +289 -18
- package/dist/index.d.ts +289 -18
- package/dist/index.mjs +1068 -236
- package/dist/index.mjs.map +1 -1
- package/package.json +39 -1
package/dist/index.mjs
CHANGED
|
@@ -2431,6 +2431,15 @@ function estimatePayloadBytes(value) {
|
|
|
2431
2431
|
}
|
|
2432
2432
|
}
|
|
2433
2433
|
}
|
|
2434
|
+
function toMessageUsage(u) {
|
|
2435
|
+
return {
|
|
2436
|
+
prompt_tokens: u.inputTokens,
|
|
2437
|
+
completion_tokens: u.outputTokens,
|
|
2438
|
+
total_tokens: u.totalTokens,
|
|
2439
|
+
prompt_tokens_details: { cached_tokens: u.cachedInputTokens, cache_write_tokens: u.cachedWriteTokens },
|
|
2440
|
+
completion_tokens_details: { reasoning_tokens: u.reasoningTokens }
|
|
2441
|
+
};
|
|
2442
|
+
}
|
|
2434
2443
|
function fromNativeProvider(provider, options) {
|
|
2435
2444
|
let boundTools = options?.__tools;
|
|
2436
2445
|
const modelName = options?.model ?? provider.defaultModel ?? provider.providerName;
|
|
@@ -2440,8 +2449,9 @@ function fromNativeProvider(provider, options) {
|
|
|
2440
2449
|
invoke: async (messages, _invokeOptions) => {
|
|
2441
2450
|
const link = linkAbortSignal(_invokeOptions);
|
|
2442
2451
|
try {
|
|
2443
|
-
|
|
2452
|
+
let request = buildRequest(messages, boundTools, options, _invokeOptions);
|
|
2444
2453
|
if (link.signal) request.signal = link.signal;
|
|
2454
|
+
request = await applyTransform(request);
|
|
2445
2455
|
const response = await provider.complete(request);
|
|
2446
2456
|
return toBaseChatMessage(response);
|
|
2447
2457
|
} finally {
|
|
@@ -2451,33 +2461,46 @@ function fromNativeProvider(provider, options) {
|
|
|
2451
2461
|
stream: async function* (messages, _invokeOptions) {
|
|
2452
2462
|
const link = linkAbortSignal(_invokeOptions);
|
|
2453
2463
|
try {
|
|
2454
|
-
|
|
2464
|
+
let request = buildRequest(messages, boundTools, options, _invokeOptions);
|
|
2455
2465
|
request.stream = true;
|
|
2456
2466
|
if (link.signal) request.signal = link.signal;
|
|
2467
|
+
request = await applyTransform(request);
|
|
2457
2468
|
let fullContent = "";
|
|
2458
2469
|
let allToolCalls = [];
|
|
2459
2470
|
let lastUsage;
|
|
2460
2471
|
let reasoningBlocks;
|
|
2472
|
+
let reasoningText = "";
|
|
2473
|
+
let finishReason;
|
|
2474
|
+
let responseModel;
|
|
2461
2475
|
const toolCallBuffers = /* @__PURE__ */ new Map();
|
|
2462
2476
|
for await (const chunk of provider.completeStream(request)) {
|
|
2463
2477
|
if (chunk.delta.content) {
|
|
2464
2478
|
fullContent += chunk.delta.content;
|
|
2465
2479
|
yield chunk.delta.content;
|
|
2466
2480
|
}
|
|
2481
|
+
if (chunk.model) responseModel = chunk.model;
|
|
2482
|
+
if (chunk.finishReason) finishReason = chunk.finishReason;
|
|
2467
2483
|
if (chunk.delta.reasoning?.blocks?.length) {
|
|
2468
2484
|
reasoningBlocks = chunk.delta.reasoning.blocks;
|
|
2469
2485
|
}
|
|
2486
|
+
const reasoningDelta = chunk.delta.reasoning?.summary;
|
|
2487
|
+
if (reasoningDelta) {
|
|
2488
|
+
reasoningText += reasoningDelta;
|
|
2489
|
+
yield { type: "reasoning", reasoning_content: reasoningDelta };
|
|
2490
|
+
}
|
|
2470
2491
|
if (chunk.delta.toolCalls) {
|
|
2471
2492
|
for (const tc of chunk.delta.toolCalls) {
|
|
2472
2493
|
if (tc.id) {
|
|
2473
2494
|
const existing = toolCallBuffers.get(tc.id);
|
|
2474
2495
|
if (existing) {
|
|
2475
2496
|
if (tc.arguments) existing.arguments += tc.arguments;
|
|
2497
|
+
if (tc.thoughtSignature) existing.thoughtSignature = tc.thoughtSignature;
|
|
2476
2498
|
} else {
|
|
2477
2499
|
toolCallBuffers.set(tc.id, {
|
|
2478
2500
|
id: tc.id,
|
|
2479
2501
|
name: tc.name ?? "",
|
|
2480
|
-
arguments: tc.arguments ?? ""
|
|
2502
|
+
arguments: tc.arguments ?? "",
|
|
2503
|
+
...tc.thoughtSignature ? { thoughtSignature: tc.thoughtSignature } : {}
|
|
2481
2504
|
});
|
|
2482
2505
|
}
|
|
2483
2506
|
}
|
|
@@ -2488,8 +2511,18 @@ function fromNativeProvider(provider, options) {
|
|
|
2488
2511
|
if (link.signal?.aborted) return;
|
|
2489
2512
|
allToolCalls = [...toolCallBuffers.values()];
|
|
2490
2513
|
const finalMessage = assembleMessage(fullContent, allToolCalls, lastUsage);
|
|
2491
|
-
if (reasoningBlocks?.length) {
|
|
2492
|
-
finalMessage.reasoning = {
|
|
2514
|
+
if (reasoningBlocks?.length || reasoningText) {
|
|
2515
|
+
finalMessage.reasoning = {
|
|
2516
|
+
...reasoningBlocks?.length ? { blocks: reasoningBlocks } : {},
|
|
2517
|
+
...reasoningText ? { summary: reasoningText } : {}
|
|
2518
|
+
};
|
|
2519
|
+
}
|
|
2520
|
+
if (finishReason || responseModel) {
|
|
2521
|
+
finalMessage.response_metadata = {
|
|
2522
|
+
...finalMessage.response_metadata ?? {},
|
|
2523
|
+
...finishReason ? { finish_reason: finishReason } : {},
|
|
2524
|
+
...responseModel ? { model_name: responseModel } : {}
|
|
2525
|
+
};
|
|
2493
2526
|
}
|
|
2494
2527
|
yield finalMessage;
|
|
2495
2528
|
} finally {
|
|
@@ -2503,6 +2536,11 @@ function fromNativeProvider(provider, options) {
|
|
|
2503
2536
|
}
|
|
2504
2537
|
};
|
|
2505
2538
|
return adapted;
|
|
2539
|
+
async function applyTransform(req) {
|
|
2540
|
+
if (!options?.transformRequest) return req;
|
|
2541
|
+
const out = await options.transformRequest(req);
|
|
2542
|
+
return out ?? req;
|
|
2543
|
+
}
|
|
2506
2544
|
function buildRequest(messages, tools, opts, invokeOptions) {
|
|
2507
2545
|
const req = {
|
|
2508
2546
|
model: opts?.model ?? modelName,
|
|
@@ -2510,6 +2548,10 @@ function fromNativeProvider(provider, options) {
|
|
|
2510
2548
|
};
|
|
2511
2549
|
if (opts?.temperature != null) req.temperature = opts.temperature;
|
|
2512
2550
|
if (opts?.maxTokens != null) req.maxTokens = opts.maxTokens;
|
|
2551
|
+
if (opts?.topP != null) req.topP = opts.topP;
|
|
2552
|
+
if (opts?.stop?.length) req.stop = opts.stop;
|
|
2553
|
+
if (opts?.presencePenalty != null) req.presencePenalty = opts.presencePenalty;
|
|
2554
|
+
if (opts?.frequencyPenalty != null) req.frequencyPenalty = opts.frequencyPenalty;
|
|
2513
2555
|
if (tools?.length) req.tools = tools;
|
|
2514
2556
|
if (opts?.extra) req.extra = opts.extra;
|
|
2515
2557
|
const reasoningOverride = invokeOptions?.reasoning;
|
|
@@ -2562,7 +2604,8 @@ function toUnifiedMessage(msg) {
|
|
|
2562
2604
|
unified.toolCalls = msg.tool_calls.map((tc) => ({
|
|
2563
2605
|
id: tc.id,
|
|
2564
2606
|
name: tc.function?.name ?? tc.name ?? "",
|
|
2565
|
-
arguments: tc.function?.arguments ?? tc.arguments ?? "{}"
|
|
2607
|
+
arguments: tc.function?.arguments ?? tc.arguments ?? "{}",
|
|
2608
|
+
...tc.thoughtSignature ? { thoughtSignature: tc.thoughtSignature } : {}
|
|
2566
2609
|
}));
|
|
2567
2610
|
}
|
|
2568
2611
|
const reasoning = msg.reasoning;
|
|
@@ -2836,29 +2879,16 @@ function toToolDefinition(tool, strict) {
|
|
|
2836
2879
|
}
|
|
2837
2880
|
return { name, description, parameters, ...useStrict ? { strict: true } : {} };
|
|
2838
2881
|
}
|
|
2882
|
+
function legacyTokenUsage(u) {
|
|
2883
|
+
return { ...toMessageUsage(u), cached_tokens: u.cachedInputTokens, cache_write_tokens: u.cachedWriteTokens };
|
|
2884
|
+
}
|
|
2839
2885
|
function toBaseChatMessage(response) {
|
|
2840
2886
|
const msg = {
|
|
2841
2887
|
role: "assistant",
|
|
2842
2888
|
content: response.content ?? "",
|
|
2843
|
-
usage:
|
|
2844
|
-
prompt_tokens: response.usage.inputTokens,
|
|
2845
|
-
completion_tokens: response.usage.outputTokens,
|
|
2846
|
-
total_tokens: response.usage.totalTokens,
|
|
2847
|
-
prompt_tokens_details: {
|
|
2848
|
-
cached_tokens: response.usage.cachedInputTokens
|
|
2849
|
-
},
|
|
2850
|
-
completion_tokens_details: {
|
|
2851
|
-
reasoning_tokens: response.usage.reasoningTokens
|
|
2852
|
-
}
|
|
2853
|
-
},
|
|
2889
|
+
usage: toMessageUsage(response.usage),
|
|
2854
2890
|
response_metadata: {
|
|
2855
|
-
token_usage:
|
|
2856
|
-
prompt_tokens: response.usage.inputTokens,
|
|
2857
|
-
completion_tokens: response.usage.outputTokens,
|
|
2858
|
-
total_tokens: response.usage.totalTokens,
|
|
2859
|
-
cached_tokens: response.usage.cachedInputTokens,
|
|
2860
|
-
cache_write_tokens: response.usage.cachedWriteTokens
|
|
2861
|
-
},
|
|
2891
|
+
token_usage: legacyTokenUsage(response.usage),
|
|
2862
2892
|
finish_reason: response.finishReason,
|
|
2863
2893
|
model_name: response.model
|
|
2864
2894
|
}
|
|
@@ -2867,7 +2897,8 @@ function toBaseChatMessage(response) {
|
|
|
2867
2897
|
msg.tool_calls = response.toolCalls.map((tc) => ({
|
|
2868
2898
|
id: tc.id,
|
|
2869
2899
|
type: "function",
|
|
2870
|
-
function: { name: tc.name, arguments: tc.arguments }
|
|
2900
|
+
function: { name: tc.name, arguments: tc.arguments },
|
|
2901
|
+
...tc.thoughtSignature ? { thoughtSignature: tc.thoughtSignature } : {}
|
|
2871
2902
|
}));
|
|
2872
2903
|
}
|
|
2873
2904
|
if (response.reasoning && (response.reasoning.blocks?.length || response.reasoning.summary)) {
|
|
@@ -2881,32 +2912,15 @@ function assembleMessage(content, toolCalls, usage) {
|
|
|
2881
2912
|
content
|
|
2882
2913
|
};
|
|
2883
2914
|
if (usage) {
|
|
2884
|
-
msg.usage =
|
|
2885
|
-
|
|
2886
|
-
completion_tokens: usage.outputTokens,
|
|
2887
|
-
total_tokens: usage.totalTokens,
|
|
2888
|
-
prompt_tokens_details: {
|
|
2889
|
-
cached_tokens: usage.cachedInputTokens
|
|
2890
|
-
},
|
|
2891
|
-
completion_tokens_details: {
|
|
2892
|
-
reasoning_tokens: usage.reasoningTokens
|
|
2893
|
-
}
|
|
2894
|
-
};
|
|
2895
|
-
msg.response_metadata = {
|
|
2896
|
-
token_usage: {
|
|
2897
|
-
prompt_tokens: usage.inputTokens,
|
|
2898
|
-
completion_tokens: usage.outputTokens,
|
|
2899
|
-
total_tokens: usage.totalTokens,
|
|
2900
|
-
cached_tokens: usage.cachedInputTokens,
|
|
2901
|
-
cache_write_tokens: usage.cachedWriteTokens
|
|
2902
|
-
}
|
|
2903
|
-
};
|
|
2915
|
+
msg.usage = toMessageUsage(usage);
|
|
2916
|
+
msg.response_metadata = { token_usage: legacyTokenUsage(usage) };
|
|
2904
2917
|
}
|
|
2905
2918
|
if (toolCalls.length > 0) {
|
|
2906
2919
|
msg.tool_calls = toolCalls.map((tc) => ({
|
|
2907
2920
|
id: tc.id,
|
|
2908
2921
|
type: "function",
|
|
2909
|
-
function: { name: tc.name, arguments: tc.arguments }
|
|
2922
|
+
function: { name: tc.name, arguments: tc.arguments },
|
|
2923
|
+
...tc.thoughtSignature ? { thoughtSignature: tc.thoughtSignature } : {}
|
|
2910
2924
|
}));
|
|
2911
2925
|
}
|
|
2912
2926
|
return msg;
|
|
@@ -2939,8 +2953,8 @@ function resolveCapabilities(provider) {
|
|
|
2939
2953
|
return {
|
|
2940
2954
|
structuredOutput: "tool_based",
|
|
2941
2955
|
strictToolCalling: false,
|
|
2942
|
-
streaming:
|
|
2943
|
-
//
|
|
2956
|
+
streaming: true,
|
|
2957
|
+
// ConverseStream (AWS event-stream frames)
|
|
2944
2958
|
provider: "bedrock"
|
|
2945
2959
|
};
|
|
2946
2960
|
case "vertex":
|
|
@@ -4646,6 +4660,10 @@ ${append}`;
|
|
|
4646
4660
|
if (chunk && typeof chunk === "object" && chunk.role) {
|
|
4647
4661
|
streamedMessage = chunk;
|
|
4648
4662
|
}
|
|
4663
|
+
if (chunk && typeof chunk === "object" && chunk.type === "reasoning" && typeof chunk.reasoning_content === "string") {
|
|
4664
|
+
onEvent?.({ type: "reasoning", text: chunk.reasoning_content });
|
|
4665
|
+
continue;
|
|
4666
|
+
}
|
|
4649
4667
|
const text = extractText2(chunk);
|
|
4650
4668
|
const isAssembledMessage = Boolean(chunk && typeof chunk === "object" && chunk.role) && text.length > 0 && text === streamedText;
|
|
4651
4669
|
if (text && !isAssembledMessage) {
|
|
@@ -11526,6 +11544,28 @@ async function runSmartAgentEvalHarness(params) {
|
|
|
11526
11544
|
return results;
|
|
11527
11545
|
}
|
|
11528
11546
|
|
|
11547
|
+
// src/providers/types.ts
|
|
11548
|
+
function emptyUsage() {
|
|
11549
|
+
return {
|
|
11550
|
+
inputTokens: 0,
|
|
11551
|
+
outputTokens: 0,
|
|
11552
|
+
totalTokens: 0,
|
|
11553
|
+
cachedInputTokens: 0,
|
|
11554
|
+
cachedWriteTokens: 0,
|
|
11555
|
+
cachedOutputTokens: 0,
|
|
11556
|
+
reasoningTokens: 0
|
|
11557
|
+
};
|
|
11558
|
+
}
|
|
11559
|
+
var ProviderError = class extends Error {
|
|
11560
|
+
constructor(message, provider, statusCode, responseBody) {
|
|
11561
|
+
super(message);
|
|
11562
|
+
this.provider = provider;
|
|
11563
|
+
this.statusCode = statusCode;
|
|
11564
|
+
this.responseBody = responseBody;
|
|
11565
|
+
this.name = "ProviderError";
|
|
11566
|
+
}
|
|
11567
|
+
};
|
|
11568
|
+
|
|
11529
11569
|
// src/providers/base.ts
|
|
11530
11570
|
var DEFAULT_RETRY = {
|
|
11531
11571
|
maxRetries: 3,
|
|
@@ -11536,6 +11576,55 @@ var BaseProvider = class {
|
|
|
11536
11576
|
constructor() {
|
|
11537
11577
|
this.retryPolicy = DEFAULT_RETRY;
|
|
11538
11578
|
}
|
|
11579
|
+
/** Applies the transport options shared by every provider config. */
|
|
11580
|
+
configureTransport(config) {
|
|
11581
|
+
this.fetchImpl = config.fetch;
|
|
11582
|
+
this.timeoutMs = typeof config.timeoutMs === "number" && config.timeoutMs > 0 ? config.timeoutMs : void 0;
|
|
11583
|
+
}
|
|
11584
|
+
/**
|
|
11585
|
+
* The single HTTP entry point for every provider call site. Uses the
|
|
11586
|
+
* configured `fetch` and applies `timeoutMs`: the timer covers the time until
|
|
11587
|
+
* the response HEADERS arrive and is cleared after that, so a long-running
|
|
11588
|
+
* stream is never cut by it (use the request `signal` to cancel a stream).
|
|
11589
|
+
* A timeout surfaces as a `ProviderError` with status 408. The caller's
|
|
11590
|
+
* `signal` still aborts the request as before.
|
|
11591
|
+
*/
|
|
11592
|
+
async httpFetch(url, init = {}) {
|
|
11593
|
+
const doFetch = this.fetchImpl ?? fetch;
|
|
11594
|
+
const timeoutMs = this.timeoutMs;
|
|
11595
|
+
if (!timeoutMs) return doFetch(url, init);
|
|
11596
|
+
const controller = new AbortController();
|
|
11597
|
+
const outer = init.signal ?? void 0;
|
|
11598
|
+
let timedOut = false;
|
|
11599
|
+
const onOuterAbort = () => controller.abort(outer?.reason);
|
|
11600
|
+
if (outer) {
|
|
11601
|
+
if (outer.aborted) controller.abort(outer.reason);
|
|
11602
|
+
else outer.addEventListener("abort", onOuterAbort, { once: true });
|
|
11603
|
+
}
|
|
11604
|
+
const timer = setTimeout(() => {
|
|
11605
|
+
timedOut = true;
|
|
11606
|
+
controller.abort(new Error(`timed out after ${timeoutMs}ms`));
|
|
11607
|
+
}, timeoutMs);
|
|
11608
|
+
try {
|
|
11609
|
+
const res = await doFetch(url, { ...init, signal: controller.signal });
|
|
11610
|
+
return res;
|
|
11611
|
+
} catch (err) {
|
|
11612
|
+
if (timedOut) {
|
|
11613
|
+
throw new ProviderError(`${this.providerName} request timed out after ${timeoutMs}ms`, this.providerName, 408);
|
|
11614
|
+
}
|
|
11615
|
+
throw err;
|
|
11616
|
+
} finally {
|
|
11617
|
+
clearTimeout(timer);
|
|
11618
|
+
}
|
|
11619
|
+
}
|
|
11620
|
+
/**
|
|
11621
|
+
* Embeds `request.input`. Implemented by the providers that have an
|
|
11622
|
+
* embeddings endpoint (OpenAI, Azure, openai-compatible, Bedrock, Vertex);
|
|
11623
|
+
* the others reject with a 400 ProviderError.
|
|
11624
|
+
*/
|
|
11625
|
+
async embed(_request) {
|
|
11626
|
+
throw new ProviderError(`${this.providerName} does not support embeddings`, this.providerName, 400);
|
|
11627
|
+
}
|
|
11539
11628
|
/**
|
|
11540
11629
|
* Helper concrete providers can wrap their fetch with. Retries 429/5xx
|
|
11541
11630
|
* with exponential backoff and respects Retry-After if the response
|
|
@@ -11577,34 +11666,13 @@ var BaseProvider = class {
|
|
|
11577
11666
|
}
|
|
11578
11667
|
};
|
|
11579
11668
|
|
|
11580
|
-
// src/providers/types.ts
|
|
11581
|
-
function emptyUsage() {
|
|
11582
|
-
return {
|
|
11583
|
-
inputTokens: 0,
|
|
11584
|
-
outputTokens: 0,
|
|
11585
|
-
totalTokens: 0,
|
|
11586
|
-
cachedInputTokens: 0,
|
|
11587
|
-
cachedWriteTokens: 0,
|
|
11588
|
-
cachedOutputTokens: 0,
|
|
11589
|
-
reasoningTokens: 0
|
|
11590
|
-
};
|
|
11591
|
-
}
|
|
11592
|
-
var ProviderError = class extends Error {
|
|
11593
|
-
constructor(message, provider, statusCode, responseBody) {
|
|
11594
|
-
super(message);
|
|
11595
|
-
this.provider = provider;
|
|
11596
|
-
this.statusCode = statusCode;
|
|
11597
|
-
this.responseBody = responseBody;
|
|
11598
|
-
this.name = "ProviderError";
|
|
11599
|
-
}
|
|
11600
|
-
};
|
|
11601
|
-
|
|
11602
11669
|
// src/providers/jev.ts
|
|
11603
11670
|
var JEV_DEFAULT_BASE_URL = "https://api.typesafe.ai";
|
|
11604
11671
|
var JevProvider = class extends BaseProvider {
|
|
11605
11672
|
constructor(config) {
|
|
11606
11673
|
super();
|
|
11607
11674
|
this.providerName = "jev";
|
|
11675
|
+
this.configureTransport(config);
|
|
11608
11676
|
this.apiKey = config.apiKey;
|
|
11609
11677
|
this.baseURL = (config.baseURL ?? JEV_DEFAULT_BASE_URL).replace(/\/$/, "");
|
|
11610
11678
|
this.defaultModel = config.defaultModel;
|
|
@@ -11620,7 +11688,7 @@ var JevProvider = class extends BaseProvider {
|
|
|
11620
11688
|
questions: request.questions
|
|
11621
11689
|
};
|
|
11622
11690
|
const res = await this.doFetchWithRetry(
|
|
11623
|
-
() =>
|
|
11691
|
+
() => this.httpFetch(`${this.baseURL}/v1/systemone`, {
|
|
11624
11692
|
method: "POST",
|
|
11625
11693
|
headers: {
|
|
11626
11694
|
"Content-Type": "application/json",
|
|
@@ -13856,12 +13924,12 @@ function responseCache(config = {}) {
|
|
|
13856
13924
|
};
|
|
13857
13925
|
}
|
|
13858
13926
|
function signRequest(req) {
|
|
13859
|
-
const now = /* @__PURE__ */ new Date();
|
|
13927
|
+
const now = req.now ?? /* @__PURE__ */ new Date();
|
|
13860
13928
|
const dateStamp = toDateStamp(now);
|
|
13861
13929
|
const amzDate = toAmzDate(now);
|
|
13862
13930
|
const parsed = new URL(req.url);
|
|
13863
13931
|
const host = parsed.host;
|
|
13864
|
-
const canonicalUri = parsed.pathname || "/";
|
|
13932
|
+
const canonicalUri = (parsed.pathname || "/").split("/").map((seg) => encodeURIComponent(seg).replace(/[!'()*]/g, (c) => "%" + c.charCodeAt(0).toString(16).toUpperCase())).join("/");
|
|
13865
13933
|
const canonicalQuerystring = sortQueryParams(parsed.searchParams);
|
|
13866
13934
|
const headers = {
|
|
13867
13935
|
...req.headers,
|
|
@@ -15178,73 +15246,6 @@ function languageGuard(config) {
|
|
|
15178
15246
|
// src/index.ts
|
|
15179
15247
|
init_content();
|
|
15180
15248
|
|
|
15181
|
-
// src/providers/utils/sse.ts
|
|
15182
|
-
async function* parseSSEStream(body, signal) {
|
|
15183
|
-
const reader = body.getReader();
|
|
15184
|
-
const decoder = new TextDecoder();
|
|
15185
|
-
let buffer = "";
|
|
15186
|
-
try {
|
|
15187
|
-
while (true) {
|
|
15188
|
-
if (signal?.aborted) throw abortReason(signal);
|
|
15189
|
-
const { done, value } = await reader.read();
|
|
15190
|
-
if (done) break;
|
|
15191
|
-
buffer += decoder.decode(value, { stream: true });
|
|
15192
|
-
const parts = buffer.split(/\r?\n\r?\n/);
|
|
15193
|
-
buffer = parts.pop() ?? "";
|
|
15194
|
-
for (const part of parts) {
|
|
15195
|
-
if (!part.trim()) continue;
|
|
15196
|
-
const event = parseSSEBlock(part);
|
|
15197
|
-
if (event) yield event;
|
|
15198
|
-
}
|
|
15199
|
-
}
|
|
15200
|
-
if (buffer.trim()) {
|
|
15201
|
-
const event = parseSSEBlock(buffer);
|
|
15202
|
-
if (event) yield event;
|
|
15203
|
-
}
|
|
15204
|
-
} finally {
|
|
15205
|
-
reader.cancel().catch(() => void 0);
|
|
15206
|
-
reader.releaseLock();
|
|
15207
|
-
}
|
|
15208
|
-
}
|
|
15209
|
-
function parseSSEBlock(block) {
|
|
15210
|
-
let event;
|
|
15211
|
-
let id;
|
|
15212
|
-
let retry;
|
|
15213
|
-
const dataLines = [];
|
|
15214
|
-
for (const line of block.split(/\r?\n/)) {
|
|
15215
|
-
if (line.startsWith(":")) continue;
|
|
15216
|
-
const colonIdx = line.indexOf(":");
|
|
15217
|
-
let field;
|
|
15218
|
-
let value;
|
|
15219
|
-
if (colonIdx === -1) {
|
|
15220
|
-
field = line;
|
|
15221
|
-
value = "";
|
|
15222
|
-
} else {
|
|
15223
|
-
field = line.slice(0, colonIdx);
|
|
15224
|
-
value = line.slice(colonIdx + 1);
|
|
15225
|
-
if (value.startsWith(" ")) value = value.slice(1);
|
|
15226
|
-
}
|
|
15227
|
-
switch (field) {
|
|
15228
|
-
case "event":
|
|
15229
|
-
event = value;
|
|
15230
|
-
break;
|
|
15231
|
-
case "data":
|
|
15232
|
-
dataLines.push(value);
|
|
15233
|
-
break;
|
|
15234
|
-
case "id":
|
|
15235
|
-
id = value;
|
|
15236
|
-
break;
|
|
15237
|
-
case "retry": {
|
|
15238
|
-
const n = parseInt(value, 10);
|
|
15239
|
-
if (!isNaN(n)) retry = n;
|
|
15240
|
-
break;
|
|
15241
|
-
}
|
|
15242
|
-
}
|
|
15243
|
-
}
|
|
15244
|
-
if (dataLines.length === 0) return null;
|
|
15245
|
-
return { event, data: dataLines.join("\n"), id, retry };
|
|
15246
|
-
}
|
|
15247
|
-
|
|
15248
15249
|
// src/providers/utils/reasoning.ts
|
|
15249
15250
|
var ANTHROPIC_EFFORT_BUDGET = {
|
|
15250
15251
|
// 0 = off. `applyAnthropicReasoning` bails on a falsy budget and emits no
|
|
@@ -15266,6 +15267,7 @@ var GEMINI_EFFORT_BUDGET = {
|
|
|
15266
15267
|
high: 12e3
|
|
15267
15268
|
};
|
|
15268
15269
|
var THINKING_OUTPUT_RESERVE = 1024;
|
|
15270
|
+
var MIN_THINKING_BUDGET = 1024;
|
|
15269
15271
|
var THINKING_MIN_MAX_TOKENS = 4096;
|
|
15270
15272
|
function applyOpenAIReasoning(body, reasoning, mode = "legacy_effort") {
|
|
15271
15273
|
if (!reasoning) return;
|
|
@@ -15281,8 +15283,48 @@ function applyOpenAIReasoning(body, reasoning, mode = "legacy_effort") {
|
|
|
15281
15283
|
if (reasoning.providerExtras) Object.assign(body, reasoning.providerExtras);
|
|
15282
15284
|
}
|
|
15283
15285
|
}
|
|
15284
|
-
function
|
|
15286
|
+
function supportsAdaptiveThinking(model) {
|
|
15287
|
+
if (typeof model !== "string") return false;
|
|
15288
|
+
const id = model.toLowerCase();
|
|
15289
|
+
const at = id.indexOf("claude-");
|
|
15290
|
+
if (at < 0) return false;
|
|
15291
|
+
for (const tok of id.slice(at + 7).split("-")) {
|
|
15292
|
+
if (tok === "fable") return true;
|
|
15293
|
+
const m = /^(\d+)(?:@|$)/.exec(tok);
|
|
15294
|
+
if (m) {
|
|
15295
|
+
if (m[1].length <= 2) return Number(m[1]) >= 5;
|
|
15296
|
+
return false;
|
|
15297
|
+
}
|
|
15298
|
+
}
|
|
15299
|
+
return false;
|
|
15300
|
+
}
|
|
15301
|
+
function resolveThinkingForm(model, mode) {
|
|
15302
|
+
if (mode === "adaptive" || mode === "budget") return mode;
|
|
15303
|
+
return supportsAdaptiveThinking(model) ? "adaptive" : "budget";
|
|
15304
|
+
}
|
|
15305
|
+
function applyAdaptiveThinking(_body, reasoning, setThinking, setOutputConfig) {
|
|
15306
|
+
const requested = normalizeEffort(reasoning.effort);
|
|
15307
|
+
if (requested === "none") return false;
|
|
15308
|
+
let effort;
|
|
15309
|
+
if (requested) effort = requested === "minimal" ? "low" : requested;
|
|
15310
|
+
else if (typeof reasoning.budgetTokens === "number" && reasoning.budgetTokens > 0) {
|
|
15311
|
+
effort = reasoning.budgetTokens <= ANTHROPIC_EFFORT_BUDGET.low ? "low" : reasoning.budgetTokens <= ANTHROPIC_EFFORT_BUDGET.medium ? "medium" : "high";
|
|
15312
|
+
}
|
|
15313
|
+
if (!effort) return false;
|
|
15314
|
+
const thinking = { type: "adaptive" };
|
|
15315
|
+
if (reasoning.includeThoughts !== false) thinking.display = "summarized";
|
|
15316
|
+
if (reasoning.providerExtras) Object.assign(thinking, reasoning.providerExtras);
|
|
15317
|
+
setThinking({ thinking });
|
|
15318
|
+
setOutputConfig({ effort });
|
|
15319
|
+
return true;
|
|
15320
|
+
}
|
|
15321
|
+
function applyAnthropicReasoning(body, reasoning, opts) {
|
|
15285
15322
|
if (!reasoning) return;
|
|
15323
|
+
if (resolveThinkingForm(opts?.model ?? body.model, opts?.mode) === "adaptive") {
|
|
15324
|
+
const on = applyAdaptiveThinking(body, reasoning, (extra) => body.thinking = extra.thinking, (o) => body.output_config = { ...body.output_config ?? {}, ...o });
|
|
15325
|
+
if (on) stripSamplingParams(body, ["temperature", "top_p", "top_k"]);
|
|
15326
|
+
return;
|
|
15327
|
+
}
|
|
15286
15328
|
let budget = resolveBudget(reasoning, ANTHROPIC_EFFORT_BUDGET);
|
|
15287
15329
|
if (!budget) return;
|
|
15288
15330
|
const currentMax = typeof body.max_tokens === "number" ? body.max_tokens : 0;
|
|
@@ -15290,14 +15332,20 @@ function applyAnthropicReasoning(body, reasoning) {
|
|
|
15290
15332
|
if (currentMax < requiredMax) {
|
|
15291
15333
|
body.max_tokens = requiredMax;
|
|
15292
15334
|
}
|
|
15293
|
-
budget = clampBudget(budget, body.max_tokens);
|
|
15335
|
+
budget = Math.max(MIN_THINKING_BUDGET, clampBudget(budget, body.max_tokens));
|
|
15294
15336
|
const thinking = { type: "enabled", budget_tokens: budget };
|
|
15295
15337
|
if (reasoning.providerExtras) Object.assign(thinking, reasoning.providerExtras);
|
|
15296
15338
|
body.thinking = thinking;
|
|
15297
15339
|
stripSamplingParams(body, ["temperature", "top_p", "top_k"]);
|
|
15298
15340
|
}
|
|
15299
|
-
function applyBedrockReasoning(body, reasoning) {
|
|
15341
|
+
function applyBedrockReasoning(body, reasoning, opts) {
|
|
15300
15342
|
if (!reasoning) return;
|
|
15343
|
+
if (resolveThinkingForm(opts?.model ?? body.modelId, opts?.mode) === "adaptive") {
|
|
15344
|
+
const fields = () => body.additionalModelRequestFields ?? (body.additionalModelRequestFields = {});
|
|
15345
|
+
const on = applyAdaptiveThinking(body, reasoning, (extra2) => fields().thinking = extra2.thinking, (o) => fields().output_config = { ...fields().output_config ?? {}, ...o });
|
|
15346
|
+
if (on && body.inferenceConfig) stripSamplingParams(body.inferenceConfig, ["temperature", "topP"]);
|
|
15347
|
+
return;
|
|
15348
|
+
}
|
|
15301
15349
|
let budget = resolveBudget(reasoning, ANTHROPIC_EFFORT_BUDGET);
|
|
15302
15350
|
if (!budget) return;
|
|
15303
15351
|
const inference = body.inferenceConfig ?? (body.inferenceConfig = {});
|
|
@@ -15306,7 +15354,7 @@ function applyBedrockReasoning(body, reasoning) {
|
|
|
15306
15354
|
if (currentMax < requiredMax) {
|
|
15307
15355
|
inference.maxTokens = requiredMax;
|
|
15308
15356
|
}
|
|
15309
|
-
budget = clampBudget(budget, inference.maxTokens);
|
|
15357
|
+
budget = Math.max(MIN_THINKING_BUDGET, clampBudget(budget, inference.maxTokens));
|
|
15310
15358
|
const extra = body.additionalModelRequestFields ?? (body.additionalModelRequestFields = {});
|
|
15311
15359
|
const thinking = { type: "enabled", budget_tokens: budget };
|
|
15312
15360
|
if (reasoning.providerExtras) Object.assign(thinking, reasoning.providerExtras);
|
|
@@ -15316,8 +15364,9 @@ function applyBedrockReasoning(body, reasoning) {
|
|
|
15316
15364
|
function applyGeminiReasoning(generationConfig, reasoning) {
|
|
15317
15365
|
if (!reasoning) return;
|
|
15318
15366
|
const budget = resolveBudget(reasoning, GEMINI_EFFORT_BUDGET);
|
|
15319
|
-
|
|
15320
|
-
|
|
15367
|
+
const level = typeof reasoning.thinkingLevel === "string" && reasoning.thinkingLevel ? reasoning.thinkingLevel : void 0;
|
|
15368
|
+
if (budget == null && !level) return;
|
|
15369
|
+
const thinkingConfig = level && budget !== 0 ? { thinkingLevel: level } : { thinkingBudget: budget ?? 0 };
|
|
15321
15370
|
if (reasoning.includeThoughts) thinkingConfig.includeThoughts = true;
|
|
15322
15371
|
if (reasoning.providerExtras) Object.assign(thinkingConfig, reasoning.providerExtras);
|
|
15323
15372
|
generationConfig.thinkingConfig = thinkingConfig;
|
|
@@ -15348,6 +15397,73 @@ function resolveBudget(reasoning, effortBudget) {
|
|
|
15348
15397
|
return void 0;
|
|
15349
15398
|
}
|
|
15350
15399
|
|
|
15400
|
+
// src/providers/utils/sse.ts
|
|
15401
|
+
async function* parseSSEStream(body, signal) {
|
|
15402
|
+
const reader = body.getReader();
|
|
15403
|
+
const decoder = new TextDecoder();
|
|
15404
|
+
let buffer = "";
|
|
15405
|
+
try {
|
|
15406
|
+
while (true) {
|
|
15407
|
+
if (signal?.aborted) throw abortReason(signal);
|
|
15408
|
+
const { done, value } = await reader.read();
|
|
15409
|
+
if (done) break;
|
|
15410
|
+
buffer += decoder.decode(value, { stream: true });
|
|
15411
|
+
const parts = buffer.split(/\r?\n\r?\n/);
|
|
15412
|
+
buffer = parts.pop() ?? "";
|
|
15413
|
+
for (const part of parts) {
|
|
15414
|
+
if (!part.trim()) continue;
|
|
15415
|
+
const event = parseSSEBlock(part);
|
|
15416
|
+
if (event) yield event;
|
|
15417
|
+
}
|
|
15418
|
+
}
|
|
15419
|
+
if (buffer.trim()) {
|
|
15420
|
+
const event = parseSSEBlock(buffer);
|
|
15421
|
+
if (event) yield event;
|
|
15422
|
+
}
|
|
15423
|
+
} finally {
|
|
15424
|
+
reader.cancel().catch(() => void 0);
|
|
15425
|
+
reader.releaseLock();
|
|
15426
|
+
}
|
|
15427
|
+
}
|
|
15428
|
+
function parseSSEBlock(block) {
|
|
15429
|
+
let event;
|
|
15430
|
+
let id;
|
|
15431
|
+
let retry;
|
|
15432
|
+
const dataLines = [];
|
|
15433
|
+
for (const line of block.split(/\r?\n/)) {
|
|
15434
|
+
if (line.startsWith(":")) continue;
|
|
15435
|
+
const colonIdx = line.indexOf(":");
|
|
15436
|
+
let field;
|
|
15437
|
+
let value;
|
|
15438
|
+
if (colonIdx === -1) {
|
|
15439
|
+
field = line;
|
|
15440
|
+
value = "";
|
|
15441
|
+
} else {
|
|
15442
|
+
field = line.slice(0, colonIdx);
|
|
15443
|
+
value = line.slice(colonIdx + 1);
|
|
15444
|
+
if (value.startsWith(" ")) value = value.slice(1);
|
|
15445
|
+
}
|
|
15446
|
+
switch (field) {
|
|
15447
|
+
case "event":
|
|
15448
|
+
event = value;
|
|
15449
|
+
break;
|
|
15450
|
+
case "data":
|
|
15451
|
+
dataLines.push(value);
|
|
15452
|
+
break;
|
|
15453
|
+
case "id":
|
|
15454
|
+
id = value;
|
|
15455
|
+
break;
|
|
15456
|
+
case "retry": {
|
|
15457
|
+
const n = parseInt(value, 10);
|
|
15458
|
+
if (!isNaN(n)) retry = n;
|
|
15459
|
+
break;
|
|
15460
|
+
}
|
|
15461
|
+
}
|
|
15462
|
+
}
|
|
15463
|
+
if (dataLines.length === 0) return null;
|
|
15464
|
+
return { event, data: dataLines.join("\n"), id, retry };
|
|
15465
|
+
}
|
|
15466
|
+
|
|
15351
15467
|
// src/providers/utils/media.ts
|
|
15352
15468
|
var EXTENSION_MIME = {
|
|
15353
15469
|
jpg: "image/jpeg",
|
|
@@ -15539,11 +15655,64 @@ function isObject2(value) {
|
|
|
15539
15655
|
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
15540
15656
|
}
|
|
15541
15657
|
|
|
15658
|
+
// src/providers/utils/embeddings.ts
|
|
15659
|
+
function chunkArray(items, size) {
|
|
15660
|
+
const n = Math.max(1, Math.floor(size));
|
|
15661
|
+
const out = [];
|
|
15662
|
+
for (let i = 0; i < items.length; i += n) out.push(items.slice(i, i + n));
|
|
15663
|
+
return out;
|
|
15664
|
+
}
|
|
15665
|
+
async function mapWithConcurrency(items, limit, fn, signal) {
|
|
15666
|
+
const results = new Array(items.length);
|
|
15667
|
+
let next = 0;
|
|
15668
|
+
let failure;
|
|
15669
|
+
let failed = false;
|
|
15670
|
+
const worker = async () => {
|
|
15671
|
+
while (!failed) {
|
|
15672
|
+
if (signal?.aborted) throw signal.reason ?? new Error("aborted");
|
|
15673
|
+
const i = next++;
|
|
15674
|
+
if (i >= items.length) return;
|
|
15675
|
+
try {
|
|
15676
|
+
results[i] = await fn(items[i], i);
|
|
15677
|
+
} catch (err) {
|
|
15678
|
+
failed = true;
|
|
15679
|
+
failure = err;
|
|
15680
|
+
return;
|
|
15681
|
+
}
|
|
15682
|
+
}
|
|
15683
|
+
};
|
|
15684
|
+
await Promise.all(Array.from({ length: Math.min(Math.max(1, limit), items.length) }, worker));
|
|
15685
|
+
if (failed) throw failure;
|
|
15686
|
+
return results;
|
|
15687
|
+
}
|
|
15688
|
+
function decodeBase64Vector(b64) {
|
|
15689
|
+
const buf = Buffer.from(b64, "base64");
|
|
15690
|
+
const view = new DataView(buf.buffer, buf.byteOffset, buf.byteLength);
|
|
15691
|
+
const out = new Array(Math.floor(buf.byteLength / 4));
|
|
15692
|
+
for (let i = 0; i < out.length; i++) out[i] = view.getFloat32(i * 4, true);
|
|
15693
|
+
return out;
|
|
15694
|
+
}
|
|
15695
|
+
function assertVectorCount(provider, vectors, expected) {
|
|
15696
|
+
if (vectors.length !== expected) {
|
|
15697
|
+
throw new ProviderError(
|
|
15698
|
+
`${provider} embeddings returned ${vectors.length} vectors for ${expected} inputs`,
|
|
15699
|
+
provider,
|
|
15700
|
+
502
|
|
15701
|
+
);
|
|
15702
|
+
}
|
|
15703
|
+
}
|
|
15704
|
+
function requireEmbeddingModel(provider, model) {
|
|
15705
|
+
if (!model) throw new ProviderError(`${provider} embeddings require a model`, provider, 400);
|
|
15706
|
+
return model;
|
|
15707
|
+
}
|
|
15708
|
+
|
|
15542
15709
|
// src/providers/openai.ts
|
|
15543
|
-
var OpenAIProvider = class
|
|
15710
|
+
var OpenAIProvider = class extends BaseProvider {
|
|
15544
15711
|
constructor(config) {
|
|
15545
15712
|
super();
|
|
15546
15713
|
this.providerName = "openai";
|
|
15714
|
+
this.configureTransport(config);
|
|
15715
|
+
this.maxTokensParam = config.maxTokensParam ?? "auto";
|
|
15547
15716
|
this.apiKey = config.apiKey;
|
|
15548
15717
|
this.baseURL = (config.baseURL ?? "https://api.openai.com/v1").replace(/\/$/, "");
|
|
15549
15718
|
this.defaultModel = config.defaultModel ?? "gpt-4o";
|
|
@@ -15551,10 +15720,14 @@ var OpenAIProvider = class _OpenAIProvider extends BaseProvider {
|
|
|
15551
15720
|
...config.defaultHeaders,
|
|
15552
15721
|
...config.organization ? { "OpenAI-Organization": config.organization } : {}
|
|
15553
15722
|
};
|
|
15554
|
-
|
|
15555
|
-
const
|
|
15556
|
-
this.
|
|
15557
|
-
this.
|
|
15723
|
+
const legacy = config.responsesApi;
|
|
15724
|
+
const explicit = config.api === "chat" || config.api === "responses" ? config.api : void 0;
|
|
15725
|
+
this.responsesApi = explicit === "responses" ? "always" : explicit === "chat" ? "never" : legacy ?? (config._autoMeansChat ? "never" : "auto");
|
|
15726
|
+
this.apiExplicitChat = explicit === "chat" || explicit === void 0 && legacy === "never";
|
|
15727
|
+
this.apiExplicitResponses = this.responsesApi === "always";
|
|
15728
|
+
this.apiResponsesNative = explicit === "responses";
|
|
15729
|
+
this.responsesApiModels = [...config.responsesApiModels ?? []];
|
|
15730
|
+
this.responsesStreaming = config.responsesStreaming ?? this.apiResponsesNative;
|
|
15558
15731
|
if (config.retry) this.retryPolicy = { ...this.retryPolicy, ...config.retry };
|
|
15559
15732
|
}
|
|
15560
15733
|
/** True when the caller listed this request's model in `responsesApiModels`. */
|
|
@@ -15580,9 +15753,10 @@ var OpenAIProvider = class _OpenAIProvider extends BaseProvider {
|
|
|
15580
15753
|
* A model listed in `responsesApiModels` is the caller stating the answer
|
|
15581
15754
|
* for that model alone; `never` still overrides it. */
|
|
15582
15755
|
useResponsesApi(request) {
|
|
15583
|
-
if (this.
|
|
15584
|
-
if (this.
|
|
15756
|
+
if (this.apiExplicitChat) return false;
|
|
15757
|
+
if (this.apiExplicitResponses) return true;
|
|
15585
15758
|
if (this.isResponsesApiModel(request)) return true;
|
|
15759
|
+
if (this.responsesApi !== "auto") return false;
|
|
15586
15760
|
if (!request.reasoning) return false;
|
|
15587
15761
|
return isReasoningModel(request.model || this.defaultModel);
|
|
15588
15762
|
}
|
|
@@ -15597,7 +15771,7 @@ var OpenAIProvider = class _OpenAIProvider extends BaseProvider {
|
|
|
15597
15771
|
}
|
|
15598
15772
|
async *completeStream(request) {
|
|
15599
15773
|
if (this.useResponsesApi(request)) {
|
|
15600
|
-
if (this.responsesStreaming && this.isResponsesApiModel(request)) {
|
|
15774
|
+
if (this.responsesStreaming && (this.apiResponsesNative || this.isResponsesApiModel(request))) {
|
|
15601
15775
|
yield* this.streamResponses(request);
|
|
15602
15776
|
return;
|
|
15603
15777
|
}
|
|
@@ -15647,9 +15821,14 @@ var OpenAIProvider = class _OpenAIProvider extends BaseProvider {
|
|
|
15647
15821
|
delta: {},
|
|
15648
15822
|
finishReason: mapFinishReason(choice.finish_reason)
|
|
15649
15823
|
};
|
|
15824
|
+
if (typeof choice.finish_reason === "string") out.rawFinishReason = choice.finish_reason;
|
|
15825
|
+
const fields = pickProviderFields(chunk, delta, choice);
|
|
15826
|
+
if (fields) out.providerFields = fields;
|
|
15650
15827
|
if (delta.content) {
|
|
15651
15828
|
out.delta.content = delta.content;
|
|
15652
15829
|
}
|
|
15830
|
+
const reasoningDelta = extractReasoningText(delta);
|
|
15831
|
+
if (reasoningDelta) out.delta.reasoning = { summary: reasoningDelta };
|
|
15653
15832
|
if (delta.tool_calls) {
|
|
15654
15833
|
const partials = [];
|
|
15655
15834
|
for (const tc of delta.tool_calls) {
|
|
@@ -15661,7 +15840,7 @@ var OpenAIProvider = class _OpenAIProvider extends BaseProvider {
|
|
|
15661
15840
|
if (tc.id) buf.id = tc.id;
|
|
15662
15841
|
if (tc.function?.name) buf.name = tc.function.name;
|
|
15663
15842
|
if (tc.function?.arguments) buf.arguments += tc.function.arguments;
|
|
15664
|
-
partials.push({ id: buf.id, name: buf.name || void 0, arguments: tc.function?.arguments });
|
|
15843
|
+
partials.push({ id: buf.id, name: buf.name || void 0, arguments: tc.function?.arguments, index: idx });
|
|
15665
15844
|
}
|
|
15666
15845
|
out.delta.toolCalls = partials;
|
|
15667
15846
|
}
|
|
@@ -15669,6 +15848,51 @@ var OpenAIProvider = class _OpenAIProvider extends BaseProvider {
|
|
|
15669
15848
|
yield out;
|
|
15670
15849
|
}
|
|
15671
15850
|
}
|
|
15851
|
+
// ─── Embeddings ──────────────────────────────────────────────────────────
|
|
15852
|
+
/** POST /embeddings, batched (default 2048 inputs per request, the OpenAI cap). */
|
|
15853
|
+
async embed(request) {
|
|
15854
|
+
const model = requireEmbeddingModel(this.providerName, request.model);
|
|
15855
|
+
const batches = chunkArray(request.input, request.batchSize ?? 2048);
|
|
15856
|
+
const vectors = [];
|
|
15857
|
+
const raw = [];
|
|
15858
|
+
let inputTokens = 0;
|
|
15859
|
+
let totalTokens = 0;
|
|
15860
|
+
let responseModel = model;
|
|
15861
|
+
for (const batch of batches) {
|
|
15862
|
+
const body = { model, input: batch };
|
|
15863
|
+
if (request.dimensions != null) body.dimensions = request.dimensions;
|
|
15864
|
+
if (request.encodingFormat) body.encoding_format = request.encodingFormat;
|
|
15865
|
+
if (request.extra) Object.assign(body, request.extra);
|
|
15866
|
+
const res = await this.embeddingsFetch(body, request.signal);
|
|
15867
|
+
const json = await res.json();
|
|
15868
|
+
raw.push(json);
|
|
15869
|
+
const data = Array.isArray(json.data) ? [...json.data] : [];
|
|
15870
|
+
data.sort((a, b) => (a.index ?? 0) - (b.index ?? 0));
|
|
15871
|
+
for (const d of data) {
|
|
15872
|
+
vectors.push(typeof d.embedding === "string" ? decodeBase64Vector(d.embedding) : d.embedding);
|
|
15873
|
+
}
|
|
15874
|
+
inputTokens += json.usage?.prompt_tokens ?? 0;
|
|
15875
|
+
totalTokens += json.usage?.total_tokens ?? json.usage?.prompt_tokens ?? 0;
|
|
15876
|
+
responseModel = json.model ?? responseModel;
|
|
15877
|
+
}
|
|
15878
|
+
assertVectorCount(this.providerName, vectors, request.input.length);
|
|
15879
|
+
return { model: responseModel, vectors, usage: { inputTokens, totalTokens }, raw };
|
|
15880
|
+
}
|
|
15881
|
+
async embeddingsFetch(body, signal) {
|
|
15882
|
+
const url = `${this.baseURL}/embeddings`;
|
|
15883
|
+
const headers = {
|
|
15884
|
+
"Content-Type": "application/json",
|
|
15885
|
+
Authorization: `Bearer ${this.apiKey}`,
|
|
15886
|
+
...this.defaultHeaders
|
|
15887
|
+
};
|
|
15888
|
+
const payload = JSON.stringify(body);
|
|
15889
|
+
const res = await this.doFetchWithRetry(() => this.httpFetch(url, { method: "POST", headers, body: payload, signal }), signal);
|
|
15890
|
+
if (!res.ok) {
|
|
15891
|
+
const text = await res.text().catch(() => "");
|
|
15892
|
+
throw new ProviderError(`OpenAI embeddings API error ${res.status}: ${text}`, this.providerName, res.status, text);
|
|
15893
|
+
}
|
|
15894
|
+
return res;
|
|
15895
|
+
}
|
|
15672
15896
|
// ─── Internals ───────────────────────────────────────────────────────────
|
|
15673
15897
|
buildRequestBody(request, stream) {
|
|
15674
15898
|
const body = {
|
|
@@ -15676,15 +15900,27 @@ var OpenAIProvider = class _OpenAIProvider extends BaseProvider {
|
|
|
15676
15900
|
messages: request.messages.map((m) => this.toOpenAIMessage(m)),
|
|
15677
15901
|
stream
|
|
15678
15902
|
};
|
|
15679
|
-
if (stream) {
|
|
15903
|
+
if (stream && request.streamUsage !== false) {
|
|
15680
15904
|
body.stream_options = { include_usage: true };
|
|
15681
15905
|
}
|
|
15682
|
-
|
|
15683
|
-
|
|
15684
|
-
if (request.
|
|
15906
|
+
const modelId = String(body.model);
|
|
15907
|
+
const reasoningModel = isReasoningModel(modelId) && !/chat/i.test(modelId);
|
|
15908
|
+
if (request.temperature != null && !reasoningModel) body.temperature = request.temperature;
|
|
15909
|
+
if (request.maxTokens != null) {
|
|
15910
|
+
const useCompletionTokens = this.maxTokensParam === "max_completion_tokens" || this.maxTokensParam === "auto" && isReasoningModel(modelId);
|
|
15911
|
+
body[useCompletionTokens ? "max_completion_tokens" : "max_tokens"] = request.maxTokens;
|
|
15912
|
+
}
|
|
15913
|
+
if (request.topP != null && !reasoningModel) body.top_p = request.topP;
|
|
15685
15914
|
if (request.stop) body.stop = request.stop;
|
|
15915
|
+
if (request.presencePenalty != null) body.presence_penalty = request.presencePenalty;
|
|
15916
|
+
if (request.frequencyPenalty != null) body.frequency_penalty = request.frequencyPenalty;
|
|
15917
|
+
if (request.seed != null) body.seed = request.seed;
|
|
15918
|
+
if (request.n != null) body.n = request.n;
|
|
15919
|
+
if (request.logprobs != null) body.logprobs = request.logprobs;
|
|
15920
|
+
if (request.topLogprobs != null) body.top_logprobs = request.topLogprobs;
|
|
15686
15921
|
if (request.tools?.length) {
|
|
15687
15922
|
body.tools = request.tools.map((t) => this.toOpenAITool(t));
|
|
15923
|
+
if (request.parallelToolCalls != null) body.parallel_tool_calls = request.parallelToolCalls;
|
|
15688
15924
|
}
|
|
15689
15925
|
if (request.toolChoice != null && request.tools?.length) {
|
|
15690
15926
|
if (typeof request.toolChoice === "string") {
|
|
@@ -15716,7 +15952,7 @@ var OpenAIProvider = class _OpenAIProvider extends BaseProvider {
|
|
|
15716
15952
|
// ─── Responses API (reasoning models) ──────────────────────────────────────
|
|
15717
15953
|
async completeResponses(request) {
|
|
15718
15954
|
const body = this.buildResponsesBody(request);
|
|
15719
|
-
if (this.isResponsesApiModel(request)) adaptChatExtrasForResponses(body, request.extra);
|
|
15955
|
+
if (this.apiResponsesNative || this.isResponsesApiModel(request)) adaptChatExtrasForResponses(body, request.extra);
|
|
15720
15956
|
const res = await this.responsesFetch(body, request.signal);
|
|
15721
15957
|
const json = await res.json();
|
|
15722
15958
|
return this.parseResponsesResponse(json, request.model || this.defaultModel);
|
|
@@ -15739,6 +15975,7 @@ var OpenAIProvider = class _OpenAIProvider extends BaseProvider {
|
|
|
15739
15975
|
let model = modelId;
|
|
15740
15976
|
const calls = /* @__PURE__ */ new Map();
|
|
15741
15977
|
let final;
|
|
15978
|
+
let streamedSummary = false;
|
|
15742
15979
|
for await (const event of parseSSEStream(res.body, request.signal)) {
|
|
15743
15980
|
if (event.data === "[DONE]") break;
|
|
15744
15981
|
let data;
|
|
@@ -15756,19 +15993,28 @@ var OpenAIProvider = class _OpenAIProvider extends BaseProvider {
|
|
|
15756
15993
|
case "response.output_text.delta":
|
|
15757
15994
|
if (data.delta) yield { id, model, delta: { content: data.delta } };
|
|
15758
15995
|
break;
|
|
15996
|
+
case "response.reasoning_summary_part.added":
|
|
15997
|
+
if (streamedSummary) yield { id, model, delta: { reasoning: { summary: "\n\n" } } };
|
|
15998
|
+
break;
|
|
15999
|
+
case "response.reasoning_summary_text.delta":
|
|
16000
|
+
if (typeof data.delta === "string" && data.delta) {
|
|
16001
|
+
streamedSummary = true;
|
|
16002
|
+
yield { id, model, delta: { reasoning: { summary: data.delta } } };
|
|
16003
|
+
}
|
|
16004
|
+
break;
|
|
15759
16005
|
case "response.output_item.added": {
|
|
15760
16006
|
const item = data.item;
|
|
15761
16007
|
if (item?.type !== "function_call") break;
|
|
15762
|
-
const call = { callId: item.call_id ?? item.id ?? "", name: item.name ?? "", arguments: item.arguments ?? "" };
|
|
16008
|
+
const call = { callId: item.call_id ?? item.id ?? "", name: item.name ?? "", arguments: item.arguments ?? "", index: calls.size };
|
|
15763
16009
|
calls.set(item.id ?? call.callId, call);
|
|
15764
|
-
yield { id, model, delta: { toolCalls: [{ id: call.callId, name: call.name, arguments: call.arguments }] } };
|
|
16010
|
+
yield { id, model, delta: { toolCalls: [{ id: call.callId, name: call.name, arguments: call.arguments, index: call.index }] } };
|
|
15765
16011
|
break;
|
|
15766
16012
|
}
|
|
15767
16013
|
case "response.function_call_arguments.delta": {
|
|
15768
16014
|
const call = calls.get(data.item_id);
|
|
15769
16015
|
if (!call || !data.delta) break;
|
|
15770
16016
|
call.arguments += data.delta;
|
|
15771
|
-
yield { id, model, delta: { toolCalls: [{ id: call.callId, arguments: data.delta }] } };
|
|
16017
|
+
yield { id, model, delta: { toolCalls: [{ id: call.callId, arguments: data.delta, index: call.index }] } };
|
|
15772
16018
|
break;
|
|
15773
16019
|
}
|
|
15774
16020
|
case "response.output_item.done": {
|
|
@@ -15777,13 +16023,13 @@ var OpenAIProvider = class _OpenAIProvider extends BaseProvider {
|
|
|
15777
16023
|
const full = typeof item.arguments === "string" ? item.arguments : "";
|
|
15778
16024
|
const call = calls.get(item.id ?? item.call_id);
|
|
15779
16025
|
if (!call) {
|
|
15780
|
-
const added = { callId: item.call_id ?? item.id ?? "", name: item.name ?? "", arguments: full };
|
|
16026
|
+
const added = { callId: item.call_id ?? item.id ?? "", name: item.name ?? "", arguments: full, index: calls.size };
|
|
15781
16027
|
calls.set(item.id ?? added.callId, added);
|
|
15782
|
-
yield { id, model, delta: { toolCalls: [{ id: added.callId, name: added.name, arguments: full }] } };
|
|
16028
|
+
yield { id, model, delta: { toolCalls: [{ id: added.callId, name: added.name, arguments: full, index: added.index }] } };
|
|
15783
16029
|
} else if (full.length > call.arguments.length && full.startsWith(call.arguments)) {
|
|
15784
16030
|
const rest = full.slice(call.arguments.length);
|
|
15785
16031
|
call.arguments = full;
|
|
15786
|
-
yield { id, model, delta: { toolCalls: [{ id: call.callId, arguments: rest }] } };
|
|
16032
|
+
yield { id, model, delta: { toolCalls: [{ id: call.callId, arguments: rest, index: call.index }] } };
|
|
15787
16033
|
}
|
|
15788
16034
|
break;
|
|
15789
16035
|
}
|
|
@@ -15806,7 +16052,8 @@ var OpenAIProvider = class _OpenAIProvider extends BaseProvider {
|
|
|
15806
16052
|
yield {
|
|
15807
16053
|
id: final?.id || id,
|
|
15808
16054
|
model: final?.model || model,
|
|
15809
|
-
|
|
16055
|
+
// Summary text already went out as deltas; do not repeat it.
|
|
16056
|
+
delta: final?.reasoning && !streamedSummary ? { reasoning: final.reasoning } : {},
|
|
15810
16057
|
usage: final?.usage,
|
|
15811
16058
|
finishReason: final?.finishReason ?? (calls.size > 0 ? "tool_calls" : "stop")
|
|
15812
16059
|
};
|
|
@@ -15916,7 +16163,7 @@ var OpenAIProvider = class _OpenAIProvider extends BaseProvider {
|
|
|
15916
16163
|
...this.defaultHeaders
|
|
15917
16164
|
};
|
|
15918
16165
|
const payload = JSON.stringify(body);
|
|
15919
|
-
const res = await this.doFetchWithRetry(() =>
|
|
16166
|
+
const res = await this.doFetchWithRetry(() => this.httpFetch(url, { method: "POST", headers, body: payload, signal }), signal);
|
|
15920
16167
|
if (!res.ok) {
|
|
15921
16168
|
const text = await res.text().catch(() => "");
|
|
15922
16169
|
throw new ProviderError(
|
|
@@ -16045,7 +16292,7 @@ var OpenAIProvider = class _OpenAIProvider extends BaseProvider {
|
|
|
16045
16292
|
...this.defaultHeaders
|
|
16046
16293
|
};
|
|
16047
16294
|
const payload = JSON.stringify(body);
|
|
16048
|
-
const res = await this.doFetchWithRetry(() =>
|
|
16295
|
+
const res = await this.doFetchWithRetry(() => this.httpFetch(url, { method: "POST", headers, body: payload, signal }), signal);
|
|
16049
16296
|
if (!res.ok) {
|
|
16050
16297
|
const text = await res.text().catch(() => "");
|
|
16051
16298
|
throw new ProviderError(
|
|
@@ -16065,6 +16312,8 @@ var OpenAIProvider = class _OpenAIProvider extends BaseProvider {
|
|
|
16065
16312
|
name: tc.function?.name ?? "",
|
|
16066
16313
|
arguments: tc.function?.arguments ?? "{}"
|
|
16067
16314
|
}));
|
|
16315
|
+
const reasoningText = extractReasoningText(message);
|
|
16316
|
+
const providerFields = pickProviderFields(json, message, choice);
|
|
16068
16317
|
return {
|
|
16069
16318
|
id: json.id ?? "",
|
|
16070
16319
|
model: json.model ?? "",
|
|
@@ -16072,6 +16321,9 @@ var OpenAIProvider = class _OpenAIProvider extends BaseProvider {
|
|
|
16072
16321
|
toolCalls,
|
|
16073
16322
|
usage: this.extractUsage(json.usage),
|
|
16074
16323
|
finishReason: mapFinishReason(choice?.finish_reason),
|
|
16324
|
+
...typeof choice?.finish_reason === "string" ? { rawFinishReason: choice.finish_reason } : {},
|
|
16325
|
+
...providerFields ? { providerFields } : {},
|
|
16326
|
+
...reasoningText ? { reasoning: { summary: reasoningText } } : {},
|
|
16075
16327
|
raw: json
|
|
16076
16328
|
};
|
|
16077
16329
|
}
|
|
@@ -16090,6 +16342,23 @@ var OpenAIProvider = class _OpenAIProvider extends BaseProvider {
|
|
|
16090
16342
|
};
|
|
16091
16343
|
}
|
|
16092
16344
|
};
|
|
16345
|
+
function extractReasoningText(src) {
|
|
16346
|
+
if (!src || typeof src !== "object") return void 0;
|
|
16347
|
+
for (const key of ["reasoning_content", "reasoning"]) {
|
|
16348
|
+
const v = src[key];
|
|
16349
|
+
if (typeof v === "string" && v.length > 0) return v;
|
|
16350
|
+
}
|
|
16351
|
+
return void 0;
|
|
16352
|
+
}
|
|
16353
|
+
function pickProviderFields(top, message, choice) {
|
|
16354
|
+
const out = {};
|
|
16355
|
+
if (top?.system_fingerprint != null) out.system_fingerprint = top.system_fingerprint;
|
|
16356
|
+
if (top?.service_tier != null) out.service_tier = top.service_tier;
|
|
16357
|
+
if (message?.annotations != null) out.annotations = message.annotations;
|
|
16358
|
+
if (message?.refusal != null) out.refusal = message.refusal;
|
|
16359
|
+
if (choice?.logprobs != null) out.logprobs = choice.logprobs;
|
|
16360
|
+
return Object.keys(out).length > 0 ? out : void 0;
|
|
16361
|
+
}
|
|
16093
16362
|
function isReasoningModel(model) {
|
|
16094
16363
|
if (!model) return false;
|
|
16095
16364
|
const m = model.toLowerCase();
|
|
@@ -16166,36 +16435,86 @@ function mapFinishReason(reason) {
|
|
|
16166
16435
|
}
|
|
16167
16436
|
}
|
|
16168
16437
|
|
|
16438
|
+
// src/providers/utils/toolChoice.ts
|
|
16439
|
+
function supportsForcedToolChoice(model) {
|
|
16440
|
+
if (typeof model !== "string") return true;
|
|
16441
|
+
const id = model.toLowerCase();
|
|
16442
|
+
const at = id.indexOf("claude-");
|
|
16443
|
+
if (at < 0) return true;
|
|
16444
|
+
const toks = id.slice(at + 7).split("-");
|
|
16445
|
+
let family = false;
|
|
16446
|
+
for (const tok of toks) {
|
|
16447
|
+
if (tok === "sonnet" || tok === "opus") {
|
|
16448
|
+
family = true;
|
|
16449
|
+
continue;
|
|
16450
|
+
}
|
|
16451
|
+
const m = /^(\d+)(?:@|:|$)/.exec(tok);
|
|
16452
|
+
if (m) {
|
|
16453
|
+
if (m[1].length > 2) continue;
|
|
16454
|
+
if (Number(m[1]) < 5) return true;
|
|
16455
|
+
if (family) return false;
|
|
16456
|
+
return !toks.some((t) => t === "sonnet" || t === "opus");
|
|
16457
|
+
}
|
|
16458
|
+
}
|
|
16459
|
+
return true;
|
|
16460
|
+
}
|
|
16461
|
+
function forcedToolChoiceRejected(text) {
|
|
16462
|
+
const t = text.toLowerCase();
|
|
16463
|
+
return t.indexOf("tool_choice") >= 0 && t.indexOf("not supported for this model") >= 0;
|
|
16464
|
+
}
|
|
16465
|
+
|
|
16169
16466
|
// src/providers/anthropic.ts
|
|
16467
|
+
var DEFAULT_MAX_TOKENS = 4096;
|
|
16468
|
+
function normalizeExplicitThinking(body) {
|
|
16469
|
+
const t = body.thinking;
|
|
16470
|
+
if (t == null) {
|
|
16471
|
+
delete body.thinking;
|
|
16472
|
+
return;
|
|
16473
|
+
}
|
|
16474
|
+
if (t.type !== "enabled") return;
|
|
16475
|
+
const budget = typeof t.budget_tokens === "number" ? t.budget_tokens : 0;
|
|
16476
|
+
if (budget > 0 && (typeof body.max_tokens !== "number" || body.max_tokens <= budget)) {
|
|
16477
|
+
body.max_tokens = budget + 1024;
|
|
16478
|
+
}
|
|
16479
|
+
for (const k of ["temperature", "top_p", "top_k"]) delete body[k];
|
|
16480
|
+
}
|
|
16481
|
+
function thinkingFormRejected(text) {
|
|
16482
|
+
const t = text.toLowerCase();
|
|
16483
|
+
if (t.indexOf("thinking.type.enabled") >= 0 && t.indexOf("not supported") >= 0) return "enabled";
|
|
16484
|
+
if (t.indexOf("thinking.type.adaptive") >= 0 && t.indexOf("not supported") >= 0 && t.indexOf("thinking.type.enabled") < 0) return "adaptive";
|
|
16485
|
+
return void 0;
|
|
16486
|
+
}
|
|
16170
16487
|
var AnthropicProvider = class extends BaseProvider {
|
|
16171
16488
|
constructor(config) {
|
|
16172
16489
|
super();
|
|
16173
16490
|
this.providerName = "anthropic";
|
|
16491
|
+
this.configureTransport(config);
|
|
16174
16492
|
this.apiKey = config.apiKey;
|
|
16175
16493
|
this.baseURL = (config.baseURL ?? "https://api.anthropic.com").replace(/\/$/, "");
|
|
16176
16494
|
this.defaultModel = config.defaultModel ?? "claude-sonnet-4-20250514";
|
|
16177
16495
|
this.defaultHeaders = config.defaultHeaders ?? {};
|
|
16178
16496
|
this.anthropicVersion = config.anthropicVersion ?? "2023-06-01";
|
|
16497
|
+
this.thinkingMode = config.thinkingMode ?? "auto";
|
|
16179
16498
|
this.promptCachingEnabled = config.prompt_caching?.enabled === true;
|
|
16180
16499
|
if (config.retry) this.retryPolicy = { ...this.retryPolicy, ...config.retry };
|
|
16181
16500
|
}
|
|
16182
16501
|
async complete(request) {
|
|
16183
|
-
const
|
|
16184
|
-
const res = await this.doFetch(body, request.signal);
|
|
16502
|
+
const res = await this.send(request, false);
|
|
16185
16503
|
const json = await res.json();
|
|
16186
16504
|
return this.parseResponse(json);
|
|
16187
16505
|
}
|
|
16188
16506
|
async *completeStream(request) {
|
|
16189
|
-
const
|
|
16190
|
-
const res = await this.doFetch(body, request.signal);
|
|
16507
|
+
const res = await this.send(request, true);
|
|
16191
16508
|
if (!res.body) throw new ProviderError("No response body for stream", this.providerName);
|
|
16192
16509
|
let id = "";
|
|
16193
16510
|
let model = "";
|
|
16194
16511
|
let inputTokens = 0;
|
|
16195
16512
|
let outputTokens = 0;
|
|
16513
|
+
let thinkingTokens = 0;
|
|
16196
16514
|
let cacheReadInputTokens = 0;
|
|
16197
16515
|
let cacheCreationInputTokens = 0;
|
|
16198
16516
|
const currentToolCalls = /* @__PURE__ */ new Map();
|
|
16517
|
+
let toolOrdinal = 0;
|
|
16199
16518
|
const reasoningBlocks = /* @__PURE__ */ new Map();
|
|
16200
16519
|
for await (const event of parseSSEStream(res.body, request.signal)) {
|
|
16201
16520
|
let data;
|
|
@@ -16224,8 +16543,11 @@ var AnthropicProvider = class extends BaseProvider {
|
|
|
16224
16543
|
currentToolCalls.set(idx, {
|
|
16225
16544
|
id: block.id ?? "",
|
|
16226
16545
|
name: block.name ?? "",
|
|
16227
|
-
arguments: ""
|
|
16546
|
+
arguments: "",
|
|
16547
|
+
ordinal: toolOrdinal++
|
|
16228
16548
|
});
|
|
16549
|
+
const opened = currentToolCalls.get(idx);
|
|
16550
|
+
yield { id, model, delta: { toolCalls: [{ id: opened.id, name: opened.name, arguments: "", index: opened.ordinal }] } };
|
|
16229
16551
|
} else if (block?.type === "thinking") {
|
|
16230
16552
|
reasoningBlocks.set(idx, { type: "thinking", text: block.thinking ?? "", signature: block.signature });
|
|
16231
16553
|
} else if (block?.type === "redacted_thinking") {
|
|
@@ -16263,7 +16585,7 @@ var AnthropicProvider = class extends BaseProvider {
|
|
|
16263
16585
|
id,
|
|
16264
16586
|
model,
|
|
16265
16587
|
delta: {
|
|
16266
|
-
toolCalls: [{ id: tc.id, name: tc.name, arguments: delta.partial_json }]
|
|
16588
|
+
toolCalls: [{ id: tc.id, name: tc.name, arguments: delta.partial_json, index: tc.ordinal }]
|
|
16267
16589
|
}
|
|
16268
16590
|
};
|
|
16269
16591
|
}
|
|
@@ -16276,8 +16598,10 @@ var AnthropicProvider = class extends BaseProvider {
|
|
|
16276
16598
|
const delta = data.delta;
|
|
16277
16599
|
if (data.usage) {
|
|
16278
16600
|
outputTokens = data.usage.output_tokens ?? outputTokens;
|
|
16601
|
+
thinkingTokens = data.usage.output_tokens_details?.thinking_tokens ?? thinkingTokens;
|
|
16279
16602
|
}
|
|
16280
16603
|
const finishReason = mapAnthropicStopReason(delta?.stop_reason);
|
|
16604
|
+
const rawFinishReason = typeof delta?.stop_reason === "string" ? delta.stop_reason : void 0;
|
|
16281
16605
|
const usage = {
|
|
16282
16606
|
inputTokens,
|
|
16283
16607
|
outputTokens,
|
|
@@ -16285,7 +16609,7 @@ var AnthropicProvider = class extends BaseProvider {
|
|
|
16285
16609
|
cachedInputTokens: cacheReadInputTokens,
|
|
16286
16610
|
cachedWriteTokens: cacheCreationInputTokens,
|
|
16287
16611
|
cachedOutputTokens: 0,
|
|
16288
|
-
reasoningTokens:
|
|
16612
|
+
reasoningTokens: thinkingTokens
|
|
16289
16613
|
};
|
|
16290
16614
|
const blocks = [...reasoningBlocks.values()].filter(
|
|
16291
16615
|
(b) => b.type === "thinking" && b.signature || b.type === "redacted_thinking" && b.data
|
|
@@ -16295,6 +16619,7 @@ var AnthropicProvider = class extends BaseProvider {
|
|
|
16295
16619
|
model,
|
|
16296
16620
|
delta: blocks.length > 0 ? { reasoning: { blocks } } : {},
|
|
16297
16621
|
finishReason,
|
|
16622
|
+
...rawFinishReason ? { rawFinishReason } : {},
|
|
16298
16623
|
usage
|
|
16299
16624
|
};
|
|
16300
16625
|
break;
|
|
@@ -16309,12 +16634,12 @@ var AnthropicProvider = class extends BaseProvider {
|
|
|
16309
16634
|
}
|
|
16310
16635
|
}
|
|
16311
16636
|
// ─── Internals ───────────────────────────────────────────────────────────
|
|
16312
|
-
buildRequestBody(request, stream) {
|
|
16637
|
+
buildRequestBody(request, stream, modeOverride, downgradeToolChoice = false) {
|
|
16313
16638
|
const { system, messages } = this.splitSystemMessages(request.messages);
|
|
16314
16639
|
const body = {
|
|
16315
16640
|
model: request.model || this.defaultModel,
|
|
16316
16641
|
messages: this.toAnthropicMessages(messages),
|
|
16317
|
-
max_tokens: request.maxTokens ??
|
|
16642
|
+
max_tokens: request.maxTokens ?? DEFAULT_MAX_TOKENS,
|
|
16318
16643
|
stream
|
|
16319
16644
|
};
|
|
16320
16645
|
if (system) {
|
|
@@ -16335,18 +16660,27 @@ var AnthropicProvider = class extends BaseProvider {
|
|
|
16335
16660
|
body.tools = tools;
|
|
16336
16661
|
}
|
|
16337
16662
|
if (request.toolChoice != null) {
|
|
16663
|
+
const forceOk = !downgradeToolChoice && supportsForcedToolChoice(body.model);
|
|
16338
16664
|
if (request.toolChoice === "auto") {
|
|
16339
16665
|
body.tool_choice = { type: "auto" };
|
|
16340
16666
|
} else if (request.toolChoice === "required") {
|
|
16341
|
-
body.tool_choice = { type: "any" };
|
|
16667
|
+
body.tool_choice = forceOk ? { type: "any" } : { type: "auto" };
|
|
16342
16668
|
} else if (request.toolChoice === "none") ; else {
|
|
16343
|
-
body.tool_choice = { type: "tool", name: request.toolChoice.name };
|
|
16669
|
+
body.tool_choice = forceOk ? { type: "tool", name: request.toolChoice.name } : { type: "auto" };
|
|
16344
16670
|
}
|
|
16345
16671
|
}
|
|
16346
16672
|
if (request.extra) {
|
|
16347
16673
|
Object.assign(body, request.extra);
|
|
16348
16674
|
}
|
|
16349
|
-
|
|
16675
|
+
const explicitThinking = request.extra && typeof request.extra === "object" && "thinking" in request.extra;
|
|
16676
|
+
if (explicitThinking) {
|
|
16677
|
+
normalizeExplicitThinking(body);
|
|
16678
|
+
} else {
|
|
16679
|
+
applyAnthropicReasoning(body, request.reasoning, { model: body.model, mode: modeOverride ?? this.thinkingMode });
|
|
16680
|
+
}
|
|
16681
|
+
if (typeof body.max_tokens !== "number" || !(body.max_tokens > 0)) {
|
|
16682
|
+
body.max_tokens = DEFAULT_MAX_TOKENS;
|
|
16683
|
+
}
|
|
16350
16684
|
return body;
|
|
16351
16685
|
}
|
|
16352
16686
|
splitSystemMessages(messages) {
|
|
@@ -16477,6 +16811,34 @@ var AnthropicProvider = class extends BaseProvider {
|
|
|
16477
16811
|
input_schema: t.parameters
|
|
16478
16812
|
};
|
|
16479
16813
|
}
|
|
16814
|
+
/** Builds and sends the request; retries once with the other thinking form
|
|
16815
|
+
* when the upstream rejects the one we picked. */
|
|
16816
|
+
async send(request, stream) {
|
|
16817
|
+
let mode;
|
|
16818
|
+
let downgrade = false;
|
|
16819
|
+
let flippedThinking = false;
|
|
16820
|
+
for (; ; ) {
|
|
16821
|
+
const body = this.buildRequestBody(request, stream, mode, downgrade);
|
|
16822
|
+
try {
|
|
16823
|
+
return await this.doFetch(body, request.signal);
|
|
16824
|
+
} catch (err) {
|
|
16825
|
+
if (!(err instanceof ProviderError) || err.statusCode !== 400) throw err;
|
|
16826
|
+
const text = String(err.responseBody ?? err.message);
|
|
16827
|
+
if (!downgrade && body.tool_choice && body.tool_choice.type !== "auto" && forcedToolChoiceRejected(text)) {
|
|
16828
|
+
downgrade = true;
|
|
16829
|
+
continue;
|
|
16830
|
+
}
|
|
16831
|
+
const explicit = request.extra && typeof request.extra === "object" && "thinking" in request.extra;
|
|
16832
|
+
if (flippedThinking || explicit || !request.reasoning) throw err;
|
|
16833
|
+
const wrong = thinkingFormRejected(text);
|
|
16834
|
+
if (!wrong) throw err;
|
|
16835
|
+
const used = resolveThinkingForm(request.model ?? this.defaultModel, this.thinkingMode);
|
|
16836
|
+
if (wrong === "enabled" && used !== "budget" || wrong === "adaptive" && used !== "adaptive") throw err;
|
|
16837
|
+
mode = wrong === "enabled" ? "adaptive" : "budget";
|
|
16838
|
+
flippedThinking = true;
|
|
16839
|
+
}
|
|
16840
|
+
}
|
|
16841
|
+
}
|
|
16480
16842
|
async doFetch(body, signal) {
|
|
16481
16843
|
const url = `${this.baseURL}/v1/messages`;
|
|
16482
16844
|
const headers = {
|
|
@@ -16486,7 +16848,7 @@ var AnthropicProvider = class extends BaseProvider {
|
|
|
16486
16848
|
...this.defaultHeaders
|
|
16487
16849
|
};
|
|
16488
16850
|
const payload = JSON.stringify(body);
|
|
16489
|
-
const res = await this.doFetchWithRetry(() =>
|
|
16851
|
+
const res = await this.doFetchWithRetry(() => this.httpFetch(url, { method: "POST", headers, body: payload, signal }), signal);
|
|
16490
16852
|
if (!res.ok) {
|
|
16491
16853
|
const text = await res.text().catch(() => "");
|
|
16492
16854
|
throw new ProviderError(
|
|
@@ -16531,10 +16893,9 @@ var AnthropicProvider = class extends BaseProvider {
|
|
|
16531
16893
|
cachedInputTokens: usage.cache_read_input_tokens ?? 0,
|
|
16532
16894
|
cachedWriteTokens: usage.cache_creation_input_tokens ?? 0,
|
|
16533
16895
|
cachedOutputTokens: 0,
|
|
16534
|
-
//
|
|
16535
|
-
//
|
|
16536
|
-
|
|
16537
|
-
reasoningTokens: 0
|
|
16896
|
+
// Thinking tokens are billed inside `output_tokens`; newer models also
|
|
16897
|
+
// report the split as `output_tokens_details.thinking_tokens`.
|
|
16898
|
+
reasoningTokens: usage.output_tokens_details?.thinking_tokens ?? 0
|
|
16538
16899
|
};
|
|
16539
16900
|
return {
|
|
16540
16901
|
id: json.id ?? "",
|
|
@@ -16543,6 +16904,7 @@ var AnthropicProvider = class extends BaseProvider {
|
|
|
16543
16904
|
toolCalls,
|
|
16544
16905
|
usage: tokenUsage,
|
|
16545
16906
|
finishReason: mapAnthropicStopReason(json.stop_reason),
|
|
16907
|
+
...typeof json.stop_reason === "string" ? { rawFinishReason: json.stop_reason } : {},
|
|
16546
16908
|
reasoning: reasoningBlocks.length > 0 ? { blocks: reasoningBlocks, summary: summaryParts.join("\n").trim() || void 0 } : void 0,
|
|
16547
16909
|
raw: json
|
|
16548
16910
|
};
|
|
@@ -16588,7 +16950,15 @@ var AzureProvider = class extends OpenAIProvider {
|
|
|
16588
16950
|
provider: "openai",
|
|
16589
16951
|
apiKey: config.apiKey,
|
|
16590
16952
|
defaultModel: config.defaultModel ?? config.deploymentName ?? "gpt-4o",
|
|
16591
|
-
defaultHeaders: config.defaultHeaders
|
|
16953
|
+
defaultHeaders: config.defaultHeaders,
|
|
16954
|
+
retry: config.retry,
|
|
16955
|
+
fetch: config.fetch,
|
|
16956
|
+
timeoutMs: config.timeoutMs,
|
|
16957
|
+
maxTokensParam: config.maxTokensParam,
|
|
16958
|
+
api: config.api,
|
|
16959
|
+
responsesApi: config.responsesApi,
|
|
16960
|
+
responsesApiModels: config.responsesApiModels,
|
|
16961
|
+
responsesStreaming: config.responsesStreaming
|
|
16592
16962
|
});
|
|
16593
16963
|
this.providerName = "azure";
|
|
16594
16964
|
this.endpoint = config.endpoint.replace(/\/$/, "");
|
|
@@ -16603,16 +16973,17 @@ var AzureProvider = class extends OpenAIProvider {
|
|
|
16603
16973
|
}
|
|
16604
16974
|
const url = `${this.endpoint}/openai/deployments/${deployment}/chat/completions?api-version=${this.apiVersion}`;
|
|
16605
16975
|
const { model: _model, ...bodyWithoutModel } = body;
|
|
16606
|
-
const
|
|
16976
|
+
const payload = JSON.stringify(bodyWithoutModel);
|
|
16977
|
+
const res = await this.doFetchWithRetry(() => this.httpFetch(url, {
|
|
16607
16978
|
method: "POST",
|
|
16608
16979
|
headers: {
|
|
16609
16980
|
"Content-Type": "application/json",
|
|
16610
16981
|
"api-key": this.azureApiKey,
|
|
16611
16982
|
...this.defaultHeaders
|
|
16612
16983
|
},
|
|
16613
|
-
body:
|
|
16984
|
+
body: payload,
|
|
16614
16985
|
signal
|
|
16615
|
-
});
|
|
16986
|
+
}), signal);
|
|
16616
16987
|
if (!res.ok) {
|
|
16617
16988
|
const text = await res.text().catch(() => "");
|
|
16618
16989
|
throw new ProviderError(
|
|
@@ -16624,6 +16995,32 @@ var AzureProvider = class extends OpenAIProvider {
|
|
|
16624
16995
|
}
|
|
16625
16996
|
return res;
|
|
16626
16997
|
}
|
|
16998
|
+
/** Azure embeddings: the deployment named by the request's model (falling back
|
|
16999
|
+
* to the configured deployment) in the path, api-key auth. */
|
|
17000
|
+
async embeddingsFetch(body, signal) {
|
|
17001
|
+
const deployment = body.model || this.deploymentName;
|
|
17002
|
+
if (!deployment) {
|
|
17003
|
+
throw new ProviderError("Azure embeddings require a deployment name or model", this.providerName, 400);
|
|
17004
|
+
}
|
|
17005
|
+
const url = `${this.endpoint}/openai/deployments/${deployment}/embeddings?api-version=${this.apiVersion}`;
|
|
17006
|
+
const { model: _model, ...bodyWithoutModel } = body;
|
|
17007
|
+
const payload = JSON.stringify(bodyWithoutModel);
|
|
17008
|
+
const res = await this.doFetchWithRetry(() => this.httpFetch(url, {
|
|
17009
|
+
method: "POST",
|
|
17010
|
+
headers: {
|
|
17011
|
+
"Content-Type": "application/json",
|
|
17012
|
+
"api-key": this.azureApiKey,
|
|
17013
|
+
...this.defaultHeaders
|
|
17014
|
+
},
|
|
17015
|
+
body: payload,
|
|
17016
|
+
signal
|
|
17017
|
+
}), signal);
|
|
17018
|
+
if (!res.ok) {
|
|
17019
|
+
const text = await res.text().catch(() => "");
|
|
17020
|
+
throw new ProviderError(`Azure OpenAI embeddings API error ${res.status}: ${text}`, this.providerName, res.status, text);
|
|
17021
|
+
}
|
|
17022
|
+
return res;
|
|
17023
|
+
}
|
|
16627
17024
|
/** Azure exposes the Responses API at /openai/responses with api-key auth.
|
|
16628
17025
|
* Reasoning summaries require a preview api-version; callers can override via
|
|
16629
17026
|
* the `apiVersion` config. */
|
|
@@ -16635,7 +17032,7 @@ var AzureProvider = class extends OpenAIProvider {
|
|
|
16635
17032
|
}
|
|
16636
17033
|
const url = `${this.endpoint}/openai/responses?api-version=${this.apiVersion}`;
|
|
16637
17034
|
const payload = JSON.stringify({ ...body, model: deployment });
|
|
16638
|
-
const res = await
|
|
17035
|
+
const res = await this.doFetchWithRetry(() => this.httpFetch(url, {
|
|
16639
17036
|
method: "POST",
|
|
16640
17037
|
headers: {
|
|
16641
17038
|
"Content-Type": "application/json",
|
|
@@ -16644,7 +17041,7 @@ var AzureProvider = class extends OpenAIProvider {
|
|
|
16644
17041
|
},
|
|
16645
17042
|
body: payload,
|
|
16646
17043
|
signal
|
|
16647
|
-
});
|
|
17044
|
+
}), signal);
|
|
16648
17045
|
if (!res.ok) {
|
|
16649
17046
|
const text = await res.text().catch(() => "");
|
|
16650
17047
|
throw new ProviderError(
|
|
@@ -16680,20 +17077,155 @@ var OpenAICompatibleProvider = class extends OpenAIProvider {
|
|
|
16680
17077
|
apiKey: config.apiKey,
|
|
16681
17078
|
baseURL: config.baseURL,
|
|
16682
17079
|
defaultModel: config.defaultModel,
|
|
16683
|
-
defaultHeaders: config.defaultHeaders
|
|
17080
|
+
defaultHeaders: config.defaultHeaders,
|
|
17081
|
+
organization: config.organization,
|
|
17082
|
+
retry: config.retry,
|
|
17083
|
+
fetch: config.fetch,
|
|
17084
|
+
timeoutMs: config.timeoutMs,
|
|
17085
|
+
maxTokensParam: config.maxTokensParam,
|
|
17086
|
+
api: config.api,
|
|
17087
|
+
// Unlike OpenAI / Azure, "auto" on a compatible server means Chat
|
|
17088
|
+
// Completions (the 0.11 default): the model name is the operator's.
|
|
17089
|
+
// `responsesApiModels` still applies; `responsesApi: "auto"` opts in.
|
|
17090
|
+
_autoMeansChat: true,
|
|
17091
|
+
responsesApi: config.responsesApi,
|
|
17092
|
+
responsesApiModels: config.responsesApiModels,
|
|
17093
|
+
responsesStreaming: config.responsesStreaming
|
|
16684
17094
|
});
|
|
16685
17095
|
this.providerName = "openai-compatible";
|
|
16686
17096
|
}
|
|
16687
17097
|
};
|
|
16688
17098
|
|
|
17099
|
+
// src/providers/utils/eventStream.ts
|
|
17100
|
+
var EventStreamError = class extends Error {
|
|
17101
|
+
constructor(message) {
|
|
17102
|
+
super(message);
|
|
17103
|
+
this.name = "EventStreamError";
|
|
17104
|
+
}
|
|
17105
|
+
};
|
|
17106
|
+
var CRC_TABLE = (() => {
|
|
17107
|
+
const table = new Uint32Array(256);
|
|
17108
|
+
for (let n = 0; n < 256; n++) {
|
|
17109
|
+
let c = n;
|
|
17110
|
+
for (let k = 0; k < 8; k++) c = c & 1 ? 3988292384 ^ c >>> 1 : c >>> 1;
|
|
17111
|
+
table[n] = c >>> 0;
|
|
17112
|
+
}
|
|
17113
|
+
return table;
|
|
17114
|
+
})();
|
|
17115
|
+
function crc32(bytes, start = 0, end = bytes.length) {
|
|
17116
|
+
let c = 4294967295;
|
|
17117
|
+
for (let i = start; i < end; i++) c = CRC_TABLE[(c ^ bytes[i]) & 255] ^ c >>> 8;
|
|
17118
|
+
return (c ^ 4294967295) >>> 0;
|
|
17119
|
+
}
|
|
17120
|
+
function decodeFrame(frame) {
|
|
17121
|
+
const view = new DataView(frame.buffer, frame.byteOffset, frame.byteLength);
|
|
17122
|
+
const total = view.getUint32(0);
|
|
17123
|
+
const headersLen = view.getUint32(4);
|
|
17124
|
+
if (total !== frame.byteLength) throw new EventStreamError("event-stream frame length mismatch");
|
|
17125
|
+
if (crc32(frame, 0, 8) !== view.getUint32(8)) throw new EventStreamError("event-stream prelude CRC mismatch");
|
|
17126
|
+
if (crc32(frame, 0, total - 4) !== view.getUint32(total - 4)) throw new EventStreamError("event-stream message CRC mismatch");
|
|
17127
|
+
if (12 + headersLen > total - 4) throw new EventStreamError("event-stream headers overflow frame");
|
|
17128
|
+
const headers = {};
|
|
17129
|
+
const td = new TextDecoder();
|
|
17130
|
+
let o = 12;
|
|
17131
|
+
const headersEnd = 12 + headersLen;
|
|
17132
|
+
while (o < headersEnd) {
|
|
17133
|
+
const nameLen = frame[o++];
|
|
17134
|
+
const name = td.decode(frame.subarray(o, o + nameLen));
|
|
17135
|
+
o += nameLen;
|
|
17136
|
+
const type = frame[o++];
|
|
17137
|
+
switch (type) {
|
|
17138
|
+
case 0:
|
|
17139
|
+
headers[name] = true;
|
|
17140
|
+
break;
|
|
17141
|
+
case 1:
|
|
17142
|
+
headers[name] = false;
|
|
17143
|
+
break;
|
|
17144
|
+
case 2:
|
|
17145
|
+
headers[name] = view.getInt8(o);
|
|
17146
|
+
o += 1;
|
|
17147
|
+
break;
|
|
17148
|
+
case 3:
|
|
17149
|
+
headers[name] = view.getInt16(o);
|
|
17150
|
+
o += 2;
|
|
17151
|
+
break;
|
|
17152
|
+
case 4:
|
|
17153
|
+
headers[name] = view.getInt32(o);
|
|
17154
|
+
o += 4;
|
|
17155
|
+
break;
|
|
17156
|
+
case 5:
|
|
17157
|
+
headers[name] = view.getBigInt64(o);
|
|
17158
|
+
o += 8;
|
|
17159
|
+
break;
|
|
17160
|
+
case 6: {
|
|
17161
|
+
const len = view.getUint16(o);
|
|
17162
|
+
o += 2;
|
|
17163
|
+
headers[name] = frame.slice(o, o + len);
|
|
17164
|
+
o += len;
|
|
17165
|
+
break;
|
|
17166
|
+
}
|
|
17167
|
+
case 7: {
|
|
17168
|
+
const len = view.getUint16(o);
|
|
17169
|
+
o += 2;
|
|
17170
|
+
headers[name] = td.decode(frame.subarray(o, o + len));
|
|
17171
|
+
o += len;
|
|
17172
|
+
break;
|
|
17173
|
+
}
|
|
17174
|
+
case 8:
|
|
17175
|
+
headers[name] = view.getBigInt64(o);
|
|
17176
|
+
o += 8;
|
|
17177
|
+
break;
|
|
17178
|
+
case 9:
|
|
17179
|
+
headers[name] = frame.slice(o, o + 16);
|
|
17180
|
+
o += 16;
|
|
17181
|
+
break;
|
|
17182
|
+
default:
|
|
17183
|
+
throw new EventStreamError(`unknown event-stream header type ${type}`);
|
|
17184
|
+
}
|
|
17185
|
+
}
|
|
17186
|
+
return { headers, payload: frame.slice(headersEnd, total - 4) };
|
|
17187
|
+
}
|
|
17188
|
+
async function* parseEventStream(body, signal) {
|
|
17189
|
+
const reader = body.getReader();
|
|
17190
|
+
let buf = new Uint8Array(0);
|
|
17191
|
+
try {
|
|
17192
|
+
while (true) {
|
|
17193
|
+
if (signal?.aborted) throw abortReason(signal);
|
|
17194
|
+
const { done, value } = await reader.read();
|
|
17195
|
+
if (done) break;
|
|
17196
|
+
if (!value?.length) continue;
|
|
17197
|
+
const merged = new Uint8Array(buf.length + value.length);
|
|
17198
|
+
merged.set(buf, 0);
|
|
17199
|
+
merged.set(value, buf.length);
|
|
17200
|
+
buf = merged;
|
|
17201
|
+
while (buf.length >= 12) {
|
|
17202
|
+
const total = new DataView(buf.buffer, buf.byteOffset, buf.byteLength).getUint32(0);
|
|
17203
|
+
if (total < 16) throw new EventStreamError("invalid event-stream frame length");
|
|
17204
|
+
if (buf.length < total) break;
|
|
17205
|
+
yield decodeFrame(buf.subarray(0, total));
|
|
17206
|
+
buf = buf.subarray(total);
|
|
17207
|
+
}
|
|
17208
|
+
}
|
|
17209
|
+
if (buf.length > 0) throw new EventStreamError("event-stream ended inside a frame");
|
|
17210
|
+
} finally {
|
|
17211
|
+
reader.cancel().catch(() => void 0);
|
|
17212
|
+
try {
|
|
17213
|
+
reader.releaseLock();
|
|
17214
|
+
} catch {
|
|
17215
|
+
}
|
|
17216
|
+
}
|
|
17217
|
+
}
|
|
17218
|
+
|
|
16689
17219
|
// src/providers/bedrock.ts
|
|
16690
17220
|
var BedrockProvider = class extends BaseProvider {
|
|
16691
17221
|
constructor(config) {
|
|
16692
17222
|
super();
|
|
16693
17223
|
this.providerName = "bedrock";
|
|
17224
|
+
this.configureTransport(config);
|
|
16694
17225
|
this.region = config.region;
|
|
16695
17226
|
this.defaultModel = config.defaultModel ?? "anthropic.claude-sonnet-4-20250514-v1:0";
|
|
16696
17227
|
this.defaultHeaders = config.defaultHeaders ?? {};
|
|
17228
|
+
this.thinkingMode = config.thinkingMode ?? "auto";
|
|
16697
17229
|
this.promptCachingEnabled = config.prompt_caching?.enabled === true;
|
|
16698
17230
|
if (config.retry) this.retryPolicy = { ...this.retryPolicy, ...config.retry };
|
|
16699
17231
|
this.credentials = {
|
|
@@ -16710,25 +17242,202 @@ var BedrockProvider = class extends BaseProvider {
|
|
|
16710
17242
|
}
|
|
16711
17243
|
async complete(request) {
|
|
16712
17244
|
const modelId = request.model || this.defaultModel;
|
|
16713
|
-
const
|
|
16714
|
-
|
|
16715
|
-
return this.parseResponse(json, modelId);
|
|
17245
|
+
const res = await this.converseFetch(modelId, request, false);
|
|
17246
|
+
return this.parseResponse(await res.json(), modelId);
|
|
16716
17247
|
}
|
|
17248
|
+
/**
|
|
17249
|
+
* Real streaming over ConverseStream. The response is an AWS event-stream
|
|
17250
|
+
* (binary frames); each frame carries one JSON event: messageStart,
|
|
17251
|
+
* contentBlockStart/Delta/Stop (text, toolUse, reasoningContent),
|
|
17252
|
+
* messageStop and, last, metadata (usage). Text, tool-call argument and
|
|
17253
|
+
* reasoning deltas are yielded as they arrive; one closing chunk carries the
|
|
17254
|
+
* finish reason, usage and the signed reasoning blocks.
|
|
17255
|
+
*/
|
|
16717
17256
|
async *completeStream(request) {
|
|
16718
|
-
const
|
|
17257
|
+
const modelId = request.model || this.defaultModel;
|
|
17258
|
+
const res = await this.converseFetch(modelId, request, true);
|
|
17259
|
+
if (!res.body) throw new ProviderError("No response body for stream", this.providerName);
|
|
17260
|
+
const id = res.headers.get("x-amzn-requestid") ?? "";
|
|
17261
|
+
const toolsByIndex = /* @__PURE__ */ new Map();
|
|
17262
|
+
const reasoningByIndex = /* @__PURE__ */ new Map();
|
|
17263
|
+
let finishReason;
|
|
17264
|
+
let rawFinishReason;
|
|
17265
|
+
let toolOrdinal = 0;
|
|
17266
|
+
let usage;
|
|
17267
|
+
for await (const msg of parseEventStream(res.body, request.signal)) {
|
|
17268
|
+
const messageType = String(msg.headers[":message-type"] ?? "event");
|
|
17269
|
+
const eventType = String(msg.headers[":event-type"] ?? msg.headers[":exception-type"] ?? "");
|
|
17270
|
+
let data = {};
|
|
17271
|
+
const text = new TextDecoder().decode(msg.payload);
|
|
17272
|
+
if (text) {
|
|
17273
|
+
try {
|
|
17274
|
+
data = JSON.parse(text);
|
|
17275
|
+
} catch {
|
|
17276
|
+
data = { message: text };
|
|
17277
|
+
}
|
|
17278
|
+
}
|
|
17279
|
+
if (messageType === "exception" || messageType === "error") {
|
|
17280
|
+
const code = String(msg.headers[":exception-type"] ?? msg.headers[":error-code"] ?? eventType);
|
|
17281
|
+
throw new ProviderError(
|
|
17282
|
+
`Bedrock stream error ${code}: ${data.message ?? text}`,
|
|
17283
|
+
this.providerName,
|
|
17284
|
+
bedrockExceptionStatus(code),
|
|
17285
|
+
data
|
|
17286
|
+
);
|
|
17287
|
+
}
|
|
17288
|
+
switch (eventType) {
|
|
17289
|
+
case "contentBlockStart": {
|
|
17290
|
+
const idx = data.contentBlockIndex ?? 0;
|
|
17291
|
+
const tu = data.start?.toolUse;
|
|
17292
|
+
if (tu) {
|
|
17293
|
+
const ordinal = toolOrdinal++;
|
|
17294
|
+
toolsByIndex.set(idx, { id: tu.toolUseId ?? "", name: tu.name ?? "", ordinal });
|
|
17295
|
+
yield { id, model: modelId, delta: { toolCalls: [{ id: tu.toolUseId, name: tu.name, arguments: "", index: ordinal }] } };
|
|
17296
|
+
}
|
|
17297
|
+
break;
|
|
17298
|
+
}
|
|
17299
|
+
case "contentBlockDelta": {
|
|
17300
|
+
const idx = data.contentBlockIndex ?? 0;
|
|
17301
|
+
const d = data.delta ?? {};
|
|
17302
|
+
if (typeof d.text === "string" && d.text) {
|
|
17303
|
+
yield { id, model: modelId, delta: { content: d.text } };
|
|
17304
|
+
} else if (d.toolUse) {
|
|
17305
|
+
const tc = toolsByIndex.get(idx);
|
|
17306
|
+
if (tc && typeof d.toolUse.input === "string" && d.toolUse.input) {
|
|
17307
|
+
yield { id, model: modelId, delta: { toolCalls: [{ id: tc.id, name: tc.name, arguments: d.toolUse.input, index: tc.ordinal }] } };
|
|
17308
|
+
}
|
|
17309
|
+
} else if (d.reasoningContent) {
|
|
17310
|
+
const rc = d.reasoningContent;
|
|
17311
|
+
const blk = reasoningByIndex.get(idx) ?? { type: "thinking", text: "" };
|
|
17312
|
+
if (typeof rc.text === "string" && rc.text) {
|
|
17313
|
+
blk.text = (blk.text ?? "") + rc.text;
|
|
17314
|
+
reasoningByIndex.set(idx, blk);
|
|
17315
|
+
yield { id, model: modelId, delta: { reasoning: { summary: rc.text } } };
|
|
17316
|
+
}
|
|
17317
|
+
if (typeof rc.signature === "string" && rc.signature) {
|
|
17318
|
+
blk.signature = (blk.signature ?? "") + rc.signature;
|
|
17319
|
+
reasoningByIndex.set(idx, blk);
|
|
17320
|
+
}
|
|
17321
|
+
if (rc.redactedContent) {
|
|
17322
|
+
reasoningByIndex.set(idx, { type: "redacted_thinking", data: rc.redactedContent });
|
|
17323
|
+
}
|
|
17324
|
+
}
|
|
17325
|
+
break;
|
|
17326
|
+
}
|
|
17327
|
+
case "messageStop":
|
|
17328
|
+
finishReason = mapBedrockStopReason(data.stopReason);
|
|
17329
|
+
if (typeof data.stopReason === "string") rawFinishReason = data.stopReason;
|
|
17330
|
+
break;
|
|
17331
|
+
case "metadata": {
|
|
17332
|
+
const u = data.usage ?? {};
|
|
17333
|
+
usage = {
|
|
17334
|
+
inputTokens: u.inputTokens ?? 0,
|
|
17335
|
+
outputTokens: u.outputTokens ?? 0,
|
|
17336
|
+
totalTokens: u.totalTokens ?? (u.inputTokens ?? 0) + (u.outputTokens ?? 0),
|
|
17337
|
+
cachedInputTokens: u.cacheReadInputTokens ?? u.cacheReadInputTokenCount ?? 0,
|
|
17338
|
+
cachedWriteTokens: u.cacheWriteInputTokens ?? u.cacheWriteInputTokenCount ?? 0,
|
|
17339
|
+
cachedOutputTokens: 0,
|
|
17340
|
+
reasoningTokens: 0
|
|
17341
|
+
};
|
|
17342
|
+
break;
|
|
17343
|
+
}
|
|
17344
|
+
}
|
|
17345
|
+
}
|
|
17346
|
+
const blocks = [...reasoningByIndex.values()].filter(
|
|
17347
|
+
(b) => b.type === "thinking" && b.signature || b.type === "redacted_thinking" && b.data
|
|
17348
|
+
);
|
|
16719
17349
|
yield {
|
|
16720
|
-
id
|
|
16721
|
-
model:
|
|
16722
|
-
delta: {
|
|
16723
|
-
|
|
16724
|
-
|
|
16725
|
-
|
|
16726
|
-
usage: response.usage,
|
|
16727
|
-
finishReason: response.finishReason
|
|
17350
|
+
id,
|
|
17351
|
+
model: modelId,
|
|
17352
|
+
delta: blocks.length > 0 ? { reasoning: { blocks } } : {},
|
|
17353
|
+
finishReason: finishReason ?? "stop",
|
|
17354
|
+
...rawFinishReason ? { rawFinishReason } : {},
|
|
17355
|
+
usage
|
|
16728
17356
|
};
|
|
16729
17357
|
}
|
|
17358
|
+
// ─── Embeddings ──────────────────────────────────────────────────────────
|
|
17359
|
+
/**
|
|
17360
|
+
* InvokeModel embeddings. Supported families (by model id, inference-profile
|
|
17361
|
+
* prefixes such as `us.` allowed):
|
|
17362
|
+
* - Amazon Titan Text Embeddings (v1, v2): one text per call, `dimensions`
|
|
17363
|
+
* (v2: 256/512/1024) and `normalize` via `extra`.
|
|
17364
|
+
* - Cohere Embed (v3, v4): a batch of texts per call (default 96), `inputType`
|
|
17365
|
+
* maps to `input_type`, `dimensions` to `output_dimension` (v4).
|
|
17366
|
+
*/
|
|
17367
|
+
async embed(request) {
|
|
17368
|
+
const model = requireEmbeddingModel(this.providerName, request.model);
|
|
17369
|
+
const id = model.toLowerCase();
|
|
17370
|
+
const raw = [];
|
|
17371
|
+
let inputTokens = 0;
|
|
17372
|
+
let vectors = [];
|
|
17373
|
+
if (id.includes("titan-embed")) {
|
|
17374
|
+
const results = await mapWithConcurrency(request.input, 4, async (text) => {
|
|
17375
|
+
const body = { inputText: text };
|
|
17376
|
+
if (request.dimensions != null && !id.includes("titan-embed-text-v1")) body.dimensions = request.dimensions;
|
|
17377
|
+
if (request.extra) Object.assign(body, request.extra);
|
|
17378
|
+
const res = await this.invokeModel(model, body, request.signal);
|
|
17379
|
+
const json = await res.json();
|
|
17380
|
+
return { json, tokens: json.inputTextTokenCount ?? Number(res.headers.get("x-amzn-bedrock-input-token-count") ?? 0) };
|
|
17381
|
+
}, request.signal);
|
|
17382
|
+
for (const r of results) {
|
|
17383
|
+
raw.push(r.json);
|
|
17384
|
+
inputTokens += r.tokens || 0;
|
|
17385
|
+
vectors.push(r.json.embedding ?? r.json.embeddingsByType?.float);
|
|
17386
|
+
}
|
|
17387
|
+
} else if (id.includes("cohere.embed")) {
|
|
17388
|
+
for (const batch of chunkArray(request.input, request.batchSize ?? 96)) {
|
|
17389
|
+
const body = {
|
|
17390
|
+
texts: batch,
|
|
17391
|
+
input_type: request.inputType ?? "search_document",
|
|
17392
|
+
embedding_types: ["float"]
|
|
17393
|
+
};
|
|
17394
|
+
if (request.dimensions != null) body.output_dimension = request.dimensions;
|
|
17395
|
+
if (request.extra) Object.assign(body, request.extra);
|
|
17396
|
+
const res = await this.invokeModel(model, body, request.signal);
|
|
17397
|
+
const json = await res.json();
|
|
17398
|
+
raw.push(json);
|
|
17399
|
+
const emb = Array.isArray(json.embeddings) ? json.embeddings : json.embeddings?.float;
|
|
17400
|
+
vectors.push(...emb ?? []);
|
|
17401
|
+
inputTokens += Number(res.headers.get("x-amzn-bedrock-input-token-count") ?? 0) || 0;
|
|
17402
|
+
}
|
|
17403
|
+
} else {
|
|
17404
|
+
throw new ProviderError(
|
|
17405
|
+
`Bedrock embeddings are supported for Amazon Titan and Cohere Embed models, not "${model}"`,
|
|
17406
|
+
this.providerName,
|
|
17407
|
+
400
|
|
17408
|
+
);
|
|
17409
|
+
}
|
|
17410
|
+
assertVectorCount(this.providerName, vectors, request.input.length);
|
|
17411
|
+
return { model, vectors, usage: { inputTokens, totalTokens: inputTokens }, raw };
|
|
17412
|
+
}
|
|
17413
|
+
async invokeModel(modelId, body, signal) {
|
|
17414
|
+
const host = `bedrock-runtime.${this.region}.amazonaws.com`;
|
|
17415
|
+
const url = `https://${host}/model/${encodeURIComponent(modelId)}/invoke`;
|
|
17416
|
+
const bodyStr = JSON.stringify(body);
|
|
17417
|
+
const res = await this.doFetchWithRetry(() => {
|
|
17418
|
+
const headers = signRequest({
|
|
17419
|
+
method: "POST",
|
|
17420
|
+
url,
|
|
17421
|
+
headers: {
|
|
17422
|
+
"Content-Type": "application/json",
|
|
17423
|
+
Accept: "application/json",
|
|
17424
|
+
...this.defaultHeaders
|
|
17425
|
+
},
|
|
17426
|
+
body: bodyStr,
|
|
17427
|
+
region: this.region,
|
|
17428
|
+
service: "bedrock",
|
|
17429
|
+
credentials: this.credentials
|
|
17430
|
+
});
|
|
17431
|
+
return this.httpFetch(url, { method: "POST", headers, body: bodyStr, signal });
|
|
17432
|
+
}, signal);
|
|
17433
|
+
if (!res.ok) {
|
|
17434
|
+
const text = await res.text().catch(() => "");
|
|
17435
|
+
throw new ProviderError(`Bedrock API error ${res.status}: ${text}`, this.providerName, res.status, text);
|
|
17436
|
+
}
|
|
17437
|
+
return res;
|
|
17438
|
+
}
|
|
16730
17439
|
// ─── Internals ───────────────────────────────────────────────────────────
|
|
16731
|
-
buildConverseBody(request) {
|
|
17440
|
+
buildConverseBody(request, downgradeToolChoice = false) {
|
|
16732
17441
|
const { system, messages } = this.splitSystemMessages(request.messages);
|
|
16733
17442
|
const body = {
|
|
16734
17443
|
messages: this.toBedrockMessages(messages)
|
|
@@ -16752,8 +17461,9 @@ var BedrockProvider = class extends BaseProvider {
|
|
|
16752
17461
|
body.toolConfig = {
|
|
16753
17462
|
tools
|
|
16754
17463
|
};
|
|
17464
|
+
const forceOk = !downgradeToolChoice && supportsForcedToolChoice(request.model || this.defaultModel);
|
|
16755
17465
|
if (request.toolChoice != null) {
|
|
16756
|
-
if (request.toolChoice === "auto") {
|
|
17466
|
+
if (request.toolChoice === "auto" || !forceOk && request.toolChoice !== "none") {
|
|
16757
17467
|
body.toolConfig.toolChoice = { auto: {} };
|
|
16758
17468
|
} else if (request.toolChoice === "required") {
|
|
16759
17469
|
body.toolConfig.toolChoice = { any: {} };
|
|
@@ -16763,9 +17473,17 @@ var BedrockProvider = class extends BaseProvider {
|
|
|
16763
17473
|
}
|
|
16764
17474
|
}
|
|
16765
17475
|
if (request.extra) {
|
|
16766
|
-
|
|
17476
|
+
const fields = { ...request.extra.additionalModelRequestFields ?? {} };
|
|
17477
|
+
const topLevel = { ...request.extra.__top ?? {} };
|
|
17478
|
+
for (const [key, value] of Object.entries(request.extra)) {
|
|
17479
|
+
if (key === "additionalModelRequestFields" || key === "__top") continue;
|
|
17480
|
+
if (CONVERSE_TOP_LEVEL_FIELDS.has(key)) body[key] = value;
|
|
17481
|
+
else fields[key] = value;
|
|
17482
|
+
}
|
|
17483
|
+
Object.assign(body, topLevel);
|
|
17484
|
+
if (Object.keys(fields).length > 0) body.additionalModelRequestFields = fields;
|
|
16767
17485
|
}
|
|
16768
|
-
applyBedrockReasoning(body, request.reasoning);
|
|
17486
|
+
applyBedrockReasoning(body, request.reasoning, { model: request.model || this.defaultModel, mode: this.thinkingMode });
|
|
16769
17487
|
return body;
|
|
16770
17488
|
}
|
|
16771
17489
|
splitSystemMessages(messages) {
|
|
@@ -16888,9 +17606,22 @@ var BedrockProvider = class extends BaseProvider {
|
|
|
16888
17606
|
}
|
|
16889
17607
|
};
|
|
16890
17608
|
}
|
|
16891
|
-
|
|
17609
|
+
/** Sends the Converse call; retries once with toolChoice auto when the
|
|
17610
|
+
* model rejects forced tool use. */
|
|
17611
|
+
async converseFetch(modelId, request, stream) {
|
|
17612
|
+
const body = this.buildConverseBody(request);
|
|
17613
|
+
try {
|
|
17614
|
+
return await this.doFetch(modelId, body, request.signal, stream);
|
|
17615
|
+
} catch (err) {
|
|
17616
|
+
const tc = body.toolConfig?.toolChoice;
|
|
17617
|
+
if (!(err instanceof ProviderError) || err.statusCode !== 400 || !tc || tc.auto) throw err;
|
|
17618
|
+
if (!forcedToolChoiceRejected(String(err.responseBody ?? err.message))) throw err;
|
|
17619
|
+
return this.doFetch(modelId, this.buildConverseBody(request, true), request.signal, stream);
|
|
17620
|
+
}
|
|
17621
|
+
}
|
|
17622
|
+
async doFetch(modelId, body, signal, stream) {
|
|
16892
17623
|
const host = `bedrock-runtime.${this.region}.amazonaws.com`;
|
|
16893
|
-
const url = `https://${host}/model/${encodeURIComponent(modelId)}
|
|
17624
|
+
const url = `https://${host}/model/${encodeURIComponent(modelId)}/${stream ? "converse-stream" : "converse"}`;
|
|
16894
17625
|
const bodyStr = JSON.stringify(body);
|
|
16895
17626
|
const res = await this.doFetchWithRetry(() => {
|
|
16896
17627
|
const headers = signRequest({
|
|
@@ -16898,7 +17629,7 @@ var BedrockProvider = class extends BaseProvider {
|
|
|
16898
17629
|
url,
|
|
16899
17630
|
headers: {
|
|
16900
17631
|
"Content-Type": "application/json",
|
|
16901
|
-
Accept: "application/json",
|
|
17632
|
+
Accept: stream ? "application/vnd.amazon.eventstream" : "application/json",
|
|
16902
17633
|
...this.defaultHeaders
|
|
16903
17634
|
},
|
|
16904
17635
|
body: bodyStr,
|
|
@@ -16906,7 +17637,7 @@ var BedrockProvider = class extends BaseProvider {
|
|
|
16906
17637
|
service: "bedrock",
|
|
16907
17638
|
credentials: this.credentials
|
|
16908
17639
|
});
|
|
16909
|
-
return
|
|
17640
|
+
return this.httpFetch(url, { method: "POST", headers, body: bodyStr, signal });
|
|
16910
17641
|
}, signal);
|
|
16911
17642
|
if (!res.ok) {
|
|
16912
17643
|
const text = await res.text().catch(() => "");
|
|
@@ -16917,7 +17648,7 @@ var BedrockProvider = class extends BaseProvider {
|
|
|
16917
17648
|
text
|
|
16918
17649
|
);
|
|
16919
17650
|
}
|
|
16920
|
-
return res
|
|
17651
|
+
return res;
|
|
16921
17652
|
}
|
|
16922
17653
|
parseResponse(json, modelId) {
|
|
16923
17654
|
const output = json.output?.message;
|
|
@@ -16953,8 +17684,8 @@ var BedrockProvider = class extends BaseProvider {
|
|
|
16953
17684
|
inputTokens: usage.inputTokens ?? 0,
|
|
16954
17685
|
outputTokens: usage.outputTokens ?? 0,
|
|
16955
17686
|
totalTokens: usage.totalTokens ?? (usage.inputTokens ?? 0) + (usage.outputTokens ?? 0),
|
|
16956
|
-
cachedInputTokens: usage.cacheReadInputTokenCount ?? 0,
|
|
16957
|
-
cachedWriteTokens: usage.cacheWriteInputTokenCount ?? 0,
|
|
17687
|
+
cachedInputTokens: usage.cacheReadInputTokens ?? usage.cacheReadInputTokenCount ?? 0,
|
|
17688
|
+
cachedWriteTokens: usage.cacheWriteInputTokens ?? usage.cacheWriteInputTokenCount ?? 0,
|
|
16958
17689
|
cachedOutputTokens: 0,
|
|
16959
17690
|
// Bedrock bills thinking tokens inside outputTokens; no separate count.
|
|
16960
17691
|
reasoningTokens: 0
|
|
@@ -16966,11 +17697,26 @@ var BedrockProvider = class extends BaseProvider {
|
|
|
16966
17697
|
toolCalls,
|
|
16967
17698
|
usage: tokenUsage,
|
|
16968
17699
|
finishReason: mapBedrockStopReason(json.stopReason),
|
|
17700
|
+
...typeof json.stopReason === "string" ? { rawFinishReason: json.stopReason } : {},
|
|
16969
17701
|
reasoning: reasoningBlocks.length > 0 ? { blocks: reasoningBlocks, summary: summaryParts.join("\n").trim() || void 0 } : void 0,
|
|
16970
17702
|
raw: json
|
|
16971
17703
|
};
|
|
16972
17704
|
}
|
|
16973
17705
|
};
|
|
17706
|
+
var CONVERSE_TOP_LEVEL_FIELDS = /* @__PURE__ */ new Set([
|
|
17707
|
+
"messages",
|
|
17708
|
+
"system",
|
|
17709
|
+
"inferenceConfig",
|
|
17710
|
+
"toolConfig",
|
|
17711
|
+
"guardrailConfig",
|
|
17712
|
+
"additionalModelRequestFields",
|
|
17713
|
+
"additionalModelResponseFieldPaths",
|
|
17714
|
+
"promptVariables",
|
|
17715
|
+
"requestMetadata",
|
|
17716
|
+
"performanceConfig",
|
|
17717
|
+
"serviceTier",
|
|
17718
|
+
"outputConfig"
|
|
17719
|
+
]);
|
|
16974
17720
|
function appendBedrockReasoning(content, blocks) {
|
|
16975
17721
|
if (!blocks?.length) return;
|
|
16976
17722
|
for (const b of blocks) {
|
|
@@ -16985,6 +17731,23 @@ function appendBedrockReasoning(content, blocks) {
|
|
|
16985
17731
|
}
|
|
16986
17732
|
}
|
|
16987
17733
|
}
|
|
17734
|
+
function bedrockExceptionStatus(code) {
|
|
17735
|
+
switch (code) {
|
|
17736
|
+
case "throttlingException":
|
|
17737
|
+
return 429;
|
|
17738
|
+
case "validationException":
|
|
17739
|
+
return 400;
|
|
17740
|
+
case "modelTimeoutException":
|
|
17741
|
+
return 408;
|
|
17742
|
+
case "serviceUnavailableException":
|
|
17743
|
+
return 503;
|
|
17744
|
+
case "internalServerException":
|
|
17745
|
+
case "modelStreamErrorException":
|
|
17746
|
+
return 500;
|
|
17747
|
+
default:
|
|
17748
|
+
return void 0;
|
|
17749
|
+
}
|
|
17750
|
+
}
|
|
16988
17751
|
function mapBedrockStopReason(reason) {
|
|
16989
17752
|
switch (reason) {
|
|
16990
17753
|
case "end_turn":
|
|
@@ -16993,8 +17756,10 @@ function mapBedrockStopReason(reason) {
|
|
|
16993
17756
|
case "tool_use":
|
|
16994
17757
|
return "tool_calls";
|
|
16995
17758
|
case "max_tokens":
|
|
17759
|
+
case "model_context_window_exceeded":
|
|
16996
17760
|
return "length";
|
|
16997
17761
|
case "content_filtered":
|
|
17762
|
+
case "guardrail_intervened":
|
|
16998
17763
|
case "guardrail":
|
|
16999
17764
|
return "content_filter";
|
|
17000
17765
|
default:
|
|
@@ -17024,10 +17789,12 @@ var VertexProvider = class extends BaseProvider {
|
|
|
17024
17789
|
super();
|
|
17025
17790
|
this.providerName = "vertex";
|
|
17026
17791
|
this.tokenExpiry = 0;
|
|
17792
|
+
this.configureTransport(config);
|
|
17027
17793
|
this.projectId = config.projectId;
|
|
17028
17794
|
this.location = config.location ?? "us-central1";
|
|
17029
17795
|
this.defaultModel = config.defaultModel ?? "gemini-2.0-flash";
|
|
17030
17796
|
this.defaultHeaders = config.defaultHeaders ?? {};
|
|
17797
|
+
if (config.retry) this.retryPolicy = { ...this.retryPolicy, ...config.retry };
|
|
17031
17798
|
if (config.accessToken) {
|
|
17032
17799
|
this.accessToken = config.accessToken;
|
|
17033
17800
|
this.tokenExpiry = Date.now() + 36e5;
|
|
@@ -17050,6 +17817,7 @@ var VertexProvider = class extends BaseProvider {
|
|
|
17050
17817
|
const url = this.buildUrl(modelId, true);
|
|
17051
17818
|
const res = await this.doFetch(url, body, request.signal);
|
|
17052
17819
|
if (!res.body) throw new ProviderError("No response body for stream", this.providerName);
|
|
17820
|
+
const counter = { next: 0 };
|
|
17053
17821
|
const contentType = res.headers.get("content-type") ?? "";
|
|
17054
17822
|
if (contentType.includes("text/event-stream")) {
|
|
17055
17823
|
for await (const event of parseSSEStream(res.body, request.signal)) {
|
|
@@ -17060,7 +17828,7 @@ var VertexProvider = class extends BaseProvider {
|
|
|
17060
17828
|
} catch {
|
|
17061
17829
|
continue;
|
|
17062
17830
|
}
|
|
17063
|
-
yield this.parseStreamChunk(chunk, modelId);
|
|
17831
|
+
yield this.parseStreamChunk(chunk, modelId, counter);
|
|
17064
17832
|
}
|
|
17065
17833
|
} else {
|
|
17066
17834
|
const reader = res.body.getReader();
|
|
@@ -17078,7 +17846,7 @@ var VertexProvider = class extends BaseProvider {
|
|
|
17078
17846
|
if (!trimmed || trimmed === "[" || trimmed === "]") continue;
|
|
17079
17847
|
try {
|
|
17080
17848
|
const chunk = JSON.parse(trimmed);
|
|
17081
|
-
yield this.parseStreamChunk(chunk, modelId);
|
|
17849
|
+
yield this.parseStreamChunk(chunk, modelId, counter);
|
|
17082
17850
|
} catch {
|
|
17083
17851
|
buffer = line + "\n" + buffer;
|
|
17084
17852
|
break;
|
|
@@ -17089,7 +17857,7 @@ var VertexProvider = class extends BaseProvider {
|
|
|
17089
17857
|
if (remaining && remaining !== "[" && remaining !== "]") {
|
|
17090
17858
|
try {
|
|
17091
17859
|
const chunk = JSON.parse(remaining);
|
|
17092
|
-
yield this.parseStreamChunk(chunk, modelId);
|
|
17860
|
+
yield this.parseStreamChunk(chunk, modelId, counter);
|
|
17093
17861
|
} catch {
|
|
17094
17862
|
}
|
|
17095
17863
|
}
|
|
@@ -17100,6 +17868,48 @@ var VertexProvider = class extends BaseProvider {
|
|
|
17100
17868
|
}
|
|
17101
17869
|
}
|
|
17102
17870
|
// ─── Internals ───────────────────────────────────────────────────────────
|
|
17871
|
+
/**
|
|
17872
|
+
* Vertex `:predict` embeddings (text-embedding-00x, text-multilingual-embedding,
|
|
17873
|
+
* gemini-embedding-001). `inputType` maps to the task type; `dimensions` to
|
|
17874
|
+
* `outputDimensionality`. gemini-embedding takes one instance per request, the
|
|
17875
|
+
* text-embedding models up to `batchSize` (default 100).
|
|
17876
|
+
*/
|
|
17877
|
+
async embed(request) {
|
|
17878
|
+
const model = requireEmbeddingModel(this.providerName, request.model);
|
|
17879
|
+
const perRequest = request.batchSize ?? (/gemini-embedding/i.test(model) ? 1 : 100);
|
|
17880
|
+
const url = `https://${this.location}-aiplatform.googleapis.com/v1/projects/${this.projectId}/locations/${this.location}/publishers/google/models/${model}:predict`;
|
|
17881
|
+
const taskType = request.inputType ? Object.prototype.hasOwnProperty.call(GEMINI_TASK_TYPES, request.inputType) ? GEMINI_TASK_TYPES[request.inputType] : request.inputType.toUpperCase() : void 0;
|
|
17882
|
+
const vectors = [];
|
|
17883
|
+
const raw = [];
|
|
17884
|
+
let inputTokens = 0;
|
|
17885
|
+
for (const batch of chunkArray(request.input, perRequest)) {
|
|
17886
|
+
const body = {
|
|
17887
|
+
instances: batch.map((content) => ({ content, ...taskType ? { task_type: taskType } : {} }))
|
|
17888
|
+
};
|
|
17889
|
+
const { parameters: extraParameters, ...extraRest } = request.extra ?? {};
|
|
17890
|
+
const parameters = {
|
|
17891
|
+
...request.dimensions != null ? { outputDimensionality: request.dimensions } : {},
|
|
17892
|
+
// Caller-supplied parameters are merged in, not replacing the above (an
|
|
17893
|
+
// explicit extra.parameters.outputDimensionality still wins).
|
|
17894
|
+
...extraParameters && typeof extraParameters === "object" ? extraParameters : {}
|
|
17895
|
+
};
|
|
17896
|
+
if (Object.keys(parameters).length > 0) body.parameters = parameters;
|
|
17897
|
+
Object.assign(body, extraRest);
|
|
17898
|
+
const res = await this.doFetch(url, body, request.signal);
|
|
17899
|
+
const json = await res.json();
|
|
17900
|
+
raw.push(json);
|
|
17901
|
+
for (const p of json.predictions ?? []) {
|
|
17902
|
+
const values = p.embeddings?.values;
|
|
17903
|
+
if (!Array.isArray(values)) {
|
|
17904
|
+
throw new ProviderError("Vertex embeddings response has a prediction without an embeddings.values array", this.providerName, void 0, json);
|
|
17905
|
+
}
|
|
17906
|
+
vectors.push(values);
|
|
17907
|
+
inputTokens += p.embeddings?.statistics?.token_count ?? 0;
|
|
17908
|
+
}
|
|
17909
|
+
}
|
|
17910
|
+
assertVectorCount(this.providerName, vectors, request.input.length);
|
|
17911
|
+
return { model, vectors, usage: { inputTokens, totalTokens: inputTokens }, raw };
|
|
17912
|
+
}
|
|
17103
17913
|
buildUrl(modelId, stream) {
|
|
17104
17914
|
const base = `https://${this.location}-aiplatform.googleapis.com/v1`;
|
|
17105
17915
|
const path2 = `projects/${this.projectId}/locations/${this.location}/publishers/google/models/${modelId}`;
|
|
@@ -17197,7 +18007,9 @@ var VertexProvider = class extends BaseProvider {
|
|
|
17197
18007
|
functionCall: {
|
|
17198
18008
|
name: tc.name,
|
|
17199
18009
|
args: safeJsonParse3(tc.arguments)
|
|
17200
|
-
}
|
|
18010
|
+
},
|
|
18011
|
+
// Gemini 3 requires the signature of each functionCall echoed back.
|
|
18012
|
+
...tc.thoughtSignature ? { thoughtSignature: tc.thoughtSignature } : {}
|
|
17201
18013
|
});
|
|
17202
18014
|
}
|
|
17203
18015
|
return { role: "model", parts: parts2 };
|
|
@@ -17294,7 +18106,7 @@ var VertexProvider = class extends BaseProvider {
|
|
|
17294
18106
|
sign.update(signingInput);
|
|
17295
18107
|
const signature = sign.sign(sa.private_key, "base64url");
|
|
17296
18108
|
const jwt = `${signingInput}.${signature}`;
|
|
17297
|
-
const tokenRes = await
|
|
18109
|
+
const tokenRes = await this.httpFetch("https://oauth2.googleapis.com/token", {
|
|
17298
18110
|
method: "POST",
|
|
17299
18111
|
headers: { "Content-Type": "application/x-www-form-urlencoded" },
|
|
17300
18112
|
body: `grant_type=urn:ietf:params:oauth:grant-type:jwt-bearer&assertion=${jwt}`
|
|
@@ -17308,16 +18120,20 @@ var VertexProvider = class extends BaseProvider {
|
|
|
17308
18120
|
}
|
|
17309
18121
|
async doFetch(url, body, signal) {
|
|
17310
18122
|
const token = await this.getAccessToken();
|
|
17311
|
-
const
|
|
17312
|
-
|
|
17313
|
-
|
|
17314
|
-
|
|
17315
|
-
|
|
17316
|
-
|
|
17317
|
-
|
|
17318
|
-
|
|
18123
|
+
const bodyStr = JSON.stringify(body);
|
|
18124
|
+
const res = await this.doFetchWithRetry(
|
|
18125
|
+
() => this.httpFetch(url, {
|
|
18126
|
+
method: "POST",
|
|
18127
|
+
headers: {
|
|
18128
|
+
"Content-Type": "application/json",
|
|
18129
|
+
Authorization: `Bearer ${token}`,
|
|
18130
|
+
...this.defaultHeaders
|
|
18131
|
+
},
|
|
18132
|
+
body: bodyStr,
|
|
18133
|
+
signal
|
|
18134
|
+
}),
|
|
17319
18135
|
signal
|
|
17320
|
-
|
|
18136
|
+
);
|
|
17321
18137
|
if (!res.ok) {
|
|
17322
18138
|
const text = await res.text().catch(() => "");
|
|
17323
18139
|
throw new ProviderError(
|
|
@@ -17347,7 +18163,8 @@ var VertexProvider = class extends BaseProvider {
|
|
|
17347
18163
|
toolCalls.push({
|
|
17348
18164
|
id: `call_${toolCallIdx++}`,
|
|
17349
18165
|
name: part.functionCall.name,
|
|
17350
|
-
arguments: JSON.stringify(part.functionCall.args ?? {})
|
|
18166
|
+
arguments: JSON.stringify(part.functionCall.args ?? {}),
|
|
18167
|
+
...part.thoughtSignature ? { thoughtSignature: part.thoughtSignature } : {}
|
|
17351
18168
|
});
|
|
17352
18169
|
}
|
|
17353
18170
|
}
|
|
@@ -17368,11 +18185,12 @@ var VertexProvider = class extends BaseProvider {
|
|
|
17368
18185
|
toolCalls,
|
|
17369
18186
|
usage: tokenUsage,
|
|
17370
18187
|
finishReason: mapGeminiFinishReason(candidate?.finishReason),
|
|
18188
|
+
...typeof candidate?.finishReason === "string" ? { rawFinishReason: candidate.finishReason } : {},
|
|
17371
18189
|
reasoning: thoughtParts.length > 0 ? { summary: thoughtParts.join("\n").trim() || void 0 } : void 0,
|
|
17372
18190
|
raw: json
|
|
17373
18191
|
};
|
|
17374
18192
|
}
|
|
17375
|
-
parseStreamChunk(chunk, modelId) {
|
|
18193
|
+
parseStreamChunk(chunk, modelId, counter) {
|
|
17376
18194
|
const candidate = chunk.candidates?.[0];
|
|
17377
18195
|
const parts = candidate?.content?.parts ?? [];
|
|
17378
18196
|
const delta = {};
|
|
@@ -17386,9 +18204,12 @@ var VertexProvider = class extends BaseProvider {
|
|
|
17386
18204
|
} else if (part.functionCall) {
|
|
17387
18205
|
if (!delta.toolCalls) delta.toolCalls = [];
|
|
17388
18206
|
delta.toolCalls.push({
|
|
17389
|
-
|
|
18207
|
+
// Unique across the whole stream: the adapter merges chunks by id.
|
|
18208
|
+
id: `call_${counter.next}`,
|
|
18209
|
+
index: counter.next++,
|
|
17390
18210
|
name: part.functionCall.name,
|
|
17391
|
-
arguments: JSON.stringify(part.functionCall.args ?? {})
|
|
18211
|
+
arguments: JSON.stringify(part.functionCall.args ?? {}),
|
|
18212
|
+
...part.thoughtSignature ? { thoughtSignature: part.thoughtSignature } : {}
|
|
17392
18213
|
});
|
|
17393
18214
|
}
|
|
17394
18215
|
}
|
|
@@ -17410,10 +18231,21 @@ var VertexProvider = class extends BaseProvider {
|
|
|
17410
18231
|
model: modelId,
|
|
17411
18232
|
delta,
|
|
17412
18233
|
usage,
|
|
17413
|
-
finishReason: mapGeminiFinishReason(candidate?.finishReason)
|
|
18234
|
+
finishReason: mapGeminiFinishReason(candidate?.finishReason),
|
|
18235
|
+
...typeof candidate?.finishReason === "string" ? { rawFinishReason: candidate.finishReason } : {}
|
|
17414
18236
|
};
|
|
17415
18237
|
}
|
|
17416
18238
|
};
|
|
18239
|
+
var GEMINI_TASK_TYPES = {
|
|
18240
|
+
search_document: "RETRIEVAL_DOCUMENT",
|
|
18241
|
+
search_query: "RETRIEVAL_QUERY",
|
|
18242
|
+
classification: "CLASSIFICATION",
|
|
18243
|
+
clustering: "CLUSTERING",
|
|
18244
|
+
semantic_similarity: "SEMANTIC_SIMILARITY",
|
|
18245
|
+
question_answering: "QUESTION_ANSWERING",
|
|
18246
|
+
fact_verification: "FACT_VERIFICATION",
|
|
18247
|
+
code_retrieval_query: "CODE_RETRIEVAL_QUERY"
|
|
18248
|
+
};
|
|
17417
18249
|
function mapGeminiFinishReason(reason) {
|
|
17418
18250
|
switch (reason) {
|
|
17419
18251
|
case "STOP":
|
|
@@ -17462,6 +18294,6 @@ function createProvider(config) {
|
|
|
17462
18294
|
}
|
|
17463
18295
|
}
|
|
17464
18296
|
|
|
17465
|
-
export { ASK_USER_TOOL_NAME, AnthropicProvider, AzureProvider, BaseProvider, BedrockProvider, CCRStore, CONSOLE_HOOK_MAP, CONTEXT_PILOT_JSON_MARKER_KEY, CONTROL_PLANE_TOOL_NAMES, DEFAULT_MAX_TOOL_INPUT_FIELD_CHARS, DEFAULT_PROFILE_CONFIGS, DEFAULT_SKILL_POLICY, DEFAULT_SUBAGENT_POLICY, DEFAULT_SUBAGENT_TOOL_NAMES, DEFAULT_TOOL_INPUT_DIGEST_HEAD_CHARS, DELEGATION_TOOL_NAMES, DedupTracker, GuardrailPhase, HOOK_CONTRACT_VERSION, HOOK_NAMES, HookTimeoutError, InMemoryMemoryStore, JevProvider, NativeJsonSchemaStrategy, OpenAICompatibleProvider, OpenAIProvider, PREOPEN_TOOL_CALL_PREFIX, ProviderError, SMALL_TIER_SKILL_POLICY, StructuredOutputManager, TOOL_INPUT_DIGEST_KEY, ToolBasedStrategy, VertexProvider, agentVerdictRule, appendBoundTools, auditLog, azureContentSafety, bedrockGuardrail, budgetGuard, buildHandoffTools, buildResponseFormatSection, buildSkillHeaderBlock, buildSubagentCatalogBlock, buildSystemPrompt, buildToolDefinitionsSection, canOpenSkill, canSpawn, captureSnapshot, checkpointing, codePresenceRule, coerceToolArgs, cognipeerGuardrail, cognipeerSink, collectAttachments, collectToolRetentionDeclarations, composeToolSets, compressDiffOutput, compressJsonOutput, compressLogOutput, compressSearchOutput, compressTextOutput, compressToolOutput, contentPartToText, contentToString, conversationHistory, countApproxTokens, countMessagesTokens, createAgent, createAgentNode, createAskUserQuestionTool, createBindSkillToolsTool, createCodeGuardrail, createContextPilotRuntime, createContextSummarizeNode, createContextTools, createDelegateTool, createGetToolResponseTool, createGuardrail, createGuardrailPlugin, createJsonGuardrail, createManageTodoListAliasTool, createManageTodoTool, createOpenSkillTool, createParallelTool, createPluginHost, createProvider, createRegexGuardrail, createResolverNode, createSearchSkillsTool, createSkillRegistryRef, createSkillTools, createSmartAgent, createSpawnTool, createSubagentRegistryRef, createSubagentTools, createTool, createToolLimitFinalizeNode, createToolsNode, customCallbackRule, customGuardrail, customSink, dedupeToolsByName, defaultTokenCounter, defineHook, definePlugin, describeContentPart, detectLanguage, detectTextFormat, detectVolatileContent, digestToolInputArguments, digestToolInputValue, emptyUsage, evaluateGuardrails, extractLatestUserQuery, extractMessageText, fileCheckpointStore, fileSink, findSubagent, formatZodError, fromLangchainModel, fromLangchainTools, fromNativeProvider, generateSpanId, generateTraceId, getModelCapabilities, getNestedValue, getResolvedSmartConfig, getTokenCounter, hasMediaPart, hasToolResponseRecoveryReference, httpGuardrail, httpSink, inMemoryCheckpointStore, inMemoryConversationStore, isHookImplemented, isOpenAIHostedEndpoint, isSmartModel, isValidIban, isValidLuhn, isValidTckn, jsonSchemaRule, defaultBuildPayload as langfuseDefaultPayload, langfuseTracing, languageGuard, loadSkillsFromDisk, mapConsoleHookVerdict, mapTextParts, mcp, mediaKindOf, mediaPolicy, normalizeSmartAgentOptions, normalizeVerdicts, openAIModeration, otelTracing, otlpSink, outputGuard, parseApprovalDecision, parseSkillFrontmatter, pathSandbox, piiRedaction, pluginCapabilities, portkeyGateway, portkeyGuardrail, preopenSkills, preopenToolCallId, prepareStrictToolMenu, promptInjectionGuard, rateLimit, readMemoryFacts, redactText, regexGuardrail, regexRule, replaceTextContent, resolveAvailableSkills, resolveAvailableSubagents, resolveInputRetention, resolveMemoryStore, resolveReasoning, resolveStrategy, resolveSubagentTools, resolveSummarizationRetention, resolveToolApprovalState, resolveUserQuestionState, responseCache, restoreSnapshot, restoreToolCalls, runSmartAgentEvalHarness, scoreItemsByRelevance, searchSkills, seedChildMessages, selectTopIndicesInOrder, sessionMetrics, setTokenCounter, startStreamingSession, summarizeObject, textFromContent, toStrictCompatible, toStrictToolSchema, tokenize, toolPolicy, traceSessionToOtlp, validateReasoningConfig, validateToolArgs, webhookApproval, withTools, withinDepth, writeSummaryFactsToMemory };
|
|
18297
|
+
export { ASK_USER_TOOL_NAME, AnthropicProvider, AzureProvider, BaseProvider, BedrockProvider, CCRStore, CONSOLE_HOOK_MAP, CONTEXT_PILOT_JSON_MARKER_KEY, CONTROL_PLANE_TOOL_NAMES, DEFAULT_MAX_TOOL_INPUT_FIELD_CHARS, DEFAULT_PROFILE_CONFIGS, DEFAULT_SKILL_POLICY, DEFAULT_SUBAGENT_POLICY, DEFAULT_SUBAGENT_TOOL_NAMES, DEFAULT_TOOL_INPUT_DIGEST_HEAD_CHARS, DELEGATION_TOOL_NAMES, DedupTracker, GuardrailPhase, HOOK_CONTRACT_VERSION, HOOK_NAMES, HookTimeoutError, InMemoryMemoryStore, JevProvider, NativeJsonSchemaStrategy, OpenAICompatibleProvider, OpenAIProvider, PREOPEN_TOOL_CALL_PREFIX, ProviderError, SMALL_TIER_SKILL_POLICY, StructuredOutputManager, TOOL_INPUT_DIGEST_KEY, ToolBasedStrategy, VertexProvider, agentVerdictRule, appendBoundTools, auditLog, azureContentSafety, bedrockGuardrail, budgetGuard, buildHandoffTools, buildResponseFormatSection, buildSkillHeaderBlock, buildSubagentCatalogBlock, buildSystemPrompt, buildToolDefinitionsSection, canOpenSkill, canSpawn, captureSnapshot, checkpointing, codePresenceRule, coerceToolArgs, cognipeerGuardrail, cognipeerSink, collectAttachments, collectToolRetentionDeclarations, composeToolSets, compressDiffOutput, compressJsonOutput, compressLogOutput, compressSearchOutput, compressTextOutput, compressToolOutput, contentPartToText, contentToString, conversationHistory, countApproxTokens, countMessagesTokens, createAgent, createAgentNode, createAskUserQuestionTool, createBindSkillToolsTool, createCodeGuardrail, createContextPilotRuntime, createContextSummarizeNode, createContextTools, createDelegateTool, createGetToolResponseTool, createGuardrail, createGuardrailPlugin, createJsonGuardrail, createManageTodoListAliasTool, createManageTodoTool, createOpenSkillTool, createParallelTool, createPluginHost, createProvider, createRegexGuardrail, createResolverNode, createSearchSkillsTool, createSkillRegistryRef, createSkillTools, createSmartAgent, createSpawnTool, createSubagentRegistryRef, createSubagentTools, createTool, createToolLimitFinalizeNode, createToolsNode, customCallbackRule, customGuardrail, customSink, dedupeToolsByName, defaultTokenCounter, defineHook, definePlugin, describeContentPart, detectLanguage, detectTextFormat, detectVolatileContent, digestToolInputArguments, digestToolInputValue, emptyUsage, evaluateGuardrails, extractLatestUserQuery, extractMessageText, fileCheckpointStore, fileSink, findSubagent, formatZodError, fromLangchainModel, fromLangchainTools, fromNativeProvider, generateSpanId, generateTraceId, getModelCapabilities, getNestedValue, getResolvedSmartConfig, getTokenCounter, hasMediaPart, hasToolResponseRecoveryReference, httpGuardrail, httpSink, inMemoryCheckpointStore, inMemoryConversationStore, isHookImplemented, isOpenAIHostedEndpoint, isSmartModel, isValidIban, isValidLuhn, isValidTckn, jsonSchemaRule, defaultBuildPayload as langfuseDefaultPayload, langfuseTracing, languageGuard, loadSkillsFromDisk, mapConsoleHookVerdict, mapTextParts, mcp, mediaKindOf, mediaPolicy, normalizeSmartAgentOptions, normalizeVerdicts, openAIModeration, otelTracing, otlpSink, outputGuard, parseApprovalDecision, parseSkillFrontmatter, pathSandbox, piiRedaction, pluginCapabilities, portkeyGateway, portkeyGuardrail, preopenSkills, preopenToolCallId, prepareStrictToolMenu, promptInjectionGuard, rateLimit, readMemoryFacts, redactText, regexGuardrail, regexRule, replaceTextContent, resolveAvailableSkills, resolveAvailableSubagents, resolveInputRetention, resolveMemoryStore, resolveReasoning, resolveStrategy, resolveSubagentTools, resolveSummarizationRetention, resolveToolApprovalState, resolveUserQuestionState, responseCache, restoreSnapshot, restoreToolCalls, runSmartAgentEvalHarness, scoreItemsByRelevance, searchSkills, seedChildMessages, selectTopIndicesInOrder, sessionMetrics, setTokenCounter, startStreamingSession, summarizeObject, supportsAdaptiveThinking, textFromContent, toMessageUsage, toStrictCompatible, toStrictToolSchema, tokenize, toolPolicy, traceSessionToOtlp, validateReasoningConfig, validateToolArgs, webhookApproval, withTools, withinDepth, writeSummaryFactsToMemory };
|
|
17466
18298
|
//# sourceMappingURL=index.mjs.map
|
|
17467
18299
|
//# sourceMappingURL=index.mjs.map
|