Refactor BearClaw and Telegram integration for improved message handling and lifecycle callbacks

This commit is contained in:
Carlo Costanzo
2026-04-16 14:05:15 -04:00
parent 38926271f9
commit 5e995604ea
5 changed files with 114 additions and 308 deletions

View File

@@ -55,7 +55,7 @@ Live collection of plug-and-play Home Assistant packages. Each YAML file in this
| [mariadb.yaml](mariadb.yaml) | MariaDB recorder health and capacity SQL sensors. | `sensor.mariadb_status`, `sensor.database_size` |
| [tugtainer_updates.yaml](tugtainer_updates.yaml) | Tugtainer container update notifications via webhook + persistent alerts, plus event-based Joanna dispatch when reports include `### Available:` (24h cooldown via `mode: single` + delay, no new helpers). | `persistent_notification.create`, `event: tugtainer_available_detected`, `script.joanna_dispatch`, `input_datetime.tugtainer_last_update` |
| [bearclaw.yaml](bearclaw.yaml) | Joanna/BearClaw bridge automations that forward Telegram commands to codex_appliance, include LLM-first routing context for freeform text, relay replies back, ingest `/api/bearclaw/status` telemetry, and expose dispatch plus QMD/memory-index sensors for Infrastructure dashboards. | `rest_command.bearclaw_*`, `sensor.bearclaw_status_telemetry`, `sensor.joanna_*`, `binary_sensor.joanna_*`, `automation.bearclaw_*`, `script.send_to_logbook` |
| [telegram_bot.yaml](telegram_bot.yaml) | Telegram transport package for BearClaw and other ops flows; the shared `joanna_send_telegram` helper now lives under `config/script/`. | `telegram_bot.send_message`, `script.joanna_send_telegram` |
| [telegram_bot.yaml](telegram_bot.yaml) | Legacy Telegram transport marker for BearClaw; the shared `joanna_send_telegram` helper now forwards through the codex_appliance direct Telegram API. | `rest_command.bearclaw_telegram_send`, `script.joanna_send_telegram` |
| [phynplus.yaml](phynplus.yaml) | Phyn shutoff automations with push + Activity feed + Repairs issues for leak events. | `valve.phyn_shutoff_valve`, `binary_sensor.phyn_leak_test_running`, `repairs.create` |
| [water_delivery.yaml](water_delivery.yaml) | ReadyRefresh delivery date helper with night-before + garage door Alexa reminders, plus helper-change audit logging and Telegram confirmations. | `input_datetime.water_delivery_date`, `script.send_to_logbook`, `script.joanna_send_telegram`, `notify.alexa_media_garage` |
| [vacation_mode.yaml](vacation_mode.yaml) | Auto-enable vacation mode after 24 hours away or no bed use, track sitter analytics/secure-house checks, and deliver Chromecast-first vacation briefings with a garage Alexa welcome. | `input_boolean.vacation_mode`, `input_boolean.house_sitter_present`, `sensor.vacation_house_sitter_*`, `group.garage_doors`, `lock.front_door`, `script.notify_engine`, `script.joanna_send_telegram` |

View File

