@xsai-ext/telemetry 0.5.0-beta.2 → 0.5.0-beta.4

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.
Files changed (2) hide show
  1. package/dist/index.js +57 -65
  2. 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, resolveStepOptions, chat, responseJSON, InvalidResponseError, stepCountAtLeast, executeTool, shouldStop, determineStepType, DelayedPromise, objCamelToSnake } from 'xsai';
1
+ import { embed as embed$1, clean, embedMany as embedMany$1, trampoline, resolvePrepareStep, chat, responseJSON, normalizeChatCompletionUsage, computeTotalUsage, InvalidResponseError, stepCountAtLeast, executeTool, shouldStop, DelayedPromise, objCamelToSnake } from 'xsai';
2
2
  export * from 'xsai';
3
3
  import { trace, SpanStatusCode } from '@opentelemetry/api';
4
4
  import { createControlledStream, errorControllers, closeControllers, EventSourceParserStream, JsonMessageTransformStream } from '@xsai/shared-stream';
5
5
 
6
- var version = "0.5.0-beta.2";
6
+ var version = "0.5.0-beta.4";
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 resolveStepOptions({
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,22 @@ const generateText = async (options) => {
145
145
  });
146
146
  return recordSpan(chatSpan({
147
147
  ...options2,
148
- messages: stepOptions.messages,
148
+ messages: stepOptions.input,
149
149
  model: stepOptions.model,
150
150
  toolChoice: stepOptions.toolChoice
151
151
  }, tracer), async (span) => chat({
152
152
  ...options2,
153
- maxSteps: void 0,
154
- messages: stepOptions.messages,
153
+ messages: stepOptions.input,
155
154
  model: stepOptions.model,
156
155
  steps: void 0,
157
- stopWhen: void 0,
158
156
  stream: false,
159
- toolChoice: stepOptions.toolChoice
157
+ telemetry: void 0,
158
+ toolChoice: stepOptions.toolChoice,
159
+ totalUsage: void 0
160
160
  }).then(responseJSON).then(async (res) => {
161
- const { choices, usage } = res;
161
+ const { choices } = res;
162
+ const usage = normalizeChatCompletionUsage(res.usage);
163
+ const totalUsage = computeTotalUsage(options2.totalUsage, usage);
162
164
  if (!choices?.length) {
163
165
  const responseBody = JSON.stringify(res);
164
166
  throw new InvalidResponseError(`No choices returned, response body: ${responseBody}`, {
@@ -182,13 +184,17 @@ const generateText = async (options) => {
182
184
  tools: options2.tools
183
185
  }))
184
186
  );
185
- for (const { completionToolCall, completionToolResult, message: message2 } of results) {
187
+ for (const { completionToolCall, completionToolResult, result } of results) {
186
188
  toolCalls.push(completionToolCall);
187
189
  toolResults.push(completionToolResult);
188
- messages.push(message2);
190
+ messages.push({
191
+ content: result,
192
+ role: "tool",
193
+ tool_call_id: completionToolCall.toolCallId
194
+ });
189
195
  }
190
196
  }
191
- const stopStep = {
197
+ const step = {
192
198
  finishReason,
193
199
  text: Array.isArray(message.content) ? message.content.filter((m) => m.type === "text").map((m) => m.text).join("\n") : message.content,
194
200
  toolCalls,
@@ -196,25 +202,16 @@ const generateText = async (options) => {
196
202
  usage
197
203
  };
198
204
  const stop = shouldStop(stopWhen, {
199
- messages,
200
- step: stopStep,
201
- steps: [...steps, stopStep]
205
+ input: messages,
206
+ step,
207
+ steps: [...steps, step]
202
208
  });
203
209
  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
210
  steps.push(step);
214
211
  span.setAttributes({
215
212
  "gen_ai.response.finish_reasons": [step.finishReason],
216
- "gen_ai.usage.input_tokens": step.usage.prompt_tokens,
217
- "gen_ai.usage.output_tokens": step.usage.completion_tokens
213
+ "gen_ai.usage.input_tokens": step.usage.inputTokens,
214
+ "gen_ai.usage.output_tokens": step.usage.outputTokens
218
215
  });
219
216
  if (options2.onStepFinish)
220
217
  await options2.onStepFinish(step);
@@ -227,13 +224,15 @@ const generateText = async (options) => {
227
224
  text: step.text,
228
225
  toolCalls: step.toolCalls,
229
226
  toolResults: step.toolResults,
227
+ totalUsage,
230
228
  usage: step.usage
231
229
  };
232
230
  } else {
233
231
  return async () => rawGenerateText({
234
232
  ...options2,
235
233
  messages,
236
- steps
234
+ steps,
235
+ totalUsage
237
236
  });
238
237
  }
239
238
  }));
@@ -257,6 +256,7 @@ const streamText = (options) => {
257
256
  const resultUsage = new DelayedPromise();
258
257
  const resultTotalUsage = new DelayedPromise();
259
258
  const [eventStream, eventCtrl] = createControlledStream();
259
+ const [fullStream, fullCtrl] = createControlledStream();
260
260
  const [textStream, textCtrl] = createControlledStream();
261
261
  const [reasoningTextStream, reasoningTextCtrl] = createControlledStream();
262
262
  const pushEvent = (stepEvent) => {
@@ -269,8 +269,8 @@ const streamText = (options) => {
269
269
  };
270
270
  const tools = options.tools != null && options.tools.length > 0 ? options.tools.map((tool) => wrapTool(tool, tracer)) : void 0;
271
271
  const doStream = async () => {
272
- const stepOptions = await resolveStepOptions({
273
- messages,
272
+ const stepOptions = await resolvePrepareStep({
273
+ input: messages,
274
274
  model: options.model,
275
275
  prepareStep: options.prepareStep,
276
276
  stepNumber: steps.length,
@@ -279,28 +279,25 @@ const streamText = (options) => {
279
279
  });
280
280
  return recordSpan(chatSpan({
281
281
  ...options,
282
- messages: stepOptions.messages,
282
+ messages: stepOptions.input,
283
283
  model: stepOptions.model,
284
284
  toolChoice: stepOptions.toolChoice
285
285
  }, tracer), async (span) => {
286
286
  const { body: stream } = await chat({
287
287
  ...options,
288
- maxSteps: void 0,
289
- messages: stepOptions.messages,
288
+ messages: stepOptions.input,
290
289
  model: stepOptions.model,
291
- stopWhen: void 0,
292
290
  stream: true,
293
291
  streamOptions: options.streamOptions != null ? objCamelToSnake(options.streamOptions) : void 0,
292
+ telemetry: void 0,
294
293
  toolChoice: stepOptions.toolChoice,
295
294
  tools
296
295
  });
297
296
  const pushUsage = (u) => {
298
- usage = u;
299
- totalUsage = totalUsage ? {
300
- completion_tokens: totalUsage.completion_tokens + u.completion_tokens,
301
- prompt_tokens: totalUsage.prompt_tokens + u.prompt_tokens,
302
- total_tokens: totalUsage.total_tokens + u.total_tokens
303
- } : u;
297
+ if (u == null)
298
+ return;
299
+ usage = normalizeChatCompletionUsage(u);
300
+ totalUsage = computeTotalUsage(totalUsage, usage);
304
301
  };
305
302
  let text = "";
306
303
  let reasoningText;
@@ -309,8 +306,7 @@ const streamText = (options) => {
309
306
  text += content;
310
307
  };
311
308
  const pushReasoningText = (reasoningContent) => {
312
- if (reasoningText == null)
313
- reasoningText = "";
309
+ reasoningText ??= "";
314
310
  reasoningTextCtrl.current?.enqueue(reasoningContent);
315
311
  reasoningText += reasoningContent;
316
312
  };
@@ -320,14 +316,14 @@ const streamText = (options) => {
320
316
  let finishReason = "other";
321
317
  await stream.pipeThrough(new TextDecoderStream()).pipeThrough(new EventSourceParserStream()).pipeThrough(new JsonMessageTransformStream()).pipeTo(new WritableStream({
322
318
  abort: (reason) => {
323
- errorControllers(reason, eventCtrl, textCtrl, reasoningTextCtrl);
319
+ errorControllers(reason, eventCtrl, fullCtrl, textCtrl, reasoningTextCtrl);
324
320
  },
325
321
  close: () => {
326
322
  },
327
323
  // eslint-disable-next-line sonarjs/cognitive-complexity
328
324
  write: (chunk) => {
329
- if (chunk.usage)
330
- pushUsage(chunk.usage);
325
+ fullCtrl.current?.enqueue(chunk);
326
+ pushUsage(chunk.usage);
331
327
  if (chunk.choices == null || chunk.choices.length === 0)
332
328
  return;
333
329
  const choice = chunk.choices[0];
@@ -400,10 +396,14 @@ const streamText = (options) => {
400
396
  tools
401
397
  }))
402
398
  );
403
- for (const { completionToolCall, completionToolResult, message: message2 } of results) {
399
+ for (const { completionToolCall, completionToolResult, result } of results) {
404
400
  toolCalls.push(completionToolCall);
405
401
  toolResults.push(completionToolResult);
406
- messages.push(message2);
402
+ messages.push({
403
+ content: result,
404
+ role: "tool",
405
+ tool_call_id: completionToolCall.toolCallId
406
+ });
407
407
  pushEvent({ ...completionToolCall, type: "tool-call" });
408
408
  pushEvent({ ...completionToolResult, type: "tool-result" });
409
409
  }
@@ -414,7 +414,7 @@ const streamText = (options) => {
414
414
  usage
415
415
  });
416
416
  }
417
- const stopStep = {
417
+ const step = {
418
418
  finishReason,
419
419
  text,
420
420
  toolCalls,
@@ -422,26 +422,17 @@ const streamText = (options) => {
422
422
  usage
423
423
  };
424
424
  const stop = shouldStop(stopWhen, {
425
- messages,
426
- step: stopStep,
427
- steps: [...steps, stopStep]
425
+ input: messages,
426
+ step,
427
+ steps: [...steps, step]
428
428
  });
429
429
  const willContinue = toolCalls.length > 0 && !stop;
430
- const step = {
431
- ...stopStep,
432
- stepType: determineStepType({
433
- finishReason,
434
- stepsLength: steps.length,
435
- toolCallsLength: toolCalls.length,
436
- willContinue
437
- })
438
- };
439
430
  pushStep(step);
440
431
  span.setAttributes({
441
432
  "gen_ai.response.finish_reasons": [step.finishReason],
442
433
  ...step.usage && {
443
- "gen_ai.usage.input_tokens": step.usage.prompt_tokens,
444
- "gen_ai.usage.output_tokens": step.usage.completion_tokens
434
+ "gen_ai.usage.input_tokens": step.usage.inputTokens,
435
+ "gen_ai.usage.output_tokens": step.usage.outputTokens
445
436
  }
446
437
  });
447
438
  if (willContinue)
@@ -461,21 +452,22 @@ const streamText = (options) => {
461
452
  finalError ??= err;
462
453
  }
463
454
  if (finalError != null) {
464
- errorControllers(finalError, eventCtrl, textCtrl, reasoningTextCtrl);
455
+ errorControllers(finalError, eventCtrl, fullCtrl, textCtrl, reasoningTextCtrl);
465
456
  resultSteps.reject(finalError);
466
457
  resultMessages.reject(finalError);
467
458
  resultUsage.reject(finalError);
468
459
  resultTotalUsage.reject(finalError);
469
460
  return;
470
461
  }
471
- closeControllers(eventCtrl, textCtrl, reasoningTextCtrl);
462
+ closeControllers(eventCtrl, fullCtrl, textCtrl, reasoningTextCtrl);
472
463
  resultSteps.resolve(steps);
473
464
  resultMessages.resolve(messages);
474
465
  resultUsage.resolve(usage);
475
466
  resultTotalUsage.resolve(totalUsage);
476
467
  })();
477
468
  return {
478
- fullStream: eventStream,
469
+ eventStream,
470
+ fullStream,
479
471
  messages: resultMessages.promise,
480
472
  reasoningTextStream,
481
473
  steps: resultSteps.promise,
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.2",
4
+ "version": "0.5.0-beta.4",
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.0",
33
- "@xsai/shared-stream": "~0.5.0-beta.2",
34
- "xsai": "~0.5.0-beta.2"
32
+ "@opentelemetry/api": "^1.9.1",
33
+ "@xsai/shared-stream": "0.5.0-beta.4",
34
+ "xsai": "0.5.0-beta.4"
35
35
  },
36
36
  "devDependencies": {
37
- "@langfuse/otel": "^4.5.1",
38
- "@opentelemetry/sdk-trace-base": "^2.2.0",
39
- "@opentelemetry/sdk-trace-node": "^2.2.0",
40
- "zod": "^4.2.1"
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",