micro-models-agent 0.43.2 → 0.44.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/dist/main.js +148 -53
- package/package.json +1 -1
package/dist/main.js
CHANGED
|
@@ -2580,6 +2580,7 @@ Fix the error and re-edit the file (a clean write clears the failure), or mark t
|
|
|
2580
2580
|
"verify.script_passed": "Script '{script}' passed",
|
|
2581
2581
|
"verify.script_failed": "Script '{script}' failed: {message}",
|
|
2582
2582
|
"verify.syntax_error": "Syntax error in: {path}",
|
|
2583
|
+
"verify.file_still_exists": "File should be deleted but still exists: {path}",
|
|
2583
2584
|
"verify.no_files": "Step {step} has no named files to verify — run a real check instead (bash: bun run build / bun test / lsp_check) and confirm the result.",
|
|
2584
2585
|
"lsp.unavailable": "static checks are unavailable (server not found). Verify via the project's own build/test instead.",
|
|
2585
2586
|
"lsp.check_disabled": "LSP checks are disabled in the config.",
|
|
@@ -3237,6 +3238,7 @@ var init_ru = __esm(() => {
|
|
|
3237
3238
|
"verify.script_passed": "Скрипт '{script}' пройден",
|
|
3238
3239
|
"verify.script_failed": "Скрипт '{script}' не пройден: {message}",
|
|
3239
3240
|
"verify.syntax_error": "Синтаксическая ошибка в: {path}",
|
|
3241
|
+
"verify.file_still_exists": "Файл должен быть удалён, но всё ещё существует: {path}",
|
|
3240
3242
|
"verify.no_files": "Шаг {step} не содержит именованных файлов для проверки — выполни реальную проверку (bun run build / bun test / lsp_check) и подтверди результат.",
|
|
3241
3243
|
"lsp.unavailable": "статические проверки недоступны (сервер не найден). Проверяйте через собственный build/test проекта.",
|
|
3242
3244
|
"lsp.check_disabled": "LSP-проверки отключены в конфигурации.",
|
|
@@ -6290,6 +6292,7 @@ var init_read_file = __esm(() => {
|
|
|
6290
6292
|
init_path_utils();
|
|
6291
6293
|
readFileTool = {
|
|
6292
6294
|
name: "read_file",
|
|
6295
|
+
icon: "\uD83D\uDC40",
|
|
6293
6296
|
description: `Read a file from the filesystem. Reads up to ${DEFAULT_LIMIT} lines at a time by default; use offset to page through large files.`,
|
|
6294
6297
|
tags: ["file", "code"],
|
|
6295
6298
|
boundedOutput: true,
|
|
@@ -6659,6 +6662,7 @@ var init_write_file = __esm(() => {
|
|
|
6659
6662
|
init_path_utils();
|
|
6660
6663
|
writeFileTool = {
|
|
6661
6664
|
name: "write_file",
|
|
6665
|
+
icon: "\uD83D\uDCDD",
|
|
6662
6666
|
description: "Create or overwrite a file with given content. Creates intermediate directories if needed.",
|
|
6663
6667
|
tags: ["file", "code"],
|
|
6664
6668
|
parameters: {
|
|
@@ -6734,6 +6738,7 @@ var init_edit_file = __esm(() => {
|
|
|
6734
6738
|
init_path_utils();
|
|
6735
6739
|
editFileTool = {
|
|
6736
6740
|
name: "edit_file",
|
|
6741
|
+
icon: "✏️",
|
|
6737
6742
|
description: "Find and replace text in an existing file. Uses exact string match (not regex).",
|
|
6738
6743
|
tags: ["file", "code"],
|
|
6739
6744
|
parameters: {
|
|
@@ -6807,6 +6812,7 @@ var init_glob_tool = __esm(() => {
|
|
|
6807
6812
|
init_i18n();
|
|
6808
6813
|
globTool = {
|
|
6809
6814
|
name: "glob",
|
|
6815
|
+
icon: "\uD83D\uDD0E",
|
|
6810
6816
|
description: `Search for files matching a glob pattern. Shows up to ${MAX_PREVIEW_LINES} results by default. Uses standard glob syntax (e.g., **/*.ts, src/**/*.test.ts).`,
|
|
6811
6817
|
tags: ["file", "code", "research"],
|
|
6812
6818
|
parameters: {
|
|
@@ -6848,6 +6854,7 @@ var init_grep_tool = __esm(() => {
|
|
|
6848
6854
|
init_audit_log();
|
|
6849
6855
|
grepTool = {
|
|
6850
6856
|
name: "grep",
|
|
6857
|
+
icon: "\uD83D\uDD0D",
|
|
6851
6858
|
description: `Search file contents using a regular expression. Shows up to ${MAX_PREVIEW_LINES} matching lines by default. Uses ripgrep (rg) if available, otherwise falls back to grep -r.`,
|
|
6852
6859
|
tags: ["file", "code", "research"],
|
|
6853
6860
|
parameters: {
|
|
@@ -6923,6 +6930,7 @@ var init_list_dir = __esm(() => {
|
|
|
6923
6930
|
init_path_utils();
|
|
6924
6931
|
listDirTool = {
|
|
6925
6932
|
name: "list_dir",
|
|
6933
|
+
icon: "\uD83D\uDCC2",
|
|
6926
6934
|
description: `List files and directories in a given path. Shows up to ${MAX_PREVIEW_LINES} entries by default.`,
|
|
6927
6935
|
tags: ["file"],
|
|
6928
6936
|
boundedOutput: true,
|
|
@@ -6975,6 +6983,7 @@ var init_create_dir = __esm(() => {
|
|
|
6975
6983
|
init_path_utils();
|
|
6976
6984
|
createDirTool = {
|
|
6977
6985
|
name: "create_dir",
|
|
6986
|
+
icon: "\uD83D\uDCC1",
|
|
6978
6987
|
description: "Create a directory (and any intermediate directories).",
|
|
6979
6988
|
tags: ["file"],
|
|
6980
6989
|
parameters: {
|
|
@@ -7029,6 +7038,7 @@ var init_delete_file = __esm(() => {
|
|
|
7029
7038
|
init_path_utils();
|
|
7030
7039
|
deleteFileTool = {
|
|
7031
7040
|
name: "delete_file",
|
|
7041
|
+
icon: "\uD83D\uDDD1️",
|
|
7032
7042
|
description: "Delete a file from the filesystem.",
|
|
7033
7043
|
tags: ["file"],
|
|
7034
7044
|
parameters: {
|
|
@@ -7090,6 +7100,7 @@ var init_move_file = __esm(() => {
|
|
|
7090
7100
|
init_path_utils();
|
|
7091
7101
|
moveFileTool = {
|
|
7092
7102
|
name: "move_file",
|
|
7103
|
+
icon: "\uD83D\uDCE6",
|
|
7093
7104
|
description: "Move or rename a file or directory.",
|
|
7094
7105
|
tags: ["file"],
|
|
7095
7106
|
parameters: {
|
|
@@ -7168,6 +7179,7 @@ var init_file_info = __esm(() => {
|
|
|
7168
7179
|
init_path_utils();
|
|
7169
7180
|
fileInfoTool = {
|
|
7170
7181
|
name: "file_info",
|
|
7182
|
+
icon: "ℹ️",
|
|
7171
7183
|
description: "Get metadata about a file or directory (size, creation date, modification date).",
|
|
7172
7184
|
tags: ["file"],
|
|
7173
7185
|
boundedOutput: true,
|
|
@@ -7842,6 +7854,7 @@ var init_bash = __esm(() => {
|
|
|
7842
7854
|
NPM_EXEC_RE = /could not determine executable to run/i;
|
|
7843
7855
|
bashTool = {
|
|
7844
7856
|
name: "bash",
|
|
7857
|
+
icon: "\uD83D\uDCBB",
|
|
7845
7858
|
description: `Execute a shell command and return its output. Use for running tests, build, git, and shell operations. Commands that are still running after a few seconds are automatically moved to the background and return a process id — manage them with process_list, process_log, process_kill. Set background=true to return a process id immediately for commands you know are long-running (dev servers, watchers).
|
|
7846
7859
|
|
|
7847
7860
|
Windows notes: the shell is cmd.exe — PowerShell cmdlets (Write-Host, Get-Content, Select-String, Out-File) and bash heredocs (cat << EOF) do NOT work there. Use the read_file/write_file tools instead of cat/echo redirection. Sequential commands: use && (a leading ; is auto-converted to &).`,
|
|
@@ -8010,6 +8023,7 @@ var init_process_list = __esm(() => {
|
|
|
8010
8023
|
init_i18n();
|
|
8011
8024
|
processListTool = {
|
|
8012
8025
|
name: "process_list",
|
|
8026
|
+
icon: "\uD83D\uDCCA",
|
|
8013
8027
|
description: "List background processes started via the bash tool (dev servers, watchers, long-running commands). Shows id, pid, command, status, and recent output. Use with process_log and process_kill to inspect or stop them.",
|
|
8014
8028
|
tags: ["shell"],
|
|
8015
8029
|
parameters: {
|
|
@@ -8054,6 +8068,7 @@ var init_process_log = __esm(() => {
|
|
|
8054
8068
|
DEFAULT_TAIL = MAX_PREVIEW_LINES;
|
|
8055
8069
|
processLogTool = {
|
|
8056
8070
|
name: "process_log",
|
|
8071
|
+
icon: "\uD83D\uDCDC",
|
|
8057
8072
|
description: `Show the buffered output of a background process started via bash. Shows the last ${DEFAULT_TAIL} lines by default. Use after starting a dev server to verify it came up without errors, and while it runs to check its state.`,
|
|
8058
8073
|
tags: ["shell"],
|
|
8059
8074
|
boundedOutput: true,
|
|
@@ -8099,6 +8114,7 @@ var init_process_kill = __esm(() => {
|
|
|
8099
8114
|
init_i18n();
|
|
8100
8115
|
processKillTool = {
|
|
8101
8116
|
name: "process_kill",
|
|
8117
|
+
icon: "⛔",
|
|
8102
8118
|
description: "Stop a background process started via bash (dev server, watcher). Kills the whole process tree (children included). Use the id returned by bash or process_list.",
|
|
8103
8119
|
tags: ["shell"],
|
|
8104
8120
|
parameters: {
|
|
@@ -9670,6 +9686,9 @@ class StuckDetector {
|
|
|
9670
9686
|
this.consecutiveFailures = 0;
|
|
9671
9687
|
this.lastFailedTool = "";
|
|
9672
9688
|
this.escalationCount = 0;
|
|
9689
|
+
if (this.iterationsOnCurrentStep > 0) {
|
|
9690
|
+
this.iterationsOnCurrentStep = Math.max(0, this.iterationsOnCurrentStep - 1);
|
|
9691
|
+
}
|
|
9673
9692
|
}
|
|
9674
9693
|
setCurrentStep(stepId, description) {
|
|
9675
9694
|
if (stepId !== this.currentStepId) {
|
|
@@ -11061,7 +11080,7 @@ class StepVerifier {
|
|
|
11061
11080
|
details
|
|
11062
11081
|
};
|
|
11063
11082
|
}
|
|
11064
|
-
async verifyStep(stepDescription) {
|
|
11083
|
+
async verifyStep(stepDescription, kind) {
|
|
11065
11084
|
const fileMatches = extractFileLikeTokens(stripUrls(stepDescription));
|
|
11066
11085
|
if (fileMatches.length === 0) {
|
|
11067
11086
|
return { passed: false, syntaxValid: true, failed: [], noFiles: true };
|
|
@@ -11070,7 +11089,15 @@ class StepVerifier {
|
|
|
11070
11089
|
let syntaxValid = true;
|
|
11071
11090
|
for (const filePath of fileMatches) {
|
|
11072
11091
|
const resolved = findExistingFile(this.baseDir, filePath);
|
|
11073
|
-
|
|
11092
|
+
const exists = !!resolved;
|
|
11093
|
+
if (kind === "delete") {
|
|
11094
|
+
results.push({
|
|
11095
|
+
passed: !exists,
|
|
11096
|
+
message: exists ? t("verify.file_still_exists", { path: filePath }) : t("verify.file_not_found", { path: filePath })
|
|
11097
|
+
});
|
|
11098
|
+
continue;
|
|
11099
|
+
}
|
|
11100
|
+
if (!exists) {
|
|
11074
11101
|
results.push({ passed: false, message: t("verify.file_not_found", { path: filePath }) });
|
|
11075
11102
|
continue;
|
|
11076
11103
|
}
|
|
@@ -11523,6 +11550,7 @@ ${t("tool.truncated", { tokens: Math.ceil(removedChars / 2) })}`;
|
|
|
11523
11550
|
if (result) {
|
|
11524
11551
|
logger.debug("Context compacted");
|
|
11525
11552
|
slog.logCompaction({ reason: "interval", iteration, ...result });
|
|
11553
|
+
hallucinationDetector.addKnownFiles(contextManager.getKnownFiles());
|
|
11526
11554
|
}
|
|
11527
11555
|
}
|
|
11528
11556
|
const currentTokens = contextManager.getEstimatedTokens();
|
|
@@ -11538,6 +11566,7 @@ ${t("tool.truncated", { tokens: Math.ceil(removedChars / 2) })}`;
|
|
|
11538
11566
|
iteration,
|
|
11539
11567
|
...result
|
|
11540
11568
|
});
|
|
11569
|
+
hallucinationDetector.addKnownFiles(contextManager.getKnownFiles());
|
|
11541
11570
|
}
|
|
11542
11571
|
}
|
|
11543
11572
|
if (currentTokens > budget2.history) {
|
|
@@ -11549,6 +11578,7 @@ ${t("tool.truncated", { tokens: Math.ceil(removedChars / 2) })}`;
|
|
|
11549
11578
|
iteration,
|
|
11550
11579
|
...result
|
|
11551
11580
|
});
|
|
11581
|
+
hallucinationDetector.addKnownFiles(contextManager.getKnownFiles());
|
|
11552
11582
|
}
|
|
11553
11583
|
}
|
|
11554
11584
|
this.refreshSystemPrompt();
|
|
@@ -11700,6 +11730,7 @@ ${t("tool.truncated", { tokens: Math.ceil(removedChars / 2) })}`;
|
|
|
11700
11730
|
});
|
|
11701
11731
|
const summaries = [];
|
|
11702
11732
|
let anyToolFailed = false;
|
|
11733
|
+
const infoTools = new Set(["file_info"]);
|
|
11703
11734
|
for (const call of toolCalls) {
|
|
11704
11735
|
this.setScope();
|
|
11705
11736
|
const startTime = Date.now();
|
|
@@ -11708,14 +11739,15 @@ ${t("tool.truncated", { tokens: Math.ceil(removedChars / 2) })}`;
|
|
|
11708
11739
|
args: call.arguments
|
|
11709
11740
|
});
|
|
11710
11741
|
pluginManager.runOnToolStart({ iteration, logger, contextManager }, { id: call.id, name: call.name, arguments: call.arguments });
|
|
11711
|
-
|
|
11742
|
+
const toolIcon = this.deps.toolExecutor.getRegistry().get(call.name)?.icon;
|
|
11743
|
+
onTool?.({ type: "start", tool: call.name, args: call.arguments, icon: toolIcon });
|
|
11712
11744
|
slog.logToolCall(call, iteration);
|
|
11713
11745
|
const tokensBeforeTool = contextManager.getEstimatedTokens();
|
|
11714
11746
|
const result = await toolExecutor.execute(call, this.abortController?.signal);
|
|
11715
11747
|
if (this.shutdownRequested)
|
|
11716
11748
|
break;
|
|
11717
11749
|
const duration = Date.now() - startTime;
|
|
11718
|
-
if (!result.success)
|
|
11750
|
+
if (!result.success && !infoTools.has(call.name))
|
|
11719
11751
|
anyToolFailed = true;
|
|
11720
11752
|
if (result.success && call.arguments.path) {
|
|
11721
11753
|
const filePath = String(call.arguments.path);
|
|
@@ -11774,9 +11806,10 @@ ${t("tool.truncated", { tokens: Math.ceil(removedChars / 2) })}`;
|
|
|
11774
11806
|
iteration,
|
|
11775
11807
|
...result2
|
|
11776
11808
|
});
|
|
11809
|
+
hallucinationDetector.addKnownFiles(contextManager.getKnownFiles());
|
|
11777
11810
|
}
|
|
11778
11811
|
}
|
|
11779
|
-
if (!result.success) {
|
|
11812
|
+
if (!result.success && !infoTools.has(call.name)) {
|
|
11780
11813
|
const key = call.name;
|
|
11781
11814
|
const prev = toolFailureCounts.get(key) ?? { count: 0, error: "" };
|
|
11782
11815
|
prev.count++;
|
|
@@ -12171,6 +12204,10 @@ class FactExtractor {
|
|
|
12171
12204
|
return null;
|
|
12172
12205
|
return `[Files: ${liveFiles.slice(-15).join("; ")}]`;
|
|
12173
12206
|
}
|
|
12207
|
+
getKnownFiles() {
|
|
12208
|
+
const deletedSet = new Set(this.deletedFacts);
|
|
12209
|
+
return this.fileFacts.filter((p) => !deletedSet.has(p));
|
|
12210
|
+
}
|
|
12174
12211
|
deletedLine() {
|
|
12175
12212
|
if (this.deletedFacts.length === 0)
|
|
12176
12213
|
return null;
|
|
@@ -12295,6 +12332,9 @@ class ContextManager {
|
|
|
12295
12332
|
getIterationsSinceCompaction() {
|
|
12296
12333
|
return this.iterationsSinceCompaction;
|
|
12297
12334
|
}
|
|
12335
|
+
getKnownFiles() {
|
|
12336
|
+
return this.facts.getKnownFiles();
|
|
12337
|
+
}
|
|
12298
12338
|
noteIteration() {
|
|
12299
12339
|
this.iterationsSinceCompaction++;
|
|
12300
12340
|
}
|
|
@@ -12634,9 +12674,14 @@ class FactualCheck {
|
|
|
12634
12674
|
static NAME_CACHE_TTL_MS = 5000;
|
|
12635
12675
|
static RESCAN_COOLDOWN_MS = 2000;
|
|
12636
12676
|
static MAX_INDEXED_FILES = 20000;
|
|
12677
|
+
knownFiles = new Set;
|
|
12637
12678
|
constructor(baseDir) {
|
|
12638
12679
|
this.baseDir = baseDir;
|
|
12639
12680
|
}
|
|
12681
|
+
addKnownFiles(files) {
|
|
12682
|
+
for (const f of files)
|
|
12683
|
+
this.knownFiles.add(f);
|
|
12684
|
+
}
|
|
12640
12685
|
validate(response) {
|
|
12641
12686
|
const filePaths = this.extractFilePaths(response);
|
|
12642
12687
|
if (filePaths.length === 0)
|
|
@@ -12660,6 +12705,8 @@ class FactualCheck {
|
|
|
12660
12705
|
pathExists(fp) {
|
|
12661
12706
|
if (isAbsolute2(fp))
|
|
12662
12707
|
return existsSync23(fp);
|
|
12708
|
+
if (this.knownFiles.has(fp))
|
|
12709
|
+
return true;
|
|
12663
12710
|
if (!fp.includes("/") && !fp.includes("\\")) {
|
|
12664
12711
|
return this.bareNameExists(fp);
|
|
12665
12712
|
}
|
|
@@ -12670,6 +12717,11 @@ class FactualCheck {
|
|
|
12670
12717
|
return true;
|
|
12671
12718
|
if (this.indexHas(name))
|
|
12672
12719
|
return true;
|
|
12720
|
+
for (const known of this.knownFiles) {
|
|
12721
|
+
if (known.endsWith(`/${name}`) || known.endsWith(`\\${name}`) || known === name) {
|
|
12722
|
+
return true;
|
|
12723
|
+
}
|
|
12724
|
+
}
|
|
12673
12725
|
const now = Date.now();
|
|
12674
12726
|
if (now - this.lastRescan < FactualCheck.RESCAN_COOLDOWN_MS)
|
|
12675
12727
|
return false;
|
|
@@ -12849,6 +12901,9 @@ class HallucinationDetector {
|
|
|
12849
12901
|
getConfidenceCheck() {
|
|
12850
12902
|
return this.confidence;
|
|
12851
12903
|
}
|
|
12904
|
+
addKnownFiles(files) {
|
|
12905
|
+
this.factual?.addKnownFiles(files);
|
|
12906
|
+
}
|
|
12852
12907
|
async validate(response) {
|
|
12853
12908
|
const confidenceResult = this.confidence.validate(response);
|
|
12854
12909
|
if (confidenceResult.status === "retry" || confidenceResult.status === "block") {
|
|
@@ -13195,6 +13250,7 @@ var init_subagent = __esm(() => {
|
|
|
13195
13250
|
init_store();
|
|
13196
13251
|
subagentTool = {
|
|
13197
13252
|
name: "subagent",
|
|
13253
|
+
icon: "\uD83E\uDD16",
|
|
13198
13254
|
description: "Spawn an isolated sub-agent to work on a task independently. The sub-agent has its own context and executes autonomously. Use for parallel work or complex sub-tasks.",
|
|
13199
13255
|
tags: ["code"],
|
|
13200
13256
|
parameters: {
|
|
@@ -13493,6 +13549,7 @@ var init_chunk_query = __esm(() => {
|
|
|
13493
13549
|
init_scope_check();
|
|
13494
13550
|
chunkQueryTool = {
|
|
13495
13551
|
name: "chunk_query",
|
|
13552
|
+
icon: "\uD83E\uDDE9",
|
|
13496
13553
|
description: "Answer a query over a large text (file or inline) by splitting it into chunks and querying the model per chunk in parallel, then optionally synthesizing a final answer. Use when the input is too large for the context window.",
|
|
13497
13554
|
tags: ["research", "code"],
|
|
13498
13555
|
timeoutMs: 300000,
|
|
@@ -13692,6 +13749,7 @@ var init_web_search = __esm(() => {
|
|
|
13692
13749
|
init_session_isolation();
|
|
13693
13750
|
webSearchTool = {
|
|
13694
13751
|
name: "web_search",
|
|
13752
|
+
icon: "\uD83C\uDF0D",
|
|
13695
13753
|
description: "Search the web for information. Returns search results with titles and snippets. Use this for search queries instead of opening search engines (Google/Yandex/Bing) in the browser — they block headless browsers.",
|
|
13696
13754
|
tags: ["research"],
|
|
13697
13755
|
parameters: {
|
|
@@ -13759,6 +13817,7 @@ var init_web_fetch = __esm(() => {
|
|
|
13759
13817
|
init_security();
|
|
13760
13818
|
webFetchTool = {
|
|
13761
13819
|
name: "web_fetch",
|
|
13820
|
+
icon: "⬇️",
|
|
13762
13821
|
description: 'Fetch a URL and convert its content to markdown. Use for reading documentation, APIs, web pages. This is a plain HTTP request without a browser engine — it does NOT run JavaScript, so JS-rendered single-page apps (weather sites, dashboards, modern SPAs) return empty or near-empty content; use the "browser" tool for those.',
|
|
13763
13822
|
tags: ["research"],
|
|
13764
13823
|
parameters: {
|
|
@@ -13845,6 +13904,7 @@ var init_web_browse = __esm(() => {
|
|
|
13845
13904
|
init_session_isolation();
|
|
13846
13905
|
webBrowseTool = {
|
|
13847
13906
|
name: "web_browse",
|
|
13907
|
+
icon: "\uD83C\uDF10",
|
|
13848
13908
|
description: `Fetch and read a web page. Returns the page content as plain text (max ${MAX_PREVIEW_LINES} lines / ${MAX_CHARS2} chars). This is a plain HTTP request — it does NOT execute JavaScript, so JS-rendered single-page apps (weather sites, dashboards, modern SPAs) return empty or near-empty content. For such pages use the "browser" tool instead.`,
|
|
13849
13909
|
tags: ["research"],
|
|
13850
13910
|
parameters: {
|
|
@@ -13929,6 +13989,7 @@ var init_download_file = __esm(() => {
|
|
|
13929
13989
|
MAX_DOWNLOAD_BYTES = 100 * 1024 * 1024;
|
|
13930
13990
|
downloadFileTool = {
|
|
13931
13991
|
name: "download_file",
|
|
13992
|
+
icon: "⬇️",
|
|
13932
13993
|
description: "Download a file (image, archive, binary, font, etc.) from a URL and save it to disk. Returns only the path, size and content type — read the saved file with read_file/attach_image afterwards. Use this for binary files; web_fetch/web_browse return text only and cannot save bytes.",
|
|
13933
13994
|
tags: ["file", "research"],
|
|
13934
13995
|
parameters: {
|
|
@@ -14032,6 +14093,7 @@ var init_download_file = __esm(() => {
|
|
|
14032
14093
|
function createLoadSkillTool(skillsModule) {
|
|
14033
14094
|
return {
|
|
14034
14095
|
name: "load_skill",
|
|
14096
|
+
icon: "\uD83C\uDFAF",
|
|
14035
14097
|
tags: ["core"],
|
|
14036
14098
|
description: "Load a skill by name. Skills provide specialized instructions and workflows. When loaded, the skill content is injected into the system prompt (not conversation history) so it persists through context compaction. Only use when the task clearly requires domain-specific knowledge.",
|
|
14037
14099
|
parameters: {
|
|
@@ -14263,6 +14325,7 @@ var init_pipeline_run = __esm(() => {
|
|
|
14263
14325
|
engine = new PipelineEngine;
|
|
14264
14326
|
pipelineRunTool = {
|
|
14265
14327
|
name: "pipeline_run",
|
|
14328
|
+
icon: "▶️",
|
|
14266
14329
|
description: "Run a named pipeline with YAML definition. Creates a DAG of sub-agents that execute in dependency order.",
|
|
14267
14330
|
tags: ["shell", "code"],
|
|
14268
14331
|
parameters: {
|
|
@@ -14794,6 +14857,7 @@ var init_mcp_call = __esm(() => {
|
|
|
14794
14857
|
registry = new MCPRegistry;
|
|
14795
14858
|
mcpCallTool = {
|
|
14796
14859
|
name: "mcp_call",
|
|
14860
|
+
icon: "\uD83D\uDD17",
|
|
14797
14861
|
description: "Call a tool on an MCP (Model Context Protocol) server. MCP servers provide external capabilities like databases, APIs, or specialized tools.",
|
|
14798
14862
|
tags: ["code", "research"],
|
|
14799
14863
|
parameters: {
|
|
@@ -14863,6 +14927,7 @@ var init_search_history = __esm(() => {
|
|
|
14863
14927
|
init_i18n();
|
|
14864
14928
|
searchHistoryTool = {
|
|
14865
14929
|
name: "search_history",
|
|
14930
|
+
icon: "\uD83D\uDD75️",
|
|
14866
14931
|
description: "Search through session history for past interactions across all sessions.",
|
|
14867
14932
|
tags: ["research"],
|
|
14868
14933
|
parameters: {
|
|
@@ -15059,6 +15124,7 @@ var init_remember = __esm(() => {
|
|
|
15059
15124
|
CATEGORIES = ["preferences", "conventions", "decisions", "errors", "facts"];
|
|
15060
15125
|
rememberTool = {
|
|
15061
15126
|
name: "remember",
|
|
15127
|
+
icon: "\uD83E\uDDE0",
|
|
15062
15128
|
description: "Remember information across sessions. Use for user preferences, facts, conventions, decisions, or errors.",
|
|
15063
15129
|
tags: ["memory"],
|
|
15064
15130
|
parameters: {
|
|
@@ -15186,6 +15252,7 @@ var init_recall = __esm(() => {
|
|
|
15186
15252
|
CATEGORIES2 = ["preferences", "conventions", "decisions", "errors", "facts"];
|
|
15187
15253
|
recallTool = {
|
|
15188
15254
|
name: "recall",
|
|
15255
|
+
icon: "\uD83D\uDCBE",
|
|
15189
15256
|
description: "Recall stored information from memory. Search across preferences, facts, conventions, decisions, errors.",
|
|
15190
15257
|
tags: ["memory"],
|
|
15191
15258
|
parameters: {
|
|
@@ -16215,6 +16282,7 @@ function formatScreenshotResult(snapshot, screenshot, supportsVision) {
|
|
|
16215
16282
|
function createBrowserTool() {
|
|
16216
16283
|
return {
|
|
16217
16284
|
name: "browser",
|
|
16285
|
+
icon: "\uD83C\uDF10",
|
|
16218
16286
|
tags: ["browser", "vision"],
|
|
16219
16287
|
description: [
|
|
16220
16288
|
"Control a headless browser. Navigate pages, click elements, type text, scroll, take screenshots.",
|
|
@@ -16419,6 +16487,7 @@ var init_attach_image = __esm(() => {
|
|
|
16419
16487
|
init_audit_log();
|
|
16420
16488
|
attachImageTool = {
|
|
16421
16489
|
name: "attach_image",
|
|
16490
|
+
icon: "\uD83D\uDDBC️",
|
|
16422
16491
|
description: "Attach an image to the conversation from a file path, URL, or clipboard. The image will be included in the next message sent to the model. Supports PNG, JPEG, GIF, WebP.",
|
|
16423
16492
|
tags: ["vision", "image"],
|
|
16424
16493
|
parameters: {
|
|
@@ -16504,6 +16573,7 @@ var init_enable_tools = __esm(() => {
|
|
|
16504
16573
|
init_i18n();
|
|
16505
16574
|
enableToolsTool = {
|
|
16506
16575
|
name: "enable_tools",
|
|
16576
|
+
icon: "\uD83D\uDD0C",
|
|
16507
16577
|
description: "Enable hidden tool categories for the current session. Only the essential tools (file/code/shell) are active by default. Call this with the tags you need and they become available from the next turn. Available tags: file, code, shell, research, browser, vision, image, memory, core. Returns the newly available tools. To run a task in a separate context instead, use subagent with tool_tags.",
|
|
16508
16578
|
alwaysOn: true,
|
|
16509
16579
|
parameters: {
|
|
@@ -17545,30 +17615,29 @@ function createExecutionPlugin(deps) {
|
|
|
17545
17615
|
if (currentIter - deps.state.lastRecoveryIteration >= STUCK_RECOVERY_COOLDOWN) {
|
|
17546
17616
|
const recovery = deps.stuckDetector.getRecoveryMessage();
|
|
17547
17617
|
if (recovery && ctx.contextManager) {
|
|
17548
|
-
|
|
17549
|
-
|
|
17550
|
-
|
|
17551
|
-
|
|
17552
|
-
|
|
17553
|
-
|
|
17554
|
-
|
|
17555
|
-
|
|
17556
|
-
|
|
17557
|
-
|
|
17558
|
-
|
|
17559
|
-
|
|
17560
|
-
|
|
17561
|
-
|
|
17562
|
-
|
|
17563
|
-
|
|
17564
|
-
|
|
17565
|
-
|
|
17566
|
-
|
|
17567
|
-
|
|
17568
|
-
});
|
|
17618
|
+
let tscContext = "";
|
|
17619
|
+
if (deps.state.typecheckFailures.size > 0) {
|
|
17620
|
+
const currentStep = deps.trackerRef.current?.getCurrentStep();
|
|
17621
|
+
if (currentStep) {
|
|
17622
|
+
const stepFiles = extractFileLikeTokens(stripUrls(currentStep.description));
|
|
17623
|
+
for (const [file, error] of deps.state.typecheckFailures) {
|
|
17624
|
+
if (!file || stepFiles.some((f) => file.endsWith(f) || f.endsWith(file))) {
|
|
17625
|
+
tscContext = `
|
|
17626
|
+
Last compile error: ${error}`;
|
|
17627
|
+
break;
|
|
17628
|
+
}
|
|
17629
|
+
}
|
|
17630
|
+
if (!tscContext) {
|
|
17631
|
+
const first = deps.state.typecheckFailures.entries().next().value;
|
|
17632
|
+
if (first)
|
|
17633
|
+
tscContext = `
|
|
17634
|
+
Last compile error: ${first[1]}`;
|
|
17635
|
+
}
|
|
17636
|
+
}
|
|
17637
|
+
}
|
|
17569
17638
|
ctx.contextManager.addMessage({
|
|
17570
17639
|
role: "user",
|
|
17571
|
-
content: `<system-summary>${
|
|
17640
|
+
content: `<system-summary>${recovery}${tscContext}</system-summary>`
|
|
17572
17641
|
});
|
|
17573
17642
|
}
|
|
17574
17643
|
deps.stuckDetector.recordEscalation();
|
|
@@ -17627,6 +17696,24 @@ Tool "${deps.stuckDetector.getLastFailedTool()}" is failing. Try "${alternative}
|
|
|
17627
17696
|
if (call.name === "bash") {
|
|
17628
17697
|
deps.stuckDetector.recordBashOutput(String(call.arguments?.command ?? ""), String(result.output ?? ""));
|
|
17629
17698
|
}
|
|
17699
|
+
if (call.name === "delete_file" && result.success && deps.trackerRef.current) {
|
|
17700
|
+
const deletedPath = String(call.arguments?.path ?? "");
|
|
17701
|
+
if (deletedPath) {
|
|
17702
|
+
const plan = deps.trackerRef.current.getPlan();
|
|
17703
|
+
const tokens = extractFileLikeTokens(stripUrls(deletedPath));
|
|
17704
|
+
for (const step of plan.steps) {
|
|
17705
|
+
if (step.status !== "pending" && step.status !== "in_progress")
|
|
17706
|
+
continue;
|
|
17707
|
+
const stepTokens = extractFileLikeTokens(stripUrls(step.description));
|
|
17708
|
+
const overlap = tokens.some((t2) => stepTokens.some((st) => t2.endsWith(st) || st.endsWith(t2)));
|
|
17709
|
+
if (overlap && step.kind !== "delete") {
|
|
17710
|
+
step.kind = "delete";
|
|
17711
|
+
deps.store.saveActive(plan);
|
|
17712
|
+
break;
|
|
17713
|
+
}
|
|
17714
|
+
}
|
|
17715
|
+
}
|
|
17716
|
+
}
|
|
17630
17717
|
const toolText = String(result.output ?? "");
|
|
17631
17718
|
const hasTypeError = /error TS\d+|\[Project typecheck failed\]|\[Syntax check failed\]/.test(toolText);
|
|
17632
17719
|
if (hasTypeError) {
|
|
@@ -17659,19 +17746,6 @@ Tool "${deps.stuckDetector.getLastFailedTool()}" is failing. Try "${alternative}
|
|
|
17659
17746
|
if (!hasTypeError) {
|
|
17660
17747
|
deps.stuckDetector.recordToolError(call.name, result.output);
|
|
17661
17748
|
}
|
|
17662
|
-
const actionableHints = deps.stuckDetector.getActionableHints();
|
|
17663
|
-
const alternative = deps.stuckDetector.getToolAlternative();
|
|
17664
|
-
if (actionableHints.length > 0 || alternative) {
|
|
17665
|
-
const parts = [...actionableHints];
|
|
17666
|
-
if (alternative) {
|
|
17667
|
-
parts.push(`Tool "${call.name}" crashed. Try "${alternative}" instead.`);
|
|
17668
|
-
}
|
|
17669
|
-
deps.pendingMessages.push({
|
|
17670
|
-
role: "user",
|
|
17671
|
-
content: `<system-summary>${t("exec.hints", { hints: parts.map((h) => `- ${h}`).join(`
|
|
17672
|
-
`) })}</system-summary>`
|
|
17673
|
-
});
|
|
17674
|
-
}
|
|
17675
17749
|
} else {
|
|
17676
17750
|
deps.stuckDetector.recordToolSuccess();
|
|
17677
17751
|
if (call.name === "bash" && result.success) {
|
|
@@ -17687,11 +17761,6 @@ Tool "${deps.stuckDetector.getLastFailedTool()}" is failing. Try "${alternative}
|
|
|
17687
17761
|
role: "user",
|
|
17688
17762
|
content: `<system-summary>${testRun.framework}: all ${testRun.passed} test(s) passed for "${cmd}". You may mark the current step as done via plan update step=N status=done.</system-summary>`
|
|
17689
17763
|
});
|
|
17690
|
-
} else if (/node|tsx|ts-node|python|npm\s+(start|test|run)/.test(cmd)) {
|
|
17691
|
-
deps.pendingMessages.push({
|
|
17692
|
-
role: "user",
|
|
17693
|
-
content: `<system-summary>The command "${cmd}" completed successfully. If this was testing your code, mark the current step as done via plan update step=N status=done.</system-summary>`
|
|
17694
|
-
});
|
|
17695
17764
|
}
|
|
17696
17765
|
}
|
|
17697
17766
|
}
|
|
@@ -17729,6 +17798,7 @@ function createPlanToolDefinitions(deps) {
|
|
|
17729
17798
|
return [
|
|
17730
17799
|
{
|
|
17731
17800
|
name: "plan",
|
|
17801
|
+
icon: "\uD83D\uDCCB",
|
|
17732
17802
|
alwaysOn: true,
|
|
17733
17803
|
description: `Create, update, show, abort, list, switch, delete, purge, or re-plan multi-step plans.
|
|
17734
17804
|
|
|
@@ -18005,6 +18075,20 @@ ${progress2}`,
|
|
|
18005
18075
|
};
|
|
18006
18076
|
}
|
|
18007
18077
|
}
|
|
18078
|
+
if (status === "done" && target.kind !== "delete") {
|
|
18079
|
+
const missing = deps.missingStepDeliverables(target);
|
|
18080
|
+
if (missing.length > 0) {
|
|
18081
|
+
const existing = deps.stillExistingDeliverables(target);
|
|
18082
|
+
const allGone = deps.hasStepDeliverables(target) && existing.length === 0;
|
|
18083
|
+
if (allGone) {
|
|
18084
|
+
const wasDeleted = deps.wasFileDeleted ? missing.every((f) => deps.wasFileDeleted(f)) : false;
|
|
18085
|
+
if (wasDeleted) {
|
|
18086
|
+
target.kind = "delete";
|
|
18087
|
+
deps.store.saveActive(tracker.getPlan());
|
|
18088
|
+
}
|
|
18089
|
+
}
|
|
18090
|
+
}
|
|
18091
|
+
}
|
|
18008
18092
|
if (status === "done") {
|
|
18009
18093
|
if (target.kind === "delete") {
|
|
18010
18094
|
const leftovers = deps.stillExistingDeliverables(target);
|
|
@@ -18174,6 +18258,7 @@ ${progress}${vacuousNote}`,
|
|
|
18174
18258
|
},
|
|
18175
18259
|
{
|
|
18176
18260
|
name: "todo",
|
|
18261
|
+
icon: "☑️",
|
|
18177
18262
|
alwaysOn: true,
|
|
18178
18263
|
description: "Manage sub-tasks within current plan step. Use to break down complex steps into smaller tasks.",
|
|
18179
18264
|
parameters: {
|
|
@@ -18270,6 +18355,7 @@ ${lines.join(`
|
|
|
18270
18355
|
},
|
|
18271
18356
|
{
|
|
18272
18357
|
name: "verify",
|
|
18358
|
+
icon: "✅",
|
|
18273
18359
|
alwaysOn: true,
|
|
18274
18360
|
description: "Run verification for the current step. Checks files mentioned in the step description.",
|
|
18275
18361
|
parameters: {
|
|
@@ -18285,7 +18371,7 @@ ${lines.join(`
|
|
|
18285
18371
|
const step = args.step ? tracker.getStep(Number(args.step)) : tracker.getCurrentStep();
|
|
18286
18372
|
if (!step)
|
|
18287
18373
|
return { success: false, output: t("plan.step_not_found") };
|
|
18288
|
-
const result = await deps.verifier.verifyStep(step.description);
|
|
18374
|
+
const result = await deps.verifier.verifyStep(step.description, step.kind);
|
|
18289
18375
|
if (result.noFiles) {
|
|
18290
18376
|
return {
|
|
18291
18377
|
success: true,
|
|
@@ -18330,6 +18416,7 @@ class ExecutionModule {
|
|
|
18330
18416
|
retryWebSearchSignatures = new Set;
|
|
18331
18417
|
lastErrorSearchAt = 0;
|
|
18332
18418
|
errorSearchCooldownMs;
|
|
18419
|
+
hallucinationDetector = null;
|
|
18333
18420
|
state = {
|
|
18334
18421
|
lastRecoveryIteration: -STUCK_RECOVERY_COOLDOWN,
|
|
18335
18422
|
consecutivePlanWarnings: 0,
|
|
@@ -18368,6 +18455,9 @@ class ExecutionModule {
|
|
|
18368
18455
|
this.completedPlan = null;
|
|
18369
18456
|
this._auditSkipsRemaining = 0;
|
|
18370
18457
|
}
|
|
18458
|
+
setHallucinationDetector(detector) {
|
|
18459
|
+
this.hallucinationDetector = detector;
|
|
18460
|
+
}
|
|
18371
18461
|
recordCompleted(plan) {
|
|
18372
18462
|
this.completedPlan = plan;
|
|
18373
18463
|
}
|
|
@@ -18522,7 +18612,8 @@ class ExecutionModule {
|
|
|
18522
18612
|
parseKinds: (a, st) => this.parseKinds(a, st),
|
|
18523
18613
|
getTaskText: (c) => this.getTaskText(c),
|
|
18524
18614
|
typecheckFailures: this.state.typecheckFailures,
|
|
18525
|
-
baseDir: this.baseDir
|
|
18615
|
+
baseDir: this.baseDir,
|
|
18616
|
+
wasFileDeleted: this.hallucinationDetector ? (path) => this.hallucinationDetector.getConsistencyCheck().getDeletedFiles().includes(path) : undefined
|
|
18526
18617
|
});
|
|
18527
18618
|
}
|
|
18528
18619
|
getPlugin() {
|
|
@@ -18532,6 +18623,7 @@ class ExecutionModule {
|
|
|
18532
18623
|
pendingMessages: this.pendingMessages,
|
|
18533
18624
|
forbiddenBashFailures: this.forbiddenBashFailures,
|
|
18534
18625
|
state: this.state,
|
|
18626
|
+
store: this.store,
|
|
18535
18627
|
checkPlanAlignment: (call) => this.checkPlanAlignment(call),
|
|
18536
18628
|
advancePlanIfStepComplete: (cm, sl) => this.advancePlanIfStepComplete(cm, sl),
|
|
18537
18629
|
maybeSearchError: (ctx, call) => this.maybeSearchError(ctx, call)
|
|
@@ -20054,6 +20146,7 @@ ${items}`;
|
|
|
20054
20146
|
return [
|
|
20055
20147
|
{
|
|
20056
20148
|
name: "lsp_check",
|
|
20149
|
+
icon: "\uD83E\uDE7A",
|
|
20057
20150
|
description: 'Run static checks (LSP diagnostics) on a file or directory. For "check for errors" tasks: pass a file to check it, or a directory to check its source files (capped at 15). Returns [LSP errors] / [LSP warnings] for files with a configured LSP server.',
|
|
20058
20151
|
tags: ["code", "check"],
|
|
20059
20152
|
alwaysOn: true,
|
|
@@ -20788,6 +20881,7 @@ ${t("indexer.and_more", { count: result.files.length - 100 })}` : "";
|
|
|
20788
20881
|
createProjectMapTool() {
|
|
20789
20882
|
return {
|
|
20790
20883
|
name: "project_map",
|
|
20884
|
+
icon: "\uD83D\uDDFA️",
|
|
20791
20885
|
alwaysOn: true,
|
|
20792
20886
|
description: t("indexer.project_map_desc"),
|
|
20793
20887
|
parameters: {
|
|
@@ -21314,6 +21408,7 @@ async function bootstrap(configDir, projectDir, noAgentsMd, exitOnComplete) {
|
|
|
21314
21408
|
execModule.restorePlan();
|
|
21315
21409
|
}
|
|
21316
21410
|
moduleRegistry.register(execModule);
|
|
21411
|
+
execModule.setHallucinationDetector(hallucinationDetector);
|
|
21317
21412
|
const sessionModule = new SessionModule(sessionManager);
|
|
21318
21413
|
moduleRegistry.register(sessionModule);
|
|
21319
21414
|
moduleRegistry.register(indexerModule);
|
|
@@ -32673,20 +32768,20 @@ class Renderer {
|
|
|
32673
32768
|
thinkingEnd() {
|
|
32674
32769
|
this.spinner.stop();
|
|
32675
32770
|
}
|
|
32676
|
-
toolStart(tool, args, stepContext) {
|
|
32771
|
+
toolStart(tool, args, stepContext, icon) {
|
|
32677
32772
|
this.endCard();
|
|
32678
32773
|
this.spinner.stop();
|
|
32679
32774
|
const summary = summarizeArgs2(args);
|
|
32680
32775
|
const step = stepContext ? ` ${pc2.cyan(`← ${stepContext}`)}` : "";
|
|
32776
|
+
const marker = icon || toolMarker(tool);
|
|
32681
32777
|
if (!this.rich) {
|
|
32682
32778
|
this.out.write(`
|
|
32683
|
-
${pc2.dim(
|
|
32779
|
+
${pc2.dim(marker)} ${friendlyTool(tool)}${summary ? ` ${pc2.dim(summary)}` : ""}${step}
|
|
32684
32780
|
`);
|
|
32685
32781
|
return;
|
|
32686
32782
|
}
|
|
32687
32783
|
this.card = { tool, args, body: [], start: Date.now() };
|
|
32688
32784
|
if (this.toolStyle === "inline") {
|
|
32689
|
-
const marker = toolMarker(tool);
|
|
32690
32785
|
this.out.write(`
|
|
32691
32786
|
${pc2.dim(marker)} ${friendlyTool(tool)}${summary ? ` ${pc2.dim(summary)}` : ""}${step}
|
|
32692
32787
|
`);
|
|
@@ -32695,7 +32790,7 @@ ${pc2.dim(marker)} ${friendlyTool(tool)}${summary ? ` ${pc2.dim(summary)}` : ""}
|
|
|
32695
32790
|
}
|
|
32696
32791
|
return;
|
|
32697
32792
|
}
|
|
32698
|
-
this.spinner.start(`${pc2.dim(
|
|
32793
|
+
this.spinner.start(`${pc2.dim(marker)} ${friendlyTool(tool)}${summary ? ` ${pc2.dim(summary)}` : ""}${step}`);
|
|
32699
32794
|
}
|
|
32700
32795
|
planBlock(lines) {
|
|
32701
32796
|
this.endCard();
|
|
@@ -33255,7 +33350,7 @@ ${t("image.clipboard_empty")}`));
|
|
|
33255
33350
|
this.refreshActivePlan(renderer);
|
|
33256
33351
|
const result = await this.agent.run(input, (c) => renderer.text(c), (m) => renderer.meta(m), (ev) => {
|
|
33257
33352
|
if (ev.type === "start") {
|
|
33258
|
-
renderer.toolStart(ev.tool, ev.args, stepContextForTool(this.activePlan, ev.tool, ev.args));
|
|
33353
|
+
renderer.toolStart(ev.tool, ev.args, stepContextForTool(this.activePlan, ev.tool, ev.args), ev.icon);
|
|
33259
33354
|
} else {
|
|
33260
33355
|
renderer.toolEnd(ev.tool, ev.duration ?? 0, ev.error, ev.ctxDelta);
|
|
33261
33356
|
if (ev.tool === "plan" || ev.tool === "todo") {
|
|
@@ -33701,7 +33796,7 @@ async function main() {
|
|
|
33701
33796
|
});
|
|
33702
33797
|
const result = await agent.run(prompt, (chunk) => renderer.text(chunk), (meta) => renderer.meta(meta), (ev) => {
|
|
33703
33798
|
if (ev.type === "start") {
|
|
33704
|
-
renderer.toolStart(ev.tool, ev.args);
|
|
33799
|
+
renderer.toolStart(ev.tool, ev.args, undefined, ev.icon);
|
|
33705
33800
|
} else {
|
|
33706
33801
|
renderer.toolEnd(ev.tool, ev.duration ?? 0, ev.error, ev.ctxDelta);
|
|
33707
33802
|
}
|