@xsai-ext/telemetry 0.4.0 → 0.4.1

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.d.ts CHANGED
@@ -1,5 +1,5 @@
1
1
  import { Attributes } from '@opentelemetry/api';
2
- import { WithUnknown, GenerateTextOptions, GenerateTextResult, StreamTextOptions, StreamTextResult } from 'xsai';
2
+ import { EmbedOptions, EmbedResult, EmbedManyOptions, EmbedManyResult, WithUnknown, GenerateTextOptions, GenerateTextResult, StreamTextOptions, StreamTextResult } from 'xsai';
3
3
  export * from 'xsai';
4
4
 
5
5
  interface TelemetryOptions {
@@ -9,6 +9,17 @@ type WithTelemetry<T> = T & {
9
9
  telemetry?: TelemetryOptions;
10
10
  };
11
11
 
12
+ /**
13
+ * @experimental
14
+ * Embeddings with Telemetry.
15
+ */
16
+ declare const embed: (options: WithTelemetry<EmbedOptions>) => Promise<EmbedResult>;
17
+ /**
18
+ * @experimental
19
+ * Embeddings with Telemetry.
20
+ */
21
+ declare const embedMany: (options: WithTelemetry<EmbedManyOptions>) => Promise<EmbedManyResult>;
22
+
12
23
  /**
13
24
  * @experimental
14
25
  * Generating Text with Telemetry.
@@ -21,5 +32,5 @@ declare const generateText: (options: WithUnknown<WithTelemetry<GenerateTextOpti
21
32
  */
22
33
  declare const streamText: (options: WithUnknown<WithTelemetry<StreamTextOptions>>) => StreamTextResult;
23
34
 
24
- export { generateText, streamText };
35
+ export { embed, embedMany, generateText, streamText };
25
36
  export type { TelemetryOptions, WithTelemetry };
package/dist/index.js CHANGED
@@ -1,33 +1,8 @@
1
- import { trampoline, chat, responseJSON, determineStepType, executeTool, DelayedPromise, objCamelToSnake } from 'xsai';
1
+ import { embed as embed$1, clean, embedMany as embedMany$1, trampoline, chat, responseJSON, determineStepType, executeTool, DelayedPromise, objCamelToSnake } from 'xsai';
2
2
  export * from 'xsai';
3
3
  import { trace, SpanStatusCode } from '@opentelemetry/api';
4
4
 
5
- const chatSpan = (options, tracer) => ({
6
- attributes: {
7
- "gen_ai.input.messages": JSON.stringify(options.messages),
8
- "gen_ai.operation.name": "chat",
9
- "gen_ai.provider.name": "openai",
10
- "gen_ai.request.choice.count": 1,
11
- "gen_ai.request.frequency_penalty": options.frequencyPenalty,
12
- "gen_ai.request.model": options.model,
13
- "gen_ai.request.presence_penalty": options.presencePenalty,
14
- "gen_ai.request.seed": options.seed,
15
- "gen_ai.request.stop_sequences": options.stop == null ? void 0 : Array.isArray(options.stop) ? options.stop : [options.stop],
16
- "gen_ai.request.temperature": options.temperature,
17
- "gen_ai.request.top_k": options.topK,
18
- "gen_ai.request.top_p": options.topP,
19
- "gen_ai.response.id": crypto.randomUUID(),
20
- "gen_ai.response.model": options.model,
21
- "gen_ai.tool.definitions": JSON.stringify(options.tools?.map((tool) => ({ function: tool.function, type: tool.type }))),
22
- "server.address": new URL(options.baseURL).host,
23
- ...options.telemetry?.attributes
24
- // TODO: gen_ai.output.type
25
- },
26
- name: `chat ${options.model}`,
27
- tracer
28
- });
29
-
30
- var version = "0.4.0";
5
+ var version = "0.4.1";
31
6
  var pkg = {
32
7
  version: version};
33
8
 
@@ -35,6 +10,10 @@ const getTracer = () => trace.getTracer("@xsai-ext/telemetry", pkg.version);
35
10
 
36
11
  const recordErrorOnSpan = (span, error) => {
37
12
  if (error instanceof Error) {
13
+ span.setAttributes({
14
+ "error.message": error.message,
15
+ "error.type": error.name
16
+ });
38
17
  span.recordException({
39
18
  message: error.message,
40
19
  name: error.name,
@@ -69,6 +48,67 @@ const recordSpan = async ({
69
48
  }
70
49
  });
71
50
 
51
+ const serverAddressAndPort = (baseURL) => {
52
+ const url = new URL(baseURL);
53
+ return {
54
+ "server.address": url.hostname,
55
+ "server.port": url.port ? Number.parseInt(url.port) : url.protocol === "https:" ? 443 : 80
56
+ };
57
+ };
58
+ const chatSpan = (options, tracer) => ({
59
+ attributes: {
60
+ "gen_ai.input.messages": JSON.stringify(options.messages),
61
+ "gen_ai.operation.name": "chat",
62
+ "gen_ai.provider.name": "openai",
63
+ "gen_ai.request.choice.count": 1,
64
+ "gen_ai.request.frequency_penalty": options.frequencyPenalty,
65
+ "gen_ai.request.model": options.model,
66
+ "gen_ai.request.presence_penalty": options.presencePenalty,
67
+ "gen_ai.request.seed": options.seed,
68
+ "gen_ai.request.stop_sequences": options.stop == null ? void 0 : Array.isArray(options.stop) ? options.stop : [options.stop],
69
+ "gen_ai.request.temperature": options.temperature,
70
+ "gen_ai.request.top_k": options.topK,
71
+ "gen_ai.request.top_p": options.topP,
72
+ "gen_ai.response.id": crypto.randomUUID(),
73
+ "gen_ai.response.model": options.model,
74
+ "gen_ai.tool.definitions": JSON.stringify(options.tools?.map((tool) => ({ function: tool.function, type: tool.type }))),
75
+ ...serverAddressAndPort(options.baseURL),
76
+ ...options.telemetry?.attributes
77
+ // TODO: gen_ai.output.type
78
+ },
79
+ name: `chat ${options.model}`,
80
+ tracer
81
+ });
82
+ const embedSpan = (options, tracer) => ({
83
+ attributes: {
84
+ "gen_ai.embeddings.dimension.count": options.dimensions,
85
+ "gen_ai.operation.name": "embeddings",
86
+ "gen_ai.request.encoding_formats": "float",
87
+ "gen_ai.request.model": options.model,
88
+ ...serverAddressAndPort(options.baseURL),
89
+ ...options.telemetry?.attributes
90
+ },
91
+ name: `embeddings ${options.model}`,
92
+ tracer
93
+ });
94
+
95
+ const embed = async (options) => {
96
+ const tracer = getTracer();
97
+ return recordSpan(embedSpan(options, tracer), async (span) => {
98
+ const result = await embed$1(clean({ ...options, telemetry: void 0 }));
99
+ span.setAttribute("gen_ai.usage.input_tokens", result.usage.prompt_tokens);
100
+ return result;
101
+ });
102
+ };
103
+ const embedMany = async (options) => {
104
+ const tracer = getTracer();
105
+ return recordSpan(embedSpan(options, tracer), async (span) => {
106
+ const result = await embedMany$1(clean({ ...options, telemetry: void 0 }));
107
+ span.setAttribute("gen_ai.usage.input_tokens", result.usage.prompt_tokens);
108
+ return result;
109
+ });
110
+ };
111
+
72
112
  const wrapTool = (tool, tracer) => ({
73
113
  execute: async (input, options) => recordSpan({
74
114
  attributes: {
@@ -81,15 +121,9 @@ const wrapTool = (tool, tracer) => ({
81
121
  name: `execute_tool ${tool.function.name}`,
82
122
  tracer
83
123
  }, async (span) => {
84
- try {
85
- const result = await tool.execute(input, options);
86
- span.setAttribute("gen_ai.tool.call.result", JSON.stringify(result));
87
- return result;
88
- } catch (err) {
89
- if (err instanceof Error)
90
- span.setAttribute("error.type", err.message);
91
- throw err;
92
- }
124
+ const result = await tool.execute(input, options);
125
+ span.setAttribute("gen_ai.tool.call.result", JSON.stringify(result));
126
+ return result;
93
127
  }),
94
128
  function: tool.function,
95
129
  type: tool.type
@@ -220,6 +254,7 @@ const streamText = (options) => {
220
254
  const maxSteps = options.maxSteps ?? 1;
221
255
  let usage;
222
256
  let totalUsage;
257
+ let reasoningField;
223
258
  const resultSteps = new DelayedPromise();
224
259
  const resultMessages = new DelayedPromise();
225
260
  const resultUsage = new DelayedPromise();
@@ -254,7 +289,7 @@ const streamText = (options) => {
254
289
  completion_tokens: totalUsage.completion_tokens + u.completion_tokens,
255
290
  prompt_tokens: totalUsage.prompt_tokens + u.prompt_tokens,
256
291
  total_tokens: totalUsage.total_tokens + u.total_tokens
257
- } : { ...u };
292
+ } : u;
258
293
  };
259
294
  let text = "";
260
295
  let reasoningText;
@@ -286,7 +321,14 @@ const streamText = (options) => {
286
321
  if (chunk.choices == null || chunk.choices.length === 0)
287
322
  return;
288
323
  const choice = chunk.choices[0];
289
- if (choice.delta.reasoning_content != null) {
324
+ if (choice.delta.reasoning != null) {
325
+ if (reasoningField !== "reasoning")
326
+ reasoningField = "reasoning";
327
+ pushEvent({ text: choice.delta.reasoning, type: "reasoning-delta" });
328
+ pushReasoningText(choice.delta.reasoning);
329
+ } else if (choice.delta.reasoning_content != null) {
330
+ if (reasoningField !== "reasoning_content")
331
+ reasoningField = "reasoning_content";
290
332
  pushEvent({ text: choice.delta.reasoning_content, type: "reasoning-delta" });
291
333
  pushReasoningText(choice.delta.reasoning_content);
292
334
  }
@@ -331,8 +373,8 @@ const streamText = (options) => {
331
373
  }
332
374
  }));
333
375
  const message = {
376
+ ...reasoningField != null ? { [reasoningField]: reasoningText } : {},
334
377
  content: text,
335
- reasoning_content: reasoningText,
336
378
  role: "assistant",
337
379
  tool_calls: tool_calls.length > 0 ? tool_calls : void 0
338
380
  };
@@ -414,4 +456,4 @@ const streamText = (options) => {
414
456
  };
415
457
  };
416
458
 
417
- export { generateText, streamText };
459
+ export { embed, embedMany, generateText, streamText };
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@xsai-ext/telemetry",
3
3
  "type": "module",
4
- "version": "0.4.0",
4
+ "version": "0.4.1",
5
5
  "description": "extra-small AI SDK.",
6
6
  "author": "Moeru AI",
7
7
  "license": "MIT",
@@ -30,7 +30,7 @@
30
30
  ],
31
31
  "dependencies": {
32
32
  "@opentelemetry/api": "^1.9.0",
33
- "xsai": "~0.4.0"
33
+ "xsai": "~0.4.1"
34
34
  },
35
35
  "devDependencies": {
36
36
  "@langfuse/otel": "^4.5.1",