codeep 3.4.0 → 3.5.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/dist/acp/commands.d.ts +15 -0
- package/dist/acp/commands.js +39 -5
- package/dist/acp/server.d.ts +13 -0
- package/dist/acp/server.js +283 -27
- package/dist/acp/serverHandlers.js +10 -10
- package/dist/acp/session.d.ts +13 -2
- package/dist/acp/transport.d.ts +6 -0
- package/dist/acp/transport.js +98 -3
- package/dist/api/index.js +6 -3
- package/dist/config/index.js +12 -4
- package/dist/config/providers.d.ts +48 -4
- package/dist/config/providers.js +325 -88
- package/dist/renderer/agentExecution.js +116 -69
- package/dist/renderer/commands.js +36 -11
- package/dist/renderer/main.d.ts +24 -0
- package/dist/renderer/main.js +57 -2
- package/dist/utils/agent.d.ts +33 -2
- package/dist/utils/agent.js +86 -8
- package/dist/utils/agentChat.js +22 -10
- package/dist/utils/checkpoints.js +3 -0
- package/dist/utils/codeReview.js +28 -23
- package/dist/utils/git.d.ts +262 -4
- package/dist/utils/git.js +1928 -61
- package/dist/utils/gitHookInstaller.d.ts +32 -1
- package/dist/utils/gitHookInstaller.js +76 -8
- package/dist/utils/headlessReview.js +26 -5
- package/dist/utils/personalities.js +8 -2
- package/dist/utils/shell.d.ts +108 -0
- package/dist/utils/shell.js +364 -5
- package/dist/utils/taskPlanner.js +12 -4
- package/dist/utils/telegramApproval.d.ts +10 -2
- package/dist/utils/telegramApproval.js +22 -4
- package/dist/utils/tokenTracker.d.ts +13 -5
- package/dist/utils/tokenTracker.js +163 -34
- package/dist/utils/toolExecution.d.ts +41 -0
- package/dist/utils/toolExecution.js +357 -1
- package/dist/version.d.ts +1 -1
- package/dist/version.js +1 -1
- package/package.json +1 -1
|
@@ -11,10 +11,15 @@ const MODEL_CONTEXT_WINDOWS = {
|
|
|
11
11
|
// Z.AI / ZhipuAI
|
|
12
12
|
'glm-5.3': 1_000_000,
|
|
13
13
|
'glm-5.3-flash': 1_000_000,
|
|
14
|
+
'glm-5.3-flashx': 1_000_000,
|
|
14
15
|
'glm-5.2': 1_000_000,
|
|
15
16
|
'glm-5.1': 200_000,
|
|
16
17
|
'glm-5-turbo': 202_752,
|
|
17
|
-
// OpenAI
|
|
18
|
+
// OpenAI — every 5.6 and GPT-6 page gives a 1,050,000 window with a
|
|
19
|
+
// "Maximum input tokens: 922,000"; this sizes the context meter only, and
|
|
20
|
+
// compaction is character-based, so the window figure is what belongs here.
|
|
21
|
+
'gpt-6-sol': 1_050_000,
|
|
22
|
+
'gpt-6-luna': 1_050_000,
|
|
18
23
|
'gpt-6-astra': 1_050_000,
|
|
19
24
|
'gpt-5.6-sol': 1_050_000,
|
|
20
25
|
'gpt-5.6-terra': 1_050_000,
|
|
@@ -25,6 +30,7 @@ const MODEL_CONTEXT_WINDOWS = {
|
|
|
25
30
|
// Anthropic
|
|
26
31
|
'claude-fable-5-1': 1_000_000,
|
|
27
32
|
'claude-fable-5': 1_000_000,
|
|
33
|
+
'claude-opus-5-5': 1_000_000,
|
|
28
34
|
'claude-opus-5': 1_000_000,
|
|
29
35
|
'claude-sonnet-4-6': 1_000_000,
|
|
30
36
|
'claude-sonnet-5': 1_000_000,
|
|
@@ -40,7 +46,7 @@ const MODEL_CONTEXT_WINDOWS = {
|
|
|
40
46
|
'gemini-3.6-flash': 1_048_576,
|
|
41
47
|
'gemini-3.5-flash': 1_048_576,
|
|
42
48
|
'gemini-3.5-flash-lite': 1_048_576,
|
|
43
|
-
'gemini-3-flash-preview':
|
|
49
|
+
'gemini-3-flash-preview': 1_048_576,
|
|
44
50
|
// MiniMax
|
|
45
51
|
'MiniMax-M3': 1_000_000,
|
|
46
52
|
// Kimi (Moonshot) — 1M on K3, 256K across K2.x
|
|
@@ -48,11 +54,17 @@ const MODEL_CONTEXT_WINDOWS = {
|
|
|
48
54
|
'kimi-k2.7-code': 262_144,
|
|
49
55
|
'kimi-k2.7-code-highspeed': 262_144,
|
|
50
56
|
'kimi-k2.6': 262_144,
|
|
51
|
-
|
|
57
|
+
// K2.8 Preview since 2026-09-11: 1,048,576 on every Kimi Code tier.
|
|
58
|
+
'kimi-for-coding': 1_048_576,
|
|
52
59
|
'kimi-for-coding-highspeed': 262_144,
|
|
53
|
-
|
|
60
|
+
// 1,048,576 on Pro/Allegretto and above, 262,144 on Plus/Moderato. Codeep
|
|
61
|
+
// cannot see the plan, so this carries the plan-independent window of the id;
|
|
62
|
+
// a Plus user past 256K gets Kimi's 401, which the ACP server now words as a
|
|
63
|
+
// plan limit rather than a missing key.
|
|
64
|
+
'k3': 1_048_576,
|
|
54
65
|
'k3-256k': 262_144,
|
|
55
66
|
// Grok (xAI)
|
|
67
|
+
'grok-4.7': 500_000,
|
|
56
68
|
'grok-4.6': 500_000,
|
|
57
69
|
'grok-4.5': 500_000,
|
|
58
70
|
'grok-build-0.1': 256_000,
|
|
@@ -63,11 +75,15 @@ const MODEL_CONTEXT_WINDOWS = {
|
|
|
63
75
|
'qwen3.8-max': 1_000_000,
|
|
64
76
|
'qwen3.8-flash': 1_000_000,
|
|
65
77
|
'qwen3.7-max': 1_000_000,
|
|
78
|
+
// Retired on the Token Plan (routed to qwen3.8-max); kept for old sessions.
|
|
66
79
|
'qwen3.8-max-preview': 1_000_000,
|
|
67
80
|
'qwen3.7-plus': 1_000_000,
|
|
68
81
|
'qwen3.6-plus': 1_000_000,
|
|
69
82
|
'qwen3.5-plus': 1_000_000,
|
|
70
83
|
'qwen3.6-flash': 1_000_000,
|
|
84
|
+
// ModelScope fallback default: 262,144 native, per its model card.
|
|
85
|
+
'Qwen/Qwen3.5-397B-A17B': 262_144,
|
|
86
|
+
// The previous ModelScope fallback, no longer served there.
|
|
71
87
|
'Qwen/Qwen3-Coder-480B-A35B-Instruct': 262_144,
|
|
72
88
|
};
|
|
73
89
|
const DEFAULT_CONTEXT_WINDOW = 128_000;
|
|
@@ -88,16 +104,27 @@ const MODEL_PRICING = {
|
|
|
88
104
|
// inferred from the match — the two being equal today is a coincidence of the
|
|
89
105
|
// price list, not a rule.
|
|
90
106
|
'glm-5.3': { inputPer1M: 1.40, outputPer1M: 4.40 },
|
|
91
|
-
// Flash lists at $0.15/$0.50 with a
|
|
92
|
-
//
|
|
93
|
-
//
|
|
107
|
+
// Flash lists at $0.15/$0.50. It launched with a promotion that the
|
|
108
|
+
// international page no longer shows; the list price is what belongs here
|
|
109
|
+
// either way, since a promotional rate understates every session the day it
|
|
110
|
+
// ends.
|
|
94
111
|
'glm-5.3-flash': { inputPer1M: 0.15, outputPer1M: 0.50 },
|
|
112
|
+
'glm-5.3-flashx': { inputPer1M: 0.37, outputPer1M: 1.25 },
|
|
95
113
|
'glm-5.2': { inputPer1M: 1.40, outputPer1M: 4.40 },
|
|
96
114
|
'glm-5.1': { inputPer1M: 1.40, outputPer1M: 4.40 },
|
|
115
|
+
// Turbo's last international list price (2026-07-31); it has since left that
|
|
116
|
+
// list. China still sells it at CNY 5/22 below 32K input, which this
|
|
117
|
+
// over-estimates.
|
|
97
118
|
'glm-5-turbo': { inputPer1M: 1.20, outputPer1M: 4.00 },
|
|
98
119
|
// OpenAI
|
|
99
|
-
//
|
|
100
|
-
//
|
|
120
|
+
// GPT-6 Sol and Luna, released 2026-09-22. Cached reads are 0.1x input and
|
|
121
|
+
// cache writes 1.25x — the defaults below — so no rate rows are needed.
|
|
122
|
+
// Above 272K input a request bills $4/$15 (Sol) or $0.20/$0.75 (Luna); like
|
|
123
|
+
// every row here, these hold the standard short-context tier.
|
|
124
|
+
'gpt-6-sol': { inputPer1M: 2.00, outputPer1M: 10.00 },
|
|
125
|
+
'gpt-6-luna': { inputPer1M: 0.10, outputPer1M: 0.50 },
|
|
126
|
+
// No longer offered on `openai` (no tool calls on Chat Completions); kept so
|
|
127
|
+
// restored sessions still price. 2.5x 5.6 Sol at its promotional rate.
|
|
101
128
|
'gpt-6-astra': { inputPer1M: 10.00, outputPer1M: 50.00 },
|
|
102
129
|
// Promotional rate "available at least through 2026-11-21" per OpenAI's
|
|
103
130
|
// pricing page. Carried because it is what users are billed now, and no end
|
|
@@ -112,6 +139,8 @@ const MODEL_PRICING = {
|
|
|
112
139
|
// Anthropic
|
|
113
140
|
'claude-fable-5-1': { inputPer1M: 10.00, outputPer1M: 50.00 },
|
|
114
141
|
'claude-fable-5': { inputPer1M: 10.00, outputPer1M: 50.00 },
|
|
142
|
+
// No long-context tier: 4.6+ models bill the full 1M at these rates.
|
|
143
|
+
'claude-opus-5-5': { inputPer1M: 4.00, outputPer1M: 20.00 },
|
|
115
144
|
'claude-opus-5': { inputPer1M: 5.00, outputPer1M: 25.00 },
|
|
116
145
|
'claude-sonnet-4-6': { inputPer1M: 3.00, outputPer1M: 15.00 },
|
|
117
146
|
'claude-sonnet-5': { inputPer1M: 2.00, outputPer1M: 10.00 },
|
|
@@ -134,8 +163,8 @@ const MODEL_PRICING = {
|
|
|
134
163
|
'deepseek-flash': { inputPer1M: 0.30, outputPer1M: 1.20 },
|
|
135
164
|
// Retired V4 Flash is served by V4.1 Flash and billed at its price.
|
|
136
165
|
'deepseek-v4-flash': { inputPer1M: 0.30, outputPer1M: 1.20 },
|
|
137
|
-
// Pro's own peak rate
|
|
138
|
-
//
|
|
166
|
+
// Pro's own peak rate. DeepSeek cancelled its routing to Flash, so this is a
|
|
167
|
+
// live, separately billed model again (off-peak halves it).
|
|
139
168
|
'deepseek-v4-pro': { inputPer1M: 1.32, outputPer1M: 3.96 },
|
|
140
169
|
// Google
|
|
141
170
|
// Gemini 3.6/3.7/3.8 Flash carry PROMOTIONAL rates that run through 2026-12-31
|
|
@@ -155,22 +184,26 @@ const MODEL_PRICING = {
|
|
|
155
184
|
// 0.60/2.40. The old 0.60/2.40 row was the long-context tier and doubled the
|
|
156
185
|
// estimate for virtually every real request.
|
|
157
186
|
'MiniMax-M3': { inputPer1M: 0.30, outputPer1M: 1.20 },
|
|
158
|
-
// Kimi (Moonshot) — pay-per-use cache-miss rates
|
|
159
|
-
// subscription alias
|
|
187
|
+
// Kimi (Moonshot) — pay-per-use cache-miss rates. `kimi-for-coding` is the
|
|
188
|
+
// subscription alias: flat-fee, so this figure is never shown as a cost. It
|
|
189
|
+
// is now K2.8 Preview, which has no pay-per-use price at all; the row keeps
|
|
190
|
+
// the K2.7 Code rate it was given so old exports read the same.
|
|
160
191
|
'kimi-k3': { inputPer1M: 3.00, outputPer1M: 15.00 },
|
|
161
192
|
'kimi-k2.7-code': { inputPer1M: 0.95, outputPer1M: 4.00 },
|
|
162
193
|
// Highspeed is the same model served faster, at exactly double the rate
|
|
163
|
-
// across every token category (platform.kimi.ai/docs/pricing/chat
|
|
194
|
+
// across every token category (platform.kimi.ai/docs/pricing/chat).
|
|
164
195
|
'kimi-k2.7-code-highspeed': { inputPer1M: 1.90, outputPer1M: 8.00 },
|
|
165
|
-
// Kimi doesn't publish a distinct high-speed price in its main table.
|
|
166
|
-
// Leave that variant unpriced rather than presenting an invented estimate.
|
|
167
196
|
'kimi-k2.6': { inputPer1M: 0.95, outputPer1M: 4.00 },
|
|
168
197
|
'kimi-for-coding': { inputPer1M: 0.95, outputPer1M: 4.00 },
|
|
169
198
|
'kimi-for-coding-highspeed': { inputPer1M: 0.95, outputPer1M: 4.00 },
|
|
170
199
|
'k3': { inputPer1M: 3.00, outputPer1M: 15.00 },
|
|
171
200
|
'k3-256k': { inputPer1M: 3.00, outputPer1M: 15.00 },
|
|
172
|
-
// Grok (xAI) — base-tier rates.
|
|
173
|
-
//
|
|
201
|
+
// Grok (xAI) — base-tier rates. EVERY Grok text model (4.7, 4.6, 4.5,
|
|
202
|
+
// build-0.1, 4.3) doubles once a prompt reaches 200K tokens, and then bills
|
|
203
|
+
// all tokens in that request at the higher rate, not just those past 200K
|
|
204
|
+
// (docs.x.ai pricing). This table stores one rate per model, so it shows the
|
|
205
|
+
// base tier and under-states those long requests.
|
|
206
|
+
'grok-4.7': { inputPer1M: 2.00, outputPer1M: 6.00 },
|
|
174
207
|
'grok-4.6': { inputPer1M: 2.00, outputPer1M: 6.00 },
|
|
175
208
|
'grok-4.5': { inputPer1M: 2.00, outputPer1M: 6.00 },
|
|
176
209
|
'grok-build-0.1': { inputPer1M: 1.00, outputPer1M: 2.00 },
|
|
@@ -179,17 +212,19 @@ const MODEL_PRICING = {
|
|
|
179
212
|
'grok-4-fast-reasoning': { inputPer1M: 0.20, outputPer1M: 0.50 },
|
|
180
213
|
// Qwen (Alibaba) — list prices for the first context tier. Coding Plan
|
|
181
214
|
// variants are flat-fee; these rates describe pay-per-use calls.
|
|
182
|
-
// `qwen3.8-max-preview`
|
|
183
|
-
//
|
|
184
|
-
// Leave it unpriced rather than borrowing the GA qwen3.8-max rate.
|
|
215
|
+
// `qwen3.8-max-preview` was Token-Plan-only with no published per-token
|
|
216
|
+
// price; it is retired there now and stays unpriced.
|
|
185
217
|
'qwen3.8-max': { inputPer1M: 2.00, outputPer1M: 6.00 },
|
|
186
218
|
'qwen3.8-flash': { inputPer1M: 0.15, outputPer1M: 0.47 },
|
|
187
219
|
'qwen3.7-max': { inputPer1M: 2.50, outputPer1M: 7.50 },
|
|
188
220
|
'qwen3.7-plus': { inputPer1M: 0.40, outputPer1M: 1.60 },
|
|
189
|
-
|
|
221
|
+
// $0.5/$3 up to 256K, $2/$6 above (model-pricing, 2026-09-22). This row
|
|
222
|
+
// used to carry 3.5 Plus's $0.40/$2.40, 20% low.
|
|
223
|
+
'qwen3.6-plus': { inputPer1M: 0.50, outputPer1M: 3.00 },
|
|
190
224
|
'qwen3.5-plus': { inputPer1M: 0.40, outputPer1M: 2.40 },
|
|
191
225
|
'qwen3.6-flash': { inputPer1M: 0.25, outputPer1M: 1.50 },
|
|
192
226
|
// ModelScope free tier — no per-token charge.
|
|
227
|
+
'Qwen/Qwen3.5-397B-A17B': { inputPer1M: 0, outputPer1M: 0 },
|
|
193
228
|
'Qwen/Qwen3-Coder-480B-A35B-Instruct': { inputPer1M: 0, outputPer1M: 0 },
|
|
194
229
|
};
|
|
195
230
|
export function getPricingTable() {
|
|
@@ -257,10 +292,18 @@ export function extractOpenAIUsage(data) {
|
|
|
257
292
|
const nested = data.usage.prompt_tokens_details?.cached_tokens;
|
|
258
293
|
const topLevel = data.usage.cached_tokens ?? data.usage.prompt_cache_hit_tokens;
|
|
259
294
|
const cached = (typeof nested === 'number' ? nested : topLevel) || 0;
|
|
295
|
+
// Cache WRITES, reported by OpenAI from GPT-5.6 on ("For GPT-5.6 and later,
|
|
296
|
+
// cache writes cost 1.25× the standard, uncached input-token rate") and by
|
|
297
|
+
// Kimi K3. Like cached_tokens they are part of prompt_tokens — OpenAI's own
|
|
298
|
+
// formula is input_tokens - cached_tokens - cache_write_tokens — so the
|
|
299
|
+
// cost maths subtracts them from the uncached remainder rather than adding
|
|
300
|
+
// them. Unread, they billed at 1.0× and every estimate erred low.
|
|
301
|
+
const written = data.usage.prompt_tokens_details?.cache_write_tokens;
|
|
260
302
|
return {
|
|
261
303
|
promptTokens: data.usage.prompt_tokens || 0,
|
|
262
304
|
completionTokens: data.usage.completion_tokens || 0,
|
|
263
305
|
totalTokens: data.usage.total_tokens || 0,
|
|
306
|
+
cacheCreationTokens: (typeof written === 'number' && written > 0) ? written : undefined,
|
|
264
307
|
cacheReadTokens: cached || undefined,
|
|
265
308
|
};
|
|
266
309
|
}
|
|
@@ -306,18 +349,63 @@ export function extractAnthropicUsage(data) {
|
|
|
306
349
|
*/
|
|
307
350
|
const MODEL_CACHE_READ_RATE = {
|
|
308
351
|
'claude-fable-5-1': 0.025,
|
|
352
|
+
// "On Claude Opus 5.5, a cache hit costs 5% of the standard input price
|
|
353
|
+
// ($0.20 USD per million tokens)" — half the 0.1× every other Opus pays.
|
|
354
|
+
'claude-opus-5-5': 0.05,
|
|
309
355
|
// V4 Pro's own ratio: $0.044 hit against $1.32 miss (peak; off-peak halves
|
|
310
|
-
// both, so the ratio holds).
|
|
311
|
-
// 2026-09-14 and configs holding it are migrated.
|
|
356
|
+
// both, so the ratio holds).
|
|
312
357
|
'deepseek-v4-pro': 0.044 / 1.32,
|
|
358
|
+
// K3's cached input is one tenth of a miss ($0.30 against $3.00; CNY 2
|
|
359
|
+
// against 20) and has been since launch. The provider-level 0.2 below is
|
|
360
|
+
// K2.7 Code's ratio and billed every K3 hit at twice its price. `k3` and
|
|
361
|
+
// `k3-256k` are the Kimi Code aliases for the same model.
|
|
362
|
+
'kimi-k3': 0.1,
|
|
363
|
+
'k3': 0.1,
|
|
364
|
+
'k3-256k': 0.1,
|
|
365
|
+
// xAI's cached-input price over its input price, below 200K prompt tokens
|
|
366
|
+
// (docs.x.ai models / pricing, 2026-09-21). None is Anthropic's 0.1, so
|
|
367
|
+
// every Grok cache hit used to bill below its cost.
|
|
368
|
+
'grok-4.7': 0.50 / 2.00,
|
|
369
|
+
'grok-4.6': 0.50 / 2.00,
|
|
370
|
+
'grok-4.5': 0.30 / 2.00,
|
|
371
|
+
'grok-build-0.1': 0.20 / 1.00,
|
|
372
|
+
'grok-4.3': 0.20 / 1.25,
|
|
373
|
+
};
|
|
374
|
+
/**
|
|
375
|
+
* Surface-specific read rates, checked first: the same GLM id has a different
|
|
376
|
+
* cached/uncached ratio on Z.AI's international API and on BigModel China, so
|
|
377
|
+
* neither a model row nor a provider row can hold both. Read off each
|
|
378
|
+
* platform's own price table (docs.z.ai/guides/overview/pricing in USD,
|
|
379
|
+
* docs.bigmodel.cn/cn/guide/start/pricing in CNY). The two Coding Plans are
|
|
380
|
+
* flat-fee and need none.
|
|
381
|
+
*/
|
|
382
|
+
const SURFACE_CACHE_READ_RATE = {
|
|
383
|
+
'z.ai-api': {
|
|
384
|
+
'glm-5.3': 0.26 / 1.4,
|
|
385
|
+
'glm-5.2': 0.26 / 1.4,
|
|
386
|
+
'glm-5.3-flash': 0.03 / 0.15,
|
|
387
|
+
'glm-5.3-flashx': 0.075 / 0.37,
|
|
388
|
+
// Its last international listing (2026-07-31): $0.24 against $1.2.
|
|
389
|
+
'glm-5-turbo': 0.24 / 1.2,
|
|
390
|
+
},
|
|
391
|
+
'z.ai-cn-api': {
|
|
392
|
+
'glm-5.3': 2 / 8,
|
|
393
|
+
'glm-5.2': 2 / 8,
|
|
394
|
+
'glm-5.3-flash': 0.23 / 0.8,
|
|
395
|
+
'glm-5.3-flashx': 0.57 / 2,
|
|
396
|
+
'glm-5-turbo': 1.2 / 5,
|
|
397
|
+
},
|
|
313
398
|
};
|
|
314
399
|
const CACHE_READ_RATE = {
|
|
315
400
|
// V4.1 Flash: $0.006 hit against $0.30 miss at peak, $0.003 against $0.15
|
|
316
401
|
// off-peak — 0.02 either way. Without an entry DeepSeek fell to the 0.1
|
|
317
402
|
// default and every cached token billed at five times its price.
|
|
318
403
|
'deepseek': 0.02,
|
|
404
|
+
// K2.7 Code (and HighSpeed): $0.19 against $0.95, ¥1.30 against ¥6.50. China
|
|
405
|
+
// had no entry and fell to 0.1, billing its K2.x hits at half their cost.
|
|
319
406
|
'kimi': 0.2,
|
|
320
407
|
'kimi-api': 0.2,
|
|
408
|
+
'kimi-cn': 0.2,
|
|
321
409
|
'qwen': 0.2,
|
|
322
410
|
'qwen-api': 0.2,
|
|
323
411
|
'qwen-cn': 0.2,
|
|
@@ -335,10 +423,43 @@ const DEFAULT_CACHE_READ_RATE = 0.1;
|
|
|
335
423
|
* cost and a "saved" figure that disagreed with each other.
|
|
336
424
|
*/
|
|
337
425
|
export function cacheReadRateFor(model, provider) {
|
|
338
|
-
|
|
339
|
-
|
|
426
|
+
const surface = provider?.trim().toLowerCase() ?? '';
|
|
427
|
+
return SURFACE_CACHE_READ_RATE[surface]?.[model]
|
|
428
|
+
?? MODEL_CACHE_READ_RATE[model]
|
|
429
|
+
?? CACHE_READ_RATE[surface]
|
|
340
430
|
?? DEFAULT_CACHE_READ_RATE;
|
|
341
431
|
}
|
|
432
|
+
/**
|
|
433
|
+
* Models that write to the cache at their plain input rate. GPT-5.5 and
|
|
434
|
+
* earlier have "No additional cache-write charge" (OpenAI prompt-caching
|
|
435
|
+
* guide); only GPT-5.6 and later bill writes at 1.25×.
|
|
436
|
+
*/
|
|
437
|
+
const MODEL_CACHE_WRITE_RATE = {
|
|
438
|
+
'gpt-5.5': 1,
|
|
439
|
+
'gpt-5.4': 1,
|
|
440
|
+
'gpt-5.4-mini': 1,
|
|
441
|
+
};
|
|
442
|
+
/**
|
|
443
|
+
* Kimi K3 reports writes in the same field as OpenAI, but its default
|
|
444
|
+
* 5-minute write costs exactly a cache-miss input token ($3.00 against $3.00;
|
|
445
|
+
* the 1-hour TTL, which Codeep never asks for, is 2×).
|
|
446
|
+
*/
|
|
447
|
+
const CACHE_WRITE_RATE = {
|
|
448
|
+
'kimi': 1,
|
|
449
|
+
'kimi-api': 1,
|
|
450
|
+
'kimi-cn': 1,
|
|
451
|
+
};
|
|
452
|
+
/** Anthropic's 5-minute write and OpenAI's GPT-5.6+ write both cost 1.25×. */
|
|
453
|
+
const DEFAULT_CACHE_WRITE_RATE = 1.25;
|
|
454
|
+
/**
|
|
455
|
+
* What writing a prompt token into the cache costs, as a multiple of the
|
|
456
|
+
* model's input rate. Same order as reads: model, then provider, then default.
|
|
457
|
+
*/
|
|
458
|
+
export function cacheWriteRateFor(model, provider) {
|
|
459
|
+
return MODEL_CACHE_WRITE_RATE[model]
|
|
460
|
+
?? CACHE_WRITE_RATE[provider?.trim().toLowerCase() ?? '']
|
|
461
|
+
?? DEFAULT_CACHE_WRITE_RATE;
|
|
462
|
+
}
|
|
342
463
|
/**
|
|
343
464
|
* The rate note for a report. One rate reads as "0.02×"; a session mixing
|
|
344
465
|
* providers reads as a range, because any single number there would be wrong
|
|
@@ -380,17 +501,18 @@ export function getCostBreakdown(startIndex = 0) {
|
|
|
380
501
|
else {
|
|
381
502
|
const pricing = MODEL_PRICING[record.model];
|
|
382
503
|
if (pricing) {
|
|
383
|
-
// Cache writes
|
|
384
|
-
//
|
|
385
|
-
//
|
|
386
|
-
// prompt tokens bill at the standard 1.0× rate.
|
|
504
|
+
// Cache writes and cache reads each bill at the fraction of the input
|
|
505
|
+
// rate the model's provider charges for them (writes: 1.25× on
|
|
506
|
+
// Anthropic and GPT-5.6+, 1.0× on Kimi and older GPT). The remaining
|
|
507
|
+
// (uncached) prompt tokens bill at the standard 1.0× rate.
|
|
387
508
|
const cacheCreate = record.cacheCreationTokens ?? 0;
|
|
388
509
|
const cacheRead = record.cacheReadTokens ?? 0;
|
|
389
510
|
const cacheReadRate = cacheReadRateFor(record.model, record.provider);
|
|
511
|
+
const cacheWriteRate = cacheWriteRateFor(record.model, record.provider);
|
|
390
512
|
const uncachedPrompt = Math.max(0, record.promptTokens - cacheCreate - cacheRead);
|
|
391
513
|
existing.estimatedCost +=
|
|
392
514
|
(uncachedPrompt / 1_000_000) * pricing.inputPer1M
|
|
393
|
-
+ (cacheCreate / 1_000_000) * pricing.inputPer1M *
|
|
515
|
+
+ (cacheCreate / 1_000_000) * pricing.inputPer1M * cacheWriteRate
|
|
394
516
|
+ (cacheRead / 1_000_000) * pricing.inputPer1M * cacheReadRate
|
|
395
517
|
+ (record.completionTokens / 1_000_000) * pricing.outputPer1M;
|
|
396
518
|
}
|
|
@@ -406,6 +528,7 @@ export function getCacheStats() {
|
|
|
406
528
|
let flatFeeCached = 0;
|
|
407
529
|
let meteredCached = 0;
|
|
408
530
|
const readRates = [];
|
|
531
|
+
const writeRates = [];
|
|
409
532
|
for (const record of currentRecords()) {
|
|
410
533
|
const cached = (record.cacheCreationTokens ?? 0) + (record.cacheReadTokens ?? 0);
|
|
411
534
|
cacheCreate += record.cacheCreationTokens ?? 0;
|
|
@@ -422,14 +545,18 @@ export function getCacheStats() {
|
|
|
422
545
|
// minus what they cost at the model's own read rate. This hardcoded 0.9
|
|
423
546
|
// (a 0.1 read) for every provider, so Kimi and Qwen (0.2) over-reported
|
|
424
547
|
// savings while DeepSeek (0.02) and Fable 5.1 (0.025) under-reported them.
|
|
425
|
-
//
|
|
548
|
+
// Cache creation costs whatever its write rate is above a plain input
|
|
549
|
+
// token — 0.25× where writes bill at 1.25×, nothing on Kimi — netted in.
|
|
426
550
|
const pricing = MODEL_PRICING[record.model];
|
|
427
551
|
if (pricing) {
|
|
428
552
|
const readRate = cacheReadRateFor(record.model, record.provider);
|
|
553
|
+
const writeRate = cacheWriteRateFor(record.model, record.provider);
|
|
429
554
|
if ((record.cacheReadTokens ?? 0) > 0)
|
|
430
555
|
readRates.push(readRate);
|
|
556
|
+
if ((record.cacheCreationTokens ?? 0) > 0)
|
|
557
|
+
writeRates.push(writeRate);
|
|
431
558
|
const cReadSaved = ((record.cacheReadTokens ?? 0) / 1_000_000) * pricing.inputPer1M * (1 - readRate);
|
|
432
|
-
const cCreateCost = ((record.cacheCreationTokens ?? 0) / 1_000_000) * pricing.inputPer1M *
|
|
559
|
+
const cCreateCost = ((record.cacheCreationTokens ?? 0) / 1_000_000) * pricing.inputPer1M * (writeRate - 1);
|
|
433
560
|
savings += cReadSaved - cCreateCost;
|
|
434
561
|
}
|
|
435
562
|
}
|
|
@@ -440,6 +567,7 @@ export function getCacheStats() {
|
|
|
440
567
|
hasFlatFeeCacheUsage: flatFeeCached > 0,
|
|
441
568
|
isEntirelyFlatFeeCache: flatFeeCached > 0 && meteredCached === 0,
|
|
442
569
|
cacheReadRates: readRates,
|
|
570
|
+
cacheWriteRates: writeRates,
|
|
443
571
|
};
|
|
444
572
|
}
|
|
445
573
|
/**
|
|
@@ -552,7 +680,8 @@ export function formatCostReport() {
|
|
|
552
680
|
// nothing is billed per token, so quoting a rate there would be as invented
|
|
553
681
|
// as the per-model prices this report already refuses to show.
|
|
554
682
|
const readNote = cache.isEntirelyFlatFeeCache ? '' : formatCacheReadRates(cache.cacheReadRates);
|
|
555
|
-
|
|
683
|
+
// The same wording fits writes: a rate against the input price.
|
|
684
|
+
const writeNote = cache.isEntirelyFlatFeeCache ? '' : formatCacheReadRates(cache.cacheWriteRates);
|
|
556
685
|
lines.push(`**Cache reads:** ${formatTokenCount(cache.cacheReadTokens)} tokens${readNote}`);
|
|
557
686
|
if (cache.cacheCreationTokens > 0) {
|
|
558
687
|
lines.push(`**Cache writes:** ${formatTokenCount(cache.cacheCreationTokens)} tokens${writeNote}`);
|
|
@@ -5,6 +5,7 @@
|
|
|
5
5
|
* executeTool() dispatches to individual tool handlers.
|
|
6
6
|
* listDirectory() and htmlToText() are private helpers.
|
|
7
7
|
* createActionLog() converts a ToolCall+ToolResult into a history ActionLog.
|
|
8
|
+
* trustBearingWrite() names the writes that decide what runs later.
|
|
8
9
|
*/
|
|
9
10
|
import { ToolCall, ToolResult, ActionLog } from './tools';
|
|
10
11
|
export { isBlockedIp, assertFetchUrlAllowed } from './ssrfGuard';
|
|
@@ -18,6 +19,46 @@ export declare function validatePath(path: string, projectRoot: string): {
|
|
|
18
19
|
absolutePath: string;
|
|
19
20
|
error?: string;
|
|
20
21
|
};
|
|
22
|
+
/** Drop the cached hook directories. Call before spawning a command line. */
|
|
23
|
+
export declare function forgetHooksDirectory(): void;
|
|
24
|
+
/**
|
|
25
|
+
* The tail of the refusal one of these writes gets when the run has nobody to
|
|
26
|
+
* ask — no permission callback at all, which is how `codeep review --fix`
|
|
27
|
+
* runs in CI. agent.ts builds the refusal; headlessReview.ts recognises it by
|
|
28
|
+
* this text so it can say so in the run output rather than leave it buried in
|
|
29
|
+
* the agent's tool log.
|
|
30
|
+
*
|
|
31
|
+
* One constant, in the module that owns the classification rather than in
|
|
32
|
+
* agent.ts, for two reasons: a reworded refusal that stopped matching would
|
|
33
|
+
* put CI back to failing silently, and agent.js is a module the fix-run tests
|
|
34
|
+
* replace wholesale — a constant read from there would have been undefined in
|
|
35
|
+
* exactly the test that guards this.
|
|
36
|
+
*/
|
|
37
|
+
export declare const NO_CONFIRMER_REFUSAL = "Nobody could be asked to confirm it, so nothing was written.";
|
|
38
|
+
export interface TrustBearingWrite {
|
|
39
|
+
/** The path exactly as the tool call named it, for the prompt. */
|
|
40
|
+
path: string;
|
|
41
|
+
/** The absolute path the classification matched — one spelling per file, so
|
|
42
|
+
* a "never again" answer given for `.git/config` also covers
|
|
43
|
+
* `./.git/config` and the symlink that reaches it. Never shown to anyone;
|
|
44
|
+
* it exists to key that answer (see agent.ts). */
|
|
45
|
+
file: string;
|
|
46
|
+
/** One plain sentence about what the file controls. */
|
|
47
|
+
reason: string;
|
|
48
|
+
}
|
|
49
|
+
/**
|
|
50
|
+
* What a tool call would write that decides what runs later, or null.
|
|
51
|
+
*
|
|
52
|
+
* Callers use this for two things: to force a confirmation the mode would
|
|
53
|
+
* otherwise skip (see agent.ts), and to tell the person answering it what
|
|
54
|
+
* they are approving.
|
|
55
|
+
*
|
|
56
|
+
* A symlink inside the project can point at one of these names — `ln -s .git
|
|
57
|
+
* tools/cfg` makes a write to `tools/cfg/config` land in the real `.git`, and
|
|
58
|
+
* validatePath allows it because it never leaves the project — so the
|
|
59
|
+
* resolved path is classified alongside the one the model asked for.
|
|
60
|
+
*/
|
|
61
|
+
export declare function trustBearingWrite(toolCall: ToolCall, projectRoot: string): TrustBearingWrite | null;
|
|
21
62
|
/**
|
|
22
63
|
* Optional filesystem delegation. When an ACP client advertises `fs`
|
|
23
64
|
* capability (Zed always does, VS Code may), the server should route
|