@kenkaiiii/gg-core 4.4.0 → 4.6.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.
@@ -98,6 +98,7 @@ var MODELS = [
98
98
  supportsThinking: true,
99
99
  supportsImages: true,
100
100
  supportsVideo: true,
101
+ maxVideoBytes: 20 * 1024 * 1024,
101
102
  costTier: "low",
102
103
  maxThinkingLevel: "high"
103
104
  },
@@ -110,6 +111,7 @@ var MODELS = [
110
111
  supportsThinking: true,
111
112
  supportsImages: true,
112
113
  supportsVideo: true,
114
+ maxVideoBytes: 20 * 1024 * 1024,
113
115
  costTier: "low",
114
116
  maxThinkingLevel: "high"
115
117
  },
@@ -123,6 +125,7 @@ var MODELS = [
123
125
  supportsThinking: true,
124
126
  supportsImages: true,
125
127
  supportsVideo: true,
128
+ maxVideoBytes: 100 * 1024 * 1024,
126
129
  costTier: "medium",
127
130
  maxThinkingLevel: "high"
128
131
  },
@@ -173,13 +176,16 @@ var MODELS = [
173
176
  supportsThinking: true,
174
177
  supportsImages: true,
175
178
  supportsVideo: true,
179
+ maxVideoBytes: 50 * 1024 * 1024,
176
180
  costTier: "medium",
177
181
  maxThinkingLevel: "high"
178
182
  },
179
183
  // ── Xiaomi (MiMo) ──────────────────────────────────────
