mirror of
https://github.com/CCOSTAN/Home-AssistantConfig.git
synced 2026-05-27 13:09:10 +00:00
Refactor BearClaw and Telegram integration for improved message handling and lifecycle callbacks
This commit is contained in:
@@ -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` |
|
||||
|
||||
@@ -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 '' }}
|
||||
|
||||
@@ -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.
|
||||
######################################################################
|
||||
|
||||
{}
|
||||
|
||||
@@ -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:
|
||||
|
||||
@@ -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 }}"
|
||||
|
||||
Reference in New Issue
Block a user