micro-models-agent 0.24.3 → 0.24.4
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 +147 -13
- package/package.json +1 -1
package/dist/main.js
CHANGED
|
@@ -2125,9 +2125,9 @@ var init_defaults = __esm(() => {
|
|
|
2125
2125
|
offloadKvCacheToGpu: true
|
|
2126
2126
|
},
|
|
2127
2127
|
retry: {
|
|
2128
|
-
maxRetries:
|
|
2129
|
-
baseDelay:
|
|
2130
|
-
maxDelay:
|
|
2128
|
+
maxRetries: 5,
|
|
2129
|
+
baseDelay: 5000,
|
|
2130
|
+
maxDelay: 120000
|
|
2131
2131
|
},
|
|
2132
2132
|
maxToolIterations: 1000,
|
|
2133
2133
|
stuckThreshold: 8,
|
|
@@ -4884,7 +4884,8 @@ function runCommand(command, options = {}) {
|
|
|
4884
4884
|
cwd,
|
|
4885
4885
|
callId,
|
|
4886
4886
|
timeoutMs = 120000,
|
|
4887
|
-
maxBuffer = 10 * 1024 * 1024
|
|
4887
|
+
maxBuffer = 10 * 1024 * 1024,
|
|
4888
|
+
onOutput
|
|
4888
4889
|
} = options;
|
|
4889
4890
|
return new Promise((resolve) => {
|
|
4890
4891
|
let timedOut = false;
|
|
@@ -4903,6 +4904,7 @@ function runCommand(command, options = {}) {
|
|
|
4903
4904
|
const decodeChunk = (chunk) => decoder ? decoder.decode(chunk, { stream: true }) : chunk.toString("utf-8");
|
|
4904
4905
|
child.stdout?.on("data", (chunk) => {
|
|
4905
4906
|
const text = decodeChunk(chunk);
|
|
4907
|
+
onOutput?.(text);
|
|
4906
4908
|
const next = stdoutRef.value.length + text.length;
|
|
4907
4909
|
if (next > maxBuffer) {
|
|
4908
4910
|
stdoutRef.value = stdoutRef.value.slice(stdoutRef.value.length + text.length - maxBuffer) + text;
|
|
@@ -4912,6 +4914,7 @@ function runCommand(command, options = {}) {
|
|
|
4912
4914
|
});
|
|
4913
4915
|
child.stderr?.on("data", (chunk) => {
|
|
4914
4916
|
const text = decodeChunk(chunk);
|
|
4917
|
+
onOutput?.(text);
|
|
4915
4918
|
const next = stderrRef.value.length + text.length;
|
|
4916
4919
|
if (next > maxBuffer) {
|
|
4917
4920
|
stderrRef.value = stderrRef.value.slice(stderrRef.value.length + text.length - maxBuffer) + text;
|
|
@@ -4945,7 +4948,13 @@ function runCommand(command, options = {}) {
|
|
|
4945
4948
|
clearTimeout(timer);
|
|
4946
4949
|
if (callId)
|
|
4947
4950
|
activeChildren.delete(callId);
|
|
4948
|
-
resolve({
|
|
4951
|
+
resolve({
|
|
4952
|
+
stdout: stdoutRef.value,
|
|
4953
|
+
stderr: stderrRef.value,
|
|
4954
|
+
code,
|
|
4955
|
+
signal,
|
|
4956
|
+
timedOut
|
|
4957
|
+
});
|
|
4949
4958
|
});
|
|
4950
4959
|
});
|
|
4951
4960
|
}
|
|
@@ -4954,11 +4963,61 @@ var init_runner = __esm(() => {
|
|
|
4954
4963
|
activeChildren = new Map;
|
|
4955
4964
|
});
|
|
4956
4965
|
|
|
4966
|
+
// src/tools/cache.ts
|
|
4967
|
+
class ToolResultCache {
|
|
4968
|
+
cache = new Map;
|
|
4969
|
+
maxEntries;
|
|
4970
|
+
defaultTtlMs;
|
|
4971
|
+
constructor(maxEntries = 50, defaultTtlMs = 60000) {
|
|
4972
|
+
this.maxEntries = maxEntries;
|
|
4973
|
+
this.defaultTtlMs = defaultTtlMs;
|
|
4974
|
+
}
|
|
4975
|
+
get(key) {
|
|
4976
|
+
const entry = this.cache.get(key);
|
|
4977
|
+
if (!entry)
|
|
4978
|
+
return;
|
|
4979
|
+
if (Date.now() > entry.expiresAt) {
|
|
4980
|
+
this.cache.delete(key);
|
|
4981
|
+
return;
|
|
4982
|
+
}
|
|
4983
|
+
this.cache.delete(key);
|
|
4984
|
+
this.cache.set(key, entry);
|
|
4985
|
+
return entry.value;
|
|
4986
|
+
}
|
|
4987
|
+
set(key, value, ttlMs) {
|
|
4988
|
+
if (this.cache.size >= this.maxEntries) {
|
|
4989
|
+
const firstKey = this.cache.keys().next().value;
|
|
4990
|
+
if (firstKey !== undefined) {
|
|
4991
|
+
this.cache.delete(firstKey);
|
|
4992
|
+
}
|
|
4993
|
+
}
|
|
4994
|
+
this.cache.set(key, {
|
|
4995
|
+
value,
|
|
4996
|
+
expiresAt: Date.now() + (ttlMs ?? this.defaultTtlMs)
|
|
4997
|
+
});
|
|
4998
|
+
}
|
|
4999
|
+
has(key) {
|
|
5000
|
+
return this.get(key) !== undefined;
|
|
5001
|
+
}
|
|
5002
|
+
clear() {
|
|
5003
|
+
this.cache.clear();
|
|
5004
|
+
}
|
|
5005
|
+
get size() {
|
|
5006
|
+
return this.cache.size;
|
|
5007
|
+
}
|
|
5008
|
+
}
|
|
5009
|
+
function hashKey(toolName, args) {
|
|
5010
|
+
const payload = toolName + JSON.stringify(args);
|
|
5011
|
+
const hash = Bun.hash(payload).toString(16).slice(0, 16);
|
|
5012
|
+
return hash;
|
|
5013
|
+
}
|
|
5014
|
+
|
|
4957
5015
|
// src/tools/executor.ts
|
|
4958
5016
|
class ToolExecutor {
|
|
4959
5017
|
registry;
|
|
4960
5018
|
ctx;
|
|
4961
5019
|
pluginManager;
|
|
5020
|
+
cache = new ToolResultCache(50, CACHE_TTL_MS);
|
|
4962
5021
|
constructor(registry, ctx, pluginManager) {
|
|
4963
5022
|
this.registry = registry;
|
|
4964
5023
|
this.ctx = ctx;
|
|
@@ -4973,6 +5032,18 @@ class ToolExecutor {
|
|
|
4973
5032
|
toolCallId: call.id
|
|
4974
5033
|
};
|
|
4975
5034
|
}
|
|
5035
|
+
if (CACHEABLE_TOOLS.has(call.name)) {
|
|
5036
|
+
const key = hashKey(call.name, call.arguments);
|
|
5037
|
+
const cached = this.cache.get(key);
|
|
5038
|
+
if (cached !== undefined) {
|
|
5039
|
+
this.ctx.logger.debug(`Tool ${call.name}: CACHE HIT`);
|
|
5040
|
+
return {
|
|
5041
|
+
success: true,
|
|
5042
|
+
output: cached,
|
|
5043
|
+
toolCallId: call.id
|
|
5044
|
+
};
|
|
5045
|
+
}
|
|
5046
|
+
}
|
|
4976
5047
|
for (const plugin of this.pluginManager.getAllPlugins()) {
|
|
4977
5048
|
if (plugin.onBeforeTool) {
|
|
4978
5049
|
try {
|
|
@@ -5043,6 +5114,11 @@ class ToolExecutor {
|
|
|
5043
5114
|
}
|
|
5044
5115
|
}
|
|
5045
5116
|
}
|
|
5117
|
+
if (result.success && CACHEABLE_TOOLS.has(call.name)) {
|
|
5118
|
+
const key = hashKey(call.name, call.arguments);
|
|
5119
|
+
this.cache.set(key, result.output);
|
|
5120
|
+
this.ctx.logger.debug(`Tool ${call.name}: CACHED`);
|
|
5121
|
+
}
|
|
5046
5122
|
this.ctx.logger.debug(`Tool ${call.name}: ${result.success ? "OK" : "FAIL"}`);
|
|
5047
5123
|
return result;
|
|
5048
5124
|
}
|
|
@@ -5052,6 +5128,9 @@ class ToolExecutor {
|
|
|
5052
5128
|
getRegistry() {
|
|
5053
5129
|
return this.registry;
|
|
5054
5130
|
}
|
|
5131
|
+
getContext() {
|
|
5132
|
+
return this.ctx;
|
|
5133
|
+
}
|
|
5055
5134
|
setScope(scope) {
|
|
5056
5135
|
this.ctx.scope = scope;
|
|
5057
5136
|
}
|
|
@@ -5059,10 +5138,11 @@ class ToolExecutor {
|
|
|
5059
5138
|
this.ctx.llmProvider = provider;
|
|
5060
5139
|
}
|
|
5061
5140
|
}
|
|
5062
|
-
var TOOL_EXECUTION_TIMEOUT_MS = 60000;
|
|
5141
|
+
var TOOL_EXECUTION_TIMEOUT_MS = 60000, CACHEABLE_TOOLS, CACHE_TTL_MS = 60000;
|
|
5063
5142
|
var init_executor = __esm(() => {
|
|
5064
5143
|
init_runner();
|
|
5065
5144
|
init_i18n();
|
|
5145
|
+
CACHEABLE_TOOLS = new Set(["web_fetch"]);
|
|
5066
5146
|
});
|
|
5067
5147
|
|
|
5068
5148
|
// src/modules/security/path-validator.ts
|
|
@@ -5593,7 +5673,7 @@ function safeResolvePath(baseDir, userPath) {
|
|
|
5593
5673
|
var init_path_utils = () => {};
|
|
5594
5674
|
|
|
5595
5675
|
// src/tools/preview.ts
|
|
5596
|
-
var MAX_PREVIEW_LINES =
|
|
5676
|
+
var MAX_PREVIEW_LINES = 100;
|
|
5597
5677
|
|
|
5598
5678
|
// src/tools/read-file.ts
|
|
5599
5679
|
import { readFileSync as readFileSync5, existsSync as existsSync9 } from "fs";
|
|
@@ -6957,8 +7037,14 @@ var init_bash = __esm(() => {
|
|
|
6957
7037
|
type: "object",
|
|
6958
7038
|
properties: {
|
|
6959
7039
|
command: { type: "string", description: "Shell command to execute" },
|
|
6960
|
-
workdir: {
|
|
6961
|
-
|
|
7040
|
+
workdir: {
|
|
7041
|
+
type: "string",
|
|
7042
|
+
description: "Working directory (default: baseDir)"
|
|
7043
|
+
},
|
|
7044
|
+
background: {
|
|
7045
|
+
type: "boolean",
|
|
7046
|
+
description: "Start the command in the background and return immediately with a process id (default: auto-detect long-running commands)"
|
|
7047
|
+
}
|
|
6962
7048
|
},
|
|
6963
7049
|
required: ["command"]
|
|
6964
7050
|
},
|
|
@@ -7005,7 +7091,8 @@ ${t("proc.manage_hint", {
|
|
|
7005
7091
|
const res = await runCommand(command, {
|
|
7006
7092
|
cwd: workdir,
|
|
7007
7093
|
callId: ctx.activeCallId,
|
|
7008
|
-
timeoutMs: BASH_TIMEOUT_MS
|
|
7094
|
+
timeoutMs: BASH_TIMEOUT_MS,
|
|
7095
|
+
onOutput: ctx.onMeta
|
|
7009
7096
|
});
|
|
7010
7097
|
const parts = [res.stdout.trimEnd(), res.stderr.trimEnd()].filter(Boolean);
|
|
7011
7098
|
let output = parts.join(`
|
|
@@ -9065,6 +9152,16 @@ var init_store = __esm(() => {
|
|
|
9065
9152
|
|
|
9066
9153
|
// src/core/agent.ts
|
|
9067
9154
|
import { join as join10 } from "path";
|
|
9155
|
+
function canRunInParallel(calls) {
|
|
9156
|
+
if (calls.length <= 1)
|
|
9157
|
+
return false;
|
|
9158
|
+
for (const call of calls) {
|
|
9159
|
+
if (SIDE_EFFECT_TOOLS.has(call.name) || WRITE_TOOLS.has(call.name)) {
|
|
9160
|
+
return false;
|
|
9161
|
+
}
|
|
9162
|
+
}
|
|
9163
|
+
return true;
|
|
9164
|
+
}
|
|
9068
9165
|
|
|
9069
9166
|
class Agent {
|
|
9070
9167
|
deps;
|
|
@@ -9327,7 +9424,7 @@ ${t("tool.truncated", { tokens: Math.ceil(removedChars / 2) })}`;
|
|
|
9327
9424
|
});
|
|
9328
9425
|
const summaries = [];
|
|
9329
9426
|
let anyToolFailed = false;
|
|
9330
|
-
|
|
9427
|
+
const executeToolCall = async (call) => {
|
|
9331
9428
|
this.setScope();
|
|
9332
9429
|
const startTime = Date.now();
|
|
9333
9430
|
pluginManager.runOnToolCall({
|
|
@@ -9338,11 +9435,28 @@ ${t("tool.truncated", { tokens: Math.ceil(removedChars / 2) })}`;
|
|
|
9338
9435
|
onTool?.({ type: "start", tool: call.name, args: call.arguments });
|
|
9339
9436
|
slog.logToolCall(call, iteration);
|
|
9340
9437
|
const tokensBeforeTool = contextManager.getEstimatedTokens();
|
|
9438
|
+
const toolCtx = this.deps.toolExecutor?.getContext?.();
|
|
9439
|
+
const prevOnMeta = toolCtx?.onMeta;
|
|
9440
|
+
if (toolCtx) {
|
|
9441
|
+
toolCtx.onMeta = onMeta;
|
|
9442
|
+
}
|
|
9341
9443
|
const result = await toolExecutor.execute(call, this.abortController?.signal);
|
|
9444
|
+
if (toolCtx) {
|
|
9445
|
+
toolCtx.onMeta = prevOnMeta;
|
|
9446
|
+
}
|
|
9342
9447
|
const duration = Date.now() - startTime;
|
|
9448
|
+
pluginManager.runOnToolEnd({ iteration, logger }, { id: call.id, name: call.name, arguments: call.arguments }, result, duration);
|
|
9449
|
+
return { call, result, duration, tokensBefore: tokensBeforeTool };
|
|
9450
|
+
};
|
|
9451
|
+
const processToolResult = (entry) => {
|
|
9452
|
+
const {
|
|
9453
|
+
call,
|
|
9454
|
+
result,
|
|
9455
|
+
duration,
|
|
9456
|
+
tokensBefore: tokensBeforeTool
|
|
9457
|
+
} = entry;
|
|
9343
9458
|
if (!result.success)
|
|
9344
9459
|
anyToolFailed = true;
|
|
9345
|
-
pluginManager.runOnToolEnd({ iteration, logger }, { id: call.id, name: call.name, arguments: call.arguments }, result, duration);
|
|
9346
9460
|
if (result.display) {
|
|
9347
9461
|
onMeta?.(`
|
|
9348
9462
|
` + result.display + `
|
|
@@ -9386,6 +9500,17 @@ ${t("tool.truncated", { tokens: Math.ceil(removedChars / 2) })}`;
|
|
|
9386
9500
|
contextManager.compact();
|
|
9387
9501
|
logger.debug("Context compacted after tool result");
|
|
9388
9502
|
}
|
|
9503
|
+
};
|
|
9504
|
+
if (canRunInParallel(toolCalls)) {
|
|
9505
|
+
const entries = await Promise.all(toolCalls.map(executeToolCall));
|
|
9506
|
+
for (const entry of entries) {
|
|
9507
|
+
processToolResult(entry);
|
|
9508
|
+
}
|
|
9509
|
+
} else {
|
|
9510
|
+
for (const call of toolCalls) {
|
|
9511
|
+
const entry = await executeToolCall(call);
|
|
9512
|
+
processToolResult(entry);
|
|
9513
|
+
}
|
|
9389
9514
|
}
|
|
9390
9515
|
if (anyToolFailed) {
|
|
9391
9516
|
consecutiveToolFailures++;
|
|
@@ -9596,7 +9721,7 @@ ${taskReminder}</system-summary>`
|
|
|
9596
9721
|
});
|
|
9597
9722
|
}
|
|
9598
9723
|
}
|
|
9599
|
-
var TOOL_RESULT_MAX_TOKENS_RATIO = 0.3, TOOL_RESULT_ABSOLUTE_MAX_CHARS = 15000;
|
|
9724
|
+
var TOOL_RESULT_MAX_TOKENS_RATIO = 0.3, TOOL_RESULT_ABSOLUTE_MAX_CHARS = 15000, WRITE_TOOLS, SIDE_EFFECT_TOOLS;
|
|
9600
9725
|
var init_agent = __esm(() => {
|
|
9601
9726
|
init_i18n();
|
|
9602
9727
|
init_colors();
|
|
@@ -9604,6 +9729,14 @@ var init_agent = __esm(() => {
|
|
|
9604
9729
|
init_processes();
|
|
9605
9730
|
init_agent_moe();
|
|
9606
9731
|
init_store();
|
|
9732
|
+
WRITE_TOOLS = new Set([
|
|
9733
|
+
"write_file",
|
|
9734
|
+
"edit_file",
|
|
9735
|
+
"delete_file",
|
|
9736
|
+
"move_file",
|
|
9737
|
+
"create_dir"
|
|
9738
|
+
]);
|
|
9739
|
+
SIDE_EFFECT_TOOLS = new Set(["bash", "subagent", "pipeline_run"]);
|
|
9607
9740
|
});
|
|
9608
9741
|
|
|
9609
9742
|
// src/modules/context/manager.ts
|
|
@@ -15309,6 +15442,7 @@ function buildSystemInfo(config, baseDir, profileCompressed) {
|
|
|
15309
15442
|
lines.push(``, `Windows environment — use Windows-compatible commands:`, `- Use "dir" instead of "ls". Use "dir /b" for bare listing.`, `- Use "type" or "Get-Content" instead of "cat".`, `- Use "cd" instead of "pwd". Use "echo %cd%" to print working directory.`, `- Use "copy" instead of "cp", "move" instead of "mv", "del" instead of "rm".`, `- Do not use "mkdir -p" — Windows mkdir creates intermediate dirs by default. Use the create_dir tool instead.`, `- Use forward slashes (/) or escaped backslashes (\\\\) in file paths.`, `- Your working directory is: ${baseDir}`);
|
|
15310
15443
|
}
|
|
15311
15444
|
lines.push(``, `Bash tool rules:`, `- Use the "workdir" parameter to run commands in a specific directory. Prefer workdir over "cd dir && cmd" chaining.`, `- Run one command per tool call. Split multi-step shell operations into separate bash calls.`, `- Background processes (dev servers, watchers, long-running npm install): use the "background: true" parameter or the tool will auto-detect and background them. Check output with process_log.`);
|
|
15445
|
+
lines.push(``, `Parallel tool calls:`, `- When you need to read multiple files, call read_file for ALL of them in a SINGLE response (one tool_calls array with multiple read_file calls). They will execute in parallel — much faster than reading one at a time.`, `- Example: to read 3 files, return one assistant message with 3 read_file tool_calls. Do NOT read them one by one in separate iterations.`, `- This works for: read_file, glob, grep, file_info, list_dir — any read-only operations.`, `- Do NOT parallelize write operations (write_file, edit_file, delete_file, bash) — these run sequentially.`);
|
|
15312
15446
|
lines.push(``, `=== DEVELOPMENT RULES — follow these strictly ===`, ``, `1. DEPENDENCIES FIRST: Before writing any source code, ALWAYS install project dependencies (e.g., "npm install", "pip install -r requirements.txt", "cargo build", "go mod tidy"). Verify the package manager's lock file or dependency directory exists. Never write code that imports/uses packages that aren't installed yet.`, `2. TOOLKIT/FWK FIRST: If the task specifies a framework or UI library, initialize and configure it BEFORE writing application code. Run its project init command first, then add components/modules. Never write your own version of what the framework already provides.`, `3. ONE STEP AT A TIME: Follow the plan sequentially. Complete step N before starting step N+1. When a step is done: verify the deliverables exist and have real content (not empty), then call "plan update step=N status=done". Do not redo completed work.`, `4. VERIFY YOUR WORK: After creating/modifying files, verify they exist on disk. After installing dependencies, verify the package manager completed successfully. After any command, check its output for errors. Don't assume operations succeeded.`, `5. NO PREMATURE WORK: Do not create files for future steps. Do not add imports/references to packages or modules that haven't been installed yet. Do not reference files or components that don't exist yet. Build incrementally — one layer at a time.`, `6. WHEN STUCK: If a command fails 2+ times, STOP and try a different approach. Write files directly instead of using commands. Ask the user for help. Never repeat the same failing command more than twice.`, ``, `=== PLAN QUALITY RULES — your plan MUST follow these ===`, ``, `- Each step must describe CONCRETE deliverables: exact filenames with paths, exact packages to install, exact CLI commands to run. Avoid vague steps — be specific.`, `- A step like "Настройка проекта" or "Setup the project" is too vague — describe what exactly needs to be configured or set up.`, `- A step like "Создать src/components/Header.tsx с навигацией и логотипом, добавить в src/App.tsx импорт <Header />" is GOOD.`, `- Include file extensions (.tsx, .css, .json) and directory paths. Every step must mention at least one file or command.`, `- The plan must cover EVERYTHING needed: init → deps → framework setup → code → verification.`, `- Number of steps: 5-8 for a typical task. Too few means you're being vague. Too many means you're over-splitting.`);
|
|
15313
15447
|
if (config.autoPlan) {
|
|
15314
15448
|
lines.push(``, `Plan rule (MANDATORY): For ANY task that requires creating files, installing packages, or multiple actions — you MUST create a plan using the "plan" tool BEFORE starting work. Each step must describe a concrete deliverable (specific files to create, packages to install, commands to run). Do not combine unrelated work into one step.`);
|