@proteinjs/conversation 2.6.0 → 2.7.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/CHANGELOG.md +18 -0
- package/dist/index.d.ts +1 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +1 -0
- package/dist/index.js.map +1 -1
- package/dist/src/Conversation.d.ts.map +1 -1
- package/dist/src/Conversation.js +12 -16
- package/dist/src/Conversation.js.map +1 -1
- package/dist/src/OpenAi.js +3 -3
- package/dist/src/OpenAi.js.map +1 -1
- package/dist/src/OpenAiResponses.d.ts +41 -4
- package/dist/src/OpenAiResponses.d.ts.map +1 -1
- package/dist/src/OpenAiResponses.js +757 -77
- package/dist/src/OpenAiResponses.js.map +1 -1
- package/dist/src/OpenAiStreamProcessor.js +4 -4
- package/dist/src/OpenAiStreamProcessor.js.map +1 -1
- package/dist/src/UsageData.d.ts +39 -4
- package/dist/src/UsageData.d.ts.map +1 -1
- package/dist/src/UsageData.js +302 -11
- package/dist/src/UsageData.js.map +1 -1
- package/dist/src/fs/conversation_fs/ConversationFsModule.d.ts.map +1 -1
- package/dist/src/fs/conversation_fs/ConversationFsModule.js +1 -0
- package/dist/src/fs/conversation_fs/ConversationFsModule.js.map +1 -1
- package/dist/src/fs/conversation_fs/FsFunctions.d.ts +26 -0
- package/dist/src/fs/conversation_fs/FsFunctions.d.ts.map +1 -1
- package/dist/src/fs/conversation_fs/FsFunctions.js +68 -27
- package/dist/src/fs/conversation_fs/FsFunctions.js.map +1 -1
- package/index.ts +1 -1
- package/package.json +5 -6
- package/src/Conversation.ts +14 -17
- package/src/OpenAi.ts +3 -3
- package/src/OpenAiResponses.ts +905 -112
- package/src/OpenAiStreamProcessor.ts +3 -3
- package/src/UsageData.ts +376 -13
- package/src/fs/conversation_fs/ConversationFsModule.ts +2 -0
- package/src/fs/conversation_fs/FsFunctions.ts +32 -2
- package/LICENSE +0 -21
|
@@ -90,10 +90,10 @@ export class OpenAiStreamProcessor {
|
|
|
90
90
|
this.outputStreamTerminated = true;
|
|
91
91
|
} else if (chunk.usage) {
|
|
92
92
|
this.usageDataAccumulator.addTokenUsage({
|
|
93
|
-
|
|
93
|
+
inputTokens: chunk.usage.prompt_tokens,
|
|
94
|
+
cachedInputTokens: chunk.usage.prompt_tokens_details?.cached_tokens ?? 0,
|
|
94
95
|
reasoningTokens: chunk.usage.completion_tokens_details?.reasoning_tokens ?? 0,
|
|
95
|
-
|
|
96
|
-
completionTokens: chunk.usage.completion_tokens,
|
|
96
|
+
outputTokens: chunk.usage.completion_tokens,
|
|
97
97
|
totalTokens: chunk.usage.total_tokens,
|
|
98
98
|
});
|
|
99
99
|
if (finishedProcessingToolCallStream) {
|
package/src/UsageData.ts
CHANGED
|
@@ -1,13 +1,30 @@
|
|
|
1
1
|
import { TiktokenModel } from 'tiktoken';
|
|
2
2
|
|
|
3
3
|
export type TokenUsage = {
|
|
4
|
-
|
|
4
|
+
inputTokens: number;
|
|
5
|
+
cachedInputTokens: number;
|
|
5
6
|
reasoningTokens: number;
|
|
6
|
-
|
|
7
|
-
completionTokens: number;
|
|
7
|
+
outputTokens: number;
|
|
8
8
|
totalTokens: number;
|
|
9
9
|
};
|
|
10
10
|
|
|
11
|
+
export type ModelApiCost = {
|
|
12
|
+
/** USD per 1M input tokens */
|
|
13
|
+
inputUsdPer1M: number;
|
|
14
|
+
/** USD per 1M cached input tokens (if supported) */
|
|
15
|
+
cachedInputUsdPer1M?: number;
|
|
16
|
+
/** USD per 1M output tokens */
|
|
17
|
+
outputUsdPer1M: number;
|
|
18
|
+
};
|
|
19
|
+
|
|
20
|
+
export type UsageCostUsd = {
|
|
21
|
+
inputUsd: number;
|
|
22
|
+
cachedInputUsd: number;
|
|
23
|
+
reasoningUsd: number;
|
|
24
|
+
outputUsd: number;
|
|
25
|
+
totalUsd: number;
|
|
26
|
+
};
|
|
27
|
+
|
|
11
28
|
/**
|
|
12
29
|
* Usage data accumulated throughout the lifecycle of a single call to
|
|
13
30
|
* `OpenAi.generateResponse` or `OpenAi.generateStreamingResponse`.
|
|
@@ -17,8 +34,12 @@ export type UsageData = {
|
|
|
17
34
|
model: TiktokenModel;
|
|
18
35
|
/** The token usage of the initial request sent to the assistant */
|
|
19
36
|
initialRequestTokenUsage: TokenUsage;
|
|
37
|
+
/** The USD cost of the initial request */
|
|
38
|
+
initialRequestCostUsd: UsageCostUsd;
|
|
20
39
|
/** The total token usage of all requests sent to the assistant (ie. initial request + all subsequent tool call requests) */
|
|
21
40
|
totalTokenUsage: TokenUsage;
|
|
41
|
+
/** The total USD cost of all requests sent to the assistant */
|
|
42
|
+
totalCostUsd: UsageCostUsd;
|
|
22
43
|
/** The number of requests sent to the assistant */
|
|
23
44
|
totalRequestsToAssistant: number;
|
|
24
45
|
/** The number of times each tool was called by the assistant */
|
|
@@ -39,36 +60,71 @@ export class UsageDataAccumulator {
|
|
|
39
60
|
this.usageData = {
|
|
40
61
|
model,
|
|
41
62
|
initialRequestTokenUsage: {
|
|
42
|
-
|
|
63
|
+
inputTokens: 0,
|
|
43
64
|
reasoningTokens: 0,
|
|
44
|
-
|
|
45
|
-
|
|
65
|
+
cachedInputTokens: 0,
|
|
66
|
+
outputTokens: 0,
|
|
46
67
|
totalTokens: 0,
|
|
47
68
|
},
|
|
69
|
+
initialRequestCostUsd: {
|
|
70
|
+
inputUsd: 0,
|
|
71
|
+
cachedInputUsd: 0,
|
|
72
|
+
reasoningUsd: 0,
|
|
73
|
+
outputUsd: 0,
|
|
74
|
+
totalUsd: 0,
|
|
75
|
+
},
|
|
48
76
|
totalTokenUsage: {
|
|
49
|
-
|
|
77
|
+
inputTokens: 0,
|
|
78
|
+
cachedInputTokens: 0,
|
|
50
79
|
reasoningTokens: 0,
|
|
51
|
-
|
|
52
|
-
completionTokens: 0,
|
|
80
|
+
outputTokens: 0,
|
|
53
81
|
totalTokens: 0,
|
|
54
82
|
},
|
|
83
|
+
totalCostUsd: {
|
|
84
|
+
inputUsd: 0,
|
|
85
|
+
cachedInputUsd: 0,
|
|
86
|
+
reasoningUsd: 0,
|
|
87
|
+
outputUsd: 0,
|
|
88
|
+
totalUsd: 0,
|
|
89
|
+
},
|
|
55
90
|
totalRequestsToAssistant: 0,
|
|
56
91
|
callsPerTool: {},
|
|
57
92
|
totalToolCalls: 0,
|
|
58
93
|
};
|
|
59
94
|
}
|
|
60
95
|
|
|
61
|
-
addTokenUsage(tokenUsage: TokenUsage) {
|
|
96
|
+
addTokenUsage(tokenUsage: TokenUsage, opts?: { serviceTier?: string }) {
|
|
62
97
|
this.usageData.totalRequestsToAssistant++;
|
|
98
|
+
|
|
99
|
+
const cost = calculateUsageCostUsd(this.usageData.model, tokenUsage, { serviceTier: opts?.serviceTier });
|
|
100
|
+
|
|
63
101
|
if (!this.processedInitialRequest) {
|
|
64
102
|
this.usageData.initialRequestTokenUsage = tokenUsage;
|
|
103
|
+
this.usageData.initialRequestCostUsd = cost;
|
|
65
104
|
this.processedInitialRequest = true;
|
|
66
105
|
}
|
|
106
|
+
|
|
107
|
+
if (cost) {
|
|
108
|
+
if (!this.usageData.totalCostUsd) {
|
|
109
|
+
this.usageData.totalCostUsd = { ...cost };
|
|
110
|
+
} else {
|
|
111
|
+
this.usageData.totalCostUsd = {
|
|
112
|
+
inputUsd: this.usageData.totalCostUsd.inputUsd + cost.inputUsd,
|
|
113
|
+
cachedInputUsd: this.usageData.totalCostUsd.cachedInputUsd + cost.cachedInputUsd,
|
|
114
|
+
reasoningUsd: this.usageData.totalCostUsd.reasoningUsd + cost.reasoningUsd,
|
|
115
|
+
outputUsd: this.usageData.totalCostUsd.outputUsd + cost.outputUsd,
|
|
116
|
+
totalUsd: this.usageData.totalCostUsd.totalUsd + cost.totalUsd,
|
|
117
|
+
};
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
this.usageData.totalCostUsd = roundUsageCostUsdToCents(this.usageData.totalCostUsd);
|
|
121
|
+
}
|
|
122
|
+
|
|
67
123
|
this.usageData.totalTokenUsage = {
|
|
68
|
-
|
|
124
|
+
inputTokens: this.usageData.totalTokenUsage.inputTokens + tokenUsage.inputTokens,
|
|
125
|
+
cachedInputTokens: this.usageData.totalTokenUsage.cachedInputTokens + tokenUsage.cachedInputTokens,
|
|
69
126
|
reasoningTokens: this.usageData.totalTokenUsage.reasoningTokens + tokenUsage.reasoningTokens,
|
|
70
|
-
|
|
71
|
-
completionTokens: this.usageData.totalTokenUsage.completionTokens + tokenUsage.completionTokens,
|
|
127
|
+
outputTokens: this.usageData.totalTokenUsage.outputTokens + tokenUsage.outputTokens,
|
|
72
128
|
totalTokens: this.usageData.totalTokenUsage.totalTokens + tokenUsage.totalTokens,
|
|
73
129
|
};
|
|
74
130
|
}
|
|
@@ -82,3 +138,310 @@ export class UsageDataAccumulator {
|
|
|
82
138
|
this.usageData.totalToolCalls++;
|
|
83
139
|
}
|
|
84
140
|
}
|
|
141
|
+
|
|
142
|
+
/**
|
|
143
|
+
* Aggregate multiple UsageData objects into a single UsageData.
|
|
144
|
+
*/
|
|
145
|
+
export function aggregateUsageData(list: UsageData[]): UsageData | undefined {
|
|
146
|
+
if (!Array.isArray(list) || list.length === 0) {
|
|
147
|
+
return undefined;
|
|
148
|
+
}
|
|
149
|
+
|
|
150
|
+
const first = list[0];
|
|
151
|
+
|
|
152
|
+
const out: UsageData = {
|
|
153
|
+
model: first.model,
|
|
154
|
+
initialRequestTokenUsage: { ...first.initialRequestTokenUsage },
|
|
155
|
+
totalTokenUsage: { ...first.totalTokenUsage },
|
|
156
|
+
totalRequestsToAssistant: first.totalRequestsToAssistant,
|
|
157
|
+
callsPerTool: { ...first.callsPerTool },
|
|
158
|
+
totalToolCalls: first.totalToolCalls,
|
|
159
|
+
initialRequestCostUsd: { ...first.initialRequestCostUsd },
|
|
160
|
+
totalCostUsd: { ...first.totalCostUsd },
|
|
161
|
+
};
|
|
162
|
+
|
|
163
|
+
for (const u of list.slice(1)) {
|
|
164
|
+
out.totalTokenUsage.inputTokens += u.totalTokenUsage.inputTokens;
|
|
165
|
+
out.totalTokenUsage.cachedInputTokens += u.totalTokenUsage.cachedInputTokens;
|
|
166
|
+
out.totalTokenUsage.reasoningTokens += u.totalTokenUsage.reasoningTokens;
|
|
167
|
+
out.totalTokenUsage.outputTokens += u.totalTokenUsage.outputTokens;
|
|
168
|
+
out.totalTokenUsage.totalTokens += u.totalTokenUsage.totalTokens;
|
|
169
|
+
|
|
170
|
+
out.totalRequestsToAssistant += u.totalRequestsToAssistant;
|
|
171
|
+
out.totalToolCalls += u.totalToolCalls;
|
|
172
|
+
|
|
173
|
+
for (const [k, v] of Object.entries(u.callsPerTool)) {
|
|
174
|
+
out.callsPerTool[k] = (out.callsPerTool[k] ?? 0) + v;
|
|
175
|
+
}
|
|
176
|
+
|
|
177
|
+
out.totalCostUsd.inputUsd += u.totalCostUsd.inputUsd;
|
|
178
|
+
out.totalCostUsd.cachedInputUsd += u.totalCostUsd.cachedInputUsd;
|
|
179
|
+
out.totalCostUsd.reasoningUsd += u.totalCostUsd.reasoningUsd;
|
|
180
|
+
out.totalCostUsd.outputUsd += u.totalCostUsd.outputUsd;
|
|
181
|
+
out.totalCostUsd.totalUsd += u.totalCostUsd.totalUsd;
|
|
182
|
+
|
|
183
|
+
out.totalCostUsd = roundUsageCostUsdToCents(out.totalCostUsd);
|
|
184
|
+
}
|
|
185
|
+
|
|
186
|
+
return out;
|
|
187
|
+
}
|
|
188
|
+
|
|
189
|
+
/**
|
|
190
|
+
* Standard tier costs (USD per 1M tokens) based on the pricing on OpenAI's website.
|
|
191
|
+
*/
|
|
192
|
+
export const MODEL_API_COST_USD_PER_1M_TOKENS_STANDARD: Record<string, ModelApiCost> = {
|
|
193
|
+
'gpt-5.2': { inputUsdPer1M: 1.75, cachedInputUsdPer1M: 0.175, outputUsdPer1M: 14.0 },
|
|
194
|
+
'gpt-5.1': { inputUsdPer1M: 1.25, cachedInputUsdPer1M: 0.125, outputUsdPer1M: 10.0 },
|
|
195
|
+
'gpt-5': { inputUsdPer1M: 1.25, cachedInputUsdPer1M: 0.125, outputUsdPer1M: 10.0 },
|
|
196
|
+
'gpt-5-mini': { inputUsdPer1M: 0.25, cachedInputUsdPer1M: 0.025, outputUsdPer1M: 2.0 },
|
|
197
|
+
'gpt-5-nano': { inputUsdPer1M: 0.05, cachedInputUsdPer1M: 0.005, outputUsdPer1M: 0.4 },
|
|
198
|
+
|
|
199
|
+
'gpt-5.2-chat-latest': { inputUsdPer1M: 1.75, cachedInputUsdPer1M: 0.175, outputUsdPer1M: 14.0 },
|
|
200
|
+
'gpt-5.1-chat-latest': { inputUsdPer1M: 1.25, cachedInputUsdPer1M: 0.125, outputUsdPer1M: 10.0 },
|
|
201
|
+
'gpt-5-chat-latest': { inputUsdPer1M: 1.25, cachedInputUsdPer1M: 0.125, outputUsdPer1M: 10.0 },
|
|
202
|
+
|
|
203
|
+
'gpt-5.2-codex': { inputUsdPer1M: 1.75, cachedInputUsdPer1M: 0.175, outputUsdPer1M: 14.0 },
|
|
204
|
+
'gpt-5.1-codex-max': { inputUsdPer1M: 1.25, cachedInputUsdPer1M: 0.125, outputUsdPer1M: 10.0 },
|
|
205
|
+
'gpt-5.1-codex': { inputUsdPer1M: 1.25, cachedInputUsdPer1M: 0.125, outputUsdPer1M: 10.0 },
|
|
206
|
+
'gpt-5-codex': { inputUsdPer1M: 1.25, cachedInputUsdPer1M: 0.125, outputUsdPer1M: 10.0 },
|
|
207
|
+
|
|
208
|
+
'gpt-5.2-pro': { inputUsdPer1M: 21.0, outputUsdPer1M: 168.0 },
|
|
209
|
+
'gpt-5-pro': { inputUsdPer1M: 15.0, outputUsdPer1M: 120.0 },
|
|
210
|
+
|
|
211
|
+
'gpt-4.1': { inputUsdPer1M: 2.0, cachedInputUsdPer1M: 0.5, outputUsdPer1M: 8.0 },
|
|
212
|
+
'gpt-4.1-mini': { inputUsdPer1M: 0.4, cachedInputUsdPer1M: 0.1, outputUsdPer1M: 1.6 },
|
|
213
|
+
'gpt-4.1-nano': { inputUsdPer1M: 0.1, cachedInputUsdPer1M: 0.025, outputUsdPer1M: 0.4 },
|
|
214
|
+
|
|
215
|
+
'gpt-4o': { inputUsdPer1M: 2.5, cachedInputUsdPer1M: 1.25, outputUsdPer1M: 10.0 },
|
|
216
|
+
'gpt-4o-2024-05-13': { inputUsdPer1M: 5.0, outputUsdPer1M: 15.0 },
|
|
217
|
+
'gpt-4o-mini': { inputUsdPer1M: 0.15, cachedInputUsdPer1M: 0.075, outputUsdPer1M: 0.6 },
|
|
218
|
+
|
|
219
|
+
'gpt-realtime': { inputUsdPer1M: 4.0, cachedInputUsdPer1M: 0.4, outputUsdPer1M: 16.0 },
|
|
220
|
+
'gpt-realtime-mini': { inputUsdPer1M: 0.6, cachedInputUsdPer1M: 0.06, outputUsdPer1M: 2.4 },
|
|
221
|
+
|
|
222
|
+
'gpt-4o-realtime-preview': { inputUsdPer1M: 5.0, cachedInputUsdPer1M: 2.5, outputUsdPer1M: 20.0 },
|
|
223
|
+
'gpt-4o-mini-realtime-preview': { inputUsdPer1M: 0.6, cachedInputUsdPer1M: 0.3, outputUsdPer1M: 2.4 },
|
|
224
|
+
|
|
225
|
+
'gpt-audio': { inputUsdPer1M: 2.5, outputUsdPer1M: 10.0 },
|
|
226
|
+
'gpt-audio-mini': { inputUsdPer1M: 0.6, outputUsdPer1M: 2.4 },
|
|
227
|
+
'gpt-4o-audio-preview': { inputUsdPer1M: 2.5, outputUsdPer1M: 10.0 },
|
|
228
|
+
'gpt-4o-mini-audio-preview': { inputUsdPer1M: 0.15, outputUsdPer1M: 0.6 },
|
|
229
|
+
|
|
230
|
+
o1: { inputUsdPer1M: 15.0, cachedInputUsdPer1M: 7.5, outputUsdPer1M: 60.0 },
|
|
231
|
+
'o1-pro': { inputUsdPer1M: 150.0, outputUsdPer1M: 600.0 },
|
|
232
|
+
'o1-mini': { inputUsdPer1M: 1.1, cachedInputUsdPer1M: 0.55, outputUsdPer1M: 4.4 },
|
|
233
|
+
|
|
234
|
+
o3: { inputUsdPer1M: 2.0, cachedInputUsdPer1M: 0.5, outputUsdPer1M: 8.0 },
|
|
235
|
+
'o3-pro': { inputUsdPer1M: 20.0, outputUsdPer1M: 80.0 },
|
|
236
|
+
'o3-mini': { inputUsdPer1M: 1.1, cachedInputUsdPer1M: 0.55, outputUsdPer1M: 4.4 },
|
|
237
|
+
'o3-deep-research': { inputUsdPer1M: 10.0, cachedInputUsdPer1M: 2.5, outputUsdPer1M: 40.0 },
|
|
238
|
+
|
|
239
|
+
'o4-mini': { inputUsdPer1M: 1.1, cachedInputUsdPer1M: 0.275, outputUsdPer1M: 4.4 },
|
|
240
|
+
'o4-mini-deep-research': { inputUsdPer1M: 2.0, cachedInputUsdPer1M: 0.5, outputUsdPer1M: 8.0 },
|
|
241
|
+
|
|
242
|
+
'gpt-5-search-api': { inputUsdPer1M: 1.25, cachedInputUsdPer1M: 0.125, outputUsdPer1M: 10.0 },
|
|
243
|
+
'gpt-4o-mini-search-preview': { inputUsdPer1M: 0.15, outputUsdPer1M: 0.6 },
|
|
244
|
+
'gpt-4o-search-preview': { inputUsdPer1M: 2.5, outputUsdPer1M: 10.0 },
|
|
245
|
+
'computer-use-preview': { inputUsdPer1M: 3.0, outputUsdPer1M: 12.0 },
|
|
246
|
+
|
|
247
|
+
'gpt-5.1-codex-mini': { inputUsdPer1M: 0.25, cachedInputUsdPer1M: 0.025, outputUsdPer1M: 2.0 },
|
|
248
|
+
'codex-mini-latest': { inputUsdPer1M: 1.5, cachedInputUsdPer1M: 0.375, outputUsdPer1M: 6.0 },
|
|
249
|
+
};
|
|
250
|
+
|
|
251
|
+
export const MODEL_API_COST_USD_PER_1M_TOKENS_BATCH: Record<string, ModelApiCost> = {
|
|
252
|
+
'gpt-5.2': { inputUsdPer1M: 0.875, cachedInputUsdPer1M: 0.0875, outputUsdPer1M: 7.0 },
|
|
253
|
+
'gpt-5.1': { inputUsdPer1M: 0.625, cachedInputUsdPer1M: 0.0625, outputUsdPer1M: 5.0 },
|
|
254
|
+
'gpt-5': { inputUsdPer1M: 0.625, cachedInputUsdPer1M: 0.0625, outputUsdPer1M: 5.0 },
|
|
255
|
+
'gpt-5-mini': { inputUsdPer1M: 0.125, cachedInputUsdPer1M: 0.0125, outputUsdPer1M: 1.0 },
|
|
256
|
+
'gpt-5-nano': { inputUsdPer1M: 0.025, cachedInputUsdPer1M: 0.0025, outputUsdPer1M: 0.2 },
|
|
257
|
+
|
|
258
|
+
'gpt-5.2-pro': { inputUsdPer1M: 10.5, outputUsdPer1M: 84.0 },
|
|
259
|
+
'gpt-5-pro': { inputUsdPer1M: 7.5, outputUsdPer1M: 60.0 },
|
|
260
|
+
|
|
261
|
+
'gpt-4.1': { inputUsdPer1M: 1.0, outputUsdPer1M: 4.0 },
|
|
262
|
+
'gpt-4.1-mini': { inputUsdPer1M: 0.2, outputUsdPer1M: 0.8 },
|
|
263
|
+
'gpt-4.1-nano': { inputUsdPer1M: 0.05, outputUsdPer1M: 0.2 },
|
|
264
|
+
|
|
265
|
+
'gpt-4o': { inputUsdPer1M: 1.25, outputUsdPer1M: 5.0 },
|
|
266
|
+
'gpt-4o-2024-05-13': { inputUsdPer1M: 2.5, outputUsdPer1M: 7.5 },
|
|
267
|
+
'gpt-4o-mini': { inputUsdPer1M: 0.075, outputUsdPer1M: 0.3 },
|
|
268
|
+
|
|
269
|
+
o1: { inputUsdPer1M: 7.5, outputUsdPer1M: 30.0 },
|
|
270
|
+
'o1-pro': { inputUsdPer1M: 75.0, outputUsdPer1M: 300.0 },
|
|
271
|
+
|
|
272
|
+
'o3-pro': { inputUsdPer1M: 10.0, outputUsdPer1M: 40.0 },
|
|
273
|
+
o3: { inputUsdPer1M: 1.0, outputUsdPer1M: 4.0 },
|
|
274
|
+
'o3-deep-research': { inputUsdPer1M: 5.0, outputUsdPer1M: 20.0 },
|
|
275
|
+
|
|
276
|
+
'o4-mini': { inputUsdPer1M: 0.55, outputUsdPer1M: 2.2 },
|
|
277
|
+
'o4-mini-deep-research': { inputUsdPer1M: 1.0, outputUsdPer1M: 4.0 },
|
|
278
|
+
'o3-mini': { inputUsdPer1M: 0.55, outputUsdPer1M: 2.2 },
|
|
279
|
+
'o1-mini': { inputUsdPer1M: 0.55, outputUsdPer1M: 2.2 },
|
|
280
|
+
|
|
281
|
+
'computer-use-preview': { inputUsdPer1M: 1.5, outputUsdPer1M: 6.0 },
|
|
282
|
+
};
|
|
283
|
+
|
|
284
|
+
export const MODEL_API_COST_USD_PER_1M_TOKENS_FLEX: Record<string, ModelApiCost> = {
|
|
285
|
+
'gpt-5.2': { inputUsdPer1M: 0.875, cachedInputUsdPer1M: 0.0875, outputUsdPer1M: 7.0 },
|
|
286
|
+
'gpt-5.1': { inputUsdPer1M: 0.625, cachedInputUsdPer1M: 0.0625, outputUsdPer1M: 5.0 },
|
|
287
|
+
'gpt-5': { inputUsdPer1M: 0.625, cachedInputUsdPer1M: 0.0625, outputUsdPer1M: 5.0 },
|
|
288
|
+
'gpt-5-mini': { inputUsdPer1M: 0.125, cachedInputUsdPer1M: 0.0125, outputUsdPer1M: 1.0 },
|
|
289
|
+
'gpt-5-nano': { inputUsdPer1M: 0.025, cachedInputUsdPer1M: 0.0025, outputUsdPer1M: 0.2 },
|
|
290
|
+
|
|
291
|
+
o3: { inputUsdPer1M: 1.0, cachedInputUsdPer1M: 0.25, outputUsdPer1M: 4.0 },
|
|
292
|
+
'o4-mini': { inputUsdPer1M: 0.55, cachedInputUsdPer1M: 0.138, outputUsdPer1M: 2.2 },
|
|
293
|
+
};
|
|
294
|
+
|
|
295
|
+
export const MODEL_API_COST_USD_PER_1M_TOKENS_PRIORITY: Record<string, ModelApiCost> = {
|
|
296
|
+
'gpt-5.2': { inputUsdPer1M: 3.5, cachedInputUsdPer1M: 0.35, outputUsdPer1M: 28.0 },
|
|
297
|
+
'gpt-5.1': { inputUsdPer1M: 2.5, cachedInputUsdPer1M: 0.25, outputUsdPer1M: 20.0 },
|
|
298
|
+
'gpt-5': { inputUsdPer1M: 2.5, cachedInputUsdPer1M: 0.25, outputUsdPer1M: 20.0 },
|
|
299
|
+
'gpt-5-mini': { inputUsdPer1M: 0.45, cachedInputUsdPer1M: 0.045, outputUsdPer1M: 3.6 },
|
|
300
|
+
|
|
301
|
+
'gpt-5.2-codex': { inputUsdPer1M: 3.5, cachedInputUsdPer1M: 0.35, outputUsdPer1M: 28.0 },
|
|
302
|
+
'gpt-5.1-codex-max': { inputUsdPer1M: 2.5, cachedInputUsdPer1M: 0.25, outputUsdPer1M: 20.0 },
|
|
303
|
+
'gpt-5.1-codex': { inputUsdPer1M: 2.5, cachedInputUsdPer1M: 0.25, outputUsdPer1M: 20.0 },
|
|
304
|
+
'gpt-5-codex': { inputUsdPer1M: 2.5, cachedInputUsdPer1M: 0.25, outputUsdPer1M: 20.0 },
|
|
305
|
+
|
|
306
|
+
'gpt-4.1': { inputUsdPer1M: 3.5, cachedInputUsdPer1M: 0.875, outputUsdPer1M: 14.0 },
|
|
307
|
+
'gpt-4.1-mini': { inputUsdPer1M: 0.7, cachedInputUsdPer1M: 0.175, outputUsdPer1M: 2.8 },
|
|
308
|
+
'gpt-4.1-nano': { inputUsdPer1M: 0.2, cachedInputUsdPer1M: 0.05, outputUsdPer1M: 0.8 },
|
|
309
|
+
|
|
310
|
+
'gpt-4o': { inputUsdPer1M: 4.25, cachedInputUsdPer1M: 2.125, outputUsdPer1M: 17.0 },
|
|
311
|
+
'gpt-4o-2024-05-13': { inputUsdPer1M: 8.75, outputUsdPer1M: 26.25 },
|
|
312
|
+
'gpt-4o-mini': { inputUsdPer1M: 0.25, cachedInputUsdPer1M: 0.125, outputUsdPer1M: 1.0 },
|
|
313
|
+
|
|
314
|
+
o3: { inputUsdPer1M: 3.5, cachedInputUsdPer1M: 0.875, outputUsdPer1M: 14.0 },
|
|
315
|
+
'o4-mini': { inputUsdPer1M: 2.0, cachedInputUsdPer1M: 0.5, outputUsdPer1M: 8.0 },
|
|
316
|
+
};
|
|
317
|
+
|
|
318
|
+
const TOKENS_PER_1M = 1_000_000;
|
|
319
|
+
|
|
320
|
+
const normalizeModelIdForPricing = (model: string): string => {
|
|
321
|
+
const raw = String(model ?? '').trim();
|
|
322
|
+
if (!raw) {
|
|
323
|
+
return '';
|
|
324
|
+
}
|
|
325
|
+
|
|
326
|
+
// handle e.g. "openai:gpt-4o" or "openai/gpt-4o"
|
|
327
|
+
const afterColon = raw.includes(':') ? raw.split(':').pop() ?? raw : raw;
|
|
328
|
+
const afterSlash = afterColon.includes('/') ? afterColon.split('/').pop() ?? afterColon : afterColon;
|
|
329
|
+
return afterSlash;
|
|
330
|
+
};
|
|
331
|
+
|
|
332
|
+
type UsagePricingTier = 'standard' | 'batch' | 'flex' | 'priority';
|
|
333
|
+
|
|
334
|
+
const normalizeServiceTierForPricing = (serviceTier?: string): UsagePricingTier => {
|
|
335
|
+
const v = String(serviceTier ?? '')
|
|
336
|
+
.trim()
|
|
337
|
+
.toLowerCase();
|
|
338
|
+
if (v === 'priority') {
|
|
339
|
+
return 'priority';
|
|
340
|
+
}
|
|
341
|
+
if (v === 'flex') {
|
|
342
|
+
return 'flex';
|
|
343
|
+
}
|
|
344
|
+
if (v === 'batch') {
|
|
345
|
+
return 'batch';
|
|
346
|
+
}
|
|
347
|
+
return 'standard';
|
|
348
|
+
};
|
|
349
|
+
|
|
350
|
+
const resolveModelApiCost = (model: string, tier?: UsagePricingTier): ModelApiCost | undefined => {
|
|
351
|
+
const m = normalizeModelIdForPricing(model);
|
|
352
|
+
if (!m) {
|
|
353
|
+
return undefined;
|
|
354
|
+
}
|
|
355
|
+
|
|
356
|
+
const t: UsagePricingTier = tier ?? 'standard';
|
|
357
|
+
const table =
|
|
358
|
+
t === 'priority'
|
|
359
|
+
? MODEL_API_COST_USD_PER_1M_TOKENS_PRIORITY
|
|
360
|
+
: t === 'flex'
|
|
361
|
+
? MODEL_API_COST_USD_PER_1M_TOKENS_FLEX
|
|
362
|
+
: t === 'batch'
|
|
363
|
+
? MODEL_API_COST_USD_PER_1M_TOKENS_BATCH
|
|
364
|
+
: MODEL_API_COST_USD_PER_1M_TOKENS_STANDARD;
|
|
365
|
+
|
|
366
|
+
const direct = table[m];
|
|
367
|
+
if (direct) {
|
|
368
|
+
return direct;
|
|
369
|
+
}
|
|
370
|
+
|
|
371
|
+
// common suffix normalization (only if the base exists)
|
|
372
|
+
if (m.endsWith('-latest')) {
|
|
373
|
+
const base = m.slice(0, -'-latest'.length);
|
|
374
|
+
const baseCost = table[base];
|
|
375
|
+
if (baseCost) {
|
|
376
|
+
return baseCost;
|
|
377
|
+
}
|
|
378
|
+
}
|
|
379
|
+
|
|
380
|
+
return undefined;
|
|
381
|
+
};
|
|
382
|
+
|
|
383
|
+
export const calculateUsageCostUsd = (
|
|
384
|
+
model: string,
|
|
385
|
+
tokenUsage: TokenUsage,
|
|
386
|
+
opts?: { serviceTier?: string }
|
|
387
|
+
): UsageCostUsd => {
|
|
388
|
+
const tier = normalizeServiceTierForPricing(opts?.serviceTier);
|
|
389
|
+
const pricing = resolveModelApiCost(model, tier);
|
|
390
|
+
if (!pricing) {
|
|
391
|
+
return {
|
|
392
|
+
inputUsd: 0,
|
|
393
|
+
cachedInputUsd: 0,
|
|
394
|
+
reasoningUsd: 0,
|
|
395
|
+
outputUsd: 0,
|
|
396
|
+
totalUsd: 0,
|
|
397
|
+
};
|
|
398
|
+
}
|
|
399
|
+
|
|
400
|
+
const input = Number.isFinite(tokenUsage.inputTokens) ? Number(tokenUsage.inputTokens) : 0;
|
|
401
|
+
const cachedInput = Number.isFinite(tokenUsage.cachedInputTokens) ? Number(tokenUsage.cachedInputTokens) : 0;
|
|
402
|
+
const reasoning = Number.isFinite(tokenUsage.reasoningTokens) ? Number(tokenUsage.reasoningTokens) : 0;
|
|
403
|
+
const output = Number.isFinite(tokenUsage.outputTokens) ? Number(tokenUsage.outputTokens) : 0;
|
|
404
|
+
|
|
405
|
+
const inputTokens = Math.max(0, input);
|
|
406
|
+
const cachedInputTokens = Math.max(0, cachedInput);
|
|
407
|
+
const nonCachedInputTokens = Math.max(0, inputTokens - cachedInputTokens);
|
|
408
|
+
const reasoningTokens = Math.max(0, reasoning);
|
|
409
|
+
const outputTokens = Math.max(0, output);
|
|
410
|
+
|
|
411
|
+
const cachedRate =
|
|
412
|
+
typeof pricing.cachedInputUsdPer1M === 'number' ? pricing.cachedInputUsdPer1M : pricing.inputUsdPer1M;
|
|
413
|
+
|
|
414
|
+
const inputUsd = (nonCachedInputTokens * pricing.inputUsdPer1M + cachedInputTokens * cachedRate) / TOKENS_PER_1M;
|
|
415
|
+
const cachedInputUsd = (cachedInputTokens * cachedRate) / TOKENS_PER_1M;
|
|
416
|
+
const reasoningUsd = (reasoningTokens * pricing.outputUsdPer1M) / TOKENS_PER_1M;
|
|
417
|
+
const outputUsd = (outputTokens * pricing.outputUsdPer1M) / TOKENS_PER_1M;
|
|
418
|
+
const totalUsd = inputUsd + outputUsd;
|
|
419
|
+
|
|
420
|
+
return roundUsageCostUsdToCents({
|
|
421
|
+
inputUsd,
|
|
422
|
+
cachedInputUsd,
|
|
423
|
+
reasoningUsd,
|
|
424
|
+
outputUsd,
|
|
425
|
+
totalUsd,
|
|
426
|
+
});
|
|
427
|
+
};
|
|
428
|
+
|
|
429
|
+
function roundToHundredths(value: number): number {
|
|
430
|
+
return Math.round(value * 100) / 100;
|
|
431
|
+
}
|
|
432
|
+
|
|
433
|
+
function roundUsageCostUsdToCents(cost: UsageCostUsd): UsageCostUsd {
|
|
434
|
+
const inputUsd = roundToHundredths(cost.inputUsd);
|
|
435
|
+
const cachedInputUsd = roundToHundredths(cost.cachedInputUsd);
|
|
436
|
+
const reasoningUsd = roundToHundredths(cost.reasoningUsd);
|
|
437
|
+
const outputUsd = roundToHundredths(cost.outputUsd);
|
|
438
|
+
const totalUsd = roundToHundredths(inputUsd + cachedInputUsd + outputUsd);
|
|
439
|
+
|
|
440
|
+
return {
|
|
441
|
+
inputUsd,
|
|
442
|
+
cachedInputUsd,
|
|
443
|
+
reasoningUsd,
|
|
444
|
+
outputUsd,
|
|
445
|
+
totalUsd,
|
|
446
|
+
};
|
|
447
|
+
}
|
|
@@ -4,6 +4,7 @@ import { searchFilesFunctionName } from '../keyword_to_files_index/KeywordToFile
|
|
|
4
4
|
import { searchLibrariesFunctionName, searchPackagesFunctionName } from '../package/PackageFunctions';
|
|
5
5
|
import { ConversationFsModerator } from './ConversationFsModerator';
|
|
6
6
|
import {
|
|
7
|
+
deleteFilesFunction,
|
|
7
8
|
fsFunctions,
|
|
8
9
|
getRecentlyAccessedFilePathsFunction,
|
|
9
10
|
grepFunction,
|
|
@@ -46,6 +47,7 @@ export class ConversationFsModule implements ConversationModule {
|
|
|
46
47
|
return [
|
|
47
48
|
readFilesFunction(this),
|
|
48
49
|
writeFilesFunction(this),
|
|
50
|
+
deleteFilesFunction(this),
|
|
49
51
|
getRecentlyAccessedFilePathsFunction(this),
|
|
50
52
|
grepFunction(this),
|
|
51
53
|
...fsFunctions,
|
|
@@ -115,6 +115,36 @@ export function writeFilesFunction(fsModule: ConversationFsModule) {
|
|
|
115
115
|
};
|
|
116
116
|
}
|
|
117
117
|
|
|
118
|
+
export const deleteFilesFunctionName = 'deleteFiles';
|
|
119
|
+
export function deleteFilesFunction(fsModule: ConversationFsModule) {
|
|
120
|
+
return {
|
|
121
|
+
definition: {
|
|
122
|
+
name: deleteFilesFunctionName,
|
|
123
|
+
description: 'Delete files from the file system',
|
|
124
|
+
parameters: {
|
|
125
|
+
type: 'object',
|
|
126
|
+
properties: {
|
|
127
|
+
paths: {
|
|
128
|
+
type: 'array',
|
|
129
|
+
description: 'Paths to the files',
|
|
130
|
+
items: { type: 'string' },
|
|
131
|
+
},
|
|
132
|
+
},
|
|
133
|
+
required: ['paths'],
|
|
134
|
+
},
|
|
135
|
+
},
|
|
136
|
+
call: async (params: { paths: string[] }) => {
|
|
137
|
+
try {
|
|
138
|
+
const absPaths = await canonicalizePaths(fsModule, params.paths);
|
|
139
|
+
return await Fs.deleteFiles(absPaths);
|
|
140
|
+
} catch (error: any) {
|
|
141
|
+
return error.message;
|
|
142
|
+
}
|
|
143
|
+
},
|
|
144
|
+
instructions: [`To delete files from the local file system, use the ${deleteFilesFunctionName} function`],
|
|
145
|
+
};
|
|
146
|
+
}
|
|
147
|
+
|
|
118
148
|
export const getRecentlyAccessedFilePathsFunctionName = 'getRecentlyAccessedFilePaths';
|
|
119
149
|
export function getRecentlyAccessedFilePathsFunction(fsModule: ConversationFsModule) {
|
|
120
150
|
return {
|
|
@@ -131,8 +161,8 @@ export function getRecentlyAccessedFilePathsFunction(fsModule: ConversationFsMod
|
|
|
131
161
|
};
|
|
132
162
|
}
|
|
133
163
|
|
|
134
|
-
const createFolderFunctionName = 'createFolder';
|
|
135
|
-
const createFolderFunction: Function = {
|
|
164
|
+
export const createFolderFunctionName = 'createFolder';
|
|
165
|
+
export const createFolderFunction: Function = {
|
|
136
166
|
definition: {
|
|
137
167
|
name: createFolderFunctionName,
|
|
138
168
|
description: 'Create a folder/directory',
|
package/LICENSE
DELETED
|
@@ -1,21 +0,0 @@
|
|
|
1
|
-
MIT License
|
|
2
|
-
|
|
3
|
-
Copyright (c) 2023 Brent Bahry
|
|
4
|
-
|
|
5
|
-
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
-
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
-
in the Software without restriction, including without limitation the rights
|
|
8
|
-
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
-
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
-
furnished to do so, subject to the following conditions:
|
|
11
|
-
|
|
12
|
-
The above copyright notice and this permission notice shall be included in all
|
|
13
|
-
copies or substantial portions of the Software.
|
|
14
|
-
|
|
15
|
-
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
-
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
-
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
-
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
-
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
-
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
-
SOFTWARE.
|