@ai-sdk-tool/middleware 0.0.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.
@@ -0,0 +1,210 @@
1
+ // src/reasoning-parser/index.ts
2
+ function getPotentialStartIndex(text, searchedText) {
3
+ if (searchedText.length === 0) {
4
+ return null;
5
+ }
6
+ const directIndex = text.indexOf(searchedText);
7
+ if (directIndex !== -1) {
8
+ return directIndex;
9
+ }
10
+ for (let i = text.length - 1; i >= 0; i -= 1) {
11
+ const suffix = text.substring(i);
12
+ if (searchedText.startsWith(suffix)) {
13
+ return i;
14
+ }
15
+ }
16
+ return null;
17
+ }
18
+ function extractReasoningMiddleware({
19
+ openingTag,
20
+ closingTag,
21
+ separator = "\n",
22
+ startWithReasoning = false
23
+ }) {
24
+ function processTextPart(text, transformedContent) {
25
+ var _a;
26
+ const regexp = new RegExp(`${openingTag}(.*?)${closingTag}`, "gs");
27
+ const matches = Array.from(text.matchAll(regexp));
28
+ if (!matches.length) {
29
+ return;
30
+ }
31
+ const reasoningText = matches.map((match) => match[1]).join(separator);
32
+ let textWithoutReasoning = text;
33
+ for (let i = matches.length - 1; i >= 0; i -= 1) {
34
+ const match = matches[i];
35
+ const beforeMatch = textWithoutReasoning.slice(0, match.index);
36
+ const matchIndex = (_a = match.index) != null ? _a : 0;
37
+ const afterMatch = textWithoutReasoning.slice(
38
+ matchIndex + match[0].length
39
+ );
40
+ textWithoutReasoning = beforeMatch + (beforeMatch.length > 0 && afterMatch.length > 0 ? separator : "") + afterMatch;
41
+ }
42
+ transformedContent.push({
43
+ type: "reasoning",
44
+ text: reasoningText
45
+ });
46
+ transformedContent.push({
47
+ type: "text",
48
+ text: textWithoutReasoning
49
+ });
50
+ }
51
+ return {
52
+ specificationVersion: "v3",
53
+ wrapGenerate: async ({ doGenerate }) => {
54
+ const { content, ...rest } = await doGenerate();
55
+ const transformedContent = [];
56
+ for (const part of content) {
57
+ if (part.type !== "text") {
58
+ transformedContent.push(part);
59
+ continue;
60
+ }
61
+ const text = startWithReasoning ? openingTag + part.text : part.text;
62
+ const regexp = new RegExp(`${openingTag}(.*?)${closingTag}`, "gs");
63
+ const matches = Array.from(text.matchAll(regexp));
64
+ if (!matches.length) {
65
+ transformedContent.push(part);
66
+ continue;
67
+ }
68
+ processTextPart(text, transformedContent);
69
+ }
70
+ return { content: transformedContent, ...rest };
71
+ },
72
+ wrapStream: async ({ doStream }) => {
73
+ const { stream, ...rest } = await doStream();
74
+ const reasoningExtractions = {};
75
+ function createPublisher(activeExtraction, controller) {
76
+ return (text) => {
77
+ if (text.length === 0) {
78
+ return;
79
+ }
80
+ const prefix = getPrefix(activeExtraction);
81
+ enqueueReasoningStart(activeExtraction, controller);
82
+ enqueueDelta(activeExtraction, controller, prefix, text);
83
+ updateExtractionState(activeExtraction);
84
+ };
85
+ }
86
+ function getPrefix(activeExtraction) {
87
+ return activeExtraction.afterSwitch && (activeExtraction.isReasoning ? !activeExtraction.isFirstReasoning : !activeExtraction.isFirstText) ? separator : "";
88
+ }
89
+ function enqueueReasoningStart(activeExtraction, controller) {
90
+ if (activeExtraction.afterSwitch && activeExtraction.isReasoning || activeExtraction.isFirstReasoning) {
91
+ controller.enqueue({
92
+ type: "reasoning-start",
93
+ id: `reasoning-${activeExtraction.idCounter}`
94
+ });
95
+ }
96
+ }
97
+ function enqueueDelta(activeExtraction, controller, prefix, text) {
98
+ controller.enqueue(
99
+ activeExtraction.isReasoning ? {
100
+ type: "reasoning-delta",
101
+ delta: prefix + text,
102
+ id: `reasoning-${activeExtraction.idCounter}`
103
+ } : {
104
+ type: "text-delta",
105
+ delta: prefix + text,
106
+ id: activeExtraction.textId
107
+ }
108
+ );
109
+ }
110
+ function updateExtractionState(activeExtraction) {
111
+ activeExtraction.afterSwitch = false;
112
+ if (activeExtraction.isReasoning) {
113
+ activeExtraction.isFirstReasoning = false;
114
+ } else {
115
+ activeExtraction.isFirstText = false;
116
+ }
117
+ }
118
+ function handleFullMatch(activeExtraction, controller, startIndex, nextTag) {
119
+ activeExtraction.buffer = activeExtraction.buffer.slice(
120
+ startIndex + nextTag.length
121
+ );
122
+ if (activeExtraction.isReasoning) {
123
+ controller.enqueue({
124
+ type: "reasoning-end",
125
+ id: `reasoning-${activeExtraction.idCounter}`
126
+ });
127
+ activeExtraction.idCounter += 1;
128
+ }
129
+ activeExtraction.isReasoning = !activeExtraction.isReasoning;
130
+ activeExtraction.afterSwitch = true;
131
+ }
132
+ function processTagMatch({
133
+ activeExtraction,
134
+ controller,
135
+ publish,
136
+ startIndex,
137
+ nextTag
138
+ }) {
139
+ publish(activeExtraction.buffer.slice(0, startIndex));
140
+ const foundFullMatch = startIndex + nextTag.length <= activeExtraction.buffer.length;
141
+ if (foundFullMatch) {
142
+ handleFullMatch(activeExtraction, controller, startIndex, nextTag);
143
+ return true;
144
+ }
145
+ activeExtraction.buffer = activeExtraction.buffer.slice(startIndex);
146
+ return false;
147
+ }
148
+ function processBuffer(activeExtraction, controller) {
149
+ const publish = createPublisher(activeExtraction, controller);
150
+ let continueProcessing = true;
151
+ while (continueProcessing) {
152
+ const nextTag = activeExtraction.isReasoning ? closingTag : openingTag;
153
+ const startIndex = getPotentialStartIndex(
154
+ activeExtraction.buffer,
155
+ nextTag
156
+ );
157
+ if (startIndex == null) {
158
+ publish(activeExtraction.buffer);
159
+ activeExtraction.buffer = "";
160
+ break;
161
+ }
162
+ continueProcessing = processTagMatch({
163
+ activeExtraction,
164
+ controller,
165
+ publish,
166
+ startIndex,
167
+ nextTag
168
+ });
169
+ }
170
+ }
171
+ return {
172
+ stream: stream.pipeThrough(
173
+ new TransformStream({
174
+ transform: (chunk, controller) => {
175
+ if (chunk.type !== "text-delta") {
176
+ controller.enqueue(chunk);
177
+ return;
178
+ }
179
+ if (reasoningExtractions[chunk.id] == null) {
180
+ reasoningExtractions[chunk.id] = {
181
+ isFirstReasoning: true,
182
+ isFirstText: true,
183
+ afterSwitch: false,
184
+ isReasoning: startWithReasoning,
185
+ buffer: "",
186
+ idCounter: 0,
187
+ textId: chunk.id
188
+ };
189
+ }
190
+ const activeExtraction = reasoningExtractions[chunk.id];
191
+ activeExtraction.buffer += chunk.delta;
192
+ processBuffer(activeExtraction, controller);
193
+ }
194
+ })
195
+ ),
196
+ ...rest
197
+ };
198
+ }
199
+ };
200
+ }
201
+
202
+ export {
203
+ getPotentialStartIndex,
204
+ extractReasoningMiddleware
205
+ };
206
+ /**
207
+ * @license
208
+ * Copyright (c) 2021-present, FriendliAI Inc. All rights reserved.
209
+ */
210
+ //# sourceMappingURL=chunk-Q2TVVB35.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/reasoning-parser/index.ts"],"sourcesContent":["/**\n * @license\n * Copyright (c) 2021-present, FriendliAI Inc. All rights reserved.\n */\n\nimport type {\n LanguageModelV3Content,\n LanguageModelV3Middleware,\n LanguageModelV3StreamPart,\n} from \"@ai-sdk/provider\";\n\n/**\n * All code below is forked from the following link:\n * https://github.com/vercel/ai/blob/v5/packages/ai/core/middleware/extract-reasoning-middleware.ts\n */\n\n/**\n * Returns the index of the start of the searchedText in the text, or null if it\n * is not found.\n */\nexport function getPotentialStartIndex(\n text: string,\n searchedText: string\n): number | null {\n // Return null immediately if searchedText is empty.\n if (searchedText.length === 0) {\n return null;\n }\n\n // Check if the searchedText exists as a direct substring of text.\n const directIndex = text.indexOf(searchedText);\n if (directIndex !== -1) {\n return directIndex;\n }\n\n // Otherwise, look for the largest suffix of \"text\" that matches\n // a prefix of \"searchedText\". We go from the end of text inward.\n for (let i = text.length - 1; i >= 0; i -= 1) {\n const suffix = text.substring(i);\n if (searchedText.startsWith(suffix)) {\n return i;\n }\n }\n\n return null;\n}\n\n/**\n * Extract an XML-tagged reasoning section from the generated text and exposes it\n * as a `reasoning` property on the result.\n *\n * @param openingTag - The opening XML tag to extract reasoning from.\n * @param closingTag - The closing XML tag to extract reasoning from.\n * @param separator - The separator to use between reasoning and text sections.\n * @param startWithReasoning - Whether to start with reasoning tokens.\n */\nexport function extractReasoningMiddleware({\n openingTag,\n closingTag,\n separator = \"\\n\",\n startWithReasoning = false,\n}: {\n openingTag: string;\n closingTag: string;\n separator?: string;\n startWithReasoning?: boolean;\n}): LanguageModelV3Middleware {\n function processTextPart(\n text: string,\n transformedContent: LanguageModelV3Content[]\n ) {\n const regexp = new RegExp(`${openingTag}(.*?)${closingTag}`, \"gs\");\n const matches = Array.from(text.matchAll(regexp));\n\n if (!matches.length) {\n return;\n }\n\n const reasoningText = matches.map((match) => match[1]).join(separator);\n\n let textWithoutReasoning = text;\n for (let i = matches.length - 1; i >= 0; i -= 1) {\n const match = matches[i];\n\n const beforeMatch = textWithoutReasoning.slice(0, match.index);\n const matchIndex = match.index ?? 0;\n const afterMatch = textWithoutReasoning.slice(\n matchIndex + match[0].length\n );\n\n textWithoutReasoning =\n beforeMatch +\n (beforeMatch.length > 0 && afterMatch.length > 0 ? separator : \"\") +\n afterMatch;\n }\n\n transformedContent.push({\n type: \"reasoning\",\n text: reasoningText,\n });\n\n transformedContent.push({\n type: \"text\",\n text: textWithoutReasoning,\n });\n }\n\n return {\n specificationVersion: \"v3\",\n wrapGenerate: async ({ doGenerate }) => {\n const { content, ...rest } = await doGenerate();\n\n const transformedContent: LanguageModelV3Content[] = [];\n for (const part of content) {\n if (part.type !== \"text\") {\n transformedContent.push(part);\n continue;\n }\n\n const text = startWithReasoning ? openingTag + part.text : part.text;\n const regexp = new RegExp(`${openingTag}(.*?)${closingTag}`, \"gs\");\n const matches = Array.from(text.matchAll(regexp));\n\n if (!matches.length) {\n transformedContent.push(part);\n continue;\n }\n\n processTextPart(text, transformedContent);\n }\n\n return { content: transformedContent, ...rest };\n },\n\n wrapStream: async ({ doStream }) => {\n const { stream, ...rest } = await doStream();\n\n interface ExtractionState {\n isFirstReasoning: boolean;\n isFirstText: boolean;\n afterSwitch: boolean;\n isReasoning: boolean;\n buffer: string;\n idCounter: number;\n textId: string;\n }\n\n const reasoningExtractions: Record<string, ExtractionState> = {};\n\n function createPublisher(\n activeExtraction: ExtractionState,\n controller: TransformStreamDefaultController<LanguageModelV3StreamPart>\n ) {\n return (text: string) => {\n if (text.length === 0) {\n return;\n }\n\n const prefix = getPrefix(activeExtraction);\n enqueueReasoningStart(activeExtraction, controller);\n enqueueDelta(activeExtraction, controller, prefix, text);\n updateExtractionState(activeExtraction);\n };\n }\n\n function getPrefix(activeExtraction: ExtractionState): string {\n return activeExtraction.afterSwitch &&\n (activeExtraction.isReasoning\n ? !activeExtraction.isFirstReasoning\n : !activeExtraction.isFirstText)\n ? separator\n : \"\";\n }\n\n function enqueueReasoningStart(\n activeExtraction: ExtractionState,\n controller: TransformStreamDefaultController<LanguageModelV3StreamPart>\n ) {\n if (\n (activeExtraction.afterSwitch && activeExtraction.isReasoning) ||\n activeExtraction.isFirstReasoning\n ) {\n controller.enqueue({\n type: \"reasoning-start\",\n id: `reasoning-${activeExtraction.idCounter}`,\n });\n }\n }\n\n function enqueueDelta(\n activeExtraction: ExtractionState,\n controller: TransformStreamDefaultController<LanguageModelV3StreamPart>,\n prefix: string,\n text: string\n ) {\n controller.enqueue(\n activeExtraction.isReasoning\n ? {\n type: \"reasoning-delta\",\n delta: prefix + text,\n id: `reasoning-${activeExtraction.idCounter}`,\n }\n : {\n type: \"text-delta\",\n delta: prefix + text,\n id: activeExtraction.textId,\n }\n );\n }\n\n function updateExtractionState(activeExtraction: ExtractionState) {\n activeExtraction.afterSwitch = false;\n if (activeExtraction.isReasoning) {\n activeExtraction.isFirstReasoning = false;\n } else {\n activeExtraction.isFirstText = false;\n }\n }\n\n function handleFullMatch(\n activeExtraction: ExtractionState,\n controller: TransformStreamDefaultController<LanguageModelV3StreamPart>,\n startIndex: number,\n nextTag: string\n ) {\n activeExtraction.buffer = activeExtraction.buffer.slice(\n startIndex + nextTag.length\n );\n\n if (activeExtraction.isReasoning) {\n controller.enqueue({\n type: \"reasoning-end\",\n id: `reasoning-${activeExtraction.idCounter}`,\n });\n activeExtraction.idCounter += 1;\n }\n\n activeExtraction.isReasoning = !activeExtraction.isReasoning;\n activeExtraction.afterSwitch = true;\n }\n\n function processTagMatch({\n activeExtraction,\n controller,\n publish,\n startIndex,\n nextTag,\n }: {\n activeExtraction: ExtractionState;\n controller: TransformStreamDefaultController<LanguageModelV3StreamPart>;\n publish: (text: string) => void;\n startIndex: number;\n nextTag: string;\n }): boolean {\n publish(activeExtraction.buffer.slice(0, startIndex));\n\n const foundFullMatch =\n startIndex + nextTag.length <= activeExtraction.buffer.length;\n\n if (foundFullMatch) {\n handleFullMatch(activeExtraction, controller, startIndex, nextTag);\n return true;\n }\n\n activeExtraction.buffer = activeExtraction.buffer.slice(startIndex);\n return false;\n }\n\n function processBuffer(\n activeExtraction: ExtractionState,\n controller: TransformStreamDefaultController<LanguageModelV3StreamPart>\n ) {\n const publish = createPublisher(activeExtraction, controller);\n let continueProcessing = true;\n\n while (continueProcessing) {\n const nextTag = activeExtraction.isReasoning\n ? closingTag\n : openingTag;\n const startIndex = getPotentialStartIndex(\n activeExtraction.buffer,\n nextTag\n );\n\n if (startIndex == null) {\n publish(activeExtraction.buffer);\n activeExtraction.buffer = \"\";\n break;\n }\n\n continueProcessing = processTagMatch({\n activeExtraction,\n controller,\n publish,\n startIndex,\n nextTag,\n });\n }\n }\n\n return {\n stream: stream.pipeThrough(\n new TransformStream<\n LanguageModelV3StreamPart,\n LanguageModelV3StreamPart\n >({\n transform: (chunk, controller) => {\n if (chunk.type !== \"text-delta\") {\n controller.enqueue(chunk);\n return;\n }\n\n if (reasoningExtractions[chunk.id] == null) {\n reasoningExtractions[chunk.id] = {\n isFirstReasoning: true,\n isFirstText: true,\n afterSwitch: false,\n isReasoning: startWithReasoning,\n buffer: \"\",\n idCounter: 0,\n textId: chunk.id,\n };\n }\n\n const activeExtraction = reasoningExtractions[chunk.id];\n activeExtraction.buffer += chunk.delta;\n processBuffer(activeExtraction, controller);\n },\n })\n ),\n ...rest,\n };\n },\n };\n}\n"],"mappings":"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","names":[]}
package/dist/index.cjs ADDED
@@ -0,0 +1,339 @@
1
+ "use strict";
2
+ var __defProp = Object.defineProperty;
3
+ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
4
+ var __getOwnPropNames = Object.getOwnPropertyNames;
5
+ var __hasOwnProp = Object.prototype.hasOwnProperty;
6
+ var __export = (target, all) => {
7
+ for (var name in all)
8
+ __defProp(target, name, { get: all[name], enumerable: true });
9
+ };
10
+ var __copyProps = (to, from, except, desc) => {
11
+ if (from && typeof from === "object" || typeof from === "function") {
12
+ for (let key of __getOwnPropNames(from))
13
+ if (!__hasOwnProp.call(to, key) && key !== except)
14
+ __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
15
+ }
16
+ return to;
17
+ };
18
+ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
19
+
20
+ // src/index.ts
21
+ var src_exports = {};
22
+ __export(src_exports, {
23
+ defaultSystemPromptMiddleware: () => defaultSystemPromptMiddleware,
24
+ extractReasoningMiddleware: () => extractReasoningMiddleware,
25
+ getPotentialStartIndex: () => getPotentialStartIndex
26
+ });
27
+ module.exports = __toCommonJS(src_exports);
28
+
29
+ // src/default-system-prompt.ts
30
+ function extractSystemText(content) {
31
+ if (typeof content === "string") {
32
+ return content;
33
+ }
34
+ if (!Array.isArray(content)) {
35
+ if (content == null) {
36
+ return;
37
+ }
38
+ return String(content);
39
+ }
40
+ const parts = content.map((part) => {
41
+ var _a;
42
+ if ((part == null ? void 0 : part.type) === "text" && "text" in part) {
43
+ return String((_a = part.text) != null ? _a : "");
44
+ }
45
+ return JSON.stringify(part);
46
+ });
47
+ const textParts = parts.filter((value) => value.length > 0);
48
+ if (textParts.length === 0) {
49
+ return;
50
+ }
51
+ return textParts.join("\n");
52
+ }
53
+ function mergeSystemPrompts({
54
+ base,
55
+ addition,
56
+ placement
57
+ }) {
58
+ if (!base) {
59
+ return addition;
60
+ }
61
+ if (addition.length === 0) {
62
+ return base;
63
+ }
64
+ return placement === "first" ? `${addition}
65
+
66
+ ${base}` : `${base}
67
+
68
+ ${addition}`;
69
+ }
70
+ function ensurePromptArray(prompt) {
71
+ if (!prompt) {
72
+ return [];
73
+ }
74
+ return [...prompt];
75
+ }
76
+ function defaultSystemPromptMiddleware({
77
+ systemPrompt,
78
+ placement = "first"
79
+ }) {
80
+ return {
81
+ specificationVersion: "v3",
82
+ transformParams: ({ params }) => {
83
+ const prompt = ensurePromptArray(params.prompt);
84
+ const systemIndex = prompt.findIndex(
85
+ (message) => message.role === "system"
86
+ );
87
+ if (systemIndex === -1) {
88
+ const promptWithSystem = placement === "first" ? [
89
+ {
90
+ role: "system",
91
+ content: systemPrompt
92
+ },
93
+ ...prompt
94
+ ] : [
95
+ ...prompt,
96
+ {
97
+ role: "system",
98
+ content: systemPrompt
99
+ }
100
+ ];
101
+ const nextParams2 = {
102
+ ...params,
103
+ prompt: promptWithSystem
104
+ };
105
+ return Promise.resolve(nextParams2);
106
+ }
107
+ const systemMessage = prompt[systemIndex];
108
+ const baseText = extractSystemText(systemMessage.content);
109
+ const mergedContent = mergeSystemPrompts({
110
+ base: baseText,
111
+ addition: systemPrompt,
112
+ placement
113
+ });
114
+ const updatedPrompt = prompt.map(
115
+ (message, index) => index === systemIndex ? {
116
+ ...message,
117
+ content: mergedContent
118
+ } : message
119
+ );
120
+ const nextParams = {
121
+ ...params,
122
+ prompt: updatedPrompt
123
+ };
124
+ return Promise.resolve(nextParams);
125
+ }
126
+ };
127
+ }
128
+
129
+ // src/reasoning-parser/index.ts
130
+ function getPotentialStartIndex(text, searchedText) {
131
+ if (searchedText.length === 0) {
132
+ return null;
133
+ }
134
+ const directIndex = text.indexOf(searchedText);
135
+ if (directIndex !== -1) {
136
+ return directIndex;
137
+ }
138
+ for (let i = text.length - 1; i >= 0; i -= 1) {
139
+ const suffix = text.substring(i);
140
+ if (searchedText.startsWith(suffix)) {
141
+ return i;
142
+ }
143
+ }
144
+ return null;
145
+ }
146
+ function extractReasoningMiddleware({
147
+ openingTag,
148
+ closingTag,
149
+ separator = "\n",
150
+ startWithReasoning = false
151
+ }) {
152
+ function processTextPart(text, transformedContent) {
153
+ var _a;
154
+ const regexp = new RegExp(`${openingTag}(.*?)${closingTag}`, "gs");
155
+ const matches = Array.from(text.matchAll(regexp));
156
+ if (!matches.length) {
157
+ return;
158
+ }
159
+ const reasoningText = matches.map((match) => match[1]).join(separator);
160
+ let textWithoutReasoning = text;
161
+ for (let i = matches.length - 1; i >= 0; i -= 1) {
162
+ const match = matches[i];
163
+ const beforeMatch = textWithoutReasoning.slice(0, match.index);
164
+ const matchIndex = (_a = match.index) != null ? _a : 0;
165
+ const afterMatch = textWithoutReasoning.slice(
166
+ matchIndex + match[0].length
167
+ );
168
+ textWithoutReasoning = beforeMatch + (beforeMatch.length > 0 && afterMatch.length > 0 ? separator : "") + afterMatch;
169
+ }
170
+ transformedContent.push({
171
+ type: "reasoning",
172
+ text: reasoningText
173
+ });
174
+ transformedContent.push({
175
+ type: "text",
176
+ text: textWithoutReasoning
177
+ });
178
+ }
179
+ return {
180
+ specificationVersion: "v3",
181
+ wrapGenerate: async ({ doGenerate }) => {
182
+ const { content, ...rest } = await doGenerate();
183
+ const transformedContent = [];
184
+ for (const part of content) {
185
+ if (part.type !== "text") {
186
+ transformedContent.push(part);
187
+ continue;
188
+ }
189
+ const text = startWithReasoning ? openingTag + part.text : part.text;
190
+ const regexp = new RegExp(`${openingTag}(.*?)${closingTag}`, "gs");
191
+ const matches = Array.from(text.matchAll(regexp));
192
+ if (!matches.length) {
193
+ transformedContent.push(part);
194
+ continue;
195
+ }
196
+ processTextPart(text, transformedContent);
197
+ }
198
+ return { content: transformedContent, ...rest };
199
+ },
200
+ wrapStream: async ({ doStream }) => {
201
+ const { stream, ...rest } = await doStream();
202
+ const reasoningExtractions = {};
203
+ function createPublisher(activeExtraction, controller) {
204
+ return (text) => {
205
+ if (text.length === 0) {
206
+ return;
207
+ }
208
+ const prefix = getPrefix(activeExtraction);
209
+ enqueueReasoningStart(activeExtraction, controller);
210
+ enqueueDelta(activeExtraction, controller, prefix, text);
211
+ updateExtractionState(activeExtraction);
212
+ };
213
+ }
214
+ function getPrefix(activeExtraction) {
215
+ return activeExtraction.afterSwitch && (activeExtraction.isReasoning ? !activeExtraction.isFirstReasoning : !activeExtraction.isFirstText) ? separator : "";
216
+ }
217
+ function enqueueReasoningStart(activeExtraction, controller) {
218
+ if (activeExtraction.afterSwitch && activeExtraction.isReasoning || activeExtraction.isFirstReasoning) {
219
+ controller.enqueue({
220
+ type: "reasoning-start",
221
+ id: `reasoning-${activeExtraction.idCounter}`
222
+ });
223
+ }
224
+ }
225
+ function enqueueDelta(activeExtraction, controller, prefix, text) {
226
+ controller.enqueue(
227
+ activeExtraction.isReasoning ? {
228
+ type: "reasoning-delta",
229
+ delta: prefix + text,
230
+ id: `reasoning-${activeExtraction.idCounter}`
231
+ } : {
232
+ type: "text-delta",
233
+ delta: prefix + text,
234
+ id: activeExtraction.textId
235
+ }
236
+ );
237
+ }
238
+ function updateExtractionState(activeExtraction) {
239
+ activeExtraction.afterSwitch = false;
240
+ if (activeExtraction.isReasoning) {
241
+ activeExtraction.isFirstReasoning = false;
242
+ } else {
243
+ activeExtraction.isFirstText = false;
244
+ }
245
+ }
246
+ function handleFullMatch(activeExtraction, controller, startIndex, nextTag) {
247
+ activeExtraction.buffer = activeExtraction.buffer.slice(
248
+ startIndex + nextTag.length
249
+ );
250
+ if (activeExtraction.isReasoning) {
251
+ controller.enqueue({
252
+ type: "reasoning-end",
253
+ id: `reasoning-${activeExtraction.idCounter}`
254
+ });
255
+ activeExtraction.idCounter += 1;
256
+ }
257
+ activeExtraction.isReasoning = !activeExtraction.isReasoning;
258
+ activeExtraction.afterSwitch = true;
259
+ }
260
+ function processTagMatch({
261
+ activeExtraction,
262
+ controller,
263
+ publish,
264
+ startIndex,
265
+ nextTag
266
+ }) {
267
+ publish(activeExtraction.buffer.slice(0, startIndex));
268
+ const foundFullMatch = startIndex + nextTag.length <= activeExtraction.buffer.length;
269
+ if (foundFullMatch) {
270
+ handleFullMatch(activeExtraction, controller, startIndex, nextTag);
271
+ return true;
272
+ }
273
+ activeExtraction.buffer = activeExtraction.buffer.slice(startIndex);
274
+ return false;
275
+ }
276
+ function processBuffer(activeExtraction, controller) {
277
+ const publish = createPublisher(activeExtraction, controller);
278
+ let continueProcessing = true;
279
+ while (continueProcessing) {
280
+ const nextTag = activeExtraction.isReasoning ? closingTag : openingTag;
281
+ const startIndex = getPotentialStartIndex(
282
+ activeExtraction.buffer,
283
+ nextTag
284
+ );
285
+ if (startIndex == null) {
286
+ publish(activeExtraction.buffer);
287
+ activeExtraction.buffer = "";
288
+ break;
289
+ }
290
+ continueProcessing = processTagMatch({
291
+ activeExtraction,
292
+ controller,
293
+ publish,
294
+ startIndex,
295
+ nextTag
296
+ });
297
+ }
298
+ }
299
+ return {
300
+ stream: stream.pipeThrough(
301
+ new TransformStream({
302
+ transform: (chunk, controller) => {
303
+ if (chunk.type !== "text-delta") {
304
+ controller.enqueue(chunk);
305
+ return;
306
+ }
307
+ if (reasoningExtractions[chunk.id] == null) {
308
+ reasoningExtractions[chunk.id] = {
309
+ isFirstReasoning: true,
310
+ isFirstText: true,
311
+ afterSwitch: false,
312
+ isReasoning: startWithReasoning,
313
+ buffer: "",
314
+ idCounter: 0,
315
+ textId: chunk.id
316
+ };
317
+ }
318
+ const activeExtraction = reasoningExtractions[chunk.id];
319
+ activeExtraction.buffer += chunk.delta;
320
+ processBuffer(activeExtraction, controller);
321
+ }
322
+ })
323
+ ),
324
+ ...rest
325
+ };
326
+ }
327
+ };
328
+ }
329
+ // Annotate the CommonJS export names for ESM import in node:
330
+ 0 && (module.exports = {
331
+ defaultSystemPromptMiddleware,
332
+ extractReasoningMiddleware,
333
+ getPotentialStartIndex
334
+ });
335
+ /**
336
+ * @license
337
+ * Copyright (c) 2021-present, FriendliAI Inc. All rights reserved.
338
+ */
339
+ //# sourceMappingURL=index.cjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/index.ts","../src/default-system-prompt.ts","../src/reasoning-parser/index.ts"],"sourcesContent":["// biome-ignore lint/performance/noBarrelFile: Package entrypoint - must re-export for public API\nexport * from \"./default-system-prompt\";\nexport * from \"./reasoning-parser\";\n","import type {\n LanguageModelV3CallOptions,\n LanguageModelV3Content,\n LanguageModelV3Middleware,\n LanguageModelV3Prompt,\n} from \"@ai-sdk/provider\";\n\ntype SystemPromptPlacement = \"first\" | \"last\";\n\ninterface DefaultSystemPromptMiddlewareOptions {\n systemPrompt: string;\n placement?: SystemPromptPlacement;\n}\n\nfunction extractSystemText(content: unknown): string | undefined {\n if (typeof content === \"string\") {\n return content;\n }\n\n if (!Array.isArray(content)) {\n if (content == null) {\n return;\n }\n return String(content);\n }\n\n const parts = (content as LanguageModelV3Content[]).map((part) => {\n if (part?.type === \"text\" && \"text\" in part) {\n return String(part.text ?? \"\");\n }\n\n return JSON.stringify(part);\n });\n\n const textParts = parts.filter((value) => value.length > 0);\n if (textParts.length === 0) {\n return;\n }\n\n return textParts.join(\"\\n\");\n}\n\nfunction mergeSystemPrompts({\n base,\n addition,\n placement,\n}: {\n base?: string;\n addition: string;\n placement: SystemPromptPlacement;\n}): string {\n if (!base) {\n return addition;\n }\n\n if (addition.length === 0) {\n return base;\n }\n\n return placement === \"first\"\n ? `${addition}\\n\\n${base}`\n : `${base}\\n\\n${addition}`;\n}\n\nfunction ensurePromptArray(\n prompt?: LanguageModelV3Prompt\n): LanguageModelV3Prompt {\n if (!prompt) {\n return [];\n }\n\n return [...prompt];\n}\n\nexport function defaultSystemPromptMiddleware({\n systemPrompt,\n placement = \"first\",\n}: DefaultSystemPromptMiddlewareOptions): LanguageModelV3Middleware {\n return {\n specificationVersion: \"v3\",\n transformParams: ({ params }) => {\n const prompt = ensurePromptArray(params.prompt);\n const systemIndex = prompt.findIndex(\n (message) => message.role === \"system\"\n );\n\n if (systemIndex === -1) {\n const promptWithSystem =\n placement === \"first\"\n ? ([\n {\n role: \"system\" as const,\n content: systemPrompt,\n },\n ...prompt,\n ] as LanguageModelV3Prompt)\n : ([\n ...prompt,\n {\n role: \"system\" as const,\n content: systemPrompt,\n },\n ] as LanguageModelV3Prompt);\n\n const nextParams: LanguageModelV3CallOptions = {\n ...params,\n prompt: promptWithSystem,\n };\n\n return Promise.resolve<LanguageModelV3CallOptions>(nextParams);\n }\n\n const systemMessage = prompt[systemIndex];\n const baseText = extractSystemText(systemMessage.content);\n const mergedContent = mergeSystemPrompts({\n base: baseText,\n addition: systemPrompt,\n placement,\n });\n\n const updatedPrompt = prompt.map((message, index) =>\n index === systemIndex\n ? {\n ...message,\n content: mergedContent,\n }\n : message\n ) as LanguageModelV3Prompt;\n\n const nextParams: LanguageModelV3CallOptions = {\n ...params,\n prompt: updatedPrompt,\n };\n\n return Promise.resolve<LanguageModelV3CallOptions>(nextParams);\n },\n };\n}\n","/**\n * @license\n * Copyright (c) 2021-present, FriendliAI Inc. All rights reserved.\n */\n\nimport type {\n LanguageModelV3Content,\n LanguageModelV3Middleware,\n LanguageModelV3StreamPart,\n} from \"@ai-sdk/provider\";\n\n/**\n * All code below is forked from the following link:\n * https://github.com/vercel/ai/blob/v5/packages/ai/core/middleware/extract-reasoning-middleware.ts\n */\n\n/**\n * Returns the index of the start of the searchedText in the text, or null if it\n * is not found.\n */\nexport function getPotentialStartIndex(\n text: string,\n searchedText: string\n): number | null {\n // Return null immediately if searchedText is empty.\n if (searchedText.length === 0) {\n return null;\n }\n\n // Check if the searchedText exists as a direct substring of text.\n const directIndex = text.indexOf(searchedText);\n if (directIndex !== -1) {\n return directIndex;\n }\n\n // Otherwise, look for the largest suffix of \"text\" that matches\n // a prefix of \"searchedText\". We go from the end of text inward.\n for (let i = text.length - 1; i >= 0; i -= 1) {\n const suffix = text.substring(i);\n if (searchedText.startsWith(suffix)) {\n return i;\n }\n }\n\n return null;\n}\n\n/**\n * Extract an XML-tagged reasoning section from the generated text and exposes it\n * as a `reasoning` property on the result.\n *\n * @param openingTag - The opening XML tag to extract reasoning from.\n * @param closingTag - The closing XML tag to extract reasoning from.\n * @param separator - The separator to use between reasoning and text sections.\n * @param startWithReasoning - Whether to start with reasoning tokens.\n */\nexport function extractReasoningMiddleware({\n openingTag,\n closingTag,\n separator = \"\\n\",\n startWithReasoning = false,\n}: {\n openingTag: string;\n closingTag: string;\n separator?: string;\n startWithReasoning?: boolean;\n}): LanguageModelV3Middleware {\n function processTextPart(\n text: string,\n transformedContent: LanguageModelV3Content[]\n ) {\n const regexp = new RegExp(`${openingTag}(.*?)${closingTag}`, \"gs\");\n const matches = Array.from(text.matchAll(regexp));\n\n if (!matches.length) {\n return;\n }\n\n const reasoningText = matches.map((match) => match[1]).join(separator);\n\n let textWithoutReasoning = text;\n for (let i = matches.length - 1; i >= 0; i -= 1) {\n const match = matches[i];\n\n const beforeMatch = textWithoutReasoning.slice(0, match.index);\n const matchIndex = match.index ?? 0;\n const afterMatch = textWithoutReasoning.slice(\n matchIndex + match[0].length\n );\n\n textWithoutReasoning =\n beforeMatch +\n (beforeMatch.length > 0 && afterMatch.length > 0 ? separator : \"\") +\n afterMatch;\n }\n\n transformedContent.push({\n type: \"reasoning\",\n text: reasoningText,\n });\n\n transformedContent.push({\n type: \"text\",\n text: textWithoutReasoning,\n });\n }\n\n return {\n specificationVersion: \"v3\",\n wrapGenerate: async ({ doGenerate }) => {\n const { content, ...rest } = await doGenerate();\n\n const transformedContent: LanguageModelV3Content[] = [];\n for (const part of content) {\n if (part.type !== \"text\") {\n transformedContent.push(part);\n continue;\n }\n\n const text = startWithReasoning ? openingTag + part.text : part.text;\n const regexp = new RegExp(`${openingTag}(.*?)${closingTag}`, \"gs\");\n const matches = Array.from(text.matchAll(regexp));\n\n if (!matches.length) {\n transformedContent.push(part);\n continue;\n }\n\n processTextPart(text, transformedContent);\n }\n\n return { content: transformedContent, ...rest };\n },\n\n wrapStream: async ({ doStream }) => {\n const { stream, ...rest } = await doStream();\n\n interface ExtractionState {\n isFirstReasoning: boolean;\n isFirstText: boolean;\n afterSwitch: boolean;\n isReasoning: boolean;\n buffer: string;\n idCounter: number;\n textId: string;\n }\n\n const reasoningExtractions: Record<string, ExtractionState> = {};\n\n function createPublisher(\n activeExtraction: ExtractionState,\n controller: TransformStreamDefaultController<LanguageModelV3StreamPart>\n ) {\n return (text: string) => {\n if (text.length === 0) {\n return;\n }\n\n const prefix = getPrefix(activeExtraction);\n enqueueReasoningStart(activeExtraction, controller);\n enqueueDelta(activeExtraction, controller, prefix, text);\n updateExtractionState(activeExtraction);\n };\n }\n\n function getPrefix(activeExtraction: ExtractionState): string {\n return activeExtraction.afterSwitch &&\n (activeExtraction.isReasoning\n ? !activeExtraction.isFirstReasoning\n : !activeExtraction.isFirstText)\n ? separator\n : \"\";\n }\n\n function enqueueReasoningStart(\n activeExtraction: ExtractionState,\n controller: TransformStreamDefaultController<LanguageModelV3StreamPart>\n ) {\n if (\n (activeExtraction.afterSwitch && activeExtraction.isReasoning) ||\n activeExtraction.isFirstReasoning\n ) {\n controller.enqueue({\n type: \"reasoning-start\",\n id: `reasoning-${activeExtraction.idCounter}`,\n });\n }\n }\n\n function enqueueDelta(\n activeExtraction: ExtractionState,\n controller: TransformStreamDefaultController<LanguageModelV3StreamPart>,\n prefix: string,\n text: string\n ) {\n controller.enqueue(\n activeExtraction.isReasoning\n ? {\n type: \"reasoning-delta\",\n delta: prefix + text,\n id: `reasoning-${activeExtraction.idCounter}`,\n }\n : {\n type: \"text-delta\",\n delta: prefix + text,\n id: activeExtraction.textId,\n }\n );\n }\n\n function updateExtractionState(activeExtraction: ExtractionState) {\n activeExtraction.afterSwitch = false;\n if (activeExtraction.isReasoning) {\n activeExtraction.isFirstReasoning = false;\n } else {\n activeExtraction.isFirstText = false;\n }\n }\n\n function handleFullMatch(\n activeExtraction: ExtractionState,\n controller: TransformStreamDefaultController<LanguageModelV3StreamPart>,\n startIndex: number,\n nextTag: string\n ) {\n activeExtraction.buffer = activeExtraction.buffer.slice(\n startIndex + nextTag.length\n );\n\n if (activeExtraction.isReasoning) {\n controller.enqueue({\n type: \"reasoning-end\",\n id: `reasoning-${activeExtraction.idCounter}`,\n });\n activeExtraction.idCounter += 1;\n }\n\n activeExtraction.isReasoning = !activeExtraction.isReasoning;\n activeExtraction.afterSwitch = true;\n }\n\n function processTagMatch({\n activeExtraction,\n controller,\n publish,\n startIndex,\n nextTag,\n }: {\n activeExtraction: ExtractionState;\n controller: TransformStreamDefaultController<LanguageModelV3StreamPart>;\n publish: (text: string) => void;\n startIndex: number;\n nextTag: string;\n }): boolean {\n publish(activeExtraction.buffer.slice(0, startIndex));\n\n const foundFullMatch =\n startIndex + nextTag.length <= activeExtraction.buffer.length;\n\n if (foundFullMatch) {\n handleFullMatch(activeExtraction, controller, startIndex, nextTag);\n return true;\n }\n\n activeExtraction.buffer = activeExtraction.buffer.slice(startIndex);\n return false;\n }\n\n function processBuffer(\n activeExtraction: ExtractionState,\n controller: TransformStreamDefaultController<LanguageModelV3StreamPart>\n ) {\n const publish = createPublisher(activeExtraction, controller);\n let continueProcessing = true;\n\n while (continueProcessing) {\n const nextTag = activeExtraction.isReasoning\n ? closingTag\n : openingTag;\n const startIndex = getPotentialStartIndex(\n activeExtraction.buffer,\n nextTag\n );\n\n if (startIndex == null) {\n publish(activeExtraction.buffer);\n activeExtraction.buffer = \"\";\n break;\n }\n\n continueProcessing = processTagMatch({\n activeExtraction,\n controller,\n publish,\n startIndex,\n nextTag,\n });\n }\n }\n\n return {\n stream: stream.pipeThrough(\n new TransformStream<\n LanguageModelV3StreamPart,\n LanguageModelV3StreamPart\n >({\n transform: (chunk, controller) => {\n if (chunk.type !== \"text-delta\") {\n controller.enqueue(chunk);\n return;\n }\n\n if (reasoningExtractions[chunk.id] == null) {\n reasoningExtractions[chunk.id] = {\n isFirstReasoning: true,\n isFirstText: true,\n afterSwitch: false,\n isReasoning: startWithReasoning,\n buffer: \"\",\n idCounter: 0,\n textId: chunk.id,\n };\n }\n\n const activeExtraction = reasoningExtractions[chunk.id];\n activeExtraction.buffer += chunk.delta;\n processBuffer(activeExtraction, controller);\n },\n })\n ),\n ...rest,\n };\n },\n };\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;;ACcA,SAAS,kBAAkB,SAAsC;AAC/D,MAAI,OAAO,YAAY,UAAU;AAC/B,WAAO;AAAA,EACT;AAEA,MAAI,CAAC,MAAM,QAAQ,OAAO,GAAG;AAC3B,QAAI,WAAW,MAAM;AACnB;AAAA,IACF;AACA,WAAO,OAAO,OAAO;AAAA,EACvB;AAEA,QAAM,QAAS,QAAqC,IAAI,CAAC,SAAS;AA1BpE;AA2BI,SAAI,6BAAM,UAAS,UAAU,UAAU,MAAM;AAC3C,aAAO,QAAO,UAAK,SAAL,YAAa,EAAE;AAAA,IAC/B;AAEA,WAAO,KAAK,UAAU,IAAI;AAAA,EAC5B,CAAC;AAED,QAAM,YAAY,MAAM,OAAO,CAAC,UAAU,MAAM,SAAS,CAAC;AAC1D,MAAI,UAAU,WAAW,GAAG;AAC1B;AAAA,EACF;AAEA,SAAO,UAAU,KAAK,IAAI;AAC5B;AAEA,SAAS,mBAAmB;AAAA,EAC1B;AAAA,EACA;AAAA,EACA;AACF,GAIW;AACT,MAAI,CAAC,MAAM;AACT,WAAO;AAAA,EACT;AAEA,MAAI,SAAS,WAAW,GAAG;AACzB,WAAO;AAAA,EACT;AAEA,SAAO,cAAc,UACjB,GAAG,QAAQ;AAAA;AAAA,EAAO,IAAI,KACtB,GAAG,IAAI;AAAA;AAAA,EAAO,QAAQ;AAC5B;AAEA,SAAS,kBACP,QACuB;AACvB,MAAI,CAAC,QAAQ;AACX,WAAO,CAAC;AAAA,EACV;AAEA,SAAO,CAAC,GAAG,MAAM;AACnB;AAEO,SAAS,8BAA8B;AAAA,EAC5C;AAAA,EACA,YAAY;AACd,GAAoE;AAClE,SAAO;AAAA,IACL,sBAAsB;AAAA,IACtB,iBAAiB,CAAC,EAAE,OAAO,MAAM;AAC/B,YAAM,SAAS,kBAAkB,OAAO,MAAM;AAC9C,YAAM,cAAc,OAAO;AAAA,QACzB,CAAC,YAAY,QAAQ,SAAS;AAAA,MAChC;AAEA,UAAI,gBAAgB,IAAI;AACtB,cAAM,mBACJ,cAAc,UACT;AAAA,UACC;AAAA,YACE,MAAM;AAAA,YACN,SAAS;AAAA,UACX;AAAA,UACA,GAAG;AAAA,QACL,IACC;AAAA,UACC,GAAG;AAAA,UACH;AAAA,YACE,MAAM;AAAA,YACN,SAAS;AAAA,UACX;AAAA,QACF;AAEN,cAAMA,cAAyC;AAAA,UAC7C,GAAG;AAAA,UACH,QAAQ;AAAA,QACV;AAEA,eAAO,QAAQ,QAAoCA,WAAU;AAAA,MAC/D;AAEA,YAAM,gBAAgB,OAAO,WAAW;AACxC,YAAM,WAAW,kBAAkB,cAAc,OAAO;AACxD,YAAM,gBAAgB,mBAAmB;AAAA,QACvC,MAAM;AAAA,QACN,UAAU;AAAA,QACV;AAAA,MACF,CAAC;AAED,YAAM,gBAAgB,OAAO;AAAA,QAAI,CAAC,SAAS,UACzC,UAAU,cACN;AAAA,UACE,GAAG;AAAA,UACH,SAAS;AAAA,QACX,IACA;AAAA,MACN;AAEA,YAAM,aAAyC;AAAA,QAC7C,GAAG;AAAA,QACH,QAAQ;AAAA,MACV;AAEA,aAAO,QAAQ,QAAoC,UAAU;AAAA,IAC/D;AAAA,EACF;AACF;;;ACrHO,SAAS,uBACd,MACA,cACe;AAEf,MAAI,aAAa,WAAW,GAAG;AAC7B,WAAO;AAAA,EACT;AAGA,QAAM,cAAc,KAAK,QAAQ,YAAY;AAC7C,MAAI,gBAAgB,IAAI;AACtB,WAAO;AAAA,EACT;AAIA,WAAS,IAAI,KAAK,SAAS,GAAG,KAAK,GAAG,KAAK,GAAG;AAC5C,UAAM,SAAS,KAAK,UAAU,CAAC;AAC/B,QAAI,aAAa,WAAW,MAAM,GAAG;AACnC,aAAO;AAAA,IACT;AAAA,EACF;AAEA,SAAO;AACT;AAWO,SAAS,2BAA2B;AAAA,EACzC;AAAA,EACA;AAAA,EACA,YAAY;AAAA,EACZ,qBAAqB;AACvB,GAK8B;AAC5B,WAAS,gBACP,MACA,oBACA;AAtEJ;AAuEI,UAAM,SAAS,IAAI,OAAO,GAAG,UAAU,QAAQ,UAAU,IAAI,IAAI;AACjE,UAAM,UAAU,MAAM,KAAK,KAAK,SAAS,MAAM,CAAC;AAEhD,QAAI,CAAC,QAAQ,QAAQ;AACnB;AAAA,IACF;AAEA,UAAM,gBAAgB,QAAQ,IAAI,CAAC,UAAU,MAAM,CAAC,CAAC,EAAE,KAAK,SAAS;AAErE,QAAI,uBAAuB;AAC3B,aAAS,IAAI,QAAQ,SAAS,GAAG,KAAK,GAAG,KAAK,GAAG;AAC/C,YAAM,QAAQ,QAAQ,CAAC;AAEvB,YAAM,cAAc,qBAAqB,MAAM,GAAG,MAAM,KAAK;AAC7D,YAAM,cAAa,WAAM,UAAN,YAAe;AAClC,YAAM,aAAa,qBAAqB;AAAA,QACtC,aAAa,MAAM,CAAC,EAAE;AAAA,MACxB;AAEA,6BACE,eACC,YAAY,SAAS,KAAK,WAAW,SAAS,IAAI,YAAY,MAC/D;AAAA,IACJ;AAEA,uBAAmB,KAAK;AAAA,MACtB,MAAM;AAAA,MACN,MAAM;AAAA,IACR,CAAC;AAED,uBAAmB,KAAK;AAAA,MACtB,MAAM;AAAA,MACN,MAAM;AAAA,IACR,CAAC;AAAA,EACH;AAEA,SAAO;AAAA,IACL,sBAAsB;AAAA,IACtB,cAAc,OAAO,EAAE,WAAW,MAAM;AACtC,YAAM,EAAE,SAAS,GAAG,KAAK,IAAI,MAAM,WAAW;AAE9C,YAAM,qBAA+C,CAAC;AACtD,iBAAW,QAAQ,SAAS;AAC1B,YAAI,KAAK,SAAS,QAAQ;AACxB,6BAAmB,KAAK,IAAI;AAC5B;AAAA,QACF;AAEA,cAAM,OAAO,qBAAqB,aAAa,KAAK,OAAO,KAAK;AAChE,cAAM,SAAS,IAAI,OAAO,GAAG,UAAU,QAAQ,UAAU,IAAI,IAAI;AACjE,cAAM,UAAU,MAAM,KAAK,KAAK,SAAS,MAAM,CAAC;AAEhD,YAAI,CAAC,QAAQ,QAAQ;AACnB,6BAAmB,KAAK,IAAI;AAC5B;AAAA,QACF;AAEA,wBAAgB,MAAM,kBAAkB;AAAA,MAC1C;AAEA,aAAO,EAAE,SAAS,oBAAoB,GAAG,KAAK;AAAA,IAChD;AAAA,IAEA,YAAY,OAAO,EAAE,SAAS,MAAM;AAClC,YAAM,EAAE,QAAQ,GAAG,KAAK,IAAI,MAAM,SAAS;AAY3C,YAAM,uBAAwD,CAAC;AAE/D,eAAS,gBACP,kBACA,YACA;AACA,eAAO,CAAC,SAAiB;AACvB,cAAI,KAAK,WAAW,GAAG;AACrB;AAAA,UACF;AAEA,gBAAM,SAAS,UAAU,gBAAgB;AACzC,gCAAsB,kBAAkB,UAAU;AAClD,uBAAa,kBAAkB,YAAY,QAAQ,IAAI;AACvD,gCAAsB,gBAAgB;AAAA,QACxC;AAAA,MACF;AAEA,eAAS,UAAU,kBAA2C;AAC5D,eAAO,iBAAiB,gBACrB,iBAAiB,cACd,CAAC,iBAAiB,mBAClB,CAAC,iBAAiB,eACpB,YACA;AAAA,MACN;AAEA,eAAS,sBACP,kBACA,YACA;AACA,YACG,iBAAiB,eAAe,iBAAiB,eAClD,iBAAiB,kBACjB;AACA,qBAAW,QAAQ;AAAA,YACjB,MAAM;AAAA,YACN,IAAI,aAAa,iBAAiB,SAAS;AAAA,UAC7C,CAAC;AAAA,QACH;AAAA,MACF;AAEA,eAAS,aACP,kBACA,YACA,QACA,MACA;AACA,mBAAW;AAAA,UACT,iBAAiB,cACb;AAAA,YACE,MAAM;AAAA,YACN,OAAO,SAAS;AAAA,YAChB,IAAI,aAAa,iBAAiB,SAAS;AAAA,UAC7C,IACA;AAAA,YACE,MAAM;AAAA,YACN,OAAO,SAAS;AAAA,YAChB,IAAI,iBAAiB;AAAA,UACvB;AAAA,QACN;AAAA,MACF;AAEA,eAAS,sBAAsB,kBAAmC;AAChE,yBAAiB,cAAc;AAC/B,YAAI,iBAAiB,aAAa;AAChC,2BAAiB,mBAAmB;AAAA,QACtC,OAAO;AACL,2BAAiB,cAAc;AAAA,QACjC;AAAA,MACF;AAEA,eAAS,gBACP,kBACA,YACA,YACA,SACA;AACA,yBAAiB,SAAS,iBAAiB,OAAO;AAAA,UAChD,aAAa,QAAQ;AAAA,QACvB;AAEA,YAAI,iBAAiB,aAAa;AAChC,qBAAW,QAAQ;AAAA,YACjB,MAAM;AAAA,YACN,IAAI,aAAa,iBAAiB,SAAS;AAAA,UAC7C,CAAC;AACD,2BAAiB,aAAa;AAAA,QAChC;AAEA,yBAAiB,cAAc,CAAC,iBAAiB;AACjD,yBAAiB,cAAc;AAAA,MACjC;AAEA,eAAS,gBAAgB;AAAA,QACvB;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,MACF,GAMY;AACV,gBAAQ,iBAAiB,OAAO,MAAM,GAAG,UAAU,CAAC;AAEpD,cAAM,iBACJ,aAAa,QAAQ,UAAU,iBAAiB,OAAO;AAEzD,YAAI,gBAAgB;AAClB,0BAAgB,kBAAkB,YAAY,YAAY,OAAO;AACjE,iBAAO;AAAA,QACT;AAEA,yBAAiB,SAAS,iBAAiB,OAAO,MAAM,UAAU;AAClE,eAAO;AAAA,MACT;AAEA,eAAS,cACP,kBACA,YACA;AACA,cAAM,UAAU,gBAAgB,kBAAkB,UAAU;AAC5D,YAAI,qBAAqB;AAEzB,eAAO,oBAAoB;AACzB,gBAAM,UAAU,iBAAiB,cAC7B,aACA;AACJ,gBAAM,aAAa;AAAA,YACjB,iBAAiB;AAAA,YACjB;AAAA,UACF;AAEA,cAAI,cAAc,MAAM;AACtB,oBAAQ,iBAAiB,MAAM;AAC/B,6BAAiB,SAAS;AAC1B;AAAA,UACF;AAEA,+BAAqB,gBAAgB;AAAA,YACnC;AAAA,YACA;AAAA,YACA;AAAA,YACA;AAAA,YACA;AAAA,UACF,CAAC;AAAA,QACH;AAAA,MACF;AAEA,aAAO;AAAA,QACL,QAAQ,OAAO;AAAA,UACb,IAAI,gBAGF;AAAA,YACA,WAAW,CAAC,OAAO,eAAe;AAChC,kBAAI,MAAM,SAAS,cAAc;AAC/B,2BAAW,QAAQ,KAAK;AACxB;AAAA,cACF;AAEA,kBAAI,qBAAqB,MAAM,EAAE,KAAK,MAAM;AAC1C,qCAAqB,MAAM,EAAE,IAAI;AAAA,kBAC/B,kBAAkB;AAAA,kBAClB,aAAa;AAAA,kBACb,aAAa;AAAA,kBACb,aAAa;AAAA,kBACb,QAAQ;AAAA,kBACR,WAAW;AAAA,kBACX,QAAQ,MAAM;AAAA,gBAChB;AAAA,cACF;AAEA,oBAAM,mBAAmB,qBAAqB,MAAM,EAAE;AACtD,+BAAiB,UAAU,MAAM;AACjC,4BAAc,kBAAkB,UAAU;AAAA,YAC5C;AAAA,UACF,CAAC;AAAA,QACH;AAAA,QACA,GAAG;AAAA,MACL;AAAA,IACF;AAAA,EACF;AACF;","names":["nextParams"]}
@@ -0,0 +1,11 @@
1
+ import { LanguageModelV3Middleware } from '@ai-sdk/provider';
2
+ export { extractReasoningMiddleware, getPotentialStartIndex } from './reasoning-parser.cjs';
3
+
4
+ type SystemPromptPlacement = "first" | "last";
5
+ interface DefaultSystemPromptMiddlewareOptions {
6
+ systemPrompt: string;
7
+ placement?: SystemPromptPlacement;
8
+ }
9
+ declare function defaultSystemPromptMiddleware({ systemPrompt, placement, }: DefaultSystemPromptMiddlewareOptions): LanguageModelV3Middleware;
10
+
11
+ export { defaultSystemPromptMiddleware };
@@ -0,0 +1,11 @@
1
+ import { LanguageModelV3Middleware } from '@ai-sdk/provider';
2
+ export { extractReasoningMiddleware, getPotentialStartIndex } from './reasoning-parser.js';
3
+
4
+ type SystemPromptPlacement = "first" | "last";
5
+ interface DefaultSystemPromptMiddlewareOptions {
6
+ systemPrompt: string;
7
+ placement?: SystemPromptPlacement;
8
+ }
9
+ declare function defaultSystemPromptMiddleware({ systemPrompt, placement, }: DefaultSystemPromptMiddlewareOptions): LanguageModelV3Middleware;
10
+
11
+ export { defaultSystemPromptMiddleware };
package/dist/index.js ADDED
@@ -0,0 +1,110 @@
1
+ import {
2
+ extractReasoningMiddleware,
3
+ getPotentialStartIndex
4
+ } from "./chunk-Q2TVVB35.js";
5
+
6
+ // src/default-system-prompt.ts
7
+ function extractSystemText(content) {
8
+ if (typeof content === "string") {
9
+ return content;
10
+ }
11
+ if (!Array.isArray(content)) {
12
+ if (content == null) {
13
+ return;
14
+ }
15
+ return String(content);
16
+ }
17
+ const parts = content.map((part) => {
18
+ var _a;
19
+ if ((part == null ? void 0 : part.type) === "text" && "text" in part) {
20
+ return String((_a = part.text) != null ? _a : "");
21
+ }
22
+ return JSON.stringify(part);
23
+ });
24
+ const textParts = parts.filter((value) => value.length > 0);
25
+ if (textParts.length === 0) {
26
+ return;
27
+ }
28
+ return textParts.join("\n");
29
+ }
30
+ function mergeSystemPrompts({
31
+ base,
32
+ addition,
33
+ placement
34
+ }) {
35
+ if (!base) {
36
+ return addition;
37
+ }
38
+ if (addition.length === 0) {
39
+ return base;
40
+ }
41
+ return placement === "first" ? `${addition}
42
+
43
+ ${base}` : `${base}
44
+
45
+ ${addition}`;
46
+ }
47
+ function ensurePromptArray(prompt) {
48
+ if (!prompt) {
49
+ return [];
50
+ }
51
+ return [...prompt];
52
+ }
53
+ function defaultSystemPromptMiddleware({
54
+ systemPrompt,
55
+ placement = "first"
56
+ }) {
57
+ return {
58
+ specificationVersion: "v3",
59
+ transformParams: ({ params }) => {
60
+ const prompt = ensurePromptArray(params.prompt);
61
+ const systemIndex = prompt.findIndex(
62
+ (message) => message.role === "system"
63
+ );
64
+ if (systemIndex === -1) {
65
+ const promptWithSystem = placement === "first" ? [
66
+ {
67
+ role: "system",
68
+ content: systemPrompt
69
+ },
70
+ ...prompt
71
+ ] : [
72
+ ...prompt,
73
+ {
74
+ role: "system",
75
+ content: systemPrompt
76
+ }
77
+ ];
78
+ const nextParams2 = {
79
+ ...params,
80
+ prompt: promptWithSystem
81
+ };
82
+ return Promise.resolve(nextParams2);
83
+ }
84
+ const systemMessage = prompt[systemIndex];
85
+ const baseText = extractSystemText(systemMessage.content);
86
+ const mergedContent = mergeSystemPrompts({
87
+ base: baseText,
88
+ addition: systemPrompt,
89
+ placement
90
+ });
91
+ const updatedPrompt = prompt.map(
92
+ (message, index) => index === systemIndex ? {
93
+ ...message,
94
+ content: mergedContent
95
+ } : message
96
+ );
97
+ const nextParams = {
98
+ ...params,
99
+ prompt: updatedPrompt
100
+ };
101
+ return Promise.resolve(nextParams);
102
+ }
103
+ };
104
+ }
105
+ export {
106
+ defaultSystemPromptMiddleware,
107
+ extractReasoningMiddleware,
108
+ getPotentialStartIndex
109
+ };
110
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/default-system-prompt.ts"],"sourcesContent":["import type {\n LanguageModelV3CallOptions,\n LanguageModelV3Content,\n LanguageModelV3Middleware,\n LanguageModelV3Prompt,\n} from \"@ai-sdk/provider\";\n\ntype SystemPromptPlacement = \"first\" | \"last\";\n\ninterface DefaultSystemPromptMiddlewareOptions {\n systemPrompt: string;\n placement?: SystemPromptPlacement;\n}\n\nfunction extractSystemText(content: unknown): string | undefined {\n if (typeof content === \"string\") {\n return content;\n }\n\n if (!Array.isArray(content)) {\n if (content == null) {\n return;\n }\n return String(content);\n }\n\n const parts = (content as LanguageModelV3Content[]).map((part) => {\n if (part?.type === \"text\" && \"text\" in part) {\n return String(part.text ?? \"\");\n }\n\n return JSON.stringify(part);\n });\n\n const textParts = parts.filter((value) => value.length > 0);\n if (textParts.length === 0) {\n return;\n }\n\n return textParts.join(\"\\n\");\n}\n\nfunction mergeSystemPrompts({\n base,\n addition,\n placement,\n}: {\n base?: string;\n addition: string;\n placement: SystemPromptPlacement;\n}): string {\n if (!base) {\n return addition;\n }\n\n if (addition.length === 0) {\n return base;\n }\n\n return placement === \"first\"\n ? `${addition}\\n\\n${base}`\n : `${base}\\n\\n${addition}`;\n}\n\nfunction ensurePromptArray(\n prompt?: LanguageModelV3Prompt\n): LanguageModelV3Prompt {\n if (!prompt) {\n return [];\n }\n\n return [...prompt];\n}\n\nexport function defaultSystemPromptMiddleware({\n systemPrompt,\n placement = \"first\",\n}: DefaultSystemPromptMiddlewareOptions): LanguageModelV3Middleware {\n return {\n specificationVersion: \"v3\",\n transformParams: ({ params }) => {\n const prompt = ensurePromptArray(params.prompt);\n const systemIndex = prompt.findIndex(\n (message) => message.role === \"system\"\n );\n\n if (systemIndex === -1) {\n const promptWithSystem =\n placement === \"first\"\n ? ([\n {\n role: \"system\" as const,\n content: systemPrompt,\n },\n ...prompt,\n ] as LanguageModelV3Prompt)\n : ([\n ...prompt,\n {\n role: \"system\" as const,\n content: systemPrompt,\n },\n ] as LanguageModelV3Prompt);\n\n const nextParams: LanguageModelV3CallOptions = {\n ...params,\n prompt: promptWithSystem,\n };\n\n return Promise.resolve<LanguageModelV3CallOptions>(nextParams);\n }\n\n const systemMessage = prompt[systemIndex];\n const baseText = extractSystemText(systemMessage.content);\n const mergedContent = mergeSystemPrompts({\n base: baseText,\n addition: systemPrompt,\n placement,\n });\n\n const updatedPrompt = prompt.map((message, index) =>\n index === systemIndex\n ? {\n ...message,\n content: mergedContent,\n }\n : message\n ) as LanguageModelV3Prompt;\n\n const nextParams: LanguageModelV3CallOptions = {\n ...params,\n prompt: updatedPrompt,\n };\n\n return Promise.resolve<LanguageModelV3CallOptions>(nextParams);\n },\n };\n}\n"],"mappings":";;;;;;AAcA,SAAS,kBAAkB,SAAsC;AAC/D,MAAI,OAAO,YAAY,UAAU;AAC/B,WAAO;AAAA,EACT;AAEA,MAAI,CAAC,MAAM,QAAQ,OAAO,GAAG;AAC3B,QAAI,WAAW,MAAM;AACnB;AAAA,IACF;AACA,WAAO,OAAO,OAAO;AAAA,EACvB;AAEA,QAAM,QAAS,QAAqC,IAAI,CAAC,SAAS;AA1BpE;AA2BI,SAAI,6BAAM,UAAS,UAAU,UAAU,MAAM;AAC3C,aAAO,QAAO,UAAK,SAAL,YAAa,EAAE;AAAA,IAC/B;AAEA,WAAO,KAAK,UAAU,IAAI;AAAA,EAC5B,CAAC;AAED,QAAM,YAAY,MAAM,OAAO,CAAC,UAAU,MAAM,SAAS,CAAC;AAC1D,MAAI,UAAU,WAAW,GAAG;AAC1B;AAAA,EACF;AAEA,SAAO,UAAU,KAAK,IAAI;AAC5B;AAEA,SAAS,mBAAmB;AAAA,EAC1B;AAAA,EACA;AAAA,EACA;AACF,GAIW;AACT,MAAI,CAAC,MAAM;AACT,WAAO;AAAA,EACT;AAEA,MAAI,SAAS,WAAW,GAAG;AACzB,WAAO;AAAA,EACT;AAEA,SAAO,cAAc,UACjB,GAAG,QAAQ;AAAA;AAAA,EAAO,IAAI,KACtB,GAAG,IAAI;AAAA;AAAA,EAAO,QAAQ;AAC5B;AAEA,SAAS,kBACP,QACuB;AACvB,MAAI,CAAC,QAAQ;AACX,WAAO,CAAC;AAAA,EACV;AAEA,SAAO,CAAC,GAAG,MAAM;AACnB;AAEO,SAAS,8BAA8B;AAAA,EAC5C;AAAA,EACA,YAAY;AACd,GAAoE;AAClE,SAAO;AAAA,IACL,sBAAsB;AAAA,IACtB,iBAAiB,CAAC,EAAE,OAAO,MAAM;AAC/B,YAAM,SAAS,kBAAkB,OAAO,MAAM;AAC9C,YAAM,cAAc,OAAO;AAAA,QACzB,CAAC,YAAY,QAAQ,SAAS;AAAA,MAChC;AAEA,UAAI,gBAAgB,IAAI;AACtB,cAAM,mBACJ,cAAc,UACT;AAAA,UACC;AAAA,YACE,MAAM;AAAA,YACN,SAAS;AAAA,UACX;AAAA,UACA,GAAG;AAAA,QACL,IACC;AAAA,UACC,GAAG;AAAA,UACH;AAAA,YACE,MAAM;AAAA,YACN,SAAS;AAAA,UACX;AAAA,QACF;AAEN,cAAMA,cAAyC;AAAA,UAC7C,GAAG;AAAA,UACH,QAAQ;AAAA,QACV;AAEA,eAAO,QAAQ,QAAoCA,WAAU;AAAA,MAC/D;AAEA,YAAM,gBAAgB,OAAO,WAAW;AACxC,YAAM,WAAW,kBAAkB,cAAc,OAAO;AACxD,YAAM,gBAAgB,mBAAmB;AAAA,QACvC,MAAM;AAAA,QACN,UAAU;AAAA,QACV;AAAA,MACF,CAAC;AAED,YAAM,gBAAgB,OAAO;AAAA,QAAI,CAAC,SAAS,UACzC,UAAU,cACN;AAAA,UACE,GAAG;AAAA,UACH,SAAS;AAAA,QACX,IACA;AAAA,MACN;AAEA,YAAM,aAAyC;AAAA,QAC7C,GAAG;AAAA,QACH,QAAQ;AAAA,MACV;AAEA,aAAO,QAAQ,QAAoC,UAAU;AAAA,IAC/D;AAAA,EACF;AACF;","names":["nextParams"]}
@@ -0,0 +1,235 @@
1
+ "use strict";
2
+ var __defProp = Object.defineProperty;
3
+ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
4
+ var __getOwnPropNames = Object.getOwnPropertyNames;
5
+ var __hasOwnProp = Object.prototype.hasOwnProperty;
6
+ var __export = (target, all) => {
7
+ for (var name in all)
8
+ __defProp(target, name, { get: all[name], enumerable: true });
9
+ };
10
+ var __copyProps = (to, from, except, desc) => {
11
+ if (from && typeof from === "object" || typeof from === "function") {
12
+ for (let key of __getOwnPropNames(from))
13
+ if (!__hasOwnProp.call(to, key) && key !== except)
14
+ __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
15
+ }
16
+ return to;
17
+ };
18
+ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
19
+
20
+ // src/reasoning-parser/index.ts
21
+ var reasoning_parser_exports = {};
22
+ __export(reasoning_parser_exports, {
23
+ extractReasoningMiddleware: () => extractReasoningMiddleware,
24
+ getPotentialStartIndex: () => getPotentialStartIndex
25
+ });
26
+ module.exports = __toCommonJS(reasoning_parser_exports);
27
+ function getPotentialStartIndex(text, searchedText) {
28
+ if (searchedText.length === 0) {
29
+ return null;
30
+ }
31
+ const directIndex = text.indexOf(searchedText);
32
+ if (directIndex !== -1) {
33
+ return directIndex;
34
+ }
35
+ for (let i = text.length - 1; i >= 0; i -= 1) {
36
+ const suffix = text.substring(i);
37
+ if (searchedText.startsWith(suffix)) {
38
+ return i;
39
+ }
40
+ }
41
+ return null;
42
+ }
43
+ function extractReasoningMiddleware({
44
+ openingTag,
45
+ closingTag,
46
+ separator = "\n",
47
+ startWithReasoning = false
48
+ }) {
49
+ function processTextPart(text, transformedContent) {
50
+ var _a;
51
+ const regexp = new RegExp(`${openingTag}(.*?)${closingTag}`, "gs");
52
+ const matches = Array.from(text.matchAll(regexp));
53
+ if (!matches.length) {
54
+ return;
55
+ }
56
+ const reasoningText = matches.map((match) => match[1]).join(separator);
57
+ let textWithoutReasoning = text;
58
+ for (let i = matches.length - 1; i >= 0; i -= 1) {
59
+ const match = matches[i];
60
+ const beforeMatch = textWithoutReasoning.slice(0, match.index);
61
+ const matchIndex = (_a = match.index) != null ? _a : 0;
62
+ const afterMatch = textWithoutReasoning.slice(
63
+ matchIndex + match[0].length
64
+ );
65
+ textWithoutReasoning = beforeMatch + (beforeMatch.length > 0 && afterMatch.length > 0 ? separator : "") + afterMatch;
66
+ }
67
+ transformedContent.push({
68
+ type: "reasoning",
69
+ text: reasoningText
70
+ });
71
+ transformedContent.push({
72
+ type: "text",
73
+ text: textWithoutReasoning
74
+ });
75
+ }
76
+ return {
77
+ specificationVersion: "v3",
78
+ wrapGenerate: async ({ doGenerate }) => {
79
+ const { content, ...rest } = await doGenerate();
80
+ const transformedContent = [];
81
+ for (const part of content) {
82
+ if (part.type !== "text") {
83
+ transformedContent.push(part);
84
+ continue;
85
+ }
86
+ const text = startWithReasoning ? openingTag + part.text : part.text;
87
+ const regexp = new RegExp(`${openingTag}(.*?)${closingTag}`, "gs");
88
+ const matches = Array.from(text.matchAll(regexp));
89
+ if (!matches.length) {
90
+ transformedContent.push(part);
91
+ continue;
92
+ }
93
+ processTextPart(text, transformedContent);
94
+ }
95
+ return { content: transformedContent, ...rest };
96
+ },
97
+ wrapStream: async ({ doStream }) => {
98
+ const { stream, ...rest } = await doStream();
99
+ const reasoningExtractions = {};
100
+ function createPublisher(activeExtraction, controller) {
101
+ return (text) => {
102
+ if (text.length === 0) {
103
+ return;
104
+ }
105
+ const prefix = getPrefix(activeExtraction);
106
+ enqueueReasoningStart(activeExtraction, controller);
107
+ enqueueDelta(activeExtraction, controller, prefix, text);
108
+ updateExtractionState(activeExtraction);
109
+ };
110
+ }
111
+ function getPrefix(activeExtraction) {
112
+ return activeExtraction.afterSwitch && (activeExtraction.isReasoning ? !activeExtraction.isFirstReasoning : !activeExtraction.isFirstText) ? separator : "";
113
+ }
114
+ function enqueueReasoningStart(activeExtraction, controller) {
115
+ if (activeExtraction.afterSwitch && activeExtraction.isReasoning || activeExtraction.isFirstReasoning) {
116
+ controller.enqueue({
117
+ type: "reasoning-start",
118
+ id: `reasoning-${activeExtraction.idCounter}`
119
+ });
120
+ }
121
+ }
122
+ function enqueueDelta(activeExtraction, controller, prefix, text) {
123
+ controller.enqueue(
124
+ activeExtraction.isReasoning ? {
125
+ type: "reasoning-delta",
126
+ delta: prefix + text,
127
+ id: `reasoning-${activeExtraction.idCounter}`
128
+ } : {
129
+ type: "text-delta",
130
+ delta: prefix + text,
131
+ id: activeExtraction.textId
132
+ }
133
+ );
134
+ }
135
+ function updateExtractionState(activeExtraction) {
136
+ activeExtraction.afterSwitch = false;
137
+ if (activeExtraction.isReasoning) {
138
+ activeExtraction.isFirstReasoning = false;
139
+ } else {
140
+ activeExtraction.isFirstText = false;
141
+ }
142
+ }
143
+ function handleFullMatch(activeExtraction, controller, startIndex, nextTag) {
144
+ activeExtraction.buffer = activeExtraction.buffer.slice(
145
+ startIndex + nextTag.length
146
+ );
147
+ if (activeExtraction.isReasoning) {
148
+ controller.enqueue({
149
+ type: "reasoning-end",
150
+ id: `reasoning-${activeExtraction.idCounter}`
151
+ });
152
+ activeExtraction.idCounter += 1;
153
+ }
154
+ activeExtraction.isReasoning = !activeExtraction.isReasoning;
155
+ activeExtraction.afterSwitch = true;
156
+ }
157
+ function processTagMatch({
158
+ activeExtraction,
159
+ controller,
160
+ publish,
161
+ startIndex,
162
+ nextTag
163
+ }) {
164
+ publish(activeExtraction.buffer.slice(0, startIndex));
165
+ const foundFullMatch = startIndex + nextTag.length <= activeExtraction.buffer.length;
166
+ if (foundFullMatch) {
167
+ handleFullMatch(activeExtraction, controller, startIndex, nextTag);
168
+ return true;
169
+ }
170
+ activeExtraction.buffer = activeExtraction.buffer.slice(startIndex);
171
+ return false;
172
+ }
173
+ function processBuffer(activeExtraction, controller) {
174
+ const publish = createPublisher(activeExtraction, controller);
175
+ let continueProcessing = true;
176
+ while (continueProcessing) {
177
+ const nextTag = activeExtraction.isReasoning ? closingTag : openingTag;
178
+ const startIndex = getPotentialStartIndex(
179
+ activeExtraction.buffer,
180
+ nextTag
181
+ );
182
+ if (startIndex == null) {
183
+ publish(activeExtraction.buffer);
184
+ activeExtraction.buffer = "";
185
+ break;
186
+ }
187
+ continueProcessing = processTagMatch({
188
+ activeExtraction,
189
+ controller,
190
+ publish,
191
+ startIndex,
192
+ nextTag
193
+ });
194
+ }
195
+ }
196
+ return {
197
+ stream: stream.pipeThrough(
198
+ new TransformStream({
199
+ transform: (chunk, controller) => {
200
+ if (chunk.type !== "text-delta") {
201
+ controller.enqueue(chunk);
202
+ return;
203
+ }
204
+ if (reasoningExtractions[chunk.id] == null) {
205
+ reasoningExtractions[chunk.id] = {
206
+ isFirstReasoning: true,
207
+ isFirstText: true,
208
+ afterSwitch: false,
209
+ isReasoning: startWithReasoning,
210
+ buffer: "",
211
+ idCounter: 0,
212
+ textId: chunk.id
213
+ };
214
+ }
215
+ const activeExtraction = reasoningExtractions[chunk.id];
216
+ activeExtraction.buffer += chunk.delta;
217
+ processBuffer(activeExtraction, controller);
218
+ }
219
+ })
220
+ ),
221
+ ...rest
222
+ };
223
+ }
224
+ };
225
+ }
226
+ // Annotate the CommonJS export names for ESM import in node:
227
+ 0 && (module.exports = {
228
+ extractReasoningMiddleware,
229
+ getPotentialStartIndex
230
+ });
231
+ /**
232
+ * @license
233
+ * Copyright (c) 2021-present, FriendliAI Inc. All rights reserved.
234
+ */
235
+ //# sourceMappingURL=reasoning-parser.cjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/reasoning-parser/index.ts"],"sourcesContent":["/**\n * @license\n * Copyright (c) 2021-present, FriendliAI Inc. All rights reserved.\n */\n\nimport type {\n LanguageModelV3Content,\n LanguageModelV3Middleware,\n LanguageModelV3StreamPart,\n} from \"@ai-sdk/provider\";\n\n/**\n * All code below is forked from the following link:\n * https://github.com/vercel/ai/blob/v5/packages/ai/core/middleware/extract-reasoning-middleware.ts\n */\n\n/**\n * Returns the index of the start of the searchedText in the text, or null if it\n * is not found.\n */\nexport function getPotentialStartIndex(\n text: string,\n searchedText: string\n): number | null {\n // Return null immediately if searchedText is empty.\n if (searchedText.length === 0) {\n return null;\n }\n\n // Check if the searchedText exists as a direct substring of text.\n const directIndex = text.indexOf(searchedText);\n if (directIndex !== -1) {\n return directIndex;\n }\n\n // Otherwise, look for the largest suffix of \"text\" that matches\n // a prefix of \"searchedText\". We go from the end of text inward.\n for (let i = text.length - 1; i >= 0; i -= 1) {\n const suffix = text.substring(i);\n if (searchedText.startsWith(suffix)) {\n return i;\n }\n }\n\n return null;\n}\n\n/**\n * Extract an XML-tagged reasoning section from the generated text and exposes it\n * as a `reasoning` property on the result.\n *\n * @param openingTag - The opening XML tag to extract reasoning from.\n * @param closingTag - The closing XML tag to extract reasoning from.\n * @param separator - The separator to use between reasoning and text sections.\n * @param startWithReasoning - Whether to start with reasoning tokens.\n */\nexport function extractReasoningMiddleware({\n openingTag,\n closingTag,\n separator = \"\\n\",\n startWithReasoning = false,\n}: {\n openingTag: string;\n closingTag: string;\n separator?: string;\n startWithReasoning?: boolean;\n}): LanguageModelV3Middleware {\n function processTextPart(\n text: string,\n transformedContent: LanguageModelV3Content[]\n ) {\n const regexp = new RegExp(`${openingTag}(.*?)${closingTag}`, \"gs\");\n const matches = Array.from(text.matchAll(regexp));\n\n if (!matches.length) {\n return;\n }\n\n const reasoningText = matches.map((match) => match[1]).join(separator);\n\n let textWithoutReasoning = text;\n for (let i = matches.length - 1; i >= 0; i -= 1) {\n const match = matches[i];\n\n const beforeMatch = textWithoutReasoning.slice(0, match.index);\n const matchIndex = match.index ?? 0;\n const afterMatch = textWithoutReasoning.slice(\n matchIndex + match[0].length\n );\n\n textWithoutReasoning =\n beforeMatch +\n (beforeMatch.length > 0 && afterMatch.length > 0 ? separator : \"\") +\n afterMatch;\n }\n\n transformedContent.push({\n type: \"reasoning\",\n text: reasoningText,\n });\n\n transformedContent.push({\n type: \"text\",\n text: textWithoutReasoning,\n });\n }\n\n return {\n specificationVersion: \"v3\",\n wrapGenerate: async ({ doGenerate }) => {\n const { content, ...rest } = await doGenerate();\n\n const transformedContent: LanguageModelV3Content[] = [];\n for (const part of content) {\n if (part.type !== \"text\") {\n transformedContent.push(part);\n continue;\n }\n\n const text = startWithReasoning ? openingTag + part.text : part.text;\n const regexp = new RegExp(`${openingTag}(.*?)${closingTag}`, \"gs\");\n const matches = Array.from(text.matchAll(regexp));\n\n if (!matches.length) {\n transformedContent.push(part);\n continue;\n }\n\n processTextPart(text, transformedContent);\n }\n\n return { content: transformedContent, ...rest };\n },\n\n wrapStream: async ({ doStream }) => {\n const { stream, ...rest } = await doStream();\n\n interface ExtractionState {\n isFirstReasoning: boolean;\n isFirstText: boolean;\n afterSwitch: boolean;\n isReasoning: boolean;\n buffer: string;\n idCounter: number;\n textId: string;\n }\n\n const reasoningExtractions: Record<string, ExtractionState> = {};\n\n function createPublisher(\n activeExtraction: ExtractionState,\n controller: TransformStreamDefaultController<LanguageModelV3StreamPart>\n ) {\n return (text: string) => {\n if (text.length === 0) {\n return;\n }\n\n const prefix = getPrefix(activeExtraction);\n enqueueReasoningStart(activeExtraction, controller);\n enqueueDelta(activeExtraction, controller, prefix, text);\n updateExtractionState(activeExtraction);\n };\n }\n\n function getPrefix(activeExtraction: ExtractionState): string {\n return activeExtraction.afterSwitch &&\n (activeExtraction.isReasoning\n ? !activeExtraction.isFirstReasoning\n : !activeExtraction.isFirstText)\n ? separator\n : \"\";\n }\n\n function enqueueReasoningStart(\n activeExtraction: ExtractionState,\n controller: TransformStreamDefaultController<LanguageModelV3StreamPart>\n ) {\n if (\n (activeExtraction.afterSwitch && activeExtraction.isReasoning) ||\n activeExtraction.isFirstReasoning\n ) {\n controller.enqueue({\n type: \"reasoning-start\",\n id: `reasoning-${activeExtraction.idCounter}`,\n });\n }\n }\n\n function enqueueDelta(\n activeExtraction: ExtractionState,\n controller: TransformStreamDefaultController<LanguageModelV3StreamPart>,\n prefix: string,\n text: string\n ) {\n controller.enqueue(\n activeExtraction.isReasoning\n ? {\n type: \"reasoning-delta\",\n delta: prefix + text,\n id: `reasoning-${activeExtraction.idCounter}`,\n }\n : {\n type: \"text-delta\",\n delta: prefix + text,\n id: activeExtraction.textId,\n }\n );\n }\n\n function updateExtractionState(activeExtraction: ExtractionState) {\n activeExtraction.afterSwitch = false;\n if (activeExtraction.isReasoning) {\n activeExtraction.isFirstReasoning = false;\n } else {\n activeExtraction.isFirstText = false;\n }\n }\n\n function handleFullMatch(\n activeExtraction: ExtractionState,\n controller: TransformStreamDefaultController<LanguageModelV3StreamPart>,\n startIndex: number,\n nextTag: string\n ) {\n activeExtraction.buffer = activeExtraction.buffer.slice(\n startIndex + nextTag.length\n );\n\n if (activeExtraction.isReasoning) {\n controller.enqueue({\n type: \"reasoning-end\",\n id: `reasoning-${activeExtraction.idCounter}`,\n });\n activeExtraction.idCounter += 1;\n }\n\n activeExtraction.isReasoning = !activeExtraction.isReasoning;\n activeExtraction.afterSwitch = true;\n }\n\n function processTagMatch({\n activeExtraction,\n controller,\n publish,\n startIndex,\n nextTag,\n }: {\n activeExtraction: ExtractionState;\n controller: TransformStreamDefaultController<LanguageModelV3StreamPart>;\n publish: (text: string) => void;\n startIndex: number;\n nextTag: string;\n }): boolean {\n publish(activeExtraction.buffer.slice(0, startIndex));\n\n const foundFullMatch =\n startIndex + nextTag.length <= activeExtraction.buffer.length;\n\n if (foundFullMatch) {\n handleFullMatch(activeExtraction, controller, startIndex, nextTag);\n return true;\n }\n\n activeExtraction.buffer = activeExtraction.buffer.slice(startIndex);\n return false;\n }\n\n function processBuffer(\n activeExtraction: ExtractionState,\n controller: TransformStreamDefaultController<LanguageModelV3StreamPart>\n ) {\n const publish = createPublisher(activeExtraction, controller);\n let continueProcessing = true;\n\n while (continueProcessing) {\n const nextTag = activeExtraction.isReasoning\n ? closingTag\n : openingTag;\n const startIndex = getPotentialStartIndex(\n activeExtraction.buffer,\n nextTag\n );\n\n if (startIndex == null) {\n publish(activeExtraction.buffer);\n activeExtraction.buffer = \"\";\n break;\n }\n\n continueProcessing = processTagMatch({\n activeExtraction,\n controller,\n publish,\n startIndex,\n nextTag,\n });\n }\n }\n\n return {\n stream: stream.pipeThrough(\n new TransformStream<\n LanguageModelV3StreamPart,\n LanguageModelV3StreamPart\n >({\n transform: (chunk, controller) => {\n if (chunk.type !== \"text-delta\") {\n controller.enqueue(chunk);\n return;\n }\n\n if (reasoningExtractions[chunk.id] == null) {\n reasoningExtractions[chunk.id] = {\n isFirstReasoning: true,\n isFirstText: true,\n afterSwitch: false,\n isReasoning: startWithReasoning,\n buffer: \"\",\n idCounter: 0,\n textId: chunk.id,\n };\n }\n\n const activeExtraction = reasoningExtractions[chunk.id];\n activeExtraction.buffer += chunk.delta;\n processBuffer(activeExtraction, controller);\n },\n })\n ),\n ...rest,\n };\n },\n };\n}\n"],"mappings":"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","names":[]}
@@ -0,0 +1,33 @@
1
+ import { LanguageModelV3Middleware } from '@ai-sdk/provider';
2
+
3
+ /**
4
+ * @license
5
+ * Copyright (c) 2021-present, FriendliAI Inc. All rights reserved.
6
+ */
7
+
8
+ /**
9
+ * All code below is forked from the following link:
10
+ * https://github.com/vercel/ai/blob/v5/packages/ai/core/middleware/extract-reasoning-middleware.ts
11
+ */
12
+ /**
13
+ * Returns the index of the start of the searchedText in the text, or null if it
14
+ * is not found.
15
+ */
16
+ declare function getPotentialStartIndex(text: string, searchedText: string): number | null;
17
+ /**
18
+ * Extract an XML-tagged reasoning section from the generated text and exposes it
19
+ * as a `reasoning` property on the result.
20
+ *
21
+ * @param openingTag - The opening XML tag to extract reasoning from.
22
+ * @param closingTag - The closing XML tag to extract reasoning from.
23
+ * @param separator - The separator to use between reasoning and text sections.
24
+ * @param startWithReasoning - Whether to start with reasoning tokens.
25
+ */
26
+ declare function extractReasoningMiddleware({ openingTag, closingTag, separator, startWithReasoning, }: {
27
+ openingTag: string;
28
+ closingTag: string;
29
+ separator?: string;
30
+ startWithReasoning?: boolean;
31
+ }): LanguageModelV3Middleware;
32
+
33
+ export { extractReasoningMiddleware, getPotentialStartIndex };
@@ -0,0 +1,33 @@
1
+ import { LanguageModelV3Middleware } from '@ai-sdk/provider';
2
+
3
+ /**
4
+ * @license
5
+ * Copyright (c) 2021-present, FriendliAI Inc. All rights reserved.
6
+ */
7
+
8
+ /**
9
+ * All code below is forked from the following link:
10
+ * https://github.com/vercel/ai/blob/v5/packages/ai/core/middleware/extract-reasoning-middleware.ts
11
+ */
12
+ /**
13
+ * Returns the index of the start of the searchedText in the text, or null if it
14
+ * is not found.
15
+ */
16
+ declare function getPotentialStartIndex(text: string, searchedText: string): number | null;
17
+ /**
18
+ * Extract an XML-tagged reasoning section from the generated text and exposes it
19
+ * as a `reasoning` property on the result.
20
+ *
21
+ * @param openingTag - The opening XML tag to extract reasoning from.
22
+ * @param closingTag - The closing XML tag to extract reasoning from.
23
+ * @param separator - The separator to use between reasoning and text sections.
24
+ * @param startWithReasoning - Whether to start with reasoning tokens.
25
+ */
26
+ declare function extractReasoningMiddleware({ openingTag, closingTag, separator, startWithReasoning, }: {
27
+ openingTag: string;
28
+ closingTag: string;
29
+ separator?: string;
30
+ startWithReasoning?: boolean;
31
+ }): LanguageModelV3Middleware;
32
+
33
+ export { extractReasoningMiddleware, getPotentialStartIndex };
@@ -0,0 +1,9 @@
1
+ import {
2
+ extractReasoningMiddleware,
3
+ getPotentialStartIndex
4
+ } from "./chunk-Q2TVVB35.js";
5
+ export {
6
+ extractReasoningMiddleware,
7
+ getPotentialStartIndex
8
+ };
9
+ //# sourceMappingURL=reasoning-parser.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":[],"sourcesContent":[],"mappings":"","names":[]}
package/package.json ADDED
@@ -0,0 +1,54 @@
1
+ {
2
+ "name": "@ai-sdk-tool/middleware",
3
+ "version": "0.0.0",
4
+ "description": "Collection of reusable AI SDK middlewares",
5
+ "type": "module",
6
+ "repository": {
7
+ "type": "git",
8
+ "url": "https://github.com/minpeter/ai-sdk-tool-call-middleware",
9
+ "directory": "packages/middleware"
10
+ },
11
+ "main": "./dist/index.js",
12
+ "module": "./dist/index.mjs",
13
+ "types": "./dist/index.d.ts",
14
+ "exports": {
15
+ ".": {
16
+ "types": "./dist/index.d.ts",
17
+ "import": "./dist/index.js",
18
+ "require": "./dist/index.cjs"
19
+ },
20
+ "./reasoning-parser": {
21
+ "types": "./dist/reasoning-parser.d.ts",
22
+ "import": "./dist/reasoning-parser.js",
23
+ "require": "./dist/reasoning-parser.cjs"
24
+ }
25
+ },
26
+ "files": [
27
+ "dist/**/*"
28
+ ],
29
+ "publishConfig": {
30
+ "access": "public"
31
+ },
32
+ "scripts": {
33
+ "build": "pnpm clean && tsup --tsconfig tsconfig.build.json",
34
+ "build:watch": "pnpm clean && tsup --watch --tsconfig tsconfig.build.json",
35
+ "clean": "rm -rf dist *.tsbuildinfo",
36
+ "typecheck": "tsc --noEmit",
37
+ "test": "vitest run"
38
+ },
39
+ "dependencies": {
40
+ "@ai-sdk/provider": "3.0.0"
41
+ },
42
+ "devDependencies": {
43
+ "@ai-sdkx/tsconfig": "workspace:*",
44
+ "@types/node": "^25.0.3",
45
+ "tsup": "^8.5.1"
46
+ },
47
+ "keywords": [
48
+ "ai",
49
+ "sdk",
50
+ "middleware"
51
+ ],
52
+ "author": "",
53
+ "license": "Apache-2.0"
54
+ }