Commit graph

34 commits

Author SHA1 Message Date
harald
0027b4d746 fix(telegram): treat "message is not modified" as success in finalize_draft
Telegram returns 400 with "message is not modified" when editMessageText
is called with content identical to the current message. This happens
when streaming deltas have already updated the draft to the final text.
Previously this triggered a fallback to sendMessage, producing a
duplicate message.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-21 08:24:31 +01:00
Chummy
ce104bed45 feat(proxy): add scoped proxy configuration and docs runbooks
- add scope-aware proxy schema and runtime wiring for providers/channels/tools

- add agent callable proxy_config tool for fast proxy setup

- standardize docs system with index, template, and playbooks
2026-02-18 22:10:42 +08:00
Chummy
cfa7215688 fix(telegram): harden mention-only matching and retry cache 2026-02-18 19:51:42 +08:00
ZeroClaw Contributor
c0a80ad656 feat(channel): add mention_only option for Telegram groups
Adds mention_only config option to Telegram channel, allowing the bot
to only respond to messages that @-mention the bot in group chats.
Direct messages are always processed regardless of this setting.

Behavior:
- When mention_only = true: Bot only responds to group messages containing @botname
- When mention_only = false (default): Bot responds to all allowed messages
- DM/private chats always work regardless of mention_only setting

Implementation:
- Fetch and cache bot username from Telegram API on startup
- Check for @botname mention in group messages
- Strip mention from message content before processing

Config example:
[channels.telegram]
bot_token = "your_token"
mention_only = true

Changes:
- src/config/schema.rs: Add mention_only to TelegramConfig
- src/channels/telegram.rs: Implement mention_only logic + 6 new tests
- src/channels/mod.rs: Update factory calls
- src/cron/scheduler.rs: Update constructor call
- src/onboard/wizard.rs: Update wizard config
- src/daemon/mod.rs: Update test config
- src/integrations/registry.rs: Update test config
- TESTING_TELEGRAM.md: Add mention_only test section
- CHANGELOG.md: Document feature

Risk: medium
Backward compatible: Yes (default: false)
2026-02-18 19:51:42 +08:00
Chummy
219764d4d8 fix(channels): recover malformed invoke/tool_call output in daemon mode 2026-02-18 17:01:36 +08:00
Xiangjun Ma
f1db63219c refactor(telegram): address code review findings
- Add strip_tool_call_tags() to finalize_draft to prevent Markdown
  parse failures from tool-call tags reaching Telegram API
- Deduplicate parse_reply_target() call in update_draft (was called
  twice, discarding thread_id both times)
- Replace body.as_object_mut().unwrap() mutation with separate
  plain_body JSON literal (eliminates unwrap in runtime path)
- Clean up per-chat rate-limit HashMap entry in finalize_draft to
  prevent unbounded growth over long uptimes
- Extract magic number 80 to STREAM_CHUNK_MIN_CHARS constant in
  agent loop
2026-02-18 16:33:33 +08:00
Chummy
e326e12039 test(telegram): cover draft streaming paths and simplify stream modes 2026-02-18 16:33:33 +08:00
Xiangjun Ma
e21fe1ff55 fix(telegram): address Copilot review feedback
- Fix silent parse failures: message_id.parse().unwrap_or(0) replaced
  with match + tracing::warn on parse error (update_draft, finalize_draft)
- Fix UTF-8 panic: byte-based truncation replaced with char_indices()
  safe boundary detection for TELEGRAM_MAX_MESSAGE_LENGTH
- Fix global rate limiter: Mutex<Option<Instant>> replaced with
  Mutex<HashMap<String, Instant>> for per-chat rate limiting so
  concurrent conversations don't interfere with each other
- Document Block variant: clarify it's reserved for future use and
  currently behaves the same as Partial
