UNPKG

@openai/agents-core

Version:

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

234 lines 8.57 kB
import { AgentHooks } from "./lifecycle.js"; import { getAllMcpTools } from "./mcp.js"; import { tool, } from "./tool.js"; import { Runner } from "./run.js"; import { toFunctionToolName } from "./utils/tools.js"; import { getOutputText } from "./utils/messages.js"; import { isAgentToolInput } from "./utils/typeGuards.js"; import { isZodObject } from "./utils/typeGuards.js"; import { ModelBehaviorError, UserError } from "./errors.js"; import logger from "./logger.js"; /** * 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. */ export class Agent extends 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 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 ?? {}; 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; // --- 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.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 (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 } = options; return tool({ name: toolName ?? toFunctionToolName(this.name), description: toolDescription ?? '', parameters: { type: 'object', properties: { input: { type: 'string', }, }, required: ['input'], additionalProperties: false, }, strict: true, execute: async (data, context) => { if (!isAgentToolInput(data)) { throw new ModelBehaviorError('Agent tool called with invalid input'); } const runner = new Runner(); const result = await runner.run(this, data.input, { context: context?.context, }); if (typeof customOutputExtractor === 'function') { return customOutputExtractor(result); } return getOutputText(result.rawResponses[result.rawResponses.length - 1]); }, }); } /** * 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 getAllMcpTools(this.mcpServers, runContext, this, false); } return []; } /** * ALl agent tools, including the MCPl and function tools. * * @returns all configured tools */ async getAllTools(runContext) { return [...(await this.getMcpTools(runContext)), ...this.tools]; } /** * 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 (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, }; } } //# sourceMappingURL=agent.js.map