@cartanova/qgrid-ai-sdk 2.6.8 → 2.6.10
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.js +259 -2
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -1,3 +1,257 @@
|
|
|
1
|
+
//#region src/envelope-stream-parser.ts
|
|
2
|
+
const ESCAPE_MAP = {
|
|
3
|
+
"\"": "\"",
|
|
4
|
+
"\\": "\\",
|
|
5
|
+
"/": "/",
|
|
6
|
+
b: "\b",
|
|
7
|
+
f: "\f",
|
|
8
|
+
n: "\n",
|
|
9
|
+
r: "\r",
|
|
10
|
+
t: " "
|
|
11
|
+
};
|
|
12
|
+
const LITERAL_CHARS = /[0-9a-zA-Z+\-.eE]/;
|
|
13
|
+
function createEnvelopeStreamParser(answerKind) {
|
|
14
|
+
let action = null;
|
|
15
|
+
let discard = false;
|
|
16
|
+
let pending = "";
|
|
17
|
+
let out = "";
|
|
18
|
+
const emit = (text) => {
|
|
19
|
+
if (discard || text === "") return;
|
|
20
|
+
if (action === "answer") out += text;
|
|
21
|
+
else pending += text;
|
|
22
|
+
};
|
|
23
|
+
const resolveAction = (value) => {
|
|
24
|
+
if (action !== null) return;
|
|
25
|
+
if (value === "answer") {
|
|
26
|
+
action = "answer";
|
|
27
|
+
out += pending;
|
|
28
|
+
pending = "";
|
|
29
|
+
} else {
|
|
30
|
+
action = "tool_call";
|
|
31
|
+
discard = true;
|
|
32
|
+
pending = "";
|
|
33
|
+
}
|
|
34
|
+
};
|
|
35
|
+
const stack = [];
|
|
36
|
+
let mode = "value";
|
|
37
|
+
let currentKey = null;
|
|
38
|
+
let inString = false;
|
|
39
|
+
let stringIsKey = false;
|
|
40
|
+
let escape = false;
|
|
41
|
+
let unicode = null;
|
|
42
|
+
let keyBuf = "";
|
|
43
|
+
let actionBuf = "";
|
|
44
|
+
let capture = "none";
|
|
45
|
+
let rawActive = false;
|
|
46
|
+
let rawDepth = 0;
|
|
47
|
+
let rawInString = false;
|
|
48
|
+
let rawEscape = false;
|
|
49
|
+
let rawIsLiteral = false;
|
|
50
|
+
const atEnvelopeLevel = () => stack.length === 2 && stack[0].openedAtKey === null && stack[1].openedAtKey === "result";
|
|
51
|
+
const deliverStringChar = (ch) => {
|
|
52
|
+
if (stringIsKey) keyBuf += ch;
|
|
53
|
+
else if (capture === "action") actionBuf += ch;
|
|
54
|
+
else if (capture === "answer-text") emit(ch);
|
|
55
|
+
};
|
|
56
|
+
const endString = () => {
|
|
57
|
+
inString = false;
|
|
58
|
+
if (stringIsKey) {
|
|
59
|
+
currentKey = keyBuf;
|
|
60
|
+
mode = "colon";
|
|
61
|
+
return;
|
|
62
|
+
}
|
|
63
|
+
if (capture === "action") resolveAction(actionBuf);
|
|
64
|
+
capture = "none";
|
|
65
|
+
mode = "afterValue";
|
|
66
|
+
};
|
|
67
|
+
const endRaw = (reprocessChar) => {
|
|
68
|
+
rawActive = false;
|
|
69
|
+
mode = "afterValue";
|
|
70
|
+
if (reprocessChar !== void 0) step(reprocessChar);
|
|
71
|
+
};
|
|
72
|
+
const rawStep = (c) => {
|
|
73
|
+
if (rawIsLiteral) {
|
|
74
|
+
if (LITERAL_CHARS.test(c)) return;
|
|
75
|
+
rawIsLiteral = false;
|
|
76
|
+
endRaw(c);
|
|
77
|
+
return;
|
|
78
|
+
}
|
|
79
|
+
emit(c);
|
|
80
|
+
if (rawInString) {
|
|
81
|
+
if (rawEscape) rawEscape = false;
|
|
82
|
+
else if (c === "\\") rawEscape = true;
|
|
83
|
+
else if (c === "\"") {
|
|
84
|
+
rawInString = false;
|
|
85
|
+
if (rawDepth === 0) endRaw();
|
|
86
|
+
}
|
|
87
|
+
return;
|
|
88
|
+
}
|
|
89
|
+
if (c === "\"") rawInString = true;
|
|
90
|
+
else if (c === "{" || c === "[") rawDepth++;
|
|
91
|
+
else if (c === "}" || c === "]") {
|
|
92
|
+
rawDepth--;
|
|
93
|
+
if (rawDepth === 0) endRaw();
|
|
94
|
+
}
|
|
95
|
+
};
|
|
96
|
+
const startValue = (c) => {
|
|
97
|
+
const watchedAction = atEnvelopeLevel() && currentKey === "action";
|
|
98
|
+
const watchedAnswer = atEnvelopeLevel() && currentKey === "answer";
|
|
99
|
+
if (watchedAnswer && answerKind === "json") {
|
|
100
|
+
rawActive = true;
|
|
101
|
+
rawDepth = 0;
|
|
102
|
+
rawInString = false;
|
|
103
|
+
rawEscape = false;
|
|
104
|
+
rawIsLiteral = false;
|
|
105
|
+
if (c === "{" || c === "[") {
|
|
106
|
+
rawDepth = 1;
|
|
107
|
+
emit(c);
|
|
108
|
+
} else if (c === "\"") {
|
|
109
|
+
rawInString = true;
|
|
110
|
+
emit(c);
|
|
111
|
+
} else rawIsLiteral = true;
|
|
112
|
+
return;
|
|
113
|
+
}
|
|
114
|
+
if (c === "\"") {
|
|
115
|
+
inString = true;
|
|
116
|
+
stringIsKey = false;
|
|
117
|
+
escape = false;
|
|
118
|
+
unicode = null;
|
|
119
|
+
if (watchedAction) {
|
|
120
|
+
capture = "action";
|
|
121
|
+
actionBuf = "";
|
|
122
|
+
} else if (watchedAnswer && answerKind === "text") capture = "answer-text";
|
|
123
|
+
else capture = "none";
|
|
124
|
+
return;
|
|
125
|
+
}
|
|
126
|
+
if (c === "{") {
|
|
127
|
+
stack.push({
|
|
128
|
+
type: "object",
|
|
129
|
+
openedAtKey: currentKey
|
|
130
|
+
});
|
|
131
|
+
currentKey = null;
|
|
132
|
+
mode = "key";
|
|
133
|
+
return;
|
|
134
|
+
}
|
|
135
|
+
if (c === "[") {
|
|
136
|
+
stack.push({
|
|
137
|
+
type: "array",
|
|
138
|
+
openedAtKey: currentKey
|
|
139
|
+
});
|
|
140
|
+
currentKey = null;
|
|
141
|
+
mode = "value";
|
|
142
|
+
return;
|
|
143
|
+
}
|
|
144
|
+
if (c === "]" && stack[stack.length - 1]?.type === "array") {
|
|
145
|
+
stack.pop();
|
|
146
|
+
mode = "afterValue";
|
|
147
|
+
return;
|
|
148
|
+
}
|
|
149
|
+
if (LITERAL_CHARS.test(c)) {
|
|
150
|
+
mode = "literal";
|
|
151
|
+
return;
|
|
152
|
+
}
|
|
153
|
+
discard = true;
|
|
154
|
+
};
|
|
155
|
+
const step = (c) => {
|
|
156
|
+
if (discard) return;
|
|
157
|
+
if (rawActive) {
|
|
158
|
+
rawStep(c);
|
|
159
|
+
return;
|
|
160
|
+
}
|
|
161
|
+
if (inString) {
|
|
162
|
+
if (unicode !== null) {
|
|
163
|
+
unicode += c;
|
|
164
|
+
if (unicode.length === 4) {
|
|
165
|
+
const code = Number.parseInt(unicode, 16);
|
|
166
|
+
unicode = null;
|
|
167
|
+
if (Number.isNaN(code)) {
|
|
168
|
+
discard = true;
|
|
169
|
+
return;
|
|
170
|
+
}
|
|
171
|
+
deliverStringChar(String.fromCharCode(code));
|
|
172
|
+
}
|
|
173
|
+
return;
|
|
174
|
+
}
|
|
175
|
+
if (escape) {
|
|
176
|
+
escape = false;
|
|
177
|
+
if (c === "u") {
|
|
178
|
+
unicode = "";
|
|
179
|
+
return;
|
|
180
|
+
}
|
|
181
|
+
const mapped = ESCAPE_MAP[c];
|
|
182
|
+
if (mapped === void 0) {
|
|
183
|
+
discard = true;
|
|
184
|
+
return;
|
|
185
|
+
}
|
|
186
|
+
deliverStringChar(mapped);
|
|
187
|
+
return;
|
|
188
|
+
}
|
|
189
|
+
if (c === "\\") {
|
|
190
|
+
escape = true;
|
|
191
|
+
return;
|
|
192
|
+
}
|
|
193
|
+
if (c === "\"") {
|
|
194
|
+
endString();
|
|
195
|
+
return;
|
|
196
|
+
}
|
|
197
|
+
deliverStringChar(c);
|
|
198
|
+
return;
|
|
199
|
+
}
|
|
200
|
+
if (mode === "literal") {
|
|
201
|
+
if (LITERAL_CHARS.test(c)) return;
|
|
202
|
+
mode = "afterValue";
|
|
203
|
+
step(c);
|
|
204
|
+
return;
|
|
205
|
+
}
|
|
206
|
+
if (c === " " || c === " " || c === "\n" || c === "\r") return;
|
|
207
|
+
switch (mode) {
|
|
208
|
+
case "value":
|
|
209
|
+
startValue(c);
|
|
210
|
+
return;
|
|
211
|
+
case "key":
|
|
212
|
+
if (c === "\"") {
|
|
213
|
+
inString = true;
|
|
214
|
+
stringIsKey = true;
|
|
215
|
+
escape = false;
|
|
216
|
+
unicode = null;
|
|
217
|
+
keyBuf = "";
|
|
218
|
+
} else if (c === "}") {
|
|
219
|
+
stack.pop();
|
|
220
|
+
mode = "afterValue";
|
|
221
|
+
} else discard = true;
|
|
222
|
+
return;
|
|
223
|
+
case "colon":
|
|
224
|
+
if (c === ":") {
|
|
225
|
+
mode = "value";
|
|
226
|
+
stringIsKey = false;
|
|
227
|
+
} else discard = true;
|
|
228
|
+
return;
|
|
229
|
+
case "afterValue":
|
|
230
|
+
if (c === ",") {
|
|
231
|
+
const frame = stack[stack.length - 1];
|
|
232
|
+
if (!frame) {
|
|
233
|
+
discard = true;
|
|
234
|
+
return;
|
|
235
|
+
}
|
|
236
|
+
currentKey = null;
|
|
237
|
+
mode = frame.type === "object" ? "key" : "value";
|
|
238
|
+
} else if (c === "}" || c === "]") stack.pop();
|
|
239
|
+
else discard = true;
|
|
240
|
+
return;
|
|
241
|
+
}
|
|
242
|
+
};
|
|
243
|
+
return { push(chunk) {
|
|
244
|
+
if (discard) return "";
|
|
245
|
+
for (const c of chunk) {
|
|
246
|
+
step(c);
|
|
247
|
+
if (discard) break;
|
|
248
|
+
}
|
|
249
|
+
const emitted = out;
|
|
250
|
+
out = "";
|
|
251
|
+
return emitted;
|
|
252
|
+
} };
|
|
253
|
+
}
|
|
254
|
+
//#endregion
|
|
1
255
|
//#region src/qgrid.constant.ts
|
|
2
256
|
const QGRID_PROVIDER_NAME = "qgrid";
|
|
3
257
|
const THREAD_COORD_TTL_MS = 10 * 6e4;
|
|
@@ -941,11 +1195,14 @@ function qgrid(modelId, config) {
|
|
|
941
1195
|
const textId = `${TEXT_STREAM_ID_PREFIX}_${Math.random().toString(36).slice(2, 10)}`;
|
|
942
1196
|
let textStarted = false;
|
|
943
1197
|
let deltaTextEmitted = false;
|
|
1198
|
+
const envelopeParser = hasTools ? createEnvelopeStreamParser(jsonSchema ? "json" : "text") : void 0;
|
|
944
1199
|
return { stream: new ReadableStream({ async start(controller) {
|
|
945
1200
|
try {
|
|
946
1201
|
let streamCompleted = false;
|
|
947
1202
|
for await (const event of parseSSE(streamRes.body)) if (event.type === "delta") {
|
|
948
|
-
|
|
1203
|
+
const raw = event.data.text;
|
|
1204
|
+
const text = envelopeParser ? envelopeParser.push(raw) : raw;
|
|
1205
|
+
if (text !== "") {
|
|
949
1206
|
if (!textStarted) {
|
|
950
1207
|
controller.enqueue({
|
|
951
1208
|
type: "text-start",
|
|
@@ -956,7 +1213,7 @@ function qgrid(modelId, config) {
|
|
|
956
1213
|
controller.enqueue({
|
|
957
1214
|
type: "text-delta",
|
|
958
1215
|
id: textId,
|
|
959
|
-
delta:
|
|
1216
|
+
delta: text
|
|
960
1217
|
});
|
|
961
1218
|
deltaTextEmitted = true;
|
|
962
1219
|
}
|