2026-02-18 16:33:33 +08:00
Xiangjun Ma
118cd53922 feat(channel): stream LLM responses to Telegram via draft message edits
Wire the existing provider-layer streaming infrastructure through the
channel trait and agent loop so Telegram users see tokens arrive
progressively via editMessageText, instead of waiting for the full
response.

Changes:
- Add StreamMode enum (off/partial/block) and draft_update_interval_ms
  to TelegramConfig (backward-compatible defaults: off, 1000ms)
- Add supports_draft_updates/send_draft/update_draft/finalize_draft to
  Channel trait with no-op defaults (zero impact on existing channels)
- Implement draft methods on TelegramChannel using sendMessage +
  editMessageText with rate limiting and Markdown fallback
- Add on_delta mpsc::Sender<String> parameter to run_tool_call_loop
  (None preserves existing behavior)
- Wire streaming in process_channel_message: when channel supports
  drafts, send initial draft, spawn updater task, finalize on completion

Edge cases handled:
- 4096-char limit: finalize draft and fall back to chunked send
- Broken Markdown: use no parse_mode during streaming, apply on finalize
- Edit failures: fall back to sending complete response as new message
- Rate limiting: configurable draft_update_interval_ms (default 1s)
2026-02-18 16:33:33 +08:00
Edvard
b3b1679218 feat(channels): implement typing indicator for Telegram channel
Add start_typing/stop_typing overrides to TelegramChannel following the
same pattern as DiscordChannel: spawn a tokio task that sends
sendChatAction every 4 seconds (Telegram typing expires after 5s),
and abort it on stop_typing.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-18 12:06:58 +08:00
ZeroClaw Agent
36062fb1c2 feat(telegram): add forum topic support
Implement Telegram Forum (topic) support to allow the bot to respond
in the same topic where it was mentioned/called.

Changes:
- parse_update_message(): Extract message_thread_id and format reply_target as 'chat_id:thread_id'
- send(): Parse recipient to extract chat_id and optional thread_id
- All send methods now pass thread_id parameter and include message_thread_id in API requests
- Added test for forum topic message parsing

This ensures bot replies stay within the same forum topic thread.
2026-02-18 10:22:40 +08:00
Chummy
e2e431d9e7 style(channels): apply rustfmt drift after main rebase 2026-02-18 00:45:26 +08:00
Argenis
0f68756ec7
fix(telegram): strip tool_call tags before sending messages
Strip XML-style tool call tags from messages before sending to Telegram to prevent Markdown parsing failures (status 400).

Fixes #503

Co-Authored-By: ayush-thakur02 <ayush.th2002@gmail.com>
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-17 11:28:35 -05:00
Chummy
cd0dd13476 fix(channels): complete SendMessage migration after rebase 2026-02-17 23:28:08 +08:00
Kieran
dbebd48dfe refactor(channel): accept SendMessage struct in Channel::send()
Refactor the Channel trait to accept a SendMessage struct instead of
separate message and recipient string parameters. This enables passing
additional metadata like email subjects.

Changes:
- Add SendMessage struct with content, recipient, and optional subject
- Update Channel::send() signature to accept &SendMessage
- Update all 12 channel implementations
- Update call sites in channels/mod.rs and gateway/mod.rs

