UNPKG

@openai/agents-core

Version:

The OpenAI Agents SDK is a lightweight yet powerful framework for building multi-agent workflows.

432 lines • 17.6 kB
"use strict"; var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) { if (k2 === undefined) k2 = k; var desc = Object.getOwnPropertyDescriptor(m, k); if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) { desc = { enumerable: true, get: function() { return m[k]; } }; } Object.defineProperty(o, k2, desc); }) : (function(o, m, k, k2) { if (k2 === undefined) k2 = k; o[k2] = m[k]; })); var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) { Object.defineProperty(o, "default", { enumerable: true, value: v }); }) : function(o, v) { o["default"] = v; }); var __importStar = (this && this.__importStar) || (function () { var ownKeys = function(o) { ownKeys = Object.getOwnPropertyNames || function (o) { var ar = []; for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k; return ar; }; return ownKeys(o); }; return function (mod) { if (mod && mod.__esModule) return mod; var result = {}; if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]); __setModuleDefault(result, mod); return result; }; })(); Object.defineProperty(exports, "__esModule", { value: true }); exports.TraceProvider = void 0; exports.getGlobalTraceProvider = getGlobalTraceProvider; const context_1 = require("./context.js"); const _shims_1 = require("@openai/agents-core/_shims"); const config_1 = require("../config.js"); const logger_1 = __importStar(require("../logger.js")); const processor_1 = require("./processor.js"); const spans_1 = require("./spans.js"); const traces_1 = require("./traces.js"); const utils_1 = require("./utils.js"); function resolveTracingIdGenerator(idGenerator) { return { generateTraceId: idGenerator?.generateTraceId ?? utils_1.defaultTracingIdGenerator.generateTraceId, generateSpanId: idGenerator?.generateSpanId ?? utils_1.defaultTracingIdGenerator.generateSpanId, }; } class TraceProvider { #multiProcessor; #disabled; #shutdownPromise; #idGenerator; constructor(options = {}) { this.#multiProcessor = new processor_1.MultiTracingProcessor(); this.#disabled = config_1.tracing.disabled; this.#shutdownPromise = null; this.#idGenerator = resolveTracingIdGenerator(options.idGenerator); this.#addCleanupListeners(); } /** * Add a processor to the list of processors. Each processor will receive all traces/spans. * * @param processor - The processor to add. */ registerProcessor(processor) { this.#shutdownPromise = null; this.#multiProcessor.addTraceProcessor(processor); } /** * Set the list of processors. This will replace any existing processors. * * @param processors - The list of processors to set. */ setProcessors(processors) { this.#shutdownPromise = null; this.#multiProcessor.setProcessors(processors); } /** * Get the current trace. * * @returns The current trace. */ getCurrentTrace() { return (0, context_1.getCurrentTrace)(); } getCurrentSpan() { return (0, context_1.getCurrentSpan)(); } setDisabled(disabled) { this.#disabled = disabled; } setIdGenerator(idGenerator) { this.#idGenerator = resolveTracingIdGenerator(idGenerator); } /** * Generate a new trace ID. * * Override this in custom providers to take precedence over configured ID generators. */ generateTraceId() { return this.#idGenerator.generateTraceId(); } /** * Generate a new span ID. * * Override this in custom providers to take precedence over configured ID generators. */ generateSpanId() { return this.#idGenerator.generateSpanId(); } startExportLoop() { this.#multiProcessor.start(); } /** * Dispatches a completed trace lifecycle to all registered processors. * * This is useful when an integration receives a trace that was started and * ended outside this process and needs to fan out the lifecycle without * mutating the trace state. */ async dispatchTrace(trace) { if (this.#disabled) { if (logger_1.default.dontLogModelData || logger_1.default.dontLogToolData) { logger_1.default.debug('Tracing is disabled. Not dispatching trace.'); } else { logger_1.default.debug('Tracing is disabled, Not dispatching trace %o', trace); } return; } await this.#multiProcessor.dispatchTrace(trace); } /** * Dispatches a completed span lifecycle to all registered processors. * * This is useful when an integration receives a span that already has * lifecycle timestamps and needs to fan out the lifecycle without mutating * those timestamps. */ async dispatchSpan(span) { if (this.#disabled) { if (logger_1.default.dontLogModelData || logger_1.default.dontLogToolData) { logger_1.default.debug('Tracing is disabled. Not dispatching span.'); } else { logger_1.default.debug('Tracing is disabled, Not dispatching span %o', span); } return; } await this.#multiProcessor.dispatchSpan(span); } /** * Dispatches a span start event to all registered processors. * * This is useful when an integration receives a span start outside this * process and needs to fan out the start without mutating the span state. */ async dispatchSpanStart(span) { if (this.#disabled) { if (logger_1.default.dontLogModelData || logger_1.default.dontLogToolData) { logger_1.default.debug('Tracing is disabled. Not dispatching span start.'); } else { logger_1.default.debug('Tracing is disabled, Not dispatching span start %o', span); } return; } await this.#multiProcessor.dispatchSpanStart(span); } /** * Dispatches a span end event to all registered processors. * * This is useful when an integration receives a span end outside this process * and needs to fan out the end without mutating the span state. */ async dispatchSpanEnd(span) { if (this.#disabled) { if (logger_1.default.dontLogModelData || logger_1.default.dontLogToolData) { logger_1.default.debug('Tracing is disabled. Not dispatching span end.'); } else { logger_1.default.debug('Tracing is disabled, Not dispatching span end %o', span); } return; } await this.#multiProcessor.dispatchSpanEnd(span); } createTrace(traceOptions) { if (this.#disabled) { if (logger_1.default.dontLogModelData || logger_1.default.dontLogToolData) { logger_1.default.debug('Tracing is disabled. Not creating trace.'); } else { logger_1.default.debug('Tracing is disabled, Not creating trace %o', traceOptions); } return new traces_1.NoopTrace(); } const traceId = traceOptions.traceId ?? this.generateTraceId(); const name = traceOptions.name ?? 'Agent workflow'; if (logger_1.default.dontLogModelData || logger_1.default.dontLogToolData) { logger_1.default.debug('Creating trace. Trace data is redacted.'); } else { logger_1.default.debug('Creating trace %s with name %s', traceId, name); } return new traces_1.Trace({ ...traceOptions, name, traceId }, this.#multiProcessor); } createSpan(spanOptions, parent) { if (this.#disabled || spanOptions.disabled) { if (logger_1.default.dontLogModelData || logger_1.default.dontLogToolData) { logger_1.default.debug('Tracing is disabled. Not creating span.'); } else { logger_1.default.debug('Tracing is disabled, Not creating span %o', spanOptions); } return new spans_1.NoopSpan(spanOptions.data, this.#multiProcessor); } if (spanOptions.spanId === utils_1.NOOP_TRACE_OR_SPAN_ID) { logger_1.default.debug('Span id is no-op, returning NoopSpan'); return new spans_1.NoopSpan(spanOptions.data, this.#multiProcessor); } let parentId; let traceId; let tracingApiKey; let traceMetadata; if (!parent) { const currentTrace = (0, context_1.getCurrentTrace)(); const currentSpan = (0, context_1.getCurrentSpan)(); if (!currentTrace) { logger_1.default.debug('No active trace. Make sure to start a trace with `withTrace()` first. Returning NoopSpan.'); return new spans_1.NoopSpan(spanOptions.data, this.#multiProcessor); } if (currentSpan instanceof spans_1.NoopSpan || currentSpan?.spanId === utils_1.NOOP_TRACE_OR_SPAN_ID || currentTrace instanceof traces_1.NoopTrace || currentTrace.traceId === utils_1.NOOP_TRACE_OR_SPAN_ID) { logger_1.default.debug(`Parent ${currentSpan} or ${currentTrace} is no-op, returning NoopSpan`); return new spans_1.NoopSpan(spanOptions.data, this.#multiProcessor); } traceId = currentTrace.traceId; tracingApiKey = currentTrace.tracingApiKey; traceMetadata = currentTrace.metadata; if (currentSpan) { logger_1.default.debug('Using parent span %s', currentSpan.spanId); parentId = currentSpan.spanId; } else { logger_1.default.debug('No parent span, using current trace %s', currentTrace.traceId); } } else if (parent instanceof traces_1.Trace) { if (parent instanceof traces_1.NoopTrace || parent.traceId === utils_1.NOOP_TRACE_OR_SPAN_ID) { logger_1.default.debug('Parent trace is no-op, returning NoopSpan'); return new spans_1.NoopSpan(spanOptions.data, this.#multiProcessor); } traceId = parent.traceId; tracingApiKey = parent.tracingApiKey; traceMetadata = parent.metadata; } else if (parent instanceof spans_1.Span) { if (parent instanceof spans_1.NoopSpan || parent.spanId === utils_1.NOOP_TRACE_OR_SPAN_ID || parent.traceId === utils_1.NOOP_TRACE_OR_SPAN_ID) { logger_1.default.debug('Parent span is no-op, returning NoopSpan'); return new spans_1.NoopSpan(spanOptions.data, this.#multiProcessor); } parentId = parent.spanId; traceId = parent.traceId; tracingApiKey = parent.tracingApiKey; traceMetadata = parent.traceMetadata; } if (!traceId || traceId === utils_1.NOOP_TRACE_OR_SPAN_ID) { logger_1.default.error('No traceId found. Make sure to start a trace with `withTrace()` first. Returning NoopSpan.'); return new spans_1.NoopSpan(spanOptions.data, this.#multiProcessor); } const spanId = spanOptions.spanId ?? this.generateSpanId(); if (spanId === utils_1.NOOP_TRACE_OR_SPAN_ID) { logger_1.default.debug('Span id is no-op, returning NoopSpan'); return new spans_1.NoopSpan(spanOptions.data, this.#multiProcessor); } if (logger_1.default.dontLogModelData || logger_1.default.dontLogToolData) { logger_1.default.debug('Creating span. Span data is redacted.'); } else { logger_1.default.debug(`Creating span ${JSON.stringify(spanOptions.data)} with id ${spanId}`); } return new spans_1.Span({ ...spanOptions, spanId, traceId, parentId, traceMetadata: traceMetadata ?? spanOptions.traceMetadata, tracingApiKey: tracingApiKey ?? spanOptions.tracingApiKey, }, this.#multiProcessor); } async shutdown(timeout) { if (!this.#shutdownPromise) { this.#shutdownPromise = (async () => { try { logger_1.default.debug('Shutting down tracing provider'); await this.#multiProcessor.shutdown(timeout); } catch (error) { (0, logger_1.logModelAndToolActionError)(logger_1.default, 'Error shutting down tracing provider', error); } })(); } await this.#shutdownPromise; } /** Adds listeners to `process` to ensure `shutdown` occurs before exit. */ #addCleanupListeners() { if ((0, _shims_1.supportsProcessLifecycleEvents)() && typeof process !== 'undefined' && typeof process.on === 'function') { // handling Node.js process termination const cleanup = async () => { const timeoutMs = 5000; let timeout; try { await Promise.race([ this.shutdown(timeoutMs), new Promise((resolve) => { timeout = setTimeout(() => { console.warn('Tracing cleanup timed out; continuing exit'); resolve(); }, timeoutMs); }), ]); } finally { if (timeout) { clearTimeout(timeout); } } }; // Handle normal termination process.once('beforeExit', cleanup); // Handle CTRL+C (SIGINT) process.on('SIGINT', async () => { await cleanup(); if (!hasOtherListenersForSignals('SIGINT')) { // Only when there are no other listeners, exit the process on this SDK side process.exit(130); } }); // Handle termination (SIGTERM) process.on('SIGTERM', async () => { await cleanup(); if (!hasOtherListenersForSignals('SIGTERM')) { // Only when there are no other listeners, exit the process on this SDK side process.exit(0); } }); process.on('unhandledRejection', async (reason, promise) => { (0, logger_1.logModelAndToolActionError)(logger_1.default, 'Unhandled rejection', reason, promise); await cleanup(); if (!hasOtherListenersForEvents('unhandledRejection')) { // Only when there are no other listeners, exit the process on this SDK side process.exit(1); } }); } } async forceFlush() { await this.#multiProcessor.forceFlush(); } } exports.TraceProvider = TraceProvider; let moduleTraceProvider; function hasOtherListenersForSignals(event) { return process.listeners(event).length > 1; } function hasOtherListenersForEvents(event) { return process.listeners(event).length > 1; } function getGlobalTraceProvider() { const symbol = Symbol.for('openai.agents.core.traceProvider'); try { const globalHolder = globalThis; // Avoid constructing extra providers when globalThis is frozen/sealed. We // first short-circuit on existing instances, then check writability before // instantiation so hardened runtimes do not leak constructors or listeners. const existing = globalHolder[symbol]; if (existing) { return existing; } const descriptor = Object.getOwnPropertyDescriptor(globalHolder, symbol); if (descriptor && descriptor.writable === false && descriptor.configurable === false && !descriptor.set) { return getModuleTraceProvider(); } if (!descriptor) { try { Object.defineProperty(globalHolder, symbol, { value: undefined, writable: true, configurable: true, }); } catch { return getModuleTraceProvider(); } } try { const provider = new TraceProvider(); globalHolder[symbol] = provider; return provider; } catch { return getModuleTraceProvider(); } } catch { // Hardened runtimes can freeze or seal globalThis; fall back to a // module-local singleton instead of throwing so tracing still works. return getModuleTraceProvider(); } } function getModuleTraceProvider() { if (!moduleTraceProvider) { moduleTraceProvider = new TraceProvider(); } return moduleTraceProvider; } //# sourceMappingURL=provider.js.map