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
This commit is contained in:
79
fix_hooks.py
Normal file
79
fix_hooks.py
Normal file
@@ -0,0 +1,79 @@
|
||||
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")
|
||||
Reference in New Issue
Block a user