Subject field usage:
- Email: uses subject for email subject line
- DingTalk: uses subject as markdown message title
- All others: ignore subject (no native platform support)
2026-02-17 23:28:08 +08:00
leon
62eadec274 fix(telegram): surface getUpdates API conflicts in logs 2026-02-17 22:48:40 +08:00
leon
bfc67c9c29 feat(telegram): add bind-code pairing and fix reply routing 2026-02-17 22:48:40 +08:00
Chummy
ae37e59423
fix(channels): resolve telegram reply target and media delivery (#525)
Co-authored-by: Will Sarg <12886992+willsarg@users.noreply.github.com>
2026-02-17 08:07:23 -05:00
chenmi
18952f9a2b fix(channels): add reply_to field to ChannelMessage for correct reply routing
ChannelMessage.sender was used both for display (username) and as the
reply target in Channel::send(). For Telegram, sender is the username
(e.g. "unknown") while send() requires the numeric chat_id, causing
"Bad Request: chat not found" errors.

Add a dedicated reply_to field to ChannelMessage that stores the
channel-specific reply address (Telegram chat_id, Discord channel_id,
Slack channel, etc.). Update all channel implementations and dispatch
code to use reply_to for send/start_typing/stop_typing calls.

This also fixes the same latent bug in Discord and Slack channels where
sender (user ID) was incorrectly passed as the reply target.
2026-02-17 19:33:32 +08:00
darwin808
4413790859 chore(lint): remove unused imports, variables, and redundant mut bindings
Eliminate low-risk clippy warnings as part of the strict lint backlog (#409):

- Remove unused `uuid::Uuid` imports from slack and telegram channels
- Remove unnecessary `mut` and redundant rebindings in agent loop
- Prefix unused `channel_id` variable in discord channel
- Remove unused test imports (`ChatResponse`, `ToolCall`, `TempDir`, `Path`)
2026-02-17 16:40:58 +08:00
Argenis
e8553a800a
fix(channels): use platform message IDs to prevent duplicate memories
Fixes #430 - Prevents duplicate memories after restart by using platform message IDs instead of random UUIDs.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-16 19:04:37 -05:00
Chummy
8882746ced
fix(onboard): refresh MiniMax defaults and endpoint (#299) 2026-02-16 23:40:44 +08:00
chumyin
dedb465377 test(telegram): ensure newline split case exceeds max length 2026-02-16 19:36:39 +08:00
chumyin
2d6ec2fb71 fix(rebase): resolve PR #266 conflicts against latest main 2026-02-16 19:33:04 +08:00
Abdul Samad
4fd1408034
fix(telegram): add message splitting, timeout, and validation fixes (#246)
High-priority fixes:
- Message length validation and splitting (4096 char limit)
- Empty chat_id validation to prevent silent failures
- Health check timeout (5s) to prevent service hangs

Testing infrastructure:
- Comprehensive test suite (20+ automated tests)
- Quick smoke test script
- Test message generator
- Complete testing documentation

All changes are backward compatible.

Co-authored-by: Claude Sonnet 4.5 <noreply@anthropic.com>
2026-02-16 05:59:11 -05:00
Chummy
b442a07530
fix(memory): prevent autosave key collisions across runtime flows
Fixes #221 - SQLite Memory Override bug.

This PR resolves memory overwrite behavior in autosave paths by replacing fixed memory keys with unique keys, and improves short-horizon recall quality in channel runtime.

**Root Cause**
SQLite memory uses a unique constraint on `memories.key` and writes with `ON CONFLICT(key) DO UPDATE`.
Several autosave paths reused fixed keys (or sender-stable keys), so newer messages overwrote earlier conversation entries.

**Changes**
- Channel runtime: autosave key changed from `channel_sender` to `channel_sender_messageId`
- Added memory-context injection before provider calls (aligned with agent loop behavior)
- Agent loop: autosave keys changed from fixed `user_msg`/`assistant_resp` to UUID-suffixed keys
- Gateway: Webhook/WhatsApp autosave keys changed to UUID-suffixed keys

All CI checks passing.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-15 22:55:52 -05:00
junbaor
3b7a140aad
feat(telegram): add typing indicator when receiving messages
- Send 'typing' chat action immediately upon receiving a message
- Improves user experience by showing the bot is processing
- Telegram displays '...is typing' indicator while the AI generates response
- Gracefully ignores errors to avoid breaking message handling

Previously, there was no typing indicator implementation, causing
users to wait without feedback during AI response generation.
2026-02-15 15:02:36 -05:00
Argenis
dca95cac7a
fix: add channel message timeouts, Telegram fallback, and fix identity/observer tests
Closes #184
2026-02-15 12:31:40 -05:00
Argenis
ef00cc9a66
fix(channels): check response status in send() for Telegram, Slack, and Discord
Reliability fix: check HTTP response status in channel send methods
2026-02-15 09:48:58 -05:00
argenis de la rosa
09d3140127 feat: add Docker env var support for PORT, HOST, and TEMPERATURE
- Add port and host fields to GatewayConfig with defaults (3000, 127.0.0.1)
- Enhanced apply_env_overrides() to support:
  - ZEROCLAW_GATEWAY_PORT or PORT - Gateway server port
  - ZEROCLAW_GATEWAY_HOST or HOST - Gateway bind address
  - ZEROCLAW_TEMPERATURE - Default temperature (0.0-2.0)
- Add comprehensive tests for all new env var overrides
- Fix clippy warnings (is_multiple_of, too_many_lines)

Closes #45
2026-02-14 16:19:26 -05:00
argenis de la rosa
ec2d5cc93d feat: enhance agent personality, tool guidance, and memory hygiene
- Expand communication style presets (professional, expressive, custom)
- Enrich SOUL.md with human-like tone and emoji-awareness guidance
- Add crash recovery and sub-task scoping guidance to AGENTS.md scaffold
- Add 'Use when / Don't use when' guidance to TOOLS.md and runtime prompts
- Implement memory hygiene system with configurable archiving and retention
- Add MemoryConfig options: hygiene_enabled, archive_after_days, purge_after_days, conversation_retention_days
- Archive old daily memory and session files to archive subdirectories
- Purge old archives and prune stale SQLite conversation rows
- Add comprehensive tests for new features
2026-02-14 11:28:39 -05:00
argenis de la rosa
bc31e4389b style: cargo fmt — fix all formatting for CI
Ran cargo fmt across entire codebase to pass CI's cargo fmt --check.
No logic changes, only whitespace/formatting.
2026-02-13 16:03:50 -05:00
argenis de la rosa
a5887ad2dc docs+tests: architecture diagram, security docs, 75 new edge-case tests
README:
- Add ASCII architecture flow diagram showing all layers
- Add Security Architecture section (Layer 1: Channel Auth,
  Layer 2: Rate Limiting, Layer 3: Tool Sandbox)
- Update test count to 629

New edge-case tests (75 new):
- SecurityPolicy: command injection (semicolon, backtick, dollar-paren,
  env prefix, newline), path traversal (encoded dots, double-dot in
  filename, null byte, symlink, tilde-ssh, /var/run), rate limiter
  boundaries (exactly-at, zero, high), autonomy+command combos,
  from_config fresh tracker
- Discord: exact match not substring, empty user ID, wildcard+specific,
  case sensitivity, base64 edge cases
- Slack: exact match, empty user ID, case sensitivity, wildcard combo
- Telegram: exact match, empty string, case sensitivity, wildcard combo
- Gateway: first-match-wins, empty value, colon in value, different
  headers, empty request, newline-only request
- Config schema: backward compat (Discord/Slack without allowed_users),
  TOML roundtrip, webhook secret presence/absence

629 tests passing, 0 clippy warnings
2026-02-13 16:00:15 -05:00
argenis de la rosa
05cb353f7f feat: initial release — ZeroClaw v0.1.0
- 22 AI providers (OpenRouter, Anthropic, OpenAI, Mistral, etc.)
- 7 channels (CLI, Telegram, Discord, Slack, iMessage, Matrix, Webhook)
- 5-step onboarding wizard with Project Context personalization
- OpenClaw-aligned system prompt (SOUL.md, IDENTITY.md, USER.md, AGENTS.md, etc.)
- SQLite memory backend with auto-save
- Skills system with on-demand loading
- Security: autonomy levels, command allowlists, cost limits
- 532 tests passing, 0 clippy warnings
2026-02-13 12:19:14 -05:00