micro-models-agent 2.11.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 +10 -0
- package/dist/assets/js/tabs.js +22 -3
- 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/index.js +37 -3
- 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 +273 -47
- 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,6 +1,9 @@
|
|
|
1
|
+
/** Вентиль халлюцинаций: проверка финального ответа перед принятием. */
|
|
1
2
|
import { pc } from "../../ui/colors";
|
|
2
3
|
import { t } from "../../i18n/index";
|
|
3
|
-
import {
|
|
4
|
+
import { checkSuccessClaim } from "../../modules/hallucination/success-claim";
|
|
5
|
+
import { checkArtifactClaims, checkUnverifiedOutput, } from "../../modules/hallucination/artifact-claim";
|
|
6
|
+
import { MAX_CLAIM_CHECK_RETRIES, MAX_HALLUCINATION_RETRIES } from "./constants";
|
|
4
7
|
/**
|
|
5
8
|
* Вентиль проверки халлюцинаций финального текстового ответа.
|
|
6
9
|
*
|
|
@@ -12,11 +15,38 @@ import { MAX_HALLUCINATION_RETRIES } from "./constants";
|
|
|
12
15
|
* Возвращает структурированный вердикт; решение о `break`/`continue`/`return`
|
|
13
16
|
* принимает цикл. Вся мутация состояния живёт здесь — цикл остаётся тонким.
|
|
14
17
|
*/
|
|
18
|
+
/**
|
|
19
|
+
* Свежие выводы тулов для проверки заявлений: последние 10 сообщений
|
|
20
|
+
* role:"tool" (текст урезан; чекер режет повторно). Тот же источник
|
|
21
|
+
* getActiveHistory, что у вентиля критика.
|
|
22
|
+
*/
|
|
23
|
+
function lastToolEvidence(deps) {
|
|
24
|
+
let history;
|
|
25
|
+
try {
|
|
26
|
+
history = deps.contextManager.getActiveHistory() ?? [];
|
|
27
|
+
}
|
|
28
|
+
catch {
|
|
29
|
+
return [];
|
|
30
|
+
}
|
|
31
|
+
return history
|
|
32
|
+
.filter((m) => m.role === "tool")
|
|
33
|
+
.slice(-10)
|
|
34
|
+
.map((m) => ({
|
|
35
|
+
name: m.name,
|
|
36
|
+
ok: m.success,
|
|
37
|
+
text: typeof m.content === "string" ? m.content : JSON.stringify(m.content) ?? "",
|
|
38
|
+
}))
|
|
39
|
+
.filter((m) => m.text.trim().length > 0);
|
|
40
|
+
}
|
|
15
41
|
export class HallucinationGate {
|
|
16
42
|
detector;
|
|
17
43
|
constructor(detector) {
|
|
18
44
|
this.detector = detector;
|
|
19
45
|
}
|
|
46
|
+
/**
|
|
47
|
+
* Проверяет финальный текст ответа (детектор + заявления об успехе).
|
|
48
|
+
* @param deps состояние, текст, контекст; @returns структурированный вердикт.
|
|
49
|
+
*/
|
|
20
50
|
async evaluate(deps) {
|
|
21
51
|
const { state, textContent, logger } = deps;
|
|
22
52
|
// Обновляем базу сравнения ДО validate: confidence-чек смотрит на
|
|
@@ -26,56 +56,136 @@ export class HallucinationGate {
|
|
|
26
56
|
state.lastModelText = textContent;
|
|
27
57
|
const result = await this.detector.validate(textContent);
|
|
28
58
|
if (result.status === "block") {
|
|
29
|
-
logger.warn
|
|
59
|
+
logger.diagnostic("warn", `Response blocked: ${result.reason}`);
|
|
30
60
|
return { action: "block", reason: result.reason || "" };
|
|
31
61
|
}
|
|
32
62
|
if (result.status === "warn") {
|
|
33
|
-
logger.warn
|
|
63
|
+
logger.diagnostic("warn", `Hallucination warning: ${result.reason}`);
|
|
34
64
|
this.displayWarnLine(result.reason, deps);
|
|
35
65
|
return { action: "warn" };
|
|
36
66
|
}
|
|
37
67
|
if (result.status === "retry") {
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
68
|
+
return this.applyRetry(deps, textContent, result);
|
|
69
|
+
}
|
|
70
|
+
// Проверка заявлений (ses_muih0ah5): сильное заявление о готовности
|
|
71
|
+
// («done», «published», «готово»), когда свежие результаты тулов — с ошибками.
|
|
72
|
+
// Одна ограниченная перепроверка — затем fail-open (принять как есть), не блок.
|
|
73
|
+
const claimRetry = this.checkSuccessClaim(deps, textContent);
|
|
74
|
+
if (claimRetry)
|
|
75
|
+
return claimRetry;
|
|
76
|
+
return { action: "accept" };
|
|
77
|
+
}
|
|
78
|
+
/**
|
|
79
|
+
* Общий инжект повтора: фиксирует отклонённый ответ, дописывает причину
|
|
80
|
+
* как `<system-summary>` и просит цикл о следующем ходе.
|
|
81
|
+
*/
|
|
82
|
+
applyRetry(deps, textContent, result) {
|
|
83
|
+
const { state, logger } = deps;
|
|
84
|
+
state.iterHallucinationRetry = true;
|
|
85
|
+
// Exit-on-complete fast-exit НЕ должен обходить финальный аудит: при
|
|
86
|
+
// активном плане модель может ответить "done" с невыполненными шагами
|
|
87
|
+
// (регрессия сертификации: модель ответила, не запустив свой скрипт).
|
|
88
|
+
// Короткое замыкание — только когда аудитить нечего.
|
|
89
|
+
if (deps.exitOnComplete && textContent?.trim() && !deps.hasFinalAudit) {
|
|
90
|
+
logger.debug("Exit-on-complete: stopping on first response");
|
|
91
|
+
// Сохраняем ДО break — lastText всё ещё текст предыдущей (туловой)
|
|
92
|
+
// итерации, и без этого итоговый ответ теряется (reported text: "").
|
|
93
|
+
state.lastText = textContent;
|
|
94
|
+
state.finalAnswerAccepted = true;
|
|
95
|
+
return { action: "exit" };
|
|
96
|
+
}
|
|
97
|
+
if (state.suppressRepetitionRetry && result.kind === "repetition") {
|
|
98
|
+
// Аудит отклонил предыдущий ответ и переспросил; его переформулировка
|
|
99
|
+
// выполненной задачи естественно "повторяющаяся" — это ожидаемо, а не
|
|
100
|
+
// деградация. Снижаем до предупреждения и пропускаем в acceptance path
|
|
101
|
+
// (сам аудит ограничен MAX_AUDIT_RETRIES).
|
|
102
|
+
state.suppressRepetitionRetry = false;
|
|
103
|
+
logger.diagnostic("warn", `Audit-triggered re-answer repetition — not counted as hallucination retry`);
|
|
104
|
+
this.displayWarnLine(result.reason, deps);
|
|
105
|
+
return { action: "accept" };
|
|
106
|
+
}
|
|
107
|
+
if (state.hallucinationRetries >= MAX_HALLUCINATION_RETRIES) {
|
|
108
|
+
logger.diagnostic("warn", `Hallucination retries exhausted (${MAX_HALLUCINATION_RETRIES}), returning error`);
|
|
109
|
+
return { action: "block", reason: t("hall.max_retries_exhausted") };
|
|
110
|
+
}
|
|
111
|
+
state.hallucinationRetries++;
|
|
112
|
+
logger.diagnostic("warn", `Hallucination retry (${state.hallucinationRetries}/${MAX_HALLUCINATION_RETRIES}): ${result.reason}`);
|
|
113
|
+
if (textContent) {
|
|
114
|
+
deps.contextManager.addMessage({ role: "assistant", content: textContent });
|
|
115
|
+
}
|
|
116
|
+
deps.contextManager.addMessage({
|
|
117
|
+
role: "user",
|
|
118
|
+
content: `<system-summary>[Retry context: ${result.reason}. Original task: "${deps.input}". You must either call a needed tool or provide a substantive response. Empty replies are not allowed.]</system-summary>`,
|
|
119
|
+
});
|
|
120
|
+
return { action: "retry" };
|
|
121
|
+
}
|
|
122
|
+
/**
|
|
123
|
+
* Детерминированные проверки заявлений против улик (без LLM): исходная
|
|
124
|
+
* проверка success-claim плюс заземление артефактов (файл отсутствует/
|
|
125
|
+
* не парсится) и провенанс вывода (вывод подан как исполненный без
|
|
126
|
+
* исполняющего тула). У каждого класса свой ограниченный бюджет перепроверок
|
|
127
|
+
* (fail-open): съеденный бюджет одной проверки не должен экранировать другую
|
|
128
|
+
* ложь в том же ответе (наблюдалось: retry success-claim съел единый бюджет,
|
|
129
|
+
* и «output written to fizzbuzz_output.txt» прошёл при отсутствующем файле).
|
|
130
|
+
*/
|
|
131
|
+
checkSuccessClaim(deps, textContent) {
|
|
132
|
+
const { state } = deps;
|
|
133
|
+
const text = textContent ?? "";
|
|
134
|
+
const evidence = lastToolEvidence(deps);
|
|
135
|
+
if (state.claimCheckRetries < MAX_CLAIM_CHECK_RETRIES) {
|
|
136
|
+
const contradiction = checkSuccessClaim(text, evidence);
|
|
137
|
+
if (contradiction) {
|
|
138
|
+
state.claimCheckRetries++;
|
|
139
|
+
return this.retryClaim(deps, textContent, t("hall.claim_contradiction", {
|
|
140
|
+
tool: contradiction.tool,
|
|
141
|
+
snippet: contradiction.snippet,
|
|
142
|
+
}), `Success-claim contradiction: ${contradiction.tool}: ${contradiction.snippet}`);
|
|
60
143
|
}
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
144
|
+
}
|
|
145
|
+
if (state.artifactClaimRetries < MAX_CLAIM_CHECK_RETRIES &&
|
|
146
|
+
deps.artifacts &&
|
|
147
|
+
deps.artifacts.length > 0) {
|
|
148
|
+
const artifact = checkArtifactClaims(text, deps.artifacts);
|
|
149
|
+
if (artifact) {
|
|
150
|
+
state.artifactClaimRetries++;
|
|
151
|
+
return this.retryClaim(deps, textContent, t("hall.claim_artifact", { path: artifact.path, detail: artifact.snippet }), `Artifact-claim contradiction: ${artifact.snippet}`);
|
|
64
152
|
}
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
153
|
+
}
|
|
154
|
+
if (state.outputClaimRetries < MAX_CLAIM_CHECK_RETRIES) {
|
|
155
|
+
const unverified = checkUnverifiedOutput(text, evidence);
|
|
156
|
+
if (unverified) {
|
|
157
|
+
state.outputClaimRetries++;
|
|
158
|
+
return this.retryClaim(deps, textContent, t("hall.claim_output_unverified", { detail: unverified.snippet }), `Unverified output: ${unverified.snippet}`);
|
|
69
159
|
}
|
|
70
|
-
deps.contextManager.addMessage({
|
|
71
|
-
role: "user",
|
|
72
|
-
content: `<system-summary>[Retry context: ${result.reason}. Original task: "${deps.input}". You must either call a needed tool or provide a substantive response. Empty replies are not allowed.]</system-summary>`,
|
|
73
|
-
});
|
|
74
|
-
return { action: "retry" };
|
|
75
160
|
}
|
|
76
|
-
return
|
|
161
|
+
return null;
|
|
162
|
+
}
|
|
163
|
+
/**
|
|
164
|
+
* Общий инжект claim-повтора: фиксирует отклонённый ответ, дописывает
|
|
165
|
+
* причину как `<system-summary>` и просит цикл о следующем ходе.
|
|
166
|
+
*/
|
|
167
|
+
retryClaim(deps, textContent, reason, logLine) {
|
|
168
|
+
const { state, logger } = deps;
|
|
169
|
+
state.iterHallucinationRetry = true;
|
|
170
|
+
// Переответ пересказывает выполненную задачу и естественно повторяется —
|
|
171
|
+
// бюджет халлюцинаций на его форму не жжём (та же логика, что даунгрейд
|
|
172
|
+
// в applyRetry после отклонения аудита).
|
|
173
|
+
state.suppressRepetitionRetry = true;
|
|
174
|
+
logger.diagnostic("warn", logLine);
|
|
175
|
+
if (textContent) {
|
|
176
|
+
deps.contextManager.addMessage({ role: "assistant", content: textContent });
|
|
177
|
+
}
|
|
178
|
+
deps.contextManager.addMessage({
|
|
179
|
+
role: "user",
|
|
180
|
+
content: `<system-summary>${reason} Original task: "${deps.input}".</system-summary>`,
|
|
181
|
+
});
|
|
182
|
+
return { action: "retry" };
|
|
77
183
|
}
|
|
78
184
|
displayWarnLine(reason, deps) {
|
|
185
|
+
// Диагностика: в чате только пользовательские уведомления; модель всё равно
|
|
186
|
+
// получает retry-контекст, вердикт остаётся в логах сессии/приложения.
|
|
187
|
+
if (!deps.verbose)
|
|
188
|
+
return;
|
|
79
189
|
const warnLine = `${t("hall.uncertainty_prefix").trim()} ${reason ?? ""}`;
|
|
80
190
|
if (deps.onMeta) {
|
|
81
191
|
deps.onMeta(`\n${pc.yellow(warnLine)}\n`);
|
|
@@ -1,4 +1,6 @@
|
|
|
1
|
+
/** Состояние одного запуска агентного цикла: счётчики, бюджеты, сигналы. */
|
|
1
2
|
import { FORCED_COMPACTION_COOLDOWN } from "./constants";
|
|
3
|
+
import { createArtifactChurnState } from "./artifact-progress";
|
|
2
4
|
/** Фабрика начального состояния цикла. */
|
|
3
5
|
export function createLoopState() {
|
|
4
6
|
return {
|
|
@@ -7,14 +9,22 @@ export function createLoopState() {
|
|
|
7
9
|
lastModelText: "",
|
|
8
10
|
lastForcedCompactionIteration: -FORCED_COMPACTION_COOLDOWN,
|
|
9
11
|
hallucinationRetries: 0,
|
|
12
|
+
claimCheckRetries: 0,
|
|
13
|
+
artifactClaimRetries: 0,
|
|
14
|
+
outputClaimRetries: 0,
|
|
10
15
|
lastToolSignature: "",
|
|
11
16
|
consecutiveToolFailures: 0,
|
|
17
|
+
consecutiveFailedBatches: 0,
|
|
18
|
+
honestStopNudged: false,
|
|
12
19
|
consecutiveToolSuccesses: 0,
|
|
13
20
|
repeatedToolCount: 0,
|
|
14
21
|
toolFailureCounts: new Map(),
|
|
15
22
|
memoryRuleRecorded: new Set(),
|
|
16
23
|
toolTargetCounts: new Map(),
|
|
17
24
|
cycleNudgedKeys: new Set(),
|
|
25
|
+
artifactChurn: createArtifactChurnState(),
|
|
26
|
+
sawSecurityBlock: false,
|
|
27
|
+
scriptWorkaroundNudged: false,
|
|
18
28
|
apiPromptTokens: 0,
|
|
19
29
|
apiCompletionTokens: 0,
|
|
20
30
|
apiCompletionChars: 0,
|
|
@@ -26,8 +36,13 @@ export function createLoopState() {
|
|
|
26
36
|
cacheSource: "none",
|
|
27
37
|
auditRetries: 0,
|
|
28
38
|
lastAuditSummary: "",
|
|
39
|
+
criticCalls: 0,
|
|
40
|
+
criticRepairCycles: 0,
|
|
41
|
+
mutationsSinceCritic: 0,
|
|
42
|
+
seenCriticIssues: new Set(),
|
|
29
43
|
emptyResponseRetries: 0,
|
|
30
44
|
emptyResponseExhausted: false,
|
|
45
|
+
retryLoopStopped: false,
|
|
31
46
|
auditFailed: false,
|
|
32
47
|
finalAnswerAccepted: false,
|
|
33
48
|
suppressRepetitionRetry: false,
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
/** Резолвер уровня reasoning на итерацию: override → политика → фикс. */
|
|
1
2
|
import { evaluateReasoningPolicy } from "../../modules/reasoning/policy";
|
|
2
3
|
/**
|
|
3
4
|
* Резолвер уровня reasoning на итерацию.
|
|
@@ -15,6 +16,11 @@ import { evaluateReasoningPolicy } from "../../modules/reasoning/policy";
|
|
|
15
16
|
* clearIterationSignals сразу после resolve).
|
|
16
17
|
*/
|
|
17
18
|
export class ReasoningEffortResolver {
|
|
19
|
+
/**
|
|
20
|
+
* Вычисляет уровень reasoning на итерацию (override → политика → фикс).
|
|
21
|
+
* @param deps состояние цикла, политика, конфиг, probe, стратегия.
|
|
22
|
+
* @returns уровень, стратегия и источник решения.
|
|
23
|
+
*/
|
|
18
24
|
resolve(deps) {
|
|
19
25
|
const { state, reasoningConfig, reasoningState } = deps;
|
|
20
26
|
let level;
|
|
@@ -42,7 +48,10 @@ export class ReasoningEffortResolver {
|
|
|
42
48
|
planCreated: state.iterPlanCreated,
|
|
43
49
|
consecutiveSuccesses: state.consecutiveToolSuccesses,
|
|
44
50
|
isRepetitive: state.iterRepetitive,
|
|
45
|
-
|
|
51
|
+
// Baseline — настроенный минимум (`min`, по умолчанию "low"),
|
|
52
|
+
// чтобы конфиг без явного baseline не жёг "medium" на пустяках.
|
|
53
|
+
// Политика всё равно повышает уровень по сигналам.
|
|
54
|
+
baseline: reasoningConfig.baseline ?? reasoningConfig.min,
|
|
46
55
|
}, deps.policyState);
|
|
47
56
|
level = policyResult.level;
|
|
48
57
|
source = "policy";
|
|
@@ -14,10 +14,10 @@ import { estimateTokens } from "../../llm/token-counter";
|
|
|
14
14
|
*/
|
|
15
15
|
export class TokenTracker {
|
|
16
16
|
costTracker;
|
|
17
|
-
|
|
18
|
-
constructor(costTracker,
|
|
17
|
+
getProvenance;
|
|
18
|
+
constructor(costTracker, getProvenance) {
|
|
19
19
|
this.costTracker = costTracker;
|
|
20
|
-
this.
|
|
20
|
+
this.getProvenance = getProvenance;
|
|
21
21
|
}
|
|
22
22
|
/**
|
|
23
23
|
* Начало итерации: фиксирует baseline API-токенов и аккумулирует оценку
|
|
@@ -64,7 +64,10 @@ export class TokenTracker {
|
|
|
64
64
|
state.cacheWriteTotal += state.cacheUsage.cacheWriteTokens;
|
|
65
65
|
state.cacheSource = state.cacheUsage.source;
|
|
66
66
|
}
|
|
67
|
+
const prov = this.getProvenance();
|
|
67
68
|
slog.logLlmUsage(iteration, {
|
|
69
|
+
provider: prov.provider,
|
|
70
|
+
model: prov.model,
|
|
68
71
|
promptTokens: prompt,
|
|
69
72
|
completionTokens: completion,
|
|
70
73
|
totalTokens: prompt + completion,
|
|
@@ -75,7 +78,7 @@ export class TokenTracker {
|
|
|
75
78
|
});
|
|
76
79
|
// Кеш учитываем только когда цифры пришли от API: оценка chars/4 о кеше
|
|
77
80
|
// ничего не знает и не должна менять тарификацию.
|
|
78
|
-
this.costTracker.record(prompt, completion,
|
|
81
|
+
this.costTracker.record(prompt, completion, prov.provider, source === "api" ? state.cacheUsage : undefined);
|
|
79
82
|
}
|
|
80
83
|
/**
|
|
81
84
|
* Финальные метрики результата. API-токены в приоритете; иначе — сумма
|
|
@@ -1,8 +1,10 @@
|
|
|
1
|
+
/** Исполнитель пакета тулов: жизненный цикл вызовов за итерацию. */
|
|
1
2
|
import { pc } from "../../ui/colors";
|
|
2
3
|
import { t } from "../../i18n/index";
|
|
3
|
-
import { summarizeToolArgs, truncateToolOutput,
|
|
4
|
+
import { summarizeToolArgs, truncateToolOutput, toolFailureSummary, isExecutableScriptPath, } from "./tool-output";
|
|
5
|
+
import { queueToolImages } from "./tool-images";
|
|
4
6
|
import { errMsg } from "../../utils";
|
|
5
|
-
import { MAX_CONSECUTIVE_TOOL_FAILURES, MIN_REPEATED_TOOL_FAILURES, } from "./constants";
|
|
7
|
+
import { MAX_CONSECUTIVE_TOOL_FAILURES, MIN_REPEATED_TOOL_FAILURES, MAX_CONSECUTIVE_FAILED_BATCHES, HARD_STOP_FAILED_BATCHES } from "./constants";
|
|
6
8
|
/**
|
|
7
9
|
* Выполнение пакета тулов, полученных от модели за одну итерацию.
|
|
8
10
|
*
|
|
@@ -24,6 +26,13 @@ export class ToolBatchExecutor {
|
|
|
24
26
|
constructor(deps) {
|
|
25
27
|
this.deps = deps;
|
|
26
28
|
}
|
|
29
|
+
/**
|
|
30
|
+
* Выполняет пакет tool_calls одной итерации (контекст, UI, учёт неудач).
|
|
31
|
+
* @param state состояние цикла; @param toolCalls вызовы от модели;
|
|
32
|
+
* @param boundedToolNames тулы с собственным лимитом вывода;
|
|
33
|
+
* @param textContent/reasoningContent/input тексты хода;
|
|
34
|
+
* @returns флаг прерывания по shutdown.
|
|
35
|
+
*/
|
|
27
36
|
async execute(state, toolCalls, boundedToolNames, textContent, reasoningContent, input, onTool, onMeta, slog) {
|
|
28
37
|
const { config, pluginManager, contextManager, logger } = this.deps;
|
|
29
38
|
const iteration = state.iteration;
|
|
@@ -62,9 +71,13 @@ export class ToolBatchExecutor {
|
|
|
62
71
|
};
|
|
63
72
|
const summaries = [];
|
|
64
73
|
let anyToolFailed = false;
|
|
74
|
+
let batchHasSuccess = false;
|
|
65
75
|
// Информационные read-only тулы, чей "фейл" — ожидаемое поведение
|
|
66
76
|
// (file_info "Not found" после delete_file) — исключены из учёта неудач.
|
|
67
77
|
const infoTools = new Set(["file_info"]);
|
|
78
|
+
// Флаг блока безопасности действует в пределах текущего пакета вызовов:
|
|
79
|
+
// иначе старый блок влиял бы на nudge через десятки итераций.
|
|
80
|
+
state.sawSecurityBlock = false;
|
|
68
81
|
for (const call of toolCalls) {
|
|
69
82
|
this.deps.setScope();
|
|
70
83
|
const startTime = Date.now();
|
|
@@ -77,6 +90,9 @@ export class ToolBatchExecutor {
|
|
|
77
90
|
onTool?.({ type: "start", tool: call.name, args: call.arguments, icon: toolIcon });
|
|
78
91
|
slog?.logToolCall(call, iteration);
|
|
79
92
|
const tokensBeforeTool = contextManager.getEstimatedTokens();
|
|
93
|
+
// Снимок стоимости ДО тула: рендеру нужна стоимость именно этого вызова
|
|
94
|
+
// (subagent/mcp/pipeline тратят токены), а не накопленная за сессию.
|
|
95
|
+
const costBeforeTool = this.deps.costTracker.total;
|
|
80
96
|
let result;
|
|
81
97
|
try {
|
|
82
98
|
result = await this.deps.toolExecutor.execute(call, this.deps.getAbortSignal());
|
|
@@ -89,7 +105,7 @@ export class ToolBatchExecutor {
|
|
|
89
105
|
synthesizePendingToolResults();
|
|
90
106
|
throw err;
|
|
91
107
|
}
|
|
92
|
-
logger.warn
|
|
108
|
+
logger.diagnostic("warn", `Tool ${call.name} threw: ${errMsg(err)}`);
|
|
93
109
|
result = {
|
|
94
110
|
success: false,
|
|
95
111
|
output: `${t("error.prefix")}${errMsg(err)}`,
|
|
@@ -104,6 +120,8 @@ export class ToolBatchExecutor {
|
|
|
104
120
|
const duration = Date.now() - startTime;
|
|
105
121
|
if (!result.success && !result.blocked && !infoTools.has(call.name))
|
|
106
122
|
anyToolFailed = true;
|
|
123
|
+
if (result.success)
|
|
124
|
+
batchHasSuccess = true;
|
|
107
125
|
if (result.success && call.name === "plan") {
|
|
108
126
|
const action = String(call.arguments.action ?? "");
|
|
109
127
|
if (action === "create" || action === "re-plan")
|
|
@@ -122,28 +140,34 @@ export class ToolBatchExecutor {
|
|
|
122
140
|
// Проверка наличия, а не истинности: read_file возвращает display ""
|
|
123
141
|
// на полном чтении (заголовок уже показывает путь) — фолбэк на пустую
|
|
124
142
|
// строку вывалил бы всё содержимое файла в REPL.
|
|
143
|
+
// kind="tool": тела тулов model-facing, в quiet-чатах скрываются
|
|
144
|
+
// (статусы контекста/компакции идут с kind по умолчанию и всегда видны).
|
|
145
|
+
const TOOL_META = "tool";
|
|
125
146
|
if (result.display !== undefined) {
|
|
126
147
|
if (result.display.length > 0) {
|
|
127
|
-
onMeta?.(
|
|
148
|
+
onMeta?.(`\n${result.display}\n`, TOOL_META);
|
|
128
149
|
}
|
|
129
150
|
}
|
|
130
151
|
else if (result.success) {
|
|
131
152
|
const metaOut = pluginManager.runOnMeta({ iteration, logger, contextManager }, result.output);
|
|
132
|
-
onMeta?.(
|
|
153
|
+
onMeta?.(`\n${pc.dim(metaOut)}\n`, TOOL_META);
|
|
133
154
|
}
|
|
134
155
|
else {
|
|
135
|
-
//
|
|
136
|
-
//
|
|
137
|
-
//
|
|
138
|
-
const
|
|
139
|
-
const metaOut =
|
|
140
|
-
? pluginManager.runOnMeta({ iteration, logger, contextManager },
|
|
156
|
+
// Упавший тул: `output` — model-facing (хинты, recovery-директивы,
|
|
157
|
+
// «Do NOT …»). Пользователю нужна спокойная суть — первая строка,
|
|
158
|
+
// а не инструкции для агента. Мягкие гарды — варнинги, не ошибки.
|
|
159
|
+
const failure = toolFailureSummary(result.output);
|
|
160
|
+
const metaOut = failure.text
|
|
161
|
+
? pluginManager.runOnMeta({ iteration, logger, contextManager }, failure.text)
|
|
141
162
|
: "";
|
|
142
|
-
if (metaOut)
|
|
143
|
-
|
|
163
|
+
if (metaOut) {
|
|
164
|
+
const color = failure.severity === "warn" ? pc.yellow : pc.red;
|
|
165
|
+
const glyph = failure.severity === "warn" ? "⚠" : "✗";
|
|
166
|
+
onMeta?.(`\n${color(`${glyph} ${metaOut}`)}\n`, TOOL_META);
|
|
167
|
+
}
|
|
144
168
|
}
|
|
145
169
|
if (result.diff) {
|
|
146
|
-
onMeta?.(
|
|
170
|
+
onMeta?.(`\n${result.diff}\n`, TOOL_META);
|
|
147
171
|
}
|
|
148
172
|
const currentTokens = contextManager.getEstimatedTokens();
|
|
149
173
|
const budget = contextManager.getBudget();
|
|
@@ -158,17 +182,40 @@ export class ToolBatchExecutor {
|
|
|
158
182
|
arguments: call.arguments,
|
|
159
183
|
});
|
|
160
184
|
answeredToolCallIds.add(call.id);
|
|
185
|
+
// Изображения тула (browser screenshot и т.п.) встают в очередь и
|
|
186
|
+
// прицепятся к следующему user-сообщению — обычно к <system-summary>
|
|
187
|
+
// в конце этого же batch'а. В role:"tool" строку base64 не пишем.
|
|
188
|
+
queueToolImages(contextManager, result.images);
|
|
161
189
|
const tokensAfterTool = contextManager.getEstimatedTokens();
|
|
190
|
+
const costAfterTool = this.deps.costTracker.total;
|
|
162
191
|
onTool?.({
|
|
163
192
|
type: "end",
|
|
164
193
|
tool: call.name,
|
|
165
194
|
args: call.arguments,
|
|
166
195
|
duration,
|
|
167
196
|
error: !result.success,
|
|
197
|
+
output: typeof result.output === "string" ? result.output : undefined,
|
|
168
198
|
ctxDelta: tokensAfterTool - tokensBeforeTool,
|
|
169
|
-
costUsd:
|
|
199
|
+
costUsd: costBeforeTool !== undefined && costAfterTool !== undefined
|
|
200
|
+
? costAfterTool - costBeforeTool
|
|
201
|
+
: undefined,
|
|
170
202
|
});
|
|
171
203
|
summaries.push(`[Tool: ${call.name}${summarizeToolArgs(call.arguments)} → ${truncatedOutput.slice(0, 200)}]`);
|
|
204
|
+
// Видели блок безопасности? Запоминаем для эвристики скрипта-обёртки.
|
|
205
|
+
if (typeof result.output === "string" && result.output.includes("[SECURITY BLOCKED]")) {
|
|
206
|
+
state.sawSecurityBlock = true;
|
|
207
|
+
}
|
|
208
|
+
// Скрипт-обход: после блока безопасности запись shell-скрипта
|
|
209
|
+
// (.bat/.cmd/.sh/.ps1) почти всегда — попытка обойти заблокированный
|
|
210
|
+
// оператор; nudge один раз, обобщённо (без привязки к тулу/языку).
|
|
211
|
+
if (state.sawSecurityBlock &&
|
|
212
|
+
!state.scriptWorkaroundNudged &&
|
|
213
|
+
call.name === "write_file" &&
|
|
214
|
+
typeof call.arguments.path === "string" &&
|
|
215
|
+
isExecutableScriptPath(call.arguments.path)) {
|
|
216
|
+
state.scriptWorkaroundNudged = true;
|
|
217
|
+
summaries.push(t("exec.script_workaround_nudge"));
|
|
218
|
+
}
|
|
172
219
|
if (config.session.autoSave) {
|
|
173
220
|
slog?.logToolResult(call, result, duration, iteration);
|
|
174
221
|
}
|
|
@@ -188,7 +235,7 @@ export class ToolBatchExecutor {
|
|
|
188
235
|
const memStore = this.deps.memoryStore;
|
|
189
236
|
if (memStore) {
|
|
190
237
|
memStore.appendRule("errors", `Tool ${key} failed ${prev.count}x (${prev.error})`, `Repeated ${key} failures suggest a systemic problem (config, environment, or a broken tool), not a one-off`, "Check the error message, verify the tool's dependencies are installed/configured, and consider a different tool");
|
|
191
|
-
logger.warn
|
|
238
|
+
logger.diagnostic("warn", `Recorded repeated ${key} failures to memory (${prev.count}x)`);
|
|
192
239
|
}
|
|
193
240
|
}
|
|
194
241
|
}
|
|
@@ -210,8 +257,8 @@ export class ToolBatchExecutor {
|
|
|
210
257
|
const recoveryMsg = t("exec.consecutive_failures_recovery", {
|
|
211
258
|
count: state.consecutiveToolFailures,
|
|
212
259
|
});
|
|
213
|
-
logger.warn
|
|
214
|
-
const taskSnippet = input.length > 200 ? input.slice(0, 200)
|
|
260
|
+
logger.diagnostic("warn", `Consecutive tool failures: ${state.consecutiveToolFailures}`);
|
|
261
|
+
const taskSnippet = input.length > 200 ? `${input.slice(0, 200)}...` : input;
|
|
215
262
|
const taskReminder = t("exec.task_reminder", { task: taskSnippet });
|
|
216
263
|
contextManager.addMessage({
|
|
217
264
|
role: "user",
|
|
@@ -222,6 +269,34 @@ export class ToolBatchExecutor {
|
|
|
222
269
|
memStore.appendRule("errors", `${state.consecutiveToolFailures} consecutive tool failures`, "Multiple tools failing suggests environment or configuration issue", "Check dependencies, verify file paths, try write_file directly instead of shell commands");
|
|
223
270
|
}
|
|
224
271
|
}
|
|
272
|
+
// Honest-stop полностью провальных пакетов: каждый вызов пакета — неудача
|
|
273
|
+
// или tool-level блок (в отличие от consecutiveToolFailures выше, блоки
|
|
274
|
+
// ВХОДЯТ в учёт — перебор вариантов заблокированной команды это та же
|
|
275
|
+
// петля). Смешанные пакеты и успехи сбрасывают стрик: связка
|
|
276
|
+
// «упал → поправил → упал» (дебаг) под него не попадает.
|
|
277
|
+
// Plugin-level блоки (result.blocked, guard-rails) нейтральны по контракту
|
|
278
|
+
// ToolResult.blocked — не успех и не неудача.
|
|
279
|
+
if (anyToolFailed && !batchHasSuccess) {
|
|
280
|
+
state.consecutiveFailedBatches++;
|
|
281
|
+
}
|
|
282
|
+
else if (batchHasSuccess) {
|
|
283
|
+
state.consecutiveFailedBatches = 0;
|
|
284
|
+
state.honestStopNudged = false;
|
|
285
|
+
}
|
|
286
|
+
if (state.consecutiveFailedBatches >= MAX_CONSECUTIVE_FAILED_BATCHES &&
|
|
287
|
+
!state.honestStopNudged) {
|
|
288
|
+
state.honestStopNudged = true;
|
|
289
|
+
logger.diagnostic("warn", `Consecutive failed tool batches: ${state.consecutiveFailedBatches} — honest-stop directive`);
|
|
290
|
+
contextManager.addMessage({
|
|
291
|
+
role: "user",
|
|
292
|
+
content: `<system-summary>${t("exec.honest_stop", { count: state.consecutiveFailedBatches })}</system-summary>`,
|
|
293
|
+
});
|
|
294
|
+
}
|
|
295
|
+
if (state.consecutiveFailedBatches >= HARD_STOP_FAILED_BATCHES) {
|
|
296
|
+
state.retryLoopStopped = true;
|
|
297
|
+
logger.diagnostic("warn", `Retry loop hard-stopped after ${state.consecutiveFailedBatches} consecutive failed batches`);
|
|
298
|
+
return { interrupted: true };
|
|
299
|
+
}
|
|
225
300
|
// Статусная строка плана после каждого пакета тулов. Заменяет динамический
|
|
226
301
|
// plan-блок, который жил в system prompt (удалён ради KV-cache — план
|
|
227
302
|
// меняется каждую итерацию).
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Ставит изображения, произведённые тулом, в очередь pending-изображений
|
|
3
|
+
* контекста. Они прикрепятся к следующему user-сообщению (обычно это
|
|
4
|
+
* `<system-summary>` с итогами пакета тулов в конце batch'а) — так картинка
|
|
5
|
+
* доходит до модели как валидный image-part, а не как base64-текст в
|
|
6
|
+
* `role:"tool"` (который и не портируем, и усекается бюджетом).
|
|
7
|
+
*
|
|
8
|
+
* Намеренно не складывает изображения в промежуточные tool-сообщения:
|
|
9
|
+
* вставка user-сообщения между результатами одного assistant(tool_calls)
|
|
10
|
+
* нарушает порядок, требуемый Jinja-шаблонами (см. architecture.md).
|
|
11
|
+
*/
|
|
12
|
+
export function queueToolImages(sink, images) {
|
|
13
|
+
if (!sink || !images || images.length === 0)
|
|
14
|
+
return;
|
|
15
|
+
for (const image of images) {
|
|
16
|
+
sink.addPendingImage(image);
|
|
17
|
+
}
|
|
18
|
+
}
|