| import { feature } from 'bun:bundle' |
| import memoize from 'lodash-es/memoize.js' |
| import { basename } from 'path' |
| import type { SettingSource } from 'src/utils/settings/constants.js' |
| import { z } from 'zod/v4' |
| import { isAutoMemoryEnabled } from '../../memdir/paths.js' |
| import { |
| type AnalyticsMetadata_I_VERIFIED_THIS_IS_NOT_CODE_OR_FILEPATHS, |
| logEvent, |
| } from '../../services/analytics/index.js' |
| import { |
| type McpServerConfig, |
| McpServerConfigSchema, |
| } from '../../services/mcp/types.js' |
| import type { ToolUseContext } from '../../Tool.js' |
| import { logForDebugging } from '../../utils/debug.js' |
| import { |
| EFFORT_LEVELS, |
| type EffortValue, |
| parseEffortValue, |
| } from '../../utils/effort.js' |
| import { isEnvTruthy } from '../../utils/envUtils.js' |
| import { parsePositiveIntFromFrontmatter } from '../../utils/frontmatterParser.js' |
| import { lazySchema } from '../../utils/lazySchema.js' |
| import { logError } from '../../utils/log.js' |
| import { |
| loadMarkdownFilesForSubdir, |
| parseAgentToolsFromFrontmatter, |
| parseSlashCommandToolsFromFrontmatter, |
| } from '../../utils/markdownConfigLoader.js' |
| import { |
| PERMISSION_MODES, |
| type PermissionMode, |
| } from '../../utils/permissions/PermissionMode.js' |
| import { |
| clearPluginAgentCache, |
| loadPluginAgents, |
| } from '../../utils/plugins/loadPluginAgents.js' |
| import { HooksSchema, type HooksSettings } from '../../utils/settings/types.js' |
| import { jsonStringify } from '../../utils/slowOperations.js' |
| import { FILE_EDIT_TOOL_NAME } from '../FileEditTool/constants.js' |
| import { FILE_READ_TOOL_NAME } from '../FileReadTool/prompt.js' |
| import { FILE_WRITE_TOOL_NAME } from '../FileWriteTool/prompt.js' |
| import { |
| AGENT_COLORS, |
| type AgentColorName, |
| setAgentColor, |
| } from './agentColorManager.js' |
| import { type AgentMemoryScope, loadAgentMemoryPrompt } from './agentMemory.js' |
| import { |
| checkAgentMemorySnapshot, |
| initializeFromSnapshot, |
| } from './agentMemorySnapshot.js' |
| import { getBuiltInAgents } from './builtInAgents.js' |
|
|
| |
| |
| export type AgentMcpServerSpec = |
| | string |
| | { [name: string]: McpServerConfig } |
|
|
| |
| const AgentMcpServerSpecSchema = lazySchema(() => |
| z.union([ |
| z.string(), |
| z.record(z.string(), McpServerConfigSchema()), |
| ]), |
| ) |
|
|
| |
| |
| |
| const AgentJsonSchema = lazySchema(() => |
| z.object({ |
| description: z.string().min(1, 'Description cannot be empty'), |
| tools: z.array(z.string()).optional(), |
| disallowedTools: z.array(z.string()).optional(), |
| prompt: z.string().min(1, 'Prompt cannot be empty'), |
| model: z |
| .string() |
| .trim() |
| .min(1, 'Model cannot be empty') |
| .transform(m => (m.toLowerCase() === 'inherit' ? 'inherit' : m)) |
| .optional(), |
| effort: z.union([z.enum(EFFORT_LEVELS), z.number().int()]).optional(), |
| permissionMode: z.enum(PERMISSION_MODES).optional(), |
| mcpServers: z.array(AgentMcpServerSpecSchema()).optional(), |
| hooks: HooksSchema().optional(), |
| maxTurns: z.number().int().positive().optional(), |
| skills: z.array(z.string()).optional(), |
| initialPrompt: z.string().optional(), |
| memory: z.enum(['user', 'project', 'local']).optional(), |
| background: z.boolean().optional(), |
| isolation: (process.env.USER_TYPE === 'ant' |
| ? z.enum(['worktree', 'remote']) |
| : z.enum(['worktree']) |
| ).optional(), |
| }), |
| ) |
|
|
| const AgentsJsonSchema = lazySchema(() => |
| z.record(z.string(), AgentJsonSchema()), |
| ) |
|
|
| |
| export type BaseAgentDefinition = { |
| agentType: string |
| whenToUse: string |
| tools?: string[] |
| disallowedTools?: string[] |
| skills?: string[] |
| mcpServers?: AgentMcpServerSpec[] |
| hooks?: HooksSettings |
| color?: AgentColorName |
| model?: string |
| effort?: EffortValue |
| permissionMode?: PermissionMode |
| maxTurns?: number |
| filename?: string |
| baseDir?: string |
| criticalSystemReminder_EXPERIMENTAL?: string |
| requiredMcpServers?: string[] |
| background?: boolean |
| initialPrompt?: string |
| memory?: AgentMemoryScope |
| isolation?: 'worktree' | 'remote' |
| pendingSnapshotUpdate?: { snapshotTimestamp: string } |
| |
| |
| |
| |
| omitClaudeMd?: boolean |
| } |
|
|
| |
| export type BuiltInAgentDefinition = BaseAgentDefinition & { |
| source: 'built-in' |
| baseDir: 'built-in' |
| callback?: () => void |
| getSystemPrompt: (params: { |
| toolUseContext: Pick<ToolUseContext, 'options'> |
| }) => string |
| } |
|
|
| |
| export type CustomAgentDefinition = BaseAgentDefinition & { |
| getSystemPrompt: () => string |
| source: SettingSource |
| filename?: string |
| baseDir?: string |
| } |
|
|
| |
| export type PluginAgentDefinition = BaseAgentDefinition & { |
| getSystemPrompt: () => string |
| source: 'plugin' |
| filename?: string |
| plugin: string |
| } |
|
|
| |
| export type AgentDefinition = |
| | BuiltInAgentDefinition |
| | CustomAgentDefinition |
| | PluginAgentDefinition |
|
|
| |
| export function isBuiltInAgent( |
| agent: AgentDefinition, |
| ): agent is BuiltInAgentDefinition { |
| return agent.source === 'built-in' |
| } |
|
|
| export function isCustomAgent( |
| agent: AgentDefinition, |
| ): agent is CustomAgentDefinition { |
| return agent.source !== 'built-in' && agent.source !== 'plugin' |
| } |
|
|
| export function isPluginAgent( |
| agent: AgentDefinition, |
| ): agent is PluginAgentDefinition { |
| return agent.source === 'plugin' |
| } |
|
|
| export type AgentDefinitionsResult = { |
| activeAgents: AgentDefinition[] |
| allAgents: AgentDefinition[] |
| failedFiles?: Array<{ path: string; error: string }> |
| allowedAgentTypes?: string[] |
| } |
|
|
| export function getActiveAgentsFromList( |
| allAgents: AgentDefinition[], |
| ): AgentDefinition[] { |
| const builtInAgents = allAgents.filter(a => a.source === 'built-in') |
| const pluginAgents = allAgents.filter(a => a.source === 'plugin') |
| const userAgents = allAgents.filter(a => a.source === 'userSettings') |
| const projectAgents = allAgents.filter(a => a.source === 'projectSettings') |
| const managedAgents = allAgents.filter(a => a.source === 'policySettings') |
| const flagAgents = allAgents.filter(a => a.source === 'flagSettings') |
|
|
| const agentGroups = [ |
| builtInAgents, |
| pluginAgents, |
| userAgents, |
| projectAgents, |
| flagAgents, |
| managedAgents, |
| ] |
|
|
| const agentMap = new Map<string, AgentDefinition>() |
|
|
| for (const agents of agentGroups) { |
| for (const agent of agents) { |
| agentMap.set(agent.agentType, agent) |
| } |
| } |
|
|
| return Array.from(agentMap.values()) |
| } |
|
|
| |
| |
| |
| |
| |
| |
| export function hasRequiredMcpServers( |
| agent: AgentDefinition, |
| availableServers: string[], |
| ): boolean { |
| if (!agent.requiredMcpServers || agent.requiredMcpServers.length === 0) { |
| return true |
| } |
| |
| return agent.requiredMcpServers.every(pattern => |
| availableServers.some(server => |
| server.toLowerCase().includes(pattern.toLowerCase()), |
| ), |
| ) |
| } |
|
|
| |
| |
| |
| |
| |
| |
| export function filterAgentsByMcpRequirements( |
| agents: AgentDefinition[], |
| availableServers: string[], |
| ): AgentDefinition[] { |
| return agents.filter(agent => hasRequiredMcpServers(agent, availableServers)) |
| } |
|
|
| |
| |
| |
| |
| |
| async function initializeAgentMemorySnapshots( |
| agents: CustomAgentDefinition[], |
| ): Promise<void> { |
| await Promise.all( |
| agents.map(async agent => { |
| if (agent.memory !== 'user') return |
| const result = await checkAgentMemorySnapshot( |
| agent.agentType, |
| agent.memory, |
| ) |
| switch (result.action) { |
| case 'initialize': |
| logForDebugging( |
| `Initializing ${agent.agentType} memory from project snapshot`, |
| ) |
| await initializeFromSnapshot( |
| agent.agentType, |
| agent.memory, |
| result.snapshotTimestamp!, |
| ) |
| break |
| case 'prompt-update': |
| agent.pendingSnapshotUpdate = { |
| snapshotTimestamp: result.snapshotTimestamp!, |
| } |
| logForDebugging( |
| `Newer snapshot available for ${agent.agentType} memory (snapshot: ${result.snapshotTimestamp})`, |
| ) |
| break |
| } |
| }), |
| ) |
| } |
|
|
| export const getAgentDefinitionsWithOverrides = memoize( |
| async (cwd: string): Promise<AgentDefinitionsResult> => { |
| |
| if (isEnvTruthy(process.env.CLAUDE_CODE_SIMPLE)) { |
| const builtInAgents = getBuiltInAgents() |
| return { |
| activeAgents: builtInAgents, |
| allAgents: builtInAgents, |
| } |
| } |
|
|
| try { |
| const markdownFiles = await loadMarkdownFilesForSubdir('agents', cwd) |
|
|
| const failedFiles: Array<{ path: string; error: string }> = [] |
| const customAgents = markdownFiles |
| .map(({ filePath, baseDir, frontmatter, content, source }) => { |
| const agent = parseAgentFromMarkdown( |
| filePath, |
| baseDir, |
| frontmatter, |
| content, |
| source, |
| ) |
| if (!agent) { |
| |
| |
| |
| if (!frontmatter['name']) { |
| return null |
| } |
| const errorMsg = getParseError(frontmatter) |
| failedFiles.push({ path: filePath, error: errorMsg }) |
| logForDebugging( |
| `Failed to parse agent from ${filePath}: ${errorMsg}`, |
| ) |
| logEvent('tengu_agent_parse_error', { |
| error: |
| errorMsg as AnalyticsMetadata_I_VERIFIED_THIS_IS_NOT_CODE_OR_FILEPATHS, |
| location: |
| source as AnalyticsMetadata_I_VERIFIED_THIS_IS_NOT_CODE_OR_FILEPATHS, |
| }) |
| return null |
| } |
| return agent |
| }) |
| .filter(agent => agent !== null) |
|
|
| |
| |
| |
| let pluginAgentsPromise = loadPluginAgents() |
| if (feature('AGENT_MEMORY_SNAPSHOT') && isAutoMemoryEnabled()) { |
| const [pluginAgents_] = await Promise.all([ |
| pluginAgentsPromise, |
| initializeAgentMemorySnapshots(customAgents), |
| ]) |
| pluginAgentsPromise = Promise.resolve(pluginAgents_) |
| } |
| const pluginAgents = await pluginAgentsPromise |
|
|
| const builtInAgents = getBuiltInAgents() |
|
|
| const allAgentsList: AgentDefinition[] = [ |
| ...builtInAgents, |
| ...pluginAgents, |
| ...customAgents, |
| ] |
|
|
| const activeAgents = getActiveAgentsFromList(allAgentsList) |
|
|
| |
| for (const agent of activeAgents) { |
| if (agent.color) { |
| setAgentColor(agent.agentType, agent.color) |
| } |
| } |
|
|
| return { |
| activeAgents, |
| allAgents: allAgentsList, |
| failedFiles: failedFiles.length > 0 ? failedFiles : undefined, |
| } |
| } catch (error) { |
| const errorMessage = |
| error instanceof Error ? error.message : String(error) |
| logForDebugging(`Error loading agent definitions: ${errorMessage}`) |
| logError(error) |
| |
| const builtInAgents = getBuiltInAgents() |
| return { |
| activeAgents: builtInAgents, |
| allAgents: builtInAgents, |
| failedFiles: [{ path: 'unknown', error: errorMessage }], |
| } |
| } |
| }, |
| ) |
|
|
| export function clearAgentDefinitionsCache(): void { |
| getAgentDefinitionsWithOverrides.cache.clear?.() |
| clearPluginAgentCache() |
| } |
|
|
| |
| |
| |
| function getParseError(frontmatter: Record<string, unknown>): string { |
| const agentType = frontmatter['name'] |
| const description = frontmatter['description'] |
|
|
| if (!agentType || typeof agentType !== 'string') { |
| return 'Missing required "name" field in frontmatter' |
| } |
|
|
| if (!description || typeof description !== 'string') { |
| return 'Missing required "description" field in frontmatter' |
| } |
|
|
| return 'Unknown parsing error' |
| } |
|
|
| |
| |
| |
| |
| |
| |
| function parseHooksFromFrontmatter( |
| frontmatter: Record<string, unknown>, |
| agentType: string, |
| ): HooksSettings | undefined { |
| if (!frontmatter.hooks) { |
| return undefined |
| } |
|
|
| const result = HooksSchema().safeParse(frontmatter.hooks) |
| if (!result.success) { |
| logForDebugging( |
| `Invalid hooks in agent '${agentType}': ${result.error.message}`, |
| ) |
| return undefined |
| } |
| return result.data |
| } |
|
|
| |
| |
| |
| export function parseAgentFromJson( |
| name: string, |
| definition: unknown, |
| source: SettingSource = 'flagSettings', |
| ): CustomAgentDefinition | null { |
| try { |
| const parsed = AgentJsonSchema().parse(definition) |
|
|
| let tools = parseAgentToolsFromFrontmatter(parsed.tools) |
|
|
| |
| if (isAutoMemoryEnabled() && parsed.memory && tools !== undefined) { |
| const toolSet = new Set(tools) |
| for (const tool of [ |
| FILE_WRITE_TOOL_NAME, |
| FILE_EDIT_TOOL_NAME, |
| FILE_READ_TOOL_NAME, |
| ]) { |
| if (!toolSet.has(tool)) { |
| tools = [...tools, tool] |
| } |
| } |
| } |
|
|
| const disallowedTools = |
| parsed.disallowedTools !== undefined |
| ? parseAgentToolsFromFrontmatter(parsed.disallowedTools) |
| : undefined |
|
|
| const systemPrompt = parsed.prompt |
|
|
| const agent: CustomAgentDefinition = { |
| agentType: name, |
| whenToUse: parsed.description, |
| ...(tools !== undefined ? { tools } : {}), |
| ...(disallowedTools !== undefined ? { disallowedTools } : {}), |
| getSystemPrompt: () => { |
| if (isAutoMemoryEnabled() && parsed.memory) { |
| return ( |
| systemPrompt + '\n\n' + loadAgentMemoryPrompt(name, parsed.memory) |
| ) |
| } |
| return systemPrompt |
| }, |
| source, |
| ...(parsed.model ? { model: parsed.model } : {}), |
| ...(parsed.effort !== undefined ? { effort: parsed.effort } : {}), |
| ...(parsed.permissionMode |
| ? { permissionMode: parsed.permissionMode } |
| : {}), |
| ...(parsed.mcpServers && parsed.mcpServers.length > 0 |
| ? { mcpServers: parsed.mcpServers } |
| : {}), |
| ...(parsed.hooks ? { hooks: parsed.hooks } : {}), |
| ...(parsed.maxTurns !== undefined ? { maxTurns: parsed.maxTurns } : {}), |
| ...(parsed.skills && parsed.skills.length > 0 |
| ? { skills: parsed.skills } |
| : {}), |
| ...(parsed.initialPrompt ? { initialPrompt: parsed.initialPrompt } : {}), |
| ...(parsed.background ? { background: parsed.background } : {}), |
| ...(parsed.memory ? { memory: parsed.memory } : {}), |
| ...(parsed.isolation ? { isolation: parsed.isolation } : {}), |
| } |
|
|
| return agent |
| } catch (error) { |
| const errorMessage = error instanceof Error ? error.message : String(error) |
| logForDebugging(`Error parsing agent '${name}' from JSON: ${errorMessage}`) |
| logError(error) |
| return null |
| } |
| } |
|
|
| |
| |
| |
| export function parseAgentsFromJson( |
| agentsJson: unknown, |
| source: SettingSource = 'flagSettings', |
| ): AgentDefinition[] { |
| try { |
| const parsed = AgentsJsonSchema().parse(agentsJson) |
| return Object.entries(parsed) |
| .map(([name, def]) => parseAgentFromJson(name, def, source)) |
| .filter((agent): agent is CustomAgentDefinition => agent !== null) |
| } catch (error) { |
| const errorMessage = error instanceof Error ? error.message : String(error) |
| logForDebugging(`Error parsing agents from JSON: ${errorMessage}`) |
| logError(error) |
| return [] |
| } |
| } |
|
|
| |
| |
| |
| export function parseAgentFromMarkdown( |
| filePath: string, |
| baseDir: string, |
| frontmatter: Record<string, unknown>, |
| content: string, |
| source: SettingSource, |
| ): CustomAgentDefinition | null { |
| try { |
| const agentType = frontmatter['name'] |
| let whenToUse = frontmatter['description'] as string |
|
|
| |
| |
| if (!agentType || typeof agentType !== 'string') { |
| return null |
| } |
| if (!whenToUse || typeof whenToUse !== 'string') { |
| logForDebugging( |
| `Agent file ${filePath} is missing required 'description' in frontmatter`, |
| ) |
| return null |
| } |
|
|
| |
| whenToUse = whenToUse.replace(/\\n/g, '\n') |
|
|
| const color = frontmatter['color'] as AgentColorName | undefined |
| const modelRaw = frontmatter['model'] |
| let model: string | undefined |
| if (typeof modelRaw === 'string' && modelRaw.trim().length > 0) { |
| const trimmed = modelRaw.trim() |
| model = trimmed.toLowerCase() === 'inherit' ? 'inherit' : trimmed |
| } |
|
|
| |
| const backgroundRaw = frontmatter['background'] |
|
|
| if ( |
| backgroundRaw !== undefined && |
| backgroundRaw !== 'true' && |
| backgroundRaw !== 'false' && |
| backgroundRaw !== true && |
| backgroundRaw !== false |
| ) { |
| logForDebugging( |
| `Agent file ${filePath} has invalid background value '${backgroundRaw}'. Must be 'true', 'false', or omitted.`, |
| ) |
| } |
|
|
| const background = |
| backgroundRaw === 'true' || backgroundRaw === true ? true : undefined |
|
|
| |
| const VALID_MEMORY_SCOPES: AgentMemoryScope[] = ['user', 'project', 'local'] |
| const memoryRaw = frontmatter['memory'] as string | undefined |
| let memory: AgentMemoryScope | undefined |
| if (memoryRaw !== undefined) { |
| if (VALID_MEMORY_SCOPES.includes(memoryRaw as AgentMemoryScope)) { |
| memory = memoryRaw as AgentMemoryScope |
| } else { |
| logForDebugging( |
| `Agent file ${filePath} has invalid memory value '${memoryRaw}'. Valid options: ${VALID_MEMORY_SCOPES.join(', ')}`, |
| ) |
| } |
| } |
|
|
| |
| type IsolationMode = 'worktree' | 'remote' |
| const VALID_ISOLATION_MODES: readonly IsolationMode[] = |
| process.env.USER_TYPE === 'ant' ? ['worktree', 'remote'] : ['worktree'] |
| const isolationRaw = frontmatter['isolation'] as string | undefined |
| let isolation: IsolationMode | undefined |
| if (isolationRaw !== undefined) { |
| if (VALID_ISOLATION_MODES.includes(isolationRaw as IsolationMode)) { |
| isolation = isolationRaw as IsolationMode |
| } else { |
| logForDebugging( |
| `Agent file ${filePath} has invalid isolation value '${isolationRaw}'. Valid options: ${VALID_ISOLATION_MODES.join(', ')}`, |
| ) |
| } |
| } |
|
|
| |
| const effortRaw = frontmatter['effort'] |
| const parsedEffort = |
| effortRaw !== undefined ? parseEffortValue(effortRaw) : undefined |
|
|
| if (effortRaw !== undefined && parsedEffort === undefined) { |
| logForDebugging( |
| `Agent file ${filePath} has invalid effort '${effortRaw}'. Valid options: ${EFFORT_LEVELS.join(', ')} or an integer`, |
| ) |
| } |
|
|
| |
| const permissionModeRaw = frontmatter['permissionMode'] as |
| | string |
| | undefined |
| const isValidPermissionMode = |
| permissionModeRaw && |
| (PERMISSION_MODES as readonly string[]).includes(permissionModeRaw) |
|
|
| if (permissionModeRaw && !isValidPermissionMode) { |
| const errorMsg = `Agent file ${filePath} has invalid permissionMode '${permissionModeRaw}'. Valid options: ${PERMISSION_MODES.join(', ')}` |
| logForDebugging(errorMsg) |
| } |
|
|
| |
| const maxTurnsRaw = frontmatter['maxTurns'] |
| const maxTurns = parsePositiveIntFromFrontmatter(maxTurnsRaw) |
| if (maxTurnsRaw !== undefined && maxTurns === undefined) { |
| logForDebugging( |
| `Agent file ${filePath} has invalid maxTurns '${maxTurnsRaw}'. Must be a positive integer.`, |
| ) |
| } |
|
|
| |
| const filename = basename(filePath, '.md') |
|
|
| |
| let tools = parseAgentToolsFromFrontmatter(frontmatter['tools']) |
|
|
| |
| if (isAutoMemoryEnabled() && memory && tools !== undefined) { |
| const toolSet = new Set(tools) |
| for (const tool of [ |
| FILE_WRITE_TOOL_NAME, |
| FILE_EDIT_TOOL_NAME, |
| FILE_READ_TOOL_NAME, |
| ]) { |
| if (!toolSet.has(tool)) { |
| tools = [...tools, tool] |
| } |
| } |
| } |
|
|
| |
| const disallowedToolsRaw = frontmatter['disallowedTools'] |
| const disallowedTools = |
| disallowedToolsRaw !== undefined |
| ? parseAgentToolsFromFrontmatter(disallowedToolsRaw) |
| : undefined |
|
|
| |
| const skills = parseSlashCommandToolsFromFrontmatter(frontmatter['skills']) |
|
|
| const initialPromptRaw = frontmatter['initialPrompt'] |
| const initialPrompt = |
| typeof initialPromptRaw === 'string' && initialPromptRaw.trim() |
| ? initialPromptRaw |
| : undefined |
|
|
| |
| const mcpServersRaw = frontmatter['mcpServers'] |
| let mcpServers: AgentMcpServerSpec[] | undefined |
| if (Array.isArray(mcpServersRaw)) { |
| mcpServers = mcpServersRaw |
| .map(item => { |
| const result = AgentMcpServerSpecSchema().safeParse(item) |
| if (result.success) { |
| return result.data |
| } |
| logForDebugging( |
| `Agent file ${filePath} has invalid mcpServers item: ${jsonStringify(item)}. Error: ${result.error.message}`, |
| ) |
| return null |
| }) |
| .filter((item): item is AgentMcpServerSpec => item !== null) |
| } |
|
|
| |
| const hooks = parseHooksFromFrontmatter(frontmatter, agentType) |
|
|
| const systemPrompt = content.trim() |
| const agentDef: CustomAgentDefinition = { |
| baseDir, |
| agentType: agentType, |
| whenToUse: whenToUse, |
| ...(tools !== undefined ? { tools } : {}), |
| ...(disallowedTools !== undefined ? { disallowedTools } : {}), |
| ...(skills !== undefined ? { skills } : {}), |
| ...(initialPrompt !== undefined ? { initialPrompt } : {}), |
| ...(mcpServers !== undefined && mcpServers.length > 0 |
| ? { mcpServers } |
| : {}), |
| ...(hooks !== undefined ? { hooks } : {}), |
| getSystemPrompt: () => { |
| if (isAutoMemoryEnabled() && memory) { |
| const memoryPrompt = loadAgentMemoryPrompt(agentType, memory) |
| return systemPrompt + '\n\n' + memoryPrompt |
| } |
| return systemPrompt |
| }, |
| source, |
| filename, |
| ...(color && typeof color === 'string' && AGENT_COLORS.includes(color) |
| ? { color } |
| : {}), |
| ...(model !== undefined ? { model } : {}), |
| ...(parsedEffort !== undefined ? { effort: parsedEffort } : {}), |
| ...(isValidPermissionMode |
| ? { permissionMode: permissionModeRaw as PermissionMode } |
| : {}), |
| ...(maxTurns !== undefined ? { maxTurns } : {}), |
| ...(background ? { background } : {}), |
| ...(memory ? { memory } : {}), |
| ...(isolation ? { isolation } : {}), |
| } |
| return agentDef |
| } catch (error) { |
| const errorMessage = error instanceof Error ? error.message : String(error) |
| logForDebugging(`Error parsing agent from ${filePath}: ${errorMessage}`) |
| logError(error) |
| return null |
| } |
| } |
|
|