weflayr 0.24.0 → 0.26.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 (234) hide show
  1. package/README.md +2 -2
  2. package/dist/{api → src/api}/generated/facade.gen.d.ts +86 -12
  3. package/dist/{api → src/api}/generated/facade.gen.js +4 -2
  4. package/dist/src/api/generated/index.d.ts +2 -0
  5. package/dist/{api → src/api}/generated/index.js +3 -1
  6. package/dist/{api → src/api}/generated/sdk.gen.d.ts +11 -3
  7. package/dist/{api → src/api}/generated/sdk.gen.js +34 -4
  8. package/{src/api/generated/types.gen.ts → dist/src/api/generated/types.gen.d.ts} +436 -153
  9. package/dist/{api → src/api}/makeEndpoint.js +1 -3
  10. package/dist/src/auto-instrument.d.ts +42 -0
  11. package/dist/src/auto-instrument.js +156 -0
  12. package/dist/src/index.d.ts +9 -0
  13. package/dist/src/index.js +49 -0
  14. package/dist/src/instrumentation/anthropic/get_cache_and_reasoning_telemetry.d.ts +20 -0
  15. package/dist/src/instrumentation/anthropic/get_cache_and_reasoning_telemetry.js +114 -0
  16. package/dist/src/instrumentation/anthropic/get_cache_config_telemetry.d.ts +28 -0
  17. package/dist/src/instrumentation/anthropic/get_cache_config_telemetry.js +92 -0
  18. package/dist/src/instrumentation/anthropic/get_streaming_accumulation_telemetry.d.ts +25 -0
  19. package/dist/src/instrumentation/anthropic/get_streaming_accumulation_telemetry.js +141 -0
  20. package/dist/src/instrumentation/anthropic/get_structured_output_schema_telemetry.d.ts +9 -0
  21. package/dist/src/instrumentation/anthropic/get_structured_output_schema_telemetry.js +17 -0
  22. package/dist/src/instrumentation/anthropic/get_tool_definitions_telemetry.d.ts +15 -0
  23. package/dist/src/instrumentation/anthropic/get_tool_definitions_telemetry.js +50 -0
  24. package/dist/src/instrumentation/anthropic/set_telemetry_attributes.d.ts +15 -0
  25. package/dist/src/instrumentation/anthropic/set_telemetry_attributes.js +39 -0
  26. package/dist/src/instrumentation/bedrock/get_cache_config_telemetry.d.ts +22 -0
  27. package/dist/src/instrumentation/bedrock/get_cache_config_telemetry.js +97 -0
  28. package/dist/src/instrumentation/bedrock/get_cache_telemetry.d.ts +22 -0
  29. package/dist/src/instrumentation/bedrock/get_cache_telemetry.js +102 -0
  30. package/dist/src/instrumentation/bedrock/get_input_message_content_telemetry.d.ts +15 -0
  31. package/dist/src/instrumentation/bedrock/get_input_message_content_telemetry.js +91 -0
  32. package/dist/src/instrumentation/bedrock/get_model_id_telemetry.d.ts +21 -0
  33. package/dist/src/instrumentation/bedrock/get_model_id_telemetry.js +54 -0
  34. package/dist/src/instrumentation/bedrock/get_reasoning_output_telemetry.d.ts +19 -0
  35. package/dist/src/instrumentation/bedrock/get_reasoning_output_telemetry.js +81 -0
  36. package/dist/src/instrumentation/bedrock/get_streaming_output_message_telemetry.d.ts +27 -0
  37. package/dist/src/instrumentation/bedrock/get_streaming_output_message_telemetry.js +126 -0
  38. package/dist/src/instrumentation/bedrock/get_tool_call_output_telemetry.d.ts +17 -0
  39. package/dist/src/instrumentation/bedrock/get_tool_call_output_telemetry.js +85 -0
  40. package/dist/src/instrumentation/bedrock/get_tool_definitions_telemetry.d.ts +15 -0
  41. package/dist/src/instrumentation/bedrock/get_tool_definitions_telemetry.js +68 -0
  42. package/dist/src/instrumentation/bedrock/set_telemetry_attributes.d.ts +18 -0
  43. package/dist/src/instrumentation/bedrock/set_telemetry_attributes.js +47 -0
  44. package/dist/src/instrumentation/cohere/get_chat_telemetry.d.ts +23 -0
  45. package/dist/src/instrumentation/cohere/get_chat_telemetry.js +77 -0
  46. package/dist/src/instrumentation/cohere/get_embeddings_telemetry.d.ts +18 -0
  47. package/dist/src/instrumentation/cohere/get_embeddings_telemetry.js +88 -0
  48. package/dist/src/instrumentation/cohere/get_structured_output_schema_telemetry.d.ts +12 -0
  49. package/dist/src/instrumentation/cohere/get_structured_output_schema_telemetry.js +18 -0
  50. package/dist/src/instrumentation/cohere/get_tool_call_output_telemetry.d.ts +31 -0
  51. package/dist/src/instrumentation/cohere/get_tool_call_output_telemetry.js +106 -0
  52. package/dist/src/instrumentation/cohere/get_tool_definitions_telemetry.d.ts +27 -0
  53. package/dist/src/instrumentation/cohere/get_tool_definitions_telemetry.js +75 -0
  54. package/dist/src/instrumentation/cohere/set_telemetry_attributes.d.ts +17 -0
  55. package/dist/src/instrumentation/cohere/set_telemetry_attributes.js +44 -0
  56. package/dist/src/instrumentation/elevenlabs/full_instrumentation.d.ts +28 -0
  57. package/dist/src/instrumentation/elevenlabs/full_instrumentation.js +209 -0
  58. package/dist/src/instrumentation/google/get_audio_telemetry.d.ts +9 -0
  59. package/dist/src/instrumentation/google/get_audio_telemetry.js +28 -0
  60. package/dist/src/instrumentation/google/get_cache_operations_telemetry.d.ts +23 -0
  61. package/dist/src/instrumentation/google/get_cache_operations_telemetry.js +154 -0
  62. package/dist/src/instrumentation/google/get_cache_telemetry.d.ts +16 -0
  63. package/{src → dist/src}/instrumentation/google/get_cache_telemetry.js +18 -19
  64. package/dist/src/instrumentation/google/get_embeddings_telemetry.d.ts +12 -0
  65. package/dist/src/instrumentation/google/get_embeddings_telemetry.js +85 -0
  66. package/dist/src/instrumentation/google/get_provider_name.d.ts +11 -0
  67. package/{src → dist/src}/instrumentation/google/get_provider_name.js +11 -12
  68. package/{src/instrumentation/google/get_reasoning_telemetry.js → dist/src/instrumentation/google/get_reasoning_telemetry.d.ts} +1 -11
  69. package/dist/src/instrumentation/google/get_reasoning_telemetry.js +21 -0
  70. package/dist/src/instrumentation/google/get_structured_output_schema_telemetry.d.ts +12 -0
  71. package/dist/src/instrumentation/google/get_structured_output_schema_telemetry.js +19 -0
  72. package/dist/src/instrumentation/google/set_telemetry_attributes.d.ts +18 -0
  73. package/dist/src/instrumentation/google/set_telemetry_attributes.js +98 -0
  74. package/dist/src/instrumentation/openai/get_audio_telemetry.d.ts +25 -0
  75. package/dist/src/instrumentation/openai/get_audio_telemetry.js +123 -0
  76. package/dist/src/instrumentation/openai/get_bedrock_mantle_telemetry.d.ts +35 -0
  77. package/dist/src/instrumentation/openai/get_bedrock_mantle_telemetry.js +148 -0
  78. package/dist/src/instrumentation/openai/get_cache_and_reasoning_telemetry.d.ts +27 -0
  79. package/dist/src/instrumentation/openai/get_cache_and_reasoning_telemetry.js +72 -0
  80. package/dist/src/instrumentation/openai/get_cache_config_telemetry.d.ts +28 -0
  81. package/dist/src/instrumentation/openai/get_cache_config_telemetry.js +91 -0
  82. package/dist/src/instrumentation/openai/get_embeddings_telemetry.d.ts +18 -0
  83. package/dist/src/instrumentation/openai/get_embeddings_telemetry.js +86 -0
  84. package/dist/src/instrumentation/openai/get_streaming_usage.d.ts +21 -0
  85. package/dist/src/instrumentation/openai/get_streaming_usage.js +74 -0
  86. package/dist/src/instrumentation/openai/get_structured_output_schema_telemetry.d.ts +12 -0
  87. package/dist/src/instrumentation/openai/get_structured_output_schema_telemetry.js +20 -0
  88. package/dist/src/instrumentation/openai/set_telemetry_attributes.d.ts +17 -0
  89. package/dist/src/instrumentation/openai/set_telemetry_attributes.js +47 -0
  90. package/dist/src/instrumentation/shared/get_structured_output_schema_telemetry.d.ts +35 -0
  91. package/dist/src/instrumentation/shared/get_structured_output_schema_telemetry.js +76 -0
  92. package/dist/src/instrumentation/vercel/full_instrumentation.d.ts +3 -0
  93. package/dist/src/instrumentation/vercel/full_instrumentation.js +54 -0
  94. package/dist/src/instrumentation/vercel/get_cache_creation_telemetry.d.ts +22 -0
  95. package/dist/src/instrumentation/vercel/get_cache_creation_telemetry.js +66 -0
  96. package/dist/src/instrumentation/vercel/get_structured_output_schema_telemetry.d.ts +24 -0
  97. package/dist/src/instrumentation/vercel/get_structured_output_schema_telemetry.js +84 -0
  98. package/dist/src/logger.d.ts +1 -0
  99. package/dist/src/logger.js +6 -0
  100. package/dist/src/otel/exporter.d.ts +19 -0
  101. package/dist/src/otel/exporter.js +94 -0
  102. package/dist/src/otel/propagation.d.ts +46 -0
  103. package/dist/src/otel/propagation.js +110 -0
  104. package/dist/src/otel/span-filter.d.ts +3 -0
  105. package/dist/src/otel/span-filter.js +61 -0
  106. package/dist/src/otel/span-processor.d.ts +55 -0
  107. package/dist/src/otel/span-processor.js +169 -0
  108. package/dist/src/otel/vercel-ai-sdk-span-filter.d.ts +12 -0
  109. package/dist/src/otel/vercel-ai-sdk-span-filter.js +88 -0
  110. package/dist/src/setup.d.ts +50 -0
  111. package/dist/src/setup.js +155 -0
  112. package/package.json +11 -5
  113. package/.prettierignore +0 -2
  114. package/.prettierrc.json +0 -7
  115. package/LICENSE-MIT +0 -21
  116. package/NOTICE +0 -12
  117. package/dist/api/generated/index.d.ts +0 -2
  118. package/dist/api/generated/types.gen.d.ts +0 -1005
  119. package/eslint.config.mjs +0 -36
  120. package/index.d.ts +0 -170
  121. package/openapi-ts.config.mjs +0 -9
  122. package/scripts/generate_facade.mjs +0 -86
  123. package/src/api/caseConversion.ts +0 -58
  124. package/src/api/generated/client/client.gen.ts +0 -277
  125. package/src/api/generated/client/index.ts +0 -27
  126. package/src/api/generated/client/types.gen.ts +0 -218
  127. package/src/api/generated/client/utils.gen.ts +0 -316
  128. package/src/api/generated/client.gen.ts +0 -16
  129. package/src/api/generated/core/auth.gen.ts +0 -48
  130. package/src/api/generated/core/bodySerializer.gen.ts +0 -82
  131. package/src/api/generated/core/params.gen.ts +0 -178
  132. package/src/api/generated/core/pathSerializer.gen.ts +0 -171
  133. package/src/api/generated/core/queryKeySerializer.gen.ts +0 -117
  134. package/src/api/generated/core/serverSentEvents.gen.ts +0 -242
  135. package/src/api/generated/core/types.gen.ts +0 -110
  136. package/src/api/generated/core/utils.gen.ts +0 -140
  137. package/src/api/generated/facade.gen.ts +0 -104
  138. package/src/api/generated/index.ts +0 -4
  139. package/src/api/generated/sdk.gen.ts +0 -175
  140. package/src/api/index.ts +0 -45
  141. package/src/api/makeEndpoint.ts +0 -54
  142. package/src/auto-instrument.js +0 -172
  143. package/src/index.js +0 -19
  144. package/src/instrumentation/anthropic/get_cache_and_reasoning_telemetry.js +0 -118
  145. package/src/instrumentation/anthropic/get_cache_config_telemetry.js +0 -90
  146. package/src/instrumentation/anthropic/get_streaming_stop_reason_telemetry.js +0 -121
  147. package/src/instrumentation/anthropic/get_tool_definitions_telemetry.js +0 -55
  148. package/src/instrumentation/anthropic/set_telemetry_attributes.js +0 -39
  149. package/src/instrumentation/bedrock/get_cache_config_telemetry.js +0 -106
  150. package/src/instrumentation/bedrock/get_cache_telemetry.js +0 -109
  151. package/src/instrumentation/bedrock/get_input_message_content_telemetry.js +0 -94
  152. package/src/instrumentation/bedrock/get_streaming_output_message_telemetry.js +0 -87
  153. package/src/instrumentation/bedrock/set_telemetry_attributes.js +0 -40
  154. package/src/instrumentation/cohere/get_chat_telemetry.js +0 -88
  155. package/src/instrumentation/cohere/get_embeddings_telemetry.js +0 -107
  156. package/src/instrumentation/cohere/set_telemetry_attributes.js +0 -32
  157. package/src/instrumentation/elevenlabs/full_instrumentation.js +0 -236
  158. package/src/instrumentation/google/get_audio_telemetry.js +0 -30
  159. package/src/instrumentation/google/get_cache_operations_telemetry.js +0 -171
  160. package/src/instrumentation/google/get_embeddings_telemetry.js +0 -99
  161. package/src/instrumentation/google/set_telemetry_attributes.js +0 -104
  162. package/src/instrumentation/openai/get_audio_telemetry.js +0 -149
  163. package/src/instrumentation/openai/get_cache_and_reasoning_telemetry.js +0 -71
  164. package/src/instrumentation/openai/get_cache_config_telemetry.js +0 -63
  165. package/src/instrumentation/openai/get_embeddings_telemetry.js +0 -107
  166. package/src/instrumentation/openai/get_streaming_usage.js +0 -81
  167. package/src/instrumentation/openai/set_telemetry_attributes.js +0 -41
  168. package/src/instrumentation/vercel/full_instrumentation.js +0 -52
  169. package/src/instrumentation/vercel/get_cache_creation_telemetry.js +0 -70
  170. package/src/logger.js +0 -8
  171. package/src/otel/exporter.js +0 -108
  172. package/src/otel/propagation.js +0 -146
  173. package/src/otel/span-filter.js +0 -69
  174. package/src/otel/span-processor.js +0 -170
  175. package/src/otel/vercel-ai-sdk-span-filter.js +0 -79
  176. package/src/setup.js +0 -167
  177. package/tests/api/index.test.js +0 -437
  178. package/tests/index.test.js +0 -884
  179. package/tests/instrumentation/anthropic/get_cache_and_reasoning_telemetry.test.js +0 -181
  180. package/tests/instrumentation/anthropic/get_cache_config_telemetry.test.js +0 -92
  181. package/tests/instrumentation/anthropic/get_streaming_stop_reason_telemetry.test.js +0 -117
  182. package/tests/instrumentation/anthropic/get_tool_definitions_telemetry.test.js +0 -97
  183. package/tests/instrumentation/bedrock/get_cache_config_telemetry.test.js +0 -107
  184. package/tests/instrumentation/bedrock/get_cache_telemetry.test.js +0 -118
  185. package/tests/instrumentation/bedrock/get_input_message_content_telemetry.test.js +0 -89
  186. package/tests/instrumentation/bedrock/get_streaming_output_message_telemetry.test.js +0 -87
  187. package/tests/instrumentation/cohere/get_chat_telemetry.test.js +0 -148
  188. package/tests/instrumentation/cohere/get_embeddings_telemetry.test.js +0 -132
  189. package/tests/instrumentation/elevenlabs/full_instrumentation.test.js +0 -258
  190. package/tests/instrumentation/google/get_cache_operations_telemetry.test.js +0 -130
  191. package/tests/instrumentation/google/get_embeddings_telemetry.test.js +0 -128
  192. package/tests/instrumentation/google/get_reasoning_telemetry.test.js +0 -41
  193. package/tests/instrumentation/google/set_telemetry_attributes.test.js +0 -219
  194. package/tests/instrumentation/openai/get_audio_telemetry.test.js +0 -170
  195. package/tests/instrumentation/openai/get_cache_and_reasoning_telemetry.test.js +0 -83
  196. package/tests/instrumentation/openai/get_cache_config_telemetry.test.js +0 -83
  197. package/tests/instrumentation/openai/get_embeddings_telemetry.test.js +0 -145
  198. package/tests/instrumentation/openai/get_streaming_usage.test.js +0 -105
  199. package/tests/instrumentation/vercel/full_instrumentation.test.js +0 -16
  200. package/tests/instrumentation/vercel/get_cache_creation_telemetry.test.js +0 -96
  201. package/tests/otel/vercel-ai-sdk-span-filter.test.js +0 -159
  202. package/tsconfig.json +0 -18
  203. /package/dist/{api → src/api}/caseConversion.d.ts +0 -0
  204. /package/dist/{api → src/api}/caseConversion.js +0 -0
  205. /package/dist/{api → src/api}/generated/client/client.gen.d.ts +0 -0
  206. /package/dist/{api → src/api}/generated/client/client.gen.js +0 -0
  207. /package/dist/{api → src/api}/generated/client/index.d.ts +0 -0
  208. /package/dist/{api → src/api}/generated/client/index.js +0 -0
  209. /package/dist/{api → src/api}/generated/client/types.gen.d.ts +0 -0
  210. /package/dist/{api → src/api}/generated/client/types.gen.js +0 -0
  211. /package/dist/{api → src/api}/generated/client/utils.gen.d.ts +0 -0
  212. /package/dist/{api → src/api}/generated/client/utils.gen.js +0 -0
  213. /package/dist/{api → src/api}/generated/client.gen.d.ts +0 -0
  214. /package/dist/{api → src/api}/generated/client.gen.js +0 -0
  215. /package/dist/{api → src/api}/generated/core/auth.gen.d.ts +0 -0
  216. /package/dist/{api → src/api}/generated/core/auth.gen.js +0 -0
  217. /package/dist/{api → src/api}/generated/core/bodySerializer.gen.d.ts +0 -0
  218. /package/dist/{api → src/api}/generated/core/bodySerializer.gen.js +0 -0
  219. /package/dist/{api → src/api}/generated/core/params.gen.d.ts +0 -0
  220. /package/dist/{api → src/api}/generated/core/params.gen.js +0 -0
  221. /package/dist/{api → src/api}/generated/core/pathSerializer.gen.d.ts +0 -0
  222. /package/dist/{api → src/api}/generated/core/pathSerializer.gen.js +0 -0
  223. /package/dist/{api → src/api}/generated/core/queryKeySerializer.gen.d.ts +0 -0
  224. /package/dist/{api → src/api}/generated/core/queryKeySerializer.gen.js +0 -0
  225. /package/dist/{api → src/api}/generated/core/serverSentEvents.gen.d.ts +0 -0
  226. /package/dist/{api → src/api}/generated/core/serverSentEvents.gen.js +0 -0
  227. /package/dist/{api → src/api}/generated/core/types.gen.d.ts +0 -0
  228. /package/dist/{api → src/api}/generated/core/types.gen.js +0 -0
  229. /package/dist/{api → src/api}/generated/core/utils.gen.d.ts +0 -0
  230. /package/dist/{api → src/api}/generated/core/utils.gen.js +0 -0
  231. /package/dist/{api → src/api}/generated/types.gen.js +0 -0
  232. /package/dist/{api → src/api}/index.d.ts +0 -0
  233. /package/dist/{api → src/api}/index.js +0 -0
  234. /package/dist/{api → src/api}/makeEndpoint.d.ts +0 -0
