@apo-ai/sdk 0.2.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.
- package/LICENSE +21 -0
- package/README.md +314 -0
- package/dist/agent-task/integrations/ai-sdk.d.ts +121 -0
- package/dist/agent-task/integrations/ai-sdk.js +10 -0
- package/dist/agent-task/integrations/ai-sdk.js.map +1 -0
- package/dist/agent-task/integrations/anthropic.d.ts +67 -0
- package/dist/agent-task/integrations/anthropic.js +10 -0
- package/dist/agent-task/integrations/anthropic.js.map +1 -0
- package/dist/agent-task/integrations/openai.d.ts +77 -0
- package/dist/agent-task/integrations/openai.js +10 -0
- package/dist/agent-task/integrations/openai.js.map +1 -0
- package/dist/agent-task/public.d.ts +1326 -0
- package/dist/agent-task/public.js +3026 -0
- package/dist/agent-task/public.js.map +1 -0
- package/dist/chunk-DT2LMB7O.js +80 -0
- package/dist/chunk-DT2LMB7O.js.map +1 -0
- package/dist/chunk-GDB6SDGN.js +75 -0
- package/dist/chunk-GDB6SDGN.js.map +1 -0
- package/dist/chunk-HKLBPIB4.js +232 -0
- package/dist/chunk-HKLBPIB4.js.map +1 -0
- package/dist/chunk-HWZVL6TS.js +37 -0
- package/dist/chunk-HWZVL6TS.js.map +1 -0
- package/dist/chunk-PMYLL2H4.js +495 -0
- package/dist/chunk-PMYLL2H4.js.map +1 -0
- package/dist/chunk-SZDSIPXC.js +74 -0
- package/dist/chunk-SZDSIPXC.js.map +1 -0
- package/dist/index.d.ts +95 -0
- package/dist/index.js +39 -0
- package/dist/index.js.map +1 -0
- package/dist/otel/index.d.ts +270 -0
- package/dist/otel/index.js +32 -0
- package/dist/otel/index.js.map +1 -0
- package/dist/tracing-DtbhYQV6.d.ts +26 -0
- package/dist/types-C-nrDEVf.d.ts +140 -0
- package/package.json +92 -0
|
@@ -0,0 +1,495 @@
|
|
|
1
|
+
// Auto-generated by `pnpm --filter @apo-ai/sdk build` (tsup.config.ts).
|
|
2
|
+
// Do not edit by hand — edit the src/ originals and rebuild.
|
|
3
|
+
import {
|
|
4
|
+
extractTokenCounts
|
|
5
|
+
} from "./chunk-HWZVL6TS.js";
|
|
6
|
+
|
|
7
|
+
// src/otel/index.ts
|
|
8
|
+
import {
|
|
9
|
+
trace,
|
|
10
|
+
context,
|
|
11
|
+
defaultTextMapGetter,
|
|
12
|
+
defaultTextMapSetter
|
|
13
|
+
} from "@opentelemetry/api";
|
|
14
|
+
import { W3CTraceContextPropagator } from "@opentelemetry/core";
|
|
15
|
+
import {
|
|
16
|
+
BasicTracerProvider,
|
|
17
|
+
BatchSpanProcessor,
|
|
18
|
+
SimpleSpanProcessor
|
|
19
|
+
} from "@opentelemetry/sdk-trace-base";
|
|
20
|
+
import { AsyncHooksContextManager } from "@opentelemetry/context-async-hooks";
|
|
21
|
+
import { resourceFromAttributes } from "@opentelemetry/resources";
|
|
22
|
+
import {
|
|
23
|
+
SEMRESATTRS_SERVICE_NAME,
|
|
24
|
+
SEMRESATTRS_SERVICE_VERSION,
|
|
25
|
+
SEMRESATTRS_SERVICE_NAMESPACE,
|
|
26
|
+
SEMRESATTRS_DEPLOYMENT_ENVIRONMENT
|
|
27
|
+
} from "@opentelemetry/semantic-conventions";
|
|
28
|
+
import { OTLPTraceExporter } from "@opentelemetry/exporter-trace-otlp-http";
|
|
29
|
+
|
|
30
|
+
// src/agent-task/integrations/run-context.ts
|
|
31
|
+
import { AsyncLocalStorage } from "async_hooks";
|
|
32
|
+
var runStorage = new AsyncLocalStorage();
|
|
33
|
+
function withApoRun(ctx, fn) {
|
|
34
|
+
return runStorage.run(ctx, fn);
|
|
35
|
+
}
|
|
36
|
+
function withApoRunSync(ctx, fn) {
|
|
37
|
+
return runStorage.run(ctx, fn);
|
|
38
|
+
}
|
|
39
|
+
function getActiveApoRun() {
|
|
40
|
+
return runStorage.getStore();
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
// src/agent-task/integrations/otel-translate.ts
|
|
44
|
+
function safeParse(raw) {
|
|
45
|
+
if (typeof raw !== "string") return raw;
|
|
46
|
+
try {
|
|
47
|
+
return JSON.parse(raw);
|
|
48
|
+
} catch {
|
|
49
|
+
return raw;
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
function monotonicNowMs() {
|
|
53
|
+
if (typeof performance !== "undefined" && typeof performance.now === "function") {
|
|
54
|
+
return performance.now();
|
|
55
|
+
}
|
|
56
|
+
return Date.now();
|
|
57
|
+
}
|
|
58
|
+
function round3(n) {
|
|
59
|
+
return Math.round(n * 1e3) / 1e3;
|
|
60
|
+
}
|
|
61
|
+
function translateOtelSpan(spanName, data) {
|
|
62
|
+
const { attributes, status } = data;
|
|
63
|
+
const isError = status.code === 2;
|
|
64
|
+
const errorMessage = status.message;
|
|
65
|
+
if (spanName === "ai.toolCall") {
|
|
66
|
+
return {
|
|
67
|
+
observationType: "TOOL",
|
|
68
|
+
stepName: String(attributes["ai.toolCall.name"] ?? "unknown"),
|
|
69
|
+
input: safeParse(attributes["ai.toolCall.args"]),
|
|
70
|
+
output: safeParse(attributes["ai.toolCall.result"]),
|
|
71
|
+
error: isError,
|
|
72
|
+
errorMessage
|
|
73
|
+
};
|
|
74
|
+
}
|
|
75
|
+
if (spanName === "ai.generateText" || spanName === "ai.streamText") {
|
|
76
|
+
return {
|
|
77
|
+
observationType: "GENERATION",
|
|
78
|
+
stepName: "agent.generate",
|
|
79
|
+
text: extractTextFromAttrs(attributes),
|
|
80
|
+
model: String(
|
|
81
|
+
attributes["gen_ai.request.model"] ?? attributes["ai.model.id"] ?? attributes["ai.response.model"] ?? "unknown"
|
|
82
|
+
),
|
|
83
|
+
...extractTokenCounts(attributes),
|
|
84
|
+
error: isError,
|
|
85
|
+
errorMessage
|
|
86
|
+
};
|
|
87
|
+
}
|
|
88
|
+
const operation = attributes["gen_ai.operation.name"];
|
|
89
|
+
if (operation === "execute_tool" || spanName.startsWith("gen_ai.tool") || spanName.includes("tool") && attributes["gen_ai.tool.name"]) {
|
|
90
|
+
return {
|
|
91
|
+
observationType: "TOOL",
|
|
92
|
+
stepName: String(attributes["gen_ai.tool.name"] ?? "unknown"),
|
|
93
|
+
input: safeParse(attributes["gen_ai.tool.call.arguments"]),
|
|
94
|
+
output: safeParse(attributes["gen_ai.tool.call.result"]),
|
|
95
|
+
error: isError,
|
|
96
|
+
errorMessage
|
|
97
|
+
};
|
|
98
|
+
}
|
|
99
|
+
if (operation === "invoke_agent") {
|
|
100
|
+
return {
|
|
101
|
+
observationType: "AGENT",
|
|
102
|
+
stepName: String(attributes["gen_ai.agent.name"] ?? "agent"),
|
|
103
|
+
output: safeParse(attributes["gen_ai.tool.call.result"]),
|
|
104
|
+
error: isError,
|
|
105
|
+
errorMessage
|
|
106
|
+
};
|
|
107
|
+
}
|
|
108
|
+
if (operation === "chat" || operation === "generate_content" || operation === "text_completion") {
|
|
109
|
+
return {
|
|
110
|
+
observationType: "GENERATION",
|
|
111
|
+
stepName: "agent.generate",
|
|
112
|
+
text: extractTextFromAttrs(attributes, "gen_ai."),
|
|
113
|
+
...extractTokenCounts(attributes),
|
|
114
|
+
error: isError,
|
|
115
|
+
errorMessage
|
|
116
|
+
};
|
|
117
|
+
}
|
|
118
|
+
return null;
|
|
119
|
+
}
|
|
120
|
+
function extractTextFromAttrs(attrs, prefix) {
|
|
121
|
+
const candidates = prefix === "gen_ai." ? ["gen_ai.completion", "gen_ai.response.text"] : prefix === "ai." ? ["ai.response.text", "ai.response.output", "ai.generateText.result"] : [
|
|
122
|
+
"gen_ai.completion",
|
|
123
|
+
"gen_ai.response.text",
|
|
124
|
+
"ai.response.text",
|
|
125
|
+
"ai.response.output",
|
|
126
|
+
"ai.generateText.result"
|
|
127
|
+
];
|
|
128
|
+
for (const key of candidates) {
|
|
129
|
+
const val = attrs[key];
|
|
130
|
+
if (typeof val === "string" && val.length > 0) {
|
|
131
|
+
const parsed = safeParse(val);
|
|
132
|
+
return typeof parsed === "string" ? parsed : val;
|
|
133
|
+
}
|
|
134
|
+
}
|
|
135
|
+
return void 0;
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
// src/agent-task/integrations/otel-processor.ts
|
|
139
|
+
var ApoSpanProcessor = class {
|
|
140
|
+
constructor() {
|
|
141
|
+
this.spanMap = /* @__PURE__ */ new Map();
|
|
142
|
+
}
|
|
143
|
+
onStart(span, _parentContext) {
|
|
144
|
+
const run = getActiveApoRun();
|
|
145
|
+
if (!run) return;
|
|
146
|
+
const translated = translateOtelSpan(span.name, {
|
|
147
|
+
attributes: span.attributes ?? {},
|
|
148
|
+
status: { code: 0 }
|
|
149
|
+
// no error at start
|
|
150
|
+
});
|
|
151
|
+
if (!translated) return;
|
|
152
|
+
const parentOtelId = span.parentSpanContext?.spanId;
|
|
153
|
+
const parentTracked = parentOtelId ? this.spanMap.get(parentOtelId) : void 0;
|
|
154
|
+
const parentApoId = parentTracked?.apoSpanId || run.parentSpanId || run.trace.rootSpanId;
|
|
155
|
+
const apoSpanId = run.trace.createSpan({
|
|
156
|
+
task_id: run.taskId ?? "otel-trace",
|
|
157
|
+
parent_call_id: parentApoId,
|
|
158
|
+
step_name: translated.stepName,
|
|
159
|
+
model: translated.model ?? translated.stepName,
|
|
160
|
+
observation_type: translated.observationType,
|
|
161
|
+
...translated.input ? { input: translated.input } : {},
|
|
162
|
+
metadata: {
|
|
163
|
+
...run.taskId ? { taskId: run.taskId } : {},
|
|
164
|
+
...run.turnNumber !== void 0 ? { turnNumber: run.turnNumber } : {},
|
|
165
|
+
source: "otel-processor"
|
|
166
|
+
}
|
|
167
|
+
});
|
|
168
|
+
this.spanMap.set(span.spanContext().spanId, {
|
|
169
|
+
apoSpanId,
|
|
170
|
+
otelSpanName: span.name,
|
|
171
|
+
startedAt: monotonicNowMs()
|
|
172
|
+
});
|
|
173
|
+
}
|
|
174
|
+
onEnd(span) {
|
|
175
|
+
const otelId = span.spanContext().spanId;
|
|
176
|
+
const tracked = this.spanMap.get(otelId);
|
|
177
|
+
if (!tracked) return;
|
|
178
|
+
this.spanMap.delete(otelId);
|
|
179
|
+
const run = getActiveApoRun();
|
|
180
|
+
if (!run) return;
|
|
181
|
+
const translated = translateOtelSpan(tracked.otelSpanName, {
|
|
182
|
+
attributes: span.attributes ?? {},
|
|
183
|
+
status: span.status ?? { code: 0 }
|
|
184
|
+
});
|
|
185
|
+
const latency = round3(monotonicNowMs() - tracked.startedAt);
|
|
186
|
+
run.trace.endSpan(tracked.apoSpanId, {
|
|
187
|
+
latency_ms: latency,
|
|
188
|
+
...buildEndParams(translated)
|
|
189
|
+
});
|
|
190
|
+
}
|
|
191
|
+
forceFlush() {
|
|
192
|
+
return Promise.resolve();
|
|
193
|
+
}
|
|
194
|
+
shutdown() {
|
|
195
|
+
this.spanMap.clear();
|
|
196
|
+
return Promise.resolve();
|
|
197
|
+
}
|
|
198
|
+
/** Clear all state — for testing. */
|
|
199
|
+
reset() {
|
|
200
|
+
this.spanMap.clear();
|
|
201
|
+
}
|
|
202
|
+
};
|
|
203
|
+
function buildEndParams(t) {
|
|
204
|
+
if (!t) return {};
|
|
205
|
+
const params = {};
|
|
206
|
+
if (t.promptTokens !== void 0) params.prompt_tokens = t.promptTokens;
|
|
207
|
+
if (t.completionTokens !== void 0) params.completion_tokens = t.completionTokens;
|
|
208
|
+
if (t.observationType === "GENERATION") {
|
|
209
|
+
if (t.text !== void 0) {
|
|
210
|
+
params.output = { text: t.text };
|
|
211
|
+
}
|
|
212
|
+
} else if (t.observationType === "TOOL") {
|
|
213
|
+
if (t.output !== void 0) {
|
|
214
|
+
params.output = t.output && typeof t.output === "object" ? t.output : { value: t.output };
|
|
215
|
+
}
|
|
216
|
+
}
|
|
217
|
+
if (t.error) {
|
|
218
|
+
params.level = "ERROR";
|
|
219
|
+
if (t.errorMessage) params.status_message = t.errorMessage;
|
|
220
|
+
}
|
|
221
|
+
return params;
|
|
222
|
+
}
|
|
223
|
+
|
|
224
|
+
// src/agent-task/integrations/register.ts
|
|
225
|
+
var registered = false;
|
|
226
|
+
var currentProcessor = null;
|
|
227
|
+
async function registerApoTracing(_options) {
|
|
228
|
+
if (registered) return;
|
|
229
|
+
registered = true;
|
|
230
|
+
currentProcessor = new ApoSpanProcessor();
|
|
231
|
+
}
|
|
232
|
+
function getRegisteredApoProcessor() {
|
|
233
|
+
return currentProcessor;
|
|
234
|
+
}
|
|
235
|
+
function resetApoTracing() {
|
|
236
|
+
registered = false;
|
|
237
|
+
currentProcessor = null;
|
|
238
|
+
}
|
|
239
|
+
|
|
240
|
+
// src/otel/index.ts
|
|
241
|
+
var w3cPropagator = new W3CTraceContextPropagator();
|
|
242
|
+
var ownedContext = null;
|
|
243
|
+
function createApoTraceExporter(options) {
|
|
244
|
+
return new OTLPTraceExporter({
|
|
245
|
+
url: options.endpoint,
|
|
246
|
+
headers: options.headers
|
|
247
|
+
});
|
|
248
|
+
}
|
|
249
|
+
function createApoSpanProcessor(options) {
|
|
250
|
+
const exporter = createApoTraceExporter(options);
|
|
251
|
+
return options.processor === "simple" ? new SimpleSpanProcessor(exporter) : new BatchSpanProcessor(exporter);
|
|
252
|
+
}
|
|
253
|
+
var DEFAULT_APO_OTLP_ENDPOINT = "http://localhost:8000/api/public/otel/v1/traces";
|
|
254
|
+
function buildApoAuthHeaders(publicKey, secretKey, authToken) {
|
|
255
|
+
const pk = publicKey ?? process.env.APO_PUBLIC_KEY;
|
|
256
|
+
const sk = secretKey ?? process.env.APO_SECRET_KEY;
|
|
257
|
+
const token = authToken ?? process.env.APO_AUTH_TOKEN;
|
|
258
|
+
if (pk && sk) {
|
|
259
|
+
const credentials = typeof btoa === "function" ? btoa(`${pk}:${sk}`) : Buffer.from(`${pk}:${sk}`).toString("base64");
|
|
260
|
+
return { Authorization: `Basic ${credentials}` };
|
|
261
|
+
}
|
|
262
|
+
if (token) {
|
|
263
|
+
return { Authorization: `Bearer ${token}` };
|
|
264
|
+
}
|
|
265
|
+
return {};
|
|
266
|
+
}
|
|
267
|
+
function resolveTelemetryConfig(options) {
|
|
268
|
+
const endpoint = options.endpoint ?? process.env.APO_OTLP_ENDPOINT ?? DEFAULT_APO_OTLP_ENDPOINT;
|
|
269
|
+
const project = options.project ?? process.env.APO_PROJECT;
|
|
270
|
+
const serviceName = options.serviceName ?? "apo-agent";
|
|
271
|
+
const headers = options.headers ?? buildApoAuthHeaders(options.publicKey, options.secretKey, options.authToken);
|
|
272
|
+
return { endpoint, headers, project, serviceName };
|
|
273
|
+
}
|
|
274
|
+
function configureInstrumentationEnvironment() {
|
|
275
|
+
if (!process.env.OTEL_INSTRUMENTATION_GENAI_CAPTURE_MESSAGE_CONTENT) {
|
|
276
|
+
process.env.OTEL_INSTRUMENTATION_GENAI_CAPTURE_MESSAGE_CONTENT = "span_only";
|
|
277
|
+
}
|
|
278
|
+
}
|
|
279
|
+
async function configureApoTelemetry(options) {
|
|
280
|
+
if (options.takeOwnership !== true) {
|
|
281
|
+
throw new TypeError("standalone bootstrap requires takeOwnership: true");
|
|
282
|
+
}
|
|
283
|
+
if (options.provider !== void 0) {
|
|
284
|
+
throw new TypeError(
|
|
285
|
+
"A host provider cannot be mutated after construction in OTel JS 2.x; construct it with createApoSpanProcessor() instead."
|
|
286
|
+
);
|
|
287
|
+
}
|
|
288
|
+
const { endpoint, headers, project, serviceName } = resolveTelemetryConfig(options);
|
|
289
|
+
configureInstrumentationEnvironment();
|
|
290
|
+
const releaseContext = acquireContextManager();
|
|
291
|
+
const resourceAttrs = {
|
|
292
|
+
[SEMRESATTRS_SERVICE_NAME]: serviceName
|
|
293
|
+
};
|
|
294
|
+
if (project) resourceAttrs[SEMRESATTRS_SERVICE_NAMESPACE] = project;
|
|
295
|
+
if (options.serviceVersion) resourceAttrs[SEMRESATTRS_SERVICE_VERSION] = options.serviceVersion;
|
|
296
|
+
if (options.environment) resourceAttrs[SEMRESATTRS_DEPLOYMENT_ENVIRONMENT] = options.environment;
|
|
297
|
+
const resource = resourceFromAttributes(resourceAttrs);
|
|
298
|
+
const spanProcessors = [createApoSpanProcessor({
|
|
299
|
+
endpoint,
|
|
300
|
+
headers,
|
|
301
|
+
processor: options.processor
|
|
302
|
+
})];
|
|
303
|
+
const apoProcessor = getRegisteredApoProcessor();
|
|
304
|
+
if (apoProcessor) {
|
|
305
|
+
spanProcessors.push(apoProcessor);
|
|
306
|
+
}
|
|
307
|
+
const provider = new BasicTracerProvider({
|
|
308
|
+
resource,
|
|
309
|
+
spanProcessors
|
|
310
|
+
});
|
|
311
|
+
const tracer = provider.getTracer("apo-sdk", "0.2.0");
|
|
312
|
+
let registeredGlobal = false;
|
|
313
|
+
if (options.registerGlobal) {
|
|
314
|
+
registeredGlobal = trace.setGlobalTracerProvider(provider);
|
|
315
|
+
}
|
|
316
|
+
let stopped = false;
|
|
317
|
+
return {
|
|
318
|
+
tracer,
|
|
319
|
+
provider,
|
|
320
|
+
async forceFlush() {
|
|
321
|
+
await provider.forceFlush();
|
|
322
|
+
},
|
|
323
|
+
async shutdown() {
|
|
324
|
+
if (stopped) return;
|
|
325
|
+
stopped = true;
|
|
326
|
+
await Promise.race([
|
|
327
|
+
(async () => {
|
|
328
|
+
await provider.forceFlush().catch(() => void 0);
|
|
329
|
+
await provider.shutdown().catch(() => void 0);
|
|
330
|
+
})(),
|
|
331
|
+
new Promise((resolve) => setTimeout(resolve, 2e3))
|
|
332
|
+
]);
|
|
333
|
+
if (registeredGlobal) {
|
|
334
|
+
trace.disable();
|
|
335
|
+
}
|
|
336
|
+
releaseContext();
|
|
337
|
+
}
|
|
338
|
+
};
|
|
339
|
+
}
|
|
340
|
+
function acquireContextManager() {
|
|
341
|
+
if (ownedContext !== null) {
|
|
342
|
+
ownedContext.references += 1;
|
|
343
|
+
const acquired2 = ownedContext;
|
|
344
|
+
return () => releaseOwnedContext(acquired2);
|
|
345
|
+
}
|
|
346
|
+
const manager = new AsyncHooksContextManager().enable();
|
|
347
|
+
if (!context.setGlobalContextManager(manager)) {
|
|
348
|
+
manager.disable();
|
|
349
|
+
return () => void 0;
|
|
350
|
+
}
|
|
351
|
+
const acquired = { manager, references: 1 };
|
|
352
|
+
ownedContext = acquired;
|
|
353
|
+
return () => releaseOwnedContext(acquired);
|
|
354
|
+
}
|
|
355
|
+
function releaseOwnedContext(acquired) {
|
|
356
|
+
if (ownedContext !== acquired) return;
|
|
357
|
+
acquired.references -= 1;
|
|
358
|
+
if (acquired.references > 0) return;
|
|
359
|
+
context.disable();
|
|
360
|
+
ownedContext = null;
|
|
361
|
+
}
|
|
362
|
+
async function withApoTrace(options, tracer, fn) {
|
|
363
|
+
const spanOptions = {};
|
|
364
|
+
if (options.attributes) {
|
|
365
|
+
spanOptions.attributes = options.attributes;
|
|
366
|
+
}
|
|
367
|
+
return new Promise((resolve, reject) => {
|
|
368
|
+
tracer.startActiveSpan(options.name, spanOptions, async (span) => {
|
|
369
|
+
if (options.observationType) {
|
|
370
|
+
span.setAttribute("apo.observation.type", options.observationType);
|
|
371
|
+
}
|
|
372
|
+
try {
|
|
373
|
+
const result = await fn(span);
|
|
374
|
+
span.end();
|
|
375
|
+
resolve(result);
|
|
376
|
+
} catch (err) {
|
|
377
|
+
span.recordException(err);
|
|
378
|
+
span.setStatus({ code: 2, message: err instanceof Error ? err.message : String(err) });
|
|
379
|
+
span.end();
|
|
380
|
+
reject(err);
|
|
381
|
+
}
|
|
382
|
+
});
|
|
383
|
+
});
|
|
384
|
+
}
|
|
385
|
+
async function traceTool(tracer, name, params, fn) {
|
|
386
|
+
return withApoTrace(
|
|
387
|
+
{
|
|
388
|
+
name: `tool ${name}`,
|
|
389
|
+
observationType: "TOOL",
|
|
390
|
+
attributes: {
|
|
391
|
+
"gen_ai.tool.name": name,
|
|
392
|
+
"gen_ai.tool.call.arguments": JSON.stringify(params)
|
|
393
|
+
}
|
|
394
|
+
},
|
|
395
|
+
tracer,
|
|
396
|
+
async (span) => {
|
|
397
|
+
const result = await fn();
|
|
398
|
+
span.setAttribute("gen_ai.tool.call.result", JSON.stringify(result));
|
|
399
|
+
return result;
|
|
400
|
+
}
|
|
401
|
+
);
|
|
402
|
+
}
|
|
403
|
+
async function traceAgent(tracer, name, fn) {
|
|
404
|
+
return withApoTrace(
|
|
405
|
+
{ name, observationType: "AGENT" },
|
|
406
|
+
tracer,
|
|
407
|
+
async () => fn()
|
|
408
|
+
);
|
|
409
|
+
}
|
|
410
|
+
async function traceChain(tracer, name, fn) {
|
|
411
|
+
return withApoTrace(
|
|
412
|
+
{ name, observationType: "CHAIN" },
|
|
413
|
+
tracer,
|
|
414
|
+
async () => fn()
|
|
415
|
+
);
|
|
416
|
+
}
|
|
417
|
+
async function traceRetriever(tracer, query, fn) {
|
|
418
|
+
return withApoTrace(
|
|
419
|
+
{ name: "retrieve", observationType: "RETRIEVER", attributes: { query } },
|
|
420
|
+
tracer,
|
|
421
|
+
async () => fn()
|
|
422
|
+
);
|
|
423
|
+
}
|
|
424
|
+
async function score(params, config) {
|
|
425
|
+
const url = params.observationId ? `${config.endpoint}/api/v1/observations/${params.observationId}/scores` : `${config.endpoint}/api/v1/traces/${params.traceId}/scores`;
|
|
426
|
+
const body = {
|
|
427
|
+
name: params.name,
|
|
428
|
+
value: params.value,
|
|
429
|
+
data_type: params.dataType ?? "NUMERIC",
|
|
430
|
+
source: params.source ?? "API"
|
|
431
|
+
};
|
|
432
|
+
if (params.comment) body.comment = params.comment;
|
|
433
|
+
try {
|
|
434
|
+
const response = await fetch(url, {
|
|
435
|
+
method: "POST",
|
|
436
|
+
headers: { "Content-Type": "application/json", ...config.headers },
|
|
437
|
+
body: JSON.stringify(body)
|
|
438
|
+
});
|
|
439
|
+
if (!response.ok) {
|
|
440
|
+
const text = await response.text().catch(() => "");
|
|
441
|
+
console.error(`[apo score] HTTP ${response.status}: ${text.slice(0, 200)}`);
|
|
442
|
+
}
|
|
443
|
+
} catch (err) {
|
|
444
|
+
console.error("[apo score] failed:", err);
|
|
445
|
+
}
|
|
446
|
+
}
|
|
447
|
+
function injectTraceparent() {
|
|
448
|
+
const carrier = {};
|
|
449
|
+
w3cPropagator.inject(context.active(), carrier, defaultTextMapSetter);
|
|
450
|
+
return carrier;
|
|
451
|
+
}
|
|
452
|
+
async function extractTraceparent(headers, tracer, fn) {
|
|
453
|
+
const extracted = w3cPropagator.extract(context.active(), headers, defaultTextMapGetter);
|
|
454
|
+
const parent = trace.getSpan(extracted);
|
|
455
|
+
if (!parent) {
|
|
456
|
+
return withApoTrace({ name: "inbound" }, tracer, fn);
|
|
457
|
+
}
|
|
458
|
+
return new Promise((resolve, reject) => {
|
|
459
|
+
context.with(extracted, () => {
|
|
460
|
+
tracer.startActiveSpan("inbound", async (span) => {
|
|
461
|
+
try {
|
|
462
|
+
const result = await fn(span);
|
|
463
|
+
span.end();
|
|
464
|
+
resolve(result);
|
|
465
|
+
} catch (err) {
|
|
466
|
+
span.recordException(err);
|
|
467
|
+
span.end();
|
|
468
|
+
reject(err);
|
|
469
|
+
}
|
|
470
|
+
});
|
|
471
|
+
});
|
|
472
|
+
});
|
|
473
|
+
}
|
|
474
|
+
|
|
475
|
+
export {
|
|
476
|
+
withApoRun,
|
|
477
|
+
withApoRunSync,
|
|
478
|
+
getActiveApoRun,
|
|
479
|
+
ApoSpanProcessor,
|
|
480
|
+
registerApoTracing,
|
|
481
|
+
resetApoTracing,
|
|
482
|
+
createApoTraceExporter,
|
|
483
|
+
createApoSpanProcessor,
|
|
484
|
+
buildApoAuthHeaders,
|
|
485
|
+
configureApoTelemetry,
|
|
486
|
+
withApoTrace,
|
|
487
|
+
traceTool,
|
|
488
|
+
traceAgent,
|
|
489
|
+
traceChain,
|
|
490
|
+
traceRetriever,
|
|
491
|
+
score,
|
|
492
|
+
injectTraceparent,
|
|
493
|
+
extractTraceparent
|
|
494
|
+
};
|
|
495
|
+
//# sourceMappingURL=chunk-PMYLL2H4.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/otel/index.ts","../src/agent-task/integrations/run-context.ts","../src/agent-task/integrations/otel-translate.ts","../src/agent-task/integrations/otel-processor.ts","../src/agent-task/integrations/register.ts"],"sourcesContent":["/**\n * OTel-native tracing setup for the apo SDK.\n *\n * This module provides the standard OpenTelemetry setup path for apo:\n * - ``configureApoTelemetry`` creates a tracer provider with an OTLP exporter\n * - ``withApoTrace`` creates root/child spans using standard OTel context\n * - Helper functions (``traceTool``, ``traceAgent``, etc.) emit normal OTel\n * spans with GenAI or apo vendor attributes\n *\n * This replaces the deprecated ``TraceTracker`` custom event protocol. New\n * users should use this module; existing ``TraceTracker`` code continues to\n * work through a compatibility bridge.\n *\n * @module @apo-ai/sdk/otel\n */\n\nimport {\n trace,\n context,\n defaultTextMapGetter,\n defaultTextMapSetter,\n type Span,\n type Tracer,\n type SpanOptions,\n type TracerProvider,\n} from \"@opentelemetry/api\";\nimport { W3CTraceContextPropagator } from \"@opentelemetry/core\";\n\n/**\n * Shared W3C Trace Context propagator. OTel's official implementation handles\n * `traceparent`/`tracestate`, edge cases (invalid traceId/spanId, versioning),\n * and stays correct as the spec evolves — so we delegate to it instead of\n * hand-rolling `00-<trace>-<span>-<flags>` parsing.\n */\nconst w3cPropagator = new W3CTraceContextPropagator();\nimport {\n BasicTracerProvider,\n BatchSpanProcessor,\n SimpleSpanProcessor,\n type SpanExporter,\n type SpanProcessor,\n} from \"@opentelemetry/sdk-trace-base\";\nimport { AsyncHooksContextManager } from \"@opentelemetry/context-async-hooks\";\nimport { resourceFromAttributes } from \"@opentelemetry/resources\";\nimport {\n SEMRESATTRS_SERVICE_NAME,\n SEMRESATTRS_SERVICE_VERSION,\n SEMRESATTRS_SERVICE_NAMESPACE,\n SEMRESATTRS_DEPLOYMENT_ENVIRONMENT,\n} from \"@opentelemetry/semantic-conventions\";\nimport { OTLPTraceExporter } from \"@opentelemetry/exporter-trace-otlp-http\";\nimport { getRegisteredApoProcessor } from \"../agent-task/integrations/register.ts\";\n\n// ── public types ───────────────────────────────────────────\n\nexport interface ConfigureApoTelemetryOptions {\n /** Explicit permission for this standalone helper to own OTel lifecycle. */\n takeOwnership: true;\n /**\n * Full OTLP traces endpoint URL. Falls back to the `APO_OTLP_ENDPOINT` env\n * var when omitted, then to `http://localhost:8000/api/public/otel/v1/traces`.\n */\n endpoint?: string;\n /**\n * Diagnostic resource attribute only. Auth owns tenancy — the project is\n * determined by the API key / service token, never by this field.\n * Falls back to the `APO_PROJECT` env var when omitted.\n */\n project?: string;\n /**\n * Service name for the OTel resource (required). Defaults to `\"apo-agent\"`.\n */\n serviceName?: string;\n /** Service version for the OTel resource. */\n serviceVersion?: string;\n /** Deployment environment (production, staging, etc.). */\n environment?: string;\n /**\n * Auth headers (Authorization: Basic/Bearer). Falls back to headers derived\n * from `APO_PUBLIC_KEY`+`APO_SECRET_KEY` (Basic) or `APO_AUTH_TOKEN` (Bearer)\n * env vars when omitted. Use {@link buildApoAuthHeaders} to build them\n * explicitly.\n */\n headers?: Record<string, string>;\n /**\n * Public key for Basic auth. Falls back to `APO_PUBLIC_KEY` env var.\n * Used with `secretKey` to build `Authorization: Basic base64(pk:sk)`.\n */\n publicKey?: string;\n /**\n * Secret key for Basic auth. Falls back to `APO_SECRET_KEY` env var.\n */\n secretKey?: string;\n /**\n * Bearer auth token. Falls back to `APO_AUTH_TOKEN` env var. Used only when\n * `publicKey`/`secretKey` are absent.\n */\n authToken?: string;\n /**\n * @deprecated OTel JS 2.x providers cannot accept processors after\n * construction. Use `createApoSpanProcessor()` in the host provider's\n * `spanProcessors` array instead.\n */\n provider?: TracerProvider;\n /** Batch for services; simple is useful for short-lived task subprocesses. */\n processor?: \"batch\" | \"simple\";\n /**\n * Whether to register apo's provider as the global tracer provider. Defaults\n * to false. When true, registration only happens if no global provider is\n * registered yet — apo never silently replaces an existing global provider.\n */\n registerGlobal?: boolean;\n}\n\nexport interface ApoTelemetryHandle {\n /** The OTel tracer for creating spans. */\n tracer: Tracer;\n /** The provider, for advanced use. */\n provider: TracerProvider;\n /** Export all ended spans without relinquishing provider ownership. */\n forceFlush(): Promise<void>;\n /** Gracefully shut down the provider and flush pending spans. */\n shutdown(): Promise<void>;\n}\n\nexport interface ApoTraceExporterOptions {\n /** Full standard OTLP/HTTP traces endpoint. */\n endpoint: string;\n /** Authentication headers sent by the official OTLP exporter. */\n headers: Record<string, string>;\n}\n\nexport interface ApoSpanProcessorOptions extends ApoTraceExporterOptions {\n /** Batch for long-lived services (default), simple for short-lived jobs. */\n processor?: \"batch\" | \"simple\";\n}\n\nexport interface ApoTraceOptions {\n /** Span name. */\n name: string;\n /** apo.observation.type override. */\n observationType?: string;\n /** Additional attributes. */\n attributes?: Record<string, unknown>;\n}\n\ninterface OwnedContextState {\n manager: AsyncHooksContextManager;\n references: number;\n}\n\nlet ownedContext: OwnedContextState | null = null;\n\n/** Create the official OTLP/HTTP exporter for a host-owned OTel provider. */\nexport function createApoTraceExporter(\n options: ApoTraceExporterOptions,\n): SpanExporter {\n return new OTLPTraceExporter({\n url: options.endpoint,\n headers: options.headers,\n });\n}\n\n/**\n * Create an apo OTLP processor for inclusion when constructing a host provider.\n * This factory has no global side effects and transfers lifecycle ownership to\n * the host provider.\n */\nexport function createApoSpanProcessor(\n options: ApoSpanProcessorOptions,\n): SpanProcessor {\n const exporter = createApoTraceExporter(options);\n return options.processor === \"simple\"\n ? new SimpleSpanProcessor(exporter)\n : new BatchSpanProcessor(exporter);\n}\n\n// ── auth + env-var helpers (mirror apo-otel-python) ─────────────────────\n\nconst DEFAULT_APO_OTLP_ENDPOINT = \"http://localhost:8000/api/public/otel/v1/traces\";\n\n/**\n * Build the `Authorization` header for apo's OTLP endpoint.\n *\n * - If `publicKey` + `secretKey` are given (or read from `APO_PUBLIC_KEY` /\n * `APO_SECRET_KEY`), returns HTTP Basic: `Basic base64(pk:sk)`. * both halves are required — a public identifier alone is not a\n * credential, so partial Basic is never synthesized.\n * - Else if `authToken` is given (or read from `APO_AUTH_TOKEN`), returns\n * `Bearer <token>`. (Covers short-lived task-run/attempt tokens and\n * secret-bearing legacy API keys.)\n * - Else returns an empty object (unauthenticated).\n *\n * Mirrors Python's `_build_auth_headers` in apo-otel-python.\n */\nexport function buildApoAuthHeaders(\n publicKey?: string,\n secretKey?: string,\n authToken?: string,\n): Record<string, string> {\n const pk = publicKey ?? process.env.APO_PUBLIC_KEY;\n const sk = secretKey ?? process.env.APO_SECRET_KEY;\n const token = authToken ?? process.env.APO_AUTH_TOKEN;\n if (pk && sk) {\n const credentials = typeof btoa === \"function\"\n ? btoa(`${pk}:${sk}`)\n : Buffer.from(`${pk}:${sk}`).toString(\"base64\");\n return { Authorization: `Basic ${credentials}` };\n }\n if (token) {\n return { Authorization: `Bearer ${token}` };\n }\n return {};\n}\n\n/**\n * Resolve telemetry config: explicit kwarg wins, else env var, else default.\n * Mirrors Python's `_resolve_standalone_configuration`.\n */\nfunction resolveTelemetryConfig(options: ConfigureApoTelemetryOptions): {\n endpoint: string;\n headers: Record<string, string>;\n project: string | undefined;\n serviceName: string;\n} {\n const endpoint = options.endpoint\n ?? process.env.APO_OTLP_ENDPOINT\n ?? DEFAULT_APO_OTLP_ENDPOINT;\n const project = options.project ?? process.env.APO_PROJECT;\n const serviceName = options.serviceName ?? \"apo-agent\";\n const headers = options.headers\n ?? buildApoAuthHeaders(options.publicKey, options.secretKey, options.authToken);\n return { endpoint, headers, project, serviceName };\n}\n\n/**\n * Set the GenAI content-capture env var so instrumentation libs emit prompt\n * and completion text into spans. Uses `setdefault`-equivalent semantics: an\n * explicit user setting is never overridden. Mirrors Python's\n * `_configure_instrumentation_environment`.\n */\nfunction configureInstrumentationEnvironment(): void {\n if (!process.env.OTEL_INSTRUMENTATION_GENAI_CAPTURE_MESSAGE_CONTENT) {\n process.env.OTEL_INSTRUMENTATION_GENAI_CAPTURE_MESSAGE_CONTENT = \"span_only\";\n }\n}\n\n// ── configureApoTelemetry ────────────────────────────────────────────────\n\n/**\n * Configure apo's OpenTelemetry tracing.\n *\n * Builds apo's trace export from official OTel components: a real\n * {@link Resource} (service.name, service.version, deployment.environment)\n * and the official {@link OTLPTraceExporter} (standard OTLP/HTTP, no custom\n * wire format). This is the explicit standalone bootstrap. Host applications\n * that already own a provider should use `createApoSpanProcessor()` instead.\n *\n * @example\n * ```ts\n * import { configureApoTelemetry } from \"@apo-ai/sdk/otel\";\n *\n * const apo = await configureApoTelemetry({\n * takeOwnership: true,\n * endpoint: \"https://apo.example.com/api/public/otel/v1/traces\",\n * serviceName: \"my-agent\",\n * headers: { Authorization: `Basic ${btoa(\"pk-apo-...:sk-apo-...\")}` },\n * });\n *\n * const result = await withApoTrace({ name: \"chat\" }, apo.tracer, async (span) => {\n * span.setAttribute(\"gen_ai.request.model\", \"gpt-4o\");\n * // ... do work ...\n * return \"done\";\n * });\n *\n * await apo.shutdown();\n * ```\n */\nexport async function configureApoTelemetry(\n options: ConfigureApoTelemetryOptions,\n): Promise<ApoTelemetryHandle> {\n if (options.takeOwnership !== true) {\n throw new TypeError(\"standalone bootstrap requires takeOwnership: true\");\n }\n if (options.provider !== undefined) {\n throw new TypeError(\n \"A host provider cannot be mutated after construction in OTel JS 2.x; \" +\n \"construct it with createApoSpanProcessor() instead.\",\n );\n }\n\n // Resolve config from kwargs → env vars → defaults (mirror apo-otel-python).\n const { endpoint, headers, project, serviceName } = resolveTelemetryConfig(options);\n\n // Enable prompt/completion content capture for instrumentation libs.\n configureInstrumentationEnvironment();\n\n // Set up the async context manager so context.active() carries the active\n // span. Concurrent apo handles share one owned manager; a host-owned manager\n // is used as-is and is never disabled by apo.\n const releaseContext = acquireContextManager();\n\n // Build the official OTel Resource with standard semantic attributes.\n const resourceAttrs: Record<string, string> = {\n [SEMRESATTRS_SERVICE_NAME]: serviceName,\n };\n if (project) resourceAttrs[SEMRESATTRS_SERVICE_NAMESPACE] = project;\n if (options.serviceVersion) resourceAttrs[SEMRESATTRS_SERVICE_VERSION] = options.serviceVersion;\n if (options.environment) resourceAttrs[SEMRESATTRS_DEPLOYMENT_ENVIRONMENT] = options.environment;\n const resource = resourceFromAttributes(resourceAttrs);\n\n // Official OTLP/HTTP trace exporter — standard OTLP wire format, no custom\n // serializer. Headers carry the auth the apo receiver validates.\n // The standalone path owns this provider. Host-owned providers compose with\n // createApoSpanProcessor() at their own construction boundary.\n const spanProcessors: SpanProcessor[] = [createApoSpanProcessor({\n endpoint,\n headers,\n processor: options.processor,\n })];\n\n // If an ApoSpanProcessor was registered via registerApoTracing(), add it to\n // this provider so GenAI spans from SDKs (Vercel AI, OpenAI, etc.) are fed\n // into the projection-tee for local assertions AND exported via OTLP.\n const apoProcessor = getRegisteredApoProcessor();\n if (apoProcessor) {\n spanProcessors.push(apoProcessor as unknown as SpanProcessor);\n }\n\n const provider = new BasicTracerProvider({\n resource,\n spanProcessors,\n });\n\n const tracer = provider.getTracer(\"apo-sdk\", \"0.2.0\");\n\n // Register globally only when explicitly requested AND no host provider was\n // supplied AND no global provider is registered yet. apo never silently\n // replaces a host/global provider.\n let registeredGlobal = false;\n if (options.registerGlobal) {\n registeredGlobal = trace.setGlobalTracerProvider(provider);\n }\n\n let stopped = false;\n\n return {\n tracer,\n provider,\n async forceFlush() {\n await provider.forceFlush();\n },\n async shutdown() {\n if (stopped) return;\n stopped = true;\n // Force-flush + shut down the provider, but bound the whole teardown so\n // an unreachable export endpoint (e.g. no backend in unit tests) never\n // hangs the process. The span processors/exporters swallow their own\n // transport errors; this guards against the wait itself.\n await Promise.race([\n (async () => {\n await provider.forceFlush().catch(() => undefined);\n await provider.shutdown().catch(() => undefined);\n })(),\n new Promise<void>((resolve) => setTimeout(resolve, 2000)),\n ]);\n // Reset global state so a later configuration starts clean.\n if (registeredGlobal) {\n trace.disable();\n }\n releaseContext();\n },\n };\n}\n\nfunction acquireContextManager(): () => void {\n if (ownedContext !== null) {\n ownedContext.references += 1;\n const acquired = ownedContext;\n return () => releaseOwnedContext(acquired);\n }\n\n const manager = new AsyncHooksContextManager().enable();\n if (!context.setGlobalContextManager(manager)) {\n manager.disable();\n return () => undefined;\n }\n\n const acquired: OwnedContextState = { manager, references: 1 };\n ownedContext = acquired;\n return () => releaseOwnedContext(acquired);\n}\n\nfunction releaseOwnedContext(acquired: OwnedContextState): void {\n if (ownedContext !== acquired) return;\n acquired.references -= 1;\n if (acquired.references > 0) return;\n context.disable();\n ownedContext = null;\n}\n\n// ── withApoTrace ─────────────────────────────────────────────────────────\n\n/**\n * Run a function inside an OTel span.\n *\n * Creates a span using the active OTel context (standard context propagation,\n * not apo-specific span IDs passed by hand). The span automatically ends when\n * the function returns or throws.\n *\n * @example\n * ```ts\n * const result = await withApoTrace(\n * { name: \"agent-turn\", observationType: \"AGENT\" },\n * apo.tracer,\n * async (span) => {\n * span.setAttribute(\"gen_ai.request.model\", \"gpt-4o\");\n * return await llm.complete(\"hello\");\n * },\n * );\n * ```\n */\nexport async function withApoTrace<T>(\n options: ApoTraceOptions,\n tracer: Tracer,\n fn: (span: Span) => Promise<T>,\n): Promise<T> {\n const spanOptions: SpanOptions = {};\n if (options.attributes) {\n spanOptions.attributes = options.attributes as Record<string, string | number | boolean>;\n }\n\n // Use startActiveSpan which creates the span AND activates it in context,\n // so nested withApoTrace calls automatically inherit it as parent.\n return new Promise<T>((resolve, reject) => {\n tracer.startActiveSpan(options.name, spanOptions, async (span: Span) => {\n // Set apo vendor attributes\n if (options.observationType) {\n span.setAttribute(\"apo.observation.type\", options.observationType);\n }\n\n try {\n const result = await fn(span);\n span.end();\n resolve(result);\n } catch (err) {\n span.recordException(err as Error);\n span.setStatus({ code: 2, message: err instanceof Error ? err.message : String(err) });\n span.end();\n reject(err);\n }\n });\n });\n}\n\n// ── helper functions ─────────────────────────────────────────────────────\n\n/**\n * Trace a tool execution as an OTel span.\n *\n * Creates a span with ``gen_ai.tool.name``, ``gen_ai.tool.call.arguments``,\n * and ``gen_ai.tool.call.result`` attributes so the backend normalizer\n * classifies it as a TOOL observation.\n */\nexport async function traceTool<T>(\n tracer: Tracer,\n name: string,\n params: Record<string, unknown>,\n fn: () => Promise<T>,\n): Promise<T> {\n return withApoTrace(\n {\n name: `tool ${name}`,\n observationType: \"TOOL\",\n attributes: {\n \"gen_ai.tool.name\": name,\n \"gen_ai.tool.call.arguments\": JSON.stringify(params),\n },\n },\n tracer,\n async (span) => {\n const result = await fn();\n span.setAttribute(\"gen_ai.tool.call.result\", JSON.stringify(result));\n return result;\n },\n );\n}\n\n/**\n * Trace an agent invocation as an OTel span.\n */\nexport async function traceAgent<T>(\n tracer: Tracer,\n name: string,\n fn: () => Promise<T>,\n): Promise<T> {\n return withApoTrace(\n { name, observationType: \"AGENT\" },\n tracer,\n async () => fn(),\n );\n}\n\n/**\n * Trace a chain/step as an OTel span.\n */\nexport async function traceChain<T>(\n tracer: Tracer,\n name: string,\n fn: () => Promise<T>,\n): Promise<T> {\n return withApoTrace(\n { name, observationType: \"CHAIN\" },\n tracer,\n async () => fn(),\n );\n}\n\n/**\n * Trace a retrieval as an OTel span.\n */\nexport async function traceRetriever<T>(\n tracer: Tracer,\n query: string,\n fn: () => Promise<T>,\n): Promise<T> {\n return withApoTrace(\n { name: \"retrieve\", observationType: \"RETRIEVER\", attributes: { query } },\n tracer,\n async () => fn(),\n );\n}\n\n// ── Score API ─────────\n\nexport interface ScoreOptions {\n name: string;\n value: number | string | boolean;\n dataType?: \"NUMERIC\" | \"CATEGORICAL\" | \"BOOLEAN\";\n source?: \"API\" | \"EVAL\" | \"ANNOTATION\";\n comment?: string;\n observationId?: string;\n}\n\n/**\n * Record a score for a trace (or a specific observation within a trace).\n *\n * \"A Score is an apo domain record attached to a Trace or\n * Observation. It is not encoded as a fake span.\"\n *\n * This calls the native score API (`POST /api/v1/traces/{id}/scores` or\n * `POST /api/v1/observations/{id}/scores`) instead of creating a sentinel\n * span. The score is stored as a `RunMetricDB` or `CallMetricDB` row.\n *\n * @example\n * ```ts\n * await score({\n * traceId: \"abc123...\",\n * name: \"helpfulness\",\n * value: 0.85,\n * dataType: \"NUMERIC\",\n * source: \"EVAL\",\n * }, { endpoint: \"http://localhost:8000\", headers: authHeaders });\n * ```\n */\nexport async function score(\n params: ScoreOptions & { traceId: string },\n config: { endpoint: string; headers: Record<string, string> },\n): Promise<void> {\n const url = params.observationId\n ? `${config.endpoint}/api/v1/observations/${params.observationId}/scores`\n : `${config.endpoint}/api/v1/traces/${params.traceId}/scores`;\n\n const body: Record<string, unknown> = {\n name: params.name,\n value: params.value,\n data_type: params.dataType ?? \"NUMERIC\",\n source: params.source ?? \"API\",\n };\n if (params.comment) body.comment = params.comment;\n\n try {\n const response = await fetch(url, {\n method: \"POST\",\n headers: { \"Content-Type\": \"application/json\", ...config.headers },\n body: JSON.stringify(body),\n });\n if (!response.ok) {\n const text = await response.text().catch(() => \"\");\n console.error(`[apo score] HTTP ${response.status}: ${text.slice(0, 200)}`);\n }\n } catch (err) {\n console.error(\"[apo score] failed:\", err);\n }\n}\n\n// ── W3C trace context propagation ───────────────\n\n/**\n * Inject the current span's trace context into a headers dict for outbound\n * HTTP/queue calls. Produces a standard W3C `traceparent` header so the\n * downstream service can extract it and create a child span in the same trace.\n *\n * Delegates to OTel's official `W3CTraceContextPropagator`, which also emits\n * `tracestate` and handles the spec's edge cases.\n *\n * @example\n * ```ts\n * const headers = injectTraceparent();\n * await fetch(\"http://downstream-service/api\", { headers });\n * ```\n */\nexport function injectTraceparent(): Record<string, string> {\n const carrier: Record<string, string> = {};\n w3cPropagator.inject(context.active(), carrier, defaultTextMapSetter);\n return carrier;\n}\n\n/**\n * Extract a W3C trace context from inbound headers and run a function as a\n * child span within that trace. If no `traceparent` header is present (or it\n * is malformed), a new root span is created.\n *\n * Transport parsing is delegated to OTel's `W3CTraceContextPropagator`; the\n * span creation on top of the extracted remote parent is apo-specific and\n * kept here.\n *\n * @example\n * ```ts\n * // In a downstream HTTP handler:\n * app.post(\"/api\", (req, res) => {\n * const result = await extractTraceparent(req.headers, tracer, async (span) => {\n * return await doWork();\n * });\n * res.json(result);\n * });\n * ```\n */\nexport async function extractTraceparent<T>(\n headers: Record<string, string>,\n tracer: Tracer,\n fn: (span: Span) => Promise<T>,\n): Promise<T> {\n // Extract the upstream context. The propagator handles invalid/missing\n // traceparent by returning the input context unchanged (no extracted span).\n const extracted = w3cPropagator.extract(context.active(), headers, defaultTextMapGetter);\n const parent = trace.getSpan(extracted);\n if (!parent) {\n // No upstream context → new root span\n return withApoTrace({ name: \"inbound\" }, tracer, fn);\n }\n\n // Create a child span in the extracted context (shares the upstream traceId).\n return new Promise<T>((resolve, reject) => {\n context.with(extracted, () => {\n tracer.startActiveSpan(\"inbound\", async (span: Span) => {\n try {\n const result = await fn(span);\n span.end();\n resolve(result);\n } catch (err) {\n span.recordException(err as Error);\n span.end();\n reject(err);\n }\n });\n });\n });\n}\n","/**\n * Per-run context propagation via Node's AsyncLocalStorage.\n *\n * The OTel {@link ApoSpanProcessor} is global — it doesn't know which run a\n * span belongs to. This module solves that: {@link withApoRun} establishes\n * the run's trace context on AsyncLocalStorage, and any code called during\n * the run (including the processor's `onStart`/`onEnd`) can read it via\n * {@link getActiveApoRun}.\n *\n * This is the same propagation mechanism OTel's own\n * `AsyncLocalStorageContextManager` uses under the hood.\n *\n * @module\n */\n\nimport { AsyncLocalStorage } from \"node:async_hooks\";\nimport type { AgentTaskTraceContext } from \"../tracing.ts\";\n\nexport interface ApoRunContext {\n /** The tee'd trace context for this run. */\n trace: AgentTaskTraceContext;\n /** The parent span id (the run's root span or the current turn span). */\n parentSpanId?: string;\n /** The task id, surfaced in span metadata. */\n taskId?: string;\n /** The current turn number, surfaced in span metadata. */\n turnNumber?: number;\n}\n\nconst runStorage = new AsyncLocalStorage<ApoRunContext>();\n\n/**\n * Run `fn` with `ctx` as the active apo run context. Any code inside `fn`\n * (including across `await` boundaries) can call {@link getActiveApoRun}\n * to retrieve it.\n */\nexport function withApoRun<T>(ctx: ApoRunContext, fn: () => Promise<T>): Promise<T> {\n return runStorage.run(ctx, fn);\n}\n\n/**\n * Run `fn` synchronously with `ctx` as the active apo run context.\n */\nexport function withApoRunSync<T>(ctx: ApoRunContext, fn: () => T): T {\n return runStorage.run(ctx, fn);\n}\n\n/**\n * Get the active run context, or `undefined` if called outside a run.\n *\n * This is what the {@link ApoSpanProcessor} calls in `onStart`/`onEnd` to\n * know which run a span belongs to.\n */\nexport function getActiveApoRun(): ApoRunContext | undefined {\n return runStorage.getStore();\n}\n","/**\n * Shared span-translation helpers for the tracing integrations.\n *\n * Maps OpenTelemetry spans from both the Vercel AI SDK (`ai.*` attributes)\n * and the standard GenAI semantic conventions (`gen_ai.*` attributes) to\n * apo's observation types (`TOOL`, `GENERATION`, `AGENT`).\n *\n * Used by:\n * - {@link ApoSpanProcessor} (the OTel-native path)\n * - `createApoTracer` (the per-turn AI SDK tracer)\n *\n * @module\n */\n\n// ── shared utility functions ─────────────────────────────────────────────\n\nimport { extractTokenCounts } from \"./token-usage.ts\";\n\n/** Parse a JSON string, returning the original value if parsing fails. */\nexport function safeParse(raw: unknown): unknown {\n if (typeof raw !== \"string\") return raw;\n try {\n return JSON.parse(raw);\n } catch {\n return raw;\n }\n}\n\n/** High-resolution monotonic timestamp in milliseconds. */\nexport function monotonicNowMs(): number {\n if (typeof performance !== \"undefined\" && typeof performance.now === \"function\") {\n return performance.now();\n }\n return Date.now();\n}\n\n/** Round to 3 decimal places (for latency precision). */\nexport function round3(n: number): number {\n return Math.round(n * 1000) / 1000;\n}\n\n// ── the translation contract ─────────────────────────────────────────────\n\n/**\n * apo observation types that the FlowTee recognizes. Only spans with one\n * of these types become FlowEvents that `t.*` assertions read.\n */\nexport type ApoObservationType = \"TOOL\" | \"GENERATION\" | \"AGENT\";\n\n/**\n * The result of translating an OTel span to apo's format.\n * `null` means the span is not load-bearing (housekeeping, internal, etc.)\n * and should be ignored.\n */\nexport interface TranslatedSpan {\n observationType: ApoObservationType;\n stepName: string;\n /** Model name (for GENERATION spans). */\n model?: string;\n /** Tool call input (for TOOL spans). */\n input?: Record<string, unknown>;\n /** Tool call result (set on end, not start). */\n output?: unknown;\n /** Generation text (for GENERATION spans). */\n text?: string;\n promptTokens?: number;\n completionTokens?: number;\n error?: boolean;\n errorMessage?: string;\n}\n\n/**\n * An OTel span's attributes and status, in a shape that doesn't require\n * importing `@opentelemetry/api` at the type level.\n */\nexport interface OtelSpanData {\n attributes: Record<string, unknown>;\n status: { code: number; message?: string };\n}\n\n/**\n * Translate an OTel span to apo's observation format.\n *\n * Handles both attribute conventions:\n * - **AI SDK** (`ai.*`): `ai.toolCall.*`, `ai.generateText`, `ai.streamText`\n * - **GenAI standard** (`gen_ai.*`): `gen_ai.tool.*`, `gen_ai.operation.name`\n *\n * Returns `null` for spans that aren't load-bearing (internal housekeeping,\n * non-GenAI operations, etc.).\n */\nexport function translateOtelSpan(\n spanName: string,\n data: OtelSpanData,\n): TranslatedSpan | null {\n const { attributes, status } = data;\n const isError = status.code === 2;\n const errorMessage = status.message;\n\n // ── AI SDK convention (ai.*) ────────────────────────────────────────\n\n if (spanName === \"ai.toolCall\") {\n return {\n observationType: \"TOOL\",\n stepName: String(attributes[\"ai.toolCall.name\"] ?? \"unknown\"),\n input: safeParse(attributes[\"ai.toolCall.args\"]) as Record<string, unknown>,\n output: safeParse(attributes[\"ai.toolCall.result\"]),\n error: isError,\n errorMessage,\n };\n }\n\n // The AI SDK emits a parent span (ai.generateText) and per-step child spans\n // (ai.generateText.doGenerate). The parent span carries:\n // - ai.model.id (at creation)\n // - ai.prompt.messages (the input, at creation)\n // - ai.response.text (the final assembled text, set at end)\n // - ai.usage.promptTokens/completionTokens (total usage, set at end)\n // The child doGenerate spans carry per-step data but NOT the final text.\n // We translate the parent span (which has the complete picture) and skip\n // the per-step child spans.\n if (\n spanName === \"ai.generateText\" ||\n spanName === \"ai.streamText\"\n ) {\n return {\n observationType: \"GENERATION\",\n stepName: \"agent.generate\",\n text: extractTextFromAttrs(attributes),\n model: String(\n attributes[\"gen_ai.request.model\"] ??\n attributes[\"ai.model.id\"] ??\n attributes[\"ai.response.model\"] ??\n \"unknown\",\n ),\n ...extractTokenCounts(attributes),\n error: isError,\n errorMessage,\n };\n }\n\n // ── Standard OTel GenAI conventions (gen_ai.*) ─────────────────────\n\n const operation = attributes[\"gen_ai.operation.name\"];\n\n // Tool execution span\n if (\n operation === \"execute_tool\" ||\n spanName.startsWith(\"gen_ai.tool\") ||\n (spanName.includes(\"tool\") && attributes[\"gen_ai.tool.name\"])\n ) {\n return {\n observationType: \"TOOL\",\n stepName: String(attributes[\"gen_ai.tool.name\"] ?? \"unknown\"),\n input: safeParse(attributes[\"gen_ai.tool.call.arguments\"]) as Record<string, unknown>,\n output: safeParse(attributes[\"gen_ai.tool.call.result\"]),\n error: isError,\n errorMessage,\n };\n }\n\n // Agent invocation span\n if (operation === \"invoke_agent\") {\n return {\n observationType: \"AGENT\",\n stepName: String(attributes[\"gen_ai.agent.name\"] ?? \"agent\"),\n output: safeParse(attributes[\"gen_ai.tool.call.result\"]),\n error: isError,\n errorMessage,\n };\n }\n\n // Chat / generation span\n if (\n operation === \"chat\" ||\n operation === \"generate_content\" ||\n operation === \"text_completion\"\n ) {\n return {\n observationType: \"GENERATION\",\n stepName: \"agent.generate\",\n text: extractTextFromAttrs(attributes, \"gen_ai.\"),\n ...extractTokenCounts(attributes),\n error: isError,\n errorMessage,\n };\n }\n\n // ── Not a load-bearing span ────────────────────────────────────────\n\n return null;\n}\n\n/**\n * Extract the model's text response from span attributes.\n * Tries both `ai.*` and `gen_ai.*` response keys.\n */\nexport function extractTextFromAttrs(\n attrs: Record<string, unknown>,\n prefix?: string,\n): string | undefined {\n const candidates = prefix === \"gen_ai.\"\n ? [\"gen_ai.completion\", \"gen_ai.response.text\"]\n : prefix === \"ai.\"\n ? [\"ai.response.text\", \"ai.response.output\", \"ai.generateText.result\"]\n : [\n \"gen_ai.completion\",\n \"gen_ai.response.text\",\n \"ai.response.text\",\n \"ai.response.output\",\n \"ai.generateText.result\",\n ];\n\n for (const key of candidates) {\n const val = attrs[key];\n if (typeof val === \"string\" && val.length > 0) {\n const parsed = safeParse(val);\n return typeof parsed === \"string\" ? parsed : val;\n }\n }\n return undefined;\n}\n","/**\n * ApoSpanProcessor — an OpenTelemetry SpanProcessor that routes GenAI spans\n * into apo's Flow.\n *\n * This is the OTel-native tracing path. After calling {@link registerApoTracing},\n * any SDK that emits OTel spans (Vercel AI SDK, OpenAI Agents SDK, etc.)\n * will be traced automatically — no per-SDK wrapper needed.\n *\n * The processor is global, but run isolation is maintained via\n * {@link AsyncLocalStorage}: {@link getActiveApoRun} returns the current\n * run's trace context, so each span is routed to the correct run's FlowTee.\n *\n * **Design: eager creation, deferred completion.** The apo span is created\n * at `onStart` (when initial attributes like tool name and model are\n * available). The span is ended at `onEnd` with the final attributes\n * (results, tokens, text). This gives correct ordering: parent spans\n * are created before children, matching the real call hierarchy.\n *\n * @module\n */\n\nimport { getActiveApoRun } from \"./run-context.ts\";\nimport {\n translateOtelSpan,\n round3,\n monotonicNowMs,\n type TranslatedSpan,\n} from \"./otel-translate.ts\";\n\n// ── minimal OTel type shapes (no runtime dependency on @opentelemetry/api) ──\n\ninterface OTelSpanContext {\n spanId: string;\n traceId: string;\n traceFlags: number;\n}\n\ninterface OTelSpanStatus {\n code: number;\n message?: string;\n}\n\ninterface OTelReadableSpan {\n name: string;\n spanContext(): OTelSpanContext;\n parentSpanContext?: OTelSpanContext;\n attributes: Record<string, unknown>;\n status: OTelSpanStatus;\n duration: [number, number];\n startTime: [number, number];\n ended: boolean;\n}\n\ninterface OTelSpan extends OTelReadableSpan {\n setAttribute(key: string, value: unknown): this;\n setAttributes(attributes: Record<string, unknown>): this;\n setStatus(status: OTelSpanStatus): this;\n recordException(exception: unknown): void;\n updateName(name: string): this;\n end(endTime?: unknown): void;\n isRecording(): boolean;\n}\n\ninterface OTelContext {\n getValue(key: symbol): unknown;\n setValue(key: symbol, value: unknown): OTelContext;\n deleteValue(key: symbol): OTelContext;\n}\n\ninterface OTelSpanProcessorLifecycle {\n forceFlush(): Promise<void>;\n shutdown(): Promise<void>;\n}\n\n/**\n * Tracks an active span: the apo span ID, the OTel span name, and the\n * start timestamp for latency calculation.\n */\ninterface TrackedSpan {\n apoSpanId: string;\n otelSpanName: string;\n startedAt: number;\n}\n\n/**\n * A SpanProcessor that translates GenAI OTel spans into apo observations.\n *\n * Spans are created at `onStart` (eager) and completed at `onEnd`\n * (deferred). This gives correct parent/child ordering — parent spans\n * are created before their children, matching the real call hierarchy.\n *\n * If a span isn't load-bearing (not a GenAI tool/generation span), no\n * apo span is created.\n */\nexport class ApoSpanProcessor implements OTelSpanProcessorLifecycle {\n private spanMap = new Map<string, TrackedSpan>();\n\n onStart(span: OTelSpan, _parentContext: OTelContext): void {\n const run = getActiveApoRun();\n if (!run) return;\n\n // Quick check: is this span potentially load-bearing?\n // At onStart, the AI SDK has already set the initial attributes\n // (ai.toolCall.name, ai.toolCall.args for tool spans; ai.model.id\n // for generation spans). So we CAN translate now.\n const translated = translateOtelSpan(span.name, {\n attributes: span.attributes ?? {},\n status: { code: 0 }, // no error at start\n });\n if (!translated) return; // not load-bearing — skip\n\n // Resolve parent: check if the parent OTel span has an apo mapping\n const parentOtelId = span.parentSpanContext?.spanId;\n const parentTracked = parentOtelId ? this.spanMap.get(parentOtelId) : undefined;\n const parentApoId = parentTracked?.apoSpanId || run.parentSpanId || run.trace.rootSpanId;\n\n // Create the apo span eagerly (at start time)\n const apoSpanId = run.trace.createSpan({\n task_id: run.taskId ?? \"otel-trace\",\n parent_call_id: parentApoId,\n step_name: translated.stepName,\n model: translated.model ?? translated.stepName,\n observation_type: translated.observationType,\n ...(translated.input ? { input: translated.input } : {}),\n metadata: {\n ...(run.taskId ? { taskId: run.taskId } : {}),\n ...(run.turnNumber !== undefined ? { turnNumber: run.turnNumber } : {}),\n source: \"otel-processor\",\n },\n });\n\n this.spanMap.set(span.spanContext().spanId, {\n apoSpanId,\n otelSpanName: span.name,\n startedAt: monotonicNowMs(),\n });\n }\n\n onEnd(span: OTelReadableSpan): void {\n const otelId = span.spanContext().spanId;\n const tracked = this.spanMap.get(otelId);\n if (!tracked) return; // wasn't tracked (not load-bearing or outside run)\n this.spanMap.delete(otelId);\n\n const run = getActiveApoRun();\n if (!run) return;\n\n // Re-translate with final attributes (results, text, tokens set during execution)\n const translated = translateOtelSpan(tracked.otelSpanName, {\n attributes: span.attributes ?? {},\n status: span.status ?? { code: 0 },\n });\n\n const latency = round3(monotonicNowMs() - tracked.startedAt);\n\n // End the apo span with the final data\n run.trace.endSpan(tracked.apoSpanId, {\n latency_ms: latency,\n ...buildEndParams(translated),\n });\n }\n\n forceFlush(): Promise<void> {\n return Promise.resolve();\n }\n\n shutdown(): Promise<void> {\n this.spanMap.clear();\n return Promise.resolve();\n }\n\n /** Clear all state — for testing. */\n reset(): void {\n this.spanMap.clear();\n }\n}\n\n/**\n * Build the `endSpan` params from the translated span.\n * Handles observation-type-specific output shapes.\n */\nfunction buildEndParams(t: TranslatedSpan | null): Record<string, unknown> {\n if (!t) return {};\n\n const params: Record<string, unknown> = {};\n\n if (t.promptTokens !== undefined) params.prompt_tokens = t.promptTokens;\n if (t.completionTokens !== undefined) params.completion_tokens = t.completionTokens;\n\n if (t.observationType === \"GENERATION\") {\n if (t.text !== undefined) {\n params.output = { text: t.text };\n }\n } else if (t.observationType === \"TOOL\") {\n if (t.output !== undefined) {\n params.output =\n t.output && typeof t.output === \"object\"\n ? (t.output as Record<string, unknown>)\n : { value: t.output };\n }\n }\n\n if (t.error) {\n params.level = \"ERROR\";\n if (t.errorMessage) params.status_message = t.errorMessage;\n }\n\n return params;\n}\n","/**\n * Registration API for the OTel-native tracing integration.\n *\n * Call {@link registerApoTracing} once at startup (e.g., in `startSession`\n * or at module load). After this, any SDK that emits OTel spans during a run\n * will be traced automatically — no per-SDK wrapper needed.\n *\n * @example\n * ```ts\n * import { registerApoTracing } from \"@apo-ai/sdk/agent-task\";\n *\n * async startSession(ctx) {\n * registerApoTracing(); // one line, once\n * return { async sendUserTurn(turn) { ... } };\n * }\n * ```\n *\n * @module\n */\n\nimport { ApoSpanProcessor } from \"./otel-processor.ts\";\n\n// We use dynamic imports for @opentelemetry so the module is importable\n// without the packages installed. In practice they're transitive deps of `ai`.\n\nlet registered = false;\nlet currentProcessor: ApoSpanProcessor | null = null;\n\nexport interface RegisterApoTracingOptions {\n /**\n * Set as the global tracer provider (default: true).\n * Set to false if the host app has its own OTel setup and you want to\n * add apo's processor to an existing provider instead.\n */\n setGlobal?: boolean;\n}\n\n/**\n * Register apo's OTel SpanProcessor. Idempotent — calling it more than\n * once is a no-op.\n *\n * After registration, any OTel span created during an apo run (inside\n * `withApoRun`) that matches the GenAI conventions (`ai.*` or `gen_ai.*`)\n * is automatically translated and fed into the run's Flow.\n */\nexport async function registerApoTracing(\n _options?: RegisterApoTracingOptions,\n): Promise<void> {\n if (registered) return;\n registered = true;\n\n // Create the processor but DON'T register our own provider. The processor\n // is picked up by configureApoTelemetry (via getRegisteredApoProcessor)\n // and added to the OTLP-exporting provider. This ensures GenAI spans from\n // SDKs (Vercel AI, OpenAI, etc.) reach BOTH the projection-tee (for local\n // assertions) AND the OTLP exporter (for the backend), all through a single\n // global provider — no competing providers.\n currentProcessor = new ApoSpanProcessor();\n}\n\n/**\n * Get the registered processor (for testing or advanced use).\n * Returns null if `registerApoTracing` hasn't been called.\n */\nexport function getApoProcessor(): ApoSpanProcessor | null {\n return currentProcessor;\n}\n\n/**\n * Alias used by configureApoTelemetry to pick up the processor and add it\n * to the OTLP-exporting provider.\n */\nexport function getRegisteredApoProcessor(): ApoSpanProcessor | null {\n return currentProcessor;\n}\n\n/**\n * Reset registration state — for testing only.\n */\nexport function resetApoTracing(): void {\n registered = false;\n currentProcessor = null;\n}\n"],"mappings":"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","names":["acquired"]}
|