{"version":3,"file":"after-tool-call.mjs","names":[],"sources":["../../../src/hooks/after-tool-call.ts"],"sourcesContent":["/**\n * after_tool_call hook — Post-execution tracking and progression\n *\n * Handles:\n * - Onboarding progression (advance tutorial on tool success)\n * - Missing config detection (hint user about required env vars)\n * - Auto-record swaps to cost basis tracker\n * - Auto-record to transaction ledger (event-sourced audit trail)\n * - Auto-record costs to budget service\n * - Session recall indexing\n * - Evolution mode nudge tracking\n */\n\nimport { getOnboardingFlow, type OnboardingMessage } from '../services/onboarding-flow.js';\nimport { recordSwapTrade } from '../tools/cost-basis.js';\nimport { getTxLedger, toolToEventType, chainIdToName } from '../services/tx-ledger.js';\nimport { getBudgetService } from '../services/budget-service.js';\nimport { getEvolutionMode } from '../services/evolution-mode.js';\nimport { getSessionRecall } from '../services/session-recall.js';\nimport { parseSessionKey, extractSenderId, extractChannelId, type ChannelId } from '../services/channel-sender.js';\nimport { getCredentialVault } from '../services/credential-vault.js';\n\n/** Dependencies injected by the plugin register() function. */\nexport interface AfterToolCallDeps {\n  /** The single source of truth for write-tool names. */\n  writeToolNames: Set<string>;\n  /** Send an onboarding message to a specific channel/user. */\n  sendOnboardingMessage: (channel: ChannelId, chatId: string, msg: OnboardingMessage) => Promise<void>;\n  /** Mark a conversation as handled by onboarding (sets flag with TTL). */\n  markOnboardingHandled: (chatId: string) => void;\n  /** Get current wallet connection state. */\n  getWalletState: () => {\n    connected: boolean;\n    address?: string | null;\n    chainId?: number | null;\n    mode?: string | null;\n  };\n  logger?: {\n    info?: (message: string, ...args: unknown[]) => void;\n    warn?: (message: string, ...args: unknown[]) => void;\n  } | null;\n}\n\n/**\n * Handle the after_tool_call hook event.\n *\n * This function contains all post-tool-call side effects: onboarding,\n * cost basis recording, ledger, budget, session recall, and evolution.\n */\nexport async function handleAfterToolCall(\n  event: any,\n  ctx: any,\n  deps: AfterToolCallDeps,\n): Promise<void> {\n  try {\n    // ── Credential leak scan ──────────────────────────────────\n    // Scan tool output for accidentally leaked secrets before it reaches the LLM.\n    try {\n      const result = event?.result ?? event?.details;\n      if (result) {\n        const text = typeof result === 'string' ? result : JSON.stringify(result);\n        const vault = getCredentialVault();\n        const scan = vault.scanForLeaks(text);\n        if (!scan.clean) {\n          deps.logger?.warn?.(\n            `[credential-leak] Tool \"${event?.toolName ?? event?.tool}\" output contains ${scan.leaks.length} leaked secret(s): ${scan.leaks.map((l: any) => l.type).join(', ')}. Redacting.`\n          );\n          // Mutate the result in-place so the LLM sees the redacted version\n          if (event && typeof event.result === 'string') {\n            event.result = scan.redactedText;\n          } else if (event?.result?.content) {\n            for (const block of event.result.content) {\n              if (block.type === 'text' && typeof block.text === 'string') {\n                const blockScan = vault.scanForLeaks(block.text);\n                if (!blockScan.clean) block.text = blockScan.redactedText;\n              }\n            }\n          }\n        }\n      }\n    } catch {\n      // Leak scanning is best-effort — never block the pipeline\n    }\n\n    // ── Onboarding progression ─────────────────────────────────\n    const sessionKey = ctx?.sessionKey ?? '';\n    const parsedSession = parseSessionKey(sessionKey);\n    const userId = parsedSession?.userId ?? extractSenderId(null, ctx);\n    const channel: ChannelId = parsedSession?.channel ?? extractChannelId(ctx) ?? 'telegram';\n\n    if (userId) {\n      const flow = getOnboardingFlow(userId);\n      if (flow.isActive) {\n        const toolName = event?.toolName ?? event?.tool;\n        const success = !event?.error;\n        const response = flow.processToolResult(String(toolName), success);\n        if (response) {\n          // Derive chatId the same way message_received and message_sending do:\n          // ctx.conversationId is the canonical key, falling back to userId for DMs.\n          const chatId = ctx?.conversationId ? String(ctx.conversationId) : String(userId);\n          await deps.sendOnboardingMessage(channel, chatId, response).catch((err: any) =>\n            deps.logger?.warn?.(`[crypto] Failed to send onboarding msg: ${err}`));\n          deps.markOnboardingHandled(chatId);\n          deps.logger?.info?.(\n            `[crypto] Onboarding advanced for user ${userId}: ${flow.currentStep}`\n          );\n        }\n      }\n    }\n\n    // ── Missing config detection ──────────────────────────────\n    const tool = event?.toolName ?? event?.tool;\n    const result = event?.result ?? event?.details;\n    const errorStr = typeof event?.error === 'string' ? event.error\n      : typeof result === 'string' ? result : '';\n\n    if (event?.error || (typeof result === 'string' && result.includes('error'))) {\n      const MISSING_CONFIG_HINTS: Record<string, { envVar: string; hint: string }> = {\n        herd_intelligence: {\n          envVar: 'HERD_ACCESS_TOKEN',\n          hint: 'Get a token from the Herd dashboard, then set HERD_ACCESS_TOKEN.\\n  Fly.io: `/flykeys set HERD_ACCESS_TOKEN your-token` then /flyrestart\\n  Docker: add to your `.env` file and restart',\n        },\n        hummingbot: {\n          envVar: 'HUMMINGBOT_API_URL',\n          hint: 'Point to a running Hummingbot instance. Set HUMMINGBOT_API_URL.\\n  Fly.io: `/flykeys set HUMMINGBOT_API_URL http://your-hummingbot:8000` then /flyrestart\\n  Docker: add to your `.env` file and restart',\n        },\n        molten: {\n          envVar: 'MOLTEN_API_KEY',\n          hint: 'Register on Molten first (ask me to \"register on Molten\"), then set MOLTEN_API_KEY.\\n  Fly.io: `/flykeys set MOLTEN_API_KEY your-key` then /flyrestart\\n  Docker: add to your `.env` file and restart',\n        },\n        bankr_launch: {\n          envVar: 'BANKR_API_KEY',\n          hint: 'Connect via Bankr first: /connect_bankr',\n        },\n        bankr_automate: {\n          envVar: 'BANKR_API_KEY',\n          hint: 'Connect via Bankr first: /connect_bankr',\n        },\n        bankr_polymarket: {\n          envVar: 'BANKR_API_KEY',\n          hint: 'Connect via Bankr first: /connect_bankr',\n        },\n        bankr_leverage: {\n          envVar: 'BANKR_API_KEY',\n          hint: 'Connect via Bankr first: /connect_bankr',\n        },\n      };\n\n      const configHint = MISSING_CONFIG_HINTS[String(tool)];\n      if (configHint && !process.env[configHint.envVar]) {\n        const chatId = ctx?.conversationId ?? userId;\n        if (chatId) {\n          await deps.sendOnboardingMessage(channel, String(chatId), {\n            text: `This feature requires ${configHint.envVar} to be configured.\\n\\n${configHint.hint}`,\n          }).catch((err: any) =>\n            deps.logger?.warn?.(`[crypto] Failed to send config hint: ${err}`));\n        }\n      }\n    }\n\n    // ── Auto-record swaps to cost basis tracker ────────────────\n    if (tool === 'defi_swap' && result && !event?.error) {\n      try {\n        const data = typeof result === 'string' ? JSON.parse(result) : result;\n        const details = data?.details ?? data;\n        if (details?.status === 'success' && details?.txHash) {\n          const sellToken = details.sellToken ?? details.sell_token;\n          const buyToken = details.buyToken ?? details.buy_token;\n          const sellAmount = parseFloat(details.sellAmount ?? details.sell_amount ?? '0');\n          const buyAmount = parseFloat(details.buyAmount ?? details.buy_amount ?? '0');\n          const sellSymbol = details.sellSymbol ?? details.sell_symbol ?? 'UNKNOWN';\n          const buySymbol = details.buySymbol ?? details.buy_symbol ?? 'UNKNOWN';\n          const txHash = details.txHash ?? details.tx_hash;\n\n          if (sellToken && sellAmount > 0) {\n            const priceUsd = buyAmount > 0 && sellAmount > 0\n              ? (details.sellValueUsd ?? details.sell_value_usd ?? 0) / sellAmount\n              : 0;\n            if (priceUsd > 0) {\n              recordSwapTrade({\n                token: sellToken,\n                symbol: sellSymbol,\n                amount: sellAmount,\n                priceUsd,\n                type: 'sell',\n                txHash,\n              });\n            }\n          }\n          if (buyToken && buyAmount > 0) {\n            const priceUsd = buyAmount > 0\n              ? (details.buyValueUsd ?? details.buy_value_usd ?? details.sellValueUsd ?? details.sell_value_usd ?? 0) / buyAmount\n              : 0;\n            if (priceUsd > 0) {\n              recordSwapTrade({\n                token: buyToken,\n                symbol: buySymbol,\n                amount: buyAmount,\n                priceUsd,\n                type: 'buy',\n                txHash,\n              });\n            }\n          }\n          deps.logger?.info?.(\n            `[crypto] Auto-recorded swap: ${sellSymbol} → ${buySymbol} (${txHash?.slice(0, 10)}...)`\n          );\n        }\n      } catch (swapErr) {\n        deps.logger?.warn?.(\n          `[crypto] Failed to auto-record swap: ${swapErr instanceof Error ? swapErr.message : String(swapErr)}`\n        );\n      }\n    }\n\n    // ── Auto-record to Transaction Ledger ─────────────────────────\n    if (tool && deps.writeToolNames.has(String(tool))) {\n      const writeData = typeof result === 'string' ? (() => { try { return JSON.parse(result); } catch { return {}; } })() : (result ?? {});\n      const details = (writeData as any)?.details ?? writeData;\n      const walletState = deps.getWalletState();\n\n      try {\n        const ledger = getTxLedger();\n\n        ledger.append({\n          type: toolToEventType(String(tool)),\n          userId: userId ?? 'unknown',\n          txHash: details?.txHash ?? details?.tx_hash ?? null,\n          chainId: details?.chainId ?? walletState.chainId ?? 8453,\n          chain: chainIdToName(details?.chainId ?? walletState.chainId ?? 8453),\n          from: walletState.address ?? 'unknown',\n          to: details?.to ?? details?.contract ?? null,\n          status: event?.error ? 'failed' : (details?.status === 'success' ? 'confirmed' : 'pending'),\n          summary: details?.summary ?? `${String(tool)} call`,\n          data: typeof details === 'object' ? details : {},\n          gasCostUsd: details?.gasCostUsd ?? details?.gas_cost_usd,\n          tool: String(tool),\n          error: event?.error ? String(event.error) : undefined,\n        });\n      } catch (ledgerErr) {\n        deps.logger?.warn?.(\n          `[crypto] Failed to record to tx ledger: ${ledgerErr instanceof Error ? ledgerErr.message : String(ledgerErr)}`\n        );\n      }\n\n      // ── Auto-record costs to Budget Service ─────────────────────\n      try {\n        const budgetSvc = getBudgetService();\n        const budgetUserId = userId ?? 'unknown';\n        const activeSession = budgetSvc.getActiveSession(budgetUserId);\n        if (activeSession) {\n          const gasCostUsd = parseFloat(details?.gasCostUsd ?? details?.gas_cost_usd ?? '0') || 0;\n          const feesUsd = parseFloat(details?.feesUsd ?? details?.fees_usd ?? '0') || 0;\n          const slippageUsd = parseFloat(details?.slippageUsd ?? details?.slippage_usd ?? '0') || 0;\n          const tradeValueUsd = parseFloat(details?.sellValueUsd ?? details?.sell_value_usd ?? details?.valueUsd ?? '0') || 0;\n\n          budgetSvc.recordCost(activeSession.id, {\n            stepLabel: `${String(tool)}: ${details?.summary ?? 'operation'}`,\n            gasUsd: Math.max(0, gasCostUsd),\n            slippageUsd: Math.max(0, slippageUsd),\n            feesUsd: Math.max(0, feesUsd),\n            tradeValueUsd: Math.max(0, tradeValueUsd),\n            txHash: details?.txHash ?? details?.tx_hash,\n          });\n\n          const check = budgetSvc.checkBudget(activeSession.id);\n          if (!check.ok) {\n            deps.logger?.warn?.(\n              `[crypto] Budget exceeded for user ${budgetUserId}: ${check.blockers.join('; ')}`\n            );\n          }\n        }\n      } catch (budgetErr) {\n        deps.logger?.warn?.(\n          `[crypto] Failed to record to budget service: ${budgetErr instanceof Error ? budgetErr.message : String(budgetErr)}`\n        );\n      }\n    }\n\n    // ── Session recall: index tool results ────────────────────────\n    try {\n      const recallSessionKey = ctx?.sessionKey ?? (parsedSession ? `${parsedSession.channel}-${parsedSession.userId}` : undefined);\n      if (recallSessionKey) {\n        const toolName = event?.toolName ?? event?.tool ?? 'unknown';\n        const toolResult = event?.result ?? event?.details;\n        const resultStr = typeof toolResult === 'string'\n          ? toolResult\n          : (toolResult ? JSON.stringify(toolResult).slice(0, 2000) : '');\n        if (resultStr) {\n          getSessionRecall().recordTurn({\n            sessionKey: recallSessionKey,\n            role: 'assistant',\n            content: `[tool:${toolName}] ${resultStr}`.slice(0, 2000),\n            userId: userId ? String(userId) : undefined,\n            timestamp: Date.now(),\n          });\n        }\n      }\n    } catch {\n      // Non-critical\n    }\n\n    // ── Evolution mode: nudge tracking ────────────────────────────\n    try {\n      if (userId) {\n        const evo = getEvolutionMode();\n        if (evo.isEvolving(String(userId))) {\n          const nudge = evo.recordTurn(String(userId));\n          if (nudge) {\n            deps.logger?.info?.(`[crypto] Evolution nudge for ${userId}: ${nudge.slice(0, 80)}...`);\n          }\n        }\n      }\n    } catch {\n      // Non-critical\n    }\n  } catch (err) {\n    deps.logger?.warn?.(\n      `[crypto] After tool call hook error: ${err instanceof Error ? err.message : String(err)}`\n    );\n  }\n}\n"],"mappings":"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"}