@latitude-data/telemetry 2.0.2 → 3.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.cjs CHANGED
@@ -5,7 +5,6 @@ var incubating = require('@opentelemetry/semantic-conventions/incubating');
5
5
  var semanticConventions = require('@opentelemetry/semantic-conventions');
6
6
  var otel = require('@opentelemetry/api');
7
7
  var rosettaAi = require('rosetta-ai');
8
- var uuid = require('uuid');
9
8
  var baggageSpanProcessor = require('@opentelemetry/baggage-span-processor');
10
9
  var contextAsyncHooks = require('@opentelemetry/context-async-hooks');
11
10
  var core = require('@opentelemetry/core');
@@ -218,17 +217,23 @@ const expectedOutputConfiguration = zod.z.object({
218
217
  fieldAccessor: zod.z.string().optional(), // Field accessor to get the output from if it's a key-value format
219
218
  });
220
219
  const EVALUATION_TRIGGER_TARGETS = ['first', 'every', 'last'];
221
- const DEFAULT_LAST_INTERACTION_DEBOUNCE_SECONDS = 120;
222
220
  const LAST_INTERACTION_DEBOUNCE_MIN_SECONDS = 30;
223
221
  const LAST_INTERACTION_DEBOUNCE_MAX_SECONDS = 60 * 60 * 24; // 1 day
222
+ const MIN_EVALUATION_SAMPLE_RATE = 0; // 0%
223
+ const MAX_EVALUATION_SAMPLE_RATE = 100; // 100%
224
224
  const triggerConfiguration = zod.z.object({
225
225
  target: zod.z.enum(EVALUATION_TRIGGER_TARGETS),
226
226
  lastInteractionDebounce: zod.z
227
227
  .number()
228
228
  .min(LAST_INTERACTION_DEBOUNCE_MIN_SECONDS)
229
229
  .max(LAST_INTERACTION_DEBOUNCE_MAX_SECONDS)
230
- .optional()
231
- .default(DEFAULT_LAST_INTERACTION_DEBOUNCE_SECONDS),
230
+ .optional(),
231
+ sampleRate: zod.z
232
+ .number()
233
+ .int()
234
+ .min(MIN_EVALUATION_SAMPLE_RATE)
235
+ .max(MAX_EVALUATION_SAMPLE_RATE)
236
+ .optional(),
232
237
  });
