@introspection-sdk/introspection-node 0.7.0 → 0.7.2
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.
- package/.turbo/turbo-build.log +1 -1
- package/README.md +24 -111
- package/dist/converters/claude.js +4 -4
- package/dist/converters/claude.js.map +1 -1
- package/dist/converters/gemini.d.ts +1 -1
- package/dist/converters/gemini.js +6 -6
- package/dist/converters/gemini.js.map +1 -1
- package/dist/converters/openai.js +4 -4
- package/dist/converters/openai.js.map +1 -1
- package/dist/converters/openinference.d.ts.map +1 -1
- package/dist/converters/openinference.js +4 -4
- package/dist/converters/openinference.js.map +1 -1
- package/dist/converters/vercel.js +4 -4
- package/dist/converters/vercel.js.map +1 -1
- package/dist/otel/anthropic.d.ts +3 -4
- package/dist/otel/anthropic.d.ts.map +1 -1
- package/dist/otel/anthropic.js +3 -4
- package/dist/otel/anthropic.js.map +1 -1
- package/dist/otel/claude-hooks.d.ts +2 -2
- package/dist/otel/claude-hooks.d.ts.map +1 -1
- package/dist/otel/claude-hooks.js +12 -10
- package/dist/otel/claude-hooks.js.map +1 -1
- package/dist/otel/gemini.d.ts +4 -4
- package/dist/otel/gemini.d.ts.map +1 -1
- package/dist/otel/gemini.js +1 -2
- package/dist/otel/gemini.js.map +1 -1
- package/dist/otel/langchain-handler.d.ts.map +1 -1
- package/dist/otel/langchain-handler.js +7 -4
- package/dist/otel/langchain-handler.js.map +1 -1
- package/dist/otel/logs.d.ts.map +1 -1
- package/dist/otel/logs.js +2 -1
- package/dist/otel/logs.js.map +1 -1
- package/dist/otel/mastra-exporter.d.ts.map +1 -1
- package/dist/otel/mastra-exporter.js +7 -5
- package/dist/otel/mastra-exporter.js.map +1 -1
- package/dist/otel/span-processor.d.ts.map +1 -1
- package/dist/otel/span-processor.js +3 -2
- package/dist/otel/span-processor.js.map +1 -1
- package/dist/otel/tracing-processor.d.ts +1 -1
- package/dist/otel/tracing-processor.d.ts.map +1 -1
- package/dist/otel/tracing-processor.js +13 -7
- package/dist/otel/tracing-processor.js.map +1 -1
- package/package.json +21 -21
- package/src/converters/claude.ts +4 -4
- package/src/converters/gemini.ts +6 -6
- package/src/converters/openai.ts +4 -4
- package/src/converters/openinference.ts +4 -9
- package/src/converters/vercel.ts +4 -4
- package/src/otel/anthropic.ts +9 -15
- package/src/otel/claude-hooks.ts +15 -10
- package/src/otel/gemini.ts +6 -12
- package/src/otel/langchain-handler.ts +11 -4
- package/src/otel/logs.ts +2 -1
- package/src/otel/mastra-exporter.ts +7 -5
- package/src/otel/span-processor.ts +3 -2
- package/src/otel/tracing-processor.ts +13 -7
|
@@ -121,11 +121,6 @@ function extractResponseId(attrs: Attributes): string | undefined {
|
|
|
121
121
|
}
|
|
122
122
|
}
|
|
123
123
|
|
|
124
|
-
/** Local extended tool definition that includes the optional `type` field from OpenInference. */
|
|
125
|
-
interface OIToolDefinition extends ToolDefinition {
|
|
126
|
-
type?: string;
|
|
127
|
-
}
|
|
128
|
-
|
|
129
124
|
function extractSystemInstructions(
|
|
130
125
|
attrs: Attributes,
|
|
131
126
|
): SystemInstruction[] | undefined {
|
|
@@ -160,7 +155,7 @@ function extractSystemInstructions(
|
|
|
160
155
|
function extractToolDefinitions(
|
|
161
156
|
attrs: Attributes,
|
|
162
157
|
): ToolDefinition[] | undefined {
|
|
163
|
-
const tools:
|
|
158
|
+
const tools: ToolDefinition[] = [];
|
|
164
159
|
|
|
165
160
|
for (const [key, value] of Object.entries(attrs)) {
|
|
166
161
|
const match = key.match(/^llm\.tools\.(\d+)\.tool\.json_schema$/);
|
|
@@ -315,7 +310,7 @@ function extractOutputMessages(attrs: Attributes): OutputMessage[] | undefined {
|
|
|
315
310
|
const parsed = JSON.parse(toolArgs) as Record<string, unknown>;
|
|
316
311
|
if (typeof parsed.thinking === "string" && parsed.thinking) {
|
|
317
312
|
const reasoningPart: ReasoningPart = {
|
|
318
|
-
type: "
|
|
313
|
+
type: "reasoning",
|
|
319
314
|
content: parsed.thinking,
|
|
320
315
|
};
|
|
321
316
|
parts.push(reasoningPart);
|
|
@@ -385,8 +380,8 @@ export function convertOpenInferenceToGenAI(
|
|
|
385
380
|
const model = extractModel(attrs);
|
|
386
381
|
if (model) result.requestModel = model;
|
|
387
382
|
|
|
388
|
-
const
|
|
389
|
-
if (
|
|
383
|
+
const providerName = extractSystem(attrs);
|
|
384
|
+
if (providerName) result.providerName = providerName;
|
|
390
385
|
|
|
391
386
|
const responseId = extractResponseId(attrs);
|
|
392
387
|
if (responseId) result.responseId = responseId;
|
package/src/converters/vercel.ts
CHANGED
|
@@ -90,14 +90,14 @@ export function convertVercelAIToGenAI(
|
|
|
90
90
|
result["gen_ai.conversation.id"] = metadataConvId;
|
|
91
91
|
}
|
|
92
92
|
|
|
93
|
-
// gen_ai.request.model and gen_ai.
|
|
93
|
+
// gen_ai.request.model and gen_ai.provider.name from ai.model.*
|
|
94
94
|
const modelId = attrs["ai.model.id"];
|
|
95
95
|
if (typeof modelId === "string" && !attrs["gen_ai.request.model"]) {
|
|
96
96
|
result["gen_ai.request.model"] = modelId;
|
|
97
97
|
}
|
|
98
98
|
const modelProvider = attrs["ai.model.provider"];
|
|
99
|
-
if (typeof modelProvider === "string" && !attrs["gen_ai.
|
|
100
|
-
result["gen_ai.
|
|
99
|
+
if (typeof modelProvider === "string" && !attrs["gen_ai.provider.name"]) {
|
|
100
|
+
result["gen_ai.provider.name"] = modelProvider;
|
|
101
101
|
}
|
|
102
102
|
|
|
103
103
|
// Vercel AI SDK stores prompt data in two formats:
|
|
@@ -141,7 +141,7 @@ export function convertVercelAIToGenAI(
|
|
|
141
141
|
if (typeof responseText === "string" && responseText) {
|
|
142
142
|
const parts: GenAIPart[] = [];
|
|
143
143
|
if (typeof responseReasoning === "string" && responseReasoning) {
|
|
144
|
-
parts.push({ type: "
|
|
144
|
+
parts.push({ type: "reasoning", content: responseReasoning });
|
|
145
145
|
}
|
|
146
146
|
parts.push({ type: "text", content: responseText });
|
|
147
147
|
result["gen_ai.output.messages"] = JSON.stringify([
|
package/src/otel/anthropic.ts
CHANGED
|
@@ -32,8 +32,7 @@ import {
|
|
|
32
32
|
SpanKind,
|
|
33
33
|
SpanStatusCode,
|
|
34
34
|
} from "@opentelemetry/api";
|
|
35
|
-
import type { Tracer, Span } from "@opentelemetry/api";
|
|
36
|
-
import type { BasicTracerProvider } from "@opentelemetry/sdk-trace-base";
|
|
35
|
+
import type { Tracer, Span, TracerProvider } from "@opentelemetry/api";
|
|
37
36
|
|
|
38
37
|
// ---------------------------------------------------------------------------
|
|
39
38
|
// Converters
|
|
@@ -51,8 +50,8 @@ function blockToParts(block: Record<string, unknown>): MessagePart[] {
|
|
|
51
50
|
|
|
52
51
|
if (bt === "thinking") {
|
|
53
52
|
const part: ReasoningPart = {
|
|
54
|
-
type: "
|
|
55
|
-
content: (block.thinking as string) ||
|
|
53
|
+
type: "reasoning",
|
|
54
|
+
content: (block.thinking as string) || REDACTED_THINKING_CONTENT,
|
|
56
55
|
signature: (block.signature as string) || undefined,
|
|
57
56
|
provider_name: "anthropic",
|
|
58
57
|
};
|
|
@@ -62,11 +61,11 @@ function blockToParts(block: Record<string, unknown>): MessagePart[] {
|
|
|
62
61
|
if (bt === "redacted_thinking") {
|
|
63
62
|
return [
|
|
64
63
|
{
|
|
65
|
-
type: "
|
|
64
|
+
type: "reasoning",
|
|
66
65
|
content: REDACTED_THINKING_CONTENT,
|
|
67
66
|
signature: (block.data as string) || undefined,
|
|
68
67
|
provider_name: "anthropic",
|
|
69
|
-
}
|
|
68
|
+
},
|
|
70
69
|
];
|
|
71
70
|
}
|
|
72
71
|
|
|
@@ -169,7 +168,6 @@ function startSpan(
|
|
|
169
168
|
const span = tracer.startSpan("chat", {
|
|
170
169
|
kind: SpanKind.CLIENT,
|
|
171
170
|
attributes: {
|
|
172
|
-
"gen_ai.system": "anthropic",
|
|
173
171
|
"gen_ai.provider.name": "anthropic",
|
|
174
172
|
"gen_ai.operation.name": "chat",
|
|
175
173
|
"gen_ai.request.model": model,
|
|
@@ -535,7 +533,7 @@ export class AnthropicInstrumentor {
|
|
|
535
533
|
private conversationId: string | undefined;
|
|
536
534
|
|
|
537
535
|
instrument(opts: {
|
|
538
|
-
tracerProvider?:
|
|
536
|
+
tracerProvider?: TracerProvider;
|
|
539
537
|
/** The Anthropic client instance to instrument. */
|
|
540
538
|
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
541
539
|
client: any;
|
|
@@ -557,9 +555,7 @@ export class AnthropicInstrumentor {
|
|
|
557
555
|
this.conversationId = opts.conversationId ?? crypto.randomUUID();
|
|
558
556
|
|
|
559
557
|
const provider = opts.tracerProvider ?? trace.getTracerProvider();
|
|
560
|
-
this.tracer =
|
|
561
|
-
"introspection-anthropic",
|
|
562
|
-
);
|
|
558
|
+
this.tracer = provider.getTracer("introspection-anthropic");
|
|
563
559
|
|
|
564
560
|
const origCreate = client.messages.create.bind(client.messages);
|
|
565
561
|
this.patchedClients.push({ client, originalCreate: origCreate });
|
|
@@ -582,7 +578,7 @@ export class AnthropicInstrumentor {
|
|
|
582
578
|
instrumentClass(opts: {
|
|
583
579
|
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
584
580
|
anthropic: any;
|
|
585
|
-
tracerProvider?:
|
|
581
|
+
tracerProvider?: TracerProvider;
|
|
586
582
|
conversationId?: string;
|
|
587
583
|
}): void {
|
|
588
584
|
const Messages = opts.anthropic?.Messages;
|
|
@@ -596,9 +592,7 @@ export class AnthropicInstrumentor {
|
|
|
596
592
|
|
|
597
593
|
this.conversationId = opts.conversationId ?? crypto.randomUUID();
|
|
598
594
|
const provider = opts.tracerProvider ?? trace.getTracerProvider();
|
|
599
|
-
this.tracer =
|
|
600
|
-
"introspection-anthropic",
|
|
601
|
-
);
|
|
595
|
+
this.tracer = provider.getTracer("introspection-anthropic");
|
|
602
596
|
|
|
603
597
|
const origCreate = proto.create;
|
|
604
598
|
const patched = buildTracedCreate(
|
package/src/otel/claude-hooks.ts
CHANGED
|
@@ -295,8 +295,8 @@ export interface IntrospectionClaudeHooksOptions {
|
|
|
295
295
|
* Provides instrumented hooks for Claude Agent SDK.
|
|
296
296
|
*
|
|
297
297
|
* Creates OpenTelemetry spans with gen_ai.* semantic convention attributes:
|
|
298
|
-
* - Session spans: gen_ai.
|
|
299
|
-
* - Tool spans: gen_ai.tool.name, gen_ai.tool.
|
|
298
|
+
* - Session spans: gen_ai.provider.name, gen_ai.request.model
|
|
299
|
+
* - Tool spans: gen_ai.tool.name, gen_ai.tool.call.arguments, gen_ai.tool.call.result
|
|
300
300
|
* - Subagent spans: gen_ai.agent.name
|
|
301
301
|
*
|
|
302
302
|
* Usage tracking is captured from streamed messages via recordUsage().
|
|
@@ -689,7 +689,7 @@ export class IntrospectionClaudeHooks {
|
|
|
689
689
|
logger.debug(`Starting session span from init message: ${sessionId}`);
|
|
690
690
|
const ids = this._resolveIdentity(sessionId);
|
|
691
691
|
const attrs: Attributes = {
|
|
692
|
-
"gen_ai.
|
|
692
|
+
"gen_ai.provider.name": "anthropic",
|
|
693
693
|
"gen_ai.operation.name": "chat",
|
|
694
694
|
"gen_ai.agent.name": ids.agentName,
|
|
695
695
|
"gen_ai.conversation.id": ids.conversationId,
|
|
@@ -835,7 +835,7 @@ export class IntrospectionClaudeHooks {
|
|
|
835
835
|
// when the caller wrapped the query in withAgent() / withConversation().
|
|
836
836
|
const ids = this._resolveIdentity(sessionInput.session_id);
|
|
837
837
|
const attrs: Attributes = {
|
|
838
|
-
"gen_ai.
|
|
838
|
+
"gen_ai.provider.name": "anthropic",
|
|
839
839
|
"gen_ai.operation.name": "chat",
|
|
840
840
|
"gen_ai.agent.name": ids.agentName,
|
|
841
841
|
"gen_ai.conversation.id": ids.conversationId,
|
|
@@ -952,11 +952,14 @@ export class IntrospectionClaudeHooks {
|
|
|
952
952
|
: undefined;
|
|
953
953
|
|
|
954
954
|
const span = this._tracer.startSpan(
|
|
955
|
-
`
|
|
955
|
+
`execute_tool ${toolInput.tool_name}`,
|
|
956
956
|
{
|
|
957
957
|
kind: SpanKind.INTERNAL,
|
|
958
958
|
attributes: {
|
|
959
|
+
"gen_ai.operation.name": "execute_tool",
|
|
959
960
|
"gen_ai.tool.name": toolInput.tool_name,
|
|
961
|
+
"gen_ai.tool.type": "function",
|
|
962
|
+
"gen_ai.tool.call.id": toolInput.tool_use_id,
|
|
960
963
|
"claude.session_id": toolInput.session_id,
|
|
961
964
|
"claude.tool_use_id": toolInput.tool_use_id,
|
|
962
965
|
},
|
|
@@ -967,11 +970,14 @@ export class IntrospectionClaudeHooks {
|
|
|
967
970
|
if (toolInput.tool_input) {
|
|
968
971
|
try {
|
|
969
972
|
span.setAttribute(
|
|
970
|
-
"gen_ai.tool.
|
|
973
|
+
"gen_ai.tool.call.arguments",
|
|
971
974
|
JSON.stringify(toolInput.tool_input),
|
|
972
975
|
);
|
|
973
976
|
} catch {
|
|
974
|
-
span.setAttribute(
|
|
977
|
+
span.setAttribute(
|
|
978
|
+
"gen_ai.tool.call.arguments",
|
|
979
|
+
String(toolInput.tool_input),
|
|
980
|
+
);
|
|
975
981
|
}
|
|
976
982
|
}
|
|
977
983
|
|
|
@@ -998,17 +1004,16 @@ export class IntrospectionClaudeHooks {
|
|
|
998
1004
|
if (toolInput.tool_response !== undefined) {
|
|
999
1005
|
try {
|
|
1000
1006
|
span.setAttribute(
|
|
1001
|
-
"gen_ai.tool.
|
|
1007
|
+
"gen_ai.tool.call.result",
|
|
1002
1008
|
JSON.stringify(toolInput.tool_response),
|
|
1003
1009
|
);
|
|
1004
1010
|
} catch {
|
|
1005
1011
|
span.setAttribute(
|
|
1006
|
-
"gen_ai.tool.
|
|
1012
|
+
"gen_ai.tool.call.result",
|
|
1007
1013
|
String(toolInput.tool_response),
|
|
1008
1014
|
);
|
|
1009
1015
|
}
|
|
1010
1016
|
}
|
|
1011
|
-
span.setStatus({ code: SpanStatusCode.OK });
|
|
1012
1017
|
span.end();
|
|
1013
1018
|
this._toolSpans.delete(toolInput.tool_use_id);
|
|
1014
1019
|
}
|
package/src/otel/gemini.ts
CHANGED
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
* Lightweight Google Gemini (`@google/genai`) instrumentor for Introspection SDK.
|
|
3
3
|
*
|
|
4
4
|
* Captures the full Gemini response including per-part `thoughtSignature`
|
|
5
|
-
* payloads (Gemini 3.x extended thinking) as gen_ai `
|
|
5
|
+
* payloads (Gemini 3.x extended thinking) as gen_ai `reasoning` parts with
|
|
6
6
|
* `signature` set — mirroring how the {@link AnthropicInstrumentor} captures
|
|
7
7
|
* Anthropic thinking blocks.
|
|
8
8
|
*
|
|
@@ -23,8 +23,7 @@
|
|
|
23
23
|
*/
|
|
24
24
|
|
|
25
25
|
import { trace, SpanKind, SpanStatusCode } from "@opentelemetry/api";
|
|
26
|
-
import type { Tracer, Span } from "@opentelemetry/api";
|
|
27
|
-
import type { BasicTracerProvider } from "@opentelemetry/sdk-trace-base";
|
|
26
|
+
import type { Tracer, Span, TracerProvider } from "@opentelemetry/api";
|
|
28
27
|
|
|
29
28
|
import type { InputMessage, OutputMessage } from "@introspection-sdk/types";
|
|
30
29
|
import { providerCostAttributes } from "@introspection-sdk/types";
|
|
@@ -64,7 +63,6 @@ function startSpan(
|
|
|
64
63
|
return tracer.startSpan("chat", {
|
|
65
64
|
kind: SpanKind.CLIENT,
|
|
66
65
|
attributes: {
|
|
67
|
-
"gen_ai.system": GEMINI_PROVIDER_NAME,
|
|
68
66
|
"gen_ai.provider.name": GEMINI_PROVIDER_NAME,
|
|
69
67
|
"gen_ai.operation.name": "chat",
|
|
70
68
|
"gen_ai.request.model": model,
|
|
@@ -374,7 +372,7 @@ export class GeminiInstrumentor {
|
|
|
374
372
|
private conversationId: string | undefined;
|
|
375
373
|
|
|
376
374
|
instrument(opts: {
|
|
377
|
-
tracerProvider?:
|
|
375
|
+
tracerProvider?: TracerProvider;
|
|
378
376
|
/** A `@google/genai` `GoogleGenAI` client instance. */
|
|
379
377
|
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
380
378
|
client: any;
|
|
@@ -394,9 +392,7 @@ export class GeminiInstrumentor {
|
|
|
394
392
|
this.conversationId = opts.conversationId ?? crypto.randomUUID();
|
|
395
393
|
|
|
396
394
|
const provider = opts.tracerProvider ?? trace.getTracerProvider();
|
|
397
|
-
this.tracer =
|
|
398
|
-
"introspection-gemini",
|
|
399
|
-
);
|
|
395
|
+
this.tracer = provider.getTracer("introspection-gemini");
|
|
400
396
|
const tracer = this.tracer;
|
|
401
397
|
const conversationId = this.conversationId;
|
|
402
398
|
|
|
@@ -436,7 +432,7 @@ export class GeminiInstrumentor {
|
|
|
436
432
|
instrumentClass(opts: {
|
|
437
433
|
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
438
434
|
genai: any;
|
|
439
|
-
tracerProvider?:
|
|
435
|
+
tracerProvider?: TracerProvider;
|
|
440
436
|
conversationId?: string;
|
|
441
437
|
}): void {
|
|
442
438
|
const proto = opts.genai?.Models?.prototype;
|
|
@@ -449,9 +445,7 @@ export class GeminiInstrumentor {
|
|
|
449
445
|
|
|
450
446
|
this.conversationId = opts.conversationId ?? crypto.randomUUID();
|
|
451
447
|
const provider = opts.tracerProvider ?? trace.getTracerProvider();
|
|
452
|
-
this.tracer =
|
|
453
|
-
"introspection-gemini",
|
|
454
|
-
);
|
|
448
|
+
this.tracer = provider.getTracer("introspection-gemini");
|
|
455
449
|
const conversationId = this.conversationId;
|
|
456
450
|
|
|
457
451
|
const origGenerate = proto.generateContentInternal;
|
|
@@ -317,7 +317,7 @@ export class IntrospectionCallbackHandler extends BaseCallbackHandler {
|
|
|
317
317
|
|
|
318
318
|
const provider = this._extractProvider(llm);
|
|
319
319
|
if (provider) {
|
|
320
|
-
otelSpan.setAttribute("gen_ai.
|
|
320
|
+
otelSpan.setAttribute("gen_ai.provider.name", provider);
|
|
321
321
|
}
|
|
322
322
|
|
|
323
323
|
const invocationParams = extraParams?.["invocation_params"] as
|
|
@@ -571,15 +571,22 @@ export class IntrospectionCallbackHandler extends BaseCallbackHandler {
|
|
|
571
571
|
const toolName =
|
|
572
572
|
runName || tool?.name || tool?.id?.[tool.id.length - 1] || "tool";
|
|
573
573
|
|
|
574
|
-
const otelSpan = this._createChildSpan(
|
|
574
|
+
const otelSpan = this._createChildSpan(
|
|
575
|
+
`execute_tool ${toolName}`,
|
|
576
|
+
runId,
|
|
577
|
+
parentRunId,
|
|
578
|
+
);
|
|
575
579
|
this._spans.set(runId, otelSpan);
|
|
576
580
|
|
|
577
581
|
const conversationId = this._getConversationId(metadata);
|
|
578
582
|
this._setRootConversationId(conversationId, runId, parentRunId);
|
|
579
583
|
|
|
584
|
+
otelSpan.setAttribute("gen_ai.operation.name", "execute_tool");
|
|
580
585
|
otelSpan.setAttribute("gen_ai.tool.name", toolName);
|
|
586
|
+
otelSpan.setAttribute("gen_ai.tool.type", "function");
|
|
587
|
+
otelSpan.setAttribute("gen_ai.tool.call.id", runId);
|
|
581
588
|
otelSpan.setAttribute("openinference.span.kind", "TOOL");
|
|
582
|
-
otelSpan.setAttribute("gen_ai.tool.
|
|
589
|
+
otelSpan.setAttribute("gen_ai.tool.call.arguments", input);
|
|
583
590
|
otelSpan.setAttribute("gen_ai.conversation.id", conversationId);
|
|
584
591
|
}
|
|
585
592
|
|
|
@@ -591,7 +598,7 @@ export class IntrospectionCallbackHandler extends BaseCallbackHandler {
|
|
|
591
598
|
|
|
592
599
|
if (output != null) {
|
|
593
600
|
otelSpan.setAttribute(
|
|
594
|
-
"gen_ai.tool.
|
|
601
|
+
"gen_ai.tool.call.result",
|
|
595
602
|
typeof output === "string" ? output : JSON.stringify(output),
|
|
596
603
|
);
|
|
597
604
|
}
|
package/src/otel/logs.ts
CHANGED
|
@@ -113,7 +113,8 @@ export class IntrospectionLogs {
|
|
|
113
113
|
}),
|
|
114
114
|
);
|
|
115
115
|
|
|
116
|
-
const processor = new BatchLogRecordProcessor(
|
|
116
|
+
const processor = new BatchLogRecordProcessor({
|
|
117
|
+
exporter,
|
|
117
118
|
maxQueueSize: options.maxBatchSize ?? 100,
|
|
118
119
|
scheduledDelayMillis: options.flushInterval ?? 5000,
|
|
119
120
|
});
|
|
@@ -358,7 +358,7 @@ export class IntrospectionMastraExporter extends BaseExporter {
|
|
|
358
358
|
otelSpan.setAttribute("openinference.span.kind", "LLM");
|
|
359
359
|
|
|
360
360
|
if (model) otelSpan.setAttribute("gen_ai.request.model", model);
|
|
361
|
-
if (provider) otelSpan.setAttribute("gen_ai.
|
|
361
|
+
if (provider) otelSpan.setAttribute("gen_ai.provider.name", provider);
|
|
362
362
|
if (responseModel)
|
|
363
363
|
otelSpan.setAttribute("gen_ai.response.model", responseModel);
|
|
364
364
|
if (responseId) otelSpan.setAttribute("gen_ai.response.id", responseId);
|
|
@@ -481,14 +481,16 @@ export class IntrospectionMastraExporter extends BaseExporter {
|
|
|
481
481
|
const conversationId = this._getConversationId(span);
|
|
482
482
|
const toolName = span.entityName || span.name || "tool";
|
|
483
483
|
|
|
484
|
-
const otelSpan = this._createSpan(span, toolName);
|
|
484
|
+
const otelSpan = this._createSpan(span, `execute_tool ${toolName}`);
|
|
485
|
+
otelSpan.setAttribute("gen_ai.operation.name", "execute_tool");
|
|
485
486
|
otelSpan.setAttribute("gen_ai.tool.name", toolName);
|
|
487
|
+
otelSpan.setAttribute("gen_ai.tool.type", "function");
|
|
486
488
|
otelSpan.setAttribute("gen_ai.conversation.id", conversationId);
|
|
487
489
|
otelSpan.setAttribute("openinference.span.kind", "TOOL");
|
|
488
490
|
|
|
489
491
|
if (span.input != null) {
|
|
490
492
|
otelSpan.setAttribute(
|
|
491
|
-
"gen_ai.tool.
|
|
493
|
+
"gen_ai.tool.call.arguments",
|
|
492
494
|
typeof span.input === "string"
|
|
493
495
|
? span.input
|
|
494
496
|
: JSON.stringify(span.input),
|
|
@@ -496,7 +498,7 @@ export class IntrospectionMastraExporter extends BaseExporter {
|
|
|
496
498
|
}
|
|
497
499
|
if (span.output != null) {
|
|
498
500
|
otelSpan.setAttribute(
|
|
499
|
-
"gen_ai.tool.
|
|
501
|
+
"gen_ai.tool.call.result",
|
|
500
502
|
typeof span.output === "string"
|
|
501
503
|
? span.output
|
|
502
504
|
: JSON.stringify(span.output),
|
|
@@ -600,7 +602,7 @@ export class IntrospectionMastraExporter extends BaseExporter {
|
|
|
600
602
|
if (Array.isArray(out.reasoning)) {
|
|
601
603
|
for (const r of out.reasoning as Record<string, unknown>[]) {
|
|
602
604
|
const text = (r.text || r.content || "") as string;
|
|
603
|
-
if (text) parts.push({ type: "
|
|
605
|
+
if (text) parts.push({ type: "reasoning", content: text });
|
|
604
606
|
}
|
|
605
607
|
}
|
|
606
608
|
|
|
@@ -308,7 +308,7 @@ export class IntrospectionSpanProcessor implements SpanProcessor {
|
|
|
308
308
|
const hasGenAi =
|
|
309
309
|
isOI ||
|
|
310
310
|
isVercel ||
|
|
311
|
-
span.attributes["gen_ai.
|
|
311
|
+
span.attributes["gen_ai.provider.name"] != null ||
|
|
312
312
|
span.attributes["gen_ai.operation.name"] != null ||
|
|
313
313
|
span.attributes["gen_ai.request.model"] != null ||
|
|
314
314
|
span.attributes["gen_ai.input.messages"] != null ||
|
|
@@ -333,7 +333,7 @@ export class IntrospectionSpanProcessor implements SpanProcessor {
|
|
|
333
333
|
if (
|
|
334
334
|
key === "gen_ai.output.messages" &&
|
|
335
335
|
typeof value === "string" &&
|
|
336
|
-
value.includes('"
|
|
336
|
+
value.includes('"reasoning"')
|
|
337
337
|
) {
|
|
338
338
|
attrs[key] = value;
|
|
339
339
|
} else if (attrs[key] === undefined) {
|
|
@@ -351,6 +351,7 @@ export class IntrospectionSpanProcessor implements SpanProcessor {
|
|
|
351
351
|
} else {
|
|
352
352
|
attrs = { ...span.attributes };
|
|
353
353
|
}
|
|
354
|
+
delete attrs["gen_ai.system"];
|
|
354
355
|
|
|
355
356
|
// Read baggage from active context
|
|
356
357
|
const baggage = propagation.getBaggage(otelContext.active());
|
|
@@ -97,7 +97,7 @@ export interface IntrospectionTracingProcessorOptions {
|
|
|
97
97
|
*
|
|
98
98
|
* Extracts OTel Gen AI semantic convention attributes from span data:
|
|
99
99
|
* - Agent spans: `gen_ai.agent.name`, `gen_ai.tool.definitions`, `gen_ai.agent.handoffs`
|
|
100
|
-
* - Function spans: `gen_ai.tool.name`, `gen_ai.tool.
|
|
100
|
+
* - Function spans: `gen_ai.tool.name`, `gen_ai.tool.call.arguments`, `gen_ai.tool.call.result`
|
|
101
101
|
* - Response spans: `gen_ai.input/output.messages`, `gen_ai.usage.*`, `gen_ai.request.model`
|
|
102
102
|
* - Generation spans: `gen_ai.request.model`, `gen_ai.usage.*`
|
|
103
103
|
* - Handoff spans: `gen_ai.handoff.from_agent`, `gen_ai.handoff.to_agent`
|
|
@@ -336,12 +336,15 @@ export class IntrospectionTracingProcessor implements TracingProcessor {
|
|
|
336
336
|
*/
|
|
337
337
|
private _processAgentSpan(otelSpan: OtelSpan, spanData: AgentSpanData): void {
|
|
338
338
|
otelSpan.setAttribute("gen_ai.agent.name", spanData.name);
|
|
339
|
-
otelSpan.setAttribute("gen_ai.
|
|
339
|
+
otelSpan.setAttribute("gen_ai.provider.name", "openai");
|
|
340
340
|
otelSpan.setAttribute("openinference.span.kind", "AGENT");
|
|
341
341
|
|
|
342
342
|
if (spanData.tools) {
|
|
343
343
|
// Wrap tool names as objects for ClickHouse Array(JSON) compatibility
|
|
344
|
-
const toolDefs = spanData.tools.map((t: string) => ({
|
|
344
|
+
const toolDefs = spanData.tools.map((t: string) => ({
|
|
345
|
+
type: "function",
|
|
346
|
+
name: t,
|
|
347
|
+
}));
|
|
345
348
|
otelSpan.setAttribute(
|
|
346
349
|
"gen_ai.tool.definitions",
|
|
347
350
|
JSON.stringify(toolDefs),
|
|
@@ -367,15 +370,18 @@ export class IntrospectionTracingProcessor implements TracingProcessor {
|
|
|
367
370
|
otelSpan: OtelSpan,
|
|
368
371
|
spanData: FunctionSpanData,
|
|
369
372
|
): void {
|
|
373
|
+
otelSpan.updateName(`execute_tool ${spanData.name}`);
|
|
374
|
+
otelSpan.setAttribute("gen_ai.operation.name", "execute_tool");
|
|
370
375
|
otelSpan.setAttribute("gen_ai.tool.name", spanData.name);
|
|
376
|
+
otelSpan.setAttribute("gen_ai.tool.type", "function");
|
|
371
377
|
otelSpan.setAttribute("openinference.span.kind", "TOOL");
|
|
372
378
|
|
|
373
379
|
if (spanData.input) {
|
|
374
|
-
otelSpan.setAttribute("gen_ai.tool.
|
|
380
|
+
otelSpan.setAttribute("gen_ai.tool.call.arguments", spanData.input);
|
|
375
381
|
}
|
|
376
382
|
|
|
377
383
|
if (spanData.output) {
|
|
378
|
-
otelSpan.setAttribute("gen_ai.tool.
|
|
384
|
+
otelSpan.setAttribute("gen_ai.tool.call.result", String(spanData.output));
|
|
379
385
|
}
|
|
380
386
|
}
|
|
381
387
|
|
|
@@ -388,7 +394,7 @@ export class IntrospectionTracingProcessor implements TracingProcessor {
|
|
|
388
394
|
spanData: ResponseSpanData,
|
|
389
395
|
): void {
|
|
390
396
|
otelSpan.setAttribute("gen_ai.operation.name", "chat");
|
|
391
|
-
otelSpan.setAttribute("gen_ai.
|
|
397
|
+
otelSpan.setAttribute("gen_ai.provider.name", "openai");
|
|
392
398
|
otelSpan.setAttribute("openinference.span.kind", "LLM");
|
|
393
399
|
|
|
394
400
|
// Response ID (from span_data directly)
|
|
@@ -494,7 +500,7 @@ export class IntrospectionTracingProcessor implements TracingProcessor {
|
|
|
494
500
|
spanData: GenerationSpanData,
|
|
495
501
|
): void {
|
|
496
502
|
otelSpan.setAttribute("gen_ai.operation.name", "chat");
|
|
497
|
-
otelSpan.setAttribute("gen_ai.
|
|
503
|
+
otelSpan.setAttribute("gen_ai.provider.name", "openai");
|
|
498
504
|
otelSpan.setAttribute("openinference.span.kind", "LLM");
|
|
499
505
|
|
|
500
506
|
if (spanData.model) {
|