@introspection-sdk/introspection-node 0.4.3 → 0.4.4

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 (122) hide show
  1. package/.turbo/turbo-build.log +1 -1
  2. package/dist/otel/anthropic.d.ts +14 -12
  3. package/dist/otel/anthropic.d.ts.map +1 -1
  4. package/dist/otel/anthropic.js +89 -47
  5. package/dist/otel/anthropic.js.map +1 -1
  6. package/dist/otel/gemini.d.ts +15 -7
  7. package/dist/otel/gemini.d.ts.map +1 -1
  8. package/dist/otel/gemini.js +88 -37
  9. package/dist/otel/gemini.js.map +1 -1
  10. package/dist/otel/index.d.ts +5 -0
  11. package/dist/otel/index.d.ts.map +1 -1
  12. package/dist/otel/index.js +8 -0
  13. package/dist/otel/index.js.map +1 -1
  14. package/dist/otel/init.d.ts +126 -0
  15. package/dist/otel/init.d.ts.map +1 -0
  16. package/dist/otel/init.js +259 -0
  17. package/dist/otel/init.js.map +1 -0
  18. package/dist/otel/integrations/anthropic.d.ts +10 -0
  19. package/dist/otel/integrations/anthropic.d.ts.map +1 -0
  20. package/dist/otel/integrations/anthropic.js +22 -0
  21. package/dist/otel/integrations/anthropic.js.map +1 -0
  22. package/dist/otel/integrations/base.d.ts +83 -0
  23. package/dist/otel/integrations/base.d.ts.map +1 -0
  24. package/dist/otel/integrations/base.js +23 -0
  25. package/dist/otel/integrations/base.js.map +1 -0
  26. package/dist/otel/integrations/claude-agent.d.ts +13 -0
  27. package/dist/otel/integrations/claude-agent.d.ts.map +1 -0
  28. package/dist/otel/integrations/claude-agent.js +27 -0
  29. package/dist/otel/integrations/claude-agent.js.map +1 -0
  30. package/dist/otel/integrations/gemini.d.ts +11 -0
  31. package/dist/otel/integrations/gemini.d.ts.map +1 -0
  32. package/dist/otel/integrations/gemini.js +21 -0
  33. package/dist/otel/integrations/gemini.js.map +1 -0
  34. package/dist/otel/integrations/index.d.ts +39 -0
  35. package/dist/otel/integrations/index.d.ts.map +1 -0
  36. package/dist/otel/integrations/index.js +131 -0
  37. package/dist/otel/integrations/index.js.map +1 -0
  38. package/dist/otel/integrations/langchain.d.ts +16 -0
  39. package/dist/otel/integrations/langchain.d.ts.map +1 -0
  40. package/dist/otel/integrations/langchain.js +41 -0
  41. package/dist/otel/integrations/langchain.js.map +1 -0
  42. package/dist/otel/integrations/mastra.d.ts +14 -0
  43. package/dist/otel/integrations/mastra.d.ts.map +1 -0
  44. package/dist/otel/integrations/mastra.js +27 -0
  45. package/dist/otel/integrations/mastra.js.map +1 -0
  46. package/dist/otel/integrations/openai-agents.d.ts +11 -0
  47. package/dist/otel/integrations/openai-agents.d.ts.map +1 -0
  48. package/dist/otel/integrations/openai-agents.js +25 -0
  49. package/dist/otel/integrations/openai-agents.js.map +1 -0
  50. package/dist/otel/integrations/pi.d.ts +12 -0
  51. package/dist/otel/integrations/pi.d.ts.map +1 -0
  52. package/dist/otel/integrations/pi.js +20 -0
  53. package/dist/otel/integrations/pi.js.map +1 -0
  54. package/dist/otel/integrations/vercel.d.ts +15 -0
  55. package/dist/otel/integrations/vercel.d.ts.map +1 -0
  56. package/dist/otel/integrations/vercel.js +20 -0
  57. package/dist/otel/integrations/vercel.js.map +1 -0
  58. package/dist/otel/register.d.ts +8 -0
  59. package/dist/otel/register.d.ts.map +1 -0
  60. package/dist/otel/register.js +48 -0
  61. package/dist/otel/register.js.map +1 -0
  62. package/dist/otel/setup.d.ts +29 -0
  63. package/dist/otel/setup.d.ts.map +1 -1
  64. package/dist/otel/setup.js +22 -3
  65. package/dist/otel/setup.js.map +1 -1
  66. package/dist/utils.d.ts +10 -0
  67. package/dist/utils.d.ts.map +1 -1
  68. package/dist/utils.js +12 -4
  69. package/dist/utils.js.map +1 -1
  70. package/package.json +17 -5
  71. package/src/otel/anthropic.ts +128 -63
  72. package/src/otel/gemini.ts +139 -45
  73. package/src/otel/index.ts +41 -0
  74. package/src/otel/init.ts +411 -0
  75. package/src/otel/integrations/anthropic.ts +26 -0
  76. package/src/otel/integrations/base.ts +95 -0
  77. package/src/otel/integrations/claude-agent.ts +32 -0
  78. package/src/otel/integrations/gemini.ts +25 -0
  79. package/src/otel/integrations/index.ts +151 -0
  80. package/src/otel/integrations/langchain.ts +45 -0
  81. package/src/otel/integrations/mastra.ts +30 -0
  82. package/src/otel/integrations/openai-agents.ts +31 -0
  83. package/src/otel/integrations/pi.ts +24 -0
  84. package/src/otel/integrations/vercel.ts +24 -0
  85. package/src/otel/register.ts +50 -0
  86. package/src/otel/setup.ts +44 -3
  87. package/src/utils.ts +12 -5
  88. package/.turbo/turbo-check-types.log +0 -4
  89. package/.turbo/turbo-lint.log +0 -5
  90. package/dist/ai-sdk-integration.d.ts +0 -123
  91. package/dist/ai-sdk-integration.d.ts.map +0 -1
  92. package/dist/ai-sdk-integration.js +0 -475
  93. package/dist/anthropic.d.ts +0 -54
  94. package/dist/anthropic.d.ts.map +0 -1
  95. package/dist/anthropic.js +0 -375
  96. package/dist/claude-hooks.d.ts +0 -328
  97. package/dist/claude-hooks.d.ts.map +0 -1
  98. package/dist/claude-hooks.js +0 -571
  99. package/dist/claude-wrapper.d.ts +0 -93
  100. package/dist/claude-wrapper.d.ts.map +0 -1
  101. package/dist/claude-wrapper.js +0 -154
  102. package/dist/converters/ai-sdk.d.ts +0 -65
  103. package/dist/converters/ai-sdk.d.ts.map +0 -1
  104. package/dist/converters/ai-sdk.js +0 -261
  105. package/dist/converters/openclaw.d.ts +0 -16
  106. package/dist/converters/openclaw.d.ts.map +0 -1
  107. package/dist/converters/openclaw.js +0 -49
  108. package/dist/langchain-handler.d.ts +0 -103
  109. package/dist/langchain-handler.d.ts.map +0 -1
  110. package/dist/langchain-handler.js +0 -518
  111. package/dist/mastra-exporter.d.ts +0 -85
  112. package/dist/mastra-exporter.d.ts.map +0 -1
  113. package/dist/mastra-exporter.js +0 -471
  114. package/dist/span-processor.d.ts +0 -62
  115. package/dist/span-processor.d.ts.map +0 -1
  116. package/dist/span-processor.js +0 -313
  117. package/dist/tracing-processor.d.ts +0 -136
  118. package/dist/tracing-processor.d.ts.map +0 -1
  119. package/dist/tracing-processor.js +0 -368
  120. package/dist/types/genai.d.ts +0 -165
  121. package/dist/types/genai.d.ts.map +0 -1
  122. package/dist/types/genai.js +0 -82
