@openai/agents-core
Version:
The OpenAI Agents SDK is a lightweight yet powerful framework for building multi-agent workflows.
147 lines • 5.85 kB
JavaScript
import { MaxTurnsExceededError, ModelBehaviorError, ModelRefusalError, ModelTimeoutError, ToolCallError, ToolInputGuardrailTripwireTriggered, ToolOutputGuardrailTripwireTriggered, UserError, } from "../errors.mjs";
import { assistant } from "../helpers/message.mjs";
import { RunMessageOutputItem } from "../items.mjs";
import logger from "../logger.mjs";
import { getRunOutput, getTurnInput } from "./items.mjs";
import { streamStepItemsToRunResult } from "./streaming.mjs";
import { createRedactedErrorDetailsError } from "../utils/finalOutputError.mjs";
export async function preserveInvalidFinalOutputRedaction(callback, inheritedRedaction = false) {
const redactFromStart = inheritedRedaction || logger.dontLogModelData;
try {
return await callback(redactFromStart);
}
catch (error) {
if (redactFromStart || logger.dontLogModelData) {
throw createRedactedErrorDetailsError();
}
throw error;
}
}
/**
* Attaches the active run state to errors that need resumable caller context.
*/
export const attachRunStateToError = (error, state) => {
if (error instanceof ModelTimeoutError) {
error.state ??= state;
return;
}
if (!(error instanceof ToolCallError)) {
return;
}
if (error.error instanceof ToolInputGuardrailTripwireTriggered ||
error.error instanceof ToolOutputGuardrailTripwireTriggered) {
error.error.state ??= state;
}
};
const buildRunData = (state) => ({
input: state._originalInput,
newItems: state._generatedItems,
history: getTurnInput(state._originalInput, state._generatedItems, state._reasoningItemIdPolicy),
output: getRunOutput(state._generatedItems, state._reasoningItemIdPolicy),
rawResponses: state._modelResponses,
lastAgent: state._currentAgent,
state,
});
const formatFinalOutput = (agent, finalOutput) => {
if (agent.outputType === 'text') {
return String(finalOutput);
}
return JSON.stringify(finalOutput);
};
const createFinalOutputItem = (agent, outputText) => new RunMessageOutputItem(assistant(outputText), agent);
function validateRunErrorFinalOutput(agent, outputText, redactInvalidOutputDetails = false, redactFromStart = false) {
try {
agent.processFinalOutput(outputText);
}
catch (error) {
if (redactInvalidOutputDetails &&
(redactFromStart || logger.dontLogModelData)) {
throw createRedactedErrorDetailsError();
}
const message = error instanceof Error ? error.message : String(error);
throw new UserError(`Invalid run error handler finalOutput: ${message}`);
}
}
export const formatRunErrorFinalOutput = formatFinalOutput;
export const createRunErrorFinalOutputItem = createFinalOutputItem;
export const validateRunErrorHandlerFinalOutput = validateRunErrorFinalOutput;
export function invalidateAcceptedResponseReplayEvidence(state) {
if (state?._currentStep?.type === 'next_step_interruption' &&
state._currentStep.data?.responseAccepted === true) {
state._lastProcessedResponse = undefined;
}
}
export const resolveRunErrorHandler = async ({ error, errorKind, errorHandlers, context, runData, attemptedErrors, }) => {
const kind = errorKind ??
(error instanceof MaxTurnsExceededError
? 'maxTurns'
: error instanceof ModelRefusalError
? 'modelRefusal'
: undefined);
if (!kind) {
return undefined;
}
const typedError = kind === 'maxTurns' && error instanceof MaxTurnsExceededError
? error
: kind === 'modelRefusal' && error instanceof ModelRefusalError
? error
: kind === 'invalidFinalOutput' && error instanceof ModelBehaviorError
? error
: undefined;
if (!typedError) {
return undefined;
}
const handler = errorHandlers?.[kind] ?? errorHandlers?.default;
if (!handler) {
return undefined;
}
if (attemptedErrors?.has(typedError)) {
return undefined;
}
attemptedErrors?.add(typedError);
invalidateAcceptedResponseReplayEvidence(runData.state);
const handlerResult = await handler({
error: typedError,
context,
runData,
});
return handlerResult || undefined;
};
export const prepareRunErrorFinalOutput = async ({ error, state, errorHandlers, streamResult, responseAccepted, attemptedErrors, }) => {
const handlerResult = await resolveRunErrorHandler({
error,
errorHandlers,
context: state._context,
runData: buildRunData(state),
attemptedErrors,
});
if (!handlerResult) {
return undefined;
}
const includeInHistory = handlerResult.includeInHistory !== false;
const outputText = formatFinalOutput(state._currentAgent, handlerResult.finalOutput);
validateRunErrorFinalOutput(state._currentAgent, outputText);
streamResult?._hideFinalOutput();
state._lastTurnResponse = undefined;
state._lastProcessedResponse = undefined;
const item = createFinalOutputItem(state._currentAgent, outputText);
const deferredItem = error instanceof MaxTurnsExceededError && includeInHistory
? item
: undefined;
if (includeInHistory && !deferredItem) {
state._generatedItems.push(item);
}
if (streamResult &&
!deferredItem &&
(includeInHistory || !(error instanceof MaxTurnsExceededError))) {
streamStepItemsToRunResult(streamResult, [item]);
}
state._currentStep = {
type: 'next_step_final_output',
output: outputText,
...(responseAccepted ? { responseAccepted: true } : {}),
};
state._finalOutputSource = 'error_handler';
return { deferredItem };
};
//# sourceMappingURL=errorHandlers.mjs.map