feat: add AI Agent chat integration with Anthropic Claude API

Add AI writing assistant (Agent) powered by Anthropic Claude API. Agent can be enabled on Write page (replaces textarea) and optionally in RightSidebar on posts/pages via frontmatter.

Features:
- AIChatView component with per-page chat history
- Page content context support for AI responses
- Markdown rendering for AI responses
- User-friendly error handling for missing API keys
- System prompt configurable via Convex environment variables
- Anonymous session authentication using localStorage

Environment variables required:
- ANTHROPIC_API_KEY (required)
- CLAUDE_PROMPT_STYLE, CLAUDE_PROMPT_COMMUNITY, CLAUDE_PROMPT_RULES (optional split prompts)
- CLAUDE_SYSTEM_PROMPT (optional single prompt fallback)

Configuration:
- siteConfig.aiChat.enabledOnWritePage: Enable Agent toggle on /write page
- siteConfig.aiChat.enabledOnContent: Allow Agent on posts/pages via frontmatter
- Frontmatter aiChat: true (requires rightSidebar: true)

Updated files:
- src/components/AIChatView.tsx: AI chat interface component
- src/components/RightSidebar.tsx: Conditional Agent rendering
- src/pages/Write.tsx: Agent mode toggle (title changes to Agent)
- convex/aiChats.ts: Chat history queries and mutations
- convex/aiChatActions.ts: Claude API integration with error handling
- convex/schema.ts: aiChats table with indexes
- src/config/siteConfig.ts: AIChatConfig interface
- Documentation updated across all files

Documentation:
- files.md: Updated component descriptions
- changelog.md: Added v1.33.0 entry
- TASK.md: Marked AI chat tasks as completed
- README.md: Added AI Agent Chat section
- content/pages/docs.md: Added AI Agent chat documentation
- content/blog/setup-guide.md: Added AI Agent chat setup instructions
- public/raw/changelog.md: Added v1.33.0 entry
This commit is contained in:
Wayne Sutton
2025-12-26 12:31:33 -08:00
parent 50890e9153
commit bfe88d0217
34 changed files with 3867 additions and 245 deletions

View File

@@ -38,6 +38,7 @@ interface PostFrontmatter {
authorImage?: string; // Author avatar image URL (round)
layout?: string; // Layout type: "sidebar" for docs-style layout
rightSidebar?: boolean; // Enable right sidebar with CopyPageDropdown (default: true when siteConfig.rightSidebar.enabled)
aiChat?: boolean; // Enable AI chat in right sidebar (requires rightSidebar: true)
}
interface ParsedPost {
@@ -59,6 +60,7 @@ interface ParsedPost {
rightSidebar?: boolean; // Enable right sidebar with CopyPageDropdown (default: true when siteConfig.rightSidebar.enabled)
showFooter?: boolean; // Show footer on this post (overrides siteConfig default)
footer?: string; // Footer markdown content (overrides siteConfig defaultContent)
aiChat?: boolean; // Enable AI chat in right sidebar (requires rightSidebar: true)
}
// Page frontmatter (for static pages like About, Projects, Contact)
@@ -77,6 +79,7 @@ interface PageFrontmatter {
layout?: string; // Layout type: "sidebar" for docs-style layout
rightSidebar?: boolean; // Enable right sidebar with CopyPageDropdown (default: true when siteConfig.rightSidebar.enabled)
showFooter?: boolean; // Show footer on this page (overrides siteConfig default)
aiChat?: boolean; // Enable AI chat in right sidebar (requires rightSidebar: true)
}
interface ParsedPage {
@@ -95,6 +98,7 @@ interface ParsedPage {
layout?: string; // Layout type: "sidebar" for docs-style layout
rightSidebar?: boolean; // Enable right sidebar with CopyPageDropdown (default: true when siteConfig.rightSidebar.enabled)
showFooter?: boolean; // Show footer on this page (overrides siteConfig default)
aiChat?: boolean; // Enable AI chat in right sidebar (requires rightSidebar: true)
}
// Calculate reading time based on word count
@@ -138,6 +142,7 @@ function parseMarkdownFile(filePath: string): ParsedPost | null {
rightSidebar: frontmatter.rightSidebar, // Enable right sidebar with CopyPageDropdown
showFooter: frontmatter.showFooter, // Show footer on this post
footer: frontmatter.footer, // Footer markdown content
aiChat: frontmatter.aiChat, // Enable AI chat in right sidebar
};
} catch (error) {
console.error(`Error parsing ${filePath}:`, error);
@@ -191,6 +196,7 @@ function parsePageFile(filePath: string): ParsedPage | null {
layout: frontmatter.layout, // Layout type: "sidebar" for docs-style layout
rightSidebar: frontmatter.rightSidebar, // Enable right sidebar with CopyPageDropdown
showFooter: frontmatter.showFooter, // Show footer on this page
aiChat: frontmatter.aiChat, // Enable AI chat in right sidebar
};
} catch (error) {
console.error(`Error parsing page ${filePath}:`, error);