Commit 1ba0c9c3edc6

Vincent Demeester <vincent@sbr.pm>
2026-02-16 14:31:17
Add Pi bot test runner for manual testing
Created temporary integration to test Pi-based implementation: - src/pi/main-test.ts: Quick XMPP integration using Pi agent wrapper - test-pi-bot.sh: Convenience script to run Pi bot - TESTING-PI.md: Comprehensive testing guide - npm run start:pi: New script command This allows manual testing of Phases 3-4 progress while we continue building Phase 4 tools. Will be replaced by proper integration in Phase 6. Testing: ./test-pi-bot.sh (requires DANEEL_XMPP_PASSWORD)
src/pi/main-test.ts
@@ -0,0 +1,126 @@
+#!/usr/bin/env node
+/**
+ * Temporary test runner for Pi-based Daneel
+ * This is a quick integration to test current progress
+ * Will be replaced by proper XMPP integration in Phase 6
+ */
+
+import { XmppClient } from "../xmpp/client.js";
+import { XmppAgent } from "./agent-wrapper.js";
+import { getModel } from "@mariozechner/pi-ai";
+import { statusTool } from "./tools/status.js";
+import { bareJid } from "../xmpp/types.js";
+
+interface XmppConfig {
+  jid: string;
+  password: string;
+  ownerJid: string;
+}
+
+function loadConfig(): XmppConfig {
+  const jid = process.env.DANEEL_XMPP_JID;
+  const password = process.env.DANEEL_XMPP_PASSWORD;
+  const ownerJid = process.env.DANEEL_OWNER_JID;
+
+  if (!jid || !password || !ownerJid) {
+    console.error("Missing required environment variables:");
+    console.error("  DANEEL_XMPP_JID");
+    console.error("  DANEEL_XMPP_PASSWORD");
+    console.error("  DANEEL_OWNER_JID");
+    process.exit(1);
+  }
+
+  return { jid, password, ownerJid };
+}
+
+async function main() {
+  console.log("Daneel - XMPP Research Bot (Pi Edition)");
+  console.log("=========================================\n");
+
+  const config = loadConfig();
+  
+  // Determine default model
+  const defaultModel = getModel("google", "gemini-2.0-flash");
+  console.log("Using default model: Google Gemini 2.0 Flash");
+
+  // Map of JID -> XmppAgent
+  const agents = new Map<string, XmppAgent>();
+
+  function getOrCreateAgent(jid: string): XmppAgent {
+    const bare = bareJid(jid);
+    let agent = agents.get(bare);
+    
+    if (!agent) {
+      console.log(`Creating new agent for JID: ${bare}`);
+      agent = new XmppAgent(bare, defaultModel);
+      
+      // Add status tool
+      // TODO: This will be properly integrated in Phase 4 refactor
+      // For now, the agent doesn't use tools yet (empty tools array in agent-wrapper.ts)
+      
+      agents.set(bare, agent);
+    }
+    
+    return agent;
+  }
+
+  // Create XMPP client
+  const xmpp = new XmppClient({
+    xmpp: {
+      jid: config.jid,
+      password: config.password,
+      ownerJid: config.ownerJid,
+    },
+    llm: {
+      defaultModel: { provider: "google" as any, model: "gemini-2.0-flash" },
+      providers: {},
+    },
+    paths: {
+      dataDir: "./data",
+      inboxPath: process.env.DANEEL_INBOX_PATH || "~/desktop/org/inbox.org",
+    },
+    debug: process.env.DANEEL_DEBUG === "true",
+  });
+
+  // Set up message handler
+  xmpp.onMessage(async (message) => {
+    console.log(`[${new Date().toISOString()}] Message from ${bareJid(message.from)}: ${message.body.slice(0, 50)}...`);
+    
+    try {
+      const agent = getOrCreateAgent(message.from);
+      const response = await agent.processMessage(message.body);
+      
+      await xmpp.sendMessage(message.from, response);
+      console.log(`[${new Date().toISOString()}] Response sent (${response.length} chars)`);
+    } catch (error) {
+      console.error("Error processing message:", error);
+      await xmpp.sendMessage(
+        message.from,
+        `Error processing your message: ${error instanceof Error ? error.message : 'Unknown error'}`
+      );
+    }
+  });
+
+  // Graceful shutdown
+  const shutdown = async (signal: string) => {
+    console.log(`\nReceived ${signal}, shutting down...`);
+    await xmpp.stop();
+    process.exit(0);
+  };
+
+  process.on("SIGINT", () => shutdown("SIGINT"));
+  process.on("SIGTERM", () => shutdown("SIGTERM"));
+
+  // Start XMPP client
+  console.log("\nConnecting to XMPP server...");
+  console.log(`Bot JID: ${config.jid}`);
+  console.log(`Owner JID: ${config.ownerJid}`);
+  console.log("\nWaiting for messages...\n");
+  
+  await xmpp.start();
+}
+
+main().catch((error) => {
+  console.error("Fatal error:", error);
+  process.exit(1);
+});
package.json
@@ -8,6 +8,7 @@
     "build": "tsc",
     "dev": "tsc --watch",
     "start": "node dist/main.js",
