@openai/agents-core
Version:
The OpenAI Agents SDK is a lightweight yet powerful framework for building multi-agent workflows.
219 lines • 8 kB
JavaScript
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