Addresses automated review: document that the guard is an intentional hard group-only switch (allowlisted DMs blocked by design) and that str() guards a None sender_id. Comment-only.
Co-Authored-By: Claude <noreply@anthropic.com>
In group chats, prefix the outbound markdown reply with an H1 naming the sender (# @<nick>) so the addressed user can spot it in a busy group. Private replies are sent verbatim.
Visual only: DingTalk markdown robot messages do not push real @ notifications (that would require staffId plumbing and a different message type). sender_name is read from OutboundMessage.metadata, which the agent loop already propagates from inbound metadata.
Co-Authored-By: Claude <noreply@anthropic.com>
Add a `disable_private_chat` config flag (JSON alias `disablePrivateChat`,
default False) to the DingTalk channel. When enabled, any non-group (1:1)
message is rejected with a Chinese notice directing the user to group chat
("该机器人未开启私聊,请在群聊中与我对话。") before permission/pairing logic
runs, so even allowlisted senders are redirected. Group messages are
unaffected.
Co-Authored-By: Claude <noreply@anthropic.com>
Before this change, idle compaction is triggered every 1 second
if the incoming message stream is idle.
When triggered, it enumerates all session files, loads and parses them,
and then checks their expiration.
This becomes too CPU-intensive, especially on low-power devices like Raspberry Pi.
It's unlikely that you actually need to compact every second over the long time.
This change adds a configurable throttling for idle-compaction.
Default behavior is unchanged.
Reset both the recovered segments and retry budget whenever injected input starts a new logical answer. Cover fatal tool-error boundaries and rename the prompt test module so pytest can collect the full suite.