micro-models-agent 0.61.1 → 0.62.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 +18 -0
- package/dist/i18n/en.json +19 -0
- package/dist/i18n/ru.json +19 -0
- package/dist/main.js +664 -94
- package/package.json +1 -1
package/dist/main.js
CHANGED
|
@@ -3188,6 +3188,25 @@ Apply a matching solution from these results. If none is relevant — do NOT rep
|
|
|
3188
3188
|
"repl.cost": "Total cost: {cost}",
|
|
3189
3189
|
"repl.cost_breakdown": "By provider: {breakdown}",
|
|
3190
3190
|
"repl.tokens": "Tokens used: {tokens}",
|
|
3191
|
+
"repl.cache": "Cache: {hit}% hit · saved {saved}",
|
|
3192
|
+
"repl.cache_nosave": "Cache: {hit}% hit",
|
|
3193
|
+
"repl.prefix": "Prefix stable: {stable}% · broke: {cause}",
|
|
3194
|
+
"cache.cause.system": "system prompt",
|
|
3195
|
+
"cache.cause.tools": "tool set",
|
|
3196
|
+
"cache.cause.history": "history",
|
|
3197
|
+
"cache.cause.volatile": "volatile content",
|
|
3198
|
+
"cache.cause.unknown": "unknown",
|
|
3199
|
+
"cli.session_usage": "API usage: {prompt} prompt + {completion} completion = {total} tokens",
|
|
3200
|
+
"cli.session_cache": "Cache: {hit}% hit ({cached} cached / {uncached} uncached)",
|
|
3201
|
+
"cli.usage": "Show provider balance/usage (OpenRouter)",
|
|
3202
|
+
"cli.usage_unsupported": 'Provider "{provider}" does not expose an API balance. Only OpenRouter does; OpenCode Zen/Go show it in the web dashboard.',
|
|
3203
|
+
"cli.usage_no_key": "No API key configured for the active provider.",
|
|
3204
|
+
"cli.usage_error": "Failed to fetch balance: {error}",
|
|
3205
|
+
"cli.usage_key_usage": "Key usage: {usage}",
|
|
3206
|
+
"cli.usage_key_limit": "Key limit: {limit} · remaining {remaining}",
|
|
3207
|
+
"cli.usage_balance": "Balance: {balance}",
|
|
3208
|
+
"cli.usage_account": "Account: {credits} purchased · {used} used",
|
|
3209
|
+
"cli.usage_empty": "No balance information returned.",
|
|
3191
3210
|
"repl.ctrl_c_interrupt": `
|
|
3192
3211
|
[Ctrl+C] Stopping agent... (press again to force)`,
|
|
3193
3212
|
"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.',
|
|
@@ -4005,6 +4024,25 @@ var init_ru = __esm(() => {
|
|
|
4005
4024
|
"repl.cost": "Итого потрачено: {cost}",
|
|
4006
4025
|
"repl.cost_breakdown": "По провайдерам: {breakdown}",
|
|
4007
4026
|
"repl.tokens": "Потрачено токенов: {tokens}",
|
|
4027
|
+
"repl.cache": "Кеш: {hit}% попаданий · сэкономлено {saved}",
|
|
4028
|
+
"repl.cache_nosave": "Кеш: {hit}% попаданий",
|
|
4029
|
+
"repl.prefix": "Префикс стабилен: {stable}% · сломалось: {cause}",
|
|
4030
|
+
"cache.cause.system": "системный промпт",
|
|
4031
|
+
"cache.cause.tools": "набор инструментов",
|
|
4032
|
+
"cache.cause.history": "история",
|
|
4033
|
+
"cache.cause.volatile": "волатильное содержимое",
|
|
4034
|
+
"cache.cause.unknown": "неизвестно",
|
|
4035
|
+
"cli.session_usage": "API-использование: {prompt} prompt + {completion} completion = {total} токенов",
|
|
4036
|
+
"cli.session_cache": "Кеш: {hit}% попаданий ({cached} из кеша / {uncached} новых)",
|
|
4037
|
+
"cli.usage": "Показать баланс/расход провайдера (OpenRouter)",
|
|
4038
|
+
"cli.usage_unsupported": 'Провайдер "{provider}" не отдаёт баланс по API. Это умеет только OpenRouter; OpenCode Zen/Go показывают его в веб-дашборде.',
|
|
4039
|
+
"cli.usage_no_key": "Для активного провайдера не настроен API-ключ.",
|
|
4040
|
+
"cli.usage_error": "Не удалось получить баланс: {error}",
|
|
4041
|
+
"cli.usage_key_usage": "Расход по ключу: {usage}",
|
|
4042
|
+
"cli.usage_key_limit": "Лимит ключа: {limit} · осталось {remaining}",
|
|
4043
|
+
"cli.usage_balance": "Баланс: {balance}",
|
|
4044
|
+
"cli.usage_account": "Аккаунт: куплено {credits} · израсходовано {used}",
|
|
4045
|
+
"cli.usage_empty": "Провайдер не вернул данных о балансе.",
|
|
4008
4046
|
"repl.ctrl_c_interrupt": `
|
|
4009
4047
|
[Ctrl+C] Остановка агента... (ещё раз — принудительно)`,
|
|
4010
4048
|
"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 +5931,73 @@ class StreamState {
|
|
|
5893
5931
|
}
|
|
5894
5932
|
}
|
|
5895
5933
|
|
|
5934
|
+
// src/llm/cache-usage.ts
|
|
5935
|
+
function num(value) {
|
|
5936
|
+
return typeof value === "number" && Number.isFinite(value) ? value : undefined;
|
|
5937
|
+
}
|
|
5938
|
+
function isRecord(value) {
|
|
5939
|
+
return typeof value === "object" && value !== null;
|
|
5940
|
+
}
|
|
5941
|
+
function parseCacheUsage(usage, format, estimatedPromptTokens) {
|
|
5942
|
+
if (!isRecord(usage))
|
|
5943
|
+
return;
|
|
5944
|
+
switch (format) {
|
|
5945
|
+
case "openai": {
|
|
5946
|
+
const details = usage.prompt_tokens_details;
|
|
5947
|
+
if (!isRecord(details))
|
|
5948
|
+
return;
|
|
5949
|
+
const cached = num(details.cached_tokens);
|
|
5950
|
+
if (cached === undefined)
|
|
5951
|
+
return;
|
|
5952
|
+
const prompt = num(usage.prompt_tokens) ?? cached;
|
|
5953
|
+
const write = num(details.cache_write_tokens) ?? 0;
|
|
5954
|
+
return {
|
|
5955
|
+
cachedTokens: cached,
|
|
5956
|
+
cacheWriteTokens: write,
|
|
5957
|
+
uncachedTokens: Math.max(0, prompt - cached),
|
|
5958
|
+
source: "api"
|
|
5959
|
+
};
|
|
5960
|
+
}
|
|
5961
|
+
case "deepseek": {
|
|
5962
|
+
const hit = num(usage.prompt_cache_hit_tokens);
|
|
5963
|
+
const miss = num(usage.prompt_cache_miss_tokens);
|
|
5964
|
+
if (hit === undefined && miss === undefined)
|
|
5965
|
+
return;
|
|
5966
|
+
return {
|
|
5967
|
+
cachedTokens: hit ?? 0,
|
|
5968
|
+
cacheWriteTokens: 0,
|
|
5969
|
+
uncachedTokens: miss ?? 0,
|
|
5970
|
+
source: "api"
|
|
5971
|
+
};
|
|
5972
|
+
}
|
|
5973
|
+
case "anthropic": {
|
|
5974
|
+
const read = num(usage.cache_read_input_tokens);
|
|
5975
|
+
const creation = num(usage.cache_creation_input_tokens);
|
|
5976
|
+
if (read === undefined && creation === undefined)
|
|
5977
|
+
return;
|
|
5978
|
+
return {
|
|
5979
|
+
cachedTokens: read ?? 0,
|
|
5980
|
+
cacheWriteTokens: creation ?? 0,
|
|
5981
|
+
uncachedTokens: num(usage.input_tokens) ?? 0,
|
|
5982
|
+
source: "api"
|
|
5983
|
+
};
|
|
5984
|
+
}
|
|
5985
|
+
case "ollama": {
|
|
5986
|
+
const evaluated = num(usage.prompt_eval_count);
|
|
5987
|
+
if (evaluated === undefined || estimatedPromptTokens === undefined)
|
|
5988
|
+
return;
|
|
5989
|
+
return {
|
|
5990
|
+
cachedTokens: Math.max(0, estimatedPromptTokens - evaluated),
|
|
5991
|
+
cacheWriteTokens: 0,
|
|
5992
|
+
uncachedTokens: evaluated,
|
|
5993
|
+
source: "derived"
|
|
5994
|
+
};
|
|
5995
|
+
}
|
|
5996
|
+
default:
|
|
5997
|
+
return;
|
|
5998
|
+
}
|
|
5999
|
+
}
|
|
6000
|
+
|
|
5896
6001
|
// src/llm/openai-compat.ts
|
|
5897
6002
|
var exports_openai_compat = {};
|
|
5898
6003
|
__export(exports_openai_compat, {
|
|
@@ -5911,6 +6016,14 @@ function buildRequestBody(opts) {
|
|
|
5911
6016
|
};
|
|
5912
6017
|
if (opts.maxTokens !== undefined)
|
|
5913
6018
|
body.max_tokens = opts.maxTokens;
|
|
6019
|
+
if (opts.cachePrompt)
|
|
6020
|
+
body.cache_prompt = true;
|
|
6021
|
+
if (opts.promptCacheKey)
|
|
6022
|
+
body.prompt_cache_key = opts.promptCacheKey;
|
|
6023
|
+
if (opts.sessionId)
|
|
6024
|
+
body.session_id = opts.sessionId;
|
|
6025
|
+
if (opts.stream && opts.streamUsage)
|
|
6026
|
+
body.stream_options = { include_usage: true };
|
|
5914
6027
|
const strategy = opts.reasoningStrategy ?? "openai-effort";
|
|
5915
6028
|
const level = opts.reasoningEffort;
|
|
5916
6029
|
if (strategy === "openai-effort" && level && level !== "default") {
|
|
@@ -5944,10 +6057,14 @@ class OpenAICompatProvider {
|
|
|
5944
6057
|
debug;
|
|
5945
6058
|
getSessionId;
|
|
5946
6059
|
userAgent;
|
|
6060
|
+
cache;
|
|
6061
|
+
cacheReport;
|
|
5947
6062
|
constructor(config) {
|
|
5948
6063
|
this.config = config;
|
|
5949
6064
|
this.model = config.model;
|
|
5950
6065
|
this.contextWindow = config.contextWindow ?? 32768;
|
|
6066
|
+
this.cache = config.cache;
|
|
6067
|
+
this.cacheReport = config.cache?.report ?? "openai";
|
|
5951
6068
|
this.tokenCounter = new TokenCounter;
|
|
5952
6069
|
this.retryConfig = config.retry ?? {
|
|
5953
6070
|
maxRetries: 3,
|
|
@@ -6050,7 +6167,8 @@ class OpenAICompatProvider {
|
|
|
6050
6167
|
stream: true,
|
|
6051
6168
|
maxTokens,
|
|
6052
6169
|
reasoningEffort: options?.reasoningEffort,
|
|
6053
|
-
reasoningStrategy: options?.reasoningStrategy
|
|
6170
|
+
reasoningStrategy: options?.reasoningStrategy,
|
|
6171
|
+
...this.cacheHints()
|
|
6054
6172
|
});
|
|
6055
6173
|
this.debug?.("LLM stream request", {
|
|
6056
6174
|
baseUrl: this.config.baseUrl,
|
|
@@ -6158,7 +6276,8 @@ class OpenAICompatProvider {
|
|
|
6158
6276
|
st.usage = {
|
|
6159
6277
|
promptTokens: parsed.usage.prompt_tokens ?? 0,
|
|
6160
6278
|
completionTokens: parsed.usage.completion_tokens ?? 0,
|
|
6161
|
-
totalTokens: parsed.usage.total_tokens ?? 0
|
|
6279
|
+
totalTokens: parsed.usage.total_tokens ?? 0,
|
|
6280
|
+
cache: parseCacheUsage(parsed.usage, this.cacheReport)
|
|
6162
6281
|
};
|
|
6163
6282
|
this.debug?.("LLM stream usage", { ...st.usage });
|
|
6164
6283
|
} else if (parsed.error) {
|
|
@@ -6246,6 +6365,15 @@ class OpenAICompatProvider {
|
|
|
6246
6365
|
}
|
|
6247
6366
|
return st.sawDone;
|
|
6248
6367
|
}
|
|
6368
|
+
cacheHints() {
|
|
6369
|
+
const sessionId = this.getSessionId?.();
|
|
6370
|
+
return {
|
|
6371
|
+
cachePrompt: this.cache?.requestCachePrompt === true,
|
|
6372
|
+
promptCacheKey: this.cache?.requestPromptCacheKey ? sessionId : undefined,
|
|
6373
|
+
sessionId: this.cache?.requestSessionId ? sessionId : undefined,
|
|
6374
|
+
streamUsage: this.cache?.requestStreamUsage === true
|
|
6375
|
+
};
|
|
6376
|
+
}
|
|
6249
6377
|
buildRequestSetup(signal) {
|
|
6250
6378
|
const headers = {
|
|
6251
6379
|
"Content-Type": "application/json",
|
|
@@ -6255,7 +6383,8 @@ class OpenAICompatProvider {
|
|
|
6255
6383
|
headers["Authorization"] = `Bearer ${this.config.apiKey}`;
|
|
6256
6384
|
}
|
|
6257
6385
|
const sessionId = this.getSessionId?.();
|
|
6258
|
-
|
|
6386
|
+
const sendSessionHeader = this.cache ? this.cache.sessionHeader : true;
|
|
6387
|
+
if (sessionId && sendSessionHeader)
|
|
6259
6388
|
headers["x-opencode-session"] = sessionId;
|
|
6260
6389
|
const controller = new AbortController;
|
|
6261
6390
|
let timedOut = false;
|
|
@@ -6294,7 +6423,8 @@ class OpenAICompatProvider {
|
|
|
6294
6423
|
stream: false,
|
|
6295
6424
|
maxTokens: options?.maxTokens ?? this.config.maxCompletionTokens ?? 4096,
|
|
6296
6425
|
reasoningEffort: options?.reasoningEffort,
|
|
6297
|
-
reasoningStrategy: options?.reasoningStrategy
|
|
6426
|
+
reasoningStrategy: options?.reasoningStrategy,
|
|
6427
|
+
...this.cacheHints()
|
|
6298
6428
|
});
|
|
6299
6429
|
const { headers, abortSignal, cleanup, isTimeout } = this.buildRequestSetup(signal);
|
|
6300
6430
|
try {
|
|
@@ -6347,7 +6477,8 @@ class OpenAICompatProvider {
|
|
|
6347
6477
|
usage: {
|
|
6348
6478
|
promptTokens: data.usage.prompt_tokens ?? 0,
|
|
6349
6479
|
completionTokens: data.usage.completion_tokens ?? 0,
|
|
6350
|
-
totalTokens: data.usage.total_tokens ?? 0
|
|
6480
|
+
totalTokens: data.usage.total_tokens ?? 0,
|
|
6481
|
+
cache: parseCacheUsage(data.usage, this.cacheReport)
|
|
6351
6482
|
}
|
|
6352
6483
|
});
|
|
6353
6484
|
}
|
|
@@ -6469,6 +6600,7 @@ function openaiCompat(opts) {
|
|
|
6469
6600
|
rateLimits,
|
|
6470
6601
|
maxCompletionTokens: opts.maxCompletionTokens,
|
|
6471
6602
|
getSessionId: opts.getSessionId,
|
|
6603
|
+
cache: opts.capabilities?.cache,
|
|
6472
6604
|
logger: opts.logger
|
|
6473
6605
|
});
|
|
6474
6606
|
}
|
|
@@ -6486,7 +6618,17 @@ var init_presets = __esm(() => {
|
|
|
6486
6618
|
reasoningStrategy: "prompt-tag",
|
|
6487
6619
|
listModels: true,
|
|
6488
6620
|
requiresKey: false,
|
|
6489
|
-
auth: "bearer"
|
|
6621
|
+
auth: "bearer",
|
|
6622
|
+
cache: {
|
|
6623
|
+
mechanism: "local",
|
|
6624
|
+
report: "openai",
|
|
6625
|
+
sessionHeader: false,
|
|
6626
|
+
requestCachePrompt: false,
|
|
6627
|
+
requestPromptCacheKey: false,
|
|
6628
|
+
requestSessionId: false,
|
|
6629
|
+
requestCacheControl: false,
|
|
6630
|
+
requestStreamUsage: true
|
|
6631
|
+
}
|
|
6490
6632
|
},
|
|
6491
6633
|
create: openaiCompat
|
|
6492
6634
|
};
|
|
@@ -6501,7 +6643,17 @@ var init_presets = __esm(() => {
|
|
|
6501
6643
|
reasoningStrategy: "openai-effort",
|
|
6502
6644
|
listModels: true,
|
|
6503
6645
|
requiresKey: true,
|
|
6504
|
-
auth: "bearer"
|
|
6646
|
+
auth: "bearer",
|
|
6647
|
+
cache: {
|
|
6648
|
+
mechanism: "auto",
|
|
6649
|
+
report: "openai",
|
|
6650
|
+
sessionHeader: false,
|
|
6651
|
+
requestCachePrompt: false,
|
|
6652
|
+
requestPromptCacheKey: false,
|
|
6653
|
+
requestSessionId: true,
|
|
6654
|
+
requestCacheControl: false,
|
|
6655
|
+
requestStreamUsage: true
|
|
6656
|
+
}
|
|
6505
6657
|
},
|
|
6506
6658
|
create: openaiCompat
|
|
6507
6659
|
};
|
|
@@ -6516,7 +6668,17 @@ var init_presets = __esm(() => {
|
|
|
6516
6668
|
reasoningStrategy: "openai-effort",
|
|
6517
6669
|
listModels: true,
|
|
6518
6670
|
requiresKey: true,
|
|
6519
|
-
auth: "bearer"
|
|
6671
|
+
auth: "bearer",
|
|
6672
|
+
cache: {
|
|
6673
|
+
mechanism: "auto",
|
|
6674
|
+
report: "openai",
|
|
6675
|
+
sessionHeader: false,
|
|
6676
|
+
requestCachePrompt: false,
|
|
6677
|
+
requestPromptCacheKey: true,
|
|
6678
|
+
requestSessionId: false,
|
|
6679
|
+
requestCacheControl: false,
|
|
6680
|
+
requestStreamUsage: true
|
|
6681
|
+
}
|
|
6520
6682
|
},
|
|
6521
6683
|
create: openaiCompat
|
|
6522
6684
|
};
|
|
@@ -6531,7 +6693,17 @@ var init_presets = __esm(() => {
|
|
|
6531
6693
|
reasoningStrategy: "none",
|
|
6532
6694
|
listModels: false,
|
|
6533
6695
|
requiresKey: true,
|
|
6534
|
-
auth: "header"
|
|
6696
|
+
auth: "header",
|
|
6697
|
+
cache: {
|
|
6698
|
+
mechanism: "explicit",
|
|
6699
|
+
report: "anthropic",
|
|
6700
|
+
sessionHeader: false,
|
|
6701
|
+
requestCachePrompt: false,
|
|
6702
|
+
requestPromptCacheKey: false,
|
|
6703
|
+
requestSessionId: false,
|
|
6704
|
+
requestCacheControl: true,
|
|
6705
|
+
requestStreamUsage: false
|
|
6706
|
+
}
|
|
6535
6707
|
},
|
|
6536
6708
|
create: openaiCompat
|
|
6537
6709
|
};
|
|
@@ -6546,7 +6718,17 @@ var init_presets = __esm(() => {
|
|
|
6546
6718
|
reasoningStrategy: "openai-effort",
|
|
6547
6719
|
listModels: true,
|
|
6548
6720
|
requiresKey: false,
|
|
6549
|
-
auth: "bearer"
|
|
6721
|
+
auth: "bearer",
|
|
6722
|
+
cache: {
|
|
6723
|
+
mechanism: "auto",
|
|
6724
|
+
report: "openai",
|
|
6725
|
+
sessionHeader: true,
|
|
6726
|
+
requestCachePrompt: false,
|
|
6727
|
+
requestPromptCacheKey: false,
|
|
6728
|
+
requestSessionId: false,
|
|
6729
|
+
requestCacheControl: false,
|
|
6730
|
+
requestStreamUsage: true
|
|
6731
|
+
}
|
|
6550
6732
|
},
|
|
6551
6733
|
create: openaiCompat
|
|
6552
6734
|
};
|
|
@@ -6561,7 +6743,17 @@ var init_presets = __esm(() => {
|
|
|
6561
6743
|
reasoningStrategy: "openai-effort",
|
|
6562
6744
|
listModels: true,
|
|
6563
6745
|
requiresKey: false,
|
|
6564
|
-
auth: "bearer"
|
|
6746
|
+
auth: "bearer",
|
|
6747
|
+
cache: {
|
|
6748
|
+
mechanism: "auto",
|
|
6749
|
+
report: "openai",
|
|
6750
|
+
sessionHeader: true,
|
|
6751
|
+
requestCachePrompt: false,
|
|
6752
|
+
requestPromptCacheKey: false,
|
|
6753
|
+
requestSessionId: false,
|
|
6754
|
+
requestCacheControl: false,
|
|
6755
|
+
requestStreamUsage: true
|
|
6756
|
+
}
|
|
6565
6757
|
},
|
|
6566
6758
|
create: openaiCompat
|
|
6567
6759
|
};
|
|
@@ -6624,6 +6816,25 @@ var init_create = __esm(() => {
|
|
|
6624
6816
|
init_presets();
|
|
6625
6817
|
});
|
|
6626
6818
|
|
|
6819
|
+
// src/modules/providers/cache.ts
|
|
6820
|
+
function resolveCacheCapability(spec, override) {
|
|
6821
|
+
const base = spec?.capabilities.cache ?? NO_CACHE_CAPABILITY;
|
|
6822
|
+
return { ...base, ...override ?? {} };
|
|
6823
|
+
}
|
|
6824
|
+
var NO_CACHE_CAPABILITY;
|
|
6825
|
+
var init_cache = __esm(() => {
|
|
6826
|
+
NO_CACHE_CAPABILITY = {
|
|
6827
|
+
mechanism: "none",
|
|
6828
|
+
report: "none",
|
|
6829
|
+
sessionHeader: false,
|
|
6830
|
+
requestCachePrompt: false,
|
|
6831
|
+
requestPromptCacheKey: false,
|
|
6832
|
+
requestSessionId: false,
|
|
6833
|
+
requestCacheControl: false,
|
|
6834
|
+
requestStreamUsage: false
|
|
6835
|
+
};
|
|
6836
|
+
});
|
|
6837
|
+
|
|
6627
6838
|
// src/modules/providers/manager.ts
|
|
6628
6839
|
class ProviderManager {
|
|
6629
6840
|
entries;
|
|
@@ -6747,17 +6958,25 @@ class ProviderManager {
|
|
|
6747
6958
|
rateLimits: entry.rateLimits ?? this.opts.rateLimits,
|
|
6748
6959
|
maxCompletionTokens: entry.maxCompletionTokens,
|
|
6749
6960
|
getSessionId: this.opts.getSessionId,
|
|
6961
|
+
capabilities: this.resolveCapabilities(entry),
|
|
6750
6962
|
logger: this.opts.logger
|
|
6751
6963
|
}, this.registry);
|
|
6752
6964
|
this.cache.set(key, provider);
|
|
6753
6965
|
return provider;
|
|
6754
6966
|
}
|
|
6967
|
+
resolveCapabilities(entry) {
|
|
6968
|
+
const spec = this.registry.get(entry.type);
|
|
6969
|
+
if (!spec)
|
|
6970
|
+
return { cache: resolveCacheCapability(undefined, entry.cache) };
|
|
6971
|
+
return { ...spec.capabilities, cache: resolveCacheCapability(spec, entry.cache) };
|
|
6972
|
+
}
|
|
6755
6973
|
resetCache() {
|
|
6756
6974
|
this.cache.clear();
|
|
6757
6975
|
}
|
|
6758
6976
|
}
|
|
6759
6977
|
var init_manager = __esm(() => {
|
|
6760
6978
|
init_create();
|
|
6979
|
+
init_cache();
|
|
6761
6980
|
init_presets();
|
|
6762
6981
|
});
|
|
6763
6982
|
|
|
@@ -8160,8 +8379,8 @@ function buildDiff(oldLines, newLines) {
|
|
|
8160
8379
|
return result;
|
|
8161
8380
|
}
|
|
8162
8381
|
function formatLine(line, maxNumWidth) {
|
|
8163
|
-
const
|
|
8164
|
-
const numStr =
|
|
8382
|
+
const num2 = line.type === "remove" ? line.oldNum : line.newNum;
|
|
8383
|
+
const numStr = num2 !== null ? String(num2).padStart(maxNumWidth) : " ".repeat(maxNumWidth);
|
|
8165
8384
|
if (line.type === "remove") {
|
|
8166
8385
|
return `${numStr} ${pc2.red("-")} ${line.content}`;
|
|
8167
8386
|
} else if (line.type === "add") {
|
|
@@ -10296,7 +10515,12 @@ class SessionLogger {
|
|
|
10296
10515
|
completionTokens: usage.completionTokens,
|
|
10297
10516
|
totalTokens: usage.totalTokens,
|
|
10298
10517
|
source: usage.source,
|
|
10299
|
-
durationMs: usage.durationMs
|
|
10518
|
+
durationMs: usage.durationMs,
|
|
10519
|
+
cacheStable: usage.prefix ? Number(usage.prefix.stableRatio.toFixed(4)) : undefined,
|
|
10520
|
+
cacheCause: usage.prefix?.cause,
|
|
10521
|
+
cachedTokens: usage.cache?.cachedTokens,
|
|
10522
|
+
cacheWriteTokens: usage.cache?.cacheWriteTokens,
|
|
10523
|
+
cacheSource: usage.cache?.source
|
|
10300
10524
|
});
|
|
10301
10525
|
}
|
|
10302
10526
|
logError(message) {
|
|
@@ -10946,52 +11170,52 @@ ${output}
|
|
|
10946
11170
|
}
|
|
10947
11171
|
function parseNumber() {
|
|
10948
11172
|
const start = i;
|
|
10949
|
-
let
|
|
11173
|
+
let num2 = "";
|
|
10950
11174
|
let invalid = false;
|
|
10951
11175
|
if (text[i] === "-") {
|
|
10952
|
-
|
|
11176
|
+
num2 += text[i];
|
|
10953
11177
|
i++;
|
|
10954
11178
|
if (!isDigit(text[i]) && atEndOfNumber()) {
|
|
10955
|
-
|
|
11179
|
+
num2 += "0";
|
|
10956
11180
|
}
|
|
10957
11181
|
}
|
|
10958
11182
|
if (text[i] === "0" && isDigit(text[i + 1])) {
|
|
10959
11183
|
invalid = true;
|
|
10960
11184
|
}
|
|
10961
11185
|
while (isDigit(text[i])) {
|
|
10962
|
-
|
|
11186
|
+
num2 += text[i];
|
|
10963
11187
|
i++;
|
|
10964
11188
|
}
|
|
10965
11189
|
if (text[i] === ".") {
|
|
10966
|
-
if (
|
|
10967
|
-
|
|
11190
|
+
if (num2 === "" || num2 === "-") {
|
|
11191
|
+
num2 += "0";
|
|
10968
11192
|
}
|
|
10969
|
-
|
|
11193
|
+
num2 += text[i];
|
|
10970
11194
|
i++;
|
|
10971
11195
|
if (!isDigit(text[i])) {
|
|
10972
|
-
|
|
11196
|
+
num2 += "0";
|
|
10973
11197
|
}
|
|
10974
11198
|
while (isDigit(text[i])) {
|
|
10975
|
-
|
|
11199
|
+
num2 += text[i];
|
|
10976
11200
|
i++;
|
|
10977
11201
|
}
|
|
10978
11202
|
}
|
|
10979
11203
|
if (i > start) {
|
|
10980
11204
|
if (text[i] === "e" || text[i] === "E") {
|
|
10981
|
-
if (
|
|
11205
|
+
if (num2 === "-") {
|
|
10982
11206
|
invalid = true;
|
|
10983
11207
|
}
|
|
10984
|
-
|
|
11208
|
+
num2 += text[i];
|
|
10985
11209
|
i++;
|
|
10986
11210
|
if (text[i] === "-" || text[i] === "+") {
|
|
10987
|
-
|
|
11211
|
+
num2 += text[i];
|
|
10988
11212
|
i++;
|
|
10989
11213
|
}
|
|
10990
11214
|
if (!isDigit(text[i])) {
|
|
10991
|
-
|
|
11215
|
+
num2 += "0";
|
|
10992
11216
|
}
|
|
10993
11217
|
while (isDigit(text[i])) {
|
|
10994
|
-
|
|
11218
|
+
num2 += text[i];
|
|
10995
11219
|
i++;
|
|
10996
11220
|
}
|
|
10997
11221
|
}
|
|
@@ -10999,7 +11223,7 @@ ${output}
|
|
|
10999
11223
|
i = start;
|
|
11000
11224
|
return false;
|
|
11001
11225
|
}
|
|
11002
|
-
output += invalid ? `"${text.substring(start, i)}"` :
|
|
11226
|
+
output += invalid ? `"${text.substring(start, i)}"` : num2;
|
|
11003
11227
|
return true;
|
|
11004
11228
|
}
|
|
11005
11229
|
return false;
|
|
@@ -12791,6 +13015,24 @@ var init_moe_executor = __esm(() => {
|
|
|
12791
13015
|
// src/modules/lsp/project-root.ts
|
|
12792
13016
|
import { existsSync as existsSync24 } from "fs";
|
|
12793
13017
|
import { dirname as dirname9, join as join14, relative as relative3, isAbsolute as isAbsolute3 } from "path";
|
|
13018
|
+
import { platform as platform4 } from "os";
|
|
13019
|
+
function resolveTscCommand(startDir, maxLevels = 8) {
|
|
13020
|
+
const runtime = process.execPath;
|
|
13021
|
+
let dir = startDir;
|
|
13022
|
+
for (let i = 0;i < maxLevels; i++) {
|
|
13023
|
+
const js = join14(dir, "node_modules", "typescript", "bin", "tsc");
|
|
13024
|
+
if (existsSync24(js))
|
|
13025
|
+
return `"${runtime}" "${js}"`;
|
|
13026
|
+
const stub = join14(dir, "node_modules", ".bin", platform4() === "win32" ? "tsc.cmd" : "tsc");
|
|
13027
|
+
if (existsSync24(stub))
|
|
13028
|
+
return `"${stub}"`;
|
|
13029
|
+
const parent = dirname9(dir);
|
|
13030
|
+
if (parent === dir)
|
|
13031
|
+
break;
|
|
13032
|
+
dir = parent;
|
|
13033
|
+
}
|
|
13034
|
+
return null;
|
|
13035
|
+
}
|
|
12794
13036
|
function findProjectRoot(filePath, baseDir, markers) {
|
|
12795
13037
|
if (!markers || markers.length === 0)
|
|
12796
13038
|
return baseDir;
|
|
@@ -13163,7 +13405,10 @@ function findTypecheckRoot(baseDir, existingFiles = []) {
|
|
|
13163
13405
|
return best?.root ?? null;
|
|
13164
13406
|
}
|
|
13165
13407
|
async function runTypecheck(baseDir) {
|
|
13166
|
-
const
|
|
13408
|
+
const tsc = resolveTscCommand(baseDir);
|
|
13409
|
+
if (!tsc)
|
|
13410
|
+
return null;
|
|
13411
|
+
const entry = processRegistry.start(`${tsc} --noEmit --skipLibCheck`, baseDir);
|
|
13167
13412
|
const exited = await processRegistry.waitForExit(entry.id, 90000);
|
|
13168
13413
|
const output = entry.log.join(`
|
|
13169
13414
|
`);
|
|
@@ -13176,6 +13421,7 @@ var SKIP_DIRS, TEST_EXT_RE, PY_TEST_RE, TEST_STEP_RE;
|
|
|
13176
13421
|
var init_audit_runners = __esm(() => {
|
|
13177
13422
|
init_bash();
|
|
13178
13423
|
init_processes();
|
|
13424
|
+
init_project_root();
|
|
13179
13425
|
SKIP_DIRS = new Set([
|
|
13180
13426
|
"node_modules",
|
|
13181
13427
|
".git",
|
|
@@ -13354,7 +13600,7 @@ var init_auditor = __esm(() => {
|
|
|
13354
13600
|
|
|
13355
13601
|
// src/modules/execution/verifier.ts
|
|
13356
13602
|
import { existsSync as existsSync27, readFileSync as readFileSync14 } from "fs";
|
|
13357
|
-
import { resolve as resolve13, extname as extname3, join as join17 } from "path";
|
|
13603
|
+
import { resolve as resolve13, extname as extname3, dirname as dirname11, join as join17 } from "path";
|
|
13358
13604
|
import { spawn as spawn4 } from "child_process";
|
|
13359
13605
|
|
|
13360
13606
|
class StepVerifier {
|
|
@@ -13386,8 +13632,11 @@ class StepVerifier {
|
|
|
13386
13632
|
if (!existsSync27(tsconfigPath)) {
|
|
13387
13633
|
return { passed: true, message: "No tsconfig.json found — skipping type check" };
|
|
13388
13634
|
}
|
|
13635
|
+
const tsc = resolveTscCommand(this.baseDir);
|
|
13636
|
+
if (!tsc)
|
|
13637
|
+
return { passed: true, message: "tsc not installed — skipping type check" };
|
|
13389
13638
|
try {
|
|
13390
|
-
await this.runAsync(
|
|
13639
|
+
await this.runAsync(`${tsc} --noEmit`, this.baseDir, 60000);
|
|
13391
13640
|
return { passed: true, message: "TypeScript type check passed" };
|
|
13392
13641
|
} catch (e) {
|
|
13393
13642
|
const stderr = e.stderr?.toString() || e.stdout?.toString() || e.message;
|
|
@@ -13400,8 +13649,11 @@ class StepVerifier {
|
|
|
13400
13649
|
if (!existsSync27(tsconfigPath)) {
|
|
13401
13650
|
return { passed: true, message: "No tsconfig.json found — skipping type check" };
|
|
13402
13651
|
}
|
|
13652
|
+
const tsc = resolveTscCommand(projectRoot);
|
|
13653
|
+
if (!tsc)
|
|
13654
|
+
return { passed: true, message: "tsc not installed — skipping type check" };
|
|
13403
13655
|
try {
|
|
13404
|
-
await this.runAsync(
|
|
13656
|
+
await this.runAsync(`${tsc} --noEmit --skipLibCheck`, projectRoot, 60000);
|
|
13405
13657
|
return { passed: true, message: "TypeScript type check passed" };
|
|
13406
13658
|
} catch (e) {
|
|
13407
13659
|
const stderr = e.stderr?.toString() || e.stdout?.toString() || e.message;
|
|
@@ -13554,8 +13806,11 @@ class StepVerifier {
|
|
|
13554
13806
|
async validateSyntax(filePath) {
|
|
13555
13807
|
const ext = extname3(filePath);
|
|
13556
13808
|
if (ext === ".ts" || ext === ".tsx" || ext === ".cts" || ext === ".mts") {
|
|
13809
|
+
const tsc = resolveTscCommand(dirname11(filePath));
|
|
13810
|
+
if (!tsc)
|
|
13811
|
+
return true;
|
|
13557
13812
|
try {
|
|
13558
|
-
await this.runAsync(
|
|
13813
|
+
await this.runAsync(`${tsc} --noEmit --skipLibCheck "${filePath}"`, this.baseDir, 20000);
|
|
13559
13814
|
return true;
|
|
13560
13815
|
} catch (err) {
|
|
13561
13816
|
if (err.status === 127 || err.message.includes("not found") || err.message.includes("ENOENT")) {
|
|
@@ -13885,11 +14140,18 @@ function resolvePrice(model, config) {
|
|
|
13885
14140
|
return direct;
|
|
13886
14141
|
return ZEN_PRICES[bare];
|
|
13887
14142
|
}
|
|
13888
|
-
function
|
|
14143
|
+
function calculateCostDetailed(model, promptTokens, completionTokens, config, cache) {
|
|
13889
14144
|
const price = resolvePrice(model, config);
|
|
13890
14145
|
if (!price)
|
|
13891
14146
|
return;
|
|
13892
|
-
|
|
14147
|
+
const cached = Math.max(0, cache?.cachedTokens ?? 0);
|
|
14148
|
+
const write = Math.max(0, cache?.cacheWriteTokens ?? 0);
|
|
14149
|
+
const uncached = Math.max(0, promptTokens - cached);
|
|
14150
|
+
const cachedRate = price.cachedInput ?? price.input;
|
|
14151
|
+
const writeRate = price.cacheWrite ?? 0;
|
|
14152
|
+
const cost = uncached / 1e6 * price.input + cached / 1e6 * cachedRate + write / 1e6 * writeRate + completionTokens / 1e6 * price.output;
|
|
14153
|
+
const saved = cached / 1e6 * (price.input - cachedRate);
|
|
14154
|
+
return { cost, saved };
|
|
13893
14155
|
}
|
|
13894
14156
|
function formatCost(cost) {
|
|
13895
14157
|
if (cost === 0)
|
|
@@ -13909,12 +14171,12 @@ var init_prices = __esm(() => {
|
|
|
13909
14171
|
"nemotron-3-ultra-free": { input: 0, output: 0 },
|
|
13910
14172
|
"nemotron-3.5-lightning-free": { input: 0, output: 0 },
|
|
13911
14173
|
"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 },
|
|
14174
|
+
"minimax-m3": { input: 0.3, output: 1.2, cachedInput: 0.06 },
|
|
14175
|
+
"minimax-m2.7": { input: 0.3, output: 1.2, cachedInput: 0.06 },
|
|
14176
|
+
"minimax-m2.5": { input: 0.3, output: 1.2, cachedInput: 0.06 },
|
|
14177
|
+
"glm-5.2": { input: 1.4, output: 4.4, cachedInput: 0.26 },
|
|
14178
|
+
"glm-5.1": { input: 1.4, output: 4.4, cachedInput: 0.26 },
|
|
14179
|
+
"glm-5": { input: 1, output: 3.2, cachedInput: 0.2 },
|
|
13918
14180
|
"glm-5.3": { input: 1.4, output: 4.4 },
|
|
13919
14181
|
"kimi-k2.7-code": { input: 0.95, output: 4 },
|
|
13920
14182
|
"kimi-k3": { input: 3, output: 15 },
|
|
@@ -13976,6 +14238,7 @@ class CostTracker {
|
|
|
13976
14238
|
config;
|
|
13977
14239
|
model;
|
|
13978
14240
|
_total = 0;
|
|
14241
|
+
_saved = 0;
|
|
13979
14242
|
_known = false;
|
|
13980
14243
|
byProvider = new Map;
|
|
13981
14244
|
constructor(model, config) {
|
|
@@ -13985,24 +14248,28 @@ class CostTracker {
|
|
|
13985
14248
|
setModel(model) {
|
|
13986
14249
|
this.model = model;
|
|
13987
14250
|
}
|
|
13988
|
-
record(promptTokens, completionTokens, provider) {
|
|
14251
|
+
record(promptTokens, completionTokens, provider, cache) {
|
|
13989
14252
|
const key = provider || "unknown";
|
|
13990
|
-
const
|
|
13991
|
-
if (
|
|
14253
|
+
const result = calculateCostDetailed(this.model, promptTokens, completionTokens, this.config, cache);
|
|
14254
|
+
if (!result)
|
|
13992
14255
|
return;
|
|
13993
14256
|
this._known = true;
|
|
13994
|
-
this._total += cost;
|
|
14257
|
+
this._total += result.cost;
|
|
14258
|
+
this._saved += result.saved;
|
|
13995
14259
|
let entry = this.byProvider.get(key);
|
|
13996
14260
|
if (!entry) {
|
|
13997
14261
|
entry = { total: 0, known: false };
|
|
13998
14262
|
this.byProvider.set(key, entry);
|
|
13999
14263
|
}
|
|
14000
14264
|
entry.known = true;
|
|
14001
|
-
entry.total += cost;
|
|
14265
|
+
entry.total += result.cost;
|
|
14002
14266
|
}
|
|
14003
14267
|
get total() {
|
|
14004
14268
|
return this._known ? this._total : undefined;
|
|
14005
14269
|
}
|
|
14270
|
+
get saved() {
|
|
14271
|
+
return this._known ? this._saved : undefined;
|
|
14272
|
+
}
|
|
14006
14273
|
totalFor(provider) {
|
|
14007
14274
|
const entry = this.byProvider.get(provider);
|
|
14008
14275
|
return entry && entry.known ? entry.total : undefined;
|
|
@@ -14083,6 +14350,10 @@ function createLoopState() {
|
|
|
14083
14350
|
apiCompletionChars: 0,
|
|
14084
14351
|
estimatedPromptTokensTotal: 0,
|
|
14085
14352
|
totalLlmDuration: 0,
|
|
14353
|
+
cacheCachedTotal: 0,
|
|
14354
|
+
cacheUncachedTotal: 0,
|
|
14355
|
+
cacheWriteTotal: 0,
|
|
14356
|
+
cacheSource: "none",
|
|
14086
14357
|
auditRetries: 0,
|
|
14087
14358
|
lastAuditSummary: "",
|
|
14088
14359
|
emptyResponseRetries: 0,
|
|
@@ -14189,6 +14460,7 @@ class TokenTracker {
|
|
|
14189
14460
|
}
|
|
14190
14461
|
beginIteration(state, estimatedPromptTokens) {
|
|
14191
14462
|
state.estimatedPromptTokensTotal += estimatedPromptTokens;
|
|
14463
|
+
state.cacheUsage = undefined;
|
|
14192
14464
|
return {
|
|
14193
14465
|
promptBefore: state.apiPromptTokens,
|
|
14194
14466
|
completionBefore: state.apiCompletionTokens
|
|
@@ -14197,6 +14469,7 @@ class TokenTracker {
|
|
|
14197
14469
|
recordApiUsage(state, baseline, usage) {
|
|
14198
14470
|
state.apiPromptTokens = baseline.promptBefore + usage.promptTokens;
|
|
14199
14471
|
state.apiCompletionTokens = baseline.completionBefore + usage.completionTokens;
|
|
14472
|
+
state.cacheUsage = usage.cache;
|
|
14200
14473
|
}
|
|
14201
14474
|
addCompletionChars(state, chars) {
|
|
14202
14475
|
state.apiCompletionChars += chars;
|
|
@@ -14207,14 +14480,22 @@ class TokenTracker {
|
|
|
14207
14480
|
const source = usagePrompt > 0 || usageCompletion > 0 ? "api" : "estimate";
|
|
14208
14481
|
const prompt = source === "api" ? usagePrompt : contextTokens;
|
|
14209
14482
|
const completion = source === "api" ? usageCompletion : estimateTokens(textContent);
|
|
14483
|
+
if (state.cacheUsage) {
|
|
14484
|
+
state.cacheCachedTotal += state.cacheUsage.cachedTokens;
|
|
14485
|
+
state.cacheUncachedTotal += state.cacheUsage.uncachedTokens;
|
|
14486
|
+
state.cacheWriteTotal += state.cacheUsage.cacheWriteTokens;
|
|
14487
|
+
state.cacheSource = state.cacheUsage.source;
|
|
14488
|
+
}
|
|
14210
14489
|
slog.logLlmUsage(iteration, {
|
|
14211
14490
|
promptTokens: prompt,
|
|
14212
14491
|
completionTokens: completion,
|
|
14213
14492
|
totalTokens: prompt + completion,
|
|
14214
14493
|
source,
|
|
14215
|
-
durationMs
|
|
14494
|
+
durationMs,
|
|
14495
|
+
prefix: state.prefixDelta,
|
|
14496
|
+
cache: state.cacheUsage
|
|
14216
14497
|
});
|
|
14217
|
-
this.costTracker.record(prompt, completion, this.getProviderName());
|
|
14498
|
+
this.costTracker.record(prompt, completion, this.getProviderName(), source === "api" ? state.cacheUsage : undefined);
|
|
14218
14499
|
}
|
|
14219
14500
|
resolveFinal(state) {
|
|
14220
14501
|
if (state.apiPromptTokens > 0 || state.apiCompletionTokens > 0) {
|
|
@@ -14233,6 +14514,75 @@ var init_token_tracker = __esm(() => {
|
|
|
14233
14514
|
init_token_counter();
|
|
14234
14515
|
});
|
|
14235
14516
|
|
|
14517
|
+
// src/core/agent/prefix-monitor.ts
|
|
14518
|
+
function serializeTools(tools) {
|
|
14519
|
+
return tools.map((t2) => `${t2.name}\x01${t2.description}\x01${JSON.stringify(t2.parameters)}`).join("\x02");
|
|
14520
|
+
}
|
|
14521
|
+
function serializeMessages(messages) {
|
|
14522
|
+
return messages.map((m) => `${m.role}\x01${typeof m.content === "string" ? m.content : JSON.stringify(m.content)}`).join("\x02");
|
|
14523
|
+
}
|
|
14524
|
+
function buildPromptSnapshot(messages, tools) {
|
|
14525
|
+
const system = [];
|
|
14526
|
+
const rest = [];
|
|
14527
|
+
for (const m of messages) {
|
|
14528
|
+
if (m.role === "system")
|
|
14529
|
+
system.push(m);
|
|
14530
|
+
else
|
|
14531
|
+
rest.push(m);
|
|
14532
|
+
}
|
|
14533
|
+
return {
|
|
14534
|
+
system: serializeMessages(system),
|
|
14535
|
+
tools: serializeTools(tools),
|
|
14536
|
+
history: serializeMessages(rest)
|
|
14537
|
+
};
|
|
14538
|
+
}
|
|
14539
|
+
function frame(s) {
|
|
14540
|
+
const full = s.system + SEP + s.tools + SEP + s.history;
|
|
14541
|
+
const toolsStart = s.system.length + SEP.length;
|
|
14542
|
+
const historyStart = toolsStart + s.tools.length + SEP.length;
|
|
14543
|
+
return { full, toolsStart, historyStart };
|
|
14544
|
+
}
|
|
14545
|
+
function diffPrompt(prev, curr, countTokens) {
|
|
14546
|
+
const c = frame(curr);
|
|
14547
|
+
const currTokens = countTokens(c.full);
|
|
14548
|
+
if (!prev) {
|
|
14549
|
+
return {
|
|
14550
|
+
prevTokens: 0,
|
|
14551
|
+
currTokens,
|
|
14552
|
+
commonPrefixTokens: 0,
|
|
14553
|
+
stableRatio: 0,
|
|
14554
|
+
cause: "unknown"
|
|
14555
|
+
};
|
|
14556
|
+
}
|
|
14557
|
+
const p = frame(prev);
|
|
14558
|
+
const prevTokens = countTokens(p.full);
|
|
14559
|
+
const maxCp = Math.min(p.full.length, c.full.length);
|
|
14560
|
+
let cp = 0;
|
|
14561
|
+
while (cp < maxCp && p.full[cp] === c.full[cp])
|
|
14562
|
+
cp++;
|
|
14563
|
+
const commonPrefixTokens = countTokens(c.full.slice(0, cp));
|
|
14564
|
+
const stableRatio = currTokens === 0 ? 0 : Math.min(1, commonPrefixTokens / currTokens);
|
|
14565
|
+
if (cp === maxCp) {
|
|
14566
|
+
return { prevTokens, currTokens, commonPrefixTokens, stableRatio, cause: "none" };
|
|
14567
|
+
}
|
|
14568
|
+
let cause;
|
|
14569
|
+
if (cp >= c.historyStart)
|
|
14570
|
+
cause = "history";
|
|
14571
|
+
else if (cp >= c.toolsStart)
|
|
14572
|
+
cause = "tools";
|
|
14573
|
+
else
|
|
14574
|
+
cause = "system";
|
|
14575
|
+
const window = c.full.slice(Math.max(0, cp - 40), cp + 160) + p.full.slice(Math.max(0, cp - 40), cp + 160);
|
|
14576
|
+
if (VOLATILE_RE.test(window))
|
|
14577
|
+
cause = "volatile";
|
|
14578
|
+
return { prevTokens, currTokens, commonPrefixTokens, stableRatio, cause };
|
|
14579
|
+
}
|
|
14580
|
+
var SEP = `
|
|
14581
|
+
`, VOLATILE_RE;
|
|
14582
|
+
var init_prefix_monitor = __esm(() => {
|
|
14583
|
+
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\/)/;
|
|
14584
|
+
});
|
|
14585
|
+
|
|
14236
14586
|
// src/core/agent/reasoning-resolver.ts
|
|
14237
14587
|
class ReasoningEffortResolver {
|
|
14238
14588
|
resolve(deps) {
|
|
@@ -15261,6 +15611,12 @@ class Agent {
|
|
|
15261
15611
|
compactionService.compactIfNeeded(state);
|
|
15262
15612
|
this.refreshSystemPrompt();
|
|
15263
15613
|
const history = contextManager.getActiveHistory();
|
|
15614
|
+
const promptSnapshot = buildPromptSnapshot(history, allToolsForBudget);
|
|
15615
|
+
state.prefixDelta = diffPrompt(state.prevPrompt, promptSnapshot, estimateTokens);
|
|
15616
|
+
state.prevPrompt = promptSnapshot;
|
|
15617
|
+
if (state.prefixDelta.cause === "system" || state.prefixDelta.cause === "tools" || state.prefixDelta.cause === "history" || state.prefixDelta.cause === "volatile") {
|
|
15618
|
+
state.lastPrefixBreak = state.prefixDelta;
|
|
15619
|
+
}
|
|
15264
15620
|
slog.logToolDefs(allToolsForBudget.length, allToolsForBudget.map((t2) => t2.name), state.iteration);
|
|
15265
15621
|
if (state.iteration === 1) {
|
|
15266
15622
|
const { blocks } = this.buildSystemPrompt();
|
|
@@ -15509,6 +15865,7 @@ class Agent {
|
|
|
15509
15865
|
const tokensUsed = contextManager.getEstimatedTokens();
|
|
15510
15866
|
const budget = contextManager.getBudget();
|
|
15511
15867
|
const usageTokens = tokenTracker.resolveFinal(state);
|
|
15868
|
+
const cacheStats = this.buildCacheStats(state);
|
|
15512
15869
|
if (state.iteration >= config.maxToolIterations && !state.finalAnswerAccepted) {
|
|
15513
15870
|
return {
|
|
15514
15871
|
success: false,
|
|
@@ -15522,6 +15879,7 @@ class Agent {
|
|
|
15522
15879
|
totalTokens: usageTokens.total,
|
|
15523
15880
|
totalCost: this.costTracker.total,
|
|
15524
15881
|
costBreakdown: this.costTracker.breakdown(),
|
|
15882
|
+
cache: cacheStats,
|
|
15525
15883
|
compactionCount: contextManager.getCompactionCount(),
|
|
15526
15884
|
contextQuality: contextManager.getQuality()
|
|
15527
15885
|
};
|
|
@@ -15538,11 +15896,29 @@ class Agent {
|
|
|
15538
15896
|
totalTokens: usageTokens.total,
|
|
15539
15897
|
totalCost: this.costTracker.total,
|
|
15540
15898
|
costBreakdown: this.costTracker.breakdown(),
|
|
15899
|
+
cache: cacheStats,
|
|
15541
15900
|
compactionCount: contextManager.getCompactionCount(),
|
|
15542
15901
|
contextQuality: contextManager.getQuality(),
|
|
15543
15902
|
llmDurationMs: state.totalLlmDuration
|
|
15544
15903
|
};
|
|
15545
15904
|
}
|
|
15905
|
+
buildCacheStats(state) {
|
|
15906
|
+
const hasTokens = state.cacheCachedTotal > 0 || state.cacheUncachedTotal > 0 || state.cacheWriteTotal > 0;
|
|
15907
|
+
const prefix = state.lastPrefixBreak ?? state.prefixDelta;
|
|
15908
|
+
if (!hasTokens && prefix?.stableRatio === undefined)
|
|
15909
|
+
return;
|
|
15910
|
+
const denom = state.cacheCachedTotal + state.cacheUncachedTotal;
|
|
15911
|
+
return {
|
|
15912
|
+
cachedTokens: state.cacheCachedTotal,
|
|
15913
|
+
uncachedTokens: state.cacheUncachedTotal,
|
|
15914
|
+
cacheWriteTokens: state.cacheWriteTotal,
|
|
15915
|
+
hitRate: denom > 0 ? state.cacheCachedTotal / denom : 0,
|
|
15916
|
+
saved: this.costTracker.saved,
|
|
15917
|
+
prefixStable: prefix?.stableRatio,
|
|
15918
|
+
prefixCause: prefix?.cause,
|
|
15919
|
+
source: state.cacheSource
|
|
15920
|
+
};
|
|
15921
|
+
}
|
|
15546
15922
|
clearContext() {
|
|
15547
15923
|
this.deps.contextManager.clear();
|
|
15548
15924
|
this.systemPromptAdded = false;
|
|
@@ -15647,6 +16023,7 @@ var init_agent = __esm(() => {
|
|
|
15647
16023
|
init_loop_state();
|
|
15648
16024
|
init_compaction();
|
|
15649
16025
|
init_token_tracker();
|
|
16026
|
+
init_prefix_monitor();
|
|
15650
16027
|
init_reasoning_resolver();
|
|
15651
16028
|
init_context_renderer();
|
|
15652
16029
|
init_tool_batch();
|
|
@@ -16538,8 +16915,8 @@ var init_detector = __esm(() => {
|
|
|
16538
16915
|
// src/modules/lsp/command.ts
|
|
16539
16916
|
import { delimiter, join as join21 } from "path";
|
|
16540
16917
|
import { existsSync as existsSync30 } from "fs";
|
|
16541
|
-
import { platform as
|
|
16542
|
-
function resolveSpawnCommand(command, platformName =
|
|
16918
|
+
import { platform as platform5 } from "os";
|
|
16919
|
+
function resolveSpawnCommand(command, platformName = platform5(), pathEnv = process.env.PATH ?? "") {
|
|
16543
16920
|
if (platformName !== "win32")
|
|
16544
16921
|
return command;
|
|
16545
16922
|
if (command.includes("/") || command.includes("\\") || WIN_EXTS.some((ext) => command.toLowerCase().endsWith(ext))) {
|
|
@@ -16571,7 +16948,7 @@ var init_command = __esm(() => {
|
|
|
16571
16948
|
});
|
|
16572
16949
|
|
|
16573
16950
|
// src/modules/updater/checker.ts
|
|
16574
|
-
import { platform as
|
|
16951
|
+
import { platform as platform6 } from "os";
|
|
16575
16952
|
function semverGt(a, b) {
|
|
16576
16953
|
const pa = a.replace(/^v/, "").split(/[.-]/).map((p) => Number.parseInt(p, 10) || 0);
|
|
16577
16954
|
const pb = b.replace(/^v/, "").split(/[.-]/).map((p) => Number.parseInt(p, 10) || 0);
|
|
@@ -16642,7 +17019,7 @@ class Updater {
|
|
|
16642
17019
|
buildInstallCommand(latest) {
|
|
16643
17020
|
const npmArgs = ["install", "-g", `${this.packageName}@${latest}`];
|
|
16644
17021
|
const command = resolveSpawnCommand("npm");
|
|
16645
|
-
if (
|
|
17022
|
+
if (platform6() === "win32" && /\.(cmd|bat)$/i.test(command)) {
|
|
16646
17023
|
return { command: "cmd.exe", args: ["/c", command, ...npmArgs] };
|
|
16647
17024
|
}
|
|
16648
17025
|
return { command, args: npmArgs };
|
|
@@ -20167,11 +20544,11 @@ async function readClipboardImage() {
|
|
|
20167
20544
|
return readClipboardFallback();
|
|
20168
20545
|
}
|
|
20169
20546
|
async function readClipboardFallback() {
|
|
20170
|
-
const { platform:
|
|
20547
|
+
const { platform: platform7 } = await import("os");
|
|
20171
20548
|
const { execSync } = await import("child_process");
|
|
20172
20549
|
const { readFileSync: readFileSync21, unlinkSync: unlinkSync5 } = await import("fs");
|
|
20173
20550
|
const { join: join30 } = await import("path");
|
|
20174
|
-
if (
|
|
20551
|
+
if (platform7() !== "linux")
|
|
20175
20552
|
return null;
|
|
20176
20553
|
const tmpPath = join30(process.env.TEMP || process.env.TMP || "/tmp", `mma-clip-${Date.now()}.png`);
|
|
20177
20554
|
const commands = [
|
|
@@ -20847,7 +21224,7 @@ var init_auto_fixer = __esm(() => {
|
|
|
20847
21224
|
import { spawn as spawn7, execSync } from "child_process";
|
|
20848
21225
|
import { existsSync as existsSync37, readFileSync as readFileSync21, writeFileSync as writeFileSync13 } from "fs";
|
|
20849
21226
|
import { resolve as resolve17, extname as extname6, join as join31 } from "path";
|
|
20850
|
-
import { platform as
|
|
21227
|
+
import { platform as platform7 } from "os";
|
|
20851
21228
|
function lintCacheKey(baseDir, lintScript) {
|
|
20852
21229
|
return `${baseDir}::${lintScript}`;
|
|
20853
21230
|
}
|
|
@@ -20868,7 +21245,7 @@ function contentHash2(content) {
|
|
|
20868
21245
|
function getWinDecoder() {
|
|
20869
21246
|
if (_winDecoder !== undefined)
|
|
20870
21247
|
return _winDecoder;
|
|
20871
|
-
if (
|
|
21248
|
+
if (platform7() !== "win32") {
|
|
20872
21249
|
_winDecoder = new TextDecoder("utf-8");
|
|
20873
21250
|
return _winDecoder;
|
|
20874
21251
|
}
|
|
@@ -21029,6 +21406,10 @@ ${stdout}`;
|
|
|
21029
21406
|
if (!existsSync37(tsconfigPath)) {
|
|
21030
21407
|
return;
|
|
21031
21408
|
}
|
|
21409
|
+
const tsc = resolveTscCommand(projectRoot);
|
|
21410
|
+
if (!tsc) {
|
|
21411
|
+
return;
|
|
21412
|
+
}
|
|
21032
21413
|
const now = Date.now();
|
|
21033
21414
|
if (this._checkPromise && now - this._checkTimestamp < TYPE_CHECK_DEBOUNCE_MS) {
|
|
21034
21415
|
const error2 = await this._checkPromise;
|
|
@@ -21040,10 +21421,10 @@ ${stdout}`;
|
|
|
21040
21421
|
return;
|
|
21041
21422
|
}
|
|
21042
21423
|
this._checkTimestamp = now;
|
|
21043
|
-
this._checkPromise = this.runTscCheck(projectRoot, signal);
|
|
21424
|
+
this._checkPromise = this.runTscCheck(tsc, projectRoot, signal);
|
|
21044
21425
|
const error = await this._checkPromise;
|
|
21045
21426
|
if (error) {
|
|
21046
|
-
const { stdout, stderr } = await runAsync(
|
|
21427
|
+
const { stdout, stderr } = await runAsync(`${tsc} --noEmit --skipLibCheck 2>&1`, projectRoot, 30000, signal).catch(() => ({ stdout: "", stderr: error }));
|
|
21047
21428
|
const output = stderr || stdout;
|
|
21048
21429
|
const errors = parseTscOutput(output);
|
|
21049
21430
|
if (errors.length > 0) {
|
|
@@ -21072,9 +21453,9 @@ ${stdout}`;
|
|
|
21072
21453
|
}
|
|
21073
21454
|
}
|
|
21074
21455
|
}
|
|
21075
|
-
async runTscCheck(baseDir, signal) {
|
|
21456
|
+
async runTscCheck(tsc, baseDir, signal) {
|
|
21076
21457
|
try {
|
|
21077
|
-
const { stdout, stderr } = await runAsync(
|
|
21458
|
+
const { stdout, stderr } = await runAsync(`${tsc} --noEmit --skipLibCheck`, baseDir, 30000, signal);
|
|
21078
21459
|
return null;
|
|
21079
21460
|
} catch (err) {
|
|
21080
21461
|
if (err.status === 127 || err.message.includes("not found") || err.message.includes("ENOENT")) {
|
|
@@ -21560,7 +21941,7 @@ function switchStepToDelete(plan, step, save) {
|
|
|
21560
21941
|
}
|
|
21561
21942
|
|
|
21562
21943
|
// src/modules/execution/execution-plugin.ts
|
|
21563
|
-
import { platform as
|
|
21944
|
+
import { platform as platform8 } from "os";
|
|
21564
21945
|
function normalizeBrokenPath(p) {
|
|
21565
21946
|
return toForwardSlash(p).replace(/^\.\//, "");
|
|
21566
21947
|
}
|
|
@@ -21793,7 +22174,7 @@ Last compile error: ${first[1]}`;
|
|
|
21793
22174
|
if (call.name === "bash") {
|
|
21794
22175
|
deps.stuckDetector.recordBashAttempt(false);
|
|
21795
22176
|
}
|
|
21796
|
-
if (call.name === "bash" &&
|
|
22177
|
+
if (call.name === "bash" && platform8() === "win32") {
|
|
21797
22178
|
const cmd = String(call.arguments?.command ?? "");
|
|
21798
22179
|
const forbidden = forbiddenWindowsCommand(cmd);
|
|
21799
22180
|
if (forbidden) {
|
|
@@ -23687,7 +24068,7 @@ class ProfileCompressor {
|
|
|
23687
24068
|
// src/modules/user-profile/profile.ts
|
|
23688
24069
|
import { readFileSync as readFileSync26, writeFileSync as writeFileSync17, existsSync as existsSync42, mkdirSync as mkdirSync18 } from "fs";
|
|
23689
24070
|
import { join as join35 } from "path";
|
|
23690
|
-
import { homedir as homedir10, hostname, platform as
|
|
24071
|
+
import { homedir as homedir10, hostname, platform as platform9, type } from "os";
|
|
23691
24072
|
import { env } from "process";
|
|
23692
24073
|
|
|
23693
24074
|
class UserProfile {
|
|
@@ -23699,7 +24080,7 @@ class UserProfile {
|
|
|
23699
24080
|
}
|
|
23700
24081
|
collect() {
|
|
23701
24082
|
this.info = {
|
|
23702
|
-
platform:
|
|
24083
|
+
platform: platform9(),
|
|
23703
24084
|
os: `${type()} ${hostname()}`,
|
|
23704
24085
|
hostname: hostname(),
|
|
23705
24086
|
shell: env.SHELL || env.ComSpec || "unknown",
|
|
@@ -24021,7 +24402,7 @@ var init_browser2 = __esm(() => {
|
|
|
24021
24402
|
// src/modules/lsp/client.ts
|
|
24022
24403
|
import { spawn as spawn8, execSync as execSync2 } from "child_process";
|
|
24023
24404
|
import { resolve as resolve19 } from "path";
|
|
24024
|
-
import { platform as
|
|
24405
|
+
import { platform as platform10 } from "os";
|
|
24025
24406
|
|
|
24026
24407
|
class FileOnlyLogger {
|
|
24027
24408
|
logger;
|
|
@@ -24141,7 +24522,7 @@ class LspClient {
|
|
|
24141
24522
|
if (config.command === "npx" && effectiveArgs.length > 0) {
|
|
24142
24523
|
const binaryName = this.extractBinaryFromNpxArgs(effectiveArgs);
|
|
24143
24524
|
if (binaryName) {
|
|
24144
|
-
const whichCmd =
|
|
24525
|
+
const whichCmd = platform10() === "win32" ? `where ${binaryName}` : `which ${binaryName}`;
|
|
24145
24526
|
try {
|
|
24146
24527
|
execSync2(whichCmd, { stdio: "pipe", timeout: 3000 });
|
|
24147
24528
|
effectiveCommand = binaryName;
|
|
@@ -24154,7 +24535,7 @@ class LspClient {
|
|
|
24154
24535
|
}
|
|
24155
24536
|
return new Promise((resolve20, reject) => {
|
|
24156
24537
|
const args = effectiveArgs;
|
|
24157
|
-
const isWin =
|
|
24538
|
+
const isWin = platform10() === "win32";
|
|
24158
24539
|
let spawnCommand = resolveSpawnCommand(effectiveCommand);
|
|
24159
24540
|
let spawnArgs = args;
|
|
24160
24541
|
const spawnOpts = {
|
|
@@ -24760,8 +25141,11 @@ async function runCheck(config, baseDir, deps) {
|
|
|
24760
25141
|
return { lines: lines.slice(0, STARTUP_CHECK_ERROR_CAP) };
|
|
24761
25142
|
}
|
|
24762
25143
|
async function runTscDefault(projectRoot, timeoutMs) {
|
|
25144
|
+
const tsc = resolveTscCommand(projectRoot);
|
|
25145
|
+
if (!tsc)
|
|
25146
|
+
return [];
|
|
24763
25147
|
return new Promise((resolve22) => {
|
|
24764
|
-
const child = spawn9(
|
|
25148
|
+
const child = spawn9(`${tsc} --noEmit --skipLibCheck`, {
|
|
24765
25149
|
cwd: projectRoot,
|
|
24766
25150
|
shell: true,
|
|
24767
25151
|
windowsHide: true,
|
|
@@ -25165,7 +25549,7 @@ class IndexCache {
|
|
|
25165
25549
|
}
|
|
25166
25550
|
}
|
|
25167
25551
|
}
|
|
25168
|
-
var
|
|
25552
|
+
var init_cache2 = () => {};
|
|
25169
25553
|
|
|
25170
25554
|
// src/modules/indexer/map-select.ts
|
|
25171
25555
|
function isNoiseFile(file) {
|
|
@@ -25637,7 +26021,7 @@ ${stackLine}` : summary;
|
|
|
25637
26021
|
var MAP_FILE_LIMIT = 80;
|
|
25638
26022
|
var init_module6 = __esm(() => {
|
|
25639
26023
|
init_walker();
|
|
25640
|
-
|
|
26024
|
+
init_cache2();
|
|
25641
26025
|
init_map_select();
|
|
25642
26026
|
init_project_profile();
|
|
25643
26027
|
init_i18n();
|
|
@@ -25648,7 +26032,7 @@ var init_module6 = __esm(() => {
|
|
|
25648
26032
|
// src/modules/indexer/index.ts
|
|
25649
26033
|
var init_indexer = __esm(() => {
|
|
25650
26034
|
init_walker();
|
|
25651
|
-
|
|
26035
|
+
init_cache2();
|
|
25652
26036
|
init_module6();
|
|
25653
26037
|
});
|
|
25654
26038
|
|
|
@@ -25993,7 +26377,7 @@ import { spawnSync as spawnSync3 } from "child_process";
|
|
|
25993
26377
|
import { createRequire as createRequire2 } from "module";
|
|
25994
26378
|
import { join as join43, dirname as dirname16 } from "path";
|
|
25995
26379
|
import { fileURLToPath as fileURLToPath3 } from "url";
|
|
25996
|
-
import { arch, homedir as homedir12, hostname as hostname2, platform as
|
|
26380
|
+
import { arch, homedir as homedir12, hostname as hostname2, platform as platform11, release } from "os";
|
|
25997
26381
|
import { env as env2 } from "process";
|
|
25998
26382
|
function readEngineRequirement() {
|
|
25999
26383
|
const here = dirname16(fileURLToPath3(import.meta.url));
|
|
@@ -26139,7 +26523,7 @@ function collectEnvironment(opts) {
|
|
|
26139
26523
|
mmaVersion: readMmaVersion(),
|
|
26140
26524
|
runtime,
|
|
26141
26525
|
os: {
|
|
26142
|
-
platform:
|
|
26526
|
+
platform: platform11(),
|
|
26143
26527
|
arch: arch(),
|
|
26144
26528
|
release: release(),
|
|
26145
26529
|
hostname: hostname2(),
|
|
@@ -26496,6 +26880,7 @@ var init_set_thinking = __esm(() => {
|
|
|
26496
26880
|
// src/core/bootstrap.ts
|
|
26497
26881
|
var exports_bootstrap = {};
|
|
26498
26882
|
__export(exports_bootstrap, {
|
|
26883
|
+
setOneShotMode: () => setOneShotMode,
|
|
26499
26884
|
buildSystemInfo: () => buildSystemInfo,
|
|
26500
26885
|
bootstrap: () => bootstrap
|
|
26501
26886
|
});
|
|
@@ -26611,6 +26996,9 @@ function buildSystemInfo(config, baseDir, profileCompressed) {
|
|
|
26611
26996
|
return lines.join(`
|
|
26612
26997
|
`);
|
|
26613
26998
|
}
|
|
26999
|
+
function setOneShotMode(value) {
|
|
27000
|
+
oneShotMode = value;
|
|
27001
|
+
}
|
|
26614
27002
|
async function bootstrap(configDir, projectDir, noAgentsMd, exitOnComplete, reasoningLevel) {
|
|
26615
27003
|
const dir = configDir || process.env.MMA_CONFIG_DIR || join46(homedir15(), ".mma");
|
|
26616
27004
|
const projectConfigPath = projectDir ? join46(projectDir, ".mmrc") : join46(process.cwd(), ".mmrc");
|
|
@@ -26846,7 +27234,7 @@ async function bootstrap(configDir, projectDir, noAgentsMd, exitOnComplete, reas
|
|
|
26846
27234
|
moduleRegistry.register(lspModule);
|
|
26847
27235
|
registerBuiltinPlugin(pluginManager, lspModule.getPlugin());
|
|
26848
27236
|
let startupCheckBlock = null;
|
|
26849
|
-
const startupCheckPromise = !exitOnComplete ? runStartupHealthCheck(config.lsp ?? DEFAULT_LSP_CONFIG, baseDir, { logger: lspLogger }) : Promise.resolve(null);
|
|
27237
|
+
const startupCheckPromise = !oneShotMode && !exitOnComplete ? runStartupHealthCheck(config.lsp ?? DEFAULT_LSP_CONFIG, baseDir, { logger: lspLogger }) : Promise.resolve(null);
|
|
26850
27238
|
const moduleTools = moduleRegistry.collectToolDefinitions();
|
|
26851
27239
|
for (const tool of moduleTools) {
|
|
26852
27240
|
toolRegistry.register(tool);
|
|
@@ -27001,6 +27389,7 @@ async function bootstrap(configDir, projectDir, noAgentsMd, exitOnComplete, reas
|
|
|
27001
27389
|
contextProbe: contextProbePromise
|
|
27002
27390
|
};
|
|
27003
27391
|
}
|
|
27392
|
+
var oneShotMode = false;
|
|
27004
27393
|
var init_bootstrap = __esm(() => {
|
|
27005
27394
|
init_config2();
|
|
27006
27395
|
init_app_logger();
|
|
@@ -27476,9 +27865,9 @@ class Spinner {
|
|
|
27476
27865
|
tick() {
|
|
27477
27866
|
if (!this.timer)
|
|
27478
27867
|
return;
|
|
27479
|
-
const
|
|
27868
|
+
const frame2 = FRAMES[this.frame % FRAMES.length];
|
|
27480
27869
|
this.frame++;
|
|
27481
|
-
this.stream.write("\r" + pc2.cyan(
|
|
27870
|
+
this.stream.write("\r" + pc2.cyan(frame2) + " " + this.message + "\x1B[K");
|
|
27482
27871
|
}
|
|
27483
27872
|
}
|
|
27484
27873
|
var FRAMES;
|
|
@@ -30074,9 +30463,9 @@ var require_stringifyNumber = __commonJS((exports) => {
|
|
|
30074
30463
|
function stringifyNumber({ format, minFractionDigits, tag, value }) {
|
|
30075
30464
|
if (typeof value === "bigint")
|
|
30076
30465
|
return String(value);
|
|
30077
|
-
const
|
|
30078
|
-
if (!isFinite(
|
|
30079
|
-
return isNaN(
|
|
30466
|
+
const num3 = typeof value === "number" ? value : Number(value);
|
|
30467
|
+
if (!isFinite(num3))
|
|
30468
|
+
return isNaN(num3) ? ".nan" : num3 < 0 ? "-.inf" : ".inf";
|
|
30080
30469
|
let n = Object.is(value, -0) ? "-0" : JSON.stringify(value);
|
|
30081
30470
|
if (!format && minFractionDigits && (!tag || tag === "tag:yaml.org,2002:float") && /^-?\d/.test(n) && !n.includes("e")) {
|
|
30082
30471
|
let i = n.indexOf(".");
|
|
@@ -30113,8 +30502,8 @@ var require_float = __commonJS((exports) => {
|
|
|
30113
30502
|
test: /^[-+]?(?:\.[0-9]+|[0-9]+(?:\.[0-9]*)?)[eE][-+]?[0-9]+$/,
|
|
30114
30503
|
resolve: (str) => parseFloat(str),
|
|
30115
30504
|
stringify(node) {
|
|
30116
|
-
const
|
|
30117
|
-
return isFinite(
|
|
30505
|
+
const num3 = Number(node.value);
|
|
30506
|
+
return isFinite(num3) ? num3.toExponential() : stringifyNumber.stringifyNumber(node);
|
|
30118
30507
|
}
|
|
30119
30508
|
};
|
|
30120
30509
|
var float = {
|
|
@@ -30518,8 +30907,8 @@ var require_float2 = __commonJS((exports) => {
|
|
|
30518
30907
|
test: /^[-+]?(?:[0-9][0-9_]*)?(?:\.[0-9_]*)?[eE][-+]?[0-9]+$/,
|
|
30519
30908
|
resolve: (str) => parseFloat(str.replace(/_/g, "")),
|
|
30520
30909
|
stringify(node) {
|
|
30521
|
-
const
|
|
30522
|
-
return isFinite(
|
|
30910
|
+
const num3 = Number(node.value);
|
|
30911
|
+
return isFinite(num3) ? num3.toExponential() : stringifyNumber.stringifyNumber(node);
|
|
30523
30912
|
}
|
|
30524
30913
|
};
|
|
30525
30914
|
var float = {
|
|
@@ -30709,23 +31098,23 @@ var require_timestamp = __commonJS((exports) => {
|
|
|
30709
31098
|
function parseSexagesimal(str, asBigInt) {
|
|
30710
31099
|
const sign = str[0];
|
|
30711
31100
|
const parts = sign === "-" || sign === "+" ? str.substring(1) : str;
|
|
30712
|
-
const
|
|
30713
|
-
const res = parts.replace(/_/g, "").split(":").reduce((res2, p) => res2 *
|
|
30714
|
-
return sign === "-" ?
|
|
31101
|
+
const num3 = (n) => asBigInt ? BigInt(n) : Number(n);
|
|
31102
|
+
const res = parts.replace(/_/g, "").split(":").reduce((res2, p) => res2 * num3(60) + num3(p), num3(0));
|
|
31103
|
+
return sign === "-" ? num3(-1) * res : res;
|
|
30715
31104
|
}
|
|
30716
31105
|
function stringifySexagesimal(node) {
|
|
30717
31106
|
let { value } = node;
|
|
30718
|
-
let
|
|
31107
|
+
let num3 = (n) => n;
|
|
30719
31108
|
if (typeof value === "bigint")
|
|
30720
|
-
|
|
31109
|
+
num3 = (n) => BigInt(n);
|
|
30721
31110
|
else if (isNaN(value) || !isFinite(value))
|
|
30722
31111
|
return stringifyNumber.stringifyNumber(node);
|
|
30723
31112
|
let sign = "";
|
|
30724
31113
|
if (value < 0) {
|
|
30725
31114
|
sign = "-";
|
|
30726
|
-
value *=
|
|
31115
|
+
value *= num3(-1);
|
|
30727
31116
|
}
|
|
30728
|
-
const _60 =
|
|
31117
|
+
const _60 = num3(60);
|
|
30729
31118
|
const parts = [value % _60];
|
|
30730
31119
|
if (value < 60) {
|
|
30731
31120
|
parts.unshift(0);
|
|
@@ -37566,6 +37955,63 @@ init_version();
|
|
|
37566
37955
|
init_map_command();
|
|
37567
37956
|
init_budget();
|
|
37568
37957
|
|
|
37958
|
+
// src/llm/provider-budget.ts
|
|
37959
|
+
var DEFAULT_TIMEOUT_MS = 5000;
|
|
37960
|
+
function num2(value) {
|
|
37961
|
+
return typeof value === "number" && Number.isFinite(value) ? value : undefined;
|
|
37962
|
+
}
|
|
37963
|
+
async function getJson(url, apiKey, timeoutMs) {
|
|
37964
|
+
const response = await fetch(url, {
|
|
37965
|
+
headers: { Authorization: `Bearer ${apiKey}` },
|
|
37966
|
+
signal: AbortSignal.timeout(timeoutMs)
|
|
37967
|
+
});
|
|
37968
|
+
if (!response.ok) {
|
|
37969
|
+
throw new Error(`HTTP ${response.status}`);
|
|
37970
|
+
}
|
|
37971
|
+
return response.json();
|
|
37972
|
+
}
|
|
37973
|
+
async function fetchProviderBudget(provider, baseUrl, apiKey, options) {
|
|
37974
|
+
if (provider !== "openrouter") {
|
|
37975
|
+
options.log("debug", `budget: provider "${provider}" does not expose an API balance`);
|
|
37976
|
+
return { budget: null, reason: "unsupported" };
|
|
37977
|
+
}
|
|
37978
|
+
if (!apiKey) {
|
|
37979
|
+
options.log("debug", "budget: no api key configured");
|
|
37980
|
+
return { budget: null, reason: "no-key" };
|
|
37981
|
+
}
|
|
37982
|
+
const base = baseUrl.replace(/\/$/, "");
|
|
37983
|
+
const timeoutMs = options.timeoutMs ?? DEFAULT_TIMEOUT_MS;
|
|
37984
|
+
try {
|
|
37985
|
+
const keyBody = await getJson(`${base}/key`, apiKey, timeoutMs);
|
|
37986
|
+
const data = keyBody?.data ?? {};
|
|
37987
|
+
const budget = { provider, source: "openrouter" };
|
|
37988
|
+
budget.keyLabel = typeof data.label === "string" ? data.label : undefined;
|
|
37989
|
+
budget.keyUsageUsd = num2(data.usage);
|
|
37990
|
+
budget.keyLimitUsd = num2(data.limit);
|
|
37991
|
+
budget.keyRemainingUsd = num2(data.limit_remaining);
|
|
37992
|
+
budget.isFreeTier = typeof data.is_free_tier === "boolean" ? data.is_free_tier : undefined;
|
|
37993
|
+
try {
|
|
37994
|
+
const creditsBody = await getJson(`${base}/credits`, apiKey, timeoutMs);
|
|
37995
|
+
const c = creditsBody?.data ?? {};
|
|
37996
|
+
budget.totalCreditsUsd = num2(c.total_credits);
|
|
37997
|
+
budget.totalUsageUsd = num2(c.total_usage);
|
|
37998
|
+
if (budget.totalCreditsUsd !== undefined && budget.totalUsageUsd !== undefined) {
|
|
37999
|
+
budget.balanceUsd = budget.totalCreditsUsd - budget.totalUsageUsd;
|
|
38000
|
+
}
|
|
38001
|
+
} catch (creditsErr) {
|
|
38002
|
+
options.log("debug", `budget: /credits unavailable (${creditsErr instanceof Error ? creditsErr.message : String(creditsErr)})`);
|
|
38003
|
+
}
|
|
38004
|
+
return { budget, reason: "ok" };
|
|
38005
|
+
} catch (err) {
|
|
38006
|
+
const message = err instanceof Error ? err.message : String(err);
|
|
38007
|
+
options.log("warn", `budget: request failed (${message})`);
|
|
38008
|
+
return { budget: null, reason: "error", error: message };
|
|
38009
|
+
}
|
|
38010
|
+
}
|
|
38011
|
+
|
|
38012
|
+
// src/cli/commands.ts
|
|
38013
|
+
init_prices();
|
|
38014
|
+
|
|
37569
38015
|
// src/modules/updater/changelog-reader.ts
|
|
37570
38016
|
import { readFileSync as readFileSync35, existsSync as existsSync53 } from "fs";
|
|
37571
38017
|
import { dirname as dirname20, join as join48 } from "path";
|
|
@@ -37854,6 +38300,53 @@ function buildContextCommand(program2) {
|
|
|
37854
38300
|
console.log(t("cli.context_set", { size: contextWindow }));
|
|
37855
38301
|
});
|
|
37856
38302
|
}
|
|
38303
|
+
function buildUsageCommand(program2) {
|
|
38304
|
+
program2.command("usage").description(t("cli.usage")).action(async () => {
|
|
38305
|
+
const { config, logger: logger4 } = await bootstrap();
|
|
38306
|
+
const { type: provider, baseUrl, apiKey } = config.provider;
|
|
38307
|
+
const result = await fetchProviderBudget(provider, baseUrl, apiKey, {
|
|
38308
|
+
log: (level, message) => level === "warn" ? logger4.warn(message) : logger4.debug(message)
|
|
38309
|
+
});
|
|
38310
|
+
if (result.reason === "unsupported") {
|
|
38311
|
+
console.log(t("cli.usage_unsupported", { provider }));
|
|
38312
|
+
return;
|
|
38313
|
+
}
|
|
38314
|
+
if (result.reason === "no-key") {
|
|
38315
|
+
console.log(t("cli.usage_no_key"));
|
|
38316
|
+
return;
|
|
38317
|
+
}
|
|
38318
|
+
if (result.reason === "error" || !result.budget) {
|
|
38319
|
+
console.log(t("cli.usage_error", { error: result.error ?? "" }));
|
|
38320
|
+
return;
|
|
38321
|
+
}
|
|
38322
|
+
const b = result.budget;
|
|
38323
|
+
let printed = false;
|
|
38324
|
+
if (b.keyUsageUsd !== undefined) {
|
|
38325
|
+
console.log(t("cli.usage_key_usage", { usage: formatCost(b.keyUsageUsd) }));
|
|
38326
|
+
printed = true;
|
|
38327
|
+
}
|
|
38328
|
+
if (b.keyLimitUsd !== undefined && b.keyRemainingUsd !== undefined) {
|
|
38329
|
+
console.log(t("cli.usage_key_limit", {
|
|
38330
|
+
limit: formatCost(b.keyLimitUsd),
|
|
38331
|
+
remaining: formatCost(b.keyRemainingUsd)
|
|
38332
|
+
}));
|
|
38333
|
+
printed = true;
|
|
38334
|
+
}
|
|
38335
|
+
if (b.balanceUsd !== undefined) {
|
|
38336
|
+
console.log(t("cli.usage_balance", { balance: formatCost(b.balanceUsd) }));
|
|
38337
|
+
printed = true;
|
|
38338
|
+
}
|
|
38339
|
+
if (b.totalCreditsUsd !== undefined && b.totalUsageUsd !== undefined) {
|
|
38340
|
+
console.log(t("cli.usage_account", {
|
|
38341
|
+
credits: formatCost(b.totalCreditsUsd),
|
|
38342
|
+
used: formatCost(b.totalUsageUsd)
|
|
38343
|
+
}));
|
|
38344
|
+
printed = true;
|
|
38345
|
+
}
|
|
38346
|
+
if (!printed)
|
|
38347
|
+
console.log(t("cli.usage_empty"));
|
|
38348
|
+
});
|
|
38349
|
+
}
|
|
37857
38350
|
function buildMapCommand(program2) {
|
|
37858
38351
|
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
38352
|
const { agent } = await bootstrap();
|
|
@@ -38010,6 +38503,31 @@ function buildSessionCommands(program2) {
|
|
|
38010
38503
|
}
|
|
38011
38504
|
}
|
|
38012
38505
|
}
|
|
38506
|
+
const usageEvents = sessionManager.loadSessionLog(id).filter((e) => e.type === "llm_usage");
|
|
38507
|
+
if (usageEvents.length > 0) {
|
|
38508
|
+
let prompt = 0;
|
|
38509
|
+
let completion = 0;
|
|
38510
|
+
let cached = 0;
|
|
38511
|
+
for (const e of usageEvents) {
|
|
38512
|
+
prompt += e.promptTokens ?? 0;
|
|
38513
|
+
completion += e.completionTokens ?? 0;
|
|
38514
|
+
cached += e.cachedTokens ?? 0;
|
|
38515
|
+
}
|
|
38516
|
+
console.log("");
|
|
38517
|
+
console.log(pc2.cyan(t("cli.session_usage", {
|
|
38518
|
+
prompt,
|
|
38519
|
+
completion,
|
|
38520
|
+
total: prompt + completion
|
|
38521
|
+
})));
|
|
38522
|
+
if (cached > 0 && prompt > 0) {
|
|
38523
|
+
const hit = Math.round(cached / prompt * 100);
|
|
38524
|
+
console.log(pc2.dim(t("cli.session_cache", {
|
|
38525
|
+
hit,
|
|
38526
|
+
cached,
|
|
38527
|
+
uncached: Math.max(0, prompt - cached)
|
|
38528
|
+
})));
|
|
38529
|
+
}
|
|
38530
|
+
}
|
|
38013
38531
|
});
|
|
38014
38532
|
session2.command("delete").argument("<id>", "Session id").description(t("cli.delete_session")).action(async (id) => {
|
|
38015
38533
|
const { sessionManager } = await bootstrap();
|
|
@@ -38049,6 +38567,7 @@ function createProgram() {
|
|
|
38049
38567
|
buildConfigCommands(program2);
|
|
38050
38568
|
buildModelCommands(program2);
|
|
38051
38569
|
buildContextCommand(program2);
|
|
38570
|
+
buildUsageCommand(program2);
|
|
38052
38571
|
buildMapCommand(program2);
|
|
38053
38572
|
buildProviderCommands(program2);
|
|
38054
38573
|
buildSessionCommands(program2);
|
|
@@ -38056,11 +38575,15 @@ function createProgram() {
|
|
|
38056
38575
|
createPluginCommand(program2);
|
|
38057
38576
|
buildChangelogCommand(program2);
|
|
38058
38577
|
program2.argument("[prompt...]", "Prompt to execute").description("Run a single prompt").action((prompt) => {});
|
|
38059
|
-
|
|
38578
|
+
const attachOneShotExit = (cmd) => {
|
|
38060
38579
|
cmd.hook("postAction", () => {
|
|
38061
38580
|
process.exit(0);
|
|
38062
38581
|
});
|
|
38063
|
-
|
|
38582
|
+
for (const sub of cmd.commands)
|
|
38583
|
+
attachOneShotExit(sub);
|
|
38584
|
+
};
|
|
38585
|
+
for (const cmd of program2.commands)
|
|
38586
|
+
attachOneShotExit(cmd);
|
|
38064
38587
|
return program2;
|
|
38065
38588
|
}
|
|
38066
38589
|
|
|
@@ -39693,6 +40216,28 @@ function stepContextForTool(plan, tool, args) {
|
|
|
39693
40216
|
// src/cli/repl.ts
|
|
39694
40217
|
init_prices();
|
|
39695
40218
|
|
|
40219
|
+
// src/cli/cache-line.ts
|
|
40220
|
+
init_i18n();
|
|
40221
|
+
init_prices();
|
|
40222
|
+
function formatCacheLine(cache) {
|
|
40223
|
+
if (!cache)
|
|
40224
|
+
return;
|
|
40225
|
+
const total = cache.cachedTokens + cache.uncachedTokens;
|
|
40226
|
+
const hit = Math.round(cache.hitRate * 100);
|
|
40227
|
+
if (total > 0) {
|
|
40228
|
+
if (cache.saved !== undefined && cache.saved > 0) {
|
|
40229
|
+
return t("repl.cache", { hit, saved: formatCost(cache.saved) });
|
|
40230
|
+
}
|
|
40231
|
+
return t("repl.cache_nosave", { hit });
|
|
40232
|
+
}
|
|
40233
|
+
const broken = cache.prefixCause !== undefined && cache.prefixCause !== "none" && cache.prefixCause !== "unknown";
|
|
40234
|
+
if (broken && cache.prefixStable !== undefined && cache.prefixStable < 0.98) {
|
|
40235
|
+
const stable = Math.round(cache.prefixStable * 100);
|
|
40236
|
+
return t("repl.prefix", { stable, cause: t(`cache.cause.${cache.prefixCause}`) });
|
|
40237
|
+
}
|
|
40238
|
+
return;
|
|
40239
|
+
}
|
|
40240
|
+
|
|
39696
40241
|
// src/ui/output.ts
|
|
39697
40242
|
function writeWarning(text) {
|
|
39698
40243
|
process.stdout.write(formatWarning(text) + `
|
|
@@ -40199,6 +40744,10 @@ ${t("image.clipboard_empty")}`));
|
|
|
40199
40744
|
if (result.totalCost !== undefined && result.totalCost > 0) {
|
|
40200
40745
|
console.log(pc2.yellow(` ${t("repl.cost", { cost: formatCost(result.totalCost) })}`));
|
|
40201
40746
|
}
|
|
40747
|
+
const cacheLine = formatCacheLine(result.cache);
|
|
40748
|
+
if (cacheLine) {
|
|
40749
|
+
console.log(pc2.dim(` ${cacheLine}`));
|
|
40750
|
+
}
|
|
40202
40751
|
} else if (ui?.showCompaction && result.compactionCount !== undefined) {
|
|
40203
40752
|
if (result.compactionCount > this.lastCompactionShown) {
|
|
40204
40753
|
this.lastCompactionShown = result.compactionCount;
|
|
@@ -40383,6 +40932,10 @@ function printRunResult(result, flush) {
|
|
|
40383
40932
|
} else if (result.totalTokens !== undefined && result.totalTokens > 0) {
|
|
40384
40933
|
console.log(pc2.dim(`${t("repl.tokens", { tokens: result.totalTokens })}`));
|
|
40385
40934
|
}
|
|
40935
|
+
const cacheLine = formatCacheLine(result.cache);
|
|
40936
|
+
if (cacheLine) {
|
|
40937
|
+
console.log(pc2.dim(` ${cacheLine}`));
|
|
40938
|
+
}
|
|
40386
40939
|
if (!result.text) {
|
|
40387
40940
|
console.log(pc2.yellow(t("cli.no_output")));
|
|
40388
40941
|
}
|
|
@@ -40621,6 +41174,22 @@ function startAutoUpdate(config) {
|
|
|
40621
41174
|
async function main() {
|
|
40622
41175
|
installCrashHandlers();
|
|
40623
41176
|
const program2 = createProgram();
|
|
41177
|
+
const valueOpts = new Set(["-d", "--dir", "--reasoning"]);
|
|
41178
|
+
const argv = process.argv.slice(2);
|
|
41179
|
+
let firstPositional;
|
|
41180
|
+
for (let i = 0;i < argv.length; i++) {
|
|
41181
|
+
const a = argv[i];
|
|
41182
|
+
if (a.startsWith("-")) {
|
|
41183
|
+
if (valueOpts.has(a))
|
|
41184
|
+
i++;
|
|
41185
|
+
continue;
|
|
41186
|
+
}
|
|
41187
|
+
firstPositional = a;
|
|
41188
|
+
break;
|
|
41189
|
+
}
|
|
41190
|
+
if (firstPositional && program2.commands.some((c) => c.name() === firstPositional)) {
|
|
41191
|
+
setOneShotMode(true);
|
|
41192
|
+
}
|
|
40624
41193
|
program2.parse(process.argv);
|
|
40625
41194
|
const cmdNames = new Set(program2.commands.map((c) => c.name()));
|
|
40626
41195
|
const opts = program2.opts();
|
|
@@ -40672,7 +41241,8 @@ async function main() {
|
|
|
40672
41241
|
completionTokens: result2.completionTokens ?? null,
|
|
40673
41242
|
totalTokens: result2.totalTokens ?? null,
|
|
40674
41243
|
totalCost: result2.totalCost ?? null,
|
|
40675
|
-
costBreakdown: result2.costBreakdown ?? []
|
|
41244
|
+
costBreakdown: result2.costBreakdown ?? [],
|
|
41245
|
+
cache: result2.cache ?? null
|
|
40676
41246
|
}, null, 2));
|
|
40677
41247
|
process.stdout.write(`
|
|
40678
41248
|
`);
|