micro-models-agent 0.50.1 → 0.51.1
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 +360 -77
- package/package.json +1 -1
package/dist/main.js
CHANGED
|
@@ -2276,7 +2276,7 @@ var init_defaults = __esm(() => {
|
|
|
2276
2276
|
baseDelay: 1000,
|
|
2277
2277
|
maxDelay: 30000,
|
|
2278
2278
|
maxStreamRetries: 2,
|
|
2279
|
-
noDataTimeoutMs:
|
|
2279
|
+
noDataTimeoutMs: 180000
|
|
2280
2280
|
},
|
|
2281
2281
|
maxToolIterations: 1000,
|
|
2282
2282
|
stuckThreshold: 6,
|
|
@@ -2388,6 +2388,7 @@ The path was joined onto the working directory because it does not exist as give
|
|
|
2388
2388
|
"file.truncated": `
|
|
2389
2389
|
... (truncated)`,
|
|
2390
2390
|
"file.read_header": "── {path} ({ext}, {total} lines, lines {from}-{to})",
|
|
2391
|
+
"file.read_range": "lines {from}-{to} of {total}",
|
|
2391
2392
|
"file.read_truncated": `
|
|
2392
2393
|
|
|
2393
2394
|
[Truncated: {remaining} more lines. Use read_file with offset={next} to continue]`,
|
|
@@ -2411,7 +2412,10 @@ The path was joined onto the working directory because it does not exist as give
|
|
|
2411
2412
|
"error.llm_retries": "LLM request failed after retries",
|
|
2412
2413
|
"error.llm_429": "Rate limit exceeded (HTTP 429) for {model} on {baseUrl}. The provider is throttling requests — free models are especially strict. Get an API key or switch to a paid/faster model: {baseUrl}",
|
|
2413
2414
|
"error.no_response_body": "No response body stream",
|
|
2414
|
-
"error.llm_stream_idle":
|
|
2415
|
+
"error.llm_stream_idle": 'LLM stream stalled — no data for {timeout}ms. If the provider buffers streaming (e.g. LM Studio) or generates very long tool calls, raise "retry.noDataTimeoutMs" in ~/.mma/config.json (restart required)',
|
|
2416
|
+
"error.llm_stream_idle_toolcall": 'LLM stream stalled after a tool_call started — no data for {timeout}ms. The provider most likely buffers SSE instead of streaming tool-call argument deltas (seen with LM Studio). Raise "retry.noDataTimeoutMs" in ~/.mma/config.json (restart required)',
|
|
2417
|
+
"error.llm_truncated": 'Response hit the completion token limit ({tokens}) and was cut off before any content arrived. Split the task into smaller outputs or raise "maxCompletionTokens" in the config',
|
|
2418
|
+
"error.llm_truncated_toolcall": 'Response hit the completion token limit ({tokens}) in the middle of a tool_call — its arguments were cut off. Write the file in smaller chunks (several write_file/edit_file calls) or raise "maxCompletionTokens" in the config',
|
|
2415
2419
|
"error.llm_timeout": "LLM request timed out ({timeout}ms)",
|
|
2416
2420
|
"env.runtime_node": "Running under Node (v{version}) — clipboard image paste, subagent performance and LSP spawn on Windows degrade. Install Bun (https://bun.sh) for full features.",
|
|
2417
2421
|
"env.runtime_old": "Runtime version {version} is below the required engines {engine}.",
|
|
@@ -2910,6 +2914,7 @@ Use this knowledge to answer the user's question.`,
|
|
|
2910
2914
|
"exec.tool_errors_recovery": "Tool {tool} has failed {count} times in a row. Try an alternative: create files directly via write_file, use a different command, or if nothing works — skip this step via plan update step=N status=skipped with a note explaining why.",
|
|
2911
2915
|
"exec.repetitive_tool": "Called {tool} {count} times with identical arguments and result. Try a different approach — create files directly, change arguments, or check process status via process_log.",
|
|
2912
2916
|
"exec.consecutive_failures_recovery": "{count} consecutive tool failures. Create files directly via write_file instead of terminal commands. Check that dependencies are installed (npm install). Do not run build/tests until all files are created.",
|
|
2917
|
+
"exec.bash_flailing_recovery": "bash failed in {fails} of the last {window} attempts. Stop using shell commands for file operations on this machine — they do not work. Use the dedicated tools instead: read_file (the header shows line counts), write_file, edit_file, file_info (file size), glob/grep for search",
|
|
2913
2918
|
"exec.read_only_loop": "No write/exec for {count} tool calls — the agent is only reading/exploring.",
|
|
2914
2919
|
"exec.read_only_loop_recovery": "{count} consecutive read-only tool calls (read_file/glob/grep/browser) with no writes. STOP exploring and make the edit the task requires: read the file, then call write_file or edit_file. If you cannot finish the task, ask the user instead of re-reading the same files.",
|
|
2915
2920
|
"exec.plan_warning": 'Current plan step {step} is "{description}", but {tool} is being called for files outside this step. Complete the current step first, then call plan update step={step} status=done before moving to the next step.',
|
|
@@ -3103,6 +3108,7 @@ var init_ru = __esm(() => {
|
|
|
3103
3108
|
"file.truncated": `
|
|
3104
3109
|
... (обрезано)`,
|
|
3105
3110
|
"file.read_header": "── {path} ({ext}, {total} строк, строки {from}-{to})",
|
|
3111
|
+
"file.read_range": "строки {from}-{to} из {total}",
|
|
3106
3112
|
"file.read_truncated": `
|
|
3107
3113
|
|
|
3108
3114
|
[Обрезано: ещё {remaining} строк. Продолжите чтение через read_file с offset={next}]`,
|
|
@@ -3126,7 +3132,10 @@ var init_ru = __esm(() => {
|
|
|
3126
3132
|
"error.llm_retries": "Запрос LLM не удался после повторов",
|
|
3127
3133
|
"error.llm_429": "Превышен лимит запросов (HTTP 429) для {model} на {baseUrl}. Провайдер ограничивает трафик — особенно строгие free-модели. Получите API-ключ или переключитесь на платную/быструю модель: {baseUrl}",
|
|
3128
3134
|
"error.no_response_body": "Нет потока тела ответа",
|
|
3129
|
-
"error.llm_stream_idle":
|
|
3135
|
+
"error.llm_stream_idle": 'Поток LLM завис — нет данных {timeout}мс. Если провайдер буферизирует стрим (например, LM Studio) или генерирует очень длинные tool calls, увеличьте "retry.noDataTimeoutMs" в ~/.mma/config.json (нужен рестарт)',
|
|
3136
|
+
"error.llm_stream_idle_toolcall": 'Поток LLM завис после начала tool_call — нет данных {timeout}мс. Скорее всего провайдер буферизирует SSE вместо потоковой передачи аргументов tool_call (наблюдается в LM Studio). Увеличьте "retry.noDataTimeoutMs" в ~/.mma/config.json (нужен рестарт)',
|
|
3137
|
+
"error.llm_truncated": 'Ответ упёрся в лимит токенов генерации ({tokens}) и был обрезан до какого-либо содержимого. Разбейте задачу на меньшие порции вывода или увеличьте "maxCompletionTokens" в конфиге',
|
|
3138
|
+
"error.llm_truncated_toolcall": 'Ответ упёрся в лимит токенов генерации ({tokens}) посреди tool_call — его аргументы обрезаны. Пишите файл частями (несколько вызовов write_file/edit_file) или увеличьте "maxCompletionTokens" в конфиге',
|
|
3130
3139
|
"error.llm_timeout": "Время запроса LLM истекло ({timeout}мс)",
|
|
3131
3140
|
"env.runtime_node": "Запущено под Node (v{version}) — вставка изображений из буфера и LSP на Windows работают урезанно. Установите Bun (https://bun.sh) для полного функционала.",
|
|
3132
3141
|
"env.runtime_old": "Версия рантайма {version} ниже требуемой engines {engine}.",
|
|
@@ -3624,6 +3633,7 @@ var init_ru = __esm(() => {
|
|
|
3624
3633
|
"exec.tool_errors_recovery": "Инструмент {tool} упал {count} раз подряд. Попробуйте альтернативу: создайте файлы напрямую через write_file, используйте другую команду, или пропустите этот шаг через plan update step=N status=skipped с пометкой почему.",
|
|
3625
3634
|
"exec.repetitive_tool": "Инструмент {tool} вызван {count} раз с одинаковыми аргументами и результатом. Попробуйте другой подход — создайте файлы напрямую, измените аргументы или проверьте статус процесса через process_log.",
|
|
3626
3635
|
"exec.consecutive_failures_recovery": "{count} инструментов подряд упали. Создавайте файлы напрямую через write_file вместо команд терминала. Проверьте что зависимости установлены (npm install). Не запускайте сборку/тесты пока не созданы все файлы.",
|
|
3636
|
+
"exec.bash_flailing_recovery": "bash упал в {fails} из последних {window} попыток. Хватит использовать шелл-команды для файловых операций на этой машине — они не работают. Используй специализированные инструменты: read_file (в заголовке число строк), write_file, edit_file, file_info (размер файла), glob/grep для поиска",
|
|
3627
3637
|
"exec.read_only_loop": "Нет записи/выполнения за {count} вызовов — агент только читает/исследует.",
|
|
3628
3638
|
"exec.read_only_loop_recovery": "{count} вызовов только для чтения подряд (read_file/glob/grep/browser) без записи. Хватит исследовать — внесите правку, которую требует задача: прочитайте файл, затем вызовите write_file или edit_file. Если не можете завершить задачу — спросите пользователя, а не перечитывайте одни и те же файлы.",
|
|
3629
3639
|
"exec.plan_warning": 'Текущий шаг плана {step} — "{description}", но вызывается {tool} для файлов вне этого шага. Завершите текущий шаг, вызовите plan update step={step} status=done, затем переходите к следующему.',
|
|
@@ -5344,7 +5354,7 @@ class OpenAICompatProvider {
|
|
|
5344
5354
|
baseDelay: 1000,
|
|
5345
5355
|
maxDelay: 30000,
|
|
5346
5356
|
maxStreamRetries: 2,
|
|
5347
|
-
noDataTimeoutMs:
|
|
5357
|
+
noDataTimeoutMs: 180000
|
|
5348
5358
|
};
|
|
5349
5359
|
this.rateLimiter = createRateLimiter(config.rateLimits);
|
|
5350
5360
|
}
|
|
@@ -5373,7 +5383,7 @@ class OpenAICompatProvider {
|
|
|
5373
5383
|
async* doStream(messages, tools, signal, options) {
|
|
5374
5384
|
const { baseDelay, maxDelay, maxStreamRetries, noDataTimeoutMs } = this.retryConfig;
|
|
5375
5385
|
const streamRetries = maxStreamRetries ?? 2;
|
|
5376
|
-
const idleTimeoutMs = noDataTimeoutMs ??
|
|
5386
|
+
const idleTimeoutMs = noDataTimeoutMs ?? 180000;
|
|
5377
5387
|
for (let attempt = 0;; attempt++) {
|
|
5378
5388
|
let emitted = false;
|
|
5379
5389
|
const onEmit = () => {
|
|
@@ -5397,12 +5407,13 @@ class OpenAICompatProvider {
|
|
|
5397
5407
|
}
|
|
5398
5408
|
}
|
|
5399
5409
|
async* streamOnce(messages, tools, signal, options, onEmit, idleTimeoutMs) {
|
|
5410
|
+
const maxTokens = options?.maxTokens ?? this.config.maxCompletionTokens ?? 4096;
|
|
5400
5411
|
const body = buildRequestBody({
|
|
5401
5412
|
model: this.model,
|
|
5402
5413
|
messages,
|
|
5403
5414
|
tools,
|
|
5404
5415
|
stream: true,
|
|
5405
|
-
maxTokens
|
|
5416
|
+
maxTokens,
|
|
5406
5417
|
reasoningEffort: options?.reasoningEffort
|
|
5407
5418
|
});
|
|
5408
5419
|
const { headers, abortSignal, cleanup, isTimeout, flagTimeout, controller } = this.buildRequestSetup(signal);
|
|
@@ -5440,8 +5451,11 @@ class OpenAICompatProvider {
|
|
|
5440
5451
|
const decoder = new TextDecoder;
|
|
5441
5452
|
let buffer = "";
|
|
5442
5453
|
const toolCallAccs = new Map;
|
|
5454
|
+
let sawToolCallStart = false;
|
|
5443
5455
|
let usage;
|
|
5444
5456
|
let sawDone = false;
|
|
5457
|
+
let lastFinishReason;
|
|
5458
|
+
let sawText = false;
|
|
5445
5459
|
const readIdle = () => new Promise((resolve, reject) => {
|
|
5446
5460
|
const idleTimer = setTimeout(() => {
|
|
5447
5461
|
flagTimeout();
|
|
@@ -5450,13 +5464,13 @@ class OpenAICompatProvider {
|
|
|
5450
5464
|
reader.read().then((result) => {
|
|
5451
5465
|
clearTimeout(idleTimer);
|
|
5452
5466
|
if (isTimeout())
|
|
5453
|
-
reject(new Error(t("error.llm_stream_idle", { timeout: idleTimeoutMs })));
|
|
5467
|
+
reject(new Error(t(sawToolCallStart ? "error.llm_stream_idle_toolcall" : "error.llm_stream_idle", { timeout: idleTimeoutMs })));
|
|
5454
5468
|
else
|
|
5455
5469
|
resolve(result);
|
|
5456
5470
|
}, (err) => {
|
|
5457
5471
|
clearTimeout(idleTimer);
|
|
5458
5472
|
if (isTimeout())
|
|
5459
|
-
reject(new Error(t("error.llm_stream_idle", { timeout: idleTimeoutMs })));
|
|
5473
|
+
reject(new Error(t(sawToolCallStart ? "error.llm_stream_idle_toolcall" : "error.llm_stream_idle", { timeout: idleTimeoutMs })));
|
|
5460
5474
|
else
|
|
5461
5475
|
reject(err);
|
|
5462
5476
|
});
|
|
@@ -5494,11 +5508,14 @@ class OpenAICompatProvider {
|
|
|
5494
5508
|
}
|
|
5495
5509
|
const delta = choice.delta || {};
|
|
5496
5510
|
const finishReason = choice.finish_reason;
|
|
5511
|
+
if (finishReason)
|
|
5512
|
+
lastFinishReason = finishReason;
|
|
5497
5513
|
if (delta.reasoning_content) {
|
|
5498
5514
|
onEmit();
|
|
5499
5515
|
yield { type: "reasoning", content: delta.reasoning_content };
|
|
5500
5516
|
}
|
|
5501
5517
|
if (delta.tool_calls) {
|
|
5518
|
+
sawToolCallStart = true;
|
|
5502
5519
|
for (const tc of delta.tool_calls) {
|
|
5503
5520
|
const idx = tc.index ?? 0;
|
|
5504
5521
|
if (!toolCallAccs.has(idx)) {
|
|
@@ -5516,6 +5533,7 @@ class OpenAICompatProvider {
|
|
|
5516
5533
|
}
|
|
5517
5534
|
if (delta.content) {
|
|
5518
5535
|
onEmit();
|
|
5536
|
+
sawText = true;
|
|
5519
5537
|
yield { type: "text", content: delta.content };
|
|
5520
5538
|
}
|
|
5521
5539
|
if (finishReason === "tool_calls" && toolCallAccs.size > 0) {
|
|
@@ -5541,6 +5559,17 @@ class OpenAICompatProvider {
|
|
|
5541
5559
|
onEmit();
|
|
5542
5560
|
yield { type: "done", usage };
|
|
5543
5561
|
}
|
|
5562
|
+
if (lastFinishReason === "length") {
|
|
5563
|
+
const truncatedToolCall = sawToolCallStart && toolCallAccs.size > 0;
|
|
5564
|
+
if (truncatedToolCall || !sawText) {
|
|
5565
|
+
const err = new Error(t(truncatedToolCall ? "error.llm_truncated_toolcall" : "error.llm_truncated", {
|
|
5566
|
+
tokens: maxTokens
|
|
5567
|
+
}));
|
|
5568
|
+
err.llmTerminal = true;
|
|
5569
|
+
err.recoverableLlm = true;
|
|
5570
|
+
throw err;
|
|
5571
|
+
}
|
|
5572
|
+
}
|
|
5544
5573
|
} finally {
|
|
5545
5574
|
cleanup();
|
|
5546
5575
|
reader.releaseLock();
|
|
@@ -7117,7 +7146,12 @@ var init_read_file = __esm(() => {
|
|
|
7117
7146
|
remaining: String(total - end),
|
|
7118
7147
|
next: String(end + 1)
|
|
7119
7148
|
}) : "";
|
|
7120
|
-
const
|
|
7149
|
+
const fullRead = offset === 1 && end >= total;
|
|
7150
|
+
const display = fullRead ? "" : t("file.read_range", {
|
|
7151
|
+
from: String(offset),
|
|
7152
|
+
to: String(end),
|
|
7153
|
+
total: String(total)
|
|
7154
|
+
});
|
|
7121
7155
|
return {
|
|
7122
7156
|
success: true,
|
|
7123
7157
|
output: `${header}
|
|
@@ -10504,6 +10538,7 @@ class StuckDetector {
|
|
|
10504
10538
|
lastBashOutput = "";
|
|
10505
10539
|
emptyBashRunCount = 0;
|
|
10506
10540
|
readOnlyStreak = 0;
|
|
10541
|
+
bashRecent = [];
|
|
10507
10542
|
errorSignatureCounts = new Map;
|
|
10508
10543
|
searchedErrorSignatures = new Set;
|
|
10509
10544
|
webSearchThreshold;
|
|
@@ -10558,6 +10593,20 @@ class StuckDetector {
|
|
|
10558
10593
|
this.lastBashCommand = command;
|
|
10559
10594
|
this.lastBashOutput = output;
|
|
10560
10595
|
}
|
|
10596
|
+
recordBashAttempt(success) {
|
|
10597
|
+
this.bashRecent.push(success);
|
|
10598
|
+
if (this.bashRecent.length > BASH_FLAIL_WINDOW)
|
|
10599
|
+
this.bashRecent.shift();
|
|
10600
|
+
}
|
|
10601
|
+
hasBashFlailing() {
|
|
10602
|
+
if (this.bashRecent.length < BASH_FLAIL_THRESHOLD)
|
|
10603
|
+
return false;
|
|
10604
|
+
let failures = 0;
|
|
10605
|
+
for (const ok of this.bashRecent)
|
|
10606
|
+
if (!ok)
|
|
10607
|
+
failures++;
|
|
10608
|
+
return failures >= BASH_FLAIL_THRESHOLD;
|
|
10609
|
+
}
|
|
10561
10610
|
getLastBashCommand() {
|
|
10562
10611
|
return this.lastBashCommand;
|
|
10563
10612
|
}
|
|
@@ -10796,6 +10845,8 @@ class StuckDetector {
|
|
|
10796
10845
|
const errorTool = Array.from(this.toolErrors.entries()).find(([_, c]) => c >= this.errorThreshold);
|
|
10797
10846
|
if (errorTool)
|
|
10798
10847
|
return `tool-errors:${errorTool[0]}`;
|
|
10848
|
+
if (this.hasBashFlailing())
|
|
10849
|
+
return "bash-flailing";
|
|
10799
10850
|
if (this.hasConsecutiveFailures())
|
|
10800
10851
|
return "consecutive";
|
|
10801
10852
|
if (this.hasRepetitiveToolCalls())
|
|
@@ -10844,6 +10895,13 @@ class StuckDetector {
|
|
|
10844
10895
|
count: this.consecutiveFailures
|
|
10845
10896
|
});
|
|
10846
10897
|
}
|
|
10898
|
+
if (reason === "bash-flailing") {
|
|
10899
|
+
const fails = this.bashRecent.filter((ok) => !ok).length;
|
|
10900
|
+
return t("exec.bash_flailing_recovery", {
|
|
10901
|
+
fails: String(fails),
|
|
10902
|
+
window: String(this.bashRecent.length)
|
|
10903
|
+
});
|
|
10904
|
+
}
|
|
10847
10905
|
if (reason === "repetitive") {
|
|
10848
10906
|
return this.getRepetitiveToolMessage();
|
|
10849
10907
|
}
|
|
@@ -10860,6 +10918,8 @@ class StuckDetector {
|
|
|
10860
10918
|
const errorTool = Array.from(this.toolErrors.entries()).find(([_, c]) => c >= this.errorThreshold);
|
|
10861
10919
|
if (errorTool)
|
|
10862
10920
|
return "tool-errors";
|
|
10921
|
+
if (this.hasBashFlailing())
|
|
10922
|
+
return "bash-flailing";
|
|
10863
10923
|
if (this.hasConsecutiveFailures())
|
|
10864
10924
|
return "consecutive";
|
|
10865
10925
|
if (this.hasRepetitiveToolCalls())
|
|
@@ -10881,6 +10941,7 @@ class StuckDetector {
|
|
|
10881
10941
|
this.lastBashCommand = "";
|
|
10882
10942
|
this.lastBashOutput = "";
|
|
10883
10943
|
this.emptyBashRunCount = 0;
|
|
10944
|
+
this.bashRecent = [];
|
|
10884
10945
|
this.readOnlyStreak = 0;
|
|
10885
10946
|
this.errorSignatureCounts.clear();
|
|
10886
10947
|
this.searchedErrorSignatures.clear();
|
|
@@ -10897,6 +10958,7 @@ class StuckDetector {
|
|
|
10897
10958
|
this.lastBashCommand = "";
|
|
10898
10959
|
this.lastBashOutput = "";
|
|
10899
10960
|
this.emptyBashRunCount = 0;
|
|
10961
|
+
this.bashRecent = [];
|
|
10900
10962
|
this.errorSignatureCounts.clear();
|
|
10901
10963
|
this.searchedErrorSignatures.clear();
|
|
10902
10964
|
}
|
|
@@ -10912,12 +10974,13 @@ class StuckDetector {
|
|
|
10912
10974
|
this.lastBashCommand = "";
|
|
10913
10975
|
this.lastBashOutput = "";
|
|
10914
10976
|
this.emptyBashRunCount = 0;
|
|
10977
|
+
this.bashRecent = [];
|
|
10915
10978
|
this.readOnlyStreak = 0;
|
|
10916
10979
|
this.errorSignatureCounts.clear();
|
|
10917
10980
|
this.searchedErrorSignatures.clear();
|
|
10918
10981
|
}
|
|
10919
10982
|
}
|
|
10920
|
-
var READ_ONLY_TOOLS, READ_ONLY_LOOP_THRESHOLD = 10, ANSI_RE, ERROR_LOC_RE, SIGNATURE_MAX_CHARS = 120, SEARCHABLE_PATTERNS, RUNTIME_WORDS, FRAMEWORK_WORDS;
|
|
10983
|
+
var READ_ONLY_TOOLS, READ_ONLY_LOOP_THRESHOLD = 10, BASH_FLAIL_WINDOW = 6, BASH_FLAIL_THRESHOLD = 4, ANSI_RE, ERROR_LOC_RE, SIGNATURE_MAX_CHARS = 120, SEARCHABLE_PATTERNS, RUNTIME_WORDS, FRAMEWORK_WORDS;
|
|
10921
10984
|
var init_stuck_detector = __esm(() => {
|
|
10922
10985
|
init_i18n();
|
|
10923
10986
|
READ_ONLY_TOOLS = new Set([
|
|
@@ -12576,16 +12639,41 @@ ${t("tool.truncated", { tokens: Math.ceil(removedChars / 2) })}`;
|
|
|
12576
12639
|
}
|
|
12577
12640
|
contextManager.addMessage({ role: "user", content: input });
|
|
12578
12641
|
slog.logUser(input);
|
|
12579
|
-
|
|
12580
|
-
|
|
12642
|
+
const startedAt = Date.now();
|
|
12643
|
+
let toolCalls = 0;
|
|
12644
|
+
const countTool = (ev) => {
|
|
12645
|
+
if (ev.type === "end")
|
|
12646
|
+
toolCalls++;
|
|
12647
|
+
onTool?.(ev);
|
|
12648
|
+
};
|
|
12649
|
+
const emitTurnEnd = (result, err) => {
|
|
12650
|
+
const interrupted = err instanceof Error && err.name === "AbortError" || this.shutdownRequested;
|
|
12651
|
+
pluginManager.runOnTurnEnd?.({
|
|
12652
|
+
logger,
|
|
12653
|
+
sessionManager: sessionManager?.getActiveMeta(),
|
|
12654
|
+
contextManager
|
|
12655
|
+
}, {
|
|
12656
|
+
success: !!result && result.success !== false && !err,
|
|
12657
|
+
durationMs: Date.now() - startedAt,
|
|
12658
|
+
textLength: (result?.text || "").length,
|
|
12659
|
+
toolCalls,
|
|
12660
|
+
interrupted: interrupted || undefined
|
|
12661
|
+
});
|
|
12662
|
+
};
|
|
12663
|
+
try {
|
|
12664
|
+
const result = config.moe?.enabled === true ? await runWithMoE({
|
|
12581
12665
|
config,
|
|
12582
12666
|
llmProvider,
|
|
12583
12667
|
toolExecutor,
|
|
12584
12668
|
logger,
|
|
12585
12669
|
baseDir: this.deps.baseDir
|
|
12586
|
-
}, input, () => this.executeSingleAgentLoop(input, onChunk, onMeta,
|
|
12670
|
+
}, input, () => this.executeSingleAgentLoop(input, onChunk, onMeta, countTool, onPhase), { onMeta, onTool: countTool, onPhase }) : await this.executeSingleAgentLoop(input, onChunk, onMeta, countTool, onPhase);
|
|
12671
|
+
emitTurnEnd(result);
|
|
12672
|
+
return result;
|
|
12673
|
+
} catch (err) {
|
|
12674
|
+
emitTurnEnd(null, err);
|
|
12675
|
+
throw err;
|
|
12587
12676
|
}
|
|
12588
|
-
return this.executeSingleAgentLoop(input, onChunk, onMeta, onTool, onPhase);
|
|
12589
12677
|
}
|
|
12590
12678
|
async executeSingleAgentLoop(input, onChunk, onMeta, onTool, onPhase) {
|
|
12591
12679
|
const {
|
|
@@ -12626,6 +12714,7 @@ ${t("tool.truncated", { tokens: Math.ceil(removedChars / 2) })}`;
|
|
|
12626
12714
|
let suppressRepetitionRetry = false;
|
|
12627
12715
|
let repeatedToolCount = 0;
|
|
12628
12716
|
const MAX_REPEATED_TOOL_CALLS = 2;
|
|
12717
|
+
let llmErrorRetries = 0;
|
|
12629
12718
|
let allToolsForBudget = toolExecutor.getToolDefinitions(this.deps.toolTags);
|
|
12630
12719
|
let boundedToolNames = new Set(allToolsForBudget.filter((t2) => t2.boundedOutput).map((t2) => t2.name));
|
|
12631
12720
|
let toolTokenEstimate = allToolsForBudget.reduce((sum, t2) => sum + Math.ceil((t2.description.length + JSON.stringify(t2.parameters).length) / 4), 0);
|
|
@@ -12750,6 +12839,17 @@ ${t("tool.truncated", { tokens: Math.ceil(removedChars / 2) })}`;
|
|
|
12750
12839
|
logger.info("LLM call aborted (interrupt)");
|
|
12751
12840
|
break;
|
|
12752
12841
|
}
|
|
12842
|
+
if (err?.recoverableLlm && llmErrorRetries < MAX_LLM_ERROR_RETRIES) {
|
|
12843
|
+
llmErrorRetries++;
|
|
12844
|
+
logger.warn(`Recoverable LLM error, feeding back (${llmErrorRetries}/${MAX_LLM_ERROR_RETRIES}): ${err.message}`);
|
|
12845
|
+
slog.logError(err.message);
|
|
12846
|
+
pluginManager.runOnError({ iteration, logger, contextManager }, err);
|
|
12847
|
+
contextManager.addMessage({
|
|
12848
|
+
role: "user",
|
|
12849
|
+
content: `<system-summary>${err.message}</system-summary>`
|
|
12850
|
+
});
|
|
12851
|
+
continue;
|
|
12852
|
+
}
|
|
12753
12853
|
logger.logLLMResponse(config.model, textContent.length, Date.now() - llmStart, err.message, "agent");
|
|
12754
12854
|
logger.error(`LLM call failed: ${err.message}`);
|
|
12755
12855
|
slog.logError(err.message);
|
|
@@ -13245,7 +13345,7 @@ ${warnLine}
|
|
|
13245
13345
|
});
|
|
13246
13346
|
}
|
|
13247
13347
|
}
|
|
13248
|
-
var TOOL_RESULT_MAX_TOKENS_RATIO = 0.3, TOOL_RESULT_ABSOLUTE_MAX_CHARS = 15000, QUALITY_TRIGGER_THRESHOLD = 40, FORCED_COMPACTION_COOLDOWN = 3;
|
|
13348
|
+
var TOOL_RESULT_MAX_TOKENS_RATIO = 0.3, TOOL_RESULT_ABSOLUTE_MAX_CHARS = 15000, QUALITY_TRIGGER_THRESHOLD = 40, FORCED_COMPACTION_COOLDOWN = 3, MAX_LLM_ERROR_RETRIES = 2;
|
|
13249
13349
|
var init_agent = __esm(() => {
|
|
13250
13350
|
init_manager();
|
|
13251
13351
|
init_i18n();
|
|
@@ -14228,6 +14328,18 @@ var init_checker = __esm(() => {
|
|
|
14228
14328
|
// src/modules/plugins/manager.ts
|
|
14229
14329
|
class PluginManager {
|
|
14230
14330
|
plugins = [];
|
|
14331
|
+
hostBridge = null;
|
|
14332
|
+
setHostBridge(bridge) {
|
|
14333
|
+
this.hostBridge = bridge;
|
|
14334
|
+
}
|
|
14335
|
+
withHost(ctx) {
|
|
14336
|
+
if (!ctx || typeof ctx !== "object")
|
|
14337
|
+
return ctx;
|
|
14338
|
+
if (!this.hostBridge || ctx.hostBridge !== undefined) {
|
|
14339
|
+
return ctx;
|
|
14340
|
+
}
|
|
14341
|
+
return { ...ctx, hostBridge: this.hostBridge };
|
|
14342
|
+
}
|
|
14231
14343
|
register(plugin, source) {
|
|
14232
14344
|
if (source)
|
|
14233
14345
|
plugin.source = source;
|
|
@@ -14266,7 +14378,8 @@ class PluginManager {
|
|
|
14266
14378
|
}
|
|
14267
14379
|
});
|
|
14268
14380
|
}
|
|
14269
|
-
async runOnBeforeTool(
|
|
14381
|
+
async runOnBeforeTool(rawCtx, call) {
|
|
14382
|
+
const ctx = this.withHost(rawCtx);
|
|
14270
14383
|
for (const plugin of this.plugins) {
|
|
14271
14384
|
if (plugin.onBeforeTool) {
|
|
14272
14385
|
try {
|
|
@@ -14278,7 +14391,8 @@ class PluginManager {
|
|
|
14278
14391
|
}
|
|
14279
14392
|
return true;
|
|
14280
14393
|
}
|
|
14281
|
-
async runOnAfterTool(
|
|
14394
|
+
async runOnAfterTool(rawCtx, call, result) {
|
|
14395
|
+
const ctx = this.withHost(rawCtx);
|
|
14282
14396
|
for (const plugin of this.plugins) {
|
|
14283
14397
|
if (plugin.onAfterTool) {
|
|
14284
14398
|
try {
|
|
@@ -14287,7 +14401,8 @@ class PluginManager {
|
|
|
14287
14401
|
}
|
|
14288
14402
|
}
|
|
14289
14403
|
}
|
|
14290
|
-
async runOnError(
|
|
14404
|
+
async runOnError(rawCtx, error) {
|
|
14405
|
+
const ctx = this.withHost(rawCtx);
|
|
14291
14406
|
for (const plugin of this.plugins) {
|
|
14292
14407
|
if (plugin.onError) {
|
|
14293
14408
|
try {
|
|
@@ -14296,7 +14411,8 @@ class PluginManager {
|
|
|
14296
14411
|
}
|
|
14297
14412
|
}
|
|
14298
14413
|
}
|
|
14299
|
-
runOnSessionStart(
|
|
14414
|
+
runOnSessionStart(rawCtx) {
|
|
14415
|
+
const ctx = this.withHost(rawCtx);
|
|
14300
14416
|
for (const plugin of this.plugins) {
|
|
14301
14417
|
if (plugin.onSessionStart) {
|
|
14302
14418
|
try {
|
|
@@ -14305,7 +14421,8 @@ class PluginManager {
|
|
|
14305
14421
|
}
|
|
14306
14422
|
}
|
|
14307
14423
|
}
|
|
14308
|
-
runOnBeforeThink(
|
|
14424
|
+
runOnBeforeThink(rawCtx) {
|
|
14425
|
+
const ctx = this.withHost(rawCtx);
|
|
14309
14426
|
for (const plugin of this.plugins) {
|
|
14310
14427
|
if (plugin.onBeforeThink) {
|
|
14311
14428
|
try {
|
|
@@ -14314,7 +14431,8 @@ class PluginManager {
|
|
|
14314
14431
|
}
|
|
14315
14432
|
}
|
|
14316
14433
|
}
|
|
14317
|
-
runOnAfterThink(
|
|
14434
|
+
runOnAfterThink(rawCtx, response) {
|
|
14435
|
+
const ctx = this.withHost(rawCtx);
|
|
14318
14436
|
for (const plugin of this.plugins) {
|
|
14319
14437
|
if (plugin.onAfterThink) {
|
|
14320
14438
|
try {
|
|
@@ -14323,7 +14441,8 @@ class PluginManager {
|
|
|
14323
14441
|
}
|
|
14324
14442
|
}
|
|
14325
14443
|
}
|
|
14326
|
-
runOnSessionEnd(
|
|
14444
|
+
runOnSessionEnd(rawCtx) {
|
|
14445
|
+
const ctx = this.withHost(rawCtx);
|
|
14327
14446
|
for (const plugin of this.plugins) {
|
|
14328
14447
|
if (plugin.onSessionEnd) {
|
|
14329
14448
|
try {
|
|
@@ -14332,7 +14451,8 @@ class PluginManager {
|
|
|
14332
14451
|
}
|
|
14333
14452
|
}
|
|
14334
14453
|
}
|
|
14335
|
-
runOnToolCall(
|
|
14454
|
+
runOnToolCall(rawCtx) {
|
|
14455
|
+
const ctx = this.withHost(rawCtx);
|
|
14336
14456
|
for (const plugin of this.plugins) {
|
|
14337
14457
|
if (plugin.onToolCall) {
|
|
14338
14458
|
try {
|
|
@@ -14341,7 +14461,8 @@ class PluginManager {
|
|
|
14341
14461
|
}
|
|
14342
14462
|
}
|
|
14343
14463
|
}
|
|
14344
|
-
runOnPhase(
|
|
14464
|
+
runOnPhase(rawCtx, phase) {
|
|
14465
|
+
const ctx = this.withHost(rawCtx);
|
|
14345
14466
|
for (const plugin of this.plugins) {
|
|
14346
14467
|
if (plugin.onPhase) {
|
|
14347
14468
|
try {
|
|
@@ -14350,7 +14471,8 @@ class PluginManager {
|
|
|
14350
14471
|
}
|
|
14351
14472
|
}
|
|
14352
14473
|
}
|
|
14353
|
-
runOnToolStart(
|
|
14474
|
+
runOnToolStart(rawCtx, call) {
|
|
14475
|
+
const ctx = this.withHost(rawCtx);
|
|
14354
14476
|
for (const plugin of this.plugins) {
|
|
14355
14477
|
if (plugin.onToolStart) {
|
|
14356
14478
|
try {
|
|
@@ -14359,7 +14481,8 @@ class PluginManager {
|
|
|
14359
14481
|
}
|
|
14360
14482
|
}
|
|
14361
14483
|
}
|
|
14362
|
-
runOnToolEnd(
|
|
14484
|
+
runOnToolEnd(rawCtx, call, result, durationMs) {
|
|
14485
|
+
const ctx = this.withHost(rawCtx);
|
|
14363
14486
|
for (const plugin of this.plugins) {
|
|
14364
14487
|
if (plugin.onToolEnd) {
|
|
14365
14488
|
try {
|
|
@@ -14368,7 +14491,8 @@ class PluginManager {
|
|
|
14368
14491
|
}
|
|
14369
14492
|
}
|
|
14370
14493
|
}
|
|
14371
|
-
runOnText(
|
|
14494
|
+
runOnText(rawCtx, chunk) {
|
|
14495
|
+
const ctx = this.withHost(rawCtx);
|
|
14372
14496
|
for (const plugin of this.plugins) {
|
|
14373
14497
|
if (plugin.onText) {
|
|
14374
14498
|
try {
|
|
@@ -14380,7 +14504,8 @@ class PluginManager {
|
|
|
14380
14504
|
}
|
|
14381
14505
|
return chunk;
|
|
14382
14506
|
}
|
|
14383
|
-
runOnMeta(
|
|
14507
|
+
runOnMeta(rawCtx, chunk) {
|
|
14508
|
+
const ctx = this.withHost(rawCtx);
|
|
14384
14509
|
for (const plugin of this.plugins) {
|
|
14385
14510
|
if (plugin.onMeta) {
|
|
14386
14511
|
try {
|
|
@@ -14392,6 +14517,16 @@ class PluginManager {
|
|
|
14392
14517
|
}
|
|
14393
14518
|
return chunk;
|
|
14394
14519
|
}
|
|
14520
|
+
runOnTurnEnd(rawCtx, summary) {
|
|
14521
|
+
const ctx = this.withHost(rawCtx);
|
|
14522
|
+
for (const plugin of this.plugins) {
|
|
14523
|
+
if (plugin.onTurnEnd) {
|
|
14524
|
+
try {
|
|
14525
|
+
plugin.onTurnEnd(ctx, summary);
|
|
14526
|
+
} catch {}
|
|
14527
|
+
}
|
|
14528
|
+
}
|
|
14529
|
+
}
|
|
14395
14530
|
}
|
|
14396
14531
|
var init_manager3 = __esm(() => {
|
|
14397
14532
|
init_checker();
|
|
@@ -18072,7 +18207,7 @@ function lintCacheKey(baseDir, lintScript) {
|
|
|
18072
18207
|
return `${baseDir}::${lintScript}`;
|
|
18073
18208
|
}
|
|
18074
18209
|
function isMissingBinaryError(err, combinedOutput) {
|
|
18075
|
-
if (err.status === 127)
|
|
18210
|
+
if (err.status === 127 || err.status === 9009)
|
|
18076
18211
|
return true;
|
|
18077
18212
|
if (err.code === "ENOENT")
|
|
18078
18213
|
return true;
|
|
@@ -18086,24 +18221,43 @@ function contentHash(content) {
|
|
|
18086
18221
|
return String(h);
|
|
18087
18222
|
}
|
|
18088
18223
|
function getWinDecoder() {
|
|
18089
|
-
if (_winDecoder
|
|
18090
|
-
|
|
18091
|
-
|
|
18092
|
-
|
|
18093
|
-
|
|
18094
|
-
|
|
18095
|
-
|
|
18096
|
-
|
|
18097
|
-
|
|
18098
|
-
|
|
18099
|
-
|
|
18100
|
-
|
|
18101
|
-
|
|
18102
|
-
|
|
18103
|
-
|
|
18224
|
+
if (_winDecoder !== undefined)
|
|
18225
|
+
return _winDecoder;
|
|
18226
|
+
if (platform5() !== "win32") {
|
|
18227
|
+
_winDecoder = new TextDecoder("utf-8");
|
|
18228
|
+
return _winDecoder;
|
|
18229
|
+
}
|
|
18230
|
+
let decoder = null;
|
|
18231
|
+
try {
|
|
18232
|
+
const cpOut = execSync("chcp.com", {
|
|
18233
|
+
encoding: "buffer",
|
|
18234
|
+
timeout: 2000,
|
|
18235
|
+
windowsHide: true
|
|
18236
|
+
}).toString("latin1");
|
|
18237
|
+
const m = cpOut.match(/(\d+)/);
|
|
18238
|
+
if (m)
|
|
18239
|
+
decoder = new TextDecoder("ibm" + m[1]);
|
|
18240
|
+
} catch {}
|
|
18241
|
+
if (!decoder) {
|
|
18242
|
+
try {
|
|
18243
|
+
decoder = new TextDecoder("ibm866");
|
|
18244
|
+
} catch {
|
|
18245
|
+
return new TextDecoder("utf-8");
|
|
18104
18246
|
}
|
|
18105
18247
|
}
|
|
18106
|
-
|
|
18248
|
+
_winDecoder = decoder;
|
|
18249
|
+
return _winDecoder;
|
|
18250
|
+
}
|
|
18251
|
+
function decodeOutput(chunks) {
|
|
18252
|
+
const raw = Buffer.concat(chunks);
|
|
18253
|
+
try {
|
|
18254
|
+
return new TextDecoder("utf-8", { fatal: true }).decode(raw);
|
|
18255
|
+
} catch {}
|
|
18256
|
+
try {
|
|
18257
|
+
return getWinDecoder().decode(raw);
|
|
18258
|
+
} catch {
|
|
18259
|
+
return raw.toString("latin1");
|
|
18260
|
+
}
|
|
18107
18261
|
}
|
|
18108
18262
|
|
|
18109
18263
|
class LintOnWritePlugin {
|
|
@@ -18275,14 +18429,13 @@ function runAsync(command, cwd, timeoutMs, signal) {
|
|
|
18275
18429
|
windowsHide: true,
|
|
18276
18430
|
stdio: ["ignore", "pipe", "pipe"]
|
|
18277
18431
|
});
|
|
18278
|
-
|
|
18279
|
-
|
|
18280
|
-
const decoder = getWinDecoder();
|
|
18432
|
+
const utf8Chunks = [];
|
|
18433
|
+
const oemChunks = [];
|
|
18281
18434
|
child.stdout?.on("data", (d) => {
|
|
18282
|
-
|
|
18435
|
+
utf8Chunks.push(Buffer.from(d));
|
|
18283
18436
|
});
|
|
18284
18437
|
child.stderr?.on("data", (d) => {
|
|
18285
|
-
|
|
18438
|
+
oemChunks.push(Buffer.from(d));
|
|
18286
18439
|
});
|
|
18287
18440
|
const timer = setTimeout(() => {
|
|
18288
18441
|
child.kill();
|
|
@@ -18298,7 +18451,7 @@ function runAsync(command, cwd, timeoutMs, signal) {
|
|
|
18298
18451
|
clearTimeout(timer);
|
|
18299
18452
|
signal?.removeEventListener("abort", onAbort);
|
|
18300
18453
|
if (signal?.aborted) {
|
|
18301
|
-
resolve19({ stdout, stderr });
|
|
18454
|
+
resolve19({ stdout: decodeOutput(utf8Chunks), stderr: decodeOutput(oemChunks) });
|
|
18302
18455
|
} else {
|
|
18303
18456
|
reject(err);
|
|
18304
18457
|
}
|
|
@@ -18306,8 +18459,8 @@ function runAsync(command, cwd, timeoutMs, signal) {
|
|
|
18306
18459
|
child.on("close", (code) => {
|
|
18307
18460
|
clearTimeout(timer);
|
|
18308
18461
|
signal?.removeEventListener("abort", onAbort);
|
|
18309
|
-
stdout
|
|
18310
|
-
stderr
|
|
18462
|
+
const stdout = decodeOutput(utf8Chunks);
|
|
18463
|
+
const stderr = decodeOutput(oemChunks);
|
|
18311
18464
|
if (signal?.aborted || code === 0) {
|
|
18312
18465
|
resolve19({ stdout, stderr });
|
|
18313
18466
|
} else {
|
|
@@ -18991,6 +19144,9 @@ Last compile error: ${first[1]}`;
|
|
|
18991
19144
|
}
|
|
18992
19145
|
}
|
|
18993
19146
|
if (!result.success) {
|
|
19147
|
+
if (call.name === "bash") {
|
|
19148
|
+
deps.stuckDetector.recordBashAttempt(false);
|
|
19149
|
+
}
|
|
18994
19150
|
if (call.name === "bash" && platform6() === "win32") {
|
|
18995
19151
|
const cmd = String(call.arguments?.command ?? "");
|
|
18996
19152
|
const forbidden = forbiddenWindowsCommand(cmd);
|
|
@@ -19010,6 +19166,9 @@ Last compile error: ${first[1]}`;
|
|
|
19010
19166
|
}
|
|
19011
19167
|
} else {
|
|
19012
19168
|
deps.stuckDetector.recordToolSuccess();
|
|
19169
|
+
if (call.name === "bash") {
|
|
19170
|
+
deps.stuckDetector.recordBashAttempt(true);
|
|
19171
|
+
}
|
|
19013
19172
|
if (call.name === "bash" && result.success) {
|
|
19014
19173
|
const cmd = String(call.arguments?.command ?? "");
|
|
19015
19174
|
const testRun = detectTestResults(String(result.output ?? ""));
|
|
@@ -33371,8 +33530,9 @@ function stripAnsi2(s) {
|
|
|
33371
33530
|
function charLen(s) {
|
|
33372
33531
|
return Array.from(s).length;
|
|
33373
33532
|
}
|
|
33374
|
-
function wrapLine(line, width) {
|
|
33533
|
+
function wrapLine(line, width, firstRowWidth) {
|
|
33375
33534
|
const w = width > 0 ? width : 80;
|
|
33535
|
+
let limit = firstRowWidth !== undefined && firstRowWidth > 0 ? firstRowWidth : w;
|
|
33376
33536
|
const chars = Array.from(line);
|
|
33377
33537
|
const rows = [];
|
|
33378
33538
|
let start = 0;
|
|
@@ -33387,10 +33547,11 @@ function wrapLine(line, width) {
|
|
|
33387
33547
|
continue;
|
|
33388
33548
|
}
|
|
33389
33549
|
const cw = stringWidth(ch);
|
|
33390
|
-
if (cells + cw >
|
|
33550
|
+
if (cells + cw > limit && cells > 0) {
|
|
33391
33551
|
rows.push({ text: chars.slice(start, i).join(""), charStart: start });
|
|
33392
33552
|
start = i;
|
|
33393
33553
|
cells = cw;
|
|
33554
|
+
limit = w;
|
|
33394
33555
|
} else {
|
|
33395
33556
|
cells += cw;
|
|
33396
33557
|
}
|
|
@@ -33398,10 +33559,10 @@ function wrapLine(line, width) {
|
|
|
33398
33559
|
rows.push({ text: chars.slice(start).join(""), charStart: start });
|
|
33399
33560
|
return rows;
|
|
33400
33561
|
}
|
|
33401
|
-
function buildLayout(lines, width) {
|
|
33562
|
+
function buildLayout(lines, width, firstRowWidth) {
|
|
33402
33563
|
const rows = [];
|
|
33403
33564
|
for (let b = 0;b < lines.length; b++) {
|
|
33404
|
-
for (const r of wrapLine(lines[b], width)) {
|
|
33565
|
+
for (const r of wrapLine(lines[b], width, b === 0 ? firstRowWidth : undefined)) {
|
|
33405
33566
|
rows.push({ bufRow: b, charStart: r.charStart, text: r.text });
|
|
33406
33567
|
}
|
|
33407
33568
|
}
|
|
@@ -33438,6 +33599,7 @@ class LineEditor {
|
|
|
33438
33599
|
input;
|
|
33439
33600
|
output;
|
|
33440
33601
|
onKeyInput;
|
|
33602
|
+
onInterrupt;
|
|
33441
33603
|
promptStr;
|
|
33442
33604
|
completer;
|
|
33443
33605
|
history;
|
|
@@ -33456,11 +33618,15 @@ class LineEditor {
|
|
|
33456
33618
|
rawMode = false;
|
|
33457
33619
|
listeners = {};
|
|
33458
33620
|
prevCursorRow = 0;
|
|
33621
|
+
frameTopAbs = null;
|
|
33622
|
+
dsrPending = false;
|
|
33623
|
+
dsrTail = "";
|
|
33459
33624
|
constructor(opts) {
|
|
33460
33625
|
this.input = opts.input;
|
|
33461
33626
|
this.output = opts.output;
|
|
33462
33627
|
this.promptStr = opts.prompt ?? "";
|
|
33463
33628
|
this.completer = opts.completer;
|
|
33629
|
+
this.onInterrupt = opts.onInterrupt;
|
|
33464
33630
|
this.history = opts.history ?? [];
|
|
33465
33631
|
this.historySize = opts.historySize ?? 50;
|
|
33466
33632
|
if (this.history.length > this.historySize) {
|
|
@@ -33471,6 +33637,7 @@ class LineEditor {
|
|
|
33471
33637
|
if (this.rawMode)
|
|
33472
33638
|
this.input.setRawMode(true);
|
|
33473
33639
|
this.enableTerminalProtocols();
|
|
33640
|
+
this.input.on("data", (buf) => this.consumeDsrReplies(buf.toString("utf-8")));
|
|
33474
33641
|
readline2.emitKeypressEvents(this.input);
|
|
33475
33642
|
this.input.on("keypress", (str, key) => this.onKey(str, key));
|
|
33476
33643
|
} else {
|
|
@@ -33513,7 +33680,7 @@ class LineEditor {
|
|
|
33513
33680
|
this.col = 0;
|
|
33514
33681
|
this.historyIndex = -1;
|
|
33515
33682
|
this.stash = null;
|
|
33516
|
-
this.
|
|
33683
|
+
this.invalidateAnchor();
|
|
33517
33684
|
if (this.input.isTTY)
|
|
33518
33685
|
this.render();
|
|
33519
33686
|
}
|
|
@@ -33523,7 +33690,7 @@ class LineEditor {
|
|
|
33523
33690
|
this.lines = [""];
|
|
33524
33691
|
this.row = 0;
|
|
33525
33692
|
this.col = 0;
|
|
33526
|
-
this.
|
|
33693
|
+
this.invalidateAnchor();
|
|
33527
33694
|
if (this.input.isTTY)
|
|
33528
33695
|
this.render();
|
|
33529
33696
|
}
|
|
@@ -33743,10 +33910,10 @@ class LineEditor {
|
|
|
33743
33910
|
this.commitFrame();
|
|
33744
33911
|
this.output.write(`\r
|
|
33745
33912
|
`);
|
|
33913
|
+
this.invalidateAnchor();
|
|
33746
33914
|
this.lines = [""];
|
|
33747
33915
|
this.row = 0;
|
|
33748
33916
|
this.col = 0;
|
|
33749
|
-
this.prevCursorRow = 0;
|
|
33750
33917
|
cb(answer);
|
|
33751
33918
|
return;
|
|
33752
33919
|
}
|
|
@@ -33763,17 +33930,21 @@ class LineEditor {
|
|
|
33763
33930
|
this.commitFrame();
|
|
33764
33931
|
this.output.write(`\r
|
|
33765
33932
|
`);
|
|
33933
|
+
this.invalidateAnchor();
|
|
33766
33934
|
this.lines = [""];
|
|
33767
33935
|
this.row = 0;
|
|
33768
33936
|
this.col = 0;
|
|
33769
|
-
this.prevCursorRow = 0;
|
|
33770
33937
|
this.emitLine(text);
|
|
33771
33938
|
}
|
|
33772
33939
|
commitFrame() {
|
|
33773
|
-
const layout = this.
|
|
33940
|
+
const layout = this.visibleLayout();
|
|
33941
|
+
const lastLen = charLen(stripAnsi2(layout[layout.length - 1].text));
|
|
33942
|
+
if (this.frameTopAbs !== null) {
|
|
33943
|
+
this.output.write(`\x1B[${this.frameTopAbs + layout.length - 1};${lastLen + 1}H`);
|
|
33944
|
+
return;
|
|
33945
|
+
}
|
|
33774
33946
|
const idx = layoutIndexFor(layout, this.row, this.col);
|
|
33775
33947
|
const rowsDown = layout.length - 1 - idx;
|
|
33776
|
-
const lastLen = charLen(stripAnsi2(layout[layout.length - 1].text));
|
|
33777
33948
|
const out = [];
|
|
33778
33949
|
if (rowsDown > 0)
|
|
33779
33950
|
out.push(`\x1B[${rowsDown}B`);
|
|
@@ -33786,9 +33957,15 @@ class LineEditor {
|
|
|
33786
33957
|
this.lines = [""];
|
|
33787
33958
|
this.row = 0;
|
|
33788
33959
|
this.col = 0;
|
|
33789
|
-
this.
|
|
33960
|
+
this.invalidateAnchor();
|
|
33790
33961
|
this.render();
|
|
33791
|
-
|
|
33962
|
+
if (this.onInterrupt) {
|
|
33963
|
+
this.onInterrupt();
|
|
33964
|
+
return;
|
|
33965
|
+
}
|
|
33966
|
+
if (process.listenerCount("SIGINT") > 0) {
|
|
33967
|
+
process.emit("SIGINT");
|
|
33968
|
+
}
|
|
33792
33969
|
}
|
|
33793
33970
|
ctrlD() {
|
|
33794
33971
|
if (this.lines.length === 1 && this.lines[0] === "") {
|
|
@@ -34055,28 +34232,68 @@ class LineEditor {
|
|
|
34055
34232
|
}
|
|
34056
34233
|
clearScreen() {
|
|
34057
34234
|
this.output.write("\x1B[2J\x1B[H");
|
|
34058
|
-
this.
|
|
34235
|
+
this.invalidateAnchor();
|
|
34059
34236
|
this.render();
|
|
34060
34237
|
}
|
|
34061
34238
|
columns() {
|
|
34062
34239
|
return this.output.columns || 80;
|
|
34063
34240
|
}
|
|
34064
34241
|
layout() {
|
|
34065
|
-
|
|
34242
|
+
const promptWidth = stringWidth(stripAnsi2(this.promptStr));
|
|
34243
|
+
return buildLayout(this.lines, this.columns(), Math.max(1, this.columns() - promptWidth));
|
|
34244
|
+
}
|
|
34245
|
+
screenRows() {
|
|
34246
|
+
const r = this.output.rows;
|
|
34247
|
+
return typeof r === "number" && r > 3 ? r : null;
|
|
34248
|
+
}
|
|
34249
|
+
visibleLayout() {
|
|
34250
|
+
const layout = this.layout();
|
|
34251
|
+
const H = this.screenRows();
|
|
34252
|
+
const maxRows = H ? H - 2 : 0;
|
|
34253
|
+
if (maxRows > 0 && layout.length > maxRows) {
|
|
34254
|
+
return layout.slice(layout.length - maxRows);
|
|
34255
|
+
}
|
|
34256
|
+
return layout;
|
|
34257
|
+
}
|
|
34258
|
+
invalidateAnchor() {
|
|
34259
|
+
this.frameTopAbs = null;
|
|
34260
|
+
this.dsrPending = false;
|
|
34261
|
+
this.dsrTail = "";
|
|
34262
|
+
this.prevCursorRow = 0;
|
|
34263
|
+
}
|
|
34264
|
+
consumeDsrReplies(chunk) {
|
|
34265
|
+
this.dsrTail = (this.dsrTail + chunk).slice(-80);
|
|
34266
|
+
const m = /\x1b\[(\d+);(\d+)R/.exec(this.dsrTail);
|
|
34267
|
+
if (!m)
|
|
34268
|
+
return;
|
|
34269
|
+
this.dsrTail = "";
|
|
34270
|
+
if (!this.dsrPending)
|
|
34271
|
+
return;
|
|
34272
|
+
this.dsrPending = false;
|
|
34273
|
+
const row = Number(m[1]);
|
|
34274
|
+
const idx = Number(m[2]);
|
|
34275
|
+
const top = row - this.prevCursorRow;
|
|
34276
|
+
if (top >= 1)
|
|
34277
|
+
this.frameTopAbs = top;
|
|
34066
34278
|
}
|
|
34067
34279
|
render() {
|
|
34068
34280
|
if (!this.input.isTTY || this.isDone)
|
|
34069
34281
|
return;
|
|
34070
|
-
const layout = this.
|
|
34282
|
+
const layout = this.visibleLayout();
|
|
34071
34283
|
const promptWidth = stringWidth(stripAnsi2(this.promptStr));
|
|
34072
34284
|
const idx = layoutIndexFor(layout, this.row, this.col);
|
|
34073
34285
|
const vcol = visualColAt(layout, idx, this.col);
|
|
34074
34286
|
const rowsAfter = layout.length - idx - 1;
|
|
34075
34287
|
const ccol = (idx === 0 ? promptWidth : 0) + vcol;
|
|
34076
34288
|
const out = [];
|
|
34077
|
-
if (this.
|
|
34289
|
+
if (this.frameTopAbs !== null) {
|
|
34290
|
+
out.push(`\x1B[${this.frameTopAbs};1H`);
|
|
34291
|
+
} else if (this.prevCursorRow > 0) {
|
|
34078
34292
|
out.push(`\x1B[${this.prevCursorRow}A`);
|
|
34079
|
-
|
|
34293
|
+
out.push("\r");
|
|
34294
|
+
} else {
|
|
34295
|
+
out.push("\r");
|
|
34296
|
+
}
|
|
34080
34297
|
for (let i = 0;i < layout.length; i++) {
|
|
34081
34298
|
out.push("\x1B[2K");
|
|
34082
34299
|
if (i === 0)
|
|
@@ -34092,8 +34309,17 @@ class LineEditor {
|
|
|
34092
34309
|
out.push("\r");
|
|
34093
34310
|
if (ccol > 0)
|
|
34094
34311
|
out.push(`\x1B[${ccol}C`);
|
|
34095
|
-
this.prevCursorRow = idx;
|
|
34096
34312
|
this.output.write(out.join(""));
|
|
34313
|
+
if (this.frameTopAbs !== null) {
|
|
34314
|
+
const H = this.screenRows();
|
|
34315
|
+
if (H) {
|
|
34316
|
+
const T = this.frameTopAbs;
|
|
34317
|
+
const L = layout.length;
|
|
34318
|
+
if (T + L - 1 > H)
|
|
34319
|
+
this.frameTopAbs = H - L + 1;
|
|
34320
|
+
}
|
|
34321
|
+
} else if (!this.dsrPending) {}
|
|
34322
|
+
this.prevCursorRow = idx;
|
|
34097
34323
|
}
|
|
34098
34324
|
enableTerminalProtocols() {
|
|
34099
34325
|
this.output.write("\x1B[?2004h");
|
|
@@ -34450,9 +34676,28 @@ init_box();
|
|
|
34450
34676
|
init_table();
|
|
34451
34677
|
init_i18n();
|
|
34452
34678
|
init_prices();
|
|
34679
|
+
import { isAbsolute as isAbsolute4, relative as relative6, sep as sep2 } from "path";
|
|
34453
34680
|
function formatUsd(cost) {
|
|
34454
34681
|
return formatCost(cost);
|
|
34455
34682
|
}
|
|
34683
|
+
var PATH_TOOLS = new Set([
|
|
34684
|
+
"read_file",
|
|
34685
|
+
"write_file",
|
|
34686
|
+
"edit_file",
|
|
34687
|
+
"delete_file",
|
|
34688
|
+
"create_dir",
|
|
34689
|
+
"move_file",
|
|
34690
|
+
"list_dir",
|
|
34691
|
+
"file_info"
|
|
34692
|
+
]);
|
|
34693
|
+
function toDisplayPath(baseDir, p) {
|
|
34694
|
+
if (!baseDir || !isAbsolute4(p))
|
|
34695
|
+
return p;
|
|
34696
|
+
const rel = relative6(baseDir, p);
|
|
34697
|
+
if (!rel || rel.startsWith("..") || isAbsolute4(rel))
|
|
34698
|
+
return p;
|
|
34699
|
+
return rel.split(sep2).join("/");
|
|
34700
|
+
}
|
|
34456
34701
|
var GUTTER = " ";
|
|
34457
34702
|
var BUSY_TOOLS = new Set(["lsp_check"]);
|
|
34458
34703
|
function toolMarker(tool) {
|
|
@@ -34506,6 +34751,7 @@ class Renderer {
|
|
|
34506
34751
|
err;
|
|
34507
34752
|
width;
|
|
34508
34753
|
toolStyle;
|
|
34754
|
+
baseDir;
|
|
34509
34755
|
card = null;
|
|
34510
34756
|
constructor(opts = {}) {
|
|
34511
34757
|
this.rich = opts.rich ?? isRichTerminal();
|
|
@@ -34513,6 +34759,7 @@ class Renderer {
|
|
|
34513
34759
|
this.err = opts.err ?? process.stderr;
|
|
34514
34760
|
this.width = opts.width ?? getTerminalWidth();
|
|
34515
34761
|
this.toolStyle = opts.toolStyle ?? "inline";
|
|
34762
|
+
this.baseDir = opts.baseDir;
|
|
34516
34763
|
this.spinner = new Spinner({
|
|
34517
34764
|
enabled: this.rich && (opts.spinner ?? true),
|
|
34518
34765
|
stream: this.err,
|
|
@@ -34560,7 +34807,8 @@ class Renderer {
|
|
|
34560
34807
|
toolStart(tool, args, stepContext, icon) {
|
|
34561
34808
|
this.endCard();
|
|
34562
34809
|
this.spinner.stop();
|
|
34563
|
-
const
|
|
34810
|
+
const displayArgs = PATH_TOOLS.has(tool) && typeof args.path === "string" ? { ...args, path: toDisplayPath(this.baseDir, args.path) } : args;
|
|
34811
|
+
const summary = summarizeArgs2(displayArgs);
|
|
34564
34812
|
const step = stepContext ? ` ${pc2.cyan(`← ${stepContext}`)}` : "";
|
|
34565
34813
|
const marker = icon || toolMarker(tool);
|
|
34566
34814
|
if (!this.rich) {
|
|
@@ -34862,6 +35110,22 @@ function formatContextBar(used, limit, compactions, quality) {
|
|
|
34862
35110
|
}
|
|
34863
35111
|
return line;
|
|
34864
35112
|
}
|
|
35113
|
+
function createHostBridge(opts) {
|
|
35114
|
+
return {
|
|
35115
|
+
isBusy: opts.isBusy,
|
|
35116
|
+
async submit(text, o) {
|
|
35117
|
+
if (opts.isBusy())
|
|
35118
|
+
throw new Error("agent is busy");
|
|
35119
|
+
for (const url of o?.images ?? [])
|
|
35120
|
+
opts.addPendingImage(url);
|
|
35121
|
+
return opts.runAgent(text);
|
|
35122
|
+
},
|
|
35123
|
+
interrupt() {
|
|
35124
|
+
if (opts.isBusy())
|
|
35125
|
+
opts.interruptRun();
|
|
35126
|
+
}
|
|
35127
|
+
};
|
|
35128
|
+
}
|
|
34865
35129
|
|
|
34866
35130
|
class Repl {
|
|
34867
35131
|
completer = new Completer;
|
|
@@ -34934,6 +35198,19 @@ class Repl {
|
|
|
34934
35198
|
registerAllCommands(this);
|
|
34935
35199
|
this.setupCompleter();
|
|
34936
35200
|
this.setupListeners();
|
|
35201
|
+
if (pluginManager) {
|
|
35202
|
+
pluginManager.setHostBridge(createHostBridge({
|
|
35203
|
+
isBusy: () => this.agentRunning,
|
|
35204
|
+
addPendingImage: (url) => {
|
|
35205
|
+
this.agent.contextManager?.addPendingImage?.({
|
|
35206
|
+
type: "image_url",
|
|
35207
|
+
image_url: { url }
|
|
35208
|
+
});
|
|
35209
|
+
},
|
|
35210
|
+
runAgent: (text) => this.runAgent(text),
|
|
35211
|
+
interruptRun: () => this.agent.shutdown()
|
|
35212
|
+
}));
|
|
35213
|
+
}
|
|
34937
35214
|
}
|
|
34938
35215
|
loadHistory() {
|
|
34939
35216
|
if (existsSync52(this.historyPath)) {
|
|
@@ -35071,7 +35348,10 @@ class Repl {
|
|
|
35071
35348
|
this.rl.onKeyInput = (str, key) => this.handleSpecialKey(str, key);
|
|
35072
35349
|
}
|
|
35073
35350
|
let forceExitTimer = null;
|
|
35074
|
-
|
|
35351
|
+
if (typeof Repl.sigintHandler === "function") {
|
|
35352
|
+
process.removeListener("SIGINT", Repl.sigintHandler);
|
|
35353
|
+
}
|
|
35354
|
+
Repl.sigintHandler = () => {
|
|
35075
35355
|
if (this.agentRunning) {
|
|
35076
35356
|
console.log(pc2.yellow(t("repl.ctrl_c_interrupt")));
|
|
35077
35357
|
this.agent.shutdown();
|
|
@@ -35082,7 +35362,8 @@ class Repl {
|
|
|
35082
35362
|
} else {
|
|
35083
35363
|
process.exit(0);
|
|
35084
35364
|
}
|
|
35085
|
-
}
|
|
35365
|
+
};
|
|
35366
|
+
process.on("SIGINT", Repl.sigintHandler);
|
|
35086
35367
|
}
|
|
35087
35368
|
handleSpecialKey(str, key) {
|
|
35088
35369
|
if (key.name === "escape") {
|
|
@@ -35160,7 +35441,8 @@ ${t("image.clipboard_empty")}`));
|
|
|
35160
35441
|
` + pc2.green(t("repl.agent")));
|
|
35161
35442
|
const renderer = new Renderer({
|
|
35162
35443
|
spinner: this.config.ui?.spinner ?? true,
|
|
35163
|
-
toolStyle: this.config.ui?.toolStyle ?? "inline"
|
|
35444
|
+
toolStyle: this.config.ui?.toolStyle ?? "inline",
|
|
35445
|
+
baseDir: this.baseDir
|
|
35164
35446
|
});
|
|
35165
35447
|
const result = await this.agent.run(input, (c) => renderer.text(c), (m) => renderer.meta(m), (ev) => {
|
|
35166
35448
|
if (ev.type === "start") {
|
|
@@ -35642,7 +35924,7 @@ async function main() {
|
|
|
35642
35924
|
}
|
|
35643
35925
|
if (program2.args.length > 0) {
|
|
35644
35926
|
const prompt = program2.args.join(" ");
|
|
35645
|
-
const { agent, config } = await bootstrap(undefined, projectDir, noAgentsMd, exitOnComplete);
|
|
35927
|
+
const { agent, config, baseDir } = await bootstrap(undefined, projectDir, noAgentsMd, exitOnComplete);
|
|
35646
35928
|
const updater = exitOnComplete ? undefined : startAutoUpdate(config);
|
|
35647
35929
|
if (jsonMode) {
|
|
35648
35930
|
const result2 = await agent.run(prompt);
|
|
@@ -35667,7 +35949,8 @@ async function main() {
|
|
|
35667
35949
|
}
|
|
35668
35950
|
const renderer = new Renderer({
|
|
35669
35951
|
spinner: config.ui?.spinner ?? true,
|
|
35670
|
-
toolStyle: config.ui?.toolStyle ?? "inline"
|
|
35952
|
+
toolStyle: config.ui?.toolStyle ?? "inline",
|
|
35953
|
+
baseDir
|
|
35671
35954
|
});
|
|
35672
35955
|
const result = await agent.run(prompt, (chunk) => renderer.text(chunk), (meta) => renderer.meta(meta), (ev) => {
|
|
35673
35956
|
if (ev.type === "start") {
|