openlit 1.11.0 → 1.13.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 (192) hide show
  1. package/README.md +1 -1
  2. package/dist/config.d.ts +12 -4
  3. package/dist/config.js +7 -17
  4. package/dist/config.js.map +1 -1
  5. package/dist/evals/llm/anthropic.js +10 -6
  6. package/dist/evals/llm/anthropic.js.map +1 -1
  7. package/dist/evals/llm/openai.js +9 -5
  8. package/dist/evals/llm/openai.js.map +1 -1
  9. package/dist/features/vault.js +1 -1
  10. package/dist/features/vault.js.map +1 -1
  11. package/dist/helpers.d.ts +93 -1
  12. package/dist/helpers.js +271 -8
  13. package/dist/helpers.js.map +1 -1
  14. package/dist/index.d.ts +6 -5
  15. package/dist/index.js +95 -50
  16. package/dist/index.js.map +1 -1
  17. package/dist/instrumentation/__tests__/anthropic-wrapper.test.js +215 -27
  18. package/dist/instrumentation/__tests__/anthropic-wrapper.test.js.map +1 -1
  19. package/dist/instrumentation/__tests__/base-wrapper.test.js +19 -23
  20. package/dist/instrumentation/__tests__/base-wrapper.test.js.map +1 -1
  21. package/dist/instrumentation/__tests__/bedrock-trace-comparison.test.d.ts +1 -0
  22. package/dist/instrumentation/__tests__/bedrock-trace-comparison.test.js +422 -0
  23. package/dist/instrumentation/__tests__/bedrock-trace-comparison.test.js.map +1 -0
  24. package/dist/instrumentation/__tests__/chroma-trace-comparison.test.js +1 -1
  25. package/dist/instrumentation/__tests__/chroma-trace-comparison.test.js.map +1 -1
  26. package/dist/instrumentation/__tests__/cohere-wrapper.test.js +150 -25
  27. package/dist/instrumentation/__tests__/cohere-wrapper.test.js.map +1 -1
  28. package/dist/instrumentation/__tests__/google-ai-trace-comparison.test.js +152 -33
  29. package/dist/instrumentation/__tests__/google-ai-trace-comparison.test.js.map +1 -1
  30. package/dist/instrumentation/__tests__/groq-trace-comparison.test.js +391 -45
  31. package/dist/instrumentation/__tests__/groq-trace-comparison.test.js.map +1 -1
  32. package/dist/instrumentation/__tests__/huggingface-trace-comparison.test.d.ts +2 -2
  33. package/dist/instrumentation/__tests__/huggingface-trace-comparison.test.js +323 -31
  34. package/dist/instrumentation/__tests__/huggingface-trace-comparison.test.js.map +1 -1
  35. package/dist/instrumentation/__tests__/langchain-wrapper.test.d.ts +1 -0
  36. package/dist/instrumentation/__tests__/langchain-wrapper.test.js +282 -0
  37. package/dist/instrumentation/__tests__/langchain-wrapper.test.js.map +1 -0
  38. package/dist/instrumentation/__tests__/milvus-trace-comparison.test.js +1 -1
  39. package/dist/instrumentation/__tests__/milvus-trace-comparison.test.js.map +1 -1
  40. package/dist/instrumentation/__tests__/mistral-trace-comparison.test.d.ts +0 -3
  41. package/dist/instrumentation/__tests__/mistral-trace-comparison.test.js +275 -68
  42. package/dist/instrumentation/__tests__/mistral-trace-comparison.test.js.map +1 -1
  43. package/dist/instrumentation/__tests__/openai-wrapper.test.js +7 -9
  44. package/dist/instrumentation/__tests__/openai-wrapper.test.js.map +1 -1
  45. package/dist/instrumentation/__tests__/qdrant-trace-comparison.test.js +1 -1
  46. package/dist/instrumentation/__tests__/qdrant-trace-comparison.test.js.map +1 -1
  47. package/dist/instrumentation/__tests__/replicate-trace-comparison.test.d.ts +2 -1
  48. package/dist/instrumentation/__tests__/replicate-trace-comparison.test.js +209 -21
  49. package/dist/instrumentation/__tests__/replicate-trace-comparison.test.js.map +1 -1
  50. package/dist/instrumentation/__tests__/together-trace-comparison.test.js +231 -51
  51. package/dist/instrumentation/__tests__/together-trace-comparison.test.js.map +1 -1
  52. package/dist/instrumentation/__tests__/vercel-ai-trace-comparison.test.d.ts +8 -0
  53. package/dist/instrumentation/__tests__/vercel-ai-trace-comparison.test.js +446 -0
  54. package/dist/instrumentation/__tests__/vercel-ai-trace-comparison.test.js.map +1 -0
  55. package/dist/instrumentation/anthropic/index.d.ts +2 -3
  56. package/dist/instrumentation/anthropic/index.js.map +1 -1
  57. package/dist/instrumentation/anthropic/wrapper.d.ts +1 -3
  58. package/dist/instrumentation/anthropic/wrapper.js +211 -91
  59. package/dist/instrumentation/anthropic/wrapper.js.map +1 -1
  60. package/dist/instrumentation/azure-ai-inference/index.d.ts +11 -0
  61. package/dist/instrumentation/azure-ai-inference/index.js +76 -0
  62. package/dist/instrumentation/azure-ai-inference/index.js.map +1 -0
  63. package/dist/instrumentation/azure-ai-inference/wrapper.d.ts +42 -0
  64. package/dist/instrumentation/azure-ai-inference/wrapper.js +515 -0
  65. package/dist/instrumentation/azure-ai-inference/wrapper.js.map +1 -0
  66. package/dist/instrumentation/base-wrapper.d.ts +2 -1
  67. package/dist/instrumentation/base-wrapper.js +35 -23
  68. package/dist/instrumentation/base-wrapper.js.map +1 -1
  69. package/dist/instrumentation/bedrock/wrapper.d.ts +21 -3
  70. package/dist/instrumentation/bedrock/wrapper.js +318 -265
  71. package/dist/instrumentation/bedrock/wrapper.js.map +1 -1
  72. package/dist/instrumentation/chroma/wrapper.js +1 -1
  73. package/dist/instrumentation/chroma/wrapper.js.map +1 -1
  74. package/dist/instrumentation/claude-agent-sdk/index.d.ts +23 -0
  75. package/dist/instrumentation/claude-agent-sdk/index.js +83 -0
  76. package/dist/instrumentation/claude-agent-sdk/index.js.map +1 -0
  77. package/dist/instrumentation/claude-agent-sdk/wrapper.d.ts +13 -0
  78. package/dist/instrumentation/claude-agent-sdk/wrapper.js +1031 -0
  79. package/dist/instrumentation/claude-agent-sdk/wrapper.js.map +1 -0
  80. package/dist/instrumentation/cohere/index.d.ts +2 -3
  81. package/dist/instrumentation/cohere/index.js.map +1 -1
  82. package/dist/instrumentation/cohere/wrapper.d.ts +1 -1
  83. package/dist/instrumentation/cohere/wrapper.js +215 -56
  84. package/dist/instrumentation/cohere/wrapper.js.map +1 -1
  85. package/dist/instrumentation/cursor-sdk/index.d.ts +21 -0
  86. package/dist/instrumentation/cursor-sdk/index.js +58 -0
  87. package/dist/instrumentation/cursor-sdk/index.js.map +1 -0
  88. package/dist/instrumentation/cursor-sdk/wrapper.d.ts +17 -0
  89. package/dist/instrumentation/cursor-sdk/wrapper.js +689 -0
  90. package/dist/instrumentation/cursor-sdk/wrapper.js.map +1 -0
  91. package/dist/instrumentation/google-adk/index.d.ts +57 -0
  92. package/dist/instrumentation/google-adk/index.js +371 -0
  93. package/dist/instrumentation/google-adk/index.js.map +1 -0
  94. package/dist/instrumentation/google-adk/utils.d.ts +45 -0
  95. package/dist/instrumentation/google-adk/utils.js +663 -0
  96. package/dist/instrumentation/google-adk/utils.js.map +1 -0
  97. package/dist/instrumentation/google-adk/wrapper.d.ts +11 -0
  98. package/dist/instrumentation/google-adk/wrapper.js +391 -0
  99. package/dist/instrumentation/google-adk/wrapper.js.map +1 -0
  100. package/dist/instrumentation/google-ai/wrapper.d.ts +7 -4
  101. package/dist/instrumentation/google-ai/wrapper.js +197 -61
  102. package/dist/instrumentation/google-ai/wrapper.js.map +1 -1
  103. package/dist/instrumentation/groq/wrapper.js +137 -65
  104. package/dist/instrumentation/groq/wrapper.js.map +1 -1
  105. package/dist/instrumentation/huggingface/wrapper.js +241 -39
  106. package/dist/instrumentation/huggingface/wrapper.js.map +1 -1
  107. package/dist/instrumentation/index.d.ts +2 -2
  108. package/dist/instrumentation/index.js +66 -6
  109. package/dist/instrumentation/index.js.map +1 -1
  110. package/dist/instrumentation/langchain/index.d.ts +0 -7
  111. package/dist/instrumentation/langchain/index.js +2 -20
  112. package/dist/instrumentation/langchain/index.js.map +1 -1
  113. package/dist/instrumentation/langchain/wrapper.d.ts +35 -0
  114. package/dist/instrumentation/langchain/wrapper.js +1098 -184
  115. package/dist/instrumentation/langchain/wrapper.js.map +1 -1
  116. package/dist/instrumentation/langgraph/index.d.ts +12 -0
  117. package/dist/instrumentation/langgraph/index.js +99 -0
  118. package/dist/instrumentation/langgraph/index.js.map +1 -0
  119. package/dist/instrumentation/langgraph/wrapper.d.ts +20 -0
  120. package/dist/instrumentation/langgraph/wrapper.js +619 -0
  121. package/dist/instrumentation/langgraph/wrapper.js.map +1 -0
  122. package/dist/instrumentation/llamaindex/index.d.ts +31 -6
  123. package/dist/instrumentation/llamaindex/index.js +180 -61
  124. package/dist/instrumentation/llamaindex/index.js.map +1 -1
  125. package/dist/instrumentation/llamaindex/wrapper.d.ts +15 -3
  126. package/dist/instrumentation/llamaindex/wrapper.js +670 -179
  127. package/dist/instrumentation/llamaindex/wrapper.js.map +1 -1
  128. package/dist/instrumentation/milvus/wrapper.js +1 -1
  129. package/dist/instrumentation/milvus/wrapper.js.map +1 -1
  130. package/dist/instrumentation/mistral/wrapper.js +154 -79
  131. package/dist/instrumentation/mistral/wrapper.js.map +1 -1
  132. package/dist/instrumentation/ollama/index.js +33 -4
  133. package/dist/instrumentation/ollama/index.js.map +1 -1
  134. package/dist/instrumentation/ollama/wrapper.d.ts +28 -2
  135. package/dist/instrumentation/ollama/wrapper.js +432 -48
  136. package/dist/instrumentation/ollama/wrapper.js.map +1 -1
  137. package/dist/instrumentation/openai/index.d.ts +2 -3
  138. package/dist/instrumentation/openai/index.js.map +1 -1
  139. package/dist/instrumentation/openai/wrapper.js +293 -194
  140. package/dist/instrumentation/openai/wrapper.js.map +1 -1
  141. package/dist/instrumentation/openai-agents/index.d.ts +20 -0
  142. package/dist/instrumentation/openai-agents/index.js +174 -0
  143. package/dist/instrumentation/openai-agents/index.js.map +1 -0
  144. package/dist/instrumentation/openai-agents/processor.d.ts +35 -0
  145. package/dist/instrumentation/openai-agents/processor.js +249 -0
  146. package/dist/instrumentation/openai-agents/processor.js.map +1 -0
  147. package/dist/instrumentation/openai-agents/utils.d.ts +20 -0
  148. package/dist/instrumentation/openai-agents/utils.js +624 -0
  149. package/dist/instrumentation/openai-agents/utils.js.map +1 -0
  150. package/dist/instrumentation/pinecone/wrapper.js +2 -2
  151. package/dist/instrumentation/pinecone/wrapper.js.map +1 -1
  152. package/dist/instrumentation/qdrant/wrapper.js +1 -1
  153. package/dist/instrumentation/qdrant/wrapper.js.map +1 -1
  154. package/dist/instrumentation/replicate/wrapper.js +103 -21
  155. package/dist/instrumentation/replicate/wrapper.js.map +1 -1
  156. package/dist/instrumentation/strands/index.d.ts +21 -0
  157. package/dist/instrumentation/strands/index.js +83 -0
  158. package/dist/instrumentation/strands/index.js.map +1 -0
  159. package/dist/instrumentation/strands/processor.d.ts +45 -0
  160. package/dist/instrumentation/strands/processor.js +545 -0
  161. package/dist/instrumentation/strands/processor.js.map +1 -0
  162. package/dist/instrumentation/strands/utils.d.ts +24 -0
  163. package/dist/instrumentation/strands/utils.js +360 -0
  164. package/dist/instrumentation/strands/utils.js.map +1 -0
  165. package/dist/instrumentation/together/wrapper.js +125 -51
  166. package/dist/instrumentation/together/wrapper.js.map +1 -1
  167. package/dist/instrumentation/vercel-ai/wrapper.d.ts +28 -2
  168. package/dist/instrumentation/vercel-ai/wrapper.js +314 -164
  169. package/dist/instrumentation/vercel-ai/wrapper.js.map +1 -1
  170. package/dist/llm/anthropic.js +10 -6
  171. package/dist/llm/anthropic.js.map +1 -1
  172. package/dist/llm/openai.js +9 -5
  173. package/dist/llm/openai.js.map +1 -1
  174. package/dist/otel/__tests__/metrics.test.js +16 -27
  175. package/dist/otel/__tests__/metrics.test.js.map +1 -1
  176. package/dist/otel/events.d.ts +11 -0
  177. package/dist/otel/events.js +74 -0
  178. package/dist/otel/events.js.map +1 -0
  179. package/dist/otel/metrics.d.ts +5 -6
  180. package/dist/otel/metrics.js +66 -48
  181. package/dist/otel/metrics.js.map +1 -1
  182. package/dist/otel/tracing.d.ts +6 -2
  183. package/dist/otel/tracing.js +71 -24
  184. package/dist/otel/tracing.js.map +1 -1
  185. package/dist/otel/utils.d.ts +11 -0
  186. package/dist/otel/utils.js +34 -0
  187. package/dist/otel/utils.js.map +1 -0
  188. package/dist/semantic-convention.d.ts +49 -5
  189. package/dist/semantic-convention.js +56 -8
  190. package/dist/semantic-convention.js.map +1 -1
  191. package/dist/types.d.ts +58 -22
  192. package/package.json +41 -9
