micro-models-agent 2.14.0 → 2.16.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +38 -0
- package/dist/assets/app.js +9 -3
- package/dist/assets/index.html +2 -0
- package/dist/assets/js/dom.js +1 -0
- package/dist/assets/js/feed.js +103 -53
- package/dist/assets/js/format.js +8 -0
- package/dist/assets/js/settings.js +94 -8
- package/dist/assets/js/sidebar.js +198 -5
- package/dist/assets/js/tabs.js +105 -18
- package/dist/assets/styles.css +107 -30
- package/dist/i18n/en.json +30 -1
- package/dist/i18n/ru.json +30 -1
- package/dist/main.js +615 -166
- package/package.json +1 -1
package/dist/main.js
CHANGED
|
@@ -2395,18 +2395,7 @@ var init_defaults = __esm(() => {
|
|
|
2395
2395
|
verbosity: "quiet",
|
|
2396
2396
|
fontSize: "comfortable"
|
|
2397
2397
|
},
|
|
2398
|
-
mcpServers: {
|
|
2399
|
-
context7: {
|
|
2400
|
-
name: "context7",
|
|
2401
|
-
transport: "http",
|
|
2402
|
-
url: "https://mcp.context7.com/mcp",
|
|
2403
|
-
headers: {
|
|
2404
|
-
CONTEXT7_API_KEY: process.env.CONTEXT7_API_KEY || ""
|
|
2405
|
-
},
|
|
2406
|
-
enabled: true,
|
|
2407
|
-
timeout: 30000
|
|
2408
|
-
}
|
|
2409
|
-
},
|
|
2398
|
+
mcpServers: {},
|
|
2410
2399
|
security: DEFAULT_SECURITY_CONFIG,
|
|
2411
2400
|
sessionIsolation: {
|
|
2412
2401
|
enabled: false,
|
|
@@ -3073,6 +3062,9 @@ Available commands:`,
|
|
|
3073
3062
|
"repl.model": "Model:",
|
|
3074
3063
|
"repl.provider": "Provider:",
|
|
3075
3064
|
"repl.context": "Context:",
|
|
3065
|
+
"repl.ctx_part_system": "system",
|
|
3066
|
+
"repl.ctx_part_reserve": "reserve",
|
|
3067
|
+
"repl.ctx_part_history": "history",
|
|
3076
3068
|
"repl.sysprompt_label": "System prompt:",
|
|
3077
3069
|
"repl.sysprompt_size": "{used} / {budget} tokens",
|
|
3078
3070
|
"repl.sysprompt_desc": "System prompt size and blocks (use --full for the text)",
|
|
@@ -3577,6 +3569,8 @@ Updated: {updatedAt}`,
|
|
|
3577
3569
|
"web.sessbar.prev": "previous session",
|
|
3578
3570
|
"web.sessbar.next": "next session",
|
|
3579
3571
|
"web.conn.reconnecting": "reconnecting…",
|
|
3572
|
+
"web.i18n.stale": "translations updated — restart the server",
|
|
3573
|
+
"web.i18n.reload": "reload page",
|
|
3580
3574
|
"web.sidebar.plan": "plan",
|
|
3581
3575
|
"web.sidebar.session": "session",
|
|
3582
3576
|
"web.sidebar.usage": "usage",
|
|
@@ -3607,6 +3601,18 @@ Updated: {updatedAt}`,
|
|
|
3607
3601
|
"web.sidebar.trace_text": "composing… {count} chars",
|
|
3608
3602
|
"web.sidebar.trace_plan": "plan update",
|
|
3609
3603
|
"web.sidebar.trace_question": "question",
|
|
3604
|
+
"web.sidebar.trace_status": "status",
|
|
3605
|
+
"web.sidebar.trace_log": "log · {level}",
|
|
3606
|
+
"web.sidebar.trace_retract": "draft retracted",
|
|
3607
|
+
"web.sidebar.trace_index": "index · {phase}",
|
|
3608
|
+
"web.sidebar.trace_critic": "critic · {status}",
|
|
3609
|
+
"web.sidebar.trace_moe": "moe",
|
|
3610
|
+
"web.sidebar.trace_compaction": "compaction",
|
|
3611
|
+
"web.sidebar.trace_probe": "context probe",
|
|
3612
|
+
"web.sidebar.trace_usage": "llm usage",
|
|
3613
|
+
"web.sidebar.trace_audit": "audit",
|
|
3614
|
+
"web.sidebar.trace_claim": "claim retry · {kind}",
|
|
3615
|
+
"web.sidebar.trace_output": "output",
|
|
3610
3616
|
"web.sidebar.detail_metadata": "metadata",
|
|
3611
3617
|
"web.sidebar.detail_arguments": "arguments",
|
|
3612
3618
|
"web.sidebar.detail_output": "output",
|
|
@@ -3621,6 +3627,10 @@ Updated: {updatedAt}`,
|
|
|
3621
3627
|
"web.sidebar.detail_time": "time",
|
|
3622
3628
|
"web.sidebar.detail_tool_call": "tool call",
|
|
3623
3629
|
"web.sidebar.detail_session": "session",
|
|
3630
|
+
"web.sidebar.detail_turn": "turn",
|
|
3631
|
+
"web.sidebar.detail_iteration": "iteration",
|
|
3632
|
+
"web.sidebar.detail_provenance": "session-log provenance",
|
|
3633
|
+
"web.sidebar.detail_provenance_count": "{n} assistant messages in log",
|
|
3624
3634
|
"web.env.dir": "dir",
|
|
3625
3635
|
"web.env.agents": "AGENTS.md",
|
|
3626
3636
|
"web.env.map": "map",
|
|
@@ -3643,6 +3653,11 @@ Updated: {updatedAt}`,
|
|
|
3643
3653
|
"web.usage.cache": "cache",
|
|
3644
3654
|
"web.usage.cost": "cost",
|
|
3645
3655
|
"web.usage.compactions": "compactions",
|
|
3656
|
+
"web.usage.part_system": "instructions",
|
|
3657
|
+
"web.usage.part_tools": "tools",
|
|
3658
|
+
"web.usage.part_history": "dialogue",
|
|
3659
|
+
"web.usage.part_reserve": "response reserve",
|
|
3660
|
+
"web.usage.part_free": "free",
|
|
3646
3661
|
"web.usage.quality": "quality",
|
|
3647
3662
|
"web.usage.probe": "probe",
|
|
3648
3663
|
"web.usage.probe_loaded": "{actual} loaded",
|
|
@@ -3935,9 +3950,10 @@ Updated: {updatedAt}`,
|
|
|
3935
3950
|
"web.input.shift_enter": "Shift+Enter — newline",
|
|
3936
3951
|
"web.input.esc": "Esc — stop",
|
|
3937
3952
|
"web.input.attach": "Ctrl+V — attach",
|
|
3938
|
-
"web.input.busy": "still working — Esc to stop",
|
|
3939
3953
|
"web.input.send": "send",
|
|
3940
3954
|
"web.input.stop": "stop",
|
|
3955
|
+
"web.input.queued": "queued · position {n}",
|
|
3956
|
+
"web.input.queue_full": "message queue is full — wait for the turn to end",
|
|
3941
3957
|
"web.empty.title": "new chat",
|
|
3942
3958
|
"web.empty.hint": "type a message below · / — commands · model and context are chosen above the input",
|
|
3943
3959
|
"web.attach.title": "attach image",
|
|
@@ -3954,6 +3970,7 @@ Updated: {updatedAt}`,
|
|
|
3954
3970
|
"web.sessions.none_active": "— no active session —",
|
|
3955
3971
|
"web.sessions.none": "— none —",
|
|
3956
3972
|
"web.sessions.delete": "delete",
|
|
3973
|
+
"web.sessions.search": "search sessions…",
|
|
3957
3974
|
"web.sessions.create_failed": "session create failed",
|
|
3958
3975
|
"web.sessions.delete_failed": "delete failed",
|
|
3959
3976
|
"web.sessions.confirm_title": "Delete session?",
|
|
@@ -3966,6 +3983,7 @@ Updated: {updatedAt}`,
|
|
|
3966
3983
|
"web.selectors.switch_busy": "switch in progress, please wait",
|
|
3967
3984
|
"web.selectors.reasoning_off": "off (backend ignores it)",
|
|
3968
3985
|
"web.selectors.no_models": "no models",
|
|
3986
|
+
"web.selectors.search_models": "search models…",
|
|
3969
3987
|
"web.selectors.refresh_list": "↻ refresh list",
|
|
3970
3988
|
"web.selectors.custom": "custom…",
|
|
3971
3989
|
"web.selectors.current": "current",
|
|
@@ -4972,6 +4990,9 @@ var init_ru = __esm(() => {
|
|
|
4972
4990
|
"repl.model": "Модель:",
|
|
4973
4991
|
"repl.provider": "Провайдер:",
|
|
4974
4992
|
"repl.context": "Контекст:",
|
|
4993
|
+
"repl.ctx_part_system": "система",
|
|
4994
|
+
"repl.ctx_part_reserve": "резерв",
|
|
4995
|
+
"repl.ctx_part_history": "история",
|
|
4975
4996
|
"repl.sysprompt_label": "Системный промпт:",
|
|
4976
4997
|
"repl.sysprompt_size": "{used} / {budget} токенов",
|
|
4977
4998
|
"repl.sysprompt_desc": "Размер системного промпта и блоки (текст — через --full)",
|
|
@@ -5483,6 +5504,8 @@ var init_ru = __esm(() => {
|
|
|
5483
5504
|
"web.sessbar.prev": "предыдущая сессия",
|
|
5484
5505
|
"web.sessbar.next": "следующая сессия",
|
|
5485
5506
|
"web.conn.reconnecting": "переподключение…",
|
|
5507
|
+
"web.i18n.stale": "переводы обновлены — перезапустите сервер",
|
|
5508
|
+
"web.i18n.reload": "обновить страницу",
|
|
5486
5509
|
"web.sidebar.plan": "план",
|
|
5487
5510
|
"web.sidebar.session": "сессия",
|
|
5488
5511
|
"web.sidebar.usage": "использование",
|
|
@@ -5513,6 +5536,18 @@ var init_ru = __esm(() => {
|
|
|
5513
5536
|
"web.sidebar.trace_text": "печатает… {count} симв.",
|
|
5514
5537
|
"web.sidebar.trace_plan": "обновление плана",
|
|
5515
5538
|
"web.sidebar.trace_question": "вопрос",
|
|
5539
|
+
"web.sidebar.trace_status": "статус",
|
|
5540
|
+
"web.sidebar.trace_log": "лог · {level}",
|
|
5541
|
+
"web.sidebar.trace_retract": "черновик отозван",
|
|
5542
|
+
"web.sidebar.trace_index": "индекс · {phase}",
|
|
5543
|
+
"web.sidebar.trace_critic": "критик · {status}",
|
|
5544
|
+
"web.sidebar.trace_moe": "moe",
|
|
5545
|
+
"web.sidebar.trace_compaction": "компакция",
|
|
5546
|
+
"web.sidebar.trace_probe": "проба контекста",
|
|
5547
|
+
"web.sidebar.trace_usage": "расход llm",
|
|
5548
|
+
"web.sidebar.trace_audit": "аудит",
|
|
5549
|
+
"web.sidebar.trace_claim": "перепроверка · {kind}",
|
|
5550
|
+
"web.sidebar.trace_output": "вывод",
|
|
5516
5551
|
"web.sidebar.detail_metadata": "метаданные",
|
|
5517
5552
|
"web.sidebar.detail_arguments": "аргументы",
|
|
5518
5553
|
"web.sidebar.detail_output": "вывод",
|
|
@@ -5527,6 +5562,10 @@ var init_ru = __esm(() => {
|
|
|
5527
5562
|
"web.sidebar.detail_time": "время",
|
|
5528
5563
|
"web.sidebar.detail_tool_call": "вызов тула",
|
|
5529
5564
|
"web.sidebar.detail_session": "сессия",
|
|
5565
|
+
"web.sidebar.detail_turn": "ход",
|
|
5566
|
+
"web.sidebar.detail_iteration": "итерация",
|
|
5567
|
+
"web.sidebar.detail_provenance": "сверка с логом",
|
|
5568
|
+
"web.sidebar.detail_provenance_count": "assistant-сообщений в логе: {n}",
|
|
5530
5569
|
"web.env.dir": "директория",
|
|
5531
5570
|
"web.env.agents": "AGENTS.md",
|
|
5532
5571
|
"web.env.map": "карта",
|
|
@@ -5549,6 +5588,11 @@ var init_ru = __esm(() => {
|
|
|
5549
5588
|
"web.usage.cache": "кеш",
|
|
5550
5589
|
"web.usage.cost": "стоимость",
|
|
5551
5590
|
"web.usage.compactions": "сжатия",
|
|
5591
|
+
"web.usage.part_system": "инструкции",
|
|
5592
|
+
"web.usage.part_tools": "инструменты",
|
|
5593
|
+
"web.usage.part_history": "диалог",
|
|
5594
|
+
"web.usage.part_reserve": "резерв ответа",
|
|
5595
|
+
"web.usage.part_free": "свободно",
|
|
5552
5596
|
"web.usage.quality": "качество",
|
|
5553
5597
|
"web.usage.probe": "проб",
|
|
5554
5598
|
"web.usage.probe_loaded": "загружено {actual}",
|
|
@@ -5814,9 +5858,10 @@ var init_ru = __esm(() => {
|
|
|
5814
5858
|
"web.input.shift_enter": "Shift+Enter — новая строка",
|
|
5815
5859
|
"web.input.esc": "Esc — стоп",
|
|
5816
5860
|
"web.input.attach": "Ctrl+V — вложить",
|
|
5817
|
-
"web.input.busy": "ещё работаю — Esc для остановки",
|
|
5818
5861
|
"web.input.send": "отправить",
|
|
5819
5862
|
"web.input.stop": "остановить",
|
|
5863
|
+
"web.input.queued": "в очереди · позиция {n}",
|
|
5864
|
+
"web.input.queue_full": "очередь сообщений полна — дождись конца хода",
|
|
5820
5865
|
"web.empty.title": "новый чат",
|
|
5821
5866
|
"web.empty.hint": "введи сообщение ниже · / — команды · модель и контекст выбираются над полем",
|
|
5822
5867
|
"web.attach.title": "прикрепить изображение",
|
|
@@ -5833,6 +5878,7 @@ var init_ru = __esm(() => {
|
|
|
5833
5878
|
"web.sessions.none_active": "— нет активной сессии —",
|
|
5834
5879
|
"web.sessions.none": "— нет —",
|
|
5835
5880
|
"web.sessions.delete": "удалить",
|
|
5881
|
+
"web.sessions.search": "поиск сессий…",
|
|
5836
5882
|
"web.sessions.create_failed": "не удалось создать сессию",
|
|
5837
5883
|
"web.sessions.delete_failed": "не удалось удалить",
|
|
5838
5884
|
"web.sessions.confirm_title": "Удалить сессию?",
|
|
@@ -5845,6 +5891,7 @@ var init_ru = __esm(() => {
|
|
|
5845
5891
|
"web.selectors.switch_busy": "переключение уже идёт, подождите",
|
|
5846
5892
|
"web.selectors.reasoning_off": "выкл (бэкенд игнорирует)",
|
|
5847
5893
|
"web.selectors.no_models": "нет моделей",
|
|
5894
|
+
"web.selectors.search_models": "поиск моделей…",
|
|
5848
5895
|
"web.selectors.refresh_list": "↻ обновить список",
|
|
5849
5896
|
"web.selectors.custom": "другое…",
|
|
5850
5897
|
"web.selectors.current": "текущее",
|
|
@@ -11093,7 +11140,7 @@ function buildSystemInfo(config, baseDir, profileCompressed) {
|
|
|
11093
11140
|
if (config.autoPlan) {
|
|
11094
11141
|
lines.push(`PLAN (MANDATORY): file creation, package installs, or multi-action tasks MUST create a "plan" BEFORE starting.`);
|
|
11095
11142
|
}
|
|
11096
|
-
lines.push(`Runtime verification: when a bug is described in terms of runtime behavior`, `(what happens when the app runs), reproduce it —`, `run the app / build / browser tool — confirm the fix against actual runtime output`, `before calling "plan_step step=N status=done".`, `Check existing servers first (process_list/process_log): a stale dev server`, `runs the old pipeline and keeps failing after the fix.`, `Restart/kill it (process_kill) and verify the exact endpoint/port reported —`, `a fresh port does NOT prove the user's error is gone.`);
|
|
11143
|
+
lines.push(`Runtime verification: when a bug is described in terms of runtime behavior`, `(what happens when the app runs), reproduce it —`, `run the app / build / browser tool — confirm the fix against actual runtime output`, `before calling "plan_step step=N status=done".`, `Check existing servers first (process_list/process_log): a stale dev server`, `runs the old pipeline and keeps failing after the fix.`, `Restart/kill it (process_kill) and verify the exact endpoint/port reported —`, `a fresh port does NOT prove the user's error is gone.`, `Verification "mma web" servers run isolated (MMA_CONFIG_DIR=<empty tmp dir>) —`, `never verify against the user's live server/sessions/state.`);
|
|
11097
11144
|
const sec = config.security;
|
|
11098
11145
|
if (sec?.enabled) {
|
|
11099
11146
|
const secLines = [
|
|
@@ -14404,6 +14451,40 @@ var init_write_file = __esm(() => {
|
|
|
14404
14451
|
// src/tools/edit-file.ts
|
|
14405
14452
|
import { readFileSync as readFileSync19, writeFileSync as writeFileSync13 } from "fs";
|
|
14406
14453
|
import { resolve as resolve6 } from "path";
|
|
14454
|
+
function spliceNormalized(content, oldStr, newStr) {
|
|
14455
|
+
const normOld = oldStr.replace(/\r\n/g, `
|
|
14456
|
+
`);
|
|
14457
|
+
const norm = [];
|
|
14458
|
+
const map = [];
|
|
14459
|
+
for (let i = 0;i < content.length; i++) {
|
|
14460
|
+
if (content[i] === "\r" && content[i + 1] === `
|
|
14461
|
+
`) {
|
|
14462
|
+
norm.push(`
|
|
14463
|
+
`);
|
|
14464
|
+
map.push(i);
|
|
14465
|
+
i++;
|
|
14466
|
+
} else {
|
|
14467
|
+
norm.push(content[i]);
|
|
14468
|
+
map.push(i);
|
|
14469
|
+
}
|
|
14470
|
+
}
|
|
14471
|
+
const normContent = norm.join("");
|
|
14472
|
+
const idx = normContent.indexOf(normOld);
|
|
14473
|
+
if (idx === -1 || normOld.length === 0)
|
|
14474
|
+
return null;
|
|
14475
|
+
const startOrig = map[idx];
|
|
14476
|
+
const endNorm = idx + normOld.length;
|
|
14477
|
+
const endOrig = endNorm < map.length ? map[endNorm] : content.length;
|
|
14478
|
+
let insert = newStr;
|
|
14479
|
+
if (content.includes(`\r
|
|
14480
|
+
`) && !newStr.includes(`\r
|
|
14481
|
+
`) && newStr.includes(`
|
|
14482
|
+
`)) {
|
|
14483
|
+
insert = newStr.replace(/\n/g, `\r
|
|
14484
|
+
`);
|
|
14485
|
+
}
|
|
14486
|
+
return content.slice(0, startOrig) + insert + content.slice(endOrig);
|
|
14487
|
+
}
|
|
14407
14488
|
var editFileTool;
|
|
14408
14489
|
var init_edit_file = __esm(() => {
|
|
14409
14490
|
init_i18n();
|
|
@@ -14488,13 +14569,19 @@ var init_edit_file = __esm(() => {
|
|
|
14488
14569
|
output: t("file.read_failed", { path, error: errMsg(err) })
|
|
14489
14570
|
};
|
|
14490
14571
|
}
|
|
14491
|
-
|
|
14492
|
-
|
|
14493
|
-
|
|
14494
|
-
|
|
14495
|
-
|
|
14572
|
+
let updated;
|
|
14573
|
+
if (content.includes(oldStr)) {
|
|
14574
|
+
updated = content.replace(oldStr, () => newStr);
|
|
14575
|
+
} else {
|
|
14576
|
+
const spliced = spliceNormalized(content, oldStr, newStr);
|
|
14577
|
+
if (!spliced) {
|
|
14578
|
+
return {
|
|
14579
|
+
success: false,
|
|
14580
|
+
output: t("file.string_not_found", { str: oldStr, path })
|
|
14581
|
+
};
|
|
14582
|
+
}
|
|
14583
|
+
updated = spliced;
|
|
14496
14584
|
}
|
|
14497
|
-
const updated = content.replace(oldStr, () => newStr);
|
|
14498
14585
|
if (securityConfig?.enabled && securityConfig?.contentScan?.enabled) {
|
|
14499
14586
|
const scanResult = scanContent(updated, path, securityConfig.contentScan);
|
|
14500
14587
|
if (!scanResult.allowed) {
|
|
@@ -21460,6 +21547,27 @@ function queueToolImages(sink, images) {
|
|
|
21460
21547
|
}
|
|
21461
21548
|
|
|
21462
21549
|
// src/core/agent/tool-batch.ts
|
|
21550
|
+
function diagnoseRepeatedFailures(tool, headlines) {
|
|
21551
|
+
const genericCause = "Repeated failures suggest a systemic problem (config, environment, or a broken tool), not a one-off";
|
|
21552
|
+
const genericSolution = "Check the error message, verify the tool's dependencies are installed/configured, and consider a different tool";
|
|
21553
|
+
const modelMiss = tool === "bash" ? [/did not match any test files?/i, /no such file/i, /cannot find (the )?path/i] : [];
|
|
21554
|
+
if (headlines.length > 0 && headlines.every((h) => /^\(exit code \d+\)$/.test(h.trim()) || modelMiss.some((re) => re.test(h)))) {
|
|
21555
|
+
return {
|
|
21556
|
+
skip: true,
|
|
21557
|
+
cause: "Model named a wrong target (path/filter); the tool itself works",
|
|
21558
|
+
solution: "Re-check the target path or filter instead of blaming the tool"
|
|
21559
|
+
};
|
|
21560
|
+
}
|
|
21561
|
+
if (tool === "edit_file" && headlines.some((h) => /string not found|не найдена/i.test(h))) {
|
|
21562
|
+
return {
|
|
21563
|
+
skip: false,
|
|
21564
|
+
cause: "Anchor mismatch between the model anchor and file content — often CRLF vs LF line endings or a stale read, not a broken tool",
|
|
21565
|
+
solution: "Re-read the exact block with read_file and retry with a short unique single-line anchor"
|
|
21566
|
+
};
|
|
21567
|
+
}
|
|
21568
|
+
return { skip: false, cause: genericCause, solution: genericSolution };
|
|
21569
|
+
}
|
|
21570
|
+
|
|
21463
21571
|
class ToolBatchExecutor {
|
|
21464
21572
|
deps;
|
|
21465
21573
|
constructor(deps) {
|
|
@@ -21619,15 +21727,22 @@ ${result.diff}
|
|
|
21619
21727
|
this.deps.compactionService.compactAfterTool(state);
|
|
21620
21728
|
if (!result.success && !result.blocked && !infoTools.has(call.name)) {
|
|
21621
21729
|
const key = call.name;
|
|
21622
|
-
const prev = state.toolFailureCounts.get(key) ?? { count: 0, error: "" };
|
|
21730
|
+
const prev = state.toolFailureCounts.get(key) ?? { count: 0, error: "", samples: [] };
|
|
21623
21731
|
prev.count++;
|
|
21624
|
-
|
|
21732
|
+
const errText = String(result.output ?? "");
|
|
21733
|
+
prev.error = errText.slice(0, 200);
|
|
21734
|
+
const headline = errText.split(`
|
|
21735
|
+
`)[0].slice(0, 160).trim();
|
|
21736
|
+
if (headline && !prev.samples.includes(headline) && prev.samples.length < 3) {
|
|
21737
|
+
prev.samples.push(headline);
|
|
21738
|
+
}
|
|
21625
21739
|
state.toolFailureCounts.set(key, prev);
|
|
21626
21740
|
if (prev.count >= MIN_REPEATED_TOOL_FAILURES && !state.memoryRuleRecorded.has(key)) {
|
|
21627
21741
|
state.memoryRuleRecorded.add(key);
|
|
21628
21742
|
const memStore = this.deps.memoryStore;
|
|
21629
|
-
|
|
21630
|
-
|
|
21743
|
+
const diagnosis = diagnoseRepeatedFailures(key, prev.samples);
|
|
21744
|
+
if (memStore && !diagnosis.skip) {
|
|
21745
|
+
memStore.appendRule("errors", `Tool ${key} failed ${prev.count}x (${prev.samples.join(" | ") || prev.error})`, diagnosis.cause, diagnosis.solution);
|
|
21631
21746
|
logger3.diagnostic("warn", `Recorded repeated ${key} failures to memory (${prev.count}x)`);
|
|
21632
21747
|
}
|
|
21633
21748
|
}
|
|
@@ -21704,7 +21819,7 @@ function checkSuccessClaim(response, tools) {
|
|
|
21704
21819
|
return null;
|
|
21705
21820
|
if (HEDGE_RE.test(response))
|
|
21706
21821
|
return null;
|
|
21707
|
-
const recent = tools.filter((t2) => t2.text?.trim()).slice(-EVIDENCE_WINDOW);
|
|
21822
|
+
const recent = tools.filter((t2) => t2.text?.trim() && !BOOKKEEPING_TOOLS.has(t2.name ?? "")).slice(-EVIDENCE_WINDOW);
|
|
21708
21823
|
for (let i = recent.length - 1;i >= 0; i--) {
|
|
21709
21824
|
const entry = recent[i];
|
|
21710
21825
|
const text = entry.text.slice(0, EVIDENCE_TEXT_CAP);
|
|
@@ -21721,11 +21836,12 @@ function checkSuccessClaim(response, tools) {
|
|
|
21721
21836
|
}
|
|
21722
21837
|
return null;
|
|
21723
21838
|
}
|
|
21724
|
-
var WORD = "A-Za-zА-Яа-яЁё0-9_", wb = (body) => new RegExp(`(?<![${WORD}])(?:${body})(?![${WORD}])`, "i"), SUCCESS_CLAIM_RE, HEDGE_RE, FAILURE_SIGNAL_RE, EVIDENCE_WINDOW = 10, EVIDENCE_TEXT_CAP = 400, SNIPPET_MAX_CHARS = 160;
|
|
21839
|
+
var WORD = "A-Za-zА-Яа-яЁё0-9_", wb = (body) => new RegExp(`(?<![${WORD}])(?:${body})(?![${WORD}])`, "i"), SUCCESS_CLAIM_RE, HEDGE_RE, FAILURE_SIGNAL_RE, EVIDENCE_WINDOW = 10, EVIDENCE_TEXT_CAP = 400, SNIPPET_MAX_CHARS = 160, BOOKKEEPING_TOOLS;
|
|
21725
21840
|
var init_success_claim = __esm(() => {
|
|
21726
21841
|
SUCCESS_CLAIM_RE = wb("published|опубликован[а-яё]*|задеплоен[а-яё]*|deployed|shipped|готово|выполнено|завершен[а-яё]*|успешно|success(?:ful(?:ly)?)?|done|completed?|finished|все сделано|всё сделано");
|
|
21727
21842
|
HEDGE_RE = wb("may take|being processed|processing|staged|propagat[a-z]*|in progress|shortly|soon|will appear|несколько минут|обрабатывается|застейджен[а-яё]*|подожд[а-яё]*|проверь[а-яё]* позже|появится|пропагир[а-яё]*|кэш[а-яё]*|cach[a-z]*|обычно|typically");
|
|
21728
21843
|
FAILURE_SIGNAL_RE = new RegExp(`${wb("404|409|40[03]|50\\d|failed|failure|not found|ERR_[A-Z_]+|E(?:404|409|ACCES|PERM|CONNREFUSED|TIMED?OUT)|conflict|denied|ошибка|ошибк[а-яё]*|не найден[а-яё]*|не удалось|отклонено").source}|✗|⛔`, "i");
|
|
21844
|
+
BOOKKEEPING_TOOLS = new Set(["plan", "plan_step", "todo"]);
|
|
21729
21845
|
});
|
|
21730
21846
|
|
|
21731
21847
|
// src/modules/hallucination/artifact-claim.ts
|
|
@@ -22459,6 +22575,7 @@ var init_provider = __esm(() => {
|
|
|
22459
22575
|
|
|
22460
22576
|
// src/modules/critic/evidence.ts
|
|
22461
22577
|
import { readFileSync as readFileSync26 } from "fs";
|
|
22578
|
+
import { execFileSync } from "node:child_process";
|
|
22462
22579
|
import { resolve as resolve15 } from "path";
|
|
22463
22580
|
function isWorkMutation(name) {
|
|
22464
22581
|
return MUTATING_TOOLS.has(name) || name === "bash";
|
|
@@ -22476,6 +22593,10 @@ function buildEvidencePack(input) {
|
|
|
22476
22593
|
if (cmd)
|
|
22477
22594
|
commands.push(cmd);
|
|
22478
22595
|
}
|
|
22596
|
+
if (input.baseDir) {
|
|
22597
|
+
for (const f of gitChangedFiles(input.baseDir))
|
|
22598
|
+
changedFiles.add(f);
|
|
22599
|
+
}
|
|
22479
22600
|
return {
|
|
22480
22601
|
task: input.task,
|
|
22481
22602
|
planSummary: input.planSummary,
|
|
@@ -22500,6 +22621,45 @@ function changedFileOf(ev) {
|
|
|
22500
22621
|
return;
|
|
22501
22622
|
return typeof ev.args?.path === "string" ? ev.args.path : undefined;
|
|
22502
22623
|
}
|
|
22624
|
+
function parsePorcelainLine(line) {
|
|
22625
|
+
if (line.length < 4)
|
|
22626
|
+
return null;
|
|
22627
|
+
let p = line.slice(3).trim();
|
|
22628
|
+
const arrow = p.indexOf(" -> ");
|
|
22629
|
+
if (arrow !== -1)
|
|
22630
|
+
p = p.slice(arrow + 4).trim();
|
|
22631
|
+
if (p.length >= 2 && p.startsWith('"') && p.endsWith('"')) {
|
|
22632
|
+
try {
|
|
22633
|
+
p = JSON.parse(p);
|
|
22634
|
+
} catch {
|
|
22635
|
+
p = p.slice(1, -1);
|
|
22636
|
+
}
|
|
22637
|
+
}
|
|
22638
|
+
return p || null;
|
|
22639
|
+
}
|
|
22640
|
+
function gitChangedFiles(baseDir) {
|
|
22641
|
+
let out;
|
|
22642
|
+
try {
|
|
22643
|
+
out = execFileSync("git", ["status", "--porcelain"], {
|
|
22644
|
+
cwd: resolve15(baseDir),
|
|
22645
|
+
encoding: "utf-8",
|
|
22646
|
+
stdio: ["ignore", "pipe", "ignore"],
|
|
22647
|
+
timeout: 1e4
|
|
22648
|
+
});
|
|
22649
|
+
} catch {
|
|
22650
|
+
return [];
|
|
22651
|
+
}
|
|
22652
|
+
const files = [];
|
|
22653
|
+
for (const line of out.split(`
|
|
22654
|
+
`)) {
|
|
22655
|
+
const p = parsePorcelainLine(line);
|
|
22656
|
+
if (p)
|
|
22657
|
+
files.push(p);
|
|
22658
|
+
if (files.length >= MAX_GIT_FILES)
|
|
22659
|
+
break;
|
|
22660
|
+
}
|
|
22661
|
+
return files;
|
|
22662
|
+
}
|
|
22503
22663
|
function commandOf(ev) {
|
|
22504
22664
|
if (ev.tool !== "bash" || typeof ev.args?.command !== "string")
|
|
22505
22665
|
return;
|
|
@@ -22523,7 +22683,7 @@ function readExcerpts(baseDir, paths) {
|
|
|
22523
22683
|
}
|
|
22524
22684
|
return out;
|
|
22525
22685
|
}
|
|
22526
|
-
var MUTATING_TOOLS, MAX_DIGEST_LINES = 40, MAX_DIGEST_OUTPUT_CHARS = 300, MAX_EXCERPT_FILES = 5, MAX_EXCERPT_CHARS = 1200, MAX_ANSWER_CHARS = 2000;
|
|
22686
|
+
var MUTATING_TOOLS, MAX_DIGEST_LINES = 40, MAX_DIGEST_OUTPUT_CHARS = 300, MAX_EXCERPT_FILES = 5, MAX_EXCERPT_CHARS = 1200, MAX_ANSWER_CHARS = 2000, MAX_GIT_FILES = 20;
|
|
22527
22687
|
var init_evidence = __esm(() => {
|
|
22528
22688
|
init_tool_output();
|
|
22529
22689
|
init_context_log();
|
|
@@ -23660,7 +23820,8 @@ class Agent {
|
|
|
23660
23820
|
costBreakdown: this.costTracker.breakdown(),
|
|
23661
23821
|
cache: cacheStats,
|
|
23662
23822
|
compactionCount: contextManager.getCompactionCount(),
|
|
23663
|
-
contextQuality: contextManager.getQuality()
|
|
23823
|
+
contextQuality: contextManager.getQuality(),
|
|
23824
|
+
contextBreakdown: contextManager.getBreakdown?.()
|
|
23664
23825
|
};
|
|
23665
23826
|
}
|
|
23666
23827
|
return {
|
|
@@ -23678,6 +23839,7 @@ class Agent {
|
|
|
23678
23839
|
cache: cacheStats,
|
|
23679
23840
|
compactionCount: contextManager.getCompactionCount(),
|
|
23680
23841
|
contextQuality: contextManager.getQuality(),
|
|
23842
|
+
contextBreakdown: contextManager.getBreakdown?.(),
|
|
23681
23843
|
llmDurationMs: state.totalLlmDuration
|
|
23682
23844
|
};
|
|
23683
23845
|
}
|
|
@@ -24290,6 +24452,28 @@ ${lines.join(`
|
|
|
24290
24452
|
summary: this.compactedBlock ?? ""
|
|
24291
24453
|
};
|
|
24292
24454
|
}
|
|
24455
|
+
systemTokens() {
|
|
24456
|
+
const sys = this.messages.find((m) => m.role === "system");
|
|
24457
|
+
return sys ? this.estimateMessageTokensCached(sys) : 0;
|
|
24458
|
+
}
|
|
24459
|
+
getBreakdown() {
|
|
24460
|
+
const used = this.getEstimatedTokens();
|
|
24461
|
+
const system = this.systemTokens();
|
|
24462
|
+
const tools = this.toolTokens;
|
|
24463
|
+
const history = Math.max(0, used - system - tools);
|
|
24464
|
+
const b = this.budget;
|
|
24465
|
+
return {
|
|
24466
|
+
system,
|
|
24467
|
+
tools,
|
|
24468
|
+
history,
|
|
24469
|
+
used,
|
|
24470
|
+
systemBudget: b.systemPrompt,
|
|
24471
|
+
historyBudget: b.history,
|
|
24472
|
+
reserve: b.responseReserve,
|
|
24473
|
+
free: Math.max(0, this.contextWindow - used - b.responseReserve),
|
|
24474
|
+
window: this.contextWindow
|
|
24475
|
+
};
|
|
24476
|
+
}
|
|
24293
24477
|
getSnapshot() {
|
|
24294
24478
|
return {
|
|
24295
24479
|
window: this.contextWindow,
|
|
@@ -24299,7 +24483,8 @@ ${lines.join(`
|
|
|
24299
24483
|
messageCount: this.messages.length,
|
|
24300
24484
|
quality: this.getQuality(),
|
|
24301
24485
|
compactionCount: this.compactionCount,
|
|
24302
|
-
iterationsSinceCompaction: this.iterationsSinceCompaction
|
|
24486
|
+
iterationsSinceCompaction: this.iterationsSinceCompaction,
|
|
24487
|
+
breakdown: this.getBreakdown()
|
|
24303
24488
|
};
|
|
24304
24489
|
}
|
|
24305
24490
|
updateSystemPrompt(content) {
|
|
@@ -24504,7 +24689,33 @@ var init_factual = __esm(() => {
|
|
|
24504
24689
|
if (!fp.includes("/") && !fp.includes("\\")) {
|
|
24505
24690
|
return this.bareNameExists(fp);
|
|
24506
24691
|
}
|
|
24507
|
-
return
|
|
24692
|
+
return this.suffixExists(fp);
|
|
24693
|
+
}
|
|
24694
|
+
suffixExists(fp) {
|
|
24695
|
+
const norm = fp.replace(/\\/g, "/");
|
|
24696
|
+
const tail = `/${norm}`;
|
|
24697
|
+
const base = norm.split("/").pop() ?? norm;
|
|
24698
|
+
const fwd = (p) => p.replace(/\\/g, "/");
|
|
24699
|
+
for (const known of this.knownFiles) {
|
|
24700
|
+
if (fwd(known).endsWith(tail))
|
|
24701
|
+
return true;
|
|
24702
|
+
}
|
|
24703
|
+
const checkIndex = () => {
|
|
24704
|
+
for (const full of this.getNameIndex().get(base) ?? []) {
|
|
24705
|
+
if (fwd(full).endsWith(tail))
|
|
24706
|
+
return true;
|
|
24707
|
+
}
|
|
24708
|
+
return false;
|
|
24709
|
+
};
|
|
24710
|
+
if (checkIndex())
|
|
24711
|
+
return true;
|
|
24712
|
+
const now = Date.now();
|
|
24713
|
+
if (now - this.lastRescan < FactualCheck.RESCAN_COOLDOWN_MS)
|
|
24714
|
+
return false;
|
|
24715
|
+
this.lastRescan = now;
|
|
24716
|
+
this.nameCache = null;
|
|
24717
|
+
this.nameCacheTime = 0;
|
|
24718
|
+
return checkIndex();
|
|
24508
24719
|
}
|
|
24509
24720
|
dotfileVariants(fp) {
|
|
24510
24721
|
const variants = [fp];
|
|
@@ -28751,6 +28962,7 @@ function createBrowserTool() {
|
|
|
28751
28962
|
"Do NOT use it for search queries: search engines (Google, Yandex, Bing) block headless browsers with CAPTCHA/429/redirect pages — use the web_search tool for searching.",
|
|
28752
28963
|
"Each snapshot returns: a numbered list of interactive elements, the visible page text (Content section), browser console messages, and network errors.",
|
|
28753
28964
|
"Use the Content section to understand what the page says; use element numbers as targets for click/type.",
|
|
28965
|
+
"Without vision capabilities screenshots return only a text note — verify visuals through snapshot text, and for local web UI prefer DOM/API assertions (fetch /api/* endpoints, grep built assets) over driving the browser.",
|
|
28754
28966
|
"Actions: open (url), click (target), type (target, text), scroll (direction), back, forward, screenshot, snapshot, close, wait (ms)."
|
|
28755
28967
|
].join(" "),
|
|
28756
28968
|
parameters: {
|
|
@@ -32393,11 +32605,26 @@ var init_plan_tool = __esm(() => {
|
|
|
32393
32605
|
});
|
|
32394
32606
|
|
|
32395
32607
|
// src/modules/execution/module.ts
|
|
32396
|
-
import { existsSync as existsSync51, readFileSync as readFileSync37 } from "fs";
|
|
32608
|
+
import { existsSync as existsSync51, readFileSync as readFileSync37, statSync as statSync11 } from "fs";
|
|
32397
32609
|
import { resolve as resolve22 } from "path";
|
|
32398
32610
|
function planPathToken(p) {
|
|
32399
32611
|
return toForwardSlash(p).toLowerCase();
|
|
32400
32612
|
}
|
|
32613
|
+
function provablyStale(resolved, sinceMs) {
|
|
32614
|
+
if (Number.isNaN(sinceMs))
|
|
32615
|
+
return false;
|
|
32616
|
+
for (const r of resolved) {
|
|
32617
|
+
if (!r)
|
|
32618
|
+
return false;
|
|
32619
|
+
try {
|
|
32620
|
+
if (statSync11(r).mtimeMs > sinceMs)
|
|
32621
|
+
return false;
|
|
32622
|
+
} catch {
|
|
32623
|
+
return false;
|
|
32624
|
+
}
|
|
32625
|
+
}
|
|
32626
|
+
return true;
|
|
32627
|
+
}
|
|
32401
32628
|
|
|
32402
32629
|
class ExecutionModule {
|
|
32403
32630
|
name = "execution";
|
|
@@ -32641,6 +32868,8 @@ class ExecutionModule {
|
|
|
32641
32868
|
});
|
|
32642
32869
|
if (empty)
|
|
32643
32870
|
continue;
|
|
32871
|
+
if (provablyStale(resolved, Date.parse(plan.createdAt)))
|
|
32872
|
+
continue;
|
|
32644
32873
|
}
|
|
32645
32874
|
step.status = "done";
|
|
32646
32875
|
step.note = `auto-closed by final audit: ${step.kind === "delete" ? "all named files removed" : "all named files exist with content"} (${tokens.join(", ")})`;
|
|
@@ -32868,6 +33097,11 @@ class ExecutionModule {
|
|
|
32868
33097
|
const satisfied = step.kind === "delete" ? allGone && !allExist : allExist;
|
|
32869
33098
|
if (!satisfied)
|
|
32870
33099
|
return;
|
|
33100
|
+
if (step.kind !== "delete") {
|
|
33101
|
+
const plan = this.tracker?.getPlan();
|
|
33102
|
+
if (plan && provablyStale(resolved, Date.parse(plan.createdAt)))
|
|
33103
|
+
return;
|
|
33104
|
+
}
|
|
32871
33105
|
if (step.kind !== "delete") {
|
|
32872
33106
|
const emptyFiles = [];
|
|
32873
33107
|
for (const r of resolved) {
|
|
@@ -44567,7 +44801,7 @@ var init_loader3 = __esm(() => {
|
|
|
44567
44801
|
});
|
|
44568
44802
|
|
|
44569
44803
|
// src/modules/certification/fact-checker.ts
|
|
44570
|
-
import { existsSync as existsSync56, readFileSync as readFileSync40, statSync as
|
|
44804
|
+
import { existsSync as existsSync56, readFileSync as readFileSync40, statSync as statSync12 } from "fs";
|
|
44571
44805
|
import { join as join50 } from "path";
|
|
44572
44806
|
function checkSandbox(sandboxDir, checks, exitCode, output) {
|
|
44573
44807
|
const failures = [];
|
|
@@ -44613,14 +44847,14 @@ function runCheck2(sandboxDir, check, exitCode, output) {
|
|
|
44613
44847
|
}
|
|
44614
44848
|
function isFile(p) {
|
|
44615
44849
|
try {
|
|
44616
|
-
return existsSync56(p) &&
|
|
44850
|
+
return existsSync56(p) && statSync12(p).isFile();
|
|
44617
44851
|
} catch {
|
|
44618
44852
|
return false;
|
|
44619
44853
|
}
|
|
44620
44854
|
}
|
|
44621
44855
|
function isDir(p) {
|
|
44622
44856
|
try {
|
|
44623
|
-
return existsSync56(p) &&
|
|
44857
|
+
return existsSync56(p) && statSync12(p).isDirectory();
|
|
44624
44858
|
} catch {
|
|
44625
44859
|
return false;
|
|
44626
44860
|
}
|
|
@@ -49242,7 +49476,7 @@ import { homedir as homedir8 } from "os";
|
|
|
49242
49476
|
// src/cli/completer.ts
|
|
49243
49477
|
init_registry2();
|
|
49244
49478
|
init_i18n();
|
|
49245
|
-
import { readdirSync as readdirSync19, statSync as
|
|
49479
|
+
import { readdirSync as readdirSync19, statSync as statSync13 } from "fs";
|
|
49246
49480
|
import { join as join54 } from "path";
|
|
49247
49481
|
function buildSlashCompletions(commands) {
|
|
49248
49482
|
return Array.from(commands.entries()).map(([name, cmd]) => ({
|
|
@@ -49316,7 +49550,7 @@ class FilePathProvider {
|
|
|
49316
49550
|
const matches = [];
|
|
49317
49551
|
for (const entry of entries) {
|
|
49318
49552
|
const entryPath = join54(fullPath, entry);
|
|
49319
|
-
const stat2 =
|
|
49553
|
+
const stat2 = statSync13(entryPath);
|
|
49320
49554
|
const completion = prefix + entry + (stat2.isDirectory() ? "/" : "");
|
|
49321
49555
|
if (completion.startsWith(ctx.partial)) {
|
|
49322
49556
|
matches.push(completion);
|
|
@@ -51320,7 +51554,7 @@ ${divider()}`);
|
|
|
51320
51554
|
row(t("repl.model"), pc.white(this.config.model));
|
|
51321
51555
|
const endpoint = activeProviderEndpoint(this.config.provider);
|
|
51322
51556
|
row(t("repl.provider"), `${endpoint.type} → ${pc.dim(endpoint.baseUrl)}`);
|
|
51323
|
-
row(t("repl.context"), `${pc.white(String(ctx))} ${pc.dim(`(
|
|
51557
|
+
row(t("repl.context"), `${pc.white(String(ctx))} ${pc.dim(`(${t("repl.ctx_part_system")}:${sysBudget} ${t("repl.ctx_part_reserve")}:${resBudget} ${t("repl.ctx_part_history")}:${histBudget})`)}`);
|
|
51324
51558
|
const si = this.agent.getSystemPromptInfo();
|
|
51325
51559
|
row(t("repl.sysprompt_label"), pc.dim(t("repl.sysprompt_size", { used: si.tokenCount, budget: sysBudget })));
|
|
51326
51560
|
if (this.skillsModule) {
|
|
@@ -51544,7 +51778,7 @@ init_output();
|
|
|
51544
51778
|
init_i18n();
|
|
51545
51779
|
init_colors();
|
|
51546
51780
|
import { existsSync as existsSync63 } from "node:fs";
|
|
51547
|
-
import { join as
|
|
51781
|
+
import { join as join61 } from "node:path";
|
|
51548
51782
|
|
|
51549
51783
|
// src/modules/webui/module.ts
|
|
51550
51784
|
init_config2();
|
|
@@ -51945,6 +52179,7 @@ function exportCmd(state, args, out) {
|
|
|
51945
52179
|
|
|
51946
52180
|
// src/modules/webui/limits.ts
|
|
51947
52181
|
var MAX_BODY_BYTES = 24 * 1024 * 1024;
|
|
52182
|
+
var MAX_QUEUE_LENGTH = 5;
|
|
51948
52183
|
|
|
51949
52184
|
// src/modules/webui/state.ts
|
|
51950
52185
|
init_env();
|
|
@@ -51964,6 +52199,8 @@ function createWebUiState() {
|
|
|
51964
52199
|
busy: false,
|
|
51965
52200
|
agentRunning: false,
|
|
51966
52201
|
turnToken: null,
|
|
52202
|
+
turnSeq: 0,
|
|
52203
|
+
pendingQueue: [],
|
|
51967
52204
|
lastPostTs: 0,
|
|
51968
52205
|
minPostIntervalMs: 500,
|
|
51969
52206
|
historyTail: 200,
|
|
@@ -52290,111 +52527,14 @@ function makeForwarder(s, sink = (ev) => broadcast(ev, s), opts = {}) {
|
|
|
52290
52527
|
s.busy = false;
|
|
52291
52528
|
s.agentRunning = false;
|
|
52292
52529
|
s.turnToken = null;
|
|
52293
|
-
|
|
52530
|
+
s.turnSeq += 1;
|
|
52531
|
+
sink({ type: "turn_end", ts: Date.now(), turnSeq: s.turnSeq, ...summary });
|
|
52532
|
+
opts.onQueueDrained?.();
|
|
52294
52533
|
},
|
|
52295
52534
|
flushNow: flush
|
|
52296
52535
|
};
|
|
52297
52536
|
}
|
|
52298
52537
|
|
|
52299
|
-
// src/modules/webui/log-forward.ts
|
|
52300
|
-
init_bus();
|
|
52301
|
-
init_context_log();
|
|
52302
|
-
var FORWARDED = ["info", "warn", "error"];
|
|
52303
|
-
function installOutputForwarding(state, bus = defaultOutputBus) {
|
|
52304
|
-
return bus.subscribe((ev) => {
|
|
52305
|
-
if (!FORWARDED.includes(ev.level))
|
|
52306
|
-
return;
|
|
52307
|
-
broadcast({
|
|
52308
|
-
type: "log",
|
|
52309
|
-
ts: ev.ts,
|
|
52310
|
-
level: ev.level,
|
|
52311
|
-
source: ev.source,
|
|
52312
|
-
text: redactContextSecrets(ev.text),
|
|
52313
|
-
diagnostic: ev.data?.diagnostic === true
|
|
52314
|
-
}, state);
|
|
52315
|
-
});
|
|
52316
|
-
}
|
|
52317
|
-
|
|
52318
|
-
// src/modules/webui/prompt-io.ts
|
|
52319
|
-
init_question();
|
|
52320
|
-
init_approve();
|
|
52321
|
-
var questionSeq = 0;
|
|
52322
|
-
function nextQuestionId() {
|
|
52323
|
-
questionSeq += 1;
|
|
52324
|
-
return `q${Date.now().toString(36)}-${questionSeq}`;
|
|
52325
|
-
}
|
|
52326
|
-
function toIndexes(value) {
|
|
52327
|
-
if (!Array.isArray(value))
|
|
52328
|
-
return [];
|
|
52329
|
-
const out = [];
|
|
52330
|
-
for (const item of value) {
|
|
52331
|
-
const n = typeof item === "number" ? item : Number(item);
|
|
52332
|
-
if (Number.isInteger(n) && n >= -1)
|
|
52333
|
-
out.push(n);
|
|
52334
|
-
}
|
|
52335
|
-
return out;
|
|
52336
|
-
}
|
|
52337
|
-
function toText(value) {
|
|
52338
|
-
if (typeof value === "string")
|
|
52339
|
-
return value;
|
|
52340
|
-
if (value == null)
|
|
52341
|
-
return "";
|
|
52342
|
-
return String(value);
|
|
52343
|
-
}
|
|
52344
|
-
function ask2(state, payload, coerce) {
|
|
52345
|
-
return new Promise((resolve27) => {
|
|
52346
|
-
const id = nextQuestionId();
|
|
52347
|
-
state.pendingQuestions.set(id, (value) => resolve27(coerce(value)));
|
|
52348
|
-
broadcast({ type: "question", ts: Date.now(), id, ...payload }, state);
|
|
52349
|
-
});
|
|
52350
|
-
}
|
|
52351
|
-
function createWebPromptIO(state) {
|
|
52352
|
-
return {
|
|
52353
|
-
askText(question) {
|
|
52354
|
-
return ask2(state, { text: question, kind: "text" }, toText);
|
|
52355
|
-
},
|
|
52356
|
-
askChoice(question, options, opts = {}) {
|
|
52357
|
-
return ask2(state, {
|
|
52358
|
-
text: question,
|
|
52359
|
-
kind: "choice",
|
|
52360
|
-
options: options.map((o) => o.label ?? String(o)),
|
|
52361
|
-
multiple: !!opts.multiple,
|
|
52362
|
-
allowCustom: !!opts.allowCustom
|
|
52363
|
-
}, toIndexes);
|
|
52364
|
-
}
|
|
52365
|
-
};
|
|
52366
|
-
}
|
|
52367
|
-
function resolveAnswer(state, id, value) {
|
|
52368
|
-
const resolver = state.pendingQuestions.get(id);
|
|
52369
|
-
if (!resolver)
|
|
52370
|
-
return false;
|
|
52371
|
-
state.pendingQuestions.delete(id);
|
|
52372
|
-
resolver(value);
|
|
52373
|
-
return true;
|
|
52374
|
-
}
|
|
52375
|
-
function cancelPendingQuestions(state) {
|
|
52376
|
-
const pending = [...state.pendingQuestions.values()];
|
|
52377
|
-
state.pendingQuestions.clear();
|
|
52378
|
-
for (const resolve27 of pending)
|
|
52379
|
-
resolve27(undefined);
|
|
52380
|
-
}
|
|
52381
|
-
function installWebPromptIO(deps) {
|
|
52382
|
-
if (deps.registry) {
|
|
52383
|
-
for (const tool of [questionTool, approveTool]) {
|
|
52384
|
-
if (!deps.registry.has(tool.name))
|
|
52385
|
-
deps.registry.register(tool);
|
|
52386
|
-
}
|
|
52387
|
-
}
|
|
52388
|
-
if (deps.toolCtx)
|
|
52389
|
-
deps.toolCtx.exitOnComplete = false;
|
|
52390
|
-
const io = createWebPromptIO(deps.state);
|
|
52391
|
-
deps.agent.setPromptIO(io);
|
|
52392
|
-
return io;
|
|
52393
|
-
}
|
|
52394
|
-
|
|
52395
|
-
// src/modules/webui/server.ts
|
|
52396
|
-
import { createServer } from "node:http";
|
|
52397
|
-
|
|
52398
52538
|
// src/modules/webui/util.ts
|
|
52399
52539
|
init_context_log();
|
|
52400
52540
|
import { exec } from "node:child_process";
|
|
@@ -52535,6 +52675,32 @@ function readBodyError(req, res, err) {
|
|
|
52535
52675
|
}
|
|
52536
52676
|
sendJson(res, 400, { error: "bad request" });
|
|
52537
52677
|
}
|
|
52678
|
+
function submitTurn(s, bridge, text, images, token = reserveBusy(s)) {
|
|
52679
|
+
broadcast({ type: "state", ts: Date.now(), busy: true, queueLen: s.pendingQueue.length }, s);
|
|
52680
|
+
const run = Promise.resolve(bridge.submit(text, { images }));
|
|
52681
|
+
run.catch((err) => {
|
|
52682
|
+
if (releaseBusy(s, token)) {
|
|
52683
|
+
broadcast({ type: "error", ts: Date.now(), error: scrubError(err) }, s);
|
|
52684
|
+
broadcast({ type: "state", ts: Date.now(), busy: false, queueLen: s.pendingQueue.length }, s);
|
|
52685
|
+
}
|
|
52686
|
+
});
|
|
52687
|
+
}
|
|
52688
|
+
function drainQueueTurn(s) {
|
|
52689
|
+
const bridge = s.bridge;
|
|
52690
|
+
if (!bridge || s.busy || bridge.isBusy())
|
|
52691
|
+
return false;
|
|
52692
|
+
const next = s.pendingQueue.shift();
|
|
52693
|
+
if (!next)
|
|
52694
|
+
return false;
|
|
52695
|
+
submitTurn(s, bridge, next.text, next.images);
|
|
52696
|
+
return true;
|
|
52697
|
+
}
|
|
52698
|
+
function enqueueMessage(s, text, images) {
|
|
52699
|
+
if (s.pendingQueue.length >= MAX_QUEUE_LENGTH)
|
|
52700
|
+
return null;
|
|
52701
|
+
s.pendingQueue.push({ text, images, ts: Date.now() });
|
|
52702
|
+
return s.pendingQueue.length;
|
|
52703
|
+
}
|
|
52538
52704
|
function handleMessagePost(req, res, s) {
|
|
52539
52705
|
if (s.setupRequired) {
|
|
52540
52706
|
sendJson(res, 409, { error: "setup_required" });
|
|
@@ -52545,7 +52711,27 @@ function handleMessagePost(req, res, s) {
|
|
|
52545
52711
|
return;
|
|
52546
52712
|
}
|
|
52547
52713
|
if (s.busy || s.bridge.isBusy()) {
|
|
52548
|
-
|
|
52714
|
+
if (s.minPostIntervalMs > 0 && Date.now() - s.lastPostTs < s.minPostIntervalMs) {
|
|
52715
|
+
sendJson(res, 429, { error: "rate_limited" });
|
|
52716
|
+
return;
|
|
52717
|
+
}
|
|
52718
|
+
readBody(req, s.maxBodyBytes).then((raw) => {
|
|
52719
|
+
const body = parseMessageBody(raw);
|
|
52720
|
+
if ("error" in body) {
|
|
52721
|
+
sendJson(res, 400, { error: body.error });
|
|
52722
|
+
return;
|
|
52723
|
+
}
|
|
52724
|
+
s.lastPostTs = Date.now();
|
|
52725
|
+
const pos = enqueueMessage(s, body.text, body.images);
|
|
52726
|
+
if (pos === null) {
|
|
52727
|
+
sendJson(res, 429, { error: "queue_full" });
|
|
52728
|
+
return;
|
|
52729
|
+
}
|
|
52730
|
+
broadcast({ type: "state", ts: Date.now(), busy: true, queueLen: s.pendingQueue.length }, s);
|
|
52731
|
+
sendJson(res, 202, { ok: true, queued: pos });
|
|
52732
|
+
}).catch((err) => {
|
|
52733
|
+
readBodyError(req, res, err);
|
|
52734
|
+
});
|
|
52549
52735
|
return;
|
|
52550
52736
|
}
|
|
52551
52737
|
if (s.minPostIntervalMs > 0 && Date.now() - s.lastPostTs < s.minPostIntervalMs) {
|
|
@@ -52554,28 +52740,22 @@ function handleMessagePost(req, res, s) {
|
|
|
52554
52740
|
}
|
|
52555
52741
|
const bridge = s.bridge;
|
|
52556
52742
|
const token = reserveBusy(s);
|
|
52557
|
-
broadcast({ type: "state", ts: Date.now(), busy: true }, s);
|
|
52743
|
+
broadcast({ type: "state", ts: Date.now(), busy: true, queueLen: s.pendingQueue.length }, s);
|
|
52558
52744
|
readBody(req, s.maxBodyBytes).then((raw) => {
|
|
52559
52745
|
const body = parseMessageBody(raw);
|
|
52560
52746
|
if ("error" in body) {
|
|
52561
52747
|
if (releaseBusy(s, token)) {
|
|
52562
|
-
broadcast({ type: "state", ts: Date.now(), busy: false }, s);
|
|
52748
|
+
broadcast({ type: "state", ts: Date.now(), busy: false, queueLen: s.pendingQueue.length }, s);
|
|
52563
52749
|
}
|
|
52564
52750
|
sendJson(res, 400, { error: body.error });
|
|
52565
52751
|
return;
|
|
52566
52752
|
}
|
|
52567
52753
|
s.lastPostTs = Date.now();
|
|
52568
|
-
|
|
52569
|
-
run.catch((err) => {
|
|
52570
|
-
if (releaseBusy(s, token)) {
|
|
52571
|
-
broadcast({ type: "error", ts: Date.now(), error: scrubError(err) }, s);
|
|
52572
|
-
broadcast({ type: "state", ts: Date.now(), busy: false }, s);
|
|
52573
|
-
}
|
|
52574
|
-
});
|
|
52754
|
+
submitTurn(s, bridge, body.text, body.images, token);
|
|
52575
52755
|
sendJson(res, 202, { ok: true });
|
|
52576
52756
|
}).catch((err) => {
|
|
52577
52757
|
if (releaseBusy(s, token)) {
|
|
52578
|
-
broadcast({ type: "state", ts: Date.now(), busy: false }, s);
|
|
52758
|
+
broadcast({ type: "state", ts: Date.now(), busy: false, queueLen: s.pendingQueue.length }, s);
|
|
52579
52759
|
}
|
|
52580
52760
|
readBodyError(req, res, err);
|
|
52581
52761
|
});
|
|
@@ -52591,6 +52771,105 @@ function tryOpenBrowser(url) {
|
|
|
52591
52771
|
} catch {}
|
|
52592
52772
|
}
|
|
52593
52773
|
|
|
52774
|
+
// src/modules/webui/log-forward.ts
|
|
52775
|
+
init_bus();
|
|
52776
|
+
init_context_log();
|
|
52777
|
+
var FORWARDED = ["info", "warn", "error"];
|
|
52778
|
+
function installOutputForwarding(state, bus = defaultOutputBus) {
|
|
52779
|
+
return bus.subscribe((ev) => {
|
|
52780
|
+
if (!FORWARDED.includes(ev.level))
|
|
52781
|
+
return;
|
|
52782
|
+
broadcast({
|
|
52783
|
+
type: "log",
|
|
52784
|
+
ts: ev.ts,
|
|
52785
|
+
level: ev.level,
|
|
52786
|
+
source: ev.source,
|
|
52787
|
+
text: redactContextSecrets(ev.text),
|
|
52788
|
+
diagnostic: ev.data?.diagnostic === true
|
|
52789
|
+
}, state);
|
|
52790
|
+
});
|
|
52791
|
+
}
|
|
52792
|
+
|
|
52793
|
+
// src/modules/webui/prompt-io.ts
|
|
52794
|
+
init_question();
|
|
52795
|
+
init_approve();
|
|
52796
|
+
var questionSeq = 0;
|
|
52797
|
+
function nextQuestionId() {
|
|
52798
|
+
questionSeq += 1;
|
|
52799
|
+
return `q${Date.now().toString(36)}-${questionSeq}`;
|
|
52800
|
+
}
|
|
52801
|
+
function toIndexes(value) {
|
|
52802
|
+
if (!Array.isArray(value))
|
|
52803
|
+
return [];
|
|
52804
|
+
const out = [];
|
|
52805
|
+
for (const item of value) {
|
|
52806
|
+
const n = typeof item === "number" ? item : Number(item);
|
|
52807
|
+
if (Number.isInteger(n) && n >= -1)
|
|
52808
|
+
out.push(n);
|
|
52809
|
+
}
|
|
52810
|
+
return out;
|
|
52811
|
+
}
|
|
52812
|
+
function toText(value) {
|
|
52813
|
+
if (typeof value === "string")
|
|
52814
|
+
return value;
|
|
52815
|
+
if (value == null)
|
|
52816
|
+
return "";
|
|
52817
|
+
return String(value);
|
|
52818
|
+
}
|
|
52819
|
+
function ask2(state, payload, coerce) {
|
|
52820
|
+
return new Promise((resolve27) => {
|
|
52821
|
+
const id = nextQuestionId();
|
|
52822
|
+
state.pendingQuestions.set(id, (value) => resolve27(coerce(value)));
|
|
52823
|
+
broadcast({ type: "question", ts: Date.now(), id, ...payload }, state);
|
|
52824
|
+
});
|
|
52825
|
+
}
|
|
52826
|
+
function createWebPromptIO(state) {
|
|
52827
|
+
return {
|
|
52828
|
+
askText(question) {
|
|
52829
|
+
return ask2(state, { text: question, kind: "text" }, toText);
|
|
52830
|
+
},
|
|
52831
|
+
askChoice(question, options, opts = {}) {
|
|
52832
|
+
return ask2(state, {
|
|
52833
|
+
text: question,
|
|
52834
|
+
kind: "choice",
|
|
52835
|
+
options: options.map((o) => o.label ?? String(o)),
|
|
52836
|
+
multiple: !!opts.multiple,
|
|
52837
|
+
allowCustom: !!opts.allowCustom
|
|
52838
|
+
}, toIndexes);
|
|
52839
|
+
}
|
|
52840
|
+
};
|
|
52841
|
+
}
|
|
52842
|
+
function resolveAnswer(state, id, value) {
|
|
52843
|
+
const resolver = state.pendingQuestions.get(id);
|
|
52844
|
+
if (!resolver)
|
|
52845
|
+
return false;
|
|
52846
|
+
state.pendingQuestions.delete(id);
|
|
52847
|
+
resolver(value);
|
|
52848
|
+
return true;
|
|
52849
|
+
}
|
|
52850
|
+
function cancelPendingQuestions(state) {
|
|
52851
|
+
const pending = [...state.pendingQuestions.values()];
|
|
52852
|
+
state.pendingQuestions.clear();
|
|
52853
|
+
for (const resolve27 of pending)
|
|
52854
|
+
resolve27(undefined);
|
|
52855
|
+
}
|
|
52856
|
+
function installWebPromptIO(deps) {
|
|
52857
|
+
if (deps.registry) {
|
|
52858
|
+
for (const tool of [questionTool, approveTool]) {
|
|
52859
|
+
if (!deps.registry.has(tool.name))
|
|
52860
|
+
deps.registry.register(tool);
|
|
52861
|
+
}
|
|
52862
|
+
}
|
|
52863
|
+
if (deps.toolCtx)
|
|
52864
|
+
deps.toolCtx.exitOnComplete = false;
|
|
52865
|
+
const io = createWebPromptIO(deps.state);
|
|
52866
|
+
deps.agent.setPromptIO(io);
|
|
52867
|
+
return io;
|
|
52868
|
+
}
|
|
52869
|
+
|
|
52870
|
+
// src/modules/webui/server.ts
|
|
52871
|
+
import { createServer } from "node:http";
|
|
52872
|
+
|
|
52594
52873
|
// src/modules/webui/body.ts
|
|
52595
52874
|
function parseJsonBody(raw) {
|
|
52596
52875
|
let parsed;
|
|
@@ -52760,10 +53039,28 @@ function handleModelsGet(res, s) {
|
|
|
52760
53039
|
|
|
52761
53040
|
// src/modules/webui/i18n-api.ts
|
|
52762
53041
|
init_i18n();
|
|
53042
|
+
|
|
53043
|
+
// src/modules/webui/i18n-stale.ts
|
|
53044
|
+
import { statSync as statSync14 } from "fs";
|
|
53045
|
+
import { join as join60 } from "path";
|
|
53046
|
+
var serverStartedAt = Date.now();
|
|
53047
|
+
var dictFiles = ["en.json", "ru.json"].map((f) => join60(import.meta.dirname, "..", "..", "i18n", f));
|
|
53048
|
+
function isI18nStale() {
|
|
53049
|
+
for (const p of dictFiles) {
|
|
53050
|
+
try {
|
|
53051
|
+
if (statSync14(p).mtimeMs > serverStartedAt)
|
|
53052
|
+
return true;
|
|
53053
|
+
} catch {}
|
|
53054
|
+
}
|
|
53055
|
+
return false;
|
|
53056
|
+
}
|
|
53057
|
+
|
|
53058
|
+
// src/modules/webui/i18n-api.ts
|
|
52763
53059
|
function handleI18nGet(res, s) {
|
|
52764
53060
|
sendJson(res, 200, {
|
|
52765
53061
|
locale: s.config?.locale ?? "en",
|
|
52766
|
-
dicts: getFlatDicts()
|
|
53062
|
+
dicts: getFlatDicts(),
|
|
53063
|
+
i18nStale: isI18nStale()
|
|
52767
53064
|
});
|
|
52768
53065
|
}
|
|
52769
53066
|
|
|
@@ -52887,6 +53184,134 @@ function handleSessionHistory(res, id, s) {
|
|
|
52887
53184
|
sendJson(res, 200, { id, history: normalizeHistory(log2, s.historyTail, messages) });
|
|
52888
53185
|
}
|
|
52889
53186
|
|
|
53187
|
+
// src/modules/webui/log-api.ts
|
|
53188
|
+
init_context_log();
|
|
53189
|
+
var TRACE_LOG_TYPES = [
|
|
53190
|
+
"assistant",
|
|
53191
|
+
"llm_usage",
|
|
53192
|
+
"compaction",
|
|
53193
|
+
"context_probe",
|
|
53194
|
+
"audit",
|
|
53195
|
+
"moe_plan",
|
|
53196
|
+
"moe_subtask",
|
|
53197
|
+
"moe_replan",
|
|
53198
|
+
"moe_verify",
|
|
53199
|
+
"output",
|
|
53200
|
+
"critic_check",
|
|
53201
|
+
"critic_verdict",
|
|
53202
|
+
"critic_escalation",
|
|
53203
|
+
"claim_retry"
|
|
53204
|
+
];
|
|
53205
|
+
var ALLOWED_TYPES = new Set([
|
|
53206
|
+
...TRACE_LOG_TYPES,
|
|
53207
|
+
"tool_call",
|
|
53208
|
+
"tool_result",
|
|
53209
|
+
"user",
|
|
53210
|
+
"error",
|
|
53211
|
+
"context"
|
|
53212
|
+
]);
|
|
53213
|
+
var DEFAULT_LIMIT2 = 100;
|
|
53214
|
+
var MAX_LIMIT = 500;
|
|
53215
|
+
function scrub2(text) {
|
|
53216
|
+
return text ? stripAnsi2(redactContextSecrets(text)) : undefined;
|
|
53217
|
+
}
|
|
53218
|
+
var STR_FIELDS = [
|
|
53219
|
+
"status",
|
|
53220
|
+
"kind",
|
|
53221
|
+
"provider",
|
|
53222
|
+
"model",
|
|
53223
|
+
"tool",
|
|
53224
|
+
"title",
|
|
53225
|
+
"subtaskId",
|
|
53226
|
+
"expertTag"
|
|
53227
|
+
];
|
|
53228
|
+
var NUM_FIELDS = [
|
|
53229
|
+
"iteration",
|
|
53230
|
+
"promptTokens",
|
|
53231
|
+
"completionTokens",
|
|
53232
|
+
"totalTokens",
|
|
53233
|
+
"duration",
|
|
53234
|
+
"cycle"
|
|
53235
|
+
];
|
|
53236
|
+
function copyStr(out, e, f) {
|
|
53237
|
+
const v = e[f];
|
|
53238
|
+
if (typeof v === "string")
|
|
53239
|
+
out[f] = v;
|
|
53240
|
+
}
|
|
53241
|
+
function copyNum(out, e, f) {
|
|
53242
|
+
const v = e[f];
|
|
53243
|
+
if (typeof v === "number")
|
|
53244
|
+
out[f] = v;
|
|
53245
|
+
}
|
|
53246
|
+
function pick(e) {
|
|
53247
|
+
const out = { ts: e.ts, type: e.type };
|
|
53248
|
+
for (const f of STR_FIELDS)
|
|
53249
|
+
copyStr(out, e, f);
|
|
53250
|
+
for (const f of NUM_FIELDS)
|
|
53251
|
+
copyNum(out, e, f);
|
|
53252
|
+
if (typeof e.success === "boolean")
|
|
53253
|
+
out.success = e.success;
|
|
53254
|
+
if (typeof e.tool_call_id === "string")
|
|
53255
|
+
out.toolCallId = e.tool_call_id;
|
|
53256
|
+
const text = scrub2(e.content ?? e.summary ?? e.message);
|
|
53257
|
+
if (text !== undefined)
|
|
53258
|
+
out.content = text;
|
|
53259
|
+
return out;
|
|
53260
|
+
}
|
|
53261
|
+
function parseQuery(url) {
|
|
53262
|
+
try {
|
|
53263
|
+
return new URL(url ?? "", "http://127.0.0.1").searchParams;
|
|
53264
|
+
} catch {
|
|
53265
|
+
return new URLSearchParams;
|
|
53266
|
+
}
|
|
53267
|
+
}
|
|
53268
|
+
function tailSessionLog(entries, opts = {}) {
|
|
53269
|
+
const types2 = opts.types && opts.types.length > 0 ? new Set(opts.types) : new Set(TRACE_LOG_TYPES);
|
|
53270
|
+
const since = opts.since ? Date.parse(opts.since) : NaN;
|
|
53271
|
+
const limit = Math.min(Math.max(opts.limit ?? DEFAULT_LIMIT2, 1), MAX_LIMIT);
|
|
53272
|
+
const out = [];
|
|
53273
|
+
for (const e of entries) {
|
|
53274
|
+
if (!ALLOWED_TYPES.has(e.type) || !types2.has(e.type))
|
|
53275
|
+
continue;
|
|
53276
|
+
if (!Number.isNaN(since)) {
|
|
53277
|
+
const ts = Date.parse(e.ts);
|
|
53278
|
+
if (Number.isNaN(ts) || ts <= since)
|
|
53279
|
+
continue;
|
|
53280
|
+
}
|
|
53281
|
+
out.push(pick(e));
|
|
53282
|
+
}
|
|
53283
|
+
return out.slice(-limit);
|
|
53284
|
+
}
|
|
53285
|
+
function handleSessionLog(req, res, id, s) {
|
|
53286
|
+
if (!s.sessionManager) {
|
|
53287
|
+
sendJson(res, 503, { error: "sessions_unavailable" });
|
|
53288
|
+
return;
|
|
53289
|
+
}
|
|
53290
|
+
const manager = s.sessionManager;
|
|
53291
|
+
if (!id || !manager.get(id)) {
|
|
53292
|
+
sendJson(res, 404, { error: "not_found" });
|
|
53293
|
+
return;
|
|
53294
|
+
}
|
|
53295
|
+
const q = parseQuery(req.url);
|
|
53296
|
+
const types2 = (q.get("types") ?? "").split(",").map((t2) => t2.trim()).filter((t2) => ALLOWED_TYPES.has(t2));
|
|
53297
|
+
const rawLimit = q.get("limit");
|
|
53298
|
+
const limit = rawLimit === null || rawLimit.trim() === "" ? undefined : Number(rawLimit);
|
|
53299
|
+
let log2 = [];
|
|
53300
|
+
try {
|
|
53301
|
+
log2 = manager.loadSessionLog?.(id) ?? [];
|
|
53302
|
+
} catch {
|
|
53303
|
+
log2 = [];
|
|
53304
|
+
}
|
|
53305
|
+
sendJson(res, 200, {
|
|
53306
|
+
id,
|
|
53307
|
+
log: tailSessionLog(log2, {
|
|
53308
|
+
types: types2,
|
|
53309
|
+
since: q.get("since") ?? undefined,
|
|
53310
|
+
limit: limit !== undefined && Number.isFinite(limit) ? limit : undefined
|
|
53311
|
+
})
|
|
53312
|
+
});
|
|
53313
|
+
}
|
|
53314
|
+
|
|
52890
53315
|
// src/modules/webui/sessions-api.ts
|
|
52891
53316
|
function handleSessionsGet(res, s) {
|
|
52892
53317
|
if (!s.sessionManager) {
|
|
@@ -53016,6 +53441,11 @@ function handleSessionsApi(req, res, reqUrl, s) {
|
|
|
53016
53441
|
handleSessionHistory(res, id, s);
|
|
53017
53442
|
return true;
|
|
53018
53443
|
}
|
|
53444
|
+
if (p.startsWith("/api/sessions/") && p.endsWith("/log") && req.method === "GET") {
|
|
53445
|
+
const id = decodeURIComponent(p.slice("/api/sessions/".length, -"/log".length));
|
|
53446
|
+
handleSessionLog(req, res, id, s);
|
|
53447
|
+
return true;
|
|
53448
|
+
}
|
|
53019
53449
|
if (p.startsWith("/api/sessions/") && req.method === "DELETE") {
|
|
53020
53450
|
const id = decodeURIComponent(p.slice("/api/sessions/".length));
|
|
53021
53451
|
handleSessionDelete(res, id, s);
|
|
@@ -54350,7 +54780,7 @@ function handleEvents(req, res, s) {
|
|
|
54350
54780
|
const greeted = res.write(`retry: 1200
|
|
54351
54781
|
|
|
54352
54782
|
`) && res.write(`event: state
|
|
54353
|
-
data: ${JSON.stringify({ busy: s.busy })}
|
|
54783
|
+
data: ${JSON.stringify({ busy: s.busy, queueLen: s.pendingQueue.length })}
|
|
54354
54784
|
|
|
54355
54785
|
`);
|
|
54356
54786
|
if (!greeted) {
|
|
@@ -54383,7 +54813,11 @@ function dropClient(res, s) {
|
|
|
54383
54813
|
}
|
|
54384
54814
|
var API_ROUTES = {
|
|
54385
54815
|
"GET /api/state": (_req, res, s) => {
|
|
54386
|
-
sendJson(res, 200, {
|
|
54816
|
+
sendJson(res, 200, {
|
|
54817
|
+
busy: s.busy,
|
|
54818
|
+
queueLen: s.pendingQueue.length,
|
|
54819
|
+
state: s.bridge?.getState?.() ?? null
|
|
54820
|
+
});
|
|
54387
54821
|
},
|
|
54388
54822
|
"POST /api/message": (req, res, s) => handleMessagePost(req, res, s),
|
|
54389
54823
|
"GET /api/config": (_req, res, s) => handleConfigGet(res, s),
|
|
@@ -54545,6 +54979,7 @@ function stopServer(s = getDefaultState()) {
|
|
|
54545
54979
|
s.busy = false;
|
|
54546
54980
|
s.agentRunning = false;
|
|
54547
54981
|
s.turnToken = null;
|
|
54982
|
+
s.pendingQueue.length = 0;
|
|
54548
54983
|
s.lastPostTs = 0;
|
|
54549
54984
|
}
|
|
54550
54985
|
|
|
@@ -54584,6 +55019,8 @@ function captureUsage(result, fallbackLimit) {
|
|
|
54584
55019
|
}
|
|
54585
55020
|
if (typeof result.contextQuality === "number")
|
|
54586
55021
|
usage.contextQuality = result.contextQuality;
|
|
55022
|
+
if (result.contextBreakdown)
|
|
55023
|
+
usage.contextBreakdown = result.contextBreakdown;
|
|
54587
55024
|
return usage;
|
|
54588
55025
|
}
|
|
54589
55026
|
function planEventFor(toolName, execModule) {
|
|
@@ -54606,10 +55043,12 @@ function buildHostState(deps, busy) {
|
|
|
54606
55043
|
compactionCount: deps.usage?.compactionCount,
|
|
54607
55044
|
cacheHitRate: deps.usage?.cacheHitRate,
|
|
54608
55045
|
contextQuality: deps.usage?.contextQuality,
|
|
55046
|
+
contextBreakdown: deps.usage?.contextBreakdown,
|
|
54609
55047
|
contextProbe: deps.contextProbe,
|
|
54610
55048
|
workspace: deps.workspace,
|
|
54611
55049
|
instructions: deps.instructions,
|
|
54612
55050
|
projectMap: deps.projectMap ?? undefined,
|
|
55051
|
+
i18nStale: isI18nStale(),
|
|
54613
55052
|
plan: planSnapshotFromModule(adaptActivePlan(deps.execModule?.getActivePlan()))
|
|
54614
55053
|
};
|
|
54615
55054
|
}
|
|
@@ -54662,7 +55101,7 @@ function makeRunAgent(deps) {
|
|
|
54662
55101
|
toolCalls,
|
|
54663
55102
|
interrupted: interrupted || undefined
|
|
54664
55103
|
});
|
|
54665
|
-
broadcast({ type: "state", ts: Date.now(), busy: state.busy, usage: state.usage }, state);
|
|
55104
|
+
broadcast({ type: "state", ts: Date.now(), busy: state.busy, queueLen: state.pendingQueue.length, usage: state.usage }, state);
|
|
54666
55105
|
return result;
|
|
54667
55106
|
} catch (err) {
|
|
54668
55107
|
forwarder.onTurnEnd({ success: false, interrupted: interrupted || undefined });
|
|
@@ -54687,7 +55126,7 @@ function makeReconfigure(state, agent, after) {
|
|
|
54687
55126
|
await after();
|
|
54688
55127
|
} catch {}
|
|
54689
55128
|
}
|
|
54690
|
-
broadcast({ type: "state", ts: Date.now(), busy: state.busy, usage: state.usage }, state);
|
|
55129
|
+
broadcast({ type: "state", ts: Date.now(), busy: state.busy, queueLen: state.pendingQueue.length, usage: state.usage }, state);
|
|
54691
55130
|
};
|
|
54692
55131
|
}
|
|
54693
55132
|
async function startWebUi(deps) {
|
|
@@ -54711,8 +55150,16 @@ async function startWebUi(deps) {
|
|
|
54711
55150
|
if (deps.indexer.refresh) {
|
|
54712
55151
|
const refresh = deps.indexer.refresh.bind(deps.indexer);
|
|
54713
55152
|
state.refreshIndex = async () => {
|
|
54714
|
-
|
|
54715
|
-
|
|
55153
|
+
broadcast({ type: "index", ts: Date.now(), phase: "start" }, state);
|
|
55154
|
+
try {
|
|
55155
|
+
await refresh();
|
|
55156
|
+
} catch {
|
|
55157
|
+
broadcast({ type: "index", ts: Date.now(), phase: "error" }, state);
|
|
55158
|
+
throw new Error("index refresh failed");
|
|
55159
|
+
}
|
|
55160
|
+
const stats = state.projectMapStats?.() ?? null;
|
|
55161
|
+
broadcast({ type: "index", ts: Date.now(), phase: "done", stats }, state);
|
|
55162
|
+
broadcast({ type: "state", ts: Date.now(), busy: state.busy, queueLen: state.pendingQueue.length, usage: state.usage }, state);
|
|
54716
55163
|
};
|
|
54717
55164
|
}
|
|
54718
55165
|
}
|
|
@@ -54728,7 +55175,9 @@ async function startWebUi(deps) {
|
|
|
54728
55175
|
if (modelCache)
|
|
54729
55176
|
modelCache.refresh();
|
|
54730
55177
|
state.reconfigure = makeReconfigure(state, deps.agent, modelCache ? () => modelCache.refresh() : undefined);
|
|
54731
|
-
const forwarder = makeForwarder(state
|
|
55178
|
+
const forwarder = makeForwarder(state, undefined, {
|
|
55179
|
+
onQueueDrained: () => drainQueueTurn(state)
|
|
55180
|
+
});
|
|
54732
55181
|
const stopOutputForwarding = installOutputForwarding(state);
|
|
54733
55182
|
let probe;
|
|
54734
55183
|
if (deps.contextProbe) {
|
|
@@ -54811,7 +55260,7 @@ async function runWeb(opts) {
|
|
|
54811
55260
|
process.env[MMA_ENV.WEBUI_OPEN] = "0";
|
|
54812
55261
|
const mmaDir = globalMmaDir();
|
|
54813
55262
|
const { hasDomainFiles: hasDomainFiles2 } = await Promise.resolve().then(() => (init_domains(), exports_domains));
|
|
54814
|
-
const virgin = !existsSync63(
|
|
55263
|
+
const virgin = !existsSync63(join61(mmaDir, "config.json")) && !hasDomainFiles2(mmaDir);
|
|
54815
55264
|
const {
|
|
54816
55265
|
agent,
|
|
54817
55266
|
config,
|
|
@@ -54933,7 +55382,7 @@ init_config2();
|
|
|
54933
55382
|
init_i18n();
|
|
54934
55383
|
init_colors();
|
|
54935
55384
|
import { existsSync as existsSync64, readFileSync as readFileSync45 } from "fs";
|
|
54936
|
-
import { join as
|
|
55385
|
+
import { join as join63, dirname as dirname30 } from "path";
|
|
54937
55386
|
import { fileURLToPath as fileURLToPath7 } from "url";
|
|
54938
55387
|
|
|
54939
55388
|
// src/modules/updater/index.ts
|
|
@@ -55055,7 +55504,7 @@ init_i18n();
|
|
|
55055
55504
|
init_utils();
|
|
55056
55505
|
init_paths();
|
|
55057
55506
|
import { appendFileSync as appendFileSync8, mkdirSync as mkdirSync30 } from "fs";
|
|
55058
|
-
import { join as
|
|
55507
|
+
import { join as join62 } from "path";
|
|
55059
55508
|
import { homedir as homedir9 } from "os";
|
|
55060
55509
|
var CRASH_LOG_DIR = globalLogsDir();
|
|
55061
55510
|
var CRASH_LOG_FILE = "crash.jsonl";
|
|
@@ -55073,7 +55522,7 @@ function formatCrashEntry(type2, err) {
|
|
|
55073
55522
|
function writeCrashEntry(dir, entry) {
|
|
55074
55523
|
try {
|
|
55075
55524
|
mkdirSync30(dir, { recursive: true });
|
|
55076
|
-
appendFileSync8(
|
|
55525
|
+
appendFileSync8(join62(dir, CRASH_LOG_FILE), `${JSON.stringify(entry)}
|
|
55077
55526
|
`, "utf-8");
|
|
55078
55527
|
} catch {}
|
|
55079
55528
|
}
|
|
@@ -55144,7 +55593,7 @@ function resolveEarlyLocale() {
|
|
|
55144
55593
|
if (env3)
|
|
55145
55594
|
return env3;
|
|
55146
55595
|
const dir = globalMmaDir();
|
|
55147
|
-
for (const p of [
|
|
55596
|
+
for (const p of [join63(dir, "config", "core.json"), join63(dir, "config.json")]) {
|
|
55148
55597
|
try {
|
|
55149
55598
|
const parsed = JSON.parse(readFileSync45(p, "utf-8"));
|
|
55150
55599
|
if (typeof parsed.locale === "string")
|
|
@@ -55244,7 +55693,7 @@ async function main() {
|
|
|
55244
55693
|
const prompt = program2.args.join(" ");
|
|
55245
55694
|
const mmaDir = globalMmaDir();
|
|
55246
55695
|
const { hasDomainFiles: hasDomainFiles2 } = await Promise.resolve().then(() => (init_domains(), exports_domains));
|
|
55247
|
-
const virgin = !existsSync64(
|
|
55696
|
+
const virgin = !existsSync64(join63(mmaDir, "config.json")) && !hasDomainFiles2(mmaDir);
|
|
55248
55697
|
const { agent, config, baseDir, legacyDetected, contextProbe } = await bootstrap(undefined, projectDir, noAgentsMd, exitOnComplete, reasoningLevel, contextLog);
|
|
55249
55698
|
if (verboseOpt)
|
|
55250
55699
|
config.ui.verbosity = "verbose";
|
|
@@ -55335,7 +55784,7 @@ async function main() {
|
|
|
55335
55784
|
if (onboardingStart === "init")
|
|
55336
55785
|
process.env[MMA_ENV.START_INIT] = "1";
|
|
55337
55786
|
const mmaDir = globalMmaDir();
|
|
55338
|
-
const legacyConfigPath =
|
|
55787
|
+
const legacyConfigPath = join63(mmaDir, "config.json");
|
|
55339
55788
|
let hasAnyConfig = existsSync64(legacyConfigPath);
|
|
55340
55789
|
if (!hasAnyConfig) {
|
|
55341
55790
|
try {
|
|
@@ -55343,7 +55792,7 @@ async function main() {
|
|
|
55343
55792
|
hasAnyConfig = hasDomainFiles2(mmaDir);
|
|
55344
55793
|
} catch {}
|
|
55345
55794
|
}
|
|
55346
|
-
const projectConfigPath = projectDir ?
|
|
55795
|
+
const projectConfigPath = projectDir ? join63(projectDir, ".mmrc") : join63(process.cwd(), ".mmrc");
|
|
55347
55796
|
if (!hasAnyConfig && !exitOnComplete && readEnv("POST_SETUP") !== "1") {
|
|
55348
55797
|
getDefaultChannel().writeLine(`
|
|
55349
55798
|
${t("cli.first_run")}
|