@@ -3,20 +3,17 @@
# For more info visit https://www.vcloudinfo.com/click-here
# Original Repo : https://github.com/CCOSTAN/Home-AssistantConfig
# -------------------------------------------------------------------
# BearClaw Bridge - Telegram and webhook glue for Joanna agent
# Routes Telegram -> codex_appliance and codex_appliance -> Telegram/HA.
# BearClaw Integration - Home Assistant dispatch + lifecycle callbacks
# Home Assistant dispatches jobs to codex_appliance and receives structured lifecycle callbacks.
# -------------------------------------------------------------------
# Notes: Keep BearClaw transport + bridge logic centralized in this package.
# Notes: Telegram ingress now lives directly in docker_17/codex_appliance.
# Notes: Most BearClaw decision logic runs in docker_17/codex_appliance (server.js).
# Notes: GitHub capture behavior (issue creation/labels/research flow) belongs in codex_appliance, not HA YAML.
# Notes: Shared script helper `script.joanna_dispatch` lives in config/script/joanna_dispatch.yaml.
# Notes: Telegram inline button callbacks are handled here and mapped to BearClaw commands.
# Notes: Inbound Telegram handling enforces user_id + chat_id allowlists from secrets CSV values.
# Notes: Reply webhook writes JOANNA activity entries to logbook for traceability.
# Notes: Non-urgent autonomous Joanna Telegram replies are suppressed during quiet hours (23:00-08:00) unless the appliance marks `quiet_hours_bypass`; urgent levels and Telegram-initiated conversations still deliver immediately.
# Notes: The callback webhook writes JOANNA activity entries to logbook for traceability and optional HA alerts.
# Notes: Status telemetry polling expects !secret bearclaw_status_url (token header stays !secret bearclaw_token).
# Notes: Nightly Duplicati verification calls a codex_appliance admin endpoint and returns structured health to HA via response_variable.
# Notes: Telegram freeform input now includes LLM-first routing context to improve intent understanding before entity lookups.
# Notes: v2 intake is the primary HA contract; legacy command/ingest routes remain appliance-side shims.
# Notes: Command payload supports async_only for automation-first queueing when immediate inline handling is not required.
# Notes: Blog: https://www.vcloudinfo.com/2026/03/joanna-dispatch-telemetry-home-assistant-infrastructure-dashboard/
######################################################################
@@ -31,11 +28,28 @@ rest_command:
x-codex-token: !secret bearclaw_token
payload: >
{
"text": {{ text | tojson }},
"user": {{ user | default('carlo') | tojson }},
"kind": "command",
"transport": "ha",
"source": {{ source | default('home_assistant') | tojson }},
"context": {{ context | default(none) | tojson }},
"callback": {{ callback | default(none) | tojson }},
"actor": {
"id": {{ user | default('carlo') | tojson }}
},
"conversation": {
"id": {{ source | default('home_assistant') | tojson }},
"type": "automation"
},
"input": {
"text": {{ text | tojson }},
"context": {{ context | default(none) | tojson }},
"callback": {{ callback | default(none) | tojson }}
},
"replyTargets": [
{
"type": "ha",
"callbackEventType": "lifecycle"
}
],
"priority": {{ priority | default(none) | tojson }},
"async_only": {{ async_only | default(false) | tojson }}
}
@@ -47,9 +61,26 @@ rest_command:
x-codex-token: !secret bearclaw_token
payload: >
{
"summary": {{ summary | default('event') | tojson }},
"wake": {{ wake | default(false) | tojson }},
"source": "home_assistant"
"kind": "event",
"transport": "ha",
"source": "homeassistant",
"actor": {
"id": "system"
},
"conversation": {
"id": "homeassistant",
"type": "automation"
},
"input": {
"text": {{ summary | default('event') | tojson }},
"event": {
"summary": {{ summary | default('event') | tojson }},
"wake": {{ wake | default(false) | tojson }},
"priority": {{ priority | default(none) | tojson }},
"source": "homeassistant"
}
},
"replyTargets": []
}
bearclaw_duplicati_verify:
@@ -63,6 +94,22 @@ rest_command:
{
"reason": {{ reason | default('home_assistant') | tojson }}
}
bearclaw_telegram_send:
url: !secret bearclaw_telegram_send_url
method: post
timeout: 30
content_type: application/json
headers:
x-codex-token: !secret bearclaw_token
payload: >
{
"message": {{ message | tojson }},
"parse_mode": {{ parse_mode | default('plain_text') | tojson }},
"disable_web_page_preview": {{ disable_web_page_preview | default(true) | tojson }},
"chat_id": {{ chat_id | default(none) | tojson }},
"user": {{ user | default('carlo') | tojson }}
}
sensor:
- platform: rest
name: BearClaw Status Telemetry
@@ -78,6 +125,8 @@ sensor:
- dispatchStats
- queue
- active
- platform
- transports
- qmdHealth
- memoryIndex
@@ -264,224 +313,9 @@ template:
{% set memory = state_attr('sensor.bearclaw_status_telemetry', 'memoryIndex') | default({}, true) %}
{{ memory.get('stale', false) in [true, 'true', 'True', 'on', 'yes', 1, '1'] }}
automation:
- id: bearclaw_telegram_bear_command
alias: BearClaw Telegram Bear Command
description: Handles /bear commands and forwards text to Joanna.
mode: queued
trigger:
- platform: event
event_type: telegram_command
event_data:
command: /bear
variables:
allowed_user_ids_csv: !secret bearclaw_allowed_telegram_user_ids
allowed_chat_ids_csv: !secret bearclaw_allowed_telegram_chat_ids
condition:
- condition: template
value_template: >-
{% set has_user = trigger.event.data.user_id is defined %}
{% set has_chat = trigger.event.data.chat_id is defined %}
{% set allowed_users = (allowed_user_ids_csv | default('', true) | string).split(',') | map('trim') | reject('equalto', '') | list %}
{% set allowed_chats = (allowed_chat_ids_csv | default('', true) | string).split(',') | map('trim') | reject('equalto', '') | list %}
{% set incoming_user = trigger.event.data.user_id | default('') | string | trim %}
{% set incoming_chat = trigger.event.data.chat_id | default('') | string | trim %}
{{ has_user and has_chat and allowed_users | count > 0 and allowed_chats | count > 0 and incoming_user in allowed_users and incoming_chat in allowed_chats }}
action:
- variables:
command_text: "{{ (trigger.event.data.args | default([])) | join(' ') | trim }}"
from_user: "{{ (trigger.event.data.from_first | default('carlo')) | lower }}"
- choose:
- conditions:
- condition: template
value_template: "{{ command_text == '' }}"
sequence:
- service: telegram_bot.send_message
data:
chat_id: !secret telegram_allowed_chat_id_carlo
message: "Choose a BearClaw action or send /bear <message>."
parse_mode: plain_text
disable_web_page_preview: true
inline_keyboard:
- "Status:/bear_status, Add to GitHub:/bear_github_help"
default:
- service: rest_command.bearclaw_command
data:
text: "{{ command_text }}"
user: "{{ from_user }}"
source: telegram_command
- id: bearclaw_telegram_callback_actions
alias: BearClaw Telegram Callback Actions
description: Handles BearClaw Telegram inline button callbacks.
mode: queued
trigger:
- platform: event
event_type: telegram_callback
variables:
allowed_user_ids_csv: !secret bearclaw_allowed_telegram_user_ids
allowed_chat_ids_csv: !secret bearclaw_allowed_telegram_chat_ids
condition:
- condition: template
value_template: >-
{% set has_user = trigger.event.data.user_id is defined %}
{% set has_chat = trigger.event.data.chat_id is defined %}
{% set allowed_users = (allowed_user_ids_csv | default('', true) | string).split(',') | map('trim') | reject('equalto', '') | list %}
{% set allowed_chats = (allowed_chat_ids_csv | default('', true) | string).split(',') | map('trim') | reject('equalto', '') | list %}
{% set incoming_user = trigger.event.data.user_id | default('') | string | trim %}
{% set incoming_chat = trigger.event.data.chat_id | default('') | string | trim %}
{% set cb = trigger.event.data.data | default('') %}
{{ has_user and has_chat and allowed_users | count > 0 and allowed_chats | count > 0 and incoming_user in allowed_users and incoming_chat in allowed_chats and (cb.startswith('/bear_') or cb.startswith('/bc_')) }}
action:
- variables:
callback_id: "{{ trigger.event.data.id | default('') }}"
callback_data: "{{ trigger.event.data.data | default('') | trim }}"
from_user: "{{ (trigger.event.data.from_first | default('carlo')) | lower }}"
callback_payload: "{{ callback_data[6:] if callback_data.startswith('/bear_') else '' }}"
callback_parts: "{{ callback_payload.split('_') if callback_payload | length > 0 else [] }}"
action_name: "{{ callback_parts[0] if callback_parts | count > 0 else '' }}"
job_id: "{{ callback_parts[1:] | join('_') if callback_parts | count > 1 else '' }}"
- service: telegram_bot.answer_callback_query
continue_on_error: true
data:
callback_query_id: "{{ callback_id }}"
message: "Processing..."
show_alert: false
- choose:
- conditions:
- condition: template
value_template: "{{ callback_data.startswith('/bc_') }}"
sequence:
- service: rest_command.bearclaw_command
data:
text: ""
user: "{{ from_user }}"
source: telegram_callback
callback:
token: "{{ callback_data[4:] }}"
raw: "{{ callback_data }}"
chat_id: "{{ trigger.event.data.chat_id | default('') }}"
callback_id: "{{ callback_id }}"
message_id: "{{ trigger.event.data.message.message_id if trigger.event.data.message is defined and trigger.event.data.message.message_id is defined else '' }}"
- conditions:
- condition: template
value_template: "{{ action_name == 'status' }}"
sequence:
- service: rest_command.bearclaw_command
data:
text: "{{ 'status ' ~ job_id if job_id | length > 0 else 'status' }}"
user: "{{ from_user }}"
source: telegram_callback
- conditions:
- condition: template
value_template: "{{ action_name == 'cancel' and job_id | length > 0 }}"
sequence:
- service: rest_command.bearclaw_command
data:
text: "{{ 'cancel ' ~ job_id }}"
user: "{{ from_user }}"
source: telegram_callback
- conditions:
- condition: template
value_template: "{{ action_name == 'github_help' }}"
sequence:
- service: script.joanna_send_telegram
data:
message: >-
To create a GitHub capture, send:
add to github <short topic>
Example: add to github Evaluate Smart Home Planner HACS app
- conditions:
- condition: template
value_template: "{{ action_name == 'yes' }}"
sequence:
- service: rest_command.bearclaw_command
data:
text: "{{ 'yes ' ~ job_id if job_id | length > 0 else 'Yes.' }}"
user: "{{ from_user }}"
source: telegram_callback
- conditions:
- condition: template
value_template: "{{ action_name == 'no' }}"
sequence:
- service: rest_command.bearclaw_command
data:
text: "{{ 'no ' ~ job_id if job_id | length > 0 else 'No.' }}"
user: "{{ from_user }}"
source: telegram_callback
default:
- service: script.joanna_send_telegram
data:
message: "Unknown BearClaw button action. Try /bear to open the menu."
- choose:
- conditions:
- condition: template
value_template: "{{ trigger.event.data.message is defined and trigger.event.data.message.message_id is defined }}"
sequence:
- service: telegram_bot.edit_replymarkup
continue_on_error: true
data:
chat_id: "{{ trigger.event.data.chat_id }}"
message_id: "{{ trigger.event.data.message.message_id }}"
inline_keyboard: []
- id: bearclaw_telegram_text_no_slash_needed
alias: BearClaw Telegram Text No Slash Needed
description: Treats plain Telegram text as BearClaw command input and forwards LLM-first routing context.
mode: queued
trigger:
- platform: event
event_type: telegram_text
variables:
allowed_user_ids_csv: !secret bearclaw_allowed_telegram_user_ids
allowed_chat_ids_csv: !secret bearclaw_allowed_telegram_chat_ids
condition:
- condition: template
value_template: >-
{% set has_user = trigger.event.data.user_id is defined %}
{% set has_chat = trigger.event.data.chat_id is defined %}
{% set allowed_users = (allowed_user_ids_csv | default('', true) | string).split(',') | map('trim') | reject('equalto', '') | list %}
{% set allowed_chats = (allowed_chat_ids_csv | default('', true) | string).split(',') | map('trim') | reject('equalto', '') | list %}
{% set incoming_user = trigger.event.data.user_id | default('') | string | trim %}
{% set incoming_chat = trigger.event.data.chat_id | default('') | string | trim %}
{% set plain_text = trigger.event.data.text | default('') | trim %}
{{ has_user and has_chat and allowed_users | count > 0 and allowed_chats | count > 0 and incoming_user in allowed_users and incoming_chat in allowed_chats and plain_text != '' and not plain_text.startswith('/') }}
action:
- variables:
plain_text: "{{ trigger.event.data.text | default('') | trim }}"
plain_text_lower: "{{ plain_text | lower }}"
from_user: "{{ (trigger.event.data.from_first | default('carlo')) | lower }}"
command_like_request: >-
{% set action_verbs = ['disable', 'enable', 'turn off', 'turn on', 'stop', 'start', 'restart', 'review', 'fix', 'change', 'update', 'set', 'open', 'close'] %}
{{ action_verbs | select('in', plain_text_lower) | list | count > 0 }}
status_like_request: >-
{{ (plain_text_lower.startswith('is ')
or plain_text_lower.startswith('are ')
or plain_text_lower.startswith('what is ')
or plain_text_lower.startswith("what's ")
or ' status' in plain_text_lower
or plain_text_lower.startswith('status '))
and not command_like_request }}
llm_route_hint: >-
{% if command_like_request %}
llm_first_action
{% elif status_like_request %}
llm_first_status
{% else %}
llm_first_general
{% endif %}
llm_context: >-
telegram_freeform route={{ llm_route_hint | trim }}.
Prefer LLM intent interpretation and clarification for action or automation requests before returning entity status.
- service: rest_command.bearclaw_command
data:
text: "{{ plain_text }}"
user: "{{ from_user }}"
source: telegram_text
context: "{{ llm_context | trim }}"
- id: bearclaw_reply_webhook
alias: BearClaw Reply Webhook
description: Receives BearClaw replies from codex_appliance and relays to Telegram/HA push.
- id: bearclaw_lifecycle_webhook
alias: BearClaw Lifecycle Webhook
description: Receives structured BearClaw lifecycle callbacks for HA-triggered work.
mode: queued
trigger:
- platform: webhook
@@ -491,77 +325,39 @@ automation:
local_only: true
action:
- variables:
message: "{{ trigger.json.message | default('Joanna: empty reply') }}"
telegram_message: "{{ trigger.json.telegram_message | default(message, true) }}"
telegram_parse_mode: >-
{% set raw = trigger.json.telegram_parse_mode | default('plain_text', true) | string | lower | trim %}
{% if raw in ['html', 'plain_text'] %}
{{ raw }}
{% else %}
plain_text
{% endif %}
telegram_disable_preview: "{{ trigger.json.disable_web_page_preview | default(true, true) }}"
level: "{{ trigger.json.level | default('active') | lower }}"
reply_source: "{{ trigger.json.source | default('', true) | string | lower | trim }}"
quiet_hours_bypass: >-
{{ trigger.json.quiet_hours_bypass | default(false, true) in [true, 'true', 'True', 'on', 'yes', 1, '1'] }}
quiet_hours_active: >-
{% set now_time = now().strftime('%H:%M:%S') %}
{{ now_time >= '23:00:00' or now_time < '08:00:00' }}
should_send_telegram: >-
{% set user_initiated = reply_source in ['telegram_command', 'telegram_callback', 'telegram_text'] %}
{% set urgent = level in ['warning', 'error', 'critical'] %}
{% set quiet = quiet_hours_active in [true, 'true', 'True', 'on', 'yes', 1, '1'] %}
{{ quiet_hours_bypass or user_initiated or urgent or not quiet }}
inline_keyboard_payload: >-
{% set kb = trigger.json.inline_keyboard if trigger.json.inline_keyboard is defined else none %}
{% if kb is string %}
{{ kb | trim }}
{% elif kb is sequence and kb is not string and (kb | count) > 0 %}
{{ kb | map('string') | map('trim') | reject('equalto', '') | list | join('\n') }}
{% else %}
{{ '' }}
{% endif %}
event_type: "{{ trigger.json.event_type | default('progress') | lower }}"
status: "{{ trigger.json.status | default(event_type, true) | lower }}"
source: "{{ trigger.json.source | default('homeassistant', true) | string | lower | trim }}"
severity: "{{ trigger.json.severity | default('active', true) | string | lower | trim }}"
summary: "{{ trigger.json.summary | default('Joanna lifecycle callback', true) }}"
message: "{{ trigger.json.message | default(summary, true) }}"
job_id: "{{ trigger.json.job_id | default('', true) }}"
run_id: "{{ trigger.json.run_id | default('', true) }}"
logbook_message: >-
{% set compact = message | replace('\r', ' ') | replace('\n', ' ') | trim %}
{% set compact = (event_type ~ ' | ' ~ summary ~ ' | ' ~ message) | replace('\r', ' ') | replace('\n', ' ') | trim %}
{% if compact | length > 240 %}
{{ compact[:237] ~ '...' }}
{% else %}
{{ compact }}
{% endif %}
- choose:
- conditions:
- condition: template
value_template: "{{ should_send_telegram }}"
- condition: template
value_template: "{{ inline_keyboard_payload | length > 0 }}"
sequence:
- service: telegram_bot.send_message
data:
chat_id: !secret telegram_allowed_chat_id_carlo
message: "{{ telegram_message }}"
parse_mode: "{{ telegram_parse_mode }}"
disable_web_page_preview: "{{ telegram_disable_preview }}"
inline_keyboard: "{{ inline_keyboard_payload }}"
- conditions:
- condition: template
value_template: "{{ should_send_telegram }}"
sequence:
- service: script.joanna_send_telegram
data:
message: "{{ telegram_message }}"
parse_mode: "{{ telegram_parse_mode }}"
disable_web_page_preview: "{{ telegram_disable_preview }}"
- service: script.send_to_logbook
data:
topic: JOANNA
message: "{{ level | upper }}: {{ logbook_message }}"
message: "{{ status | upper }}: {{ logbook_message }}"
- choose:
- conditions:
- condition: template
value_template: "{{ level in ['warning', 'error', 'critical'] }}"
value_template: "{{ severity in ['warning', 'error', 'critical'] or status in ['failed', 'canceled'] }}"
sequence:
- service: script.notify_engine
data:
title: Joanna Alert
value1: "{{ message }}"
value1: >-
{{ summary }}
{% if job_id | trim != '' %}
(job={{ job_id }})
{% endif %}
{% if run_id | trim != '' %}
run={{ run_id }}
{% endif %}
{{ '\n' ~ message if message | trim != '' else '' }}

