125 Commits

Author SHA1 Message Date
Re-bin
b0a5435b87 refactor(llm): share transient retry across agent paths 2026-03-10 10:10:37 +00:00
Re-bin
46b31ce7e7 Merge remote-tracking branch 'origin/main' into pr-1512 2026-03-10 09:40:48 +00:00
Re-bin
43fc59da00 fix: hide internal reasoning in progress 2026-03-07 14:53:14 +00:00
VITOHJL
cf76011c1a fix: hide reasoning_content from user progress updates 2026-03-07 17:09:59 +08:00
Re-bin
d32c6f946c fix(telegram): pin ptb>=22.6, fix double progress, clean up stale hatch config 2026-03-05 15:17:30 +00:00
Sergio Sánchez Vallés
33f59d8a37
fix(agent): separate reasoning and tool hints to respect channel config 2026-03-05 00:45:15 +01:00
Sergio Sánchez Vallés
c27d2b1522
fix(agent): prevent tool hints from overwriting reasoning in streaming drafts 2026-03-05 00:33:27 +01:00
Sergio Sánchez Vallés
61f658e045
add reasoning content to on progress message 2026-03-04 12:11:18 +01:00
Kiplangatkorir
d0c6479186 feat: add LLM retry with exponential backoff for transient errors
provider.chat() had no retry logic — a transient 429 rate limit,
502 gateway error, or network timeout would permanently fail the
entire message. For a system running cron jobs and heartbeats 24/7,
even a brief provider blip causes lost tasks.

Adds _chat_with_retry() that:
- Retries up to 3 times with 1s/2s/4s exponential backoff
- Only retries transient errors (429, 5xx, timeout, connection)
- Returns immediately on permanent errors (400, 401, etc.)
- Falls through to the final attempt if all retries exhaust
2026-03-04 11:20:50 +03:00
Re-bin
03b83fb79e fix(agent): skip empty multimodal user entries after runtime-context strip 2026-03-03 05:13:17 +00:00
Nikolas de Hor
ad99d5aaa0 fix: merge consecutive user messages into single message
Some LLM providers (Minimax, Dashscope) strictly reject consecutive
messages with the same role. build_messages() was emitting two separate
user messages back-to-back: the runtime context and the actual user
content.

Merge them into a single user message, handling both plain text and
multimodal (image) content. Update _save_turn() to strip the runtime
context prefix from the merged message when persisting to session
history.

Fixes #1414
Fixes #1344
2026-03-03 00:59:58 -03:00
chengyongru
82be2ae1a5 feat(tool): add web search proxy 2026-03-01 16:51:54 +08:00
Re-bin
5ca386ebf5 fix: preserve reasoning_content and thinking_blocks in session history 2026-02-28 17:37:12 +00:00
Re-bin
f9d72e2e74 feat: add reasoning_effort config to enable LLM thinking mode 2026-02-28 17:18:05 +00:00
Re-bin
8410f859f7 refactor: use WeakValueDictionary for consolidation locks — auto-cleanup, no manual pop 2026-02-28 08:26:55 +00:00
Re-bin
89c0f4cae9 refactor: compress tool hint args handling to two lines 2026-02-28 08:06:20 +00:00
Re-bin
90eb90335a Merge remote-tracking branch 'origin/main' into pr-1294 2026-02-28 08:01:04 +00:00
Re-bin
0036116e0b fix: filter empty assistant messages in _save_turn instead of patching at send time 2026-02-28 07:35:07 +00:00
Nikolas de Hor
66063abb8c fix: prevent session poisoning from null/error LLM responses
When an LLM returns content: null on a plain assistant message (no
tool_calls), the null gets saved to session history and causes
permanent 400 errors on every subsequent request.

- Sanitize None content on plain assistant messages to "(empty)" in
  _sanitize_empty_content(), matching the existing empty-string handling
- Skip persisting error responses (finish_reason="error") to the
  message history in _run_agent_loop(), preventing poison loops

Closes #1303
2026-02-28 00:57:08 -03:00
Michael-lhh
11f1880c02 fix: handle list-type tool arguments in _tool_hint
Some models (e.g., Kimi K2.5 via OpenRouter) return tool call arguments
as a list instead of a dict. This caused an AttributeError when trying
to call .values() on the list.

The fix checks if arguments is a list and extracts the first element
before accessing .values().

