micro-models-agent 0.44.0 → 0.46.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/bin/mma.mjs +41 -41
- package/dist/cli/commands.js +9 -19
- package/dist/cli/completer.js +36 -37
- package/dist/cli/index.js +2 -2
- package/dist/cli/main.js +48 -23
- package/dist/cli/plugin-commands.js +36 -0
- package/dist/cli/repl-commands.js +40 -12
- package/dist/cli/repl.js +217 -87
- package/dist/cli/run-result.js +22 -0
- package/dist/cli/security-commands.js +5 -7
- package/dist/cli/setup.js +8 -26
- package/dist/config/config.js +52 -5
- package/dist/config/defaults.js +29 -5
- package/dist/config/experts.js +1 -1
- package/dist/config/index.js +3 -3
- package/dist/config/security.js +3 -10
- package/dist/core/agent-moe.js +2 -10
- package/dist/core/agent.js +273 -82
- package/dist/core/bootstrap.js +80 -13
- package/dist/core/index.js +2 -2
- package/dist/core/prompt-builder.js +23 -2
- package/dist/core/session-logger.js +46 -4
- package/dist/core/version.js +24 -0
- package/dist/i18n/en.json +75 -2
- package/dist/i18n/ru.json +74 -1
- package/dist/index.js +1 -1
- package/dist/llm/image-utils.js +4 -5
- package/dist/llm/index.js +4 -4
- package/dist/llm/model-loader.js +6 -6
- package/dist/llm/openai-compat.js +40 -34
- package/dist/llm/orchestrator.js +33 -29
- package/dist/llm/response.js +9 -9
- package/dist/logger/app-logger.js +1 -1
- package/dist/logger/index.js +1 -1
- package/dist/main.js +525 -85
- package/dist/migration/backup.js +13 -13
- package/dist/migration/detect.js +11 -11
- package/dist/migration/index.js +2 -2
- package/dist/modules/artifacts/store.js +61 -0
- package/dist/modules/browser/actions.js +34 -4
- package/dist/modules/browser/bridge-client.js +199 -0
- package/dist/modules/browser/bridge-path.js +10 -0
- package/dist/modules/browser/bridge-server.mjs +202 -202
- package/dist/modules/browser/cookie-store.js +6 -6
- package/dist/modules/browser/driver.js +136 -0
- package/dist/modules/browser/index.js +7 -5
- package/dist/modules/browser/module.js +8 -7
- package/dist/modules/browser/session.js +87 -84
- package/dist/modules/browser/snapshot.js +92 -58
- package/dist/modules/browser/types.js +4 -1
- package/dist/modules/certification/cli.js +2 -4
- package/dist/modules/certification/fact-checker.js +1 -3
- package/dist/modules/certification/loader.js +3 -9
- package/dist/modules/certification/runner.js +1 -4
- package/dist/modules/context/chunk-query.js +100 -0
- package/dist/modules/context/fact-extractor.js +162 -0
- package/dist/modules/context/history.js +15 -0
- package/dist/modules/context/index.js +1 -1
- package/dist/modules/context/manager.js +160 -86
- package/dist/modules/execution/audit-runners.js +152 -0
- package/dist/modules/execution/auditor.js +177 -25
- package/dist/modules/execution/execution-plugin.js +272 -0
- package/dist/modules/execution/module.js +201 -544
- package/dist/modules/execution/moe-executor.js +25 -0
- package/dist/modules/execution/plan-store.js +1 -3
- package/dist/modules/execution/plan-tool.js +508 -0
- package/dist/modules/execution/plan-validator.js +10 -10
- package/dist/modules/execution/planner.js +6 -1
- package/dist/modules/execution/stuck-detector.js +173 -10
- package/dist/modules/execution/verifier.js +86 -42
- package/dist/modules/execution/windows-commands.js +41 -0
- package/dist/modules/hallucination/confidence.js +8 -1
- package/dist/modules/hallucination/detector.js +2 -5
- package/dist/modules/hallucination/factual.js +3 -64
- package/dist/modules/hallucination/index.js +1 -1
- package/dist/modules/hallucination/js-identifiers.js +190 -0
- package/dist/modules/hallucination/llm-judge.js +1 -3
- package/dist/modules/indexer/cache.js +9 -7
- package/dist/modules/indexer/index.js +3 -3
- package/dist/modules/indexer/module.js +95 -42
- package/dist/modules/indexer/project-profile.js +183 -0
- package/dist/modules/indexer/walker.js +17 -17
- package/dist/modules/lsp/check-tool.js +58 -0
- package/dist/modules/lsp/client.js +74 -31
- package/dist/modules/lsp/command.js +60 -0
- package/dist/modules/lsp/config.js +87 -33
- package/dist/modules/lsp/index.js +3 -3
- package/dist/modules/lsp/module.js +185 -21
- package/dist/modules/lsp/probe.js +76 -0
- package/dist/modules/lsp/project-root.js +32 -0
- package/dist/modules/lsp/startup-check.js +141 -0
- package/dist/modules/mcp/module.js +2 -6
- package/dist/modules/memory/index.js +1 -1
- package/dist/modules/memory/module.js +71 -23
- package/dist/modules/memory/search.js +11 -9
- package/dist/modules/memory/store.js +13 -13
- package/dist/modules/pipelines/engine.js +10 -10
- package/dist/modules/pipelines/index.js +3 -3
- package/dist/modules/pipelines/parser.js +17 -14
- package/dist/modules/pipelines/template.js +1 -1
- package/dist/modules/plugins/builtin/lint-on-write.js +21 -16
- package/dist/modules/plugins/builtin/notify.js +3 -2
- package/dist/modules/plugins/index.js +1 -1
- package/dist/modules/plugins/loader.js +59 -17
- package/dist/modules/plugins/manager.js +73 -17
- package/dist/modules/processes/detect.js +34 -0
- package/dist/modules/processes/index.js +1 -1
- package/dist/modules/processes/registry.js +135 -46
- package/dist/modules/registry.js +4 -2
- package/dist/modules/security/audit-notifier.js +39 -39
- package/dist/modules/security/command-validator.js +2 -8
- package/dist/modules/security/data-sanitizer.js +1 -9
- package/dist/modules/security/encryption.js +58 -56
- package/dist/modules/security/network-validator.js +1 -9
- package/dist/modules/security/path-validator.js +1 -3
- package/dist/modules/security/security-policies.js +3 -19
- package/dist/modules/security/session-encryption.js +1 -1
- package/dist/modules/security/session-isolation.js +8 -8
- package/dist/modules/session/index.js +3 -3
- package/dist/modules/session/module.js +5 -5
- package/dist/modules/session/store.js +3 -9
- package/dist/modules/skills/matcher.js +27 -0
- package/dist/modules/skills/module.js +1 -2
- package/dist/modules/updater/checker.js +70 -6
- package/dist/modules/updater/index.js +2 -1
- package/dist/modules/updater/module.js +116 -0
- package/dist/modules/user-profile/compressor.js +2 -2
- package/dist/modules/user-profile/index.js +1 -1
- package/dist/modules/user-profile/profile.js +9 -9
- package/dist/tools/attach-image.js +1 -1
- package/dist/tools/bash.js +178 -19
- package/dist/tools/browser.js +46 -29
- package/dist/tools/chunk-query.js +99 -0
- package/dist/tools/download-file.js +116 -0
- package/dist/tools/enable-tools.js +58 -0
- package/dist/tools/executor.js +4 -5
- package/dist/tools/file-info.js +13 -12
- package/dist/tools/filter-tools.js +9 -2
- package/dist/tools/glob-tool.js +11 -11
- package/dist/tools/grep-tool.js +1 -3
- package/dist/tools/hidden-tools-block.js +37 -0
- package/dist/tools/index.js +13 -2
- package/dist/tools/list-dir.js +18 -17
- package/dist/tools/load-skill.js +1 -3
- package/dist/tools/path-utils.js +4 -4
- package/dist/tools/pipeline-run.js +25 -25
- package/dist/tools/process-kill.js +11 -11
- package/dist/tools/process-list.js +20 -22
- package/dist/tools/process-log.js +22 -18
- package/dist/tools/question.js +1 -3
- package/dist/tools/read-file.js +10 -2
- package/dist/tools/recall.js +44 -37
- package/dist/tools/registry.js +15 -4
- package/dist/tools/remember.js +29 -29
- package/dist/tools/scope-check.js +9 -9
- package/dist/tools/subagent.js +54 -9
- package/dist/tools/user-input.js +1 -1
- package/dist/tools/web-browse.js +3 -3
- package/dist/tools/web-fetch.js +3 -3
- package/dist/tools/web-search.js +3 -3
- package/dist/tools/write-file.js +1 -3
- package/dist/ui/box.js +1 -5
- package/dist/ui/index.js +6 -6
- package/dist/ui/line-editor.js +703 -0
- package/dist/ui/line-math.js +69 -0
- package/dist/ui/md-formatter.js +33 -33
- package/dist/ui/output.js +5 -5
- package/dist/ui/plan-view.js +103 -0
- package/dist/ui/renderer.js +15 -10
- package/dist/ui/table.js +1 -1
- package/package.json +48 -48
package/dist/main.js
CHANGED
|
@@ -2263,7 +2263,9 @@ var init_defaults = __esm(() => {
|
|
|
2263
2263
|
retry: {
|
|
2264
2264
|
maxRetries: 3,
|
|
2265
2265
|
baseDelay: 1000,
|
|
2266
|
-
maxDelay: 30000
|
|
2266
|
+
maxDelay: 30000,
|
|
2267
|
+
maxStreamRetries: 2,
|
|
2268
|
+
noDataTimeoutMs: 60000
|
|
2267
2269
|
},
|
|
2268
2270
|
maxToolIterations: 1000,
|
|
2269
2271
|
stuckThreshold: 6,
|
|
@@ -2298,6 +2300,10 @@ var init_defaults = __esm(() => {
|
|
|
2298
2300
|
maxSearchesPerSession: 3,
|
|
2299
2301
|
requestTimeoutMs: 1e4
|
|
2300
2302
|
},
|
|
2303
|
+
pricing: {
|
|
2304
|
+
enabled: true,
|
|
2305
|
+
overrides: {}
|
|
2306
|
+
},
|
|
2301
2307
|
ui: {
|
|
2302
2308
|
spinner: true,
|
|
2303
2309
|
toolStyle: "inline",
|
|
@@ -2390,7 +2396,10 @@ Use read_file on {path} to see the current content before editing — the target
|
|
|
2390
2396
|
"error.http": "HTTP {status}: {statusText}",
|
|
2391
2397
|
"error.llm_api": "LLM API error {status} ({statusText}): {errorText}",
|
|
2392
2398
|
"error.llm_retries": "LLM request failed after retries",
|
|
2399
|
+
"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}",
|
|
2393
2400
|
"error.no_response_body": "No response body stream",
|
|
2401
|
+
"error.llm_stream_idle": "LLM stream stalled — no data for {timeout}ms",
|
|
2402
|
+
"error.llm_timeout": "LLM request timed out ({timeout}ms)",
|
|
2394
2403
|
"session.started": "Session started: {id}",
|
|
2395
2404
|
"session.ended": "Session ended: {id}",
|
|
2396
2405
|
"session.not_found": "Session not found: {id}",
|
|
@@ -2774,6 +2783,19 @@ Available commands:`,
|
|
|
2774
2783
|
"repl.lsp_timeout": "timeout",
|
|
2775
2784
|
"repl.lsp_failed": "did not start",
|
|
2776
2785
|
"repl.lsp_unknown": "unknown",
|
|
2786
|
+
"repl.lsp": "LSP server management (status, restart, check)",
|
|
2787
|
+
"repl.lsp_usage": "Usage: /lsp [status|restart|check <path>]",
|
|
2788
|
+
"repl.lsp_not_available": "LSP module not available",
|
|
2789
|
+
"repl.lsp_status_header": "LSP Status:",
|
|
2790
|
+
"repl.lsp_enabled": "Enabled:",
|
|
2791
|
+
"repl.lsp_disabled_servers": "Disabled servers:",
|
|
2792
|
+
"repl.lsp_failure_counts": "Failure counts:",
|
|
2793
|
+
"repl.lsp_all_ok": "All servers operational",
|
|
2794
|
+
"repl.lsp_restarting": "Resetting LSP server state...",
|
|
2795
|
+
"repl.lsp_restarted": "LSP servers reset. Failed servers will be retried on next use.",
|
|
2796
|
+
"repl.lsp_check_usage": "Usage: /lsp check <file-or-directory>",
|
|
2797
|
+
"repl.lsp_checking": "Running LSP check on {path}...",
|
|
2798
|
+
"repl.lsp_check_error": "LSP check failed: {error}",
|
|
2777
2799
|
"repl.work_dir": "Dir:",
|
|
2778
2800
|
"repl.agents_label": "Instructions:",
|
|
2779
2801
|
"repl.not_found": "not found",
|
|
@@ -2999,7 +3021,10 @@ Apply a matching solution from these results. If none is relevant — do NOT rep
|
|
|
2999
3021
|
"tools.enable_already_active": "Tool tags already active: {tags}.",
|
|
3000
3022
|
"tools.enable_added": "Enabled tool tags: {tags}. Available tools now: {tools}",
|
|
3001
3023
|
"tools.hidden_header": "Additional tools (enable on demand via enable_tools or route to subagent tool_tags):",
|
|
3002
|
-
"tool.friendly.enable_tools": "Enable tools"
|
|
3024
|
+
"tool.friendly.enable_tools": "Enable tools",
|
|
3025
|
+
"cli.provider_base_hint": "Base URL set to: {baseUrl}",
|
|
3026
|
+
"repl.cost": "Total cost: {cost}",
|
|
3027
|
+
"repl.tokens": "Tokens used: {tokens}"
|
|
3003
3028
|
};
|
|
3004
3029
|
});
|
|
3005
3030
|
|
|
@@ -3049,7 +3074,10 @@ var init_ru = __esm(() => {
|
|
|
3049
3074
|
"error.http": "HTTP {status}: {statusText}",
|
|
3050
3075
|
"error.llm_api": "Ошибка LLM API {status} ({statusText}): {errorText}",
|
|
3051
3076
|
"error.llm_retries": "Запрос LLM не удался после повторов",
|
|
3077
|
+
"error.llm_429": "Превышен лимит запросов (HTTP 429) для {model} на {baseUrl}. Провайдер ограничивает трафик — особенно строгие free-модели. Получите API-ключ или переключитесь на платную/быструю модель: {baseUrl}",
|
|
3052
3078
|
"error.no_response_body": "Нет потока тела ответа",
|
|
3079
|
+
"error.llm_stream_idle": "Поток LLM завис — нет данных {timeout}мс",
|
|
3080
|
+
"error.llm_timeout": "Время запроса LLM истекло ({timeout}мс)",
|
|
3053
3081
|
"session.started": "Сессия начата: {id}",
|
|
3054
3082
|
"session.ended": "Сессия завершена: {id}",
|
|
3055
3083
|
"session.not_found": "Сессия не найдена: {id}",
|
|
@@ -3428,6 +3456,19 @@ var init_ru = __esm(() => {
|
|
|
3428
3456
|
"repl.lsp_timeout": "таймаут",
|
|
3429
3457
|
"repl.lsp_failed": "не стартовал",
|
|
3430
3458
|
"repl.lsp_unknown": "неизвестно",
|
|
3459
|
+
"repl.lsp": "Управление LSP-серверами (status, restart, check)",
|
|
3460
|
+
"repl.lsp_usage": "Использование: /lsp [status|restart|check <путь>]",
|
|
3461
|
+
"repl.lsp_not_available": "Модуль LSP недоступен",
|
|
3462
|
+
"repl.lsp_status_header": "Статус LSP:",
|
|
3463
|
+
"repl.lsp_enabled": "Включён:",
|
|
3464
|
+
"repl.lsp_disabled_servers": "Отключённые серверы:",
|
|
3465
|
+
"repl.lsp_failure_counts": "Количество ошибок:",
|
|
3466
|
+
"repl.lsp_all_ok": "Все серверы работают",
|
|
3467
|
+
"repl.lsp_restarting": "Сброс состояния LSP-серверов...",
|
|
3468
|
+
"repl.lsp_restarted": "LSP-серверы сброшены. Упавшие серверы будут повторно запущены при следующем использовании.",
|
|
3469
|
+
"repl.lsp_check_usage": "Использование: /lsp check <файл-или-каталог>",
|
|
3470
|
+
"repl.lsp_checking": "Запуск LSP-проверки {path}...",
|
|
3471
|
+
"repl.lsp_check_error": "LSP-проверка не удалась: {error}",
|
|
3431
3472
|
"repl.work_dir": "Директория:",
|
|
3432
3473
|
"repl.agents_label": "Инструкции:",
|
|
3433
3474
|
"repl.not_found": "не найден",
|
|
@@ -3659,7 +3700,10 @@ var init_ru = __esm(() => {
|
|
|
3659
3700
|
"tools.enable_already_active": "Теги тулов уже активны: {tags}.",
|
|
3660
3701
|
"tools.enable_added": "Включены теги тулов: {tags}. Теперь доступны тулы: {tools}",
|
|
3661
3702
|
"tools.hidden_header": "Дополнительные тулы (включите по требованию через enable_tools или маршрутизируйте через subagent tool_tags):",
|
|
3662
|
-
"tool.friendly.enable_tools": "Включить тулы"
|
|
3703
|
+
"tool.friendly.enable_tools": "Включить тулы",
|
|
3704
|
+
"cli.provider_base_hint": "Базовый URL установлен: {baseUrl}",
|
|
3705
|
+
"repl.cost": "Итого потрачено: {cost}",
|
|
3706
|
+
"repl.tokens": "Потрачено токенов: {tokens}"
|
|
3663
3707
|
};
|
|
3664
3708
|
});
|
|
3665
3709
|
|
|
@@ -5160,7 +5204,9 @@ class OpenAICompatProvider {
|
|
|
5160
5204
|
this.retryConfig = config.retry ?? {
|
|
5161
5205
|
maxRetries: 3,
|
|
5162
5206
|
baseDelay: 1000,
|
|
5163
|
-
maxDelay: 30000
|
|
5207
|
+
maxDelay: 30000,
|
|
5208
|
+
maxStreamRetries: 2,
|
|
5209
|
+
noDataTimeoutMs: 60000
|
|
5164
5210
|
};
|
|
5165
5211
|
this.rateLimiter = createRateLimiter(config.rateLimits);
|
|
5166
5212
|
}
|
|
@@ -5191,6 +5237,32 @@ class OpenAICompatProvider {
|
|
|
5191
5237
|
}
|
|
5192
5238
|
}
|
|
5193
5239
|
async* doStream(messages, tools, signal, options) {
|
|
5240
|
+
const { baseDelay, maxDelay, maxStreamRetries, noDataTimeoutMs } = this.retryConfig;
|
|
5241
|
+
const streamRetries = maxStreamRetries ?? 2;
|
|
5242
|
+
const idleTimeoutMs = noDataTimeoutMs ?? 60000;
|
|
5243
|
+
for (let attempt = 0;; attempt++) {
|
|
5244
|
+
let emitted = false;
|
|
5245
|
+
const onEmit = () => {
|
|
5246
|
+
emitted = true;
|
|
5247
|
+
};
|
|
5248
|
+
try {
|
|
5249
|
+
const sawDone = yield* this.streamOnce(messages, tools, signal, options, onEmit, idleTimeoutMs);
|
|
5250
|
+
if (sawDone || emitted)
|
|
5251
|
+
return;
|
|
5252
|
+
if (attempt >= streamRetries)
|
|
5253
|
+
return;
|
|
5254
|
+
} catch (err) {
|
|
5255
|
+
if (err?.name === "AbortError" || err?.llmTerminal || signal?.aborted)
|
|
5256
|
+
throw err;
|
|
5257
|
+
if (emitted || attempt >= streamRetries)
|
|
5258
|
+
throw err;
|
|
5259
|
+
}
|
|
5260
|
+
const delay = Math.min(baseDelay * Math.pow(2, attempt), maxDelay);
|
|
5261
|
+
const jitter = Math.random() * baseDelay * 0.1;
|
|
5262
|
+
await this.sleep(delay + jitter, signal);
|
|
5263
|
+
}
|
|
5264
|
+
}
|
|
5265
|
+
async* streamOnce(messages, tools, signal, options, onEmit, idleTimeoutMs) {
|
|
5194
5266
|
const body = buildRequestBody({
|
|
5195
5267
|
model: this.model,
|
|
5196
5268
|
messages,
|
|
@@ -5206,8 +5278,11 @@ class OpenAICompatProvider {
|
|
|
5206
5278
|
headers["Authorization"] = `Bearer ${this.config.apiKey}`;
|
|
5207
5279
|
}
|
|
5208
5280
|
const controller = new AbortController;
|
|
5209
|
-
|
|
5210
|
-
const timeoutId = setTimeout(() =>
|
|
5281
|
+
let timedOut = false;
|
|
5282
|
+
const timeoutId = setTimeout(() => {
|
|
5283
|
+
timedOut = true;
|
|
5284
|
+
controller.abort();
|
|
5285
|
+
}, REQUEST_TIMEOUT_MS);
|
|
5211
5286
|
const abortSignal = (() => {
|
|
5212
5287
|
if (!signal)
|
|
5213
5288
|
return controller.signal;
|
|
@@ -5220,20 +5295,31 @@ class OpenAICompatProvider {
|
|
|
5220
5295
|
return controller.signal;
|
|
5221
5296
|
}
|
|
5222
5297
|
})();
|
|
5223
|
-
|
|
5224
|
-
|
|
5225
|
-
|
|
5226
|
-
|
|
5227
|
-
|
|
5228
|
-
|
|
5298
|
+
let response;
|
|
5299
|
+
try {
|
|
5300
|
+
response = await this.fetchWithRetry(`${this.config.baseUrl}/chat/completions`, {
|
|
5301
|
+
method: "POST",
|
|
5302
|
+
headers,
|
|
5303
|
+
body: JSON.stringify(body),
|
|
5304
|
+
signal: abortSignal
|
|
5305
|
+
});
|
|
5306
|
+
} catch (err) {
|
|
5307
|
+
if (err?.name === "AbortError")
|
|
5308
|
+
throw err;
|
|
5309
|
+
const wrapped = err instanceof Error ? err : new Error(String(err));
|
|
5310
|
+
wrapped.llmTerminal = true;
|
|
5311
|
+
throw wrapped;
|
|
5312
|
+
}
|
|
5229
5313
|
if (!response.ok) {
|
|
5230
5314
|
clearTimeout(timeoutId);
|
|
5231
5315
|
const errorText = await response.text();
|
|
5232
|
-
|
|
5316
|
+
const err = new Error(t("error.llm_api", {
|
|
5233
5317
|
status: response.status,
|
|
5234
5318
|
statusText: response.statusText,
|
|
5235
5319
|
errorText
|
|
5236
5320
|
}));
|
|
5321
|
+
err.llmTerminal = true;
|
|
5322
|
+
throw err;
|
|
5237
5323
|
}
|
|
5238
5324
|
const reader = response.body?.getReader();
|
|
5239
5325
|
if (!reader) {
|
|
@@ -5244,9 +5330,29 @@ class OpenAICompatProvider {
|
|
|
5244
5330
|
let buffer = "";
|
|
5245
5331
|
const toolCallAccs = new Map;
|
|
5246
5332
|
let usage;
|
|
5333
|
+
let sawDone = false;
|
|
5334
|
+
const readIdle = () => new Promise((resolve, reject) => {
|
|
5335
|
+
const idleTimer = setTimeout(() => {
|
|
5336
|
+
timedOut = true;
|
|
5337
|
+
controller.abort();
|
|
5338
|
+
}, idleTimeoutMs);
|
|
5339
|
+
reader.read().then((result) => {
|
|
5340
|
+
clearTimeout(idleTimer);
|
|
5341
|
+
if (timedOut)
|
|
5342
|
+
reject(new Error(t("error.llm_stream_idle", { timeout: idleTimeoutMs })));
|
|
5343
|
+
else
|
|
5344
|
+
resolve(result);
|
|
5345
|
+
}, (err) => {
|
|
5346
|
+
clearTimeout(idleTimer);
|
|
5347
|
+
if (timedOut)
|
|
5348
|
+
reject(new Error(t("error.llm_stream_idle", { timeout: idleTimeoutMs })));
|
|
5349
|
+
else
|
|
5350
|
+
reject(err);
|
|
5351
|
+
});
|
|
5352
|
+
});
|
|
5247
5353
|
try {
|
|
5248
5354
|
while (true) {
|
|
5249
|
-
const { done, value } = await
|
|
5355
|
+
const { done, value } = await readIdle();
|
|
5250
5356
|
if (done)
|
|
5251
5357
|
break;
|
|
5252
5358
|
buffer += decoder.decode(value, { stream: true });
|
|
@@ -5258,8 +5364,10 @@ class OpenAICompatProvider {
|
|
|
5258
5364
|
if (!trimmed || !trimmed.startsWith("data: "))
|
|
5259
5365
|
continue;
|
|
5260
5366
|
const data = trimmed.slice(6);
|
|
5261
|
-
if (data === "[DONE]")
|
|
5367
|
+
if (data === "[DONE]") {
|
|
5368
|
+
sawDone = true;
|
|
5262
5369
|
continue;
|
|
5370
|
+
}
|
|
5263
5371
|
try {
|
|
5264
5372
|
const parsed = JSON.parse(data);
|
|
5265
5373
|
const choice = parsed.choices?.[0];
|
|
@@ -5276,6 +5384,7 @@ class OpenAICompatProvider {
|
|
|
5276
5384
|
const delta = choice.delta || {};
|
|
5277
5385
|
const finishReason = choice.finish_reason;
|
|
5278
5386
|
if (delta.reasoning_content) {
|
|
5387
|
+
onEmit();
|
|
5279
5388
|
yield { type: "reasoning", content: delta.reasoning_content };
|
|
5280
5389
|
}
|
|
5281
5390
|
if (delta.tool_calls) {
|
|
@@ -5295,11 +5404,13 @@ class OpenAICompatProvider {
|
|
|
5295
5404
|
}
|
|
5296
5405
|
}
|
|
5297
5406
|
if (delta.content) {
|
|
5407
|
+
onEmit();
|
|
5298
5408
|
yield { type: "text", content: delta.content };
|
|
5299
5409
|
}
|
|
5300
5410
|
if (finishReason === "tool_calls" && toolCallAccs.size > 0) {
|
|
5301
5411
|
for (const [, acc] of toolCallAccs) {
|
|
5302
5412
|
if (acc.name) {
|
|
5413
|
+
onEmit();
|
|
5303
5414
|
yield {
|
|
5304
5415
|
type: "tool_call",
|
|
5305
5416
|
toolCall: {
|
|
@@ -5316,12 +5427,14 @@ class OpenAICompatProvider {
|
|
|
5316
5427
|
}
|
|
5317
5428
|
}
|
|
5318
5429
|
if (usage) {
|
|
5430
|
+
onEmit();
|
|
5319
5431
|
yield { type: "done", usage };
|
|
5320
5432
|
}
|
|
5321
5433
|
} finally {
|
|
5322
5434
|
clearTimeout(timeoutId);
|
|
5323
5435
|
reader.releaseLock();
|
|
5324
5436
|
}
|
|
5437
|
+
return sawDone;
|
|
5325
5438
|
}
|
|
5326
5439
|
async doNonStreaming(messages, tools, signal, options) {
|
|
5327
5440
|
const body = buildRequestBody({
|
|
@@ -5338,12 +5451,30 @@ class OpenAICompatProvider {
|
|
|
5338
5451
|
if (this.config.apiKey && this.config.apiKey !== "not-needed") {
|
|
5339
5452
|
headers["Authorization"] = `Bearer ${this.config.apiKey}`;
|
|
5340
5453
|
}
|
|
5454
|
+
const controller = new AbortController;
|
|
5455
|
+
let timedOut = false;
|
|
5456
|
+
const timeoutId = setTimeout(() => {
|
|
5457
|
+
timedOut = true;
|
|
5458
|
+
controller.abort();
|
|
5459
|
+
}, REQUEST_TIMEOUT_MS);
|
|
5460
|
+
const abortSignal = (() => {
|
|
5461
|
+
if (!signal)
|
|
5462
|
+
return controller.signal;
|
|
5463
|
+
try {
|
|
5464
|
+
return AbortSignal.any([controller.signal, signal]);
|
|
5465
|
+
} catch {
|
|
5466
|
+
signal.addEventListener("abort", () => controller.abort(), {
|
|
5467
|
+
once: true
|
|
5468
|
+
});
|
|
5469
|
+
return controller.signal;
|
|
5470
|
+
}
|
|
5471
|
+
})();
|
|
5341
5472
|
try {
|
|
5342
5473
|
const response = await this.fetchWithRetry(`${this.config.baseUrl}/chat/completions`, {
|
|
5343
5474
|
method: "POST",
|
|
5344
5475
|
headers,
|
|
5345
5476
|
body: JSON.stringify(body),
|
|
5346
|
-
signal
|
|
5477
|
+
signal: abortSignal
|
|
5347
5478
|
});
|
|
5348
5479
|
if (!response.ok) {
|
|
5349
5480
|
const errorText = await response.text();
|
|
@@ -5390,7 +5521,12 @@ class OpenAICompatProvider {
|
|
|
5390
5521
|
}
|
|
5391
5522
|
return chunks;
|
|
5392
5523
|
} catch (err) {
|
|
5524
|
+
if (timedOut && err?.name === "AbortError") {
|
|
5525
|
+
throw new Error(t("error.llm_timeout", { timeout: REQUEST_TIMEOUT_MS }));
|
|
5526
|
+
}
|
|
5393
5527
|
throw err instanceof Error ? err : new Error(String(err));
|
|
5528
|
+
} finally {
|
|
5529
|
+
clearTimeout(timeoutId);
|
|
5394
5530
|
}
|
|
5395
5531
|
}
|
|
5396
5532
|
countTokens(text) {
|
|
@@ -5421,26 +5557,36 @@ class OpenAICompatProvider {
|
|
|
5421
5557
|
}
|
|
5422
5558
|
async fetchWithRetry(url, init) {
|
|
5423
5559
|
const { maxRetries, baseDelay, maxDelay } = this.retryConfig;
|
|
5424
|
-
let
|
|
5560
|
+
let lastStatus = 0;
|
|
5561
|
+
let lastRetryAfter = 0;
|
|
5425
5562
|
for (let attempt = 0;attempt <= maxRetries; attempt++) {
|
|
5426
5563
|
try {
|
|
5427
5564
|
const response = await fetch(url, init);
|
|
5428
5565
|
if (!this.isRetryable(response.status))
|
|
5429
5566
|
return response;
|
|
5430
|
-
|
|
5567
|
+
lastStatus = response.status;
|
|
5568
|
+
const retryAfter = Number(response.headers.get("retry-after") ?? 0);
|
|
5569
|
+
lastRetryAfter = retryAfter > 0 ? retryAfter * 1000 : 0;
|
|
5431
5570
|
} catch (err) {
|
|
5432
5571
|
if (err.name === "AbortError") {
|
|
5433
5572
|
throw err;
|
|
5434
5573
|
}
|
|
5435
|
-
|
|
5574
|
+
if (attempt === maxRetries)
|
|
5575
|
+
throw err;
|
|
5436
5576
|
}
|
|
5437
5577
|
if (attempt < maxRetries) {
|
|
5438
|
-
const delay = Math.min(baseDelay * Math.pow(2, attempt), maxDelay);
|
|
5578
|
+
const delay = lastRetryAfter > 0 ? Math.min(lastRetryAfter, maxDelay) : Math.min(baseDelay * Math.pow(2, attempt), maxDelay);
|
|
5439
5579
|
const jitter = Math.random() * baseDelay * 0.1;
|
|
5440
5580
|
await this.sleep(delay + jitter, init.signal ?? undefined);
|
|
5441
5581
|
}
|
|
5442
5582
|
}
|
|
5443
|
-
|
|
5583
|
+
if (lastStatus === 429) {
|
|
5584
|
+
throw new Error(t("error.llm_429", {
|
|
5585
|
+
model: this.model,
|
|
5586
|
+
baseUrl: this.config.baseUrl
|
|
5587
|
+
}));
|
|
5588
|
+
}
|
|
5589
|
+
throw new Error(t("error.llm_retries"));
|
|
5444
5590
|
}
|
|
5445
5591
|
isRetryable(status) {
|
|
5446
5592
|
return status === 429 || status >= 500;
|
|
@@ -5464,6 +5610,7 @@ class OpenAICompatProvider {
|
|
|
5464
5610
|
});
|
|
5465
5611
|
}
|
|
5466
5612
|
}
|
|
5613
|
+
var REQUEST_TIMEOUT_MS = 120000;
|
|
5467
5614
|
var init_openai_compat = __esm(() => {
|
|
5468
5615
|
init_token_counter();
|
|
5469
5616
|
init_i18n();
|
|
@@ -11293,6 +11440,145 @@ var init_agent_moe = __esm(() => {
|
|
|
11293
11440
|
init_verifier();
|
|
11294
11441
|
});
|
|
11295
11442
|
|
|
11443
|
+
// src/modules/pricing/prices.ts
|
|
11444
|
+
function normalizeModelId(model) {
|
|
11445
|
+
let id = model.trim();
|
|
11446
|
+
for (const prefix of PROVIDER_PREFIXES) {
|
|
11447
|
+
if (id.startsWith(prefix)) {
|
|
11448
|
+
id = id.slice(prefix.length);
|
|
11449
|
+
break;
|
|
11450
|
+
}
|
|
11451
|
+
}
|
|
11452
|
+
const parts = id.split("/");
|
|
11453
|
+
return parts[parts.length - 1];
|
|
11454
|
+
}
|
|
11455
|
+
function resolvePrice(model, config) {
|
|
11456
|
+
if (!config?.enabled)
|
|
11457
|
+
return;
|
|
11458
|
+
const bare = normalizeModelId(model);
|
|
11459
|
+
const overrides = config.overrides ?? {};
|
|
11460
|
+
const direct = overrides[model] ?? overrides[bare];
|
|
11461
|
+
if (direct)
|
|
11462
|
+
return direct;
|
|
11463
|
+
return ZEN_PRICES[bare];
|
|
11464
|
+
}
|
|
11465
|
+
function calculateCost(model, promptTokens, completionTokens, config) {
|
|
11466
|
+
const price = resolvePrice(model, config);
|
|
11467
|
+
if (!price)
|
|
11468
|
+
return;
|
|
11469
|
+
return promptTokens / 1e6 * price.input + completionTokens / 1e6 * price.output;
|
|
11470
|
+
}
|
|
11471
|
+
function formatCost(cost) {
|
|
11472
|
+
if (cost === 0)
|
|
11473
|
+
return "$0.00";
|
|
11474
|
+
if (cost >= 0.01)
|
|
11475
|
+
return `$${cost.toFixed(2)}`;
|
|
11476
|
+
if (cost >= 0.0001)
|
|
11477
|
+
return `$${cost.toFixed(4)}`;
|
|
11478
|
+
return `$${cost.toFixed(6)}`;
|
|
11479
|
+
}
|
|
11480
|
+
var ZEN_PRICES, PROVIDER_PREFIXES;
|
|
11481
|
+
var init_prices = __esm(() => {
|
|
11482
|
+
ZEN_PRICES = {
|
|
11483
|
+
"big-pickle": { input: 0, output: 0 },
|
|
11484
|
+
"mimo-v2.5-free": { input: 0, output: 0 },
|
|
11485
|
+
"hy3-free": { input: 0, output: 0 },
|
|
11486
|
+
"nemotron-3-ultra-free": { input: 0, output: 0 },
|
|
11487
|
+
"nemotron-3.5-lightning-free": { input: 0, output: 0 },
|
|
11488
|
+
"muse-spark-1.2-contributor-free": { input: 0, output: 0 },
|
|
11489
|
+
"minimax-m3": { input: 0.3, output: 1.2 },
|
|
11490
|
+
"minimax-m2.7": { input: 0.3, output: 1.2 },
|
|
11491
|
+
"minimax-m2.5": { input: 0.3, output: 1.2 },
|
|
11492
|
+
"glm-5.2": { input: 1.4, output: 4.4 },
|
|
11493
|
+
"glm-5.1": { input: 1.4, output: 4.4 },
|
|
11494
|
+
"glm-5": { input: 1, output: 3.2 },
|
|
11495
|
+
"glm-5.3": { input: 1.4, output: 4.4 },
|
|
11496
|
+
"kimi-k2.7-code": { input: 0.95, output: 4 },
|
|
11497
|
+
"kimi-k3": { input: 3, output: 15 },
|
|
11498
|
+
"kimi-k2.6": { input: 0.95, output: 4 },
|
|
11499
|
+
"kimi-k2.5": { input: 0.6, output: 3 },
|
|
11500
|
+
"qwen3.7-max": { input: 2.5, output: 7.5 },
|
|
11501
|
+
"qwen3.7-plus": { input: 0.4, output: 1.6 },
|
|
11502
|
+
"qwen3.6-plus": { input: 0.5, output: 3 },
|
|
11503
|
+
"qwen3.5-plus": { input: 0.2, output: 1.2 },
|
|
11504
|
+
"qwen3.8-max": { input: 2.5, output: 7.5 },
|
|
11505
|
+
"deepseek-v4-pro": { input: 0.66, output: 1.98 },
|
|
11506
|
+
"deepseek-v4-flash": { input: 0.22, output: 0.66 },
|
|
11507
|
+
"claude-fable-5": { input: 10, output: 50 },
|
|
11508
|
+
"claude-opus-5": { input: 5, output: 25 },
|
|
11509
|
+
"claude-opus-4-8": { input: 5, output: 25 },
|
|
11510
|
+
"claude-opus-4-7": { input: 5, output: 25 },
|
|
11511
|
+
"claude-opus-4-6": { input: 5, output: 25 },
|
|
11512
|
+
"claude-opus-4-5": { input: 5, output: 25 },
|
|
11513
|
+
"claude-sonnet-5": { input: 2, output: 10 },
|
|
11514
|
+
"claude-sonnet-4-6": { input: 3, output: 15 },
|
|
11515
|
+
"claude-sonnet-4-5": { input: 3, output: 15 },
|
|
11516
|
+
"claude-haiku-4-5": { input: 1, output: 5 },
|
|
11517
|
+
"gemini-3.7-flash": { input: 1.5, output: 7.5 },
|
|
11518
|
+
"gemini-3.6-flash": { input: 1.5, output: 7.5 },
|
|
11519
|
+
"gemini-3.5-flash": { input: 1.5, output: 9 },
|
|
11520
|
+
"gemini-3.5-flash-lite": { input: 0.3, output: 2.5 },
|
|
11521
|
+
"gemini-3.1-pro": { input: 2, output: 12 },
|
|
11522
|
+
"gemini-3-flash": { input: 0.5, output: 3 },
|
|
11523
|
+
"grok-4.6": { input: 2, output: 6 },
|
|
11524
|
+
"grok-4.5": { input: 2, output: 6 },
|
|
11525
|
+
"grok-build-0.1": { input: 1, output: 2 },
|
|
11526
|
+
"muse-spark-1.2": { input: 1.25, output: 4.25 },
|
|
11527
|
+
"gpt-5.6-sol": { input: 5, output: 30 },
|
|
11528
|
+
"gpt-5.6-terra": { input: 2, output: 12 },
|
|
11529
|
+
"gpt-5.6-luna": { input: 0.2, output: 1.2 },
|
|
11530
|
+
"gpt-5.5": { input: 5, output: 30 },
|
|
11531
|
+
"gpt-5.5-pro": { input: 30, output: 180 },
|
|
11532
|
+
"gpt-5.4": { input: 2.5, output: 15 },
|
|
11533
|
+
"gpt-5.4-pro": { input: 30, output: 180 },
|
|
11534
|
+
"gpt-5.4-mini": { input: 0.75, output: 4.5 },
|
|
11535
|
+
"gpt-5.4-nano": { input: 0.2, output: 1.25 },
|
|
11536
|
+
"gpt-5.3-codex": { input: 1.75, output: 14 },
|
|
11537
|
+
"gpt-5.3-codex-spark": { input: 1.75, output: 14 },
|
|
11538
|
+
"gpt-5.2": { input: 1.75, output: 14 },
|
|
11539
|
+
"gpt-5.2-codex": { input: 1.75, output: 14 },
|
|
11540
|
+
"gpt-5.1": { input: 1.07, output: 8.5 },
|
|
11541
|
+
"gpt-5.1-codex": { input: 1.07, output: 8.5 },
|
|
11542
|
+
"gpt-5.1-codex-max": { input: 1.25, output: 10 },
|
|
11543
|
+
"gpt-5.1-codex-mini": { input: 0.25, output: 2 },
|
|
11544
|
+
"gpt-5": { input: 1.07, output: 8.5 },
|
|
11545
|
+
"gpt-5-codex": { input: 1.07, output: 8.5 },
|
|
11546
|
+
"gpt-5-nano": { input: 0.05, output: 0.4 }
|
|
11547
|
+
};
|
|
11548
|
+
PROVIDER_PREFIXES = ["opencode-go/", "opencode/", "openai/", "anthropic/"];
|
|
11549
|
+
});
|
|
11550
|
+
|
|
11551
|
+
// src/modules/pricing/index.ts
|
|
11552
|
+
class CostTracker {
|
|
11553
|
+
config;
|
|
11554
|
+
model;
|
|
11555
|
+
_total = 0;
|
|
11556
|
+
_known = false;
|
|
11557
|
+
constructor(model, config) {
|
|
11558
|
+
this.model = model;
|
|
11559
|
+
this.config = config;
|
|
11560
|
+
}
|
|
11561
|
+
setModel(model) {
|
|
11562
|
+
this.model = model;
|
|
11563
|
+
}
|
|
11564
|
+
record(promptTokens, completionTokens) {
|
|
11565
|
+
const cost = calculateCost(this.model, promptTokens, completionTokens, this.config);
|
|
11566
|
+
if (cost === undefined)
|
|
11567
|
+
return;
|
|
11568
|
+
this._known = true;
|
|
11569
|
+
this._total += cost;
|
|
11570
|
+
}
|
|
11571
|
+
get total() {
|
|
11572
|
+
return this._known ? this._total : undefined;
|
|
11573
|
+
}
|
|
11574
|
+
get formatted() {
|
|
11575
|
+
return this._known ? formatCost(this._total) : undefined;
|
|
11576
|
+
}
|
|
11577
|
+
}
|
|
11578
|
+
var init_pricing = __esm(() => {
|
|
11579
|
+
init_prices();
|
|
11580
|
+
});
|
|
11581
|
+
|
|
11296
11582
|
// src/core/agent.ts
|
|
11297
11583
|
function isToolCallJson(text) {
|
|
11298
11584
|
const trimmed = text.trim();
|
|
@@ -11319,8 +11605,10 @@ class Agent {
|
|
|
11319
11605
|
shutdownRequested = false;
|
|
11320
11606
|
abortController = null;
|
|
11321
11607
|
lastCompactionShown = 0;
|
|
11608
|
+
costTracker;
|
|
11322
11609
|
constructor(deps) {
|
|
11323
11610
|
this.deps = deps;
|
|
11611
|
+
this.costTracker = new CostTracker(deps.config.model, deps.config.pricing);
|
|
11324
11612
|
}
|
|
11325
11613
|
get contextManager() {
|
|
11326
11614
|
return this.deps.contextManager;
|
|
@@ -11424,6 +11712,7 @@ ${t("tool.truncated", { tokens: Math.ceil(removedChars / 2) })}`;
|
|
|
11424
11712
|
onPhase?.(phase);
|
|
11425
11713
|
}
|
|
11426
11714
|
async run(input, onChunk, onMeta, onTool, onPhase) {
|
|
11715
|
+
this.shutdownRequested = false;
|
|
11427
11716
|
this.setScope();
|
|
11428
11717
|
const {
|
|
11429
11718
|
config,
|
|
@@ -11676,6 +11965,7 @@ ${t("tool.truncated", { tokens: Math.ceil(removedChars / 2) })}`;
|
|
|
11676
11965
|
source,
|
|
11677
11966
|
durationMs: Date.now() - llmStart
|
|
11678
11967
|
});
|
|
11968
|
+
this.costTracker.record(prompt, completion);
|
|
11679
11969
|
}
|
|
11680
11970
|
if (this.shutdownRequested) {
|
|
11681
11971
|
break;
|
|
@@ -11791,7 +12081,8 @@ ${t("tool.truncated", { tokens: Math.ceil(removedChars / 2) })}`;
|
|
|
11791
12081
|
args: call.arguments,
|
|
11792
12082
|
duration,
|
|
11793
12083
|
error: !result.success,
|
|
11794
|
-
ctxDelta: tokensAfterTool - tokensBeforeTool
|
|
12084
|
+
ctxDelta: tokensAfterTool - tokensBeforeTool,
|
|
12085
|
+
costUsd: this.costTracker.total
|
|
11795
12086
|
});
|
|
11796
12087
|
summaries.push(`[Tool: ${call.name} (${JSON.stringify(call.arguments)}) → ${truncatedOutput.slice(0, 200)}]`);
|
|
11797
12088
|
if (config.session.autoSave) {
|
|
@@ -12026,6 +12317,7 @@ ${warnLine}
|
|
|
12026
12317
|
promptTokens: usageTokens.prompt,
|
|
12027
12318
|
completionTokens: usageTokens.completion,
|
|
12028
12319
|
totalTokens: usageTokens.total,
|
|
12320
|
+
totalCost: this.costTracker.total,
|
|
12029
12321
|
compactionCount: contextManager.getCompactionCount(),
|
|
12030
12322
|
contextQuality: contextManager.getQuality()
|
|
12031
12323
|
};
|
|
@@ -12040,6 +12332,7 @@ ${warnLine}
|
|
|
12040
12332
|
promptTokens: usageTokens.prompt,
|
|
12041
12333
|
completionTokens: usageTokens.completion,
|
|
12042
12334
|
totalTokens: usageTokens.total,
|
|
12335
|
+
totalCost: this.costTracker.total,
|
|
12043
12336
|
compactionCount: contextManager.getCompactionCount(),
|
|
12044
12337
|
contextQuality: contextManager.getQuality()
|
|
12045
12338
|
};
|
|
@@ -12065,6 +12358,7 @@ ${warnLine}
|
|
|
12065
12358
|
const newTokenCounter = new TokenCounter2(config.model);
|
|
12066
12359
|
this.deps.contextManager.resize(config.contextWindow, config.contextBudget, newTokenCounter);
|
|
12067
12360
|
this.deps.config = config;
|
|
12361
|
+
this.costTracker.setModel(config.model);
|
|
12068
12362
|
}
|
|
12069
12363
|
setContext(messages) {
|
|
12070
12364
|
const { contextManager } = this.deps;
|
|
@@ -12091,7 +12385,6 @@ ${warnLine}
|
|
|
12091
12385
|
if (killed > 0) {
|
|
12092
12386
|
logger.info(`Killed ${killed} background process(es) on shutdown`);
|
|
12093
12387
|
}
|
|
12094
|
-
logger.closeSessionLog();
|
|
12095
12388
|
pluginManager.runOnSessionEnd({
|
|
12096
12389
|
logger,
|
|
12097
12390
|
sessionManager: sessionManager?.getActiveMeta(),
|
|
@@ -12108,6 +12401,7 @@ var init_agent = __esm(() => {
|
|
|
12108
12401
|
init_session_logger();
|
|
12109
12402
|
init_agent_moe();
|
|
12110
12403
|
init_verifier();
|
|
12404
|
+
init_pricing();
|
|
12111
12405
|
});
|
|
12112
12406
|
|
|
12113
12407
|
// src/modules/context/fact-extractor.ts
|
|
@@ -19746,6 +20040,10 @@ import { resolve as resolve20 } from "path";
|
|
|
19746
20040
|
import { platform as platform8 } from "os";
|
|
19747
20041
|
|
|
19748
20042
|
class LspClient {
|
|
20043
|
+
logger = null;
|
|
20044
|
+
setLogger(logger) {
|
|
20045
|
+
this.logger = logger;
|
|
20046
|
+
}
|
|
19749
20047
|
process = null;
|
|
19750
20048
|
requestId = 0;
|
|
19751
20049
|
pending = new Map;
|
|
@@ -19805,11 +20103,25 @@ class LspClient {
|
|
|
19805
20103
|
try {
|
|
19806
20104
|
await this.sendRequest("initialize", initParams, timeout);
|
|
19807
20105
|
} catch (e) {
|
|
20106
|
+
const msg = e instanceof Error ? e.message : String(e);
|
|
20107
|
+
this.logger?.warn(`LSP initialize failed (attempt 1): ${msg}`, {
|
|
20108
|
+
command: config.command,
|
|
20109
|
+
projectRoot
|
|
20110
|
+
});
|
|
19808
20111
|
if (!(e instanceof Error) || !e.message.includes("initialize"))
|
|
19809
20112
|
throw e;
|
|
19810
20113
|
await this.shutdown();
|
|
19811
20114
|
await this.startServer(config, projectRoot);
|
|
19812
|
-
|
|
20115
|
+
try {
|
|
20116
|
+
await this.sendRequest("initialize", initParams, timeout);
|
|
20117
|
+
} catch (retryErr) {
|
|
20118
|
+
const retryMsg = retryErr instanceof Error ? retryErr.message : String(retryErr);
|
|
20119
|
+
this.logger?.error(`LSP initialize failed (attempt 2, giving up): ${retryMsg}`, {
|
|
20120
|
+
command: config.command,
|
|
20121
|
+
projectRoot
|
|
20122
|
+
});
|
|
20123
|
+
throw retryErr;
|
|
20124
|
+
}
|
|
19813
20125
|
}
|
|
19814
20126
|
this.initialized = true;
|
|
19815
20127
|
}
|
|
@@ -19847,8 +20159,11 @@ class LspClient {
|
|
|
19847
20159
|
});
|
|
19848
20160
|
this.process = proc;
|
|
19849
20161
|
setTimeout(() => {
|
|
19850
|
-
if (!this.initialized && this.process)
|
|
19851
|
-
|
|
20162
|
+
if (!this.initialized && this.process) {
|
|
20163
|
+
const msg = "LSP server start timeout";
|
|
20164
|
+
this.logger?.error(msg, { command: config.command, projectRoot, timeout: config.timeout ?? 1e4 });
|
|
20165
|
+
reject(new Error(msg));
|
|
20166
|
+
}
|
|
19852
20167
|
}, config.timeout ?? 1e4);
|
|
19853
20168
|
});
|
|
19854
20169
|
}
|
|
@@ -19887,7 +20202,9 @@ class LspClient {
|
|
|
19887
20202
|
try {
|
|
19888
20203
|
const msg = JSON.parse(body);
|
|
19889
20204
|
this.handleMessage(msg);
|
|
19890
|
-
} catch {
|
|
20205
|
+
} catch (e) {
|
|
20206
|
+
this.logger?.debug(`LSP JSON parse error: ${e instanceof Error ? e.message : String(e)}`);
|
|
20207
|
+
}
|
|
19891
20208
|
}
|
|
19892
20209
|
}
|
|
19893
20210
|
handleMessage(msg) {
|
|
@@ -19925,7 +20242,9 @@ class LspClient {
|
|
|
19925
20242
|
setTimeout(() => {
|
|
19926
20243
|
if (this.pending.has(id)) {
|
|
19927
20244
|
this.pending.delete(id);
|
|
19928
|
-
|
|
20245
|
+
const msg = `LSP request timeout: ${method}`;
|
|
20246
|
+
this.logger?.warn(msg, { method, timeout });
|
|
20247
|
+
reject(new Error(msg));
|
|
19929
20248
|
}
|
|
19930
20249
|
}, timeout);
|
|
19931
20250
|
});
|
|
@@ -19935,27 +20254,37 @@ class LspClient {
|
|
|
19935
20254
|
this.write(message);
|
|
19936
20255
|
}
|
|
19937
20256
|
write(message) {
|
|
19938
|
-
if (!this.process?.stdin?.writable)
|
|
20257
|
+
if (!this.process?.stdin?.writable) {
|
|
20258
|
+
this.logger?.debug("LSP write failed: process stdin not writable");
|
|
19939
20259
|
return;
|
|
20260
|
+
}
|
|
19940
20261
|
const header = `Content-Length: ${Buffer.byteLength(message)}\r
|
|
19941
20262
|
\r
|
|
19942
20263
|
`;
|
|
19943
20264
|
try {
|
|
19944
20265
|
this.process.stdin.write(header + message);
|
|
19945
|
-
} catch {
|
|
20266
|
+
} catch (e) {
|
|
20267
|
+
this.logger?.debug(`LSP write error: ${e instanceof Error ? e.message : String(e)}`);
|
|
20268
|
+
}
|
|
19946
20269
|
}
|
|
19947
20270
|
async shutdown() {
|
|
19948
20271
|
try {
|
|
19949
20272
|
if (this.process && this.initialized && this.process.stdin?.writable) {
|
|
19950
|
-
this.sendRequest("shutdown", null, 3000).catch(() => {
|
|
20273
|
+
this.sendRequest("shutdown", null, 3000).catch((e) => {
|
|
20274
|
+
this.logger?.debug(`LSP shutdown request failed: ${e instanceof Error ? e.message : String(e)}`);
|
|
20275
|
+
});
|
|
19951
20276
|
this.sendNotification("exit", null);
|
|
19952
20277
|
await new Promise((r) => setTimeout(r, 200));
|
|
19953
20278
|
}
|
|
19954
|
-
} catch
|
|
20279
|
+
} catch (e) {
|
|
20280
|
+
this.logger?.debug(`LSP shutdown error: ${e instanceof Error ? e.message : String(e)}`);
|
|
20281
|
+
} finally {
|
|
19955
20282
|
if (this.process) {
|
|
19956
20283
|
try {
|
|
19957
20284
|
killTree(this.process);
|
|
19958
|
-
} catch {
|
|
20285
|
+
} catch (e) {
|
|
20286
|
+
this.logger?.debug(`LSP killTree error: ${e instanceof Error ? e.message : String(e)}`);
|
|
20287
|
+
}
|
|
19959
20288
|
this.process = null;
|
|
19960
20289
|
}
|
|
19961
20290
|
this.initialized = false;
|
|
@@ -20063,9 +20392,26 @@ class LspModule {
|
|
|
20063
20392
|
client;
|
|
20064
20393
|
failuresByServer = new Map;
|
|
20065
20394
|
disabledServers = new Set;
|
|
20066
|
-
|
|
20395
|
+
logger = null;
|
|
20396
|
+
constructor(config, client, logger) {
|
|
20067
20397
|
this.config = { ...DEFAULT_LSP_CONFIG, ...config };
|
|
20068
20398
|
this.client = client ?? new LspClient;
|
|
20399
|
+
this.logger = logger ?? null;
|
|
20400
|
+
this.client.setLogger(this.logger);
|
|
20401
|
+
}
|
|
20402
|
+
setLogger(logger) {
|
|
20403
|
+
this.logger = logger;
|
|
20404
|
+
this.client.setLogger(logger);
|
|
20405
|
+
}
|
|
20406
|
+
resetDisabledServers() {
|
|
20407
|
+
this.failuresByServer.clear();
|
|
20408
|
+
this.disabledServers.clear();
|
|
20409
|
+
}
|
|
20410
|
+
getDisabledServers() {
|
|
20411
|
+
return Array.from(this.disabledServers);
|
|
20412
|
+
}
|
|
20413
|
+
getFailureCounts() {
|
|
20414
|
+
return new Map(this.failuresByServer);
|
|
20069
20415
|
}
|
|
20070
20416
|
isLspDisabled() {
|
|
20071
20417
|
return this.disabledServers.size > 0;
|
|
@@ -20336,7 +20682,9 @@ async function runCheck(config, baseDir, deps) {
|
|
|
20336
20682
|
lines.push(formatStartupError(file, baseDir, d));
|
|
20337
20683
|
}
|
|
20338
20684
|
}
|
|
20339
|
-
} catch {
|
|
20685
|
+
} catch (e) {
|
|
20686
|
+
deps.logger?.debug(`Startup LSP check failed for ${file}: ${e instanceof Error ? e.message : String(e)}`);
|
|
20687
|
+
}
|
|
20340
20688
|
}
|
|
20341
20689
|
if (checked === 0 || lines.length === 0)
|
|
20342
20690
|
return null;
|
|
@@ -21427,7 +21775,7 @@ async function bootstrap(configDir, projectDir, noAgentsMd, exitOnComplete) {
|
|
|
21427
21775
|
pluginManager.register(browserPlugin);
|
|
21428
21776
|
}
|
|
21429
21777
|
}
|
|
21430
|
-
const lspModule = new LspModule(config.lsp);
|
|
21778
|
+
const lspModule = new LspModule(config.lsp, undefined, logger);
|
|
21431
21779
|
moduleRegistry.register(lspModule);
|
|
21432
21780
|
const lspPlugin = lspModule.getPlugin();
|
|
21433
21781
|
if (lspPlugin) {
|
|
@@ -22264,10 +22612,8 @@ async function runSetup(externalRl) {
|
|
|
22264
22612
|
console.log(t("setup.no_servers"));
|
|
22265
22613
|
apiBase = await ask(rl, t("setup.api_base"), "http://localhost:1234/v1");
|
|
22266
22614
|
}
|
|
22267
|
-
} else
|
|
22268
|
-
apiBase = "
|
|
22269
|
-
} else if (provider === "anthropic") {
|
|
22270
|
-
apiBase = "https://api.anthropic.com";
|
|
22615
|
+
} else {
|
|
22616
|
+
apiBase = HOSTED_BASE_URLS[provider] ?? "";
|
|
22271
22617
|
}
|
|
22272
22618
|
const defaultKey = provider === "openai-compat" ? "not-needed" : "";
|
|
22273
22619
|
const apiKey = await ask(rl, t("setup.api_key"), defaultKey);
|
|
@@ -22332,7 +22678,7 @@ async function runSetup(externalRl) {
|
|
|
22332
22678
|
console.log(l);
|
|
22333
22679
|
return answers;
|
|
22334
22680
|
}
|
|
22335
|
-
var PROVIDER_TYPES, KNOWN_PORTS;
|
|
22681
|
+
var PROVIDER_TYPES, KNOWN_PORTS, HOSTED_BASE_URLS;
|
|
22336
22682
|
var init_setup = __esm(() => {
|
|
22337
22683
|
init_colors();
|
|
22338
22684
|
init_i18n();
|
|
@@ -22345,7 +22691,9 @@ var init_setup = __esm(() => {
|
|
|
22345
22691
|
label: "OpenAI-compatible (LM Studio, Ollama, vLLM, etc.)"
|
|
22346
22692
|
},
|
|
22347
22693
|
{ value: "openai", label: "OpenAI API" },
|
|
22348
|
-
{ value: "anthropic", label: "Anthropic Claude" }
|
|
22694
|
+
{ value: "anthropic", label: "Anthropic Claude" },
|
|
22695
|
+
{ value: "opencode-zen", label: "OpenCode Zen (opencode.ai/zen)" },
|
|
22696
|
+
{ value: "opencode-go", label: "OpenCode Go (opencode.ai/go)" }
|
|
22349
22697
|
];
|
|
22350
22698
|
KNOWN_PORTS = [
|
|
22351
22699
|
{ port: 1234, label: "LM Studio" },
|
|
@@ -22353,6 +22701,12 @@ var init_setup = __esm(() => {
|
|
|
22353
22701
|
{ port: 8080, label: "vLLM / custom" },
|
|
22354
22702
|
{ port: 4891, label: "GPT4All" }
|
|
22355
22703
|
];
|
|
22704
|
+
HOSTED_BASE_URLS = {
|
|
22705
|
+
openai: "https://api.openai.com/v1",
|
|
22706
|
+
anthropic: "https://api.anthropic.com",
|
|
22707
|
+
"opencode-zen": "https://opencode.ai/zen/v1",
|
|
22708
|
+
"opencode-go": "https://opencode.ai/zen/go/v1"
|
|
22709
|
+
};
|
|
22356
22710
|
});
|
|
22357
22711
|
|
|
22358
22712
|
// src/modules/certification/manifest.ts
|
|
@@ -30445,6 +30799,70 @@ Excluded blocks: ${info.excluded.length}`));
|
|
|
30445
30799
|
}
|
|
30446
30800
|
}
|
|
30447
30801
|
});
|
|
30802
|
+
ctx.registerCommand({
|
|
30803
|
+
name: "lsp",
|
|
30804
|
+
description: t("repl.lsp"),
|
|
30805
|
+
usage: t("repl.lsp_usage"),
|
|
30806
|
+
action: async (args) => {
|
|
30807
|
+
const subcommand = args[0] || "status";
|
|
30808
|
+
const lspModule = ctx.agent.deps?.moduleRegistry?.getModules?.()?.find((m) => m.name === "lsp");
|
|
30809
|
+
if (!lspModule) {
|
|
30810
|
+
console.log(pc2.yellow(t("repl.lsp_not_available")));
|
|
30811
|
+
return;
|
|
30812
|
+
}
|
|
30813
|
+
switch (subcommand) {
|
|
30814
|
+
case "status": {
|
|
30815
|
+
const disabled = lspModule.getDisabledServers();
|
|
30816
|
+
const failures = lspModule.getFailureCounts();
|
|
30817
|
+
const config = ctx.config.lsp;
|
|
30818
|
+
console.log(pc2.bold(t("repl.lsp_status_header")));
|
|
30819
|
+
console.log(`${t("repl.lsp_enabled")} ${config?.enabled ? pc2.green("yes") : pc2.red("no")}`);
|
|
30820
|
+
if (disabled.length > 0) {
|
|
30821
|
+
console.log(pc2.yellow(`${t("repl.lsp_disabled_servers")} ${disabled.join(", ")}`));
|
|
30822
|
+
}
|
|
30823
|
+
if (failures.size > 0) {
|
|
30824
|
+
console.log(pc2.dim(t("repl.lsp_failure_counts")));
|
|
30825
|
+
for (const [server, count] of failures) {
|
|
30826
|
+
console.log(pc2.dim(` ${server}: ${count}`));
|
|
30827
|
+
}
|
|
30828
|
+
}
|
|
30829
|
+
if (disabled.length === 0 && failures.size === 0) {
|
|
30830
|
+
console.log(pc2.green(t("repl.lsp_all_ok")));
|
|
30831
|
+
}
|
|
30832
|
+
break;
|
|
30833
|
+
}
|
|
30834
|
+
case "restart": {
|
|
30835
|
+
console.log(pc2.yellow(t("repl.lsp_restarting")));
|
|
30836
|
+
lspModule.resetDisabledServers();
|
|
30837
|
+
console.log(pc2.green(t("repl.lsp_restarted")));
|
|
30838
|
+
break;
|
|
30839
|
+
}
|
|
30840
|
+
case "check": {
|
|
30841
|
+
const path = args[1];
|
|
30842
|
+
if (!path) {
|
|
30843
|
+
console.log(pc2.yellow(t("repl.lsp_check_usage")));
|
|
30844
|
+
return;
|
|
30845
|
+
}
|
|
30846
|
+
console.log(pc2.dim(t("repl.lsp_checking", { path })));
|
|
30847
|
+
try {
|
|
30848
|
+
const result = await ctx.agent.deps?.toolExecutor?.execute("lsp_check", { path }, ctx.agent.deps?.toolCtx);
|
|
30849
|
+
if (result?.output) {
|
|
30850
|
+
console.log(result.output);
|
|
30851
|
+
}
|
|
30852
|
+
} catch (e) {
|
|
30853
|
+
console.log(pc2.red(t("repl.lsp_check_error", {
|
|
30854
|
+
error: e instanceof Error ? e.message : String(e)
|
|
30855
|
+
})));
|
|
30856
|
+
}
|
|
30857
|
+
break;
|
|
30858
|
+
}
|
|
30859
|
+
default: {
|
|
30860
|
+
console.log(pc2.dim(t("repl.lsp_usage")));
|
|
30861
|
+
break;
|
|
30862
|
+
}
|
|
30863
|
+
}
|
|
30864
|
+
}
|
|
30865
|
+
});
|
|
30448
30866
|
}
|
|
30449
30867
|
function registerSessionCommands(ctx) {
|
|
30450
30868
|
if (!ctx.sessionManager)
|
|
@@ -30699,6 +31117,7 @@ var init_repl_commands = __esm(() => {
|
|
|
30699
31117
|
reload: "agent",
|
|
30700
31118
|
wizard: "agent",
|
|
30701
31119
|
sysprompt: "agent",
|
|
31120
|
+
lsp: "agent",
|
|
30702
31121
|
sessions: "session",
|
|
30703
31122
|
new: "session",
|
|
30704
31123
|
resume: "session",
|
|
@@ -31367,6 +31786,7 @@ function createPluginCommand(program2) {
|
|
|
31367
31786
|
}
|
|
31368
31787
|
|
|
31369
31788
|
// src/cli/commands.ts
|
|
31789
|
+
init_setup();
|
|
31370
31790
|
import { fileURLToPath as fileURLToPath4 } from "url";
|
|
31371
31791
|
function readVersion2() {
|
|
31372
31792
|
const here = dirname16(fileURLToPath4(import.meta.url));
|
|
@@ -31552,8 +31972,15 @@ function createProgram() {
|
|
|
31552
31972
|
const configPath = join44(homedir15(), ".mma", "config.json");
|
|
31553
31973
|
const { config } = await bootstrap();
|
|
31554
31974
|
config.provider.type = name;
|
|
31975
|
+
const baseUrl = HOSTED_BASE_URLS[name];
|
|
31976
|
+
if (baseUrl) {
|
|
31977
|
+
config.provider.baseUrl = baseUrl;
|
|
31978
|
+
}
|
|
31555
31979
|
saveConfig(config, configPath);
|
|
31556
31980
|
console.log(t("cli.provider_set", { name }));
|
|
31981
|
+
if (baseUrl) {
|
|
31982
|
+
console.log(t("cli.provider_base_hint", { baseUrl }));
|
|
31983
|
+
}
|
|
31557
31984
|
});
|
|
31558
31985
|
const session2 = program2.command("session").description(t("cli.manage_sessions"));
|
|
31559
31986
|
session2.command("list").description(t("cli.list_sessions")).action(async () => {
|
|
@@ -32358,9 +32785,8 @@ class LineEditor {
|
|
|
32358
32785
|
|
|
32359
32786
|
// src/cli/repl.ts
|
|
32360
32787
|
import { existsSync as existsSync53, readFileSync as readFileSync35, writeFileSync as writeFileSync17 } from "fs";
|
|
32361
|
-
import { join as join47
|
|
32788
|
+
import { join as join47 } from "path";
|
|
32362
32789
|
import { homedir as homedir17 } from "os";
|
|
32363
|
-
import { fileURLToPath as fileURLToPath6 } from "url";
|
|
32364
32790
|
|
|
32365
32791
|
// src/cli/completer.ts
|
|
32366
32792
|
class SlashCommandProvider {
|
|
@@ -32664,6 +33090,10 @@ init_spinner();
|
|
|
32664
33090
|
init_box();
|
|
32665
33091
|
init_table();
|
|
32666
33092
|
init_i18n();
|
|
33093
|
+
init_prices();
|
|
33094
|
+
function formatUsd(cost) {
|
|
33095
|
+
return formatCost(cost);
|
|
33096
|
+
}
|
|
32667
33097
|
var GUTTER = " ";
|
|
32668
33098
|
var BUSY_TOOLS = new Set(["lsp_check"]);
|
|
32669
33099
|
function toolMarker(tool) {
|
|
@@ -32800,14 +33230,20 @@ ${pc2.dim(marker)} ${friendlyTool(tool)}${summary ? ` ${pc2.dim(summary)}` : ""}
|
|
|
32800
33230
|
`);
|
|
32801
33231
|
}
|
|
32802
33232
|
}
|
|
32803
|
-
toolEnd(_tool, duration, error, ctxDelta) {
|
|
33233
|
+
toolEnd(_tool, duration, error, ctxDelta, costUsd) {
|
|
32804
33234
|
this.spinner.stop();
|
|
32805
33235
|
if (!this.rich) {
|
|
33236
|
+
const parts = [];
|
|
32806
33237
|
if (ctxDelta !== undefined && ctxDelta !== 0) {
|
|
32807
33238
|
const deltaStr = ctxDelta > 0 ? pc2.green(`+${ctxDelta}`) : pc2.yellow(`${ctxDelta} ↓`);
|
|
32808
|
-
|
|
32809
|
-
|
|
33239
|
+
parts.push(`${pc2.dim("ctx")} ${deltaStr}`);
|
|
33240
|
+
}
|
|
33241
|
+
if (costUsd !== undefined && costUsd > 0) {
|
|
33242
|
+
parts.push(`${pc2.dim("cost")} ${pc2.yellow(formatUsd(costUsd))}`);
|
|
32810
33243
|
}
|
|
33244
|
+
if (parts.length > 0)
|
|
33245
|
+
this.out.write(`${parts.join(" ")}
|
|
33246
|
+
`);
|
|
32811
33247
|
return;
|
|
32812
33248
|
}
|
|
32813
33249
|
if (!this.card)
|
|
@@ -32819,6 +33255,9 @@ ${pc2.dim(marker)} ${friendlyTool(tool)}${summary ? ` ${pc2.dim(summary)}` : ""}
|
|
|
32819
33255
|
const deltaStr = ctxDelta > 0 ? pc2.green(`+${ctxDelta}`) : pc2.yellow(`${ctxDelta} ↓`);
|
|
32820
33256
|
footer += ` ${pc2.dim("ctx")} ${deltaStr}`;
|
|
32821
33257
|
}
|
|
33258
|
+
if (costUsd !== undefined && costUsd > 0) {
|
|
33259
|
+
footer += ` ${pc2.dim("cost")} ${pc2.yellow(formatUsd(costUsd))}`;
|
|
33260
|
+
}
|
|
32822
33261
|
if (this.toolStyle === "inline") {
|
|
32823
33262
|
this.out.write(`${GUTTER}${footer}
|
|
32824
33263
|
`);
|
|
@@ -32918,16 +33357,24 @@ async function probeLspServers(config, baseDir, deps = {}) {
|
|
|
32918
33357
|
await probeClient.probe(server, projectRoot, serverTimeout);
|
|
32919
33358
|
ok.push({ language, ok: true, durationMs: Date.now() - started });
|
|
32920
33359
|
} catch (e) {
|
|
33360
|
+
const errorMsg = e instanceof Error ? e.message : String(e);
|
|
33361
|
+
deps.logger?.warn(`LSP probe failed for ${language}: ${errorMsg}`, {
|
|
33362
|
+
command: server.command,
|
|
33363
|
+
timeout: serverTimeout,
|
|
33364
|
+
durationMs: Date.now() - started
|
|
33365
|
+
});
|
|
32921
33366
|
failed.push({
|
|
32922
33367
|
language,
|
|
32923
33368
|
ok: false,
|
|
32924
|
-
error:
|
|
33369
|
+
error: errorMsg,
|
|
32925
33370
|
durationMs: Date.now() - started
|
|
32926
33371
|
});
|
|
32927
33372
|
}
|
|
32928
33373
|
};
|
|
32929
33374
|
for (let i = 0;i < servers.length; i += maxParallel) {
|
|
32930
33375
|
if (Date.now() >= deadline) {
|
|
33376
|
+
const remaining = servers.slice(i).map((s) => s.language);
|
|
33377
|
+
deps.logger?.warn(`LSP probe deadline reached, skipping: ${remaining.join(", ")}`);
|
|
32931
33378
|
for (const { language } of servers.slice(i)) {
|
|
32932
33379
|
failed.push({ language, ok: false, error: "timeout", durationMs: 0 });
|
|
32933
33380
|
}
|
|
@@ -33046,21 +33493,7 @@ function stepContextForTool(plan, tool, args) {
|
|
|
33046
33493
|
}
|
|
33047
33494
|
|
|
33048
33495
|
// src/cli/repl.ts
|
|
33049
|
-
|
|
33050
|
-
const here = dirname18(fileURLToPath6(import.meta.url));
|
|
33051
|
-
const candidates = [join47(here, "..", "..", "package.json"), join47(here, "..", "package.json")];
|
|
33052
|
-
for (const p of candidates) {
|
|
33053
|
-
if (existsSync53(p)) {
|
|
33054
|
-
try {
|
|
33055
|
-
const raw = JSON.parse(readFileSync35(p, "utf8"));
|
|
33056
|
-
if (raw.version)
|
|
33057
|
-
return raw.version;
|
|
33058
|
-
} catch {}
|
|
33059
|
-
}
|
|
33060
|
-
}
|
|
33061
|
-
return "0.0.0";
|
|
33062
|
-
}
|
|
33063
|
-
var version3 = readVersion4();
|
|
33496
|
+
init_prices();
|
|
33064
33497
|
function formatContextBar(used, limit, compactions, quality) {
|
|
33065
33498
|
const pct = Math.min(100, Math.round(used / limit * 100));
|
|
33066
33499
|
const barLen = 20;
|
|
@@ -33240,6 +33673,7 @@ class Repl {
|
|
|
33240
33673
|
this.running = false;
|
|
33241
33674
|
this.saveHistory();
|
|
33242
33675
|
this.agent.shutdown();
|
|
33676
|
+
this.logger?.closeSessionLog();
|
|
33243
33677
|
if (this.exitOnClose)
|
|
33244
33678
|
process.exit(0);
|
|
33245
33679
|
});
|
|
@@ -33248,6 +33682,7 @@ class Repl {
|
|
|
33248
33682
|
this.running = false;
|
|
33249
33683
|
this.saveHistory();
|
|
33250
33684
|
this.agent.shutdown();
|
|
33685
|
+
this.logger?.closeSessionLog();
|
|
33251
33686
|
process.exit(0);
|
|
33252
33687
|
});
|
|
33253
33688
|
}
|
|
@@ -33352,7 +33787,7 @@ ${t("image.clipboard_empty")}`));
|
|
|
33352
33787
|
if (ev.type === "start") {
|
|
33353
33788
|
renderer.toolStart(ev.tool, ev.args, stepContextForTool(this.activePlan, ev.tool, ev.args), ev.icon);
|
|
33354
33789
|
} else {
|
|
33355
|
-
renderer.toolEnd(ev.tool, ev.duration ?? 0, ev.error, ev.ctxDelta);
|
|
33790
|
+
renderer.toolEnd(ev.tool, ev.duration ?? 0, ev.error, ev.ctxDelta, ev.costUsd);
|
|
33356
33791
|
if (ev.tool === "plan" || ev.tool === "todo") {
|
|
33357
33792
|
this.refreshActivePlan(renderer);
|
|
33358
33793
|
}
|
|
@@ -33471,6 +33906,9 @@ ${t("image.clipboard_empty")}`));
|
|
|
33471
33906
|
const apiLine = pc2.dim(` API: ${result.promptTokens} prompt + ${result.completionTokens} completion = ${result.totalTokens} total`);
|
|
33472
33907
|
console.log(apiLine);
|
|
33473
33908
|
}
|
|
33909
|
+
if (result.totalCost !== undefined && result.totalCost > 0) {
|
|
33910
|
+
console.log(pc2.yellow(` ${t("repl.cost", { cost: formatCost(result.totalCost) })}`));
|
|
33911
|
+
}
|
|
33474
33912
|
} else if (ui?.showCompaction && result.compactionCount !== undefined) {
|
|
33475
33913
|
if (result.compactionCount > this.lastCompactionShown) {
|
|
33476
33914
|
this.lastCompactionShown = result.compactionCount;
|
|
@@ -33502,9 +33940,9 @@ ${t("image.clipboard_empty")}`));
|
|
|
33502
33940
|
const infos = this.pluginManager.getPluginInfos().filter(({ plugin: plugin3 }) => !plugin3.isBuiltin);
|
|
33503
33941
|
if (infos.length > 0) {
|
|
33504
33942
|
const pluginNames = infos.map(({ plugin: plugin3, source }) => {
|
|
33505
|
-
const
|
|
33943
|
+
const version3 = plugin3.version ? `${pc2.dim(plugin3.version)}` : "";
|
|
33506
33944
|
const origin = source ? pc2.dim(` [${source}]`) : "";
|
|
33507
|
-
return `${plugin3.name}${
|
|
33945
|
+
return `${plugin3.name}${version3}${origin}`;
|
|
33508
33946
|
}).join(", ");
|
|
33509
33947
|
row(t("repl.plugins_label"), `${pc2.white(String(infos.length))} active ${pc2.dim(`(${pluginNames})`)}`);
|
|
33510
33948
|
}
|
|
@@ -33545,33 +33983,27 @@ ${t("image.clipboard_empty")}`));
|
|
|
33545
33983
|
if (lspEnabled) {
|
|
33546
33984
|
row(t("repl.lsp_label"), pc2.dim("…"));
|
|
33547
33985
|
}
|
|
33548
|
-
const
|
|
33549
|
-
|
|
33550
|
-
width: headerWidth
|
|
33551
|
-
});
|
|
33552
|
-
for (const line of boxLines) {
|
|
33553
|
-
console.log(line);
|
|
33986
|
+
for (const line of info) {
|
|
33987
|
+
console.log(pc2.dim(line).trimEnd());
|
|
33554
33988
|
}
|
|
33555
33989
|
console.log();
|
|
33556
33990
|
this.rl.prompt();
|
|
33557
33991
|
if (lspEnabled) {
|
|
33558
33992
|
this.probeLspBanner().then((lspSummary) => {
|
|
33559
33993
|
if (lspSummary)
|
|
33560
|
-
this.updateLspRow(
|
|
33994
|
+
this.updateLspRow(headerWidth, lspSummary);
|
|
33561
33995
|
}).catch(() => {});
|
|
33562
33996
|
}
|
|
33563
33997
|
}
|
|
33564
|
-
updateLspRow(
|
|
33998
|
+
updateLspRow(headerWidth, summary) {
|
|
33565
33999
|
if (this.agentRunning || !process.stdout.isTTY)
|
|
33566
34000
|
return;
|
|
33567
34001
|
if ((process.stdout.columns ?? 96) < headerWidth)
|
|
33568
34002
|
return;
|
|
33569
|
-
const inner = headerWidth - 4;
|
|
33570
34003
|
const rowText = `${pc2.yellow(t("repl.lsp_label"))} ${summary.replace(/\s+/g, " ").trim()}`;
|
|
33571
|
-
if (stringWidth(rowText) >
|
|
34004
|
+
if (stringWidth(rowText) > headerWidth)
|
|
33572
34005
|
return;
|
|
33573
|
-
const
|
|
33574
|
-
const line = pc2.dim("│") + " " + padded + " " + pc2.dim("│");
|
|
34006
|
+
const line = pc2.dim(rowText);
|
|
33575
34007
|
process.stdout.write(`\x1B[2A\r\x1B[2K${line}\x1B[2B\r`);
|
|
33576
34008
|
}
|
|
33577
34009
|
async probeLspBanner() {
|
|
@@ -33597,6 +34029,7 @@ ${t("image.clipboard_empty")}`));
|
|
|
33597
34029
|
this.running = false;
|
|
33598
34030
|
this.saveHistory();
|
|
33599
34031
|
this.agent.shutdown();
|
|
34032
|
+
this.logger?.closeSessionLog();
|
|
33600
34033
|
this.rl.close();
|
|
33601
34034
|
}
|
|
33602
34035
|
}
|
|
@@ -33604,9 +34037,15 @@ ${t("image.clipboard_empty")}`));
|
|
|
33604
34037
|
// src/cli/run-result.ts
|
|
33605
34038
|
init_i18n();
|
|
33606
34039
|
init_colors();
|
|
34040
|
+
init_prices();
|
|
33607
34041
|
function printRunResult(result, flush) {
|
|
33608
34042
|
flush();
|
|
33609
34043
|
if (result.success) {
|
|
34044
|
+
if (result.totalCost !== undefined && result.totalCost > 0) {
|
|
34045
|
+
console.log(pc2.dim(`${t("repl.cost", { cost: formatCost(result.totalCost) })}`));
|
|
34046
|
+
} else if (result.totalTokens !== undefined && result.totalTokens > 0) {
|
|
34047
|
+
console.log(pc2.dim(`${t("repl.tokens", { tokens: result.totalTokens })}`));
|
|
34048
|
+
}
|
|
33610
34049
|
if (!result.text) {
|
|
33611
34050
|
console.log(pc2.yellow(t("cli.no_output")));
|
|
33612
34051
|
}
|
|
@@ -33622,9 +34061,9 @@ init_config2();
|
|
|
33622
34061
|
init_i18n();
|
|
33623
34062
|
init_colors();
|
|
33624
34063
|
import { existsSync as existsSync54, readFileSync as readFileSync36 } from "fs";
|
|
33625
|
-
import { join as join48, dirname as
|
|
34064
|
+
import { join as join48, dirname as dirname18 } from "path";
|
|
33626
34065
|
import { homedir as homedir18 } from "os";
|
|
33627
|
-
import { fileURLToPath as
|
|
34066
|
+
import { fileURLToPath as fileURLToPath6 } from "url";
|
|
33628
34067
|
|
|
33629
34068
|
// src/modules/updater/index.ts
|
|
33630
34069
|
init_checker();
|
|
@@ -33724,8 +34163,8 @@ class UpdaterModule {
|
|
|
33724
34163
|
}
|
|
33725
34164
|
}
|
|
33726
34165
|
// src/cli/main.ts
|
|
33727
|
-
function
|
|
33728
|
-
const here =
|
|
34166
|
+
function readVersion4() {
|
|
34167
|
+
const here = dirname18(fileURLToPath6(import.meta.url));
|
|
33729
34168
|
const candidates = [join48(here, "..", "..", "package.json"), join48(here, "..", "package.json")];
|
|
33730
34169
|
for (const p of candidates) {
|
|
33731
34170
|
if (existsSync54(p)) {
|
|
@@ -33740,7 +34179,7 @@ function readVersion5() {
|
|
|
33740
34179
|
}
|
|
33741
34180
|
function startAutoUpdate(config) {
|
|
33742
34181
|
try {
|
|
33743
|
-
const module = new UpdaterModule(config.updater,
|
|
34182
|
+
const module = new UpdaterModule(config.updater, readVersion4(), "micro-models-agent", {
|
|
33744
34183
|
info: (m) => process.stderr.write(pc2.dim(m) + `
|
|
33745
34184
|
`),
|
|
33746
34185
|
warn: (m) => process.stderr.write(pc2.yellow(m) + `
|
|
@@ -33783,7 +34222,8 @@ async function main() {
|
|
|
33783
34222
|
contextLimit: result2.contextLimit ?? null,
|
|
33784
34223
|
promptTokens: result2.promptTokens ?? null,
|
|
33785
34224
|
completionTokens: result2.completionTokens ?? null,
|
|
33786
|
-
totalTokens: result2.totalTokens ?? null
|
|
34225
|
+
totalTokens: result2.totalTokens ?? null,
|
|
34226
|
+
totalCost: result2.totalCost ?? null
|
|
33787
34227
|
}, null, 2));
|
|
33788
34228
|
process.stdout.write(`
|
|
33789
34229
|
`);
|
|
@@ -33798,7 +34238,7 @@ async function main() {
|
|
|
33798
34238
|
if (ev.type === "start") {
|
|
33799
34239
|
renderer.toolStart(ev.tool, ev.args, undefined, ev.icon);
|
|
33800
34240
|
} else {
|
|
33801
|
-
renderer.toolEnd(ev.tool, ev.duration ?? 0, ev.error, ev.ctxDelta);
|
|
34241
|
+
renderer.toolEnd(ev.tool, ev.duration ?? 0, ev.error, ev.ctxDelta, ev.costUsd);
|
|
33802
34242
|
}
|
|
33803
34243
|
}, (phase) => {
|
|
33804
34244
|
if (phase === "thinking") {
|