micro-models-agent 0.61.1 → 0.63.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 +26 -0
- package/dist/i18n/en.json +22 -1
- package/dist/i18n/ru.json +22 -1
- package/dist/main.js +913 -262
- package/package.json +1 -1
package/dist/main.js
CHANGED
|
@@ -2945,7 +2945,9 @@ Excluded blocks: {count}`,
|
|
|
2945
2945
|
"repl.provider_list": "List configured providers or hot-swap the active one",
|
|
2946
2946
|
"repl.provider_current": "Current provider",
|
|
2947
2947
|
"repl.provider_set": "Provider set to: {name}",
|
|
2948
|
-
"repl.provider_usage": "/provider list - show entries (* = active, prio = fallback order) | /provider use <name> - switch without restart",
|
|
2948
|
+
"repl.provider_usage": "/provider list - show entries (* = active, prio = fallback order) | /provider use <name> - switch without restart | /provider add <name> [--url <url>] [--key <key>] [--priority <n>] [--context-window <n>] [--rpm <n>] [--parallel <n>] - add to config",
|
|
2949
|
+
"repl.provider_add_missing_value": "Missing value for {flag}",
|
|
2950
|
+
"repl.provider_switch_hint": "Switch to it with: /provider use {name}",
|
|
2949
2951
|
"repl.model_list": "List models of the active provider or switch the model",
|
|
2950
2952
|
"repl.model_current": "Current model",
|
|
2951
2953
|
"repl.model_set": "Model set to: {name}",
|
|
@@ -3188,6 +3190,25 @@ Apply a matching solution from these results. If none is relevant — do NOT rep
|
|
|
3188
3190
|
"repl.cost": "Total cost: {cost}",
|
|
3189
3191
|
"repl.cost_breakdown": "By provider: {breakdown}",
|
|
3190
3192
|
"repl.tokens": "Tokens used: {tokens}",
|
|
3193
|
+
"repl.cache": "Cache: {hit}% hit · saved {saved}",
|
|
3194
|
+
"repl.cache_nosave": "Cache: {hit}% hit",
|
|
3195
|
+
"repl.prefix": "Prefix stable: {stable}% · broke: {cause}",
|
|
3196
|
+
"cache.cause.system": "system prompt",
|
|
3197
|
+
"cache.cause.tools": "tool set",
|
|
3198
|
+
"cache.cause.history": "history",
|
|
3199
|
+
"cache.cause.volatile": "volatile content",
|
|
3200
|
+
"cache.cause.unknown": "unknown",
|
|
3201
|
+
"cli.session_usage": "API usage: {prompt} prompt + {completion} completion = {total} tokens",
|
|
3202
|
+
"cli.session_cache": "Cache: {hit}% hit ({cached} cached / {uncached} uncached)",
|
|
3203
|
+
"cli.usage": "Show provider balance/usage (OpenRouter)",
|
|
3204
|
+
"cli.usage_unsupported": 'Provider "{provider}" does not expose an API balance. Only OpenRouter does; OpenCode Zen/Go show it in the web dashboard.',
|
|
3205
|
+
"cli.usage_no_key": "No API key configured for the active provider.",
|
|
3206
|
+
"cli.usage_error": "Failed to fetch balance: {error}",
|
|
3207
|
+
"cli.usage_key_usage": "Key usage: {usage}",
|
|
3208
|
+
"cli.usage_key_limit": "Key limit: {limit} · remaining {remaining}",
|
|
3209
|
+
"cli.usage_balance": "Balance: {balance}",
|
|
3210
|
+
"cli.usage_account": "Account: {credits} purchased · {used} used",
|
|
3211
|
+
"cli.usage_empty": "No balance information returned.",
|
|
3191
3212
|
"repl.ctrl_c_interrupt": `
|
|
3192
3213
|
[Ctrl+C] Stopping agent... (press again to force)`,
|
|
3193
3214
|
"exec.stop_directive": 'STOP. Step {stepId} ("{description}") took {iterations} iterations with no progress. DO NOT continue this step. Immediately call: plan update step={stepId} status=done (if code works despite warnings) OR plan update step={stepId} status=skipped note="reason". Do NOT make any other tool calls before updating the plan.',
|
|
@@ -3755,7 +3776,9 @@ var init_ru = __esm(() => {
|
|
|
3755
3776
|
"repl.provider_list": "Список настроенных провайдеров или горячая смена активного",
|
|
3756
3777
|
"repl.provider_current": "Текущий провайдер",
|
|
3757
3778
|
"repl.provider_set": "Провайдер установлен: {name}",
|
|
3758
|
-
"repl.provider_usage": "/provider list — записи (* = активный, prio = порядок fallback) | /provider use <имя> — смена без перезапуска",
|
|
3779
|
+
"repl.provider_usage": "/provider list — записи (* = активный, prio = порядок fallback) | /provider use <имя> — смена без перезапуска | /provider add <имя> [--url <url>] [--key <ключ>] [--priority <n>] [--context-window <n>] [--rpm <n>] [--parallel <n>] — добавить в конфиг",
|
|
3780
|
+
"repl.provider_add_missing_value": "Нет значения для {flag}",
|
|
3781
|
+
"repl.provider_switch_hint": "Переключитесь на него: /provider use {name}",
|
|
3759
3782
|
"repl.model_list": "Список моделей активного провайдера или смена модели",
|
|
3760
3783
|
"repl.model_current": "Текущая модель",
|
|
3761
3784
|
"repl.model_set": "Модель установлена: {name}",
|
|
@@ -4005,6 +4028,25 @@ var init_ru = __esm(() => {
|
|
|
4005
4028
|
"repl.cost": "Итого потрачено: {cost}",
|
|
4006
4029
|
"repl.cost_breakdown": "По провайдерам: {breakdown}",
|
|
4007
4030
|
"repl.tokens": "Потрачено токенов: {tokens}",
|
|
4031
|
+
"repl.cache": "Кеш: {hit}% попаданий · сэкономлено {saved}",
|
|
4032
|
+
"repl.cache_nosave": "Кеш: {hit}% попаданий",
|
|
4033
|
+
"repl.prefix": "Префикс стабилен: {stable}% · сломалось: {cause}",
|
|
4034
|
+
"cache.cause.system": "системный промпт",
|
|
4035
|
+
"cache.cause.tools": "набор инструментов",
|
|
4036
|
+
"cache.cause.history": "история",
|
|
4037
|
+
"cache.cause.volatile": "волатильное содержимое",
|
|
4038
|
+
"cache.cause.unknown": "неизвестно",
|
|
4039
|
+
"cli.session_usage": "API-использование: {prompt} prompt + {completion} completion = {total} токенов",
|
|
4040
|
+
"cli.session_cache": "Кеш: {hit}% попаданий ({cached} из кеша / {uncached} новых)",
|
|
4041
|
+
"cli.usage": "Показать баланс/расход провайдера (OpenRouter)",
|
|
4042
|
+
"cli.usage_unsupported": 'Провайдер "{provider}" не отдаёт баланс по API. Это умеет только OpenRouter; OpenCode Zen/Go показывают его в веб-дашборде.',
|
|
4043
|
+
"cli.usage_no_key": "Для активного провайдера не настроен API-ключ.",
|
|
4044
|
+
"cli.usage_error": "Не удалось получить баланс: {error}",
|
|
4045
|
+
"cli.usage_key_usage": "Расход по ключу: {usage}",
|
|
4046
|
+
"cli.usage_key_limit": "Лимит ключа: {limit} · осталось {remaining}",
|
|
4047
|
+
"cli.usage_balance": "Баланс: {balance}",
|
|
4048
|
+
"cli.usage_account": "Аккаунт: куплено {credits} · израсходовано {used}",
|
|
4049
|
+
"cli.usage_empty": "Провайдер не вернул данных о балансе.",
|
|
4008
4050
|
"repl.ctrl_c_interrupt": `
|
|
4009
4051
|
[Ctrl+C] Остановка агента... (ещё раз — принудительно)`,
|
|
4010
4052
|
"exec.stop_directive": 'STOP. Step {stepId} ("{description}") took {iterations} iterations with no progress. DO NOT continue this step. Immediately call: plan update step={stepId} status=done (if code works despite warnings) OR plan update step={stepId} status=skipped note="reason". Do NOT make any other tool calls before updating the plan.',
|
|
@@ -5893,6 +5935,73 @@ class StreamState {
|
|
|
5893
5935
|
}
|
|
5894
5936
|
}
|
|
5895
5937
|
|
|
5938
|
+
// src/llm/cache-usage.ts
|
|
5939
|
+
function num(value) {
|
|
5940
|
+
return typeof value === "number" && Number.isFinite(value) ? value : undefined;
|
|
5941
|
+
}
|
|
5942
|
+
function isRecord(value) {
|
|
5943
|
+
return typeof value === "object" && value !== null;
|
|
5944
|
+
}
|
|
5945
|
+
function parseCacheUsage(usage, format, estimatedPromptTokens) {
|
|
5946
|
+
if (!isRecord(usage))
|
|
5947
|
+
return;
|
|
5948
|
+
switch (format) {
|
|
5949
|
+
case "openai": {
|
|
5950
|
+
const details = usage.prompt_tokens_details;
|
|
5951
|
+
if (!isRecord(details))
|
|
5952
|
+
return;
|
|
5953
|
+
const cached = num(details.cached_tokens);
|
|
5954
|
+
if (cached === undefined)
|
|
5955
|
+
return;
|
|
5956
|
+
const prompt = num(usage.prompt_tokens) ?? cached;
|
|
5957
|
+
const write = num(details.cache_write_tokens) ?? 0;
|
|
5958
|
+
return {
|
|
5959
|
+
cachedTokens: cached,
|
|
5960
|
+
cacheWriteTokens: write,
|
|
5961
|
+
uncachedTokens: Math.max(0, prompt - cached),
|
|
5962
|
+
source: "api"
|
|
5963
|
+
};
|
|
5964
|
+
}
|
|
5965
|
+
case "deepseek": {
|
|
5966
|
+
const hit = num(usage.prompt_cache_hit_tokens);
|
|
5967
|
+
const miss = num(usage.prompt_cache_miss_tokens);
|
|
5968
|
+
if (hit === undefined && miss === undefined)
|
|
5969
|
+
return;
|
|
5970
|
+
return {
|
|
5971
|
+
cachedTokens: hit ?? 0,
|
|
5972
|
+
cacheWriteTokens: 0,
|
|
5973
|
+
uncachedTokens: miss ?? 0,
|
|
5974
|
+
source: "api"
|
|
5975
|
+
};
|
|
5976
|
+
}
|
|
5977
|
+
case "anthropic": {
|
|
5978
|
+
const read = num(usage.cache_read_input_tokens);
|
|
5979
|
+
const creation = num(usage.cache_creation_input_tokens);
|
|
5980
|
+
if (read === undefined && creation === undefined)
|
|
5981
|
+
return;
|
|
5982
|
+
return {
|
|
5983
|
+
cachedTokens: read ?? 0,
|
|
5984
|
+
cacheWriteTokens: creation ?? 0,
|
|
5985
|
+
uncachedTokens: num(usage.input_tokens) ?? 0,
|
|
5986
|
+
source: "api"
|
|
5987
|
+
};
|
|
5988
|
+
}
|
|
5989
|
+
case "ollama": {
|
|
5990
|
+
const evaluated = num(usage.prompt_eval_count);
|
|
5991
|
+
if (evaluated === undefined || estimatedPromptTokens === undefined)
|
|
5992
|
+
return;
|
|
5993
|
+
return {
|
|
5994
|
+
cachedTokens: Math.max(0, estimatedPromptTokens - evaluated),
|
|
5995
|
+
cacheWriteTokens: 0,
|
|
5996
|
+
uncachedTokens: evaluated,
|
|
5997
|
+
source: "derived"
|
|
5998
|
+
};
|
|
5999
|
+
}
|
|
6000
|
+
default:
|
|
6001
|
+
return;
|
|
6002
|
+
}
|
|
6003
|
+
}
|
|
6004
|
+
|
|
5896
6005
|
// src/llm/openai-compat.ts
|
|
5897
6006
|
var exports_openai_compat = {};
|
|
5898
6007
|
__export(exports_openai_compat, {
|
|
@@ -5911,6 +6020,14 @@ function buildRequestBody(opts) {
|
|
|
5911
6020
|
};
|
|
5912
6021
|
if (opts.maxTokens !== undefined)
|
|
5913
6022
|
body.max_tokens = opts.maxTokens;
|
|
6023
|
+
if (opts.cachePrompt)
|
|
6024
|
+
body.cache_prompt = true;
|
|
6025
|
+
if (opts.promptCacheKey)
|
|
6026
|
+
body.prompt_cache_key = opts.promptCacheKey;
|
|
6027
|
+
if (opts.sessionId)
|
|
6028
|
+
body.session_id = opts.sessionId;
|
|
6029
|
+
if (opts.stream && opts.streamUsage)
|
|
6030
|
+
body.stream_options = { include_usage: true };
|
|
5914
6031
|
const strategy = opts.reasoningStrategy ?? "openai-effort";
|
|
5915
6032
|
const level = opts.reasoningEffort;
|
|
5916
6033
|
if (strategy === "openai-effort" && level && level !== "default") {
|
|
@@ -5944,10 +6061,14 @@ class OpenAICompatProvider {
|
|
|
5944
6061
|
debug;
|
|
5945
6062
|
getSessionId;
|
|
5946
6063
|
userAgent;
|
|
6064
|
+
cache;
|
|
6065
|
+
cacheReport;
|
|
5947
6066
|
constructor(config) {
|
|
5948
6067
|
this.config = config;
|
|
5949
6068
|
this.model = config.model;
|
|
5950
6069
|
this.contextWindow = config.contextWindow ?? 32768;
|
|
6070
|
+
this.cache = config.cache;
|
|
6071
|
+
this.cacheReport = config.cache?.report ?? "openai";
|
|
5951
6072
|
this.tokenCounter = new TokenCounter;
|
|
5952
6073
|
this.retryConfig = config.retry ?? {
|
|
5953
6074
|
maxRetries: 3,
|
|
@@ -6050,7 +6171,8 @@ class OpenAICompatProvider {
|
|
|
6050
6171
|
stream: true,
|
|
6051
6172
|
maxTokens,
|
|
6052
6173
|
reasoningEffort: options?.reasoningEffort,
|
|
6053
|
-
reasoningStrategy: options?.reasoningStrategy
|
|
6174
|
+
reasoningStrategy: options?.reasoningStrategy,
|
|
6175
|
+
...this.cacheHints()
|
|
6054
6176
|
});
|
|
6055
6177
|
this.debug?.("LLM stream request", {
|
|
6056
6178
|
baseUrl: this.config.baseUrl,
|
|
@@ -6158,7 +6280,8 @@ class OpenAICompatProvider {
|
|
|
6158
6280
|
st.usage = {
|
|
6159
6281
|
promptTokens: parsed.usage.prompt_tokens ?? 0,
|
|
6160
6282
|
completionTokens: parsed.usage.completion_tokens ?? 0,
|
|
6161
|
-
totalTokens: parsed.usage.total_tokens ?? 0
|
|
6283
|
+
totalTokens: parsed.usage.total_tokens ?? 0,
|
|
6284
|
+
cache: parseCacheUsage(parsed.usage, this.cacheReport)
|
|
6162
6285
|
};
|
|
6163
6286
|
this.debug?.("LLM stream usage", { ...st.usage });
|
|
6164
6287
|
} else if (parsed.error) {
|
|
@@ -6246,6 +6369,15 @@ class OpenAICompatProvider {
|
|
|
6246
6369
|
}
|
|
6247
6370
|
return st.sawDone;
|
|
6248
6371
|
}
|
|
6372
|
+
cacheHints() {
|
|
6373
|
+
const sessionId = this.getSessionId?.();
|
|
6374
|
+
return {
|
|
6375
|
+
cachePrompt: this.cache?.requestCachePrompt === true,
|
|
6376
|
+
promptCacheKey: this.cache?.requestPromptCacheKey ? sessionId : undefined,
|
|
6377
|
+
sessionId: this.cache?.requestSessionId ? sessionId : undefined,
|
|
6378
|
+
streamUsage: this.cache?.requestStreamUsage === true
|
|
6379
|
+
};
|
|
6380
|
+
}
|
|
6249
6381
|
buildRequestSetup(signal) {
|
|
6250
6382
|
const headers = {
|
|
6251
6383
|
"Content-Type": "application/json",
|
|
@@ -6255,7 +6387,8 @@ class OpenAICompatProvider {
|
|
|
6255
6387
|
headers["Authorization"] = `Bearer ${this.config.apiKey}`;
|
|
6256
6388
|
}
|
|
6257
6389
|
const sessionId = this.getSessionId?.();
|
|
6258
|
-
|
|
6390
|
+
const sendSessionHeader = this.cache ? this.cache.sessionHeader : true;
|
|
6391
|
+
if (sessionId && sendSessionHeader)
|
|
6259
6392
|
headers["x-opencode-session"] = sessionId;
|
|
6260
6393
|
const controller = new AbortController;
|
|
6261
6394
|
let timedOut = false;
|
|
@@ -6294,7 +6427,8 @@ class OpenAICompatProvider {
|
|
|
6294
6427
|
stream: false,
|
|
6295
6428
|
maxTokens: options?.maxTokens ?? this.config.maxCompletionTokens ?? 4096,
|
|
6296
6429
|
reasoningEffort: options?.reasoningEffort,
|
|
6297
|
-
reasoningStrategy: options?.reasoningStrategy
|
|
6430
|
+
reasoningStrategy: options?.reasoningStrategy,
|
|
6431
|
+
...this.cacheHints()
|
|
6298
6432
|
});
|
|
6299
6433
|
const { headers, abortSignal, cleanup, isTimeout } = this.buildRequestSetup(signal);
|
|
6300
6434
|
try {
|
|
@@ -6347,7 +6481,8 @@ class OpenAICompatProvider {
|
|
|
6347
6481
|
usage: {
|
|
6348
6482
|
promptTokens: data.usage.prompt_tokens ?? 0,
|
|
6349
6483
|
completionTokens: data.usage.completion_tokens ?? 0,
|
|
6350
|
-
totalTokens: data.usage.total_tokens ?? 0
|
|
6484
|
+
totalTokens: data.usage.total_tokens ?? 0,
|
|
6485
|
+
cache: parseCacheUsage(data.usage, this.cacheReport)
|
|
6351
6486
|
}
|
|
6352
6487
|
});
|
|
6353
6488
|
}
|
|
@@ -6469,6 +6604,7 @@ function openaiCompat(opts) {
|
|
|
6469
6604
|
rateLimits,
|
|
6470
6605
|
maxCompletionTokens: opts.maxCompletionTokens,
|
|
6471
6606
|
getSessionId: opts.getSessionId,
|
|
6607
|
+
cache: opts.capabilities?.cache,
|
|
6472
6608
|
logger: opts.logger
|
|
6473
6609
|
});
|
|
6474
6610
|
}
|
|
@@ -6486,7 +6622,17 @@ var init_presets = __esm(() => {
|
|
|
6486
6622
|
reasoningStrategy: "prompt-tag",
|
|
6487
6623
|
listModels: true,
|
|
6488
6624
|
requiresKey: false,
|
|
6489
|
-
auth: "bearer"
|
|
6625
|
+
auth: "bearer",
|
|
6626
|
+
cache: {
|
|
6627
|
+
mechanism: "local",
|
|
6628
|
+
report: "openai",
|
|
6629
|
+
sessionHeader: false,
|
|
6630
|
+
requestCachePrompt: false,
|
|
6631
|
+
requestPromptCacheKey: false,
|
|
6632
|
+
requestSessionId: false,
|
|
6633
|
+
requestCacheControl: false,
|
|
6634
|
+
requestStreamUsage: true
|
|
6635
|
+
}
|
|
6490
6636
|
},
|
|
6491
6637
|
create: openaiCompat
|
|
6492
6638
|
};
|
|
@@ -6501,7 +6647,17 @@ var init_presets = __esm(() => {
|
|
|
6501
6647
|
reasoningStrategy: "openai-effort",
|
|
6502
6648
|
listModels: true,
|
|
6503
6649
|
requiresKey: true,
|
|
6504
|
-
auth: "bearer"
|
|
6650
|
+
auth: "bearer",
|
|
6651
|
+
cache: {
|
|
6652
|
+
mechanism: "auto",
|
|
6653
|
+
report: "openai",
|
|
6654
|
+
sessionHeader: false,
|
|
6655
|
+
requestCachePrompt: false,
|
|
6656
|
+
requestPromptCacheKey: false,
|
|
6657
|
+
requestSessionId: true,
|
|
6658
|
+
requestCacheControl: false,
|
|
6659
|
+
requestStreamUsage: true
|
|
6660
|
+
}
|
|
6505
6661
|
},
|
|
6506
6662
|
create: openaiCompat
|
|
6507
6663
|
};
|
|
@@ -6516,7 +6672,17 @@ var init_presets = __esm(() => {
|
|
|
6516
6672
|
reasoningStrategy: "openai-effort",
|
|
6517
6673
|
listModels: true,
|
|
6518
6674
|
requiresKey: true,
|
|
6519
|
-
auth: "bearer"
|
|
6675
|
+
auth: "bearer",
|
|
6676
|
+
cache: {
|
|
6677
|
+
mechanism: "auto",
|
|
6678
|
+
report: "openai",
|
|
6679
|
+
sessionHeader: false,
|
|
6680
|
+
requestCachePrompt: false,
|
|
6681
|
+
requestPromptCacheKey: true,
|
|
6682
|
+
requestSessionId: false,
|
|
6683
|
+
requestCacheControl: false,
|
|
6684
|
+
requestStreamUsage: true
|
|
6685
|
+
}
|
|
6520
6686
|
},
|
|
6521
6687
|
create: openaiCompat
|
|
6522
6688
|
};
|
|
@@ -6531,7 +6697,17 @@ var init_presets = __esm(() => {
|
|
|
6531
6697
|
reasoningStrategy: "none",
|
|
6532
6698
|
listModels: false,
|
|
6533
6699
|
requiresKey: true,
|
|
6534
|
-
auth: "header"
|
|
6700
|
+
auth: "header",
|
|
6701
|
+
cache: {
|
|
6702
|
+
mechanism: "explicit",
|
|
6703
|
+
report: "anthropic",
|
|
6704
|
+
sessionHeader: false,
|
|
6705
|
+
requestCachePrompt: false,
|
|
6706
|
+
requestPromptCacheKey: false,
|
|
6707
|
+
requestSessionId: false,
|
|
6708
|
+
requestCacheControl: true,
|
|
6709
|
+
requestStreamUsage: false
|
|
6710
|
+
}
|
|
6535
6711
|
},
|
|
6536
6712
|
create: openaiCompat
|
|
6537
6713
|
};
|
|
@@ -6546,7 +6722,17 @@ var init_presets = __esm(() => {
|
|
|
6546
6722
|
reasoningStrategy: "openai-effort",
|
|
6547
6723
|
listModels: true,
|
|
6548
6724
|
requiresKey: false,
|
|
6549
|
-
auth: "bearer"
|
|
6725
|
+
auth: "bearer",
|
|
6726
|
+
cache: {
|
|
6727
|
+
mechanism: "auto",
|
|
6728
|
+
report: "openai",
|
|
6729
|
+
sessionHeader: true,
|
|
6730
|
+
requestCachePrompt: false,
|
|
6731
|
+
requestPromptCacheKey: false,
|
|
6732
|
+
requestSessionId: false,
|
|
6733
|
+
requestCacheControl: false,
|
|
6734
|
+
requestStreamUsage: true
|
|
6735
|
+
}
|
|
6550
6736
|
},
|
|
6551
6737
|
create: openaiCompat
|
|
6552
6738
|
};
|
|
@@ -6561,7 +6747,17 @@ var init_presets = __esm(() => {
|
|
|
6561
6747
|
reasoningStrategy: "openai-effort",
|
|
6562
6748
|
listModels: true,
|
|
6563
6749
|
requiresKey: false,
|
|
6564
|
-
auth: "bearer"
|
|
6750
|
+
auth: "bearer",
|
|
6751
|
+
cache: {
|
|
6752
|
+
mechanism: "auto",
|
|
6753
|
+
report: "openai",
|
|
6754
|
+
sessionHeader: true,
|
|
6755
|
+
requestCachePrompt: false,
|
|
6756
|
+
requestPromptCacheKey: false,
|
|
6757
|
+
requestSessionId: false,
|
|
6758
|
+
requestCacheControl: false,
|
|
6759
|
+
requestStreamUsage: true
|
|
6760
|
+
}
|
|
6565
6761
|
},
|
|
6566
6762
|
create: openaiCompat
|
|
6567
6763
|
};
|
|
@@ -6624,6 +6820,25 @@ var init_create = __esm(() => {
|
|
|
6624
6820
|
init_presets();
|
|
6625
6821
|
});
|
|
6626
6822
|
|
|
6823
|
+
// src/modules/providers/cache.ts
|
|
6824
|
+
function resolveCacheCapability(spec, override) {
|
|
6825
|
+
const base = spec?.capabilities.cache ?? NO_CACHE_CAPABILITY;
|
|
6826
|
+
return { ...base, ...override ?? {} };
|
|
6827
|
+
}
|
|
6828
|
+
var NO_CACHE_CAPABILITY;
|
|
6829
|
+
var init_cache = __esm(() => {
|
|
6830
|
+
NO_CACHE_CAPABILITY = {
|
|
6831
|
+
mechanism: "none",
|
|
6832
|
+
report: "none",
|
|
6833
|
+
sessionHeader: false,
|
|
6834
|
+
requestCachePrompt: false,
|
|
6835
|
+
requestPromptCacheKey: false,
|
|
6836
|
+
requestSessionId: false,
|
|
6837
|
+
requestCacheControl: false,
|
|
6838
|
+
requestStreamUsage: false
|
|
6839
|
+
};
|
|
6840
|
+
});
|
|
6841
|
+
|
|
6627
6842
|
// src/modules/providers/manager.ts
|
|
6628
6843
|
class ProviderManager {
|
|
6629
6844
|
entries;
|
|
@@ -6747,17 +6962,25 @@ class ProviderManager {
|
|
|
6747
6962
|
rateLimits: entry.rateLimits ?? this.opts.rateLimits,
|
|
6748
6963
|
maxCompletionTokens: entry.maxCompletionTokens,
|
|
6749
6964
|
getSessionId: this.opts.getSessionId,
|
|
6965
|
+
capabilities: this.resolveCapabilities(entry),
|
|
6750
6966
|
logger: this.opts.logger
|
|
6751
6967
|
}, this.registry);
|
|
6752
6968
|
this.cache.set(key, provider);
|
|
6753
6969
|
return provider;
|
|
6754
6970
|
}
|
|
6971
|
+
resolveCapabilities(entry) {
|
|
6972
|
+
const spec = this.registry.get(entry.type);
|
|
6973
|
+
if (!spec)
|
|
6974
|
+
return { cache: resolveCacheCapability(undefined, entry.cache) };
|
|
6975
|
+
return { ...spec.capabilities, cache: resolveCacheCapability(spec, entry.cache) };
|
|
6976
|
+
}
|
|
6755
6977
|
resetCache() {
|
|
6756
6978
|
this.cache.clear();
|
|
6757
6979
|
}
|
|
6758
6980
|
}
|
|
6759
6981
|
var init_manager = __esm(() => {
|
|
6760
6982
|
init_create();
|
|
6983
|
+
init_cache();
|
|
6761
6984
|
init_presets();
|
|
6762
6985
|
});
|
|
6763
6986
|
|
|
@@ -8160,8 +8383,8 @@ function buildDiff(oldLines, newLines) {
|
|
|
8160
8383
|
return result;
|
|
8161
8384
|
}
|
|
8162
8385
|
function formatLine(line, maxNumWidth) {
|
|
8163
|
-
const
|
|
8164
|
-
const numStr =
|
|
8386
|
+
const num2 = line.type === "remove" ? line.oldNum : line.newNum;
|
|
8387
|
+
const numStr = num2 !== null ? String(num2).padStart(maxNumWidth) : " ".repeat(maxNumWidth);
|
|
8165
8388
|
if (line.type === "remove") {
|
|
8166
8389
|
return `${numStr} ${pc2.red("-")} ${line.content}`;
|
|
8167
8390
|
} else if (line.type === "add") {
|
|
@@ -10296,7 +10519,12 @@ class SessionLogger {
|
|
|
10296
10519
|
completionTokens: usage.completionTokens,
|
|
10297
10520
|
totalTokens: usage.totalTokens,
|
|
10298
10521
|
source: usage.source,
|
|
10299
|
-
durationMs: usage.durationMs
|
|
10522
|
+
durationMs: usage.durationMs,
|
|
10523
|
+
cacheStable: usage.prefix ? Number(usage.prefix.stableRatio.toFixed(4)) : undefined,
|
|
10524
|
+
cacheCause: usage.prefix?.cause,
|
|
10525
|
+
cachedTokens: usage.cache?.cachedTokens,
|
|
10526
|
+
cacheWriteTokens: usage.cache?.cacheWriteTokens,
|
|
10527
|
+
cacheSource: usage.cache?.source
|
|
10300
10528
|
});
|
|
10301
10529
|
}
|
|
10302
10530
|
logError(message) {
|
|
@@ -10946,52 +11174,52 @@ ${output}
|
|
|
10946
11174
|
}
|
|
10947
11175
|
function parseNumber() {
|
|
10948
11176
|
const start = i;
|
|
10949
|
-
let
|
|
11177
|
+
let num2 = "";
|
|
10950
11178
|
let invalid = false;
|
|
10951
11179
|
if (text[i] === "-") {
|
|
10952
|
-
|
|
11180
|
+
num2 += text[i];
|
|
10953
11181
|
i++;
|
|
10954
11182
|
if (!isDigit(text[i]) && atEndOfNumber()) {
|
|
10955
|
-
|
|
11183
|
+
num2 += "0";
|
|
10956
11184
|
}
|
|
10957
11185
|
}
|
|
10958
11186
|
if (text[i] === "0" && isDigit(text[i + 1])) {
|
|
10959
11187
|
invalid = true;
|
|
10960
11188
|
}
|
|
10961
11189
|
while (isDigit(text[i])) {
|
|
10962
|
-
|
|
11190
|
+
num2 += text[i];
|
|
10963
11191
|
i++;
|
|
10964
11192
|
}
|
|
10965
11193
|
if (text[i] === ".") {
|
|
10966
|
-
if (
|
|
10967
|
-
|
|
11194
|
+
if (num2 === "" || num2 === "-") {
|
|
11195
|
+
num2 += "0";
|
|
10968
11196
|
}
|
|
10969
|
-
|
|
11197
|
+
num2 += text[i];
|
|
10970
11198
|
i++;
|
|
10971
11199
|
if (!isDigit(text[i])) {
|
|
10972
|
-
|
|
11200
|
+
num2 += "0";
|
|
10973
11201
|
}
|
|
10974
11202
|
while (isDigit(text[i])) {
|
|
10975
|
-
|
|
11203
|
+
num2 += text[i];
|
|
10976
11204
|
i++;
|
|
10977
11205
|
}
|
|
10978
11206
|
}
|
|
10979
11207
|
if (i > start) {
|
|
10980
11208
|
if (text[i] === "e" || text[i] === "E") {
|
|
10981
|
-
if (
|
|
11209
|
+
if (num2 === "-") {
|
|
10982
11210
|
invalid = true;
|
|
10983
11211
|
}
|
|
10984
|
-
|
|
11212
|
+
num2 += text[i];
|
|
10985
11213
|
i++;
|
|
10986
11214
|
if (text[i] === "-" || text[i] === "+") {
|
|
10987
|
-
|
|
11215
|
+
num2 += text[i];
|
|
10988
11216
|
i++;
|
|
10989
11217
|
}
|
|
10990
11218
|
if (!isDigit(text[i])) {
|
|
10991
|
-
|
|
11219
|
+
num2 += "0";
|
|
10992
11220
|
}
|
|
10993
11221
|
while (isDigit(text[i])) {
|
|
10994
|
-
|
|
11222
|
+
num2 += text[i];
|
|
10995
11223
|
i++;
|
|
10996
11224
|
}
|
|
10997
11225
|
}
|
|
@@ -10999,7 +11227,7 @@ ${output}
|
|
|
10999
11227
|
i = start;
|
|
11000
11228
|
return false;
|
|
11001
11229
|
}
|
|
11002
|
-
output += invalid ? `"${text.substring(start, i)}"` :
|
|
11230
|
+
output += invalid ? `"${text.substring(start, i)}"` : num2;
|
|
11003
11231
|
return true;
|
|
11004
11232
|
}
|
|
11005
11233
|
return false;
|
|
@@ -12791,6 +13019,24 @@ var init_moe_executor = __esm(() => {
|
|
|
12791
13019
|
// src/modules/lsp/project-root.ts
|
|
12792
13020
|
import { existsSync as existsSync24 } from "fs";
|
|
12793
13021
|
import { dirname as dirname9, join as join14, relative as relative3, isAbsolute as isAbsolute3 } from "path";
|
|
13022
|
+
import { platform as platform4 } from "os";
|
|
13023
|
+
function resolveTscCommand(startDir, maxLevels = 8) {
|
|
13024
|
+
const runtime = process.execPath;
|
|
13025
|
+
let dir = startDir;
|
|
13026
|
+
for (let i = 0;i < maxLevels; i++) {
|
|
13027
|
+
const js = join14(dir, "node_modules", "typescript", "bin", "tsc");
|
|
13028
|
+
if (existsSync24(js))
|
|
13029
|
+
return `"${runtime}" "${js}"`;
|
|
13030
|
+
const stub = join14(dir, "node_modules", ".bin", platform4() === "win32" ? "tsc.cmd" : "tsc");
|
|
13031
|
+
if (existsSync24(stub))
|
|
13032
|
+
return `"${stub}"`;
|
|
13033
|
+
const parent = dirname9(dir);
|
|
13034
|
+
if (parent === dir)
|
|
13035
|
+
break;
|
|
13036
|
+
dir = parent;
|
|
13037
|
+
}
|
|
13038
|
+
return null;
|
|
13039
|
+
}
|
|
12794
13040
|
function findProjectRoot(filePath, baseDir, markers) {
|
|
12795
13041
|
if (!markers || markers.length === 0)
|
|
12796
13042
|
return baseDir;
|
|
@@ -13163,7 +13409,10 @@ function findTypecheckRoot(baseDir, existingFiles = []) {
|
|
|
13163
13409
|
return best?.root ?? null;
|
|
13164
13410
|
}
|
|
13165
13411
|
async function runTypecheck(baseDir) {
|
|
13166
|
-
const
|
|
13412
|
+
const tsc = resolveTscCommand(baseDir);
|
|
13413
|
+
if (!tsc)
|
|
13414
|
+
return null;
|
|
13415
|
+
const entry = processRegistry.start(`${tsc} --noEmit --skipLibCheck`, baseDir);
|
|
13167
13416
|
const exited = await processRegistry.waitForExit(entry.id, 90000);
|
|
13168
13417
|
const output = entry.log.join(`
|
|
13169
13418
|
`);
|
|
@@ -13176,6 +13425,7 @@ var SKIP_DIRS, TEST_EXT_RE, PY_TEST_RE, TEST_STEP_RE;
|
|
|
13176
13425
|
var init_audit_runners = __esm(() => {
|
|
13177
13426
|
init_bash();
|
|
13178
13427
|
init_processes();
|
|
13428
|
+
init_project_root();
|
|
13179
13429
|
SKIP_DIRS = new Set([
|
|
13180
13430
|
"node_modules",
|
|
13181
13431
|
".git",
|
|
@@ -13354,7 +13604,7 @@ var init_auditor = __esm(() => {
|
|
|
13354
13604
|
|
|
13355
13605
|
// src/modules/execution/verifier.ts
|
|
13356
13606
|
import { existsSync as existsSync27, readFileSync as readFileSync14 } from "fs";
|
|
13357
|
-
import { resolve as resolve13, extname as extname3, join as join17 } from "path";
|
|
13607
|
+
import { resolve as resolve13, extname as extname3, dirname as dirname11, join as join17 } from "path";
|
|
13358
13608
|
import { spawn as spawn4 } from "child_process";
|
|
13359
13609
|
|
|
13360
13610
|
class StepVerifier {
|
|
@@ -13386,8 +13636,11 @@ class StepVerifier {
|
|
|
13386
13636
|
if (!existsSync27(tsconfigPath)) {
|
|
13387
13637
|
return { passed: true, message: "No tsconfig.json found — skipping type check" };
|
|
13388
13638
|
}
|
|
13639
|
+
const tsc = resolveTscCommand(this.baseDir);
|
|
13640
|
+
if (!tsc)
|
|
13641
|
+
return { passed: true, message: "tsc not installed — skipping type check" };
|
|
13389
13642
|
try {
|
|
13390
|
-
await this.runAsync(
|
|
13643
|
+
await this.runAsync(`${tsc} --noEmit`, this.baseDir, 60000);
|
|
13391
13644
|
return { passed: true, message: "TypeScript type check passed" };
|
|
13392
13645
|
} catch (e) {
|
|
13393
13646
|
const stderr = e.stderr?.toString() || e.stdout?.toString() || e.message;
|
|
@@ -13400,8 +13653,11 @@ class StepVerifier {
|
|
|
13400
13653
|
if (!existsSync27(tsconfigPath)) {
|
|
13401
13654
|
return { passed: true, message: "No tsconfig.json found — skipping type check" };
|
|
13402
13655
|
}
|
|
13656
|
+
const tsc = resolveTscCommand(projectRoot);
|
|
13657
|
+
if (!tsc)
|
|
13658
|
+
return { passed: true, message: "tsc not installed — skipping type check" };
|
|
13403
13659
|
try {
|
|
13404
|
-
await this.runAsync(
|
|
13660
|
+
await this.runAsync(`${tsc} --noEmit --skipLibCheck`, projectRoot, 60000);
|
|
13405
13661
|
return { passed: true, message: "TypeScript type check passed" };
|
|
13406
13662
|
} catch (e) {
|
|
13407
13663
|
const stderr = e.stderr?.toString() || e.stdout?.toString() || e.message;
|
|
@@ -13554,8 +13810,11 @@ class StepVerifier {
|
|
|
13554
13810
|
async validateSyntax(filePath) {
|
|
13555
13811
|
const ext = extname3(filePath);
|
|
13556
13812
|
if (ext === ".ts" || ext === ".tsx" || ext === ".cts" || ext === ".mts") {
|
|
13813
|
+
const tsc = resolveTscCommand(dirname11(filePath));
|
|
13814
|
+
if (!tsc)
|
|
13815
|
+
return true;
|
|
13557
13816
|
try {
|
|
13558
|
-
await this.runAsync(
|
|
13817
|
+
await this.runAsync(`${tsc} --noEmit --skipLibCheck "${filePath}"`, this.baseDir, 20000);
|
|
13559
13818
|
return true;
|
|
13560
13819
|
} catch (err) {
|
|
13561
13820
|
if (err.status === 127 || err.message.includes("not found") || err.message.includes("ENOENT")) {
|
|
@@ -13885,11 +14144,18 @@ function resolvePrice(model, config) {
|
|
|
13885
14144
|
return direct;
|
|
13886
14145
|
return ZEN_PRICES[bare];
|
|
13887
14146
|
}
|
|
13888
|
-
function
|
|
14147
|
+
function calculateCostDetailed(model, promptTokens, completionTokens, config, cache) {
|
|
13889
14148
|
const price = resolvePrice(model, config);
|
|
13890
14149
|
if (!price)
|
|
13891
14150
|
return;
|
|
13892
|
-
|
|
14151
|
+
const cached = Math.max(0, cache?.cachedTokens ?? 0);
|
|
14152
|
+
const write = Math.max(0, cache?.cacheWriteTokens ?? 0);
|
|
14153
|
+
const uncached = Math.max(0, promptTokens - cached);
|
|
14154
|
+
const cachedRate = price.cachedInput ?? price.input;
|
|
14155
|
+
const writeRate = price.cacheWrite ?? 0;
|
|
14156
|
+
const cost = uncached / 1e6 * price.input + cached / 1e6 * cachedRate + write / 1e6 * writeRate + completionTokens / 1e6 * price.output;
|
|
14157
|
+
const saved = cached / 1e6 * (price.input - cachedRate);
|
|
14158
|
+
return { cost, saved };
|
|
13893
14159
|
}
|
|
13894
14160
|
function formatCost(cost) {
|
|
13895
14161
|
if (cost === 0)
|
|
@@ -13909,12 +14175,12 @@ var init_prices = __esm(() => {
|
|
|
13909
14175
|
"nemotron-3-ultra-free": { input: 0, output: 0 },
|
|
13910
14176
|
"nemotron-3.5-lightning-free": { input: 0, output: 0 },
|
|
13911
14177
|
"muse-spark-1.2-contributor-free": { input: 0, output: 0 },
|
|
13912
|
-
"minimax-m3": { input: 0.3, output: 1.2 },
|
|
13913
|
-
"minimax-m2.7": { input: 0.3, output: 1.2 },
|
|
13914
|
-
"minimax-m2.5": { input: 0.3, output: 1.2 },
|
|
13915
|
-
"glm-5.2": { input: 1.4, output: 4.4 },
|
|
13916
|
-
"glm-5.1": { input: 1.4, output: 4.4 },
|
|
13917
|
-
"glm-5": { input: 1, output: 3.2 },
|
|
14178
|
+
"minimax-m3": { input: 0.3, output: 1.2, cachedInput: 0.06 },
|
|
14179
|
+
"minimax-m2.7": { input: 0.3, output: 1.2, cachedInput: 0.06 },
|
|
14180
|
+
"minimax-m2.5": { input: 0.3, output: 1.2, cachedInput: 0.06 },
|
|
14181
|
+
"glm-5.2": { input: 1.4, output: 4.4, cachedInput: 0.26 },
|
|
14182
|
+
"glm-5.1": { input: 1.4, output: 4.4, cachedInput: 0.26 },
|
|
14183
|
+
"glm-5": { input: 1, output: 3.2, cachedInput: 0.2 },
|
|
13918
14184
|
"glm-5.3": { input: 1.4, output: 4.4 },
|
|
13919
14185
|
"kimi-k2.7-code": { input: 0.95, output: 4 },
|
|
13920
14186
|
"kimi-k3": { input: 3, output: 15 },
|
|
@@ -13976,6 +14242,7 @@ class CostTracker {
|
|
|
13976
14242
|
config;
|
|
13977
14243
|
model;
|
|
13978
14244
|
_total = 0;
|
|
14245
|
+
_saved = 0;
|
|
13979
14246
|
_known = false;
|
|
13980
14247
|
byProvider = new Map;
|
|
13981
14248
|
constructor(model, config) {
|
|
@@ -13985,24 +14252,28 @@ class CostTracker {
|
|
|
13985
14252
|
setModel(model) {
|
|
13986
14253
|
this.model = model;
|
|
13987
14254
|
}
|
|
13988
|
-
record(promptTokens, completionTokens, provider) {
|
|
14255
|
+
record(promptTokens, completionTokens, provider, cache) {
|
|
13989
14256
|
const key = provider || "unknown";
|
|
13990
|
-
const
|
|
13991
|
-
if (
|
|
14257
|
+
const result = calculateCostDetailed(this.model, promptTokens, completionTokens, this.config, cache);
|
|
14258
|
+
if (!result)
|
|
13992
14259
|
return;
|
|
13993
14260
|
this._known = true;
|
|
13994
|
-
this._total += cost;
|
|
14261
|
+
this._total += result.cost;
|
|
14262
|
+
this._saved += result.saved;
|
|
13995
14263
|
let entry = this.byProvider.get(key);
|
|
13996
14264
|
if (!entry) {
|
|
13997
14265
|
entry = { total: 0, known: false };
|
|
13998
14266
|
this.byProvider.set(key, entry);
|
|
13999
14267
|
}
|
|
14000
14268
|
entry.known = true;
|
|
14001
|
-
entry.total += cost;
|
|
14269
|
+
entry.total += result.cost;
|
|
14002
14270
|
}
|
|
14003
14271
|
get total() {
|
|
14004
14272
|
return this._known ? this._total : undefined;
|
|
14005
14273
|
}
|
|
14274
|
+
get saved() {
|
|
14275
|
+
return this._known ? this._saved : undefined;
|
|
14276
|
+
}
|
|
14006
14277
|
totalFor(provider) {
|
|
14007
14278
|
const entry = this.byProvider.get(provider);
|
|
14008
14279
|
return entry && entry.known ? entry.total : undefined;
|
|
@@ -14083,6 +14354,10 @@ function createLoopState() {
|
|
|
14083
14354
|
apiCompletionChars: 0,
|
|
14084
14355
|
estimatedPromptTokensTotal: 0,
|
|
14085
14356
|
totalLlmDuration: 0,
|
|
14357
|
+
cacheCachedTotal: 0,
|
|
14358
|
+
cacheUncachedTotal: 0,
|
|
14359
|
+
cacheWriteTotal: 0,
|
|
14360
|
+
cacheSource: "none",
|
|
14086
14361
|
auditRetries: 0,
|
|
14087
14362
|
lastAuditSummary: "",
|
|
14088
14363
|
emptyResponseRetries: 0,
|
|
@@ -14189,6 +14464,7 @@ class TokenTracker {
|
|
|
14189
14464
|
}
|
|
14190
14465
|
beginIteration(state, estimatedPromptTokens) {
|
|
14191
14466
|
state.estimatedPromptTokensTotal += estimatedPromptTokens;
|
|
14467
|
+
state.cacheUsage = undefined;
|
|
14192
14468
|
return {
|
|
14193
14469
|
promptBefore: state.apiPromptTokens,
|
|
14194
14470
|
completionBefore: state.apiCompletionTokens
|
|
@@ -14197,6 +14473,7 @@ class TokenTracker {
|
|
|
14197
14473
|
recordApiUsage(state, baseline, usage) {
|
|
14198
14474
|
state.apiPromptTokens = baseline.promptBefore + usage.promptTokens;
|
|
14199
14475
|
state.apiCompletionTokens = baseline.completionBefore + usage.completionTokens;
|
|
14476
|
+
state.cacheUsage = usage.cache;
|
|
14200
14477
|
}
|
|
14201
14478
|
addCompletionChars(state, chars) {
|
|
14202
14479
|
state.apiCompletionChars += chars;
|
|
@@ -14207,14 +14484,22 @@ class TokenTracker {
|
|
|
14207
14484
|
const source = usagePrompt > 0 || usageCompletion > 0 ? "api" : "estimate";
|
|
14208
14485
|
const prompt = source === "api" ? usagePrompt : contextTokens;
|
|
14209
14486
|
const completion = source === "api" ? usageCompletion : estimateTokens(textContent);
|
|
14487
|
+
if (state.cacheUsage) {
|
|
14488
|
+
state.cacheCachedTotal += state.cacheUsage.cachedTokens;
|
|
14489
|
+
state.cacheUncachedTotal += state.cacheUsage.uncachedTokens;
|
|
14490
|
+
state.cacheWriteTotal += state.cacheUsage.cacheWriteTokens;
|
|
14491
|
+
state.cacheSource = state.cacheUsage.source;
|
|
14492
|
+
}
|
|
14210
14493
|
slog.logLlmUsage(iteration, {
|
|
14211
14494
|
promptTokens: prompt,
|
|
14212
14495
|
completionTokens: completion,
|
|
14213
14496
|
totalTokens: prompt + completion,
|
|
14214
14497
|
source,
|
|
14215
|
-
durationMs
|
|
14498
|
+
durationMs,
|
|
14499
|
+
prefix: state.prefixDelta,
|
|
14500
|
+
cache: state.cacheUsage
|
|
14216
14501
|
});
|
|
14217
|
-
this.costTracker.record(prompt, completion, this.getProviderName());
|
|
14502
|
+
this.costTracker.record(prompt, completion, this.getProviderName(), source === "api" ? state.cacheUsage : undefined);
|
|
14218
14503
|
}
|
|
14219
14504
|
resolveFinal(state) {
|
|
14220
14505
|
if (state.apiPromptTokens > 0 || state.apiCompletionTokens > 0) {
|
|
@@ -14233,6 +14518,75 @@ var init_token_tracker = __esm(() => {
|
|
|
14233
14518
|
init_token_counter();
|
|
14234
14519
|
});
|
|
14235
14520
|
|
|
14521
|
+
// src/core/agent/prefix-monitor.ts
|
|
14522
|
+
function serializeTools(tools) {
|
|
14523
|
+
return tools.map((t2) => `${t2.name}\x01${t2.description}\x01${JSON.stringify(t2.parameters)}`).join("\x02");
|
|
14524
|
+
}
|
|
14525
|
+
function serializeMessages(messages) {
|
|
14526
|
+
return messages.map((m) => `${m.role}\x01${typeof m.content === "string" ? m.content : JSON.stringify(m.content)}`).join("\x02");
|
|
14527
|
+
}
|
|
14528
|
+
function buildPromptSnapshot(messages, tools) {
|
|
14529
|
+
const system = [];
|
|
14530
|
+
const rest = [];
|
|
14531
|
+
for (const m of messages) {
|
|
14532
|
+
if (m.role === "system")
|
|
14533
|
+
system.push(m);
|
|
14534
|
+
else
|
|
14535
|
+
rest.push(m);
|
|
14536
|
+
}
|
|
14537
|
+
return {
|
|
14538
|
+
system: serializeMessages(system),
|
|
14539
|
+
tools: serializeTools(tools),
|
|
14540
|
+
history: serializeMessages(rest)
|
|
14541
|
+
};
|
|
14542
|
+
}
|
|
14543
|
+
function frame(s) {
|
|
14544
|
+
const full = s.system + SEP + s.tools + SEP + s.history;
|
|
14545
|
+
const toolsStart = s.system.length + SEP.length;
|
|
14546
|
+
const historyStart = toolsStart + s.tools.length + SEP.length;
|
|
14547
|
+
return { full, toolsStart, historyStart };
|
|
14548
|
+
}
|
|
14549
|
+
function diffPrompt(prev, curr, countTokens) {
|
|
14550
|
+
const c = frame(curr);
|
|
14551
|
+
const currTokens = countTokens(c.full);
|
|
14552
|
+
if (!prev) {
|
|
14553
|
+
return {
|
|
14554
|
+
prevTokens: 0,
|
|
14555
|
+
currTokens,
|
|
14556
|
+
commonPrefixTokens: 0,
|
|
14557
|
+
stableRatio: 0,
|
|
14558
|
+
cause: "unknown"
|
|
14559
|
+
};
|
|
14560
|
+
}
|
|
14561
|
+
const p = frame(prev);
|
|
14562
|
+
const prevTokens = countTokens(p.full);
|
|
14563
|
+
const maxCp = Math.min(p.full.length, c.full.length);
|
|
14564
|
+
let cp = 0;
|
|
14565
|
+
while (cp < maxCp && p.full[cp] === c.full[cp])
|
|
14566
|
+
cp++;
|
|
14567
|
+
const commonPrefixTokens = countTokens(c.full.slice(0, cp));
|
|
14568
|
+
const stableRatio = currTokens === 0 ? 0 : Math.min(1, commonPrefixTokens / currTokens);
|
|
14569
|
+
if (cp === maxCp) {
|
|
14570
|
+
return { prevTokens, currTokens, commonPrefixTokens, stableRatio, cause: "none" };
|
|
14571
|
+
}
|
|
14572
|
+
let cause;
|
|
14573
|
+
if (cp >= c.historyStart)
|
|
14574
|
+
cause = "history";
|
|
14575
|
+
else if (cp >= c.toolsStart)
|
|
14576
|
+
cause = "tools";
|
|
14577
|
+
else
|
|
14578
|
+
cause = "system";
|
|
14579
|
+
const window = c.full.slice(Math.max(0, cp - 40), cp + 160) + p.full.slice(Math.max(0, cp - 40), cp + 160);
|
|
14580
|
+
if (VOLATILE_RE.test(window))
|
|
14581
|
+
cause = "volatile";
|
|
14582
|
+
return { prevTokens, currTokens, commonPrefixTokens, stableRatio, cause };
|
|
14583
|
+
}
|
|
14584
|
+
var SEP = `
|
|
14585
|
+
`, VOLATILE_RE;
|
|
14586
|
+
var init_prefix_monitor = __esm(() => {
|
|
14587
|
+
VOLATILE_RE = /(\d{4}-\d{2}-\d{2}|\d{2}:\d{2}:\d{2}|[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}|[A-Za-z]:\\|\\AppData\\|\\Temp\\|\/tmp\/)/;
|
|
14588
|
+
});
|
|
14589
|
+
|
|
14236
14590
|
// src/core/agent/reasoning-resolver.ts
|
|
14237
14591
|
class ReasoningEffortResolver {
|
|
14238
14592
|
resolve(deps) {
|
|
@@ -15261,6 +15615,12 @@ class Agent {
|
|
|
15261
15615
|
compactionService.compactIfNeeded(state);
|
|
15262
15616
|
this.refreshSystemPrompt();
|
|
15263
15617
|
const history = contextManager.getActiveHistory();
|
|
15618
|
+
const promptSnapshot = buildPromptSnapshot(history, allToolsForBudget);
|
|
15619
|
+
state.prefixDelta = diffPrompt(state.prevPrompt, promptSnapshot, estimateTokens);
|
|
15620
|
+
state.prevPrompt = promptSnapshot;
|
|
15621
|
+
if (state.prefixDelta.cause === "system" || state.prefixDelta.cause === "tools" || state.prefixDelta.cause === "history" || state.prefixDelta.cause === "volatile") {
|
|
15622
|
+
state.lastPrefixBreak = state.prefixDelta;
|
|
15623
|
+
}
|
|
15264
15624
|
slog.logToolDefs(allToolsForBudget.length, allToolsForBudget.map((t2) => t2.name), state.iteration);
|
|
15265
15625
|
if (state.iteration === 1) {
|
|
15266
15626
|
const { blocks } = this.buildSystemPrompt();
|
|
@@ -15509,6 +15869,7 @@ class Agent {
|
|
|
15509
15869
|
const tokensUsed = contextManager.getEstimatedTokens();
|
|
15510
15870
|
const budget = contextManager.getBudget();
|
|
15511
15871
|
const usageTokens = tokenTracker.resolveFinal(state);
|
|
15872
|
+
const cacheStats = this.buildCacheStats(state);
|
|
15512
15873
|
if (state.iteration >= config.maxToolIterations && !state.finalAnswerAccepted) {
|
|
15513
15874
|
return {
|
|
15514
15875
|
success: false,
|
|
@@ -15522,6 +15883,7 @@ class Agent {
|
|
|
15522
15883
|
totalTokens: usageTokens.total,
|
|
15523
15884
|
totalCost: this.costTracker.total,
|
|
15524
15885
|
costBreakdown: this.costTracker.breakdown(),
|
|
15886
|
+
cache: cacheStats,
|
|
15525
15887
|
compactionCount: contextManager.getCompactionCount(),
|
|
15526
15888
|
contextQuality: contextManager.getQuality()
|
|
15527
15889
|
};
|
|
@@ -15538,11 +15900,29 @@ class Agent {
|
|
|
15538
15900
|
totalTokens: usageTokens.total,
|
|
15539
15901
|
totalCost: this.costTracker.total,
|
|
15540
15902
|
costBreakdown: this.costTracker.breakdown(),
|
|
15903
|
+
cache: cacheStats,
|
|
15541
15904
|
compactionCount: contextManager.getCompactionCount(),
|
|
15542
15905
|
contextQuality: contextManager.getQuality(),
|
|
15543
15906
|
llmDurationMs: state.totalLlmDuration
|
|
15544
15907
|
};
|
|
15545
15908
|
}
|
|
15909
|
+
buildCacheStats(state) {
|
|
15910
|
+
const hasTokens = state.cacheCachedTotal > 0 || state.cacheUncachedTotal > 0 || state.cacheWriteTotal > 0;
|
|
15911
|
+
const prefix = state.lastPrefixBreak ?? state.prefixDelta;
|
|
15912
|
+
if (!hasTokens && prefix?.stableRatio === undefined)
|
|
15913
|
+
return;
|
|
15914
|
+
const denom = state.cacheCachedTotal + state.cacheUncachedTotal;
|
|
15915
|
+
return {
|
|
15916
|
+
cachedTokens: state.cacheCachedTotal,
|
|
15917
|
+
uncachedTokens: state.cacheUncachedTotal,
|
|
15918
|
+
cacheWriteTokens: state.cacheWriteTotal,
|
|
15919
|
+
hitRate: denom > 0 ? state.cacheCachedTotal / denom : 0,
|
|
15920
|
+
saved: this.costTracker.saved,
|
|
15921
|
+
prefixStable: prefix?.stableRatio,
|
|
15922
|
+
prefixCause: prefix?.cause,
|
|
15923
|
+
source: state.cacheSource
|
|
15924
|
+
};
|
|
15925
|
+
}
|
|
15546
15926
|
clearContext() {
|
|
15547
15927
|
this.deps.contextManager.clear();
|
|
15548
15928
|
this.systemPromptAdded = false;
|
|
@@ -15647,6 +16027,7 @@ var init_agent = __esm(() => {
|
|
|
15647
16027
|
init_loop_state();
|
|
15648
16028
|
init_compaction();
|
|
15649
16029
|
init_token_tracker();
|
|
16030
|
+
init_prefix_monitor();
|
|
15650
16031
|
init_reasoning_resolver();
|
|
15651
16032
|
init_context_renderer();
|
|
15652
16033
|
init_tool_batch();
|
|
@@ -16538,8 +16919,8 @@ var init_detector = __esm(() => {
|
|
|
16538
16919
|
// src/modules/lsp/command.ts
|
|
16539
16920
|
import { delimiter, join as join21 } from "path";
|
|
16540
16921
|
import { existsSync as existsSync30 } from "fs";
|
|
16541
|
-
import { platform as
|
|
16542
|
-
function resolveSpawnCommand(command, platformName =
|
|
16922
|
+
import { platform as platform5 } from "os";
|
|
16923
|
+
function resolveSpawnCommand(command, platformName = platform5(), pathEnv = process.env.PATH ?? "") {
|
|
16543
16924
|
if (platformName !== "win32")
|
|
16544
16925
|
return command;
|
|
16545
16926
|
if (command.includes("/") || command.includes("\\") || WIN_EXTS.some((ext) => command.toLowerCase().endsWith(ext))) {
|
|
@@ -16571,7 +16952,7 @@ var init_command = __esm(() => {
|
|
|
16571
16952
|
});
|
|
16572
16953
|
|
|
16573
16954
|
// src/modules/updater/checker.ts
|
|
16574
|
-
import { platform as
|
|
16955
|
+
import { platform as platform6 } from "os";
|
|
16575
16956
|
function semverGt(a, b) {
|
|
16576
16957
|
const pa = a.replace(/^v/, "").split(/[.-]/).map((p) => Number.parseInt(p, 10) || 0);
|
|
16577
16958
|
const pb = b.replace(/^v/, "").split(/[.-]/).map((p) => Number.parseInt(p, 10) || 0);
|
|
@@ -16642,7 +17023,7 @@ class Updater {
|
|
|
16642
17023
|
buildInstallCommand(latest) {
|
|
16643
17024
|
const npmArgs = ["install", "-g", `${this.packageName}@${latest}`];
|
|
16644
17025
|
const command = resolveSpawnCommand("npm");
|
|
16645
|
-
if (
|
|
17026
|
+
if (platform6() === "win32" && /\.(cmd|bat)$/i.test(command)) {
|
|
16646
17027
|
return { command: "cmd.exe", args: ["/c", command, ...npmArgs] };
|
|
16647
17028
|
}
|
|
16648
17029
|
return { command, args: npmArgs };
|
|
@@ -20167,11 +20548,11 @@ async function readClipboardImage() {
|
|
|
20167
20548
|
return readClipboardFallback();
|
|
20168
20549
|
}
|
|
20169
20550
|
async function readClipboardFallback() {
|
|
20170
|
-
const { platform:
|
|
20551
|
+
const { platform: platform7 } = await import("os");
|
|
20171
20552
|
const { execSync } = await import("child_process");
|
|
20172
20553
|
const { readFileSync: readFileSync21, unlinkSync: unlinkSync5 } = await import("fs");
|
|
20173
20554
|
const { join: join30 } = await import("path");
|
|
20174
|
-
if (
|
|
20555
|
+
if (platform7() !== "linux")
|
|
20175
20556
|
return null;
|
|
20176
20557
|
const tmpPath = join30(process.env.TEMP || process.env.TMP || "/tmp", `mma-clip-${Date.now()}.png`);
|
|
20177
20558
|
const commands = [
|
|
@@ -20847,7 +21228,7 @@ var init_auto_fixer = __esm(() => {
|
|
|
20847
21228
|
import { spawn as spawn7, execSync } from "child_process";
|
|
20848
21229
|
import { existsSync as existsSync37, readFileSync as readFileSync21, writeFileSync as writeFileSync13 } from "fs";
|
|
20849
21230
|
import { resolve as resolve17, extname as extname6, join as join31 } from "path";
|
|
20850
|
-
import { platform as
|
|
21231
|
+
import { platform as platform7 } from "os";
|
|
20851
21232
|
function lintCacheKey(baseDir, lintScript) {
|
|
20852
21233
|
return `${baseDir}::${lintScript}`;
|
|
20853
21234
|
}
|
|
@@ -20868,7 +21249,7 @@ function contentHash2(content) {
|
|
|
20868
21249
|
function getWinDecoder() {
|
|
20869
21250
|
if (_winDecoder !== undefined)
|
|
20870
21251
|
return _winDecoder;
|
|
20871
|
-
if (
|
|
21252
|
+
if (platform7() !== "win32") {
|
|
20872
21253
|
_winDecoder = new TextDecoder("utf-8");
|
|
20873
21254
|
return _winDecoder;
|
|
20874
21255
|
}
|
|
@@ -21029,6 +21410,10 @@ ${stdout}`;
|
|
|
21029
21410
|
if (!existsSync37(tsconfigPath)) {
|
|
21030
21411
|
return;
|
|
21031
21412
|
}
|
|
21413
|
+
const tsc = resolveTscCommand(projectRoot);
|
|
21414
|
+
if (!tsc) {
|
|
21415
|
+
return;
|
|
21416
|
+
}
|
|
21032
21417
|
const now = Date.now();
|
|
21033
21418
|
if (this._checkPromise && now - this._checkTimestamp < TYPE_CHECK_DEBOUNCE_MS) {
|
|
21034
21419
|
const error2 = await this._checkPromise;
|
|
@@ -21040,10 +21425,10 @@ ${stdout}`;
|
|
|
21040
21425
|
return;
|
|
21041
21426
|
}
|
|
21042
21427
|
this._checkTimestamp = now;
|
|
21043
|
-
this._checkPromise = this.runTscCheck(projectRoot, signal);
|
|
21428
|
+
this._checkPromise = this.runTscCheck(tsc, projectRoot, signal);
|
|
21044
21429
|
const error = await this._checkPromise;
|
|
21045
21430
|
if (error) {
|
|
21046
|
-
const { stdout, stderr } = await runAsync(
|
|
21431
|
+
const { stdout, stderr } = await runAsync(`${tsc} --noEmit --skipLibCheck 2>&1`, projectRoot, 30000, signal).catch(() => ({ stdout: "", stderr: error }));
|
|
21047
21432
|
const output = stderr || stdout;
|
|
21048
21433
|
const errors = parseTscOutput(output);
|
|
21049
21434
|
if (errors.length > 0) {
|
|
@@ -21072,9 +21457,9 @@ ${stdout}`;
|
|
|
21072
21457
|
}
|
|
21073
21458
|
}
|
|
21074
21459
|
}
|
|
21075
|
-
async runTscCheck(baseDir, signal) {
|
|
21460
|
+
async runTscCheck(tsc, baseDir, signal) {
|
|
21076
21461
|
try {
|
|
21077
|
-
const { stdout, stderr } = await runAsync(
|
|
21462
|
+
const { stdout, stderr } = await runAsync(`${tsc} --noEmit --skipLibCheck`, baseDir, 30000, signal);
|
|
21078
21463
|
return null;
|
|
21079
21464
|
} catch (err) {
|
|
21080
21465
|
if (err.status === 127 || err.message.includes("not found") || err.message.includes("ENOENT")) {
|
|
@@ -21560,7 +21945,7 @@ function switchStepToDelete(plan, step, save) {
|
|
|
21560
21945
|
}
|
|
21561
21946
|
|
|
21562
21947
|
// src/modules/execution/execution-plugin.ts
|
|
21563
|
-
import { platform as
|
|
21948
|
+
import { platform as platform8 } from "os";
|
|
21564
21949
|
function normalizeBrokenPath(p) {
|
|
21565
21950
|
return toForwardSlash(p).replace(/^\.\//, "");
|
|
21566
21951
|
}
|
|
@@ -21793,7 +22178,7 @@ Last compile error: ${first[1]}`;
|
|
|
21793
22178
|
if (call.name === "bash") {
|
|
21794
22179
|
deps.stuckDetector.recordBashAttempt(false);
|
|
21795
22180
|
}
|
|
21796
|
-
if (call.name === "bash" &&
|
|
22181
|
+
if (call.name === "bash" && platform8() === "win32") {
|
|
21797
22182
|
const cmd = String(call.arguments?.command ?? "");
|
|
21798
22183
|
const forbidden = forbiddenWindowsCommand(cmd);
|
|
21799
22184
|
if (forbidden) {
|
|
@@ -23687,7 +24072,7 @@ class ProfileCompressor {
|
|
|
23687
24072
|
// src/modules/user-profile/profile.ts
|
|
23688
24073
|
import { readFileSync as readFileSync26, writeFileSync as writeFileSync17, existsSync as existsSync42, mkdirSync as mkdirSync18 } from "fs";
|
|
23689
24074
|
import { join as join35 } from "path";
|
|
23690
|
-
import { homedir as homedir10, hostname, platform as
|
|
24075
|
+
import { homedir as homedir10, hostname, platform as platform9, type } from "os";
|
|
23691
24076
|
import { env } from "process";
|
|
23692
24077
|
|
|
23693
24078
|
class UserProfile {
|
|
@@ -23699,7 +24084,7 @@ class UserProfile {
|
|
|
23699
24084
|
}
|
|
23700
24085
|
collect() {
|
|
23701
24086
|
this.info = {
|
|
23702
|
-
platform:
|
|
24087
|
+
platform: platform9(),
|
|
23703
24088
|
os: `${type()} ${hostname()}`,
|
|
23704
24089
|
hostname: hostname(),
|
|
23705
24090
|
shell: env.SHELL || env.ComSpec || "unknown",
|
|
@@ -24021,7 +24406,7 @@ var init_browser2 = __esm(() => {
|
|
|
24021
24406
|
// src/modules/lsp/client.ts
|
|
24022
24407
|
import { spawn as spawn8, execSync as execSync2 } from "child_process";
|
|
24023
24408
|
import { resolve as resolve19 } from "path";
|
|
24024
|
-
import { platform as
|
|
24409
|
+
import { platform as platform10 } from "os";
|
|
24025
24410
|
|
|
24026
24411
|
class FileOnlyLogger {
|
|
24027
24412
|
logger;
|
|
@@ -24141,7 +24526,7 @@ class LspClient {
|
|
|
24141
24526
|
if (config.command === "npx" && effectiveArgs.length > 0) {
|
|
24142
24527
|
const binaryName = this.extractBinaryFromNpxArgs(effectiveArgs);
|
|
24143
24528
|
if (binaryName) {
|
|
24144
|
-
const whichCmd =
|
|
24529
|
+
const whichCmd = platform10() === "win32" ? `where ${binaryName}` : `which ${binaryName}`;
|
|
24145
24530
|
try {
|
|
24146
24531
|
execSync2(whichCmd, { stdio: "pipe", timeout: 3000 });
|
|
24147
24532
|
effectiveCommand = binaryName;
|
|
@@ -24154,7 +24539,7 @@ class LspClient {
|
|
|
24154
24539
|
}
|
|
24155
24540
|
return new Promise((resolve20, reject) => {
|
|
24156
24541
|
const args = effectiveArgs;
|
|
24157
|
-
const isWin =
|
|
24542
|
+
const isWin = platform10() === "win32";
|
|
24158
24543
|
let spawnCommand = resolveSpawnCommand(effectiveCommand);
|
|
24159
24544
|
let spawnArgs = args;
|
|
24160
24545
|
const spawnOpts = {
|
|
@@ -24760,8 +25145,11 @@ async function runCheck(config, baseDir, deps) {
|
|
|
24760
25145
|
return { lines: lines.slice(0, STARTUP_CHECK_ERROR_CAP) };
|
|
24761
25146
|
}
|
|
24762
25147
|
async function runTscDefault(projectRoot, timeoutMs) {
|
|
25148
|
+
const tsc = resolveTscCommand(projectRoot);
|
|
25149
|
+
if (!tsc)
|
|
25150
|
+
return [];
|
|
24763
25151
|
return new Promise((resolve22) => {
|
|
24764
|
-
const child = spawn9(
|
|
25152
|
+
const child = spawn9(`${tsc} --noEmit --skipLibCheck`, {
|
|
24765
25153
|
cwd: projectRoot,
|
|
24766
25154
|
shell: true,
|
|
24767
25155
|
windowsHide: true,
|
|
@@ -25165,7 +25553,7 @@ class IndexCache {
|
|
|
25165
25553
|
}
|
|
25166
25554
|
}
|
|
25167
25555
|
}
|
|
25168
|
-
var
|
|
25556
|
+
var init_cache2 = () => {};
|
|
25169
25557
|
|
|
25170
25558
|
// src/modules/indexer/map-select.ts
|
|
25171
25559
|
function isNoiseFile(file) {
|
|
@@ -25637,7 +26025,7 @@ ${stackLine}` : summary;
|
|
|
25637
26025
|
var MAP_FILE_LIMIT = 80;
|
|
25638
26026
|
var init_module6 = __esm(() => {
|
|
25639
26027
|
init_walker();
|
|
25640
|
-
|
|
26028
|
+
init_cache2();
|
|
25641
26029
|
init_map_select();
|
|
25642
26030
|
init_project_profile();
|
|
25643
26031
|
init_i18n();
|
|
@@ -25648,7 +26036,7 @@ var init_module6 = __esm(() => {
|
|
|
25648
26036
|
// src/modules/indexer/index.ts
|
|
25649
26037
|
var init_indexer = __esm(() => {
|
|
25650
26038
|
init_walker();
|
|
25651
|
-
|
|
26039
|
+
init_cache2();
|
|
25652
26040
|
init_module6();
|
|
25653
26041
|
});
|
|
25654
26042
|
|
|
@@ -25993,7 +26381,7 @@ import { spawnSync as spawnSync3 } from "child_process";
|
|
|
25993
26381
|
import { createRequire as createRequire2 } from "module";
|
|
25994
26382
|
import { join as join43, dirname as dirname16 } from "path";
|
|
25995
26383
|
import { fileURLToPath as fileURLToPath3 } from "url";
|
|
25996
|
-
import { arch, homedir as homedir12, hostname as hostname2, platform as
|
|
26384
|
+
import { arch, homedir as homedir12, hostname as hostname2, platform as platform11, release } from "os";
|
|
25997
26385
|
import { env as env2 } from "process";
|
|
25998
26386
|
function readEngineRequirement() {
|
|
25999
26387
|
const here = dirname16(fileURLToPath3(import.meta.url));
|
|
@@ -26139,7 +26527,7 @@ function collectEnvironment(opts) {
|
|
|
26139
26527
|
mmaVersion: readMmaVersion(),
|
|
26140
26528
|
runtime,
|
|
26141
26529
|
os: {
|
|
26142
|
-
platform:
|
|
26530
|
+
platform: platform11(),
|
|
26143
26531
|
arch: arch(),
|
|
26144
26532
|
release: release(),
|
|
26145
26533
|
hostname: hostname2(),
|
|
@@ -26496,6 +26884,7 @@ var init_set_thinking = __esm(() => {
|
|
|
26496
26884
|
// src/core/bootstrap.ts
|
|
26497
26885
|
var exports_bootstrap = {};
|
|
26498
26886
|
__export(exports_bootstrap, {
|
|
26887
|
+
setOneShotMode: () => setOneShotMode,
|
|
26499
26888
|
buildSystemInfo: () => buildSystemInfo,
|
|
26500
26889
|
bootstrap: () => bootstrap
|
|
26501
26890
|
});
|
|
@@ -26611,6 +27000,9 @@ function buildSystemInfo(config, baseDir, profileCompressed) {
|
|
|
26611
27000
|
return lines.join(`
|
|
26612
27001
|
`);
|
|
26613
27002
|
}
|
|
27003
|
+
function setOneShotMode(value) {
|
|
27004
|
+
oneShotMode = value;
|
|
27005
|
+
}
|
|
26614
27006
|
async function bootstrap(configDir, projectDir, noAgentsMd, exitOnComplete, reasoningLevel) {
|
|
26615
27007
|
const dir = configDir || process.env.MMA_CONFIG_DIR || join46(homedir15(), ".mma");
|
|
26616
27008
|
const projectConfigPath = projectDir ? join46(projectDir, ".mmrc") : join46(process.cwd(), ".mmrc");
|
|
@@ -26846,7 +27238,7 @@ async function bootstrap(configDir, projectDir, noAgentsMd, exitOnComplete, reas
|
|
|
26846
27238
|
moduleRegistry.register(lspModule);
|
|
26847
27239
|
registerBuiltinPlugin(pluginManager, lspModule.getPlugin());
|
|
26848
27240
|
let startupCheckBlock = null;
|
|
26849
|
-
const startupCheckPromise = !exitOnComplete ? runStartupHealthCheck(config.lsp ?? DEFAULT_LSP_CONFIG, baseDir, { logger: lspLogger }) : Promise.resolve(null);
|
|
27241
|
+
const startupCheckPromise = !oneShotMode && !exitOnComplete ? runStartupHealthCheck(config.lsp ?? DEFAULT_LSP_CONFIG, baseDir, { logger: lspLogger }) : Promise.resolve(null);
|
|
26850
27242
|
const moduleTools = moduleRegistry.collectToolDefinitions();
|
|
26851
27243
|
for (const tool of moduleTools) {
|
|
26852
27244
|
toolRegistry.register(tool);
|
|
@@ -27001,6 +27393,7 @@ async function bootstrap(configDir, projectDir, noAgentsMd, exitOnComplete, reas
|
|
|
27001
27393
|
contextProbe: contextProbePromise
|
|
27002
27394
|
};
|
|
27003
27395
|
}
|
|
27396
|
+
var oneShotMode = false;
|
|
27004
27397
|
var init_bootstrap = __esm(() => {
|
|
27005
27398
|
init_config2();
|
|
27006
27399
|
init_app_logger();
|
|
@@ -27476,9 +27869,9 @@ class Spinner {
|
|
|
27476
27869
|
tick() {
|
|
27477
27870
|
if (!this.timer)
|
|
27478
27871
|
return;
|
|
27479
|
-
const
|
|
27872
|
+
const frame2 = FRAMES[this.frame % FRAMES.length];
|
|
27480
27873
|
this.frame++;
|
|
27481
|
-
this.stream.write("\r" + pc2.cyan(
|
|
27874
|
+
this.stream.write("\r" + pc2.cyan(frame2) + " " + this.message + "\x1B[K");
|
|
27482
27875
|
}
|
|
27483
27876
|
}
|
|
27484
27877
|
var FRAMES;
|
|
@@ -30074,9 +30467,9 @@ var require_stringifyNumber = __commonJS((exports) => {
|
|
|
30074
30467
|
function stringifyNumber({ format, minFractionDigits, tag, value }) {
|
|
30075
30468
|
if (typeof value === "bigint")
|
|
30076
30469
|
return String(value);
|
|
30077
|
-
const
|
|
30078
|
-
if (!isFinite(
|
|
30079
|
-
return isNaN(
|
|
30470
|
+
const num3 = typeof value === "number" ? value : Number(value);
|
|
30471
|
+
if (!isFinite(num3))
|
|
30472
|
+
return isNaN(num3) ? ".nan" : num3 < 0 ? "-.inf" : ".inf";
|
|
30080
30473
|
let n = Object.is(value, -0) ? "-0" : JSON.stringify(value);
|
|
30081
30474
|
if (!format && minFractionDigits && (!tag || tag === "tag:yaml.org,2002:float") && /^-?\d/.test(n) && !n.includes("e")) {
|
|
30082
30475
|
let i = n.indexOf(".");
|
|
@@ -30113,8 +30506,8 @@ var require_float = __commonJS((exports) => {
|
|
|
30113
30506
|
test: /^[-+]?(?:\.[0-9]+|[0-9]+(?:\.[0-9]*)?)[eE][-+]?[0-9]+$/,
|
|
30114
30507
|
resolve: (str) => parseFloat(str),
|
|
30115
30508
|
stringify(node) {
|
|
30116
|
-
const
|
|
30117
|
-
return isFinite(
|
|
30509
|
+
const num3 = Number(node.value);
|
|
30510
|
+
return isFinite(num3) ? num3.toExponential() : stringifyNumber.stringifyNumber(node);
|
|
30118
30511
|
}
|
|
30119
30512
|
};
|
|
30120
30513
|
var float = {
|
|
@@ -30518,8 +30911,8 @@ var require_float2 = __commonJS((exports) => {
|
|
|
30518
30911
|
test: /^[-+]?(?:[0-9][0-9_]*)?(?:\.[0-9_]*)?[eE][-+]?[0-9]+$/,
|
|
30519
30912
|
resolve: (str) => parseFloat(str.replace(/_/g, "")),
|
|
30520
30913
|
stringify(node) {
|
|
30521
|
-
const
|
|
30522
|
-
return isFinite(
|
|
30914
|
+
const num3 = Number(node.value);
|
|
30915
|
+
return isFinite(num3) ? num3.toExponential() : stringifyNumber.stringifyNumber(node);
|
|
30523
30916
|
}
|
|
30524
30917
|
};
|
|
30525
30918
|
var float = {
|
|
@@ -30709,23 +31102,23 @@ var require_timestamp = __commonJS((exports) => {
|
|
|
30709
31102
|
function parseSexagesimal(str, asBigInt) {
|
|
30710
31103
|
const sign = str[0];
|
|
30711
31104
|
const parts = sign === "-" || sign === "+" ? str.substring(1) : str;
|
|
30712
|
-
const
|
|
30713
|
-
const res = parts.replace(/_/g, "").split(":").reduce((res2, p) => res2 *
|
|
30714
|
-
return sign === "-" ?
|
|
31105
|
+
const num3 = (n) => asBigInt ? BigInt(n) : Number(n);
|
|
31106
|
+
const res = parts.replace(/_/g, "").split(":").reduce((res2, p) => res2 * num3(60) + num3(p), num3(0));
|
|
31107
|
+
return sign === "-" ? num3(-1) * res : res;
|
|
30715
31108
|
}
|
|
30716
31109
|
function stringifySexagesimal(node) {
|
|
30717
31110
|
let { value } = node;
|
|
30718
|
-
let
|
|
31111
|
+
let num3 = (n) => n;
|
|
30719
31112
|
if (typeof value === "bigint")
|
|
30720
|
-
|
|
31113
|
+
num3 = (n) => BigInt(n);
|
|
30721
31114
|
else if (isNaN(value) || !isFinite(value))
|
|
30722
31115
|
return stringifyNumber.stringifyNumber(node);
|
|
30723
31116
|
let sign = "";
|
|
30724
31117
|
if (value < 0) {
|
|
30725
31118
|
sign = "-";
|
|
30726
|
-
value *=
|
|
31119
|
+
value *= num3(-1);
|
|
30727
31120
|
}
|
|
30728
|
-
const _60 =
|
|
31121
|
+
const _60 = num3(60);
|
|
30729
31122
|
const parts = [value % _60];
|
|
30730
31123
|
if (value < 60) {
|
|
30731
31124
|
parts.unshift(0);
|
|
@@ -36316,100 +36709,172 @@ function registerConfigCommands(ctx) {
|
|
|
36316
36709
|
});
|
|
36317
36710
|
}
|
|
36318
36711
|
function registerProviderCommands(ctx) {
|
|
36712
|
+
const list = () => {
|
|
36713
|
+
const providers = ctx.agent.listProviders();
|
|
36714
|
+
if (providers.length === 0) {
|
|
36715
|
+
console.log(`${t("repl.provider_current")} ${ctx.config.provider.type}`);
|
|
36716
|
+
console.log(` ${ctx.config.provider.baseUrl}`);
|
|
36717
|
+
return;
|
|
36718
|
+
}
|
|
36719
|
+
console.log(t("repl.provider_current"));
|
|
36720
|
+
for (const p of providers) {
|
|
36721
|
+
const marker = p.active ? pc2.green("* ") : " ";
|
|
36722
|
+
console.log(` ${marker}${p.label} (${pc2.dim(p.type)}) ${pc2.dim(p.baseUrl)}`);
|
|
36723
|
+
}
|
|
36724
|
+
};
|
|
36725
|
+
const use = async (args) => {
|
|
36726
|
+
const name = args[0];
|
|
36727
|
+
if (!name) {
|
|
36728
|
+
console.log(t("repl.provider_usage"));
|
|
36729
|
+
return;
|
|
36730
|
+
}
|
|
36731
|
+
try {
|
|
36732
|
+
await ctx.agent.setProvider(name);
|
|
36733
|
+
ctx.refreshModelCache();
|
|
36734
|
+
console.log(pc2.green(t("repl.provider_set", { name })));
|
|
36735
|
+
} catch (e) {
|
|
36736
|
+
console.log(pc2.red(e.message));
|
|
36737
|
+
}
|
|
36738
|
+
};
|
|
36739
|
+
const add = async (args) => {
|
|
36740
|
+
const flags = {};
|
|
36741
|
+
let name;
|
|
36742
|
+
for (let i = 0;i < args.length; i++) {
|
|
36743
|
+
const arg = args[i];
|
|
36744
|
+
if (arg.startsWith("--")) {
|
|
36745
|
+
const value = args[i + 1];
|
|
36746
|
+
if (value === undefined || value.startsWith("--")) {
|
|
36747
|
+
console.log(pc2.red(t("repl.provider_add_missing_value", { flag: arg })));
|
|
36748
|
+
return;
|
|
36749
|
+
}
|
|
36750
|
+
flags[arg.slice(2)] = value;
|
|
36751
|
+
i++;
|
|
36752
|
+
} else if (name === undefined) {
|
|
36753
|
+
name = arg;
|
|
36754
|
+
}
|
|
36755
|
+
}
|
|
36756
|
+
if (!name) {
|
|
36757
|
+
console.log(t("repl.provider_usage"));
|
|
36758
|
+
return;
|
|
36759
|
+
}
|
|
36760
|
+
const entries = Array.isArray(ctx.config.provider.entries) ? ctx.config.provider.entries : [];
|
|
36761
|
+
if (entries.length === 0) {
|
|
36762
|
+
entries.push({
|
|
36763
|
+
type: ctx.config.provider.type,
|
|
36764
|
+
label: ctx.config.provider.type,
|
|
36765
|
+
baseUrl: ctx.config.provider.baseUrl,
|
|
36766
|
+
apiKey: ctx.config.provider.apiKey
|
|
36767
|
+
});
|
|
36768
|
+
}
|
|
36769
|
+
const baseUrl = flags.url || HOSTED_BASE_URLS[name] || HOSTED_BASE_URLS[`opencode-${name}`] || "";
|
|
36770
|
+
if (!baseUrl) {
|
|
36771
|
+
console.log(pc2.red(t("cli.provider_no_url", { name })));
|
|
36772
|
+
return;
|
|
36773
|
+
}
|
|
36774
|
+
entries.push({
|
|
36775
|
+
type: name,
|
|
36776
|
+
label: name,
|
|
36777
|
+
baseUrl,
|
|
36778
|
+
apiKey: flags.key,
|
|
36779
|
+
...flags.priority !== undefined ? { priority: Number(flags.priority) } : {},
|
|
36780
|
+
...flags["context-window"] !== undefined ? { contextWindow: Number(flags["context-window"]) } : {},
|
|
36781
|
+
...flags.rpm !== undefined || flags.parallel !== undefined ? {
|
|
36782
|
+
rateLimits: {
|
|
36783
|
+
maxRequestsPerMinute: Number(flags.rpm ?? 0) || 60,
|
|
36784
|
+
maxParallelTasks: Number(flags.parallel ?? 0) || 1
|
|
36785
|
+
}
|
|
36786
|
+
} : {}
|
|
36787
|
+
});
|
|
36788
|
+
ctx.config.provider.entries = entries;
|
|
36789
|
+
ctx.config.provider.active = ctx.config.provider.active || ctx.config.provider.type;
|
|
36790
|
+
const configPath = join54(ctx.configDir, "config.json");
|
|
36791
|
+
saveConfig(ctx.config, configPath, dirname24(configPath));
|
|
36792
|
+
await ctx.agent.reconfigure(ctx.config);
|
|
36793
|
+
console.log(pc2.green(t("cli.provider_added", { name })));
|
|
36794
|
+
console.log(t("repl.provider_switch_hint", { name }));
|
|
36795
|
+
};
|
|
36796
|
+
const handlers = {
|
|
36797
|
+
list,
|
|
36798
|
+
use,
|
|
36799
|
+
add
|
|
36800
|
+
};
|
|
36319
36801
|
ctx.registerCommand({
|
|
36320
36802
|
name: "provider",
|
|
36321
36803
|
description: t("repl.provider_list"),
|
|
36322
36804
|
usage: t("repl.provider_usage"),
|
|
36323
36805
|
action: async (args) => {
|
|
36324
36806
|
const subcmd = args[0];
|
|
36325
|
-
|
|
36326
|
-
|
|
36327
|
-
|
|
36328
|
-
console.log(`${t("repl.provider_current")} ${ctx.config.provider.type}`);
|
|
36329
|
-
console.log(` ${ctx.config.provider.baseUrl}`);
|
|
36330
|
-
} else {
|
|
36331
|
-
console.log(t("repl.provider_current"));
|
|
36332
|
-
for (const p of providers) {
|
|
36333
|
-
const marker = p.active ? pc2.green("* ") : " ";
|
|
36334
|
-
console.log(` ${marker}${p.label} (${pc2.dim(p.type)}) ${pc2.dim(p.baseUrl)}`);
|
|
36335
|
-
}
|
|
36336
|
-
}
|
|
36807
|
+
const handler = subcmd ? handlers[subcmd] : handlers.list;
|
|
36808
|
+
if (!handler) {
|
|
36809
|
+
console.log(t("repl.provider_usage"));
|
|
36337
36810
|
return;
|
|
36338
36811
|
}
|
|
36339
|
-
|
|
36340
|
-
|
|
36341
|
-
|
|
36342
|
-
|
|
36343
|
-
|
|
36344
|
-
|
|
36345
|
-
|
|
36346
|
-
|
|
36347
|
-
|
|
36348
|
-
|
|
36349
|
-
|
|
36350
|
-
|
|
36812
|
+
await handler(args.slice(1));
|
|
36813
|
+
}
|
|
36814
|
+
});
|
|
36815
|
+
const listModels = async () => {
|
|
36816
|
+
console.log(`${t("repl.model_current")} ${ctx.config.model}`);
|
|
36817
|
+
const { OpenAICompatProvider: OpenAICompatProvider2 } = await Promise.resolve().then(() => (init_openai_compat(), exports_openai_compat));
|
|
36818
|
+
const provider = new OpenAICompatProvider2({
|
|
36819
|
+
model: ctx.config.model,
|
|
36820
|
+
baseUrl: ctx.config.provider.baseUrl,
|
|
36821
|
+
apiKey: ctx.config.provider.apiKey,
|
|
36822
|
+
contextWindow: ctx.config.contextWindow
|
|
36823
|
+
});
|
|
36824
|
+
const { Spinner: Spinner2 } = await Promise.resolve().then(() => (init_spinner(), exports_spinner));
|
|
36825
|
+
const s = new Spinner2;
|
|
36826
|
+
s.start(t("cli.fetching_models"));
|
|
36827
|
+
try {
|
|
36828
|
+
const models = await provider.listModels();
|
|
36829
|
+
s.stop();
|
|
36830
|
+
if (models.length > 0) {
|
|
36831
|
+
ctx.refreshModelCache();
|
|
36832
|
+
console.log(t("cli.available_models"));
|
|
36833
|
+
const { getCertMark: getCertMark2 } = await Promise.resolve().then(() => (init_manifest(), exports_manifest));
|
|
36834
|
+
for (const m of models) {
|
|
36835
|
+
const marker = m === ctx.config.model ? pc2.green("* ") : " ";
|
|
36836
|
+
const mark = getCertMark2(m, ctx.config.provider.baseUrl, version2, process.cwd());
|
|
36837
|
+
const cert = mark === "certified" ? pc2.green("✔") : mark === "stale" ? pc2.yellow("○") : pc2.dim("·");
|
|
36838
|
+
const label = mark === "certified" ? ` ${pc2.green(t("cli.cert_label"))}` : mark === "stale" ? ` ${pc2.yellow(t("cli.cert_stale_label"))}` : "";
|
|
36839
|
+
console.log(` ${marker}${cert} ${m}${label}`);
|
|
36351
36840
|
}
|
|
36352
|
-
|
|
36841
|
+
} else {
|
|
36842
|
+
console.log(t("cli.no_models_found"));
|
|
36353
36843
|
}
|
|
36354
|
-
|
|
36844
|
+
} catch (err) {
|
|
36845
|
+
s.stop();
|
|
36846
|
+
console.log(t("cli.model_fetch_failed", { error: String(err) }));
|
|
36355
36847
|
}
|
|
36356
|
-
|
|
36848
|
+
console.log(t("cli.model_hint"));
|
|
36849
|
+
};
|
|
36850
|
+
const useModel = async (args) => {
|
|
36851
|
+
const name = args[0];
|
|
36852
|
+
if (!name) {
|
|
36853
|
+
console.log(t("repl.model_usage"));
|
|
36854
|
+
return;
|
|
36855
|
+
}
|
|
36856
|
+
ctx.config.model = name;
|
|
36857
|
+
const configPath = join54(ctx.configDir, "config.json");
|
|
36858
|
+
saveConfig(ctx.config, configPath, dirname24(configPath));
|
|
36859
|
+
await ctx.agent.reconfigure(ctx.config);
|
|
36860
|
+
console.log(pc2.green(t("repl.model_set", { name })));
|
|
36861
|
+
};
|
|
36862
|
+
const modelHandlers = {
|
|
36863
|
+
list: listModels,
|
|
36864
|
+
use: useModel
|
|
36865
|
+
};
|
|
36357
36866
|
ctx.registerCommand({
|
|
36358
36867
|
name: "model",
|
|
36359
36868
|
description: t("repl.model_list"),
|
|
36360
36869
|
usage: t("repl.model_usage"),
|
|
36361
36870
|
action: async (args) => {
|
|
36362
36871
|
const subcmd = args[0];
|
|
36363
|
-
|
|
36364
|
-
|
|
36365
|
-
|
|
36366
|
-
const provider = new OpenAICompatProvider2({
|
|
36367
|
-
model: ctx.config.model,
|
|
36368
|
-
baseUrl: ctx.config.provider.baseUrl,
|
|
36369
|
-
apiKey: ctx.config.provider.apiKey,
|
|
36370
|
-
contextWindow: ctx.config.contextWindow
|
|
36371
|
-
});
|
|
36372
|
-
const { Spinner: Spinner2 } = await Promise.resolve().then(() => (init_spinner(), exports_spinner));
|
|
36373
|
-
const s = new Spinner2;
|
|
36374
|
-
s.start(t("cli.fetching_models"));
|
|
36375
|
-
try {
|
|
36376
|
-
const models = await provider.listModels();
|
|
36377
|
-
s.stop();
|
|
36378
|
-
if (models.length > 0) {
|
|
36379
|
-
ctx.refreshModelCache();
|
|
36380
|
-
console.log(t("cli.available_models"));
|
|
36381
|
-
const { getCertMark: getCertMark2 } = await Promise.resolve().then(() => (init_manifest(), exports_manifest));
|
|
36382
|
-
for (const m of models) {
|
|
36383
|
-
const marker = m === ctx.config.model ? pc2.green("* ") : " ";
|
|
36384
|
-
const mark = getCertMark2(m, ctx.config.provider.baseUrl, version2, process.cwd());
|
|
36385
|
-
const cert = mark === "certified" ? pc2.green("✔") : mark === "stale" ? pc2.yellow("○") : pc2.dim("·");
|
|
36386
|
-
const label = mark === "certified" ? ` ${pc2.green(t("cli.cert_label"))}` : mark === "stale" ? ` ${pc2.yellow(t("cli.cert_stale_label"))}` : "";
|
|
36387
|
-
console.log(` ${marker}${cert} ${m}${label}`);
|
|
36388
|
-
}
|
|
36389
|
-
} else {
|
|
36390
|
-
console.log(t("cli.no_models_found"));
|
|
36391
|
-
}
|
|
36392
|
-
} catch (err) {
|
|
36393
|
-
s.stop();
|
|
36394
|
-
console.log(t("cli.model_fetch_failed", { error: String(err) }));
|
|
36395
|
-
}
|
|
36396
|
-
console.log(t("cli.model_hint"));
|
|
36397
|
-
return;
|
|
36398
|
-
}
|
|
36399
|
-
if (subcmd === "use") {
|
|
36400
|
-
const name = args[1];
|
|
36401
|
-
if (!name) {
|
|
36402
|
-
console.log(t("repl.model_usage"));
|
|
36403
|
-
return;
|
|
36404
|
-
}
|
|
36405
|
-
ctx.config.model = name;
|
|
36406
|
-
const configPath = join54(ctx.configDir, "config.json");
|
|
36407
|
-
saveConfig(ctx.config, configPath, dirname24(configPath));
|
|
36408
|
-
await ctx.agent.reconfigure(ctx.config);
|
|
36409
|
-
console.log(pc2.green(t("repl.model_set", { name })));
|
|
36872
|
+
const handler = subcmd ? modelHandlers[subcmd] : modelHandlers.list;
|
|
36873
|
+
if (!handler) {
|
|
36874
|
+
console.log(t("repl.model_usage"));
|
|
36410
36875
|
return;
|
|
36411
36876
|
}
|
|
36412
|
-
|
|
36877
|
+
await handler(args.slice(1));
|
|
36413
36878
|
}
|
|
36414
36879
|
});
|
|
36415
36880
|
ctx.registerCommand({
|
|
@@ -36718,88 +37183,97 @@ function registerSessionCommands(ctx) {
|
|
|
36718
37183
|
function registerSkillCommands(ctx) {
|
|
36719
37184
|
if (!ctx.skillsModule)
|
|
36720
37185
|
return;
|
|
37186
|
+
const listSkills = () => {
|
|
37187
|
+
const available = ctx.skillsModule.getAvailable();
|
|
37188
|
+
if (available.length === 0) {
|
|
37189
|
+
console.log(t("repl.no_skills"));
|
|
37190
|
+
return;
|
|
37191
|
+
}
|
|
37192
|
+
console.log(pc2.bold(t("repl.available_skills")));
|
|
37193
|
+
for (const skill of available) {
|
|
37194
|
+
const tokens = estimateTokens(skill.content);
|
|
37195
|
+
const loaded = ctx.skillsModule.getLoaded().some((s) => s.name === skill.name);
|
|
37196
|
+
const marker = loaded ? pc2.green(" [loaded]") : "";
|
|
37197
|
+
console.log(` ${pc2.cyan(skill.name)}${marker} ${pc2.dim(`(${tokens} tokens)`)} ${skill.description.slice(0, 60)}`);
|
|
37198
|
+
}
|
|
37199
|
+
};
|
|
37200
|
+
const listLoaded = () => {
|
|
37201
|
+
const loaded = ctx.skillsModule.getLoaded();
|
|
37202
|
+
const budget = ctx.skillsModule.getBudget();
|
|
37203
|
+
if (loaded.length === 0) {
|
|
37204
|
+
console.log(t("repl.no_loaded"));
|
|
37205
|
+
return;
|
|
37206
|
+
}
|
|
37207
|
+
console.log(pc2.bold(t("repl.loaded_skills")));
|
|
37208
|
+
for (const skill of loaded) {
|
|
37209
|
+
const tokens = estimateTokens(skill.content);
|
|
37210
|
+
console.log(` ${pc2.cyan(skill.name)} ${pc2.dim(`(${tokens} tokens)`)} ${skill.description.slice(0, 60)}`);
|
|
37211
|
+
}
|
|
37212
|
+
console.log(pc2.dim(`
|
|
37213
|
+
${t("repl.budget", { used: budget.used, total: budget.total, remaining: budget.remaining })}`));
|
|
37214
|
+
};
|
|
37215
|
+
const loadSkill = (args) => {
|
|
37216
|
+
const arg = args.join(" ");
|
|
37217
|
+
if (!arg) {
|
|
37218
|
+
console.log(t("repl.skill_load_usage"));
|
|
37219
|
+
return;
|
|
37220
|
+
}
|
|
37221
|
+
const result = ctx.skillsModule.loadByName(arg);
|
|
37222
|
+
if (result.success) {
|
|
37223
|
+
console.log(pc2.green(result.message));
|
|
37224
|
+
} else {
|
|
37225
|
+
console.log(pc2.red(result.message));
|
|
37226
|
+
}
|
|
37227
|
+
};
|
|
37228
|
+
const unloadSkill = (args) => {
|
|
37229
|
+
const arg = args.join(" ");
|
|
37230
|
+
if (!arg) {
|
|
37231
|
+
console.log(t("repl.skill_unload_usage"));
|
|
37232
|
+
return;
|
|
37233
|
+
}
|
|
37234
|
+
if (ctx.skillsModule.unload(arg)) {
|
|
37235
|
+
console.log(pc2.green(t("repl.skill_unloaded", { name: arg })));
|
|
37236
|
+
} else {
|
|
37237
|
+
console.log(pc2.red(t("repl.skill_not_loaded", { name: arg })));
|
|
37238
|
+
}
|
|
37239
|
+
};
|
|
37240
|
+
const searchSkills = (args) => {
|
|
37241
|
+
const arg = args.join(" ");
|
|
37242
|
+
if (!arg) {
|
|
37243
|
+
console.log(t("repl.skill_search_usage"));
|
|
37244
|
+
return;
|
|
37245
|
+
}
|
|
37246
|
+
const results = ctx.skillsModule.search(arg);
|
|
37247
|
+
if (results.length === 0) {
|
|
37248
|
+
console.log(t("repl.no_skill_match", { query: arg }));
|
|
37249
|
+
return;
|
|
37250
|
+
}
|
|
37251
|
+
console.log(pc2.bold(t("repl.skills_matching", { query: arg })));
|
|
37252
|
+
for (const skill of results) {
|
|
37253
|
+
const tokens = estimateTokens(skill.content);
|
|
37254
|
+
console.log(` ${pc2.cyan(skill.name)} ${pc2.dim(`(${tokens} tokens)`)} ${skill.description.slice(0, 60)}`);
|
|
37255
|
+
}
|
|
37256
|
+
};
|
|
37257
|
+
const skillHandlers = {
|
|
37258
|
+
list: listSkills,
|
|
37259
|
+
loaded: listLoaded,
|
|
37260
|
+
load: loadSkill,
|
|
37261
|
+
unload: unloadSkill,
|
|
37262
|
+
search: searchSkills
|
|
37263
|
+
};
|
|
36721
37264
|
ctx.registerCommand({
|
|
36722
37265
|
name: "skill",
|
|
36723
37266
|
description: t("repl.skill"),
|
|
36724
37267
|
usage: t("repl.skill_usage"),
|
|
36725
37268
|
action: (args) => {
|
|
36726
37269
|
const subcmd = args[0];
|
|
36727
|
-
const
|
|
36728
|
-
if (!
|
|
36729
|
-
|
|
36730
|
-
|
|
36731
|
-
console.log(t("repl.no_skills"));
|
|
36732
|
-
return;
|
|
36733
|
-
}
|
|
36734
|
-
console.log(pc2.bold(t("repl.available_skills")));
|
|
36735
|
-
for (const skill of available) {
|
|
36736
|
-
const tokens = estimateTokens(skill.content);
|
|
36737
|
-
const loaded = ctx.skillsModule.getLoaded().some((s) => s.name === skill.name);
|
|
36738
|
-
const marker = loaded ? pc2.green(" [loaded]") : "";
|
|
36739
|
-
console.log(` ${pc2.cyan(skill.name)}${marker} ${pc2.dim(`(${tokens} tokens)`)} ${skill.description.slice(0, 60)}`);
|
|
36740
|
-
}
|
|
36741
|
-
return;
|
|
36742
|
-
}
|
|
36743
|
-
if (subcmd === "loaded") {
|
|
36744
|
-
const loaded = ctx.skillsModule.getLoaded();
|
|
36745
|
-
const budget = ctx.skillsModule.getBudget();
|
|
36746
|
-
if (loaded.length === 0) {
|
|
36747
|
-
console.log(t("repl.no_loaded"));
|
|
36748
|
-
return;
|
|
36749
|
-
}
|
|
36750
|
-
console.log(pc2.bold(t("repl.loaded_skills")));
|
|
36751
|
-
for (const skill of loaded) {
|
|
36752
|
-
const tokens = estimateTokens(skill.content);
|
|
36753
|
-
console.log(` ${pc2.cyan(skill.name)} ${pc2.dim(`(${tokens} tokens)`)} ${skill.description.slice(0, 60)}`);
|
|
36754
|
-
}
|
|
36755
|
-
console.log(pc2.dim(`
|
|
36756
|
-
${t("repl.budget", { used: budget.used, total: budget.total, remaining: budget.remaining })}`));
|
|
37270
|
+
const handler = subcmd ? skillHandlers[subcmd] : skillHandlers.list;
|
|
37271
|
+
if (!handler) {
|
|
37272
|
+
console.log(pc2.red(t("repl.skill_unknown_sub", { subcmd })));
|
|
37273
|
+
console.log(t("repl.skill_usage"));
|
|
36757
37274
|
return;
|
|
36758
37275
|
}
|
|
36759
|
-
|
|
36760
|
-
if (!arg) {
|
|
36761
|
-
console.log(t("repl.skill_load_usage"));
|
|
36762
|
-
return;
|
|
36763
|
-
}
|
|
36764
|
-
const result = ctx.skillsModule.loadByName(arg);
|
|
36765
|
-
if (result.success) {
|
|
36766
|
-
console.log(pc2.green(result.message));
|
|
36767
|
-
} else {
|
|
36768
|
-
console.log(pc2.red(result.message));
|
|
36769
|
-
}
|
|
36770
|
-
return;
|
|
36771
|
-
}
|
|
36772
|
-
if (subcmd === "unload") {
|
|
36773
|
-
if (!arg) {
|
|
36774
|
-
console.log(t("repl.skill_unload_usage"));
|
|
36775
|
-
return;
|
|
36776
|
-
}
|
|
36777
|
-
if (ctx.skillsModule.unload(arg)) {
|
|
36778
|
-
console.log(pc2.green(t("repl.skill_unloaded", { name: arg })));
|
|
36779
|
-
} else {
|
|
36780
|
-
console.log(pc2.red(t("repl.skill_not_loaded", { name: arg })));
|
|
36781
|
-
}
|
|
36782
|
-
return;
|
|
36783
|
-
}
|
|
36784
|
-
if (subcmd === "search") {
|
|
36785
|
-
if (!arg) {
|
|
36786
|
-
console.log(t("repl.skill_search_usage"));
|
|
36787
|
-
return;
|
|
36788
|
-
}
|
|
36789
|
-
const results = ctx.skillsModule.search(arg);
|
|
36790
|
-
if (results.length === 0) {
|
|
36791
|
-
console.log(t("repl.no_skill_match", { query: arg }));
|
|
36792
|
-
return;
|
|
36793
|
-
}
|
|
36794
|
-
console.log(pc2.bold(t("repl.skills_matching", { query: arg })));
|
|
36795
|
-
for (const skill of results) {
|
|
36796
|
-
const tokens = estimateTokens(skill.content);
|
|
36797
|
-
console.log(` ${pc2.cyan(skill.name)} ${pc2.dim(`(${tokens} tokens)`)} ${skill.description.slice(0, 60)}`);
|
|
36798
|
-
}
|
|
36799
|
-
return;
|
|
36800
|
-
}
|
|
36801
|
-
console.log(pc2.red(t("repl.skill_unknown_sub", { subcmd })));
|
|
36802
|
-
console.log(t("repl.skill_usage"));
|
|
37276
|
+
handler(args.slice(1));
|
|
36803
37277
|
}
|
|
36804
37278
|
});
|
|
36805
37279
|
}
|
|
@@ -36832,6 +37306,7 @@ var init_repl_commands = __esm(() => {
|
|
|
36832
37306
|
init_i18n();
|
|
36833
37307
|
init_setup();
|
|
36834
37308
|
init_config2();
|
|
37309
|
+
init_presets();
|
|
36835
37310
|
init_budget();
|
|
36836
37311
|
init_token_counter();
|
|
36837
37312
|
init_map_command();
|
|
@@ -37566,6 +38041,63 @@ init_version();
|
|
|
37566
38041
|
init_map_command();
|
|
37567
38042
|
init_budget();
|
|
37568
38043
|
|
|
38044
|
+
// src/llm/provider-budget.ts
|
|
38045
|
+
var DEFAULT_TIMEOUT_MS = 5000;
|
|
38046
|
+
function num2(value) {
|
|
38047
|
+
return typeof value === "number" && Number.isFinite(value) ? value : undefined;
|
|
38048
|
+
}
|
|
38049
|
+
async function getJson(url, apiKey, timeoutMs) {
|
|
38050
|
+
const response = await fetch(url, {
|
|
38051
|
+
headers: { Authorization: `Bearer ${apiKey}` },
|
|
38052
|
+
signal: AbortSignal.timeout(timeoutMs)
|
|
38053
|
+
});
|
|
38054
|
+
if (!response.ok) {
|
|
38055
|
+
throw new Error(`HTTP ${response.status}`);
|
|
38056
|
+
}
|
|
38057
|
+
return response.json();
|
|
38058
|
+
}
|
|
38059
|
+
async function fetchProviderBudget(provider, baseUrl, apiKey, options) {
|
|
38060
|
+
if (provider !== "openrouter") {
|
|
38061
|
+
options.log("debug", `budget: provider "${provider}" does not expose an API balance`);
|
|
38062
|
+
return { budget: null, reason: "unsupported" };
|
|
38063
|
+
}
|
|
38064
|
+
if (!apiKey) {
|
|
38065
|
+
options.log("debug", "budget: no api key configured");
|
|
38066
|
+
return { budget: null, reason: "no-key" };
|
|
38067
|
+
}
|
|
38068
|
+
const base = baseUrl.replace(/\/$/, "");
|
|
38069
|
+
const timeoutMs = options.timeoutMs ?? DEFAULT_TIMEOUT_MS;
|
|
38070
|
+
try {
|
|
38071
|
+
const keyBody = await getJson(`${base}/key`, apiKey, timeoutMs);
|
|
38072
|
+
const data = keyBody?.data ?? {};
|
|
38073
|
+
const budget = { provider, source: "openrouter" };
|
|
38074
|
+
budget.keyLabel = typeof data.label === "string" ? data.label : undefined;
|
|
38075
|
+
budget.keyUsageUsd = num2(data.usage);
|
|
38076
|
+
budget.keyLimitUsd = num2(data.limit);
|
|
38077
|
+
budget.keyRemainingUsd = num2(data.limit_remaining);
|
|
38078
|
+
budget.isFreeTier = typeof data.is_free_tier === "boolean" ? data.is_free_tier : undefined;
|
|
38079
|
+
try {
|
|
38080
|
+
const creditsBody = await getJson(`${base}/credits`, apiKey, timeoutMs);
|
|
38081
|
+
const c = creditsBody?.data ?? {};
|
|
38082
|
+
budget.totalCreditsUsd = num2(c.total_credits);
|
|
38083
|
+
budget.totalUsageUsd = num2(c.total_usage);
|
|
38084
|
+
if (budget.totalCreditsUsd !== undefined && budget.totalUsageUsd !== undefined) {
|
|
38085
|
+
budget.balanceUsd = budget.totalCreditsUsd - budget.totalUsageUsd;
|
|
38086
|
+
}
|
|
38087
|
+
} catch (creditsErr) {
|
|
38088
|
+
options.log("debug", `budget: /credits unavailable (${creditsErr instanceof Error ? creditsErr.message : String(creditsErr)})`);
|
|
38089
|
+
}
|
|
38090
|
+
return { budget, reason: "ok" };
|
|
38091
|
+
} catch (err) {
|
|
38092
|
+
const message = err instanceof Error ? err.message : String(err);
|
|
38093
|
+
options.log("warn", `budget: request failed (${message})`);
|
|
38094
|
+
return { budget: null, reason: "error", error: message };
|
|
38095
|
+
}
|
|
38096
|
+
}
|
|
38097
|
+
|
|
38098
|
+
// src/cli/commands.ts
|
|
38099
|
+
init_prices();
|
|
38100
|
+
|
|
37569
38101
|
// src/modules/updater/changelog-reader.ts
|
|
37570
38102
|
import { readFileSync as readFileSync35, existsSync as existsSync53 } from "fs";
|
|
37571
38103
|
import { dirname as dirname20, join as join48 } from "path";
|
|
@@ -37854,6 +38386,53 @@ function buildContextCommand(program2) {
|
|
|
37854
38386
|
console.log(t("cli.context_set", { size: contextWindow }));
|
|
37855
38387
|
});
|
|
37856
38388
|
}
|
|
38389
|
+
function buildUsageCommand(program2) {
|
|
38390
|
+
program2.command("usage").description(t("cli.usage")).action(async () => {
|
|
38391
|
+
const { config, logger: logger4 } = await bootstrap();
|
|
38392
|
+
const { type: provider, baseUrl, apiKey } = config.provider;
|
|
38393
|
+
const result = await fetchProviderBudget(provider, baseUrl, apiKey, {
|
|
38394
|
+
log: (level, message) => level === "warn" ? logger4.warn(message) : logger4.debug(message)
|
|
38395
|
+
});
|
|
38396
|
+
if (result.reason === "unsupported") {
|
|
38397
|
+
console.log(t("cli.usage_unsupported", { provider }));
|
|
38398
|
+
return;
|
|
38399
|
+
}
|
|
38400
|
+
if (result.reason === "no-key") {
|
|
38401
|
+
console.log(t("cli.usage_no_key"));
|
|
38402
|
+
return;
|
|
38403
|
+
}
|
|
38404
|
+
if (result.reason === "error" || !result.budget) {
|
|
38405
|
+
console.log(t("cli.usage_error", { error: result.error ?? "" }));
|
|
38406
|
+
return;
|
|
38407
|
+
}
|
|
38408
|
+
const b = result.budget;
|
|
38409
|
+
let printed = false;
|
|
38410
|
+
if (b.keyUsageUsd !== undefined) {
|
|
38411
|
+
console.log(t("cli.usage_key_usage", { usage: formatCost(b.keyUsageUsd) }));
|
|
38412
|
+
printed = true;
|
|
38413
|
+
}
|
|
38414
|
+
if (b.keyLimitUsd !== undefined && b.keyRemainingUsd !== undefined) {
|
|
38415
|
+
console.log(t("cli.usage_key_limit", {
|
|
38416
|
+
limit: formatCost(b.keyLimitUsd),
|
|
38417
|
+
remaining: formatCost(b.keyRemainingUsd)
|
|
38418
|
+
}));
|
|
38419
|
+
printed = true;
|
|
38420
|
+
}
|
|
38421
|
+
if (b.balanceUsd !== undefined) {
|
|
38422
|
+
console.log(t("cli.usage_balance", { balance: formatCost(b.balanceUsd) }));
|
|
38423
|
+
printed = true;
|
|
38424
|
+
}
|
|
38425
|
+
if (b.totalCreditsUsd !== undefined && b.totalUsageUsd !== undefined) {
|
|
38426
|
+
console.log(t("cli.usage_account", {
|
|
38427
|
+
credits: formatCost(b.totalCreditsUsd),
|
|
38428
|
+
used: formatCost(b.totalUsageUsd)
|
|
38429
|
+
}));
|
|
38430
|
+
printed = true;
|
|
38431
|
+
}
|
|
38432
|
+
if (!printed)
|
|
38433
|
+
console.log(t("cli.usage_empty"));
|
|
38434
|
+
});
|
|
38435
|
+
}
|
|
37857
38436
|
function buildMapCommand(program2) {
|
|
37858
38437
|
program2.command("map").description(t("cli.map.description")).argument("[action]", t("cli.map.action"), "summary").argument("[query]", t("cli.map.query")).action(async (action, query) => {
|
|
37859
38438
|
const { agent } = await bootstrap();
|
|
@@ -38010,6 +38589,31 @@ function buildSessionCommands(program2) {
|
|
|
38010
38589
|
}
|
|
38011
38590
|
}
|
|
38012
38591
|
}
|
|
38592
|
+
const usageEvents = sessionManager.loadSessionLog(id).filter((e) => e.type === "llm_usage");
|
|
38593
|
+
if (usageEvents.length > 0) {
|
|
38594
|
+
let prompt = 0;
|
|
38595
|
+
let completion = 0;
|
|
38596
|
+
let cached = 0;
|
|
38597
|
+
for (const e of usageEvents) {
|
|
38598
|
+
prompt += e.promptTokens ?? 0;
|
|
38599
|
+
completion += e.completionTokens ?? 0;
|
|
38600
|
+
cached += e.cachedTokens ?? 0;
|
|
38601
|
+
}
|
|
38602
|
+
console.log("");
|
|
38603
|
+
console.log(pc2.cyan(t("cli.session_usage", {
|
|
38604
|
+
prompt,
|
|
38605
|
+
completion,
|
|
38606
|
+
total: prompt + completion
|
|
38607
|
+
})));
|
|
38608
|
+
if (cached > 0 && prompt > 0) {
|
|
38609
|
+
const hit = Math.round(cached / prompt * 100);
|
|
38610
|
+
console.log(pc2.dim(t("cli.session_cache", {
|
|
38611
|
+
hit,
|
|
38612
|
+
cached,
|
|
38613
|
+
uncached: Math.max(0, prompt - cached)
|
|
38614
|
+
})));
|
|
38615
|
+
}
|
|
38616
|
+
}
|
|
38013
38617
|
});
|
|
38014
38618
|
session2.command("delete").argument("<id>", "Session id").description(t("cli.delete_session")).action(async (id) => {
|
|
38015
38619
|
const { sessionManager } = await bootstrap();
|
|
@@ -38049,6 +38653,7 @@ function createProgram() {
|
|
|
38049
38653
|
buildConfigCommands(program2);
|
|
38050
38654
|
buildModelCommands(program2);
|
|
38051
38655
|
buildContextCommand(program2);
|
|
38656
|
+
buildUsageCommand(program2);
|
|
38052
38657
|
buildMapCommand(program2);
|
|
38053
38658
|
buildProviderCommands(program2);
|
|
38054
38659
|
buildSessionCommands(program2);
|
|
@@ -38056,11 +38661,15 @@ function createProgram() {
|
|
|
38056
38661
|
createPluginCommand(program2);
|
|
38057
38662
|
buildChangelogCommand(program2);
|
|
38058
38663
|
program2.argument("[prompt...]", "Prompt to execute").description("Run a single prompt").action((prompt) => {});
|
|
38059
|
-
|
|
38664
|
+
const attachOneShotExit = (cmd) => {
|
|
38060
38665
|
cmd.hook("postAction", () => {
|
|
38061
38666
|
process.exit(0);
|
|
38062
38667
|
});
|
|
38063
|
-
|
|
38668
|
+
for (const sub of cmd.commands)
|
|
38669
|
+
attachOneShotExit(sub);
|
|
38670
|
+
};
|
|
38671
|
+
for (const cmd of program2.commands)
|
|
38672
|
+
attachOneShotExit(cmd);
|
|
38064
38673
|
return program2;
|
|
38065
38674
|
}
|
|
38066
38675
|
|
|
@@ -39026,22 +39635,17 @@ class SkillNameProvider {
|
|
|
39026
39635
|
return ctx.tokenIndex >= 2 && ctx.tokens[0] === "/skill" && (ctx.tokens[1] === "load" || ctx.tokens[1] === "unload");
|
|
39027
39636
|
}
|
|
39028
39637
|
complete(ctx) {
|
|
39029
|
-
const
|
|
39030
|
-
|
|
39031
|
-
|
|
39032
|
-
|
|
39033
|
-
|
|
39034
|
-
|
|
39035
|
-
return
|
|
39036
|
-
|
|
39037
|
-
if (
|
|
39038
|
-
|
|
39039
|
-
|
|
39040
|
-
if (!ctx.partial)
|
|
39041
|
-
return names;
|
|
39042
|
-
return names.filter((n) => n.toLowerCase().includes(ctx.partial.toLowerCase()));
|
|
39043
|
-
}
|
|
39044
|
-
return [];
|
|
39638
|
+
const sources = {
|
|
39639
|
+
load: () => this.skillsModule.getAvailable().map((s) => s.name),
|
|
39640
|
+
unload: () => this.skillsModule.getLoaded().map((s) => s.name)
|
|
39641
|
+
};
|
|
39642
|
+
const source = sources[ctx.tokens[1]];
|
|
39643
|
+
if (!source)
|
|
39644
|
+
return [];
|
|
39645
|
+
const names = source();
|
|
39646
|
+
if (!ctx.partial)
|
|
39647
|
+
return names;
|
|
39648
|
+
return names.filter((n) => n.toLowerCase().includes(ctx.partial.toLowerCase()));
|
|
39045
39649
|
}
|
|
39046
39650
|
}
|
|
39047
39651
|
|
|
@@ -39693,6 +40297,28 @@ function stepContextForTool(plan, tool, args) {
|
|
|
39693
40297
|
// src/cli/repl.ts
|
|
39694
40298
|
init_prices();
|
|
39695
40299
|
|
|
40300
|
+
// src/cli/cache-line.ts
|
|
40301
|
+
init_i18n();
|
|
40302
|
+
init_prices();
|
|
40303
|
+
function formatCacheLine(cache) {
|
|
40304
|
+
if (!cache)
|
|
40305
|
+
return;
|
|
40306
|
+
const total = cache.cachedTokens + cache.uncachedTokens;
|
|
40307
|
+
const hit = Math.round(cache.hitRate * 100);
|
|
40308
|
+
if (total > 0) {
|
|
40309
|
+
if (cache.saved !== undefined && cache.saved > 0) {
|
|
40310
|
+
return t("repl.cache", { hit, saved: formatCost(cache.saved) });
|
|
40311
|
+
}
|
|
40312
|
+
return t("repl.cache_nosave", { hit });
|
|
40313
|
+
}
|
|
40314
|
+
const broken = cache.prefixCause !== undefined && cache.prefixCause !== "none" && cache.prefixCause !== "unknown";
|
|
40315
|
+
if (broken && cache.prefixStable !== undefined && cache.prefixStable < 0.98) {
|
|
40316
|
+
const stable = Math.round(cache.prefixStable * 100);
|
|
40317
|
+
return t("repl.prefix", { stable, cause: t(`cache.cause.${cache.prefixCause}`) });
|
|
40318
|
+
}
|
|
40319
|
+
return;
|
|
40320
|
+
}
|
|
40321
|
+
|
|
39696
40322
|
// src/ui/output.ts
|
|
39697
40323
|
function writeWarning(text) {
|
|
39698
40324
|
process.stdout.write(formatWarning(text) + `
|
|
@@ -39872,7 +40498,7 @@ class Repl {
|
|
|
39872
40498
|
this.completer.registerProvider(new SubcommandProvider("skill", ["list", "loaded", "load", "unload", "search"]));
|
|
39873
40499
|
this.completer.registerProvider(new SkillNameProvider(this.skillsModule));
|
|
39874
40500
|
}
|
|
39875
|
-
this.completer.registerProvider(new SubcommandProvider("provider", ["list", "use"]));
|
|
40501
|
+
this.completer.registerProvider(new SubcommandProvider("provider", ["list", "use", "add"]));
|
|
39876
40502
|
this.completer.registerProvider(new SubcommandProvider("model", ["list", "use"]));
|
|
39877
40503
|
const entryLabels = this.config.provider?.entries?.map((e) => e.label || e.type) ?? [];
|
|
39878
40504
|
if (entryLabels.length > 0) {
|
|
@@ -40199,6 +40825,10 @@ ${t("image.clipboard_empty")}`));
|
|
|
40199
40825
|
if (result.totalCost !== undefined && result.totalCost > 0) {
|
|
40200
40826
|
console.log(pc2.yellow(` ${t("repl.cost", { cost: formatCost(result.totalCost) })}`));
|
|
40201
40827
|
}
|
|
40828
|
+
const cacheLine = formatCacheLine(result.cache);
|
|
40829
|
+
if (cacheLine) {
|
|
40830
|
+
console.log(pc2.dim(` ${cacheLine}`));
|
|
40831
|
+
}
|
|
40202
40832
|
} else if (ui?.showCompaction && result.compactionCount !== undefined) {
|
|
40203
40833
|
if (result.compactionCount > this.lastCompactionShown) {
|
|
40204
40834
|
this.lastCompactionShown = result.compactionCount;
|
|
@@ -40383,6 +41013,10 @@ function printRunResult(result, flush) {
|
|
|
40383
41013
|
} else if (result.totalTokens !== undefined && result.totalTokens > 0) {
|
|
40384
41014
|
console.log(pc2.dim(`${t("repl.tokens", { tokens: result.totalTokens })}`));
|
|
40385
41015
|
}
|
|
41016
|
+
const cacheLine = formatCacheLine(result.cache);
|
|
41017
|
+
if (cacheLine) {
|
|
41018
|
+
console.log(pc2.dim(` ${cacheLine}`));
|
|
41019
|
+
}
|
|
40386
41020
|
if (!result.text) {
|
|
40387
41021
|
console.log(pc2.yellow(t("cli.no_output")));
|
|
40388
41022
|
}
|
|
@@ -40621,6 +41255,22 @@ function startAutoUpdate(config) {
|
|
|
40621
41255
|
async function main() {
|
|
40622
41256
|
installCrashHandlers();
|
|
40623
41257
|
const program2 = createProgram();
|
|
41258
|
+
const valueOpts = new Set(["-d", "--dir", "--reasoning"]);
|
|
41259
|
+
const argv = process.argv.slice(2);
|
|
41260
|
+
let firstPositional;
|
|
41261
|
+
for (let i = 0;i < argv.length; i++) {
|
|
41262
|
+
const a = argv[i];
|
|
41263
|
+
if (a.startsWith("-")) {
|
|
41264
|
+
if (valueOpts.has(a))
|
|
41265
|
+
i++;
|
|
41266
|
+
continue;
|
|
41267
|
+
}
|
|
41268
|
+
firstPositional = a;
|
|
41269
|
+
break;
|
|
41270
|
+
}
|
|
41271
|
+
if (firstPositional && program2.commands.some((c) => c.name() === firstPositional)) {
|
|
41272
|
+
setOneShotMode(true);
|
|
41273
|
+
}
|
|
40624
41274
|
program2.parse(process.argv);
|
|
40625
41275
|
const cmdNames = new Set(program2.commands.map((c) => c.name()));
|
|
40626
41276
|
const opts = program2.opts();
|
|
@@ -40672,7 +41322,8 @@ async function main() {
|
|
|
40672
41322
|
completionTokens: result2.completionTokens ?? null,
|
|
40673
41323
|
totalTokens: result2.totalTokens ?? null,
|
|
40674
41324
|
totalCost: result2.totalCost ?? null,
|
|
40675
|
-
costBreakdown: result2.costBreakdown ?? []
|
|
41325
|
+
costBreakdown: result2.costBreakdown ?? [],
|
|
41326
|
+
cache: result2.cache ?? null
|
|
40676
41327
|
}, null, 2));
|
|
40677
41328
|
process.stdout.write(`
|
|
40678
41329
|
`);
|