Files
ajarbot/n8n_workflows/garvis_webhook.json

242 lines
9.7 KiB
JSON
Raw Normal View History

feat: RSO observation system, child safety, Discord adapter, Telegram watchdog, email attachments 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
2026-04-23 07:54:01 -06:00
{
"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": "## 🔐 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": "## 🔀 Action Handlers\n\n**run_pipeline** — Triggers the Content Pipeline workflow via n8n API. Use when Garvis needs to manually kick off video processing.\n\n**check_nas** — Lists files in a NAS directory. Defaults to /BlendedFamilyKitchen/DropZone. Pass custom path in request body.\n\n**check_services** — Pings Proxmox (8006), Loki (3100), and NAS (5000) to verify they're responding. Returns HTTP status codes.\n\n**send_message** — Sends a Telegram message to specified chat_id (or Jordan by default). Garvis uses this for notifications.\n\n**get_status** — 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"
},
"staticData": null,
"tags": [],
"triggerCount": 1,
"active": false
}