@codehz/ai 0.3.0 → 0.4.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/index.d.mts +68 -53
- package/dist/index.mjs +671 -813
- package/dist/index.mjs.map +1 -1
- package/package.json +1 -1
- package/src/adapters/chat-completions.ts +150 -244
- package/src/adapters/messages.ts +171 -274
- package/src/adapters/ollama.ts +118 -205
- package/src/adapters/responses.ts +135 -226
- package/src/helpers/adapter-auxiliary.ts +1 -23
- package/src/helpers/adapter-base.ts +38 -4
- package/src/helpers/incremental-stream-parser.ts +58 -0
- package/src/helpers/index.ts +20 -7
- package/src/helpers/mapping.ts +0 -8
- package/src/helpers/provider-stream.ts +147 -0
- package/src/helpers/request-mapper.ts +30 -1
- package/src/helpers/usage-mapping.ts +36 -39
- package/src/helpers/sse-parser.ts +0 -113
package/src/adapters/messages.ts
CHANGED
|
@@ -11,7 +11,7 @@
|
|
|
11
11
|
*/
|
|
12
12
|
|
|
13
13
|
import { AdapterBase } from "../helpers/adapter-base.js";
|
|
14
|
-
import {
|
|
14
|
+
import { AIRequestError } from "../core/errors.js";
|
|
15
15
|
import {
|
|
16
16
|
textBlock,
|
|
17
17
|
messageItem,
|
|
@@ -20,13 +20,17 @@ import {
|
|
|
20
20
|
opaqueItem,
|
|
21
21
|
replayFromOutput,
|
|
22
22
|
mapStopReason,
|
|
23
|
-
blockToText,
|
|
24
23
|
contentBlocksToText,
|
|
25
24
|
} from "../helpers/mapping.js";
|
|
26
|
-
import {
|
|
27
|
-
import { assertOpaqueReplayEnvelope, providerHttpError } from "../helpers/adapter-security.js";
|
|
25
|
+
import { assertOpaqueReplayEnvelope } from "../helpers/adapter-security.js";
|
|
28
26
|
import { usageFromAnthropicMessages } from "../helpers/usage-mapping.js";
|
|
29
|
-
import {
|
|
27
|
+
import {
|
|
28
|
+
NormalizedRequestMapper,
|
|
29
|
+
createSseJsonParser,
|
|
30
|
+
openProviderJsonStream,
|
|
31
|
+
iterateProviderStreamBatches,
|
|
32
|
+
createCompletionGate,
|
|
33
|
+
} from "../helpers/index.js";
|
|
30
34
|
|
|
31
35
|
import type { NormalizedRequest, AIStreamEvent, EventFactory, OutputItem, FetchFn } from "../index.js";
|
|
32
36
|
|
|
@@ -295,10 +299,7 @@ export class MessagesAdapter extends AdapterBase {
|
|
|
295
299
|
break;
|
|
296
300
|
}
|
|
297
301
|
case "tool_result": {
|
|
298
|
-
const content = mapper
|
|
299
|
-
.ensureTextBlocks(item.content, `tool_result ${item.callId} content`)
|
|
300
|
-
.map(blockToText)
|
|
301
|
-
.join("\n");
|
|
302
|
+
const content = mapper.textFromBlocks(item.content, `tool_result ${item.callId} content`);
|
|
302
303
|
const block: MessagesAPIContentBlock = {
|
|
303
304
|
type: "tool_result",
|
|
304
305
|
tool_use_id: item.callId,
|
|
@@ -352,23 +353,20 @@ export class MessagesAdapter extends AdapterBase {
|
|
|
352
353
|
|
|
353
354
|
if (systemPrompt) body.system = systemPrompt;
|
|
354
355
|
|
|
355
|
-
|
|
356
|
-
|
|
357
|
-
|
|
358
|
-
|
|
359
|
-
|
|
360
|
-
|
|
361
|
-
|
|
362
|
-
|
|
363
|
-
|
|
364
|
-
|
|
365
|
-
|
|
366
|
-
|
|
367
|
-
|
|
368
|
-
|
|
369
|
-
body.tool_choice = { type: "tool", name: request.toolChoice.name };
|
|
370
|
-
}
|
|
371
|
-
}
|
|
356
|
+
body.tools = mapper.mapToolsIfPresent(
|
|
357
|
+
request.tools,
|
|
358
|
+
(t): MessagesAPITool => ({
|
|
359
|
+
name: t.name,
|
|
360
|
+
description: t.description,
|
|
361
|
+
input_schema: t.inputSchema,
|
|
362
|
+
}),
|
|
363
|
+
);
|
|
364
|
+
|
|
365
|
+
body.tool_choice = mapper.mapToolChoice<Exclude<MessagesAPIRequest["tool_choice"], undefined>>(request.toolChoice, {
|
|
366
|
+
auto: { type: "auto" } as const,
|
|
367
|
+
none: { type: "none" } as const,
|
|
368
|
+
tool: (name) => ({ type: "tool" as const, name }),
|
|
369
|
+
});
|
|
372
370
|
|
|
373
371
|
if (request.temperature !== undefined) body.temperature = request.temperature;
|
|
374
372
|
|
|
@@ -383,7 +381,7 @@ export class MessagesAdapter extends AdapterBase {
|
|
|
383
381
|
request: NormalizedRequest,
|
|
384
382
|
): AsyncIterable<AIStreamEvent> {
|
|
385
383
|
const auxiliary = this.createAuxiliaryState(request);
|
|
386
|
-
|
|
384
|
+
const gate = createCompletionGate();
|
|
387
385
|
|
|
388
386
|
if (request.metadata) {
|
|
389
387
|
yield factory.responseWarning(
|
|
@@ -392,53 +390,20 @@ export class MessagesAdapter extends AdapterBase {
|
|
|
392
390
|
);
|
|
393
391
|
}
|
|
394
392
|
|
|
395
|
-
|
|
396
|
-
|
|
397
|
-
|
|
398
|
-
|
|
399
|
-
|
|
400
|
-
|
|
401
|
-
|
|
402
|
-
|
|
403
|
-
|
|
404
|
-
|
|
405
|
-
body: JSON.stringify(providerRequest),
|
|
406
|
-
signal: request.signal,
|
|
407
|
-
});
|
|
408
|
-
} catch (err) {
|
|
409
|
-
throw new AIProviderError(err instanceof Error ? err.message : String(err), "PROVIDER_ERROR");
|
|
410
|
-
}
|
|
411
|
-
|
|
412
|
-
if (!response.ok) {
|
|
413
|
-
const errorBody = await response.text().catch(() => "");
|
|
414
|
-
throw providerHttpError(response.status, errorBody);
|
|
415
|
-
}
|
|
416
|
-
|
|
417
|
-
const reader = response.body?.getReader();
|
|
418
|
-
if (!reader) {
|
|
419
|
-
throw new AIStreamError("Response body is not readable", "STREAM_ERROR");
|
|
420
|
-
}
|
|
421
|
-
|
|
422
|
-
// 流累积状态
|
|
423
|
-
const parser = new IncrementalStreamParser<MessagesSSEEvent>(splitSSEFrames, (frame: string) => {
|
|
424
|
-
let eventType = "";
|
|
425
|
-
let dataStr = "";
|
|
426
|
-
for (const rawLine of frame.split("\n")) {
|
|
427
|
-
const line = rawLine.trim();
|
|
428
|
-
if (line.startsWith("event: ")) eventType = line.slice(7).trim();
|
|
429
|
-
else if (line.startsWith("data: ")) dataStr += line.slice(6);
|
|
430
|
-
}
|
|
431
|
-
if (!eventType) return { status: "ignored" };
|
|
432
|
-
try {
|
|
433
|
-
const data = JSON.parse(dataStr);
|
|
434
|
-
return { status: "parsed", value: { type: eventType, data } as MessagesSSEEvent };
|
|
435
|
-
} catch {
|
|
436
|
-
return { status: "malformed" };
|
|
437
|
-
}
|
|
393
|
+
const { reader, headers } = await openProviderJsonStream({
|
|
394
|
+
fetchFn: this.fetchFn,
|
|
395
|
+
url: `${this.baseUrl}/messages`,
|
|
396
|
+
headers: {
|
|
397
|
+
"Content-Type": "application/json",
|
|
398
|
+
"x-api-key": this.apiKey,
|
|
399
|
+
"anthropic-version": this.apiVersion,
|
|
400
|
+
},
|
|
401
|
+
body: providerRequest,
|
|
402
|
+
signal: request.signal,
|
|
438
403
|
});
|
|
439
404
|
|
|
405
|
+
const parser = createSseJsonParser<MessagesSSEEvent>();
|
|
440
406
|
const output: OutputItem[] = [];
|
|
441
|
-
let streamDone = false;
|
|
442
407
|
let messageResponse: MessagesAPIMessageResponse | undefined;
|
|
443
408
|
let currentContentBlockIndex = -1;
|
|
444
409
|
let currentItemType: "message" | "reasoning" | "tool_call" | null = null;
|
|
@@ -446,215 +411,176 @@ export class MessagesAdapter extends AdapterBase {
|
|
|
446
411
|
let currentToolName = "";
|
|
447
412
|
let currentArgsText = "";
|
|
448
413
|
let currentThinkingVisibility: "full" | "redacted" = "full";
|
|
449
|
-
let hasStreamedReasoning = false;
|
|
450
414
|
const rawReplayContent: MessagesAPIContentBlock[] = [];
|
|
451
415
|
|
|
452
|
-
// 内容块累积缓冲
|
|
453
416
|
let textBuffer = "";
|
|
454
417
|
let thinkingBuffer = "";
|
|
455
418
|
let argsBuffer = "";
|
|
456
419
|
|
|
457
|
-
// 完成响应数据
|
|
458
420
|
let stopReason: string | undefined;
|
|
459
421
|
let stopSequence: string | null | undefined;
|
|
460
422
|
let rawResponseId = "";
|
|
461
423
|
|
|
462
424
|
if (request.include?.providerMetadata !== "off") {
|
|
463
|
-
const headerMetadata = pickProviderHeaders(
|
|
425
|
+
const headerMetadata = pickProviderHeaders(headers);
|
|
464
426
|
auxiliary.recordProviderMetadata(
|
|
465
427
|
"header",
|
|
466
428
|
Object.keys(headerMetadata).length > 0 ? { headers: headerMetadata } : undefined,
|
|
467
429
|
);
|
|
468
430
|
}
|
|
469
431
|
|
|
470
|
-
|
|
471
|
-
|
|
472
|
-
|
|
473
|
-
|
|
474
|
-
|
|
475
|
-
|
|
476
|
-
|
|
477
|
-
|
|
478
|
-
|
|
479
|
-
|
|
480
|
-
|
|
481
|
-
|
|
482
|
-
|
|
483
|
-
|
|
484
|
-
|
|
485
|
-
|
|
486
|
-
|
|
487
|
-
|
|
488
|
-
|
|
489
|
-
|
|
490
|
-
for (const sseEvent of events) {
|
|
491
|
-
switch (sseEvent.type) {
|
|
492
|
-
case "ping":
|
|
493
|
-
continue;
|
|
432
|
+
for await (const batch of iterateProviderStreamBatches({
|
|
433
|
+
reader,
|
|
434
|
+
parser,
|
|
435
|
+
factory,
|
|
436
|
+
providerLabel: "Messages",
|
|
437
|
+
transportLabel: "SSE event(s)",
|
|
438
|
+
incompleteMessage: "Stream ended with an incomplete Messages SSE frame",
|
|
439
|
+
})) {
|
|
440
|
+
for (const warning of batch.warnings) yield warning;
|
|
441
|
+
|
|
442
|
+
for (const sseEvent of batch.items) {
|
|
443
|
+
switch (sseEvent.type) {
|
|
444
|
+
case "ping":
|
|
445
|
+
continue;
|
|
446
|
+
|
|
447
|
+
case "error": {
|
|
448
|
+
const err = sseEvent.data.error;
|
|
449
|
+
yield factory.responseWarning(err.message, err.type);
|
|
450
|
+
continue;
|
|
451
|
+
}
|
|
494
452
|
|
|
495
|
-
|
|
496
|
-
|
|
497
|
-
|
|
498
|
-
|
|
499
|
-
|
|
453
|
+
case "message_start": {
|
|
454
|
+
messageResponse = sseEvent.data.message;
|
|
455
|
+
rawResponseId = messageResponse.id;
|
|
456
|
+
continue;
|
|
457
|
+
}
|
|
500
458
|
|
|
501
|
-
|
|
502
|
-
|
|
503
|
-
|
|
504
|
-
|
|
505
|
-
|
|
506
|
-
|
|
459
|
+
case "content_block_start": {
|
|
460
|
+
const block = sseEvent.data.content_block;
|
|
461
|
+
currentContentBlockIndex = sseEvent.data.index;
|
|
462
|
+
|
|
463
|
+
switch (block.type) {
|
|
464
|
+
case "text": {
|
|
465
|
+
currentItemType = "message";
|
|
466
|
+
currentItemId = synthesizeItemId("msg", currentContentBlockIndex, rawResponseId);
|
|
467
|
+
textBuffer = "";
|
|
468
|
+
yield factory.messageStarted(currentItemId);
|
|
469
|
+
break;
|
|
507
470
|
}
|
|
508
|
-
|
|
509
|
-
|
|
510
|
-
|
|
511
|
-
|
|
512
|
-
|
|
513
|
-
|
|
514
|
-
|
|
515
|
-
|
|
516
|
-
|
|
517
|
-
|
|
518
|
-
|
|
519
|
-
|
|
520
|
-
|
|
521
|
-
|
|
522
|
-
|
|
523
|
-
|
|
524
|
-
|
|
525
|
-
|
|
526
|
-
|
|
527
|
-
|
|
528
|
-
|
|
529
|
-
|
|
530
|
-
|
|
531
|
-
}
|
|
532
|
-
|
|
533
|
-
|
|
534
|
-
|
|
535
|
-
|
|
536
|
-
|
|
537
|
-
|
|
538
|
-
|
|
539
|
-
yield factory.reasoningDelta(currentItemId, textBlock(data));
|
|
540
|
-
const redactedItem = reasoningItem([textBlock(data)], "redacted", currentItemId);
|
|
541
|
-
yield factory.reasoningCompleted(currentItemId);
|
|
542
|
-
output.push(redactedItem);
|
|
543
|
-
rawReplayContent.push({ type: "redacted_thinking", data });
|
|
544
|
-
currentItemType = null;
|
|
545
|
-
break;
|
|
546
|
-
}
|
|
547
|
-
case "tool_use": {
|
|
548
|
-
const tuBlock = block as unknown as { id: string; name: string };
|
|
549
|
-
currentItemType = "tool_call";
|
|
550
|
-
currentItemId = tuBlock.id;
|
|
551
|
-
currentToolName = tuBlock.name;
|
|
552
|
-
currentArgsText = "";
|
|
553
|
-
argsBuffer = "";
|
|
554
|
-
yield factory.toolCallStarted(currentItemId, currentToolName);
|
|
555
|
-
break;
|
|
556
|
-
}
|
|
471
|
+
case "thinking": {
|
|
472
|
+
currentItemType = "reasoning";
|
|
473
|
+
currentItemId = synthesizeItemId("reason", currentContentBlockIndex, rawResponseId);
|
|
474
|
+
currentThinkingVisibility = "full";
|
|
475
|
+
thinkingBuffer = "";
|
|
476
|
+
yield factory.reasoningStarted(currentItemId, "full");
|
|
477
|
+
break;
|
|
478
|
+
}
|
|
479
|
+
case "redacted_thinking": {
|
|
480
|
+
currentItemType = "reasoning";
|
|
481
|
+
currentItemId = synthesizeItemId("reason-redacted", currentContentBlockIndex, rawResponseId);
|
|
482
|
+
currentThinkingVisibility = "redacted";
|
|
483
|
+
const data = (block as unknown as { data: string }).data;
|
|
484
|
+
yield factory.reasoningStarted(currentItemId, "redacted");
|
|
485
|
+
yield factory.reasoningDelta(currentItemId, textBlock(data));
|
|
486
|
+
const redactedItem = reasoningItem([textBlock(data)], "redacted", currentItemId);
|
|
487
|
+
yield factory.reasoningCompleted(currentItemId);
|
|
488
|
+
output.push(redactedItem);
|
|
489
|
+
rawReplayContent.push({ type: "redacted_thinking", data });
|
|
490
|
+
currentItemType = null;
|
|
491
|
+
break;
|
|
492
|
+
}
|
|
493
|
+
case "tool_use": {
|
|
494
|
+
const tuBlock = block as unknown as { id: string; name: string };
|
|
495
|
+
currentItemType = "tool_call";
|
|
496
|
+
currentItemId = tuBlock.id;
|
|
497
|
+
currentToolName = tuBlock.name;
|
|
498
|
+
currentArgsText = "";
|
|
499
|
+
argsBuffer = "";
|
|
500
|
+
yield factory.toolCallStarted(currentItemId, currentToolName);
|
|
501
|
+
break;
|
|
557
502
|
}
|
|
558
|
-
continue;
|
|
559
503
|
}
|
|
504
|
+
continue;
|
|
505
|
+
}
|
|
506
|
+
|
|
507
|
+
case "content_block_delta": {
|
|
508
|
+
const delta = sseEvent.data.delta;
|
|
560
509
|
|
|
561
|
-
|
|
562
|
-
|
|
563
|
-
|
|
564
|
-
|
|
565
|
-
|
|
566
|
-
|
|
567
|
-
const txt = (delta as unknown as { text: string }).text;
|
|
568
|
-
textBuffer += txt;
|
|
569
|
-
yield factory.messageDelta(currentItemId, textBlock(txt));
|
|
570
|
-
}
|
|
571
|
-
break;
|
|
510
|
+
switch (delta.type) {
|
|
511
|
+
case "text_delta": {
|
|
512
|
+
if (currentItemType === "message" && currentItemId) {
|
|
513
|
+
const txt = (delta as unknown as { text: string }).text;
|
|
514
|
+
textBuffer += txt;
|
|
515
|
+
yield factory.messageDelta(currentItemId, textBlock(txt));
|
|
572
516
|
}
|
|
573
|
-
|
|
574
|
-
|
|
575
|
-
|
|
576
|
-
|
|
577
|
-
|
|
578
|
-
|
|
579
|
-
|
|
517
|
+
break;
|
|
518
|
+
}
|
|
519
|
+
case "thinking_delta": {
|
|
520
|
+
if (currentItemType === "reasoning" && currentItemId) {
|
|
521
|
+
const txt = (delta as unknown as { thinking: string }).thinking;
|
|
522
|
+
thinkingBuffer += txt;
|
|
523
|
+
yield factory.reasoningDelta(currentItemId, textBlock(txt));
|
|
580
524
|
}
|
|
581
|
-
|
|
582
|
-
|
|
583
|
-
|
|
584
|
-
|
|
585
|
-
|
|
586
|
-
|
|
587
|
-
|
|
525
|
+
break;
|
|
526
|
+
}
|
|
527
|
+
case "input_json_delta": {
|
|
528
|
+
if (currentItemType === "tool_call" && currentItemId) {
|
|
529
|
+
const partial = (delta as unknown as { partial_json: string }).partial_json;
|
|
530
|
+
argsBuffer += partial;
|
|
531
|
+
yield factory.toolCallDelta(currentItemId, { argumentsText: partial });
|
|
588
532
|
}
|
|
533
|
+
break;
|
|
589
534
|
}
|
|
590
|
-
continue;
|
|
591
535
|
}
|
|
536
|
+
continue;
|
|
537
|
+
}
|
|
592
538
|
|
|
593
|
-
|
|
594
|
-
|
|
595
|
-
|
|
596
|
-
|
|
597
|
-
|
|
598
|
-
|
|
599
|
-
|
|
600
|
-
|
|
601
|
-
|
|
602
|
-
|
|
603
|
-
|
|
604
|
-
|
|
605
|
-
|
|
606
|
-
|
|
607
|
-
|
|
608
|
-
|
|
609
|
-
|
|
610
|
-
|
|
611
|
-
|
|
612
|
-
}
|
|
613
|
-
|
|
614
|
-
currentItemType = null;
|
|
615
|
-
currentItemId = "";
|
|
616
|
-
continue;
|
|
539
|
+
case "content_block_stop": {
|
|
540
|
+
if (currentItemType === "message" && currentItemId) {
|
|
541
|
+
yield factory.messageCompleted(currentItemId);
|
|
542
|
+
output.push(messageItem([textBlock(textBuffer)], { id: currentItemId }));
|
|
543
|
+
rawReplayContent.push({ type: "text", text: textBuffer });
|
|
544
|
+
} else if (currentItemType === "reasoning" && currentItemId && currentThinkingVisibility !== "redacted") {
|
|
545
|
+
yield factory.reasoningCompleted(currentItemId);
|
|
546
|
+
output.push(reasoningItem([textBlock(thinkingBuffer)], currentThinkingVisibility, currentItemId));
|
|
547
|
+
rawReplayContent.push({ type: "thinking", thinking: thinkingBuffer });
|
|
548
|
+
} else if (currentItemType === "tool_call" && currentItemId) {
|
|
549
|
+
const tcItem = toolCallItem(currentItemId, currentToolName, currentArgsText || argsBuffer);
|
|
550
|
+
yield factory.toolCallCompleted(currentItemId);
|
|
551
|
+
output.push(tcItem);
|
|
552
|
+
rawReplayContent.push({
|
|
553
|
+
type: "tool_use",
|
|
554
|
+
id: currentItemId,
|
|
555
|
+
name: currentToolName,
|
|
556
|
+
input: parseProviderToolUseInput(currentArgsText || argsBuffer),
|
|
557
|
+
});
|
|
617
558
|
}
|
|
618
559
|
|
|
619
|
-
|
|
620
|
-
|
|
621
|
-
|
|
622
|
-
|
|
623
|
-
if (u) {
|
|
624
|
-
auxiliary.recordUsage(usageFromAnthropicMessages(u), "stream", u);
|
|
625
|
-
}
|
|
626
|
-
continue;
|
|
627
|
-
}
|
|
560
|
+
currentItemType = null;
|
|
561
|
+
currentItemId = "";
|
|
562
|
+
continue;
|
|
563
|
+
}
|
|
628
564
|
|
|
629
|
-
|
|
630
|
-
|
|
631
|
-
|
|
565
|
+
case "message_delta": {
|
|
566
|
+
stopReason = sseEvent.data.delta.stop_reason;
|
|
567
|
+
stopSequence = sseEvent.data.delta.stop_sequence;
|
|
568
|
+
const u = sseEvent.data.usage;
|
|
569
|
+
if (u) {
|
|
570
|
+
auxiliary.recordUsage(usageFromAnthropicMessages(u), "stream", u);
|
|
632
571
|
}
|
|
572
|
+
continue;
|
|
633
573
|
}
|
|
634
|
-
}
|
|
635
574
|
|
|
636
|
-
|
|
637
|
-
|
|
638
|
-
|
|
575
|
+
case "message_stop": {
|
|
576
|
+
break;
|
|
577
|
+
}
|
|
639
578
|
}
|
|
640
579
|
}
|
|
641
|
-
} finally {
|
|
642
|
-
try {
|
|
643
|
-
if (!streamDone) await reader.cancel().catch(() => undefined);
|
|
644
|
-
} finally {
|
|
645
|
-
reader.releaseLock();
|
|
646
|
-
}
|
|
647
580
|
}
|
|
648
581
|
|
|
649
|
-
if (parser.getRemaining().trim().length > 0) {
|
|
650
|
-
yield factory.responseWarning("Stream ended with an incomplete Messages SSE frame", "STREAM_ERROR");
|
|
651
|
-
}
|
|
652
|
-
|
|
653
|
-
// 构造 replay
|
|
654
582
|
const replay = [...replayFromOutput(output)];
|
|
655
583
|
|
|
656
|
-
// 附加 opaque replay item 用于续接
|
|
657
|
-
// 保存 provider 原始 block 以实现高保真 replay
|
|
658
584
|
if (messageResponse) {
|
|
659
585
|
const replayContent = rawReplayContent.length > 0 ? rawReplayContent : messageResponse.content;
|
|
660
586
|
replay.push(
|
|
@@ -680,41 +606,12 @@ export class MessagesAdapter extends AdapterBase {
|
|
|
680
606
|
);
|
|
681
607
|
}
|
|
682
608
|
|
|
683
|
-
|
|
684
|
-
|
|
685
|
-
|
|
686
|
-
|
|
687
|
-
|
|
688
|
-
|
|
689
|
-
for (const event of auxiliaryResult.events) {
|
|
690
|
-
yield event;
|
|
691
|
-
}
|
|
692
|
-
|
|
693
|
-
if (!completedEmitted) {
|
|
694
|
-
completedEmitted = true;
|
|
695
|
-
const finalResponse = this.buildResponse(
|
|
696
|
-
request,
|
|
697
|
-
{
|
|
698
|
-
output,
|
|
699
|
-
replay,
|
|
700
|
-
stopReason: stopReason ? mapStopReason(stopReason) : undefined,
|
|
701
|
-
usage: auxiliaryResult.usage,
|
|
702
|
-
billing: auxiliaryResult.billing,
|
|
703
|
-
auxiliary: auxiliaryResult.auxiliary,
|
|
704
|
-
warnings: auxiliaryResult.warnings,
|
|
705
|
-
metadataSources: auxiliaryResult.metadataSources,
|
|
706
|
-
rawResponseId,
|
|
707
|
-
},
|
|
708
|
-
factory,
|
|
709
|
-
);
|
|
710
|
-
yield factory.responseCompleted({
|
|
711
|
-
replay: finalResponse.replay,
|
|
712
|
-
stopReason: finalResponse.stopReason,
|
|
713
|
-
trace: finalResponse.backend,
|
|
714
|
-
usage: finalResponse.usage,
|
|
715
|
-
billing: finalResponse.billing,
|
|
716
|
-
auxiliary: finalResponse.auxiliary,
|
|
717
|
-
warnings: finalResponse.warnings,
|
|
609
|
+
if (gate.tryComplete()) {
|
|
610
|
+
yield* this.emitStreamCompleted(factory, request, auxiliary, {
|
|
611
|
+
output,
|
|
612
|
+
replay,
|
|
613
|
+
stopReason: stopReason ? mapStopReason(stopReason) : undefined,
|
|
614
|
+
rawResponseId,
|
|
718
615
|
});
|
|
719
616
|
}
|
|
720
617
|
}
|