@@ -1,252 +1,743 @@
1
1
  "use strict";
2
+ /**
3
+ * OpenLIT LlamaIndex Wrapper
4
+ *
5
+ * Mirrors Python SDK: sdk/python/src/openlit/instrumentation/llamaindex/
6
+ * Uses the same OPERATION_MAP and span semantics as the Python implementation.
7
+ *
8
+ * LLM operations get full provider-style telemetry (attributes, events, metrics).
9
+ * Framework operations (query engine, retriever, index, etc.) get framework-level spans.
10
+ */
11
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
12
+ if (k2 === undefined) k2 = k;
13
+ var desc = Object.getOwnPropertyDescriptor(m, k);
14
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
15
+ desc = { enumerable: true, get: function() { return m[k]; } };
16
+ }
17
+ Object.defineProperty(o, k2, desc);
18
+ }) : (function(o, m, k, k2) {
19
+ if (k2 === undefined) k2 = k;
20
+ o[k2] = m[k];
21
+ }));
22
+ var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
23
+ Object.defineProperty(o, "default", { enumerable: true, value: v });
24
+ }) : function(o, v) {
25
+ o["default"] = v;
26
+ });
27
+ var __importStar = (this && this.__importStar) || (function () {
28
+ var ownKeys = function(o) {
29
+ ownKeys = Object.getOwnPropertyNames || function (o) {
30
+ var ar = [];
31
+ for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
32
+ return ar;
33
+ };
34
+ return ownKeys(o);
35
+ };
36
+ return function (mod) {
37
+ if (mod && mod.__esModule) return mod;
38
+ var result = {};
39
+ if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
40
+ __setModuleDefault(result, mod);
41
+ return result;
42
+ };
43
+ })();
2
44
  var __importDefault = (this && this.__importDefault) || function (mod) {
3
45
  return (mod && mod.__esModule) ? mod : { "default": mod };
4
46
  };
