Documents
stockbroker
stockbroker
Type
External
Status
Published
Created
Mar 17, 2026
Updated
Mar 17, 2026

A stock trading assistant built with LangGraph that demonstrates human-in-the-loop workflows. The assistant can research stocks, analyze market data, and prepare trades, but requires explicit user approval before executing any transactions. This pattern is essential for applications where AI assists with high-stakes decisions.

Features#

  • Multi-step Workflows: Complex operations broken into LangGraph nodes
  • Human-in-the-Loop: Critical actions require user confirmation
  • State Persistence: Workflow state maintained across interactions
  • Tool Integration: Connected to stock market APIs
  • Approval UI: Clear interface for reviewing and approving actions
  • Audit Trail: Complete history of AI decisions and user approvals

How It Works#

┌─────────────┐ ┌─────────────┐ ┌─────────────┐
│ Research │────▶│ Analyze │────▶│ Prepare │
│ Stock │ │ Data │ │ Trade │
└─────────────┘ └─────────────┘ └─────────────┘
                                    ┌─────────────────┐
                                    │ Human Approval │
                                    │ (Required) │
                                    └─────────────────┘
                                    ┌─────────────────┐
                                    │ Execute Trade │
                                    └─────────────────┘
  1. User asks about a stock (e.g., "Should I buy AAPL?")
  2. AI researches the stock and analyzes market data
  3. AI prepares a trade recommendation
  4. Workflow pauses for user approval
  5. User reviews and approves/rejects the trade
  6. If approved, trade executes

Integration#

Uses @assistant-ui/react-langgraph for LangGraph integration:

import { useLangGraphRuntime } from "@assistant-ui/react-langgraph";
import { AssistantRuntimeProvider } from "@assistant-ui/react";
import { Thread } from "@/components/assistant-ui/thread";
import { Client } from "@langchain/langgraph-sdk";

const langGraphClient = new Client({
  apiUrl: process.env.LANGGRAPH_API_URL,
});

export default function StockbrokerChat() {
  const runtime = useLangGraphRuntime({
    stream: async (messages, { abortSignal, initialize }) => {
      const { remoteId } = await initialize();
      return langGraphClient.runs.stream(
        remoteId,
        "stockbroker-assistant",
        {
          input: { messages },
          streamMode: "messages",
        },
        { signal: abortSignal }
      );
    },
    create: async () => {
      const { thread_id } = await langGraphClient.threads.create();
      return { externalId: thread_id };
    },
  });

  return (
    <AssistantRuntimeProvider runtime={runtime}>
      <Thread />
    </AssistantRuntimeProvider>
  );
}

Human-in-the-Loop Pattern#

In your LangGraph workflow, define an interrupt point:

from langgraph.graph import StateGraph
from langgraph.checkpoint.memory import MemorySaver

def prepare_trade(state):
    # Prepare trade details
    return {"trade": trade_details, "needs_approval": True}

def execute_trade(state):
    # Execute the approved trade
    return {"result": "Trade executed"}

# Graph with interrupt
graph = StateGraph(State)
graph.add_node("prepare", prepare_trade)
graph.add_node("execute", execute_trade)

# Interrupt before execute for human approval
graph.add_edge("prepare", "execute")
app = graph.compile(interrupt_before=["execute"], checkpointer=MemorySaver())

Approval UI Component#

const TradeApproval = makeAssistantToolUI({
  toolName: "execute_trade",
  render: ({ args, status, addResult }) => {
    if (status.type === "requires-action") {
      return (
        <div className="rounded-lg border p-4">
          <h3>Trade Approval Required</h3>
          <p>Buy {args.shares} shares of {args.symbol}</p>
          <div className="flex gap-2">
            <Button onClick={() => addResult({ approved: true })}>
              Approve
            </Button>
            <Button onClick={() => addResult({ approved: false })}>
              Reject
            </Button>
          </div>
        </div>
      );
    }
    return <p>Trade {status}...</p>;
  },
});

Source#