diff --git a/.cursor/plans/ai_chat_write_agent_9b3e5be2.plan.md b/.cursor/plans/ai_chat_write_agent_9b3e5be2.plan.md new file mode 100644 index 0000000..5df1540 --- /dev/null +++ b/.cursor/plans/ai_chat_write_agent_9b3e5be2.plan.md @@ -0,0 +1,269 @@ +--- +name: AI Chat Write Agent +overview: Implement an AI-powered chat write agent that integrates with the Write page (replacing textarea when active) and optionally appears in the RightSidebar on posts/pages. Uses Anthropic Claude API with anonymous sessions, per-page chat history stored in Convex, and optional page content loading. +todos: + - id: schema + content: Add aiChats table to convex/schema.ts with indexes + status: completed + - id: backend-mutations + content: Create convex/aiChats.ts with queries and mutations + status: completed + dependencies: + - schema + - id: backend-action + content: Create convex/aiChatActions.ts with Claude API integration + status: completed + dependencies: + - backend-mutations + - id: siteconfig + content: Add AIChatConfig interface and defaults to siteConfig.ts + status: completed + - id: chat-component + content: Create AIChatView.tsx component with full chat UI + status: completed + dependencies: + - backend-mutations + - backend-action + - id: chat-styles + content: Add AI chat CSS styles to global.css (theme-aware) + status: completed + dependencies: + - chat-component + - id: right-sidebar + content: Update RightSidebar.tsx to conditionally render AIChatView + status: completed + dependencies: + - chat-component + - siteconfig + - id: write-page + content: Update Write.tsx with AI chat mode toggle + status: completed + dependencies: + - chat-component + - siteconfig + - id: post-page + content: Update Post.tsx to pass content context to RightSidebar + status: completed + dependencies: + - right-sidebar + - id: frontmatter + content: Add aiChat field to sync-posts.ts and Write.tsx field definitions + status: completed + - id: dependencies + content: Add @anthropic-ai/sdk to package.json + status: completed +--- + +# AI Chat Write Agent Implementation + +## Architecture Overview + +```mermaid +flowchart TB + subgraph frontend [Frontend Components] + AIChatView[AIChatView Component] + WritePage[Write.tsx] + RightSidebar[RightSidebar.tsx] + PostPage[Post.tsx] + end + + subgraph convex [Convex Backend] + aiChats[aiChats.ts - Queries/Mutations] + aiChatActions[aiChatActions.ts - Claude API Action] + schema[schema.ts - aiChats table] + end + + subgraph external [External Services] + Claude[Anthropic Claude API] + end + + WritePage -->|mode toggle| AIChatView + RightSidebar -->|when aiChat enabled| AIChatView + PostPage -->|passes content context| RightSidebar + AIChatView -->|mutations| aiChats + AIChatView -->|action| aiChatActions + aiChatActions -->|API call| Claude + aiChats -->|read/write| schema +``` + + + +## Key Design Decisions + +- **Anonymous Sessions**: Uses localStorage `sessionId` (UUID) until auth is added +- **Chat Scope**: Per-page using slug as context identifier (e.g., "write-page", "about", "my-post-slug") +- **Page Context**: Optional button to load current page's markdown into chat context +- **Mode Toggle**: Write page switches between textarea and chat interface +- **Configuration**: Separate siteConfig toggles for Write page and RightSidebar + +--- + +## 1. Database Schema Updates + +Update [`convex/schema.ts`](convex/schema.ts) to add the `aiChats` table: + +```typescript +aiChats: defineTable({ + sessionId: v.string(), + contextId: v.string(), // slug or "write-page" + messages: v.array( + v.object({ + role: v.union(v.literal("user"), v.literal("assistant")), + content: v.string(), + timestamp: v.number(), + }), + ), + pageContext: v.optional(v.string()), // loaded page content + lastMessageAt: v.optional(v.number()), +}) + .index("by_session_and_context", ["sessionId", "contextId"]) + .index("by_session", ["sessionId"]) +``` + +--- + +## 2. Convex Backend + +### Create [`convex/aiChats.ts`](convex/aiChats.ts) + +Queries and mutations for chat management: + +- `getAIChatByContext` - Fetch chat for sessionId + contextId +- `getOrCreateAIChat` - Create chat if none exists +- `addUserMessage` - Add user message +- `addAssistantMessage` - Internal mutation for AI response +- `clearChat` - Clear messages +- `setPageContext` - Store loaded page content + +### Create [`convex/aiChatActions.ts`](convex/aiChatActions.ts) + +Node.js action for Claude API: + +- `generateResponse` - Calls Claude API with conversation history +- Uses `ANTHROPIC_API_KEY` environment variable +- Loads system prompt from `CLAUDE_SYSTEM_PROMPT` or split `CLAUDE_PROMPT_*` variables +- Model: `claude-sonnet-4-20250514` with 2048 max tokens +- Includes last 20 messages as context + +--- + +## 3. Frontend Components + +### Create [`src/components/AIChatView.tsx`](src/components/AIChatView.tsx) + +Main chat component with: + +- Message list with markdown rendering (react-markdown) +- Auto-expanding textarea input +- Send button and keyboard shortcuts (Enter to send, Shift+Enter newline) +- Loading state with stop generation button +- Clear chat command ("clear") +- Copy message button on AI responses +- "Load Page Content" button (when page content available) +- Theme-aware styling matching existing UI + +### Update [`src/components/RightSidebar.tsx`](src/components/RightSidebar.tsx) + +Transform from empty placeholder to conditional chat container: + +- Accept `aiChatEnabled`, `pageContent`, and `slug` props +- Render `AIChatView` when enabled +- Pass page context for "Load Content" feature + +--- + +## 4. Page Updates + +### Update [`src/pages/Write.tsx`](src/pages/Write.tsx) + +Add AI chat mode toggle: + +- New state: `isAIChatMode` (boolean) +- Add "AI Chat" button in Actions section (using `ChatCircle` from Phosphor Icons) +- When active: replace `