diff --git a/README.md b/README.md index be354a8..f12f23e 100644 --- a/README.md +++ b/README.md @@ -45,10 +45,11 @@ User message -> Chat UI -> FastAPI WebSocket -> LangGraph Supervisor -> Speciali | Component | Technology | |-----------|-----------| | Backend | Python 3.11+, FastAPI | -| Agent orchestration | LangGraph v1.1 | -| Session state | PostgreSQL + langgraph-checkpoint-postgres | -| LLM | Claude Sonnet 4.6 (configurable: OpenAI, Google) | +| Agent orchestration | LangGraph 0.4+, langgraph-supervisor | +| Session state | PostgreSQL 16 + langgraph-checkpoint-postgres | +| LLM | Claude Sonnet 4.6 (configurable: OpenAI, Azure OpenAI, Google) | | Frontend | React 19, TypeScript, Vite | +| Testing | pytest (backend), vitest + happy-dom (frontend) | | Deployment | Docker Compose | ## Quick Start @@ -59,7 +60,11 @@ cd smart-support # Configure your LLM API key cp .env.example .env -# Edit .env: set ANTHROPIC_API_KEY (or OPENAI_API_KEY) +# Edit .env: set LLM_PROVIDER and the corresponding API key +# anthropic -> ANTHROPIC_API_KEY +# openai -> OPENAI_API_KEY +# azure_openai -> AZURE_OPENAI_API_KEY + AZURE_OPENAI_ENDPOINT + AZURE_OPENAI_DEPLOYMENT +# google -> GOOGLE_API_KEY # Start all services docker compose up -d @@ -68,6 +73,25 @@ docker compose up -d open http://localhost ``` +### Local Development + +```bash +# Start only PostgreSQL via Docker (exposed on port 5433) +docker compose up postgres -d + +# Backend (in one terminal) +cd backend +pip install -e ".[dev]" +uvicorn app.main:app --host 0.0.0.0 --port 8001 --reload + +# Frontend (in another terminal) +cd frontend +npm install +npm run dev # http://localhost:5173 (proxies /api and /ws to :8001) +``` + +See [Deployment Guide](docs/deployment.md) for production setup, HTTPS, and scaling. + ## Project Structure ``` @@ -77,15 +101,14 @@ smart-support/ │ │ ├── main.py # FastAPI + WebSocket entry point │ │ ├── graph.py # LangGraph Supervisor │ │ ├── ws_handler.py # WebSocket message dispatch + rate limiting -│ │ ├── conversation_tracker.py # Conversation lifecycle tracking +│ │ ├── safety.py # Confirmation rules + MCP error taxonomy │ │ ├── agents/ # Agent definitions and tools │ │ ├── registry.py # YAML agent registry loader -│ │ ├── openapi/ # OpenAPI parser and review API +│ │ ├── openapi/ # OpenAPI parser, classifier, and review API │ │ ├── replay/ # Conversation replay API -│ │ ├── analytics/ # Analytics queries and API -│ │ └── tools/ # Error handling and retry utilities +│ │ └── analytics/ # Analytics queries and API │ ├── agents.yaml # Agent registry configuration -│ ├── fixtures/ # Demo data and sample OpenAPI spec +│ ├── templates/ # Vertical industry templates │ └── tests/ # Unit, integration, and E2E tests ├── frontend/ │ ├── src/ @@ -99,29 +122,6 @@ smart-support/ └── .env.example # Environment variable template ``` -## Agent Configuration - -```yaml -# agents.yaml -agents: - - name: order_agent - description: "Handles order status, tracking, and cancellations." - permission: write - tools: - - get_order_status - - cancel_order - personality: - tone: friendly - greeting: "I can help with your order. What is the order number?" - escalation_message: "I'm escalating this to a human agent." - - - name: general_agent - description: "Answers general questions and FAQs." - permission: read - tools: - - search_faq -``` - ## API Endpoints | Method | Path | Description | @@ -137,42 +137,31 @@ agents: | PUT | `/api/openapi/jobs/{id}/classifications/{idx}` | Update a classification | | POST | `/api/openapi/jobs/{id}/approve` | Approve and generate tools | -## Safety and Confirmation Rules - -Destructive-action confirmation is explicit and auditable (see `backend/app/safety.py`): - -- **Read actions** execute immediately -- no confirmation required. -- **Write actions** require human-in-the-loop approval via an interrupt gate. -- **OpenAPI-imported endpoints** use the `needs_interrupt` classification flag. -- **Multi-intent handling** is sequential: if a write action is blocked by an interrupt, subsequent actions are paused until the interrupt is resolved or rejected. -- **MCP errors** are classified into `transient` (retryable, up to 3 attempts), `validation` (not retryable), `auth` (not retryable, escalate), and `unknown` (not retryable, log and escalate). - -## Security - -- **SSRF protection** -- OpenAPI import blocks private IPs and metadata service URLs -- **Input validation** -- messages validated for size (32 KB), content length (10 KB), thread ID format -- **Rate limiting** -- 10 messages per 10 seconds per session -- **Audit trail** -- every tool call logged with agent, params, result, timestamp -- **Permission isolation** -- each agent only accesses its configured tools -- **Interrupt TTL** -- unanswered approval prompts expire after 30 minutes - ## Running Tests ```bash +# Backend (516 tests, 94% coverage) cd backend pytest --cov=app --cov-report=term-missing + +# Frontend (23 tests, vitest + happy-dom) +cd frontend +npm test ``` -Coverage is enforced at 80%+. +Backend coverage is enforced at 80%+. ## Documentation -- [Architecture](docs/ARCHITECTURE.md) -- System design and component diagram -- [Development Plan](docs/DEVELOPMENT-PLAN.md) -- Phase breakdown and status -- [Agent Config Guide](docs/agent-config-guide.md) -- How to configure agents -- [OpenAPI Import Guide](docs/openapi-import-guide.md) -- Auto-discovery workflow -- [Deployment Guide](docs/deployment.md) -- Docker and production deployment -- [Demo Script](docs/demo-script.md) -- Step-by-step live demo walkthrough +| Document | Description | +|----------|-------------| +| [Architecture](docs/ARCHITECTURE.md) | System design, component diagram, data flow, ADRs | +| [Development Plan](docs/DEVELOPMENT-PLAN.md) | Phase breakdown, task checklists, and status | +| [Agent Config Guide](docs/agent-config-guide.md) | agents.yaml format, fields, templates, routing logic | +| [OpenAPI Import Guide](docs/openapi-import-guide.md) | Auto-discovery workflow, REST API, SSRF protection | +| [Deployment Guide](docs/deployment.md) | Docker, local dev, production, HTTPS, backups, scaling | +| [Demo Script](docs/demo-script.md) | Step-by-step live demo walkthrough (5 scenes) | +| [UX Design System](docs/ux_design_system.md) | Color palette, typography, component patterns, CSS tokens | ## License diff --git a/docker-compose.yml b/docker-compose.yml index f997c62..7aa5daf 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -5,7 +5,7 @@ services: POSTGRES_DB: smart_support POSTGRES_USER: smart_support POSTGRES_PASSWORD: ${POSTGRES_PASSWORD:-dev_password} - # ports: ["5432:5432"] # Uncomment for local dev DB access only + ports: ["5433:5432"] # Local dev: expose on 5433 to match backend/.env volumes: - pgdata:/var/lib/postgresql/data healthcheck: diff --git a/docs/ARCHITECTURE.md b/docs/ARCHITECTURE.md index 7d38498..d4f1dc3 100644 --- a/docs/ARCHITECTURE.md +++ b/docs/ARCHITECTURE.md @@ -63,7 +63,7 @@ Smart Support 通过 MCP 协议连接内部系统,将自动化率提升到 60%+ v +--------+--------------------+ | LangGraph Supervisor | (Agent 编排 + 意图路由) -| langgraph-supervisor v1.1 | +| langgraph-supervisor 0.0.12+| +--------+--------------------+ | +----+----+----+----+ diff --git a/docs/agent-config-guide.md b/docs/agent-config-guide.md index 95358af..ce883ae 100644 --- a/docs/agent-config-guide.md +++ b/docs/agent-config-guide.md @@ -9,33 +9,38 @@ specialist with a specific role, permission level, and set of tools it can call. ```yaml agents: - - name: order_agent - description: "Handles order status, tracking, and cancellations." - permission: write - tools: - - get_order_status - - cancel_order - personality: - tone: friendly - greeting: "I can help with your order. What is your order number?" - escalation_message: "I'm escalating this to a human agent now." - - - name: refund_agent - description: "Processes refund requests." - permission: write - tools: - - process_refund - - check_refund_eligibility - personality: - tone: empathetic - greeting: "I'm the refund specialist. How can I help?" - escalation_message: "I need to escalate this refund request." - - - name: general_agent - description: "Answers general questions and FAQs." + - name: order_lookup + description: "Looks up order status and tracking information." + permission: read + tools: + - get_order_status + - get_tracking_info + personality: + tone: "friendly and informative" + greeting: "I can help you check your order status!" + escalation_message: "Let me connect you with our support team." + + - name: order_actions + description: "Performs order modifications like cancellations." + permission: write + tools: + - cancel_order + personality: + tone: "careful and reassuring" + greeting: "I can help you with order changes." + escalation_message: "I'll connect you with a specialist." + + - name: discount + description: "Applies discounts and generates coupon codes." + permission: write + tools: + - apply_discount + - generate_coupon + + - name: fallback + description: "Handles general questions and unclear requests." permission: read tools: - - search_faq - fallback_respond ``` @@ -52,31 +57,38 @@ user messages to the right agent. Be specific. Controls the interrupt threshold: - `read` -- no interrupt required. Agent can act immediately. - `write` -- requires human approval via interrupt before executing tools. -- `admin` -- requires human approval and is logged for audit. ### `tools` (required) -List of tool names this agent can use. Tools are registered in the agent factory. +List of tool names this agent can use. Tools are registered in `backend/app/agents/`. Each tool name must match a registered LangChain tool. +Available built-in tools: +- `get_order_status` -- look up order details +- `get_tracking_info` -- get shipping/tracking info +- `cancel_order` -- cancel an order (write) +- `apply_discount` -- apply a discount code (write) +- `generate_coupon` -- generate a new coupon (write) +- `fallback_respond` -- generic fallback response + ### `personality` (optional) Customizes agent behavior: -- `tone` -- `friendly`, `formal`, `empathetic`, `technical` -- `greeting` -- Opening message injected at session start. -- `escalation_message` -- Message sent when the agent escalates. +- `tone` -- free-text description of the agent's communication style +- `greeting` -- opening message injected at session start +- `escalation_message` -- message sent when the agent escalates ## Built-in Templates Use `TEMPLATE_NAME` environment variable to load a pre-built agent configuration: -| Template | Description | -|----------|-------------| -| `ecommerce` | Orders, refunds, shipping, product questions | -| `saas` | Account management, billing, technical support | -| `generic` | General-purpose FAQ and escalation | +| Template | Filename | Description | +|----------|----------|-------------| +| `e-commerce` | `templates/e-commerce.yaml` | Orders, shipping, discounts | +| `saas` | `templates/saas.yaml` | Account management, billing, support | +| `fintech` | `templates/fintech.yaml` | Financial services support | Example: ```bash -TEMPLATE_NAME=ecommerce uvicorn app.main:app +TEMPLATE_NAME=e-commerce uvicorn app.main:app ``` ## Adding New Agents @@ -98,7 +110,7 @@ matches the agent's description. ## Escalation -Any agent can trigger escalation by calling the `escalate` tool. This: +Any agent can trigger escalation. This: 1. Sends a webhook notification (if `WEBHOOK_URL` is configured). 2. Marks the conversation with `resolution_type = escalated`. 3. Sends the agent's `escalation_message` to the user. diff --git a/docs/demo-script.md b/docs/demo-script.md index d5a086e..c9ada77 100644 --- a/docs/demo-script.md +++ b/docs/demo-script.md @@ -46,7 +46,7 @@ Navigate to http://localhost in your browser. 1. Open the Chat tab (default). 2. Send: **"What is the status of order 12345?"** - - Observe the `tool_call` indicator appear in the sidebar (order_agent calling `get_order_status`). + - Observe the `tool_call` indicator appear in the sidebar (`order_lookup` calling `get_order_status`). - The agent responds with order status. 3. Send: **"Can you cancel that order?"** - The system detects a write operation and shows an **Interrupt Prompt**. @@ -61,15 +61,15 @@ Key points to highlight: ### Scene 2: Multi-Agent Routing (2 minutes) 1. Start a new browser tab (new session) or clear session storage. -2. Send: **"I need to track my order AND request a refund for a previous order"** - - The supervisor detects two intents: `order_agent` and `refund_agent`. +2. Send: **"I need to check order 12345 AND cancel order 67890"** + - The supervisor detects two intents: `order_lookup` (read) and `order_actions` (write). - Both agents run in sequence. - - Two interrupt prompts may appear if both operations are write-level. + - The cancellation triggers an interrupt prompt for human approval. Key points to highlight: - Intent classification detecting multiple actions - Automatic routing to appropriate specialist agents -- Sequential execution with confirmation gates +- Sequential execution with confirmation gates for write operations ### Scene 3: Conversation Replay (2 minutes) diff --git a/docs/openapi-import-guide.md b/docs/openapi-import-guide.md index 8978b24..7f85cef 100644 --- a/docs/openapi-import-guide.md +++ b/docs/openapi-import-guide.md @@ -10,7 +10,8 @@ Import a URL, review the AI-classified endpoints, approve, and your agents are l 1. **Import** -- Provide a URL to an OpenAPI 3.0 spec (JSON or YAML). 2. **Parse** -- The system downloads and parses the spec. 3. **Classify** -- An LLM classifies each endpoint's: - - `access_type`: `read`, `write`, or `admin` + - `access_type`: `read` or `write` + - `needs_interrupt`: whether human approval is required - `agent_group`: which specialist agent should handle this endpoint 4. **Review** -- You inspect and edit the classifications in the UI. 5. **Approve** -- Approved endpoints are registered as tools on the appropriate agents. @@ -19,12 +20,12 @@ Import a URL, review the AI-classified endpoints, approve, and your agents are l 1. Navigate to the **API Review** tab. 2. Paste your OpenAPI spec URL into the import form. -3. Click **Import**. +3. Click **Scan Tools**. 4. Wait for the job to complete (status: `pending` -> `processing` -> `done`). -5. Review the endpoint table: - - Edit `access_type` if the AI misclassified sensitivity. - - Edit `agent_group` to reassign an endpoint to a different agent. -6. Click **Approve & Save** when satisfied. +5. Review the endpoint cards grouped by agent: + - Edit `access_type` (Read Only / Write) if the AI misclassified sensitivity. + - Edit the agent assignment to reassign an endpoint to a different agent. +6. Click **Save Configuration** when satisfied. ## Using the REST API @@ -39,11 +40,15 @@ Content-Type: application/json } ``` -Response: +Response (202): ```json { - "success": true, - "data": { "job_id": "abc123", "status": "pending" } + "job_id": "abc123", + "status": "pending", + "spec_url": "https://api.example.com/openapi.yaml", + "total_endpoints": 0, + "classified_count": 0, + "error_message": null } ``` @@ -53,47 +58,52 @@ Response: GET /api/openapi/jobs/{job_id} ``` -### Get job results +### Get classifications ```http -GET /api/openapi/jobs/{job_id}/result +GET /api/openapi/jobs/{job_id}/classifications +``` + +Response: array of classification objects with `index`, `access_type`, +`needs_interrupt`, `agent_group`, `confidence`, `customer_params`, and `endpoint`. + +### Update a classification + +```http +PUT /api/openapi/jobs/{job_id}/classifications/{index} +Content-Type: application/json + +{ + "access_type": "write", + "needs_interrupt": true, + "agent_group": "order_actions" +} ``` ### Approve job ```http POST /api/openapi/jobs/{job_id}/approve -Content-Type: application/json - -{ - "endpoints": [ - { - "path": "/orders/{order_id}", - "method": "get", - "access_type": "read", - "agent_group": "order_agent" - } - ] -} ``` +No request body. Changes the job status to `approved`. + ## Access Type Classification | Access Type | Description | Interrupt Required | |-------------|-------------|-------------------| | `read` | GET operations, no side effects | No | -| `write` | POST/PUT/PATCH that modify data | Yes | -| `admin` | DELETE, bulk operations, sensitive writes | Yes | +| `write` | POST/PUT/PATCH/DELETE that modify data | Yes (by default) | + +The `needs_interrupt` flag can be overridden per-endpoint during review. ## SSRF Protection -All import requests are validated against an allowlist: +All import requests are validated: - Private IP ranges are blocked (10.x, 172.16.x, 192.168.x, 127.x) -- Localhost and metadata service URLs are blocked +- Localhost and cloud metadata service URLs are blocked - Only `http://` and `https://` schemes are permitted -To allow internal URLs (e.g., in development), set `SSRF_ALLOWLIST_HOSTS` in your environment. - ## Supported Spec Formats - OpenAPI 3.0.x (JSON or YAML)