@latitude-data/telemetry 0.0.3 → 1.0.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.
package/dist/index.js CHANGED
@@ -1,482 +1,1954 @@
1
- import { ExportResultCode, hrTimeToNanoseconds } from '@opentelemetry/core';
2
- import { OTLPExporterBase } from '@opentelemetry/otlp-exporter-base';
3
- import { SimpleSpanProcessor, BatchSpanProcessor } from '@opentelemetry/sdk-trace-base';
4
- import { NodeSDK } from '@opentelemetry/sdk-node';
5
- import { SimpleSpanProcessor as SimpleSpanProcessor$1, BatchSpanProcessor as BatchSpanProcessor$1 } from '@opentelemetry/sdk-trace-node';
1
+ import { z } from 'zod';
2
+ import * as otel from '@opentelemetry/api';
3
+ import { propagation, trace, context } from '@opentelemetry/api';
4
+ import { ATTR_HTTP_REQUEST_METHOD, ATTR_HTTP_RESPONSE_STATUS_CODE, ATTR_SERVICE_NAME } from '@opentelemetry/semantic-conventions';
5
+ import { ATTR_GEN_AI_OPERATION_NAME, ATTR_GEN_AI_TOOL_CALL_ID, ATTR_GEN_AI_TOOL_TYPE, ATTR_GEN_AI_TOOL_NAME, ATTR_GEN_AI_SYSTEM, ATTR_GEN_AI_RESPONSE_FINISH_REASONS, ATTR_GEN_AI_RESPONSE_MODEL, ATTR_GEN_AI_USAGE_OUTPUT_TOKENS, ATTR_GEN_AI_USAGE_INPUT_TOKENS } from '@opentelemetry/semantic-conventions/incubating';
6
+ import { v4 } from 'uuid';
7
+ import { BaggageSpanProcessor, ALLOW_ALL_BAGGAGE_KEYS } from '@opentelemetry/baggage-span-processor';
8
+ import { AsyncLocalStorageContextManager } from '@opentelemetry/context-async-hooks';
9
+ import { CompositePropagator, W3CTraceContextPropagator, W3CBaggagePropagator } from '@opentelemetry/core';
10
+ import { OTLPTraceExporter } from '@opentelemetry/exporter-trace-otlp-http';
11
+ import { registerInstrumentations } from '@opentelemetry/instrumentation';
12
+ import { Resource } from '@opentelemetry/resources';
13
+ import { NodeTracerProvider, SimpleSpanProcessor, BatchSpanProcessor } from '@opentelemetry/sdk-trace-node';
6
14
  import { AnthropicInstrumentation } from '@traceloop/instrumentation-anthropic';
7
- import { OpenAIInstrumentation } from '@traceloop/instrumentation-openai';
8
15
  import { AzureOpenAIInstrumentation } from '@traceloop/instrumentation-azure';
9
- import { VertexAIInstrumentation, AIPlatformInstrumentation } from '@traceloop/instrumentation-vertexai';
10
16
  import { BedrockInstrumentation } from '@traceloop/instrumentation-bedrock';
11
17
  import { CohereInstrumentation } from '@traceloop/instrumentation-cohere';
