axiom 0.44.0 → 0.45.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.
Files changed (40) hide show
  1. package/dist/bin.cjs +6 -6
  2. package/dist/bin.cjs.map +1 -1
  3. package/dist/bin.js +5 -5
  4. package/dist/chunk-3Q36GUCI.js +23 -0
  5. package/dist/chunk-3Q36GUCI.js.map +1 -0
  6. package/dist/{chunk-MCKVQ2IB.js → chunk-JSEK2D3F.js} +5 -19
  7. package/dist/chunk-JSEK2D3F.js.map +1 -0
  8. package/dist/{chunk-HW6E4M7S.js → chunk-N3RHEQMQ.js} +2 -2
  9. package/dist/{chunk-HW6E4M7S.js.map → chunk-N3RHEQMQ.js.map} +1 -1
  10. package/dist/{chunk-U3JDCQ3Y.js → chunk-QAIGRB75.js} +7 -7
  11. package/dist/{chunk-7NTVK3F4.js → chunk-R4CARCOX.js} +2 -2
  12. package/dist/{chunk-56V2A6IW.js → chunk-RSHQRY3F.js} +3 -3
  13. package/dist/{chunk-AAYRMTT6.js → chunk-SGAIMXRV.js} +24 -9
  14. package/dist/chunk-SGAIMXRV.js.map +1 -0
  15. package/dist/evals/online.cjs +31 -8
  16. package/dist/evals/online.cjs.map +1 -1
  17. package/dist/evals/online.d.cts +9 -4
  18. package/dist/evals/online.d.ts +9 -4
  19. package/dist/evals/online.js +3 -2
  20. package/dist/evals/online.js.map +1 -1
  21. package/dist/evals/scorers.cjs +13 -16
  22. package/dist/evals/scorers.cjs.map +1 -1
  23. package/dist/evals/scorers.js +2 -1
  24. package/dist/evals/scorers.js.map +1 -1
  25. package/dist/evals.cjs +22 -23
  26. package/dist/evals.cjs.map +1 -1
  27. package/dist/evals.js +8 -8
  28. package/dist/evals.js.map +1 -1
  29. package/dist/index.cjs +36 -24
  30. package/dist/index.cjs.map +1 -1
  31. package/dist/index.js +5 -4
  32. package/dist/index.js.map +1 -1
  33. package/dist/{run-vitest-4OEEDEHV.js → run-vitest-SYYO32TD.js} +5 -5
  34. package/package.json +1 -1
  35. package/dist/chunk-AAYRMTT6.js.map +0 -1
  36. package/dist/chunk-MCKVQ2IB.js.map +0 -1
  37. /package/dist/{chunk-U3JDCQ3Y.js.map → chunk-QAIGRB75.js.map} +0 -0
  38. /package/dist/{chunk-7NTVK3F4.js.map → chunk-R4CARCOX.js.map} +0 -0
  39. /package/dist/{chunk-56V2A6IW.js.map → chunk-RSHQRY3F.js.map} +0 -0
  40. /package/dist/{run-vitest-4OEEDEHV.js.map → run-vitest-SYYO32TD.js.map} +0 -0
