dsh-model-think-level 1.1.0 → 1.1.2
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/lib/client/HeadersEditor.d.ts +42 -2
- package/lib/client/injection/add-card.d.ts +72 -0
- package/lib/client/injection/create-card-pane.d.ts +53 -0
- package/lib/client/injection/editor-tabs.d.ts +17 -0
- package/lib/client/injection/models-page-editor.d.ts +68 -4
- package/lib/client/injection/saved-notice.d.ts +28 -0
- package/lib/client/injection/staged-headers.d.ts +128 -0
- package/lib/client/ops.d.ts +16 -0
- package/lib/client/styles.d.ts +1 -1
- package/lib/client.js +59 -14
- package/lib/client.js.map +4 -4
- package/lib/index.js +6 -1
- package/lib/index.js.map +2 -2
- package/package.json +1 -1
package/lib/index.js.map
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"version": 3,
|
|
3
3
|
"sources": ["../src/index.ts", "../src/constants.ts", "../src/key-refs.ts", "../src/key-index.ts", "../src/knowledge.ts", "../src/guard.ts", "../src/shared.ts", "../src/headers-core.ts", "../src/headers-fetch.ts", "../src/headers-pi-ai.ts", "../src/headers-conflict.ts", "../src/autofill.ts"],
|
|
4
|
-
"sourcesContent": ["/**\n * Host half of dsh-model-think-level.\n *\n * One job: settings auto-adaptation. Whenever the `llm-pi-ai` section gains a\n * hand-declared model that carries no `reasoningEfforts`, fill one in from the\n * knowledge base + protocol inference (see {@link suggestEfforts}). The fill\n * is a *suggestion* written to the user layer \u2014 the user can still edit it on\n * the Models page \u2014 and a model that already declares efforts, or an explicit\n * `false`, is never touched. All interactive editing (per-model editors and\n * per-model auto-adapt) lives in the browser half, which reuses the same\n * knowledge base as a pure module.\n *\n * @module dsh-model-think-level\n */\n\nimport type { IncomingMessage, ServerResponse } from 'node:http'\nimport type { Context } from '@deepseek-ai/cordis'\n// Type-only: pulls the webServer service merge into this program's Context.\nimport type {} from '@deepseek-ai/dsh-host-webserver'\n// Type-only: the `declare module '@deepseek-ai/cordis'` merge that types\n// `ctx.settings` as the profile-form service. `describe()` returns one\n// descriptor per active entry: an ARRAY, not the wire `{namespaces}` envelope.\n// The kernel ships no `settingsNamespace` value export (it is a private parse\n// + a compile-time SettingsNamespaceInput); the brand is a compile-time\n// concept, so a typed constant is enough.\nimport type { SettingsNamespace } from '@deepseek-ai/dsh-settings'\nimport Schema from '@deepseek-ai/schemastery'\nimport {\n AUTOFILL_CONFIG_PATH,\n DIAG_PATH,\n HEADERS_CONFIG_PATH,\n KEY_INDEX_PATH,\n PI_AI_NS,\n PLUGIN_ID,\n PROBE_PATH,\n PROVIDER_KEY_PATH,\n} from './constants.js'\nimport { isLegalKeyValue, maskKeyValue, nextKeyRef, normalizeKeyAlias } from './key-refs.js'\nimport {\n hasKeyEntry,\n keyEntriesOf,\n keyIndexFilePath,\n readKeyIndex,\n updateKeyIndex,\n withKeyAlias,\n withKeyEntry,\n withoutKeyEntry,\n} from './key-index.js'\nimport { suggestEfforts } from './knowledge.js'\nimport type { ReasoningEfforts } from './knowledge.js'\nimport { resolveGuardEffort } from './guard.js'\nimport { isRecord, looksLikeCompatRefusal, routeFactsOf } from './shared.js'\nimport { buildHeaderIndex, emptyIndex, type UserAgentIndex } from './headers-core.js'\nimport { headerOverlayInstalled, installHeaderOverlay, type OverlaySource } from './headers-fetch.js'\nimport { describePiAiHeaderState, installPiAiHeaderTransforms } from './headers-pi-ai.js'\nimport { detectHeaderConflicts, type HeaderConflictReport } from './headers-conflict.js'\n// The knowledge-base patch builder lives in its own module: the browser half\n// builds the SAME patch from its own idle-time read, so one suggestion can\n// never produce two different documents.\nimport { buildAutofillPatch, stripNewCompatKeysDeep } from './autofill.js'\n\n/** Re-exported so the package entry keeps naming the patch builder. */\nexport { buildAutofillPatch }\n\n/** Stable plugin id, matching the cordis.patch.yml row and the bundle id. */\nexport const name = PLUGIN_ID\n\n/** Hard dependencies: the loader waits for these before calling apply. */\nexport const inject = ['settings', 'llm']\n\n/** The branded settings namespace this plugin reads and fills. */\nconst PI_NS = PI_AI_NS as SettingsNamespace\n\n/**\n * Exponential backoff for the boot fill: llm-pi-ai may register its namespace\n * well after this plugin on a slow start, and registration emits no event of\n * its own \u2014 the schedule must outlast a realistically slow profile instead of\n * giving up after a few flat seconds.\n */\nconst BOOT_RETRY_DELAYS_MS = [1_000, 2_000, 4_000, 8_000, 16_000, 30_000] as const\n\n/** Probe fetch budget: a gateway that cannot answer /models in 15s will not answer the composer either. */\nconst PROBE_TIMEOUT_MS = 15_000\n\n/**\n * Plugin configuration, supplied through the profile's cordis layer\n * (the row's `config:` block). Every tunable two deployments may want\n * to set differently lives here rather than as a code constant.\n */\nexport interface Config {\n /** Auto-fill undeclared pi-ai models on boot and after settings updates (default true). */\n autofill?: boolean\n /**\n * Whether the auto-fill above also fills the input-modality declaration\n * (default true). Effort auto-fill is governed by {@link autofill} alone.\n */\n modalityAutofill?: boolean\n /** Upstream fetch timeout for the raw /models probe route, in milliseconds (default 15000). */\n probeTimeoutMs?: number\n /**\n * Boot-fill retry backoff schedule in milliseconds; an empty list means\n * \"try exactly once\" (default [1000, 2000, 4000, 8000, 16000, 30000]).\n */\n bootRetryDelaysMs?: number[]\n /**\n * Rewrite effort-less calls to forced-thinking ladders into the ladder's\n * vendor default (default true). Only the request class that today becomes\n * `thinking: {type: disabled}` on a ladder that cannot switch thinking off\n * is rewritten (issue #2); everything else passes through byte-identical.\n */\n defaultGuard?: boolean\n /**\n * Take over the configured request headers at the fetch layer for every route\n * whose `headers` declare one (default true). The official adapter may merge\n * attribution headers over profile values, so the overlay reapplies the\n * profile dictionary before the request reaches the wire. The historical\n * `uaOverride` name is retained for configuration compatibility.\n */\n uaOverride?: boolean\n}\n\n/** Schemastery schema: Cordis validates the row config and fills defaults before apply(). */\nexport const Config: Schema<Config> = Schema.object({\n autofill: Schema.boolean().default(true),\n modalityAutofill: Schema.boolean().default(true),\n probeTimeoutMs: Schema.natural().min(1).default(PROBE_TIMEOUT_MS),\n bootRetryDelaysMs: Schema.array(Schema.natural().min(1)).default([...BOOT_RETRY_DELAYS_MS]),\n defaultGuard: Schema.boolean().default(true),\n uaOverride: Schema.boolean().default(true),\n})\n\ninterface CredentialsService {\n resolve(ref: string): Promise<{ value?: string } | undefined>\n /** Per-reference configuration facts \u2014 never the values themselves. */\n describe?(refs: string[]): Promise<unknown>\n /** Store one value under one reference. */\n set?(ref: string, value: string): Promise<unknown>\n /** Forget one reference's value. */\n unset?(ref: string): Promise<unknown>\n}\n\n/** One row of the key manager's list, as the browser half reads it. */\ninterface KeyEntryView {\n /** Credential reference holding the value. */\n ref: string\n /** Stored label, when the user gave one. */\n alias?: string\n /** Whether this is the reference the adapter resolves. */\n enabled: boolean\n /** Whether the store holds a value; null when the store cannot say. */\n configured: boolean | null\n /** The value in its display form, when the store let it be read. */\n masked?: string\n}\n\n/** One route's profile inside a pi-ai section value, or undefined. */\nfunction providerProfileOf(section: unknown, route: string): Record<string, unknown> | undefined {\n if (!isRecord(section)) return undefined\n const providers = section['providers']\n if (!isRecord(providers)) return undefined\n const profile = providers[route]\n return isRecord(profile) ? profile : undefined\n}\n\n/** The reference one profile names as the key in use, when it names one. */\nfunction enabledRefOf(profile: Record<string, unknown> | undefined): string | undefined {\n const ref = profile?.['apiKeyEnv']\n return typeof ref === 'string' && ref.length > 0 ? ref : undefined\n}\n\n/** Whether a host-service answer is the refusal envelope (`{ok: false}`). */\nfunction isRefusal(answer: unknown): boolean {\n return isRecord(answer) && answer['ok'] === false\n}\n\n/** The message a host-service answer carries when it refuses. */\nfunction refusalMessage(answer: unknown): string | undefined {\n if (!isRecord(answer)) return undefined\n const error = answer['error']\n if (typeof error === 'string') return error\n if (isRecord(error) && typeof error['message'] === 'string') return error['message']\n return typeof answer['message'] === 'string' ? answer['message'] : undefined\n}\n\n/**\n * The per-reference info map a `credentials.describe()` answer carries. The\n * host service is documented to answer the map itself while the Remote face\n * wraps it in the `{ok, value}` envelope; both are read here.\n */\nfunction describeRecords(answer: unknown): Record<string, unknown> | undefined {\n const candidate = isRecord(answer) && answer['value'] !== undefined ? answer['value'] : answer\n return isRecord(candidate) ? candidate : undefined\n}\n\n/** Store one value under one reference; the refusal text, or undefined. */\nasync function storeCredential(\n credentials: CredentialsService | undefined,\n ref: string,\n value: string,\n): Promise<string | undefined> {\n const set = credentials?.set\n if (credentials === undefined || typeof set !== 'function') {\n return 'this deployment cannot write the credential store'\n }\n try {\n const answer = await set.call(credentials, ref, value)\n if (!isRefusal(answer)) return undefined\n return refusalMessage(answer) ?? `the credential store refused ${ref}`\n } catch (error) {\n return error instanceof Error ? error.message : String(error)\n }\n}\n\n/** Forget one reference's value; the refusal text, or undefined. */\nasync function forgetCredential(credentials: CredentialsService | undefined, ref: string): Promise<string | undefined> {\n const unset = credentials?.unset\n if (credentials === undefined || typeof unset !== 'function') {\n return 'this deployment cannot write the credential store'\n }\n try {\n const answer = await unset.call(credentials, ref)\n if (!isRefusal(answer)) return undefined\n return refusalMessage(answer) ?? `the credential store refused to forget ${ref}`\n } catch (error) {\n return error instanceof Error ? error.message : String(error)\n }\n}\n\n/** What the store will say about one reference: configured, and its masked value. */\ninterface CredentialFacts {\n configured: boolean\n masked?: string\n}\n\n/**\n * What the store will say about each reference: whether it holds a value, and \u2014\n * when the value can be read \u2014 the display form the list shows beside it.\n *\n * `describe` answers `configured` without handing the secret over, which is all\n * a badge needs; the masked preview needs the value itself, so it comes from\n * `resolve`, the same call the eye already makes. `describe` stays authoritative\n * about `configured` when both answer. A reference neither can speak about is\n * simply absent from the map.\n */\nasync function credentialFacts(\n credentials: CredentialsService | undefined,\n refs: readonly string[],\n): Promise<Record<string, CredentialFacts>> {\n const out: Record<string, CredentialFacts> = {}\n if (credentials === undefined || refs.length === 0) return out\n const describe = credentials.describe\n if (typeof describe === 'function') {\n try {\n const records = describeRecords(await describe.call(credentials, [...refs]))\n for (const ref of refs) {\n const info = records?.[ref]\n if (isRecord(info) && typeof info['configured'] === 'boolean') {\n out[ref] = { configured: info['configured'] }\n }\n }\n } catch {\n // Unanswered references fall through to resolve() below.\n }\n }\n const resolve = credentials.resolve\n for (const ref of refs) {\n try {\n const hit = await resolve.call(credentials, ref)\n const value = hit !== undefined && typeof hit.value === 'string' ? hit.value : undefined\n const configured = out[ref]?.configured ?? (value !== undefined && value.length > 0)\n const masked = value === undefined ? undefined : maskKeyValue(value)\n out[ref] = masked === undefined || masked.length === 0 ? { configured } : { configured, masked }\n } catch {\n // Leave it unknown: a badge is not worth failing the list over.\n }\n }\n return out\n}\n\n/**\n * Which references hold a value, as far as the store will say.\n *\n * Kept as the narrow question for callers that only badge the list; the list\n * itself asks `credentialFacts` so one read answers both.\n */\nasync function credentialConfigured(\n credentials: CredentialsService | undefined,\n refs: readonly string[],\n): Promise<Record<string, boolean>> {\n const facts = await credentialFacts(credentials, refs)\n const out: Record<string, boolean> = {}\n for (const ref of refs) {\n const configured = facts[ref]?.configured\n if (configured !== undefined) out[ref] = configured\n }\n return out\n}\n\n/** Whether a settings write was refused because the document moved under it. */\nfunction isConflictError(error: unknown): boolean {\n return isRecord(error) && error['code'] === 'SETTINGS_CONFLICT'\n}\n\n/** Read a small JSON request body; undefined when there is nothing to read. */\nasync function readJsonBody(req: IncomingMessage, limit = 8192): Promise<unknown> {\n const decoder = new TextDecoder()\n let text = ''\n try {\n for await (const chunk of req as AsyncIterable<Uint8Array | string>) {\n text += typeof chunk === 'string' ? chunk : decoder.decode(chunk, { stream: true })\n // A provider key is short; anything larger is not a body this route serves.\n if (text.length > limit) return undefined\n }\n } catch {\n return undefined\n }\n if (text.length === 0) return undefined\n try {\n return JSON.parse(text)\n } catch {\n return undefined\n }\n}\n\nfunction isLoopbackHostname(hostname: string): boolean {\n return hostname === 'localhost' || hostname === '127.0.0.1' || hostname === '::1'\n}\n\n/** WHATWG-parse a Host/Origin authority (`host` or `host:port`). */\nfunction parseAuthority(authority: string): URL | undefined {\n try {\n // http: is a WHATWG special scheme: parsing yields a hostname or throws,\n // and normalizes casing the raw header keeps. Note the hostname of an\n // IPv6 authority KEEPS its brackets (`[::1]`) \u2014 the literal check below\n // deliberately matches on the colon.\n return new URL(`http://${authority}`)\n } catch {\n return undefined\n }\n}\n\n/**\n * Whether a parsed hostname is an IP literal (IPv4 dotted quad, or IPv6 whose\n * brackets URL parsing already stripped). A browser fills Host from the URL it\n * believes it is talking to, so a DNS-rebound page ALWAYS carries the\n * attacker's domain here \u2014 it can never produce an IP-literal Host short of\n * the user genuinely navigating to that IP.\n */\nfunction isIpLiteralHostname(hostname: string): boolean {\n return /^\\d{1,3}(\\.\\d{1,3}){3}$/.test(hostname) || hostname.includes(':')\n}\n\n/**\n * Browser trust fence for the probe route. It mirrors the core /api fence's\n * DEFENSE (packages/client/connection/src/api-request-trust.ts) minus one\n * feature: there is no `trustedHosts` escape hatch yet.\n *\n * - Cross-site requests are refused outright; a same-origin/same-site\n * marker never ADMITS anything by itself.\n * - An attached Origin must name exactly this authority; the literal\n * `null` (sandboxed iframe, file: page) is refused.\n * - The Host fence binds every request and is the rebinding defense:\n * only loopback names and IP literals are answered. A rebound page\n * names the attacker's DOMAIN in Host even though the socket lands on\n * this server, so named hosts are always 403.\n *\n * The route proxies only endpoints the user's own settings already name, but\n * it does so with the stored credential attached \u2014 so it must not be callable\n * from elsewhere. LAN deployments serving the GUI under a DOMAIN name get 403\n * here by design (IP-literal LAN hosts keep working); see README known\n * limitations until a trustedHosts seam exists.\n */\nfunction isTrustedRequest(req: IncomingMessage): boolean {\n const host = req.headers.host\n if (typeof host !== 'string' || host.length === 0) return false\n const hostUrl = parseAuthority(host)\n if (hostUrl === undefined) return false\n const secFetchSite = req.headers['sec-fetch-site']\n if (secFetchSite === 'cross-site') return false\n const origin = req.headers.origin\n if (typeof origin === 'string') {\n if (origin === 'null') return false\n try {\n if (new URL(origin).host !== hostUrl.host) return false\n } catch {\n return false\n }\n }\n const hostname = hostUrl.hostname.toLowerCase()\n return isLoopbackHostname(hostname) || isIpLiteralHostname(hostname)\n}\n\nfunction sendJson(res: ServerResponse, status: number, body: unknown): void {\n res.statusCode = status\n res.setHeader('content-type', 'application/json; charset=utf-8')\n res.end(JSON.stringify(body))\n}\n\n/**\n * A URL safe to echo in responses: a baseURL may carry userinfo\n * (https://user:pass@host), and failure messages must never repeat it.\n */\nfunction displayUrl(raw: string): string {\n try {\n const url = new URL(raw)\n url.username = ''\n url.password = ''\n return url.toString()\n } catch {\n return raw\n }\n}\n\n/**\n * Probe-listing URL, mirroring the harness's own model discovery:\n * OpenAI-compatible protocols list at\n * `{baseURL}/models`; Anthropic Messages uses its native route at\n * `{root}/v1/models?limit=1000`, where the root is the base without trailing\n * slashes and without one trailing `/v1` segment (gateway documentation\n * publishes both spellings of the same root). Only this listing URL\n * normalizes that segment.\n */\nfunction probeListingUrl(baseURL: string, api: string): string {\n const base = baseURL.replace(/\\/+$/, '')\n if (api !== 'anthropic-messages') return `${base}/models`\n const root = base.endsWith('/v1') ? base.slice(0, -3) : base\n return `${root}/v1/models?limit=${String(ANTHROPIC_MODEL_LIMIT)}`\n}\n\n/** Protocols whose model listing this module can read (the harness discovery set). */\nconst LISTABLE_PROTOCOLS: ReadonlySet<string> = new Set([\n 'anthropic-messages',\n 'openai-completions',\n 'openai-responses',\n])\n\n/** Stable API version required by Anthropic's model-listing endpoint. */\nconst ANTHROPIC_VERSION = '2023-06-01'\n\n/** Largest model-list page accepted by Anthropic's public endpoint. */\nconst ANTHROPIC_MODEL_LIMIT = 1000\n\n/**\n * Compose the raw-models probe request's headers, mirroring the discipline of\n * the harness's own model discovery: the provider\n * profile's configured request headers form the base (deployment-owned\n * credentials like `x-api-key` ride along), `accept` is always JSON, and a\n * resolved credential's Bearer overwrites a profile `authorization` \u2014 which\n * survives only when no credential resolves (a route may authenticate through\n * its configured headers alone). Anthropic Messages answers through\n * `x-api-key` plus a fixed `anthropic-version`, and its Bearer arm is never\n * used (a profile `authorization` survives untouched there, exactly as the\n * official discovery leaves it). Entries Fetch would refuse are dropped\n * rather than failing the probe. Harness attribution headers are deliberately\n * not sent \u2014 this is a same-origin diagnostic, not a harness request.\n * @param profileHeaders - the profile's raw `headers` dict (simply absent\n * on older documents).\n * @param apiKey - the resolved credential, when one resolved.\n * @param api - the profile's wire protocol.\n */\nexport function composeProbeHeaders(\n profileHeaders: unknown,\n apiKey: string | undefined,\n api: string,\n): Record<string, string> {\n const headers = new Headers()\n if (isRecord(profileHeaders)) {\n for (const [name, value] of Object.entries(profileHeaders)) {\n if (typeof value !== 'string') continue\n try {\n headers.set(name, value)\n } catch {\n // Unrepresentable as a Fetch header: skip the entry, keep probing.\n }\n }\n }\n headers.set('accept', 'application/json')\n if (api === 'anthropic-messages') {\n headers.set('anthropic-version', ANTHROPIC_VERSION)\n if (apiKey !== undefined) headers.set('x-api-key', apiKey)\n } else if (apiKey !== undefined) {\n headers.set('authorization', `Bearer ${apiKey}`)\n }\n return Object.fromEntries(headers.entries())\n}\n\n/**\n * Read a listing reply body, refusing one that outgrows the ceiling (the same\n * bound the official discovery applies). A declared length is checked first\n * so an honest server is turned away without transferring anything; the\n * accumulated total is what actually enforces the bound.\n */\nasync function readBounded(response: Response, url: string): Promise<string> {\n const declared = Number(response.headers.get('content-length') ?? Number.NaN)\n if (Number.isFinite(declared) && declared > MAX_RESPONSE_BYTES) {\n await response.body?.cancel()\n throw new Error(`${displayUrl(url)} overshoots the ${MAX_RESPONSE_BYTES}-byte listing ceiling`)\n }\n if (response.body === null) return ''\n const reader = response.body.getReader()\n const chunks: Uint8Array[] = []\n let total = 0\n try {\n for (;;) {\n const { done, value } = await reader.read()\n if (done) break\n total += value.byteLength\n if (total > MAX_RESPONSE_BYTES) throw new Error(`${displayUrl(url)} overshoots the ${MAX_RESPONSE_BYTES}-byte listing ceiling`)\n chunks.push(value)\n }\n } finally {\n await reader.cancel().catch(() => {\n // Cancel after a drained read, or after this function walked away from\n // an oversized one, is cleanup; the reply is already decided either way.\n })\n }\n const body = new Uint8Array(total)\n let offset = 0\n for (const chunk of chunks) {\n body.set(chunk, offset)\n offset += chunk.byteLength\n }\n return new TextDecoder().decode(body)\n}\n\n/** Largest listing reply the probe accepts (same bound as official discovery). */\nconst MAX_RESPONSE_BYTES = 4 * 1024 * 1024\n\n/**\n * Normalize a supported listing reply into one entry array, mirroring the\n * official parser: the standard `data` array takes precedence; the\n * enriched `models` map uses each property key as the endpoint-facing id\n * (the nested `id` only falls back for an empty key \u2014 gateways may put a\n * canonical identity there instead of the alias they accept on requests);\n * only object-valued map entries are models, and entries without a usable id\n * are dropped. Returns undefined when the listing names neither shape.\n */\nfunction listingEntries(body: unknown): Record<string, unknown>[] | undefined {\n const listing = isRecord(body) ? body : {}\n const data = listing['data']\n if (Array.isArray(data)) return data.filter(isRecord)\n const models = listing['models']\n if (isRecord(models)) {\n return Object.entries(models)\n .filter(([, raw]) => isRecord(raw))\n .map(([key, raw]) => {\n // The map key is the endpoint-facing id, but an EMPTY key falls back\n // to the entry's own id exactly as the official parser's\n // label(key, entry.id) does \u2014 gateways may put the canonical identity\n // there instead of the alias they accept on requests.\n const entry = raw as Record<string, unknown>\n const ownId = typeof entry['id'] === 'string' && entry['id'].length > 0 ? entry['id'] : ''\n return { ...entry, id: key.length > 0 ? key : ownId }\n })\n .filter(entry => typeof entry['id'] === 'string' && entry['id'].length > 0)\n }\n return undefined\n}\n\n/**\n * The llm-service surface the default-guard wraps: only the two dispatch\n * entries, typed structurally so no new dependency is needed.\n */\ninterface LlmDispatchLike {\n prepareCall(config: Record<string, unknown>, signal?: unknown): Promise<Record<string, unknown>>\n stream(options: Record<string, unknown>): AsyncIterable<unknown>\n}\n\n/**\n * Fill one call config with the vendor default when it names no effort and\n * its declared ladder cannot switch thinking off (issue #2).\n *\n * Reads the resolved pi-ai section (never the user layer -- this only reads).\n * Fails open: any unreadable shape returns the config untouched, reproducing\n * today's behavior exactly.\n */\nfunction guardCallConfig(cfg: Record<string, unknown>, section: unknown): Record<string, unknown> {\n try {\n if (typeof cfg['reasoningEffort'] !== 'undefined') return cfg\n const provider = cfg['provider']\n const modelId = cfg['model']\n if (typeof provider !== 'string' || typeof modelId !== 'string') return cfg\n if (!isRecord(section)) return cfg\n const providers = section['providers']\n if (!isRecord(providers)) return cfg\n const profile = providers[provider]\n if (!isRecord(profile)) return cfg\n const rawModels = profile['models']\n if (!Array.isArray(rawModels)) return cfg\n const row = rawModels.find((candidate): candidate is Record<string, unknown> =>\n isRecord(candidate) && candidate['id'] === modelId)\n if (row === undefined || !isRecord(row['reasoningEfforts'])) return cfg\n const profileDefault = typeof profile['reasoning'] === 'string' ? profile['reasoning'] : undefined\n const facts = routeFactsOf({ providers: { [provider]: profile } }, provider)\n const suggestion = suggestEfforts(modelId, facts)\n const level = resolveGuardEffort({\n declared: row['reasoningEfforts'] as ReasoningEfforts,\n vendorDefault: suggestion.defaultEffort,\n profileDefault,\n requested: undefined,\n })\n return level === undefined ? cfg : { ...cfg, reasoningEffort: level }\n } catch {\n return cfg\n }\n}\n\n/**\n * Apply the plugin: autofill undeclared models on boot and after every commit\n * that touches the pi-ai namespace.\n * @param ctx - host context.\n */\nexport function apply(ctx: Context, config: Config = {}): void {\n // Cordis fills schema defaults; direct calls (tests) may omit fields.\n const resolved = {\n autofill: config.autofill !== false,\n modalityAutofill: config.modalityAutofill !== false,\n probeTimeoutMs: config.probeTimeoutMs ?? PROBE_TIMEOUT_MS,\n bootRetryDelaysMs: config.bootRetryDelaysMs ?? [...BOOT_RETRY_DELAYS_MS],\n defaultGuard: config.defaultGuard !== false,\n uaOverride: config.uaOverride !== false,\n }\n\n // Module-level `inject` already guarantees the settings service; using it\n // directly (instead of a redundant inner ctx.inject) keeps one dependency\n // declaration as the single source of truth.\n const settings = ctx.settings\n\n // The guard and probe route read the pi-ai section through this cached\n // closure slot. Describing every active form on every model call is both\n // needless work and, on 0.1.7+, can publish revision invalidation; retain the\n // last resolved section until the settings document reports that it moved.\n let piSectionCache: unknown\n let piSectionCached = false\n const piSection = (): unknown => {\n if (piSectionCached) return piSectionCache\n let value: unknown\n try {\n value = settings.describe().find(entry => entry.ns === PI_NS)?.value\n } catch {\n // The guard and probe are advisory: an unavailable settings form must\n // not turn a model call into a plugin failure.\n return undefined\n }\n // A missing namespace is expected during boot and must be retried.\n if (value === undefined) return undefined\n piSectionCache = value\n piSectionCached = true\n return value\n }\n ctx.on('settings/document-updated', (ns) => {\n if (ns === PI_NS) piSectionCached = false\n })\n\n if (resolved.autofill) {\n /** One autofill pass; resolves false while the pi-ai namespace is unregistered. */\n const autofillOnce = async (): Promise<boolean> => {\n const descriptor = settings.describe().find(entry => entry.ns === PI_NS)\n if (!isRecord(descriptor?.value)) return false\n // Build the patch from the RAW USER layer, never the resolved value:\n // the fill merges into the user document, and building from the\n // resolved view would materialize schema defaults / composition-base\n // models into it wholesale the moment pi-ai grows such layers for its\n // profile. A namespace whose user section holds no providers has\n // nothing this plugin may fill.\n const user = descriptor?.user\n const userProviders = isRecord(user) && isRecord(user['providers']) ? user['providers'] : undefined\n if (userProviders === undefined) return true\n const fullPatch = buildAutofillPatch(userProviders, () => true, { modalities: resolved.modalityAutofill }, descriptor?.revision ?? 0)\n if (fullPatch === undefined) return true\n // Optimistic lock: only write while the namespace has not moved past\n // this read. The fill is a background suggestion -- losing the race to a\n // user edit is fine; a later boot, or the browser half's idle pass,\n // simply fills whatever is still undeclared. Without the lock every fill\n // would bump the revision and invalidate the one the settings page read,\n // surfacing as SettingsConflictError on the next user save.\n try {\n await settings.update(PI_NS, fullPatch, descriptor?.revision)\n } catch (error) {\n const msg = String(error instanceof Error ? error.message : error)\n if (!looksLikeCompatRefusal(msg)) throw error\n const stripped = stripNewCompatKeysDeep(fullPatch)\n if (stripped === undefined) throw error\n await settings.update(PI_NS, stripped, settings.describe().find(entry => entry.ns === PI_NS)?.revision)\n }\n return true\n }\n\n /** Auto-fill must never break the settings pipeline; log and move on. */\n const logFailure = (error: unknown): void => {\n console.error(`[dsh-model-think-level] autofill failed: ${error instanceof Error ? error.message : String(error)}`)\n }\n\n // Pending boot-retry timers, cleared with the fiber (a disposed plugin\n // must not fire into a torn-down service graph).\n const timers = new Set<ReturnType<typeof setTimeout>>()\n ctx.effect(() => () => {\n for (const timer of timers) clearTimeout(timer)\n timers.clear()\n }, 'dsh-model-think-level: boot-fill retries')\n\n // Fill once at boot for models declared before this plugin was installed,\n // backing off exponentially while llm-pi-ai has not registered yet.\n const bootFill = (attempt: number): void => {\n void autofillOnce().then((ready) => {\n if (ready || attempt >= resolved.bootRetryDelaysMs.length) return\n const timer = setTimeout(() => {\n timers.delete(timer)\n bootFill(attempt + 1)\n }, resolved.bootRetryDelaysMs[attempt])\n timers.add(timer)\n }, logFailure)\n }\n bootFill(0)\n\n // Deliberately NOT re-run on `settings/document-updated`. The boot pass is safe\n // (no settings surface is open yet); a fill the moment a commit lands is\n // not: the official Models card freezes its own revision baseline while it\n // is open, so a background write there makes the user's very next save in\n // that card fail with `settings/conflict` and their edit reads as lost\n // (issue #7). The browser half carries the running complement instead: it\n // builds this SAME patch and writes it on its idle pass, once no card is\n // open. A headless composition has no editing surface to break and no\n // browser half either -- boot covers it.\n }\n\n // Default-guard (issue #2): wrap the llm dispatch entries so effort-less\n // calls to forced-thinking ladders ride the ladder's vendor default instead\n // of the wire's off-equivalent. Deferred inject: the wrap lands whenever\n // the llm service registers, and ctx.effect restores the originals on\n // dispose (disable/HMR leaves no trace).\n if (resolved.defaultGuard) {\n ctx.inject(['llm'], (llmCtx) => {\n const llm = (llmCtx as unknown as { llm?: unknown }).llm as LlmDispatchLike | undefined\n if (llm === undefined || typeof llm.prepareCall !== 'function' || typeof llm.stream !== 'function') return\n // Unbound originals: restore assigns back the exact references, and\n // dispatch keeps the service as receiver through .call.\n const origPrepare = llm.prepareCall\n const origStream = llm.stream\n llm.prepareCall = (callConfig, signal) => origPrepare.call(llm, guardCallConfig(callConfig, piSection()), signal)\n llm.stream = (options) => origStream.call(llm, guardCallConfig(options, piSection()))\n ctx.effect(() => () => {\n llm.prepareCall = origPrepare\n llm.stream = origStream\n }, 'dsh-model-think-level: default-guard')\n })\n }\n\n // Request-header takeover (issue #12): the official adapter can merge\n // attribution headers over the profile's own dictionary, so configured\n // values may be lost before the request reaches the wire. The plugin keeps\n // the fetch overlay as a compatibility fallback and also uses pi-ai's\n // request-level transform, which runs after auth/default headers are merged.\n // This mirrors the request-scoped header handling used by PI-Desktop and\n // covers SDK transports that do not call the current global fetch function.\n //\n // The index is keyed by the endpoint's ORIGIN and rebuilt from the live\n // settings section, so a route added, edited, or removed on the Models page\n // reaches the next request with no reload. `uaOverride: false` empties the\n // index instead of skipping the install: both seams stay installed and\n // simply stop matching anything.\n /** Live index the overlay reads; never undefined once apply has run. */\n const overlaySource: OverlaySource = { current: emptyIndex() }\n const headerRetryTimers = new Set<ReturnType<typeof setTimeout>>()\n let headerRetryAttempt = 0\n const stopHeaderRetries = (): void => {\n for (const timer of headerRetryTimers) clearTimeout(timer)\n headerRetryTimers.clear()\n headerRetryAttempt = 0\n }\n const scheduleHeaderRefresh = (refresh: () => void): void => {\n // A settings event may arrive while a retry is already pending. Keep one\n // timer per activation so repeated document notifications cannot accelerate\n // or multiply the boot retry sequence.\n if (headerRetryTimers.size > 0 || headerRetryAttempt >= resolved.bootRetryDelaysMs.length) return\n const delay = resolved.bootRetryDelaysMs[headerRetryAttempt]\n headerRetryAttempt += 1\n const timer = setTimeout(() => {\n headerRetryTimers.delete(timer)\n refresh()\n }, delay)\n headerRetryTimers.add(timer)\n }\n const refreshHeaders = (): void => {\n if (!resolved.uaOverride) {\n overlaySource.current = emptyIndex()\n stopHeaderRetries()\n return\n }\n const section = piSection()\n if (section === undefined) {\n // llm-pi-ai can register its settings namespace after this plugin. The\n // model probe has an independent direct-header path, but chat needs this\n // index ready before the adapter's first stream reaches fetch().\n overlaySource.current = emptyIndex()\n scheduleHeaderRefresh(refreshHeaders)\n return\n }\n stopHeaderRetries()\n const providers = isRecord(section) && isRecord(section['providers'])\n ? (section['providers'] as Record<string, Record<string, unknown>>)\n : {}\n overlaySource.current = buildHeaderIndex(providers)\n }\n refreshHeaders()\n ctx.effect(() => () => stopHeaderRetries(), 'dsh-model-think-level: header retries')\n ctx.on('settings/document-updated', (ns) => {\n if (ns === PI_NS) refreshHeaders()\n })\n const overlay = installHeaderOverlay(overlaySource)\n ctx.effect(() => () => { overlay.dispose() }, 'dsh-model-think-level: fetch header overlay')\n\n // `?diag=1` on the probe route reports this without touching the wire, so\n // the request-header takeover is observable from the running host.\n let headerBridgeState: () => unknown = () => ({ stage: 'not-installed' })\n const installPiAiBridge = (llm: unknown): void => {\n const transforms = installPiAiHeaderTransforms(llm, overlaySource)\n transforms.refresh()\n headerBridgeState = () => describePiAiHeaderState(llm, overlaySource)\n ctx.on('llm/adapters-updated', () => transforms.refresh())\n ctx.effect(() => () => transforms.dispose(), 'dsh-model-think-level: pi-ai request headers')\n }\n const availableLlm = (ctx as unknown as { llm?: unknown }).llm\n if (availableLlm === undefined) {\n // Direct callers and older hosts may omit llm from the module-level inject;\n // keep the deferred path as a compatibility fallback for those contexts.\n ctx.inject(['llm'], (llmCtx) => {\n const llm = (llmCtx as unknown as { llm?: unknown }).llm\n if (llm !== undefined) installPiAiBridge(llm)\n })\n } else {\n installPiAiBridge(availableLlm)\n }\n\n // Read once: what sits on disk changes only when the user installs or patches\n // something, and a restart is the honest moment to re-read it.\n const headerConflicts: HeaderConflictReport = detectHeaderConflicts()\n\n // Same-origin probe route: the browser half's Auto-adapt asks the endpoint's\n // RAW /models listing through here, because the sanctioned llm wire call\n // strips reasoning signals host-side. The credential resolves server-side\n // and never echoes back; only routes the user's own settings name are\n // reachable, and the trust fence rejects cross-site callers.\n ctx.inject(['webServer'], (webServerCtx) => {\n ctx.effect(\n () =>\n webServerCtx.webServer.register({\n kind: 'exact',\n path: PROBE_PATH,\n handler: async (req, res) => {\n if (!isTrustedRequest(req)) {\n sendJson(res, 403, { ok: false, error: 'forbidden' })\n return\n }\n if (req.method !== 'GET') {\n sendJson(res, 405, { ok: false, error: 'method not allowed' })\n return\n }\n const url = new URL(req.url ?? '/', 'http://x')\n // Read-only diagnostics: makes the request-header takeover\n // observable in the running host (which adapter is patched).\n if (url.searchParams.get('diag') === '1') {\n sendJson(res, 200, {\n ok: true,\n bridge: headerBridgeState(),\n overlay: {\n routes: overlaySource.current.routes.length,\n overrides: overlaySource.current.overrides.length,\n },\n })\n return\n }\n const route = url.searchParams.get('route') ?? ''\n const section = piSection()\n const profile = isRecord(section) && isRecord(section['providers'])\n ? section['providers'][route]\n : undefined\n if (!isRecord(profile)) {\n sendJson(res, 400, { ok: false, error: `no llm-pi-ai provider route \"${route}\"` })\n return\n }\n const baseURL = typeof profile['baseURL'] === 'string' ? profile['baseURL'] : ''\n if (baseURL.length === 0) {\n sendJson(res, 400, { ok: false, error: `provider route \"${route}\" has no baseURL` })\n return\n }\n // The profile's wire protocol selects the listing route and the\n // credential arm, exactly as the official discovery decides them:\n // only the protocols whose listing this mirror can read are\n // interrogated; everything else reports that it cannot.\n const api = typeof profile['api'] === 'string' ? profile['api'] : ''\n if (api.length === 0) {\n sendJson(res, 400, {\n ok: false,\n error: `provider route \"${route}\" names no API protocol to interrogate`,\n })\n return\n }\n if (!LISTABLE_PROTOCOLS.has(api)) {\n sendJson(res, 400, {\n ok: false,\n error: `protocol \"${api}\" cannot be interrogated; enter this provider's models by hand`,\n })\n return\n }\n const apiKeyEnv = typeof profile['apiKeyEnv'] === 'string' ? profile['apiKeyEnv'] : undefined\n const listingURL = probeListingUrl(baseURL, api)\n let apiKey: string | undefined\n if (apiKeyEnv !== undefined) {\n try {\n const credentials = ctx.get('credentials') as CredentialsService | undefined\n const hit = credentials === undefined ? undefined : await credentials.resolve(apiKeyEnv)\n apiKey = hit !== undefined && typeof hit.value === 'string' && hit.value.length > 0\n ? hit.value\n : undefined\n } catch {\n // Unresolvable credential: probe unauthenticated rather than fail.\n }\n }\n try {\n const upstream = await fetch(listingURL, {\n method: 'GET',\n // Header composition mirrors the harness's own model discovery:\n // the profile's configured request headers ride\n // along, so a deployment that authenticates through a custom\n // header probes here exactly as it lists officially \u2014 and an\n // Anthropic endpoint answers through x-api-key + a fixed\n // anthropic-version instead of a Bearer.\n headers: composeProbeHeaders(profile['headers'], apiKey, api),\n // A probe carries the user's stored credential, so it must\n // reach exactly the authority the profile names: Fetch's\n // default would FOLLOW a cross-origin redirect, and the\n // headers composed here (`x-api-key`, a profile's own auth\n // header) are not stripped on that hop the way `authorization`\n // is. Official discovery keeps the default; this route is\n // stricter on purpose, and the cost is bounded \u2014 a gateway\n // that lists only behind a redirect yields no endpoint\n // evidence, so Auto-adapt falls back to the knowledge base /\n // protocol inference, the path every unanswerable endpoint\n // takes.\n redirect: 'error',\n signal: AbortSignal.timeout(resolved.probeTimeoutMs),\n })\n if (!upstream.ok) {\n const hint = upstream.status === 401 || upstream.status === 403 ? '; check the API key' : ''\n sendJson(res, 502, { ok: false, error: `${displayUrl(listingURL)} answered ${upstream.status}${hint}` })\n return\n }\n const text = await readBounded(upstream, listingURL)\n let body: unknown\n try {\n body = JSON.parse(text) as unknown\n } catch {\n sendJson(res, 502, { ok: false, error: `${displayUrl(listingURL)} answered with a malformed JSON body` })\n return\n }\n // The official parser accepts the standard `data` array and the\n // enriched `models` map; entries are passed through verbatim so\n // the browser half sees the raw capability signals the sanctioned\n // wire call strips.\n const entries = listingEntries(body)\n if (entries === undefined) {\n sendJson(res, 502, {\n ok: false,\n error: `${displayUrl(listingURL)} model listing has neither a \"data\" array nor a \"models\" object`,\n })\n return\n }\n sendJson(res, 200, { ok: true, url: displayUrl(listingURL), data: entries })\n } catch (error) {\n sendJson(res, 502, {\n ok: false,\n error: `could not reach ${displayUrl(listingURL)}: ${error instanceof Error ? error.message : String(error)}`,\n })\n }\n },\n }),\n 'dsh-model-think-level: raw-models probe route',\n )\n\n // Read-only diagnostics for the request-header takeover. A path of its own\n // (rather than a flag on the probe route) so a reloaded plugin can answer\n // even while an older instance still owns the probe path.\n ctx.effect(\n () =>\n webServerCtx.webServer.register({\n kind: 'exact',\n path: DIAG_PATH,\n handler: (req, res) => {\n if (!isTrustedRequest(req)) {\n sendJson(res, 403, { ok: false, error: 'forbidden' })\n return\n }\n sendJson(res, 200, {\n ok: true,\n uaOverride: resolved.uaOverride,\n bridge: headerBridgeState(),\n overlay: {\n routes: overlaySource.current.routes.length,\n overrides: overlaySource.current.overrides.length,\n },\n })\n },\n }),\n 'dsh-model-think-level: header diagnostics route',\n )\n\n // Stored-credential route: the API-key field's eye calls it when the user\n // asks to see a key that is already saved. Every other route here keeps the\n // value host-side; this one hands it to the page on purpose, because the\n // official field is write-only by design \u2014 the settings document carries\n // only the profile's `apiKeyEnv` reference \u2014 so the affordance would\n // otherwise be a mask toggle with nothing behind it. The same trust fence\n // as the probe gates it, the value is never logged, and every answer is\n // `no-store` so neither the key nor the refusals (which name the route's\n // reference) can sit in a cache. The browser half asks only on a click, and\n // only for a card that names a route.\n ctx.effect(\n () =>\n webServerCtx.webServer.register({\n kind: 'exact',\n path: PROVIDER_KEY_PATH,\n handler: async (req, res) => {\n // Nothing this route answers may sit in a cache: not the key, and\n // not the refusals that name the route's credential reference.\n res.setHeader('cache-control', 'no-store')\n if (!isTrustedRequest(req)) {\n sendJson(res, 403, { ok: false, error: 'forbidden' })\n return\n }\n if (req.method !== 'GET') {\n sendJson(res, 405, { ok: false, error: 'method not allowed' })\n return\n }\n const url = new URL(req.url ?? '/', 'http://x')\n const route = url.searchParams.get('route') ?? ''\n const section = piSection()\n const profile = isRecord(section) && isRecord(section['providers'])\n ? section['providers'][route]\n : undefined\n if (!isRecord(profile)) {\n sendJson(res, 400, { ok: false, error: `no llm-pi-ai provider route \"${route}\"` })\n return\n }\n const apiKeyEnv = typeof profile['apiKeyEnv'] === 'string' ? profile['apiKeyEnv'] : undefined\n // A key-manager row names its own reference; the field's own eye\n // names none and means \"the key this provider is using\". A named\n // one is served only when the route's index lists it, so this route\n // can never become a resolver for arbitrary reference names.\n const named = url.searchParams.get('ref') ?? ''\n const ref = named.length > 0\n ? (named === apiKeyEnv || hasKeyEntry(readKeyIndex(keyIndexFilePath()), route, named) ? named : undefined)\n : apiKeyEnv\n if (ref === undefined) {\n sendJson(res, 404, {\n ok: false,\n error: named.length > 0\n ? `provider route \"${route}\" lists no key \"${named}\"`\n : `provider route \"${route}\" stores no credential reference`,\n })\n return\n }\n let value: string | undefined\n try {\n const credentials = ctx.get('credentials') as CredentialsService | undefined\n const hit = credentials === undefined ? undefined : await credentials.resolve(ref)\n value = hit !== undefined && typeof hit.value === 'string' && hit.value.length > 0\n ? hit.value\n : undefined\n } catch {\n value = undefined\n }\n if (value === undefined) {\n sendJson(res, 404, { ok: false, error: `no credential is configured for ${ref}` })\n return\n }\n sendJson(res, 200, { ok: true, key: value })\n },\n }),\n 'dsh-model-think-level: provider-key route',\n )\n\n // The API-key manager: one provider's list of keys, and which one is in use.\n //\n // Both halves of that list are host-side already \u2014 the values belong to the\n // harness credential store, and the reference the adapter actually resolves\n // is a field of the pi-ai profile \u2014 so this route owns the reads AND the\n // writes and the browser half only ever handles references, labels and\n // booleans. That is the same surface the official page works with, and it\n // needs no new Remote face to get it.\n ctx.effect(\n () =>\n webServerCtx.webServer.register({\n kind: 'exact',\n path: KEY_INDEX_PATH,\n handler: async (req, res) => {\n res.setHeader('cache-control', 'no-store')\n if (!isTrustedRequest(req)) {\n sendJson(res, 403, { ok: false, error: 'forbidden' })\n return\n }\n if (req.method !== 'GET' && req.method !== 'POST') {\n sendJson(res, 405, { ok: false, error: 'method not allowed' })\n return\n }\n const url = new URL(req.url ?? '/', 'http://x')\n const route = url.searchParams.get('route') ?? ''\n // Read the entry fresh rather than through the cached section: this\n // route writes to it, and an answer built from a pre-write snapshot\n // would show the user the state they just changed away from.\n const entryOf = (): { value: unknown; revision: number } | undefined => {\n try {\n const found = settings.describe().find(candidate => candidate.ns === PI_NS)\n return found === undefined ? undefined : { value: found.value, revision: found.revision }\n } catch {\n return undefined\n }\n }\n if (route.length === 0 || providerProfileOf(entryOf()?.value, route) === undefined) {\n sendJson(res, 400, { ok: false, error: `no llm-pi-ai provider route \"${route}\"` })\n return\n }\n const credentials = ctx.get('credentials') as CredentialsService | undefined\n const indexFile = keyIndexFilePath()\n\n /** The reference the profile names right now, read fresh. */\n const enabledNow = (): string | undefined => enabledRefOf(providerProfileOf(entryOf()?.value, route))\n\n /**\n * Hand the \"in use\" seat to one reference; undefined clears it. The\n * seat IS the profile's `apiKeyEnv`, so nothing else has to know\n * which key is active \u2014 every consumer of the profile, in the GUI or\n * not, resolves exactly the key the user enabled.\n * @param ref - reference to enable, or undefined to name none.\n * @returns The refusal text, or undefined when the write landed.\n */\n const setEnabledKey = async (ref: string | undefined): Promise<string | undefined> => {\n for (let attempt = 0; attempt < 2; attempt += 1) {\n const entry = entryOf()\n if (entry === undefined) return 'the llm-pi-ai settings entry is unavailable'\n try {\n await settings.mutate(\n PI_NS,\n ref === undefined\n ? [{ op: 'unset', path: ['providers', route, 'apiKeyEnv'] }]\n : [{ op: 'set', path: ['providers', route, 'apiKeyEnv'], value: ref }],\n entry.revision,\n )\n return undefined\n } catch (error) {\n // Another writer (the official card's Save, another tab, the\n // autofill pass) moved the document between this read and\n // this write: re-read once and fence on the new revision.\n if (attempt === 0 && isConflictError(error)) continue\n return error instanceof Error ? error.message : String(error)\n }\n }\n return 'the settings document kept changing; try again'\n }\n\n /** The whole list, as the browser half renders it. */\n const payload = async (): Promise<unknown> => {\n const enabledRef = enabledNow()\n const listed = keyEntriesOf(readKeyIndex(indexFile), route)\n const refs = listed.map(entry => entry.ref)\n // The key in use is always on the list, even when it was written\n // by the official page or by hand and this plugin has never seen\n // it: the panel must be able to show and act on what is active.\n if (enabledRef !== undefined && !refs.includes(enabledRef)) refs.push(enabledRef)\n const facts = await credentialFacts(credentials, refs)\n const entries: KeyEntryView[] = refs.map(ref => {\n const fact = facts[ref]\n const view: KeyEntryView = {\n ref,\n enabled: ref === enabledRef,\n configured: fact?.configured ?? null,\n }\n if (fact?.masked !== undefined) view.masked = fact.masked\n const stored = listed.find(candidate => candidate.ref === ref)\n if (stored?.alias !== undefined) view.alias = stored.alias\n return view\n })\n return { ok: true, route, enabledRef: enabledRef ?? null, entries }\n }\n\n if (req.method === 'GET') {\n sendJson(res, 200, await payload())\n return\n }\n\n const body = await readJsonBody(req)\n const op = isRecord(body) && typeof body['op'] === 'string' ? body['op'] : ''\n const ref = isRecord(body) && typeof body['ref'] === 'string' ? body['ref'] : undefined\n const alias = isRecord(body) ? normalizeKeyAlias(body['alias']) : undefined\n const value = isRecord(body) && typeof body['value'] === 'string' ? body['value'] : undefined\n // Every mutation is a set of steps that must not half-apply, so each\n // branch refuses BEFORE it writes anything it cannot undo.\n const refuse = (error: string): void => sendJson(res, 400, { ok: false, error })\n\n try {\n if (op === 'add') {\n if (!isLegalKeyValue(value)) {\n refuse('a key must be printable ASCII without spaces')\n return\n }\n const taken = keyEntriesOf(readKeyIndex(indexFile), route).map(candidate => candidate.ref)\n // The reference in use need not be listed \u2014 the official card\n // and a hand-edited profile both write one this plugin has never\n // seen \u2014 and minting it again would overwrite the very key the\n // provider is running on.\n const active = enabledNow()\n if (active !== undefined && !taken.includes(active)) taken.push(active)\n const created = nextKeyRef(route, taken)\n // The value goes into the store first: a reference the index\n // lists but the store cannot hold would render as a key the\n // user can never reveal, enable or remove.\n const refused = await storeCredential(credentials, created, value)\n if (refused !== undefined) {\n refuse(refused)\n return\n }\n updateKeyIndex(document => withKeyEntry(document, route, created, alias), indexFile)\n // The first key on a provider that names none is the key in\n // use: adding it is how a route becomes configured at all.\n if (enabledNow() === undefined) {\n const failed = await setEnabledKey(created)\n if (failed !== undefined) {\n refuse(failed)\n return\n }\n }\n } else if (op === 'enable') {\n const listed = readKeyIndex(indexFile)\n if (ref === undefined || !hasKeyEntry(listed, route, ref)) {\n refuse('that key is not listed for this provider')\n return\n }\n // Moving the seat must not take the key it leaves off the list:\n // that key was a row a moment ago, and unlisted it would fall out\n // of reach \u2014 and let a later add mint its name again, over the\n // value still sitting in the store.\n const previous = enabledNow()\n if (previous !== undefined && previous !== ref && !hasKeyEntry(listed, route, previous)) {\n const leaving: string = previous\n updateKeyIndex(\n document =>\n hasKeyEntry(document, route, leaving)\n ? document\n : withKeyEntry(document, route, leaving, undefined),\n indexFile,\n )\n }\n const failed = await setEnabledKey(ref)\n if (failed !== undefined) {\n refuse(failed)\n return\n }\n } else if (op === 'rename') {\n // The key the provider is RUNNING on takes a label too: that\n // reference is usually the one the official card wrote, which\n // this plugin has never listed. Writing it here is what puts it\n // on the list, so every later write matches an entry.\n const known =\n ref !== undefined &&\n (hasKeyEntry(readKeyIndex(indexFile), route, ref) || ref === enabledNow())\n if (ref === undefined || !known) {\n refuse('that key is not listed for this provider')\n return\n }\n const target = ref\n updateKeyIndex(\n document =>\n hasKeyEntry(document, route, target)\n ? withKeyAlias(document, route, target, alias)\n : withKeyEntry(document, route, target, alias),\n indexFile,\n )\n } else if (op === 'value') {\n const known =\n ref !== undefined &&\n (hasKeyEntry(readKeyIndex(indexFile), route, ref) || ref === enabledNow())\n if (ref === undefined || !known) {\n refuse('that key is not listed for this provider')\n return\n }\n if (!isLegalKeyValue(value)) {\n refuse('a key must be printable ASCII without spaces')\n return\n }\n // Only the secret moves: the reference keeps its name, its alias\n // and its seat. Removing and re-adding would mint a new ref, so\n // the profile would name a key the store no longer holds and the\n // row would lose everything but its value.\n const refused = await storeCredential(credentials, ref, value)\n if (refused !== undefined) {\n refuse(refused)\n return\n }\n } else if (op === 'remove') {\n const document = readKeyIndex(indexFile)\n if (ref === undefined || (!hasKeyEntry(document, route, ref) && ref !== enabledNow())) {\n refuse('that key is not listed for this provider')\n return\n }\n if (ref === enabledNow()) {\n // The seat is handed over BEFORE the value goes, so the\n // profile never names a key the store has just lost while\n // another listed key was available to take it. When none is,\n // the reference is unset rather than left dangling.\n const remaining = keyEntriesOf(document, route)\n .map(candidate => candidate.ref)\n .filter(candidate => candidate !== ref)\n const failed = await setEnabledKey(remaining[0])\n if (failed !== undefined) {\n refuse(failed)\n return\n }\n }\n const configured = (await credentialConfigured(credentials, [ref]))[ref]\n if (configured !== false) {\n const refused = await forgetCredential(credentials, ref)\n if (refused !== undefined) {\n refuse(refused)\n return\n }\n }\n updateKeyIndex(document2 => withoutKeyEntry(document2, route, ref), indexFile)\n } else {\n refuse(`unknown key operation \"${op}\"`)\n return\n }\n } catch (error) {\n sendJson(res, 500, { ok: false, error: error instanceof Error ? error.message : String(error) })\n return\n }\n sendJson(res, 200, await payload())\n },\n }),\n 'dsh-model-think-level: key index route',\n )\n\n // The autofill switches, for the browser half that runs the running\n // complement. Read-only and same-origin only, like the probe above: a\n // `dsh.client` declaration carries no plugin config, so without this route\n // a deployment configured `autofill: false` would still be written to from\n // the settings page.\n ctx.effect(\n () =>\n webServerCtx.webServer.register({\n kind: 'exact',\n path: AUTOFILL_CONFIG_PATH,\n handler: async (req, res) => {\n if (!isTrustedRequest(req)) {\n sendJson(res, 403, { ok: false, error: 'forbidden' })\n return\n }\n if (req.method !== 'GET') {\n sendJson(res, 405, { ok: false, error: 'method not allowed' })\n return\n }\n sendJson(res, 200, {\n ok: true,\n data: { autofill: resolved.autofill, modalityAutofill: resolved.modalityAutofill },\n })\n },\n }),\n 'dsh-model-think-level: autofill config route',\n )\n\n // The request-header overlay's status, for the browser half. Same-origin\n // and read-only, like the other two routes: the takeover lives host-side, so\n // the page needs this to say which routes it is changing and to warn about\n // another plugin rewriting the same surface.\n ctx.effect(\n () =>\n webServerCtx.webServer.register({\n kind: 'exact',\n path: HEADERS_CONFIG_PATH,\n handler: async (req, res) => {\n if (!isTrustedRequest(req)) {\n sendJson(res, 403, { ok: false, error: 'forbidden' })\n return\n }\n if (req.method !== 'GET') {\n sendJson(res, 405, { ok: false, error: 'method not allowed' })\n return\n }\n const index = overlaySource.current\n sendJson(res, 200, {\n ok: true,\n data: {\n /** Whether the fetch-layer takeover is enabled in this deployment. */\n enabled: resolved.uaOverride,\n /** Whether this plugin's wrapper currently owns the global fetch. */\n installed: headerOverlayInstalled(),\n /** Routes whose configured request headers are sent, by origin. */\n overrides: index.overrides.map(entry => ({\n origin: entry.origin,\n route: entry.route,\n headers: entry.headers,\n ...(entry.userAgent === undefined ? {} : { userAgent: entry.userAgent }),\n })),\n /** Same-origin routes with different User-Agent values. */\n conflicts: index.conflicts,\n /** Same-origin differences for any configured request header. */\n headerConflicts: index.headerConflicts,\n /** What was found of the plugins that rewrite the same surface. */\n environment: headerConflicts,\n },\n })\n },\n }),\n 'dsh-model-think-level: headers config route',\n )\n })\n}\n", "/**\n * Plugin-wide constants shared by the host and browser halves.\n *\n * @module dsh-model-think-level/constants\n */\n\n/** Stable plugin id, matching the cordis.patch.yml row and the bundle id. */\nexport const PLUGIN_ID = 'dsh-model-think-level'\n\n/** Same-origin host route that proxies a provider's RAW /models listing. */\nexport const PROBE_PATH = '/dsh-model-think-level/raw-models'\n/** Read-only diagnostics for the request-header takeover. */\nexport const DIAG_PATH = '/dsh-model-think-level/header-bridge'\n\n/**\n * Same-origin host route that resolves one provider profile's stored\n * credential, so the API-key field's eye can show a SAVED key.\n *\n * The harness keeps provider keys write-only on purpose: the settings document\n * carries only the profile's `apiKeyEnv` reference, and the credential service\n * reports `{ configured, source, writable }` through `describe()` \u2014 never the\n * value. Only the host can read it (`credentials.resolve()`), and it does so\n * for the request adapters; the browser normally never sees a stored key at\n * all. This route is the plugin's deliberate exception: an explicit,\n * user-initiated, same-fence read that answers with the value and is never\n * cached, so the eye can put it back into the official field.\n */\nexport const PROVIDER_KEY_PATH = '/dsh-model-think-level/provider-key'\n\n/**\n * Same-origin host route that owns a provider's list of API keys: their\n * references, their labels, and which one is in use.\n *\n * The harness has no notion of \"several keys for one provider\": a profile names\n * exactly one reference (`apiKeyEnv`) and a credential store holds exactly one\n * value per reference, with no enumeration and no label. Both facts are\n * deliberate \u2014 a configuration surface learns which references exist from its\n * settings schema \u2014 so a list of keys can only be plugin-owned state. It lives\n * in the harness home (`<DSH_HOME>/dsh-model-think-level/key-index.json`) rather\n * than in the pi-ai profile, so the official add-provider card, which writes the\n * WHOLE profile at `providers.<route>`, cannot drop it.\n *\n * The route both reads and writes: the values themselves still go to the\n * credential store through the host's own `credentials` service, so the browser\n * never needs a new Remote face.\n */\nexport const KEY_INDEX_PATH = '/dsh-model-think-level/key-index'\n\n/**\n * Same-origin host route that reports this plugin's autofill switches. The\n * browser half runs the running auto-fill complement, and a `dsh.client`\n * declaration carries no plugin config, so the two switches have to be read\n * from the host that owns the cordis row; without it a deployment that turned\n * `autofill: false` would still be written to from the page.\n */\nexport const AUTOFILL_CONFIG_PATH = '/dsh-model-think-level/autofill-config'\n\n/**\n * Same-origin host route reporting the request-header overlay (issue #12): the\n * routes whose `user-agent` the plugin is overriding, and what it found of the\n * plugins that rewrite the same surface. The browser half renders the\n * coexistence warning from here \u2014 the takeover lives host-side, so the page\n * cannot observe it on its own.\n */\nexport const HEADERS_CONFIG_PATH = '/dsh-model-think-level/headers-config'\n\n/** The settings namespace this plugin edits: pi-ai custom provider routes. */\nexport const PI_AI_NS = 'llm-pi-ai'\n\n/**\n * Model-level marker written when the user deliberately unsets the\n * declaration (\"back to inheritance\"). Schemastery passes unknown model keys\n * through, so the marker survives official-page saves and restarts \u2014 which is\n * the point: auto-fill must respect the absence as a decision, not as a gap\n * to fill.\n */\nexport const UNSET_MARKER = 'reasoningEffortsUnset'\n\n/**\n * Model-level marker for a deliberately unset input-modality declaration,\n * mirroring {@link UNSET_MARKER}: auto-fill must respect the absence of\n * `input` as a decision (the route default applies), not as a gap to fill.\n */\nexport const INPUT_UNSET_MARKER = 'inputUnset'\n\n/**\n * Model-level provenance marker written beside every ladder the HOST autofill\n * fills from the knowledge base, carrying the settings revision the fill read.\n *\n * It exists because the plugin's auto-fill and the user's staged declaration\n * race on the SAME row: whichever half runs the fill writes the knowledge base\n * suggestion, while the staged-declaration flush compares the document against\n * its own suggestion. By the time the flush looks, the suggestion may already\n * be stored -- and byte equality alone cannot tell \"the plugin wrote this\" from\n * \"the user declared this\", so a staged ladder differing from the knowledge\n * base in even one spelling (the editor's `off: null` against the knowledge\n * base's `off: 'none'`) was dropped as a document takeover: the reported\n * \"configured it on the add-provider card, saved, and it is gone\".\n *\n * With the marker the flush knows the stored ladder is a suggestion, so a\n * staged user intent overrides it. Either way the user's bytes win; the marker\n * only decides whether the flush is allowed to write at all. Schemastery passes\n * unknown model keys through, so the marker survives official-page saves and\n * restarts like the other two markers. Any ladder written through the plugin\n * clears it, which is what makes a later hand edit outrank a fresh staging.\n */\nexport const AUTOFILL_MARKER = 'reasoningEffortsAutofilled'\n\n/**\n * Model-level default-effort pick (issue #4): the level a brand-new session\n * starts this model at, outranking the remembered levels. The value is one of\n * the model's own declared ladder keys, or the field is absent when the user\n * has not picked one (memory chain applies). Deliberately NOT a harness\n * concept: pi-ai's runtime never sees it (unknown model keys ride the settings\n * document the way the other markers do), and the browser half is its only\n * consumer. The name matches the catalog's `reasoning.defaultEffort` spelling\n * so a future first-class field can adopt the stored values as-is.\n */\nexport const DEFAULT_EFFORT_FIELD = 'defaultEffort'\n\n/** Locale dictionary namespace for the browser half's copy (not a settings namespace). */\nexport const STORE_NS = PLUGIN_ID\n", "/**\n * The credential-reference vocabulary the API-key manager shares between both\n * halves.\n *\n * A provider's key list is a list of NAMES: every value lives in the harness\n * credential store under its own reference, and the profile records exactly one\n * of those names (`providers.<route>.apiKeyEnv`) as the reference the adapter\n * resolves when it calls the provider. This module owns the naming rules the\n * two halves must agree on \u2014 the browser half picks the next free name for a\n * new key, the host half re-validates whatever arrives \u2014 so one name can never\n * mean two different things on the two sides of the wire.\n *\n * Deliberately free of `node:` imports: the client bundle imports this module\n * too (the same way `constants.ts` is shared), and a single `node:` import\n * would drag the host into the browser build.\n *\n * @module dsh-model-think-level/key-refs\n */\n\n/** One key the manager lists for a provider route. */\nexport interface KeyEntry {\n /** Credential reference holding the value. */\n readonly ref: string\n /** User-facing label; absent means \"show the reference itself\". */\n readonly alias?: string\n}\n\n/** Longest reference the manager will mint or accept. */\nexport const KEY_REF_MAX_LENGTH = 80\n\n/** Longest alias the manager stores. A label, never a secret. */\nexport const KEY_ALIAS_MAX_LENGTH = 40\n\n/**\n * The shape of a reference the manager accepts. Looser than the credential\n * store's own POSIX-ish rule on purpose: a route may legitimately start with a\n * digit (`9router` \u2192 `9ROUTER_API_KEY`), and the store stays the authority on\n * what it will hold. This is the plugin's sanity bound, not the validation.\n */\nexport const KEY_REF_PATTERN = /^[A-Za-z0-9_]{1,80}$/\n\n/**\n * The reference the official Models page derives for a provider route: the\n * route upper-cased with every non-alphanumeric run folded to `_`, plus\n * `_API_KEY`. Mirrors the official page exactly so the first key the manager\n * adds for a provider is the very reference that page would have written.\n * @param route - the provider route key (`ofox`, `aliyun-cn`).\n * @returns the derived reference name.\n */\nexport function deriveKeyRef(route: string): string {\n return `${route.toUpperCase().replace(/[^A-Z0-9]+/g, '_')}_API_KEY`\n}\n\n/** Whether a value is a reference name this manager will pass to the store. */\nexport function isKeyRefName(value: unknown): value is string {\n return typeof value === 'string' && KEY_REF_PATTERN.test(value)\n}\n\n/**\n * The first free name in the sequence `<DERIVED>`, `<DERIVED>_2`, `<DERIVED>_3`\u2026\n * @param route - the provider route key.\n * @param taken - every reference already listed for that route.\n * @returns a reference not in `taken`.\n */\nexport function nextKeyRef(route: string, taken: readonly string[]): string {\n const used = new Set(taken)\n const base = deriveKeyRef(route)\n if (!used.has(base)) return base\n for (let suffix = 2; suffix <= 999; suffix += 1) {\n const candidate = `${base}_${suffix}`\n if (!used.has(candidate)) return candidate\n }\n // A thousand keys on one route is not a real deployment; stay unique anyway.\n return `${base}_${Date.now()}`\n}\n\n/**\n * A stored alias, or undefined when the label carries nothing.\n *\n * Control characters are dropped rather than escaped: an alias is rendered as\n * text on the official page, and a stray newline there is a rendering bug, not\n * data worth keeping.\n * @param value - whatever arrived (user input, or a hand-edited index file).\n * @returns the trimmed label, capped at {@link KEY_ALIAS_MAX_LENGTH}.\n */\nexport function normalizeKeyAlias(value: unknown): string | undefined {\n if (typeof value !== 'string') return undefined\n let cleaned = ''\n for (const char of value) {\n const code = char.codePointAt(0) ?? 0\n if (code < 32 || code === 127) continue\n cleaned += char\n }\n cleaned = cleaned.trim()\n if (cleaned.length === 0) return undefined\n return cleaned.slice(0, KEY_ALIAS_MAX_LENGTH)\n}\n\n/**\n * Whether a value is a key the official page would itself accept: printable\n * ASCII with no spaces (its own `LEGAL_API_KEY`). The manager applies the same\n * rule so a key it stores can never be one the official card would refuse.\n */\nexport function isLegalKeyValue(value: unknown): value is string {\n return typeof value === 'string' && /^[\\x21-\\x7E]+$/.test(value)\n}\n\n/** Shortest value that still gets a head and a tail; below it, a flat mask. */\nconst KEY_MASK_MIN_LENGTH = 12\n\n/**\n * A stored key's display form: a head, an ellipsis and a tail \u2014 enough to tell\n * two look-alike keys apart, never the whole secret.\n *\n * The manager shows every row this way, so a list can say which key a row holds\n * without putting anything usable on the page; the eye beside the field stays\n * the one gesture that reveals a value. A value too short to survive trimming\n * gets a fixed-width mask instead: at that length a head and a tail would be\n * most of the key.\n */\nexport function maskKeyValue(value: string): string {\n if (value.length === 0) return ''\n if (value.length < KEY_MASK_MIN_LENGTH) return '\u2022\u2022\u2022\u2022\u2022\u2022\u2022\u2022'\n return `${value.slice(0, 4)}...${value.slice(-4)}`\n}\n", "/**\n * The provider key index: plugin-owned metadata about the keys configured for\n * one provider route.\n *\n * The harness stores VALUES only: `<DSH_HOME>/.credentials.yaml` holds one value\n * per reference, the service reports `{configured, source, writable}` and never\n * the value, and there is no enumeration API at all. A list of \"the keys this\n * provider has\", each with a human label, therefore cannot live in the harness\n * \u2014 it is plugin state. It is kept here, beside the harness home rather than\n * inside the pi-ai profile, because the official add-provider card writes the\n * WHOLE profile at `providers.<route>` and an unknown sibling key there would\n * be at the mercy of schema validation.\n *\n * The file holds no secrets: references and labels only, which is what makes it\n * safe to keep in plain text and easy for a user to inspect or repair by hand.\n * Every read is defensive (a corrupted file degrades to \"nothing listed\") and\n * every write is atomic (`write` to a sibling temp file, then `rename`), so a\n * crash mid-write cannot leave a half-parsed index behind.\n *\n * All of it is synchronous on purpose: the host is single-threaded, so a\n * read-modify-write inside one request handler cannot interleave with another\n * request's, which is the whole concurrency story this file needs.\n *\n * @module dsh-model-think-level/key-index\n */\n\nimport { mkdirSync, readFileSync, renameSync, unlinkSync, writeFileSync } from 'node:fs'\nimport { homedir } from 'node:os'\nimport { dirname, join } from 'node:path'\nimport { normalizeKeyAlias, type KeyEntry } from './key-refs.js'\n\n/** One route's entry, re-exported so the host half has a single import site. */\nexport type KeyIndexEntry = KeyEntry\n\n/** The whole index document, exactly as it sits on disk. */\nexport interface KeyIndexDocument {\n /** Schema version; a future shape can migrate by reading this. */\n readonly version: 1\n /** Route \u2192 keys, in the order the manager lists them. */\n readonly providers: Record<string, readonly KeyIndexEntry[]>\n}\n\n/** A fresh, empty index. */\nexport function emptyKeyIndex(): KeyIndexDocument {\n return { version: 1, providers: {} }\n}\n\n/**\n * The harness home: `$DSH_HOME` when the host exports it, else the `~/.dsh`\n * the harness would have defaulted to. Never throws.\n */\nexport function harnessHome(): string {\n const configured = process.env['DSH_HOME']\n if (typeof configured === 'string' && configured.length > 0) return configured\n try {\n return join(homedir(), '.dsh')\n } catch {\n return '.dsh'\n }\n}\n\n/** Absolute path of the plugin's key index. */\nexport function keyIndexFilePath(home: string = harnessHome()): string {\n return join(home, 'dsh-model-think-level', 'key-index.json')\n}\n\n/**\n * Parse an already-decoded index document. Never throws and never trusts the\n * input: anything unrecognisable is dropped entry by entry, so a hand-edited or\n * truncated file costs at most the lines it got wrong.\n * @param raw - the decoded JSON value (or anything else).\n * @returns a well-formed document.\n */\nexport function parseKeyIndex(raw: unknown): KeyIndexDocument {\n if (typeof raw !== 'object' || raw === null) return emptyKeyIndex()\n const providers = (raw as Record<string, unknown>)['providers']\n if (typeof providers !== 'object' || providers === null) return emptyKeyIndex()\n const out: Record<string, KeyIndexEntry[]> = {}\n for (const [route, entries] of Object.entries(providers as Record<string, unknown>)) {\n if (route.length === 0 || !Array.isArray(entries)) continue\n const list: KeyIndexEntry[] = []\n for (const entry of entries) {\n if (typeof entry !== 'object' || entry === null) continue\n const record = entry as Record<string, unknown>\n const ref = record['ref']\n if (typeof ref !== 'string' || ref.length === 0) continue\n if (list.some(existing => existing.ref === ref)) continue\n const alias = normalizeKeyAlias(record['alias'])\n list.push(alias === undefined ? { ref } : { ref, alias })\n }\n if (list.length > 0) out[route] = list\n }\n return { version: 1, providers: out }\n}\n\n/** Read the index at one path, or an empty one when there is nothing to read. */\nexport function readKeyIndex(file: string = keyIndexFilePath()): KeyIndexDocument {\n try {\n return parseKeyIndex(JSON.parse(readFileSync(file, 'utf8')))\n } catch {\n // Missing, unreadable and malformed are the same answer here: the manager\n // opens with an empty list, and the profile's own enabled reference is\n // merged into what it lists anyway.\n return emptyKeyIndex()\n }\n}\n\n/** Write the index at one path, atomically. */\nexport function writeKeyIndex(document: KeyIndexDocument, file: string = keyIndexFilePath()): void {\n mkdirSync(dirname(file), { recursive: true })\n const temporary = `${file}.${process.pid}.tmp`\n writeFileSync(temporary, `${JSON.stringify(document, null, 2)}\\n`, 'utf8')\n try {\n renameSync(temporary, file)\n } catch (error) {\n try {\n unlinkSync(temporary)\n } catch {\n // The temp file is best-effort cleanup; the rename failure is the news.\n }\n throw error\n }\n}\n\n/**\n * One synchronous read-modify-write. The returned document is what was stored.\n * @param mutate - pure document transform.\n * @param file - index path (tests pass a temp file).\n */\nexport function updateKeyIndex(\n mutate: (document: KeyIndexDocument) => KeyIndexDocument,\n file: string = keyIndexFilePath(),\n): KeyIndexDocument {\n const next = mutate(readKeyIndex(file))\n writeKeyIndex(next, file)\n return next\n}\n\n/** One route's keys, or an empty list. */\nexport function keyEntriesOf(document: KeyIndexDocument, route: string): readonly KeyIndexEntry[] {\n const entries = document.providers[route]\n return Array.isArray(entries) ? entries : []\n}\n\n/** Whether one route's list names this reference. */\nexport function hasKeyEntry(document: KeyIndexDocument, route: string, ref: string): boolean {\n return keyEntriesOf(document, route).some(entry => entry.ref === ref)\n}\n\n/**\n * Add a key, or relabel the one already there. Order is preserved: the list is\n * what the panel renders, and a key that moves on every rename is a worse list.\n * @param document - the current document.\n * @param route - the provider route key.\n * @param ref - the credential reference.\n * @param alias - a label, or undefined to keep whatever is stored.\n */\nexport function withKeyEntry(\n document: KeyIndexDocument,\n route: string,\n ref: string,\n alias?: string | undefined,\n): KeyIndexDocument {\n const list = [...keyEntriesOf(document, route)]\n const index = list.findIndex(entry => entry.ref === ref)\n const label = normalizeKeyAlias(alias)\n const next: KeyIndexEntry = label === undefined ? { ref } : { ref, alias: label }\n if (index === -1) list.push(next)\n else list[index] = label === undefined && list[index]?.alias !== undefined ? { ref, alias: list[index]?.alias } : next\n return { version: 1, providers: { ...document.providers, [route]: list } }\n}\n\n/**\n * Set (or clear) one key's label.\n * @param document - the current document.\n * @param route - the provider route key.\n * @param ref - the credential reference; a no-op when it is not listed.\n * @param alias - the new label, or undefined to fall back to the reference.\n */\nexport function withKeyAlias(\n document: KeyIndexDocument,\n route: string,\n ref: string,\n alias: string | undefined,\n): KeyIndexDocument {\n const list = [...keyEntriesOf(document, route)]\n const index = list.findIndex(entry => entry.ref === ref)\n if (index === -1) return document\n const label = normalizeKeyAlias(alias)\n list[index] = label === undefined ? { ref } : { ref, alias: label }\n return { version: 1, providers: { ...document.providers, [route]: list } }\n}\n\n/**\n * Drop one key. The route key itself is removed once its list empties, so a\n * provider the user cleaned up leaves no residue in the file.\n * @param document - the current document.\n * @param route - the provider route key.\n * @param ref - the credential reference to forget.\n */\nexport function withoutKeyEntry(document: KeyIndexDocument, route: string, ref: string): KeyIndexDocument {\n const list = keyEntriesOf(document, route).filter(entry => entry.ref !== ref)\n const providers: Record<string, readonly KeyIndexEntry[]> = { ...document.providers }\n if (list.length === 0) delete providers[route]\n else providers[route] = list\n return { version: 1, providers }\n}\n", "/**\n * The reasoning-effort + input-modality knowledge base + wire-protocol\n * inference engine.\n *\n * Every model a third-party provider route serves must declare its\n * 'reasoningEfforts' (which DSH thinking levels it accepts, and the exact\n * string to send on the wire for each) before the composer's model picker\n * offers any reasoning control for it. This module answers \"what should this\n * model's declaration be?\" from three sources, in order:\n *\n * 1. An endpoint listing signal (when the route was probed): an explicit\n * \"does not reason\", a modality disclosure, or a context length.\n * 2. A curated knowledge base keyed by model id/name patterns, carrying the\n * exact level set, wire spellings, request modalities, and reference\n * capacities known to work against that family of endpoints.\n * 3. Wire-protocol inference from the route's 'api' / 'baseURL', plus a\n * conservative name heuristic for modalities, for families nothing else\n * names.\n *\n * All outputs stay on the adapter's own vocabulary (THINKING_LEVELS,\n * INPUT_MODALITIES, the reasoningEfforts/input dict shapes) so a suggested\n * declaration can be written to llm-pi-ai settings with no translation step.\n * A suggestion is a *preset*: the user can accept it, tune it, or ignore it.\n * The plugin never silently overwrites a declaration the user already made.\n *\n * @module dsh-model-think-level/knowledge\n */\n\n/** The canonical pi-ai escalation order accepted by llm-pi-ai. */\nexport const THINKING_LEVELS = ['off', 'minimal', 'low', 'medium', 'high', 'xhigh', 'max'] as const\n\nexport type ThinkingLevel = (typeof THINKING_LEVELS)[number]\n\n/**\n * The request-modality vocabulary llm-pi-ai accepts on a model entry -- a\n * local mirror of pi-ai's MODALITY_GATE (text/image today). The core schema\n * refuses anything else at write time, and its drift gate forces the\n * vocabulary to grow exactly when pi-ai's Model['input'] does; the vocabulary\n * spec pins this mirror against upstream so the UI follows.\n */\nexport const INPUT_MODALITIES = ['text', 'image'] as const\n\nexport type InputModality = (typeof INPUT_MODALITIES)[number]\n\n/** One level's wire spelling; null means \"send nothing for this level\". */\nexport type WireSpelling = string | null\n\n/** A full reasoning-effort declaration value: level -> wire spelling. */\nexport type ReasoningEfforts = Partial<Record<ThinkingLevel, WireSpelling>>\n\n/** A full input-modality declaration value: the modalities a model accepts. */\nexport type InputModalities = readonly InputModality[]\n\n/** Reasoning-budget request-field spellings pi-ai accepts (older kernels reject them). */\nexport const THINKING_TOKEN_BUDGET_FIELDS = ['thinking_token_budget', 'thinking_budget', 'thinking_budget_tokens'] as const\nexport type ThinkingTokenBudgetField = (typeof THINKING_TOKEN_BUDGET_FIELDS)[number]\n\n/** The compat fields this plugin may suggest (a subset of the profile schema). */\nexport interface CompatSuggestion {\n /** Wire format the endpoint speaks; omitted when unknown. */\n thinkingFormat?: string\n /** Whether the endpoint accepts a reasoning-effort-style parameter. */\n supportsReasoningEffort?: boolean\n /**\n * Whether pi-ai may rewrite the system prompt to the developer role for\n * reasoning models. Self-hosted relays get an explicit false (their\n * upstreams reject role:developer); official endpoints keep pi-ai's own\n * detection default by omitting the field.\n */\n supportsDeveloperRole?: boolean\n /**\n * Anthropic-messages protocol only: force adaptive thinking so the\n * declared efforts dispatch as `output_config.effort` instead of falling\n * into the older budget-based thinking path. pi-ai offers this field on\n * exactly the anthropic-messages compat gate, and the oracle models that\n * take an effort ladder all have adaptive thinking.\n */\n forceAdaptiveThinking?: boolean\n thinkingTokenBudgetField?: ThinkingTokenBudgetField\n supportsThinkingTokenBudget?: boolean\n vllmPriority?: number\n supportsMaxOutputTokens?: boolean\n}\n\nexport const NEW_COMPAT_KEYS = ['thinkingTokenBudgetField', 'vllmPriority', 'supportsMaxOutputTokens'] as const\n\n/** One knowledge-base entry: which model families it matches and what to declare. */\nexport interface KnowledgeEntry {\n /** Stable id (also used to de-duplicate user overrides). */\n id: string\n /** Model id/name patterns (lowercase substring match). */\n patterns: readonly string[]\n /**\n * Level set + wire spellings to declare. `false` marks a family the\n * official catalog serves WITHOUT any reasoning control (GPT-4o / GPT-4\n * generations): suggesting a ladder there would have the composer send\n * reasoning_effort and get a 400 from the real endpoint.\n */\n efforts: ReasoningEfforts | false\n /** Optional compat block to declare alongside the efforts. */\n compat?: CompatSuggestion\n /**\n * The model family takes an effort ladder on the anthropic-messages\n * protocol too: pi-ai only routes declared efforts to `output_config.effort`\n * when `forceAdaptiveThinking` is set, so this pin adds that compat block\n * on anthropic-messages routes (and nothing on any other protocol).\n */\n anthropicAdaptive?: boolean\n /**\n * Request modalities to declare, in core vocabulary. Absent = no modality\n * suggestion for this family. Wider support a gateway may serve (pdf,\n * audio, video) is recorded in 'note' until the core vocabulary grows.\n */\n input?: InputModalities\n /**\n * Reference context window in tokens (display-only advice; the official\n * capacity inputs are never auto-filled).\n */\n contextWindow?: number\n /** Reference max output tokens in tokens (display-only advice). */\n maxTokens?: number\n /**\n * The vendor's own default level for the family, when its docs name one\n * (the same research pass that recorded the ladders). Consumed by the\n * client's effort memory as the model-switch fallback: a switch to a model\n * with no remembered level re-applies the vendor default instead of leaving\n * the session on the host's \"Default\" (no-effort) state. Never guessed --\n * entries whose docs publish no default simply carry none.\n */\n defaultEffort?: ThinkingLevel\n /** Human note shown next to the suggestion (localized by the caller). */\n note?: string\n}\n\n/** What a provider route names about itself that inference can use. */\nexport interface RouteFacts {\n /** Wire protocol as configured ('api'), if any. */\n api?: string\n /** Endpoint URL, if any. */\n baseURL?: string\n /** Display name, if any. */\n displayName?: string\n}\n\n/** The endpoint facts a suggestion fuses, as the probe route reports them. */\nexport interface EndpointFacts {\n /** Tri-state reasoning signal: true / false / 'unknown' (listing silent). */\n reasoning: boolean | 'unknown'\n /** The listing field that produced the reasoning signal, null when none did. */\n source: string | null\n /**\n * The listing's input-modality disclosure, normalized to lowercase strings,\n * when the listing named such a field at all. Present-but-empty means the\n * field existed with no usable members; absent means the listing never\n * spoke about modalities (or the probe never ran) -- the tri-state\n * discipline: silence is not refusal.\n */\n input?: readonly string[]\n /** Context length the listing disclosed, when it carries one. */\n contextLength?: number\n}\n\n/** How a suggestion's input-modality part was derived. */\nexport type InputSource = 'knowledge' | 'endpoint' | 'heuristic'\n\n/** A resolved suggestion for one model on one route. */\nexport interface EffortSuggestion {\n /**\n * The reasoning-effort declaration to write, if one is derivable. False\n * arrives when the endpoint explicitly reports the model does not reason.\n */\n efforts?: ReasoningEfforts | false\n /**\n * The vendor's own default level for the model, when the knowledge base\n * names one and the suggested ladder carries it. The effort memory uses it\n * as the model-switch fallback (see {@link KnowledgeEntry.defaultEffort}).\n */\n defaultEffort?: ThinkingLevel\n /** The compat block to write alongside, if any. */\n compat?: CompatSuggestion\n /** Request modalities to declare, when derivable. */\n input?: InputModalities\n /** Where the modality part came from -- its confidence rides this. */\n inputSource?: InputSource\n /** Reference context window (display-only; never auto-filled anywhere). */\n contextWindow?: number\n /** Reference max output tokens (display-only). */\n maxTokens?: number\n /** Whether a knowledge-base entry matched (vs protocol inference). */\n matched: boolean\n /** The knowledge entry id when one matched. */\n entryId?: string\n /** Human-readable source of the suggestion. */\n source: string\n /**\n * Overall confidence for the UI: high = knowledge base (wire values) and/or\n * an explicit endpoint signal; medium = endpoint confirmed reasoning but the\n * level ladder is inferred; low = protocol inference alone.\n */\n confidence: 'high' | 'medium' | 'low'\n /** The endpoint signal behind this suggestion, when one was supplied. */\n endpoint?: { reasoning: boolean | 'unknown'; source: string | null }\n}\n\n/**\n * The curated knowledge base. Patterns are lowercase substring matches against\n * the model id (and display name). First match wins, longest pattern wins.\n *\n * Sources of truth (per family; DeepSeek / OpenAI / Anthropic re-checked\n * 2026-09 against their current official docs, the rest 2026-08): official API docs --\n * api-docs.deepseek.com (news/pricing/thinking/vision/API reference),\n * developers.openai.com model pages + guides (platform.openai.com blocked;\n * Azure learn mirror cross-checked), platform.claude.com (effort page,\n * models overview, OpenAI-SDK compatibility page), ai.google.dev (thinking +\n * OpenAI-compat pages), docs.x.ai (model pages + reasoning capability),\n * docs.bigmodel.cn (thinking + model pages), platform.kimi.com (models /\n * use-thinking-models / use-reasoning-effort), platform.stepfun.com (model\n * pages + reasoning), docs.byteplus.com / volcengine ModelArk (deep\n * reasoning), cloud.baidu.com (Qianfan pricing/thinking model list),\n * plus first-party GitHub cards (openai/gpt-oss, mistralai/mistral-common,\n * Tencent-Hunyuan/Hy3, MiniMax-AI/MiniMax-M3) -- cross-checked against the\n * public OpenRouter catalog (input_modalities, supported_parameters) where\n * noted. Capacities are REFERENCE values: aggregators disagree, so the note\n * says so where the spread is wide, and families whose numbers stay contested\n * simply carry none.\n */\nexport const KNOWLEDGE_BASE: readonly KnowledgeEntry[] = [\n {\n id: 'deepseek-v4-vision',\n // Must precede deepseek-v4 semantically -- guaranteed anyway by the\n // longest-boundary-hit rule, since these patterns are strictly longer.\n patterns: ['deepseek-v4-flash-vision', 'deepseek-v4-vision'],\n efforts: { off: 'none', low: 'low', high: 'high', max: 'max' },\n defaultEffort: 'high',\n compat: { thinkingFormat: 'deepseek', supportsReasoningEffort: true },\n input: ['text', 'image'],\n contextWindow: 1_048_576,\n maxTokens: 384_000,\n note: 'DeepSeek \u89C6\u89C9\u5B9E\u9A8C\u7248 id\uFF08deepseek-v4-flash-vision-exp\uFF09\u3002\u5B98\u65B9\u76EE\u5F55\u5DF2\u6807\u6CE8\u8BE5\u6A21\u578B\u9000\u5F79\uFF0C\u540D\u5B57\u4ECD\u88AB\u63A5\u53D7\u3001\u7531\u73B0\u884C deepseek-flash \u63D0\u4F9B\u670D\u52A1\u2014\u2014\u56FE\u7247\u8F93\u5165\u73B0\u5DF2\u7531 deepseek-flash \u539F\u751F\u63D0\u4F9B\u3002',\n },\n {\n id: 'deepseek-v4-1-flash',\n // V4.1-Flash is DeepSeek's CURRENT flagship and it takes image input, which\n // the shared `deepseek-v4` stem cannot express: that entry carries the text\n // floor its pro/legacy siblings share, and one modal answer cannot be both.\n // This entry keys every V4.1 spelling, and it must stay ahead of the base\n // stem -- the longest-hit rule guarantees that, these patterns are strictly\n // longer -- so an id, or a display name, that says \"V4.1 Flash\" declares\n // images even when the relay invented the id itself.\n // 'deepseek-flash' is the CURRENT official id (2026-09-10) and belongs\n // here, not to the stem: the pricing page serves it as V4.1-Flash, and a\n // third-party reseller exposing DeepSeek's own model under that name means\n // the same model.\n patterns: ['deepseek-v4.1-flash', 'deepseek-flash'],\n efforts: { off: 'none', low: 'low', high: 'high', max: 'max' },\n defaultEffort: 'high',\n compat: { thinkingFormat: 'deepseek', supportsReasoningEffort: true },\n input: ['text', 'image'],\n contextWindow: 1_048_576,\n maxTokens: 384_000,\n note: 'DeepSeek-V4.1-Flash\uFF082026-09-10 \u53D1\u5E03\u7684\u73B0\u884C\u5B98\u65B9\u6A21\u578B\uFF0C\u5B98\u65B9 id \u4E3A deepseek-flash\uFF1B25 \u4E07\u5E76\u53D1\u3001**\u539F\u751F\u56FE\u7247\u8F93\u5165**\uFF09\u3002V4.1 \u7684\u5404\u5199\u6CD5\uFF08deepseek-flash\u3001deepseek-v4.1-flash\u3001deepseek-v4-1-flash\uFF0C\u4EE5\u53CA\u5E26\u65E5\u671F\u540E\u7F00\u7684\u7B2C\u4E09\u65B9\u53D8\u4F53\uFF09\u90FD\u5F52\u6B64\u6761\u2014\u2014\u7EAF\u6587\u672C\u7684 deepseek-v4 \u4E3B\u5E72\u4E0D\u518D\u541E\u6389\u5B83\u4EEC\u3002\u5B98\u65B9\u679A\u4E3E\u540C V4 \u7CFB\uFF1AOff\uFF08thinking:\"disabled\"\uFF09/ Low / High / Max\uFF0C\u9ED8\u8BA4 High\uFF1B\u5BB9\u91CF 1,048,576 \u4E0A\u4E0B\u6587 / \u6700\u5927\u8F93\u51FA 384K\u3002',\n },\n {\n id: 'deepseek-v4',\n // One pattern covers the family's TEXT-floor members: every serving\n // suffixes the base id (deepseek-v4-flash, deepseek-v4-pro,\n // deepseek-v4-flash-free ...), so the shared stem keys them all --\n // including free/aggregator spellings the official catalog never lists.\n // Closing thinking is the 'thinking: disabled' object, so the off spelling\n // is a non-null placeholder that arms the deepseek format's disabled\n // branch. The placeholder must stay 'none': pi-ai's deepseek completions\n // branch only checks non-null (any string arms thinking:disabled), while\n // the same map rides the Responses API as reasoning.effort, whose official\n // DeepSeek values are none/low/high/max -- 'off' would be a 400 there.\n // The stem deliberately stops at 'deepseek-v4': the image-capable V4.1\n // generation keys its own strictly longer entry above, while this entry\n // keeps the retired deepseek-v4-flash spelling and the text-only\n // deepseek-v4-pro, whose declarations agree with its text floor.\n patterns: ['deepseek-v4'],\n efforts: { off: 'none', low: 'low', high: 'high', max: 'max' },\n defaultEffort: 'high',\n compat: { thinkingFormat: 'deepseek', supportsReasoningEffort: true },\n input: ['text'],\n contextWindow: 1_048_576,\n maxTokens: 384_000,\n note: 'DeepSeek \u5B98\u65B9\u679A\u4E3E Low / High / Max\uFF08\u9ED8\u8BA4 High\uFF1Bminimal\u3001medium\u3001xhigh \u517C\u5BB9\u6620\u5C04\uFF0Cultra\u2192max\uFF09\uFF0COff \u5373 thinking:\"disabled\"\uFF08Responses API \u4E0B off \u4EE5 reasoning.effort:\"none\" \u8868\u793A\uFF09\u3002\u672C\u6761\u76EE\u662F V4 \u5BB6\u65CF\u7684**\u7EAF\u6587\u672C**\u6210\u5458\uFF1Adeepseek-v4-pro\uFF08= DeepSeek-V4-Pro-0813\uFF0C\u5B98\u65B9\u4E0D\u652F\u6301\u56FE\u7247\uFF09\u4E0E\u5DF2\u9000\u5F79\u6A21\u578B\u7684\u517C\u5BB9\u522B\u540D deepseek-v4-flash\uFF08deepseek-v4-flash-vision-exp \u53E6\u6709\u89C6\u89C9\u6761\u76EE\uFF09\u3002**\u6536\u56FE\u7684 V4.1-Flash\uFF08\u5B98\u65B9 id deepseek-flash\uFF09\u53E6\u6709\u4E13\u95E8\u6761\u76EE**\uFF0C\u5176 input \u542B image\u3002\u5BB9\u91CF\uFF1A1,048,576 \u4E0A\u4E0B\u6587 / \u6700\u5927\u8F93\u51FA 384K\uFF08393,216\uFF1B\u9ED8\u8BA4\u975E\u601D\u8003 8K\u3001\u601D\u8003 64K\u3001effort=max \u65F6 128K\uFF09\u3002',\n },\n {\n id: 'deepseek-v3',\n // deepseek-reasoner belongs to the R1 entry: it is the reasoning model's\n // API name and must not match here. The old alias pair\n // (deepseek-chat / deepseek-reasoner) was retired upstream in 2026-07;\n // the id patterns stay for third-party gateways still serving V3.x.\n patterns: ['deepseek-v3', 'deepseek-chat'],\n efforts: { off: 'none', high: 'high', max: 'max' },\n compat: { thinkingFormat: 'deepseek', supportsReasoningEffort: true },\n input: ['text'],\n contextWindow: 163_840,\n maxTokens: 65_536,\n note: 'DeepSeek V3 \u6863\u4F4D\uFF1AOff / High / Max\u3002\u5B98\u65B9\u5DF2\u505C\u552E V3 \u4EE3\uFF08\u5B9A\u4EF7\u9875\u4EC5\u5269 V4 \u4E09\u578B\uFF09\uFF0C\u5BB9\u91CF\u53D6\u76EE\u5F55\u73B0\u5F79\u503C\u3002',\n },\n {\n id: 'deepseek-r1',\n patterns: ['deepseek-r1', 'deepseek-reasoner'],\n // R1's reasoning cannot be switched off at the API level; the harness\n // treats it as a thinking model whose only declared level is the default.\n efforts: { high: 'high' },\n defaultEffort: 'high',\n compat: { thinkingFormat: 'deepseek', supportsReasoningEffort: true },\n input: ['text'],\n contextWindow: 163_840,\n maxTokens: 32_768,\n note: 'DeepSeek-R1 \u4E3A\u63A8\u7406\u6A21\u578B\uFF0C\u4EC5\u63D0\u4F9B High\u3002\u5B98\u65B9\u5DF2\u4E0B\u67B6 R1 \u4EE3\uFF0C\u5BB9\u91CF\u53D6\u76EE\u5F55 r1-0528 \u503C\u3002',\n },\n {\n id: 'openai-gpt-5-2',\n patterns: ['gpt-5.2'],\n // gpt-5.2 (2025-12) took 'none' as the explicit no-thinking value\n // (replacing gpt-5's 'minimal') and added xhigh; its default is none.\n efforts: { off: 'none', low: 'low', medium: 'medium', high: 'high', xhigh: 'xhigh' },\n defaultEffort: 'off',\n compat: { thinkingFormat: 'openai', supportsReasoningEffort: true },\n input: ['text', 'image'],\n contextWindow: 400_000,\n maxTokens: 128_000,\n note: 'GPT-5.2 \u6863\u4F4D\uFF1ANone / Low / Medium / High / XHigh\uFF08\u9ED8\u8BA4 None\uFF09\u3002\u5B98\u65B9\u53E6\u652F\u6301 PDF \u8F93\u5165\uFF08\u6838\u5FC3\u8BCD\u8868\u6682\u4E0D\u542B\uFF09\u3002gpt-5.2-pro \u5B98\u65B9\u9875\u672A\u5355\u5217\u6863\u4F4D\u884C\uFF0C\u6309\u672C\u6761\u76EE\u540C\u6863\u5904\u7406\uFF1Bgpt-5.2-codex \u89C1\u5355\u72EC\u6761\u76EE\u3002',\n },\n {\n id: 'openai-gpt-5-2-codex',\n // The codex variant's official model page names low/medium/high/xhigh\n // only -- NO none -- so the shared gpt-5.2 entry must not claim an off\n // for it (a 'none' request would 400). Longer pattern wins over 'gpt-5.2'.\n patterns: ['gpt-5.2-codex'],\n efforts: { low: 'low', medium: 'medium', high: 'high', xhigh: 'xhigh' },\n // OpenAI's API default for the codex line is medium (Inspect AI's\n // per-model default table, aligned with developers.openai.com).\n defaultEffort: 'medium',\n compat: { thinkingFormat: 'openai', supportsReasoningEffort: true },\n input: ['text', 'image'],\n contextWindow: 400_000,\n maxTokens: 128_000,\n note: 'GPT-5.2-Codex \u6863\u4F4D\uFF1ALow / Medium / High / XHigh\uFF08\u65E0 None \u6863\uFF0C\u52FF\u52FE Off\uFF09\uFF0C\u5E26\u56FE\u8F93\u5165\u3001400K\u3002',\n },\n {\n id: 'openai-gpt-5-6',\n patterns: ['gpt-5.6'],\n // gpt-5.6 spans the full modern ladder including max; the sol/luna/terra\n // variants share it (official reasoning guide: values \"can include none\n // minimal low medium high xhigh, and max\").\n efforts: { off: 'none', low: 'low', medium: 'medium', high: 'high', xhigh: 'xhigh', max: 'max' },\n defaultEffort: 'medium',\n compat: { thinkingFormat: 'openai', supportsReasoningEffort: true },\n input: ['text', 'image'],\n contextWindow: 1_050_000,\n maxTokens: 128_000,\n note: 'GPT-5.6\uFF08\u522B\u540D\u5373 sol\uFF09\u6863\u4F4D\uFF1ANone / Low / Medium(\u9ED8\u8BA4) / High / XHigh / Max\uFF1Bsol/luna/terra \u540C\u6863\uFF0C\u5E26\u56FE\u8F93\u5165\u3002',\n },\n {\n id: 'openai-gpt-5-5',\n patterns: ['gpt-5.5'],\n // gpt-5.5 defaults to medium (official reasoning guide) and tops out at\n // xhigh; the -pro variant drops none/low (medium/high/xhigh only).\n efforts: { off: 'none', low: 'low', medium: 'medium', high: 'high', xhigh: 'xhigh' },\n defaultEffort: 'medium',\n compat: { thinkingFormat: 'openai', supportsReasoningEffort: true },\n input: ['text', 'image'],\n contextWindow: 1_050_000,\n maxTokens: 128_000,\n note: 'GPT-5.5 \u6863\u4F4D\uFF1ANone / Low / Medium(\u9ED8\u8BA4) / High / XHigh\uFF0C\u5E26\u56FE\u8F93\u5165\u3002pro \u53D8\u4F53\u4EC5 Medium / High(\u9ED8\u8BA4) / XHigh \u4E14\u4EC5 Responses API\u3002',\n },\n {\n id: 'openai-gpt-5-4',\n patterns: ['gpt-5.4'],\n // Official model page: none (default) / low / medium / high / xhigh;\n // pro drops none+low and is Responses-only; mini/nano sit on 400K.\n efforts: { off: 'none', low: 'low', medium: 'medium', high: 'high', xhigh: 'xhigh' },\n defaultEffort: 'off',\n compat: { thinkingFormat: 'openai', supportsReasoningEffort: true },\n input: ['text', 'image'],\n contextWindow: 1_050_000,\n maxTokens: 128_000,\n note: 'GPT-5.4 \u6863\u4F4D\uFF1ANone(\u9ED8\u8BA4) / Low / Medium / High / XHigh\uFF0C\u5E26\u56FE\u8F93\u5165\u3002pro \u53D8\u4F53\u4EC5 Medium/High/XHigh\uFF1Bmini/nano \u4E3A 400K \u4E0A\u4E0B\u6587\u3002',\n },\n {\n id: 'openai-gpt-5-3',\n patterns: ['gpt-5.3'],\n // Official model page: low / medium / high / xhigh only -- no none.\n efforts: { low: 'low', medium: 'medium', high: 'high', xhigh: 'xhigh' },\n defaultEffort: 'medium',\n compat: { thinkingFormat: 'openai', supportsReasoningEffort: true },\n input: ['text', 'image'],\n contextWindow: 400_000,\n maxTokens: 128_000,\n note: 'GPT-5.3-Codex \u6863\u4F4D\uFF1ALow / Medium / High / XHigh\uFF08\u65E0 None \u6863\uFF09\uFF0C\u5E26\u56FE\u8F93\u5165\u3001400K\uFF1Bgpt-5.3-chat \u4E3A\u975E\u63A8\u7406\u804A\u5929\u6A21\u578B\uFF08\u89C1 chat \u6761\u76EE\uFF09\u3002',\n },\n {\n id: 'openai-gpt-5-1',\n patterns: ['gpt-5.1'],\n // gpt-5.1 (2025-11): none replaces minimal; no xhigh outside codex-max.\n // The codex variants split into their own entry: their official pages\n // publish no effort line, and the codex line's 5.2/5.3 successors take\n // no none -- so the conservative declaration there drops both none and\n // xhigh (see openai-gpt-5-1-codex).\n efforts: { off: 'none', low: 'low', medium: 'medium', high: 'high' },\n defaultEffort: 'off',\n compat: { thinkingFormat: 'openai', supportsReasoningEffort: true },\n input: ['text', 'image'],\n contextWindow: 400_000,\n maxTokens: 128_000,\n note: 'GPT-5.1 \u6863\u4F4D\uFF1ANone / Low / Medium / High\uFF08\u9ED8\u8BA4 None\uFF09\u3002',\n },\n {\n id: 'openai-gpt-5-1-codex',\n // Official model pages for 5.1-codex / -codex-max / -codex-mini publish no\n // reasoning-effort line (unlike gpt-5.1 itself); the codex successors\n // 5.2/5.3 are low/medium/high/xhigh without none, so none is NOT declared\n // here either. xhigh is likewise unproven for 5.1-codex (the 5.1 page's\n // own ladder stops at high) and is withheld.\n patterns: ['gpt-5.1-codex'],\n efforts: { low: 'low', medium: 'medium', high: 'high' },\n compat: { thinkingFormat: 'openai', supportsReasoningEffort: true },\n input: ['text', 'image'],\n contextWindow: 400_000,\n maxTokens: 128_000,\n note: 'GPT-5.1-Codex \u7CFB\u5217\uFF1A\u5B98\u65B9\u6A21\u578B\u9875\u672A\u5355\u5217 effort \u503C\u57DF\uFF0C\u6309\u540C\u4EE3\u4FDD\u5B88\u6863 Low / Medium / High\uFF08\u65E0 None\uFF1Bxhigh \u672A\u8BC1\u5B9E\uFF09\u3002\u5982\u7AEF\u70B9\u652F\u6301 xhigh/none \u53EF\u624B\u8C03\u3002',\n },\n {\n id: 'openai-gpt-5',\n patterns: ['gpt-5'],\n // The 2025-08 first generation: minimal is the floor, there is no none,\n // and the default (medium) thinks -- so no off level is offered.\n efforts: { minimal: 'minimal', low: 'low', medium: 'medium', high: 'high' },\n defaultEffort: 'medium',\n compat: { thinkingFormat: 'openai', supportsReasoningEffort: true },\n input: ['text', 'image'],\n contextWindow: 400_000,\n maxTokens: 128_000,\n note: 'GPT-5 \u521D\u4EE3\u6863\u4F4D\uFF1AMinimal / Low / Medium / High\uFF0C\u65E0\u5173\u95ED\u6863\u3002',\n },\n {\n id: 'openai-chat',\n // Non-reasoning chat lines across generations: they take no\n // reasoning_effort at all (official model pages list no \"Reasoning\").\n // Official ids are the *-chat-latest snapshots; the bare -chat spellings\n // stay for gateways serving them. gpt-5-chat-latest was removed upstream\n // on 2026-07-23 and gpt-chat-latest has no model page anymore -- the\n // patterns persist for compatibility only.\n patterns: [\n 'gpt-5.1-chat-latest', 'gpt-5.2-chat-latest', 'gpt-5.3-chat-latest', 'gpt-5-chat-latest',\n 'gpt-chat-latest', 'gpt-5-chat', 'gpt-5.1-chat', 'gpt-5.2-chat', 'gpt-5.3-chat',\n ],\n efforts: false,\n input: ['text', 'image'],\n contextWindow: 128_000,\n maxTokens: 16_384,\n note: '-chat \u7CFB\u5217\uFF08\u5B98\u65B9 id \u4E3A gpt-5.x-chat-latest\uFF09\u4E3A\u975E\u63A8\u7406\u804A\u5929\u6A21\u578B\uFF0C\u4E0D\u652F\u6301 effort \u53C2\u6570\uFF08\u52FF\u52FE\u601D\u8003\u6863\uFF09\uFF1B\u5B98\u65B9\u652F\u6301\u56FE\u7247\u8F93\u5165\uFF0C128K / 16,384 \u8F93\u51FA\u3002gpt-5-chat-latest \u5DF2\u4E8E 2026-07-23 \u4E0B\u67B6\u3001gpt-chat-latest \u5DF2\u65E0\u5B98\u65B9\u9875\u9762\uFF08\u4FDD\u7559\u6A21\u5F0F\u4F9B\u7F51\u5173\uFF09\u3002',\n },\n {\n id: 'openai-o',\n // The o-series scheduled-removal notice (2026-06-11): o1/o1-pro/o3-mini/\n // o4-mini are removed 2026-10-23 and o3/o3-pro on 2026-12-11, with\n // gpt-5.6-sol / gpt-5.6-terra replacing them; the tokens stay for\n // gateways and local deployments still serving them, and match only on\n // word boundaries (see matchKnowledgeBase), so 'o1' hits 'o1-mini' but\n // not 'ko1'.\n patterns: ['o1', 'o3', 'o4'],\n // o-series had no none: not sending the parameter meant medium (think\n // on), so no off level is offered.\n efforts: { low: 'low', medium: 'medium', high: 'high' },\n defaultEffort: 'medium',\n compat: { thinkingFormat: 'openai', supportsReasoningEffort: true },\n input: ['text', 'image'],\n contextWindow: 200_000,\n maxTokens: 100_000,\n note: 'OpenAI o \u7CFB\u6863\u4F4D\uFF1ALow / Medium / High\u3002\u5B98\u65B9\u5DF2\u4E8E 2026-06 \u516C\u544A\u9000\u5F79\uFF08o1/o1-pro/o3-mini/o4-mini 2026-10-23 \u79FB\u9664\u3001o3/o3-pro 2026-12-11\uFF09\uFF0C\u7F51\u5173\u6B8B\u7559\u4ECD\u53EF\u547D\u4E2D\uFF1B\u591A\u6570 o \u7CFB\u7AEF\u70B9\u6536\u56FE\uFF08o3-mini \u4F8B\u5916\uFF09\u3002',\n },\n {\n id: 'openai-gpt-oss',\n // Official README: configurable reasoning effort low / medium / high\n // (CLI default: low); official model page: 131,072 context and exactly\n // the same 131,072 max output tokens, text input only.\n patterns: ['gpt-oss'],\n efforts: { low: 'low', medium: 'medium', high: 'high' },\n defaultEffort: 'low',\n compat: { thinkingFormat: 'openai', supportsReasoningEffort: true },\n input: ['text'],\n contextWindow: 131_072,\n maxTokens: 131_072,\n note: 'GPT-OSS \u5F00\u6E90\u6743\u91CD\uFF08Ollama/vLLM \u5E38\u89C1\uFF09\uFF1Areasoning effort Low / Medium / High\uFF0C\u7EAF\u6587\u672C\uFF0C131K \u4E0A\u4E0B\u6587 / 131K \u8F93\u51FA\u30022026-09 \u590D\u6838\uFF1A\u5B98\u65B9\u6A21\u578B\u9875\u73B0\u5728\u5199 Chat Completions = Not supported\u3001\u65E0\u56FE\u7247\u8F93\u5165\uFF08\u9ED8\u8BA4 Low \u6765\u81EA\u5B98\u65B9 CLI\uFF0C\u4E0D\u662F API \u9875\uFF09\uFF0C\u56E0\u6B64\u8FD9\u91CC\u4E0D\u518D\u58F0\u660E Off\u3002',\n },\n {\n id: 'openai-gpt-6-astra',\n // Longest-pattern-wins keeps this ahead of the 5.x entries; 'astra' is the\n // only stable token an aggregator is likely to expose.\n patterns: ['gpt-6-astra', 'gpt-6'],\n // Official reasoning guide: none returns HTTP 400 on this model, and the\n // model page lists low/medium/high/xhigh/max. Official docs publish no\n // default effort for it, so none is recorded rather than guessed.\n efforts: { low: 'low', medium: 'medium', high: 'high', xhigh: 'xhigh', max: 'max' },\n compat: { thinkingFormat: 'openai', supportsReasoningEffort: true },\n input: ['text', 'image'],\n contextWindow: 1_050_000,\n maxTokens: 128_000,\n note: 'GPT-6 Astra \u6863\u4F4D\uFF1ALow / Medium / High / XHigh / Max\u2014\u2014**\u6CA1\u6709 None \u6863**\uFF08\u5B98\u65B9\u539F\u6587\uFF1A\u8BBE\u4E3A none \u8FD4\u56DE HTTP 400\uFF09\uFF0C\u56E0\u6B64\u672C\u6761\u76EE\u4E0D\u58F0\u660E Off\u3002\u5E26\u56FE\u8F93\u5165\uFF0C1,050,000 \u4E0A\u4E0B\u6587 / 128,000 \u8F93\u51FA\uFF1BAI \u5B98\u65B9\u9ED8\u8BA4\u6863\u4F4D\u672A\u516C\u5E03\uFF0C\u6545\u4E0D\u586B\u3002\u5DE5\u5177\u8C03\u7528\u9700\u8D70 Responses API\u3002',\n },\n {\n id: 'openai-gpt-5-6-cyber',\n // Before the family entry: cyber's model page publishes NO effort line and\n // limits Chat Completions, so the family ladder (which includes none/max)\n // must not be offered for it.\n patterns: ['gpt-5.6-cyber'],\n // Conservative: the codex-style successors publish no none, and cyber's\n // page publishes nothing at all -- declare the intersection the other 5.6\n // variants agree on, plus xhigh (every published 5.6 ladder carries it).\n efforts: { low: 'low', medium: 'medium', high: 'high', xhigh: 'xhigh' },\n compat: { thinkingFormat: 'openai', supportsReasoningEffort: true },\n input: ['text', 'image'],\n contextWindow: 400_000,\n maxTokens: 128_000,\n note: 'GPT-5.6-Cyber\uFF1A\u5B98\u65B9\u6A21\u578B\u9875\u672A\u5355\u5217 effort \u503C\u57DF\uFF08\u4E0D\u7B49\u4E8E\u4E0D\u652F\u6301\uFF09\uFF0C\u6545\u6309\u540C\u4EE3\u4FDD\u5B88\u6863 Low / Medium / High / XHigh\uFF1B\u8BE5\u578B\u53F7\u4EC5 Responses API\uFF0C\u5E26\u56FE\u8F93\u5165\u3001400K \u4E0A\u4E0B\u6587\u3002\u5B98\u65B9\u652F\u6301\u7684\u5176\u4ED6\u6863\u4F4D\u53EF\u624B\u8C03\u540E\u5E94\u7528\u3002',\n },\n {\n id: 'openai-gpt-4o',\n // Boundary matching keeps 'gpt-4' from hitting 'gpt-4o', so the vision\n // generation needs its own entry. gpt-4.1 keeps its own entry below\n // (1M context, larger output cap).\n patterns: ['gpt-4o'],\n // GPT-4o is not a reasoning model (official catalog lists no reasoning,\n // the API refuses reasoning_effort): suggest `false` so the editor\n // marks the row \"does not reason\" instead of wiring a rejected ladder.\n efforts: false,\n input: ['text', 'image'],\n contextWindow: 128_000,\n maxTokens: 16_384,\n note: 'GPT-4o \u4EE3\u9645\uFF1A\u975E\u63A8\u7406\u6A21\u578B\uFF0C\u4E0D\u652F\u6301 effort \u53C2\u6570\uFF08\u52FF\u52FE\u601D\u8003\u6863\uFF09\uFF1B\u56FE\u7247\u8F93\u5165\u5168\u7CFB\u6807\u914D\uFF0C128K / 16,384 \u8F93\u51FA\u3002',\n },\n {\n id: 'openai-gpt-4-1',\n // Official model page: 1,047,576 context / 32,768 max output, text+image\n // on every variant (4.1 / mini / nano alike -- the old \"nano is\n // text-only\" claim was wrong). No reasoning step at all.\n patterns: ['gpt-4.1'],\n efforts: false,\n input: ['text', 'image'],\n contextWindow: 1_047_576,\n maxTokens: 32_768,\n note: 'GPT-4.1 \u5168\u7CFB\uFF08\u542B mini/nano\uFF09\uFF1A\u975E\u63A8\u7406\u6A21\u578B\uFF0C\u4E0D\u652F\u6301 effort \u53C2\u6570\uFF1B\u5B98\u65B9 1,047,576 \u4E0A\u4E0B\u6587 / 32,768 \u8F93\u51FA\uFF0C\u5168\u7CFB\u5E26\u56FE\u8F93\u5165\u3002',\n },\n {\n id: 'openai-gpt-4-turbo-preview',\n // The preview snapshot is text-only (later turbo snapshots take images;\n // the shared preview spelling must not claim them). Longest-boundary-hit\n // keeps it ahead of 'gpt-4-turbo'.\n patterns: ['gpt-4-turbo-preview'],\n efforts: false,\n input: ['text'],\n contextWindow: 128_000,\n maxTokens: 4_096,\n note: 'GPT-4 Turbo Preview\uFF1A\u975E\u63A8\u7406\u6A21\u578B\uFF0C\u7EAF\u6587\u672C\u8F93\u5165\uFF08\u6B63\u5F0F turbo \u5FEB\u7167\u652F\u6301\u56FE\u7247\uFF0C\u89C1\u4E0B\u6761\uFF09\uFF0C128K\u3002',\n },\n {\n id: 'openai-gpt-4-turbo',\n patterns: ['gpt-4-turbo'],\n efforts: false,\n input: ['text', 'image'],\n contextWindow: 128_000,\n maxTokens: 4_096,\n note: 'GPT-4 Turbo\uFF1A\u975E\u63A8\u7406\u6A21\u578B\uFF0C\u5B98\u65B9\u652F\u6301\u56FE\u7247\u8F93\u5165\uFF0C128K / 4,096 \u8F93\u51FA\u3002',\n },\n {\n id: 'openai-gpt',\n patterns: ['gpt-4', 'gpt-3.5'],\n // Same reasoning as gpt-4o above: the GPT-4/3.5 generations take no\n // reasoning_effort -- suggest `false` rather than a rejected ladder.\n // gpt-4 remains text-only (8K window); the vision-bearing 4o/4.1/turbo\n // lines have their own entries.\n efforts: false,\n input: ['text'],\n note: 'GPT-4/3.5 \u4EE3\u9645\uFF1A\u975E\u63A8\u7406\u6A21\u578B\uFF0C\u4E0D\u652F\u6301 effort \u53C2\u6570\uFF08\u52FF\u52FE\u601D\u8003\u6863\uFF09\u3002gpt-4-turbo/4.1 \u8D77\u652F\u6301\u56FE\u7247\uFF0C\u89C1\u5355\u72EC\u6761\u76EE\uFF1B\u65B0\u4EE3\u8BF7\u7528 GPT-5 \u7CFB\uFF08\u89C1 openai-chat/gpt-5.x \u6761\u76EE\uFF09\u3002',\n },\n {\n id: 'anthropic-claude-5',\n // Claude 5th generation (fable/mythos/opus-5/sonnet-5, 2026): adaptive\n // thinking with an effort ladder that adds xhigh and max; the fable and\n // mythos entries think always-on, so no off level. Mythos Preview is\n // split into its own entry: it takes max but NOT xhigh (official effort\n // matrix), so the shared ladder's xhigh would be a 400.\n patterns: ['claude-fable-5', 'claude-mythos-5', 'claude-opus-5', 'claude-sonnet-5'],\n // Ladder per the official effort matrix (platform.claude.com\n // docs/build-with-claude/effort). NOTE: Anthropic's own OpenAI-SDK\n // compatibility layer IGNORES reasoning_effort (thinking is driven by\n // its own param, on by default for Claude 5) -- the declaration bites\n // on third-party gateways that map it; on the native\n // anthropic-messages protocol, anthropicAdaptive pins the compat that\n // makes pi-ai dispatch these as output_config.effort.\n efforts: { low: 'low', medium: 'medium', high: 'high', xhigh: 'xhigh', max: 'max' },\n defaultEffort: 'high',\n // No thinkingFormat: pi-ai has no 'anthropic' member, and the\n // openai-completions compat gate that takes thinkingFormat is not the\n // protocol an Anthropic endpoint speaks.\n compat: { supportsReasoningEffort: true },\n anthropicAdaptive: true,\n input: ['text', 'image'],\n contextWindow: 1_000_000,\n maxTokens: 128_000,\n note: 'Claude 5 \u4EE3\uFF08Fable 5 / Mythos 5 / Opus 5 / Sonnet 5\uFF09\u6863\u4F4D\uFF1ALow / Medium / High(\u9ED8\u8BA4) / XHigh / Max\uFF1BFable 5.1 \u4E0E Mythos 5.1 \u89C1\u5355\u72EC\u6761\u76EE\uFF0CMythos Preview \u4EC5\u81F3 Max\u30021M \u4E0A\u4E0B\u6587 / 128K \u8F93\u51FA\uFF08Batch 300K\uFF09\u3002\u5B98\u65B9\u652F\u6301 PDF \u8F93\u5165\u3002\u6CE8\u610F\uFF1AAnthropic \u5B98\u65B9 OpenAI \u517C\u5BB9\u5C42\u4F1A\u5FFD\u7565 effort \u53C2\u6570\uFF0C\u58F0\u660E\u5728\u7B2C\u4E09\u65B9\u7F51\u5173\u6620\u5C04\u65F6\u751F\u6548\u3002',\n },\n {\n id: 'anthropic-claude-5-1',\n // Ahead of the claude-5 entry, whose 'claude-fable-5' / 'claude-mythos-5'\n // patterns are prefixes of these ids and would win the equal-length tie.\n // Same ladder and default as the 5.0 generation per the official effort\n // page; the meaningful difference is behavioural (these two are the\n // models allowed to change effort mid-conversation), which this plugin\n // does not declare per model.\n patterns: ['claude-fable-5-1', 'claude-mythos-5-1'],\n efforts: { low: 'low', medium: 'medium', high: 'high', xhigh: 'xhigh', max: 'max' },\n defaultEffort: 'high',\n compat: { supportsReasoningEffort: true },\n anthropicAdaptive: true,\n input: ['text', 'image'],\n contextWindow: 1_000_000,\n maxTokens: 128_000,\n note: 'Claude Fable 5.1 / Mythos 5.1\uFF1A\u5B98\u65B9\u6863\u4F4D Low / Medium / High(\u9ED8\u8BA4) / XHigh / Max\uFF0C\u81EA\u9002\u5E94\u601D\u8003\u5E38\u5F00\uFF08\u4E0D\u63A5\u53D7 enabled/disabled\uFF09\u30021M \u4E0A\u4E0B\u6587 / 128K \u8F93\u51FA\uFF1B\u8FD9\u4E24\u578B\u4E5F\u662F\u5B98\u65B9\u552F\u4E00\u5141\u8BB8\u4F1A\u8BDD\u4E2D\u9014\u6539\u6863\u7684\uFF08\u9700 beta header\uFF0C\u672C\u63D2\u4EF6\u4E0D\u6D89\u53CA\uFF09\u3002',\n },\n {\n id: 'anthropic-claude-mythos-preview',\n // Official effort matrix: max is available, xhigh is NOT (the matrix's\n // xhigh list covers Fable 5 / Mythos 5 / Opus 5 / Opus 4.8 / Opus 4.7 /\n // Sonnet 5 only).\n patterns: ['claude-mythos-preview'],\n efforts: { low: 'low', medium: 'medium', high: 'high', max: 'max' },\n // Anthropic's effort page: the API default is HIGH across the whole\n // supported list (omitting effort behaves exactly as high).\n defaultEffort: 'high',\n compat: { supportsReasoningEffort: true },\n anthropicAdaptive: true,\n input: ['text', 'image'],\n contextWindow: 1_000_000,\n maxTokens: 128_000,\n note: 'Claude Mythos Preview\uFF1A\u5B98\u65B9\u6863\u4F4D Low / Medium / High / Max\uFF08\u65E0 XHigh\uFF09\uFF0C1M \u4E0A\u4E0B\u6587\u3002',\n },\n {\n id: 'anthropic-claude-opus-4-high',\n patterns: ['claude-opus-4-8', 'claude-opus-4-7'],\n // Official effort page: Opus 4.7/4.8 take the full ladder including\n // xhigh and max (xhigh is the recommended coding start on 4.7).\n efforts: { low: 'low', medium: 'medium', high: 'high', xhigh: 'xhigh', max: 'max' },\n defaultEffort: 'high',\n compat: { supportsReasoningEffort: true },\n anthropicAdaptive: true,\n input: ['text', 'image'],\n contextWindow: 1_000_000,\n maxTokens: 128_000,\n note: 'Claude Opus 4.7/4.8 \u6863\u4F4D\uFF1ALow / Medium / High(\u9ED8\u8BA4) / XHigh / Max\uFF1Bxhigh \u4E3A\u5B98\u65B9\u63A8\u8350\u7684\u7F16\u7801\u8D77\u6B65\u6863\u30021M \u4E0A\u4E0B\u6587\u3002',\n },\n {\n id: 'anthropic-claude-4-6',\n patterns: ['claude-opus-4-6', 'claude-sonnet-4-6'],\n // Official effort page: the 4.6 generation supports max but NOT xhigh\n // (\"some models that support max don't support xhigh\").\n efforts: { low: 'low', medium: 'medium', high: 'high', max: 'max' },\n defaultEffort: 'high',\n compat: { supportsReasoningEffort: true },\n anthropicAdaptive: true,\n input: ['text', 'image'],\n contextWindow: 1_000_000,\n maxTokens: 128_000,\n note: 'Claude 4.6 \u4EE3\u6863\u4F4D\uFF1ALow / Medium / High / Max\uFF08\u65E0 XHigh\u2014\u2014\u5B98\u65B9\u660E\u8A00\u300C\u652F\u6301 max \u7684\u90E8\u5206\u578B\u53F7\u4E0D\u652F\u6301 xhigh\u300D\uFF09\u30021M \u4E0A\u4E0B\u6587\u3002',\n },\n {\n id: 'anthropic-claude-opus-4-5',\n // The only extended-thinking-only model in Anthropic's official effort\n // support list (claude-opus-4-5-20251101): effort works alongside\n // budget_tokens, and the max/xhigh columns of the official matrix do not\n // name it -- so the ladder tops out at high.\n patterns: ['claude-opus-4-5'],\n efforts: { low: 'low', medium: 'medium', high: 'high' },\n defaultEffort: 'high',\n compat: { supportsReasoningEffort: true },\n input: ['text', 'image'],\n contextWindow: 200_000,\n maxTokens: 64_000,\n note: 'Claude Opus 4.5\uFF1A\u5B98\u65B9 effort \u652F\u6301\u5217\u8868\uFF0820251101 \u5FEB\u7167\uFF09\uFF0C\u6863\u4F4D Low / Medium / High\uFF08\u65E0 XHigh/Max\uFF09\uFF0C\u53EF\u4E0E budget_tokens \u5E76\u7528\uFF1B200K / 64K\u3002',\n },\n {\n id: 'anthropic-claude',\n // Everything else in the Claude line: 3.x and the 4.5-generation\n // Sonnet/Haiku. Anthropic's official effort support list names exactly\n // fable-5 / mythos-5 / mythos-preview / opus-5 / opus-4-8 / opus-4-7 /\n // opus-4-6 / sonnet-5 / sonnet-4-6 / opus-4-5-20251101 -- none of the\n // models matching this entry take the effort parameter (their thinking\n // rides thinking.type), so a ladder here would be refused. `false` is\n // the honest \"no effort control\" declaration, matching the openai-chat\n // convention.\n patterns: ['claude'],\n efforts: false,\n input: ['text', 'image'],\n contextWindow: 200_000,\n maxTokens: 64_000,\n note: 'Claude 3.x \u4E0E Sonnet 4.5 / Haiku 4.5\uFF1A\u5B98\u65B9 effort \u53C2\u6570\u4E0D\u652F\u6301\uFF08\u4EC5 Fable/Mythos 5\u3001Opus 5/4.6-4.8\u3001Sonnet 5/4.6\u3001Opus 4.5 \u652F\u6301\uFF09\uFF0C\u601D\u8003\u7531 thinking.type \u63A7\u5236\u2014\u2014\u52FF\u52FE\u601D\u8003\u6863\u3002\u53C2\u8003\u5BB9\u91CF 200K / 64K\uFF08Haiku 3.5 \u4E3A\u7EAF\u6587\u672C\uFF0C\u6309\u9700\u53D6\u6D88\u56FE\u7247\uFF09\u3002',\n },\n {\n id: 'google-gemini',\n patterns: ['gemini'],\n // Gemini over the OpenAI-compat layer maps reasoning_effort per family\n // (3.1+/3.x -> thinking_level, 2.5 -> thinking_budget). The official\n // compatibility sheet is a full grid (minimal / low / medium / high x\n // family), but the declared ladder stays low/medium/high: the safest\n // universal set, since minimal lands on a non-native value on Gemini\n // 3.1 Pro and none is reserved for 2.5 non-Pro. Users wanting the finer\n // grid tune by hand.\n efforts: { low: 'low', medium: 'medium', high: 'high' },\n compat: { thinkingFormat: 'openai', supportsReasoningEffort: true },\n input: ['text', 'image'],\n contextWindow: 1_048_576,\n maxTokens: 65_536,\n note: 'Gemini \u901A\u7528\u5B89\u5168\u6863\uFF1ALow / Medium / High\uFF08\u5B98\u65B9 OpenAI \u517C\u5BB9\u6620\u5C04\u8868\u53E6\u6536 minimal\uFF1A2.5 \u7CFB\u6620\u5C04\u4E3A 1,024 \u9884\u7B97\u30013.1 Flash-Lite/3 Flash \u539F\u751F minimal\u30013.1 Pro \u843D low\uFF09\u3002none \u4EC5\u80FD\u5173 2.5 \u975E Pro\uFF1B2.5 Pro \u4E0E 3 \u4EE3\u4E0D\u53EF\u5173\uFF1B\u5404\u578B\u9ED8\u8BA4\u4E0D\u4E00\uFF08flash-lite \u9ED8\u8BA4\u5173\uFF09\u3002\u5B98\u65B9\u53E6\u6536\u97F3\u9891/\u89C6\u9891/PDF\u3002',\n },\n {\n id: 'xai-grok-4-7',\n // grok-4.7 shipped after the 2026-08 pass that read it as 404 upstream;\n // that reading is retired here. xAI's own docs were unreachable for this\n // pass, so every field below is a public-catalog reading rather than a\n // first-party one: OpenRouter publishes the slug x-ai/grok-4.7 with\n // reasoning_effort in its supported_parameters, and models.dev records\n // the ladder as low/medium/high/xhigh -- the same four steps 4.6 takes,\n // which is why the same declaration shape is reused. The default level\n // and whether thinking can be closed are NOT established, so neither an\n // `off` nor a defaultEffort is declared. Capacity follows the sources\n // that agree (500K context); max output disagrees across catalogs\n // (450K vs 500K), so it stays out.\n patterns: ['grok-4.7'],\n efforts: { low: 'low', medium: 'medium', high: 'high', xhigh: 'xhigh' },\n compat: { thinkingFormat: 'openai', supportsReasoningEffort: true },\n input: ['text', 'image'],\n contextWindow: 500_000,\n note: 'Grok 4.7\uFF08\u4E0A\u6E38\u5FEB\u7167 grok-4.7-20260916\uFF09\uFF1A\u6863\u4F4D Low / Medium / High / XHigh\u2014\u2014**\u53D6\u81EA\u516C\u5F00\u76EE\u5F55**\uFF08OpenRouter \u7684 supported_parameters\u3001models.dev \u5BF9 docs.x.ai \u7684\u8F6C\u8FF0\uFF09\uFF0C\u672C\u6B21 xAI \u5B98\u65B9\u6587\u6863\u7AD9\u4E0D\u53EF\u8FBE\u3001\u672A\u80FD\u4E00\u624B\u8BC1\u5B9E\uFF1B\u9ED8\u8BA4\u6863\u4F4D\u4E0E\"\u80FD\u5426\u5173\u95ED\u601D\u8003\"\u540C\u6837\u672A\u8BC1\u5B9E\uFF0C\u6545\u4E0D\u58F0\u660E Off\uFF0C\u4E5F\u4E0D\u5199\u9ED8\u8BA4\u6863\u3002\u5E26\u56FE\u8F93\u5165\uFF08\u76EE\u5F55\u8BB0 text+image+file\uFF0CPDF \u5B58\u7591\uFF09\uFF0C500K \u4E0A\u4E0B\u6587\uFF1B\u6700\u5927\u8F93\u51FA\u5404\u76EE\u5F55\u7ED9\u51FA 450K \u4E0E 500K \u4E24\u79CD\u503C\uFF0C\u6309\"\u5206\u6B67\u5373\u4E0D\u5199\"\u5904\u7406\u30022026-08 \u90A3\u6B21\"grok-4.7 \u4E0D\u5B58\u5728\uFF08\u5B98\u65B9 404\uFF09\"\u7684\u7ED3\u8BBA\u5DF2\u968F\u53D1\u5E03\u4F5C\u5E9F\u3002',\n },\n {\n id: 'xai-grok-high',\n patterns: ['grok-4.6'],\n // grok-4.6 adds xhigh on top of low/medium/high (default) and cannot\n // close thinking (docs.x.ai model page + reasoning capability page).\n // (An earlier pass read grok-4.7 as 404 upstream; it shipped later --\n // see the entry above.)\n efforts: { low: 'low', medium: 'medium', high: 'high', xhigh: 'xhigh' },\n defaultEffort: 'high',\n compat: { thinkingFormat: 'openai', supportsReasoningEffort: true },\n input: ['text', 'image'],\n contextWindow: 500_000,\n note: 'Grok 4.6 \u6863\u4F4D\uFF1ALow / Medium / High(\u9ED8\u8BA4) / XHigh\uFF0C\u601D\u8003\u4E0D\u53EF\u5173\u95ED\uFF1B\u5E26\u56FE\u8F93\u5165\u3001500K \u4E0A\u4E0B\u6587\u3002Grok 4.7 \u89C1\u4E0A\u4E00\u6761\uFF08\u6B64\u524D\u8BB0\u4E3A\"\u4E0D\u5B58\u5728\"\uFF0C\u5DF2\u968F\u53D1\u5E03\u4F5C\u5E9F\uFF09\u3002',\n },\n {\n id: 'xai-grok-4-5',\n // grok-4.5 keeps the three-step ladder (default high) with image input\n // and a 500K context window; an xhigh request is silently treated as\n // high (official reasoning page), so it is not declared here.\n patterns: ['grok-4.5'],\n efforts: { low: 'low', medium: 'medium', high: 'high' },\n defaultEffort: 'high',\n compat: { thinkingFormat: 'openai', supportsReasoningEffort: true },\n input: ['text', 'image'],\n contextWindow: 500_000,\n note: 'Grok 4.5 \u6863\u4F4D\uFF1ALow / Medium / High(\u9ED8\u8BA4)\uFF0C\u601D\u8003\u4E0D\u53EF\u5173\u95ED\uFF1B\u5E26\u56FE\u8F93\u5165\u3002\u4F20\u5165 xhigh \u4F1A\u88AB\u5B98\u65B9\u9759\u9ED8\u6309 High \u5904\u7406\u3002',\n },\n {\n id: 'xai-grok-4-3',\n // Official reasoning-capability pages: grok-4.3 documents FOUR effort\n // levels (none / low / medium / high) with a 1M context window; the\n // deprecated grok-4-fast/grok-4-1-fast/grok-4-0709 slugs redirect to\n // grok-4.3 at low/none. The old \"no none for 4.3\" reading of the docs\n // was wrong and is fixed here.\n patterns: ['grok-4.3'],\n // Official models page (docs.x.ai model JSON): supportedEfforts now\n // spans none/low/medium/high/XHIGH with defaultEffort \"low\" -- xhigh\n // joined the ladder after the 2026-08 pass, and low is the default.\n efforts: { off: 'none', low: 'low', medium: 'medium', high: 'high', xhigh: 'xhigh' },\n defaultEffort: 'low',\n compat: { thinkingFormat: 'openai', supportsReasoningEffort: true },\n input: ['text', 'image'],\n contextWindow: 1_000_000,\n note: 'Grok 4.3\uFF1A\u5B98\u65B9\u56DB\u7EA7 reasoning effort\uFF08None / Low / Medium / High\uFF09\uFF0C1M \u4E0A\u4E0B\u6587\u3001\u5E26\u56FE\u8F93\u5165\uFF1Bgrok-4-fast \u7B49\u65E7 slug 2026-05-15 \u8D77\u81EA\u52A8\u91CD\u5B9A\u5411\u5230\u672C\u578B\u53F7\u3002',\n },\n {\n id: 'xai-grok',\n // grok-4.5 (and 4.1-fast etc.) take the standard three-step ladder;\n // grok-4 and older reject reasoning_effort outright -- gateways serving\n // them will refuse the value and the user can clear it by hand. Grok\n // 4/4.1 and grok-3 retired 2026-05-15 (redirected to grok-4.3), and\n // grok-build-0.1 (early-access coding model) publishes no effort\n // contract.\n patterns: ['grok'],\n efforts: { low: 'low', medium: 'medium', high: 'high' },\n compat: { thinkingFormat: 'openai', supportsReasoningEffort: true },\n input: ['text'],\n note: 'Grok \u901A\u7528\u6863\u4F4D\uFF1ALow / Medium / High\u3002\u521D\u4EE3 grok-4\u3001grok-4.20 \u4E0E grok-build-0.1 \u4E0D\u63A5\u53D7\u8BE5\u53C2\u6570\uFF08grok-4 \u7CFB\u4E0E grok-3 \u5DF2\u4E8E 2026-05-15 \u9000\u5F79\u5E76\u91CD\u5B9A\u5411\u81F3 4.3\uFF09\uFF1Bgrok-4.20-multi-agent \u7684\u56DB\u6863\u63A7\u5236\u7684\u662F agent \u6570\u91CF\u800C\u975E\u601D\u8003\u6DF1\u5EA6\u3002\u65B0\u65E7\u4EE3\u9645\u8BF7\u4F18\u5148\u9009 4.5/4.6/4.3\uFF1B\u591A\u6A21\u6001\u53D8\u4F53\u6309\u9700\u52FE\u9009\u56FE\u7247\u3002',\n },\n {\n id: 'mistral-magistral',\n // The native magistral line is a run-together thinking family with no\n // reasoning_effort control of its own (its thinking is driven by\n // prompt_mode / always-on), and Mistral marked the whole line\n // deprecated on 2026-07-28 (phased out through mid-2026; reasoning now\n // rides the generalist models). `false` is the honest \"no effort\n // control\" declaration; gateways that happen to map an effort\n // parameter onto magistral ids can be tuned by hand.\n patterns: ['magistral'],\n efforts: false,\n input: ['text'],\n contextWindow: 32_768,\n maxTokens: 32_768,\n note: 'Magistral \u539F\u751F\u601D\u8003\u7EBF\uFF08\u65E0 effort \u53C2\u6570\uFF0C\u4E3A prompt_mode \u8BED\u4E49\uFF09\uFF0C\u5B98\u65B9\u5DF2\u4E8E 2026-07-28 \u58F0\u660E\u5F03\u7528\u3001\u9010\u6B65\u64A4\u51FA\uFF1B\u73B0\u5F79\u63A8\u7406\u8D70 mistral-small-2603 / mistral-medium-3-5 \u7684 reasoning_effort\uFF08\u89C1\u4E0B\u6761\uFF09\u3002',\n },\n {\n id: 'mistral-medium-3',\n // Official reasoning page + mistral-common request.py (the first-party\n // protocol enum) name the reasoning_effort models: values are exactly\n // none/high. The API ids today are mistral-medium-3-5 (Medium 3.5's\n // model page names the dotted spelling too) and mistral-small-2603\n // (Mistral Small 4); mistral-small-latest is its alias. The dated\n // \"small-2506\" builds are retiring and are NOT matched; the bare\n // 'mistral-medium-3' stem was dropped so the 3.1 generation (no\n // reasoning_effort) does not get the ladder.\n // Normalization folds '.' and '-' to the same space, so the one dotted\n // spelling also keys the API id (mistral-medium-3-5).\n patterns: ['mistral-medium-3.5', 'mistral-small-latest', 'mistral-small-2603'],\n efforts: { off: 'none', high: 'high' },\n // mistral-common's ModelSettings defaults reasoning_effort to None --\n // the endpoint's no-parameter behaviour IS the none/off level.\n defaultEffort: 'off',\n compat: { thinkingFormat: 'openai', supportsReasoningEffort: true },\n input: ['text', 'image'],\n note: 'Mistral \u73B0\u5F79\u63A8\u7406\u6863\uFF1ANone / High\u2014\u2014\u5B98\u65B9 reasoning_effort \u679A\u4E3E\uFF08mistral-common \u534F\u8BAE\u5E93\uFF09\u5373 none/high\uFF1Bmistral-small-2603\uFF08Small 4\uFF09\u4E0E mistral-medium-3-5 \u7ECF\u5B83\u63A7\u5236\uFF0CMedium 3.5 \u5E26\u89C6\u89C9\u3002\u5BB9\u91CF\u672A\u5728\u5B98\u65B9\u76EE\u5F55\u9875\u5355\u5217\uFF0C\u4E0D\u63D0\u4F9B\u3002',\n },\n {\n id: 'qwen-vision',\n // The DashScope vision lines: -vl suffixes and QvQ. Normalization folds\n // 'qwen2.5-vl' to 'qwen2 5 vl', hence the spelled-out middle pattern.\n // Note the modern generations (3.8-max / 3.7-plus / 3.7-flash and the\n // 3.5-omni line) are multimodal too -- see the qwen-3-8 entry and the\n // plain qwen entry note.\n patterns: ['qwen-vl', 'qwen2-vl', 'qwen2-5-vl', 'qwen3-vl', 'qvq'],\n // DashScope takes NO reasoning_effort: thinking is the enable_thinking\n // boolean -- pi-ai's 'qwen' format dispatches exactly that switch.\n // Commercial Model Studio deployments default enable_thinking to TRUE\n // (help.aliyun.com) -- the on state, which is High here.\n efforts: { off: null, high: 'high' },\n defaultEffort: 'high',\n compat: { thinkingFormat: 'qwen' },\n input: ['text', 'image'],\n contextWindow: 131_072,\n maxTokens: 8_192,\n note: '\u901A\u4E49\u89C6\u89C9\u7EBF\uFF08Qwen-VL/QvQ\uFF09\uFF1Aenable_thinking \u5F00\u5173\uFF08\u5F00=High\uFF09\uFF0C\u6536\u56FE\u3002qwen3-vl \u5BB9\u91CF\u66F4\u5927\uFF0C\u6309\u9700\u4E0A\u8C03\u3002',\n },\n {\n id: 'qwen-3-8',\n // The 3.8 generation moved from the bare enable_thinking switch to an\n // official reasoning_effort ladder: the Qwen3.8 README (\"Flexible\n // Thinking Control\"), the Qwen3.8-27B model card, the Qwen3.8-Flash-Next\n // card and the qwen.ai Flash-Next blog all document reasoning_effort\n // with xhigh as the DEFAULT (xhigh/medium/low), alongside the\n // per-request enable_thinking toggle (chat_template_kwargs on\n // open-weight serving). qwen3.8-max stays the current flagship (1M\n // context; Model Studio lists it under image/video understanding), so\n // the plain qwen entry's text-only declaration must not claim it.\n patterns: ['qwen3.8'],\n efforts: { off: null, low: 'low', medium: 'medium', xhigh: 'xhigh' },\n defaultEffort: 'xhigh',\n compat: { thinkingFormat: 'qwen', supportsReasoningEffort: true },\n input: ['text', 'image'],\n contextWindow: 1_000_000,\n note: 'Qwen 3.8 \u7CFB\uFF1A\u5B98\u65B9 reasoning_effort \u6863\u4F4D XHigh(\u9ED8\u8BA4) / Medium / Low\uFF0Cthinking \u9ED8\u8BA4\u5F00\u3001\u53EF\u6309\u8BF7\u6C42\u5173\u95ED\uFF1B\u539F\u751F\u591A\u6A21\u6001\uFF08qwen3.8-max \u56FE\u50CF/\u89C6\u9891\u7406\u89E3\uFF0C\u89C6\u9891\u672A\u5165\u6838\u5FC3\u8BCD\u8868\uFF09\u30021M \u6863\u4E0A\u4E0B\u6587\u300227B \u4E0E Flash-Next \u5F00\u6E90\u6B3E\u89C1\u5355\u72EC\u6761\u76EE\u3002',\n },\n {\n id: 'qwen-3-8-27b',\n // Open-weight dense release (2026-08-14, HF Qwen/Qwen3.8-27B model\n // card): \"native vision-language model\", 262,144 context natively\n // \"extensible up to 1,000,000 tokens\", reasoning_effort xhigh (default)\n // / medium / low with per-request thinking disable. Longer than the\n // bare 'qwen3.8' pattern, so it wins for -27B ids.\n patterns: ['qwen3.8-27b'],\n efforts: { off: null, low: 'low', medium: 'medium', xhigh: 'xhigh' },\n defaultEffort: 'xhigh',\n compat: { thinkingFormat: 'qwen', supportsReasoningEffort: true },\n input: ['text', 'image'],\n contextWindow: 262_144,\n note: 'Qwen3.8-27B\uFF08dense\uFF0C2026-08-14 \u5F00\u6E90\uFF09\uFF1A\u5B98\u65B9 reasoning_effort \u6863\u4F4D XHigh(\u9ED8\u8BA4) / Medium / Low\uFF0Cthinking \u9ED8\u8BA4\u5F00\u3001\u53EF\u6309\u8BF7\u6C42\u5173\uFF1B\u539F\u751F\u56FE\u50CF+\u89C6\u9891\u7406\u89E3\uFF08\u89C6\u9891\u672A\u5165\u6838\u5FC3\u8BCD\u8868\uFF09\u3002262,144 \u539F\u751F\u4E0A\u4E0B\u6587\u3001\u5B98\u65B9\u58F0\u660E\u53EF\u6269\u81F3 1M\u3002\u6765\u6E90\uFF1AHF Qwen/Qwen3.8-27B \u6A21\u578B\u5361\u3002',\n },\n {\n id: 'qwen-3-8-flash-next',\n // Open-weight experimental architecture preview (HF\n // Qwen/Qwen3.8-Flash-Next card + the qwen.ai blog): the\n // Qwen4-underpinning hybrid (QSA, n-gram embedding; 125B with 6B\n // activated), native vision encoder, 262,144 context natively\n // extensible to 1M. Thinking control identical to the 3.8 generation:\n // enable_thinking toggle plus reasoning_effort xhigh (default) /\n // medium / low. Longest pattern, so it wins for -flash-next ids.\n patterns: ['qwen3.8-flash-next'],\n efforts: { off: null, low: 'low', medium: 'medium', xhigh: 'xhigh' },\n defaultEffort: 'xhigh',\n compat: { thinkingFormat: 'qwen', supportsReasoningEffort: true },\n input: ['text', 'image'],\n contextWindow: 262_144,\n note: 'Qwen3.8-Flash-Next\uFF08125B-A6B \u5B9E\u9A8C\u67B6\u6784\uFF0CQwen4 \u524D\u8EAB\uFF09\uFF1A\u5B98\u65B9 reasoning_effort \u6863\u4F4D XHigh(\u9ED8\u8BA4) / Medium / Low + enable_thinking \u5F00\u5173\uFF1B\u539F\u751F\u89C6\u89C9\uFF08Vision Encoder\uFF09\u3002262,144 \u539F\u751F\u4E0A\u4E0B\u6587\u3001\u53EF\u6269\u81F3 1M\u3002\u6765\u6E90\uFF1AHF \u6A21\u578B\u5361\u4E0E qwen.ai \u5B98\u65B9\u535A\u5BA2\u3002',\n },\n {\n id: 'qwen',\n patterns: ['qwen', 'qwq'],\n // DashScope takes NO reasoning_effort: thinking is the enable_thinking\n // boolean (plus thinking_budget) -- pi-ai's 'qwen' format dispatches\n // exactly that switch, so the ladder is honestly open/close with one\n // nominal thinking level. QwQ is think-always; clearing the off level\n // there is one click. Commercial DashScope defaults enable_thinking to\n // TRUE (open-weight serving defaults to false) -- the on state is High.\n efforts: { off: null, high: 'high' },\n defaultEffort: 'high',\n compat: { thinkingFormat: 'qwen' },\n input: ['text'],\n contextWindow: 1_000_000,\n maxTokens: 65_536,\n note: '\u901A\u4E49\u5343\u95EE\uFF1Aenable_thinking \u5F00\u5173\uFF08\u65E0 effort \u6863\uFF09\uFF0C\u5F00=High\uFF1B\u73B0\u5F79\u65D7\u8230\u4E3A qwen3.8 \u7CFB\uFF081M \u6863\u4E0A\u4E0B\u6587\uFF0C\u89C1 qwen-3-8 \u6761\u76EE\uFF09\u30023.6/3.7 \u4EE3\u7684 Plus/Flash \u4EA6\u9ED8\u8BA4\u591A\u6A21\u6001\uFF08\u56FE\u7247/\u89C6\u9891\uFF09\uFF0C\u5982\u63A5\u5165\u8BF7\u6309\u9700\u52FE\u9009\u56FE\u7247\uFF1B\u89C6\u89C9\u7EBF\u89C1 qwen-vision \u6761\u76EE\u3002',\n },\n {\n id: 'glm-vision',\n // Zhipu's vision lines: glm-4v / glm-4.6v / glm-4.5v / glm-5v. Longer\n // than the plain 'glm' patterns, so they win for those ids.\n // 'glm-4-6v' (not 'glm-46v'): normalization folds 'glm-4.6v' to\n // 'glm 4 6v', so the pattern must carry the same inner separator; the\n // same fold gives 'glm-4.5v' -> 'glm 4 5v'.\n patterns: ['glm-4v', 'glm-4-6v', 'glm-4-5v', 'glm-5v'],\n efforts: { off: null, high: 'high' },\n // GLM-4.5V is forced-thinking and the 4.x line defaults to enabled\n // (docs.bigmodel.cn thinking page) -- the on state is High.\n defaultEffort: 'high',\n compat: { thinkingFormat: 'zai' },\n input: ['text', 'image'],\n contextWindow: 131_072,\n maxTokens: 32_768,\n note: '\u667A\u8C31\u89C6\u89C9\u7EBF\uFF08GLM-4V/4.5V/4.6V/5V\uFF09\uFF1Athinking \u5F00\u5173\uFF08\u5F00=High\uFF09\uFF0C\u6536\u56FE\u3002GLM-4.5V \u4E3A\u5F3A\u5236\u601D\u8003\uFF08\u4F20 disabled \u62A5\u9519\uFF0C\u8BF7\u624B\u52A8\u5220 Off \u6863\uFF09\u3002',\n },\n {\n id: 'glm-5-3-flash',\n // Official model page (docs.bigmodel.cn/cn/guide/models/vlm/glm-5.3-flash,\n // page dated 2026-08-28): input modalities \"\u89C6\u9891\u3001\u56FE\u50CF\u3001\u6587\u672C\u3001\u6587\u4EF6\", 1M\n // context / 128K max output, and \"thinking.type \u4EC5\u652F\u6301 enabled\" \u2014 forced\n // thinking, no off switch. \"\u6587\u672C\u53C2\u6570\u4E0E GLM-5.3 \u4FDD\u6301\u4E00\u81F4\" gives the flash\n // variant the 5.3 ladder (low/high/max). Native multimodal (320B), which\n // the text-only glm-5.3 entry must NOT claim \u2014 hence this separate entry;\n // the longer pattern wins over plain 'glm-5.3'.\n patterns: ['glm-5.3-flash'],\n efforts: { low: 'low', high: 'high', max: 'max' },\n defaultEffort: 'max',\n compat: { thinkingFormat: 'zai', supportsReasoningEffort: true },\n input: ['text', 'image'],\n contextWindow: 1_048_576,\n maxTokens: 131_072,\n note: 'GLM-5.3-Flash\uFF08320B\uFF0C\u5B98\u65B9\u6587\u6863 vlm \u5206\u7C7B\uFF09\uFF1A\u5F3A\u5236\u601D\u8003\uFF08thinking.type \u4EC5 enabled\uFF0C\u4E0D\u652F\u6301\u5173\u95ED\uFF09\uFF0C\u6587\u672C\u53C2\u6570\u4E0E GLM-5.3 \u4E00\u81F4\u2014\u2014\u6863\u4F4D Low / High / Max\u3002\u8F93\u5165\u6A21\u6001\uFF1A\u89C6\u9891\u3001\u56FE\u50CF\u3001\u6587\u672C\u3001\u6587\u4EF6\uFF08\u89C6\u9891/\u6587\u4EF6\u672A\u5165\u6838\u5FC3\u8BCD\u8868\uFF0C\u56FE\u7247\u53EF\u52FE\uFF09\u3002\u5B98\u65B9 1M \u4E0A\u4E0B\u6587 / 128K \u6700\u5927\u8F93\u51FA\u3002\u6765\u6E90\uFF1Adocs.bigmodel.cn \u6A21\u578B\u9875\u3002',\n },\n {\n id: 'glm-5-3',\n patterns: ['glm-5.3'],\n // glm-5.3 accepts exactly max/high/low; anything else (including the\n // 5.2 ladder's minimal/none) errors, and thinking cannot be disabled.\n // The API reference names reasoning_effort's default as max.\n efforts: { low: 'low', high: 'high', max: 'max' },\n defaultEffort: 'max',\n compat: { thinkingFormat: 'zai', supportsReasoningEffort: true },\n input: ['text'],\n contextWindow: 1_048_576,\n maxTokens: 131_072,\n note: 'GLM-5.3 \u6863\u4F4D\uFF1ALow / High / Max\uFF08\u5F3A\u5236\u601D\u8003\uFF0C\u5176\u4F59\u503C\u62A5\u9519\uFF09\u3002\u5B98\u65B9\u5BB9\u91CF 1M / 128K\u3002',\n },\n {\n id: 'glm-5-2',\n patterns: ['glm-5.2'],\n // glm-5.2 takes the widest ladder in the wild: none/minimal/low/medium/\n // high/xhigh/max (default max). The zai format arms thinking:disabled\n // for off and sends the effort for the rest.\n efforts: { off: 'none', minimal: 'minimal', low: 'low', medium: 'medium', high: 'high', xhigh: 'xhigh', max: 'max' },\n defaultEffort: 'max',\n compat: { thinkingFormat: 'zai', supportsReasoningEffort: true },\n input: ['text'],\n contextWindow: 1_048_576,\n maxTokens: 131_072,\n // Official capability page: none/minimal stop thinking, low/medium map\n // to high, xhigh maps to max -- all seven spellings are accepted.\n note: 'GLM-5.2 \u6863\u4F4D\uFF1ANone / Minimal / Low / Medium / High / XHigh / Max\uFF08\u5B98\u65B9\u6620\u5C04\uFF1ALow\u00B7Medium\u2192High\u3001XHigh\u2192Max\u3001None\u00B7Minimal=\u505C\u6B62\u601D\u8003\uFF09\u3002\u89C6\u89C9\u7EBF\u89C1 glm-vision \u6761\u76EE\u3002',\n },\n {\n id: 'glm',\n patterns: ['glm', 'zhipu', 'chatglm'],\n // GLM 4.x: thinking.type enabled/disabled only, no effort ladder --\n // the zai format sends exactly that switch (and no effort value,\n // because supportsReasoningEffort is not declared). GLM-4.5/4.6\n // default to enabled (hybrid reasoning: the model decides per\n // request) -- the on state is High.\n efforts: { off: null, high: 'high' },\n defaultEffort: 'high',\n compat: { thinkingFormat: 'zai' },\n input: ['text'],\n note: 'GLM \u901A\u7528\uFF1Athinking \u5F00\u5173\uFF08\u65E0 effort \u6863\uFF09\uFF0C\u5F00=High\uFF1Beffort \u9636\u68AF\u4EC5 GLM-5.2+ \u652F\u6301\uFF08\u89C1\u4E0A\u4E24\u6761\u76EE\uFF09\u3002\u6CE8\u610F GLM-4.7/GLM-4.5V \u4E3A\u5F3A\u5236\u601D\u8003\uFF0C\u4F20 disabled \u4F1A\u62A5\u9519\uFF08\u8BF7\u624B\u52A8\u5220 Off \u6863\uFF09\u3002\u89C6\u89C9\u7EBF\u89C1 glm-vision \u6761\u76EE\u3002',\n },\n {\n id: 'kimi-k3',\n patterns: ['kimi-k3'],\n // kimi-k3: top-level reasoning_effort low/high/max (default max),\n // always thinking -- the thinking object must not be sent at all.\n efforts: { low: 'low', high: 'high', max: 'max' },\n defaultEffort: 'max',\n compat: { thinkingFormat: 'openai', supportsReasoningEffort: true },\n input: ['text', 'image'],\n contextWindow: 1_048_576,\n note: 'Kimi K3 \u6863\u4F4D\uFF1ALow / High / Max(\u9ED8\u8BA4 Max)\uFF0C\u8D70\u9876\u5C42 reasoning_effort\uFF1B\u59CB\u7EC8\u63A8\u7406\u3001\u52FF\u4F20 thinking \u5BF9\u8C61\u3002\u539F\u751F\u89C6\u89C9\u7406\u89E3\uFF0C1M \u4E0A\u4E0B\u6587\uFF08\u6700\u5927\u8F93\u51FA\u5B98\u65B9\u672A\u5355\u72EC\u5217\uFF0C\u4E0D\u63D0\u4F9B\uFF09\u3002',\n },\n {\n id: 'kimi-k2-vision',\n // K2.5/K2.6 are multimodal thinking models with a toggleable\n // thinking.type switch (official use-thinking-models table); K2.5 was\n // re-verified as MULTIMODAL on 2026-08-24 (the old \"text-only\" note was\n // wrong). Longer patterns beat the plain 'kimi' stem below.\n patterns: ['kimi-k2.6', 'kimi-k2.5'],\n efforts: { off: null, high: 'high' },\n defaultEffort: 'high',\n compat: { thinkingFormat: 'deepseek' },\n input: ['text', 'image'],\n contextWindow: 262_144,\n note: 'Kimi K2.5/K2.6 \u89C6\u89C9\u4EE3\uFF1Athinking.type \u5F00\u5173\uFF08\u9ED8\u8BA4\u5F00\u3001\u53EF\u5173\uFF09\uFF0C\u5F00=High\uFF1B\u5E26\u89C6\u89C9\uFF0C256K\u3002K2.7 Code \u59CB\u7EC8\u601D\u8003\uFF0C\u89C1\u5355\u72EC\u6761\u76EE\u3002',\n },\n {\n id: 'kimi-k27-code',\n // K2.7 Code (and its highspeed twin) ALWAYS think: thinking.type only\n // accepts \"enabled\", sending \"disabled\" errors -- so no Off level.\n patterns: ['kimi-k2.7'],\n efforts: { high: 'high' },\n defaultEffort: 'high',\n compat: { thinkingFormat: 'deepseek' },\n input: ['text', 'image'],\n contextWindow: 262_144,\n note: 'Kimi K2.7 Code\uFF08\u542B\u9AD8\u901F\u7248\uFF09\uFF1A\u59CB\u7EC8\u601D\u8003\u2014\u2014thinking.type \u4EC5\u63A5\u53D7 enabled\uFF08\u4F20 disabled \u62A5\u9519\uFF09\uFF0C\u65E0 Off \u6863\uFF1B\u5E26\u89C6\u89C9\uFF0C256K\u3002',\n },\n {\n id: 'kimi-moonshot-v1-vision',\n // Legacy Moonshot V1 vision variants (official model list): plain\n // generation models with no thinking control, but they DO accept images\n // -- the generic 'moonshot' pattern must not declare text-only for them.\n patterns: ['moonshot-v1-8k-vision', 'moonshot-v1-32k-vision', 'moonshot-v1-128k-vision'],\n efforts: false,\n input: ['text', 'image'],\n note: 'Moonshot V1 \u89C6\u89C9\u65E7\u4EE3\uFF088k/32k/128k \u5404\u4E00\uFF09\uFF1A\u65E0\u601D\u8003\u63A7\u4EF6\uFF08\u751F\u6210\u6A21\u578B\uFF09\u3001\u652F\u6301\u56FE\u7247\u8F93\u5165\uFF1B\u8BE5\u7EBF\u5DF2\u505C\u6B62\u5BF9\u65B0\u7528\u6237\u5F00\u653E\uFF082026-08-31 \u5168\u91CF\u4E0B\u7EBF\uFF0C\u7F51\u5173\u6B8B\u7559\u4ECD\u53EF\u547D\u4E2D\uFF09\u3002',\n },\n {\n id: 'kimi',\n // k2.5/2.6 use the DeepSeek-shaped thinking.type enabled/disabled\n // switch, which the 'deepseek' format dispatches; the old k2 preview\n // ids and moonshot-v1 names are retired upstream (2026-05/08) but live\n // on gateways. Effort ladders are not part of their contract.\n patterns: ['kimi', 'moonshot'],\n efforts: { off: null, high: 'high' },\n compat: { thinkingFormat: 'deepseek' },\n input: ['text'],\n contextWindow: 262_144,\n note: 'Kimi \u901A\u7528\uFF1Athinking \u5F00\u5173\uFF08\u65E0 effort \u6863\uFF09\uFF0C\u5F00=High\u3002k2 \u7CFB\u5217 2026-05-25 \u4E0B\u7EBF\u3001kimi-latest 2026-01-28 \u4E0B\u7EBF\u3001moonshot-v1 \u7CFB 2026-08-31 \u5168\u91CF\u4E0B\u7EBF\uFF08\u7F51\u5173\u6B8B\u7559\u4ECD\u53EF\u547D\u4E2D\uFF1Bmoonshot-v1 \u672C\u8EAB\u975E\u601D\u8003\u6A21\u578B\uFF09\u3002\u89C6\u89C9\u4EE3\u4E0E K2.7 Code \u89C1\u5355\u72EC\u6761\u76EE\u3002',\n },\n {\n id: 'hunyuan-hy3',\n // Open-weight contract (Tencent-Hunyuan/Hy3 README): reasoning_effort\n // travels inside chat_template_kwargs as \"no_think\" (default) / \"low\" /\n // \"high\"; the same README's spec table states a 256K context length.\n patterns: ['hy3'],\n efforts: { low: 'low', high: 'high' },\n compat: { thinkingFormat: 'openai', supportsReasoningEffort: true },\n input: ['text'],\n contextWindow: 262_144,\n note: '\u6DF7\u5143 hy3\uFF1A\u5F00\u6E90\u5951\u7EA6\u7ECF chat_template_kwargs.reasoning_effort = no_think(\u9ED8\u8BA4)/low/high\uFF1B\u5B98\u65B9\u6A21\u578B\u5361 256K \u4E0A\u4E0B\u6587\uFF08295B MoE\uFF0C2026 \u5F00\u6E90\uFF09\u3002',\n },\n {\n id: 'hunyuan-hy4',\n // Open-weight contract (Tencent-Hunyuan/Hy4-preview README): reasoning\n // defaults to \"high\" (deep chain-of-thought) and is disabled with\n // extra_body={\"chat_template_kwargs\": {\"reasoning_effort\": \"no_think\"}}\n // \u2014 the same chat-template channel as hy3, with the default flipped to\n // high. The spec table states a 1M context length; the model is a\n // 770B-A49B MoE with Gated DSA attention. The README documents no levels\n // beyond high/no_think, so a low rung is NOT declared without evidence.\n patterns: ['hy4-preview', 'hy-4-preview'],\n efforts: { off: 'no_think', high: 'high' },\n defaultEffort: 'high',\n compat: { thinkingFormat: 'openai', supportsReasoningEffort: true },\n contextWindow: 1_000_000,\n note: '\u6DF7\u5143 Hy4 preview\uFF1A\u5B98\u65B9 README\u2014\u2014reasoning \u9ED8\u8BA4 high\uFF08\u6DF1\u5EA6\u601D\u8003\uFF09\uFF0C\u5173\u95ED\u7ECF chat_template_kwargs.reasoning_effort=no_think\uFF1B\u5B98\u65B9\u89C4\u683C\u8868 1M \u4E0A\u4E0B\u6587\uFF08770B-A49B MoE\uFF0CGated DSA\uFF09\u3002low \u6863\u5B98\u65B9\u672A\u5217\uFF0C\u5982\u6709\u8BF7\u624B\u8C03\uFF1B\u89C6\u89C9\u672A\u58F0\u660E\uFF0C\u6309\u9700\u624B\u52FE\u3002\u6765\u6E90\uFF1ATencent-Hunyuan/Hy4-preview \u5B98\u65B9 README\u3002',\n },\n {\n id: 'step-5-preview',\n // StepFun's official model is 'step-5-preview' (there is no bare\n // 'step-5'), carrying the same three-step reasoning_effort ladder as the\n // 3.x line with no way to close thinking -- hence no `off`. The official\n // page calls medium the \"default recommendation\". 1M context, 64K max\n // output, native image + video input.\n patterns: ['step-5'],\n efforts: { low: 'low', medium: 'medium', high: 'high' },\n defaultEffort: 'medium',\n compat: { thinkingFormat: 'openai', supportsReasoningEffort: true },\n input: ['text', 'image'],\n contextWindow: 1_000_000,\n maxTokens: 65_536,\n note: '\u9636\u8DC3 Step-5-Preview\uFF08\u5B98\u65B9 id \u5373 step-5-preview\uFF0C\u65E0\u88F8 step-5\uFF1Bpattern \u53D6\u5BB6\u65CF\u4E3B\u5E72\u4EE5\u517C\u5BB9\u7F51\u5173\u5199\u6CD5\uFF09\uFF1A\u6863\u4F4D Low / Medium(\u5B98\u65B9\u6807\"\u9ED8\u8BA4\u63A8\u8350\") / High\uFF0C\u601D\u8003\u4E0D\u53EF\u5173\u95ED\uFF1B\u539F\u751F\u56FE\u7247 + \u89C6\u9891\u8F93\u5165\uFF1B1M \u4E0A\u4E0B\u6587\u300164K \u6700\u5927\u8F93\u51FA\uFF08\u5B98\u65B9\u53E6\u6CE8 max_tokens \u9ED8\u8BA4 INF\u3001\u4E0E 64K \u4E0A\u9650\u5E76\u5B58\uFF0C\u4EE5\u7AEF\u70B9\u5B9E\u6D4B\u4E3A\u51C6\uFF09\u3002',\n },\n {\n id: 'step-3-7',\n // StepFun step-3.7 is the vision-capable generation; 3.5 stayed\n // text-only on the official serving plan.\n patterns: ['step-3.7', 'step-3.6'],\n efforts: { low: 'low', medium: 'medium', high: 'high' },\n defaultEffort: 'medium',\n compat: { thinkingFormat: 'openai', supportsReasoningEffort: true },\n input: ['text', 'image'],\n contextWindow: 262_144,\n note: '\u9636\u8DC3 Step-3.6/3.7 \u6863\u4F4D\uFF1ALow / Medium(\u9ED8\u8BA4\u63A8\u8350) / High\uFF0C\u539F\u751F\u56FE\u7247+\u89C6\u9891\u7406\u89E3\u3002\u4E0A\u4E0B\u6587\u4E3A\u8F93\u5165+\u8F93\u51FA\u603B\u548C\u4E0A\u9650\u3002',\n },\n {\n id: 'step-3-5',\n // step-3.5-flash (official listing): only low/high, text-only.\n patterns: ['step-3.5'],\n efforts: { low: 'low', high: 'high' },\n compat: { thinkingFormat: 'openai', supportsReasoningEffort: true },\n input: ['text'],\n contextWindow: 262_144,\n note: '\u9636\u8DC3 Step-3.5 Flash \u6863\u4F4D\uFF1ALow / High\uFF08\u7EAF\u6587\u672C\u63A8\u7406\u65D7\u8230\uFF09\u3002\u4E0A\u4E0B\u6587\u4E3A\u8F93\u5165+\u8F93\u51FA\u603B\u548C\u4E0A\u9650\u3002',\n },\n {\n id: 'step',\n // StepFun step-3.x: reasoning_effort low/medium/high (default medium);\n // thinking cannot be turned off, only tuned.\n patterns: ['step-3', 'step-2'],\n efforts: { low: 'low', medium: 'medium', high: 'high' },\n defaultEffort: 'medium',\n compat: { thinkingFormat: 'openai', supportsReasoningEffort: true },\n input: ['text'],\n note: '\u9636\u8DC3 Step \u6863\u4F4D\uFF1ALow / Medium / High\uFF08\u9ED8\u8BA4 Medium\uFF0C\u4E0D\u53EF\u5173\u95ED\uFF09\u30023.6/3.7 \u89C6\u89C9\u4EE3\u89C1\u5355\u72EC\u6761\u76EE\u3002',\n },\n {\n id: 'doubao',\n // Volcengine Ark: officially documented is the thinking.type\n // enabled/disabled/auto switch; the reasoning_effort ladder on\n // seed-2.x has community evidence (chatbox/compshare) but no first-\n // party doc yet -- kept as the conventional ladder, verify per gateway.\n // 'doubao' already covers every doubao-* spelling; the bare 'seed' token\n // (boundary-checked) catches seed-first ids some gateways serve. The\n // seed generations are vision-capable; doubao-1.5-pro stays text-only.\n patterns: ['doubao', 'seed'],\n efforts: { off: null, low: 'low', medium: 'medium', high: 'high' },\n compat: { thinkingFormat: 'openai', supportsReasoningEffort: true },\n input: ['text', 'image'],\n note: '\u8C46\u5305\u6863\u4F4D\uFF1AOff / Low / Medium / High\u2014\u2014effort \u9636\u68AF\u4ECD\u662F\u793E\u533A\u8BC1\u636E\u3001\u5B98\u65B9 Ark \u6587\u6863\u660E\u5217\u7684\u4E3A thinking.type \u5F00\u5173\uFF082026-08-24 \u590D\u6838\u4ECD\u672A\u89C1\u5230 effort \u5B98\u65B9\u660E\u6587\uFF09\u3002seed \u4EE3\u6536\u56FE\uFF081.5-pro \u4F8B\u5916\uFF09\u3002',\n },\n {\n id: 'minimax-m3',\n // Official M3 README: a thinking parameter with enabled / adaptive /\n // disabled -- NO reasoning_effort ladder. That is exactly the\n // deepseek-shaped toggle, so the kimi-style declaration fits; \"adaptive\"\n // is not expressible in the level vocabulary and defaults apply.\n patterns: ['minimax-m3'],\n efforts: { off: null, high: 'high' },\n compat: { thinkingFormat: 'deepseek' },\n input: ['text', 'image'],\n contextWindow: 1_048_576,\n note: 'MiniMax-M3\uFF1A\u5B98\u65B9 thinking \u53C2\u6570 enabled/adaptive/disabled\uFF08\u65E0 effort \u6863\uFF09\uFF0C\u5F00=High\u3001\u5173=disabled\uFF1B\u539F\u751F\u591A\u6A21\u6001\uFF08\u56FE/\u89C6\u9891\uFF0C\u6838\u5FC3\u8BCD\u8868\u4EC5\u542B\u56FE\uFF09\uFF0C1M \u4E0A\u4E0B\u6587\u3002',\n },\n {\n id: 'mimo-v2-6',\n // Xiaomi MiMo v2.6 (and the v2.5 generation it supersedes) takes a required\n // thinking.type toggle (enabled/disabled, default enabled) plus a required\n // reasoning.effort. The official page lists the accepted effort values as\n // none/minimal/low/medium/high/xhigh/max/ultra and normalizes minimal to\n // low and xhigh/max/ultra to high -- but says outright that reasoning\n // strength is not differentiated yet, so the ladder below is what the\n // endpoint ACCEPTS, not a set of levels that behave differently today.\n // xhigh/max are deliberately absent: the endpoint folds them into high.\n // One entry covers both generations: the same models are documented under\n // one contract, and the family's only text-only member (v2.5-pro) keys its\n // own entry with a strictly longer pattern.\n patterns: ['mimo-v2.6', 'mimo-v2.5'],\n efforts: { off: 'none', low: 'low', medium: 'medium', high: 'high' },\n compat: { thinkingFormat: 'openai', supportsReasoningEffort: true },\n input: ['text', 'image'],\n contextWindow: 1_048_576,\n maxTokens: 131_072,\n note: '\u5C0F\u7C73 MiMo v2.6 \u7CFB\u5217\uFF08mimo-v2.6-pro / -flash / -pro-ultraspeed\uFF1B1M \u4E0A\u4E0B\u6587 / 128K \u6700\u5927\u8F93\u51FA\u3001\u539F\u751F\u5168\u6A21\u6001\uFF09\u4E0E\u5176\u524D\u4EE3 mimo-v2.5\u3002\u5B98\u65B9\u6587\u6863\uFF1Athinking.type\uFF08enabled/disabled\uFF0C\u9ED8\u8BA4 enabled\uFF09+ reasoning.effort\uFF08none \u5173\u95ED\uFF1B\u5176\u4F59\u5408\u6CD5\u503C\u5747\u5F00\u542F\uFF0C\u4E14**\u73B0\u9636\u6BB5\u6682\u672A\u533A\u5206\u63A8\u7406\u5F3A\u5EA6**\u2014\u2014minimal \u5F52\u4E00\u4E3A low\u3001xhigh/max/ultra \u5F52\u4E00\u4E3A high\uFF09\uFF0C\u56E0\u6B64\u8FD9\u91CC\u58F0\u660E\u7684\u662F\u7AEF\u70B9**\u63A5\u53D7**\u7684\u6863\u4F4D Off / Low / Medium / High\uFF08xhigh\u3001max \u4E0D\u58F0\u660E\uFF0C\u7AEF\u70B9\u53EA\u4F1A\u6298\u53E0\u4E3A high\uFF09\u3002\u601D\u8003\u6A21\u5F0F\u4E0B temperature / top_p \u4E0D\u53EF\u81EA\u5B9A\u4E49\uFF08\u5F3A\u5236 1.0 / 0.95\uFF09\uFF1B\u5E26\u5DE5\u5177\u8C03\u7528\u7684\u5386\u53F2\u8F6E\u5FC5\u987B\u5B8C\u6574\u56DE\u4F20 reasoning_content\uFF0C\u5426\u5219 400\u3002mimo-v2.5 \u4E0E v2.5-pro \u5B98\u65B9\u5B9A\u4E8E 2026-10-21 \u4E0B\u7EBF\u3002',\n },\n {\n id: 'mimo-v2-5-pro',\n // The v2.5 flagship is the family's only text-only member -- the official\n // capability table lists no multimodal understanding for it (models.dev\n // agrees, attachment=false), while every v2.6 model and mimo-v2.5 do.\n // Strictly longer pattern than the family entry's 'mimo-v2.5', so the\n // longest-hit rule routes it here.\n patterns: ['mimo-v2.5-pro'],\n efforts: { off: 'none', low: 'low', medium: 'medium', high: 'high' },\n compat: { thinkingFormat: 'openai', supportsReasoningEffort: true },\n input: ['text'],\n contextWindow: 1_048_576,\n maxTokens: 131_072,\n note: '\u5C0F\u7C73 MiMo v2.5-Pro\uFF1A\u8BE5\u5BB6\u65CF\u552F\u4E00\u7684**\u7EAF\u6587\u672C**\u6210\u5458\uFF08\u5B98\u65B9\u80FD\u529B\u8868\u672A\u5217\u5168\u6A21\u6001\u7406\u89E3\uFF09\uFF0C1M \u4E0A\u4E0B\u6587 / 128K \u6700\u5927\u8F93\u51FA\uFF0C\u63A8\u7406\u5951\u7EA6\u4E0E v2.6 \u7CFB\u5217\u76F8\u540C\uFF08thinking.type + reasoning.effort\uFF0Cnone \u5173\u95ED\u3001\u5176\u4F59\u6863\u4F4D\u6682\u4E0D\u533A\u5206\u5F3A\u5EA6\uFF09\u3002\u5B98\u65B9\u5B9A\u4E8E 2026-10-21 \u4E0B\u7EBF\u3002',\n },\n {\n id: 'baidu-ernie',\n // Baidu Qianfan's OpenAI-compatible surface accepts no reasoning_effort\n // parameter (the v2 API parameter tables carry none); thinking is a\n // per-variant property: the -Thinking / ERNIE 5.0-Thinking-* family is\n // always-on thinking, the plain ERNIE 4.5/5.0/5.1 generations are not\n // thinking models at all. The official pricing page (2026-08) lists\n // ERNIE 5.1 / 5.0 / 5.0-Thinking-Preview|Latest|Exp / 4.5-Turbo(-VL).\n patterns: ['ernie'],\n efforts: false,\n input: ['text'],\n contextWindow: 131_072,\n note: '\u767E\u5EA6\u5343\u5E06 ERNIE \u7CFB\uFF1A\u5B98\u65B9 OpenAI \u517C\u5BB9\u63A5\u53E3\u65E0 reasoning_effort \u53C2\u6570\u2014\u2014\u601D\u8003\u7531\u6A21\u578B\u53D8\u4F53\u51B3\u5B9A\uFF08-Thinking \u7CFB\u5217\u59CB\u7EC8\u601D\u8003\u3001\u666E\u901A\u7CFB\u5217\u4E0D\u601D\u8003\uFF09\uFF0C\u52FF\u52FE\u601D\u8003\u6863\u3002ERNIE 4.5 Turbo VL \u652F\u6301\u56FE\u7247\uFF0C\u6309\u9700\u624B\u52FE\uFF1B\u53C2\u8003\u5BB9\u91CF\u53D6 Turbo 128K \u6863\u3002',\n },\n]\n\n/**\n * The generic OpenAI-compatible ladder -- the single source for every\n * OpenAI-shaped protocol row below and the fallback when nothing matches.\n */\nexport const GENERIC_OPENAI_EFFORTS: ReasoningEfforts = {\n off: null,\n low: 'low',\n medium: 'medium',\n high: 'high',\n}\n\n/**\n * Level sets keyed by pi-ai's REAL wire protocols -- the only values a\n * route's 'api' may take are 'openai-completions' | 'openai-responses' |\n * 'anthropic-messages' (llm-pi-ai provider.ts PROTOCOLS) -- plus the\n * 'deepseek' URL dialect for routes that name no api but point at DeepSeek's\n * own endpoint, which takes its native off/high/max ladder.\n *\n * 'off: null' is only offered where a no-thinking mode is plausible; the\n * conservative choice elsewhere is to omit it so the picker never promises an\n * Off the endpoint would reject. Exported for the vocabulary grid tests that\n * pin these ladders against pi-ai's resolution rules.\n */\nexport const PROTOCOL_INFERENCE: Readonly<Record<string, ReasoningEfforts>> = {\n 'openai-completions': GENERIC_OPENAI_EFFORTS,\n 'openai-responses': GENERIC_OPENAI_EFFORTS,\n 'anthropic-messages': GENERIC_OPENAI_EFFORTS,\n // The live V4 contract: low/high/max (+ thinking toggle for off, spelled\n // 'none' so an off selection also maps to the official Responses-API value\n // reasoning.effort: none).\n deepseek: { off: 'none', low: 'low', high: 'high', max: 'max' },\n}\n\n/** A best-effort generic declaration when even the protocol is unknown. */\nconst GENERIC_FALLBACK: ReasoningEfforts = { low: 'low', medium: 'medium', high: 'high' }\n\n/** Normalize one route fact for matching/inference. */\nfunction normalize(value: string | undefined): string {\n return (value ?? '').toLowerCase().trim()\n}\n\n/** Whether a character is a lowercase letter or digit (word-boundary test). */\nfunction isAlnum(ch: string | undefined): boolean {\n return ch !== undefined && /[a-z0-9]/.test(ch)\n}\n\n/**\n * Lowercase and collapse every non-alphanumeric run to one space, so id /\n * display-name / pattern separators ('-', '_', '.', spaces) compare equal:\n * pattern 'deepseek-v3' matches display name \"DeepSeek V3\".\n */\nfunction normalizeLoose(value: string): string {\n return value.toLowerCase().trim().replace(/[^a-z0-9]+/g, ' ')\n}\n\n/**\n * Whether the occurrence of a pattern at index 'at' sits on a word boundary\n * in the haystack: neither neighbor may be a letter/digit. Keeps short family\n * tokens from false-hitting ('o1' must hit 'o1 mini' but not 'ko1 pro';\n * 'seed' hits 'doubao seed 1 6' but not 'seedling').\n */\nfunction onBoundary(haystack: string, at: number, length: number): boolean {\n const before = at === 0 ? undefined : haystack[at - 1]\n const after = haystack[at + length]\n return !isAlnum(before) && !isAlnum(after)\n}\n\n/** Match the knowledge base: first match wins, longest boundary hit wins. */\nexport function matchKnowledgeBase(modelId: string, displayName?: string): KnowledgeEntry | undefined {\n const haystack = normalizeLoose(modelId) + ' ' + normalizeLoose(displayName ?? '')\n let best: { entry: KnowledgeEntry; length: number } | undefined\n for (const entry of KNOWLEDGE_BASE) {\n for (const pattern of entry.patterns) {\n const needle = normalizeLoose(pattern)\n let at = haystack.indexOf(needle)\n while (at >= 0) {\n if (onBoundary(haystack, at, needle.length)) {\n if (best === undefined || needle.length > best.length) {\n best = { entry, length: needle.length }\n }\n break\n }\n at = haystack.indexOf(needle, at + 1)\n }\n }\n }\n return best?.entry\n}\n\n/**\n * Infer which PROTOCOL_INFERENCE key applies to a route. A configured 'api'\n * is already a pi-ai protocol name and wins as-is; otherwise the endpoint's\n * HOST names the dialect -- matched on the registrable domain so an aggregator\n * path like https://gw.example.com/deepseek/v1 stays generic -- and anything\n * unrecognized resolves to the OpenAI-compatible ladder (the overwhelming\n * majority of gateways).\n */\nconst NATIVE_DIALECT_DOMAINS: Readonly<Record<string, string>> = {\n // api.deepseek.com is the official endpoint (api-docs.deepseek.com). The\n // 'deepseek.ai' form was dropped: it resolves to a Vercel-hosted site\n // (76.76.21.21), not DeepSeek infrastructure, so nothing warrants assuming\n // the native dialect for it.\n 'deepseek.com': 'deepseek',\n 'anthropic.com': 'anthropic-messages',\n}\n\nexport function inferProtocol(route: RouteFacts): string {\n const api = normalize(route.api)\n if (api.length > 0) return api\n const baseURL = route.baseURL\n if (baseURL !== undefined && baseURL.length > 0) {\n try {\n const host = new URL(baseURL).hostname.toLowerCase()\n const parts = host.split('.')\n if (parts.length >= 2) {\n const dialect = NATIVE_DIALECT_DOMAINS[parts.slice(-2).join('.')]\n if (dialect !== undefined) return dialect\n }\n } catch {\n // Malformed URL: fall through to the generic ladder.\n }\n }\n // Former 'gemini' guessing removed: pi-ai has no gemini protocol, and\n // Gemini gateways speak the OpenAI-compatible dialect.\n return 'openai-completions'\n}\n\n/**\n * The one wire protocol whose compat gate offers thinkingFormat /\n * supportsReasoningEffort (llm-pi-ai COMPLETIONS_COMPAT_GATE). pi-ai refuses\n * a model-level compat field its resolved protocol does not take\n * (assertServiceable throws at the write), so compat suggestions are gated to\n * this protocol only -- with one exception: the anthropic-messages gate\n * offers forceAdaptiveThinking, which is what makes declared efforts reach\n * the wire as output_config.effort (see {@link KnowledgeEntry.anthropicAdaptive}).\n */\nconst COMPAT_CAPABLE_PROTOCOL = 'openai-completions'\nconst ANTHROPIC_PROTOCOL = 'anthropic-messages'\n\n/** Whether a baseURL names a self-hosted endpoint (loopback, private LAN, .local, custom port). */\nexport function isSelfHostedEndpoint(baseURL: string | undefined): boolean {\n if (baseURL === undefined || baseURL.length === 0) return false\n let host = ''\n try {\n host = new URL(baseURL).hostname.toLowerCase()\n } catch {\n return false\n }\n if (host === 'localhost' || host === '::1' || host.endsWith('.local') || host.endsWith('.internal')) return true\n if (/^(127\\.|10\\.|192\\.168\\.)/.test(host)) return true\n if (/^172\\.(1[6-9]|2[0-9]|3[01])\\./.test(host)) return true\n return host.includes(':')\n}\n\n/** Drop catalog-withheld keys pi-ai never accepts from a profile (defensive). */\nexport function sanitizeCompatForProtocol(compat: CompatSuggestion, api: string): CompatSuggestion | undefined {\n const norm = normalize(api)\n const copy: Record<string, unknown> = { ...compat }\n delete copy['supportsMidConvoEffort']\n delete copy['allowedFallbackModels']\n if (norm === ANTHROPIC_PROTOCOL) {\n for (const key of ['thinkingFormat', 'supportsReasoningEffort', 'thinkingTokenBudgetField', 'supportsThinkingTokenBudget', 'vllmPriority', 'supportsMaxOutputTokens'] as const) delete copy[key]\n if (copy['forceAdaptiveThinking'] === undefined) return undefined\n return { forceAdaptiveThinking: copy['forceAdaptiveThinking'] as boolean }\n }\n if (norm === 'openai-responses') {\n for (const key of ['thinkingFormat', 'supportsReasoningEffort', 'thinkingTokenBudgetField', 'supportsThinkingTokenBudget', 'vllmPriority'] as const) delete copy[key]\n if (copy['supportsMaxOutputTokens'] === undefined) return undefined\n return { supportsMaxOutputTokens: copy['supportsMaxOutputTokens'] as boolean }\n }\n if (norm !== COMPAT_CAPABLE_PROTOCOL) return undefined\n delete copy['forceAdaptiveThinking']\n delete copy['supportsMaxOutputTokens']\n return Object.keys(copy).length === 0 ? undefined : (copy as CompatSuggestion)\n}\n\n/** Gate a compat block against the route's real protocol. */\nfunction compatForRoute(entry: KnowledgeEntry, route: RouteFacts): CompatSuggestion | undefined {\n const api = normalize(route.api)\n if (api === COMPAT_CAPABLE_PROTOCOL) {\n let compat = entry.compat\n if (compat !== undefined) compat = sanitizeCompatForProtocol(compat, api) ?? undefined\n if (compat === undefined && !isSelfHostedEndpoint(route.baseURL)) return undefined\n if (compat === undefined) return { thinkingTokenBudgetField: 'thinking_token_budget' }\n if (compat.thinkingTokenBudgetField === undefined && compat.supportsThinkingTokenBudget !== true && isSelfHostedEndpoint(route.baseURL)) {\n return { ...compat, thinkingTokenBudgetField: 'thinking_token_budget' }\n }\n return compat\n }\n if (api === ANTHROPIC_PROTOCOL && entry.anthropicAdaptive === true) {\n return { forceAdaptiveThinking: true }\n }\n return undefined\n}\n\n/**\n * Official endpoint roots where pi-ai may send role:developer, so no pin is\n * needed. Matching is a DNS-suffix match, so multi-level roots (e.g.\n * openai.azure.com) work while a relay merely hosted on the same cloud\n * (e.g. *.cloudapp.azure.com) still counts as self-hosted.\n *\n * Deliberately fail-safe: hosts outside this set get the pin. `system` is\n * accepted everywhere, `developer` is not, so an unknown host keeps the\n * universally accepted role -- the pin is harmless on official endpoints\n * too. Only add a root after verifying its endpoints accept\n * role:developer (vendor docs or a wire capture); when in doubt, leave it\n * out. The pi-ai-parity entries change no bytes (pi-ai already detects\n * those hosts as nonstandard, i.e. supportsDeveloperRole false); they are\n * listed so the two detectors cannot drift apart silently.\n */\nconst OFFICIAL_RELAY_DOMAINS: readonly string[] = [\n // First-party OpenAI-compatible endpoints (developer accepted).\n 'openai.com',\n 'openai.azure.com',\n 'deepseek.com',\n 'openrouter.ai',\n 'z.ai',\n 'bigmodel.cn',\n 'moonshot.ai',\n 'moonshot.cn',\n 'aliyuncs.com',\n 'anthropic.com',\n 'x.ai',\n 'together.ai',\n 'together.xyz',\n 'nvidia.com',\n 'cerebras.ai',\n 'cloudflare.com',\n // pi-ai-parity: detected nonstandard upstream (pin would be a no-op).\n 'chutes.ai',\n 'opencode.ai',\n 'ant-ling.com',\n]\n\n/**\n * Whether a route is a self-hosted relay whose upstreams cannot be assumed\n * to accept role:developer: openai-completions protocol on a baseURL whose\n * host no official root claims. Absent or malformed URLs answer false --\n * with nothing to judge the host by, pi-ai's detection default stands.\n */\nexport function isSelfHostedRelay(route: RouteFacts): boolean {\n if (normalize(route.api) !== COMPAT_CAPABLE_PROTOCOL) return false\n const baseURL = route.baseURL\n if (baseURL === undefined || baseURL.length === 0) return false\n try {\n const host = new URL(baseURL).hostname.toLowerCase()\n if (!host.includes('.')) return false\n return !OFFICIAL_RELAY_DOMAINS.some((root) => host === root || host.endsWith('.' + root))\n } catch {\n return false\n }\n}\n\n/**\n * Pin the system role on self-hosted relays: merge\n * `supportsDeveloperRole: false` into a compat block that would otherwise\n * let pi-ai rewrite the system prompt to role:developer (issue #2 -- the\n * upstream answers \u89D2\u8272\u4FE1\u606F\u4E0D\u6B63\u786E). An explicitly declared value always\n * wins; non-reasoning suggestions (efforts === false) never carry compat.\n */\nfunction withRolePin(\n compat: CompatSuggestion | undefined,\n route: RouteFacts,\n reasons: boolean,\n): CompatSuggestion | undefined {\n if (compat === undefined || !reasons) return compat\n if (compat.supportsDeveloperRole !== undefined) return compat\n if (!isSelfHostedRelay(route)) return compat\n return { ...compat, supportsDeveloperRole: false }\n}\n\n/** Conservative ladder offered when the endpoint confirms reasoning but nothing names the levels. */\nconst ENDPOINT_CONFIRMED_LADDER: ReasoningEfforts = { off: null, low: 'low', medium: 'medium', high: 'high' }\n\n/**\n * Name-heuristic modality tokens -- the last-resort tier (the practice\n * one-api/new-api bake into code): vision-flavored tokens that appear in\n * vendor ids often enough to suggest image input at LOW confidence. Boundary\n * matching keeps 'vl' from hitting 'eval' or 'svelte'.\n */\nconst VISION_NAME_TOKENS: readonly string[] = [\n 'vl',\n 'vision',\n 'omni',\n '4o',\n 'pixtral',\n 'internvl',\n]\n\n/** Lowest-confidence modality guess from the model id alone, or undefined. */\nexport function inferModalitiesFromName(modelId: string): InputModalities | undefined {\n const haystack = normalizeLoose(modelId)\n for (const token of VISION_NAME_TOKENS) {\n const needle = normalizeLoose(token)\n let at = haystack.indexOf(needle)\n while (at >= 0) {\n if (onBoundary(haystack, at, needle.length)) return ['text', 'image']\n at = haystack.indexOf(needle, at + 1)\n }\n }\n return undefined\n}\n\n/**\n * Intersect a raw listing disclosure with the core vocabulary. Returns\n * undefined when the listing never named a modality field OR named one whose\n * members all fall outside the core vocabulary (an audio-only declaration\n * must NOT read as \"text only\"). A present disclosure always yields at least\n * text-only when image is absent -- so an explicit text-only listing can\n * strip an image claim.\n */\nfunction declaredCoreInput(raw: readonly string[] | undefined): InputModalities | undefined {\n if (raw === undefined) return undefined\n const lowered = raw.map(value => value.toLowerCase())\n if (!lowered.some(value => (INPUT_MODALITIES as readonly string[]).includes(value))) return undefined\n return lowered.includes('image') ? ['text', 'image'] : ['text']\n}\n\n/**\n * Resolve the suggestion for one model on one route, fusing the available\n * signals by confidence:\n *\n * L1 endpoint listing signal (when supplied) -- answers \"does it reason at\n * all\" and, independently, \"what does it accept\": an explicit false\n * wins the effort ladder outright (suggest false, high); a modality\n * disclosure or a context length feeds those parts regardless;\n * L2 knowledge base -- the ONLY source of wire spellings and compat, plus\n * modality/capacity references when the endpoint stays silent;\n * L3 name heuristic -- a low-confidence image guess for vision-flavored\n * ids when both sources above are silent;\n * L4 protocol inference -- level-ladder skeleton when nothing better exists.\n *\n * @param modelId - the model id (or display name) to match.\n * @param route - route facts used when the knowledge base misses; its\n * displayName participates in knowledge-base matching.\n * @param endpoint - optional raw-listing facts for this model (from the\n * host's same-origin probe route); omit when the endpoint was not asked.\n * @returns a suggestion (always derivable -- protocol inference has a fallback).\n */\nexport function suggestEfforts(\n modelId: string,\n route: RouteFacts,\n endpoint?: EndpointFacts,\n): EffortSuggestion {\n const entry = matchKnowledgeBase(modelId, route.displayName)\n\n // ---- Modality + capacity parts (orthogonal to the effort ladder) ----\n let input: InputModalities | undefined\n let inputSource: InputSource | undefined\n let contextWindow: number | undefined\n let maxTokens: number | undefined\n\n if (entry?.input !== undefined) {\n input = entry.input\n inputSource = 'knowledge'\n }\n if (entry?.contextWindow !== undefined) contextWindow = entry.contextWindow\n if (entry?.maxTokens !== undefined) maxTokens = entry.maxTokens\n\n // An endpoint disclosure outranks the knowledge base; a disclosed context\n // length likewise replaces the reference value. Silence changes nothing.\n const listedInput = declaredCoreInput(endpoint?.input)\n if (listedInput !== undefined) {\n input = listedInput\n inputSource = 'endpoint'\n }\n if (endpoint?.contextLength !== undefined && Number.isFinite(endpoint.contextLength) && endpoint.contextLength > 0) {\n contextWindow = endpoint.contextLength\n }\n\n // L3: nothing named the modalities -- fall back to the name heuristic.\n if (input === undefined) {\n const guessed = inferModalitiesFromName(modelId)\n if (guessed !== undefined) {\n input = guessed\n inputSource = 'heuristic'\n }\n }\n\n const modalityParts = {\n ...(input === undefined ? {} : { input }),\n ...(inputSource === undefined ? {} : { inputSource }),\n ...(contextWindow === undefined ? {} : { contextWindow }),\n ...(maxTokens === undefined ? {} : { maxTokens }),\n }\n\n const endpointPart = endpoint === undefined\n ? {}\n : { endpoint: { reasoning: endpoint.reasoning, source: endpoint.source } }\n\n // L1: an explicit \"does not reason\" from the endpoint outranks everything.\n if (endpoint?.reasoning === false) {\n return {\n efforts: false,\n matched: false,\n source: 'endpoint:' + (endpoint.source ?? 'listing'),\n confidence: 'high',\n ...endpointPart,\n ...modalityParts,\n }\n }\n\n if (entry !== undefined) {\n const compat = withRolePin(compatForRoute(entry, route), route, entry.efforts !== false)\n return {\n efforts: entry.efforts,\n // The vendor default rides along only when the suggested ladder\n // actually carries it (a declaration may deliberately drop a level).\n ...(entry.efforts !== false\n && entry.defaultEffort !== undefined\n && entry.efforts[entry.defaultEffort] !== undefined\n ? { defaultEffort: entry.defaultEffort }\n : {}),\n ...(compat === undefined ? {} : { compat }),\n matched: true,\n entryId: entry.id,\n source: entry.id,\n // Knowledge base carries the wire values; an agreeing endpoint signal\n // only reinforces it. A DISAGREEING signal (endpoint says no reasoning)\n // was handled above; unknown changes nothing.\n confidence: 'high',\n ...endpointPart,\n ...modalityParts,\n }\n }\n\n // L2 missed: the ladder comes from protocol inference. An explicit endpoint\n // \"reasons\" upgrades confidence to medium -- support is confirmed, but the\n // level set and spellings are inferred, so the user should double-check.\n const protocol = inferProtocol(route)\n const efforts = PROTOCOL_INFERENCE[protocol] ?? GENERIC_FALLBACK\n const compatBase: CompatSuggestion | undefined = normalize(route.api) === COMPAT_CAPABLE_PROTOCOL\n ? { thinkingFormat: 'openai', supportsReasoningEffort: true }\n : undefined\n const compatWithBudget = compatBase !== undefined && isSelfHostedEndpoint(route.baseURL)\n ? { ...compatBase, thinkingTokenBudgetField: 'thinking_token_budget' as const }\n : compatBase\n const compat = withRolePin(compatWithBudget, route, true)\n if (endpoint?.reasoning === true) {\n return {\n efforts: { ...ENDPOINT_CONFIRMED_LADDER },\n ...(ENDPOINT_CONFIRMED_LADDER['medium'] !== undefined ? { defaultEffort: 'medium' as const } : {}),\n // compat was already gated to the protocol above; no second gate.\n ...(compat === undefined ? {} : { compat }),\n matched: false,\n source: 'endpoint:' + (endpoint.source ?? 'listing'),\n confidence: 'medium',\n ...endpointPart,\n ...modalityParts,\n }\n }\n return {\n efforts,\n // Inferred ladders default to medium (the convention codex/OpenAI set for\n // their own ladders) whenever the inferred set carries it.\n ...(efforts['medium'] !== undefined ? { defaultEffort: 'medium' as const } : {}),\n ...(compat === undefined ? {} : { compat }),\n matched: false,\n source: 'protocol:' + protocol,\n confidence: 'low',\n ...endpointPart,\n ...modalityParts,\n }\n}\n", "/**\n * Default-guard decision: which effort-less calls may take the vendor\n * default instead of the wire's off-equivalent (issue #2).\n *\n * Pi-ai always emits a thinking parameter for reasoning models, so an\n * effort-less call to a forced-thinking ladder (no `off` key) becomes\n * `thinking: {type: disabled}` / `enable_thinking: false` -- a guaranteed\n * 400 on upstreams that cannot switch thinking off. Rewriting exactly that\n * class into the ladder's vendor default produces bytes identical to the\n * user picking the level by hand, a request class that already works.\n *\n * Pure data logic (no harness imports): the host half feeds it the declared\n * ladder, the knowledge-base vendor default, and the route default, and\n * injects the returned level -- or nothing when it answers undefined.\n *\n * @module dsh-model-think-level/guard\n */\n\nimport type { ReasoningEfforts, ThinkingLevel } from './knowledge.js'\n\n/** Inputs to the guard decision, all optional except the declaration. */\nexport interface GuardInput {\n /** The model's declared ladder (`false` = non-reasoning). */\n declared: ReasoningEfforts | false | undefined\n /** The knowledge-base vendor default for the family, when one is known. */\n vendorDefault?: ThinkingLevel\n /** The route profile's configured reasoning default, when one is set. */\n profileDefault?: string\n /** The call's explicit effort, when the caller named one. */\n requested?: string\n}\n\n/**\n * The level to inject for an effort-less call, or undefined to pass through.\n * Refusals are silent and total: explicit selections, off-capable ladders,\n * undeclared/non-reasoning models, an explicit route default, and vendor\n * defaults outside the ladder all pass through untouched.\n */\nexport function resolveGuardEffort(input: GuardInput): string | undefined {\n if (input.requested !== undefined) return undefined\n const declared = input.declared\n if (declared === undefined || declared === false) return undefined\n if ('off' in declared) return undefined\n if (input.profileDefault !== undefined) return undefined\n const fallback = input.vendorDefault\n if (fallback === undefined || !(fallback in declared)) return undefined\n return fallback\n}\n", "/**\n * Shape guards and settings-dict readers shared by the host and browser\n * halves. Pure data logic only: esbuild inlines this module into both\n * bundles, so it must never import a harness package or touch DOM/node APIs.\n *\n * @module dsh-model-think-level/shared\n */\n\nimport type { RouteFacts } from './knowledge.js'\n\n/** Whether a value is a plain-ish object (not null, not an array). */\nexport const isRecord = (value: unknown): value is Record<string, unknown> =>\n typeof value === 'object' && value !== null && !Array.isArray(value)\n\n/**\n * Whether a settings refusal reads like \"this kernel does not know the newer\n * compat keys\". The host autofill and the browser write path each downgrade\n * once on this signal, so they must answer identically.\n */\nexport function looksLikeCompatRefusal(message: string): boolean {\n const msg = message.toLowerCase()\n return msg.includes('compat')\n || msg.includes('thinkingtokenbudget')\n || msg.includes('vllmpriority')\n || msg.includes('supportsmaxoutput')\n}\n\n/** The models array of one route in a providers dict, as records. */\nexport function modelsOf(providers: unknown, route: string): Record<string, unknown>[] {\n if (!isRecord(providers)) return []\n const profile = providers[route]\n if (!isRecord(profile) || !Array.isArray(profile['models'])) return []\n return profile['models'].filter(isRecord)\n}\n\n/** One provider profile's route facts, as suggestion inference reads them. */\nexport function routeFactsOf(providers: unknown, route: string): RouteFacts {\n if (!isRecord(providers)) return {}\n const profile = providers[route]\n if (!isRecord(profile)) return {}\n const api = typeof profile['api'] === 'string' ? profile['api'] : undefined\n const baseURL = typeof profile['baseURL'] === 'string' ? profile['baseURL'] : undefined\n const displayName = typeof profile['displayName'] === 'string' ? profile['displayName'] : undefined\n return { api, baseURL, displayName }\n}\n", "/**\n * Provider request-header overlay, PURE half: the origin index and the header\n * value rules shared by the fetch-layer installer and the conflict report.\n *\n * Why this exists at all (issue #12): a route's `headers` dict can be merged or\n * overwritten by the official adapter's attribution headers, with `user-agent`\n * being the most visible case. A gateway that depends on any configured client\n * header therefore may not see the value stored in the profile. The overlay\n * reapplies the complete configured dictionary at the fetch layer, the last\n * public seam before the request reaches the wire.\n *\n * The index keeps every route's endpoint path and configured model ids. The URL\n * alone cannot distinguish two routes that share an origin, while an OpenAI-\n * compatible chat request carries the selected model in its JSON body. The\n * origin map remains as a backwards-compatible fallback for requests that do\n * not expose enough identity (for example a GET /models probe).\n *\n * @module dsh-model-think-level/headers-core\n */\n\nimport { isRecord } from './shared.js'\n\n/**\n * Upper bound on one header value the plugin will send. Fetch itself refuses\n * newline-bearing values (a header-injection guard); this plugin additionally\n * refuses anything unreasonable long rather than letting a paste of a whole\n * certificate turn every request into an upstream 400.\n */\nconst MAX_UA_LENGTH = 512\n\n/** One route's configured request headers and its fetch matching metadata. */\nexport interface HeaderOverride {\n /** `scheme://host:port` of the route's endpoint, exactly as Fetch would print it. */\n origin: string\n /** Normalized pathname prefix from the route's baseURL. */\n pathPrefix: string\n /**\n * The string header pairs to apply at the fetch layer. Empty when the route\n * declares none: the route still participates in matching, so a request that\n * clearly belongs to it is NOT given another route's headers.\n */\n headers: Record<string, string>\n /** The route key that declared them (diagnostics and UI labelling). */\n route: string\n /** Model IDs declared by this route, used to disambiguate shared endpoints. */\n modelIds: string[]\n /** The configured `user-agent`, retained for compatibility and diagnostics. */\n userAgent?: string\n /** Whether this route actually declares sendable request headers. */\n hasHeaders: boolean\n}\n\n/** Backwards-compatible name retained for callers that only knew the UA seam. */\nexport type UserAgentOverride = HeaderOverride\n\n/** A same-origin header disagreement that the URL-only fetch seam cannot disambiguate. */\nexport interface HeaderConflict {\n origin: string\n header: string\n routes: string[]\n values: string[]\n}\n\n/** The route index plus what could not be indexed or was ambiguous. */\nexport interface HeaderIndex {\n /** Every route with a usable endpoint, headers included or not. */\n routes: HeaderOverride[]\n /** Every route with sendable headers, retained for diagnostics and the UI. */\n overrides: HeaderOverride[]\n /** origin \u2192 first complete header override, used as a conservative fallback. */\n byOrigin: Map<string, HeaderOverride>\n /** Same-origin routes that declare different header values. */\n conflicts: { origin: string; routes: string[]; values: string[] }[]\n /** Same-origin disagreements for any configured header. */\n headerConflicts: HeaderConflict[]\n}\n\n/** Backwards-compatible name retained for the original public index contract. */\nexport type UserAgentIndex = HeaderIndex\n\n/** An empty index, for the \"no route declares headers\" case. */\nexport function emptyIndex(): HeaderIndex {\n return { routes: [], overrides: [], byOrigin: new Map(), conflicts: [], headerConflicts: [] }\n}\n\n/** The `scheme://host:port` of a URL string, or undefined when unparseable. */\nexport function originOf(url: string | undefined): string | undefined {\n if (url === undefined || url.trim().length === 0) return undefined\n try {\n return new URL(url).origin\n } catch {\n // A relative or malformed endpoint is not an origin this seam can match.\n return undefined\n }\n}\n\n/**\n * Whether a configured value can ride a Fetch `user-agent` field. Refused\n * rather than sanitized: a header carrying a newline is a request-splitting\n * hazard, and quietly rewriting the user's value would send something they\n * never asked for.\n * @param value - the configured header value.\n * @returns whether it is safe to `Headers.set()`.\n */\nexport function isSendableUserAgent(value: string): boolean {\n if (value.length === 0 || value.length > MAX_UA_LENGTH) return false\n // CR/LF and NUL are what Fetch's own guard rejects; refusing them here keeps\n // the refusal at configuration time instead of on every request.\n return !/[\\r\\n\\0]/.test(value)\n}\n\n/**\n * Whether a configured name/value pair can ride a Fetch header. Fetch is the\n * authority for the exact token grammar, so this accepts arbitrary legal names\n * instead of maintaining a brittle allow-list.\n */\nexport function isSendableHeader(name: string, value: string): boolean {\n if (name.length === 0) return false\n try {\n const headers = new Headers()\n headers.set(name, value)\n return true\n } catch {\n return false\n }\n}\n\n/** The `headers` dict of one route profile, as string pairs, or undefined. */\nexport function headersOf(profile: Record<string, unknown> | undefined): Record<string, string> | undefined {\n if (profile === undefined) return undefined\n const headers = profile['headers']\n if (!isRecord(headers)) return undefined\n const pairs: Record<string, string> = {}\n for (const [name, value] of Object.entries(headers)) {\n if (typeof value === 'string') pairs[name] = value\n }\n return Object.keys(pairs).length === 0 ? undefined : pairs\n}\n\n/**\n * The subset of a profile's headers that Fetch can send. An invalid stored\n * entry must not make the wrapper throw and break an otherwise valid request.\n */\nfunction sendableHeadersOf(profile: Record<string, unknown> | undefined): Record<string, string> | undefined {\n const headers = headersOf(profile)\n if (headers === undefined) return undefined\n const sendable: Record<string, string> = {}\n for (const [name, value] of Object.entries(headers)) {\n if (!isSendableHeader(name, value)) continue\n // Keep the historical UA guard: it avoids sending a malformed or\n // unexpectedly huge client identity while leaving every other legal header\n // available to the arbitrary-header editor.\n if (name.toLowerCase() === 'user-agent' && !isSendableUserAgent(value)) continue\n sendable[name] = value\n }\n return Object.keys(sendable).length === 0 ? undefined : sendable\n}\n\n/**\n * The `user-agent` a route's `headers` dict declares, case-insensitively.\n *\n * A `user-agent` stored here is the user's DECLARATION of the identity their\n * gateway wants, even though the official adapter discards it; the plugin reads\n * the same key so the settings document stays the single source of truth.\n * @param profile - one route's profile record.\n * @returns the value, or undefined when the route declares none.\n */\nexport function declaredUserAgent(profile: Record<string, unknown> | undefined): string | undefined {\n const headers = headersOf(profile)\n if (headers === undefined) return undefined\n for (const [name, value] of Object.entries(headers)) {\n if (name.toLowerCase() === 'user-agent') return isSendableUserAgent(value) ? value : undefined\n }\n return undefined\n}\n\n/** Normalize a route endpoint's pathname for boundary-safe prefix matching. */\nfunction pathPrefixOf(url: string): string {\n try {\n const pathname = new URL(url).pathname.replace(/\\/+$/, '')\n return pathname.length === 0 ? '/' : pathname\n } catch {\n return '/'\n }\n}\n\n/** Model IDs that can appear in a pi-ai request body for one route. */\nfunction modelIdsOf(profile: Record<string, unknown>): string[] {\n const ids = new Set<string>()\n const models = profile['models']\n if (Array.isArray(models)) {\n for (const model of models) {\n if (!isRecord(model) || typeof model['id'] !== 'string' || model['id'].length === 0) continue\n ids.add(model['id'])\n }\n }\n // modelOverrides is keyed by model id and can carry entries not repeated in\n // the explicit models array, so include it as another source of route identity.\n const overrides = profile['modelOverrides']\n if (isRecord(overrides)) {\n for (const id of Object.keys(overrides)) if (id.length > 0) ids.add(id)\n }\n return [...ids]\n}\n\n/** Normalize names the way Fetch's Headers object compares them. */\nfunction normalizedHeaders(headers: Record<string, string>): Map<string, { name: string; value: string }> {\n const normalized = new Map<string, { name: string; value: string }>()\n for (const [name, value] of Object.entries(headers)) {\n normalized.set(name.toLowerCase(), { name, value })\n }\n return normalized\n}\n\n/** Record a same-origin difference that the URL-only fetch seam cannot route. */\nfunction recordHeaderConflicts(index: HeaderIndex, existing: HeaderOverride, route: string, headers: Record<string, string>): void {\n const first = normalizedHeaders(existing.headers)\n const next = normalizedHeaders(headers)\n const names = new Set([...first.keys(), ...next.keys()])\n for (const name of names) {\n const oldEntry = first.get(name)\n const nextEntry = next.get(name)\n if (oldEntry?.value === nextEntry?.value) continue\n const reportedName = nextEntry?.name ?? oldEntry?.name ?? name\n const reported = index.headerConflicts.find(entry => entry.origin === existing.origin && entry.header.toLowerCase() === name)\n if (reported === undefined) {\n index.headerConflicts.push({\n origin: existing.origin,\n header: reportedName,\n routes: [existing.route, route],\n values: [oldEntry?.value ?? '<not configured>', nextEntry?.value ?? '<not configured>'],\n })\n } else if (!reported.routes.includes(route)) {\n reported.routes.push(route)\n reported.values.push(nextEntry?.value ?? '<not configured>')\n }\n }\n}\n\n/** Build the route index from each provider profile's endpoint and header declaration. */\nexport function buildHeaderIndex(\n providers: Record<string, Record<string, unknown>>,\n): HeaderIndex {\n const index = emptyIndex()\n const claimedUserAgents = new Map<string, { routes: string[]; values: string[] }>()\n for (const [route, profile] of Object.entries(providers)) {\n const baseURL = typeof profile['baseURL'] === 'string' ? profile['baseURL'] : undefined\n const origin = originOf(baseURL)\n if (origin === undefined) continue\n\n const sendable = sendableHeadersOf(profile) ?? {}\n const hasHeaders = Object.keys(sendable).length > 0\n const userAgent = Object.entries(sendable).find(([name]) => name.toLowerCase() === 'user-agent')?.[1]\n const override: HeaderOverride = {\n origin,\n pathPrefix: pathPrefixOf(baseURL ?? origin),\n headers: sendable,\n route,\n modelIds: modelIdsOf(profile),\n hasHeaders,\n ...(userAgent === undefined ? {} : { userAgent }),\n }\n // Every route is registered, headers or not: a route that declares no\n // headers must still be able to claim its own requests so another route on\n // the same endpoint cannot leak its headers onto them.\n index.routes.push(override)\n if (!hasHeaders) continue\n index.overrides.push(override)\n const existing = index.byOrigin.get(origin)\n if (existing === undefined) {\n index.byOrigin.set(origin, override)\n } else {\n recordHeaderConflicts(index, existing, route, sendable)\n }\n\n if (userAgent === undefined) continue\n const claimed = claimedUserAgents.get(origin)\n if (claimed === undefined) {\n claimedUserAgents.set(origin, { routes: [route], values: [userAgent] })\n continue\n }\n claimed.routes.push(route)\n claimed.values.push(userAgent)\n // Idempotent declaration (two routes, same identity) is not a UA conflict.\n if (claimed.values.every(value => value === claimed.values[0])) continue\n const reported = index.conflicts.find(entry => entry.origin === origin)\n if (reported === undefined) index.conflicts.push({ origin, routes: [...claimed.routes], values: [...claimed.values] })\n else {\n reported.routes = [...claimed.routes]\n reported.values = [...claimed.values]\n }\n }\n return index\n}\n\n/** Original public name retained while callers migrate to the generic index. */\nexport function buildUserAgentIndex(\n providers: Record<string, Record<string, unknown>>,\n): UserAgentIndex {\n return buildHeaderIndex(providers)\n}\n\n/** The pathname of a request URL, normalized the way {@link pathPrefixOf} is. */\nexport function requestPathOf(url: string): string | undefined {\n try {\n return new URL(url).pathname\n } catch {\n return undefined\n }\n}\n\n/** Whether a request path sits under a route's baseURL path prefix. */\nfunction pathMatches(requestPath: string, prefix: string): boolean {\n if (prefix === '/') return true\n return requestPath === prefix || requestPath.startsWith(`${prefix}/`)\n}\n\n/**\n * The model id carried by a JSON request body, or undefined when the body is\n * not JSON / names no string `model`. OpenAI-compatible chat completions and\n * responses both put the selected model in the top-level `model` field.\n */\nexport function modelOfJsonBody(body: string): string | undefined {\n try {\n const parsed: unknown = JSON.parse(body)\n if (!isRecord(parsed)) return undefined\n const model = parsed['model']\n return typeof model === 'string' && model.length > 0 ? model : undefined\n } catch {\n // A non-JSON body (multipart, SSE upload, empty) carries no model identity.\n return undefined\n }\n}\n\n/**\n * The routes that could own a request, narrowed by origin and endpoint path.\n *\n * The result is the set the fetch layer must disambiguate: one element means\n * the URL already identifies the route (no body read is needed), several means\n * only the request's own `model` can decide, and zero means no route matches.\n * @param index - the live route index.\n * @param url - the request URL.\n * @returns the candidate overrides, in declaration order.\n */\nexport function pathCandidatesOf(index: HeaderIndex, url: string): HeaderOverride[] {\n const origin = originOf(url)\n if (origin === undefined) return []\n // A hand-built index may carry only the origin map; honour it as the legacy\n // single-candidate shape.\n const known = index.routes.length === 0 ? index.overrides : index.routes\n const byOrigin = known.length === 0\n ? (() => { const only = index.byOrigin.get(origin); return only === undefined ? [] : [only] })()\n : known.filter(entry => entry.origin === origin)\n if (byOrigin.length <= 1) return byOrigin\n const requestPath = requestPathOf(url)\n if (requestPath === undefined) return byOrigin\n const matched = byOrigin.filter(entry => pathMatches(requestPath, entry.pathPrefix))\n // An empty path match means the route paths were not describable (or the\n // request targets a prefix no route declares): keep every candidate.\n return matched.length === 0 ? byOrigin : matched\n}\n\n/**\n * Pick one route out of already-narrowed candidates by the request body's model.\n *\n * The model only decides when exactly one candidate declares it; a model no\n * candidate declares, or a model several candidates share, falls back to the\n * first declarer \u2014 the same conservative rule as a request with no model at\n * all.\n * @param candidates - the path-narrowed candidates, in declaration order.\n * @param model - the model id read from the request body, when one was found.\n * @returns the override to apply, or undefined when there are no candidates.\n */\nexport function selectOverrideFrom(candidates: HeaderOverride[], model?: string): HeaderOverride | undefined {\n if (candidates.length <= 1) return candidates[0]\n if (model !== undefined) {\n const byModel = candidates.filter(entry => entry.modelIds.includes(model))\n if (byModel.length === 1) return byModel[0]\n }\n return candidates[0]\n}\n\n/**\n * Pick the route whose configured headers belong on one request.\n *\n * Two routes can share an origin, which the URL alone cannot separate. The\n * choice is therefore narrowed in three steps: the endpoint path prefix (see\n * {@link pathCandidatesOf}), then the `model` carried by the JSON body (see\n * {@link selectOverrideFrom}), then the first declarer. A request that cannot\n * be pinned down therefore keeps the conservative behaviour the plugin shipped\n * with, and the index's conflict report tells the user the endpoints overlap.\n * @param index - the live route index.\n * @param url - the request URL.\n * @param model - the model id read from the request body, when one was found.\n * @returns the override to apply, or undefined when no route matches.\n */\nexport function selectOverride(\n index: HeaderIndex,\n url: string,\n model?: string,\n): HeaderOverride | undefined {\n return selectOverrideFrom(pathCandidatesOf(index, url), model)\n}\n\n/**\n * The request URL a Fetch call is aimed at, or undefined when it cannot be\n * classified. A `Request` from another realm fails the `instanceof` test and is\n * reported as unclassifiable rather than mis-read \u2014 the same conservative\n * posture the official fetch seam takes.\n * @param input - the fetch input.\n * @returns the URL string, when one can be read.\n */\nexport function requestUrlOf(input: unknown): string | undefined {\n if (typeof input === 'string') return input\n if (typeof URL !== 'undefined' && input instanceof URL) return input.href\n if (typeof Request !== 'undefined' && input instanceof Request) return input.url\n return undefined\n}\n", "/**\n * The fetch-layer installer for provider request-header overrides. The decision of\n * WHAT to override lives in `headers-core.ts`; this module owns the global seam.\n *\n * Shape of the seam: one process-wide wrapper owns `globalThis.fetch`, and\n * every activation is an ENTRY inside it. That is what makes the plugin safe\n * next to itself (an HMR remount, a second composer, two plugin instances) and\n * what makes unloading exact: an entry leaves the registry and the wrapper is\n * restored only once the last entry is gone \u2014 never a blind\n * `globalThis.fetch = original` that would clobber a wrapper installed after\n * this one, and never a wrapper left behind holding the process's fetch.\n *\n * The wrapper is deliberately narrow: a request whose URL is not in the index\n * passes through with its ORIGINAL arguments (same object identity), so\n * unconfigured traffic pays exactly one URL classification and one index\n * lookup \u2014 no allocation beyond that, and no way for a bug in the merge path\n * to alter a request that never matched.\n *\n * Why fetch rather than the pi-ai `transformHeaders` option, which would be\n * narrower: reaching that option means holding the adapter's private `models`\n * collection, and every sanctioned seam (`llm/stream` waterfall,\n * `registerAdapter`) stops at the stream, above the wire. Fetch is the only\n * public surface that sees the merged headers. Both were probed against the\n * real runtime \u2014 see `.tmp-rel/headers-probe/`.\n *\n * @module dsh-model-think-level/headers-fetch\n */\n\nimport {\n emptyIndex,\n modelOfJsonBody,\n pathCandidatesOf,\n requestUrlOf,\n selectOverrideFrom,\n type HeaderIndex,\n type HeaderOverride,\n} from './headers-core.js'\n\n/** Registry key on `globalThis`, so a second plugin load shares the one wrapper. */\nconst REGISTRY = Symbol.for('dsh-model-think-level.fetch-overrides')\n\n/** One activation's contribution to the process-wide wrapper. */\ninterface Entry {\n /**\n * Reads the current index. A source rather than a value because the settings\n * document is live: a route added, edited, or removed on the Models page must\n * reach the next request without a plugin reload.\n */\n index: () => HeaderIndex\n}\n\n/** The process-wide wrapper state. */\ninterface Registry {\n base: typeof globalThis.fetch\n wrapper: typeof globalThis.fetch\n entries: Map<symbol, Entry>\n}\n\nfunction registryOf(): Registry | undefined {\n const holder = globalThis as unknown as Record<symbol, Registry | undefined>\n return holder[REGISTRY]\n}\n\n/**\n * Read a request body as text without consuming the request itself.\n *\n * The body is only read when the URL alone leaves the route ambiguous, so the\n * common single-route case still pays nothing. A `Request` is cloned (its\n * stream must survive for the real send); an `init.body` string is used\n * directly, and any other body shape (stream, FormData) yields undefined\n * rather than being disturbed.\n */\nasync function bodyTextOf(input: unknown, init: RequestInit | undefined): Promise<string | undefined> {\n if (typeof init?.body === 'string') return init.body\n if (typeof Request !== 'undefined' && input instanceof Request) {\n try {\n return await input.clone().text()\n } catch {\n // A body that cannot be cloned (already disturbed, or streamed) simply\n // leaves the route ambiguous and the first declarer serves.\n return undefined\n }\n }\n return undefined\n}\n\n/**\n * The caller's request headers as a mutable copy, seeded the way Fetch itself\n * resolves them: an explicit `init.headers` replaces a `Request`'s own headers,\n * and the `Request`'s are inherited only when the init names none. Seeding from\n * the wrong one would either drop the caller's headers or resurrect the ones\n * the caller replaced.\n */\nfunction seedHeaders(input: unknown, init: RequestInit | undefined): Headers {\n if (init?.headers !== undefined && init.headers !== null) return new Headers(init.headers as HeadersInit)\n if (typeof Request !== 'undefined' && input instanceof Request) return new Headers(input.headers)\n return new Headers()\n}\n\n/** The wrapper: inject the matched route's request headers and delegate everything else. */\nfunction makeWrapper(base: typeof globalThis.fetch, entries: Map<symbol, Entry>): typeof globalThis.fetch {\n return async function fetchWithProviderHeaders(input: RequestInfo | URL, init?: RequestInit): Promise<Response> {\n const url = requestUrlOf(input)\n if (url === undefined) return base(input, init)\n // The URL (origin + endpoint path) narrows the route. Only when it leaves\n // several candidates does the request body's `model` have to decide -- so a\n // single-route deployment keeps the zero-read, zero-allocation fast path.\n let candidates: HeaderOverride[] = []\n for (const entry of entries.values()) {\n candidates = pathCandidatesOf(entry.index(), url)\n if (candidates.length > 0) break\n }\n if (candidates.length === 0) return base(input, init)\n let override = candidates.length === 1 ? candidates[0] : undefined\n if (override === undefined) {\n const body = await bodyTextOf(input, init)\n const model = body === undefined ? undefined : modelOfJsonBody(body)\n override = selectOverrideFrom(candidates, model)\n }\n if (override === undefined) return base(input, init)\n // A route that claims the request but declares no headers is a deliberate\n // \"send nothing\": another route's identity must not leak onto it.\n if (!override.hasHeaders) return base(input, init)\n const headers = seedHeaders(input, init)\n for (const [name, value] of Object.entries(override.headers)) {\n // The index already filters invalid entries. Keep the seam defensive for\n // a live source supplied by another caller or a stale settings snapshot.\n try {\n headers.set(name, value)\n } catch {\n // A malformed stored pair must not prevent the remaining headers or the\n // underlying request from being sent.\n }\n }\n const nextInit = { ...init, headers }\n if (typeof Request !== 'undefined' && input instanceof Request) {\n return base(new Request(input, { headers }), nextInit)\n }\n return base(input, nextInit)\n }\n}\n\n/** Handle one activation keeps; `dispose` is idempotent. */\nexport interface HeaderOverlayHandle {\n /** Remove this activation's entry, restoring the original fetch when it was the last. */\n dispose(): void\n}\n\n/** Handle for tests and the caller to swap the index a live activation reads. */\nexport interface HeaderOverlay extends HeaderOverlayHandle {\n /** Whether this activation's entry is still installed. */\n readonly active: boolean\n}\n\n/** A mutable index source an activation reads on every request. */\nexport interface OverlaySource {\n current: HeaderIndex\n}\n\n/**\n * Install (or join) the process-wide header wrapper.\n * @param source - the live index this activation contributes.\n * @returns a handle whose `dispose` removes exactly this activation.\n */\nexport function installHeaderOverlay(source: OverlaySource): HeaderOverlay {\n const holder = globalThis as unknown as Record<symbol, Registry | undefined>\n let registry = holder[REGISTRY]\n const token = Symbol('bre-header-overlay')\n if (registry === undefined) {\n const base = globalThis.fetch\n const entries = new Map<symbol, Entry>()\n const wrapper = makeWrapper(base, entries)\n registry = { base, wrapper, entries }\n holder[REGISTRY] = registry\n globalThis.fetch = wrapper\n }\n registry.entries.set(token, { index: () => source.current })\n const owned = registry\n return {\n get active(): boolean {\n return owned.entries.has(token)\n },\n dispose(): void {\n owned.entries.delete(token)\n if (owned.entries.size > 0) return\n // Last one out restores the ORIGINAL function, and only when this\n // wrapper still holds the global: a later installer's wrapper must not be\n // clobbered by our teardown.\n if (globalThis.fetch === owned.wrapper) globalThis.fetch = owned.base\n if (holder[REGISTRY] === owned) delete holder[REGISTRY]\n },\n }\n}\n\n/** Whether this plugin's wrapper currently owns the global fetch (diagnostics). */\nexport function headerOverlayInstalled(): boolean {\n const registry = registryOf()\n return registry !== undefined && globalThis.fetch === registry.wrapper\n}\n\n/** The empty index, re-exported so callers building one need a single import. */\nexport { emptyIndex }\n", "/**\n * Request-level header bridge for the pi-ai-backed Harness adapter.\n *\n * The model-list probe has its own direct fetch path, but conversation requests\n * are assembled inside dsh-llm-pi-ai and then passed to pi-ai's Models service.\n * pi-ai exposes `transformHeaders` exactly after auth and request headers have\n * been merged, so it is the right place to restore the profile values that the\n * Harness attribution layer reserves (most visibly `user-agent`).\n *\n * dsh-llm-pi-ai does not expose its private Models collection through a public\n * plugin API. Its adapter is nevertheless registered in the public llm runtime,\n * and the runtime object keeps that registration in a normal `adapters` Map. The\n * bridge uses a narrow structural adapter of that implementation detail and\n * fails open for other adapters or older runtimes.\n *\n * @module dsh-model-think-level/headers-pi-ai\n */\n\nimport { isRecord } from './shared.js'\nimport { selectOverride, type HeaderIndex, type HeaderOverride } from './headers-core.js'\n\n/** A live route index shared with the fetch overlay. */\nexport interface PiAiHeaderSource {\n current: HeaderIndex\n}\n\ntype ProviderHeaders = Record<string, string | null>\ntype HeaderTransformer = (headers: ProviderHeaders) => ProviderHeaders | Promise<ProviderHeaders>\ntype UnknownFunction = (...args: unknown[]) => unknown\n\ntype ObjectLike = Record<PropertyKey, unknown>\n\ninterface PiAiPatchState {\n originalCurrent: UnknownFunction\n wrappedCurrent: UnknownFunction\n source: PiAiHeaderSource\n users: number\n}\n\ninterface RegisterPatchState {\n originalRegister: UnknownFunction\n wrappedRegister: UnknownFunction\n users: number\n}\n\nconst PATCH_STATE = Symbol.for('dsh-model-think-level.pi-ai-header-transform')\nconst REGISTER_PATCH_STATE = Symbol.for('dsh-model-think-level.pi-ai-header-register')\nconst CORDIS_ORIGINAL = Symbol.for('cordis.original')\n\nfunction objectOf(value: unknown): ObjectLike | undefined {\n return typeof value === 'object' && value !== null ? value as ObjectLike : undefined\n}\n\nfunction runtimeObjectOf(value: unknown): ObjectLike | undefined {\n const object = objectOf(value)\n if (object === undefined) return undefined\n const original = object[CORDIS_ORIGINAL]\n return objectOf(original) ?? object\n}\n\nfunction noOpHandle(): PiAiHeaderTransformHandle {\n return {\n active: false,\n dispose(): void {},\n }\n}\n\nfunction routeOverrideOf(source: PiAiHeaderSource, model: unknown): HeaderOverride | undefined {\n try {\n if (!isRecord(model)) return undefined\n const baseURL = model['baseUrl']\n if (typeof baseURL !== 'string' || baseURL.length === 0) return undefined\n const modelId = typeof model['id'] === 'string' ? model['id'] : undefined\n return selectOverride(source.current, baseURL, modelId)\n } catch {\n // A stale or partially written settings snapshot must never break a chat.\n return undefined\n }\n}\n\nfunction modelsProxyOf(models: ObjectLike, source: PiAiHeaderSource): ObjectLike {\n return new Proxy(models, {\n get(target, property, receiver): unknown {\n if (property !== 'streamSimple') return Reflect.get(target, property, receiver)\n const streamSimple = Reflect.get(target, property, target)\n if (typeof streamSimple !== 'function') return streamSimple\n return (...args: unknown[]): unknown => {\n const model = args[0]\n const context = args[1]\n const options = args[2]\n const modelObject = isRecord(model) ? model : undefined\n if (modelObject === undefined || typeof modelObject['baseUrl'] !== 'string' || !isRecord(options)) {\n return (streamSimple as UnknownFunction).call(target, model, context, options)\n }\n\n const existing = typeof options['transformHeaders'] === 'function'\n ? options['transformHeaders'] as HeaderTransformer\n : undefined\n const transformHeaders: HeaderTransformer = async (headers) => {\n // Preserve any transform supplied by the adapter/provider first; the\n // user's route headers are the final request-level values by design.\n const merged = existing === undefined ? headers : await existing(headers)\n const override = routeOverrideOf(source, model)\n return override?.hasHeaders ? { ...merged, ...override.headers } : merged\n }\n return (streamSimple as UnknownFunction).call(target, model, context, {\n ...options,\n transformHeaders,\n })\n }\n },\n })\n}\n\nfunction snapshotProxyOf(snapshot: ObjectLike, source: PiAiHeaderSource): ObjectLike {\n const models = snapshot['models']\n const modelObject = objectOf(models)\n if (modelObject === undefined || typeof modelObject['streamSimple'] !== 'function') return snapshot\n const proxiedModels = modelsProxyOf(modelObject, source)\n return new Proxy(snapshot, {\n get(target, property, receiver): unknown {\n if (property === 'models') return proxiedModels\n return Reflect.get(target, property, receiver)\n },\n })\n}\n\n/** Handle returned for one adapter patch. */\nexport interface PiAiHeaderTransformHandle {\n readonly active: boolean\n dispose(): void\n}\n\n/** Install the request-level transform on one pi-ai-shaped adapter. */\nexport function installPiAiHeaderTransform(adapter: unknown, source: PiAiHeaderSource): PiAiHeaderTransformHandle {\n const target = objectOf(adapter)\n if (target === undefined || typeof target['current'] !== 'function') return noOpHandle()\n\n const current = target['current'] as UnknownFunction\n const stored = target[PATCH_STATE] as PiAiPatchState | undefined\n if (stored !== undefined && current === stored.wrappedCurrent) {\n stored.source = source\n stored.users += 1\n let active = true\n return {\n get active(): boolean { return active && stored.users > 0 },\n dispose(): void {\n if (!active) return\n active = false\n stored.users -= 1\n if (stored.users > 0) return\n if (target['current'] === stored.wrappedCurrent) target['current'] = stored.originalCurrent\n if (target[PATCH_STATE] === stored) delete target[PATCH_STATE]\n },\n }\n }\n\n const originalCurrent = current\n const wrappedCurrent: UnknownFunction = function (this: unknown, ...args: unknown[]): unknown {\n const snapshot = originalCurrent.apply(this, args)\n const snapshotObject = objectOf(snapshot)\n return snapshotObject === undefined ? snapshot : snapshotProxyOf(snapshotObject, state.source)\n }\n const state: PiAiPatchState = { originalCurrent, wrappedCurrent, source, users: 1 }\n target['current'] = wrappedCurrent\n Object.defineProperty(target, PATCH_STATE, { configurable: true, value: state })\n\n let active = true\n return {\n get active(): boolean { return active && state.users > 0 },\n dispose(): void {\n if (!active) return\n active = false\n state.users -= 1\n if (state.users > 0) return\n if (target['current'] === state.wrappedCurrent) target['current'] = state.originalCurrent\n if (target[PATCH_STATE] === state) delete target[PATCH_STATE]\n },\n }\n}\n\n/** Diagnostic snapshot of the bridge's live attach state. */\nexport interface PiAiHeaderBridgeState {\n runtimeFound: boolean\n registerPatched: boolean\n adaptersInRuntime: number\n adaptersPatched: number\n adapters: string[]\n routes: number\n overrides: number\n}\n\n/**\n * Describe what the bridge is currently attached to. Read-only; used by the\n * probe route's `?diag=1` arm to make the request-header takeover observable\n * from the running host instead of only from a test harness.\n */\nexport function describePiAiHeaderState(llm: unknown, source: PiAiHeaderSource): PiAiHeaderBridgeState {\n const runtime = runtimeObjectOf(llm)\n const adapters = runtime?.['adapters']\n const names: string[] = []\n let total = 0\n let patched = 0\n if (adapters instanceof Map) {\n for (const registration of adapters.values()) {\n const adapter = objectOf(objectOf(registration)?.['adapter'])\n if (adapter === undefined || typeof adapter['current'] !== 'function') continue\n total += 1\n const state = adapter[PATCH_STATE] as PiAiPatchState | undefined\n const isPatched = state !== undefined && adapter['current'] === state.wrappedCurrent\n if (isPatched) patched += 1\n const name = typeof adapter['constructor'] === 'function' ? adapter['constructor'].name : 'unknown'\n names.push(`${name}${isPatched ? '+' : '-'}`)\n }\n }\n const registerState = runtime?.[REGISTER_PATCH_STATE] as RegisterPatchState | undefined\n return {\n runtimeFound: runtime !== undefined,\n registerPatched: registerState !== undefined && runtime?.['registerAdapter'] === registerState.wrappedRegister,\n adaptersInRuntime: total,\n adaptersPatched: patched,\n adapters: names,\n routes: source.current.routes.length,\n overrides: source.current.overrides.length,\n }\n}\n\n/**\n * Install the bridge on every current pi-ai-shaped registration and expose a\n * refresh for the runtime's `llm/adapters-updated` event.\n */\nexport interface PiAiHeaderTransformsHandle {\n refresh(): void\n dispose(): void\n}\n\nexport function installPiAiHeaderTransforms(llm: unknown, source: PiAiHeaderSource): PiAiHeaderTransformsHandle {\n const installed = new Map<object, PiAiHeaderTransformHandle>()\n const runtime = runtimeObjectOf(llm)\n let disposed = false\n\n const install = (adapter: unknown): void => {\n if (disposed) return\n const adapterObject = objectOf(adapter)\n if (adapterObject === undefined || typeof adapterObject['current'] !== 'function') return\n if (!installed.has(adapterObject)) installed.set(adapterObject, installPiAiHeaderTransform(adapterObject, source))\n }\n\n const refresh = (): void => {\n if (disposed) return\n const adapters = runtime?.['adapters']\n if (!(adapters instanceof Map)) return\n const seen = new Set<object>()\n for (const registration of adapters.values()) {\n const registrationObject = objectOf(registration)\n const adapterObject = objectOf(registrationObject?.['adapter'])\n if (adapterObject === undefined || typeof adapterObject['current'] !== 'function') continue\n seen.add(adapterObject)\n install(adapterObject)\n }\n for (const [adapter, handle] of installed) {\n if (seen.has(adapter)) continue\n handle.dispose()\n installed.delete(adapter)\n }\n }\n\n // dsh-llm-pi-ai registers its adapter through this public method. Install\n // before delegating so a registration cannot emit an update and dispatch a\n // request in between the registry mutation and our refresh listener.\n let registerHandle: PiAiHeaderTransformHandle | undefined\n const originalRegister = runtime?.['registerAdapter']\n if (runtime !== undefined && typeof originalRegister === 'function') {\n const registerState = runtime[REGISTER_PATCH_STATE] as RegisterPatchState | undefined\n if (registerState !== undefined && runtime['registerAdapter'] === registerState.wrappedRegister) {\n registerState.users += 1\n registerHandle = {\n get active(): boolean { return !disposed && registerState.users > 0 },\n dispose(): void {\n if (registerState.users <= 0) return\n registerState.users -= 1\n if (registerState.users > 0) return\n if (runtime['registerAdapter'] === registerState.wrappedRegister) runtime['registerAdapter'] = registerState.originalRegister\n if (runtime[REGISTER_PATCH_STATE] === registerState) delete runtime[REGISTER_PATCH_STATE]\n },\n }\n } else {\n const original = originalRegister as UnknownFunction\n const wrappedRegister: UnknownFunction = function (this: unknown, ...args: unknown[]): unknown {\n const adapter = args[1]\n install(adapter)\n try {\n return original.apply(this, args)\n } finally {\n refresh()\n }\n }\n const state: RegisterPatchState = {\n originalRegister: original,\n wrappedRegister,\n users: 1,\n }\n runtime['registerAdapter'] = wrappedRegister\n Object.defineProperty(runtime, REGISTER_PATCH_STATE, { configurable: true, value: state })\n registerHandle = {\n get active(): boolean { return !disposed && state.users > 0 },\n dispose(): void {\n if (state.users <= 0) return\n state.users -= 1\n if (state.users > 0) return\n if (runtime['registerAdapter'] === state.wrappedRegister) runtime['registerAdapter'] = state.originalRegister\n if (runtime[REGISTER_PATCH_STATE] === state) delete runtime[REGISTER_PATCH_STATE]\n },\n }\n }\n }\n refresh()\n\n return {\n refresh,\n dispose(): void {\n if (disposed) return\n disposed = true\n registerHandle?.dispose()\n for (const handle of installed.values()) handle.dispose()\n installed.clear()\n },\n }\n}\n", "/**\n * Coexistence report for the user-agent takeover (issue #12, MVP-3).\n *\n * Overriding `user-agent` is not a private act: the stock adapter drops the\n * profile's value, so at least one published plugin patches the adapter itself\n * to keep it, and several more wrap fetch. Two of them active at once means the\n * LAST writer on the wire wins and the user sees a `user-agent` they did not\n * choose \u2014 with no error anywhere. This module reports what it found instead of\n * silently fighting.\n *\n * Three signals, in descending reliability:\n * 1. The adapter file already carries a user-agent patch (its `requestHeaders`\n * body no longer drops the profile's `user-agent`) \u2014 readable fact.\n * 2. A known sibling plugin's package is installed in a reachable tree.\n * 3. Nothing found.\n *\n * Everything here is best-effort and side-effect-free: an unreadable path, an\n * absent tree, or a hostile `package.json` yields `unknown`, never a throw \u2014\n * this report must not be able to disable the plugin.\n *\n * @module dsh-model-think-level/headers-conflict\n */\n\nimport { existsSync, readFileSync } from 'node:fs'\nimport { createRequire } from 'node:module'\nimport { dirname, join, resolve } from 'node:path'\n\n/**\n * Sibling plugins that rewrite the same request surface. The list is by PACKAGE\n * NAME, matched anywhere in a reachable `node_modules`: a plugin installed\n * under a profile but not enabled is reported as installed, and the report says\n * so rather than guessing at enablement (which a patch file or a hand-edited\n * profile can decide several ways).\n */\nconst SIBLING_PACKAGES = [\n 'dsh-client-masquerade',\n 'dsh-llm-headers',\n 'dsh-llm-pi-ai-headers',\n 'dsh-custom-provider-settings',\n] as const\n\n/**\n * Fragments proving the installed adapter already preserves a profile\n * `user-agent`. The published patch rewrites `requestHeaders()` to look for a\n * configured value; older revisions of it used the same identifier, so the\n * check survives their textual reshuffle while staying specific enough that the\n * stock function cannot match (it contains neither).\n */\nconst ADAPTER_PATCH_MARKERS = ['configuredUserAgent', 'masquerade routes rely on'] as const\n\n/** What the report found about the adapter the requests actually flow through. */\nexport type AdapterPatchState = 'patched' | 'stock' | 'unknown'\n\n/** One sibling plugin package found on disk. */\nexport interface InstalledSibling {\n /** Package name. */\n name: string\n /** Absolute path of the resolved package directory (or entry file). */\n path: string\n}\n\n/** The coexistence report. */\nexport interface HeaderConflictReport {\n /** Whether the installed `@deepseek-ai/dsh-llm-pi-ai` adapter carries a UA patch. */\n adapter: AdapterPatchState\n /** Path of the inspected adapter file, when one was found. */\n adapterPath?: string\n /** Known sibling plugins present on disk. */\n siblings: InstalledSibling[]\n /**\n * Whether this deployment should prefer the official layer instead of this\n * plugin's fetch takeover: true exactly when the adapter is already patched\n * (a profile `user-agent` reaches the wire on its own then, and a fetch\n * override on top would fight the patch).\n */\n preferOfficialLayer: boolean\n}\n\n/** Candidate `node_modules` roots to look in, most specific first. */\nfunction searchRoots(): string[] {\n const roots = new Set<string>()\n const entry = process.argv[1]\n if (typeof entry === 'string' && entry.length > 0) {\n let dir = dirname(resolve(entry))\n // Walk up a bounded number of levels: the shim, the bin dir, the package,\n // the install root.\n for (let depth = 0; depth < 8; depth += 1) {\n roots.add(join(dir, 'node_modules'))\n const parent = dirname(dir)\n if (parent === dir) break\n dir = parent\n }\n }\n // The cwd tree covers a profile-relative launch; the require chain covers\n // everything the process itself can no longer name.\n roots.add(join(process.cwd(), 'node_modules'))\n try {\n const require = createRequire(import.meta.url)\n for (const name of SIBLING_PACKAGES) {\n try {\n roots.add(join(dirname(dirname(dirname(require.resolve(`${name}/package.json`)))), 'node_modules'))\n } catch {\n // Not resolvable from here; the path search below covers the rest.\n }\n }\n } catch {\n // No require chain: path search alone.\n }\n return [...roots]\n}\n\n/** Locate the installed pi-ai adapter's bundle, or undefined when unreachable. */\nfunction findAdapterFile(): string | undefined {\n const relative = join('@deepseek-ai', 'dsh-llm-pi-ai', 'lib', 'index.js')\n const candidates: string[] = []\n try {\n const require = createRequire(import.meta.url)\n candidates.push(require.resolve('@deepseek-ai/dsh-llm-pi-ai'))\n } catch {\n // Resolve by location instead.\n }\n // dsh ships the adapter inside its own tree; probing the entry's ancestry\n // finds it for a global install, a profile install, and a monorepo alike.\n for (const root of searchRoots()) candidates.push(join(root, relative))\n for (const candidate of candidates) {\n if (existsSync(candidate)) return candidate\n }\n return undefined\n}\n\n/**\n * Whether a source text of the pi-ai adapter bundle carries a user-agent patch.\n *\n * Pure, so the decision is testable without touching a real installation: the\n * stock `requestHeaders()` filters the profile's `user-agent` into the reserved\n * set and contains neither marker, while every published revision of the patch\n * names the value it found.\n * @param source - the adapter bundle's text.\n * @returns whether the patch is present.\n */\nexport function adapterSourcePatched(source: string): boolean {\n return ADAPTER_PATCH_MARKERS.some(marker => source.includes(marker))\n}\n\n/** Whether the adapter bundle at one path carries a user-agent patch. */\nfunction adapterPatchState(path: string): AdapterPatchState {\n try {\n return adapterSourcePatched(readFileSync(path, 'utf8')) ? 'patched' : 'stock'\n } catch {\n return 'unknown'\n }\n}\n\n/** Known sibling plugins present in a reachable tree. */\nfunction findSiblings(): InstalledSibling[] {\n const found: InstalledSibling[] = []\n const seen = new Set<string>()\n for (const root of searchRoots()) {\n for (const name of SIBLING_PACKAGES) {\n if (seen.has(name)) continue\n const dir = join(root, name)\n const manifest = join(dir, 'package.json')\n if (!existsSync(manifest)) continue\n seen.add(name)\n found.push({ name, path: dir })\n }\n }\n return found\n}\n\n/**\n * Produce the coexistence report. Never throws: every probe degrades to\n * `unknown` / an empty list.\n * @returns the report.\n */\nexport function detectHeaderConflicts(): HeaderConflictReport {\n let adapter: AdapterPatchState = 'unknown'\n let adapterPath: string | undefined\n let siblings: InstalledSibling[] = []\n try {\n adapterPath = findAdapterFile()\n if (adapterPath !== undefined) adapter = adapterPatchState(adapterPath)\n } catch {\n adapter = 'unknown'\n }\n try {\n siblings = findSiblings()\n } catch {\n siblings = []\n }\n return {\n adapter,\n ...(adapterPath === undefined ? {} : { adapterPath }),\n siblings,\n preferOfficialLayer: adapter === 'patched',\n }\n}\n", "/**\n * The knowledge-base auto-fill: build the settings patch that declares\n * `reasoningEfforts` -- and, unless declined, the input-modality declaration --\n * on every undeclared model of a providers dict.\n *\n * Shared by BOTH halves on purpose. The host builds its boot fill with it, and\n * the browser half builds the very same patch from its own read, so one\n * suggestion can never produce two different documents. Pure data logic: no\n * harness package, no node or DOM API.\n *\n * @module dsh-model-think-level/autofill\n */\n\nimport { AUTOFILL_MARKER, INPUT_UNSET_MARKER, UNSET_MARKER } from './constants.js'\nimport { isSelfHostedRelay, NEW_COMPAT_KEYS, suggestEfforts } from './knowledge.js'\nimport { isRecord, routeFactsOf } from './shared.js'\n\n/** A JSON object patch. */\ntype JsonObject = Record<string, unknown>\n\n/**\n * Whether a model row carries an input-modality declaration the document\n * already answers with. An absent key and an empty array both read as \"no\n * answer here\" -- mirroring how llm-pi-ai's own resolution treats them.\n */\nfunction declaresInput(model: JsonObject): boolean {\n const input = model['input']\n return Array.isArray(input) && input.length > 0\n}\n\n/**\n * Build a patch that adds reasoningEfforts -- and, unless declined, the\n * input-modality declaration -- to every undeclared model of the given\n * routes, from the knowledge base / protocol inference. Returns the partial\n * providers patch, or undefined when nothing needs filling.\n * @param providers - the resolved providers dict.\n * @param routeFilter - optional route filter (defaults to all routes).\n * @param options - fill switches; both default on.\n * @param revision - settings revision this read is based on; recorded as the\n * provenance marker of every ladder filled here (see {@link AUTOFILL_MARKER}).\n */\nexport function buildAutofillPatch(\n providers: unknown,\n routeFilter: (route: string) => boolean = () => true,\n options: { efforts?: boolean; modalities?: boolean } = {},\n revision = 0,\n): JsonObject | undefined {\n const fillEfforts = options.efforts !== false\n const fillModalities = options.modalities !== false\n if (!isRecord(providers)) return undefined\n const patchRoutes: JsonObject = {}\n for (const route of Object.keys(providers)) {\n if (!routeFilter(route)) continue\n // Read the RAW models array: this builder rebuilds the array verbatim,\n // so a route carrying a row it cannot represent (non-record) is left\n // alone \u2014 a filtered rebuild would silently DELETE that row.\n const profile = providers[route]\n const rawModels = isRecord(profile) && Array.isArray(profile['models']) ? profile['models'] : undefined\n if (rawModels === undefined || rawModels.length === 0) continue\n if (!rawModels.every(isRecord)) continue\n const models = rawModels as Record<string, unknown>[]\n const nextModels: JsonObject[] = []\n let changed = false\n for (const model of models) {\n // Declared parts are untouched \u2014 and so are parts the user\n // deliberately unset: the durable markers record those absences as\n // decisions, so auto-fill never reads them back as gaps (the bug this\n // guards: a refill one event after every user \"unset\").\n const effortsDeclared = model['reasoningEfforts'] !== undefined || model[UNSET_MARKER] === true\n const inputDeclared = declaresInput(model) || model[INPUT_UNSET_MARKER] === true\n if ((effortsDeclared || !fillEfforts) && (inputDeclared || !fillModalities)) {\n // Versioned exception to never-touch-declared (issue #2): a declared\n // ladder whose compat lacks the role pin on a self-hosted relay gets\n // exactly that field merged in -- the declaration itself is untouched.\n const backfilled = backfillRolePin(model, providers, route)\n if (backfilled !== undefined) {\n changed = true\n nextModels.push(backfilled)\n } else {\n nextModels.push(model)\n }\n continue\n }\n const id = typeof model['id'] === 'string' ? model['id'] : ''\n if (id.length === 0) {\n nextModels.push(model)\n continue\n }\n const routeInfo = routeFactsOf(providers, route)\n const name = typeof model['name'] === 'string' ? model['name'] : undefined\n const suggestion = suggestEfforts(id, { ...routeInfo, displayName: name ?? routeInfo.displayName })\n if (suggestion.efforts === undefined) {\n nextModels.push(model)\n continue\n }\n const fill: JsonObject = { ...model }\n let touched = false\n // Capacities are never filled here: contextWindow / maxTokens are\n // display-only reference values in the browser half, and writing them\n // host-side would silently override the route defaults.\n // Reaching this branch means neither part was declared and no durable\n // unset marker stands on the row -- so there is no stale marker inside\n // `fill` to scrub; the guards above already excluded it.\n if (!effortsDeclared && fillEfforts) {\n touched = true\n fill['reasoningEfforts'] = suggestion.efforts as JsonObject\n // Provenance: the browser flush has to be able to tell this knowledge\n // base suggestion apart from a declaration the user made, or a staged\n // intent that differs in one spelling is dropped as a takeover (see\n // AUTOFILL_MARKER). The value is the revision this fill read.\n fill[AUTOFILL_MARKER] = revision\n if (suggestion.compat !== undefined) {\n const stored = isRecord(model['compat']) ? (model['compat'] as JsonObject) : {}\n fill['compat'] = { ...stored, ...(suggestion.compat as JsonObject) }\n }\n }\n if (!inputDeclared && fillModalities && suggestion.input !== undefined) {\n touched = true\n fill['input'] = [...suggestion.input]\n }\n if (!touched) {\n nextModels.push(model)\n continue\n }\n changed = true\n nextModels.push(fill)\n }\n if (changed) patchRoutes[route] = { models: nextModels }\n }\n return Object.keys(patchRoutes).length === 0 ? undefined : { providers: patchRoutes }\n}\n\n/** Strip newer-only compat keys from an autofill patch (older-kernel downgrade). */\nexport function stripNewCompatKeysDeep(patch: JsonObject): JsonObject | undefined {\n const providers = isRecord(patch['providers']) ? (patch['providers'] as JsonObject) : undefined\n if (providers === undefined) return undefined\n let strippedAny = false\n const nextProviders: JsonObject = {}\n for (const [route, profile] of Object.entries(providers)) {\n if (!isRecord(profile) || !Array.isArray(profile['models'])) {\n nextProviders[route] = profile as JsonObject\n continue\n }\n nextProviders[route] = {\n ...(profile as JsonObject),\n models: (profile['models'] as JsonObject[]).map(model => {\n if (!isRecord(model) || !isRecord(model['compat'])) return model\n const compat = { ...(model['compat'] as JsonObject) }\n for (const key of NEW_COMPAT_KEYS) {\n if (key in compat) {\n delete compat[key]\n strippedAny = true\n }\n }\n return { ...model, compat }\n }),\n }\n }\n if (!strippedAny) return undefined\n return { providers: nextProviders }\n}\n\n/**\n * Merge the role pin into one declared model row, or refuse it.\n *\n * Refusals (all silent, all deliberate): the row carries no ladder dict\n * (`false`, absent, or a deliberate-unset marker -- bare rows keep the bare\n * wire behavior they were chosen for); its compat already names an explicit\n * role value; or the route is not a self-hosted relay. A refusal changes\n * nothing; an acceptance touches exactly one compat field.\n */\nfunction backfillRolePin(\n model: Record<string, unknown>,\n providers: unknown,\n route: string,\n): JsonObject | undefined {\n if (!isRecord(model['reasoningEfforts'])) return undefined\n if (model[UNSET_MARKER] === true) return undefined\n const compat = model['compat']\n const base: JsonObject = isRecord(compat) ? { ...compat } : {}\n if (base['supportsDeveloperRole'] !== undefined) return undefined\n if (!isSelfHostedRelay(routeFactsOf(providers, route))) return undefined\n return { ...model, compat: { ...base, supportsDeveloperRole: false } }\n}\n"],
|
|
5
|
-
"mappings": "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",
|
|
4
|
+
"sourcesContent": ["/**\n * Host half of dsh-model-think-level.\n *\n * One job: settings auto-adaptation. Whenever the `llm-pi-ai` section gains a\n * hand-declared model that carries no `reasoningEfforts`, fill one in from the\n * knowledge base + protocol inference (see {@link suggestEfforts}). The fill\n * is a *suggestion* written to the user layer \u2014 the user can still edit it on\n * the Models page \u2014 and a model that already declares efforts, or an explicit\n * `false`, is never touched. All interactive editing (per-model editors and\n * per-model auto-adapt) lives in the browser half, which reuses the same\n * knowledge base as a pure module.\n *\n * @module dsh-model-think-level\n */\n\nimport type { IncomingMessage, ServerResponse } from 'node:http'\nimport type { Context } from '@deepseek-ai/cordis'\n// Type-only: pulls the webServer service merge into this program's Context.\nimport type {} from '@deepseek-ai/dsh-host-webserver'\n// Type-only: the `declare module '@deepseek-ai/cordis'` merge that types\n// `ctx.settings` as the profile-form service. `describe()` returns one\n// descriptor per active entry: an ARRAY, not the wire `{namespaces}` envelope.\n// The kernel ships no `settingsNamespace` value export (it is a private parse\n// + a compile-time SettingsNamespaceInput); the brand is a compile-time\n// concept, so a typed constant is enough.\nimport type { SettingsNamespace } from '@deepseek-ai/dsh-settings'\nimport Schema from '@deepseek-ai/schemastery'\nimport {\n AUTOFILL_CONFIG_PATH,\n DIAG_PATH,\n HEADERS_CONFIG_PATH,\n KEY_INDEX_PATH,\n PI_AI_NS,\n PLUGIN_ID,\n PROBE_PATH,\n PROVIDER_KEY_PATH,\n} from './constants.js'\nimport { isLegalKeyValue, maskKeyValue, nextKeyRef, normalizeKeyAlias } from './key-refs.js'\nimport {\n hasKeyEntry,\n keyEntriesOf,\n keyIndexFilePath,\n readKeyIndex,\n updateKeyIndex,\n withKeyAlias,\n withKeyEntry,\n withoutKeyEntry,\n} from './key-index.js'\nimport { suggestEfforts } from './knowledge.js'\nimport type { ReasoningEfforts } from './knowledge.js'\nimport { resolveGuardEffort } from './guard.js'\nimport { isRecord, looksLikeCompatRefusal, routeFactsOf } from './shared.js'\nimport { buildHeaderIndex, emptyIndex, type UserAgentIndex } from './headers-core.js'\nimport { headerOverlayInstalled, installHeaderOverlay, type OverlaySource } from './headers-fetch.js'\nimport { describePiAiHeaderState, installPiAiHeaderTransforms } from './headers-pi-ai.js'\nimport { detectHeaderConflicts, type HeaderConflictReport } from './headers-conflict.js'\n// The knowledge-base patch builder lives in its own module: the browser half\n// builds the SAME patch from its own idle-time read, so one suggestion can\n// never produce two different documents.\nimport { buildAutofillPatch, stripNewCompatKeysDeep } from './autofill.js'\n\n/** Re-exported so the package entry keeps naming the patch builder. */\nexport { buildAutofillPatch }\n\n/** Stable plugin id, matching the cordis.patch.yml row and the bundle id. */\nexport const name = PLUGIN_ID\n\n/** Hard dependencies: the loader waits for these before calling apply. */\nexport const inject = ['settings', 'llm']\n\n/** The branded settings namespace this plugin reads and fills. */\nconst PI_NS = PI_AI_NS as SettingsNamespace\n\n/**\n * Exponential backoff for the boot fill: llm-pi-ai may register its namespace\n * well after this plugin on a slow start, and registration emits no event of\n * its own \u2014 the schedule must outlast a realistically slow profile instead of\n * giving up after a few flat seconds.\n */\nconst BOOT_RETRY_DELAYS_MS = [1_000, 2_000, 4_000, 8_000, 16_000, 30_000] as const\n\n/** Probe fetch budget: a gateway that cannot answer /models in 15s will not answer the composer either. */\nconst PROBE_TIMEOUT_MS = 15_000\n\n/**\n * Plugin configuration, supplied through the profile's cordis layer\n * (the row's `config:` block). Every tunable two deployments may want\n * to set differently lives here rather than as a code constant.\n */\nexport interface Config {\n /** Auto-fill undeclared pi-ai models on boot and after settings updates (default true). */\n autofill?: boolean\n /**\n * Whether the auto-fill above also fills the input-modality declaration\n * (default true). Effort auto-fill is governed by {@link autofill} alone.\n */\n modalityAutofill?: boolean\n /** Upstream fetch timeout for the raw /models probe route, in milliseconds (default 15000). */\n probeTimeoutMs?: number\n /**\n * Boot-fill retry backoff schedule in milliseconds; an empty list means\n * \"try exactly once\" (default [1000, 2000, 4000, 8000, 16000, 30000]).\n */\n bootRetryDelaysMs?: number[]\n /**\n * Rewrite effort-less calls to forced-thinking ladders into the ladder's\n * vendor default (default true). Only the request class that today becomes\n * `thinking: {type: disabled}` on a ladder that cannot switch thinking off\n * is rewritten (issue #2); everything else passes through byte-identical.\n */\n defaultGuard?: boolean\n /**\n * Take over the configured request headers at the fetch layer for every route\n * whose `headers` declare one (default true). The official adapter may merge\n * attribution headers over profile values, so the overlay reapplies the\n * profile dictionary before the request reaches the wire. The historical\n * `uaOverride` name is retained for configuration compatibility.\n */\n uaOverride?: boolean\n}\n\n/** Schemastery schema: Cordis validates the row config and fills defaults before apply(). */\nexport const Config: Schema<Config> = Schema.object({\n autofill: Schema.boolean().default(true),\n modalityAutofill: Schema.boolean().default(true),\n probeTimeoutMs: Schema.natural().min(1).default(PROBE_TIMEOUT_MS),\n bootRetryDelaysMs: Schema.array(Schema.natural().min(1)).default([...BOOT_RETRY_DELAYS_MS]),\n defaultGuard: Schema.boolean().default(true),\n uaOverride: Schema.boolean().default(true),\n})\n\ninterface CredentialsService {\n resolve(ref: string): Promise<{ value?: string } | undefined>\n /** Per-reference configuration facts \u2014 never the values themselves. */\n describe?(refs: string[]): Promise<unknown>\n /** Store one value under one reference. */\n set?(ref: string, value: string): Promise<unknown>\n /** Forget one reference's value. */\n unset?(ref: string): Promise<unknown>\n}\n\n/** One row of the key manager's list, as the browser half reads it. */\ninterface KeyEntryView {\n /** Credential reference holding the value. */\n ref: string\n /** Stored label, when the user gave one. */\n alias?: string\n /** Whether this is the reference the adapter resolves. */\n enabled: boolean\n /** Whether the store holds a value; null when the store cannot say. */\n configured: boolean | null\n /** The value in its display form, when the store let it be read. */\n masked?: string\n}\n\n/** One route's profile inside a pi-ai section value, or undefined. */\nfunction providerProfileOf(section: unknown, route: string): Record<string, unknown> | undefined {\n if (!isRecord(section)) return undefined\n const providers = section['providers']\n if (!isRecord(providers)) return undefined\n const profile = providers[route]\n return isRecord(profile) ? profile : undefined\n}\n\n/** The reference one profile names as the key in use, when it names one. */\nfunction enabledRefOf(profile: Record<string, unknown> | undefined): string | undefined {\n const ref = profile?.['apiKeyEnv']\n return typeof ref === 'string' && ref.length > 0 ? ref : undefined\n}\n\n/** Whether a host-service answer is the refusal envelope (`{ok: false}`). */\nfunction isRefusal(answer: unknown): boolean {\n return isRecord(answer) && answer['ok'] === false\n}\n\n/** The message a host-service answer carries when it refuses. */\nfunction refusalMessage(answer: unknown): string | undefined {\n if (!isRecord(answer)) return undefined\n const error = answer['error']\n if (typeof error === 'string') return error\n if (isRecord(error) && typeof error['message'] === 'string') return error['message']\n return typeof answer['message'] === 'string' ? answer['message'] : undefined\n}\n\n/**\n * The per-reference info map a `credentials.describe()` answer carries. The\n * host service is documented to answer the map itself while the Remote face\n * wraps it in the `{ok, value}` envelope; both are read here.\n */\nfunction describeRecords(answer: unknown): Record<string, unknown> | undefined {\n const candidate = isRecord(answer) && answer['value'] !== undefined ? answer['value'] : answer\n return isRecord(candidate) ? candidate : undefined\n}\n\n/** Store one value under one reference; the refusal text, or undefined. */\nasync function storeCredential(\n credentials: CredentialsService | undefined,\n ref: string,\n value: string,\n): Promise<string | undefined> {\n const set = credentials?.set\n if (credentials === undefined || typeof set !== 'function') {\n return 'this deployment cannot write the credential store'\n }\n try {\n const answer = await set.call(credentials, ref, value)\n if (!isRefusal(answer)) return undefined\n return refusalMessage(answer) ?? `the credential store refused ${ref}`\n } catch (error) {\n return error instanceof Error ? error.message : String(error)\n }\n}\n\n/** Forget one reference's value; the refusal text, or undefined. */\nasync function forgetCredential(credentials: CredentialsService | undefined, ref: string): Promise<string | undefined> {\n const unset = credentials?.unset\n if (credentials === undefined || typeof unset !== 'function') {\n return 'this deployment cannot write the credential store'\n }\n try {\n const answer = await unset.call(credentials, ref)\n if (!isRefusal(answer)) return undefined\n return refusalMessage(answer) ?? `the credential store refused to forget ${ref}`\n } catch (error) {\n return error instanceof Error ? error.message : String(error)\n }\n}\n\n/** What the store will say about one reference: configured, and its masked value. */\ninterface CredentialFacts {\n configured: boolean\n masked?: string\n}\n\n/**\n * What the store will say about each reference: whether it holds a value, and \u2014\n * when the value can be read \u2014 the display form the list shows beside it.\n *\n * `describe` answers `configured` without handing the secret over, which is all\n * a badge needs; the masked preview needs the value itself, so it comes from\n * `resolve`, the same call the eye already makes. `describe` stays authoritative\n * about `configured` when both answer. A reference neither can speak about is\n * simply absent from the map.\n */\nasync function credentialFacts(\n credentials: CredentialsService | undefined,\n refs: readonly string[],\n): Promise<Record<string, CredentialFacts>> {\n const out: Record<string, CredentialFacts> = {}\n if (credentials === undefined || refs.length === 0) return out\n const describe = credentials.describe\n if (typeof describe === 'function') {\n try {\n const records = describeRecords(await describe.call(credentials, [...refs]))\n for (const ref of refs) {\n const info = records?.[ref]\n if (isRecord(info) && typeof info['configured'] === 'boolean') {\n out[ref] = { configured: info['configured'] }\n }\n }\n } catch {\n // Unanswered references fall through to resolve() below.\n }\n }\n const resolve = credentials.resolve\n for (const ref of refs) {\n try {\n const hit = await resolve.call(credentials, ref)\n const value = hit !== undefined && typeof hit.value === 'string' ? hit.value : undefined\n const configured = out[ref]?.configured ?? (value !== undefined && value.length > 0)\n const masked = value === undefined ? undefined : maskKeyValue(value)\n out[ref] = masked === undefined || masked.length === 0 ? { configured } : { configured, masked }\n } catch {\n // Leave it unknown: a badge is not worth failing the list over.\n }\n }\n return out\n}\n\n/**\n * Which references hold a value, as far as the store will say.\n *\n * Kept as the narrow question for callers that only badge the list; the list\n * itself asks `credentialFacts` so one read answers both.\n */\nasync function credentialConfigured(\n credentials: CredentialsService | undefined,\n refs: readonly string[],\n): Promise<Record<string, boolean>> {\n const facts = await credentialFacts(credentials, refs)\n const out: Record<string, boolean> = {}\n for (const ref of refs) {\n const configured = facts[ref]?.configured\n if (configured !== undefined) out[ref] = configured\n }\n return out\n}\n\n/** Whether a settings write was refused because the document moved under it. */\nfunction isConflictError(error: unknown): boolean {\n return isRecord(error) && error['code'] === 'SETTINGS_CONFLICT'\n}\n\n/** Read a small JSON request body; undefined when there is nothing to read. */\nasync function readJsonBody(req: IncomingMessage, limit = 8192): Promise<unknown> {\n const decoder = new TextDecoder()\n let text = ''\n try {\n for await (const chunk of req as AsyncIterable<Uint8Array | string>) {\n text += typeof chunk === 'string' ? chunk : decoder.decode(chunk, { stream: true })\n // A provider key is short; anything larger is not a body this route serves.\n if (text.length > limit) return undefined\n }\n } catch {\n return undefined\n }\n if (text.length === 0) return undefined\n try {\n return JSON.parse(text)\n } catch {\n return undefined\n }\n}\n\nfunction isLoopbackHostname(hostname: string): boolean {\n return hostname === 'localhost' || hostname === '127.0.0.1' || hostname === '::1'\n}\n\n/** WHATWG-parse a Host/Origin authority (`host` or `host:port`). */\nfunction parseAuthority(authority: string): URL | undefined {\n try {\n // http: is a WHATWG special scheme: parsing yields a hostname or throws,\n // and normalizes casing the raw header keeps. Note the hostname of an\n // IPv6 authority KEEPS its brackets (`[::1]`) \u2014 the literal check below\n // deliberately matches on the colon.\n return new URL(`http://${authority}`)\n } catch {\n return undefined\n }\n}\n\n/**\n * Whether a parsed hostname is an IP literal (IPv4 dotted quad, or IPv6 whose\n * brackets URL parsing already stripped). A browser fills Host from the URL it\n * believes it is talking to, so a DNS-rebound page ALWAYS carries the\n * attacker's domain here \u2014 it can never produce an IP-literal Host short of\n * the user genuinely navigating to that IP.\n */\nfunction isIpLiteralHostname(hostname: string): boolean {\n return /^\\d{1,3}(\\.\\d{1,3}){3}$/.test(hostname) || hostname.includes(':')\n}\n\n/**\n * Browser trust fence for the probe route. It mirrors the core /api fence's\n * DEFENSE (packages/client/connection/src/api-request-trust.ts) minus one\n * feature: there is no `trustedHosts` escape hatch yet.\n *\n * - Cross-site requests are refused outright; a same-origin/same-site\n * marker never ADMITS anything by itself.\n * - An attached Origin must name exactly this authority; the literal\n * `null` (sandboxed iframe, file: page) is refused.\n * - The Host fence binds every request and is the rebinding defense:\n * only loopback names and IP literals are answered. A rebound page\n * names the attacker's DOMAIN in Host even though the socket lands on\n * this server, so named hosts are always 403.\n *\n * The route proxies only endpoints the user's own settings already name, but\n * it does so with the stored credential attached \u2014 so it must not be callable\n * from elsewhere. LAN deployments serving the GUI under a DOMAIN name get 403\n * here by design (IP-literal LAN hosts keep working); see README known\n * limitations until a trustedHosts seam exists.\n */\nfunction isTrustedRequest(req: IncomingMessage): boolean {\n const host = req.headers.host\n if (typeof host !== 'string' || host.length === 0) return false\n const hostUrl = parseAuthority(host)\n if (hostUrl === undefined) return false\n const secFetchSite = req.headers['sec-fetch-site']\n if (secFetchSite === 'cross-site') return false\n const origin = req.headers.origin\n if (typeof origin === 'string') {\n if (origin === 'null') return false\n try {\n if (new URL(origin).host !== hostUrl.host) return false\n } catch {\n return false\n }\n }\n const hostname = hostUrl.hostname.toLowerCase()\n return isLoopbackHostname(hostname) || isIpLiteralHostname(hostname)\n}\n\nfunction sendJson(res: ServerResponse, status: number, body: unknown): void {\n res.statusCode = status\n res.setHeader('content-type', 'application/json; charset=utf-8')\n res.end(JSON.stringify(body))\n}\n\n/**\n * A URL safe to echo in responses: a baseURL may carry userinfo\n * (https://user:pass@host), and failure messages must never repeat it.\n */\nfunction displayUrl(raw: string): string {\n try {\n const url = new URL(raw)\n url.username = ''\n url.password = ''\n return url.toString()\n } catch {\n return raw\n }\n}\n\n/**\n * Probe-listing URL, mirroring the harness's own model discovery:\n * OpenAI-compatible protocols list at\n * `{baseURL}/models`; Anthropic Messages uses its native route at\n * `{root}/v1/models?limit=1000`, where the root is the base without trailing\n * slashes and without one trailing `/v1` segment (gateway documentation\n * publishes both spellings of the same root). Only this listing URL\n * normalizes that segment.\n */\nfunction probeListingUrl(baseURL: string, api: string): string {\n const base = baseURL.replace(/\\/+$/, '')\n if (api !== 'anthropic-messages') return `${base}/models`\n const root = base.endsWith('/v1') ? base.slice(0, -3) : base\n return `${root}/v1/models?limit=${String(ANTHROPIC_MODEL_LIMIT)}`\n}\n\n/** Protocols whose model listing this module can read (the harness discovery set). */\nconst LISTABLE_PROTOCOLS: ReadonlySet<string> = new Set([\n 'anthropic-messages',\n 'openai-completions',\n 'openai-responses',\n])\n\n/** Stable API version required by Anthropic's model-listing endpoint. */\nconst ANTHROPIC_VERSION = '2023-06-01'\n\n/** Largest model-list page accepted by Anthropic's public endpoint. */\nconst ANTHROPIC_MODEL_LIMIT = 1000\n\n/**\n * Compose the raw-models probe request's headers, mirroring the discipline of\n * the harness's own model discovery: the provider\n * profile's configured request headers form the base (deployment-owned\n * credentials like `x-api-key` ride along), `accept` is always JSON, and a\n * resolved credential's Bearer overwrites a profile `authorization` \u2014 which\n * survives only when no credential resolves (a route may authenticate through\n * its configured headers alone). Anthropic Messages answers through\n * `x-api-key` plus a fixed `anthropic-version`, and its Bearer arm is never\n * used (a profile `authorization` survives untouched there, exactly as the\n * official discovery leaves it). Entries Fetch would refuse are dropped\n * rather than failing the probe. Harness attribution headers are deliberately\n * not sent \u2014 this is a same-origin diagnostic, not a harness request.\n * @param profileHeaders - the profile's raw `headers` dict (simply absent\n * on older documents).\n * @param apiKey - the resolved credential, when one resolved.\n * @param api - the profile's wire protocol.\n */\nexport function composeProbeHeaders(\n profileHeaders: unknown,\n apiKey: string | undefined,\n api: string,\n): Record<string, string> {\n const headers = new Headers()\n if (isRecord(profileHeaders)) {\n for (const [name, value] of Object.entries(profileHeaders)) {\n if (typeof value !== 'string') continue\n try {\n headers.set(name, value)\n } catch {\n // Unrepresentable as a Fetch header: skip the entry, keep probing.\n }\n }\n }\n headers.set('accept', 'application/json')\n if (api === 'anthropic-messages') {\n headers.set('anthropic-version', ANTHROPIC_VERSION)\n if (apiKey !== undefined) headers.set('x-api-key', apiKey)\n } else if (apiKey !== undefined) {\n headers.set('authorization', `Bearer ${apiKey}`)\n }\n return Object.fromEntries(headers.entries())\n}\n\n/**\n * Read a listing reply body, refusing one that outgrows the ceiling (the same\n * bound the official discovery applies). A declared length is checked first\n * so an honest server is turned away without transferring anything; the\n * accumulated total is what actually enforces the bound.\n */\nasync function readBounded(response: Response, url: string): Promise<string> {\n const declared = Number(response.headers.get('content-length') ?? Number.NaN)\n if (Number.isFinite(declared) && declared > MAX_RESPONSE_BYTES) {\n await response.body?.cancel()\n throw new Error(`${displayUrl(url)} overshoots the ${MAX_RESPONSE_BYTES}-byte listing ceiling`)\n }\n if (response.body === null) return ''\n const reader = response.body.getReader()\n const chunks: Uint8Array[] = []\n let total = 0\n try {\n for (;;) {\n const { done, value } = await reader.read()\n if (done) break\n total += value.byteLength\n if (total > MAX_RESPONSE_BYTES) throw new Error(`${displayUrl(url)} overshoots the ${MAX_RESPONSE_BYTES}-byte listing ceiling`)\n chunks.push(value)\n }\n } finally {\n await reader.cancel().catch(() => {\n // Cancel after a drained read, or after this function walked away from\n // an oversized one, is cleanup; the reply is already decided either way.\n })\n }\n const body = new Uint8Array(total)\n let offset = 0\n for (const chunk of chunks) {\n body.set(chunk, offset)\n offset += chunk.byteLength\n }\n return new TextDecoder().decode(body)\n}\n\n/** Largest listing reply the probe accepts (same bound as official discovery). */\nconst MAX_RESPONSE_BYTES = 4 * 1024 * 1024\n\n/**\n * Normalize a supported listing reply into one entry array, mirroring the\n * official parser: the standard `data` array takes precedence; the\n * enriched `models` map uses each property key as the endpoint-facing id\n * (the nested `id` only falls back for an empty key \u2014 gateways may put a\n * canonical identity there instead of the alias they accept on requests);\n * only object-valued map entries are models, and entries without a usable id\n * are dropped. Returns undefined when the listing names neither shape.\n */\nfunction listingEntries(body: unknown): Record<string, unknown>[] | undefined {\n const listing = isRecord(body) ? body : {}\n const data = listing['data']\n if (Array.isArray(data)) return data.filter(isRecord)\n const models = listing['models']\n if (isRecord(models)) {\n return Object.entries(models)\n .filter(([, raw]) => isRecord(raw))\n .map(([key, raw]) => {\n // The map key is the endpoint-facing id, but an EMPTY key falls back\n // to the entry's own id exactly as the official parser's\n // label(key, entry.id) does \u2014 gateways may put the canonical identity\n // there instead of the alias they accept on requests.\n const entry = raw as Record<string, unknown>\n const ownId = typeof entry['id'] === 'string' && entry['id'].length > 0 ? entry['id'] : ''\n return { ...entry, id: key.length > 0 ? key : ownId }\n })\n .filter(entry => typeof entry['id'] === 'string' && entry['id'].length > 0)\n }\n return undefined\n}\n\n/**\n * The llm-service surface the default-guard wraps: only the two dispatch\n * entries, typed structurally so no new dependency is needed.\n */\ninterface LlmDispatchLike {\n prepareCall(config: Record<string, unknown>, signal?: unknown): Promise<Record<string, unknown>>\n stream(options: Record<string, unknown>): AsyncIterable<unknown>\n}\n\n/**\n * Fill one call config with the vendor default when it names no effort and\n * its declared ladder cannot switch thinking off (issue #2).\n *\n * Reads the resolved pi-ai section (never the user layer -- this only reads).\n * Fails open: any unreadable shape returns the config untouched, reproducing\n * today's behavior exactly.\n */\nfunction guardCallConfig(cfg: Record<string, unknown>, section: unknown): Record<string, unknown> {\n try {\n if (typeof cfg['reasoningEffort'] !== 'undefined') return cfg\n const provider = cfg['provider']\n const modelId = cfg['model']\n if (typeof provider !== 'string' || typeof modelId !== 'string') return cfg\n if (!isRecord(section)) return cfg\n const providers = section['providers']\n if (!isRecord(providers)) return cfg\n const profile = providers[provider]\n if (!isRecord(profile)) return cfg\n const rawModels = profile['models']\n if (!Array.isArray(rawModels)) return cfg\n const row = rawModels.find((candidate): candidate is Record<string, unknown> =>\n isRecord(candidate) && candidate['id'] === modelId)\n if (row === undefined || !isRecord(row['reasoningEfforts'])) return cfg\n const profileDefault = typeof profile['reasoning'] === 'string' ? profile['reasoning'] : undefined\n const facts = routeFactsOf({ providers: { [provider]: profile } }, provider)\n const suggestion = suggestEfforts(modelId, facts)\n const level = resolveGuardEffort({\n declared: row['reasoningEfforts'] as ReasoningEfforts,\n vendorDefault: suggestion.defaultEffort,\n profileDefault,\n requested: undefined,\n })\n return level === undefined ? cfg : { ...cfg, reasoningEffort: level }\n } catch {\n return cfg\n }\n}\n\n/**\n * Apply the plugin: autofill undeclared models on boot and after every commit\n * that touches the pi-ai namespace.\n * @param ctx - host context.\n */\nexport function apply(ctx: Context, config: Config = {}): void {\n // Cordis fills schema defaults; direct calls (tests) may omit fields.\n const resolved = {\n autofill: config.autofill !== false,\n modalityAutofill: config.modalityAutofill !== false,\n probeTimeoutMs: config.probeTimeoutMs ?? PROBE_TIMEOUT_MS,\n bootRetryDelaysMs: config.bootRetryDelaysMs ?? [...BOOT_RETRY_DELAYS_MS],\n defaultGuard: config.defaultGuard !== false,\n uaOverride: config.uaOverride !== false,\n }\n\n // Module-level `inject` already guarantees the settings service; using it\n // directly (instead of a redundant inner ctx.inject) keeps one dependency\n // declaration as the single source of truth.\n const settings = ctx.settings\n\n // The guard and probe route read the pi-ai section through this cached\n // closure slot. Describing every active form on every model call is both\n // needless work and, on 0.1.7+, can publish revision invalidation; retain the\n // last resolved section until the settings document reports that it moved.\n let piSectionCache: unknown\n let piSectionCached = false\n const piSection = (): unknown => {\n if (piSectionCached) return piSectionCache\n let value: unknown\n try {\n value = settings.describe().find(entry => entry.ns === PI_NS)?.value\n } catch {\n // The guard and probe are advisory: an unavailable settings form must\n // not turn a model call into a plugin failure.\n return undefined\n }\n // A missing namespace is expected during boot and must be retried.\n if (value === undefined) return undefined\n piSectionCache = value\n piSectionCached = true\n return value\n }\n ctx.on('settings/document-updated', (ns) => {\n if (ns === PI_NS) piSectionCached = false\n })\n\n if (resolved.autofill) {\n /** One autofill pass; resolves false while the pi-ai namespace is unregistered. */\n const autofillOnce = async (): Promise<boolean> => {\n const descriptor = settings.describe().find(entry => entry.ns === PI_NS)\n if (!isRecord(descriptor?.value)) return false\n // Build the patch from the RAW USER layer, never the resolved value:\n // the fill merges into the user document, and building from the\n // resolved view would materialize schema defaults / composition-base\n // models into it wholesale the moment pi-ai grows such layers for its\n // profile. A namespace whose user section holds no providers has\n // nothing this plugin may fill.\n const user = descriptor?.user\n const userProviders = isRecord(user) && isRecord(user['providers']) ? user['providers'] : undefined\n if (userProviders === undefined) return true\n const fullPatch = buildAutofillPatch(userProviders, () => true, { modalities: resolved.modalityAutofill }, descriptor?.revision ?? 0)\n if (fullPatch === undefined) return true\n // Optimistic lock: only write while the namespace has not moved past\n // this read. The fill is a background suggestion -- losing the race to a\n // user edit is fine; a later boot, or the browser half's idle pass,\n // simply fills whatever is still undeclared. Without the lock every fill\n // would bump the revision and invalidate the one the settings page read,\n // surfacing as SettingsConflictError on the next user save.\n try {\n await settings.update(PI_NS, fullPatch, descriptor?.revision)\n } catch (error) {\n const msg = String(error instanceof Error ? error.message : error)\n if (!looksLikeCompatRefusal(msg)) throw error\n const stripped = stripNewCompatKeysDeep(fullPatch)\n if (stripped === undefined) throw error\n await settings.update(PI_NS, stripped, settings.describe().find(entry => entry.ns === PI_NS)?.revision)\n }\n return true\n }\n\n /** Auto-fill must never break the settings pipeline; log and move on. */\n const logFailure = (error: unknown): void => {\n console.error(`[dsh-model-think-level] autofill failed: ${error instanceof Error ? error.message : String(error)}`)\n }\n\n // Pending boot-retry timers, cleared with the fiber (a disposed plugin\n // must not fire into a torn-down service graph).\n const timers = new Set<ReturnType<typeof setTimeout>>()\n ctx.effect(() => () => {\n for (const timer of timers) clearTimeout(timer)\n timers.clear()\n }, 'dsh-model-think-level: boot-fill retries')\n\n // Fill once at boot for models declared before this plugin was installed,\n // backing off exponentially while llm-pi-ai has not registered yet.\n const bootFill = (attempt: number): void => {\n void autofillOnce().then((ready) => {\n if (ready || attempt >= resolved.bootRetryDelaysMs.length) return\n const timer = setTimeout(() => {\n timers.delete(timer)\n bootFill(attempt + 1)\n }, resolved.bootRetryDelaysMs[attempt])\n timers.add(timer)\n }, logFailure)\n }\n bootFill(0)\n\n // Deliberately NOT re-run on `settings/document-updated`. The boot pass is safe\n // (no settings surface is open yet); a fill the moment a commit lands is\n // not: the official Models card freezes its own revision baseline while it\n // is open, so a background write there makes the user's very next save in\n // that card fail with `settings/conflict` and their edit reads as lost\n // (issue #7). The browser half carries the running complement instead: it\n // builds this SAME patch and writes it on its idle pass, once no card is\n // open. A headless composition has no editing surface to break and no\n // browser half either -- boot covers it.\n }\n\n // Default-guard (issue #2): wrap the llm dispatch entries so effort-less\n // calls to forced-thinking ladders ride the ladder's vendor default instead\n // of the wire's off-equivalent. Deferred inject: the wrap lands whenever\n // the llm service registers, and ctx.effect restores the originals on\n // dispose (disable/HMR leaves no trace).\n if (resolved.defaultGuard) {\n ctx.inject(['llm'], (llmCtx) => {\n const llm = (llmCtx as unknown as { llm?: unknown }).llm as LlmDispatchLike | undefined\n if (llm === undefined || typeof llm.prepareCall !== 'function' || typeof llm.stream !== 'function') return\n // Unbound originals: restore assigns back the exact references, and\n // dispatch keeps the service as receiver through .call.\n const origPrepare = llm.prepareCall\n const origStream = llm.stream\n llm.prepareCall = (callConfig, signal) => origPrepare.call(llm, guardCallConfig(callConfig, piSection()), signal)\n llm.stream = (options) => origStream.call(llm, guardCallConfig(options, piSection()))\n ctx.effect(() => () => {\n llm.prepareCall = origPrepare\n llm.stream = origStream\n }, 'dsh-model-think-level: default-guard')\n })\n }\n\n // Request-header takeover (issue #12): the official adapter can merge\n // attribution headers over the profile's own dictionary, so configured\n // values may be lost before the request reaches the wire. The plugin keeps\n // the fetch overlay as a compatibility fallback and also uses pi-ai's\n // request-level transform, which runs after auth/default headers are merged.\n // This mirrors the request-scoped header handling used by PI-Desktop and\n // covers SDK transports that do not call the current global fetch function.\n //\n // The index is keyed by the endpoint's ORIGIN and rebuilt from the live\n // settings section, so a route added, edited, or removed on the Models page\n // reaches the next request with no reload. `uaOverride: false` empties the\n // index instead of skipping the install: both seams stay installed and\n // simply stop matching anything.\n /** Live index the overlay reads; never undefined once apply has run. */\n const overlaySource: OverlaySource = { current: emptyIndex() }\n const headerRetryTimers = new Set<ReturnType<typeof setTimeout>>()\n let headerRetryAttempt = 0\n const stopHeaderRetries = (): void => {\n for (const timer of headerRetryTimers) clearTimeout(timer)\n headerRetryTimers.clear()\n headerRetryAttempt = 0\n }\n const scheduleHeaderRefresh = (refresh: () => void): void => {\n // A settings event may arrive while a retry is already pending. Keep one\n // timer per activation so repeated document notifications cannot accelerate\n // or multiply the boot retry sequence.\n if (headerRetryTimers.size > 0 || headerRetryAttempt >= resolved.bootRetryDelaysMs.length) return\n const delay = resolved.bootRetryDelaysMs[headerRetryAttempt]\n headerRetryAttempt += 1\n const timer = setTimeout(() => {\n headerRetryTimers.delete(timer)\n refresh()\n }, delay)\n headerRetryTimers.add(timer)\n }\n const refreshHeaders = (): void => {\n if (!resolved.uaOverride) {\n overlaySource.current = emptyIndex()\n stopHeaderRetries()\n return\n }\n const section = piSection()\n if (section === undefined) {\n // llm-pi-ai can register its settings namespace after this plugin. The\n // model probe has an independent direct-header path, but chat needs this\n // index ready before the adapter's first stream reaches fetch().\n overlaySource.current = emptyIndex()\n scheduleHeaderRefresh(refreshHeaders)\n return\n }\n stopHeaderRetries()\n const providers = isRecord(section) && isRecord(section['providers'])\n ? (section['providers'] as Record<string, Record<string, unknown>>)\n : {}\n overlaySource.current = buildHeaderIndex(providers)\n }\n refreshHeaders()\n ctx.effect(() => () => stopHeaderRetries(), 'dsh-model-think-level: header retries')\n ctx.on('settings/document-updated', (ns) => {\n if (ns === PI_NS) refreshHeaders()\n })\n const overlay = installHeaderOverlay(overlaySource)\n ctx.effect(() => () => { overlay.dispose() }, 'dsh-model-think-level: fetch header overlay')\n\n // `?diag=1` on the probe route reports this without touching the wire, so\n // the request-header takeover is observable from the running host.\n let headerBridgeState: () => unknown = () => ({ stage: 'not-installed' })\n const installPiAiBridge = (llm: unknown): void => {\n const transforms = installPiAiHeaderTransforms(llm, overlaySource)\n transforms.refresh()\n headerBridgeState = () => describePiAiHeaderState(llm, overlaySource)\n ctx.on('llm/adapters-updated', () => transforms.refresh())\n ctx.effect(() => () => transforms.dispose(), 'dsh-model-think-level: pi-ai request headers')\n }\n const availableLlm = (ctx as unknown as { llm?: unknown }).llm\n if (availableLlm === undefined) {\n // Direct callers and older hosts may omit llm from the module-level inject;\n // keep the deferred path as a compatibility fallback for those contexts.\n ctx.inject(['llm'], (llmCtx) => {\n const llm = (llmCtx as unknown as { llm?: unknown }).llm\n if (llm !== undefined) installPiAiBridge(llm)\n })\n } else {\n installPiAiBridge(availableLlm)\n }\n\n // Read once: what sits on disk changes only when the user installs or patches\n // something, and a restart is the honest moment to re-read it.\n const headerConflicts: HeaderConflictReport = detectHeaderConflicts()\n\n // Same-origin probe route: the browser half's Auto-adapt asks the endpoint's\n // RAW /models listing through here, because the sanctioned llm wire call\n // strips reasoning signals host-side. The credential resolves server-side\n // and never echoes back; only routes the user's own settings name are\n // reachable, and the trust fence rejects cross-site callers.\n ctx.inject(['webServer'], (webServerCtx) => {\n ctx.effect(\n () =>\n webServerCtx.webServer.register({\n kind: 'exact',\n path: PROBE_PATH,\n handler: async (req, res) => {\n if (!isTrustedRequest(req)) {\n sendJson(res, 403, { ok: false, error: 'forbidden' })\n return\n }\n if (req.method !== 'GET') {\n sendJson(res, 405, { ok: false, error: 'method not allowed' })\n return\n }\n const url = new URL(req.url ?? '/', 'http://x')\n // Read-only diagnostics: makes the request-header takeover\n // observable in the running host (which adapter is patched).\n if (url.searchParams.get('diag') === '1') {\n sendJson(res, 200, {\n ok: true,\n bridge: headerBridgeState(),\n overlay: {\n routes: overlaySource.current.routes.length,\n overrides: overlaySource.current.overrides.length,\n },\n })\n return\n }\n const route = url.searchParams.get('route') ?? ''\n const section = piSection()\n const profile = isRecord(section) && isRecord(section['providers'])\n ? section['providers'][route]\n : undefined\n if (!isRecord(profile)) {\n sendJson(res, 400, { ok: false, error: `no llm-pi-ai provider route \"${route}\"` })\n return\n }\n const baseURL = typeof profile['baseURL'] === 'string' ? profile['baseURL'] : ''\n if (baseURL.length === 0) {\n sendJson(res, 400, { ok: false, error: `provider route \"${route}\" has no baseURL` })\n return\n }\n // The profile's wire protocol selects the listing route and the\n // credential arm, exactly as the official discovery decides them:\n // only the protocols whose listing this mirror can read are\n // interrogated; everything else reports that it cannot.\n const api = typeof profile['api'] === 'string' ? profile['api'] : ''\n if (api.length === 0) {\n sendJson(res, 400, {\n ok: false,\n error: `provider route \"${route}\" names no API protocol to interrogate`,\n })\n return\n }\n if (!LISTABLE_PROTOCOLS.has(api)) {\n sendJson(res, 400, {\n ok: false,\n error: `protocol \"${api}\" cannot be interrogated; enter this provider's models by hand`,\n })\n return\n }\n const apiKeyEnv = typeof profile['apiKeyEnv'] === 'string' ? profile['apiKeyEnv'] : undefined\n const listingURL = probeListingUrl(baseURL, api)\n let apiKey: string | undefined\n if (apiKeyEnv !== undefined) {\n try {\n const credentials = ctx.get('credentials') as CredentialsService | undefined\n const hit = credentials === undefined ? undefined : await credentials.resolve(apiKeyEnv)\n apiKey = hit !== undefined && typeof hit.value === 'string' && hit.value.length > 0\n ? hit.value\n : undefined\n } catch {\n // Unresolvable credential: probe unauthenticated rather than fail.\n }\n }\n try {\n const upstream = await fetch(listingURL, {\n method: 'GET',\n // Header composition mirrors the harness's own model discovery:\n // the profile's configured request headers ride\n // along, so a deployment that authenticates through a custom\n // header probes here exactly as it lists officially \u2014 and an\n // Anthropic endpoint answers through x-api-key + a fixed\n // anthropic-version instead of a Bearer.\n headers: composeProbeHeaders(profile['headers'], apiKey, api),\n // A probe carries the user's stored credential, so it must\n // reach exactly the authority the profile names: Fetch's\n // default would FOLLOW a cross-origin redirect, and the\n // headers composed here (`x-api-key`, a profile's own auth\n // header) are not stripped on that hop the way `authorization`\n // is. Official discovery keeps the default; this route is\n // stricter on purpose, and the cost is bounded \u2014 a gateway\n // that lists only behind a redirect yields no endpoint\n // evidence, so Auto-adapt falls back to the knowledge base /\n // protocol inference, the path every unanswerable endpoint\n // takes.\n redirect: 'error',\n signal: AbortSignal.timeout(resolved.probeTimeoutMs),\n })\n if (!upstream.ok) {\n const hint = upstream.status === 401 || upstream.status === 403 ? '; check the API key' : ''\n sendJson(res, 502, { ok: false, error: `${displayUrl(listingURL)} answered ${upstream.status}${hint}` })\n return\n }\n const text = await readBounded(upstream, listingURL)\n let body: unknown\n try {\n body = JSON.parse(text) as unknown\n } catch {\n sendJson(res, 502, { ok: false, error: `${displayUrl(listingURL)} answered with a malformed JSON body` })\n return\n }\n // The official parser accepts the standard `data` array and the\n // enriched `models` map; entries are passed through verbatim so\n // the browser half sees the raw capability signals the sanctioned\n // wire call strips.\n const entries = listingEntries(body)\n if (entries === undefined) {\n sendJson(res, 502, {\n ok: false,\n error: `${displayUrl(listingURL)} model listing has neither a \"data\" array nor a \"models\" object`,\n })\n return\n }\n sendJson(res, 200, { ok: true, url: displayUrl(listingURL), data: entries })\n } catch (error) {\n sendJson(res, 502, {\n ok: false,\n error: `could not reach ${displayUrl(listingURL)}: ${error instanceof Error ? error.message : String(error)}`,\n })\n }\n },\n }),\n 'dsh-model-think-level: raw-models probe route',\n )\n\n // Read-only diagnostics for the request-header takeover. A path of its own\n // (rather than a flag on the probe route) so a reloaded plugin can answer\n // even while an older instance still owns the probe path.\n ctx.effect(\n () =>\n webServerCtx.webServer.register({\n kind: 'exact',\n path: DIAG_PATH,\n handler: (req, res) => {\n if (!isTrustedRequest(req)) {\n sendJson(res, 403, { ok: false, error: 'forbidden' })\n return\n }\n sendJson(res, 200, {\n ok: true,\n uaOverride: resolved.uaOverride,\n bridge: headerBridgeState(),\n overlay: {\n routes: overlaySource.current.routes.length,\n overrides: overlaySource.current.overrides.length,\n },\n })\n },\n }),\n 'dsh-model-think-level: header diagnostics route',\n )\n\n // Stored-credential route: the API-key field's eye calls it when the user\n // asks to see a key that is already saved. Every other route here keeps the\n // value host-side; this one hands it to the page on purpose, because the\n // official field is write-only by design \u2014 the settings document carries\n // only the profile's `apiKeyEnv` reference \u2014 so the affordance would\n // otherwise be a mask toggle with nothing behind it. The same trust fence\n // as the probe gates it, the value is never logged, and every answer is\n // `no-store` so neither the key nor the refusals (which name the route's\n // reference) can sit in a cache. The browser half asks only on a click, and\n // only for a card that names a route.\n ctx.effect(\n () =>\n webServerCtx.webServer.register({\n kind: 'exact',\n path: PROVIDER_KEY_PATH,\n handler: async (req, res) => {\n // Nothing this route answers may sit in a cache: not the key, and\n // not the refusals that name the route's credential reference.\n res.setHeader('cache-control', 'no-store')\n if (!isTrustedRequest(req)) {\n sendJson(res, 403, { ok: false, error: 'forbidden' })\n return\n }\n if (req.method !== 'GET') {\n sendJson(res, 405, { ok: false, error: 'method not allowed' })\n return\n }\n const url = new URL(req.url ?? '/', 'http://x')\n const route = url.searchParams.get('route') ?? ''\n const section = piSection()\n const profile = isRecord(section) && isRecord(section['providers'])\n ? section['providers'][route]\n : undefined\n if (!isRecord(profile)) {\n sendJson(res, 400, { ok: false, error: `no llm-pi-ai provider route \"${route}\"` })\n return\n }\n const apiKeyEnv = typeof profile['apiKeyEnv'] === 'string' ? profile['apiKeyEnv'] : undefined\n // A key-manager row names its own reference; the field's own eye\n // names none and means \"the key this provider is using\". A named\n // one is served only when the route's index lists it, so this route\n // can never become a resolver for arbitrary reference names.\n const named = url.searchParams.get('ref') ?? ''\n const ref = named.length > 0\n ? (named === apiKeyEnv || hasKeyEntry(readKeyIndex(keyIndexFilePath()), route, named) ? named : undefined)\n : apiKeyEnv\n if (ref === undefined) {\n sendJson(res, 404, {\n ok: false,\n error: named.length > 0\n ? `provider route \"${route}\" lists no key \"${named}\"`\n : `provider route \"${route}\" stores no credential reference`,\n })\n return\n }\n let value: string | undefined\n try {\n const credentials = ctx.get('credentials') as CredentialsService | undefined\n const hit = credentials === undefined ? undefined : await credentials.resolve(ref)\n value = hit !== undefined && typeof hit.value === 'string' && hit.value.length > 0\n ? hit.value\n : undefined\n } catch {\n value = undefined\n }\n if (value === undefined) {\n sendJson(res, 404, { ok: false, error: `no credential is configured for ${ref}` })\n return\n }\n sendJson(res, 200, { ok: true, key: value })\n },\n }),\n 'dsh-model-think-level: provider-key route',\n )\n\n // The API-key manager: one provider's list of keys, and which one is in use.\n //\n // Both halves of that list are host-side already \u2014 the values belong to the\n // harness credential store, and the reference the adapter actually resolves\n // is a field of the pi-ai profile \u2014 so this route owns the reads AND the\n // writes and the browser half only ever handles references, labels and\n // booleans. That is the same surface the official page works with, and it\n // needs no new Remote face to get it.\n ctx.effect(\n () =>\n webServerCtx.webServer.register({\n kind: 'exact',\n path: KEY_INDEX_PATH,\n handler: async (req, res) => {\n res.setHeader('cache-control', 'no-store')\n if (!isTrustedRequest(req)) {\n sendJson(res, 403, { ok: false, error: 'forbidden' })\n return\n }\n if (req.method !== 'GET' && req.method !== 'POST') {\n sendJson(res, 405, { ok: false, error: 'method not allowed' })\n return\n }\n const url = new URL(req.url ?? '/', 'http://x')\n const route = url.searchParams.get('route') ?? ''\n // Read the entry fresh rather than through the cached section: this\n // route writes to it, and an answer built from a pre-write snapshot\n // would show the user the state they just changed away from.\n const entryOf = (): { value: unknown; revision: number } | undefined => {\n try {\n const found = settings.describe().find(candidate => candidate.ns === PI_NS)\n return found === undefined ? undefined : { value: found.value, revision: found.revision }\n } catch {\n return undefined\n }\n }\n if (route.length === 0 || providerProfileOf(entryOf()?.value, route) === undefined) {\n sendJson(res, 400, { ok: false, error: `no llm-pi-ai provider route \"${route}\"` })\n return\n }\n const credentials = ctx.get('credentials') as CredentialsService | undefined\n const indexFile = keyIndexFilePath()\n\n /** The reference the profile names right now, read fresh. */\n const enabledNow = (): string | undefined => enabledRefOf(providerProfileOf(entryOf()?.value, route))\n\n /**\n * Hand the \"in use\" seat to one reference; undefined clears it. The\n * seat IS the profile's `apiKeyEnv`, so nothing else has to know\n * which key is active \u2014 every consumer of the profile, in the GUI or\n * not, resolves exactly the key the user enabled.\n * @param ref - reference to enable, or undefined to name none.\n * @returns The refusal text, or undefined when the write landed.\n */\n const setEnabledKey = async (ref: string | undefined): Promise<string | undefined> => {\n for (let attempt = 0; attempt < 2; attempt += 1) {\n const entry = entryOf()\n if (entry === undefined) return 'the llm-pi-ai settings entry is unavailable'\n try {\n await settings.mutate(\n PI_NS,\n ref === undefined\n ? [{ op: 'unset', path: ['providers', route, 'apiKeyEnv'] }]\n : [{ op: 'set', path: ['providers', route, 'apiKeyEnv'], value: ref }],\n entry.revision,\n )\n return undefined\n } catch (error) {\n // Another writer (the official card's Save, another tab, the\n // autofill pass) moved the document between this read and\n // this write: re-read once and fence on the new revision.\n if (attempt === 0 && isConflictError(error)) continue\n return error instanceof Error ? error.message : String(error)\n }\n }\n return 'the settings document kept changing; try again'\n }\n\n /** The whole list, as the browser half renders it. */\n const payload = async (): Promise<unknown> => {\n const enabledRef = enabledNow()\n const listed = keyEntriesOf(readKeyIndex(indexFile), route)\n const refs = listed.map(entry => entry.ref)\n // The key in use is always on the list, even when it was written\n // by the official page or by hand and this plugin has never seen\n // it: the panel must be able to show and act on what is active.\n if (enabledRef !== undefined && !refs.includes(enabledRef)) refs.push(enabledRef)\n const facts = await credentialFacts(credentials, refs)\n const entries: KeyEntryView[] = refs.map(ref => {\n const fact = facts[ref]\n const view: KeyEntryView = {\n ref,\n enabled: ref === enabledRef,\n configured: fact?.configured ?? null,\n }\n if (fact?.masked !== undefined) view.masked = fact.masked\n const stored = listed.find(candidate => candidate.ref === ref)\n if (stored?.alias !== undefined) view.alias = stored.alias\n return view\n })\n return { ok: true, route, enabledRef: enabledRef ?? null, entries }\n }\n\n if (req.method === 'GET') {\n sendJson(res, 200, await payload())\n return\n }\n\n const body = await readJsonBody(req)\n const op = isRecord(body) && typeof body['op'] === 'string' ? body['op'] : ''\n const ref = isRecord(body) && typeof body['ref'] === 'string' ? body['ref'] : undefined\n const alias = isRecord(body) ? normalizeKeyAlias(body['alias']) : undefined\n const value = isRecord(body) && typeof body['value'] === 'string' ? body['value'] : undefined\n // Every mutation is a set of steps that must not half-apply, so each\n // branch refuses BEFORE it writes anything it cannot undo.\n const refuse = (error: string): void => sendJson(res, 400, { ok: false, error })\n\n try {\n if (op === 'add') {\n if (!isLegalKeyValue(value)) {\n refuse('a key must be printable ASCII without spaces')\n return\n }\n const taken = keyEntriesOf(readKeyIndex(indexFile), route).map(candidate => candidate.ref)\n // The reference in use need not be listed \u2014 the official card\n // and a hand-edited profile both write one this plugin has never\n // seen \u2014 and minting it again would overwrite the very key the\n // provider is running on.\n const active = enabledNow()\n if (active !== undefined && !taken.includes(active)) taken.push(active)\n const created = nextKeyRef(route, taken)\n // The value goes into the store first: a reference the index\n // lists but the store cannot hold would render as a key the\n // user can never reveal, enable or remove.\n const refused = await storeCredential(credentials, created, value)\n if (refused !== undefined) {\n refuse(refused)\n return\n }\n updateKeyIndex(document => withKeyEntry(document, route, created, alias), indexFile)\n // The first key on a provider that names none is the key in\n // use: adding it is how a route becomes configured at all.\n if (enabledNow() === undefined) {\n const failed = await setEnabledKey(created)\n if (failed !== undefined) {\n refuse(failed)\n return\n }\n }\n } else if (op === 'enable') {\n const listed = readKeyIndex(indexFile)\n if (ref === undefined || !hasKeyEntry(listed, route, ref)) {\n refuse('that key is not listed for this provider')\n return\n }\n // Moving the seat must not take the key it leaves off the list:\n // that key was a row a moment ago, and unlisted it would fall out\n // of reach \u2014 and let a later add mint its name again, over the\n // value still sitting in the store.\n const previous = enabledNow()\n if (previous !== undefined && previous !== ref && !hasKeyEntry(listed, route, previous)) {\n const leaving: string = previous\n updateKeyIndex(\n document =>\n hasKeyEntry(document, route, leaving)\n ? document\n : withKeyEntry(document, route, leaving, undefined),\n indexFile,\n )\n }\n const failed = await setEnabledKey(ref)\n if (failed !== undefined) {\n refuse(failed)\n return\n }\n } else if (op === 'rename') {\n // The key the provider is RUNNING on takes a label too: that\n // reference is usually the one the official card wrote, which\n // this plugin has never listed. Writing it here is what puts it\n // on the list, so every later write matches an entry.\n const known =\n ref !== undefined &&\n (hasKeyEntry(readKeyIndex(indexFile), route, ref) || ref === enabledNow())\n if (ref === undefined || !known) {\n refuse('that key is not listed for this provider')\n return\n }\n const target = ref\n updateKeyIndex(\n document =>\n hasKeyEntry(document, route, target)\n ? withKeyAlias(document, route, target, alias)\n : withKeyEntry(document, route, target, alias),\n indexFile,\n )\n } else if (op === 'value') {\n const known =\n ref !== undefined &&\n (hasKeyEntry(readKeyIndex(indexFile), route, ref) || ref === enabledNow())\n if (ref === undefined || !known) {\n refuse('that key is not listed for this provider')\n return\n }\n if (!isLegalKeyValue(value)) {\n refuse('a key must be printable ASCII without spaces')\n return\n }\n // Only the secret moves: the reference keeps its name, its alias\n // and its seat. Removing and re-adding would mint a new ref, so\n // the profile would name a key the store no longer holds and the\n // row would lose everything but its value.\n const refused = await storeCredential(credentials, ref, value)\n if (refused !== undefined) {\n refuse(refused)\n return\n }\n } else if (op === 'remove') {\n const document = readKeyIndex(indexFile)\n if (ref === undefined || (!hasKeyEntry(document, route, ref) && ref !== enabledNow())) {\n refuse('that key is not listed for this provider')\n return\n }\n if (ref === enabledNow()) {\n // The seat is handed over BEFORE the value goes, so the\n // profile never names a key the store has just lost while\n // another listed key was available to take it. When none is,\n // the reference is unset rather than left dangling.\n const remaining = keyEntriesOf(document, route)\n .map(candidate => candidate.ref)\n .filter(candidate => candidate !== ref)\n const failed = await setEnabledKey(remaining[0])\n if (failed !== undefined) {\n refuse(failed)\n return\n }\n }\n const configured = (await credentialConfigured(credentials, [ref]))[ref]\n if (configured !== false) {\n const refused = await forgetCredential(credentials, ref)\n if (refused !== undefined) {\n refuse(refused)\n return\n }\n }\n updateKeyIndex(document2 => withoutKeyEntry(document2, route, ref), indexFile)\n } else {\n refuse(`unknown key operation \"${op}\"`)\n return\n }\n } catch (error) {\n sendJson(res, 500, { ok: false, error: error instanceof Error ? error.message : String(error) })\n return\n }\n sendJson(res, 200, await payload())\n },\n }),\n 'dsh-model-think-level: key index route',\n )\n\n // The autofill switches, for the browser half that runs the running\n // complement. Read-only and same-origin only, like the probe above: a\n // `dsh.client` declaration carries no plugin config, so without this route\n // a deployment configured `autofill: false` would still be written to from\n // the settings page.\n ctx.effect(\n () =>\n webServerCtx.webServer.register({\n kind: 'exact',\n path: AUTOFILL_CONFIG_PATH,\n handler: async (req, res) => {\n if (!isTrustedRequest(req)) {\n sendJson(res, 403, { ok: false, error: 'forbidden' })\n return\n }\n if (req.method !== 'GET') {\n sendJson(res, 405, { ok: false, error: 'method not allowed' })\n return\n }\n sendJson(res, 200, {\n ok: true,\n data: { autofill: resolved.autofill, modalityAutofill: resolved.modalityAutofill },\n })\n },\n }),\n 'dsh-model-think-level: autofill config route',\n )\n\n // The request-header overlay's status, for the browser half. Same-origin\n // and read-only, like the other two routes: the takeover lives host-side, so\n // the page needs this to say which routes it is changing and to warn about\n // another plugin rewriting the same surface.\n ctx.effect(\n () =>\n webServerCtx.webServer.register({\n kind: 'exact',\n path: HEADERS_CONFIG_PATH,\n handler: async (req, res) => {\n if (!isTrustedRequest(req)) {\n sendJson(res, 403, { ok: false, error: 'forbidden' })\n return\n }\n if (req.method !== 'GET') {\n sendJson(res, 405, { ok: false, error: 'method not allowed' })\n return\n }\n const index = overlaySource.current\n sendJson(res, 200, {\n ok: true,\n data: {\n /** Whether the fetch-layer takeover is enabled in this deployment. */\n enabled: resolved.uaOverride,\n /** Whether this plugin's wrapper currently owns the global fetch. */\n installed: headerOverlayInstalled(),\n /** Routes whose configured request headers are sent, by origin. */\n overrides: index.overrides.map(entry => ({\n origin: entry.origin,\n route: entry.route,\n headers: entry.headers,\n ...(entry.userAgent === undefined ? {} : { userAgent: entry.userAgent }),\n })),\n /** Same-origin routes with different User-Agent values. */\n conflicts: index.conflicts,\n /** Same-origin differences for any configured request header. */\n headerConflicts: index.headerConflicts,\n /** What was found of the plugins that rewrite the same surface. */\n environment: headerConflicts,\n },\n })\n },\n }),\n 'dsh-model-think-level: headers config route',\n )\n })\n}\n", "/**\n * Plugin-wide constants shared by the host and browser halves.\n *\n * @module dsh-model-think-level/constants\n */\n\n/** Stable plugin id, matching the cordis.patch.yml row and the bundle id. */\nexport const PLUGIN_ID = 'dsh-model-think-level'\n\n/** Same-origin host route that proxies a provider's RAW /models listing. */\nexport const PROBE_PATH = '/dsh-model-think-level/raw-models'\n/** Read-only diagnostics for the request-header takeover. */\nexport const DIAG_PATH = '/dsh-model-think-level/header-bridge'\n\n/**\n * Same-origin host route that resolves one provider profile's stored\n * credential, so the API-key field's eye can show a SAVED key.\n *\n * The harness keeps provider keys write-only on purpose: the settings document\n * carries only the profile's `apiKeyEnv` reference, and the credential service\n * reports `{ configured, source, writable }` through `describe()` \u2014 never the\n * value. Only the host can read it (`credentials.resolve()`), and it does so\n * for the request adapters; the browser normally never sees a stored key at\n * all. This route is the plugin's deliberate exception: an explicit,\n * user-initiated, same-fence read that answers with the value and is never\n * cached, so the eye can put it back into the official field.\n */\nexport const PROVIDER_KEY_PATH = '/dsh-model-think-level/provider-key'\n\n/**\n * Same-origin host route that owns a provider's list of API keys: their\n * references, their labels, and which one is in use.\n *\n * The harness has no notion of \"several keys for one provider\": a profile names\n * exactly one reference (`apiKeyEnv`) and a credential store holds exactly one\n * value per reference, with no enumeration and no label. Both facts are\n * deliberate \u2014 a configuration surface learns which references exist from its\n * settings schema \u2014 so a list of keys can only be plugin-owned state. It lives\n * in the harness home (`<DSH_HOME>/dsh-model-think-level/key-index.json`) rather\n * than in the pi-ai profile, so the official add-provider card, which writes the\n * WHOLE profile at `providers.<route>`, cannot drop it.\n *\n * The route both reads and writes: the values themselves still go to the\n * credential store through the host's own `credentials` service, so the browser\n * never needs a new Remote face.\n */\nexport const KEY_INDEX_PATH = '/dsh-model-think-level/key-index'\n\n/**\n * Same-origin host route that reports this plugin's autofill switches. The\n * browser half runs the running auto-fill complement, and a `dsh.client`\n * declaration carries no plugin config, so the two switches have to be read\n * from the host that owns the cordis row; without it a deployment that turned\n * `autofill: false` would still be written to from the page.\n */\nexport const AUTOFILL_CONFIG_PATH = '/dsh-model-think-level/autofill-config'\n\n/**\n * Same-origin host route reporting the request-header overlay (issue #12): the\n * routes whose `user-agent` the plugin is overriding, and what it found of the\n * plugins that rewrite the same surface. The browser half renders the\n * coexistence warning from here \u2014 the takeover lives host-side, so the page\n * cannot observe it on its own.\n */\nexport const HEADERS_CONFIG_PATH = '/dsh-model-think-level/headers-config'\n\n/** The settings namespace this plugin edits: pi-ai custom provider routes. */\nexport const PI_AI_NS = 'llm-pi-ai'\n\n/**\n * Model-level marker written when the user deliberately unsets the\n * declaration (\"back to inheritance\"). Schemastery passes unknown model keys\n * through, so the marker survives official-page saves and restarts \u2014 which is\n * the point: auto-fill must respect the absence as a decision, not as a gap\n * to fill.\n */\nexport const UNSET_MARKER = 'reasoningEffortsUnset'\n\n/**\n * Model-level marker for a deliberately unset input-modality declaration,\n * mirroring {@link UNSET_MARKER}: auto-fill must respect the absence of\n * `input` as a decision (the route default applies), not as a gap to fill.\n */\nexport const INPUT_UNSET_MARKER = 'inputUnset'\n\n/**\n * Model-level provenance marker written beside every ladder the HOST autofill\n * fills from the knowledge base, carrying the settings revision the fill read.\n *\n * It exists because the plugin's auto-fill and the user's staged declaration\n * race on the SAME row: whichever half runs the fill writes the knowledge base\n * suggestion, while the staged-declaration flush compares the document against\n * its own suggestion. By the time the flush looks, the suggestion may already\n * be stored -- and byte equality alone cannot tell \"the plugin wrote this\" from\n * \"the user declared this\", so a staged ladder differing from the knowledge\n * base in even one spelling (the editor's `off: null` against the knowledge\n * base's `off: 'none'`) was dropped as a document takeover: the reported\n * \"configured it on the add-provider card, saved, and it is gone\".\n *\n * With the marker the flush knows the stored ladder is a suggestion, so a\n * staged user intent overrides it. Either way the user's bytes win; the marker\n * only decides whether the flush is allowed to write at all. Schemastery passes\n * unknown model keys through, so the marker survives official-page saves and\n * restarts like the other two markers. Any ladder written through the plugin\n * clears it, which is what makes a later hand edit outrank a fresh staging.\n */\nexport const AUTOFILL_MARKER = 'reasoningEffortsAutofilled'\n\n/**\n * Model-level default-effort pick (issue #4): the level a brand-new session\n * starts this model at, outranking the remembered levels. The value is one of\n * the model's own declared ladder keys, or the field is absent when the user\n * has not picked one (memory chain applies). Deliberately NOT a harness\n * concept: pi-ai's runtime never sees it (unknown model keys ride the settings\n * document the way the other markers do), and the browser half is its only\n * consumer. The name matches the catalog's `reasoning.defaultEffort` spelling\n * so a future first-class field can adopt the stored values as-is.\n */\nexport const DEFAULT_EFFORT_FIELD = 'defaultEffort'\n\n/** Locale dictionary namespace for the browser half's copy (not a settings namespace). */\nexport const STORE_NS = PLUGIN_ID\n", "/**\n * The credential-reference vocabulary the API-key manager shares between both\n * halves.\n *\n * A provider's key list is a list of NAMES: every value lives in the harness\n * credential store under its own reference, and the profile records exactly one\n * of those names (`providers.<route>.apiKeyEnv`) as the reference the adapter\n * resolves when it calls the provider. This module owns the naming rules the\n * two halves must agree on \u2014 the browser half picks the next free name for a\n * new key, the host half re-validates whatever arrives \u2014 so one name can never\n * mean two different things on the two sides of the wire.\n *\n * Deliberately free of `node:` imports: the client bundle imports this module\n * too (the same way `constants.ts` is shared), and a single `node:` import\n * would drag the host into the browser build.\n *\n * @module dsh-model-think-level/key-refs\n */\n\n/** One key the manager lists for a provider route. */\nexport interface KeyEntry {\n /** Credential reference holding the value. */\n readonly ref: string\n /** User-facing label; absent means \"show the reference itself\". */\n readonly alias?: string\n}\n\n/** Longest reference the manager will mint or accept. */\nexport const KEY_REF_MAX_LENGTH = 80\n\n/** Longest alias the manager stores. A label, never a secret. */\nexport const KEY_ALIAS_MAX_LENGTH = 40\n\n/**\n * The shape of a reference the manager accepts. Looser than the credential\n * store's own POSIX-ish rule on purpose: a route may legitimately start with a\n * digit (`9router` \u2192 `9ROUTER_API_KEY`), and the store stays the authority on\n * what it will hold. This is the plugin's sanity bound, not the validation.\n */\nexport const KEY_REF_PATTERN = /^[A-Za-z0-9_]{1,80}$/\n\n/**\n * The reference the official Models page derives for a provider route: the\n * route upper-cased with every non-alphanumeric run folded to `_`, plus\n * `_API_KEY`. Mirrors the official page exactly so the first key the manager\n * adds for a provider is the very reference that page would have written.\n * @param route - the provider route key (`ofox`, `aliyun-cn`).\n * @returns the derived reference name.\n */\nexport function deriveKeyRef(route: string): string {\n return `${route.toUpperCase().replace(/[^A-Z0-9]+/g, '_')}_API_KEY`\n}\n\n/** Whether a value is a reference name this manager will pass to the store. */\nexport function isKeyRefName(value: unknown): value is string {\n return typeof value === 'string' && KEY_REF_PATTERN.test(value)\n}\n\n/**\n * The first free name in the sequence `<DERIVED>`, `<DERIVED>_2`, `<DERIVED>_3`\u2026\n * @param route - the provider route key.\n * @param taken - every reference already listed for that route.\n * @returns a reference not in `taken`.\n */\nexport function nextKeyRef(route: string, taken: readonly string[]): string {\n const used = new Set(taken)\n const base = deriveKeyRef(route)\n if (!used.has(base)) return base\n for (let suffix = 2; suffix <= 999; suffix += 1) {\n const candidate = `${base}_${suffix}`\n if (!used.has(candidate)) return candidate\n }\n // A thousand keys on one route is not a real deployment; stay unique anyway.\n return `${base}_${Date.now()}`\n}\n\n/**\n * A stored alias, or undefined when the label carries nothing.\n *\n * Control characters are dropped rather than escaped: an alias is rendered as\n * text on the official page, and a stray newline there is a rendering bug, not\n * data worth keeping.\n * @param value - whatever arrived (user input, or a hand-edited index file).\n * @returns the trimmed label, capped at {@link KEY_ALIAS_MAX_LENGTH}.\n */\nexport function normalizeKeyAlias(value: unknown): string | undefined {\n if (typeof value !== 'string') return undefined\n let cleaned = ''\n for (const char of value) {\n const code = char.codePointAt(0) ?? 0\n if (code < 32 || code === 127) continue\n cleaned += char\n }\n cleaned = cleaned.trim()\n if (cleaned.length === 0) return undefined\n return cleaned.slice(0, KEY_ALIAS_MAX_LENGTH)\n}\n\n/**\n * Whether a value is a key the official page would itself accept: printable\n * ASCII with no spaces (its own `LEGAL_API_KEY`). The manager applies the same\n * rule so a key it stores can never be one the official card would refuse.\n */\nexport function isLegalKeyValue(value: unknown): value is string {\n return typeof value === 'string' && /^[\\x21-\\x7E]+$/.test(value)\n}\n\n/** Shortest value that still gets a head and a tail; below it, a flat mask. */\nconst KEY_MASK_MIN_LENGTH = 12\n\n/**\n * A stored key's display form: a head, an ellipsis and a tail \u2014 enough to tell\n * two look-alike keys apart, never the whole secret.\n *\n * The manager shows every row this way, so a list can say which key a row holds\n * without putting anything usable on the page; the eye beside the field stays\n * the one gesture that reveals a value. A value too short to survive trimming\n * gets a fixed-width mask instead: at that length a head and a tail would be\n * most of the key.\n */\nexport function maskKeyValue(value: string): string {\n if (value.length === 0) return ''\n if (value.length < KEY_MASK_MIN_LENGTH) return '\u2022\u2022\u2022\u2022\u2022\u2022\u2022\u2022'\n return `${value.slice(0, 4)}...${value.slice(-4)}`\n}\n", "/**\n * The provider key index: plugin-owned metadata about the keys configured for\n * one provider route.\n *\n * The harness stores VALUES only: `<DSH_HOME>/.credentials.yaml` holds one value\n * per reference, the service reports `{configured, source, writable}` and never\n * the value, and there is no enumeration API at all. A list of \"the keys this\n * provider has\", each with a human label, therefore cannot live in the harness\n * \u2014 it is plugin state. It is kept here, beside the harness home rather than\n * inside the pi-ai profile, because the official add-provider card writes the\n * WHOLE profile at `providers.<route>` and an unknown sibling key there would\n * be at the mercy of schema validation.\n *\n * The file holds no secrets: references and labels only, which is what makes it\n * safe to keep in plain text and easy for a user to inspect or repair by hand.\n * Every read is defensive (a corrupted file degrades to \"nothing listed\") and\n * every write is atomic (`write` to a sibling temp file, then `rename`), so a\n * crash mid-write cannot leave a half-parsed index behind.\n *\n * All of it is synchronous on purpose: the host is single-threaded, so a\n * read-modify-write inside one request handler cannot interleave with another\n * request's, which is the whole concurrency story this file needs.\n *\n * @module dsh-model-think-level/key-index\n */\n\nimport { mkdirSync, readFileSync, renameSync, unlinkSync, writeFileSync } from 'node:fs'\nimport { homedir } from 'node:os'\nimport { dirname, join } from 'node:path'\nimport { normalizeKeyAlias, type KeyEntry } from './key-refs.js'\n\n/** One route's entry, re-exported so the host half has a single import site. */\nexport type KeyIndexEntry = KeyEntry\n\n/** The whole index document, exactly as it sits on disk. */\nexport interface KeyIndexDocument {\n /** Schema version; a future shape can migrate by reading this. */\n readonly version: 1\n /** Route \u2192 keys, in the order the manager lists them. */\n readonly providers: Record<string, readonly KeyIndexEntry[]>\n}\n\n/** A fresh, empty index. */\nexport function emptyKeyIndex(): KeyIndexDocument {\n return { version: 1, providers: {} }\n}\n\n/**\n * The harness home: `$DSH_HOME` when the host exports it, else the `~/.dsh`\n * the harness would have defaulted to. Never throws.\n */\nexport function harnessHome(): string {\n const configured = process.env['DSH_HOME']\n if (typeof configured === 'string' && configured.length > 0) return configured\n try {\n return join(homedir(), '.dsh')\n } catch {\n return '.dsh'\n }\n}\n\n/** Absolute path of the plugin's key index. */\nexport function keyIndexFilePath(home: string = harnessHome()): string {\n return join(home, 'dsh-model-think-level', 'key-index.json')\n}\n\n/**\n * Parse an already-decoded index document. Never throws and never trusts the\n * input: anything unrecognisable is dropped entry by entry, so a hand-edited or\n * truncated file costs at most the lines it got wrong.\n * @param raw - the decoded JSON value (or anything else).\n * @returns a well-formed document.\n */\nexport function parseKeyIndex(raw: unknown): KeyIndexDocument {\n if (typeof raw !== 'object' || raw === null) return emptyKeyIndex()\n const providers = (raw as Record<string, unknown>)['providers']\n if (typeof providers !== 'object' || providers === null) return emptyKeyIndex()\n const out: Record<string, KeyIndexEntry[]> = {}\n for (const [route, entries] of Object.entries(providers as Record<string, unknown>)) {\n if (route.length === 0 || !Array.isArray(entries)) continue\n const list: KeyIndexEntry[] = []\n for (const entry of entries) {\n if (typeof entry !== 'object' || entry === null) continue\n const record = entry as Record<string, unknown>\n const ref = record['ref']\n if (typeof ref !== 'string' || ref.length === 0) continue\n if (list.some(existing => existing.ref === ref)) continue\n const alias = normalizeKeyAlias(record['alias'])\n list.push(alias === undefined ? { ref } : { ref, alias })\n }\n if (list.length > 0) out[route] = list\n }\n return { version: 1, providers: out }\n}\n\n/** Read the index at one path, or an empty one when there is nothing to read. */\nexport function readKeyIndex(file: string = keyIndexFilePath()): KeyIndexDocument {\n try {\n return parseKeyIndex(JSON.parse(readFileSync(file, 'utf8')))\n } catch {\n // Missing, unreadable and malformed are the same answer here: the manager\n // opens with an empty list, and the profile's own enabled reference is\n // merged into what it lists anyway.\n return emptyKeyIndex()\n }\n}\n\n/** Write the index at one path, atomically. */\nexport function writeKeyIndex(document: KeyIndexDocument, file: string = keyIndexFilePath()): void {\n mkdirSync(dirname(file), { recursive: true })\n const temporary = `${file}.${process.pid}.tmp`\n writeFileSync(temporary, `${JSON.stringify(document, null, 2)}\\n`, 'utf8')\n try {\n renameSync(temporary, file)\n } catch (error) {\n try {\n unlinkSync(temporary)\n } catch {\n // The temp file is best-effort cleanup; the rename failure is the news.\n }\n throw error\n }\n}\n\n/**\n * One synchronous read-modify-write. The returned document is what was stored.\n * @param mutate - pure document transform.\n * @param file - index path (tests pass a temp file).\n */\nexport function updateKeyIndex(\n mutate: (document: KeyIndexDocument) => KeyIndexDocument,\n file: string = keyIndexFilePath(),\n): KeyIndexDocument {\n const next = mutate(readKeyIndex(file))\n writeKeyIndex(next, file)\n return next\n}\n\n/** One route's keys, or an empty list. */\nexport function keyEntriesOf(document: KeyIndexDocument, route: string): readonly KeyIndexEntry[] {\n const entries = document.providers[route]\n return Array.isArray(entries) ? entries : []\n}\n\n/** Whether one route's list names this reference. */\nexport function hasKeyEntry(document: KeyIndexDocument, route: string, ref: string): boolean {\n return keyEntriesOf(document, route).some(entry => entry.ref === ref)\n}\n\n/**\n * Add a key, or relabel the one already there. Order is preserved: the list is\n * what the panel renders, and a key that moves on every rename is a worse list.\n * @param document - the current document.\n * @param route - the provider route key.\n * @param ref - the credential reference.\n * @param alias - a label, or undefined to keep whatever is stored.\n */\nexport function withKeyEntry(\n document: KeyIndexDocument,\n route: string,\n ref: string,\n alias?: string | undefined,\n): KeyIndexDocument {\n const list = [...keyEntriesOf(document, route)]\n const index = list.findIndex(entry => entry.ref === ref)\n const label = normalizeKeyAlias(alias)\n const next: KeyIndexEntry = label === undefined ? { ref } : { ref, alias: label }\n if (index === -1) list.push(next)\n else list[index] = label === undefined && list[index]?.alias !== undefined ? { ref, alias: list[index]?.alias } : next\n return { version: 1, providers: { ...document.providers, [route]: list } }\n}\n\n/**\n * Set (or clear) one key's label.\n * @param document - the current document.\n * @param route - the provider route key.\n * @param ref - the credential reference; a no-op when it is not listed.\n * @param alias - the new label, or undefined to fall back to the reference.\n */\nexport function withKeyAlias(\n document: KeyIndexDocument,\n route: string,\n ref: string,\n alias: string | undefined,\n): KeyIndexDocument {\n const list = [...keyEntriesOf(document, route)]\n const index = list.findIndex(entry => entry.ref === ref)\n if (index === -1) return document\n const label = normalizeKeyAlias(alias)\n list[index] = label === undefined ? { ref } : { ref, alias: label }\n return { version: 1, providers: { ...document.providers, [route]: list } }\n}\n\n/**\n * Drop one key. The route key itself is removed once its list empties, so a\n * provider the user cleaned up leaves no residue in the file.\n * @param document - the current document.\n * @param route - the provider route key.\n * @param ref - the credential reference to forget.\n */\nexport function withoutKeyEntry(document: KeyIndexDocument, route: string, ref: string): KeyIndexDocument {\n const list = keyEntriesOf(document, route).filter(entry => entry.ref !== ref)\n const providers: Record<string, readonly KeyIndexEntry[]> = { ...document.providers }\n if (list.length === 0) delete providers[route]\n else providers[route] = list\n return { version: 1, providers }\n}\n", "/**\n * The reasoning-effort + input-modality knowledge base + wire-protocol\n * inference engine.\n *\n * Every model a third-party provider route serves must declare its\n * 'reasoningEfforts' (which DSH thinking levels it accepts, and the exact\n * string to send on the wire for each) before the composer's model picker\n * offers any reasoning control for it. This module answers \"what should this\n * model's declaration be?\" from three sources, in order:\n *\n * 1. An endpoint listing signal (when the route was probed): an explicit\n * \"does not reason\", a modality disclosure, or a context length.\n * 2. A curated knowledge base keyed by model id/name patterns, carrying the\n * exact level set, wire spellings, request modalities, and reference\n * capacities known to work against that family of endpoints.\n * 3. Wire-protocol inference from the route's 'api' / 'baseURL', plus a\n * conservative name heuristic for modalities, for families nothing else\n * names.\n *\n * All outputs stay on the adapter's own vocabulary (THINKING_LEVELS,\n * INPUT_MODALITIES, the reasoningEfforts/input dict shapes) so a suggested\n * declaration can be written to llm-pi-ai settings with no translation step.\n * A suggestion is a *preset*: the user can accept it, tune it, or ignore it.\n * The plugin never silently overwrites a declaration the user already made.\n *\n * @module dsh-model-think-level/knowledge\n */\n\n/** The canonical pi-ai escalation order accepted by llm-pi-ai. */\nexport const THINKING_LEVELS = ['off', 'minimal', 'low', 'medium', 'high', 'xhigh', 'max'] as const\n\nexport type ThinkingLevel = (typeof THINKING_LEVELS)[number]\n\n/**\n * The request-modality vocabulary llm-pi-ai accepts on a model entry -- a\n * local mirror of pi-ai's MODALITY_GATE (text/image today). The core schema\n * refuses anything else at write time, and its drift gate forces the\n * vocabulary to grow exactly when pi-ai's Model['input'] does; the vocabulary\n * spec pins this mirror against upstream so the UI follows.\n */\nexport const INPUT_MODALITIES = ['text', 'image'] as const\n\nexport type InputModality = (typeof INPUT_MODALITIES)[number]\n\n/** One level's wire spelling; null means \"send nothing for this level\". */\nexport type WireSpelling = string | null\n\n/** A full reasoning-effort declaration value: level -> wire spelling. */\nexport type ReasoningEfforts = Partial<Record<ThinkingLevel, WireSpelling>>\n\n/** A full input-modality declaration value: the modalities a model accepts. */\nexport type InputModalities = readonly InputModality[]\n\n/** Reasoning-budget request-field spellings pi-ai accepts (older kernels reject them). */\nexport const THINKING_TOKEN_BUDGET_FIELDS = ['thinking_token_budget', 'thinking_budget', 'thinking_budget_tokens'] as const\nexport type ThinkingTokenBudgetField = (typeof THINKING_TOKEN_BUDGET_FIELDS)[number]\n\n/** The compat fields this plugin may suggest (a subset of the profile schema). */\nexport interface CompatSuggestion {\n /** Wire format the endpoint speaks; omitted when unknown. */\n thinkingFormat?: string\n /** Whether the endpoint accepts a reasoning-effort-style parameter. */\n supportsReasoningEffort?: boolean\n /**\n * Whether pi-ai may rewrite the system prompt to the developer role for\n * reasoning models. Self-hosted relays get an explicit false (their\n * upstreams reject role:developer); official endpoints keep pi-ai's own\n * detection default by omitting the field.\n */\n supportsDeveloperRole?: boolean\n /**\n * Anthropic-messages protocol only: force adaptive thinking so the\n * declared efforts dispatch as `output_config.effort` instead of falling\n * into the older budget-based thinking path. pi-ai offers this field on\n * exactly the anthropic-messages compat gate, and the oracle models that\n * take an effort ladder all have adaptive thinking.\n */\n forceAdaptiveThinking?: boolean\n thinkingTokenBudgetField?: ThinkingTokenBudgetField\n supportsThinkingTokenBudget?: boolean\n vllmPriority?: number\n supportsMaxOutputTokens?: boolean\n}\n\nexport const NEW_COMPAT_KEYS = ['thinkingTokenBudgetField', 'vllmPriority', 'supportsMaxOutputTokens'] as const\n\n/** One knowledge-base entry: which model families it matches and what to declare. */\nexport interface KnowledgeEntry {\n /** Stable id (also used to de-duplicate user overrides). */\n id: string\n /** Model id/name patterns (lowercase substring match). */\n patterns: readonly string[]\n /**\n * Level set + wire spellings to declare. `false` marks a family the\n * official catalog serves WITHOUT any reasoning control (GPT-4o / GPT-4\n * generations): suggesting a ladder there would have the composer send\n * reasoning_effort and get a 400 from the real endpoint.\n */\n efforts: ReasoningEfforts | false\n /** Optional compat block to declare alongside the efforts. */\n compat?: CompatSuggestion\n /**\n * The model family takes an effort ladder on the anthropic-messages\n * protocol too: pi-ai only routes declared efforts to `output_config.effort`\n * when `forceAdaptiveThinking` is set, so this pin adds that compat block\n * on anthropic-messages routes (and nothing on any other protocol).\n */\n anthropicAdaptive?: boolean\n /**\n * Request modalities to declare, in core vocabulary. Absent = no modality\n * suggestion for this family. Wider support a gateway may serve (pdf,\n * audio, video) is recorded in 'note' until the core vocabulary grows.\n */\n input?: InputModalities\n /**\n * Reference context window in tokens (display-only advice; the official\n * capacity inputs are never auto-filled).\n */\n contextWindow?: number\n /** Reference max output tokens in tokens (display-only advice). */\n maxTokens?: number\n /**\n * The vendor's own default level for the family, when its docs name one\n * (the same research pass that recorded the ladders). Consumed by the\n * client's effort memory as the model-switch fallback: a switch to a model\n * with no remembered level re-applies the vendor default instead of leaving\n * the session on the host's \"Default\" (no-effort) state. Never guessed --\n * entries whose docs publish no default simply carry none.\n */\n defaultEffort?: ThinkingLevel\n /** Human note shown next to the suggestion (localized by the caller). */\n note?: string\n}\n\n/** What a provider route names about itself that inference can use. */\nexport interface RouteFacts {\n /** Wire protocol as configured ('api'), if any. */\n api?: string\n /** Endpoint URL, if any. */\n baseURL?: string\n /** Display name, if any. */\n displayName?: string\n}\n\n/** The endpoint facts a suggestion fuses, as the probe route reports them. */\nexport interface EndpointFacts {\n /** Tri-state reasoning signal: true / false / 'unknown' (listing silent). */\n reasoning: boolean | 'unknown'\n /** The listing field that produced the reasoning signal, null when none did. */\n source: string | null\n /**\n * The listing's input-modality disclosure, normalized to lowercase strings,\n * when the listing named such a field at all. Present-but-empty means the\n * field existed with no usable members; absent means the listing never\n * spoke about modalities (or the probe never ran) -- the tri-state\n * discipline: silence is not refusal.\n */\n input?: readonly string[]\n /** Context length the listing disclosed, when it carries one. */\n contextLength?: number\n}\n\n/** How a suggestion's input-modality part was derived. */\nexport type InputSource = 'knowledge' | 'endpoint' | 'heuristic'\n\n/** A resolved suggestion for one model on one route. */\nexport interface EffortSuggestion {\n /**\n * The reasoning-effort declaration to write, if one is derivable. False\n * arrives when the endpoint explicitly reports the model does not reason.\n */\n efforts?: ReasoningEfforts | false\n /**\n * The vendor's own default level for the model, when the knowledge base\n * names one and the suggested ladder carries it. The effort memory uses it\n * as the model-switch fallback (see {@link KnowledgeEntry.defaultEffort}).\n */\n defaultEffort?: ThinkingLevel\n /** The compat block to write alongside, if any. */\n compat?: CompatSuggestion\n /** Request modalities to declare, when derivable. */\n input?: InputModalities\n /** Where the modality part came from -- its confidence rides this. */\n inputSource?: InputSource\n /** Reference context window (display-only; never auto-filled anywhere). */\n contextWindow?: number\n /** Reference max output tokens (display-only). */\n maxTokens?: number\n /** Whether a knowledge-base entry matched (vs protocol inference). */\n matched: boolean\n /** The knowledge entry id when one matched. */\n entryId?: string\n /** Human-readable source of the suggestion. */\n source: string\n /**\n * Overall confidence for the UI: high = knowledge base (wire values) and/or\n * an explicit endpoint signal; medium = endpoint confirmed reasoning but the\n * level ladder is inferred; low = protocol inference alone.\n */\n confidence: 'high' | 'medium' | 'low'\n /** The endpoint signal behind this suggestion, when one was supplied. */\n endpoint?: { reasoning: boolean | 'unknown'; source: string | null }\n}\n\n/**\n * The curated knowledge base. Patterns are lowercase substring matches against\n * the model id (and display name). First match wins, longest pattern wins.\n *\n * Sources of truth (per family; DeepSeek / OpenAI / Anthropic re-checked\n * 2026-09 against their current official docs, the rest 2026-08): official API docs --\n * api-docs.deepseek.com (news/pricing/thinking/vision/API reference),\n * developers.openai.com model pages + guides (platform.openai.com blocked;\n * Azure learn mirror cross-checked), platform.claude.com (effort page,\n * models overview, OpenAI-SDK compatibility page), ai.google.dev (thinking +\n * OpenAI-compat pages), docs.x.ai (model pages + reasoning capability),\n * docs.bigmodel.cn (thinking + model pages), platform.kimi.com (models /\n * use-thinking-models / use-reasoning-effort), platform.stepfun.com (model\n * pages + reasoning), docs.byteplus.com / volcengine ModelArk (deep\n * reasoning), cloud.baidu.com (Qianfan pricing/thinking model list),\n * plus first-party GitHub cards (openai/gpt-oss, mistralai/mistral-common,\n * Tencent-Hunyuan/Hy3, MiniMax-AI/MiniMax-M3) -- cross-checked against the\n * public OpenRouter catalog (input_modalities, supported_parameters) where\n * noted. Capacities are REFERENCE values: aggregators disagree, so the note\n * says so where the spread is wide, and families whose numbers stay contested\n * simply carry none.\n */\nexport const KNOWLEDGE_BASE: readonly KnowledgeEntry[] = [\n {\n id: 'deepseek-v4-vision',\n // Must precede deepseek-v4 semantically -- guaranteed anyway by the\n // longest-boundary-hit rule, since these patterns are strictly longer.\n patterns: ['deepseek-v4-flash-vision', 'deepseek-v4-vision'],\n efforts: { off: 'none', low: 'low', high: 'high', max: 'max' },\n defaultEffort: 'high',\n compat: { thinkingFormat: 'deepseek', supportsReasoningEffort: true },\n input: ['text', 'image'],\n contextWindow: 1_048_576,\n maxTokens: 384_000,\n note: 'DeepSeek \u89C6\u89C9\u5B9E\u9A8C\u7248 id\uFF08deepseek-v4-flash-vision-exp\uFF09\u3002\u5B98\u65B9\u76EE\u5F55\u5DF2\u6807\u6CE8\u8BE5\u6A21\u578B\u9000\u5F79\uFF0C\u540D\u5B57\u4ECD\u88AB\u63A5\u53D7\u3001\u7531\u73B0\u884C deepseek-flash \u63D0\u4F9B\u670D\u52A1\u2014\u2014\u56FE\u7247\u8F93\u5165\u73B0\u5DF2\u7531 deepseek-flash \u539F\u751F\u63D0\u4F9B\u3002',\n },\n {\n id: 'deepseek-v4-1-flash',\n // V4.1-Flash is DeepSeek's CURRENT flagship and it takes image input, which\n // the shared `deepseek-v4` stem cannot express: that entry carries the text\n // floor its pro/legacy siblings share, and one modal answer cannot be both.\n // This entry keys every V4.1 spelling, and it must stay ahead of the base\n // stem -- the longest-hit rule guarantees that, these patterns are strictly\n // longer -- so an id, or a display name, that says \"V4.1 Flash\" declares\n // images even when the relay invented the id itself.\n // 'deepseek-flash' is the CURRENT official id (2026-09-10) and belongs\n // here, not to the stem: the pricing page serves it as V4.1-Flash, and a\n // third-party reseller exposing DeepSeek's own model under that name means\n // the same model.\n patterns: ['deepseek-v4.1-flash', 'deepseek-flash'],\n efforts: { off: 'none', low: 'low', high: 'high', max: 'max' },\n defaultEffort: 'high',\n compat: { thinkingFormat: 'deepseek', supportsReasoningEffort: true },\n input: ['text', 'image'],\n contextWindow: 1_048_576,\n maxTokens: 384_000,\n note: 'DeepSeek-V4.1-Flash\uFF082026-09-10 \u53D1\u5E03\u7684\u73B0\u884C\u5B98\u65B9\u6A21\u578B\uFF0C\u5B98\u65B9 id \u4E3A deepseek-flash\uFF1B25 \u4E07\u5E76\u53D1\u3001**\u539F\u751F\u56FE\u7247\u8F93\u5165**\uFF09\u3002V4.1 \u7684\u5404\u5199\u6CD5\uFF08deepseek-flash\u3001deepseek-v4.1-flash\u3001deepseek-v4-1-flash\uFF0C\u4EE5\u53CA\u5E26\u65E5\u671F\u540E\u7F00\u7684\u7B2C\u4E09\u65B9\u53D8\u4F53\uFF09\u90FD\u5F52\u6B64\u6761\u2014\u2014\u7EAF\u6587\u672C\u7684 deepseek-v4 \u4E3B\u5E72\u4E0D\u518D\u541E\u6389\u5B83\u4EEC\u3002\u5B98\u65B9\u679A\u4E3E\u540C V4 \u7CFB\uFF1AOff\uFF08thinking:\"disabled\"\uFF09/ Low / High / Max\uFF0C\u9ED8\u8BA4 High\uFF1B\u5BB9\u91CF 1,048,576 \u4E0A\u4E0B\u6587 / \u6700\u5927\u8F93\u51FA 384K\u3002',\n },\n {\n id: 'deepseek-v4',\n // One pattern covers the family's TEXT-floor members: every serving\n // suffixes the base id (deepseek-v4-flash, deepseek-v4-pro,\n // deepseek-v4-flash-free ...), so the shared stem keys them all --\n // including free/aggregator spellings the official catalog never lists.\n // Closing thinking is the 'thinking: disabled' object, so the off spelling\n // is a non-null placeholder that arms the deepseek format's disabled\n // branch. The placeholder must stay 'none': pi-ai's deepseek completions\n // branch only checks non-null (any string arms thinking:disabled), while\n // the same map rides the Responses API as reasoning.effort, whose official\n // DeepSeek values are none/low/high/max -- 'off' would be a 400 there.\n // The stem deliberately stops at 'deepseek-v4': the image-capable V4.1\n // generation keys its own strictly longer entry above, while this entry\n // keeps the retired deepseek-v4-flash spelling and the text-only\n // deepseek-v4-pro, whose declarations agree with its text floor.\n patterns: ['deepseek-v4'],\n efforts: { off: 'none', low: 'low', high: 'high', max: 'max' },\n defaultEffort: 'high',\n compat: { thinkingFormat: 'deepseek', supportsReasoningEffort: true },\n input: ['text'],\n contextWindow: 1_048_576,\n maxTokens: 384_000,\n note: 'DeepSeek \u5B98\u65B9\u679A\u4E3E Low / High / Max\uFF08\u9ED8\u8BA4 High\uFF1Bminimal\u3001medium\u3001xhigh \u517C\u5BB9\u6620\u5C04\uFF0Cultra\u2192max\uFF09\uFF0COff \u5373 thinking:\"disabled\"\uFF08Responses API \u4E0B off \u4EE5 reasoning.effort:\"none\" \u8868\u793A\uFF09\u3002\u672C\u6761\u76EE\u662F V4 \u5BB6\u65CF\u7684**\u7EAF\u6587\u672C**\u6210\u5458\uFF1Adeepseek-v4-pro\uFF08= DeepSeek-V4-Pro-0813\uFF0C\u5B98\u65B9\u4E0D\u652F\u6301\u56FE\u7247\uFF09\u4E0E\u5DF2\u9000\u5F79\u6A21\u578B\u7684\u517C\u5BB9\u522B\u540D deepseek-v4-flash\uFF08deepseek-v4-flash-vision-exp \u53E6\u6709\u89C6\u89C9\u6761\u76EE\uFF09\u3002**\u6536\u56FE\u7684 V4.1-Flash\uFF08\u5B98\u65B9 id deepseek-flash\uFF09\u53E6\u6709\u4E13\u95E8\u6761\u76EE**\uFF0C\u5176 input \u542B image\u3002\u5BB9\u91CF\uFF1A1,048,576 \u4E0A\u4E0B\u6587 / \u6700\u5927\u8F93\u51FA 384K\uFF08393,216\uFF1B\u9ED8\u8BA4\u975E\u601D\u8003 8K\u3001\u601D\u8003 64K\u3001effort=max \u65F6 128K\uFF09\u3002',\n },\n {\n id: 'deepseek-v3',\n // deepseek-reasoner belongs to the R1 entry: it is the reasoning model's\n // API name and must not match here. The old alias pair\n // (deepseek-chat / deepseek-reasoner) was retired upstream in 2026-07;\n // the id patterns stay for third-party gateways still serving V3.x.\n patterns: ['deepseek-v3', 'deepseek-chat'],\n efforts: { off: 'none', high: 'high', max: 'max' },\n compat: { thinkingFormat: 'deepseek', supportsReasoningEffort: true },\n input: ['text'],\n contextWindow: 163_840,\n maxTokens: 65_536,\n note: 'DeepSeek V3 \u6863\u4F4D\uFF1AOff / High / Max\u3002\u5B98\u65B9\u5DF2\u505C\u552E V3 \u4EE3\uFF08\u5B9A\u4EF7\u9875\u4EC5\u5269 V4 \u4E09\u578B\uFF09\uFF0C\u5BB9\u91CF\u53D6\u76EE\u5F55\u73B0\u5F79\u503C\u3002',\n },\n {\n id: 'deepseek-r1',\n patterns: ['deepseek-r1', 'deepseek-reasoner'],\n // R1's reasoning cannot be switched off at the API level; the harness\n // treats it as a thinking model whose only declared level is the default.\n efforts: { high: 'high' },\n defaultEffort: 'high',\n compat: { thinkingFormat: 'deepseek', supportsReasoningEffort: true },\n input: ['text'],\n contextWindow: 163_840,\n maxTokens: 32_768,\n note: 'DeepSeek-R1 \u4E3A\u63A8\u7406\u6A21\u578B\uFF0C\u4EC5\u63D0\u4F9B High\u3002\u5B98\u65B9\u5DF2\u4E0B\u67B6 R1 \u4EE3\uFF0C\u5BB9\u91CF\u53D6\u76EE\u5F55 r1-0528 \u503C\u3002',\n },\n {\n id: 'openai-gpt-5-2',\n patterns: ['gpt-5.2'],\n // gpt-5.2 (2025-12) took 'none' as the explicit no-thinking value\n // (replacing gpt-5's 'minimal') and added xhigh; its default is none.\n efforts: { off: 'none', low: 'low', medium: 'medium', high: 'high', xhigh: 'xhigh' },\n defaultEffort: 'off',\n compat: { thinkingFormat: 'openai', supportsReasoningEffort: true },\n input: ['text', 'image'],\n contextWindow: 400_000,\n maxTokens: 128_000,\n note: 'GPT-5.2 \u6863\u4F4D\uFF1ANone / Low / Medium / High / XHigh\uFF08\u9ED8\u8BA4 None\uFF09\u3002\u5B98\u65B9\u53E6\u652F\u6301 PDF \u8F93\u5165\uFF08\u6838\u5FC3\u8BCD\u8868\u6682\u4E0D\u542B\uFF09\u3002gpt-5.2-pro \u5B98\u65B9\u9875\u672A\u5355\u5217\u6863\u4F4D\u884C\uFF0C\u6309\u672C\u6761\u76EE\u540C\u6863\u5904\u7406\uFF1Bgpt-5.2-codex \u89C1\u5355\u72EC\u6761\u76EE\u3002',\n },\n {\n id: 'openai-gpt-5-2-codex',\n // The codex variant's official model page names low/medium/high/xhigh\n // only -- NO none -- so the shared gpt-5.2 entry must not claim an off\n // for it (a 'none' request would 400). Longer pattern wins over 'gpt-5.2'.\n patterns: ['gpt-5.2-codex'],\n efforts: { low: 'low', medium: 'medium', high: 'high', xhigh: 'xhigh' },\n // OpenAI's API default for the codex line is medium (Inspect AI's\n // per-model default table, aligned with developers.openai.com).\n defaultEffort: 'medium',\n compat: { thinkingFormat: 'openai', supportsReasoningEffort: true },\n input: ['text', 'image'],\n contextWindow: 400_000,\n maxTokens: 128_000,\n note: 'GPT-5.2-Codex \u6863\u4F4D\uFF1ALow / Medium / High / XHigh\uFF08\u65E0 None \u6863\uFF0C\u52FF\u52FE Off\uFF09\uFF0C\u5E26\u56FE\u8F93\u5165\u3001400K\u3002',\n },\n {\n id: 'openai-gpt-5-6',\n patterns: ['gpt-5.6'],\n // gpt-5.6 spans the full modern ladder including max; the sol/luna/terra\n // variants share it (official reasoning guide: values \"can include none\n // minimal low medium high xhigh, and max\").\n efforts: { off: 'none', low: 'low', medium: 'medium', high: 'high', xhigh: 'xhigh', max: 'max' },\n defaultEffort: 'medium',\n compat: { thinkingFormat: 'openai', supportsReasoningEffort: true },\n input: ['text', 'image'],\n contextWindow: 1_050_000,\n maxTokens: 128_000,\n note: 'GPT-5.6\uFF08\u522B\u540D\u5373 sol\uFF09\u6863\u4F4D\uFF1ANone / Low / Medium(\u9ED8\u8BA4) / High / XHigh / Max\uFF1Bsol/luna/terra \u540C\u6863\uFF0C\u5E26\u56FE\u8F93\u5165\u3002',\n },\n {\n id: 'openai-gpt-5-5',\n patterns: ['gpt-5.5'],\n // gpt-5.5 defaults to medium (official reasoning guide) and tops out at\n // xhigh; the -pro variant drops none/low (medium/high/xhigh only).\n efforts: { off: 'none', low: 'low', medium: 'medium', high: 'high', xhigh: 'xhigh' },\n defaultEffort: 'medium',\n compat: { thinkingFormat: 'openai', supportsReasoningEffort: true },\n input: ['text', 'image'],\n contextWindow: 1_050_000,\n maxTokens: 128_000,\n note: 'GPT-5.5 \u6863\u4F4D\uFF1ANone / Low / Medium(\u9ED8\u8BA4) / High / XHigh\uFF0C\u5E26\u56FE\u8F93\u5165\u3002pro \u53D8\u4F53\u4EC5 Medium / High(\u9ED8\u8BA4) / XHigh \u4E14\u4EC5 Responses API\u3002',\n },\n {\n id: 'openai-gpt-5-4',\n patterns: ['gpt-5.4'],\n // Official model page: none (default) / low / medium / high / xhigh;\n // pro drops none+low and is Responses-only; mini/nano sit on 400K.\n efforts: { off: 'none', low: 'low', medium: 'medium', high: 'high', xhigh: 'xhigh' },\n defaultEffort: 'off',\n compat: { thinkingFormat: 'openai', supportsReasoningEffort: true },\n input: ['text', 'image'],\n contextWindow: 1_050_000,\n maxTokens: 128_000,\n note: 'GPT-5.4 \u6863\u4F4D\uFF1ANone(\u9ED8\u8BA4) / Low / Medium / High / XHigh\uFF0C\u5E26\u56FE\u8F93\u5165\u3002pro \u53D8\u4F53\u4EC5 Medium/High/XHigh\uFF1Bmini/nano \u4E3A 400K \u4E0A\u4E0B\u6587\u3002',\n },\n {\n id: 'openai-gpt-5-3',\n patterns: ['gpt-5.3'],\n // Official model page: low / medium / high / xhigh only -- no none.\n efforts: { low: 'low', medium: 'medium', high: 'high', xhigh: 'xhigh' },\n defaultEffort: 'medium',\n compat: { thinkingFormat: 'openai', supportsReasoningEffort: true },\n input: ['text', 'image'],\n contextWindow: 400_000,\n maxTokens: 128_000,\n note: 'GPT-5.3-Codex \u6863\u4F4D\uFF1ALow / Medium / High / XHigh\uFF08\u65E0 None \u6863\uFF09\uFF0C\u5E26\u56FE\u8F93\u5165\u3001400K\uFF1Bgpt-5.3-chat \u4E3A\u975E\u63A8\u7406\u804A\u5929\u6A21\u578B\uFF08\u89C1 chat \u6761\u76EE\uFF09\u3002',\n },\n {\n id: 'openai-gpt-5-1',\n patterns: ['gpt-5.1'],\n // gpt-5.1 (2025-11): none replaces minimal; no xhigh outside codex-max.\n // The codex variants split into their own entry: their official pages\n // publish no effort line, and the codex line's 5.2/5.3 successors take\n // no none -- so the conservative declaration there drops both none and\n // xhigh (see openai-gpt-5-1-codex).\n efforts: { off: 'none', low: 'low', medium: 'medium', high: 'high' },\n defaultEffort: 'off',\n compat: { thinkingFormat: 'openai', supportsReasoningEffort: true },\n input: ['text', 'image'],\n contextWindow: 400_000,\n maxTokens: 128_000,\n note: 'GPT-5.1 \u6863\u4F4D\uFF1ANone / Low / Medium / High\uFF08\u9ED8\u8BA4 None\uFF09\u3002',\n },\n {\n id: 'openai-gpt-5-1-codex',\n // Official model pages for 5.1-codex / -codex-max / -codex-mini publish no\n // reasoning-effort line (unlike gpt-5.1 itself); the codex successors\n // 5.2/5.3 are low/medium/high/xhigh without none, so none is NOT declared\n // here either. xhigh is likewise unproven for 5.1-codex (the 5.1 page's\n // own ladder stops at high) and is withheld.\n patterns: ['gpt-5.1-codex'],\n efforts: { low: 'low', medium: 'medium', high: 'high' },\n compat: { thinkingFormat: 'openai', supportsReasoningEffort: true },\n input: ['text', 'image'],\n contextWindow: 400_000,\n maxTokens: 128_000,\n note: 'GPT-5.1-Codex \u7CFB\u5217\uFF1A\u5B98\u65B9\u6A21\u578B\u9875\u672A\u5355\u5217 effort \u503C\u57DF\uFF0C\u6309\u540C\u4EE3\u4FDD\u5B88\u6863 Low / Medium / High\uFF08\u65E0 None\uFF1Bxhigh \u672A\u8BC1\u5B9E\uFF09\u3002\u5982\u7AEF\u70B9\u652F\u6301 xhigh/none \u53EF\u624B\u8C03\u3002',\n },\n {\n id: 'openai-gpt-5',\n patterns: ['gpt-5'],\n // The 2025-08 first generation: minimal is the floor, there is no none,\n // and the default (medium) thinks -- so no off level is offered.\n efforts: { minimal: 'minimal', low: 'low', medium: 'medium', high: 'high' },\n defaultEffort: 'medium',\n compat: { thinkingFormat: 'openai', supportsReasoningEffort: true },\n input: ['text', 'image'],\n contextWindow: 400_000,\n maxTokens: 128_000,\n note: 'GPT-5 \u521D\u4EE3\u6863\u4F4D\uFF1AMinimal / Low / Medium / High\uFF0C\u65E0\u5173\u95ED\u6863\u3002',\n },\n {\n id: 'openai-chat',\n // Non-reasoning chat lines across generations: they take no\n // reasoning_effort at all (official model pages list no \"Reasoning\").\n // Official ids are the *-chat-latest snapshots; the bare -chat spellings\n // stay for gateways serving them. gpt-5-chat-latest was removed upstream\n // on 2026-07-23 and gpt-chat-latest has no model page anymore -- the\n // patterns persist for compatibility only.\n patterns: [\n 'gpt-5.1-chat-latest', 'gpt-5.2-chat-latest', 'gpt-5.3-chat-latest', 'gpt-5-chat-latest',\n 'gpt-chat-latest', 'gpt-5-chat', 'gpt-5.1-chat', 'gpt-5.2-chat', 'gpt-5.3-chat',\n ],\n efforts: false,\n input: ['text', 'image'],\n contextWindow: 128_000,\n maxTokens: 16_384,\n note: '-chat \u7CFB\u5217\uFF08\u5B98\u65B9 id \u4E3A gpt-5.x-chat-latest\uFF09\u4E3A\u975E\u63A8\u7406\u804A\u5929\u6A21\u578B\uFF0C\u4E0D\u652F\u6301 effort \u53C2\u6570\uFF08\u52FF\u52FE\u601D\u8003\u6863\uFF09\uFF1B\u5B98\u65B9\u652F\u6301\u56FE\u7247\u8F93\u5165\uFF0C128K / 16,384 \u8F93\u51FA\u3002gpt-5-chat-latest \u5DF2\u4E8E 2026-07-23 \u4E0B\u67B6\u3001gpt-chat-latest \u5DF2\u65E0\u5B98\u65B9\u9875\u9762\uFF08\u4FDD\u7559\u6A21\u5F0F\u4F9B\u7F51\u5173\uFF09\u3002',\n },\n {\n id: 'openai-o',\n // The o-series scheduled-removal notice (2026-06-11): o1/o1-pro/o3-mini/\n // o4-mini are removed 2026-10-23 and o3/o3-pro on 2026-12-11, with\n // gpt-5.6-sol / gpt-5.6-terra replacing them; the tokens stay for\n // gateways and local deployments still serving them, and match only on\n // word boundaries (see matchKnowledgeBase), so 'o1' hits 'o1-mini' but\n // not 'ko1'.\n patterns: ['o1', 'o3', 'o4'],\n // o-series had no none: not sending the parameter meant medium (think\n // on), so no off level is offered.\n efforts: { low: 'low', medium: 'medium', high: 'high' },\n defaultEffort: 'medium',\n compat: { thinkingFormat: 'openai', supportsReasoningEffort: true },\n input: ['text', 'image'],\n contextWindow: 200_000,\n maxTokens: 100_000,\n note: 'OpenAI o \u7CFB\u6863\u4F4D\uFF1ALow / Medium / High\u3002\u5B98\u65B9\u5DF2\u4E8E 2026-06 \u516C\u544A\u9000\u5F79\uFF08o1/o1-pro/o3-mini/o4-mini 2026-10-23 \u79FB\u9664\u3001o3/o3-pro 2026-12-11\uFF09\uFF0C\u7F51\u5173\u6B8B\u7559\u4ECD\u53EF\u547D\u4E2D\uFF1B\u591A\u6570 o \u7CFB\u7AEF\u70B9\u6536\u56FE\uFF08o3-mini \u4F8B\u5916\uFF09\u3002',\n },\n {\n id: 'openai-gpt-oss',\n // Official README: configurable reasoning effort low / medium / high\n // (CLI default: low); official model page: 131,072 context and exactly\n // the same 131,072 max output tokens, text input only.\n patterns: ['gpt-oss'],\n efforts: { low: 'low', medium: 'medium', high: 'high' },\n defaultEffort: 'low',\n compat: { thinkingFormat: 'openai', supportsReasoningEffort: true },\n input: ['text'],\n contextWindow: 131_072,\n maxTokens: 131_072,\n note: 'GPT-OSS \u5F00\u6E90\u6743\u91CD\uFF08Ollama/vLLM \u5E38\u89C1\uFF09\uFF1Areasoning effort Low / Medium / High\uFF0C\u7EAF\u6587\u672C\uFF0C131K \u4E0A\u4E0B\u6587 / 131K \u8F93\u51FA\u30022026-09 \u590D\u6838\uFF1A\u5B98\u65B9\u6A21\u578B\u9875\u73B0\u5728\u5199 Chat Completions = Not supported\u3001\u65E0\u56FE\u7247\u8F93\u5165\uFF08\u9ED8\u8BA4 Low \u6765\u81EA\u5B98\u65B9 CLI\uFF0C\u4E0D\u662F API \u9875\uFF09\uFF0C\u56E0\u6B64\u8FD9\u91CC\u4E0D\u518D\u58F0\u660E Off\u3002',\n },\n {\n id: 'openai-gpt-6-astra',\n // Longest-pattern-wins keeps this ahead of the 5.x entries; 'astra' is the\n // only stable token an aggregator is likely to expose.\n patterns: ['gpt-6-astra', 'gpt-6'],\n // Official reasoning guide: none returns HTTP 400 on this model, and the\n // model page lists low/medium/high/xhigh/max. Official docs publish no\n // default effort for it, so none is recorded rather than guessed.\n efforts: { low: 'low', medium: 'medium', high: 'high', xhigh: 'xhigh', max: 'max' },\n compat: { thinkingFormat: 'openai', supportsReasoningEffort: true },\n input: ['text', 'image'],\n contextWindow: 1_050_000,\n maxTokens: 128_000,\n note: 'GPT-6 Astra \u6863\u4F4D\uFF1ALow / Medium / High / XHigh / Max\u2014\u2014**\u6CA1\u6709 None \u6863**\uFF08\u5B98\u65B9\u539F\u6587\uFF1A\u8BBE\u4E3A none \u8FD4\u56DE HTTP 400\uFF09\uFF0C\u56E0\u6B64\u672C\u6761\u76EE\u4E0D\u58F0\u660E Off\u3002\u5E26\u56FE\u8F93\u5165\uFF0C1,050,000 \u4E0A\u4E0B\u6587 / 128,000 \u8F93\u51FA\uFF1BAI \u5B98\u65B9\u9ED8\u8BA4\u6863\u4F4D\u672A\u516C\u5E03\uFF0C\u6545\u4E0D\u586B\u3002\u5DE5\u5177\u8C03\u7528\u9700\u8D70 Responses API\u3002',\n },\n {\n id: 'openai-gpt-5-6-cyber',\n // Before the family entry: cyber's model page publishes NO effort line and\n // limits Chat Completions, so the family ladder (which includes none/max)\n // must not be offered for it.\n patterns: ['gpt-5.6-cyber'],\n // Conservative: the codex-style successors publish no none, and cyber's\n // page publishes nothing at all -- declare the intersection the other 5.6\n // variants agree on, plus xhigh (every published 5.6 ladder carries it).\n efforts: { low: 'low', medium: 'medium', high: 'high', xhigh: 'xhigh' },\n compat: { thinkingFormat: 'openai', supportsReasoningEffort: true },\n input: ['text', 'image'],\n contextWindow: 400_000,\n maxTokens: 128_000,\n note: 'GPT-5.6-Cyber\uFF1A\u5B98\u65B9\u6A21\u578B\u9875\u672A\u5355\u5217 effort \u503C\u57DF\uFF08\u4E0D\u7B49\u4E8E\u4E0D\u652F\u6301\uFF09\uFF0C\u6545\u6309\u540C\u4EE3\u4FDD\u5B88\u6863 Low / Medium / High / XHigh\uFF1B\u8BE5\u578B\u53F7\u4EC5 Responses API\uFF0C\u5E26\u56FE\u8F93\u5165\u3001400K \u4E0A\u4E0B\u6587\u3002\u5B98\u65B9\u652F\u6301\u7684\u5176\u4ED6\u6863\u4F4D\u53EF\u624B\u8C03\u540E\u5E94\u7528\u3002',\n },\n {\n id: 'openai-gpt-4o',\n // Boundary matching keeps 'gpt-4' from hitting 'gpt-4o', so the vision\n // generation needs its own entry. gpt-4.1 keeps its own entry below\n // (1M context, larger output cap).\n patterns: ['gpt-4o'],\n // GPT-4o is not a reasoning model (official catalog lists no reasoning,\n // the API refuses reasoning_effort): suggest `false` so the editor\n // marks the row \"does not reason\" instead of wiring a rejected ladder.\n efforts: false,\n input: ['text', 'image'],\n contextWindow: 128_000,\n maxTokens: 16_384,\n note: 'GPT-4o \u4EE3\u9645\uFF1A\u975E\u63A8\u7406\u6A21\u578B\uFF0C\u4E0D\u652F\u6301 effort \u53C2\u6570\uFF08\u52FF\u52FE\u601D\u8003\u6863\uFF09\uFF1B\u56FE\u7247\u8F93\u5165\u5168\u7CFB\u6807\u914D\uFF0C128K / 16,384 \u8F93\u51FA\u3002',\n },\n {\n id: 'openai-gpt-4-1',\n // Official model page: 1,047,576 context / 32,768 max output, text+image\n // on every variant (4.1 / mini / nano alike -- the old \"nano is\n // text-only\" claim was wrong). No reasoning step at all.\n patterns: ['gpt-4.1'],\n efforts: false,\n input: ['text', 'image'],\n contextWindow: 1_047_576,\n maxTokens: 32_768,\n note: 'GPT-4.1 \u5168\u7CFB\uFF08\u542B mini/nano\uFF09\uFF1A\u975E\u63A8\u7406\u6A21\u578B\uFF0C\u4E0D\u652F\u6301 effort \u53C2\u6570\uFF1B\u5B98\u65B9 1,047,576 \u4E0A\u4E0B\u6587 / 32,768 \u8F93\u51FA\uFF0C\u5168\u7CFB\u5E26\u56FE\u8F93\u5165\u3002',\n },\n {\n id: 'openai-gpt-4-turbo-preview',\n // The preview snapshot is text-only (later turbo snapshots take images;\n // the shared preview spelling must not claim them). Longest-boundary-hit\n // keeps it ahead of 'gpt-4-turbo'.\n patterns: ['gpt-4-turbo-preview'],\n efforts: false,\n input: ['text'],\n contextWindow: 128_000,\n maxTokens: 4_096,\n note: 'GPT-4 Turbo Preview\uFF1A\u975E\u63A8\u7406\u6A21\u578B\uFF0C\u7EAF\u6587\u672C\u8F93\u5165\uFF08\u6B63\u5F0F turbo \u5FEB\u7167\u652F\u6301\u56FE\u7247\uFF0C\u89C1\u4E0B\u6761\uFF09\uFF0C128K\u3002',\n },\n {\n id: 'openai-gpt-4-turbo',\n patterns: ['gpt-4-turbo'],\n efforts: false,\n input: ['text', 'image'],\n contextWindow: 128_000,\n maxTokens: 4_096,\n note: 'GPT-4 Turbo\uFF1A\u975E\u63A8\u7406\u6A21\u578B\uFF0C\u5B98\u65B9\u652F\u6301\u56FE\u7247\u8F93\u5165\uFF0C128K / 4,096 \u8F93\u51FA\u3002',\n },\n {\n id: 'openai-gpt',\n patterns: ['gpt-4', 'gpt-3.5'],\n // Same reasoning as gpt-4o above: the GPT-4/3.5 generations take no\n // reasoning_effort -- suggest `false` rather than a rejected ladder.\n // gpt-4 remains text-only (8K window); the vision-bearing 4o/4.1/turbo\n // lines have their own entries.\n efforts: false,\n input: ['text'],\n note: 'GPT-4/3.5 \u4EE3\u9645\uFF1A\u975E\u63A8\u7406\u6A21\u578B\uFF0C\u4E0D\u652F\u6301 effort \u53C2\u6570\uFF08\u52FF\u52FE\u601D\u8003\u6863\uFF09\u3002gpt-4-turbo/4.1 \u8D77\u652F\u6301\u56FE\u7247\uFF0C\u89C1\u5355\u72EC\u6761\u76EE\uFF1B\u65B0\u4EE3\u8BF7\u7528 GPT-5 \u7CFB\uFF08\u89C1 openai-chat/gpt-5.x \u6761\u76EE\uFF09\u3002',\n },\n {\n id: 'anthropic-claude-5',\n // Claude 5th generation (fable/mythos/opus-5/sonnet-5, 2026): adaptive\n // thinking with an effort ladder that adds xhigh and max; the fable and\n // mythos entries think always-on, so no off level. Mythos Preview is\n // split into its own entry: it takes max but NOT xhigh (official effort\n // matrix), so the shared ladder's xhigh would be a 400.\n patterns: ['claude-fable-5', 'claude-mythos-5', 'claude-opus-5', 'claude-sonnet-5'],\n // Ladder per the official effort matrix (platform.claude.com\n // docs/build-with-claude/effort). NOTE: Anthropic's own OpenAI-SDK\n // compatibility layer IGNORES reasoning_effort (thinking is driven by\n // its own param, on by default for Claude 5) -- the declaration bites\n // on third-party gateways that map it; on the native\n // anthropic-messages protocol, anthropicAdaptive pins the compat that\n // makes pi-ai dispatch these as output_config.effort.\n efforts: { low: 'low', medium: 'medium', high: 'high', xhigh: 'xhigh', max: 'max' },\n defaultEffort: 'high',\n // No thinkingFormat: pi-ai has no 'anthropic' member, and the\n // openai-completions compat gate that takes thinkingFormat is not the\n // protocol an Anthropic endpoint speaks.\n compat: { supportsReasoningEffort: true },\n anthropicAdaptive: true,\n input: ['text', 'image'],\n contextWindow: 1_000_000,\n maxTokens: 128_000,\n note: 'Claude 5 \u4EE3\uFF08Fable 5 / Mythos 5 / Opus 5 / Sonnet 5\uFF09\u6863\u4F4D\uFF1ALow / Medium / High(\u9ED8\u8BA4) / XHigh / Max\uFF1BFable 5.1 \u4E0E Mythos 5.1 \u89C1\u5355\u72EC\u6761\u76EE\uFF0CMythos Preview \u4EC5\u81F3 Max\u30021M \u4E0A\u4E0B\u6587 / 128K \u8F93\u51FA\uFF08Batch 300K\uFF09\u3002\u5B98\u65B9\u652F\u6301 PDF \u8F93\u5165\u3002\u6CE8\u610F\uFF1AAnthropic \u5B98\u65B9 OpenAI \u517C\u5BB9\u5C42\u4F1A\u5FFD\u7565 effort \u53C2\u6570\uFF0C\u58F0\u660E\u5728\u7B2C\u4E09\u65B9\u7F51\u5173\u6620\u5C04\u65F6\u751F\u6548\u3002',\n },\n {\n id: 'anthropic-claude-5-1',\n // Ahead of the claude-5 entry, whose 'claude-fable-5' / 'claude-mythos-5'\n // patterns are prefixes of these ids and would win the equal-length tie.\n // Same ladder and default as the 5.0 generation per the official effort\n // page; the meaningful difference is behavioural (these two are the\n // models allowed to change effort mid-conversation), which this plugin\n // does not declare per model.\n patterns: ['claude-fable-5-1', 'claude-mythos-5-1'],\n efforts: { low: 'low', medium: 'medium', high: 'high', xhigh: 'xhigh', max: 'max' },\n defaultEffort: 'high',\n compat: { supportsReasoningEffort: true },\n anthropicAdaptive: true,\n input: ['text', 'image'],\n contextWindow: 1_000_000,\n maxTokens: 128_000,\n note: 'Claude Fable 5.1 / Mythos 5.1\uFF1A\u5B98\u65B9\u6863\u4F4D Low / Medium / High(\u9ED8\u8BA4) / XHigh / Max\uFF0C\u81EA\u9002\u5E94\u601D\u8003\u5E38\u5F00\uFF08\u4E0D\u63A5\u53D7 enabled/disabled\uFF09\u30021M \u4E0A\u4E0B\u6587 / 128K \u8F93\u51FA\uFF1B\u8FD9\u4E24\u578B\u4E5F\u662F\u5B98\u65B9\u552F\u4E00\u5141\u8BB8\u4F1A\u8BDD\u4E2D\u9014\u6539\u6863\u7684\uFF08\u9700 beta header\uFF0C\u672C\u63D2\u4EF6\u4E0D\u6D89\u53CA\uFF09\u3002',\n },\n {\n id: 'anthropic-claude-mythos-preview',\n // Official effort matrix: max is available, xhigh is NOT (the matrix's\n // xhigh list covers Fable 5 / Mythos 5 / Opus 5 / Opus 4.8 / Opus 4.7 /\n // Sonnet 5 only).\n patterns: ['claude-mythos-preview'],\n efforts: { low: 'low', medium: 'medium', high: 'high', max: 'max' },\n // Anthropic's effort page: the API default is HIGH across the whole\n // supported list (omitting effort behaves exactly as high).\n defaultEffort: 'high',\n compat: { supportsReasoningEffort: true },\n anthropicAdaptive: true,\n input: ['text', 'image'],\n contextWindow: 1_000_000,\n maxTokens: 128_000,\n note: 'Claude Mythos Preview\uFF1A\u5B98\u65B9\u6863\u4F4D Low / Medium / High / Max\uFF08\u65E0 XHigh\uFF09\uFF0C1M \u4E0A\u4E0B\u6587\u3002',\n },\n {\n id: 'anthropic-claude-opus-4-high',\n patterns: ['claude-opus-4-8', 'claude-opus-4-7'],\n // Official effort page: Opus 4.7/4.8 take the full ladder including\n // xhigh and max (xhigh is the recommended coding start on 4.7).\n efforts: { low: 'low', medium: 'medium', high: 'high', xhigh: 'xhigh', max: 'max' },\n defaultEffort: 'high',\n compat: { supportsReasoningEffort: true },\n anthropicAdaptive: true,\n input: ['text', 'image'],\n contextWindow: 1_000_000,\n maxTokens: 128_000,\n note: 'Claude Opus 4.7/4.8 \u6863\u4F4D\uFF1ALow / Medium / High(\u9ED8\u8BA4) / XHigh / Max\uFF1Bxhigh \u4E3A\u5B98\u65B9\u63A8\u8350\u7684\u7F16\u7801\u8D77\u6B65\u6863\u30021M \u4E0A\u4E0B\u6587\u3002',\n },\n {\n id: 'anthropic-claude-4-6',\n patterns: ['claude-opus-4-6', 'claude-sonnet-4-6'],\n // Official effort page: the 4.6 generation supports max but NOT xhigh\n // (\"some models that support max don't support xhigh\").\n efforts: { low: 'low', medium: 'medium', high: 'high', max: 'max' },\n defaultEffort: 'high',\n compat: { supportsReasoningEffort: true },\n anthropicAdaptive: true,\n input: ['text', 'image'],\n contextWindow: 1_000_000,\n maxTokens: 128_000,\n note: 'Claude 4.6 \u4EE3\u6863\u4F4D\uFF1ALow / Medium / High / Max\uFF08\u65E0 XHigh\u2014\u2014\u5B98\u65B9\u660E\u8A00\u300C\u652F\u6301 max \u7684\u90E8\u5206\u578B\u53F7\u4E0D\u652F\u6301 xhigh\u300D\uFF09\u30021M \u4E0A\u4E0B\u6587\u3002',\n },\n {\n id: 'anthropic-claude-opus-4-5',\n // The only extended-thinking-only model in Anthropic's official effort\n // support list (claude-opus-4-5-20251101): effort works alongside\n // budget_tokens, and the max/xhigh columns of the official matrix do not\n // name it -- so the ladder tops out at high.\n patterns: ['claude-opus-4-5'],\n efforts: { low: 'low', medium: 'medium', high: 'high' },\n defaultEffort: 'high',\n compat: { supportsReasoningEffort: true },\n input: ['text', 'image'],\n contextWindow: 200_000,\n maxTokens: 64_000,\n note: 'Claude Opus 4.5\uFF1A\u5B98\u65B9 effort \u652F\u6301\u5217\u8868\uFF0820251101 \u5FEB\u7167\uFF09\uFF0C\u6863\u4F4D Low / Medium / High\uFF08\u65E0 XHigh/Max\uFF09\uFF0C\u53EF\u4E0E budget_tokens \u5E76\u7528\uFF1B200K / 64K\u3002',\n },\n {\n id: 'anthropic-claude',\n // Everything else in the Claude line: 3.x and the 4.5-generation\n // Sonnet/Haiku. Anthropic's official effort support list names exactly\n // fable-5 / mythos-5 / mythos-preview / opus-5 / opus-4-8 / opus-4-7 /\n // opus-4-6 / sonnet-5 / sonnet-4-6 / opus-4-5-20251101 -- none of the\n // models matching this entry take the effort parameter (their thinking\n // rides thinking.type), so a ladder here would be refused. `false` is\n // the honest \"no effort control\" declaration, matching the openai-chat\n // convention.\n patterns: ['claude'],\n efforts: false,\n input: ['text', 'image'],\n contextWindow: 200_000,\n maxTokens: 64_000,\n note: 'Claude 3.x \u4E0E Sonnet 4.5 / Haiku 4.5\uFF1A\u5B98\u65B9 effort \u53C2\u6570\u4E0D\u652F\u6301\uFF08\u4EC5 Fable/Mythos 5\u3001Opus 5/4.6-4.8\u3001Sonnet 5/4.6\u3001Opus 4.5 \u652F\u6301\uFF09\uFF0C\u601D\u8003\u7531 thinking.type \u63A7\u5236\u2014\u2014\u52FF\u52FE\u601D\u8003\u6863\u3002\u53C2\u8003\u5BB9\u91CF 200K / 64K\uFF08Haiku 3.5 \u4E3A\u7EAF\u6587\u672C\uFF0C\u6309\u9700\u53D6\u6D88\u56FE\u7247\uFF09\u3002',\n },\n {\n id: 'google-gemini',\n patterns: ['gemini'],\n // Gemini over the OpenAI-compat layer maps reasoning_effort per family\n // (3.1+/3.x -> thinking_level, 2.5 -> thinking_budget). The official\n // compatibility sheet is a full grid (minimal / low / medium / high x\n // family), but the declared ladder stays low/medium/high: the safest\n // universal set, since minimal lands on a non-native value on Gemini\n // 3.1 Pro and none is reserved for 2.5 non-Pro. Users wanting the finer\n // grid tune by hand.\n efforts: { low: 'low', medium: 'medium', high: 'high' },\n compat: { thinkingFormat: 'openai', supportsReasoningEffort: true },\n input: ['text', 'image'],\n contextWindow: 1_048_576,\n maxTokens: 65_536,\n note: 'Gemini \u901A\u7528\u5B89\u5168\u6863\uFF1ALow / Medium / High\uFF08\u5B98\u65B9 OpenAI \u517C\u5BB9\u6620\u5C04\u8868\u53E6\u6536 minimal\uFF1A2.5 \u7CFB\u6620\u5C04\u4E3A 1,024 \u9884\u7B97\u30013.1 Flash-Lite/3 Flash \u539F\u751F minimal\u30013.1 Pro \u843D low\uFF09\u3002none \u4EC5\u80FD\u5173 2.5 \u975E Pro\uFF1B2.5 Pro \u4E0E 3 \u4EE3\u4E0D\u53EF\u5173\uFF1B\u5404\u578B\u9ED8\u8BA4\u4E0D\u4E00\uFF08flash-lite \u9ED8\u8BA4\u5173\uFF09\u3002\u5B98\u65B9\u53E6\u6536\u97F3\u9891/\u89C6\u9891/PDF\u3002',\n },\n {\n id: 'xai-grok-4-7',\n // grok-4.7 shipped after the 2026-08 pass that read it as 404 upstream;\n // that reading is retired here. xAI's own docs were unreachable for this\n // pass, so every field below is a public-catalog reading rather than a\n // first-party one: OpenRouter publishes the slug x-ai/grok-4.7 with\n // reasoning_effort in its supported_parameters, and models.dev records\n // the ladder as low/medium/high/xhigh -- the same four steps 4.6 takes,\n // which is why the same declaration shape is reused. The default level\n // and whether thinking can be closed are NOT established, so neither an\n // `off` nor a defaultEffort is declared. Capacity follows the sources\n // that agree (500K context); max output disagrees across catalogs\n // (450K vs 500K), so it stays out.\n patterns: ['grok-4.7'],\n efforts: { low: 'low', medium: 'medium', high: 'high', xhigh: 'xhigh' },\n compat: { thinkingFormat: 'openai', supportsReasoningEffort: true },\n input: ['text', 'image'],\n contextWindow: 500_000,\n note: 'Grok 4.7\uFF08\u4E0A\u6E38\u5FEB\u7167 grok-4.7-20260916\uFF09\uFF1A\u6863\u4F4D Low / Medium / High / XHigh\u2014\u2014**\u53D6\u81EA\u516C\u5F00\u76EE\u5F55**\uFF08OpenRouter \u7684 supported_parameters\u3001models.dev \u5BF9 docs.x.ai \u7684\u8F6C\u8FF0\uFF09\uFF0C\u672C\u6B21 xAI \u5B98\u65B9\u6587\u6863\u7AD9\u4E0D\u53EF\u8FBE\u3001\u672A\u80FD\u4E00\u624B\u8BC1\u5B9E\uFF1B\u9ED8\u8BA4\u6863\u4F4D\u4E0E\"\u80FD\u5426\u5173\u95ED\u601D\u8003\"\u540C\u6837\u672A\u8BC1\u5B9E\uFF0C\u6545\u4E0D\u58F0\u660E Off\uFF0C\u4E5F\u4E0D\u5199\u9ED8\u8BA4\u6863\u3002\u5E26\u56FE\u8F93\u5165\uFF08\u76EE\u5F55\u8BB0 text+image+file\uFF0CPDF \u5B58\u7591\uFF09\uFF0C500K \u4E0A\u4E0B\u6587\uFF1B\u6700\u5927\u8F93\u51FA\u5404\u76EE\u5F55\u7ED9\u51FA 450K \u4E0E 500K \u4E24\u79CD\u503C\uFF0C\u6309\"\u5206\u6B67\u5373\u4E0D\u5199\"\u5904\u7406\u30022026-08 \u90A3\u6B21\"grok-4.7 \u4E0D\u5B58\u5728\uFF08\u5B98\u65B9 404\uFF09\"\u7684\u7ED3\u8BBA\u5DF2\u968F\u53D1\u5E03\u4F5C\u5E9F\u3002',\n },\n {\n id: 'xai-grok-high',\n patterns: ['grok-4.6'],\n // grok-4.6 adds xhigh on top of low/medium/high (default) and cannot\n // close thinking (docs.x.ai model page + reasoning capability page).\n // (An earlier pass read grok-4.7 as 404 upstream; it shipped later --\n // see the entry above.)\n efforts: { low: 'low', medium: 'medium', high: 'high', xhigh: 'xhigh' },\n defaultEffort: 'high',\n compat: { thinkingFormat: 'openai', supportsReasoningEffort: true },\n input: ['text', 'image'],\n contextWindow: 500_000,\n note: 'Grok 4.6 \u6863\u4F4D\uFF1ALow / Medium / High(\u9ED8\u8BA4) / XHigh\uFF0C\u601D\u8003\u4E0D\u53EF\u5173\u95ED\uFF1B\u5E26\u56FE\u8F93\u5165\u3001500K \u4E0A\u4E0B\u6587\u3002Grok 4.7 \u89C1\u4E0A\u4E00\u6761\uFF08\u6B64\u524D\u8BB0\u4E3A\"\u4E0D\u5B58\u5728\"\uFF0C\u5DF2\u968F\u53D1\u5E03\u4F5C\u5E9F\uFF09\u3002',\n },\n {\n id: 'xai-grok-4-5',\n // grok-4.5 keeps the three-step ladder (default high) with image input\n // and a 500K context window; an xhigh request is silently treated as\n // high (official reasoning page), so it is not declared here.\n patterns: ['grok-4.5'],\n efforts: { low: 'low', medium: 'medium', high: 'high' },\n defaultEffort: 'high',\n compat: { thinkingFormat: 'openai', supportsReasoningEffort: true },\n input: ['text', 'image'],\n contextWindow: 500_000,\n note: 'Grok 4.5 \u6863\u4F4D\uFF1ALow / Medium / High(\u9ED8\u8BA4)\uFF0C\u601D\u8003\u4E0D\u53EF\u5173\u95ED\uFF1B\u5E26\u56FE\u8F93\u5165\u3002\u4F20\u5165 xhigh \u4F1A\u88AB\u5B98\u65B9\u9759\u9ED8\u6309 High \u5904\u7406\u3002',\n },\n {\n id: 'xai-grok-4-3',\n // Official reasoning-capability pages: grok-4.3 documents FOUR effort\n // levels (none / low / medium / high) with a 1M context window; the\n // deprecated grok-4-fast/grok-4-1-fast/grok-4-0709 slugs redirect to\n // grok-4.3 at low/none. The old \"no none for 4.3\" reading of the docs\n // was wrong and is fixed here.\n patterns: ['grok-4.3'],\n // Official models page (docs.x.ai model JSON): supportedEfforts now\n // spans none/low/medium/high/XHIGH with defaultEffort \"low\" -- xhigh\n // joined the ladder after the 2026-08 pass, and low is the default.\n efforts: { off: 'none', low: 'low', medium: 'medium', high: 'high', xhigh: 'xhigh' },\n defaultEffort: 'low',\n compat: { thinkingFormat: 'openai', supportsReasoningEffort: true },\n input: ['text', 'image'],\n contextWindow: 1_000_000,\n note: 'Grok 4.3\uFF1A\u5B98\u65B9\u56DB\u7EA7 reasoning effort\uFF08None / Low / Medium / High\uFF09\uFF0C1M \u4E0A\u4E0B\u6587\u3001\u5E26\u56FE\u8F93\u5165\uFF1Bgrok-4-fast \u7B49\u65E7 slug 2026-05-15 \u8D77\u81EA\u52A8\u91CD\u5B9A\u5411\u5230\u672C\u578B\u53F7\u3002',\n },\n {\n id: 'xai-grok',\n // grok-4.5 (and 4.1-fast etc.) take the standard three-step ladder;\n // grok-4 and older reject reasoning_effort outright -- gateways serving\n // them will refuse the value and the user can clear it by hand. Grok\n // 4/4.1 and grok-3 retired 2026-05-15 (redirected to grok-4.3), and\n // grok-build-0.1 (early-access coding model) publishes no effort\n // contract.\n patterns: ['grok'],\n efforts: { low: 'low', medium: 'medium', high: 'high' },\n compat: { thinkingFormat: 'openai', supportsReasoningEffort: true },\n input: ['text'],\n note: 'Grok \u901A\u7528\u6863\u4F4D\uFF1ALow / Medium / High\u3002\u521D\u4EE3 grok-4\u3001grok-4.20 \u4E0E grok-build-0.1 \u4E0D\u63A5\u53D7\u8BE5\u53C2\u6570\uFF08grok-4 \u7CFB\u4E0E grok-3 \u5DF2\u4E8E 2026-05-15 \u9000\u5F79\u5E76\u91CD\u5B9A\u5411\u81F3 4.3\uFF09\uFF1Bgrok-4.20-multi-agent \u7684\u56DB\u6863\u63A7\u5236\u7684\u662F agent \u6570\u91CF\u800C\u975E\u601D\u8003\u6DF1\u5EA6\u3002\u65B0\u65E7\u4EE3\u9645\u8BF7\u4F18\u5148\u9009 4.5/4.6/4.3\uFF1B\u591A\u6A21\u6001\u53D8\u4F53\u6309\u9700\u52FE\u9009\u56FE\u7247\u3002',\n },\n {\n id: 'mistral-magistral',\n // The native magistral line is a run-together thinking family with no\n // reasoning_effort control of its own (its thinking is driven by\n // prompt_mode / always-on), and Mistral marked the whole line\n // deprecated on 2026-07-28 (phased out through mid-2026; reasoning now\n // rides the generalist models). `false` is the honest \"no effort\n // control\" declaration; gateways that happen to map an effort\n // parameter onto magistral ids can be tuned by hand.\n patterns: ['magistral'],\n efforts: false,\n input: ['text'],\n contextWindow: 32_768,\n maxTokens: 32_768,\n note: 'Magistral \u539F\u751F\u601D\u8003\u7EBF\uFF08\u65E0 effort \u53C2\u6570\uFF0C\u4E3A prompt_mode \u8BED\u4E49\uFF09\uFF0C\u5B98\u65B9\u5DF2\u4E8E 2026-07-28 \u58F0\u660E\u5F03\u7528\u3001\u9010\u6B65\u64A4\u51FA\uFF1B\u73B0\u5F79\u63A8\u7406\u8D70 mistral-small-2603 / mistral-medium-3-5 \u7684 reasoning_effort\uFF08\u89C1\u4E0B\u6761\uFF09\u3002',\n },\n {\n id: 'mistral-medium-3',\n // Official reasoning page + mistral-common request.py (the first-party\n // protocol enum) name the reasoning_effort models: values are exactly\n // none/high. The API ids today are mistral-medium-3-5 (Medium 3.5's\n // model page names the dotted spelling too) and mistral-small-2603\n // (Mistral Small 4); mistral-small-latest is its alias. The dated\n // \"small-2506\" builds are retiring and are NOT matched; the bare\n // 'mistral-medium-3' stem was dropped so the 3.1 generation (no\n // reasoning_effort) does not get the ladder.\n // Normalization folds '.' and '-' to the same space, so the one dotted\n // spelling also keys the API id (mistral-medium-3-5).\n patterns: ['mistral-medium-3.5', 'mistral-small-latest', 'mistral-small-2603'],\n efforts: { off: 'none', high: 'high' },\n // mistral-common's ModelSettings defaults reasoning_effort to None --\n // the endpoint's no-parameter behaviour IS the none/off level.\n defaultEffort: 'off',\n compat: { thinkingFormat: 'openai', supportsReasoningEffort: true },\n input: ['text', 'image'],\n note: 'Mistral \u73B0\u5F79\u63A8\u7406\u6863\uFF1ANone / High\u2014\u2014\u5B98\u65B9 reasoning_effort \u679A\u4E3E\uFF08mistral-common \u534F\u8BAE\u5E93\uFF09\u5373 none/high\uFF1Bmistral-small-2603\uFF08Small 4\uFF09\u4E0E mistral-medium-3-5 \u7ECF\u5B83\u63A7\u5236\uFF0CMedium 3.5 \u5E26\u89C6\u89C9\u3002\u5BB9\u91CF\u672A\u5728\u5B98\u65B9\u76EE\u5F55\u9875\u5355\u5217\uFF0C\u4E0D\u63D0\u4F9B\u3002',\n },\n {\n id: 'qwen-vision',\n // The DashScope vision lines: -vl suffixes and QvQ. Normalization folds\n // 'qwen2.5-vl' to 'qwen2 5 vl', hence the spelled-out middle pattern.\n // Note the modern generations (3.8-max / 3.7-plus / 3.7-flash and the\n // 3.5-omni line) are multimodal too -- see the qwen-3-8 entry and the\n // plain qwen entry note.\n patterns: ['qwen-vl', 'qwen2-vl', 'qwen2-5-vl', 'qwen3-vl', 'qvq'],\n // DashScope takes NO reasoning_effort: thinking is the enable_thinking\n // boolean -- pi-ai's 'qwen' format dispatches exactly that switch.\n // Commercial Model Studio deployments default enable_thinking to TRUE\n // (help.aliyun.com) -- the on state, which is High here.\n efforts: { off: null, high: 'high' },\n defaultEffort: 'high',\n compat: { thinkingFormat: 'qwen' },\n input: ['text', 'image'],\n contextWindow: 131_072,\n maxTokens: 8_192,\n note: '\u901A\u4E49\u89C6\u89C9\u7EBF\uFF08Qwen-VL/QvQ\uFF09\uFF1Aenable_thinking \u5F00\u5173\uFF08\u5F00=High\uFF09\uFF0C\u6536\u56FE\u3002qwen3-vl \u5BB9\u91CF\u66F4\u5927\uFF0C\u6309\u9700\u4E0A\u8C03\u3002',\n },\n {\n id: 'qwen-3-8',\n // The 3.8 generation moved from the bare enable_thinking switch to an\n // official reasoning_effort ladder: the Qwen3.8 README (\"Flexible\n // Thinking Control\"), the Qwen3.8-27B model card, the Qwen3.8-Flash-Next\n // card and the qwen.ai Flash-Next blog all document reasoning_effort\n // with xhigh as the DEFAULT (xhigh/medium/low), alongside the\n // per-request enable_thinking toggle (chat_template_kwargs on\n // open-weight serving). qwen3.8-max stays the current flagship (1M\n // context; Model Studio lists it under image/video understanding), so\n // the plain qwen entry's text-only declaration must not claim it.\n patterns: ['qwen3.8'],\n efforts: { off: null, low: 'low', medium: 'medium', xhigh: 'xhigh' },\n defaultEffort: 'xhigh',\n compat: { thinkingFormat: 'qwen', supportsReasoningEffort: true },\n input: ['text', 'image'],\n contextWindow: 1_000_000,\n note: 'Qwen 3.8 \u7CFB\uFF1A\u5B98\u65B9 reasoning_effort \u6863\u4F4D XHigh(\u9ED8\u8BA4) / Medium / Low\uFF0Cthinking \u9ED8\u8BA4\u5F00\u3001\u53EF\u6309\u8BF7\u6C42\u5173\u95ED\uFF1B\u539F\u751F\u591A\u6A21\u6001\uFF08qwen3.8-max \u56FE\u50CF/\u89C6\u9891\u7406\u89E3\uFF0C\u89C6\u9891\u672A\u5165\u6838\u5FC3\u8BCD\u8868\uFF09\u30021M \u6863\u4E0A\u4E0B\u6587\u300227B \u4E0E Flash-Next \u5F00\u6E90\u6B3E\u89C1\u5355\u72EC\u6761\u76EE\u3002',\n },\n {\n id: 'qwen-3-8-27b',\n // Open-weight dense release (2026-08-14, HF Qwen/Qwen3.8-27B model\n // card): \"native vision-language model\", 262,144 context natively\n // \"extensible up to 1,000,000 tokens\", reasoning_effort xhigh (default)\n // / medium / low with per-request thinking disable. Longer than the\n // bare 'qwen3.8' pattern, so it wins for -27B ids.\n patterns: ['qwen3.8-27b'],\n efforts: { off: null, low: 'low', medium: 'medium', xhigh: 'xhigh' },\n defaultEffort: 'xhigh',\n compat: { thinkingFormat: 'qwen', supportsReasoningEffort: true },\n input: ['text', 'image'],\n contextWindow: 262_144,\n note: 'Qwen3.8-27B\uFF08dense\uFF0C2026-08-14 \u5F00\u6E90\uFF09\uFF1A\u5B98\u65B9 reasoning_effort \u6863\u4F4D XHigh(\u9ED8\u8BA4) / Medium / Low\uFF0Cthinking \u9ED8\u8BA4\u5F00\u3001\u53EF\u6309\u8BF7\u6C42\u5173\uFF1B\u539F\u751F\u56FE\u50CF+\u89C6\u9891\u7406\u89E3\uFF08\u89C6\u9891\u672A\u5165\u6838\u5FC3\u8BCD\u8868\uFF09\u3002262,144 \u539F\u751F\u4E0A\u4E0B\u6587\u3001\u5B98\u65B9\u58F0\u660E\u53EF\u6269\u81F3 1M\u3002\u6765\u6E90\uFF1AHF Qwen/Qwen3.8-27B \u6A21\u578B\u5361\u3002',\n },\n {\n id: 'qwen-3-8-flash-next',\n // Open-weight experimental architecture preview (HF\n // Qwen/Qwen3.8-Flash-Next card + the qwen.ai blog): the\n // Qwen4-underpinning hybrid (QSA, n-gram embedding; 125B with 6B\n // activated), native vision encoder, 262,144 context natively\n // extensible to 1M. Thinking control identical to the 3.8 generation:\n // enable_thinking toggle plus reasoning_effort xhigh (default) /\n // medium / low. Longest pattern, so it wins for -flash-next ids.\n patterns: ['qwen3.8-flash-next'],\n efforts: { off: null, low: 'low', medium: 'medium', xhigh: 'xhigh' },\n defaultEffort: 'xhigh',\n compat: { thinkingFormat: 'qwen', supportsReasoningEffort: true },\n input: ['text', 'image'],\n contextWindow: 262_144,\n note: 'Qwen3.8-Flash-Next\uFF08125B-A6B \u5B9E\u9A8C\u67B6\u6784\uFF0CQwen4 \u524D\u8EAB\uFF09\uFF1A\u5B98\u65B9 reasoning_effort \u6863\u4F4D XHigh(\u9ED8\u8BA4) / Medium / Low + enable_thinking \u5F00\u5173\uFF1B\u539F\u751F\u89C6\u89C9\uFF08Vision Encoder\uFF09\u3002262,144 \u539F\u751F\u4E0A\u4E0B\u6587\u3001\u53EF\u6269\u81F3 1M\u3002\u6765\u6E90\uFF1AHF \u6A21\u578B\u5361\u4E0E qwen.ai \u5B98\u65B9\u535A\u5BA2\u3002',\n },\n {\n id: 'qwen',\n patterns: ['qwen', 'qwq'],\n // DashScope takes NO reasoning_effort: thinking is the enable_thinking\n // boolean (plus thinking_budget) -- pi-ai's 'qwen' format dispatches\n // exactly that switch, so the ladder is honestly open/close with one\n // nominal thinking level. QwQ is think-always; clearing the off level\n // there is one click. Commercial DashScope defaults enable_thinking to\n // TRUE (open-weight serving defaults to false) -- the on state is High.\n efforts: { off: null, high: 'high' },\n defaultEffort: 'high',\n compat: { thinkingFormat: 'qwen' },\n input: ['text'],\n contextWindow: 1_000_000,\n maxTokens: 65_536,\n note: '\u901A\u4E49\u5343\u95EE\uFF1Aenable_thinking \u5F00\u5173\uFF08\u65E0 effort \u6863\uFF09\uFF0C\u5F00=High\uFF1B\u73B0\u5F79\u65D7\u8230\u4E3A qwen3.8 \u7CFB\uFF081M \u6863\u4E0A\u4E0B\u6587\uFF0C\u89C1 qwen-3-8 \u6761\u76EE\uFF09\u30023.6/3.7 \u4EE3\u7684 Plus/Flash \u4EA6\u9ED8\u8BA4\u591A\u6A21\u6001\uFF08\u56FE\u7247/\u89C6\u9891\uFF09\uFF0C\u5982\u63A5\u5165\u8BF7\u6309\u9700\u52FE\u9009\u56FE\u7247\uFF1B\u89C6\u89C9\u7EBF\u89C1 qwen-vision \u6761\u76EE\u3002',\n },\n {\n id: 'glm-vision',\n // Zhipu's vision lines: glm-4v / glm-4.6v / glm-4.5v / glm-5v. Longer\n // than the plain 'glm' patterns, so they win for those ids.\n // 'glm-4-6v' (not 'glm-46v'): normalization folds 'glm-4.6v' to\n // 'glm 4 6v', so the pattern must carry the same inner separator; the\n // same fold gives 'glm-4.5v' -> 'glm 4 5v'.\n patterns: ['glm-4v', 'glm-4-6v', 'glm-4-5v', 'glm-5v'],\n efforts: { off: null, high: 'high' },\n // GLM-4.5V is forced-thinking and the 4.x line defaults to enabled\n // (docs.bigmodel.cn thinking page) -- the on state is High.\n defaultEffort: 'high',\n compat: { thinkingFormat: 'zai' },\n input: ['text', 'image'],\n contextWindow: 131_072,\n maxTokens: 32_768,\n note: '\u667A\u8C31\u89C6\u89C9\u7EBF\uFF08GLM-4V/4.5V/4.6V/5V\uFF09\uFF1Athinking \u5F00\u5173\uFF08\u5F00=High\uFF09\uFF0C\u6536\u56FE\u3002GLM-4.5V \u4E3A\u5F3A\u5236\u601D\u8003\uFF08\u4F20 disabled \u62A5\u9519\uFF0C\u8BF7\u624B\u52A8\u5220 Off \u6863\uFF09\u3002',\n },\n {\n id: 'glm-5-3-flash',\n // Official model page (docs.bigmodel.cn/cn/guide/models/vlm/glm-5.3-flash,\n // page dated 2026-08-28): input modalities \"\u89C6\u9891\u3001\u56FE\u50CF\u3001\u6587\u672C\u3001\u6587\u4EF6\", 1M\n // context / 128K max output, and \"thinking.type \u4EC5\u652F\u6301 enabled\" \u2014 forced\n // thinking, no off switch. \"\u6587\u672C\u53C2\u6570\u4E0E GLM-5.3 \u4FDD\u6301\u4E00\u81F4\" gives the flash\n // variant the 5.3 ladder (low/high/max). Native multimodal (320B), which\n // the text-only glm-5.3 entry must NOT claim \u2014 hence this separate entry;\n // the longer pattern wins over plain 'glm-5.3'.\n // 'glm-5.3-flashx' is the same model under a relay spelling (ofox lists\n // 'z-ai/glm-5.3-flashx' named 'GLM-5.3-FlashX'). It must be listed\n // explicitly: boundary matching rejects the bare 'glm 5 3 flash' needle\n // there because the next character is the alnum 'x', and the shorter\n // 'glm-5.3' would then claim the id as the text-only model.\n patterns: ['glm-5.3-flash', 'glm-5.3-flashx'],\n efforts: { low: 'low', high: 'high', max: 'max' },\n defaultEffort: 'max',\n compat: { thinkingFormat: 'zai', supportsReasoningEffort: true },\n input: ['text', 'image'],\n contextWindow: 1_048_576,\n maxTokens: 131_072,\n note: 'GLM-5.3-Flash\uFF08320B\uFF0C\u5B98\u65B9\u6587\u6863 vlm \u5206\u7C7B\uFF09\uFF1A\u5F3A\u5236\u601D\u8003\uFF08thinking.type \u4EC5 enabled\uFF0C\u4E0D\u652F\u6301\u5173\u95ED\uFF09\uFF0C\u6587\u672C\u53C2\u6570\u4E0E GLM-5.3 \u4E00\u81F4\u2014\u2014\u6863\u4F4D Low / High / Max\u3002\u8F93\u5165\u6A21\u6001\uFF1A\u89C6\u9891\u3001\u56FE\u50CF\u3001\u6587\u672C\u3001\u6587\u4EF6\uFF08\u89C6\u9891/\u6587\u4EF6\u672A\u5165\u6838\u5FC3\u8BCD\u8868\uFF0C\u56FE\u7247\u53EF\u52FE\uFF09\u3002\u5B98\u65B9 1M \u4E0A\u4E0B\u6587 / 128K \u6700\u5927\u8F93\u51FA\u3002\u6765\u6E90\uFF1Adocs.bigmodel.cn \u6A21\u578B\u9875\u3002',\n },\n {\n id: 'glm-5-3',\n patterns: ['glm-5.3'],\n // glm-5.3 accepts exactly max/high/low; anything else (including the\n // 5.2 ladder's minimal/none) errors, and thinking cannot be disabled.\n // The API reference names reasoning_effort's default as max.\n efforts: { low: 'low', high: 'high', max: 'max' },\n defaultEffort: 'max',\n compat: { thinkingFormat: 'zai', supportsReasoningEffort: true },\n input: ['text'],\n contextWindow: 1_048_576,\n maxTokens: 131_072,\n note: 'GLM-5.3 \u6863\u4F4D\uFF1ALow / High / Max\uFF08\u5F3A\u5236\u601D\u8003\uFF0C\u5176\u4F59\u503C\u62A5\u9519\uFF09\u3002\u5B98\u65B9\u5BB9\u91CF 1M / 128K\u3002',\n },\n {\n id: 'glm-5-2',\n patterns: ['glm-5.2'],\n // glm-5.2 takes the widest ladder in the wild: none/minimal/low/medium/\n // high/xhigh/max (default max). The zai format arms thinking:disabled\n // for off and sends the effort for the rest.\n efforts: { off: 'none', minimal: 'minimal', low: 'low', medium: 'medium', high: 'high', xhigh: 'xhigh', max: 'max' },\n defaultEffort: 'max',\n compat: { thinkingFormat: 'zai', supportsReasoningEffort: true },\n input: ['text'],\n contextWindow: 1_048_576,\n maxTokens: 131_072,\n // Official capability page: none/minimal stop thinking, low/medium map\n // to high, xhigh maps to max -- all seven spellings are accepted.\n note: 'GLM-5.2 \u6863\u4F4D\uFF1ANone / Minimal / Low / Medium / High / XHigh / Max\uFF08\u5B98\u65B9\u6620\u5C04\uFF1ALow\u00B7Medium\u2192High\u3001XHigh\u2192Max\u3001None\u00B7Minimal=\u505C\u6B62\u601D\u8003\uFF09\u3002\u89C6\u89C9\u7EBF\u89C1 glm-vision \u6761\u76EE\u3002',\n },\n {\n id: 'glm',\n patterns: ['glm', 'zhipu', 'chatglm'],\n // GLM 4.x: thinking.type enabled/disabled only, no effort ladder --\n // the zai format sends exactly that switch (and no effort value,\n // because supportsReasoningEffort is not declared). GLM-4.5/4.6\n // default to enabled (hybrid reasoning: the model decides per\n // request) -- the on state is High.\n efforts: { off: null, high: 'high' },\n defaultEffort: 'high',\n compat: { thinkingFormat: 'zai' },\n input: ['text'],\n note: 'GLM \u901A\u7528\uFF1Athinking \u5F00\u5173\uFF08\u65E0 effort \u6863\uFF09\uFF0C\u5F00=High\uFF1Beffort \u9636\u68AF\u4EC5 GLM-5.2+ \u652F\u6301\uFF08\u89C1\u4E0A\u4E24\u6761\u76EE\uFF09\u3002\u6CE8\u610F GLM-4.7/GLM-4.5V \u4E3A\u5F3A\u5236\u601D\u8003\uFF0C\u4F20 disabled \u4F1A\u62A5\u9519\uFF08\u8BF7\u624B\u52A8\u5220 Off \u6863\uFF09\u3002\u89C6\u89C9\u7EBF\u89C1 glm-vision \u6761\u76EE\u3002',\n },\n {\n id: 'kimi-k3',\n patterns: ['kimi-k3'],\n // kimi-k3: top-level reasoning_effort low/high/max (default max),\n // always thinking -- the thinking object must not be sent at all.\n efforts: { low: 'low', high: 'high', max: 'max' },\n defaultEffort: 'max',\n compat: { thinkingFormat: 'openai', supportsReasoningEffort: true },\n input: ['text', 'image'],\n contextWindow: 1_048_576,\n note: 'Kimi K3 \u6863\u4F4D\uFF1ALow / High / Max(\u9ED8\u8BA4 Max)\uFF0C\u8D70\u9876\u5C42 reasoning_effort\uFF1B\u59CB\u7EC8\u63A8\u7406\u3001\u52FF\u4F20 thinking \u5BF9\u8C61\u3002\u539F\u751F\u89C6\u89C9\u7406\u89E3\uFF0C1M \u4E0A\u4E0B\u6587\uFF08\u6700\u5927\u8F93\u51FA\u5B98\u65B9\u672A\u5355\u72EC\u5217\uFF0C\u4E0D\u63D0\u4F9B\uFF09\u3002',\n },\n {\n id: 'kimi-k2-vision',\n // K2.5/K2.6 are multimodal thinking models with a toggleable\n // thinking.type switch (official use-thinking-models table); K2.5 was\n // re-verified as MULTIMODAL on 2026-08-24 (the old \"text-only\" note was\n // wrong). Longer patterns beat the plain 'kimi' stem below.\n patterns: ['kimi-k2.6', 'kimi-k2.5'],\n efforts: { off: null, high: 'high' },\n defaultEffort: 'high',\n compat: { thinkingFormat: 'deepseek' },\n input: ['text', 'image'],\n contextWindow: 262_144,\n note: 'Kimi K2.5/K2.6 \u89C6\u89C9\u4EE3\uFF1Athinking.type \u5F00\u5173\uFF08\u9ED8\u8BA4\u5F00\u3001\u53EF\u5173\uFF09\uFF0C\u5F00=High\uFF1B\u5E26\u89C6\u89C9\uFF0C256K\u3002K2.7 Code \u59CB\u7EC8\u601D\u8003\uFF0C\u89C1\u5355\u72EC\u6761\u76EE\u3002',\n },\n {\n id: 'kimi-k27-code',\n // K2.7 Code (and its highspeed twin) ALWAYS think: thinking.type only\n // accepts \"enabled\", sending \"disabled\" errors -- so no Off level.\n patterns: ['kimi-k2.7'],\n efforts: { high: 'high' },\n defaultEffort: 'high',\n compat: { thinkingFormat: 'deepseek' },\n input: ['text', 'image'],\n contextWindow: 262_144,\n note: 'Kimi K2.7 Code\uFF08\u542B\u9AD8\u901F\u7248\uFF09\uFF1A\u59CB\u7EC8\u601D\u8003\u2014\u2014thinking.type \u4EC5\u63A5\u53D7 enabled\uFF08\u4F20 disabled \u62A5\u9519\uFF09\uFF0C\u65E0 Off \u6863\uFF1B\u5E26\u89C6\u89C9\uFF0C256K\u3002',\n },\n {\n id: 'kimi-moonshot-v1-vision',\n // Legacy Moonshot V1 vision variants (official model list): plain\n // generation models with no thinking control, but they DO accept images\n // -- the generic 'moonshot' pattern must not declare text-only for them.\n patterns: ['moonshot-v1-8k-vision', 'moonshot-v1-32k-vision', 'moonshot-v1-128k-vision'],\n efforts: false,\n input: ['text', 'image'],\n note: 'Moonshot V1 \u89C6\u89C9\u65E7\u4EE3\uFF088k/32k/128k \u5404\u4E00\uFF09\uFF1A\u65E0\u601D\u8003\u63A7\u4EF6\uFF08\u751F\u6210\u6A21\u578B\uFF09\u3001\u652F\u6301\u56FE\u7247\u8F93\u5165\uFF1B\u8BE5\u7EBF\u5DF2\u505C\u6B62\u5BF9\u65B0\u7528\u6237\u5F00\u653E\uFF082026-08-31 \u5168\u91CF\u4E0B\u7EBF\uFF0C\u7F51\u5173\u6B8B\u7559\u4ECD\u53EF\u547D\u4E2D\uFF09\u3002',\n },\n {\n id: 'kimi',\n // k2.5/2.6 use the DeepSeek-shaped thinking.type enabled/disabled\n // switch, which the 'deepseek' format dispatches; the old k2 preview\n // ids and moonshot-v1 names are retired upstream (2026-05/08) but live\n // on gateways. Effort ladders are not part of their contract.\n patterns: ['kimi', 'moonshot'],\n efforts: { off: null, high: 'high' },\n compat: { thinkingFormat: 'deepseek' },\n input: ['text'],\n contextWindow: 262_144,\n note: 'Kimi \u901A\u7528\uFF1Athinking \u5F00\u5173\uFF08\u65E0 effort \u6863\uFF09\uFF0C\u5F00=High\u3002k2 \u7CFB\u5217 2026-05-25 \u4E0B\u7EBF\u3001kimi-latest 2026-01-28 \u4E0B\u7EBF\u3001moonshot-v1 \u7CFB 2026-08-31 \u5168\u91CF\u4E0B\u7EBF\uFF08\u7F51\u5173\u6B8B\u7559\u4ECD\u53EF\u547D\u4E2D\uFF1Bmoonshot-v1 \u672C\u8EAB\u975E\u601D\u8003\u6A21\u578B\uFF09\u3002\u89C6\u89C9\u4EE3\u4E0E K2.7 Code \u89C1\u5355\u72EC\u6761\u76EE\u3002',\n },\n {\n id: 'hunyuan-hy3',\n // Open-weight contract (Tencent-Hunyuan/Hy3 README): reasoning_effort\n // travels inside chat_template_kwargs as \"no_think\" (default) / \"low\" /\n // \"high\"; the same README's spec table states a 256K context length.\n patterns: ['hy3'],\n efforts: { low: 'low', high: 'high' },\n compat: { thinkingFormat: 'openai', supportsReasoningEffort: true },\n input: ['text'],\n contextWindow: 262_144,\n note: '\u6DF7\u5143 hy3\uFF1A\u5F00\u6E90\u5951\u7EA6\u7ECF chat_template_kwargs.reasoning_effort = no_think(\u9ED8\u8BA4)/low/high\uFF1B\u5B98\u65B9\u6A21\u578B\u5361 256K \u4E0A\u4E0B\u6587\uFF08295B MoE\uFF0C2026 \u5F00\u6E90\uFF09\u3002',\n },\n {\n id: 'hunyuan-hy4',\n // Open-weight contract (Tencent-Hunyuan/Hy4-preview README): reasoning\n // defaults to \"high\" (deep chain-of-thought) and is disabled with\n // extra_body={\"chat_template_kwargs\": {\"reasoning_effort\": \"no_think\"}}\n // \u2014 the same chat-template channel as hy3, with the default flipped to\n // high. The spec table states a 1M context length; the model is a\n // 770B-A49B MoE with Gated DSA attention. The README documents no levels\n // beyond high/no_think, so a low rung is NOT declared without evidence.\n patterns: ['hy4-preview', 'hy-4-preview'],\n efforts: { off: 'no_think', high: 'high' },\n defaultEffort: 'high',\n compat: { thinkingFormat: 'openai', supportsReasoningEffort: true },\n contextWindow: 1_000_000,\n note: '\u6DF7\u5143 Hy4 preview\uFF1A\u5B98\u65B9 README\u2014\u2014reasoning \u9ED8\u8BA4 high\uFF08\u6DF1\u5EA6\u601D\u8003\uFF09\uFF0C\u5173\u95ED\u7ECF chat_template_kwargs.reasoning_effort=no_think\uFF1B\u5B98\u65B9\u89C4\u683C\u8868 1M \u4E0A\u4E0B\u6587\uFF08770B-A49B MoE\uFF0CGated DSA\uFF09\u3002low \u6863\u5B98\u65B9\u672A\u5217\uFF0C\u5982\u6709\u8BF7\u624B\u8C03\uFF1B\u89C6\u89C9\u672A\u58F0\u660E\uFF0C\u6309\u9700\u624B\u52FE\u3002\u6765\u6E90\uFF1ATencent-Hunyuan/Hy4-preview \u5B98\u65B9 README\u3002',\n },\n {\n id: 'step-5-preview',\n // StepFun's official model is 'step-5-preview' (there is no bare\n // 'step-5'), carrying the same three-step reasoning_effort ladder as the\n // 3.x line with no way to close thinking -- hence no `off`. The official\n // page calls medium the \"default recommendation\". 1M context, 64K max\n // output, native image + video input.\n patterns: ['step-5'],\n efforts: { low: 'low', medium: 'medium', high: 'high' },\n defaultEffort: 'medium',\n compat: { thinkingFormat: 'openai', supportsReasoningEffort: true },\n input: ['text', 'image'],\n contextWindow: 1_000_000,\n maxTokens: 65_536,\n note: '\u9636\u8DC3 Step-5-Preview\uFF08\u5B98\u65B9 id \u5373 step-5-preview\uFF0C\u65E0\u88F8 step-5\uFF1Bpattern \u53D6\u5BB6\u65CF\u4E3B\u5E72\u4EE5\u517C\u5BB9\u7F51\u5173\u5199\u6CD5\uFF09\uFF1A\u6863\u4F4D Low / Medium(\u5B98\u65B9\u6807\"\u9ED8\u8BA4\u63A8\u8350\") / High\uFF0C\u601D\u8003\u4E0D\u53EF\u5173\u95ED\uFF1B\u539F\u751F\u56FE\u7247 + \u89C6\u9891\u8F93\u5165\uFF1B1M \u4E0A\u4E0B\u6587\u300164K \u6700\u5927\u8F93\u51FA\uFF08\u5B98\u65B9\u53E6\u6CE8 max_tokens \u9ED8\u8BA4 INF\u3001\u4E0E 64K \u4E0A\u9650\u5E76\u5B58\uFF0C\u4EE5\u7AEF\u70B9\u5B9E\u6D4B\u4E3A\u51C6\uFF09\u3002',\n },\n {\n id: 'step-3-7',\n // StepFun step-3.7 is the vision-capable generation; 3.5 stayed\n // text-only on the official serving plan.\n patterns: ['step-3.7', 'step-3.6'],\n efforts: { low: 'low', medium: 'medium', high: 'high' },\n defaultEffort: 'medium',\n compat: { thinkingFormat: 'openai', supportsReasoningEffort: true },\n input: ['text', 'image'],\n contextWindow: 262_144,\n note: '\u9636\u8DC3 Step-3.6/3.7 \u6863\u4F4D\uFF1ALow / Medium(\u9ED8\u8BA4\u63A8\u8350) / High\uFF0C\u539F\u751F\u56FE\u7247+\u89C6\u9891\u7406\u89E3\u3002\u4E0A\u4E0B\u6587\u4E3A\u8F93\u5165+\u8F93\u51FA\u603B\u548C\u4E0A\u9650\u3002',\n },\n {\n id: 'step-3-5',\n // step-3.5-flash (official listing): only low/high, text-only.\n patterns: ['step-3.5'],\n efforts: { low: 'low', high: 'high' },\n compat: { thinkingFormat: 'openai', supportsReasoningEffort: true },\n input: ['text'],\n contextWindow: 262_144,\n note: '\u9636\u8DC3 Step-3.5 Flash \u6863\u4F4D\uFF1ALow / High\uFF08\u7EAF\u6587\u672C\u63A8\u7406\u65D7\u8230\uFF09\u3002\u4E0A\u4E0B\u6587\u4E3A\u8F93\u5165+\u8F93\u51FA\u603B\u548C\u4E0A\u9650\u3002',\n },\n {\n id: 'step',\n // StepFun step-3.x: reasoning_effort low/medium/high (default medium);\n // thinking cannot be turned off, only tuned.\n patterns: ['step-3', 'step-2'],\n efforts: { low: 'low', medium: 'medium', high: 'high' },\n defaultEffort: 'medium',\n compat: { thinkingFormat: 'openai', supportsReasoningEffort: true },\n input: ['text'],\n note: '\u9636\u8DC3 Step \u6863\u4F4D\uFF1ALow / Medium / High\uFF08\u9ED8\u8BA4 Medium\uFF0C\u4E0D\u53EF\u5173\u95ED\uFF09\u30023.6/3.7 \u89C6\u89C9\u4EE3\u89C1\u5355\u72EC\u6761\u76EE\u3002',\n },\n {\n id: 'doubao',\n // Volcengine Ark: officially documented is the thinking.type\n // enabled/disabled/auto switch; the reasoning_effort ladder on\n // seed-2.x has community evidence (chatbox/compshare) but no first-\n // party doc yet -- kept as the conventional ladder, verify per gateway.\n // 'doubao' already covers every doubao-* spelling; the bare 'seed' token\n // (boundary-checked) catches seed-first ids some gateways serve. The\n // seed generations are vision-capable; doubao-1.5-pro stays text-only.\n patterns: ['doubao', 'seed'],\n efforts: { off: null, low: 'low', medium: 'medium', high: 'high' },\n compat: { thinkingFormat: 'openai', supportsReasoningEffort: true },\n input: ['text', 'image'],\n note: '\u8C46\u5305\u6863\u4F4D\uFF1AOff / Low / Medium / High\u2014\u2014effort \u9636\u68AF\u4ECD\u662F\u793E\u533A\u8BC1\u636E\u3001\u5B98\u65B9 Ark \u6587\u6863\u660E\u5217\u7684\u4E3A thinking.type \u5F00\u5173\uFF082026-08-24 \u590D\u6838\u4ECD\u672A\u89C1\u5230 effort \u5B98\u65B9\u660E\u6587\uFF09\u3002seed \u4EE3\u6536\u56FE\uFF081.5-pro \u4F8B\u5916\uFF09\u3002',\n },\n {\n id: 'minimax-m3',\n // Official M3 README: a thinking parameter with enabled / adaptive /\n // disabled -- NO reasoning_effort ladder. That is exactly the\n // deepseek-shaped toggle, so the kimi-style declaration fits; \"adaptive\"\n // is not expressible in the level vocabulary and defaults apply.\n patterns: ['minimax-m3'],\n efforts: { off: null, high: 'high' },\n compat: { thinkingFormat: 'deepseek' },\n input: ['text', 'image'],\n contextWindow: 1_048_576,\n note: 'MiniMax-M3\uFF1A\u5B98\u65B9 thinking \u53C2\u6570 enabled/adaptive/disabled\uFF08\u65E0 effort \u6863\uFF09\uFF0C\u5F00=High\u3001\u5173=disabled\uFF1B\u539F\u751F\u591A\u6A21\u6001\uFF08\u56FE/\u89C6\u9891\uFF0C\u6838\u5FC3\u8BCD\u8868\u4EC5\u542B\u56FE\uFF09\uFF0C1M \u4E0A\u4E0B\u6587\u3002',\n },\n {\n id: 'mimo-v2-6',\n // Xiaomi MiMo v2.6 (and the v2.5 generation it supersedes) takes a required\n // thinking.type toggle (enabled/disabled, default enabled) plus a required\n // reasoning.effort. The official page lists the accepted effort values as\n // none/minimal/low/medium/high/xhigh/max/ultra and normalizes minimal to\n // low and xhigh/max/ultra to high -- but says outright that reasoning\n // strength is not differentiated yet, so the ladder below is what the\n // endpoint ACCEPTS, not a set of levels that behave differently today.\n // xhigh/max are deliberately absent: the endpoint folds them into high.\n // One entry covers both generations: the same models are documented under\n // one contract, and the family's only text-only member (v2.5-pro) keys its\n // own entry with a strictly longer pattern.\n patterns: ['mimo-v2.6', 'mimo-v2.5'],\n efforts: { off: 'none', low: 'low', medium: 'medium', high: 'high' },\n compat: { thinkingFormat: 'openai', supportsReasoningEffort: true },\n input: ['text', 'image'],\n contextWindow: 1_048_576,\n maxTokens: 131_072,\n note: '\u5C0F\u7C73 MiMo v2.6 \u7CFB\u5217\uFF08mimo-v2.6-pro / -flash / -pro-ultraspeed\uFF1B1M \u4E0A\u4E0B\u6587 / 128K \u6700\u5927\u8F93\u51FA\u3001\u539F\u751F\u5168\u6A21\u6001\uFF09\u4E0E\u5176\u524D\u4EE3 mimo-v2.5\u3002\u5B98\u65B9\u6587\u6863\uFF1Athinking.type\uFF08enabled/disabled\uFF0C\u9ED8\u8BA4 enabled\uFF09+ reasoning.effort\uFF08none \u5173\u95ED\uFF1B\u5176\u4F59\u5408\u6CD5\u503C\u5747\u5F00\u542F\uFF0C\u4E14**\u73B0\u9636\u6BB5\u6682\u672A\u533A\u5206\u63A8\u7406\u5F3A\u5EA6**\u2014\u2014minimal \u5F52\u4E00\u4E3A low\u3001xhigh/max/ultra \u5F52\u4E00\u4E3A high\uFF09\uFF0C\u56E0\u6B64\u8FD9\u91CC\u58F0\u660E\u7684\u662F\u7AEF\u70B9**\u63A5\u53D7**\u7684\u6863\u4F4D Off / Low / Medium / High\uFF08xhigh\u3001max \u4E0D\u58F0\u660E\uFF0C\u7AEF\u70B9\u53EA\u4F1A\u6298\u53E0\u4E3A high\uFF09\u3002\u601D\u8003\u6A21\u5F0F\u4E0B temperature / top_p \u4E0D\u53EF\u81EA\u5B9A\u4E49\uFF08\u5F3A\u5236 1.0 / 0.95\uFF09\uFF1B\u5E26\u5DE5\u5177\u8C03\u7528\u7684\u5386\u53F2\u8F6E\u5FC5\u987B\u5B8C\u6574\u56DE\u4F20 reasoning_content\uFF0C\u5426\u5219 400\u3002mimo-v2.5 \u4E0E v2.5-pro \u5B98\u65B9\u5B9A\u4E8E 2026-10-21 \u4E0B\u7EBF\u3002',\n },\n {\n id: 'mimo-v2-5-pro',\n // The v2.5 flagship is the family's only text-only member -- the official\n // capability table lists no multimodal understanding for it (models.dev\n // agrees, attachment=false), while every v2.6 model and mimo-v2.5 do.\n // Strictly longer pattern than the family entry's 'mimo-v2.5', so the\n // longest-hit rule routes it here.\n patterns: ['mimo-v2.5-pro'],\n efforts: { off: 'none', low: 'low', medium: 'medium', high: 'high' },\n compat: { thinkingFormat: 'openai', supportsReasoningEffort: true },\n input: ['text'],\n contextWindow: 1_048_576,\n maxTokens: 131_072,\n note: '\u5C0F\u7C73 MiMo v2.5-Pro\uFF1A\u8BE5\u5BB6\u65CF\u552F\u4E00\u7684**\u7EAF\u6587\u672C**\u6210\u5458\uFF08\u5B98\u65B9\u80FD\u529B\u8868\u672A\u5217\u5168\u6A21\u6001\u7406\u89E3\uFF09\uFF0C1M \u4E0A\u4E0B\u6587 / 128K \u6700\u5927\u8F93\u51FA\uFF0C\u63A8\u7406\u5951\u7EA6\u4E0E v2.6 \u7CFB\u5217\u76F8\u540C\uFF08thinking.type + reasoning.effort\uFF0Cnone \u5173\u95ED\u3001\u5176\u4F59\u6863\u4F4D\u6682\u4E0D\u533A\u5206\u5F3A\u5EA6\uFF09\u3002\u5B98\u65B9\u5B9A\u4E8E 2026-10-21 \u4E0B\u7EBF\u3002',\n },\n {\n id: 'baidu-ernie',\n // Baidu Qianfan's OpenAI-compatible surface accepts no reasoning_effort\n // parameter (the v2 API parameter tables carry none); thinking is a\n // per-variant property: the -Thinking / ERNIE 5.0-Thinking-* family is\n // always-on thinking, the plain ERNIE 4.5/5.0/5.1 generations are not\n // thinking models at all. The official pricing page (2026-08) lists\n // ERNIE 5.1 / 5.0 / 5.0-Thinking-Preview|Latest|Exp / 4.5-Turbo(-VL).\n patterns: ['ernie'],\n efforts: false,\n input: ['text'],\n contextWindow: 131_072,\n note: '\u767E\u5EA6\u5343\u5E06 ERNIE \u7CFB\uFF1A\u5B98\u65B9 OpenAI \u517C\u5BB9\u63A5\u53E3\u65E0 reasoning_effort \u53C2\u6570\u2014\u2014\u601D\u8003\u7531\u6A21\u578B\u53D8\u4F53\u51B3\u5B9A\uFF08-Thinking \u7CFB\u5217\u59CB\u7EC8\u601D\u8003\u3001\u666E\u901A\u7CFB\u5217\u4E0D\u601D\u8003\uFF09\uFF0C\u52FF\u52FE\u601D\u8003\u6863\u3002ERNIE 4.5 Turbo VL \u652F\u6301\u56FE\u7247\uFF0C\u6309\u9700\u624B\u52FE\uFF1B\u53C2\u8003\u5BB9\u91CF\u53D6 Turbo 128K \u6863\u3002',\n },\n]\n\n/**\n * The generic OpenAI-compatible ladder -- the single source for every\n * OpenAI-shaped protocol row below and the fallback when nothing matches.\n */\nexport const GENERIC_OPENAI_EFFORTS: ReasoningEfforts = {\n off: null,\n low: 'low',\n medium: 'medium',\n high: 'high',\n}\n\n/**\n * Level sets keyed by pi-ai's REAL wire protocols -- the only values a\n * route's 'api' may take are 'openai-completions' | 'openai-responses' |\n * 'anthropic-messages' (llm-pi-ai provider.ts PROTOCOLS) -- plus the\n * 'deepseek' URL dialect for routes that name no api but point at DeepSeek's\n * own endpoint, which takes its native off/high/max ladder.\n *\n * 'off: null' is only offered where a no-thinking mode is plausible; the\n * conservative choice elsewhere is to omit it so the picker never promises an\n * Off the endpoint would reject. Exported for the vocabulary grid tests that\n * pin these ladders against pi-ai's resolution rules.\n */\nexport const PROTOCOL_INFERENCE: Readonly<Record<string, ReasoningEfforts>> = {\n 'openai-completions': GENERIC_OPENAI_EFFORTS,\n 'openai-responses': GENERIC_OPENAI_EFFORTS,\n 'anthropic-messages': GENERIC_OPENAI_EFFORTS,\n // The live V4 contract: low/high/max (+ thinking toggle for off, spelled\n // 'none' so an off selection also maps to the official Responses-API value\n // reasoning.effort: none).\n deepseek: { off: 'none', low: 'low', high: 'high', max: 'max' },\n}\n\n/** A best-effort generic declaration when even the protocol is unknown. */\nconst GENERIC_FALLBACK: ReasoningEfforts = { low: 'low', medium: 'medium', high: 'high' }\n\n/** Normalize one route fact for matching/inference. */\nfunction normalize(value: string | undefined): string {\n return (value ?? '').toLowerCase().trim()\n}\n\n/** Whether a character is a lowercase letter or digit (word-boundary test). */\nfunction isAlnum(ch: string | undefined): boolean {\n return ch !== undefined && /[a-z0-9]/.test(ch)\n}\n\n/**\n * Lowercase and collapse every non-alphanumeric run to one space, so id /\n * display-name / pattern separators ('-', '_', '.', spaces) compare equal:\n * pattern 'deepseek-v3' matches display name \"DeepSeek V3\".\n */\nfunction normalizeLoose(value: string): string {\n return value.toLowerCase().trim().replace(/[^a-z0-9]+/g, ' ')\n}\n\n/**\n * Whether the occurrence of a pattern at index 'at' sits on a word boundary\n * in the haystack: neither neighbor may be a letter/digit. Keeps short family\n * tokens from false-hitting ('o1' must hit 'o1 mini' but not 'ko1 pro';\n * 'seed' hits 'doubao seed 1 6' but not 'seedling').\n */\nfunction onBoundary(haystack: string, at: number, length: number): boolean {\n const before = at === 0 ? undefined : haystack[at - 1]\n const after = haystack[at + length]\n return !isAlnum(before) && !isAlnum(after)\n}\n\n/** Match the knowledge base: first match wins, longest boundary hit wins. */\nexport function matchKnowledgeBase(modelId: string, displayName?: string): KnowledgeEntry | undefined {\n const haystack = normalizeLoose(modelId) + ' ' + normalizeLoose(displayName ?? '')\n let best: { entry: KnowledgeEntry; length: number } | undefined\n for (const entry of KNOWLEDGE_BASE) {\n for (const pattern of entry.patterns) {\n const needle = normalizeLoose(pattern)\n let at = haystack.indexOf(needle)\n while (at >= 0) {\n if (onBoundary(haystack, at, needle.length)) {\n if (best === undefined || needle.length > best.length) {\n best = { entry, length: needle.length }\n }\n break\n }\n at = haystack.indexOf(needle, at + 1)\n }\n }\n }\n return best?.entry\n}\n\n/**\n * Infer which PROTOCOL_INFERENCE key applies to a route. A configured 'api'\n * is already a pi-ai protocol name and wins as-is; otherwise the endpoint's\n * HOST names the dialect -- matched on the registrable domain so an aggregator\n * path like https://gw.example.com/deepseek/v1 stays generic -- and anything\n * unrecognized resolves to the OpenAI-compatible ladder (the overwhelming\n * majority of gateways).\n */\nconst NATIVE_DIALECT_DOMAINS: Readonly<Record<string, string>> = {\n // api.deepseek.com is the official endpoint (api-docs.deepseek.com). The\n // 'deepseek.ai' form was dropped: it resolves to a Vercel-hosted site\n // (76.76.21.21), not DeepSeek infrastructure, so nothing warrants assuming\n // the native dialect for it.\n 'deepseek.com': 'deepseek',\n 'anthropic.com': 'anthropic-messages',\n}\n\nexport function inferProtocol(route: RouteFacts): string {\n const api = normalize(route.api)\n if (api.length > 0) return api\n const baseURL = route.baseURL\n if (baseURL !== undefined && baseURL.length > 0) {\n try {\n const host = new URL(baseURL).hostname.toLowerCase()\n const parts = host.split('.')\n if (parts.length >= 2) {\n const dialect = NATIVE_DIALECT_DOMAINS[parts.slice(-2).join('.')]\n if (dialect !== undefined) return dialect\n }\n } catch {\n // Malformed URL: fall through to the generic ladder.\n }\n }\n // Former 'gemini' guessing removed: pi-ai has no gemini protocol, and\n // Gemini gateways speak the OpenAI-compatible dialect.\n return 'openai-completions'\n}\n\n/**\n * The one wire protocol whose compat gate offers thinkingFormat /\n * supportsReasoningEffort (llm-pi-ai COMPLETIONS_COMPAT_GATE). pi-ai refuses\n * a model-level compat field its resolved protocol does not take\n * (assertServiceable throws at the write), so compat suggestions are gated to\n * this protocol only -- with one exception: the anthropic-messages gate\n * offers forceAdaptiveThinking, which is what makes declared efforts reach\n * the wire as output_config.effort (see {@link KnowledgeEntry.anthropicAdaptive}).\n */\nconst COMPAT_CAPABLE_PROTOCOL = 'openai-completions'\nconst ANTHROPIC_PROTOCOL = 'anthropic-messages'\n\n/** Whether a baseURL names a self-hosted endpoint (loopback, private LAN, .local, custom port). */\nexport function isSelfHostedEndpoint(baseURL: string | undefined): boolean {\n if (baseURL === undefined || baseURL.length === 0) return false\n let host = ''\n try {\n host = new URL(baseURL).hostname.toLowerCase()\n } catch {\n return false\n }\n if (host === 'localhost' || host === '::1' || host.endsWith('.local') || host.endsWith('.internal')) return true\n if (/^(127\\.|10\\.|192\\.168\\.)/.test(host)) return true\n if (/^172\\.(1[6-9]|2[0-9]|3[01])\\./.test(host)) return true\n return host.includes(':')\n}\n\n/** Drop catalog-withheld keys pi-ai never accepts from a profile (defensive). */\nexport function sanitizeCompatForProtocol(compat: CompatSuggestion, api: string): CompatSuggestion | undefined {\n const norm = normalize(api)\n const copy: Record<string, unknown> = { ...compat }\n delete copy['supportsMidConvoEffort']\n delete copy['allowedFallbackModels']\n if (norm === ANTHROPIC_PROTOCOL) {\n for (const key of ['thinkingFormat', 'supportsReasoningEffort', 'thinkingTokenBudgetField', 'supportsThinkingTokenBudget', 'vllmPriority', 'supportsMaxOutputTokens'] as const) delete copy[key]\n if (copy['forceAdaptiveThinking'] === undefined) return undefined\n return { forceAdaptiveThinking: copy['forceAdaptiveThinking'] as boolean }\n }\n if (norm === 'openai-responses') {\n for (const key of ['thinkingFormat', 'supportsReasoningEffort', 'thinkingTokenBudgetField', 'supportsThinkingTokenBudget', 'vllmPriority'] as const) delete copy[key]\n if (copy['supportsMaxOutputTokens'] === undefined) return undefined\n return { supportsMaxOutputTokens: copy['supportsMaxOutputTokens'] as boolean }\n }\n if (norm !== COMPAT_CAPABLE_PROTOCOL) return undefined\n delete copy['forceAdaptiveThinking']\n delete copy['supportsMaxOutputTokens']\n return Object.keys(copy).length === 0 ? undefined : (copy as CompatSuggestion)\n}\n\n/** Gate a compat block against the route's real protocol. */\nfunction compatForRoute(entry: KnowledgeEntry, route: RouteFacts): CompatSuggestion | undefined {\n const api = normalize(route.api)\n if (api === COMPAT_CAPABLE_PROTOCOL) {\n let compat = entry.compat\n if (compat !== undefined) compat = sanitizeCompatForProtocol(compat, api) ?? undefined\n if (compat === undefined && !isSelfHostedEndpoint(route.baseURL)) return undefined\n if (compat === undefined) return { thinkingTokenBudgetField: 'thinking_token_budget' }\n if (compat.thinkingTokenBudgetField === undefined && compat.supportsThinkingTokenBudget !== true && isSelfHostedEndpoint(route.baseURL)) {\n return { ...compat, thinkingTokenBudgetField: 'thinking_token_budget' }\n }\n return compat\n }\n if (api === ANTHROPIC_PROTOCOL && entry.anthropicAdaptive === true) {\n return { forceAdaptiveThinking: true }\n }\n return undefined\n}\n\n/**\n * Official endpoint roots where pi-ai may send role:developer, so no pin is\n * needed. Matching is a DNS-suffix match, so multi-level roots (e.g.\n * openai.azure.com) work while a relay merely hosted on the same cloud\n * (e.g. *.cloudapp.azure.com) still counts as self-hosted.\n *\n * Deliberately fail-safe: hosts outside this set get the pin. `system` is\n * accepted everywhere, `developer` is not, so an unknown host keeps the\n * universally accepted role -- the pin is harmless on official endpoints\n * too. Only add a root after verifying its endpoints accept\n * role:developer (vendor docs or a wire capture); when in doubt, leave it\n * out. The pi-ai-parity entries change no bytes (pi-ai already detects\n * those hosts as nonstandard, i.e. supportsDeveloperRole false); they are\n * listed so the two detectors cannot drift apart silently.\n */\nconst OFFICIAL_RELAY_DOMAINS: readonly string[] = [\n // First-party OpenAI-compatible endpoints (developer accepted).\n 'openai.com',\n 'openai.azure.com',\n 'deepseek.com',\n 'openrouter.ai',\n 'z.ai',\n 'bigmodel.cn',\n 'moonshot.ai',\n 'moonshot.cn',\n 'aliyuncs.com',\n 'anthropic.com',\n 'x.ai',\n 'together.ai',\n 'together.xyz',\n 'nvidia.com',\n 'cerebras.ai',\n 'cloudflare.com',\n // pi-ai-parity: detected nonstandard upstream (pin would be a no-op).\n 'chutes.ai',\n 'opencode.ai',\n 'ant-ling.com',\n]\n\n/**\n * Whether a route is a self-hosted relay whose upstreams cannot be assumed\n * to accept role:developer: openai-completions protocol on a baseURL whose\n * host no official root claims. Absent or malformed URLs answer false --\n * with nothing to judge the host by, pi-ai's detection default stands.\n */\nexport function isSelfHostedRelay(route: RouteFacts): boolean {\n if (normalize(route.api) !== COMPAT_CAPABLE_PROTOCOL) return false\n const baseURL = route.baseURL\n if (baseURL === undefined || baseURL.length === 0) return false\n try {\n const host = new URL(baseURL).hostname.toLowerCase()\n if (!host.includes('.')) return false\n return !OFFICIAL_RELAY_DOMAINS.some((root) => host === root || host.endsWith('.' + root))\n } catch {\n return false\n }\n}\n\n/**\n * Pin the system role on self-hosted relays: merge\n * `supportsDeveloperRole: false` into a compat block that would otherwise\n * let pi-ai rewrite the system prompt to role:developer (issue #2 -- the\n * upstream answers \u89D2\u8272\u4FE1\u606F\u4E0D\u6B63\u786E). An explicitly declared value always\n * wins; non-reasoning suggestions (efforts === false) never carry compat.\n */\nfunction withRolePin(\n compat: CompatSuggestion | undefined,\n route: RouteFacts,\n reasons: boolean,\n): CompatSuggestion | undefined {\n if (compat === undefined || !reasons) return compat\n if (compat.supportsDeveloperRole !== undefined) return compat\n if (!isSelfHostedRelay(route)) return compat\n return { ...compat, supportsDeveloperRole: false }\n}\n\n/** Conservative ladder offered when the endpoint confirms reasoning but nothing names the levels. */\nconst ENDPOINT_CONFIRMED_LADDER: ReasoningEfforts = { off: null, low: 'low', medium: 'medium', high: 'high' }\n\n/**\n * Name-heuristic modality tokens -- the last-resort tier (the practice\n * one-api/new-api bake into code): vision-flavored tokens that appear in\n * vendor ids often enough to suggest image input at LOW confidence. Boundary\n * matching keeps 'vl' from hitting 'eval' or 'svelte'.\n */\nconst VISION_NAME_TOKENS: readonly string[] = [\n 'vl',\n 'vision',\n 'omni',\n '4o',\n 'pixtral',\n 'internvl',\n]\n\n/** Lowest-confidence modality guess from the model id alone, or undefined. */\nexport function inferModalitiesFromName(modelId: string): InputModalities | undefined {\n const haystack = normalizeLoose(modelId)\n for (const token of VISION_NAME_TOKENS) {\n const needle = normalizeLoose(token)\n let at = haystack.indexOf(needle)\n while (at >= 0) {\n if (onBoundary(haystack, at, needle.length)) return ['text', 'image']\n at = haystack.indexOf(needle, at + 1)\n }\n }\n return undefined\n}\n\n/**\n * Intersect a raw listing disclosure with the core vocabulary. Returns\n * undefined when the listing never named a modality field OR named one whose\n * members all fall outside the core vocabulary (an audio-only declaration\n * must NOT read as \"text only\"). A present disclosure always yields at least\n * text-only when image is absent -- so an explicit text-only listing can\n * strip an image claim.\n */\nfunction declaredCoreInput(raw: readonly string[] | undefined): InputModalities | undefined {\n if (raw === undefined) return undefined\n const lowered = raw.map(value => value.toLowerCase())\n if (!lowered.some(value => (INPUT_MODALITIES as readonly string[]).includes(value))) return undefined\n return lowered.includes('image') ? ['text', 'image'] : ['text']\n}\n\n/**\n * Resolve the suggestion for one model on one route, fusing the available\n * signals by confidence:\n *\n * L1 endpoint listing signal (when supplied) -- answers \"does it reason at\n * all\" and, independently, \"what does it accept\": an explicit false\n * wins the effort ladder outright (suggest false, high); a modality\n * disclosure or a context length feeds those parts regardless;\n * L2 knowledge base -- the ONLY source of wire spellings and compat, plus\n * modality/capacity references when the endpoint stays silent;\n * L3 name heuristic -- a low-confidence image guess for vision-flavored\n * ids when both sources above are silent;\n * L4 protocol inference -- level-ladder skeleton when nothing better exists.\n *\n * @param modelId - the model id (or display name) to match.\n * @param route - route facts used when the knowledge base misses; its\n * displayName participates in knowledge-base matching.\n * @param endpoint - optional raw-listing facts for this model (from the\n * host's same-origin probe route); omit when the endpoint was not asked.\n * @returns a suggestion (always derivable -- protocol inference has a fallback).\n */\nexport function suggestEfforts(\n modelId: string,\n route: RouteFacts,\n endpoint?: EndpointFacts,\n): EffortSuggestion {\n const entry = matchKnowledgeBase(modelId, route.displayName)\n\n // ---- Modality + capacity parts (orthogonal to the effort ladder) ----\n let input: InputModalities | undefined\n let inputSource: InputSource | undefined\n let contextWindow: number | undefined\n let maxTokens: number | undefined\n\n if (entry?.input !== undefined) {\n input = entry.input\n inputSource = 'knowledge'\n }\n if (entry?.contextWindow !== undefined) contextWindow = entry.contextWindow\n if (entry?.maxTokens !== undefined) maxTokens = entry.maxTokens\n\n // An endpoint disclosure outranks the knowledge base; a disclosed context\n // length likewise replaces the reference value. Silence changes nothing.\n const listedInput = declaredCoreInput(endpoint?.input)\n if (listedInput !== undefined) {\n input = listedInput\n inputSource = 'endpoint'\n }\n if (endpoint?.contextLength !== undefined && Number.isFinite(endpoint.contextLength) && endpoint.contextLength > 0) {\n contextWindow = endpoint.contextLength\n }\n\n // L3: nothing named the modalities -- fall back to the name heuristic.\n if (input === undefined) {\n const guessed = inferModalitiesFromName(modelId)\n if (guessed !== undefined) {\n input = guessed\n inputSource = 'heuristic'\n }\n }\n\n const modalityParts = {\n ...(input === undefined ? {} : { input }),\n ...(inputSource === undefined ? {} : { inputSource }),\n ...(contextWindow === undefined ? {} : { contextWindow }),\n ...(maxTokens === undefined ? {} : { maxTokens }),\n }\n\n const endpointPart = endpoint === undefined\n ? {}\n : { endpoint: { reasoning: endpoint.reasoning, source: endpoint.source } }\n\n // L1: an explicit \"does not reason\" from the endpoint outranks everything.\n if (endpoint?.reasoning === false) {\n return {\n efforts: false,\n matched: false,\n source: 'endpoint:' + (endpoint.source ?? 'listing'),\n confidence: 'high',\n ...endpointPart,\n ...modalityParts,\n }\n }\n\n if (entry !== undefined) {\n const compat = withRolePin(compatForRoute(entry, route), route, entry.efforts !== false)\n return {\n efforts: entry.efforts,\n // The vendor default rides along only when the suggested ladder\n // actually carries it (a declaration may deliberately drop a level).\n ...(entry.efforts !== false\n && entry.defaultEffort !== undefined\n && entry.efforts[entry.defaultEffort] !== undefined\n ? { defaultEffort: entry.defaultEffort }\n : {}),\n ...(compat === undefined ? {} : { compat }),\n matched: true,\n entryId: entry.id,\n source: entry.id,\n // Knowledge base carries the wire values; an agreeing endpoint signal\n // only reinforces it. A DISAGREEING signal (endpoint says no reasoning)\n // was handled above; unknown changes nothing.\n confidence: 'high',\n ...endpointPart,\n ...modalityParts,\n }\n }\n\n // L2 missed: the ladder comes from protocol inference. An explicit endpoint\n // \"reasons\" upgrades confidence to medium -- support is confirmed, but the\n // level set and spellings are inferred, so the user should double-check.\n const protocol = inferProtocol(route)\n const efforts = PROTOCOL_INFERENCE[protocol] ?? GENERIC_FALLBACK\n const compatBase: CompatSuggestion | undefined = normalize(route.api) === COMPAT_CAPABLE_PROTOCOL\n ? { thinkingFormat: 'openai', supportsReasoningEffort: true }\n : undefined\n const compatWithBudget = compatBase !== undefined && isSelfHostedEndpoint(route.baseURL)\n ? { ...compatBase, thinkingTokenBudgetField: 'thinking_token_budget' as const }\n : compatBase\n const compat = withRolePin(compatWithBudget, route, true)\n if (endpoint?.reasoning === true) {\n return {\n efforts: { ...ENDPOINT_CONFIRMED_LADDER },\n ...(ENDPOINT_CONFIRMED_LADDER['medium'] !== undefined ? { defaultEffort: 'medium' as const } : {}),\n // compat was already gated to the protocol above; no second gate.\n ...(compat === undefined ? {} : { compat }),\n matched: false,\n source: 'endpoint:' + (endpoint.source ?? 'listing'),\n confidence: 'medium',\n ...endpointPart,\n ...modalityParts,\n }\n }\n return {\n efforts,\n // Inferred ladders default to medium (the convention codex/OpenAI set for\n // their own ladders) whenever the inferred set carries it.\n ...(efforts['medium'] !== undefined ? { defaultEffort: 'medium' as const } : {}),\n ...(compat === undefined ? {} : { compat }),\n matched: false,\n source: 'protocol:' + protocol,\n confidence: 'low',\n ...endpointPart,\n ...modalityParts,\n }\n}\n", "/**\n * Default-guard decision: which effort-less calls may take the vendor\n * default instead of the wire's off-equivalent (issue #2).\n *\n * Pi-ai always emits a thinking parameter for reasoning models, so an\n * effort-less call to a forced-thinking ladder (no `off` key) becomes\n * `thinking: {type: disabled}` / `enable_thinking: false` -- a guaranteed\n * 400 on upstreams that cannot switch thinking off. Rewriting exactly that\n * class into the ladder's vendor default produces bytes identical to the\n * user picking the level by hand, a request class that already works.\n *\n * Pure data logic (no harness imports): the host half feeds it the declared\n * ladder, the knowledge-base vendor default, and the route default, and\n * injects the returned level -- or nothing when it answers undefined.\n *\n * @module dsh-model-think-level/guard\n */\n\nimport type { ReasoningEfforts, ThinkingLevel } from './knowledge.js'\n\n/** Inputs to the guard decision, all optional except the declaration. */\nexport interface GuardInput {\n /** The model's declared ladder (`false` = non-reasoning). */\n declared: ReasoningEfforts | false | undefined\n /** The knowledge-base vendor default for the family, when one is known. */\n vendorDefault?: ThinkingLevel\n /** The route profile's configured reasoning default, when one is set. */\n profileDefault?: string\n /** The call's explicit effort, when the caller named one. */\n requested?: string\n}\n\n/**\n * The level to inject for an effort-less call, or undefined to pass through.\n * Refusals are silent and total: explicit selections, off-capable ladders,\n * undeclared/non-reasoning models, an explicit route default, and vendor\n * defaults outside the ladder all pass through untouched.\n */\nexport function resolveGuardEffort(input: GuardInput): string | undefined {\n if (input.requested !== undefined) return undefined\n const declared = input.declared\n if (declared === undefined || declared === false) return undefined\n if ('off' in declared) return undefined\n if (input.profileDefault !== undefined) return undefined\n const fallback = input.vendorDefault\n if (fallback === undefined || !(fallback in declared)) return undefined\n return fallback\n}\n", "/**\n * Shape guards and settings-dict readers shared by the host and browser\n * halves. Pure data logic only: esbuild inlines this module into both\n * bundles, so it must never import a harness package or touch DOM/node APIs.\n *\n * @module dsh-model-think-level/shared\n */\n\nimport type { RouteFacts } from './knowledge.js'\n\n/** Whether a value is a plain-ish object (not null, not an array). */\nexport const isRecord = (value: unknown): value is Record<string, unknown> =>\n typeof value === 'object' && value !== null && !Array.isArray(value)\n\n/**\n * Whether a settings refusal reads like \"this kernel does not know the newer\n * compat keys\". The host autofill and the browser write path each downgrade\n * once on this signal, so they must answer identically.\n */\nexport function looksLikeCompatRefusal(message: string): boolean {\n const msg = message.toLowerCase()\n return msg.includes('compat')\n || msg.includes('thinkingtokenbudget')\n || msg.includes('vllmpriority')\n || msg.includes('supportsmaxoutput')\n}\n\n/** The models array of one route in a providers dict, as records. */\nexport function modelsOf(providers: unknown, route: string): Record<string, unknown>[] {\n if (!isRecord(providers)) return []\n const profile = providers[route]\n if (!isRecord(profile) || !Array.isArray(profile['models'])) return []\n return profile['models'].filter(isRecord)\n}\n\n/** One provider profile's route facts, as suggestion inference reads them. */\nexport function routeFactsOf(providers: unknown, route: string): RouteFacts {\n if (!isRecord(providers)) return {}\n const profile = providers[route]\n if (!isRecord(profile)) return {}\n const api = typeof profile['api'] === 'string' ? profile['api'] : undefined\n const baseURL = typeof profile['baseURL'] === 'string' ? profile['baseURL'] : undefined\n const displayName = typeof profile['displayName'] === 'string' ? profile['displayName'] : undefined\n return { api, baseURL, displayName }\n}\n", "/**\n * Provider request-header overlay, PURE half: the origin index and the header\n * value rules shared by the fetch-layer installer and the conflict report.\n *\n * Why this exists at all (issue #12): a route's `headers` dict can be merged or\n * overwritten by the official adapter's attribution headers, with `user-agent`\n * being the most visible case. A gateway that depends on any configured client\n * header therefore may not see the value stored in the profile. The overlay\n * reapplies the complete configured dictionary at the fetch layer, the last\n * public seam before the request reaches the wire.\n *\n * The index keeps every route's endpoint path and configured model ids. The URL\n * alone cannot distinguish two routes that share an origin, while an OpenAI-\n * compatible chat request carries the selected model in its JSON body. The\n * origin map remains as a backwards-compatible fallback for requests that do\n * not expose enough identity (for example a GET /models probe).\n *\n * @module dsh-model-think-level/headers-core\n */\n\nimport { isRecord } from './shared.js'\n\n/**\n * Upper bound on one header value the plugin will send. Fetch itself refuses\n * newline-bearing values (a header-injection guard); this plugin additionally\n * refuses anything unreasonable long rather than letting a paste of a whole\n * certificate turn every request into an upstream 400.\n */\nconst MAX_UA_LENGTH = 512\n\n/** One route's configured request headers and its fetch matching metadata. */\nexport interface HeaderOverride {\n /** `scheme://host:port` of the route's endpoint, exactly as Fetch would print it. */\n origin: string\n /** Normalized pathname prefix from the route's baseURL. */\n pathPrefix: string\n /**\n * The string header pairs to apply at the fetch layer. Empty when the route\n * declares none: the route still participates in matching, so a request that\n * clearly belongs to it is NOT given another route's headers.\n */\n headers: Record<string, string>\n /** The route key that declared them (diagnostics and UI labelling). */\n route: string\n /** Model IDs declared by this route, used to disambiguate shared endpoints. */\n modelIds: string[]\n /** The configured `user-agent`, retained for compatibility and diagnostics. */\n userAgent?: string\n /** Whether this route actually declares sendable request headers. */\n hasHeaders: boolean\n}\n\n/** Backwards-compatible name retained for callers that only knew the UA seam. */\nexport type UserAgentOverride = HeaderOverride\n\n/** A same-origin header disagreement that the URL-only fetch seam cannot disambiguate. */\nexport interface HeaderConflict {\n origin: string\n header: string\n routes: string[]\n values: string[]\n}\n\n/** The route index plus what could not be indexed or was ambiguous. */\nexport interface HeaderIndex {\n /** Every route with a usable endpoint, headers included or not. */\n routes: HeaderOverride[]\n /** Every route with sendable headers, retained for diagnostics and the UI. */\n overrides: HeaderOverride[]\n /** origin \u2192 first complete header override, used as a conservative fallback. */\n byOrigin: Map<string, HeaderOverride>\n /** Same-origin routes that declare different header values. */\n conflicts: { origin: string; routes: string[]; values: string[] }[]\n /** Same-origin disagreements for any configured header. */\n headerConflicts: HeaderConflict[]\n}\n\n/** Backwards-compatible name retained for the original public index contract. */\nexport type UserAgentIndex = HeaderIndex\n\n/** An empty index, for the \"no route declares headers\" case. */\nexport function emptyIndex(): HeaderIndex {\n return { routes: [], overrides: [], byOrigin: new Map(), conflicts: [], headerConflicts: [] }\n}\n\n/** The `scheme://host:port` of a URL string, or undefined when unparseable. */\nexport function originOf(url: string | undefined): string | undefined {\n if (url === undefined || url.trim().length === 0) return undefined\n try {\n return new URL(url).origin\n } catch {\n // A relative or malformed endpoint is not an origin this seam can match.\n return undefined\n }\n}\n\n/**\n * Whether a configured value can ride a Fetch `user-agent` field. Refused\n * rather than sanitized: a header carrying a newline is a request-splitting\n * hazard, and quietly rewriting the user's value would send something they\n * never asked for.\n * @param value - the configured header value.\n * @returns whether it is safe to `Headers.set()`.\n */\nexport function isSendableUserAgent(value: string): boolean {\n if (value.length === 0 || value.length > MAX_UA_LENGTH) return false\n // CR/LF and NUL are what Fetch's own guard rejects; refusing them here keeps\n // the refusal at configuration time instead of on every request.\n return !/[\\r\\n\\0]/.test(value)\n}\n\n/**\n * Whether a configured name/value pair can ride a Fetch header. Fetch is the\n * authority for the exact token grammar, so this accepts arbitrary legal names\n * instead of maintaining a brittle allow-list.\n */\nexport function isSendableHeader(name: string, value: string): boolean {\n if (name.length === 0) return false\n try {\n const headers = new Headers()\n headers.set(name, value)\n return true\n } catch {\n return false\n }\n}\n\n/** The `headers` dict of one route profile, as string pairs, or undefined. */\nexport function headersOf(profile: Record<string, unknown> | undefined): Record<string, string> | undefined {\n if (profile === undefined) return undefined\n const headers = profile['headers']\n if (!isRecord(headers)) return undefined\n const pairs: Record<string, string> = {}\n for (const [name, value] of Object.entries(headers)) {\n if (typeof value === 'string') pairs[name] = value\n }\n return Object.keys(pairs).length === 0 ? undefined : pairs\n}\n\n/**\n * The subset of a profile's headers that Fetch can send. An invalid stored\n * entry must not make the wrapper throw and break an otherwise valid request.\n */\nfunction sendableHeadersOf(profile: Record<string, unknown> | undefined): Record<string, string> | undefined {\n const headers = headersOf(profile)\n if (headers === undefined) return undefined\n const sendable: Record<string, string> = {}\n for (const [name, value] of Object.entries(headers)) {\n if (!isSendableHeader(name, value)) continue\n // Keep the historical UA guard: it avoids sending a malformed or\n // unexpectedly huge client identity while leaving every other legal header\n // available to the arbitrary-header editor.\n if (name.toLowerCase() === 'user-agent' && !isSendableUserAgent(value)) continue\n sendable[name] = value\n }\n return Object.keys(sendable).length === 0 ? undefined : sendable\n}\n\n/**\n * The `user-agent` a route's `headers` dict declares, case-insensitively.\n *\n * A `user-agent` stored here is the user's DECLARATION of the identity their\n * gateway wants, even though the official adapter discards it; the plugin reads\n * the same key so the settings document stays the single source of truth.\n * @param profile - one route's profile record.\n * @returns the value, or undefined when the route declares none.\n */\nexport function declaredUserAgent(profile: Record<string, unknown> | undefined): string | undefined {\n const headers = headersOf(profile)\n if (headers === undefined) return undefined\n for (const [name, value] of Object.entries(headers)) {\n if (name.toLowerCase() === 'user-agent') return isSendableUserAgent(value) ? value : undefined\n }\n return undefined\n}\n\n/** Normalize a route endpoint's pathname for boundary-safe prefix matching. */\nfunction pathPrefixOf(url: string): string {\n try {\n const pathname = new URL(url).pathname.replace(/\\/+$/, '')\n return pathname.length === 0 ? '/' : pathname\n } catch {\n return '/'\n }\n}\n\n/** Model IDs that can appear in a pi-ai request body for one route. */\nfunction modelIdsOf(profile: Record<string, unknown>): string[] {\n const ids = new Set<string>()\n const models = profile['models']\n if (Array.isArray(models)) {\n for (const model of models) {\n if (!isRecord(model) || typeof model['id'] !== 'string' || model['id'].length === 0) continue\n ids.add(model['id'])\n }\n }\n // modelOverrides is keyed by model id and can carry entries not repeated in\n // the explicit models array, so include it as another source of route identity.\n const overrides = profile['modelOverrides']\n if (isRecord(overrides)) {\n for (const id of Object.keys(overrides)) if (id.length > 0) ids.add(id)\n }\n return [...ids]\n}\n\n/** Normalize names the way Fetch's Headers object compares them. */\nfunction normalizedHeaders(headers: Record<string, string>): Map<string, { name: string; value: string }> {\n const normalized = new Map<string, { name: string; value: string }>()\n for (const [name, value] of Object.entries(headers)) {\n normalized.set(name.toLowerCase(), { name, value })\n }\n return normalized\n}\n\n/** Record a same-origin difference that the URL-only fetch seam cannot route. */\nfunction recordHeaderConflicts(index: HeaderIndex, existing: HeaderOverride, route: string, headers: Record<string, string>): void {\n const first = normalizedHeaders(existing.headers)\n const next = normalizedHeaders(headers)\n const names = new Set([...first.keys(), ...next.keys()])\n for (const name of names) {\n const oldEntry = first.get(name)\n const nextEntry = next.get(name)\n if (oldEntry?.value === nextEntry?.value) continue\n const reportedName = nextEntry?.name ?? oldEntry?.name ?? name\n const reported = index.headerConflicts.find(entry => entry.origin === existing.origin && entry.header.toLowerCase() === name)\n if (reported === undefined) {\n index.headerConflicts.push({\n origin: existing.origin,\n header: reportedName,\n routes: [existing.route, route],\n values: [oldEntry?.value ?? '<not configured>', nextEntry?.value ?? '<not configured>'],\n })\n } else if (!reported.routes.includes(route)) {\n reported.routes.push(route)\n reported.values.push(nextEntry?.value ?? '<not configured>')\n }\n }\n}\n\n/** Build the route index from each provider profile's endpoint and header declaration. */\nexport function buildHeaderIndex(\n providers: Record<string, Record<string, unknown>>,\n): HeaderIndex {\n const index = emptyIndex()\n const claimedUserAgents = new Map<string, { routes: string[]; values: string[] }>()\n for (const [route, profile] of Object.entries(providers)) {\n const baseURL = typeof profile['baseURL'] === 'string' ? profile['baseURL'] : undefined\n const origin = originOf(baseURL)\n if (origin === undefined) continue\n\n const sendable = sendableHeadersOf(profile) ?? {}\n const hasHeaders = Object.keys(sendable).length > 0\n const userAgent = Object.entries(sendable).find(([name]) => name.toLowerCase() === 'user-agent')?.[1]\n const override: HeaderOverride = {\n origin,\n pathPrefix: pathPrefixOf(baseURL ?? origin),\n headers: sendable,\n route,\n modelIds: modelIdsOf(profile),\n hasHeaders,\n ...(userAgent === undefined ? {} : { userAgent }),\n }\n // Every route is registered, headers or not: a route that declares no\n // headers must still be able to claim its own requests so another route on\n // the same endpoint cannot leak its headers onto them.\n index.routes.push(override)\n if (!hasHeaders) continue\n index.overrides.push(override)\n const existing = index.byOrigin.get(origin)\n if (existing === undefined) {\n index.byOrigin.set(origin, override)\n } else {\n recordHeaderConflicts(index, existing, route, sendable)\n }\n\n if (userAgent === undefined) continue\n const claimed = claimedUserAgents.get(origin)\n if (claimed === undefined) {\n claimedUserAgents.set(origin, { routes: [route], values: [userAgent] })\n continue\n }\n claimed.routes.push(route)\n claimed.values.push(userAgent)\n // Idempotent declaration (two routes, same identity) is not a UA conflict.\n if (claimed.values.every(value => value === claimed.values[0])) continue\n const reported = index.conflicts.find(entry => entry.origin === origin)\n if (reported === undefined) index.conflicts.push({ origin, routes: [...claimed.routes], values: [...claimed.values] })\n else {\n reported.routes = [...claimed.routes]\n reported.values = [...claimed.values]\n }\n }\n return index\n}\n\n/** Original public name retained while callers migrate to the generic index. */\nexport function buildUserAgentIndex(\n providers: Record<string, Record<string, unknown>>,\n): UserAgentIndex {\n return buildHeaderIndex(providers)\n}\n\n/** The pathname of a request URL, normalized the way {@link pathPrefixOf} is. */\nexport function requestPathOf(url: string): string | undefined {\n try {\n return new URL(url).pathname\n } catch {\n return undefined\n }\n}\n\n/** Whether a request path sits under a route's baseURL path prefix. */\nfunction pathMatches(requestPath: string, prefix: string): boolean {\n if (prefix === '/') return true\n return requestPath === prefix || requestPath.startsWith(`${prefix}/`)\n}\n\n/**\n * The model id carried by a JSON request body, or undefined when the body is\n * not JSON / names no string `model`. OpenAI-compatible chat completions and\n * responses both put the selected model in the top-level `model` field.\n */\nexport function modelOfJsonBody(body: string): string | undefined {\n try {\n const parsed: unknown = JSON.parse(body)\n if (!isRecord(parsed)) return undefined\n const model = parsed['model']\n return typeof model === 'string' && model.length > 0 ? model : undefined\n } catch {\n // A non-JSON body (multipart, SSE upload, empty) carries no model identity.\n return undefined\n }\n}\n\n/**\n * The routes that could own a request, narrowed by origin and endpoint path.\n *\n * The result is the set the fetch layer must disambiguate: one element means\n * the URL already identifies the route (no body read is needed), several means\n * only the request's own `model` can decide, and zero means no route matches.\n * @param index - the live route index.\n * @param url - the request URL.\n * @returns the candidate overrides, in declaration order.\n */\nexport function pathCandidatesOf(index: HeaderIndex, url: string): HeaderOverride[] {\n const origin = originOf(url)\n if (origin === undefined) return []\n // A hand-built index may carry only the origin map; honour it as the legacy\n // single-candidate shape.\n const known = index.routes.length === 0 ? index.overrides : index.routes\n const byOrigin = known.length === 0\n ? (() => { const only = index.byOrigin.get(origin); return only === undefined ? [] : [only] })()\n : known.filter(entry => entry.origin === origin)\n if (byOrigin.length <= 1) return byOrigin\n const requestPath = requestPathOf(url)\n if (requestPath === undefined) return byOrigin\n const matched = byOrigin.filter(entry => pathMatches(requestPath, entry.pathPrefix))\n // An empty path match means the route paths were not describable (or the\n // request targets a prefix no route declares): keep every candidate.\n return matched.length === 0 ? byOrigin : matched\n}\n\n/**\n * Pick one route out of already-narrowed candidates by the request body's model.\n *\n * The model only decides when exactly one candidate declares it; a model no\n * candidate declares, or a model several candidates share, falls back to the\n * first declarer \u2014 the same conservative rule as a request with no model at\n * all.\n * @param candidates - the path-narrowed candidates, in declaration order.\n * @param model - the model id read from the request body, when one was found.\n * @returns the override to apply, or undefined when there are no candidates.\n */\nexport function selectOverrideFrom(candidates: HeaderOverride[], model?: string): HeaderOverride | undefined {\n if (candidates.length <= 1) return candidates[0]\n if (model !== undefined) {\n const byModel = candidates.filter(entry => entry.modelIds.includes(model))\n if (byModel.length === 1) return byModel[0]\n }\n return candidates[0]\n}\n\n/**\n * Pick the route whose configured headers belong on one request.\n *\n * Two routes can share an origin, which the URL alone cannot separate. The\n * choice is therefore narrowed in three steps: the endpoint path prefix (see\n * {@link pathCandidatesOf}), then the `model` carried by the JSON body (see\n * {@link selectOverrideFrom}), then the first declarer. A request that cannot\n * be pinned down therefore keeps the conservative behaviour the plugin shipped\n * with, and the index's conflict report tells the user the endpoints overlap.\n * @param index - the live route index.\n * @param url - the request URL.\n * @param model - the model id read from the request body, when one was found.\n * @returns the override to apply, or undefined when no route matches.\n */\nexport function selectOverride(\n index: HeaderIndex,\n url: string,\n model?: string,\n): HeaderOverride | undefined {\n return selectOverrideFrom(pathCandidatesOf(index, url), model)\n}\n\n/**\n * The request URL a Fetch call is aimed at, or undefined when it cannot be\n * classified. A `Request` from another realm fails the `instanceof` test and is\n * reported as unclassifiable rather than mis-read \u2014 the same conservative\n * posture the official fetch seam takes.\n * @param input - the fetch input.\n * @returns the URL string, when one can be read.\n */\nexport function requestUrlOf(input: unknown): string | undefined {\n if (typeof input === 'string') return input\n if (typeof URL !== 'undefined' && input instanceof URL) return input.href\n if (typeof Request !== 'undefined' && input instanceof Request) return input.url\n return undefined\n}\n", "/**\n * The fetch-layer installer for provider request-header overrides. The decision of\n * WHAT to override lives in `headers-core.ts`; this module owns the global seam.\n *\n * Shape of the seam: one process-wide wrapper owns `globalThis.fetch`, and\n * every activation is an ENTRY inside it. That is what makes the plugin safe\n * next to itself (an HMR remount, a second composer, two plugin instances) and\n * what makes unloading exact: an entry leaves the registry and the wrapper is\n * restored only once the last entry is gone \u2014 never a blind\n * `globalThis.fetch = original` that would clobber a wrapper installed after\n * this one, and never a wrapper left behind holding the process's fetch.\n *\n * The wrapper is deliberately narrow: a request whose URL is not in the index\n * passes through with its ORIGINAL arguments (same object identity), so\n * unconfigured traffic pays exactly one URL classification and one index\n * lookup \u2014 no allocation beyond that, and no way for a bug in the merge path\n * to alter a request that never matched.\n *\n * Why fetch rather than the pi-ai `transformHeaders` option, which would be\n * narrower: reaching that option means holding the adapter's private `models`\n * collection, and every sanctioned seam (`llm/stream` waterfall,\n * `registerAdapter`) stops at the stream, above the wire. Fetch is the only\n * public surface that sees the merged headers. Both were probed against the\n * real runtime \u2014 see `.tmp-rel/headers-probe/`.\n *\n * @module dsh-model-think-level/headers-fetch\n */\n\nimport {\n emptyIndex,\n modelOfJsonBody,\n pathCandidatesOf,\n requestUrlOf,\n selectOverrideFrom,\n type HeaderIndex,\n type HeaderOverride,\n} from './headers-core.js'\n\n/** Registry key on `globalThis`, so a second plugin load shares the one wrapper. */\nconst REGISTRY = Symbol.for('dsh-model-think-level.fetch-overrides')\n\n/** One activation's contribution to the process-wide wrapper. */\ninterface Entry {\n /**\n * Reads the current index. A source rather than a value because the settings\n * document is live: a route added, edited, or removed on the Models page must\n * reach the next request without a plugin reload.\n */\n index: () => HeaderIndex\n}\n\n/** The process-wide wrapper state. */\ninterface Registry {\n base: typeof globalThis.fetch\n wrapper: typeof globalThis.fetch\n entries: Map<symbol, Entry>\n}\n\nfunction registryOf(): Registry | undefined {\n const holder = globalThis as unknown as Record<symbol, Registry | undefined>\n return holder[REGISTRY]\n}\n\n/**\n * Read a request body as text without consuming the request itself.\n *\n * The body is only read when the URL alone leaves the route ambiguous, so the\n * common single-route case still pays nothing. A `Request` is cloned (its\n * stream must survive for the real send); an `init.body` string is used\n * directly, and any other body shape (stream, FormData) yields undefined\n * rather than being disturbed.\n */\nasync function bodyTextOf(input: unknown, init: RequestInit | undefined): Promise<string | undefined> {\n if (typeof init?.body === 'string') return init.body\n if (typeof Request !== 'undefined' && input instanceof Request) {\n try {\n return await input.clone().text()\n } catch {\n // A body that cannot be cloned (already disturbed, or streamed) simply\n // leaves the route ambiguous and the first declarer serves.\n return undefined\n }\n }\n return undefined\n}\n\n/**\n * The caller's request headers as a mutable copy, seeded the way Fetch itself\n * resolves them: an explicit `init.headers` replaces a `Request`'s own headers,\n * and the `Request`'s are inherited only when the init names none. Seeding from\n * the wrong one would either drop the caller's headers or resurrect the ones\n * the caller replaced.\n */\nfunction seedHeaders(input: unknown, init: RequestInit | undefined): Headers {\n if (init?.headers !== undefined && init.headers !== null) return new Headers(init.headers as HeadersInit)\n if (typeof Request !== 'undefined' && input instanceof Request) return new Headers(input.headers)\n return new Headers()\n}\n\n/** The wrapper: inject the matched route's request headers and delegate everything else. */\nfunction makeWrapper(base: typeof globalThis.fetch, entries: Map<symbol, Entry>): typeof globalThis.fetch {\n return async function fetchWithProviderHeaders(input: RequestInfo | URL, init?: RequestInit): Promise<Response> {\n const url = requestUrlOf(input)\n if (url === undefined) return base(input, init)\n // The URL (origin + endpoint path) narrows the route. Only when it leaves\n // several candidates does the request body's `model` have to decide -- so a\n // single-route deployment keeps the zero-read, zero-allocation fast path.\n let candidates: HeaderOverride[] = []\n for (const entry of entries.values()) {\n candidates = pathCandidatesOf(entry.index(), url)\n if (candidates.length > 0) break\n }\n if (candidates.length === 0) return base(input, init)\n let override = candidates.length === 1 ? candidates[0] : undefined\n if (override === undefined) {\n const body = await bodyTextOf(input, init)\n const model = body === undefined ? undefined : modelOfJsonBody(body)\n override = selectOverrideFrom(candidates, model)\n }\n if (override === undefined) return base(input, init)\n // A route that claims the request but declares no headers is a deliberate\n // \"send nothing\": another route's identity must not leak onto it.\n if (!override.hasHeaders) return base(input, init)\n const headers = seedHeaders(input, init)\n for (const [name, value] of Object.entries(override.headers)) {\n // The index already filters invalid entries. Keep the seam defensive for\n // a live source supplied by another caller or a stale settings snapshot.\n try {\n headers.set(name, value)\n } catch {\n // A malformed stored pair must not prevent the remaining headers or the\n // underlying request from being sent.\n }\n }\n const nextInit = { ...init, headers }\n if (typeof Request !== 'undefined' && input instanceof Request) {\n return base(new Request(input, { headers }), nextInit)\n }\n return base(input, nextInit)\n }\n}\n\n/** Handle one activation keeps; `dispose` is idempotent. */\nexport interface HeaderOverlayHandle {\n /** Remove this activation's entry, restoring the original fetch when it was the last. */\n dispose(): void\n}\n\n/** Handle for tests and the caller to swap the index a live activation reads. */\nexport interface HeaderOverlay extends HeaderOverlayHandle {\n /** Whether this activation's entry is still installed. */\n readonly active: boolean\n}\n\n/** A mutable index source an activation reads on every request. */\nexport interface OverlaySource {\n current: HeaderIndex\n}\n\n/**\n * Install (or join) the process-wide header wrapper.\n * @param source - the live index this activation contributes.\n * @returns a handle whose `dispose` removes exactly this activation.\n */\nexport function installHeaderOverlay(source: OverlaySource): HeaderOverlay {\n const holder = globalThis as unknown as Record<symbol, Registry | undefined>\n let registry = holder[REGISTRY]\n const token = Symbol('bre-header-overlay')\n if (registry === undefined) {\n const base = globalThis.fetch\n const entries = new Map<symbol, Entry>()\n const wrapper = makeWrapper(base, entries)\n registry = { base, wrapper, entries }\n holder[REGISTRY] = registry\n globalThis.fetch = wrapper\n }\n registry.entries.set(token, { index: () => source.current })\n const owned = registry\n return {\n get active(): boolean {\n return owned.entries.has(token)\n },\n dispose(): void {\n owned.entries.delete(token)\n if (owned.entries.size > 0) return\n // Last one out restores the ORIGINAL function, and only when this\n // wrapper still holds the global: a later installer's wrapper must not be\n // clobbered by our teardown.\n if (globalThis.fetch === owned.wrapper) globalThis.fetch = owned.base\n if (holder[REGISTRY] === owned) delete holder[REGISTRY]\n },\n }\n}\n\n/** Whether this plugin's wrapper currently owns the global fetch (diagnostics). */\nexport function headerOverlayInstalled(): boolean {\n const registry = registryOf()\n return registry !== undefined && globalThis.fetch === registry.wrapper\n}\n\n/** The empty index, re-exported so callers building one need a single import. */\nexport { emptyIndex }\n", "/**\n * Request-level header bridge for the pi-ai-backed Harness adapter.\n *\n * The model-list probe has its own direct fetch path, but conversation requests\n * are assembled inside dsh-llm-pi-ai and then passed to pi-ai's Models service.\n * pi-ai exposes `transformHeaders` exactly after auth and request headers have\n * been merged, so it is the right place to restore the profile values that the\n * Harness attribution layer reserves (most visibly `user-agent`).\n *\n * dsh-llm-pi-ai does not expose its private Models collection through a public\n * plugin API. Its adapter is nevertheless registered in the public llm runtime,\n * and the runtime object keeps that registration in a normal `adapters` Map. The\n * bridge uses a narrow structural adapter of that implementation detail and\n * fails open for other adapters or older runtimes.\n *\n * @module dsh-model-think-level/headers-pi-ai\n */\n\nimport { isRecord } from './shared.js'\nimport { selectOverride, type HeaderIndex, type HeaderOverride } from './headers-core.js'\n\n/** A live route index shared with the fetch overlay. */\nexport interface PiAiHeaderSource {\n current: HeaderIndex\n}\n\ntype ProviderHeaders = Record<string, string | null>\ntype HeaderTransformer = (headers: ProviderHeaders) => ProviderHeaders | Promise<ProviderHeaders>\ntype UnknownFunction = (...args: unknown[]) => unknown\n\ntype ObjectLike = Record<PropertyKey, unknown>\n\ninterface PiAiPatchState {\n originalCurrent: UnknownFunction\n wrappedCurrent: UnknownFunction\n source: PiAiHeaderSource\n users: number\n}\n\ninterface RegisterPatchState {\n originalRegister: UnknownFunction\n wrappedRegister: UnknownFunction\n users: number\n}\n\nconst PATCH_STATE = Symbol.for('dsh-model-think-level.pi-ai-header-transform')\nconst REGISTER_PATCH_STATE = Symbol.for('dsh-model-think-level.pi-ai-header-register')\nconst CORDIS_ORIGINAL = Symbol.for('cordis.original')\n\nfunction objectOf(value: unknown): ObjectLike | undefined {\n return typeof value === 'object' && value !== null ? value as ObjectLike : undefined\n}\n\nfunction runtimeObjectOf(value: unknown): ObjectLike | undefined {\n const object = objectOf(value)\n if (object === undefined) return undefined\n const original = object[CORDIS_ORIGINAL]\n return objectOf(original) ?? object\n}\n\nfunction noOpHandle(): PiAiHeaderTransformHandle {\n return {\n active: false,\n dispose(): void {},\n }\n}\n\nfunction routeOverrideOf(source: PiAiHeaderSource, model: unknown): HeaderOverride | undefined {\n try {\n if (!isRecord(model)) return undefined\n const baseURL = model['baseUrl']\n if (typeof baseURL !== 'string' || baseURL.length === 0) return undefined\n const modelId = typeof model['id'] === 'string' ? model['id'] : undefined\n return selectOverride(source.current, baseURL, modelId)\n } catch {\n // A stale or partially written settings snapshot must never break a chat.\n return undefined\n }\n}\n\nfunction modelsProxyOf(models: ObjectLike, source: PiAiHeaderSource): ObjectLike {\n return new Proxy(models, {\n get(target, property, receiver): unknown {\n if (property !== 'streamSimple') return Reflect.get(target, property, receiver)\n const streamSimple = Reflect.get(target, property, target)\n if (typeof streamSimple !== 'function') return streamSimple\n return (...args: unknown[]): unknown => {\n const model = args[0]\n const context = args[1]\n const options = args[2]\n const modelObject = isRecord(model) ? model : undefined\n if (modelObject === undefined || typeof modelObject['baseUrl'] !== 'string' || !isRecord(options)) {\n return (streamSimple as UnknownFunction).call(target, model, context, options)\n }\n\n const existing = typeof options['transformHeaders'] === 'function'\n ? options['transformHeaders'] as HeaderTransformer\n : undefined\n const transformHeaders: HeaderTransformer = async (headers) => {\n // Preserve any transform supplied by the adapter/provider first; the\n // user's route headers are the final request-level values by design.\n const merged = existing === undefined ? headers : await existing(headers)\n const override = routeOverrideOf(source, model)\n return override?.hasHeaders ? { ...merged, ...override.headers } : merged\n }\n return (streamSimple as UnknownFunction).call(target, model, context, {\n ...options,\n transformHeaders,\n })\n }\n },\n })\n}\n\nfunction snapshotProxyOf(snapshot: ObjectLike, source: PiAiHeaderSource): ObjectLike {\n const models = snapshot['models']\n const modelObject = objectOf(models)\n if (modelObject === undefined || typeof modelObject['streamSimple'] !== 'function') return snapshot\n const proxiedModels = modelsProxyOf(modelObject, source)\n return new Proxy(snapshot, {\n get(target, property, receiver): unknown {\n if (property === 'models') return proxiedModels\n return Reflect.get(target, property, receiver)\n },\n })\n}\n\n/** Handle returned for one adapter patch. */\nexport interface PiAiHeaderTransformHandle {\n readonly active: boolean\n dispose(): void\n}\n\n/** Install the request-level transform on one pi-ai-shaped adapter. */\nexport function installPiAiHeaderTransform(adapter: unknown, source: PiAiHeaderSource): PiAiHeaderTransformHandle {\n const target = objectOf(adapter)\n if (target === undefined || typeof target['current'] !== 'function') return noOpHandle()\n\n const current = target['current'] as UnknownFunction\n const stored = target[PATCH_STATE] as PiAiPatchState | undefined\n if (stored !== undefined && current === stored.wrappedCurrent) {\n stored.source = source\n stored.users += 1\n let active = true\n return {\n get active(): boolean { return active && stored.users > 0 },\n dispose(): void {\n if (!active) return\n active = false\n stored.users -= 1\n if (stored.users > 0) return\n if (target['current'] === stored.wrappedCurrent) target['current'] = stored.originalCurrent\n if (target[PATCH_STATE] === stored) delete target[PATCH_STATE]\n },\n }\n }\n\n const originalCurrent = current\n const wrappedCurrent: UnknownFunction = function (this: unknown, ...args: unknown[]): unknown {\n const snapshot = originalCurrent.apply(this, args)\n const snapshotObject = objectOf(snapshot)\n return snapshotObject === undefined ? snapshot : snapshotProxyOf(snapshotObject, state.source)\n }\n const state: PiAiPatchState = { originalCurrent, wrappedCurrent, source, users: 1 }\n target['current'] = wrappedCurrent\n Object.defineProperty(target, PATCH_STATE, { configurable: true, value: state })\n\n let active = true\n return {\n get active(): boolean { return active && state.users > 0 },\n dispose(): void {\n if (!active) return\n active = false\n state.users -= 1\n if (state.users > 0) return\n if (target['current'] === state.wrappedCurrent) target['current'] = state.originalCurrent\n if (target[PATCH_STATE] === state) delete target[PATCH_STATE]\n },\n }\n}\n\n/** Diagnostic snapshot of the bridge's live attach state. */\nexport interface PiAiHeaderBridgeState {\n runtimeFound: boolean\n registerPatched: boolean\n adaptersInRuntime: number\n adaptersPatched: number\n adapters: string[]\n routes: number\n overrides: number\n}\n\n/**\n * Describe what the bridge is currently attached to. Read-only; used by the\n * probe route's `?diag=1` arm to make the request-header takeover observable\n * from the running host instead of only from a test harness.\n */\nexport function describePiAiHeaderState(llm: unknown, source: PiAiHeaderSource): PiAiHeaderBridgeState {\n const runtime = runtimeObjectOf(llm)\n const adapters = runtime?.['adapters']\n const names: string[] = []\n let total = 0\n let patched = 0\n if (adapters instanceof Map) {\n for (const registration of adapters.values()) {\n const adapter = objectOf(objectOf(registration)?.['adapter'])\n if (adapter === undefined || typeof adapter['current'] !== 'function') continue\n total += 1\n const state = adapter[PATCH_STATE] as PiAiPatchState | undefined\n const isPatched = state !== undefined && adapter['current'] === state.wrappedCurrent\n if (isPatched) patched += 1\n const name = typeof adapter['constructor'] === 'function' ? adapter['constructor'].name : 'unknown'\n names.push(`${name}${isPatched ? '+' : '-'}`)\n }\n }\n const registerState = runtime?.[REGISTER_PATCH_STATE] as RegisterPatchState | undefined\n return {\n runtimeFound: runtime !== undefined,\n registerPatched: registerState !== undefined && runtime?.['registerAdapter'] === registerState.wrappedRegister,\n adaptersInRuntime: total,\n adaptersPatched: patched,\n adapters: names,\n routes: source.current.routes.length,\n overrides: source.current.overrides.length,\n }\n}\n\n/**\n * Install the bridge on every current pi-ai-shaped registration and expose a\n * refresh for the runtime's `llm/adapters-updated` event.\n */\nexport interface PiAiHeaderTransformsHandle {\n refresh(): void\n dispose(): void\n}\n\nexport function installPiAiHeaderTransforms(llm: unknown, source: PiAiHeaderSource): PiAiHeaderTransformsHandle {\n const installed = new Map<object, PiAiHeaderTransformHandle>()\n const runtime = runtimeObjectOf(llm)\n let disposed = false\n\n const install = (adapter: unknown): void => {\n if (disposed) return\n const adapterObject = objectOf(adapter)\n if (adapterObject === undefined || typeof adapterObject['current'] !== 'function') return\n if (!installed.has(adapterObject)) installed.set(adapterObject, installPiAiHeaderTransform(adapterObject, source))\n }\n\n const refresh = (): void => {\n if (disposed) return\n const adapters = runtime?.['adapters']\n if (!(adapters instanceof Map)) return\n const seen = new Set<object>()\n for (const registration of adapters.values()) {\n const registrationObject = objectOf(registration)\n const adapterObject = objectOf(registrationObject?.['adapter'])\n if (adapterObject === undefined || typeof adapterObject['current'] !== 'function') continue\n seen.add(adapterObject)\n install(adapterObject)\n }\n for (const [adapter, handle] of installed) {\n if (seen.has(adapter)) continue\n handle.dispose()\n installed.delete(adapter)\n }\n }\n\n // dsh-llm-pi-ai registers its adapter through this public method. Install\n // before delegating so a registration cannot emit an update and dispatch a\n // request in between the registry mutation and our refresh listener.\n let registerHandle: PiAiHeaderTransformHandle | undefined\n const originalRegister = runtime?.['registerAdapter']\n if (runtime !== undefined && typeof originalRegister === 'function') {\n const registerState = runtime[REGISTER_PATCH_STATE] as RegisterPatchState | undefined\n if (registerState !== undefined && runtime['registerAdapter'] === registerState.wrappedRegister) {\n registerState.users += 1\n registerHandle = {\n get active(): boolean { return !disposed && registerState.users > 0 },\n dispose(): void {\n if (registerState.users <= 0) return\n registerState.users -= 1\n if (registerState.users > 0) return\n if (runtime['registerAdapter'] === registerState.wrappedRegister) runtime['registerAdapter'] = registerState.originalRegister\n if (runtime[REGISTER_PATCH_STATE] === registerState) delete runtime[REGISTER_PATCH_STATE]\n },\n }\n } else {\n const original = originalRegister as UnknownFunction\n const wrappedRegister: UnknownFunction = function (this: unknown, ...args: unknown[]): unknown {\n const adapter = args[1]\n install(adapter)\n try {\n return original.apply(this, args)\n } finally {\n refresh()\n }\n }\n const state: RegisterPatchState = {\n originalRegister: original,\n wrappedRegister,\n users: 1,\n }\n runtime['registerAdapter'] = wrappedRegister\n Object.defineProperty(runtime, REGISTER_PATCH_STATE, { configurable: true, value: state })\n registerHandle = {\n get active(): boolean { return !disposed && state.users > 0 },\n dispose(): void {\n if (state.users <= 0) return\n state.users -= 1\n if (state.users > 0) return\n if (runtime['registerAdapter'] === state.wrappedRegister) runtime['registerAdapter'] = state.originalRegister\n if (runtime[REGISTER_PATCH_STATE] === state) delete runtime[REGISTER_PATCH_STATE]\n },\n }\n }\n }\n refresh()\n\n return {\n refresh,\n dispose(): void {\n if (disposed) return\n disposed = true\n registerHandle?.dispose()\n for (const handle of installed.values()) handle.dispose()\n installed.clear()\n },\n }\n}\n", "/**\n * Coexistence report for the user-agent takeover (issue #12, MVP-3).\n *\n * Overriding `user-agent` is not a private act: the stock adapter drops the\n * profile's value, so at least one published plugin patches the adapter itself\n * to keep it, and several more wrap fetch. Two of them active at once means the\n * LAST writer on the wire wins and the user sees a `user-agent` they did not\n * choose \u2014 with no error anywhere. This module reports what it found instead of\n * silently fighting.\n *\n * Three signals, in descending reliability:\n * 1. The adapter file already carries a user-agent patch (its `requestHeaders`\n * body no longer drops the profile's `user-agent`) \u2014 readable fact.\n * 2. A known sibling plugin's package is installed in a reachable tree.\n * 3. Nothing found.\n *\n * Everything here is best-effort and side-effect-free: an unreadable path, an\n * absent tree, or a hostile `package.json` yields `unknown`, never a throw \u2014\n * this report must not be able to disable the plugin.\n *\n * @module dsh-model-think-level/headers-conflict\n */\n\nimport { existsSync, readFileSync } from 'node:fs'\nimport { createRequire } from 'node:module'\nimport { dirname, join, resolve } from 'node:path'\n\n/**\n * Sibling plugins that rewrite the same request surface. The list is by PACKAGE\n * NAME, matched anywhere in a reachable `node_modules`: a plugin installed\n * under a profile but not enabled is reported as installed, and the report says\n * so rather than guessing at enablement (which a patch file or a hand-edited\n * profile can decide several ways).\n */\nconst SIBLING_PACKAGES = [\n 'dsh-client-masquerade',\n 'dsh-llm-headers',\n 'dsh-llm-pi-ai-headers',\n 'dsh-custom-provider-settings',\n] as const\n\n/**\n * Fragments proving the installed adapter already preserves a profile\n * `user-agent`. The published patch rewrites `requestHeaders()` to look for a\n * configured value; older revisions of it used the same identifier, so the\n * check survives their textual reshuffle while staying specific enough that the\n * stock function cannot match (it contains neither).\n */\nconst ADAPTER_PATCH_MARKERS = ['configuredUserAgent', 'masquerade routes rely on'] as const\n\n/** What the report found about the adapter the requests actually flow through. */\nexport type AdapterPatchState = 'patched' | 'stock' | 'unknown'\n\n/** One sibling plugin package found on disk. */\nexport interface InstalledSibling {\n /** Package name. */\n name: string\n /** Absolute path of the resolved package directory (or entry file). */\n path: string\n}\n\n/** The coexistence report. */\nexport interface HeaderConflictReport {\n /** Whether the installed `@deepseek-ai/dsh-llm-pi-ai` adapter carries a UA patch. */\n adapter: AdapterPatchState\n /** Path of the inspected adapter file, when one was found. */\n adapterPath?: string\n /** Known sibling plugins present on disk. */\n siblings: InstalledSibling[]\n /**\n * Whether this deployment should prefer the official layer instead of this\n * plugin's fetch takeover: true exactly when the adapter is already patched\n * (a profile `user-agent` reaches the wire on its own then, and a fetch\n * override on top would fight the patch).\n */\n preferOfficialLayer: boolean\n}\n\n/** Candidate `node_modules` roots to look in, most specific first. */\nfunction searchRoots(): string[] {\n const roots = new Set<string>()\n const entry = process.argv[1]\n if (typeof entry === 'string' && entry.length > 0) {\n let dir = dirname(resolve(entry))\n // Walk up a bounded number of levels: the shim, the bin dir, the package,\n // the install root.\n for (let depth = 0; depth < 8; depth += 1) {\n roots.add(join(dir, 'node_modules'))\n const parent = dirname(dir)\n if (parent === dir) break\n dir = parent\n }\n }\n // The cwd tree covers a profile-relative launch; the require chain covers\n // everything the process itself can no longer name.\n roots.add(join(process.cwd(), 'node_modules'))\n try {\n const require = createRequire(import.meta.url)\n for (const name of SIBLING_PACKAGES) {\n try {\n roots.add(join(dirname(dirname(dirname(require.resolve(`${name}/package.json`)))), 'node_modules'))\n } catch {\n // Not resolvable from here; the path search below covers the rest.\n }\n }\n } catch {\n // No require chain: path search alone.\n }\n return [...roots]\n}\n\n/** Locate the installed pi-ai adapter's bundle, or undefined when unreachable. */\nfunction findAdapterFile(): string | undefined {\n const relative = join('@deepseek-ai', 'dsh-llm-pi-ai', 'lib', 'index.js')\n const candidates: string[] = []\n try {\n const require = createRequire(import.meta.url)\n candidates.push(require.resolve('@deepseek-ai/dsh-llm-pi-ai'))\n } catch {\n // Resolve by location instead.\n }\n // dsh ships the adapter inside its own tree; probing the entry's ancestry\n // finds it for a global install, a profile install, and a monorepo alike.\n for (const root of searchRoots()) candidates.push(join(root, relative))\n for (const candidate of candidates) {\n if (existsSync(candidate)) return candidate\n }\n return undefined\n}\n\n/**\n * Whether a source text of the pi-ai adapter bundle carries a user-agent patch.\n *\n * Pure, so the decision is testable without touching a real installation: the\n * stock `requestHeaders()` filters the profile's `user-agent` into the reserved\n * set and contains neither marker, while every published revision of the patch\n * names the value it found.\n * @param source - the adapter bundle's text.\n * @returns whether the patch is present.\n */\nexport function adapterSourcePatched(source: string): boolean {\n return ADAPTER_PATCH_MARKERS.some(marker => source.includes(marker))\n}\n\n/** Whether the adapter bundle at one path carries a user-agent patch. */\nfunction adapterPatchState(path: string): AdapterPatchState {\n try {\n return adapterSourcePatched(readFileSync(path, 'utf8')) ? 'patched' : 'stock'\n } catch {\n return 'unknown'\n }\n}\n\n/** Known sibling plugins present in a reachable tree. */\nfunction findSiblings(): InstalledSibling[] {\n const found: InstalledSibling[] = []\n const seen = new Set<string>()\n for (const root of searchRoots()) {\n for (const name of SIBLING_PACKAGES) {\n if (seen.has(name)) continue\n const dir = join(root, name)\n const manifest = join(dir, 'package.json')\n if (!existsSync(manifest)) continue\n seen.add(name)\n found.push({ name, path: dir })\n }\n }\n return found\n}\n\n/**\n * Produce the coexistence report. Never throws: every probe degrades to\n * `unknown` / an empty list.\n * @returns the report.\n */\nexport function detectHeaderConflicts(): HeaderConflictReport {\n let adapter: AdapterPatchState = 'unknown'\n let adapterPath: string | undefined\n let siblings: InstalledSibling[] = []\n try {\n adapterPath = findAdapterFile()\n if (adapterPath !== undefined) adapter = adapterPatchState(adapterPath)\n } catch {\n adapter = 'unknown'\n }\n try {\n siblings = findSiblings()\n } catch {\n siblings = []\n }\n return {\n adapter,\n ...(adapterPath === undefined ? {} : { adapterPath }),\n siblings,\n preferOfficialLayer: adapter === 'patched',\n }\n}\n", "/**\n * The knowledge-base auto-fill: build the settings patch that declares\n * `reasoningEfforts` -- and, unless declined, the input-modality declaration --\n * on every undeclared model of a providers dict.\n *\n * Shared by BOTH halves on purpose. The host builds its boot fill with it, and\n * the browser half builds the very same patch from its own read, so one\n * suggestion can never produce two different documents. Pure data logic: no\n * harness package, no node or DOM API.\n *\n * @module dsh-model-think-level/autofill\n */\n\nimport { AUTOFILL_MARKER, INPUT_UNSET_MARKER, UNSET_MARKER } from './constants.js'\nimport { isSelfHostedRelay, NEW_COMPAT_KEYS, suggestEfforts } from './knowledge.js'\nimport { isRecord, routeFactsOf } from './shared.js'\n\n/** A JSON object patch. */\ntype JsonObject = Record<string, unknown>\n\n/**\n * Whether a model row carries an input-modality declaration the document\n * already answers with. An absent key and an empty array both read as \"no\n * answer here\" -- mirroring how llm-pi-ai's own resolution treats them.\n */\nfunction declaresInput(model: JsonObject): boolean {\n const input = model['input']\n return Array.isArray(input) && input.length > 0\n}\n\n/**\n * Build a patch that adds reasoningEfforts -- and, unless declined, the\n * input-modality declaration -- to every undeclared model of the given\n * routes, from the knowledge base / protocol inference. Returns the partial\n * providers patch, or undefined when nothing needs filling.\n * @param providers - the resolved providers dict.\n * @param routeFilter - optional route filter (defaults to all routes).\n * @param options - fill switches; both default on.\n * @param revision - settings revision this read is based on; recorded as the\n * provenance marker of every ladder filled here (see {@link AUTOFILL_MARKER}).\n */\nexport function buildAutofillPatch(\n providers: unknown,\n routeFilter: (route: string) => boolean = () => true,\n options: { efforts?: boolean; modalities?: boolean } = {},\n revision = 0,\n): JsonObject | undefined {\n const fillEfforts = options.efforts !== false\n const fillModalities = options.modalities !== false\n if (!isRecord(providers)) return undefined\n const patchRoutes: JsonObject = {}\n for (const route of Object.keys(providers)) {\n if (!routeFilter(route)) continue\n // Read the RAW models array: this builder rebuilds the array verbatim,\n // so a route carrying a row it cannot represent (non-record) is left\n // alone \u2014 a filtered rebuild would silently DELETE that row.\n const profile = providers[route]\n const rawModels = isRecord(profile) && Array.isArray(profile['models']) ? profile['models'] : undefined\n if (rawModels === undefined || rawModels.length === 0) continue\n if (!rawModels.every(isRecord)) continue\n const models = rawModels as Record<string, unknown>[]\n const nextModels: JsonObject[] = []\n let changed = false\n for (const model of models) {\n // Declared parts are untouched \u2014 and so are parts the user\n // deliberately unset: the durable markers record those absences as\n // decisions, so auto-fill never reads them back as gaps (the bug this\n // guards: a refill one event after every user \"unset\").\n const effortsDeclared = model['reasoningEfforts'] !== undefined || model[UNSET_MARKER] === true\n const inputDeclared = declaresInput(model) || model[INPUT_UNSET_MARKER] === true\n if ((effortsDeclared || !fillEfforts) && (inputDeclared || !fillModalities)) {\n // Versioned exception to never-touch-declared (issue #2): a declared\n // ladder whose compat lacks the role pin on a self-hosted relay gets\n // exactly that field merged in -- the declaration itself is untouched.\n const backfilled = backfillRolePin(model, providers, route)\n if (backfilled !== undefined) {\n changed = true\n nextModels.push(backfilled)\n } else {\n nextModels.push(model)\n }\n continue\n }\n const id = typeof model['id'] === 'string' ? model['id'] : ''\n if (id.length === 0) {\n nextModels.push(model)\n continue\n }\n const routeInfo = routeFactsOf(providers, route)\n const name = typeof model['name'] === 'string' ? model['name'] : undefined\n const suggestion = suggestEfforts(id, { ...routeInfo, displayName: name ?? routeInfo.displayName })\n if (suggestion.efforts === undefined) {\n nextModels.push(model)\n continue\n }\n const fill: JsonObject = { ...model }\n let touched = false\n // Capacities are never filled here: contextWindow / maxTokens are\n // display-only reference values in the browser half, and writing them\n // host-side would silently override the route defaults.\n // Reaching this branch means neither part was declared and no durable\n // unset marker stands on the row -- so there is no stale marker inside\n // `fill` to scrub; the guards above already excluded it.\n if (!effortsDeclared && fillEfforts) {\n touched = true\n fill['reasoningEfforts'] = suggestion.efforts as JsonObject\n // Provenance: the browser flush has to be able to tell this knowledge\n // base suggestion apart from a declaration the user made, or a staged\n // intent that differs in one spelling is dropped as a takeover (see\n // AUTOFILL_MARKER). The value is the revision this fill read.\n fill[AUTOFILL_MARKER] = revision\n if (suggestion.compat !== undefined) {\n const stored = isRecord(model['compat']) ? (model['compat'] as JsonObject) : {}\n fill['compat'] = { ...stored, ...(suggestion.compat as JsonObject) }\n }\n }\n if (!inputDeclared && fillModalities && suggestion.input !== undefined) {\n touched = true\n fill['input'] = [...suggestion.input]\n }\n if (!touched) {\n nextModels.push(model)\n continue\n }\n changed = true\n nextModels.push(fill)\n }\n if (changed) patchRoutes[route] = { models: nextModels }\n }\n return Object.keys(patchRoutes).length === 0 ? undefined : { providers: patchRoutes }\n}\n\n/** Strip newer-only compat keys from an autofill patch (older-kernel downgrade). */\nexport function stripNewCompatKeysDeep(patch: JsonObject): JsonObject | undefined {\n const providers = isRecord(patch['providers']) ? (patch['providers'] as JsonObject) : undefined\n if (providers === undefined) return undefined\n let strippedAny = false\n const nextProviders: JsonObject = {}\n for (const [route, profile] of Object.entries(providers)) {\n if (!isRecord(profile) || !Array.isArray(profile['models'])) {\n nextProviders[route] = profile as JsonObject\n continue\n }\n nextProviders[route] = {\n ...(profile as JsonObject),\n models: (profile['models'] as JsonObject[]).map(model => {\n if (!isRecord(model) || !isRecord(model['compat'])) return model\n const compat = { ...(model['compat'] as JsonObject) }\n for (const key of NEW_COMPAT_KEYS) {\n if (key in compat) {\n delete compat[key]\n strippedAny = true\n }\n }\n return { ...model, compat }\n }),\n }\n }\n if (!strippedAny) return undefined\n return { providers: nextProviders }\n}\n\n/**\n * Merge the role pin into one declared model row, or refuse it.\n *\n * Refusals (all silent, all deliberate): the row carries no ladder dict\n * (`false`, absent, or a deliberate-unset marker -- bare rows keep the bare\n * wire behavior they were chosen for); its compat already names an explicit\n * role value; or the route is not a self-hosted relay. A refusal changes\n * nothing; an acceptance touches exactly one compat field.\n */\nfunction backfillRolePin(\n model: Record<string, unknown>,\n providers: unknown,\n route: string,\n): JsonObject | undefined {\n if (!isRecord(model['reasoningEfforts'])) return undefined\n if (model[UNSET_MARKER] === true) return undefined\n const compat = model['compat']\n const base: JsonObject = isRecord(compat) ? { ...compat } : {}\n if (base['supportsDeveloperRole'] !== undefined) return undefined\n if (!isSelfHostedRelay(routeFactsOf(providers, route))) return undefined\n return { ...model, compat: { ...base, supportsDeveloperRole: false } }\n}\n"],
|
|
5
|
+
"mappings": "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",
|
|
6
6
|
"names": ["compat", "name", "name", "name", "active", "name", "readFileSync", "dirname", "join", "require", "name", "name", "resolve", "name", "ref"]
|
|
7
7
|
}
|