@kenkaiiii/gg-core 5.53.2 → 5.54.0
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/dist/{chunk-DZ2MDZM7.js → chunk-5NAQ4Q5O.js} +23 -1
- package/dist/{chunk-DZ2MDZM7.js.map → chunk-5NAQ4Q5O.js.map} +1 -1
- package/dist/index.cjs +23 -1
- package/dist/index.cjs.map +1 -1
- package/dist/index.js +2 -2
- package/dist/index.js.map +1 -1
- package/dist/model-registry.cjs +22 -0
- package/dist/model-registry.cjs.map +1 -1
- package/dist/model-registry.js +1 -1
- package/package.json +2 -2
package/dist/index.js
CHANGED
|
@@ -54,7 +54,7 @@ import {
|
|
|
54
54
|
registerRuntimeModels,
|
|
55
55
|
usesOpenAICodexTransport,
|
|
56
56
|
withFileLock
|
|
57
|
-
} from "./chunk-
|
|
57
|
+
} from "./chunk-5NAQ4Q5O.js";
|
|
58
58
|
import {
|
|
59
59
|
getAppPaths
|
|
60
60
|
} from "./chunk-EAIPT76S.js";
|
|
@@ -139,7 +139,7 @@ function getSupportedThinkingLevels(provider, model) {
|
|
|
139
139
|
return GLM_THINKING_LEVELS.slice(0, maxIndex2 + 1);
|
|
140
140
|
}
|
|
141
141
|
if (!isOpenAIGptModel(provider, model)) return [maxLevel];
|
|
142
|
-
const levels = model.startsWith("gpt-5.6-") ? OPENAI_GPT_56_THINKING_LEVELS : OPENAI_GPT_THINKING_LEVELS;
|
|
142
|
+
const levels = model.startsWith("gpt-5.6-") || model.startsWith("gpt-6-") ? OPENAI_GPT_56_THINKING_LEVELS : OPENAI_GPT_THINKING_LEVELS;
|
|
143
143
|
const maxIndex = levels.indexOf(maxLevel);
|
|
144
144
|
if (maxIndex === -1) return ["medium"];
|
|
145
145
|
return levels.slice(0, maxIndex + 1);
|
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/thinking-level.ts","../src/local-models.ts","../src/provider-usage.ts","../src/telegram.ts","../src/voice-transcriber.ts","../src/auto-update.ts"],"sourcesContent":["import type { Provider, ThinkingLevel } from \"@kenkaiiii/gg-ai\";\nimport { getMaxThinkingLevel, getModel } from \"./model-registry.js\";\n\nconst OPENAI_GPT_THINKING_LEVELS: readonly ThinkingLevel[] = [\"medium\", \"high\", \"xhigh\"];\nconst OPENAI_GPT_56_THINKING_LEVELS: readonly ThinkingLevel[] = [\n \"low\",\n \"medium\",\n \"high\",\n \"xhigh\",\n \"max\",\n \"ultra\",\n];\n// Sakana Fugu accepts exactly two reasoning efforts — \"high\" and \"xhigh\" — and\n// rejects anything else. Expose both so users can pick the lighter tier instead\n// of being forced into all-or-nothing xhigh.\nconst SAKANA_THINKING_LEVELS: readonly ThinkingLevel[] = [\"high\", \"xhigh\"];\n// Grok reasoning models take reasoning_effort low/medium/high (server default\n// high; reasoning can't be fully disabled — \"off\" just omits the param). Grok\n// 4.6 adds an `xhigh` top rung (docs: low/medium/high default/xhigh); 4.5\n// keeps its `high` ceiling because each model slices this ladder by its\n// registry maxThinkingLevel.\nconst XAI_THINKING_LEVELS: readonly ThinkingLevel[] = [\"low\", \"medium\", \"high\", \"xhigh\"];\n// Opus 5 / 4.7 expose the full ladder including xhigh (\"extended capability for\n// long-horizon work\"). Other adaptive Anthropic models omit xhigh and would 400.\nconst ANTHROPIC_XHIGH_THINKING_LEVELS: readonly ThinkingLevel[] = [\n \"low\",\n \"medium\",\n \"high\",\n \"xhigh\",\n \"max\",\n];\nconst ANTHROPIC_ADAPTIVE_THINKING_LEVELS: readonly ThinkingLevel[] = [\n \"low\",\n \"medium\",\n \"high\",\n \"max\",\n];\n// Kimi K3's effort ladder is declared server-side via /models think_efforts:\n// [\"low\",\"high\",\"max\"] on both the public API (default max) and the Kimi For\n// Coding OAuth endpoint (default high) — verified live 2026-07-21. Unlisted\n// efforts are rejected with a 400, so expose exactly the declared rungs.\nconst MOONSHOT_K3_THINKING_LEVELS: readonly ThinkingLevel[] = [\"low\", \"high\", \"max\"];\n// GLM's ladder is declared by the endpoint itself: an unknown effort 400s with\n// `reasoning_effort must be one of: none, minimal, low, medium, high, xhigh,\n// max` (verified live against glm-5.3, 2026-08-14). `none` is the thinking\n// toggle's job and `minimal` has no ThinkingLevel counterpart, so expose the\n// five rungs we can actually name. Effort is real, not cosmetic — measured\n// end-to-end on one hard reasoning prompt: low 0.8K reasoning chars / 15s,\n// high 3.2K / 28s, max 24.9K / 129s.\nconst GLM_THINKING_LEVELS: readonly ThinkingLevel[] = [\"low\", \"medium\", \"high\", \"xhigh\", \"max\"];\n/**\n * Effort ladder for locally hosted models. `xhigh`/`ultra` are deliberately\n * absent: no local server defines them (Ollama 0.32 answers\n * `invalid reasoning value: 'xhigh' (must be \"high\", \"medium\", \"low\", \"max\", or\n * \"none\")`). Each model's own ceiling comes from its endpoint — see\n * `toModelInfo` in local-models.ts.\n */\nconst LOCAL_THINKING_LEVELS: readonly ThinkingLevel[] = [\"low\", \"medium\", \"high\", \"max\"];\n\nfunction isOpenAIGptModel(provider: Provider, model: string): boolean {\n return provider === \"openai\" && model.startsWith(\"gpt-\");\n}\n\nfunction isSakanaModel(provider: Provider): boolean {\n return provider === \"sakana\";\n}\n\nfunction isXaiModel(provider: Provider): boolean {\n return provider === \"xai\";\n}\n\nfunction isMoonshotK3Model(provider: Provider, model: string): boolean {\n return provider === \"moonshot\" && model === \"kimi-k3\";\n}\n\nfunction isGlmModel(provider: Provider): boolean {\n return provider === \"glm\";\n}\n\nfunction isAnthropicXhighModel(provider: Provider, model: string): boolean {\n return provider === \"anthropic\" && /opus-5|opus-4-8|opus-4-7/.test(model);\n}\n\nfunction isAnthropicAdaptiveModel(provider: Provider, model: string): boolean {\n return (\n provider === \"anthropic\" &&\n /opus-5|opus-4-8|opus-4-7|opus-4-6|sonnet-5|fable-5|mythos-5/.test(model)\n );\n}\n\nexport function getSupportedThinkingLevels(\n provider: Provider,\n model: string,\n): readonly ThinkingLevel[] {\n // Local models: reasoning support is per-model and probed, not assumed. A\n // non-reasoning local model must never be sent a reasoning_effort — Ollama\n // hard-400s (`\"llama3.2\" does not support thinking`) — so it offers no levels\n // at all and the thinking toggle stays hidden.\n if (provider === \"local\") {\n const info = getModel(model);\n if (!info?.supportsThinking) return [];\n // The ceiling is the endpoint's, set at discovery: Ollama takes\n // low/medium/high/max, while the other OpenAI-compatible servers only\n // define low/medium/high (verified — Ollama rejects xhigh outright).\n const maxIndex = LOCAL_THINKING_LEVELS.indexOf(info.maxThinkingLevel);\n return maxIndex === -1\n ? LOCAL_THINKING_LEVELS.slice(0, 3)\n : LOCAL_THINKING_LEVELS.slice(0, maxIndex + 1);\n }\n const maxLevel = getMaxThinkingLevel(model);\n if (isAnthropicAdaptiveModel(provider, model)) {\n const levels = isAnthropicXhighModel(provider, model)\n ? ANTHROPIC_XHIGH_THINKING_LEVELS\n : ANTHROPIC_ADAPTIVE_THINKING_LEVELS;\n const maxIndex = levels.indexOf(maxLevel);\n if (maxIndex === -1) return [\"low\", \"medium\", \"high\"];\n return levels.slice(0, maxIndex + 1);\n }\n\n if (isSakanaModel(provider)) {\n const maxIndex = SAKANA_THINKING_LEVELS.indexOf(maxLevel);\n if (maxIndex === -1) return SAKANA_THINKING_LEVELS;\n return SAKANA_THINKING_LEVELS.slice(0, maxIndex + 1);\n }\n\n if (isXaiModel(provider)) {\n const maxIndex = XAI_THINKING_LEVELS.indexOf(maxLevel);\n if (maxIndex === -1) return XAI_THINKING_LEVELS;\n return XAI_THINKING_LEVELS.slice(0, maxIndex + 1);\n }\n\n if (isMoonshotK3Model(provider, model)) return MOONSHOT_K3_THINKING_LEVELS;\n\n if (isGlmModel(provider)) {\n const maxIndex = GLM_THINKING_LEVELS.indexOf(maxLevel);\n if (maxIndex === -1) return GLM_THINKING_LEVELS;\n return GLM_THINKING_LEVELS.slice(0, maxIndex + 1);\n }\n\n if (!isOpenAIGptModel(provider, model)) return [maxLevel];\n\n const levels = model.startsWith(\"gpt-5.6-\")\n ? OPENAI_GPT_56_THINKING_LEVELS\n : OPENAI_GPT_THINKING_LEVELS;\n const maxIndex = levels.indexOf(maxLevel);\n if (maxIndex === -1) return [\"medium\"];\n return levels.slice(0, maxIndex + 1);\n}\n\nexport function isThinkingLevelSupported(\n provider: Provider,\n model: string,\n level: ThinkingLevel,\n): boolean {\n return getSupportedThinkingLevels(provider, model).includes(level);\n}\n\nexport function getNextThinkingLevel(\n provider: Provider,\n model: string,\n current: ThinkingLevel | undefined,\n): ThinkingLevel | undefined {\n const supportedLevels = getSupportedThinkingLevels(provider, model);\n const shouldCycleLevels =\n isOpenAIGptModel(provider, model) ||\n isAnthropicAdaptiveModel(provider, model) ||\n isSakanaModel(provider) ||\n isXaiModel(provider) ||\n isMoonshotK3Model(provider, model) ||\n isGlmModel(provider) ||\n // Local servers take a real effort level, not just on/off: Ollama accepts\n // low/medium/high on `reasoning_effort` (verified against 0.32) and the\n // other OpenAI-compatible servers use the same three. A model that can't\n // reason at all already has no supported levels, so it never gets here.\n provider === \"local\";\n if (!shouldCycleLevels) {\n return current ? undefined : supportedLevels[0];\n }\n\n if (!current) return supportedLevels[0];\n const index = supportedLevels.indexOf(current);\n if (index === -1) return supportedLevels[0];\n return supportedLevels[index + 1];\n}\n","/**\n * Local model discovery — Ollama, LM Studio, llama.cpp (`llama-server`), vLLM,\n * and any other OpenAI-compatible server the user points us at.\n *\n * Everything rides the OpenAI-compatible `/v1` transport (see the `local`\n * provider in gg-ai's stream.ts); the only per-server difference is where the\n * *capabilities* come from, because `GET /v1/models` reports nothing useful:\n *\n * - Ollama → `POST /api/show` → `capabilities[]` + `model_info[\"<arch>.context_length\"]`\n * - LM Studio → `GET /api/v0/models` → `type`, `state`, `max_context_length`\n * - llama.cpp → `GET /props` → `default_generation_settings.n_ctx`\n * - vLLM/other → nothing; `max_model_len` sometimes rides the model object.\n *\n * Probing never throws: an unreachable server is a normal state (the user just\n * doesn't have it running), not an error to surface.\n */\nimport type { ModelInfo } from \"./model-registry.js\";\nimport { log } from \"./logger.js\";\n\n// ── Types ──────────────────────────────────────────────────\n\n/** Which capability API a local endpoint speaks, beyond plain `/v1/models`. */\nexport type LocalEndpointKind = \"ollama\" | \"lmstudio\" | \"llamacpp\" | \"vllm\" | \"custom\";\n\nexport interface LocalEndpoint {\n /** Stable slug, used in model ids (`local/<id>/<rawId>`) and auth keys (`local:<id>`). */\n id: string;\n label: string;\n /** OpenAI-compatible base URL, including the `/v1` suffix. */\n baseUrl: string;\n kind: LocalEndpointKind;\n /** Optional bearer token (LM Studio 0.4+ can require one). */\n apiKey?: string;\n /** True for endpoints the user added by hand (removable). */\n custom?: boolean;\n}\n\n/** One model as reported (and enriched) by a local server. */\nexport interface LocalModel {\n /** Model id on the wire, exactly as the server names it (e.g. `qwen3-coder:30b`). */\n rawId: string;\n endpointId: string;\n contextWindow: number;\n /** True when the server told us the real window; false means we guessed. */\n contextWindowKnown: boolean;\n supportsTools: boolean;\n supportsImages: boolean;\n supportsThinking: boolean;\n /** LM Studio only: whether the model is currently resident in memory. */\n loaded?: boolean;\n}\n\nexport interface LocalEndpointProbe {\n endpoint: LocalEndpoint;\n reachable: boolean;\n /** Human-readable reason when `reachable` is false (never a raw stack). */\n reason?: string;\n models: LocalModel[];\n}\n\n// ── Defaults ───────────────────────────────────────────────\n\n/**\n * The server we look for without being asked. LM Studio, llama.cpp and vLLM\n * are no longer auto-probed — one honest row beats four mostly-dead ones;\n * anything else is one \"Add endpoint\" away (custom kind keeps working).\n */\nexport const DEFAULT_LOCAL_ENDPOINTS: readonly LocalEndpoint[] = [\n { id: \"ollama\", label: \"Ollama\", baseUrl: \"http://127.0.0.1:11434/v1\", kind: \"ollama\" },\n];\n\n/**\n * Context window assumed when a server tells us nothing. Deliberately\n * conservative: over-guessing means the provider 400s mid-run at a point\n * auto-compaction already sailed past, while under-guessing only compacts early.\n */\nexport const FALLBACK_CONTEXT_WINDOW = 8192;\n\n/** Placeholder token for endpoints with no key — these servers ignore it. */\nexport const LOCAL_API_KEY_PLACEHOLDER = \"local\";\n\nconst DEFAULT_PROBE_TIMEOUT_MS = 1200;\n/** Capability lookups are per-model; cap the fan-out so 40 Ollama models don't stampede. */\nconst ENRICH_CONCURRENCY = 6;\nconst CACHE_TTL_MS = 30_000;\n\n/** Ids that are embedding/rerank models, not chat models — they can't drive an agent. */\nconst NON_CHAT_ID_PATTERN = /(?:^|[-_/])(?:embed|embedding|rerank|reranker|bge|nomic-embed)/i;\n\n// ── Model id scheme ────────────────────────────────────────\n\nconst LOCAL_ID_PREFIX = \"local/\";\n\n/**\n * `local/<endpointId>/<rawModelId>`. The raw id can itself contain slashes\n * (`hf.co/user/repo:q4`), so only the first two segments are structural.\n */\nexport function formatLocalModelId(endpointId: string, rawId: string): string {\n return `${LOCAL_ID_PREFIX}${endpointId}/${rawId}`;\n}\n\nexport function parseLocalModelId(id: string): { endpointId: string; rawId: string } | undefined {\n if (!id.startsWith(LOCAL_ID_PREFIX)) return undefined;\n const rest = id.slice(LOCAL_ID_PREFIX.length);\n const slash = rest.indexOf(\"/\");\n if (slash <= 0 || slash === rest.length - 1) return undefined;\n return { endpointId: rest.slice(0, slash), rawId: rest.slice(slash + 1) };\n}\n\nexport function isLocalModelId(id: string): boolean {\n return parseLocalModelId(id) !== undefined;\n}\n\n/** Auth-storage key holding the credential (and baseUrl) for one local endpoint. */\nexport function localAuthStorageKey(endpointId: string): string {\n return `local:${endpointId}`;\n}\n\n// ── HTTP helpers ───────────────────────────────────────────\n\n/** Base URL with any trailing `/v1` (and trailing slashes) removed — the server root. */\nexport function endpointRoot(baseUrl: string): string {\n return baseUrl.replace(/\\/+$/, \"\").replace(/\\/v1$/, \"\");\n}\n\nfunction authHeaders(endpoint: LocalEndpoint): Record<string, string> {\n return {\n Authorization: `Bearer ${endpoint.apiKey ?? LOCAL_API_KEY_PLACEHOLDER}`,\n Accept: \"application/json\",\n };\n}\n\ninterface FetchJsonOptions {\n timeoutMs: number;\n signal?: AbortSignal;\n method?: \"GET\" | \"POST\";\n body?: unknown;\n}\n\n/** GET/POST JSON with a hard timeout. Returns `undefined` on any failure. */\nasync function fetchJson<T>(\n url: string,\n endpoint: LocalEndpoint,\n options: FetchJsonOptions,\n): Promise<T | undefined> {\n try {\n const res = await fetchJsonOrThrow<T>(url, endpoint, options);\n return res;\n } catch {\n return undefined;\n }\n}\n\nasync function fetchJsonOrThrow<T>(\n url: string,\n endpoint: LocalEndpoint,\n { timeoutMs, signal, method = \"GET\", body }: FetchJsonOptions,\n): Promise<T> {\n const controller = new AbortController();\n const timer = setTimeout(() => controller.abort(), timeoutMs);\n const onAbort = () => controller.abort();\n signal?.addEventListener(\"abort\", onAbort, { once: true });\n try {\n const res = await fetch(url, {\n method,\n signal: controller.signal,\n headers: body\n ? { ...authHeaders(endpoint), \"Content-Type\": \"application/json\" }\n : authHeaders(endpoint),\n ...(body ? { body: JSON.stringify(body) } : {}),\n });\n if (!res.ok) throw new Error(`HTTP ${res.status}`);\n return (await res.json()) as T;\n } finally {\n clearTimeout(timer);\n signal?.removeEventListener(\"abort\", onAbort);\n }\n}\n\n/** Turn a fetch failure into wording a user can act on. */\nfunction unreachableReason(endpoint: LocalEndpoint, err: unknown): string {\n const message = err instanceof Error ? err.message : String(err);\n if (/abort/i.test(message)) return `No response from ${endpoint.baseUrl} (timed out)`;\n if (/HTTP 401|HTTP 403/.test(message)) {\n return `${endpoint.baseUrl} rejected the API key (HTTP ${message.includes(\"401\") ? 401 : 403})`;\n }\n if (/HTTP \\d+/.test(message)) return `${endpoint.baseUrl} returned ${message}`;\n return `Not running at ${endpoint.baseUrl}`;\n}\n\n// ── Server response shapes ─────────────────────────────────\n\ninterface OpenAIModelListEntry {\n id?: string;\n /** vLLM sometimes reports the real window here. */\n max_model_len?: number;\n}\ninterface OpenAIModelList {\n data?: OpenAIModelListEntry[];\n}\n\ninterface OllamaShowResponse {\n capabilities?: string[];\n model_info?: Record<string, unknown>;\n}\n\ninterface LmStudioModelEntry {\n id?: string;\n type?: string;\n state?: string;\n max_context_length?: number;\n loaded_context_length?: number;\n}\ninterface LmStudioModelList {\n data?: LmStudioModelEntry[];\n}\n\ninterface LlamaCppProps {\n default_generation_settings?: { n_ctx?: number };\n}\n\n// ── Probing ────────────────────────────────────────────────\n\nexport interface ProbeOptions {\n timeoutMs?: number;\n signal?: AbortSignal;\n}\n\n/**\n * Ask one endpoint what it serves. Never throws — an unreachable server yields\n * `{ reachable: false, reason }` so the UI can say \"not running\" without an\n * error toast.\n */\nexport async function probeEndpoint(\n endpoint: LocalEndpoint,\n { timeoutMs = DEFAULT_PROBE_TIMEOUT_MS, signal }: ProbeOptions = {},\n): Promise<LocalEndpointProbe> {\n const listUrl = `${endpoint.baseUrl.replace(/\\/+$/, \"\")}/models`;\n let list: OpenAIModelList;\n try {\n list = await fetchJsonOrThrow<OpenAIModelList>(listUrl, endpoint, { timeoutMs, signal });\n } catch (err) {\n return { endpoint, reachable: false, reason: unreachableReason(endpoint, err), models: [] };\n }\n\n const entries = (list.data ?? []).filter(\n (entry): entry is OpenAIModelListEntry & { id: string } =>\n typeof entry.id === \"string\" && entry.id.length > 0 && !NON_CHAT_ID_PATTERN.test(entry.id),\n );\n\n const models = await enrich(endpoint, entries, { timeoutMs, signal });\n log(\"INFO\", \"local-models\", `Probed ${endpoint.label}`, {\n baseUrl: endpoint.baseUrl,\n models: String(models.length),\n });\n return { endpoint, reachable: true, models };\n}\n\nasync function enrich(\n endpoint: LocalEndpoint,\n entries: (OpenAIModelListEntry & { id: string })[],\n options: { timeoutMs: number; signal?: AbortSignal },\n): Promise<LocalModel[]> {\n if (endpoint.kind === \"lmstudio\") return enrichLmStudio(endpoint, entries, options);\n if (endpoint.kind === \"ollama\") return enrichOllama(endpoint, entries, options);\n if (endpoint.kind === \"llamacpp\") return enrichLlamaCpp(endpoint, entries, options);\n return entries.map((entry) => genericModel(endpoint, entry));\n}\n\n/**\n * Servers that report no capabilities (vLLM, generic gateways) gate tool calling\n * per-model server-side. Assuming tools work is the useful default: a model that\n * genuinely can't will surface a normal provider error on the first tool call,\n * whereas assuming it can't makes every such model unusable.\n */\nfunction genericModel(\n endpoint: LocalEndpoint,\n entry: OpenAIModelListEntry & { id: string },\n): LocalModel {\n const declared = typeof entry.max_model_len === \"number\" ? entry.max_model_len : undefined;\n return {\n rawId: entry.id,\n endpointId: endpoint.id,\n contextWindow: declared ?? FALLBACK_CONTEXT_WINDOW,\n contextWindowKnown: declared !== undefined,\n supportsTools: true,\n supportsImages: false,\n supportsThinking: false,\n };\n}\n\nasync function enrichOllama(\n endpoint: LocalEndpoint,\n entries: (OpenAIModelListEntry & { id: string })[],\n options: { timeoutMs: number; signal?: AbortSignal },\n): Promise<LocalModel[]> {\n const showUrl = `${endpointRoot(endpoint.baseUrl)}/api/show`;\n const enriched = await mapLimited(entries, ENRICH_CONCURRENCY, async (entry) => {\n const show = await fetchJson<OllamaShowResponse>(showUrl, endpoint, {\n ...options,\n method: \"POST\",\n body: { model: entry.id },\n });\n if (!show) return genericModel(endpoint, entry);\n const caps = show.capabilities ?? [];\n // Capabilities are authoritative for \"is this a chat model at all\". Names\n // like `all-minilm` carry no hint, so filtering on the id alone leaves\n // embedding models in the picker as dead, tool-less rows.\n if (caps.includes(\"embedding\") && !caps.includes(\"completion\")) return undefined;\n const ctx = ollamaContextLength(show.model_info);\n return {\n rawId: entry.id,\n endpointId: endpoint.id,\n contextWindow: ctx ?? FALLBACK_CONTEXT_WINDOW,\n contextWindowKnown: ctx !== undefined,\n // Ollama reports capabilities honestly, so trust it here rather than\n // using the optimistic generic default.\n supportsTools: caps.includes(\"tools\"),\n supportsImages: caps.includes(\"vision\"),\n supportsThinking: caps.includes(\"thinking\"),\n };\n });\n return enriched.filter((model): model is LocalModel => model !== undefined);\n}\n\n/** `model_info` keys are architecture-prefixed, e.g. `qwen3.context_length`. */\nfunction ollamaContextLength(info: Record<string, unknown> | undefined): number | undefined {\n if (!info) return undefined;\n for (const [key, value] of Object.entries(info)) {\n if (key.endsWith(\".context_length\") && typeof value === \"number\" && value > 0) return value;\n }\n return undefined;\n}\n\nasync function enrichLmStudio(\n endpoint: LocalEndpoint,\n entries: (OpenAIModelListEntry & { id: string })[],\n options: { timeoutMs: number; signal?: AbortSignal },\n): Promise<LocalModel[]> {\n const detail = await fetchJson<LmStudioModelList>(\n `${endpointRoot(endpoint.baseUrl)}/api/v0/models`,\n endpoint,\n options,\n );\n if (!detail?.data) return entries.map((entry) => genericModel(endpoint, entry));\n const byId = new Map(detail.data.filter((m) => m.id).map((m) => [m.id!, m]));\n const models: LocalModel[] = [];\n for (const entry of entries) {\n const info = byId.get(entry.id);\n // `type` is authoritative here: embeddings models are listed by\n // /v1/models too and would otherwise show up as selectable chat models.\n if (info && info.type !== \"llm\" && info.type !== \"vlm\") continue;\n const ctx = info?.max_context_length;\n models.push({\n rawId: entry.id,\n endpointId: endpoint.id,\n contextWindow: typeof ctx === \"number\" && ctx > 0 ? ctx : FALLBACK_CONTEXT_WINDOW,\n contextWindowKnown: typeof ctx === \"number\" && ctx > 0,\n // LM Studio doesn't report tool support; it gates per-model at request time.\n supportsTools: true,\n supportsImages: info?.type === \"vlm\",\n supportsThinking: false,\n loaded: info?.state === \"loaded\",\n });\n }\n return models;\n}\n\nasync function enrichLlamaCpp(\n endpoint: LocalEndpoint,\n entries: (OpenAIModelListEntry & { id: string })[],\n options: { timeoutMs: number; signal?: AbortSignal },\n): Promise<LocalModel[]> {\n const props = await fetchJson<LlamaCppProps>(\n `${endpointRoot(endpoint.baseUrl)}/props`,\n endpoint,\n options,\n );\n const nCtx = props?.default_generation_settings?.n_ctx;\n const known = typeof nCtx === \"number\" && nCtx > 0;\n return entries.map((entry) => ({\n ...genericModel(endpoint, entry),\n contextWindow: known ? nCtx : FALLBACK_CONTEXT_WINDOW,\n contextWindowKnown: known,\n }));\n}\n\n/** Bounded-parallel map — keeps input order. */\nasync function mapLimited<T, R>(\n items: T[],\n limit: number,\n fn: (item: T) => Promise<R>,\n): Promise<R[]> {\n const results = new Array<R>(items.length);\n let next = 0;\n const workers = Array.from({ length: Math.min(limit, items.length) }, async () => {\n while (next < items.length) {\n const index = next++;\n results[index] = await fn(items[index]!);\n }\n });\n await Promise.all(workers);\n return results;\n}\n\n// ── ModelInfo mapping ──────────────────────────────────────\n\n/**\n * Highest reasoning effort an endpoint accepts. Ollama documents (and 0.32\n * verifiably accepts) `low|medium|high|max|none` on `reasoning_effort`; the\n * other OpenAI-compatible servers only define `low|medium|high`, so they stop\n * at `high` rather than risking a 400 mid-run on an effort they never declared.\n * No local server accepts `xhigh`.\n */\nfunction maxThinkingLevelFor(endpoint: LocalEndpoint): \"high\" | \"max\" {\n return endpoint.kind === \"ollama\" ? \"max\" : \"high\";\n}\n\n/** Convert a probed local model into the registry shape the whole app speaks. */\nexport function toModelInfo(model: LocalModel, endpoint: LocalEndpoint): ModelInfo {\n return {\n id: formatLocalModelId(model.endpointId, model.rawId),\n name: `${model.rawId} (${endpoint.label})`,\n provider: \"local\",\n contextWindow: model.contextWindow,\n // Leave real headroom for the prompt on small local windows.\n maxOutputTokens: Math.max(512, Math.min(4096, Math.floor(model.contextWindow / 4))),\n supportsThinking: model.supportsThinking,\n supportsImages: model.supportsImages,\n supportsVideo: false,\n costTier: \"low\",\n maxThinkingLevel: maxThinkingLevelFor(endpoint),\n authStorageKeys: [localAuthStorageKey(model.endpointId)],\n };\n}\n\n// ── Discovery ──────────────────────────────────────────────\n\nexport interface DiscoveryResult {\n probes: LocalEndpointProbe[];\n models: ModelInfo[];\n}\n\ninterface CacheEntry {\n key: string;\n at: number;\n result: DiscoveryResult;\n}\n\nlet cache: CacheEntry | undefined;\n\nfunction cacheKey(endpoints: readonly LocalEndpoint[]): string {\n return endpoints.map((e) => `${e.id}@${e.baseUrl}`).join(\"|\");\n}\n\nexport interface DiscoverOptions extends ProbeOptions {\n /** Skip the 30s cache (the UI's \"Scan\" button). */\n force?: boolean;\n}\n\n/**\n * Probe every endpoint in parallel and return both the per-endpoint status (for\n * the UI) and the `ModelInfo[]` ready for `registerRuntimeModels()`. Results are\n * cached for 30s per endpoint set so repeated `GET /models` calls don't re-probe\n * four servers; `force` bypasses it after an `ollama pull`.\n */\nexport async function discoverLocalModels(\n endpoints: readonly LocalEndpoint[] = DEFAULT_LOCAL_ENDPOINTS,\n options: DiscoverOptions = {},\n): Promise<DiscoveryResult> {\n const key = cacheKey(endpoints);\n if (!options.force && cache && cache.key === key && Date.now() - cache.at < CACHE_TTL_MS) {\n return cache.result;\n }\n const probes = await Promise.all(endpoints.map((endpoint) => probeEndpoint(endpoint, options)));\n const models = probes.flatMap((probe) =>\n probe.models.map((model) => toModelInfo(model, probe.endpoint)),\n );\n const result: DiscoveryResult = { probes, models };\n cache = { key, at: Date.now(), result };\n return result;\n}\n\n/** Drop the discovery cache (used by tests and after an endpoint is added/removed). */\nexport function clearLocalDiscoveryCache(): void {\n cache = undefined;\n}\n\n/** Look up the probed capabilities of a discovered model, by full local id. */\nexport function findProbedModel(\n probes: readonly LocalEndpointProbe[],\n modelId: string,\n): { model: LocalModel; endpoint: LocalEndpoint } | undefined {\n const parsed = parseLocalModelId(modelId);\n if (!parsed) return undefined;\n for (const probe of probes) {\n if (probe.endpoint.id !== parsed.endpointId) continue;\n const model = probe.models.find((m) => m.rawId === parsed.rawId);\n if (model) return { model, endpoint: probe.endpoint };\n }\n return undefined;\n}\n","import { kimiCodeBaseUrl, kimiCodingHeaders } from \"./oauth/kimi.js\";\nimport type { OAuthCredentials } from \"./oauth/types.js\";\n\nexport type SubscriptionUsageProvider = \"anthropic\" | \"openai\" | \"moonshot\";\n\nexport interface SubscriptionUsageWindow {\n kind: \"current\" | \"weekly\";\n label: string;\n usedPercent: number;\n /** Unix epoch milliseconds. */\n resetsAt?: number;\n}\n\nexport interface SubscriptionUsageSnapshot {\n provider: SubscriptionUsageProvider;\n displayName: string;\n windows: SubscriptionUsageWindow[];\n fetchedAt: number;\n}\n\nexport class SubscriptionUsageError extends Error {\n constructor(\n message: string,\n readonly status?: number,\n readonly retryAfterMs?: number,\n ) {\n super(message);\n this.name = \"SubscriptionUsageError\";\n }\n}\n\ntype FetchFn = (input: string | URL | Request, init?: RequestInit) => Promise<Response>;\n\ninterface FetchSubscriptionUsageOptions {\n fetchFn?: FetchFn;\n timeoutMs?: number;\n now?: () => number;\n}\n\ninterface AnthropicWindow {\n utilization?: unknown;\n resets_at?: unknown;\n}\n\ninterface AnthropicUsageResponse {\n five_hour?: AnthropicWindow | null;\n seven_day?: AnthropicWindow | null;\n}\n\ninterface CodexWindow {\n limit_window_seconds?: unknown;\n used_percent?: unknown;\n reset_at?: unknown;\n reset_after_seconds?: unknown;\n}\n\ninterface CodexUsageResponse {\n rate_limit?: {\n primary_window?: CodexWindow | null;\n secondary_window?: CodexWindow | null;\n } | null;\n}\n\ninterface KimiUsageDetail {\n limit?: unknown;\n used?: unknown;\n remaining?: unknown;\n resetTime?: unknown;\n}\n\ninterface KimiLimit {\n window?: { duration?: unknown; timeUnit?: unknown } | null;\n detail?: KimiUsageDetail | null;\n}\n\ninterface KimiUsageResponse {\n usage?: KimiUsageDetail | null;\n limits?: KimiLimit[] | null;\n}\n\nconst ANTHROPIC_USAGE_URL = \"https://api.anthropic.com/api/oauth/usage\";\nconst CODEX_USAGE_URL = \"https://chatgpt.com/backend-api/wham/usage\";\n\nfunction finiteNumber(value: unknown): number | undefined {\n return typeof value === \"number\" && Number.isFinite(value) ? value : undefined;\n}\n\nfunction clampPercent(value: unknown): number | undefined {\n const number = finiteNumber(value);\n return number === undefined ? undefined : Math.min(100, Math.max(0, number));\n}\n\nfunction isoTimestamp(value: unknown): number | undefined {\n if (typeof value !== \"string\" || !value.trim()) return undefined;\n const timestamp = Date.parse(value);\n return Number.isFinite(timestamp) ? timestamp : undefined;\n}\n\nfunction unixTimestamp(value: unknown): number | undefined {\n const seconds = finiteNumber(value);\n return seconds === undefined ? undefined : seconds * 1000;\n}\n\nfunction codexResetAt(window: CodexWindow, now: number): number | undefined {\n const absolute = unixTimestamp(window.reset_at);\n if (absolute !== undefined) return absolute;\n const afterSeconds = finiteNumber(window.reset_after_seconds);\n return afterSeconds === undefined ? undefined : now + afterSeconds * 1000;\n}\n\nfunction currentWindowLabel(seconds: unknown, fallbackHours: number): string {\n const duration = finiteNumber(seconds);\n const hours = Math.max(1, Math.round((duration ?? fallbackHours * 3600) / 3600));\n return `${hours}-hour`;\n}\n\nfunction codexWindowKind(\n window: CodexWindow,\n fallback: \"current\" | \"weekly\",\n): \"current\" | \"weekly\" {\n const duration = finiteNumber(window.limit_window_seconds);\n if (duration === undefined) return fallback;\n // The API can put its seven-day limit in either primary or secondary.\n // Classify by duration without mislabeling a future 24-hour window as weekly.\n return duration >= 6 * 24 * 60 * 60 ? \"weekly\" : \"current\";\n}\n\nfunction normalizedCodexWindow(\n window: CodexWindow | null | undefined,\n fallbackKind: \"current\" | \"weekly\",\n now: number,\n): SubscriptionUsageWindow | null {\n if (!window) return null;\n const usedPercent = clampPercent(window.used_percent);\n if (usedPercent === undefined) return null;\n const kind = codexWindowKind(window, fallbackKind);\n return {\n kind,\n label: kind === \"weekly\" ? \"Weekly\" : currentWindowLabel(window.limit_window_seconds, 5),\n usedPercent,\n resetsAt: codexResetAt(window, now),\n };\n}\n\nfunction retryAfterMs(response: Response, now: number): number | undefined {\n const value = response.headers.get(\"retry-after\")?.trim();\n if (!value) return undefined;\n if (/^\\d+(?:\\.\\d+)?$/.test(value)) return Math.ceil(Number(value) * 1_000);\n const retryAt = Date.parse(value);\n return Number.isFinite(retryAt) ? Math.max(0, retryAt - now) : undefined;\n}\n\nasync function readUsageResponse(response: Response, now: number): Promise<unknown> {\n const text = await response.text();\n if (!response.ok) {\n throw new SubscriptionUsageError(\n `Subscription usage request failed with HTTP ${response.status}`,\n response.status,\n retryAfterMs(response, now),\n );\n }\n try {\n return JSON.parse(text) as unknown;\n } catch {\n throw new SubscriptionUsageError(\"Subscription usage response was not valid JSON\");\n }\n}\n\nasync function fetchAnthropicUsage(\n credentials: Pick<OAuthCredentials, \"accessToken\">,\n fetchFn: FetchFn,\n signal: AbortSignal,\n now: () => number,\n): Promise<SubscriptionUsageSnapshot> {\n const response = await fetchFn(ANTHROPIC_USAGE_URL, {\n method: \"GET\",\n signal,\n headers: {\n Authorization: `Bearer ${credentials.accessToken}`,\n Accept: \"application/json\",\n \"anthropic-version\": \"2023-06-01\",\n \"anthropic-beta\": \"oauth-2025-04-20\",\n \"User-Agent\": \"ggcoder\",\n },\n });\n const data = (await readUsageResponse(response, now())) as AnthropicUsageResponse;\n const windows: SubscriptionUsageWindow[] = [];\n const currentPercent = clampPercent(data.five_hour?.utilization);\n if (currentPercent !== undefined) {\n windows.push({\n kind: \"current\",\n label: \"5-hour\",\n usedPercent: currentPercent,\n resetsAt: isoTimestamp(data.five_hour?.resets_at),\n });\n }\n const weeklyPercent = clampPercent(data.seven_day?.utilization);\n if (weeklyPercent !== undefined) {\n windows.push({\n kind: \"weekly\",\n label: \"Weekly\",\n usedPercent: weeklyPercent,\n resetsAt: isoTimestamp(data.seven_day?.resets_at),\n });\n }\n return {\n provider: \"anthropic\",\n displayName: \"Anthropic\",\n windows,\n fetchedAt: now(),\n };\n}\n\nasync function fetchCodexUsage(\n credentials: Pick<OAuthCredentials, \"accessToken\" | \"accountId\">,\n fetchFn: FetchFn,\n signal: AbortSignal,\n now: () => number,\n): Promise<SubscriptionUsageSnapshot> {\n const headers: Record<string, string> = {\n Authorization: `Bearer ${credentials.accessToken}`,\n Accept: \"application/json\",\n originator: \"ggcoder\",\n \"User-Agent\": \"ggcoder\",\n };\n if (credentials.accountId) headers[\"ChatGPT-Account-Id\"] = credentials.accountId;\n const response = await fetchFn(CODEX_USAGE_URL, { method: \"GET\", signal, headers });\n const data = (await readUsageResponse(response, now())) as CodexUsageResponse;\n const windows = [\n normalizedCodexWindow(data.rate_limit?.primary_window, \"current\", now()),\n normalizedCodexWindow(data.rate_limit?.secondary_window, \"weekly\", now()),\n ].filter((window): window is SubscriptionUsageWindow => window !== null);\n windows.sort((left, right) => {\n if (left.kind === right.kind) return 0;\n return left.kind === \"current\" ? -1 : 1;\n });\n return {\n provider: \"openai\",\n displayName: \"Codex\",\n windows,\n fetchedAt: now(),\n };\n}\n\n/**\n * Kimi For Coding (`/coding/v1/usages`) reports plan quota as string-valued\n * counters, so accept numbers too rather than trusting one wire shape.\n */\nfunction kimiNumber(value: unknown): number | undefined {\n if (typeof value === \"string\" && value.trim()) {\n const parsed = Number(value);\n return Number.isFinite(parsed) ? parsed : undefined;\n }\n return finiteNumber(value);\n}\n\nfunction kimiUsagePercent(detail: KimiUsageDetail | null | undefined): number | undefined {\n const used = kimiNumber(detail?.used);\n const limit = kimiNumber(detail?.limit);\n if (used === undefined || limit === undefined || limit <= 0) return undefined;\n return Math.min(100, Math.max(0, (used / limit) * 100));\n}\n\nfunction kimiWindowMinutes(window: KimiLimit[\"window\"]): number | undefined {\n const duration = kimiNumber(window?.duration);\n if (duration === undefined || duration <= 0) return undefined;\n switch (window?.timeUnit) {\n case \"TIME_UNIT_SECOND\":\n return duration / 60;\n case \"TIME_UNIT_MINUTE\":\n return duration;\n case \"TIME_UNIT_HOUR\":\n return duration * 60;\n case \"TIME_UNIT_DAY\":\n return duration * 24 * 60;\n default:\n // Unknown unit — skip the window rather than mislabel its duration.\n return undefined;\n }\n}\n\nasync function fetchKimiUsage(\n credentials: Pick<OAuthCredentials, \"accessToken\" | \"accountId\">,\n fetchFn: FetchFn,\n signal: AbortSignal,\n now: () => number,\n): Promise<SubscriptionUsageSnapshot> {\n const response = await fetchFn(`${kimiCodeBaseUrl()}/usages`, {\n method: \"GET\",\n signal,\n headers: {\n Authorization: \"Bearer \" + credentials.accessToken,\n Accept: \"application/json\",\n // The managed coding endpoint gates on the kimi-code-cli client identity,\n // same as model requests.\n ...kimiCodingHeaders(),\n },\n });\n const data = (await readUsageResponse(response, now())) as KimiUsageResponse;\n const windows: SubscriptionUsageWindow[] = [];\n // Top-level `usage` is the weekly request quota of the membership tier.\n const weeklyPercent = kimiUsagePercent(data.usage);\n if (weeklyPercent !== undefined) {\n windows.push({\n kind: \"weekly\",\n label: \"Weekly\",\n usedPercent: weeklyPercent,\n resetsAt: isoTimestamp(data.usage?.resetTime),\n });\n }\n for (const limit of data.limits ?? []) {\n const minutes = kimiWindowMinutes(limit?.window);\n const percent = kimiUsagePercent(limit?.detail);\n if (minutes === undefined || percent === undefined) continue;\n if (minutes >= 6 * 24 * 60) {\n // A weekly sub-limit duplicates the top-level quota — keep whichever\n // arrived first.\n if (!windows.some((window) => window.kind === \"weekly\")) {\n windows.push({\n kind: \"weekly\",\n label: \"Weekly\",\n usedPercent: percent,\n resetsAt: isoTimestamp(limit?.detail?.resetTime),\n });\n }\n continue;\n }\n windows.push({\n kind: \"current\",\n label: `${Math.max(1, Math.round(minutes / 60))}-hour`,\n usedPercent: percent,\n resetsAt: isoTimestamp(limit?.detail?.resetTime),\n });\n }\n windows.sort((left, right) => {\n if (left.kind === right.kind) return 0;\n return left.kind === \"current\" ? -1 : 1;\n });\n return {\n provider: \"moonshot\",\n displayName: \"Kimi\",\n windows,\n fetchedAt: now(),\n };\n}\n\n/**\n * Fetch subscription quota windows with an already-resolved OAuth credential.\n * Tokens stay server-side: callers expose only the normalized percentages and\n * reset timestamps to their UI.\n */\nexport async function fetchSubscriptionUsage(\n provider: SubscriptionUsageProvider,\n credentials: Pick<OAuthCredentials, \"accessToken\" | \"accountId\">,\n options: FetchSubscriptionUsageOptions = {},\n): Promise<SubscriptionUsageSnapshot> {\n const fetchFn = options.fetchFn ?? fetch;\n const now = options.now ?? Date.now;\n const signal = AbortSignal.timeout(options.timeoutMs ?? 8_000);\n try {\n return provider === \"anthropic\"\n ? await fetchAnthropicUsage(credentials, fetchFn, signal, now)\n : provider === \"openai\"\n ? await fetchCodexUsage(credentials, fetchFn, signal, now)\n : await fetchKimiUsage(credentials, fetchFn, signal, now);\n } catch (error) {\n if (error instanceof SubscriptionUsageError) throw error;\n const message = error instanceof Error ? error.message : String(error);\n throw new SubscriptionUsageError(message);\n }\n}\n","/**\n * Minimal Telegram Bot API client using raw fetch().\n * Supports long polling, markdown messages, inline keyboards, and message splitting.\n */\n\nconst TELEGRAM_API = \"https://api.telegram.org\";\nconst MAX_MESSAGE_LENGTH = 4096;\n\nexport interface TelegramConfig {\n botToken: string;\n /** Only accept messages from this Telegram user ID. */\n allowedUserId: number;\n}\n\nexport interface TelegramUpdate {\n update_id: number;\n message?: {\n message_id: number;\n from: { id: number; first_name: string };\n chat: { id: number; type: string; title?: string };\n text?: string;\n voice?: { file_id: string; duration: number; mime_type?: string; file_size?: number };\n };\n callback_query?: {\n id: string;\n from: { id: number };\n message: { chat: { id: number } };\n data: string;\n };\n my_chat_member?: {\n chat: { id: number; type: string; title?: string };\n from: { id: number };\n new_chat_member: { status: string };\n };\n}\n\nexport interface InlineButton {\n text: string;\n callback_data: string;\n}\n\n/** Incoming message with chat context. */\nexport interface TelegramMessage {\n text: string;\n chatId: number;\n chatType: \"private\" | \"group\" | \"supergroup\" | \"channel\";\n chatTitle?: string;\n}\n\n/** Incoming voice note with chat context. */\nexport interface TelegramVoiceMessage {\n fileId: string;\n duration: number;\n chatId: number;\n chatType: \"private\" | \"group\" | \"supergroup\" | \"channel\";\n chatTitle?: string;\n}\n\nexport class TelegramBot {\n private token: string;\n private allowedUserId: number;\n private offset = 0;\n private running = false;\n\n private onMessage: ((msg: TelegramMessage) => void) | null = null;\n private onVoiceMessage: ((msg: TelegramVoiceMessage) => void) | null = null;\n private onCallback: ((data: string, chatId: number) => void) | null = null;\n private onBotAdded: ((chatId: number, chatTitle?: string) => void) | null = null;\n private onBotRemoved: ((chatId: number) => void) | null = null;\n\n constructor(config: TelegramConfig) {\n this.token = config.botToken;\n this.allowedUserId = config.allowedUserId;\n }\n\n /** Register handler for incoming text messages. */\n onText(handler: (msg: TelegramMessage) => void): void {\n this.onMessage = handler;\n }\n\n /** Register handler for incoming voice notes. */\n onVoice(handler: (msg: TelegramVoiceMessage) => void): void {\n this.onVoiceMessage = handler;\n }\n\n /** Register handler for inline keyboard button presses. */\n onCallbackQuery(handler: (data: string, chatId: number) => void): void {\n this.onCallback = handler;\n }\n\n /** Register handler for when the bot is added to a group. */\n onAddedToGroup(handler: (chatId: number, chatTitle?: string) => void): void {\n this.onBotAdded = handler;\n }\n\n /** Register handler for when the bot is removed from a group. */\n onRemovedFromGroup(handler: (chatId: number) => void): void {\n this.onBotRemoved = handler;\n }\n\n /** Start long polling. Blocks until stop() is called. */\n async start(): Promise<void> {\n this.running = true;\n\n // Verify bot token works\n const me = await this.apiCall(\"getMe\");\n if (!me.ok) {\n throw new Error(`Invalid bot token: ${JSON.stringify(me)}`);\n }\n\n while (this.running) {\n try {\n const updates = await this.getUpdates();\n for (const update of updates) {\n await this.handleUpdate(update);\n }\n } catch (err) {\n if (!this.running) break;\n console.error(`[telegram] Poll error: ${err instanceof Error ? err.message : err}`);\n await sleep(3000);\n }\n }\n }\n\n /** Stop long polling. */\n stop(): void {\n this.running = false;\n }\n\n /** Send a text message to a specific chat. Converts markdown and splits long messages. */\n async send(chatId: number, text: string, buttons?: InlineButton[][]): Promise<void> {\n const converted = toTelegramMarkdown(text);\n const chunks = splitMessage(converted);\n\n for (let i = 0; i < chunks.length; i++) {\n const isLast = i === chunks.length - 1;\n const replyMarkup =\n isLast && buttons\n ? {\n inline_keyboard: buttons.map((row) =>\n row.map((b) => ({ text: b.text, callback_data: b.callback_data })),\n ),\n }\n : undefined;\n\n await this.apiCall(\"sendMessage\", {\n chat_id: chatId,\n text: chunks[i],\n parse_mode: \"Markdown\",\n ...(replyMarkup ? { reply_markup: replyMarkup } : {}),\n });\n }\n }\n\n /** Send a plain text message (no markdown parsing) to a specific chat. */\n async sendPlain(chatId: number, text: string): Promise<void> {\n const chunks = splitMessage(text);\n for (const chunk of chunks) {\n await this.apiCall(\"sendMessage\", {\n chat_id: chatId,\n text: chunk,\n });\n }\n }\n\n /** Send a typing indicator to a specific chat. */\n async sendTyping(chatId: number): Promise<void> {\n await this.apiCall(\"sendChatAction\", {\n chat_id: chatId,\n action: \"typing\",\n });\n }\n\n /** Get a direct download URL for a Telegram file. */\n async getFileUrl(fileId: string): Promise<string> {\n const result = await this.apiCall(\"getFile\", { file_id: fileId });\n if (!result.ok) throw new Error(`Failed to get file: ${JSON.stringify(result)}`);\n const filePath = (result.result as { file_path: string }).file_path;\n return `${TELEGRAM_API}/file/bot${this.token}/${filePath}`;\n }\n\n // ── Private ───────────────────────────────────────────\n\n private async getUpdates(): Promise<TelegramUpdate[]> {\n const result = await this.apiCall(\"getUpdates\", {\n offset: this.offset,\n timeout: 30,\n allowed_updates: [\"message\", \"callback_query\", \"my_chat_member\"],\n });\n\n if (!result.ok || !Array.isArray(result.result)) return [];\n\n const updates = result.result as TelegramUpdate[];\n if (updates.length > 0) {\n this.offset = updates[updates.length - 1]!.update_id + 1;\n }\n return updates;\n }\n\n private async handleUpdate(update: TelegramUpdate): Promise<void> {\n if (update.message) {\n const msg = update.message;\n\n // Auth check\n if (msg.from.id !== this.allowedUserId) {\n return;\n }\n\n if (msg.text && this.onMessage) {\n this.onMessage({\n text: msg.text,\n chatId: msg.chat.id,\n chatType: msg.chat.type as TelegramMessage[\"chatType\"],\n chatTitle: msg.chat.title,\n });\n } else if (msg.voice && this.onVoiceMessage) {\n this.onVoiceMessage({\n fileId: msg.voice.file_id,\n duration: msg.voice.duration,\n chatId: msg.chat.id,\n chatType: msg.chat.type as TelegramMessage[\"chatType\"],\n chatTitle: msg.chat.title,\n });\n }\n }\n\n // Bot membership changed in a group\n if (update.my_chat_member) {\n const member = update.my_chat_member;\n const status = member.new_chat_member.status;\n if ((status === \"member\" || status === \"administrator\") && this.onBotAdded) {\n this.onBotAdded(member.chat.id, member.chat.title);\n } else if ((status === \"left\" || status === \"kicked\") && this.onBotRemoved) {\n this.onBotRemoved(member.chat.id);\n }\n }\n\n if (update.callback_query) {\n const cb = update.callback_query;\n\n if (cb.from.id !== this.allowedUserId) return;\n\n await this.apiCall(\"answerCallbackQuery\", { callback_query_id: cb.id });\n\n if (cb.data && this.onCallback) {\n this.onCallback(cb.data, cb.message.chat.id);\n }\n }\n }\n\n private async apiCall(\n method: string,\n body?: Record<string, unknown>,\n ): Promise<{ ok: boolean; result?: unknown }> {\n const url = `${TELEGRAM_API}/bot${this.token}/${method}`;\n\n const response = await fetch(url, {\n method: \"POST\",\n headers: { \"Content-Type\": \"application/json\" },\n body: body ? JSON.stringify(body) : undefined,\n });\n\n if (!response.ok) {\n return { ok: false };\n }\n\n return response.json() as Promise<{ ok: boolean; result?: unknown }>;\n }\n}\n\n// ── Markdown Conversion ──────────────────────────────────\n\n/**\n * Convert GitHub-flavored markdown to Telegram-compatible Markdown.\n *\n * Telegram supports: *bold*, _italic_, `code`, ```pre```, [link](url)\n * Does NOT support: headings, horizontal rules, tables, HTML tags, images\n */\nfunction toTelegramMarkdown(text: string): string {\n const lines = text.split(\"\\n\");\n const result: string[] = [];\n let inCodeBlock = false;\n\n for (const line of lines) {\n if (line.trimStart().startsWith(\"```\")) {\n inCodeBlock = !inCodeBlock;\n result.push(line);\n continue;\n }\n\n if (inCodeBlock) {\n result.push(line);\n continue;\n }\n\n let transformed = line;\n\n // Headings → bold text\n const headingMatch = transformed.match(/^(#{1,6})\\s+(.+)$/);\n if (headingMatch) {\n transformed = `*${headingMatch[2]}*`;\n result.push(transformed);\n continue;\n }\n\n // Horizontal rules → empty line\n if (/^(-{3,}|_{3,}|\\*{3,})$/.test(transformed.trim())) {\n result.push(\"\");\n continue;\n }\n\n // **bold** → *bold*\n transformed = transformed.replace(/\\*\\*(.+?)\\*\\*/g, \"*$1*\");\n\n result.push(transformed);\n }\n\n return result.join(\"\\n\");\n}\n\n// ── Helpers ───────────────────────────────────────────────\n\nfunction splitMessage(text: string): string[] {\n if (text.length <= MAX_MESSAGE_LENGTH) return [text];\n\n const chunks: string[] = [];\n let remaining = text;\n\n while (remaining.length > 0) {\n if (remaining.length <= MAX_MESSAGE_LENGTH) {\n chunks.push(remaining);\n break;\n }\n\n let splitAt = remaining.lastIndexOf(\"\\n\", MAX_MESSAGE_LENGTH);\n if (splitAt === -1 || splitAt < MAX_MESSAGE_LENGTH * 0.5) {\n splitAt = remaining.lastIndexOf(\" \", MAX_MESSAGE_LENGTH);\n }\n if (splitAt === -1 || splitAt < MAX_MESSAGE_LENGTH * 0.5) {\n splitAt = MAX_MESSAGE_LENGTH;\n }\n\n chunks.push(remaining.slice(0, splitAt));\n remaining = remaining.slice(splitAt).trimStart();\n }\n\n return chunks;\n}\n\nfunction sleep(ms: number): Promise<void> {\n return new Promise((r) => setTimeout(r, ms));\n}\n","/**\n * Voice note transcription using local Whisper model.\n * Uses @huggingface/transformers (pure JS/WASM) — no native deps, no API keys.\n * Model (~75MB) is downloaded on first use and cached locally.\n */\n\nimport type { AutomaticSpeechRecognitionPipeline } from \"@huggingface/transformers\";\n\nconst TARGET_SAMPLE_RATE = 16000;\nconst MODEL_ID = \"Xenova/whisper-tiny.en\";\n\nlet transcriber: AutomaticSpeechRecognitionPipeline | null = null;\nlet loadPromise: Promise<AutomaticSpeechRecognitionPipeline> | null = null;\n\n/** Optional callback for model download progress. */\nexport type ProgressCallback = (info: { status: string; progress?: number; file?: string }) => void;\n\nlet onProgress: ProgressCallback | null = null;\n\n/** Set a callback to receive model download progress updates. */\nexport function setProgressCallback(cb: ProgressCallback | null): void {\n onProgress = cb;\n}\n\n/**\n * Resample audio from one sample rate to another using linear interpolation.\n */\nexport function resample(audio: Float32Array, fromRate: number, toRate: number): Float32Array {\n if (fromRate === toRate) return audio;\n const ratio = fromRate / toRate;\n const newLength = Math.round(audio.length / ratio);\n const result = new Float32Array(newLength);\n for (let i = 0; i < newLength; i++) {\n const srcIndex = i * ratio;\n const low = Math.floor(srcIndex);\n const high = Math.min(low + 1, audio.length - 1);\n const frac = srcIndex - low;\n result[i] = audio[low]! * (1 - frac) + audio[high]! * frac;\n }\n return result;\n}\n\n/**\n * Downmix multi-channel audio to mono by averaging all channels.\n */\nexport function downmixToMono(channelData: Float32Array[]): Float32Array {\n if (channelData.length === 0) return new Float32Array();\n if (channelData.length === 1) return channelData[0]!;\n\n const samples = channelData[0]!.length;\n const out = new Float32Array(samples);\n const scale = 1 / channelData.length;\n for (let i = 0; i < samples; i++) {\n let mixed = 0;\n for (const channel of channelData) mixed += channel[i] ?? 0;\n out[i] = mixed * scale;\n }\n return out;\n}\n\n/**\n * Decode OGG Opus audio buffer to 16kHz mono PCM Float32Array.\n */\nexport async function decodeOggOpus(buffer: Uint8Array): Promise<Float32Array> {\n const { OggOpusDecoder } = await import(\"ogg-opus-decoder\");\n const decoder = new OggOpusDecoder();\n await decoder.ready;\n try {\n const decoded = await decoder.decodeFile(buffer);\n\n if (!decoded.channelData?.length || !decoded.channelData[0]?.length) {\n throw new Error(\"Decoded audio is empty\");\n }\n\n const mono = downmixToMono(decoded.channelData);\n return resample(mono, decoded.sampleRate, TARGET_SAMPLE_RATE);\n } finally {\n decoder.free();\n }\n}\n\n/**\n * Get or initialize the Whisper transcription pipeline.\n * Model is downloaded on first use and cached by transformers.js.\n */\nasync function getTranscriber(): Promise<AutomaticSpeechRecognitionPipeline> {\n if (transcriber) return transcriber;\n\n if (!loadPromise) {\n loadPromise = (async () => {\n const { pipeline } = await import(\"@huggingface/transformers\");\n const instance = await pipeline(\"automatic-speech-recognition\", MODEL_ID, {\n dtype: \"fp32\",\n progress_callback: onProgress ?? undefined,\n });\n transcriber = instance;\n return instance;\n })();\n }\n\n return loadPromise;\n}\n\n/** Whether the model has been loaded already. */\nexport function isModelLoaded(): boolean {\n return transcriber !== null;\n}\n\n/**\n * Transcribe a voice message from its Telegram file URL.\n * Downloads the OGG Opus file, decodes to PCM, and runs Whisper locally.\n */\nexport async function transcribeVoice(fileUrl: string): Promise<string> {\n // Download the audio file\n const response = await fetch(fileUrl);\n if (!response.ok) throw new Error(`Failed to download voice file: ${response.status}`);\n const buffer = new Uint8Array(await response.arrayBuffer());\n\n // Decode OGG Opus → 16kHz mono PCM\n const pcm = await decodeOggOpus(buffer);\n\n // Transcribe with Whisper\n const asr = await getTranscriber();\n const result = await asr(pcm);\n\n const text = Array.isArray(result) ? result[0]?.text : (result as { text: string }).text;\n return (text ?? \"\").trim();\n}\n","import { spawn } from \"node:child_process\";\nimport fs from \"node:fs\";\nimport path from \"node:path\";\n\n/**\n * Provider-agnostic background self-updater. Each app composes its own instance\n * via `createAutoUpdater` with its npm package name and state-file path, so the\n * update logic (registry poll, version compare, detached install, throttling)\n * lives in exactly one place while branding stays in the apps.\n */\n\ninterface UpdateState {\n lastCheckedAt: number;\n latestVersion?: string;\n updatePending?: boolean;\n lastUpdateAttempt?: number;\n}\n\nenum PackageManager {\n NPM = \"npm\",\n PNPM = \"pnpm\",\n YARN = \"yarn\",\n UNKNOWN = \"unknown\",\n}\n\ninterface InstallInfo {\n packageManager: PackageManager;\n updateCommand: string | null;\n}\n\nexport interface AutoUpdateConfig {\n /** npm package to self-update, e.g. \"@kenkaiiii/ggcoder\". */\n packageName: string;\n /**\n * Absolute path to this app's update-state.json, or a thunk resolving it.\n * A thunk keeps path resolution lazy so callers can derive it from\n * `os.homedir()` without freezing the value at module-load time (which\n * breaks tests that mock the home directory after import).\n */\n stateFilePath: string | (() => string);\n /** Builds the in-session \"update available\" notification. */\n periodicMessage?: (args: {\n currentVersion: string;\n latestVersion: string;\n updateCommand: string;\n }) => string;\n}\n\nexport interface AutoUpdater {\n checkAndAutoUpdate(currentVersion: string): string | null;\n getPendingUpdate(currentVersion: string): { latestVersion: string } | null;\n startPeriodicUpdateCheck(currentVersion: string, onUpdate: (message: string) => void): void;\n stopPeriodicUpdateCheck(): void;\n}\n\nconst CHECK_INTERVAL_MS = 60 * 60 * 1000; // 1 hour\nconst FETCH_TIMEOUT_MS = 10_000; // 10s — npm can be slow\n\nfunction compareVersions(a: string, b: string): number {\n const pa = a.split(\".\").map(Number);\n const pb = b.split(\".\").map(Number);\n for (let i = 0; i < 3; i++) {\n const diff = (pa[i] ?? 0) - (pb[i] ?? 0);\n if (diff !== 0) return diff;\n }\n return 0;\n}\n\nfunction performUpdateInBackground(command: string): void {\n try {\n const parts = command.split(\" \");\n const child = spawn(parts[0]!, parts.slice(1), {\n detached: true,\n stdio: \"ignore\",\n env: { ...process.env, npm_config_loglevel: \"silent\" },\n });\n child.unref();\n } catch {\n // Non-fatal — will retry next startup\n }\n}\n\nexport function createAutoUpdater(config: AutoUpdateConfig): AutoUpdater {\n const REGISTRY_URL = `https://registry.npmjs.org/${config.packageName}/latest`;\n const periodicMessage =\n config.periodicMessage ??\n (({ currentVersion, latestVersion, updateCommand }) =>\n `Ken just pushed a fresh update — ${currentVersion} → ${latestVersion}! I'll grab it on next launch (or run ${updateCommand} if you can't wait).`);\n\n let periodicTimer: ReturnType<typeof setInterval> | null = null;\n\n function stateFilePath(): string {\n return typeof config.stateFilePath === \"function\"\n ? config.stateFilePath()\n : config.stateFilePath;\n }\n\n function readState(): UpdateState | null {\n try {\n const raw = fs.readFileSync(stateFilePath(), \"utf-8\");\n return JSON.parse(raw) as UpdateState;\n } catch {\n return null;\n }\n }\n\n function writeState(state: UpdateState): void {\n try {\n const filePath = stateFilePath();\n fs.mkdirSync(path.dirname(filePath), { recursive: true, mode: 0o700 });\n fs.writeFileSync(filePath, JSON.stringify(state));\n } catch {\n // Non-fatal\n }\n }\n\n function detectInstallInfo(): InstallInfo {\n const scriptPath = (process.argv[1] ?? \"\").replace(/\\\\/g, \"/\");\n\n // npx — skip (ephemeral)\n if (scriptPath.includes(\"/_npx/\")) {\n return { packageManager: PackageManager.UNKNOWN, updateCommand: null };\n }\n\n // pnpm global\n if (scriptPath.includes(\"/.pnpm\") || scriptPath.includes(\"/pnpm/global\")) {\n return {\n packageManager: PackageManager.PNPM,\n updateCommand: `pnpm add -g ${config.packageName}@latest`,\n };\n }\n\n // yarn global\n if (scriptPath.includes(\"/.yarn/\") || scriptPath.includes(\"/yarn/global\")) {\n return {\n packageManager: PackageManager.YARN,\n updateCommand: `yarn global add ${config.packageName}@latest`,\n };\n }\n\n // npm global (default)\n return {\n packageManager: PackageManager.NPM,\n updateCommand: `npm install -g ${config.packageName}@latest`,\n };\n }\n\n async function fetchLatestVersion(): Promise<string | null> {\n try {\n const controller = new AbortController();\n const timeout = setTimeout(() => controller.abort(), FETCH_TIMEOUT_MS);\n const response = await fetch(REGISTRY_URL, { signal: controller.signal });\n clearTimeout(timeout);\n const data = (await response.json()) as { version?: string };\n const version = data.version?.trim();\n return version && /^\\d+\\.\\d+\\.\\d+/.test(version) ? version : null;\n } catch {\n return null;\n }\n }\n\n function scheduleBackgroundCheck(currentVersion: string): void {\n fetchLatestVersion()\n .then((latestVersion) => {\n const newState: UpdateState = {\n lastCheckedAt: Date.now(),\n latestVersion: latestVersion ?? undefined,\n updatePending: false,\n };\n if (latestVersion && compareVersions(latestVersion, currentVersion) > 0) {\n newState.updatePending = true;\n }\n writeState(newState);\n })\n .catch(() => {\n // Non-fatal — will retry next time\n });\n }\n\n function checkAndAutoUpdate(currentVersion: string): string | null {\n try {\n const state = readState();\n let message: string | null = null;\n\n // Phase 1: Apply pending update from previous check\n if (state?.updatePending && state.latestVersion) {\n if (compareVersions(state.latestVersion, currentVersion) > 0) {\n const info = detectInstallInfo();\n if (info.updateCommand) {\n performUpdateInBackground(info.updateCommand);\n message = `Ken just shipped ${state.latestVersion}! Installing in the background — takes effect next launch.`;\n writeState({\n ...state,\n lastCheckedAt: Date.now(),\n updatePending: false,\n lastUpdateAttempt: Date.now(),\n });\n }\n } else {\n // Already on latest (user may have updated manually)\n writeState({ ...state, updatePending: false });\n }\n }\n\n // Phase 2: Schedule background check for next startup\n const shouldCheck = !state || Date.now() - state.lastCheckedAt > CHECK_INTERVAL_MS;\n if (shouldCheck) scheduleBackgroundCheck(currentVersion);\n\n return message;\n } catch {\n return null;\n }\n }\n\n function getPendingUpdate(currentVersion: string): { latestVersion: string } | null {\n try {\n const state = readState();\n if (!state?.latestVersion) return null;\n if (compareVersions(state.latestVersion, currentVersion) <= 0) return null;\n return { latestVersion: state.latestVersion };\n } catch {\n return null;\n }\n }\n\n function startPeriodicUpdateCheck(\n currentVersion: string,\n onUpdate: (message: string) => void,\n ): void {\n if (periodicTimer) return; // Already running\n\n periodicTimer = setInterval(() => {\n fetchLatestVersion()\n .then((latestVersion) => {\n if (!latestVersion) return;\n if (compareVersions(latestVersion, currentVersion) <= 0) return;\n\n const info = detectInstallInfo();\n if (!info.updateCommand) return;\n\n writeState({ lastCheckedAt: Date.now(), latestVersion, updatePending: true });\n onUpdate(\n periodicMessage({ currentVersion, latestVersion, updateCommand: info.updateCommand }),\n );\n\n // Stop checking once we've notified\n stopPeriodicUpdateCheck();\n })\n .catch(() => {\n // Non-fatal\n });\n }, CHECK_INTERVAL_MS);\n\n // Don't keep the process alive just for update checks\n periodicTimer.unref();\n }\n\n function stopPeriodicUpdateCheck(): void {\n if (periodicTimer) {\n clearInterval(periodicTimer);\n periodicTimer = null;\n }\n }\n\n return {\n checkAndAutoUpdate,\n getPendingUpdate,\n startPeriodicUpdateCheck,\n stopPeriodicUpdateCheck,\n };\n}\n"],"mappings":"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","names":["maxIndex","levels","retryAfterMs"]}
|
|
1
|
+
{"version":3,"sources":["../src/thinking-level.ts","../src/local-models.ts","../src/provider-usage.ts","../src/telegram.ts","../src/voice-transcriber.ts","../src/auto-update.ts"],"sourcesContent":["import type { Provider, ThinkingLevel } from \"@kenkaiiii/gg-ai\";\nimport { getMaxThinkingLevel, getModel } from \"./model-registry.js\";\n\nconst OPENAI_GPT_THINKING_LEVELS: readonly ThinkingLevel[] = [\"medium\", \"high\", \"xhigh\"];\n// GPT-5.6 and GPT-6 share the six-rung Codex ladder (low → ultra); older GPT\n// models only expose medium/high/xhigh.\nconst OPENAI_GPT_56_THINKING_LEVELS: readonly ThinkingLevel[] = [\n \"low\",\n \"medium\",\n \"high\",\n \"xhigh\",\n \"max\",\n \"ultra\",\n];\n// Sakana Fugu accepts exactly two reasoning efforts — \"high\" and \"xhigh\" — and\n// rejects anything else. Expose both so users can pick the lighter tier instead\n// of being forced into all-or-nothing xhigh.\nconst SAKANA_THINKING_LEVELS: readonly ThinkingLevel[] = [\"high\", \"xhigh\"];\n// Grok reasoning models take reasoning_effort low/medium/high (server default\n// high; reasoning can't be fully disabled — \"off\" just omits the param). Grok\n// 4.6 adds an `xhigh` top rung (docs: low/medium/high default/xhigh); 4.5\n// keeps its `high` ceiling because each model slices this ladder by its\n// registry maxThinkingLevel.\nconst XAI_THINKING_LEVELS: readonly ThinkingLevel[] = [\"low\", \"medium\", \"high\", \"xhigh\"];\n// Opus 5 / 4.7 expose the full ladder including xhigh (\"extended capability for\n// long-horizon work\"). Other adaptive Anthropic models omit xhigh and would 400.\nconst ANTHROPIC_XHIGH_THINKING_LEVELS: readonly ThinkingLevel[] = [\n \"low\",\n \"medium\",\n \"high\",\n \"xhigh\",\n \"max\",\n];\nconst ANTHROPIC_ADAPTIVE_THINKING_LEVELS: readonly ThinkingLevel[] = [\n \"low\",\n \"medium\",\n \"high\",\n \"max\",\n];\n// Kimi K3's effort ladder is declared server-side via /models think_efforts:\n// [\"low\",\"high\",\"max\"] on both the public API (default max) and the Kimi For\n// Coding OAuth endpoint (default high) — verified live 2026-07-21. Unlisted\n// efforts are rejected with a 400, so expose exactly the declared rungs.\nconst MOONSHOT_K3_THINKING_LEVELS: readonly ThinkingLevel[] = [\"low\", \"high\", \"max\"];\n// GLM's ladder is declared by the endpoint itself: an unknown effort 400s with\n// `reasoning_effort must be one of: none, minimal, low, medium, high, xhigh,\n// max` (verified live against glm-5.3, 2026-08-14). `none` is the thinking\n// toggle's job and `minimal` has no ThinkingLevel counterpart, so expose the\n// five rungs we can actually name. Effort is real, not cosmetic — measured\n// end-to-end on one hard reasoning prompt: low 0.8K reasoning chars / 15s,\n// high 3.2K / 28s, max 24.9K / 129s.\nconst GLM_THINKING_LEVELS: readonly ThinkingLevel[] = [\"low\", \"medium\", \"high\", \"xhigh\", \"max\"];\n/**\n * Effort ladder for locally hosted models. `xhigh`/`ultra` are deliberately\n * absent: no local server defines them (Ollama 0.32 answers\n * `invalid reasoning value: 'xhigh' (must be \"high\", \"medium\", \"low\", \"max\", or\n * \"none\")`). Each model's own ceiling comes from its endpoint — see\n * `toModelInfo` in local-models.ts.\n */\nconst LOCAL_THINKING_LEVELS: readonly ThinkingLevel[] = [\"low\", \"medium\", \"high\", \"max\"];\n\nfunction isOpenAIGptModel(provider: Provider, model: string): boolean {\n return provider === \"openai\" && model.startsWith(\"gpt-\");\n}\n\nfunction isSakanaModel(provider: Provider): boolean {\n return provider === \"sakana\";\n}\n\nfunction isXaiModel(provider: Provider): boolean {\n return provider === \"xai\";\n}\n\nfunction isMoonshotK3Model(provider: Provider, model: string): boolean {\n return provider === \"moonshot\" && model === \"kimi-k3\";\n}\n\nfunction isGlmModel(provider: Provider): boolean {\n return provider === \"glm\";\n}\n\nfunction isAnthropicXhighModel(provider: Provider, model: string): boolean {\n return provider === \"anthropic\" && /opus-5|opus-4-8|opus-4-7/.test(model);\n}\n\nfunction isAnthropicAdaptiveModel(provider: Provider, model: string): boolean {\n return (\n provider === \"anthropic\" &&\n /opus-5|opus-4-8|opus-4-7|opus-4-6|sonnet-5|fable-5|mythos-5/.test(model)\n );\n}\n\nexport function getSupportedThinkingLevels(\n provider: Provider,\n model: string,\n): readonly ThinkingLevel[] {\n // Local models: reasoning support is per-model and probed, not assumed. A\n // non-reasoning local model must never be sent a reasoning_effort — Ollama\n // hard-400s (`\"llama3.2\" does not support thinking`) — so it offers no levels\n // at all and the thinking toggle stays hidden.\n if (provider === \"local\") {\n const info = getModel(model);\n if (!info?.supportsThinking) return [];\n // The ceiling is the endpoint's, set at discovery: Ollama takes\n // low/medium/high/max, while the other OpenAI-compatible servers only\n // define low/medium/high (verified — Ollama rejects xhigh outright).\n const maxIndex = LOCAL_THINKING_LEVELS.indexOf(info.maxThinkingLevel);\n return maxIndex === -1\n ? LOCAL_THINKING_LEVELS.slice(0, 3)\n : LOCAL_THINKING_LEVELS.slice(0, maxIndex + 1);\n }\n const maxLevel = getMaxThinkingLevel(model);\n if (isAnthropicAdaptiveModel(provider, model)) {\n const levels = isAnthropicXhighModel(provider, model)\n ? ANTHROPIC_XHIGH_THINKING_LEVELS\n : ANTHROPIC_ADAPTIVE_THINKING_LEVELS;\n const maxIndex = levels.indexOf(maxLevel);\n if (maxIndex === -1) return [\"low\", \"medium\", \"high\"];\n return levels.slice(0, maxIndex + 1);\n }\n\n if (isSakanaModel(provider)) {\n const maxIndex = SAKANA_THINKING_LEVELS.indexOf(maxLevel);\n if (maxIndex === -1) return SAKANA_THINKING_LEVELS;\n return SAKANA_THINKING_LEVELS.slice(0, maxIndex + 1);\n }\n\n if (isXaiModel(provider)) {\n const maxIndex = XAI_THINKING_LEVELS.indexOf(maxLevel);\n if (maxIndex === -1) return XAI_THINKING_LEVELS;\n return XAI_THINKING_LEVELS.slice(0, maxIndex + 1);\n }\n\n if (isMoonshotK3Model(provider, model)) return MOONSHOT_K3_THINKING_LEVELS;\n\n if (isGlmModel(provider)) {\n const maxIndex = GLM_THINKING_LEVELS.indexOf(maxLevel);\n if (maxIndex === -1) return GLM_THINKING_LEVELS;\n return GLM_THINKING_LEVELS.slice(0, maxIndex + 1);\n }\n\n if (!isOpenAIGptModel(provider, model)) return [maxLevel];\n\n const levels =\n model.startsWith(\"gpt-5.6-\") || model.startsWith(\"gpt-6-\")\n ? OPENAI_GPT_56_THINKING_LEVELS\n : OPENAI_GPT_THINKING_LEVELS;\n const maxIndex = levels.indexOf(maxLevel);\n if (maxIndex === -1) return [\"medium\"];\n return levels.slice(0, maxIndex + 1);\n}\n\nexport function isThinkingLevelSupported(\n provider: Provider,\n model: string,\n level: ThinkingLevel,\n): boolean {\n return getSupportedThinkingLevels(provider, model).includes(level);\n}\n\nexport function getNextThinkingLevel(\n provider: Provider,\n model: string,\n current: ThinkingLevel | undefined,\n): ThinkingLevel | undefined {\n const supportedLevels = getSupportedThinkingLevels(provider, model);\n const shouldCycleLevels =\n isOpenAIGptModel(provider, model) ||\n isAnthropicAdaptiveModel(provider, model) ||\n isSakanaModel(provider) ||\n isXaiModel(provider) ||\n isMoonshotK3Model(provider, model) ||\n isGlmModel(provider) ||\n // Local servers take a real effort level, not just on/off: Ollama accepts\n // low/medium/high on `reasoning_effort` (verified against 0.32) and the\n // other OpenAI-compatible servers use the same three. A model that can't\n // reason at all already has no supported levels, so it never gets here.\n provider === \"local\";\n if (!shouldCycleLevels) {\n return current ? undefined : supportedLevels[0];\n }\n\n if (!current) return supportedLevels[0];\n const index = supportedLevels.indexOf(current);\n if (index === -1) return supportedLevels[0];\n return supportedLevels[index + 1];\n}\n","/**\n * Local model discovery — Ollama, LM Studio, llama.cpp (`llama-server`), vLLM,\n * and any other OpenAI-compatible server the user points us at.\n *\n * Everything rides the OpenAI-compatible `/v1` transport (see the `local`\n * provider in gg-ai's stream.ts); the only per-server difference is where the\n * *capabilities* come from, because `GET /v1/models` reports nothing useful:\n *\n * - Ollama → `POST /api/show` → `capabilities[]` + `model_info[\"<arch>.context_length\"]`\n * - LM Studio → `GET /api/v0/models` → `type`, `state`, `max_context_length`\n * - llama.cpp → `GET /props` → `default_generation_settings.n_ctx`\n * - vLLM/other → nothing; `max_model_len` sometimes rides the model object.\n *\n * Probing never throws: an unreachable server is a normal state (the user just\n * doesn't have it running), not an error to surface.\n */\nimport type { ModelInfo } from \"./model-registry.js\";\nimport { log } from \"./logger.js\";\n\n// ── Types ──────────────────────────────────────────────────\n\n/** Which capability API a local endpoint speaks, beyond plain `/v1/models`. */\nexport type LocalEndpointKind = \"ollama\" | \"lmstudio\" | \"llamacpp\" | \"vllm\" | \"custom\";\n\nexport interface LocalEndpoint {\n /** Stable slug, used in model ids (`local/<id>/<rawId>`) and auth keys (`local:<id>`). */\n id: string;\n label: string;\n /** OpenAI-compatible base URL, including the `/v1` suffix. */\n baseUrl: string;\n kind: LocalEndpointKind;\n /** Optional bearer token (LM Studio 0.4+ can require one). */\n apiKey?: string;\n /** True for endpoints the user added by hand (removable). */\n custom?: boolean;\n}\n\n/** One model as reported (and enriched) by a local server. */\nexport interface LocalModel {\n /** Model id on the wire, exactly as the server names it (e.g. `qwen3-coder:30b`). */\n rawId: string;\n endpointId: string;\n contextWindow: number;\n /** True when the server told us the real window; false means we guessed. */\n contextWindowKnown: boolean;\n supportsTools: boolean;\n supportsImages: boolean;\n supportsThinking: boolean;\n /** LM Studio only: whether the model is currently resident in memory. */\n loaded?: boolean;\n}\n\nexport interface LocalEndpointProbe {\n endpoint: LocalEndpoint;\n reachable: boolean;\n /** Human-readable reason when `reachable` is false (never a raw stack). */\n reason?: string;\n models: LocalModel[];\n}\n\n// ── Defaults ───────────────────────────────────────────────\n\n/**\n * The server we look for without being asked. LM Studio, llama.cpp and vLLM\n * are no longer auto-probed — one honest row beats four mostly-dead ones;\n * anything else is one \"Add endpoint\" away (custom kind keeps working).\n */\nexport const DEFAULT_LOCAL_ENDPOINTS: readonly LocalEndpoint[] = [\n { id: \"ollama\", label: \"Ollama\", baseUrl: \"http://127.0.0.1:11434/v1\", kind: \"ollama\" },\n];\n\n/**\n * Context window assumed when a server tells us nothing. Deliberately\n * conservative: over-guessing means the provider 400s mid-run at a point\n * auto-compaction already sailed past, while under-guessing only compacts early.\n */\nexport const FALLBACK_CONTEXT_WINDOW = 8192;\n\n/** Placeholder token for endpoints with no key — these servers ignore it. */\nexport const LOCAL_API_KEY_PLACEHOLDER = \"local\";\n\nconst DEFAULT_PROBE_TIMEOUT_MS = 1200;\n/** Capability lookups are per-model; cap the fan-out so 40 Ollama models don't stampede. */\nconst ENRICH_CONCURRENCY = 6;\nconst CACHE_TTL_MS = 30_000;\n\n/** Ids that are embedding/rerank models, not chat models — they can't drive an agent. */\nconst NON_CHAT_ID_PATTERN = /(?:^|[-_/])(?:embed|embedding|rerank|reranker|bge|nomic-embed)/i;\n\n// ── Model id scheme ────────────────────────────────────────\n\nconst LOCAL_ID_PREFIX = \"local/\";\n\n/**\n * `local/<endpointId>/<rawModelId>`. The raw id can itself contain slashes\n * (`hf.co/user/repo:q4`), so only the first two segments are structural.\n */\nexport function formatLocalModelId(endpointId: string, rawId: string): string {\n return `${LOCAL_ID_PREFIX}${endpointId}/${rawId}`;\n}\n\nexport function parseLocalModelId(id: string): { endpointId: string; rawId: string } | undefined {\n if (!id.startsWith(LOCAL_ID_PREFIX)) return undefined;\n const rest = id.slice(LOCAL_ID_PREFIX.length);\n const slash = rest.indexOf(\"/\");\n if (slash <= 0 || slash === rest.length - 1) return undefined;\n return { endpointId: rest.slice(0, slash), rawId: rest.slice(slash + 1) };\n}\n\nexport function isLocalModelId(id: string): boolean {\n return parseLocalModelId(id) !== undefined;\n}\n\n/** Auth-storage key holding the credential (and baseUrl) for one local endpoint. */\nexport function localAuthStorageKey(endpointId: string): string {\n return `local:${endpointId}`;\n}\n\n// ── HTTP helpers ───────────────────────────────────────────\n\n/** Base URL with any trailing `/v1` (and trailing slashes) removed — the server root. */\nexport function endpointRoot(baseUrl: string): string {\n return baseUrl.replace(/\\/+$/, \"\").replace(/\\/v1$/, \"\");\n}\n\nfunction authHeaders(endpoint: LocalEndpoint): Record<string, string> {\n return {\n Authorization: `Bearer ${endpoint.apiKey ?? LOCAL_API_KEY_PLACEHOLDER}`,\n Accept: \"application/json\",\n };\n}\n\ninterface FetchJsonOptions {\n timeoutMs: number;\n signal?: AbortSignal;\n method?: \"GET\" | \"POST\";\n body?: unknown;\n}\n\n/** GET/POST JSON with a hard timeout. Returns `undefined` on any failure. */\nasync function fetchJson<T>(\n url: string,\n endpoint: LocalEndpoint,\n options: FetchJsonOptions,\n): Promise<T | undefined> {\n try {\n const res = await fetchJsonOrThrow<T>(url, endpoint, options);\n return res;\n } catch {\n return undefined;\n }\n}\n\nasync function fetchJsonOrThrow<T>(\n url: string,\n endpoint: LocalEndpoint,\n { timeoutMs, signal, method = \"GET\", body }: FetchJsonOptions,\n): Promise<T> {\n const controller = new AbortController();\n const timer = setTimeout(() => controller.abort(), timeoutMs);\n const onAbort = () => controller.abort();\n signal?.addEventListener(\"abort\", onAbort, { once: true });\n try {\n const res = await fetch(url, {\n method,\n signal: controller.signal,\n headers: body\n ? { ...authHeaders(endpoint), \"Content-Type\": \"application/json\" }\n : authHeaders(endpoint),\n ...(body ? { body: JSON.stringify(body) } : {}),\n });\n if (!res.ok) throw new Error(`HTTP ${res.status}`);\n return (await res.json()) as T;\n } finally {\n clearTimeout(timer);\n signal?.removeEventListener(\"abort\", onAbort);\n }\n}\n\n/** Turn a fetch failure into wording a user can act on. */\nfunction unreachableReason(endpoint: LocalEndpoint, err: unknown): string {\n const message = err instanceof Error ? err.message : String(err);\n if (/abort/i.test(message)) return `No response from ${endpoint.baseUrl} (timed out)`;\n if (/HTTP 401|HTTP 403/.test(message)) {\n return `${endpoint.baseUrl} rejected the API key (HTTP ${message.includes(\"401\") ? 401 : 403})`;\n }\n if (/HTTP \\d+/.test(message)) return `${endpoint.baseUrl} returned ${message}`;\n return `Not running at ${endpoint.baseUrl}`;\n}\n\n// ── Server response shapes ─────────────────────────────────\n\ninterface OpenAIModelListEntry {\n id?: string;\n /** vLLM sometimes reports the real window here. */\n max_model_len?: number;\n}\ninterface OpenAIModelList {\n data?: OpenAIModelListEntry[];\n}\n\ninterface OllamaShowResponse {\n capabilities?: string[];\n model_info?: Record<string, unknown>;\n}\n\ninterface LmStudioModelEntry {\n id?: string;\n type?: string;\n state?: string;\n max_context_length?: number;\n loaded_context_length?: number;\n}\ninterface LmStudioModelList {\n data?: LmStudioModelEntry[];\n}\n\ninterface LlamaCppProps {\n default_generation_settings?: { n_ctx?: number };\n}\n\n// ── Probing ────────────────────────────────────────────────\n\nexport interface ProbeOptions {\n timeoutMs?: number;\n signal?: AbortSignal;\n}\n\n/**\n * Ask one endpoint what it serves. Never throws — an unreachable server yields\n * `{ reachable: false, reason }` so the UI can say \"not running\" without an\n * error toast.\n */\nexport async function probeEndpoint(\n endpoint: LocalEndpoint,\n { timeoutMs = DEFAULT_PROBE_TIMEOUT_MS, signal }: ProbeOptions = {},\n): Promise<LocalEndpointProbe> {\n const listUrl = `${endpoint.baseUrl.replace(/\\/+$/, \"\")}/models`;\n let list: OpenAIModelList;\n try {\n list = await fetchJsonOrThrow<OpenAIModelList>(listUrl, endpoint, { timeoutMs, signal });\n } catch (err) {\n return { endpoint, reachable: false, reason: unreachableReason(endpoint, err), models: [] };\n }\n\n const entries = (list.data ?? []).filter(\n (entry): entry is OpenAIModelListEntry & { id: string } =>\n typeof entry.id === \"string\" && entry.id.length > 0 && !NON_CHAT_ID_PATTERN.test(entry.id),\n );\n\n const models = await enrich(endpoint, entries, { timeoutMs, signal });\n log(\"INFO\", \"local-models\", `Probed ${endpoint.label}`, {\n baseUrl: endpoint.baseUrl,\n models: String(models.length),\n });\n return { endpoint, reachable: true, models };\n}\n\nasync function enrich(\n endpoint: LocalEndpoint,\n entries: (OpenAIModelListEntry & { id: string })[],\n options: { timeoutMs: number; signal?: AbortSignal },\n): Promise<LocalModel[]> {\n if (endpoint.kind === \"lmstudio\") return enrichLmStudio(endpoint, entries, options);\n if (endpoint.kind === \"ollama\") return enrichOllama(endpoint, entries, options);\n if (endpoint.kind === \"llamacpp\") return enrichLlamaCpp(endpoint, entries, options);\n return entries.map((entry) => genericModel(endpoint, entry));\n}\n\n/**\n * Servers that report no capabilities (vLLM, generic gateways) gate tool calling\n * per-model server-side. Assuming tools work is the useful default: a model that\n * genuinely can't will surface a normal provider error on the first tool call,\n * whereas assuming it can't makes every such model unusable.\n */\nfunction genericModel(\n endpoint: LocalEndpoint,\n entry: OpenAIModelListEntry & { id: string },\n): LocalModel {\n const declared = typeof entry.max_model_len === \"number\" ? entry.max_model_len : undefined;\n return {\n rawId: entry.id,\n endpointId: endpoint.id,\n contextWindow: declared ?? FALLBACK_CONTEXT_WINDOW,\n contextWindowKnown: declared !== undefined,\n supportsTools: true,\n supportsImages: false,\n supportsThinking: false,\n };\n}\n\nasync function enrichOllama(\n endpoint: LocalEndpoint,\n entries: (OpenAIModelListEntry & { id: string })[],\n options: { timeoutMs: number; signal?: AbortSignal },\n): Promise<LocalModel[]> {\n const showUrl = `${endpointRoot(endpoint.baseUrl)}/api/show`;\n const enriched = await mapLimited(entries, ENRICH_CONCURRENCY, async (entry) => {\n const show = await fetchJson<OllamaShowResponse>(showUrl, endpoint, {\n ...options,\n method: \"POST\",\n body: { model: entry.id },\n });\n if (!show) return genericModel(endpoint, entry);\n const caps = show.capabilities ?? [];\n // Capabilities are authoritative for \"is this a chat model at all\". Names\n // like `all-minilm` carry no hint, so filtering on the id alone leaves\n // embedding models in the picker as dead, tool-less rows.\n if (caps.includes(\"embedding\") && !caps.includes(\"completion\")) return undefined;\n const ctx = ollamaContextLength(show.model_info);\n return {\n rawId: entry.id,\n endpointId: endpoint.id,\n contextWindow: ctx ?? FALLBACK_CONTEXT_WINDOW,\n contextWindowKnown: ctx !== undefined,\n // Ollama reports capabilities honestly, so trust it here rather than\n // using the optimistic generic default.\n supportsTools: caps.includes(\"tools\"),\n supportsImages: caps.includes(\"vision\"),\n supportsThinking: caps.includes(\"thinking\"),\n };\n });\n return enriched.filter((model): model is LocalModel => model !== undefined);\n}\n\n/** `model_info` keys are architecture-prefixed, e.g. `qwen3.context_length`. */\nfunction ollamaContextLength(info: Record<string, unknown> | undefined): number | undefined {\n if (!info) return undefined;\n for (const [key, value] of Object.entries(info)) {\n if (key.endsWith(\".context_length\") && typeof value === \"number\" && value > 0) return value;\n }\n return undefined;\n}\n\nasync function enrichLmStudio(\n endpoint: LocalEndpoint,\n entries: (OpenAIModelListEntry & { id: string })[],\n options: { timeoutMs: number; signal?: AbortSignal },\n): Promise<LocalModel[]> {\n const detail = await fetchJson<LmStudioModelList>(\n `${endpointRoot(endpoint.baseUrl)}/api/v0/models`,\n endpoint,\n options,\n );\n if (!detail?.data) return entries.map((entry) => genericModel(endpoint, entry));\n const byId = new Map(detail.data.filter((m) => m.id).map((m) => [m.id!, m]));\n const models: LocalModel[] = [];\n for (const entry of entries) {\n const info = byId.get(entry.id);\n // `type` is authoritative here: embeddings models are listed by\n // /v1/models too and would otherwise show up as selectable chat models.\n if (info && info.type !== \"llm\" && info.type !== \"vlm\") continue;\n const ctx = info?.max_context_length;\n models.push({\n rawId: entry.id,\n endpointId: endpoint.id,\n contextWindow: typeof ctx === \"number\" && ctx > 0 ? ctx : FALLBACK_CONTEXT_WINDOW,\n contextWindowKnown: typeof ctx === \"number\" && ctx > 0,\n // LM Studio doesn't report tool support; it gates per-model at request time.\n supportsTools: true,\n supportsImages: info?.type === \"vlm\",\n supportsThinking: false,\n loaded: info?.state === \"loaded\",\n });\n }\n return models;\n}\n\nasync function enrichLlamaCpp(\n endpoint: LocalEndpoint,\n entries: (OpenAIModelListEntry & { id: string })[],\n options: { timeoutMs: number; signal?: AbortSignal },\n): Promise<LocalModel[]> {\n const props = await fetchJson<LlamaCppProps>(\n `${endpointRoot(endpoint.baseUrl)}/props`,\n endpoint,\n options,\n );\n const nCtx = props?.default_generation_settings?.n_ctx;\n const known = typeof nCtx === \"number\" && nCtx > 0;\n return entries.map((entry) => ({\n ...genericModel(endpoint, entry),\n contextWindow: known ? nCtx : FALLBACK_CONTEXT_WINDOW,\n contextWindowKnown: known,\n }));\n}\n\n/** Bounded-parallel map — keeps input order. */\nasync function mapLimited<T, R>(\n items: T[],\n limit: number,\n fn: (item: T) => Promise<R>,\n): Promise<R[]> {\n const results = new Array<R>(items.length);\n let next = 0;\n const workers = Array.from({ length: Math.min(limit, items.length) }, async () => {\n while (next < items.length) {\n const index = next++;\n results[index] = await fn(items[index]!);\n }\n });\n await Promise.all(workers);\n return results;\n}\n\n// ── ModelInfo mapping ──────────────────────────────────────\n\n/**\n * Highest reasoning effort an endpoint accepts. Ollama documents (and 0.32\n * verifiably accepts) `low|medium|high|max|none` on `reasoning_effort`; the\n * other OpenAI-compatible servers only define `low|medium|high`, so they stop\n * at `high` rather than risking a 400 mid-run on an effort they never declared.\n * No local server accepts `xhigh`.\n */\nfunction maxThinkingLevelFor(endpoint: LocalEndpoint): \"high\" | \"max\" {\n return endpoint.kind === \"ollama\" ? \"max\" : \"high\";\n}\n\n/** Convert a probed local model into the registry shape the whole app speaks. */\nexport function toModelInfo(model: LocalModel, endpoint: LocalEndpoint): ModelInfo {\n return {\n id: formatLocalModelId(model.endpointId, model.rawId),\n name: `${model.rawId} (${endpoint.label})`,\n provider: \"local\",\n contextWindow: model.contextWindow,\n // Leave real headroom for the prompt on small local windows.\n maxOutputTokens: Math.max(512, Math.min(4096, Math.floor(model.contextWindow / 4))),\n supportsThinking: model.supportsThinking,\n supportsImages: model.supportsImages,\n supportsVideo: false,\n costTier: \"low\",\n maxThinkingLevel: maxThinkingLevelFor(endpoint),\n authStorageKeys: [localAuthStorageKey(model.endpointId)],\n };\n}\n\n// ── Discovery ──────────────────────────────────────────────\n\nexport interface DiscoveryResult {\n probes: LocalEndpointProbe[];\n models: ModelInfo[];\n}\n\ninterface CacheEntry {\n key: string;\n at: number;\n result: DiscoveryResult;\n}\n\nlet cache: CacheEntry | undefined;\n\nfunction cacheKey(endpoints: readonly LocalEndpoint[]): string {\n return endpoints.map((e) => `${e.id}@${e.baseUrl}`).join(\"|\");\n}\n\nexport interface DiscoverOptions extends ProbeOptions {\n /** Skip the 30s cache (the UI's \"Scan\" button). */\n force?: boolean;\n}\n\n/**\n * Probe every endpoint in parallel and return both the per-endpoint status (for\n * the UI) and the `ModelInfo[]` ready for `registerRuntimeModels()`. Results are\n * cached for 30s per endpoint set so repeated `GET /models` calls don't re-probe\n * four servers; `force` bypasses it after an `ollama pull`.\n */\nexport async function discoverLocalModels(\n endpoints: readonly LocalEndpoint[] = DEFAULT_LOCAL_ENDPOINTS,\n options: DiscoverOptions = {},\n): Promise<DiscoveryResult> {\n const key = cacheKey(endpoints);\n if (!options.force && cache && cache.key === key && Date.now() - cache.at < CACHE_TTL_MS) {\n return cache.result;\n }\n const probes = await Promise.all(endpoints.map((endpoint) => probeEndpoint(endpoint, options)));\n const models = probes.flatMap((probe) =>\n probe.models.map((model) => toModelInfo(model, probe.endpoint)),\n );\n const result: DiscoveryResult = { probes, models };\n cache = { key, at: Date.now(), result };\n return result;\n}\n\n/** Drop the discovery cache (used by tests and after an endpoint is added/removed). */\nexport function clearLocalDiscoveryCache(): void {\n cache = undefined;\n}\n\n/** Look up the probed capabilities of a discovered model, by full local id. */\nexport function findProbedModel(\n probes: readonly LocalEndpointProbe[],\n modelId: string,\n): { model: LocalModel; endpoint: LocalEndpoint } | undefined {\n const parsed = parseLocalModelId(modelId);\n if (!parsed) return undefined;\n for (const probe of probes) {\n if (probe.endpoint.id !== parsed.endpointId) continue;\n const model = probe.models.find((m) => m.rawId === parsed.rawId);\n if (model) return { model, endpoint: probe.endpoint };\n }\n return undefined;\n}\n","import { kimiCodeBaseUrl, kimiCodingHeaders } from \"./oauth/kimi.js\";\nimport type { OAuthCredentials } from \"./oauth/types.js\";\n\nexport type SubscriptionUsageProvider = \"anthropic\" | \"openai\" | \"moonshot\";\n\nexport interface SubscriptionUsageWindow {\n kind: \"current\" | \"weekly\";\n label: string;\n usedPercent: number;\n /** Unix epoch milliseconds. */\n resetsAt?: number;\n}\n\nexport interface SubscriptionUsageSnapshot {\n provider: SubscriptionUsageProvider;\n displayName: string;\n windows: SubscriptionUsageWindow[];\n fetchedAt: number;\n}\n\nexport class SubscriptionUsageError extends Error {\n constructor(\n message: string,\n readonly status?: number,\n readonly retryAfterMs?: number,\n ) {\n super(message);\n this.name = \"SubscriptionUsageError\";\n }\n}\n\ntype FetchFn = (input: string | URL | Request, init?: RequestInit) => Promise<Response>;\n\ninterface FetchSubscriptionUsageOptions {\n fetchFn?: FetchFn;\n timeoutMs?: number;\n now?: () => number;\n}\n\ninterface AnthropicWindow {\n utilization?: unknown;\n resets_at?: unknown;\n}\n\ninterface AnthropicUsageResponse {\n five_hour?: AnthropicWindow | null;\n seven_day?: AnthropicWindow | null;\n}\n\ninterface CodexWindow {\n limit_window_seconds?: unknown;\n used_percent?: unknown;\n reset_at?: unknown;\n reset_after_seconds?: unknown;\n}\n\ninterface CodexUsageResponse {\n rate_limit?: {\n primary_window?: CodexWindow | null;\n secondary_window?: CodexWindow | null;\n } | null;\n}\n\ninterface KimiUsageDetail {\n limit?: unknown;\n used?: unknown;\n remaining?: unknown;\n resetTime?: unknown;\n}\n\ninterface KimiLimit {\n window?: { duration?: unknown; timeUnit?: unknown } | null;\n detail?: KimiUsageDetail | null;\n}\n\ninterface KimiUsageResponse {\n usage?: KimiUsageDetail | null;\n limits?: KimiLimit[] | null;\n}\n\nconst ANTHROPIC_USAGE_URL = \"https://api.anthropic.com/api/oauth/usage\";\nconst CODEX_USAGE_URL = \"https://chatgpt.com/backend-api/wham/usage\";\n\nfunction finiteNumber(value: unknown): number | undefined {\n return typeof value === \"number\" && Number.isFinite(value) ? value : undefined;\n}\n\nfunction clampPercent(value: unknown): number | undefined {\n const number = finiteNumber(value);\n return number === undefined ? undefined : Math.min(100, Math.max(0, number));\n}\n\nfunction isoTimestamp(value: unknown): number | undefined {\n if (typeof value !== \"string\" || !value.trim()) return undefined;\n const timestamp = Date.parse(value);\n return Number.isFinite(timestamp) ? timestamp : undefined;\n}\n\nfunction unixTimestamp(value: unknown): number | undefined {\n const seconds = finiteNumber(value);\n return seconds === undefined ? undefined : seconds * 1000;\n}\n\nfunction codexResetAt(window: CodexWindow, now: number): number | undefined {\n const absolute = unixTimestamp(window.reset_at);\n if (absolute !== undefined) return absolute;\n const afterSeconds = finiteNumber(window.reset_after_seconds);\n return afterSeconds === undefined ? undefined : now + afterSeconds * 1000;\n}\n\nfunction currentWindowLabel(seconds: unknown, fallbackHours: number): string {\n const duration = finiteNumber(seconds);\n const hours = Math.max(1, Math.round((duration ?? fallbackHours * 3600) / 3600));\n return `${hours}-hour`;\n}\n\nfunction codexWindowKind(\n window: CodexWindow,\n fallback: \"current\" | \"weekly\",\n): \"current\" | \"weekly\" {\n const duration = finiteNumber(window.limit_window_seconds);\n if (duration === undefined) return fallback;\n // The API can put its seven-day limit in either primary or secondary.\n // Classify by duration without mislabeling a future 24-hour window as weekly.\n return duration >= 6 * 24 * 60 * 60 ? \"weekly\" : \"current\";\n}\n\nfunction normalizedCodexWindow(\n window: CodexWindow | null | undefined,\n fallbackKind: \"current\" | \"weekly\",\n now: number,\n): SubscriptionUsageWindow | null {\n if (!window) return null;\n const usedPercent = clampPercent(window.used_percent);\n if (usedPercent === undefined) return null;\n const kind = codexWindowKind(window, fallbackKind);\n return {\n kind,\n label: kind === \"weekly\" ? \"Weekly\" : currentWindowLabel(window.limit_window_seconds, 5),\n usedPercent,\n resetsAt: codexResetAt(window, now),\n };\n}\n\nfunction retryAfterMs(response: Response, now: number): number | undefined {\n const value = response.headers.get(\"retry-after\")?.trim();\n if (!value) return undefined;\n if (/^\\d+(?:\\.\\d+)?$/.test(value)) return Math.ceil(Number(value) * 1_000);\n const retryAt = Date.parse(value);\n return Number.isFinite(retryAt) ? Math.max(0, retryAt - now) : undefined;\n}\n\nasync function readUsageResponse(response: Response, now: number): Promise<unknown> {\n const text = await response.text();\n if (!response.ok) {\n throw new SubscriptionUsageError(\n `Subscription usage request failed with HTTP ${response.status}`,\n response.status,\n retryAfterMs(response, now),\n );\n }\n try {\n return JSON.parse(text) as unknown;\n } catch {\n throw new SubscriptionUsageError(\"Subscription usage response was not valid JSON\");\n }\n}\n\nasync function fetchAnthropicUsage(\n credentials: Pick<OAuthCredentials, \"accessToken\">,\n fetchFn: FetchFn,\n signal: AbortSignal,\n now: () => number,\n): Promise<SubscriptionUsageSnapshot> {\n const response = await fetchFn(ANTHROPIC_USAGE_URL, {\n method: \"GET\",\n signal,\n headers: {\n Authorization: `Bearer ${credentials.accessToken}`,\n Accept: \"application/json\",\n \"anthropic-version\": \"2023-06-01\",\n \"anthropic-beta\": \"oauth-2025-04-20\",\n \"User-Agent\": \"ggcoder\",\n },\n });\n const data = (await readUsageResponse(response, now())) as AnthropicUsageResponse;\n const windows: SubscriptionUsageWindow[] = [];\n const currentPercent = clampPercent(data.five_hour?.utilization);\n if (currentPercent !== undefined) {\n windows.push({\n kind: \"current\",\n label: \"5-hour\",\n usedPercent: currentPercent,\n resetsAt: isoTimestamp(data.five_hour?.resets_at),\n });\n }\n const weeklyPercent = clampPercent(data.seven_day?.utilization);\n if (weeklyPercent !== undefined) {\n windows.push({\n kind: \"weekly\",\n label: \"Weekly\",\n usedPercent: weeklyPercent,\n resetsAt: isoTimestamp(data.seven_day?.resets_at),\n });\n }\n return {\n provider: \"anthropic\",\n displayName: \"Anthropic\",\n windows,\n fetchedAt: now(),\n };\n}\n\nasync function fetchCodexUsage(\n credentials: Pick<OAuthCredentials, \"accessToken\" | \"accountId\">,\n fetchFn: FetchFn,\n signal: AbortSignal,\n now: () => number,\n): Promise<SubscriptionUsageSnapshot> {\n const headers: Record<string, string> = {\n Authorization: `Bearer ${credentials.accessToken}`,\n Accept: \"application/json\",\n originator: \"ggcoder\",\n \"User-Agent\": \"ggcoder\",\n };\n if (credentials.accountId) headers[\"ChatGPT-Account-Id\"] = credentials.accountId;\n const response = await fetchFn(CODEX_USAGE_URL, { method: \"GET\", signal, headers });\n const data = (await readUsageResponse(response, now())) as CodexUsageResponse;\n const windows = [\n normalizedCodexWindow(data.rate_limit?.primary_window, \"current\", now()),\n normalizedCodexWindow(data.rate_limit?.secondary_window, \"weekly\", now()),\n ].filter((window): window is SubscriptionUsageWindow => window !== null);\n windows.sort((left, right) => {\n if (left.kind === right.kind) return 0;\n return left.kind === \"current\" ? -1 : 1;\n });\n return {\n provider: \"openai\",\n displayName: \"Codex\",\n windows,\n fetchedAt: now(),\n };\n}\n\n/**\n * Kimi For Coding (`/coding/v1/usages`) reports plan quota as string-valued\n * counters, so accept numbers too rather than trusting one wire shape.\n */\nfunction kimiNumber(value: unknown): number | undefined {\n if (typeof value === \"string\" && value.trim()) {\n const parsed = Number(value);\n return Number.isFinite(parsed) ? parsed : undefined;\n }\n return finiteNumber(value);\n}\n\nfunction kimiUsagePercent(detail: KimiUsageDetail | null | undefined): number | undefined {\n const used = kimiNumber(detail?.used);\n const limit = kimiNumber(detail?.limit);\n if (used === undefined || limit === undefined || limit <= 0) return undefined;\n return Math.min(100, Math.max(0, (used / limit) * 100));\n}\n\nfunction kimiWindowMinutes(window: KimiLimit[\"window\"]): number | undefined {\n const duration = kimiNumber(window?.duration);\n if (duration === undefined || duration <= 0) return undefined;\n switch (window?.timeUnit) {\n case \"TIME_UNIT_SECOND\":\n return duration / 60;\n case \"TIME_UNIT_MINUTE\":\n return duration;\n case \"TIME_UNIT_HOUR\":\n return duration * 60;\n case \"TIME_UNIT_DAY\":\n return duration * 24 * 60;\n default:\n // Unknown unit — skip the window rather than mislabel its duration.\n return undefined;\n }\n}\n\nasync function fetchKimiUsage(\n credentials: Pick<OAuthCredentials, \"accessToken\" | \"accountId\">,\n fetchFn: FetchFn,\n signal: AbortSignal,\n now: () => number,\n): Promise<SubscriptionUsageSnapshot> {\n const response = await fetchFn(`${kimiCodeBaseUrl()}/usages`, {\n method: \"GET\",\n signal,\n headers: {\n Authorization: \"Bearer \" + credentials.accessToken,\n Accept: \"application/json\",\n // The managed coding endpoint gates on the kimi-code-cli client identity,\n // same as model requests.\n ...kimiCodingHeaders(),\n },\n });\n const data = (await readUsageResponse(response, now())) as KimiUsageResponse;\n const windows: SubscriptionUsageWindow[] = [];\n // Top-level `usage` is the weekly request quota of the membership tier.\n const weeklyPercent = kimiUsagePercent(data.usage);\n if (weeklyPercent !== undefined) {\n windows.push({\n kind: \"weekly\",\n label: \"Weekly\",\n usedPercent: weeklyPercent,\n resetsAt: isoTimestamp(data.usage?.resetTime),\n });\n }\n for (const limit of data.limits ?? []) {\n const minutes = kimiWindowMinutes(limit?.window);\n const percent = kimiUsagePercent(limit?.detail);\n if (minutes === undefined || percent === undefined) continue;\n if (minutes >= 6 * 24 * 60) {\n // A weekly sub-limit duplicates the top-level quota — keep whichever\n // arrived first.\n if (!windows.some((window) => window.kind === \"weekly\")) {\n windows.push({\n kind: \"weekly\",\n label: \"Weekly\",\n usedPercent: percent,\n resetsAt: isoTimestamp(limit?.detail?.resetTime),\n });\n }\n continue;\n }\n windows.push({\n kind: \"current\",\n label: `${Math.max(1, Math.round(minutes / 60))}-hour`,\n usedPercent: percent,\n resetsAt: isoTimestamp(limit?.detail?.resetTime),\n });\n }\n windows.sort((left, right) => {\n if (left.kind === right.kind) return 0;\n return left.kind === \"current\" ? -1 : 1;\n });\n return {\n provider: \"moonshot\",\n displayName: \"Kimi\",\n windows,\n fetchedAt: now(),\n };\n}\n\n/**\n * Fetch subscription quota windows with an already-resolved OAuth credential.\n * Tokens stay server-side: callers expose only the normalized percentages and\n * reset timestamps to their UI.\n */\nexport async function fetchSubscriptionUsage(\n provider: SubscriptionUsageProvider,\n credentials: Pick<OAuthCredentials, \"accessToken\" | \"accountId\">,\n options: FetchSubscriptionUsageOptions = {},\n): Promise<SubscriptionUsageSnapshot> {\n const fetchFn = options.fetchFn ?? fetch;\n const now = options.now ?? Date.now;\n const signal = AbortSignal.timeout(options.timeoutMs ?? 8_000);\n try {\n return provider === \"anthropic\"\n ? await fetchAnthropicUsage(credentials, fetchFn, signal, now)\n : provider === \"openai\"\n ? await fetchCodexUsage(credentials, fetchFn, signal, now)\n : await fetchKimiUsage(credentials, fetchFn, signal, now);\n } catch (error) {\n if (error instanceof SubscriptionUsageError) throw error;\n const message = error instanceof Error ? error.message : String(error);\n throw new SubscriptionUsageError(message);\n }\n}\n","/**\n * Minimal Telegram Bot API client using raw fetch().\n * Supports long polling, markdown messages, inline keyboards, and message splitting.\n */\n\nconst TELEGRAM_API = \"https://api.telegram.org\";\nconst MAX_MESSAGE_LENGTH = 4096;\n\nexport interface TelegramConfig {\n botToken: string;\n /** Only accept messages from this Telegram user ID. */\n allowedUserId: number;\n}\n\nexport interface TelegramUpdate {\n update_id: number;\n message?: {\n message_id: number;\n from: { id: number; first_name: string };\n chat: { id: number; type: string; title?: string };\n text?: string;\n voice?: { file_id: string; duration: number; mime_type?: string; file_size?: number };\n };\n callback_query?: {\n id: string;\n from: { id: number };\n message: { chat: { id: number } };\n data: string;\n };\n my_chat_member?: {\n chat: { id: number; type: string; title?: string };\n from: { id: number };\n new_chat_member: { status: string };\n };\n}\n\nexport interface InlineButton {\n text: string;\n callback_data: string;\n}\n\n/** Incoming message with chat context. */\nexport interface TelegramMessage {\n text: string;\n chatId: number;\n chatType: \"private\" | \"group\" | \"supergroup\" | \"channel\";\n chatTitle?: string;\n}\n\n/** Incoming voice note with chat context. */\nexport interface TelegramVoiceMessage {\n fileId: string;\n duration: number;\n chatId: number;\n chatType: \"private\" | \"group\" | \"supergroup\" | \"channel\";\n chatTitle?: string;\n}\n\nexport class TelegramBot {\n private token: string;\n private allowedUserId: number;\n private offset = 0;\n private running = false;\n\n private onMessage: ((msg: TelegramMessage) => void) | null = null;\n private onVoiceMessage: ((msg: TelegramVoiceMessage) => void) | null = null;\n private onCallback: ((data: string, chatId: number) => void) | null = null;\n private onBotAdded: ((chatId: number, chatTitle?: string) => void) | null = null;\n private onBotRemoved: ((chatId: number) => void) | null = null;\n\n constructor(config: TelegramConfig) {\n this.token = config.botToken;\n this.allowedUserId = config.allowedUserId;\n }\n\n /** Register handler for incoming text messages. */\n onText(handler: (msg: TelegramMessage) => void): void {\n this.onMessage = handler;\n }\n\n /** Register handler for incoming voice notes. */\n onVoice(handler: (msg: TelegramVoiceMessage) => void): void {\n this.onVoiceMessage = handler;\n }\n\n /** Register handler for inline keyboard button presses. */\n onCallbackQuery(handler: (data: string, chatId: number) => void): void {\n this.onCallback = handler;\n }\n\n /** Register handler for when the bot is added to a group. */\n onAddedToGroup(handler: (chatId: number, chatTitle?: string) => void): void {\n this.onBotAdded = handler;\n }\n\n /** Register handler for when the bot is removed from a group. */\n onRemovedFromGroup(handler: (chatId: number) => void): void {\n this.onBotRemoved = handler;\n }\n\n /** Start long polling. Blocks until stop() is called. */\n async start(): Promise<void> {\n this.running = true;\n\n // Verify bot token works\n const me = await this.apiCall(\"getMe\");\n if (!me.ok) {\n throw new Error(`Invalid bot token: ${JSON.stringify(me)}`);\n }\n\n while (this.running) {\n try {\n const updates = await this.getUpdates();\n for (const update of updates) {\n await this.handleUpdate(update);\n }\n } catch (err) {\n if (!this.running) break;\n console.error(`[telegram] Poll error: ${err instanceof Error ? err.message : err}`);\n await sleep(3000);\n }\n }\n }\n\n /** Stop long polling. */\n stop(): void {\n this.running = false;\n }\n\n /** Send a text message to a specific chat. Converts markdown and splits long messages. */\n async send(chatId: number, text: string, buttons?: InlineButton[][]): Promise<void> {\n const converted = toTelegramMarkdown(text);\n const chunks = splitMessage(converted);\n\n for (let i = 0; i < chunks.length; i++) {\n const isLast = i === chunks.length - 1;\n const replyMarkup =\n isLast && buttons\n ? {\n inline_keyboard: buttons.map((row) =>\n row.map((b) => ({ text: b.text, callback_data: b.callback_data })),\n ),\n }\n : undefined;\n\n await this.apiCall(\"sendMessage\", {\n chat_id: chatId,\n text: chunks[i],\n parse_mode: \"Markdown\",\n ...(replyMarkup ? { reply_markup: replyMarkup } : {}),\n });\n }\n }\n\n /** Send a plain text message (no markdown parsing) to a specific chat. */\n async sendPlain(chatId: number, text: string): Promise<void> {\n const chunks = splitMessage(text);\n for (const chunk of chunks) {\n await this.apiCall(\"sendMessage\", {\n chat_id: chatId,\n text: chunk,\n });\n }\n }\n\n /** Send a typing indicator to a specific chat. */\n async sendTyping(chatId: number): Promise<void> {\n await this.apiCall(\"sendChatAction\", {\n chat_id: chatId,\n action: \"typing\",\n });\n }\n\n /** Get a direct download URL for a Telegram file. */\n async getFileUrl(fileId: string): Promise<string> {\n const result = await this.apiCall(\"getFile\", { file_id: fileId });\n if (!result.ok) throw new Error(`Failed to get file: ${JSON.stringify(result)}`);\n const filePath = (result.result as { file_path: string }).file_path;\n return `${TELEGRAM_API}/file/bot${this.token}/${filePath}`;\n }\n\n // ── Private ───────────────────────────────────────────\n\n private async getUpdates(): Promise<TelegramUpdate[]> {\n const result = await this.apiCall(\"getUpdates\", {\n offset: this.offset,\n timeout: 30,\n allowed_updates: [\"message\", \"callback_query\", \"my_chat_member\"],\n });\n\n if (!result.ok || !Array.isArray(result.result)) return [];\n\n const updates = result.result as TelegramUpdate[];\n if (updates.length > 0) {\n this.offset = updates[updates.length - 1]!.update_id + 1;\n }\n return updates;\n }\n\n private async handleUpdate(update: TelegramUpdate): Promise<void> {\n if (update.message) {\n const msg = update.message;\n\n // Auth check\n if (msg.from.id !== this.allowedUserId) {\n return;\n }\n\n if (msg.text && this.onMessage) {\n this.onMessage({\n text: msg.text,\n chatId: msg.chat.id,\n chatType: msg.chat.type as TelegramMessage[\"chatType\"],\n chatTitle: msg.chat.title,\n });\n } else if (msg.voice && this.onVoiceMessage) {\n this.onVoiceMessage({\n fileId: msg.voice.file_id,\n duration: msg.voice.duration,\n chatId: msg.chat.id,\n chatType: msg.chat.type as TelegramMessage[\"chatType\"],\n chatTitle: msg.chat.title,\n });\n }\n }\n\n // Bot membership changed in a group\n if (update.my_chat_member) {\n const member = update.my_chat_member;\n const status = member.new_chat_member.status;\n if ((status === \"member\" || status === \"administrator\") && this.onBotAdded) {\n this.onBotAdded(member.chat.id, member.chat.title);\n } else if ((status === \"left\" || status === \"kicked\") && this.onBotRemoved) {\n this.onBotRemoved(member.chat.id);\n }\n }\n\n if (update.callback_query) {\n const cb = update.callback_query;\n\n if (cb.from.id !== this.allowedUserId) return;\n\n await this.apiCall(\"answerCallbackQuery\", { callback_query_id: cb.id });\n\n if (cb.data && this.onCallback) {\n this.onCallback(cb.data, cb.message.chat.id);\n }\n }\n }\n\n private async apiCall(\n method: string,\n body?: Record<string, unknown>,\n ): Promise<{ ok: boolean; result?: unknown }> {\n const url = `${TELEGRAM_API}/bot${this.token}/${method}`;\n\n const response = await fetch(url, {\n method: \"POST\",\n headers: { \"Content-Type\": \"application/json\" },\n body: body ? JSON.stringify(body) : undefined,\n });\n\n if (!response.ok) {\n return { ok: false };\n }\n\n return response.json() as Promise<{ ok: boolean; result?: unknown }>;\n }\n}\n\n// ── Markdown Conversion ──────────────────────────────────\n\n/**\n * Convert GitHub-flavored markdown to Telegram-compatible Markdown.\n *\n * Telegram supports: *bold*, _italic_, `code`, ```pre```, [link](url)\n * Does NOT support: headings, horizontal rules, tables, HTML tags, images\n */\nfunction toTelegramMarkdown(text: string): string {\n const lines = text.split(\"\\n\");\n const result: string[] = [];\n let inCodeBlock = false;\n\n for (const line of lines) {\n if (line.trimStart().startsWith(\"```\")) {\n inCodeBlock = !inCodeBlock;\n result.push(line);\n continue;\n }\n\n if (inCodeBlock) {\n result.push(line);\n continue;\n }\n\n let transformed = line;\n\n // Headings → bold text\n const headingMatch = transformed.match(/^(#{1,6})\\s+(.+)$/);\n if (headingMatch) {\n transformed = `*${headingMatch[2]}*`;\n result.push(transformed);\n continue;\n }\n\n // Horizontal rules → empty line\n if (/^(-{3,}|_{3,}|\\*{3,})$/.test(transformed.trim())) {\n result.push(\"\");\n continue;\n }\n\n // **bold** → *bold*\n transformed = transformed.replace(/\\*\\*(.+?)\\*\\*/g, \"*$1*\");\n\n result.push(transformed);\n }\n\n return result.join(\"\\n\");\n}\n\n// ── Helpers ───────────────────────────────────────────────\n\nfunction splitMessage(text: string): string[] {\n if (text.length <= MAX_MESSAGE_LENGTH) return [text];\n\n const chunks: string[] = [];\n let remaining = text;\n\n while (remaining.length > 0) {\n if (remaining.length <= MAX_MESSAGE_LENGTH) {\n chunks.push(remaining);\n break;\n }\n\n let splitAt = remaining.lastIndexOf(\"\\n\", MAX_MESSAGE_LENGTH);\n if (splitAt === -1 || splitAt < MAX_MESSAGE_LENGTH * 0.5) {\n splitAt = remaining.lastIndexOf(\" \", MAX_MESSAGE_LENGTH);\n }\n if (splitAt === -1 || splitAt < MAX_MESSAGE_LENGTH * 0.5) {\n splitAt = MAX_MESSAGE_LENGTH;\n }\n\n chunks.push(remaining.slice(0, splitAt));\n remaining = remaining.slice(splitAt).trimStart();\n }\n\n return chunks;\n}\n\nfunction sleep(ms: number): Promise<void> {\n return new Promise((r) => setTimeout(r, ms));\n}\n","/**\n * Voice note transcription using local Whisper model.\n * Uses @huggingface/transformers (pure JS/WASM) — no native deps, no API keys.\n * Model (~75MB) is downloaded on first use and cached locally.\n */\n\nimport type { AutomaticSpeechRecognitionPipeline } from \"@huggingface/transformers\";\n\nconst TARGET_SAMPLE_RATE = 16000;\nconst MODEL_ID = \"Xenova/whisper-tiny.en\";\n\nlet transcriber: AutomaticSpeechRecognitionPipeline | null = null;\nlet loadPromise: Promise<AutomaticSpeechRecognitionPipeline> | null = null;\n\n/** Optional callback for model download progress. */\nexport type ProgressCallback = (info: { status: string; progress?: number; file?: string }) => void;\n\nlet onProgress: ProgressCallback | null = null;\n\n/** Set a callback to receive model download progress updates. */\nexport function setProgressCallback(cb: ProgressCallback | null): void {\n onProgress = cb;\n}\n\n/**\n * Resample audio from one sample rate to another using linear interpolation.\n */\nexport function resample(audio: Float32Array, fromRate: number, toRate: number): Float32Array {\n if (fromRate === toRate) return audio;\n const ratio = fromRate / toRate;\n const newLength = Math.round(audio.length / ratio);\n const result = new Float32Array(newLength);\n for (let i = 0; i < newLength; i++) {\n const srcIndex = i * ratio;\n const low = Math.floor(srcIndex);\n const high = Math.min(low + 1, audio.length - 1);\n const frac = srcIndex - low;\n result[i] = audio[low]! * (1 - frac) + audio[high]! * frac;\n }\n return result;\n}\n\n/**\n * Downmix multi-channel audio to mono by averaging all channels.\n */\nexport function downmixToMono(channelData: Float32Array[]): Float32Array {\n if (channelData.length === 0) return new Float32Array();\n if (channelData.length === 1) return channelData[0]!;\n\n const samples = channelData[0]!.length;\n const out = new Float32Array(samples);\n const scale = 1 / channelData.length;\n for (let i = 0; i < samples; i++) {\n let mixed = 0;\n for (const channel of channelData) mixed += channel[i] ?? 0;\n out[i] = mixed * scale;\n }\n return out;\n}\n\n/**\n * Decode OGG Opus audio buffer to 16kHz mono PCM Float32Array.\n */\nexport async function decodeOggOpus(buffer: Uint8Array): Promise<Float32Array> {\n const { OggOpusDecoder } = await import(\"ogg-opus-decoder\");\n const decoder = new OggOpusDecoder();\n await decoder.ready;\n try {\n const decoded = await decoder.decodeFile(buffer);\n\n if (!decoded.channelData?.length || !decoded.channelData[0]?.length) {\n throw new Error(\"Decoded audio is empty\");\n }\n\n const mono = downmixToMono(decoded.channelData);\n return resample(mono, decoded.sampleRate, TARGET_SAMPLE_RATE);\n } finally {\n decoder.free();\n }\n}\n\n/**\n * Get or initialize the Whisper transcription pipeline.\n * Model is downloaded on first use and cached by transformers.js.\n */\nasync function getTranscriber(): Promise<AutomaticSpeechRecognitionPipeline> {\n if (transcriber) return transcriber;\n\n if (!loadPromise) {\n loadPromise = (async () => {\n const { pipeline } = await import(\"@huggingface/transformers\");\n const instance = await pipeline(\"automatic-speech-recognition\", MODEL_ID, {\n dtype: \"fp32\",\n progress_callback: onProgress ?? undefined,\n });\n transcriber = instance;\n return instance;\n })();\n }\n\n return loadPromise;\n}\n\n/** Whether the model has been loaded already. */\nexport function isModelLoaded(): boolean {\n return transcriber !== null;\n}\n\n/**\n * Transcribe a voice message from its Telegram file URL.\n * Downloads the OGG Opus file, decodes to PCM, and runs Whisper locally.\n */\nexport async function transcribeVoice(fileUrl: string): Promise<string> {\n // Download the audio file\n const response = await fetch(fileUrl);\n if (!response.ok) throw new Error(`Failed to download voice file: ${response.status}`);\n const buffer = new Uint8Array(await response.arrayBuffer());\n\n // Decode OGG Opus → 16kHz mono PCM\n const pcm = await decodeOggOpus(buffer);\n\n // Transcribe with Whisper\n const asr = await getTranscriber();\n const result = await asr(pcm);\n\n const text = Array.isArray(result) ? result[0]?.text : (result as { text: string }).text;\n return (text ?? \"\").trim();\n}\n","import { spawn } from \"node:child_process\";\nimport fs from \"node:fs\";\nimport path from \"node:path\";\n\n/**\n * Provider-agnostic background self-updater. Each app composes its own instance\n * via `createAutoUpdater` with its npm package name and state-file path, so the\n * update logic (registry poll, version compare, detached install, throttling)\n * lives in exactly one place while branding stays in the apps.\n */\n\ninterface UpdateState {\n lastCheckedAt: number;\n latestVersion?: string;\n updatePending?: boolean;\n lastUpdateAttempt?: number;\n}\n\nenum PackageManager {\n NPM = \"npm\",\n PNPM = \"pnpm\",\n YARN = \"yarn\",\n UNKNOWN = \"unknown\",\n}\n\ninterface InstallInfo {\n packageManager: PackageManager;\n updateCommand: string | null;\n}\n\nexport interface AutoUpdateConfig {\n /** npm package to self-update, e.g. \"@kenkaiiii/ggcoder\". */\n packageName: string;\n /**\n * Absolute path to this app's update-state.json, or a thunk resolving it.\n * A thunk keeps path resolution lazy so callers can derive it from\n * `os.homedir()` without freezing the value at module-load time (which\n * breaks tests that mock the home directory after import).\n */\n stateFilePath: string | (() => string);\n /** Builds the in-session \"update available\" notification. */\n periodicMessage?: (args: {\n currentVersion: string;\n latestVersion: string;\n updateCommand: string;\n }) => string;\n}\n\nexport interface AutoUpdater {\n checkAndAutoUpdate(currentVersion: string): string | null;\n getPendingUpdate(currentVersion: string): { latestVersion: string } | null;\n startPeriodicUpdateCheck(currentVersion: string, onUpdate: (message: string) => void): void;\n stopPeriodicUpdateCheck(): void;\n}\n\nconst CHECK_INTERVAL_MS = 60 * 60 * 1000; // 1 hour\nconst FETCH_TIMEOUT_MS = 10_000; // 10s — npm can be slow\n\nfunction compareVersions(a: string, b: string): number {\n const pa = a.split(\".\").map(Number);\n const pb = b.split(\".\").map(Number);\n for (let i = 0; i < 3; i++) {\n const diff = (pa[i] ?? 0) - (pb[i] ?? 0);\n if (diff !== 0) return diff;\n }\n return 0;\n}\n\nfunction performUpdateInBackground(command: string): void {\n try {\n const parts = command.split(\" \");\n const child = spawn(parts[0]!, parts.slice(1), {\n detached: true,\n stdio: \"ignore\",\n env: { ...process.env, npm_config_loglevel: \"silent\" },\n });\n child.unref();\n } catch {\n // Non-fatal — will retry next startup\n }\n}\n\nexport function createAutoUpdater(config: AutoUpdateConfig): AutoUpdater {\n const REGISTRY_URL = `https://registry.npmjs.org/${config.packageName}/latest`;\n const periodicMessage =\n config.periodicMessage ??\n (({ currentVersion, latestVersion, updateCommand }) =>\n `Ken just pushed a fresh update — ${currentVersion} → ${latestVersion}! I'll grab it on next launch (or run ${updateCommand} if you can't wait).`);\n\n let periodicTimer: ReturnType<typeof setInterval> | null = null;\n\n function stateFilePath(): string {\n return typeof config.stateFilePath === \"function\"\n ? config.stateFilePath()\n : config.stateFilePath;\n }\n\n function readState(): UpdateState | null {\n try {\n const raw = fs.readFileSync(stateFilePath(), \"utf-8\");\n return JSON.parse(raw) as UpdateState;\n } catch {\n return null;\n }\n }\n\n function writeState(state: UpdateState): void {\n try {\n const filePath = stateFilePath();\n fs.mkdirSync(path.dirname(filePath), { recursive: true, mode: 0o700 });\n fs.writeFileSync(filePath, JSON.stringify(state));\n } catch {\n // Non-fatal\n }\n }\n\n function detectInstallInfo(): InstallInfo {\n const scriptPath = (process.argv[1] ?? \"\").replace(/\\\\/g, \"/\");\n\n // npx — skip (ephemeral)\n if (scriptPath.includes(\"/_npx/\")) {\n return { packageManager: PackageManager.UNKNOWN, updateCommand: null };\n }\n\n // pnpm global\n if (scriptPath.includes(\"/.pnpm\") || scriptPath.includes(\"/pnpm/global\")) {\n return {\n packageManager: PackageManager.PNPM,\n updateCommand: `pnpm add -g ${config.packageName}@latest`,\n };\n }\n\n // yarn global\n if (scriptPath.includes(\"/.yarn/\") || scriptPath.includes(\"/yarn/global\")) {\n return {\n packageManager: PackageManager.YARN,\n updateCommand: `yarn global add ${config.packageName}@latest`,\n };\n }\n\n // npm global (default)\n return {\n packageManager: PackageManager.NPM,\n updateCommand: `npm install -g ${config.packageName}@latest`,\n };\n }\n\n async function fetchLatestVersion(): Promise<string | null> {\n try {\n const controller = new AbortController();\n const timeout = setTimeout(() => controller.abort(), FETCH_TIMEOUT_MS);\n const response = await fetch(REGISTRY_URL, { signal: controller.signal });\n clearTimeout(timeout);\n const data = (await response.json()) as { version?: string };\n const version = data.version?.trim();\n return version && /^\\d+\\.\\d+\\.\\d+/.test(version) ? version : null;\n } catch {\n return null;\n }\n }\n\n function scheduleBackgroundCheck(currentVersion: string): void {\n fetchLatestVersion()\n .then((latestVersion) => {\n const newState: UpdateState = {\n lastCheckedAt: Date.now(),\n latestVersion: latestVersion ?? undefined,\n updatePending: false,\n };\n if (latestVersion && compareVersions(latestVersion, currentVersion) > 0) {\n newState.updatePending = true;\n }\n writeState(newState);\n })\n .catch(() => {\n // Non-fatal — will retry next time\n });\n }\n\n function checkAndAutoUpdate(currentVersion: string): string | null {\n try {\n const state = readState();\n let message: string | null = null;\n\n // Phase 1: Apply pending update from previous check\n if (state?.updatePending && state.latestVersion) {\n if (compareVersions(state.latestVersion, currentVersion) > 0) {\n const info = detectInstallInfo();\n if (info.updateCommand) {\n performUpdateInBackground(info.updateCommand);\n message = `Ken just shipped ${state.latestVersion}! Installing in the background — takes effect next launch.`;\n writeState({\n ...state,\n lastCheckedAt: Date.now(),\n updatePending: false,\n lastUpdateAttempt: Date.now(),\n });\n }\n } else {\n // Already on latest (user may have updated manually)\n writeState({ ...state, updatePending: false });\n }\n }\n\n // Phase 2: Schedule background check for next startup\n const shouldCheck = !state || Date.now() - state.lastCheckedAt > CHECK_INTERVAL_MS;\n if (shouldCheck) scheduleBackgroundCheck(currentVersion);\n\n return message;\n } catch {\n return null;\n }\n }\n\n function getPendingUpdate(currentVersion: string): { latestVersion: string } | null {\n try {\n const state = readState();\n if (!state?.latestVersion) return null;\n if (compareVersions(state.latestVersion, currentVersion) <= 0) return null;\n return { latestVersion: state.latestVersion };\n } catch {\n return null;\n }\n }\n\n function startPeriodicUpdateCheck(\n currentVersion: string,\n onUpdate: (message: string) => void,\n ): void {\n if (periodicTimer) return; // Already running\n\n periodicTimer = setInterval(() => {\n fetchLatestVersion()\n .then((latestVersion) => {\n if (!latestVersion) return;\n if (compareVersions(latestVersion, currentVersion) <= 0) return;\n\n const info = detectInstallInfo();\n if (!info.updateCommand) return;\n\n writeState({ lastCheckedAt: Date.now(), latestVersion, updatePending: true });\n onUpdate(\n periodicMessage({ currentVersion, latestVersion, updateCommand: info.updateCommand }),\n );\n\n // Stop checking once we've notified\n stopPeriodicUpdateCheck();\n })\n .catch(() => {\n // Non-fatal\n });\n }, CHECK_INTERVAL_MS);\n\n // Don't keep the process alive just for update checks\n periodicTimer.unref();\n }\n\n function stopPeriodicUpdateCheck(): void {\n if (periodicTimer) {\n clearInterval(periodicTimer);\n periodicTimer = null;\n }\n }\n\n return {\n checkAndAutoUpdate,\n getPendingUpdate,\n startPeriodicUpdateCheck,\n stopPeriodicUpdateCheck,\n };\n}\n"],"mappings":"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","names":["maxIndex","levels","retryAfterMs"]}
|
package/dist/model-registry.cjs
CHANGED
|
@@ -204,6 +204,28 @@ var MODELS = [
|
|
|
204
204
|
maxThinkingLevel: "high"
|
|
205
205
|
},
|
|
206
206
|
// ── OpenAI (Codex) ─────────────────────────────────────
|
|
207
|
+
{
|
|
208
|
+
// GPT-6 Astra — "Our most capable model for complex, demanding work."
|
|
209
|
+
// (Codex catalog priority 1, default low). Same split as the 5.6 family:
|
|
210
|
+
// 1.05M on the public Responses API, 272K on the ChatGPT OAuth route
|
|
211
|
+
// (openai/codex models.json, `gpt-6-astra`). Reasoning ladder low → medium
|
|
212
|
+
// → high → xhigh → max → ultra; `ultra` is the Codex orchestration preset
|
|
213
|
+
// (multi_agent v2) and is Codex-only — the public API tops out at `max`.
|
|
214
|
+
// Note: through a plain API key OpenAI requires the Responses API for tool
|
|
215
|
+
// calling on Astra, so the Chat Completions path is text-only; the OAuth
|
|
216
|
+
// Codex route is the supported way to use it as an agent.
|
|
217
|
+
id: "gpt-6-astra",
|
|
218
|
+
name: "GPT-6 Astra",
|
|
219
|
+
provider: "openai",
|
|
220
|
+
contextWindow: 105e4,
|
|
221
|
+
codexContextWindow: 272e3,
|
|
222
|
+
maxOutputTokens: 128e3,
|
|
223
|
+
supportsThinking: true,
|
|
224
|
+
supportsImages: true,
|
|
225
|
+
supportsVideo: false,
|
|
226
|
+
costTier: "high",
|
|
227
|
+
maxThinkingLevel: "ultra"
|
|
228
|
+
},
|
|
207
229
|
// GPT-5.6 family — three agentic coding tiers launched July 2026. The public
|
|
208
230
|
// Responses API advertises a 1.05M context window; OpenAI's Codex product
|
|
209
231
|
// catalog advertises 272K on the ChatGPT OAuth route (corrected from the
|