coding-tool-x 3.6.1 → 3.6.2

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.
@@ -5,7 +5,7 @@
5
5
  <link rel="icon" href="/favicon.ico">
6
6
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
7
7
  <title>coding-tool-x · AI 编程工作台</title>
8
- <script type="module" crossorigin src="/assets/index-CLra7uzu.js"></script>
8
+ <script type="module" crossorigin src="/assets/index-C2yKfEbU.js"></script>
9
9
  <link rel="modulepreload" crossorigin href="/assets/markdown-BNJfEgCA.js">
10
10
  <link rel="modulepreload" crossorigin href="/assets/vue-vendor-B5RqjEjQ.js">
11
11
  <link rel="modulepreload" crossorigin href="/assets/naive-ui-DM897mIP.js">
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "coding-tool-x",
3
- "version": "3.6.1",
3
+ "version": "3.6.2",
4
4
  "description": "Vibe Coding 增强工作助手 - 智能会话管理、动态渠道切换、全局搜索、实时监控",
5
5
  "main": "src/index.js",
6
6
  "bin": {
@@ -46,6 +46,7 @@ const DEFAULT_CONFIG = {
46
46
  mode: 'auto',
47
47
  input: 2.5,
48
48
  output: 15,
49
+ cacheRead: 0.25,
49
50
  models: {
50
51
  'gpt-5-codex': { mode: 'auto' },
51
52
  'gpt-4o-mini': { mode: 'auto' }
@@ -55,6 +56,7 @@ const DEFAULT_CONFIG = {
55
56
  mode: 'auto',
56
57
  input: 1.25,
57
58
  output: 10,
59
+ cacheRead: 0.125,
58
60
  models: {
59
61
  'gemini-2.5-pro': { mode: 'auto' },
60
62
  'gemini-2.5-flash': { mode: 'auto' }
@@ -64,6 +66,7 @@ const DEFAULT_CONFIG = {
64
66
  mode: 'auto',
65
67
  input: 2.5,
66
68
  output: 15,
69
+ cacheRead: 0.25,
67
70
  models: {}
68
71
  }
69
72
  }
@@ -1,7 +1,8 @@
1
1
  {
2
- "lastUpdated": "2026-04-19",
2
+ "lastUpdated": "2026-05-10",
3
3
  "defaultModels": {
4
4
  "claude": [
5
+ "claude-opus-4-7",
5
6
  "claude-opus-4-6",
6
7
  "claude-sonnet-4-6",
7
8
  "claude-opus-4-5-20251101",
@@ -9,8 +10,11 @@
9
10
  "claude-haiku-4-5-20251001"
10
11
  ],
11
12
  "codex": [
13
+ "gpt-5.5",
12
14
  "gpt-5.4",
15
+ "gpt-5.4-mini",
13
16
  "gpt-5.3-codex",
17
+ "gpt-5.3-codex-spark",
14
18
  "gpt-5.2-codex",
15
19
  "gpt-5.1-codex-max",
16
20
  "gpt-5.1-codex",
@@ -21,6 +25,8 @@
21
25
  "gpt-5"
22
26
  ],
23
27
  "gemini": [
28
+ "gemini-3.1-pro-preview",
29
+ "gemini-3.1-flash-preview",
24
30
  "gemini-3-pro-preview",
25
31
  "gemini-3-flash-preview",
26
32
  "gemini-2.5-pro",
@@ -34,17 +40,26 @@
34
40
  "gemini": "gemini-2.5-pro"
35
41
  },
36
42
  "aliases": {
43
+ "claude-opus-4-7": "claude-opus-4-7",
44
+ "claude-opus-4.7": "claude-opus-4-7",
37
45
  "claude-opus-4-6": "claude-opus-4-6",
38
46
  "claude-sonnet-4-6": "claude-sonnet-4-6",
39
47
  "claude-opus-4-5": "claude-opus-4-5-20251101",
40
48
  "claude-sonnet-4-5": "claude-sonnet-4-5-20250929",
41
49
  "claude-haiku-4-5": "claude-haiku-4-5-20251001",
42
- "gemini-3.1-pro": "gemini-3-pro-preview"
50
+ "gemini-3.1-pro": "gemini-3.1-pro-preview",
51
+ "gemini-3.1-pro-high": "gemini-3.1-pro-high",
52
+ "gemini-3.1-pro-low": "gemini-3.1-pro-low",
53
+ "gemini-3.1-flash": "gemini-3.1-flash-preview"
43
54
  },
44
55
  "models": {
56
+ "claude-opus-4-7": {
57
+ "limit": { "context": 1000000, "output": 128000 },
58
+ "pricing": { "input": 5, "output": 25, "cacheCreation": 6.25, "cacheRead": 0.5 }
59
+ },
45
60
  "claude-opus-4-6": {
46
- "limit": { "context": 200000, "output": 32000 },
47
- "pricing": { "input": 15, "output": 75, "cacheCreation": 18.75, "cacheRead": 1.5 }
61
+ "limit": { "context": 1000000, "output": 128000 },
62
+ "pricing": { "input": 5, "output": 25, "cacheCreation": 6.25, "cacheRead": 0.5 }
48
63
  },
49
64
  "claude-sonnet-4-6": {
50
65
  "limit": { "context": 200000, "output": 64000 },
@@ -63,64 +78,92 @@
63
78
  "pricing": { "input": 1, "output": 5, "cacheCreation": 1.25, "cacheRead": 0.1 }
64
79
  },
65
80
  "gpt-5": {
66
- "limit": { "context": 1000000, "output": 32768 },
67
- "pricing": { "input": 1.25, "output": 10 }
81
+ "limit": { "context": 272000, "output": 128000 },
82
+ "pricing": { "input": 1.25, "output": 10, "cacheRead": 0.125 }
68
83
  },
69
84
  "gpt-5.1": {
70
- "limit": { "context": 1000000, "output": 32768 },
71
- "pricing": { "input": 1.25, "output": 10 }
85
+ "limit": { "context": 272000, "output": 128000 },
86
+ "pricing": { "input": 1.25, "output": 10, "cacheRead": 0.125 }
72
87
  },
73
88
  "gpt-5.2": {
74
- "limit": { "context": 1000000, "output": 32768 },
75
- "pricing": { "input": 1.75, "output": 14 }
89
+ "limit": { "context": 272000, "output": 128000 },
90
+ "pricing": { "input": 1.75, "output": 14, "cacheRead": 0.175 }
91
+ },
92
+ "gpt-5.5": {
93
+ "limit": { "context": 1050000, "output": 128000 },
94
+ "pricing": { "input": 5, "output": 30, "cacheRead": 0.5 }
76
95
  },
77
96
  "gpt-5.4": {
78
- "limit": { "context": 1000000, "output": 32768 },
79
- "pricing": { "input": 2.5, "output": 15 }
97
+ "limit": { "context": 1050000, "output": 128000 },
98
+ "pricing": { "input": 2.5, "output": 15, "cacheRead": 0.25 }
99
+ },
100
+ "gpt-5.4-mini": {
101
+ "limit": { "context": 400000, "output": 128000 },
102
+ "pricing": { "input": 0.75, "output": 4.5, "cacheRead": 0.075 }
80
103
  },
81
104
  "gpt-5-codex": {
82
- "limit": { "context": 1000000, "output": 32768 },
83
- "pricing": { "input": 1.25, "output": 10 }
105
+ "limit": { "context": 272000, "output": 128000 },
106
+ "pricing": { "input": 1.25, "output": 10, "cacheRead": 0.125 }
84
107
  },
85
108
  "gpt-5.1-codex": {
86
- "limit": { "context": 1000000, "output": 32768 },
87
- "pricing": { "input": 1.25, "output": 10 }
109
+ "limit": { "context": 272000, "output": 128000 },
110
+ "pricing": { "input": 1.25, "output": 10, "cacheRead": 0.125 }
88
111
  },
89
112
  "gpt-5.1-codex-mini": {
90
- "limit": { "context": 1000000, "output": 32768 },
91
- "pricing": { "input": 0.25, "output": 2 }
113
+ "limit": { "context": 272000, "output": 128000 },
114
+ "pricing": { "input": 0.25, "output": 2, "cacheRead": 0.025 }
92
115
  },
93
116
  "gpt-5.1-codex-max": {
94
- "limit": { "context": 1000000, "output": 32768 },
95
- "pricing": { "input": 1.25, "output": 10 }
117
+ "limit": { "context": 272000, "output": 128000 },
118
+ "pricing": { "input": 1.25, "output": 10, "cacheRead": 0.125 }
96
119
  },
97
120
  "gpt-5.2-codex": {
98
- "limit": { "context": 1000000, "output": 32768 },
99
- "pricing": { "input": 1.75, "output": 14 }
121
+ "limit": { "context": 272000, "output": 128000 },
122
+ "pricing": { "input": 1.75, "output": 14, "cacheRead": 0.175 }
100
123
  },
101
124
  "gpt-5.3-codex": {
102
- "limit": { "context": 1000000, "output": 32768 },
103
- "pricing": { "input": 1.75, "output": 14 }
125
+ "limit": { "context": 272000, "output": 128000 },
126
+ "pricing": { "input": 1.75, "output": 14, "cacheRead": 0.175 }
127
+ },
128
+ "gpt-5.3-codex-spark": {
129
+ "limit": { "context": 272000, "output": 128000 },
130
+ "pricing": { "input": 1.25, "output": 10, "cacheRead": 0.125 }
131
+ },
132
+ "gemini-3.1-pro-preview": {
133
+ "limit": { "context": 1048576, "output": 65536 },
134
+ "pricing": { "input": 2, "output": 12, "cacheRead": 0.2 }
135
+ },
136
+ "gemini-3.1-pro-high": {
137
+ "limit": { "context": 1048576, "output": 65536 },
138
+ "pricing": { "input": 2, "output": 12, "cacheRead": 0.2 }
139
+ },
140
+ "gemini-3.1-pro-low": {
141
+ "limit": { "context": 1048576, "output": 65536 },
142
+ "pricing": { "input": 2, "output": 12, "cacheRead": 0.2 }
143
+ },
144
+ "gemini-3.1-flash-preview": {
145
+ "limit": { "context": 1048576, "output": 65535 },
146
+ "pricing": { "input": 0.5, "output": 3, "cacheRead": 0.05 }
104
147
  },
105
148
  "gemini-3-pro-preview": {
106
- "limit": { "context": 2097152, "output": 65536 },
107
- "pricing": { "input": 2, "output": 12 }
149
+ "limit": { "context": 1048576, "output": 65535 },
150
+ "pricing": { "input": 2, "output": 12, "cacheRead": 0.2 }
108
151
  },
109
152
  "gemini-3-flash-preview": {
110
- "limit": { "context": 1048576, "output": 65536 },
111
- "pricing": { "input": 0.5, "output": 3 }
153
+ "limit": { "context": 1048576, "output": 65535 },
154
+ "pricing": { "input": 0.5, "output": 3, "cacheRead": 0.05 }
112
155
  },
113
156
  "gemini-2.5-pro": {
114
- "limit": { "context": 1048576, "output": 65536 },
115
- "pricing": { "input": 1.25, "output": 10 }
157
+ "limit": { "context": 1048576, "output": 65535 },
158
+ "pricing": { "input": 1.25, "output": 10, "cacheRead": 0.125 }
116
159
  },
117
160
  "gemini-2.5-flash": {
118
- "limit": { "context": 1048576, "output": 65536 },
119
- "pricing": { "input": 0.3, "output": 2.5 }
161
+ "limit": { "context": 1048576, "output": 65535 },
162
+ "pricing": { "input": 0.3, "output": 2.5, "cacheRead": 0.03 }
120
163
  },
121
164
  "gemini-2.5-flash-lite": {
122
- "limit": { "context": 1048576, "output": 65536 },
123
- "pricing": { "input": 0.1, "output": 0.4 }
165
+ "limit": { "context": 1048576, "output": 65535 },
166
+ "pricing": { "input": 0.1, "output": 0.4, "cacheRead": 0.01 }
124
167
  }
125
168
  }
126
169
  }
@@ -7,7 +7,7 @@ const { allocateChannel, releaseChannel, getSchedulerState } = require('./servic
7
7
  const { recordSuccess, recordFailure } = require('./services/channel-health');
8
8
  const { loadConfig } = require('../config/loader');
9
9
  const DEFAULT_CONFIG = require('../config/default');
10
- const { resolveModelPricing } = require('./utils/pricing');
10
+ const { resolveModelPricing, calculateTokenCost } = require('./utils/pricing');
11
11
  const { recordRequest: recordCodexRequest } = require('./services/codex-statistics-service');
12
12
  const { saveProxyStartTime, clearProxyStartTime, getProxyStartTime, getProxyRuntime } = require('./services/proxy-runtime');
13
13
  const { createDecodedStream } = require('./services/response-decoder');
@@ -52,7 +52,6 @@ const PRICING = {
52
52
  };
53
53
 
54
54
  const CODEX_BASE_PRICING = DEFAULT_CONFIG.pricing.codex;
55
- const ONE_MILLION = 1000000;
56
55
 
57
56
  // detectModelTier, redirectModel, resolveTargetUrl imported from services/base/proxy-utils
58
57
 
@@ -90,13 +89,7 @@ function calculateCost(model, tokens) {
90
89
  }
91
90
 
92
91
  const pricing = resolveModelPricing('codex', model, fallbackPricing, CODEX_BASE_PRICING);
93
- const inputRate = typeof pricing.input === 'number' ? pricing.input : CODEX_BASE_PRICING.input;
94
- const outputRate = typeof pricing.output === 'number' ? pricing.output : CODEX_BASE_PRICING.output;
95
-
96
- return (
97
- (tokens.input || 0) * inputRate / ONE_MILLION +
98
- (tokens.output || 0) * outputRate / ONE_MILLION
99
- );
92
+ return calculateTokenCost(pricing, tokens, CODEX_BASE_PRICING);
100
93
  }
101
94
 
102
95
  const jsonBodyParser = express.json({
@@ -598,5 +591,6 @@ module.exports = {
598
591
  startCodexProxyServer,
599
592
  stopCodexProxyServer,
600
593
  getCodexProxyStatus,
601
- clearCodexRedirectCache
594
+ clearCodexRedirectCache,
595
+ calculateCost
602
596
  };
@@ -7,7 +7,7 @@ const { allocateChannel, releaseChannel, getSchedulerState } = require('./servic
7
7
  const { recordSuccess, recordFailure } = require('./services/channel-health');
8
8
  const { loadConfig } = require('../config/loader');
9
9
  const DEFAULT_CONFIG = require('../config/default');
10
- const { resolveModelPricing } = require('./utils/pricing');
10
+ const { resolveModelPricing, calculateTokenCost } = require('./utils/pricing');
11
11
  const { recordRequest: recordGeminiRequest } = require('./services/gemini-statistics-service');
12
12
  const { saveProxyStartTime, clearProxyStartTime, getProxyStartTime, getProxyRuntime } = require('./services/proxy-runtime');
13
13
  const { createDecodedStream } = require('./services/response-decoder');
@@ -32,8 +32,9 @@ const printedGeminiRedirectCache = new Map();
32
32
  // Gemini 模型定价(每百万 tokens 的价格,单位:美元)
33
33
  // 作为 model-metadata 未覆盖时的兜底值
34
34
  const PRICING = {
35
- 'gemini-2.5-pro': { input: 1.25, output: 5 },
36
- 'gemini-2.5-flash': { input: 0.075, output: 0.3 },
35
+ 'gemini-2.5-pro': { input: 1.25, output: 10, cacheRead: 0.125 },
36
+ 'gemini-2.5-flash': { input: 0.3, output: 2.5, cacheRead: 0.03 },
37
+ 'gemini-2.5-flash-lite': { input: 0.1, output: 0.4, cacheRead: 0.01 },
37
38
  'gemini-2.0-flash-exp': { input: 0, output: 0 }, // 实验性免费
38
39
  'gemini-2.0-flash-thinking-exp-1219': { input: 0, output: 0 }, // 实验性免费
39
40
  'gemini-1.5-pro': { input: 1.25, output: 5 },
@@ -46,7 +47,6 @@ const PRICING = {
46
47
  };
47
48
 
48
49
  const GEMINI_BASE_PRICING = DEFAULT_CONFIG.pricing.gemini;
49
- const ONE_MILLION = 1000000;
50
50
 
51
51
  // resolveGeminiTarget replaced by resolveTargetUrl from proxy-utils
52
52
  const resolveGeminiTarget = resolveTargetUrl;
@@ -68,6 +68,8 @@ function calculateCost(model, tokens) {
68
68
  const modelLower = String(model || '').toLowerCase();
69
69
  if (modelLower.includes('gemini-2.5-pro')) {
70
70
  fallbackPricing = PRICING['gemini-2.5-pro'];
71
+ } else if (modelLower.includes('gemini-2.5-flash-lite')) {
72
+ fallbackPricing = PRICING['gemini-2.5-flash-lite'];
71
73
  } else if (modelLower.includes('gemini-2.5-flash')) {
72
74
  fallbackPricing = PRICING['gemini-2.5-flash'];
73
75
  } else if (modelLower.includes('gemini-2.0-flash-thinking')) {
@@ -88,13 +90,7 @@ function calculateCost(model, tokens) {
88
90
  }
89
91
 
90
92
  const pricing = resolveModelPricing('gemini', model, fallbackPricing, GEMINI_BASE_PRICING);
91
- const inputRate = typeof pricing.input === 'number' ? pricing.input : GEMINI_BASE_PRICING.input;
92
- const outputRate = typeof pricing.output === 'number' ? pricing.output : GEMINI_BASE_PRICING.output;
93
-
94
- return (
95
- (tokens.input || 0) * inputRate / ONE_MILLION +
96
- (tokens.output || 0) * outputRate / ONE_MILLION
97
- );
93
+ return calculateTokenCost(pricing, tokens, GEMINI_BASE_PRICING);
98
94
  }
99
95
 
100
96
  // 启动 Gemini 代理服务器
@@ -571,5 +567,6 @@ module.exports = {
571
567
  startGeminiProxyServer,
572
568
  stopGeminiProxyServer,
573
569
  getGeminiProxyStatus,
574
- clearGeminiRedirectCache
570
+ clearGeminiRedirectCache,
571
+ calculateCost
575
572
  };
@@ -14,7 +14,7 @@ const { recordSuccess, recordFailure } = require('./services/channel-health');
14
14
  const { loadConfig } = require('../config/loader');
15
15
  const DEFAULT_CONFIG = require('../config/default');
16
16
  const { PATHS, ensureStorageDirMigrated } = require('../config/paths');
17
- const { resolveModelPricing } = require('./utils/pricing');
17
+ const { resolveModelPricing, calculateTokenCost } = require('./utils/pricing');
18
18
  const { recordRequest: recordOpenCodeRequest } = require('./services/opencode-statistics-service');
19
19
  const { saveProxyStartTime, clearProxyStartTime, getProxyStartTime, getProxyRuntime } = require('./services/proxy-runtime');
20
20
  const { getEnabledChannels, getEffectiveApiKey } = require('./services/opencode-channels');
@@ -58,7 +58,6 @@ const PRICING = {
58
58
  };
59
59
 
60
60
  const OPENCODE_BASE_PRICING = DEFAULT_CONFIG.pricing.opencode || DEFAULT_CONFIG.pricing.codex;
61
- const ONE_MILLION = 1000000;
62
61
  const CLAUDE_CODE_USER_AGENT = 'claude-cli/2.1.59 (external, cli)';
63
62
  const CLAUDE_MESSAGES_BETA_FLAGS = Object.freeze([
64
63
  'claude-code-20250219',
@@ -133,13 +132,7 @@ function calculateCost(model, tokens) {
133
132
  }
134
133
 
135
134
  const pricing = resolveModelPricing('opencode', model, fallbackPricing, OPENCODE_BASE_PRICING);
136
- const inputRate = typeof pricing.input === 'number' ? pricing.input : OPENCODE_BASE_PRICING.input;
137
- const outputRate = typeof pricing.output === 'number' ? pricing.output : OPENCODE_BASE_PRICING.output;
138
-
139
- return (
140
- (tokens.input || 0) * inputRate / ONE_MILLION +
141
- (tokens.output || 0) * outputRate / ONE_MILLION
142
- );
135
+ return calculateTokenCost(pricing, tokens, OPENCODE_BASE_PRICING);
143
136
  }
144
137
 
145
138
  const jsonBodyParser = express.json({
@@ -4741,5 +4734,6 @@ module.exports = {
4741
4734
  stopOpenCodeProxyServer,
4742
4735
  getOpenCodeProxyStatus,
4743
4736
  clearOpenCodeRedirectCache,
4744
- collectProxyModelList
4737
+ collectProxyModelList,
4738
+ calculateCost
4745
4739
  };
@@ -3,6 +3,7 @@ const path = require('path');
3
3
  const crypto = require('crypto');
4
4
  const { HOME_DIR } = require('../../config/paths');
5
5
  const { getGeminiDir } = require('./gemini-config');
6
+ const { resolveModelPricing } = require('../utils/pricing');
6
7
 
7
8
  // 路径映射缓存
8
9
  let pathMappingCache = null;
@@ -228,8 +229,10 @@ function readSessionMeta(filePath) {
228
229
  model = msg.model;
229
230
  const inputTokens = msg.tokens.input || 0;
230
231
  const outputTokens = msg.tokens.output || 0;
231
- // gemini-2.5-pro: $1.25 / 1M input, $5 / 1M output
232
- totalCost += (inputTokens * 1.25 / 1000000) + (outputTokens * 5 / 1000000);
232
+ const pricing = resolveModelPricing('gemini', msg.model);
233
+ const inputRate = typeof pricing.input === 'number' ? pricing.input : 1.25;
234
+ const outputRate = typeof pricing.output === 'number' ? pricing.output : 10;
235
+ totalCost += (inputTokens * inputRate / 1000000) + (outputTokens * outputRate / 1000000);
233
236
  }
234
237
  }
235
238
  });
@@ -16,6 +16,7 @@ const { PATHS } = require('../../config/paths');
16
16
  // 内置模型优先级(当配置缺失时兜底)
17
17
  const MODEL_PRIORITY = {
18
18
  claude: [
19
+ 'claude-opus-4-7',
19
20
  'claude-opus-4-6',
20
21
  'claude-sonnet-4-6',
21
22
  'claude-opus-4-5-20251101',
@@ -23,7 +24,11 @@ const MODEL_PRIORITY = {
23
24
  'claude-haiku-4-5-20251001'
24
25
  ],
25
26
  codex: [
27
+ 'gpt-5.5',
26
28
  'gpt-5.4',
29
+ 'gpt-5.4-mini',
30
+ 'gpt-5.3-codex',
31
+ 'gpt-5.3-codex-spark',
27
32
  'gpt-5.2-codex',
28
33
  'gpt-5.1-codex-max',
29
34
  'gpt-5.1-codex',
@@ -34,6 +39,8 @@ const MODEL_PRIORITY = {
34
39
  'gpt-5'
35
40
  ],
36
41
  gemini: [
42
+ 'gemini-3.1-pro-preview',
43
+ 'gemini-3.1-flash-preview',
37
44
  'gemini-3-pro-preview',
38
45
  'gemini-3-flash-preview',
39
46
  'gemini-2.5-pro',
@@ -67,7 +67,32 @@ function resolveModelPricing(_toolKey, model, fallbackPricing = {}, defaultPrici
67
67
  };
68
68
  }
69
69
 
70
+ function getRate(pricing, defaultPricing, key) {
71
+ if (typeof pricing?.[key] === 'number') return pricing[key];
72
+ if (typeof defaultPricing?.[key] === 'number') return defaultPricing[key];
73
+ return 0;
74
+ }
75
+
76
+ function calculateTokenCost(pricing = {}, tokens = {}, defaultPricing = {}) {
77
+ const inputRate = getRate(pricing, defaultPricing, 'input');
78
+ const outputRate = getRate(pricing, defaultPricing, 'output');
79
+ const cacheCreationRate = getRate(pricing, defaultPricing, 'cacheCreation');
80
+ const cacheReadRate = getRate(pricing, defaultPricing, 'cacheRead');
81
+ const inputTokens = Number(tokens.input || 0);
82
+ const outputTokens = Number(tokens.output || 0);
83
+ const cacheCreationTokens = Number(tokens.cacheCreation || 0);
84
+ const cacheReadTokens = Number(tokens.cacheRead || tokens.cached || 0);
85
+
86
+ return (
87
+ inputTokens * inputRate / 1000000 +
88
+ outputTokens * outputRate / 1000000 +
89
+ cacheCreationTokens * cacheCreationRate / 1000000 +
90
+ cacheReadTokens * cacheReadRate / 1000000
91
+ );
92
+ }
93
+
70
94
  module.exports = {
71
95
  resolvePricing,
72
- resolveModelPricing
96
+ resolveModelPricing,
97
+ calculateTokenCost
73
98
  };