micro-models-agent 0.24.1 → 0.24.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/main.js +111 -28
- package/package.json +1 -1
package/dist/main.js
CHANGED
|
@@ -2306,6 +2306,7 @@ var init_en = __esm(() => {
|
|
|
2306
2306
|
"tool.memory_error": "Memory error: {error}",
|
|
2307
2307
|
"tool.screenshot_unavailable": "[Screenshot captured — image not available for text-only model]",
|
|
2308
2308
|
"tool.timeout": "Tool {name} timed out after {seconds} seconds",
|
|
2309
|
+
"tool.aborted": "Tool {name} was interrupted by user",
|
|
2309
2310
|
"tool.interactive_disabled": "Interactive tool is disabled in exit-on-complete mode. Proceed without asking the user.",
|
|
2310
2311
|
"proc.started": `Started background process {id} (PID {pid}).
|
|
2311
2312
|
Command: {command}`,
|
|
@@ -2850,6 +2851,7 @@ var init_ru = __esm(() => {
|
|
|
2850
2851
|
"tool.memory_error": "Ошибка памяти: {error}",
|
|
2851
2852
|
"tool.screenshot_unavailable": "[Скриншот сделан — изображение недоступно для текстовой модели]",
|
|
2852
2853
|
"tool.timeout": "Инструмент {name} превысил таймаут ({seconds} сек)",
|
|
2854
|
+
"tool.aborted": "Инструмент {name} прерван пользователем",
|
|
2853
2855
|
"tool.interactive_disabled": "Интерактивный инструмент отключён в режиме exit-on-complete. Продолжай без вопроса пользователю.",
|
|
2854
2856
|
"proc.started": `Фоновый процесс запущен: {id} (PID {pid}).
|
|
2855
2857
|
Команда: {command}`,
|
|
@@ -4291,6 +4293,11 @@ function getMessageText(content) {
|
|
|
4291
4293
|
}
|
|
4292
4294
|
|
|
4293
4295
|
// src/llm/token-counter.ts
|
|
4296
|
+
var exports_token_counter = {};
|
|
4297
|
+
__export(exports_token_counter, {
|
|
4298
|
+
TokenCounter: () => TokenCounter
|
|
4299
|
+
});
|
|
4300
|
+
|
|
4294
4301
|
class TokenCounter {
|
|
4295
4302
|
encoder;
|
|
4296
4303
|
constructor(model = "gpt-4o") {
|
|
@@ -4957,7 +4964,7 @@ class ToolExecutor {
|
|
|
4957
4964
|
this.ctx = ctx;
|
|
4958
4965
|
this.pluginManager = pluginManager;
|
|
4959
4966
|
}
|
|
4960
|
-
async execute(call) {
|
|
4967
|
+
async execute(call, signal) {
|
|
4961
4968
|
const tool = this.registry.get(call.name);
|
|
4962
4969
|
if (!tool) {
|
|
4963
4970
|
return {
|
|
@@ -4999,10 +5006,25 @@ class ToolExecutor {
|
|
|
4999
5006
|
})));
|
|
5000
5007
|
}, TOOL_EXECUTION_TIMEOUT_MS);
|
|
5001
5008
|
});
|
|
5002
|
-
|
|
5009
|
+
const racePromises = [
|
|
5003
5010
|
tool.handler(this.ctx, call.arguments),
|
|
5004
5011
|
timeoutPromise
|
|
5005
|
-
]
|
|
5012
|
+
];
|
|
5013
|
+
if (signal) {
|
|
5014
|
+
const abortPromise = new Promise((_, reject) => {
|
|
5015
|
+
const onAbort = () => {
|
|
5016
|
+
killByCallId(call.id);
|
|
5017
|
+
reject(new Error(t("tool.aborted", { name: call.name })));
|
|
5018
|
+
};
|
|
5019
|
+
if (signal.aborted) {
|
|
5020
|
+
onAbort();
|
|
5021
|
+
} else {
|
|
5022
|
+
signal.addEventListener("abort", onAbort, { once: true });
|
|
5023
|
+
}
|
|
5024
|
+
});
|
|
5025
|
+
racePromises.push(abortPromise);
|
|
5026
|
+
}
|
|
5027
|
+
result = await Promise.race(racePromises);
|
|
5006
5028
|
}
|
|
5007
5029
|
result.toolCallId = call.id;
|
|
5008
5030
|
} catch (e) {
|
|
@@ -5033,6 +5055,9 @@ class ToolExecutor {
|
|
|
5033
5055
|
setScope(scope) {
|
|
5034
5056
|
this.ctx.scope = scope;
|
|
5035
5057
|
}
|
|
5058
|
+
updateProvider(provider) {
|
|
5059
|
+
this.ctx.llmProvider = provider;
|
|
5060
|
+
}
|
|
5036
5061
|
}
|
|
5037
5062
|
var TOOL_EXECUTION_TIMEOUT_MS = 60000;
|
|
5038
5063
|
var init_executor = __esm(() => {
|
|
@@ -9040,6 +9065,7 @@ class Agent {
|
|
|
9040
9065
|
deps;
|
|
9041
9066
|
systemPromptAdded = false;
|
|
9042
9067
|
shutdownRequested = false;
|
|
9068
|
+
abortController = null;
|
|
9043
9069
|
constructor(deps) {
|
|
9044
9070
|
this.deps = deps;
|
|
9045
9071
|
}
|
|
@@ -9155,6 +9181,7 @@ ${t("tool.truncated", { tokens: Math.ceil(removedChars / 2) })}`;
|
|
|
9155
9181
|
baseDir
|
|
9156
9182
|
} = this.deps;
|
|
9157
9183
|
const slog = new SessionLogger(sessionManager);
|
|
9184
|
+
this.abortController = new AbortController;
|
|
9158
9185
|
let iteration = 0;
|
|
9159
9186
|
let lastText = "";
|
|
9160
9187
|
let hallucinationRetries = 0;
|
|
@@ -9168,6 +9195,7 @@ ${t("tool.truncated", { tokens: Math.ceil(removedChars / 2) })}`;
|
|
|
9168
9195
|
const MAX_AUDIT_RETRIES = 3;
|
|
9169
9196
|
while (iteration < config.maxToolIterations && !this.shutdownRequested) {
|
|
9170
9197
|
iteration++;
|
|
9198
|
+
contextManager.noteIteration();
|
|
9171
9199
|
pluginManager.runOnBeforeThink({
|
|
9172
9200
|
iteration,
|
|
9173
9201
|
logger,
|
|
@@ -9200,6 +9228,8 @@ ${t("tool.truncated", { tokens: Math.ceil(removedChars / 2) })}`;
|
|
|
9200
9228
|
this.emitPhase(iteration, "thinking", onPhase);
|
|
9201
9229
|
try {
|
|
9202
9230
|
for await (const chunk of llmProvider.chat(history, allTools)) {
|
|
9231
|
+
if (this.shutdownRequested)
|
|
9232
|
+
break;
|
|
9203
9233
|
if (chunk.type === "text" && chunk.content) {
|
|
9204
9234
|
if (emittedReasoning && !textContent) {
|
|
9205
9235
|
onMeta?.(`
|
|
@@ -9303,7 +9333,7 @@ ${t("tool.truncated", { tokens: Math.ceil(removedChars / 2) })}`;
|
|
|
9303
9333
|
onTool?.({ type: "start", tool: call.name, args: call.arguments });
|
|
9304
9334
|
slog.logToolCall(call, iteration);
|
|
9305
9335
|
const tokensBeforeTool = contextManager.getEstimatedTokens();
|
|
9306
|
-
const result = await toolExecutor.execute(call);
|
|
9336
|
+
const result = await toolExecutor.execute(call, this.abortController?.signal);
|
|
9307
9337
|
const duration = Date.now() - startTime;
|
|
9308
9338
|
if (!result.success)
|
|
9309
9339
|
anyToolFailed = true;
|
|
@@ -9322,15 +9352,6 @@ ${t("tool.truncated", { tokens: Math.ceil(removedChars / 2) })}`;
|
|
|
9322
9352
|
` + result.diff + `
|
|
9323
9353
|
`);
|
|
9324
9354
|
}
|
|
9325
|
-
const tokensAfterTool = contextManager.getEstimatedTokens();
|
|
9326
|
-
onTool?.({
|
|
9327
|
-
type: "end",
|
|
9328
|
-
tool: call.name,
|
|
9329
|
-
args: call.arguments,
|
|
9330
|
-
duration,
|
|
9331
|
-
error: !result.success,
|
|
9332
|
-
ctxDelta: tokensAfterTool - tokensBeforeTool
|
|
9333
|
-
});
|
|
9334
9355
|
const currentTokens2 = contextManager.getEstimatedTokens();
|
|
9335
9356
|
const budget3 = contextManager.getBudget();
|
|
9336
9357
|
const truncatedOutput = this.truncateToolOutput(result.output, budget3, currentTokens2);
|
|
@@ -9342,6 +9363,15 @@ ${t("tool.truncated", { tokens: Math.ceil(removedChars / 2) })}`;
|
|
|
9342
9363
|
success: result.success,
|
|
9343
9364
|
arguments: call.arguments
|
|
9344
9365
|
});
|
|
9366
|
+
const tokensAfterTool = contextManager.getEstimatedTokens();
|
|
9367
|
+
onTool?.({
|
|
9368
|
+
type: "end",
|
|
9369
|
+
tool: call.name,
|
|
9370
|
+
args: call.arguments,
|
|
9371
|
+
duration,
|
|
9372
|
+
error: !result.success,
|
|
9373
|
+
ctxDelta: tokensAfterTool - tokensBeforeTool
|
|
9374
|
+
});
|
|
9345
9375
|
summaries.push(`[Tool: ${call.name} (${JSON.stringify(call.arguments)}) → ${truncatedOutput.slice(0, 200)}]`);
|
|
9346
9376
|
if (config.session.autoSave) {
|
|
9347
9377
|
slog.logToolResult(call, result, duration, iteration);
|
|
@@ -9512,6 +9542,23 @@ ${taskReminder}</system-summary>`
|
|
|
9512
9542
|
this.deps.contextManager.clear();
|
|
9513
9543
|
this.systemPromptAdded = false;
|
|
9514
9544
|
}
|
|
9545
|
+
async reconfigure(config) {
|
|
9546
|
+
const { OpenAICompatProvider: OpenAICompatProvider2 } = await Promise.resolve().then(() => (init_openai_compat(), exports_openai_compat));
|
|
9547
|
+
const { TokenCounter: TokenCounter2 } = await Promise.resolve().then(() => (init_token_counter(), exports_token_counter));
|
|
9548
|
+
const newProvider = new OpenAICompatProvider2({
|
|
9549
|
+
model: config.model,
|
|
9550
|
+
baseUrl: config.provider.baseUrl,
|
|
9551
|
+
apiKey: config.provider.apiKey,
|
|
9552
|
+
contextWindow: config.contextWindow,
|
|
9553
|
+
retry: config.retry,
|
|
9554
|
+
rateLimits: config.security?.rateLimits
|
|
9555
|
+
});
|
|
9556
|
+
this.deps.llmProvider = newProvider;
|
|
9557
|
+
this.deps.toolExecutor.updateProvider(newProvider);
|
|
9558
|
+
const newTokenCounter = new TokenCounter2(config.model);
|
|
9559
|
+
this.deps.contextManager.resize(config.contextWindow, config.contextBudget, newTokenCounter);
|
|
9560
|
+
this.deps.config = config;
|
|
9561
|
+
}
|
|
9515
9562
|
setContext(messages) {
|
|
9516
9563
|
const { contextManager } = this.deps;
|
|
9517
9564
|
contextManager.clear();
|
|
@@ -9530,6 +9577,7 @@ ${taskReminder}</system-summary>`
|
|
|
9530
9577
|
}
|
|
9531
9578
|
shutdown() {
|
|
9532
9579
|
this.shutdownRequested = true;
|
|
9580
|
+
this.abortController?.abort();
|
|
9533
9581
|
const { pluginManager, logger, sessionManager, contextManager } = this.deps;
|
|
9534
9582
|
contextManager.onCompact = null;
|
|
9535
9583
|
const killed = processRegistry.killAll();
|
|
@@ -9635,10 +9683,18 @@ class ContextManager {
|
|
|
9635
9683
|
getIterationsSinceCompaction() {
|
|
9636
9684
|
return this.iterationsSinceCompaction;
|
|
9637
9685
|
}
|
|
9686
|
+
noteIteration() {
|
|
9687
|
+
this.iterationsSinceCompaction++;
|
|
9688
|
+
}
|
|
9638
9689
|
getQuality() {
|
|
9639
|
-
const
|
|
9640
|
-
const
|
|
9641
|
-
|
|
9690
|
+
const usedTokens = this.getEstimatedTokens();
|
|
9691
|
+
const tokenLoad = Math.max(0, 1 - usedTokens / this.budget.history);
|
|
9692
|
+
const compactionLoss = Math.max(0, 1 - this.compactionCount * 0.15);
|
|
9693
|
+
const msgCount = this.messages.length || 1;
|
|
9694
|
+
const errorDensity = Math.max(0, 1 - Math.min(1, this.errorFacts.length / msgCount));
|
|
9695
|
+
const freshness = Math.max(0, 1 - this.iterationsSinceCompaction / COMPACTION_INTERVAL);
|
|
9696
|
+
const score = tokenLoad * 0.4 + compactionLoss * 0.25 + errorDensity * 0.2 + freshness * 0.15;
|
|
9697
|
+
return Math.round(Math.min(100, Math.max(0, score * 100)));
|
|
9642
9698
|
}
|
|
9643
9699
|
addMessage(msg) {
|
|
9644
9700
|
if (msg.role === "user" && this.pendingImageParts.length > 0) {
|
|
@@ -9653,7 +9709,6 @@ class ContextManager {
|
|
|
9653
9709
|
this.pendingImageParts = [];
|
|
9654
9710
|
}
|
|
9655
9711
|
this.messages.push(msg);
|
|
9656
|
-
this.iterationsSinceCompaction++;
|
|
9657
9712
|
const tokens = this.getEstimatedTokens();
|
|
9658
9713
|
if (tokens > this.peakTokens)
|
|
9659
9714
|
this.peakTokens = tokens;
|
|
@@ -9820,6 +9875,13 @@ ${lines.join(`
|
|
|
9820
9875
|
getEstimatedTokens() {
|
|
9821
9876
|
return this.messages.reduce((sum, m) => sum + this.estimateMessageTokens(m), 0);
|
|
9822
9877
|
}
|
|
9878
|
+
resize(contextWindow, contextBudget, tokenCounter) {
|
|
9879
|
+
this.contextWindow = contextWindow;
|
|
9880
|
+
this.budget = this.calculateBudget(contextWindow, contextBudget);
|
|
9881
|
+
if (tokenCounter !== undefined) {
|
|
9882
|
+
this.tokenCounter = tokenCounter ?? null;
|
|
9883
|
+
}
|
|
9884
|
+
}
|
|
9823
9885
|
}
|
|
9824
9886
|
var COMPACTION_INTERVAL = 15, KEEP_LAST_N = 6;
|
|
9825
9887
|
var init_manager = () => {};
|
|
@@ -10354,7 +10416,10 @@ var init_web_search = __esm(() => {
|
|
|
10354
10416
|
type: "object",
|
|
10355
10417
|
properties: {
|
|
10356
10418
|
query: { type: "string", description: "Search query" },
|
|
10357
|
-
numResults: {
|
|
10419
|
+
numResults: {
|
|
10420
|
+
type: "number",
|
|
10421
|
+
description: "Number of results (default 5)"
|
|
10422
|
+
}
|
|
10358
10423
|
},
|
|
10359
10424
|
required: ["query"]
|
|
10360
10425
|
},
|
|
@@ -10372,27 +10437,41 @@ var init_web_search = __esm(() => {
|
|
|
10372
10437
|
};
|
|
10373
10438
|
}
|
|
10374
10439
|
try {
|
|
10375
|
-
const response = await fetch(url, {
|
|
10440
|
+
const response = await fetch(url, {
|
|
10441
|
+
signal: AbortSignal.timeout(securityConfig?.requestTimeout || 1e4)
|
|
10442
|
+
});
|
|
10376
10443
|
const html = await response.text();
|
|
10377
10444
|
const results = [];
|
|
10378
|
-
const snippetRegex = /<a[^>]+class="result__a"[^>]*>([\s\S]*?)<\/a>[\s\S]*?<a[^>]+class="result__snippet"[^>]*>([\s\S]*?)<\/a>/gi;
|
|
10445
|
+
const snippetRegex = /<a[^>]+class="result__a"[^>]*href="([^"]*)"[^>]*>([\s\S]*?)<\/a>[\s\S]*?<a[^>]+class="result__snippet"[^>]*>([\s\S]*?)<\/a>/gi;
|
|
10379
10446
|
let match;
|
|
10380
10447
|
let count = 0;
|
|
10381
10448
|
while ((match = snippetRegex.exec(html)) !== null && count < numResults) {
|
|
10382
|
-
const
|
|
10383
|
-
const
|
|
10384
|
-
|
|
10449
|
+
const href = match[1].trim();
|
|
10450
|
+
const title = match[2].replace(/<[^>]+>/g, "").trim();
|
|
10451
|
+
const snippet = match[3].replace(/<[^>]+>/g, "").trim();
|
|
10452
|
+
results.push(`${count + 1}. ${title}
|
|
10453
|
+
URL: ${href}
|
|
10454
|
+
${snippet}`);
|
|
10385
10455
|
count++;
|
|
10386
10456
|
}
|
|
10387
10457
|
logNetworkRequest(ctx.sessionId, sanitizeUrl(url), true, `Results: ${results.length}`);
|
|
10388
10458
|
if (results.length === 0) {
|
|
10389
10459
|
return { success: true, output: t("tool.no_results", { query }) };
|
|
10390
10460
|
}
|
|
10391
|
-
return {
|
|
10392
|
-
|
|
10461
|
+
return {
|
|
10462
|
+
success: true,
|
|
10463
|
+
output: t("tool.search_results", {
|
|
10464
|
+
query,
|
|
10465
|
+
results: results.join(`
|
|
10466
|
+
`)
|
|
10467
|
+
})
|
|
10468
|
+
};
|
|
10393
10469
|
} catch (err) {
|
|
10394
10470
|
logNetworkRequest(ctx.sessionId, sanitizeUrl(url), false, `Error: ${err.message}`);
|
|
10395
|
-
return {
|
|
10471
|
+
return {
|
|
10472
|
+
success: false,
|
|
10473
|
+
output: t("error.search_failed", { message: err.message })
|
|
10474
|
+
};
|
|
10396
10475
|
}
|
|
10397
10476
|
}
|
|
10398
10477
|
};
|
|
@@ -24150,6 +24229,7 @@ function registerMmaCommands(ctx) {
|
|
|
24150
24229
|
ctx.config.maxToolIterations = answers.maxToolIterations;
|
|
24151
24230
|
ctx.config.locale = answers.locale;
|
|
24152
24231
|
saveConfig(ctx.config, configPath);
|
|
24232
|
+
await ctx.agent.reconfigure(ctx.config);
|
|
24153
24233
|
console.log(pc.green(t("cli.config_saved")));
|
|
24154
24234
|
});
|
|
24155
24235
|
}
|
|
@@ -24180,7 +24260,7 @@ Excluded blocks: ${info.excluded.length}`));
|
|
|
24180
24260
|
name: "provider",
|
|
24181
24261
|
description: t("repl.provider_list"),
|
|
24182
24262
|
usage: t("repl.provider_usage"),
|
|
24183
|
-
action: (args) => {
|
|
24263
|
+
action: async (args) => {
|
|
24184
24264
|
const subcmd = args[0];
|
|
24185
24265
|
if (!subcmd || subcmd === "list") {
|
|
24186
24266
|
console.log(`${t("repl.provider_current")} ${ctx.config.provider.type}`);
|
|
@@ -24196,6 +24276,7 @@ Excluded blocks: ${info.excluded.length}`));
|
|
|
24196
24276
|
ctx.config.provider.type = name;
|
|
24197
24277
|
const configPath = join35(homedir16(), ".mma", "config.json");
|
|
24198
24278
|
saveConfig(ctx.config, configPath);
|
|
24279
|
+
await ctx.agent.reconfigure(ctx.config);
|
|
24199
24280
|
console.log(pc.green(t("repl.provider_set", { name })));
|
|
24200
24281
|
return;
|
|
24201
24282
|
}
|
|
@@ -24251,6 +24332,7 @@ Excluded blocks: ${info.excluded.length}`));
|
|
|
24251
24332
|
ctx.config.model = name;
|
|
24252
24333
|
const configPath = join35(homedir16(), ".mma", "config.json");
|
|
24253
24334
|
saveConfig(ctx.config, configPath);
|
|
24335
|
+
await ctx.agent.reconfigure(ctx.config);
|
|
24254
24336
|
console.log(pc.green(t("repl.model_set", { name })));
|
|
24255
24337
|
return;
|
|
24256
24338
|
}
|
|
@@ -24261,7 +24343,7 @@ Excluded blocks: ${info.excluded.length}`));
|
|
|
24261
24343
|
name: "context",
|
|
24262
24344
|
description: t("cli.manage_context"),
|
|
24263
24345
|
usage: "/context <size>",
|
|
24264
|
-
action: (args) => {
|
|
24346
|
+
action: async (args) => {
|
|
24265
24347
|
if (args.length === 0) {
|
|
24266
24348
|
console.log(`/context ${t("repl.context")} ${ctx.config.contextWindow}`);
|
|
24267
24349
|
console.log(`Usage: /context <size> (min 1024)`);
|
|
@@ -24275,6 +24357,7 @@ Excluded blocks: ${info.excluded.length}`));
|
|
|
24275
24357
|
ctx.config.contextWindow = size;
|
|
24276
24358
|
const configPath = join35(homedir16(), ".mma", "config.json");
|
|
24277
24359
|
saveConfig(ctx.config, configPath);
|
|
24360
|
+
await ctx.agent.reconfigure(ctx.config);
|
|
24278
24361
|
console.log(pc.green(t("cli.context_set", { size })));
|
|
24279
24362
|
}
|
|
24280
24363
|
});
|