@@ -1,219 +0,0 @@
1
- 'use strict';
2
-
3
- // Tests for the Gemini generate_content enrichment complement.
4
- //
5
- // It stamps `gen_ai.system` (vertex_ai/gemini) and audio token details onto the
6
- // ACTIVE span (traceloop's chat span) when `generateContent{,Stream}Internal`
7
- // runs. The @google/genai `Models` class is stubbed; the test plays traceloop by
8
- // starting a span and making it active around the call.
9
-
10
- const test = require('node:test');
11
- const assert = require('node:assert/strict');
12
- const Module = require('node:module');
13
-
14
- const { trace, context } = require('@opentelemetry/api');
15
- const {
16
- BasicTracerProvider,
17
- InMemorySpanExporter,
18
- SimpleSpanProcessor,
19
- } = require('@opentelemetry/sdk-trace-base');
20
- const { AsyncLocalStorageContextManager } = require('@opentelemetry/context-async-hooks');
21
-
22
- const {
23
- GoogleTelemetryInstrumentor,
24
- } = require('../../../src/instrumentation/google/set_telemetry_attributes');
25
-
26
- const GENAI_MODULE = '@google/genai';
27
-
28
- // The exact chunk objects the streaming stub yields. Shared so the passthrough
29
- // test can assert object identity — proof our wrapper re-yields the user's chunks
30
- // without copying or mutating them. The last chunk carries the streamed usage.
31
- const STREAM_CHUNKS = [
32
- { text: 'hello ' },
33
- { text: 'world', usageMetadata: { cachedContentTokenCount: 32 } },
34
- ];
35
-
36
- const exporter = new InMemorySpanExporter();
37
- trace.setGlobalTracerProvider(
38
- new BasicTracerProvider({ spanProcessors: [new SimpleSpanProcessor(exporter)] })
39
- );
40
- context.setGlobalContextManager(new AsyncLocalStorageContextManager().enable());
41
-
42
- class StubModels {
43
- generateContentInternal(params = {}) {
44
- return Promise.resolve({
45
- text: 'ok',
46
- usageMetadata: {
47
- promptTokensDetails: params.audioInput
48
- ? [{ modality: 'AUDIO', tokenCount: 9 }]
49
- : [{ modality: 'TEXT', tokenCount: 2 }],
50
- candidatesTokensDetails: params.audioOutput
51
- ? [{ modality: 'AUDIO', tokenCount: 17 }]
52
- : [{ modality: 'TEXT', tokenCount: 5 }],
53
- cachedContentTokenCount: params.cached || 0,
54
- cacheTokensDetails: params.cacheDetails,
55
- },
56
- });
57
- }
58
-
59
- generateContentStreamInternal() {
60
- return Promise.resolve(
61
- (async function* () {
62
- for (const chunk of STREAM_CHUNKS) yield chunk;
63
- })()
64
- );
65
- }
66
- }
67
-
68
- function instrumented() {
69
- const stubs = { [GENAI_MODULE]: { Models: StubModels } };
70
- const origResolve = Module._resolveFilename;
71
- Module._resolveFilename = function patched(request, ...rest) {
72
- if (request in stubs) return request;
73
- return origResolve.call(this, request, ...rest);
74
- };
75
- for (const [moduleId, exports] of Object.entries(stubs)) {
76
- require.cache[moduleId] = { id: moduleId, filename: moduleId, loaded: true, exports };
77
- }
78
- const instrumentor = new GoogleTelemetryInstrumentor();
79
- instrumentor.instrument();
80
- return () => {
81
- instrumentor.uninstrument();
82
- Module._resolveFilename = origResolve;
83
- for (const moduleId of Object.keys(stubs)) delete require.cache[moduleId];
84
- exporter.reset();
85
- };
86
- }
87
-
88
- async function withActiveSpan(fn) {
89
- const span = trace.getTracer('test').startSpan('generate_content');
90
- await context.with(trace.setSpan(context.active(), span), fn);
91
- span.end();
92
- return exporter.getFinishedSpans().at(-1);
93
- }
94
-
95
- test('stamps provider gemini and audio output tokens on the active span', async () => {
96
- const teardown = instrumented();
97
- try {
98
- const client = new StubModels();
99
- client.apiClient = { isVertexAI: () => false };
100
- const span = await withActiveSpan(() =>
101
- client.generateContentInternal({ model: 'tts', audioOutput: true })
102
- );
103
- assert.equal(span.attributes['gen_ai.system'], 'gemini');
104
- assert.equal(span.attributes['gen_ai.usage.output_tokens_details.audio_tokens'], 17);
105
- assert.equal(span.attributes['gen_ai.usage.input_tokens_details.audio_tokens'], undefined);
106
- } finally {
107
- teardown();
108
- }
109
- });
110
-
111
- test('stamps provider vertex_ai and audio input tokens', async () => {
112
- const teardown = instrumented();
113
- try {
114
- const client = new StubModels();
115
- client.apiClient = { isVertexAI: () => true };
116
- const span = await withActiveSpan(() =>
117
- client.generateContentInternal({ model: 'm', audioInput: true })
118
- );
119
- assert.equal(span.attributes['gen_ai.system'], 'vertex_ai');
120
- assert.equal(span.attributes['gen_ai.usage.input_tokens_details.audio_tokens'], 9);
121
- } finally {
122
- teardown();
123
- }
124
- });
125
-
126
- test('no audio token attributes for a text-only call', async () => {
127
- const teardown = instrumented();
128
- try {
129
- const client = new StubModels();
130
- client.apiClient = { isVertexAI: () => false };
131
- const span = await withActiveSpan(() => client.generateContentInternal({ model: 'm' }));
132
- assert.equal(span.attributes['gen_ai.usage.output_tokens_details.audio_tokens'], undefined);
133
- assert.equal(span.attributes['gen_ai.usage.cache_read_input_tokens'], undefined);
134
- assert.equal(span.attributes['gen_ai.system'], 'gemini');
135
- } finally {
136
- teardown();
137
- }
138
- });
139
-
140
- test('stamps cached-content tokens on the active span', async () => {
141
- const teardown = instrumented();
142
- try {
143
- const client = new StubModels();
144
- client.apiClient = { isVertexAI: () => false };
145
- const span = await withActiveSpan(() =>
146
- client.generateContentInternal({ model: 'm', cached: 128 })
147
- );
148
- assert.equal(span.attributes['gen_ai.usage.cache_read_input_tokens'], 128);
149
- assert.equal(
150
- span.attributes['gen_ai.usage.input_tokens_details.cached_audio_tokens'],
151
- undefined
152
- );
153
- } finally {
154
- teardown();
155
- }
156
- });
157
-
158
- test('splits cached tokens into audio and text remainder by modality', async () => {
159
- const teardown = instrumented();
160
- try {
161
- const client = new StubModels();
162
- client.apiClient = { isVertexAI: () => false };
163
- // 200 cached tokens, 50 of them audio: audio is billed separately, the rest
164
- // stays as text cache-read so the two never double-count.
165
- const span = await withActiveSpan(() =>
166
- client.generateContentInternal({
167
- model: 'm',
168
- cached: 200,
169
- cacheDetails: [
170
- { modality: 'TEXT', tokenCount: 150 },
171
- { modality: 'AUDIO', tokenCount: 50 },
172
- ],
173
- })
174
- );
175
- assert.equal(span.attributes['gen_ai.usage.input_tokens_details.cached_audio_tokens'], 50);
176
- assert.equal(span.attributes['gen_ai.usage.cache_read_input_tokens'], 150);
177
- } finally {
178
- teardown();
179
- }
180
- });
181
-
182
- test('streaming sets provider only and uninstrument restores methods', async () => {
183
- const teardown = instrumented();
184
- try {
185
- const client = new StubModels();
186
- client.apiClient = { isVertexAI: () => true };
187
- const span = await withActiveSpan(() => client.generateContentStreamInternal({ model: 'm' }));
188
- assert.equal(span.attributes['gen_ai.system'], 'vertex_ai');
189
- } finally {
190
- teardown();
191
- }
192
- // After teardown the prototype method is restored.
193
- const client = new StubModels();
194
- assert.equal(typeof client.generateContentInternal, 'function');
195
- });
196
-
197
- test('streaming re-yields the user chunks unchanged and stamps cache off the stream', async () => {
198
- const teardown = instrumented();
199
- try {
200
- const client = new StubModels();
201
- client.apiClient = { isVertexAI: () => false };
202
- const collected = [];
203
- const span = await withActiveSpan(async () => {
204
- const stream = await client.generateContentStreamInternal({ model: 'm' });
205
- for await (const chunk of stream) collected.push(chunk);
206
- });
207
- // Same count, order, and object identity: observeCache re-yields each chunk
208
- // by reference — no telemetry collision with the caller's payload.
209
- assert.equal(collected.length, STREAM_CHUNKS.length);
210
- collected.forEach((chunk, index) => {
211
- assert.equal(chunk, STREAM_CHUNKS[index]);
212
- assert.equal(chunk.text, STREAM_CHUNKS[index].text);
213
- });
214
- // The wrapper still ran: cache tokens from the final chunk landed on the span.
215
- assert.equal(span.attributes['gen_ai.usage.cache_read_input_tokens'], 32);
216
- } finally {
217
- teardown();
218
- }
219
- });
@@ -1,170 +0,0 @@
1
- 'use strict';
2
-
3
- // Tests for the bundled OpenAI audio instrumentor.
4
- //
5
- // The real `openai` audio resource classes are stubbed with `create` methods
6
- // that mirror the SDK's shapes — Text-to-Speech resolves to the audio bytes and
7
- // Speech-to-Text to a transcription carrying `duration` — so the instrumentor
8
- // can be exercised without network access or the dependency installed.
9
-
10
- const test = require('node:test');
11
- const assert = require('node:assert/strict');
12
- const Module = require('node:module');
13
-
14
- const { trace, SpanStatusCode } = require('@opentelemetry/api');
15
- const {
16
- BasicTracerProvider,
17
- InMemorySpanExporter,
18
- SimpleSpanProcessor,
19
- } = require('@opentelemetry/sdk-trace-base');
20
-
21
- const {
22
- OpenAIAudioInstrumentor,
23
- } = require('../../../src/instrumentation/openai/get_audio_telemetry');
24
-
25
- const SPEECH_MODULE = 'openai/resources/audio/speech';
26
- const TRANSCRIPTIONS_MODULE = 'openai/resources/audio/transcriptions';
27
-
28
- const exporter = new InMemorySpanExporter();
29
- trace.setGlobalTracerProvider(
30
- new BasicTracerProvider({ spanProcessors: [new SimpleSpanProcessor(exporter)] })
31
- );
32
-
33
- class StubSpeech {
34
- create(body = {}) {
35
- if (body.input === 'boom') return Promise.reject(new Error('api error'));
36
- return Promise.resolve(Buffer.from('audio-bytes'));
37
- }
38
- }
39
-
40
- class StubTranscriptions {
41
- create(body = {}) {
42
- if (body.model === 'boom') return Promise.reject(new Error('api error'));
43
- return Promise.resolve({ duration: 12.4, text: 'hello' });
44
- }
45
- }
46
-
47
- // Stub the openai audio resource modules, install the instrumentor + the
48
- // in-memory exporter, and return a teardown that restores everything.
49
- function instrumented() {
50
- const stubs = {
51
- [SPEECH_MODULE]: { Speech: StubSpeech },
52
- [TRANSCRIPTIONS_MODULE]: { Transcriptions: StubTranscriptions },
53
- };
54
- const origResolve = Module._resolveFilename;
55
- Module._resolveFilename = function patched(request, ...rest) {
56
- if (request in stubs) return request;
57
- return origResolve.call(this, request, ...rest);
58
- };
59
- for (const [moduleId, exports] of Object.entries(stubs)) {
60
- require.cache[moduleId] = { id: moduleId, filename: moduleId, loaded: true, exports };
61
- }
62
-
63
- const instrumentor = new OpenAIAudioInstrumentor();
64
- instrumentor.instrument();
65
-
66
- return () => {
67
- instrumentor.uninstrument();
68
- Module._resolveFilename = origResolve;
69
- for (const moduleId of Object.keys(stubs)) delete require.cache[moduleId];
70
- exporter.reset();
71
- };
72
- }
73
-
74
- test('speech emits genai span with char count', async () => {
75
- const teardown = instrumented();
76
- try {
77
- const client = new StubSpeech();
78
- assert.deepEqual(
79
- await client.create({ input: 'hello world', model: 'tts-1', voice: 'alloy' }),
80
- Buffer.from('audio-bytes')
81
- );
82
-
83
- const [span] = exporter.getFinishedSpans();
84
- assert.equal(span.name, 'text_to_speech');
85
- assert.equal(span.attributes['gen_ai.system'], 'openai');
86
- assert.equal(span.attributes['gen_ai.operation.name'], 'text_to_speech');
87
- assert.equal(span.attributes['gen_ai.request.model'], 'tts-1');
88
- assert.equal(span.attributes['gen_ai.usage.input_characters'], 'hello world'.length);
89
- assert.equal(span.attributes['gen_ai.usage.input_seconds'], undefined);
90
- assert.equal(span.status.code, SpanStatusCode.UNSET);
91
- } finally {
92
- teardown();
93
- }
94
- });
95
-
96
- test('speech records error status on failure', async () => {
97
- const teardown = instrumented();
98
- try {
99
- const client = new StubSpeech();
100
- await assert.rejects(() => client.create({ input: 'boom', model: 'tts-1' }), /api error/);
101
-
102
- const [span] = exporter.getFinishedSpans();
103
- assert.equal(span.status.code, SpanStatusCode.ERROR);
104
- } finally {
105
- teardown();
106
- }
107
- });
108
-
109
- test('transcriptions emits span with audio duration', async () => {
110
- const teardown = instrumented();
111
- try {
112
- const client = new StubTranscriptions();
113
- const result = await client.create({ file: Buffer.from('audio'), model: 'whisper-1' });
114
- assert.equal(result.duration, 12.4);
115
-
116
- const [span] = exporter.getFinishedSpans();
117
- assert.equal(span.name, 'speech_to_text');
118
- assert.equal(span.attributes['gen_ai.system'], 'openai');
119
- assert.equal(span.attributes['gen_ai.operation.name'], 'speech_to_text');
120
- assert.equal(span.attributes['gen_ai.request.model'], 'whisper-1');
121
- assert.equal(span.attributes['gen_ai.usage.input_seconds'], 12.4);
122
- assert.equal(span.attributes['gen_ai.usage.input_characters'], undefined);
123
- assert.equal(span.status.code, SpanStatusCode.UNSET);
124
- } finally {
125
- teardown();
126
- }
127
- });
128
-
129
- test('transcriptions records error status on failure', async () => {
130
- const teardown = instrumented();
131
- try {
132
- const client = new StubTranscriptions();
133
- await assert.rejects(
134
- () => client.create({ file: Buffer.from('audio'), model: 'boom' }),
135
- /api error/
136
- );
137
-
138
- const [span] = exporter.getFinishedSpans();
139
- assert.equal(span.status.code, SpanStatusCode.ERROR);
140
- } finally {
141
- teardown();
142
- }
143
- });
144
-
145
- test('uninstrument restores original methods', async () => {
146
- const teardown = instrumented();
147
- try {
148
- const client = new StubSpeech();
149
- await client.create({ input: 'x', model: 'tts-1' });
150
- assert.equal(exporter.getFinishedSpans().length, 1);
151
- } finally {
152
- teardown();
153
- }
154
- });
155
-
156
- test('system is azure when client targets azure', async () => {
157
- const teardown = instrumented();
158
- try {
159
- const client = new StubSpeech();
160
- // Azure is reached via the same openai SDK; the vendor is read off the
161
- // client base URL so the span is attributed to azure.ai.openai, not openai.
162
- client._client = { baseURL: 'https://acme.openai.azure.com/' };
163
- await client.create({ input: 'hi', model: 'tts-1' });
164
-
165
- const [span] = exporter.getFinishedSpans();
166
- assert.equal(span.attributes['gen_ai.system'], 'azure.ai.openai');
167
- } finally {
168
- teardown();
169
- }
170
- });
@@ -1,83 +0,0 @@
1
- 'use strict';
2
-
3
- // Tests for the OpenAI non-streaming cached-prompt token complement. It wraps the
4
- // primary instrumentor's `_endSpan({ span, type, result })` to stamp
5
- // `gen_ai.usage.cache_read_input_tokens` from `usage.prompt_tokens_details.cached_tokens`.
6
-
7
- const test = require('node:test');
8
- const assert = require('node:assert/strict');
9
-
10
- const {
11
- OpenAIPromptCachingInstrumentor,
12
- } = require('../../../src/instrumentation/openai/get_cache_and_reasoning_telemetry');
13
-
14
- function fakeSpan() {
15
- const attrs = {};
16
- return {
17
- attrs,
18
- isRecording: () => true,
19
- setAttribute(key, value) {
20
- attrs[key] = value;
21
- },
22
- };
23
- }
24
-
25
- test('stamps cache_read_input_tokens and still calls the original _endSpan', () => {
26
- const calls = [];
27
- const instrumentation = {
28
- _endSpan(args) {
29
- calls.push(args);
30
- },
31
- };
32
- new OpenAIPromptCachingInstrumentor().instrument(instrumentation);
33
-
34
- const span = fakeSpan();
35
- instrumentation._endSpan({
36
- span,
37
- type: 'chat',
38
- result: { usage: { prompt_tokens: 1600, prompt_tokens_details: { cached_tokens: 1536 } } },
39
- });
40
-
41
- assert.equal(span.attrs['gen_ai.usage.cache_read_input_tokens'], 1536);
42
- assert.equal(calls.length, 1);
43
- });
44
-
45
- test('sets nothing when there are no cached tokens', () => {
46
- const instrumentation = { _endSpan() {} };
47
- new OpenAIPromptCachingInstrumentor().instrument(instrumentation);
48
-
49
- const span = fakeSpan();
50
- instrumentation._endSpan({ span, type: 'chat', result: { usage: { prompt_tokens: 10 } } });
51
-
52
- assert.equal(span.attrs['gen_ai.usage.cache_read_input_tokens'], undefined);
53
- });
54
-
55
- test('stamps reasoning_tokens from completion_tokens_details', () => {
56
- const instrumentation = { _endSpan() {} };
57
- new OpenAIPromptCachingInstrumentor().instrument(instrumentation);
58
-
59
- const span = fakeSpan();
60
- instrumentation._endSpan({
61
- span,
62
- type: 'chat',
63
- result: { usage: { output_tokens: 115, completion_tokens_details: { reasoning_tokens: 64 } } },
64
- });
65
-
66
- assert.equal(span.attrs['gen_ai.usage.reasoning_tokens'], 64);
67
- });
68
-
69
- test('is a no-op when the instrumentor has no _endSpan', () => {
70
- const instrumentation = {};
71
- new OpenAIPromptCachingInstrumentor().instrument(instrumentation);
72
- assert.equal(instrumentation._endSpan, undefined);
73
- });
74
-
75
- test('uninstrument restores the original _endSpan', () => {
76
- const original = () => {};
77
- const instrumentation = { _endSpan: original };
78
- const instrumentor = new OpenAIPromptCachingInstrumentor();
79
- instrumentor.instrument(instrumentation);
80
- assert.notEqual(instrumentation._endSpan, original);
81
- instrumentor.uninstrument();
82
- assert.equal(instrumentation._endSpan, original);
83
- });
@@ -1,83 +0,0 @@
1
- 'use strict';
2
-
3
- // Tests for the OpenAI request-side prompt-cache param capture.
4
- //
5
- // The traceloop instrumentation instance is stubbed with a `startSpan` that
6
- // returns a fake span, so the wrap can be exercised without the real SDK.
7
-
8
- const test = require('node:test');
9
- const assert = require('node:assert/strict');
10
-
11
- const {
12
- OpenAICacheConfigInstrumentor,
13
- } = require('../../../src/instrumentation/openai/get_cache_config_telemetry');
14
-
15
- function makeFakeSpan() {
16
- const attributes = {};
17
- return {
18
- attributes,
19
- setAttribute(key, value) {
20
- attributes[key] = value;
21
- },
22
- };
23
- }
24
-
25
- function makeStubInstrumentation() {
26
- return {
27
- startSpan() {
28
- return makeFakeSpan();
29
- },
30
- };
31
- }
32
-
33
- test('stamps prompt cache key and retention from the request params', () => {
34
- const instrumentation = makeStubInstrumentation();
35
- new OpenAICacheConfigInstrumentor().instrument(instrumentation);
36
-
37
- const span = instrumentation.startSpan({
38
- type: 'chat',
39
- params: {
40
- model: 'gpt-4o-mini',
41
- prompt_cache_key: 'session-42',
42
- prompt_cache_retention: '24h',
43
- },
44
- });
45
-
46
- assert.equal(span.attributes['weflayr.cache.key'], 'session-42');
47
- assert.equal(span.attributes['weflayr.cache.retention'], '24h');
48
- });
49
-
50
- test('stamps prompt cache options ttl as the retention', () => {
51
- const instrumentation = makeStubInstrumentation();
52
- new OpenAICacheConfigInstrumentor().instrument(instrumentation);
53
-
54
- const span = instrumentation.startSpan({
55
- type: 'chat',
56
- params: {
57
- model: 'gpt-5.6',
58
- prompt_cache_options: { ttl: '30m' },
59
- },
60
- });
61
-
62
- assert.equal(span.attributes['weflayr.cache.retention'], '30m');
63
- });
64
-
65
- test('no attributes without cache params', () => {
66
- const instrumentation = makeStubInstrumentation();
67
- new OpenAICacheConfigInstrumentor().instrument(instrumentation);
68
-
69
- const span = instrumentation.startSpan({ type: 'chat', params: { model: 'gpt-4o-mini' } });
70
-
71
- assert.ok(!('weflayr.cache.key' in span.attributes));
72
- assert.ok(!('weflayr.cache.retention' in span.attributes));
73
- });
74
-
75
- test('uninstrument restores the original startSpan', () => {
76
- const instrumentation = makeStubInstrumentation();
77
- const original = instrumentation.startSpan;
78
- const instrumentor = new OpenAICacheConfigInstrumentor();
79
- instrumentor.instrument(instrumentation);
80
- assert.notEqual(instrumentation.startSpan, original);
81
- instrumentor.uninstrument();
82
- assert.equal(instrumentation.startSpan, original);
83
- });
@@ -1,145 +0,0 @@
1
- 'use strict';
2
-
3
- // Tests for the bundled OpenAI embeddings instrumentor.
4
- //
5
- // The real `openai` Embeddings resource class is stubbed with a `create` method
6
- // that mirrors the SDK's shape — resolving to a response carrying `model` and a
7
- // `usage.prompt_tokens` count — so the instrumentor can be exercised without
8
- // network access or the dependency installed.
9
-
10
- const test = require('node:test');
11
- const assert = require('node:assert/strict');
12
- const Module = require('node:module');
13
-
14
- const { trace, SpanStatusCode } = require('@opentelemetry/api');
15
- const {
16
- BasicTracerProvider,
17
- InMemorySpanExporter,
18
- SimpleSpanProcessor,
19
- } = require('@opentelemetry/sdk-trace-base');
20
-
21
- const {
22
- OpenAIEmbeddingsInstrumentor,
23
- } = require('../../../src/instrumentation/openai/get_embeddings_telemetry');
24
-
25
- const EMBEDDINGS_MODULE = 'openai/resources/embeddings';
26
-
27
- const exporter = new InMemorySpanExporter();
28
- trace.setGlobalTracerProvider(
29
- new BasicTracerProvider({ spanProcessors: [new SimpleSpanProcessor(exporter)] })
30
- );
31
-
32
- class StubEmbeddings {
33
- create(body = {}) {
34
- if (body.model === 'boom') return Promise.reject(new Error('api error'));
35
- return Promise.resolve({
36
- object: 'list',
37
- data: [{ embedding: [0.1, 0.2] }],
38
- model: 'text-embedding-3-small',
39
- usage: { prompt_tokens: 8, total_tokens: 8 },
40
- });
41
- }
42
- }
43
-
44
- // Stub the openai embeddings resource module, install the instrumentor + the
45
- // in-memory exporter, and return a teardown that restores everything.
46
- function instrumented() {
47
- const stubs = { [EMBEDDINGS_MODULE]: { Embeddings: StubEmbeddings } };
48
- const origResolve = Module._resolveFilename;
49
- Module._resolveFilename = function patched(request, ...rest) {
50
- if (request in stubs) return request;
51
- return origResolve.call(this, request, ...rest);
52
- };
53
- for (const [moduleId, exports] of Object.entries(stubs)) {
54
- require.cache[moduleId] = { id: moduleId, filename: moduleId, loaded: true, exports };
55
- }
56
-
57
- const instrumentor = new OpenAIEmbeddingsInstrumentor();
58
- instrumentor.instrument();
59
-
60
- return () => {
61
- instrumentor.uninstrument();
62
- Module._resolveFilename = origResolve;
63
- for (const moduleId of Object.keys(stubs)) delete require.cache[moduleId];
64
- exporter.reset();
65
- };
66
- }
67
-
68
- test('embeddings emits genai span with prompt tokens', async () => {
69
- const teardown = instrumented();
70
- try {
71
- const client = new StubEmbeddings();
72
- const result = await client.create({ input: 'hello', model: 'text-embedding-3-small' });
73
- assert.equal(result.usage.prompt_tokens, 8);
74
-
75
- const [span] = exporter.getFinishedSpans();
76
- assert.equal(span.name, 'embeddings');
77
- assert.equal(span.attributes['gen_ai.system'], 'openai');
78
- assert.equal(span.attributes['gen_ai.operation.name'], 'embeddings');
79
- assert.equal(span.attributes['gen_ai.request.model'], 'text-embedding-3-small');
80
- assert.equal(span.attributes['gen_ai.response.model'], 'text-embedding-3-small');
81
- assert.equal(span.attributes['gen_ai.usage.input_tokens'], 8);
82
- assert.deepEqual(JSON.parse(span.attributes['gen_ai.input.messages']), [
83
- { role: 'user', parts: [{ type: 'text', content: 'hello' }] },
84
- ]);
85
- assert.equal(span.status.code, SpanStatusCode.UNSET);
86
- } finally {
87
- teardown();
88
- }
89
- });
90
-
91
- test('embeddings emits one input message per element of a list input', async () => {
92
- const teardown = instrumented();
93
- try {
94
- const client = new StubEmbeddings();
95
- await client.create({ input: ['a', 'b'], model: 'text-embedding-3-small' });
96
-
97
- const [span] = exporter.getFinishedSpans();
98
- assert.deepEqual(JSON.parse(span.attributes['gen_ai.input.messages']), [
99
- { role: 'user', parts: [{ type: 'text', content: 'a' }] },
100
- { role: 'user', parts: [{ type: 'text', content: 'b' }] },
101
- ]);
102
- } finally {
103
- teardown();
104
- }
105
- });
106
-
107
- test('embeddings records error status on failure', async () => {
108
- const teardown = instrumented();
109
- try {
110
- const client = new StubEmbeddings();
111
- await assert.rejects(() => client.create({ input: 'x', model: 'boom' }), /api error/);
112
-
113
- const [span] = exporter.getFinishedSpans();
114
- assert.equal(span.status.code, SpanStatusCode.ERROR);
115
- } finally {
116
- teardown();
117
- }
118
- });
119
-
120
- test('uninstrument restores original methods', async () => {
121
- const teardown = instrumented();
122
- try {
123
- const client = new StubEmbeddings();
124
- await client.create({ input: 'x', model: 'text-embedding-3-small' });
125
- assert.equal(exporter.getFinishedSpans().length, 1);
126
- } finally {
127
- teardown();
128
- }
129
- });
130
-
131
- test('system is azure when client targets azure', async () => {
132
- const teardown = instrumented();
133
- try {
134
- const client = new StubEmbeddings();
135
- // Azure is reached via the same openai SDK; the vendor is read off the
136
- // client base URL so the span is attributed to azure.ai.openai, not openai.
137
- client._client = { baseURL: 'https://acme.openai.azure.com/' };
138
- await client.create({ input: 'hi', model: 'text-embedding-3-small' });
139
-
140
- const [span] = exporter.getFinishedSpans();
141
- assert.equal(span.attributes['gen_ai.system'], 'azure.ai.openai');
142
- } finally {
143
- teardown();
144
- }
145
- });