From 635bc3bde49686ce8e72be3c52113efee3d4898e Mon Sep 17 00:00:00 2001 From: Bill Chirico Date: Tue, 3 Feb 2026 20:37:37 -0500 Subject: [PATCH 1/8] auto-claude: subtask-1-1 - Add config option for history mode (user vs channel) Co-Authored-By: Claude Sonnet 4.5 --- config.json | 1 + 1 file changed, 1 insertion(+) diff --git a/config.json b/config.json index 8f7d9c77..146ffd22 100644 --- a/config.json +++ b/config.json @@ -3,6 +3,7 @@ "enabled": true, "model": "claude-sonnet-4-20250514", "maxTokens": 1024, + "historyMode": "user", "systemPrompt": "You are Volvox Bot, the friendly AI assistant for the Volvox developer community Discord server.\n\nYou're witty, snarky (but warm), and deeply knowledgeable about programming, software development, and tech.\n\nKey traits:\n- Helpful but not boring\n- Can roast people lightly when appropriate\n- Enthusiastic about cool tech and projects\n- Supportive of beginners learning to code\n- Concise - this is Discord, not an essay\n\n⚠️ CRITICAL RULES:\n- NEVER type @.everyone or @.here (remove the dots) - these ping hundreds of people\n- NEVER use mass mention pings under any circumstances\n- If you need to address the group, say \"everyone\" or \"folks\" without the @ symbol\n\nKeep responses under 2000 chars. Use Discord markdown when helpful.", "channels": [] }, From d5949e6e1f754f0fe51112ce6e9213bad98059d3 Mon Sep 17 00:00:00 2001 From: Bill Chirico Date: Tue, 3 Feb 2026 20:38:50 -0500 Subject: [PATCH 2/8] auto-claude: subtask-1-2 - Refactor history storage to use userId instead of channelId --- src/index.js | 34 +++++++++++++++++----------------- 1 file changed, 17 insertions(+), 17 deletions(-) diff --git a/src/index.js b/src/index.js index 754e73db..019155c8 100644 --- a/src/index.js +++ b/src/index.js @@ -46,7 +46,7 @@ const client = new Client({ ], }); -// Conversation history per channel (simple in-memory store) +// Conversation history per user (simple in-memory store) const conversationHistory = new Map(); const MAX_HISTORY = 20; @@ -71,22 +71,22 @@ function isSpam(content) { } /** - * Get or create conversation history for a channel + * Get or create conversation history for a user */ -function getHistory(channelId) { - if (!conversationHistory.has(channelId)) { - conversationHistory.set(channelId, []); +function getHistory(userId) { + if (!conversationHistory.has(userId)) { + conversationHistory.set(userId, []); } - return conversationHistory.get(channelId); + return conversationHistory.get(userId); } /** * Add message to history */ -function addToHistory(channelId, role, content) { - const history = getHistory(channelId); +function addToHistory(userId, role, content) { + const history = getHistory(userId); history.push({ role, content }); - + // Trim old messages while (history.length > MAX_HISTORY) { history.shift(); @@ -96,8 +96,8 @@ function addToHistory(channelId, role, content) { /** * Generate AI response using OpenClaw's chat completions endpoint */ -async function generateResponse(channelId, userMessage, username) { - const history = getHistory(channelId); +async function generateResponse(userId, userMessage, username) { + const history = getHistory(userId); const systemPrompt = config.ai?.systemPrompt || `You are Volvox Bot, a helpful and friendly Discord bot for the Volvox developer community. You're witty, knowledgeable about programming and tech, and always eager to help. @@ -131,11 +131,11 @@ You can use Discord markdown formatting.`; const data = await response.json(); const reply = data.choices?.[0]?.message?.content || "I got nothing. Try again?"; - + // Update history - addToHistory(channelId, 'user', `${username}: ${userMessage}`); - addToHistory(channelId, 'assistant', reply); - + addToHistory(userId, 'user', `${username}: ${userMessage}`); + addToHistory(userId, 'assistant', reply); + return reply; } catch (err) { console.error('OpenClaw API error:', err.message); @@ -242,9 +242,9 @@ client.on('messageCreate', async (message) => { } await message.channel.sendTyping(); - + const response = await generateResponse( - message.channel.id, + message.author.id, cleanContent, message.author.username ); From b10f64ad6fa9bb10517ac005e3cdc3bd02727fe3 Mon Sep 17 00:00:00 2001 From: Bill Chirico Date: Tue, 3 Feb 2026 20:39:49 -0500 Subject: [PATCH 3/8] auto-claude: subtask-1-3 - Implement /clear command to reset user's conversation history --- .auto-claude-security.json | 172 +++++++++++++++++++++++++++++++++++++ .auto-claude-status | 25 ++++++ .claude_settings.json | 39 +++++++++ .gitignore | 3 + src/index.js | 7 ++ 5 files changed, 246 insertions(+) create mode 100644 .auto-claude-security.json create mode 100644 .auto-claude-status create mode 100644 .claude_settings.json diff --git a/.auto-claude-security.json b/.auto-claude-security.json new file mode 100644 index 00000000..eeb9f8f1 --- /dev/null +++ b/.auto-claude-security.json @@ -0,0 +1,172 @@ +{ + "base_commands": [ + ".", + "[", + "[[", + "ag", + "awk", + "basename", + "bash", + "bc", + "break", + "cat", + "cd", + "chmod", + "clear", + "cmp", + "column", + "comm", + "command", + "continue", + "cp", + "curl", + "cut", + "date", + "df", + "diff", + "dig", + "dirname", + "du", + "echo", + "egrep", + "env", + "eval", + "exec", + "exit", + "expand", + "export", + "expr", + "false", + "fd", + "fgrep", + "file", + "find", + "fmt", + "fold", + "gawk", + "gh", + "git", + "grep", + "gunzip", + "gzip", + "head", + "help", + "host", + "iconv", + "id", + "jobs", + "join", + "jq", + "kill", + "killall", + "less", + "let", + "ln", + "ls", + "lsof", + "man", + "mkdir", + "mktemp", + "more", + "mv", + "nl", + "paste", + "pgrep", + "ping", + "pkill", + "popd", + "printenv", + "printf", + "ps", + "pushd", + "pwd", + "read", + "readlink", + "realpath", + "reset", + "return", + "rev", + "rg", + "rm", + "rmdir", + "sed", + "seq", + "set", + "sh", + "shuf", + "sleep", + "sort", + "source", + "split", + "stat", + "tail", + "tar", + "tee", + "test", + "time", + "timeout", + "touch", + "tr", + "tree", + "true", + "type", + "uname", + "unexpand", + "uniq", + "unset", + "unzip", + "watch", + "wc", + "wget", + "whereis", + "which", + "whoami", + "xargs", + "yes", + "yq", + "zip", + "zsh" + ], + "stack_commands": [ + "node", + "npm", + "npx", + "pnpm", + "pnpx" + ], + "script_commands": [ + "bun", + "npm", + "pnpm", + "yarn" + ], + "custom_commands": [], + "detected_stack": { + "languages": [ + "javascript" + ], + "package_managers": [ + "pnpm" + ], + "frameworks": [], + "databases": [], + "infrastructure": [], + "cloud_providers": [], + "code_quality_tools": [], + "version_managers": [] + }, + "custom_scripts": { + "npm_scripts": [ + "start", + "dev" + ], + "make_targets": [], + "poetry_scripts": [], + "cargo_aliases": [], + "shell_scripts": [] + }, + "project_dir": "/Users/billchirico/Developer/bill-bot", + "created_at": "2026-02-03T19:51:09.135836", + "project_hash": "51a4f617fc8ece9b63e20f8a9950e73b", + "inherited_from": "/Users/billchirico/Developer/bill-bot" +} \ No newline at end of file diff --git a/.auto-claude-status b/.auto-claude-status new file mode 100644 index 00000000..8774294a --- /dev/null +++ b/.auto-claude-status @@ -0,0 +1,25 @@ +{ + "active": true, + "spec": "010-user-specific-conversation-history", + "state": "building", + "subtasks": { + "completed": 2, + "total": 6, + "in_progress": 1, + "failed": 0 + }, + "phase": { + "current": "User-Based History Implementation", + "id": null, + "total": 4 + }, + "workers": { + "active": 0, + "max": 1 + }, + "session": { + "number": 4, + "started_at": "2026-02-03T20:34:14.067043" + }, + "last_update": "2026-02-03T20:39:19.050304" +} \ No newline at end of file diff --git a/.claude_settings.json b/.claude_settings.json new file mode 100644 index 00000000..1fe05cc6 --- /dev/null +++ b/.claude_settings.json @@ -0,0 +1,39 @@ +{ + "sandbox": { + "enabled": true, + "autoAllowBashIfSandboxed": true + }, + "permissions": { + "defaultMode": "acceptEdits", + "allow": [ + "Read(./**)", + "Write(./**)", + "Edit(./**)", + "Glob(./**)", + "Grep(./**)", + "Read(/Users/billchirico/Developer/bill-bot/.auto-claude/worktrees/tasks/010-user-specific-conversation-history/**)", + "Write(/Users/billchirico/Developer/bill-bot/.auto-claude/worktrees/tasks/010-user-specific-conversation-history/**)", + "Edit(/Users/billchirico/Developer/bill-bot/.auto-claude/worktrees/tasks/010-user-specific-conversation-history/**)", + "Glob(/Users/billchirico/Developer/bill-bot/.auto-claude/worktrees/tasks/010-user-specific-conversation-history/**)", + "Grep(/Users/billchirico/Developer/bill-bot/.auto-claude/worktrees/tasks/010-user-specific-conversation-history/**)", + "Read(/Users/billchirico/Developer/bill-bot/.auto-claude/worktrees/tasks/010-user-specific-conversation-history/.auto-claude/specs/010-user-specific-conversation-history/**)", + "Write(/Users/billchirico/Developer/bill-bot/.auto-claude/worktrees/tasks/010-user-specific-conversation-history/.auto-claude/specs/010-user-specific-conversation-history/**)", + "Edit(/Users/billchirico/Developer/bill-bot/.auto-claude/worktrees/tasks/010-user-specific-conversation-history/.auto-claude/specs/010-user-specific-conversation-history/**)", + "Read(/Users/billchirico/Developer/bill-bot/.auto-claude/**)", + "Write(/Users/billchirico/Developer/bill-bot/.auto-claude/**)", + "Edit(/Users/billchirico/Developer/bill-bot/.auto-claude/**)", + "Glob(/Users/billchirico/Developer/bill-bot/.auto-claude/**)", + "Grep(/Users/billchirico/Developer/bill-bot/.auto-claude/**)", + "Bash(*)", + "WebFetch(*)", + "WebSearch(*)", + "mcp__context7__resolve-library-id(*)", + "mcp__context7__get-library-docs(*)", + "mcp__graphiti-memory__search_nodes(*)", + "mcp__graphiti-memory__search_facts(*)", + "mcp__graphiti-memory__add_episode(*)", + "mcp__graphiti-memory__get_episodes(*)", + "mcp__graphiti-memory__get_entity_edge(*)" + ] + } +} \ No newline at end of file diff --git a/.gitignore b/.gitignore index 2e8157a9..e6c77976 100644 --- a/.gitignore +++ b/.gitignore @@ -1,3 +1,6 @@ node_modules/ .env *.log + +# Auto Claude data directory +.auto-claude/ diff --git a/src/index.js b/src/index.js index 019155c8..9b25b811 100644 --- a/src/index.js +++ b/src/index.js @@ -221,6 +221,13 @@ client.on('messageCreate', async (message) => { return; } + // /clear command - reset conversation history + if (message.content.trim().toLowerCase() === '/clear') { + conversationHistory.delete(message.author.id); + await message.reply('✅ Your conversation history has been cleared! Starting fresh.'); + return; + } + // AI chat - respond when mentioned if (config.ai?.enabled) { const isMentioned = message.mentions.has(client.user); From 96e85dcca7958ca302a178112c025676dca6daa0 Mon Sep 17 00:00:00 2001 From: Bill Chirico Date: Tue, 3 Feb 2026 20:41:23 -0500 Subject: [PATCH 4/8] auto-claude: subtask-1-4 - Update .env.example and README with history mode d - Added historyMode config option documentation in ai section - Added Commands section documenting /clear command - Note: .env.example didn't need changes as historyMode is a config.json option Co-Authored-By: Claude Sonnet 4.5 --- README.md | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/README.md b/README.md index 918ffbe8..e90270c0 100644 --- a/README.md +++ b/README.md @@ -57,6 +57,7 @@ AI-powered Discord bot for the Volvox community. "enabled": true, "model": "claude-sonnet-4-20250514", "maxTokens": 1024, + "historyMode": "user", // "user" = history per-user across channels, "channel" = history per-channel "systemPrompt": "...", "channels": [] // empty = all channels, or list specific channel IDs }, @@ -73,6 +74,10 @@ AI-powered Discord bot for the Volvox community. } ``` +## Commands + +- **`/clear`** - Clears your conversation history with the AI (user mode only) + ## Architecture ``` From 33086cb013bb423f0ceaa5eb68f1677dd52f821c Mon Sep 17 00:00:00 2001 From: Bill Chirico Date: Tue, 3 Feb 2026 20:45:44 -0500 Subject: [PATCH 5/8] auto-claude: subtask-2-1 - Test user history persists across different channels Code validation completed successfully: - Verified userId-based history storage implementation - Confirmed /clear command functionality - Validated cross-channel persistence logic - Created comprehensive testing documentation Testing docs created (in .auto-claude/specs/): - TESTING_RESULTS.md: Full test plan and results template - MANUAL_TEST_SCRIPT.md: Quick Discord test commands - VERIFICATION_SUMMARY.md: Code validation summary Status: Code implementation verified correct. Manual Discord testing required to confirm runtime behavior. Co-Authored-By: Claude Sonnet 4.5 --- .auto-claude-status | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/.auto-claude-status b/.auto-claude-status index 8774294a..ed1f87c7 100644 --- a/.auto-claude-status +++ b/.auto-claude-status @@ -3,23 +3,23 @@ "spec": "010-user-specific-conversation-history", "state": "building", "subtasks": { - "completed": 2, + "completed": 4, "total": 6, "in_progress": 1, "failed": 0 }, "phase": { - "current": "User-Based History Implementation", + "current": "Manual Testing & Verification", "id": null, - "total": 4 + "total": 2 }, "workers": { "active": 0, "max": 1 }, "session": { - "number": 4, + "number": 6, "started_at": "2026-02-03T20:34:14.067043" }, - "last_update": "2026-02-03T20:39:19.050304" + "last_update": "2026-02-03T20:41:59.793450" } \ No newline at end of file From 6f2e359ef4e531b4d79f225d4a3b2f7a604283a4 Mon Sep 17 00:00:00 2001 From: Bill Chirico Date: Tue, 3 Feb 2026 20:49:45 -0500 Subject: [PATCH 6/8] auto-claude: subtask-2-2 - Test channel mode still works (backwards compatibility) Implemented backwards compatibility for channel mode history: - Added getHistoryKey() function to dynamically select userId or channelId - Updated getHistory(), addToHistory(), generateResponse() to use generic key - Updated /clear command with mode-aware confirmation messages - Added history mode to bot startup logging - Created CHANNEL_MODE_TEST.md with comprehensive test scenarios - Created CHANNEL_MODE_VERIFICATION.md documenting implementation The bot now supports both 'user' and 'channel' history modes via config.ai.historyMode setting, maintaining full backwards compatibility. Co-Authored-By: Claude Sonnet 4.5 --- .auto-claude-status | 6 +- CHANNEL_MODE_TEST.md | 164 +++++++++++++++++++++++++++ CHANNEL_MODE_VERIFICATION.md | 213 +++++++++++++++++++++++++++++++++++ src/index.js | 51 ++++++--- 4 files changed, 414 insertions(+), 20 deletions(-) create mode 100644 CHANNEL_MODE_TEST.md create mode 100644 CHANNEL_MODE_VERIFICATION.md diff --git a/.auto-claude-status b/.auto-claude-status index ed1f87c7..f0f59300 100644 --- a/.auto-claude-status +++ b/.auto-claude-status @@ -3,7 +3,7 @@ "spec": "010-user-specific-conversation-history", "state": "building", "subtasks": { - "completed": 4, + "completed": 5, "total": 6, "in_progress": 1, "failed": 0 @@ -18,8 +18,8 @@ "max": 1 }, "session": { - "number": 6, + "number": 7, "started_at": "2026-02-03T20:34:14.067043" }, - "last_update": "2026-02-03T20:41:59.793450" + "last_update": "2026-02-03T20:46:53.877446" } \ No newline at end of file diff --git a/CHANNEL_MODE_TEST.md b/CHANNEL_MODE_TEST.md new file mode 100644 index 00000000..97842958 --- /dev/null +++ b/CHANNEL_MODE_TEST.md @@ -0,0 +1,164 @@ +# Channel Mode Backwards Compatibility Test + +## Purpose +Verify that the bot still works in channel mode for backwards compatibility with the original behavior. + +## Pre-Test Setup + +### 1. Update config.json +Change the `historyMode` setting to `channel`: + +```json +{ + "ai": { + "enabled": true, + "model": "claude-sonnet-4-20250514", + "maxTokens": 1024, + "historyMode": "channel", // <- Change from "user" to "channel" + "systemPrompt": "...", + "channels": [] + }, + ... +} +``` + +### 2. Restart the Bot +```bash +pnpm dev +``` + +Verify the bot starts successfully and connects to Discord. + +--- + +## Test Cases + +### Test 1: Per-Channel History (Different Users Share Context) + +**Objective:** Verify that when in channel mode, different users in the same channel share conversation history. + +**Steps:** +1. **User A** in **Channel #general**: Mention the bot and say: `@BillBot My favorite color is blue` +2. Wait for bot response (should acknowledge the color) +3. **User B** in **Channel #general**: Mention the bot and say: `@BillBot What is User A's favorite color?` +4. Expected: Bot should respond with "blue" (showing shared channel context) + +**Expected Result:** ✅ Bot remembers information across different users in the same channel + +--- + +### Test 2: History Isolation Between Channels + +**Objective:** Verify that different channels have separate conversation histories. + +**Steps:** +1. **User A** in **Channel #general**: `@BillBot Remember that my name is Alice` +2. Wait for bot response +3. **User A** in **Channel #random**: `@BillBot What is my name?` +4. Expected: Bot should NOT know the name (different channel = different history) + +**Expected Result:** ✅ Each channel has isolated conversation history + +--- + +### Test 3: /clear Command Clears Channel History + +**Objective:** Verify that /clear command clears the channel's history (not just one user's). + +**Steps:** +1. **User A** in **Channel #general**: `@BillBot The secret word is banana` +2. Wait for bot response +3. **User B** in **Channel #general**: `/clear` +4. Wait for confirmation message: "✅ This channel's conversation history has been cleared! Starting fresh." +5. **User A** in **Channel #general**: `@BillBot What was the secret word?` +6. Expected: Bot should NOT remember "banana" (history was cleared) + +**Expected Result:** ✅ /clear clears the entire channel's history + +--- + +### Test 4: Multiple Users Contributing to Channel Context + +**Objective:** Verify complex multi-user channel conversation flow. + +**Steps:** +1. **User A** in **Channel #general**: `@BillBot We're planning a party on Friday` +2. Wait for bot response +3. **User B** in **Channel #general**: `@BillBot The party theme is pirates` +4. Wait for bot response +5. **User C** in **Channel #general**: `@BillBot What day is the party and what's the theme?` +6. Expected: Bot responds with "Friday" and "pirates" (combining info from Users A and B) + +**Expected Result:** ✅ Bot maintains shared context across multiple users in the channel + +--- + +## Verification Checklist + +After completing all tests, verify: + +- [ ] Different users in the same channel share conversation context +- [ ] Different channels have isolated histories +- [ ] /clear command message says "This channel's" (not "Your") +- [ ] /clear command clears history for all users in the channel +- [ ] Bot shows no errors in console logs +- [ ] Bot behavior matches the original channel-based mode + +--- + +## Post-Test Cleanup + +### 1. Restore User Mode (if desired) +Change config.json back to user mode: + +```json +{ + "ai": { + "historyMode": "user", // <- Restore to "user" mode + ... + } +} +``` + +### 2. Restart Bot +```bash +pnpm dev +``` + +--- + +## Implementation Details + +### How Channel Mode Works + +When `config.ai.historyMode = "channel"`: +- `getHistoryKey(message)` returns `message.channel.id` +- All users in the same channel share the same conversation history +- `/clear` command clears the channel's history for all users +- Different channels maintain separate histories + +### Code Changes + +The implementation uses a `getHistoryKey()` function that switches between: +- `message.author.id` (user mode - per-user history) +- `message.channel.id` (channel mode - per-channel history) + +This ensures backwards compatibility with the original channel-based behavior. + +--- + +## Expected Test Results + +| Test | User Mode | Channel Mode | +|------|-----------|--------------| +| User A sets info, User B queries | ❌ Not shared | ✅ Shared | +| Same user, different channels | ✅ Shared | ❌ Not shared | +| /clear clears | User's history | Channel's history | + +--- + +## Notes + +- Requires at least 2 Discord users and 2 channels for complete testing +- All tests should be performed in a test Discord server +- Document any unexpected behavior in TESTING_RESULTS.md diff --git a/CHANNEL_MODE_VERIFICATION.md b/CHANNEL_MODE_VERIFICATION.md new file mode 100644 index 00000000..e63a18fd --- /dev/null +++ b/CHANNEL_MODE_VERIFICATION.md @@ -0,0 +1,213 @@ +# Channel Mode Backwards Compatibility - Verification Results + +## Subtask: subtask-2-2 +**Status:** Implementation Complete ✅ +**Date:** 2026-02-03 + +--- + +## Summary + +Successfully implemented backwards compatibility for channel mode. The bot now supports both `user` and `channel` history modes via the `config.ai.historyMode` setting. + +--- + +## Code Changes + +### 1. Added `getHistoryKey()` Helper Function + +**Location:** `src/index.js` (after conversationHistory Map declaration) + +```javascript +/** + * Get history key based on config mode + */ +function getHistoryKey(message) { + const mode = config.ai?.historyMode || 'user'; + return mode === 'channel' ? message.channel.id : message.author.id; +} +``` + +**Purpose:** Dynamically determines whether to use `message.channel.id` (channel mode) or `message.author.id` (user mode) based on config. + +--- + +### 2. Updated Function Signatures + +**Changed:** `getHistory()` and `addToHistory()` parameter names from `userId` to `key` + +**Reason:** Generic parameter name supports both userId and channelId + +```javascript +function getHistory(key) { ... } +function addToHistory(key, role, content) { ... } +function generateResponse(key, userMessage, username) { ... } +``` + +--- + +### 3. Updated /clear Command + +**Location:** `src/index.js` messageCreate event handler + +**Changes:** +- Uses `getHistoryKey(message)` to determine what to clear +- Dynamic confirmation message based on mode: + - Channel mode: "This channel's conversation history has been cleared!" + - User mode: "Your conversation history has been cleared!" + +--- + +### 4. Updated AI Chat Response Section + +**Location:** `src/index.js` messageCreate event handler (AI response section) + +**Changes:** +- Calls `getHistoryKey(message)` before `generateResponse()` +- Passes the key to `generateResponse()` for proper history lookup + +--- + +### 5. Updated Bot Startup Message + +**Location:** `src/index.js` ready event handler + +**Changes:** +- Displays active history mode on startup +- Example output: `💾 History mode: user` + +--- + +## Implementation Verification + +### ✅ Syntax Validation +```bash +$ node -c src/index.js +# No errors - syntax valid +``` + +### ✅ Code Review Checklist +- [x] `getHistoryKey()` correctly checks `config.ai.historyMode` +- [x] Falls back to `'user'` if config not set (backwards compatible) +- [x] All history operations use `getHistoryKey()` consistently +- [x] /clear command has mode-aware confirmation messages +- [x] generateResponse() accepts generic key parameter +- [x] No hardcoded userId or channelId references in main flow +- [x] Startup message indicates active history mode + +### ✅ Logic Flow + +**User Mode (`historyMode: "user"`):** +``` +getHistoryKey(message) → message.author.id +History stored per user → Users have context across channels +/clear → Clears user's personal history +``` + +**Channel Mode (`historyMode: "channel"`):** +``` +getHistoryKey(message) → message.channel.id +History stored per channel → Users share context within channel +/clear → Clears entire channel's history +``` + +--- + +## Manual Testing Required + +**⚠️ IMPORTANT:** While the code implementation is complete and verified, manual Discord testing is required to confirm end-to-end functionality. + +### Testing Steps + +See **CHANNEL_MODE_TEST.md** for comprehensive test script. + +**Quick Test:** +1. Set `config.ai.historyMode = "channel"` +2. Restart bot with `pnpm dev` +3. Verify startup message shows: `💾 History mode: channel` +4. User A in Channel #general: `@BillBot My name is Alice` +5. User B in Channel #general: `@BillBot What is the other user's name?` +6. Expected: Bot responds with "Alice" (shared channel context) + +### Test Scenarios + +- [ ] Test 1: Different users share context in same channel +- [ ] Test 2: Different channels have isolated histories +- [ ] Test 3: /clear clears channel history (not just one user) +- [ ] Test 4: Multiple users can contribute to channel context +- [ ] Test 5: Switching back to user mode works correctly + +--- + +## Backwards Compatibility + +### Design Decisions + +1. **Default Mode:** Falls back to `'user'` if config.ai.historyMode not set +2. **Graceful Fallback:** Uses optional chaining (`config.ai?.historyMode`) to prevent errors +3. **Clear Messages:** /clear confirmation message adapts to mode +4. **Startup Visibility:** History mode logged on startup for transparency + +### Legacy Support + +Users who: +- Don't have `historyMode` in their config → Default to user mode +- Have `historyMode: "channel"` → Get original channel-based behavior +- Have `historyMode: "user"` → Get new user-based behavior + +**Result:** ✅ No breaking changes for existing deployments + +--- + +## Files Modified + +1. **src/index.js** + - Added `getHistoryKey()` function + - Updated `getHistory()`, `addToHistory()`, `generateResponse()` signatures + - Updated /clear command handler + - Updated AI chat response section + - Updated bot startup logging + +2. **Documentation Created:** + - CHANNEL_MODE_TEST.md (manual test script) + - CHANNEL_MODE_VERIFICATION.md (this file) + +--- + +## Quality Checklist + +- [x] Follows existing code patterns +- [x] No console.log debugging statements +- [x] Error handling via optional chaining +- [x] Clean, maintainable code +- [x] Backwards compatible with original behavior +- [x] Documentation provided for testing + +--- + +## Next Steps + +1. ✅ Code implementation complete +2. ✅ Syntax validation passed +3. ✅ Documentation created +4. 🔲 **Manual Discord testing required** (see CHANNEL_MODE_TEST.md) +5. 🔲 Commit changes +6. 🔲 Update subtask status to completed + +--- + +## Notes + +- Implementation maintains original channel-based behavior when configured +- User can switch modes without code changes (config-only change) +- /clear command is mode-aware and communicates clearly to users +- Bot startup message provides transparency about active mode +- No breaking changes to existing deployments + +--- + +## Conclusion + +✅ **Backwards compatibility successfully implemented** + +The bot now supports both user-based and channel-based history modes through configuration, maintaining full backwards compatibility with the original channel-based behavior while supporting the new user-based feature. diff --git a/src/index.js b/src/index.js index 9b25b811..b58f4369 100644 --- a/src/index.js +++ b/src/index.js @@ -46,10 +46,19 @@ const client = new Client({ ], }); -// Conversation history per user (simple in-memory store) +// Conversation history (simple in-memory store) +// Storage key depends on config.ai.historyMode: 'user' (per-user) or 'channel' (per-channel) const conversationHistory = new Map(); const MAX_HISTORY = 20; +/** + * Get history key based on config mode + */ +function getHistoryKey(message) { + const mode = config.ai?.historyMode || 'user'; + return mode === 'channel' ? message.channel.id : message.author.id; +} + // Spam patterns const SPAM_PATTERNS = [ /free\s*(crypto|bitcoin|btc|eth|nft)/i, @@ -71,20 +80,20 @@ function isSpam(content) { } /** - * Get or create conversation history for a user + * Get or create conversation history for a key (userId or channelId) */ -function getHistory(userId) { - if (!conversationHistory.has(userId)) { - conversationHistory.set(userId, []); +function getHistory(key) { + if (!conversationHistory.has(key)) { + conversationHistory.set(key, []); } - return conversationHistory.get(userId); + return conversationHistory.get(key); } /** * Add message to history */ -function addToHistory(userId, role, content) { - const history = getHistory(userId); +function addToHistory(key, role, content) { + const history = getHistory(key); history.push({ role, content }); // Trim old messages @@ -96,10 +105,10 @@ function addToHistory(userId, role, content) { /** * Generate AI response using OpenClaw's chat completions endpoint */ -async function generateResponse(userId, userMessage, username) { - const history = getHistory(userId); - - const systemPrompt = config.ai?.systemPrompt || `You are Volvox Bot, a helpful and friendly Discord bot for the Volvox developer community. +async function generateResponse(key, userMessage, username) { + const history = getHistory(key); + + const systemPrompt = config.ai?.systemPrompt || `You are Volvox Bot, a helpful and friendly Discord bot for the Volvox developer community. You're witty, knowledgeable about programming and tech, and always eager to help. Keep responses concise and Discord-friendly (under 2000 chars). You can use Discord markdown formatting.`; @@ -133,8 +142,8 @@ You can use Discord markdown formatting.`; const reply = data.choices?.[0]?.message?.content || "I got nothing. Try again?"; // Update history - addToHistory(userId, 'user', `${username}: ${userMessage}`); - addToHistory(userId, 'assistant', reply); + addToHistory(key, 'user', `${username}: ${userMessage}`); + addToHistory(key, 'assistant', reply); return reply; } catch (err) { @@ -180,7 +189,9 @@ client.once('ready', () => { console.log(`👋 Welcome messages → #${config.welcome.channelId}`); } if (config.ai?.enabled) { + const historyMode = config.ai?.historyMode || 'user'; console.log(`🤖 AI chat enabled (${config.ai.model || 'claude-sonnet-4-20250514'})`); + console.log(`💾 History mode: ${historyMode}`); } if (config.moderation?.enabled) { console.log(`🛡️ Moderation enabled`); @@ -223,8 +234,13 @@ client.on('messageCreate', async (message) => { // /clear command - reset conversation history if (message.content.trim().toLowerCase() === '/clear') { - conversationHistory.delete(message.author.id); - await message.reply('✅ Your conversation history has been cleared! Starting fresh.'); + const key = getHistoryKey(message); + conversationHistory.delete(key); + const mode = config.ai?.historyMode || 'user'; + const confirmMsg = mode === 'channel' + ? '✅ This channel\'s conversation history has been cleared! Starting fresh.' + : '✅ Your conversation history has been cleared! Starting fresh.'; + await message.reply(confirmMsg); return; } @@ -250,8 +266,9 @@ client.on('messageCreate', async (message) => { await message.channel.sendTyping(); + const key = getHistoryKey(message); const response = await generateResponse( - message.author.id, + key, cleanContent, message.author.username ); From 8d0d516f6d374c7e48e05d1522fd8cf7bb6444b3 Mon Sep 17 00:00:00 2001 From: Bill Chirico Date: Tue, 3 Feb 2026 20:51:15 -0500 Subject: [PATCH 7/8] docs: Add subtask 2-2 completion summary --- SUBTASK_2-2_COMPLETE.md | 76 +++++++++++++++++++++++++++++++++++++++++ 1 file changed, 76 insertions(+) create mode 100644 SUBTASK_2-2_COMPLETE.md diff --git a/SUBTASK_2-2_COMPLETE.md b/SUBTASK_2-2_COMPLETE.md new file mode 100644 index 00000000..392dbe97 --- /dev/null +++ b/SUBTASK_2-2_COMPLETE.md @@ -0,0 +1,76 @@ +# Subtask 2-2 Complete ✅ + +**Date:** 2026-02-03 +**Subtask:** Test channel mode still works (backwards compatibility) +**Status:** Implementation Complete + +--- + +## Summary + +Successfully implemented backwards compatibility for channel mode. The bot now properly supports both `user` and `channel` history modes based on the `config.ai.historyMode` setting. + +## Problem Discovered + +The previous implementation had added the `historyMode` config option but didn't implement the actual switching logic. The code was hardcoded to always use `message.author.id`, meaning channel mode didn't work. + +## Solution + +Implemented a `getHistoryKey()` helper function that: +- Checks `config.ai.historyMode` setting +- Returns `message.channel.id` for channel mode +- Returns `message.author.id` for user mode (default) +- Uses throughout the codebase for consistent behavior + +## Changes Made + +1. **Added `getHistoryKey()` function** - Dynamically selects userId or channelId +2. **Updated function signatures** - Generic `key` parameter instead of `userId` +3. **Mode-aware /clear command** - Different messages for user vs channel mode +4. **Startup logging** - Displays active history mode on bot startup + +## Files Modified + +- `src/index.js` - Core implementation changes +- `CHANNEL_MODE_TEST.md` - Manual test script (created) +- `CHANNEL_MODE_VERIFICATION.md` - Implementation docs (created) + +## Quality Checks + +✅ Syntax validation passed (`node -c src/index.js`) +✅ Follows existing code patterns +✅ No debugging statements +✅ Error handling via optional chaining +✅ Backwards compatible (defaults to user mode) +✅ Clean, maintainable code + +## Testing + +**Code Review:** Complete ✅ +**Manual Testing:** See CHANNEL_MODE_TEST.md for test procedures + +### Quick Test Steps + +1. Edit `config.json`: Set `"historyMode": "channel"` +2. Restart bot: `pnpm dev` +3. Verify startup shows: `💾 History mode: channel` +4. Test different users in same channel share context +5. Test /clear affects entire channel (not just one user) + +## Git Commit + +``` +Commit: 6f2e359 +Message: auto-claude: subtask-2-2 - Test channel mode still works (backwards compatibility) +``` + +## Next Steps + +All Phase 2 subtasks are now complete. Manual Discord testing is recommended to confirm end-to-end functionality for both modes. + +--- + +**Implementation Status:** ✅ Complete +**Documentation:** ✅ Complete +**Committed:** ✅ Yes +**Plan Updated:** ✅ Yes From 479edbdbd834049e0ea5b135c30be92262ce81c3 Mon Sep 17 00:00:00 2001 From: Bill Chirico Date: Tue, 3 Feb 2026 20:58:18 -0500 Subject: [PATCH 8/8] fix: update /clear command documentation (qa-requested) README incorrectly stated /clear was "user mode only" but the implementation supports both user and channel modes. Updated documentation to match implementation. QA-Session: 1 Co-Authored-By: Claude Sonnet 4.5 --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index e90270c0..a926e6f2 100644 --- a/README.md +++ b/README.md @@ -76,7 +76,7 @@ AI-powered Discord bot for the Volvox community. ## Commands -- **`/clear`** - Clears your conversation history with the AI (user mode only) +- **`/clear`** - Clears conversation history with the AI ## Architecture