@kkelly-offical/kkcode 0.1.7 → 0.2.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +674 -674
- package/README.md +452 -387
- package/package.json +50 -46
- package/src/agent/agent.mjs +228 -220
- package/src/agent/custom-agent-loader.mjs +6 -3
- package/src/agent/generator.mjs +2 -2
- package/src/agent/prompt/assistant.txt +12 -0
- package/src/agent/prompt/bug-hunter.txt +89 -89
- package/src/agent/prompt/frontend-designer.txt +58 -58
- package/src/agent/prompt/guide.txt +1 -1
- package/src/agent/prompt/longagent-blueprint-agent.txt +83 -83
- package/src/agent/prompt/longagent-coding-agent.txt +37 -37
- package/src/agent/prompt/longagent-debugging-agent.txt +46 -46
- package/src/agent/prompt/longagent-preview-agent.txt +63 -63
- package/src/command/custom-commands.mjs +2 -2
- package/src/commands/agent.mjs +1 -1
- package/src/commands/background.mjs +145 -4
- package/src/commands/chat.mjs +117 -76
- package/src/commands/config.mjs +148 -1
- package/src/commands/doctor.mjs +30 -6
- package/src/commands/init.mjs +32 -6
- package/src/commands/longagent.mjs +117 -0
- package/src/commands/mcp.mjs +275 -43
- package/src/commands/permission.mjs +1 -1
- package/src/commands/session.mjs +195 -140
- package/src/commands/skill.mjs +63 -0
- package/src/commands/theme.mjs +1 -1
- package/src/config/defaults.mjs +280 -260
- package/src/config/import-config.mjs +1 -1
- package/src/config/load-config.mjs +61 -4
- package/src/config/schema.mjs +591 -574
- package/src/context.mjs +4 -1
- package/src/core/constants.mjs +97 -91
- package/src/core/types.mjs +1 -1
- package/src/github/api.mjs +78 -78
- package/src/github/auth.mjs +294 -286
- package/src/github/flow.mjs +298 -298
- package/src/github/workspace.mjs +225 -212
- package/src/index.mjs +84 -82
- package/src/knowledge/frontend-aesthetics.txt +38 -38
- package/src/mcp/client-http.mjs +139 -141
- package/src/mcp/client-sse.mjs +297 -288
- package/src/mcp/client-stdio.mjs +534 -533
- package/src/mcp/constants.mjs +2 -2
- package/src/mcp/registry.mjs +498 -479
- package/src/mcp/stdio-framing.mjs +135 -133
- package/src/mcp/tool-result.mjs +24 -24
- package/src/observability/edit-diagnostics.mjs +449 -0
- package/src/observability/index.mjs +42 -42
- package/src/observability/metrics.mjs +165 -137
- package/src/observability/tracer.mjs +137 -137
- package/src/onboarding.mjs +209 -0
- package/src/orchestration/background-manager.mjs +567 -372
- package/src/orchestration/background-worker.mjs +419 -305
- package/src/orchestration/interruption-reason.mjs +21 -0
- package/src/orchestration/longagent-manager.mjs +197 -171
- package/src/orchestration/stage-scheduler.mjs +733 -728
- package/src/orchestration/subagent-router.mjs +7 -1
- package/src/orchestration/task-scheduler.mjs +219 -7
- package/src/permission/engine.mjs +1 -1
- package/src/permission/exec-policy.mjs +370 -370
- package/src/permission/file-edit-policy.mjs +108 -0
- package/src/permission/prompt.mjs +1 -1
- package/src/permission/rules.mjs +116 -7
- package/src/plugin/builtin-hooks/post-edit-format.mjs +2 -1
- package/src/plugin/builtin-hooks/post-edit-typecheck.mjs +104 -40
- package/src/plugin/hook-bus.mjs +19 -5
- package/src/plugin/manifest-loader.mjs +222 -0
- package/src/provider/anthropic.mjs +396 -390
- package/src/provider/ollama.mjs +7 -1
- package/src/provider/openai.mjs +382 -340
- package/src/provider/retry-policy.mjs +74 -68
- package/src/provider/router.mjs +242 -241
- package/src/provider/sse.mjs +104 -104
- package/src/provider/wizard.mjs +556 -0
- package/src/repl/capability-facade.mjs +30 -0
- package/src/repl/command-surface.mjs +23 -0
- package/src/repl/controller-entry.mjs +40 -0
- package/src/repl/core-shell.mjs +208 -0
- package/src/repl/dialog-router.mjs +87 -0
- package/src/repl/input-engine.mjs +76 -0
- package/src/repl/keymap.mjs +7 -0
- package/src/repl/operator-surface.mjs +15 -0
- package/src/repl/permission-flow.mjs +49 -0
- package/src/repl/runtime-facade.mjs +36 -0
- package/src/repl/slash-router.mjs +62 -0
- package/src/repl/state-store.mjs +29 -0
- package/src/repl/turn-controller.mjs +58 -0
- package/src/repl/verification.mjs +23 -0
- package/src/repl.mjs +3368 -2981
- package/src/rules/load-rules.mjs +3 -3
- package/src/runtime.mjs +1 -1
- package/src/session/agent-transaction.mjs +86 -0
- package/src/session/checkpoint.mjs +302 -302
- package/src/session/compaction.mjs +298 -298
- package/src/session/engine.mjs +417 -232
- package/src/session/longagent-4stage.mjs +467 -460
- package/src/session/longagent-hybrid.mjs +1344 -1097
- package/src/session/longagent-plan.mjs +376 -365
- package/src/session/longagent-project-memory.mjs +53 -53
- package/src/session/longagent-scaffold.mjs +291 -291
- package/src/session/longagent-task-bus.mjs +138 -54
- package/src/session/longagent-utils.mjs +828 -472
- package/src/session/longagent.mjs +911 -900
- package/src/session/loop.mjs +1005 -930
- package/src/session/prompt/agent.txt +25 -25
- package/src/session/prompt/anthropic.txt +150 -150
- package/src/session/prompt/beast.txt +1 -1
- package/src/session/prompt/plan.txt +31 -31
- package/src/session/prompt/qwen.txt +46 -46
- package/src/session/recovery.mjs +21 -0
- package/src/session/rollback.mjs +196 -195
- package/src/session/routing-observability.mjs +72 -0
- package/src/session/runtime-state.mjs +47 -0
- package/src/session/store.mjs +523 -519
- package/src/session/system-prompt.mjs +308 -273
- package/src/session/task-validator.mjs +267 -267
- package/src/session/usability-gates.mjs +2 -2
- package/src/skill/builtin/commit.mjs +64 -64
- package/src/skill/builtin/design.mjs +76 -76
- package/src/skill/generator.mjs +18 -2
- package/src/skill/registry.mjs +642 -390
- package/src/storage/audit-store.mjs +18 -11
- package/src/storage/event-log.mjs +7 -1
- package/src/storage/ghost-commit-store.mjs +243 -245
- package/src/storage/paths.mjs +13 -0
- package/src/theme/default-theme.mjs +1 -1
- package/src/theme/markdown.mjs +4 -0
- package/src/theme/schema.mjs +1 -1
- package/src/theme/status-bar.mjs +162 -158
- package/src/tool/audit-wrapper.mjs +18 -2
- package/src/tool/edit-transaction.mjs +23 -0
- package/src/tool/executor.mjs +26 -1
- package/src/tool/file-read-state.mjs +65 -0
- package/src/tool/git-auto.mjs +526 -526
- package/src/tool/git-full-auto.mjs +487 -478
- package/src/tool/mutation-guard.mjs +54 -0
- package/src/tool/prompt/edit.txt +3 -3
- package/src/tool/prompt/multiedit.txt +1 -0
- package/src/tool/prompt/notebookedit.txt +2 -1
- package/src/tool/prompt/patch.txt +25 -24
- package/src/tool/prompt/read.txt +3 -3
- package/src/tool/prompt/sysinfo.txt +29 -0
- package/src/tool/prompt/task.txt +66 -4
- package/src/tool/prompt/write.txt +2 -2
- package/src/tool/question-prompt.mjs +99 -93
- package/src/tool/registry.mjs +1701 -1343
- package/src/tool/task-tool.mjs +14 -6
- package/src/ui/activity-renderer.mjs +667 -664
- package/src/ui/repl-background-panel.mjs +7 -0
- package/src/ui/repl-capability-panel.mjs +9 -0
- package/src/ui/repl-dashboard.mjs +54 -4
- package/src/ui/repl-help.mjs +110 -0
- package/src/ui/repl-operator-panel.mjs +12 -0
- package/src/ui/repl-route-feedback.mjs +35 -0
- package/src/ui/repl-status-view.mjs +76 -0
- package/src/ui/repl-task-panel.mjs +5 -0
- package/src/ui/repl-transcript-panel.mjs +56 -0
- package/src/ui/repl-turn-summary.mjs +135 -0
- package/src/usage/pricing.mjs +122 -121
- package/src/usage/usage-meter.mjs +1 -0
- package/src/util/git.mjs +562 -519
- package/src/util/template.mjs +6 -1
package/src/usage/pricing.mjs
CHANGED
|
@@ -1,121 +1,122 @@
|
|
|
1
|
-
import path from "node:path"
|
|
2
|
-
import { access, readFile } from "node:fs/promises"
|
|
3
|
-
import YAML from "yaml"
|
|
4
|
-
|
|
5
|
-
const DEFAULT_PRICING = {
|
|
6
|
-
currency: "USD",
|
|
7
|
-
per_tokens: 1000000,
|
|
8
|
-
models: {
|
|
9
|
-
"claude-opus-4-6": { input: 5, output: 25, cache_read: 0.5, cache_write: 6.25 },
|
|
10
|
-
"claude-opus-4-5": { input: 5, output: 25, cache_read: 0.5, cache_write: 6.25 },
|
|
11
|
-
"claude-opus-4-1": { input: 15, output: 75, cache_read: 1.5, cache_write: 18.75 },
|
|
12
|
-
"claude-opus-4": { input: 15, output: 75, cache_read: 1.5, cache_write: 18.75 },
|
|
13
|
-
"claude-sonnet-4-6": { input: 3, output: 15, cache_read: 0.3, cache_write: 3.75 },
|
|
14
|
-
"claude-sonnet-4-5": { input: 3, output: 15, cache_read: 0.3, cache_write: 3.75 },
|
|
15
|
-
"claude-sonnet-4": { input: 3, output: 15, cache_read: 0.3, cache_write: 3.75 },
|
|
16
|
-
"claude-haiku-4-5": { input: 1, output: 5, cache_read: 0.1, cache_write: 1.25 },
|
|
17
|
-
"claude-haiku-3-5": { input: 0.8, output: 4, cache_read: 0.08, cache_write: 1 },
|
|
18
|
-
"gpt-5.3-codex": { input: 15, output: 60, cache_read: 7.5, cache_write: 15 },
|
|
19
|
-
"gpt-4o": { input: 2.5, output: 10, cache_read: 1.25, cache_write: 2.5 },
|
|
20
|
-
"gpt-4o-mini": { input: 0.15, output: 0.6, cache_read: 0.075, cache_write: 0.15 },
|
|
21
|
-
"deepseek-chat": { input: 0.27, output: 1.1, cache_read: 0.07, cache_write: 0.27 },
|
|
22
|
-
"deepseek-coder": { input: 0.27, output: 1.1, cache_read: 0.07, cache_write: 0.27 },
|
|
23
|
-
"deepseek-v3.1-terminus": { input: 0.55, output: 1.65, cache_read: 0.07, cache_write: 0.55 },
|
|
24
|
-
"deepseek-v3.2": { input: 0.28, output: 0.41, cache_read: 0.03, cache_write: 0.28 },
|
|
25
|
-
"kimi-k2.5": { input: 0.55, output: 2.9, cache_read: 0, cache_write: 0 },
|
|
26
|
-
"kimi-k2-0905": { input: 0.55, output: 2.2, cache_read: 0.14, cache_write: 0 },
|
|
27
|
-
"qwen-plus": { input: 0.11, output: 1.11, cache_read: 0.02, cache_write: 0 },
|
|
28
|
-
"qwen-max": { input: 0.33, output: 1.33, cache_read: 0.07, cache_write: 0 },
|
|
29
|
-
"qwen-turbo": { input: 0.04, output: 0.08, cache_read: 0.01, cache_write: 0 },
|
|
30
|
-
"qwen3-coder-plus": { input: 0.55, output: 2.2, cache_read: 0.11, cache_write: 0 },
|
|
31
|
-
"qwen3-coder-flash": { input: 0.14, output: 0.55, cache_read: 0.03, cache_write: 0 },
|
|
32
|
-
"qwen3-coder-480b-a35b": { input: 0.83, output: 3.3, cache_read: 0.17, cache_write: 0 },
|
|
33
|
-
"doubao-seed-2.0-code": { input: 0.44, output: 2.2, cache_read: 0, cache_write: 0 },
|
|
34
|
-
"doubao-seed-2.0-pro": { input: 0.44, output: 2.2, cache_read: 0, cache_write: 0 },
|
|
35
|
-
"doubao-seed-1.8": { input: 0.11, output: 1.1, cache_read: 0, cache_write: 0 },
|
|
36
|
-
"doubao-seed-code": { input: 0.17, output: 1.1, cache_read: 0, cache_write: 0 },
|
|
37
|
-
"minimax-m2.5": { input: 0.29, output: 1.16, cache_read: 0.03, cache_write: 0 },
|
|
38
|
-
"minimax-m2.5-highspeed": { input: 0.58, output: 2.32, cache_read: 0.03, cache_write: 0 },
|
|
39
|
-
"minimax-m2.1": { input: 0.29, output: 1.16, cache_read: 0.03, cache_write: 0 },
|
|
40
|
-
"minimax-m2": { input: 0.29, output: 1.16, cache_read: 0.03, cache_write: 0 },
|
|
41
|
-
"glm-5": { input: 0.55, output: 3.05, cache_read: 0, cache_write: 0 },
|
|
42
|
-
"glm-4.7": { input: 0.41, output: 1.93, cache_read: 0, cache_write: 0 },
|
|
43
|
-
"glm-4.6": { input: 0.28, output: 1.1, cache_read: 0, cache_write: 0 }
|
|
44
|
-
},
|
|
45
|
-
default: {
|
|
46
|
-
input: 3,
|
|
47
|
-
output: 15,
|
|
48
|
-
cache_read: 0.3,
|
|
49
|
-
cache_write: 3.75
|
|
50
|
-
}
|
|
51
|
-
}
|
|
52
|
-
|
|
53
|
-
async function exists(file) {
|
|
54
|
-
try {
|
|
55
|
-
await access(file)
|
|
56
|
-
return true
|
|
57
|
-
} catch {
|
|
58
|
-
return false
|
|
59
|
-
}
|
|
60
|
-
}
|
|
61
|
-
|
|
62
|
-
function parse(file, raw) {
|
|
63
|
-
if (file.endsWith(".json")) return JSON.parse(raw)
|
|
64
|
-
return YAML.parse(raw)
|
|
65
|
-
}
|
|
66
|
-
|
|
67
|
-
function resolvePricingPath(configState) {
|
|
68
|
-
const projectPath = configState.source.projectRaw?.usage?.pricing_file
|
|
69
|
-
if (typeof projectPath === "string" && projectPath.trim()) {
|
|
70
|
-
return path.resolve(configState.source.projectDir ?? process.cwd(), projectPath)
|
|
71
|
-
}
|
|
72
|
-
const userPath = configState.source.userRaw?.usage?.pricing_file
|
|
73
|
-
if (typeof userPath === "string" && userPath.trim()) {
|
|
74
|
-
return path.resolve(configState.source.userDir ?? process.cwd(), userPath)
|
|
75
|
-
}
|
|
76
|
-
return null
|
|
77
|
-
}
|
|
78
|
-
|
|
79
|
-
export async function loadPricing(configState) {
|
|
80
|
-
const file = resolvePricingPath(configState)
|
|
81
|
-
if (!file || !(await exists(file))) {
|
|
82
|
-
return { pricing: DEFAULT_PRICING, source: "default", errors: [] }
|
|
83
|
-
}
|
|
84
|
-
try {
|
|
85
|
-
const raw = await readFile(file, "utf8")
|
|
86
|
-
const parsed = parse(file, raw)
|
|
87
|
-
const pricing = {
|
|
88
|
-
...DEFAULT_PRICING,
|
|
89
|
-
...parsed,
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
}
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
const
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
(usage.
|
|
116
|
-
(usage.
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
const
|
|
120
|
-
|
|
121
|
-
}
|
|
1
|
+
import path from "node:path"
|
|
2
|
+
import { access, readFile } from "node:fs/promises"
|
|
3
|
+
import YAML from "yaml"
|
|
4
|
+
|
|
5
|
+
const DEFAULT_PRICING = {
|
|
6
|
+
currency: "USD",
|
|
7
|
+
per_tokens: 1000000,
|
|
8
|
+
models: {
|
|
9
|
+
"claude-opus-4-6": { input: 5, output: 25, cache_read: 0.5, cache_write: 6.25 },
|
|
10
|
+
"claude-opus-4-5": { input: 5, output: 25, cache_read: 0.5, cache_write: 6.25 },
|
|
11
|
+
"claude-opus-4-1": { input: 15, output: 75, cache_read: 1.5, cache_write: 18.75 },
|
|
12
|
+
"claude-opus-4": { input: 15, output: 75, cache_read: 1.5, cache_write: 18.75 },
|
|
13
|
+
"claude-sonnet-4-6": { input: 3, output: 15, cache_read: 0.3, cache_write: 3.75 },
|
|
14
|
+
"claude-sonnet-4-5": { input: 3, output: 15, cache_read: 0.3, cache_write: 3.75 },
|
|
15
|
+
"claude-sonnet-4": { input: 3, output: 15, cache_read: 0.3, cache_write: 3.75 },
|
|
16
|
+
"claude-haiku-4-5": { input: 1, output: 5, cache_read: 0.1, cache_write: 1.25 },
|
|
17
|
+
"claude-haiku-3-5": { input: 0.8, output: 4, cache_read: 0.08, cache_write: 1 },
|
|
18
|
+
"gpt-5.3-codex": { input: 15, output: 60, cache_read: 7.5, cache_write: 15 },
|
|
19
|
+
"gpt-4o": { input: 2.5, output: 10, cache_read: 1.25, cache_write: 2.5 },
|
|
20
|
+
"gpt-4o-mini": { input: 0.15, output: 0.6, cache_read: 0.075, cache_write: 0.15 },
|
|
21
|
+
"deepseek-chat": { input: 0.27, output: 1.1, cache_read: 0.07, cache_write: 0.27 },
|
|
22
|
+
"deepseek-coder": { input: 0.27, output: 1.1, cache_read: 0.07, cache_write: 0.27 },
|
|
23
|
+
"deepseek-v3.1-terminus": { input: 0.55, output: 1.65, cache_read: 0.07, cache_write: 0.55 },
|
|
24
|
+
"deepseek-v3.2": { input: 0.28, output: 0.41, cache_read: 0.03, cache_write: 0.28 },
|
|
25
|
+
"kimi-k2.5": { input: 0.55, output: 2.9, cache_read: 0, cache_write: 0 },
|
|
26
|
+
"kimi-k2-0905": { input: 0.55, output: 2.2, cache_read: 0.14, cache_write: 0 },
|
|
27
|
+
"qwen-plus": { input: 0.11, output: 1.11, cache_read: 0.02, cache_write: 0 },
|
|
28
|
+
"qwen-max": { input: 0.33, output: 1.33, cache_read: 0.07, cache_write: 0 },
|
|
29
|
+
"qwen-turbo": { input: 0.04, output: 0.08, cache_read: 0.01, cache_write: 0 },
|
|
30
|
+
"qwen3-coder-plus": { input: 0.55, output: 2.2, cache_read: 0.11, cache_write: 0 },
|
|
31
|
+
"qwen3-coder-flash": { input: 0.14, output: 0.55, cache_read: 0.03, cache_write: 0 },
|
|
32
|
+
"qwen3-coder-480b-a35b": { input: 0.83, output: 3.3, cache_read: 0.17, cache_write: 0 },
|
|
33
|
+
"doubao-seed-2.0-code": { input: 0.44, output: 2.2, cache_read: 0, cache_write: 0 },
|
|
34
|
+
"doubao-seed-2.0-pro": { input: 0.44, output: 2.2, cache_read: 0, cache_write: 0 },
|
|
35
|
+
"doubao-seed-1.8": { input: 0.11, output: 1.1, cache_read: 0, cache_write: 0 },
|
|
36
|
+
"doubao-seed-code": { input: 0.17, output: 1.1, cache_read: 0, cache_write: 0 },
|
|
37
|
+
"minimax-m2.5": { input: 0.29, output: 1.16, cache_read: 0.03, cache_write: 0 },
|
|
38
|
+
"minimax-m2.5-highspeed": { input: 0.58, output: 2.32, cache_read: 0.03, cache_write: 0 },
|
|
39
|
+
"minimax-m2.1": { input: 0.29, output: 1.16, cache_read: 0.03, cache_write: 0 },
|
|
40
|
+
"minimax-m2": { input: 0.29, output: 1.16, cache_read: 0.03, cache_write: 0 },
|
|
41
|
+
"glm-5": { input: 0.55, output: 3.05, cache_read: 0, cache_write: 0 },
|
|
42
|
+
"glm-4.7": { input: 0.41, output: 1.93, cache_read: 0, cache_write: 0 },
|
|
43
|
+
"glm-4.6": { input: 0.28, output: 1.1, cache_read: 0, cache_write: 0 }
|
|
44
|
+
},
|
|
45
|
+
default: {
|
|
46
|
+
input: 3,
|
|
47
|
+
output: 15,
|
|
48
|
+
cache_read: 0.3,
|
|
49
|
+
cache_write: 3.75
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
async function exists(file) {
|
|
54
|
+
try {
|
|
55
|
+
await access(file)
|
|
56
|
+
return true
|
|
57
|
+
} catch {
|
|
58
|
+
return false
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
function parse(file, raw) {
|
|
63
|
+
if (file.endsWith(".json")) return JSON.parse(raw)
|
|
64
|
+
return YAML.parse(raw)
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
function resolvePricingPath(configState) {
|
|
68
|
+
const projectPath = configState.source.projectRaw?.usage?.pricing_file
|
|
69
|
+
if (typeof projectPath === "string" && projectPath.trim()) {
|
|
70
|
+
return path.resolve(configState.source.projectDir ?? process.cwd(), projectPath)
|
|
71
|
+
}
|
|
72
|
+
const userPath = configState.source.userRaw?.usage?.pricing_file
|
|
73
|
+
if (typeof userPath === "string" && userPath.trim()) {
|
|
74
|
+
return path.resolve(configState.source.userDir ?? process.cwd(), userPath)
|
|
75
|
+
}
|
|
76
|
+
return null
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
export async function loadPricing(configState) {
|
|
80
|
+
const file = resolvePricingPath(configState)
|
|
81
|
+
if (!file || !(await exists(file))) {
|
|
82
|
+
return { pricing: DEFAULT_PRICING, source: "default", errors: [] }
|
|
83
|
+
}
|
|
84
|
+
try {
|
|
85
|
+
const raw = await readFile(file, "utf8")
|
|
86
|
+
const parsed = parse(file, raw)
|
|
87
|
+
const pricing = {
|
|
88
|
+
...DEFAULT_PRICING,
|
|
89
|
+
...parsed,
|
|
90
|
+
models: { ...DEFAULT_PRICING.models, ...(parsed.models ?? {}) },
|
|
91
|
+
default: { ...DEFAULT_PRICING.default, ...(parsed.default ?? {}) }
|
|
92
|
+
}
|
|
93
|
+
return { pricing, source: file, errors: [] }
|
|
94
|
+
} catch (error) {
|
|
95
|
+
return { pricing: DEFAULT_PRICING, source: "default", errors: [`${file}: ${error.message}`] }
|
|
96
|
+
}
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
function findPricingEntry(models, model) {
|
|
100
|
+
if (models[model]) return models[model]
|
|
101
|
+
// Fuzzy: try prefix match (e.g. "claude-opus-4-6-20250601" → "claude-opus-4-6")
|
|
102
|
+
const m = String(model).toLowerCase()
|
|
103
|
+
for (const key of Object.keys(models)) {
|
|
104
|
+
if (m.startsWith(key)) return models[key]
|
|
105
|
+
}
|
|
106
|
+
return null
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
export function calculateCost(pricing, model, usage) {
|
|
110
|
+
const entry = findPricingEntry(pricing.models, model) ?? pricing.default
|
|
111
|
+
const per = pricing.per_tokens || 1000000
|
|
112
|
+
// All providers normalize input to non-cached tokens only (see provider/*.mjs)
|
|
113
|
+
const amount =
|
|
114
|
+
((usage.input || 0) * (entry.input || 0) +
|
|
115
|
+
(usage.output || 0) * (entry.output || 0) +
|
|
116
|
+
(usage.cacheRead || 0) * (entry.cache_read || 0) +
|
|
117
|
+
(usage.cacheWrite || 0) * (entry.cache_write || 0)) /
|
|
118
|
+
per
|
|
119
|
+
const savings = ((usage.cacheRead || 0) * ((entry.input || 0) - (entry.cache_read || 0))) / per
|
|
120
|
+
const unknown = !findPricingEntry(pricing.models, model)
|
|
121
|
+
return { amount, savings, unknown, currency: pricing.currency }
|
|
122
|
+
}
|