{"version":3,"file":"agent-pool.mjs","names":[],"sources":["../../../src/services/agent-pool.ts"],"sourcesContent":["/**\n * Agent Pool — sub-agent definitions, CRUD, persistence, preset agents.\n *\n * Sub-agents are specialized LLM instances with custom system prompts and\n * restricted tool access. The main agent (the one the user talks to)\n * delegates tasks to sub-agents via the agent_delegate tool.\n *\n * Each sub-agent definition specifies:\n * - A system prompt (its \"personality\" and expertise)\n * - Which tools it can use (subset of built-in + user tools)\n * - Which model to use (defaults to haiku for cost efficiency)\n * - Budget and token limits per task\n *\n * Agent definitions persist to ~/.openclawnch/agents/ as JSON.\n *\n * Preset agents ship out-of-the-box and cannot be deleted (only disabled):\n * - strategist: DeFi strategy analysis and trade planning\n * - analyst: Market research, data analysis, report generation\n * - accountant: Tax, cost basis, portfolio accounting\n * - risk_manager: Transaction risk assessment and approval recommendations\n */\n\nimport { existsSync, readFileSync, writeFileSync, mkdirSync } from 'node:fs';\nimport { join } from 'node:path';\nimport type { Address, Hex } from 'viem';\n\n// ─── Types ──────────────────────────────────────────────────────────────\n\nexport interface SubAgentDef {\n  /** Unique ID. Presets use 'preset_<name>'. */\n  id: string;\n  /** Agent name (snake_case, unique). */\n  name: string;\n  /** Human-readable label. */\n  label: string;\n  /** What this agent specializes in (shown to the main LLM). */\n  description: string;\n  /** System prompt sent to the sub-agent LLM. */\n  systemPrompt: string;\n  /** Which tools this agent can call. Empty = no tool access (reasoning only). */\n  allowedTools: string[];\n  /** Model shortcut or full ID. Default: 'haiku'. */\n  model: string;\n  /** Max output tokens per task. Default: 4096. */\n  maxTokens: number;\n  /** Temperature. Default: 0.3 (focused). */\n  temperature: number;\n  /** Max tool-use loop iterations per task. Default: 10. */\n  maxToolCalls: number;\n  /** Max time per task in ms. Default: 60000 (1 min). */\n  timeoutMs: number;\n  /** Whether this agent is currently enabled. */\n  enabled: boolean;\n  /** Whether this is a built-in preset (cannot be deleted). */\n  isPreset: boolean;\n  /** Who created this agent. 'system' for presets. */\n  createdBy: string;\n  /** Usage count. */\n  usageCount: number;\n  createdAt: number;\n  updatedAt: number;\n\n  // ── Sub-delegation identity (V7) ───────────────────────────────────\n  // Ephemeral keypair for sub-delegation. Generated at agent creation,\n  // NOT persisted to disk (regenerated on restart for security).\n  // The address is used as the delegate in child delegations.\n\n  /** Ephemeral wallet address for sub-delegation. */\n  walletAddress?: Address;\n  /** Ephemeral private key (hex). In-memory only, never serialized. */\n  walletPrivateKey?: Hex;\n  /** Parent delegation hash this agent's sub-delegation chains from. */\n  parentDelegationHash?: Hex;\n}\n\n// ─── Preset Agents ──────────────────────────────────────────────────────\n\nconst PRESETS: Omit<SubAgentDef, 'id' | 'usageCount' | 'createdAt' | 'updatedAt'>[] = [\n  {\n    name: 'strategist',\n    label: 'DeFi Strategist',\n    description: 'Analyzes DeFi opportunities, compares protocols, and recommends trade strategies. Good at evaluating risk/reward tradeoffs.',\n    systemPrompt:\n      `You are a DeFi strategist sub-agent. Your job is to analyze decentralized finance opportunities and provide actionable trade strategies.\\n\\n` +\n      `Guidelines:\\n` +\n      `- Always check current prices and balances before recommending trades\\n` +\n      `- Consider gas costs, slippage, and bridge fees in your analysis\\n` +\n      `- Quantify risk: estimate max drawdown, impermanent loss, or liquidation thresholds\\n` +\n      `- Compare at least 2 options when recommending strategies\\n` +\n      `- Be explicit about assumptions (timeframe, market conditions)\\n` +\n      `- Never recommend actions without explaining the reasoning\\n` +\n      `- Format output as structured analysis with clear sections`,\n    allowedTools: ['defi_price', 'defi_balance', 'analytics', 'market_intel', 'cost_basis', 'yield', 'liquidity', 'block_explorer'],\n    model: 'haiku',\n    maxTokens: 4096,\n    temperature: 0.3,\n    maxToolCalls: 10,\n    timeoutMs: 60_000,\n    enabled: true,\n    isPreset: true,\n    createdBy: 'system',\n  },\n  {\n    name: 'analyst',\n    label: 'Market Analyst',\n    description: 'Market research, token analysis, whale tracking, and data-driven insights. Produces structured reports.',\n    systemPrompt:\n      `You are a market analyst sub-agent. Your job is to research tokens, protocols, and market conditions, then produce concise analytical reports.\\n\\n` +\n      `Guidelines:\\n` +\n      `- Start by gathering current data (prices, volumes, on-chain metrics)\\n` +\n      `- Look for patterns: whale movements, liquidity shifts, governance activity\\n` +\n      `- Compare with historical context when relevant\\n` +\n      `- Distinguish between facts (on-chain data) and interpretation (your analysis)\\n` +\n      `- Flag uncertainty explicitly: \"data is limited\", \"this depends on...\"\\n` +\n      `- Output structured reports with: Summary, Key Findings, Data Points, Risks`,\n    allowedTools: ['defi_price', 'analytics', 'market_intel', 'block_explorer', 'herd_intelligence', 'watch_activity'],\n    model: 'haiku',\n    maxTokens: 4096,\n    temperature: 0.2,\n    maxToolCalls: 12,\n    timeoutMs: 60_000,\n    enabled: true,\n    isPreset: true,\n    createdBy: 'system',\n  },\n  {\n    name: 'accountant',\n    label: 'Crypto Accountant',\n    description: 'Tax calculations, cost basis tracking, P&L reports, and multi-currency accounting across crypto and fiat.',\n    systemPrompt:\n      `You are a crypto accounting sub-agent. Your job is to calculate cost basis, track P&L, and produce accounting reports.\\n\\n` +\n      `Guidelines:\\n` +\n      `- Use FIFO (First In, First Out) as the default cost basis method\\n` +\n      `- Track both realized and unrealized gains/losses\\n` +\n      `- Account for gas fees as part of the cost basis\\n` +\n      `- Handle multi-currency (crypto + fiat) positions\\n` +\n      `- Produce clear, auditable output with transaction references\\n` +\n      `- Flag any transactions with missing cost basis data\\n` +\n      `- Note: you provide calculations, not tax advice. Recommend a tax professional for filing.`,\n    allowedTools: ['cost_basis', 'defi_balance', 'defi_price', 'analytics', 'fiat_payment'],\n    model: 'haiku',\n    maxTokens: 4096,\n    temperature: 0.1,\n    maxToolCalls: 8,\n    timeoutMs: 60_000,\n    enabled: true,\n    isPreset: true,\n    createdBy: 'system',\n  },\n  {\n    name: 'risk_manager',\n    label: 'Risk Manager',\n    description: 'Evaluates transaction risk, checks approvals and allowances, assesses protocol safety, and recommends safeguards.',\n    systemPrompt:\n      `You are a risk management sub-agent. Your job is to evaluate the safety of proposed transactions and DeFi positions.\\n\\n` +\n      `Guidelines:\\n` +\n      `- Check token approvals and unlimited allowances (flag revocation opportunities)\\n` +\n      `- Evaluate smart contract risk: is the protocol audited? TVL? Age?\\n` +\n      `- Assess concentration risk: what % of portfolio is in one position?\\n` +\n      `- Check for common scam signals: honeypot tokens, fake liquidity, rug pull patterns\\n` +\n      `- Recommend position sizing based on risk tolerance\\n` +\n      `- Output: Risk Level (Low/Medium/High/Critical), Findings, Recommendations\\n` +\n      `- When in doubt, recommend caution. Better to miss a trade than lose funds.`,\n    allowedTools: ['approvals', 'defi_balance', 'defi_price', 'block_explorer', 'analytics', 'market_intel'],\n    model: 'haiku',\n    maxTokens: 2048,\n    temperature: 0.1,\n    maxToolCalls: 8,\n    timeoutMs: 45_000,\n    enabled: true,\n    isPreset: true,\n    createdBy: 'system',\n  },\n];\n\n// ─── Ephemeral Keypair Generation ───────────────────────────────────────\n\n/**\n * Generate an ephemeral keypair for sub-agent delegation.\n * Uses viem's generatePrivateKey + privateKeyToAccount.\n * These are in-memory only and NOT persisted to disk.\n */\nasync function generateEphemeralKeypair(): Promise<{ address: Address; privateKey: Hex }> {\n  const { generatePrivateKey, privateKeyToAccount } = await import('viem/accounts');\n  const privateKey = generatePrivateKey();\n  const account = privateKeyToAccount(privateKey);\n  return { address: account.address, privateKey };\n}\n\n// ─── Validation ─────────────────────────────────────────────────────────\n\nfunction isValidAgentName(name: string): boolean {\n  return /^[a-z][a-z0-9_]{2,30}$/.test(name);\n}\n\nconst RESERVED_AGENT_NAMES = new Set(PRESETS.map(p => p.name));\n\n// ─── Service ────────────────────────────────────────────────────────────\n\nexport class AgentPool {\n  private agents = new Map<string, SubAgentDef>();\n  private stateDir: string;\n\n  constructor(opts?: { stateDir?: string }) {\n    this.stateDir = opts?.stateDir ?? join(\n      process.env.HOME ?? '', '.openclawnch', 'agents'\n    );\n    this.initPresets();\n    this.loadState();\n  }\n\n  /** Create a new sub-agent. */\n  create(params: {\n    name: string;\n    label: string;\n    description: string;\n    systemPrompt: string;\n    createdBy: string;\n    allowedTools?: string[];\n    model?: string;\n    maxTokens?: number;\n    temperature?: number;\n    maxToolCalls?: number;\n    timeoutMs?: number;\n  }): SubAgentDef {\n    if (!isValidAgentName(params.name)) {\n      throw new AgentPoolError(\n        `Invalid agent name \"${params.name}\". Must be 3-30 chars, lowercase alphanumeric + underscores, starting with a letter.`\n      );\n    }\n    if (this.getByName(params.name)) {\n      throw new AgentPoolError(`An agent named \"${params.name}\" already exists.`);\n    }\n    if (params.systemPrompt.length < 20) {\n      throw new AgentPoolError('System prompt must be at least 20 characters.');\n    }\n\n    const id = `agent_${Date.now()}_${Math.random().toString(36).slice(2, 8)}`;\n    const now = Date.now();\n\n    const agent: SubAgentDef = {\n      id,\n      name: params.name,\n      label: params.label,\n      description: params.description,\n      systemPrompt: params.systemPrompt,\n      allowedTools: params.allowedTools ?? [],\n      model: params.model ?? 'haiku',\n      maxTokens: params.maxTokens ?? 4096,\n      temperature: params.temperature ?? 0.3,\n      maxToolCalls: params.maxToolCalls ?? 10,\n      timeoutMs: params.timeoutMs ?? 60_000,\n      enabled: true,\n      isPreset: false,\n      createdBy: params.createdBy,\n      usageCount: 0,\n      createdAt: now,\n      updatedAt: now,\n    };\n\n    this.agents.set(id, agent);\n    this.saveState();\n    return agent;\n  }\n\n  /** Update an existing agent. Cannot change name or isPreset. */\n  update(id: string, updates: Partial<Pick<SubAgentDef,\n    'label' | 'description' | 'systemPrompt' | 'allowedTools' | 'model' |\n    'maxTokens' | 'temperature' | 'maxToolCalls' | 'timeoutMs' | 'enabled'\n  >>): SubAgentDef | null {\n    const agent = this.agents.get(id);\n    if (!agent) return null;\n    Object.assign(agent, updates, { updatedAt: Date.now() });\n    this.saveState();\n    return agent;\n  }\n\n  /** Delete an agent. Presets cannot be deleted (disable them instead). */\n  delete(id: string): boolean {\n    const agent = this.agents.get(id);\n    if (!agent) return false;\n    if (agent.isPreset) {\n      throw new AgentPoolError(`Cannot delete preset agent \"${agent.name}\". Use disable instead.`);\n    }\n    this.agents.delete(id);\n    this.saveState();\n    return true;\n  }\n\n  get(id: string): SubAgentDef | null {\n    return this.agents.get(id) ?? null;\n  }\n\n  getByName(name: string): SubAgentDef | null {\n    for (const a of this.agents.values()) {\n      if (a.name === name) return a;\n    }\n    return null;\n  }\n\n  list(opts?: { enabled?: boolean; isPreset?: boolean }): SubAgentDef[] {\n    let all = Array.from(this.agents.values());\n    if (opts?.enabled !== undefined) all = all.filter(a => a.enabled === opts.enabled);\n    if (opts?.isPreset !== undefined) all = all.filter(a => a.isPreset === opts.isPreset);\n    return all.sort((a, b) => {\n      // Presets first, then by name\n      if (a.isPreset !== b.isPreset) return a.isPreset ? -1 : 1;\n      return a.name.localeCompare(b.name);\n    });\n  }\n\n  getEnabledAgents(): SubAgentDef[] {\n    return this.list({ enabled: true });\n  }\n\n  recordUsage(id: string): void {\n    const agent = this.agents.get(id);\n    if (agent) {\n      agent.usageCount += 1;\n      agent.updatedAt = Date.now();\n      this.saveState();\n    }\n  }\n\n  /** Clear all agents (for testing). */\n  clear(): void {\n    this.agents.clear();\n  }\n\n  /**\n   * Assign an ephemeral keypair to an agent for sub-delegation.\n   * Generated in-memory, never persisted to disk.\n   * Safe to call multiple times — skips if already assigned.\n   */\n  async assignEphemeralWallet(id: string): Promise<{ address: Address; privateKey: Hex } | null> {\n    const agent = this.agents.get(id);\n    if (!agent) return null;\n    if (agent.walletAddress && agent.walletPrivateKey) {\n      return { address: agent.walletAddress, privateKey: agent.walletPrivateKey };\n    }\n\n    const keypair = await generateEphemeralKeypair();\n    agent.walletAddress = keypair.address;\n    agent.walletPrivateKey = keypair.privateKey;\n    agent.updatedAt = Date.now();\n    // DO NOT saveState() — private keys must not be persisted\n    return keypair;\n  }\n\n  /**\n   * Get the ephemeral wallet for an agent (if assigned).\n   */\n  getWallet(id: string): { address: Address; privateKey: Hex } | null {\n    const agent = this.agents.get(id);\n    if (!agent?.walletAddress || !agent?.walletPrivateKey) return null;\n    return { address: agent.walletAddress, privateKey: agent.walletPrivateKey };\n  }\n\n  // ── Presets ─────────────────────────────────────────────────────────\n\n  private initPresets(): void {\n    const now = Date.now();\n    for (const preset of PRESETS) {\n      const id = `preset_${preset.name}`;\n      if (!this.agents.has(id)) {\n        this.agents.set(id, {\n          ...preset,\n          id,\n          usageCount: 0,\n          createdAt: now,\n          updatedAt: now,\n        });\n      }\n    }\n  }\n\n  // ── Persistence ─────────────────────────────────────────────────────\n\n  private loadState(): void {\n    try {\n      const filePath = join(this.stateDir, 'agents.json');\n      if (existsSync(filePath)) {\n        const data = JSON.parse(readFileSync(filePath, 'utf8'));\n        for (const a of data) {\n          // Loaded agents override presets (user may have disabled/modified them)\n          this.agents.set(a.id, a);\n        }\n      }\n    } catch { /* fresh start */ }\n  }\n\n  private saveState(): void {\n    try {\n      if (!existsSync(this.stateDir)) mkdirSync(this.stateDir, { recursive: true });\n      const filePath = join(this.stateDir, 'agents.json');\n      // Strip ephemeral wallet keys — NEVER persist private keys to disk\n      const serializable = Array.from(this.agents.values()).map(a => {\n        const { walletPrivateKey, walletAddress, parentDelegationHash, ...rest } = a;\n        return rest;\n      });\n      writeFileSync(filePath, JSON.stringify(serializable, null, 2), 'utf8');\n    } catch { /* best effort */ }\n  }\n}\n\n// ─── Error Class ────────────────────────────────────────────────────────\n\nexport class AgentPoolError extends Error {\n  constructor(message: string) {\n    super(message);\n    this.name = 'AgentPoolError';\n  }\n}\n\n// ─── Singleton ──────────────────────────────────────────────────────────\n\nlet instance: AgentPool | null = null;\n\nexport function getAgentPool(opts?: { stateDir?: string }): AgentPool {\n  if (!instance) {\n    instance = new AgentPool(opts);\n  }\n  return instance;\n}\n\nexport function resetAgentPool(): void {\n  instance?.clear();\n  instance = null;\n}\n"],"mappings":"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"}