weflayr 0.23.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 (225) hide show
  1. package/README.md +2 -2
  2. package/dist/{api → src/api}/generated/facade.gen.d.ts +163 -12
  3. package/dist/{api → src/api}/generated/facade.gen.js +10 -2
  4. package/dist/src/api/generated/index.d.ts +2 -0
  5. package/dist/{api → src/api}/generated/index.js +9 -1
  6. package/dist/{api → src/api}/generated/sdk.gen.d.ts +35 -3
  7. package/dist/{api → src/api}/generated/sdk.gen.js +88 -4
  8. package/{src/api/generated/types.gen.ts → dist/src/api/generated/types.gen.d.ts} +692 -116
  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/dist/src/instrumentation/google/get_cache_telemetry.js +38 -0
  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 -749
  119. package/eslint.config.mjs +0 -36
  120. package/index.d.ts +0 -167
  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 -68
  138. package/src/api/generated/index.ts +0 -4
  139. package/src/api/generated/sdk.gen.ts +0 -121
  140. package/src/api/index.ts +0 -45
  141. package/src/api/makeEndpoint.ts +0 -54
  142. package/src/auto-instrument.js +0 -171
  143. package/src/index.js +0 -19
  144. package/src/instrumentation/anthropic/get_cache_and_reasoning_telemetry.js +0 -107
  145. package/src/instrumentation/anthropic/get_streaming_stop_reason_telemetry.js +0 -121
  146. package/src/instrumentation/anthropic/get_tool_definitions_telemetry.js +0 -50
  147. package/src/instrumentation/anthropic/set_telemetry_attributes.js +0 -37
  148. package/src/instrumentation/bedrock/get_cache_telemetry.js +0 -104
  149. package/src/instrumentation/bedrock/get_input_message_content_telemetry.js +0 -94
  150. package/src/instrumentation/bedrock/get_streaming_output_message_telemetry.js +0 -87
  151. package/src/instrumentation/bedrock/set_telemetry_attributes.js +0 -36
  152. package/src/instrumentation/cohere/get_chat_telemetry.js +0 -88
  153. package/src/instrumentation/cohere/get_embeddings_telemetry.js +0 -107
  154. package/src/instrumentation/cohere/set_telemetry_attributes.js +0 -32
  155. package/src/instrumentation/elevenlabs/full_instrumentation.js +0 -236
  156. package/src/instrumentation/google/get_audio_telemetry.js +0 -30
  157. package/src/instrumentation/google/get_cache_telemetry.js +0 -25
  158. package/src/instrumentation/google/get_embeddings_telemetry.js +0 -99
  159. package/src/instrumentation/google/set_telemetry_attributes.js +0 -98
  160. package/src/instrumentation/openai/get_audio_telemetry.js +0 -149
  161. package/src/instrumentation/openai/get_cache_and_reasoning_telemetry.js +0 -71
  162. package/src/instrumentation/openai/get_embeddings_telemetry.js +0 -107
  163. package/src/instrumentation/openai/get_streaming_usage.js +0 -81
  164. package/src/instrumentation/openai/set_telemetry_attributes.js +0 -39
  165. package/src/instrumentation/vercel/full_instrumentation.js +0 -44
  166. package/src/logger.js +0 -8
  167. package/src/otel/exporter.js +0 -108
  168. package/src/otel/propagation.js +0 -133
  169. package/src/otel/span-filter.js +0 -69
  170. package/src/otel/span-processor.js +0 -162
  171. package/src/otel/vercel-ai-sdk-span-filter.js +0 -79
  172. package/src/setup.js +0 -167
  173. package/tests/api/index.test.js +0 -437
  174. package/tests/index.test.js +0 -824
  175. package/tests/instrumentation/anthropic/get_cache_and_reasoning_telemetry.test.js +0 -158
  176. package/tests/instrumentation/anthropic/get_streaming_stop_reason_telemetry.test.js +0 -117
  177. package/tests/instrumentation/anthropic/get_tool_definitions_telemetry.test.js +0 -82
  178. package/tests/instrumentation/bedrock/get_cache_telemetry.test.js +0 -102
  179. package/tests/instrumentation/bedrock/get_input_message_content_telemetry.test.js +0 -89
  180. package/tests/instrumentation/bedrock/get_streaming_output_message_telemetry.test.js +0 -87
  181. package/tests/instrumentation/cohere/get_chat_telemetry.test.js +0 -148
  182. package/tests/instrumentation/cohere/get_embeddings_telemetry.test.js +0 -132
  183. package/tests/instrumentation/elevenlabs/full_instrumentation.test.js +0 -258
  184. package/tests/instrumentation/google/get_embeddings_telemetry.test.js +0 -128
  185. package/tests/instrumentation/google/get_reasoning_telemetry.test.js +0 -41
  186. package/tests/instrumentation/google/set_telemetry_attributes.test.js +0 -219
  187. package/tests/instrumentation/openai/get_audio_telemetry.test.js +0 -170
  188. package/tests/instrumentation/openai/get_cache_and_reasoning_telemetry.test.js +0 -83
  189. package/tests/instrumentation/openai/get_embeddings_telemetry.test.js +0 -145
  190. package/tests/instrumentation/openai/get_streaming_usage.test.js +0 -105
  191. package/tests/instrumentation/vercel/full_instrumentation.test.js +0 -16
  192. package/tests/otel/vercel-ai-sdk-span-filter.test.js +0 -159
  193. package/tsconfig.json +0 -18
  194. /package/dist/{api → src/api}/caseConversion.d.ts +0 -0
  195. /package/dist/{api → src/api}/caseConversion.js +0 -0
  196. /package/dist/{api → src/api}/generated/client/client.gen.d.ts +0 -0
  197. /package/dist/{api → src/api}/generated/client/client.gen.js +0 -0
  198. /package/dist/{api → src/api}/generated/client/index.d.ts +0 -0
  199. /package/dist/{api → src/api}/generated/client/index.js +0 -0
  200. /package/dist/{api → src/api}/generated/client/types.gen.d.ts +0 -0
  201. /package/dist/{api → src/api}/generated/client/types.gen.js +0 -0
  202. /package/dist/{api → src/api}/generated/client/utils.gen.d.ts +0 -0
  203. /package/dist/{api → src/api}/generated/client/utils.gen.js +0 -0
  204. /package/dist/{api → src/api}/generated/client.gen.d.ts +0 -0
  205. /package/dist/{api → src/api}/generated/client.gen.js +0 -0
  206. /package/dist/{api → src/api}/generated/core/auth.gen.d.ts +0 -0
  207. /package/dist/{api → src/api}/generated/core/auth.gen.js +0 -0
  208. /package/dist/{api → src/api}/generated/core/bodySerializer.gen.d.ts +0 -0
  209. /package/dist/{api → src/api}/generated/core/bodySerializer.gen.js +0 -0
  210. /package/dist/{api → src/api}/generated/core/params.gen.d.ts +0 -0
  211. /package/dist/{api → src/api}/generated/core/params.gen.js +0 -0
  212. /package/dist/{api → src/api}/generated/core/pathSerializer.gen.d.ts +0 -0
  213. /package/dist/{api → src/api}/generated/core/pathSerializer.gen.js +0 -0
  214. /package/dist/{api → src/api}/generated/core/queryKeySerializer.gen.d.ts +0 -0
  215. /package/dist/{api → src/api}/generated/core/queryKeySerializer.gen.js +0 -0
  216. /package/dist/{api → src/api}/generated/core/serverSentEvents.gen.d.ts +0 -0
  217. /package/dist/{api → src/api}/generated/core/serverSentEvents.gen.js +0 -0
  218. /package/dist/{api → src/api}/generated/core/types.gen.d.ts +0 -0
  219. /package/dist/{api → src/api}/generated/core/types.gen.js +0 -0
  220. /package/dist/{api → src/api}/generated/core/utils.gen.d.ts +0 -0
  221. /package/dist/{api → src/api}/generated/core/utils.gen.js +0 -0
  222. /package/dist/{api → src/api}/generated/types.gen.js +0 -0
  223. /package/dist/{api → src/api}/index.d.ts +0 -0
  224. /package/dist/{api → src/api}/index.js +0 -0
  225. /package/dist/{api → src/api}/makeEndpoint.d.ts +0 -0
