micro-models-agent 2.10.0 → 2.12.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 (359) hide show
  1. package/CHANGELOG.md +33 -0
  2. package/dist/assets/app.js +22 -4
  3. package/dist/assets/index.html +29 -0
  4. package/dist/assets/js/dom.js +2 -1
  5. package/dist/assets/js/feed.js +38 -26
  6. package/dist/assets/js/format.js +1 -1
  7. package/dist/assets/js/rail.js +114 -0
  8. package/dist/assets/js/settings-controls.js +2 -2
  9. package/dist/assets/js/settings.js +246 -51
  10. package/dist/assets/js/store.js +3 -0
  11. package/dist/assets/js/tabs.js +104 -2
  12. package/dist/assets/styles.css +215 -66
  13. package/dist/cli/cache-line.js +1 -0
  14. package/dist/cli/command-suggest.js +5 -4
  15. package/dist/cli/commands.js +231 -122
  16. package/dist/cli/completer.js +132 -31
  17. package/dist/cli/index.js +1 -0
  18. package/dist/cli/json-payload.js +4 -4
  19. package/dist/cli/main.js +166 -61
  20. package/dist/cli/onboarding-commands.js +126 -0
  21. package/dist/cli/plugin-commands.js +2 -1
  22. package/dist/cli/relaunch.js +16 -13
  23. package/dist/cli/repl-commands-lsp.js +75 -0
  24. package/dist/cli/repl-commands-skills.js +105 -0
  25. package/dist/cli/repl-commands.js +589 -266
  26. package/dist/cli/repl.js +436 -177
  27. package/dist/cli/run-result.js +5 -6
  28. package/dist/cli/security-commands.js +37 -28
  29. package/dist/cli/setup-order.js +4 -55
  30. package/dist/cli/setup-prompt.js +3 -2
  31. package/dist/cli/setup.js +27 -107
  32. package/dist/cli/web-command.js +98 -0
  33. package/dist/config/budget.js +5 -5
  34. package/dist/config/config.js +103 -96
  35. package/dist/config/defaults.js +38 -8
  36. package/dist/config/domains.js +24 -27
  37. package/dist/config/env.js +46 -0
  38. package/dist/config/experts.js +2 -0
  39. package/dist/config/index.js +1 -0
  40. package/dist/config/paths.js +56 -0
  41. package/dist/config/redact.js +44 -0
  42. package/dist/config/registry-extra.js +334 -0
  43. package/dist/config/registry.js +584 -0
  44. package/dist/config/security.js +35 -36
  45. package/dist/config/timeouts.js +74 -0
  46. package/dist/config/utils.js +16 -15
  47. package/dist/core/agent/artifact-progress.js +59 -0
  48. package/dist/core/agent/artifact-resolve.js +79 -0
  49. package/dist/core/agent/audit-gate.js +7 -3
  50. package/dist/core/agent/compaction.js +2 -2
  51. package/dist/core/agent/constants.js +33 -4
  52. package/dist/core/agent/context-log.js +454 -0
  53. package/dist/core/agent/context-renderer.js +5 -0
  54. package/dist/core/agent/critic-gate.js +132 -0
  55. package/dist/core/agent/hallucination-gate.js +148 -38
  56. package/dist/core/agent/loop-state.js +15 -0
  57. package/dist/core/agent/prefix-monitor.js +1 -1
  58. package/dist/core/agent/reasoning-resolver.js +10 -1
  59. package/dist/core/agent/token-tracker.js +7 -4
  60. package/dist/core/agent/tool-batch.js +93 -18
  61. package/dist/core/agent/tool-images.js +18 -0
  62. package/dist/core/agent/tool-output.js +65 -11
  63. package/dist/core/agent/tool-pairing.js +60 -0
  64. package/dist/core/agent-moe.js +25 -24
  65. package/dist/core/agent.js +429 -108
  66. package/dist/core/bootstrap/agent-phase.js +66 -0
  67. package/dist/core/bootstrap/config-phase.js +86 -0
  68. package/dist/core/bootstrap/modules-phase.js +269 -0
  69. package/dist/core/bootstrap/provider-phase.js +183 -0
  70. package/dist/core/bootstrap/session-phase.js +204 -0
  71. package/dist/core/bootstrap/state.js +94 -0
  72. package/dist/core/bootstrap/workspace-phase.js +115 -0
  73. package/dist/core/bootstrap.js +92 -660
  74. package/dist/core/crash-handler.js +17 -7
  75. package/dist/core/environment.js +37 -12
  76. package/dist/core/host-plan.js +43 -0
  77. package/dist/core/host.js +23 -0
  78. package/dist/core/index.js +1 -0
  79. package/dist/core/prompt-builder.js +17 -1
  80. package/dist/core/prompt-overflow.js +42 -43
  81. package/dist/core/session-logger.js +122 -30
  82. package/dist/core/system-prompt.js +117 -0
  83. package/dist/core/version.js +6 -4
  84. package/dist/core/web-host.js +34 -0
  85. package/dist/core/workspace.js +19 -15
  86. package/dist/i18n/en.json +106 -21
  87. package/dist/i18n/index.js +37 -3
  88. package/dist/i18n/ru.json +109 -21
  89. package/dist/index.js +7 -3
  90. package/dist/llm/image-utils.js +55 -64
  91. package/dist/llm/llm-errors.js +9 -0
  92. package/dist/llm/model-loader.js +10 -32
  93. package/dist/llm/models-dev.js +121 -0
  94. package/dist/llm/openai-compat.js +146 -73
  95. package/dist/llm/orchestrator.js +33 -11
  96. package/dist/llm/provider-budget.js +2 -2
  97. package/dist/llm/provider-context.js +233 -0
  98. package/dist/llm/provider.js +1 -1
  99. package/dist/llm/response.js +5 -0
  100. package/dist/llm/token-counter.js +27 -11
  101. package/dist/logger/app-logger.js +48 -22
  102. package/dist/logger/file-log.js +28 -19
  103. package/dist/logger/index.js +1 -0
  104. package/dist/main.js +24285 -22447
  105. package/dist/migration/backup.js +14 -3
  106. package/dist/migration/detect.js +12 -3
  107. package/dist/migration/index.js +1 -0
  108. package/dist/modules/artifacts/store.js +9 -8
  109. package/dist/modules/browser/actions.js +6 -0
  110. package/dist/modules/browser/bridge-client.js +14 -12
  111. package/dist/modules/browser/bridge-path.js +4 -4
  112. package/dist/modules/browser/console-buffer.js +37 -0
  113. package/dist/modules/browser/cookie-store.js +5 -0
  114. package/dist/modules/browser/driver-types.js +1 -0
  115. package/dist/modules/browser/driver.js +19 -11
  116. package/dist/modules/browser/index.js +3 -1
  117. package/dist/modules/browser/module.js +2 -1
  118. package/dist/modules/browser/session.js +10 -30
  119. package/dist/modules/browser/snapshot.js +19 -13
  120. package/dist/modules/browser/types.js +1 -0
  121. package/dist/modules/certification/cli.js +28 -20
  122. package/dist/modules/certification/fact-checker.js +9 -1
  123. package/dist/modules/certification/loader.js +9 -2
  124. package/dist/modules/certification/manifest.js +83 -21
  125. package/dist/modules/certification/runner.js +23 -13
  126. package/dist/modules/certification/scenarios.js +20 -20
  127. package/dist/modules/certification/syntax-scenarios.js +1 -2
  128. package/dist/modules/context/chunk-query.js +11 -9
  129. package/dist/modules/context/fact-extractor.js +37 -39
  130. package/dist/modules/context/index.js +1 -0
  131. package/dist/modules/context/manager.js +106 -80
  132. package/dist/modules/critic/client.js +176 -0
  133. package/dist/modules/critic/evidence.js +81 -0
  134. package/dist/modules/critic/provider.js +45 -0
  135. package/dist/modules/critic/tools.js +78 -0
  136. package/dist/modules/critic/types.js +1 -0
  137. package/dist/modules/execution/audit-runners.js +28 -34
  138. package/dist/modules/execution/auditor.js +53 -49
  139. package/dist/modules/execution/execution-plugin.js +142 -102
  140. package/dist/modules/execution/index.js +1 -1
  141. package/dist/modules/execution/input-from.js +37 -13
  142. package/dist/modules/execution/module.js +368 -191
  143. package/dist/modules/execution/moe-executor.js +53 -26
  144. package/dist/modules/execution/plan-actions.js +320 -202
  145. package/dist/modules/execution/plan-checks.js +35 -0
  146. package/dist/modules/execution/plan-coverage.js +36 -33
  147. package/dist/modules/execution/plan-steps.js +11 -3
  148. package/dist/modules/execution/plan-store.js +83 -17
  149. package/dist/modules/execution/plan-tool.js +89 -35
  150. package/dist/modules/execution/plan-validator.js +30 -10
  151. package/dist/modules/execution/planner.js +22 -13
  152. package/dist/modules/execution/stuck-detector.js +196 -93
  153. package/dist/modules/execution/tracker.js +22 -8
  154. package/dist/modules/execution/verifier.js +69 -48
  155. package/dist/modules/execution/windows-commands.js +12 -12
  156. package/dist/modules/hallucination/artifact-claim.js +93 -0
  157. package/dist/modules/hallucination/confidence.js +13 -11
  158. package/dist/modules/hallucination/consistency.js +10 -2
  159. package/dist/modules/hallucination/detector.js +10 -5
  160. package/dist/modules/hallucination/factual.js +43 -26
  161. package/dist/modules/hallucination/index.js +1 -0
  162. package/dist/modules/hallucination/js-identifiers.js +44 -45
  163. package/dist/modules/hallucination/llm-judge.js +17 -12
  164. package/dist/modules/hallucination/success-claim.js +59 -0
  165. package/dist/modules/indexer/cache.js +52 -4
  166. package/dist/modules/indexer/index.js +1 -0
  167. package/dist/modules/indexer/map-command.js +2 -4
  168. package/dist/modules/indexer/map-select.js +16 -16
  169. package/dist/modules/indexer/module.js +47 -12
  170. package/dist/modules/indexer/project-profile.js +8 -7
  171. package/dist/modules/indexer/symbols.js +15 -15
  172. package/dist/modules/indexer/walker.js +159 -29
  173. package/dist/modules/lsp/check-tool.js +7 -5
  174. package/dist/modules/lsp/client.js +39 -39
  175. package/dist/modules/lsp/command.js +17 -24
  176. package/dist/modules/lsp/config.js +12 -11
  177. package/dist/modules/lsp/index.js +1 -0
  178. package/dist/modules/lsp/module.js +48 -46
  179. package/dist/modules/lsp/probe.js +13 -14
  180. package/dist/modules/lsp/project-root.js +14 -17
  181. package/dist/modules/lsp/startup-check.js +18 -16
  182. package/dist/modules/mcp/client.js +59 -62
  183. package/dist/modules/mcp/index.js +1 -0
  184. package/dist/modules/mcp/module.js +66 -37
  185. package/dist/modules/mcp/registry.js +5 -0
  186. package/dist/modules/memory/index.js +1 -0
  187. package/dist/modules/memory/module.js +12 -8
  188. package/dist/modules/memory/search.js +4 -1
  189. package/dist/modules/memory/store.js +40 -2
  190. package/dist/modules/onboarding/init.js +47 -0
  191. package/dist/modules/onboarding/meet.js +30 -0
  192. package/dist/modules/onboarding/mode.js +30 -0
  193. package/dist/modules/onboarding/prompts.js +43 -0
  194. package/dist/modules/pipelines/engine.js +10 -0
  195. package/dist/modules/pipelines/index.js +1 -0
  196. package/dist/modules/pipelines/parser.js +4 -1
  197. package/dist/modules/pipelines/template.js +4 -0
  198. package/dist/modules/plugins/builtin/lint-on-write.js +80 -67
  199. package/dist/modules/plugins/builtin/notify.js +2 -0
  200. package/dist/modules/plugins/index.js +1 -0
  201. package/dist/modules/plugins/loader.js +18 -3
  202. package/dist/modules/plugins/manager.js +37 -17
  203. package/dist/modules/pricing/index.js +10 -11
  204. package/dist/modules/pricing/prices.js +12 -12
  205. package/dist/modules/processes/index.js +1 -0
  206. package/dist/modules/processes/kill-tree.js +27 -31
  207. package/dist/modules/processes/registry.js +44 -25
  208. package/dist/modules/processes/runner.js +4 -4
  209. package/dist/modules/providers/capabilities.js +28 -0
  210. package/dist/modules/providers/create.js +3 -4
  211. package/dist/modules/providers/factory.js +7 -7
  212. package/dist/modules/providers/fallback.js +12 -12
  213. package/dist/modules/providers/health.js +4 -4
  214. package/dist/modules/providers/manager.js +50 -19
  215. package/dist/modules/providers/naming.js +15 -0
  216. package/dist/modules/providers/preflight.js +71 -0
  217. package/dist/modules/providers/presets.js +39 -8
  218. package/dist/modules/providers/registry.js +7 -2
  219. package/dist/modules/reasoning/policy.js +8 -6
  220. package/dist/modules/reasoning/probe.js +30 -25
  221. package/dist/modules/security/audit-log.js +19 -36
  222. package/dist/modules/security/audit-notifier.js +35 -75
  223. package/dist/modules/security/command-validator.js +99 -51
  224. package/dist/modules/security/content-scanner.js +8 -8
  225. package/dist/modules/security/data-sanitizer.js +9 -16
  226. package/dist/modules/security/encryption.js +32 -52
  227. package/dist/modules/security/index.js +2 -1
  228. package/dist/modules/security/network-validator.js +120 -43
  229. package/dist/modules/security/path-validator.js +61 -46
  230. package/dist/modules/security/protected-paths.js +73 -0
  231. package/dist/modules/security/rate-limiter.js +17 -49
  232. package/dist/modules/security/security-policies.js +25 -57
  233. package/dist/modules/security/session-encryption.js +32 -71
  234. package/dist/modules/security/session-isolation.js +15 -28
  235. package/dist/modules/session/auto-name.js +63 -0
  236. package/dist/modules/session/export.js +98 -0
  237. package/dist/modules/session/index.js +1 -0
  238. package/dist/modules/session/manager.js +79 -28
  239. package/dist/modules/session/module.js +4 -3
  240. package/dist/modules/session/store.js +57 -20
  241. package/dist/modules/setup/answers.js +35 -0
  242. package/dist/modules/setup/apply.js +79 -0
  243. package/dist/modules/setup/discovery.js +72 -0
  244. package/dist/modules/skills/index.js +1 -0
  245. package/dist/modules/skills/loader.js +9 -1
  246. package/dist/modules/skills/module.js +11 -0
  247. package/dist/modules/updater/changelog-reader.js +15 -16
  248. package/dist/modules/updater/checker.js +9 -4
  249. package/dist/modules/updater/dev-detect.js +7 -6
  250. package/dist/modules/updater/index.js +1 -0
  251. package/dist/modules/updater/module.js +17 -15
  252. package/dist/modules/user-profile/compressor.js +2 -0
  253. package/dist/modules/user-profile/index.js +1 -0
  254. package/dist/modules/user-profile/profile.js +10 -1
  255. package/dist/modules/webui/answer-api.js +29 -0
  256. package/dist/modules/webui/assets.js +50 -0
  257. package/dist/modules/webui/body.js +21 -0
  258. package/dist/modules/webui/commands-settings.js +209 -0
  259. package/dist/modules/webui/commands-shared.js +60 -0
  260. package/dist/modules/webui/commands.js +174 -0
  261. package/dist/modules/webui/config-api.js +134 -0
  262. package/dist/modules/webui/file-api.js +202 -0
  263. package/dist/modules/webui/forward.js +159 -0
  264. package/dist/modules/webui/history-api.js +112 -0
  265. package/dist/modules/webui/host-state.js +60 -0
  266. package/dist/modules/webui/i18n-api.js +9 -0
  267. package/dist/modules/webui/limits.js +6 -0
  268. package/dist/modules/webui/log-forward.js +20 -0
  269. package/dist/modules/webui/memory-commands.js +64 -0
  270. package/dist/modules/webui/model-cache.js +18 -0
  271. package/dist/modules/webui/module.js +148 -0
  272. package/dist/modules/webui/persist.js +24 -0
  273. package/dist/modules/webui/prompt-io.js +97 -0
  274. package/dist/modules/webui/providers-api.js +337 -0
  275. package/dist/modules/webui/providers-view.js +56 -0
  276. package/dist/modules/webui/reasoning-view.js +15 -0
  277. package/dist/modules/webui/run-agent.js +81 -0
  278. package/dist/modules/webui/server.js +284 -0
  279. package/dist/modules/webui/sessions-api.js +178 -0
  280. package/dist/modules/webui/settings-api.js +561 -0
  281. package/dist/modules/webui/setup-api.js +201 -0
  282. package/dist/modules/webui/state.js +74 -0
  283. package/dist/modules/webui/util.js +261 -0
  284. package/dist/output/bus.js +7 -2
  285. package/dist/output/channel.js +80 -28
  286. package/dist/output/format.js +2 -1
  287. package/dist/output/index.js +1 -0
  288. package/dist/output/json-sink.js +5 -3
  289. package/dist/output/machine.js +4 -3
  290. package/dist/output/session-sink.js +4 -4
  291. package/dist/tools/approve.js +4 -0
  292. package/dist/tools/attach-image.js +5 -4
  293. package/dist/tools/auto-fixer.js +26 -44
  294. package/dist/tools/auto-tags.js +83 -0
  295. package/dist/tools/bash.js +193 -116
  296. package/dist/tools/browser.js +76 -31
  297. package/dist/tools/chunk-query.js +14 -6
  298. package/dist/tools/create-dir.js +9 -5
  299. package/dist/tools/delete-file.js +9 -5
  300. package/dist/tools/download-file.js +32 -7
  301. package/dist/tools/edit-file.js +52 -14
  302. package/dist/tools/enable-tools.js +6 -6
  303. package/dist/tools/executor.js +132 -27
  304. package/dist/tools/file-info.js +3 -1
  305. package/dist/tools/filter-tools.js +3 -3
  306. package/dist/tools/glob-tool.js +4 -1
  307. package/dist/tools/grep-tool.js +13 -10
  308. package/dist/tools/hidden-tools-block.js +6 -6
  309. package/dist/tools/index.js +16 -8
  310. package/dist/tools/list-dir.js +4 -2
  311. package/dist/tools/load-skill.js +7 -0
  312. package/dist/tools/mcp-call.js +15 -4
  313. package/dist/tools/meet-done.js +14 -0
  314. package/dist/tools/move-file.js +14 -7
  315. package/dist/tools/path-utils.js +29 -29
  316. package/dist/tools/pipeline-run.js +29 -7
  317. package/dist/tools/preview.js +1 -1
  318. package/dist/tools/process-ids.js +31 -0
  319. package/dist/tools/process-kill.js +9 -16
  320. package/dist/tools/process-list.js +1 -0
  321. package/dist/tools/process-log.js +11 -16
  322. package/dist/tools/process-wait.js +63 -0
  323. package/dist/tools/prompt-io.js +4 -3
  324. package/dist/tools/question.js +172 -25
  325. package/dist/tools/read-file.js +55 -34
  326. package/dist/tools/recall.js +14 -8
  327. package/dist/tools/registry.js +6 -5
  328. package/dist/tools/remember.js +8 -4
  329. package/dist/tools/scope-request.js +11 -6
  330. package/dist/tools/search-history.js +5 -2
  331. package/dist/tools/session-info.js +2 -0
  332. package/dist/tools/set-thinking.js +8 -4
  333. package/dist/tools/subagent.js +59 -39
  334. package/dist/tools/syntax-validator.js +292 -90
  335. package/dist/tools/user-input.js +22 -18
  336. package/dist/tools/web-browse.js +9 -3
  337. package/dist/tools/web-fetch.js +12 -23
  338. package/dist/tools/web-search.js +7 -5
  339. package/dist/tools/write-file.js +45 -15
  340. package/dist/ui/action-log.js +13 -0
  341. package/dist/ui/box.js +4 -3
  342. package/dist/ui/colors.js +2 -0
  343. package/dist/ui/diff.js +6 -5
  344. package/dist/ui/index.js +1 -0
  345. package/dist/ui/line-editor.js +230 -122
  346. package/dist/ui/line-math.js +10 -2
  347. package/dist/ui/md-formatter.js +57 -37
  348. package/dist/ui/output.js +8 -3
  349. package/dist/ui/plan-view.js +21 -10
  350. package/dist/ui/renderer.js +393 -67
  351. package/dist/ui/spinner.js +16 -5
  352. package/dist/ui/table.js +15 -17
  353. package/dist/ui/theme.js +143 -0
  354. package/dist/utils/child-run.js +20 -0
  355. package/dist/utils/error.js +1 -1
  356. package/dist/utils/index.js +2 -0
  357. package/dist/utils/retry.js +2 -2
  358. package/dist/utils/truncate.js +1 -1
  359. package/package.json +1 -1
