UNPKG

@openai/agents-core

Version:

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

219 lines • 8 kB
import { resetCurrentSpan, setCurrentSpan } from "../tracing/context.mjs"; import { createAgentSpan, createTaskSpan, createTurnSpan } from "../tracing/index.mjs"; import { getGlobalTraceProvider } from "../tracing/provider.mjs"; function sumUsageDetail(usage, key) { return usage.inputTokensDetails.reduce((total, details) => { const value = details[key]; return total + (typeof value === 'number' ? value : 0); }, 0); } function snapshotUsage(usage) { return { requests: usage.requests, inputTokens: usage.inputTokens, outputTokens: usage.outputTokens, totalTokens: usage.totalTokens, cachedInputTokens: sumUsageDetail(usage, 'cached_tokens') + sumUsageDetail(usage, 'cached_input_tokens'), cacheWriteInputTokens: sumUsageDetail(usage, 'cache_write_tokens'), }; } function emptyUsageSnapshot() { return { requests: 0, inputTokens: 0, outputTokens: 0, totalTokens: 0, cachedInputTokens: 0, cacheWriteInputTokens: 0, }; } function addUsageSnapshot(target, increment) { const added = snapshotUsage(increment); target.requests += added.requests; target.inputTokens += added.inputTokens; target.outputTokens += added.outputTokens; target.totalTokens += added.totalTokens; target.cachedInputTokens += added.cachedInputTokens; target.cacheWriteInputTokens += added.cacheWriteInputTokens; } function trackRunnerSpanUsage(span) { return { span, ownedUsage: emptyUsageSnapshot() }; } export function recordRunnerSpanUsage(lifecycle, increment) { if (lifecycle) { addUsageSnapshot(lifecycle.ownedUsage, increment); } } function hasUsage(usage) { return Object.values(usage).some((value) => value !== 0); } function toTurnUsageData(usage) { return { input_tokens: usage.inputTokens, output_tokens: usage.outputTokens, cached_input_tokens: usage.cachedInputTokens, cache_write_input_tokens: usage.cacheWriteInputTokens, }; } export function startTaskSpan(name, parent) { const span = createTaskSpan({ data: { name } }, parent); span.start(); setCurrentSpan(span); return trackRunnerSpanUsage(span); } function startAgentSpanForInterruptedResume(agent, restoredSpan, parent) { const span = createAgentSpan({ data: { name: agent.name, handoffs: [...(restoredSpan?.spanData.handoffs ?? [])], tools: [...(restoredSpan?.spanData.tools ?? [])], output_type: restoredSpan?.spanData.output_type ?? agent.outputSchemaName, }, }, parent); span.start(); setCurrentSpan(span); return span; } export function ensureActiveAgentSpanForInterruptedResume(options) { if (options.restoredAgentSpan?.endedAt === null) { setCurrentSpan(options.restoredAgentSpan); return options.restoredAgentSpan; } return startAgentSpanForInterruptedResume(options.agent, options.restoredAgentSpan, options.parent); } export function startRunnerInvocationSpans(options) { options.restoredAgentSpan?.end(); const taskSpan = startTaskSpan(options.name, options.parent); const agentSpan = options.resumeInterruptedTurn ? startAgentSpanForInterruptedResume(options.agent, options.restoredAgentSpan, taskSpan.span) : undefined; return { taskSpan, agentSpan }; } export function startTurnSpan(turn, agentName, parent) { const span = createTurnSpan({ data: { turn, agent_name: agentName } }, parent); span.start(); setCurrentSpan(span); return trackRunnerSpanUsage(span); } export function ensureTurnSpan(current, turn, agentName, parent) { return current ?? startTurnSpan(turn, agentName, parent); } export function finishRunnerSpan(lifecycle) { if (!lifecycle) { return; } if (hasUsage(lifecycle.ownedUsage)) { if (lifecycle.span.spanData.type === 'task') { const taskUsage = { ...toTurnUsageData(lifecycle.ownedUsage), requests: lifecycle.ownedUsage.requests, total_tokens: lifecycle.ownedUsage.totalTokens, }; lifecycle.span.spanData.usage = taskUsage; } else { lifecycle.span.spanData.usage = toTurnUsageData(lifecycle.ownedUsage); } } lifecycle.span.end(); resetCurrentSpan(); } export function setRunnerSpanError(lifecycle, error, traceIncludeSensitiveData) { lifecycle?.span.setError({ message: 'Error in agent run', data: { error: getRunnerSpanErrorDetails(error, traceIncludeSensitiveData), }, }); } export function getRunnerSpanErrorDetails(error, traceIncludeSensitiveData) { if (traceIncludeSensitiveData) { return String(error); } return 'Error'; } /** * Normalizes tracing configuration into the format expected by model providers. * Returns `false` to disable tracing, `true` to include full payload data, or * `'enabled_without_data'` to omit sensitive content while still emitting spans. */ export function getTracing(tracingDisabled, traceIncludeSensitiveData) { if (tracingDisabled) { return false; } if (traceIncludeSensitiveData) { return true; } return 'enabled_without_data'; } function rebaseSpanChain(span, trace) { const previousSpan = span.previousSpan ? rebaseSpanChain(span.previousSpan, trace) : undefined; const parent = previousSpan ?? trace; const rebasedSpan = getGlobalTraceProvider().createSpan({ spanId: span.spanId, parentId: span.parentId ?? undefined, startedAt: span.startedAt ?? undefined, endedAt: span.endedAt ?? undefined, data: span.spanData, error: span.error ?? undefined, tracingApiKey: span.tracingApiKey, }, parent); rebasedSpan.previousSpan = previousSpan; return rebasedSpan; } export function applyTraceOverrides(trace, currentSpan, overrides) { const traceIdOverride = overrides.traceId !== undefined && overrides.traceId !== trace.traceId; const tracingApiKeyOverride = overrides.tracingApiKey !== undefined && overrides.tracingApiKey !== trace.tracingApiKey; const traceMetadataOverride = overrides.traceMetadata !== undefined && overrides.traceMetadata !== trace.metadata; if (overrides.traceId !== undefined) { trace.traceId = overrides.traceId; } if (overrides.workflowName !== undefined) { trace.name = overrides.workflowName; } if (overrides.groupId !== undefined) { trace.groupId = overrides.groupId ?? null; } if (overrides.traceMetadata !== undefined) { trace.metadata = overrides.traceMetadata; } if (overrides.tracingApiKey !== undefined) { trace.tracingApiKey = overrides.tracingApiKey; } if (currentSpan && (traceIdOverride || tracingApiKeyOverride || traceMetadataOverride)) { return { trace, currentSpan: rebaseSpanChain(currentSpan, trace) }; } return { trace, currentSpan }; } /** * Ensures an agent span exists and updates tool metadata if already present. * Returns the span so callers can pass it through run state. */ export function ensureAgentSpan(params) { const { agent, handoffs, tools, currentSpan, parent } = params; const existingSpan = currentSpan; if (existingSpan) { existingSpan.spanData.handoffs = handoffs.map((h) => h.agentName); existingSpan.spanData.tools = tools.map((t) => t.name); return existingSpan; } const handoffNames = handoffs.map((h) => h.agentName); const span = createAgentSpan({ data: { name: agent.name, handoffs: handoffNames, tools: tools.map((t) => t.name), output_type: agent.outputSchemaName, }, }, parent); span.start(); setCurrentSpan(span); return span; } //# sourceMappingURL=tracing.mjs.map