@nextclaw/ncp-agent-runtime 0.3.28 → 0.3.29-beta.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.js CHANGED
@@ -1,153 +1,9 @@
1
+ import { NcpAssistantTextStreamNormalizer, NcpEventType, isHiddenNcpMessage, normalizeAssistantText, sanitizeAssistantReplyTags } from "@nextclaw/ncp";
1
2
  import { copyFileSync, existsSync, readFileSync } from "node:fs";
2
3
  import AjvPkg from "ajv";
3
4
  import { createHash, randomUUID } from "node:crypto";
4
5
  import { copyFile, mkdir, readFile, stat, writeFile } from "node:fs/promises";
5
6
  import { basename, dirname, join, resolve } from "node:path";
6
- import { NcpAssistantTextStreamNormalizer, NcpEventType, isHiddenNcpMessage, normalizeAssistantText } from "@nextclaw/ncp";
7
- //#region src/runtime/user-content.utils.ts
8
- function readOptionalString$1(value) {
9
- if (typeof value !== "string") return null;
10
- const trimmed = value.trim();
11
- return trimmed.length > 0 ? trimmed : null;
12
- }
13
- function formatAssetReferenceBlock(params) {
14
- const { fileName: rawFileName, mimeType: rawMimeType, assetUri: rawAssetUri, url: rawUrl, sizeBytes } = params;
15
- const fileName = readOptionalString$1(rawFileName) ?? "asset";
16
- const mimeType = readOptionalString$1(rawMimeType) ?? "application/octet-stream";
17
- const assetUri = readOptionalString$1(rawAssetUri);
18
- const url = readOptionalString$1(rawUrl);
19
- const sizeText = typeof sizeBytes === "number" && Number.isFinite(sizeBytes) ? String(sizeBytes) : null;
20
- return [
21
- `[Asset: ${fileName}]`,
22
- `[MIME: ${mimeType}]`,
23
- ...assetUri ? [`[Asset URI: ${assetUri}]`] : [],
24
- ...sizeText ? [`[Size Bytes: ${sizeText}]`] : [],
25
- ...url ? [`[Preview URL: ${url}]`] : [],
26
- "[Instruction: This file is not embedded in the prompt. If you need to inspect or transform it, use asset_export to copy it to a normal file path first.]"
27
- ].join("\n");
28
- }
29
- function resolveFilePart(part, assetStore) {
30
- const assetUri = readOptionalString$1(part.assetUri);
31
- const stored = assetUri ? assetStore?.getByUri(assetUri) : null;
32
- return {
33
- fileName: readOptionalString$1(stored?.fileName) ?? readOptionalString$1(part.name) ?? "asset",
34
- mimeType: readOptionalString$1(stored?.mimeType) ?? readOptionalString$1(part.mimeType) ?? "application/octet-stream",
35
- assetUri,
36
- url: readOptionalString$1(part.url),
37
- contentBase64: readOptionalString$1(part.contentBase64),
38
- sizeBytes: stored?.sizeBytes ?? (typeof part.sizeBytes === "number" ? part.sizeBytes : void 0),
39
- contentPath: assetUri ? assetStore?.resolveContentPath(assetUri) ?? null : null
40
- };
41
- }
42
- function formatImageAttachmentHint(params) {
43
- const { fileName: rawFileName, mimeType: rawMimeType, assetUri: rawAssetUri, sizeBytes } = params;
44
- const fileName = readOptionalString$1(rawFileName) ?? "asset";
45
- const mimeType = readOptionalString$1(rawMimeType) ?? "application/octet-stream";
46
- const assetUri = readOptionalString$1(rawAssetUri);
47
- const sizeText = typeof sizeBytes === "number" && Number.isFinite(sizeBytes) ? String(sizeBytes) : null;
48
- return [
49
- `[Attached Image: ${fileName}]`,
50
- `[MIME: ${mimeType}]`,
51
- ...assetUri ? [`[Asset URI: ${assetUri}]`] : [],
52
- ...sizeText ? [`[Size Bytes: ${sizeText}]`] : [],
53
- assetUri ? "[Instruction: This image is embedded in the prompt. If you need to transform or process the original file with tools, use the asset URI.]" : "[Instruction: This image is embedded in the prompt.]"
54
- ].join("\n");
55
- }
56
- function isImageMimeType(value) {
57
- return value?.startsWith("image/") ?? false;
58
- }
59
- function isModelReachableImageUrl(value) {
60
- return value !== null && (/^https?:\/\//i.test(value) || /^data:/i.test(value));
61
- }
62
- function buildImageDataUrl(mimeType, bytes) {
63
- return `data:${mimeType};base64,${Buffer.from(bytes).toString("base64")}`;
64
- }
65
- function resolveImageContentPart(part, assetStore) {
66
- const resolved = resolveFilePart(part, assetStore);
67
- if (!isImageMimeType(resolved.mimeType)) return null;
68
- if (resolved.contentBase64) return {
69
- type: "image_url",
70
- image_url: {
71
- url: `data:${resolved.mimeType};base64,${resolved.contentBase64}`,
72
- detail: "auto"
73
- }
74
- };
75
- if (resolved.contentPath) return {
76
- type: "image_url",
77
- image_url: {
78
- url: buildImageDataUrl(resolved.mimeType, readFileSync(resolved.contentPath)),
79
- detail: "auto"
80
- }
81
- };
82
- const reachableImageUrl = resolved.url;
83
- if (isModelReachableImageUrl(reachableImageUrl)) return {
84
- type: "image_url",
85
- image_url: {
86
- url: reachableImageUrl,
87
- detail: "auto"
88
- }
89
- };
90
- return null;
91
- }
92
- function resolveImageAttachmentHint(part, assetStore) {
93
- const resolved = resolveFilePart(part, assetStore);
94
- if (!isImageMimeType(resolved.mimeType)) return null;
95
- return formatImageAttachmentHint({
96
- fileName: resolved.fileName,
97
- mimeType: resolved.mimeType,
98
- assetUri: resolved.assetUri,
99
- sizeBytes: resolved.sizeBytes
100
- });
101
- }
102
- function resolveAssetReferenceBlock(part, assetStore) {
103
- const resolved = resolveFilePart(part, assetStore);
104
- if (resolved.assetUri) return formatAssetReferenceBlock({
105
- fileName: resolved.fileName,
106
- mimeType: resolved.mimeType,
107
- assetUri: resolved.assetUri,
108
- url: resolved.url,
109
- sizeBytes: resolved.sizeBytes
110
- });
111
- if (resolved.url || resolved.contentBase64) return formatAssetReferenceBlock({
112
- fileName: resolved.fileName,
113
- mimeType: resolved.mimeType,
114
- url: resolved.url,
115
- sizeBytes: resolved.sizeBytes
116
- });
117
- return null;
118
- }
119
- function buildNcpUserContent(parts, options = {}) {
120
- const content = [];
121
- for (const part of parts) {
122
- if ((part.type === "text" || part.type === "rich-text") && part.text.trim().length > 0) {
123
- content.push({
124
- type: "text",
125
- text: part.text
126
- });
127
- continue;
128
- }
129
- if (part.type !== "file") continue;
130
- const imageContentPart = resolveImageContentPart(part, options.assetStore);
131
- if (imageContentPart) {
132
- content.push(imageContentPart);
133
- const imageAttachmentHint = resolveImageAttachmentHint(part, options.assetStore);
134
- if (imageAttachmentHint) content.push({
135
- type: "text",
136
- text: imageAttachmentHint
137
- });
138
- continue;
139
- }
140
- const assetReferenceBlock = resolveAssetReferenceBlock(part, options.assetStore);
141
- if (assetReferenceBlock) content.push({
142
- type: "text",
143
- text: assetReferenceBlock
144
- });
145
- }
146
- if (content.length === 0) return "";
147
- if (content.length === 1 && content[0]?.type === "text") return content[0].text;
148
- return content;
149
- }
150
- //#endregion
151
7
  //#region src/tool-result/tool-result-content.utils.ts
152
8
  const LARGE_INLINE_PAYLOAD_CHARS$1 = 2048;
153
9
  function sanitizePositiveInt(value, fallback) {
@@ -565,7 +421,233 @@ var ToolResultContentManager = class {
565
421
  };
566
422
  const defaultToolResultContentManager = new ToolResultContentManager();
567
423
  //#endregion
568
- //#region src/runtime/utils.ts
424
+ //#region src/runtime/user-content.utils.ts
425
+ function readOptionalString$1(value) {
426
+ if (typeof value !== "string") return null;
427
+ const trimmed = value.trim();
428
+ return trimmed.length > 0 ? trimmed : null;
429
+ }
430
+ function formatAssetReferenceBlock(params) {
431
+ const { fileName: rawFileName, mimeType: rawMimeType, assetUri: rawAssetUri, url: rawUrl, sizeBytes } = params;
432
+ const fileName = readOptionalString$1(rawFileName) ?? "asset";
433
+ const mimeType = readOptionalString$1(rawMimeType) ?? "application/octet-stream";
434
+ const assetUri = readOptionalString$1(rawAssetUri);
435
+ const url = readOptionalString$1(rawUrl);
436
+ const sizeText = typeof sizeBytes === "number" && Number.isFinite(sizeBytes) ? String(sizeBytes) : null;
437
+ return [
438
+ `[Asset: ${fileName}]`,
439
+ `[MIME: ${mimeType}]`,
440
+ ...assetUri ? [`[Asset URI: ${assetUri}]`] : [],
441
+ ...sizeText ? [`[Size Bytes: ${sizeText}]`] : [],
442
+ ...url ? [`[Preview URL: ${url}]`] : [],
443
+ "[Instruction: This file is not embedded in the prompt. If you need to inspect or transform it, use asset_export to copy it to a normal file path first.]"
444
+ ].join("\n");
445
+ }
446
+ function resolveFilePart(part, assetStore) {
447
+ const assetUri = readOptionalString$1(part.assetUri);
448
+ const stored = assetUri ? assetStore?.getByUri(assetUri) : null;
449
+ return {
450
+ fileName: readOptionalString$1(stored?.fileName) ?? readOptionalString$1(part.name) ?? "asset",
451
+ mimeType: readOptionalString$1(stored?.mimeType) ?? readOptionalString$1(part.mimeType) ?? "application/octet-stream",
452
+ assetUri,
453
+ url: readOptionalString$1(part.url),
454
+ contentBase64: readOptionalString$1(part.contentBase64),
455
+ sizeBytes: stored?.sizeBytes ?? (typeof part.sizeBytes === "number" ? part.sizeBytes : void 0),
456
+ contentPath: assetUri ? assetStore?.resolveContentPath(assetUri) ?? null : null
457
+ };
458
+ }
459
+ function formatImageAttachmentHint(params) {
460
+ const { fileName: rawFileName, mimeType: rawMimeType, assetUri: rawAssetUri, sizeBytes } = params;
461
+ const fileName = readOptionalString$1(rawFileName) ?? "asset";
462
+ const mimeType = readOptionalString$1(rawMimeType) ?? "application/octet-stream";
463
+ const assetUri = readOptionalString$1(rawAssetUri);
464
+ const sizeText = typeof sizeBytes === "number" && Number.isFinite(sizeBytes) ? String(sizeBytes) : null;
465
+ return [
466
+ `[Attached Image: ${fileName}]`,
467
+ `[MIME: ${mimeType}]`,
468
+ ...assetUri ? [`[Asset URI: ${assetUri}]`] : [],
469
+ ...sizeText ? [`[Size Bytes: ${sizeText}]`] : [],
470
+ assetUri ? "[Instruction: This image is embedded in the prompt. If you need to transform or process the original file with tools, use the asset URI.]" : "[Instruction: This image is embedded in the prompt.]"
471
+ ].join("\n");
472
+ }
473
+ function isImageMimeType(value) {
474
+ return value?.startsWith("image/") ?? false;
475
+ }
476
+ function isModelReachableImageUrl(value) {
477
+ return value !== null && (/^https?:\/\//i.test(value) || /^data:/i.test(value));
478
+ }
479
+ function buildImageDataUrl(mimeType, bytes) {
480
+ return `data:${mimeType};base64,${Buffer.from(bytes).toString("base64")}`;
481
+ }
482
+ function resolveImageContentPart(part, assetStore) {
483
+ const resolved = resolveFilePart(part, assetStore);
484
+ if (!isImageMimeType(resolved.mimeType)) return null;
485
+ if (resolved.contentBase64) return {
486
+ type: "image_url",
487
+ image_url: {
488
+ url: `data:${resolved.mimeType};base64,${resolved.contentBase64}`,
489
+ detail: "auto"
490
+ }
491
+ };
492
+ if (resolved.contentPath) return {
493
+ type: "image_url",
494
+ image_url: {
495
+ url: buildImageDataUrl(resolved.mimeType, readFileSync(resolved.contentPath)),
496
+ detail: "auto"
497
+ }
498
+ };
499
+ const reachableImageUrl = resolved.url;
500
+ if (isModelReachableImageUrl(reachableImageUrl)) return {
501
+ type: "image_url",
502
+ image_url: {
503
+ url: reachableImageUrl,
504
+ detail: "auto"
505
+ }
506
+ };
507
+ return null;
508
+ }
509
+ function resolveImageAttachmentHint(part, assetStore) {
510
+ const resolved = resolveFilePart(part, assetStore);
511
+ if (!isImageMimeType(resolved.mimeType)) return null;
512
+ return formatImageAttachmentHint({
513
+ fileName: resolved.fileName,
514
+ mimeType: resolved.mimeType,
515
+ assetUri: resolved.assetUri,
516
+ sizeBytes: resolved.sizeBytes
517
+ });
518
+ }
519
+ function resolveAssetReferenceBlock(part, assetStore) {
520
+ const resolved = resolveFilePart(part, assetStore);
521
+ if (resolved.assetUri) return formatAssetReferenceBlock({
522
+ fileName: resolved.fileName,
523
+ mimeType: resolved.mimeType,
524
+ assetUri: resolved.assetUri,
525
+ url: resolved.url,
526
+ sizeBytes: resolved.sizeBytes
527
+ });
528
+ if (resolved.url || resolved.contentBase64) return formatAssetReferenceBlock({
529
+ fileName: resolved.fileName,
530
+ mimeType: resolved.mimeType,
531
+ url: resolved.url,
532
+ sizeBytes: resolved.sizeBytes
533
+ });
534
+ return null;
535
+ }
536
+ function buildNcpUserContent(parts, options = {}) {
537
+ const content = [];
538
+ for (const part of parts) {
539
+ if ((part.type === "text" || part.type === "rich-text") && part.text.trim().length > 0) {
540
+ content.push({
541
+ type: "text",
542
+ text: part.text
543
+ });
544
+ continue;
545
+ }
546
+ if (part.type !== "file") continue;
547
+ const imageContentPart = resolveImageContentPart(part, options.assetStore);
548
+ if (imageContentPart) {
549
+ content.push(imageContentPart);
550
+ const imageAttachmentHint = resolveImageAttachmentHint(part, options.assetStore);
551
+ if (imageAttachmentHint) content.push({
552
+ type: "text",
553
+ text: imageAttachmentHint
554
+ });
555
+ continue;
556
+ }
557
+ const assetReferenceBlock = resolveAssetReferenceBlock(part, options.assetStore);
558
+ if (assetReferenceBlock) content.push({
559
+ type: "text",
560
+ text: assetReferenceBlock
561
+ });
562
+ }
563
+ if (content.length === 0) return "";
564
+ if (content.length === 1 && content[0]?.type === "text") return content[0].text;
565
+ return content;
566
+ }
567
+ //#endregion
568
+ //#region src/runtime/utils/message-converter.utils.ts
569
+ function isRecord$2(value) {
570
+ return Boolean(value) && typeof value === "object" && !Array.isArray(value);
571
+ }
572
+ function isTextLikePart(part) {
573
+ return part.type === "text" || part.type === "rich-text";
574
+ }
575
+ function readText(parts) {
576
+ return parts.filter(isTextLikePart).map((part) => part.text).join("");
577
+ }
578
+ function ncpMessageToOpenAiMessages(rawMessage, options = {}) {
579
+ const message = rawMessage.role === "assistant" ? sanitizeAssistantReplyTags(rawMessage) : rawMessage;
580
+ const parts = message.parts ?? [];
581
+ if (message.role === "user") return [{
582
+ role: "user",
583
+ content: buildNcpUserContent(parts, { assetStore: options.assetStore })
584
+ }];
585
+ if (message.role === "system" || message.role === "service") return [{
586
+ role: "system",
587
+ content: readText(parts)
588
+ }];
589
+ if (message.role === "tool") return [{
590
+ role: "tool",
591
+ content: readText(parts),
592
+ tool_call_id: message.id
593
+ }];
594
+ if (message.role !== "assistant") return [];
595
+ const texts = [];
596
+ const reasonings = [];
597
+ const toolInvocations = [];
598
+ for (const part of parts) {
599
+ if (part.type === "reasoning") reasonings.push(part.text);
600
+ if (part.type === "text") texts.push(part.text);
601
+ if (part.type === "tool-invocation" && part.state === "result" && part.result !== void 0) toolInvocations.push({
602
+ toolCallId: part.toolCallId ?? "",
603
+ toolName: part.toolName,
604
+ args: part.args ?? {},
605
+ result: part.result,
606
+ resultContentItems: part.resultContentItems
607
+ });
608
+ }
609
+ const text = texts.join("");
610
+ const reasoning = reasonings.join("");
611
+ const toolResultContentManager = options.toolResultContentManager ?? defaultToolResultContentManager;
612
+ if (toolInvocations.length === 0) return [{
613
+ role: "assistant",
614
+ content: text,
615
+ ...reasoning ? { reasoning_content: reasoning } : {}
616
+ }];
617
+ return [
618
+ {
619
+ role: "assistant",
620
+ content: text || null,
621
+ ...reasoning ? { reasoning_content: reasoning } : {},
622
+ tool_calls: toolInvocations.map((toolInvocation) => ({
623
+ id: toolInvocation.toolCallId,
624
+ type: "function",
625
+ function: {
626
+ name: toolInvocation.toolName,
627
+ arguments: typeof toolInvocation.args === "string" ? toolInvocation.args : JSON.stringify(toolInvocation.args ?? {})
628
+ }
629
+ }))
630
+ },
631
+ ...toolInvocations.map((toolInvocation) => ({
632
+ role: "tool",
633
+ content: toolResultContentManager.toModelContent(toolInvocation.result, {
634
+ toolCallId: toolInvocation.toolCallId,
635
+ toolName: toolInvocation.toolName
636
+ }),
637
+ tool_call_id: toolInvocation.toolCallId
638
+ })),
639
+ ...toolResultContentManager.toVisualObservationMessages(toolInvocations.map((toolInvocation) => ({
640
+ toolCallId: toolInvocation.toolCallId,
641
+ toolName: toolInvocation.toolName,
642
+ args: isRecord$2(toolInvocation.args) ? toolInvocation.args : null,
643
+ rawArgsText: typeof toolInvocation.args === "string" ? toolInvocation.args : JSON.stringify(toolInvocation.args ?? {}),
644
+ result: toolInvocation.result,
645
+ contentItems: toolInvocation.resultContentItems
646
+ })))
647
+ ];
648
+ }
649
+ //#endregion
650
+ //#region src/runtime/runtime.utils.ts
569
651
  const toolSchemaValidator = new AjvPkg({
570
652
  allErrors: true,
571
653
  strict: false,
@@ -750,9 +832,6 @@ function readOptionalString(value) {
750
832
  const trimmed = value.trim();
751
833
  return trimmed.length > 0 ? trimmed : null;
752
834
  }
753
- function isTextLikePart(part) {
754
- return part.type === "text" || part.type === "rich-text";
755
- }
756
835
  function mergeMessageAndRequestMetadata(input) {
757
836
  const messageMetadata = input.messages.slice().reverse().find((message) => isRecord(message.metadata))?.metadata;
758
837
  return {
@@ -773,73 +852,6 @@ function readRequestedToolNames(metadata) {
773
852
  function isDefaultNcpContextBuilderOptions(value) {
774
853
  return Boolean(value) && typeof value === "object" && !("getToolDefinitions" in value);
775
854
  }
776
- function messageToOpenAI(msg, options) {
777
- const role = msg.role;
778
- const parts = msg.parts ?? [];
779
- if (role === "user" || role === "system") {
780
- if (role === "user") return [{
781
- role,
782
- content: buildNcpUserContent(parts, { assetStore: options.assetStore })
783
- }];
784
- return [{
785
- role,
786
- content: parts.filter(isTextLikePart).map((part) => part.text).join("")
787
- }];
788
- }
789
- if (role === "assistant") {
790
- const texts = [];
791
- const reasonings = [];
792
- const toolInvocations = [];
793
- for (const p of parts) {
794
- if (p.type === "reasoning") reasonings.push(p.text);
795
- if (p.type === "text") texts.push(p.text);
796
- if (p.type === "tool-invocation" && p.state === "result" && p.result !== void 0) toolInvocations.push({
797
- toolCallId: p.toolCallId ?? "",
798
- toolName: p.toolName,
799
- args: p.args ?? {},
800
- result: p.result,
801
- resultContentItems: p.resultContentItems
802
- });
803
- }
804
- const text = texts.join("");
805
- const reasoning = reasonings.join("");
806
- const out = [];
807
- if (toolInvocations.length > 0) {
808
- out.push({
809
- role: "assistant",
810
- content: text || null,
811
- ...reasoning ? { reasoning_content: reasoning } : {},
812
- tool_calls: toolInvocations.map((t) => ({
813
- id: t.toolCallId,
814
- type: "function",
815
- function: {
816
- name: t.toolName,
817
- arguments: typeof t.args === "string" ? t.args : JSON.stringify(t.args ?? {})
818
- }
819
- }))
820
- });
821
- for (const t of toolInvocations) out.push({
822
- role: "tool",
823
- content: typeof t.result === "string" ? t.result : JSON.stringify(t.result),
824
- tool_call_id: t.toolCallId
825
- });
826
- out.push(...defaultToolResultContentManager.toVisualObservationMessages(toolInvocations.map((toolInvocation) => ({
827
- toolCallId: toolInvocation.toolCallId,
828
- toolName: toolInvocation.toolName,
829
- args: isRecord(toolInvocation.args) ? toolInvocation.args : null,
830
- rawArgsText: typeof toolInvocation.args === "string" ? toolInvocation.args : JSON.stringify(toolInvocation.args ?? {}),
831
- result: toolInvocation.result,
832
- contentItems: toolInvocation.resultContentItems
833
- }))));
834
- } else out.push({
835
- role: "assistant",
836
- content: text,
837
- ...reasoning ? { reasoning_content: reasoning } : {}
838
- });
839
- return out;
840
- }
841
- return [];
842
- }
843
855
  var DefaultNcpContextBuilder = class {
844
856
  toolRegistry;
845
857
  assetStore;
@@ -862,8 +874,8 @@ var DefaultNcpContextBuilder = class {
862
874
  role: "system",
863
875
  content: systemPrompt
864
876
  });
865
- for (const msg of sessionMessages.slice(-maxMessages)) messages.push(...messageToOpenAI(msg, { assetStore: this.assetStore }));
866
- for (const msg of input.messages) messages.push(...messageToOpenAI(msg, { assetStore: this.assetStore }));
877
+ for (const msg of sessionMessages.slice(-maxMessages)) messages.push(...ncpMessageToOpenAiMessages(msg, { assetStore: this.assetStore }));
878
+ for (const msg of input.messages) messages.push(...ncpMessageToOpenAiMessages(msg, { assetStore: this.assetStore }));
867
879
  const toolDefinitions = this.toolRegistry?.getToolDefinitions() ?? [];
868
880
  const tools = (requestedToolNames.length > 0 ? toolDefinitions.filter((definition) => requestedToolNames.includes(definition.name)) : toolDefinitions).map(buildOpenAiFunctionTool);
869
881
  return {
@@ -1384,6 +1396,111 @@ function createStreamContentState(reasoningNormalizationMode) {
1384
1396
  };
1385
1397
  }
1386
1398
  //#endregion
1399
+ //#region src/runtime/round-collector.ts
1400
+ var DefaultNcpRoundCollector = class {
1401
+ rawText = "";
1402
+ explicitReasoning = "";
1403
+ toolCallBuffers = /* @__PURE__ */ new Map();
1404
+ constructor(reasoningNormalizationMode = "off") {
1405
+ this.reasoningNormalizationMode = reasoningNormalizationMode;
1406
+ }
1407
+ clear() {
1408
+ this.rawText = "";
1409
+ this.explicitReasoning = "";
1410
+ this.toolCallBuffers.clear();
1411
+ }
1412
+ consumeChunk(chunk) {
1413
+ const choice = chunk.choices?.[0];
1414
+ if (!choice) return;
1415
+ const delta = choice.delta;
1416
+ if (!delta) return;
1417
+ if (typeof delta.content === "string" && delta.content.length > 0) this.rawText += delta.content;
1418
+ const reasoning = delta.reasoning_content ?? delta.reasoning;
1419
+ if (typeof reasoning === "string" && reasoning.length > 0) this.explicitReasoning += reasoning;
1420
+ const toolDeltas = delta.tool_calls;
1421
+ if (!Array.isArray(toolDeltas)) return;
1422
+ for (const toolDelta of toolDeltas) {
1423
+ const index = getToolCallIndex(toolDelta, this.toolCallBuffers.size);
1424
+ const current = applyToolDelta(this.toolCallBuffers.get(index) ?? { argumentsText: "" }, toolDelta);
1425
+ this.toolCallBuffers.set(index, current);
1426
+ }
1427
+ }
1428
+ getText() {
1429
+ if (this.reasoningNormalizationMode !== "think-tags") return this.rawText;
1430
+ return normalizeAssistantText(this.rawText, this.reasoningNormalizationMode).text;
1431
+ }
1432
+ getReasoning() {
1433
+ if (this.explicitReasoning.length > 0) return this.explicitReasoning;
1434
+ if (this.reasoningNormalizationMode !== "think-tags") return "";
1435
+ return normalizeAssistantText(this.rawText, this.reasoningNormalizationMode).reasoning;
1436
+ }
1437
+ getToolCalls() {
1438
+ const orderedEntries = Array.from(this.toolCallBuffers.entries()).sort(([left], [right]) => left - right);
1439
+ const toolCalls = [];
1440
+ for (const [, buffer] of orderedEntries) {
1441
+ if (!buffer.id || !buffer.name) continue;
1442
+ toolCalls.push({
1443
+ toolCallId: buffer.id,
1444
+ toolName: buffer.name,
1445
+ args: buffer.argumentsText
1446
+ });
1447
+ }
1448
+ return toolCalls;
1449
+ }
1450
+ };
1451
+ //#endregion
1452
+ //#region src/runtime/utils/tool-call-execution.utils.ts
1453
+ async function executeCollectedToolCall(options) {
1454
+ const { toolCall, tool } = options;
1455
+ const parsedArgs = parseToolArgs(toolCall.args);
1456
+ if (!parsedArgs.ok) return {
1457
+ toolCallId: toolCall.toolCallId,
1458
+ toolName: toolCall.toolName,
1459
+ args: null,
1460
+ rawArgsText: parsedArgs.rawText,
1461
+ result: createInvalidToolArgumentsResult({
1462
+ toolCallId: toolCall.toolCallId,
1463
+ toolName: toolCall.toolName,
1464
+ rawArgumentsText: parsedArgs.rawText,
1465
+ issues: parsedArgs.issues
1466
+ })
1467
+ };
1468
+ const validationIssues = tool ? [...validateToolArgs(parsedArgs.value, tool.parameters), ...tool.validateArgs?.(parsedArgs.value) ?? []] : [];
1469
+ if (validationIssues.length > 0) return {
1470
+ toolCallId: toolCall.toolCallId,
1471
+ toolName: toolCall.toolName,
1472
+ args: null,
1473
+ rawArgsText: parsedArgs.rawText,
1474
+ result: createInvalidToolArgumentsResult({
1475
+ toolCallId: toolCall.toolCallId,
1476
+ toolName: toolCall.toolName,
1477
+ rawArgumentsText: parsedArgs.rawText,
1478
+ issues: validationIssues
1479
+ })
1480
+ };
1481
+ try {
1482
+ return {
1483
+ toolCallId: toolCall.toolCallId,
1484
+ toolName: toolCall.toolName,
1485
+ args: parsedArgs.value,
1486
+ rawArgsText: parsedArgs.rawText,
1487
+ result: await options.execute(tool, parsedArgs.value)
1488
+ };
1489
+ } catch (error) {
1490
+ return {
1491
+ toolCallId: toolCall.toolCallId,
1492
+ toolName: toolCall.toolName,
1493
+ args: parsedArgs.value,
1494
+ rawArgsText: parsedArgs.rawText,
1495
+ result: createToolExecutionFailedResult({
1496
+ toolCallId: toolCall.toolCallId,
1497
+ toolName: toolCall.toolName,
1498
+ error
1499
+ })
1500
+ };
1501
+ }
1502
+ }
1503
+ //#endregion
1387
1504
  //#region src/runtime/stream-encoder.ts
1388
1505
  /**
1389
1506
  * Converts LLM stream chunks to NCP events (text, reasoning, tool calls).
@@ -1396,6 +1513,11 @@ var DefaultNcpStreamEncoder = class {
1396
1513
  }
1397
1514
  async *encode(stream, context) {
1398
1515
  const { sessionId, messageId } = context;
1516
+ const streamContext = {
1517
+ sessionId,
1518
+ messageId,
1519
+ correlationId: context.correlationId
1520
+ };
1399
1521
  let state = createStreamContentState(this.reasoningNormalizationMode);
1400
1522
  const toolCallBuffers = /* @__PURE__ */ new Map();
1401
1523
  for await (const chunk of stream) {
@@ -1403,39 +1525,18 @@ var DefaultNcpStreamEncoder = class {
1403
1525
  if (!choice) continue;
1404
1526
  const delta = choice.delta;
1405
1527
  if (delta) {
1406
- yield* emitReasoningDelta(delta, {
1407
- sessionId,
1408
- messageId
1409
- });
1410
- state = yield* emitTextDeltas(delta, {
1411
- sessionId,
1412
- messageId
1413
- }, state);
1414
- state = yield* closeTextPartBeforeToolCalls(delta, {
1415
- sessionId,
1416
- messageId
1417
- }, state);
1418
- yield* emitToolCallDeltas(delta, toolCallBuffers, {
1419
- sessionId,
1420
- messageId
1421
- });
1528
+ yield* emitReasoningDelta(delta, streamContext);
1529
+ state = yield* emitTextDeltas(delta, streamContext, state);
1530
+ state = yield* closeTextPartBeforeToolCalls(delta, streamContext, state);
1531
+ yield* emitToolCallDeltas(delta, toolCallBuffers, streamContext);
1422
1532
  }
1423
1533
  const finishReason = choice.finish_reason;
1424
1534
  if (typeof finishReason === "string" && finishReason.trim().length > 0) {
1425
- state = yield* flushTextDeltas({
1426
- sessionId,
1427
- messageId
1428
- }, state);
1429
- yield* flushToolCalls(toolCallBuffers, {
1430
- sessionId,
1431
- messageId
1432
- });
1535
+ state = yield* flushTextDeltas(streamContext, state);
1536
+ yield* flushToolCalls(toolCallBuffers, streamContext);
1433
1537
  if (state.textStarted) yield {
1434
1538
  type: NcpEventType.MessageTextEnd,
1435
- payload: {
1436
- sessionId,
1437
- messageId
1438
- }
1539
+ payload: streamContext
1439
1540
  };
1440
1541
  }
1441
1542
  }
@@ -1506,59 +1607,6 @@ var EchoNcpLLMApi = class {
1506
1607
  };
1507
1608
  };
1508
1609
  //#endregion
1509
- //#region src/runtime/round-collector.ts
1510
- var DefaultNcpRoundCollector = class {
1511
- rawText = "";
1512
- explicitReasoning = "";
1513
- toolCallBuffers = /* @__PURE__ */ new Map();
1514
- constructor(reasoningNormalizationMode = "off") {
1515
- this.reasoningNormalizationMode = reasoningNormalizationMode;
1516
- }
1517
- clear() {
1518
- this.rawText = "";
1519
- this.explicitReasoning = "";
1520
- this.toolCallBuffers.clear();
1521
- }
1522
- consumeChunk(chunk) {
1523
- const choice = chunk.choices?.[0];
1524
- if (!choice) return;
1525
- const delta = choice.delta;
1526
- if (!delta) return;
1527
- if (typeof delta.content === "string" && delta.content.length > 0) this.rawText += delta.content;
1528
- const reasoning = delta.reasoning_content ?? delta.reasoning;
1529
- if (typeof reasoning === "string" && reasoning.length > 0) this.explicitReasoning += reasoning;
1530
- const toolDeltas = delta.tool_calls;
1531
- if (!Array.isArray(toolDeltas)) return;
1532
- for (const toolDelta of toolDeltas) {
1533
- const index = getToolCallIndex(toolDelta, this.toolCallBuffers.size);
1534
- const current = applyToolDelta(this.toolCallBuffers.get(index) ?? { argumentsText: "" }, toolDelta);
1535
- this.toolCallBuffers.set(index, current);
1536
- }
1537
- }
1538
- getText() {
1539
- if (this.reasoningNormalizationMode !== "think-tags") return this.rawText;
1540
- return normalizeAssistantText(this.rawText, this.reasoningNormalizationMode).text;
1541
- }
1542
- getReasoning() {
1543
- if (this.explicitReasoning.length > 0) return this.explicitReasoning;
1544
- if (this.reasoningNormalizationMode !== "think-tags") return "";
1545
- return normalizeAssistantText(this.rawText, this.reasoningNormalizationMode).reasoning;
1546
- }
1547
- getToolCalls() {
1548
- const orderedEntries = Array.from(this.toolCallBuffers.entries()).sort(([left], [right]) => left - right);
1549
- const toolCalls = [];
1550
- for (const [, buffer] of orderedEntries) {
1551
- if (!buffer.id || !buffer.name) continue;
1552
- toolCalls.push({
1553
- toolCallId: buffer.id,
1554
- toolName: buffer.name,
1555
- args: buffer.argumentsText
1556
- });
1557
- }
1558
- return toolCalls;
1559
- }
1560
- };
1561
- //#endregion
1562
1610
  //#region src/runtime/agent-runtime.service.ts
1563
1611
  var DefaultNcpAgentRuntime = class {
1564
1612
  contextBuilder;
@@ -1656,56 +1704,11 @@ var DefaultNcpAgentRuntime = class {
1656
1704
  }
1657
1705
  };
1658
1706
  executeToolCall = async function(toolCall) {
1659
- const tool = this.toolRegistry.getTool(toolCall.toolName);
1660
- const parsedArgs = parseToolArgs(toolCall.args);
1661
- if (!parsedArgs.ok) return {
1662
- toolCallId: toolCall.toolCallId,
1663
- toolName: toolCall.toolName,
1664
- args: null,
1665
- rawArgsText: parsedArgs.rawText,
1666
- result: createInvalidToolArgumentsResult({
1667
- toolCallId: toolCall.toolCallId,
1668
- toolName: toolCall.toolName,
1669
- rawArgumentsText: parsedArgs.rawText,
1670
- issues: parsedArgs.issues
1671
- })
1672
- };
1673
- const validationIssues = this.resolveValidationIssues(parsedArgs.value, tool);
1674
- if (validationIssues.length > 0) return {
1675
- toolCallId: toolCall.toolCallId,
1676
- toolName: toolCall.toolName,
1677
- args: null,
1678
- rawArgsText: parsedArgs.rawText,
1679
- result: createInvalidToolArgumentsResult({
1680
- toolCallId: toolCall.toolCallId,
1681
- toolName: toolCall.toolName,
1682
- rawArgumentsText: parsedArgs.rawText,
1683
- issues: validationIssues
1684
- })
1685
- };
1686
- return {
1687
- toolCallId: toolCall.toolCallId,
1688
- toolName: toolCall.toolName,
1689
- args: parsedArgs.value,
1690
- rawArgsText: parsedArgs.rawText,
1691
- result: await this.executeValidatedToolCall(toolCall, parsedArgs.value)
1692
- };
1693
- };
1694
- resolveValidationIssues = function(args, tool) {
1695
- const schemaIssues = validateToolArgs(args, tool?.parameters);
1696
- if (schemaIssues.length > 0) return schemaIssues;
1697
- return typeof tool?.validateArgs === "function" ? tool.validateArgs(args) : [];
1698
- };
1699
- executeValidatedToolCall = async function(toolCall, args) {
1700
- try {
1701
- return await this.toolRegistry.execute(toolCall.toolCallId, toolCall.toolName, args);
1702
- } catch (error) {
1703
- return createToolExecutionFailedResult({
1704
- toolCallId: toolCall.toolCallId,
1705
- toolName: toolCall.toolName,
1706
- error
1707
- });
1708
- }
1707
+ return executeCollectedToolCall({
1708
+ toolCall,
1709
+ tool: this.toolRegistry.getTool(toolCall.toolName),
1710
+ execute: (_tool, args) => this.toolRegistry.execute(toolCall.toolCallId, toolCall.toolName, args)
1711
+ });
1709
1712
  };
1710
1713
  tapStream = async function* (stream, onChunk) {
1711
1714
  for await (const chunk of stream) {
@@ -1715,6 +1718,6 @@ var DefaultNcpAgentRuntime = class {
1715
1718
  };
1716
1719
  };
1717
1720
  //#endregion
1718
- export { DefaultNcpAgentRuntime, DefaultNcpContextBuilder, DefaultNcpRoundBuffer, DefaultNcpStreamEncoder, DefaultNcpToolRegistry, EchoNcpLLMApi, LocalAssetStore, ToolResultContentManager, appendToolRoundToInput, assertOpenAiFunctionParametersSchema, buildAssetContentPath, buildNcpUserContent, buildOpenAiFunctionTool, createInvalidToolArgumentsResult, createToolExecutionFailedResult, defaultToolResultContentManager, genId, getOpenAiFunctionParametersSchemaIssues, isTextLikeAsset, parseToolArgs, validateToolArgs };
1721
+ export { DefaultNcpAgentRuntime, DefaultNcpContextBuilder, DefaultNcpRoundBuffer, DefaultNcpRoundCollector, DefaultNcpStreamEncoder, DefaultNcpToolRegistry, EchoNcpLLMApi, LocalAssetStore, ToolResultContentManager, appendToolRoundToInput, assertOpenAiFunctionParametersSchema, buildAssetContentPath, buildNcpUserContent, buildOpenAiFunctionTool, createInvalidToolArgumentsResult, createToolExecutionFailedResult, defaultToolResultContentManager, executeCollectedToolCall, genId, getOpenAiFunctionParametersSchemaIssues, isTextLikeAsset, ncpMessageToOpenAiMessages, parseToolArgs, validateToolArgs };
1719
1722
 
1720
1723
  //# sourceMappingURL=index.js.map