From 5c0222f0c4f95a28260a76cd87f420e93dc23e45 Mon Sep 17 00:00:00 2001 From: twentyOne2x Date: Sat, 20 Jun 2026 01:10:21 +0200 Subject: [PATCH] Add disposable Leo Telegram test agent --- docs/leo-disposable-test-agent.md | 60 ++++++++++++++++++++++++++ telegram/agents/leo-test.yaml | 59 +++++++++++++++++++++++++ tests/test_telegram_leo_x402_bridge.py | 7 +++ 3 files changed, 126 insertions(+) create mode 100644 docs/leo-disposable-test-agent.md create mode 100644 telegram/agents/leo-test.yaml diff --git a/docs/leo-disposable-test-agent.md b/docs/leo-disposable-test-agent.md new file mode 100644 index 0000000..e3ff503 --- /dev/null +++ b/docs/leo-disposable-test-agent.md @@ -0,0 +1,60 @@ +# Leo Disposable Test Agent + +## Working Target + +Run a second Leo Telegram transport against `https://leo.livingip.xyz/api/agents/leo/chat` without touching the production `@TeleoHumanBot` token or `teleo-agent@leo` service. + +## Why + +Production Leo is currently blocked by a Telegram `getUpdates` conflict from an unseen consumer. A disposable bot avoids that conflict by using a separate Telegram bot token and service instance. + +## Secret Boundary + +Do not commit the bot token. Store it only on the VPS as: + +```text +/opt/teleo-eval/secrets/leo-test-telegram-bot-token +``` + +The file should be readable by the `teleo` runtime user and should not be printed in logs. + +## Boot + +After syncing this branch or PR to the VPS: + +```sh +sudo -u teleo /opt/teleo-eval/pipeline/.venv/bin/python3 \ + /opt/teleo-eval/telegram/agent_runner.py --agent leo-test --validate + +sudo systemctl start teleo-agent@leo-test +sudo systemctl is-active teleo-agent@leo-test +``` + +Then DM the disposable Telegram bot from a user account. Do not post into public groups for this canary. + +## Evidence + +Collect sanitized logs only: + +```sh +journalctl -u teleo-agent@leo-test --since "10 minutes ago" --no-pager +``` + +Retained proof should say: + +- bot token value was not printed; +- production `teleo-agent@leo` was not stopped; +- disposable service name was `teleo-agent@leo-test`; +- public HTTP Leo route responded through the Telegram transport; +- no paid x402 spend was attempted unless separately authorized. + +## Tear Down + +```sh +sudo systemctl stop teleo-agent@leo-test +sudo systemctl is-active teleo-agent@leo-test || true +``` + +## Slack Note + +Slack is the preferred long-term internal transport, but this repository does not yet include a Slack bot transport. A Slack canary should be a separate PR with a Socket Mode or Events API adapter and separate `leo-slack-*` secret files. diff --git a/telegram/agents/leo-test.yaml b/telegram/agents/leo-test.yaml new file mode 100644 index 0000000..12a6714 --- /dev/null +++ b/telegram/agents/leo-test.yaml @@ -0,0 +1,59 @@ +# Leo Test — disposable Living IP x402 research agent +# Uses a separate Telegram bot token so test polling cannot collide with Leo prod. + +# ─── Identity ──────────────────────────────────────────────────────────── +name: Leo Test +handle: "@LivingIPLeoTestBot" +x_handle: "@teLEOhuman" +mention_aliases: + - "@leo-test" + - "@LivingIPLeoTestBot" +bot_token_file: leo-test-telegram-bot-token +pentagon_agent_id: livingip-leo-test +domain: collective-intelligence +domain_expertise: > + collective intelligence, Living IP strategy, agent markets, paid research, + x402 service rails, and transport canary validation + +# ─── Hosted Leo Runtime ────────────────────────────────────────────────── +http_chat_proxy_url: "https://leo.livingip.xyz/api/agents/leo/chat" +respond_to_private_chats: true + +# ─── KB Scope ──────────────────────────────────────────────────────────── +kb_scope: + primary: + - domains/collective-intelligence + - domains/ai-alignment + - domains/space-development + - foundations + - core + +# ─── Voice ─────────────────────────────────────────────────────────────── +voice_summary: "Disposable Leo transport canary. Direct, proof-aware, concise." + +voice_definition: | + ## Register + You are Leo Test, a disposable transport canary for Living IP's Leo agent. + Be direct, proof-aware, and concise. Prefer current route/readback evidence + over broad claims. + + ## x402 / Paid Research + When a user asks about paid services, research spend, or x402 capability, + answer from retained Living IP runtime evidence and current route state. + Do not claim payment execution unless the HTTP route returns retained + payment/readback evidence. + + ## Test Boundary + Make clear that this Telegram bot is a disposable test transport. Do not + claim it is the production Leo bot. + +# ─── Learnings ─────────────────────────────────────────────────────────── +learnings_file: agents/leo/learnings.md + +# ─── Model ─────────────────────────────────────────────────────────────── +response_model: anthropic/claude-opus-4-6 +triage_model: anthropic/claude-haiku-4.5 +max_tokens: 500 + +# ─── Rate Limits ───────────────────────────────────────────────────────── +max_response_per_user_per_hour: 10 diff --git a/tests/test_telegram_leo_x402_bridge.py b/tests/test_telegram_leo_x402_bridge.py index 1e5baa4..e4fbf3c 100644 --- a/tests/test_telegram_leo_x402_bridge.py +++ b/tests/test_telegram_leo_x402_bridge.py @@ -15,12 +15,19 @@ from http_chat_proxy import build_chat_proxy_payload, extract_chat_proxy_reply def test_leo_config_opts_into_http_chat_proxy_without_changing_default_agents(): leo = load_agent_config(str(TELEGRAM_DIR / "agents" / "leo.yaml")) + leo_test = load_agent_config(str(TELEGRAM_DIR / "agents" / "leo-test.yaml")) rio = load_agent_config(str(TELEGRAM_DIR / "agents" / "rio.yaml")) assert leo.name == "Leo" assert leo.http_chat_proxy_url == "https://leo.livingip.xyz/api/agents/leo/chat" assert leo.respond_to_private_chats is True assert "@teLEOhuman" in leo.mention_aliases + assert leo_test.name == "Leo Test" + assert leo_test.http_chat_proxy_url == leo.http_chat_proxy_url + assert leo_test.respond_to_private_chats is True + assert leo_test.bot_token_file == "leo-test-telegram-bot-token" + assert leo_test.bot_token_file != leo.bot_token_file + assert leo_test.handle != leo.handle assert rio.http_chat_proxy_url is None assert rio.respond_to_private_chats is False