Skip to content

Code Walkthrough

This document provides a detailed walkthrough of how the code works, with diagrams showing the relationships between different components.

1. Entry Points and Main Flow

graph TD
    subgraph "Frontend Entry"
        USER[User Input]
        CHAT[ChatContainer.tsx]
        INPUT[UserInput.tsx]
    end

    subgraph "API Call"
        CTX[ChatContext.tsx]
        API[api.ts:getAIResponse]
        HTTP[HTTP POST]
    end

    subgraph "Backend Entry"
        ROUTE[chat.py:send_message]
        AGENT[financial_agent.py]
        RESP[Response]
    end

    USER --> INPUT
    INPUT --> CHAT
    CHAT --> CTX
    CTX --> API
    API --> HTTP
    HTTP --> ROUTE
    ROUTE --> AGENT
    AGENT --> RESP
    RESP --> CTX

    style USER fill:#fbbf24
    style CTX fill:#818cf8
    style AGENT fill:#4ade80

2. Backend Code Structure

classDiagram
    class FinancialAgentSystem {
        -conversation_state: ConversationState
        -yfinance_server: YFinanceMCPServer
        -web_search_server: WebSearchMCPServer
        -llm_client: Gemini
        +process_question(question, history)
    }

    class MCPServer {
        -name: string
        -tools: dict
        +register_tool(name, func, description)
        +call_tool(tool_name, kwargs)
    }

    class YFinanceMCPServer {
        -alpha_vantage_ts: TimeSeries
        -alpha_vantage_fd: FundamentalData
        +_get_stock_price(ticker)
        +_get_historical_data(ticker, period)
        +_get_portfolio_analysis(symbols, weights)
        +_get_company_info(ticker)
    }

    class WebSearchMCPServer {
        -client: Gemini
        +_search(query, focus)
        +_get_news(topic, timeframe)
    }

    class ConversationState {
        -messages: list
        -context: dict
        +add_message(role, content, metadata)
        +get_context_summary()
    }

    FinancialAgentSystem --> ConversationState
    FinancialAgentSystem --> YFinanceMCPServer
    FinancialAgentSystem --> WebSearchMCPServer
    YFinanceMCPServer --|> MCPServer
    WebSearchMCPServer --|> MCPServer

3. Frontend Component Hierarchy

graph TD
    subgraph "App Structure"
        APP[App.tsx]
        PROVIDER[ChatProvider]
        HEADER[Header.tsx]
        SIDEBAR[Sidebar.tsx]
        MAIN[Main Content]
    end

    subgraph "Chat Components"
        CONTAINER[ChatContainer.tsx]
        MESSAGE[Message.tsx]
        INPUT[UserInput.tsx]
    end

    subgraph "Tool Components"
        STOCK[StockCard.tsx]
        NEWS[NewsCard.tsx]
    end

    APP --> PROVIDER
    PROVIDER --> HEADER
    PROVIDER --> SIDEBAR
    PROVIDER --> MAIN
    MAIN --> CONTAINER
    CONTAINER --> MESSAGE
    CONTAINER --> INPUT
    MESSAGE --> STOCK
    MESSAGE --> NEWS

    style APP fill:#61dafb
    style PROVIDER fill:#818cf8
    style MESSAGE fill:#4ade80

4. API Endpoint Flow

# Backend: app/api/chat.py

@router.post("/", response_model=ChatResponse)
async def send_message(request: ChatRequest):
    """
    1. Check for Gemini API key
    2. Get conversation history from DB
    3. Process with financial_agent
    4. Format response for frontend
    5. Save to database
    6. Return ChatResponse
    """
flowchart TD
    REQ[Request: ChatRequest]

    CHECK{Gemini API?}
    HIST[Get History from DB]
    PROCESS[financial_agent.process_question]
    FORMAT[Format Response]
    SAVE[Save to DB]
    RETURN[Return ChatResponse]

    REQ --> CHECK
    CHECK -->|Yes| HIST
    CHECK -->|No| MOCK[Use Mock Service]
    HIST --> PROCESS
    MOCK --> FORMAT
    PROCESS --> FORMAT
    FORMAT --> SAVE
    SAVE --> RETURN

    style REQ fill:#fbbf24
    style PROCESS fill:#818cf8
    style RETURN fill:#4ade80

5. Financial Agent Processing Steps

# financial_agent.py: process_question()
stateDiagram-v2
    [*] --> AddUserMessage

    AddUserMessage --> GetContext
    note right of GetContext: Last 6 messages

    GetContext --> CreatePrompt
    note right of CreatePrompt: Include tools & context

    CreatePrompt --> GeminiPlan
    note left of GeminiPlan: AI creates JSON plan

    GeminiPlan --> ExecutePlan

    state ExecutePlan {
        [*] --> ReadStep
        ReadStep --> CheckAgent
        CheckAgent --> GatherData: data_gatherer
        CheckAgent --> Analyze: analyzer

        state GatherData {
            [*] --> CallTool
            CallTool --> RouteServer
            RouteServer --> Execute
            Execute --> StoreResult
            StoreResult --> [*]
        }

        GatherData --> ReadStep: Next step
        Analyze --> [*]: Done
    }

    ExecutePlan --> FormatResponse

    FormatResponse --> [*]

