teapot-coding-agent 0.19.5 → 0.19.6
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/agent/agent.js +59 -3
- package/dist/master.js +11 -0
- package/dist/model-meta.js +8 -0
- package/package.json +1 -1
- package/public/assets/{index-CjCG5i5v.js → index-Ck2SeYdT.js} +9 -9
- package/public/assets/index-Ck2SeYdT.js.map +1 -0
- package/public/assets/{shiki-DM6ItGHw.js → shiki-DbdbHcOD.js} +2 -2
- package/public/assets/{shiki-DM6ItGHw.js.map → shiki-DbdbHcOD.js.map} +1 -1
- package/public/index.html +1 -1
- package/public/assets/index-CjCG5i5v.js.map +0 -1
package/dist/agent/agent.js
CHANGED
|
@@ -78,6 +78,8 @@ export class Agent {
|
|
|
78
78
|
outputTokens: 0,
|
|
79
79
|
compactions: 0,
|
|
80
80
|
startedAt: null,
|
|
81
|
+
/** running cost estimate in USD (pricing known only) */
|
|
82
|
+
costUsd: 0,
|
|
81
83
|
};
|
|
82
84
|
opts;
|
|
83
85
|
messages = [];
|
|
@@ -105,6 +107,9 @@ export class Agent {
|
|
|
105
107
|
lastProgressAt = Date.now();
|
|
106
108
|
/** the provider's own prompt_tokens from the last completed turn */
|
|
107
109
|
lastUsage;
|
|
110
|
+
/** USD per token for the CURRENT model (from provider /models metadata);
|
|
111
|
+
undefined = pricing unknown → cost estimate stays 0 and hidden */
|
|
112
|
+
modelPricing;
|
|
108
113
|
/** messages.length right after the last successful compaction */
|
|
109
114
|
compactedAtLen = 0;
|
|
110
115
|
/** live compaction phase for UI progress ("summarizing"/"harvesting") */
|
|
@@ -194,6 +199,35 @@ export class Agent {
|
|
|
194
199
|
this.messages = msgs;
|
|
195
200
|
this.compactedAtLen = 0;
|
|
196
201
|
}
|
|
202
|
+
/**
|
|
203
|
+
* Attach USD-per-token pricing for the CURRENT model (provider /models
|
|
204
|
+
* metadata). Late resolution is normal: the metadata lookup races boot.
|
|
205
|
+
* Recomputes the session cost from the log so a restart with pricing now
|
|
206
|
+
* known still shows the full number instead of starting from zero.
|
|
207
|
+
*/
|
|
208
|
+
async setModelPricing(p) {
|
|
209
|
+
const wasUndefined = !this.modelPricing;
|
|
210
|
+
this.modelPricing = p;
|
|
211
|
+
if (!p || !wasUndefined)
|
|
212
|
+
return; // already priced, or nothing to price
|
|
213
|
+
// recompute from the usage events (cheap: file is mtime-cached)
|
|
214
|
+
try {
|
|
215
|
+
const events = await readEvents(this.log.filePath);
|
|
216
|
+
let cost = 0;
|
|
217
|
+
for (const e of events) {
|
|
218
|
+
if (e.type !== "usage")
|
|
219
|
+
continue;
|
|
220
|
+
const u = e.data;
|
|
221
|
+
const inTok = u.inputTokens ?? 0;
|
|
222
|
+
const cached = Math.min(u.cachedInputTokens ?? 0, inTok);
|
|
223
|
+
cost += (inTok - cached) * p.prompt + (u.outputTokens ?? 0) * p.completion + cached * p.prompt * 0.1;
|
|
224
|
+
}
|
|
225
|
+
this.stats.costUsd = cost;
|
|
226
|
+
}
|
|
227
|
+
catch {
|
|
228
|
+
/* no log yet — live accumulation takes over */
|
|
229
|
+
}
|
|
230
|
+
}
|
|
197
231
|
get workspace() {
|
|
198
232
|
return this.opts.workspace;
|
|
199
233
|
}
|
|
@@ -420,6 +454,15 @@ export class Agent {
|
|
|
420
454
|
this.stats.inputTokens += u.inputTokens ?? 0;
|
|
421
455
|
this.stats.outputTokens += u.outputTokens ?? 0;
|
|
422
456
|
this.stats.cachedInputTokens += u.cachedInputTokens ?? 0;
|
|
457
|
+
if (this.modelPricing) {
|
|
458
|
+
const p = this.modelPricing;
|
|
459
|
+
const inTok = u.inputTokens ?? 0;
|
|
460
|
+
const cached = Math.min(u.cachedInputTokens ?? 0, inTok);
|
|
461
|
+
// same blended-cache model as the live path (cached ≈ 10% of prompt)
|
|
462
|
+
this.stats.costUsd =
|
|
463
|
+
(this.stats.costUsd ?? 0) +
|
|
464
|
+
((inTok - cached) * p.prompt + (u.outputTokens ?? 0) * p.completion + cached * p.prompt * 0.1);
|
|
465
|
+
}
|
|
423
466
|
}
|
|
424
467
|
else if (e.type === "system_note") {
|
|
425
468
|
const d = e.data;
|
|
@@ -666,7 +709,7 @@ export class Agent {
|
|
|
666
709
|
...(this.goal.audit ? { audit: this.goal.audit } : {}),
|
|
667
710
|
},
|
|
668
711
|
latestProgress: this.latestProgress,
|
|
669
|
-
stats: { ...this.stats },
|
|
712
|
+
stats: { ...this.stats, costUsd: this.modelPricing ? this.stats.costUsd : undefined },
|
|
670
713
|
model: this.opts.llm.model,
|
|
671
714
|
provider: this.opts.provider,
|
|
672
715
|
sessionDir: this.opts.sessionDir,
|
|
@@ -1029,9 +1072,22 @@ export class Agent {
|
|
|
1029
1072
|
throw err;
|
|
1030
1073
|
}
|
|
1031
1074
|
if (res.usage) {
|
|
1032
|
-
|
|
1033
|
-
|
|
1075
|
+
const inTok = res.usage.inputTokens ?? 0;
|
|
1076
|
+
const cached = res.usage.cachedInputTokens ?? 0;
|
|
1077
|
+
this.stats.inputTokens += inTok;
|
|
1078
|
+
this.stats.cachedInputTokens += cached;
|
|
1034
1079
|
this.stats.outputTokens += res.usage.outputTokens ?? 0;
|
|
1080
|
+
// cost estimate: uncached input at prompt rate, cache hits usually
|
|
1081
|
+
// bill at a fraction (OpenRouter reports the blended prompt price, so
|
|
1082
|
+
// cached tokens are charged separately at ~10% — a common provider
|
|
1083
|
+
// convention; without per-provider detail this is the honest guess)
|
|
1084
|
+
if (this.modelPricing) {
|
|
1085
|
+
const p = this.modelPricing;
|
|
1086
|
+
const uncached = Math.max(0, inTok - cached);
|
|
1087
|
+
this.stats.costUsd =
|
|
1088
|
+
(this.stats.costUsd ?? 0) +
|
|
1089
|
+
(uncached * p.prompt + (res.usage.outputTokens ?? 0) * p.completion + cached * p.prompt * 0.1);
|
|
1090
|
+
}
|
|
1035
1091
|
this.lastUsage = {
|
|
1036
1092
|
input: res.usage.inputTokens ?? 0,
|
|
1037
1093
|
output: res.usage.outputTokens ?? 0,
|
package/dist/master.js
CHANGED
|
@@ -397,6 +397,11 @@ export class Master {
|
|
|
397
397
|
...(ac.parent ? { parent: ac.parent } : {}),
|
|
398
398
|
...(ac.chatFn ? { chatFn: ac.chatFn } : {}),
|
|
399
399
|
});
|
|
400
|
+
// pricing metadata (USD/token) for the runtime cost estimate — best
|
|
401
|
+
// effort: providers without pricing in /models simply show no cost
|
|
402
|
+
void fetchModelList(llm.baseUrl, llm.apiKey)
|
|
403
|
+
.then((list) => agent.setModelPricing(list.find((m) => m.id === llm.model)?.pricing))
|
|
404
|
+
.catch(() => { });
|
|
400
405
|
// console line + broadcast: the web UI only refreshes on bus traffic, so
|
|
401
406
|
// every appended event must reach it (otherwise messages sit invisible
|
|
402
407
|
// until an unrelated status change happens to fire)
|
|
@@ -812,6 +817,12 @@ When this task is done (or truly blocked), call finish() with a summary for @${p
|
|
|
812
817
|
if (!agent.compactBudgetIsManual)
|
|
813
818
|
opts.opts.contextTokenBudget = Math.round(win * 0.75);
|
|
814
819
|
}
|
|
820
|
+
// re-price for the NEW model (cost estimate follows the model switch)
|
|
821
|
+
try {
|
|
822
|
+
const list = await fetchModelList(llm.baseUrl, llm.apiKey);
|
|
823
|
+
await agent.setModelPricing(list.find((m) => m.id === llm.model)?.pricing);
|
|
824
|
+
}
|
|
825
|
+
catch { /* pricing stays stale — cosmetic only */ }
|
|
815
826
|
this.saveConfig();
|
|
816
827
|
void agent.log.append("system_note", agent.currentSession, agent.currentBranch, {
|
|
817
828
|
event: "model-changed",
|
package/dist/model-meta.js
CHANGED
|
@@ -30,6 +30,14 @@ export async function fetchModelList(baseUrl, apiKey) {
|
|
|
30
30
|
.map((m) => ({
|
|
31
31
|
id: typeof m.id === "string" ? m.id : "",
|
|
32
32
|
contextLength: typeof m.context_length === "number" ? m.context_length : undefined,
|
|
33
|
+
// OpenRouter-style USD per token (e.g. "0.000003") — powers the
|
|
34
|
+
// runtime cost estimate. Providers without pricing stay undefined.
|
|
35
|
+
pricing: m.pricing && (m.pricing.prompt !== undefined || m.pricing.completion !== undefined)
|
|
36
|
+
? {
|
|
37
|
+
prompt: Number(m.pricing.prompt ?? 0),
|
|
38
|
+
completion: Number(m.pricing.completion ?? 0),
|
|
39
|
+
}
|
|
40
|
+
: undefined,
|
|
33
41
|
}))
|
|
34
42
|
.filter((m) => m.id);
|
|
35
43
|
cache.set(root, { at: Date.now(), list });
|