/** * Translation helpers for the native Gemini `generateContent` battery. * * @module @nhtio/adk/batteries/llm/gemini_generate_content/helpers * * @remarks * Every function is injectable via {@link GeminiGenerateContentAdapterOptions.helpers} and has a * `default*` alias. The wire-shape-agnostic renderers (untrusted/trusted envelopes, memories, * retrievables, thought envelopes, the system-prompt assembler) are re-exported unchanged from the * shared internal `../chat_common/helpers`; only the parts that are genuinely Gemini-shaped live * here. */ import { renderTrustedContent, renderUntrustedContent } from "../chat_common/helpers"; import type { SpooledArtifact } from "../../../common"; import type { Tool, ArtifactTool, Media, ToolCall, Tokenizable } from "../../../common"; import type { GeminiContent, GeminiInlineData, GeminiGenerateContentRequest, GeminiRequestBuildInput, GeminiTool, JsonSchema, UnsupportedMediaPolicy } from "./types"; export { descriptionToChatCompletionsJsonSchema, defaultDescriptionToChatCompletionsJsonSchema, renderUntrustedContent, defaultRenderUntrustedContent, renderTrustedContent, defaultRenderTrustedContent, renderStandingInstructions, defaultRenderStandingInstructions, renderMemories, defaultRenderMemories, renderRetrievables, defaultRenderRetrievables, renderRetrievableSafetyDirective, defaultRenderRetrievableSafetyDirective, renderFirstPartyRetrievables, defaultRenderFirstPartyRetrievables, renderThirdPartyPublicRetrievables, defaultRenderThirdPartyPublicRetrievables, renderThirdPartyPrivateRetrievables, defaultRenderThirdPartyPrivateRetrievables, renderThought, defaultRenderThought, filterThoughts, defaultFilterThoughts, renderChatCompletionsSystemPrompt, defaultRenderChatCompletionsSystemPrompt, renderArtifactHandleBody, defaultRenderArtifactHandleBody, renderRetrievableHandleBody, defaultRenderRetrievableHandleBody, } from "../chat_common/helpers"; /** * Default context-bucket order for the system instruction. * * @remarks * Matches the other chat batteries so a consumer switching batteries gets the same system-prompt * layout. Exported so a caller can reorder without reconstructing the whole list. */ export declare const DEFAULT_GEMINI_BUCKET_ORDER: readonly [ "standingInstructions", "memories", "retrievables", "timeline" ]; /** * Recursively strip schema keywords Gemini rejects. * * @param schema - Any JSON-Schema-shaped value. * @returns The same shape with unsupported keywords removed. */ export declare const sanitizeGeminiSchema: (schema: unknown) => JsonSchema; /** Default implementation; alias of {@link sanitizeGeminiSchema}. */ export declare const defaultSanitizeGeminiSchema: (schema: unknown) => JsonSchema; /** * ADK tools → native `functionDeclarations`. * * @remarks * Names are normalised through the shared `normalizeToolName` so a tool whose ADK name contains * characters Gemini rejects still resolves; `functionResponse.name` must later match whatever this * produced, which is why both sides call the same normaliser. */ export declare const toolsToGeminiTools: (tools: Iterable) => GeminiTool[]; /** Default implementation; alias of {@link toolsToGeminiTools}. */ export declare const defaultToolsToGeminiTools: (tools: Iterable) => GeminiTool[]; /** * Render one tool result into a `functionResponse.response` object. * * @remarks * Gemini requires an OBJECT here, not a bare string — a string is rejected. Text is therefore * wrapped as `{ result: }`, keeping the untrusted-content envelope the other batteries use * so a tool result cannot impersonate a system directive. */ export declare const renderGeminiToolResult: (input: { toolCall: ToolCall; results: Tokenizable | SpooledArtifact | SpooledArtifact[] | Media | Media[]; tool: Tool | ArtifactTool | undefined; renderUntrustedContent: typeof renderUntrustedContent; renderTrustedContent: typeof renderTrustedContent; unsupportedMediaPolicy: UnsupportedMediaPolicy | undefined; warn?: (message: string) => void; }) => Promise>; /** Default implementation; alias of {@link renderGeminiToolResult}. */ export declare const defaultRenderGeminiToolResult: (input: { toolCall: ToolCall; results: Tokenizable | SpooledArtifact | SpooledArtifact[] | Media | Media[]; tool: Tool | ArtifactTool | undefined; renderUntrustedContent: typeof renderUntrustedContent; renderTrustedContent: typeof renderTrustedContent; unsupportedMediaPolicy: UnsupportedMediaPolicy | undefined; warn?: (message: string) => void; }) => Promise>; /** Decode an ADK Media into Gemini's `inlineData`. */ export declare const mediaToGeminiInlineData: (media: Media) => Promise; /** Default implementation; alias of {@link mediaToGeminiInlineData}. */ export declare const defaultMediaToGeminiInlineData: (media: Media) => Promise; /** * Assemble the native request from ADK turn state. THE ordering seam. * * @remarks * The translation that makes this battery different from pointing `openai_chat_completions` at a * Gemini gateway: * * - System text goes to `systemInstruction`, not a `contents[]` turn. * - `Message.role: 'assistant'` becomes `role: 'model'`. * - A `ToolCall` becomes TWO turns: a `model` turn with a `functionCall` part, then a `user` turn * with a `functionResponse` part. `functionResponse.name` carries the DECLARED tool name, * because Gemini has no call-id correlation. * - Timeline order is `createdAt`, matching the ordering guard's own view, so what the guard * validates is what gets dispatched. * - The thought-signature sentinel is stamped on the FIRST `functionCall` only when no part * already carries a real signature and the caller has not opted out. Preserving a genuine * signature matters: it is prefix-bound, and replacing one invalidates it. */ export declare const buildGeminiRequest: (input: GeminiRequestBuildInput) => Promise; /** Default implementation; alias of {@link buildGeminiRequest}. */ export declare const defaultBuildGeminiRequest: (input: GeminiRequestBuildInput) => Promise; /** * Extract text, reasoning, and function calls from a response. * * @remarks * `thought: true` parts are reasoning and must NOT be concatenated into user-visible text — doing * so leaks the model's scratchpad into the answer. */ export declare const extractGeminiGeneration: (response: { candidates?: Array<{ content?: GeminiContent; finishReason?: string; }>; } | undefined) => { text: string; reasoning: string; functionCalls: Array<{ name: string; args: Record; thoughtSignature?: string; }>; finishReason: string | undefined; }; /** Default implementation; alias of {@link extractGeminiGeneration}. */ export declare const defaultExtractGeminiGeneration: (response: { candidates?: Array<{ content?: GeminiContent; finishReason?: string; }>; } | undefined) => { text: string; reasoning: string; functionCalls: Array<{ name: string; args: Record; thoughtSignature?: string; }>; finishReason: string | undefined; };