micro-models-agent 0.44.0 → 0.45.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.
Files changed (188) hide show
  1. package/README.md +312 -312
  2. package/bin/mma.mjs +41 -41
  3. package/dist/main.js +241 -56
  4. package/dist/skills/builtin/git.md +36 -36
  5. package/dist/skills/builtin/typescript.md +35 -35
  6. package/package.json +1 -1
  7. package/dist/cli/commands.js +0 -333
  8. package/dist/cli/completer.js +0 -168
  9. package/dist/cli/index.js +0 -2
  10. package/dist/cli/main.js +0 -140
  11. package/dist/cli/repl-commands.js +0 -633
  12. package/dist/cli/repl.js +0 -486
  13. package/dist/cli/security-commands.js +0 -166
  14. package/dist/cli/setup.js +0 -249
  15. package/dist/config/config.js +0 -202
  16. package/dist/config/defaults.js +0 -100
  17. package/dist/config/experts.js +0 -15
  18. package/dist/config/index.js +0 -3
  19. package/dist/config/security.js +0 -200
  20. package/dist/config/types.js +0 -1
  21. package/dist/core/agent-moe.js +0 -110
  22. package/dist/core/agent.js +0 -695
  23. package/dist/core/bootstrap.js +0 -337
  24. package/dist/core/index.js +0 -2
  25. package/dist/core/prompt-builder.js +0 -55
  26. package/dist/core/session-logger.js +0 -155
  27. package/dist/core/types.js +0 -1
  28. package/dist/core/workspace.js +0 -76
  29. package/dist/i18n/en.json +0 -525
  30. package/dist/i18n/index.js +0 -46
  31. package/dist/i18n/ru.json +0 -525
  32. package/dist/index.js +0 -22
  33. package/dist/llm/image-utils.js +0 -144
  34. package/dist/llm/index.js +0 -4
  35. package/dist/llm/model-loader.js +0 -78
  36. package/dist/llm/openai-compat.js +0 -353
  37. package/dist/llm/orchestrator.js +0 -194
  38. package/dist/llm/provider.js +0 -10
  39. package/dist/llm/response.js +0 -39
  40. package/dist/llm/token-counter.js +0 -39
  41. package/dist/llm/types.js +0 -1
  42. package/dist/logger/app-logger.js +0 -143
  43. package/dist/logger/file-log.js +0 -151
  44. package/dist/logger/index.js +0 -1
  45. package/dist/migration/backup.js +0 -45
  46. package/dist/migration/detect.js +0 -50
  47. package/dist/migration/index.js +0 -2
  48. package/dist/modules/browser/actions.js +0 -46
  49. package/dist/modules/browser/cookie-store.js +0 -24
  50. package/dist/modules/browser/index.js +0 -5
  51. package/dist/modules/browser/module.js +0 -28
  52. package/dist/modules/browser/session.js +0 -335
  53. package/dist/modules/browser/snapshot.js +0 -114
  54. package/dist/modules/browser/types.js +0 -9
  55. package/dist/modules/certification/cli.js +0 -176
  56. package/dist/modules/certification/fact-checker.js +0 -84
  57. package/dist/modules/certification/loader.js +0 -111
  58. package/dist/modules/certification/manifest.js +0 -50
  59. package/dist/modules/certification/runner.js +0 -162
  60. package/dist/modules/certification/scenarios.js +0 -124
  61. package/dist/modules/certification/types.js +0 -1
  62. package/dist/modules/context/index.js +0 -1
  63. package/dist/modules/context/manager.js +0 -349
  64. package/dist/modules/execution/auditor.js +0 -66
  65. package/dist/modules/execution/index.js +0 -8
  66. package/dist/modules/execution/module.js +0 -779
  67. package/dist/modules/execution/moe-executor.js +0 -266
  68. package/dist/modules/execution/plan-coverage.js +0 -68
  69. package/dist/modules/execution/plan-persister.js +0 -46
  70. package/dist/modules/execution/plan-store.js +0 -159
  71. package/dist/modules/execution/plan-validator.js +0 -153
  72. package/dist/modules/execution/planner.js +0 -85
  73. package/dist/modules/execution/stuck-detector.js +0 -347
  74. package/dist/modules/execution/tracker.js +0 -67
  75. package/dist/modules/execution/types.js +0 -1
  76. package/dist/modules/execution/verifier.js +0 -178
  77. package/dist/modules/hallucination/confidence.js +0 -59
  78. package/dist/modules/hallucination/consistency.js +0 -26
  79. package/dist/modules/hallucination/detector.js +0 -46
  80. package/dist/modules/hallucination/factual.js +0 -190
  81. package/dist/modules/hallucination/index.js +0 -5
  82. package/dist/modules/hallucination/js-identifiers.js +0 -72
  83. package/dist/modules/hallucination/llm-judge.js +0 -103
  84. package/dist/modules/index.js +0 -5
  85. package/dist/modules/indexer/cache.js +0 -38
  86. package/dist/modules/indexer/index.js +0 -3
  87. package/dist/modules/indexer/module.js +0 -192
  88. package/dist/modules/indexer/walker.js +0 -101
  89. package/dist/modules/lsp/client.js +0 -235
  90. package/dist/modules/lsp/config.js +0 -81
  91. package/dist/modules/lsp/index.js +0 -3
  92. package/dist/modules/lsp/module.js +0 -68
  93. package/dist/modules/lsp/types.js +0 -1
  94. package/dist/modules/mcp/client.js +0 -399
  95. package/dist/modules/mcp/index.js +0 -3
  96. package/dist/modules/mcp/module.js +0 -146
  97. package/dist/modules/mcp/registry.js +0 -15
  98. package/dist/modules/memory/index.js +0 -1
  99. package/dist/modules/memory/module.js +0 -48
  100. package/dist/modules/memory/search.js +0 -40
  101. package/dist/modules/memory/store.js +0 -69
  102. package/dist/modules/pipelines/engine.js +0 -60
  103. package/dist/modules/pipelines/index.js +0 -3
  104. package/dist/modules/pipelines/parser.js +0 -53
  105. package/dist/modules/pipelines/template.js +0 -14
  106. package/dist/modules/plugins/builtin/lint-on-write.js +0 -226
  107. package/dist/modules/plugins/builtin/notify.js +0 -8
  108. package/dist/modules/plugins/index.js +0 -1
  109. package/dist/modules/plugins/loader.js +0 -28
  110. package/dist/modules/plugins/manager.js +0 -161
  111. package/dist/modules/plugins/types.js +0 -1
  112. package/dist/modules/processes/index.js +0 -2
  113. package/dist/modules/processes/registry.js +0 -238
  114. package/dist/modules/processes/runner.js +0 -23
  115. package/dist/modules/registry.js +0 -45
  116. package/dist/modules/security/audit-log.js +0 -136
  117. package/dist/modules/security/audit-notifier.js +0 -292
  118. package/dist/modules/security/command-validator.js +0 -211
  119. package/dist/modules/security/content-scanner.js +0 -53
  120. package/dist/modules/security/data-sanitizer.js +0 -97
  121. package/dist/modules/security/encryption.js +0 -240
  122. package/dist/modules/security/index.js +0 -14
  123. package/dist/modules/security/network-validator.js +0 -79
  124. package/dist/modules/security/path-validator.js +0 -209
  125. package/dist/modules/security/rate-limiter.js +0 -119
  126. package/dist/modules/security/security-policies.js +0 -547
  127. package/dist/modules/security/session-encryption.js +0 -210
  128. package/dist/modules/security/session-isolation.js +0 -95
  129. package/dist/modules/session/index.js +0 -3
  130. package/dist/modules/session/manager.js +0 -172
  131. package/dist/modules/session/module.js +0 -24
  132. package/dist/modules/session/store.js +0 -228
  133. package/dist/modules/session/types.js +0 -1
  134. package/dist/modules/skills/index.js +0 -2
  135. package/dist/modules/skills/loader.js +0 -72
  136. package/dist/modules/skills/module.js +0 -130
  137. package/dist/modules/types.js +0 -1
  138. package/dist/modules/updater/checker.js +0 -32
  139. package/dist/modules/updater/index.js +0 -1
  140. package/dist/modules/user-profile/compressor.js +0 -16
  141. package/dist/modules/user-profile/index.js +0 -1
  142. package/dist/modules/user-profile/profile.js +0 -68
  143. package/dist/tools/approve.js +0 -32
  144. package/dist/tools/attach-image.js +0 -89
  145. package/dist/tools/bash.js +0 -337
  146. package/dist/tools/browser.js +0 -97
  147. package/dist/tools/create-dir.js +0 -55
  148. package/dist/tools/delete-file.js +0 -62
  149. package/dist/tools/edit-file.js +0 -79
  150. package/dist/tools/executor.js +0 -145
  151. package/dist/tools/file-info.js +0 -45
  152. package/dist/tools/filter-tools.js +0 -10
  153. package/dist/tools/glob-tool.js +0 -26
  154. package/dist/tools/grep-tool.js +0 -86
  155. package/dist/tools/index.js +0 -67
  156. package/dist/tools/list-dir.js +0 -47
  157. package/dist/tools/load-skill.js +0 -44
  158. package/dist/tools/mcp-call.js +0 -68
  159. package/dist/tools/move-file.js +0 -85
  160. package/dist/tools/path-utils.js +0 -51
  161. package/dist/tools/pipeline-run.js +0 -144
  162. package/dist/tools/preview.js +0 -2
  163. package/dist/tools/process-kill.js +0 -29
  164. package/dist/tools/process-list.js +0 -38
  165. package/dist/tools/process-log.js +0 -41
  166. package/dist/tools/question.js +0 -142
  167. package/dist/tools/read-file.js +0 -83
  168. package/dist/tools/recall.js +0 -110
  169. package/dist/tools/registry.js +0 -36
  170. package/dist/tools/remember.js +0 -67
  171. package/dist/tools/scope-check.js +0 -30
  172. package/dist/tools/search-history.js +0 -84
  173. package/dist/tools/subagent.js +0 -151
  174. package/dist/tools/types.js +0 -1
  175. package/dist/tools/user-input.js +0 -123
  176. package/dist/tools/web-browse.js +0 -86
  177. package/dist/tools/web-fetch.js +0 -98
  178. package/dist/tools/web-search.js +0 -78
  179. package/dist/tools/write-file.js +0 -83
  180. package/dist/ui/box.js +0 -81
  181. package/dist/ui/colors.js +0 -4
  182. package/dist/ui/diff.js +0 -178
  183. package/dist/ui/index.js +0 -6
  184. package/dist/ui/md-formatter.js +0 -212
  185. package/dist/ui/output.js +0 -13
  186. package/dist/ui/renderer.js +0 -204
  187. package/dist/ui/spinner.js +0 -70
  188. package/dist/ui/table.js +0 -144
