---
created: 2026-03-30
type: log
project: "[[Smart Support]]"
source: docs/phases/phase-1-dev-log.md
tags:
  - dev-log
  - phase-1
  - fastapi
  - websocket
  - langgraph
  - agent-orchestration
  - postgresql
  - react
  - testing
  - docker
  - yaml-registry
  - interrupt
  - token-tracking
---

# Phase 1: Core Framework -- Development Log

> Status: COMPLETED
> Phase branch: `phase-1/core-framework`
> Date started: 2026-03-30
> Date completed: 2026-03-30
> Related plan section: [Phase 1 in DEVELOPMENT-PLAN](../DEVELOPMENT-PLAN.md#phase-1-核心框架-第-1-3-周)

## What Was Built

- FastAPI WebSocket backend with `/ws` endpoint for real-time chat
- LangGraph Supervisor (via `langgraph-supervisor`) connecting 3 agents
- YAML-based Agent Registry with Pydantic validation
- 3 Mock Agents: order_lookup (read), order_actions (write + interrupt), fallback
- PostgresSaver checkpoint persistence via `langgraph-checkpoint-postgres`
- Session TTL management with 30-minute sliding window and interrupt extension
- LLM provider abstraction (Anthropic/OpenAI/Google) with prompt caching support
- Token usage tracking callback handler
- React Chat UI with streaming display, interrupt confirmation, and agent action viewer
- Docker Compose configuration (PostgreSQL 16 + backend)

## Code Structure

### New files

Backend (`backend/app/`):
- `config.py` -- pydantic-settings centralized configuration
- `db.py` -- Async PostgreSQL pool + AsyncPostgresSaver setup
- `llm.py` -- LLM provider factory (ChatAnthropic/ChatOpenAI/ChatGoogleGenerativeAI)
- `callbacks.py` -- Token usage + cost tracking callback handler
- `registry.py` -- YAML agent registry with validation + immutable config models
- `session_manager.py` -- Session TTL with sliding window + interrupt extension
- `graph.py` -- LangGraph Supervisor construction from registry
- `ws_handler.py` -- WebSocket message dispatch + streaming logic
- `main.py` -- FastAPI app entry with lifespan + WebSocket endpoint
- `agents/__init__.py` -- Tool name-to-function bridge
- `agents/order_lookup.py` -- Mock order status/tracking tools
- `agents/order_actions.py` -- Mock cancel_order with interrupt()
- `agents/fallback.py` -- Fallback response tool

Frontend (`frontend/src/`):
- `types.ts` -- WebSocket message protocol TypeScript types
- `hooks/useWebSocket.ts` -- WebSocket connection + reconnect + message dispatch
- `components/ChatMessages.tsx` -- Streaming message display
- `components/ChatInput.tsx` -- Message input
- `components/InterruptPrompt.tsx` -- Approve/reject interrupt UI
- `components/AgentAction.tsx` -- Tool call inline display
- `pages/ChatPage.tsx` -- Main chat page composing all components

Infrastructure:
- `backend/pyproject.toml` -- Dependencies + pytest + ruff config
- `backend/agents.yaml` -- Agent registry YAML config
- `backend/Dockerfile` -- Backend container
- `docker-compose.yml` -- PostgreSQL 16 + backend services
- `.gitignore` -- Updated for Python + Node artifacts

Tests (`backend/tests/unit/`):
- `test_config.py` -- Settings validation tests
- `test_registry.py` -- 17 tests for registry loading/validation
- `test_agents.py` -- 10 tests for tool functions + tool bridge
- `test_llm.py` -- 3 tests for LLM provider factory
- `test_callbacks.py` -- 9 tests for token usage tracking
- `test_session_manager.py` -- 9 tests for session TTL logic
- `test_graph.py` -- 4 tests for supervisor construction
- `test_db.py` -- 5 tests for database setup
- `test_ws_handler.py` -- 12 tests for WebSocket message handling
- `test_main.py` -- 5 tests for app configuration

## Test Coverage

- Unit test count: 82
- Integration test count: 0 (requires running PostgreSQL)
- E2E test count: 0 (manual verification in plan)
- Overall coverage: 88%

## Deviations from Plan

- Used `astream(stream_mode="messages")` instead of `astream_events()` per langgraph best practices
- Separated WebSocket handler logic into `ws_handler.py` for testability (not in original plan)
- Session manager uses in-memory storage instead of DB-backed (sufficient for Phase 1 single-instance)

## Known Issues / Tech Debt

- Session manager not DB-backed (loses state on restart) -- acceptable for Phase 1 single-instance
- WebSocket reconnect does not re-send pending interrupt state from server
- No rate limiting on WebSocket endpoint (Phase 2)
- No authentication (Phase 2)
- `main.py` coverage at 47% -- lifespan function not unit-testable without full DB
