@agent-inspect/openai-agents 1.8.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 ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 AgentInspect contributors
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/dist/index.cjs ADDED
@@ -0,0 +1,581 @@
1
+ 'use strict';
2
+
3
+ var writers = require('agent-inspect/writers');
4
+
5
+ // packages/openai-agents/src/index.ts
6
+ var OPENAI_AGENTS_SOURCE = {
7
+ type: "adapter",
8
+ name: "@agent-inspect/openai-agents",
9
+ version: "experimental"
10
+ };
11
+ function nowIso() {
12
+ return (/* @__PURE__ */ new Date()).toISOString();
13
+ }
14
+ function normalizeError(error) {
15
+ if (error instanceof Error && error.message.trim() !== "") {
16
+ return error.message;
17
+ }
18
+ if (typeof error === "string" && error.trim() !== "") {
19
+ return error;
20
+ }
21
+ return "Unknown OpenAI Agents processor error";
22
+ }
23
+ function durationMs(startedAt, endedAt) {
24
+ const started = Date.parse(startedAt);
25
+ const ended = Date.parse(endedAt);
26
+ if (!Number.isFinite(started) || !Number.isFinite(ended)) return void 0;
27
+ return Math.max(0, ended - started);
28
+ }
29
+ function countRecordKeys(value) {
30
+ if (typeof value !== "object" || value === null || Array.isArray(value)) {
31
+ return void 0;
32
+ }
33
+ return Object.keys(value).length;
34
+ }
35
+ function normalizeMaxPreviewChars(value) {
36
+ if (typeof value !== "number" || !Number.isFinite(value) || value < 0) {
37
+ return void 0;
38
+ }
39
+ return Math.floor(value);
40
+ }
41
+ function summarizeUnknown(value) {
42
+ if (value === null) return { type: "null" };
43
+ if (Array.isArray(value)) return { type: "array", itemCount: value.length };
44
+ if (typeof value === "object") {
45
+ return { type: "object", keyCount: countRecordKeys(value) ?? 0 };
46
+ }
47
+ if (typeof value === "string") {
48
+ return { type: "string", length: value.length };
49
+ }
50
+ const valueType = typeof value;
51
+ if (valueType === "number" || valueType === "boolean" || valueType === "bigint") {
52
+ return { type: valueType };
53
+ }
54
+ if (valueType === "undefined") return { type: "undefined" };
55
+ return { type: "unknown" };
56
+ }
57
+ function summarizeOptionalUnknown(value) {
58
+ return value === void 0 ? void 0 : summarizeUnknown(value);
59
+ }
60
+ function summarizeError(error) {
61
+ if (!error?.message) return void 0;
62
+ return { message: error.message };
63
+ }
64
+ function summarizeUsage(usage) {
65
+ if (typeof usage !== "object" || usage === null || Array.isArray(usage)) {
66
+ return void 0;
67
+ }
68
+ const record = usage;
69
+ const tokenUsage = {};
70
+ if (typeof record.input_tokens === "number" && Number.isFinite(record.input_tokens)) {
71
+ tokenUsage.input = record.input_tokens;
72
+ }
73
+ if (typeof record.output_tokens === "number" && Number.isFinite(record.output_tokens)) {
74
+ tokenUsage.output = record.output_tokens;
75
+ }
76
+ if (tokenUsage.input !== void 0 || tokenUsage.output !== void 0) {
77
+ tokenUsage.total = (tokenUsage.input ?? 0) + (tokenUsage.output ?? 0);
78
+ }
79
+ const details = record.details;
80
+ if (typeof details === "object" && details !== null && !Array.isArray(details)) {
81
+ const detailRecord = details;
82
+ const cached = detailRecord.cached_tokens ?? detailRecord.cached_input_tokens;
83
+ if (typeof cached === "number" && Number.isFinite(cached)) {
84
+ tokenUsage.cached = cached;
85
+ }
86
+ }
87
+ return Object.keys(tokenUsage).length > 0 ? tokenUsage : void 0;
88
+ }
89
+ function spanKind(type) {
90
+ switch (type) {
91
+ case "agent":
92
+ return "AGENT";
93
+ case "generation":
94
+ case "response":
95
+ case "transcription":
96
+ case "speech":
97
+ return "LLM";
98
+ case "function":
99
+ case "mcp_tools":
100
+ return "TOOL";
101
+ case "handoff":
102
+ case "guardrail":
103
+ return "DECISION";
104
+ case "custom":
105
+ case "speech_group":
106
+ return "LOGIC";
107
+ default:
108
+ return "LOGIC";
109
+ }
110
+ }
111
+ function spanName(data) {
112
+ switch (data.type) {
113
+ case "agent":
114
+ case "function":
115
+ case "custom":
116
+ case "guardrail":
117
+ return data.name;
118
+ case "generation":
119
+ return data.model ? `generation:${data.model}` : "generation";
120
+ case "response":
121
+ return data.response_id ? `response:${data.response_id}` : "response";
122
+ case "handoff":
123
+ return data.to_agent ? `handoff:${data.to_agent}` : "handoff";
124
+ case "mcp_tools":
125
+ return data.server ? `mcp-tools:${data.server}` : "mcp-tools";
126
+ case "transcription":
127
+ return data.model ? `transcription:${data.model}` : "transcription";
128
+ case "speech":
129
+ return data.model ? `speech:${data.model}` : "speech";
130
+ case "speech_group":
131
+ return "speech-group";
132
+ default:
133
+ return "openai-agents-span";
134
+ }
135
+ }
136
+ function commonSpanAttributes(span) {
137
+ return {
138
+ legacyEvent: "step_started",
139
+ stepId: span.spanId,
140
+ stepType: mapSpanTypeToStepType(span.spanData.type),
141
+ spanType: span.spanData.type,
142
+ traceId: span.traceId,
143
+ spanId: span.spanId,
144
+ parentSpanId: span.parentId ?? void 0,
145
+ traceMetadataKeyCount: countRecordKeys(span.traceMetadata)
146
+ };
147
+ }
148
+ function specificSpanAttributes(data) {
149
+ switch (data.type) {
150
+ case "agent":
151
+ return {
152
+ agentName: data.name,
153
+ handoffCount: data.handoffs?.length ?? 0,
154
+ handoffNames: data.handoffs,
155
+ toolCount: data.tools?.length ?? 0,
156
+ toolNames: data.tools,
157
+ outputType: data.output_type
158
+ };
159
+ case "function":
160
+ return {
161
+ toolName: data.name,
162
+ hasInput: data.input !== void 0,
163
+ hasOutput: data.output !== void 0,
164
+ inputSummary: summarizeUnknown(data.input),
165
+ outputSummary: summarizeUnknown(data.output),
166
+ mcpDataSummary: summarizeOptionalUnknown(data.mcp_data)
167
+ };
168
+ case "generation":
169
+ return {
170
+ model: data.model,
171
+ modelConfigKeyCount: countRecordKeys(data.model_config),
172
+ inputSummary: summarizeOptionalUnknown(data.input),
173
+ outputSummary: summarizeOptionalUnknown(data.output),
174
+ usageDetailsKeyCount: countRecordKeys(data.usage?.details)
175
+ };
176
+ case "response":
177
+ return {
178
+ responseId: data.response_id,
179
+ inputSummary: summarizeOptionalUnknown(data._input),
180
+ responseSummary: summarizeOptionalUnknown(data._response)
181
+ };
182
+ case "handoff":
183
+ return {
184
+ fromAgent: data.from_agent,
185
+ toAgent: data.to_agent
186
+ };
187
+ case "custom":
188
+ return {
189
+ customName: data.name,
190
+ dataSummary: summarizeUnknown(data.data)
191
+ };
192
+ case "guardrail":
193
+ return {
194
+ guardrailName: data.name,
195
+ triggered: data.triggered
196
+ };
197
+ case "mcp_tools":
198
+ return {
199
+ server: data.server,
200
+ toolCount: data.result?.length ?? 0,
201
+ toolNames: data.result
202
+ };
203
+ case "transcription":
204
+ return {
205
+ model: data.model,
206
+ inputFormat: data.input.format,
207
+ inputSummary: summarizeUnknown(data.input.data),
208
+ outputSummary: summarizeOptionalUnknown(data.output),
209
+ modelConfigKeyCount: countRecordKeys(data.model_config)
210
+ };
211
+ case "speech":
212
+ return {
213
+ model: data.model,
214
+ inputSummary: summarizeOptionalUnknown(data.input),
215
+ outputFormat: data.output.format,
216
+ outputSummary: summarizeUnknown(data.output.data),
217
+ modelConfigKeyCount: countRecordKeys(data.model_config)
218
+ };
219
+ case "speech_group":
220
+ return {
221
+ inputSummary: summarizeOptionalUnknown(data.input)
222
+ };
223
+ default:
224
+ return {};
225
+ }
226
+ }
227
+ function mapSpanTypeToStepType(type) {
228
+ switch (type) {
229
+ case "generation":
230
+ case "response":
231
+ case "transcription":
232
+ case "speech":
233
+ return "llm";
234
+ case "function":
235
+ case "mcp_tools":
236
+ return "tool";
237
+ case "handoff":
238
+ case "guardrail":
239
+ return "decision";
240
+ case "agent":
241
+ return "logic";
242
+ case "custom":
243
+ case "speech_group":
244
+ return "custom";
245
+ default:
246
+ return "logic";
247
+ }
248
+ }
249
+ function spanInputSummary(data) {
250
+ switch (data.type) {
251
+ case "generation":
252
+ return summarizeOptionalUnknown(data.input);
253
+ case "function":
254
+ return summarizeUnknown(data.input);
255
+ case "response":
256
+ return summarizeOptionalUnknown(data._input);
257
+ case "custom":
258
+ return summarizeUnknown(data.data);
259
+ case "transcription":
260
+ return { format: data.input.format, ...summarizeUnknown(data.input.data) };
261
+ case "speech":
262
+ case "speech_group":
263
+ return summarizeOptionalUnknown(data.input);
264
+ default:
265
+ return void 0;
266
+ }
267
+ }
268
+ function spanOutputSummary(data) {
269
+ switch (data.type) {
270
+ case "generation":
271
+ return summarizeOptionalUnknown(data.output);
272
+ case "function":
273
+ return summarizeUnknown(data.output);
274
+ case "response":
275
+ return summarizeOptionalUnknown(data._response);
276
+ case "guardrail":
277
+ return { triggered: data.triggered };
278
+ case "mcp_tools":
279
+ return { toolCount: data.result?.length ?? 0 };
280
+ case "transcription":
281
+ return summarizeOptionalUnknown(data.output);
282
+ case "speech":
283
+ return { format: data.output.format, ...summarizeUnknown(data.output.data) };
284
+ default:
285
+ return void 0;
286
+ }
287
+ }
288
+ function traceEventId(traceId) {
289
+ return `openai_agents_trace:${traceId}`;
290
+ }
291
+ function spanEventId(spanId) {
292
+ return `openai_agents_span:${spanId}`;
293
+ }
294
+ var AgentInspectOpenAiAgentsTracingProcessor = class {
295
+ constructor(options) {
296
+ this.options = options;
297
+ this.requestedCapture = options.capture ?? "metadata-only";
298
+ this.writer = options.writer ?? (options.traceDir ? writers.fileWriter({ dir: options.traceDir }) : void 0);
299
+ for (const key of [
300
+ "options",
301
+ "writer",
302
+ "requestedCapture",
303
+ "effectiveCapture",
304
+ "diagnostics",
305
+ "activeTraces",
306
+ "activeSpans",
307
+ "closed"
308
+ ]) {
309
+ Object.defineProperty(this, key, { enumerable: false });
310
+ }
311
+ this.recordCaptureOptionWarnings();
312
+ }
313
+ options;
314
+ installMode = "setTraceProcessors";
315
+ localOnly = true;
316
+ writer;
317
+ requestedCapture;
318
+ effectiveCapture = "metadata-only";
319
+ diagnostics = {
320
+ writeFailures: 0,
321
+ lifecycleWarnings: 0,
322
+ flushFailures: 0,
323
+ shutdownFailures: 0,
324
+ runtimeMappingImplemented: true
325
+ };
326
+ activeTraces = /* @__PURE__ */ new Map();
327
+ activeSpans = /* @__PURE__ */ new Map();
328
+ closed = false;
329
+ start() {
330
+ }
331
+ async onTraceStart(trace) {
332
+ await this.handleLifecycle("onTraceStart", async () => {
333
+ if (this.closed) {
334
+ this.recordLifecycleWarning("onTraceStart ignored because processor is shut down.");
335
+ return;
336
+ }
337
+ const startedAt = nowIso();
338
+ const name = this.options.workflowName ?? trace.name ?? "openai-agents-run";
339
+ const eventId = traceEventId(trace.traceId);
340
+ this.activeTraces.set(trace.traceId, { eventId, startedAt, name });
341
+ await this.write({
342
+ schemaVersion: "0.2",
343
+ eventId,
344
+ runId: trace.traceId,
345
+ kind: "RUN",
346
+ name,
347
+ status: "running",
348
+ timestamp: startedAt,
349
+ startedAt,
350
+ confidence: "explicit",
351
+ source: OPENAI_AGENTS_SOURCE,
352
+ attributes: {
353
+ legacyEvent: "run_started",
354
+ installMode: this.installMode,
355
+ capture: this.effectiveCapture,
356
+ requestedCapture: this.requestedCapture === this.effectiveCapture ? void 0 : this.requestedCapture,
357
+ previewCaptureSupported: this.requestedCapture === "preview" ? false : void 0,
358
+ redactionProfile: this.options.redactionProfile,
359
+ maxPreviewChars: normalizeMaxPreviewChars(this.options.maxPreviewChars),
360
+ groupId: trace.groupId ?? void 0,
361
+ metadataKeyCount: countRecordKeys(trace.metadata)
362
+ },
363
+ trace: {
364
+ traceId: trace.traceId
365
+ }
366
+ });
367
+ });
368
+ }
369
+ async onTraceEnd(trace) {
370
+ await this.handleLifecycle("onTraceEnd", async () => {
371
+ if (this.closed) {
372
+ this.recordLifecycleWarning("onTraceEnd ignored because processor is shut down.");
373
+ return;
374
+ }
375
+ const active = this.activeTraces.get(trace.traceId);
376
+ if (!active) {
377
+ this.recordLifecycleWarning(
378
+ `onTraceEnd ignored because trace ${trace.traceId} has no matching start callback.`
379
+ );
380
+ return;
381
+ }
382
+ const endedAt = nowIso();
383
+ await this.write({
384
+ schemaVersion: "0.2",
385
+ eventId: active.eventId,
386
+ runId: trace.traceId,
387
+ kind: "RUN",
388
+ name: active.name,
389
+ status: "ok",
390
+ timestamp: endedAt,
391
+ startedAt: active.startedAt,
392
+ endedAt,
393
+ durationMs: durationMs(active.startedAt, endedAt),
394
+ confidence: "explicit",
395
+ source: OPENAI_AGENTS_SOURCE,
396
+ attributes: {
397
+ legacyEvent: "run_completed",
398
+ installMode: this.installMode,
399
+ groupId: trace.groupId ?? void 0,
400
+ metadataKeyCount: countRecordKeys(trace.metadata)
401
+ },
402
+ trace: {
403
+ traceId: trace.traceId
404
+ }
405
+ });
406
+ this.activeTraces.delete(trace.traceId);
407
+ });
408
+ }
409
+ async onSpanStart(span) {
410
+ await this.handleLifecycle("onSpanStart", async () => {
411
+ if (this.closed) {
412
+ this.recordLifecycleWarning("onSpanStart ignored because processor is shut down.");
413
+ return;
414
+ }
415
+ const startedAt = span.startedAt ?? nowIso();
416
+ const eventId = spanEventId(span.spanId);
417
+ const parentId = this.resolveParentEventId(span);
418
+ const kind = spanKind(span.spanData.type);
419
+ const name = spanName(span.spanData);
420
+ this.activeSpans.set(span.spanId, {
421
+ eventId,
422
+ runId: span.traceId,
423
+ parentId,
424
+ startedAt,
425
+ name,
426
+ kind
427
+ });
428
+ await this.write({
429
+ schemaVersion: "0.2",
430
+ eventId,
431
+ runId: span.traceId,
432
+ parentId,
433
+ kind,
434
+ name,
435
+ status: "running",
436
+ timestamp: startedAt,
437
+ startedAt,
438
+ confidence: "explicit",
439
+ source: OPENAI_AGENTS_SOURCE,
440
+ attributes: {
441
+ ...commonSpanAttributes(span),
442
+ ...specificSpanAttributes(span.spanData)
443
+ },
444
+ inputSummary: spanInputSummary(span.spanData),
445
+ tokenUsage: summarizeUsage(
446
+ span.spanData.type === "generation" ? span.spanData.usage : void 0
447
+ ),
448
+ trace: {
449
+ traceId: span.traceId,
450
+ spanId: span.spanId,
451
+ parentSpanId: span.parentId ?? void 0
452
+ }
453
+ });
454
+ });
455
+ }
456
+ async onSpanEnd(span) {
457
+ await this.handleLifecycle("onSpanEnd", async () => {
458
+ if (this.closed) {
459
+ this.recordLifecycleWarning("onSpanEnd ignored because processor is shut down.");
460
+ return;
461
+ }
462
+ const active = this.activeSpans.get(span.spanId);
463
+ if (!active) {
464
+ this.recordLifecycleWarning(
465
+ `onSpanEnd ignored because span ${span.spanId} has no matching start callback.`
466
+ );
467
+ return;
468
+ }
469
+ const endedAt = span.endedAt ?? nowIso();
470
+ const error = summarizeError(span.error);
471
+ await this.write({
472
+ schemaVersion: "0.2",
473
+ eventId: active.eventId,
474
+ runId: active.runId,
475
+ parentId: active.parentId,
476
+ kind: active.kind,
477
+ name: active.name,
478
+ status: error ? "error" : "ok",
479
+ timestamp: endedAt,
480
+ startedAt: active.startedAt,
481
+ endedAt,
482
+ durationMs: durationMs(active.startedAt, endedAt),
483
+ confidence: "explicit",
484
+ source: OPENAI_AGENTS_SOURCE,
485
+ attributes: {
486
+ ...commonSpanAttributes(span),
487
+ ...specificSpanAttributes(span.spanData),
488
+ legacyEvent: "step_completed",
489
+ errorDataSummary: summarizeOptionalUnknown(span.error?.data)
490
+ },
491
+ inputSummary: spanInputSummary(span.spanData),
492
+ outputSummary: spanOutputSummary(span.spanData),
493
+ error,
494
+ tokenUsage: summarizeUsage(
495
+ span.spanData.type === "generation" ? span.spanData.usage : void 0
496
+ ),
497
+ trace: {
498
+ traceId: span.traceId,
499
+ spanId: span.spanId,
500
+ parentSpanId: span.parentId ?? void 0
501
+ }
502
+ });
503
+ this.activeSpans.delete(span.spanId);
504
+ });
505
+ }
506
+ async forceFlush() {
507
+ try {
508
+ await this.writer?.flush?.();
509
+ } catch (error) {
510
+ this.diagnostics.flushFailures += 1;
511
+ this.diagnostics.lastError = normalizeError(error);
512
+ }
513
+ }
514
+ async shutdown(_timeout) {
515
+ if (this.closed) return;
516
+ try {
517
+ await this.writer?.close?.();
518
+ } catch (error) {
519
+ this.diagnostics.shutdownFailures += 1;
520
+ this.diagnostics.lastError = normalizeError(error);
521
+ } finally {
522
+ this.closed = true;
523
+ this.activeTraces.clear();
524
+ this.activeSpans.clear();
525
+ }
526
+ }
527
+ getDiagnostics() {
528
+ return { ...this.diagnostics };
529
+ }
530
+ getWriterStats() {
531
+ return this.writer?.getStats?.();
532
+ }
533
+ resolveParentEventId(span) {
534
+ if (span.parentId) return spanEventId(span.parentId);
535
+ return this.activeTraces.get(span.traceId)?.eventId;
536
+ }
537
+ async handleLifecycle(callbackName, run) {
538
+ try {
539
+ await run();
540
+ } catch (error) {
541
+ this.recordLifecycleWarning(`${callbackName}: ${normalizeError(error)}`);
542
+ }
543
+ }
544
+ recordLifecycleWarning(message) {
545
+ this.diagnostics.lifecycleWarnings += 1;
546
+ this.diagnostics.lastWarning = message;
547
+ }
548
+ recordCaptureOptionWarnings() {
549
+ const previewOnlyOptions = [];
550
+ if (this.requestedCapture === "preview") previewOnlyOptions.push("capture");
551
+ if (this.options.redactionProfile !== void 0) previewOnlyOptions.push("redactionProfile");
552
+ if (this.options.maxPreviewChars !== void 0) previewOnlyOptions.push("maxPreviewChars");
553
+ if (this.requestedCapture === "preview") {
554
+ this.recordLifecycleWarning(
555
+ `OpenAI Agents preview capture is not supported yet; falling back to metadata-only capture. Unsupported options: ${previewOnlyOptions.join(", ")}.`
556
+ );
557
+ return;
558
+ }
559
+ if (previewOnlyOptions.length > 0) {
560
+ this.recordLifecycleWarning(
561
+ `OpenAI Agents preview-only options have no effect in metadata-only capture: ${previewOnlyOptions.join(", ")}.`
562
+ );
563
+ }
564
+ }
565
+ async write(event) {
566
+ if (!this.writer) return;
567
+ try {
568
+ await this.writer.write(event);
569
+ } catch (error) {
570
+ this.diagnostics.writeFailures += 1;
571
+ this.diagnostics.lastError = normalizeError(error);
572
+ }
573
+ }
574
+ };
575
+ function agentInspectProcessor(options = {}) {
576
+ return new AgentInspectOpenAiAgentsTracingProcessor(options);
577
+ }
578
+
579
+ exports.agentInspectProcessor = agentInspectProcessor;
580
+ //# sourceMappingURL=index.cjs.map
581
+ //# sourceMappingURL=index.cjs.map