feat: configurable AI-bridge trigger word for telegram listener
gates / consistency-and-conventions (push) Successful in 1m50s
gates / consistency-and-conventions (push) Successful in 1m50s
The listener's "ai " bridge prefix was hard-coded. Messages starting with <prefix> + space (case-insensitive, literal match) are now forwarded to Gemini; default stays "ai". - TELEGRAM_AI_PREFIX in telegram.env (default ai), hot-reloaded per message like the command map — no daemon restart needed - New 'prefix' verb: pos communication telegram listener prefix [word] (validated [A-Za-z0-9][A-Za-z0-9_-]*; writes telegram.env chmod 600) - Field added to the telegram # POS_CONFIG: scope (sender header) so 'pos config telegram' edits it too - --status shows the current prefix; usage + POS_SUBCMDS: prefix (completions regenerated) - Matching via scoped nocasematch + quoted-literal =~ prefix; ai_bridge_prefix() precedence: env file > env var > default ai Verified: routing harness (default/custom/case-insensitive/reset/ fallback/unknown-command) green, CLI verb tests, dispatch smoke, pos config render, gates 0 FAIL 0 WARN.
This commit is contained in:
@@ -136,3 +136,4 @@ summary (newest last).
|
||||
- **2026-08-23** — Menu Phase 2 + firewall style-migration (decision "a" activated: P1 landed, `lib/menu-lib.sh` exists). `pos docker vbox` (157→261): 6-item menu hub over the inline case verbs via a quoted self-invocation `menu_self` (verbs never re-enter the menu → no recursion); `enter` hands over the terminal and returns to the loop; rm/create behind VM-naming y/N. `pos network download` (950→1104): 13-item top-verb map onto existing cmd_* fns — add URL (`menu_ask_value`, optional `--tmux`), gid-pick → info/pause/resume/remove/restart (remove names name+gid before delete), typed-confirm purge, watch handover, daemon start/stop (stop confirmed); non-fatal RPC liveness gate (`-m 3`) keeps queue views alive on a dead daemon; deliberately NOT added to INTERACTIVE_CMDS — menu-lib's tty-guarded reads make membership unnecessary and keep tee-logging for all scripted verbs (survey E-002; Reviewer traced the lint pass as honest through `uses_stdin`). `pos system firewall` (308→325) migrated to repo-standard mechanics ONLY: menu heredoc render → stderr `{ … } >&2` (body byte-preserved), all **38** interactive reads → `/dev/tty` via tool-local `tty_read()` (EOF/no-tty → pointer + rc1, never hangs), `prompt_ipver` de-command-substituted so EOF exits gracefully; root gate / per-cmd confirm / typed RESET / pager / notify / every ufw invocation untouched. Both new tools register `# POS_SUBCMDS:` += `menu`; POS.md rows updated; GEN regen'd. Chain: Builder T4 (`reportAgents/2026-08-23-builder-t4-p2-menus-vbox-download.md`; correctly caught an Orchestrator brief error claiming download was in INTERACTIVE_CMDS) + T5 (`-t5-firewall-menu-migration.md`; pty parity captures vs pre-edit baseline) → Reviewer ACCEPT-WITH-NITS over both (`-reviewer-phase2-menu.md`, transcribed by Orchestrator; recursion/injection analysis, 13/13 mapping proof, four T5 intents verified hunk-by-hunk). Verified: bash -n ×3 + gates green after each pass; final trio re-run by Orchestrator post-T5 — `make check` OK · `make lint` 0 FAIL / 0 WARN (76s under box load ~7; the earlier apparent lint hang was shared-box CPU contention, no code issue). Remaining notes for later sessions: errexit kills whole menu when a backing verb hard-fails (repo-wide pattern, all six menus); `confirm()` EOF hits set-u unbound `yn` (pre-existing common.sh); vbox create EOF at dir prompt degrades to default while name/image prompts abort (cosmetic).
|
||||
- **2026-08-26** — `pos ai alias` activation rework (Option B) + `pos config` listing readability, per the 2026-08-26 Architect/Designer specs (`AgentsReport/{architect,designer}/2026-08-26-*.md`). **Alias activation:** the stale sourced-snapshot mechanism is gone — every `pos ai alias` invocation runs `_alias_sync()` (two-way reconciliation: render-diff-install of one executable wrapper per ENV record at `~/.local/bin/<name>` chmod 755 via mktemp+mv with a `bash -n` pre-commit guard; marker-guarded deletion of owned wrappers missing from ENV; legacy `ai-aliases.sh` generation stopped and generator-marker-guarded auto-removal with an `unalias <names>` remediation hint; loud PATH guidance when `~/.local/bin` is off PATH). Edits are live on next invocation with no shell reload (kills the reported stale-gemini-alias bug class); create refuses foreign-file and PATH-binary collisions; `show` gains the wrapper path; `pos-system-uninstall` sweeps the wrappers by their line-2 marker in discovery+removal. Dup-table menu bug fixed with a single `_alias_table` renderer (menu option 4 returns to the loop whose pre-render already shows fresh state). **Config readability** (`lib/config-ui.sh`, fully generic): new optional `# POS_CONFIG:` field types — `@Caption` / `@[KEY=v1|v2] Caption` group captions (condition evaluated per render via `cfg_value`; inactive groups dimmed with a textual reason, never hidden → numbering stable; empty-alt segment = unset-as-default) and `*providers=<tag>` adapter filtering (zero match warns once + suppresses its caption); uniform typography tier for ALL scopes (bold title/keys, CYAN rule, dim numbers/placeholders/examples/captions, hanging-indent wrap clamped 60–120 cols, whole render block → stderr per menu-lib house pattern, honest prompt `Number to edit [r=refresh, q=quit]:`); masking/edit flow byte-compatible, no per-scope branches. `bin/pos-ai` line-6 header adopted to the caption/tag syntax (single-line change). Verified: stub-PATH harness (`HOME=/tmp/…`, `CONFIG_DIR` seam, argv-capturing `pos` shim) covering %q quoting round-trips (quotes/backticks/`$()`/%/unicode), staleness kill-test, orphan retraction, collision-refusal matrix, legacy migration (marker + foreign), PATH-absent warning, non-tty guard, idempotent double-sync; rendered-output diffs vs Designer mockups for `ai` AND old-format `system`; gates `make gen && make check && make lint` 0 FAIL / 0 WARN.
|
||||
- **2026-08-27** — Critical fix: paste injection + multiline paste in `pos ai alias`'s Insert Prompt (root cause: `menu_ask_value` → plain line-oriented `read -rp`; a multi-line Ctrl+V paste floods the tty queue, `read` consumes only line one and the rest execute as commands later or get eaten by the next prompt — user-verified `$(whoami)`/`; ls`/`sudo apt update` behavior). New `menu_read_value()` in `lib/menu-lib.sh` (169→362): raw-mode (`stty -icanon -echo -isig min 1 time 0`) bracketed-paste-aware value reader — `\e[?2004h/l` markers, text inside `[200~…[201~` inserted LITERALLY (embedded newlines/CR are data), Enter submits only outside a paste, Backspace/DEL/Left/Right/Home/End/Delete/Ctrl-U edit, Ctrl-D-on-empty + Ctrl-C/Z/\ cancel (terminal restored first); bytes read chunk-wise via `dd bs=4096|od -tx1|tr` — NOT bash's `read` builtin, which self-interrupts on an ETX byte from a tty even with ISIG disabled (SIGINTs the whole script on Ctrl-C); confirmed `read -erp` (readline) atomically consumes a paste but returns only its first line, so a custom reader was required. `bin/pos-ai-alias` (712→760): `_alias_prompt_encode/_decode` (backslash→`\\`, newline→`\n`; literal `[ = ]` comparisons — bash `case` patterns don't match a single backslash), `_alias_prompt_truncate` newline-safe + max-length arg; load/save encode/decode the prompt field; edit wizard shows a truncated display default but Enter restores the FULL original prompt (fixes pre-existing silent truncation of >80-char prompts), empty-original Enter continues. Verified: pty harnesses (`/tmp/pty_{menulib,cancel,e2e_alias}.py`, `/tmp/roundtrip_test.sh`) — bracketed multiline paste captured verbatim incl. `C:\temp\note`/`$(whoami)`/`; ls`/`echo test`/`sudo apt update`, nothing executed, clean exit; single-line paste; Ctrl-D and Ctrl-C both cancel cleanly (CANCELLED→DONE, terminal restored); full create→list→show→edit E2E with decode round-trip and Enter-keeps-full; `bash -n` ×2, `make gen && make check`, `make lint` 0 FAIL / 0 WARN.
|
||||
- **2026-08-27** — Configurable AI-bridge trigger word for the Telegram listener: the hard-coded `ai ` prefix in `pos-communication-telegram-listener` became `TELEGRAM_AI_PREFIX` (default `ai`) — messages starting with `<prefix> ` (case-insensitive, literal match) are forwarded to Gemini. New `prefix` verb: `pos communication telegram listener prefix` shows the current word, `prefix <word>` sets it (validated `[A-Za-z0-9][A-Za-z0-9_-]*`, writes `TELEGRAM_AI_PREFIX` to `telegram.env` chmod 600); also editable via `pos config telegram` (field added to the sender's `# POS_CONFIG:` telegram scope — registry-driven, no code in config-ui). Matching is per-message hot-reloaded (like the command map — no daemon restart), via scoped `shopt -s nocasematch` + quoted-literal `=~` prefix (bash `case` patterns can't do literal-then-whitespace + case-insensitivity in one test); `ai_bridge_prefix()` precedence: telegram.env > env from load_config > default `ai`. `--status` shows the current prefix; usage + `# POS_SUBCMDS: prefix` added (completions regenerate). Preserved edge: bare `ai` (no trailing space) never matched the old regex, so it still falls through to "Unknown command". Docs: POS.md listener rows/paragraph, howto/ai.md Telegram section + troubleshooting (also corrected a stale claim that AI errors reply with a `pos config ai` hint — code replies `AI error: …` only). Verified: function-level routing harness (`/tmp/ai_prefix_routing_test.sh` — extraction of the real listener functions + PATH stub `pos`): default `ai`/`AI` routes, bare-prefix and unknown-command fallthrough, `ai /reset` and custom-`bot` `/reset` reset the session, custom `bot`/`BOT` routes and old `ai` no longer routes, per-message hot-reload after removing the var; CLI verb tests (show/set/invalid rc 1/leading-digit/`--status`); dispatch smoke `pos communication telegram listener prefix` + flat form; `pos config telegram` render shows the field; `bash -n` ×2, `make gen && make check`, `make lint` 0 FAIL / 0 WARN.
|
||||
|
||||
@@ -609,7 +609,7 @@ Use conventional prefixes: `feat:`, `fix:`, `docs:`, `refactor:`, `chore:`
|
||||
| `bin/pos-communication-matrix-listener` | 568 | Matrix listener: map /command → bash, run them on room messages |
|
||||
| `bin/pos-communication-matrix-sender` | 224 | Send messages to a Matrix room via the client-server API (send, test, login) |
|
||||
| `bin/pos-communication-scrcpy` | 254 | Mirror/control an Android device via scrcpy+adb (mirror, devices, record, tcpip, connect, push, pull, screenshot, info) |
|
||||
| `bin/pos-communication-telegram-listener` | 566 | Telegram bot listener: map /command → bash, run them on chat messages |
|
||||
| `bin/pos-communication-telegram-listener` | 623 | Telegram bot listener: map /command → bash, run them on chat messages |
|
||||
| `bin/pos-communication-telegram-sender` | 221 | Send Telegram messages/files/links/stickers via Bot API (send, test) |
|
||||
| `bin/pos-docker-compose` | 487 | Docker Compose service manager (ls/up/down/restart/logs/update/config) |
|
||||
| `bin/pos-docker-health` | 107 | One-glance container health dashboard (exits 1 if unhealthy) |
|
||||
@@ -644,7 +644,7 @@ Use conventional prefixes: `feat:`, `fix:`, `docs:`, `refactor:`, `chore:`
|
||||
| `bin/pos-ai` | 692 | AI assistant: ask, chat, sessions, capture, models, providers |
|
||||
| `bin/pos-config` | 80 | Interactive editor for the tools' runtime config (reads # POS_CONFIG: registry) |
|
||||
| `bin/pos-tree` | 118 | Show the pos CLI command tree: categories, commands, and subcommands |
|
||||
| `completions/pos.bash` | 307 | Dynamic bash completion |
|
||||
| `completions/pos.bash` | 308 | Dynamic bash completion |
|
||||
<!-- GEN:END filetable -->
|
||||
| `apps/install.sh` | 171 | App install/uninstall picker/orchestrator |
|
||||
|
||||
|
||||
+3
-1
@@ -339,8 +339,10 @@ The bot token is a secret — it is stored only in `~/.config/linux_post_install
|
||||
| `pos communication telegram listener --disable` | Stops, disables, and removes the service |
|
||||
| `pos communication telegram listener --sync-commands` | Push the mapped `/commands` to the bot's `/` menu (`setMyCommands`) — also run automatically after every map edit, on `--enable`, and at daemon start |
|
||||
| `pos communication telegram listener --run` | Run the polling loop in the foreground (what the service executes) |
|
||||
| `pos communication telegram listener prefix` | Show the AI-bridge trigger word (default `ai`) |
|
||||
| `pos communication telegram listener prefix <word>` | Set the AI-bridge trigger word (one word of letters/digits/`-`/`_`); non-command messages starting with `<word>` + space are answered by Gemini. Also editable via `pos config telegram` (`TELEGRAM_AI_PREFIX`); takes effect immediately, no daemon restart |
|
||||
|
||||
The map file is re-read for every message — edits apply without a restart. The listener only reacts to the owner chat (`TELEGRAM_CHAT_ID`); anyone else's message is ignored. `/help` lists mapped commands; an unmapped command replies "Unknown command". Non-command text starting with `ai ` (case-insensitive, e.g. `ai what is Nvidia`) is forwarded to Gemini via `pos ai gemini ask` and the answer is replied verbatim; an AI failure replies the error plus a `pos config ai` hint. Commands run as your user via `timeout 60 bash -c "…"` (stdout + stderr are replied, truncated to ~3800 chars; empty output → `OK`), so `sudo` inside them needs a NOPASSWD rule. A map value prefixed with `@quiet ` runs the command but does NOT reply — for commands that already send their own notification (e.g. `pos system backup` self-notifies, so `/backup=@quiet pos system backup $HOME/Documents` avoids a double message). `--enable` warns if linger is off — the service stops when you log out unless you run `sudo loginctl enable-linger $(whoami)`.
|
||||
The map file is re-read for every message — edits apply without a restart. The listener only reacts to the owner chat (`TELEGRAM_CHAT_ID`); anyone else's message is ignored. `/help` lists mapped commands; an unmapped command replies "Unknown command". Non-command text starting with `<prefix> ` — default `ai `, configurable via `pos communication telegram listener prefix <word>` or `pos config telegram` — is forwarded to Gemini via `pos ai gemini ask` (case-insensitive, e.g. `ai what is Nvidia` or `BOT what is Nvidia` with prefix `bot`) and the answer is replied verbatim; an AI failure replies the error. Commands run as your user via `timeout 60 bash -c "…"` (stdout + stderr are replied, truncated to ~3800 chars; empty output → `OK`), so `sudo` inside them needs a NOPASSWD rule. A map value prefixed with `@quiet ` runs the command but does NOT reply — for commands that already send their own notification (e.g. `pos system backup` self-notifies, so `/backup=@quiet pos system backup $HOME/Documents` avoids a double message). `--enable` warns if linger is off — the service stops when you log out unless you run `sudo loginctl enable-linger $(whoami)`.
|
||||
|
||||
Map entries may carry an optional **description** shown in the bot's `/` menu: `/cmd::short description=bash command` (the description falls back to the bash command, truncated to ~40 chars, when omitted). After every add/edit/remove the command list is pushed to the bot via `setMyCommands`, so the menu stays in sync; an empty map clears the menu. Telegram only registers lowercase `[a-z0-9_]` names (1–32 chars) — commands like `/Status` or `/my-cmd` are skipped from the menu with a warning but still resolve when typed.
|
||||
|
||||
|
||||
+13
-6
@@ -150,6 +150,11 @@ you: ai what is Nvidia
|
||||
bot: NVIDIA is a company best known for GPUs...
|
||||
```
|
||||
|
||||
The trigger word is configurable via `pos communication telegram listener
|
||||
prefix <word>` (or `pos config telegram` → `TELEGRAM_AI_PREFIX`); it takes
|
||||
effect immediately, so with prefix `bot` you'd message `bot what is Nvidia`.
|
||||
`pos communication telegram listener prefix` shows the current value.
|
||||
|
||||
The bridge lives in the Telegram listener's `handle_message` (it calls
|
||||
`pos ai ask`); only the owner chat is served, so your key stays private.
|
||||
Set a different model per message:
|
||||
@@ -162,13 +167,14 @@ you: ai --model gemini-2.5-flash explain a Raft consensus log
|
||||
|
||||
Each chat has its own persistent session (`telegram-<chat id>` — independent
|
||||
of your terminal's `default` session), so the model
|
||||
remembers the conversation; `ai /reset` clears it. The listener passes a system
|
||||
remembers the conversation; `<prefix> /reset` clears it (with the default
|
||||
prefix that's `ai /reset`). The listener passes a system
|
||||
prompt telling the model it is answering in a Telegram chat — so it uses emojis
|
||||
and stays lively — and strips markdown (`**x**`, backticks, `#`, links…) from
|
||||
the reply before sending it, since messages go out as plain text.
|
||||
|
||||
Replying to a message before `ai …` makes that message part of the prompt, so
|
||||
the model can answer about it:
|
||||
Replying to a message before `<prefix> …` makes that message part of the
|
||||
prompt, so the model can answer about it:
|
||||
|
||||
```
|
||||
you: /status → bot: (system health output…)
|
||||
@@ -237,9 +243,10 @@ truncated). To disable: `unset __POS_CAPTURE_ACTIVE`.
|
||||
model's context window; check `pos ai models`.
|
||||
- `API error 429` → rate limit (free tier); wait and retry, or use a different
|
||||
model.
|
||||
- Nothing in Telegram for `ai …` → the listener daemon must be running
|
||||
(`pos communication telegram listener --status`); the bot token and owner
|
||||
chat id must match `pos config telegram`.
|
||||
- Nothing in Telegram for `<prefix> …` (default `ai`) → the listener daemon
|
||||
must be running (`pos communication telegram listener --status`); the bot
|
||||
token and owner chat id must match `pos config telegram`. Check the current
|
||||
trigger word with `pos communication telegram listener prefix`.
|
||||
|
||||
---
|
||||
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
set -euo pipefail
|
||||
# POS: communication telegram-listener — Telegram bot listener: map /command → bash, run them on chat messages
|
||||
# POS_FLAGS: --enable --disable --status --sync-commands --run
|
||||
# POS_SUBCMDS: prefix
|
||||
|
||||
CONFIG_DIR="${CONFIG_DIR:-${XDG_CONFIG_HOME:-$HOME/.config}/linux_post_install}"
|
||||
CONFIG_FILE="$CONFIG_DIR/telegram.env"
|
||||
@@ -10,8 +11,11 @@ API="https://api.telegram.org"
|
||||
SERVICE="pos-telegram-listener.service"
|
||||
USER_SYSTEMD_DIR="${XDG_CONFIG_HOME:-$HOME/.config}/systemd/user"
|
||||
|
||||
# System prompt for the "ai " bridge: replies are posted straight into the
|
||||
# chat, so ask for concise, emoji-friendly Telegram-style answers.
|
||||
# System prompt for the "<prefix> " AI bridge (default prefix: "ai"): replies
|
||||
# are posted straight into the chat, so ask for concise, emoji-friendly
|
||||
# Telegram-style answers. The trigger word is configurable via
|
||||
# TELEGRAM_AI_PREFIX in telegram.env ('pos communication telegram listener
|
||||
# prefix <word>' or 'pos config telegram').
|
||||
AI_SYSTEM="You are a friendly assistant chatting in a Telegram chat. Keep replies concise, use emojis and light formatting to make them lively, and never claim to send messages yourself."
|
||||
|
||||
err() { echo "ERROR: $*" >&2; exit 1; }
|
||||
@@ -32,8 +36,13 @@ Commands:
|
||||
--sync-commands
|
||||
Push the mapped /commands to the bot's "/" menu (setMyCommands)
|
||||
--run Run the polling loop in the foreground (used by the service)
|
||||
prefix [word]
|
||||
Show (no argument) or set the AI-bridge trigger word — any
|
||||
non-command message starting with '<word> ' is answered by
|
||||
Gemini (default 'ai'). Restore the default with 'prefix ai'.
|
||||
|
||||
Config: $CONFIG_FILE (TELEGRAM_BOT_TOKEN, TELEGRAM_CHAT_ID — edit with 'pos config telegram')
|
||||
Config: $CONFIG_FILE (TELEGRAM_BOT_TOKEN, TELEGRAM_CHAT_ID,
|
||||
TELEGRAM_AI_PREFIX — edit with 'pos config telegram')
|
||||
Map: $MAP_FILE — '/cmd=bash command' per line (optional
|
||||
'/cmd::short description=bash command' shown in the bot menu)
|
||||
|
||||
@@ -417,6 +426,8 @@ status() {
|
||||
fi
|
||||
echo "config: $CONFIG_FILE"
|
||||
echo "map file: $MAP_FILE"
|
||||
load_config
|
||||
echo "ai prefix: ${TELEGRAM_AI_PREFIX:-ai}"
|
||||
load_map
|
||||
echo "commands: $MAP_N mapped"
|
||||
local i
|
||||
@@ -425,6 +436,44 @@ status() {
|
||||
done
|
||||
}
|
||||
|
||||
# ── AI-bridge trigger word (TELEGRAM_AI_PREFIX) ─────────────────
|
||||
# Show or set the word that starts the AI bridge in handle_message.
|
||||
# Default 'ai'; a word is [A-Za-z0-9][A-Za-z0-9_-]* (no spaces, no pattern
|
||||
# metacharacters — the match is a literal, case-insensitive prefix).
|
||||
prefix_cmd() {
|
||||
local val="${1:-}"
|
||||
if [ -z "$val" ]; then
|
||||
load_config
|
||||
echo "AI bridge prefix: ${TELEGRAM_AI_PREFIX:-ai}"
|
||||
echo "Non-command messages starting with '<prefix> ' are answered by Gemini."
|
||||
echo "Set it with: pos communication telegram listener prefix <word> (default: ai)"
|
||||
return 0
|
||||
fi
|
||||
if ! [[ "$val" =~ ^[A-Za-z0-9][A-Za-z0-9_-]*$ ]]; then
|
||||
err "invalid prefix '$val' — use one word of letters, digits, '-' or '_' (no spaces)"
|
||||
fi
|
||||
mkdir -p "$CONFIG_DIR"
|
||||
touch "$CONFIG_FILE"
|
||||
chmod 600 "$CONFIG_FILE"
|
||||
local tmp
|
||||
tmp="$(mktemp)"
|
||||
grep -vE '^TELEGRAM_AI_PREFIX=' "$CONFIG_FILE" > "$tmp" || true
|
||||
printf 'TELEGRAM_AI_PREFIX=%s\n' "$val" >> "$tmp"
|
||||
mv "$tmp" "$CONFIG_FILE"
|
||||
chmod 600 "$CONFIG_FILE"
|
||||
log "AI bridge prefix set to '$val' — messages starting with '$val ' go to Gemini (takes effect immediately, no restart)"
|
||||
}
|
||||
|
||||
# Current AI-bridge trigger word. Like the command map, re-read per message so
|
||||
# 'prefix <word>' edits apply without restarting the daemon. Precedence:
|
||||
# telegram.env > env var from load_config (--run) > default 'ai'.
|
||||
ai_bridge_prefix() {
|
||||
local v=""
|
||||
[ -f "$CONFIG_FILE" ] && v="$(grep -E '^TELEGRAM_AI_PREFIX=' "$CONFIG_FILE" | tail -1 | sed 's/^[^=]*=//; s/^["'\'']//; s/["'\'']$//')" || true
|
||||
[ -n "$v" ] || v="${TELEGRAM_AI_PREFIX:-ai}"
|
||||
printf '%s' "$v"
|
||||
}
|
||||
|
||||
# ── polling daemon ──────────────────────────────────────────────
|
||||
reply() {
|
||||
local text="$1" msg_id="$2" rc="${3:-}"
|
||||
@@ -460,14 +509,20 @@ handle_message() {
|
||||
reply "Mapped commands: $(map_cmds_list)" "$msg_id"
|
||||
return ;;
|
||||
esac
|
||||
# AI bridge: non-command text starting with "ai " (case-insensitive) is
|
||||
# forwarded to Gemini; the model's answer is replied verbatim. Each chat
|
||||
# gets its own persistent memory session ("telegram-<chat_id>"); the exact
|
||||
# prompt "ai /reset" clears it. Future non-command intents (e.g. reminders)
|
||||
# slot in as more case arms here.
|
||||
if [[ "$text" != /* && "$text" =~ ^[Aa][Ii][[:space:]](.*)$ ]]; then
|
||||
# AI bridge: non-command text starting with "<prefix> " (default "ai",
|
||||
# case-insensitive, configurable via 'pos communication telegram listener
|
||||
# prefix <word>' / TELEGRAM_AI_PREFIX) is forwarded to Gemini; the model's
|
||||
# answer is replied verbatim. Each chat gets its own persistent memory
|
||||
# session ("telegram-<chat_id>"); the exact prompt "<prefix> /reset"
|
||||
# clears it. Future non-command intents (e.g. reminders) slot in as more
|
||||
# case arms here.
|
||||
local prefix
|
||||
prefix="$(ai_bridge_prefix)"
|
||||
shopt -s nocasematch
|
||||
if [[ "$text" != /* && "$text" =~ ^"$prefix"[[:space:]](.*)$ ]]; then
|
||||
shopt -u nocasematch
|
||||
local prompt="${BASH_REMATCH[1]}" answer session
|
||||
[ -n "$prompt" ] || { reply "Usage: ai <prompt> — e.g. 'ai what is Nvidia'" "$msg_id"; return; }
|
||||
[ -n "$prompt" ] || { reply "Usage: $prefix <prompt> — e.g. '$prefix what is Nvidia'" "$msg_id"; return; }
|
||||
session="telegram-${TELEGRAM_CHAT_ID}"
|
||||
if [[ "$prompt" =~ ^/?reset[[:space:]]*$ ]]; then
|
||||
if pos ai gemini sessions reset "$session" >/dev/null 2>&1; then
|
||||
@@ -477,7 +532,7 @@ handle_message() {
|
||||
fi
|
||||
return
|
||||
fi
|
||||
log "ai: $prompt"
|
||||
log "$prefix: $prompt"
|
||||
if [ -n "$reply_text" ]; then
|
||||
prompt="[Reply context — the message you are replying to]\n${reply_text}\n\n${prompt}"
|
||||
fi
|
||||
@@ -489,6 +544,7 @@ handle_message() {
|
||||
fi
|
||||
return
|
||||
fi
|
||||
shopt -u nocasematch
|
||||
value="$(map_get "$text")"
|
||||
if [ -z "$value" ]; then
|
||||
reply "Unknown command: $text (send /help)" "$msg_id"
|
||||
@@ -561,6 +617,7 @@ case "${1:-}" in
|
||||
--status) status ;;
|
||||
--sync-commands) sync_bot_commands ;;
|
||||
--run) run_daemon ;;
|
||||
prefix) prefix_cmd "${2:-}" ;;
|
||||
"") ui ;;
|
||||
*) err "Unknown option '$1' (see --help)" ;;
|
||||
esac
|
||||
|
||||
@@ -3,7 +3,7 @@ set -euo pipefail
|
||||
# POS: communication telegram-sender — Send Telegram messages/files/links/stickers via Bot API (send, test)
|
||||
# POS_FLAGS: --type --caption --parse-mode --no-preview --token --chat-id --markdown
|
||||
# POS_SUBCMDS: send test
|
||||
# POS_CONFIG: telegram | telegram.env | TELEGRAM_BOT_TOKEN=secret:Bot token from @BotFather | TELEGRAM_CHAT_ID=digits:Numeric chat id from @userinfobot
|
||||
# POS_CONFIG: telegram | telegram.env | TELEGRAM_BOT_TOKEN=secret:Bot token from @BotFather | TELEGRAM_CHAT_ID=digits:Numeric chat id from @userinfobot | TELEGRAM_AI_PREFIX=:AI-bridge trigger word in the telegram listener (default ai)::ai
|
||||
|
||||
CONFIG_DIR="${CONFIG_DIR:-${XDG_CONFIG_HOME:-$HOME/.config}/linux_post_install}"
|
||||
CONFIG_FILE="$CONFIG_DIR/telegram.env"
|
||||
|
||||
@@ -30,6 +30,7 @@ _pos_subcmds[ai-gemini]="ask chat models sessions capture"
|
||||
_pos_subcmds[ai-openrouter]="ask chat sessions capture"
|
||||
_pos_subcmds[communication-matrix-sender]="send test login"
|
||||
_pos_subcmds[communication-scrcpy]="devices record tcpip connect push pull screenshot info"
|
||||
_pos_subcmds[communication-telegram-listener]="prefix"
|
||||
_pos_subcmds[communication-telegram-sender]="send test"
|
||||
_pos_subcmds[docker-compose]="ls installed up down restart logs update config menu"
|
||||
_pos_subcmds[docker-vbox]="create enter stop start rm ls menu"
|
||||
|
||||
Reference in New Issue
Block a user