View File

@@ -3,14 +3,13 @@
# For more info visit https://www.vcloudinfo.com/click-here
# Original Repo : https://github.com/CCOSTAN/Home-AssistantConfig
# -------------------------------------------------------------------
# Telegram Bot Helpers - Joanna/BearClaw Telegram send wrappers
# Script wrappers for Telegram messaging using UI-configured integration.
# Telegram Bot Helpers - Legacy Joanna/BearClaw Telegram placeholder
# BearClaw owns Telegram transport directly; this package remains as a documentation marker only.
# -------------------------------------------------------------------
# Notes: Do not add `telegram_bot:` YAML here; integration is UI-only.
# Notes: Do not add `telegram_bot:` YAML here.
# Notes: Shared helper `script.joanna_send_telegram` lives in config/script/joanna_send_telegram.yaml.
# Notes: Joanna transport defaults to plain_text, but can opt into HTML when the appliance provides a vetted rich message.
# Notes: Keep Skills logic in docker_17/codex_appliance; this package is delivery/transport only.
# Notes: HA Core 2026.4 webhook support is optional; service-call wrappers remain compatible with polling or webhook transport.
# Notes: Keep Skills logic in docker_17/codex_appliance; HA no longer owns Telegram polling for BearClaw.
######################################################################
{}

