@struktur/telemetry 2.1.2 → 2.3.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.
@@ -1,93 +0,0 @@
1
- /**
2
- * Unit tests for telemetry factory functions
3
- */
4
-
5
- import { test, expect, describe } from "bun:test";
6
- import {
7
- createTelemetry,
8
- createPhoenixTelemetry,
9
- createLangfuseTelemetry,
10
- createNoopTelemetry
11
- } from "../src/factory.js";
12
- import type { TelemetryOptions, PhoenixConfig, LangfuseConfig } from "../src/types.js";
13
-
14
- describe("createTelemetry", () => {
15
- test("should return null when disabled", async () => {
16
- const options: TelemetryOptions = {
17
- provider: "phoenix",
18
- config: { projectName: "test" },
19
- enabled: false,
20
- };
21
-
22
- const telemetry = await createTelemetry(options);
23
- expect(telemetry).toBeNull();
24
- });
25
-
26
- test("should throw error for unknown provider", async () => {
27
- const options: TelemetryOptions = {
28
- provider: "unknown" as any,
29
- config: {},
30
- };
31
-
32
- await expect(createTelemetry(options)).rejects.toThrow("Unknown telemetry provider");
33
- });
34
- });
35
-
36
- describe("createNoopTelemetry", () => {
37
- test("should create noop adapter", () => {
38
- const adapter = createNoopTelemetry();
39
-
40
- expect(adapter).toBeDefined();
41
- expect(adapter.name).toBe("noop");
42
- expect(adapter.version).toBe("1.0.0");
43
- });
44
-
45
- test("should work without initialization", async () => {
46
- const adapter = createNoopTelemetry();
47
-
48
- // Should not require initialize
49
- const span = adapter.startSpan({
50
- name: "test",
51
- kind: "CHAIN",
52
- });
53
-
54
- expect(span).toBeDefined();
55
- expect(span.name).toBe("test");
56
- });
57
- });
58
-
59
- describe("createPhoenixTelemetry", () => {
60
- test("should create Phoenix adapter when dependencies available", async () => {
61
- const config: PhoenixConfig = {
62
- projectName: "test",
63
- url: "http://localhost:6006",
64
- };
65
-
66
- try {
67
- const adapter = await createPhoenixTelemetry(config);
68
- expect(adapter).toBeDefined();
69
- expect(adapter.name).toBe("phoenix");
70
- } catch (error) {
71
- // Expected if dependencies not installed
72
- expect(error).toBeInstanceOf(Error);
73
- }
74
- });
75
- });
76
-
77
- describe("createLangfuseTelemetry", () => {
78
- test("should create Langfuse adapter when dependencies available", async () => {
79
- const config: LangfuseConfig = {
80
- publicKey: "pk-test",
81
- secretKey: "sk-test",
82
- };
83
-
84
- try {
85
- const adapter = await createLangfuseTelemetry(config);
86
- expect(adapter).toBeDefined();
87
- expect(adapter.name).toBe("langfuse");
88
- } catch (error) {
89
- // Expected if dependencies not installed
90
- expect(error).toBeInstanceOf(Error);
91
- }
92
- });
93
- });
@@ -1,248 +0,0 @@
1
- /**
2
- * Unit tests for core telemetry types
3
- */
4
-
5
- import { test, expect, describe } from "bun:test";
6
- import {
7
- NoopTelemetryAdapter,
8
- type SpanContext,
9
- type SpanResult,
10
- type LLMCallEvent,
11
- type ValidationEvent,
12
- type ChunkEvent,
13
- type ToolCallEvent,
14
- type MergeEvent,
15
- type ParseEvent,
16
- } from "../src/types.js";
17
-
18
- describe("NoopTelemetryAdapter", () => {
19
- test("should create noop adapter", () => {
20
- const adapter = new NoopTelemetryAdapter();
21
-
22
- expect(adapter.name).toBe("noop");
23
- expect(adapter.version).toBe("1.0.0");
24
- });
25
-
26
- test("should initialize without error", async () => {
27
- const adapter = new NoopTelemetryAdapter();
28
- await expect(adapter.initialize()).resolves.toBeUndefined();
29
- });
30
-
31
- test("should shutdown without error", async () => {
32
- const adapter = new NoopTelemetryAdapter();
33
- await expect(adapter.shutdown()).resolves.toBeUndefined();
34
- });
35
-
36
- test("should create spans", () => {
37
- const adapter = new NoopTelemetryAdapter();
38
-
39
- const context: SpanContext = {
40
- name: "test-span",
41
- kind: "CHAIN",
42
- attributes: { test: true },
43
- };
44
-
45
- const span = adapter.startSpan(context);
46
-
47
- expect(span.id).toBeDefined();
48
- expect(span.name).toBe("test-span");
49
- expect(span.kind).toBe("CHAIN");
50
- expect(span.traceId).toBeDefined();
51
- expect(span.startTime).toBeGreaterThan(0);
52
- });
53
-
54
- test("should create child spans", () => {
55
- const adapter = new NoopTelemetryAdapter();
56
-
57
- const parentContext: SpanContext = {
58
- name: "parent",
59
- kind: "CHAIN",
60
- };
61
-
62
- const parentSpan = adapter.startSpan(parentContext);
63
-
64
- const childContext: SpanContext = {
65
- name: "child",
66
- kind: "LLM",
67
- parentSpan,
68
- };
69
-
70
- const childSpan = adapter.startSpan(childContext);
71
-
72
- expect(childSpan.parentId).toBe(parentSpan.id);
73
- // Noop adapter creates new traceIds for each span
74
- expect(childSpan).toBeDefined();
75
- expect(parentSpan).toBeDefined();
76
- });
77
-
78
- test("should end spans without error", () => {
79
- const adapter = new NoopTelemetryAdapter();
80
-
81
- const span = adapter.startSpan({
82
- name: "test",
83
- kind: "CHAIN",
84
- });
85
-
86
- const result: SpanResult = {
87
- status: "ok",
88
- output: { data: "test" },
89
- latencyMs: 100,
90
- };
91
-
92
- expect(() => adapter.endSpan(span, result)).not.toThrow();
93
- });
94
-
95
- test("should record events without error", () => {
96
- const adapter = new NoopTelemetryAdapter();
97
-
98
- const span = adapter.startSpan({
99
- name: "test",
100
- kind: "LLM",
101
- });
102
-
103
- const event: LLMCallEvent = {
104
- type: "llm_call",
105
- model: "gpt-4o",
106
- provider: "openai",
107
- input: {
108
- messages: [{ role: "user", content: "Hello" }],
109
- temperature: 0.5,
110
- maxTokens: 100,
111
- },
112
- output: {
113
- content: "Hi there!",
114
- usage: { input: 10, output: 5, total: 15 },
115
- },
116
- latencyMs: 250,
117
- };
118
-
119
- expect(() => adapter.recordEvent(span, event)).not.toThrow();
120
- });
121
-
122
- test("should set attributes without error", () => {
123
- const adapter = new NoopTelemetryAdapter();
124
-
125
- const span = adapter.startSpan({
126
- name: "test",
127
- kind: "CHAIN",
128
- });
129
-
130
- expect(() =>
131
- adapter.setAttributes(span, { key: "value", num: 42 })
132
- ).not.toThrow();
133
- });
134
-
135
- test("should set context without error", () => {
136
- const adapter = new NoopTelemetryAdapter();
137
-
138
- expect(() =>
139
- adapter.setContext({
140
- sessionId: "session-123",
141
- userId: "user-456",
142
- metadata: { source: "test" },
143
- tags: ["test", "unit"],
144
- })
145
- ).not.toThrow();
146
- });
147
-
148
- test("should handle error results", () => {
149
- const adapter = new NoopTelemetryAdapter();
150
-
151
- const span = adapter.startSpan({
152
- name: "test",
153
- kind: "LLM",
154
- });
155
-
156
- const result: SpanResult = {
157
- status: "error",
158
- error: new Error("Test error"),
159
- };
160
-
161
- expect(() => adapter.endSpan(span, result)).not.toThrow();
162
- });
163
-
164
- test("should handle all event types", () => {
165
- const adapter = new NoopTelemetryAdapter();
166
-
167
- const span = adapter.startSpan({
168
- name: "test",
169
- kind: "CHAIN",
170
- });
171
-
172
- // LLM call event
173
- const llmEvent: LLMCallEvent = {
174
- type: "llm_call",
175
- model: "gpt-4o",
176
- provider: "openai",
177
- input: {
178
- messages: [{ role: "user", content: "Hello" }],
179
- },
180
- output: {
181
- content: "Hi",
182
- usage: { input: 5, output: 2, total: 7 },
183
- },
184
- latencyMs: 100,
185
- };
186
-
187
- expect(() => adapter.recordEvent(span, llmEvent)).not.toThrow();
188
-
189
- // Validation event
190
- const validationEvent: ValidationEvent = {
191
- type: "validation",
192
- attempt: 1,
193
- maxAttempts: 3,
194
- schema: { type: "object" },
195
- input: { data: "test" },
196
- success: true,
197
- latencyMs: 50,
198
- };
199
-
200
- expect(() => adapter.recordEvent(span, validationEvent)).not.toThrow();
201
-
202
- // Chunk event
203
- const chunkEvent: ChunkEvent = {
204
- type: "chunk",
205
- chunkIndex: 0,
206
- totalChunks: 5,
207
- tokens: 1000,
208
- images: 2,
209
- };
210
-
211
- expect(() => adapter.recordEvent(span, chunkEvent)).not.toThrow();
212
-
213
- // Tool call event
214
- const toolEvent: ToolCallEvent = {
215
- type: "tool_call",
216
- toolName: "read",
217
- args: { file_path: "/test.txt" },
218
- result: "file contents",
219
- latencyMs: 25,
220
- };
221
-
222
- expect(() => adapter.recordEvent(span, toolEvent)).not.toThrow();
223
-
224
- // Merge event
225
- const mergeEvent: MergeEvent = {
226
- type: "merge",
227
- strategy: "parallel",
228
- inputCount: 5,
229
- outputCount: 4,
230
- deduped: 1,
231
- };
232
-
233
- expect(() => adapter.recordEvent(span, mergeEvent)).not.toThrow();
234
-
235
- // Parse event
236
- const parseEvent: ParseEvent = {
237
- type: "parse",
238
- mimeType: "application/pdf",
239
- parser: "pdf-parse",
240
- inputSize: 1024,
241
- outputTokens: 500,
242
- outputImages: 0,
243
- latencyMs: 200,
244
- };
245
-
246
- expect(() => adapter.recordEvent(span, parseEvent)).not.toThrow();
247
- });
248
- });