@@ -1,11 +1,11 @@
1
1
  /**
2
- * Built-in price table (USD per 1M tokens) for OpenCode Zen / Go models.
3
- * Values from https://opencode.ai/docs/zen/ and /docs/go/ (August 2026).
4
- * Model ids are stored WITHOUT the `opencode/` or `opencode-go/` prefix so a
5
- * single table serves both providers; lookup strips the prefix.
2
+ * Встроенная таблица цен (USD за 1M токенов) для моделей OpenCode Zen / Go.
3
+ * Значения из https://opencode.ai/docs/zen/ и /docs/go/ (август 2026).
4
+ * Id хранятся БЕЗ префиксов `opencode/` и `opencode-go/`, чтобы одна таблица
5
+ * обслуживала обоих провайдеров; лукап срезает префикс.
6
6
  */
7
7
  const ZEN_PRICES = {
8
- // Free models
8
+ // Бесплатные модели
9
9
  "big-pickle": { input: 0, output: 0 },
10
10
  "mimo-v2.5-free": { input: 0, output: 0 },
11
11
  "hy3-free": { input: 0, output: 0 },
@@ -32,7 +32,7 @@ const ZEN_PRICES = {
32
32
  "qwen3.6-plus": { input: 0.5, output: 3.0 },
33
33
  "qwen3.5-plus": { input: 0.2, output: 1.2 },
34
34
  "qwen3.8-max": { input: 2.5, output: 7.5 },
35
- // DeepSeek (off-peak)
35
+ // DeepSeek (внепиковые тарифы)
36
36
  "deepseek-v4-pro": { input: 0.66, output: 1.98 },
37
37
  "deepseek-v4-flash": { input: 0.22, output: 0.66 },
38
38
  // Claude
@@ -59,7 +59,7 @@ const ZEN_PRICES = {
59
59
  "grok-build-0.1": { input: 1, output: 2 },
60
60
  // Muse Spark
61
61
  "muse-spark-1.2": { input: 1.25, output: 4.25 },
62
- // GPT-5.x (Zen pricing; Go may differ)
62
+ // GPT-5.x (цены Zen; у Go могут отличаться)
63
63
  "gpt-5.6-sol": { input: 5, output: 30 },
64
64
  "gpt-5.6-terra": { input: 2, output: 12 },
65
65
  "gpt-5.6-luna": { input: 0.2, output: 1.2 },
@@ -81,9 +81,9 @@ const ZEN_PRICES = {
81
81
  "gpt-5-codex": { input: 1.07, output: 8.5 },
82
82
  "gpt-5-nano": { input: 0.05, output: 0.4 },
83
83
  };
84
- /** Provider prefixes stripped before a price lookup. */
84
+ /** Префиксы провайдеров, срезаемые перед поиском цены. */
85
85
  const PROVIDER_PREFIXES = ["opencode-go/", "opencode/", "openai/", "anthropic/"];
86
- /** Normalize a model id to its bare form for the price table lookup. */
86
+ /** Нормализует id модели к голой форме для поиска в таблице цен. */
87
87
  export function normalizeModelId(model) {
88
88
  let id = model.trim();
89
89
  for (const prefix of PROVIDER_PREFIXES) {
@@ -92,11 +92,11 @@ export function normalizeModelId(model) {
92
92
  break;
93
93
  }
94
94
  }
95
- // Strip a vendor path like qwen/qwen3.5-9b -> qwen3.5-9b (keeps bare ids).
95
+ // Срезаем вендорный путь вида qwen/qwen3.5-9b -> qwen3.5-9b (голые id не трогаем).
96
96
  const parts = id.split("/");
97
97
  return parts[parts.length - 1];
98
98
  }
99
- /** Resolve the price for a model id. Overrides win, then the builtin table. */
99
+ /** Резолвит цену модели. Оверрайды побеждают, затем встроенная таблица. */
100
100
  export function resolvePrice(model, config) {
101
101
  if (!config?.enabled)
102
102
  return undefined;
@@ -135,7 +135,7 @@ export function calculateCostDetailed(model, promptTokens, completionTokens, con
135
135
  export function calculateCost(model, promptTokens, completionTokens, config, cache) {
136
136
  return calculateCostDetailed(model, promptTokens, completionTokens, config, cache)?.cost;
137
137
  }
138
- /** Format a USD cost for display. Zero and very small amounts stay readable. */
138
+ /** Форматирует USD-стоимость для показа. Ноль и копейки остаются читаемыми. */
139
139
  export function formatCost(cost) {
140
140
  if (cost === 0)
141
141
  return "$0.00";
@@ -1,3 +1,4 @@
1
+ // Публичная поверхность фоновых процессов: реестр, килл дерева и kill-колбэки тулов.
1
2
  export { registerKillable, unregisterKillable, killByCallId } from "./runner";
2
3
  export { processRegistry } from "./registry";
3
4
  export { killTree } from "./kill-tree";
@@ -1,45 +1,41 @@
1
- import { spawnSync } from "child_process";
1
+ // Кроссплатформенный килл дерева процессов, неблокирующий (без stall event loop).
2
+ import { spawn } from "child_process";
2
3
  import { platform } from "os";
3
- /** Synchronous pause without blocking the event loop (via Atomics.wait). */
4
- function sleepSync(ms) {
5
- try {
6
- Atomics.wait(new Int32Array(new SharedArrayBuffer(4)), 0, 0, ms);
7
- }
8
- catch {
9
- /* ignore */
10
- }
11
- }
4
+ /** Fire a `taskkill /T /F` and resolve when it exits (never rejects). */
12
5
  function taskkillPid(pid) {
13
- try {
14
- spawnSync("taskkill", ["/pid", String(pid), "/T", "/F"], {
15
- windowsHide: true,
16
- stdio: "ignore",
17
- timeout: 5000,
18
- });
19
- }
20
- catch {
21
- /* already dead */
22
- }
6
+ return new Promise((resolve) => {
7
+ try {
8
+ const child = spawn("taskkill", ["/pid", String(pid), "/T", "/F"], {
9
+ windowsHide: true,
10
+ stdio: "ignore",
11
+ });
12
+ child.on("close", () => resolve());
13
+ child.on("error", () => resolve());
14
+ }
15
+ catch {
16
+ /* уже мёртв / нет taskkill */
17
+ }
18
+ });
23
19
  }
24
20
  /**
25
- * Kill a spawned process tree — cross-platform.
21
+ * Убивает дерево спавненного процесса — кроссплатформенно, неблокирующе.
26
22
  *
27
- * Windows: double `taskkill /T /F` with a 150ms settle gap. The second pass
28
- * catches late-attaching children that were still being created during the
29
- * first tree walk (e.g. `cmd.exe → node → tsserver` chains where node is
30
- * still starting up when cmd is killed).
23
+ * Windows: два прохода `taskkill /T /F` с паузой 150мс (второй добирает детей,
24
+ * ещё создававшихся во время первого обхода дерева, напр. `cmd → node →
25
+ * tsserver`). Оба АСИНХРОННЫ: прежние `spawnSync` + `Atomics.wait` стопили
26
+ * event loop (фроз UI/стрима) до ~10с на процесс при шатдауне.
31
27
  *
32
- * POSIX: process-group kill (`-pid`). Falls back to `SIGKILL` on the direct
33
- * child when the group kill fails (e.g. non-detached process).
28
+ * POSIX: килл группы (`-pid`), при неудаче — `SIGKILL` прямому ребёнку
29
+ * (напр. не-detached процесс).
34
30
  */
35
31
  export function killTree(child) {
36
32
  const pid = child.pid;
37
33
  if (!pid)
38
34
  return;
39
35
  if (platform() === "win32") {
40
- taskkillPid(pid);
41
- sleepSync(150);
42
- taskkillPid(pid);
36
+ void taskkillPid(pid).then(() => {
37
+ setTimeout(() => void taskkillPid(pid), 150);
38
+ });
43
39
  return;
44
40
  }
45
41
  try {
@@ -50,7 +46,7 @@ export function killTree(child) {
50
46
  child.kill("SIGKILL");
51
47
  }
52
48
  catch {
53
- /* already dead */
49
+ /* уже мёртв */
54
50
  }
55
51
  }
56
52
  }
@@ -1,10 +1,14 @@
1
+ // Реестр фоновых процессов: спавн, буферизация лога, килл, ожидание выхода.
1
2
  import { spawn, spawnSync } from "child_process";
2
3
  import { platform } from "os";
3
4
  import { killTree } from "./kill-tree";
4
5
  const MAX_LOG_LINES = 2000;
6
+ /** Кап одной незавершённой строки, чтобы дамп без переводов не дал OOM. */
7
+ const MAX_PARTIAL_CHARS = 64 * 1024;
8
+ const MAX_PARTIAL_BYTES = 64 * 1024;
5
9
  const MAX_KEPT_PROCESSES = 20;
6
10
  let seq = 0;
7
- /** OEM decoder (Russian CP866 / active code page) — cached after first use. */
11
+ /** OEM-декодер (русская CP866 / активная кодовая страница) — кеш после первого вызова. */
8
12
  let oemDecoder;
9
13
  function getOemDecoder() {
10
14
  if (oemDecoder !== undefined)
@@ -19,7 +23,7 @@ function getOemDecoder() {
19
23
  const m = cpOut ? cpOut.toString("latin1").match(/(\d+)/) : null;
20
24
  if (m) {
21
25
  try {
22
- oemDecoder = new TextDecoder("ibm" + m[1]);
26
+ oemDecoder = new TextDecoder(`ibm${m[1]}`);
23
27
  }
24
28
  catch {
25
29
  oemDecoder = null;
@@ -40,19 +44,19 @@ function getOemDecoder() {
40
44
  return oemDecoder;
41
45
  }
42
46
  /**
43
- * Decode one complete line of output to UTF-8.
47
+ * Декодирует одну готовую строку вывода в UTF-8.
44
48
  *
45
- * Modern tools (Bun, Node, npm, git) write UTF-8 into the pipe regardless of
46
- * the console code page, while built-in cmd.exe commands (echo, type, dir)
47
- * emit the OEM code page (CP866 on Russian Windows). Try strict UTF-8 first;
48
- * fall back to the OEM decoder when the bytes are not valid UTF-8.
49
+ * Современные тулы (Bun, Node, npm, git) пишут UTF-8 в пайп независимо от
50
+ * кодовой страницы консоли, а встроенные команды cmd.exe (echo, type, dir) —
51
+ * OEM-страницу (CP866 на русской Windows). Сначала строгий UTF-8; если байты
52
+ * невалидны — откат на OEM-декодер.
49
53
  */
50
54
  function decodeLineToUtf8(buf) {
51
55
  try {
52
56
  return new TextDecoder("utf-8", { fatal: true }).decode(buf);
53
57
  }
54
58
  catch {
55
- /* not valid UTF-8 → OEM code page output */
59
+ /* невалидный UTF-8 → вывод в OEM-кодировке */
56
60
  }
57
61
  const oem = getOemDecoder();
58
62
  if (oem) {
@@ -60,19 +64,20 @@ function decodeLineToUtf8(buf) {
60
64
  return oem.decode(buf);
61
65
  }
62
66
  catch {
63
- /* unknown encoding — latin1 fallback */
67
+ /* неизвестная кодировка — откат на latin1 */
64
68
  }
65
69
  }
66
70
  return buf.toString("latin1");
67
71
  }
72
+ /** Реэкспорт килла дерева для потребителей реестра. */
68
73
  export { killTree } from "./kill-tree";
69
74
  class ProcessRegistry {
70
75
  procs = new Map();
71
76
  children = new Map();
72
77
  exitWaiters = new Map();
73
78
  /**
74
- * Start a command. The returned entry buffers output and reports status; a
75
- * call may check `waitForExit(id)` to learn when (if ever) it finishes.
79
+ * Запускает команду. Возвращённая запись буферизует вывод и отдаёт статус;
80
+ * дождаться завершения можно через `waitForExit(id)`.
76
81
  */
77
82
  start(command, cwd, sessionId) {
78
83
  const id = `proc_${Date.now()}_${++seq}`;
@@ -126,12 +131,17 @@ class ProcessRegistry {
126
131
  for (const line of lines) {
127
132
  pushLine(line);
128
133
  }
134
+ // Сбрасываем очень длинную частичную строку вместо безлимитной буферизации.
135
+ if (buf.length > MAX_PARTIAL_CHARS) {
136
+ pushLine(buf);
137
+ buf = "";
138
+ }
129
139
  return;
130
140
  }
131
- // Windows: buffer raw bytes and decode per line. Modern tools (Bun, Node,
132
- // npm, git) write UTF-8 into the pipe regardless of the console code
133
- // page; cmd.exe builtins (echo, type, dir) emit the OEM code page. Pick
134
- // the right decoding per line so Russian text survives either way.
141
+ // Windows: копим сырые байты и декодируем построчно. Современные тулы
142
+ // (Bun, Node, npm, git) пишут UTF-8 в пайп независимо от кодовой страницы
143
+ // консоли; встроенные команды cmd.exe (echo, type, dir) — OEM-страницу.
144
+ // Декодировка подбирается построчно, чтобы русский выживал в обоих случаях.
135
145
  byteBuf = byteBuf.length ? Buffer.concat([byteBuf, chunk]) : Buffer.from(chunk);
136
146
  let nl;
137
147
  while ((nl = byteBuf.indexOf(0x0a)) !== -1) {
@@ -139,6 +149,11 @@ class ProcessRegistry {
139
149
  byteBuf = byteBuf.subarray(nl + 1);
140
150
  pushLine(decodeLineToUtf8(raw).replace(/\r$/, ""));
141
151
  }
152
+ // Сбрасываем очень длинную частичную строку вместо безлимитной буферизации.
153
+ if (byteBuf.length > MAX_PARTIAL_BYTES) {
154
+ pushLine(decodeLineToUtf8(byteBuf));
155
+ byteBuf = Buffer.alloc(0);
156
+ }
142
157
  };
143
158
  const flush = () => {
144
159
  if (!isWin) {
@@ -164,9 +179,9 @@ class ProcessRegistry {
164
179
  entry.status = "killed";
165
180
  }
166
181
  entry.spawnError = err.message;
167
- // Write directly to the log, not through `append`: a failed spawn often
168
- // never emits `close`, so the buffered line would never be flushed and
169
- // the log would be empty (observed: "records a spawn error" test).
182
+ // Пишем прямо в лог, не через `append`: упавший спавн часто вообще
183
+ // не эмитит `close`, и буферизованная строка не сбросилась бы —
184
+ // лог остался бы пустым (видно в тесте "records a spawn error").
170
185
  pushLine(`[process error] ${err.message}`);
171
186
  resolveExit();
172
187
  });
@@ -186,15 +201,18 @@ class ProcessRegistry {
186
201
  this.exitWaiters.set(id, { promise, resolve });
187
202
  return entry;
188
203
  }
204
+ /** Список процессов, опционально по сессии. */
189
205
  list(sessionId) {
190
206
  const all = Array.from(this.procs.values());
191
207
  if (!sessionId)
192
208
  return all;
193
209
  return all.filter((p) => p.sessionId === sessionId);
194
210
  }
211
+ /** Процесс по id; undefined, если нет. */
195
212
  get(id) {
196
213
  return this.procs.get(id);
197
214
  }
215
+ /** Лог процесса целиком или хвостом `tail` строк. */
198
216
  getLog(id, tail) {
199
217
  const entry = this.procs.get(id);
200
218
  if (!entry)
@@ -202,7 +220,7 @@ class ProcessRegistry {
202
220
  const lines = tail && tail > 0 ? entry.log.slice(-tail) : entry.log;
203
221
  return lines.join("\n");
204
222
  }
205
- /** Kill a background process tree. Returns false when not found. */
223
+ /** Убивает дерево фонового процесса. False, если не найден. */
206
224
  kill(id) {
207
225
  const entry = this.procs.get(id);
208
226
  if (!entry)
@@ -216,7 +234,7 @@ class ProcessRegistry {
216
234
  }
217
235
  return true;
218
236
  }
219
- /** Kill every managed background process (used on agent shutdown). */
237
+ /** Убивает все управляемые фоновые процессы (при останове агента). Возвращает число. */
220
238
  killAll(sessionId) {
221
239
  const targets = this.list(sessionId);
222
240
  for (const entry of targets) {
@@ -225,13 +243,13 @@ class ProcessRegistry {
225
243
  return targets.length;
226
244
  }
227
245
  /**
228
- * Resolve `true` when the process exits (or fails to spawn) within
229
- * `timeoutMs`, otherwise `false` (still running → a background process).
246
+ * Резолвит `true`, если процесс вышел (или не спавнился) за `timeoutMs`,
247
+ * иначе `false` (всё ещё бежит → фоновый процесс).
230
248
  */
231
249
  waitForExit(id, timeoutMs) {
232
250
  const entry = this.procs.get(id);
233
251
  const waiter = this.exitWaiters.get(id);
234
- if (!entry || entry.status !== "running" || !waiter) {
252
+ if (entry?.status !== "running" || !waiter) {
235
253
  return Promise.resolve(true);
236
254
  }
237
255
  return new Promise((resolve) => {
@@ -243,8 +261,8 @@ class ProcessRegistry {
243
261
  });
244
262
  }
245
263
  /**
246
- * Remove a finished entry (foreground results do not linger). A still-running
247
- * entry is killed first so nothing is orphaned.
264
+ * Удаляет завершённую запись (foreground-результаты не залеживаются).
265
+ * Ещё бегущая сначала убивается, чтобы не осиротеть.
248
266
  */
249
267
  remove(id) {
250
268
  const entry = this.procs.get(id);
@@ -272,4 +290,5 @@ class ProcessRegistry {
272
290
  }
273
291
  }
274
292
  }
293
+ /** Синглтон реестра фоновых процессов. */
275
294
  export const processRegistry = new ProcessRegistry();
@@ -1,13 +1,13 @@
1
1
  const activeChildren = new Map();
2
- /** Register a kill callback for a tool call id (executor timeout/abort). */
2
+ /** Регистрирует kill-колбэк тул-вызова (для таймаута/аборта экзекутора). */
3
3
  export function registerKillable(callId, kill) {
4
4
  activeChildren.set(callId, { kill });
5
5
  }
6
- /** Unregister a tool call's kill callback once its handler finished. */
6
+ /** Снимает kill-колбэк завершившегося хендлера. */
7
7
  export function unregisterKillable(callId) {
8
8
  activeChildren.delete(callId);
9
9
  }
10
- /** Invoke (and drop) the kill callback registered for `callId`. */
10
+ /** Вызывает (и снимает) kill-колбэк для `callId`; false — не было. */
11
11
  export function killByCallId(callId) {
12
12
  const entry = activeChildren.get(callId);
13
13
  if (!entry)
@@ -17,7 +17,7 @@ export function killByCallId(callId) {
17
17
  entry.kill();
18
18
  }
19
19
  catch {
20
- /* already dead */
20
+ /* уже мёртв */
21
21
  }
22
22
  return true;
23
23
  }
@@ -0,0 +1,28 @@
1
+ /**
2
+ * Консервативный фолбэк, когда ни пресет, ни probe, ни конфиг не дали данных.
3
+ * "false" безопаснее "true": неверное "нет vision" ведёт к текстовому
4
+ * snapshot'у, неверное "есть vision" — к отправке картинки, которую бэкенд
5
+ * отвергнет или проигнорирует.
6
+ */
7
+ export const DEFAULT_MODEL_CAPABILITIES = {
8
+ vision: false,
9
+ tools: false,
10
+ };
11
+ /**
12
+ * Единый источник правды о возможностях АКТИВНОЙ модели (данные, не
13
+ * эвристика по имени — правило #10). Приоритет слоёв, от высшего к низшему:
14
+ *
15
+ * 1. явный конфиг-оверрайд пользователя (`config.modelCapabilities[model]`);
16
+ * 2. живой probe провайдера (LM Studio native API и т.п.);
17
+ * 3. пресет провайдера (`providers/presets.ts`).
18
+ *
19
+ * Всегда возвращает новый объект: вызывающий не рискует мутировать общий
20
+ * пресет или конфиг. Отсутствующие в probe поля берутся из нижнего слоя —
21
+ * probe может уточнять только часть возможностей.
22
+ */
23
+ export function resolveModelCapabilities(preset, probe, override) {
24
+ const base = preset
25
+ ? { vision: preset.vision, tools: preset.tools }
26
+ : { ...DEFAULT_MODEL_CAPABILITIES };
27
+ return { ...base, ...(probe ?? {}), ...(override ?? {}) };
28
+ }
@@ -1,9 +1,8 @@
1
1
  import { BUILTIN_PROVIDERS } from "./presets";
2
2
  import { ProviderRegistry as Registry } from "./registry";
3
3
  /**
4
- * The single entry point for building a provider. Unknown types fall back to
5
- * the OpenAI-compatible provider (backward compatible with legacy configs that
6
- * use a custom `type` + baseUrl).
4
+ * Единая точка сборки провайдера. Неизвестные типы откатываются на
5
+ * OpenAI-совместимый (совместимость с легаси-конфигами: кастомный `type` + baseUrl).
7
6
  */
8
7
  export function createProvider(type, opts, registry = defaultRegistry()) {
9
8
  const spec = registry.get(type);
@@ -12,7 +11,7 @@ export function createProvider(type, opts, registry = defaultRegistry()) {
12
11
  }
13
12
  return spec.create(opts);
14
13
  }
15
- /** Registry preloaded with all builtin provider presets. */
14
+ /** Реестр, предзагруженный всеми builtin-пресетами. */
16
15
  export function defaultRegistry() {
17
16
  const registry = new Registry();
18
17
  for (const spec of BUILTIN_PROVIDERS) {
@@ -1,14 +1,14 @@
1
1
  import { ProviderManager } from "./manager";
2
2
  import { FallbackProvider } from "./fallback";
3
3
  /**
4
- * Shared factory for building the ACTIVE provider from a config, used by both
5
- * bootstrap and Agent.setProvider/reconfigure. Previously the three
6
- * construction sites drifted — bootstrap wrapped the manager in
7
- * FallbackProvider when `fallback && entries > 1`, but a hot-swap
8
- * (setProvider) rebuilt a bare manager and silently dropped failover (B4).
9
- * The wrapper reads `manager.active` live, so switching the manager after
10
- * build keeps the failover active.
4
+ * Общая фабрика АКТИВНОГО провайдера из конфига — для bootstrap и
5
+ * Agent.setProvider/reconfigure. Раньше три места сборки дрейфовали: bootstrap
6
+ * оборачивал менеджер в FallbackProvider при `fallback && entries > 1`, а
7
+ * hot-swap (setProvider) пересобирал голый менеджер и молча ронял failover (B4).
8
+ * Обёртка читает `manager.active` живьём, так что переключение менеджера после
9
+ * сборки failover сохраняет.
11
10
  */
11
+ /** Собрать активный провайдер (+ failover-обёртка при entries > 1). */
12
12
  export function buildActiveProvider(config, logger, opts) {
13
13
  const manager = new ProviderManager(config.provider, {
14
14
  contextWindow: config.contextWindow,
@@ -1,14 +1,14 @@
1
1
  import { LlmError } from "../../llm/llm-errors";
2
- /** True when the error is worth failing over to another provider. */
2
+ /** Стоит ли ошибка переключения на другой провайдер. */
3
3
  export function isFailoverError(err) {
4
4
  if (err instanceof Error && err.name === "AbortError")
5
5
  return false;
6
- // HTTP status, attached by openai-compat as a typed LlmError: retryable only.
6
+ // HTTP-статус, прикреплённый openai-compat как типизированный LlmError: только ретраируемые.
7
7
  if (err instanceof LlmError && typeof err.llmStatus === "number") {
8
8
  return err.llmStatus === 429 || err.llmStatus >= 500;
9
9
  }
10
- // Network-level failures by errno-style code (Bun: "ConnectionRefused",
11
- // Node: "ECONNREFUSED", DNS: "ENOTFOUND"/"EAI_AGAIN", etc).
10
+ // Сетевые падения по errno-коду (Bun: "ConnectionRefused",
11
+ // Node: "ECONNREFUSED", DNS: "ENOTFOUND"/"EAI_AGAIN" и т.д.).
12
12
  const e = err;
13
13
  const normCode = (e?.code ?? "").replace(/[-_]/g, "").toLowerCase();
14
14
  if (/^abort/.test(normCode))
@@ -16,15 +16,15 @@ export function isFailoverError(err) {
16
16
  if (/conn(refused|reset|timedout)|enotfound|eai_again|namenotresolved/.test(normCode)) {
17
17
  return true;
18
18
  }
19
- // Network-level failures by message (fetch failed, timeouts, socket resets).
19
+ // Сетевые падения по сообщению (fetch failed, таймауты, сбросы сокета).
20
20
  return /fetch failed|unable to connect|network|econnrefused|enotfound|etimedout|socket hang up|connection refused|connection reset/i.test(e?.message ?? "");
21
21
  }
22
22
  /**
23
- * Wraps a FallbackSource so that retryable failures (429/5xx/network) on the
24
- * active provider transparently switch to the next configured entry and retry
25
- * there. Failover happens ONLY before any chunk was emitted — mid-stream
26
- * failures rethrow to avoid duplicated output. The last provider that served
27
- * a successful call becomes the new active entry (sticky).
23
+ * Оборачивает FallbackSource: ретраируемые падения (429/5xx/сеть) активного
24
+ * провайдера прозрачно переключаются на следующую запись с ретраем там.
25
+ * Failover — ТОЛЬКО до первого чанка: падение посреди стрима пробрасывается,
26
+ * чтобы не дублировать вывод. Последний провайдер с успешным вызовом
27
+ * становится активным (sticky).
28
28
  */
29
29
  export class FallbackProvider {
30
30
  source;
@@ -61,8 +61,8 @@ export class FallbackProvider {
61
61
  return;
62
62
  }
63
63
  catch (err) {
64
- // Mid-stream failure after content was delivered: a restart would
65
- // duplicate chunks — surface the error instead of failing over.
64
+ // Падение посреди стрима после отданного контента: рестарт
65
+ // задублировал бы чанки — пробросить ошибку вместо failover.
66
66
  if (emitted || !isFailoverError(err))
67
67
  throw err;
68
68
  lastError = err;
@@ -1,8 +1,8 @@
1
1
  import { errMsg } from "../../utils";
2
2
  /**
3
- * Probe providers concurrently (bounded by the caller passing few entries)
4
- * and report ✓/✗ per entry. Uses `listModels()` — a free, cheap call — never
5
- * a billed chat completion. Input order is preserved in the output.
3
+ * Пробить провайдеры конкурентно и отчитаться ✓/✗ по каждой записи.
4
+ * Только `listModels()` — бесплатный дешёвый вызов, никогда не платный chat.
5
+ * Порядок входа в выводе сохраняется.
6
6
  */
7
7
  export async function probeProviders(targets, opts) {
8
8
  const timeoutMs = opts?.timeoutMs ?? 5000;
@@ -38,7 +38,7 @@ function withTimeout(promise, ms) {
38
38
  });
39
39
  });
40
40
  }
41
- /** Build probe targets from a name→provider mapping (priority order). */
41
+ /** Собрать цели проб из маппинга имя→провайдер (порядок приоритетов). */
42
42
  export function targetsFromProviders(entries) {
43
43
  return entries.map(({ name, provider }) => ({
44
44
  name,