Core agent improvements: - RSO (Relevance Scoring & Observation) system: interaction_logger, memory_scorer, signal_detector - Memory access logging (memory_access_log table) for relevance scoring; high-signal turn detection - Rich conversation storage for notable turns; compact_conversation truncates long user messages - Task-type classifier (query/action/analysis/creative) for observation tagging - Nested sub-agent visibility: deep delegations now register against the main agent's manager Child safety (Gabriel profile): - child_safety.py: filtering, audit logging, prompt constants for restricted sessions - .kiro/specs/child-safety-profile: requirements, design, tasks specs - GABRIEL_BOT_PROPOSAL.md: initial proposal doc - Reduced context window (10 msgs) and tutor-mode identity for restricted users Telegram adapter: - Polling watchdog: auto-restarts updater if polling drops unexpectedly - get_me() with exponential-backoff retry on NetworkError at startup - Correct stop() ordering: signal watchdog before cancelling tasks Email / Gmail: - send_email: supports file attachments (attachments list param) - get_email: surfaces attachment metadata in response Scheduled tasks / weather: - Remove OpenWeatherMap API calls from morning-weather task; use wttr.in exclusively - New scheduled tasks and scheduler state persistence Discord: - adapters/discord/__init__.py scaffold - discord-plugin: MCP plugin for Claude Code Discord integration (server.ts, skills, config) Infrastructure: - n8n workflow exports (garvis_webhook, content_pipeline variants) - memory_workspace: context, homelab-repo-updates, weekly observation summaries, error logs - UCS C240 migration plan doc - requirements.txt: new deps - .claude/settings.json, fix_hooks.py: hook/permission tuning
1 line
8.0 KiB
JSON
1 line
8.0 KiB
JSON
{"name": "Garvis Webhook - Bot Actions", "nodes": [{"parameters": {"httpMethod": "POST", "path": "garvis", "responseMode": "responseNode", "options": {}}, "id": "b2c3d4e5-2222-4000-8000-000000000001", "name": "Webhook", "type": "n8n-nodes-base.webhook", "typeVersion": 2, "position": [0, 300], "webhookId": "garvis-webhook"}, {"parameters": {"conditions": {"options": {"caseSensitive": true, "leftValue": "", "typeValidation": "strict"}, "conditions": [{"id": "auth1", "leftValue": "={{ $json.headers['x-garvis-secret'] }}", "rightValue": "={{ $env.GARVIS_WEBHOOK_SECRET }}", "operator": {"type": "string", "operation": "equals"}}], "combinator": "and"}}, "id": "b2c3d4e5-2222-4000-8000-000000000002", "name": "IF Auth Valid?", "type": "n8n-nodes-base.if", "typeVersion": 2, "position": [220, 300]}, {"parameters": {"respondWith": "json", "responseBody": "={\"error\": \"Unauthorized\", \"message\": \"Invalid or missing x-garvis-secret header\"}", "options": {"responseCode": 401}}, "id": "b2c3d4e5-2222-4000-8000-000000000003", "name": "Respond 401", "type": "n8n-nodes-base.respondToWebhook", "typeVersion": 1.1, "position": [440, 480]}, {"parameters": {"rules": {"rules": [{"value": "run_pipeline", "output": 0}, {"value": "check_nas", "output": 1}, {"value": "check_services", "output": 2}, {"value": "send_message", "output": 3}, {"value": "get_status", "output": 4}]}, "value": "={{ $json.body.action }}"}, "id": "b2c3d4e5-2222-4000-8000-000000000004", "name": "Switch Action", "type": "n8n-nodes-base.switch", "typeVersion": 3, "position": [440, 200]}, {"parameters": {"method": "POST", "url": "http://192.168.2.113:5678/api/v1/workflows/{{ $env.CONTENT_PIPELINE_ID }}/activate", "sendHeaders": true, "headerParameters": {"parameters": [{"name": "X-N8N-API-KEY", "value": "={{ $env.N8N_API_KEY }}"}]}}, "id": "b2c3d4e5-2222-4000-8000-000000000005", "name": "Trigger Content Pipeline", "type": "n8n-nodes-base.httpRequest", "typeVersion": 4.2, "position": [700, 0]}, {"parameters": {"method": "POST", "url": "http://192.168.2.210:5000/webapi/entry.cgi", "sendBody": true, "bodyParameters": {"parameters": [{"name": "api", "value": "SYNO.FileStation.List"}, {"name": "version", "value": "2"}, {"name": "method", "value": "list"}, {"name": "folder_path", "value": "={{ $json.body.path || '/BlendedFamilyKitchen/DropZone' }}"}]}}, "id": "b2c3d4e5-2222-4000-8000-000000000006", "name": "Check NAS Files", "type": "n8n-nodes-base.httpRequest", "typeVersion": 4.2, "position": [700, 140]}, {"parameters": {"command": "=echo '{\"proxmox\": \"checking...\", \"loki\": \"checking...\", \"nas\": \"checking...\"}' && curl -s -o /dev/null -w '%{http_code}' http://192.168.2.100:8006 && curl -s -o /dev/null -w '%{http_code}' http://192.168.2.114:3100/ready && curl -s -o /dev/null -w '%{http_code}' http://192.168.2.210:5000"}, "id": "b2c3d4e5-2222-4000-8000-000000000007", "name": "Check Services Health", "type": "n8n-nodes-base.executeCommand", "typeVersion": 1, "position": [700, 280]}, {"parameters": {"method": "POST", "url": "=https://api.telegram.org/bot{{ $env.TELEGRAM_BOT_TOKEN }}/sendMessage", "sendBody": true, "specifyBody": "json", "jsonBody": "={\n \"chat_id\": \"{{ $json.body.chat_id || $env.JORDAN_CHAT_ID }}\",\n \"text\": \"{{ $json.body.message }}\",\n \"parse_mode\": \"HTML\"\n}"}, "id": "b2c3d4e5-2222-4000-8000-000000000008", "name": "Send Telegram Message", "type": "n8n-nodes-base.httpRequest", "typeVersion": 4.2, "position": [700, 420]}, {"parameters": {"mode": "manual", "duplicateItem": false, "assignments": {"assignments": [{"id": "st1", "name": "status", "value": "operational", "type": "string"}, {"id": "st2", "name": "workflows_active", "value": "={{ $env.ACTIVE_WORKFLOW_COUNT || '0' }}", "type": "string"}, {"id": "st3", "name": "uptime", "value": "={{ $now.toISO() }}", "type": "string"}, {"id": "st4", "name": "version", "value": "1.0.0", "type": "string"}]}}, "id": "b2c3d4e5-2222-4000-8000-000000000009", "name": "Get System Status", "type": "n8n-nodes-base.set", "typeVersion": 3.4, "position": [700, 560]}, {"parameters": {"respondWith": "json", "responseBody": "={{ JSON.stringify({success: true, action: $('Switch Action').item.json.body.action, result: $json}) }}", "options": {"responseCode": 200}}, "id": "b2c3d4e5-2222-4000-8000-000000000010", "name": "Respond 200 Success", "type": "n8n-nodes-base.respondToWebhook", "typeVersion": 1.1, "position": [960, 280]}, {"parameters": {"respondWith": "json", "responseBody": "={\"error\": \"Unknown action\", \"message\": \"Valid actions: run_pipeline, check_nas, check_services, send_message, get_status\", \"received\": \"{{ $json.body.action }}\"}", "options": {"responseCode": 400}}, "id": "b2c3d4e5-2222-4000-8000-000000000011", "name": "Respond 400 Unknown", "type": "n8n-nodes-base.respondToWebhook", "typeVersion": 1.1, "position": [700, 720]}, {"parameters": {"content": "## \ud83d\udd10 Webhook Auth & Entry\n\n**Endpoint:** POST http://192.168.2.113:5678/webhook/garvis\n\n**Request format:**\n```json\n{\n \"action\": \"run_pipeline|check_nas|check_services|send_message|get_status\",\n \"message\": \"(for send_message)\",\n \"chat_id\": \"(optional, defaults to Jordan)\",\n \"path\": \"(optional, for check_nas)\"\n}\n```\n\n**Auth:** x-garvis-secret header must match GARVIS_WEBHOOK_SECRET env var\n\n**Test command:**\n```bash\ncurl -X POST http://192.168.2.113:5678/webhook/garvis \\\n -H 'Content-Type: application/json' \\\n -H 'x-garvis-secret: YOUR_SECRET' \\\n -d '{\"action\": \"get_status\"}'\n```\n\n**TODO:**\n- [ ] Generate GARVIS_WEBHOOK_SECRET and add to n8n env\n- [ ] Add webhook URL to Garvis bot config\n- [ ] Test from Garvis agent with real request", "width": 560, "height": 520}, "id": "b2c3d4e5-2222-4000-8000-000000000012", "name": "Sticky - Webhook Setup", "type": "n8n-nodes-base.stickyNote", "typeVersion": 1, "position": [-40, -260]}, {"parameters": {"content": "## \ud83d\udd00 Action Handlers\n\n**run_pipeline** \u2014 Triggers the Content Pipeline workflow via n8n API. Use when Garvis needs to manually kick off video processing.\n\n**check_nas** \u2014 Lists files in a NAS directory. Defaults to /BlendedFamilyKitchen/DropZone. Pass custom path in request body.\n\n**check_services** \u2014 Pings Proxmox (8006), Loki (3100), and NAS (5000) to verify they're responding. Returns HTTP status codes.\n\n**send_message** \u2014 Sends a Telegram message to specified chat_id (or Jordan by default). Garvis uses this for notifications.\n\n**get_status** \u2014 Returns n8n system status: operational state, active workflow count, uptime, version.\n\n**TODO:**\n- [ ] Add CONTENT_PIPELINE_ID env var after deploying content pipeline\n- [ ] Add N8N_API_KEY env var for internal API calls\n- [ ] Add TELEGRAM_BOT_TOKEN and JORDAN_CHAT_ID env vars\n- [ ] Consider adding: restart_vm, run_backup, deploy_update actions", "width": 560, "height": 480}, "id": "b2c3d4e5-2222-4000-8000-000000000013", "name": "Sticky - Action Handlers", "type": "n8n-nodes-base.stickyNote", "typeVersion": 1, "position": [600, -260]}], "connections": {"Webhook": {"main": [[{"node": "IF Auth Valid?", "type": "main", "index": 0}]]}, "IF Auth Valid?": {"main": [[{"node": "Switch Action", "type": "main", "index": 0}], [{"node": "Respond 401", "type": "main", "index": 0}]]}, "Switch Action": {"main": [[{"node": "Trigger Content Pipeline", "type": "main", "index": 0}], [{"node": "Check NAS Files", "type": "main", "index": 0}], [{"node": "Check Services Health", "type": "main", "index": 0}], [{"node": "Send Telegram Message", "type": "main", "index": 0}], [{"node": "Get System Status", "type": "main", "index": 0}]]}, "Trigger Content Pipeline": {"main": [[{"node": "Respond 200 Success", "type": "main", "index": 0}]]}, "Check NAS Files": {"main": [[{"node": "Respond 200 Success", "type": "main", "index": 0}]]}, "Check Services Health": {"main": [[{"node": "Respond 200 Success", "type": "main", "index": 0}]]}, "Send Telegram Message": {"main": [[{"node": "Respond 200 Success", "type": "main", "index": 0}]]}, "Get System Status": {"main": [[{"node": "Respond 200 Success", "type": "main", "index": 0}]]}}, "settings": {"executionOrder": "v1"}} |