Skip to content

Telegram - #2

Closed
jramirezhdez02 wants to merge 6 commits into
mainfrom
telegram
Closed

Telegram#2
jramirezhdez02 wants to merge 6 commits into
mainfrom
telegram

Conversation

@jramirezhdez02

Copy link
Copy Markdown

No description provided.

yordis and others added 6 commits February 16, 2026 14:21
Signed-off-by: Yordis Prieto <yordis.prieto@gmail.com>
Add foundational crates for Telegram-NATS integration:

- telegram-types: Shared types (events, commands, chat types, policies, session management)
  * Event types for bot updates (text, photo, video, audio, callbacks)
  * Command types for agent actions (send, edit, delete messages)
  * Access control policies (DM/group allowlists)
  * Session ID generation logic

- telegram-nats: NATS messaging infrastructure
  * Subject pattern builders for bot events and agent commands
  * Message publisher/subscriber with serialization
  * NATS connection management with reconnect logic
  * JetStream setup for event streams and session KV store

- telegram-bot: Bot application scaffolding (Cargo.toml only)

All crates compile successfully with proper error handling and tracing support.
Implements a fully functional Telegram bot that bridges Telegram and NATS,
enabling AI agents to interact with users through Telegram.

## Components Added

### Core Bot Implementation
- **Bridge Module**: Converts Telegram updates to NATS events
- **Outbound Processor**: Processes NATS commands and sends to Telegram
- **Handlers**: Message handlers for text, photo, video, callbacks
- **Session Manager**: Persistent session tracking with JetStream KV
- **Config System**: TOML + env vars + CLI args configuration

### Features
- Bidirectional Telegram ↔ NATS communication
- Support for text, photo, video messages
- Command parsing and routing
- Callback query handling (interactive buttons)
- Access control (admins, allowed users/groups)
- Streaming message support
- Inline keyboards
- Chat actions (typing indicators)
- Comprehensive error handling
- Structured logging with tracing

### NATS Integration
Inbound events:
- telegram.bot.message.{text,photo,video}
- telegram.bot.command.{name}
- telegram.bot.callback_query

Outbound commands:
- telegram.agent.message.{send,edit,delete,send_photo,stream}
- telegram.agent.callback.answer
- telegram.agent.chat.action

### Configuration & Documentation
- Example configuration files
- Comprehensive README with architecture, guides, and API reference
- Environment variable template
- Implementation status document

### Dependencies
- teloxide 0.14.1 (Telegram Bot API)
- clap 4.5.26 (CLI parsing)
- toml 0.8.23 (config parsing)
- chrono 0.4.43 (timestamps)

## Build Status
✅ All components compile successfully
✅ No critical warnings
✅ Ready for Phase 2 (Agent implementation)
- Add #[allow(deprecated)] to convert_parse_mode function to suppress
  warning about ParseMode::Markdown (maintained for backward compatibility)
- Add #[allow(dead_code)] to unused SessionManager methods (get, update, delete)
  that are part of the public API for future use

Build now completes with zero warnings.
## Tests Added
- Session ID generation tests for all chat types (4 tests)
- Configuration default value tests (3 tests)
- All tests passing (7/7)

## Configuration Fixes
- Fixed AccessConfig structure to match telegram-types schema
- Added missing fields: dm_policy, group_policy
- Renamed fields for consistency:
  - admin_ids → admin_users
  - allowed_user_ids → user_allowlist
  - allowed_group_ids → group_allowlist
- Updated all config files (toml, example, test)

## Integration Testing
- Bot successfully loads configuration
- Bot successfully connects to NATS
- Bot correctly attempts JetStream setup
- Proper error handling when NATS server unavailable

Test Results:
✅ 7 unit tests passing
✅ Configuration parsing working
✅ NATS connection working
✅ Error handling verified
✅ Logging system operational
Implements a functional AI agent that processes Telegram messages and
generates responses via NATS.

## Components Added

### Core Agent (telegram-agent)
- **Agent Module**: Subscribes to NATS events and routes messages
- **Processor Module**: Handles business logic for different message types
- **Main Binary**: CLI with configuration and initialization