12
- import { Resource } from '@opentelemetry/resources';
13
- import { context, trace } from '@opentelemetry/api';
18
+ import { LangChainInstrumentation } from '@traceloop/instrumentation-langchain';
19
+ import { LlamaIndexInstrumentation } from '@traceloop/instrumentation-llamaindex';
20
+ import { OpenAIInstrumentation } from '@traceloop/instrumentation-openai';
21
+ import { TogetherInstrumentation } from '@traceloop/instrumentation-together';
22
+ import { VertexAIInstrumentation, AIPlatformInstrumentation } from '@traceloop/instrumentation-vertexai';
23
+
24
+ class RedactSpanProcessor {
25
+ options;
26
+ constructor(options) {
27
+ this.options = options;
28
+ if (!options.mask) {
29
+ this.options.mask = (_attribute, _value) => '******';
30
+ }
31
+ }
32
+ onStart(_span, _context) {
33
+ // Noop
34
+ }
35
+ onEnd(span) {
36
+ Object.assign(span.attributes, this.redactAttributes(span.attributes));
37
+ for (const event of span.events) {
38
+ if (!event.attributes)
39
+ continue;
40
+ Object.assign(event.attributes, this.redactAttributes(event.attributes));
41
+ }
42
+ for (const link of span.links) {
43
+ if (!link.attributes)
44
+ continue;
45
+ Object.assign(link.attributes, this.redactAttributes(link.attributes));
46
+ }
47
+ }
48
+ forceFlush() {
49
+ return Promise.resolve();
50
+ }
51
+ shutdown() {
52
+ return Promise.resolve();
53
+ }
54
+ shouldRedact(attribute) {
55
+ return this.options.attributes.some((pattern) => {
56
+ if (typeof pattern === 'string') {
57
+ return attribute === pattern;
58
+ }
59
+ else if (pattern instanceof RegExp) {
60
+ return pattern.test(attribute);
61
+ }
62
+ return false;
63
+ });
64
+ }
65
+ redactAttributes(attributes) {
66
+ const redacted = {};
67
+ for (const [key, value] of Object.entries(attributes)) {
68
+ if (this.shouldRedact(key)) {
69
+ redacted[key] = this.options.mask(key, value);
70
+ }
71
+ }
72
+ return redacted;
73
+ }
74
+ }
75
+ const DEFAULT_REDACT_SPAN_PROCESSOR = () => new RedactSpanProcessor({
76
+ attributes: [
77
+ /^.*auth.*$/i,
78
+ /^.*authorization.*$/i,
79
+ /^(?!gen_ai\.).*token.*$/i,
80
+ /^.*secret.*$/i,
81
+ /^.*key.*$/i,
82
+ /^.*password.*$/i,
83
+ /^.*cookie.*$/i,
84
+ /^.*session.*$/i,
85
+ /^.*credential.*$/i,
86
+ /^.*signature.*$/i,
87
+ /^.*oauth.*$/i,
88
+ /^.*saml.*$/i,
89
+ /^.*openid.*$/i,
90
+ /^.*refresh.*$/i,
91
+ /^.*jwt.*$/i,
92
+ /^.*otp.*$/i,
93
+ /^.*mfa.*$/i,
94
+ /^.*csrf.*$/i,
95
+ /^.*xsrf.*$/i,
96
+ /^.*refresh.*$/i,
97
+ /^.*x[-_]forwarded[-_]for.*$/i,
98
+ /^.*x[-_]real[-_]ip.*$/i,
99
+ ],
100
+ });
101
+
102
+ const DEFAULT_GATEWAY_BASE_URL = {
103
+ production: 'https://gateway.latitude.so',
104
+ development: 'http://localhost:8787',
105
+ test: 'http://localhost:8787',
106
+ }["production"];
107
+ function GET_GATEWAY_BASE_URL() {
108
+ if (process.env.GATEWAY_BASE_URL) {
109
+ return process.env.GATEWAY_BASE_URL;
110
+ }
111
+ if (!process.env.GATEWAY_HOSTNAME) {
112
+ return DEFAULT_GATEWAY_BASE_URL;
113
+ }
114
+ const protocol = process.env.GATEWAY_SSL ? 'https' : 'http';
115
+ const port = process.env.GATEWAY_PORT ?? (process.env.GATEWAY_SSL ? 443 : 80);
116
+ const hostname = process.env.GATEWAY_HOSTNAME;
117
+ return `${protocol}://${hostname}:${port}`;
118
+ }
119
+ const env = { GATEWAY_BASE_URL: GET_GATEWAY_BASE_URL() };
120
+
121
+ var SegmentSource;
122
+ (function (SegmentSource) {
123
+ SegmentSource["API"] = "api";
124
+ SegmentSource["Playground"] = "playground";
125
+ SegmentSource["Evaluation"] = "evaluation";
126
+ SegmentSource["Experiment"] = "experiment";
127
+ SegmentSource["User"] = "user";
128
+ SegmentSource["SharedPrompt"] = "shared_prompt";
129
+ SegmentSource["AgentAsTool"] = "agent_as_tool";
130
+ SegmentSource["EmailTrigger"] = "email_trigger";
131
+ SegmentSource["ScheduledTrigger"] = "scheduled_trigger";
132
+ })(SegmentSource || (SegmentSource = {}));
133
+ var SegmentType;
134
+ (function (SegmentType) {
135
+ SegmentType["Document"] = "document";
136
+ SegmentType["Step"] = "step";
137
+ })(SegmentType || (SegmentType = {}));
138
+ const baseSegmentBaggageSchema = z.object({
139
+ id: z.string(),
140
+ parentId: z.string().optional(),
141
+ source: z.nativeEnum(SegmentSource),
142
+ });
143
+ z.discriminatedUnion('type', [
144
+ baseSegmentBaggageSchema.extend({
145
+ type: z.literal(SegmentType.Document),
146
+ data: z.object({
147
+ logUuid: z.string().optional(), // TODO(tracing): temporal related log, remove when observability is ready
148
+ commitUuid: z.string(),
149
+ documentUuid: z.string(),
150
+ experimentUuid: z.string().optional(),
151
+ externalId: z.string().optional(),
152
+ }),
153
+ }),
154
+ baseSegmentBaggageSchema.extend({
155
+ type: z.literal(SegmentType.Step),
156
+ data: z.undefined().optional(),
157
+ }),
158
+ ]);
159
+
160
+ var SpanKind;
161
+ (function (SpanKind) {
162
+ SpanKind["Internal"] = "internal";
163
+ SpanKind["Server"] = "server";
164
+ SpanKind["Client"] = "client";
165
+ SpanKind["Producer"] = "producer";
166
+ SpanKind["Consumer"] = "consumer";
167
+ })(SpanKind || (SpanKind = {}));
168
+ // Note: loosely based on OpenTelemetry GenAI semantic conventions
169
+ var SpanType;
170
+ (function (SpanType) {
171
+ SpanType["Tool"] = "tool";
172
+ SpanType["Completion"] = "completion";
173
+ SpanType["Embedding"] = "embedding";
174
+ SpanType["Retrieval"] = "retrieval";
175
+ SpanType["Reranking"] = "reranking";
176
+ SpanType["Http"] = "http";
177
+ SpanType["Segment"] = "segment";
178
+ SpanType["Unknown"] = "unknown";
179
+ })(SpanType || (SpanType = {}));
180
+ const GENAI_SPANS = [
181
+ SpanType.Tool,
182
+ SpanType.Completion,
183
+ SpanType.Embedding,
184
+ SpanType.Retrieval,
185
+ SpanType.Reranking,
186
+ ];
187
+ [SpanType.Http, SpanType.Segment, SpanType.Unknown];
188
+ var SpanStatus;
189
+ (function (SpanStatus) {
190
+ SpanStatus["Unset"] = "unset";
191
+ SpanStatus["Ok"] = "ok";
192
+ SpanStatus["Error"] = "error";
193
+ })(SpanStatus || (SpanStatus = {}));
194
+
195
+ // Note: Traces are unmaterialized but this context is used to propagate the trace
196
+ // See www.w3.org/TR/trace-context and w3c.github.io/baggage
197
+ z.object({
198
+ traceparent: z.string(), // <version>-<trace-id>-<span-id>-<trace-flags>
199
+ tracestate: z.string().optional(), // <key>=urlencoded(<value>)[,<key>=urlencoded(<value>)]*
200
+ baggage: z.string().optional(), // <key>=urlencoded(<value>)[,<key>=urlencoded(<value>)]*
201
+ });
202
+
203
+ /* Note: Instrumentation scopes from all language SDKs */
204
+ const SCOPE_LATITUDE = 'so.latitude.instrumentation';
205
+ var InstrumentationScope;
206
+ (function (InstrumentationScope) {
207
+ InstrumentationScope["Manual"] = "manual";
208
+ InstrumentationScope["Latitude"] = "latitude";
209
+ InstrumentationScope["OpenAI"] = "openai";
210
+ InstrumentationScope["Anthropic"] = "anthropic";
211
+ InstrumentationScope["AzureOpenAI"] = "azure";
212
+ InstrumentationScope["VercelAI"] = "vercelai";
213
+ InstrumentationScope["VertexAI"] = "vertexai";
214
+ InstrumentationScope["AIPlatform"] = "aiplatform";
215
+ InstrumentationScope["MistralAI"] = "mistralai";
216
+ InstrumentationScope["Bedrock"] = "bedrock";
217
+ InstrumentationScope["Sagemaker"] = "sagemaker";
218
+ InstrumentationScope["TogetherAI"] = "togetherai";
219
+ InstrumentationScope["Replicate"] = "replicate";
220
+ InstrumentationScope["Groq"] = "groq";
221
+ InstrumentationScope["Cohere"] = "cohere";
222
+ InstrumentationScope["LiteLLM"] = "litellm";
223
+ InstrumentationScope["Langchain"] = "langchain";
224
+ InstrumentationScope["LlamaIndex"] = "llamaindex";
225
+ InstrumentationScope["DSPy"] = "dspy";
226
+ InstrumentationScope["Haystack"] = "haystack";
227
+ InstrumentationScope["Ollama"] = "ollama";
228
+ InstrumentationScope["Transformers"] = "transformers";
229
+ InstrumentationScope["AlephAlpha"] = "alephalpha";
230
+ })(InstrumentationScope || (InstrumentationScope = {}));
231
+ /* Note: non-standard OpenTelemetry semantic conventions used in Latitude */
232
+ const ATTR_LATITUDE = 'latitude';
233
+ const ATTR_LATITUDE_TYPE = `${ATTR_LATITUDE}.type`;
234
+ const ATTR_LATITUDE_SEGMENT_ID = `${ATTR_LATITUDE}.segment.id`;
235
+ const ATTR_LATITUDE_SEGMENT_PARENT_ID = `${ATTR_LATITUDE}.segment.parent_id`;
236
+ const ATTR_LATITUDE_SEGMENTS = `${ATTR_LATITUDE}.segments`;
237
+ const GEN_AI_TOOL_TYPE_VALUE_FUNCTION = 'function';
238
+ const ATTR_GEN_AI_TOOL_CALL_ARGUMENTS = 'gen_ai.tool.call.arguments';
239
+ const ATTR_GEN_AI_TOOL_RESULT_VALUE = 'gen_ai.tool.result.value';
240
+ const ATTR_GEN_AI_TOOL_RESULT_IS_ERROR = 'gen_ai.tool.result.is_error';
241
+ const ATTR_GEN_AI_REQUEST = 'gen_ai.request';
242
+ const ATTR_GEN_AI_REQUEST_CONFIGURATION = 'gen_ai.request.configuration';
243
+ const ATTR_GEN_AI_REQUEST_TEMPLATE = 'gen_ai.request.template';
244
+ const ATTR_GEN_AI_REQUEST_PARAMETERS = 'gen_ai.request.parameters';
245
+ const ATTR_GEN_AI_REQUEST_MESSAGES = 'gen_ai.request.messages';
246
+ const ATTR_GEN_AI_RESPONSE = 'gen_ai.response';
247
+ const ATTR_GEN_AI_RESPONSE_MESSAGES = 'gen_ai.response.messages';
248
+ const ATTR_GEN_AI_USAGE_PROMPT_TOKENS = 'gen_ai.usage.prompt_tokens';
249
+ const ATTR_GEN_AI_USAGE_CACHED_TOKENS = 'gen_ai.usage.cached_tokens';
250
+ const ATTR_GEN_AI_USAGE_REASONING_TOKENS = 'gen_ai.usage.reasoning_tokens'; // prettier-ignore
251
+ const ATTR_GEN_AI_USAGE_COMPLETION_TOKENS = 'gen_ai.usage.completion_tokens'; // prettier-ignore
252
+ const ATTR_GEN_AI_PROMPTS = 'gen_ai.prompt'; // gen_ai.prompt.{index}.{role/content/...}
253
+ const ATTR_GEN_AI_COMPLETIONS = 'gen_ai.completion'; // gen_ai.completion.{index}.{role/content/...}
254
+ const ATTR_GEN_AI_MESSAGE_ROLE = 'role';
255
+ const ATTR_GEN_AI_MESSAGE_CONTENT = 'content'; // string or object
256
+ const ATTR_GEN_AI_MESSAGE_TOOL_NAME = 'tool_name';
257
+ const ATTR_GEN_AI_MESSAGE_TOOL_CALL_ID = 'tool_call_id';
258
+ const ATTR_GEN_AI_MESSAGE_TOOL_RESULT_IS_ERROR = 'is_error';
259
+ const ATTR_GEN_AI_MESSAGE_TOOL_CALLS = 'tool_calls'; // gen_ai.completion.{index}.tool_calls.{index}.{id/name/arguments}
260
+ const ATTR_GEN_AI_MESSAGE_TOOL_CALLS_ID = 'id';
261
+ const ATTR_GEN_AI_MESSAGE_TOOL_CALLS_NAME = 'name';
262
+ const ATTR_GEN_AI_MESSAGE_TOOL_CALLS_ARGUMENTS = 'arguments';
263
+ const GEN_AI_RESPONSE_FINISH_REASON_VALUE_STOP = 'stop';
264
+ const GEN_AI_RESPONSE_FINISH_REASON_VALUE_TOOL_CALLS = 'tool_calls';
265
+ const ATTR_HTTP_REQUEST_URL = 'http.request.url';
266
+ const ATTR_HTTP_REQUEST_BODY = 'http.request.body';
267
+ const ATTR_HTTP_REQUEST_HEADERS = 'http.request.header';
268
+ const ATTR_HTTP_RESPONSE_BODY = 'http.response.body';
269
+ const ATTR_HTTP_RESPONSE_HEADERS = 'http.response.header';
270
+ /* Note: Schemas for span ingestion following OpenTelemetry service request specification */
271
+ var Otlp;
272
+ (function (Otlp) {
273
+ Otlp.attributeValueSchema = z.object({
274
+ stringValue: z.string().optional(),
275
+ intValue: z.number().optional(),
276
+ boolValue: z.boolean().optional(),
277
+ arrayValue: z
278
+ .object({
279
+ values: z.array(z.object({
280
+ stringValue: z.string().optional(),
281
+ intValue: z.number().optional(),
282
+ boolValue: z.boolean().optional(),
283
+ })),
284
+ })
285
+ .optional(),
286
+ });
287
+ Otlp.attributeSchema = z.object({
288
+ key: z.string(),
289
+ value: Otlp.attributeValueSchema,
290
+ });
291
+ Otlp.eventSchema = z.object({
292
+ name: z.string(),
293
+ timeUnixNano: z.string(),
294
+ attributes: z.array(Otlp.attributeSchema).optional(),
295
+ });
296
+ Otlp.linkSchema = z.object({
297
+ traceId: z.string(),
298
+ spanId: z.string(),
299
+ attributes: z.array(Otlp.attributeSchema).optional(),
300
+ });
301
+ Otlp.statusSchema = z.object({
302
+ code: z.number(),
303
+ message: z.string().optional(),
304
+ });
305
+ Otlp.spanSchema = z.object({
306
+ traceId: z.string(),
307
+ spanId: z.string(),
308
+ parentSpanId: z.string().optional(),
309
+ name: z.string(),
310
+ kind: z.number(),
311
+ startTimeUnixNano: z.string(),
312
+ endTimeUnixNano: z.string(),
313
+ status: Otlp.statusSchema.optional(),
314
+ events: z.array(Otlp.eventSchema).optional(),
315
+ links: z.array(Otlp.linkSchema).optional(),
316
+ attributes: z.array(Otlp.attributeSchema).optional(),
317
+ });
318
+ Otlp.scopeSchema = z.object({
319
+ name: z.string(),
320
+ version: z.string().optional(),
321
+ });
322
+ Otlp.scopeSpanSchema = z.object({
323
+ scope: Otlp.scopeSchema,
324
+ spans: z.array(Otlp.spanSchema),
325
+ });
326
+ Otlp.resourceSchema = z.object({
327
+ attributes: z.array(Otlp.attributeSchema),
328
+ });
329
+ Otlp.resourceSpanSchema = z.object({
330
+ resource: Otlp.resourceSchema,
331
+ scopeSpans: z.array(Otlp.scopeSpanSchema),
332
+ });
333
+ Otlp.serviceRequestSchema = z.object({
334
+ resourceSpans: z.array(Otlp.resourceSpanSchema),
335
+ });
336
+ })(Otlp || (Otlp = {}));
337
+
338
+ var StreamEventTypes;
339
+ (function (StreamEventTypes) {
340
+ StreamEventTypes["Latitude"] = "latitude-event";
341
+ StreamEventTypes["Provider"] = "provider-event";
342
+ })(StreamEventTypes || (StreamEventTypes = {}));
343
+ z.object({
344
+ id: z.string(),
345
+ name: z.string(),
346
+ result: z.unknown(),
347
+ isError: z.boolean().optional(),
348
+ text: z.string().optional(),
349
+ });
350
+
351
+ var ParameterType;
352
+ (function (ParameterType) {
353
+ ParameterType["Text"] = "text";
354
+ ParameterType["Image"] = "image";
355
+ ParameterType["File"] = "file";
356
+ })(ParameterType || (ParameterType = {}));
357
+ var LatitudeTool;
358
+ (function (LatitudeTool) {
359
+ LatitudeTool["RunCode"] = "code";
360
+ LatitudeTool["WebSearch"] = "search";
361
+ LatitudeTool["WebExtract"] = "extract";
362
+ })(LatitudeTool || (LatitudeTool = {}));
363
+ var LatitudeToolInternalName;
364
+ (function (LatitudeToolInternalName) {
365
+ LatitudeToolInternalName["RunCode"] = "lat_tool_run_code";
366
+ LatitudeToolInternalName["WebSearch"] = "lat_tool_web_search";
367
+ LatitudeToolInternalName["WebExtract"] = "lat_tool_web_extract";
368
+ })(LatitudeToolInternalName || (LatitudeToolInternalName = {}));
369
+
370
+ const actualOutputConfiguration = z.object({
371
+ messageSelection: z.enum(['last', 'all']), // Which assistant messages to select
372
+ contentFilter: z.enum(['text', 'image', 'file', 'tool_call']).optional(),
373
+ parsingFormat: z.enum(['string', 'json']),
374
+ fieldAccessor: z.string().optional(), // Field accessor to get the output from if it's a key-value format
375
+ });
376
+ const expectedOutputConfiguration = z.object({
377
+ parsingFormat: z.enum(['string', 'json']),
378
+ fieldAccessor: z.string().optional(), // Field accessor to get the output from if it's a key-value format
379
+ });
380
+ const baseEvaluationConfiguration = z.object({
381
+ reverseScale: z.boolean(), // If true, lower is better, otherwise, higher is better
382
+ actualOutput: actualOutputConfiguration.optional(), // Optional for backwards compatibility
383
+ expectedOutput: expectedOutputConfiguration.optional(), // Optional for backwards compatibility
384
+ });
385
+ const baseEvaluationResultMetadata = z.object({
386
+ // Configuration snapshot is defined in every metric specification
387
+ actualOutput: z.string(),
388
+ expectedOutput: z.string().optional(),
389
+ datasetLabel: z.string().optional(),
390
+ });
391
+ const baseEvaluationResultError = z.object({
392
+ message: z.string(),
393
+ });
394
+
395
+ const humanEvaluationConfiguration = baseEvaluationConfiguration.extend({
396
+ criteria: z.string().optional(),
397
+ });
398
+ const humanEvaluationResultMetadata = baseEvaluationResultMetadata.extend({
399
+ reason: z.string().optional(),
400
+ });
401
+ const humanEvaluationResultError = baseEvaluationResultError.extend({});
402
+ // BINARY
403
+ const humanEvaluationBinaryConfiguration = humanEvaluationConfiguration.extend({
404
+ passDescription: z.string().optional(),
405
+ failDescription: z.string().optional(),
406
+ });
407
+ humanEvaluationResultMetadata.extend({
408
+ configuration: humanEvaluationBinaryConfiguration,
409
+ });
410
+ humanEvaluationResultError.extend({});
411
+ const HumanEvaluationBinarySpecification = {
412
+ };
413
+ // RATING
414
+ const humanEvaluationRatingConfiguration = humanEvaluationConfiguration.extend({
415
+ minRating: z.number(),
416
+ minRatingDescription: z.string().optional(),
417
+ maxRating: z.number(),
418
+ maxRatingDescription: z.string().optional(),
419
+ minThreshold: z.number().optional(), // Threshold in rating range
420
+ maxThreshold: z.number().optional(), // Threshold in rating range
421
+ });
422
+ humanEvaluationResultMetadata.extend({
423
+ configuration: humanEvaluationRatingConfiguration,
424
+ });
425
+ humanEvaluationResultError.extend({});
426
+ const HumanEvaluationRatingSpecification = {
427
+ };
428
+ /* ------------------------------------------------------------------------- */
429
+ var HumanEvaluationMetric;
430
+ (function (HumanEvaluationMetric) {
431
+ HumanEvaluationMetric["Binary"] = "binary";
432
+ HumanEvaluationMetric["Rating"] = "rating";
433
+ })(HumanEvaluationMetric || (HumanEvaluationMetric = {}));
434
+ const HumanEvaluationSpecification = {
435
+ // prettier-ignore
436
+ metrics: {
437
+ [HumanEvaluationMetric.Binary]: HumanEvaluationBinarySpecification,
438
+ [HumanEvaluationMetric.Rating]: HumanEvaluationRatingSpecification,
439
+ },
440
+ };
14
441
 
