Commit Graph
10 Commits
Author SHA1 Message Date
Nikolas de Hor 4cbd857250 fix: handle edge cases in message splitting and send failure
- _split_message: return empty list for empty/None content instead
  of a list with one empty string (Discord rejects empty content)
- _split_message: use pos <= 0 fallback to prevent empty chunks
  when content starts with a newline or space
- _send_payload: return bool to indicate success/failure
- send: abort remaining chunks when a chunk fails to send,
  preventing partial/corrupted message delivery
2026-02-20 10:09:04 -03:00
Nikolas de Hor f19baa8fc4 fix: convert remaining f-string logger calls to loguru native format
Follow-up to #864. Three f-string logger calls in base.py and dingtalk.py
were missed in the original sweep. These can cause KeyError if interpolated
values contain curly braces, since loguru interprets them as format placeholders.
2026-02-20 10:01:38 -03:00
Nikolas de Hor 73530d51ac fix: store session key in JSONL metadata to avoid lossy filename reconstruction
list_sessions() previously reconstructed the session key by replacing all
underscores in the filename with colons. This is lossy: a key like
'cli:user_name' became 'cli:user:name' after round-tripping.

Now the actual key is persisted in the metadata line during save() and read
back in list_sessions(). Legacy files without the key field fall back to
replacing only the first underscore, which handles the common channel:chat_id
pattern correctly.

Closes #899
2026-02-20 09:57:11 -03:00
Nikolas de Hor 4c75e1673f fix: split Discord messages exceeding 2000-character limit
Discord's API rejects messages longer than 2000 characters with HTTP 400.
Previously, long agent responses were silently lost after retries exhausted.

Adds _split_message() (matching Telegram's approach) to chunk content at
line boundaries before sending. Only the first chunk carries the reply
reference. Retry logic extracted to _send_payload() for reuse across chunks.

Closes #898
2026-02-20 09:55:22 -03:00
Nikolas de Hor 53b83a38e2 fix: use loguru native formatting to prevent KeyError on messages containing curly braces
Closes #857
2026-02-19 17:19:36 -03:00
Nikolas de Hor c86dbc9f45 fix: wait for killed process after shell timeout to prevent fd leaks
When a shell command times out, process.kill() is called but the
process object was never awaited after that. This leaves subprocess
pipes undrained and file descriptors open. If many commands time out,
fd leaks accumulate.

Add a bounded wait (5s) after kill to let the process fully terminate
and release its resources.
2026-02-19 10:27:11 -03:00
Nikolas de Hor 1b49bf9602 fix: avoid duplicate messages on retry and reset final_content
Address review feedback:
- Remove on_progress call for interim text to prevent duplicate
  messages when the model simply answers a direct question
- Reset final_content to None before continue to avoid stale
  interim text leaking as the final response on empty retry

Closes #705
2026-02-19 10:26:49 -03:00
Nikolas de Hor 464352c664 fix: allow one retry for models that send interim text before tool calls
Some LLM providers (MiniMax, Gemini Flash, GPT-4.1, etc.) send an
initial text-only response like "Let me investigate..." before actually
making tool calls. The agent loop previously broke immediately on any
text response without tool calls, preventing these models from ever
using tools.

Now, when the model responds with text but hasn't used any tools yet,
the loop forwards the text as progress to the user and gives the model
one additional iteration to make tool calls. This is limited to a
single retry to prevent infinite loops.

Closes #705
2026-02-18 21:31:12 -03:00
Nikolas de Hor 33d760d312 fix: handle /help command directly in Telegram, bypassing ACL check
The /help command was routed through _forward_command → _handle_message
→ is_allowed(), which denied access to users not in the allowFrom list.
Since /help is purely informational, it should be accessible to all
users — similar to how /start already works with its own handler.

Add a dedicated _on_help handler that replies directly without going
through the message bus access control.

Closes #687
2026-02-18 21:31:11 -03:00
Nikolas de Hor 107a380e61 fix: prevent duplicate memory consolidation tasks per session
Add a `_consolidating` set to track which sessions have an active
consolidation task. Skip creating a new task if one is already in
progress for the same session key, and clean up the flag when done.

This prevents the excessive API calls reported when messages exceed
the memory_window threshold — previously every single message after
the threshold triggered a new background consolidation.

Closes #751
2026-02-18 21:31:09 -03:00