6. Data Source Selection Logic

# YFinanceMCPServer._get_stock_price()
flowchart TD
    START[Start: Get ticker]

    TRY1[Try yfinance.history]
    CHECK1{Has data?}

    TRY2[Try yf.download]
    CHECK2{Has data?}

    TRY3[Try Alpha Vantage]
    CHECK3{Success?}

    MOCK[Use Mock Data]
    CHECK4{Known ticker?}

    SUCCESS[Return data]
    ERROR[Return error]

    START --> TRY1
    TRY1 --> CHECK1
    CHECK1 -->|Yes| SUCCESS
    CHECK1 -->|No| TRY2
    TRY2 --> CHECK2
    CHECK2 -->|Yes| SUCCESS
    CHECK2 -->|No| TRY3
    TRY3 --> CHECK3
    CHECK3 -->|Yes| SUCCESS
    CHECK3 -->|No| MOCK
    MOCK --> CHECK4
    CHECK4 -->|Yes| SUCCESS
    CHECK4 -->|No| ERROR

    style START fill:#fbbf24
    style SUCCESS fill:#4ade80
    style ERROR fill:#ef4444

7. Frontend State Management

// ChatContext.tsx
graph TD
    subgraph ChatState ["ChatContext State"]
        STATE[State]
        STATE --> MESSAGES[messages: Message Array]
        STATE --> LOADING[isLoading: boolean]
    end

    subgraph Actions ["Actions"]
        SEND[sendMessage]
        CLEAR[clearChat]
    end

    subgraph Effects ["Effects"]
        SAVE[Save to localStorage]
        LOAD[Load from localStorage]
    end

    SEND --> API[Call API]
    API --> UPDATE[Update messages]
    UPDATE --> SAVE

    CLEAR --> RESET[Reset state]
    RESET --> SAVE

    LOAD --> STATE

    style STATE fill:#818cf8
    style SEND fill:#4ade80
    style API fill:#fbbf24

8. Tool Result Processing

# financial_agent.py: Format tools for frontend
graph LR
    subgraph "Gathered Data"
        RAW[Raw Results Dict]
        RAW --> CHECK{Status: success?}
    end

    subgraph "Type Detection"
        CHECK -->|Yes| DETECT[Detect tool type]
        DETECT --> PRICE{Has price?}
        DETECT --> NEWS{Has search/news?}
        DETECT --> PORT{Has portfolio?}
    end

    subgraph "Tool Creation"
        PRICE -->|Yes| STOCK[Create Stock Tool]
        NEWS -->|Yes| NEWST[Create News Tool]
        PORT -->|Yes| EARN[Create Earnings Tool]
    end

    subgraph "Output"
        STOCK --> ARRAY[tools array]
        NEWST --> ARRAY
        EARN --> ARRAY
    end

    style RAW fill:#fbbf24
    style ARRAY fill:#4ade80

9. Complete Example: "What's Apple stock price?"

sequenceDiagram
    participant U as User
    participant UI as UserInput.tsx
    participant CTX as ChatContext
    participant API as api.ts
    participant BE as Backend
    participant FA as FinancialAgent
    participant G1 as Gemini (Plan)
    participant YF as YFinance
    participant G2 as Gemini (Analysis)

    U->>UI: Types "What's Apple stock price?"
    UI->>CTX: sendMessage()
    CTX->>API: getAIResponse()
    API->>BE: POST /api/chat/
    BE->>FA: process_question()

    FA->>G1: Create plan for question
    G1-->>FA: {steps: [{tool: "get_stock_price", params: {ticker: "AAPL"}}]}

    FA->>YF: get_stock_price("AAPL")
    YF-->>FA: {price: 189.50, change: 2.35, ...}

    FA->>G2: Analyze data and create response
    G2-->>FA: "Apple (AAPL) is currently trading at $189.50..."

    FA-->>BE: {content: "...", tools: [{type: "price", data: {...}}]}
    BE-->>API: ChatResponse
    API-->>CTX: Message object
    CTX-->>UI: Update UI with message

    Note over UI: Displays message with StockCard

Key Code Patterns

1. Async/Await Pattern

async def process_question(self, question: str):
    # All I/O operations are async
    result = await self.yfinance_server.call_tool(...)

2. Error Handling Pattern

try:
    # Primary method
except Exception as e:
    try:
        # Fallback method
    except:
        # Final fallback

3. State Management Pattern

const [messages, setMessages] = useState<Message[]>([]);
// Immutable updates
setMessages(prev => [...prev, newMessage]);

4. Tool Registration Pattern

self.register_tool("get_stock_price", 
                  self._get_stock_price, 
                  "Get current stock price")

5. Response Formatting Pattern

return {
    "status": "success",
    "content": final_answer,
    "thinking": "\n".join(thinking_steps),
    "tools": formatted_tools
}