/**
 * GeminiProvider — wraps `@google/genai` as an `LLMProvider` (9.13.0).
 *
 * Pattern: Adapter (GoF) + Ports-and-Adapters (Cockburn 2005).
 * Role:    Outer ring — translates `LLMRequest`/`LLMResponse` to/from Google's
 *          `generateContent` API. Knows nothing about agents, recorders, or
 *          compositions.
 * Emits:   N/A — providers don't emit; recorders observe via Agent.
 *
 * ─── Two doors, one adapter ─────────────────────────────────────────
 *
 * The same SDK reaches two different services, and which one you get is a
 * property of the OPTIONS, not of a separate factory:
 *
 *   • **Vertex** — `gemini({ project, location })` builds
 *     `new GoogleGenAI({ vertexai: true, project, location, googleAuthOptions })`.
 *     Auth is Application Default Credentials (env key file, gcloud user
 *     credentials, or the metadata server on GCE / Cloud Run / Agent Runtime).
 *     No API key exists on this path.
 *   • **Gemini API (AI Studio)** — `gemini({ apiKey })` builds
 *     `new GoogleGenAI({ apiKey })`. One key, no cloud project.
 *
 * Neither is guessed. The factory refuses at construction when it can resolve
 * neither a project nor a key, naming both doors — because the SDK's own
 * behaviour in that case is to WARN on stderr, construct anyway, and fail on
 * the first call, which reads like a network problem rather than a missing
 * setting.
 *
 * ─── Status, per door, because the doors differ ─────────────────────
 *
 * • **Vertex: field-validated.** An independent trial ran this adapter,
 *   unchanged since 9.13.0, against a live project through Application Default
 *   Credentials: a two-call tool loop on `gemini-2.5-flash` returning the
 *   expected answer with real token counts, and a stream delivering 10 content
 *   chunks that reconstructed exactly (FINDINGS "Part 1 — native Gemini on
 *   Vertex through ADC", "Part 2C"). `geminiEmbedder` passed on the same door.
 * • **Gemini API (AI Studio): NOT field-validated, and not for want of
 *   trying.** The trial's key-door calls never reached a model: the old
 *   default model answered 404 for a new account, and a current model answered
 *   429 for AI Studio prepayment, which is billing SEPARATE from the Google
 *   Cloud account's credit. What that door does with a funded key is
 *   untested here, which is why it has no default model.
 * • **Tool calling on a 3.x model: field-validated.** The signature round trip
 *   below was built from the trial's captured 400, and the same independent
 *   trial then re-ran it on live Vertex against the published fix
 *   (2026-08-14): `gemini-3.1-flash-lite` called a tool, the tool answered,
 *   the signature went back byte for byte, and the second model call
 *   completed with the right answer — two LLM calls, one tool execution, real
 *   token counts. What it does NOT cover is a signature attached to a TEXT
 *   part with no function call beside it; see below.
 *
 * ─── Why native, and not `openai({ baseURL })` ──────────────────────
 *
 * Google publishes an OpenAI-compatible endpoint, and it does work — for about
 * an hour. It authenticates with an OAuth access token that expires (9.29.0
 * gives `openai({ apiKey })` a callback form so a long-running process can
 * refresh one, which is a mitigation and not a fix); its
 * `tools.function.parameters` is **OpenAPI**, not JSON Schema, so `$ref` /
 * `oneOf` / `additionalProperties` diverge silently; unsupported parameters are
 * ignored rather than refused; and its documented response carries no cached-
 * or reasoning-token counts. This adapter exists because every one of those is
 * answerable on the native SDK: ADC refreshes itself, tools go over as JSON
 * Schema untranslated (`parametersJsonSchema`), a forced single tool is
 * expressible, and `usageMetadata` reports cached and thinking tokens as
 * separate numbers.
 *
 * A field trial measured both halves of that: the native path completed a call
 * after a forced credential expiry, while the compatible path returned HTTP 401
 * on an expired token (FINDINGS "Part 2B").
 *
 * ─── Thought signatures: the round trip a tool loop cannot skip ─────
 *
 * A current Gemini model does not merely PREFER its thought signature back —
 * it refuses the turn without it. An independent field trial on live GCP ran
 * `gemini-3.1-flash-lite` on Vertex through one ordinary tool loop: the first
 * call asked for the function, the tool ran, and the second call came back
 *
 *   400 INVALID_ARGUMENT — "Function call is missing a thought_signature in
 *   functionCall parts. This is required for tools to work correctly …"
 *
 * (FINDINGS "Failure 4"). The cost of that shape is what makes it worth this
 * paragraph: the failure lands AFTER the tool has already executed, so a
 * side-effecting tool has run and the answer is unreachable.
 *
 * So the signature is CARRIED, not dropped. `Part.thoughtSignature` (a base64
 * string on the installed @google/genai 2.16.0 `Part`) is read off the same
 * part as the `functionCall` it belongs to, parked on the port's neutral
 * `toolCalls[].providerMeta`, and written back onto the reconstructed
 * `functionCall` part on the next request — byte for byte, because a signature
 * is checked and not read. This is the same round trip the Anthropic adapter
 * does with signed thinking blocks, one field along: there the carrier is
 * `LLMMessage.thinkingBlocks[].signature`, here it is the tool call itself,
 * because that is where Google puts it.
 *
 * What that does NOT cover, said plainly: a signature attached to a TEXT part
 * of an answer with no function call. The port's assistant turn is a string,
 * and a string has nowhere to keep one. The trial's failure was the functionCall
 * shape; that shape is fixed here, and the other one is named rather than
 * quietly half-handled.
 *
 * ─── Limitations (stated, not discovered) ───────────────────────────
 *
 * • Multi-modal input/output NOT supported — `LLMMessage.content` is `string`,
 *   so this adapter sends and reads text parts only. Inline data, files and
 *   generated images are out of scope for the port as it stands.
 * • **Thought summaries are not requested.** `usage.thinking` is reported
 *   honestly from `thoughtsTokenCount`, and `req.thinking.budget` is threaded
 *   to `thinkingConfig.thinkingBudget` — but `includeThoughts` is deliberately
 *   left unset, so no `rawThinking` is produced and there is no Gemini
 *   `ThinkingHandler` in this release to normalize thought TEXT. Asking for
 *   content nothing can carry would be a leak, not a feature. Signature
 *   round-tripping (above) is a separate thing and does not need one.
 *   `thinkingConfig.thinkingLevel` has no field on `LLMRequest` and is
 *   likewise not sent.
 * • `responseJsonSchema` (native structured output) is NOT exposed; use
 *   `.outputSchema(...)`, which goes over as a forced tool — a shape this
 *   adapter DOES carry.
 * • Grounding tools (Google Search, code execution, URL context, MCP servers)
 *   are not exposed. `tools` carries function declarations only.
 */
