micro-models-agent 0.29.1 → 0.29.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.
Files changed (2) hide show
  1. package/dist/main.js +77 -16
  2. package/package.json +1 -1
package/dist/main.js CHANGED
@@ -2304,6 +2304,7 @@ var init_en = __esm(() => {
2304
2304
  "error.response_blocked": "Response blocked: {reason}",
2305
2305
  "error.max_iters": "Max iterations ({max}) reached",
2306
2306
  "error.empty_response": "Model returned an empty response after retries",
2307
+ "error.audit_failed": "Task could not be verified as complete: {summary}",
2307
2308
  "error.grep_failed": "Grep failed: {message}",
2308
2309
  "error.search_failed": "Search failed: {message}",
2309
2310
  "error.fetch_failed": "Fetch failed: {message}",
@@ -2448,6 +2449,8 @@ Command: {command}`,
2448
2449
  "plan.step_status": "Step {step}: {status}",
2449
2450
  "plan.no_active": "No active plan",
2450
2451
  "plan.step_not_found": "Step not found",
2452
+ "plan.step_already_done": "Step {step} is already marked done. Stop re-marking it — either continue with the next step or investigate why progress appears stuck.",
2453
+ "plan.order_blocked": 'Cannot mark step {step} done: step {first} ("{desc}") is not finished yet. Complete earlier steps first, or mark step {first} status=skipped if it is not needed.',
2451
2454
  "plan.show_header": "Plan status:",
2452
2455
  "plan.show_empty": "(plan has no steps)",
2453
2456
  "plan.list_header": "Plans:",
@@ -2870,6 +2873,7 @@ var init_ru = __esm(() => {
2870
2873
  "error.response_blocked": "Ответ заблокирован: {reason}",
2871
2874
  "error.max_iters": "Достигнут максимум итераций ({max})",
2872
2875
  "error.empty_response": "Модель вернула пустой ответ после повторных попыток",
2876
+ "error.audit_failed": "Задача не может быть подтверждена как выполненная: {summary}",
2873
2877
  "error.grep_failed": "Ошибка grep: {message}",
2874
2878
  "error.search_failed": "Ошибка поиска: {message}",
2875
2879
  "error.fetch_failed": "Ошибка загрузки: {message}",
@@ -3013,6 +3017,8 @@ var init_ru = __esm(() => {
3013
3017
  "plan.step_status": "Шаг {step}: {status}",
3014
3018
  "plan.no_active": "Нет активного плана",
3015
3019
  "plan.step_not_found": "Шаг не найден",
3020
+ "plan.step_already_done": "Шаг {step} уже отмечен выполненным. Прекратите повторную отметку — переходите к следующему шагу или выясните, почему прогресс заблокирован.",
3021
+ "plan.order_blocked": "Нельзя отметить шаг {step} выполненным: шаг {first} («{desc}») ещё не завершён. Сначала завершите предыдущие шаги или отметьте шаг {first} status=skipped, если он не нужен.",
3016
3022
  "plan.show_header": "Статус плана:",
3017
3023
  "plan.show_empty": "(в плане нет шагов)",
3018
3024
  "plan.list_header": "Планы:",
@@ -7469,7 +7475,7 @@ function emptyCliRunHint(command, output, code) {
7469
7475
  return null;
7470
7476
  return "the command exited 0 but printed NOTHING to stdout. If this should run a CLI program, the file probably has no entry point: read it with read_file and check the code actually calls its main function with command-line arguments (e.g. main(process.argv[2])) and prints results with console.log.";
7471
7477
  }
7472
- var BASH_GRACE_MS = 5000, SPAWN_SETTLE_MS = 100, bashGraceMs, UNIX_TO_WIN_HINTS, UNIX_TO_WIN_TRANSLATE, NEVER_TOOL_CALLS, CLI_FILE_RUN_RE, bashTool;
7478
+ var BASH_GRACE_MS = 5000, SPAWN_SETTLE_MS = 100, bashGraceMs, FAILING_FIRST_WORDS, HARD_BLOCK_THRESHOLD = 3, UNIX_TO_WIN_HINTS, UNIX_TO_WIN_TRANSLATE, NEVER_TOOL_CALLS, CLI_FILE_RUN_RE, bashTool;
7473
7479
  var init_bash = __esm(() => {
7474
7480
  init_command_validator();
7475
7481
  init_audit_log();
@@ -7478,6 +7484,7 @@ var init_bash = __esm(() => {
7478
7484
  init_processes();
7479
7485
  init_i18n();
7480
7486
  bashGraceMs = BASH_GRACE_MS;
7487
+ FAILING_FIRST_WORDS = new Map;
7481
7488
  UNIX_TO_WIN_HINTS = {
7482
7489
  ls: "Use the list_dir tool instead.",
7483
7490
  pwd: "Use the file_info tool instead.",
@@ -7629,13 +7636,22 @@ ${output2}`;
7629
7636
  if (!output2 && code !== 0) {
7630
7637
  output2 = `(exit code ${code})`;
7631
7638
  }
7632
- if (platform2() === "win32" && code !== 0) {
7639
+ if (platform2() === "win32") {
7633
7640
  const firstWord = command.trim().split(/\s+/)[0]?.split(/[\\/]/).pop();
7634
- const hint = firstWord ? UNIX_TO_WIN_HINTS[firstWord] : undefined;
7635
- if (hint) {
7636
- output2 = `${output2}
7641
+ if (firstWord && firstWord in UNIX_TO_WIN_HINTS) {
7642
+ if (code === 0) {
7643
+ FAILING_FIRST_WORDS.delete(firstWord);
7644
+ } else {
7645
+ const failures = (FAILING_FIRST_WORDS.get(firstWord) || 0) + 1;
7646
+ FAILING_FIRST_WORDS.set(firstWord, failures);
7647
+ if (failures >= HARD_BLOCK_THRESHOLD) {
7648
+ output2 = `STOP using "${firstWord}" — it does not work in this cmd.exe shell and has failed ${failures} times in a row. ${UNIX_TO_WIN_HINTS[firstWord]}`;
7649
+ } else {
7650
+ output2 = `${output2}
7637
7651
 
7638
- Hint: "${firstWord}" may not work on Windows. ${hint}`;
7652
+ Hint: "${firstWord}" may not work on Windows. ${UNIX_TO_WIN_HINTS[firstWord]}`;
7653
+ }
7654
+ }
7639
7655
  }
7640
7656
  }
7641
7657
  if (securityConfig?.logCommands) {
@@ -10392,6 +10408,7 @@ ${t("tool.truncated", { tokens: Math.ceil(removedChars / 2) })}`;
10392
10408
  this.abortController = new AbortController;
10393
10409
  let iteration = 0;
10394
10410
  let lastText = "";
10411
+ let lastForcedCompactionIteration = -FORCED_COMPACTION_COOLDOWN;
10395
10412
  let hallucinationRetries = 0;
10396
10413
  let lastToolSignature = "";
10397
10414
  let apiPromptTokens = 0;
@@ -10405,6 +10422,8 @@ ${t("tool.truncated", { tokens: Math.ceil(removedChars / 2) })}`;
10405
10422
  let emptyResponseRetries = 0;
10406
10423
  const MAX_EMPTY_RESPONSE_RETRIES = 2;
10407
10424
  let emptyResponseExhausted = false;
10425
+ let auditFailed = false;
10426
+ let lastAuditSummary = "";
10408
10427
  let repeatedToolCount = 0;
10409
10428
  const MAX_REPEATED_TOOL_CALLS = 2;
10410
10429
  const allToolsForBudget = toolExecutor.getToolDefinitions(this.deps.toolTags);
@@ -10431,7 +10450,8 @@ ${t("tool.truncated", { tokens: Math.ceil(removedChars / 2) })}`;
10431
10450
  const currentTokens = contextManager.getEstimatedTokens();
10432
10451
  const budget2 = contextManager.getBudget();
10433
10452
  const quality = contextManager.getQuality();
10434
- if (quality < QUALITY_TRIGGER_THRESHOLD && contextManager.getCompactionCount() > 0) {
10453
+ if (quality < QUALITY_TRIGGER_THRESHOLD && contextManager.getCompactionCount() > 0 && iteration - lastForcedCompactionIteration >= FORCED_COMPACTION_COOLDOWN) {
10454
+ lastForcedCompactionIteration = iteration;
10435
10455
  contextManager.compact();
10436
10456
  logger.warn(`Low context quality (${quality}%) — forced compaction`);
10437
10457
  slog.logCompaction(`quality-triggered compaction (${quality}% < ${QUALITY_TRIGGER_THRESHOLD}%), iteration ${iteration}`, iteration, currentTokens, budget2.history);
@@ -10794,8 +10814,10 @@ ${warnLine}
10794
10814
  });
10795
10815
  slog.logAudit(audit.summary, iteration);
10796
10816
  auditRetries++;
10817
+ lastAuditSummary = audit.summary;
10797
10818
  if (auditRetries >= MAX_AUDIT_RETRIES || iteration >= config.maxToolIterations - 1) {
10798
- logger.warn(`Final audit still incomplete after ${auditRetries} retries — finishing anyway`);
10819
+ logger.warn(`Final audit still incomplete after ${auditRetries} retries — reporting failure`);
10820
+ auditFailed = true;
10799
10821
  break;
10800
10822
  }
10801
10823
  continue;
@@ -10823,9 +10845,9 @@ ${warnLine}
10823
10845
  };
10824
10846
  }
10825
10847
  return {
10826
- success: emptyResponseExhausted ? false : true,
10848
+ success: emptyResponseExhausted || auditFailed ? false : true,
10827
10849
  text: lastText,
10828
- error: emptyResponseExhausted ? t("error.empty_response") : undefined,
10850
+ error: emptyResponseExhausted ? t("error.empty_response") : auditFailed ? t("error.audit_failed", { summary: lastAuditSummary }) : undefined,
10829
10851
  iterationCount: iteration,
10830
10852
  contextUsed: tokensUsed,
10831
10853
  contextLimit: budget.history,
@@ -10890,7 +10912,7 @@ ${warnLine}
10890
10912
  });
10891
10913
  }
10892
10914
  }
10893
- var TOOL_RESULT_MAX_TOKENS_RATIO = 0.3, TOOL_RESULT_ABSOLUTE_MAX_CHARS = 15000, QUALITY_TRIGGER_THRESHOLD = 40;
10915
+ var TOOL_RESULT_MAX_TOKENS_RATIO = 0.3, TOOL_RESULT_ABSOLUTE_MAX_CHARS = 15000, QUALITY_TRIGGER_THRESHOLD = 40, FORCED_COMPACTION_COOLDOWN = 3;
10894
10916
  var init_agent = __esm(() => {
10895
10917
  init_i18n();
10896
10918
  init_colors();
@@ -10993,7 +11015,8 @@ class ContextManager {
10993
11015
  getQuality() {
10994
11016
  const usedTokens = this.getEstimatedTokens();
10995
11017
  const tokenLoad = Math.max(0, 1 - usedTokens / this.budget.history);
10996
- const compactionLoss = Math.max(0, 1 - this.compactionCount * 0.15);
11018
+ const COMPACTION_PENALTY_FLOOR = 0.5;
11019
+ const compactionLoss = Math.max(COMPACTION_PENALTY_FLOOR, 1 - this.compactionCount * 0.15);
10997
11020
  const msgCount = this.messages.length || 1;
10998
11021
  const errorDensity = Math.max(0, 1 - Math.min(1, this.errorFacts.length / msgCount));
10999
11022
  const freshness = Math.max(0, 1 - this.iterationsSinceCompaction / COMPACTION_INTERVAL);
@@ -11139,6 +11162,9 @@ ${lines.join(`
11139
11162
  const newErrors = [];
11140
11163
  for (const msg of turns) {
11141
11164
  const content = getMessageText(msg.content);
11165
+ if (msg.role === "user" && (content.startsWith("<system-summary>") || content.includes("[Compressed:"))) {
11166
+ continue;
11167
+ }
11142
11168
  if (msg.role === "tool") {
11143
11169
  for (const pattern of filePatterns) {
11144
11170
  for (const match of content.matchAll(pattern)) {
@@ -15592,7 +15618,34 @@ ${display}`,
15592
15618
  };
15593
15619
  }
15594
15620
  if (action === "update" && args.step && this.tracker) {
15595
- this.tracker.updateStepStatus(Number(args.step), args.status || "done");
15621
+ const stepId = Number(args.step);
15622
+ const target = this.tracker.getStep(stepId);
15623
+ if (!target) {
15624
+ return { success: false, output: t("plan.step_not_found") };
15625
+ }
15626
+ const status = String(args.status || "done");
15627
+ if (status === "done" && target.status === "done") {
15628
+ return {
15629
+ success: false,
15630
+ output: t("plan.step_already_done", {
15631
+ step: String(stepId)
15632
+ })
15633
+ };
15634
+ }
15635
+ if (status === "done") {
15636
+ const blockers = this.tracker.getPlan().steps.filter((s) => s.id < stepId && s.status !== "done" && s.status !== "skipped");
15637
+ if (blockers.length > 0) {
15638
+ return {
15639
+ success: false,
15640
+ output: t("plan.order_blocked", {
15641
+ step: String(stepId),
15642
+ first: String(blockers[0].id),
15643
+ desc: blockers[0].description
15644
+ })
15645
+ };
15646
+ }
15647
+ }
15648
+ this.tracker.updateStepStatus(stepId, status);
15596
15649
  if (args.note)
15597
15650
  this.tracker.addNote(Number(args.step), String(args.note));
15598
15651
  this.tracker.syncCurrentStep();
@@ -17016,8 +17069,8 @@ class LspClient {
17016
17069
  }
17017
17070
  });
17018
17071
  return await diagPromise;
17019
- } catch {
17020
- return [];
17072
+ } catch (e) {
17073
+ throw e instanceof Error ? e : new Error(String(e));
17021
17074
  } finally {
17022
17075
  await this.shutdown();
17023
17076
  }
@@ -17249,7 +17302,15 @@ ${items}`;
17249
17302
  [LSP warnings]:
17250
17303
  ${items}`;
17251
17304
  }
17252
- } catch {}
17305
+ } catch (e) {
17306
+ const msg = e instanceof Error ? e.message : String(e);
17307
+ try {
17308
+ _ctx.logger?.warn(`LSP check failed for ${filePath}: ${msg}`);
17309
+ } catch {}
17310
+ result.output += `
17311
+
17312
+ [LSP check failed]: ${msg}`;
17313
+ }
17253
17314
  }
17254
17315
  };
17255
17316
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "micro-models-agent",
3
- "version": "0.29.1",
3
+ "version": "0.29.2",
4
4
  "description": "Micro Models Agent (MMA) — LLM agent harness for small models (Qwen3.5-9B, 32K-64K context)",
5
5
  "type": "module",
6
6
  "bin": {