package/dist/bin.js CHANGED
@@ -2,7 +2,7 @@
2
2
  import {
3
3
  extractOverrides,
4
4
  loadEvalCommand
5
- } from "./chunk-56V2A6IW.js";
5
+ } from "./chunk-RSHQRY3F.js";
6
6
  import {
7
7
  OAuth,
8
8
  fetchOrganizations,
@@ -15,12 +15,12 @@ import {
15
15
  verifyToken,
16
16
  waitForCallback
17
17
  } from "./chunk-T4FBJ252.js";
18
- import "./chunk-7NTVK3F4.js";
18
+ import "./chunk-R4CARCOX.js";
19
19
  import {
20
20
  AxiomCLIError
21
21
  } from "./chunk-S65FSMB3.js";
22
22
  import "./chunk-X2LH7XLM.js";
23
- import "./chunk-HW6E4M7S.js";
23
+ import "./chunk-N3RHEQMQ.js";
24
24
  import "./chunk-TWE3LIRZ.js";
25
25
  import {
26
26
  init_esm_shims
@@ -400,7 +400,7 @@ import { Command } from "commander";
400
400
  var loadVersionCommand = (program2) => {
401
401
  return program2.addCommand(
402
402
  new Command("version").description("cli version").action(() => {
403
- console.log("0.44.0");
403
+ console.log("0.45.0");
404
404
  })
405
405
  );
406
406
  };
@@ -410,7 +410,7 @@ var { loadEnvConfig } = pkg;
410
410
  loadEnvConfig(process.cwd());
411
411
  var { cleanedArgv, overrides } = extractOverrides(process.argv.slice(2));
412
412
  var program = new Command2();
413
- program.name("axiom").description("Axiom's CLI to manage your objects and run evals").version("0.44.0");
413
+ program.name("axiom").description("Axiom's CLI to manage your objects and run evals").version("0.45.0");
414
414
  program.hook("preAction", async (_, actionCommand) => {
415
415
  const commandName = actionCommand.name();
416
416
  const parentCommand = actionCommand.parent;
@@ -0,0 +1,23 @@
1
+ import {
2
+ Attr
3
+ } from "./chunk-TWE3LIRZ.js";
4
+ import {
5
+ init_esm_shims
6
+ } from "./chunk-4VNFFUM5.js";
7
+
8
+ // src/evals/normalize-score.ts
9
+ init_esm_shims();
10
+ function normalizeBooleanScore(score, metadata) {
11
+ if (typeof score !== "boolean") {
12
+ return { score, metadata };
13
+ }
14
+ return {
15
+ score: score ? 1 : 0,
16
+ metadata: { ...metadata, [Attr.Eval.Score.IsBoolean]: true }
17
+ };
18
+ }
19
+
20
+ export {
21
+ normalizeBooleanScore
22
+ };
23
+ //# sourceMappingURL=chunk-3Q36GUCI.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/evals/normalize-score.ts"],"sourcesContent":["import { Attr } from '../otel/semconv/attributes';\nimport type { Score } from './scorer.types';\n\n/**\n * Normalizes a boolean score to numeric (1/0) and adds eval.score.is_boolean\n * to metadata. Numbers and null pass through unchanged.\n */\nexport function normalizeBooleanScore(\n score: Score['score'],\n metadata?: Record<string, unknown>,\n): { score: number | null; metadata?: Record<string, unknown> } {\n if (typeof score !== 'boolean') {\n return { score, metadata };\n }\n return {\n score: score ? 1 : 0,\n metadata: { ...metadata, [Attr.Eval.Score.IsBoolean]: true },\n };\n}\n"],"mappings":";;;;;;;;AAAA;AAOO,SAAS,sBACd,OACA,UAC8D;AAC9D,MAAI,OAAO,UAAU,WAAW;AAC9B,WAAO,EAAE,OAAO,SAAS;AAAA,EAC3B;AACA,SAAO;AAAA,IACL,OAAO,QAAQ,IAAI;AAAA,IACnB,UAAU,EAAE,GAAG,UAAU,CAAC,KAAK,KAAK,MAAM,SAAS,GAAG,KAAK;AAAA,EAC7D;AACF;","names":[]}
@@ -1,6 +1,6 @@
1
1
  import {
2
- Attr
3
- } from "./chunk-TWE3LIRZ.js";
2
+ normalizeBooleanScore
3
+ } from "./chunk-3Q36GUCI.js";
4
4
  import {
5
5
  init_esm_shims
6
6
  } from "./chunk-4VNFFUM5.js";
@@ -13,23 +13,9 @@ function createScorer(name, fn, options) {
13
13
  return { score: res };
14
14
  }
15
15
  if (typeof res === "boolean") {
16
- return {
17
- score: res ? 1 : 0,
18
- metadata: {
19
- [Attr.Eval.Score.IsBoolean]: true
20
- }
21
- };
16
+ return normalizeBooleanScore(res);
22
17
  }
23
- if (typeof res.score === "boolean") {
24
- return {
25
- score: res.score ? 1 : 0,
26
- metadata: {
27
- ...res.metadata,
28
- [Attr.Eval.Score.IsBoolean]: true
29
- }
30
- };
31
- }
32
- return res;
18
+ return normalizeBooleanScore(res.score, res.metadata);
33
19
  };
34
20
  const scorer = (args) => {
35
21
  const res = fn(args);
@@ -56,4 +42,4 @@ function createScorer(name, fn, options) {
56
42
  export {
57
43
  createScorer
58
44
  };
59
- //# sourceMappingURL=chunk-MCKVQ2IB.js.map
45
+ //# sourceMappingURL=chunk-JSEK2D3F.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/evals/scorer.factory.ts"],"sourcesContent":["import type { ValidateName } from '../util/name-validation';\nimport { normalizeBooleanScore } from './normalize-score';\nimport type { Score, Scorer, ScorerOptions } from './scorer.types';\n\n// Helper to force TypeScript to evaluate/simplify types\ntype Simplify<T> = { [K in keyof T]: T[K] } & {};\n\ntype ScorerReturnValue = number | boolean | Score;\ntype AwaitedValue<T> = T extends Promise<infer U> ? U : T;\ntype InferScorerMetadata<T> =\n AwaitedValue<T> extends Score<infer TMetadata> ? TMetadata : Record<string, any>;\ntype NormalizeScorerReturn<T, TMetadata extends Record<string, any>> =\n T extends Promise<any> ? Promise<Score<TMetadata>> : Score<TMetadata>;\n\n/**\n * Creates a scorer to be used in evals.\n *\n * Scorers need to return a number or a boolean. If returning a number, it is\n * suggested that this number is between 0 and 1.\n *\n * @example\n * const scorer = createScorer('exact-match',\n * (args: { output: string; expected: string; }) => {\n * return args.output === args.expected ? true : false;\n * }\n * );\n *\n * @example\n * // With aggregation for trials\n * import { PassAtK } from '@axiomhq/ai/evals/aggregations';\n * const scorer = createScorer('tool-called',\n * (args: { output: string }) => args.output.includes('tool') ? 1 : 0,\n * { aggregation: PassAtK({ threshold: 0.8 }) }\n * );\n */\nexport function createScorer<\n TArgs extends Record<string, any> = {},\n // Use tuple wrapping to prevent distributive conditional types\n TInput = [TArgs] extends [{ input: infer I }] ? I : unknown,\n TExpected = [TArgs] extends [{ expected: infer E }] ? Exclude<E, undefined> : unknown,\n TOutput = [TArgs] extends [{ output: infer O }] ? Exclude<O, undefined> : never,\n TExtra extends Record<string, any> = Simplify<\n Omit<TArgs, 'input' | 'expected' | 'output' | 'trialIndex'>\n >,\n TReturn extends ScorerReturnValue | Promise<ScorerReturnValue> =\n | ScorerReturnValue\n | Promise<ScorerReturnValue>,\n TName extends string = string,\n>(\n /**\n * The name of the scorer\n */\n name: ValidateName<TName>,\n /**\n * The scorer function. Can be sync or async.\n */\n fn: (args: TArgs) => TReturn,\n /**\n * Optional configuration for the scorer, including aggregation for trials.\n */\n options?: ScorerOptions,\n): [TOutput] extends [never]\n ? never\n : Scorer<\n TInput,\n TExpected,\n TOutput,\n TExtra,\n InferScorerMetadata<TReturn>,\n NormalizeScorerReturn<TReturn, InferScorerMetadata<TReturn>>\n > {\n const normalizeScore = (res: ScorerReturnValue): Score => {\n if (typeof res === 'number') {\n return { score: res };\n }\n if (typeof res === 'boolean') {\n return normalizeBooleanScore(res);\n }\n return normalizeBooleanScore(res.score, res.metadata);\n };\n\n const scorer: any = (args: TArgs) => {\n const res = fn(args);\n\n // If user returned a Promise, handle async\n if (res instanceof Promise) {\n return res.then(normalizeScore);\n }\n\n // Otherwise handle sync\n return normalizeScore(res);\n };\n\n // Attach name property to function for pre-execution access\n Object.defineProperty(scorer, 'name', {\n value: name,\n configurable: true,\n enumerable: true,\n });\n\n // Attach aggregation config if provided\n if (options?.aggregation) {\n Object.defineProperty(scorer, 'aggregation', {\n value: options.aggregation,\n configurable: true,\n enumerable: true,\n });\n }\n\n return scorer as [TOutput] extends [never]\n ? never\n : Scorer<\n TInput,\n TExpected,\n TOutput,\n TExtra,\n InferScorerMetadata<TReturn>,\n NormalizeScorerReturn<TReturn, InferScorerMetadata<TReturn>>\n >;\n}\n"],"mappings":";;;;;;;;AAAA;AAmCO,SAAS,aAiBd,MAIA,IAIA,SAUI;AACJ,QAAM,iBAAiB,CAAC,QAAkC;AACxD,QAAI,OAAO,QAAQ,UAAU;AAC3B,aAAO,EAAE,OAAO,IAAI;AAAA,IACtB;AACA,QAAI,OAAO,QAAQ,WAAW;AAC5B,aAAO,sBAAsB,GAAG;AAAA,IAClC;AACA,WAAO,sBAAsB,IAAI,OAAO,IAAI,QAAQ;AAAA,EACtD;AAEA,QAAM,SAAc,CAAC,SAAgB;AACnC,UAAM,MAAM,GAAG,IAAI;AAGnB,QAAI,eAAe,SAAS;AAC1B,aAAO,IAAI,KAAK,cAAc;AAAA,IAChC;AAGA,WAAO,eAAe,GAAG;AAAA,EAC3B;AAGA,SAAO,eAAe,QAAQ,QAAQ;AAAA,IACpC,OAAO;AAAA,IACP,cAAc;AAAA,IACd,YAAY;AAAA,EACd,CAAC;AAGD,MAAI,SAAS,aAAa;AACxB,WAAO,eAAe,QAAQ,eAAe;AAAA,MAC3C,OAAO,QAAQ;AAAA,MACf,cAAc;AAAA,MACd,YAAY;AAAA,IACd,CAAC;AAAA,EACH;AAEA,SAAO;AAUT;","names":[]}
@@ -69,7 +69,7 @@ import { trace } from "@opentelemetry/api";
69
69
  // package.json
70
70
  var package_default = {
71
71
  name: "axiom",
72
- version: "0.44.0",
72
+ version: "0.45.0",
73
73
  type: "module",
74
74
  author: "Axiom, Inc.",
75
75
  contributors: [
@@ -299,4 +299,4 @@ export {
299
299
  getGlobalTracer,
300
300
  resetAxiomAI
301
301
  };
302
- //# sourceMappingURL=chunk-HW6E4M7S.js.map
302
+ //# sourceMappingURL=chunk-N3RHEQMQ.js.map
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/otel/utils/redaction.ts","../src/otel/withSpanBaggageKey.ts","../src/otel/initAxiomAI.ts","../package.json"],"sourcesContent":["import { context, propagation, type Baggage, type Span } from '@opentelemetry/api';\nimport { WITHSPAN_REDACTION_POLICY_KEY } from '../withSpanBaggageKey';\n\ntype CaptureMessageContent = 'full' | 'off';\n\nexport type AxiomAIRedactionPolicy = {\n captureMessageContent?: CaptureMessageContent;\n mirrorToolPayloadOnToolSpan?: boolean;\n};\n\nexport const RedactionPolicy = {\n /**\n * Includes message content on chat spans, and mirrors tool\n * payload on tool spans for more convenient querying.\n */\n AxiomDefault: {\n captureMessageContent: 'full',\n mirrorToolPayloadOnToolSpan: true,\n },\n /**\n * Redacts message content on chat spans, and does not put\n * tool payload on tool spans.\n */\n OpenTelemetryDefault: {\n captureMessageContent: 'off',\n mirrorToolPayloadOnToolSpan: false,\n },\n} as const satisfies Record<string, AxiomAIRedactionPolicy>;\n\n// Global key to store redaction policy across all execution contexts\nexport const AXIOM_AI_REDACTION_KEY = Symbol.for('__axiom_ai_redaction__');\n\n/**\n * Get the globally stored redaction policy\n * @returns The global redaction policy or undefined if not set\n */\nfunction getGlobalRedactionPolicy(): AxiomAIRedactionPolicy | undefined {\n return (globalThis as any)[AXIOM_AI_REDACTION_KEY];\n}\n\n/**\n * Resolves the effective redaction policy by merging global and per-call policies.\n * Per-call policies take precedence over global policies.\n *\n * @param globalPolicy - The global redaction policy from initAxiomAI\n * @param localPolicy - The per-call redaction policy from withSpan or middleware\n * @returns The effective redaction policy with all fields resolved\n */\nfunction getEffectiveRedactionPolicy(\n globalPolicy?: AxiomAIRedactionPolicy,\n localPolicy?: AxiomAIRedactionPolicy,\n): AxiomAIRedactionPolicy {\n // Per-call policy overrides global policy, with defaults\n return {\n captureMessageContent:\n localPolicy?.captureMessageContent ??\n globalPolicy?.captureMessageContent ??\n RedactionPolicy.AxiomDefault.captureMessageContent,\n mirrorToolPayloadOnToolSpan:\n localPolicy?.mirrorToolPayloadOnToolSpan ??\n globalPolicy?.mirrorToolPayloadOnToolSpan ??\n RedactionPolicy.AxiomDefault.mirrorToolPayloadOnToolSpan,\n };\n}\n\n/**\n * Get the active redaction policy\n */\nexport function getRedactionPolicy() {\n return getEffectiveRedactionPolicy(getGlobalRedactionPolicy(), getPerCallRedactionPolicy());\n}\n\n/**\n * Conditionally sets a span attribute based on the capture message content policy.\n * When policy is 'off', the attribute is not set at all.\n *\n * @param span - The OpenTelemetry span to set the attribute on\n * @param attribute - The attribute name/key\n * @param value - The attribute value\n * @param captureMessageContent - The capture policy ('full' sets attribute, 'off' skips it)\n */\nexport function handleMaybeRedactedAttribute(\n span: Span,\n attribute: string,\n value: any,\n captureMessageContent?: CaptureMessageContent,\n): void {\n if (captureMessageContent === 'full') {\n span.setAttribute(attribute, value);\n }\n\n // For 'off', don't set the attribute at all\n // Future: Could add callback-based redaction here\n}\n\n/**\n * Extracts the per-call redaction policy from OpenTelemetry baggage context.\n * This allows middleware and tools to access redaction policies passed via withSpan.\n *\n * @returns The per-call redaction policy or undefined if not set\n */\nfunction getPerCallRedactionPolicy(): AxiomAIRedactionPolicy | undefined {\n const baggage: Baggage = propagation.getBaggage(context.active()) || propagation.createBaggage();\n const serializedPolicy = baggage.getEntry(WITHSPAN_REDACTION_POLICY_KEY)?.value;\n\n if (!serializedPolicy) {\n return undefined;\n }\n\n try {\n return JSON.parse(serializedPolicy) as AxiomAIRedactionPolicy;\n } catch (error) {\n console.warn('[AxiomAI] Failed to parse redaction policy from baggage:', error);\n return undefined;\n }\n}\n","/**\n * We need a way to know that we're inside `withSpan`\n * Because we don't own `generateText` and similar functions,\n * we use OTel Baggage to propagate this information. Another\n * consideration might be to use AsyncLocalStorage in Node and\n * some kind of KV in workerd.\n */\nexport const WITHSPAN_BAGGAGE_KEY = '__withspan_gen_ai_call';\nexport const WITHSPAN_REDACTION_POLICY_KEY = '__withspan_redaction_policy';\n","import type { Tracer } from '@opentelemetry/api';\nimport { trace } from '@opentelemetry/api';\nimport packageJson from '../../package.json';\nimport { AXIOM_AI_REDACTION_KEY, type AxiomAIRedactionPolicy } from './utils/redaction';\n\n// Global key to store tracer scope information across all execution contexts\nconst AXIOM_AI_SCOPE_KEY = Symbol.for('__axiom_ai_scope__');\n\ninterface TracerScope {\n name: string;\n version?: string;\n}\n\n/**\n * Extract scope information from a tracer, with fallback to package.json\n */\nfunction extractTracerScope(tracer: Tracer): TracerScope {\n const tracerAny = tracer as any;\n\n // Guard access to private fields with optional chaining\n // Note: These are internal OTEL fields that may change in future versions\n // _instrumentationScope is modern, instrumentationLibrary is legacy (<1.16)\n const name =\n tracerAny._instrumentationScope?.name ||\n tracerAny.instrumentationLibrary?.name ||\n packageJson.name;\n\n const version =\n tracerAny._instrumentationScope?.version ||\n tracerAny.instrumentationLibrary?.version ||\n packageJson.version;\n\n return { name, version };\n}\n\n/**\n * Register this in your `instrumentation.ts` to set up axiom.\n * This function stores the tracer's scope information globally to enable Context Propagation\n * and Instrumentation Scope. The tracer will be available across all execution contexts including Next.js.\n *\n * This function is idempotent - calling it multiple times with the same scope has no additional cost.\n *\n * @param config\n * @param config.tracer - The tracer that you are using in your application.\n * @param config.redactionPolicy - Optional redaction policy to control what data is captured in spans.\n */\nexport function initAxiomAI(config: { tracer: Tracer; redactionPolicy?: AxiomAIRedactionPolicy }) {\n const newScope = extractTracerScope(config.tracer);\n const existingScope = (globalThis as any)[AXIOM_AI_SCOPE_KEY] as TracerScope | undefined;\n\n // Check if already initialized with same scope (idempotent behavior)\n if (\n existingScope &&\n existingScope.name === newScope.name &&\n existingScope.version === newScope.version\n ) {\n return;\n }\n\n // Warn about double initialization with different scopes\n if (existingScope) {\n console.warn(\n '[AxiomAI] initAxiomAI() called multiple times with different scopes. ' +\n `Previous: ${existingScope.name}@${existingScope.version}, ` +\n `New: ${newScope.name}@${newScope.version}`,\n );\n }\n\n // Store scope information globally (works across Next.js contexts)\n (globalThis as any)[AXIOM_AI_SCOPE_KEY] = newScope;\n\n // Store redaction policy globally if provided\n if (config.redactionPolicy) {\n (globalThis as any)[AXIOM_AI_REDACTION_KEY] = config.redactionPolicy;\n }\n}\n\n/**\n * Get a tracer using the globally stored scope information\n * Fall back to package.json defaults if not set\n */\nexport function getGlobalTracer(): Tracer {\n // Get stored scope information or fall back to package defaults\n const scope = (globalThis as any)[AXIOM_AI_SCOPE_KEY] as TracerScope | undefined;\n\n // Warn if initAxiomAI was never called\n if (!scope) {\n const isDebug = process.env.AXIOM_DEBUG === 'true';\n if (!isDebug) {\n console.warn(\n '[AxiomAI] AXIOM_AI_SCOPE_KEY is undefined. This probably means that ' +\n 'initAxiomAI() was never called. ' +\n 'Make sure to call initAxiomAI({ tracer }) in your instrumentation setup.',\n );\n }\n }\n\n let { name, version } = scope || { name: packageJson.name, version: packageJson.version };\n\n if (!name || !version) {\n name = packageJson.name;\n version = packageJson.version;\n if (!name || !version) {\n name = 'axiom';\n version = 'unknown';\n }\n }\n\n // Use OpenTelemetry's standard global provider mechanism\n return trace.getTracer(name, version);\n}\n\n/**\n * Reset AxiomAI configuration (useful for testing)\n */\nexport function resetAxiomAI() {\n (globalThis as any)[AXIOM_AI_SCOPE_KEY] = undefined;\n (globalThis as any)[AXIOM_AI_REDACTION_KEY] = undefined;\n}\n","{\n \"name\": \"axiom\",\n \"version\": \"0.44.0\",\n \"type\": \"module\",\n \"author\": \"Axiom, Inc.\",\n \"contributors\": [\n \"Islam Shehata <islam@axiom.co>\",\n \"Chris Ehrlich <chris@axiom.co>\",\n \"Gabriel de Andrade <gabriel@axiom.co>\"\n ],\n \"scripts\": {\n \"dev\": \"tsup --watch\",\n \"build\": \"tsup && chmod +x dist/bin.js && pnpm check:vitest-entrypoints\",\n \"check:vitest-entrypoints\": \"node ./scripts/check-vitest-entrypoints.mjs\",\n \"format\": \"prettier --write .\",\n \"format:check\": \"prettier --check .\",\n \"lint\": \"eslint './**/*.{js,ts}'\",\n \"typecheck\": \"tsc --noEmit\",\n \"test\": \"vitest run\",\n \"test:watch\": \"vitest --watch\",\n \"publint\": \"npx publint\"\n },\n \"types\": \"./dist/index.d.ts\",\n \"main\": \"./dist/index.cjs\",\n \"module\": \"./dist/index.js\",\n \"bin\": {\n \"axiom\": \"./dist/bin.js\"\n },\n \"exports\": {\n \"./ai\": {\n \"import\": {\n \"types\": \"./dist/index.d.ts\",\n \"default\": \"./dist/index.js\"\n },\n \"require\": {\n \"types\": \"./dist/index.d.cts\",\n \"default\": \"./dist/index.cjs\"\n }\n },\n \"./ai/evals\": {\n \"import\": {\n \"types\": \"./dist/evals.d.ts\",\n \"default\": \"./dist/evals.js\"\n },\n \"require\": {\n \"types\": \"./dist/evals.d.cts\",\n \"default\": \"./dist/evals.cjs\"\n }\n },\n \"./ai/evals/aggregations\": {\n \"import\": {\n \"types\": \"./dist/evals/aggregations.d.ts\",\n \"default\": \"./dist/evals/aggregations.js\"\n },\n \"require\": {\n \"types\": \"./dist/evals/aggregations.d.cts\",\n \"default\": \"./dist/evals/aggregations.cjs\"\n }\n },\n \"./ai/evals/scorers\": {\n \"import\": {\n \"types\": \"./dist/evals/scorers.d.ts\",\n \"default\": \"./dist/evals/scorers.js\"\n },\n \"require\": {\n \"types\": \"./dist/evals/scorers.d.cts\",\n \"default\": \"./dist/evals/scorers.cjs\"\n }\n },\n \"./ai/evals/online\": {\n \"import\": {\n \"types\": \"./dist/evals/online.d.ts\",\n \"default\": \"./dist/evals/online.js\"\n },\n \"require\": {\n \"types\": \"./dist/evals/online.d.cts\",\n \"default\": \"./dist/evals/online.cjs\"\n }\n },\n \"./ai/config\": {\n \"import\": {\n \"types\": \"./dist/config.d.ts\",\n \"default\": \"./dist/config.js\"\n },\n \"require\": {\n \"types\": \"./dist/config.d.cts\",\n \"default\": \"./dist/config.cjs\"\n }\n },\n \"./ai/feedback\": {\n \"import\": {\n \"types\": \"./dist/feedback.d.ts\",\n \"default\": \"./dist/feedback.js\"\n },\n \"require\": {\n \"types\": \"./dist/feedback.d.cts\",\n \"default\": \"./dist/feedback.cjs\"\n }\n }\n },\n \"keywords\": [\n \"axiom\",\n \"logging\",\n \"ai\",\n \"otel\",\n \"opentelemetry\"\n ],\n \"repository\": {\n \"type\": \"git\",\n \"url\": \"git+https://github.com/axiomhq/ai.git\",\n \"directory\": \"packages/ai\"\n },\n \"license\": \"MIT\",\n \"dependencies\": {\n \"@next/env\": \"^15.4.2\",\n \"@opentelemetry/auto-instrumentations-node\": \"^0.60.1\",\n \"@opentelemetry/context-async-hooks\": \"^2.0.1\",\n \"@opentelemetry/exporter-trace-otlp-http\": \"^0.202.0\",\n \"@opentelemetry/resources\": \"^2.0.1\",\n \"@opentelemetry/sdk-trace-node\": \"^2.0.1\",\n \"@opentelemetry/semantic-conventions\": \"^1.38.0\",\n \"@sinclair/typebox\": \"^0.34.37\",\n \"c12\": \"^3.3.3\",\n \"commander\": \"^14.0.0\",\n \"defu\": \"^6.1.4\",\n \"handlebars\": \"^4.7.8\",\n \"nanoid\": \"^5.1.5\",\n \"open\": \"^10.1.0\",\n \"vite-tsconfig-paths\": \"^5.1.4\",\n \"vitest\": \"^4.0.0\"\n },\n \"peerDependencies\": {\n \"@opentelemetry/api\": \"^1.9.0\",\n \"zod\": \"^3.25.0 || ^4.0.0\"\n },\n \"devDependencies\": {\n \"@ai-sdk/anthropicv1\": \"npm:@ai-sdk/anthropic@^1.2.12\",\n \"@ai-sdk/anthropicv2\": \"npm:@ai-sdk/anthropic@^2.0.57\",\n \"@ai-sdk/anthropicv3\": \"npm:@ai-sdk/anthropic@^3.0.9\",\n \"@ai-sdk/openaiv1\": \"npm:@ai-sdk/openai@^1.3.24\",\n \"@ai-sdk/openaiv2\": \"npm:@ai-sdk/openai@^2.0.88\",\n \"@ai-sdk/openaiv3\": \"npm:@ai-sdk/openai@^3.0.7\",\n \"@ai-sdk/providerv1\": \"npm:@ai-sdk/provider@^1.1.3\",\n \"@ai-sdk/providerv2\": \"npm:@ai-sdk/provider@^2.0.1\",\n \"@ai-sdk/providerv3\": \"npm:@ai-sdk/provider@^3.0.2\",\n \"@opentelemetry/api\": \"^1.9.0\",\n \"@opentelemetry/core\": \"^2.0.1\",\n \"@opentelemetry/sdk-trace-base\": \"^2.0.1\",\n \"@opentelemetry/sdk-trace-node\": \"^2.0.1\",\n \"@repo/eslint-config\": \"workspace:*\",\n \"@types/node\": \"^22.15.29\",\n \"@vitest/coverage-v8\": \"^4.0.0\",\n \"aiv4\": \"npm:ai@^4.3.19\",\n \"aiv5\": \"npm:ai@^5.0.118\",\n \"aiv6\": \"npm:ai@^6.0.6\",\n \"esbuild\": \"^0.25.8\",\n \"eslint\": \"catalog:\",\n \"msw\": \"^2.12.2\",\n \"prettier\": \"catalog:\",\n \"tinyrainbow\": \"^2.0.0\",\n \"tsup\": \"catalog:\",\n \"typescript\": \"catalog:\",\n \"vitest\": \"catalog:\",\n \"zod\": \"catalog:\"\n },\n \"files\": [\n \"dist\"\n ],\n \"packageManager\": \"pnpm@10.16.1\"\n}\n"],"mappings":"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","names":[]}
1
+ {"version":3,"sources":["../src/otel/utils/redaction.ts","../src/otel/withSpanBaggageKey.ts","../src/otel/initAxiomAI.ts","../package.json"],"sourcesContent":["import { context, propagation, type Baggage, type Span } from '@opentelemetry/api';\nimport { WITHSPAN_REDACTION_POLICY_KEY } from '../withSpanBaggageKey';\n\ntype CaptureMessageContent = 'full' | 'off';\n\nexport type AxiomAIRedactionPolicy = {\n captureMessageContent?: CaptureMessageContent;\n mirrorToolPayloadOnToolSpan?: boolean;\n};\n\nexport const RedactionPolicy = {\n /**\n * Includes message content on chat spans, and mirrors tool\n * payload on tool spans for more convenient querying.\n */\n AxiomDefault: {\n captureMessageContent: 'full',\n mirrorToolPayloadOnToolSpan: true,\n },\n /**\n * Redacts message content on chat spans, and does not put\n * tool payload on tool spans.\n */\n OpenTelemetryDefault: {\n captureMessageContent: 'off',\n mirrorToolPayloadOnToolSpan: false,\n },\n} as const satisfies Record<string, AxiomAIRedactionPolicy>;\n\n// Global key to store redaction policy across all execution contexts\nexport const AXIOM_AI_REDACTION_KEY = Symbol.for('__axiom_ai_redaction__');\n\n/**\n * Get the globally stored redaction policy\n * @returns The global redaction policy or undefined if not set\n */\nfunction getGlobalRedactionPolicy(): AxiomAIRedactionPolicy | undefined {\n return (globalThis as any)[AXIOM_AI_REDACTION_KEY];\n}\n\n/**\n * Resolves the effective redaction policy by merging global and per-call policies.\n * Per-call policies take precedence over global policies.\n *\n * @param globalPolicy - The global redaction policy from initAxiomAI\n * @param localPolicy - The per-call redaction policy from withSpan or middleware\n * @returns The effective redaction policy with all fields resolved\n */\nfunction getEffectiveRedactionPolicy(\n globalPolicy?: AxiomAIRedactionPolicy,\n localPolicy?: AxiomAIRedactionPolicy,\n): AxiomAIRedactionPolicy {\n // Per-call policy overrides global policy, with defaults\n return {\n captureMessageContent:\n localPolicy?.captureMessageContent ??\n globalPolicy?.captureMessageContent ??\n RedactionPolicy.AxiomDefault.captureMessageContent,\n mirrorToolPayloadOnToolSpan:\n localPolicy?.mirrorToolPayloadOnToolSpan ??\n globalPolicy?.mirrorToolPayloadOnToolSpan ??\n RedactionPolicy.AxiomDefault.mirrorToolPayloadOnToolSpan,\n };\n}\n\n/**\n * Get the active redaction policy\n */\nexport function getRedactionPolicy() {\n return getEffectiveRedactionPolicy(getGlobalRedactionPolicy(), getPerCallRedactionPolicy());\n}\n\n/**\n * Conditionally sets a span attribute based on the capture message content policy.\n * When policy is 'off', the attribute is not set at all.\n *\n * @param span - The OpenTelemetry span to set the attribute on\n * @param attribute - The attribute name/key\n * @param value - The attribute value\n * @param captureMessageContent - The capture policy ('full' sets attribute, 'off' skips it)\n */\nexport function handleMaybeRedactedAttribute(\n span: Span,\n attribute: string,\n value: any,\n captureMessageContent?: CaptureMessageContent,\n): void {\n if (captureMessageContent === 'full') {\n span.setAttribute(attribute, value);\n }\n\n // For 'off', don't set the attribute at all\n // Future: Could add callback-based redaction here\n}\n\n/**\n * Extracts the per-call redaction policy from OpenTelemetry baggage context.\n * This allows middleware and tools to access redaction policies passed via withSpan.\n *\n * @returns The per-call redaction policy or undefined if not set\n */\nfunction getPerCallRedactionPolicy(): AxiomAIRedactionPolicy | undefined {\n const baggage: Baggage = propagation.getBaggage(context.active()) || propagation.createBaggage();\n const serializedPolicy = baggage.getEntry(WITHSPAN_REDACTION_POLICY_KEY)?.value;\n\n if (!serializedPolicy) {\n return undefined;\n }\n\n try {\n return JSON.parse(serializedPolicy) as AxiomAIRedactionPolicy;\n } catch (error) {\n console.warn('[AxiomAI] Failed to parse redaction policy from baggage:', error);\n return undefined;\n }\n}\n","/**\n * We need a way to know that we're inside `withSpan`\n * Because we don't own `generateText` and similar functions,\n * we use OTel Baggage to propagate this information. Another\n * consideration might be to use AsyncLocalStorage in Node and\n * some kind of KV in workerd.\n */\nexport const WITHSPAN_BAGGAGE_KEY = '__withspan_gen_ai_call';\nexport const WITHSPAN_REDACTION_POLICY_KEY = '__withspan_redaction_policy';\n","import type { Tracer } from '@opentelemetry/api';\nimport { trace } from '@opentelemetry/api';\nimport packageJson from '../../package.json';\nimport { AXIOM_AI_REDACTION_KEY, type AxiomAIRedactionPolicy } from './utils/redaction';\n\n// Global key to store tracer scope information across all execution contexts\nconst AXIOM_AI_SCOPE_KEY = Symbol.for('__axiom_ai_scope__');\n\ninterface TracerScope {\n name: string;\n version?: string;\n}\n\n/**\n * Extract scope information from a tracer, with fallback to package.json\n */\nfunction extractTracerScope(tracer: Tracer): TracerScope {\n const tracerAny = tracer as any;\n\n // Guard access to private fields with optional chaining\n // Note: These are internal OTEL fields that may change in future versions\n // _instrumentationScope is modern, instrumentationLibrary is legacy (<1.16)\n const name =\n tracerAny._instrumentationScope?.name ||\n tracerAny.instrumentationLibrary?.name ||\n packageJson.name;\n\n const version =\n tracerAny._instrumentationScope?.version ||\n tracerAny.instrumentationLibrary?.version ||\n packageJson.version;\n\n return { name, version };\n}\n\n/**\n * Register this in your `instrumentation.ts` to set up axiom.\n * This function stores the tracer's scope information globally to enable Context Propagation\n * and Instrumentation Scope. The tracer will be available across all execution contexts including Next.js.\n *\n * This function is idempotent - calling it multiple times with the same scope has no additional cost.\n *\n * @param config\n * @param config.tracer - The tracer that you are using in your application.\n * @param config.redactionPolicy - Optional redaction policy to control what data is captured in spans.\n */\nexport function initAxiomAI(config: { tracer: Tracer; redactionPolicy?: AxiomAIRedactionPolicy }) {\n const newScope = extractTracerScope(config.tracer);\n const existingScope = (globalThis as any)[AXIOM_AI_SCOPE_KEY] as TracerScope | undefined;\n\n // Check if already initialized with same scope (idempotent behavior)\n if (\n existingScope &&\n existingScope.name === newScope.name &&\n existingScope.version === newScope.version\n ) {\n return;\n }\n\n // Warn about double initialization with different scopes\n if (existingScope) {\n console.warn(\n '[AxiomAI] initAxiomAI() called multiple times with different scopes. ' +\n `Previous: ${existingScope.name}@${existingScope.version}, ` +\n `New: ${newScope.name}@${newScope.version}`,\n );\n }\n\n // Store scope information globally (works across Next.js contexts)\n (globalThis as any)[AXIOM_AI_SCOPE_KEY] = newScope;\n\n // Store redaction policy globally if provided\n if (config.redactionPolicy) {\n (globalThis as any)[AXIOM_AI_REDACTION_KEY] = config.redactionPolicy;\n }\n}\n\n/**\n * Get a tracer using the globally stored scope information\n * Fall back to package.json defaults if not set\n */\nexport function getGlobalTracer(): Tracer {\n // Get stored scope information or fall back to package defaults\n const scope = (globalThis as any)[AXIOM_AI_SCOPE_KEY] as TracerScope | undefined;\n\n // Warn if initAxiomAI was never called\n if (!scope) {\n const isDebug = process.env.AXIOM_DEBUG === 'true';\n if (!isDebug) {\n console.warn(\n '[AxiomAI] AXIOM_AI_SCOPE_KEY is undefined. This probably means that ' +\n 'initAxiomAI() was never called. ' +\n 'Make sure to call initAxiomAI({ tracer }) in your instrumentation setup.',\n );\n }\n }\n\n let { name, version } = scope || { name: packageJson.name, version: packageJson.version };\n\n if (!name || !version) {\n name = packageJson.name;\n version = packageJson.version;\n if (!name || !version) {\n name = 'axiom';\n version = 'unknown';\n }\n }\n\n // Use OpenTelemetry's standard global provider mechanism\n return trace.getTracer(name, version);\n}\n\n/**\n * Reset AxiomAI configuration (useful for testing)\n */\nexport function resetAxiomAI() {\n (globalThis as any)[AXIOM_AI_SCOPE_KEY] = undefined;\n (globalThis as any)[AXIOM_AI_REDACTION_KEY] = undefined;\n}\n","{\n \"name\": \"axiom\",\n \"version\": \"0.45.0\",\n \"type\": \"module\",\n \"author\": \"Axiom, Inc.\",\n \"contributors\": [\n \"Islam Shehata <islam@axiom.co>\",\n \"Chris Ehrlich <chris@axiom.co>\",\n \"Gabriel de Andrade <gabriel@axiom.co>\"\n ],\n \"scripts\": {\n \"dev\": \"tsup --watch\",\n \"build\": \"tsup && chmod +x dist/bin.js && pnpm check:vitest-entrypoints\",\n \"check:vitest-entrypoints\": \"node ./scripts/check-vitest-entrypoints.mjs\",\n \"format\": \"prettier --write .\",\n \"format:check\": \"prettier --check .\",\n \"lint\": \"eslint './**/*.{js,ts}'\",\n \"typecheck\": \"tsc --noEmit\",\n \"test\": \"vitest run\",\n \"test:watch\": \"vitest --watch\",\n \"publint\": \"npx publint\"\n },\n \"types\": \"./dist/index.d.ts\",\n \"main\": \"./dist/index.cjs\",\n \"module\": \"./dist/index.js\",\n \"bin\": {\n \"axiom\": \"./dist/bin.js\"\n },\n \"exports\": {\n \"./ai\": {\n \"import\": {\n \"types\": \"./dist/index.d.ts\",\n \"default\": \"./dist/index.js\"\n },\n \"require\": {\n \"types\": \"./dist/index.d.cts\",\n \"default\": \"./dist/index.cjs\"\n }\n },\n \"./ai/evals\": {\n \"import\": {\n \"types\": \"./dist/evals.d.ts\",\n \"default\": \"./dist/evals.js\"\n },\n \"require\": {\n \"types\": \"./dist/evals.d.cts\",\n \"default\": \"./dist/evals.cjs\"\n }\n },\n \"./ai/evals/aggregations\": {\n \"import\": {\n \"types\": \"./dist/evals/aggregations.d.ts\",\n \"default\": \"./dist/evals/aggregations.js\"\n },\n \"require\": {\n \"types\": \"./dist/evals/aggregations.d.cts\",\n \"default\": \"./dist/evals/aggregations.cjs\"\n }\n },\n \"./ai/evals/scorers\": {\n \"import\": {\n \"types\": \"./dist/evals/scorers.d.ts\",\n \"default\": \"./dist/evals/scorers.js\"\n },\n \"require\": {\n \"types\": \"./dist/evals/scorers.d.cts\",\n \"default\": \"./dist/evals/scorers.cjs\"\n }\n },\n \"./ai/evals/online\": {\n \"import\": {\n \"types\": \"./dist/evals/online.d.ts\",\n \"default\": \"./dist/evals/online.js\"\n },\n \"require\": {\n \"types\": \"./dist/evals/online.d.cts\",\n \"default\": \"./dist/evals/online.cjs\"\n }\n },\n \"./ai/config\": {\n \"import\": {\n \"types\": \"./dist/config.d.ts\",\n \"default\": \"./dist/config.js\"\n },\n \"require\": {\n \"types\": \"./dist/config.d.cts\",\n \"default\": \"./dist/config.cjs\"\n }\n },\n \"./ai/feedback\": {\n \"import\": {\n \"types\": \"./dist/feedback.d.ts\",\n \"default\": \"./dist/feedback.js\"\n },\n \"require\": {\n \"types\": \"./dist/feedback.d.cts\",\n \"default\": \"./dist/feedback.cjs\"\n }\n }\n },\n \"keywords\": [\n \"axiom\",\n \"logging\",\n \"ai\",\n \"otel\",\n \"opentelemetry\"\n ],\n \"repository\": {\n \"type\": \"git\",\n \"url\": \"git+https://github.com/axiomhq/ai.git\",\n \"directory\": \"packages/ai\"\n },\n \"license\": \"MIT\",\n \"dependencies\": {\n \"@next/env\": \"^15.4.2\",\n \"@opentelemetry/auto-instrumentations-node\": \"^0.60.1\",\n \"@opentelemetry/context-async-hooks\": \"^2.0.1\",\n \"@opentelemetry/exporter-trace-otlp-http\": \"^0.202.0\",\n \"@opentelemetry/resources\": \"^2.0.1\",\n \"@opentelemetry/sdk-trace-node\": \"^2.0.1\",\n \"@opentelemetry/semantic-conventions\": \"^1.38.0\",\n \"@sinclair/typebox\": \"^0.34.37\",\n \"c12\": \"^3.3.3\",\n \"commander\": \"^14.0.0\",\n \"defu\": \"^6.1.4\",\n \"handlebars\": \"^4.7.8\",\n \"nanoid\": \"^5.1.5\",\n \"open\": \"^10.1.0\",\n \"vite-tsconfig-paths\": \"^5.1.4\",\n \"vitest\": \"^4.0.0\"\n },\n \"peerDependencies\": {\n \"@opentelemetry/api\": \"^1.9.0\",\n \"zod\": \"^3.25.0 || ^4.0.0\"\n },\n \"devDependencies\": {\n \"@ai-sdk/anthropicv1\": \"npm:@ai-sdk/anthropic@^1.2.12\",\n \"@ai-sdk/anthropicv2\": \"npm:@ai-sdk/anthropic@^2.0.57\",\n \"@ai-sdk/anthropicv3\": \"npm:@ai-sdk/anthropic@^3.0.9\",\n \"@ai-sdk/openaiv1\": \"npm:@ai-sdk/openai@^1.3.24\",\n \"@ai-sdk/openaiv2\": \"npm:@ai-sdk/openai@^2.0.88\",\n \"@ai-sdk/openaiv3\": \"npm:@ai-sdk/openai@^3.0.7\",\n \"@ai-sdk/providerv1\": \"npm:@ai-sdk/provider@^1.1.3\",\n \"@ai-sdk/providerv2\": \"npm:@ai-sdk/provider@^2.0.1\",\n \"@ai-sdk/providerv3\": \"npm:@ai-sdk/provider@^3.0.2\",\n \"@opentelemetry/api\": \"^1.9.0\",\n \"@opentelemetry/core\": \"^2.0.1\",\n \"@opentelemetry/sdk-trace-base\": \"^2.0.1\",\n \"@opentelemetry/sdk-trace-node\": \"^2.0.1\",\n \"@repo/eslint-config\": \"workspace:*\",\n \"@types/node\": \"^22.15.29\",\n \"@vitest/coverage-v8\": \"^4.0.0\",\n \"aiv4\": \"npm:ai@^4.3.19\",\n \"aiv5\": \"npm:ai@^5.0.118\",\n \"aiv6\": \"npm:ai@^6.0.6\",\n \"esbuild\": \"^0.25.8\",\n \"eslint\": \"catalog:\",\n \"msw\": \"^2.12.2\",\n \"prettier\": \"catalog:\",\n \"tinyrainbow\": \"^2.0.0\",\n \"tsup\": \"catalog:\",\n \"typescript\": \"catalog:\",\n \"vitest\": \"catalog:\",\n \"zod\": \"catalog:\"\n },\n \"files\": [\n \"dist\"\n ],\n \"packageManager\": \"pnpm@10.16.1\"\n}\n"],"mappings":"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","names":[]}
@@ -2,19 +2,19 @@ import {
2
2
  getConsoleUrl,
3
3
  loadConfig,
4
4
  u
5
- } from "./chunk-56V2A6IW.js";
5
+ } from "./chunk-RSHQRY3F.js";
6
6
  import {
7
7
  dotNotationToNested,
8
8
  flattenObject,
9
9
  getAxiomConfig
10
- } from "./chunk-7NTVK3F4.js";
10
+ } from "./chunk-R4CARCOX.js";
11
11
  import {
12
12
  AxiomCLIError,
13
13
  errorToString
14
14
  } from "./chunk-S65FSMB3.js";
15
15
  import {
16
16
  initAxiomAI
17
- } from "./chunk-HW6E4M7S.js";
17
+ } from "./chunk-N3RHEQMQ.js";
18
18
  import {
19
19
  __publicField,
20
20
  init_esm_shims
@@ -656,11 +656,11 @@ function setupEvalProvider(connection) {
656
656
  axiomProvider = new NodeTracerProvider({
657
657
  resource: resourceFromAttributes({
658
658
  ["service.name"]: "axiom",
659
- ["service.version"]: "0.44.0"
659
+ ["service.version"]: "0.45.0"
660
660
  }),
661
661
  spanProcessors: [processor]
662
662
  });
663
- axiomTracer = axiomProvider.getTracer("axiom", "0.44.0");
663
+ axiomTracer = axiomProvider.getTracer("axiom", "0.45.0");
664
664
  }
665
665
  async function initInstrumentation(config) {
666
666
  if (initialized) {
@@ -672,7 +672,7 @@ async function initInstrumentation(config) {
672
672
  }
673
673
  initializationPromise = (async () => {
674
674
  if (!config.enabled) {
675
- axiomTracer = trace.getTracer("axiom", "0.44.0");
675
+ axiomTracer = trace.getTracer("axiom", "0.45.0");
676
676
  initialized = true;
677
677
  return;
678
678
  }
@@ -787,4 +787,4 @@ export {
787
787
  startSpan,
788
788
  startActiveSpan
789
789
  };
790
- //# sourceMappingURL=chunk-U3JDCQ3Y.js.map
790
+ //# sourceMappingURL=chunk-QAIGRB75.js.map
@@ -8,7 +8,7 @@ import {
8
8
  getRedactionPolicy,
9
9
  handleMaybeRedactedAttribute,
10
10
  package_default
11
- } from "./chunk-HW6E4M7S.js";
11
+ } from "./chunk-N3RHEQMQ.js";
12
12
  import {
13
13
  Attr
14
14
  } from "./chunk-TWE3LIRZ.js";
@@ -3128,4 +3128,4 @@ export {
3128
3128
  withEvalContext,
3129
3129
  getConfigScope
3130
3130
  };
3131
- //# sourceMappingURL=chunk-7NTVK3F4.js.map
3131
+ //# sourceMappingURL=chunk-R4CARCOX.js.map
@@ -16,7 +16,7 @@ import {
16
16
  putOnSpan,
17
17
  setGlobalFlagOverrides,
18
18
  withEvalContext
19
- } from "./chunk-7NTVK3F4.js";
19
+ } from "./chunk-R4CARCOX.js";
20
20
  import {
21
21
  AxiomCLIError,
22
22
  errorToString
@@ -437,7 +437,7 @@ var loadEvalCommand = (program, flagOverrides = {}) => {
437
437
  consoleUrl = options.consoleUrl;
438
438
  let runVitestModule;
439
439
  try {
440
- runVitestModule = await import("./run-vitest-4OEEDEHV.js");
440
+ runVitestModule = await import("./run-vitest-SYYO32TD.js");
441
441
  } catch (err) {
442
442
  if (err && typeof err === "object" && "code" in err && (err.code === "ERR_MODULE_NOT_FOUND" || err.code === "MODULE_NOT_FOUND")) {
443
443
  throw new AxiomCLIError("Failed to load vitest.");
@@ -480,4 +480,4 @@ export {
480
480
  getConsoleUrl,
481
481
  loadEvalCommand
482
482
  };
483
- //# sourceMappingURL=chunk-56V2A6IW.js.map
483
+ //# sourceMappingURL=chunk-RSHQRY3F.js.map
@@ -1,6 +1,9 @@
1
1
  import {
2
2
  getGlobalTracer
3
- } from "./chunk-HW6E4M7S.js";
3
+ } from "./chunk-N3RHEQMQ.js";
4
+ import {
5
+ normalizeBooleanScore
6
+ } from "./chunk-3Q36GUCI.js";
4
7
  import {
5
8
  Attr
6
9
  } from "./chunk-TWE3LIRZ.js";
@@ -16,16 +19,17 @@ import { context as context2, trace as trace2, SpanStatusCode as SpanStatusCode2
16
19
  init_esm_shims();
17
20
  import { context, trace, SpanStatusCode } from "@opentelemetry/api";
18
21
  function setScorerSpanAttrs(scorerSpan, scorerName, result, meta) {
22
+ const { score: scoreValue, metadata } = normalizeBooleanScore(result.score, result.metadata);
19
23
  const attrs = {
20
24
  [Attr.GenAI.Operation.Name]: "eval.score",
21
25
  [Attr.Eval.Score.Name]: scorerName,
22
26
  [Attr.Eval.Tags]: JSON.stringify(["online"]),
23
- [Attr.Eval.Score.Value]: result.score ?? void 0,
27
+ [Attr.Eval.Score.Value]: scoreValue ?? void 0,
24
28
  [Attr.Eval.Capability.Name]: meta?.capability,
25
29
  [Attr.Eval.Step.Name]: meta?.step
26
30
  };
27
- if (result.metadata && Object.keys(result.metadata).length > 0) {
28
- attrs[Attr.Eval.Score.Metadata] = JSON.stringify(result.metadata);
31
+ if (metadata && Object.keys(metadata).length > 0) {
32
+ attrs[Attr.Eval.Score.Metadata] = JSON.stringify(metadata);
29
33
  }
30
34
  scorerSpan.setAttributes(attrs);
31
35
  }
@@ -129,15 +133,16 @@ function onlineEval(meta, options) {
129
133
  if (options.scorers.length === 0) {
130
134
  return Promise.resolve({});
131
135
  }
132
- const linkSpanContext = meta.link ?? trace2.getSpan(context2.active())?.spanContext();
133
- return executeOnlineEvalInternal(meta, options, linkSpanContext);
136
+ const rawLinks = meta.links ?? trace2.getSpan(context2.active())?.spanContext();
137
+ const linkContexts = rawLinks ? Array.isArray(rawLinks) ? rawLinks : [rawLinks] : [];
138
+ return executeOnlineEvalInternal(meta, options, linkContexts);
134
139
  }
135
- async function executeOnlineEvalInternal(meta, options, linkSpanContext) {
140
+ async function executeOnlineEvalInternal(meta, options, linkContexts) {
136
141
  const tracer = getGlobalTracer();
137
142
  const spanName = meta.step ? `eval ${meta.capability}/${meta.step}` : `eval ${meta.capability}`;
138
143
  const evalSpan = tracer.startSpan(
139
144
  spanName,
140
- linkSpanContext ? { links: [{ context: linkSpanContext }] } : {}
145
+ linkContexts.length > 0 ? { links: linkContexts.map((ctx) => ({ context: ctx })) } : {}
141
146
  );
142
147
  const evalAttrs = {
143
148
  [Attr.GenAI.Operation.Name]: "eval",
@@ -206,7 +211,17 @@ async function executeOnlineEvalInternal(meta, options, linkSpanContext) {
206
211
  }
207
212
  const failedCount = Object.values(results).filter((result) => result.error).length;
208
213
  const ranCount = Object.keys(results).length;
214
+ const scoresSummary = {};
215
+ for (const [name, result] of Object.entries(results)) {
216
+ scoresSummary[name] = {
217
+ name: result.name,
218
+ score: result.score,
219
+ ...result.metadata && Object.keys(result.metadata).length > 0 && { metadata: result.metadata },
220
+ ...result.error && { error: result.error }
221
+ };
222
+ }
209
223
  evalSpan.setAttributes({
224
+ [Attr.Eval.Case.Scores]: JSON.stringify(scoresSummary),
210
225
  "axiom.eval.online.scorers.total": normalizedScorers.length,
211
226
  "axiom.eval.online.scorers.ran": ranCount,
212
227
  "axiom.eval.online.scorers.sampled_out": sampledOutCount,
@@ -237,4 +252,4 @@ async function executeOnlineEvalInternal(meta, options, linkSpanContext) {
237
252
  export {
238
253
  onlineEval
239
254
  };
240
- //# sourceMappingURL=chunk-AAYRMTT6.js.map
255
+ //# sourceMappingURL=chunk-SGAIMXRV.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/online-evals/onlineEval.ts","../src/online-evals/executor.ts"],"sourcesContent":["import { context, trace, SpanStatusCode, type SpanContext } from '@opentelemetry/api';\nimport { getGlobalTracer } from '../otel/initAxiomAI';\nimport type {\n OnlineEvalScorerEntry,\n OnlineEvalScorerInput,\n SampledOnlineEvalScorer,\n Scorer,\n ScorerResult,\n ScorerSampling,\n} from './types';\nimport { executeScorer } from './executor';\nimport { Attr } from '../otel/semconv/attributes';\n\ntype ScorerEntry<TInput, TOutput> = OnlineEvalScorerEntry<TInput, TOutput, any>;\ntype ScorerInput<TInput, TOutput> = OnlineEvalScorerInput<TInput, TOutput, any>;\n\ntype InferScorerMetadata<TScorerEntry> =\n TScorerEntry extends SampledOnlineEvalScorer<any, any, any>\n ? InferScorerMetadata<TScorerEntry['scorer']>\n : TScorerEntry extends Scorer<any, any, infer TMetadata>\n ? TMetadata\n : TScorerEntry extends ScorerResult<infer TMetadata>\n ? TMetadata\n : never;\n\ntype InferScorerName<TScorerEntry> =\n TScorerEntry extends SampledOnlineEvalScorer<any, any, any>\n ? InferScorerName<TScorerEntry['scorer']>\n : TScorerEntry extends ScorerResult<any>\n ? TScorerEntry['name']\n : TScorerEntry extends Scorer<any, any, any>\n ? string\n : never;\n\ntype IsBroadString<T extends string> = string extends T ? true : false;\n\ntype DuplicateScorerNames<\n TEntries extends readonly unknown[],\n Seen extends string = never,\n Duplicates extends string = never,\n> = TEntries extends readonly [infer Head, ...infer Tail]\n ? InferScorerName<Head> extends infer ScorerName\n ? ScorerName extends string\n ? IsBroadString<ScorerName> extends true\n ? DuplicateScorerNames<Tail extends readonly unknown[] ? Tail : never, Seen, Duplicates>\n : ScorerName extends Seen\n ? DuplicateScorerNames<\n Tail extends readonly unknown[] ? Tail : never,\n Seen,\n Duplicates | ScorerName\n >\n : DuplicateScorerNames<\n Tail extends readonly unknown[] ? Tail : never,\n Seen | ScorerName,\n Duplicates\n >\n : DuplicateScorerNames<Tail extends readonly unknown[] ? Tail : never, Seen, Duplicates>\n : never\n : Duplicates;\n\ntype EnsureUniqueScorerNames<TEntries extends readonly unknown[]> = [\n DuplicateScorerNames<TEntries>,\n] extends [never]\n ? TEntries\n : never & {\n __axiomDuplicateScorerNames__: DuplicateScorerNames<TEntries>;\n };\n\ntype InferOnlineEvalResult<TScorers extends readonly unknown[]> = ScorerResult<\n InferScorerMetadata<TScorers[number]>\n>;\n\ntype InferOnlineEvalResultRecord<TScorers extends readonly unknown[]> = Partial<\n Record<Extract<InferScorerName<TScorers[number]>, string>, InferOnlineEvalResult<TScorers>>\n>;\n\ntype NormalizedScorerEntry<TInput, TOutput> = {\n name: string;\n scorer: ScorerInput<TInput, TOutput>;\n sampling?: ScorerSampling<TInput, TOutput>;\n};\n\n/**\n * Metadata for categorizing online evaluations.\n */\nexport type OnlineEvalMeta = {\n /** High-level capability being evaluated (e.g., 'qa', 'summarization') */\n capability: string;\n /** Specific step within the capability (e.g., 'answer', 'extract') */\n step?: string;\n /**\n * Explicit SpanContext(s) to link the eval span to originating generation span(s).\n * When omitted, the active span's context is used automatically.\n * Use this for deferred evaluation when onlineEval is called after the\n * originating span has completed.\n * Supports both single context and multiple contexts for multi-span linking.\n */\n links?: SpanContext | SpanContext[];\n};\n\n/**\n * Options for online evaluation.\n */\nexport type OnlineEvalOptions<\n TInput,\n TOutput,\n TScorers extends readonly ScorerEntry<TInput, TOutput>[] = readonly ScorerEntry<\n TInput,\n TOutput\n >[],\n> = {\n /** Input to pass to scorers (optional - only needed for input+output scorers) */\n input?: TInput;\n /** Output to evaluate */\n output: TOutput;\n /** Scorers or precomputed scores. Supports optional per-scorer sampling. */\n scorers: EnsureUniqueScorerNames<TScorers>;\n};\n\n/**\n * Determines if an individual scorer should run based on sampling configuration.\n */\nasync function shouldSample<TInput, TOutput>(\n sampling: ScorerSampling<TInput, TOutput> | undefined,\n args: { input?: TInput; output: TOutput },\n): Promise<boolean> {\n if (sampling === undefined) return true;\n if (typeof sampling === 'number') {\n if (sampling >= 1) return true;\n if (sampling <= 0) return false;\n return Math.random() < sampling;\n }\n return Boolean(await sampling(args));\n}\n\nfunction isSampledScorerEntry<TInput, TOutput>(\n entry: ScorerEntry<TInput, TOutput>,\n): entry is SampledOnlineEvalScorer<TInput, TOutput, any> {\n return typeof entry === 'object' && entry !== null && 'scorer' in entry;\n}\n\nfunction resolveScorerName<TInput, TOutput>(scorer: ScorerInput<TInput, TOutput>): string {\n if (typeof scorer === 'function') {\n return scorer.name || 'unknown';\n }\n return scorer.name;\n}\n\nfunction normalizeScorerEntry<TInput, TOutput>(\n entry: ScorerEntry<TInput, TOutput>,\n): NormalizedScorerEntry<TInput, TOutput> {\n if (isSampledScorerEntry(entry)) {\n return {\n name: resolveScorerName(entry.scorer),\n scorer: entry.scorer,\n sampling: entry.sampling,\n };\n }\n\n return {\n name: resolveScorerName(entry),\n scorer: entry,\n };\n}\n\nfunction getDuplicateScorerNames<TInput, TOutput>(\n entries: readonly NormalizedScorerEntry<TInput, TOutput>[],\n): string[] {\n const nameCounts = new Map<string, number>();\n\n for (const entry of entries) {\n nameCounts.set(entry.name, (nameCounts.get(entry.name) ?? 0) + 1);\n }\n\n return [...nameCounts.entries()]\n .filter(([, count]) => count > 1)\n .map(([name]) => name)\n .sort();\n}\n\n/**\n * Run online evaluation scorers against production outputs.\n *\n * Returns a promise that resolves to scorer results. Use `void onlineEval(...)`\n * for fire-and-forget, or `await onlineEval(...)` when you need to wait for\n * completion (e.g., before flushing telemetry in short-lived processes).\n *\n * Each eval span links back to the originating generation span via an\n * OpenTelemetry span link. Parent/child hierarchy follows natural context\n * propagation — inside `withSpan` the eval is a child, outside it depends\n * on the active context.\n *\n * ## Usage Patterns\n *\n * **Inside withSpan (recommended):**\n * Active span is automatically detected and linked.\n * ```ts\n * await withSpan({ capability: 'qa', step: 'answer' }, async () => {\n * const response = await generateText({ ... });\n * void onlineEval(\n * { capability: 'qa', step: 'answer' },\n * { output: response.text, scorers: [formatScorer] }\n * );\n * return response.text;\n * });\n * ```\n *\n * **Deferred evaluation with explicit link:**\n * Pass the originating span's context for linking when evaluating later.\n * Supports single or multiple span contexts.\n * ```ts\n * let spanCtx: SpanContext;\n * const result = await withSpan({ ... }, async (span) => {\n * spanCtx = span.spanContext();\n * return await generateText({ ... });\n * });\n * void onlineEval({ ..., links: spanCtx }, { output: result, scorers });\n *\n * // Or link to multiple spans:\n * void onlineEval({ ..., links: [spanCtx1, spanCtx2] }, { output, scorers });\n * ```\n *\n * **Awaiting for flush (short-lived processes):**\n * ```ts\n * await onlineEval({ ... }, { output, scorers });\n * await flushTelemetry();\n * ```\n *\n * @param meta - Evaluation metadata for categorization\n * @param meta.capability - High-level capability being evaluated\n * @param meta.step - Optional step within the capability\n * @param meta.links - Optional SpanContext(s) to link to (auto-detected if omitted)\n * @param options - Evaluation configuration\n * @param options.input - Input to pass to scorers\n * @param options.output - Output to evaluate\n * @param options.scorers - Scorer entries with optional per-scorer sampling\n * @returns Promise resolving to scorer results keyed by scorer name\n */\nexport function onlineEval<\n TInput,\n TOutput,\n const TScorers extends readonly ScorerEntry<TInput, TOutput>[],\n>(\n meta: OnlineEvalMeta,\n options: OnlineEvalOptions<TInput, TOutput, TScorers>,\n): Promise<InferOnlineEvalResultRecord<TScorers>> {\n if (options.scorers.length === 0) {\n return Promise.resolve({});\n }\n\n const rawLinks = meta.links ?? trace.getSpan(context.active())?.spanContext();\n const linkContexts = rawLinks ? (Array.isArray(rawLinks) ? rawLinks : [rawLinks]) : [];\n\n return executeOnlineEvalInternal(meta, options, linkContexts);\n}\n\nasync function executeOnlineEvalInternal<\n TInput,\n TOutput,\n const TScorers extends readonly ScorerEntry<TInput, TOutput>[],\n>(\n meta: OnlineEvalMeta,\n options: OnlineEvalOptions<TInput, TOutput, TScorers>,\n linkContexts: SpanContext[],\n): Promise<InferOnlineEvalResultRecord<TScorers>> {\n const tracer = getGlobalTracer();\n\n const spanName = meta.step ? `eval ${meta.capability}/${meta.step}` : `eval ${meta.capability}`;\n\n const evalSpan = tracer.startSpan(\n spanName,\n linkContexts.length > 0 ? { links: linkContexts.map((ctx) => ({ context: ctx })) } : {},\n );\n\n const evalAttrs: Record<string, string> = {\n [Attr.GenAI.Operation.Name]: 'eval',\n [Attr.Eval.Capability.Name]: meta.capability,\n [Attr.Eval.Tags]: JSON.stringify(['online']),\n };\n if (meta.step) {\n evalAttrs[Attr.Eval.Step.Name] = meta.step;\n }\n evalSpan.setAttributes(evalAttrs);\n\n try {\n const normalizedScorers = options.scorers.map((entry) => normalizeScorerEntry(entry));\n const duplicateScorerNames = getDuplicateScorerNames(normalizedScorers);\n if (duplicateScorerNames.length > 0) {\n throw new Error(\n `Duplicate scorer names are not allowed: ${duplicateScorerNames\n .map((name) => `\"${name}\"`)\n .join(', ')}`,\n );\n }\n\n const outcomes = await Promise.all(\n normalizedScorers.map(async (entry) => {\n try {\n const sampledIn = await shouldSample(entry.sampling, {\n input: options.input,\n output: options.output,\n });\n\n if (!sampledIn) {\n return { sampledOut: true as const };\n }\n\n return {\n sampledOut: false as const,\n result: await executeScorer(\n entry.scorer,\n options.input,\n options.output,\n evalSpan,\n meta,\n ),\n };\n } catch (err) {\n const error = err instanceof Error ? err : new Error(String(err));\n return {\n sampledOut: false as const,\n result: await executeScorer(\n {\n name: entry.name,\n score: null,\n error: error.message,\n },\n options.input,\n options.output,\n evalSpan,\n meta,\n ),\n };\n }\n }),\n );\n\n const results: Record<string, InferOnlineEvalResult<TScorers>> = {};\n let sampledOutCount = 0;\n\n for (const outcome of outcomes) {\n if (outcome.sampledOut) {\n sampledOutCount += 1;\n continue;\n }\n\n results[outcome.result.name] = outcome.result as InferOnlineEvalResult<TScorers>;\n }\n\n const failedCount = Object.values(results).filter((result) => result.error).length;\n const ranCount = Object.keys(results).length;\n\n const scoresSummary: Record<string, ScorerResult> = {};\n for (const [name, result] of Object.entries(results)) {\n scoresSummary[name] = {\n name: result.name,\n score: result.score,\n ...(result.metadata &&\n Object.keys(result.metadata).length > 0 && { metadata: result.metadata }),\n ...(result.error && { error: result.error }),\n };\n }\n\n evalSpan.setAttributes({\n [Attr.Eval.Case.Scores]: JSON.stringify(scoresSummary),\n 'axiom.eval.online.scorers.total': normalizedScorers.length,\n 'axiom.eval.online.scorers.ran': ranCount,\n 'axiom.eval.online.scorers.sampled_out': sampledOutCount,\n 'axiom.eval.online.scorers.failed': failedCount,\n });\n\n if (failedCount > 0) {\n evalSpan.setStatus({\n code: SpanStatusCode.ERROR,\n message: 'One or more scorers failed',\n });\n } else {\n evalSpan.setStatus({ code: SpanStatusCode.OK });\n }\n\n return results as InferOnlineEvalResultRecord<TScorers>;\n } catch (err) {\n const error = err instanceof Error ? err : new Error(String(err));\n evalSpan.recordException(error);\n evalSpan.setStatus({\n code: SpanStatusCode.ERROR,\n message: error.message,\n });\n return {};\n } finally {\n evalSpan.end();\n }\n}\n","import { context, trace, SpanStatusCode, type Span } from '@opentelemetry/api';\nimport { normalizeBooleanScore } from '../evals/normalize-score';\nimport { getGlobalTracer } from '../otel/initAxiomAI';\nimport type { Scorer, ScorerResult } from './types';\nimport type { OnlineEvalMeta } from './onlineEval';\nimport { Attr } from '../otel/semconv/attributes';\n\ntype OnlineEvalScorerInput<TInput, TOutput> = Scorer<TInput, TOutput, any> | ScorerResult<any>;\n\nfunction setScorerSpanAttrs(\n scorerSpan: Span,\n scorerName: string,\n result: Pick<ScorerResult<any>, 'score' | 'metadata'>,\n meta?: OnlineEvalMeta,\n): void {\n const { score: scoreValue, metadata } = normalizeBooleanScore(result.score, result.metadata);\n\n const attrs: Record<string, string | number | boolean | undefined> = {\n [Attr.GenAI.Operation.Name]: 'eval.score',\n [Attr.Eval.Score.Name]: scorerName,\n [Attr.Eval.Tags]: JSON.stringify(['online']),\n [Attr.Eval.Score.Value]: scoreValue ?? undefined,\n [Attr.Eval.Capability.Name]: meta?.capability,\n [Attr.Eval.Step.Name]: meta?.step,\n };\n\n if (metadata && Object.keys(metadata).length > 0) {\n attrs[Attr.Eval.Score.Metadata] = JSON.stringify(metadata);\n }\n\n scorerSpan.setAttributes(attrs);\n}\n\n/**\n * Executes a single scorer or emits a precomputed scorer result.\n */\nexport async function executeScorer<TInput, TOutput>(\n scorer: OnlineEvalScorerInput<TInput, TOutput>,\n input: TInput | undefined,\n output: TOutput,\n parentSpan: Span,\n meta?: OnlineEvalMeta,\n): Promise<ScorerResult<any>> {\n const tracer = getGlobalTracer();\n const parentContext = trace.setSpan(context.active(), parentSpan);\n\n return context.with(parentContext, async () => {\n const scorerName =\n typeof scorer === 'function'\n ? // undefined/unknown case shouldn't happen, but better safe than sorry\n scorer.name || 'unknown'\n : scorer.name;\n const scorerSpan = tracer.startSpan(`score ${scorerName}`);\n\n try {\n const result =\n typeof scorer === 'function'\n ? ({\n ...(await scorer({\n input,\n output,\n })),\n name: scorerName,\n } satisfies ScorerResult)\n : scorer;\n\n setScorerSpanAttrs(scorerSpan, scorerName, result, meta);\n if (result.error) {\n const error = new Error(result.error);\n scorerSpan.recordException(error);\n scorerSpan.setAttributes({\n [Attr.Error.Message]: error.message,\n [Attr.Error.Type]: error.name,\n });\n scorerSpan.setStatus({\n code: SpanStatusCode.ERROR,\n message: error.message,\n });\n } else {\n scorerSpan.setStatus({ code: SpanStatusCode.OK });\n }\n\n return result;\n } catch (err) {\n const error = err instanceof Error ? err : new Error(String(err));\n const failedResult: ScorerResult = {\n name: scorerName,\n score: null,\n error: error.message,\n };\n\n setScorerSpanAttrs(scorerSpan, scorerName, failedResult, meta);\n\n scorerSpan.recordException(error);\n scorerSpan.setAttributes({\n [Attr.Error.Message]: error.message,\n [Attr.Error.Type]: error.name,\n });\n scorerSpan.setStatus({\n code: SpanStatusCode.ERROR,\n message: error.message,\n });\n\n return failedResult;\n } finally {\n scorerSpan.end();\n }\n });\n}\n"],"mappings":"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","names":["context","trace","SpanStatusCode","trace","context","SpanStatusCode"]}
@@ -33,7 +33,7 @@ var import_api2 = require("@opentelemetry/api");
33
33
  // package.json
34
34
  var package_default = {
35
35
  name: "axiom",
36
- version: "0.44.0",
36
+ version: "0.45.0",
37
37
  type: "module",
38
38
  author: "Axiom, Inc.",
39
39
  contributors: [
@@ -536,18 +536,30 @@ var Attr = {
536
536
  }
537
537
  };
538
538
 
539
+ // src/evals/normalize-score.ts
540
+ function normalizeBooleanScore(score, metadata) {
541
+ if (typeof score !== "boolean") {
542
+ return { score, metadata };
543
+ }
544
+ return {
545
+ score: score ? 1 : 0,
546
+ metadata: { ...metadata, [Attr.Eval.Score.IsBoolean]: true }
547
+ };
548
+ }
549
+
539
550
  // src/online-evals/executor.ts
540
551
  function setScorerSpanAttrs(scorerSpan, scorerName, result, meta) {
552
+ const { score: scoreValue, metadata } = normalizeBooleanScore(result.score, result.metadata);
541
553
  const attrs = {
542
554
  [Attr.GenAI.Operation.Name]: "eval.score",
543
555
  [Attr.Eval.Score.Name]: scorerName,
544
556
  [Attr.Eval.Tags]: JSON.stringify(["online"]),
545
- [Attr.Eval.Score.Value]: result.score ?? void 0,
557
+ [Attr.Eval.Score.Value]: scoreValue ?? void 0,
546
558
  [Attr.Eval.Capability.Name]: meta?.capability,
547
559
  [Attr.Eval.Step.Name]: meta?.step
548
560
  };
549
- if (result.metadata && Object.keys(result.metadata).length > 0) {
550
- attrs[Attr.Eval.Score.Metadata] = JSON.stringify(result.metadata);
561
+ if (metadata && Object.keys(metadata).length > 0) {
562
+ attrs[Attr.Eval.Score.Metadata] = JSON.stringify(metadata);
551
563
  }
552
564
  scorerSpan.setAttributes(attrs);
553
565
  }
@@ -651,15 +663,16 @@ function onlineEval(meta, options) {
651
663
  if (options.scorers.length === 0) {
652
664
  return Promise.resolve({});
653
665
  }
654
- const linkSpanContext = meta.link ?? import_api4.trace.getSpan(import_api4.context.active())?.spanContext();
655
- return executeOnlineEvalInternal(meta, options, linkSpanContext);
666
+ const rawLinks = meta.links ?? import_api4.trace.getSpan(import_api4.context.active())?.spanContext();
667
+ const linkContexts = rawLinks ? Array.isArray(rawLinks) ? rawLinks : [rawLinks] : [];
668
+ return executeOnlineEvalInternal(meta, options, linkContexts);
656
669
  }
657
- async function executeOnlineEvalInternal(meta, options, linkSpanContext) {
670
+ async function executeOnlineEvalInternal(meta, options, linkContexts) {
658
671
  const tracer = getGlobalTracer();
659
672
  const spanName = meta.step ? `eval ${meta.capability}/${meta.step}` : `eval ${meta.capability}`;
660
673
  const evalSpan = tracer.startSpan(
661
674
  spanName,
662
- linkSpanContext ? { links: [{ context: linkSpanContext }] } : {}
675
+ linkContexts.length > 0 ? { links: linkContexts.map((ctx) => ({ context: ctx })) } : {}
663
676
  );
664
677
  const evalAttrs = {
665
678
  [Attr.GenAI.Operation.Name]: "eval",
@@ -728,7 +741,17 @@ async function executeOnlineEvalInternal(meta, options, linkSpanContext) {
728
741
  }
729
742
  const failedCount = Object.values(results).filter((result) => result.error).length;
730
743
  const ranCount = Object.keys(results).length;
744
+ const scoresSummary = {};
745
+ for (const [name, result] of Object.entries(results)) {
746
+ scoresSummary[name] = {
747
+ name: result.name,
748
+ score: result.score,
749
+ ...result.metadata && Object.keys(result.metadata).length > 0 && { metadata: result.metadata },
750
+ ...result.error && { error: result.error }
751
+ };
752
+ }
731
753
  evalSpan.setAttributes({
754
+ [Attr.Eval.Case.Scores]: JSON.stringify(scoresSummary),
732
755
  "axiom.eval.online.scorers.total": normalizedScorers.length,
733
756
  "axiom.eval.online.scorers.ran": ranCount,
734
757
  "axiom.eval.online.scorers.sampled_out": sampledOutCount,