@nextclaw/ncp 0.2.0 → 0.3.1
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.ts +53 -2
- package/dist/index.js +275 -1
- package/package.json +1 -1
package/dist/index.d.ts
CHANGED
|
@@ -222,6 +222,7 @@ type NcpSessionSummary = {
|
|
|
222
222
|
messageCount: number;
|
|
223
223
|
updatedAt: string;
|
|
224
224
|
status?: NcpSessionStatus;
|
|
225
|
+
metadata?: Record<string, unknown>;
|
|
225
226
|
};
|
|
226
227
|
type ListSessionsOptions = {
|
|
227
228
|
limit?: number;
|
|
@@ -231,6 +232,9 @@ type ListMessagesOptions = {
|
|
|
231
232
|
limit?: number;
|
|
232
233
|
cursor?: string;
|
|
233
234
|
};
|
|
235
|
+
type NcpSessionPatch = {
|
|
236
|
+
metadata?: Record<string, unknown> | null;
|
|
237
|
+
};
|
|
234
238
|
/**
|
|
235
239
|
* API for session list, message history, and session lifecycle.
|
|
236
240
|
* Implementations that support persistence can provide this alongside NcpAgentClientEndpoint.
|
|
@@ -239,6 +243,7 @@ interface NcpSessionApi {
|
|
|
239
243
|
listSessions(options?: ListSessionsOptions): Promise<NcpSessionSummary[]>;
|
|
240
244
|
listSessionMessages(sessionId: string, options?: ListMessagesOptions): Promise<NcpMessage[]>;
|
|
241
245
|
getSession(sessionId: string): Promise<NcpSessionSummary | null>;
|
|
246
|
+
updateSession(sessionId: string, patch: NcpSessionPatch): Promise<NcpSessionSummary | null>;
|
|
242
247
|
deleteSession(sessionId: string): Promise<void>;
|
|
243
248
|
}
|
|
244
249
|
|
|
@@ -668,6 +673,7 @@ type NcpAgentRunInput = {
|
|
|
668
673
|
sessionId: string;
|
|
669
674
|
messages: ReadonlyArray<NcpMessage>;
|
|
670
675
|
correlationId?: string;
|
|
676
|
+
metadata?: Record<string, unknown>;
|
|
671
677
|
};
|
|
672
678
|
type NcpAgentRunOptions = {
|
|
673
679
|
signal?: AbortSignal;
|
|
@@ -703,6 +709,7 @@ type OpenAIChatMessage = {
|
|
|
703
709
|
} | {
|
|
704
710
|
role: "assistant";
|
|
705
711
|
content?: string | null;
|
|
712
|
+
reasoning_content?: string;
|
|
706
713
|
tool_calls?: OpenAIToolCall[];
|
|
707
714
|
} | {
|
|
708
715
|
role: "tool";
|
|
@@ -748,6 +755,7 @@ type NcpLLMApiInput = {
|
|
|
748
755
|
messages: OpenAIChatMessage[];
|
|
749
756
|
tools?: OpenAITool[];
|
|
750
757
|
model?: string;
|
|
758
|
+
thinkingLevel?: string | null;
|
|
751
759
|
max_tokens?: number;
|
|
752
760
|
};
|
|
753
761
|
type NcpLLMApiOptions = {
|
|
@@ -781,9 +789,21 @@ interface NcpTool {
|
|
|
781
789
|
type NcpToolCallResult = {
|
|
782
790
|
toolCallId: string;
|
|
783
791
|
toolName: string;
|
|
784
|
-
args: unknown;
|
|
792
|
+
args: Record<string, unknown> | null;
|
|
793
|
+
rawArgsText: string;
|
|
785
794
|
result: unknown;
|
|
786
795
|
};
|
|
796
|
+
type NcpInvalidToolArgumentsResult = {
|
|
797
|
+
ok: false;
|
|
798
|
+
error: {
|
|
799
|
+
code: "invalid_tool_arguments";
|
|
800
|
+
message: string;
|
|
801
|
+
toolCallId: string;
|
|
802
|
+
toolName: string;
|
|
803
|
+
rawArgumentsText: string;
|
|
804
|
+
issues: string[];
|
|
805
|
+
};
|
|
806
|
+
};
|
|
787
807
|
interface NcpToolRegistry {
|
|
788
808
|
listTools(): ReadonlyArray<NcpTool>;
|
|
789
809
|
getTool(name: string): NcpTool | undefined;
|
|
@@ -916,4 +936,35 @@ interface NcpAgentConversationStateManager extends NcpConversationStateManager {
|
|
|
916
936
|
handleEndpointError(payload: NcpError): void;
|
|
917
937
|
}
|
|
918
938
|
|
|
919
|
-
|
|
939
|
+
type NcpReplyTagParseResult = {
|
|
940
|
+
content: string;
|
|
941
|
+
replyTo?: string;
|
|
942
|
+
};
|
|
943
|
+
declare function stripReplyTagsFromText(content: string, currentMessageId?: string): NcpReplyTagParseResult;
|
|
944
|
+
declare function sanitizeAssistantReplyTags(message: NcpMessage, currentMessageId?: string): NcpMessage;
|
|
945
|
+
|
|
946
|
+
type NcpAssistantReasoningNormalizationMode = "off" | "think-tags";
|
|
947
|
+
type NcpAssistantReasoningSegment = {
|
|
948
|
+
type: "text" | "reasoning";
|
|
949
|
+
text: string;
|
|
950
|
+
};
|
|
951
|
+
declare function readAssistantReasoningNormalizationMode(value: unknown): NcpAssistantReasoningNormalizationMode | null;
|
|
952
|
+
declare function readAssistantReasoningNormalizationModeFromMetadata(metadata: Record<string, unknown> | null | undefined): NcpAssistantReasoningNormalizationMode | null;
|
|
953
|
+
declare function writeAssistantReasoningNormalizationModeToMetadata(metadata: Record<string, unknown>, mode: NcpAssistantReasoningNormalizationMode): Record<string, unknown>;
|
|
954
|
+
declare class NcpAssistantTextStreamNormalizer {
|
|
955
|
+
private readonly mode;
|
|
956
|
+
private buffer;
|
|
957
|
+
private phase;
|
|
958
|
+
private stripLeadingTextControlTags;
|
|
959
|
+
constructor(mode?: NcpAssistantReasoningNormalizationMode);
|
|
960
|
+
push(delta: string): NcpAssistantReasoningSegment[];
|
|
961
|
+
finish(): NcpAssistantReasoningSegment[];
|
|
962
|
+
private flush;
|
|
963
|
+
}
|
|
964
|
+
declare function normalizeAssistantText(text: string, mode: NcpAssistantReasoningNormalizationMode): {
|
|
965
|
+
text: string;
|
|
966
|
+
reasoning: string;
|
|
967
|
+
parts: NcpAssistantReasoningSegment[];
|
|
968
|
+
};
|
|
969
|
+
|
|
970
|
+
export { type ListMessagesOptions, type ListSessionsOptions, type NcpActionPart, type NcpAgentClientEndpoint, type NcpAgentConversationHydrationParams, type NcpAgentConversationSnapshot, type NcpAgentConversationStateManager, type NcpAgentRunApi, type NcpAgentRunInput, type NcpAgentRunOptions, type NcpAgentRunSendOptions, type NcpAgentRunStreamOptions, type NcpAgentRuntime, type NcpAgentServerEndpoint, type NcpAgentStreamProvider, type NcpAssistantReasoningNormalizationMode, type NcpAssistantReasoningSegment, NcpAssistantTextStreamNormalizer, type NcpCardPart, type NcpCompletedEnvelope, type NcpContextBuilder, type NcpContextPrepareOptions, type NcpConversationSnapshot, type NcpConversationStateManager, type NcpEncodeContext, type NcpEndpoint, type NcpEndpointEvent, type NcpEndpointKind, type NcpEndpointLatency, type NcpEndpointManifest, type NcpEndpointSubscriber, type NcpError, type NcpErrorCode, NcpEventType, type NcpExtensionPart, type NcpFailedEnvelope, type NcpFilePart, type NcpInvalidToolArgumentsResult, type NcpLLMApi, type NcpLLMApiInput, type NcpLLMApiOptions, type NcpMessage, type NcpMessageAbortPayload, type NcpMessageAcceptedPayload, type NcpMessageDeliveredPayload, type NcpMessagePart, type NcpMessageReactionPayload, type NcpMessageReadPayload, type NcpMessageRecalledPayload, type NcpMessageRole, type NcpMessageSentPayload, type NcpMessageStatus, type NcpPendingToolCall, type NcpPresenceUpdatedPayload, type NcpReasoningDeltaPayload, type NcpReasoningEndPayload, type NcpReasoningPart, type NcpReasoningStartPayload, type NcpReplyTagParseResult, type NcpRequestEnvelope, type NcpResponseEnvelope, type NcpRichTextPart, type NcpRoundBuffer, type NcpRunContext, type NcpRunErrorPayload, type NcpRunFinalMetadata, type NcpRunFinishedPayload, type NcpRunMetadataPayload, type NcpRunReadyMetadata, type NcpRunStartedPayload, type NcpSessionApi, type NcpSessionPatch, type NcpSessionStatus, type NcpSessionSummary, type NcpSourcePart, type NcpStepStartPart, type NcpStreamEncoder, type NcpStreamRequestPayload, type NcpTextDeltaPayload, type NcpTextEndPayload, type NcpTextPart, type NcpTextStartPayload, type NcpTool, type NcpToolCallArgsDeltaPayload, type NcpToolCallArgsPayload, type NcpToolCallEndPayload, type NcpToolCallResult, type NcpToolCallResultPayload, type NcpToolCallStartPayload, type NcpToolDefinition, type NcpToolInvocationPart, type NcpToolRegistry, type NcpTypingEndPayload, type NcpTypingStartPayload, type OpenAIChatChunk, type OpenAIChatMessage, type OpenAIContentPart, type OpenAITool, type OpenAIToolCall, type OpenAIToolCallDelta, normalizeAssistantText, readAssistantReasoningNormalizationMode, readAssistantReasoningNormalizationModeFromMetadata, sanitizeAssistantReplyTags, stripReplyTagsFromText, writeAssistantReasoningNormalizationModeToMetadata };
|
package/dist/index.js
CHANGED
|
@@ -34,6 +34,280 @@ var NcpEventType = /* @__PURE__ */ ((NcpEventType2) => {
|
|
|
34
34
|
NcpEventType2["PresenceUpdated"] = "presence.updated";
|
|
35
35
|
return NcpEventType2;
|
|
36
36
|
})(NcpEventType || {});
|
|
37
|
+
|
|
38
|
+
// src/toolkit/reply-tags.ts
|
|
39
|
+
var REPLY_TO_CURRENT_PATTERN = /\[\[\s*reply_to_current\s*\]\]/gi;
|
|
40
|
+
var REPLY_TO_ID_PATTERN = /\[\[\s*reply_to\s*:\s*([^\]]+?)\s*\]\]/i;
|
|
41
|
+
function normalizeReplyTarget(value) {
|
|
42
|
+
if (typeof value !== "string") {
|
|
43
|
+
return void 0;
|
|
44
|
+
}
|
|
45
|
+
const trimmed = value.trim();
|
|
46
|
+
return trimmed.length > 0 ? trimmed : void 0;
|
|
47
|
+
}
|
|
48
|
+
function stripReplyTagsFromText(content, currentMessageId) {
|
|
49
|
+
let nextContent = content;
|
|
50
|
+
let replyTo;
|
|
51
|
+
if (REPLY_TO_CURRENT_PATTERN.test(nextContent)) {
|
|
52
|
+
replyTo = normalizeReplyTarget(currentMessageId);
|
|
53
|
+
nextContent = nextContent.replace(REPLY_TO_CURRENT_PATTERN, "").trim();
|
|
54
|
+
}
|
|
55
|
+
const explicitReplyTarget = nextContent.match(REPLY_TO_ID_PATTERN)?.[1];
|
|
56
|
+
if (explicitReplyTarget) {
|
|
57
|
+
replyTo = normalizeReplyTarget(explicitReplyTarget);
|
|
58
|
+
nextContent = nextContent.replace(REPLY_TO_ID_PATTERN, "").trim();
|
|
59
|
+
}
|
|
60
|
+
return replyTo ? { content: nextContent, replyTo } : { content: nextContent };
|
|
61
|
+
}
|
|
62
|
+
function sanitizeAssistantReplyTags(message, currentMessageId = message.id) {
|
|
63
|
+
if (message.role !== "assistant") {
|
|
64
|
+
return {
|
|
65
|
+
...message,
|
|
66
|
+
parts: [...message.parts],
|
|
67
|
+
metadata: message.metadata ? { ...message.metadata } : void 0
|
|
68
|
+
};
|
|
69
|
+
}
|
|
70
|
+
const firstTextIndex = message.parts.findIndex((part) => part.type === "text");
|
|
71
|
+
const nextMetadata = message.metadata ? { ...message.metadata } : void 0;
|
|
72
|
+
const existingReplyTo = normalizeReplyTarget(nextMetadata?.reply_to);
|
|
73
|
+
if (firstTextIndex < 0) {
|
|
74
|
+
return {
|
|
75
|
+
...message,
|
|
76
|
+
parts: [...message.parts],
|
|
77
|
+
metadata: nextMetadata
|
|
78
|
+
};
|
|
79
|
+
}
|
|
80
|
+
const firstTextPart = message.parts[firstTextIndex];
|
|
81
|
+
if (!firstTextPart || firstTextPart.type !== "text") {
|
|
82
|
+
return {
|
|
83
|
+
...message,
|
|
84
|
+
parts: [...message.parts],
|
|
85
|
+
metadata: nextMetadata
|
|
86
|
+
};
|
|
87
|
+
}
|
|
88
|
+
const { content, replyTo } = stripReplyTagsFromText(firstTextPart.text, currentMessageId);
|
|
89
|
+
const effectiveReplyTo = replyTo ?? existingReplyTo;
|
|
90
|
+
const nextParts = message.parts.flatMap((part, index) => {
|
|
91
|
+
if (index !== firstTextIndex || part.type !== "text") {
|
|
92
|
+
return [part];
|
|
93
|
+
}
|
|
94
|
+
if (content.length === 0) {
|
|
95
|
+
return [];
|
|
96
|
+
}
|
|
97
|
+
return [{ ...part, text: content }];
|
|
98
|
+
});
|
|
99
|
+
if (effectiveReplyTo) {
|
|
100
|
+
return {
|
|
101
|
+
...message,
|
|
102
|
+
parts: nextParts,
|
|
103
|
+
metadata: {
|
|
104
|
+
...nextMetadata,
|
|
105
|
+
reply_to: effectiveReplyTo
|
|
106
|
+
}
|
|
107
|
+
};
|
|
108
|
+
}
|
|
109
|
+
return {
|
|
110
|
+
...message,
|
|
111
|
+
parts: nextParts,
|
|
112
|
+
metadata: nextMetadata
|
|
113
|
+
};
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
// src/toolkit/reasoning-normalization.ts
|
|
117
|
+
var THINK_OPEN_TAG = "<think>";
|
|
118
|
+
var THINK_CLOSE_TAG = "</think>";
|
|
119
|
+
var FINAL_OPEN_TAG = "<final>";
|
|
120
|
+
var FINAL_CLOSE_TAG = "</final>";
|
|
121
|
+
var LEADING_CONTROL_TAGS = [THINK_CLOSE_TAG, FINAL_OPEN_TAG, FINAL_CLOSE_TAG];
|
|
122
|
+
var MAX_REASONING_DELIMITER_TAIL = THINK_CLOSE_TAG.length - 1;
|
|
123
|
+
function isRecord(value) {
|
|
124
|
+
return Boolean(value) && typeof value === "object" && !Array.isArray(value);
|
|
125
|
+
}
|
|
126
|
+
function isWhitespace(char) {
|
|
127
|
+
return /\s/.test(char);
|
|
128
|
+
}
|
|
129
|
+
function normalizeMode(value) {
|
|
130
|
+
if (value === "off" || value === "think-tags") {
|
|
131
|
+
return value;
|
|
132
|
+
}
|
|
133
|
+
return null;
|
|
134
|
+
}
|
|
135
|
+
function readLeadingThinkTagState(buffer) {
|
|
136
|
+
let cursor = 0;
|
|
137
|
+
while (cursor < buffer.length && isWhitespace(buffer[cursor])) {
|
|
138
|
+
cursor += 1;
|
|
139
|
+
}
|
|
140
|
+
const rest = buffer.slice(cursor);
|
|
141
|
+
if (rest.startsWith(THINK_OPEN_TAG)) {
|
|
142
|
+
return {
|
|
143
|
+
status: "matched",
|
|
144
|
+
consumed: cursor + THINK_OPEN_TAG.length
|
|
145
|
+
};
|
|
146
|
+
}
|
|
147
|
+
if (THINK_OPEN_TAG.startsWith(rest)) {
|
|
148
|
+
return { status: "pending" };
|
|
149
|
+
}
|
|
150
|
+
return { status: "rejected" };
|
|
151
|
+
}
|
|
152
|
+
function stripLeadingControlTags(buffer) {
|
|
153
|
+
let nextBuffer = buffer;
|
|
154
|
+
while (true) {
|
|
155
|
+
let cursor = 0;
|
|
156
|
+
while (cursor < nextBuffer.length && isWhitespace(nextBuffer[cursor])) {
|
|
157
|
+
cursor += 1;
|
|
158
|
+
}
|
|
159
|
+
const rest = nextBuffer.slice(cursor);
|
|
160
|
+
if (rest.length === 0) {
|
|
161
|
+
return { buffer: "", pending: false };
|
|
162
|
+
}
|
|
163
|
+
const matchedTag = LEADING_CONTROL_TAGS.find((tag) => rest.startsWith(tag));
|
|
164
|
+
if (matchedTag) {
|
|
165
|
+
nextBuffer = rest.slice(matchedTag.length);
|
|
166
|
+
continue;
|
|
167
|
+
}
|
|
168
|
+
if (LEADING_CONTROL_TAGS.some((tag) => tag.startsWith(rest))) {
|
|
169
|
+
return { buffer: rest, pending: true };
|
|
170
|
+
}
|
|
171
|
+
return { buffer: rest, pending: false };
|
|
172
|
+
}
|
|
173
|
+
}
|
|
174
|
+
function findReasoningBoundary(buffer) {
|
|
175
|
+
const indices = [
|
|
176
|
+
{ index: buffer.indexOf(THINK_CLOSE_TAG), tag: THINK_CLOSE_TAG },
|
|
177
|
+
{ index: buffer.indexOf(FINAL_OPEN_TAG), tag: FINAL_OPEN_TAG }
|
|
178
|
+
].filter((entry) => entry.index >= 0);
|
|
179
|
+
if (indices.length === 0) {
|
|
180
|
+
return null;
|
|
181
|
+
}
|
|
182
|
+
return indices.reduce((left, right) => right.index < left.index ? right : left);
|
|
183
|
+
}
|
|
184
|
+
function readAssistantReasoningNormalizationMode(value) {
|
|
185
|
+
if (typeof value === "string") {
|
|
186
|
+
return normalizeMode(value);
|
|
187
|
+
}
|
|
188
|
+
if (isRecord(value)) {
|
|
189
|
+
return normalizeMode(value.mode);
|
|
190
|
+
}
|
|
191
|
+
return null;
|
|
192
|
+
}
|
|
193
|
+
function readAssistantReasoningNormalizationModeFromMetadata(metadata) {
|
|
194
|
+
if (!metadata) {
|
|
195
|
+
return null;
|
|
196
|
+
}
|
|
197
|
+
return readAssistantReasoningNormalizationMode(metadata.reasoning_normalization) ?? readAssistantReasoningNormalizationMode(metadata.reasoningNormalization) ?? normalizeMode(metadata.reasoning_normalization_mode) ?? normalizeMode(metadata.reasoningNormalizationMode);
|
|
198
|
+
}
|
|
199
|
+
function writeAssistantReasoningNormalizationModeToMetadata(metadata, mode) {
|
|
200
|
+
const nextMetadata = {
|
|
201
|
+
...metadata
|
|
202
|
+
};
|
|
203
|
+
delete nextMetadata.reasoningNormalization;
|
|
204
|
+
delete nextMetadata.reasoningNormalizationMode;
|
|
205
|
+
delete nextMetadata.reasoning_normalization_mode;
|
|
206
|
+
nextMetadata.reasoning_normalization = { mode };
|
|
207
|
+
return nextMetadata;
|
|
208
|
+
}
|
|
209
|
+
var NcpAssistantTextStreamNormalizer = class {
|
|
210
|
+
constructor(mode = "off") {
|
|
211
|
+
this.mode = mode;
|
|
212
|
+
}
|
|
213
|
+
buffer = "";
|
|
214
|
+
phase = "initial";
|
|
215
|
+
stripLeadingTextControlTags = false;
|
|
216
|
+
push(delta) {
|
|
217
|
+
if (!delta) {
|
|
218
|
+
return [];
|
|
219
|
+
}
|
|
220
|
+
if (this.mode !== "think-tags") {
|
|
221
|
+
return [{ type: "text", text: delta }];
|
|
222
|
+
}
|
|
223
|
+
this.buffer += delta;
|
|
224
|
+
return this.flush(false);
|
|
225
|
+
}
|
|
226
|
+
finish() {
|
|
227
|
+
if (this.mode !== "think-tags") {
|
|
228
|
+
return [];
|
|
229
|
+
}
|
|
230
|
+
return this.flush(true);
|
|
231
|
+
}
|
|
232
|
+
flush(final) {
|
|
233
|
+
const segments = [];
|
|
234
|
+
while (true) {
|
|
235
|
+
if (this.phase === "initial") {
|
|
236
|
+
const leadingState = readLeadingThinkTagState(this.buffer);
|
|
237
|
+
if (leadingState.status === "matched") {
|
|
238
|
+
this.buffer = this.buffer.slice(leadingState.consumed);
|
|
239
|
+
this.phase = "reasoning";
|
|
240
|
+
continue;
|
|
241
|
+
}
|
|
242
|
+
if (leadingState.status === "pending" && !final) {
|
|
243
|
+
return segments;
|
|
244
|
+
}
|
|
245
|
+
this.phase = "text";
|
|
246
|
+
continue;
|
|
247
|
+
}
|
|
248
|
+
if (this.phase === "reasoning") {
|
|
249
|
+
const boundary = findReasoningBoundary(this.buffer);
|
|
250
|
+
if (boundary) {
|
|
251
|
+
const reasoningText = this.buffer.slice(0, boundary.index);
|
|
252
|
+
if (reasoningText.length > 0) {
|
|
253
|
+
segments.push({ type: "reasoning", text: reasoningText });
|
|
254
|
+
}
|
|
255
|
+
this.buffer = this.buffer.slice(boundary.index + boundary.tag.length);
|
|
256
|
+
this.phase = "text";
|
|
257
|
+
this.stripLeadingTextControlTags = true;
|
|
258
|
+
continue;
|
|
259
|
+
}
|
|
260
|
+
const safeLength = final ? this.buffer.length : Math.max(0, this.buffer.length - MAX_REASONING_DELIMITER_TAIL);
|
|
261
|
+
if (safeLength === 0) {
|
|
262
|
+
return segments;
|
|
263
|
+
}
|
|
264
|
+
segments.push({
|
|
265
|
+
type: "reasoning",
|
|
266
|
+
text: this.buffer.slice(0, safeLength)
|
|
267
|
+
});
|
|
268
|
+
this.buffer = this.buffer.slice(safeLength);
|
|
269
|
+
if (!final) {
|
|
270
|
+
return segments;
|
|
271
|
+
}
|
|
272
|
+
continue;
|
|
273
|
+
}
|
|
274
|
+
if (this.stripLeadingTextControlTags) {
|
|
275
|
+
const stripped = stripLeadingControlTags(this.buffer);
|
|
276
|
+
if (stripped.pending && !final) {
|
|
277
|
+
this.buffer = stripped.buffer;
|
|
278
|
+
return segments;
|
|
279
|
+
}
|
|
280
|
+
this.buffer = stripped.buffer;
|
|
281
|
+
this.stripLeadingTextControlTags = false;
|
|
282
|
+
}
|
|
283
|
+
if (this.buffer.length === 0) {
|
|
284
|
+
return segments;
|
|
285
|
+
}
|
|
286
|
+
segments.push({
|
|
287
|
+
type: "text",
|
|
288
|
+
text: this.buffer
|
|
289
|
+
});
|
|
290
|
+
this.buffer = "";
|
|
291
|
+
return segments;
|
|
292
|
+
}
|
|
293
|
+
}
|
|
294
|
+
};
|
|
295
|
+
function normalizeAssistantText(text, mode) {
|
|
296
|
+
const normalizer = new NcpAssistantTextStreamNormalizer(mode);
|
|
297
|
+
const parts = [...normalizer.push(text), ...normalizer.finish()].filter((part) => part.text.length > 0);
|
|
298
|
+
return {
|
|
299
|
+
text: parts.filter((part) => part.type === "text").map((part) => part.text).join(""),
|
|
300
|
+
reasoning: parts.filter((part) => part.type === "reasoning").map((part) => part.text).join(""),
|
|
301
|
+
parts
|
|
302
|
+
};
|
|
303
|
+
}
|
|
37
304
|
export {
|
|
38
|
-
|
|
305
|
+
NcpAssistantTextStreamNormalizer,
|
|
306
|
+
NcpEventType,
|
|
307
|
+
normalizeAssistantText,
|
|
308
|
+
readAssistantReasoningNormalizationMode,
|
|
309
|
+
readAssistantReasoningNormalizationModeFromMetadata,
|
|
310
|
+
sanitizeAssistantReplyTags,
|
|
311
|
+
stripReplyTagsFromText,
|
|
312
|
+
writeAssistantReasoningNormalizationModeToMetadata
|
|
39
313
|
};
|