15
- const DOMAIN = 'gateway.latitude.so/api/v2/otlp'
16
- ;
17
- const PROTOCOL = 'https' ;
18
- class LatitudeExporter extends OTLPExporterBase {
19
- url;
20
- headers;
21
- constructor(config) {
22
- super(config);
23
- this.url = config.endpoint || this.__defaultUrl;
24
- this.headers = {
25
- Authorization: `Bearer ${config.apiKey}`,
442
+ const llmEvaluationConfiguration = baseEvaluationConfiguration.extend({
443
+ provider: z.string(),
444
+ model: z.string(),
445
+ });
446
+ const llmEvaluationResultMetadata = baseEvaluationResultMetadata.extend({
447
+ evaluationLogId: z.number(),
448
+ reason: z.string(),
449
+ tokens: z.number(),
450
+ cost: z.number(),
451
+ duration: z.number(),
452
+ });
453
+ const llmEvaluationResultError = baseEvaluationResultError.extend({
454
+ runErrorId: z.number().optional(),
455
+ });
456
+ // BINARY
457
+ const llmEvaluationBinaryConfiguration = llmEvaluationConfiguration.extend({
458
+ criteria: z.string(),
459
+ passDescription: z.string(),
460
+ failDescription: z.string(),
461
+ });
462
+ llmEvaluationResultMetadata.extend({
463
+ configuration: llmEvaluationBinaryConfiguration,
464
+ });
465
+ llmEvaluationResultError.extend({});
466
+ const LlmEvaluationBinarySpecification = {
467
+ };
468
+ // RATING
469
+ const llmEvaluationRatingConfiguration = llmEvaluationConfiguration.extend({
470
+ criteria: z.string(),
471
+ minRating: z.number(),
472
+ minRatingDescription: z.string(),
473
+ maxRating: z.number(),
474
+ maxRatingDescription: z.string(),
475
+ minThreshold: z.number().optional(), // Threshold in rating range
476
+ maxThreshold: z.number().optional(), // Threshold in rating range
477
+ });
478
+ llmEvaluationResultMetadata.extend({
479
+ configuration: llmEvaluationRatingConfiguration,
480
+ });
481
+ llmEvaluationResultError.extend({});
482
+ const LlmEvaluationRatingSpecification = {
483
+ };
484
+ // COMPARISON
485
+ const llmEvaluationComparisonConfiguration = llmEvaluationConfiguration.extend({
486
+ criteria: z.string(),
487
+ passDescription: z.string(),
488
+ failDescription: z.string(),
489
+ minThreshold: z.number().optional(), // Threshold percentage
490
+ maxThreshold: z.number().optional(), // Threshold percentage
491
+ });
492
+ llmEvaluationResultMetadata.extend({
493
+ configuration: llmEvaluationComparisonConfiguration,
494
+ });
495
+ llmEvaluationResultError.extend({});
496
+ const LlmEvaluationComparisonSpecification = {
497
+ };
498
+ // CUSTOM
499
+ const llmEvaluationCustomConfiguration = llmEvaluationConfiguration.extend({
500
+ prompt: z.string(),
501
+ minScore: z.number(),
502
+ maxScore: z.number(),
503
+ minThreshold: z.number().optional(), // Threshold percentage
504
+ maxThreshold: z.number().optional(), // Threshold percentage
505
+ });
506
+ llmEvaluationResultMetadata.extend({
507
+ configuration: llmEvaluationCustomConfiguration,
508
+ });
509
+ llmEvaluationResultError.extend({});
510
+ const LlmEvaluationCustomSpecification = {
511
+ };
512
+ // CUSTOM LABELED
513
+ const LlmEvaluationCustomLabeledSpecification = {
514
+ };
515
+ /* ------------------------------------------------------------------------- */
516
+ var LlmEvaluationMetric;
517
+ (function (LlmEvaluationMetric) {
518
+ LlmEvaluationMetric["Binary"] = "binary";
519
+ LlmEvaluationMetric["Rating"] = "rating";
520
+ LlmEvaluationMetric["Comparison"] = "comparison";
521
+ LlmEvaluationMetric["Custom"] = "custom";
522
+ LlmEvaluationMetric["CustomLabeled"] = "custom_labeled";
523
+ })(LlmEvaluationMetric || (LlmEvaluationMetric = {}));
524
+ const LlmEvaluationSpecification = {
525
+ // prettier-ignore
526
+ metrics: {
527
+ [LlmEvaluationMetric.Binary]: LlmEvaluationBinarySpecification,
528
+ [LlmEvaluationMetric.Rating]: LlmEvaluationRatingSpecification,
529
+ [LlmEvaluationMetric.Comparison]: LlmEvaluationComparisonSpecification,
530
+ [LlmEvaluationMetric.Custom]: LlmEvaluationCustomSpecification,
531
+ [LlmEvaluationMetric.CustomLabeled]: LlmEvaluationCustomLabeledSpecification,
532
+ },
533
+ };
534
+
535
+ const ruleEvaluationConfiguration = baseEvaluationConfiguration.extend({});
536
+ const ruleEvaluationResultMetadata = baseEvaluationResultMetadata.extend({});
537
+ const ruleEvaluationResultError = baseEvaluationResultError.extend({});
538
+ // EXACT MATCH
539
+ const ruleEvaluationExactMatchConfiguration = ruleEvaluationConfiguration.extend({
540
+ caseInsensitive: z.boolean(),
541
+ });
542
+ ruleEvaluationResultMetadata.extend({
543
+ configuration: ruleEvaluationExactMatchConfiguration,
544
+ });
545
+ ruleEvaluationResultError.extend({});
546
+ const RuleEvaluationExactMatchSpecification = {
547
+ };
548
+ // REGULAR EXPRESSION
549
+ const ruleEvaluationRegularExpressionConfiguration = ruleEvaluationConfiguration.extend({
550
+ pattern: z.string(),
551
+ });
552
+ ruleEvaluationResultMetadata.extend({
553
+ configuration: ruleEvaluationRegularExpressionConfiguration,
554
+ });
555
+ ruleEvaluationResultError.extend({});
556
+ const RuleEvaluationRegularExpressionSpecification = {
557
+ };
558
+ // SCHEMA VALIDATION
559
+ const ruleEvaluationSchemaValidationConfiguration = ruleEvaluationConfiguration.extend({
560
+ format: z.enum(['json']),
561
+ schema: z.string(),
562
+ });
563
+ ruleEvaluationResultMetadata.extend({
564
+ configuration: ruleEvaluationSchemaValidationConfiguration,
565
+ });
566
+ ruleEvaluationResultError.extend({});
567
+ const RuleEvaluationSchemaValidationSpecification = {
568
+ };
569
+ // LENGTH COUNT
570
+ const ruleEvaluationLengthCountConfiguration = ruleEvaluationConfiguration.extend({
571
+ algorithm: z.enum(['character', 'word', 'sentence']),
572
+ minLength: z.number().optional(),
573
+ maxLength: z.number().optional(),
574
+ });
575
+ ruleEvaluationResultMetadata.extend({
576
+ configuration: ruleEvaluationLengthCountConfiguration,
577
+ });
578
+ ruleEvaluationResultError.extend({});
579
+ const RuleEvaluationLengthCountSpecification = {
580
+ };
581
+ // LEXICAL OVERLAP
582
+ const ruleEvaluationLexicalOverlapConfiguration = ruleEvaluationConfiguration.extend({
583
+ algorithm: z.enum(['substring', 'levenshtein_distance', 'rouge']),
584
+ minOverlap: z.number().optional(), // Percentage of overlap
585
+ maxOverlap: z.number().optional(), // Percentage of overlap
586
+ });
587
+ ruleEvaluationResultMetadata.extend({
588
+ configuration: ruleEvaluationLexicalOverlapConfiguration,
589
+ });
590
+ ruleEvaluationResultError.extend({});
591
+ const RuleEvaluationLexicalOverlapSpecification = {
592
+ };
593
+ // SEMANTIC SIMILARITY
594
+ const ruleEvaluationSemanticSimilarityConfiguration = ruleEvaluationConfiguration.extend({
595
+ algorithm: z.enum(['cosine_distance']),
596
+ minSimilarity: z.number().optional(), // Percentage of similarity
597
+ maxSimilarity: z.number().optional(), // Percentage of similarity
598
+ });
599
+ ruleEvaluationResultMetadata.extend({
600
+ configuration: ruleEvaluationSemanticSimilarityConfiguration,
601
+ });
602
+ ruleEvaluationResultError.extend({});
603
+ const RuleEvaluationSemanticSimilaritySpecification = {
604
+ };
605
+ // NUMERIC SIMILARITY
606
+ const ruleEvaluationNumericSimilarityConfiguration = ruleEvaluationConfiguration.extend({
607
+ algorithm: z.enum(['relative_difference']),
608
+ minSimilarity: z.number().optional(), // Percentage of similarity
609
+ maxSimilarity: z.number().optional(), // Percentage of similarity
610
+ });
611
+ ruleEvaluationResultMetadata.extend({
612
+ configuration: ruleEvaluationNumericSimilarityConfiguration,
613
+ });
614
+ ruleEvaluationResultError.extend({});
615
+ const RuleEvaluationNumericSimilaritySpecification = {
616
+ };
617
+ /* ------------------------------------------------------------------------- */
618
+ var RuleEvaluationMetric;
619
+ (function (RuleEvaluationMetric) {
620
+ RuleEvaluationMetric["ExactMatch"] = "exact_match";
621
+ RuleEvaluationMetric["RegularExpression"] = "regular_expression";
622
+ RuleEvaluationMetric["SchemaValidation"] = "schema_validation";
623
+ RuleEvaluationMetric["LengthCount"] = "length_count";
624
+ RuleEvaluationMetric["LexicalOverlap"] = "lexical_overlap";
625
+ RuleEvaluationMetric["SemanticSimilarity"] = "semantic_similarity";
626
+ RuleEvaluationMetric["NumericSimilarity"] = "numeric_similarity";
627
+ })(RuleEvaluationMetric || (RuleEvaluationMetric = {}));
628
+ const RuleEvaluationSpecification = {
629
+ // prettier-ignore
630
+ metrics: {
631
+ [RuleEvaluationMetric.ExactMatch]: RuleEvaluationExactMatchSpecification,
632
+ [RuleEvaluationMetric.RegularExpression]: RuleEvaluationRegularExpressionSpecification,
633
+ [RuleEvaluationMetric.SchemaValidation]: RuleEvaluationSchemaValidationSpecification,
634
+ [RuleEvaluationMetric.LengthCount]: RuleEvaluationLengthCountSpecification,
635
+ [RuleEvaluationMetric.LexicalOverlap]: RuleEvaluationLexicalOverlapSpecification,
636
+ [RuleEvaluationMetric.SemanticSimilarity]: RuleEvaluationSemanticSimilaritySpecification,
637
+ [RuleEvaluationMetric.NumericSimilarity]: RuleEvaluationNumericSimilaritySpecification,
638
+ },
639
+ };
640
+
641
+ var EvaluationType;
642
+ (function (EvaluationType) {
643
+ EvaluationType["Rule"] = "rule";
644
+ EvaluationType["Llm"] = "llm";
645
+ EvaluationType["Human"] = "human";
646
+ })(EvaluationType || (EvaluationType = {}));
647
+ const EvaluationTypeSchema = z.nativeEnum(EvaluationType);
648
+ const EvaluationMetricSchema = z.union([
649
+ z.nativeEnum(RuleEvaluationMetric),
650
+ z.nativeEnum(LlmEvaluationMetric),
651
+ z.nativeEnum(HumanEvaluationMetric),
652
+ ]);
653
+ const EvaluationConfigurationSchema = z.custom();
654
+ // prettier-ignore
655
+ z.custom();
656
+ // prettier-ignore
657
+ z.custom();
658
+ ({
659
+ [EvaluationType.Rule]: RuleEvaluationSpecification,
660
+ [EvaluationType.Llm]: LlmEvaluationSpecification,
661
+ [EvaluationType.Human]: HumanEvaluationSpecification,
662
+ });
663
+ z.object({
664
+ name: z.string(),
665
+ description: z.string(),
666
+ type: EvaluationTypeSchema,
667
+ metric: EvaluationMetricSchema,
668
+ configuration: EvaluationConfigurationSchema,
669
+ });
670
+ z.object({
671
+ evaluateLiveLogs: z.boolean().nullable().optional(),
672
+ enableSuggestions: z.boolean().nullable().optional(),
673
+ autoApplySuggestions: z.boolean().nullable().optional(),
674
+ });
675
+ Object.values(SegmentSource).filter((source) => source !== SegmentSource.Evaluation && source !== SegmentSource.Experiment);
676
+
677
+ var LegacyChainEventTypes;
678
+ (function (LegacyChainEventTypes) {
679
+ LegacyChainEventTypes["Error"] = "chain-error";
680
+ LegacyChainEventTypes["Step"] = "chain-step";
681
+ LegacyChainEventTypes["Complete"] = "chain-complete";
682
+ LegacyChainEventTypes["StepComplete"] = "chain-step-complete";
683
+ })(LegacyChainEventTypes || (LegacyChainEventTypes = {}));
684
+
685
+ var ChainEventTypes;
686
+ (function (ChainEventTypes) {
687
+ ChainEventTypes["ChainStarted"] = "chain-started";
688
+ ChainEventTypes["StepStarted"] = "step-started";
689
+ ChainEventTypes["ProviderStarted"] = "provider-started";
690
+ ChainEventTypes["ProviderCompleted"] = "provider-completed";
691
+ ChainEventTypes["ToolsStarted"] = "tools-started";
692
+ ChainEventTypes["ToolCompleted"] = "tool-completed";
693
+ ChainEventTypes["StepCompleted"] = "step-completed";
694
+ ChainEventTypes["ChainCompleted"] = "chain-completed";
695
+ ChainEventTypes["ChainError"] = "chain-error";
696
+ ChainEventTypes["ToolsRequested"] = "tools-requested";
697
+ ChainEventTypes["IntegrationWakingUp"] = "integration-waking-up";
698
+ })(ChainEventTypes || (ChainEventTypes = {}));
699
+
700
+ var IntegrationType;
701
+ (function (IntegrationType) {
702
+ IntegrationType["Latitude"] = "latitude";
703
+ IntegrationType["ExternalMCP"] = "custom_mcp";
704
+ IntegrationType["HostedMCP"] = "mcp_server";
705
+ })(IntegrationType || (IntegrationType = {}));
706
+ var HostedIntegrationType;
707
+ (function (HostedIntegrationType) {
708
+ HostedIntegrationType["Stripe"] = "stripe";
709
+ HostedIntegrationType["Slack"] = "slack";
710
+ HostedIntegrationType["Github"] = "github";
711
+ HostedIntegrationType["Notion"] = "notion";
712
+ HostedIntegrationType["Twitter"] = "twitter";
713
+ HostedIntegrationType["Airtable"] = "airtable";
714
+ HostedIntegrationType["Linear"] = "linear";
715
+ HostedIntegrationType["YoutubeCaptions"] = "youtube_captions";
716
+ HostedIntegrationType["Reddit"] = "reddit";
717
+ HostedIntegrationType["Telegram"] = "telegram";
718
+ HostedIntegrationType["Tinybird"] = "tinybird";
719
+ HostedIntegrationType["Perplexity"] = "perplexity";
720
+ HostedIntegrationType["AwsKbRetrieval"] = "aws_kb_retrieval";
721
+ HostedIntegrationType["BraveSearch"] = "brave_search";
722
+ HostedIntegrationType["EverArt"] = "ever_art";
723
+ HostedIntegrationType["Fetch"] = "fetch";
724
+ HostedIntegrationType["GitLab"] = "gitlab";
725
+ HostedIntegrationType["GoogleMaps"] = "google_maps";
726
+ HostedIntegrationType["Sentry"] = "sentry";
727
+ HostedIntegrationType["Puppeteer"] = "puppeteer";
728
+ HostedIntegrationType["Time"] = "time";
729
+ HostedIntegrationType["browserbase"] = "browserbase";
730
+ HostedIntegrationType["Neon"] = "neon";
731
+ HostedIntegrationType["Postgres"] = "postgres";
732
+ HostedIntegrationType["Supabase"] = "supabase";
733
+ HostedIntegrationType["Redis"] = "redis";
734
+ HostedIntegrationType["Jira"] = "jira";
735
+ HostedIntegrationType["Attio"] = "attio";
736
+ HostedIntegrationType["Ghost"] = "ghost";
737
+ HostedIntegrationType["Figma"] = "figma";
738
+ HostedIntegrationType["Hyperbrowser"] = "hyperbrowser";
739
+ HostedIntegrationType["Audiense"] = "audiense";
740
+ HostedIntegrationType["Apify"] = "apify";
741
+ HostedIntegrationType["Exa"] = "exa";
742
+ HostedIntegrationType["YepCode"] = "yepcode";
743
+ HostedIntegrationType["Monday"] = "monday";
744
+ HostedIntegrationType["AgentQL"] = "agentql";
745
+ HostedIntegrationType["AgentRPC"] = "agentrpc";
746
+ HostedIntegrationType["AstraDB"] = "astra_db";
747
+ HostedIntegrationType["Bankless"] = "bankless";
748
+ HostedIntegrationType["Bicscan"] = "bicscan";
749
+ HostedIntegrationType["Chargebee"] = "chargebee";
750
+ HostedIntegrationType["Chronulus"] = "chronulus";
751
+ HostedIntegrationType["CircleCI"] = "circleci";
752
+ HostedIntegrationType["Codacy"] = "codacy";
753
+ HostedIntegrationType["CodeLogic"] = "codelogic";
754
+ HostedIntegrationType["Convex"] = "convex";
755
+ HostedIntegrationType["Dart"] = "dart";
756
+ HostedIntegrationType["DevHubCMS"] = "devhub_cms";
757
+ HostedIntegrationType["Elasticsearch"] = "elasticsearch";
758
+ HostedIntegrationType["ESignatures"] = "esignatures";
759
+ HostedIntegrationType["Fewsats"] = "fewsats";
760
+ HostedIntegrationType["Firecrawl"] = "firecrawl";
761
+ HostedIntegrationType["Graphlit"] = "graphlit";
762
+ HostedIntegrationType["Heroku"] = "heroku";
763
+ HostedIntegrationType["IntegrationAppHubspot"] = "integration_app_hubspot";
764
+ HostedIntegrationType["LaraTranslate"] = "lara_translate";
765
+ HostedIntegrationType["Logfire"] = "logfire";
766
+ HostedIntegrationType["Langfuse"] = "langfuse";
767
+ HostedIntegrationType["LingoSupabase"] = "lingo_supabase";
768
+ HostedIntegrationType["Make"] = "make";
769
+ HostedIntegrationType["Meilisearch"] = "meilisearch";
770
+ HostedIntegrationType["Momento"] = "momento";
771
+ HostedIntegrationType["Neo4jAura"] = "neo4j_aura";
772
+ HostedIntegrationType["Octagon"] = "octagon";
773
+ HostedIntegrationType["Paddle"] = "paddle";
774
+ HostedIntegrationType["PayPal"] = "paypal";
775
+ HostedIntegrationType["Qdrant"] = "qdrant";
776
+ HostedIntegrationType["Raygun"] = "raygun";
777
+ HostedIntegrationType["Rember"] = "rember";
778
+ HostedIntegrationType["Riza"] = "riza";
779
+ HostedIntegrationType["Search1API"] = "search1api";
780
+ HostedIntegrationType["Semgrep"] = "semgrep";
781
+ HostedIntegrationType["Tavily"] = "tavily";
782
+ HostedIntegrationType["Unstructured"] = "unstructured";
783
+ HostedIntegrationType["Vectorize"] = "vectorize";
784
+ HostedIntegrationType["Xero"] = "xero";
785
+ HostedIntegrationType["Readwise"] = "readwise";
786
+ HostedIntegrationType["Airbnb"] = "airbnb";
787
+ HostedIntegrationType["Mintlify"] = "mintlify";
788
+ // Require all auth file :point_down:
789
+ // Gmail = 'google_drive',
790
+ // GoogleCalendar = 'google_drive',
791
+ // GoogleDrive = 'google_drive',
792
+ // GoogleWorkspace = 'google_workspace', // env vars not supported (?)
793
+ // TODO: implement these
794
+ // Wordpress = 'wordpress', // Not on OpenTools
795
+ // Discord = 'discord', // Not on OpenTools
796
+ // Intercom = 'intercom', // Not on OpenTools
797
+ // Hubspot = 'hubspot', // Docker based
798
+ // Loops = 'loops', // Does not exist
799
+ })(HostedIntegrationType || (HostedIntegrationType = {}));
800
+
801
+ // TODO(evalsv2): Remove
802
+ var EvaluationResultableType;
803
+ (function (EvaluationResultableType) {
804
+ EvaluationResultableType["Boolean"] = "evaluation_resultable_booleans";
805
+ EvaluationResultableType["Text"] = "evaluation_resultable_texts";
806
+ EvaluationResultableType["Number"] = "evaluation_resultable_numbers";
807
+ })(EvaluationResultableType || (EvaluationResultableType = {}));
808
+
809
+ var ModifiedDocumentType;
810
+ (function (ModifiedDocumentType) {
811
+ ModifiedDocumentType["Created"] = "created";
812
+ ModifiedDocumentType["Updated"] = "updated";
813
+ ModifiedDocumentType["UpdatedPath"] = "updated_path";
814
+ ModifiedDocumentType["Deleted"] = "deleted";
815
+ })(ModifiedDocumentType || (ModifiedDocumentType = {}));
816
+
817
+ // TODO(tracing): deprecated
818
+ const HEAD_COMMIT = 'live';
819
+ var Providers;
820
+ (function (Providers) {
821
+ Providers["OpenAI"] = "openai";
822
+ Providers["Anthropic"] = "anthropic";
823
+ Providers["Groq"] = "groq";
824
+ Providers["Mistral"] = "mistral";
825
+ Providers["Azure"] = "azure";
826
+ Providers["Google"] = "google";
827
+ Providers["GoogleVertex"] = "google_vertex";
828
+ Providers["AnthropicVertex"] = "anthropic_vertex";
829
+ Providers["Custom"] = "custom";
830
+ Providers["XAI"] = "xai";
831
+ Providers["AmazonBedrock"] = "amazon_bedrock";
832
+ Providers["DeepSeek"] = "deepseek";
833
+ Providers["Perplexity"] = "perplexity";
834
+ })(Providers || (Providers = {}));
835
+ var DocumentType;
836
+ (function (DocumentType) {
837
+ DocumentType["Prompt"] = "prompt";
838
+ DocumentType["Agent"] = "agent";
839
+ })(DocumentType || (DocumentType = {}));
840
+ var DocumentTriggerType;
841
+ (function (DocumentTriggerType) {
842
+ DocumentTriggerType["Email"] = "email";
843
+ DocumentTriggerType["Scheduled"] = "scheduled";
844
+ })(DocumentTriggerType || (DocumentTriggerType = {}));
845
+ var DocumentTriggerParameters;
846
+ (function (DocumentTriggerParameters) {
847
+ DocumentTriggerParameters["SenderEmail"] = "senderEmail";
848
+ DocumentTriggerParameters["SenderName"] = "senderName";
849
+ DocumentTriggerParameters["Subject"] = "subject";
850
+ DocumentTriggerParameters["Body"] = "body";
851
+ DocumentTriggerParameters["Attachments"] = "attachments";
852
+ })(DocumentTriggerParameters || (DocumentTriggerParameters = {}));
853
+
854
+ class ManualInstrumentation {
855
+ enabled;
856
+ source;
857
+ tracer;
858
+ constructor(source, tracer) {
859
+ this.enabled = false;
860
+ this.source = source;
861
+ this.tracer = tracer;
862
+ }
863
+ isEnabled() {
864
+ return this.enabled;
865
+ }
866
+ enable() {
867
+ this.enabled = true;
868
+ }
869
+ disable() {
870
+ this.enabled = false;
871
+ }
872
+ baggage(ctx) {
873
+ if ('traceparent' in ctx) {
874
+ ctx = propagation.extract(otel.ROOT_CONTEXT, ctx);
875
+ }
876
+ const baggage = Object.fromEntries(propagation.getBaggage(ctx)?.getAllEntries() || []);
877
+ if (!(ATTR_LATITUDE_SEGMENT_ID in baggage) ||
878
+ !(ATTR_LATITUDE_SEGMENTS in baggage)) {
879
+ return undefined;
880
+ }
881
+ const segment = {
882
+ id: baggage[ATTR_LATITUDE_SEGMENT_ID].value,
883
+ parentId: baggage[ATTR_LATITUDE_SEGMENT_PARENT_ID]?.value,
26
884
  };
885
+ let segments = [];
886
+ try {
887
+ segments = JSON.parse(baggage[ATTR_LATITUDE_SEGMENTS].value);
888
+ }
889
+ catch (error) {
890
+ return undefined;
891
+ }
892
+ if (segments.length < 1) {
893
+ return undefined;
894
+ }
895
+ return { segment, segments };
27
896
  }
28
- async export(spans, resultCallback) {
29
- await this.send(spans, () => resultCallback({ code: ExportResultCode.SUCCESS }), (error) => {
30
- resultCallback({ code: ExportResultCode.FAILED, error });
897
+ setBaggage(ctx, baggage, extra) {
898
+ let parent = Object.fromEntries(propagation.getBaggage(ctx)?.getAllEntries() || []);
899
+ parent = Object.fromEntries(Object.entries(parent).filter(([attribute]) => attribute !== ATTR_LATITUDE_SEGMENT_ID &&
900
+ attribute !== ATTR_LATITUDE_SEGMENT_PARENT_ID &&
901
+ attribute !== ATTR_LATITUDE_SEGMENTS));
902
+ if (!baggage) {
903
+ const payload = propagation.createBaggage({ ...parent, ...(extra || {}) });
904
+ return propagation.setBaggage(ctx, payload);
905
+ }
906
+ let jsonSegments = '';
907
+ try {
908
+ jsonSegments = JSON.stringify(baggage.segments);
909
+ }
910
+ catch (error) {
911
+ jsonSegments = '[]';
912
+ }
913
+ const payload = propagation.createBaggage({
914
+ ...parent,
915
+ [ATTR_LATITUDE_SEGMENT_ID]: { value: baggage.segment.id },
916
+ ...(baggage.segment.parentId && {
917
+ [ATTR_LATITUDE_SEGMENT_PARENT_ID]: { value: baggage.segment.parentId },
918
+ }),
919
+ [ATTR_LATITUDE_SEGMENTS]: { value: jsonSegments },
920
+ ...(extra || {}),
31
921
  });
922
+ return propagation.setBaggage(ctx, payload);
32
923
  }
33
- async shutdown() {
34
- // No-op
924
+ pause(ctx) {
925
+ const baggage = this.baggage(ctx);
926
+ if (baggage) {
927
+ baggage.segments.at(-1).paused = true;
928
+ }
929
+ ctx = this.setBaggage(ctx, baggage);
930
+ let carrier = {};
931
+ propagation.inject(ctx, carrier);
932
+ return carrier;
933
+ }
934
+ resume(ctx) {
935
+ return propagation.extract(otel.ROOT_CONTEXT, ctx);
936
+ }
937
+ restored(ctx) {
938
+ const baggage = this.baggage(ctx);
939
+ return !baggage?.segments.some((segment) => segment.paused);
940
+ }
941
+ restore(ctx) {
942
+ let baggage = this.baggage(ctx);
943
+ if (!baggage)
944
+ return ctx;
945
+ const segments = baggage.segments;
946
+ while (segments.at(-1)?.paused)
947
+ segments.pop();
948
+ const segment = segments.at(-1);
949
+ if (!segment)
950
+ return otel.ROOT_CONTEXT;
951
+ baggage = {
952
+ segment: { id: segment.id, parentId: segment.parentId },
953
+ segments: segments,
954
+ };
955
+ ctx = this.setBaggage(ctx, baggage);
956
+ let carrier = {};
957
+ propagation.inject(ctx, carrier);
958
+ carrier.traceparent = segment.traceparent;
959
+ carrier.tracestate = segment.tracestate;
960
+ return this.resume(carrier);
961
+ }
962
+ capitalize(str) {
963
+ if (str.length === 0)
964
+ return str;
965
+ return str.charAt(0).toUpperCase() + str.toLowerCase().slice(1);
966
+ }
967
+ toCamelCase(str) {
968
+ return str
969
+ .replace(/([a-z0-9])([A-Z])/g, '$1 $2')
970
+ .replace(/[^A-Za-z0-9]+/g, ' ')
971
+ .trim()
972
+ .split(' ')
973
+ .map((w, i) => (i ? this.capitalize(w) : w.toLowerCase()))
974
+ .join('');
975
+ }
976
+ toSnakeCase(str) {
977
+ return str
978
+ .replace(/([a-z0-9])([A-Z])/g, '$1_$2')
979
+ .replace(/[^A-Za-z0-9]+/g, '_')
980
+ .replace(/_+/g, '_')
981
+ .replace(/^_+|_+$/g, '')
982
+ .toLowerCase();
35
983
  }
36
- async onShutdown() {
37
- // No-op
984
+ toKebabCase(input) {
985
+ return input
986
+ .replace(/([a-z0-9])([A-Z])/g, '$1-$2')
987
+ .replace(/[^A-Za-z0-9]+/g, '-')
988
+ .replace(/-+/g, '-')
989
+ .replace(/^-+|-+$/g, '')
990
+ .toLowerCase();
38
991
  }
39
- async onInit() {
40
- // No-op
992
+ error(span, error, options) {
993
+ options = options || {};
994
+ span.recordException(error);
995
+ span.setAttributes(options.attributes || {});
996
+ span.setStatus({
997
+ code: otel.SpanStatusCode.ERROR,
998
+ message: error.message || undefined,
999
+ });
1000
+ span.end();
41
1001
  }
42
- async send(spans, onSuccess, onError) {
43
- if (spans.length === 0) {
44
- onSuccess();
45
- return;
1002
+ span(ctx, name, type, options) {
1003
+ if (!this.enabled) {
1004
+ return {
1005
+ context: ctx,
1006
+ end: (_options) => { },
1007
+ fail: (_error, _options) => { },
1008
+ };
1009
+ }
1010
+ const start = options || {};
1011
+ let operation = undefined;
1012
+ if (GENAI_SPANS.includes(type)) {
1013
+ operation = type;
46
1014
  }
47
- const serviceRequest = this.convert(spans);
48
- const body = JSON.stringify(serviceRequest);
1015
+ const span = this.tracer.startSpan(name, {
1016
+ attributes: {
1017
+ [ATTR_LATITUDE_TYPE]: type,
1018
+ ...(operation && {
1019
+ [ATTR_GEN_AI_OPERATION_NAME]: operation,
1020
+ }),
1021
+ ...(start.attributes || {}),
1022
+ },
1023
+ kind: otel.SpanKind.CLIENT,
1024
+ }, ctx);
1025
+ const newCtx = trace.setSpan(ctx, span);
1026
+ return {
1027
+ context: newCtx,
1028
+ end: (options) => {
1029
+ const end = options || {};
1030
+ span.setAttributes(end.attributes || {});
1031
+ span.setStatus({ code: otel.SpanStatusCode.OK });
1032
+ span.end();
1033
+ },
1034
+ fail: (error, options) => {
1035
+ this.error(span, error, options);
1036
+ },
1037
+ };
1038
+ }
1039
+ tool(ctx, options) {
1040
+ const start = options;
1041
+ let jsonArguments = '';
49
1042
  try {
50
- const response = await fetch(this.url, {
51
- method: 'POST',
52
- headers: {
53
- 'Content-Type': 'application/json',
54
- ...this.headers,
55
- },
56
- body,
57
- });
58
- if (!response.ok || response.status >= 400) {
59
- throw new Error(`${response.status} ${response.statusText}`);
1043
+ jsonArguments = JSON.stringify(start.call.arguments);
1044
+ }
1045
+ catch (error) {
1046
+ jsonArguments = '{}';
1047
+ }
1048
+ const span = this.span(ctx, start.name, SpanType.Tool, {
1049
+ attributes: {
1050
+ [ATTR_GEN_AI_TOOL_NAME]: start.name,
1051
+ [ATTR_GEN_AI_TOOL_TYPE]: GEN_AI_TOOL_TYPE_VALUE_FUNCTION,
1052
+ [ATTR_GEN_AI_TOOL_CALL_ID]: start.call.id,
1053
+ [ATTR_GEN_AI_TOOL_CALL_ARGUMENTS]: jsonArguments,
1054
+ ...(start.attributes || {}),
1055
+ },
1056
+ });
1057
+ return {
1058
+ context: span.context,
1059
+ end: (options) => {
1060
+ const end = options;
1061
+ let stringResult = '';
1062
+ if (typeof end.result.value !== 'string') {
1063
+ try {
1064
+ stringResult = JSON.stringify(end.result.value);
1065
+ }
1066
+ catch (error) {
1067
+ stringResult = '{}';
1068
+ }
1069
+ }
1070
+ else {
1071
+ stringResult = end.result.value;
1072
+ }
1073
+ span.end({
1074
+ attributes: {
1075
+ [ATTR_GEN_AI_TOOL_RESULT_VALUE]: stringResult,
1076
+ [ATTR_GEN_AI_TOOL_RESULT_IS_ERROR]: end.result.isError,
1077
+ ...(end.attributes || {}),
1078
+ },
1079
+ });
1080
+ },
1081
+ fail: span.fail,
1082
+ };
1083
+ }
1084
+ attribifyMessageToolCalls(prefix, toolCalls) {
1085
+ const attributes = {};
1086
+ for (let i = 0; i < toolCalls.length; i++) {
1087
+ for (const key in toolCalls[i]) {
1088
+ const field = this.toCamelCase(key);
1089
+ let value = toolCalls[i][key];
1090
+ if (value === null || value === undefined)
1091
+ continue;
1092
+ switch (field) {
1093
+ case 'id':
1094
+ case 'toolCallId':
1095
+ case 'toolUseId': {
1096
+ if (typeof value !== 'string')
1097
+ continue;
1098
+ attributes[`${prefix}.${ATTR_GEN_AI_MESSAGE_TOOL_CALLS}.${i}.${ATTR_GEN_AI_MESSAGE_TOOL_CALLS_ID}`] = value;
1099
+ break;
1100
+ }
1101
+ case 'name':
1102
+ case 'toolName': {
1103
+ if (typeof value !== 'string')
1104
+ continue;
1105
+ attributes[`${prefix}.${ATTR_GEN_AI_MESSAGE_TOOL_CALLS}.${i}.${ATTR_GEN_AI_MESSAGE_TOOL_CALLS_NAME}`] = value;
1106
+ break;
1107
+ }
1108
+ case 'arguments':
1109
+ case 'toolArguments':
1110
+ case 'input': {
1111
+ if (typeof value === 'string') {
1112
+ attributes[`${prefix}.${ATTR_GEN_AI_MESSAGE_TOOL_CALLS}.${i}.${ATTR_GEN_AI_MESSAGE_TOOL_CALLS_ARGUMENTS}`] = value;
1113
+ }
1114
+ else {
1115
+ try {
1116
+ attributes[`${prefix}.${ATTR_GEN_AI_MESSAGE_TOOL_CALLS}.${i}.${ATTR_GEN_AI_MESSAGE_TOOL_CALLS_ARGUMENTS}`] = JSON.stringify(value);
1117
+ }
1118
+ catch (error) {
1119
+ attributes[`${prefix}.${ATTR_GEN_AI_MESSAGE_TOOL_CALLS}.${i}.${ATTR_GEN_AI_MESSAGE_TOOL_CALLS_ARGUMENTS}`] = '{}';
1120
+ }
1121
+ }
1122
+ break;
1123
+ }
1124
+ /* OpenAI function calls */
1125
+ case 'function': {
1126
+ if (typeof value !== 'object')
1127
+ continue;
1128
+ if (!('name' in value))
1129
+ continue;
1130
+ if (typeof value.name !== 'string')
1131
+ continue;
1132
+ if (!('arguments' in value))
1133
+ continue;
1134
+ if (typeof value.arguments !== 'string')
1135
+ continue;
1136
+ attributes[`${prefix}.${ATTR_GEN_AI_MESSAGE_TOOL_CALLS}.${i}.${ATTR_GEN_AI_MESSAGE_TOOL_CALLS_NAME}`] = value.name;
1137
+ attributes[`${prefix}.${ATTR_GEN_AI_MESSAGE_TOOL_CALLS}.${i}.${ATTR_GEN_AI_MESSAGE_TOOL_CALLS_ARGUMENTS}`] = value.arguments;
1138
+ break;
1139
+ }
1140
+ }
60
1141
  }
61
- onSuccess();
1142
+ }
1143
+ return attributes;
1144
+ }
1145
+ attribifyMessageContent(prefix, content) {
1146
+ let attributes = {};
1147
+ if (typeof content === 'string') {
1148
+ attributes[`${prefix}.${ATTR_GEN_AI_MESSAGE_CONTENT}`] = content;
1149
+ return attributes;
1150
+ }
1151
+ try {
1152
+ attributes[`${prefix}.${ATTR_GEN_AI_MESSAGE_CONTENT}`] =
1153
+ JSON.stringify(content);
62
1154
  }
63
1155
  catch (error) {
64
- onError(error);
1156
+ attributes[`${prefix}.${ATTR_GEN_AI_MESSAGE_CONTENT}`] = '[]';
1157
+ }
1158
+ if (!Array.isArray(content))
1159
+ return attributes;
1160
+ /* Tool calls for Anthropic and PromptL are in the content */
1161
+ const toolCalls = [];
1162
+ for (const item of content) {
1163
+ for (const key in item) {
1164
+ if (this.toCamelCase(key) !== 'type')
1165
+ continue;
1166
+ if (typeof item[key] !== 'string')
1167
+ continue;
1168
+ if (item[key] !== 'tool-call' && item[key] !== 'tool_use')
1169
+ continue;
1170
+ toolCalls.push(item);
1171
+ }
1172
+ }
1173
+ if (toolCalls.length > 0) {
1174
+ attributes = {
1175
+ ...attributes,
1176
+ ...this.attribifyMessageToolCalls(prefix, toolCalls),
1177
+ };
1178
+ }
1179
+ return attributes;
1180
+ }
1181
+ attribifyMessages(direction, messages) {
1182
+ const prefix = direction === 'input' ? ATTR_GEN_AI_PROMPTS : ATTR_GEN_AI_COMPLETIONS;
1183
+ let attributes = {};
1184
+ for (let i = 0; i < messages.length; i++) {
1185
+ for (const key in messages[i]) {
1186
+ const field = this.toCamelCase(key);
1187
+ let value = messages[i][key];
1188
+ if (value === null || value === undefined)
1189
+ continue;
1190
+ switch (field) {
1191
+ case 'role': {
1192
+ if (typeof value !== 'string')
1193
+ continue;
1194
+ attributes[`${prefix}.${i}.${ATTR_GEN_AI_MESSAGE_ROLE}`] = value;
1195
+ break;
1196
+ }
1197
+ /* Tool calls for Anthropic and PromptL are in the content */
1198
+ case 'content': {
1199
+ attributes = {
1200
+ ...attributes,
1201
+ ...this.attribifyMessageContent(`${prefix}.${i}`, value),
1202
+ };
1203
+ break;
1204
+ }
1205
+ /* Tool calls for OpenAI */
1206
+ case 'toolCalls': {
1207
+ if (!Array.isArray(value))
1208
+ continue;
1209
+ attributes = {
1210
+ ...attributes,
1211
+ ...this.attribifyMessageToolCalls(`${prefix}.${i}`, value),
1212
+ };
1213
+ break;
1214
+ }
1215
+ /* Tool result for OpenAI / Anthropic / PromptL */
1216
+ case 'toolCallId':
1217
+ case 'toolId':
1218
+ case 'toolUseId': {
1219
+ if (typeof value !== 'string')
1220
+ continue;
1221
+ attributes[`${prefix}.${i}.${ATTR_GEN_AI_MESSAGE_TOOL_CALL_ID}`] =
1222
+ value;
1223
+ break;
1224
+ }
1225
+ case 'toolName': {
1226
+ if (typeof value !== 'string')
1227
+ continue;
1228
+ attributes[`${prefix}.${i}.${ATTR_GEN_AI_MESSAGE_TOOL_NAME}`] =
1229
+ value;
1230
+ break;
1231
+ }
1232
+ // Note: 'toolResult' is 'content' itself
1233
+ case 'isError': {
1234
+ if (typeof value !== 'boolean')
1235
+ continue;
1236
+ attributes[`${prefix}.${i}.${ATTR_GEN_AI_MESSAGE_TOOL_RESULT_IS_ERROR}`] = value;
1237
+ break;
1238
+ }
1239
+ }
1240
+ }
65
1241
  }
1242
+ return attributes;
66
1243
  }
67
- convert(spans) {
1244
+ attribifyConfiguration(direction, configuration) {
1245
+ const prefix = direction === 'input' ? ATTR_GEN_AI_REQUEST : ATTR_GEN_AI_RESPONSE;
1246
+ const attributes = {};
1247
+ for (const key in configuration) {
1248
+ const field = this.toSnakeCase(key);
1249
+ let value = configuration[key];
1250
+ if (value === null || value === undefined)
1251
+ continue;
1252
+ if (typeof value === 'object' && !Array.isArray(value)) {
1253
+ try {
1254
+ value = JSON.stringify(value);
1255
+ }
1256
+ catch (error) {
1257
+ value = '{}';
1258
+ }
1259
+ }
1260
+ attributes[`${prefix}.${field}`] = value;
1261
+ }
1262
+ return attributes;
1263
+ }
1264
+ completion(ctx, options) {
1265
+ const start = options;
1266
+ const configuration = {
1267
+ ...start.configuration,
1268
+ model: start.model,
1269
+ };
1270
+ let jsonConfiguration = '';
1271
+ try {
1272
+ jsonConfiguration = JSON.stringify(configuration);
1273
+ }
1274
+ catch (error) {
1275
+ jsonConfiguration = '{}';
1276
+ }
1277
+ const attrConfiguration = this.attribifyConfiguration('input', configuration);
1278
+ let jsonInput = '';
1279
+ try {
1280
+ jsonInput = JSON.stringify(start.input);
1281
+ }
1282
+ catch (error) {
1283
+ jsonInput = '[]';
1284
+ }
1285
+ const attrInput = this.attribifyMessages('input', start.input);
1286
+ const span = this.span(ctx, start.name || `${start.provider} / ${start.model}`, SpanType.Completion, {
1287
+ attributes: {
1288
+ [ATTR_GEN_AI_SYSTEM]: start.provider,
1289
+ [ATTR_GEN_AI_REQUEST_CONFIGURATION]: jsonConfiguration,
1290
+ ...attrConfiguration,
1291
+ [ATTR_GEN_AI_REQUEST_MESSAGES]: jsonInput,
1292
+ ...attrInput,
1293
+ ...(start.attributes || {}),
1294
+ },
1295
+ });
68
1296
  return {
69
- resourceSpans: [
70
- {
71
- resource: {
72
- attributes: this.convertAttributes(spans[0]?.resource?.attributes || {}),
1297
+ context: span.context,
1298
+ end: (options) => {
1299
+ const end = options;
1300
+ let jsonOutput = '';
1301
+ try {
1302
+ jsonOutput = JSON.stringify(end.output);
1303
+ }
1304
+ catch (error) {
1305
+ jsonOutput = '[]';
1306
+ }
1307
+ const attrOutput = this.attribifyMessages('output', end.output);
1308
+ const inputTokens = end.tokens.prompt + end.tokens.cached;
1309
+ const outputTokens = end.tokens.reasoning + end.tokens.completion;
1310
+ span.end({
1311
+ attributes: {
1312
+ [ATTR_GEN_AI_RESPONSE_MESSAGES]: jsonOutput,
1313
+ ...attrOutput,
1314
+ [ATTR_GEN_AI_USAGE_INPUT_TOKENS]: inputTokens,
1315
+ [ATTR_GEN_AI_USAGE_PROMPT_TOKENS]: end.tokens.prompt,
1316
+ [ATTR_GEN_AI_USAGE_CACHED_TOKENS]: end.tokens.cached,
1317
+ [ATTR_GEN_AI_USAGE_REASONING_TOKENS]: end.tokens.reasoning,
1318
+ [ATTR_GEN_AI_USAGE_COMPLETION_TOKENS]: end.tokens.completion,
1319
+ [ATTR_GEN_AI_USAGE_OUTPUT_TOKENS]: outputTokens,
1320
+ [ATTR_GEN_AI_RESPONSE_MODEL]: start.model,
1321
+ [ATTR_GEN_AI_RESPONSE_FINISH_REASONS]: [end.finishReason],
1322
+ ...(end.attributes || {}),
73
1323
  },
74
- scopeSpans: [
75
- {
76
- spans: spans.map((span) => ({
77
- traceId: span.spanContext().traceId,
78
- spanId: span.spanContext().spanId,
79
- parentSpanId: span.parentSpanId,
80
- name: span.name,
81
- kind: span.kind,
82
- startTimeUnixNano: hrTimeToNanoseconds(span.startTime).toString(),
83
- endTimeUnixNano: span.endTime
84
- ? hrTimeToNanoseconds(span.endTime).toString()
85
- : undefined,
86
- attributes: this.convertAttributes(span.attributes),
87
- status: span.status && {
88
- code: span.status.code,
89
- message: span.status.message,
90
- },
91
- events: span.events?.map((event) => ({
92
- timeUnixNano: hrTimeToNanoseconds(event.time).toString(),
93
- name: event.name,
94
- attributes: this.convertAttributes(event.attributes),
95
- })),
96
- links: span.links?.map((link) => ({
97
- traceId: link.context.traceId,
98
- spanId: link.context.spanId,
99
- attributes: this.convertAttributes(link.attributes),
100
- })),
101
- })),
102
- },
103
- ],
104
- },
105
- ],
1324
+ });
1325
+ },
1326
+ fail: span.fail,
106
1327
  };
107
1328
  }
108
- getDefaultUrl(config) {
109
- return config.endpoint || this.__defaultUrl;
1329
+ embedding(ctx, options) {
1330
+ return this.span(ctx, options?.name || 'Embedding', SpanType.Embedding, options);
110
1331
  }
111
- get __defaultUrl() {
112
- return `${PROTOCOL}://${DOMAIN}/v1/traces`;
1332
+ retrieval(ctx, options) {
1333
+ return this.span(ctx, options?.name || 'Retrieval', SpanType.Retrieval, options);
113
1334
  }
114
- convertAttributes(attributes = {}) {
115
- return Object.entries(attributes).map(([key, value]) => ({
116
- key,
117
- value: this.convertAttributeValue(value),
118
- }));
1335
+ reranking(ctx, options) {
1336
+ return this.span(ctx, options?.name || 'Reranking', SpanType.Reranking, options);
119
1337
  }
120
- convertAttributeValue(value) {
121
- if (typeof value === 'string')
122
- return { stringValue: value };
123
- if (typeof value === 'number')
124
- return { intValue: value };
125
- if (typeof value === 'boolean')
126
- return { boolValue: value };
127
- return { stringValue: String(value) };
1338
+ attribifyHeaders(direction, headers) {
1339
+ const prefix = direction === 'request'
1340
+ ? ATTR_HTTP_REQUEST_HEADERS
1341
+ : ATTR_HTTP_RESPONSE_HEADERS;
1342
+ const attributes = {};
1343
+ for (const key in headers) {
1344
+ const field = this.toKebabCase(key);
1345
+ const value = headers[key];
1346
+ if (value === null || value === undefined)
1347
+ continue;
1348
+ attributes[`${prefix}.${field}`] = value;
1349
+ }
1350
+ return attributes;
128
1351
  }
129
- }
130
-
131
- /**
132
- * Below are the semantic conventions for the Vercel AI SDK.
133
- * @see https://sdk.vercel.ai/docs/ai-sdk-core/telemetry#collected-data
134
- */
135
- const AI_PREFIX = 'ai';
136
- const AIPrefixes = {
137
- settings: 'settings',
138
- model: 'model',
139
- usage: 'usage',
140
- telemetry: 'telemetry',
141
- prompt: 'prompt',
142
- toolCall: 'toolCall',
143
- response: 'response',
144
- };
145
- const AIUsagePostfixes = {
146
- completionTokens: 'completionTokens',
147
- promptTokens: 'promptTokens',
148
- };
149
- const AIResultPostfixes = {
150
- text: 'text',
151
- toolCalls: 'toolCalls',
152
- object: 'object',
153
- };
154
- const AIPromptPostfixes = {
155
- messages: 'messages',
156
- };
157
- const AIToolCallPostfixes = {
158
- id: 'id',
159
- name: 'name',
160
- args: 'args',
161
- result: 'result',
162
- };
163
- const SETTINGS = `${AI_PREFIX}.${AIPrefixes.settings}`;
164
- const MODEL_ID = `${AI_PREFIX}.${AIPrefixes.model}.id`;
165
- const METADATA = `${AI_PREFIX}.${AIPrefixes.telemetry}.metadata`;
166
- const TOKEN_COUNT_COMPLETION = `${AI_PREFIX}.${AIPrefixes.usage}.${AIUsagePostfixes.completionTokens}`;
167
- const TOKEN_COUNT_PROMPT = `${AI_PREFIX}.${AIPrefixes.usage}.${AIUsagePostfixes.promptTokens}`;
168
- const RESPONSE_TEXT = `${AI_PREFIX}.${AIPrefixes.response}.${AIResultPostfixes.text}`;
169
- const RESPONSE_TOOL_CALLS = `${AI_PREFIX}.${AIPrefixes.response}.${AIResultPostfixes.toolCalls}`;
170
- const RESULT_OBJECT = `${AI_PREFIX}.${AIPrefixes.response}.${AIResultPostfixes.object}`;
171
- const PROMPT = `${AI_PREFIX}.${AIPrefixes.prompt}`;
172
- const PROMPT_MESSAGES = `${PROMPT}.${AIPromptPostfixes.messages}`;
173
- const EMBEDDING_TEXT = `${AI_PREFIX}.value`;
174
- const EMBEDDING_VECTOR = `${AI_PREFIX}.embedding`;
175
- const EMBEDDING_TEXTS = `${AI_PREFIX}.values`;
176
- const EMBEDDING_VECTORS = `${AI_PREFIX}.embeddings`;
177
- const TOOL_CALL_ID = `${AI_PREFIX}.${AIPrefixes.toolCall}.${AIToolCallPostfixes.id}`;
178
- const TOOL_CALL_NAME = `${AI_PREFIX}.${AIPrefixes.toolCall}.${AIToolCallPostfixes.name}`;
179
- const TOOL_CALL_ARGS = `${AI_PREFIX}.${AIPrefixes.toolCall}.${AIToolCallPostfixes.args}`;
180
- const TOOL_CALL_RESULT = `${AI_PREFIX}.${AIPrefixes.toolCall}.${AIToolCallPostfixes.result}`;
181
- /**
182
- * The semantic conventions used by the Vercel AI SDK.
183
- * @see https://sdk.vercel.ai/docs/ai-sdk-core/telemetry#collected-data
184
- */
185
- const AISemanticConventions = {
186
- MODEL_ID,
187
- METADATA,
188
- SETTINGS,
189
- TOKEN_COUNT_COMPLETION,
190
- TOKEN_COUNT_PROMPT,
191
- RESPONSE_TEXT,
192
- RESPONSE_TOOL_CALLS,
193
- RESULT_OBJECT,
194
- PROMPT,
195
- PROMPT_MESSAGES,
196
- EMBEDDING_TEXT,
197
- EMBEDDING_VECTOR,
198
- EMBEDDING_TEXTS,
199
- EMBEDDING_VECTORS,
200
- TOOL_CALL_ID,
201
- TOOL_CALL_NAME,
202
- TOOL_CALL_ARGS,
203
- TOOL_CALL_RESULT,
204
- };
205
- Object.freeze(Object.values(AISemanticConventions));
206
-
207
- class VercelSpanProcessor extends SimpleSpanProcessor {
208
- onEnd(span) {
209
- if (!shouldProcess(span))
210
- return;
211
- if (shouldConvertToLatitudeFormat(span))
212
- convertToLatitudeFormat(span);
213
- super.onEnd(span);
1352
+ http(ctx, options) {
1353
+ const start = options;
1354
+ const method = start.request.method.toUpperCase();
1355
+ const attrHeaders = this.attribifyHeaders('request', start.request.headers);
1356
+ let finalBody = '';
1357
+ if (typeof start.request.body === 'string') {
1358
+ finalBody = start.request.body;
1359
+ }
1360
+ else {
1361
+ try {
1362
+ finalBody = JSON.stringify(start.request.body);
1363
+ }
1364
+ catch (error) {
1365
+ finalBody = '{}';
1366
+ }
1367
+ }
1368
+ const span = this.span(ctx, start.name || `${method} ${start.request.url}`, SpanType.Http, {
1369
+ attributes: {
1370
+ [ATTR_HTTP_REQUEST_METHOD]: method,
1371
+ [ATTR_HTTP_REQUEST_URL]: start.request.url,
1372
+ ...attrHeaders,
1373
+ [ATTR_HTTP_REQUEST_BODY]: finalBody,
1374
+ ...(start.attributes || {}),
1375
+ },
1376
+ });
1377
+ return {
1378
+ context: span.context,
1379
+ end: (options) => {
1380
+ const end = options;
1381
+ const attrHeaders = this.attribifyHeaders('response', end.response.headers);
1382
+ let finalBody = '';
1383
+ if (typeof end.response.body === 'string') {
1384
+ finalBody = end.response.body;
1385
+ }
1386
+ else {
1387
+ try {
1388
+ finalBody = JSON.stringify(end.response.body);
1389
+ }
1390
+ catch (error) {
1391
+ finalBody = '{}';
1392
+ }
1393
+ }
1394
+ span.end({
1395
+ attributes: {
1396
+ [ATTR_HTTP_RESPONSE_STATUS_CODE]: end.response.status,
1397
+ ...attrHeaders,
1398
+ [ATTR_HTTP_RESPONSE_BODY]: finalBody,
1399
+ ...(end.attributes || {}),
1400
+ },
1401
+ });
1402
+ },
1403
+ fail: span.fail,
1404
+ };
214
1405
  }
215
- }
216
- class VercelBatchSpanProcessor extends BatchSpanProcessor {
217
- onEnd(span) {
218
- if (!shouldProcess(span))
219
- return;
220
- if (shouldConvertToLatitudeFormat(span))
221
- convertToLatitudeFormat(span);
222
- super.onEnd(span);
1406
+ segment(ctx, type, data, options) {
1407
+ options = options || {};
1408
+ let baggage = this.baggage(ctx);
1409
+ const parent = baggage?.segments.at(-1);
1410
+ const segments = baggage?.segments || [];
1411
+ segments.push({
1412
+ ...{
1413
+ id: options._internal?.id || v4(),
1414
+ ...(parent?.id && { parentId: parent.id }),
1415
+ source: options._internal?.source || parent?.source || this.source,
1416
+ type: type,
1417
+ data: data,
1418
+ },
1419
+ traceparent: 'undefined',
1420
+ tracestate: undefined,
1421
+ });
1422
+ const segment = segments.at(-1);
1423
+ baggage = {
1424
+ segment: { id: segment.id, parentId: segment.parentId },
1425
+ segments: segments,
1426
+ };
1427
+ ctx = this.setBaggage(ctx, baggage, options.baggage);
1428
+ // Dummy wrapper to force the same trace and carry on some segment attributes
1429
+ const span = this.span(ctx, type, SpanType.Segment, {
1430
+ attributes: options.attributes,
1431
+ });
1432
+ let carrier = {};
1433
+ propagation.inject(span.context, carrier);
1434
+ baggage.segments.at(-1).traceparent = carrier.traceparent;
1435
+ baggage.segments.at(-1).tracestate = carrier.tracestate;
1436
+ // Fix current segment span segments attribute now that we know the trace
1437
+ trace
1438
+ .getSpan(span.context)
1439
+ .setAttribute(ATTR_LATITUDE_SEGMENTS, JSON.stringify(baggage.segments));
1440
+ ctx = this.setBaggage(span.context, baggage, options.baggage);
1441
+ return { context: ctx, end: span.end, fail: span.fail };
223
1442
  }
224
- }
225
- function shouldProcess(span) {
226
- return (Object.keys(span.attributes).some((k) => k.startsWith('latitude.')) ||
227
- Object.keys(span.attributes).some((k) => k.startsWith('ai.')));
228
- }
229
- function shouldConvertToLatitudeFormat(span) {
230
- return Object.keys(span.attributes).some((k) => k.startsWith('ai.'));
231
- }
232
- function convertToLatitudeFormat(span) {
233
- try {
234
- const computedAttrs = computeOpenLLMAttributes(span);
235
- if (computedAttrs) {
236
- ;
237
- span.attributes = {
238
- ...span.attributes,
239
- ...computedAttrs,
240
- };
1443
+ prompt(ctx, { logUuid, versionUuid, promptUuid, experimentUuid, externalId, template, parameters, ...rest }) {
1444
+ const baggage = {
1445
+ ...(logUuid && { logUuid }), // TODO(tracing): temporal related log, remove when observability is ready
1446
+ commitUuid: versionUuid || HEAD_COMMIT,
1447
+ documentUuid: promptUuid,
1448
+ ...(experimentUuid && { experimentUuid }),
1449
+ ...(externalId && { externalId }),
1450
+ };
1451
+ let jsonParameters = '';
1452
+ try {
1453
+ jsonParameters = JSON.stringify(parameters || {});
241
1454
  }
1455
+ catch (error) {
1456
+ jsonParameters = '{}';
1457
+ }
1458
+ const attributes = {
1459
+ [ATTR_GEN_AI_REQUEST_TEMPLATE]: template,
1460
+ [ATTR_GEN_AI_REQUEST_PARAMETERS]: jsonParameters,
1461
+ ...(rest.attributes || {}),
1462
+ };
1463
+ return this.segment(ctx, SegmentType.Document, baggage, {
1464
+ ...rest,
1465
+ attributes,
1466
+ });
242
1467
  }
243
- catch (e) {
244
- console.log('Latitude telemetry Error: ', e);
245
- // do nothing
1468
+ step(ctx, options) {
1469
+ return this.segment(ctx, SegmentType.Step, undefined, options);
246
1470
  }
247
1471
  }
248
- function computeOpenLLMAttributes(span) {
249
- const attrs = span.attributes || {};
250
- const result = {};
251
- // Extract model information
252
- if (attrs[AISemanticConventions.MODEL_ID]) {
253
- result['gen_ai.request.model'] = String(attrs[AISemanticConventions.MODEL_ID]);
254
- result['gen_ai.response.model'] = String(attrs[AISemanticConventions.MODEL_ID]);
255
- }
256
- // Extract settings
257
- try {
258
- const settings = attrs[AISemanticConventions.SETTINGS]
259
- ? JSON.parse(String(attrs[AISemanticConventions.SETTINGS]))
260
- : {};
261
- if (settings) {
262
- // Add max tokens if present
263
- if (settings.maxTokens) {
264
- result['gen_ai.request.max_tokens'] = settings.maxTokens;
1472
+
1473
+ class LatitudeInstrumentation {
1474
+ options;
1475
+ telemetry;
1476
+ constructor(source, tracer, options) {
1477
+ this.telemetry = new ManualInstrumentation(source, tracer);
1478
+ this.options = options;
1479
+ }
1480
+ isEnabled() {
1481
+ return this.telemetry.isEnabled();
1482
+ }
1483
+ enable() {
1484
+ this.options.module.instrument(this);
1485
+ this.telemetry.enable();
1486
+ }
1487
+ disable() {
1488
+ this.telemetry.disable();
1489
+ this.options.module.uninstrument();
1490
+ }
1491
+ countTokens(messages) {
1492
+ let length = 0;
1493
+ for (const message of messages) {
1494
+ if (!('content' in message))
1495
+ continue;
1496
+ if (typeof message.content === 'string') {
1497
+ length += message.content.length;
265
1498
  }
266
- if (!attrs['gen_ai.system'] && settings.provider) {
267
- result['gen_ai.system'] = String(settings.provider);
1499
+ else if (Array.isArray(message.content)) {
1500
+ for (const content of message.content) {
1501
+ if (content.type === 'text') {
1502
+ length += content.text.length;
1503
+ }
1504
+ }
268
1505
  }
269
1506
  }
1507
+ // Note: this is an estimation to not bundle a tokenizer
1508
+ return Math.ceil(length / 4);
1509
+ }
1510
+ withTraceContext(ctx, fn) {
1511
+ return context.with(this.telemetry.resume(ctx), fn);
270
1512
  }
271
- catch (e) {
272
- console.error('Error parsing settings', e);
273
- }
274
- // Set request type to chat as that's what Vercel AI SDK uses
275
- result['llm.request.type'] = 'chat';
276
- // Extract messages
277
- try {
278
- const messages = attrs['ai.prompt.messages']
279
- ? JSON.parse(String(attrs['ai.prompt.messages']))
280
- : [];
281
- // Process prompt messages
282
- messages.forEach((msg, index) => {
283
- result[`gen_ai.prompt.${index}.role`] = msg.role;
284
- result[`gen_ai.prompt.${index}.content`] =
285
- typeof msg.content === 'string'
286
- ? msg.content
287
- : JSON.stringify(msg.content);
1513
+ async wrapToolHandler(fn, ...args) {
1514
+ const toolArguments = args[0];
1515
+ const { toolId, toolName } = args[1];
1516
+ const $tool = this.telemetry.tool(context.active(), {
1517
+ name: toolName,
1518
+ call: {
1519
+ id: toolId,
1520
+ arguments: toolArguments,
1521
+ },
288
1522
  });
1523
+ let result;
1524
+ try {
1525
+ result = await context.with($tool.context, async () => await fn(...args));
1526
+ }
1527
+ catch (error) {
1528
+ if (error.name === 'ToolExecutionPausedError') {
1529
+ $tool.fail(error);
1530
+ throw error;
1531
+ }
1532
+ $tool.end({
1533
+ result: {
1534
+ value: error.message,
1535
+ isError: true,
1536
+ },
1537
+ });
1538
+ throw error;
1539
+ }
1540
+ $tool.end({
1541
+ result: {
1542
+ value: result,
1543
+ isError: false,
1544
+ },
1545
+ });
1546
+ return result;
289
1547
  }
290
- catch (e) {
291
- console.error('Error parsing messages', e);
292
- return undefined;
1548
+ async wrapRenderChain(fn, ...args) {
1549
+ const { prompt, parameters } = args[0];
1550
+ const $prompt = this.telemetry.prompt(context.active(), {
1551
+ versionUuid: prompt.versionUuid,
1552
+ promptUuid: prompt.uuid,
1553
+ template: prompt.content,
1554
+ parameters: parameters,
1555
+ });
1556
+ let result;
1557
+ try {
1558
+ result = await context.with($prompt.context, async () => await fn(...args));
1559
+ }
1560
+ catch (error) {
1561
+ $prompt.fail(error);
1562
+ throw error;
1563
+ }
1564
+ $prompt.end();
1565
+ return result;
293
1566
  }
294
- // Extract completion/response
295
- const responseText = attrs['ai.response.text'];
296
- const responseObject = attrs['ai.response.object'];
297
- const responseToolCalls = attrs['ai.response.toolCalls'];
298
- if (responseText) {
299
- result[`gen_ai.completion.0.role`] = 'assistant';
300
- result[`gen_ai.completion.0.content`] = String(responseText);
1567
+ async wrapRenderAgent(fn, ...args) {
1568
+ const { prompt, parameters } = args[0];
1569
+ const $prompt = this.telemetry.prompt(context.active(), {
1570
+ versionUuid: prompt.versionUuid,
1571
+ promptUuid: prompt.uuid,
1572
+ template: prompt.content,
1573
+ parameters: parameters,
1574
+ });
1575
+ let result;
1576
+ try {
1577
+ result = await context.with($prompt.context, async () => await fn(...args));
1578
+ }
1579
+ catch (error) {
1580
+ $prompt.fail(error);
1581
+ throw error;
1582
+ }
1583
+ $prompt.end();
1584
+ return result;
301
1585
  }
302
- else if (responseToolCalls) {
1586
+ async wrapRenderStep(fn, ...args) {
1587
+ const $step = this.telemetry.step(context.active());
1588
+ let result;
303
1589
  try {
304
- const toolCalls = JSON.parse(String(responseToolCalls));
305
- if (toolCalls.length > 0) {
306
- result['gen_ai.completion.0.finish_reason'] = 'tool_calls';
307
- result[`gen_ai.completion.0.role`] = 'assistant';
308
- toolCalls.forEach((toolCall, toolCallIndex) => {
309
- result[`gen_ai.completion.0.tool_calls.${toolCallIndex}.id`] =
310
- toolCall.toolCallId;
311
- result[`gen_ai.completion.0.tool_calls.${toolCallIndex}.name`] =
312
- toolCall.toolName;
313
- result[`gen_ai.completion.0.tool_calls.${toolCallIndex}.arguments`] =
314
- toolCall.args;
315
- });
316
- }
1590
+ result = await context.with($step.context, async () => await fn(...args));
317
1591
  }
318
- catch (e) {
319
- console.error('Error parsing tool calls', e);
1592
+ catch (error) {
1593
+ $step.fail(error);
1594
+ throw error;
320
1595
  }
1596
+ $step.end();
1597
+ return result;
321
1598
  }
322
- else if (responseObject) {
323
- result['gen_ai.completion.0.role'] = 'assistant';
324
- result['gen_ai.completion.0.content'] = String(responseObject);
1599
+ async wrapRenderCompletion(fn, ...args) {
1600
+ if (!this.options.completions) {
1601
+ return await fn(...args);
1602
+ }
1603
+ const { provider, config, messages } = args[0];
1604
+ const model = config.model || 'unknown';
1605
+ const $completion = this.telemetry.completion(context.active(), {
1606
+ name: `${provider} / ${model}`,
1607
+ provider: provider,
1608
+ model: model,
1609
+ configuration: config,
1610
+ input: messages,
1611
+ });
1612
+ let result;
1613
+ try {
1614
+ result = await context.with($completion.context, async () => await fn(...args));
1615
+ }
1616
+ catch (error) {
1617
+ $completion.fail(error);
1618
+ throw error;
1619
+ }
1620
+ // Note: enhance, this is just an estimation
1621
+ const promptTokens = this.countTokens(messages);
1622
+ const completionTokens = this.countTokens(result.messages);
1623
+ $completion.end({
1624
+ output: result.messages,
1625
+ tokens: {
1626
+ prompt: promptTokens,
1627
+ cached: 0,
1628
+ reasoning: 0,
1629
+ completion: completionTokens,
1630
+ },
1631
+ finishReason: result.toolRequests.length > 0
1632
+ ? GEN_AI_RESPONSE_FINISH_REASON_VALUE_TOOL_CALLS
1633
+ : GEN_AI_RESPONSE_FINISH_REASON_VALUE_STOP,
1634
+ });
1635
+ return result;
325
1636
  }
326
- // Extract token usage
327
- const completionTokens = attrs['ai.usage.completionTokens'];
328
- const promptTokens = attrs['ai.usage.promptTokens'];
329
- if (typeof completionTokens === 'number') {
330
- result['gen_ai.usage.completion_tokens'] = completionTokens;
1637
+ async wrapRenderTool(fn, ...args) {
1638
+ const { toolRequest } = args[0];
1639
+ const $tool = this.telemetry.tool(context.active(), {
1640
+ name: toolRequest.toolName,
1641
+ call: {
1642
+ id: toolRequest.toolCallId,
1643
+ arguments: toolRequest.toolArguments,
1644
+ },
1645
+ });
1646
+ let result;
1647
+ try {
1648
+ result = await context.with($tool.context, async () => await fn(...args));
1649
+ }
1650
+ catch (error) {
1651
+ $tool.fail(error);
1652
+ throw error;
1653
+ }
1654
+ $tool.end({
1655
+ result: {
1656
+ value: result,
1657
+ isError: false, // Note: currently unknown
1658
+ },
1659
+ });
1660
+ return result;
331
1661
  }
332
- if (typeof promptTokens === 'number') {
333
- result['gen_ai.usage.prompt_tokens'] = promptTokens;
1662
+ }
1663
+
1664
+ const TRACES_URL = `${env.GATEWAY_BASE_URL}/api/v3/otlp/v1/traces`;
1665
+ const SERVICE_NAME = process.env.npm_package_name || 'unknown';
1666
+ const SCOPE_VERSION = process.env.npm_package_version || 'unknown';
1667
+ const BACKGROUND = () => otel.ROOT_CONTEXT;
1668
+ class ScopedTracerProvider {
1669
+ scope;
1670
+ version;
1671
+ provider;
1672
+ constructor(scope, version, provider) {
1673
+ this.scope = scope;
1674
+ this.version = version;
1675
+ this.provider = provider;
334
1676
  }
335
- if (typeof completionTokens === 'number' &&
336
- typeof promptTokens === 'number') {
337
- result['llm.usage.total_tokens'] = completionTokens + promptTokens;
1677
+ getTracer(_name, _version, options) {
1678
+ return this.provider.getTracer(this.scope, this.version, options);
338
1679
  }
339
- return result;
340
1680
  }
341
-
342
- class LatitudeTelemetrySDK {
343
- exporter;
344
- constructor({ exporter, modules = {}, disableBatch = false, processors = [], }) {
345
- this.exporter = exporter;
346
- this._init(modules, { disableBatch, processors });
347
- }
348
- _init(modules, options) {
349
- const instrumentations = [];
350
- if (modules?.openAI) {
351
- const openAIInstrumentation = new OpenAIInstrumentation({
1681
+ const DEFAULT_SPAN_EXPORTER = (apiKey) => new OTLPTraceExporter({
1682
+ url: TRACES_URL,
1683
+ headers: {
1684
+ Authorization: `Bearer ${apiKey}`,
1685
+ 'Content-Type': 'application/json',
1686
+ },
1687
+ timeoutMillis: 30 * 1000,
1688
+ });
1689
+ // Note: Only exporting typescript instrumentations
1690
+ var Instrumentation;
1691
+ (function (Instrumentation) {
1692
+ Instrumentation["Latitude"] = "latitude";
1693
+ Instrumentation["OpenAI"] = "openai";
1694
+ Instrumentation["Anthropic"] = "anthropic";
1695
+ Instrumentation["AzureOpenAI"] = "azure";
1696
+ Instrumentation["VercelAI"] = "vercelai";
1697
+ Instrumentation["VertexAI"] = "vertexai";
1698
+ Instrumentation["AIPlatform"] = "aiplatform";
1699
+ Instrumentation["Bedrock"] = "bedrock";
1700
+ Instrumentation["TogetherAI"] = "togetherai";
1701
+ Instrumentation["Cohere"] = "cohere";
1702
+ Instrumentation["Langchain"] = "langchain";
1703
+ Instrumentation["LlamaIndex"] = "llamaindex";
1704
+ })(Instrumentation || (Instrumentation = {}));
1705
+ class LatitudeTelemetry {
1706
+ options;
1707
+ provider;
1708
+ telemetry;
1709
+ instrumentations;
1710
+ constructor(apiKey, options) {
1711
+ this.options = options || {};
1712
+ if (!this.options.exporter) {
1713
+ this.options.exporter = DEFAULT_SPAN_EXPORTER(apiKey);
1714
+ }
1715
+ context.setGlobalContextManager(new AsyncLocalStorageContextManager().enable());
1716
+ propagation.setGlobalPropagator(new CompositePropagator({
1717
+ propagators: [
1718
+ ...(this.options.propagators || []),
1719
+ new W3CTraceContextPropagator(),
1720
+ new W3CBaggagePropagator(),
1721
+ ],
1722
+ }));
1723
+ this.provider = new NodeTracerProvider({
1724
+ resource: new Resource({ [ATTR_SERVICE_NAME]: SERVICE_NAME }),
1725
+ });
1726
+ // Note: important, must run before the exporter span processors
1727
+ this.provider.addSpanProcessor(new BaggageSpanProcessor(ALLOW_ALL_BAGGAGE_KEYS));
1728
+ if (this.options.processors) {
1729
+ this.options.processors.forEach((processor) => {
1730
+ this.provider.addSpanProcessor(processor);
1731
+ });
1732
+ }
1733
+ else {
1734
+ this.provider.addSpanProcessor(DEFAULT_REDACT_SPAN_PROCESSOR());
1735
+ }
1736
+ if (this.options.disableBatch) {
1737
+ this.provider.addSpanProcessor(new SimpleSpanProcessor(this.options.exporter));
1738
+ }
1739
+ else {
1740
+ this.provider.addSpanProcessor(new BatchSpanProcessor(this.options.exporter));
1741
+ }
1742
+ this.provider.register();
1743
+ process.on('SIGTERM', async () => this.shutdown);
1744
+ process.on('SIGINT', async () => this.shutdown);
1745
+ this.telemetry = null;
1746
+ this.instrumentations = [];
1747
+ this.initInstrumentations();
1748
+ this.instrument();
1749
+ }
1750
+ async flush() {
1751
+ await this.provider.forceFlush();
1752
+ await this.options.exporter.forceFlush?.();
1753
+ }
1754
+ async shutdown() {
1755
+ await this.flush();
1756
+ await this.provider.shutdown();
1757
+ await this.options.exporter.shutdown?.();
1758
+ }
1759
+ tracerProvider(instrumentation) {
1760
+ return new ScopedTracerProvider(`${SCOPE_LATITUDE}.${instrumentation}`, SCOPE_VERSION, this.provider);
1761
+ }
1762
+ tracer(instrumentation) {
1763
+ return this.tracerProvider(instrumentation).getTracer('');
1764
+ }
1765
+ // TODO(tracing): auto instrument outgoing HTTP requests
1766
+ initInstrumentations() {
1767
+ this.instrumentations = [];
1768
+ const tracer = this.tracer(InstrumentationScope.Manual);
1769
+ this.telemetry = new ManualInstrumentation(SegmentSource.API, tracer);
1770
+ this.instrumentations.push(this.telemetry);
1771
+ const latitude = this.options.instrumentations?.latitude;
1772
+ if (latitude) {
1773
+ const tracer = this.tracer(Instrumentation.Latitude);
1774
+ const instrumentation = new LatitudeInstrumentation(SegmentSource.API, tracer, typeof latitude === 'object' ? latitude : { module: latitude });
1775
+ this.instrumentations.push(instrumentation);
1776
+ }
1777
+ const openai = this.options.instrumentations?.openai;
1778
+ if (openai) {
1779
+ const provider = this.tracerProvider(Instrumentation.OpenAI);
1780
+ const instrumentation = new OpenAIInstrumentation({ enrichTokens: true });
1781
+ instrumentation.setTracerProvider(provider);
1782
+ instrumentation.manuallyInstrument(openai);
1783
+ registerInstrumentations({
1784
+ instrumentations: [instrumentation],
1785
+ tracerProvider: provider,
1786
+ });
1787
+ this.instrumentations.push(instrumentation);
1788
+ }
1789
+ const anthropic = this.options.instrumentations?.anthropic;
1790
+ if (anthropic) {
1791
+ const provider = this.tracerProvider(Instrumentation.Anthropic);
1792
+ const instrumentation = new AnthropicInstrumentation();
1793
+ instrumentation.setTracerProvider(provider);
1794
+ instrumentation.manuallyInstrument(anthropic);
1795
+ registerInstrumentations({
1796
+ instrumentations: [instrumentation],
1797
+ tracerProvider: provider,
1798
+ });
1799
+ this.instrumentations.push(instrumentation);
1800
+ }
1801
+ const azure = this.options.instrumentations?.azure;
1802
+ if (azure) {
1803
+ const provider = this.tracerProvider(Instrumentation.AzureOpenAI);
1804
+ const instrumentation = new AzureOpenAIInstrumentation();
1805
+ instrumentation.setTracerProvider(provider);
1806
+ instrumentation.manuallyInstrument(azure);
1807
+ registerInstrumentations({
1808
+ instrumentations: [instrumentation],
1809
+ tracerProvider: provider,
1810
+ });
1811
+ this.instrumentations.push(instrumentation);
1812
+ }
1813
+ const vertexai = this.options.instrumentations?.vertexai;
1814
+ if (vertexai) {
1815
+ const provider = this.tracerProvider(Instrumentation.VertexAI);
1816
+ const instrumentation = new VertexAIInstrumentation();
1817
+ instrumentation.setTracerProvider(provider);
1818
+ instrumentation.manuallyInstrument(vertexai);
1819
+ registerInstrumentations({
1820
+ instrumentations: [instrumentation],
1821
+ tracerProvider: provider,
1822
+ });
1823
+ this.instrumentations.push(instrumentation);
1824
+ }
1825
+ const aiplatform = this.options.instrumentations?.aiplatform;
1826
+ if (aiplatform) {
1827
+ const provider = this.tracerProvider(Instrumentation.AIPlatform);
1828
+ const instrumentation = new AIPlatformInstrumentation();
1829
+ instrumentation.setTracerProvider(provider);
1830
+ instrumentation.manuallyInstrument(aiplatform);
1831
+ registerInstrumentations({
1832
+ instrumentations: [instrumentation],
1833
+ tracerProvider: provider,
1834
+ });
1835
+ this.instrumentations.push(instrumentation);
1836
+ }
1837
+ const bedrock = this.options.instrumentations?.bedrock;
1838
+ if (bedrock) {
1839
+ const provider = this.tracerProvider(Instrumentation.Bedrock);
1840
+ const instrumentation = new BedrockInstrumentation();
1841
+ instrumentation.setTracerProvider(provider);
1842
+ instrumentation.manuallyInstrument(bedrock);
1843
+ registerInstrumentations({
1844
+ instrumentations: [instrumentation],
1845
+ tracerProvider: provider,
1846
+ });
1847
+ this.instrumentations.push(instrumentation);
1848
+ }
1849
+ const togetherai = this.options.instrumentations?.togetherai;
1850
+ if (togetherai) {
1851
+ const provider = this.tracerProvider(Instrumentation.TogetherAI);
1852
+ const instrumentation = new TogetherInstrumentation({
352
1853
  enrichTokens: true,
353
1854
  });
354
- // @ts-ignore
355
- openAIInstrumentation.manuallyInstrument(modules.openAI);
356
- instrumentations.push(openAIInstrumentation);
357
- }
358
- if (modules?.anthropic) {
359
- const anthropicInstrumentation = new AnthropicInstrumentation();
360
- anthropicInstrumentation.manuallyInstrument(modules.anthropic);
361
- instrumentations.push(new AnthropicInstrumentation());
362
- }
363
- if (modules?.azureOpenAI) {
364
- const azureOpenAIInstrumentation = new AzureOpenAIInstrumentation();
365
- azureOpenAIInstrumentation.manuallyInstrument(modules.azureOpenAI);
366
- instrumentations.push(azureOpenAIInstrumentation);
367
- }
368
- if (modules?.cohere) {
369
- const cohereInstrumentation = new CohereInstrumentation();
370
- cohereInstrumentation.manuallyInstrument(modules.cohere);
371
- instrumentations.push(cohereInstrumentation);
372
- }
373
- if (modules?.google_vertexai) {
374
- const vertexAIInstrumentation = new VertexAIInstrumentation();
375
- vertexAIInstrumentation.manuallyInstrument(modules.google_vertexai);
376
- instrumentations.push(vertexAIInstrumentation);
377
- }
378
- if (modules?.google_aiplatform) {
379
- const aiplatformInstrumentation = new AIPlatformInstrumentation();
380
- aiplatformInstrumentation.manuallyInstrument(modules.google_aiplatform);
381
- instrumentations.push(aiplatformInstrumentation);
382
- }
383
- if (modules?.bedrock) {
384
- const bedrockInstrumentation = new BedrockInstrumentation();
385
- bedrockInstrumentation.manuallyInstrument(modules.bedrock);
386
- instrumentations.push(bedrockInstrumentation);
387
- }
388
- // TODO: Enable these once we have manually tested them
389
- //if (modules?.langchain) {
390
- // const langchainInstrumentation = new LangChainInstrumentation()
391
- // langchainInstrumentation.manuallyInstrument(modules.langchain!)
392
- // instrumentations.push(langchainInstrumentation)
393
- //}
394
- //
395
- //if (modules?.llamaIndex) {
396
- // const llamaindexInstrumentation = new LlamaIndexInstrumentation()
397
- // llamaindexInstrumentation.manuallyInstrument(modules.llamaIndex!)
398
- // instrumentations.push(llamaindexInstrumentation)
399
- //}
400
- //if (modules?.pinecone) {
401
- // const pineconeInstrumentation = new PineconeInstrumentation()
402
- // pineconeInstrumentation.manuallyInstrument(modules.pinecone!)
403
- // instrumentations.push(pineconeInstrumentation)
404
- //}
405
- //if (modules?.chromadb) {
406
- // const chromadbInstrumentation = new ChromaDBInstrumentation()
407
- // chromadbInstrumentation.manuallyInstrument(modules.chromadb!)
408
- // instrumentations.push(chromadbInstrumentation)
409
- //}
410
- //if (modules?.qdrant) {
411
- // const qdrantInstrumentation = new QdrantInstrumentation()
412
- // qdrantInstrumentation.manuallyInstrument(modules.qdrant!)
413
- // instrumentations.push(qdrantInstrumentation)
414
- //}
415
- if (!instrumentations.length && !options?.processors?.length) {
416
- console.warn('Latitude: No instrumentations or processors to initialize');
417
- return;
418
- }
419
- const processors = options?.disableBatch
420
- ? [
421
- new SimpleSpanProcessor$1(this.exporter),
422
- ...(options?.processors?.map((processor) => new processor(this.exporter)) || []),
423
- ]
424
- : [
425
- new BatchSpanProcessor$1(this.exporter),
426
- ...(options?.processors?.map((processor) => new processor(this.exporter)) || []),
427
- ];
428
- const sdk = new NodeSDK({
429
- resource: new Resource({
430
- 'service.name': process.env.npm_package_name,
431
- }),
432
- instrumentations,
433
- traceExporter: this.exporter,
434
- // @ts-ignore
435
- spanProcessors: processors,
1855
+ instrumentation.setTracerProvider(provider);
1856
+ instrumentation.manuallyInstrument(togetherai);
1857
+ registerInstrumentations({
1858
+ instrumentations: [instrumentation],
1859
+ tracerProvider: provider,
1860
+ });
1861
+ this.instrumentations.push(instrumentation);
1862
+ }
1863
+ const cohere = this.options.instrumentations?.cohere;
1864
+ if (cohere) {
1865
+ const provider = this.tracerProvider(Instrumentation.Cohere);
1866
+ const instrumentation = new CohereInstrumentation();
1867
+ instrumentation.setTracerProvider(provider);
1868
+ instrumentation.manuallyInstrument(cohere);
1869
+ registerInstrumentations({
1870
+ instrumentations: [instrumentation],
1871
+ tracerProvider: provider,
1872
+ });
1873
+ this.instrumentations.push(instrumentation);
1874
+ }
1875
+ const langchain = this.options.instrumentations?.langchain;
1876
+ if (langchain) {
1877
+ const provider = this.tracerProvider(Instrumentation.Langchain);
1878
+ const instrumentation = new LangChainInstrumentation();
1879
+ instrumentation.setTracerProvider(provider);
1880
+ instrumentation.manuallyInstrument(langchain);
1881
+ registerInstrumentations({
1882
+ instrumentations: [instrumentation],
1883
+ tracerProvider: provider,
1884
+ });
1885
+ this.instrumentations.push(instrumentation);
1886
+ }
1887
+ const llamaindex = this.options.instrumentations?.llamaindex;
1888
+ if (llamaindex) {
1889
+ const provider = this.tracerProvider(Instrumentation.LlamaIndex);
1890
+ const instrumentation = new LlamaIndexInstrumentation();
1891
+ instrumentation.setTracerProvider(provider);
1892
+ instrumentation.manuallyInstrument(llamaindex);
1893
+ registerInstrumentations({
1894
+ instrumentations: [instrumentation],
1895
+ tracerProvider: provider,
1896
+ });
1897
+ this.instrumentations.push(instrumentation);
1898
+ }
1899
+ }
1900
+ instrument() {
1901
+ this.instrumentations.forEach((instrumentation) => {
1902
+ if (!instrumentation.isEnabled())
1903
+ instrumentation.enable();
436
1904
  });
437
- sdk.start();
438
1905
  }
439
- span(s, fn) {
440
- const c = context.active();
441
- return context.with(c, () => trace
442
- .getTracer('latitude')
443
- .startActiveSpan(s.name ?? 'latitude.span', {}, c, async (span) => {
444
- try {
445
- if (s.prompt) {
446
- try {
447
- span.setAttribute('latitude.prompt', JSON.stringify(s.prompt));
448
- }
449
- catch (e) {
450
- console.error('Latitude: Could not serialize latitude.prompt attribute', e);
451
- }
452
- }
453
- if (s.distinctId) {
454
- span.setAttribute('latitude.distinctId', s.distinctId);
455
- }
456
- if (s.metadata) {
457
- try {
458
- span.setAttribute('latitude.metadata', JSON.stringify(s.metadata));
459
- }
460
- catch (e) {
461
- console.error('Latitude: Could not serialize latitude.metadata attribute', e);
462
- }
463
- }
464
- }
465
- catch (error) {
466
- console.error(error);
467
- }
468
- const res = fn(span);
469
- if (res instanceof Promise) {
470
- return res.then((resolvedRes) => {
471
- span.end();
472
- return resolvedRes;
473
- });
474
- }
475
- span.end();
476
- return res;
477
- }));
1906
+ uninstrument() {
1907
+ this.instrumentations.forEach((instrumentation) => {
1908
+ if (instrumentation.isEnabled())
1909
+ instrumentation.disable();
1910
+ });
1911
+ }
1912
+ baggage(ctx) {
1913
+ return this.telemetry.baggage(ctx);
1914
+ }
1915
+ pause(ctx) {
1916
+ return this.telemetry.pause(ctx);
1917
+ }
1918
+ resume(ctx) {
1919
+ return this.telemetry.resume(ctx);
1920
+ }
1921
+ restored(ctx) {
1922
+ return this.telemetry.restored(ctx);
1923
+ }
1924
+ restore(ctx) {
1925
+ return this.telemetry.restore(ctx);
1926
+ }
1927
+ tool(ctx, options) {
1928
+ return this.telemetry.tool(ctx, options);
1929
+ }
1930
+ completion(ctx, options) {
1931
+ return this.telemetry.completion(ctx, options);
1932
+ }
1933
+ embedding(ctx, options) {
1934
+ return this.telemetry.embedding(ctx, options);
1935
+ }
1936
+ retrieval(ctx, options) {
1937
+ return this.telemetry.retrieval(ctx, options);
1938
+ }
1939
+ reranking(ctx, options) {
1940
+ return this.telemetry.reranking(ctx, options);
1941
+ }
1942
+ http(ctx, options) {
1943
+ return this.telemetry.http(ctx, options);
1944
+ }
1945
+ prompt(ctx, options) {
1946
+ return this.telemetry.prompt(ctx, options);
1947
+ }
1948
+ step(ctx, options) {
1949
+ return this.telemetry.step(ctx, options);
478
1950
  }
479
1951
  }
480
1952
 
481
- export { LatitudeExporter, LatitudeTelemetrySDK, VercelBatchSpanProcessor, VercelSpanProcessor };
1953
+ export { BACKGROUND, DEFAULT_REDACT_SPAN_PROCESSOR, DEFAULT_SPAN_EXPORTER, Instrumentation, LatitudeTelemetry, RedactSpanProcessor };
482
1954
  //# sourceMappingURL=index.js.map