184
+ // Pro series: text-only coding/agentic flagship. The legacy mimo-v2-pro
185
+ // auto-routes to v2.5 on 2026-06-01 and is fully deprecated by 2026-06-30.
180
186
  {
181
- id: "mimo-v2-pro",
182
- name: "MiMo-V2-Pro",
187
+ id: "mimo-v2.5-pro",
188
+ name: "MiMo-V2.5-Pro",
183
189
  provider: "xiaomi",
184
190
  contextWindow: 1e6,
185
191
  maxOutputTokens: 131072,
@@ -189,6 +195,22 @@ var MODELS = [
189
195
  costTier: "medium",
190
196
  maxThinkingLevel: "high"
191
197
  },
198
+ // Omni series: native full-modal understanding (image + audio + video).
199
+ // Video/image ride the OpenAI-compatible transport as base64 data URLs
200
+ // (`video_url`/`image_url`), which the shared transform already emits.
201
+ {
202
+ id: "mimo-v2.5",
203
+ name: "MiMo-V2.5",
204
+ provider: "xiaomi",
205
+ contextWindow: 1e6,
206
+ maxOutputTokens: 131072,
207
+ supportsThinking: true,
208
+ supportsImages: true,
209
+ supportsVideo: true,
210
+ maxVideoBytes: 36 * 1024 * 1024,
211
+ costTier: "medium",
212
+ maxThinkingLevel: "high"
213
+ },
192
214
  // ── DeepSeek ───────────────────────────────────────────
193
215
  {
194
216
  id: "deepseek-v4-pro",
@@ -235,8 +257,14 @@ function getModel(id) {
235
257
  function getModelsForProvider(provider) {
236
258
  return MODELS.filter((m) => m.provider === provider);
237
259
  }
260
+ var DEFAULT_MAX_VIDEO_BYTES = 20 * 1024 * 1024;
261
+ function getVideoByteLimit(modelId) {
262
+ const model = getModel(modelId);
263
+ if (!model?.supportsVideo) return void 0;
264
+ return model.maxVideoBytes ?? DEFAULT_MAX_VIDEO_BYTES;
265
+ }
238
266
  function getDefaultModel(provider) {
239
- if (provider === "xiaomi") return MODELS.find((m) => m.id === "mimo-v2-pro");
267
+ if (provider === "xiaomi") return MODELS.find((m) => m.id === "mimo-v2.5-pro");
240
268
  if (provider === "openai") return MODELS.find((m) => m.id === "gpt-5.5");
241
269
  if (provider === "gemini") return MODELS.find((m) => m.id === "gemini-3.1-flash-lite-preview");
242
270
  if (provider === "glm") return MODELS.find((m) => m.id === "glm-5.1");
@@ -275,10 +303,12 @@ export {
275
303
  MODELS,
276
304
  getModel,
277
305
  getModelsForProvider,
306
+ DEFAULT_MAX_VIDEO_BYTES,
307
+ getVideoByteLimit,
278
308
  getDefaultModel,
279
309
  usesOpenAICodexTransport,
280
310
  getContextWindow,
281
311
  getMaxThinkingLevel,
282
312
  getSummaryModel
283
313
  };
284
- //# sourceMappingURL=chunk-USAVZGPP.js.map
314
+ //# sourceMappingURL=chunk-74Z6I5V7.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/model-registry.ts"],"sourcesContent":["import type { Provider, ThinkingLevel } from \"@kenkaiiii/gg-ai\";\n\nexport interface ModelInfo {\n id: string;\n name: string;\n provider: Provider;\n contextWindow: number;\n /**\n * ChatGPT Codex transport uses product-specific windows that can differ from\n * the public API model window. OpenAI OAuth requests include an accountId and\n * route through `/codex/responses`; API-key requests do not.\n */\n codexContextWindow?: number;\n maxOutputTokens: number;\n supportsThinking: boolean;\n supportsImages: boolean;\n supportsVideo: boolean;\n /**\n * Max video payload (bytes) this model's transport accepts, used to decide\n * when an attached/read video must be compressed before sending. Differs by\n * provider delivery mechanism:\n * - Moonshot/Kimi: 100 MB (file-service upload cap)\n * - MiniMax: 50 MB (Anthropic-compatible base64 inline cap)\n * - Gemini: 20 MB (inlineData per-request cap)\n * - Xiaomi (MiMo): ~36 MB raw — the API caps the base64 STRING at 50 MB,\n * and base64 inflates bytes by ~4/3, so 36 MB raw ≈ 48 MB encoded.\n * Only meaningful when `supportsVideo` is true.\n */\n maxVideoBytes?: number;\n costTier: \"low\" | \"medium\" | \"high\";\n /**\n * The top reasoning tier this model genuinely uses. Used when thinking is\n * enabled to pick the strongest setting per model:\n * - OpenAI GPT-5.5-era: `xhigh`\n * - OpenAI Pro/Codex/old: clamped to what the model accepts\n * - Claude Opus 4.8 / 4.7 / 4.6 and Sonnet 4.6: `max`\n * - Claude Haiku 4.5: `high` (no adaptive `max` tier)\n * - GLM / Moonshot / Xiaomi / MiniMax / Qwen: `high` — binary-thinking\n * providers ignore the level on the wire, so the value is cosmetic\n * - DeepSeek V4: `xhigh` (DeepSeek maps `xhigh` → its internal `max`)\n */\n maxThinkingLevel: ThinkingLevel;\n}\n\n// Provider display order — mirrors `PROVIDERS` in ui/login.tsx so the\n// /model selector and login selector sort models identically.\nexport const MODELS: ModelInfo[] = [\n // ── Anthropic ──────────────────────────────────────────\n {\n id: \"claude-opus-4-8\",\n name: \"Claude Opus 4.8\",\n provider: \"anthropic\",\n contextWindow: 1_000_000,\n maxOutputTokens: 128_000,\n supportsThinking: true,\n supportsImages: true,\n supportsVideo: false,\n costTier: \"high\",\n maxThinkingLevel: \"max\",\n },\n {\n id: \"claude-sonnet-4-6\",\n name: \"Claude Sonnet 4.6\",\n provider: \"anthropic\",\n contextWindow: 1_000_000,\n maxOutputTokens: 64_000,\n supportsThinking: true,\n supportsImages: true,\n supportsVideo: false,\n costTier: \"medium\",\n maxThinkingLevel: \"max\",\n },\n {\n id: \"claude-haiku-4-5-20251001\",\n name: \"Claude Haiku 4.5\",\n provider: \"anthropic\",\n contextWindow: 200_000,\n maxOutputTokens: 64_000,\n supportsThinking: true,\n supportsImages: true,\n supportsVideo: false,\n costTier: \"low\",\n maxThinkingLevel: \"high\",\n },\n // ── OpenAI (Codex) ─────────────────────────────────────\n {\n id: \"gpt-5.5\",\n name: \"GPT-5.5\",\n provider: \"openai\",\n contextWindow: 1_050_000,\n codexContextWindow: 272_000,\n maxOutputTokens: 128_000,\n supportsThinking: true,\n supportsImages: true,\n supportsVideo: false,\n costTier: \"high\",\n maxThinkingLevel: \"xhigh\",\n },\n {\n id: \"gpt-5.4\",\n name: \"GPT-5.4\",\n provider: \"openai\",\n contextWindow: 1_050_000,\n codexContextWindow: 272_000,\n maxOutputTokens: 128_000,\n supportsThinking: true,\n supportsImages: true,\n supportsVideo: false,\n costTier: \"high\",\n maxThinkingLevel: \"xhigh\",\n },\n {\n id: \"gpt-5.4-mini\",\n name: \"GPT-5.4 Mini\",\n provider: \"openai\",\n contextWindow: 400_000,\n maxOutputTokens: 128_000,\n supportsThinking: true,\n supportsImages: true,\n supportsVideo: false,\n costTier: \"low\",\n maxThinkingLevel: \"xhigh\",\n },\n {\n id: \"gpt-5.3-codex\",\n name: \"GPT-5.3 Codex\",\n provider: \"openai\",\n contextWindow: 400_000,\n maxOutputTokens: 128_000,\n supportsThinking: true,\n supportsImages: true,\n supportsVideo: false,\n costTier: \"high\",\n maxThinkingLevel: \"xhigh\",\n },\n // ── Gemini ─────────────────────────────────────────────\n {\n id: \"gemini-3.1-flash-lite-preview\",\n name: \"Gemini 3.1 Flash Lite Preview\",\n provider: \"gemini\",\n contextWindow: 1_048_576,\n maxOutputTokens: 65_536,\n supportsThinking: true,\n supportsImages: true,\n supportsVideo: true,\n maxVideoBytes: 20 * 1024 * 1024,\n costTier: \"low\",\n maxThinkingLevel: \"high\",\n },\n {\n id: \"gemini-3.5-flash\",\n name: \"Gemini 3.5 Flash\",\n provider: \"gemini\",\n contextWindow: 1_048_576,\n maxOutputTokens: 65_536,\n supportsThinking: true,\n supportsImages: true,\n supportsVideo: true,\n maxVideoBytes: 20 * 1024 * 1024,\n costTier: \"low\",\n maxThinkingLevel: \"high\",\n },\n // ── Moonshot (Kimi) ────────────────────────────────────\n {\n id: \"kimi-k2.6\",\n name: \"Kimi K2.6\",\n provider: \"moonshot\",\n contextWindow: 262_144,\n maxOutputTokens: 262_144,\n supportsThinking: true,\n supportsImages: true,\n supportsVideo: true,\n maxVideoBytes: 100 * 1024 * 1024,\n costTier: \"medium\",\n maxThinkingLevel: \"high\",\n },\n // ── Z.AI (GLM) ─────────────────────────────────────────\n {\n id: \"glm-5.1\",\n name: \"GLM-5.1\",\n provider: \"glm\",\n contextWindow: 204_800,\n maxOutputTokens: 131_072,\n supportsThinking: true,\n supportsImages: false,\n supportsVideo: false,\n costTier: \"medium\",\n maxThinkingLevel: \"high\",\n },\n {\n id: \"glm-4.7\",\n name: \"GLM-4.7\",\n provider: \"glm\",\n contextWindow: 200_000,\n maxOutputTokens: 131_072,\n supportsThinking: true,\n supportsImages: false,\n supportsVideo: false,\n costTier: \"low\",\n maxThinkingLevel: \"high\",\n },\n {\n id: \"glm-4.7-flash\",\n name: \"GLM-4.7 Flash\",\n provider: \"glm\",\n contextWindow: 200_000,\n maxOutputTokens: 131_072,\n supportsThinking: true,\n supportsImages: false,\n supportsVideo: false,\n costTier: \"low\",\n maxThinkingLevel: \"high\",\n },\n // ── MiniMax ────────────────────────────────────────────\n {\n id: \"MiniMax-M3\",\n name: \"MiniMax M3\",\n provider: \"minimax\",\n contextWindow: 1_000_000,\n maxOutputTokens: 131_072,\n supportsThinking: true,\n supportsImages: true,\n supportsVideo: true,\n maxVideoBytes: 50 * 1024 * 1024,\n costTier: \"medium\",\n maxThinkingLevel: \"high\",\n },\n // ── Xiaomi (MiMo) ──────────────────────────────────────\n // Pro series: text-only coding/agentic flagship. The legacy mimo-v2-pro\n // auto-routes to v2.5 on 2026-06-01 and is fully deprecated by 2026-06-30.\n {\n id: \"mimo-v2.5-pro\",\n name: \"MiMo-V2.5-Pro\",\n provider: \"xiaomi\",\n contextWindow: 1_000_000,\n maxOutputTokens: 131_072,\n supportsThinking: true,\n supportsImages: false,\n supportsVideo: false,\n costTier: \"medium\",\n maxThinkingLevel: \"high\",\n },\n // Omni series: native full-modal understanding (image + audio + video).\n // Video/image ride the OpenAI-compatible transport as base64 data URLs\n // (`video_url`/`image_url`), which the shared transform already emits.\n {\n id: \"mimo-v2.5\",\n name: \"MiMo-V2.5\",\n provider: \"xiaomi\",\n contextWindow: 1_000_000,\n maxOutputTokens: 131_072,\n supportsThinking: true,\n supportsImages: true,\n supportsVideo: true,\n maxVideoBytes: 36 * 1024 * 1024,\n costTier: \"medium\",\n maxThinkingLevel: \"high\",\n },\n // ── DeepSeek ───────────────────────────────────────────\n {\n id: \"deepseek-v4-pro\",\n name: \"DeepSeek V4 Pro\",\n provider: \"deepseek\",\n contextWindow: 1_048_576,\n maxOutputTokens: 384_000,\n supportsThinking: true,\n supportsImages: false,\n supportsVideo: false,\n costTier: \"high\",\n // DeepSeek V4 maps `xhigh` → its internal `max` tier.\n maxThinkingLevel: \"xhigh\",\n },\n {\n id: \"deepseek-v4-flash\",\n name: \"DeepSeek V4 Flash\",\n provider: \"deepseek\",\n contextWindow: 1_048_576,\n maxOutputTokens: 384_000,\n supportsThinking: true,\n supportsImages: false,\n supportsVideo: false,\n costTier: \"low\",\n maxThinkingLevel: \"xhigh\",\n },\n // ── OpenRouter ─────────────────────────────────────────\n {\n id: \"qwen/qwen3.6-plus\",\n name: \"Qwen3.6-Plus\",\n provider: \"openrouter\",\n contextWindow: 1_000_000,\n maxOutputTokens: 65_536,\n supportsThinking: true,\n supportsImages: false,\n supportsVideo: false,\n costTier: \"medium\",\n maxThinkingLevel: \"high\",\n },\n];\n\nexport function getModel(id: string): ModelInfo | undefined {\n return MODELS.find((m) => m.id === id);\n}\n\nexport function getModelsForProvider(provider: Provider): ModelInfo[] {\n return MODELS.filter((m) => m.provider === provider);\n}\n\n/** Default video payload cap (bytes) when a video model doesn't declare one. */\nexport const DEFAULT_MAX_VIDEO_BYTES = 20 * 1024 * 1024;\n\n/**\n * Max video payload (bytes) the given model's transport accepts before the clip\n * must be compressed. Returns `undefined` for models without video support, so\n * callers can skip the native-video path entirely.\n */\nexport function getVideoByteLimit(modelId: string): number | undefined {\n const model = getModel(modelId);\n if (!model?.supportsVideo) return undefined;\n return model.maxVideoBytes ?? DEFAULT_MAX_VIDEO_BYTES;\n}\n\nexport function getDefaultModel(provider: Provider): ModelInfo {\n if (provider === \"xiaomi\") return MODELS.find((m) => m.id === \"mimo-v2.5-pro\")!;\n if (provider === \"openai\") return MODELS.find((m) => m.id === \"gpt-5.5\")!;\n if (provider === \"gemini\") return MODELS.find((m) => m.id === \"gemini-3.1-flash-lite-preview\")!;\n if (provider === \"glm\") return MODELS.find((m) => m.id === \"glm-5.1\")!;\n if (provider === \"moonshot\") return MODELS.find((m) => m.id === \"kimi-k2.6\")!;\n if (provider === \"minimax\") return MODELS.find((m) => m.id === \"MiniMax-M3\")!;\n if (provider === \"deepseek\") return MODELS.find((m) => m.id === \"deepseek-v4-pro\")!;\n if (provider === \"openrouter\") return MODELS.find((m) => m.id === \"qwen/qwen3.6-plus\")!;\n return MODELS.find((m) => m.id === \"claude-sonnet-4-6\")!;\n}\n\nexport interface ContextWindowOptions {\n provider?: Provider;\n accountId?: string;\n}\n\nexport function usesOpenAICodexTransport(options?: ContextWindowOptions): boolean {\n return options?.provider === \"openai\" && Boolean(options.accountId);\n}\n\nexport function getContextWindow(modelId: string, options?: ContextWindowOptions): number {\n const model = getModel(modelId);\n if (!model) return 200_000;\n if (usesOpenAICodexTransport(options) && model.codexContextWindow) {\n return model.codexContextWindow;\n }\n return model.contextWindow;\n}\n\n/**\n * The strongest thinking level the given model genuinely uses. Falls back to\n * `\"high\"` for unknown models since every provider we ship accepts it.\n */\nexport function getMaxThinkingLevel(modelId: string): ThinkingLevel {\n return getModel(modelId)?.maxThinkingLevel ?? \"high\";\n}\n\n/**\n * Get the model to use for compaction summarization.\n * - Anthropic: always Sonnet 4.6\n * - OpenAI: cheapest (Codex Mini)\n * - Gemini: use the current model\n * - GLM: GLM-4.7 Flash (cheap alternative)\n * - Moonshot: use the current model (no cheap alternative)\n */\nexport function getSummaryModel(provider: Provider, currentModelId: string): ModelInfo {\n if (provider === \"anthropic\") {\n return MODELS.find((m) => m.id === \"claude-sonnet-4-6\")!;\n }\n if (provider === \"openai\" || provider === \"glm\" || provider === \"deepseek\") {\n const low = getModelsForProvider(provider).find((m) => m.costTier === \"low\");\n if (low) return low;\n }\n // Moonshot or fallback: use current model\n return getModel(currentModelId) ?? getDefaultModel(provider);\n}\n"],"mappings":"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","names":[]}
package/dist/index.cjs CHANGED
@@ -31,7 +31,9 @@ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: tru
31
31
  var index_exports = {};
32
32
  __export(index_exports, {
33
33
  AuthStorage: () => AuthStorage,
34
+ DEFAULT_MAX_VIDEO_BYTES: () => DEFAULT_MAX_VIDEO_BYTES,
34
35
  MODELS: () => MODELS,
36
+ MOONSHOT_OAUTH_KEY: () => MOONSHOT_OAUTH_KEY,
35
37
  NotLoggedInError: () => NotLoggedInError,
36
38
  TelegramBot: () => TelegramBot,
37
39
  closeLogger: () => closeLogger,
@@ -51,16 +53,22 @@ __export(index_exports, {
51
53
  getSessionId: () => getSessionId,
52
54
  getSummaryModel: () => getSummaryModel,
53
55
  getSupportedThinkingLevels: () => getSupportedThinkingLevels,
56
+ getVideoByteLimit: () => getVideoByteLimit,
57
+ isKimiCodingEndpoint: () => isKimiCodingEndpoint,
54
58
  isLoggerOpen: () => isLoggerOpen,
55
59
  isModelLoaded: () => isModelLoaded,
56
60
  isThinkingLevelSupported: () => isThinkingLevelSupported,
61
+ kimiCodeBaseUrl: () => kimiCodeBaseUrl,
62
+ kimiCodingHeaders: () => kimiCodingHeaders,
57
63
  log: () => log,
58
64
  loginAnthropic: () => loginAnthropic,
59
65
  loginGemini: () => loginGemini,
66
+ loginKimi: () => loginKimi,
60
67
  loginOpenAI: () => loginOpenAI,
61
68
  openLog: () => openLog,
62
69
  refreshAnthropicToken: () => refreshAnthropicToken,
63
70
  refreshGeminiToken: () => refreshGeminiToken,
71
+ refreshKimiToken: () => refreshKimiToken,
64
72
  refreshOpenAIToken: () => refreshOpenAIToken,
65
73
  registerLogCleanup: () => registerLogCleanup,
66
74
  resample: () => resample,
@@ -171,6 +179,7 @@ var MODELS = [
171
179
  supportsThinking: true,
172
180
  supportsImages: true,
173
181
  supportsVideo: true,
182
+ maxVideoBytes: 20 * 1024 * 1024,
174
183
  costTier: "low",
175
184
  maxThinkingLevel: "high"
176
185
  },
@@ -183,6 +192,7 @@ var MODELS = [
183
192
  supportsThinking: true,
184
193
  supportsImages: true,
185
194
  supportsVideo: true,
195
+ maxVideoBytes: 20 * 1024 * 1024,
186
196
  costTier: "low",
187
197
  maxThinkingLevel: "high"
188
198
  },
@@ -196,6 +206,7 @@ var MODELS = [
196
206
  supportsThinking: true,
197
207
  supportsImages: true,
198
208
  supportsVideo: true,
209
+ maxVideoBytes: 100 * 1024 * 1024,
199
210
  costTier: "medium",
200
211
  maxThinkingLevel: "high"
201
212
  },
@@ -246,13 +257,16 @@ var MODELS = [
246
257
  supportsThinking: true,
247
258
  supportsImages: true,
248
259
  supportsVideo: true,
260
+ maxVideoBytes: 50 * 1024 * 1024,
249
261
  costTier: "medium",
250
262
  maxThinkingLevel: "high"
251
263
  },
252
264
  // ── Xiaomi (MiMo) ──────────────────────────────────────
265
+ // Pro series: text-only coding/agentic flagship. The legacy mimo-v2-pro
266
+ // auto-routes to v2.5 on 2026-06-01 and is fully deprecated by 2026-06-30.
253
267
  {
254
- id: "mimo-v2-pro",
255
- name: "MiMo-V2-Pro",
268
+ id: "mimo-v2.5-pro",
269
+ name: "MiMo-V2.5-Pro",
256
270
  provider: "xiaomi",
257
271
  contextWindow: 1e6,
258
272
  maxOutputTokens: 131072,
@@ -262,6 +276,22 @@ var MODELS = [
262
276
  costTier: "medium",
263
277
  maxThinkingLevel: "high"
264
278
  },
279
+ // Omni series: native full-modal understanding (image + audio + video).
280
+ // Video/image ride the OpenAI-compatible transport as base64 data URLs
281
+ // (`video_url`/`image_url`), which the shared transform already emits.
282
+ {
283
+ id: "mimo-v2.5",
284
+ name: "MiMo-V2.5",
285
+ provider: "xiaomi",
286
+ contextWindow: 1e6,
287
+ maxOutputTokens: 131072,
288
+ supportsThinking: true,
289
+ supportsImages: true,
290
+ supportsVideo: true,
291
+ maxVideoBytes: 36 * 1024 * 1024,
292
+ costTier: "medium",
293
+ maxThinkingLevel: "high"
294
+ },
265
295
  // ── DeepSeek ───────────────────────────────────────────
266
296
  {
267
297
  id: "deepseek-v4-pro",
@@ -308,8 +338,14 @@ function getModel(id) {
308
338
  function getModelsForProvider(provider) {
309
339
  return MODELS.filter((m) => m.provider === provider);
310
340
  }
341
+ var DEFAULT_MAX_VIDEO_BYTES = 20 * 1024 * 1024;
342
+ function getVideoByteLimit(modelId) {
343
+ const model = getModel(modelId);
344
+ if (!model?.supportsVideo) return void 0;
345
+ return model.maxVideoBytes ?? DEFAULT_MAX_VIDEO_BYTES;
346
+ }
311
347
  function getDefaultModel(provider) {
312
- if (provider === "xiaomi") return MODELS.find((m) => m.id === "mimo-v2-pro");
348
+ if (provider === "xiaomi") return MODELS.find((m) => m.id === "mimo-v2.5-pro");
313
349
  if (provider === "openai") return MODELS.find((m) => m.id === "gpt-5.5");
314
350
  if (provider === "gemini") return MODELS.find((m) => m.id === "gemini-3.1-flash-lite-preview");
315
351
  if (provider === "glm") return MODELS.find((m) => m.id === "glm-5.1");
@@ -648,7 +684,7 @@ async function getClaudeCliUserAgent() {
648
684
 
649
685
  // src/auth-storage.ts
650
686
  var import_promises4 = __toESM(require("fs/promises"), 1);
651
- var import_node_crypto5 = __toESM(require("crypto"), 1);
687
+ var import_node_crypto6 = __toESM(require("crypto"), 1);
652
688
 
653
689
  // src/oauth/anthropic.ts
654
690
  var import_node_crypto2 = __toESM(require("crypto"), 1);
@@ -1303,7 +1339,232 @@ function codeAssistHeaders(accessToken) {
1303
1339
  };
1304
1340
  }
1305
1341
 
1342
+ // src/oauth/kimi.ts
1343
+ var import_node_child_process = require("child_process");
1344
+ var import_node_crypto5 = require("crypto");
1345
+ var import_node_fs2 = require("fs");
1346
+ var import_node_os2 = require("os");
1347
+ var import_node_path4 = __toESM(require("path"), 1);
1348
+ var CLIENT_ID3 = "17e5f671-d194-4dfb-9706-5516cb48c098";
1349
+ var DEFAULT_OAUTH_HOST = "https://auth.kimi.com";
1350
+ var DEFAULT_CODING_BASE_URL = "https://api.kimi.com/coding/v1";
1351
+ var KIMI_PLATFORM = "kimi_code_cli";
1352
+ var DEFAULT_KIMI_VERSION = "1.0.11";
1353
+ var DEVICE_TIMEOUT_MS = 15 * 60 * 1e3;
1354
+ function oauthHost() {
1355
+ const host = process.env.KIMI_CODE_OAUTH_HOST ?? process.env.KIMI_OAUTH_HOST ?? DEFAULT_OAUTH_HOST;
1356
+ return host.replace(/\/+$/, "");
1357
+ }
1358
+ function kimiCodeBaseUrl() {
1359
+ return (process.env.KIMI_CODE_BASE_URL ?? DEFAULT_CODING_BASE_URL).replace(/\/+$/, "");
1360
+ }
1361
+ function kimiVersion() {
1362
+ const v = process.env.KIMI_CODE_VERSION ?? DEFAULT_KIMI_VERSION;
1363
+ return asciiHeader(v, DEFAULT_KIMI_VERSION);
1364
+ }
1365
+ function asciiHeader(value, fallback = "unknown") {
1366
+ const cleaned = value.replace(/[^\u0020-\u007E]/g, "").trim();
1367
+ return cleaned.length > 0 ? cleaned : fallback;
1368
+ }
1369
+ function macOsProductVersion() {
1370
+ try {
1371
+ const version = (0, import_node_child_process.execFileSync)("/usr/bin/sw_vers", ["-productVersion"], {
1372
+ encoding: "utf-8",
1373
+ timeout: 1e3
1374
+ }).trim();
1375
+ return version.length > 0 ? version : void 0;
1376
+ } catch {
1377
+ return void 0;
1378
+ }
1379
+ }
1380
+ function deviceModel() {
1381
+ const os2 = (0, import_node_os2.type)();
1382
+ const version = (0, import_node_os2.release)();
1383
+ const osArch = (0, import_node_os2.arch)();
1384
+ if (os2 === "Darwin") return `macOS ${macOsProductVersion() ?? version} ${osArch}`;
1385
+ if (os2 === "Windows_NT") return `Windows ${version} ${osArch}`;
1386
+ return `${os2} ${version} ${osArch}`.trim();
1387
+ }
1388
+ function deviceId() {
1389
+ const idPath = import_node_path4.default.join(getAppPaths().agentDir, "kimi_device_id");
1390
+ if ((0, import_node_fs2.existsSync)(idPath)) {
1391
+ try {
1392
+ const text = (0, import_node_fs2.readFileSync)(idPath, "utf-8").trim();
1393
+ if (text.length > 0) return text;
1394
+ } catch {
1395
+ }
1396
+ }
1397
+ const id = (0, import_node_crypto5.randomUUID)();
1398
+ try {
1399
+ (0, import_node_fs2.mkdirSync)(getAppPaths().agentDir, { recursive: true, mode: 448 });
1400
+ (0, import_node_fs2.writeFileSync)(idPath, id, { encoding: "utf-8", mode: 384 });
1401
+ } catch {
1402
+ }
1403
+ return id;
1404
+ }
1405
+ function deviceHeaders() {
1406
+ return {
1407
+ "X-Msh-Platform": KIMI_PLATFORM,
1408
+ "X-Msh-Version": kimiVersion(),
1409
+ "X-Msh-Device-Name": asciiHeader((0, import_node_os2.hostname)()),
1410
+ "X-Msh-Device-Model": asciiHeader(deviceModel()),
1411
+ "X-Msh-Os-Version": asciiHeader((0, import_node_os2.release)()),
1412
+ "X-Msh-Device-Id": deviceId()
1413
+ };
1414
+ }
1415
+ function kimiCodingHeaders() {
1416
+ return {
1417
+ "User-Agent": `kimi-code-cli/${kimiVersion()}`,
1418
+ ...deviceHeaders()
1419
+ };
1420
+ }
1421
+ function isKimiCodingEndpoint(baseUrl) {
1422
+ if (typeof baseUrl !== "string" || baseUrl.length === 0) return false;
1423
+ const normalized = baseUrl.replace(/\/+$/, "");
1424
+ return normalized === kimiCodeBaseUrl() || /(^|\.)kimi\.com/i.test(normalized);
1425
+ }
1426
+ async function postForm(endpoint, params) {
1427
+ const response = await fetch(`${oauthHost()}${endpoint}`, {
1428
+ method: "POST",
1429
+ headers: {
1430
+ ...deviceHeaders(),
1431
+ "Content-Type": "application/x-www-form-urlencoded",
1432
+ Accept: "application/json"
1433
+ },
1434
+ body: new URLSearchParams(params).toString()
1435
+ });
1436
+ let data = {};
1437
+ try {
1438
+ const parsed = await response.json();
1439
+ if (parsed && typeof parsed === "object") data = parsed;
1440
+ } catch {
1441
+ }
1442
+ return { status: response.status, data };
1443
+ }
1444
+ function errorDetail(data) {
1445
+ const desc = data.error_description ?? data.message ?? data.error;
1446
+ return typeof desc === "string" && desc.length > 0 ? desc : "unknown error";
1447
+ }
1448
+ function credsFromTokenResponse(data) {
1449
+ const accessToken = data.access_token;
1450
+ const refreshToken = data.refresh_token;
1451
+ const expiresIn = Number(data.expires_in);
1452
+ if (typeof accessToken !== "string" || accessToken.length === 0) {
1453
+ throw new Error("Kimi OAuth response missing access_token.");
1454
+ }
1455
+ if (typeof refreshToken !== "string" || refreshToken.length === 0) {
1456
+ throw new Error("Kimi OAuth response missing refresh_token.");
1457
+ }
1458
+ if (!Number.isFinite(expiresIn) || expiresIn <= 0) {
1459
+ throw new Error("Kimi OAuth response missing or invalid expires_in.");
1460
+ }
1461
+ return {
1462
+ accessToken,
1463
+ refreshToken,
1464
+ expiresAt: Date.now() + expiresIn * 1e3,
1465
+ baseUrl: kimiCodeBaseUrl()
1466
+ };
1467
+ }
1468
+ async function requestDeviceAuthorization() {
1469
+ const { status, data } = await postForm("/api/oauth/device_authorization", {
1470
+ client_id: CLIENT_ID3
1471
+ });
1472
+ if (status !== 200) {
1473
+ throw new Error(`Kimi device authorization failed (${status}): ${errorDetail(data)}`);
1474
+ }
1475
+ const userCode = data.user_code;
1476
+ const deviceCode = data.device_code;
1477
+ const verificationUriComplete = data.verification_uri_complete;
1478
+ if (typeof userCode !== "string" || typeof deviceCode !== "string") {
1479
+ throw new Error("Kimi device authorization response missing user_code/device_code.");
1480
+ }
1481
+ return {
1482
+ userCode,
1483
+ deviceCode,
1484
+ verificationUri: typeof data.verification_uri === "string" ? data.verification_uri : "",
1485
+ verificationUriComplete: typeof verificationUriComplete === "string" ? verificationUriComplete : "",
1486
+ interval: Number(data.interval ?? 5) || 5
1487
+ };
1488
+ }
1489
+ async function pollDeviceToken(deviceCode) {
1490
+ const { status, data } = await postForm("/api/oauth/token", {
1491
+ client_id: CLIENT_ID3,
1492
+ device_code: deviceCode,
1493
+ grant_type: "urn:ietf:params:oauth:grant-type:device_code"
1494
+ });
1495
+ if (status === 200 && typeof data.access_token === "string") {
1496
+ return { kind: "success", creds: credsFromTokenResponse(data) };
1497
+ }
1498
+ if (status >= 500) {
1499
+ throw new Error(`Kimi token polling server error (${status}): ${errorDetail(data)}`);
1500
+ }
1501
+ const errorCode = typeof data.error === "string" ? data.error : "unknown_error";
1502
+ switch (errorCode) {
1503
+ case "authorization_pending":
1504
+ return { kind: "pending" };
1505
+ case "slow_down":
1506
+ return { kind: "slow_down" };
1507
+ case "expired_token":
1508
+ return { kind: "expired" };
1509
+ case "access_denied":
1510
+ return { kind: "denied" };
1511
+ default:
1512
+ throw new Error(`Kimi token polling failed (${status}): ${errorDetail(data)}`);
1513
+ }
1514
+ }
1515
+ function sleep(ms) {
1516
+ return new Promise((resolve) => {
1517
+ setTimeout(resolve, ms);
1518
+ });
1519
+ }
1520
+ async function loginKimi(callbacks) {
1521
+ const auth = await requestDeviceAuthorization();
1522
+ callbacks.onStatus(
1523
+ `Visit ${auth.verificationUri || auth.verificationUriComplete} and enter code: ${auth.userCode}`
1524
+ );
1525
+ callbacks.onOpenUrl(auth.verificationUriComplete || auth.verificationUri);
1526
+ callbacks.onStatus("Waiting for you to authorize in the browser...");
1527
+ const deadline = Date.now() + DEVICE_TIMEOUT_MS;
1528
+ let interval = Math.max(auth.interval, 1);
1529
+ while (Date.now() < deadline) {
1530
+ await sleep(interval * 1e3);
1531
+ const result = await pollDeviceToken(auth.deviceCode);
1532
+ if (result.kind === "success") return result.creds;
1533
+ if (result.kind === "denied") {
1534
+ throw new Error("Kimi authorization was denied.");
1535
+ }
1536
+ if (result.kind === "expired") {
1537
+ throw new Error("Kimi device code expired. Please run login again.");
1538
+ }
1539
+ if (result.kind === "slow_down") {
1540
+ interval += 5;
1541
+ }
1542
+ }
1543
+ throw new Error("Kimi login timed out. Please run login again.");
1544
+ }
1545
+ async function refreshKimiToken(refreshToken) {
1546
+ const { status, data } = await postForm("/api/oauth/token", {
1547
+ client_id: CLIENT_ID3,
1548
+ grant_type: "refresh_token",
1549
+ refresh_token: refreshToken
1550
+ });
1551
+ if (status === 200 && typeof data.access_token === "string") {
1552
+ return credsFromTokenResponse(data);
1553
+ }
1554
+ const errorCode = typeof data.error === "string" ? data.error : "";
1555
+ throw new Error(`Kimi token refresh failed (${status}): ${errorCode || errorDetail(data)}`);
1556
+ }
1557
+
1306
1558
  // src/auth-storage.ts
1559
+ var MOONSHOT_OAUTH_KEY = "moonshot-oauth";
1560
+ var STATIC_API_KEY_PROVIDERS = /* @__PURE__ */ new Set([
1561
+ "glm",
1562
+ "moonshot",
1563
+ "xiaomi",
1564
+ "minimax",
1565
+ "deepseek",
1566
+ "openrouter"
1567
+ ]);
1307
1568
  var AuthStorage = class {
1308
1569
  data = {};
1309
1570
  filePath;
@@ -1327,6 +1588,30 @@ var AuthStorage = class {
1327
1588
  await this.ensureLoaded();
1328
1589
  return Boolean(this.data[provider]);
1329
1590
  }
1591
+ /**
1592
+ * True if the user has any usable auth for the logical provider. For
1593
+ * `moonshot` this is satisfied by either the Kimi OAuth credential or the
1594
+ * Moonshot API key.
1595
+ */
1596
+ async hasProviderAuth(provider) {
1597
+ await this.ensureLoaded();
1598
+ if (provider === "moonshot") {
1599
+ return Boolean(this.data[MOONSHOT_OAUTH_KEY] || this.data["moonshot"]);
1600
+ }
1601
+ return Boolean(this.data[provider]);
1602
+ }
1603
+ /**
1604
+ * True if the active credential for `provider` is a static API key with no
1605
+ * refresh mechanism. For `moonshot` this is only true when the Kimi OAuth
1606
+ * credential is absent (a present OAuth credential is refreshable).
1607
+ */
1608
+ async isStaticApiKey(provider) {
1609
+ await this.ensureLoaded();
1610
+ if (provider === "moonshot" && this.data[MOONSHOT_OAUTH_KEY]) {
1611
+ return false;
1612
+ }
1613
+ return STATIC_API_KEY_PROVIDERS.has(provider);
1614
+ }
1330
1615
  async load() {
1331
1616
  await withFileLock(this.filePath, async () => {
1332
1617
  try {
@@ -1381,11 +1666,21 @@ var AuthStorage = class {
1381
1666
  */
1382
1667
  async resolveCredentials(provider, opts) {
1383
1668
  await this.ensureLoaded();
1669
+ if (provider === "moonshot" && this.data[MOONSHOT_OAUTH_KEY]) {
1670
+ try {
1671
+ return await this.resolveCredentials(MOONSHOT_OAUTH_KEY, opts);
1672
+ } catch (err) {
1673
+ if (err instanceof NotLoggedInError && this.data["moonshot"]) {
1674
+ return this.data["moonshot"];
1675
+ }
1676
+ throw err;
1677
+ }
1678
+ }
1384
1679
  const creds = this.data[provider];
1385
1680
  if (!creds) {
1386
1681
  throw new NotLoggedInError(provider);
1387
1682
  }
1388
- if (provider === "glm" || provider === "moonshot" || provider === "xiaomi" || provider === "minimax" || provider === "deepseek" || provider === "openrouter") {
1683
+ if (STATIC_API_KEY_PROVIDERS.has(provider)) {
1389
1684
  return creds;
1390
1685
  }
1391
1686
  if (!opts?.forceRefresh && Date.now() < creds.expiresAt) {
@@ -1404,7 +1699,7 @@ var AuthStorage = class {
1404
1699
  }
1405
1700
  } catch {
1406
1701
  }
1407
- const refreshFn = provider === "anthropic" ? refreshAnthropicToken : provider === "gemini" ? refreshGeminiToken : refreshOpenAIToken;
1702
+ const refreshFn = provider === "anthropic" ? refreshAnthropicToken : provider === "gemini" ? refreshGeminiToken : provider === MOONSHOT_OAUTH_KEY ? refreshKimiToken : refreshOpenAIToken;
1408
1703
  let refreshed;
1409
1704
  try {
1410
1705
  refreshed = await refreshFn(creds.refreshToken);
@@ -1450,7 +1745,7 @@ var AuthStorage = class {
1450
1745
  }
1451
1746
  };
1452
1747
  async function atomicWriteFile(filePath, content) {
1453
- const tmpPath = `${filePath}.${process.pid}.${Date.now()}.${import_node_crypto5.default.randomUUID().slice(0, 8)}.tmp`;
1748
+ const tmpPath = `${filePath}.${process.pid}.${Date.now()}.${import_node_crypto6.default.randomUUID().slice(0, 8)}.tmp`;
1454
1749
  try {
1455
1750
  await import_promises4.default.writeFile(tmpPath, content, { encoding: "utf-8", mode: 384 });
1456
1751
  await import_promises4.default.rename(tmpPath, filePath);
@@ -1522,7 +1817,7 @@ var TelegramBot = class {
1522
1817
  } catch (err) {
1523
1818
  if (!this.running) break;
1524
1819
  console.error(`[telegram] Poll error: ${err instanceof Error ? err.message : err}`);
1525
- await sleep(3e3);
1820
+ await sleep2(3e3);
1526
1821
  }
1527
1822
  }
1528
1823
  }
@@ -1692,7 +1987,7 @@ function splitMessage(text) {
1692
1987
  }
1693
1988
  return chunks;
1694
1989
  }
1695
- function sleep(ms) {
1990
+ function sleep2(ms) {
1696
1991
  return new Promise((r) => setTimeout(r, ms));
1697
1992
  }
1698
1993
 
@@ -1777,9 +2072,9 @@ async function transcribeVoice(fileUrl) {
1777
2072
  }
1778
2073
 
1779
2074
  // src/auto-update.ts
1780
- var import_node_child_process = require("child_process");
1781
- var import_node_fs2 = __toESM(require("fs"), 1);
1782
- var import_node_path4 = __toESM(require("path"), 1);
2075
+ var import_node_child_process2 = require("child_process");
2076
+ var import_node_fs3 = __toESM(require("fs"), 1);
2077
+ var import_node_path5 = __toESM(require("path"), 1);
1783
2078
  var CHECK_INTERVAL_MS = 60 * 60 * 1e3;
1784
2079
  var FETCH_TIMEOUT_MS2 = 1e4;
1785
2080
  function compareVersions(a, b) {
@@ -1794,7 +2089,7 @@ function compareVersions(a, b) {
1794
2089
  function performUpdateInBackground(command) {
1795
2090
  try {
1796
2091
  const parts = command.split(" ");
1797
- const child = (0, import_node_child_process.spawn)(parts[0], parts.slice(1), {
2092
+ const child = (0, import_node_child_process2.spawn)(parts[0], parts.slice(1), {
1798
2093
  detached: true,
1799
2094
  stdio: "ignore",
1800
2095
  env: { ...process.env, npm_config_loglevel: "silent" }
@@ -1812,7 +2107,7 @@ function createAutoUpdater(config) {
1812
2107
  }
1813
2108
  function readState() {
1814
2109
  try {
1815
- const raw = import_node_fs2.default.readFileSync(stateFilePath(), "utf-8");
2110
+ const raw = import_node_fs3.default.readFileSync(stateFilePath(), "utf-8");
1816
2111
  return JSON.parse(raw);
1817
2112
  } catch {
1818
2113
  return null;
@@ -1821,8 +2116,8 @@ function createAutoUpdater(config) {
1821
2116
  function writeState(state) {
1822
2117
  try {
1823
2118
  const filePath = stateFilePath();
1824
- import_node_fs2.default.mkdirSync(import_node_path4.default.dirname(filePath), { recursive: true, mode: 448 });
1825
- import_node_fs2.default.writeFileSync(filePath, JSON.stringify(state));
2119
+ import_node_fs3.default.mkdirSync(import_node_path5.default.dirname(filePath), { recursive: true, mode: 448 });
2120
+ import_node_fs3.default.writeFileSync(filePath, JSON.stringify(state));
1826
2121
  } catch {
1827
2122
  }
1828
2123
  }
@@ -1947,7 +2242,9 @@ function createAutoUpdater(config) {
1947
2242
  // Annotate the CommonJS export names for ESM import in node:
1948
2243
  0 && (module.exports = {
1949
2244
  AuthStorage,
2245
+ DEFAULT_MAX_VIDEO_BYTES,
1950
2246
  MODELS,
2247
+ MOONSHOT_OAUTH_KEY,
1951
2248
  NotLoggedInError,
1952
2249
  TelegramBot,
1953
2250
  closeLogger,
@@ -1967,16 +2264,22 @@ function createAutoUpdater(config) {
1967
2264
  getSessionId,
1968
2265
  getSummaryModel,
1969
2266
  getSupportedThinkingLevels,
2267
+ getVideoByteLimit,
2268
+ isKimiCodingEndpoint,
1970
2269
  isLoggerOpen,
1971
2270
  isModelLoaded,
1972
2271
  isThinkingLevelSupported,
2272
+ kimiCodeBaseUrl,
2273
+ kimiCodingHeaders,
1973
2274
  log,
1974
2275
  loginAnthropic,
1975
2276
  loginGemini,
2277
+ loginKimi,
1976
2278
  loginOpenAI,
1977
2279
  openLog,
1978
2280
  refreshAnthropicToken,
1979
2281
  refreshGeminiToken,
2282
+ refreshKimiToken,
1980
2283
  refreshOpenAIToken,
1981
2284
  registerLogCleanup,
1982
2285
  resample,