mu-agent 0.1.4 → 0.1.6

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.
Files changed (120) hide show
  1. package/CHANGELOG.md +53 -0
  2. package/README.md +7 -3
  3. package/dist/bundle/chunks/anthropic-messages-VMESUHQ7.js +6 -0
  4. package/dist/bundle/chunks/azure-openai-responses-K232MQFF.js +2 -0
  5. package/dist/bundle/chunks/bedrock-converse-stream.js +2 -2
  6. package/dist/bundle/chunks/chunk-2X3AO33C.js +2 -0
  7. package/dist/bundle/chunks/{chunk-FUXEF6JQ.js → chunk-4O2SCVYF.js} +1 -1
  8. package/dist/bundle/chunks/chunk-E3TC4YNV.js +2 -0
  9. package/dist/bundle/chunks/chunk-FU4XQUSL.js +11 -0
  10. package/dist/bundle/chunks/{chunk-S7SZN6Z3.js → chunk-GNYZK6XN.js} +1 -1
  11. package/dist/bundle/chunks/chunk-MVPXOVOJ.js +2 -0
  12. package/dist/bundle/chunks/{chunk-XOBBIK6P.js → chunk-TUBB3BLE.js} +71 -64
  13. package/dist/bundle/chunks/chunk-UTB4DTYQ.js +2 -0
  14. package/dist/bundle/chunks/{chunk-WIUZI2CJ.js → chunk-V7IXECST.js} +2 -2
  15. package/dist/bundle/chunks/cloudflare-workers-ai-system-one-NR2TDCXU.js +2 -0
  16. package/dist/bundle/chunks/github-copilot.js +1 -1
  17. package/dist/bundle/chunks/google-generative-ai-C44KRRZ4.js +2 -0
  18. package/dist/bundle/chunks/google-vertex-25DUXPTJ.js +2 -0
  19. package/dist/bundle/chunks/meta.js +2 -0
  20. package/dist/bundle/chunks/mistral-conversations-6IHQOR4R.js +5 -0
  21. package/dist/bundle/chunks/{openai-codex-responses-QDSOTBBO.js → openai-codex-responses-3UAYOSSR.js} +2 -2
  22. package/dist/bundle/chunks/{openai-completions-KQPOPEVM.js → openai-completions-FIEQGWAH.js} +3 -3
  23. package/dist/bundle/chunks/openai-responses-OZJXLHFC.js +2 -0
  24. package/dist/bundle/chunks/{openrouter-images-N4XVVFSD.js → openrouter-images-JVEJN44Q.js} +1 -1
  25. package/dist/bundle/chunks/{pi-messages-GFKBWJHZ.js → pi-messages-TM5SOOIW.js} +2 -2
  26. package/dist/bundle/chunks/typesafe-system-one-VKYX4OGY.js +2 -0
  27. package/dist/bundle/chunks/{virtual-modules-MYFARBUK.js → virtual-modules-IOLJJ5KK.js} +1 -1
  28. package/dist/bundle/cli-runtime.js +3 -0
  29. package/dist/bundle/cli.js +4 -2
  30. package/dist/bundle/index.js +1 -1
  31. package/dist/bundle/rpc-entry.js +1 -1
  32. package/dist/core/export-html/template.css +10 -0
  33. package/dist/core/export-html/template.js +56 -18
  34. package/dist/modes/interactive/theme/theme-controller.d.ts +6 -0
  35. package/dist/modes/interactive/theme/theme-controller.d.ts.map +1 -1
  36. package/dist/modes/interactive/theme/theme-controller.js +41 -3
  37. package/dist/modes/interactive/theme/theme-controller.js.map +1 -1
  38. package/dist/modes/interactive/theme/theme-json.d.ts +1 -0
  39. package/dist/modes/interactive/theme/theme-json.d.ts.map +1 -1
  40. package/dist/modes/interactive/theme/theme-json.js +3 -1
  41. package/dist/modes/interactive/theme/theme-json.js.map +1 -1
  42. package/dist/modes/interactive/theme/theme-schema.json +7 -2
  43. package/dist/modes/interactive/theme/theme.d.ts +40 -7
  44. package/dist/modes/interactive/theme/theme.d.ts.map +1 -1
  45. package/dist/modes/interactive/theme/theme.js +122 -214
  46. package/dist/modes/interactive/theme/theme.js.map +1 -1
  47. package/docs/cli-integration.md +106 -0
  48. package/docs/cli.md +268 -0
  49. package/docs/compaction.md +45 -26
  50. package/docs/configuration.md +45 -0
  51. package/docs/containerization.md +109 -82
  52. package/docs/custom-provider.md +109 -722
  53. package/docs/docs.json +139 -99
  54. package/docs/environment-variables.md +3 -5
  55. package/docs/extensions.md +137 -2953
  56. package/docs/how-pi-works.md +49 -0
  57. package/docs/images/interactive-mode.png +0 -0
  58. package/docs/index.md +24 -69
  59. package/docs/json.md +193 -65
  60. package/docs/keybindings.md +57 -102
  61. package/docs/llama-cpp.md +3 -3
  62. package/docs/message-types.md +261 -0
  63. package/docs/models.md +64 -546
  64. package/docs/packages.md +67 -166
  65. package/docs/prompt-templates.md +31 -68
  66. package/docs/providers.md +102 -232
  67. package/docs/quickstart.md +61 -106
  68. package/docs/rpc-commands.md +854 -0
  69. package/docs/rpc-extension-ui.md +200 -0
  70. package/docs/rpc.md +129 -1556
  71. package/docs/sdk.md +76 -1160
  72. package/docs/security.md +70 -32
  73. package/docs/session-format.md +25 -216
  74. package/docs/sessions.md +35 -141
  75. package/docs/settings.md +109 -387
  76. package/docs/shell-aliases.md +85 -5
  77. package/docs/skills.md +51 -190
  78. package/docs/slash-commands.md +60 -0
  79. package/docs/terminal-setup.md +105 -78
  80. package/docs/termux.md +74 -83
  81. package/docs/themes.md +71 -279
  82. package/docs/tmux.md +31 -39
  83. package/docs/tui.md +74 -910
  84. package/docs/usage.md +54 -272
  85. package/docs/windows.md +43 -17
  86. package/examples/README.md +13 -2
  87. package/examples/extensions/README.md +1 -0
  88. package/examples/extensions/custom-provider-anthropic/package-lock.json +2 -2
  89. package/examples/extensions/custom-provider-anthropic/package.json +1 -1
  90. package/examples/extensions/custom-provider-gitlab-duo/package.json +1 -1
  91. package/examples/extensions/debug-provider.ts +90 -0
  92. package/examples/extensions/gondolin/package-lock.json +2 -2
  93. package/examples/extensions/gondolin/package.json +1 -1
  94. package/examples/extensions/sandbox/package-lock.json +2 -2
  95. package/examples/extensions/sandbox/package.json +1 -1
  96. package/examples/extensions/with-deps/package-lock.json +2 -2
  97. package/examples/extensions/with-deps/package.json +1 -1
  98. package/examples/plugins/pi-example-plugin/src/session.ts +3 -2
  99. package/examples/rpc-client.ts +35 -0
  100. package/examples/rpc-extension-ui.ts +25 -5
  101. package/examples/sdk/README.md +1 -1
  102. package/judge/dist/auth.js +166 -28
  103. package/judge/dist/chrome.js +12 -1
  104. package/judge/dist/kyrn-judge.js +1424 -589
  105. package/judge/dist/setup.js +2051 -0
  106. package/judge/manifest.json +13 -13
  107. package/judge/skills/mu-browser/SKILL.md +1 -0
  108. package/kyrn/bin/kyrn-doctor +107 -18
  109. package/kyrn/bin/mu.mjs +293 -17
  110. package/package.json +4 -4
  111. package/dist/bundle/chunks/anthropic-messages-MYU5ZMRF.js +0 -6
  112. package/dist/bundle/chunks/azure-openai-responses-HUSQ3GP2.js +0 -2
  113. package/dist/bundle/chunks/chunk-6R7UI4IY.js +0 -2
  114. package/dist/bundle/chunks/chunk-CK5Z65DM.js +0 -2
  115. package/dist/bundle/chunks/chunk-RCZIEVGO.js +0 -11
  116. package/dist/bundle/chunks/google-generative-ai-IMS5EK2Y.js +0 -2
  117. package/dist/bundle/chunks/google-vertex-O4YJEQUW.js +0 -2
  118. package/dist/bundle/chunks/mistral-conversations-NOSQHBEY.js +0 -5
  119. package/dist/bundle/chunks/openai-responses-HWEUZ6WZ.js +0 -2
  120. package/docs/development.md +0 -90
