@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.
- package/dist/chunk-Q2TVVB35.js +210 -0
- package/dist/chunk-Q2TVVB35.js.map +1 -0
- package/dist/index.cjs +339 -0
- package/dist/index.cjs.map +1 -0
- package/dist/index.d.cts +11 -0
- package/dist/index.d.ts +11 -0
- package/dist/index.js +110 -0
- package/dist/index.js.map +1 -0
- package/dist/reasoning-parser.cjs +235 -0
- package/dist/reasoning-parser.cjs.map +1 -0
- package/dist/reasoning-parser.d.cts +33 -0
- package/dist/reasoning-parser.d.ts +33 -0
- package/dist/reasoning-parser.js +9 -0
- package/dist/reasoning-parser.js.map +1 -0
- package/package.json +54 -0
|
@@ -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":"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","names":["nextParams"]}
|
package/dist/index.d.cts
ADDED
|
@@ -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 };
|
package/dist/index.d.ts
ADDED
|
@@ -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 @@
|
|
|
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
|
+
}
|