{"version":3,"file":"ApprovalGateNode.cjs","sources":["../../../src/nodes/ApprovalGateNode.ts"],"sourcesContent":["import { interrupt } from '@langchain/langgraph';\nimport type { RunnableConfig } from '@langchain/core/runnables';\nimport type { ApprovalGateConfig, BaseGraphState } from '@/types/graph';\nimport type { ToolApprovalResponse } from '@/types/tools';\nimport { GraphEvents } from '@/common';\nimport { safeDispatchCustomEvent } from '@/utils/events';\n\n/**\n * Interrupt payload for approval gate nodes.\n * Passed to interrupt() and persisted in the checkpoint.\n */\nexport interface ApprovalGateInterrupt {\n  /** Discriminator to distinguish from tool approval interrupts */\n  type: 'approval_gate';\n  /** Unique gate identifier */\n  gateId: string;\n  /** Approval channel (chat, outlook, telegram) */\n  channel: string;\n  /** Human-readable prompt for the approver */\n  prompt?: string;\n  /** Approver identifier */\n  approver?: string;\n  /** Timeout in ms */\n  timeoutMs?: number;\n  /** Source agent ID (who just finished) */\n  sourceAgentId?: string;\n  /** Destination agent ID (who will run next if approved) */\n  destinationAgentId?: string;\n}\n\n/**\n * Creates a graph node function that acts as an approval gate.\n *\n * Unlike tool approval (which respects ExecutionContext and can be auto-approved\n * in scheduled/handoff modes), approval gates ALWAYS fire. They are placed by\n * the builder between agents in a sequence and represent explicit human\n * checkpoints that cannot be bypassed.\n *\n * Flow:\n * 1. Dispatch ON_APPROVAL_GATE notification (for SSE/persistence)\n * 2. Call interrupt() — graph pauses, state is checkpointed\n * 3. On resume, interrupt() returns the ToolApprovalResponse\n * 4. If approved, pass state through (next agent runs)\n * 5. If denied, return state as-is (routing handled by conditional edge)\n *\n * @param config - The approval gate configuration from the edge definition\n * @param sourceAgentId - The agent that precedes this gate\n * @param destinationAgentId - The agent that follows this gate\n */\nexport function createApprovalGateNode(\n  config: ApprovalGateConfig,\n  sourceAgentId: string,\n  destinationAgentId: string\n) {\n  const { gateId, channel = 'chat', prompt, approver, timeoutMs } = config;\n\n  /**\n   * The gate node function. Receives the current graph state,\n   * dispatches a notification, calls interrupt(), and returns\n   * the state with an approval result annotation.\n   */\n  return async function approvalGateNode(\n    state: BaseGraphState,\n    runnableConfig?: RunnableConfig\n  ): Promise<Partial<BaseGraphState>> {\n    const interruptPayload: ApprovalGateInterrupt = {\n      type: 'approval_gate',\n      gateId,\n      channel,\n      prompt,\n      approver,\n      timeoutMs,\n      sourceAgentId,\n      destinationAgentId,\n    };\n\n    // Dispatch notification event so the host can:\n    // 1. Persist the approval request to MongoDB\n    // 2. Route to the appropriate channel adapter\n    // 3. Emit SSE event for chat UI\n    safeDispatchCustomEvent(\n      GraphEvents.ON_APPROVAL_GATE,\n      interruptPayload,\n      runnableConfig\n    );\n\n    // Pause the graph — state is checkpointed by the MongoDBSaver.\n    // On resume via Command({ resume: ToolApprovalResponse }), interrupt()\n    // returns the response value.\n    const response = interrupt(interruptPayload) as ToolApprovalResponse;\n\n    // Return empty state update — the graph structure (conditional edges)\n    // handles routing based on the approval result. We store the response\n    // in a message so downstream nodes can access it if needed.\n    if (response.approved) {\n      return {};\n    }\n\n    // On denial, we could add a system message noting the denial.\n    // The conditional edge after this node will route to END or skip.\n    return {};\n  };\n}\n\n/**\n * Node ID for an approval gate, derived from the gate configuration.\n * Used by MultiAgentGraph when inserting gate nodes into the graph.\n */\nexport function getApprovalGateNodeId(gateId: string): string {\n  return `approval_gate_${gateId}`;\n}\n"],"names":["safeDispatchCustomEvent","GraphEvents","interrupt"],"mappings":";;;;;;;AA8BA;;;;;;;;;;;;;;;;;;AAkBG;SACa,sBAAsB,CACpC,MAA0B,EAC1B,aAAqB,EACrB,kBAA0B,EAAA;AAE1B,IAAA,MAAM,EAAE,MAAM,EAAE,OAAO,GAAG,MAAM,EAAE,MAAM,EAAE,QAAQ,EAAE,SAAS,EAAE,GAAG,MAAM;AAExE;;;;AAIG;AACH,IAAA,OAAO,eAAe,gBAAgB,CACpC,KAAqB,EACrB,cAA+B,EAAA;AAE/B,QAAA,MAAM,gBAAgB,GAA0B;AAC9C,YAAA,IAAI,EAAE,eAAe;YACrB,MAAM;YACN,OAAO;YACP,MAAM;YACN,QAAQ;YACR,SAAS;YACT,aAAa;YACb,kBAAkB;SACnB;;;;;QAMDA,8BAAuB,CACrBC,iBAAW,CAAC,gBAAgB,EAC5B,gBAAgB,EAChB,cAAc,CACf;;;;AAKD,QAAA,MAAM,QAAQ,GAAGC,mBAAS,CAAC,gBAAgB,CAAyB;;;;AAKpE,QAAA,IAAI,QAAQ,CAAC,QAAQ,EAAE;AACrB,YAAA,OAAO,EAAE;QACX;;;AAIA,QAAA,OAAO,EAAE;AACX,IAAA,CAAC;AACH;AAEA;;;AAGG;AACG,SAAU,qBAAqB,CAAC,MAAc,EAAA;IAClD,OAAO,CAAA,cAAA,EAAiB,MAAM,CAAA,CAAE;AAClC;;;;;"}