233
238
  const baseEvaluationConfiguration = zod.z.object({
234
239
  reverseScale: zod.z.boolean(), // If true, lower is better, otherwise, higher is better
@@ -941,16 +946,11 @@ const ATTRIBUTES = {
941
946
  // Custom attributes added and used by Latitude spans (Prompt / External / Chat)
942
947
  LATITUDE: {
943
948
  type: 'latitude.type',
944
- documentUuid: 'latitude.document_uuid',
945
949
  promptPath: 'latitude.prompt_path',
946
950
  commitUuid: 'latitude.commit_uuid',
947
951
  documentLogUuid: 'latitude.document_log_uuid',
948
952
  projectId: 'latitude.project_id',
949
- experimentUuid: 'latitude.experiment_uuid',
950
- source: 'latitude.source',
951
953
  externalId: 'latitude.external_id',
952
- testDeploymentId: 'latitude.test_deployment_id',
953
- previousTraceId: 'latitude.previous_trace_id',
954
954
  // Custom additions to the GenAI semantic conventions (deprecated)
955
955
  request: {
956
956
  _root: 'gen_ai.request',
@@ -1171,6 +1171,12 @@ const OptimizationBudgetSchema = zod.z.object({
1171
1171
  tokens: zod.z.number().min(0).optional(),
1172
1172
  });
1173
1173
  zod.z.object({
1174
+ dataset: zod.z
1175
+ .object({
1176
+ target: zod.z.number().min(0).optional(), // Note: number of rows to curate when not provided by the user
1177
+ label: zod.z.string().optional(), // Note: expected output column when using a labeled evaluation
1178
+ })
1179
+ .optional(),
1174
1180
  parameters: zod.z
1175
1181
  .record(zod.z.string(), zod.z.object({
1176
1182
  column: zod.z.string().optional(), // Note: corresponding column in the user-provided trainset and testset
@@ -1188,7 +1194,6 @@ zod.z.object({
1188
1194
  });
1189
1195
 
1190
1196
  // TODO(tracing): deprecated
1191
- const HEAD_COMMIT = 'live';
1192
1197
  var Providers;
1193
1198
  (function (Providers) {
1194
1199
  Providers["OpenAI"] = "openai";
@@ -1343,6 +1348,7 @@ class ManualInstrumentation {
1343
1348
  jsonArguments = '{}';
1344
1349
  }
1345
1350
  const span = this.span(ctx, start.name, SpanType.Tool, {
1351
+ ...start,
1346
1352
  attributes: {
1347
1353
  [ATTRIBUTES.OPENTELEMETRY.GEN_AI._deprecated.tool.name]: start.name,
1348
1354
  [ATTRIBUTES.OPENTELEMETRY.GEN_AI._deprecated.tool.type]: VALUES.OPENTELEMETRY.GEN_AI.tool.type.function,
@@ -1430,6 +1436,7 @@ class ManualInstrumentation {
1430
1436
  jsonInput = '[]';
1431
1437
  }
1432
1438
  const span = this.span(ctx, start.name || `${start.provider} / ${start.model}`, SpanType.Completion, {
1439
+ ...start,
1433
1440
  attributes: {
1434
1441
  [ATTRIBUTES.OPENTELEMETRY.GEN_AI._deprecated.system]: start.provider,
1435
1442
  [ATTRIBUTES.LATITUDE.request.configuration]: jsonConfiguration,
@@ -1437,9 +1444,6 @@ class ManualInstrumentation {
1437
1444
  [ATTRIBUTES.OPENTELEMETRY.GEN_AI.systemInstructions]: jsonSystem,
1438
1445
  [ATTRIBUTES.OPENTELEMETRY.GEN_AI.input.messages]: jsonInput,
1439
1446
  ...(start.attributes || {}),
1440
- [ATTRIBUTES.LATITUDE.commitUuid]: start.versionUuid,
1441
- [ATTRIBUTES.LATITUDE.documentUuid]: start.promptUuid,
1442
- [ATTRIBUTES.LATITUDE.experimentUuid]: start.experimentUuid,
1443
1447
  },
1444
1448
  });
1445
1449
  return {
@@ -1522,6 +1526,7 @@ class ManualInstrumentation {
1522
1526
  }
1523
1527
  }
1524
1528
  const span = this.span(ctx, start.name || `${method} ${start.request.url}`, SpanType.Http, {
1529
+ ...start,
1525
1530
  attributes: {
1526
1531
  [ATTRIBUTES.OPENTELEMETRY.HTTP.request.method]: method,
1527
1532
  [ATTRIBUTES.OPENTELEMETRY.HTTP.request.url]: start.request.url,
@@ -1559,7 +1564,8 @@ class ManualInstrumentation {
1559
1564
  },
1560
1565
  };
1561
1566
  }
1562
- prompt(ctx, { documentLogUuid, versionUuid, promptUuid, projectId, experimentUuid, testDeploymentId, externalId, template, parameters, name, source, ...rest }) {
1567
+ prompt(ctx, options) {
1568
+ const { template, parameters, name, attributes: userAttributes } = options;
1563
1569
  let jsonParameters = '';
1564
1570
  try {
1565
1571
  jsonParameters = JSON.stringify(parameters || {});
@@ -1570,51 +1576,27 @@ class ManualInstrumentation {
1570
1576
  const attributes = {
1571
1577
  [ATTRIBUTES.LATITUDE.request.template]: template,
1572
1578
  [ATTRIBUTES.LATITUDE.request.parameters]: jsonParameters,
1573
- [ATTRIBUTES.LATITUDE.commitUuid]: versionUuid || HEAD_COMMIT,
1574
- [ATTRIBUTES.LATITUDE.documentUuid]: promptUuid,
1575
- [ATTRIBUTES.LATITUDE.projectId]: projectId,
1576
- [ATTRIBUTES.LATITUDE.documentLogUuid]: documentLogUuid,
1577
- ...(experimentUuid && {
1578
- [ATTRIBUTES.LATITUDE.experimentUuid]: experimentUuid,
1579
- }),
1580
- ...(testDeploymentId && {
1581
- [ATTRIBUTES.LATITUDE.testDeploymentId]: testDeploymentId,
1582
- }),
1583
- ...(externalId && { [ATTRIBUTES.LATITUDE.externalId]: externalId }),
1584
- ...(source && { [ATTRIBUTES.LATITUDE.source]: source }),
1585
- ...(rest.attributes || {}),
1579
+ ...(userAttributes || {}),
1586
1580
  };
1587
- return this.span(ctx, name || `prompt-${promptUuid}`, SpanType.Prompt, {
1588
- attributes,
1589
- });
1581
+ return this.span(ctx, name || 'prompt', SpanType.Prompt, { attributes });
1590
1582
  }
1591
- chat(ctx, { documentLogUuid, previousTraceId, source, name, versionUuid, promptUuid, ...rest }) {
1583
+ chat(ctx, options) {
1584
+ const { name, attributes: userAttributes } = options;
1592
1585
  const attributes = {
1593
- [ATTRIBUTES.LATITUDE.documentLogUuid]: documentLogUuid,
1594
- [ATTRIBUTES.LATITUDE.previousTraceId]: previousTraceId,
1595
- ...(versionUuid && { [ATTRIBUTES.LATITUDE.commitUuid]: versionUuid }),
1596
- ...(promptUuid && { [ATTRIBUTES.LATITUDE.documentUuid]: promptUuid }),
1597
- ...(source && { [ATTRIBUTES.LATITUDE.source]: source }),
1598
- ...(rest.attributes || {}),
1586
+ ...(userAttributes || {}),
1599
1587
  };
1600
- return this.span(ctx, name || `chat-${documentLogUuid}`, SpanType.Chat, {
1601
- attributes,
1602
- });
1588
+ return this.span(ctx, name || 'chat', SpanType.Chat, { attributes });
1603
1589
  }
1604
- external(ctx, { promptUuid, documentLogUuid, source, versionUuid, externalId, name, ...rest }) {
1590
+ external(ctx, options) {
1591
+ const { externalId, name, attributes: userAttributes } = options;
1605
1592
  const attributes = {
1606
- [ATTRIBUTES.LATITUDE.documentUuid]: promptUuid,
1607
- [ATTRIBUTES.LATITUDE.documentLogUuid]: documentLogUuid,
1608
- [ATTRIBUTES.LATITUDE.source]: source ?? LogSources.API,
1609
- ...(versionUuid && { [ATTRIBUTES.LATITUDE.commitUuid]: versionUuid }),
1610
1593
  ...(externalId && { [ATTRIBUTES.LATITUDE.externalId]: externalId }),
1611
- ...(rest.attributes || {}),
1594
+ ...(userAttributes || {}),
1612
1595
  };
1613
- return this.span(ctx, name || `external-${promptUuid}`, SpanType.External, {
1614
- attributes,
1615
- });
1596
+ return this.span(ctx, name || 'external', SpanType.External, { attributes });
1616
1597
  }
1617
- unresolvedExternal(ctx, { path, projectId, versionUuid, conversationUuid, name, ...rest }) {
1598
+ unresolvedExternal(ctx, options) {
1599
+ const { path, projectId, versionUuid, conversationUuid, name, attributes: userAttributes, } = options;
1618
1600
  const attributes = {
1619
1601
  [ATTRIBUTES.LATITUDE.promptPath]: path,
1620
1602
  [ATTRIBUTES.LATITUDE.projectId]: projectId,
@@ -1622,7 +1604,7 @@ class ManualInstrumentation {
1622
1604
  ...(conversationUuid && {
1623
1605
  [ATTRIBUTES.LATITUDE.documentLogUuid]: conversationUuid,
1624
1606
  }),
1625
- ...(rest.attributes || {}),
1607
+ ...(userAttributes || {}),
1626
1608
  };
1627
1609
  return this.span(ctx, name || `capture-${path}`, SpanType.UnresolvedExternal, { attributes });
1628
1610
  }
@@ -1668,9 +1650,6 @@ class LatitudeInstrumentation {
1668
1650
  async wrapRenderChain(fn, ...args) {
1669
1651
  const { prompt, parameters } = args[0];
1670
1652
  const $prompt = this.manualTelemetry.prompt(otel.context.active(), {
1671
- documentLogUuid: uuid.v4(),
1672
- versionUuid: prompt.versionUuid,
1673
- promptUuid: prompt.uuid,
1674
1653
  template: prompt.content,
1675
1654
  parameters: parameters,
1676
1655
  });
@@ -1874,6 +1853,51 @@ class ContextManager {
1874
1853
  with(ctx, fn, thisArg, ...args) {
1875
1854
  return otel.context.with(ctx, fn, thisArg, ...args);
1876
1855
  }
1856
+ /**
1857
+ * Sets custom attributes in the OpenTelemetry baggage that will be
1858
+ * automatically propagated to all child spans in the trace.
1859
+ *
1860
+ * This is useful for setting trace-level metadata that should be
1861
+ * inherited by all spans without manually passing them to each span.
1862
+ *
1863
+ * Example:
1864
+ * ```typescript
1865
+ * const ctx = telemetry.context.setAttributes(
1866
+ * telemetry.context.active(),
1867
+ * {
1868
+ * 'latitude.documentLogUuid': 'uuid-123',
1869
+ * 'latitude.documentUuid': 'prompt-456',
1870
+ * 'latitude.commitUuid': 'commit-789',
1871
+ * 'latitude.projectId': '123',
1872
+ * 'custom.attribute': 'value'
1873
+ * }
1874
+ * )
1875
+ *
1876
+ * // Latitude keys are normalized to snake_case in baggage:
1877
+ * // latitude.document_log_uuid, latitude.document_uuid, ...
1878
+ *
1879
+ * // Use context.with() to make the context active
1880
+ * // All spans created within this context will automatically
1881
+ * // inherit the baggage attributes without explicitly passing ctx
1882
+ * telemetry.context.with(ctx, () => {
1883
+ * telemetry.span.tool({ name: 'my-tool', call: { id: '1', arguments: {} } })
1884
+ * // ... other spans
1885
+ * })
1886
+ * ```
1887
+ */
1888
+ setAttributes(ctx, attributes) {
1889
+ const baggage = otel.propagation.getBaggage(ctx) || otel.propagation.createBaggage({});
1890
+ const newBaggage = Object.entries(attributes).reduce((bag, [key, value]) => bag.setEntry(this.normalizeBaggageKey(key), { value }), baggage);
1891
+ return otel.propagation.setBaggage(ctx, newBaggage);
1892
+ }
1893
+ normalizeBaggageKey(key) {
1894
+ if (!key.startsWith('latitude.'))
1895
+ return key;
1896
+ const [namespace, ...path] = key.split('.');
1897
+ if (!namespace || path.length === 0)
1898
+ return key;
1899
+ return [namespace, ...path.map(toSnakeCase)].join('.');
1900
+ }
1877
1901
  }
1878
1902
  class InstrumentationManager {
1879
1903
  instrumentations;