import type { LLMCallHooks, LLMChunk, LLMProvider, LLMRequest, LLMResponse, WireRole } from '../../provider-contract/types.js';
import { type GoogleGenAIConnectionOptions } from './googleGenAI.js';
/** One `parts[]` entry. Only the members this adapter reads or writes. */
export interface GeminiPart {
    readonly text?: string;
    /** `true` on a thought-summary part. Never joined into visible content. */
    readonly thought?: boolean;
    /**
     * The model's opaque signature for the thinking behind THIS part — base64,
     * per `Part.thoughtSignature` on the installed @google/genai 2.16.0 surface.
     *
     * Read off a `functionCall` part and written back onto the same part on the
     * next request. Never parsed, never trimmed, never regenerated: the service
     * verifies it, so the only correct handling is byte-for-byte.
     */
    readonly thoughtSignature?: string;
    readonly functionCall?: {
        readonly id?: string;
        readonly name?: string;
        readonly args?: Record<string, unknown>;
    };
    readonly functionResponse?: {
        readonly id?: string;
        readonly name?: string;
        readonly response?: Record<string, unknown>;
    };
}
/** One conversation turn. Gemini's assistant role is spelled `'model'`. */
export interface GeminiContent {
    readonly role: 'user' | 'model';
    readonly parts: readonly GeminiPart[];
}
/** A `FunctionDeclaration`, JSON-Schema flavour. */
export interface GeminiFunctionDeclaration {
    readonly name: string;
    readonly description: string;
    /**
     * JSON Schema, passed through UNCHANGED. The sibling `parameters` field
     * takes OpenAPI instead and is never set here — sending both is what makes
     * an adapter's tool schemas quietly disagree with the ones it was given.
     */
    readonly parametersJsonSchema: Record<string, unknown>;
}
export interface GeminiGenerateConfig {
    systemInstruction?: string;
    temperature?: number;
    maxOutputTokens?: number;
    stopSequences?: string[];
    abortSignal?: AbortSignal;
    tools?: {
        functionDeclarations: GeminiFunctionDeclaration[];
    }[];
    toolConfig?: {
        functionCallingConfig: {
            mode: 'AUTO' | 'ANY' | 'NONE';
            allowedFunctionNames?: string[];
        };
    };
    thinkingConfig?: {
        thinkingBudget: number;
    };
}
export interface GeminiGenerateParams {
    readonly model: string;
    readonly contents: readonly GeminiContent[];
    readonly config?: GeminiGenerateConfig;
}
export interface GeminiUsageMetadata {
    readonly promptTokenCount?: number;
    readonly candidatesTokenCount?: number;
    readonly cachedContentTokenCount?: number;
    readonly thoughtsTokenCount?: number;
    readonly totalTokenCount?: number;
}
export interface GeminiCandidate {
    readonly content?: {
        readonly parts?: readonly GeminiPart[];
    };
    readonly finishReason?: string;
}
export interface GeminiGenerateResponse {
    readonly candidates?: readonly GeminiCandidate[];
    readonly usageMetadata?: GeminiUsageMetadata;
    readonly responseId?: string;
}
/**
 * The `models` namespace, narrowed to the two operations this adapter
 * dispatches.
 *
 * `countTokens` is deliberately ABSENT. It exists on the real namespace and it
 * would be an easy way to fill in a usage number the wire did not report —
 * which is precisely why it is not here. A count we asked for separately is not
 * what the call was billed for; see the streaming note on `stream()`.
 */
