@use-lattice/litmus 0.121.3

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 (199) hide show
  1. package/LICENSE +19 -0
  2. package/dist/src/accounts-Bt1oJb1Z.cjs +219 -0
  3. package/dist/src/accounts-DjOU8Rm3.js +178 -0
  4. package/dist/src/agentic-utils-D03IiXQc.js +153 -0
  5. package/dist/src/agentic-utils-Dh7xaMQM.cjs +180 -0
  6. package/dist/src/agents-C6BIMlZa.js +231 -0
  7. package/dist/src/agents-DvIpNX1L.cjs +666 -0
  8. package/dist/src/agents-ZP0RP9vV.cjs +231 -0
  9. package/dist/src/agents-maJXdjbR.js +665 -0
  10. package/dist/src/aimlapi-BTbQjG2E.cjs +30 -0
  11. package/dist/src/aimlapi-CwMxqfXP.js +30 -0
  12. package/dist/src/audio-BBUdvsde.cjs +97 -0
  13. package/dist/src/audio-D5DPZ7I-.js +97 -0
  14. package/dist/src/base-BEysXrkq.cjs +222 -0
  15. package/dist/src/base-C451JQfq.js +193 -0
  16. package/dist/src/blobs-BY8MDmpo.js +230 -0
  17. package/dist/src/blobs-BgcNn97m.cjs +256 -0
  18. package/dist/src/cache-BBE_lsTA.cjs +4 -0
  19. package/dist/src/cache-BkrqU5Ba.js +237 -0
  20. package/dist/src/cache-DsCxFlsZ.cjs +297 -0
  21. package/dist/src/chat-CPJWDP6a.cjs +289 -0
  22. package/dist/src/chat-CXX3xzkk.cjs +811 -0
  23. package/dist/src/chat-CcDgZFJ4.js +787 -0
  24. package/dist/src/chat-Dz5ZeGO2.js +289 -0
  25. package/dist/src/chatkit-Dw0mKkML.cjs +1158 -0
  26. package/dist/src/chatkit-swAIVuea.js +1157 -0
  27. package/dist/src/chunk-DEq-mXcV.js +15 -0
  28. package/dist/src/claude-agent-sdk-BXZJtOg6.js +379 -0
  29. package/dist/src/claude-agent-sdk-CkfyjDoG.cjs +383 -0
  30. package/dist/src/cloudflare-ai-BzpJcqUH.js +161 -0
  31. package/dist/src/cloudflare-ai-Cmy_R1y2.cjs +161 -0
  32. package/dist/src/cloudflare-gateway-B9tVQKok.cjs +272 -0
  33. package/dist/src/cloudflare-gateway-DrD3ew3H.js +272 -0
  34. package/dist/src/codex-sdk-Dezj9Nwm.js +1056 -0
  35. package/dist/src/codex-sdk-Dl9D4k5B.cjs +1060 -0
  36. package/dist/src/cometapi-C-9YvCHC.js +54 -0
  37. package/dist/src/cometapi-DHgDKoO2.cjs +54 -0
  38. package/dist/src/completion-B8Ctyxpr.js +120 -0
  39. package/dist/src/completion-Cxrt08sj.cjs +131 -0
  40. package/dist/src/createHash-BwgE13yv.cjs +27 -0
  41. package/dist/src/createHash-DmPQkvBh.js +15 -0
  42. package/dist/src/docker-BiqcTwLv.js +80 -0
  43. package/dist/src/docker-C7tEJnP-.cjs +80 -0
  44. package/dist/src/esm-C62Zofr1.cjs +409 -0
  45. package/dist/src/esm-DMVc93eh.js +379 -0
  46. package/dist/src/evalResult-C3NJPQOo.cjs +301 -0
  47. package/dist/src/evalResult-C7JJAPBb.js +295 -0
  48. package/dist/src/evalResult-DoVTZZWI.cjs +2 -0
  49. package/dist/src/extractor-DnMD3fwt.cjs +391 -0
  50. package/dist/src/extractor-DtlL28vL.js +374 -0
  51. package/dist/src/fetch-BTxakTSg.cjs +1133 -0
  52. package/dist/src/fetch-DQckpUFz.js +928 -0
  53. package/dist/src/fileExtensions-DnqA1y9x.js +85 -0
  54. package/dist/src/fileExtensions-bYh77CN8.cjs +114 -0
  55. package/dist/src/genaiTracer-CyZrmaK0.cjs +268 -0
  56. package/dist/src/genaiTracer-D3fD9dNV.js +256 -0
  57. package/dist/src/graders-BNscxFrU.js +13644 -0
  58. package/dist/src/graders-D2oE9Msq.js +2 -0
  59. package/dist/src/graders-c0Ez_w-9.cjs +2 -0
  60. package/dist/src/graders-d0F2M3e9.cjs +14056 -0
  61. package/dist/src/image-0ZhE0VlR.cjs +280 -0
  62. package/dist/src/image-CWE1pdNv.js +257 -0
  63. package/dist/src/image-D9ZK6hwL.js +163 -0
  64. package/dist/src/image-DKZgZITg.cjs +163 -0
  65. package/dist/src/index.cjs +11366 -0
  66. package/dist/src/index.d.cts +19640 -0
  67. package/dist/src/index.d.ts +19641 -0
  68. package/dist/src/index.js +11306 -0
  69. package/dist/src/invariant-Ddh24eXh.js +25 -0
  70. package/dist/src/invariant-kfQ8Bu82.cjs +30 -0
  71. package/dist/src/knowledgeBase-BgPyGFUd.cjs +122 -0
  72. package/dist/src/knowledgeBase-DyHilYaP.js +122 -0
  73. package/dist/src/litellm-CyMeneHS.js +135 -0
  74. package/dist/src/litellm-DWDF73yF.cjs +135 -0
  75. package/dist/src/logger-C40ZGil9.js +717 -0
  76. package/dist/src/logger-DyfK9PBt.cjs +917 -0
  77. package/dist/src/luma-ray-BAU9X_ep.cjs +315 -0
  78. package/dist/src/luma-ray-nwVseBbv.js +313 -0
  79. package/dist/src/messages-B5ADWTTv.js +245 -0
  80. package/dist/src/messages-BCnZfqrS.cjs +257 -0
  81. package/dist/src/meteor-DLZZ3osF.cjs +134 -0
  82. package/dist/src/meteor-DUiCJRC-.js +134 -0
  83. package/dist/src/modelslab-00cveB8L.cjs +163 -0
  84. package/dist/src/modelslab-D9sCU_L7.js +163 -0
  85. package/dist/src/nova-reel-CTapvqYH.js +276 -0
  86. package/dist/src/nova-reel-DlWuuroF.cjs +278 -0
  87. package/dist/src/nova-sonic-5UPWfeMv.cjs +363 -0
  88. package/dist/src/nova-sonic-BhSwQNym.js +363 -0
  89. package/dist/src/openai-BWrJK9d8.cjs +52 -0
  90. package/dist/src/openai-DumO8WQn.js +47 -0
  91. package/dist/src/openclaw-B8brrjC_.cjs +577 -0
  92. package/dist/src/openclaw-Bkayww9q.js +571 -0
  93. package/dist/src/opencode-sdk-7xjoDNiM.cjs +562 -0
  94. package/dist/src/opencode-sdk-SGwAPxht.js +558 -0
  95. package/dist/src/otlpReceiver-CoAHfAN9.cjs +15 -0
  96. package/dist/src/otlpReceiver-oO3EQwI9.js +14 -0
  97. package/dist/src/providerRegistry-4yjhaEM8.js +45 -0
  98. package/dist/src/providerRegistry-DhV4rJIc.cjs +50 -0
  99. package/dist/src/providers-B5RJVG-7.cjs +33609 -0
  100. package/dist/src/providers-BdmZCLzV.js +33262 -0
  101. package/dist/src/providers-CxtRxn8e.js +2 -0
  102. package/dist/src/providers-DnQLNbx1.cjs +3 -0
  103. package/dist/src/pythonUtils-BD0druiM.cjs +275 -0
  104. package/dist/src/pythonUtils-IBhn5YGR.js +249 -0
  105. package/dist/src/quiverai-BDOwZBsM.cjs +213 -0
  106. package/dist/src/quiverai-D3JTF5lD.js +213 -0
  107. package/dist/src/responses-B2LCDCXZ.js +667 -0
  108. package/dist/src/responses-BvNm4Xv9.cjs +685 -0
  109. package/dist/src/rubyUtils-B0NwnfpY.cjs +245 -0
  110. package/dist/src/rubyUtils-BroxzZ7c.cjs +2 -0
  111. package/dist/src/rubyUtils-hqVw5UvJ.js +222 -0
  112. package/dist/src/sagemaker-Cno2V-Sx.js +689 -0
  113. package/dist/src/sagemaker-fV_KUgs5.cjs +691 -0
  114. package/dist/src/server-BOuAXb06.cjs +238 -0
  115. package/dist/src/server-CtI-EWzm.cjs +2 -0
  116. package/dist/src/server-Cy3DZymt.js +189 -0
  117. package/dist/src/slack-CP8xBePa.js +135 -0
  118. package/dist/src/slack-DSQ1yXVb.cjs +135 -0
  119. package/dist/src/store-BwDDaBjb.cjs +246 -0
  120. package/dist/src/store-DcbLC593.cjs +2 -0
  121. package/dist/src/store-IGpqMIkv.js +240 -0
  122. package/dist/src/tables-3Q2cL7So.cjs +373 -0
  123. package/dist/src/tables-Bi2fjr4W.js +288 -0
  124. package/dist/src/telemetry-Bg2WqF79.js +161 -0
  125. package/dist/src/telemetry-D0x6u5kX.cjs +166 -0
  126. package/dist/src/telemetry-DXNimrI0.cjs +2 -0
  127. package/dist/src/text-B_UCRPp2.js +22 -0
  128. package/dist/src/text-CW1cyrwj.cjs +33 -0
  129. package/dist/src/tokenUsageUtils-NYT-WKS6.js +138 -0
  130. package/dist/src/tokenUsageUtils-bVa1ga6f.cjs +173 -0
  131. package/dist/src/transcription-Cl_W16Pr.js +122 -0
  132. package/dist/src/transcription-yt1EecY8.cjs +124 -0
  133. package/dist/src/transform-BCtGrl_W.cjs +228 -0
  134. package/dist/src/transform-Bv6gG2MJ.cjs +1688 -0
  135. package/dist/src/transform-CY1wbpRy.js +1507 -0
  136. package/dist/src/transform-DU8rUL9P.cjs +2 -0
  137. package/dist/src/transform-yWaShiKr.js +216 -0
  138. package/dist/src/transformersAvailability-BGkzavwb.js +35 -0
  139. package/dist/src/transformersAvailability-DKoRtQLy.cjs +35 -0
  140. package/dist/src/types-5aqHpBwE.cjs +3769 -0
  141. package/dist/src/types-Bn6D9c4U.js +3300 -0
  142. package/dist/src/util-BkKlTkI2.js +293 -0
  143. package/dist/src/util-CTh0bfOm.cjs +1119 -0
  144. package/dist/src/util-D17oBwo7.cjs +328 -0
  145. package/dist/src/util-DsS_-v4p.js +613 -0
  146. package/dist/src/util-DuntT1Ga.js +951 -0
  147. package/dist/src/util-aWjdCYMI.cjs +667 -0
  148. package/dist/src/utils-CisQwpjA.js +94 -0
  149. package/dist/src/utils-yWamDvmz.cjs +123 -0
  150. package/dist/tsconfig.tsbuildinfo +1 -0
  151. package/drizzle/0000_lush_hellion.sql +36 -0
  152. package/drizzle/0001_wide_calypso.sql +3 -0
  153. package/drizzle/0002_tidy_juggernaut.sql +1 -0
  154. package/drizzle/0003_lively_naoko.sql +8 -0
  155. package/drizzle/0004_minor_peter_quill.sql +19 -0
  156. package/drizzle/0005_silky_millenium_guard.sql +2 -0
  157. package/drizzle/0006_harsh_caretaker.sql +42 -0
  158. package/drizzle/0007_cloudy_wong.sql +1 -0
  159. package/drizzle/0008_broad_boomer.sql +2 -0
  160. package/drizzle/0009_strong_marten_broadcloak.sql +19 -0
  161. package/drizzle/0010_needy_bishop.sql +11 -0
  162. package/drizzle/0011_moaning_millenium_guard.sql +1 -0
  163. package/drizzle/0012_late_marten_broadcloak.sql +2 -0
  164. package/drizzle/0013_previous_dormammu.sql +9 -0
  165. package/drizzle/0014_lazy_captain_universe.sql +2 -0
  166. package/drizzle/0015_zippy_wallop.sql +29 -0
  167. package/drizzle/0016_jazzy_zemo.sql +2 -0
  168. package/drizzle/0017_reflective_praxagora.sql +4 -0
  169. package/drizzle/0018_fat_vanisher.sql +22 -0
  170. package/drizzle/0019_new_clint_barton.sql +8 -0
  171. package/drizzle/0020_skinny_maverick.sql +1 -0
  172. package/drizzle/0021_mysterious_madelyne_pryor.sql +13 -0
  173. package/drizzle/0022_sleepy_ultimo.sql +25 -0
  174. package/drizzle/0023_wooden_mandrill.sql +2 -0
  175. package/drizzle/AGENTS.md +68 -0
  176. package/drizzle/CLAUDE.md +1 -0
  177. package/drizzle/meta/0000_snapshot.json +221 -0
  178. package/drizzle/meta/0001_snapshot.json +214 -0
  179. package/drizzle/meta/0002_snapshot.json +221 -0
  180. package/drizzle/meta/0005_snapshot.json +369 -0
  181. package/drizzle/meta/0006_snapshot.json +638 -0
  182. package/drizzle/meta/0007_snapshot.json +640 -0
  183. package/drizzle/meta/0008_snapshot.json +649 -0
  184. package/drizzle/meta/0009_snapshot.json +554 -0
  185. package/drizzle/meta/0010_snapshot.json +619 -0
  186. package/drizzle/meta/0011_snapshot.json +627 -0
  187. package/drizzle/meta/0012_snapshot.json +639 -0
  188. package/drizzle/meta/0013_snapshot.json +717 -0
  189. package/drizzle/meta/0014_snapshot.json +717 -0
  190. package/drizzle/meta/0015_snapshot.json +897 -0
  191. package/drizzle/meta/0016_snapshot.json +1031 -0
  192. package/drizzle/meta/0018_snapshot.json +1210 -0
  193. package/drizzle/meta/0019_snapshot.json +1165 -0
  194. package/drizzle/meta/0020_snapshot.json +1232 -0
  195. package/drizzle/meta/0021_snapshot.json +1311 -0
  196. package/drizzle/meta/0022_snapshot.json +1481 -0
  197. package/drizzle/meta/0023_snapshot.json +1496 -0
  198. package/drizzle/meta/_journal.json +174 -0
  199. package/package.json +240 -0