@@ -1,518 +0,0 @@
1
- /**
2
- * LangChain/LangGraph Callback Handler for Introspection.
3
- *
4
- * Hooks into LangChain's native callback system to capture LLM, tool, and
5
- * chain interactions as gen_ai.* OTel spans for the Introspection backend.
6
- *
7
- * Similar to IntrospectionTracingProcessor for OpenAI Agents SDK and
8
- * IntrospectionClaudeHooks for Claude Agent SDK.
9
- *
10
- * **Important:** This module requires `@langchain/core` at runtime.
11
- * Import via the subpath: `@introspection-sdk/introspection-node/langchain`
12
- *
13
- * @example
14
- * ```ts
15
- * import { IntrospectionCallbackHandler } from "@introspection-sdk/introspection-node/langchain";
16
- * import { ChatOpenAI } from "@langchain/openai";
17
- *
18
- * const handler = new IntrospectionCallbackHandler({
19
- * serviceName: "my-langchain-app",
20
- * });
21
- *
22
- * const model = new ChatOpenAI({ modelName: "gpt-4o" });
23
- * const response = await model.invoke("Hello!", { callbacks: [handler] });
24
- *
25
- * await handler.shutdown();
26
- * ```
27
- */
28
- import { BaseCallbackHandler } from "@langchain/core/callbacks/base";
29
- import { context as otelContext, ROOT_CONTEXT, SpanStatusCode, trace as otelTrace, } from "@opentelemetry/api";
30
- import { BasicTracerProvider, BatchSpanProcessor, SimpleSpanProcessor, } from "@opentelemetry/sdk-trace-base";
31
- import { OTLPTraceExporter } from "@opentelemetry/exporter-trace-otlp-proto";
32
- import { resourceFromAttributes } from "@opentelemetry/resources";
33
- import { ATTR_SERVICE_NAME } from "@opentelemetry/semantic-conventions";
34
- import { randomUUID } from "crypto";
35
- import { logger, withOtlpHttpsProxy } from "./utils.js";
36
- import { VERSION } from "./version.js";
37
- // ---------------------------------------------------------------------------
38
- // Handler
39
- // ---------------------------------------------------------------------------
40
- /**
41
- * LangChain callback handler that captures LLM, tool, and chain events
42
- * as gen_ai.* OTel spans and exports them to the Introspection backend.
43
- *
44
- * Pass as a callback to any LangChain invoke call, or set globally via
45
- * `setGlobalHandler()`.
46
- */
47
- export class IntrospectionCallbackHandler extends BaseCallbackHandler {
48
- name = "IntrospectionCallbackHandler";
49
- _tracerProvider;
50
- _tracer;
51
- _spans = new Map();
52
- _conversationId;
53
- // Track span names and parents so children can resolve gen_ai.agent.name
54
- _spanNames = new Map();
55
- _spanParents = new Map();
56
- _runRoots = new Map();
57
- // LangChain wrapper names to skip when resolving agent names
58
- static _wrapperNames = new Set([
59
- "RunnableSequence",
60
- "RunnableParallel",
61
- "RunnableMap",
62
- "RunnableLambda",
63
- "RunnableRetry",
64
- "_ConfigurableModel",
65
- "ChatOpenAI",
66
- "ChatAnthropic",
67
- "ChatGoogleGenerativeAI",
68
- "ChatGroq",
69
- ]);
70
- // Store LLM input messages per runId for use in handleLLMEnd
71
- _llmInputs = new Map();
72
- constructor(options = {}) {
73
- super();
74
- const advanced = options.advanced;
75
- const serviceName = options.serviceName || process.env.INTROSPECTION_SERVICE_NAME;
76
- const resource = serviceName
77
- ? resourceFromAttributes({ [ATTR_SERVICE_NAME]: serviceName })
78
- : undefined;
79
- if (!advanced?.spanExporter) {
80
- const token = options.token || process.env.INTROSPECTION_TOKEN;
81
- if (!token) {
82
- throw new Error("INTROSPECTION_TOKEN is required");
83
- }
84
- const baseUrl = options.baseUrl ||
85
- process.env.INTROSPECTION_BASE_URL ||
86
- "https://otel.introspection.dev";
87
- const endpoint = baseUrl.endsWith("/v1/traces")
88
- ? baseUrl
89
- : `${baseUrl.replace(/\/$/, "")}/v1/traces`;
90
- const headers = {
91
- "User-Agent": `introspection-sdk/${VERSION}`,
92
- Authorization: `Bearer ${token}`,
93
- ...options.additionalHeaders,
94
- };
95
- logger.info(`IntrospectionCallbackHandler initialized: endpoint=${endpoint}`);
96
- const spanExporter = new OTLPTraceExporter(withOtlpHttpsProxy({ url: endpoint, headers }));
97
- const effectiveBatchSize = token.startsWith("intro_dev") || token.startsWith("intro_staging")
98
- ? 1
99
- : undefined;
100
- const useSimple = advanced?.useSimpleSpanProcessor || effectiveBatchSize === 1;
101
- const spanProcessor = useSimple
102
- ? new SimpleSpanProcessor(spanExporter)
103
- : new BatchSpanProcessor(spanExporter, {
104
- scheduledDelayMillis: 1000,
105
- ...(effectiveBatchSize
106
- ? { maxExportBatchSize: effectiveBatchSize }
107
- : {}),
108
- });
109
- this._tracerProvider = new BasicTracerProvider({
110
- resource,
111
- idGenerator: advanced?.idGenerator,
112
- spanProcessors: [spanProcessor],
113
- });
114
- }
115
- else {
116
- logger.info("IntrospectionCallbackHandler initialized in test mode with custom exporter");
117
- const spanProcessor = advanced.useSimpleSpanProcessor
118
- ? new SimpleSpanProcessor(advanced.spanExporter)
119
- : new BatchSpanProcessor(advanced.spanExporter, {
120
- scheduledDelayMillis: 100,
121
- });
122
- this._tracerProvider = new BasicTracerProvider({
123
- resource,
124
- idGenerator: advanced.idGenerator,
125
- spanProcessors: [spanProcessor],
126
- });
127
- }
128
- this._tracer = this._tracerProvider.getTracer("langchain", VERSION);
129
- this._conversationId = `intro_conv_${randomUUID().replace(/-/g, "")}`;
130
- }
131
- _rootRunId(runId, parentRunId) {
132
- if (!parentRunId)
133
- return runId;
134
- return this._runRoots.get(parentRunId) || parentRunId;
135
- }
136
- /** Keep the top-level run span aligned with child conversation IDs. */
137
- _setRootConversationId(conversationId, runId, parentRunId) {
138
- const root = this._spans.get(this._rootRunId(runId, parentRunId));
139
- root?.setAttribute("gen_ai.conversation.id", conversationId);
140
- }
141
- _endRootIfComplete(runId) {
142
- this._runRoots.delete(runId);
143
- this._spanNames.delete(runId);
144
- this._spanParents.delete(runId);
145
- }
146
- /** Create a span under a LangChain parent when one exists.
147
- * Sets gen_ai.agent.name to the parent span's name for hierarchy. */
148
- _createChildSpan(name, runId, parentRunId) {
149
- const parent = parentRunId ? this._spans.get(parentRunId) : undefined;
150
- this._runRoots.set(runId, this._rootRunId(runId, parentRunId));
151
- const ctx = parent
152
- ? otelTrace.setSpan(otelContext.active(), parent)
153
- : ROOT_CONTEXT;
154
- const span = this._tracer.startSpan(name, {}, ctx);
155
- this._spanNames.set(runId, name);
156
- if (parentRunId) {
157
- this._spanParents.set(runId, parentRunId);
158
- }
159
- // Walk up parents to find first non-wrapper name for gen_ai.agent.name
160
- const agentName = this._findAgentName(parentRunId);
161
- if (agentName) {
162
- span.setAttribute("gen_ai.agent.name", agentName);
163
- }
164
- return span;
165
- }
166
- // -------------------------------------------------------------------------
167
- // Chat model callbacks (preferred over LLM callbacks for chat models)
168
- // -------------------------------------------------------------------------
169
- handleChatModelStart(llm, messages, runId, parentRunId, extraParams, _tags, metadata, runName) {
170
- const modelName = this._extractModelName(llm, extraParams);
171
- const spanName = modelName ? `chat ${modelName}` : runName || "chat";
172
- const otelSpan = this._createChildSpan(spanName, runId, parentRunId);
173
- this._spans.set(runId, otelSpan);
174
- const conversationId = this._getConversationId(metadata);
175
- this._setRootConversationId(conversationId, runId, parentRunId);
176
- otelSpan.setAttribute("gen_ai.operation.name", "chat");
177
- otelSpan.setAttribute("gen_ai.conversation.id", conversationId);
178
- otelSpan.setAttribute("openinference.span.kind", "LLM");
179
- if (modelName) {
180
- otelSpan.setAttribute("gen_ai.request.model", modelName);
181
- }
182
- const flatMessages = messages[0] || [];
183
- const { inputMessages, systemInstructions } = this._convertMessages(flatMessages);
184
- if (inputMessages.length > 0) {
185
- otelSpan.setAttribute("gen_ai.input.messages", JSON.stringify(inputMessages));
186
- this._llmInputs.set(runId, inputMessages);
187
- }
188
- if (systemInstructions.length > 0) {
189
- otelSpan.setAttribute("gen_ai.system_instructions", JSON.stringify(systemInstructions.map((s) => ({ type: "text", content: s }))));
190
- }
191
- const provider = this._extractProvider(llm);
192
- if (provider) {
193
- otelSpan.setAttribute("gen_ai.system", provider);
194
- }
195
- const invocationParams = extraParams?.["invocation_params"];
196
- const tools = invocationParams?.["tools"];
197
- if (tools && tools.length > 0) {
198
- otelSpan.setAttribute("gen_ai.tool.definitions", JSON.stringify(tools.map((t) => {
199
- const fn = (t.function || t);
200
- return {
201
- type: t.type || "function",
202
- name: (fn.name || ""),
203
- description: (fn.description || ""),
204
- parameters: fn.parameters,
205
- };
206
- })));
207
- }
208
- if (invocationParams?.["temperature"] != null) {
209
- otelSpan.setAttribute("gen_ai.request.temperature", invocationParams["temperature"]);
210
- }
211
- }
212
- handleLLMStart(llm, prompts, runId, parentRunId, extraParams, _tags, metadata, runName) {
213
- const modelName = this._extractModelName(llm, extraParams);
214
- const spanName = modelName ? `chat ${modelName}` : runName || "llm";
215
- const otelSpan = this._createChildSpan(spanName, runId, parentRunId);
216
- this._spans.set(runId, otelSpan);
217
- const conversationId = this._getConversationId(metadata);
218
- this._setRootConversationId(conversationId, runId, parentRunId);
219
- otelSpan.setAttribute("gen_ai.operation.name", "chat");
220
- otelSpan.setAttribute("gen_ai.conversation.id", conversationId);
221
- otelSpan.setAttribute("openinference.span.kind", "LLM");
222
- if (modelName) {
223
- otelSpan.setAttribute("gen_ai.request.model", modelName);
224
- }
225
- if (prompts.length > 0) {
226
- const inputMessages = prompts.map((p) => ({
227
- role: "user",
228
- parts: [{ type: "text", content: p }],
229
- }));
230
- otelSpan.setAttribute("gen_ai.input.messages", JSON.stringify(inputMessages));
231
- this._llmInputs.set(runId, inputMessages);
232
- }
233
- }
234
- handleLLMEnd(output, runId) {
235
- const otelSpan = this._spans.get(runId);
236
- if (!otelSpan)
237
- return;
238
- this._spans.delete(runId);
239
- this._spanNames.delete(runId);
240
- this._llmInputs.delete(runId);
241
- this._endRootIfComplete(runId);
242
- const generations = output.generations?.[0];
243
- if (generations && generations.length > 0) {
244
- const parts = [];
245
- for (const gen of generations) {
246
- if (gen.text) {
247
- parts.push({ type: "text", content: gen.text });
248
- }
249
- const msg = gen.message;
250
- const kwargs = (msg?.["kwargs"] || msg);
251
- const additionalKwargs = kwargs?.["additional_kwargs"];
252
- const toolCalls = (additionalKwargs?.["tool_calls"] ||
253
- kwargs?.["tool_calls"]);
254
- if (toolCalls) {
255
- for (const tc of toolCalls) {
256
- const fn = (tc.function || tc);
257
- parts.push({
258
- type: "tool_call",
259
- name: (fn.name || tc.name || ""),
260
- id: (tc.id || ""),
261
- arguments: (fn.arguments || tc.args || ""),
262
- });
263
- }
264
- }
265
- }
266
- if (parts.length > 0) {
267
- const outputMessages = [{ role: "assistant", parts }];
268
- otelSpan.setAttribute("gen_ai.output.messages", JSON.stringify(outputMessages));
269
- }
270
- }
271
- const usage = output.llmOutput;
272
- const tokenUsage = (usage?.["tokenUsage"] ||
273
- usage?.["token_usage"] ||
274
- usage?.["usage"]);
275
- if (tokenUsage) {
276
- const inputTokens = tokenUsage["promptTokens"] ||
277
- tokenUsage["prompt_tokens"] ||
278
- tokenUsage["input_tokens"];
279
- const outputTokens = tokenUsage["completionTokens"] ||
280
- tokenUsage["completion_tokens"] ||
281
- tokenUsage["output_tokens"];
282
- if (typeof inputTokens === "number") {
283
- otelSpan.setAttribute("gen_ai.usage.input_tokens", inputTokens);
284
- }
285
- if (typeof outputTokens === "number") {
286
- otelSpan.setAttribute("gen_ai.usage.output_tokens", outputTokens);
287
- }
288
- }
289
- const model = usage?.["model"] || usage?.["model_name"];
290
- if (typeof model === "string") {
291
- otelSpan.setAttribute("gen_ai.response.model", model);
292
- }
293
- // gen_ai.response.id — required by the server for conversation tracking.
294
- const responseId = usage?.["id"] || usage?.["system_fingerprint"];
295
- otelSpan.setAttribute("gen_ai.response.id", typeof responseId === "string" ? responseId : `langchain-${runId}`);
296
- otelSpan.end();
297
- }
298
- handleLLMError(err, runId) {
299
- const otelSpan = this._spans.get(runId);
300
- if (!otelSpan)
301
- return;
302
- this._spans.delete(runId);
303
- this._spanNames.delete(runId);
304
- this._llmInputs.delete(runId);
305
- this._endRootIfComplete(runId);
306
- otelSpan.recordException(err);
307
- otelSpan.setStatus({ code: SpanStatusCode.ERROR, message: err.message });
308
- otelSpan.setAttribute("exception.message", err.message);
309
- otelSpan.end();
310
- }
311
- // -------------------------------------------------------------------------
312
- // Chain callbacks
313
- // -------------------------------------------------------------------------
314
- handleChainStart(chain, _inputs, runId, _runType, _tags, metadata, runName, parentRunId) {
315
- const name = runName || chain?.name || chain?.id?.[chain.id.length - 1] || "chain";
316
- const otelSpan = this._createChildSpan(name, runId, parentRunId);
317
- this._spans.set(runId, otelSpan);
318
- const conversationId = this._getConversationId(metadata);
319
- this._setRootConversationId(conversationId, runId, parentRunId);
320
- otelSpan.setAttribute("gen_ai.conversation.id", conversationId);
321
- }
322
- handleChainEnd(_outputs, runId) {
323
- const otelSpan = this._spans.get(runId);
324
- if (!otelSpan)
325
- return;
326
- this._spans.delete(runId);
327
- this._endRootIfComplete(runId);
328
- otelSpan.end();
329
- }
330
- handleChainError(err, runId) {
331
- const otelSpan = this._spans.get(runId);
332
- if (!otelSpan)
333
- return;
334
- this._spans.delete(runId);
335
- this._endRootIfComplete(runId);
336
- otelSpan.recordException(err);
337
- otelSpan.setStatus({ code: SpanStatusCode.ERROR, message: err.message });
338
- otelSpan.setAttribute("exception.message", err.message);
339
- otelSpan.end();
340
- }
341
- // -------------------------------------------------------------------------
342
- // Tool callbacks
343
- // -------------------------------------------------------------------------
344
- handleToolStart(tool, input, runId, parentRunId, _tags, metadata, runName) {
345
- const toolName = runName || tool?.name || tool?.id?.[tool.id.length - 1] || "tool";
346
- const otelSpan = this._createChildSpan(toolName, runId, parentRunId);
347
- this._spans.set(runId, otelSpan);
348
- const conversationId = this._getConversationId(metadata);
349
- this._setRootConversationId(conversationId, runId, parentRunId);
350
- otelSpan.setAttribute("gen_ai.tool.name", toolName);
351
- otelSpan.setAttribute("openinference.span.kind", "TOOL");
352
- otelSpan.setAttribute("gen_ai.tool.input", input);
353
- otelSpan.setAttribute("gen_ai.conversation.id", conversationId);
354
- }
355
- handleToolEnd(output, runId) {
356
- const otelSpan = this._spans.get(runId);
357
- if (!otelSpan)
358
- return;
359
- this._spans.delete(runId);
360
- this._endRootIfComplete(runId);
361
- if (output != null) {
362
- otelSpan.setAttribute("gen_ai.tool.output", typeof output === "string" ? output : JSON.stringify(output));
363
- }
364
- otelSpan.end();
365
- }
366
- handleToolError(err, runId) {
367
- const otelSpan = this._spans.get(runId);
368
- if (!otelSpan)
369
- return;
370
- this._spans.delete(runId);
371
- this._endRootIfComplete(runId);
372
- otelSpan.recordException(err);
373
- otelSpan.setStatus({ code: SpanStatusCode.ERROR, message: err.message });
374
- otelSpan.setAttribute("exception.message", err.message);
375
- otelSpan.end();
376
- }
377
- // -------------------------------------------------------------------------
378
- // Lifecycle
379
- // -------------------------------------------------------------------------
380
- async shutdown() {
381
- for (const span of this._spans.values())
382
- span.end();
383
- this._spans.clear();
384
- this._spanNames.clear();
385
- this._spanParents.clear();
386
- this._runRoots.clear();
387
- await this._tracerProvider.shutdown();
388
- }
389
- async forceFlush() {
390
- await this._tracerProvider.forceFlush();
391
- }
392
- // -------------------------------------------------------------------------
393
- // Helpers
394
- // -------------------------------------------------------------------------
395
- _extractModelName(llm, extraParams) {
396
- const invocationParams = extraParams?.["invocation_params"];
397
- if (invocationParams) {
398
- const model = invocationParams["model"] ||
399
- invocationParams["model_name"] ||
400
- invocationParams["modelName"];
401
- if (typeof model === "string")
402
- return model;
403
- }
404
- const kwargs = llm?.kwargs;
405
- if (kwargs) {
406
- const model = kwargs["model"] || kwargs["model_name"] || kwargs["modelName"];
407
- if (typeof model === "string")
408
- return model;
409
- }
410
- return undefined;
411
- }
412
- _extractProvider(llm) {
413
- const id = llm?.id;
414
- if (Array.isArray(id) && id.length > 0) {
415
- return id[id.length - 1];
416
- }
417
- return undefined;
418
- }
419
- /** Walk up the span tree to find the first non-wrapper span name. */
420
- _findAgentName(runId) {
421
- let current = runId;
422
- for (let i = 0; i < 20 && current; i++) {
423
- const name = this._spanNames.get(current);
424
- if (name && !IntrospectionCallbackHandler._wrapperNames.has(name)) {
425
- return name;
426
- }
427
- current = this._spanParents.get(current);
428
- }
429
- return undefined;
430
- }
431
- _getConversationId(metadata) {
432
- const metaConvId = metadata?.["gen_ai.conversation.id"];
433
- if (metaConvId !== undefined && metaConvId !== null) {
434
- return String(metaConvId);
435
- }
436
- const threadId = metadata?.["thread_id"];
437
- if (threadId !== undefined && threadId !== null) {
438
- return String(threadId);
439
- }
440
- return this._conversationId;
441
- }
442
- _convertMessages(messages) {
443
- const inputMessages = [];
444
- const systemInstructions = [];
445
- for (const msg of messages) {
446
- const msgType = msg._getType?.() ||
447
- msg.type ||
448
- "unknown";
449
- const role = this._mapRole(msgType);
450
- const content = this._extractContent(msg.content);
451
- if (role === "system") {
452
- systemInstructions.push(typeof msg.content === "string"
453
- ? msg.content
454
- : JSON.stringify(msg.content));
455
- continue;
456
- }
457
- const parts = [];
458
- if (role === "tool") {
459
- const toolCallId = msg
460
- .tool_call_id || "";
461
- parts.push({
462
- type: "tool_call_response",
463
- id: toolCallId,
464
- response: content,
465
- });
466
- }
467
- else if (content) {
468
- parts.push({ type: "text", content });
469
- }
470
- const toolCalls = msg
471
- .tool_calls;
472
- if (toolCalls) {
473
- for (const tc of toolCalls) {
474
- parts.push({
475
- type: "tool_call",
476
- name: (tc.name || ""),
477
- id: (tc.id || ""),
478
- arguments: typeof tc.args === "string" ? tc.args : JSON.stringify(tc.args),
479
- });
480
- }
481
- }
482
- if (parts.length > 0) {
483
- inputMessages.push({ role, parts });
484
- }
485
- }
486
- return { inputMessages, systemInstructions };
487
- }
488
- _mapRole(msgType) {
489
- switch (msgType) {
490
- case "human":
491
- return "user";
492
- case "ai":
493
- return "assistant";
494
- case "system":
495
- return "system";
496
- case "tool":
497
- return "tool";
498
- default:
499
- return "user";
500
- }
501
- }
502
- _extractContent(content) {
503
- if (typeof content === "string")
504
- return content;
505
- if (Array.isArray(content)) {
506
- return content
507
- .map((part) => {
508
- const p = part;
509
- if (p.type === "text")
510
- return (p.text || "");
511
- return "";
512
- })
513
- .filter(Boolean)
514
- .join("");
515
- }
516
- return String(content || "");
517
- }
518
- }
@@ -1,85 +0,0 @@
1
- /**
2
- * Mastra-compatible Exporter for Introspection.
3
- *
4
- * Extends Mastra's BaseExporter to receive TracingEvents (Mastra's native
5
- * span format) and convert them to gen_ai.* OTel spans for the Introspection
6
- * backend.
7
- *
8
- * **Important:** This module requires `@mastra/observability` and `@mastra/core`
9
- * at runtime. Import via the subpath: `@introspection-sdk/introspection-node/mastra`
10
- *
11
- * @example
12
- * ```ts
13
- * import { Mastra } from "@mastra/core/mastra";
14
- * import { IntrospectionMastraExporter } from "@introspection-sdk/introspection-node/mastra";
15
- *
16
- * const mastra = new Mastra({
17
- * agents: { myAgent },
18
- * observability: {
19
- * configs: {
20
- * otel: {
21
- * serviceName: "my-mastra-app",
22
- * exporters: [new IntrospectionMastraExporter()],
23
- * },
24
- * },
25
- * },
26
- * });
27
- * ```
28
- */
29
- import { BaseExporter } from "@mastra/observability";
30
- import type { TracingEvent, InitExporterOptions } from "@mastra/core/observability";
31
- import { type SpanExporter, type IdGenerator } from "@opentelemetry/sdk-trace-base";
32
- /** Advanced options for testing and customization. */
33
- export interface MastraExporterAdvancedOptions {
34
- /** Custom span exporter for testing. */
35
- spanExporter?: SpanExporter;
36
- /** Custom ID generator for testing. */
37
- idGenerator?: IdGenerator;
38
- /** Use SimpleSpanProcessor instead of BatchSpanProcessor. */
39
- useSimpleSpanProcessor?: boolean;
40
- }
41
- /** Configuration for {@link IntrospectionMastraExporter}. */
42
- export interface IntrospectionMastraExporterOptions {
43
- /** Authentication token (env: INTROSPECTION_TOKEN). */
44
- token?: string;
45
- /** Base URL for the API (env: INTROSPECTION_BASE_URL). */
46
- baseUrl?: string;
47
- /** Additional headers to include in requests. */
48
- additionalHeaders?: Record<string, string>;
49
- /** Enable debug logging. */
50
- debug?: boolean;
51
- /** Advanced options for testing. */
52
- advanced?: MastraExporterAdvancedOptions;
53
- }
54
- export declare class IntrospectionMastraExporter extends BaseExporter {
55
- name: string;
56
- private _options;
57
- private _tracerProvider?;
58
- private _tracer?;
59
- private _conversationIds;
60
- private _rootSpans;
61
- constructor(options?: IntrospectionMastraExporterOptions);
62
- /**
63
- * Called by Mastra after the instance is fully configured.
64
- * We defer TracerProvider creation to here so we can use the service name.
65
- */
66
- init(options: InitExporterOptions): void;
67
- private _initProvider;
68
- protected _exportTracingEvent(event: TracingEvent): Promise<void>;
69
- flush(): Promise<void>;
70
- shutdown(): Promise<void>;
71
- private _exportSpan;
72
- /** Ensure a root OTel span exists for this Mastra trace.
73
- * Events arrive in end-order (children first, agent_run last),
74
- * so we create a synthetic root on first encounter. */
75
- private _ensureRoot;
76
- private _createSpan;
77
- private _exportAgentRun;
78
- private _exportModelStep;
79
- private _exportToolCall;
80
- private _getConversationId;
81
- private _convertInput;
82
- private _convertOutput;
83
- private _extractParts;
84
- }
85
- //# sourceMappingURL=mastra-exporter.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"mastra-exporter.d.ts","sourceRoot":"","sources":["../src/mastra-exporter.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;GA2BG;AAEH,OAAO,EAAE,YAAY,EAAE,MAAM,uBAAuB,CAAC;AACrD,OAAO,KAAK,EACV,YAAY,EACZ,mBAAmB,EAEpB,MAAM,4BAA4B,CAAC;AAOpC,OAAO,EAIL,KAAK,YAAY,EACjB,KAAK,WAAW,EACjB,MAAM,+BAA+B,CAAC;AAkBvC,sDAAsD;AACtD,MAAM,WAAW,6BAA6B;IAC5C,wCAAwC;IACxC,YAAY,CAAC,EAAE,YAAY,CAAC;IAC5B,uCAAuC;IACvC,WAAW,CAAC,EAAE,WAAW,CAAC;IAC1B,6DAA6D;IAC7D,sBAAsB,CAAC,EAAE,OAAO,CAAC;CAClC;AAED,6DAA6D;AAC7D,MAAM,WAAW,kCAAkC;IACjD,uDAAuD;IACvD,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,0DAA0D;IAC1D,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,iDAAiD;IACjD,iBAAiB,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IAC3C,4BAA4B;IAC5B,KAAK,CAAC,EAAE,OAAO,CAAC;IAChB,oCAAoC;IACpC,QAAQ,CAAC,EAAE,6BAA6B,CAAC;CAC1C;AAMD,qBAAa,2BAA4B,SAAQ,YAAY;IAC3D,IAAI,SAAmB;IAEvB,OAAO,CAAC,QAAQ,CAAqC;IACrD,OAAO,CAAC,eAAe,CAAC,CAAsB;IAC9C,OAAO,CAAC,OAAO,CAAC,CAA+C;IAC/D,OAAO,CAAC,gBAAgB,CAAkC;IAE1D,OAAO,CAAC,UAAU,CAAoC;gBAE1C,OAAO,GAAE,kCAAuC;IAU5D;;;OAGG;IACH,IAAI,CAAC,OAAO,EAAE,mBAAmB,GAAG,IAAI;IASxC,OAAO,CAAC,aAAa;cA4EL,mBAAmB,CAAC,KAAK,EAAE,YAAY,GAAG,OAAO,CAAC,IAAI,CAAC;IAajE,KAAK,IAAI,OAAO,CAAC,IAAI,CAAC;IAItB,QAAQ,IAAI,OAAO,CAAC,IAAI,CAAC;IAW/B,OAAO,CAAC,WAAW;IAsBnB;;4DAEwD;IACxD,OAAO,CAAC,WAAW;IAQnB,OAAO,CAAC,WAAW;IAiBnB,OAAO,CAAC,eAAe;IAoCvB,OAAO,CAAC,gBAAgB;IA+HxB,OAAO,CAAC,eAAe;IAiCvB,OAAO,CAAC,kBAAkB;IAoB1B,OAAO,CAAC,aAAa;IAiDrB,OAAO,CAAC,cAAc;IA6CtB,OAAO,CAAC,aAAa;CA6DtB"}