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
|
@@ -6,25 +6,25 @@ import { toForwardSlash } from "../../tools/path-utils";
|
|
|
6
6
|
import { platform } from "os";
|
|
7
7
|
import { switchStepToDelete } from "./plan-steps";
|
|
8
8
|
/**
|
|
9
|
-
*
|
|
10
|
-
* ExecutionModule
|
|
11
|
-
*
|
|
9
|
+
* Кулдаун (в итерациях) между инжектами stuck-восстановления. Экспортируется,
|
|
10
|
+
* чтобы ExecutionModule сидировал state.lastRecoveryIteration тем же офсетом,
|
|
11
|
+
* с которым плагин сравнивает.
|
|
12
12
|
*/
|
|
13
13
|
export const STUCK_RECOVERY_COOLDOWN = 5;
|
|
14
14
|
const MAX_PLAN_WARNINGS_BEFORE_BLOCK = 3;
|
|
15
15
|
const FORCE_SKIP_THRESHOLD = 10;
|
|
16
|
-
/**
|
|
17
|
-
*
|
|
18
|
-
*
|
|
19
|
-
*
|
|
16
|
+
/** Один и тот же stuck-варнинг перелоггируем не чаще каждых N итераций (новый
|
|
17
|
+
* ключ — всегда сразу). Не даёт идентичному варнингу флудить каждую итерацию
|
|
18
|
+
* (было в ses_mt4fn58c: "Tool bash failed N times" после ~30 успешных записей,
|
|
19
|
+
* "No write/exec" на каждом чтении). */
|
|
20
20
|
export const STUCK_WARN_REPEAT_EVERY = 5;
|
|
21
|
-
/**
|
|
22
|
-
*
|
|
23
|
-
*
|
|
21
|
+
/** Сколько файл-мутирующих вызовов (write/edit/bash/download) без активного
|
|
22
|
+
* плана триггерит nudge создания плана. Evidence-based (правило #10):
|
|
23
|
+
* агент явно работает с файлами — план оправдан. */
|
|
24
24
|
const PLAN_NUDGE_THRESHOLD = 2;
|
|
25
|
-
/**
|
|
26
|
-
*
|
|
27
|
-
*
|
|
25
|
+
/** Тулы, чей успех мог поменять ФС — после них перепроверяем deliverables
|
|
26
|
+
* текущего шага для автопродвижения. Read-only осознанно исключены (см. вызов
|
|
27
|
+
* advance в onAfterTool ниже). */
|
|
28
28
|
const FS_MUTATING_TOOLS = new Set([
|
|
29
29
|
"write_file",
|
|
30
30
|
"edit_file",
|
|
@@ -41,8 +41,8 @@ const FS_MUTATING_TOOLS = new Set([
|
|
|
41
41
|
function normalizeBrokenPath(p) {
|
|
42
42
|
return toForwardSlash(p).replace(/^\.\//, "");
|
|
43
43
|
}
|
|
44
|
-
/**
|
|
45
|
-
*
|
|
44
|
+
/** Парсит строку ошибки tsc / bun build / node --check в путь файла.
|
|
45
|
+
* Null, если в строке нет привязки к файлу (напр. `error: Could not
|
|
46
46
|
* resolve "..."`). */
|
|
47
47
|
export function parseBrokenFile(line) {
|
|
48
48
|
const trimmed = line.trim();
|
|
@@ -56,9 +56,9 @@ export function parseBrokenFile(line) {
|
|
|
56
56
|
return normalizeBrokenPath(bn[1]);
|
|
57
57
|
return null;
|
|
58
58
|
}
|
|
59
|
-
/**
|
|
60
|
-
*
|
|
61
|
-
* `[Syntax check failed]: <line>`)
|
|
59
|
+
/** Вытаскивает пофайловые compile-фейлы из вывода write/edit. Смотрит только
|
|
60
|
+
* строки-маркеры (`[Project typecheck failed]: <line>` /
|
|
61
|
+
* `[Syntax check failed]: <line>`), чтобы тело диффа не давало ложных. */
|
|
62
62
|
export function extractBrokenFiles(output) {
|
|
63
63
|
const out = [];
|
|
64
64
|
for (const line of output.split("\n")) {
|
|
@@ -75,6 +75,7 @@ function resetStepFlags(state, stepId) {
|
|
|
75
75
|
state.consecutivePlanWarnings = 0;
|
|
76
76
|
state.lastStepId = stepId;
|
|
77
77
|
state.stuckNotified = false;
|
|
78
|
+
state.escalationDirectiveSent = false;
|
|
78
79
|
}
|
|
79
80
|
/** Полный сброс состояния плана (завершён или его нет). */
|
|
80
81
|
function resetPlanState(state) {
|
|
@@ -83,14 +84,14 @@ function resetPlanState(state) {
|
|
|
83
84
|
state.stuckNotified = false;
|
|
84
85
|
state.mutationsWithoutPlan = 0;
|
|
85
86
|
state.planNudgeSent = false;
|
|
87
|
+
state.escalationDirectiveSent = false;
|
|
86
88
|
}
|
|
87
89
|
/**
|
|
88
|
-
*
|
|
89
|
-
*
|
|
90
|
-
*
|
|
91
|
-
*
|
|
92
|
-
*
|
|
93
|
-
* the model, or null to allow the done.
|
|
90
|
+
* Гейт для `plan update status=done`: реджектит, пока последний write/edit
|
|
91
|
+
* репортит compile-ошибку. Фейл без привязки к файлу блокирует весь проект;
|
|
92
|
+
* иначе именованные токены файлов шага матчатся против битых (суффикс пути,
|
|
93
|
+
* регистронезависимо). Шаг без файлов обвинить не в чем — его done остаётся
|
|
94
|
+
* vacuous. Возвращает первую ошибку для показа модели, или null чтобы пустить.
|
|
94
95
|
*/
|
|
95
96
|
export function stepTypecheckGate(failures, stepDescription) {
|
|
96
97
|
if (failures.size === 0)
|
|
@@ -109,28 +110,27 @@ export function stepTypecheckGate(failures, stepDescription) {
|
|
|
109
110
|
return null;
|
|
110
111
|
}
|
|
111
112
|
/**
|
|
112
|
-
*
|
|
113
|
-
*
|
|
114
|
-
* tracker)
|
|
113
|
+
* Хуки execution-плагина, вынесенные дословно из ExecutionModule.getPlugin().
|
|
114
|
+
* Всё разделяемое мутабельное состояние (pendingMessages, forbiddenBashFailures,
|
|
115
|
+
* state, tracker) принадлежит модулю и мутируется по ссылке через `deps`.
|
|
115
116
|
*/
|
|
116
117
|
export function createExecutionPlugin(deps) {
|
|
117
118
|
return {
|
|
118
119
|
name: "execution",
|
|
119
120
|
onBeforeThink: (ctx) => {
|
|
120
|
-
//
|
|
121
|
-
//
|
|
121
|
+
// Отложенные <system-summary> флашим первыми: видны следующему вызову
|
|
122
|
+
// модели, но не interleav'ят tool-сообщения.
|
|
122
123
|
if (ctx.contextManager && deps.pendingMessages.length > 0) {
|
|
123
124
|
for (const m of deps.pendingMessages.splice(0)) {
|
|
124
125
|
ctx.contextManager.addMessage(m);
|
|
125
126
|
}
|
|
126
127
|
}
|
|
127
128
|
if (deps.trackerRef.current?.isComplete()) {
|
|
128
|
-
//
|
|
129
|
-
//
|
|
130
|
-
//
|
|
131
|
-
//
|
|
132
|
-
//
|
|
133
|
-
// writes and no recovery hint).
|
|
129
|
+
// Все шаги done/skipped — перестаём считать "no progress" против
|
|
130
|
+
// последнего шага и глушим step-stuck варнинги готового плана, НО
|
|
131
|
+
// историю вызовов храним, чтобы петля чтения-без-записи ловилась
|
|
132
|
+
// (было: план готов + ложноположительный аудит → модель 50+ итераций
|
|
133
|
+
// перечитывала файлы с нулем записей без recovery-хинта).
|
|
134
134
|
deps.stuckDetector.resetStepProgress();
|
|
135
135
|
resetPlanState(deps.state);
|
|
136
136
|
}
|
|
@@ -147,12 +147,15 @@ export function createExecutionPlugin(deps) {
|
|
|
147
147
|
deps.state.planNudgeSent = false;
|
|
148
148
|
}
|
|
149
149
|
else {
|
|
150
|
-
|
|
150
|
+
// До-плана: историю цикла (свежие вызовы, read-only стрик) храним,
|
|
151
|
+
// чтобы петли повторов/read-only ловились и без плана. `reset()`
|
|
152
|
+
// тёр её каждую итерацию, отключая детекцию.
|
|
153
|
+
deps.stuckDetector.resetStepProgress();
|
|
151
154
|
resetStepFlags(deps.state, -1);
|
|
152
|
-
// Evidence-based
|
|
153
|
-
//
|
|
154
|
-
//
|
|
155
|
-
//
|
|
155
|
+
// Evidence-based nudge плана (правило #10 — без голого счётчика
|
|
156
|
+
// итераций, без keyword-классификации задач): только когда агент
|
|
157
|
+
// реально сделал файл-мутирующие вызовы (write/edit/bash/download)
|
|
158
|
+
// без плана, ему нужен план.
|
|
156
159
|
const mutations = deps.state.mutationsWithoutPlan;
|
|
157
160
|
if (mutations >= PLAN_NUDGE_THRESHOLD &&
|
|
158
161
|
!deps.state.planNudgeSent &&
|
|
@@ -169,10 +172,9 @@ export function createExecutionPlugin(deps) {
|
|
|
169
172
|
}
|
|
170
173
|
const stuckReason = deps.stuckDetector.getStuckReason();
|
|
171
174
|
if (stuckReason) {
|
|
172
|
-
//
|
|
173
|
-
//
|
|
174
|
-
//
|
|
175
|
-
// dedicated once-per-episode flag.
|
|
175
|
+
// Логируем раз на эпизод варнинга, а не спамим каждую итерацию: новый
|
|
176
|
+
// ключ — сразу; ТОТ ЖЕ ключ — только каждые STUCK_WARN_REPEAT_EVERY
|
|
177
|
+
// итераций. Step-stuck причина хранит свой once-per-episode флаг.
|
|
176
178
|
const isStuck = deps.stuckDetector.isStuck();
|
|
177
179
|
const warnKey = deps.stuckDetector.getWarningKey();
|
|
178
180
|
const iter = typeof ctx.iteration === "number" ? ctx.iteration : 0;
|
|
@@ -194,12 +196,14 @@ export function createExecutionPlugin(deps) {
|
|
|
194
196
|
}
|
|
195
197
|
if (deps.stuckDetector.isStuck() ||
|
|
196
198
|
deps.stuckDetector.hasRepetitiveToolCalls() ||
|
|
197
|
-
deps.stuckDetector.hasReadOnlyLoop()
|
|
199
|
+
deps.stuckDetector.hasReadOnlyLoop() ||
|
|
200
|
+
deps.stuckDetector.hasBashFlailing() ||
|
|
201
|
+
deps.stuckDetector.hasConsecutiveFailures()) {
|
|
198
202
|
const currentIter = typeof ctx.iteration === "number" ? ctx.iteration : 0;
|
|
199
203
|
if (currentIter - deps.state.lastRecoveryIteration >= STUCK_RECOVERY_COOLDOWN) {
|
|
200
204
|
const recovery = deps.stuckDetector.getRecoveryMessage();
|
|
201
205
|
if (recovery && ctx.contextManager) {
|
|
202
|
-
//
|
|
206
|
+
// Прикладываем контекст tsc-ошибки, чтобы модель знала, ПОЧЕМУ застряла.
|
|
203
207
|
let tscContext = "";
|
|
204
208
|
if (deps.state.typecheckFailures.size > 0) {
|
|
205
209
|
const currentStep = deps.trackerRef.current?.getCurrentStep();
|
|
@@ -218,21 +222,35 @@ export function createExecutionPlugin(deps) {
|
|
|
218
222
|
}
|
|
219
223
|
}
|
|
220
224
|
}
|
|
225
|
+
// Префикс стабильной машиночитаемой классификации: модель видит,
|
|
226
|
+
// ПОЧЕМУ застряла, до локализованного recovery-гайданса.
|
|
227
|
+
const diagnostic = deps.stuckDetector.getStuckDiagnostic(currentIter);
|
|
221
228
|
ctx.contextManager.addMessage({
|
|
222
229
|
role: "user",
|
|
223
|
-
content: `<system-summary>${recovery}${tscContext}</system-summary>`,
|
|
230
|
+
content: `<system-summary>${diagnostic ? `${diagnostic}\n` : ""}${recovery}${tscContext}</system-summary>`,
|
|
224
231
|
});
|
|
225
232
|
}
|
|
226
233
|
deps.stuckDetector.recordEscalation();
|
|
227
234
|
deps.state.lastRecoveryIteration = currentIter;
|
|
228
|
-
if (deps.stuckDetector.shouldEscalate()
|
|
235
|
+
if (deps.stuckDetector.shouldEscalate()) {
|
|
229
236
|
const escalation = t("exec.escalation", {
|
|
230
237
|
stepId: String(deps.trackerRef.current?.getCurrentStep()?.id ?? "?"),
|
|
231
238
|
description: deps.trackerRef.current?.getCurrentStep()?.description ?? "",
|
|
232
239
|
});
|
|
233
|
-
|
|
240
|
+
// Эскалируем МОДЕЛИ, а не только UI-баннеру: после нескольких попыток
|
|
241
|
+
// восстановления даём явные общие опции (сменить подход, поискать
|
|
242
|
+
// ошибку, спросить юзера, re-plan/skip) вместо повтора того же
|
|
243
|
+
// фейлящегося действия. Инжектится раз на эпизод.
|
|
244
|
+
if (!deps.state.escalationDirectiveSent && ctx.contextManager) {
|
|
245
|
+
deps.state.escalationDirectiveSent = true;
|
|
246
|
+
ctx.contextManager.addMessage({
|
|
247
|
+
role: "user",
|
|
248
|
+
content: `<system-summary>${t("exec.escalation_directive")}</system-summary>`,
|
|
249
|
+
});
|
|
250
|
+
}
|
|
251
|
+
ctx.onMeta?.(escalation);
|
|
234
252
|
}
|
|
235
|
-
//
|
|
253
|
+
// Форс-скип после слишком долгого сидения на одном шаге
|
|
236
254
|
if (deps.stuckDetector.getIterationsOnCurrentStep() >= FORCE_SKIP_THRESHOLD &&
|
|
237
255
|
ctx.contextManager) {
|
|
238
256
|
const step = deps.trackerRef.current?.getCurrentStep();
|
|
@@ -261,8 +279,8 @@ export function createExecutionPlugin(deps) {
|
|
|
261
279
|
role: "user",
|
|
262
280
|
content: `<system-summary>${t("exec.plan_blocked", { step: String(deps.trackerRef.current?.getCurrentStep()?.id ?? "?"), max: MAX_PLAN_WARNINGS_BEFORE_BLOCK })}</system-summary>`,
|
|
263
281
|
});
|
|
264
|
-
//
|
|
265
|
-
//
|
|
282
|
+
// Блок с явной причиной, чтобы модель видела, ПОЧЕМУ вызов
|
|
283
|
+
// заблокирован (executor показывает через tool.blocked_reason).
|
|
266
284
|
return t("exec.plan_blocked", {
|
|
267
285
|
step: String(deps.trackerRef.current?.getCurrentStep()?.id ?? "?"),
|
|
268
286
|
max: MAX_PLAN_WARNINGS_BEFORE_BLOCK,
|
|
@@ -279,8 +297,8 @@ export function createExecutionPlugin(deps) {
|
|
|
279
297
|
const args = ctx?.args;
|
|
280
298
|
if (toolName && args) {
|
|
281
299
|
deps.stuckDetector.recordToolCall(toolName, args);
|
|
282
|
-
//
|
|
283
|
-
// evidence-based
|
|
300
|
+
// Считаем файл-мутирующие вызовы БЕЗ активного плана — питают
|
|
301
|
+
// evidence-based nudge создания плана в onBeforeThink.
|
|
284
302
|
if (!deps.trackerRef.current &&
|
|
285
303
|
(toolName === "write_file" ||
|
|
286
304
|
toolName === "edit_file" ||
|
|
@@ -291,14 +309,14 @@ export function createExecutionPlugin(deps) {
|
|
|
291
309
|
}
|
|
292
310
|
},
|
|
293
311
|
onAfterTool: (ctx, call, result) => {
|
|
294
|
-
//
|
|
295
|
-
//
|
|
312
|
+
// Запоминаем каждый вызов bash (успех или нет): детекция рассуждает,
|
|
313
|
+
// напр., о повторных прогонах с пустым выводом.
|
|
296
314
|
if (call.name === "bash") {
|
|
297
315
|
deps.stuckDetector.recordBashOutput(String(call.arguments?.command ?? ""), String(result.output ?? ""));
|
|
298
316
|
}
|
|
299
|
-
//
|
|
300
|
-
//
|
|
301
|
-
//
|
|
317
|
+
// Авто-детект delete-намерения из действий модели: при вызове delete_file
|
|
318
|
+
// находим совпадающий шаг плана и ставим kind="delete". Языконезависимо —
|
|
319
|
+
// по СДЕЛАННОМУ моделью, не по сказанному.
|
|
302
320
|
if (call.name === "delete_file" && result.success && deps.trackerRef.current) {
|
|
303
321
|
const deletedPath = String(call.arguments?.path ?? "");
|
|
304
322
|
if (deletedPath) {
|
|
@@ -316,21 +334,20 @@ export function createExecutionPlugin(deps) {
|
|
|
316
334
|
}
|
|
317
335
|
}
|
|
318
336
|
}
|
|
319
|
-
//
|
|
320
|
-
//
|
|
321
|
-
//
|
|
322
|
-
// to the stuck detector so the rewrite-loop hint fires.
|
|
337
|
+
// write/edit/bash с успехом, но type/syntax-ошибкой в выводе — НЕ успех:
|
|
338
|
+
// модель чинит реальную ошибку, а не переписывает файл вслепую. Кормим
|
|
339
|
+
// stuck-детектор, чтобы сработал хинт rewrite-петли.
|
|
323
340
|
const toolText = String(result.output ?? "");
|
|
324
341
|
const hasTypeError = /error TS\d+|\[Project typecheck failed\]|\[Syntax check failed\]/.test(toolText);
|
|
325
342
|
if (hasTypeError) {
|
|
326
343
|
deps.stuckDetector.recordToolError(call.name, toolText.slice(0, 300));
|
|
327
344
|
}
|
|
328
|
-
//
|
|
329
|
-
//
|
|
330
|
-
//
|
|
331
|
-
//
|
|
332
|
-
//
|
|
333
|
-
//
|
|
345
|
+
// Трекаем compile-фейлы пофайлово: done-gate плана реджектит "done", пока
|
|
346
|
+
// последняя правка не компилируется (было: агент маркил шаги done, а
|
|
347
|
+
// проектный typecheck фейлился на каждой записи — каскад "починю позже").
|
|
348
|
+
// ЧИСТЫЙ результат чистит карту: дебаунснутый проектный tsc перегнал и
|
|
349
|
+
// прошёл (или tsconfig неприменим) — старые фейлы завершение вечно не
|
|
350
|
+
// блокируют.
|
|
334
351
|
if (call.name === "write_file" || call.name === "edit_file") {
|
|
335
352
|
const broken = extractBrokenFiles(toolText);
|
|
336
353
|
if (broken.length > 0) {
|
|
@@ -338,22 +355,34 @@ export function createExecutionPlugin(deps) {
|
|
|
338
355
|
deps.state.typecheckFailures.set(b.file, b.error);
|
|
339
356
|
}
|
|
340
357
|
else if (result.success) {
|
|
341
|
-
|
|
358
|
+
// Чистим только записи только что писанного/правленного файла (и
|
|
359
|
+
// проектную безадресную запись, которую чистая правка вероятно
|
|
360
|
+
// закрыла). Сплошной `.clear()` стирал несвязанный успешной правкой
|
|
361
|
+
// чужой фейл, обходя done-gate.
|
|
362
|
+
const edited = normalizeBrokenPath(String(call.arguments?.path ?? ""));
|
|
363
|
+
for (const key of [...deps.state.typecheckFailures.keys()]) {
|
|
364
|
+
if (key === "" ||
|
|
365
|
+
!edited ||
|
|
366
|
+
key === edited ||
|
|
367
|
+
key.endsWith(edited) ||
|
|
368
|
+
edited.endsWith(key)) {
|
|
369
|
+
deps.state.typecheckFailures.delete(key);
|
|
370
|
+
}
|
|
371
|
+
}
|
|
342
372
|
}
|
|
343
373
|
}
|
|
344
374
|
if (!result.success) {
|
|
345
|
-
//
|
|
346
|
-
//
|
|
347
|
-
//
|
|
375
|
+
// Исход bash-попытки кормим во флейлинг-окно ДО пер-командной обработки —
|
|
376
|
+
// ротация разных фейлящихся команд (wc → cat → Get-Content → …) обязана
|
|
377
|
+
// триггерить детектор.
|
|
348
378
|
if (call.name === "bash") {
|
|
349
379
|
deps.stuckDetector.recordBashAttempt(false);
|
|
350
380
|
}
|
|
351
|
-
// Hard stop
|
|
352
|
-
//
|
|
353
|
-
//
|
|
354
|
-
//
|
|
355
|
-
//
|
|
356
|
-
// these commands exist and fail for legit reasons.
|
|
381
|
+
// Hard stop для запрещённых Windows-команд: после второго фейла той же
|
|
382
|
+
// запрещённой команды (grep/sed/ls/find/…) инжектим STOP, чтобы сессия
|
|
383
|
+
// не жгла bash-вызовы на командах без cmd.exe. Зеркалит собственный
|
|
384
|
+
// win32-gated hard-stop тула bash (src/tools/bash.ts) — на macOS/Linux
|
|
385
|
+
// эти команды есть и фейлятся по легитимным причинам.
|
|
357
386
|
if (call.name === "bash" && platform() === "win32") {
|
|
358
387
|
const cmd = String(call.arguments?.command ?? "");
|
|
359
388
|
const forbidden = forbiddenWindowsCommand(cmd);
|
|
@@ -368,36 +397,48 @@ export function createExecutionPlugin(deps) {
|
|
|
368
397
|
}
|
|
369
398
|
}
|
|
370
399
|
}
|
|
371
|
-
//
|
|
372
|
-
//
|
|
373
|
-
//
|
|
374
|
-
//
|
|
375
|
-
// web search at half the intended threshold.
|
|
400
|
+
// Type/syntax-ошибка в иначе "успешном" результате уже записана выше.
|
|
401
|
+
// Фейлящийся вызов (result.success === false) иначе посчитал бы ту же
|
|
402
|
+
// ошибку дважды (typecheck-ветка + failure-ветка), раздув счётчик
|
|
403
|
+
// error-сигнатур и триггернув веб-поиск на половине порога.
|
|
376
404
|
if (!hasTypeError) {
|
|
377
405
|
deps.stuckDetector.recordToolError(call.name, result.output);
|
|
378
406
|
}
|
|
379
407
|
}
|
|
380
408
|
else {
|
|
381
|
-
|
|
409
|
+
// "Успешная" запись/правка может нести type/syntax-ошибку (lint-on-write
|
|
410
|
+
// хук аппендит её, оставляя success:true). Скормленный здесь
|
|
411
|
+
// recordToolSuccess() отменял recordToolError выше на том же вызове —
|
|
412
|
+
// rewrite-loop сигнал не накапливался.
|
|
413
|
+
if (!hasTypeError)
|
|
414
|
+
deps.stuckDetector.recordToolSuccess();
|
|
382
415
|
if (call.name === "bash") {
|
|
383
416
|
deps.stuckDetector.recordBashAttempt(true);
|
|
384
417
|
}
|
|
385
|
-
//
|
|
386
|
-
//
|
|
387
|
-
//
|
|
418
|
+
// Успешно отработавшая команда bash с кодом — предлагаем маркить шаг
|
|
419
|
+
// done, если только вывод не показывает упавшие тесты (их нельзя
|
|
420
|
+
// репортить чистым успехом).
|
|
388
421
|
if (call.name === "bash" && result.success) {
|
|
389
422
|
const cmd = String(call.arguments?.command ?? "");
|
|
390
423
|
const testRun = detectTestResults(String(result.output ?? ""));
|
|
391
424
|
if (testRun && testRun.failed > 0) {
|
|
392
425
|
deps.pendingMessages.push({
|
|
393
426
|
role: "user",
|
|
394
|
-
content: `<system-summary>${
|
|
427
|
+
content: `<system-summary>${t("exec.test_fail_summary", {
|
|
428
|
+
framework: testRun.framework,
|
|
429
|
+
failed: String(testRun.failed),
|
|
430
|
+
passed: String(testRun.passed),
|
|
431
|
+
})}</system-summary>`,
|
|
395
432
|
});
|
|
396
433
|
}
|
|
397
434
|
else if (testRun && testRun.failed === 0 && testRun.passed > 0) {
|
|
398
435
|
deps.pendingMessages.push({
|
|
399
436
|
role: "user",
|
|
400
|
-
content: `<system-summary>${
|
|
437
|
+
content: `<system-summary>${t("exec.test_pass_summary", {
|
|
438
|
+
framework: testRun.framework,
|
|
439
|
+
passed: String(testRun.passed),
|
|
440
|
+
cmd,
|
|
441
|
+
})}</system-summary>`,
|
|
401
442
|
});
|
|
402
443
|
}
|
|
403
444
|
}
|
|
@@ -418,20 +459,19 @@ export function createExecutionPlugin(deps) {
|
|
|
418
459
|
}
|
|
419
460
|
}
|
|
420
461
|
}
|
|
421
|
-
//
|
|
422
|
-
//
|
|
423
|
-
// bash (`echo ... > f`,
|
|
424
|
-
//
|
|
425
|
-
//
|
|
426
|
-
//
|
|
427
|
-
//
|
|
428
|
-
//
|
|
429
|
-
// advancePlanIfStepComplete is a no-op when tokens don't resolve.
|
|
462
|
+
// Автопродвижение срабатывает после каждого успешного ФС-МУТИРУЮЩЕГО
|
|
463
|
+
// тула, не только write_file/edit_file. Мелкие модели часто создают файлы
|
|
464
|
+
// через bash (`echo ... > f`, heredoc'и) или delete/move через shell
|
|
465
|
+
// вместо выделенных тулов — план тогда не двигается с шага, хотя
|
|
466
|
+
// deliverables на диске (сертификация 3.5/3.8: файлы на месте, план
|
|
467
|
+
// висит на 1/4 и 4/5). Read-only тулы исключены: успешный read/glob иначе
|
|
468
|
+
// закрыл бы шаг "Update X", чей файл существует с раннего шага, — без
|
|
469
|
+
// единой правки. advancePlanIfStepComplete — no-op, если токены не резолвятся.
|
|
430
470
|
if (result.success && FS_MUTATING_TOOLS.has(call.name)) {
|
|
431
|
-
deps.advancePlanIfStepComplete(ctx.
|
|
471
|
+
deps.advancePlanIfStepComplete(ctx.sessionLog);
|
|
432
472
|
}
|
|
433
|
-
//
|
|
434
|
-
//
|
|
473
|
+
// Автопоиск в вебе повторяющейся ошибки (fire-and-forget, результаты
|
|
474
|
+
// падают в pendingMessages на следующем флаше onBeforeThink).
|
|
435
475
|
deps.maybeSearchError(ctx, call);
|
|
436
476
|
},
|
|
437
477
|
};
|
|
@@ -1,8 +1,8 @@
|
|
|
1
|
+
// Модуль исполнения: реэкспорт планов, трекера, верификатора, stuck-детектора, аудитора.
|
|
1
2
|
export { ExecutionModule } from "./module";
|
|
2
3
|
export { PlanCreator } from "./planner";
|
|
3
4
|
export { PlanTracker } from "./tracker";
|
|
4
5
|
export { StepVerifier } from "./verifier";
|
|
5
6
|
export { StuckDetector } from "./stuck-detector";
|
|
6
7
|
export { Auditor } from "./auditor";
|
|
7
|
-
export { PlanPersister } from "./plan-persister";
|
|
8
8
|
export { PlanStore } from "./plan-store";
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
/**
|
|
2
|
-
*
|
|
3
|
-
* (`[{"subtaskId": "task-1", "field": "json"}]`)
|
|
2
|
+
* Принимает обе формы input_from: компактную (`["task-1"]`) и детальную
|
|
3
|
+
* (`[{"subtaskId": "task-1", "field": "json"}]`).
|
|
4
4
|
*/
|
|
5
5
|
export function normalizeInputFrom(input) {
|
|
6
6
|
if (!Array.isArray(input))
|
|
@@ -10,8 +10,14 @@ export function normalizeInputFrom(input) {
|
|
|
10
10
|
if (typeof entry === "string") {
|
|
11
11
|
refs.push({ subtaskId: entry });
|
|
12
12
|
}
|
|
13
|
-
else if (entry && typeof entry === "object"
|
|
14
|
-
|
|
13
|
+
else if (entry && typeof entry === "object") {
|
|
14
|
+
const obj = entry;
|
|
15
|
+
if (typeof obj.subtaskId === "string") {
|
|
16
|
+
refs.push({
|
|
17
|
+
subtaskId: obj.subtaskId,
|
|
18
|
+
field: typeof obj.field === "string" ? obj.field : undefined,
|
|
19
|
+
});
|
|
20
|
+
}
|
|
15
21
|
}
|
|
16
22
|
}
|
|
17
23
|
return refs;
|
|
@@ -23,24 +29,42 @@ function truncate(text, cap) {
|
|
|
23
29
|
return `${flat.slice(0, cap)}…`;
|
|
24
30
|
}
|
|
25
31
|
/**
|
|
26
|
-
*
|
|
27
|
-
*
|
|
28
|
-
*
|
|
32
|
+
* Рендерит секцию "Input from previous tasks" для промпта зависимой
|
|
33
|
+
* подзадачи. Упавшие зависимости помечаются явно, чтобы читатель не строил
|
|
34
|
+
* логику на отсутствующих данных.
|
|
29
35
|
*/
|
|
30
36
|
export function buildInputSection(subtask, depResults, maxChars) {
|
|
31
37
|
const refs = normalizeInputFrom(subtask.input_from);
|
|
32
38
|
if (refs.length === 0)
|
|
33
39
|
return "";
|
|
34
|
-
|
|
40
|
+
// Агрегатный кап: без него 10 зависимостей × maxChars раздувают промпт
|
|
41
|
+
// выше бюджета контекста маленькой модели.
|
|
42
|
+
const totalCap = maxChars * 4;
|
|
43
|
+
const lines = [];
|
|
44
|
+
let used = 0;
|
|
45
|
+
let omitted = 0;
|
|
46
|
+
for (const ref of refs) {
|
|
35
47
|
const dep = depResults.get(ref.subtaskId);
|
|
36
48
|
if (!dep) {
|
|
37
|
-
|
|
49
|
+
const line = `- ${ref.subtaskId}: (no result available)`;
|
|
50
|
+
lines.push(line);
|
|
51
|
+
used += line.length;
|
|
52
|
+
continue;
|
|
38
53
|
}
|
|
39
54
|
const label = ref.field ? `${ref.subtaskId}.${ref.field}` : ref.subtaskId;
|
|
40
|
-
|
|
41
|
-
|
|
55
|
+
const body = dep.success
|
|
56
|
+
? truncate(dep.result || dep.summary, maxChars)
|
|
57
|
+
: `[FAILED] ${truncate(dep.error || dep.summary || "unknown error", maxChars)}`;
|
|
58
|
+
const line = `- ${label}: ${body}`;
|
|
59
|
+
if (used + line.length > totalCap) {
|
|
60
|
+
omitted++;
|
|
61
|
+
continue;
|
|
42
62
|
}
|
|
43
|
-
|
|
44
|
-
|
|
63
|
+
lines.push(line);
|
|
64
|
+
used += line.length;
|
|
65
|
+
}
|
|
66
|
+
if (omitted > 0) {
|
|
67
|
+
lines.push(`- (${omitted} more input(s) omitted: input budget reached)`);
|
|
68
|
+
}
|
|
45
69
|
return `\n\nInput from previous tasks:\n${lines.join("\n")}`;
|
|
46
70
|
}
|