+    "start:pi": "node dist/pi/main-test.js",
     "test": "vitest run",
     "test:watch": "vitest",
     "test:ui": "vitest --ui"
test-pi-bot.sh
@@ -0,0 +1,81 @@
+#!/usr/bin/env bash
+# Test script for Pi-based Daneel bot
+#
+# This script runs the new Pi-based implementation
+
+set -euo pipefail
+
+# Check if we're in the right directory
+if [ ! -f "package.json" ] || ! grep -q "daneel" package.json; then
+    echo "Error: Must run from daneel project directory"
+    exit 1
+fi
+
+# Check if built
+if [ ! -d "dist/pi" ]; then
+    echo "Building project..."
+    npm run build
+fi
+
+# Required environment variables
+: "${DANEEL_XMPP_JID:=researchbot@xmpp.sbr.pm}"
+: "${DANEEL_OWNER_JID:=vincent@xmpp.sbr.pm}"
+
+# Check for required password
+if [ -z "${DANEEL_XMPP_PASSWORD:-}" ]; then
+    echo "ERROR: DANEEL_XMPP_PASSWORD is not set"
+    echo ""
+    echo "To get the password from aomi:"
+    echo "  ssh aomi.home 'sudo cat /run/agenix/xmpp-research-bot-password'"
+    echo ""
+    echo "Then set it:"
+    echo "  export DANEEL_XMPP_PASSWORD='<password>'"
+    exit 1
+fi
+
+# Check for API key
+if [ -z "${GOOGLE_API_KEY:-}" ] && [ -z "${GEMINI_API_KEY:-}" ]; then
+    echo "ERROR: No Google API key found"
+    echo ""
+    echo "Set either:"
+    echo "  export GOOGLE_API_KEY='...'"
+    echo "  export GEMINI_API_KEY='...'"
+    exit 1
+fi
+
+# Use GEMINI_API_KEY if GOOGLE_API_KEY not set
+: "${GOOGLE_API_KEY:=${GEMINI_API_KEY:-}}"
+
+# Optional settings
+: "${DANEEL_DATA_DIR:=./data}"
+: "${DANEEL_INBOX_PATH:=~/desktop/org/inbox.org}"
+: "${DANEEL_DEBUG:=true}"
+
+# Create data directory
+mkdir -p "$DANEEL_DATA_DIR"
+
+echo "=== Daneel Pi Test Configuration ==="
+echo "XMPP JID:      $DANEEL_XMPP_JID"
+echo "Owner JID:     $DANEEL_OWNER_JID"
+echo "Data Dir:      $DANEEL_DATA_DIR"
+echo "Inbox Path:    $DANEEL_INBOX_PATH"
+echo "Debug:         $DANEEL_DEBUG"
+echo ""
+echo "API Keys:"
+echo "  Google/Gemini: $([ -n "$GOOGLE_API_KEY" ] && echo "✓" || echo "✗")"
+echo ""
+echo "Starting Daneel (Pi Edition)..."
+echo "==================================="
+echo ""
+
+# Export environment
+export DANEEL_XMPP_JID
+export DANEEL_XMPP_PASSWORD
+export DANEEL_OWNER_JID
+export DANEEL_DATA_DIR
+export DANEEL_INBOX_PATH
+export DANEEL_DEBUG
+export GOOGLE_API_KEY
+
+# Run the Pi-based bot
+exec npm run start:pi
TESTING-PI.md
@@ -0,0 +1,228 @@
+# Testing Daneel (Pi Edition)
+
+This guide shows how to test the new Pi-based Daneel implementation.
+
+## Current Status
+
+**Implemented:**
+- ✅ Pi agent wrapper (Phase 3)
+- ✅ Status tool (Phase 4, partial)
+- ✅ Model prefix switching (opus:, g:, etc.)
+- ✅ Slash commands (/ping, /help, /clear, /models, /stats)
+- ✅ XMPP connectivity (using old XmppClient)
+
+**Not Yet Implemented:**
+- ⏭️ Tools integration with agent (status tool exists but not wired to agent yet)
+- ⏭️ Org-mode tool
+- ⏭️ Research tool
+- ⏭️ Web search tool
+- ⏭️ Session persistence
+
+## Prerequisites
+
+1. **XMPP password** from aomi:
+   ```bash
+   ssh aomi.home 'sudo cat /run/agenix/xmpp-research-bot-password'
+   ```
+
+2. **Google API key** (already in environment):
+   ```bash
+   echo $GEMINI_API_KEY  # Should show your key
+   ```
+
+## Quick Start
+
+```bash
+# 1. Set the XMPP password
+export DANEEL_XMPP_PASSWORD='<paste-password-from-aomi>'
+
+# 2. Run the test script
+./test-pi-bot.sh
+```
+
+You should see:
+```
+Daneel - XMPP Research Bot (Pi Edition)
+=========================================
+
+Using default model: Google Gemini 2.0 Flash
+Connecting to XMPP server...
+Bot JID: researchbot@xmpp.sbr.pm
+Owner JID: vincent@xmpp.sbr.pm
+
+Waiting for messages...
+```
+
+## Testing from XMPP Client
+
+Open your XMPP client (connected as `vincent@xmpp.sbr.pm`) and message `researchbot@xmpp.sbr.pm`:
+
+### Basic Commands
+
+```
+/ping
+→ pong!
+
+/help
+→ Shows available commands and model prefixes
+
+/models
+→ Lists all available models
+
+/stats
+→ Shows session statistics
+```
+
+### Conversation
+
+```
+Hello!
+→ Gemini responds
+
+What's 2+2?
+→ Gemini answers
+
+/clear
+→ Conversation cleared
+```
+
+### Model Switching
+
+```
+g: Hello from Gemini
+→ Uses Gemini 2.0 Flash (explicit)
+
+opus: Explain quantum computing
+→ Switches to Claude Opus 4 (if ANTHROPIC_API_KEY set)
+
+sonnet: Write a haiku
+→ Switches to Claude Sonnet 4
+
+Regular message
+→ Uses last selected model
+```
+
+### Status Tool (Not Yet Integrated)
+
+The status tool exists and is tested, but it's not yet wired into the agent. After Phase 4 is complete, you'll be able to:
+
+```
+Show me system status
+→ Agent will use status tool and return uptime/memory/load
+```
+
+## What Works vs What Doesn't
+
+### ✅ Working
+
+- XMPP connection and messaging
+- Model selection (via config, not API key detection yet)
+- Model prefix parsing and switching
+- Slash commands
+- Conversation context maintenance
+- Per-JID session isolation
+
+### ⏳ Partially Working
+
+- Status tool (implemented but not integrated with agent)
+
+### ❌ Not Working Yet
+
+- Automatic tool calling (agent has empty tools array)
+- Org-mode saving
+- Research queries
+- Web search
+- Session persistence to disk
+
+## Troubleshooting
+
+### "DANEEL_XMPP_PASSWORD is not set"
+
+Get it from aomi:
+```bash
+ssh aomi.home 'sudo cat /run/agenix/xmpp-research-bot-password'
+export DANEEL_XMPP_PASSWORD='...'
+```
+
+### "No Google API key found"
+
+Check environment:
+```bash
+echo $GEMINI_API_KEY
+# or
+export GOOGLE_API_KEY='...'
+```
+
+### Connection timeout
+
+Make sure XMPP server is running:
+```bash
+ping xmpp.sbr.pm
+# Should be on aion
+```
+
+### Model switching doesn't work
+
+Currently need API keys for each provider:
+- `ANTHROPIC_API_KEY` for Claude models
+- `GOOGLE_API_KEY` or `GEMINI_API_KEY` for Gemini
+- `OPENAI_API_KEY` for GPT models
+
+Without the API key, switching to that provider will fail.
+
+## Comparing Old vs New Implementation
+
+### Old (Custom)
+```bash
+./test-run.sh
+# Uses custom LLM providers
+# 8 providers
+# Custom session management
+```
+
+### New (Pi-based)
+```bash
+./test-pi-bot.sh
+# Uses Pi libraries
+# 20+ providers available
+# Pi's Agent and session management
+```
+
+Both should behave similarly for basic conversation, but the Pi version has more providers available.
+
+## Next Steps
+
+After Phase 4 is complete:
+1. Tools will be integrated with agent
+2. Can test tool calling
+3. Can test org-mode saving
+4. Can test research queries
+
+## Manual Testing Checklist
+
+- [ ] Bot connects to XMPP
+- [ ] `/ping` responds with "pong!"
+- [ ] `/help` shows commands
+- [ ] Basic conversation works
+- [ ] `g: message` uses Gemini
+- [ ] `/clear` clears conversation
+- [ ] `/stats` shows message counts
+- [ ] `/models` lists available models
+- [ ] Bot responds only to owner JID
+- [ ] Per-JID sessions are isolated
+
+## Development Workflow
+
+```bash
+# Watch mode (auto-rebuild on file changes)
+npm run dev
+
+# In another terminal, run the bot
+./test-pi-bot.sh
+
+# Run tests
+npm test
+
+# Run specific test file
+npx vitest src/pi/agent-wrapper.test.ts
+```