@jini-ai/agent-runtime 0.3.10 → 0.4.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/CHANGELOG.md +103 -0
- package/README.md +34 -17
- package/dist/acp-model-probe.d.ts +6 -4
- package/dist/acp-model-probe.js +3 -3
- package/dist/agent-protocol/acp/account-failure.d.ts +4 -2
- package/dist/agent-protocol/acp/account-failure.js +1 -1
- package/dist/agent-protocol/acp/json.d.ts +6 -6
- package/dist/agent-protocol/acp/json.js +3 -3
- package/dist/agent-protocol/acp/models.d.ts +10 -5
- package/dist/agent-protocol/acp/models.js +32 -31
- package/dist/agent-protocol/acp/session-params.d.ts +3 -1
- package/dist/agent-protocol/acp/session-params.js +2 -1
- package/dist/agent-protocol/acp/session.d.ts +28 -22
- package/dist/agent-protocol/acp/session.js +181 -147
- package/dist/agent-protocol/acp/text-suppression.d.ts +1 -1
- package/dist/agent-protocol/acp/text-suppression.js +1 -1
- package/dist/agent-protocol/acp/types.d.ts +3 -2
- package/dist/agent-protocol/acp/updates.d.ts +11 -11
- package/dist/agent-protocol/acp/updates.js +2 -2
- package/dist/agent-protocol/core/json-line-stream.d.ts +24 -8
- package/dist/agent-protocol/core/json-line-stream.js +8 -8
- package/dist/agent-protocol/pi-rpc/events.d.ts +5 -1
- package/dist/agent-protocol/pi-rpc/events.js +36 -36
- package/dist/agent-protocol/pi-rpc/internal.d.ts +4 -1
- package/dist/agent-protocol/pi-rpc/models.d.ts +3 -1
- package/dist/agent-protocol/pi-rpc/models.js +1 -1
- package/dist/agent-protocol/pi-rpc/session.d.ts +1 -1
- package/dist/agent-protocol/pi-rpc/session.js +33 -32
- package/dist/amr-model-cache.d.ts +12 -4
- package/dist/amr-model-cache.js +17 -21
- package/dist/amr-profile-resolver.d.ts +3 -1
- package/dist/anthropic-live-models.js +0 -0
- package/dist/artifact-taxonomy.d.ts +6 -2
- package/dist/auth.d.ts +52 -15
- package/dist/auth.js +36 -36
- package/dist/claude-code-models.js +2 -2
- package/dist/claude-stream.d.ts +22 -3
- package/dist/claude-stream.js +24 -8
- package/dist/copilot-stream.d.ts +7 -3
- package/dist/copilot-stream.js +3 -3
- package/dist/defs/aider.d.ts +8 -1
- package/dist/defs/aider.js +2 -2
- package/dist/defs/amp.d.ts +8 -1
- package/dist/defs/amp.js +2 -2
- package/dist/defs/amr.d.ts +22 -6
- package/dist/defs/amr.js +23 -23
- package/dist/defs/antigravity.d.ts +15 -4
- package/dist/defs/antigravity.js +9 -8
- package/dist/defs/auggie.d.ts +4 -1
- package/dist/defs/auggie.js +1 -1
- package/dist/defs/claude.d.ts +12 -2
- package/dist/defs/claude.js +5 -5
- package/dist/defs/cline.d.ts +4 -1
- package/dist/defs/cline.js +1 -1
- package/dist/defs/codebuddy.d.ts +8 -1
- package/dist/defs/codebuddy.js +2 -2
- package/dist/defs/codex.d.ts +18 -4
- package/dist/defs/codex.js +7 -7
- package/dist/defs/copilot.d.ts +8 -1
- package/dist/defs/copilot.js +2 -2
- package/dist/defs/crush.d.ts +8 -1
- package/dist/defs/crush.js +1 -1
- package/dist/defs/cursor-agent.d.ts +14 -3
- package/dist/defs/cursor-agent.js +5 -5
- package/dist/defs/deepseek.d.ts +8 -1
- package/dist/defs/deepseek.js +2 -2
- package/dist/defs/devin.d.ts +12 -2
- package/dist/defs/devin.js +3 -3
- package/dist/defs/droid.d.ts +8 -1
- package/dist/defs/droid.js +1 -1
- package/dist/defs/gemini.d.ts +8 -1
- package/dist/defs/gemini.js +1 -1
- package/dist/defs/goose.d.ts +4 -1
- package/dist/defs/goose.js +1 -1
- package/dist/defs/grok-build.d.ts +11 -2
- package/dist/defs/grok-build.js +3 -3
- package/dist/defs/hermes.d.ts +4 -1
- package/dist/defs/hermes.js +2 -2
- package/dist/defs/kilo.d.ts +4 -1
- package/dist/defs/kilo.js +2 -2
- package/dist/defs/kimi.d.ts +4 -1
- package/dist/defs/kimi.js +2 -2
- package/dist/defs/kiro.d.ts +4 -1
- package/dist/defs/kiro.js +2 -2
- package/dist/defs/mimo.d.ts +8 -1
- package/dist/defs/mimo.js +2 -2
- package/dist/defs/opencode.d.ts +9 -2
- package/dist/defs/opencode.js +2 -2
- package/dist/defs/pi.d.ts +12 -2
- package/dist/defs/pi.js +9 -9
- package/dist/defs/qoder.d.ts +8 -1
- package/dist/defs/qoder.js +2 -2
- package/dist/defs/qwen.d.ts +8 -1
- package/dist/defs/qwen.js +2 -2
- package/dist/defs/reasonix.d.ts +4 -1
- package/dist/defs/reasonix.js +3 -3
- package/dist/defs/shared.d.ts +4 -2
- package/dist/defs/shared.js +2 -2
- package/dist/defs/trae-cli.d.ts +12 -2
- package/dist/defs/trae-cli.js +3 -3
- package/dist/defs/vibe.d.ts +4 -1
- package/dist/defs/vibe.js +2 -2
- package/dist/detection.d.ts +19 -4
- package/dist/detection.js +33 -33
- package/dist/diagnostics.d.ts +14 -3
- package/dist/diagnostics.js +5 -5
- package/dist/env.d.ts +16 -4
- package/dist/env.js +7 -7
- package/dist/executables.d.ts +24 -8
- package/dist/executables.js +13 -13
- package/dist/index.d.ts +228 -4
- package/dist/index.js +230 -6
- package/dist/invocation.d.ts +6 -1
- package/dist/invocation.js +2 -2
- package/dist/json-event-stream.d.ts +7 -2
- package/dist/json-event-stream.js +3 -3
- package/dist/launch.d.ts +12 -2
- package/dist/launch.js +3 -3
- package/dist/log-file.d.ts +4 -1
- package/dist/log-file.js +2 -2
- package/dist/mcp.d.ts +6 -3
- package/dist/mcp.js +1 -1
- package/dist/metadata.d.ts +7 -3
- package/dist/metadata.js +1 -1
- package/dist/mmd-routes.d.ts +22 -6
- package/dist/mmd-routes.js +14 -14
- package/dist/model-catalog-cache.d.ts +50 -0
- package/dist/model-catalog-cache.js +61 -0
- package/dist/model-loading-state.d.ts +10 -0
- package/dist/model-loading-state.js +23 -0
- package/dist/model-registry.d.ts +28 -7
- package/dist/model-registry.js +11 -8
- package/dist/models.d.ts +31 -6
- package/dist/models.js +6 -6
- package/dist/opencode-log.d.ts +12 -4
- package/dist/opencode-log.js +8 -8
- package/dist/paths.d.ts +6 -2
- package/dist/paths.js +3 -3
- package/dist/pi-models.d.ts +3 -1
- package/dist/pi-models.js +2 -2
- package/dist/prompt-budget.d.ts +17 -4
- package/dist/prompt-budget.js +3 -3
- package/dist/prompt-file.d.ts +5 -1
- package/dist/prompt-file.js +1 -1
- package/dist/providers/aihubmix.d.ts +34 -9
- package/dist/providers/aihubmix.js +26 -26
- package/dist/providers/anthropic-messages.d.ts +77 -20
- package/dist/providers/anthropic-messages.js +53 -50
- package/dist/providers/azure-chat.d.ts +21 -7
- package/dist/providers/azure-chat.js +18 -16
- package/dist/providers/connection-guard.d.ts +45 -31
- package/dist/providers/connection-guard.js +40 -143
- package/dist/providers/connection-test.d.ts +1 -1
- package/dist/providers/connection-test.js +13 -30
- package/dist/providers/elevenlabs.d.ts +7 -2
- package/dist/providers/elevenlabs.js +4 -4
- package/dist/providers/google-messages.d.ts +44 -10
- package/dist/providers/google-messages.js +36 -34
- package/dist/providers/google-schema.d.ts +26 -0
- package/dist/providers/google-schema.js +253 -0
- package/dist/providers/google.d.ts +21 -6
- package/dist/providers/google.js +10 -10
- package/dist/providers/index.d.ts +3 -2
- package/dist/providers/index.js +3 -2
- package/dist/providers/model-catalog.d.ts +1 -1
- package/dist/providers/model-catalog.js +14 -27
- package/dist/providers/oauth-callback-server.d.ts +1 -1
- package/dist/providers/oauth-callback-server.js +3 -2
- package/dist/providers/oauth-credentials.d.ts +7 -1
- package/dist/providers/oauth-credentials.js +5 -5
- package/dist/providers/oauth-provider.d.ts +2 -2
- package/dist/providers/oauth-provider.js +20 -25
- package/dist/providers/oauth-tokens.d.ts +26 -6
- package/dist/providers/oauth-tokens.js +9 -9
- package/dist/providers/ollama-chat.d.ts +66 -31
- package/dist/providers/ollama-chat.js +64 -61
- package/dist/providers/openai-chat.d.ts +77 -22
- package/dist/providers/openai-chat.js +71 -67
- package/dist/providers/pkce.d.ts +33 -20
- package/dist/providers/pkce.js +75 -146
- package/dist/providers/sse-decode.d.ts +3 -1
- package/dist/providers/sse-decode.js +1 -1
- package/dist/providers/token-params.d.ts +16 -5
- package/dist/providers/token-params.js +6 -6
- package/dist/providers/tool-turn-types.d.ts +89 -0
- package/dist/providers/tool-turn-types.js +2 -0
- package/dist/providers/tool-turn.d.ts +10 -0
- package/dist/providers/tool-turn.js +252 -0
- package/dist/qoder-stream.d.ts +7 -3
- package/dist/qoder-stream.js +3 -3
- package/dist/registry.d.ts +6 -2
- package/dist/registry.js +4 -4
- package/dist/resolution.d.ts +5 -1
- package/dist/resolution.js +3 -3
- package/dist/role-marker-guard.d.ts +9 -5
- package/dist/role-marker-guard.js +5 -5
- package/dist/terminal-launch.d.ts +6 -1
- package/dist/terminal-launch.js +2 -2
- package/dist/types.d.ts +22 -6
- package/package.json +43 -4
|
@@ -247,19 +247,38 @@ export interface GoogleStreamState {
|
|
|
247
247
|
finishReason: string | null;
|
|
248
248
|
usage: Record<string, unknown> | null;
|
|
249
249
|
}
|
|
250
|
-
export declare function applyGoogleUsage(state
|
|
250
|
+
export declare function applyGoogleUsage({ state, data, onEvent }: {
|
|
251
|
+
state: GoogleStreamState;
|
|
252
|
+
data: Record<string, unknown>;
|
|
253
|
+
onEvent: (event: GoogleTurnEvent) => void;
|
|
254
|
+
}): void;
|
|
251
255
|
/** Checks `data.promptFeedback` for a documented block reason and, if present, emits the `error` event for it (the caller emits `end` — see `processGoogleFrame`). Returns whether the frame loop should stop. */
|
|
252
|
-
export declare function handleGoogleBlockedPrompt(data
|
|
256
|
+
export declare function handleGoogleBlockedPrompt({ data, onEvent }: {
|
|
257
|
+
data: Record<string, unknown>;
|
|
258
|
+
onEvent: (event: GoogleTurnEvent) => void;
|
|
259
|
+
}): boolean;
|
|
253
260
|
/**
|
|
254
261
|
* Feeds one text part through the role-marker guard and emits the safe portion. Returns `'break'`
|
|
255
262
|
* once the guard flags contamination (the caller ends the turn immediately), otherwise
|
|
256
263
|
* `'continue'` — same contract as `anthropic-messages.ts#handleAnthropicTextDelta`.
|
|
257
264
|
*/
|
|
258
|
-
export declare function handleGoogleTextPart(state
|
|
265
|
+
export declare function handleGoogleTextPart({ state, text, onEvent }: {
|
|
266
|
+
state: GoogleStreamState;
|
|
267
|
+
text: string;
|
|
268
|
+
onEvent: (event: GoogleTurnEvent) => void;
|
|
269
|
+
}): 'continue' | 'break';
|
|
259
270
|
/** `rawPart.functionCall` must already be confirmed a record by the caller. Reads `thoughtSignature` off `rawPart` (a sibling of `functionCall`, not a member of it) — see `GoogleFunctionCallPart.thoughtSignature`'s doc for why only a non-empty string is carried. */
|
|
260
|
-
export declare function handleGoogleFunctionCallPart(state
|
|
271
|
+
export declare function handleGoogleFunctionCallPart({ state, rawPart, onEvent }: {
|
|
272
|
+
state: GoogleStreamState;
|
|
273
|
+
rawPart: Record<string, unknown>;
|
|
274
|
+
onEvent: (event: GoogleTurnEvent) => void;
|
|
275
|
+
}): void;
|
|
261
276
|
/** Dispatches one part between the text and function-call handlers above. Returns `'break'` once a text part contaminates the guard, else `'continue'`. */
|
|
262
|
-
export declare function processGoogleRawPart(state
|
|
277
|
+
export declare function processGoogleRawPart({ state, rawPart, onEvent }: {
|
|
278
|
+
state: GoogleStreamState;
|
|
279
|
+
rawPart: unknown;
|
|
280
|
+
onEvent: (event: GoogleTurnEvent) => void;
|
|
281
|
+
}): 'continue' | 'break';
|
|
263
282
|
/** One frame's dispatch outcome — `'end'` carries the reason `runSingleGoogleRequest`'s loop passes to `emitEnd`, matching `anthropic-messages.ts#AnthropicFrameOutcome`'s identical split (the low-level handlers below only ever *report* why to stop; only the loop itself calls `emitEnd`, keeping that call in exactly one place). */
|
|
264
283
|
export type GoogleFrameOutcome = {
|
|
265
284
|
readonly action: 'continue';
|
|
@@ -274,7 +293,11 @@ export type GoogleFrameOutcome = {
|
|
|
274
293
|
* nesting-penalized top-level `if`s into one function call plus one outcome check — see
|
|
275
294
|
* `runSingleGoogleRequest`'s loop below.
|
|
276
295
|
*/
|
|
277
|
-
export declare function processGoogleFrame(state
|
|
296
|
+
export declare function processGoogleFrame({ state, data, onEvent }: {
|
|
297
|
+
state: GoogleStreamState;
|
|
298
|
+
data: Record<string, unknown>;
|
|
299
|
+
onEvent: (event: GoogleTurnEvent) => void;
|
|
300
|
+
}): GoogleFrameOutcome;
|
|
278
301
|
/**
|
|
279
302
|
* Decides why the tool loop should stop after one request, or returns `null` when it should
|
|
280
303
|
* instead proceed to execute the pending tool calls. Pure — no events, no I/O — mirrors
|
|
@@ -283,9 +306,16 @@ export declare function processGoogleFrame(state: GoogleStreamState, data: Recor
|
|
|
283
306
|
* `finishReason` comparison (see module doc, point 2, for why Gemini's `finishReason` enum cannot
|
|
284
307
|
* be used here).
|
|
285
308
|
*/
|
|
286
|
-
export declare function googleLoopExitReason(outcome
|
|
309
|
+
export declare function googleLoopExitReason({ outcome, toolTurns, maxToolTurns }: {
|
|
310
|
+
outcome: SingleRequestOutcome;
|
|
311
|
+
toolTurns: number;
|
|
312
|
+
maxToolTurns: number;
|
|
313
|
+
}): GoogleTurnEndReason | null;
|
|
287
314
|
/** Builds the `model`-role `Content`'s `parts` recording the pending tool calls — text (if any) followed by one `functionCall` part per call, each with its `thoughtSignature` spread back on as a sibling field, in the same shape the response delivered it and only when the response actually carried one (a `functionCall` part with no signature is legal; one with an empty-string signature is not). */
|
|
288
|
-
export declare function buildGoogleAssistantParts(text
|
|
315
|
+
export declare function buildGoogleAssistantParts({ text, toolCalls }: {
|
|
316
|
+
text: string;
|
|
317
|
+
toolCalls: readonly GoogleToolCall[];
|
|
318
|
+
}): GooglePart[];
|
|
289
319
|
export interface GoogleToolExecutionOutcome {
|
|
290
320
|
readonly functionResponseParts: GooglePart[];
|
|
291
321
|
readonly followUpParts: GooglePart[];
|
|
@@ -297,13 +327,17 @@ export interface GoogleToolExecutionOutcome {
|
|
|
297
327
|
* functionResponse" section for why images travel this way instead of a separate follow-up
|
|
298
328
|
* message (unlike `openai-chat.ts`/`azure-chat.ts`).
|
|
299
329
|
*/
|
|
300
|
-
export declare function executeGoogleToolCalls(executeTool
|
|
330
|
+
export declare function executeGoogleToolCalls({ executeTool, calls, onEvent }: {
|
|
331
|
+
executeTool: GoogleToolExecutor;
|
|
332
|
+
calls: readonly GoogleToolCall[];
|
|
333
|
+
onEvent: (event: GoogleTurnEvent) => void;
|
|
334
|
+
}): Promise<GoogleToolExecutionOutcome>;
|
|
301
335
|
/**
|
|
302
336
|
* Runs a full Gemini `streamGenerateContent` turn, including the
|
|
303
337
|
* tool-execution loop when `options.executeTool` is supplied and the model
|
|
304
338
|
* requests a function call. See `anthropic-messages.ts#runAnthropicToolTurn`'s
|
|
305
339
|
* doc for the shared event-stream/`ended`-flag contract this mirrors.
|
|
306
340
|
*/
|
|
307
|
-
export declare function runGoogleToolTurn(
|
|
341
|
+
export declare function runGoogleToolTurn(requiredArgs: Pick<GoogleTurnOptions, "apiKey" | "model" | "contents" | "onEvent">, optionalArgs?: Omit<GoogleTurnOptions, "apiKey" | "model" | "contents" | "onEvent">): Promise<GoogleTurnResult>;
|
|
308
342
|
export {};
|
|
309
343
|
//# sourceMappingURL=google-messages.d.ts.map
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { redactSecrets } from '@jini-ai/core';
|
|
1
2
|
/**
|
|
2
3
|
* @module providers/google-messages
|
|
3
4
|
*
|
|
@@ -94,7 +95,7 @@
|
|
|
94
95
|
* tool-loop body and its test file's multi-tool-call image test).
|
|
95
96
|
*/
|
|
96
97
|
import { createRoleMarkerGuard } from '../role-marker-guard.js';
|
|
97
|
-
import { defaultDnsLookup, pinnedFetch,
|
|
98
|
+
import { defaultDnsLookup, pinnedFetch, validateBaseUrlResolved } from './connection-guard.js';
|
|
98
99
|
import { googleStreamGenerateContentUrl } from './google.js';
|
|
99
100
|
import { decodeSseStream } from './sse-decode.js';
|
|
100
101
|
import { createTurnEndGuard } from './turn-end-guard.js';
|
|
@@ -117,7 +118,7 @@ function isRecord(value) {
|
|
|
117
118
|
* parity correction and a real hardening.
|
|
118
119
|
*/
|
|
119
120
|
function googleRequestUrl(baseUrl, model) {
|
|
120
|
-
return googleStreamGenerateContentUrl(baseUrl ?? DEFAULT_GOOGLE_BASE_URL, model);
|
|
121
|
+
return googleStreamGenerateContentUrl({ baseUrl: baseUrl ?? DEFAULT_GOOGLE_BASE_URL, model: model });
|
|
121
122
|
}
|
|
122
123
|
function googleHeaders(options) {
|
|
123
124
|
return {
|
|
@@ -150,7 +151,7 @@ function extractGoogleErrorDetail(rawText) {
|
|
|
150
151
|
}
|
|
151
152
|
return rawText.trim().slice(0, 500);
|
|
152
153
|
}
|
|
153
|
-
export function applyGoogleUsage(state, data, onEvent) {
|
|
154
|
+
export function applyGoogleUsage({ state, data, onEvent }) {
|
|
154
155
|
if (!isRecord(data.usageMetadata))
|
|
155
156
|
return;
|
|
156
157
|
state.usage = data.usageMetadata;
|
|
@@ -162,7 +163,7 @@ function firstGoogleCandidate(data) {
|
|
|
162
163
|
return candidates[0];
|
|
163
164
|
}
|
|
164
165
|
/** Checks `data.promptFeedback` for a documented block reason and, if present, emits the `error` event for it (the caller emits `end` — see `processGoogleFrame`). Returns whether the frame loop should stop. */
|
|
165
|
-
export function handleGoogleBlockedPrompt(data, onEvent) {
|
|
166
|
+
export function handleGoogleBlockedPrompt({ data, onEvent }) {
|
|
166
167
|
if (!isRecord(data.promptFeedback) || typeof data.promptFeedback.blockReason !== 'string')
|
|
167
168
|
return false;
|
|
168
169
|
onEvent({ type: 'error', message: `prompt blocked: ${data.promptFeedback.blockReason}`, code: data.promptFeedback.blockReason });
|
|
@@ -177,8 +178,8 @@ function googleCandidateParts(candidate) {
|
|
|
177
178
|
* once the guard flags contamination (the caller ends the turn immediately), otherwise
|
|
178
179
|
* `'continue'` — same contract as `anthropic-messages.ts#handleAnthropicTextDelta`.
|
|
179
180
|
*/
|
|
180
|
-
export function handleGoogleTextPart(state, text, onEvent) {
|
|
181
|
-
const safe = state.guard.feedText(text);
|
|
181
|
+
export function handleGoogleTextPart({ state, text, onEvent }) {
|
|
182
|
+
const safe = state.guard.feedText({ text: text });
|
|
182
183
|
if (safe.length > 0) {
|
|
183
184
|
state.fullText += safe;
|
|
184
185
|
onEvent({ type: 'text_delta', delta: safe });
|
|
@@ -191,7 +192,7 @@ export function handleGoogleTextPart(state, text, onEvent) {
|
|
|
191
192
|
return 'break';
|
|
192
193
|
}
|
|
193
194
|
/** `rawPart.functionCall` must already be confirmed a record by the caller. Reads `thoughtSignature` off `rawPart` (a sibling of `functionCall`, not a member of it) — see `GoogleFunctionCallPart.thoughtSignature`'s doc for why only a non-empty string is carried. */
|
|
194
|
-
export function handleGoogleFunctionCallPart(state, rawPart, onEvent) {
|
|
195
|
+
export function handleGoogleFunctionCallPart({ state, rawPart, onEvent }) {
|
|
195
196
|
const fc = rawPart.functionCall;
|
|
196
197
|
const name = typeof fc.name === 'string' ? fc.name : null;
|
|
197
198
|
if (!name)
|
|
@@ -203,21 +204,21 @@ export function handleGoogleFunctionCallPart(state, rawPart, onEvent) {
|
|
|
203
204
|
onEvent({ type: 'tool_use', id: call.id, name: call.name, input: call.input });
|
|
204
205
|
}
|
|
205
206
|
/** Dispatches one part between the text and function-call handlers above. Returns `'break'` once a text part contaminates the guard, else `'continue'`. */
|
|
206
|
-
export function processGoogleRawPart(state, rawPart, onEvent) {
|
|
207
|
+
export function processGoogleRawPart({ state, rawPart, onEvent }) {
|
|
207
208
|
if (!isRecord(rawPart))
|
|
208
209
|
return 'continue';
|
|
209
210
|
if (typeof rawPart.text === 'string' && rawPart.text.length > 0) {
|
|
210
|
-
return handleGoogleTextPart(state, rawPart.text, onEvent);
|
|
211
|
+
return handleGoogleTextPart({ state: state, text: rawPart.text, onEvent: onEvent });
|
|
211
212
|
}
|
|
212
213
|
if (isRecord(rawPart.functionCall)) {
|
|
213
|
-
handleGoogleFunctionCallPart(state, rawPart, onEvent);
|
|
214
|
+
handleGoogleFunctionCallPart({ state: state, rawPart: rawPart, onEvent: onEvent });
|
|
214
215
|
}
|
|
215
216
|
return 'continue';
|
|
216
217
|
}
|
|
217
218
|
/** Dispatches one candidate's `parts` array, one part at a time, via `processGoogleRawPart`. Returns `'break'` once a text part contaminates the guard. */
|
|
218
219
|
function processGoogleParts(state, parts, onEvent) {
|
|
219
220
|
for (const rawPart of parts) {
|
|
220
|
-
if (processGoogleRawPart(state, rawPart, onEvent) === 'break')
|
|
221
|
+
if (processGoogleRawPart({ state: state, rawPart: rawPart, onEvent: onEvent }) === 'break')
|
|
221
222
|
return 'break';
|
|
222
223
|
}
|
|
223
224
|
return 'continue';
|
|
@@ -229,11 +230,11 @@ function processGoogleParts(state, parts, onEvent) {
|
|
|
229
230
|
* nesting-penalized top-level `if`s into one function call plus one outcome check — see
|
|
230
231
|
* `runSingleGoogleRequest`'s loop below.
|
|
231
232
|
*/
|
|
232
|
-
export function processGoogleFrame(state, data, onEvent) {
|
|
233
|
-
applyGoogleUsage(state, data, onEvent);
|
|
233
|
+
export function processGoogleFrame({ state, data, onEvent }) {
|
|
234
|
+
applyGoogleUsage({ state: state, data: data, onEvent: onEvent });
|
|
234
235
|
const rawCandidate = firstGoogleCandidate(data);
|
|
235
236
|
if (!rawCandidate) {
|
|
236
|
-
return handleGoogleBlockedPrompt(data, onEvent) ? { action: 'end', reason: 'error' } : { action: 'continue' };
|
|
237
|
+
return handleGoogleBlockedPrompt({ data: data, onEvent: onEvent }) ? { action: 'end', reason: 'error' } : { action: 'continue' };
|
|
237
238
|
}
|
|
238
239
|
if (!isRecord(rawCandidate))
|
|
239
240
|
return { action: 'continue' };
|
|
@@ -253,7 +254,7 @@ export function processGoogleFrame(state, data, onEvent) {
|
|
|
253
254
|
*/
|
|
254
255
|
async function openGoogleResponseStream(options, contents, emitEnd) {
|
|
255
256
|
const { onEvent } = options;
|
|
256
|
-
const baseUrlCheck = await validateBaseUrlResolved(options.baseUrl ?? DEFAULT_GOOGLE_BASE_URL, options.dnsLookup ?? defaultDnsLookup);
|
|
257
|
+
const baseUrlCheck = await validateBaseUrlResolved({ baseUrl: options.baseUrl ?? DEFAULT_GOOGLE_BASE_URL, lookup: options.dnsLookup ?? defaultDnsLookup });
|
|
257
258
|
if (baseUrlCheck.error) {
|
|
258
259
|
onEvent({ type: 'error', message: baseUrlCheck.error });
|
|
259
260
|
emitEnd('error');
|
|
@@ -261,17 +262,17 @@ async function openGoogleResponseStream(options, contents, emitEnd) {
|
|
|
261
262
|
}
|
|
262
263
|
let response;
|
|
263
264
|
try {
|
|
264
|
-
response = await (options.fetchImpl ?? pinnedFetch)(googleRequestUrl(options.baseUrl, options.model), {
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
265
|
+
response = await (options.fetchImpl ?? pinnedFetch)({ url: googleRequestUrl(options.baseUrl, options.model), init: {
|
|
266
|
+
method: 'POST',
|
|
267
|
+
headers: googleHeaders(options),
|
|
268
|
+
body: JSON.stringify(googleRequestBody(options, contents)),
|
|
269
|
+
redirect: 'error',
|
|
270
|
+
...(options.signal ? { signal: options.signal } : {}),
|
|
271
|
+
}, pinnedAddress: baseUrlCheck.pinnedAddress });
|
|
271
272
|
}
|
|
272
273
|
catch (error) {
|
|
273
274
|
const message = error instanceof Error ? error.message : String(error);
|
|
274
|
-
onEvent({ type: 'error', message: redactSecrets(message, [options.apiKey]) });
|
|
275
|
+
onEvent({ type: 'error', message: redactSecrets({ input: message }, { exactSecrets: [options.apiKey] }) });
|
|
275
276
|
emitEnd('error');
|
|
276
277
|
return null;
|
|
277
278
|
}
|
|
@@ -279,7 +280,7 @@ async function openGoogleResponseStream(options, contents, emitEnd) {
|
|
|
279
280
|
const rawText = await response.text();
|
|
280
281
|
onEvent({
|
|
281
282
|
type: 'error',
|
|
282
|
-
message: redactSecrets(extractGoogleErrorDetail(rawText), [options.apiKey]),
|
|
283
|
+
message: redactSecrets({ input: extractGoogleErrorDetail(rawText) }, { exactSecrets: [options.apiKey] }),
|
|
283
284
|
code: String(response.status),
|
|
284
285
|
});
|
|
285
286
|
emitEnd('error');
|
|
@@ -301,13 +302,13 @@ async function runSingleGoogleRequest(options, contents, emitEnd) {
|
|
|
301
302
|
}
|
|
302
303
|
onEvent({ type: 'status', label: 'requesting' });
|
|
303
304
|
const state = {
|
|
304
|
-
guard: createRoleMarkerGuard('google-turn'),
|
|
305
|
+
guard: createRoleMarkerGuard({ messageId: 'google-turn' }),
|
|
305
306
|
toolCalls: [],
|
|
306
307
|
fullText: '',
|
|
307
308
|
finishReason: null,
|
|
308
309
|
usage: null,
|
|
309
310
|
};
|
|
310
|
-
frameLoop: for await (const frame of decodeSseStream(body)) {
|
|
311
|
+
frameLoop: for await (const frame of decodeSseStream({ source: body })) {
|
|
311
312
|
// No re-check of an "ended" flag at the top of this loop: the only way this loop calls
|
|
312
313
|
// `emitEnd` is the `outcome.action === 'end'` branch below, immediately followed by
|
|
313
314
|
// `break frameLoop` — same reachability proof as
|
|
@@ -321,7 +322,7 @@ async function runSingleGoogleRequest(options, contents, emitEnd) {
|
|
|
321
322
|
}
|
|
322
323
|
if (!isRecord(data))
|
|
323
324
|
continue;
|
|
324
|
-
const outcome = processGoogleFrame(state, data, onEvent);
|
|
325
|
+
const outcome = processGoogleFrame({ state: state, data: data, onEvent: onEvent });
|
|
325
326
|
if (outcome.action === 'end') {
|
|
326
327
|
emitEnd(outcome.reason);
|
|
327
328
|
break frameLoop;
|
|
@@ -415,7 +416,7 @@ function splitGoogleToolResultContent(content) {
|
|
|
415
416
|
* `finishReason` comparison (see module doc, point 2, for why Gemini's `finishReason` enum cannot
|
|
416
417
|
* be used here).
|
|
417
418
|
*/
|
|
418
|
-
export function googleLoopExitReason(outcome, toolTurns, maxToolTurns) {
|
|
419
|
+
export function googleLoopExitReason({ outcome, toolTurns, maxToolTurns }) {
|
|
419
420
|
if (outcome.toolCalls.length === 0)
|
|
420
421
|
return 'stop';
|
|
421
422
|
if (toolTurns >= maxToolTurns)
|
|
@@ -423,7 +424,7 @@ export function googleLoopExitReason(outcome, toolTurns, maxToolTurns) {
|
|
|
423
424
|
return null;
|
|
424
425
|
}
|
|
425
426
|
/** Builds the `model`-role `Content`'s `parts` recording the pending tool calls — text (if any) followed by one `functionCall` part per call, each with its `thoughtSignature` spread back on as a sibling field, in the same shape the response delivered it and only when the response actually carried one (a `functionCall` part with no signature is legal; one with an empty-string signature is not). */
|
|
426
|
-
export function buildGoogleAssistantParts(text, toolCalls) {
|
|
427
|
+
export function buildGoogleAssistantParts({ text, toolCalls }) {
|
|
427
428
|
return [
|
|
428
429
|
...(text ? [{ text }] : []),
|
|
429
430
|
...toolCalls.map((call) => ({
|
|
@@ -439,7 +440,7 @@ export function buildGoogleAssistantParts(text, toolCalls) {
|
|
|
439
440
|
* functionResponse" section for why images travel this way instead of a separate follow-up
|
|
440
441
|
* message (unlike `openai-chat.ts`/`azure-chat.ts`).
|
|
441
442
|
*/
|
|
442
|
-
export async function executeGoogleToolCalls(executeTool, calls, onEvent) {
|
|
443
|
+
export async function executeGoogleToolCalls({ executeTool, calls, onEvent }) {
|
|
443
444
|
const functionResponseParts = [];
|
|
444
445
|
const followUpParts = [];
|
|
445
446
|
for (const call of calls) {
|
|
@@ -468,7 +469,8 @@ export async function executeGoogleToolCalls(executeTool, calls, onEvent) {
|
|
|
468
469
|
* requests a function call. See `anthropic-messages.ts#runAnthropicToolTurn`'s
|
|
469
470
|
* doc for the shared event-stream/`ended`-flag contract this mirrors.
|
|
470
471
|
*/
|
|
471
|
-
export async function runGoogleToolTurn(
|
|
472
|
+
export async function runGoogleToolTurn(requiredArgs, optionalArgs = {}) {
|
|
473
|
+
const options = { ...optionalArgs, ...requiredArgs };
|
|
472
474
|
const maxToolTurns = options.maxToolTurns ?? DEFAULT_MAX_TOOL_TURNS;
|
|
473
475
|
const executeTool = options.executeTool;
|
|
474
476
|
const endGuard = createTurnEndGuard(options.onEvent, (reason) => ({ type: 'end', reason }));
|
|
@@ -481,7 +483,7 @@ export async function runGoogleToolTurn(options) {
|
|
|
481
483
|
lastFinishReason = outcome.finishReason;
|
|
482
484
|
if (endGuard.hasEnded())
|
|
483
485
|
break;
|
|
484
|
-
const exitReason = googleLoopExitReason(outcome, toolTurns, maxToolTurns);
|
|
486
|
+
const exitReason = googleLoopExitReason({ outcome: outcome, toolTurns: toolTurns, maxToolTurns: maxToolTurns });
|
|
485
487
|
if (exitReason) {
|
|
486
488
|
emitEnd(exitReason);
|
|
487
489
|
break;
|
|
@@ -494,8 +496,8 @@ export async function runGoogleToolTurn(options) {
|
|
|
494
496
|
break;
|
|
495
497
|
}
|
|
496
498
|
toolTurns += 1;
|
|
497
|
-
const modelParts = buildGoogleAssistantParts(outcome.text, outcome.toolCalls);
|
|
498
|
-
const { functionResponseParts, followUpParts } = await executeGoogleToolCalls(executeTool, outcome.toolCalls, options.onEvent);
|
|
499
|
+
const modelParts = buildGoogleAssistantParts({ text: outcome.text, toolCalls: outcome.toolCalls });
|
|
500
|
+
const { functionResponseParts, followUpParts } = await executeGoogleToolCalls({ executeTool: executeTool, calls: outcome.toolCalls, onEvent: options.onEvent });
|
|
499
501
|
contents = [
|
|
500
502
|
...contents,
|
|
501
503
|
{ role: 'model', parts: modelParts },
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
import type { ProviderToolDescriptor } from './tool-turn-types.js';
|
|
2
|
+
/** Converts JSON Schema into Gemini's restricted schema dialect. Unsupported constraints are guidance only; hosts must still validate tool input. Reference expansion defaults to four hops. Time and space are proportional to the expanded schema tree; this bound limits reference hops, not ordinary object nesting. */
|
|
3
|
+
export declare function sanitizeGoogleSchema({ schema }: {
|
|
4
|
+
schema: unknown;
|
|
5
|
+
}, { defs, maxRefDepth }?: {
|
|
6
|
+
defs?: Readonly<Record<string, unknown>>;
|
|
7
|
+
maxRefDepth?: number;
|
|
8
|
+
}): unknown;
|
|
9
|
+
/** Produces the schema actually placed on a Gemini function declaration, including required node types and array items. */
|
|
10
|
+
export declare function googleParametersOf({ descriptor }: {
|
|
11
|
+
descriptor: ProviderToolDescriptor;
|
|
12
|
+
}, { maxRefDepth }?: {
|
|
13
|
+
maxRefDepth?: number;
|
|
14
|
+
}): Record<string, unknown>;
|
|
15
|
+
/** Finds numeric enum fields through object properties. Array, union and reference traversal are outside this conversion's current scope. */
|
|
16
|
+
export declare function findNumericEnumPaths({ schema }: {
|
|
17
|
+
schema: unknown;
|
|
18
|
+
}, { prefix }?: {
|
|
19
|
+
prefix?: readonly string[];
|
|
20
|
+
}): string[];
|
|
21
|
+
/** Reverses Gemini's numeric enum stringification without mutating the incoming tool argument. Paths use dot-separated property names. */
|
|
22
|
+
export declare function coerceNumericEnumStringsToNumbers({ input, paths }: {
|
|
23
|
+
input: unknown;
|
|
24
|
+
paths: readonly string[];
|
|
25
|
+
}): unknown;
|
|
26
|
+
//# sourceMappingURL=google-schema.d.ts.map
|
|
@@ -0,0 +1,253 @@
|
|
|
1
|
+
function inputSchemaOf(descriptor) {
|
|
2
|
+
return descriptor.inputSchema && typeof descriptor.inputSchema === "object"
|
|
3
|
+
? descriptor.inputSchema
|
|
4
|
+
: { type: "object", additionalProperties: false, required: [], properties: {} };
|
|
5
|
+
}
|
|
6
|
+
const GOOGLE_SUPPORTED_SCHEMA_KEYS = new Set([
|
|
7
|
+
"type",
|
|
8
|
+
"format",
|
|
9
|
+
"title",
|
|
10
|
+
"description",
|
|
11
|
+
"nullable",
|
|
12
|
+
"default",
|
|
13
|
+
"items",
|
|
14
|
+
"minItems",
|
|
15
|
+
"maxItems",
|
|
16
|
+
"enum",
|
|
17
|
+
"properties",
|
|
18
|
+
"propertyOrdering",
|
|
19
|
+
"required",
|
|
20
|
+
"minProperties",
|
|
21
|
+
"maxProperties",
|
|
22
|
+
"minimum",
|
|
23
|
+
"maximum",
|
|
24
|
+
"minLength",
|
|
25
|
+
"maxLength",
|
|
26
|
+
"pattern",
|
|
27
|
+
"example",
|
|
28
|
+
"anyOf",
|
|
29
|
+
]);
|
|
30
|
+
const MAX_GOOGLE_REF_DEPTH = 4;
|
|
31
|
+
function isRecord(value) {
|
|
32
|
+
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
33
|
+
}
|
|
34
|
+
function inferGoogleTypeFromLiteral(value) {
|
|
35
|
+
if (typeof value === "boolean")
|
|
36
|
+
return "boolean";
|
|
37
|
+
if (typeof value === "number")
|
|
38
|
+
return Number.isInteger(value) ? "integer" : "number";
|
|
39
|
+
return "string";
|
|
40
|
+
}
|
|
41
|
+
function collapseGoogleTypeArray(members) {
|
|
42
|
+
const names = members.filter((member) => typeof member === "string");
|
|
43
|
+
const nullable = names.includes("null");
|
|
44
|
+
const nonNull = names.filter((name) => name !== "null");
|
|
45
|
+
return { type: nonNull[0] ?? "string", nullable };
|
|
46
|
+
}
|
|
47
|
+
function resolveGoogleRef(ref, defs) {
|
|
48
|
+
const prefix = "#/$defs/";
|
|
49
|
+
if (!ref.startsWith(prefix))
|
|
50
|
+
return { type: "object" };
|
|
51
|
+
return defs[ref.slice(prefix.length)] ?? { type: "object" };
|
|
52
|
+
}
|
|
53
|
+
function terminalGoogleRefStub(resolved) {
|
|
54
|
+
const type = isRecord(resolved) && typeof resolved.type === "string" ? resolved.type : "object";
|
|
55
|
+
const originalDescription = isRecord(resolved) && typeof resolved.description === "string" ? `${resolved.description} ` : "";
|
|
56
|
+
return { type, description: `${originalDescription}(further nesting simplified for Gemini compatibility)` };
|
|
57
|
+
}
|
|
58
|
+
function enforceGoogleSchemaShape(node) {
|
|
59
|
+
const usesAnyOf = Array.isArray(node.anyOf) && node.anyOf.length > 0;
|
|
60
|
+
if (!usesAnyOf && typeof node.type !== "string")
|
|
61
|
+
node.type = "object";
|
|
62
|
+
if (node.type === "array" && !isRecord(node.items)) {
|
|
63
|
+
node.items = { type: "string", description: "Contents simplified for Gemini compatibility." };
|
|
64
|
+
}
|
|
65
|
+
return node;
|
|
66
|
+
}
|
|
67
|
+
function isGoogleIgnoredSchemaKey(key) {
|
|
68
|
+
return key === "$defs" || key === "$ref" || key === "oneOf";
|
|
69
|
+
}
|
|
70
|
+
function isGoogleTypeArrayKey(key, value) {
|
|
71
|
+
return key === "type" && Array.isArray(value);
|
|
72
|
+
}
|
|
73
|
+
function isGoogleNullableEnumKey(key, value) {
|
|
74
|
+
return key === "enum" && Array.isArray(value) && value.includes(null);
|
|
75
|
+
}
|
|
76
|
+
function applyGoogleSchemaEnum(result, value) {
|
|
77
|
+
result.enum = value.filter((member) => member !== null);
|
|
78
|
+
}
|
|
79
|
+
function isGooglePropertiesKey(key, value) {
|
|
80
|
+
return key === "properties" && isRecord(value);
|
|
81
|
+
}
|
|
82
|
+
function isGoogleSchemaPositionKey(key) {
|
|
83
|
+
return key === "items" || key === "anyOf";
|
|
84
|
+
}
|
|
85
|
+
function applyGoogleSchemaTypeArray(result, value) {
|
|
86
|
+
const collapsed = collapseGoogleTypeArray(value);
|
|
87
|
+
result.type = collapsed.type;
|
|
88
|
+
return collapsed.nullable ? { inferredNullable: true } : {};
|
|
89
|
+
}
|
|
90
|
+
function sanitizeGoogleSchemaValuePositionValue(value, defs, remainingRefDepth) {
|
|
91
|
+
return Array.isArray(value)
|
|
92
|
+
? value.map((member) => sanitizeGoogleSubschema(member, defs, remainingRefDepth))
|
|
93
|
+
: sanitizeGoogleSubschema(value, defs, remainingRefDepth);
|
|
94
|
+
}
|
|
95
|
+
function applyGoogleSchemaEntry(result, key, value, localDefs, remainingRefDepth) {
|
|
96
|
+
if (isGoogleIgnoredSchemaKey(key))
|
|
97
|
+
return {};
|
|
98
|
+
if (key === "const") {
|
|
99
|
+
result.enum = [value];
|
|
100
|
+
return { hasConst: true, constValue: value };
|
|
101
|
+
}
|
|
102
|
+
if (isGoogleTypeArrayKey(key, value))
|
|
103
|
+
return applyGoogleSchemaTypeArray(result, value);
|
|
104
|
+
if (isGoogleNullableEnumKey(key, value)) {
|
|
105
|
+
applyGoogleSchemaEnum(result, value);
|
|
106
|
+
return {};
|
|
107
|
+
}
|
|
108
|
+
if (!GOOGLE_SUPPORTED_SCHEMA_KEYS.has(key))
|
|
109
|
+
return {};
|
|
110
|
+
if (isGooglePropertiesKey(key, value)) {
|
|
111
|
+
result.properties = Object.fromEntries(Object.entries(value).map(([name, propSchema]) => [name, sanitizeGoogleSubschema(propSchema, localDefs, remainingRefDepth)]));
|
|
112
|
+
return {};
|
|
113
|
+
}
|
|
114
|
+
if (isGoogleSchemaPositionKey(key)) {
|
|
115
|
+
result[key] = sanitizeGoogleSchemaValuePositionValue(value, localDefs, remainingRefDepth);
|
|
116
|
+
return {};
|
|
117
|
+
}
|
|
118
|
+
result[key] = sanitizeGoogleSchemaValue(value, localDefs, remainingRefDepth);
|
|
119
|
+
return {};
|
|
120
|
+
}
|
|
121
|
+
function mergeGoogleOneOf(schema, result, defs, remainingRefDepth) {
|
|
122
|
+
if (!Array.isArray(schema.oneOf))
|
|
123
|
+
return undefined;
|
|
124
|
+
const merged = [...(Array.isArray(result.anyOf) ? result.anyOf : []), ...schema.oneOf];
|
|
125
|
+
return merged.map((member) => sanitizeGoogleSubschema(member, defs, remainingRefDepth));
|
|
126
|
+
}
|
|
127
|
+
function buildGoogleSchemaResult(schema, localDefs, remainingRefDepth) {
|
|
128
|
+
const result = {};
|
|
129
|
+
let constValue;
|
|
130
|
+
let hasConst = false;
|
|
131
|
+
let inferredNullable = false;
|
|
132
|
+
for (const [key, value] of Object.entries(schema)) {
|
|
133
|
+
const effect = applyGoogleSchemaEntry(result, key, value, localDefs, remainingRefDepth);
|
|
134
|
+
if (effect.hasConst) {
|
|
135
|
+
hasConst = true;
|
|
136
|
+
constValue = effect.constValue;
|
|
137
|
+
}
|
|
138
|
+
if (effect.inferredNullable)
|
|
139
|
+
inferredNullable = true;
|
|
140
|
+
}
|
|
141
|
+
const mergedOneOf = mergeGoogleOneOf(schema, result, localDefs, remainingRefDepth);
|
|
142
|
+
if (mergedOneOf)
|
|
143
|
+
result.anyOf = mergedOneOf;
|
|
144
|
+
return { result, hasConst, constValue, inferredNullable };
|
|
145
|
+
}
|
|
146
|
+
function sanitizeGoogleSchemaValueRef(ref, localDefs, remainingRefDepth) {
|
|
147
|
+
const resolved = resolveGoogleRef(ref, localDefs);
|
|
148
|
+
if (remainingRefDepth <= 0)
|
|
149
|
+
return enforceGoogleSchemaShape(terminalGoogleRefStub(resolved));
|
|
150
|
+
return sanitizeGoogleSchemaValue(resolved, localDefs, remainingRefDepth - 1);
|
|
151
|
+
}
|
|
152
|
+
function hasGoogleNumericEnumValues(schema) {
|
|
153
|
+
return Array.isArray(schema.enum) && schema.enum.length > 0 && schema.enum.every((member) => typeof member === "number");
|
|
154
|
+
}
|
|
155
|
+
function applyGoogleNumericEnumStringification(schema, result) {
|
|
156
|
+
if (!hasGoogleNumericEnumValues(schema))
|
|
157
|
+
return;
|
|
158
|
+
result.enum = schema.enum.map((member) => String(member));
|
|
159
|
+
result.type = "string";
|
|
160
|
+
}
|
|
161
|
+
function applyGoogleConstTypeInference(result, hasConst, constValue) {
|
|
162
|
+
if (!hasConst || result.type !== undefined)
|
|
163
|
+
return;
|
|
164
|
+
result.type = inferGoogleTypeFromLiteral(constValue);
|
|
165
|
+
}
|
|
166
|
+
function sanitizeGoogleSchemaValue(schema, defs = {}, remainingRefDepth = MAX_GOOGLE_REF_DEPTH) {
|
|
167
|
+
if (Array.isArray(schema))
|
|
168
|
+
return schema.map((entry) => sanitizeGoogleSchemaValue(entry, defs, remainingRefDepth));
|
|
169
|
+
if (!isRecord(schema))
|
|
170
|
+
return schema;
|
|
171
|
+
const localDefs = isRecord(schema.$defs) ? { ...defs, ...schema.$defs } : defs;
|
|
172
|
+
if (typeof schema.$ref === "string")
|
|
173
|
+
return sanitizeGoogleSchemaValueRef(schema.$ref, localDefs, remainingRefDepth);
|
|
174
|
+
const { result, hasConst, constValue, inferredNullable } = buildGoogleSchemaResult(schema, localDefs, remainingRefDepth);
|
|
175
|
+
if (inferredNullable)
|
|
176
|
+
result.nullable = true;
|
|
177
|
+
applyGoogleConstTypeInference(result, hasConst, constValue);
|
|
178
|
+
applyGoogleNumericEnumStringification(schema, result);
|
|
179
|
+
return result;
|
|
180
|
+
}
|
|
181
|
+
function sanitizeGoogleSubschema(value, defs, depth) {
|
|
182
|
+
const sanitized = sanitizeGoogleSchemaValue(value, defs, depth);
|
|
183
|
+
return isRecord(sanitized) ? enforceGoogleSchemaShape(sanitized) : sanitized;
|
|
184
|
+
}
|
|
185
|
+
function googleParametersOfValue(descriptor, maxRefDepth = MAX_GOOGLE_REF_DEPTH) {
|
|
186
|
+
return enforceGoogleSchemaShape(sanitizeGoogleSchemaValue(inputSchemaOf(descriptor), {}, maxRefDepth));
|
|
187
|
+
}
|
|
188
|
+
function isGoogleNumericEnumSchema(schema) {
|
|
189
|
+
return (schema.type === "integer" || schema.type === "number") && hasGoogleNumericEnumValues(schema);
|
|
190
|
+
}
|
|
191
|
+
function findNumericEnumPathsValue(schema, prefix = []) {
|
|
192
|
+
if (!isRecord(schema))
|
|
193
|
+
return [];
|
|
194
|
+
const paths = [];
|
|
195
|
+
if (isGoogleNumericEnumSchema(schema))
|
|
196
|
+
paths.push(prefix.join("."));
|
|
197
|
+
if (isRecord(schema.properties)) {
|
|
198
|
+
for (const [name, propSchema] of Object.entries(schema.properties)) {
|
|
199
|
+
paths.push(...findNumericEnumPathsValue(propSchema, [...prefix, name]));
|
|
200
|
+
}
|
|
201
|
+
}
|
|
202
|
+
return paths;
|
|
203
|
+
}
|
|
204
|
+
function readAtGooglePath(input, segments) {
|
|
205
|
+
let current = input;
|
|
206
|
+
for (const segment of segments) {
|
|
207
|
+
if (!isRecord(current))
|
|
208
|
+
return undefined;
|
|
209
|
+
current = current[segment];
|
|
210
|
+
}
|
|
211
|
+
return current;
|
|
212
|
+
}
|
|
213
|
+
function writeAtGooglePath(input, segments, value) {
|
|
214
|
+
const [head, ...rest] = segments;
|
|
215
|
+
if (head === undefined)
|
|
216
|
+
return input;
|
|
217
|
+
if (rest.length === 0)
|
|
218
|
+
return { ...input, [head]: value };
|
|
219
|
+
const child = input[head];
|
|
220
|
+
if (!isRecord(child))
|
|
221
|
+
return input;
|
|
222
|
+
return { ...input, [head]: writeAtGooglePath(child, rest, value) };
|
|
223
|
+
}
|
|
224
|
+
function coerceNumericEnumStringsToNumbersValue(input, paths) {
|
|
225
|
+
if (paths.length === 0 || !isRecord(input))
|
|
226
|
+
return input;
|
|
227
|
+
let result = input;
|
|
228
|
+
for (const path of paths) {
|
|
229
|
+
const segments = path.split(".");
|
|
230
|
+
const current = readAtGooglePath(result, segments);
|
|
231
|
+
if (typeof current === "string" && current.trim().length > 0 && Number.isFinite(Number(current))) {
|
|
232
|
+
result = writeAtGooglePath(result, segments, Number(current));
|
|
233
|
+
}
|
|
234
|
+
}
|
|
235
|
+
return result;
|
|
236
|
+
}
|
|
237
|
+
/** Converts JSON Schema into Gemini's restricted schema dialect. Unsupported constraints are guidance only; hosts must still validate tool input. Reference expansion defaults to four hops. Time and space are proportional to the expanded schema tree; this bound limits reference hops, not ordinary object nesting. */
|
|
238
|
+
export function sanitizeGoogleSchema({ schema }, { defs = {}, maxRefDepth = MAX_GOOGLE_REF_DEPTH } = {}) {
|
|
239
|
+
return sanitizeGoogleSchemaValue(schema, defs, maxRefDepth);
|
|
240
|
+
}
|
|
241
|
+
/** Produces the schema actually placed on a Gemini function declaration, including required node types and array items. */
|
|
242
|
+
export function googleParametersOf({ descriptor }, { maxRefDepth = MAX_GOOGLE_REF_DEPTH } = {}) {
|
|
243
|
+
return googleParametersOfValue(descriptor, maxRefDepth);
|
|
244
|
+
}
|
|
245
|
+
/** Finds numeric enum fields through object properties. Array, union and reference traversal are outside this conversion's current scope. */
|
|
246
|
+
export function findNumericEnumPaths({ schema }, { prefix = [] } = {}) {
|
|
247
|
+
return findNumericEnumPathsValue(schema, prefix);
|
|
248
|
+
}
|
|
249
|
+
/** Reverses Gemini's numeric enum stringification without mutating the incoming tool argument. Paths use dot-separated property names. */
|
|
250
|
+
export function coerceNumericEnumStringsToNumbers({ input, paths }) {
|
|
251
|
+
return coerceNumericEnumStringsToNumbersValue(input, paths);
|
|
252
|
+
}
|
|
253
|
+
//# sourceMappingURL=google-schema.js.map
|
|
@@ -6,15 +6,30 @@
|
|
|
6
6
|
* verbatim.
|
|
7
7
|
*/
|
|
8
8
|
/** Strips any trailing `/v1`/`/v1beta` API-version segment and trailing slashes from a configured base URL. */
|
|
9
|
-
export declare function googleGenerativeLanguageBaseUrl(baseUrl
|
|
9
|
+
export declare function googleGenerativeLanguageBaseUrl({ baseUrl }: {
|
|
10
|
+
baseUrl: string;
|
|
11
|
+
}): string;
|
|
10
12
|
/** Strips the `models/` prefix Google's API sometimes includes in a model id. */
|
|
11
|
-
export declare function normalizeGoogleModelId(model
|
|
13
|
+
export declare function normalizeGoogleModelId({ model }: {
|
|
14
|
+
model: string;
|
|
15
|
+
}): string;
|
|
12
16
|
/** URL-encodes a normalized model id for use as a path segment. */
|
|
13
|
-
export declare function googleModelPathSegment(model
|
|
17
|
+
export declare function googleModelPathSegment({ model }: {
|
|
18
|
+
model: string;
|
|
19
|
+
}): string;
|
|
14
20
|
/** Builds the non-streaming `generateContent` endpoint URL for a model. */
|
|
15
|
-
export declare function googleGenerateContentUrl(baseUrl
|
|
21
|
+
export declare function googleGenerateContentUrl({ baseUrl, model }: {
|
|
22
|
+
baseUrl: string;
|
|
23
|
+
model: string;
|
|
24
|
+
}): string;
|
|
16
25
|
/** Builds the SSE-streaming `streamGenerateContent` endpoint URL for a model. */
|
|
17
|
-
export declare function googleStreamGenerateContentUrl(baseUrl
|
|
26
|
+
export declare function googleStreamGenerateContentUrl({ baseUrl, model }: {
|
|
27
|
+
baseUrl: string;
|
|
28
|
+
model: string;
|
|
29
|
+
}): string;
|
|
18
30
|
/** Builds the model-catalog listing endpoint URL, with the API key attached as a query param. */
|
|
19
|
-
export declare function googleProviderModelsUrl(baseUrl
|
|
31
|
+
export declare function googleProviderModelsUrl({ baseUrl, apiKey }: {
|
|
32
|
+
baseUrl: string;
|
|
33
|
+
apiKey: string;
|
|
34
|
+
}): string;
|
|
20
35
|
//# sourceMappingURL=google.d.ts.map
|