veryfront 0.1.966 → 0.1.967
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/esm/deno.js +1 -1
- package/esm/extensions/ext-llm-anthropic/src/anthropic-stream.d.ts +5 -1
- package/esm/extensions/ext-llm-anthropic/src/anthropic-stream.d.ts.map +1 -1
- package/esm/extensions/ext-llm-anthropic/src/anthropic-stream.js +278 -179
- package/esm/src/eval/model-comparison.d.ts.map +1 -1
- package/esm/src/eval/model-comparison.js +1 -0
- package/esm/src/utils/version-constant.d.ts +1 -1
- package/esm/src/utils/version-constant.js +1 -1
- package/package.json +1 -1
package/esm/deno.js
CHANGED
|
@@ -1,8 +1,12 @@
|
|
|
1
1
|
import type { RuntimeUsage } from "../../../src/provider/shared/index.js";
|
|
2
|
+
type AnthropicStreamOptions = {
|
|
3
|
+
clientToolUseTrailingUsageGraceMs?: number;
|
|
4
|
+
};
|
|
2
5
|
export declare function normalizeAnthropicFinishReason(raw: unknown): string | {
|
|
3
6
|
unified: string;
|
|
4
7
|
raw: string;
|
|
5
8
|
} | null;
|
|
6
9
|
export declare function extractAnthropicUsage(payload: unknown): RuntimeUsage | undefined;
|
|
7
|
-
export declare function streamAnthropicCompatibleParts(stream: ReadableStream<Uint8Array
|
|
10
|
+
export declare function streamAnthropicCompatibleParts(stream: ReadableStream<Uint8Array>, options?: AnthropicStreamOptions): AsyncIterable<unknown>;
|
|
11
|
+
export {};
|
|
8
12
|
//# sourceMappingURL=anthropic-stream.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"anthropic-stream.d.ts","sourceRoot":"","sources":["../../../../src/extensions/ext-llm-anthropic/src/anthropic-stream.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"anthropic-stream.d.ts","sourceRoot":"","sources":["../../../../src/extensions/ext-llm-anthropic/src/anthropic-stream.ts"],"names":[],"mappings":"AAOA,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,uCAAuC,CAAC;AAgB1E,KAAK,sBAAsB,GAAG;IAC5B,iCAAiC,CAAC,EAAE,MAAM,CAAC;CAC5C,CAAC;AAmBF,wBAAgB,8BAA8B,CAC5C,GAAG,EAAE,OAAO,GACX,MAAM,GAAG;IAAE,OAAO,EAAE,MAAM,CAAC;IAAC,GAAG,EAAE,MAAM,CAAA;CAAE,GAAG,IAAI,CAgBlD;AAED,wBAAgB,qBAAqB,CAAC,OAAO,EAAE,OAAO,GAAG,YAAY,GAAG,SAAS,CA6DhF;AAoED,wBAAuB,8BAA8B,CACnD,MAAM,EAAE,cAAc,CAAC,UAAU,CAAC,EAClC,OAAO,GAAE,sBAA2B,GACnC,aAAa,CAAC,OAAO,CAAC,CAoUxB"}
|
|
@@ -1,4 +1,7 @@
|
|
|
1
|
+
import * as dntShim from "../../../_dnt.shims.js";
|
|
1
2
|
import { mergeUsage, parseSseChunk, readRecord, stringifyJsonValue, } from "../../../src/provider/shared/index.js";
|
|
3
|
+
const CLIENT_TOOL_USE_FINISH_REASON = { unified: "tool-calls", raw: "tool_use" };
|
|
4
|
+
const DEFAULT_CLIENT_TOOL_USE_TRAILING_USAGE_GRACE_MS = 100;
|
|
2
5
|
function isEmptyRecord(value) {
|
|
3
6
|
return Boolean(value &&
|
|
4
7
|
typeof value === "object" &&
|
|
@@ -81,231 +84,327 @@ export function extractAnthropicUsage(payload) {
|
|
|
81
84
|
: {}),
|
|
82
85
|
};
|
|
83
86
|
}
|
|
84
|
-
|
|
87
|
+
function isToolCallsFinishReason(finishReason) {
|
|
88
|
+
return finishReason === "tool-calls" ||
|
|
89
|
+
(typeof finishReason === "object" && finishReason?.unified === "tool-calls");
|
|
90
|
+
}
|
|
91
|
+
function hasGatewayUsageMetadata(usage) {
|
|
92
|
+
return usage?.billableInputTokens !== undefined ||
|
|
93
|
+
usage?.billableOutputTokens !== undefined ||
|
|
94
|
+
usage?.providerInputCostUsd !== undefined ||
|
|
95
|
+
usage?.providerOutputCostUsd !== undefined ||
|
|
96
|
+
usage?.providerCostUsd !== undefined ||
|
|
97
|
+
usage?.veryfrontInputChargeUsd !== undefined ||
|
|
98
|
+
usage?.veryfrontOutputChargeUsd !== undefined ||
|
|
99
|
+
usage?.veryfrontChargeUsd !== undefined ||
|
|
100
|
+
usage?.veryfrontBilledUsd !== undefined ||
|
|
101
|
+
usage?.costCredits !== undefined ||
|
|
102
|
+
usage?.costSource !== undefined ||
|
|
103
|
+
usage?.usageCaptureStatus !== undefined;
|
|
104
|
+
}
|
|
105
|
+
async function readStreamChunk(reader, timeoutMs) {
|
|
106
|
+
if (timeoutMs === undefined) {
|
|
107
|
+
const read = await reader.read();
|
|
108
|
+
return read.done ? { kind: "done" } : { kind: "chunk", chunk: read.value };
|
|
109
|
+
}
|
|
110
|
+
let timeoutId;
|
|
111
|
+
const readPromise = reader.read().then((read) => read.done ? { kind: "done" } : { kind: "chunk", chunk: read.value });
|
|
112
|
+
const timeoutPromise = new Promise((resolve) => {
|
|
113
|
+
timeoutId = dntShim.setTimeout(() => resolve({ kind: "timeout" }), Math.max(1, timeoutMs));
|
|
114
|
+
});
|
|
115
|
+
try {
|
|
116
|
+
const result = await Promise.race([readPromise, timeoutPromise]);
|
|
117
|
+
if (result.kind === "timeout") {
|
|
118
|
+
await cancelStreamReader(reader, "Timed out waiting for trailing Anthropic tool-use usage metadata");
|
|
119
|
+
}
|
|
120
|
+
return result;
|
|
121
|
+
}
|
|
122
|
+
finally {
|
|
123
|
+
if (timeoutId) {
|
|
124
|
+
clearTimeout(timeoutId);
|
|
125
|
+
}
|
|
126
|
+
}
|
|
127
|
+
}
|
|
128
|
+
async function cancelStreamReader(reader, reason) {
|
|
129
|
+
try {
|
|
130
|
+
await reader.cancel(reason);
|
|
131
|
+
}
|
|
132
|
+
catch {
|
|
133
|
+
// The upstream body may already be closed or canceled by the runtime.
|
|
134
|
+
}
|
|
135
|
+
}
|
|
136
|
+
export async function* streamAnthropicCompatibleParts(stream, options = {}) {
|
|
85
137
|
const decoder = new TextDecoder();
|
|
138
|
+
const reader = stream.getReader();
|
|
139
|
+
const trailingUsageGraceMs = options.clientToolUseTrailingUsageGraceMs ??
|
|
140
|
+
DEFAULT_CLIENT_TOOL_USE_TRAILING_USAGE_GRACE_MS;
|
|
86
141
|
let buffer = "";
|
|
87
142
|
const toolCalls = new Map();
|
|
88
143
|
const reasoningBlocks = new Map();
|
|
89
144
|
let finishReason = null;
|
|
90
145
|
let usage;
|
|
91
146
|
let completedClientToolUseStep = false;
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
147
|
+
let clientToolUseIdleDeadlineMs = null;
|
|
148
|
+
let clientToolUseTerminalDeadlineMs = null;
|
|
149
|
+
const mergeTrailingBufferUsage = () => {
|
|
150
|
+
if (buffer.trim().length === 0) {
|
|
151
|
+
return;
|
|
152
|
+
}
|
|
153
|
+
const parsed = parseSseChunk(`${buffer}\n\n`);
|
|
95
154
|
buffer = parsed.remainder;
|
|
96
155
|
for (const event of parsed.events) {
|
|
97
156
|
if (event === "[DONE]") {
|
|
98
157
|
continue;
|
|
99
158
|
}
|
|
100
159
|
const record = readRecord(event);
|
|
101
|
-
const eventType = typeof record?.type === "string" ? record.type : undefined;
|
|
102
160
|
usage = mergeUsage(usage, extractAnthropicUsage(record));
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
161
|
+
}
|
|
162
|
+
};
|
|
163
|
+
const getClientToolUseReadTimeoutMs = () => {
|
|
164
|
+
if (!completedClientToolUseStep || toolCalls.size > 0) {
|
|
165
|
+
return undefined;
|
|
166
|
+
}
|
|
167
|
+
const deadline = isToolCallsFinishReason(finishReason)
|
|
168
|
+
? clientToolUseTerminalDeadlineMs
|
|
169
|
+
: clientToolUseIdleDeadlineMs;
|
|
170
|
+
return deadline === null ? undefined : Math.max(1, deadline - Date.now());
|
|
171
|
+
};
|
|
172
|
+
const buildFinishPart = () => ({
|
|
173
|
+
type: "finish",
|
|
174
|
+
finishReason: finishReason ??
|
|
175
|
+
(completedClientToolUseStep ? CLIENT_TOOL_USE_FINISH_REASON : null),
|
|
176
|
+
...(usage ? { usage } : {}),
|
|
177
|
+
});
|
|
178
|
+
try {
|
|
179
|
+
while (true) {
|
|
180
|
+
const read = await readStreamChunk(reader, getClientToolUseReadTimeoutMs());
|
|
181
|
+
if (read.kind === "timeout") {
|
|
182
|
+
mergeTrailingBufferUsage();
|
|
183
|
+
finishReason ??= CLIENT_TOOL_USE_FINISH_REASON;
|
|
184
|
+
yield buildFinishPart();
|
|
185
|
+
return;
|
|
186
|
+
}
|
|
187
|
+
if (read.kind === "done") {
|
|
188
|
+
break;
|
|
106
189
|
}
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
if (
|
|
112
|
-
contentBlock.text.length > 0) {
|
|
113
|
-
yield { type: "text-delta", delta: contentBlock.text };
|
|
190
|
+
buffer += decoder.decode(read.chunk, { stream: true });
|
|
191
|
+
const parsed = parseSseChunk(buffer);
|
|
192
|
+
buffer = parsed.remainder;
|
|
193
|
+
for (const event of parsed.events) {
|
|
194
|
+
if (event === "[DONE]") {
|
|
114
195
|
continue;
|
|
115
196
|
}
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
197
|
+
const record = readRecord(event);
|
|
198
|
+
const eventType = typeof record?.type === "string" ? record.type : undefined;
|
|
199
|
+
usage = mergeUsage(usage, extractAnthropicUsage(record));
|
|
200
|
+
if (eventType === "message_start") {
|
|
201
|
+
usage = mergeUsage(usage, extractAnthropicUsage(record?.message));
|
|
202
|
+
continue;
|
|
203
|
+
}
|
|
204
|
+
if (eventType === "content_block_start") {
|
|
205
|
+
const index = typeof record?.index === "number" ? record.index : 0;
|
|
206
|
+
const contentBlock = readRecord(record?.content_block);
|
|
207
|
+
const blockType = typeof contentBlock?.type === "string" ? contentBlock.type : undefined;
|
|
208
|
+
if (blockType === "text" && typeof contentBlock?.text === "string" &&
|
|
209
|
+
contentBlock.text.length > 0) {
|
|
210
|
+
yield { type: "text-delta", delta: contentBlock.text };
|
|
211
|
+
continue;
|
|
212
|
+
}
|
|
213
|
+
if (blockType === "thinking") {
|
|
214
|
+
const reasoningId = `thinking-${index}`;
|
|
215
|
+
reasoningBlocks.set(index, { id: reasoningId, text: "" });
|
|
216
|
+
yield {
|
|
217
|
+
type: "reasoning-start",
|
|
218
|
+
id: reasoningId,
|
|
219
|
+
};
|
|
220
|
+
if (typeof contentBlock?.thinking === "string" && contentBlock.thinking.length > 0) {
|
|
221
|
+
const current = reasoningBlocks.get(index);
|
|
222
|
+
if (current) {
|
|
223
|
+
current.text += contentBlock.thinking;
|
|
224
|
+
}
|
|
225
|
+
yield {
|
|
226
|
+
type: "reasoning-delta",
|
|
227
|
+
id: reasoningId,
|
|
228
|
+
delta: contentBlock.thinking,
|
|
229
|
+
};
|
|
127
230
|
}
|
|
231
|
+
continue;
|
|
232
|
+
}
|
|
233
|
+
// Redacted thinking blocks arrive as opaque encrypted payloads when
|
|
234
|
+
// Claude's safety classifier flags the reasoning trace. Surface them
|
|
235
|
+
// as a zero-length reasoning block so callers know thinking happened
|
|
236
|
+
// without leaking the (legitimately hidden) contents.
|
|
237
|
+
if (blockType === "redacted_thinking") {
|
|
238
|
+
const reasoningId = `thinking-${index}`;
|
|
239
|
+
reasoningBlocks.set(index, {
|
|
240
|
+
id: reasoningId,
|
|
241
|
+
text: "",
|
|
242
|
+
...(typeof contentBlock?.data === "string"
|
|
243
|
+
? { redactedData: contentBlock.data }
|
|
244
|
+
: {}),
|
|
245
|
+
});
|
|
128
246
|
yield {
|
|
129
|
-
type: "reasoning-
|
|
247
|
+
type: "reasoning-start",
|
|
130
248
|
id: reasoningId,
|
|
131
|
-
delta: contentBlock.thinking,
|
|
132
249
|
};
|
|
250
|
+
continue;
|
|
133
251
|
}
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
yield {
|
|
148
|
-
type: "reasoning-start",
|
|
149
|
-
id: reasoningId,
|
|
150
|
-
};
|
|
151
|
-
continue;
|
|
152
|
-
}
|
|
153
|
-
if ((blockType === "tool_use" || blockType === "server_tool_use") &&
|
|
154
|
-
typeof contentBlock?.id === "string" &&
|
|
155
|
-
typeof contentBlock?.name === "string") {
|
|
156
|
-
const providerExecuted = blockType === "server_tool_use" ? true : undefined;
|
|
157
|
-
const current = {
|
|
158
|
-
id: contentBlock.id,
|
|
159
|
-
name: contentBlock.name,
|
|
160
|
-
input: "",
|
|
161
|
-
...(providerExecuted ? { providerExecuted } : {}),
|
|
162
|
-
};
|
|
163
|
-
toolCalls.set(index, current);
|
|
164
|
-
yield {
|
|
165
|
-
type: "tool-input-start",
|
|
166
|
-
id: current.id,
|
|
167
|
-
toolName: current.name,
|
|
168
|
-
...(providerExecuted ? { providerExecuted } : {}),
|
|
169
|
-
};
|
|
170
|
-
const initialInput = contentBlock.input;
|
|
171
|
-
if (initialInput !== undefined && !isEmptyRecord(initialInput)) {
|
|
172
|
-
const serializedInput = stringifyJsonValue(initialInput);
|
|
173
|
-
current.input += serializedInput;
|
|
252
|
+
if ((blockType === "tool_use" || blockType === "server_tool_use") &&
|
|
253
|
+
typeof contentBlock?.id === "string" &&
|
|
254
|
+
typeof contentBlock?.name === "string") {
|
|
255
|
+
const providerExecuted = blockType === "server_tool_use" ? true : undefined;
|
|
256
|
+
const current = {
|
|
257
|
+
id: contentBlock.id,
|
|
258
|
+
name: contentBlock.name,
|
|
259
|
+
input: "",
|
|
260
|
+
...(providerExecuted ? { providerExecuted } : {}),
|
|
261
|
+
};
|
|
262
|
+
toolCalls.set(index, current);
|
|
263
|
+
clientToolUseIdleDeadlineMs = null;
|
|
264
|
+
clientToolUseTerminalDeadlineMs = null;
|
|
174
265
|
yield {
|
|
175
|
-
type: "tool-input-
|
|
266
|
+
type: "tool-input-start",
|
|
176
267
|
id: current.id,
|
|
177
|
-
|
|
268
|
+
toolName: current.name,
|
|
269
|
+
...(providerExecuted ? { providerExecuted } : {}),
|
|
270
|
+
};
|
|
271
|
+
const initialInput = contentBlock.input;
|
|
272
|
+
if (initialInput !== undefined && !isEmptyRecord(initialInput)) {
|
|
273
|
+
const serializedInput = stringifyJsonValue(initialInput);
|
|
274
|
+
current.input += serializedInput;
|
|
275
|
+
yield {
|
|
276
|
+
type: "tool-input-delta",
|
|
277
|
+
id: current.id,
|
|
278
|
+
delta: serializedInput,
|
|
279
|
+
};
|
|
280
|
+
}
|
|
281
|
+
continue;
|
|
282
|
+
}
|
|
283
|
+
if (blockType === "web_search_tool_result" &&
|
|
284
|
+
typeof contentBlock?.tool_use_id === "string" &&
|
|
285
|
+
Array.isArray(contentBlock?.content)) {
|
|
286
|
+
yield {
|
|
287
|
+
type: "tool-result",
|
|
288
|
+
toolCallId: contentBlock.tool_use_id,
|
|
289
|
+
toolName: "web_search",
|
|
290
|
+
result: contentBlock.content,
|
|
291
|
+
providerExecuted: true,
|
|
292
|
+
};
|
|
293
|
+
}
|
|
294
|
+
if (blockType === "web_fetch_tool_result" &&
|
|
295
|
+
typeof contentBlock?.tool_use_id === "string" &&
|
|
296
|
+
readRecord(contentBlock?.content)) {
|
|
297
|
+
yield {
|
|
298
|
+
type: "tool-result",
|
|
299
|
+
toolCallId: contentBlock.tool_use_id,
|
|
300
|
+
toolName: "web_fetch",
|
|
301
|
+
result: contentBlock.content,
|
|
302
|
+
providerExecuted: true,
|
|
178
303
|
};
|
|
179
304
|
}
|
|
180
305
|
continue;
|
|
181
306
|
}
|
|
182
|
-
if (
|
|
183
|
-
typeof
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
toolName: "web_search",
|
|
189
|
-
result: contentBlock.content,
|
|
190
|
-
providerExecuted: true,
|
|
191
|
-
};
|
|
192
|
-
}
|
|
193
|
-
if (blockType === "web_fetch_tool_result" &&
|
|
194
|
-
typeof contentBlock?.tool_use_id === "string" &&
|
|
195
|
-
readRecord(contentBlock?.content)) {
|
|
196
|
-
yield {
|
|
197
|
-
type: "tool-result",
|
|
198
|
-
toolCallId: contentBlock.tool_use_id,
|
|
199
|
-
toolName: "web_fetch",
|
|
200
|
-
result: contentBlock.content,
|
|
201
|
-
providerExecuted: true,
|
|
202
|
-
};
|
|
203
|
-
}
|
|
204
|
-
continue;
|
|
205
|
-
}
|
|
206
|
-
if (eventType === "content_block_delta") {
|
|
207
|
-
const index = typeof record?.index === "number" ? record.index : 0;
|
|
208
|
-
const delta = readRecord(record?.delta);
|
|
209
|
-
const deltaType = typeof delta?.type === "string" ? delta.type : undefined;
|
|
210
|
-
if (deltaType === "text_delta" && typeof delta?.text === "string" && delta.text.length > 0) {
|
|
211
|
-
yield { type: "text-delta", delta: delta.text };
|
|
212
|
-
continue;
|
|
213
|
-
}
|
|
214
|
-
if (deltaType === "thinking_delta" && typeof delta?.thinking === "string" &&
|
|
215
|
-
delta.thinking.length > 0) {
|
|
216
|
-
const current = reasoningBlocks.get(index);
|
|
217
|
-
if (!current) {
|
|
307
|
+
if (eventType === "content_block_delta") {
|
|
308
|
+
const index = typeof record?.index === "number" ? record.index : 0;
|
|
309
|
+
const delta = readRecord(record?.delta);
|
|
310
|
+
const deltaType = typeof delta?.type === "string" ? delta.type : undefined;
|
|
311
|
+
if (deltaType === "text_delta" && typeof delta?.text === "string" && delta.text.length > 0) {
|
|
312
|
+
yield { type: "text-delta", delta: delta.text };
|
|
218
313
|
continue;
|
|
219
314
|
}
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
315
|
+
if (deltaType === "thinking_delta" && typeof delta?.thinking === "string" &&
|
|
316
|
+
delta.thinking.length > 0) {
|
|
317
|
+
const current = reasoningBlocks.get(index);
|
|
318
|
+
if (!current) {
|
|
319
|
+
continue;
|
|
320
|
+
}
|
|
321
|
+
current.text += delta.thinking;
|
|
322
|
+
yield {
|
|
323
|
+
type: "reasoning-delta",
|
|
324
|
+
id: current.id,
|
|
325
|
+
delta: delta.thinking,
|
|
326
|
+
};
|
|
327
|
+
continue;
|
|
328
|
+
}
|
|
329
|
+
if (deltaType === "signature_delta" && typeof delta?.signature === "string") {
|
|
330
|
+
const current = reasoningBlocks.get(index);
|
|
331
|
+
if (current) {
|
|
332
|
+
current.signature = delta.signature;
|
|
333
|
+
}
|
|
334
|
+
continue;
|
|
335
|
+
}
|
|
336
|
+
if (deltaType === "input_json_delta" && typeof delta?.partial_json === "string") {
|
|
337
|
+
const current = toolCalls.get(index);
|
|
338
|
+
if (!current) {
|
|
339
|
+
continue;
|
|
340
|
+
}
|
|
341
|
+
current.input += delta.partial_json;
|
|
342
|
+
yield {
|
|
343
|
+
type: "tool-input-delta",
|
|
344
|
+
id: current.id,
|
|
345
|
+
delta: delta.partial_json,
|
|
346
|
+
};
|
|
232
347
|
}
|
|
233
348
|
continue;
|
|
234
349
|
}
|
|
235
|
-
if (
|
|
350
|
+
if (eventType === "content_block_stop") {
|
|
351
|
+
const index = typeof record?.index === "number" ? record.index : 0;
|
|
352
|
+
const reasoning = reasoningBlocks.get(index);
|
|
353
|
+
if (reasoning) {
|
|
354
|
+
yield {
|
|
355
|
+
type: "reasoning-end",
|
|
356
|
+
id: reasoning.id,
|
|
357
|
+
...(reasoning.signature ? { signature: reasoning.signature } : {}),
|
|
358
|
+
...(reasoning.redactedData ? { redactedData: reasoning.redactedData } : {}),
|
|
359
|
+
};
|
|
360
|
+
reasoningBlocks.delete(index);
|
|
361
|
+
continue;
|
|
362
|
+
}
|
|
236
363
|
const current = toolCalls.get(index);
|
|
237
364
|
if (!current) {
|
|
238
365
|
continue;
|
|
239
366
|
}
|
|
240
|
-
current.input += delta.partial_json;
|
|
241
367
|
yield {
|
|
242
|
-
type: "tool-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
continue;
|
|
248
|
-
}
|
|
249
|
-
if (eventType === "content_block_stop") {
|
|
250
|
-
const index = typeof record?.index === "number" ? record.index : 0;
|
|
251
|
-
const reasoning = reasoningBlocks.get(index);
|
|
252
|
-
if (reasoning) {
|
|
253
|
-
yield {
|
|
254
|
-
type: "reasoning-end",
|
|
255
|
-
id: reasoning.id,
|
|
256
|
-
...(reasoning.signature ? { signature: reasoning.signature } : {}),
|
|
257
|
-
...(reasoning.redactedData ? { redactedData: reasoning.redactedData } : {}),
|
|
368
|
+
type: "tool-call",
|
|
369
|
+
toolCallId: current.id,
|
|
370
|
+
toolName: current.name,
|
|
371
|
+
input: current.input.length > 0 ? current.input : "{}",
|
|
372
|
+
...(current.providerExecuted ? { providerExecuted: true } : {}),
|
|
258
373
|
};
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
374
|
+
if (!current.providerExecuted) {
|
|
375
|
+
completedClientToolUseStep = true;
|
|
376
|
+
clientToolUseIdleDeadlineMs = null;
|
|
377
|
+
}
|
|
378
|
+
toolCalls.delete(index);
|
|
264
379
|
continue;
|
|
265
380
|
}
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
};
|
|
273
|
-
if (!current.providerExecuted) {
|
|
274
|
-
completedClientToolUseStep = true;
|
|
381
|
+
if (eventType === "message_delta") {
|
|
382
|
+
const delta = readRecord(record?.delta);
|
|
383
|
+
const normalizedFinishReason = normalizeAnthropicFinishReason(delta?.stop_reason);
|
|
384
|
+
if (normalizedFinishReason) {
|
|
385
|
+
finishReason = normalizedFinishReason;
|
|
386
|
+
}
|
|
275
387
|
}
|
|
276
|
-
toolCalls.delete(index);
|
|
277
|
-
continue;
|
|
278
388
|
}
|
|
279
|
-
if (
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
389
|
+
if (completedClientToolUseStep && toolCalls.size === 0) {
|
|
390
|
+
if (isToolCallsFinishReason(finishReason)) {
|
|
391
|
+
clientToolUseIdleDeadlineMs = null;
|
|
392
|
+
clientToolUseTerminalDeadlineMs ??= Date.now() + trailingUsageGraceMs;
|
|
393
|
+
if (hasGatewayUsageMetadata(usage)) {
|
|
394
|
+
await cancelStreamReader(reader, "Finished Anthropic tool-use turn after gateway usage metadata");
|
|
395
|
+
yield buildFinishPart();
|
|
396
|
+
return;
|
|
397
|
+
}
|
|
398
|
+
}
|
|
399
|
+
else {
|
|
400
|
+
clientToolUseIdleDeadlineMs ??= Date.now() + trailingUsageGraceMs;
|
|
284
401
|
}
|
|
285
402
|
}
|
|
286
403
|
}
|
|
287
|
-
if (completedClientToolUseStep && toolCalls.size === 0) {
|
|
288
|
-
yield {
|
|
289
|
-
type: "finish",
|
|
290
|
-
finishReason: { unified: "tool-calls", raw: "tool_use" },
|
|
291
|
-
...(usage ? { usage } : {}),
|
|
292
|
-
};
|
|
293
|
-
return;
|
|
294
|
-
}
|
|
295
404
|
}
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
for (const event of parsed.events) {
|
|
299
|
-
if (event === "[DONE]") {
|
|
300
|
-
continue;
|
|
301
|
-
}
|
|
302
|
-
const record = readRecord(event);
|
|
303
|
-
usage = mergeUsage(usage, extractAnthropicUsage(record));
|
|
304
|
-
}
|
|
405
|
+
finally {
|
|
406
|
+
reader.releaseLock();
|
|
305
407
|
}
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
finishReason,
|
|
309
|
-
...(usage ? { usage } : {}),
|
|
310
|
-
};
|
|
408
|
+
mergeTrailingBufferUsage();
|
|
409
|
+
yield buildFinishPart();
|
|
311
410
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"model-comparison.d.ts","sourceRoot":"","sources":["../../../src/src/eval/model-comparison.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAGV,mBAAmB,EAEnB,0BAA0B,EAE1B,UAAU,EACX,MAAM,YAAY,CAAC;AAgkBpB,oFAAoF;AACpF,wBAAgB,uBAAuB,CACrC,OAAO,EAAE,UAAU,EAAE,EACrB,OAAO,EAAE,0BAA0B,GAClC,mBAAmB,CAqBrB;AA0BD,gFAAgF;AAChF,wBAAgB,iCAAiC,CAAC,UAAU,EAAE,mBAAmB,GAAG,MAAM,
|
|
1
|
+
{"version":3,"file":"model-comparison.d.ts","sourceRoot":"","sources":["../../../src/src/eval/model-comparison.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAGV,mBAAmB,EAEnB,0BAA0B,EAE1B,UAAU,EACX,MAAM,YAAY,CAAC;AAgkBpB,oFAAoF;AACpF,wBAAgB,uBAAuB,CACrC,OAAO,EAAE,UAAU,EAAE,EACrB,OAAO,EAAE,0BAA0B,GAClC,mBAAmB,CAqBrB;AA0BD,gFAAgF;AAChF,wBAAgB,iCAAiC,CAAC,UAAU,EAAE,mBAAmB,GAAG,MAAM,CAmEzF"}
|
|
@@ -499,6 +499,7 @@ export function createEvalModelComparisonMarkdown(comparison) {
|
|
|
499
499
|
for (const model of comparison.models) {
|
|
500
500
|
lines.push(`| ${model.model} | ${model.role} | ${model.passed} | ${model.failed} | ${Math.round(model.passRate * 100)}% | ${decimalCell(model.groundednessScore)} | ${numberCell(model.inputTokens)} | ${numberCell(model.outputTokens)} | ${numberCell(model.totalTokens)} | ${numberCell(model.billableInputTokens)} | ${numberCell(model.billableOutputTokens)} | ${costCell(model.providerInputCostUsd, model.costSource)} | ${costCell(model.providerOutputCostUsd, model.costSource)} | ${costCell(model.providerCostUsd ?? model.costUsd, model.costSource)} | ${costCell(model.veryfrontInputChargeUsd, model.costSource)} | ${costCell(model.veryfrontOutputChargeUsd, model.costSource)} | ${costCell(model.veryfrontChargeUsd, model.costSource)} | ${costCell(model.veryfrontBilledUsd, model.costSource)} | ${decimalCell(model.costCredits)} | ${model.costSource ?? "-"} | ${numberCell(model.p95Ms)} |`);
|
|
501
501
|
}
|
|
502
|
+
lines.push("", "_Metered USD is the token-metered Veryfront charge before billing minimums. Billed USD and Credits include gateway request minimums and match the billed eval cost._");
|
|
502
503
|
if (comparison.candidates.length > 0) {
|
|
503
504
|
lines.push("", "## Candidates", "", "| Model | Decision | Objective score | Constraint failures |", "| --- | --- | ---: | --- |");
|
|
504
505
|
for (const candidate of comparison.candidates) {
|