Files
ajarbot/fix_hooks.py

80 lines
4.9 KiB
Python
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
import json
with open('C:/Users/fam1n/projects/ajarbot/bfk_workflow.json', 'r', encoding='utf-8') as f:
wf = json.load(f)
for node in wf['nodes']:
if node['name'] == 'AI Generate Hooks':
# Fix: Use JSON.stringify() to properly escape the transcript text
# so special characters (quotes, newlines) don't break the JSON body.
# .slice(1,-1) removes the outer quotes that JSON.stringify adds.
new_body = '={{ JSON.stringify({\n' \
' "contents": [{\n' \
' "parts": [{\n' \
' "text": "You are a TikTok content expert for a blended family cooking channel called BlendedFamilyKitchen. Given this transcript from a cooking video, generate:\\n1) Three hook text options (max 8 words each, attention-grabbing, food-focused)\\n2) A caption/description with relevant hashtags (mix of popular and niche)\\n3) Three title options\\n\\nFormat your response as JSON with keys: hooks (array of 3 strings), caption (string), titles (array of 3 strings).\\n\\nTranscript: " + ($("Whisper Transcribe").item.json.data || $("Whisper Transcribe").item.json.text || "No transcript available")\n' \
' }]\n' \
' }],\n' \
' "generationConfig": {\n' \
' "temperature": 0.8,\n' \
' "maxOutputTokens": 500,\n' \
' "responseMimeType": "application/json"\n' \
' }\n' \
'}) }}'
node['parameters']['jsonBody'] = new_body
# Also need to change contentType to 'raw' and set rawContentType
# Actually the better approach: set specifyBody to 'string' mode
# But simplest: use the expression-based JSON approach with JSON.stringify
# wrapping the whole object so n8n sends it as a properly escaped JSON string
# Actually, the cleanest n8n fix: keep specifyBody as "json" but use
# the expression wrapper approach
node['parameters']['specifyBody'] = 'string'
node['parameters']['body'] = new_body
del node['parameters']['jsonBody']
# Hmm, let me reconsider. The "json" mode with jsonBody expects valid JSON.
# The issue is the expression injects raw text. JSON.stringify wrapping the
# whole thing as an expression should work.
# Actually simplest: keep specifyBody=json, but wrap entire object in JSON.stringify
# n8n will parse the expression result. If expression returns a string (from JSON.stringify),
# n8n's json mode should send it as-is.
#
# But wait - the error says "JSON parameter needs to be valid JSON"
# This means n8n validates the jsonBody template BEFORE expression evaluation.
# The raw transcript chars break the JSON template structure.
#
# Real fix: use specifyBody = "json" but build the body using n8n's
# built-in JSON key-value pairs, not a raw string. Or use a Code node.
#
# Cleanest approach: Insert a Set node before this one that builds the prompt
# text safely, then reference it. But that changes workflow structure.
#
# Simplest working fix: keep raw JSON mode but use JSON.stringify on the
# transcript portion only, and use proper escaping.
# Let me just do it right:
node['parameters'] = {
"method": "POST",
"url": "=https://generativelanguage.googleapis.com/v1beta/models/gemini-2.5-flash:generateContent?key=AIzaSyDQPi9kXbVpxW790RBuUCeC8t_UgyxX7m4",
"sendHeaders": True,
"headerParameters": {
"parameters": [
{"name": "Content-Type", "value": "application/json"}
]
},
"sendBody": True,
"specifyBody": "json",
"jsonBody": "={{ JSON.stringify({ contents: [{ parts: [{ text: \"You are a TikTok content expert for a blended family cooking channel called BlendedFamilyKitchen. Given this transcript from a cooking video, generate:\\n1) Three hook text options (max 8 words each, attention-grabbing, food-focused)\\n2) A caption/description with relevant hashtags (mix of popular and niche)\\n3) Three title options\\n\\nFormat your response as JSON with keys: hooks (array of 3 strings), caption (string), titles (array of 3 strings).\\n\\nTranscript: \" + String($json.srt_content || $json.text || $('Whisper Transcribe').item.json.data || $('Whisper Transcribe').item.json.text || 'No transcript available') }] }], generationConfig: { temperature: 0.8, maxOutputTokens: 500, responseMimeType: \"application/json\" } }) }}",
"options": {}
}
print("Updated AI Generate Hooks node parameters")
print(f"New jsonBody: {node['parameters']['jsonBody'][:200]}...")
break
with open('C:/Users/fam1n/projects/ajarbot/bfk_workflow_fixed.json', 'w', encoding='utf-8') as f:
json.dump(wf, f)
print("\nSaved fixed workflow to bfk_workflow_fixed.json")