export interface GeminiModelsLike {
    generateContent(params: GeminiGenerateParams): Promise<GeminiGenerateResponse>;
    /** Note the double await: the SDK returns a PROMISE of an async generator. */
    generateContentStream(params: GeminiGenerateParams): Promise<AsyncIterable<GeminiGenerateResponse>>;
}
/** What `new GoogleGenAI(...)` gives us, narrowed to what we use. */
export interface GeminiClientLike {
    readonly models: GeminiModelsLike;
}
export interface GeminiProviderOptions extends GoogleGenAIConnectionOptions {
    /**
     * Default model used when `LLMRequest.model` is `'gemini'` (the shorthand).
     * A request naming a full model id wins.
     *
     * **Unset behaves differently per door, because the doors behave
     * differently.** On **Vertex** the shorthand resolves to
     * `'gemini-2.5-flash'`, which a live field trial ran end to end through ADC.
     * On the **Gemini API (AI Studio)** door the shorthand is REFUSED by name:
     * the same trial's key-door call to that exact model returned HTTP 404 —
     * *"no longer available to new users"* (FINDINGS "Failure 1") — and no model
     * could be proven working on that door at all, because the account's separate
     * AI Studio prepayment was empty (FINDINGS "Failure 2", a 429 on
     * `gemini-3.1-flash-lite`, which at least proves that id resolves there).
     *
     * Shipping a second silent default nobody has run would be this library
     * guessing on a service's behalf; the refusal names the door and the fix.
     */
    readonly defaultModel?: string;
    /** Default `maxOutputTokens` when the request doesn't set it. Optional. */
    readonly defaultMaxTokens?: number;
    /** @internal Pre-built client for testing. Skips the SDK import entirely. */
    readonly _client?: GeminiClientLike;
}
/**
 * Build an `LLMProvider` backed by Gemini — on Vertex or on the Gemini API.
 *
 * @example  Vertex (Application Default Credentials)
 * ```ts
 * import { Agent } from 'agentfootprint';
 * import { gemini } from 'agentfootprint/providers';
 *
 * const agent = Agent.create({
 *   provider: gemini({ project: 'my-project', location: 'us-central1' }),
 *   model: 'gemini',
 * })
 *   .tool(weatherTool)
 *   .build();
 * ```
 *
 * @example  Gemini API (one key, no cloud project)
 * ```ts
 * const provider = gemini({ apiKey: process.env.GEMINI_API_KEY });
 * ```
 *
 * @throws at construction when neither a project nor an API key is resolvable,
 *         and when `@google/genai` is not installed.
 */
export declare function gemini(options?: GeminiProviderOptions): LLMProvider;
/**
 * Class form for consumers who prefer `new GeminiProvider(...)` over the
 * `gemini(...)` factory. Identical behavior; trivial wrapper.
 */
export declare class GeminiProvider implements LLMProvider {
    readonly name = "gemini";
    readonly carriesInMessages: readonly WireRole[];
    readonly carriesForcedToolChoice = true;
    private readonly inner;
    constructor(options?: GeminiProviderOptions);
    complete(req: LLMRequest, hooks?: LLMCallHooks): Promise<LLMResponse>;
    stream(req: LLMRequest, hooks?: LLMCallHooks): AsyncIterable<LLMChunk>;
}