Made-with: Cursor
2026-02-28 00:18:00 +08:00
Re-bin
bc558d0592 refactor: merge user-role branches in _save_turn 2026-02-27 10:07:22 +00:00
Re-bin
6bdb590028 Merge remote-tracking branch 'origin/main' into pr-1222 2026-02-27 09:57:45 +00:00
Re-bin
ec8dee802c refactor: simplify message tool suppress and inline consolidation locks 2026-02-27 02:39:38 +00:00
Re-bin
29e6709e26 refactor: simplify message tool suppress — bool check instead of target tracking 2026-02-27 02:27:18 +00:00
Re-bin
ac1c40db91 Merge remote-tracking branch 'origin/main' into pr-1206 2026-02-27 02:17:04 +00:00
Kim
286e67ddef style(agent): remove inline comment in runtime-context history filter 2026-02-26 14:21:44 +08:00
Kim
45ae410f05 fix(agent): do not persist runtime context metadata in session history 2026-02-26 14:12:37 +08:00
Re-bin
988a85d8de refactor: optimize matrix channel — optional deps, trim comments, simplify methods 2026-02-26 03:04:01 +00:00
Re-bin
a1440cf4cb refactor: inline base64 image stripping in _save_turn 2026-02-26 02:43:45 +00:00
Re-bin
0a9bb1d8df Merge remote-tracking branch 'origin/main' into pr-1191 2026-02-26 02:39:53 +00:00
Re-bin
3902e31165 refactor: drop redundant tool_calls=None in final assistant message 2026-02-26 02:33:38 +00:00
Re-bin
23b9880478 Merge remote-tracking branch 'origin/main' into pr-1198 2026-02-26 02:29:45 +00:00
Re-bin
cdbede2fa8 refactor: simplify /stop dispatch, inline commands, trim verbose docstrings 2026-02-25 17:04:08 +00:00
chengyongru
fafd8d4eb8 fix(agent): only suppress final reply when message tool sends to same target
A refactoring in commit 132807a introduced a regression where the final
response was silently discarded whenever the message tool was used,
regardless of the target. This restored the original logic from PR #832
that only suppresses the final reply when the message tool sends to the
same (channel, chat_id) as the original message.

Changes:
- message.py: Replace _sent_in_turn: bool with _turn_sends: list[tuple]
  to track actual send targets, add get_turn_sends() method
- loop.py: Check if (msg.channel, msg.chat_id) is in sent_targets before
  suppressing final reply. Also move the "Response to" log after the
  suppress check to avoid misleading logs.
- Add unit tests for the suppress logic

This ensures:
- Email sent via message tool → Feishu still gets confirmation
- Message tool sends to same Feishu chat → No duplicate (suppressed)
2026-02-26 00:32:48 +08:00
Re-bin
149f26af32 Merge branch 'main' into pr-1180 2026-02-25 16:16:18 +00:00
VITOHJL
f2e0847d64 Fix assistant messages without tool calls not being saved to session 2026-02-25 23:27:41 +08:00
dxtime
6aed4265b7 Fix: The base64 images are stored in the session history, causing context overflow. 2026-02-25 20:58:59 +08:00
coldxiangyu
4768b9a09d fix: parallel subagent cancellation + register task before lock
- cancel_by_session: use asyncio.gather for parallel cancellation
  instead of sequential await per task
- _dispatch: register in _active_tasks before acquiring lock so /stop
  can find queued tasks (synced from #1179)
2026-02-25 18:21:46 +08:00
coldxiangyu
2466b8b843 feat: /stop cancels spawned subagents via session tracking
- SubagentManager tracks _session_tasks: session_key -> {task_id, ...}
- cancel_by_session() cancels all subagents for a session
- SpawnTool passes session_key through to SubagentManager
- /stop response reports subagent cancellation count
- Cleanup callback removes from both _running_tasks and _session_tasks

Builds on #1179
2026-02-25 17:53:54 +08:00
coldxiangyu
3c12efa728 feat: extensible command system + task-based dispatch with /stop
- Add commands.py with CommandDef registry, parse_command(), get_help_text()
- Refactor run() to dispatch messages as asyncio tasks (non-blocking)
- /stop is an 'immediate' command: handled inline, cancels active task
- Global processing lock serializes message handling (safe for shared state)
- _pending_tasks set prevents GC of dispatched tasks before lock acquisition
- _dispatch() registers/clears active tasks, catches CancelledError gracefully
- /help now auto-generated from COMMANDS registry

Closes #849
2026-02-25 17:51:00 +08:00
aiguozhi123456
07ae82583b fix: pass path_append from config to ExecTool 2026-02-24 12:31:18 +00:00
Re-bin
d9462284e1 improve agent reliability: behavioral constraints, full tool history, error hints 2026-02-23 09:13:08 +00:00
Re-bin
491739223d fix: lower default temperature from 0.7 to 0.1 2026-02-23 08:24:53 +00:00
Re-bin
df2c837e25 feat(channels): split send_progress into send_progress + send_tool_hints 2026-02-23 07:12:41 +00:00
Re-bin
bc32e85c25 fix(memory): trigger consolidation by unconsolidated count, not total 2026-02-23 05:51:44 +00:00
Re-bin
b13d7f853e fix(agent): make tool hint a fallback when no content in on_progress 2026-02-22 17:17:35 +00:00
Re-bin
1cfcc647b7 fix(loop): resolve conflicts with main and improve /new handler 2026-02-22 17:11:59 +00:00
Re-bin
0b30f514b4 style(loop): compact empty outbound message construction 2026-02-21 08:27:49 +00:00
Re-bin
012a5e78e5 Merge branch 'main' into pr-926 2026-02-21 08:21:17 +00:00
Re-bin
ab026c5131 refactor: extract memory consolidation to MemoryStore, slim down AgentLoop 2026-02-21 08:14:46 +00:00