@@ -1,39 +0,0 @@
1
- 'use strict';
2
-
3
- /**
4
- * OpenAI telemetry complement — the registered orchestrator.
5
- *
6
- * Wires every weflayr-supplied patch the traceloop OpenAI instrumentor misses:
7
- * - the audio (TTS/STT) and embeddings endpoints it doesn't cover, and
8
- * - usage it drops on the chat endpoint it does cover: streamed token usage and
9
- * non-streamed cached-prompt tokens (these enrich the traceloop instrumentor
10
- * instance, hence the `instrumentation` argument).
11
- */
12
-
13
- const { OpenAIAudioInstrumentor } = require('./get_audio_telemetry');
14
- const { OpenAIEmbeddingsInstrumentor } = require('./get_embeddings_telemetry');
15
- const { OpenAIStreamingUsageInstrumentor } = require('./get_streaming_usage');
16
- const { OpenAIPromptCachingInstrumentor } = require('./get_cache_and_reasoning_telemetry');
17
-
18
- class OpenAITelemetryInstrumentor {
19
- constructor() {
20
- this._subInstrumentors = [
21
- new OpenAIAudioInstrumentor(),
22
- new OpenAIEmbeddingsInstrumentor(),
23
- new OpenAIStreamingUsageInstrumentor(),
24
- new OpenAIPromptCachingInstrumentor(),
25
- ];
26
- }
27
-
28
- // The endpoint complements ignore `instrumentation`; the streaming/cache ones
29
- // patch its internal handlers.
30
- instrument(instrumentation) {
31
- for (const sub of this._subInstrumentors) sub.instrument(instrumentation);
32
- }
33
-
34
- uninstrument() {
35
- for (const sub of this._subInstrumentors) sub.uninstrument();
36
- }
37
- }
38
-
39
- module.exports = { OpenAITelemetryInstrumentor };
@@ -1,44 +0,0 @@
1
- 'use strict';
2
-
3
- /**
4
- * Instrumentor for the Vercel AI SDK (`ai` package, v7+).
5
- *
6
- * The AI SDK ships its own OTel integration in `@ai-sdk/otel`; instrumenting
7
- * is registering it globally so every generateText/streamText/embed call emits
8
- * GenAI semconv spans through the tracer provider weflayr's setup() installed.
9
- * `usage: true` adds the `ai.usage.*` token details (reasoning tokens, uncached
10
- * input) that the semconv attributes do not carry.
11
- *
12
- * The aggregate spans the integration emits around each model call
13
- * (invoke_agent, agent_step, duplicated embeddings spans) are filtered out
14
- * before export by otel/vercel-ai-sdk-span-filter.js.
15
- */
16
- class VercelAiSdkInstrumentor {
17
- instrument() {
18
- let registerTelemetry;
19
- let OpenTelemetry;
20
- try {
21
- ({ registerTelemetry } = require('ai'));
22
- ({ OpenTelemetry } = require('@ai-sdk/otel'));
23
- } catch (err) {
24
- throw new Error(
25
- 'weflayr.autoInstrument("vercel_ai_gateway"): failed to load "ai" / "@ai-sdk/otel". ' +
26
- `Install them with: npm install ai @ai-sdk/otel\nUnderlying error: ${err.message}`
27
- );
28
- }
29
- // registerTelemetry only exists since v7.
30
- if (typeof registerTelemetry !== 'function') {
31
- throw new Error(
32
- 'weflayr.autoInstrument("vercel_ai_gateway") requires version 7+ of the Vercel AI SDK ' +
33
- '(the "ai" package), which added global telemetry registration. ' +
34
- 'Upgrade with: npm install ai@latest @ai-sdk/otel.\n' +
35
- 'On ai <= 6 telemetry can only be enabled per call: remove "vercel_ai_gateway" from ' +
36
- 'aiSdks (pass an empty list if no other sdks need to be instrumented). Instead, make sure ' +
37
- 'experimental_telemetry: { isEnabled: true } is passed on each generateText/streamText call.'
38
- );
39
- }
40
- registerTelemetry(new OpenTelemetry({ usage: true }));
41
- }
42
- }
43
-
44
- module.exports = { VercelAiSdkInstrumentor };
package/src/logger.js DELETED
@@ -1,8 +0,0 @@
1
- 'use strict';
2
-
3
- const { debuglog } = require('node:util');
4
-
5
- // Enable with NODE_DEBUG=weflayr
6
- const debug = debuglog('weflayr');
7
-
8
- module.exports = { debug };
@@ -1,108 +0,0 @@
1
- 'use strict';
2
-
3
- const retry = require('async-retry');
4
- const { OTLPTraceExporter } = require('@opentelemetry/exporter-trace-otlp-http');
5
-
6
- const { debug } = require('../logger');
7
-
8
- // OTLP-spec retryable statuses: rate-limit + transient server errors.
9
- const _RETRYABLE_STATUS = new Set([429, 502, 503, 504]);
10
-
11
- function _isNonRetryable(err) {
12
- // Tells async-retry's `bail` whether to give up: bail on 4xx (other than
13
- // 429); retry on retryable statuses and on transport errors (no status).
14
- const status = err?.exportResult?.error?.code;
15
- return status !== undefined && !_RETRYABLE_STATUS.has(status);
16
- }
17
-
18
- function _formatFailure(result, url) {
19
- const err = result?.error;
20
- const status = err?.code;
21
- const body = typeof err?.data === 'string' ? err.data.slice(0, 200) : undefined;
22
- const message = err?.message || String(err) || 'unknown error';
23
- let hint = '';
24
- if (status === 401 || status === 403) {
25
- hint = ' Check your apiKey / WEFLAYR_API_KEY.';
26
- } else if (status === 404) {
27
- hint = ' Check the baseUrl is correct.';
28
- } else if (!status && /ECONN|ENOTFOUND|timeout/i.test(message)) {
29
- hint = ' The endpoint is unreachable — check baseUrl and network.';
30
- }
31
- return (
32
- `Weflayr: failed to export telemetry to ${url}` +
33
- (status ? ` (HTTP ${status})` : '') +
34
- `: ${message}.${hint}` +
35
- (body ? ` Response: ${body}` : '')
36
- );
37
- }
38
-
39
- // Wrap a callback-style OTel exporter `export(spans, cb)` with retry. Retries
40
- // transport errors + retryable HTTP statuses; bails on other 4xx.
41
- function _exportWithRetry(originalExport, { maxRetries, maxRetryMs }) {
42
- return (spans, resultCallback) => {
43
- retry(
44
- async (bail) => {
45
- const result = await new Promise((resolve) => originalExport(spans, resolve));
46
- if (result?.code === 0) return result;
47
- const err = new Error(result?.error?.message || 'export failed');
48
- err.exportResult = result;
49
- if (_isNonRetryable(err)) {
50
- bail(err);
51
- return;
52
- }
53
- throw err;
54
- },
55
- { retries: maxRetries - 1, minTimeout: 50, maxRetryTime: maxRetryMs, factor: 2 }
56
- )
57
- .then((result) => resultCallback(result))
58
- .catch((err) => resultCallback(err.exportResult || { code: 1, error: err }));
59
- };
60
- }
61
-
62
- function buildExporter({
63
- baseUrl,
64
- apiKey,
65
- timeoutMs = 5000,
66
- warnOnExportError = true,
67
- maxRetries = 2,
68
- maxRetryMs = 1000,
69
- }) {
70
- const url = `${baseUrl.replace(/\/$/, '')}/`;
71
- const exporter = new OTLPTraceExporter({
72
- url,
73
- headers: {
74
- Authorization: `Bearer ${apiKey}`,
75
- },
76
- timeoutMillis: timeoutMs,
77
- });
78
- const originalExport = exporter.export.bind(exporter);
79
- const wrappedExport = _exportWithRetry(originalExport, { maxRetries, maxRetryMs });
80
- exporter.export = (spans, resultCallback) => {
81
- const start = Date.now();
82
- debug('exporter.export: posting count=%d', spans.length);
83
- wrappedExport(spans, (result) => {
84
- const ms = Date.now() - start;
85
- if (result && result.code === 0) {
86
- debug('exporter.export: ok count=%d elapsed_ms=%d', spans.length, ms);
87
- } else {
88
- debug(
89
- 'exporter.export: FAIL count=%d elapsed_ms=%d code=%s error=%s',
90
- spans.length,
91
- ms,
92
- result?.code,
93
- result?.error?.message || result?.error || '(none)'
94
- );
95
- if (warnOnExportError) {
96
- // console.warn writes to stderr synchronously. process.emitWarning
97
- // is queued for the next tick, so a caller doing process.exit() from
98
- // their error handler races past it and the warning is lost.
99
- console.warn(`[weflayr] ${_formatFailure(result, url)}`);
100
- }
101
- }
102
- resultCallback(result);
103
- });
104
- };
105
- return exporter;
106
- }
107
-
108
- module.exports = { buildExporter, _exportWithRetry, _RETRYABLE_STATUS };
@@ -1,133 +0,0 @@
1
- // Copyright 2024 Langfuse GmbH
2
- // Licensed under the MIT License.
3
- // Original source: https://github.com/langfuse/langfuse-js/blob/main/packages/core/src/propagation.ts
4
- //
5
- // Modifications copyright 2026 Weflayr
6
- // This file has been modified from its original form:
7
- // - Translated from TypeScript to JavaScript
8
- // - Replaced Langfuse's fixed schema with Weflayr's structured metadata
9
- // (featureName, customerName, providerName, extraTags) plus an
10
- // auto-generated per-call uuid
11
- // - Removed asBaggage cross-process propagation (not needed yet)
12
- // - Removed experiment framework keys
13
- // - Structured fields are written under stable `weflayr.*` span attribute
14
- // keys; extraTags entries are written verbatim
15
- //
16
- // See LICENSE-MIT in the package root for the full license text.
17
-
18
- 'use strict';
19
-
20
- const { randomUUID } = require('node:crypto');
21
- const { context: otelContext, trace, createContextKey } = require('@opentelemetry/api');
22
-
23
- const WEFLAYR_METADATA_CONTEXT_KEY = createContextKey('weflayr_metadata');
24
-
25
- const FEATURE_NAME_ATTR = 'weflayr.feature_name';
26
- const CUSTOMER_NAME_ATTR = 'weflayr.customer_name';
27
- const PROVIDER_NAME_ATTR = 'weflayr.provider_name';
28
- const UUID_ATTR = 'weflayr.uuid';
29
- // Prefix for user-supplied `extraTags` so downstream normalizers can pick
30
- // them out without colliding with instrumentor-set `gen_ai.*` attributes.
31
- const EXTRA_TAG_PREFIX = 'weflayr.tag.';
32
-
33
- function getMergedMetadataFromContext(parentContext) {
34
- const ctx = parentContext ?? otelContext.active();
35
- const existing = ctx.getValue(WEFLAYR_METADATA_CONTEXT_KEY);
36
- return existing && typeof existing === 'object' ? { ...existing } : {};
37
- }
38
-
39
- function _buildAttributes({ featureName, customerName, providerName, extraTags, spanUuid }) {
40
- const attributes = {
41
- [FEATURE_NAME_ATTR]: featureName,
42
- [CUSTOMER_NAME_ATTR]: customerName,
43
- [UUID_ATTR]: spanUuid,
44
- };
45
- for (const [key, value] of Object.entries(extraTags)) {
46
- attributes[`${EXTRA_TAG_PREFIX}${key}`] = value;
47
- }
48
- if (providerName !== undefined && providerName !== null) {
49
- attributes[PROVIDER_NAME_ATTR] = providerName;
50
- }
51
- return attributes;
52
- }
53
-
54
- /**
55
- * Attach Weflayr metadata to every LLM span created inside this scope.
56
- *
57
- * Callable form: `propagateMetadata(options, fn)` runs `fn` immediately.
58
- * Decorator form: `propagateMetadata(options)` returns a wrapper usable as a
59
- * function-decorator (`@propagateMetadata(...)` on class methods) or as a
60
- * plain `wrap(fn)` -> wrappedFn helper. Each invocation of the wrapped
61
- * function mints a fresh `uuid`, matching the callable form's "one uuid per
62
- * propagateMetadata call" contract.
63
- */
64
- function propagateMetadata(options, fn) {
65
- const { featureName, customerId } = options ?? {};
66
- let { customerName } = options ?? {};
67
- if (customerId != null) {
68
- process.emitWarning(
69
- 'propagateMetadata: `customerId` is deprecated, use `customerName`',
70
- 'DeprecationWarning'
71
- );
72
- customerName = customerName ?? customerId;
73
- }
74
- if (featureName == null || customerName == null) {
75
- throw new Error('propagateMetadata: `featureName` and `customerName` are required');
76
- }
77
- const normalizedOptions = { ...options, customerName };
78
-
79
- if (typeof fn === 'function') {
80
- return _runWithMetadata(normalizedOptions, fn);
81
- }
82
-
83
- return function decorator(target, key, descriptor) {
84
- if (descriptor && typeof descriptor.value === 'function') {
85
- const original = descriptor.value;
86
- descriptor.value = function wrapped(...args) {
87
- return _runWithMetadata(normalizedOptions, () => original.apply(this, args));
88
- };
89
- return descriptor;
90
- }
91
- if (typeof target === 'function') {
92
- return function wrapped(...args) {
93
- return _runWithMetadata(normalizedOptions, () => target.apply(this, args));
94
- };
95
- }
96
- return target;
97
- };
98
- }
99
-
100
- function _runWithMetadata(options, fn) {
101
- const { featureName, customerName, providerName, extraTags } = options;
102
- const attributes = _buildAttributes({
103
- featureName,
104
- customerName,
105
- providerName,
106
- extraTags: extraTags ?? {},
107
- spanUuid: randomUUID().replace(/-/g, ''),
108
- });
109
-
110
- const parent = otelContext.active();
111
- const merged = { ...getMergedMetadataFromContext(parent), ...attributes };
112
- const newContext = parent.setValue(WEFLAYR_METADATA_CONTEXT_KEY, merged);
113
-
114
- const activeSpan = trace.getActiveSpan();
115
- if (activeSpan && activeSpan.isRecording && activeSpan.isRecording()) {
116
- for (const [k, v] of Object.entries(attributes)) {
117
- activeSpan.setAttribute(k, v);
118
- }
119
- }
120
-
121
- return otelContext.with(newContext, fn);
122
- }
123
-
124
- module.exports = {
125
- propagateMetadata,
126
- getMergedMetadataFromContext,
127
- WEFLAYR_METADATA_CONTEXT_KEY,
128
- FEATURE_NAME_ATTR,
129
- CUSTOMER_NAME_ATTR,
130
- PROVIDER_NAME_ATTR,
131
- UUID_ATTR,
132
- EXTRA_TAG_PREFIX,
133
- };
@@ -1,69 +0,0 @@
1
- // Copyright 2024 Langfuse GmbH
2
- // Licensed under the MIT License.
3
- // Original source: https://github.com/langfuse/langfuse-js/blob/main/packages/otel/src/span-filter.ts
4
- //
5
- // Modifications copyright 2026 Weflayr
6
- // This file has been modified from its original form:
7
- // - Translated from TypeScript to JavaScript
8
- // - Dropped the LANGFUSE_TRACER_NAME special case (we have no SDK-internal tracer)
9
- // - Dropped isLangfuseSpan
10
- //
11
- // See LICENSE-MIT in the package root for the full license text.
12
-
13
- 'use strict';
14
-
15
- const KNOWN_LLM_INSTRUMENTATION_SCOPE_PREFIXES = [
16
- 'agent_framework',
17
- 'ai',
18
- 'haystack',
19
- 'langsmith',
20
- 'litellm',
21
- 'openinference',
22
- 'opentelemetry.instrumentation.anthropic',
23
- 'opentelemetry.instrumentation.aws_bedrock',
24
- 'opentelemetry.instrumentation.bedrock',
25
- 'opentelemetry.instrumentation.gemini',
26
- 'opentelemetry.instrumentation.google_genai',
27
- 'opentelemetry.instrumentation.google_generativeai',
28
- 'opentelemetry.instrumentation.openai',
29
- 'opentelemetry.instrumentation.openai_v2',
30
- 'weflayr.instrumentation.elevenlabs',
31
- 'strands-agents',
32
- 'vllm',
33
- '@traceloop/instrumentation-openai',
34
- '@traceloop/instrumentation-anthropic',
35
- '@traceloop/instrumentation-bedrock',
36
- '@traceloop/instrumentation-cohere',
37
- '@traceloop/instrumentation-google-generativeai',
38
- '@traceloop/instrumentation-langchain',
39
- '@traceloop/instrumentation-llamaindex',
40
- '@traceloop/instrumentation-pinecone',
41
- '@traceloop/instrumentation-chromadb',
42
- '@traceloop/instrumentation-qdrant',
43
- '@traceloop/instrumentation-mcp',
44
- ];
45
-
46
- const EXACT_LLM_INSTRUMENTATION_SCOPES = new Set(['ai']);
47
-
48
- function isGenAISpan(span) {
49
- return Object.keys(span.attributes).some((key) => key.startsWith('gen_ai.'));
50
- }
51
-
52
- function isKnownLLMInstrumentor(span) {
53
- const scope = span.instrumentationScope.name;
54
- return KNOWN_LLM_INSTRUMENTATION_SCOPE_PREFIXES.some(
55
- (prefix) =>
56
- scope === prefix ||
57
- (!EXACT_LLM_INSTRUMENTATION_SCOPES.has(prefix) && scope.startsWith(`${prefix}.`))
58
- );
59
- }
60
-
61
- function isDefaultExportSpan(span) {
62
- return isGenAISpan(span) || isKnownLLMInstrumentor(span);
63
- }
64
-
65
- module.exports = {
66
- isGenAISpan,
67
- isKnownLLMInstrumentor,
68
- isDefaultExportSpan,
69
- };
@@ -1,162 +0,0 @@
1
- // Copyright 2024 Langfuse GmbH
2
- // Licensed under the MIT License.
3
- // Original source: https://github.com/langfuse/langfuse-js/blob/main/packages/otel/src/span-processor.ts
4
- //
5
- // Modifications copyright 2026 Weflayr
6
- // This file has been modified from its original form:
7
- // - Translated from TypeScript to JavaScript
8
- // - Removed MediaService integration (no media upload support yet)
9
- // - Removed LangfuseAPIClient / app-root marker logic (not used)
10
- // - Removed Langfuse-specific span attributes (TRACE_INPUT/OUTPUT/METADATA, IS_APP_ROOT, ENVIRONMENT, RELEASE)
11
- // - Mask hook now receives the full flat attribute bag, not a {data} envelope, and runs synchronously
12
- // - default_tags are applied as span attributes in onStart
13
- // - propagated tags come from Weflayr's tag bag (see propagation.js), not Langfuse's typed schema
14
- //
15
- // See LICENSE-MIT in the package root for the full license text.
16
-
17
- 'use strict';
18
-
19
- const { SpanStatusCode } = require('@opentelemetry/api');
20
- const { BatchSpanProcessor, SimpleSpanProcessor } = require('@opentelemetry/sdk-trace-base');
21
- const { EXTRA_TAG_PREFIX, getMergedMetadataFromContext } = require('./propagation');
22
- const { isDefaultExportSpan, isKnownLLMInstrumentor } = require('./span-filter');
23
- const {
24
- VercelAiSdkSpanFilter,
25
- stampVercelGatewayProviderName,
26
- } = require('./vercel-ai-sdk-span-filter');
27
- const { debug } = require('../logger');
28
-
29
- // setup({captureMessageContent: ...}) records the choice in this env var (the
30
- // official OTel GenAI one). Instrumentors gate content on their own knobs
31
- // (openllmetry reads its own config and captures by default), so the processor
32
- // enforces the flag itself: when the env var is "false", message content is
33
- // stripped from every span before export.
34
- const CONTENT_CAPTURE_ENV = 'OTEL_INSTRUMENTATION_GENAI_CAPTURE_MESSAGE_CONTENT';
35
-
36
- // The new-semconv JSON message attributes and the legacy indexed
37
- // `gen_ai.prompt.{i}.*` / `gen_ai.completion.{i}.*` attributes.
38
- const CONTENT_ATTRIBUTES = [
39
- 'gen_ai.input.messages',
40
- 'gen_ai.output.messages',
41
- 'gen_ai.system_instructions',
42
- ];
43
- const CONTENT_ATTRIBUTE_PREFIXES = ['gen_ai.prompt.', 'gen_ai.completion.'];
44
-
45
- function _isContentAttribute(key) {
46
- return (
47
- CONTENT_ATTRIBUTES.includes(key) ||
48
- CONTENT_ATTRIBUTE_PREFIXES.some((prefix) => key.startsWith(prefix))
49
- );
50
- }
51
-
52
- class WeflayrSpanProcessor {
53
- constructor({ exporter, exportMode = 'batch', defaultTags = {}, mask, shouldExportSpan } = {}) {
54
- if (!exporter) {
55
- throw new Error('WeflayrSpanProcessor: exporter is required');
56
- }
57
- this._delegate =
58
- exportMode === 'immediate'
59
- ? new SimpleSpanProcessor(exporter)
60
- : new BatchSpanProcessor(exporter);
61
- this._defaultTags = defaultTags;
62
- this._mask = mask;
63
- this._shouldExportSpan = shouldExportSpan ?? isDefaultExportSpan;
64
- this._vercelAiSdkSpanFilter = new VercelAiSdkSpanFilter();
65
- // LLM spans we've started but not yet seen end. On forceFlush we end any
66
- // leftovers with ERROR status — covers cases like openllmetry's anthropic
67
- // streaming wrapper, which leaks the span when the underlying call
68
- // rejects. Generic across providers; no per-provider patching needed.
69
- this._openLlmSpans = new Set();
70
- }
71
-
72
- onStart(span, parentContext) {
73
- for (const [k, v] of Object.entries(this._defaultTags)) {
74
- span.setAttribute(`${EXTRA_TAG_PREFIX}${k}`, v);
75
- }
76
- const propagated = getMergedMetadataFromContext(parentContext);
77
- for (const [k, v] of Object.entries(propagated)) {
78
- span.setAttribute(k, v);
79
- }
80
- if (isKnownLLMInstrumentor(span)) {
81
- this._openLlmSpans.add(span);
82
- }
83
- this._vercelAiSdkSpanFilter.onStart(span);
84
- debug(
85
- 'span start: name=%s defaultTags=%d propagatedMetadata=%d',
86
- span.name,
87
- Object.keys(this._defaultTags).length,
88
- Object.keys(propagated).length
89
- );
90
- return this._delegate.onStart(span, parentContext);
91
- }
92
-
93
- onEnd(span) {
94
- this._openLlmSpans.delete(span);
95
- try {
96
- const vercelVerdict = this._vercelAiSdkSpanFilter.shouldExport(span);
97
- if (vercelVerdict === true) {
98
- stampVercelGatewayProviderName(span);
99
- }
100
- if (vercelVerdict === false || (vercelVerdict === null && !this._shouldExportSpan(span))) {
101
- debug(
102
- 'span end: filtered out name=%s scope=%s',
103
- span.name,
104
- span.instrumentationScope?.name
105
- );
106
- return;
107
- }
108
- } catch {
109
- return;
110
- }
111
- debug('span end: exporting name=%s scope=%s', span.name, span.instrumentationScope?.name);
112
-
113
- if ((process.env[CONTENT_CAPTURE_ENV] || '').toLowerCase() === 'false') {
114
- for (const key of Object.keys(span.attributes)) {
115
- if (_isContentAttribute(key)) delete span.attributes[key];
116
- }
117
- }
118
-
119
- if (this._mask) {
120
- try {
121
- const masked = this._mask(span.attributes);
122
- if (masked && masked !== span.attributes) {
123
- for (const k of Object.keys(span.attributes)) delete span.attributes[k];
124
- Object.assign(span.attributes, masked);
125
- }
126
- } catch {
127
- for (const k of Object.keys(span.attributes)) delete span.attributes[k];
128
- }
129
- }
130
-
131
- return this._delegate.onEnd(span);
132
- }
133
-
134
- async forceFlush() {
135
- this._endOrphanedLlmSpans();
136
- return this._delegate.forceFlush();
137
- }
138
-
139
- _endOrphanedLlmSpans() {
140
- const orphans = [...this._openLlmSpans];
141
- this._openLlmSpans.clear();
142
- for (const span of orphans) {
143
- try {
144
- if (typeof span.isRecording === 'function' && !span.isRecording()) continue;
145
- span.setStatus({
146
- code: SpanStatusCode.ERROR,
147
- message: 'weflayr: span did not complete before flush',
148
- });
149
- span.end();
150
- debug('forceFlush: ended orphaned LLM span name=%s', span.name);
151
- } catch (err) {
152
- debug('forceFlush: failed to end orphan span: %s', err?.message || err);
153
- }
154
- }
155
- }
156
-
157
- shutdown() {
158
- return this._delegate.shutdown();
159
- }
160
- }
161
-
162
- module.exports = { CONTENT_CAPTURE_ENV, WeflayrSpanProcessor };
@@ -1,79 +0,0 @@
1
- 'use strict';
2
-
3
- // The Vercel AI SDK's OTel integrations emit aggregate spans around each model
4
- // call, all repeating the same usage counts:
5
- // - `@ai-sdk/otel` (ai >= 7, scope "gen_ai"): per-call "chat" spans are
6
- // wrapped in "agent_step" + "invoke_agent" spans, and embed/embedMany
7
- // emits an outer "embeddings" operation span around the model-call
8
- // "embeddings" span(s).
9
- // - the legacy integration (ai <= 6, scope "ai"): `ai.<fn>.do<Call>` spans
10
- // are wrapped in an outer `ai.<fn>` span.
11
- // Exactly one span per model call may reach the exporter — exporting an
12
- // aggregate alongside its children would bill every call twice.
13
-
14
- const VERCEL_SEMCONV_SCOPE = 'gen_ai';
15
- const VERCEL_LEGACY_SCOPE = 'ai';
16
-
17
- const LEGACY_MODEL_CALL_SPAN_NAME = /\.do(Generate|Stream|Embed)$/;
18
-
19
- function _parentSpanId(span) {
20
- return span.parentSpanContext?.spanId ?? span.parentSpanId;
21
- }
22
-
23
- class VercelAiSdkSpanFilter {
24
- constructor() {
25
- // spanId -> gen_ai.operation.name for open "gen_ai"-scope spans, so a
26
- // span can check what its parent is (children end before their parent).
27
- this._openSpanOperations = new Map();
28
- }
29
-
30
- onStart(span) {
31
- if (span.instrumentationScope?.name !== VERCEL_SEMCONV_SCOPE) return;
32
- this._openSpanOperations.set(
33
- span.spanContext().spanId,
34
- span.attributes['gen_ai.operation.name']
35
- );
36
- }
37
-
38
- /**
39
- * Export verdict for a Vercel AI SDK span, or null when the span is not
40
- * one (the caller falls back to the default filter).
41
- */
42
- shouldExport(span) {
43
- const scope = span.instrumentationScope?.name;
44
- if (scope === VERCEL_LEGACY_SCOPE) {
45
- return LEGACY_MODEL_CALL_SPAN_NAME.test(span.name);
46
- }
47
- if (scope !== VERCEL_SEMCONV_SCOPE) {
48
- return null;
49
- }
50
- const operation = span.attributes['gen_ai.operation.name'];
51
- this._openSpanOperations.delete(span.spanContext().spanId);
52
- if (operation === 'chat') {
53
- return true;
54
- }
55
- if (operation === 'embeddings') {
56
- // Keep the outer aggregate (one event per embed/embedMany call, with the
57
- // total usage) and drop the nested model-call span(s) repeating it.
58
- return this._openSpanOperations.get(_parentSpanId(span)) !== 'embeddings';
59
- }
60
- // invoke_agent / agent_step (usage aggregates) and execute_tool (no usage).
61
- return false;
62
- }
63
- }
64
-
65
- // `@ai-sdk/otel` reports the Vercel AI Gateway as the bare provider id
66
- // "gateway" — too generic a name to special-case downstream. Stamp the weflayr
67
- // provider override (which the normalizer prefers) with the canonical name.
68
- // A providerName set through propagateMetadata was stamped at span start and
69
- // wins.
70
- function stampVercelGatewayProviderName(span) {
71
- if (
72
- span.attributes['gen_ai.provider.name'] === 'gateway' &&
73
- span.attributes['weflayr.provider_name'] === undefined
74
- ) {
75
- span.attributes['weflayr.provider_name'] = 'vercel_ai_gateway';
76
- }
77
- }
78
-
79
- module.exports = { VercelAiSdkSpanFilter, stampVercelGatewayProviderName };