import type { Api, Model } from "@earendil-works/pi-ai/compat";
/**
 * Round-trips GitHub Copilot Gemini "thought signatures" so multi-turn tool use
 * does not silently die after the first tool call.
 *
 * Why this exists
 * ---------------
 * `github-copilot` Gemini models (e.g. `gemini-3.1-pro-preview`) are served
 * through Copilot's CAPI gateway, which proxies to Google's GenAI API. Gemini
 * is a thinking model: when it emits a function/tool call it also returns an
 * opaque **thought signature** that must be sent back, verbatim, on the next
 * request or Gemini refuses to continue the reasoning chain.
 *
 * CAPI carries that signature in a non-standard OpenAI-completions field named
 * **`reasoning_opaque`** (an encrypted blob) on the assistant message / streamed
 * delta, and on replay it reads the same `reasoning_opaque` back off the
 * assistant message and re-attaches the signature to each Gemini function-call
 * part (keyed by `tool_call.id`). The underlying OpenAI-completions client
 * (`@earendil-works/pi-ai`) does not understand `reasoning_opaque`; it captures
 * thought signatures only from the OpenRouter-style
 * `reasoning_details: [{ type: "reasoning.encrypted", id, data }]` shape, which
 * CAPI never emits. So the real Gemini thought signature was being dropped on
 * the way in and never replayed on the way out.
 *
 * With the signature missing, CAPI substitutes the sentinel
 * `skip_thought_signature_validator` on the first replayed function call, and
 * Gemini responds with an empty candidate / `finish_reason: "stop"` and zero
 * output tokens — the harness sees a degenerate empty completion, retries with
 * the same signature-less history, and eventually gives up: "Gemini just stops
 * responding."
 *
 * What this does
 * --------------
 * Two gated, self-contained transforms bridge CAPI's `reasoning_opaque` to the
 * `reasoning_details` mechanism the client already round-trips:
 *
 *  - **Inbound** ({@link rewriteCopilotGeminiSseData} via
 *    {@link createCopilotGeminiSseStream}): rewrites the CAPI Gemini SSE
 *    stream so each streamed delta that carries both `reasoning_opaque` and a
 *    `tool_calls[].id` gains a
 *    `reasoning_details: [{ type: "reasoning.encrypted", id, data: <opaque> }]`
 *    entry. The client then stores it as the tool call's `thoughtSignature`.
 *    CAPI confirms `reasoning_opaque` rides on the same streamed delta as the
 *    first (id-bearing) tool-call chunk, so the association is exact.
 *  - **Outbound** ({@link restoreCopilotGeminiReasoningOpaque} from the
 *    `onPayload` hook): converts the `reasoning_details` the client re-emits on
 *    replayed assistant messages back into a single `reasoning_opaque` field on
 *    that assistant message, which is the only shape CAPI reads.
 *
 * Both transforms are gated to GitHub Copilot Gemini and are no-ops for every
 * other provider/model (and for Gemini turns that carry no thought signature).
 */
type JsonObject = {
    [key: string]: JsonValue;
};
type JsonValue = string | number | boolean | null | JsonValue[] | JsonObject;
/**
 * Inject `reasoning_details` into a parsed CAPI Gemini streaming chunk so the
 * pi-ai OpenAI-completions parser captures the Gemini thought signature.
 *
 * For each `choices[].delta` that carries a non-empty `reasoning_opaque` string
 * and a `tool_calls[]` entry with an `id`, adds a single
 * `reasoning_details: [{ type: "reasoning.encrypted", id, data: <opaque> }]`
 * entry keyed by that tool-call id. Returns whether the chunk was mutated.
 *
 * No-op when the delta already has `reasoning_details`, has no id-bearing tool
 * call (e.g. argument-continuation deltas or pure-text thought chunks), or has
 * no `reasoning_opaque`.
 */
export declare function injectCopilotGeminiReasoningDetails(chunk: JsonValue): boolean;
/**
 * Rewrite the JSON payload of a single SSE `data:` line. Returns the original
 * string unchanged when it is not a Gemini chunk that needs a thought signature
 * bridged, or when parsing fails (fail-open: never corrupt the stream).
 */
export declare function rewriteCopilotGeminiSseData(dataPayload: string): string;
/**
 * Wrap a CAPI Gemini SSE byte stream so `reasoning_opaque` is bridged into
 * `reasoning_details`. Buffers across chunk boundaries and rewrites whole lines
 * only; bytes that are not affected pass through unchanged.
 *
 * Implemented as a `ReadableStream` over the source reader (rather than a
 * `TransformStream` piped via `pipeThrough`) so the transform pulls lazily and
 * propagates cancellation to the upstream body.
 */
export declare function createCopilotGeminiSseStream(source: ReadableStream<Uint8Array>): ReadableStream<Uint8Array>;
/**
 * Convert the `reasoning_details` the pi-ai client re-emits on replayed
 * assistant messages back into the single `reasoning_opaque` field CAPI reads.
 *
 * For GitHub Copilot Gemini payloads, each assistant message that carries a
 * `reasoning_details` entry of `type: "reasoning.encrypted"` has its `data`
 * (the original CAPI thought-signature blob) promoted to `reasoning_opaque`,
 * and the now-redundant `reasoning_details` removed. No-op for every other
 * provider/model and for payloads without such messages.
 */
export declare function restoreCopilotGeminiReasoningOpaque(payload: unknown, model: Pick<Model<Api>, "provider" | "api" | "id">): unknown;
/**
 * Rewrite a streaming CAPI Gemini response so its SSE body bridges
 * `reasoning_opaque` into `reasoning_details`. Returns the original response
 * untouched for non-Copilot hosts, non-event-stream responses, or bodyless
 * responses, keeping the blast radius to streaming CAPI Gemini turns only.
 */
export declare function maybeRewriteCopilotGeminiResponse(url: string | undefined, response: Response): Response;
/**
 * Apply Copilot response-body transforms before pi-ai parses streamed provider
 * output. Anthropic Messages repair gets first refusal for `/v1/messages`
 * streams; other Copilot event streams keep the existing Gemini reasoning bridge.
 */
export declare function maybeRewriteCopilotProviderResponse(url: string | undefined, response: Response): Response;
/**
 * Install a `globalThis.fetch` wrapper that applies Copilot-only stream
 * compatibility shims before pi-ai parses provider output. Currently this
 * includes the Gemini `reasoning_opaque` bridge and the Anthropic Messages
 * terminal `message_stop` repair. Idempotent.
 *
 * SDK clients resolve `globalThis.fetch` at client-construction time, and a new
 * client is built per request, so wrapping the global before the first request
 * is reliably picked up. Non-Copilot hosts and non-event-stream responses are
 * returned untouched by the underlying shims.
 */
export declare function installCopilotResponseInterceptor(): void;
/** Backward-compatible name for the original Gemini-only interceptor export. */
export declare function installCopilotGeminiReasoningInterceptor(): void;
export {};
//# sourceMappingURL=copilot-gemini-reasoning.d.ts.map