@xsai-ext/telemetry 0.5.0-beta.1 → 0.5.0-beta.3
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 +53 -99
- package/package.json +8 -8
package/dist/index.js
CHANGED
|
@@ -1,9 +1,9 @@
|
|
|
1
|
-
import { embed as embed$1, clean, embedMany as embedMany$1, trampoline,
|
|
1
|
+
import { embed as embed$1, clean, embedMany as embedMany$1, trampoline, resolvePrepareStep, chat, responseJSON, normalizeChatCompletionUsage, InvalidResponseError, stepCountAtLeast, executeTool, shouldStop, DelayedPromise, objCamelToSnake, computeTotalUsage } from 'xsai';
|
|
2
2
|
export * from 'xsai';
|
|
3
3
|
import { trace, SpanStatusCode } from '@opentelemetry/api';
|
|
4
|
-
import { EventSourceParserStream } from '
|
|
4
|
+
import { createControlledStream, errorControllers, closeControllers, EventSourceParserStream, JsonMessageTransformStream } from '@xsai/shared-stream';
|
|
5
5
|
|
|
6
|
-
var version = "0.5.0-beta.
|
|
6
|
+
var version = "0.5.0-beta.3";
|
|
7
7
|
var pkg = {
|
|
8
8
|
version: version};
|
|
9
9
|
|
|
@@ -135,8 +135,8 @@ const generateText = async (options) => {
|
|
|
135
135
|
const rawGenerateText = async (options2) => {
|
|
136
136
|
const messages = options2.steps == null ? structuredClone(options2.messages) : options2.messages;
|
|
137
137
|
const steps = options2.steps ?? [];
|
|
138
|
-
const stepOptions = await
|
|
139
|
-
messages,
|
|
138
|
+
const stepOptions = await resolvePrepareStep({
|
|
139
|
+
input: messages,
|
|
140
140
|
model: options2.model,
|
|
141
141
|
prepareStep: options2.prepareStep,
|
|
142
142
|
stepNumber: steps.length,
|
|
@@ -145,20 +145,21 @@ const generateText = async (options) => {
|
|
|
145
145
|
});
|
|
146
146
|
return recordSpan(chatSpan({
|
|
147
147
|
...options2,
|
|
148
|
-
messages: stepOptions.
|
|
148
|
+
messages: stepOptions.input,
|
|
149
149
|
model: stepOptions.model,
|
|
150
150
|
toolChoice: stepOptions.toolChoice
|
|
151
151
|
}, tracer), async (span) => chat({
|
|
152
152
|
...options2,
|
|
153
153
|
maxSteps: void 0,
|
|
154
|
-
messages: stepOptions.
|
|
154
|
+
messages: stepOptions.input,
|
|
155
155
|
model: stepOptions.model,
|
|
156
156
|
steps: void 0,
|
|
157
157
|
stopWhen: void 0,
|
|
158
158
|
stream: false,
|
|
159
159
|
toolChoice: stepOptions.toolChoice
|
|
160
160
|
}).then(responseJSON).then(async (res) => {
|
|
161
|
-
const { choices
|
|
161
|
+
const { choices } = res;
|
|
162
|
+
const usage = normalizeChatCompletionUsage(res.usage);
|
|
162
163
|
if (!choices?.length) {
|
|
163
164
|
const responseBody = JSON.stringify(res);
|
|
164
165
|
throw new InvalidResponseError(`No choices returned, response body: ${responseBody}`, {
|
|
@@ -182,13 +183,17 @@ const generateText = async (options) => {
|
|
|
182
183
|
tools: options2.tools
|
|
183
184
|
}))
|
|
184
185
|
);
|
|
185
|
-
for (const { completionToolCall, completionToolResult,
|
|
186
|
+
for (const { completionToolCall, completionToolResult, result } of results) {
|
|
186
187
|
toolCalls.push(completionToolCall);
|
|
187
188
|
toolResults.push(completionToolResult);
|
|
188
|
-
messages.push(
|
|
189
|
+
messages.push({
|
|
190
|
+
content: result,
|
|
191
|
+
role: "tool",
|
|
192
|
+
tool_call_id: completionToolCall.toolCallId
|
|
193
|
+
});
|
|
189
194
|
}
|
|
190
195
|
}
|
|
191
|
-
const
|
|
196
|
+
const step = {
|
|
192
197
|
finishReason,
|
|
193
198
|
text: Array.isArray(message.content) ? message.content.filter((m) => m.type === "text").map((m) => m.text).join("\n") : message.content,
|
|
194
199
|
toolCalls,
|
|
@@ -196,25 +201,16 @@ const generateText = async (options) => {
|
|
|
196
201
|
usage
|
|
197
202
|
};
|
|
198
203
|
const stop = shouldStop(stopWhen, {
|
|
199
|
-
messages,
|
|
200
|
-
step
|
|
201
|
-
steps: [...steps,
|
|
204
|
+
input: messages,
|
|
205
|
+
step,
|
|
206
|
+
steps: [...steps, step]
|
|
202
207
|
});
|
|
203
208
|
const willContinue = toolCalls.length > 0 && !stop;
|
|
204
|
-
const step = {
|
|
205
|
-
...stopStep,
|
|
206
|
-
stepType: determineStepType({
|
|
207
|
-
finishReason,
|
|
208
|
-
stepsLength: steps.length,
|
|
209
|
-
toolCallsLength: toolCalls.length,
|
|
210
|
-
willContinue
|
|
211
|
-
})
|
|
212
|
-
};
|
|
213
209
|
steps.push(step);
|
|
214
210
|
span.setAttributes({
|
|
215
211
|
"gen_ai.response.finish_reasons": [step.finishReason],
|
|
216
|
-
"gen_ai.usage.input_tokens": step.usage.
|
|
217
|
-
"gen_ai.usage.output_tokens": step.usage.
|
|
212
|
+
"gen_ai.usage.input_tokens": step.usage.inputTokens,
|
|
213
|
+
"gen_ai.usage.output_tokens": step.usage.outputTokens
|
|
218
214
|
});
|
|
219
215
|
if (options2.onStepFinish)
|
|
220
216
|
await options2.onStepFinish(step);
|
|
@@ -244,31 +240,6 @@ const generateText = async (options) => {
|
|
|
244
240
|
}));
|
|
245
241
|
};
|
|
246
242
|
|
|
247
|
-
const parseChunk = (data) => {
|
|
248
|
-
if (data.startsWith("{") && data.includes('"error":')) {
|
|
249
|
-
throw new RemoteAPIError(`Error from server: ${data}`, {
|
|
250
|
-
responseBody: data
|
|
251
|
-
});
|
|
252
|
-
}
|
|
253
|
-
try {
|
|
254
|
-
return JSON.parse(data);
|
|
255
|
-
} catch (cause) {
|
|
256
|
-
throw new JSONParseError(`Failed to parse stream chunk JSON: ${data}`, {
|
|
257
|
-
cause,
|
|
258
|
-
text: data
|
|
259
|
-
});
|
|
260
|
-
}
|
|
261
|
-
};
|
|
262
|
-
const transformChunk = () => {
|
|
263
|
-
return new TransformStream({
|
|
264
|
-
transform: async (chunk, controller) => {
|
|
265
|
-
if (!chunk.data || chunk.data === "[DONE]")
|
|
266
|
-
return;
|
|
267
|
-
controller.enqueue(parseChunk(chunk.data));
|
|
268
|
-
}
|
|
269
|
-
});
|
|
270
|
-
};
|
|
271
|
-
|
|
272
243
|
const streamText = (options) => {
|
|
273
244
|
const tracer = getTracer();
|
|
274
245
|
const steps = [];
|
|
@@ -281,14 +252,11 @@ const streamText = (options) => {
|
|
|
281
252
|
const resultMessages = new DelayedPromise();
|
|
282
253
|
const resultUsage = new DelayedPromise();
|
|
283
254
|
const resultTotalUsage = new DelayedPromise();
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
const eventStream = new ReadableStream({ start: (controller) => eventCtrl = controller });
|
|
288
|
-
const textStream = new ReadableStream({ start: (controller) => textCtrl = controller });
|
|
289
|
-
const reasoningTextStream = new ReadableStream({ start: (controller) => reasoningTextCtrl = controller });
|
|
255
|
+
const [eventStream, eventCtrl] = createControlledStream();
|
|
256
|
+
const [textStream, textCtrl] = createControlledStream();
|
|
257
|
+
const [reasoningTextStream, reasoningTextCtrl] = createControlledStream();
|
|
290
258
|
const pushEvent = (stepEvent) => {
|
|
291
|
-
eventCtrl?.enqueue(stepEvent);
|
|
259
|
+
eventCtrl.current?.enqueue(stepEvent);
|
|
292
260
|
void options.onEvent?.(stepEvent);
|
|
293
261
|
};
|
|
294
262
|
const pushStep = (step) => {
|
|
@@ -297,8 +265,8 @@ const streamText = (options) => {
|
|
|
297
265
|
};
|
|
298
266
|
const tools = options.tools != null && options.tools.length > 0 ? options.tools.map((tool) => wrapTool(tool, tracer)) : void 0;
|
|
299
267
|
const doStream = async () => {
|
|
300
|
-
const stepOptions = await
|
|
301
|
-
messages,
|
|
268
|
+
const stepOptions = await resolvePrepareStep({
|
|
269
|
+
input: messages,
|
|
302
270
|
model: options.model,
|
|
303
271
|
prepareStep: options.prepareStep,
|
|
304
272
|
stepNumber: steps.length,
|
|
@@ -307,14 +275,14 @@ const streamText = (options) => {
|
|
|
307
275
|
});
|
|
308
276
|
return recordSpan(chatSpan({
|
|
309
277
|
...options,
|
|
310
|
-
messages: stepOptions.
|
|
278
|
+
messages: stepOptions.input,
|
|
311
279
|
model: stepOptions.model,
|
|
312
280
|
toolChoice: stepOptions.toolChoice
|
|
313
281
|
}, tracer), async (span) => {
|
|
314
282
|
const { body: stream } = await chat({
|
|
315
283
|
...options,
|
|
316
284
|
maxSteps: void 0,
|
|
317
|
-
messages: stepOptions.
|
|
285
|
+
messages: stepOptions.input,
|
|
318
286
|
model: stepOptions.model,
|
|
319
287
|
stopWhen: void 0,
|
|
320
288
|
stream: true,
|
|
@@ -323,40 +291,35 @@ const streamText = (options) => {
|
|
|
323
291
|
tools
|
|
324
292
|
});
|
|
325
293
|
const pushUsage = (u) => {
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
|
|
329
|
-
|
|
330
|
-
total_tokens: totalUsage.total_tokens + u.total_tokens
|
|
331
|
-
} : u;
|
|
294
|
+
if (u == null)
|
|
295
|
+
return;
|
|
296
|
+
usage = normalizeChatCompletionUsage(u);
|
|
297
|
+
totalUsage = computeTotalUsage(totalUsage, usage);
|
|
332
298
|
};
|
|
333
299
|
let text = "";
|
|
334
300
|
let reasoningText;
|
|
335
301
|
const pushText = (content) => {
|
|
336
|
-
textCtrl?.enqueue(content);
|
|
302
|
+
textCtrl.current?.enqueue(content);
|
|
337
303
|
text += content;
|
|
338
304
|
};
|
|
339
305
|
const pushReasoningText = (reasoningContent) => {
|
|
340
|
-
|
|
341
|
-
|
|
342
|
-
reasoningTextCtrl?.enqueue(reasoningContent);
|
|
306
|
+
reasoningText ??= "";
|
|
307
|
+
reasoningTextCtrl.current?.enqueue(reasoningContent);
|
|
343
308
|
reasoningText += reasoningContent;
|
|
344
309
|
};
|
|
345
310
|
const tool_calls = [];
|
|
346
311
|
const toolCalls = [];
|
|
347
312
|
const toolResults = [];
|
|
348
313
|
let finishReason = "other";
|
|
349
|
-
await stream.pipeThrough(new TextDecoderStream()).pipeThrough(new EventSourceParserStream()).pipeThrough(
|
|
314
|
+
await stream.pipeThrough(new TextDecoderStream()).pipeThrough(new EventSourceParserStream()).pipeThrough(new JsonMessageTransformStream()).pipeTo(new WritableStream({
|
|
350
315
|
abort: (reason) => {
|
|
351
|
-
|
|
352
|
-
textCtrl?.error(reason);
|
|
316
|
+
errorControllers(reason, eventCtrl, textCtrl, reasoningTextCtrl);
|
|
353
317
|
},
|
|
354
318
|
close: () => {
|
|
355
319
|
},
|
|
356
320
|
// eslint-disable-next-line sonarjs/cognitive-complexity
|
|
357
321
|
write: (chunk) => {
|
|
358
|
-
|
|
359
|
-
pushUsage(chunk.usage);
|
|
322
|
+
pushUsage(chunk.usage);
|
|
360
323
|
if (chunk.choices == null || chunk.choices.length === 0)
|
|
361
324
|
return;
|
|
362
325
|
const choice = chunk.choices[0];
|
|
@@ -429,10 +392,14 @@ const streamText = (options) => {
|
|
|
429
392
|
tools
|
|
430
393
|
}))
|
|
431
394
|
);
|
|
432
|
-
for (const { completionToolCall, completionToolResult,
|
|
395
|
+
for (const { completionToolCall, completionToolResult, result } of results) {
|
|
433
396
|
toolCalls.push(completionToolCall);
|
|
434
397
|
toolResults.push(completionToolResult);
|
|
435
|
-
messages.push(
|
|
398
|
+
messages.push({
|
|
399
|
+
content: result,
|
|
400
|
+
role: "tool",
|
|
401
|
+
tool_call_id: completionToolCall.toolCallId
|
|
402
|
+
});
|
|
436
403
|
pushEvent({ ...completionToolCall, type: "tool-call" });
|
|
437
404
|
pushEvent({ ...completionToolResult, type: "tool-result" });
|
|
438
405
|
}
|
|
@@ -443,7 +410,7 @@ const streamText = (options) => {
|
|
|
443
410
|
usage
|
|
444
411
|
});
|
|
445
412
|
}
|
|
446
|
-
const
|
|
413
|
+
const step = {
|
|
447
414
|
finishReason,
|
|
448
415
|
text,
|
|
449
416
|
toolCalls,
|
|
@@ -451,26 +418,17 @@ const streamText = (options) => {
|
|
|
451
418
|
usage
|
|
452
419
|
};
|
|
453
420
|
const stop = shouldStop(stopWhen, {
|
|
454
|
-
messages,
|
|
455
|
-
step
|
|
456
|
-
steps: [...steps,
|
|
421
|
+
input: messages,
|
|
422
|
+
step,
|
|
423
|
+
steps: [...steps, step]
|
|
457
424
|
});
|
|
458
425
|
const willContinue = toolCalls.length > 0 && !stop;
|
|
459
|
-
const step = {
|
|
460
|
-
...stopStep,
|
|
461
|
-
stepType: determineStepType({
|
|
462
|
-
finishReason,
|
|
463
|
-
stepsLength: steps.length,
|
|
464
|
-
toolCallsLength: toolCalls.length,
|
|
465
|
-
willContinue
|
|
466
|
-
})
|
|
467
|
-
};
|
|
468
426
|
pushStep(step);
|
|
469
427
|
span.setAttributes({
|
|
470
428
|
"gen_ai.response.finish_reasons": [step.finishReason],
|
|
471
429
|
...step.usage && {
|
|
472
|
-
"gen_ai.usage.input_tokens": step.usage.
|
|
473
|
-
"gen_ai.usage.output_tokens": step.usage.
|
|
430
|
+
"gen_ai.usage.input_tokens": step.usage.inputTokens,
|
|
431
|
+
"gen_ai.usage.output_tokens": step.usage.outputTokens
|
|
474
432
|
}
|
|
475
433
|
});
|
|
476
434
|
if (willContinue)
|
|
@@ -490,18 +448,14 @@ const streamText = (options) => {
|
|
|
490
448
|
finalError ??= err;
|
|
491
449
|
}
|
|
492
450
|
if (finalError != null) {
|
|
493
|
-
|
|
494
|
-
textCtrl?.error(finalError);
|
|
495
|
-
reasoningTextCtrl?.error(finalError);
|
|
451
|
+
errorControllers(finalError, eventCtrl, textCtrl, reasoningTextCtrl);
|
|
496
452
|
resultSteps.reject(finalError);
|
|
497
453
|
resultMessages.reject(finalError);
|
|
498
454
|
resultUsage.reject(finalError);
|
|
499
455
|
resultTotalUsage.reject(finalError);
|
|
500
456
|
return;
|
|
501
457
|
}
|
|
502
|
-
eventCtrl
|
|
503
|
-
textCtrl?.close();
|
|
504
|
-
reasoningTextCtrl?.close();
|
|
458
|
+
closeControllers(eventCtrl, textCtrl, reasoningTextCtrl);
|
|
505
459
|
resultSteps.resolve(steps);
|
|
506
460
|
resultMessages.resolve(messages);
|
|
507
461
|
resultUsage.resolve(usage);
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@xsai-ext/telemetry",
|
|
3
3
|
"type": "module",
|
|
4
|
-
"version": "0.5.0-beta.
|
|
4
|
+
"version": "0.5.0-beta.3",
|
|
5
5
|
"description": "extra-small AI SDK.",
|
|
6
6
|
"author": "Moeru AI",
|
|
7
7
|
"license": "MIT",
|
|
@@ -29,15 +29,15 @@
|
|
|
29
29
|
"dist"
|
|
30
30
|
],
|
|
31
31
|
"dependencies": {
|
|
32
|
-
"@opentelemetry/api": "^1.9.
|
|
33
|
-
"
|
|
34
|
-
"xsai": "
|
|
32
|
+
"@opentelemetry/api": "^1.9.1",
|
|
33
|
+
"xsai": "0.5.0-beta.3",
|
|
34
|
+
"@xsai/shared-stream": "0.5.0-beta.3"
|
|
35
35
|
},
|
|
36
36
|
"devDependencies": {
|
|
37
|
-
"@langfuse/otel": "^
|
|
38
|
-
"@opentelemetry/sdk-trace-base": "^2.
|
|
39
|
-
"@opentelemetry/sdk-trace-node": "^2.
|
|
40
|
-
"zod": "^4.
|
|
37
|
+
"@langfuse/otel": "^5.1.0",
|
|
38
|
+
"@opentelemetry/sdk-trace-base": "^2.6.1",
|
|
39
|
+
"@opentelemetry/sdk-trace-node": "^2.6.1",
|
|
40
|
+
"zod": "^4.3.6"
|
|
41
41
|
},
|
|
42
42
|
"scripts": {
|
|
43
43
|
"build": "pkgroll",
|