@qwen-code/arena-agent 0.0.9-dev.29 → 0.0.9-dev.30

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.
@@ -0,0 +1,399 @@
1
+ function record(value) {
2
+ return value !== null && typeof value === "object" && !Array.isArray(value)
3
+ ? value
4
+ : {};
5
+ }
6
+ function stringValue(value) {
7
+ return typeof value === "string" ? value : "";
8
+ }
9
+ function responsesUserContent(content) {
10
+ if (!Array.isArray(content))
11
+ return content;
12
+ return content.map((part) => {
13
+ const value = record(part);
14
+ if (typeof value.image === "string") {
15
+ return {
16
+ type: "input_image",
17
+ image_url: value.image,
18
+ detail: "auto",
19
+ };
20
+ }
21
+ if (value.type === "image_url") {
22
+ const imageUrl = record(value.image_url);
23
+ return {
24
+ type: "input_image",
25
+ image_url: stringValue(imageUrl.url),
26
+ detail: stringValue(imageUrl.detail) || "auto",
27
+ };
28
+ }
29
+ return { type: "input_text", text: stringValue(value.text) };
30
+ });
31
+ }
32
+ /** Convert Arena's durable history into Responses API input items. */
33
+ export function responsesInput(messages) {
34
+ const input = [];
35
+ for (const message of messages) {
36
+ if (message.role === "system" || message.role === "user") {
37
+ input.push({
38
+ role: message.role,
39
+ content: responsesUserContent(message.content),
40
+ });
41
+ continue;
42
+ }
43
+ if (message.role === "tool") {
44
+ input.push({
45
+ type: "function_call_output",
46
+ call_id: message.tool_call_id,
47
+ output: message.content,
48
+ });
49
+ continue;
50
+ }
51
+ if (message.openai_response_items?.length) {
52
+ input.push(...structuredClone(message.openai_response_items));
53
+ continue;
54
+ }
55
+ // Compatibility fallback for histories created before Arena persisted
56
+ // native Responses output items.
57
+ if (message.content) {
58
+ input.push({ role: "assistant", content: message.content });
59
+ }
60
+ for (const call of message.tool_calls || []) {
61
+ input.push({
62
+ type: "function_call",
63
+ call_id: call.id,
64
+ name: call.function.name,
65
+ arguments: call.function.arguments,
66
+ });
67
+ }
68
+ }
69
+ return input;
70
+ }
71
+ function responsesTools(tools) {
72
+ return tools.map((tool) => ({
73
+ type: "function",
74
+ name: tool.function.name,
75
+ ...(tool.function.description
76
+ ? { description: tool.function.description }
77
+ : {}),
78
+ parameters: tool.function.parameters,
79
+ }));
80
+ }
81
+ /** Build a native OpenAI Responses request without Chat Completions fields. */
82
+ export function responsesRequestBody(request, model) {
83
+ const allTurnsReasoning = model.toLowerCase().includes("gpt-5.6");
84
+ const reasoning = request.reasoningEffort || allTurnsReasoning
85
+ ? {
86
+ ...(request.reasoningEffort
87
+ ? { effort: request.reasoningEffort }
88
+ : {}),
89
+ ...(allTurnsReasoning ? { context: "all_turns" } : {}),
90
+ }
91
+ : undefined;
92
+ return {
93
+ model,
94
+ input: responsesInput(request.messages),
95
+ ...(request.tools.length
96
+ ? { tools: responsesTools(request.tools), tool_choice: request.toolChoice }
97
+ : {}),
98
+ ...(request.maxTokens !== undefined
99
+ ? { max_output_tokens: request.maxTokens }
100
+ : {}),
101
+ // Do not inherit Arena's generic temperature on the native Responses path:
102
+ // reasoning models reject sampling controls. Non-reasoning models can opt
103
+ // in explicitly through ARENA_EXTRA_BODY, which is merged by the client.
104
+ ...(reasoning ? { reasoning } : {}),
105
+ stream: true,
106
+ // Keep the transport stateless. Completed output items, including opaque
107
+ // encrypted reasoning, are persisted by Arena and replayed in input.
108
+ store: false,
109
+ include: ["reasoning.encrypted_content"],
110
+ };
111
+ }
112
+ function responsesUsage(value) {
113
+ const usage = record(value);
114
+ if (!Object.keys(usage).length)
115
+ return undefined;
116
+ const inputTokens = usage.input_tokens;
117
+ const outputTokens = usage.output_tokens;
118
+ const totalTokens = usage.total_tokens;
119
+ return {
120
+ ...usage,
121
+ ...(typeof inputTokens === "number" ? { prompt_tokens: inputTokens } : {}),
122
+ ...(typeof outputTokens === "number"
123
+ ? { completion_tokens: outputTokens }
124
+ : {}),
125
+ ...(typeof totalTokens === "number" ? { total_tokens: totalTokens } : {}),
126
+ };
127
+ }
128
+ function responsesError(event) {
129
+ const error = record(event.error);
130
+ const response = record(event.response);
131
+ const responseError = record(response.error);
132
+ const message = stringValue(error.message) ||
133
+ stringValue(responseError.message) ||
134
+ stringValue(event.message) ||
135
+ `OpenAI Responses stream failed (${stringValue(event.type) || "unknown event"})`;
136
+ return new Error(message);
137
+ }
138
+ function toolIndex(event, fallback) {
139
+ return typeof event.output_index === "number" ? event.output_index : fallback;
140
+ }
141
+ function toolDelta(state, values) {
142
+ return {
143
+ choices: [
144
+ {
145
+ delta: {
146
+ tool_calls: [
147
+ {
148
+ index: state.index,
149
+ ...(values.id ? { id: values.id, type: "function" } : {}),
150
+ function: {
151
+ ...(values.name ? { name: values.name } : {}),
152
+ ...(values.arguments !== undefined
153
+ ? { arguments: values.arguments }
154
+ : {}),
155
+ },
156
+ },
157
+ ],
158
+ },
159
+ },
160
+ ],
161
+ };
162
+ }
163
+ /** Translate native Responses SSE events into Arena's provider-neutral chunks. */
164
+ export async function* responsesChunks(stream) {
165
+ const reader = stream.getReader();
166
+ const decoder = new TextDecoder();
167
+ const tools = new Map();
168
+ const completedItemIndexes = new Set();
169
+ let buffer = "";
170
+ const captureOutputItem = function* (index, item, replace = false) {
171
+ if (!Object.keys(item).length ||
172
+ (!replace && completedItemIndexes.has(index))) {
173
+ return;
174
+ }
175
+ completedItemIndexes.add(index);
176
+ yield {
177
+ openai_response_items: [{ index, item: structuredClone(item) }],
178
+ };
179
+ };
180
+ const processEvent = function* (event) {
181
+ const type = stringValue(event.type);
182
+ const response = record(event.response);
183
+ if (type === "error" || type === "response.failed") {
184
+ throw responsesError(event);
185
+ }
186
+ if (type === "response.created" || type === "response.in_progress") {
187
+ return;
188
+ }
189
+ if (type === "response.output_text.delta" || type === "response.refusal.delta") {
190
+ yield {
191
+ choices: [{ delta: { content: stringValue(event.delta) } }],
192
+ };
193
+ return;
194
+ }
195
+ if (type === "response.reasoning_summary_text.delta" ||
196
+ type === "response.reasoning_text.delta") {
197
+ yield {
198
+ choices: [{ delta: { reasoning_content: stringValue(event.delta) } }],
199
+ };
200
+ return;
201
+ }
202
+ if (type === "response.output_item.added") {
203
+ const item = record(event.item);
204
+ if (item.type !== "function_call")
205
+ return;
206
+ const index = toolIndex(event, tools.size);
207
+ const state = {
208
+ index,
209
+ id: stringValue(item.call_id),
210
+ name: stringValue(item.name),
211
+ arguments: stringValue(item.arguments),
212
+ headerEmitted: true,
213
+ };
214
+ tools.set(index, state);
215
+ yield {
216
+ ...toolDelta(state, {
217
+ id: state.id,
218
+ name: state.name,
219
+ ...(state.arguments ? { arguments: state.arguments } : {}),
220
+ }),
221
+ };
222
+ return;
223
+ }
224
+ if (type === "response.function_call_arguments.delta") {
225
+ const index = toolIndex(event, tools.size);
226
+ const state = tools.get(index) || {
227
+ index,
228
+ id: "",
229
+ name: "",
230
+ arguments: "",
231
+ headerEmitted: false,
232
+ };
233
+ const delta = stringValue(event.delta);
234
+ state.arguments += delta;
235
+ tools.set(index, state);
236
+ yield {
237
+ ...toolDelta(state, { arguments: delta }),
238
+ };
239
+ return;
240
+ }
241
+ if (type === "response.function_call_arguments.done" ||
242
+ type === "response.output_item.done") {
243
+ const item = record(event.item);
244
+ const index = toolIndex(event, tools.size);
245
+ if (type === "response.output_item.done") {
246
+ yield* captureOutputItem(index, item);
247
+ }
248
+ if (type === "response.output_item.done" && item.type !== "function_call") {
249
+ return;
250
+ }
251
+ const state = tools.get(index) || {
252
+ index,
253
+ id: "",
254
+ name: "",
255
+ arguments: "",
256
+ headerEmitted: false,
257
+ };
258
+ const id = stringValue(item.call_id) || state.id;
259
+ const name = stringValue(item.name) || state.name;
260
+ const completeArguments = stringValue(event.arguments) || stringValue(item.arguments);
261
+ const suffix = completeArguments.startsWith(state.arguments)
262
+ ? completeArguments.slice(state.arguments.length)
263
+ : state.arguments
264
+ ? ""
265
+ : completeArguments;
266
+ if (!state.headerEmitted || suffix) {
267
+ yield {
268
+ ...toolDelta(state, {
269
+ ...(!state.headerEmitted && id ? { id } : {}),
270
+ ...(!state.headerEmitted && name ? { name } : {}),
271
+ ...(suffix ? { arguments: suffix } : {}),
272
+ }),
273
+ };
274
+ }
275
+ state.id = id;
276
+ state.name = name;
277
+ state.arguments = completeArguments || state.arguments;
278
+ state.headerEmitted = true;
279
+ tools.set(index, state);
280
+ return;
281
+ }
282
+ if (type === "response.completed" || type === "response.incomplete") {
283
+ const completed = response;
284
+ if (Array.isArray(completed.output)) {
285
+ for (const [index, rawItem] of completed.output.entries()) {
286
+ // The completed response is authoritative and may carry fields such
287
+ // as encrypted_content that were absent from an earlier added/done
288
+ // event emitted by a compatible gateway.
289
+ yield* captureOutputItem(index, record(rawItem), true);
290
+ }
291
+ }
292
+ const incompleteDetails = record(completed.incomplete_details);
293
+ const incompleteReason = stringValue(incompleteDetails.reason);
294
+ yield {
295
+ ...(responsesUsage(completed.usage)
296
+ ? { usage: responsesUsage(completed.usage) }
297
+ : {}),
298
+ choices: [
299
+ {
300
+ delta: {},
301
+ finish_reason: type === "response.incomplete" || incompleteReason
302
+ ? incompleteReason === "max_output_tokens"
303
+ ? "length"
304
+ : "incomplete"
305
+ : tools.size
306
+ ? "tool_calls"
307
+ : "stop",
308
+ },
309
+ ],
310
+ };
311
+ }
312
+ };
313
+ const consumeFrame = function* (frame) {
314
+ const payload = frame
315
+ .split("\n")
316
+ .filter((line) => line.startsWith("data:"))
317
+ .map((line) => line.slice(5).trimStart())
318
+ .join("\n");
319
+ if (!payload || payload === "[DONE]")
320
+ return;
321
+ yield* processEvent(JSON.parse(payload));
322
+ };
323
+ while (true) {
324
+ const { done, value } = await reader.read();
325
+ buffer += decoder.decode(value, { stream: !done }).replace(/\r\n/g, "\n");
326
+ let boundary = buffer.indexOf("\n\n");
327
+ while (boundary !== -1) {
328
+ yield* consumeFrame(buffer.slice(0, boundary));
329
+ buffer = buffer.slice(boundary + 2);
330
+ boundary = buffer.indexOf("\n\n");
331
+ }
332
+ if (done)
333
+ break;
334
+ }
335
+ if (buffer)
336
+ yield* consumeFrame(buffer);
337
+ }
338
+ /** Translate a non-streaming Responses object into one Arena chunk. */
339
+ export function responsesFallbackChunk(value) {
340
+ const output = Array.isArray(value.output) ? value.output : [];
341
+ const content = [];
342
+ const reasoning = [];
343
+ const toolCalls = [];
344
+ for (const rawItem of output) {
345
+ const item = record(rawItem);
346
+ if (item.type === "message" && Array.isArray(item.content)) {
347
+ for (const rawPart of item.content) {
348
+ const part = record(rawPart);
349
+ if (part.type === "output_text" || part.type === "refusal") {
350
+ content.push(stringValue(part.text) || stringValue(part.refusal));
351
+ }
352
+ }
353
+ }
354
+ else if (item.type === "reasoning" && Array.isArray(item.summary)) {
355
+ for (const rawPart of item.summary) {
356
+ reasoning.push(stringValue(record(rawPart).text));
357
+ }
358
+ }
359
+ else if (item.type === "function_call") {
360
+ toolCalls.push({
361
+ index: toolCalls.length,
362
+ id: stringValue(item.call_id),
363
+ type: "function",
364
+ function: {
365
+ name: stringValue(item.name),
366
+ arguments: stringValue(item.arguments),
367
+ },
368
+ });
369
+ }
370
+ }
371
+ const incompleteDetails = record(value.incomplete_details);
372
+ const incompleteReason = stringValue(incompleteDetails.reason);
373
+ return {
374
+ openai_response_items: output.map((rawItem, index) => ({
375
+ index,
376
+ item: structuredClone(record(rawItem)),
377
+ })),
378
+ usage: responsesUsage(value.usage),
379
+ choices: [
380
+ {
381
+ delta: {
382
+ ...(content.length ? { content: content.join("") } : {}),
383
+ ...(reasoning.length
384
+ ? { reasoning_content: reasoning.join("") }
385
+ : {}),
386
+ ...(toolCalls.length ? { tool_calls: toolCalls } : {}),
387
+ },
388
+ finish_reason: incompleteReason
389
+ ? incompleteReason === "max_output_tokens"
390
+ ? "length"
391
+ : "incomplete"
392
+ : toolCalls.length
393
+ ? "tool_calls"
394
+ : "stop",
395
+ },
396
+ ],
397
+ };
398
+ }
399
+ //# sourceMappingURL=openai-responses.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"openai-responses.js","sourceRoot":"","sources":["../src/openai-responses.ts"],"names":[],"mappings":"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"}
@@ -24,6 +24,9 @@ export interface ApiConnection {
24
24
  liteLlmProxy: boolean;
25
25
  headers: Record<string, string>;
26
26
  }