package/bin/mma.mjs CHANGED
@@ -1,41 +1,41 @@
1
- #!/usr/bin/env node
2
- import { spawnSync } from "node:child_process";
3
- import { fileURLToPath, pathToFileURL } from "node:url";
4
- import { dirname, join } from "node:path";
5
-
6
- // MMA is designed to run under Bun: clipboard image paste relies on
7
- // `Bun.Image.fromClipboard()` (Node has no clipboard API), and on Windows a
8
- // bare `npx.cmd` shim can only be spawned reliably through Bun's child_process
9
- // (under Node it throws `spawn EINVAL`). The global npm shim (`mma` /
10
- // `mma.cmd`) launches this file under Node, so re-execute ourselves under Bun
11
- // when it is available. The `bun run mma` path already runs under Bun and
12
- // skips the respawn.
13
- const runningUnderBun =
14
- typeof globalThis.Bun !== "undefined" &&
15
- typeof globalThis.Bun?.version !== "undefined";
16
-
17
- if (process.env.MMA_DEBUG_RUNTIME) {
18
- console.error(
19
- "[mma] runtime=" +
20
- (runningUnderBun ? "bun " + globalThis.Bun.version : "node " + process.version),
21
- );
22
- }
23
-
24
- if (!runningUnderBun) {
25
- try {
26
- const res = spawnSync("bun", [process.argv[1], ...process.argv.slice(2)], {
27
- stdio: "inherit",
28
- windowsHide: true,
29
- });
30
- if (res.error) throw res.error;
31
- process.exit(res.status ?? 0);
32
- } catch {
33
- // `bun` is not on PATH — fall back to the Node import path (clipboard
34
- // paste and LSP will degrade, but the agent still works).
35
- }
36
- }
37
-
38
- const __dirname = dirname(fileURLToPath(import.meta.url));
39
- const main = join(__dirname, "..", "dist", "main.js");
40
-
41
- await import(pathToFileURL(main).href);
1
+ #!/usr/bin/env node
2
+ import { spawnSync } from "node:child_process";
3
+ import { fileURLToPath, pathToFileURL } from "node:url";
4
+ import { dirname, join } from "node:path";
5
+
6
+ // MMA is designed to run under Bun: clipboard image paste relies on
7
+ // `Bun.Image.fromClipboard()` (Node has no clipboard API), and on Windows a
8
+ // bare `npx.cmd` shim can only be spawned reliably through Bun's child_process
9
+ // (under Node it throws `spawn EINVAL`). The global npm shim (`mma` /
10
+ // `mma.cmd`) launches this file under Node, so re-execute ourselves under Bun
11
+ // when it is available. The `bun run mma` path already runs under Bun and
12
+ // skips the respawn.
13
+ const runningUnderBun =
14
+ typeof globalThis.Bun !== "undefined" &&
15
+ typeof globalThis.Bun?.version !== "undefined";
16
+
17
+ if (process.env.MMA_DEBUG_RUNTIME) {
18
+ console.error(
19
+ "[mma] runtime=" +
20
+ (runningUnderBun ? "bun " + globalThis.Bun.version : "node " + process.version),
21
+ );
22
+ }
23
+
24
+ if (!runningUnderBun) {
25
+ try {
26
+ const res = spawnSync("bun", [process.argv[1], ...process.argv.slice(2)], {
27
+ stdio: "inherit",
28
+ windowsHide: true,
29
+ });
30
+ if (res.error) throw res.error;
31
+ process.exit(res.status ?? 0);
32
+ } catch {
33
+ // `bun` is not on PATH — fall back to the Node import path (clipboard
34
+ // paste and LSP will degrade, but the agent still works).
35
+ }
36
+ }
37
+
38
+ const __dirname = dirname(fileURLToPath(import.meta.url));
39
+ const main = join(__dirname, "..", "dist", "main.js");
40
+
41
+ await import(pathToFileURL(main).href);
package/dist/main.js CHANGED
@@ -2298,6 +2298,10 @@ var init_defaults = __esm(() => {
2298
2298
  maxSearchesPerSession: 3,
2299
2299
  requestTimeoutMs: 1e4
2300
2300
  },
2301
+ pricing: {
2302
+ enabled: true,
2303
+ overrides: {}
2304
+ },
2301
2305
  ui: {
2302
2306
  spinner: true,
2303
2307
  toolStyle: "inline",
@@ -2390,6 +2394,7 @@ Use read_file on {path} to see the current content before editing — the target
2390
2394
  "error.http": "HTTP {status}: {statusText}",
2391
2395
  "error.llm_api": "LLM API error {status} ({statusText}): {errorText}",
2392
2396
  "error.llm_retries": "LLM request failed after retries",
2397
+ "error.llm_429": "Rate limit exceeded (HTTP 429) for {model} on {baseUrl}. The provider is throttling requests — free models are especially strict. Get an API key or switch to a paid/faster model: {baseUrl}",
2393
2398
  "error.no_response_body": "No response body stream",
2394
2399
  "session.started": "Session started: {id}",
2395
2400
  "session.ended": "Session ended: {id}",
@@ -2999,7 +3004,10 @@ Apply a matching solution from these results. If none is relevant — do NOT rep
2999
3004
  "tools.enable_already_active": "Tool tags already active: {tags}.",
3000
3005
  "tools.enable_added": "Enabled tool tags: {tags}. Available tools now: {tools}",
3001
3006
  "tools.hidden_header": "Additional tools (enable on demand via enable_tools or route to subagent tool_tags):",
3002
- "tool.friendly.enable_tools": "Enable tools"
3007
+ "tool.friendly.enable_tools": "Enable tools",
3008
+ "cli.provider_base_hint": "Base URL set to: {baseUrl}",
3009
+ "repl.cost": "Total cost: {cost}",
3010
+ "repl.tokens": "Tokens used: {tokens}"
3003
3011
  };
3004
3012
  });
