feat: overhaul chat architecture with persistent JdbcChatMemory, reactive UI components, and improved conversation management
This commit is contained in:
190
context.md
190
context.md
@@ -4,150 +4,96 @@ trigger: always_on
|
||||
|
||||
# Project Context: Loyalty Agent Service
|
||||
|
||||
This repository is a local development workspace for a loyalty AI assistant. It has a React chat UI at the repository root and two Spring Boot backend modules managed by a parent Maven project.
|
||||
An AI Assistant system designed to manage and operate Loyalty business domain tasks (Campaigns, Rules, Point Pools, Tiers, and Members) for enterprise applications. The repository is structured as a monorepo containing 3 distinct applications communicating via WebSocket STOMP, HTTP REST APIs, and MCP SSE.
|
||||
|
||||
## Architecture
|
||||
---
|
||||
|
||||
### Frontend: root directory
|
||||
## 1. Architecture Overview
|
||||
|
||||
- Stack: React 19, Vite, TypeScript, Tailwind CSS, shadcn-style UI primitives, Zustand, `@stomp/stompjs`, `react-markdown`, `remark-gfm`.
|
||||
- Entry point: `src/main.tsx` renders `src/App.tsx`, which renders `ChatLayout`.
|
||||
- Dev port: `9333` from `vite.config.ts`.
|
||||
- Main UI flow:
|
||||
- `src/store/useChatStore.ts` owns chat state and STOMP connection.
|
||||
- WebSocket URL is currently hard-coded as `ws://localhost:9332/ws`.
|
||||
- User messages are published to `/app/chat`.
|
||||
- Agent events are received from `/user/queue/chat-events`.
|
||||
- `CampaignList` fetches campaign data from `http://localhost:9332/api/v1/agent/campaigns` and campaign rules from `http://localhost:9332/api/v1/agent/campaigns/{campaignId}/rules`.
|
||||
```
|
||||
┌──────────────────────────────────┐
|
||||
│ Frontend (React 19 + Vite) │
|
||||
│ Port: 9333 (Dev Server) │
|
||||
└─────────────────┬────────────────┘
|
||||
│
|
||||
WebSocket │ REST Proxy
|
||||
(STOMP /ws) │ (/api/v1/agent/...)
|
||||
▼
|
||||
┌──────────────────────────────────┐
|
||||
│ `loyalty-agent` (Spring Boot) │
|
||||
│ Port: 9332 | BFF & AI Service │
|
||||
└─────────┬───────────────┬────────┘
|
||||
│ │
|
||||
Ollama │ │ MCP SSE
|
||||
(qwen3.5:4b) │ │ (http://localhost:9331/sse)
|
||||
▼ ▼
|
||||
┌──────────────────┐ ┌──────────────────────────────────┐
|
||||
│ Ollama LLM Server│ │ `loyalty-mcp-server` │
|
||||
│ 192.168.99.10 │ │ Port: 9331 | MCP Tool Server │
|
||||
└──────────────────┘ └────────────────┬────────────────┘
|
||||
│ OAuth2 Client Credentials
|
||||
▼
|
||||
┌──────────────────────────────────┐
|
||||
│ Loyalty Core API (Spring Boot) │
|
||||
│ 192.168.99.242:8081 │
|
||||
└──────────────────────────────────┘
|
||||
```
|
||||
|
||||
### `loyalty-agent`
|
||||
---
|
||||
|
||||
- Spring Boot application: `dev.sonpx.loyalty.agent.LoyaltyAgentApplication`.
|
||||
- Runtime port: `9332`.
|
||||
- Role: BFF and AI orchestration layer for the frontend.
|
||||
- Key files:
|
||||
- `controller/AgentController.java`: STOMP chat endpoint and REST campaign proxy endpoints.
|
||||
- `service/LoyaltyAgentService.java`: builds a Spring AI `ChatClient`, streams LLM output, wraps tool calls, and emits tool status events.
|
||||
- `config/WebSocketConfig.java`: STOMP endpoint `/ws`, application prefix `/app`, user destination prefix `/user`, broker prefixes `/topic` and `/queue`.
|
||||
- `config/AgentConfig.java`: OAuth2-enabled `RestClient` for the loyalty core API.
|
||||
- `controller/ConversationController.java`: simple in-memory conversation/message REST endpoints.
|
||||
- AI configuration:
|
||||
- Uses Ollama at `http://192.168.99.10:11434`.
|
||||
- Default model in `application.yml`: `qwen3.5:4b`.
|
||||
- MCP client connects to `${MCP_SERVER_URL:http://localhost:9331/sse}`.
|
||||
- Agent event types sent to the UI: `TOKEN`, `TOOL_STATUS`, `DONE`, `ERROR`.
|
||||
## 2. Applications & Dedicated Context Files
|
||||
|
||||
### `loyalty-mcp-server`
|
||||
Each application has a dedicated context file containing detailed architecture documentation, message contracts, and development guidelines:
|
||||
|
||||
- Spring Boot application: `dev.sonpx.loyalty.mcp.McpServerApplication`.
|
||||
- Runtime port: `9331`.
|
||||
- Role: MCP tool server for loyalty operations. The agent calls this service through Spring AI MCP SSE.
|
||||
- MCP endpoints from `application.yml`:
|
||||
- SSE endpoint: `/sse`
|
||||
- Message endpoint: `/message`
|
||||
- Key files:
|
||||
- `config/McpServerConfig.java`: registers MCP tool objects.
|
||||
- `tool/LoyaltyAgentTools.java`: member tiers, point pools, campaign creation, static attributes.
|
||||
- `tool/reward/CampaignTools.java`: campaign listing and campaign draft lifecycle.
|
||||
- `tool/reward/CampaignRuleTools.java`: campaign rule listing, creation, editing, and draft rule attachment.
|
||||
- `tool/pool/PointPoolTools.java`: pool and SOP draft tools.
|
||||
- `draft/DraftSessionManager.java`: in-memory draft sessions keyed by `conversationId`, with a 1-hour TTL.
|
||||
- `draft/DependencyValidator.java`: validates draft dependencies before tools mutate or submit drafts.
|
||||
- API clients call the loyalty core service with OAuth2 client credentials.
|
||||
1. **`loyalty-agent` (BFF & AI Orchestrator)**:
|
||||
- **Port**: `9332`
|
||||
- **Role**: Manages Ollama LLM interactions, STOMP WebSocket streaming to the UI, MCP Client execution, and conversation history.
|
||||
- **Detailed Specs**: [context-agent.md](./context-agent.md) (`@context-agent.md`)
|
||||
|
||||
## External Services And Environment
|
||||
2. **`loyalty-mcp-server` (MCP Tool Server)**:
|
||||
- **Port**: `9331`
|
||||
- **Role**: Exposes `@McpTool` endpoints for loyalty business domain operations (Campaigns, Rules, Pools), interacting with Loyalty Core API via OAuth2.
|
||||
- **Detailed Specs**: [context-mcp-server.md](./context-mcp-server.md) (`@context-mcp-server.md`)
|
||||
|
||||
Create `.env` from `.env.example` for local development.
|
||||
3. **Frontend (React Chat UI)**:
|
||||
- **Port**: `9333`
|
||||
- **Role**: User interface for the AI Chatbot, handling STOMP stream events, rendering Markdown, displaying animated tool status badges, and rendering side panels.
|
||||
- **Detailed Specs**: [context-fe.md](./context-fe.md) (`@context-fe.md`)
|
||||
|
||||
Important variables:
|
||||
---
|
||||
|
||||
- `KEYCLOAK_CLIENT_SECRET`
|
||||
- `KEYCLOAK_TOKEN_URI`
|
||||
- `LOYALTY_CORE_BASE_URL`
|
||||
- `MCP_SERVER_URL`
|
||||
- `VITE_AGENT_HTTP_URL`
|
||||
- `VITE_AGENT_WS_URL`
|
||||
|
||||
Current defaults:
|
||||
|
||||
- Keycloak token URI: `http://192.168.99.235/auth/realms/ols-cn-sit/protocol/openid-connect/token`
|
||||
- Loyalty core base URL: `http://192.168.99.242:8081`
|
||||
- MCP server URL: `http://localhost:9331`
|
||||
- Agent HTTP URL: `http://localhost:9332`
|
||||
- Agent WS URL: `ws://localhost:9332`
|
||||
|
||||
Note: some frontend code still uses hard-coded localhost URLs instead of the `VITE_*` variables.
|
||||
|
||||
## Local Startup
|
||||
|
||||
Use the root script for the full local stack:
|
||||
## 3. Quick Startup & Commands
|
||||
|
||||
### Launch Entire Stack (Root Script)
|
||||
```bash
|
||||
./start-all.sh
|
||||
```
|
||||
*Automatically starts MCP Server (`9331`), Agent Service (`9332`), and Frontend (`9333`).*
|
||||
|
||||
What the script does:
|
||||
|
||||
1. Loads `.env` if present.
|
||||
2. Kills processes on ports `9331`, `9332`, and `9333`.
|
||||
3. Starts `loyalty-mcp-server` and waits for port `9331`.
|
||||
4. Starts a `nodemon` compile watcher for the MCP server.
|
||||
5. Starts `loyalty-agent` and waits for port `9332`.
|
||||
6. Starts a `nodemon` compile watcher for the agent.
|
||||
7. Starts the frontend with `pnpm dev` on port `9333`.
|
||||
8. Writes logs to `log/`.
|
||||
|
||||
Manual startup:
|
||||
|
||||
### Manual Application Startup
|
||||
```bash
|
||||
# Terminal 1: MCP Server
|
||||
./mvnw spring-boot:run -pl loyalty-mcp-server
|
||||
|
||||
# Terminal 2: Agent Service
|
||||
./mvnw spring-boot:run -pl loyalty-agent
|
||||
|
||||
# Terminal 3: Frontend
|
||||
pnpm dev
|
||||
```
|
||||
|
||||
The script currently invokes `-Pgen`, but the checked-in POM files do not define a `gen` Maven profile. Do not assume OpenAPI generation is wired unless you verify or add that profile.
|
||||
### Build & Test Commands
|
||||
- **Frontend**: `pnpm install` | `pnpm lint` | `pnpm build`
|
||||
- **Backend (Spring Boot)**: `./mvnw test` (Run all) | `./mvnw test -pl loyalty-agent` | `./mvnw test -pl loyalty-mcp-server`
|
||||
|
||||
## Build, Lint, And Tests
|
||||
---
|
||||
|
||||
Frontend:
|
||||
## 4. Ports & Environment Variables Reference
|
||||
|
||||
```bash
|
||||
pnpm install
|
||||
pnpm lint
|
||||
pnpm build
|
||||
```
|
||||
|
||||
Backend:
|
||||
|
||||
```bash
|
||||
./mvnw test
|
||||
./mvnw test -pl loyalty-agent
|
||||
./mvnw test -pl loyalty-mcp-server
|
||||
```
|
||||
|
||||
Relevant tests:
|
||||
|
||||
- `loyalty-agent/src/test/java/dev/sonpx/loyalty/agent/controller/AgentControllerTest.java`
|
||||
- `loyalty-agent/src/test/java/dev/sonpx/loyalty/agent/domain/AgentEventTest.java`
|
||||
- `loyalty-mcp-server/src/test/java/dev/sonpx/loyalty/mcp/tool/McpOrchestratorTest.java`
|
||||
- `loyalty-mcp-server/src/test/java/dev/sonpx/loyalty/mcp/tool/reward/CampaignRuleMapperTest.java`
|
||||
- `loyalty-mcp-server/src/test/java/dev/sonpx/loyalty/mcp/tool/LoyaltyAgentToolsRealApiTest.java`
|
||||
|
||||
`LoyaltyAgentToolsRealApiTest` may depend on real external API availability and credentials.
|
||||
|
||||
## Development Guidelines For Agents
|
||||
|
||||
- Keep the boundary clear:
|
||||
- `loyalty-agent` owns frontend-facing chat orchestration and REST proxy endpoints.
|
||||
- `loyalty-mcp-server` owns tool implementations and loyalty core API access.
|
||||
- The frontend owns STOMP state, message rendering, chat layout, and campaign context panels.
|
||||
- Preserve the STOMP contract unless intentionally changing both sides:
|
||||
- Client publishes to `/app/chat`.
|
||||
- Server handles `@MessageMapping("/chat")`.
|
||||
- Server sends events to `/user/queue/chat-events`.
|
||||
- Preserve `conversationId` propagation. MCP draft tools depend on it to keep draft campaign/pool/rule state in `DraftSessionManager`.
|
||||
- Tool responses may contain `presentation.content`; the agent system prompt requires displaying that content exactly.
|
||||
- Reuse existing UI primitives in `src/components/ui` and existing Tailwind conventions.
|
||||
- Do not introduce persistent storage assumptions. Conversation repositories and draft sessions are currently in memory.
|
||||
- Do not hard-code new service URLs when a matching environment variable already exists.
|
||||
- Be careful with ports: MCP is `9331`, agent is `9332`, frontend is `9333`.
|
||||
| Component | Port | Default Endpoint | Key Environment Variables |
|
||||
| :--- | :--- | :--- | :--- |
|
||||
| **Frontend UI** | `9333` | `http://localhost:9333` | `VITE_AGENT_HTTP_URL`, `VITE_AGENT_WS_URL` |
|
||||
| **Loyalty Agent** | `9332` | `http://localhost:9332`, `ws://localhost:9332/ws` | `MCP_SERVER_URL`, `LOYALTY_CORE_BASE_URL` |
|
||||
| **Loyalty MCP Server** | `9331` | `http://localhost:9331/sse` | `KEYCLOAK_TOKEN_URI`, `KEYCLOAK_CLIENT_SECRET` |
|
||||
| **Ollama LLM** | `11434` | `http://192.168.99.10:11434` | Defined in `loyalty-agent/application.yml` |
|
||||
| **Loyalty Core API** | `8081` | `http://192.168.99.242:8081` | `LOYALTY_CORE_BASE_URL` |
|
||||
|
||||
Reference in New Issue
Block a user