@introspection-sdk/introspection-pi 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/README.md +23 -2
- package/dist/attributes.d.ts +21 -3
- package/dist/attributes.d.ts.map +1 -1
- package/dist/attributes.js +108 -8
- package/dist/attributes.js.map +1 -1
- package/dist/convert.d.ts +8 -0
- package/dist/convert.d.ts.map +1 -1
- package/dist/convert.js +44 -8
- package/dist/convert.js.map +1 -1
- package/dist/error-type.d.ts +16 -0
- package/dist/error-type.d.ts.map +1 -0
- package/dist/error-type.js +32 -0
- package/dist/error-type.js.map +1 -0
- package/dist/index.d.ts +6 -3
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +7 -3
- package/dist/index.js.map +1 -1
- package/dist/instrument-agent.d.ts +35 -6
- package/dist/instrument-agent.d.ts.map +1 -1
- package/dist/instrument-agent.js +128 -21
- package/dist/instrument-agent.js.map +1 -1
- package/dist/instrument-stream.d.ts +11 -3
- package/dist/instrument-stream.d.ts.map +1 -1
- package/dist/instrument-stream.js +112 -25
- package/dist/instrument-stream.js.map +1 -1
- package/dist/metrics.d.ts +26 -0
- package/dist/metrics.d.ts.map +1 -0
- package/dist/metrics.js +64 -0
- package/dist/metrics.js.map +1 -0
- package/package.json +4 -4
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* Subscribe to a pi-agent {@link Agent} to emit `execute_tool` spans for every
|
|
3
|
-
* tool call the loop runs.
|
|
3
|
+
* tool call the loop runs, and (optionally) one `invoke_agent` span per run.
|
|
4
4
|
*/
|
|
5
|
-
import { type Attributes, type Context as OtelContext, type Tracer } from "@opentelemetry/api";
|
|
5
|
+
import { type Attributes, type Context as OtelContext, type Meter, type Tracer } from "@opentelemetry/api";
|
|
6
6
|
import type { Agent, AgentEvent } from "@earendil-works/pi-agent-core";
|
|
7
7
|
import { type AgentMeta } from "./attributes.js";
|
|
8
8
|
export interface InstrumentAgentOptions {
|
|
@@ -10,9 +10,31 @@ export interface InstrumentAgentOptions {
|
|
|
10
10
|
tracer: Tracer;
|
|
11
11
|
/** Required metadata stamped onto every execute_tool span. */
|
|
12
12
|
meta: AgentMeta;
|
|
13
|
+
/**
|
|
14
|
+
* Optional meter. When set, the wrapper also records
|
|
15
|
+
* `gen_ai.execute_tool.duration` per tool call and (when `runSpans` is
|
|
16
|
+
* enabled) `gen_ai.invoke_agent.duration` per run.
|
|
17
|
+
*/
|
|
18
|
+
meter?: Meter;
|
|
19
|
+
/**
|
|
20
|
+
* Emit one `invoke_agent {agent.name}` span per agent run
|
|
21
|
+
* (`agent_start` → `agent_end`), carrying conversation/agent identity
|
|
22
|
+
* and the final finish reason. Usage attributes stay on the chat spans
|
|
23
|
+
* only, so aggregations that sum a whole trace don't double-count.
|
|
24
|
+
*
|
|
25
|
+
* Off by default: hosts that already create their own turn/run spans
|
|
26
|
+
* (and parent chat spans onto them via `getParentContext`) would get
|
|
27
|
+
* duplicate run spans otherwise. When enabled, wire the chat spans under
|
|
28
|
+
* the run span with
|
|
29
|
+
* `instrumentStream(fn, { getParentContext: () => handle.getRunContext() })`;
|
|
30
|
+
* tool spans parent onto the run span automatically unless
|
|
31
|
+
* `getParentContext` is provided.
|
|
32
|
+
*/
|
|
33
|
+
runSpans?: boolean;
|
|
13
34
|
/**
|
|
14
35
|
* Returns the parent OTel context for the next tool span. If undefined or
|
|
15
|
-
* returns null,
|
|
36
|
+
* returns null, the active run span (when `runSpans` is enabled) or
|
|
37
|
+
* `context.active()` is used at the time the start event fires.
|
|
16
38
|
*/
|
|
17
39
|
getParentContext?: () => OtelContext | null | undefined;
|
|
18
40
|
/**
|
|
@@ -26,13 +48,20 @@ export interface InstrumentAgentOptions {
|
|
|
26
48
|
spanName?: (toolName: string) => string;
|
|
27
49
|
}
|
|
28
50
|
export interface AgentInstrumentation {
|
|
29
|
-
/** Stop subscribing and finalize any
|
|
51
|
+
/** Stop subscribing and finalize any spans still open. */
|
|
30
52
|
stop: () => void;
|
|
53
|
+
/**
|
|
54
|
+
* OTel context of the active `invoke_agent` span, when `runSpans` is
|
|
55
|
+
* enabled and a run is in flight. Pass to `instrumentStream`'s
|
|
56
|
+
* `getParentContext` so chat spans nest under the run span.
|
|
57
|
+
*/
|
|
58
|
+
getRunContext: () => OtelContext | undefined;
|
|
31
59
|
}
|
|
32
60
|
/**
|
|
33
61
|
* Subscribe to {@link Agent.subscribe} and emit one `execute_tool ${name}`
|
|
34
|
-
* span per tool call
|
|
35
|
-
* finalizes any still-open
|
|
62
|
+
* span per tool call (plus one `invoke_agent` span per run when enabled).
|
|
63
|
+
* Returns a handle whose `stop()` unsubscribes and finalizes any still-open
|
|
64
|
+
* spans.
|
|
36
65
|
*
|
|
37
66
|
* Tool call IDs are assumed unique per agent run; concurrent tool execution
|
|
38
67
|
* (`ToolExecutionMode = "parallel"`) is supported because each id keys its
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"instrument-agent.d.ts","sourceRoot":"","sources":["../src/instrument-agent.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,
|
|
1
|
+
{"version":3,"file":"instrument-agent.d.ts","sourceRoot":"","sources":["../src/instrument-agent.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,EAKL,KAAK,UAAU,EACf,KAAK,OAAO,IAAI,WAAW,EAC3B,KAAK,KAAK,EAEV,KAAK,MAAM,EACZ,MAAM,oBAAoB,CAAC;AAC5B,OAAO,KAAK,EAAE,KAAK,EAAE,UAAU,EAAE,MAAM,+BAA+B,CAAC;AAMvE,OAAO,EAIL,KAAK,SAAS,EACf,MAAM,iBAAiB,CAAC;AAKzB,MAAM,WAAW,sBAAsB;IACrC,iDAAiD;IACjD,MAAM,EAAE,MAAM,CAAC;IACf,8DAA8D;IAC9D,IAAI,EAAE,SAAS,CAAC;IAChB;;;;OAIG;IACH,KAAK,CAAC,EAAE,KAAK,CAAC;IACd;;;;;;;;;;;;;OAaG;IACH,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB;;;;OAIG;IACH,gBAAgB,CAAC,EAAE,MAAM,WAAW,GAAG,IAAI,GAAG,SAAS,CAAC;IACxD;;;OAGG;IACH,eAAe,CAAC,EAAE,CAChB,KAAK,EAAE,OAAO,CAAC,UAAU,EAAE;QAAE,IAAI,EAAE,sBAAsB,CAAA;KAAE,CAAC,KACzD,UAAU,CAAC;IAChB,8CAA8C;IAC9C,QAAQ,CAAC,EAAE,CAAC,QAAQ,EAAE,MAAM,KAAK,MAAM,CAAC;CACzC;AAED,MAAM,WAAW,oBAAoB;IACnC,0DAA0D;IAC1D,IAAI,EAAE,MAAM,IAAI,CAAC;IACjB;;;;OAIG;IACH,aAAa,EAAE,MAAM,WAAW,GAAG,SAAS,CAAC;CAC9C;AAeD;;;;;;;;;GASG;AACH,wBAAgB,eAAe,CAC7B,KAAK,EAAE,KAAK,EACZ,IAAI,EAAE,sBAAsB,GAC3B,oBAAoB,CAiCtB"}
|
package/dist/instrument-agent.js
CHANGED
|
@@ -1,14 +1,18 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* Subscribe to a pi-agent {@link Agent} to emit `execute_tool` spans for every
|
|
3
|
-
* tool call the loop runs.
|
|
3
|
+
* tool call the loop runs, and (optionally) one `invoke_agent` span per run.
|
|
4
4
|
*/
|
|
5
|
-
import { context as otelContext, SpanKind, SpanStatusCode, } from "@opentelemetry/api";
|
|
6
|
-
import { GenAiSpanName, IntrospectionAttr } from "@introspection-sdk/types";
|
|
7
|
-
import { executeToolAttributes, executeToolResultAttribute, } from "./attributes.js";
|
|
5
|
+
import { context as otelContext, SpanKind, SpanStatusCode, trace, } from "@opentelemetry/api";
|
|
6
|
+
import { GenAi, GenAiSpanName, IntrospectionAttr, } from "@introspection-sdk/types";
|
|
7
|
+
import { executeToolAttributes, executeToolResultAttribute, invokeAgentAttributes, } from "./attributes.js";
|
|
8
|
+
import { semconvFinishReason } from "./convert.js";
|
|
9
|
+
import { classifyErrorType } from "./error-type.js";
|
|
10
|
+
import { genAiMetrics } from "./metrics.js";
|
|
8
11
|
/**
|
|
9
12
|
* Subscribe to {@link Agent.subscribe} and emit one `execute_tool ${name}`
|
|
10
|
-
* span per tool call
|
|
11
|
-
* finalizes any still-open
|
|
13
|
+
* span per tool call (plus one `invoke_agent` span per run when enabled).
|
|
14
|
+
* Returns a handle whose `stop()` unsubscribes and finalizes any still-open
|
|
15
|
+
* spans.
|
|
12
16
|
*
|
|
13
17
|
* Tool call IDs are assumed unique per agent run; concurrent tool execution
|
|
14
18
|
* (`ToolExecutionMode = "parallel"`) is supported because each id keys its
|
|
@@ -17,39 +21,85 @@ import { executeToolAttributes, executeToolResultAttribute, } from "./attributes
|
|
|
17
21
|
export function instrumentAgent(agent, opts) {
|
|
18
22
|
const buildSpanName = opts.spanName ?? GenAiSpanName.executeTool;
|
|
19
23
|
const activeSpans = new Map();
|
|
24
|
+
const metrics = opts.meter ? genAiMetrics(opts.meter) : undefined;
|
|
25
|
+
const state = { run: undefined };
|
|
20
26
|
const unsubscribe = agent.subscribe((event, signal) => {
|
|
21
|
-
handleEvent(event, opts, activeSpans, buildSpanName, signal);
|
|
27
|
+
handleEvent(event, agent, opts, activeSpans, state, metrics, buildSpanName, signal);
|
|
22
28
|
});
|
|
23
29
|
return {
|
|
24
30
|
stop: () => {
|
|
25
31
|
unsubscribe();
|
|
26
|
-
for (const span of activeSpans.values()) {
|
|
27
|
-
span.setStatus({ code: SpanStatusCode.OK });
|
|
32
|
+
for (const { span } of activeSpans.values()) {
|
|
28
33
|
span.end();
|
|
29
34
|
}
|
|
30
35
|
activeSpans.clear();
|
|
36
|
+
if (state.run) {
|
|
37
|
+
state.run.span.end();
|
|
38
|
+
state.run = undefined;
|
|
39
|
+
}
|
|
31
40
|
},
|
|
41
|
+
getRunContext: () => state.run?.context,
|
|
32
42
|
};
|
|
33
43
|
}
|
|
34
|
-
function handleEvent(event, opts, activeSpans, buildSpanName, signal) {
|
|
44
|
+
function handleEvent(event, agent, opts, activeSpans, state, metrics, buildSpanName, signal) {
|
|
35
45
|
switch (event.type) {
|
|
36
|
-
case "
|
|
46
|
+
case "agent_start": {
|
|
47
|
+
if (!opts.runSpans)
|
|
48
|
+
return;
|
|
37
49
|
const parentContext = opts.getParentContext?.() ?? otelContext.active();
|
|
38
|
-
const span = opts.tracer.startSpan(
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
50
|
+
const span = opts.tracer.startSpan(GenAiSpanName.invokeAgent(opts.meta.agentName), {
|
|
51
|
+
kind: SpanKind.INTERNAL,
|
|
52
|
+
attributes: invokeAgentAttributes(opts.meta),
|
|
53
|
+
}, parentContext ?? undefined);
|
|
54
|
+
state.run = {
|
|
55
|
+
span,
|
|
56
|
+
context: trace.setSpan(parentContext ?? otelContext.active(), span),
|
|
57
|
+
startedAt: Date.now(),
|
|
58
|
+
};
|
|
59
|
+
return;
|
|
60
|
+
}
|
|
61
|
+
case "message_end": {
|
|
62
|
+
const run = state.run;
|
|
63
|
+
const message = event.message;
|
|
64
|
+
if (!run || message.role !== "assistant" || !("usage" in message)) {
|
|
65
|
+
return;
|
|
43
66
|
}
|
|
44
|
-
|
|
67
|
+
// Track outcome only. The run span deliberately carries NO
|
|
68
|
+
// gen_ai.usage.* attributes: platform aggregations sum usage across
|
|
69
|
+
// every span in a conversation, so aggregated usage on the run span
|
|
70
|
+
// would double-count the chat spans beneath it.
|
|
71
|
+
run.lastStopReason = message.stopReason;
|
|
72
|
+
run.errorMessage = message.errorMessage;
|
|
73
|
+
return;
|
|
74
|
+
}
|
|
75
|
+
case "agent_end": {
|
|
76
|
+
const run = state.run;
|
|
77
|
+
if (!run)
|
|
78
|
+
return;
|
|
79
|
+
state.run = undefined;
|
|
80
|
+
finishRunSpan(run, opts.meta, metrics, signal);
|
|
81
|
+
return;
|
|
82
|
+
}
|
|
83
|
+
case "tool_execution_start": {
|
|
84
|
+
const parentContext = opts.getParentContext?.() ?? state.run?.context ?? otelContext.active();
|
|
85
|
+
const description = lookupToolDescription(agent, event.toolName);
|
|
86
|
+
// Full attribute set at span creation time so samplers see
|
|
87
|
+
// gen_ai.operation.name / tool.name / tool.type.
|
|
88
|
+
const attributes = {
|
|
89
|
+
...executeToolAttributes(event.toolName, event.toolCallId, event.args, opts.meta, description),
|
|
90
|
+
...opts.extraAttributes?.(event),
|
|
91
|
+
};
|
|
92
|
+
const span = opts.tracer.startSpan(buildSpanName(event.toolName), { kind: SpanKind.INTERNAL, attributes }, parentContext ?? undefined);
|
|
93
|
+
activeSpans.set(event.toolCallId, { span, startedAt: Date.now() });
|
|
45
94
|
return;
|
|
46
95
|
}
|
|
47
96
|
case "tool_execution_end": {
|
|
48
|
-
const
|
|
49
|
-
if (!
|
|
97
|
+
const active = activeSpans.get(event.toolCallId);
|
|
98
|
+
if (!active)
|
|
50
99
|
return;
|
|
51
100
|
activeSpans.delete(event.toolCallId);
|
|
52
|
-
span
|
|
101
|
+
const { span, startedAt } = active;
|
|
102
|
+
let errorType;
|
|
53
103
|
if (event.isError && signal?.aborted) {
|
|
54
104
|
// The run's AbortSignal fired: pi synthesizes "Operation aborted"
|
|
55
105
|
// error results for tool calls cut short by a requested abort. A
|
|
@@ -58,6 +108,8 @@ function handleEvent(event, opts, activeSpans, buildSpanName, signal) {
|
|
|
58
108
|
span.setAttribute(IntrospectionAttr.TERMINATION_REASON, "cancelled");
|
|
59
109
|
}
|
|
60
110
|
else if (event.isError) {
|
|
111
|
+
errorType = "tool_error";
|
|
112
|
+
span.setAttribute("error.type", errorType);
|
|
61
113
|
span.setStatus({
|
|
62
114
|
code: SpanStatusCode.ERROR,
|
|
63
115
|
message: typeof event.result === "string"
|
|
@@ -68,15 +120,70 @@ function handleEvent(event, opts, activeSpans, buildSpanName, signal) {
|
|
|
68
120
|
});
|
|
69
121
|
}
|
|
70
122
|
else {
|
|
71
|
-
|
|
123
|
+
// Semconv scopes gen_ai.tool.call.result to successful executions;
|
|
124
|
+
// error text is carried on the span status instead.
|
|
125
|
+
span.setAttributes(executeToolResultAttribute(event.result));
|
|
72
126
|
}
|
|
73
127
|
span.end();
|
|
128
|
+
if (metrics) {
|
|
129
|
+
const attributes = {
|
|
130
|
+
[GenAi.TOOL_NAME]: event.toolName,
|
|
131
|
+
[GenAi.TOOL_TYPE]: "function",
|
|
132
|
+
[GenAi.AGENT_NAME]: opts.meta.agentName,
|
|
133
|
+
};
|
|
134
|
+
if (errorType)
|
|
135
|
+
attributes["error.type"] = errorType;
|
|
136
|
+
metrics.executeToolDuration.record((Date.now() - startedAt) / 1000, attributes);
|
|
137
|
+
}
|
|
74
138
|
return;
|
|
75
139
|
}
|
|
76
140
|
default:
|
|
77
141
|
return;
|
|
78
142
|
}
|
|
79
143
|
}
|
|
144
|
+
function finishRunSpan(run, meta, metrics, signal) {
|
|
145
|
+
const { span } = run;
|
|
146
|
+
if (run.lastStopReason) {
|
|
147
|
+
span.setAttribute(GenAi.RESPONSE_FINISH_REASONS, [
|
|
148
|
+
semconvFinishReason(run.lastStopReason),
|
|
149
|
+
]);
|
|
150
|
+
}
|
|
151
|
+
let errorType;
|
|
152
|
+
const aborted = run.lastStopReason === "aborted" || signal?.aborted === true;
|
|
153
|
+
if (aborted) {
|
|
154
|
+
// Mirrors the chat-span contract: a requested cancellation is an
|
|
155
|
+
// outcome, not a failure.
|
|
156
|
+
span.setAttribute(IntrospectionAttr.TERMINATION_REASON, "cancelled");
|
|
157
|
+
}
|
|
158
|
+
else if (run.lastStopReason === "error") {
|
|
159
|
+
const errorMessage = run.errorMessage ?? "Unknown error";
|
|
160
|
+
errorType = classifyErrorType(errorMessage, "model_error");
|
|
161
|
+
span.setAttribute("error.type", errorType);
|
|
162
|
+
span.recordException(new Error(errorMessage));
|
|
163
|
+
span.setStatus({ code: SpanStatusCode.ERROR, message: errorMessage });
|
|
164
|
+
}
|
|
165
|
+
span.end();
|
|
166
|
+
if (metrics) {
|
|
167
|
+
const attributes = { [GenAi.AGENT_NAME]: meta.agentName };
|
|
168
|
+
if (errorType)
|
|
169
|
+
attributes["error.type"] = errorType;
|
|
170
|
+
metrics.invokeAgentDuration.record((Date.now() - run.startedAt) / 1000, attributes);
|
|
171
|
+
}
|
|
172
|
+
}
|
|
173
|
+
/**
|
|
174
|
+
* Best-effort `gen_ai.tool.description` lookup from the agent's tool
|
|
175
|
+
* registry. Defensive against partial Agent implementations (tests, mocks)
|
|
176
|
+
* that don't expose `state.tools`.
|
|
177
|
+
*/
|
|
178
|
+
function lookupToolDescription(agent, toolName) {
|
|
179
|
+
try {
|
|
180
|
+
return agent.state?.tools?.find((tool) => tool.name === toolName)
|
|
181
|
+
?.description;
|
|
182
|
+
}
|
|
183
|
+
catch {
|
|
184
|
+
return undefined;
|
|
185
|
+
}
|
|
186
|
+
}
|
|
80
187
|
function safeStringify(value) {
|
|
81
188
|
try {
|
|
82
189
|
return JSON.stringify(value);
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"instrument-agent.js","sourceRoot":"","sources":["../src/instrument-agent.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,EACL,OAAO,IAAI,WAAW,EACtB,QAAQ,EACR,cAAc,
|
|
1
|
+
{"version":3,"file":"instrument-agent.js","sourceRoot":"","sources":["../src/instrument-agent.ts"],"names":[],"mappings":"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"}
|
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
* Wrap a pi-agent `StreamFn` so each invocation emits a `chat` span that
|
|
3
3
|
* conforms to the OTEL GenAI semantic convention.
|
|
4
4
|
*/
|
|
5
|
-
import { type Attributes, type Context as OtelContext, type Tracer } from "@opentelemetry/api";
|
|
5
|
+
import { type Attributes, type Context as OtelContext, type Meter, type Tracer } from "@opentelemetry/api";
|
|
6
6
|
import { type Api, type Context, type Model } from "@earendil-works/pi-ai";
|
|
7
7
|
import type { StreamFn } from "@earendil-works/pi-agent-core";
|
|
8
8
|
import { type AbortTerminationReason } from "@introspection-sdk/types";
|
|
@@ -12,6 +12,13 @@ export interface InstrumentStreamOptions {
|
|
|
12
12
|
tracer: Tracer;
|
|
13
13
|
/** Required metadata stamped onto every chat span. */
|
|
14
14
|
meta: AgentMeta;
|
|
15
|
+
/**
|
|
16
|
+
* Optional meter. When set, the wrapper also records the GenAI client
|
|
17
|
+
* metrics (`gen_ai.client.token.usage`, `gen_ai.client.operation.duration`,
|
|
18
|
+
* `gen_ai.client.operation.time_to_first_chunk`,
|
|
19
|
+
* `gen_ai.client.operation.time_per_output_chunk`).
|
|
20
|
+
*/
|
|
21
|
+
meter?: Meter;
|
|
15
22
|
/**
|
|
16
23
|
* Returns the parent OTel context for the next chat span. If undefined or
|
|
17
24
|
* returns null, `context.active()` is used at call time.
|
|
@@ -22,7 +29,7 @@ export interface InstrumentStreamOptions {
|
|
|
22
29
|
* on top of the GenAI semconv attributes for each chat span.
|
|
23
30
|
*/
|
|
24
31
|
extraAttributes?: (model: Model<Api>, context: Context) => Attributes;
|
|
25
|
-
/** Override the default span name builder. */
|
|
32
|
+
/** Override the default span name builder (default: `chat {model.id}`). */
|
|
26
33
|
spanName?: (model: Model<Api>, context: Context) => string;
|
|
27
34
|
/**
|
|
28
35
|
* Returns the compaction summaries known for the session, read at span
|
|
@@ -47,7 +54,8 @@ export interface InstrumentStreamOptions {
|
|
|
47
54
|
abortTerminationReason?: () => AbortTerminationReason | null;
|
|
48
55
|
}
|
|
49
56
|
/**
|
|
50
|
-
* Wrap a {@link StreamFn} to emit `chat
|
|
57
|
+
* Wrap a {@link StreamFn} to emit `chat {model}` spans (CLIENT kind — the
|
|
58
|
+
* model runs in a remote process).
|
|
51
59
|
*
|
|
52
60
|
* Reassign `agent.streamFn` with the result:
|
|
53
61
|
*
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"instrument-stream.d.ts","sourceRoot":"","sources":["../src/instrument-stream.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,EAKL,KAAK,UAAU,EACf,KAAK,OAAO,IAAI,WAAW,
|
|
1
|
+
{"version":3,"file":"instrument-stream.d.ts","sourceRoot":"","sources":["../src/instrument-stream.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,EAKL,KAAK,UAAU,EACf,KAAK,OAAO,IAAI,WAAW,EAC3B,KAAK,KAAK,EAEV,KAAK,MAAM,EACZ,MAAM,oBAAoB,CAAC;AAC5B,OAAO,EAKL,KAAK,GAAG,EACR,KAAK,OAAO,EACZ,KAAK,KAAK,EACX,MAAM,uBAAuB,CAAC;AAC/B,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,+BAA+B,CAAC;AAC9D,OAAO,EAIL,KAAK,sBAAsB,EAC5B,MAAM,0BAA0B,CAAC;AAClC,OAAO,EAIL,KAAK,SAAS,EACf,MAAM,iBAAiB,CAAC;AAIzB,MAAM,WAAW,uBAAuB;IACtC,wCAAwC;IACxC,MAAM,EAAE,MAAM,CAAC;IACf,sDAAsD;IACtD,IAAI,EAAE,SAAS,CAAC;IAChB;;;;;OAKG;IACH,KAAK,CAAC,EAAE,KAAK,CAAC;IACd;;;OAGG;IACH,gBAAgB,CAAC,EAAE,MAAM,WAAW,GAAG,IAAI,GAAG,SAAS,CAAC;IACxD;;;OAGG;IACH,eAAe,CAAC,EAAE,CAAC,KAAK,EAAE,KAAK,CAAC,GAAG,CAAC,EAAE,OAAO,EAAE,OAAO,KAAK,UAAU,CAAC;IACtE,2EAA2E;IAC3E,QAAQ,CAAC,EAAE,CAAC,KAAK,EAAE,KAAK,CAAC,GAAG,CAAC,EAAE,OAAO,EAAE,OAAO,KAAK,MAAM,CAAC;IAC3D;;;;;;;OAOG;IACH,sBAAsB,CAAC,EAAE,MAAM,SAAS,MAAM,EAAE,CAAC;IACjD;;;;;;;;;;OAUG;IACH,sBAAsB,CAAC,EAAE,MAAM,sBAAsB,GAAG,IAAI,CAAC;CAC9D;AAED;;;;;;;;;;;;;GAaG;AACH,wBAAgB,gBAAgB,CAC9B,QAAQ,EAAE,QAAQ,EAClB,IAAI,EAAE,uBAAuB,GAC5B,QAAQ,CA6CV"}
|
|
@@ -4,10 +4,13 @@
|
|
|
4
4
|
*/
|
|
5
5
|
import { context as otelContext, SpanKind, SpanStatusCode, trace, } from "@opentelemetry/api";
|
|
6
6
|
import { createAssistantMessageEventStream, } from "@earendil-works/pi-ai";
|
|
7
|
-
import { GenAiSpanName, IntrospectionAttr, } from "@introspection-sdk/types";
|
|
8
|
-
import { chatRequestAttributes, chatResponseAttributes, } from "./attributes.js";
|
|
7
|
+
import { GenAi, GenAiSpanName, IntrospectionAttr, } from "@introspection-sdk/types";
|
|
8
|
+
import { chatRequestAttributes, chatResponseAttributes, serverAttributes, } from "./attributes.js";
|
|
9
|
+
import { classifyErrorType, classifyThrownErrorType } from "./error-type.js";
|
|
10
|
+
import { genAiMetrics } from "./metrics.js";
|
|
9
11
|
/**
|
|
10
|
-
* Wrap a {@link StreamFn} to emit `chat
|
|
12
|
+
* Wrap a {@link StreamFn} to emit `chat {model}` spans (CLIENT kind — the
|
|
13
|
+
* model runs in a remote process).
|
|
11
14
|
*
|
|
12
15
|
* Reassign `agent.streamFn` with the result:
|
|
13
16
|
*
|
|
@@ -20,17 +23,21 @@ import { chatRequestAttributes, chatResponseAttributes, } from "./attributes.js"
|
|
|
20
23
|
* `error` events, never thrown synchronously.
|
|
21
24
|
*/
|
|
22
25
|
export function instrumentStream(streamFn, opts) {
|
|
23
|
-
const buildSpanName = opts.spanName ?? ((model) => GenAiSpanName.chat(model.
|
|
26
|
+
const buildSpanName = opts.spanName ?? ((model) => GenAiSpanName.chat(model.id));
|
|
27
|
+
const metrics = opts.meter ? genAiMetrics(opts.meter) : undefined;
|
|
24
28
|
return ((model, context, options) => {
|
|
25
29
|
const parentContext = opts.getParentContext?.() ?? otelContext.active();
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
30
|
+
// Compute the full attribute set up front and pass it at span creation
|
|
31
|
+
// time so samplers see gen_ai.operation.name / provider / model /
|
|
32
|
+
// server.*.
|
|
33
|
+
const attributes = {
|
|
34
|
+
...chatRequestAttributes(model, context, opts.meta, {
|
|
35
|
+
compactionSummaries: opts.getCompactionSummaries?.(),
|
|
36
|
+
streamOptions: options,
|
|
37
|
+
}),
|
|
38
|
+
...opts.extraAttributes?.(model, context),
|
|
39
|
+
};
|
|
40
|
+
const span = opts.tracer.startSpan(buildSpanName(model, context), { kind: SpanKind.CLIENT, attributes }, parentContext ?? undefined);
|
|
34
41
|
const proxy = createAssistantMessageEventStream();
|
|
35
42
|
const spanContext = trace.setSpan(parentContext ?? otelContext.active(), span);
|
|
36
43
|
void runUpstream({
|
|
@@ -41,20 +48,43 @@ export function instrumentStream(streamFn, opts) {
|
|
|
41
48
|
spanContext,
|
|
42
49
|
span,
|
|
43
50
|
proxy,
|
|
51
|
+
metrics,
|
|
44
52
|
abortTerminationReason: opts.abortTerminationReason,
|
|
45
53
|
});
|
|
46
54
|
return proxy;
|
|
47
55
|
});
|
|
48
56
|
}
|
|
49
|
-
async function runUpstream({ streamFn, model, context, options, spanContext, span, proxy, abortTerminationReason, }) {
|
|
57
|
+
async function runUpstream({ streamFn, model, context, options, spanContext, span, proxy, metrics, abortTerminationReason, }) {
|
|
50
58
|
let finished = false;
|
|
59
|
+
const startedAt = Date.now();
|
|
60
|
+
const startedAtMonotonic = performance.now();
|
|
61
|
+
let lastChunkAt;
|
|
51
62
|
try {
|
|
52
63
|
const upstream = await otelContext.with(spanContext, () => streamFn(model, context, options));
|
|
53
64
|
for await (const event of upstream) {
|
|
65
|
+
if (isOutputChunk(event)) {
|
|
66
|
+
const now = performance.now();
|
|
67
|
+
if (lastChunkAt === undefined) {
|
|
68
|
+
const timeToFirstChunk = (now - startedAtMonotonic) / 1000;
|
|
69
|
+
span.setAttribute("gen_ai.response.time_to_first_chunk", timeToFirstChunk);
|
|
70
|
+
metrics?.timeToFirstChunk.record(timeToFirstChunk, chatMetricAttributes(model));
|
|
71
|
+
}
|
|
72
|
+
else {
|
|
73
|
+
metrics?.timePerOutputChunk.record((now - lastChunkAt) / 1000, chatMetricAttributes(model));
|
|
74
|
+
}
|
|
75
|
+
lastChunkAt = now;
|
|
76
|
+
}
|
|
54
77
|
proxy.push(event);
|
|
55
78
|
if (!finished && (event.type === "done" || event.type === "error")) {
|
|
56
79
|
finished = true;
|
|
57
|
-
finishSpan(
|
|
80
|
+
finishSpan({
|
|
81
|
+
span,
|
|
82
|
+
event,
|
|
83
|
+
model,
|
|
84
|
+
startedAt,
|
|
85
|
+
metrics,
|
|
86
|
+
abortTerminationReason,
|
|
87
|
+
});
|
|
58
88
|
}
|
|
59
89
|
}
|
|
60
90
|
}
|
|
@@ -62,26 +92,40 @@ async function runUpstream({ streamFn, model, context, options, spanContext, spa
|
|
|
62
92
|
const errorMessage = err instanceof Error ? err.message : String(err);
|
|
63
93
|
const errorEvent = {
|
|
64
94
|
type: "error",
|
|
65
|
-
reason: "error",
|
|
66
|
-
error: assistantErrorMessage(model, errorMessage),
|
|
95
|
+
reason: options?.signal?.aborted === true ? "aborted" : "error",
|
|
96
|
+
error: assistantErrorMessage(model, errorMessage, options?.signal?.aborted === true),
|
|
67
97
|
};
|
|
68
|
-
|
|
98
|
+
if (options?.signal?.aborted !== true) {
|
|
99
|
+
recordGenAiException(span, err, classifyThrownErrorType(err));
|
|
100
|
+
}
|
|
69
101
|
proxy.push(errorEvent);
|
|
70
102
|
if (!finished) {
|
|
71
103
|
finished = true;
|
|
72
|
-
finishSpan(
|
|
104
|
+
finishSpan({
|
|
105
|
+
span,
|
|
106
|
+
event: errorEvent,
|
|
107
|
+
model,
|
|
108
|
+
startedAt,
|
|
109
|
+
metrics,
|
|
110
|
+
abortTerminationReason,
|
|
111
|
+
});
|
|
73
112
|
}
|
|
74
113
|
}
|
|
75
114
|
finally {
|
|
76
115
|
if (!finished) {
|
|
77
116
|
// Upstream ended without a terminal event — close the span anyway so
|
|
78
117
|
// we don't leak.
|
|
79
|
-
span.setStatus({ code: SpanStatusCode.OK });
|
|
80
118
|
span.end();
|
|
81
119
|
}
|
|
82
120
|
}
|
|
83
121
|
}
|
|
84
|
-
function
|
|
122
|
+
function isOutputChunk(event) {
|
|
123
|
+
return ((event.type === "text_delta" ||
|
|
124
|
+
event.type === "thinking_delta" ||
|
|
125
|
+
event.type === "toolcall_delta") &&
|
|
126
|
+
event.delta.length > 0);
|
|
127
|
+
}
|
|
128
|
+
function finishSpan({ span, event, model, startedAt, metrics, abortTerminationReason, }) {
|
|
85
129
|
const message = event.type === "done" ? event.message : event.error;
|
|
86
130
|
span.setAttributes(chatResponseAttributes(message));
|
|
87
131
|
const aborted = (event.type === "error" && event.reason === "aborted") ||
|
|
@@ -91,6 +135,7 @@ function finishSpan(span, event, abortTerminationReason) {
|
|
|
91
135
|
: abortTerminationReason
|
|
92
136
|
? abortTerminationReason()
|
|
93
137
|
: "cancelled";
|
|
138
|
+
let errorType;
|
|
94
139
|
if (terminationReason !== null) {
|
|
95
140
|
// A requested cancellation is an outcome, not a failure: status stays
|
|
96
141
|
// Unset (no success assertion over a truncated generation, no error),
|
|
@@ -105,15 +150,57 @@ function finishSpan(span, event, abortTerminationReason) {
|
|
|
105
150
|
// abort (callback returned null) — fail toward a false error, never a
|
|
106
151
|
// hidden one.
|
|
107
152
|
const errorMessage = message.errorMessage ?? "Unknown error";
|
|
108
|
-
|
|
153
|
+
errorType = classifyErrorType(errorMessage, "model_error");
|
|
154
|
+
recordGenAiException(span, new Error(errorMessage), errorType);
|
|
109
155
|
span.setStatus({ code: SpanStatusCode.ERROR, message: errorMessage });
|
|
110
156
|
}
|
|
111
|
-
|
|
112
|
-
|
|
157
|
+
if (metrics) {
|
|
158
|
+
recordCompletionMetrics(metrics, model, message, startedAt, errorType);
|
|
113
159
|
}
|
|
114
160
|
span.end();
|
|
115
161
|
}
|
|
116
|
-
function
|
|
162
|
+
function chatMetricAttributes(model) {
|
|
163
|
+
return {
|
|
164
|
+
[GenAi.OPERATION_NAME]: "chat",
|
|
165
|
+
[GenAi.PROVIDER_NAME]: model.provider,
|
|
166
|
+
[GenAi.REQUEST_MODEL]: model.id,
|
|
167
|
+
...serverAttributes(model.baseUrl),
|
|
168
|
+
};
|
|
169
|
+
}
|
|
170
|
+
function recordCompletionMetrics(metrics, model, message, startedAt, errorType) {
|
|
171
|
+
const attributes = chatMetricAttributes(model);
|
|
172
|
+
if (message.model) {
|
|
173
|
+
attributes[GenAi.RESPONSE_MODEL] = message.model;
|
|
174
|
+
}
|
|
175
|
+
const durationAttributes = errorType
|
|
176
|
+
? { ...attributes, "error.type": errorType }
|
|
177
|
+
: attributes;
|
|
178
|
+
metrics.operationDuration.record((Date.now() - startedAt) / 1000, durationAttributes);
|
|
179
|
+
const inputTokens = message.usage.input + message.usage.cacheRead + message.usage.cacheWrite;
|
|
180
|
+
if (inputTokens > 0) {
|
|
181
|
+
metrics.tokenUsage.record(inputTokens, {
|
|
182
|
+
...attributes,
|
|
183
|
+
"gen_ai.token.type": "input",
|
|
184
|
+
});
|
|
185
|
+
}
|
|
186
|
+
if (message.usage.output > 0) {
|
|
187
|
+
metrics.tokenUsage.record(message.usage.output, {
|
|
188
|
+
...attributes,
|
|
189
|
+
"gen_ai.token.type": "output",
|
|
190
|
+
});
|
|
191
|
+
}
|
|
192
|
+
}
|
|
193
|
+
function recordGenAiException(span, error, errorType) {
|
|
194
|
+
const exception = error instanceof Error ? error : new Error(String(error));
|
|
195
|
+
span.setAttribute("error.type", errorType);
|
|
196
|
+
// recordException writes the standard `exception` span event
|
|
197
|
+
// (exception.type / exception.message / exception.stacktrace). The
|
|
198
|
+
// semconv `gen_ai.client.operation.exception` signal is a *log* event —
|
|
199
|
+
// duplicating it as a second span event is not part of the convention,
|
|
200
|
+
// so only the standard exception event is recorded here.
|
|
201
|
+
span.recordException(exception);
|
|
202
|
+
}
|
|
203
|
+
function assistantErrorMessage(model, errorMessage, aborted = false) {
|
|
117
204
|
return {
|
|
118
205
|
role: "assistant",
|
|
119
206
|
content: [],
|
|
@@ -128,7 +215,7 @@ function assistantErrorMessage(model, errorMessage) {
|
|
|
128
215
|
totalTokens: 0,
|
|
129
216
|
cost: { input: 0, output: 0, cacheRead: 0, cacheWrite: 0, total: 0 },
|
|
130
217
|
},
|
|
131
|
-
stopReason: "error",
|
|
218
|
+
stopReason: aborted ? "aborted" : "error",
|
|
132
219
|
errorMessage,
|
|
133
220
|
timestamp: Date.now(),
|
|
134
221
|
};
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"instrument-stream.js","sourceRoot":"","sources":["../src/instrument-stream.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,EACL,OAAO,IAAI,WAAW,EACtB,QAAQ,EACR,cAAc,EACd,KAAK,
|
|
1
|
+
{"version":3,"file":"instrument-stream.js","sourceRoot":"","sources":["../src/instrument-stream.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* GenAI client metric instruments per the OTel GenAI semconv metrics doc.
|
|
3
|
+
*
|
|
4
|
+
* Instruments are created lazily per `Meter` and cached, so repeated
|
|
5
|
+
* `instrumentStream` / `instrumentAgent` calls sharing a meter reuse the
|
|
6
|
+
* same histograms. Bucket boundaries follow the spec's
|
|
7
|
+
* ExplicitBucketBoundaries advice where one is defined.
|
|
8
|
+
*/
|
|
9
|
+
import type { Histogram, Meter } from "@opentelemetry/api";
|
|
10
|
+
export interface GenAiMetrics {
|
|
11
|
+
/** `gen_ai.client.token.usage` — record once per token type per call. */
|
|
12
|
+
tokenUsage: Histogram;
|
|
13
|
+
/** `gen_ai.client.operation.duration` — seconds per chat call. */
|
|
14
|
+
operationDuration: Histogram;
|
|
15
|
+
/** `gen_ai.client.operation.time_to_first_chunk` — streaming only. */
|
|
16
|
+
timeToFirstChunk: Histogram;
|
|
17
|
+
/** `gen_ai.client.operation.time_per_output_chunk` — per chunk after the first. */
|
|
18
|
+
timePerOutputChunk: Histogram;
|
|
19
|
+
/** `gen_ai.execute_tool.duration` — seconds per tool execution. */
|
|
20
|
+
executeToolDuration: Histogram;
|
|
21
|
+
/** `gen_ai.invoke_agent.duration` — seconds per in-process agent run. */
|
|
22
|
+
invokeAgentDuration: Histogram;
|
|
23
|
+
}
|
|
24
|
+
/** Get (or create) the GenAI instruments for a meter. */
|
|
25
|
+
export declare function genAiMetrics(meter: Meter): GenAiMetrics;
|
|
26
|
+
//# sourceMappingURL=metrics.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"metrics.d.ts","sourceRoot":"","sources":["../src/metrics.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAEH,OAAO,KAAK,EAAE,SAAS,EAAE,KAAK,EAAE,MAAM,oBAAoB,CAAC;AAmB3D,MAAM,WAAW,YAAY;IAC3B,yEAAyE;IACzE,UAAU,EAAE,SAAS,CAAC;IACtB,kEAAkE;IAClE,iBAAiB,EAAE,SAAS,CAAC;IAC7B,sEAAsE;IACtE,gBAAgB,EAAE,SAAS,CAAC;IAC5B,mFAAmF;IACnF,kBAAkB,EAAE,SAAS,CAAC;IAC9B,mEAAmE;IACnE,mBAAmB,EAAE,SAAS,CAAC;IAC/B,yEAAyE;IACzE,mBAAmB,EAAE,SAAS,CAAC;CAChC;AAID,yDAAyD;AACzD,wBAAgB,YAAY,CAAC,KAAK,EAAE,KAAK,GAAG,YAAY,CAmDvD"}
|