3005
3013
 
@@ -3049,6 +3057,7 @@ var init_ru = __esm(() => {
3049
3057
  "error.http": "HTTP {status}: {statusText}",
3050
3058
  "error.llm_api": "Ошибка LLM API {status} ({statusText}): {errorText}",
3051
3059
  "error.llm_retries": "Запрос LLM не удался после повторов",
3060
+ "error.llm_429": "Превышен лимит запросов (HTTP 429) для {model} на {baseUrl}. Провайдер ограничивает трафик — особенно строгие free-модели. Получите API-ключ или переключитесь на платную/быструю модель: {baseUrl}",
3052
3061
  "error.no_response_body": "Нет потока тела ответа",
3053
3062
  "session.started": "Сессия начата: {id}",
3054
3063
  "session.ended": "Сессия завершена: {id}",
@@ -3659,7 +3668,10 @@ var init_ru = __esm(() => {
3659
3668
  "tools.enable_already_active": "Теги тулов уже активны: {tags}.",
3660
3669
  "tools.enable_added": "Включены теги тулов: {tags}. Теперь доступны тулы: {tools}",
3661
3670
  "tools.hidden_header": "Дополнительные тулы (включите по требованию через enable_tools или маршрутизируйте через subagent tool_tags):",
3662
- "tool.friendly.enable_tools": "Включить тулы"
3671
+ "tool.friendly.enable_tools": "Включить тулы",
3672
+ "cli.provider_base_hint": "Базовый URL установлен: {baseUrl}",
3673
+ "repl.cost": "Итого потрачено: {cost}",
3674
+ "repl.tokens": "Потрачено токенов: {tokens}"
3663
3675
  };
3664
3676
  });
3665
3677
 
@@ -5421,26 +5433,36 @@ class OpenAICompatProvider {
5421
5433
  }
5422
5434
  async fetchWithRetry(url, init) {
5423
5435
  const { maxRetries, baseDelay, maxDelay } = this.retryConfig;
5424
- let lastError = null;
5436
+ let lastStatus = 0;
5437
+ let lastRetryAfter = 0;
5425
5438
  for (let attempt = 0;attempt <= maxRetries; attempt++) {
5426
5439
  try {
5427
5440
  const response = await fetch(url, init);
5428
5441
  if (!this.isRetryable(response.status))
5429
5442
  return response;
5430
- lastError = new Error(`HTTP ${response.status}: ${response.statusText}`);
5443
+ lastStatus = response.status;
5444
+ const retryAfter = Number(response.headers.get("retry-after") ?? 0);
5445
+ lastRetryAfter = retryAfter > 0 ? retryAfter * 1000 : 0;
5431
5446
  } catch (err) {
5432
5447
  if (err.name === "AbortError") {
5433
5448
  throw err;
5434
5449
  }
5435
- lastError = err;
5450
+ if (attempt === maxRetries)
5451
+ throw err;
5436
5452
  }
5437
5453
  if (attempt < maxRetries) {
5438
- const delay = Math.min(baseDelay * Math.pow(2, attempt), maxDelay);
5454
+ const delay = lastRetryAfter > 0 ? Math.min(lastRetryAfter, maxDelay) : Math.min(baseDelay * Math.pow(2, attempt), maxDelay);
5439
5455
  const jitter = Math.random() * baseDelay * 0.1;
5440
5456
  await this.sleep(delay + jitter, init.signal ?? undefined);
5441
5457
  }
5442
5458
  }
5443
- throw lastError ?? new Error(t("error.llm_retries"));
5459
+ if (lastStatus === 429) {
5460
+ throw new Error(t("error.llm_429", {
5461
+ model: this.model,
5462
+ baseUrl: this.config.baseUrl
5463
+ }));
5464
+ }
5465
+ throw new Error(t("error.llm_retries"));
5444
5466
  }
5445
5467
  isRetryable(status) {
5446
5468
  return status === 429 || status >= 500;
@@ -11293,6 +11315,145 @@ var init_agent_moe = __esm(() => {
11293
11315
  init_verifier();
11294
11316
  });
11295
11317
 
11318
+ // src/modules/pricing/prices.ts
11319
+ function normalizeModelId(model) {
11320
+ let id = model.trim();
11321
+ for (const prefix of PROVIDER_PREFIXES) {
11322
+ if (id.startsWith(prefix)) {
11323
+ id = id.slice(prefix.length);
11324
+ break;
11325
+ }
11326
+ }
11327
+ const parts = id.split("/");
11328
+ return parts[parts.length - 1];
11329
+ }
11330
+ function resolvePrice(model, config) {
11331
+ if (!config?.enabled)
11332
+ return;
11333
+ const bare = normalizeModelId(model);
11334
+ const overrides = config.overrides ?? {};
11335
+ const direct = overrides[model] ?? overrides[bare];
11336
+ if (direct)
11337
+ return direct;
11338
+ return ZEN_PRICES[bare];
11339
+ }
11340
+ function calculateCost(model, promptTokens, completionTokens, config) {
11341
+ const price = resolvePrice(model, config);
11342
+ if (!price)
11343
+ return;
11344
+ return promptTokens / 1e6 * price.input + completionTokens / 1e6 * price.output;
11345
+ }
11346
+ function formatCost(cost) {
11347
+ if (cost === 0)
11348
+ return "$0.00";
11349
+ if (cost >= 0.01)
11350
+ return `$${cost.toFixed(2)}`;
11351
+ if (cost >= 0.0001)
11352
+ return `$${cost.toFixed(4)}`;
11353
+ return `$${cost.toFixed(6)}`;
11354
+ }
11355
+ var ZEN_PRICES, PROVIDER_PREFIXES;
11356
+ var init_prices = __esm(() => {
11357
+ ZEN_PRICES = {
11358
+ "big-pickle": { input: 0, output: 0 },
11359
+ "mimo-v2.5-free": { input: 0, output: 0 },
11360
+ "hy3-free": { input: 0, output: 0 },
11361
+ "nemotron-3-ultra-free": { input: 0, output: 0 },
11362
+ "nemotron-3.5-lightning-free": { input: 0, output: 0 },
11363
+ "muse-spark-1.2-contributor-free": { input: 0, output: 0 },
11364
+ "minimax-m3": { input: 0.3, output: 1.2 },
11365
+ "minimax-m2.7": { input: 0.3, output: 1.2 },
11366
+ "minimax-m2.5": { input: 0.3, output: 1.2 },
11367
+ "glm-5.2": { input: 1.4, output: 4.4 },
11368
+ "glm-5.1": { input: 1.4, output: 4.4 },
11369
+ "glm-5": { input: 1, output: 3.2 },
11370
+ "glm-5.3": { input: 1.4, output: 4.4 },
11371
+ "kimi-k2.7-code": { input: 0.95, output: 4 },
11372
+ "kimi-k3": { input: 3, output: 15 },
11373
+ "kimi-k2.6": { input: 0.95, output: 4 },
11374
+ "kimi-k2.5": { input: 0.6, output: 3 },
11375
+ "qwen3.7-max": { input: 2.5, output: 7.5 },
11376
+ "qwen3.7-plus": { input: 0.4, output: 1.6 },
11377
+ "qwen3.6-plus": { input: 0.5, output: 3 },
11378
+ "qwen3.5-plus": { input: 0.2, output: 1.2 },
11379
+ "qwen3.8-max": { input: 2.5, output: 7.5 },
11380
+ "deepseek-v4-pro": { input: 0.66, output: 1.98 },
11381
+ "deepseek-v4-flash": { input: 0.22, output: 0.66 },
11382
+ "claude-fable-5": { input: 10, output: 50 },
11383
+ "claude-opus-5": { input: 5, output: 25 },
11384
+ "claude-opus-4-8": { input: 5, output: 25 },
11385
+ "claude-opus-4-7": { input: 5, output: 25 },
11386
+ "claude-opus-4-6": { input: 5, output: 25 },
11387
+ "claude-opus-4-5": { input: 5, output: 25 },
11388
+ "claude-sonnet-5": { input: 2, output: 10 },
11389
+ "claude-sonnet-4-6": { input: 3, output: 15 },
11390
+ "claude-sonnet-4-5": { input: 3, output: 15 },
11391
+ "claude-haiku-4-5": { input: 1, output: 5 },
11392
+ "gemini-3.7-flash": { input: 1.5, output: 7.5 },
11393
+ "gemini-3.6-flash": { input: 1.5, output: 7.5 },
11394
+ "gemini-3.5-flash": { input: 1.5, output: 9 },
11395
+ "gemini-3.5-flash-lite": { input: 0.3, output: 2.5 },
11396
+ "gemini-3.1-pro": { input: 2, output: 12 },
11397
+ "gemini-3-flash": { input: 0.5, output: 3 },
11398
+ "grok-4.6": { input: 2, output: 6 },
11399
+ "grok-4.5": { input: 2, output: 6 },
11400
+ "grok-build-0.1": { input: 1, output: 2 },
11401
+ "muse-spark-1.2": { input: 1.25, output: 4.25 },
11402
+ "gpt-5.6-sol": { input: 5, output: 30 },
11403
+ "gpt-5.6-terra": { input: 2, output: 12 },
11404
+ "gpt-5.6-luna": { input: 0.2, output: 1.2 },
11405
+ "gpt-5.5": { input: 5, output: 30 },
11406
+ "gpt-5.5-pro": { input: 30, output: 180 },
11407
+ "gpt-5.4": { input: 2.5, output: 15 },
11408
+ "gpt-5.4-pro": { input: 30, output: 180 },
11409
+ "gpt-5.4-mini": { input: 0.75, output: 4.5 },
11410
+ "gpt-5.4-nano": { input: 0.2, output: 1.25 },
11411
+ "gpt-5.3-codex": { input: 1.75, output: 14 },
11412
+ "gpt-5.3-codex-spark": { input: 1.75, output: 14 },
11413
+ "gpt-5.2": { input: 1.75, output: 14 },
11414
+ "gpt-5.2-codex": { input: 1.75, output: 14 },
11415
+ "gpt-5.1": { input: 1.07, output: 8.5 },
11416
+ "gpt-5.1-codex": { input: 1.07, output: 8.5 },
11417
+ "gpt-5.1-codex-max": { input: 1.25, output: 10 },
11418
+ "gpt-5.1-codex-mini": { input: 0.25, output: 2 },
11419
+ "gpt-5": { input: 1.07, output: 8.5 },
11420
+ "gpt-5-codex": { input: 1.07, output: 8.5 },
11421
+ "gpt-5-nano": { input: 0.05, output: 0.4 }
11422
+ };
11423
+ PROVIDER_PREFIXES = ["opencode-go/", "opencode/", "openai/", "anthropic/"];
11424
+ });
11425
+
11426
+ // src/modules/pricing/index.ts
11427
+ class CostTracker {
11428
+ config;
11429
+ model;
11430
+ _total = 0;
11431
+ _known = false;
11432
+ constructor(model, config) {
11433
+ this.model = model;
11434
+ this.config = config;
11435
+ }
11436
+ setModel(model) {
11437
+ this.model = model;
11438
+ }
11439
+ record(promptTokens, completionTokens) {
11440
+ const cost = calculateCost(this.model, promptTokens, completionTokens, this.config);
11441
+ if (cost === undefined)
11442
+ return;
11443
+ this._known = true;
11444
+ this._total += cost;
11445
+ }
11446
+ get total() {
11447
+ return this._known ? this._total : undefined;
11448
+ }
11449
+ get formatted() {
11450
+ return this._known ? formatCost(this._total) : undefined;
11451
+ }
11452
+ }
11453
+ var init_pricing = __esm(() => {
11454
+ init_prices();
11455
+ });
11456
+
11296
11457
  // src/core/agent.ts
11297
11458
  function isToolCallJson(text) {
11298
11459
  const trimmed = text.trim();
@@ -11319,8 +11480,10 @@ class Agent {
11319
11480
  shutdownRequested = false;
11320
11481
  abortController = null;
11321
11482
  lastCompactionShown = 0;
11483
+ costTracker;
11322
11484
  constructor(deps) {
11323
11485
  this.deps = deps;
11486
+ this.costTracker = new CostTracker(deps.config.model, deps.config.pricing);
11324
11487
  }
11325
11488
  get contextManager() {
11326
11489
  return this.deps.contextManager;
@@ -11676,6 +11839,7 @@ ${t("tool.truncated", { tokens: Math.ceil(removedChars / 2) })}`;
11676
11839
  source,
11677
11840
  durationMs: Date.now() - llmStart
11678
11841
  });
11842
+ this.costTracker.record(prompt, completion);
11679
11843
  }
11680
11844
  if (this.shutdownRequested) {
11681
11845
  break;
@@ -11791,7 +11955,8 @@ ${t("tool.truncated", { tokens: Math.ceil(removedChars / 2) })}`;
11791
11955
  args: call.arguments,
11792
11956
  duration,
11793
11957
  error: !result.success,
11794
- ctxDelta: tokensAfterTool - tokensBeforeTool
11958
+ ctxDelta: tokensAfterTool - tokensBeforeTool,
11959
+ costUsd: this.costTracker.total
11795
11960
  });
11796
11961
  summaries.push(`[Tool: ${call.name} (${JSON.stringify(call.arguments)}) → ${truncatedOutput.slice(0, 200)}]`);
11797
11962
  if (config.session.autoSave) {
@@ -12026,6 +12191,7 @@ ${warnLine}
12026
12191
  promptTokens: usageTokens.prompt,
12027
12192
  completionTokens: usageTokens.completion,
12028
12193
  totalTokens: usageTokens.total,
12194
+ totalCost: this.costTracker.total,
12029
12195
  compactionCount: contextManager.getCompactionCount(),
12030
12196
  contextQuality: contextManager.getQuality()
12031
12197
  };
@@ -12040,6 +12206,7 @@ ${warnLine}
12040
12206
  promptTokens: usageTokens.prompt,
12041
12207
  completionTokens: usageTokens.completion,
12042
12208
  totalTokens: usageTokens.total,
12209
+ totalCost: this.costTracker.total,
12043
12210
  compactionCount: contextManager.getCompactionCount(),
12044
12211
  contextQuality: contextManager.getQuality()
12045
12212
  };
@@ -12065,6 +12232,7 @@ ${warnLine}
12065
12232
  const newTokenCounter = new TokenCounter2(config.model);
12066
12233
  this.deps.contextManager.resize(config.contextWindow, config.contextBudget, newTokenCounter);
12067
12234
  this.deps.config = config;
12235
+ this.costTracker.setModel(config.model);
12068
12236
  }
12069
12237
  setContext(messages) {
12070
12238
  const { contextManager } = this.deps;
@@ -12108,6 +12276,7 @@ var init_agent = __esm(() => {
12108
12276
  init_session_logger();
12109
12277
  init_agent_moe();
12110
12278
  init_verifier();
12279
+ init_pricing();
12111
12280
  });
12112
12281
 
12113
12282
  // src/modules/context/fact-extractor.ts
@@ -22264,10 +22433,8 @@ async function runSetup(externalRl) {
22264
22433
  console.log(t("setup.no_servers"));
22265
22434
  apiBase = await ask(rl, t("setup.api_base"), "http://localhost:1234/v1");
22266
22435
  }
22267
- } else if (provider === "openai") {
22268
- apiBase = "https://api.openai.com/v1";
22269
- } else if (provider === "anthropic") {
22270
- apiBase = "https://api.anthropic.com";
22436
+ } else {
22437
+ apiBase = HOSTED_BASE_URLS[provider] ?? "";
22271
22438
  }
22272
22439
  const defaultKey = provider === "openai-compat" ? "not-needed" : "";
22273
22440
  const apiKey = await ask(rl, t("setup.api_key"), defaultKey);
@@ -22332,7 +22499,7 @@ async function runSetup(externalRl) {
22332
22499
  console.log(l);
22333
22500
  return answers;
22334
22501
  }
22335
- var PROVIDER_TYPES, KNOWN_PORTS;
22502
+ var PROVIDER_TYPES, KNOWN_PORTS, HOSTED_BASE_URLS;
22336
22503
  var init_setup = __esm(() => {
22337
22504
  init_colors();
22338
22505
  init_i18n();
@@ -22345,7 +22512,9 @@ var init_setup = __esm(() => {
22345
22512
  label: "OpenAI-compatible (LM Studio, Ollama, vLLM, etc.)"
22346
22513
  },
22347
22514
  { value: "openai", label: "OpenAI API" },
22348
- { value: "anthropic", label: "Anthropic Claude" }
22515
+ { value: "anthropic", label: "Anthropic Claude" },
22516
+ { value: "opencode-zen", label: "OpenCode Zen (opencode.ai/zen)" },
22517
+ { value: "opencode-go", label: "OpenCode Go (opencode.ai/go)" }
22349
22518
  ];
22350
22519
  KNOWN_PORTS = [
22351
22520
  { port: 1234, label: "LM Studio" },
@@ -22353,6 +22522,12 @@ var init_setup = __esm(() => {
22353
22522
  { port: 8080, label: "vLLM / custom" },
22354
22523
  { port: 4891, label: "GPT4All" }
22355
22524
  ];
22525
+ HOSTED_BASE_URLS = {
22526
+ openai: "https://api.openai.com/v1",
22527
+ anthropic: "https://api.anthropic.com",
22528
+ "opencode-zen": "https://opencode.ai/zen/v1",
22529
+ "opencode-go": "https://opencode.ai/zen/go/v1"
22530
+ };
22356
22531
  });
22357
22532
 
22358
22533
  // src/modules/certification/manifest.ts
@@ -31367,6 +31542,7 @@ function createPluginCommand(program2) {
31367
31542
  }
31368
31543
 
31369
31544
  // src/cli/commands.ts
31545
+ init_setup();
31370
31546
  import { fileURLToPath as fileURLToPath4 } from "url";
31371
31547
  function readVersion2() {
31372
31548
  const here = dirname16(fileURLToPath4(import.meta.url));
@@ -31552,8 +31728,15 @@ function createProgram() {
31552
31728
  const configPath = join44(homedir15(), ".mma", "config.json");
31553
31729
  const { config } = await bootstrap();
31554
31730
  config.provider.type = name;
31731
+ const baseUrl = HOSTED_BASE_URLS[name];
31732
+ if (baseUrl) {
31733
+ config.provider.baseUrl = baseUrl;
31734
+ }
31555
31735
  saveConfig(config, configPath);
31556
31736
  console.log(t("cli.provider_set", { name }));
31737
+ if (baseUrl) {
31738
+ console.log(t("cli.provider_base_hint", { baseUrl }));
31739
+ }
31557
31740
  });
31558
31741
  const session2 = program2.command("session").description(t("cli.manage_sessions"));
31559
31742
  session2.command("list").description(t("cli.list_sessions")).action(async () => {
@@ -32358,9 +32541,8 @@ class LineEditor {
32358
32541
 
32359
32542
  // src/cli/repl.ts
32360
32543
  import { existsSync as existsSync53, readFileSync as readFileSync35, writeFileSync as writeFileSync17 } from "fs";
32361
- import { join as join47, dirname as dirname18 } from "path";
32544
+ import { join as join47 } from "path";
32362
32545
  import { homedir as homedir17 } from "os";
32363
- import { fileURLToPath as fileURLToPath6 } from "url";
32364
32546
 
32365
32547
  // src/cli/completer.ts
32366
32548
  class SlashCommandProvider {
@@ -32664,6 +32846,10 @@ init_spinner();
32664
32846
  init_box();
32665
32847
  init_table();
32666
32848
  init_i18n();
32849
+ init_prices();
32850
+ function formatUsd(cost) {
32851
+ return formatCost(cost);
32852
+ }
32667
32853
  var GUTTER = " ";
32668
32854
  var BUSY_TOOLS = new Set(["lsp_check"]);
32669
32855
  function toolMarker(tool) {
@@ -32800,14 +32986,20 @@ ${pc2.dim(marker)} ${friendlyTool(tool)}${summary ? ` ${pc2.dim(summary)}` : ""}
32800
32986
  `);
32801
32987
  }
32802
32988
  }
32803
- toolEnd(_tool, duration, error, ctxDelta) {
32989
+ toolEnd(_tool, duration, error, ctxDelta, costUsd) {
32804
32990
  this.spinner.stop();
32805
32991
  if (!this.rich) {
32992
+ const parts = [];
32806
32993
  if (ctxDelta !== undefined && ctxDelta !== 0) {
32807
32994
  const deltaStr = ctxDelta > 0 ? pc2.green(`+${ctxDelta}`) : pc2.yellow(`${ctxDelta} ↓`);
32808
- this.out.write(`${pc2.dim("ctx")} ${deltaStr}
32809
- `);
32995
+ parts.push(`${pc2.dim("ctx")} ${deltaStr}`);
32996
+ }
32997
+ if (costUsd !== undefined && costUsd > 0) {
32998
+ parts.push(`${pc2.dim("cost")} ${pc2.yellow(formatUsd(costUsd))}`);
32810
32999
  }
33000
+ if (parts.length > 0)
33001
+ this.out.write(`${parts.join(" ")}
33002
+ `);
32811
33003
  return;
32812
33004
  }
32813
33005
  if (!this.card)
@@ -32819,6 +33011,9 @@ ${pc2.dim(marker)} ${friendlyTool(tool)}${summary ? ` ${pc2.dim(summary)}` : ""}
32819
33011
  const deltaStr = ctxDelta > 0 ? pc2.green(`+${ctxDelta}`) : pc2.yellow(`${ctxDelta} ↓`);
32820
33012
  footer += ` ${pc2.dim("ctx")} ${deltaStr}`;
32821
33013
  }
33014
+ if (costUsd !== undefined && costUsd > 0) {
33015
+ footer += ` ${pc2.dim("cost")} ${pc2.yellow(formatUsd(costUsd))}`;
33016
+ }
32822
33017
  if (this.toolStyle === "inline") {
32823
33018
  this.out.write(`${GUTTER}${footer}
32824
33019
  `);
@@ -33046,21 +33241,7 @@ function stepContextForTool(plan, tool, args) {
33046
33241
  }
33047
33242
 
33048
33243
  // src/cli/repl.ts
33049
- function readVersion4() {
33050
- const here = dirname18(fileURLToPath6(import.meta.url));
33051
- const candidates = [join47(here, "..", "..", "package.json"), join47(here, "..", "package.json")];
33052
- for (const p of candidates) {
33053
- if (existsSync53(p)) {
33054
- try {
33055
- const raw = JSON.parse(readFileSync35(p, "utf8"));
33056
- if (raw.version)
33057
- return raw.version;
33058
- } catch {}
33059
- }
33060
- }
33061
- return "0.0.0";
33062
- }
33063
- var version3 = readVersion4();
33244
+ init_prices();
33064
33245
  function formatContextBar(used, limit, compactions, quality) {
33065
33246
  const pct = Math.min(100, Math.round(used / limit * 100));
33066
33247
  const barLen = 20;
@@ -33352,7 +33533,7 @@ ${t("image.clipboard_empty")}`));
33352
33533
  if (ev.type === "start") {
33353
33534
  renderer.toolStart(ev.tool, ev.args, stepContextForTool(this.activePlan, ev.tool, ev.args), ev.icon);
33354
33535
  } else {
33355
- renderer.toolEnd(ev.tool, ev.duration ?? 0, ev.error, ev.ctxDelta);
33536
+ renderer.toolEnd(ev.tool, ev.duration ?? 0, ev.error, ev.ctxDelta, ev.costUsd);
33356
33537
  if (ev.tool === "plan" || ev.tool === "todo") {
33357
33538
  this.refreshActivePlan(renderer);
33358
33539
  }
@@ -33471,6 +33652,9 @@ ${t("image.clipboard_empty")}`));
33471
33652
  const apiLine = pc2.dim(` API: ${result.promptTokens} prompt + ${result.completionTokens} completion = ${result.totalTokens} total`);
33472
33653
  console.log(apiLine);
33473
33654
  }
33655
+ if (result.totalCost !== undefined && result.totalCost > 0) {
33656
+ console.log(pc2.yellow(` ${t("repl.cost", { cost: formatCost(result.totalCost) })}`));
33657
+ }
33474
33658
  } else if (ui?.showCompaction && result.compactionCount !== undefined) {
33475
33659
  if (result.compactionCount > this.lastCompactionShown) {
33476
33660
  this.lastCompactionShown = result.compactionCount;
@@ -33502,9 +33686,9 @@ ${t("image.clipboard_empty")}`));
33502
33686
  const infos = this.pluginManager.getPluginInfos().filter(({ plugin: plugin3 }) => !plugin3.isBuiltin);
33503
33687
  if (infos.length > 0) {
33504
33688
  const pluginNames = infos.map(({ plugin: plugin3, source }) => {
33505
- const version4 = plugin3.version ? `${pc2.dim(plugin3.version)}` : "";
33689
+ const version3 = plugin3.version ? `${pc2.dim(plugin3.version)}` : "";
33506
33690
  const origin = source ? pc2.dim(` [${source}]`) : "";
33507
- return `${plugin3.name}${version4}${origin}`;
33691
+ return `${plugin3.name}${version3}${origin}`;
33508
33692
  }).join(", ");
33509
33693
  row(t("repl.plugins_label"), `${pc2.white(String(infos.length))} active ${pc2.dim(`(${pluginNames})`)}`);
33510
33694
  }
@@ -33545,33 +33729,27 @@ ${t("image.clipboard_empty")}`));
33545
33729
  if (lspEnabled) {
33546
33730
  row(t("repl.lsp_label"), pc2.dim("…"));
33547
33731
  }
33548
- const boxLines = box(info, {
33549
- title: t("repl.title", { version: version3 }),
33550
- width: headerWidth
33551
- });
33552
- for (const line of boxLines) {
33553
- console.log(line);
33732
+ for (const line of info) {
33733
+ console.log(pc2.dim(line).trimEnd());
33554
33734
  }
33555
33735
  console.log();
33556
33736
  this.rl.prompt();
33557
33737
  if (lspEnabled) {
33558
33738
  this.probeLspBanner().then((lspSummary) => {
33559
33739
  if (lspSummary)
33560
- this.updateLspRow(boxLines.length, headerWidth, lspSummary);
33740
+ this.updateLspRow(headerWidth, lspSummary);
33561
33741
  }).catch(() => {});
33562
33742
  }
33563
33743
  }
33564
- updateLspRow(boxLineCount, headerWidth, summary) {
33744
+ updateLspRow(headerWidth, summary) {
33565
33745
  if (this.agentRunning || !process.stdout.isTTY)
33566
33746
  return;
33567
33747
  if ((process.stdout.columns ?? 96) < headerWidth)
33568
33748
  return;
33569
- const inner = headerWidth - 4;
33570
33749
  const rowText = `${pc2.yellow(t("repl.lsp_label"))} ${summary.replace(/\s+/g, " ").trim()}`;
33571
- if (stringWidth(rowText) > inner)
33750
+ if (stringWidth(rowText) > headerWidth)
33572
33751
  return;
33573
- const padded = rowText + " ".repeat(Math.max(0, inner - stringWidth(rowText)));
33574
- const line = pc2.dim("│") + " " + padded + " " + pc2.dim("│");
33752
+ const line = pc2.dim(rowText);
33575
33753
  process.stdout.write(`\x1B[2A\r\x1B[2K${line}\x1B[2B\r`);
33576
33754
  }
33577
33755
  async probeLspBanner() {
@@ -33604,9 +33782,15 @@ ${t("image.clipboard_empty")}`));
33604
33782
  // src/cli/run-result.ts
33605
33783
  init_i18n();
33606
33784
  init_colors();
33785
+ init_prices();
33607
33786
  function printRunResult(result, flush) {
33608
33787
  flush();
33609
33788
  if (result.success) {
33789
+ if (result.totalCost !== undefined && result.totalCost > 0) {
33790
+ console.log(pc2.dim(`${t("repl.cost", { cost: formatCost(result.totalCost) })}`));
33791
+ } else if (result.totalTokens !== undefined && result.totalTokens > 0) {
33792
+ console.log(pc2.dim(`${t("repl.tokens", { tokens: result.totalTokens })}`));
33793
+ }
33610
33794
  if (!result.text) {
33611
33795
  console.log(pc2.yellow(t("cli.no_output")));
33612
33796
  }
@@ -33622,9 +33806,9 @@ init_config2();
33622
33806
  init_i18n();
33623
33807
  init_colors();
33624
33808
  import { existsSync as existsSync54, readFileSync as readFileSync36 } from "fs";
33625
- import { join as join48, dirname as dirname19 } from "path";
33809
+ import { join as join48, dirname as dirname18 } from "path";
33626
33810
  import { homedir as homedir18 } from "os";
33627
- import { fileURLToPath as fileURLToPath7 } from "url";
33811
+ import { fileURLToPath as fileURLToPath6 } from "url";
33628
33812
 
33629
33813
  // src/modules/updater/index.ts
33630
33814
  init_checker();
@@ -33724,8 +33908,8 @@ class UpdaterModule {
33724
33908
  }
33725
33909
  }
33726
33910
  // src/cli/main.ts
33727
- function readVersion5() {
33728
- const here = dirname19(fileURLToPath7(import.meta.url));
33911
+ function readVersion4() {
33912
+ const here = dirname18(fileURLToPath6(import.meta.url));
33729
33913
  const candidates = [join48(here, "..", "..", "package.json"), join48(here, "..", "package.json")];
33730
33914
  for (const p of candidates) {
33731
33915
  if (existsSync54(p)) {
@@ -33740,7 +33924,7 @@ function readVersion5() {
33740
33924
  }
33741
33925
  function startAutoUpdate(config) {
33742
33926
  try {
33743
- const module = new UpdaterModule(config.updater, readVersion5(), "micro-models-agent", {
33927
+ const module = new UpdaterModule(config.updater, readVersion4(), "micro-models-agent", {
33744
33928
  info: (m) => process.stderr.write(pc2.dim(m) + `
33745
33929
  `),
33746
33930
  warn: (m) => process.stderr.write(pc2.yellow(m) + `
@@ -33783,7 +33967,8 @@ async function main() {
33783
33967
  contextLimit: result2.contextLimit ?? null,
33784
33968
  promptTokens: result2.promptTokens ?? null,
33785
33969
  completionTokens: result2.completionTokens ?? null,
33786
- totalTokens: result2.totalTokens ?? null
33970
+ totalTokens: result2.totalTokens ?? null,
33971
+ totalCost: result2.totalCost ?? null
33787
33972
  }, null, 2));
33788
33973
  process.stdout.write(`
33789
33974
  `);
@@ -33798,7 +33983,7 @@ async function main() {
33798
33983
  if (ev.type === "start") {
33799
33984
  renderer.toolStart(ev.tool, ev.args, undefined, ev.icon);
33800
33985
  } else {
33801
- renderer.toolEnd(ev.tool, ev.duration ?? 0, ev.error, ev.ctxDelta);
33986
+ renderer.toolEnd(ev.tool, ev.duration ?? 0, ev.error, ev.ctxDelta, ev.costUsd);
33802
33987
  }
33803
33988
  }, (phase) => {
33804
33989
  if (phase === "thinking") {