aigie-sdk 0.0.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.mts +2268 -0
- package/dist/index.d.ts +2268 -0
- package/dist/index.js +7807 -0
- package/dist/index.js.map +1 -0
- package/dist/index.mjs +7711 -0
- package/dist/index.mjs.map +1 -0
- package/dist/testing/index.d.mts +7 -0
- package/dist/testing/index.d.ts +7 -0
- package/dist/testing/index.js +649 -0
- package/dist/testing/index.js.map +1 -0
- package/dist/testing/index.mjs +646 -0
- package/dist/testing/index.mjs.map +1 -0
- package/package.json +143 -0
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
type TestFn$1 = (name: string, fn: () => void | Promise<void>, timeout?: number) => void;
|
|
2
|
+
declare function wrapJest(testFn: TestFn$1): TestFn$1;
|
|
3
|
+
|
|
4
|
+
type TestFn = (name: string, fn: () => void | Promise<void>, timeout?: number) => void;
|
|
5
|
+
declare function wrapVitest(testFn: TestFn): TestFn;
|
|
6
|
+
|
|
7
|
+
export { wrapJest, wrapVitest };
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
type TestFn$1 = (name: string, fn: () => void | Promise<void>, timeout?: number) => void;
|
|
2
|
+
declare function wrapJest(testFn: TestFn$1): TestFn$1;
|
|
3
|
+
|
|
4
|
+
type TestFn = (name: string, fn: () => void | Promise<void>, timeout?: number) => void;
|
|
5
|
+
declare function wrapVitest(testFn: TestFn): TestFn;
|
|
6
|
+
|
|
7
|
+
export { wrapJest, wrapVitest };
|
|
@@ -0,0 +1,649 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
var async_hooks = require('async_hooks');
|
|
4
|
+
|
|
5
|
+
var __defProp = Object.defineProperty;
|
|
6
|
+
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
7
|
+
var __esm = (fn, res) => function __init() {
|
|
8
|
+
return fn && (res = (0, fn[__getOwnPropNames(fn)[0]])(fn = 0)), res;
|
|
9
|
+
};
|
|
10
|
+
var __export = (target, all) => {
|
|
11
|
+
for (var name in all)
|
|
12
|
+
__defProp(target, name, { get: all[name], enumerable: true });
|
|
13
|
+
};
|
|
14
|
+
|
|
15
|
+
// src/utils/uuid.ts
|
|
16
|
+
function uuidv7() {
|
|
17
|
+
let timestamp = Date.now();
|
|
18
|
+
if (timestamp === lastTimestamp) {
|
|
19
|
+
sequence++;
|
|
20
|
+
if (sequence > 4095) {
|
|
21
|
+
timestamp = Date.now();
|
|
22
|
+
sequence = 0;
|
|
23
|
+
}
|
|
24
|
+
} else {
|
|
25
|
+
sequence = 0;
|
|
26
|
+
lastTimestamp = timestamp;
|
|
27
|
+
}
|
|
28
|
+
const timestampHex = timestamp.toString(16).padStart(12, "0");
|
|
29
|
+
const seqHex = (7 << 12 | sequence & 4095).toString(16).padStart(4, "0");
|
|
30
|
+
const randomBits = new Uint8Array(8);
|
|
31
|
+
if (typeof crypto !== "undefined" && crypto.getRandomValues) {
|
|
32
|
+
crypto.getRandomValues(randomBits);
|
|
33
|
+
} else {
|
|
34
|
+
for (let i = 0; i < 8; i++) {
|
|
35
|
+
randomBits[i] = Math.floor(Math.random() * 256);
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
randomBits[0] = randomBits[0] & 63 | 128;
|
|
39
|
+
const randomHex = Array.from(randomBits).map((b) => b.toString(16).padStart(2, "0")).join("");
|
|
40
|
+
return [
|
|
41
|
+
timestampHex.slice(0, 8),
|
|
42
|
+
timestampHex.slice(8, 12),
|
|
43
|
+
seqHex,
|
|
44
|
+
randomHex.slice(0, 4),
|
|
45
|
+
randomHex.slice(4, 16)
|
|
46
|
+
].join("-");
|
|
47
|
+
}
|
|
48
|
+
var lastTimestamp, sequence;
|
|
49
|
+
var init_uuid = __esm({
|
|
50
|
+
"src/utils/uuid.ts"() {
|
|
51
|
+
lastTimestamp = 0;
|
|
52
|
+
sequence = 0;
|
|
53
|
+
}
|
|
54
|
+
});
|
|
55
|
+
|
|
56
|
+
// src/client.ts
|
|
57
|
+
var client_exports = {};
|
|
58
|
+
__export(client_exports, {
|
|
59
|
+
AigieClient: () => AigieClient,
|
|
60
|
+
KyteClient: () => AigieClient,
|
|
61
|
+
getAigie: () => getAigie,
|
|
62
|
+
getKyte: () => getKyte,
|
|
63
|
+
initAigie: () => initAigie,
|
|
64
|
+
initKyte: () => initKyte
|
|
65
|
+
});
|
|
66
|
+
function initKyte(config) {
|
|
67
|
+
globalClient = new AigieClient(config);
|
|
68
|
+
return globalClient;
|
|
69
|
+
}
|
|
70
|
+
function getKyte() {
|
|
71
|
+
if (!globalClient) {
|
|
72
|
+
throw new Error("Kyte SDK not initialized. Call initKyte() first.");
|
|
73
|
+
}
|
|
74
|
+
return globalClient;
|
|
75
|
+
}
|
|
76
|
+
var contextStorage, globalClient, initAigie, getAigie, SpanBuilderImpl, ActiveSpanImpl, AigieClient;
|
|
77
|
+
var init_client = __esm({
|
|
78
|
+
"src/client.ts"() {
|
|
79
|
+
init_uuid();
|
|
80
|
+
contextStorage = new async_hooks.AsyncLocalStorage();
|
|
81
|
+
globalClient = null;
|
|
82
|
+
initAigie = initKyte;
|
|
83
|
+
getAigie = getKyte;
|
|
84
|
+
SpanBuilderImpl = class {
|
|
85
|
+
client;
|
|
86
|
+
options = {};
|
|
87
|
+
constructor(client, name) {
|
|
88
|
+
this.client = client;
|
|
89
|
+
this.options.name = name;
|
|
90
|
+
}
|
|
91
|
+
setName(name) {
|
|
92
|
+
this.options.name = name;
|
|
93
|
+
return this;
|
|
94
|
+
}
|
|
95
|
+
setType(type) {
|
|
96
|
+
this.options.type = type;
|
|
97
|
+
return this;
|
|
98
|
+
}
|
|
99
|
+
setInput(input) {
|
|
100
|
+
this.options.input = input;
|
|
101
|
+
return this;
|
|
102
|
+
}
|
|
103
|
+
setMetadata(metadata) {
|
|
104
|
+
this.options.metadata = metadata;
|
|
105
|
+
return this;
|
|
106
|
+
}
|
|
107
|
+
addMetadata(key, value) {
|
|
108
|
+
this.options.metadata = { ...this.options.metadata, [key]: value };
|
|
109
|
+
return this;
|
|
110
|
+
}
|
|
111
|
+
setTags(tags) {
|
|
112
|
+
this.options.tags = tags;
|
|
113
|
+
return this;
|
|
114
|
+
}
|
|
115
|
+
addTag(tag) {
|
|
116
|
+
this.options.tags = [...this.options.tags || [], tag];
|
|
117
|
+
return this;
|
|
118
|
+
}
|
|
119
|
+
setUserId(userId) {
|
|
120
|
+
this.options.userId = userId;
|
|
121
|
+
return this;
|
|
122
|
+
}
|
|
123
|
+
setSessionId(sessionId) {
|
|
124
|
+
this.options.sessionId = sessionId;
|
|
125
|
+
return this;
|
|
126
|
+
}
|
|
127
|
+
setModelName(modelName) {
|
|
128
|
+
this.options.modelName = modelName;
|
|
129
|
+
return this;
|
|
130
|
+
}
|
|
131
|
+
start() {
|
|
132
|
+
return this.client.startSpan(this.options);
|
|
133
|
+
}
|
|
134
|
+
};
|
|
135
|
+
ActiveSpanImpl = class {
|
|
136
|
+
id;
|
|
137
|
+
traceId;
|
|
138
|
+
client;
|
|
139
|
+
span;
|
|
140
|
+
scores = [];
|
|
141
|
+
ended = false;
|
|
142
|
+
constructor(client, span) {
|
|
143
|
+
this.client = client;
|
|
144
|
+
this.span = span;
|
|
145
|
+
this.id = span.id;
|
|
146
|
+
this.traceId = span.traceId;
|
|
147
|
+
}
|
|
148
|
+
update(data) {
|
|
149
|
+
if (this.ended) {
|
|
150
|
+
console.warn("Cannot update ended span");
|
|
151
|
+
return this;
|
|
152
|
+
}
|
|
153
|
+
if (data.output) this.span.output = data.output;
|
|
154
|
+
if (data.tokens) this.span.tokens = data.tokens;
|
|
155
|
+
if (data.cost) this.span.cost = data.cost;
|
|
156
|
+
if (data.metadata) this.span.metadata = { ...this.span.metadata, ...data.metadata };
|
|
157
|
+
if (data.tags) this.span.tags = [...this.span.tags, ...data.tags];
|
|
158
|
+
if (data.modelName) this.span.modelName = data.modelName;
|
|
159
|
+
return this;
|
|
160
|
+
}
|
|
161
|
+
setOutput(output) {
|
|
162
|
+
return this.update({ output });
|
|
163
|
+
}
|
|
164
|
+
setTokens(tokens) {
|
|
165
|
+
return this.update({ tokens });
|
|
166
|
+
}
|
|
167
|
+
setCost(cost) {
|
|
168
|
+
return this.update({ cost });
|
|
169
|
+
}
|
|
170
|
+
addScore(score) {
|
|
171
|
+
this.scores.push(score);
|
|
172
|
+
return this;
|
|
173
|
+
}
|
|
174
|
+
setError(error) {
|
|
175
|
+
if (this.ended) {
|
|
176
|
+
console.warn("Cannot set error on ended span");
|
|
177
|
+
return this;
|
|
178
|
+
}
|
|
179
|
+
this.span.status = "failed";
|
|
180
|
+
this.span.errorMessage = typeof error === "string" ? error : error.message;
|
|
181
|
+
return this;
|
|
182
|
+
}
|
|
183
|
+
async end() {
|
|
184
|
+
if (this.ended) {
|
|
185
|
+
console.warn("Span already ended");
|
|
186
|
+
return;
|
|
187
|
+
}
|
|
188
|
+
this.ended = true;
|
|
189
|
+
this.span.endTime = (/* @__PURE__ */ new Date()).toISOString();
|
|
190
|
+
this.span.durationNs = (new Date(this.span.endTime).getTime() - new Date(this.span.startTime).getTime()) * 1e6;
|
|
191
|
+
if (this.span.status === "pending") {
|
|
192
|
+
this.span.status = "success";
|
|
193
|
+
}
|
|
194
|
+
await this.client.sendSpanUpdate(this.span);
|
|
195
|
+
for (const score of this.scores) {
|
|
196
|
+
await this.client.addScore(this.traceId, score, this.id);
|
|
197
|
+
}
|
|
198
|
+
}
|
|
199
|
+
};
|
|
200
|
+
AigieClient = class {
|
|
201
|
+
config;
|
|
202
|
+
eventQueue = [];
|
|
203
|
+
batchTimer = null;
|
|
204
|
+
enabled;
|
|
205
|
+
constructor(config) {
|
|
206
|
+
const rawUrl = config.apiUrl || process.env.KYTTE_URL || process.env.AIGIE_URL || process.env.AIGIE_API_URL || "";
|
|
207
|
+
const apiUrl = rawUrl.replace(/\/v1?\/?$/, "");
|
|
208
|
+
const apiKey = config.apiKey || process.env.KYTTE_TOKEN || process.env.AIGIE_TOKEN || process.env.AIGIE_API_KEY || "";
|
|
209
|
+
this.config = {
|
|
210
|
+
batchEnabled: true,
|
|
211
|
+
batchSize: 10,
|
|
212
|
+
batchTimeout: 5e3,
|
|
213
|
+
maxQueueSize: 1e3,
|
|
214
|
+
maxRetries: 1,
|
|
215
|
+
retryDelay: 2e3,
|
|
216
|
+
enabled: true,
|
|
217
|
+
...config,
|
|
218
|
+
apiUrl,
|
|
219
|
+
apiKey
|
|
220
|
+
};
|
|
221
|
+
this.enabled = this.config.enabled ?? true;
|
|
222
|
+
}
|
|
223
|
+
// ============================================================================
|
|
224
|
+
// Enable/Disable
|
|
225
|
+
// ============================================================================
|
|
226
|
+
isEnabled() {
|
|
227
|
+
return this.enabled;
|
|
228
|
+
}
|
|
229
|
+
disable() {
|
|
230
|
+
this.enabled = false;
|
|
231
|
+
}
|
|
232
|
+
enable() {
|
|
233
|
+
this.enabled = true;
|
|
234
|
+
}
|
|
235
|
+
// ============================================================================
|
|
236
|
+
// Context Management
|
|
237
|
+
// ============================================================================
|
|
238
|
+
getCurrentContext() {
|
|
239
|
+
return contextStorage.getStore();
|
|
240
|
+
}
|
|
241
|
+
// ============================================================================
|
|
242
|
+
// Fluent Builder API
|
|
243
|
+
// ============================================================================
|
|
244
|
+
spanBuilder(name) {
|
|
245
|
+
return new SpanBuilderImpl(this, name);
|
|
246
|
+
}
|
|
247
|
+
startSpan(options) {
|
|
248
|
+
const context = this.getCurrentContext();
|
|
249
|
+
const spanId = uuidv7();
|
|
250
|
+
const traceId = context?.traceId || uuidv7();
|
|
251
|
+
const span = {
|
|
252
|
+
id: spanId,
|
|
253
|
+
traceId,
|
|
254
|
+
parentSpanId: context?.spanId || options.parentSpanId,
|
|
255
|
+
name: options.name || "unnamed-span",
|
|
256
|
+
type: options.type || "custom",
|
|
257
|
+
input: options.input || {},
|
|
258
|
+
status: "pending",
|
|
259
|
+
tags: [...this.config.defaultTags || [], ...options.tags || []],
|
|
260
|
+
metadata: { ...this.config.defaultMetadata, ...options.metadata },
|
|
261
|
+
modelName: options.modelName,
|
|
262
|
+
startTime: (/* @__PURE__ */ new Date()).toISOString(),
|
|
263
|
+
createdAt: (/* @__PURE__ */ new Date()).toISOString()
|
|
264
|
+
};
|
|
265
|
+
this.queueEvent(this.spanToEvent(span));
|
|
266
|
+
return new ActiveSpanImpl(this, span);
|
|
267
|
+
}
|
|
268
|
+
// ============================================================================
|
|
269
|
+
// Trace API
|
|
270
|
+
// ============================================================================
|
|
271
|
+
async trace(name, fn, options = {}) {
|
|
272
|
+
if (!this.enabled) {
|
|
273
|
+
return fn();
|
|
274
|
+
}
|
|
275
|
+
const traceId = uuidv7();
|
|
276
|
+
const trace = {
|
|
277
|
+
id: traceId,
|
|
278
|
+
name,
|
|
279
|
+
type: options.type || "chain",
|
|
280
|
+
input: options.input || {},
|
|
281
|
+
status: "pending",
|
|
282
|
+
tags: [...this.config.defaultTags || [], ...options.tags || []],
|
|
283
|
+
metadata: { ...this.config.defaultMetadata, ...options.metadata },
|
|
284
|
+
projectName: this.config.projectName,
|
|
285
|
+
userId: options.userId || this.config.defaultUserId,
|
|
286
|
+
sessionId: options.sessionId || this.config.defaultSessionId,
|
|
287
|
+
startTime: (/* @__PURE__ */ new Date()).toISOString(),
|
|
288
|
+
createdAt: (/* @__PURE__ */ new Date()).toISOString()
|
|
289
|
+
};
|
|
290
|
+
const context = { traceId };
|
|
291
|
+
this.queueEvent(this.traceToEvent(trace));
|
|
292
|
+
try {
|
|
293
|
+
const result = await contextStorage.run(context, async () => {
|
|
294
|
+
return await fn();
|
|
295
|
+
});
|
|
296
|
+
trace.status = "success";
|
|
297
|
+
trace.output = { result: typeof result === "object" ? result : { value: result } };
|
|
298
|
+
trace.endTime = (/* @__PURE__ */ new Date()).toISOString();
|
|
299
|
+
trace.durationNs = (new Date(trace.endTime).getTime() - new Date(trace.startTime).getTime()) * 1e6;
|
|
300
|
+
await this.sendTraceUpdate(trace);
|
|
301
|
+
return result;
|
|
302
|
+
} catch (error) {
|
|
303
|
+
trace.status = "failed";
|
|
304
|
+
trace.errorMessage = error instanceof Error ? error.message : String(error);
|
|
305
|
+
trace.endTime = (/* @__PURE__ */ new Date()).toISOString();
|
|
306
|
+
trace.durationNs = (new Date(trace.endTime).getTime() - new Date(trace.startTime).getTime()) * 1e6;
|
|
307
|
+
await this.sendTraceUpdate(trace);
|
|
308
|
+
throw error;
|
|
309
|
+
}
|
|
310
|
+
}
|
|
311
|
+
// ============================================================================
|
|
312
|
+
// Span API
|
|
313
|
+
// ============================================================================
|
|
314
|
+
async span(name, fn, options = {}) {
|
|
315
|
+
if (!this.enabled) {
|
|
316
|
+
return fn();
|
|
317
|
+
}
|
|
318
|
+
const context = this.getCurrentContext();
|
|
319
|
+
if (!context) {
|
|
320
|
+
return this.trace(name, fn, options);
|
|
321
|
+
}
|
|
322
|
+
const spanId = uuidv7();
|
|
323
|
+
const span = {
|
|
324
|
+
id: spanId,
|
|
325
|
+
traceId: context.traceId,
|
|
326
|
+
parentSpanId: context.spanId || options.parentSpanId,
|
|
327
|
+
name,
|
|
328
|
+
type: options.type || "custom",
|
|
329
|
+
input: options.input || {},
|
|
330
|
+
status: "pending",
|
|
331
|
+
tags: [...this.config.defaultTags || [], ...options.tags || []],
|
|
332
|
+
metadata: { ...this.config.defaultMetadata, ...options.metadata },
|
|
333
|
+
modelName: options.modelName,
|
|
334
|
+
startTime: (/* @__PURE__ */ new Date()).toISOString(),
|
|
335
|
+
createdAt: (/* @__PURE__ */ new Date()).toISOString()
|
|
336
|
+
};
|
|
337
|
+
const newContext = {
|
|
338
|
+
traceId: context.traceId,
|
|
339
|
+
spanId,
|
|
340
|
+
parentSpanId: context.spanId
|
|
341
|
+
};
|
|
342
|
+
this.queueEvent(this.spanToEvent(span));
|
|
343
|
+
try {
|
|
344
|
+
const result = await contextStorage.run(newContext, async () => {
|
|
345
|
+
return await fn();
|
|
346
|
+
});
|
|
347
|
+
span.status = "success";
|
|
348
|
+
span.output = { result: typeof result === "object" ? result : { value: result } };
|
|
349
|
+
span.endTime = (/* @__PURE__ */ new Date()).toISOString();
|
|
350
|
+
span.durationNs = (new Date(span.endTime).getTime() - new Date(span.startTime).getTime()) * 1e6;
|
|
351
|
+
await this.sendSpanUpdate(span);
|
|
352
|
+
return result;
|
|
353
|
+
} catch (error) {
|
|
354
|
+
span.status = "failed";
|
|
355
|
+
span.errorMessage = error instanceof Error ? error.message : String(error);
|
|
356
|
+
span.endTime = (/* @__PURE__ */ new Date()).toISOString();
|
|
357
|
+
span.durationNs = (new Date(span.endTime).getTime() - new Date(span.startTime).getTime()) * 1e6;
|
|
358
|
+
await this.sendSpanUpdate(span);
|
|
359
|
+
throw error;
|
|
360
|
+
}
|
|
361
|
+
}
|
|
362
|
+
// ============================================================================
|
|
363
|
+
// Score API
|
|
364
|
+
// ============================================================================
|
|
365
|
+
async addScore(traceId, score, spanId) {
|
|
366
|
+
if (!this.enabled) return;
|
|
367
|
+
try {
|
|
368
|
+
await this.sendToApi("/v1/scores", {
|
|
369
|
+
traceId,
|
|
370
|
+
spanId,
|
|
371
|
+
...score
|
|
372
|
+
});
|
|
373
|
+
} catch (error) {
|
|
374
|
+
if (this.config.debug) {
|
|
375
|
+
console.error("Failed to add score:", error);
|
|
376
|
+
}
|
|
377
|
+
}
|
|
378
|
+
}
|
|
379
|
+
// ============================================================================
|
|
380
|
+
// Send APIs
|
|
381
|
+
// ============================================================================
|
|
382
|
+
async sendTraceUpdate(trace) {
|
|
383
|
+
if (!this.enabled) return;
|
|
384
|
+
const event = this.traceUpdateEvent(trace);
|
|
385
|
+
if (this.config.batchEnabled) {
|
|
386
|
+
this.queueEvent(event);
|
|
387
|
+
} else {
|
|
388
|
+
await this.sendToApi("/v1/ingestion", { batch: [event] });
|
|
389
|
+
}
|
|
390
|
+
}
|
|
391
|
+
async sendSpanUpdate(span) {
|
|
392
|
+
if (!this.enabled) return;
|
|
393
|
+
const event = this.spanUpdateEvent(span);
|
|
394
|
+
if (this.config.batchEnabled) {
|
|
395
|
+
this.queueEvent(event);
|
|
396
|
+
} else {
|
|
397
|
+
await this.sendToApi("/v1/ingestion", { batch: [event] });
|
|
398
|
+
}
|
|
399
|
+
}
|
|
400
|
+
// ============================================================================
|
|
401
|
+
// Batching
|
|
402
|
+
// ============================================================================
|
|
403
|
+
queueEvent(event) {
|
|
404
|
+
const maxSize = this.config.maxQueueSize || 1e3;
|
|
405
|
+
if (this.eventQueue.length >= maxSize) {
|
|
406
|
+
this.eventQueue.splice(0, this.eventQueue.length - maxSize + 1);
|
|
407
|
+
if (this.config.debug) {
|
|
408
|
+
console.warn(`Event queue exceeded max size (${maxSize}), dropping oldest events`);
|
|
409
|
+
}
|
|
410
|
+
}
|
|
411
|
+
this.eventQueue.push(event);
|
|
412
|
+
if (this.eventQueue.length >= (this.config.batchSize || 10)) {
|
|
413
|
+
this.flushBatch();
|
|
414
|
+
} else if (!this.batchTimer) {
|
|
415
|
+
this.batchTimer = setTimeout(() => {
|
|
416
|
+
this.flushBatch();
|
|
417
|
+
}, this.config.batchTimeout || 5e3);
|
|
418
|
+
}
|
|
419
|
+
}
|
|
420
|
+
mapSpanType(type) {
|
|
421
|
+
const typeMap = {
|
|
422
|
+
llm: "generation",
|
|
423
|
+
custom: "span",
|
|
424
|
+
chain: "span",
|
|
425
|
+
tool: "tool",
|
|
426
|
+
retrieval: "retrieval",
|
|
427
|
+
retriever: "retrieval",
|
|
428
|
+
agent: "agent",
|
|
429
|
+
embedding: "generation",
|
|
430
|
+
prompt: "span",
|
|
431
|
+
guardrail: "span",
|
|
432
|
+
evaluation: "span",
|
|
433
|
+
remediation: "span"
|
|
434
|
+
};
|
|
435
|
+
return typeMap[type] || "span";
|
|
436
|
+
}
|
|
437
|
+
traceToEvent(trace) {
|
|
438
|
+
return {
|
|
439
|
+
id: uuidv7(),
|
|
440
|
+
timestamp: (/* @__PURE__ */ new Date()).toISOString(),
|
|
441
|
+
type: "trace-create",
|
|
442
|
+
body: {
|
|
443
|
+
id: trace.id,
|
|
444
|
+
name: trace.name,
|
|
445
|
+
input: trace.input,
|
|
446
|
+
output: trace.output,
|
|
447
|
+
status: trace.status,
|
|
448
|
+
status_message: trace.errorMessage,
|
|
449
|
+
metadata: trace.metadata,
|
|
450
|
+
tags: trace.tags,
|
|
451
|
+
user_id: trace.userId,
|
|
452
|
+
session_id: trace.sessionId,
|
|
453
|
+
environment: this.config.environment,
|
|
454
|
+
start_time: trace.startTime,
|
|
455
|
+
end_time: trace.endTime,
|
|
456
|
+
duration_ns: trace.durationNs
|
|
457
|
+
}
|
|
458
|
+
};
|
|
459
|
+
}
|
|
460
|
+
buildTokenUsage(tokens) {
|
|
461
|
+
if (!tokens) return void 0;
|
|
462
|
+
return {
|
|
463
|
+
prompt_tokens: tokens.prompt,
|
|
464
|
+
completion_tokens: tokens.completion,
|
|
465
|
+
total_tokens: tokens.total,
|
|
466
|
+
cached_tokens: tokens.cached
|
|
467
|
+
};
|
|
468
|
+
}
|
|
469
|
+
spanToEvent(span) {
|
|
470
|
+
return {
|
|
471
|
+
id: uuidv7(),
|
|
472
|
+
timestamp: (/* @__PURE__ */ new Date()).toISOString(),
|
|
473
|
+
type: "span-create",
|
|
474
|
+
body: {
|
|
475
|
+
id: span.id,
|
|
476
|
+
trace_id: span.traceId,
|
|
477
|
+
parent_id: span.parentSpanId,
|
|
478
|
+
name: span.name,
|
|
479
|
+
type: this.mapSpanType(span.type),
|
|
480
|
+
start_time: span.startTime,
|
|
481
|
+
input: span.input,
|
|
482
|
+
model: span.modelName,
|
|
483
|
+
metadata: span.metadata,
|
|
484
|
+
tags: span.tags,
|
|
485
|
+
status: span.status
|
|
486
|
+
}
|
|
487
|
+
};
|
|
488
|
+
}
|
|
489
|
+
traceUpdateEvent(trace) {
|
|
490
|
+
return {
|
|
491
|
+
id: uuidv7(),
|
|
492
|
+
timestamp: (/* @__PURE__ */ new Date()).toISOString(),
|
|
493
|
+
type: "trace-update",
|
|
494
|
+
body: {
|
|
495
|
+
id: trace.id,
|
|
496
|
+
output: trace.output,
|
|
497
|
+
status: trace.status,
|
|
498
|
+
status_message: trace.errorMessage,
|
|
499
|
+
end_time: trace.endTime,
|
|
500
|
+
duration_ns: trace.durationNs
|
|
501
|
+
}
|
|
502
|
+
};
|
|
503
|
+
}
|
|
504
|
+
spanUpdateEvent(span) {
|
|
505
|
+
return {
|
|
506
|
+
id: uuidv7(),
|
|
507
|
+
timestamp: (/* @__PURE__ */ new Date()).toISOString(),
|
|
508
|
+
type: "span-update",
|
|
509
|
+
body: {
|
|
510
|
+
id: span.id,
|
|
511
|
+
trace_id: span.traceId,
|
|
512
|
+
output: span.output,
|
|
513
|
+
status: span.status,
|
|
514
|
+
status_message: span.errorMessage,
|
|
515
|
+
end_time: span.endTime,
|
|
516
|
+
duration_ns: span.durationNs,
|
|
517
|
+
token_usage: this.buildTokenUsage(span.tokens),
|
|
518
|
+
cost: span.cost
|
|
519
|
+
}
|
|
520
|
+
};
|
|
521
|
+
}
|
|
522
|
+
async flushBatch() {
|
|
523
|
+
if (this.batchTimer) {
|
|
524
|
+
clearTimeout(this.batchTimer);
|
|
525
|
+
this.batchTimer = null;
|
|
526
|
+
}
|
|
527
|
+
if (this.eventQueue.length === 0) return;
|
|
528
|
+
const events = [...this.eventQueue];
|
|
529
|
+
this.eventQueue = [];
|
|
530
|
+
const typePriority = {
|
|
531
|
+
"trace-create": 0,
|
|
532
|
+
"span-create": 1,
|
|
533
|
+
"span-update": 2,
|
|
534
|
+
"trace-update": 3
|
|
535
|
+
};
|
|
536
|
+
events.sort((a, b) => (typePriority[a.type] ?? 99) - (typePriority[b.type] ?? 99));
|
|
537
|
+
const maxRetries = this.config.maxRetries ?? 1;
|
|
538
|
+
const retryDelay = this.config.retryDelay ?? 2e3;
|
|
539
|
+
for (let attempt = 0; attempt <= maxRetries; attempt++) {
|
|
540
|
+
try {
|
|
541
|
+
await this.sendToApi("/v1/ingestion", { batch: events });
|
|
542
|
+
return;
|
|
543
|
+
} catch (error) {
|
|
544
|
+
if (attempt < maxRetries) {
|
|
545
|
+
const delay = retryDelay * 2 ** attempt;
|
|
546
|
+
await new Promise((resolve) => setTimeout(resolve, delay));
|
|
547
|
+
} else {
|
|
548
|
+
if (this.config.onError) {
|
|
549
|
+
this.config.onError(error instanceof Error ? error : new Error(String(error)));
|
|
550
|
+
}
|
|
551
|
+
if (this.config.debug) {
|
|
552
|
+
console.error("Failed to send batch after retries:", error);
|
|
553
|
+
}
|
|
554
|
+
}
|
|
555
|
+
}
|
|
556
|
+
}
|
|
557
|
+
}
|
|
558
|
+
// ============================================================================
|
|
559
|
+
// API Communication
|
|
560
|
+
// ============================================================================
|
|
561
|
+
async sendToApi(endpoint, data) {
|
|
562
|
+
const response = await fetch(`${this.config.apiUrl}${endpoint}`, {
|
|
563
|
+
method: "POST",
|
|
564
|
+
headers: {
|
|
565
|
+
"Content-Type": "application/json",
|
|
566
|
+
"X-API-Key": this.config.apiKey,
|
|
567
|
+
"X-Project-Name": this.config.projectName || ""
|
|
568
|
+
},
|
|
569
|
+
body: JSON.stringify(data)
|
|
570
|
+
});
|
|
571
|
+
if (!response.ok) {
|
|
572
|
+
throw new Error(`API error: ${response.status} ${response.statusText}`);
|
|
573
|
+
}
|
|
574
|
+
return response;
|
|
575
|
+
}
|
|
576
|
+
// ============================================================================
|
|
577
|
+
// Shutdown
|
|
578
|
+
// ============================================================================
|
|
579
|
+
/**
|
|
580
|
+
* Force flush all pending spans and signals immediately.
|
|
581
|
+
* Unlike shutdown(), this does not disable the client afterwards.
|
|
582
|
+
*/
|
|
583
|
+
async forceFlush() {
|
|
584
|
+
await this.flushBatch();
|
|
585
|
+
}
|
|
586
|
+
async shutdown() {
|
|
587
|
+
await this.flushBatch();
|
|
588
|
+
this.disable();
|
|
589
|
+
}
|
|
590
|
+
};
|
|
591
|
+
}
|
|
592
|
+
});
|
|
593
|
+
|
|
594
|
+
// src/testing/jest.ts
|
|
595
|
+
function wrapJest(testFn) {
|
|
596
|
+
return (name, fn, timeout) => {
|
|
597
|
+
testFn(
|
|
598
|
+
name,
|
|
599
|
+
async () => {
|
|
600
|
+
let client;
|
|
601
|
+
try {
|
|
602
|
+
const { getKyte: getKyte2 } = await Promise.resolve().then(() => (init_client(), client_exports));
|
|
603
|
+
client = getKyte2();
|
|
604
|
+
} catch {
|
|
605
|
+
return fn();
|
|
606
|
+
}
|
|
607
|
+
return client.trace(
|
|
608
|
+
`test: ${name}`,
|
|
609
|
+
async () => {
|
|
610
|
+
return fn();
|
|
611
|
+
},
|
|
612
|
+
{ type: "custom", metadata: { testFramework: "jest" } }
|
|
613
|
+
);
|
|
614
|
+
},
|
|
615
|
+
timeout
|
|
616
|
+
);
|
|
617
|
+
};
|
|
618
|
+
}
|
|
619
|
+
|
|
620
|
+
// src/testing/vitest.ts
|
|
621
|
+
function wrapVitest(testFn) {
|
|
622
|
+
return (name, fn, timeout) => {
|
|
623
|
+
testFn(
|
|
624
|
+
name,
|
|
625
|
+
async () => {
|
|
626
|
+
let client;
|
|
627
|
+
try {
|
|
628
|
+
const { getKyte: getKyte2 } = await Promise.resolve().then(() => (init_client(), client_exports));
|
|
629
|
+
client = getKyte2();
|
|
630
|
+
} catch {
|
|
631
|
+
return fn();
|
|
632
|
+
}
|
|
633
|
+
return client.trace(
|
|
634
|
+
`test: ${name}`,
|
|
635
|
+
async () => {
|
|
636
|
+
return fn();
|
|
637
|
+
},
|
|
638
|
+
{ type: "custom", metadata: { testFramework: "vitest" } }
|
|
639
|
+
);
|
|
640
|
+
},
|
|
641
|
+
timeout
|
|
642
|
+
);
|
|
643
|
+
};
|
|
644
|
+
}
|
|
645
|
+
|
|
646
|
+
exports.wrapJest = wrapJest;
|
|
647
|
+
exports.wrapVitest = wrapVitest;
|
|
648
|
+
//# sourceMappingURL=index.js.map
|
|
649
|
+
//# sourceMappingURL=index.js.map
|