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.
- package/CHANGELOG.md +33 -0
- package/dist/assets/app.js +22 -4
- package/dist/assets/index.html +29 -0
- package/dist/assets/js/dom.js +2 -1
- package/dist/assets/js/feed.js +38 -26
- package/dist/assets/js/format.js +1 -1
- package/dist/assets/js/rail.js +114 -0
- package/dist/assets/js/settings-controls.js +2 -2
- package/dist/assets/js/settings.js +246 -51
- package/dist/assets/js/store.js +3 -0
- package/dist/assets/js/tabs.js +104 -2
- package/dist/assets/styles.css +215 -66
- package/dist/cli/cache-line.js +1 -0
- package/dist/cli/command-suggest.js +5 -4
- package/dist/cli/commands.js +231 -122
- package/dist/cli/completer.js +132 -31
- package/dist/cli/index.js +1 -0
- package/dist/cli/json-payload.js +4 -4
- package/dist/cli/main.js +166 -61
- package/dist/cli/onboarding-commands.js +126 -0
- package/dist/cli/plugin-commands.js +2 -1
- package/dist/cli/relaunch.js +16 -13
- package/dist/cli/repl-commands-lsp.js +75 -0
- package/dist/cli/repl-commands-skills.js +105 -0
- package/dist/cli/repl-commands.js +589 -266
- package/dist/cli/repl.js +436 -177
- package/dist/cli/run-result.js +5 -6
- package/dist/cli/security-commands.js +37 -28
- package/dist/cli/setup-order.js +4 -55
- package/dist/cli/setup-prompt.js +3 -2
- package/dist/cli/setup.js +27 -107
- package/dist/cli/web-command.js +98 -0
- package/dist/config/budget.js +5 -5
- package/dist/config/config.js +103 -96
- package/dist/config/defaults.js +38 -8
- package/dist/config/domains.js +24 -27
- package/dist/config/env.js +46 -0
- package/dist/config/experts.js +2 -0
- package/dist/config/index.js +1 -0
- package/dist/config/paths.js +56 -0
- package/dist/config/redact.js +44 -0
- package/dist/config/registry-extra.js +334 -0
- package/dist/config/registry.js +584 -0
- package/dist/config/security.js +35 -36
- package/dist/config/timeouts.js +74 -0
- package/dist/config/utils.js +16 -15
- package/dist/core/agent/artifact-progress.js +59 -0
- package/dist/core/agent/artifact-resolve.js +79 -0
- package/dist/core/agent/audit-gate.js +7 -3
- package/dist/core/agent/compaction.js +2 -2
- package/dist/core/agent/constants.js +33 -4
- package/dist/core/agent/context-log.js +454 -0
- package/dist/core/agent/context-renderer.js +5 -0
- package/dist/core/agent/critic-gate.js +132 -0
- package/dist/core/agent/hallucination-gate.js +148 -38
- package/dist/core/agent/loop-state.js +15 -0
- package/dist/core/agent/prefix-monitor.js +1 -1
- package/dist/core/agent/reasoning-resolver.js +10 -1
- package/dist/core/agent/token-tracker.js +7 -4
- package/dist/core/agent/tool-batch.js +93 -18
- package/dist/core/agent/tool-images.js +18 -0
- package/dist/core/agent/tool-output.js +65 -11
- package/dist/core/agent/tool-pairing.js +60 -0
- package/dist/core/agent-moe.js +25 -24
- package/dist/core/agent.js +429 -108
- package/dist/core/bootstrap/agent-phase.js +66 -0
- package/dist/core/bootstrap/config-phase.js +86 -0
- package/dist/core/bootstrap/modules-phase.js +269 -0
- package/dist/core/bootstrap/provider-phase.js +183 -0
- package/dist/core/bootstrap/session-phase.js +204 -0
- package/dist/core/bootstrap/state.js +94 -0
- package/dist/core/bootstrap/workspace-phase.js +115 -0
- package/dist/core/bootstrap.js +92 -660
- package/dist/core/crash-handler.js +17 -7
- package/dist/core/environment.js +37 -12
- package/dist/core/host-plan.js +43 -0
- package/dist/core/host.js +23 -0
- package/dist/core/index.js +1 -0
- package/dist/core/prompt-builder.js +17 -1
- package/dist/core/prompt-overflow.js +42 -43
- package/dist/core/session-logger.js +122 -30
- package/dist/core/system-prompt.js +117 -0
- package/dist/core/version.js +6 -4
- package/dist/core/web-host.js +34 -0
- package/dist/core/workspace.js +19 -15
- package/dist/i18n/en.json +106 -21
- package/dist/i18n/index.js +37 -3
- package/dist/i18n/ru.json +109 -21
- package/dist/index.js +7 -3
- package/dist/llm/image-utils.js +55 -64
- package/dist/llm/llm-errors.js +9 -0
- package/dist/llm/model-loader.js +10 -32
- package/dist/llm/models-dev.js +121 -0
- package/dist/llm/openai-compat.js +146 -73
- package/dist/llm/orchestrator.js +33 -11
- package/dist/llm/provider-budget.js +2 -2
- package/dist/llm/provider-context.js +233 -0
- package/dist/llm/provider.js +1 -1
- package/dist/llm/response.js +5 -0
- package/dist/llm/token-counter.js +27 -11
- package/dist/logger/app-logger.js +48 -22
- package/dist/logger/file-log.js +28 -19
- package/dist/logger/index.js +1 -0
- package/dist/main.js +24285 -22447
- package/dist/migration/backup.js +14 -3
- package/dist/migration/detect.js +12 -3
- package/dist/migration/index.js +1 -0
- package/dist/modules/artifacts/store.js +9 -8
- package/dist/modules/browser/actions.js +6 -0
- package/dist/modules/browser/bridge-client.js +14 -12
- package/dist/modules/browser/bridge-path.js +4 -4
- package/dist/modules/browser/console-buffer.js +37 -0
- package/dist/modules/browser/cookie-store.js +5 -0
- package/dist/modules/browser/driver-types.js +1 -0
- package/dist/modules/browser/driver.js +19 -11
- package/dist/modules/browser/index.js +3 -1
- package/dist/modules/browser/module.js +2 -1
- package/dist/modules/browser/session.js +10 -30
- package/dist/modules/browser/snapshot.js +19 -13
- package/dist/modules/browser/types.js +1 -0
- package/dist/modules/certification/cli.js +28 -20
- package/dist/modules/certification/fact-checker.js +9 -1
- package/dist/modules/certification/loader.js +9 -2
- package/dist/modules/certification/manifest.js +83 -21
- package/dist/modules/certification/runner.js +23 -13
- package/dist/modules/certification/scenarios.js +20 -20
- package/dist/modules/certification/syntax-scenarios.js +1 -2
- package/dist/modules/context/chunk-query.js +11 -9
- package/dist/modules/context/fact-extractor.js +37 -39
- package/dist/modules/context/index.js +1 -0
- package/dist/modules/context/manager.js +106 -80
- package/dist/modules/critic/client.js +176 -0
- package/dist/modules/critic/evidence.js +81 -0
- package/dist/modules/critic/provider.js +45 -0
- package/dist/modules/critic/tools.js +78 -0
- package/dist/modules/critic/types.js +1 -0
- package/dist/modules/execution/audit-runners.js +28 -34
- package/dist/modules/execution/auditor.js +53 -49
- package/dist/modules/execution/execution-plugin.js +142 -102
- package/dist/modules/execution/index.js +1 -1
- package/dist/modules/execution/input-from.js +37 -13
- package/dist/modules/execution/module.js +368 -191
- package/dist/modules/execution/moe-executor.js +53 -26
- package/dist/modules/execution/plan-actions.js +320 -202
- package/dist/modules/execution/plan-checks.js +35 -0
- package/dist/modules/execution/plan-coverage.js +36 -33
- package/dist/modules/execution/plan-steps.js +11 -3
- package/dist/modules/execution/plan-store.js +83 -17
- package/dist/modules/execution/plan-tool.js +89 -35
- package/dist/modules/execution/plan-validator.js +30 -10
- package/dist/modules/execution/planner.js +22 -13
- package/dist/modules/execution/stuck-detector.js +196 -93
- package/dist/modules/execution/tracker.js +22 -8
- package/dist/modules/execution/verifier.js +69 -48
- package/dist/modules/execution/windows-commands.js +12 -12
- package/dist/modules/hallucination/artifact-claim.js +93 -0
- package/dist/modules/hallucination/confidence.js +13 -11
- package/dist/modules/hallucination/consistency.js +10 -2
- package/dist/modules/hallucination/detector.js +10 -5
- package/dist/modules/hallucination/factual.js +43 -26
- package/dist/modules/hallucination/index.js +1 -0
- package/dist/modules/hallucination/js-identifiers.js +44 -45
- package/dist/modules/hallucination/llm-judge.js +17 -12
- package/dist/modules/hallucination/success-claim.js +59 -0
- package/dist/modules/indexer/cache.js +52 -4
- package/dist/modules/indexer/index.js +1 -0
- package/dist/modules/indexer/map-command.js +2 -4
- package/dist/modules/indexer/map-select.js +16 -16
- package/dist/modules/indexer/module.js +47 -12
- package/dist/modules/indexer/project-profile.js +8 -7
- package/dist/modules/indexer/symbols.js +15 -15
- package/dist/modules/indexer/walker.js +159 -29
- package/dist/modules/lsp/check-tool.js +7 -5
- package/dist/modules/lsp/client.js +39 -39
- package/dist/modules/lsp/command.js +17 -24
- package/dist/modules/lsp/config.js +12 -11
- package/dist/modules/lsp/index.js +1 -0
- package/dist/modules/lsp/module.js +48 -46
- package/dist/modules/lsp/probe.js +13 -14
- package/dist/modules/lsp/project-root.js +14 -17
- package/dist/modules/lsp/startup-check.js +18 -16
- package/dist/modules/mcp/client.js +59 -62
- package/dist/modules/mcp/index.js +1 -0
- package/dist/modules/mcp/module.js +66 -37
- package/dist/modules/mcp/registry.js +5 -0
- package/dist/modules/memory/index.js +1 -0
- package/dist/modules/memory/module.js +12 -8
- package/dist/modules/memory/search.js +4 -1
- package/dist/modules/memory/store.js +40 -2
- package/dist/modules/onboarding/init.js +47 -0
- package/dist/modules/onboarding/meet.js +30 -0
- package/dist/modules/onboarding/mode.js +30 -0
- package/dist/modules/onboarding/prompts.js +43 -0
- package/dist/modules/pipelines/engine.js +10 -0
- package/dist/modules/pipelines/index.js +1 -0
- package/dist/modules/pipelines/parser.js +4 -1
- package/dist/modules/pipelines/template.js +4 -0
- package/dist/modules/plugins/builtin/lint-on-write.js +80 -67
- package/dist/modules/plugins/builtin/notify.js +2 -0
- package/dist/modules/plugins/index.js +1 -0
- package/dist/modules/plugins/loader.js +18 -3
- package/dist/modules/plugins/manager.js +37 -17
- package/dist/modules/pricing/index.js +10 -11
- package/dist/modules/pricing/prices.js +12 -12
- package/dist/modules/processes/index.js +1 -0
- package/dist/modules/processes/kill-tree.js +27 -31
- package/dist/modules/processes/registry.js +44 -25
- package/dist/modules/processes/runner.js +4 -4
- package/dist/modules/providers/capabilities.js +28 -0
- package/dist/modules/providers/create.js +3 -4
- package/dist/modules/providers/factory.js +7 -7
- package/dist/modules/providers/fallback.js +12 -12
- package/dist/modules/providers/health.js +4 -4
- package/dist/modules/providers/manager.js +50 -19
- package/dist/modules/providers/naming.js +15 -0
- package/dist/modules/providers/preflight.js +71 -0
- package/dist/modules/providers/presets.js +39 -8
- package/dist/modules/providers/registry.js +7 -2
- package/dist/modules/reasoning/policy.js +8 -6
- package/dist/modules/reasoning/probe.js +30 -25
- package/dist/modules/security/audit-log.js +19 -36
- package/dist/modules/security/audit-notifier.js +35 -75
- package/dist/modules/security/command-validator.js +99 -51
- package/dist/modules/security/content-scanner.js +8 -8
- package/dist/modules/security/data-sanitizer.js +9 -16
- package/dist/modules/security/encryption.js +32 -52
- package/dist/modules/security/index.js +2 -1
- package/dist/modules/security/network-validator.js +120 -43
- package/dist/modules/security/path-validator.js +61 -46
- package/dist/modules/security/protected-paths.js +73 -0
- package/dist/modules/security/rate-limiter.js +17 -49
- package/dist/modules/security/security-policies.js +25 -57
- package/dist/modules/security/session-encryption.js +32 -71
- package/dist/modules/security/session-isolation.js +15 -28
- package/dist/modules/session/auto-name.js +63 -0
- package/dist/modules/session/export.js +98 -0
- package/dist/modules/session/index.js +1 -0
- package/dist/modules/session/manager.js +79 -28
- package/dist/modules/session/module.js +4 -3
- package/dist/modules/session/store.js +57 -20
- package/dist/modules/setup/answers.js +35 -0
- package/dist/modules/setup/apply.js +79 -0
- package/dist/modules/setup/discovery.js +72 -0
- package/dist/modules/skills/index.js +1 -0
- package/dist/modules/skills/loader.js +9 -1
- package/dist/modules/skills/module.js +11 -0
- package/dist/modules/updater/changelog-reader.js +15 -16
- package/dist/modules/updater/checker.js +9 -4
- package/dist/modules/updater/dev-detect.js +7 -6
- package/dist/modules/updater/index.js +1 -0
- package/dist/modules/updater/module.js +17 -15
- package/dist/modules/user-profile/compressor.js +2 -0
- package/dist/modules/user-profile/index.js +1 -0
- package/dist/modules/user-profile/profile.js +10 -1
- package/dist/modules/webui/answer-api.js +29 -0
- package/dist/modules/webui/assets.js +50 -0
- package/dist/modules/webui/body.js +21 -0
- package/dist/modules/webui/commands-settings.js +209 -0
- package/dist/modules/webui/commands-shared.js +60 -0
- package/dist/modules/webui/commands.js +174 -0
- package/dist/modules/webui/config-api.js +134 -0
- package/dist/modules/webui/file-api.js +202 -0
- package/dist/modules/webui/forward.js +159 -0
- package/dist/modules/webui/history-api.js +112 -0
- package/dist/modules/webui/host-state.js +60 -0
- package/dist/modules/webui/i18n-api.js +9 -0
- package/dist/modules/webui/limits.js +6 -0
- package/dist/modules/webui/log-forward.js +20 -0
- package/dist/modules/webui/memory-commands.js +64 -0
- package/dist/modules/webui/model-cache.js +18 -0
- package/dist/modules/webui/module.js +148 -0
- package/dist/modules/webui/persist.js +24 -0
- package/dist/modules/webui/prompt-io.js +97 -0
- package/dist/modules/webui/providers-api.js +337 -0
- package/dist/modules/webui/providers-view.js +56 -0
- package/dist/modules/webui/reasoning-view.js +15 -0
- package/dist/modules/webui/run-agent.js +81 -0
- package/dist/modules/webui/server.js +284 -0
- package/dist/modules/webui/sessions-api.js +178 -0
- package/dist/modules/webui/settings-api.js +561 -0
- package/dist/modules/webui/setup-api.js +201 -0
- package/dist/modules/webui/state.js +74 -0
- package/dist/modules/webui/util.js +261 -0
- package/dist/output/bus.js +7 -2
- package/dist/output/channel.js +80 -28
- package/dist/output/format.js +2 -1
- package/dist/output/index.js +1 -0
- package/dist/output/json-sink.js +5 -3
- package/dist/output/machine.js +4 -3
- package/dist/output/session-sink.js +4 -4
- package/dist/tools/approve.js +4 -0
- package/dist/tools/attach-image.js +5 -4
- package/dist/tools/auto-fixer.js +26 -44
- package/dist/tools/auto-tags.js +83 -0
- package/dist/tools/bash.js +193 -116
- package/dist/tools/browser.js +76 -31
- package/dist/tools/chunk-query.js +14 -6
- package/dist/tools/create-dir.js +9 -5
- package/dist/tools/delete-file.js +9 -5
- package/dist/tools/download-file.js +32 -7
- package/dist/tools/edit-file.js +52 -14
- package/dist/tools/enable-tools.js +6 -6
- package/dist/tools/executor.js +132 -27
- package/dist/tools/file-info.js +3 -1
- package/dist/tools/filter-tools.js +3 -3
- package/dist/tools/glob-tool.js +4 -1
- package/dist/tools/grep-tool.js +13 -10
- package/dist/tools/hidden-tools-block.js +6 -6
- package/dist/tools/index.js +16 -8
- package/dist/tools/list-dir.js +4 -2
- package/dist/tools/load-skill.js +7 -0
- package/dist/tools/mcp-call.js +15 -4
- package/dist/tools/meet-done.js +14 -0
- package/dist/tools/move-file.js +14 -7
- package/dist/tools/path-utils.js +29 -29
- package/dist/tools/pipeline-run.js +29 -7
- package/dist/tools/preview.js +1 -1
- package/dist/tools/process-ids.js +31 -0
- package/dist/tools/process-kill.js +9 -16
- package/dist/tools/process-list.js +1 -0
- package/dist/tools/process-log.js +11 -16
- package/dist/tools/process-wait.js +63 -0
- package/dist/tools/prompt-io.js +4 -3
- package/dist/tools/question.js +172 -25
- package/dist/tools/read-file.js +55 -34
- package/dist/tools/recall.js +14 -8
- package/dist/tools/registry.js +6 -5
- package/dist/tools/remember.js +8 -4
- package/dist/tools/scope-request.js +11 -6
- package/dist/tools/search-history.js +5 -2
- package/dist/tools/session-info.js +2 -0
- package/dist/tools/set-thinking.js +8 -4
- package/dist/tools/subagent.js +59 -39
- package/dist/tools/syntax-validator.js +292 -90
- package/dist/tools/user-input.js +22 -18
- package/dist/tools/web-browse.js +9 -3
- package/dist/tools/web-fetch.js +12 -23
- package/dist/tools/web-search.js +7 -5
- package/dist/tools/write-file.js +45 -15
- package/dist/ui/action-log.js +13 -0
- package/dist/ui/box.js +4 -3
- package/dist/ui/colors.js +2 -0
- package/dist/ui/diff.js +6 -5
- package/dist/ui/index.js +1 -0
- package/dist/ui/line-editor.js +230 -122
- package/dist/ui/line-math.js +10 -2
- package/dist/ui/md-formatter.js +57 -37
- package/dist/ui/output.js +8 -3
- package/dist/ui/plan-view.js +21 -10
- package/dist/ui/renderer.js +393 -67
- package/dist/ui/spinner.js +16 -5
- package/dist/ui/table.js +15 -17
- package/dist/ui/theme.js +143 -0
- package/dist/utils/child-run.js +20 -0
- package/dist/utils/error.js +1 -1
- package/dist/utils/index.js +2 -0
- package/dist/utils/retry.js +2 -2
- package/dist/utils/truncate.js +1 -1
- package/package.json +1 -1
|
@@ -1,11 +1,11 @@
|
|
|
1
1
|
/**
|
|
2
|
-
*
|
|
3
|
-
*
|
|
4
|
-
*
|
|
5
|
-
*
|
|
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
|
-
//
|
|
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 (
|
|
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
|
|
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
|
-
/**
|
|
84
|
+
/** Префиксы провайдеров, срезаемые перед поиском цены. */
|
|
85
85
|
const PROVIDER_PREFIXES = ["opencode-go/", "opencode/", "openai/", "anthropic/"];
|
|
86
|
-
/**
|
|
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
|
-
//
|
|
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
|
-
/**
|
|
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
|
-
/**
|
|
138
|
+
/** Форматирует USD-стоимость для показа. Ноль и копейки остаются читаемыми. */
|
|
139
139
|
export function formatCost(cost) {
|
|
140
140
|
if (cost === 0)
|
|
141
141
|
return "$0.00";
|
|
@@ -1,45 +1,41 @@
|
|
|
1
|
-
|
|
1
|
+
// Кроссплатформенный килл дерева процессов, неблокирующий (без stall event loop).
|
|
2
|
+
import { spawn } from "child_process";
|
|
2
3
|
import { platform } from "os";
|
|
3
|
-
/**
|
|
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
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
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
|
-
*
|
|
21
|
+
* Убивает дерево спавненного процесса — кроссплатформенно, неблокирующе.
|
|
26
22
|
*
|
|
27
|
-
* Windows:
|
|
28
|
-
*
|
|
29
|
-
*
|
|
30
|
-
*
|
|
23
|
+
* Windows: два прохода `taskkill /T /F` с паузой 150мс (второй добирает детей,
|
|
24
|
+
* ещё создававшихся во время первого обхода дерева, напр. `cmd → node →
|
|
25
|
+
* tsserver`). Оба АСИНХРОННЫ: прежние `spawnSync` + `Atomics.wait` стопили
|
|
26
|
+
* event loop (фроз UI/стрима) до ~10с на процесс при шатдауне.
|
|
31
27
|
*
|
|
32
|
-
* POSIX:
|
|
33
|
-
*
|
|
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
|
-
|
|
42
|
-
|
|
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
|
-
/*
|
|
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
|
|
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(
|
|
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
|
-
*
|
|
47
|
+
* Декодирует одну готовую строку вывода в UTF-8.
|
|
44
48
|
*
|
|
45
|
-
*
|
|
46
|
-
*
|
|
47
|
-
*
|
|
48
|
-
*
|
|
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
|
-
/*
|
|
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
|
-
/*
|
|
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
|
-
*
|
|
75
|
-
*
|
|
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:
|
|
132
|
-
// npm, git)
|
|
133
|
-
//
|
|
134
|
-
//
|
|
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
|
-
//
|
|
168
|
-
//
|
|
169
|
-
//
|
|
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
|
-
/**
|
|
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
|
-
/**
|
|
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
|
-
*
|
|
229
|
-
*
|
|
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 (
|
|
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
|
-
*
|
|
247
|
-
*
|
|
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
|
-
/**
|
|
2
|
+
/** Регистрирует kill-колбэк тул-вызова (для таймаута/аборта экзекутора). */
|
|
3
3
|
export function registerKillable(callId, kill) {
|
|
4
4
|
activeChildren.set(callId, { kill });
|
|
5
5
|
}
|
|
6
|
-
/**
|
|
6
|
+
/** Снимает kill-колбэк завершившегося хендлера. */
|
|
7
7
|
export function unregisterKillable(callId) {
|
|
8
8
|
activeChildren.delete(callId);
|
|
9
9
|
}
|
|
10
|
-
/**
|
|
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
|
-
/*
|
|
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
|
-
*
|
|
5
|
-
*
|
|
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
|
-
/**
|
|
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
|
-
*
|
|
5
|
-
*
|
|
6
|
-
*
|
|
7
|
-
*
|
|
8
|
-
*
|
|
9
|
-
*
|
|
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
|
-
/**
|
|
2
|
+
/** Стоит ли ошибка переключения на другой провайдер. */
|
|
3
3
|
export function isFailoverError(err) {
|
|
4
4
|
if (err instanceof Error && err.name === "AbortError")
|
|
5
5
|
return false;
|
|
6
|
-
// HTTP
|
|
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
|
-
//
|
|
11
|
-
// Node: "ECONNREFUSED", DNS: "ENOTFOUND"/"EAI_AGAIN"
|
|
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
|
-
//
|
|
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
|
-
*
|
|
24
|
-
*
|
|
25
|
-
*
|
|
26
|
-
*
|
|
27
|
-
*
|
|
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
|
-
//
|
|
65
|
-
//
|
|
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
|
-
*
|
|
4
|
-
*
|
|
5
|
-
*
|
|
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
|
-
/**
|
|
41
|
+
/** Собрать цели проб из маппинга имя→провайдер (порядок приоритетов). */
|
|
42
42
|
export function targetsFromProviders(entries) {
|
|
43
43
|
return entries.map(({ name, provider }) => ({
|
|
44
44
|
name,
|