27
+ export type ModelTransport = "anthropic-messages" | "openai-chat-completions" | "openai-responses";
28
+ /** Select the wire protocol without resolving credentials or making a request. */
29
+ export declare function modelTransport(config: ArenaConfig, requestedModel?: string): ModelTransport;
27
30
  export declare function resolveApiConnection(config: ArenaConfig, requestedModel?: string): ApiConnection;
28
31
  export declare function apiEndpoint(connection: ApiConnection, pathname: string): string;
29
32
  export declare function withIdleTimeout(stream: ReadableStream<Uint8Array>, timeoutMs: number | undefined): ReadableStream<Uint8Array>;
@@ -48,6 +51,7 @@ export declare class HttpModelClient implements ModelClient {
48
51
  private fetchWithHeadersTimeout;
49
52
  private completionResponse;
50
53
  stream(request: ModelRequest): AsyncIterable<ModelChunk>;
54
+ private streamOpenAIResponses;
51
55
  private streamAnthropic;
52
56
  }
53
57
  export declare function checkedFetch(connection: ApiConnection, pathname: string, init: RequestInit): Promise<Response>;
package/dist/provider.js CHANGED
@@ -1,6 +1,7 @@
1
1
  import crypto from "node:crypto";
2
2
  import { anthropicChunks, anthropicFallbackChunk, anthropicRequestBody, } from "./anthropic.js";