5
47
  Object.defineProperty(exports, "__esModule", { value: true });
6
48
  const api_1 = require("@opentelemetry/api");
7
49
  const config_1 = __importDefault(require("../../config"));
8
- const helpers_1 = __importDefault(require("../../helpers"));
50
+ const helpers_1 = __importStar(require("../../helpers"));
9
51
  const semantic_convention_1 = __importDefault(require("../../semantic-convention"));
10
52
  const base_wrapper_1 = __importDefault(require("../base-wrapper"));
11
- class LlamaIndexWrapper extends base_wrapper_1.default {
12
- // ---- Helpers ---------------------------------------------------------------
53
+ /**
54
+ * Operation mapping matching Python SDK's OPERATION_MAP in
55
+ * sdk/python/src/openlit/instrumentation/llamaindex/utils.py
56
+ */
57
+ const OPERATION_MAP = {
58
+ // Document Loading & Processing
59
+ document_load: semantic_convention_1.default.GEN_AI_OPERATION_TYPE_RETRIEVE,
60
+ document_transform: semantic_convention_1.default.GEN_AI_OPERATION_TYPE_FRAMEWORK,
61
+ document_split: semantic_convention_1.default.GEN_AI_OPERATION_TYPE_FRAMEWORK,
62
+ // Index Construction & Management
63
+ index_construct: semantic_convention_1.default.GEN_AI_OPERATION_TYPE_FRAMEWORK,
64
+ index_insert: semantic_convention_1.default.GEN_AI_OPERATION_TYPE_FRAMEWORK,
65
+ index_delete: semantic_convention_1.default.GEN_AI_OPERATION_TYPE_FRAMEWORK,
66
+ index_build: semantic_convention_1.default.GEN_AI_OPERATION_TYPE_FRAMEWORK,
67
+ // Query Engine Operations
68
+ query_engine_create: semantic_convention_1.default.GEN_AI_OPERATION_TYPE_FRAMEWORK,
69
+ query_engine_query: semantic_convention_1.default.GEN_AI_OPERATION_TYPE_RETRIEVE,
70
+ // Retriever Operations
71
+ retriever_create: semantic_convention_1.default.GEN_AI_OPERATION_TYPE_FRAMEWORK,
72
+ retriever_retrieve: semantic_convention_1.default.GEN_AI_OPERATION_TYPE_RETRIEVE,
73
+ // LLM Operations
74
+ llm_chat: semantic_convention_1.default.GEN_AI_OPERATION_TYPE_CHAT,
75
+ llm_complete: semantic_convention_1.default.GEN_AI_OPERATION_TYPE_CHAT,
76
+ // Embedding Operations
77
+ embedding_generate: semantic_convention_1.default.GEN_AI_OPERATION_TYPE_EMBEDDING,
78
+ // Response Synthesis
79
+ response_synthesize: semantic_convention_1.default.GEN_AI_OPERATION_TYPE_CHAT,
80
+ // Text Processing Components
81
+ text_splitter_split: semantic_convention_1.default.GEN_AI_OPERATION_TYPE_FRAMEWORK,
82
+ node_parser_parse: semantic_convention_1.default.GEN_AI_OPERATION_TYPE_FRAMEWORK,
83
+ // Vector Store Components
84
+ vector_store_add: semantic_convention_1.default.GEN_AI_OPERATION_TYPE_FRAMEWORK,
85
+ vector_store_delete: semantic_convention_1.default.GEN_AI_OPERATION_TYPE_FRAMEWORK,
86
+ vector_store_query: semantic_convention_1.default.GEN_AI_OPERATION_TYPE_RETRIEVE,
87
+ // Postprocessor
88
+ postprocessor_process: semantic_convention_1.default.GEN_AI_OPERATION_TYPE_FRAMEWORK,
89
+ };
90
+ class LlamaIndexWrapper {
91
+ // ---------------------------------------------------------------------------
92
+ // Helpers (mirrors Python set_server_address_and_port / model extraction)
93
+ // ---------------------------------------------------------------------------
94
+ static _extractModel(instance) {
95
+ return instance?.model
96
+ || instance?.modelName
97
+ || instance?.metadata?.model
98
+ || instance?.llm?.model
99
+ || instance?._llm?.model
100
+ || instance?._responseSynthesizer?.llm?.model
101
+ || instance?._responseSynthesizer?._llm?.model
102
+ || 'unknown';
103
+ }
13
104
  static _extractServerInfo(instance) {
14
- const baseUrl = instance?.session?.openai?.baseURL ||
15
- instance?._client?.baseURL ||
16
- instance?.clientOptions?.baseURL ||
17
- instance?.llm?.session?.openai?.baseURL ||
18
- instance?._llm?.session?.openai?.baseURL ||
19
- '';
20
- if (baseUrl) {
21
- try {
22
- const url = new URL(baseUrl);
23
- const port = url.port ? parseInt(url.port) : (url.protocol === 'https:' ? 443 : 80);
24
- return { address: url.hostname, port };
105
+ const candidates = [
106
+ instance?._client?.baseURL,
107
+ instance?.session?.openai?.baseURL,
108
+ instance?.clientOptions?.baseURL,
109
+ instance?.llm?._client?.baseURL,
110
+ instance?._llm?._client?.baseURL,
111
+ instance?.llm?.session?.openai?.baseURL,
112
+ instance?._llm?.session?.openai?.baseURL,
113
+ ];
114
+ for (const rawUrl of candidates) {
115
+ if (rawUrl) {
116
+ try {
117
+ const parsed = new URL(rawUrl);
118
+ return {
119
+ address: parsed.hostname,
120
+ port: parsed.port
121
+ ? parseInt(parsed.port, 10)
122
+ : (parsed.protocol === 'https:' ? 443 : 80),
123
+ };
124
+ }
125
+ catch { /* try next */ }
25
126
  }
26
- catch { /* ignore */ }
27
127
  }
28
- return { address: 'api.openai.com', port: 443 };
128
+ return { address: 'localhost', port: 8000 };
29
129
  }
30
- // ---- LLM patches -----------------------------------------------------------
130
+ // ---------------------------------------------------------------------------
131
+ // LLM chat patch — full provider-style telemetry + frameworkLlmActive
132
+ // Mirrors Python: LLM.chat -> operation_type "chat"
133
+ // ---------------------------------------------------------------------------
31
134
  static _patchLLMChat(tracer) {
32
- const genAIEndpoint = 'llamaindex.llm.chat';
135
+ const endpoint = 'llm_chat';
136
+ const operationType = OPERATION_MAP[endpoint];
33
137
  return (originalMethod) => {
34
- return async function (...args) {
35
- const span = tracer.startSpan(genAIEndpoint, { kind: api_1.SpanKind.CLIENT });
36
- return api_1.context.with(api_1.trace.setSpan(api_1.context.active(), span), async () => {
37
- let metricParams;
138
+ return function (...args) {
139
+ const requestModel = LlamaIndexWrapper._extractModel(this);
140
+ const { address, port } = LlamaIndexWrapper._extractServerInfo(this);
141
+ const spanName = `${operationType} ${requestModel}`;
142
+ const span = tracer.startSpan(spanName, {
143
+ kind: api_1.SpanKind.CLIENT,
144
+ attributes: {
145
+ [semantic_convention_1.default.GEN_AI_OPERATION]: operationType,
146
+ [semantic_convention_1.default.GEN_AI_PROVIDER_NAME_OTEL]: LlamaIndexWrapper.aiSystem,
147
+ [semantic_convention_1.default.GEN_AI_REQUEST_MODEL]: requestModel,
148
+ [semantic_convention_1.default.SERVER_ADDRESS]: address,
149
+ [semantic_convention_1.default.SERVER_PORT]: port,
150
+ },
151
+ });
152
+ return api_1.context.with(api_1.trace.setSpan(api_1.context.active(), span), () => {
38
153
  const startTime = Date.now();
39
- try {
40
- const response = await originalMethod.apply(this, args);
41
- const duration = (Date.now() - startTime) / 1000;
42
- const params = args[0] || {};
43
- const messages = params.messages || [];
44
- const modelId = this.model || this.modelName || this.metadata?.model || 'unknown';
45
- const aiSystem = LlamaIndexWrapper.aiSystem;
46
- const rawUsage = response?.raw?.usage || response?.usage || {};
47
- const promptTokens = rawUsage.prompt_tokens || rawUsage.input_tokens || 0;
48
- const completionTokens = rawUsage.completion_tokens || rawUsage.output_tokens || 0;
49
- const totalTokens = rawUsage.total_tokens || promptTokens + completionTokens;
50
- const finishReason = response?.raw?.choices?.[0]?.finish_reason || 'stop';
51
- const pricingInfo = await config_1.default.updatePricingJson(config_1.default.pricing_json);
52
- const cost = helpers_1.default.getChatModelCost(modelId, pricingInfo, promptTokens, completionTokens);
53
- const { address, port } = LlamaIndexWrapper._extractServerInfo(this);
54
- LlamaIndexWrapper.setBaseSpanAttributes(span, { genAIEndpoint, model: modelId, cost, aiSystem, serverAddress: address, serverPort: port });
55
- span.setAttribute(semantic_convention_1.default.GEN_AI_OPERATION, semantic_convention_1.default.GEN_AI_OPERATION_TYPE_CHAT);
56
- span.setAttribute(semantic_convention_1.default.GEN_AI_REQUEST_IS_STREAM, false);
57
- span.setAttribute(semantic_convention_1.default.GEN_AI_RESPONSE_MODEL, modelId);
58
- span.setAttribute(semantic_convention_1.default.GEN_AI_USAGE_INPUT_TOKENS, promptTokens);
59
- span.setAttribute(semantic_convention_1.default.GEN_AI_USAGE_OUTPUT_TOKENS, completionTokens);
60
- span.setAttribute(semantic_convention_1.default.GEN_AI_USAGE_TOTAL_TOKENS, totalTokens);
61
- span.setAttribute(semantic_convention_1.default.GEN_AI_CLIENT_TOKEN_USAGE, totalTokens);
62
- span.setAttribute(semantic_convention_1.default.GEN_AI_RESPONSE_FINISH_REASON, [finishReason]);
63
- span.setAttribute(semantic_convention_1.default.GEN_AI_CLIENT_OPERATION_DURATION, duration);
64
- span.setAttribute(semantic_convention_1.default.SERVER_ADDRESS, address);
65
- span.setAttribute(semantic_convention_1.default.SERVER_PORT, port);
66
- if (config_1.default.traceContent) {
67
- const formattedMessages = messages.map((m) => ({
68
- role: m.role || 'user',
69
- content: typeof m.content === 'string' ? m.content : JSON.stringify(m.content),
70
- }));
71
- span.setAttribute(semantic_convention_1.default.GEN_AI_INPUT_MESSAGES, helpers_1.default.buildInputMessages(formattedMessages));
72
- const outputContent = response?.message?.content || response?.text || '';
73
- span.setAttribute(semantic_convention_1.default.GEN_AI_OUTPUT_MESSAGES, helpers_1.default.buildOutputMessages(outputContent, finishReason));
154
+ const onSuccess = (response) => {
155
+ try {
156
+ LlamaIndexWrapper._processLLMResponse(span, response, requestModel, address, port, startTime, args, 'chat');
74
157
  }
75
- metricParams = { genAIEndpoint, model: modelId, cost, aiSystem };
158
+ catch { /* swallow telemetry errors */ }
76
159
  return response;
77
- }
78
- catch (e) {
160
+ };
161
+ const onError = (e) => {
79
162
  helpers_1.default.handleException(span, e);
163
+ base_wrapper_1.default.recordMetrics(span, {
164
+ genAIEndpoint: endpoint,
165
+ model: requestModel,
166
+ aiSystem: LlamaIndexWrapper.aiSystem,
167
+ serverAddress: address,
168
+ serverPort: port,
169
+ errorType: e?.constructor?.name || '_OTHER',
170
+ });
171
+ span.end();
80
172
  throw e;
173
+ };
174
+ try {
175
+ const result = (0, helpers_1.runWithFrameworkLlm)(() => originalMethod.apply(this, args));
176
+ if (result && typeof result.then === 'function') {
177
+ return result.then(onSuccess).catch(onError);
178
+ }
179
+ return onSuccess(result);
81
180
  }
82
- finally {
83
- span.end();
84
- if (metricParams)
85
- base_wrapper_1.default.recordMetrics(span, metricParams);
181
+ catch (e) {
182
+ return onError(e);
86
183
  }
87
184
  });
88
185
  };
89
186
  };
90
187
  }
188
+ // ---------------------------------------------------------------------------
189
+ // LLM complete patch — full provider-style telemetry + frameworkLlmActive
190
+ // Mirrors Python: LLM.complete -> operation_type "chat"
191
+ // ---------------------------------------------------------------------------
91
192
  static _patchLLMComplete(tracer) {
92
- const genAIEndpoint = 'llamaindex.llm.complete';
193
+ const endpoint = 'llm_complete';
194
+ const operationType = OPERATION_MAP[endpoint];
93
195
  return (originalMethod) => {
94
- return async function (...args) {
95
- const span = tracer.startSpan(genAIEndpoint, { kind: api_1.SpanKind.CLIENT });
96
- return api_1.context.with(api_1.trace.setSpan(api_1.context.active(), span), async () => {
97
- let metricParams;
196
+ return function (...args) {
197
+ const requestModel = LlamaIndexWrapper._extractModel(this);
198
+ const { address, port } = LlamaIndexWrapper._extractServerInfo(this);
199
+ const spanName = `${operationType} ${requestModel}`;
200
+ const span = tracer.startSpan(spanName, {
201
+ kind: api_1.SpanKind.CLIENT,
202
+ attributes: {
203
+ [semantic_convention_1.default.GEN_AI_OPERATION]: operationType,
204
+ [semantic_convention_1.default.GEN_AI_PROVIDER_NAME_OTEL]: LlamaIndexWrapper.aiSystem,
205
+ [semantic_convention_1.default.GEN_AI_REQUEST_MODEL]: requestModel,
206
+ [semantic_convention_1.default.SERVER_ADDRESS]: address,
207
+ [semantic_convention_1.default.SERVER_PORT]: port,
208
+ },
209
+ });
210
+ return api_1.context.with(api_1.trace.setSpan(api_1.context.active(), span), () => {
98
211
  const startTime = Date.now();
99
- try {
100
- const response = await originalMethod.apply(this, args);
101
- const duration = (Date.now() - startTime) / 1000;
102
- const prompt = typeof args[0] === 'string' ? args[0] : args[0]?.prompt || '';
103
- const modelId = this.model || this.modelName || this.metadata?.model || 'unknown';
104
- const aiSystem = LlamaIndexWrapper.aiSystem;
105
- const rawUsage = response?.raw?.usage || response?.usage || {};
106
- const promptTokens = rawUsage.prompt_tokens || rawUsage.input_tokens || 0;
107
- const completionTokens = rawUsage.completion_tokens || rawUsage.output_tokens || 0;
108
- const totalTokens = rawUsage.total_tokens || promptTokens + completionTokens;
109
- const finishReason = response?.raw?.choices?.[0]?.finish_reason || 'stop';
110
- const pricingInfo = await config_1.default.updatePricingJson(config_1.default.pricing_json);
111
- const cost = helpers_1.default.getChatModelCost(modelId, pricingInfo, promptTokens, completionTokens);
112
- const { address, port } = LlamaIndexWrapper._extractServerInfo(this);
113
- LlamaIndexWrapper.setBaseSpanAttributes(span, { genAIEndpoint, model: modelId, cost, aiSystem, serverAddress: address, serverPort: port });
114
- span.setAttribute(semantic_convention_1.default.GEN_AI_OPERATION, semantic_convention_1.default.GEN_AI_OPERATION_TYPE_CHAT);
115
- span.setAttribute(semantic_convention_1.default.GEN_AI_REQUEST_IS_STREAM, false);
116
- span.setAttribute(semantic_convention_1.default.GEN_AI_RESPONSE_MODEL, modelId);
117
- span.setAttribute(semantic_convention_1.default.GEN_AI_USAGE_INPUT_TOKENS, promptTokens);
118
- span.setAttribute(semantic_convention_1.default.GEN_AI_USAGE_OUTPUT_TOKENS, completionTokens);
119
- span.setAttribute(semantic_convention_1.default.GEN_AI_USAGE_TOTAL_TOKENS, totalTokens);
120
- span.setAttribute(semantic_convention_1.default.GEN_AI_CLIENT_TOKEN_USAGE, totalTokens);
121
- span.setAttribute(semantic_convention_1.default.GEN_AI_RESPONSE_FINISH_REASON, [finishReason]);
122
- span.setAttribute(semantic_convention_1.default.GEN_AI_CLIENT_OPERATION_DURATION, duration);
123
- span.setAttribute(semantic_convention_1.default.SERVER_ADDRESS, address);
124
- span.setAttribute(semantic_convention_1.default.SERVER_PORT, port);
125
- if (config_1.default.traceContent) {
126
- span.setAttribute(semantic_convention_1.default.GEN_AI_INPUT_MESSAGES, helpers_1.default.buildInputMessages([{ role: 'user', content: prompt }]));
127
- const outputContent = response?.text || '';
128
- span.setAttribute(semantic_convention_1.default.GEN_AI_OUTPUT_MESSAGES, helpers_1.default.buildOutputMessages(outputContent, finishReason));
212
+ const onSuccess = (response) => {
213
+ try {
214
+ LlamaIndexWrapper._processLLMResponse(span, response, requestModel, address, port, startTime, args, 'complete');
129
215
  }
130
- metricParams = { genAIEndpoint, model: modelId, cost, aiSystem };
216
+ catch { /* swallow */ }
131
217
  return response;
132
- }
133
- catch (e) {
218
+ };
219
+ const onError = (e) => {
134
220
  helpers_1.default.handleException(span, e);
221
+ base_wrapper_1.default.recordMetrics(span, {
222
+ genAIEndpoint: endpoint,
223
+ model: requestModel,
224
+ aiSystem: LlamaIndexWrapper.aiSystem,
225
+ serverAddress: address,
226
+ serverPort: port,
227
+ errorType: e?.constructor?.name || '_OTHER',
228
+ });
229
+ span.end();
135
230
  throw e;
231
+ };
232
+ try {
233
+ const result = (0, helpers_1.runWithFrameworkLlm)(() => originalMethod.apply(this, args));
234
+ if (result && typeof result.then === 'function') {
235
+ return result.then(onSuccess).catch(onError);
236
+ }
237
+ return onSuccess(result);
136
238
  }
137
- finally {
138
- span.end();
139
- if (metricParams)
140
- base_wrapper_1.default.recordMetrics(span, metricParams);
239
+ catch (e) {
240
+ return onError(e);
141
241
  }
142
242
  });
143
243
  };
144
244
  };
145
245
  }
146
- // ---- Query engine patch ----------------------------------------------------
246
+ // ---------------------------------------------------------------------------
247
+ // Shared LLM response processor — attributes, events, metrics
248
+ // ---------------------------------------------------------------------------
249
+ static _processLLMResponse(span, response, requestModel, serverAddress, serverPort, startTime, args, mode) {
250
+ const endpoint = mode === 'chat' ? 'llm_chat' : 'llm_complete';
251
+ const duration = (Date.now() - startTime) / 1000;
252
+ const rawUsage = response?.raw?.usage || response?.usage || {};
253
+ const inputTokens = rawUsage.prompt_tokens || rawUsage.input_tokens || 0;
254
+ const outputTokens = rawUsage.completion_tokens || rawUsage.output_tokens || 0;
255
+ const finishReason = response?.raw?.choices?.[0]?.finish_reason || 'stop';
256
+ const responseModel = response?.raw?.model || requestModel;
257
+ const responseId = response?.raw?.id || '';
258
+ const pricingInfo = config_1.default.pricingInfo || {};
259
+ const cost = helpers_1.default.getChatModelCost(requestModel, pricingInfo, inputTokens, outputTokens);
260
+ base_wrapper_1.default.setBaseSpanAttributes(span, {
261
+ genAIEndpoint: endpoint,
262
+ model: requestModel,
263
+ cost,
264
+ aiSystem: LlamaIndexWrapper.aiSystem,
265
+ serverAddress,
266
+ serverPort,
267
+ });
268
+ span.setAttribute(semantic_convention_1.default.GEN_AI_REQUEST_IS_STREAM, false);
269
+ if (responseModel) {
270
+ span.setAttribute(semantic_convention_1.default.GEN_AI_RESPONSE_MODEL, responseModel);
271
+ }
272
+ if (responseId) {
273
+ span.setAttribute(semantic_convention_1.default.GEN_AI_RESPONSE_ID, responseId);
274
+ }
275
+ span.setAttribute(semantic_convention_1.default.GEN_AI_RESPONSE_FINISH_REASON, [finishReason]);
276
+ if (inputTokens) {
277
+ span.setAttribute(semantic_convention_1.default.GEN_AI_USAGE_INPUT_TOKENS, inputTokens);
278
+ }
279
+ if (outputTokens) {
280
+ span.setAttribute(semantic_convention_1.default.GEN_AI_USAGE_OUTPUT_TOKENS, outputTokens);
281
+ }
282
+ span.setAttribute(semantic_convention_1.default.GEN_AI_CLIENT_OPERATION_DURATION, duration);
283
+ let inputMessagesJson = '';
284
+ let outputMessagesJson = '';
285
+ if (config_1.default.captureMessageContent) {
286
+ if (mode === 'chat') {
287
+ const messages = args[0]?.messages || (Array.isArray(args[0]) ? args[0] : []);
288
+ const formatted = (Array.isArray(messages) ? messages : [messages]).map((m) => ({
289
+ role: m.role || 'user',
290
+ content: typeof m.content === 'string' ? m.content : JSON.stringify(m.content || ''),
291
+ }));
292
+ inputMessagesJson = helpers_1.default.buildInputMessages(formatted);
293
+ const text = response?.message?.content || response?.text || '';
294
+ outputMessagesJson = helpers_1.default.buildOutputMessages(text, finishReason);
295
+ }
296
+ else {
297
+ const prompt = typeof args[0] === 'string' ? args[0] : args[0]?.prompt || '';
298
+ inputMessagesJson = helpers_1.default.buildInputMessages([{ role: 'user', content: prompt }]);
299
+ const text = response?.text || '';
300
+ outputMessagesJson = helpers_1.default.buildOutputMessages(text, finishReason);
301
+ }
302
+ span.setAttribute(semantic_convention_1.default.GEN_AI_INPUT_MESSAGES, inputMessagesJson);
303
+ span.setAttribute(semantic_convention_1.default.GEN_AI_OUTPUT_MESSAGES, outputMessagesJson);
304
+ }
305
+ const eventAttrs = {
306
+ [semantic_convention_1.default.GEN_AI_OPERATION]: semantic_convention_1.default.GEN_AI_OPERATION_TYPE_CHAT,
307
+ [semantic_convention_1.default.GEN_AI_REQUEST_MODEL]: requestModel,
308
+ [semantic_convention_1.default.GEN_AI_RESPONSE_MODEL]: responseModel,
309
+ [semantic_convention_1.default.SERVER_ADDRESS]: serverAddress,
310
+ [semantic_convention_1.default.SERVER_PORT]: serverPort,
311
+ [semantic_convention_1.default.GEN_AI_RESPONSE_ID]: responseId,
312
+ [semantic_convention_1.default.GEN_AI_RESPONSE_FINISH_REASON]: [finishReason],
313
+ [semantic_convention_1.default.GEN_AI_OUTPUT_TYPE]: semantic_convention_1.default.GEN_AI_OUTPUT_TYPE_TEXT,
314
+ [semantic_convention_1.default.GEN_AI_USAGE_INPUT_TOKENS]: inputTokens,
315
+ [semantic_convention_1.default.GEN_AI_USAGE_OUTPUT_TOKENS]: outputTokens,
316
+ };
317
+ if (config_1.default.captureMessageContent) {
318
+ eventAttrs[semantic_convention_1.default.GEN_AI_INPUT_MESSAGES] = inputMessagesJson;
319
+ eventAttrs[semantic_convention_1.default.GEN_AI_OUTPUT_MESSAGES] = outputMessagesJson;
320
+ }
321
+ helpers_1.default.emitInferenceEvent(span, eventAttrs);
322
+ base_wrapper_1.default.recordMetrics(span, {
323
+ genAIEndpoint: endpoint,
324
+ model: requestModel,
325
+ cost,
326
+ aiSystem: LlamaIndexWrapper.aiSystem,
327
+ serverAddress,
328
+ serverPort,
329
+ });
330
+ span.end();
331
+ }
332
+ // ---------------------------------------------------------------------------
333
+ // Query engine query patch — retrieval span with source nodes
334
+ // Mirrors Python: RetrieverQueryEngine.query -> operation_type "retrieval"
335
+ // ---------------------------------------------------------------------------
147
336
  static _patchQueryEngineQuery(tracer) {
148
- const genAIEndpoint = 'llamaindex.query_engine.query';
337
+ const endpoint = 'query_engine_query';
338
+ const operationType = OPERATION_MAP[endpoint];
149
339
  return (originalMethod) => {
150
- return async function (...args) {
151
- const span = tracer.startSpan(genAIEndpoint, { kind: api_1.SpanKind.CLIENT });
152
- return api_1.context.with(api_1.trace.setSpan(api_1.context.active(), span), async () => {
153
- let metricParams;
340
+ return function (...args) {
341
+ const requestModel = LlamaIndexWrapper._extractModel(this);
342
+ const { address, port } = LlamaIndexWrapper._extractServerInfo(this?.llm || this?._llm || this);
343
+ const spanName = `${operationType} ${endpoint}`;
344
+ const span = tracer.startSpan(spanName, {
345
+ kind: api_1.SpanKind.CLIENT,
346
+ attributes: {
347
+ [semantic_convention_1.default.GEN_AI_OPERATION]: operationType,
348
+ [semantic_convention_1.default.GEN_AI_PROVIDER_NAME_OTEL]: LlamaIndexWrapper.aiSystem,
349
+ },
350
+ });
351
+ return api_1.context.with(api_1.trace.setSpan(api_1.context.active(), span), () => {
154
352
  const startTime = Date.now();
353
+ const onSuccess = (response) => {
354
+ try {
355
+ const duration = (Date.now() - startTime) / 1000;
356
+ base_wrapper_1.default.setBaseSpanAttributes(span, {
357
+ genAIEndpoint: endpoint,
358
+ model: requestModel,
359
+ aiSystem: LlamaIndexWrapper.aiSystem,
360
+ serverAddress: address,
361
+ serverPort: port,
362
+ });
363
+ span.setAttribute(semantic_convention_1.default.GEN_AI_CLIENT_OPERATION_DURATION, duration);
364
+ const sourceNodes = response?.sourceNodes || response?.source_nodes || [];
365
+ if (sourceNodes.length > 0) {
366
+ span.setAttribute(semantic_convention_1.default.GEN_AI_RETRIEVAL_SOURCE, JSON.stringify(sourceNodes.slice(0, 5).map((n) => ({
367
+ id: n.node?.id_ || n.id_ || '',
368
+ score: n.score,
369
+ text: n.node?.text?.slice(0, 200) || '',
370
+ }))));
371
+ }
372
+ if (config_1.default.captureMessageContent) {
373
+ const queryStr = typeof args[0] === 'string'
374
+ ? args[0]
375
+ : args[0]?.query || args[0]?.queryStr || '';
376
+ span.setAttribute(semantic_convention_1.default.GEN_AI_INPUT_MESSAGES, helpers_1.default.buildInputMessages([{ role: 'user', content: queryStr }]));
377
+ const responseText = typeof response?.response === 'string'
378
+ ? response.response
379
+ : response?.message?.content || response?.toString?.() || '';
380
+ span.setAttribute(semantic_convention_1.default.GEN_AI_OUTPUT_MESSAGES, helpers_1.default.buildOutputMessages(responseText, 'stop'));
381
+ }
382
+ base_wrapper_1.default.recordMetrics(span, {
383
+ genAIEndpoint: endpoint,
384
+ model: requestModel,
385
+ aiSystem: LlamaIndexWrapper.aiSystem,
386
+ serverAddress: address,
387
+ serverPort: port,
388
+ });
389
+ }
390
+ catch { /* swallow */ }
391
+ span.end();
392
+ return response;
393
+ };
394
+ const onError = (e) => {
395
+ helpers_1.default.handleException(span, e);
396
+ base_wrapper_1.default.recordMetrics(span, {
397
+ genAIEndpoint: endpoint,
398
+ model: requestModel,
399
+ aiSystem: LlamaIndexWrapper.aiSystem,
400
+ serverAddress: address,
401
+ serverPort: port,
402
+ errorType: e?.constructor?.name || '_OTHER',
403
+ });
404
+ span.end();
405
+ throw e;
406
+ };
155
407
  try {
156
- const response = await originalMethod.apply(this, args);
157
- const duration = (Date.now() - startTime) / 1000;
158
- const queryStr = typeof args[0] === 'string' ? args[0] : args[0]?.query || '';
159
- const llm = this.llm || this._llm;
160
- const modelId = llm?.model || llm?.modelName || llm?.metadata?.model || 'unknown';
161
- const aiSystem = LlamaIndexWrapper.aiSystem;
162
- const { address, port } = LlamaIndexWrapper._extractServerInfo(llm || this);
163
- LlamaIndexWrapper.setBaseSpanAttributes(span, { genAIEndpoint, model: modelId, aiSystem, serverAddress: address, serverPort: port });
164
- span.setAttribute(semantic_convention_1.default.GEN_AI_OPERATION, semantic_convention_1.default.GEN_AI_OPERATION_TYPE_FRAMEWORK);
165
- span.setAttribute(semantic_convention_1.default.GEN_AI_REQUEST_IS_STREAM, false);
166
- span.setAttribute(semantic_convention_1.default.GEN_AI_CLIENT_OPERATION_DURATION, duration);
167
- span.setAttribute(semantic_convention_1.default.SERVER_ADDRESS, address);
168
- span.setAttribute(semantic_convention_1.default.SERVER_PORT, port);
169
- const sourceNodes = response.sourceNodes || response.source_nodes || [];
170
- if (sourceNodes.length > 0) {
171
- span.setAttribute(semantic_convention_1.default.GEN_AI_RETRIEVAL_SOURCE, JSON.stringify(sourceNodes.slice(0, 5).map((n) => ({
172
- id: n.node?.id_ || n.id_ || '',
173
- score: n.score,
174
- text: n.node?.text?.slice(0, 200) || '',
175
- }))));
408
+ const result = originalMethod.apply(this, args);
409
+ if (result && typeof result.then === 'function') {
410
+ return result.then(onSuccess).catch(onError);
176
411
  }
177
- if (config_1.default.traceContent) {
178
- span.setAttribute(semantic_convention_1.default.GEN_AI_INPUT_MESSAGES, helpers_1.default.buildInputMessages([{ role: 'user', content: queryStr }]));
179
- const responseText = typeof response.response === 'string'
180
- ? response.response
181
- : response.toString?.() || '';
182
- span.setAttribute(semantic_convention_1.default.GEN_AI_OUTPUT_MESSAGES, helpers_1.default.buildOutputMessages(responseText, 'stop'));
412
+ return onSuccess(result);
413
+ }
414
+ catch (e) {
415
+ return onError(e);
416
+ }
417
+ });
418
+ };
419
+ };
420
+ }
421
+ // ---------------------------------------------------------------------------
422
+ // Chat engine chat patch — framework span with chat content
423
+ // Mirrors Python: chat engine operations -> operation_type "invoke_workflow"
424
+ // ---------------------------------------------------------------------------
425
+ static _patchChatEngineChat(tracer) {
426
+ const endpoint = 'chat_engine_chat';
427
+ const operationType = semantic_convention_1.default.GEN_AI_OPERATION_TYPE_FRAMEWORK;
428
+ return (originalMethod) => {
429
+ return function (...args) {
430
+ const requestModel = LlamaIndexWrapper._extractModel(this);
431
+ const { address, port } = LlamaIndexWrapper._extractServerInfo(this?.llm || this?._llm || this);
432
+ const workflowName = this?.constructor?.name || 'chat_engine';
433
+ const spanName = `${operationType} ${workflowName}`;
434
+ const span = tracer.startSpan(spanName, {
435
+ kind: api_1.SpanKind.INTERNAL,
436
+ attributes: {
437
+ [semantic_convention_1.default.GEN_AI_OPERATION]: operationType,
438
+ [semantic_convention_1.default.GEN_AI_PROVIDER_NAME_OTEL]: LlamaIndexWrapper.aiSystem,
439
+ [semantic_convention_1.default.GEN_AI_WORKFLOW_NAME]: workflowName,
440
+ },
441
+ });
442
+ return api_1.context.with(api_1.trace.setSpan(api_1.context.active(), span), () => {
443
+ const startTime = Date.now();
444
+ const onSuccess = (response) => {
445
+ try {
446
+ const duration = (Date.now() - startTime) / 1000;
447
+ base_wrapper_1.default.setBaseSpanAttributes(span, {
448
+ genAIEndpoint: endpoint,
449
+ model: requestModel,
450
+ aiSystem: LlamaIndexWrapper.aiSystem,
451
+ serverAddress: address,
452
+ serverPort: port,
453
+ });
454
+ span.setAttribute(semantic_convention_1.default.GEN_AI_CLIENT_OPERATION_DURATION, duration);
455
+ if (config_1.default.captureMessageContent) {
456
+ const messageInput = args[0];
457
+ const message = typeof messageInput === 'string'
458
+ ? messageInput
459
+ : messageInput?.message || messageInput?.content || '';
460
+ span.setAttribute(semantic_convention_1.default.GEN_AI_INPUT_MESSAGES, helpers_1.default.buildInputMessages([{ role: 'user', content: message }]));
461
+ const responseContent = response?.message?.content
462
+ || (typeof response?.response === 'string' ? response.response : '')
463
+ || response?.toString?.() || '';
464
+ span.setAttribute(semantic_convention_1.default.GEN_AI_OUTPUT_MESSAGES, helpers_1.default.buildOutputMessages(responseContent, 'stop'));
465
+ }
466
+ base_wrapper_1.default.recordMetrics(span, {
467
+ genAIEndpoint: endpoint,
468
+ model: requestModel,
469
+ aiSystem: LlamaIndexWrapper.aiSystem,
470
+ serverAddress: address,
471
+ serverPort: port,
472
+ });
183
473
  }
184
- metricParams = { genAIEndpoint, model: modelId, aiSystem };
474
+ catch { /* swallow */ }
475
+ span.end();
185
476
  return response;
477
+ };
478
+ const onError = (e) => {
479
+ helpers_1.default.handleException(span, e);
480
+ base_wrapper_1.default.recordMetrics(span, {
481
+ genAIEndpoint: endpoint,
482
+ model: requestModel,
483
+ aiSystem: LlamaIndexWrapper.aiSystem,
484
+ serverAddress: address,
485
+ serverPort: port,
486
+ errorType: e?.constructor?.name || '_OTHER',
487
+ });
488
+ span.end();
489
+ throw e;
490
+ };
491
+ try {
492
+ const result = originalMethod.apply(this, args);
493
+ if (result && typeof result.then === 'function') {
494
+ return result.then(onSuccess).catch(onError);
495
+ }
496
+ return onSuccess(result);
186
497
  }
187
498
  catch (e) {
499
+ return onError(e);
500
+ }
501
+ });
502
+ };
503
+ };
504
+ }
505
+ // ---------------------------------------------------------------------------
506
+ // Retriever retrieve patch — retrieval span
507
+ // Mirrors Python: BaseRetriever.retrieve -> operation_type "retrieval"
508
+ // ---------------------------------------------------------------------------
509
+ static _patchRetrieverRetrieve(tracer) {
510
+ const endpoint = 'retriever_retrieve';
511
+ const operationType = OPERATION_MAP[endpoint];
512
+ return (originalMethod) => {
513
+ return function (...args) {
514
+ const { address, port } = LlamaIndexWrapper._extractServerInfo(this);
515
+ const spanName = `${operationType} ${endpoint}`;
516
+ const span = tracer.startSpan(spanName, {
517
+ kind: api_1.SpanKind.CLIENT,
518
+ attributes: {
519
+ [semantic_convention_1.default.GEN_AI_OPERATION]: operationType,
520
+ [semantic_convention_1.default.GEN_AI_PROVIDER_NAME_OTEL]: LlamaIndexWrapper.aiSystem,
521
+ },
522
+ });
523
+ return api_1.context.with(api_1.trace.setSpan(api_1.context.active(), span), () => {
524
+ const startTime = Date.now();
525
+ const model = LlamaIndexWrapper._extractModel(this);
526
+ const onSuccess = (response) => {
527
+ try {
528
+ const duration = (Date.now() - startTime) / 1000;
529
+ base_wrapper_1.default.setBaseSpanAttributes(span, {
530
+ genAIEndpoint: endpoint,
531
+ model,
532
+ aiSystem: LlamaIndexWrapper.aiSystem,
533
+ serverAddress: address,
534
+ serverPort: port,
535
+ });
536
+ span.setAttribute(semantic_convention_1.default.GEN_AI_CLIENT_OPERATION_DURATION, duration);
537
+ if (Array.isArray(response) && response.length > 0) {
538
+ span.setAttribute(semantic_convention_1.default.GEN_AI_RETRIEVAL_SOURCE, JSON.stringify(response.slice(0, 5).map((n) => ({
539
+ id: n.node?.id_ || n.id_ || '',
540
+ score: n.score,
541
+ text: n.node?.text?.slice(0, 200) || n.text?.slice(0, 200) || '',
542
+ }))));
543
+ }
544
+ if (config_1.default.captureMessageContent) {
545
+ const queryStr = typeof args[0] === 'string'
546
+ ? args[0]
547
+ : args[0]?.query || args[0]?.queryStr || '';
548
+ span.setAttribute(semantic_convention_1.default.GEN_AI_INPUT_MESSAGES, helpers_1.default.buildInputMessages([{ role: 'user', content: queryStr }]));
549
+ }
550
+ base_wrapper_1.default.recordMetrics(span, {
551
+ genAIEndpoint: endpoint,
552
+ model,
553
+ aiSystem: LlamaIndexWrapper.aiSystem,
554
+ serverAddress: address,
555
+ serverPort: port,
556
+ });
557
+ }
558
+ catch { /* swallow */ }
559
+ span.end();
560
+ return response;
561
+ };
562
+ const onError = (e) => {
188
563
  helpers_1.default.handleException(span, e);
564
+ base_wrapper_1.default.recordMetrics(span, {
565
+ genAIEndpoint: endpoint,
566
+ model,
567
+ aiSystem: LlamaIndexWrapper.aiSystem,
568
+ serverAddress: address,
569
+ serverPort: port,
570
+ errorType: e?.constructor?.name || '_OTHER',
571
+ });
572
+ span.end();
189
573
  throw e;
574
+ };
575
+ try {
576
+ const result = originalMethod.apply(this, args);
577
+ if (result && typeof result.then === 'function') {
578
+ return result.then(onSuccess).catch(onError);
579
+ }
580
+ return onSuccess(result);
190
581
  }
191
- finally {
192
- span.end();
193
- if (metricParams)
194
- base_wrapper_1.default.recordMetrics(span, metricParams);
582
+ catch (e) {
583
+ return onError(e);
195
584
  }
196
585
  });
197
586
  };
198
587
  };
199
588
  }
200
- // ---- Chat engine patch -----------------------------------------------------
201
- static _patchChatEngineChat(tracer) {
202
- const genAIEndpoint = 'llamaindex.chat_engine.chat';
589
+ // ---------------------------------------------------------------------------
590
+ // Embedding patch — embeddings span
591
+ // Mirrors Python: BaseEmbedding.get_text_embedding_batch -> "embeddings"
592
+ // ---------------------------------------------------------------------------
593
+ static _patchEmbedding(tracer, endpoint = 'embedding_generate') {
594
+ const operationType = OPERATION_MAP[endpoint] || semantic_convention_1.default.GEN_AI_OPERATION_TYPE_EMBEDDING;
203
595
  return (originalMethod) => {
204
- return async function (...args) {
205
- const span = tracer.startSpan(genAIEndpoint, { kind: api_1.SpanKind.CLIENT });
206
- return api_1.context.with(api_1.trace.setSpan(api_1.context.active(), span), async () => {
207
- let metricParams;
596
+ return function (...args) {
597
+ const model = LlamaIndexWrapper._extractModel(this);
598
+ const { address, port } = LlamaIndexWrapper._extractServerInfo(this);
599
+ const spanName = `${operationType} ${endpoint}`;
600
+ const span = tracer.startSpan(spanName, {
601
+ kind: api_1.SpanKind.CLIENT,
602
+ attributes: {
603
+ [semantic_convention_1.default.GEN_AI_OPERATION]: operationType,
604
+ [semantic_convention_1.default.GEN_AI_PROVIDER_NAME_OTEL]: LlamaIndexWrapper.aiSystem,
605
+ [semantic_convention_1.default.GEN_AI_REQUEST_MODEL]: model,
606
+ [semantic_convention_1.default.SERVER_ADDRESS]: address,
607
+ [semantic_convention_1.default.SERVER_PORT]: port,
608
+ },
609
+ });
610
+ return api_1.context.with(api_1.trace.setSpan(api_1.context.active(), span), () => {
208
611
  const startTime = Date.now();
209
- try {
210
- const response = await originalMethod.apply(this, args);
211
- const duration = (Date.now() - startTime) / 1000;
212
- const messageInput = args[0];
213
- const message = typeof messageInput === 'string'
214
- ? messageInput
215
- : messageInput?.message || messageInput?.content || '';
216
- const llm = this.llm || this._llm;
217
- const modelId = llm?.model || llm?.modelName || llm?.metadata?.model || 'unknown';
218
- const aiSystem = LlamaIndexWrapper.aiSystem;
219
- const { address, port } = LlamaIndexWrapper._extractServerInfo(llm || this);
220
- LlamaIndexWrapper.setBaseSpanAttributes(span, { genAIEndpoint, model: modelId, aiSystem, serverAddress: address, serverPort: port });
221
- span.setAttribute(semantic_convention_1.default.GEN_AI_OPERATION, semantic_convention_1.default.GEN_AI_OPERATION_TYPE_FRAMEWORK);
222
- span.setAttribute(semantic_convention_1.default.GEN_AI_REQUEST_IS_STREAM, false);
223
- span.setAttribute(semantic_convention_1.default.GEN_AI_CLIENT_OPERATION_DURATION, duration);
224
- span.setAttribute(semantic_convention_1.default.SERVER_ADDRESS, address);
225
- span.setAttribute(semantic_convention_1.default.SERVER_PORT, port);
226
- if (config_1.default.traceContent) {
227
- span.setAttribute(semantic_convention_1.default.GEN_AI_INPUT_MESSAGES, helpers_1.default.buildInputMessages([{ role: 'user', content: message }]));
228
- const responseContent = response?.message?.content ||
229
- (typeof response?.response === 'string' ? response.response : '') ||
230
- response?.toString?.() || '';
231
- span.setAttribute(semantic_convention_1.default.GEN_AI_OUTPUT_MESSAGES, helpers_1.default.buildOutputMessages(responseContent, 'stop'));
612
+ const onSuccess = (response) => {
613
+ try {
614
+ const duration = (Date.now() - startTime) / 1000;
615
+ base_wrapper_1.default.setBaseSpanAttributes(span, {
616
+ genAIEndpoint: endpoint,
617
+ model,
618
+ aiSystem: LlamaIndexWrapper.aiSystem,
619
+ serverAddress: address,
620
+ serverPort: port,
621
+ });
622
+ span.setAttribute(semantic_convention_1.default.GEN_AI_CLIENT_OPERATION_DURATION, duration);
623
+ if (Array.isArray(response) && response.length > 0) {
624
+ if (Array.isArray(response[0])) {
625
+ span.setAttribute(semantic_convention_1.default.GEN_AI_EMBEDDINGS_DIMENSION_COUNT, response[0].length);
626
+ }
627
+ else if (typeof response[0] === 'number') {
628
+ span.setAttribute(semantic_convention_1.default.GEN_AI_EMBEDDINGS_DIMENSION_COUNT, response.length);
629
+ }
630
+ }
631
+ base_wrapper_1.default.recordMetrics(span, {
632
+ genAIEndpoint: endpoint,
633
+ model,
634
+ aiSystem: LlamaIndexWrapper.aiSystem,
635
+ serverAddress: address,
636
+ serverPort: port,
637
+ });
232
638
  }
233
- metricParams = { genAIEndpoint, model: modelId, aiSystem };
639
+ catch { /* swallow */ }
640
+ span.end();
234
641
  return response;
642
+ };
643
+ const onError = (e) => {
644
+ helpers_1.default.handleException(span, e);
645
+ base_wrapper_1.default.recordMetrics(span, {
646
+ genAIEndpoint: endpoint,
647
+ model,
648
+ aiSystem: LlamaIndexWrapper.aiSystem,
649
+ serverAddress: address,
650
+ serverPort: port,
651
+ errorType: e?.constructor?.name || '_OTHER',
652
+ });
653
+ span.end();
654
+ throw e;
655
+ };
656
+ try {
657
+ const result = (0, helpers_1.runWithFrameworkLlm)(() => originalMethod.apply(this, args));
658
+ if (result && typeof result.then === 'function') {
659
+ return result.then(onSuccess).catch(onError);
660
+ }
661
+ return onSuccess(result);
235
662
  }
236
663
  catch (e) {
664
+ return onError(e);
665
+ }
666
+ });
667
+ };
668
+ };
669
+ }
670
+ // ---------------------------------------------------------------------------
671
+ // Generic framework method patch — for index, document, synthesizer, etc.
672
+ // Mirrors Python: common_llamaindex_logic with framework-level attributes
673
+ // ---------------------------------------------------------------------------
674
+ static _patchFrameworkMethod(tracer, endpoint) {
675
+ const operationType = OPERATION_MAP[endpoint] || semantic_convention_1.default.GEN_AI_OPERATION_TYPE_FRAMEWORK;
676
+ return (originalMethod) => {
677
+ return function (...args) {
678
+ const { address, port } = LlamaIndexWrapper._extractServerInfo(this);
679
+ const spanName = `${operationType} ${endpoint}`;
680
+ const span = tracer.startSpan(spanName, {
681
+ kind: api_1.SpanKind.CLIENT,
682
+ attributes: {
683
+ [semantic_convention_1.default.GEN_AI_OPERATION]: operationType,
684
+ [semantic_convention_1.default.GEN_AI_PROVIDER_NAME_OTEL]: LlamaIndexWrapper.aiSystem,
685
+ },
686
+ });
687
+ return api_1.context.with(api_1.trace.setSpan(api_1.context.active(), span), () => {
688
+ const startTime = Date.now();
689
+ const model = LlamaIndexWrapper._extractModel(this);
690
+ const onSuccess = (response) => {
691
+ try {
692
+ const duration = (Date.now() - startTime) / 1000;
693
+ base_wrapper_1.default.setBaseSpanAttributes(span, {
694
+ genAIEndpoint: endpoint,
695
+ model,
696
+ aiSystem: LlamaIndexWrapper.aiSystem,
697
+ serverAddress: address,
698
+ serverPort: port,
699
+ });
700
+ span.setAttribute(semantic_convention_1.default.GEN_AI_CLIENT_OPERATION_DURATION, duration);
701
+ base_wrapper_1.default.recordMetrics(span, {
702
+ genAIEndpoint: endpoint,
703
+ model,
704
+ aiSystem: LlamaIndexWrapper.aiSystem,
705
+ serverAddress: address,
706
+ serverPort: port,
707
+ });
708
+ }
709
+ catch { /* swallow */ }
710
+ span.end();
711
+ return response;
712
+ };
713
+ const onError = (e) => {
237
714
  helpers_1.default.handleException(span, e);
715
+ base_wrapper_1.default.recordMetrics(span, {
716
+ genAIEndpoint: endpoint,
717
+ model,
718
+ aiSystem: LlamaIndexWrapper.aiSystem,
719
+ serverAddress: address,
720
+ serverPort: port,
721
+ errorType: e?.constructor?.name || '_OTHER',
722
+ });
723
+ span.end();
238
724
  throw e;
725
+ };
726
+ try {
727
+ const result = originalMethod.apply(this, args);
728
+ if (result && typeof result.then === 'function') {
729
+ return result.then(onSuccess).catch(onError);
730
+ }
731
+ return onSuccess(result);
239
732
  }
240
- finally {
241
- span.end();
242
- if (metricParams)
243
- base_wrapper_1.default.recordMetrics(span, metricParams);
733
+ catch (e) {
734
+ return onError(e);
244
735
  }
245
736
  });
246
737
  };
247
738
  };
248
739
  }
249
740
  }
250
- LlamaIndexWrapper.aiSystem = 'llamaindex';
741
+ LlamaIndexWrapper.aiSystem = semantic_convention_1.default.GEN_AI_SYSTEM_LLAMAINDEX;
251
742
  exports.default = LlamaIndexWrapper;
252
743
  //# sourceMappingURL=wrapper.js.map