View File

@@ -4,11 +4,12 @@
# Original Repo : https://github.com/CCOSTAN/Home-AssistantConfig
# -------------------------------------------------------------------
# Joanna Dispatch - Shared BearClaw dispatch helper for automations
# Normalizes remediation context and forwards requests via bearclaw_command.
# Normalizes remediation context and forwards requests via BearClaw v2 intake.
# -------------------------------------------------------------------
# Notes: Keep this helper generic so package automations can reuse one schema.
# Notes: Source defaults to home_assistant_automation.unknown when omitted.
# Notes: Automation dispatches are async_only by default so HA calls return quickly while BearClaw works in queue.
# Notes: HA is a dispatcher/integration here; Telegram transport ownership lives in docker_17/codex_appliance.
######################################################################
joanna_dispatch:

View File

@@ -4,15 +4,16 @@
# Original Repo : https://github.com/CCOSTAN/Home-AssistantConfig
# -------------------------------------------------------------------
# Joanna Send Telegram - Shared Telegram delivery helper
# Chunks long messages, sends Telegram replies, and falls back to plain text when needed.
# Chunks long messages and sends them through BearClaw's direct Telegram transport.
# -------------------------------------------------------------------
# Notes: Shared helper moved out of packages so cross-file callers resolve from config/script.
# Notes: Keep Joanna/BearClaw decision logic in docker_17/codex_appliance; this script only delivers messages.
# Notes: Primary BearClaw Telegram ingress/delivery now lives directly in docker_17/codex_appliance.
# Notes: Keep Joanna/BearClaw decision logic in docker_17/codex_appliance; this script is HA-side delivery fallback only.
######################################################################
joanna_send_telegram:
alias: Joanna Send Telegram
description: Sends resilient Telegram messages with chunking and plain-text fallback.
description: Sends resilient Telegram messages through BearClaw with chunking and plain-text fallback.
mode: queued
fields:
message:
@@ -24,6 +25,12 @@ joanna_send_telegram:
disable_web_page_preview:
description: Whether Telegram should suppress web page previews.
example: true
chat_id:
description: Optional Telegram chat override. Leave empty to use BearClaw defaults.
example: "7976075034"
user:
description: Optional BearClaw user hint for target resolution.
example: carlo
sequence:
- variables:
chunk_size: 3400
@@ -35,6 +42,8 @@ joanna_send_telegram:
plain_text
{% endif %}
preview_disabled: "{{ disable_web_page_preview | default(true, true) }}"
target_chat_id: "{{ chat_id | default('', true) | string | trim }}"
target_user: "{{ user | default('carlo', true) | string | trim }}"
normalized_message: >-
{% set raw = message | default('', true) | string %}
{{ raw | replace('\r\n', '\n') | replace('\r', '\n') | trim }}
@@ -67,26 +76,27 @@ joanna_send_telegram:
| regex_replace(find='[\x00-\x08\x0B\x0C\x0E-\x1F]', replace=' ')
| trim }}
telegram_send_response: null
- service: telegram_bot.send_message
- service: rest_command.bearclaw_telegram_send
continue_on_error: true
data:
chat_id: !secret telegram_allowed_chat_id_carlo
message: "{{ chunk_message }}"
parse_mode: "{{ requested_parse_mode }}"
disable_web_page_preview: "{{ preview_disabled }}"
chat_id: "{{ target_chat_id }}"
user: "{{ target_user }}"
response_variable: telegram_send_response
- choose:
- conditions:
- condition: template
value_template: >-
{{ telegram_send_response is none
or telegram_send_response.chats is not defined
or (telegram_send_response.chats | count) == 0 }}
{% set status = telegram_send_response.status | default(0, true) | int(0) %}
{{ status == 0 or status >= 300 }}
sequence:
- service: telegram_bot.send_message
- service: rest_command.bearclaw_telegram_send
continue_on_error: true
data:
chat_id: !secret telegram_allowed_chat_id_carlo
message: "{{ fallback_message if fallback_message | length > 0 else 'Joanna: message delivery fallback (content omitted)' }}"
parse_mode: plain_text
disable_web_page_preview: "{{ preview_disabled }}"
chat_id: "{{ target_chat_id }}"
user: "{{ target_user }}"