UNPKG

@openai/agents-core

Version:

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

319 lines 12.9 kB
"use strict"; var __importDefault = (this && this.__importDefault) || function (mod) { return (mod && mod.__esModule) ? mod : { "default": mod }; }; Object.defineProperty(exports, "__esModule", { value: true }); exports.Agent = void 0; exports.saveAgentToolRunResult = saveAgentToolRunResult; exports.consumeAgentToolRunResult = consumeAgentToolRunResult; const zod_1 = require("zod"); const lifecycle_1 = require("./lifecycle.js"); const mcp_1 = require("./mcp.js"); const defaultModel_1 = require("./defaultModel.js"); const tool_1 = require("./tool.js"); const handoff_1 = require("./handoff.js"); const run_1 = require("./run.js"); const tools_1 = require("./utils/tools.js"); const messages_1 = require("./utils/messages.js"); const typeGuards_1 = require("./utils/typeGuards.js"); const typeGuards_2 = require("./utils/typeGuards.js"); const errors_1 = require("./errors.js"); const logger_1 = __importDefault(require("./logger.js")); // Per-process, ephemeral map linking a function tool call to its nested // Agent run result within the same run; entry is removed after consumption. const agentToolRunResults = new WeakMap(); function saveAgentToolRunResult(toolCall, runResult) { if (toolCall) { agentToolRunResults.set(toolCall, runResult); } } function consumeAgentToolRunResult(toolCall) { const runResult = agentToolRunResults.get(toolCall); if (runResult) { agentToolRunResults.delete(toolCall); } return runResult; } // The parameter type fo needApproval function for the tool created by Agent.asTool() method const AgentAsToolNeedApprovalSchame = zod_1.z.object({ input: zod_1.z.string() }); /** * The class representing an AI agent configured with instructions, tools, guardrails, handoffs and more. * * We strongly recommend passing `instructions`, which is the "system prompt" for the agent. In * addition, you can pass `handoffDescription`, which is a human-readable description of the * agent, used when the agent is used inside tools/handoffs. * * Agents are generic on the context type. The context is a (mutable) object you create. It is * passed to tool functions, handoffs, guardrails, etc. */ class Agent extends lifecycle_1.AgentHooks { /** * Create an Agent with handoffs and automatically infer the union type for TOutput from the handoff agents' output types. */ static create(config) { return new Agent({ ...config, handoffs: config.handoffs, outputType: config.outputType, handoffOutputTypeWarningEnabled: false, }); } static DEFAULT_MODEL_PLACEHOLDER = ''; name; instructions; prompt; handoffDescription; handoffs; model; modelSettings; tools; mcpServers; inputGuardrails; outputGuardrails; outputType = 'text'; toolUseBehavior; resetToolChoice; constructor(config) { super(); if (typeof config.name !== 'string' || config.name.trim() === '') { throw new errors_1.UserError('Agent must have a name.'); } this.name = config.name; this.instructions = config.instructions ?? Agent.DEFAULT_MODEL_PLACEHOLDER; this.prompt = config.prompt; this.handoffDescription = config.handoffDescription ?? ''; this.handoffs = config.handoffs ?? []; this.model = config.model ?? ''; this.modelSettings = config.modelSettings ?? (0, defaultModel_1.getDefaultModelSettings)(); this.tools = config.tools ?? []; this.mcpServers = config.mcpServers ?? []; this.inputGuardrails = config.inputGuardrails ?? []; this.outputGuardrails = config.outputGuardrails ?? []; if (config.outputType) { this.outputType = config.outputType; } this.toolUseBehavior = config.toolUseBehavior ?? 'run_llm_again'; this.resetToolChoice = config.resetToolChoice ?? true; if ( // The user sets a non-default model config.model !== undefined && // The default model is gpt-5 (0, defaultModel_1.isGpt5Default)() && // However, the specified model is not a gpt-5 model (typeof config.model !== 'string' || !(0, defaultModel_1.gpt5ReasoningSettingsRequired)(config.model)) && // The model settings are not customized for the specified model config.modelSettings === undefined) { // In this scenario, we should use a generic model settings // because non-gpt-5 models are not compatible with the default gpt-5 model settings. // This is a best-effort attempt to make the agent work with non-gpt-5 models. this.modelSettings = {}; } // --- Runtime warning for handoff output type compatibility --- if (config.handoffOutputTypeWarningEnabled === undefined || config.handoffOutputTypeWarningEnabled) { if (this.handoffs && this.outputType) { const outputTypes = new Set([JSON.stringify(this.outputType)]); for (const h of this.handoffs) { if ('outputType' in h && h.outputType) { outputTypes.add(JSON.stringify(h.outputType)); } else if ('agent' in h && h.agent.outputType) { outputTypes.add(JSON.stringify(h.agent.outputType)); } } if (outputTypes.size > 1) { logger_1.default.warn(`[Agent] Warning: Handoff agents have different output types: ${Array.from(outputTypes).join(', ')}. You can make it type-safe by using Agent.create({ ... }) method instead.`); } } } } /** * Output schema name. */ get outputSchemaName() { if (this.outputType === 'text') { return 'text'; } else if ((0, typeGuards_2.isZodObject)(this.outputType)) { return 'ZodOutput'; } else if (typeof this.outputType === 'object') { return this.outputType.name; } throw new Error(`Unknown output type: ${this.outputType}`); } /** * Makes a copy of the agent, with the given arguments changed. For example, you could do: * * ``` * const newAgent = agent.clone({ instructions: 'New instructions' }) * ``` * * @param config - A partial configuration to change. * @returns A new agent with the given changes. */ clone(config) { return new Agent({ ...this, ...config, }); } /** * Transform this agent into a tool, callable by other agents. * * This is different from handoffs in two ways: * 1. In handoffs, the new agent receives the conversation history. In this tool, the new agent * receives generated input. * 2. In handoffs, the new agent takes over the conversation. In this tool, the new agent is * called as a tool, and the conversation is continued by the original agent. * * @param options - Options for the tool. * @returns A tool that runs the agent and returns the output text. */ asTool(options) { const { toolName, toolDescription, customOutputExtractor, needsApproval, runConfig, runOptions, isEnabled, } = options; return (0, tool_1.tool)({ name: toolName ?? (0, tools_1.toFunctionToolName)(this.name), description: toolDescription ?? '', parameters: AgentAsToolNeedApprovalSchame, strict: true, needsApproval, isEnabled, execute: async (data, context, details) => { if (!(0, typeGuards_1.isAgentToolInput)(data)) { throw new errors_1.ModelBehaviorError('Agent tool called with invalid input'); } const runner = new run_1.Runner(runConfig ?? {}); const result = await runner.run(this, data.input, { context, ...(runOptions ?? {}), }); const completedResult = result; const usesStopAtToolNames = typeof this.toolUseBehavior === 'object' && this.toolUseBehavior !== null && 'stopAtToolNames' in this.toolUseBehavior; if (typeof customOutputExtractor !== 'function' && usesStopAtToolNames) { logger_1.default.debug(`You're passing the agent (name: ${this.name}) with toolUseBehavior.stopAtToolNames configured as a tool to a different agent; this may not work as you expect. You may want to have a wrapper function tool to consistently return the final output.`); } const outputText = typeof customOutputExtractor === 'function' ? await customOutputExtractor(completedResult) : (0, messages_1.getOutputText)(completedResult.rawResponses[completedResult.rawResponses.length - 1]); if (details?.toolCall) { saveAgentToolRunResult(details.toolCall, completedResult); } return outputText; }, }); } /** * Returns the system prompt for the agent. * * If the agent has a function as its instructions, this function will be called with the * runContext and the agent instance. */ async getSystemPrompt(runContext) { if (typeof this.instructions === 'function') { return await this.instructions(runContext, this); } return this.instructions; } /** * Returns the prompt template for the agent, if defined. * * If the agent has a function as its prompt, this function will be called with the * runContext and the agent instance. */ async getPrompt(runContext) { if (typeof this.prompt === 'function') { return await this.prompt(runContext, this); } return this.prompt; } /** * Fetches the available tools from the MCP servers. * @returns the MCP powered tools */ async getMcpTools(runContext) { if (this.mcpServers.length > 0) { return (0, mcp_1.getAllMcpTools)({ mcpServers: this.mcpServers, runContext, agent: this, convertSchemasToStrict: false, }); } return []; } /** * ALl agent tools, including the MCPl and function tools. * * @returns all configured tools */ async getAllTools(runContext) { const mcpTools = await this.getMcpTools(runContext); const enabledTools = []; for (const candidate of this.tools) { if (candidate.type === 'function') { const maybeIsEnabled = candidate.isEnabled; const enabled = typeof maybeIsEnabled === 'function' ? await maybeIsEnabled(runContext, this) : typeof maybeIsEnabled === 'boolean' ? maybeIsEnabled : true; if (!enabled) { continue; } } enabledTools.push(candidate); } return [...mcpTools, ...enabledTools]; } /** * Returns the handoffs that should be exposed to the model for the current run. * * Handoffs that provide an `isEnabled` function returning `false` are omitted. */ async getEnabledHandoffs(runContext) { const handoffs = this.handoffs?.map((h) => (0, handoff_1.getHandoff)(h)) ?? []; const enabled = []; for (const handoff of handoffs) { if (await handoff.isEnabled({ runContext, agent: this })) { enabled.push(handoff); } } return enabled; } /** * Processes the final output of the agent. * * @param output - The output of the agent. * @returns The parsed out. */ processFinalOutput(output) { if (this.outputType === 'text') { return output; } if (typeof this.outputType === 'object') { const parsed = JSON.parse(output); if ((0, typeGuards_2.isZodObject)(this.outputType)) { return this.outputType.parse(parsed); } return parsed; } throw new Error(`Unknown output type: ${this.outputType}`); } /** * Returns a JSON representation of the agent, which is serializable. * * @returns A JSON object containing the agent's name. */ toJSON() { return { name: this.name, }; } } exports.Agent = Agent; //# sourceMappingURL=agent.js.map