* docs: add brainstorm report for discord guild-user memory
* docs: update brainstorm report with corrected root cause analysis
* feat(discord): per-user memory scope in guild channels
Fixes shared USER.md between guild members by scoping userID to
"guild:{guildID}:user:{senderID}" for Discord group messages.
Updates all group-context prefix checks (write permissions, writer
cache, cron peer kind, history filter) to include the new guild: prefix.
Closes#165
Cron jobs ran in isolated sessions with no context about who requested
them or where to deliver responses. The agent would misroute responses
(e.g., using team_message instead of replying to the original chat).
- Inject ExtraSystemPrompt with job name, requester ID, and delivery
target so the agent knows to produce content directly
- Pass client.UserID() in Web UI cron.create instead of empty string
* fix(gateway): extract media forwarding helper and fix group writer cron/media gaps
- Extract appendMediaToOutbound() helper to deduplicate media attachment conversion across all outbound paths
- Add media forwarding to cron job handler, handoff announce, and teammate message flows
- Fix silent reply suppression to allow media-only responses (no text content)
- Skip group writer refusal prompt for system-initiated runs (cron, delegate, subagent) with empty senderID
* fix(agent): protect identity files in system-initiated group writer runs
- Move writer list lookup before senderID check so cron/delegate/subagent
runs still load group writer config
- Inject file protection prompt for system-initiated runs instead of
skipping entirely, preventing modification of SOUL.md, IDENTITY.md,
AGENTS.md, and USER.md
- Retain fail-open behavior when writer list is unavailable
---------
Co-authored-by: Nam Nguyen Ngoc <namnn.0911@gmail.com>
* fix(agent): use ChannelType in system prompt for proper channel context
The system prompt was using the channel instance name (e.g. "zep-lao") instead
of the platform type (e.g. "zalo_personal"), causing the LLM to not understand
which messaging platform it's running on. This led to context confusion where
the bot would ask users which channel to send to instead of using the current one.
Changes:
- Add ChannelType field to RunRequest and SystemPromptConfig
- Thread channel type from consumer/cron → agent loop → system prompt
- Add WithToolChannelType/ToolChannelTypeFromCtx for tool context
- Register channel types for both config-based and DB-loaded instances
- Fix Zalo group thread type detection with approvedGroups cache
- Update cron handler to resolve channel type for cron-triggered runs
* refactor(channels): add Type() to Channel interface, remove channelTypes map
Move channel type from a separate map in Manager to the Channel interface
itself. BaseChannel.Type() falls back to Name() for config-based channels
where name == type. Extracts resolveChannelType helper to DRY up 6
repeated resolution blocks across consumer and cron handlers.
* feat(zalo): add pending group history for conversation context
Zalo personal groups now record non-@mentioned messages in a ring buffer
(default 50, configurable via history_limit). When the bot IS mentioned,
pending history is flushed as context — matching Telegram/Discord/Feishu.
Separated mention gating from policy gating in checkGroupPolicy for
cleaner control flow.
- Override LLM-provided channel ID with context value to prevent
misrouted deliveries (LLM was confusing guild ID with channel ID)
- Send cron reminder message directly instead of agent response
so reminders appear as bot notifications in Discord