### Message Handlers
- **Text Messages**: Echo responses with typing indicator
- **Photo Messages**: Acknowledgment with caption support
- **Commands**: /start, /help, /status
- **Callback Queries**: Button click handling

### Features
- ✅ Concurrent message processing (4 handlers in parallel)
- ✅ Typing indicators for better UX
- ✅ Error handling per message (failures don't crash agent)
- ✅ Structured logging
- ✅ CLI configuration
- ✅ Clean separation of concerns

## Architecture

```
Telegram → Bot → NATS → Agent → NATS → Bot → Telegram
```

Agent subscribes to:
- telegram.bot.message.text
- telegram.bot.message.photo
- telegram.bot.command.*
- telegram.bot.callback_query

Agent publishes to:
- telegram.agent.message.send
- telegram.agent.callback.answer
- telegram.agent.chat.action

## Current Implementation

**Echo Bot**: The agent currently echoes messages back to demonstrate
the full message flow. Ready for LLM integration in next phase.

## Build Status
✅ Compiles successfully
✅ All dependencies resolved
✅ 1 harmless warning (unused import false positive)

## Next Steps (Phase 3)
- LLM integration (Claude/OpenAI)
- Conversation state management
- Context/memory system
- Advanced response generation
@coderabbitai

coderabbitai Bot commented Feb 16, 2026

Copy link
Copy Markdown

Caution

Review failed

The head commit changed during the review from 2842f4a to df7a5a5.

✨ Finishing touches
  • 📝 Generate docstrings
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch telegram

Tip

Issue Planner is now in beta. Read the docs and try it out! Share your feedback on Discord.


Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

jramirezhdez02 added a commit that referenced this pull request Mar 21, 2026
When the ACP client advertises `_meta.terminal_output: true` during
initialize, Bash tool notifications now carry the terminal lifecycle
metadata expected by Zed (matching codex-acp behaviour):

- tool_call: `_meta.terminal_info = { terminal_id }`
- tool_call_update #1: `_meta.terminal_output = { terminal_id, data }`
- tool_call_update #2: `_meta.terminal_exit = { terminal_id, exit_code, signal }`

The capability flag is stored on `Bridge` via an `AtomicBool` so it can
be set from `&self` context. Both code paths that handle `initialize`
now store the flag:
- `acp-nats` Bridge path (`initialize::handle`)
- `trogon-acp` `TrogonAcpAgent::initialize`

`replay_history` in `trogon-acp` also replays the terminal metadata for
Bash calls that are loaded from session history.

Signed-off-by: Jorge <jramirezhdez02@gmail.com>
jramirezhdez02 added a commit that referenced this pull request Mar 24, 2026
When the ACP client advertises `_meta.terminal_output: true` during
initialize, Bash tool notifications now carry the terminal lifecycle
metadata expected by Zed (matching codex-acp behaviour):

- tool_call: `_meta.terminal_info = { terminal_id }`
- tool_call_update #1: `_meta.terminal_output = { terminal_id, data }`
- tool_call_update #2: `_meta.terminal_exit = { terminal_id, exit_code, signal }`

The capability flag is stored on `Bridge` via an `AtomicBool` so it can
be set from `&self` context. Both code paths that handle `initialize`
now store the flag:
- `acp-nats` Bridge path (`initialize::handle`)
- `trogon-acp` `TrogonAcpAgent::initialize`

`replay_history` in `trogon-acp` also replays the terminal metadata for
Bash calls that are loaded from session history.

Signed-off-by: Jorge <jramirezhdez02@gmail.com>
jramirezhdez02 added a commit that referenced this pull request Mar 24, 2026
When the ACP client advertises `_meta.terminal_output: true` during
initialize, Bash tool notifications now carry the terminal lifecycle
metadata expected by Zed (matching codex-acp behaviour):

- tool_call: `_meta.terminal_info = { terminal_id }`
- tool_call_update #1: `_meta.terminal_output = { terminal_id, data }`
- tool_call_update #2: `_meta.terminal_exit = { terminal_id, exit_code, signal }`

The capability flag is stored on `Bridge` via an `AtomicBool` so it can
be set from `&self` context. Both code paths that handle `initialize`
now store the flag:
- `acp-nats` Bridge path (`initialize::handle`)
- `trogon-acp` `TrogonAcpAgent::initialize`

`replay_history` in `trogon-acp` also replays the terminal metadata for
Bash calls that are loaded from session history.

Signed-off-by: Jorge <jramirezhdez02@gmail.com>
jramirezhdez02 added a commit that referenced this pull request Mar 24, 2026
When the ACP client advertises `_meta.terminal_output: true` during
initialize, Bash tool notifications now carry the terminal lifecycle
metadata expected by Zed (matching codex-acp behaviour):

- tool_call: `_meta.terminal_info = { terminal_id }`
- tool_call_update #1: `_meta.terminal_output = { terminal_id, data }`
- tool_call_update #2: `_meta.terminal_exit = { terminal_id, exit_code, signal }`

The capability flag is stored on `Bridge` via an `AtomicBool` so it can
be set from `&self` context. Both code paths that handle `initialize`
now store the flag:
- `acp-nats` Bridge path (`initialize::handle`)
- `trogon-acp` `TrogonAcpAgent::initialize`

`replay_history` in `trogon-acp` also replays the terminal metadata for
Bash calls that are loaded from session history.

Signed-off-by: Jorge <jramirezhdez02@gmail.com>
mariorha added a commit that referenced this pull request Apr 14, 2026
#2 — recovering flag now flips to false only after a successful checkpoint
write, not after the first tool turn. With checkpointing_disabled=true the
flag stays true throughout so every subsequent tool turn consults the KV
result cache, preventing re-execution after a crash in a disabled-checkpoint
run.

#4 — write_promise_terminal retries with a fresh KV revision on CAS conflict.
When checkpointing is disabled the pre-LLM heartbeat advances the revision
without updating the local copy, making the stored revision stale. The retry
reloads get_promise and re-attempts the write so the promise is durably marked
terminal instead of staying Running.

#9 — Linear post_comment now embeds a trogon-idempotency-key HTML marker in
the comment body and scans existing comments for that marker before posting,
mirroring the defence-in-depth approach used for GitHub post_pr_comment. The
Idempotency-Key header is still passed as primary protection; the marker scan
is a fallback for header-window expiry. Three pipeline e2e tests updated to
mock the new get_comments pre-check request.
mariorha added a commit that referenced this pull request Apr 14, 2026
…eviewer dedup

#1 — Linear post_comment: embed now uses idempotency_marker()
The pre-check scan (tools/linear.rs:71) used super::idempotency_marker(key)
which replaces -- with __ in the key. The embed (line 117) used the raw key
directly, so the two paths produced different marker strings whenever the key
contained --. The check would search for abc__def but the stored body had
abc--def — a silent false negative that lets duplicates through. Now both
paths call idempotency_marker() so write and scan are byte-identical.

#2 — request_reviewers: filter already-added reviewers instead of all-or-nothing
The previous dedup skipped the POST only if ALL requested reviewers were
already in the pending list. A crash after GitHub partially applied the request
(some reviewers added, others not) caused recovery to re-execute with all
reviewers, sending duplicate notifications to those already added. Now we
filter the already-present reviewers from the request list and only POST the
missing ones; if no reviewers are missing the POST is skipped entirely.

Note: #6 (startup recovery rate limiting) turned out to be already implemented
correctly — recover_stale_promises processes promises sequentially, not
concurrently (intentional, see runner.rs comment at line 1092).
mariorha pushed a commit that referenced this pull request Apr 15, 2026
#5 — heartbeat KV timeout now reloads revision and retries the write,
matching the CAS-conflict arm. Under sustained NATS degradation the old
code left claimed_at frozen; the reload+retry keeps it fresh and avoids
false-positive stale detection by startup recovery.

#2 — recovering resets to false when checkpointing is permanently
disabled (payload exceeds all trim levels). Previously recovering stayed
true forever, causing same-input tool calls in genuinely-new turns to
return stale cached results (polling anti-pattern). New test
recovering_resets_when_checkpointing_permanently_disabled covers the
case.

#7 — summarize_dropped_messages is now wrapped in a 30 s timeout.
The call inherits a 5-minute LLM timeout which blocks the checkpoint
write and leaves claimed_at stale for that window. 30 s is generous for
a short summary; on timeout the empty Vec triggers the plain-trim
fallback that was already there.

#6 — list_running timeout raised from NATS_KV_TIMEOUT (10 s) to a
dedicated LIST_RUNNING_TIMEOUT (2 min). The operation does N+1 KV reads;
at 50+ stale promises under mild load the 10 s ceiling fires and silently
skips recovery. 2 min covers hundreds of promises without blocking the
consumer loop (recovery runs in a background task).
yordis added a commit that referenced this pull request Jun 22, 2026
#2 — recovering flag now flips to false only after a successful checkpoint
write, not after the first tool turn. With checkpointing_disabled=true the
flag stays true throughout so every subsequent tool turn consults the KV
result cache, preventing re-execution after a crash in a disabled-checkpoint
run.

#4 — write_promise_terminal retries with a fresh KV revision on CAS conflict.
When checkpointing is disabled the pre-LLM heartbeat advances the revision
without updating the local copy, making the stored revision stale. The retry
reloads get_promise and re-attempts the write so the promise is durably marked
terminal instead of staying Running.

#9 — Linear post_comment now embeds a trogon-idempotency-key HTML marker in
the comment body and scans existing comments for that marker before posting,
mirroring the defence-in-depth approach used for GitHub post_pr_comment. The
Idempotency-Key header is still passed as primary protection; the marker scan
is a fallback for header-window expiry. Three pipeline e2e tests updated to
mock the new get_comments pre-check request.

Signed-off-by: Yordis Prieto <yordis.prieto@gmail.com>
yordis added a commit that referenced this pull request Jun 22, 2026
…eviewer dedup

#1 — Linear post_comment: embed now uses idempotency_marker()
The pre-check scan (tools/linear.rs:71) used super::idempotency_marker(key)
which replaces -- with __ in the key. The embed (line 117) used the raw key
directly, so the two paths produced different marker strings whenever the key
contained --. The check would search for abc__def but the stored body had
abc--def — a silent false negative that lets duplicates through. Now both
paths call idempotency_marker() so write and scan are byte-identical.

#2 — request_reviewers: filter already-added reviewers instead of all-or-nothing
The previous dedup skipped the POST only if ALL requested reviewers were
already in the pending list. A crash after GitHub partially applied the request
(some reviewers added, others not) caused recovery to re-execute with all
reviewers, sending duplicate notifications to those already added. Now we
filter the already-present reviewers from the request list and only POST the
missing ones; if no reviewers are missing the POST is skipped entirely.

Note: #6 (startup recovery rate limiting) turned out to be already implemented
correctly — recover_stale_promises processes promises sequentially, not
concurrently (intentional, see runner.rs comment at line 1092).

Signed-off-by: Yordis Prieto <yordis.prieto@gmail.com>
yordis added a commit that referenced this pull request Jun 22, 2026
#5 — heartbeat KV timeout now reloads revision and retries the write,
matching the CAS-conflict arm. Under sustained NATS degradation the old
code left claimed_at frozen; the reload+retry keeps it fresh and avoids
false-positive stale detection by startup recovery.

#2 — recovering resets to false when checkpointing is permanently
disabled (payload exceeds all trim levels). Previously recovering stayed
true forever, causing same-input tool calls in genuinely-new turns to
return stale cached results (polling anti-pattern). New test
recovering_resets_when_checkpointing_permanently_disabled covers the
case.

#7 — summarize_dropped_messages is now wrapped in a 30 s timeout.
The call inherits a 5-minute LLM timeout which blocks the checkpoint
write and leaves claimed_at stale for that window. 30 s is generous for
a short summary; on timeout the empty Vec triggers the plain-trim
fallback that was already there.

#6 — list_running timeout raised from NATS_KV_TIMEOUT (10 s) to a
dedicated LIST_RUNNING_TIMEOUT (2 min). The operation does N+1 KV reads;
at 50+ stale promises under mild load the 10 s ceiling fires and silently
skips recovery. 2 min covers hundreds of promises without blocking the
consumer loop (recovery runs in a background task).

Signed-off-by: Yordis Prieto <yordis.prieto@gmail.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants