+113
-6
@@ -58,9 +58,91 @@ /** @deprecated Use provider prefix strings instead, e.g. `"anthropic:claude-sonnet-4-5"` */ | ||
| } | ||
| /** | ||
| * A single conversation turn passed to `callWithRetries`. The SDK serializes | ||
| * these into each provider's native message format. | ||
| * | ||
| * ## Multi-turn tool calls | ||
| * To continue after the model calls a tool, append the model's own assistant | ||
| * turn and then the tool result, then call again: | ||
| * | ||
| * 1. Read the assistant turn off the response: `function_calls` (each with an | ||
| * `id`) and — for reasoning models — `reasoning` / `reasoningDetails`. | ||
| * 2. Push back an `assistant` message carrying those same `functionCalls` (and, | ||
| * to keep the model's chain-of-thought, the captured reasoning fields). | ||
| * 3. Push back one `role: "tool"` message whose `toolResults` answer each call | ||
| * by `toolCallId`. | ||
| * | ||
| * The SDK is a pure transport: it does NOT echo reasoning or pair results for | ||
| * you — it serializes exactly what you put here. Every tool/reasoning field is | ||
| * optional, so a plain `{ role, content }` message behaves as before. | ||
| * | ||
| * @example | ||
| * // turn 1 — model asks for the weather | ||
| * const a = await callWithRetries(id, { model, messages, functions }); | ||
| * // a.function_calls -> [{ id: "call_abc", name: "get_weather", arguments: { city: "Tokyo" } }] | ||
| * | ||
| * // turn 2 — feed the call + its result back | ||
| * const next = await callWithRetries(id, { model, functions, messages: [ | ||
| * ...messages, | ||
| * { role: "assistant", content: a.content ?? "", functionCalls: a.function_calls, | ||
| * reasoning: a.reasoning, reasoningDetails: a.reasoningDetails }, | ||
| * { role: "tool", content: "", toolResults: [ | ||
| * { toolCallId: "call_abc", name: "get_weather", content: '{"tempC":22}' } ] }, | ||
| * ]}); | ||
| */ | ||
| interface GenericMessage { | ||
| role: "user" | "assistant" | "system"; | ||
| /** | ||
| * `"tool"` carries tool results (see `toolResults`) back to the model and | ||
| * must immediately follow the `assistant` turn that made the matching calls. | ||
| */ | ||
| role: "user" | "assistant" | "system" | "tool"; | ||
| /** Plain-text content. Use `""` for a tool-call-only or tool-result turn. */ | ||
| content: string; | ||
| timestamp?: string; | ||
| files?: File[]; | ||
| /** | ||
| * Tool calls the model made on an `assistant` turn. Pass back the `id`s you | ||
| * received in `ParsedResponseMessage.function_calls` so the provider can pair | ||
| * them with the `toolResults` that follow. | ||
| */ | ||
| functionCalls?: FunctionCall[]; | ||
| /** | ||
| * Tool outputs on a `role: "tool"` message — one entry per call (parallel | ||
| * calls produce several). Each `toolCallId` must match a `FunctionCall.id` | ||
| * from the preceding assistant turn. | ||
| */ | ||
| toolResults?: ToolResult[]; | ||
| /** | ||
| * Optional reasoning string to echo back on an `assistant` turn (e.g. | ||
| * OpenRouter/DeepSeek `reasoning`). Round-tripping it keeps the model's | ||
| * chain-of-thought across tool calls; some thinking models (DeepSeek V4) | ||
| * require it to avoid a 400 on the next turn. | ||
| */ | ||
| reasoning?: string; | ||
| /** | ||
| * Optional structured reasoning to echo back on an `assistant` turn | ||
| * (OpenRouter `reasoning_details`, or Anthropic `thinking` / | ||
| * `redacted_thinking` blocks captured in | ||
| * `ParsedResponseMessage.reasoningDetails`). Preserves the signatures / | ||
| * encrypted payloads that providers validate on round-trip. | ||
| */ | ||
| reasoningDetails?: any; | ||
| } | ||
| /** | ||
| * The result of executing one tool call, fed back to the model on a | ||
| * `role: "tool"` message. The SDK maps this to each provider's native shape: | ||
| * OpenAI/Groq/OpenRouter `{ role: "tool", tool_call_id, content }`, Anthropic a | ||
| * `tool_result` block, Google a `functionResponse` part. | ||
| */ | ||
| interface ToolResult { | ||
| /** The `id` of the `FunctionCall` this answers (from the prior assistant turn). */ | ||
| toolCallId: string; | ||
| /** | ||
| * The tool/function name. Required by Anthropic and Google on round-trip; the | ||
| * SDK falls back to the matching call's name when omitted, but supplying it is | ||
| * recommended. | ||
| */ | ||
| name?: string; | ||
| /** The tool output, serialized to a string (JSON or plain text). */ | ||
| content: string; | ||
| } | ||
| interface File { | ||
@@ -74,5 +156,20 @@ mimeType: string; | ||
| content: string | null; | ||
| /** First of `function_calls` (backward-compat); carries `id` when the provider returns one. */ | ||
| function_call: FunctionCall | null; | ||
| /** All tool calls the model made this turn, each with an `id` for round-tripping. */ | ||
| function_calls: FunctionCall[]; | ||
| files: File[]; | ||
| /** | ||
| * Reasoning string from reasoning models (OpenRouter/DeepSeek `reasoning`). | ||
| * Echo back via `GenericMessage.reasoning` to preserve chain-of-thought across | ||
| * tool calls. Undefined when the model/provider returns none. | ||
| */ | ||
| reasoning?: string; | ||
| /** | ||
| * Structured reasoning (OpenRouter `reasoning_details`, or Anthropic | ||
| * `thinking` / `redacted_thinking` blocks). Echo back verbatim via | ||
| * `GenericMessage.reasoningDetails` — it carries signatures some providers | ||
| * validate. Undefined when the model/provider returns none. | ||
| */ | ||
| reasoningDetails?: any; | ||
| usage: { | ||
@@ -87,9 +184,19 @@ prompt_tokens: number; | ||
| interface FunctionCall { | ||
| /** | ||
| * Provider tool-call id, surfaced on responses and used to pair a call with | ||
| * its `ToolResult.toolCallId` on the next turn. The SDK synthesizes | ||
| * `call_<index>` for providers that don't return one (e.g. Google). | ||
| */ | ||
| id?: string; | ||
| name: string; | ||
| arguments: Record<string, any>; | ||
| /** | ||
| * Opaque per-call signature that must be echoed back verbatim on round-trip. | ||
| * Currently Google's `thoughtSignature` — Gemini REQUIRES it on functionCall | ||
| * parts in multi-turn tool use (a missing one 400s the next request). The SDK | ||
| * captures it on responses and re-emits it when you pass the call back; | ||
| * undefined for providers that don't use one. | ||
| */ | ||
| thoughtSignature?: string; | ||
| } | ||
| interface FunctionCall { | ||
| name: string; | ||
| arguments: Record<string, any>; | ||
| } | ||
| interface OpenAIConfig { | ||
@@ -164,2 +271,2 @@ service: "azure" | "openai"; | ||
| export { type AnyModel, ClaudeModel, type FunctionDefinition, GPTModel, GeminiModel, type GenericMessage, type GenericPayload, GroqModel, type OpenAIConfig, OpenRouterModel, type Provider, callWithRetries, parseModelString }; | ||
| export { type AnyModel, ClaudeModel, type FunctionCall, type FunctionDefinition, GPTModel, GeminiModel, type GenericMessage, type GenericPayload, GroqModel, type OpenAIConfig, OpenRouterModel, type OpenRouterProviderPreferences, type ParsedResponseMessage, type Provider, type ToolResult, callWithRetries, parseModelString }; |
+113
-6
@@ -58,9 +58,91 @@ /** @deprecated Use provider prefix strings instead, e.g. `"anthropic:claude-sonnet-4-5"` */ | ||
| } | ||
| /** | ||
| * A single conversation turn passed to `callWithRetries`. The SDK serializes | ||
| * these into each provider's native message format. | ||
| * | ||
| * ## Multi-turn tool calls | ||
| * To continue after the model calls a tool, append the model's own assistant | ||
| * turn and then the tool result, then call again: | ||
| * | ||
| * 1. Read the assistant turn off the response: `function_calls` (each with an | ||
| * `id`) and — for reasoning models — `reasoning` / `reasoningDetails`. | ||
| * 2. Push back an `assistant` message carrying those same `functionCalls` (and, | ||
| * to keep the model's chain-of-thought, the captured reasoning fields). | ||
| * 3. Push back one `role: "tool"` message whose `toolResults` answer each call | ||
| * by `toolCallId`. | ||
| * | ||
| * The SDK is a pure transport: it does NOT echo reasoning or pair results for | ||
| * you — it serializes exactly what you put here. Every tool/reasoning field is | ||
| * optional, so a plain `{ role, content }` message behaves as before. | ||
| * | ||
| * @example | ||
| * // turn 1 — model asks for the weather | ||
| * const a = await callWithRetries(id, { model, messages, functions }); | ||
| * // a.function_calls -> [{ id: "call_abc", name: "get_weather", arguments: { city: "Tokyo" } }] | ||
| * | ||
| * // turn 2 — feed the call + its result back | ||
| * const next = await callWithRetries(id, { model, functions, messages: [ | ||
| * ...messages, | ||
| * { role: "assistant", content: a.content ?? "", functionCalls: a.function_calls, | ||
| * reasoning: a.reasoning, reasoningDetails: a.reasoningDetails }, | ||
| * { role: "tool", content: "", toolResults: [ | ||
| * { toolCallId: "call_abc", name: "get_weather", content: '{"tempC":22}' } ] }, | ||
| * ]}); | ||
| */ | ||
| interface GenericMessage { | ||
| role: "user" | "assistant" | "system"; | ||
| /** | ||
| * `"tool"` carries tool results (see `toolResults`) back to the model and | ||
| * must immediately follow the `assistant` turn that made the matching calls. | ||
| */ | ||
| role: "user" | "assistant" | "system" | "tool"; | ||
| /** Plain-text content. Use `""` for a tool-call-only or tool-result turn. */ | ||
| content: string; | ||
| timestamp?: string; | ||
| files?: File[]; | ||
| /** | ||
| * Tool calls the model made on an `assistant` turn. Pass back the `id`s you | ||
| * received in `ParsedResponseMessage.function_calls` so the provider can pair | ||
| * them with the `toolResults` that follow. | ||
| */ | ||
| functionCalls?: FunctionCall[]; | ||
| /** | ||
| * Tool outputs on a `role: "tool"` message — one entry per call (parallel | ||
| * calls produce several). Each `toolCallId` must match a `FunctionCall.id` | ||
| * from the preceding assistant turn. | ||
| */ | ||
| toolResults?: ToolResult[]; | ||
| /** | ||
| * Optional reasoning string to echo back on an `assistant` turn (e.g. | ||
| * OpenRouter/DeepSeek `reasoning`). Round-tripping it keeps the model's | ||
| * chain-of-thought across tool calls; some thinking models (DeepSeek V4) | ||
| * require it to avoid a 400 on the next turn. | ||
| */ | ||
| reasoning?: string; | ||
| /** | ||
| * Optional structured reasoning to echo back on an `assistant` turn | ||
| * (OpenRouter `reasoning_details`, or Anthropic `thinking` / | ||
| * `redacted_thinking` blocks captured in | ||
| * `ParsedResponseMessage.reasoningDetails`). Preserves the signatures / | ||
| * encrypted payloads that providers validate on round-trip. | ||
| */ | ||
| reasoningDetails?: any; | ||
| } | ||
| /** | ||
| * The result of executing one tool call, fed back to the model on a | ||
| * `role: "tool"` message. The SDK maps this to each provider's native shape: | ||
| * OpenAI/Groq/OpenRouter `{ role: "tool", tool_call_id, content }`, Anthropic a | ||
| * `tool_result` block, Google a `functionResponse` part. | ||
| */ | ||
| interface ToolResult { | ||
| /** The `id` of the `FunctionCall` this answers (from the prior assistant turn). */ | ||
| toolCallId: string; | ||
| /** | ||
| * The tool/function name. Required by Anthropic and Google on round-trip; the | ||
| * SDK falls back to the matching call's name when omitted, but supplying it is | ||
| * recommended. | ||
| */ | ||
| name?: string; | ||
| /** The tool output, serialized to a string (JSON or plain text). */ | ||
| content: string; | ||
| } | ||
| interface File { | ||
@@ -74,5 +156,20 @@ mimeType: string; | ||
| content: string | null; | ||
| /** First of `function_calls` (backward-compat); carries `id` when the provider returns one. */ | ||
| function_call: FunctionCall | null; | ||
| /** All tool calls the model made this turn, each with an `id` for round-tripping. */ | ||
| function_calls: FunctionCall[]; | ||
| files: File[]; | ||
| /** | ||
| * Reasoning string from reasoning models (OpenRouter/DeepSeek `reasoning`). | ||
| * Echo back via `GenericMessage.reasoning` to preserve chain-of-thought across | ||
| * tool calls. Undefined when the model/provider returns none. | ||
| */ | ||
| reasoning?: string; | ||
| /** | ||
| * Structured reasoning (OpenRouter `reasoning_details`, or Anthropic | ||
| * `thinking` / `redacted_thinking` blocks). Echo back verbatim via | ||
| * `GenericMessage.reasoningDetails` — it carries signatures some providers | ||
| * validate. Undefined when the model/provider returns none. | ||
| */ | ||
| reasoningDetails?: any; | ||
| usage: { | ||
@@ -87,9 +184,19 @@ prompt_tokens: number; | ||
| interface FunctionCall { | ||
| /** | ||
| * Provider tool-call id, surfaced on responses and used to pair a call with | ||
| * its `ToolResult.toolCallId` on the next turn. The SDK synthesizes | ||
| * `call_<index>` for providers that don't return one (e.g. Google). | ||
| */ | ||
| id?: string; | ||
| name: string; | ||
| arguments: Record<string, any>; | ||
| /** | ||
| * Opaque per-call signature that must be echoed back verbatim on round-trip. | ||
| * Currently Google's `thoughtSignature` — Gemini REQUIRES it on functionCall | ||
| * parts in multi-turn tool use (a missing one 400s the next request). The SDK | ||
| * captures it on responses and re-emits it when you pass the call back; | ||
| * undefined for providers that don't use one. | ||
| */ | ||
| thoughtSignature?: string; | ||
| } | ||
| interface FunctionCall { | ||
| name: string; | ||
| arguments: Record<string, any>; | ||
| } | ||
| interface OpenAIConfig { | ||
@@ -164,2 +271,2 @@ service: "azure" | "openai"; | ||
| export { type AnyModel, ClaudeModel, type FunctionDefinition, GPTModel, GeminiModel, type GenericMessage, type GenericPayload, GroqModel, type OpenAIConfig, OpenRouterModel, type Provider, callWithRetries, parseModelString }; | ||
| export { type AnyModel, ClaudeModel, type FunctionCall, type FunctionDefinition, GPTModel, GeminiModel, type GenericMessage, type GenericPayload, GroqModel, type OpenAIConfig, OpenRouterModel, type OpenRouterProviderPreferences, type ParsedResponseMessage, type Provider, type ToolResult, callWithRetries, parseModelString }; |
+259
-73
@@ -142,3 +142,2 @@ "use strict"; | ||
| // index.ts | ||
| var import_genai = require("@google/genai"); | ||
| var sharp = require("sharp"); | ||
@@ -174,5 +173,6 @@ var decode = require("heic-decode"); | ||
| } | ||
| function parseStreamedResponse(identifier, paragraph, toolCallAccumulators, allowedFunctionNames) { | ||
| function parseStreamedResponse(identifier, paragraph, toolCallAccumulators, allowedFunctionNames, reasoning) { | ||
| const functionCalls = []; | ||
| for (const acc of toolCallAccumulators) { | ||
| for (let i = 0; i < toolCallAccumulators.length; i++) { | ||
| const acc = toolCallAccumulators[i]; | ||
| if (!acc.name || !acc.arguments) | ||
@@ -187,2 +187,3 @@ continue; | ||
| functionCalls.push({ | ||
| id: acc.id || `call_${i}`, | ||
| name: acc.name, | ||
@@ -216,2 +217,3 @@ arguments: JSON.parse(acc.arguments) | ||
| files: [], | ||
| reasoning: reasoning || void 0, | ||
| usage: null | ||
@@ -318,3 +320,3 @@ }; | ||
| async function prepareOpenAIPayload(identifier, payload) { | ||
| var _a; | ||
| var _a, _b; | ||
| const preparedPayload = { | ||
@@ -330,2 +332,12 @@ model: payload.model, | ||
| for (const message of payload.messages) { | ||
| if (message.role === "tool") { | ||
| for (const tr of message.toolResults || []) { | ||
| preparedPayload.messages.push({ | ||
| role: "tool", | ||
| tool_call_id: tr.toolCallId, | ||
| content: tr.content | ||
| }); | ||
| } | ||
| continue; | ||
| } | ||
| const contentBlocks = []; | ||
@@ -356,6 +368,25 @@ if (message.content) { | ||
| } | ||
| preparedPayload.messages.push({ | ||
| const outMessage = { | ||
| role: message.role, | ||
| content: contentBlocks | ||
| }); | ||
| // OpenAI wants null (not []) content on a tool-call-only assistant turn. | ||
| content: contentBlocks.length ? contentBlocks : null | ||
| }; | ||
| if ((_b = message.functionCalls) == null ? void 0 : _b.length) { | ||
| outMessage.tool_calls = message.functionCalls.map((fc, i) => { | ||
| var _a2; | ||
| return { | ||
| id: (_a2 = fc.id) != null ? _a2 : `call_${i}`, | ||
| type: "function", | ||
| function: { | ||
| name: fc.name, | ||
| arguments: JSON.stringify(fc.arguments) | ||
| } | ||
| }; | ||
| }); | ||
| } | ||
| if (message.reasoning) | ||
| outMessage.reasoning = message.reasoning; | ||
| if (message.reasoningDetails) | ||
| outMessage.reasoning_details = message.reasoningDetails; | ||
| preparedPayload.messages.push(outMessage); | ||
| } | ||
@@ -365,3 +396,3 @@ return preparedPayload; | ||
| async function callOpenAIStream(id, openAiPayload, openAiConfig, chunkTimeoutMs) { | ||
| var _a, _b, _c, _d, _e, _f, _g, _h; | ||
| var _a, _b, _c, _d, _e, _f, _g, _h, _i, _j; | ||
| const functionNames = openAiPayload.tools ? new Set(openAiPayload.tools.map((fn) => fn.function.name)) : null; | ||
@@ -384,2 +415,3 @@ const { endpoint, headers } = buildOpenAIRequestConfig( | ||
| let paragraph = ""; | ||
| let reasoning = ""; | ||
| const toolCallAccumulators = []; | ||
@@ -419,3 +451,4 @@ const reader = response.body.getReader(); | ||
| toolCallAccumulators, | ||
| functionNames | ||
| functionNames, | ||
| reasoning | ||
| ); | ||
@@ -450,2 +483,4 @@ } | ||
| } | ||
| if (toolCall.id) | ||
| toolCallAccumulators[idx].id = toolCall.id; | ||
| if ((_e = toolCall.function) == null ? void 0 : _e.name) | ||
@@ -460,2 +495,5 @@ toolCallAccumulators[idx].name += toolCall.function.name; | ||
| paragraph += text; | ||
| const reasoningDelta = (_j = (_i = json.choices[0]) == null ? void 0 : _i.delta) == null ? void 0 : _j.reasoning; | ||
| if (reasoningDelta) | ||
| reasoning += reasoningDelta; | ||
| } | ||
@@ -465,3 +503,3 @@ } | ||
| async function callOpenAI(id, openAiPayload, openAiConfig) { | ||
| var _a, _b, _c, _d, _e; | ||
| var _a, _b, _c, _d, _e, _f, _g, _h, _i, _j; | ||
| const { endpoint, headers } = buildOpenAIRequestConfig( | ||
@@ -494,4 +532,6 @@ id, | ||
| if (toolCalls == null ? void 0 : toolCalls.length) { | ||
| for (const tc of toolCalls) { | ||
| for (let i = 0; i < toolCalls.length; i++) { | ||
| const tc = toolCalls[i]; | ||
| functionCalls.push({ | ||
| id: (_c = tc.id) != null ? _c : `call_${i}`, | ||
| name: tc.function.name, | ||
@@ -503,2 +543,3 @@ arguments: JSON.parse(tc.function.arguments) | ||
| functionCalls.push({ | ||
| id: "call_0", | ||
| name: choice.function_call.name, | ||
@@ -508,3 +549,3 @@ arguments: JSON.parse(choice.function_call.arguments) | ||
| } | ||
| if (!((_c = choice.message) == null ? void 0 : _c.content) && !functionCalls.length) { | ||
| if (!((_d = choice.message) == null ? void 0 : _d.content) && !functionCalls.length) { | ||
| logger_default.error( | ||
@@ -525,2 +566,4 @@ id, | ||
| files: [], | ||
| reasoning: (_f = (_e = choice.message) == null ? void 0 : _e.reasoning) != null ? _f : void 0, | ||
| reasoningDetails: (_h = (_g = choice.message) == null ? void 0 : _g.reasoning_details) != null ? _h : void 0, | ||
| usage: data.usage ? { | ||
@@ -530,3 +573,3 @@ prompt_tokens: data.usage.prompt_tokens, | ||
| total_tokens: data.usage.total_tokens, | ||
| cached_tokens: (_e = (_d = data.usage.prompt_tokens_details) == null ? void 0 : _d.cached_tokens) != null ? _e : 0 | ||
| cached_tokens: (_j = (_i = data.usage.prompt_tokens_details) == null ? void 0 : _i.cached_tokens) != null ? _j : 0 | ||
| } : null | ||
@@ -584,3 +627,4 @@ }; | ||
| function jigAnthropicMessages(messages) { | ||
| var _a, _b; | ||
| var _a; | ||
| const hasToolBlock = (content) => Array.isArray(content) && content.some((b) => b.type === "tool_use" || b.type === "tool_result"); | ||
| let jiggedMessages = messages.slice(); | ||
@@ -600,7 +644,4 @@ if (((_a = jiggedMessages[0]) == null ? void 0 : _a.role) !== "user") { | ||
| const newContent = Array.isArray(message.content) ? message.content : [{ type: "text", text: message.content }]; | ||
| lastMessage.content = [ | ||
| ...lastContent, | ||
| { type: "text", text: "\n\n---\n\n" }, | ||
| ...newContent | ||
| ]; | ||
| const separator = hasToolBlock(lastMessage.content) || hasToolBlock(message.content) ? [] : [{ type: "text", text: "\n\n---\n\n" }]; | ||
| lastMessage.content = [...lastContent, ...separator, ...newContent]; | ||
| return acc; | ||
@@ -613,3 +654,4 @@ } | ||
| }, []); | ||
| if (((_b = jiggedMessages[jiggedMessages.length - 1]) == null ? void 0 : _b.role) === "assistant") { | ||
| const last = jiggedMessages[jiggedMessages.length - 1]; | ||
| if ((last == null ? void 0 : last.role) === "assistant" && !hasToolBlock(last.content)) { | ||
| jiggedMessages.push({ role: "user", content: "..." }); | ||
@@ -631,2 +673,13 @@ } | ||
| } | ||
| if (message.role === "tool") { | ||
| preparedPayload.messages.push({ | ||
| role: "user", | ||
| content: (message.toolResults || []).map((tr) => ({ | ||
| type: "tool_result", | ||
| tool_use_id: tr.toolCallId, | ||
| content: tr.content | ||
| })) | ||
| }); | ||
| continue; | ||
| } | ||
| const contentBlocks = []; | ||
@@ -669,5 +722,15 @@ if (message.content) { | ||
| } | ||
| const leadingBlocks = message.role === "assistant" && Array.isArray(message.reasoningDetails) ? message.reasoningDetails : []; | ||
| const toolUseBlocks = (message.functionCalls || []).map((fc, i) => { | ||
| var _a; | ||
| return { | ||
| type: "tool_use", | ||
| id: (_a = fc.id) != null ? _a : `call_${i}`, | ||
| name: fc.name, | ||
| input: fc.arguments | ||
| }; | ||
| }); | ||
| preparedPayload.messages.push({ | ||
| role: message.role, | ||
| content: contentBlocks | ||
| content: [...leadingBlocks, ...contentBlocks, ...toolUseBlocks] | ||
| }); | ||
@@ -739,2 +802,3 @@ } | ||
| const functionCalls = []; | ||
| const reasoningBlocks = []; | ||
| for (const answer of answers) { | ||
@@ -759,5 +823,8 @@ if (!answer.type) { | ||
| functionCalls.push({ | ||
| id: answer.id, | ||
| name: answer.name, | ||
| arguments: answer.input | ||
| }); | ||
| } else if (answer.type === "thinking" || answer.type === "redacted_thinking") { | ||
| reasoningBlocks.push(answer); | ||
| } | ||
@@ -791,2 +858,3 @@ } | ||
| files: [], | ||
| reasoningDetails: reasoningBlocks.length ? reasoningBlocks : void 0, | ||
| usage | ||
@@ -806,3 +874,4 @@ }; | ||
| function jigGoogleMessages(messages) { | ||
| var _a, _b; | ||
| var _a; | ||
| const hasFunctionPart = (parts) => parts.some((p) => "functionCall" in p || "functionResponse" in p); | ||
| let jiggedMessages = messages.slice(); | ||
@@ -825,3 +894,4 @@ if (((_a = jiggedMessages[0]) == null ? void 0 : _a.role) === "model") { | ||
| }, []); | ||
| if (((_b = jiggedMessages[jiggedMessages.length - 1]) == null ? void 0 : _b.role) === "model") { | ||
| const last = jiggedMessages[jiggedMessages.length - 1]; | ||
| if ((last == null ? void 0 : last.role) === "model" && !hasFunctionPart(last.parts)) { | ||
| jiggedMessages.push({ role: "user", parts: [{ text: "..." }] }); | ||
@@ -845,2 +915,9 @@ } | ||
| }; | ||
| const toolNameById = /* @__PURE__ */ new Map(); | ||
| for (const m of payload.messages) { | ||
| for (const fc of m.functionCalls || []) { | ||
| if (fc.id) | ||
| toolNameById.set(fc.id, fc.name); | ||
| } | ||
| } | ||
| for (const message of payload.messages) { | ||
@@ -851,2 +928,18 @@ if (message.role === "system") { | ||
| } | ||
| if (message.role === "tool") { | ||
| preparedPayload.messages.push({ | ||
| role: "user", | ||
| parts: (message.toolResults || []).map((tr) => { | ||
| var _a, _b; | ||
| return { | ||
| functionResponse: { | ||
| id: tr.toolCallId, | ||
| name: (_b = (_a = tr.name) != null ? _a : toolNameById.get(tr.toolCallId)) != null ? _b : "", | ||
| response: { output: tr.content } | ||
| } | ||
| }; | ||
| }) | ||
| }); | ||
| continue; | ||
| } | ||
| const parts = []; | ||
@@ -880,2 +973,13 @@ if (message.content) { | ||
| } | ||
| for (const fc of message.functionCalls || []) { | ||
| parts.push({ | ||
| functionCall: { | ||
| id: fc.id, | ||
| name: fc.name, | ||
| args: fc.arguments | ||
| }, | ||
| // Gemini requires its thoughtSignature echoed back on the call part. | ||
| ...fc.thoughtSignature ? { thoughtSignature: fc.thoughtSignature } : {} | ||
| }); | ||
| } | ||
| preparedPayload.messages.push({ | ||
@@ -889,35 +993,66 @@ role: message.role === "assistant" ? "model" : message.role, | ||
| async function callGoogleAI(id, payload) { | ||
| var _a, _b, _c, _d, _e, _f, _g, _h, _i, _j; | ||
| const googleMessages = jigGoogleMessages(payload.messages); | ||
| const history = googleMessages.slice(0, -1); | ||
| const lastMessage = googleMessages.slice(-1)[0]; | ||
| const genAI = new import_genai.GoogleGenAI({ apiKey: process.env.GEMINI_API_KEY }); | ||
| const chat = genAI.chats.create({ | ||
| model: payload.model, | ||
| history, | ||
| config: { | ||
| responseModalities: ["Text"], | ||
| tools: payload.tools ? [payload.tools] : void 0, | ||
| systemInstruction: payload.systemInstruction | ||
| } | ||
| }); | ||
| const response = await chat.sendMessage({ message: lastMessage.parts }); | ||
| var _a, _b, _c, _d, _e, _f, _g, _h, _i, _j, _k, _l, _m, _n, _o, _p, _q, _r; | ||
| const contents = jigGoogleMessages(payload.messages); | ||
| const requestBody = { | ||
| contents, | ||
| generationConfig: { responseModalities: ["TEXT"] } | ||
| }; | ||
| if (payload.tools) | ||
| requestBody.tools = [payload.tools]; | ||
| if (payload.systemInstruction) { | ||
| requestBody.systemInstruction = { | ||
| parts: [{ text: payload.systemInstruction }] | ||
| }; | ||
| } | ||
| let response; | ||
| try { | ||
| const httpResponse = await import_axios.default.post( | ||
| `https://generativelanguage.googleapis.com/v1beta/models/${payload.model}:generateContent`, | ||
| requestBody, | ||
| { | ||
| headers: { | ||
| "content-type": "application/json", | ||
| "x-goog-api-key": process.env.GEMINI_API_KEY | ||
| }, | ||
| timeout: 6e4 | ||
| } | ||
| ); | ||
| response = httpResponse.data; | ||
| } catch (err) { | ||
| const apiError = (_b = (_a = err == null ? void 0 : err.response) == null ? void 0 : _a.data) == null ? void 0 : _b.error; | ||
| const wrapped = new Error( | ||
| (apiError == null ? void 0 : apiError.message) || (err == null ? void 0 : err.message) || "Google AI API request failed" | ||
| ); | ||
| wrapped.status = (_d = apiError == null ? void 0 : apiError.status) != null ? _d : (_c = err == null ? void 0 : err.response) == null ? void 0 : _c.status; | ||
| wrapped.code = apiError == null ? void 0 : apiError.code; | ||
| wrapped.details = apiError == null ? void 0 : apiError.details; | ||
| wrapped.promptFeedback = (_f = (_e = err == null ? void 0 : err.response) == null ? void 0 : _e.data) == null ? void 0 : _f.promptFeedback; | ||
| throw wrapped; | ||
| } | ||
| let text = ""; | ||
| const files = []; | ||
| for (const part of ((_c = (_b = (_a = response.candidates) == null ? void 0 : _a[0]) == null ? void 0 : _b.content) == null ? void 0 : _c.parts) || []) { | ||
| const reasoningParts = []; | ||
| const functionCalls = []; | ||
| for (const part of ((_i = (_h = (_g = response.candidates) == null ? void 0 : _g[0]) == null ? void 0 : _h.content) == null ? void 0 : _i.parts) || []) { | ||
| if (part.thought) { | ||
| reasoningParts.push(part); | ||
| continue; | ||
| } | ||
| if (part.functionCall) { | ||
| functionCalls.push({ | ||
| id: (_j = part.functionCall.id) != null ? _j : `call_${functionCalls.length}`, | ||
| name: (_k = part.functionCall.name) != null ? _k : "", | ||
| arguments: (_l = part.functionCall.args) != null ? _l : {}, | ||
| thoughtSignature: part.thoughtSignature | ||
| }); | ||
| continue; | ||
| } | ||
| if (part.text) | ||
| text += part.text; | ||
| if ((_d = part.inlineData) == null ? void 0 : _d.data) { | ||
| if ((_m = part.inlineData) == null ? void 0 : _m.data) { | ||
| files.push({ mimeType: "image/png", data: part.inlineData.data }); | ||
| } | ||
| } | ||
| const functionCalls = (_e = response.functionCalls) == null ? void 0 : _e.map((fc) => { | ||
| var _a2, _b2; | ||
| return { | ||
| name: (_a2 = fc.name) != null ? _a2 : "", | ||
| arguments: (_b2 = fc.args) != null ? _b2 : {} | ||
| }; | ||
| }); | ||
| if (!text && !(functionCalls == null ? void 0 : functionCalls.length) && !files.length) { | ||
| const candidate = (_f = response.candidates) == null ? void 0 : _f[0]; | ||
| if (!text && !functionCalls.length && !files.length) { | ||
| const candidate = (_n = response.candidates) == null ? void 0 : _n[0]; | ||
| const finishReason = candidate == null ? void 0 : candidate.finishReason; | ||
@@ -953,9 +1088,10 @@ logger_default.error(id, "Missing text & functions in Google AI API response:", { | ||
| files, | ||
| function_call: (functionCalls == null ? void 0 : functionCalls[0]) || null, | ||
| function_calls: functionCalls || [], | ||
| function_call: functionCalls[0] || null, | ||
| function_calls: functionCalls, | ||
| reasoningDetails: reasoningParts.length ? reasoningParts : void 0, | ||
| usage: response.usageMetadata ? { | ||
| prompt_tokens: (_g = response.usageMetadata.promptTokenCount) != null ? _g : 0, | ||
| completion_tokens: (_h = response.usageMetadata.candidatesTokenCount) != null ? _h : 0, | ||
| total_tokens: (_i = response.usageMetadata.totalTokenCount) != null ? _i : 0, | ||
| cached_tokens: (_j = response.usageMetadata.cachedContentTokenCount) != null ? _j : 0 | ||
| prompt_tokens: (_o = response.usageMetadata.promptTokenCount) != null ? _o : 0, | ||
| completion_tokens: (_p = response.usageMetadata.candidatesTokenCount) != null ? _p : 0, | ||
| total_tokens: (_q = response.usageMetadata.totalTokenCount) != null ? _q : 0, | ||
| cached_tokens: (_r = response.usageMetadata.cachedContentTokenCount) != null ? _r : 0 | ||
| } : null | ||
@@ -1056,2 +1192,43 @@ }; | ||
| } | ||
| function prepareOpenAICompatMessages(messages) { | ||
| var _a; | ||
| const out = []; | ||
| for (const message of messages) { | ||
| if (message.role === "tool") { | ||
| for (const tr of message.toolResults || []) { | ||
| out.push({ | ||
| role: "tool", | ||
| tool_call_id: tr.toolCallId, | ||
| content: tr.content | ||
| }); | ||
| } | ||
| continue; | ||
| } | ||
| const outMessage = { | ||
| role: message.role, | ||
| content: normalizeMessageContent(message.content) | ||
| }; | ||
| if ((_a = message.functionCalls) == null ? void 0 : _a.length) { | ||
| outMessage.tool_calls = message.functionCalls.map((fc, i) => { | ||
| var _a2; | ||
| return { | ||
| id: (_a2 = fc.id) != null ? _a2 : `call_${i}`, | ||
| type: "function", | ||
| function: { | ||
| name: fc.name, | ||
| arguments: JSON.stringify(fc.arguments) | ||
| } | ||
| }; | ||
| }); | ||
| if (!message.content) | ||
| outMessage.content = null; | ||
| } | ||
| if (message.reasoning) | ||
| outMessage.reasoning = message.reasoning; | ||
| if (message.reasoningDetails) | ||
| outMessage.reasoning_details = message.reasoningDetails; | ||
| out.push(outMessage); | ||
| } | ||
| return out; | ||
| } | ||
| function prepareGroqPayload(payload) { | ||
@@ -1061,6 +1238,3 @@ var _a; | ||
| model: payload.model, | ||
| messages: payload.messages.map((message) => ({ | ||
| role: message.role, | ||
| content: normalizeMessageContent(message.content) | ||
| })), | ||
| messages: prepareOpenAICompatMessages(payload.messages), | ||
| tools: (_a = payload.functions) == null ? void 0 : _a.map((fn) => ({ | ||
@@ -1075,3 +1249,3 @@ type: "function", | ||
| async function callGroq(id, payload) { | ||
| var _a, _b, _c, _d; | ||
| var _a, _b, _c, _d, _e, _f, _g; | ||
| const response = await import_axios.default.post( | ||
@@ -1087,3 +1261,7 @@ "https://api.groq.com/openai/v1/chat/completions", | ||
| ); | ||
| const answer = (_a = response.data.choices[0]) == null ? void 0 : _a.message; | ||
| if (response.data.error) { | ||
| logger_default.error(id, "Groq error:", response.data.error); | ||
| throw new Error(`Groq error: ${response.data.error.message}`); | ||
| } | ||
| const answer = (_b = (_a = response.data.choices) == null ? void 0 : _a[0]) == null ? void 0 : _b.message; | ||
| if (!answer) { | ||
@@ -1094,5 +1272,7 @@ logger_default.error(id, "Missing answer in Groq API response:", response.data); | ||
| const functionCalls = []; | ||
| if ((_b = answer.tool_calls) == null ? void 0 : _b.length) { | ||
| for (const tc of answer.tool_calls) { | ||
| if ((_c = answer.tool_calls) == null ? void 0 : _c.length) { | ||
| for (let i = 0; i < answer.tool_calls.length; i++) { | ||
| const tc = answer.tool_calls[i]; | ||
| functionCalls.push({ | ||
| id: (_d = tc.id) != null ? _d : `call_${i}`, | ||
| name: tc.function.name, | ||
@@ -1119,2 +1299,3 @@ arguments: JSON.parse(tc.function.arguments) | ||
| files: [], | ||
| reasoning: (_e = answer.reasoning) != null ? _e : void 0, | ||
| usage: response.data.usage ? { | ||
@@ -1124,3 +1305,3 @@ prompt_tokens: response.data.usage.prompt_tokens, | ||
| total_tokens: response.data.usage.total_tokens, | ||
| cached_tokens: (_d = (_c = response.data.usage.prompt_tokens_details) == null ? void 0 : _c.cached_tokens) != null ? _d : 0 | ||
| cached_tokens: (_g = (_f = response.data.usage.prompt_tokens_details) == null ? void 0 : _f.cached_tokens) != null ? _g : 0 | ||
| } : null | ||
@@ -1136,6 +1317,3 @@ }; | ||
| model: payload.model, | ||
| messages: payload.messages.map((message) => ({ | ||
| role: message.role, | ||
| content: normalizeMessageContent(message.content) | ||
| })), | ||
| messages: prepareOpenAICompatMessages(payload.messages), | ||
| tools: (_a = payload.functions) == null ? void 0 : _a.map((fn) => ({ | ||
@@ -1151,3 +1329,3 @@ type: "function", | ||
| async function callOpenRouter(id, payload) { | ||
| var _a, _b, _c, _d; | ||
| var _a, _b, _c, _d, _e, _f, _g, _h; | ||
| const response = await import_axios.default.post( | ||
@@ -1163,3 +1341,7 @@ "https://openrouter.ai/api/v1/chat/completions", | ||
| ); | ||
| const answer = (_a = response.data.choices[0]) == null ? void 0 : _a.message; | ||
| if (response.data.error) { | ||
| logger_default.error(id, "OpenRouter error:", response.data.error); | ||
| throw new Error(`OpenRouter error: ${response.data.error.message}`); | ||
| } | ||
| const answer = (_b = (_a = response.data.choices) == null ? void 0 : _a[0]) == null ? void 0 : _b.message; | ||
| if (!answer) { | ||
@@ -1170,5 +1352,7 @@ logger_default.error(id, "Missing answer in OpenRouter API response:", response.data); | ||
| const functionCalls = []; | ||
| if ((_b = answer.tool_calls) == null ? void 0 : _b.length) { | ||
| for (const tc of answer.tool_calls) { | ||
| if ((_c = answer.tool_calls) == null ? void 0 : _c.length) { | ||
| for (let i = 0; i < answer.tool_calls.length; i++) { | ||
| const tc = answer.tool_calls[i]; | ||
| functionCalls.push({ | ||
| id: (_d = tc.id) != null ? _d : `call_${i}`, | ||
| name: tc.function.name, | ||
@@ -1195,2 +1379,4 @@ arguments: JSON.parse(tc.function.arguments) | ||
| files: [], | ||
| reasoning: (_e = answer.reasoning) != null ? _e : void 0, | ||
| reasoningDetails: (_f = answer.reasoning_details) != null ? _f : void 0, | ||
| usage: response.data.usage ? { | ||
@@ -1200,3 +1386,3 @@ prompt_tokens: response.data.usage.prompt_tokens, | ||
| total_tokens: response.data.usage.total_tokens, | ||
| cached_tokens: (_d = (_c = response.data.usage.prompt_tokens_details) == null ? void 0 : _c.cached_tokens) != null ? _d : 0 | ||
| cached_tokens: (_h = (_g = response.data.usage.prompt_tokens_details) == null ? void 0 : _g.cached_tokens) != null ? _h : 0 | ||
| } : null | ||
@@ -1203,0 +1389,0 @@ }; |
+259
-73
@@ -111,3 +111,2 @@ var __require = /* @__PURE__ */ ((x) => typeof require !== "undefined" ? require : typeof Proxy !== "undefined" ? new Proxy(x, { | ||
| // index.ts | ||
| import { GoogleGenAI } from "@google/genai"; | ||
| var sharp = __require("sharp"); | ||
@@ -143,5 +142,6 @@ var decode = __require("heic-decode"); | ||
| } | ||
| function parseStreamedResponse(identifier, paragraph, toolCallAccumulators, allowedFunctionNames) { | ||
| function parseStreamedResponse(identifier, paragraph, toolCallAccumulators, allowedFunctionNames, reasoning) { | ||
| const functionCalls = []; | ||
| for (const acc of toolCallAccumulators) { | ||
| for (let i = 0; i < toolCallAccumulators.length; i++) { | ||
| const acc = toolCallAccumulators[i]; | ||
| if (!acc.name || !acc.arguments) | ||
@@ -156,2 +156,3 @@ continue; | ||
| functionCalls.push({ | ||
| id: acc.id || `call_${i}`, | ||
| name: acc.name, | ||
@@ -185,2 +186,3 @@ arguments: JSON.parse(acc.arguments) | ||
| files: [], | ||
| reasoning: reasoning || void 0, | ||
| usage: null | ||
@@ -287,3 +289,3 @@ }; | ||
| async function prepareOpenAIPayload(identifier, payload) { | ||
| var _a; | ||
| var _a, _b; | ||
| const preparedPayload = { | ||
@@ -299,2 +301,12 @@ model: payload.model, | ||
| for (const message of payload.messages) { | ||
| if (message.role === "tool") { | ||
| for (const tr of message.toolResults || []) { | ||
| preparedPayload.messages.push({ | ||
| role: "tool", | ||
| tool_call_id: tr.toolCallId, | ||
| content: tr.content | ||
| }); | ||
| } | ||
| continue; | ||
| } | ||
| const contentBlocks = []; | ||
@@ -325,6 +337,25 @@ if (message.content) { | ||
| } | ||
| preparedPayload.messages.push({ | ||
| const outMessage = { | ||
| role: message.role, | ||
| content: contentBlocks | ||
| }); | ||
| // OpenAI wants null (not []) content on a tool-call-only assistant turn. | ||
| content: contentBlocks.length ? contentBlocks : null | ||
| }; | ||
| if ((_b = message.functionCalls) == null ? void 0 : _b.length) { | ||
| outMessage.tool_calls = message.functionCalls.map((fc, i) => { | ||
| var _a2; | ||
| return { | ||
| id: (_a2 = fc.id) != null ? _a2 : `call_${i}`, | ||
| type: "function", | ||
| function: { | ||
| name: fc.name, | ||
| arguments: JSON.stringify(fc.arguments) | ||
| } | ||
| }; | ||
| }); | ||
| } | ||
| if (message.reasoning) | ||
| outMessage.reasoning = message.reasoning; | ||
| if (message.reasoningDetails) | ||
| outMessage.reasoning_details = message.reasoningDetails; | ||
| preparedPayload.messages.push(outMessage); | ||
| } | ||
@@ -334,3 +365,3 @@ return preparedPayload; | ||
| async function callOpenAIStream(id, openAiPayload, openAiConfig, chunkTimeoutMs) { | ||
| var _a, _b, _c, _d, _e, _f, _g, _h; | ||
| var _a, _b, _c, _d, _e, _f, _g, _h, _i, _j; | ||
| const functionNames = openAiPayload.tools ? new Set(openAiPayload.tools.map((fn) => fn.function.name)) : null; | ||
@@ -353,2 +384,3 @@ const { endpoint, headers } = buildOpenAIRequestConfig( | ||
| let paragraph = ""; | ||
| let reasoning = ""; | ||
| const toolCallAccumulators = []; | ||
@@ -388,3 +420,4 @@ const reader = response.body.getReader(); | ||
| toolCallAccumulators, | ||
| functionNames | ||
| functionNames, | ||
| reasoning | ||
| ); | ||
@@ -419,2 +452,4 @@ } | ||
| } | ||
| if (toolCall.id) | ||
| toolCallAccumulators[idx].id = toolCall.id; | ||
| if ((_e = toolCall.function) == null ? void 0 : _e.name) | ||
@@ -429,2 +464,5 @@ toolCallAccumulators[idx].name += toolCall.function.name; | ||
| paragraph += text; | ||
| const reasoningDelta = (_j = (_i = json.choices[0]) == null ? void 0 : _i.delta) == null ? void 0 : _j.reasoning; | ||
| if (reasoningDelta) | ||
| reasoning += reasoningDelta; | ||
| } | ||
@@ -434,3 +472,3 @@ } | ||
| async function callOpenAI(id, openAiPayload, openAiConfig) { | ||
| var _a, _b, _c, _d, _e; | ||
| var _a, _b, _c, _d, _e, _f, _g, _h, _i, _j; | ||
| const { endpoint, headers } = buildOpenAIRequestConfig( | ||
@@ -463,4 +501,6 @@ id, | ||
| if (toolCalls == null ? void 0 : toolCalls.length) { | ||
| for (const tc of toolCalls) { | ||
| for (let i = 0; i < toolCalls.length; i++) { | ||
| const tc = toolCalls[i]; | ||
| functionCalls.push({ | ||
| id: (_c = tc.id) != null ? _c : `call_${i}`, | ||
| name: tc.function.name, | ||
@@ -472,2 +512,3 @@ arguments: JSON.parse(tc.function.arguments) | ||
| functionCalls.push({ | ||
| id: "call_0", | ||
| name: choice.function_call.name, | ||
@@ -477,3 +518,3 @@ arguments: JSON.parse(choice.function_call.arguments) | ||
| } | ||
| if (!((_c = choice.message) == null ? void 0 : _c.content) && !functionCalls.length) { | ||
| if (!((_d = choice.message) == null ? void 0 : _d.content) && !functionCalls.length) { | ||
| logger_default.error( | ||
@@ -494,2 +535,4 @@ id, | ||
| files: [], | ||
| reasoning: (_f = (_e = choice.message) == null ? void 0 : _e.reasoning) != null ? _f : void 0, | ||
| reasoningDetails: (_h = (_g = choice.message) == null ? void 0 : _g.reasoning_details) != null ? _h : void 0, | ||
| usage: data.usage ? { | ||
@@ -499,3 +542,3 @@ prompt_tokens: data.usage.prompt_tokens, | ||
| total_tokens: data.usage.total_tokens, | ||
| cached_tokens: (_e = (_d = data.usage.prompt_tokens_details) == null ? void 0 : _d.cached_tokens) != null ? _e : 0 | ||
| cached_tokens: (_j = (_i = data.usage.prompt_tokens_details) == null ? void 0 : _i.cached_tokens) != null ? _j : 0 | ||
| } : null | ||
@@ -553,3 +596,4 @@ }; | ||
| function jigAnthropicMessages(messages) { | ||
| var _a, _b; | ||
| var _a; | ||
| const hasToolBlock = (content) => Array.isArray(content) && content.some((b) => b.type === "tool_use" || b.type === "tool_result"); | ||
| let jiggedMessages = messages.slice(); | ||
@@ -569,7 +613,4 @@ if (((_a = jiggedMessages[0]) == null ? void 0 : _a.role) !== "user") { | ||
| const newContent = Array.isArray(message.content) ? message.content : [{ type: "text", text: message.content }]; | ||
| lastMessage.content = [ | ||
| ...lastContent, | ||
| { type: "text", text: "\n\n---\n\n" }, | ||
| ...newContent | ||
| ]; | ||
| const separator = hasToolBlock(lastMessage.content) || hasToolBlock(message.content) ? [] : [{ type: "text", text: "\n\n---\n\n" }]; | ||
| lastMessage.content = [...lastContent, ...separator, ...newContent]; | ||
| return acc; | ||
@@ -582,3 +623,4 @@ } | ||
| }, []); | ||
| if (((_b = jiggedMessages[jiggedMessages.length - 1]) == null ? void 0 : _b.role) === "assistant") { | ||
| const last = jiggedMessages[jiggedMessages.length - 1]; | ||
| if ((last == null ? void 0 : last.role) === "assistant" && !hasToolBlock(last.content)) { | ||
| jiggedMessages.push({ role: "user", content: "..." }); | ||
@@ -600,2 +642,13 @@ } | ||
| } | ||
| if (message.role === "tool") { | ||
| preparedPayload.messages.push({ | ||
| role: "user", | ||
| content: (message.toolResults || []).map((tr) => ({ | ||
| type: "tool_result", | ||
| tool_use_id: tr.toolCallId, | ||
| content: tr.content | ||
| })) | ||
| }); | ||
| continue; | ||
| } | ||
| const contentBlocks = []; | ||
@@ -638,5 +691,15 @@ if (message.content) { | ||
| } | ||
| const leadingBlocks = message.role === "assistant" && Array.isArray(message.reasoningDetails) ? message.reasoningDetails : []; | ||
| const toolUseBlocks = (message.functionCalls || []).map((fc, i) => { | ||
| var _a; | ||
| return { | ||
| type: "tool_use", | ||
| id: (_a = fc.id) != null ? _a : `call_${i}`, | ||
| name: fc.name, | ||
| input: fc.arguments | ||
| }; | ||
| }); | ||
| preparedPayload.messages.push({ | ||
| role: message.role, | ||
| content: contentBlocks | ||
| content: [...leadingBlocks, ...contentBlocks, ...toolUseBlocks] | ||
| }); | ||
@@ -708,2 +771,3 @@ } | ||
| const functionCalls = []; | ||
| const reasoningBlocks = []; | ||
| for (const answer of answers) { | ||
@@ -728,5 +792,8 @@ if (!answer.type) { | ||
| functionCalls.push({ | ||
| id: answer.id, | ||
| name: answer.name, | ||
| arguments: answer.input | ||
| }); | ||
| } else if (answer.type === "thinking" || answer.type === "redacted_thinking") { | ||
| reasoningBlocks.push(answer); | ||
| } | ||
@@ -760,2 +827,3 @@ } | ||
| files: [], | ||
| reasoningDetails: reasoningBlocks.length ? reasoningBlocks : void 0, | ||
| usage | ||
@@ -775,3 +843,4 @@ }; | ||
| function jigGoogleMessages(messages) { | ||
| var _a, _b; | ||
| var _a; | ||
| const hasFunctionPart = (parts) => parts.some((p) => "functionCall" in p || "functionResponse" in p); | ||
| let jiggedMessages = messages.slice(); | ||
@@ -794,3 +863,4 @@ if (((_a = jiggedMessages[0]) == null ? void 0 : _a.role) === "model") { | ||
| }, []); | ||
| if (((_b = jiggedMessages[jiggedMessages.length - 1]) == null ? void 0 : _b.role) === "model") { | ||
| const last = jiggedMessages[jiggedMessages.length - 1]; | ||
| if ((last == null ? void 0 : last.role) === "model" && !hasFunctionPart(last.parts)) { | ||
| jiggedMessages.push({ role: "user", parts: [{ text: "..." }] }); | ||
@@ -814,2 +884,9 @@ } | ||
| }; | ||
| const toolNameById = /* @__PURE__ */ new Map(); | ||
| for (const m of payload.messages) { | ||
| for (const fc of m.functionCalls || []) { | ||
| if (fc.id) | ||
| toolNameById.set(fc.id, fc.name); | ||
| } | ||
| } | ||
| for (const message of payload.messages) { | ||
@@ -820,2 +897,18 @@ if (message.role === "system") { | ||
| } | ||
| if (message.role === "tool") { | ||
| preparedPayload.messages.push({ | ||
| role: "user", | ||
| parts: (message.toolResults || []).map((tr) => { | ||
| var _a, _b; | ||
| return { | ||
| functionResponse: { | ||
| id: tr.toolCallId, | ||
| name: (_b = (_a = tr.name) != null ? _a : toolNameById.get(tr.toolCallId)) != null ? _b : "", | ||
| response: { output: tr.content } | ||
| } | ||
| }; | ||
| }) | ||
| }); | ||
| continue; | ||
| } | ||
| const parts = []; | ||
@@ -849,2 +942,13 @@ if (message.content) { | ||
| } | ||
| for (const fc of message.functionCalls || []) { | ||
| parts.push({ | ||
| functionCall: { | ||
| id: fc.id, | ||
| name: fc.name, | ||
| args: fc.arguments | ||
| }, | ||
| // Gemini requires its thoughtSignature echoed back on the call part. | ||
| ...fc.thoughtSignature ? { thoughtSignature: fc.thoughtSignature } : {} | ||
| }); | ||
| } | ||
| preparedPayload.messages.push({ | ||
@@ -858,35 +962,66 @@ role: message.role === "assistant" ? "model" : message.role, | ||
| async function callGoogleAI(id, payload) { | ||
| var _a, _b, _c, _d, _e, _f, _g, _h, _i, _j; | ||
| const googleMessages = jigGoogleMessages(payload.messages); | ||
| const history = googleMessages.slice(0, -1); | ||
| const lastMessage = googleMessages.slice(-1)[0]; | ||
| const genAI = new GoogleGenAI({ apiKey: process.env.GEMINI_API_KEY }); | ||
| const chat = genAI.chats.create({ | ||
| model: payload.model, | ||
| history, | ||
| config: { | ||
| responseModalities: ["Text"], | ||
| tools: payload.tools ? [payload.tools] : void 0, | ||
| systemInstruction: payload.systemInstruction | ||
| } | ||
| }); | ||
| const response = await chat.sendMessage({ message: lastMessage.parts }); | ||
| var _a, _b, _c, _d, _e, _f, _g, _h, _i, _j, _k, _l, _m, _n, _o, _p, _q, _r; | ||
| const contents = jigGoogleMessages(payload.messages); | ||
| const requestBody = { | ||
| contents, | ||
| generationConfig: { responseModalities: ["TEXT"] } | ||
| }; | ||
| if (payload.tools) | ||
| requestBody.tools = [payload.tools]; | ||
| if (payload.systemInstruction) { | ||
| requestBody.systemInstruction = { | ||
| parts: [{ text: payload.systemInstruction }] | ||
| }; | ||
| } | ||
| let response; | ||
| try { | ||
| const httpResponse = await axios.post( | ||
| `https://generativelanguage.googleapis.com/v1beta/models/${payload.model}:generateContent`, | ||
| requestBody, | ||
| { | ||
| headers: { | ||
| "content-type": "application/json", | ||
| "x-goog-api-key": process.env.GEMINI_API_KEY | ||
| }, | ||
| timeout: 6e4 | ||
| } | ||
| ); | ||
| response = httpResponse.data; | ||
| } catch (err) { | ||
| const apiError = (_b = (_a = err == null ? void 0 : err.response) == null ? void 0 : _a.data) == null ? void 0 : _b.error; | ||
| const wrapped = new Error( | ||
| (apiError == null ? void 0 : apiError.message) || (err == null ? void 0 : err.message) || "Google AI API request failed" | ||
| ); | ||
| wrapped.status = (_d = apiError == null ? void 0 : apiError.status) != null ? _d : (_c = err == null ? void 0 : err.response) == null ? void 0 : _c.status; | ||
| wrapped.code = apiError == null ? void 0 : apiError.code; | ||
| wrapped.details = apiError == null ? void 0 : apiError.details; | ||
| wrapped.promptFeedback = (_f = (_e = err == null ? void 0 : err.response) == null ? void 0 : _e.data) == null ? void 0 : _f.promptFeedback; | ||
| throw wrapped; | ||
| } | ||
| let text = ""; | ||
| const files = []; | ||
| for (const part of ((_c = (_b = (_a = response.candidates) == null ? void 0 : _a[0]) == null ? void 0 : _b.content) == null ? void 0 : _c.parts) || []) { | ||
| const reasoningParts = []; | ||
| const functionCalls = []; | ||
| for (const part of ((_i = (_h = (_g = response.candidates) == null ? void 0 : _g[0]) == null ? void 0 : _h.content) == null ? void 0 : _i.parts) || []) { | ||
| if (part.thought) { | ||
| reasoningParts.push(part); | ||
| continue; | ||
| } | ||
| if (part.functionCall) { | ||
| functionCalls.push({ | ||
| id: (_j = part.functionCall.id) != null ? _j : `call_${functionCalls.length}`, | ||
| name: (_k = part.functionCall.name) != null ? _k : "", | ||
| arguments: (_l = part.functionCall.args) != null ? _l : {}, | ||
| thoughtSignature: part.thoughtSignature | ||
| }); | ||
| continue; | ||
| } | ||
| if (part.text) | ||
| text += part.text; | ||
| if ((_d = part.inlineData) == null ? void 0 : _d.data) { | ||
| if ((_m = part.inlineData) == null ? void 0 : _m.data) { | ||
| files.push({ mimeType: "image/png", data: part.inlineData.data }); | ||
| } | ||
| } | ||
| const functionCalls = (_e = response.functionCalls) == null ? void 0 : _e.map((fc) => { | ||
| var _a2, _b2; | ||
| return { | ||
| name: (_a2 = fc.name) != null ? _a2 : "", | ||
| arguments: (_b2 = fc.args) != null ? _b2 : {} | ||
| }; | ||
| }); | ||
| if (!text && !(functionCalls == null ? void 0 : functionCalls.length) && !files.length) { | ||
| const candidate = (_f = response.candidates) == null ? void 0 : _f[0]; | ||
| if (!text && !functionCalls.length && !files.length) { | ||
| const candidate = (_n = response.candidates) == null ? void 0 : _n[0]; | ||
| const finishReason = candidate == null ? void 0 : candidate.finishReason; | ||
@@ -922,9 +1057,10 @@ logger_default.error(id, "Missing text & functions in Google AI API response:", { | ||
| files, | ||
| function_call: (functionCalls == null ? void 0 : functionCalls[0]) || null, | ||
| function_calls: functionCalls || [], | ||
| function_call: functionCalls[0] || null, | ||
| function_calls: functionCalls, | ||
| reasoningDetails: reasoningParts.length ? reasoningParts : void 0, | ||
| usage: response.usageMetadata ? { | ||
| prompt_tokens: (_g = response.usageMetadata.promptTokenCount) != null ? _g : 0, | ||
| completion_tokens: (_h = response.usageMetadata.candidatesTokenCount) != null ? _h : 0, | ||
| total_tokens: (_i = response.usageMetadata.totalTokenCount) != null ? _i : 0, | ||
| cached_tokens: (_j = response.usageMetadata.cachedContentTokenCount) != null ? _j : 0 | ||
| prompt_tokens: (_o = response.usageMetadata.promptTokenCount) != null ? _o : 0, | ||
| completion_tokens: (_p = response.usageMetadata.candidatesTokenCount) != null ? _p : 0, | ||
| total_tokens: (_q = response.usageMetadata.totalTokenCount) != null ? _q : 0, | ||
| cached_tokens: (_r = response.usageMetadata.cachedContentTokenCount) != null ? _r : 0 | ||
| } : null | ||
@@ -1025,2 +1161,43 @@ }; | ||
| } | ||
| function prepareOpenAICompatMessages(messages) { | ||
| var _a; | ||
| const out = []; | ||
| for (const message of messages) { | ||
| if (message.role === "tool") { | ||
| for (const tr of message.toolResults || []) { | ||
| out.push({ | ||
| role: "tool", | ||
| tool_call_id: tr.toolCallId, | ||
| content: tr.content | ||
| }); | ||
| } | ||
| continue; | ||
| } | ||
| const outMessage = { | ||
| role: message.role, | ||
| content: normalizeMessageContent(message.content) | ||
| }; | ||
| if ((_a = message.functionCalls) == null ? void 0 : _a.length) { | ||
| outMessage.tool_calls = message.functionCalls.map((fc, i) => { | ||
| var _a2; | ||
| return { | ||
| id: (_a2 = fc.id) != null ? _a2 : `call_${i}`, | ||
| type: "function", | ||
| function: { | ||
| name: fc.name, | ||
| arguments: JSON.stringify(fc.arguments) | ||
| } | ||
| }; | ||
| }); | ||
| if (!message.content) | ||
| outMessage.content = null; | ||
| } | ||
| if (message.reasoning) | ||
| outMessage.reasoning = message.reasoning; | ||
| if (message.reasoningDetails) | ||
| outMessage.reasoning_details = message.reasoningDetails; | ||
| out.push(outMessage); | ||
| } | ||
| return out; | ||
| } | ||
| function prepareGroqPayload(payload) { | ||
@@ -1030,6 +1207,3 @@ var _a; | ||
| model: payload.model, | ||
| messages: payload.messages.map((message) => ({ | ||
| role: message.role, | ||
| content: normalizeMessageContent(message.content) | ||
| })), | ||
| messages: prepareOpenAICompatMessages(payload.messages), | ||
| tools: (_a = payload.functions) == null ? void 0 : _a.map((fn) => ({ | ||
@@ -1044,3 +1218,3 @@ type: "function", | ||
| async function callGroq(id, payload) { | ||
| var _a, _b, _c, _d; | ||
| var _a, _b, _c, _d, _e, _f, _g; | ||
| const response = await axios.post( | ||
@@ -1056,3 +1230,7 @@ "https://api.groq.com/openai/v1/chat/completions", | ||
| ); | ||
| const answer = (_a = response.data.choices[0]) == null ? void 0 : _a.message; | ||
| if (response.data.error) { | ||
| logger_default.error(id, "Groq error:", response.data.error); | ||
| throw new Error(`Groq error: ${response.data.error.message}`); | ||
| } | ||
| const answer = (_b = (_a = response.data.choices) == null ? void 0 : _a[0]) == null ? void 0 : _b.message; | ||
| if (!answer) { | ||
@@ -1063,5 +1241,7 @@ logger_default.error(id, "Missing answer in Groq API response:", response.data); | ||
| const functionCalls = []; | ||
| if ((_b = answer.tool_calls) == null ? void 0 : _b.length) { | ||
| for (const tc of answer.tool_calls) { | ||
| if ((_c = answer.tool_calls) == null ? void 0 : _c.length) { | ||
| for (let i = 0; i < answer.tool_calls.length; i++) { | ||
| const tc = answer.tool_calls[i]; | ||
| functionCalls.push({ | ||
| id: (_d = tc.id) != null ? _d : `call_${i}`, | ||
| name: tc.function.name, | ||
@@ -1088,2 +1268,3 @@ arguments: JSON.parse(tc.function.arguments) | ||
| files: [], | ||
| reasoning: (_e = answer.reasoning) != null ? _e : void 0, | ||
| usage: response.data.usage ? { | ||
@@ -1093,3 +1274,3 @@ prompt_tokens: response.data.usage.prompt_tokens, | ||
| total_tokens: response.data.usage.total_tokens, | ||
| cached_tokens: (_d = (_c = response.data.usage.prompt_tokens_details) == null ? void 0 : _c.cached_tokens) != null ? _d : 0 | ||
| cached_tokens: (_g = (_f = response.data.usage.prompt_tokens_details) == null ? void 0 : _f.cached_tokens) != null ? _g : 0 | ||
| } : null | ||
@@ -1105,6 +1286,3 @@ }; | ||
| model: payload.model, | ||
| messages: payload.messages.map((message) => ({ | ||
| role: message.role, | ||
| content: normalizeMessageContent(message.content) | ||
| })), | ||
| messages: prepareOpenAICompatMessages(payload.messages), | ||
| tools: (_a = payload.functions) == null ? void 0 : _a.map((fn) => ({ | ||
@@ -1120,3 +1298,3 @@ type: "function", | ||
| async function callOpenRouter(id, payload) { | ||
| var _a, _b, _c, _d; | ||
| var _a, _b, _c, _d, _e, _f, _g, _h; | ||
| const response = await axios.post( | ||
@@ -1132,3 +1310,7 @@ "https://openrouter.ai/api/v1/chat/completions", | ||
| ); | ||
| const answer = (_a = response.data.choices[0]) == null ? void 0 : _a.message; | ||
| if (response.data.error) { | ||
| logger_default.error(id, "OpenRouter error:", response.data.error); | ||
| throw new Error(`OpenRouter error: ${response.data.error.message}`); | ||
| } | ||
| const answer = (_b = (_a = response.data.choices) == null ? void 0 : _a[0]) == null ? void 0 : _b.message; | ||
| if (!answer) { | ||
@@ -1139,5 +1321,7 @@ logger_default.error(id, "Missing answer in OpenRouter API response:", response.data); | ||
| const functionCalls = []; | ||
| if ((_b = answer.tool_calls) == null ? void 0 : _b.length) { | ||
| for (const tc of answer.tool_calls) { | ||
| if ((_c = answer.tool_calls) == null ? void 0 : _c.length) { | ||
| for (let i = 0; i < answer.tool_calls.length; i++) { | ||
| const tc = answer.tool_calls[i]; | ||
| functionCalls.push({ | ||
| id: (_d = tc.id) != null ? _d : `call_${i}`, | ||
| name: tc.function.name, | ||
@@ -1164,2 +1348,4 @@ arguments: JSON.parse(tc.function.arguments) | ||
| files: [], | ||
| reasoning: (_e = answer.reasoning) != null ? _e : void 0, | ||
| reasoningDetails: (_f = answer.reasoning_details) != null ? _f : void 0, | ||
| usage: response.data.usage ? { | ||
@@ -1169,3 +1355,3 @@ prompt_tokens: response.data.usage.prompt_tokens, | ||
| total_tokens: response.data.usage.total_tokens, | ||
| cached_tokens: (_d = (_c = response.data.usage.prompt_tokens_details) == null ? void 0 : _c.cached_tokens) != null ? _d : 0 | ||
| cached_tokens: (_h = (_g = response.data.usage.prompt_tokens_details) == null ? void 0 : _g.cached_tokens) != null ? _h : 0 | ||
| } : null | ||
@@ -1172,0 +1358,0 @@ }; |
+1
-1
| { | ||
| "name": "190proof", | ||
| "version": "1.0.96", | ||
| "version": "1.0.97", | ||
| "description": "", | ||
@@ -5,0 +5,0 @@ "main": "./dist/index.js", |
Sorry, the diff of this file is too big to display
Sorry, the diff of this file is too big to display
URL strings
Supply chain riskPackage contains fragments of external URLs or IP addresses, which the package may be accessing at runtime.
URL strings
Supply chain riskPackage contains fragments of external URLs or IP addresses, which the package may be accessing at runtime.
351925
24.62%3138
18.06%