import type { ResponseInput } from "openai/resources/responses/responses"; import type { CacheRetention, OpenAIResponsesHistoryPayload, ProviderPayload } from "./types"; export { isRecord } from "@gajae-code/utils"; export declare function normalizeSystemPrompts(systemPrompt: readonly string[] | string | undefined | null): string[]; export declare function sanitizeJsonStrings(value: unknown): unknown; export declare function toNumber(value: unknown): number | undefined; export declare function toPositiveNumber(value: unknown, fallback: number): number; export declare function toBoolean(value: unknown): boolean | undefined; export declare function normalizeToolCallId(id: string): string; type ResponsesToolItemIdPrefix = "fc" | "ctc"; export declare function normalizeResponsesToolCallId(id: string, itemPrefix?: ResponsesToolItemIdPrefix): { callId: string; itemId: string; }; /** * Truncate an OpenAI Responses API item ID to 64 characters. * IDs exceeding the limit are replaced with a hash-based ID using the given prefix. */ export declare function truncateResponseItemId(id: string, prefix: string): string; export declare function sanitizeOpenAIResponsesHistoryItemsForReplay(items: Array>): ResponseInput; /** * Neutralize leaked OpenAI Harmony / control tokens (`<|channel|>`, `<|message|>`, * `<|call|>`, `<|constrain|>`, `<|recipient|>`, `<|content|>`, ...) in replayed * history text. A subagent whose tool-call channel degenerates can dump raw * control-token scaffolding into its reply text; once that poisoned text lands in * history the Codex / Responses endpoint rejects every subsequent request with * `Request blocked (code=invalid_prompt)`, permanently wedging the session because * the offending item is re-sent on each turn. Insert a zero-width space after `<` * so the delimiter can no longer be tokenized as a reserved control token while the * text stays human-readable. * * The pattern matches the two control-token shapes only, so ordinary text and pipe * syntax is left untouched: * - simple form `<|ident|>` — a leading run of identifier chars then `|>`; and * - header form `<|role to=recipient|>` — a known Harmony role * (`system`/`developer`/`user`/`assistant`/`tool`) followed by a single * recipient assignment `to=` whose value is an unbounded run of * non-delimiter, non-whitespace chars (so long MCP/custom tool recipients like * `to=functions.` are covered). * The header branch is deliberately scoped to the known role + `to=` recipient * grammar rather than an arbitrary `key=value`, so request-boundary sanitization * never rewrites non-control delimiter text such as `<|foo bar=baz|>`. A single-line * body (no `\n`) and the required leading identifier char also leave compact * pipe/operator syntax alone — e.g. F# `value <| f |> g` (space after `<|`), * `sum<|a+b|>c` (punctuation body), and `<|foo bar|>` (no assignment) never match. * The simple branch is a strict superset of the original identifier-only pattern: * every marker the old regex caught still matches. */ export declare function neutralizeReservedControlTokens(text: string): string; /** * Shape-tolerant classifier for the poisoned-history rejection that wedges * gpt-5.6 sessions: `Request blocked (code=invalid_prompt)`. Accepts a raw * provider error, an assistant message, or any object carrying a * `providerCode` / `transportFailure` / `errorMessage` field, and returns true * when the failure is the deterministic `invalid_prompt` content fault rather * than a transient upstream error. This is the single shared contract the * provider transports and the session-level circuit breaker key on so the * classification is explicit (not inferred from a catch-all bucket) and * uniformly testable across transports. */ export declare function isInvalidPromptError(input: unknown): boolean; /** * Shape-tolerant classifier for the DeepSeek-family reasoning-content replay * rejection: "The `reasoning_content` in the thinking mode must be passed back * to the API." DeepSeek V4 (and reasoning-capable siblings reached through any * OpenAI-compatible proxy) 400 every follow-up turn once a prior assistant turn * carried reasoning the proxy stripped to an empty `encrypted_content` / * `reasoning_content`. Resending the identical history re-triggers it, so naive * session auto-retry just burns the budget — it needs the same bounded * repair-and-resend contract as the `invalid_prompt` poisoned-history breaker. * * Accepts a raw provider error, an assistant message, or any object carrying an * `errorMessage` field (the agent-loop circuit breaker keys on this). */ export declare function isReasoningContentReplayError(input: unknown): boolean; /** * Remove Responses-API `reasoning` items whose `encrypted_content` is missing or * empty from an outgoing history payload. DeepSeek rejects replay of reasoning * whose encrypted blob a proxy stripped to `""`; dropping those items lets the * model re-reason on the next turn instead of re-triggering a deterministic 400. * Non-reasoning items (text, function_call, function_call_output, ...) are kept * verbatim so tool-use pairing and message order are preserved. Returns whether * any item was actually removed — the circuit breaker uses this to decide * between a single repaired resend (removed) and immediate fail-fast (unchanged). */ export declare function stripUnusableReasoningItems(items: Array>): { result: Array>; removed: number; }; /** * Neutralize leaked reserved control tokens across every string in an outgoing * Responses `input` array. This is the request-boundary complement to the * replay-history sanitizer: leaked Harmony markers (`<|channel|>analysis`, ...) * can enter the payload from assistant reasoning summaries, live-converted * message/tool-output text, or user-authored content — not just replayed * history — and every gpt-5.6 request that carries one is rejected with * `Request blocked (code=invalid_prompt)`. Walking every string (rather than an * item-type allowlist) guarantees no leak source is missed as item shapes * evolve; the zero-width-space insertion is idempotent (`<\u200b|` no longer * matches `<|`) and keeps the text human-readable. */ export declare function neutralizeResponsesInputControlTokens(items: readonly T[]): T[]; export declare function createOpenAIResponsesHistoryPayload(provider: string, items: Array>, incremental?: boolean): OpenAIResponsesHistoryPayload; export declare function getOpenAIResponsesHistoryPayload(providerPayload: ProviderPayload | undefined, currentProvider: string, fallbackProvider?: string): OpenAIResponsesHistoryPayload | undefined; export declare function getOpenAIResponsesHistoryItems(providerPayload: ProviderPayload | undefined, currentProvider: string, fallbackProvider?: string): Array> | undefined; /** * Resolve cache retention preference. * * Resolution order: explicit request value → `GJC_CACHE_RETENTION` → * legacy `PI_CACHE_RETENTION` → `fallback`. Both env vars act as explicit * opt-in (`"long"`) or opt-out (any other value) so a provider-specific * `fallback` only applies when nothing else is configured. `fallback` * defaults to `"short"` to preserve the historical behaviour for callers * that don't pass one. */ export declare function resolveCacheRetention(cacheRetention?: CacheRetention, fallback?: CacheRetention): CacheRetention; export declare function isAnthropicOAuthToken(key: string): boolean;