@@ -1,12 +1,12 @@
1
1
  {
2
2
  "name": "pi-extension-sandbox",
3
- "version": "1.16.0",
3
+ "version": "1.17.1",
4
4
  "lockfileVersion": 3,
5
5
  "requires": true,
6
6
  "packages": {
7
7
  "": {
8
8
  "name": "pi-extension-sandbox",
9
- "version": "1.16.0",
9
+ "version": "1.17.1",
10
10
  "dependencies": {
11
11
  "@anthropic-ai/sandbox-runtime": "^0.0.26"
12
12
  }
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "pi-extension-sandbox",
3
3
  "private": true,
4
- "version": "1.16.0",
4
+ "version": "1.17.1",
5
5
  "type": "module",
6
6
  "scripts": {
7
7
  "clean": "echo 'nothing to clean'",
@@ -1,12 +1,12 @@
1
1
  {
2
2
  "name": "pi-extension-with-deps",
3
- "version": "0.86.0",
3
+ "version": "0.87.1",
4
4
  "lockfileVersion": 3,
5
5
  "requires": true,
6
6
  "packages": {
7
7
  "": {
8
8
  "name": "pi-extension-with-deps",
9
- "version": "0.86.0",
9
+ "version": "0.87.1",
10
10
  "dependencies": {
11
11
  "ms": "^2.1.3"
12
12
  },
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "pi-extension-with-deps",
3
3
  "private": true,
4
- "version": "0.86.0",
4
+ "version": "0.87.1",
5
5
  "type": "module",
6
6
  "scripts": {
7
7
  "clean": "echo 'nothing to clean'",
@@ -16,8 +16,9 @@ export default defineFacet({
16
16
  },
17
17
  });
18
18
  env.onActivate(() => {
19
- workerActivations.state.count += 1;
20
- workerActivations.publish(BACKGROUND_CONTEXT);
19
+ workerActivations.change(BACKGROUND_CONTEXT, (draft) => {
20
+ draft.count += 1;
21
+ });
21
22
  });
22
23
  },
23
24
  });
@@ -0,0 +1,35 @@
1
+ /**
2
+ * Run one prompt through a Pi RPC child process.
3
+ *
4
+ * Build the coding-agent package first, then run:
5
+ * npx tsx examples/rpc-client.ts "Explain this repository"
6
+ */
7
+
8
+ import { dirname, join } from "node:path";
9
+ import { fileURLToPath } from "node:url";
10
+ import { RpcClient } from "@earendil-works/pi-coding-agent";
11
+
12
+ const exampleDirectory = dirname(fileURLToPath(import.meta.url));
13
+ const prompt = process.argv.slice(2).join(" ") || "Explain this repository in one paragraph.";
14
+
15
+ const client = new RpcClient({
16
+ cliPath: join(exampleDirectory, "../dist/cli.js"),
17
+ args: ["--no-session"],
18
+ });
19
+
20
+ const unsubscribe = client.onEvent((event) => {
21
+ if (event.type === "message_update" && event.assistantMessageEvent.type === "text_delta") {
22
+ process.stdout.write(event.assistantMessageEvent.delta);
23
+ } else if (event.type === "tool_execution_start") {
24
+ process.stderr.write(`\n[tool: ${event.toolName}]\n`);
25
+ }
26
+ });
27
+
28
+ try {
29
+ await client.start();
30
+ await client.promptAndWait(prompt);
31
+ process.stdout.write("\n");
32
+ } finally {
33
+ unsubscribe();
34
+ await client.stop();
35
+ }
@@ -16,7 +16,7 @@
16
16
 
17
17
  import { spawn } from "node:child_process";
18
18
  import { dirname, join } from "node:path";
19
- import * as readline from "node:readline";
19
+ import { StringDecoder } from "node:string_decoder";
20
20
  import { fileURLToPath } from "node:url";
21
21
  import {
22
22
  type Component,
@@ -258,7 +258,7 @@ async function main() {
258
258
 
259
259
  const agent = spawn(
260
260
  "node",
261
- [cliPath, "--mode", "rpc", "--no-session", "--no-extension", "--extension", extensionPath],
261
+ [cliPath, "--mode", "rpc", "--no-session", "--no-extensions", "--extension", extensionPath],
262
262
  { stdio: ["pipe", "pipe", "pipe"] },
263
263
  );
264
264
 
@@ -518,9 +518,7 @@ async function main() {
518
518
 
519
519
  // -- Process agent stdout --
520
520
 
521
- const stdoutRl = readline.createInterface({ input: agent.stdout!, terminal: false });
522
-
523
- stdoutRl.on("line", (line) => {
521
+ function handleAgentLine(line: string): void {
524
522
  let data: Record<string, unknown>;
525
523
  try {
526
524
  data = JSON.parse(line);
@@ -583,6 +581,28 @@ async function main() {
583
581
  tui.requestRender();
584
582
  return;
585
583
  }
584
+ }
585
+
586
+ const stdoutDecoder = new StringDecoder("utf8");
587
+ let stdoutBuffer = "";
588
+
589
+ agent.stdout!.on("data", (chunk: Buffer) => {
590
+ stdoutBuffer += stdoutDecoder.write(chunk);
591
+ while (true) {
592
+ const newlineIndex = stdoutBuffer.indexOf("\n");
593
+ if (newlineIndex === -1) break;
594
+
595
+ const line = stdoutBuffer.slice(0, newlineIndex);
596
+ stdoutBuffer = stdoutBuffer.slice(newlineIndex + 1);
597
+ handleAgentLine(line.endsWith("\r") ? line.slice(0, -1) : line);
598
+ }
599
+ });
600
+
601
+ agent.stdout!.on("end", () => {
602
+ stdoutBuffer += stdoutDecoder.end();
603
+ if (stdoutBuffer.length > 0) {
604
+ handleAgentLine(stdoutBuffer.endsWith("\r") ? stdoutBuffer.slice(0, -1) : stdoutBuffer);
605
+ }
586
606
  });
587
607
 
588
608
  // -- User input --
@@ -15,7 +15,7 @@ The runtime example shows how to build a recreate function that closes over proc
15
15
  | `05-tools.ts` | Built-in tool allowlists |
16
16
  | `06-extensions.ts` | Logging, blocking, result modification |
17
17
  | `07-context-files.ts` | AGENTS.md context files |
18
- | `08-slash-commands.ts` | File-based slash commands |
18
+ | `08-prompt-templates.ts` | File-based prompt templates |
19
19
  | `09-api-keys-and-oauth.ts` | API key resolution, OAuth config |
20
20
  | `10-settings.ts` | Override compaction, retry, terminal settings |
21
21
  | `11-sessions.ts` | In-memory, persistent, continue, list sessions |
@@ -18,6 +18,7 @@ var init_cloud_code = __esm({
18
18
  });
19
19
 
20
20
  // packages/kyrn-judge/src/auth/main.ts
21
+ import { constants } from "node:os";
21
22
  import { join as join3 } from "node:path";
22
23
  import { createInterface } from "node:readline";
23
24
  import { defaultModelPerProvider, ModelRuntime } from "../../dist/bundle/index.js";
@@ -80,7 +81,7 @@ function readJudges(value) {
80
81
  if (!isRecord(value)) return judges;
81
82
  for (const [name, config] of Object.entries(value)) {
82
83
  if (!isRecord(config) || typeof config.type !== "string") continue;
83
- if (!["jev", "typesafe", "gateway", "local", "http", "llm", "mock"].includes(config.type)) continue;
84
+ if (!["jev", "typesafe", "clm", "gateway", "local", "http", "llm", "mock"].includes(config.type)) continue;
84
85
  judges[name] = config;
85
86
  }
86
87
  return judges;
@@ -236,8 +237,8 @@ var EventStream = class {
236
237
  this.done = false;
237
238
  this.isComplete = isComplete;
238
239
  this.extractResult = extractResult;
239
- this.finalResultPromise = new Promise((resolve) => {
240
- this.resolveFinalResult = resolve;
240
+ this.finalResultPromise = new Promise((resolve2) => {
241
+ this.resolveFinalResult = resolve2;
241
242
  });
242
243
  }
243
244
  push(event) {
@@ -270,7 +271,7 @@ var EventStream = class {
270
271
  } else if (this.done) {
271
272
  return;
272
273
  } else {
273
- const result = await new Promise((resolve) => this.waiting.enqueue(resolve));
274
+ const result = await new Promise((resolve2) => this.waiting.enqueue(resolve2));
274
275
  if (result.done) return;
275
276
  yield result.value;
276
277
  }
@@ -468,7 +469,7 @@ function formatThrownValue(value) {
468
469
  return String(value);
469
470
  }
470
471
 
471
- // packages/ai/src/auth/resolve.ts
472
+ // packages/ai/src/utils/models-error.ts
472
473
  var ModelsError = class extends Error {
473
474
  constructor(code, message, options) {
474
475
  super(withCauseDetail(message, options?.cause), options);
@@ -482,24 +483,70 @@ function withCauseDetail(message, cause) {
482
483
  if (!detail || message.includes(detail)) return message;
483
484
  return `${message}: ${detail}`;
484
485
  }
486
+
487
+ // packages/ai/src/auth/resolve.ts
485
488
  var DEFAULT_OAUTH_MINIMUM_VALIDITY_MS = 5 * 60 * 1e3;
486
489
 
490
+ // packages/ai/src/utils/model-operations.ts
491
+ function getModelType(model) {
492
+ return model.type ?? "chat";
493
+ }
494
+ function isModelType(model, type) {
495
+ return getModelType(model) === type;
496
+ }
497
+ function imageErrorResult(model, error, aborted = false) {
498
+ return {
499
+ api: model.api,
500
+ provider: model.provider,
501
+ model: model.id,
502
+ output: [],
503
+ stopReason: aborted ? "aborted" : "error",
504
+ errorMessage: error instanceof Error ? error.message : String(error),
505
+ timestamp: Date.now()
506
+ };
507
+ }
508
+ function classifierErrorResult(model, error, aborted = false) {
509
+ return {
510
+ api: model.api,
511
+ provider: model.provider,
512
+ model: model.id,
513
+ answers: {},
514
+ stopReason: aborted ? "aborted" : "error",
515
+ errorMessage: error instanceof Error ? error.message : String(error),
516
+ timestamp: Date.now()
517
+ };
518
+ }
519
+
487
520
  // packages/ai/src/models.ts
521
+ var KNOWN_MODEL_TYPES = { chat: true, image: true, classifier: true };
522
+ function hasKnownModelType(model) {
523
+ return Object.hasOwn(KNOWN_MODEL_TYPES, getModelType(model));
524
+ }
488
525
  function createProvider(input) {
526
+ const single = input.api && typeof input.api.stream === "function" ? input.api : void 0;
527
+ const byApi = single || !input.api ? void 0 : input.api;
528
+ const images = input.images;
529
+ const classifiers = input.classifiers;
530
+ const streams = single ? [single] : Object.values(byApi ?? {}).filter((entry) => entry !== void 0);
531
+ const imageImplementations = Object.values(images ?? {}).filter((entry) => entry !== void 0);
532
+ const classifierImplementations = Object.values(classifiers ?? {}).filter((entry) => entry !== void 0);
533
+ if (streams.length === 0 && imageImplementations.length === 0 && classifierImplementations.length === 0) {
534
+ throw new Error(`Provider ${input.id}: at least one of "api", "images", or "classifiers" is required.`);
535
+ }
489
536
  const baselineModels = input.models;
490
537
  let dynamicModels = [];
491
538
  const fetchModels = input.fetchModels;
492
539
  const currentModels = () => {
493
540
  const merged = [...baselineModels];
494
541
  for (const model of dynamicModels) {
495
- const index = merged.findIndex((entry) => entry.id === model.id);
542
+ const index = merged.findIndex(
543
+ (entry) => getModelType(entry) === getModelType(model) && entry.id === model.id
544
+ );
496
545
  if (index >= 0) merged[index] = model;
497
546
  else merged.push(model);
498
547
  }
499
548
  return merged;
500
549
  };
501
- const single = typeof input.api.stream === "function" ? input.api : void 0;
502
- const byApi = single ? void 0 : input.api;
503
550
  const apiFor = (model) => single ?? byApi?.[model.api];
504
551
  const dispatch = (model, run) => {
505
552
  const streams2 = apiFor(model);
@@ -516,7 +563,8 @@ function createProvider(input) {
516
563
  baseUrl: input.baseUrl,
517
564
  headers: input.headers,
518
565
  auth: input.auth,
519
- getModels: currentModels,
566
+ getModels: () => currentModels().filter((model) => isModelType(model, "chat")),
567
+ getAllModels: currentModels,
520
568
  refreshModels: fetchModels ? async (context) => {
521
569
  if (context.stored) {
522
570
  const restored = context.stored.models.filter((model) => model.provider === input.id).map((model) => model);
@@ -529,8 +577,9 @@ function createProvider(input) {
529
577
  }
530
578
  }
531
579
  if (!context.allowNetwork || context.signal.aborted) return;
532
- const refreshed = await fetchModels(context);
580
+ const fetched = await fetchModels(context);
533
581
  if (context.signal.aborted) return;
582
+ const refreshed = fetched.filter(hasKnownModelType);
534
583
  await context.publish({
535
584
  persist: { models: refreshed, checkedAt: Date.now() },
536
585
  update: () => {
@@ -539,10 +588,10 @@ function createProvider(input) {
539
588
  });
540
589
  } : void 0,
541
590
  filterModels: input.filterModels,
591
+ filterAllModels: input.filterAllModels,
542
592
  stream: (model, context, options) => dispatch(model, (streams2) => streams2.stream(model, context, options)),
543
593
  streamSimple: (model, context, options) => dispatch(model, (streams2) => streams2.streamSimple(model, context, options))
544
594
  };
545
- const streams = single ? [single] : Object.values(byApi ?? {}).filter((entry) => entry !== void 0);
546
595
  if (streams.some((entry) => entry.fetchDeferred !== void 0)) {
547
596
  provider.fetchDeferred = (model, handle, options) => lazyStream(model, async () => {
548
597
  const implementation = apiFor(model);
@@ -567,19 +616,59 @@ function createProvider(input) {
567
616
  await implementation.cancelDeferred(model, handle, options);
568
617
  };
569
618
  }
619
+ if (images && imageImplementations.length > 0) {
620
+ provider.generateImages = async (model, context, options) => {
621
+ const implementation = images[model.api];
622
+ if (!implementation) {
623
+ return imageErrorResult(
624
+ model,
625
+ new ModelsError(
626
+ "provider",
627
+ `Provider ${input.id} has no image generation implementation for "${model.api}"`
628
+ )
629
+ );
630
+ }
631
+ return implementation.generateImages(model, context, options);
632
+ };
633
+ }
634
+ if (classifiers && classifierImplementations.length > 0) {
635
+ provider.classify = async (model, context, options) => {
636
+ const implementation = classifiers[model.api];
637
+ if (!implementation) {
638
+ return classifierErrorResult(
639
+ model,
640
+ new ModelsError("provider", `Provider ${input.id} has no classifier implementation for "${model.api}"`)
641
+ );
642
+ }
643
+ return implementation.classify(model, context, options);
644
+ };
645
+ }
570
646
  return provider;
571
647
  }
572
648
 
573
649
  // packages/ai/src/providers/data/google.json
574
- var google_default = { "google-generative-ai": { "deep-research-max-preview-04-2026": { id: "deep-research-max-preview-04-2026", name: "Deep Research Max Preview (Apr-21-2026)", api: "google-generative-ai", provider: "google", baseUrl: "https://generativelanguage.googleapis.com/v1beta", reasoning: true, input: ["text", "image"], cost: { input: 2, output: 12, cacheRead: 0.2, cacheWrite: 0 }, contextWindow: 131072, maxTokens: 65536 }, "deep-research-preview-04-2026": { id: "deep-research-preview-04-2026", name: "Deep Research Preview (Apr-21-2026)", api: "google-generative-ai", provider: "google", baseUrl: "https://generativelanguage.googleapis.com/v1beta", reasoning: true, input: ["text", "image"], cost: { input: 2, output: 12, cacheRead: 0.2, cacheWrite: 0 }, contextWindow: 131072, maxTokens: 65536 }, "gemini-2.5-computer-use-preview-10-2025": { id: "gemini-2.5-computer-use-preview-10-2025", name: "Gemini 2.5 Computer Use Preview 10-2025", api: "google-generative-ai", provider: "google", baseUrl: "https://generativelanguage.googleapis.com/v1beta", reasoning: true, input: ["text", "image"], cost: { input: 1.25, output: 10, cacheRead: 0, cacheWrite: 0 }, contextWindow: 131072, maxTokens: 65536 }, "gemini-2.5-flash": { id: "gemini-2.5-flash", name: "Gemini 2.5 Flash", api: "google-generative-ai", provider: "google", baseUrl: "https://generativelanguage.googleapis.com/v1beta", reasoning: true, input: ["text", "image"], cost: { input: 0.3, output: 2.5, cacheRead: 0.03, cacheWrite: 0 }, contextWindow: 1048576, maxTokens: 65536 }, "gemini-2.5-flash-lite": { id: "gemini-2.5-flash-lite", name: "Gemini 2.5 Flash-Lite", api: "google-generative-ai", provider: "google", baseUrl: "https://generativelanguage.googleapis.com/v1beta", reasoning: true, input: ["text", "image"], cost: { input: 0.1, output: 0.4, cacheRead: 0.01, cacheWrite: 0 }, contextWindow: 1048576, maxTokens: 65536 }, "gemini-2.5-pro": { id: "gemini-2.5-pro", name: "Gemini 2.5 Pro", api: "google-generative-ai", provider: "google", baseUrl: "https://generativelanguage.googleapis.com/v1beta", reasoning: true, input: ["text", "image"], cost: { input: 1.25, output: 10, cacheRead: 0.125, cacheWrite: 0 }, contextWindow: 1048576, maxTokens: 65536 }, "gemini-3-flash-preview": { id: "gemini-3-flash-preview", name: "Gemini 3 Flash Preview", api: "google-generative-ai", provider: "google", baseUrl: "https://generativelanguage.googleapis.com/v1beta", reasoning: true, thinkingLevelMap: { off: null, minimal: "minimal", low: "low", medium: "medium", high: "high", xhigh: null, max: null }, input: ["text", "image"], cost: { input: 0.5, output: 3, cacheRead: 0.05, cacheWrite: 0 }, contextWindow: 1048576, maxTokens: 65536 }, "gemini-3.1-flash-lite": { id: "gemini-3.1-flash-lite", name: "Gemini 3.1 Flash Lite", api: "google-generative-ai", provider: "google", baseUrl: "https://generativelanguage.googleapis.com/v1beta", reasoning: true, thinkingLevelMap: { off: null, minimal: "minimal", low: "low", medium: "medium", high: "high", xhigh: null, max: null }, input: ["text", "image"], cost: { input: 0.25, output: 1.5, cacheRead: 0.025, cacheWrite: 0 }, contextWindow: 1048576, maxTokens: 65536 }, "gemini-3.1-flash-lite-image": { id: "gemini-3.1-flash-lite-image", name: "Nano Banana 2 Lite", api: "google-generative-ai", provider: "google", baseUrl: "https://generativelanguage.googleapis.com/v1beta", reasoning: true, thinkingLevelMap: { off: null, minimal: "minimal", low: null, medium: null, high: "high", xhigh: null, max: null }, input: ["text", "image"], cost: { input: 0.25, output: 30, cacheRead: 0, cacheWrite: 0 }, contextWindow: 65536, maxTokens: 65536 }, "gemini-3.1-flash-lite-preview": { id: "gemini-3.1-flash-lite-preview", name: "Gemini 3.1 Flash Lite Preview", api: "google-generative-ai", provider: "google", baseUrl: "https://generativelanguage.googleapis.com/v1beta", reasoning: true, thinkingLevelMap: { off: null, minimal: "minimal", low: "low", medium: "medium", high: "high", xhigh: null, max: null }, input: ["text", "image"], cost: { input: 0.25, output: 1.5, cacheRead: 0.025, cacheWrite: 0 }, contextWindow: 1048576, maxTokens: 65536 }, "gemini-3.1-flash-live-preview": { id: "gemini-3.1-flash-live-preview", name: "Gemini 3.1 Flash Live Preview", api: "google-generative-ai", provider: "google", baseUrl: "https://generativelanguage.googleapis.com/v1beta", reasoning: true, thinkingLevelMap: { off: null, minimal: "minimal", low: "low", medium: "medium", high: "high", xhigh: null, max: null }, input: ["text", "image"], cost: { input: 0.75, output: 4.5, cacheRead: 0, cacheWrite: 0 }, contextWindow: 131072, maxTokens: 65536 }, "gemini-3.1-pro-preview": { id: "gemini-3.1-pro-preview", name: "Gemini 3.1 Pro Preview", api: "google-generative-ai", provider: "google", baseUrl: "https://generativelanguage.googleapis.com/v1beta", reasoning: true, thinkingLevelMap: { off: null, minimal: null, low: "low", medium: "medium", high: "high", xhigh: null, max: null }, input: ["text", "image"], cost: { input: 2, output: 12, cacheRead: 0.2, cacheWrite: 0 }, contextWindow: 1048576, maxTokens: 65536 }, "gemini-3.1-pro-preview-customtools": { id: "gemini-3.1-pro-preview-customtools", name: "Gemini 3.1 Pro Preview Custom Tools", api: "google-generative-ai", provider: "google", baseUrl: "https://generativelanguage.googleapis.com/v1beta", reasoning: true, thinkingLevelMap: { off: null, minimal: null, low: "low", medium: "medium", high: "high", xhigh: null, max: null }, input: ["text", "image"], cost: { input: 2, output: 12, cacheRead: 0.2, cacheWrite: 0 }, contextWindow: 1048576, maxTokens: 65536 }, "gemini-3.5-flash": { id: "gemini-3.5-flash", name: "Gemini 3.5 Flash", api: "google-generative-ai", provider: "google", baseUrl: "https://generativelanguage.googleapis.com/v1beta", reasoning: true, thinkingLevelMap: { off: null, minimal: "minimal", low: "low", medium: "medium", high: "high", xhigh: null, max: null }, input: ["text", "image"], cost: { input: 1.5, output: 9, cacheRead: 0.15, cacheWrite: 0 }, contextWindow: 1048576, maxTokens: 65536 }, "gemini-3.5-flash-lite": { id: "gemini-3.5-flash-lite", name: "Gemini 3.5 Flash Lite", api: "google-generative-ai", provider: "google", baseUrl: "https://generativelanguage.googleapis.com/v1beta", reasoning: true, thinkingLevelMap: { off: null, minimal: "minimal", low: "low", medium: "medium", high: "high", xhigh: null, max: null }, input: ["text", "image"], cost: { input: 0.3, output: 2.5, cacheRead: 0.03, cacheWrite: 0 }, contextWindow: 1048576, maxTokens: 65536 }, "gemini-3.6-flash": { id: "gemini-3.6-flash", name: "Gemini 3.6 Flash", api: "google-generative-ai", provider: "google", baseUrl: "https://generativelanguage.googleapis.com/v1beta", reasoning: true, thinkingLevelMap: { off: null, minimal: "minimal", low: "low", medium: "medium", high: "high", xhigh: null, max: null }, input: ["text", "image"], cost: { input: 0.75, output: 3.75, cacheRead: 0.075, cacheWrite: 0 }, contextWindow: 1048576, maxTokens: 65536 }, "gemini-3.7-flash": { id: "gemini-3.7-flash", name: "Gemini 3.7 Flash", api: "google-generative-ai", provider: "google", baseUrl: "https://generativelanguage.googleapis.com/v1beta", reasoning: true, thinkingLevelMap: { off: null, minimal: null, low: "low", medium: "medium", high: "high", xhigh: null, max: null }, input: ["text", "image"], cost: { input: 0.75, output: 3.75, cacheRead: 0.075, cacheWrite: 0 }, contextWindow: 1048576, maxTokens: 65536 }, "gemini-3.8-flash": { id: "gemini-3.8-flash", name: "Gemini 3.8 Flash", api: "google-generative-ai", provider: "google", baseUrl: "https://generativelanguage.googleapis.com/v1beta", reasoning: true, thinkingLevelMap: { off: null, minimal: null, low: "low", medium: "medium", high: "high", xhigh: null, max: null }, input: ["text", "image"], cost: { input: 0.75, output: 3.75, cacheRead: 0.075, cacheWrite: 0 }, contextWindow: 1048576, maxTokens: 65536 }, "gemini-flash-latest": { id: "gemini-flash-latest", name: "Gemini Flash Latest", api: "google-generative-ai", provider: "google", baseUrl: "https://generativelanguage.googleapis.com/v1beta", reasoning: true, thinkingLevelMap: { off: null, minimal: "minimal", low: "low", medium: "medium", high: "high", xhigh: null, max: null }, input: ["text", "image"], cost: { input: 1.5, output: 9, cacheRead: 0.15, cacheWrite: 0 }, contextWindow: 1048576, maxTokens: 65536 }, "gemini-flash-lite-latest": { id: "gemini-flash-lite-latest", name: "Gemini Flash-Lite Latest", api: "google-generative-ai", provider: "google", baseUrl: "https://generativelanguage.googleapis.com/v1beta", reasoning: true, thinkingLevelMap: { off: null, minimal: "minimal", low: "low", medium: "medium", high: "high", xhigh: null, max: null }, input: ["text", "image"], cost: { input: 0.25, output: 1.5, cacheRead: 0.025, cacheWrite: 0 }, contextWindow: 1048576, maxTokens: 65536 }, "gemma-4-26b-a4b-it": { id: "gemma-4-26b-a4b-it", name: "Gemma 4 26B A4B IT", api: "google-generative-ai", provider: "google", baseUrl: "https://generativelanguage.googleapis.com/v1beta", reasoning: true, thinkingLevelMap: { off: null, minimal: "MINIMAL", low: null, medium: null, high: "HIGH" }, input: ["text", "image"], cost: { input: 0, output: 0, cacheRead: 0, cacheWrite: 0 }, contextWindow: 262144, maxTokens: 32768 }, "gemma-4-31b-it": { id: "gemma-4-31b-it", name: "Gemma 4 31B IT", api: "google-generative-ai", provider: "google", baseUrl: "https://generativelanguage.googleapis.com/v1beta", reasoning: true, thinkingLevelMap: { off: null, minimal: "MINIMAL", low: null, medium: null, high: "HIGH" }, input: ["text", "image"], cost: { input: 0, output: 0, cacheRead: 0, cacheWrite: 0 }, contextWindow: 262144, maxTokens: 32768 } } };
650
+ var google_default = { "google-generative-ai": { "chat:deep-research-max-preview-04-2026": { id: "deep-research-max-preview-04-2026", name: "Deep Research Max Preview (Apr-21-2026)", api: "google-generative-ai", provider: "google", baseUrl: "https://generativelanguage.googleapis.com/v1beta", reasoning: true, input: ["text", "image"], cost: { input: 2, output: 12, cacheRead: 0.2, cacheWrite: 0 }, contextWindow: 131072, maxTokens: 65536, inputLimits: { maxRequestBytes: 20971520, images: { maxPerRequest: 3600, resize: { maxWidth: 2e3, maxHeight: 2e3, maxBytes: 4718592, jpegQuality: 80 } } }, type: "chat" }, "chat:deep-research-preview-04-2026": { id: "deep-research-preview-04-2026", name: "Deep Research Preview (Apr-21-2026)", api: "google-generative-ai", provider: "google", baseUrl: "https://generativelanguage.googleapis.com/v1beta", reasoning: true, input: ["text", "image"], cost: { input: 2, output: 12, cacheRead: 0.2, cacheWrite: 0 }, contextWindow: 131072, maxTokens: 65536, inputLimits: { maxRequestBytes: 20971520, images: { maxPerRequest: 3600, resize: { maxWidth: 2e3, maxHeight: 2e3, maxBytes: 4718592, jpegQuality: 80 } } }, type: "chat" }, "chat:gemini-2.5-computer-use-preview-10-2025": { id: "gemini-2.5-computer-use-preview-10-2025", name: "Gemini 2.5 Computer Use Preview 10-2025", api: "google-generative-ai", provider: "google", baseUrl: "https://generativelanguage.googleapis.com/v1beta", reasoning: true, input: ["text", "image"], cost: { input: 1.25, output: 10, cacheRead: 0, cacheWrite: 0 }, contextWindow: 128e3, maxTokens: 64e3, inputLimits: { maxRequestBytes: 20971520, images: { maxPerRequest: 3600, resize: { maxWidth: 2e3, maxHeight: 2e3, maxBytes: 4718592, jpegQuality: 80 } } }, type: "chat" }, "chat:gemini-2.5-flash": { id: "gemini-2.5-flash", name: "Gemini 2.5 Flash", api: "google-generative-ai", provider: "google", baseUrl: "https://generativelanguage.googleapis.com/v1beta", reasoning: true, input: ["text", "image"], cost: { input: 0.3, output: 2.5, cacheRead: 0.03, cacheWrite: 0 }, contextWindow: 1048576, maxTokens: 65536, inputLimits: { maxRequestBytes: 20971520, images: { maxPerRequest: 3600, resize: { maxWidth: 2e3, maxHeight: 2e3, maxBytes: 4718592, jpegQuality: 80 } } }, type: "chat" }, "chat:gemini-2.5-flash-lite": { id: "gemini-2.5-flash-lite", name: "Gemini 2.5 Flash-Lite", api: "google-generative-ai", provider: "google", baseUrl: "https://generativelanguage.googleapis.com/v1beta", reasoning: true, input: ["text", "image"], cost: { input: 0.1, output: 0.4, cacheRead: 0.01, cacheWrite: 0 }, contextWindow: 1048576, maxTokens: 65536, inputLimits: { maxRequestBytes: 20971520, images: { maxPerRequest: 3600, resize: { maxWidth: 2e3, maxHeight: 2e3, maxBytes: 4718592, jpegQuality: 80 } } }, type: "chat" }, "chat:gemini-2.5-pro": { id: "gemini-2.5-pro", name: "Gemini 2.5 Pro", api: "google-generative-ai", provider: "google", baseUrl: "https://generativelanguage.googleapis.com/v1beta", reasoning: true, input: ["text", "image"], cost: { input: 1.25, output: 10, cacheRead: 0.125, cacheWrite: 0 }, contextWindow: 1048576, maxTokens: 65536, inputLimits: { maxRequestBytes: 20971520, images: { maxPerRequest: 3600, resize: { maxWidth: 2e3, maxHeight: 2e3, maxBytes: 4718592, jpegQuality: 80 } } }, type: "chat" }, "chat:gemini-3-flash-preview": { id: "gemini-3-flash-preview", name: "Gemini 3 Flash Preview", api: "google-generative-ai", provider: "google", baseUrl: "https://generativelanguage.googleapis.com/v1beta", reasoning: true, thinkingLevelMap: { off: null, minimal: "minimal", low: "low", medium: "medium", high: "high", xhigh: null, max: null }, input: ["text", "image"], cost: { input: 0.5, output: 3, cacheRead: 0.05, cacheWrite: 0 }, contextWindow: 1048576, maxTokens: 65536, inputLimits: { maxRequestBytes: 20971520, images: { maxPerRequest: 3600, resize: { maxWidth: 2e3, maxHeight: 2e3, maxBytes: 4718592, jpegQuality: 80 } } }, type: "chat" }, "chat:gemini-3.1-flash-lite": { id: "gemini-3.1-flash-lite", name: "Gemini 3.1 Flash Lite", api: "google-generative-ai", provider: "google", baseUrl: "https://generativelanguage.googleapis.com/v1beta", reasoning: true, thinkingLevelMap: { off: null, minimal: "minimal", low: "low", medium: "medium", high: "high", xhigh: null, max: null }, input: ["text", "image"], cost: { input: 0.25, output: 1.5, cacheRead: 0.025, cacheWrite: 0 }, contextWindow: 1048576, maxTokens: 65536, inputLimits: { maxRequestBytes: 20971520, images: { maxPerRequest: 3600, resize: { maxWidth: 2e3, maxHeight: 2e3, maxBytes: 4718592, jpegQuality: 80 } } }, type: "chat" }, "chat:gemini-3.1-flash-lite-image": { id: "gemini-3.1-flash-lite-image", name: "Nano Banana 2 Lite", api: "google-generative-ai", provider: "google", baseUrl: "https://generativelanguage.googleapis.com/v1beta", reasoning: true, thinkingLevelMap: { off: null, minimal: "minimal", low: null, medium: null, high: "high", xhigh: null, max: null }, input: ["text", "image"], cost: { input: 0.25, output: 30, cacheRead: 0, cacheWrite: 0 }, contextWindow: 65536, maxTokens: 4096, inputLimits: { maxRequestBytes: 20971520, images: { maxPerRequest: 3600, resize: { maxWidth: 2e3, maxHeight: 2e3, maxBytes: 4718592, jpegQuality: 80 } } }, type: "chat" }, "chat:gemini-3.1-flash-lite-preview": { id: "gemini-3.1-flash-lite-preview", name: "Gemini 3.1 Flash Lite Preview", api: "google-generative-ai", provider: "google", baseUrl: "https://generativelanguage.googleapis.com/v1beta", reasoning: true, thinkingLevelMap: { off: null, minimal: "minimal", low: "low", medium: "medium", high: "high", xhigh: null, max: null }, input: ["text", "image"], cost: { input: 0.25, output: 1.5, cacheRead: 0.025, cacheWrite: 0 }, contextWindow: 1048576, maxTokens: 65536, inputLimits: { maxRequestBytes: 20971520, images: { maxPerRequest: 3600, resize: { maxWidth: 2e3, maxHeight: 2e3, maxBytes: 4718592, jpegQuality: 80 } } }, type: "chat" }, "chat:gemini-3.1-flash-live-preview": { id: "gemini-3.1-flash-live-preview", name: "Gemini 3.1 Flash Live Preview", api: "google-generative-ai", provider: "google", baseUrl: "https://generativelanguage.googleapis.com/v1beta", reasoning: true, thinkingLevelMap: { off: null, minimal: "minimal", low: "low", medium: "medium", high: "high", xhigh: null, max: null }, input: ["text", "image"], cost: { input: 0.75, output: 4.5, cacheRead: 0, cacheWrite: 0 }, contextWindow: 131072, maxTokens: 65536, inputLimits: { maxRequestBytes: 20971520, images: { maxPerRequest: 3600, resize: { maxWidth: 2e3, maxHeight: 2e3, maxBytes: 4718592, jpegQuality: 80 } } }, type: "chat" }, "chat:gemini-3.1-pro-preview": { id: "gemini-3.1-pro-preview", name: "Gemini 3.1 Pro Preview", api: "google-generative-ai", provider: "google", baseUrl: "https://generativelanguage.googleapis.com/v1beta", reasoning: true, thinkingLevelMap: { off: null, minimal: null, low: "low", medium: "medium", high: "high", xhigh: null, max: null }, input: ["text", "image"], cost: { input: 2, output: 12, cacheRead: 0.2, cacheWrite: 0 }, contextWindow: 1048576, maxTokens: 65536, inputLimits: { maxRequestBytes: 20971520, images: { maxPerRequest: 3600, resize: { maxWidth: 2e3, maxHeight: 2e3, maxBytes: 4718592, jpegQuality: 80 } } }, type: "chat" }, "chat:gemini-3.1-pro-preview-customtools": { id: "gemini-3.1-pro-preview-customtools", name: "Gemini 3.1 Pro Preview Custom Tools", api: "google-generative-ai", provider: "google", baseUrl: "https://generativelanguage.googleapis.com/v1beta", reasoning: true, thinkingLevelMap: { off: null, minimal: null, low: "low", medium: "medium", high: "high", xhigh: null, max: null }, input: ["text", "image"], cost: { input: 2, output: 12, cacheRead: 0.2, cacheWrite: 0 }, contextWindow: 1048576, maxTokens: 65536, inputLimits: { maxRequestBytes: 20971520, images: { maxPerRequest: 3600, resize: { maxWidth: 2e3, maxHeight: 2e3, maxBytes: 4718592, jpegQuality: 80 } } }, type: "chat" }, "chat:gemini-3.5-flash": { id: "gemini-3.5-flash", name: "Gemini 3.5 Flash", api: "google-generative-ai", provider: "google", baseUrl: "https://generativelanguage.googleapis.com/v1beta", reasoning: true, thinkingLevelMap: { off: null, minimal: "minimal", low: "low", medium: "medium", high: "high", xhigh: null, max: null }, input: ["text", "image"], cost: { input: 1.5, output: 9, cacheRead: 0.15, cacheWrite: 0 }, contextWindow: 1048576, maxTokens: 65536, inputLimits: { maxRequestBytes: 20971520, images: { maxPerRequest: 3600, resize: { maxWidth: 2e3, maxHeight: 2e3, maxBytes: 4718592, jpegQuality: 80 } } }, type: "chat" }, "chat:gemini-3.5-flash-lite": { id: "gemini-3.5-flash-lite", name: "Gemini 3.5 Flash Lite", api: "google-generative-ai", provider: "google", baseUrl: "https://generativelanguage.googleapis.com/v1beta", reasoning: true, thinkingLevelMap: { off: null, minimal: "minimal", low: "low", medium: "medium", high: "high", xhigh: null, max: null }, input: ["text", "image"], cost: { input: 0.3, output: 2.5, cacheRead: 0.03, cacheWrite: 0 }, contextWindow: 1048576, maxTokens: 65536, inputLimits: { maxRequestBytes: 20971520, images: { maxPerRequest: 3600, resize: { maxWidth: 2e3, maxHeight: 2e3, maxBytes: 4718592, jpegQuality: 80 } } }, type: "chat" }, "chat:gemini-3.6-flash": { id: "gemini-3.6-flash", name: "Gemini 3.6 Flash", api: "google-generative-ai", provider: "google", baseUrl: "https://generativelanguage.googleapis.com/v1beta", reasoning: true, thinkingLevelMap: { off: null, minimal: "minimal", low: "low", medium: "medium", high: "high", xhigh: null, max: null }, input: ["text", "image"], cost: { input: 0.75, output: 3.75, cacheRead: 0.075, cacheWrite: 0 }, contextWindow: 1048576, maxTokens: 65536, inputLimits: { maxRequestBytes: 20971520, images: { maxPerRequest: 3600, resize: { maxWidth: 2e3, maxHeight: 2e3, maxBytes: 4718592, jpegQuality: 80 } } }, type: "chat" }, "chat:gemini-3.7-flash": { id: "gemini-3.7-flash", name: "Gemini 3.7 Flash", api: "google-generative-ai", provider: "google", baseUrl: "https://generativelanguage.googleapis.com/v1beta", reasoning: true, thinkingLevelMap: { off: null, minimal: null, low: "low", medium: "medium", high: "high", xhigh: null, max: null }, input: ["text", "image"], cost: { input: 0.75, output: 3.75, cacheRead: 0.075, cacheWrite: 0 }, contextWindow: 1048576, maxTokens: 65536, inputLimits: { maxRequestBytes: 20971520, images: { maxPerRequest: 3600, resize: { maxWidth: 2e3, maxHeight: 2e3, maxBytes: 4718592, jpegQuality: 80 } } }, type: "chat" }, "chat:gemini-3.8-flash": { id: "gemini-3.8-flash", name: "Gemini 3.8 Flash", api: "google-generative-ai", provider: "google", baseUrl: "https://generativelanguage.googleapis.com/v1beta", reasoning: true, thinkingLevelMap: { off: null, minimal: null, low: "low", medium: "medium", high: "high", xhigh: null, max: null }, input: ["text", "image"], cost: { input: 0.75, output: 3.75, cacheRead: 0.075, cacheWrite: 0 }, contextWindow: 1048576, maxTokens: 65536, inputLimits: { maxRequestBytes: 20971520, images: { maxPerRequest: 3600, resize: { maxWidth: 2e3, maxHeight: 2e3, maxBytes: 4718592, jpegQuality: 80 } } }, type: "chat" }, "chat:gemini-flash-latest": { id: "gemini-flash-latest", name: "Gemini Flash Latest", api: "google-generative-ai", provider: "google", baseUrl: "https://generativelanguage.googleapis.com/v1beta", reasoning: true, thinkingLevelMap: { off: null, minimal: "minimal", low: "low", medium: "medium", high: "high", xhigh: null, max: null }, input: ["text", "image"], cost: { input: 1.5, output: 9, cacheRead: 0.15, cacheWrite: 0 }, contextWindow: 1048576, maxTokens: 65536, inputLimits: { maxRequestBytes: 20971520, images: { maxPerRequest: 3600, resize: { maxWidth: 2e3, maxHeight: 2e3, maxBytes: 4718592, jpegQuality: 80 } } }, type: "chat" }, "chat:gemini-flash-lite-latest": { id: "gemini-flash-lite-latest", name: "Gemini Flash-Lite Latest", api: "google-generative-ai", provider: "google", baseUrl: "https://generativelanguage.googleapis.com/v1beta", reasoning: true, thinkingLevelMap: { off: null, minimal: "minimal", low: "low", medium: "medium", high: "high", xhigh: null, max: null }, input: ["text", "image"], cost: { input: 0.25, output: 1.5, cacheRead: 0.025, cacheWrite: 0 }, contextWindow: 1048576, maxTokens: 65536, inputLimits: { maxRequestBytes: 20971520, images: { maxPerRequest: 3600, resize: { maxWidth: 2e3, maxHeight: 2e3, maxBytes: 4718592, jpegQuality: 80 } } }, type: "chat" }, "chat:gemma-4-26b-a4b-it": { id: "gemma-4-26b-a4b-it", name: "Gemma 4 26B A4B IT", api: "google-generative-ai", provider: "google", baseUrl: "https://generativelanguage.googleapis.com/v1beta", reasoning: true, thinkingLevelMap: { off: null, minimal: "MINIMAL", low: null, medium: null, high: "HIGH" }, input: ["text", "image"], cost: { input: 0, output: 0, cacheRead: 0, cacheWrite: 0 }, contextWindow: 262144, maxTokens: 32768, inputLimits: { maxRequestBytes: 20971520, images: { maxPerRequest: 3600, resize: { maxWidth: 2e3, maxHeight: 2e3, maxBytes: 4718592, jpegQuality: 80 } } }, type: "chat" }, "chat:gemma-4-31b-it": { id: "gemma-4-31b-it", name: "Gemma 4 31B IT", api: "google-generative-ai", provider: "google", baseUrl: "https://generativelanguage.googleapis.com/v1beta", reasoning: true, thinkingLevelMap: { off: null, minimal: "MINIMAL", low: null, medium: null, high: "HIGH" }, input: ["text", "image"], cost: { input: 0, output: 0, cacheRead: 0, cacheWrite: 0 }, contextWindow: 262144, maxTokens: 32768, inputLimits: { maxRequestBytes: 20971520, images: { maxPerRequest: 3600, resize: { maxWidth: 2e3, maxHeight: 2e3, maxBytes: 4718592, jpegQuality: 80 } } }, type: "chat" } } };
575
651
 
576
652
  // packages/ai/src/model-catalog.ts
577
- function flattenModelCatalog(_provider, groups) {
578
- return Object.assign({}, ...Object.values(groups));
653
+ function flattenModelCatalog(groups, type) {
654
+ return Object.fromEntries(
655
+ Object.values(groups).flatMap((models) => Object.values(models)).filter((model) => model.type === type).map((model) => [model.id, model])
656
+ );
657
+ }
658
+ function flattenChatModelCatalog(_provider, groups) {
659
+ return flattenModelCatalog(groups, "chat");
660
+ }
661
+ function flattenImageModelCatalog(_provider, groups) {
662
+ return flattenModelCatalog(groups, "image");
663
+ }
664
+ function flattenClassifierModelCatalog(_provider, groups) {
665
+ return flattenModelCatalog(groups, "classifier");
579
666
  }
580
667
 
581
668
  // packages/ai/src/providers/google.models.ts
582
- var GOOGLE_MODELS = flattenModelCatalog("google", google_default);
669
+ var GOOGLE_MODELS = flattenChatModelCatalog("google", google_default);
670
+ var GOOGLE_IMAGE_MODELS = flattenImageModelCatalog("google", google_default);
671
+ var GOOGLE_CLASSIFIER_MODELS = flattenClassifierModelCatalog("google", google_default);
583
672
 
584
673
  // packages/kyrn-judge/src/google-login/endpoints.ts
585
674
  var CLOUD_CODE_API = "google-cloud-code";
@@ -653,7 +742,7 @@ async function pkce() {
653
742
  return { verifier, challenge: base64url(new Uint8Array(digest)) };
654
743
  }
655
744
  function listen(config, state) {
656
- return new Promise((resolve, reject) => {
745
+ return new Promise((resolve2, reject) => {
657
746
  let settle = () => {
658
747
  };
659
748
  const wait = new Promise((done) => {
@@ -700,7 +789,7 @@ function listen(config, state) {
700
789
  server.listen(
701
790
  config.callbackPort,
702
791
  config.callbackHost,
703
- () => resolve({ server, wait, cancel: () => settle(void 0) })
792
+ () => resolve2({ server, wait, cancel: () => settle(void 0) })
704
793
  );
705
794
  });
706
795
  }
@@ -793,7 +882,7 @@ async function geminiProject(config, token, interaction) {
793
882
  if (!started.ok) throw new Error(`onboardUser failed (${started.status}): ${(await started.text()).slice(0, 300)}`);
794
883
  let operation = await started.json();
795
884
  for (let attempt = 0; !operation.done && operation.name && attempt < 60; attempt++) {
796
- await new Promise((resolve) => setTimeout(resolve, attempt === 0 ? 1e3 : 5e3));
885
+ await new Promise((resolve2) => setTimeout(resolve2, attempt === 0 ? 1e3 : 5e3));
797
886
  const polled = await fetch(`${endpoint}/v1internal/${operation.name}`, { headers, signal: interaction.signal });
798
887
  if (!polled.ok) throw new Error(`Setting up the project failed (${polled.status})`);
799
888
  operation = await polled.json();
@@ -1088,6 +1177,47 @@ function antigravityProvider(fetcher) {
1088
1177
  });
1089
1178
  }
1090
1179
 
1180
+ // packages/kyrn-judge/src/auth/exit.ts
1181
+ import { mkdirSync, rmdirSync } from "node:fs";
1182
+ import { resolve } from "node:path";
1183
+ import { setTimeout as sleep } from "node:timers/promises";
1184
+ async function exitWhenUnlocked(code, files, exit, { limitMs = 5e3, pollMs = 20 } = {}) {
1185
+ const locks = lockFolders(files);
1186
+ const deadline = Date.now() + limitMs;
1187
+ while (true) {
1188
+ const taken = takeAll(locks);
1189
+ if (taken || Date.now() >= deadline) {
1190
+ for (const lock of taken ?? []) drop(lock);
1191
+ exit(code);
1192
+ return;
1193
+ }
1194
+ await sleep(pollMs);
1195
+ }
1196
+ }
1197
+ function lockFolders(files) {
1198
+ return [...new Set(files.map((file) => `${resolve(file)}.lock`))];
1199
+ }
1200
+ function takeAll(locks) {
1201
+ const taken = [];
1202
+ for (const lock of locks) {
1203
+ try {
1204
+ mkdirSync(lock);
1205
+ taken.push(lock);
1206
+ } catch (error) {
1207
+ if (error.code !== "EEXIST") continue;
1208
+ for (const mine of taken) drop(mine);
1209
+ return void 0;
1210
+ }
1211
+ }
1212
+ return taken;
1213
+ }
1214
+ function drop(lock) {
1215
+ try {
1216
+ rmdirSync(lock);
1217
+ } catch {
1218
+ }
1219
+ }
1220
+
1091
1221
  // packages/kyrn-judge/src/auth/runner.ts
1092
1222
  var BUILT_IN_PROVIDERS = ["openai-codex", "anthropic", "xai"];
1093
1223
  var LISTED_BY_ACCOUNT = /* @__PURE__ */ new Set(["google-antigravity"]);
@@ -1172,8 +1302,8 @@ async function signIn(provider, { runtime, preferred, io, modelsReadMs }) {
1172
1302
  await runtime.login(provider, "oauth", {
1173
1303
  signal: controller.signal,
1174
1304
  notify: (event) => io.say({ type: "event", event }),
1175
- prompt: (prompt) => isBrowserChoice(prompt) ? Promise.resolve(BROWSER_METHOD) : new Promise((resolve, reject) => {
1176
- const entry = { resolve, reject };
1305
+ prompt: (prompt) => isBrowserChoice(prompt) ? Promise.resolve(BROWSER_METHOD) : new Promise((resolve2, reject) => {
1306
+ const entry = { resolve: resolve2, reject };
1177
1307
  pending = entry;
1178
1308
  prompt.signal?.addEventListener(
1179
1309
  "abort",
@@ -1199,6 +1329,8 @@ async function signIn(provider, { runtime, preferred, io, modelsReadMs }) {
1199
1329
 
1200
1330
  // packages/kyrn-judge/src/auth/main.ts
1201
1331
  var agentDir = muEnv("AGENT_DIR") || join3(muHome(), "agent");
1332
+ var authPath = join3(agentDir, "auth.json");
1333
+ var modelsStorePath = join3(agentDir, "models-store.json");
1202
1334
  var say = (message) => process.stdout.write(`${JSON.stringify(message)}
1203
1335
  `);
1204
1336
  function googleProviders() {
@@ -1221,8 +1353,9 @@ function googleProviders() {
1221
1353
  }
1222
1354
  async function main() {
1223
1355
  const runtime = await ModelRuntime.create({
1224
- authPath: join3(agentDir, "auth.json"),
1356
+ authPath,
1225
1357
  modelsPath: join3(agentDir, "models.json"),
1358
+ modelsStorePath,
1226
1359
  refreshOnCreate: false
1227
1360
  });
1228
1361
  return runAuth(process.argv.slice(2), {
@@ -1239,10 +1372,15 @@ async function main() {
1239
1372
  }
1240
1373
  });
1241
1374
  }
1242
- main().then(
1243
- (code) => process.exit(code),
1244
- (error) => {
1245
- say({ type: "error", message: error instanceof Error ? error.message : String(error) });
1246
- process.exit(1);
1247
- }
1248
- );
1375
+ var leaving = false;
1376
+ var leave = (code) => {
1377
+ if (leaving) return;
1378
+ leaving = true;
1379
+ void exitWhenUnlocked(code, [authPath, modelsStorePath], (exitCode) => process.exit(exitCode));
1380
+ };
1381
+ for (const signal of ["SIGTERM", "SIGINT", "SIGHUP"])
1382
+ process.on(signal, () => leave(128 + constants.signals[signal]));
1383
+ main().then(leave, (error) => {
1384
+ say({ type: "error", message: error instanceof Error ? error.message : String(error) });
1385
+ leave(1);
1386
+ });
@@ -270,6 +270,16 @@ async function isAlive(endpoint) {
270
270
  return false;
271
271
  }
272
272
  }
273
+ function exitOf(child, ms) {
274
+ if (child.exitCode !== null || child.signalCode !== null) return Promise.resolve();
275
+ return new Promise((resolve) => {
276
+ const timer = setTimeout(resolve, ms);
277
+ child.once("exit", () => {
278
+ clearTimeout(timer);
279
+ resolve();
280
+ });
281
+ });
282
+ }
273
283
  async function launchChrome(options = {}) {
274
284
  const host = options.host ?? thisBrowserHost();
275
285
  const browser = options.executable ? { executable: options.executable, side: sideOf(options.executable, host) } : findBrowser(host);
@@ -294,7 +304,7 @@ async function launchChrome(options = {}) {
294
304
  child.on("error", (error) => {
295
305
  failure = error;
296
306
  });
297
- const deadline = Date.now() + 15e3;
307
+ const deadline = Date.now() + (options.portWaitMs ?? 15e3);
298
308
  while (Date.now() < deadline) {
299
309
  const endpoint = readEndpoint(profileDir);
300
310
  if (endpoint && await isAlive(endpoint)) return { endpoint, process: child, profileDir };
@@ -311,6 +321,7 @@ async function launchChrome(options = {}) {
311
321
  await new Promise((resolve) => setTimeout(resolve, 100));
312
322
  }
313
323
  child.kill();
324
+ await exitOf(child, 5e3);
314
325
  throw codedError("Chrome did not open its DevTools port in time", { code: "devtools_port_timeout" });
315
326
  }
316
327
  export {