@steve31415/baselib 3.58.1 → 3.59.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/llm/complete.js +1 -0
- package/dist/llm/providers/gemini.js +19 -3
- package/dist/llm/providers/openai.js +19 -3
- package/dist/llm/types.d.ts +33 -9
- package/package.json +1 -1
package/dist/llm/complete.js
CHANGED
|
@@ -155,6 +155,7 @@ export async function llmComplete(request) {
|
|
|
155
155
|
model: modelEntry.apiModelId,
|
|
156
156
|
tokensUsed: result.tokensUsed,
|
|
157
157
|
outputTokens: result.outputTokens,
|
|
158
|
+
reasoningTokens: result.reasoningTokens,
|
|
158
159
|
cacheReadTokens: result.cacheReadTokens,
|
|
159
160
|
cacheCreationTokens: result.cacheCreationTokens,
|
|
160
161
|
finishReason: result.finishReason,
|
|
@@ -151,8 +151,19 @@ export const geminiProvider = {
|
|
|
151
151
|
const data = JSON.parse(responseText);
|
|
152
152
|
const latencyMs = Date.now() - startTime;
|
|
153
153
|
const text = data.candidates?.[0]?.content?.parts?.[0]?.text || '';
|
|
154
|
-
|
|
155
|
-
|
|
154
|
+
// totalTokenCount = promptTokenCount (cached part included) + candidates
|
|
155
|
+
// + thoughts (verified live on 3.6 Flash, 2026-11-07). Google bills
|
|
156
|
+
// thoughts at the output rate and implicit-cache hits at a tenth of the
|
|
157
|
+
// input rate, so thoughts count as output and the cached part is reported
|
|
158
|
+
// apart and kept out of tokensUsed — the contract Anthropic's usage sets
|
|
159
|
+
// (types.ts LLMResponse.tokensUsed).
|
|
160
|
+
const usage = data.usageMetadata;
|
|
161
|
+
const reasoningTokens = usage?.thoughtsTokenCount || undefined;
|
|
162
|
+
const cacheReadTokens = usage?.cachedContentTokenCount || undefined;
|
|
163
|
+
const outputTokens = usage?.candidatesTokenCount === undefined && reasoningTokens === undefined
|
|
164
|
+
? undefined
|
|
165
|
+
: (usage?.candidatesTokenCount ?? 0) + (reasoningTokens ?? 0);
|
|
166
|
+
const tokensUsed = Math.max(0, (usage?.totalTokenCount || 0) - (cacheReadTokens ?? 0));
|
|
156
167
|
const finishReason = data.candidates?.[0]?.finishReason?.toLowerCase() ?? undefined;
|
|
157
168
|
let json;
|
|
158
169
|
if (request.jsonSchema) {
|
|
@@ -164,8 +175,13 @@ export const geminiProvider = {
|
|
|
164
175
|
request.logger?.info('llm.response', {
|
|
165
176
|
provider: 'gemini', model: request.apiModelId,
|
|
166
177
|
status: response.status, latencyMs, tokensUsed, outputTokens, finishReason,
|
|
178
|
+
...(reasoningTokens !== undefined ? { reasoningTokens } : {}),
|
|
179
|
+
...(cacheReadTokens !== undefined ? { cacheReadTokens } : {}),
|
|
167
180
|
...(request.callSite ? { callSite: request.callSite } : {}),
|
|
168
181
|
});
|
|
169
|
-
return {
|
|
182
|
+
return {
|
|
183
|
+
text, json, tokensUsed, outputTokens, reasoningTokens, cacheReadTokens,
|
|
184
|
+
finishReason, finishCategory: classifyFinish(finishReason), latencyMs,
|
|
185
|
+
};
|
|
170
186
|
},
|
|
171
187
|
};
|
|
@@ -181,8 +181,18 @@ export const openaiProvider = {
|
|
|
181
181
|
const data = JSON.parse(responseText);
|
|
182
182
|
const latencyMs = Date.now() - startTime;
|
|
183
183
|
const text = data.choices?.[0]?.message?.content || '';
|
|
184
|
-
|
|
185
|
-
|
|
184
|
+
// prompt_tokens includes cache reads and writes; completion_tokens
|
|
185
|
+
// includes reasoning (verified live on gpt-5.6-luna, 2026-11-07). OpenAI
|
|
186
|
+
// bills cache reads at a tenth and 30-minute cache writes at 1.25x the
|
|
187
|
+
// input rate, so both are reported apart and kept out of tokensUsed —
|
|
188
|
+
// the contract Anthropic's usage sets (types.ts LLMResponse.tokensUsed).
|
|
189
|
+
const usage = data.usage;
|
|
190
|
+
const outputTokens = usage?.completion_tokens ?? undefined;
|
|
191
|
+
const reasoningTokens = usage?.completion_tokens_details?.reasoning_tokens || undefined;
|
|
192
|
+
const cacheReadTokens = usage?.prompt_tokens_details?.cached_tokens || undefined;
|
|
193
|
+
const cacheCreationTokens = usage?.prompt_tokens_details?.cache_write_tokens || undefined;
|
|
194
|
+
const uncachedInput = Math.max(0, (usage?.prompt_tokens || 0) - (cacheReadTokens ?? 0) - (cacheCreationTokens ?? 0));
|
|
195
|
+
const tokensUsed = uncachedInput + (usage?.completion_tokens || 0);
|
|
186
196
|
const finishReason = data.choices?.[0]?.finish_reason ?? undefined;
|
|
187
197
|
let json;
|
|
188
198
|
if (request.jsonSchema) {
|
|
@@ -194,8 +204,14 @@ export const openaiProvider = {
|
|
|
194
204
|
request.logger?.info('llm.response', {
|
|
195
205
|
provider: 'openai', model: request.apiModelId,
|
|
196
206
|
status: response.status, latencyMs, tokensUsed, outputTokens, finishReason,
|
|
207
|
+
...(reasoningTokens !== undefined ? { reasoningTokens } : {}),
|
|
208
|
+
...(cacheReadTokens !== undefined ? { cacheReadTokens } : {}),
|
|
209
|
+
...(cacheCreationTokens !== undefined ? { cacheCreationTokens } : {}),
|
|
197
210
|
...(request.callSite ? { callSite: request.callSite } : {}),
|
|
198
211
|
});
|
|
199
|
-
return {
|
|
212
|
+
return {
|
|
213
|
+
text, json, tokensUsed, outputTokens, reasoningTokens, cacheReadTokens, cacheCreationTokens,
|
|
214
|
+
finishReason, finishCategory: classifyFinish(finishReason), latencyMs,
|
|
215
|
+
};
|
|
200
216
|
},
|
|
201
217
|
};
|
package/dist/llm/types.d.ts
CHANGED
|
@@ -116,18 +116,39 @@ export interface LLMResponse {
|
|
|
116
116
|
provider: ProviderName;
|
|
117
117
|
/** The API model ID that produced this response. */
|
|
118
118
|
model: string;
|
|
119
|
-
/**
|
|
119
|
+
/**
|
|
120
|
+
* Tokens billed at the regular rates: uncached input + output (hidden
|
|
121
|
+
* reasoning included). Prompt-cache reads and writes are NOT in it — they
|
|
122
|
+
* are reported apart, as every provider bills them at their own rate — so
|
|
123
|
+
* total input = tokensUsed − outputTokens + cacheReadTokens +
|
|
124
|
+
* cacheCreationTokens, and uncached input = tokensUsed − outputTokens.
|
|
125
|
+
* The same on all three providers (since 3.59.0; before it, Gemini and
|
|
126
|
+
* OpenAI counted cached input in here and Gemini left thinking out of
|
|
127
|
+
* outputTokens).
|
|
128
|
+
*/
|
|
120
129
|
tokensUsed: number;
|
|
121
|
-
/**
|
|
130
|
+
/**
|
|
131
|
+
* Output tokens, hidden reasoning included (Gemini's thoughts, OpenAI's
|
|
132
|
+
* reasoning tokens, Anthropic's thinking) — all billed at the output rate.
|
|
133
|
+
* Undefined when the provider reports no split.
|
|
134
|
+
*/
|
|
122
135
|
outputTokens?: number;
|
|
123
136
|
/**
|
|
124
|
-
*
|
|
125
|
-
*
|
|
137
|
+
* The hidden-reasoning share of {@link outputTokens}, already included in
|
|
138
|
+
* it — informational, never added to output (Gemini `thoughtsTokenCount`,
|
|
139
|
+
* OpenAI `reasoning_tokens`; Anthropic does not report it). Absent when 0.
|
|
140
|
+
*/
|
|
141
|
+
reasoningTokens?: number;
|
|
142
|
+
/**
|
|
143
|
+
* Prompt-cache tokens read from the cache: Anthropic when `cacheSystemPrompt`
|
|
144
|
+
* is used, Gemini implicit-cache hits, OpenAI automatic caching. Billed at
|
|
145
|
+
* about a tenth of the input rate (gpt-4o: half). Not in tokensUsed.
|
|
126
146
|
*/
|
|
127
147
|
cacheReadTokens?: number;
|
|
128
148
|
/**
|
|
129
|
-
* Prompt-cache tokens written to the cache (Anthropic
|
|
130
|
-
*
|
|
149
|
+
* Prompt-cache tokens written to the cache (Anthropic with
|
|
150
|
+
* `cacheSystemPrompt`; OpenAI's 30-minute writes on the gpt-5.6 family).
|
|
151
|
+
* Billed at 1.25x the input rate. Not in tokensUsed.
|
|
131
152
|
*/
|
|
132
153
|
cacheCreationTokens?: number;
|
|
133
154
|
/**
|
|
@@ -230,12 +251,15 @@ export interface ProviderCallRequest {
|
|
|
230
251
|
export interface ProviderCallResponse {
|
|
231
252
|
text: string;
|
|
232
253
|
json?: unknown;
|
|
254
|
+
/** Uncached input + output; see {@link LLMResponse.tokensUsed}. */
|
|
233
255
|
tokensUsed: number;
|
|
234
|
-
/** Output tokens
|
|
256
|
+
/** Output tokens, reasoning included; see {@link LLMResponse.outputTokens}. */
|
|
235
257
|
outputTokens?: number;
|
|
236
|
-
/**
|
|
258
|
+
/** The reasoning share of outputTokens; see {@link LLMResponse.reasoningTokens}. */
|
|
259
|
+
reasoningTokens?: number;
|
|
260
|
+
/** Prompt-cache read tokens; see {@link LLMResponse.cacheReadTokens}. */
|
|
237
261
|
cacheReadTokens?: number;
|
|
238
|
-
/** Prompt-cache creation tokens
|
|
262
|
+
/** Prompt-cache creation tokens; see {@link LLMResponse.cacheCreationTokens}. */
|
|
239
263
|
cacheCreationTokens?: number;
|
|
240
264
|
/** Normalized finish reason (lowercased common values where known). */
|
|
241
265
|
finishReason?: string;
|
package/package.json
CHANGED