micro-models-agent 0.6.0 → 0.6.2
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/dist/agent/error-escalation.d.ts +1 -0
- package/dist/agent/error-escalation.d.ts.map +1 -1
- package/dist/agent/error-escalation.js +16 -3
- package/dist/agent/error-escalation.js.map +1 -1
- package/dist/agent/loop.d.ts.map +1 -1
- package/dist/agent/loop.js +177 -200
- package/dist/agent/loop.js.map +1 -1
- package/dist/agent/tool-executor.js +1 -1
- package/dist/agent/tool-executor.js.map +1 -1
- package/dist/agent/write-enforcer.d.ts +1 -1
- package/dist/agent/write-enforcer.d.ts.map +1 -1
- package/dist/agent/write-enforcer.js +4 -24
- package/dist/agent/write-enforcer.js.map +1 -1
- package/dist/config/config.d.ts.map +1 -1
- package/dist/config/config.js +2 -2
- package/dist/config/config.js.map +1 -1
- package/dist/tools/adapters/bash-to-fs.d.ts +20 -0
- package/dist/tools/adapters/bash-to-fs.d.ts.map +1 -0
- package/dist/tools/adapters/bash-to-fs.js +74 -0
- package/dist/tools/adapters/bash-to-fs.js.map +1 -0
- package/dist/tools/adapters/content-sanitizer.d.ts +13 -0
- package/dist/tools/adapters/content-sanitizer.d.ts.map +1 -0
- package/dist/tools/adapters/content-sanitizer.js +73 -0
- package/dist/tools/adapters/content-sanitizer.js.map +1 -0
- package/dist/tools/adapters/grounding-fixer.d.ts +15 -0
- package/dist/tools/adapters/grounding-fixer.d.ts.map +1 -0
- package/dist/tools/adapters/grounding-fixer.js +57 -0
- package/dist/tools/adapters/grounding-fixer.js.map +1 -0
- package/dist/tools/adapters/index.d.ts +6 -0
- package/dist/tools/adapters/index.d.ts.map +1 -0
- package/dist/tools/adapters/index.js +5 -0
- package/dist/tools/adapters/index.js.map +1 -0
- package/dist/tools/adapters/pipeline.d.ts +34 -0
- package/dist/tools/adapters/pipeline.d.ts.map +1 -0
- package/dist/tools/adapters/pipeline.js +58 -0
- package/dist/tools/adapters/pipeline.js.map +1 -0
- package/dist/tools/adapters/types.d.ts +46 -0
- package/dist/tools/adapters/types.d.ts.map +1 -0
- package/dist/tools/adapters/types.js +2 -0
- package/dist/tools/adapters/types.js.map +1 -0
- package/dist/tools/subagent.d.ts.map +1 -1
- package/dist/tools/subagent.js +36 -1
- package/dist/tools/subagent.js.map +1 -1
- package/package.json +1 -1
|
@@ -8,6 +8,7 @@ import type { OutputRenderer } from "../ui/renderer.js";
|
|
|
8
8
|
*/
|
|
9
9
|
export declare class ErrorEscalator {
|
|
10
10
|
consecutiveToolErrors: Map<string, number>;
|
|
11
|
+
lastToolArgs: Map<string, string>;
|
|
11
12
|
totalToolErrors: number;
|
|
12
13
|
specialistSpawnedFor: string | null;
|
|
13
14
|
errorStrategy: "normal" | "subagent-hint" | "force-subagent";
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"error-escalation.d.ts","sourceRoot":"","sources":["../../src/agent/error-escalation.ts"],"names":[],"mappings":"AAQA,OAAO,KAAK,EAAE,WAAW,EAAE,WAAW,EAAE,MAAM,oBAAoB,CAAC;AACnE,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,sBAAsB,CAAC;AACzD,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,oBAAoB,CAAC;AACvD,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,mBAAmB,CAAC;AAgGxD;;;GAGG;AACH,qBAAa,cAAc;IACzB,qBAAqB,sBAA6B;IAClD,eAAe,SAAK;IACpB,oBAAoB,EAAE,MAAM,GAAG,IAAI,CAAQ;IAC3C,aAAa,EAAE,QAAQ,GAAG,eAAe,GAAG,gBAAgB,CAAY;IAExE,YAAY,CAAC,QAAQ,EAAE,MAAM,GAAG,IAAI;
|
|
1
|
+
{"version":3,"file":"error-escalation.d.ts","sourceRoot":"","sources":["../../src/agent/error-escalation.ts"],"names":[],"mappings":"AAQA,OAAO,KAAK,EAAE,WAAW,EAAE,WAAW,EAAE,MAAM,oBAAoB,CAAC;AACnE,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,sBAAsB,CAAC;AACzD,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,oBAAoB,CAAC;AACvD,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,mBAAmB,CAAC;AAgGxD;;;GAGG;AACH,qBAAa,cAAc;IACzB,qBAAqB,sBAA6B;IAClD,YAAY,sBAA6B;IACzC,eAAe,SAAK;IACpB,oBAAoB,EAAE,MAAM,GAAG,IAAI,CAAQ;IAC3C,aAAa,EAAE,QAAQ,GAAG,eAAe,GAAG,gBAAgB,CAAY;IAExE,YAAY,CAAC,QAAQ,EAAE,MAAM,GAAG,IAAI;IAWpC,KAAK,IAAI,IAAI;IAQP,eAAe,CACnB,QAAQ,EAAE,MAAM,EAChB,UAAU,EAAE,MAAM,EAClB,QAAQ,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EACjC,MAAM,EAAE,MAAM,EACd,QAAQ,EAAE,WAAW,EAAE,EACvB,YAAY,EAAE,MAAM,EAAE,EACtB,cAAc,EAAE,MAAM,EACtB,QAAQ,EAAE,cAAc,GAAG,SAAS,EACpC,KAAK,EAAE,OAAO,EACd,QAAQ,EAAE,WAAW,EACrB,QAAQ,EAAE,YAAY,EACtB,YAAY,EAAE,YAAY,EAC1B,UAAU,EAAE,GAAG,EACf,MAAM,EAAE,GAAG,GACV,OAAO,CAAC,UAAU,GAAG,OAAO,CAAC;CA2GjC"}
|
|
@@ -55,6 +55,7 @@ async function spawnSpecialist(p) {
|
|
|
55
55
|
*/
|
|
56
56
|
export class ErrorEscalator {
|
|
57
57
|
consecutiveToolErrors = new Map();
|
|
58
|
+
lastToolArgs = new Map();
|
|
58
59
|
totalToolErrors = 0;
|
|
59
60
|
specialistSpawnedFor = null;
|
|
60
61
|
errorStrategy = "normal";
|
|
@@ -63,10 +64,15 @@ export class ErrorEscalator {
|
|
|
63
64
|
if (key.startsWith(toolName + "::"))
|
|
64
65
|
this.consecutiveToolErrors.delete(key);
|
|
65
66
|
}
|
|
67
|
+
for (const [key] of this.lastToolArgs) {
|
|
68
|
+
if (key.startsWith(toolName + "::"))
|
|
69
|
+
this.lastToolArgs.delete(key);
|
|
70
|
+
}
|
|
66
71
|
this.specialistSpawnedFor = null;
|
|
67
72
|
}
|
|
68
73
|
reset() {
|
|
69
74
|
this.consecutiveToolErrors.clear();
|
|
75
|
+
this.lastToolArgs.clear();
|
|
70
76
|
this.totalToolErrors = 0;
|
|
71
77
|
this.specialistSpawnedFor = null;
|
|
72
78
|
this.errorStrategy = "normal";
|
|
@@ -77,6 +83,13 @@ export class ErrorEscalator {
|
|
|
77
83
|
.slice(0, 100)
|
|
78
84
|
.replace(/[A-Z]:\\[^\s"']+/gi, "<PATH>")
|
|
79
85
|
.replace(/\/[^\s"']+/g, "<PATH>")}`;
|
|
86
|
+
// Если аргументы изменились — сбрасываем счётчик ошибок для этого ключа
|
|
87
|
+
const argsStr = JSON.stringify(toolArgs);
|
|
88
|
+
const prevArgs = this.lastToolArgs.get(errKey);
|
|
89
|
+
if (prevArgs !== undefined && prevArgs !== argsStr) {
|
|
90
|
+
this.consecutiveToolErrors.delete(errKey);
|
|
91
|
+
}
|
|
92
|
+
this.lastToolArgs.set(errKey, argsStr);
|
|
80
93
|
const prevCount = this.consecutiveToolErrors.get(errKey) ?? 0;
|
|
81
94
|
this.consecutiveToolErrors.set(errKey, prevCount + 1);
|
|
82
95
|
const errorCount = prevCount + 1;
|
|
@@ -138,15 +151,15 @@ export class ErrorEscalator {
|
|
|
138
151
|
if (!quiet)
|
|
139
152
|
renderer?.writeWarning(` [strategy: subagent-hint after ${this.totalToolErrors} errors]`);
|
|
140
153
|
}
|
|
141
|
-
if (errorCount >=
|
|
154
|
+
if (errorCount >= 6) {
|
|
142
155
|
const blockId = generateToolCallId();
|
|
143
156
|
messages.push({
|
|
144
157
|
role: "tool",
|
|
145
|
-
content: `BLOCKED: Tool "${toolName}" failed ${errorCount} times.
|
|
158
|
+
content: `BLOCKED: Tool "${toolName}" failed ${errorCount} times with the same error. Use subagent for a fresh context or try a different approach.`,
|
|
146
159
|
tool_call_id: blockId,
|
|
147
160
|
});
|
|
148
161
|
if (!quiet)
|
|
149
|
-
renderer?.writeWarning(` [blocked ${toolName}:
|
|
162
|
+
renderer?.writeWarning(` [blocked ${toolName}: ${errorCount} consecutive errors]`);
|
|
150
163
|
return "block";
|
|
151
164
|
}
|
|
152
165
|
return "block";
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"error-escalation.js","sourceRoot":"","sources":["../../src/agent/error-escalation.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,kBAAkB,EAAE,MAAM,oBAAoB,CAAC;AACxD,OAAO,EAAE,OAAO,EAAE,QAAQ,EAAE,MAAM,cAAc,CAAC;AACjD,OAAO,EAAE,UAAU,EAAE,mBAAmB,EAAE,MAAM,qBAAqB,CAAC;AACtE,OAAO,EAAE,mBAAmB,EAAE,cAAc,EAAE,MAAM,uBAAuB,CAAC;AAC5E,OAAO,EAAE,oBAAoB,EAAE,MAAM,wBAAwB,CAAC;AAC9D,OAAO,EAAE,eAAe,EAAE,MAAM,sBAAsB,CAAC;AACvD,OAAO,EAAE,gBAAgB,EAAE,MAAM,4BAA4B,CAAC;AAC9D,OAAO,EAAE,cAAc,EAAE,MAAM,oBAAoB,CAAC;AA6BpD;;GAEG;AACH,KAAK,UAAU,eAAe,CAAC,CAAmB;IAChD,IAAI,CAAC,CAAC,CAAC,KAAK,EAAE,CAAC;QACb,CAAC,CAAC,QAAQ,EAAE,eAAe,CACzB,YAAY,EACZ,YAAY,CAAC,CAAC,WAAW,CAAC,KAAK,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,OAAO,CAAC,KAAK,EAAE,GAAG,CAAC,YAAY,CACvE,CAAC;IACJ,CAAC;IACD,MAAM,IAAI,GAAG,mBAAmB,CAC9B,CAAC,CAAC,QAAQ,EACV,CAAC,CAAC,QAAQ,EACV,CAAC,CAAC,WAAW,EACb,CAAC,CAAC,cAAc,EAChB,CAAC,CAAC,UAAU,CACb,CAAC;IACF,MAAM,GAAG,GAAG,oBAAoB,CAAC,OAAO,CAAC,GAAG,EAAE,CAAC,CAAC;IAChD,MAAM,GAAG,GAAG,IAAI,gBAAgB,EAAE,CAAC;IACnC,IAAI,CAAC;QACH,OAAO,CACL,MAAM,EACN,2BAA2B,CAAC,CAAC,QAAQ,cAAc,CAAC,CAAC,UAAU,GAAG,CACnE,CAAC;QACF,MAAM,CAAC,GAAG,MAAM,eAAe,CAC7B,CAAC,CAAC,QAAQ,EACV,CAAC,CAAC,QAAQ,EACV,IAAI,EACJ,GAAG,EACH,OAAO,CAAC,GAAG,EAAE,EACb,CAAC,CAAC,KAAK,EACP,GAAG,EACH,CAAC,CAAC,YAAY,EACd,CAAC,CAAC,UAAU,CAAC,YAAY,EACzB,CAAC,CAAC,MAAM,CAAC,SAAS,EAClB,CAAC,CAAC,aAAa,CAAC,QAAQ,CACzB,CAAC;QACF,KAAK,IAAI,CAAC,GAAG,CAAC,CAAC,QAAQ,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC,IAAI,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC;YAChD,IACE,CAAC,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC,IAAI,KAAK,MAAM;gBAC7B,CAAC,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC,YAAY,KAAK,CAAC,CAAC,MAAM,EACvC,CAAC;gBACD,MAAM,IAAI,GACR,CAAC,CAAC,MAAM,CAAC,MAAM,GAAG,CAAC;oBACjB,CAAC,CAAC,iCAAiC,CAAC,CAAC,QAAQ,kBAAkB,CAAC,CAAC,MAAM,CAAC,IAAI,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,OAAO,8BAA8B;oBAC9H,CAAC,CAAC,yBAAyB,CAAC,CAAC,QAAQ,aAAa,CAAC,CAAC,OAAO,4BAA4B,CAAC;gBAC5F,CAAC,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC,OAAO,GAAG,cAAc,CAAC,CAAC,CAAC,QAAQ,EAAE,IAAI,EAAE,CAAC,CAAC,CAAC;gBAC5D,MAAM;YACR,CAAC;QACH,CAAC;QACD,KAAK,MAAM,CAAC,IAAI,CAAC,CAAC,YAAY,EAAE,CAAC;YAC/B,IAAI,CAAC,CAAC,CAAC,YAAY,CAAC,QAAQ,CAAC,CAAC,CAAC;gBAAE,CAAC,CAAC,YAAY,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;QAC1D,CAAC;QACD,MAAM,GAAG,GAAG,GAAG,CAAC,SAAS,EAAE,CAAC;QAC5B,IAAI,CAAC,CAAC,CAAC,KAAK,IAAI,CAAC,CAAC,QAAQ,EAAE,eAAe;YACzC,CAAC,CAAC,QAAQ,CAAC,eAAe,CAAC;gBACzB,KAAK,EAAE,GAAG,CAAC,KAAK;gBAChB,SAAS,EAAE,GAAG,CAAC,SAAS;aACzB,CAAC,CAAC;QACL,OAAO,CACL,MAAM,EACN,4BAA4B,CAAC,CAAC,YAAY,CAAC,MAAM,aAAa,CAAC,CAAC,KAAK,cAAc,CAAC,CAAC,MAAM,CAAC,MAAM,EAAE,CACrG,CAAC;QACF,OAAO,IAAI,CAAC;IACd,CAAC;IAAC,OAAO,CAAM,EAAE,CAAC;QAChB,QAAQ,CAAC,MAAM,EAAE,qBAAqB,CAAC,CAAC,OAAO,EAAE,CAAC,CAAC;QACnD,IAAI,CAAC,CAAC,CAAC,KAAK;YAAE,CAAC,CAAC,QAAQ,EAAE,UAAU,CAAC,yBAAyB,CAAC,CAAC,OAAO,GAAG,CAAC,CAAC;QAC5E,OAAO,KAAK,CAAC;IACf,CAAC;AACH,CAAC;AAED;;;GAGG;AACH,MAAM,OAAO,cAAc;IACzB,qBAAqB,GAAG,IAAI,GAAG,EAAkB,CAAC;IAClD,eAAe,GAAG,CAAC,CAAC;IACpB,oBAAoB,GAAkB,IAAI,CAAC;IAC3C,aAAa,GAAkD,QAAQ,CAAC;IAExE,YAAY,CAAC,QAAgB;QAC3B,KAAK,MAAM,CAAC,GAAG,CAAC,IAAI,IAAI,CAAC,qBAAqB,EAAE,CAAC;YAC/C,IAAI,GAAG,CAAC,UAAU,CAAC,QAAQ,GAAG,IAAI,CAAC;gBACjC,IAAI,CAAC,qBAAqB,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC;QAC3C,CAAC;QACD,IAAI,CAAC,oBAAoB,GAAG,IAAI,CAAC;IACnC,CAAC;IAED,KAAK;QACH,IAAI,CAAC,qBAAqB,CAAC,KAAK,EAAE,CAAC;QACnC,IAAI,CAAC,eAAe,GAAG,CAAC,CAAC;QACzB,IAAI,CAAC,oBAAoB,GAAG,IAAI,CAAC;QACjC,IAAI,CAAC,aAAa,GAAG,QAAQ,CAAC;IAChC,CAAC;IAED,KAAK,CAAC,eAAe,CACnB,QAAgB,EAChB,UAAkB,EAClB,QAAiC,EACjC,MAAc,EACd,QAAuB,EACvB,YAAsB,EACtB,cAAsB,EACtB,QAAoC,EACpC,KAAc,EACd,QAAqB,EACrB,QAAsB,EACtB,YAA0B,EAC1B,UAAe,EACf,MAAW;QAEX,IAAI,CAAC,eAAe,EAAE,CAAC;QACvB,MAAM,MAAM,GAAG,GAAG,QAAQ,KAAK,UAAU;aACtC,KAAK,CAAC,CAAC,EAAE,GAAG,CAAC;aACb,OAAO,CAAC,oBAAoB,EAAE,QAAQ,CAAC;aACvC,OAAO,CAAC,aAAa,EAAE,QAAQ,CAAC,EAAE,CAAC;
|
|
1
|
+
{"version":3,"file":"error-escalation.js","sourceRoot":"","sources":["../../src/agent/error-escalation.ts"],"names":[],"mappings":"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"}
|
package/dist/agent/loop.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"loop.d.ts","sourceRoot":"","sources":["../../src/agent/loop.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,WAAW,EAAE,WAAW,EAAE,MAAM,oBAAoB,CAAC;AACnE,OAAO,EAAE,YAAY,EAAE,MAAM,sBAAsB,CAAC;
|
|
1
|
+
{"version":3,"file":"loop.d.ts","sourceRoot":"","sources":["../../src/agent/loop.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,WAAW,EAAE,WAAW,EAAE,MAAM,oBAAoB,CAAC;AACnE,OAAO,EAAE,YAAY,EAAE,MAAM,sBAAsB,CAAC;AAQpD,OAAO,EAAE,cAAc,EAAE,MAAM,cAAc,CAAC;AAgC9C,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,mBAAmB,CAAC;AAcxD,OAAO,KAAK,EAAE,SAAS,EAAE,YAAY,EAAE,MAAM,oBAAoB,CAAC;AAqFlE;;;;GAIG;AACH,MAAM,WAAW,eAAe;IAC9B,QAAQ,EAAE,WAAW,EAAE,CAAC;IACxB,eAAe,CAAC,EAAE;QAAE,QAAQ,EAAE,MAAM,CAAC;QAAC,OAAO,CAAC,EAAE,MAAM,EAAE,CAAA;KAAE,CAAC;CAC5D;AAED;;;;;;;;;;;;;;;;;;;;;GAqBG;AACH,wBAAsB,YAAY,CAChC,QAAQ,EAAE,WAAW,EACrB,QAAQ,EAAE,YAAY,EACtB,MAAM,EAAE,MAAM,EACd,cAAc,CAAC,EAAE,cAAc,EAC/B,gBAAgB,CAAC,EAAE,WAAW,EAAE,EAChC,QAAQ,CAAC,EAAE,cAAc,EACzB,YAAY,CAAC,EAAE,MAAM,EACrB,OAAO,CAAC,EAAE;IACR,KAAK,CAAC,EAAE,OAAO,CAAC;IAChB,YAAY,CAAC,EAAE,OAAO,CAAC;IACvB,IAAI,CAAC,EAAE,SAAS,CAAC;IACjB,KAAK,CAAC,EAAE,YAAY,CAAC;CACtB,GACA,OAAO,CAAC,eAAe,CAAC,CAiqC1B"}
|
package/dist/agent/loop.js
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
|
-
import { readFileSync
|
|
1
|
+
import { readFileSync } from "node:fs";
|
|
2
2
|
import { join, isAbsolute, relative } from "node:path";
|
|
3
3
|
import { parseToolCalls } from "../tools/parse-tool-call.js";
|
|
4
|
+
import { AdapterPipeline, } from "../tools/adapters/index.js";
|
|
4
5
|
import { parseFileRefs } from "../file-loader.js";
|
|
5
6
|
import { ContextManager } from "./context.js";
|
|
6
7
|
import { ModeRegistry } from "./modes/registry.js";
|
|
@@ -225,6 +226,8 @@ export async function runAgentLoop(provider, registry, prompt, contextManager, p
|
|
|
225
226
|
let consecutiveInvalidCalls = 0; // счётчик невалидных tool call подряд
|
|
226
227
|
/** Счётчик бесполезных действий (list_dir, glob_search, todo list без результата) */
|
|
227
228
|
let uselessActionCount = 0;
|
|
229
|
+
/** Сколько шагов подряд модель не вызывает инструменты */
|
|
230
|
+
let consecutiveNoToolSteps = 0;
|
|
228
231
|
/** История последних чтений файлов для.detect повторных чтений */
|
|
229
232
|
const recentReadFiles = [];
|
|
230
233
|
/** История последних grep-запросов для detect повторных поисков */
|
|
@@ -263,6 +266,9 @@ export async function runAgentLoop(provider, registry, prompt, contextManager, p
|
|
|
263
266
|
]);
|
|
264
267
|
const errorEscalator = new ErrorEscalator();
|
|
265
268
|
const writeEnforcer = new WriteEnforcer();
|
|
269
|
+
const adapterPipeline = new AdapterPipeline();
|
|
270
|
+
/** Отслеживание созданных/изменённых файлов за всю сессию */
|
|
271
|
+
const createdFiles = [];
|
|
266
272
|
// Reset abort signal for this run
|
|
267
273
|
if (renderer?.abortSignal === undefined) {
|
|
268
274
|
// Renderer doesn't support abort — fine
|
|
@@ -281,7 +287,6 @@ export async function runAgentLoop(provider, registry, prompt, contextManager, p
|
|
|
281
287
|
break;
|
|
282
288
|
}
|
|
283
289
|
let skillsAutoLoaded = false;
|
|
284
|
-
const createdFiles = []; // отслеживание созданных/изменённых файлов
|
|
285
290
|
logDebug("LOOP", `step ${step + 1}/${maxSteps} starting, ${messages.length} messages`);
|
|
286
291
|
// Инкрементальный подсчёт — считаем только новые сообщения (быстрее в ~100x на больших историях)
|
|
287
292
|
if (step === 0) {
|
|
@@ -426,6 +431,36 @@ export async function runAgentLoop(provider, registry, prompt, contextManager, p
|
|
|
426
431
|
consecutiveEmpty = 0;
|
|
427
432
|
messages.push({ role: "assistant", content: response });
|
|
428
433
|
const { validCalls, invalidCalls } = parseToolCalls(response);
|
|
434
|
+
// ─── Adapter pipeline: чиним кривые вызовы маленьких моделей ──
|
|
435
|
+
const adapterLogs = [];
|
|
436
|
+
const adaptedCalls = [];
|
|
437
|
+
const adapterCtx = {
|
|
438
|
+
cwd: process.cwd(),
|
|
439
|
+
config,
|
|
440
|
+
responseText: response,
|
|
441
|
+
existingFiles: createdFiles,
|
|
442
|
+
};
|
|
443
|
+
for (const call of validCalls) {
|
|
444
|
+
const result = await adapterPipeline.process(call, adapterCtx);
|
|
445
|
+
if ("blocked" in result) {
|
|
446
|
+
invalidCalls.push(result.blocked);
|
|
447
|
+
if (!quiet)
|
|
448
|
+
renderer?.writeError(` [adapter blocked: ${result.blocked}]`);
|
|
449
|
+
}
|
|
450
|
+
else {
|
|
451
|
+
adaptedCalls.push(result.call);
|
|
452
|
+
adapterLogs.push(...result.logs);
|
|
453
|
+
}
|
|
454
|
+
}
|
|
455
|
+
// Заменяем validCalls на адаптированные
|
|
456
|
+
validCalls.length = 0;
|
|
457
|
+
validCalls.push(...adaptedCalls);
|
|
458
|
+
// Показываем логи адаптеров
|
|
459
|
+
if (adapterLogs.length > 0 && !quiet) {
|
|
460
|
+
for (const log of adapterLogs) {
|
|
461
|
+
renderer?.writeDim(` ${log}`);
|
|
462
|
+
}
|
|
463
|
+
}
|
|
429
464
|
if (validCalls.length === 0) {
|
|
430
465
|
if (invalidCalls.length > 0) {
|
|
431
466
|
// If the response has substantial text outside tool_call tags,
|
|
@@ -469,141 +504,122 @@ export async function runAgentLoop(provider, registry, prompt, contextManager, p
|
|
|
469
504
|
continue;
|
|
470
505
|
}
|
|
471
506
|
}
|
|
472
|
-
|
|
473
|
-
|
|
474
|
-
|
|
475
|
-
|
|
476
|
-
|
|
477
|
-
|
|
478
|
-
|
|
479
|
-
|
|
480
|
-
|
|
481
|
-
|
|
482
|
-
|
|
483
|
-
|
|
484
|
-
|
|
485
|
-
|
|
486
|
-
|
|
507
|
+
// ─── Определение завершения: только по поведению, не по тексту ──────
|
|
508
|
+
// Смотрим: были ли хоть какие-то вызовы инструментов за сессию.
|
|
509
|
+
// Сообщения с role:tool — это результаты выполненных инструментов
|
|
510
|
+
// (кроме invalid — они с tool_call_id вида "invalid-...").
|
|
511
|
+
const hasDoneAnyWork = messages.some((m) => m.role === "tool" &&
|
|
512
|
+
m.tool_call_id &&
|
|
513
|
+
!m.tool_call_id.startsWith("invalid-"));
|
|
514
|
+
const planStatus = showPlan();
|
|
515
|
+
const hasActivePlan = !planStatus.startsWith("No active plan");
|
|
516
|
+
const pendingSteps = getPlanPendingCount();
|
|
517
|
+
// === 1. Незавершённый план ===
|
|
518
|
+
if (hasActivePlan && pendingSteps > 0) {
|
|
519
|
+
const planText = planStatus;
|
|
520
|
+
const pendingLines = planText
|
|
521
|
+
.split("\n")
|
|
522
|
+
.filter((l) => l.includes("○") || l.includes("►"));
|
|
523
|
+
const nextStep = pendingLines[0] || "";
|
|
524
|
+
const nextStepMatch = nextStep.match(/\d+\.\s*(.+)/);
|
|
525
|
+
const nextStepTitle = nextStepMatch ? nextStepMatch[1].trim() : "";
|
|
526
|
+
if (!quiet) {
|
|
527
|
+
renderer?.writeWarning(` [plan has ${pendingSteps} incomplete steps — pushing agent to continue]`);
|
|
528
|
+
}
|
|
529
|
+
const nudge = nextStepTitle
|
|
530
|
+
? `Plan is NOT complete! ${pendingSteps} step(s) remaining.\nNext step: ${nextStepTitle}\nUse subagent to execute this step, then mark done: plan({action:"done", step:N})`
|
|
531
|
+
: `Plan is NOT complete! ${pendingSteps} step(s) remaining:\n${pendingLines.join("\n")}\n\nContinue with the next step using subagent.`;
|
|
532
|
+
messages.push({ role: "user", content: nudge });
|
|
533
|
+
continuationNudges = 0;
|
|
534
|
+
continue;
|
|
535
|
+
}
|
|
536
|
+
// === 2. План завершён — аудит файлов ===
|
|
537
|
+
// Проверка по createdFiles: если план выполнен, но ни одного файла
|
|
538
|
+
// не создано — скорее всего модель галлюцинирует выполнение шагов.
|
|
539
|
+
if (hasActivePlan && pendingSteps === 0) {
|
|
540
|
+
if (createdFiles.length === 0) {
|
|
487
541
|
if (!quiet) {
|
|
488
|
-
renderer?.writeWarning(` [plan
|
|
542
|
+
renderer?.writeWarning(` [plan complete but no files created]`);
|
|
489
543
|
}
|
|
490
|
-
|
|
491
|
-
|
|
492
|
-
: `Plan
|
|
493
|
-
|
|
544
|
+
messages.push({
|
|
545
|
+
role: "user",
|
|
546
|
+
content: `Plan claims all steps done, but no files were created via write_file or subagent. Either execute the steps properly or explain why files aren't needed.`,
|
|
547
|
+
});
|
|
494
548
|
continuationNudges = 0;
|
|
495
549
|
continue;
|
|
496
550
|
}
|
|
497
|
-
//
|
|
498
|
-
|
|
499
|
-
|
|
500
|
-
|
|
501
|
-
|
|
502
|
-
|
|
503
|
-
|
|
504
|
-
|
|
505
|
-
|
|
506
|
-
|
|
507
|
-
|
|
508
|
-
|
|
509
|
-
|
|
510
|
-
|
|
511
|
-
|
|
512
|
-
|
|
513
|
-
|
|
514
|
-
|
|
515
|
-
|
|
516
|
-
|
|
517
|
-
|
|
518
|
-
missingFiles.push(fileName);
|
|
519
|
-
}
|
|
520
|
-
}
|
|
521
|
-
}
|
|
522
|
-
if (missingFiles.length > 0) {
|
|
523
|
-
if (!quiet) {
|
|
524
|
-
renderer?.writeWarning(` [plan complete but missing files: ${missingFiles.join(", ")}]`);
|
|
525
|
-
}
|
|
526
|
-
messages.push({
|
|
527
|
-
role: "user",
|
|
528
|
-
content: `Plan claims all steps done, but these files are missing: ${missingFiles.join(", ")}. Create them before finishing.`,
|
|
529
|
-
});
|
|
530
|
-
continuationNudges = 0;
|
|
531
|
-
continue;
|
|
532
|
-
}
|
|
533
|
-
}
|
|
551
|
+
// Файлы созданы — выходим
|
|
552
|
+
return { messages };
|
|
553
|
+
}
|
|
554
|
+
// === 3. Нет активного плана ===
|
|
555
|
+
// Stuck detection (без изменений)
|
|
556
|
+
const isUselessAction = validCalls.some((c) => c.parsed.name === "list_dir" ||
|
|
557
|
+
c.parsed.name === "tree" ||
|
|
558
|
+
(c.parsed.name === "todo" && c.parsed.arguments?.action === "list") ||
|
|
559
|
+
(c.parsed.name === "question" && !c.parsed.arguments?.question));
|
|
560
|
+
let isRepeatedRead = false;
|
|
561
|
+
let isRepeatedSearch = false;
|
|
562
|
+
let isRepeatedQuestion = false;
|
|
563
|
+
let isRepeatedBash = false;
|
|
564
|
+
for (const c of validCalls) {
|
|
565
|
+
if (c.parsed.name === "read_file") {
|
|
566
|
+
const filePath = String(c.parsed.arguments?.path || "");
|
|
567
|
+
if (recentReadFiles.includes(filePath))
|
|
568
|
+
isRepeatedRead = true;
|
|
569
|
+
recentReadFiles.push(filePath);
|
|
570
|
+
if (recentReadFiles.length > 5)
|
|
571
|
+
recentReadFiles.shift();
|
|
534
572
|
}
|
|
535
|
-
|
|
536
|
-
|
|
537
|
-
|
|
538
|
-
|
|
539
|
-
|
|
540
|
-
(
|
|
541
|
-
|
|
542
|
-
let isRepeatedRead = false;
|
|
543
|
-
let isRepeatedSearch = false;
|
|
544
|
-
let isRepeatedQuestion = false;
|
|
545
|
-
let isRepeatedBash = false;
|
|
546
|
-
for (const c of validCalls) {
|
|
547
|
-
if (c.parsed.name === "read_file") {
|
|
548
|
-
const filePath = String(c.parsed.arguments?.path || "");
|
|
549
|
-
if (recentReadFiles.includes(filePath)) {
|
|
550
|
-
isRepeatedRead = true;
|
|
551
|
-
}
|
|
552
|
-
recentReadFiles.push(filePath);
|
|
553
|
-
if (recentReadFiles.length > 5)
|
|
554
|
-
recentReadFiles.shift();
|
|
555
|
-
}
|
|
556
|
-
if (c.parsed.name === "grep_search") {
|
|
557
|
-
const pattern = String(c.parsed.arguments?.pattern || "");
|
|
558
|
-
if (recentGrepPatterns.includes(pattern)) {
|
|
559
|
-
isRepeatedSearch = true;
|
|
560
|
-
}
|
|
561
|
-
recentGrepPatterns.push(pattern);
|
|
562
|
-
if (recentGrepPatterns.length > 5)
|
|
563
|
-
recentGrepPatterns.shift();
|
|
564
|
-
}
|
|
565
|
-
if (c.parsed.name === "question") {
|
|
566
|
-
const questionText = String(c.parsed.arguments?.question || "");
|
|
567
|
-
if (recentQuestions.includes(questionText)) {
|
|
568
|
-
isRepeatedQuestion = true;
|
|
569
|
-
}
|
|
570
|
-
recentQuestions.push(questionText);
|
|
571
|
-
if (recentQuestions.length > 3)
|
|
572
|
-
recentQuestions.shift();
|
|
573
|
-
}
|
|
574
|
-
if (c.parsed.name === "bash") {
|
|
575
|
-
const cmdText = String(c.parsed.arguments?.cmd || "");
|
|
576
|
-
const normalized = cmdText.trim().replace(/\s+/g, " ");
|
|
577
|
-
if (recentBashCommands.includes(normalized)) {
|
|
578
|
-
isRepeatedBash = true;
|
|
579
|
-
}
|
|
580
|
-
recentBashCommands.push(normalized);
|
|
581
|
-
if (recentBashCommands.length > 5)
|
|
582
|
-
recentBashCommands.shift();
|
|
583
|
-
}
|
|
573
|
+
if (c.parsed.name === "grep_search") {
|
|
574
|
+
const pattern = String(c.parsed.arguments?.pattern || "");
|
|
575
|
+
if (recentGrepPatterns.includes(pattern))
|
|
576
|
+
isRepeatedSearch = true;
|
|
577
|
+
recentGrepPatterns.push(pattern);
|
|
578
|
+
if (recentGrepPatterns.length > 5)
|
|
579
|
+
recentGrepPatterns.shift();
|
|
584
580
|
}
|
|
585
|
-
|
|
586
|
-
|
|
587
|
-
|
|
588
|
-
|
|
589
|
-
|
|
590
|
-
|
|
591
|
-
|
|
592
|
-
|
|
593
|
-
|
|
594
|
-
|
|
595
|
-
|
|
596
|
-
|
|
597
|
-
|
|
598
|
-
|
|
599
|
-
|
|
600
|
-
|
|
601
|
-
|
|
602
|
-
|
|
603
|
-
|
|
581
|
+
if (c.parsed.name === "question") {
|
|
582
|
+
const questionText = String(c.parsed.arguments?.question || "");
|
|
583
|
+
if (recentQuestions.includes(questionText))
|
|
584
|
+
isRepeatedQuestion = true;
|
|
585
|
+
recentQuestions.push(questionText);
|
|
586
|
+
if (recentQuestions.length > 3)
|
|
587
|
+
recentQuestions.shift();
|
|
588
|
+
}
|
|
589
|
+
if (c.parsed.name === "bash") {
|
|
590
|
+
const cmdText = String(c.parsed.arguments?.cmd || "");
|
|
591
|
+
const normalized = cmdText.trim().replace(/\s+/g, " ");
|
|
592
|
+
if (recentBashCommands.includes(normalized))
|
|
593
|
+
isRepeatedBash = true;
|
|
594
|
+
recentBashCommands.push(normalized);
|
|
595
|
+
if (recentBashCommands.length > 5)
|
|
596
|
+
recentBashCommands.shift();
|
|
597
|
+
}
|
|
598
|
+
}
|
|
599
|
+
const isStuckAction = isUselessAction ||
|
|
600
|
+
isRepeatedRead ||
|
|
601
|
+
isRepeatedSearch ||
|
|
602
|
+
isRepeatedQuestion ||
|
|
603
|
+
isRepeatedBash;
|
|
604
|
+
if (isStuckAction) {
|
|
605
|
+
uselessActionCount++;
|
|
606
|
+
if (uselessActionCount >= 3) {
|
|
607
|
+
if (!quiet) {
|
|
608
|
+
renderer?.writeWarning(` [agent stuck: ${uselessActionCount} useless actions]`);
|
|
604
609
|
}
|
|
610
|
+
clearPlan();
|
|
611
|
+
messages.push({
|
|
612
|
+
role: "user",
|
|
613
|
+
content: `[System: You are stuck in a loop. STOP calling the same tool. The user already answered your question — use their answer and proceed with the task. Do NOT ask the same question again.]`,
|
|
614
|
+
});
|
|
615
|
+
uselessActionCount = 0;
|
|
616
|
+
continuationNudges = 0;
|
|
617
|
+
continue;
|
|
605
618
|
}
|
|
606
|
-
|
|
619
|
+
}
|
|
620
|
+
else {
|
|
621
|
+
consecutiveNoToolSteps = 0;
|
|
622
|
+
if (validCalls.some((c) => c.parsed.name === "subagent" ||
|
|
607
623
|
c.parsed.name === "write_file" ||
|
|
608
624
|
c.parsed.name === "bash")) {
|
|
609
625
|
uselessActionCount = 0;
|
|
@@ -612,21 +628,44 @@ export async function runAgentLoop(provider, registry, prompt, contextManager, p
|
|
|
612
628
|
recentQuestions.length = 0;
|
|
613
629
|
recentBashCommands.length = 0;
|
|
614
630
|
}
|
|
615
|
-
|
|
616
|
-
|
|
631
|
+
}
|
|
632
|
+
// === 4. Выход: решение по поведению, а не по тексту ===
|
|
633
|
+
// 4a. Модель ничего не делала — поведенческий контроль
|
|
634
|
+
if (!hasDoneAnyWork) {
|
|
635
|
+
if (step > 0)
|
|
636
|
+
consecutiveNoToolSteps++;
|
|
637
|
+
if (consecutiveNoToolSteps >= 2) {
|
|
638
|
+
if (!quiet) {
|
|
639
|
+
renderer?.writeWarning(` [idle: ${consecutiveNoToolSteps} steps without any tool calls]`);
|
|
640
|
+
}
|
|
641
|
+
const idleSteps = consecutiveNoToolSteps;
|
|
642
|
+
consecutiveNoToolSteps = 0;
|
|
617
643
|
messages.push({
|
|
618
644
|
role: "user",
|
|
619
|
-
content: `
|
|
645
|
+
content: `[System: ты уже ${idleSteps} шага подряд не вызываешь инструменты. Если задача требует создания/изменения файлов — вызови write_file или edit_file. Если задача уже выполнена — напиши результат пользователю.]`,
|
|
620
646
|
});
|
|
621
647
|
continuationNudges = 0;
|
|
622
648
|
continue;
|
|
623
649
|
}
|
|
650
|
+
// Первый ответ (step === 0) без инструментов — обычный диалог
|
|
624
651
|
return { messages };
|
|
625
652
|
}
|
|
626
|
-
|
|
653
|
+
// 4b. Модель что-то делала — проверяем созданные файлы перед выходом
|
|
654
|
+
if (createdFiles.length > 0) {
|
|
655
|
+
messages.push({
|
|
656
|
+
role: "user",
|
|
657
|
+
content: `Files created: ${createdFiles.join(", ")}. Before finishing — verify all files are complete and connected to each other. If any file is missing or not imported, continue working.`,
|
|
658
|
+
});
|
|
659
|
+
continuationNudges = 0;
|
|
660
|
+
continue;
|
|
661
|
+
}
|
|
662
|
+
// 4c. Модель работала, но не создавала файлы (читала, искала и т.д.)
|
|
663
|
+
return { messages };
|
|
627
664
|
}
|
|
628
|
-
// ─── Grounding check
|
|
629
|
-
//
|
|
665
|
+
// ─── Grounding check (ослаблен, агент больше не блокирует) ──
|
|
666
|
+
// Раньше grounding strict mode гонял модель по retry-циклу.
|
|
667
|
+
// Теперь grounding-fixer адаптер сам добавляет маркеры —
|
|
668
|
+
// grounding check только предупреждает, никогда не блокирует.
|
|
630
669
|
if (validCalls.length > 0) {
|
|
631
670
|
const groundingCfg = getGroundingConfig(config);
|
|
632
671
|
if (groundingCfg.enabled) {
|
|
@@ -635,76 +674,12 @@ export async function runAgentLoop(provider, registry, prompt, contextManager, p
|
|
|
635
674
|
const pathCalls = validCalls.filter((c) => c.parsed.arguments?.path);
|
|
636
675
|
if (pathCalls.length > groundPaths.length) {
|
|
637
676
|
consecutiveMissingGrounding++;
|
|
638
|
-
|
|
639
|
-
|
|
640
|
-
if (consecutiveMissingGrounding >= maxMissing) {
|
|
641
|
-
// CRITICAL — сброс счётчика + учёт retry
|
|
642
|
-
consecutiveMissingGrounding = 0;
|
|
643
|
-
groundingRetryCount++;
|
|
644
|
-
if (groundingRetryCount > maxRetries) {
|
|
645
|
-
// Полный bypass — выполняем tool_call без маркера
|
|
646
|
-
if (!quiet)
|
|
647
|
-
renderer?.writeWarning(` [grounding: exceeded limit, bypassing]`);
|
|
648
|
-
groundingRetryCount = 0;
|
|
649
|
-
messages.push({
|
|
650
|
-
role: "user",
|
|
651
|
-
content: `[Note: Grounding check disabled after repeated failures. Proceeding without marker. To re-enable, reset the agent.]`,
|
|
652
|
-
});
|
|
653
|
-
// fall through — tool call будет выполнен
|
|
654
|
-
}
|
|
655
|
-
else {
|
|
656
|
-
if (!quiet)
|
|
657
|
-
renderer?.writeError(` [grounding: ${groundingRetryCount}/${maxRetries} retries]`);
|
|
658
|
-
messages.push({
|
|
659
|
-
role: "user",
|
|
660
|
-
content: `[CRITICAL: Output @grounding[файл: <path>] BEFORE each <tool_call>.\nExample:\n@grounding[файл: package.json]\n<tool_call>{"name":"read_file","arguments":{"path":"package.json"}}</tool_call>]`,
|
|
661
|
-
});
|
|
662
|
-
continue;
|
|
663
|
-
}
|
|
664
|
-
}
|
|
665
|
-
else if (groundingCfg.strictMode) {
|
|
666
|
-
if (!quiet)
|
|
667
|
-
renderer?.writeError(` [grounding: strict mode, retrying]`);
|
|
668
|
-
messages.push({
|
|
669
|
-
role: "user",
|
|
670
|
-
content: `[Grounding Error: Missing @grounding[файл: path] marker. Output the marker BEFORE each <tool_call>. Example:\n@grounding[файл: package.json]\n<tool_call>{"name":"read_file","arguments":{"path":"package.json"}}</tool_call>]`,
|
|
671
|
-
});
|
|
672
|
-
continue;
|
|
673
|
-
}
|
|
674
|
-
else {
|
|
675
|
-
if (!quiet)
|
|
676
|
-
renderer?.writeDim(` [grounding: missing marker, reminder ${consecutiveMissingGrounding}/${maxMissing}]`);
|
|
677
|
-
messages.push({
|
|
678
|
-
role: "user",
|
|
679
|
-
content: `[Reminder: Include @grounding[файл: path] marker before each <tool_call> to prevent path hallucinations. Example:\n@grounding[файл: package.json]\n<tool_call>{"name":"read_file","arguments":{"path":"package.json"}}</tool_call>]`,
|
|
680
|
-
});
|
|
681
|
-
continue;
|
|
682
|
-
}
|
|
677
|
+
if (!quiet)
|
|
678
|
+
renderer?.writeDim(` [grounding: ${consecutiveMissingGrounding} call(s) without marker — adapter handled]`);
|
|
683
679
|
}
|
|
684
680
|
else {
|
|
685
681
|
consecutiveMissingGrounding = 0;
|
|
686
682
|
groundingRetryCount = 0;
|
|
687
|
-
// Проверка соответствия пути в маркере и в аргументах tool_call
|
|
688
|
-
for (let i = 0; i < pathCalls.length && i < groundPaths.length; i++) {
|
|
689
|
-
const callPath = String(pathCalls[i].parsed.arguments.path || "")
|
|
690
|
-
.replace(/\\/g, "/")
|
|
691
|
-
.replace(/^\.\//, "");
|
|
692
|
-
const groundPath = groundPaths[i]
|
|
693
|
-
.replace(/\\/g, "/")
|
|
694
|
-
.replace(/^\.\//, "");
|
|
695
|
-
if (callPath &&
|
|
696
|
-
groundPath &&
|
|
697
|
-
!callPath.endsWith(groundPath) &&
|
|
698
|
-
!groundPath.endsWith(callPath)) {
|
|
699
|
-
if (!quiet)
|
|
700
|
-
renderer?.writeWarning(` [grounding: path mismatch — marker says "${groundPath}", tool says "${callPath}"]`);
|
|
701
|
-
messages.push({
|
|
702
|
-
role: "user",
|
|
703
|
-
content: `[Warning: Grounding marker path "${groundPath}" doesn't match tool call path "${callPath}". Fix the marker to match the actual path.]`,
|
|
704
|
-
});
|
|
705
|
-
break;
|
|
706
|
-
}
|
|
707
|
-
}
|
|
708
683
|
}
|
|
709
684
|
}
|
|
710
685
|
}
|
|
@@ -1033,6 +1008,8 @@ export async function runAgentLoop(provider, registry, prompt, contextManager, p
|
|
|
1033
1008
|
}
|
|
1034
1009
|
}
|
|
1035
1010
|
}
|
|
1011
|
+
// Любой выполненный tool call сбрасывает счётчик бездействия
|
|
1012
|
+
consecutiveNoToolSteps = 0;
|
|
1036
1013
|
messages.push({
|
|
1037
1014
|
role: "tool",
|
|
1038
1015
|
content: truncateOutput(parsed.name, toolOutput, toolExitCode),
|