@@ -0,0 +1,256 @@
1
+ import { ROOT_CONTEXT, SpanKind, SpanStatusCode, context, propagation, trace } from "@opentelemetry/api";
2
+ //#region src/tracing/genaiTracer.ts
3
+ const TRACER_NAME = "promptfoo.providers";
4
+ const TRACER_VERSION = "1.0.0";
5
+ const GenAIAttributes = {
6
+ SYSTEM: "gen_ai.system",
7
+ OPERATION_NAME: "gen_ai.operation.name",
8
+ REQUEST_MODEL: "gen_ai.request.model",
9
+ REQUEST_MAX_TOKENS: "gen_ai.request.max_tokens",
10
+ REQUEST_TEMPERATURE: "gen_ai.request.temperature",
11
+ REQUEST_TOP_P: "gen_ai.request.top_p",
12
+ REQUEST_TOP_K: "gen_ai.request.top_k",
13
+ REQUEST_STOP_SEQUENCES: "gen_ai.request.stop_sequences",
14
+ REQUEST_FREQUENCY_PENALTY: "gen_ai.request.frequency_penalty",
15
+ REQUEST_PRESENCE_PENALTY: "gen_ai.request.presence_penalty",
16
+ RESPONSE_MODEL: "gen_ai.response.model",
17
+ RESPONSE_ID: "gen_ai.response.id",
18
+ RESPONSE_FINISH_REASONS: "gen_ai.response.finish_reasons",
19
+ USAGE_INPUT_TOKENS: "gen_ai.usage.input_tokens",
20
+ USAGE_OUTPUT_TOKENS: "gen_ai.usage.output_tokens",
21
+ USAGE_TOTAL_TOKENS: "gen_ai.usage.total_tokens",
22
+ USAGE_CACHED_TOKENS: "gen_ai.usage.cached_tokens",
23
+ USAGE_REASONING_TOKENS: "gen_ai.usage.reasoning_tokens",
24
+ USAGE_ACCEPTED_PREDICTION_TOKENS: "gen_ai.usage.accepted_prediction_tokens",
25
+ USAGE_REJECTED_PREDICTION_TOKENS: "gen_ai.usage.rejected_prediction_tokens"
26
+ };
27
+ const PromptfooAttributes = {
28
+ PROVIDER_ID: "promptfoo.provider.id",
29
+ EVAL_ID: "promptfoo.eval.id",
30
+ TEST_INDEX: "promptfoo.test.index",
31
+ PROMPT_LABEL: "promptfoo.prompt.label",
32
+ CACHE_HIT: "promptfoo.cache_hit",
33
+ REQUEST_BODY: "promptfoo.request.body",
34
+ RESPONSE_BODY: "promptfoo.response.body"
35
+ };
36
+ /** Maximum length for request/response body attributes (characters) */
37
+ const MAX_BODY_LENGTH = 4096;
38
+ /**
39
+ * Patterns to redact from request/response bodies for security.
40
+ * These patterns match common API key and secret formats.
41
+ */
42
+ const SENSITIVE_PATTERNS = [
43
+ {
44
+ pattern: /\b(sk-[a-zA-Z0-9_-]{20,})/g,
45
+ replacement: "<REDACTED_API_KEY>"
46
+ },
47
+ {
48
+ pattern: /\b(pk-[a-zA-Z0-9_-]{20,})/g,
49
+ replacement: "<REDACTED_API_KEY>"
50
+ },
51
+ {
52
+ pattern: /\b(api[_-]?key["']?\s*[:=]\s*["']?)([a-zA-Z0-9_-]{16,})/gi,
53
+ replacement: "$1<REDACTED>"
54
+ },
55
+ {
56
+ pattern: /\b(secret["']?\s*[:=]\s*["']?)([a-zA-Z0-9_-]{16,})/gi,
57
+ replacement: "$1<REDACTED>"
58
+ },
59
+ {
60
+ pattern: /\b(token["']?\s*[:=]\s*["']?)([a-zA-Z0-9_-]{16,})/gi,
61
+ replacement: "$1<REDACTED>"
62
+ },
63
+ {
64
+ pattern: /\b(password["']?\s*[:=]\s*["']?)([^\s"',}{]+)/gi,
65
+ replacement: "$1<REDACTED>"
66
+ },
67
+ {
68
+ pattern: /(Authorization["']?\s*[:=]\s*["']?)(Bearer\s+)?([a-zA-Z0-9_.-]{16,})/gi,
69
+ replacement: "$1$2<REDACTED>"
70
+ },
71
+ {
72
+ pattern: /\b(AKIA[A-Z0-9]{16})/g,
73
+ replacement: "<REDACTED_AWS_KEY>"
74
+ },
75
+ {
76
+ pattern: /\b([a-zA-Z0-9/+=]{40})/g,
77
+ replacement: (match) => {
78
+ if (/^[A-Za-z0-9+/=]{40}$/.test(match) && match.includes("/")) return "<REDACTED_SECRET>";
79
+ return match;
80
+ }
81
+ },
82
+ {
83
+ pattern: /\b[a-f0-9]{64,}\b/gi,
84
+ replacement: "<REDACTED_HASH>"
85
+ }
86
+ ];
87
+ /**
88
+ * Get the tracer instance for GenAI operations.
89
+ */
90
+ function getGenAITracer() {
91
+ return trace.getTracer(TRACER_NAME, TRACER_VERSION);
92
+ }
93
+ /**
94
+ * Execute a function within a GenAI span.
95
+ *
96
+ * This wrapper:
97
+ * 1. Creates a span with GenAI semantic conventions
98
+ * 2. Sets request attributes before execution
99
+ * 3. Executes the provided function
100
+ * 4. Sets response attributes (including token usage) after execution
101
+ * 5. Handles errors and sets appropriate span status
102
+ *
103
+ * @param ctx - GenAI span context with request information
104
+ * @param fn - The async function to execute (typically the API call)
105
+ * @param resultExtractor - Optional function to extract result data from the return value
106
+ * @returns The return value from fn
107
+ *
108
+ * @example
109
+ * ```typescript
110
+ * const response = await withGenAISpan(
111
+ * {
112
+ * system: 'openai',
113
+ * operationName: 'chat',
114
+ * model: 'gpt-4',
115
+ * providerId: 'openai:gpt-4',
116
+ * },
117
+ * async (span) => {
118
+ * return await openai.chat.completions.create({...});
119
+ * },
120
+ * (response) => ({
121
+ * tokenUsage: {
122
+ * prompt: response.usage?.prompt_tokens,
123
+ * completion: response.usage?.completion_tokens,
124
+ * },
125
+ * responseId: response.id,
126
+ * })
127
+ * );
128
+ * ```
129
+ */
130
+ async function withGenAISpan(ctx, fn, resultExtractor) {
131
+ const tracer = getGenAITracer();
132
+ const spanName = `${ctx.operationName} ${ctx.model}`;
133
+ let parentContext = context.active();
134
+ if (ctx.traceparent) {
135
+ const carrier = { traceparent: ctx.traceparent };
136
+ parentContext = propagation.extract(ROOT_CONTEXT, carrier);
137
+ }
138
+ const spanCallback = async (span) => {
139
+ try {
140
+ const value = await fn(span);
141
+ if (resultExtractor) setGenAIResponseAttributes(span, resultExtractor(value), ctx.sanitizeBodies);
142
+ const valueAsRecord = value;
143
+ if (valueAsRecord && typeof valueAsRecord.error === "string" && valueAsRecord.error) span.setStatus({
144
+ code: SpanStatusCode.ERROR,
145
+ message: valueAsRecord.error
146
+ });
147
+ else span.setStatus({ code: SpanStatusCode.OK });
148
+ return value;
149
+ } catch (error) {
150
+ span.setStatus({
151
+ code: SpanStatusCode.ERROR,
152
+ message: error instanceof Error ? error.message : String(error)
153
+ });
154
+ if (error instanceof Error) span.recordException(error);
155
+ throw error;
156
+ } finally {
157
+ span.end();
158
+ }
159
+ };
160
+ return tracer.startActiveSpan(spanName, {
161
+ kind: SpanKind.CLIENT,
162
+ attributes: buildRequestAttributes(ctx)
163
+ }, parentContext, spanCallback);
164
+ }
165
+ /**
166
+ * Build request attributes for a GenAI span.
167
+ */
168
+ function buildRequestAttributes(ctx) {
169
+ const attrs = {
170
+ [GenAIAttributes.SYSTEM]: ctx.system,
171
+ [GenAIAttributes.OPERATION_NAME]: ctx.operationName,
172
+ [GenAIAttributes.REQUEST_MODEL]: ctx.model,
173
+ [PromptfooAttributes.PROVIDER_ID]: ctx.providerId
174
+ };
175
+ if (ctx.maxTokens !== void 0) attrs[GenAIAttributes.REQUEST_MAX_TOKENS] = ctx.maxTokens;
176
+ if (ctx.temperature !== void 0) attrs[GenAIAttributes.REQUEST_TEMPERATURE] = ctx.temperature;
177
+ if (ctx.topP !== void 0) attrs[GenAIAttributes.REQUEST_TOP_P] = ctx.topP;
178
+ if (ctx.topK !== void 0) attrs[GenAIAttributes.REQUEST_TOP_K] = ctx.topK;
179
+ if (ctx.stopSequences && ctx.stopSequences.length > 0) attrs[GenAIAttributes.REQUEST_STOP_SEQUENCES] = ctx.stopSequences;
180
+ if (ctx.frequencyPenalty !== void 0) attrs[GenAIAttributes.REQUEST_FREQUENCY_PENALTY] = ctx.frequencyPenalty;
181
+ if (ctx.presencePenalty !== void 0) attrs[GenAIAttributes.REQUEST_PRESENCE_PENALTY] = ctx.presencePenalty;
182
+ if (ctx.evalId) attrs[PromptfooAttributes.EVAL_ID] = ctx.evalId;
183
+ if (ctx.testIndex !== void 0) attrs[PromptfooAttributes.TEST_INDEX] = ctx.testIndex;
184
+ if (ctx.promptLabel) attrs[PromptfooAttributes.PROMPT_LABEL] = ctx.promptLabel;
185
+ if (ctx.requestBody) attrs[PromptfooAttributes.REQUEST_BODY] = truncateBody(ctx.requestBody, ctx.sanitizeBodies);
186
+ return attrs;
187
+ }
188
+ /**
189
+ * Sanitize sensitive data from a body string.
190
+ * Redacts API keys, secrets, tokens, and other sensitive patterns.
191
+ */
192
+ function sanitizeBody(body) {
193
+ let sanitized = body;
194
+ for (const { pattern, replacement } of SENSITIVE_PATTERNS) if (typeof replacement === "function") sanitized = sanitized.replace(pattern, replacement);
195
+ else sanitized = sanitized.replace(pattern, replacement);
196
+ return sanitized;
197
+ }
198
+ /**
199
+ * Truncate a body string to MAX_BODY_LENGTH.
200
+ * Optionally sanitizes sensitive data first if sanitize=true.
201
+ *
202
+ * @param body - The body string to process
203
+ * @param sanitize - Whether to sanitize sensitive data (defaults to true)
204
+ */
205
+ function truncateBody(body, sanitize = true) {
206
+ const processed = sanitize ? sanitizeBody(body) : body;
207
+ if (processed.length <= MAX_BODY_LENGTH) return processed;
208
+ return processed.slice(0, MAX_BODY_LENGTH - 15) + "... [truncated]";
209
+ }
210
+ /**
211
+ * Set response attributes on a span after the API call completes.
212
+ *
213
+ * @param span - The span to update
214
+ * @param result - The result data containing token usage and response metadata
215
+ * @param sanitize - Whether to sanitize sensitive data from response body (defaults to true)
216
+ */
217
+ function setGenAIResponseAttributes(span, result, sanitize = true) {
218
+ if (result.tokenUsage) {
219
+ const usage = result.tokenUsage;
220
+ if (usage.prompt !== void 0) span.setAttribute(GenAIAttributes.USAGE_INPUT_TOKENS, usage.prompt);
221
+ if (usage.completion !== void 0) span.setAttribute(GenAIAttributes.USAGE_OUTPUT_TOKENS, usage.completion);
222
+ if (usage.total !== void 0) span.setAttribute(GenAIAttributes.USAGE_TOTAL_TOKENS, usage.total);
223
+ if (usage.cached !== void 0) span.setAttribute(GenAIAttributes.USAGE_CACHED_TOKENS, usage.cached);
224
+ if (usage.completionDetails) {
225
+ if (usage.completionDetails.reasoning !== void 0) span.setAttribute(GenAIAttributes.USAGE_REASONING_TOKENS, usage.completionDetails.reasoning);
226
+ if (usage.completionDetails.acceptedPrediction !== void 0) span.setAttribute(GenAIAttributes.USAGE_ACCEPTED_PREDICTION_TOKENS, usage.completionDetails.acceptedPrediction);
227
+ if (usage.completionDetails.rejectedPrediction !== void 0) span.setAttribute(GenAIAttributes.USAGE_REJECTED_PREDICTION_TOKENS, usage.completionDetails.rejectedPrediction);
228
+ }
229
+ }
230
+ if (result.responseModel) span.setAttribute(GenAIAttributes.RESPONSE_MODEL, result.responseModel);
231
+ if (result.responseId) span.setAttribute(GenAIAttributes.RESPONSE_ID, result.responseId);
232
+ if (result.finishReasons && result.finishReasons.length > 0) span.setAttribute(GenAIAttributes.RESPONSE_FINISH_REASONS, result.finishReasons);
233
+ if (result.cacheHit !== void 0) span.setAttribute(PromptfooAttributes.CACHE_HIT, result.cacheHit);
234
+ if (result.responseBody) span.setAttribute(PromptfooAttributes.RESPONSE_BODY, truncateBody(result.responseBody, sanitize));
235
+ if (result.additionalAttributes) {
236
+ for (const [key, value] of Object.entries(result.additionalAttributes)) if (value !== void 0 && value !== null) if (typeof value === "string") span.setAttribute(key, truncateBody(value, sanitize));
237
+ else span.setAttribute(key, value);
238
+ }
239
+ }
240
+ /**
241
+ * Get the W3C traceparent header value from the current active span.
242
+ * Returns undefined if there is no active span.
243
+ *
244
+ * This can be used to propagate trace context to downstream services.
245
+ */
246
+ function getTraceparent() {
247
+ const activeSpan = trace.getActiveSpan();
248
+ if (!activeSpan) return;
249
+ const ctx = activeSpan.spanContext();
250
+ const traceFlags = ctx.traceFlags.toString(16).padStart(2, "0");
251
+ return `00-${ctx.traceId}-${ctx.spanId}-${traceFlags}`;
252
+ }
253
+ //#endregion
254
+ export { withGenAISpan as n, getTraceparent as t };
255
+
256
+ //# sourceMappingURL=genaiTracer-D3fD9dNV.js.map