3
3
  import { diagnosticError, diagnosticValue, rawDiagnosticValue, requestDiagnosticSummary, requestMediaTypes, responseRequestIds, safeEndpoint, } from "./model-diagnostics.js";
4
+ import { responsesChunks, responsesFallbackChunk, responsesRequestBody, } from "./openai-responses.js";
4
5
  const defaultModelTransportTimeoutMs = 300_000;
5
6
  let undiciRuntimePromise;
6
7
  async function modelUndiciRuntime() {
@@ -147,7 +148,7 @@ function wireMessages(messages) {
147
148
  };
148
149
  }
149
150
  if (message.role === "assistant") {
150
- const { usage: _usage, reasoning_details: _details, reasoning_content: reasoningContent, ...wire } = message;
151
+ const { usage: _usage, reasoning_details: _details, openai_response_items: _responseItems, reasoning_content: reasoningContent, ...wire } = message;
151
152
  return {
152
153
  ...wire,
153
154
  ...(reasoningContent ? { reasoning_content: reasoningContent } : {}),
@@ -158,13 +159,39 @@ function wireMessages(messages) {
158
159
  }
159
160
  function stripProviderPrefix(model) {
160
161
  const separator = model.indexOf("/");
161
- if (separator === -1)
162
- return { provider: "openai", model };
162
+ if (separator === -1) {
163
+ const normalized = model.toLowerCase();
164
+ return {
165
+ provider: normalized.includes("gpt") || !normalized.includes("claude")
166
+ ? "openai"
167
+ : "anthropic",
168
+ model,
169
+ };
170
+ }
163
171
  return {
164
172
  provider: model.slice(0, separator),
165
173
  model: model.slice(separator + 1),
166
174
  };
167
175
  }
176
+ /** Select the wire protocol without resolving credentials or making a request. */
177
+ export function modelTransport(config, requestedModel = config.model) {
178
+ if (config.liteLlmProxyUrl)
179
+ return "openai-chat-completions";
180
+ const parsed = stripProviderPrefix(requestedModel);
181
+ const provider = parsed.provider === "google" ? "gemini" : parsed.provider.toLowerCase();
182
+ if (provider === "anthropic")
183
+ return "anthropic-messages";
184
+ if (provider !== "openai")
185
+ return "openai-chat-completions";
186
+ if (config.openaiApi === "responses")
187
+ return "openai-responses";
188
+ if (config.openaiApi === "chat-completions") {
189
+ return "openai-chat-completions";
190
+ }
191
+ return parsed.model.toLowerCase().includes("gpt")
192
+ ? "openai-responses"
193
+ : "openai-chat-completions";
194
+ }
168
195
  export function resolveApiConnection(config, requestedModel = config.model) {
169
196
  if (config.liteLlmProxyUrl) {
170
197
  const apiKey = config.liteLlmApiKey || config.apiKey || process.env.LITELLM_API_KEY || "";
@@ -355,8 +382,12 @@ class DiagnosticResponseAccumulator {
355
382
  content = [];
356
383
  reasoning = [];
357
384
  toolCalls = new Map();
385
+ responseItems = new Map();
358
386
  reasoningDetails;
359
387
  add(chunk) {
388
+ for (const value of chunk.openai_response_items || []) {
389
+ this.responseItems.set(value.index, structuredClone(value.item));
390
+ }
360
391
  if (chunk.reasoning_details?.length) {
361
392
  this.reasoningDetails = chunk.reasoning_details;
362
393
  }
@@ -401,6 +432,13 @@ class DiagnosticResponseAccumulator {
401
432
  ...(this.reasoningDetails
402
433
  ? { reasoning_details: this.reasoningDetails }
403
434
  : {}),
435
+ ...(this.responseItems.size
436
+ ? {
437
+ openai_response_items: [...this.responseItems.entries()]
438
+ .sort(([left], [right]) => left - right)
439
+ .map(([, item]) => item),
440
+ }
441
+ : {}),
404
442
  finish_reason: reasons.at(-1) || null,
405
443
  };
406
444
  }
@@ -602,19 +640,22 @@ export class HttpModelClient {
602
640
  }
603
641
  async *stream(request) {
604
642
  const connection = resolveApiConnection(this.config, request.model);
643
+ const transport = modelTransport(this.config, request.model);
605
644
  const context = {
606
645
  callId: crypto.randomUUID(),
607
- protocol: connection.provider === "anthropic"
608
- ? "anthropic-messages"
609
- : "openai-chat-completions",
646
+ protocol: transport,
610
647
  };
611
648
  // Direct anthropic/ connections speak the native Messages protocol; the
612
649
  // LiteLLM proxy path resolves to provider "litellm" and stays on the
613
650
  // OpenAI-compatible wire format below.
614
- if (connection.provider === "anthropic") {
651
+ if (transport === "anthropic-messages") {
615
652
  yield* this.streamAnthropic(connection, request, context);
616
653
  return;
617
654
  }
655
+ if (transport === "openai-responses") {
656
+ yield* this.streamOpenAIResponses(connection, request, context);
657
+ return;
658
+ }
618
659
  const body = {
619
660
  model: connection.model,
620
661
  messages: wireMessages(request.messages),
@@ -752,6 +793,122 @@ export class HttpModelClient {
752
793
  throw error;
753
794
  }
754
795
  }
796
+ async *streamOpenAIResponses(connection, request, context) {
797
+ const body = responsesRequestBody(request, connection.model);
798
+ if (this.config.extraBody && !request.useProviderDefaults) {
799
+ Object.assign(body, this.config.extraBody);
800
+ }
801
+ // Accept the most common Chat Completions spellings in shared rollout
802
+ // configuration, but never send them to the native Responses endpoint.
803
+ if (body.reasoning_effort !== undefined && body.reasoning === undefined) {
804
+ body.reasoning = { effort: body.reasoning_effort };
805
+ }
806
+ if (body.max_tokens !== undefined && body.max_output_tokens === undefined) {
807
+ body.max_output_tokens = body.max_tokens;
808
+ }
809
+ if (body.max_completion_tokens !== undefined &&
810
+ body.max_output_tokens === undefined) {
811
+ body.max_output_tokens = body.max_completion_tokens;
812
+ }
813
+ for (const key of [
814
+ "reasoning_effort",
815
+ "max_tokens",
816
+ "max_completion_tokens",
817
+ "messages",
818
+ "previous_response_id",
819
+ "conversation",
820
+ "stream_options",
821
+ "incremental_output",
822
+ "result_format",
823
+ "enable_thinking",
824
+ "thinking_budget",
825
+ "preserve_thinking",
826
+ ]) {
827
+ delete body[key];
828
+ }
829
+ const include = Array.isArray(body.include)
830
+ ? body.include.filter((value) => typeof value === "string")
831
+ : [];
832
+ if (!include.includes("reasoning.encrypted_content")) {
833
+ include.push("reasoning.encrypted_content");
834
+ }
835
+ body.include = include;
836
+ body.store = false;
837
+ body.stream = true;
838
+ const endpoint = apiEndpoint(connection, "/responses");
839
+ const startedAt = this.now();
840
+ const mediaTypes = requestMediaTypes(body);
841
+ await this.recordRequest(context, connection, endpoint, body);
842
+ try {
843
+ const { response, httpAttempt } = await this.completionResponse(endpoint, {
844
+ method: "POST",
845
+ headers: {
846
+ "content-type": "application/json",
847
+ ...connection.headers,
848
+ ...this.affinityHeaders,
849
+ },
850
+ body: JSON.stringify(body),
851
+ signal: request.signal,
852
+ }, context);
853
+ await this.recordResponseHeaders(context, response, httpAttempt, startedAt);
854
+ if (!response.ok) {
855
+ const rawResponseBody = await response.text();
856
+ const original = responseErrorFromText(response, rawResponseBody);
857
+ Object.assign(original, { rawResponseBody });
858
+ const capabilityHint = mediaTypes.length > 0 &&
859
+ isMediaContentRejection(original.message)
860
+ ? `The request included media content (${mediaTypes.join(", ")}), ` +
861
+ `but model "${connection.model}" or its selected endpoint rejected ` +
862
+ "a content part. Verify that the configured route supports those " +
863
+ "media types; Arena did not automatically switch models."
864
+ : undefined;
865
+ throw capabilityHint
866
+ ? Object.assign(new ModelCapabilityError(capabilityHint, original, mediaTypes), { rawResponseBody })
867
+ : original;
868
+ }
869
+ let chunks = 0;
870
+ const finishReasons = new Set();
871
+ const aggregatedResponse = new DiagnosticResponseAccumulator();
872
+ let usage;
873
+ if (response.body &&
874
+ (response.headers.get("content-type") || "").includes("text/event-stream")) {
875
+ for await (const chunk of responsesChunks(withIdleTimeout(response.body, this.config.modelStreamIdleTimeoutMs))) {
876
+ chunks += 1;
877
+ aggregatedResponse.add(chunk);
878
+ if (chunk.usage)
879
+ usage = chunk.usage;
880
+ for (const choice of chunk.choices || []) {
881
+ if (choice.finish_reason)
882
+ finishReasons.add(choice.finish_reason);
883
+ }
884
+ yield chunk;
885
+ }
886
+ }
887
+ else {
888
+ const value = (await response.json());
889
+ const chunk = responsesFallbackChunk(value);
890
+ chunks = 1;
891
+ aggregatedResponse.add(chunk);
892
+ usage = chunk.usage;
893
+ for (const choice of chunk.choices || []) {
894
+ if (choice.finish_reason)
895
+ finishReasons.add(choice.finish_reason);
896
+ }
897
+ yield chunk;
898
+ }
899
+ await this.recordAggregatedResponse(context, aggregatedResponse, finishReasons);
900
+ await this.recordCompletion(context, startedAt, chunks, finishReasons, usage);
901
+ }
902
+ catch (error) {
903
+ await this.recordCallError(context, startedAt, error, error instanceof ModelCapabilityError
904
+ ? error.capabilityHint
905
+ : undefined, typeof error?.rawResponseBody ===
906
+ "string"
907
+ ? error.rawResponseBody
908
+ : undefined);
909
+ throw error;
910
+ }
911
+ }
755
912
  async *streamAnthropic(connection, request, context) {
756
913
  const body = anthropicRequestBody(request, connection.model);
757
914
  if (this.config.extraBody && !request.useProviderDefaults) {