mirror of
https://github.com/pewdiepie-archdaemon/odysseus.git
synced 2026-06-16 01:35:36 -04:00
feat(reminders): add generic webhook as a fourth reminder channel (#2952)
Replaces any Discord-specific reminder channel with a generic outbound
webhook channel. Users pick any saved Integration as the target and
supply a JSON payload template with {{title}} and {{message}}
placeholders — values are JSON-escaped before substitution. Works with
Discord, Slack, Teams, ntfy (JSON mode), or any service that accepts a
POST with a JSON body.
- `src/settings.py` — reminder_webhook_integration_id +
reminder_webhook_payload_template defaults
- `routes/note_routes.py` — webhook delivery block; Integration lookup,
template rendering, auth wiring; built-in preset defaults so
discord_webhook works out of the box without a configured template;
settings_override kwarg avoids test-button race condition
- `routes/auth_routes.py` — discord_webhook preset test handler
- `src/integrations.py` — discord_webhook preset with description +
example templates; hides auth/key fields in the Integration form
- `src/builtin_actions.py` — webhook_sent delivery check
- `src/tool_implementations.py` — webhook aliases + enum updated
- `static/index.html` — Webhook channel option; Integration picker +
payload template textarea
- `static/js/settings.js` — Integration list, populateWebhookIntegrations,
syncChannelRows, hints, load/save, auto-fill preset templates,
test-button override payload, hide auth/key for URL-auth presets
Co-authored-by: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -1902,6 +1902,8 @@ async def action_check_email_urgency(owner: str, **kwargs) -> Tuple[str, bool]:
|
||||
delivered = bool(dispatch_result.get("email_sent"))
|
||||
elif channel == "ntfy":
|
||||
delivered = bool(dispatch_result.get("ntfy_sent"))
|
||||
elif channel == "webhook":
|
||||
delivered = bool(dispatch_result.get("webhook_sent"))
|
||||
if delivered:
|
||||
newly_notified.update(new_urgent)
|
||||
else:
|
||||
|
||||
@@ -100,6 +100,19 @@ INTEGRATION_PRESETS: Dict[str, Dict[str, Any]] = {
|
||||
" GET /{topic}/json?poll=1 — poll for messages"
|
||||
),
|
||||
},
|
||||
"discord_webhook": {
|
||||
"name": "Discord Webhook",
|
||||
"auth_type": "none",
|
||||
"description": (
|
||||
"Discord Incoming Webhook. Paste the full webhook URL (including the token) as the Base URL.\n"
|
||||
"To get a URL: Discord server -> Server Settings -> Integrations -> Webhooks -> New Webhook -> Copy Webhook URL.\n"
|
||||
"The secret is embedded in the URL — leave auth type as None.\n\n"
|
||||
"Use this integration as the target in Settings -> Reminders -> Webhook channel.\n"
|
||||
"Payload template examples:\n"
|
||||
" Simple: {\"content\": \"{{title}}: {{message}}\"}\n"
|
||||
" Embed: {\"embeds\": [{\"title\": \"{{title}}\", \"description\": \"{{message}}\", \"color\": 5793266}]}"
|
||||
),
|
||||
},
|
||||
"vaultwarden": {
|
||||
"name": "Vaultwarden",
|
||||
"auth_type": "header",
|
||||
|
||||
+8
-1
@@ -141,10 +141,17 @@ DEFAULT_SETTINGS = {
|
||||
# library can grow beyond this; cleanup/retirement is an explicit review flow.
|
||||
"skill_max_injected": 3,
|
||||
# Reminders
|
||||
"reminder_channel": "browser", # "browser" | "email" | "ntfy"
|
||||
"reminder_channel": "browser", # "browser" | "email" | "ntfy" | "webhook"
|
||||
"reminder_llm_synthesis": False,
|
||||
"reminder_ntfy_topic": "Reminders",
|
||||
"reminder_email_to": "",
|
||||
# Generic outbound webhook channel: pick any saved Integration as the
|
||||
# target and supply a JSON payload template. Use {{title}} and {{message}}
|
||||
# as placeholders — they are JSON-escaped before substitution, so the
|
||||
# rendered string is always valid JSON. Works with Discord, Slack, Teams,
|
||||
# ntfy (JSON mode), or any service that accepts a POST with a JSON body.
|
||||
"reminder_webhook_integration_id": "",
|
||||
"reminder_webhook_payload_template": "",
|
||||
# Email triage scanner rules. Running/paused state and schedule live in
|
||||
# Tasks via the built-in `check_email_urgency` task.
|
||||
"urgent_email_prompt": (
|
||||
|
||||
@@ -1566,6 +1566,8 @@ async def do_manage_settings(content: str, owner: Optional[str] = None) -> Dict:
|
||||
"image gen": "image_gen_enabled", "image generation": "image_gen_enabled",
|
||||
"reminder channel": "reminder_channel", "reminders": "reminder_channel",
|
||||
"ntfy topic": "reminder_ntfy_topic",
|
||||
"webhook integration": "reminder_webhook_integration_id",
|
||||
"webhook template": "reminder_webhook_payload_template", "webhook payload": "reminder_webhook_payload_template",
|
||||
"agent tool calls": "agent_max_tool_calls", "max tool calls": "agent_max_tool_calls",
|
||||
"agent timeout": "agent_stream_timeout_seconds", "stream timeout": "agent_stream_timeout_seconds",
|
||||
"token budget": "agent_input_token_budget", "input budget": "agent_input_token_budget",
|
||||
@@ -1581,7 +1583,7 @@ async def do_manage_settings(content: str, owner: Optional[str] = None) -> Dict:
|
||||
|
||||
_ENUMS = {
|
||||
"image_quality": ["low", "medium", "high"],
|
||||
"reminder_channel": ["browser", "email", "ntfy"],
|
||||
"reminder_channel": ["browser", "email", "ntfy", "webhook"],
|
||||
}
|
||||
def _coerce(value, default):
|
||||
if isinstance(default, bool):
|
||||
|
||||
Reference in New Issue
Block a user