diff --git a/internal/agent/resolver_helpers.go b/internal/agent/resolver_helpers.go index 1bb1f983..94d92cd7 100644 --- a/internal/agent/resolver_helpers.go +++ b/internal/agent/resolver_helpers.go @@ -85,7 +85,9 @@ func buildTeamMD(team *store.TeamData, members []store.TeamMemberData, selfID uu sb.WriteString("- Always specify `assignee` — match member expertise from the list above\n") sb.WriteString("- **Check task board first** — ALWAYS call `team_tasks(action=\"list\")` before creating tasks. The system blocks creation if you skip this step\n") sb.WriteString("- Create all tasks first, then briefly tell the user what you delegated\n") - sb.WriteString("- Do NOT add confirmations (\"Done!\", \"Got it!\") — just state what was assigned\n") + sb.WriteString("- Do NOT say \"done\", \"xong\", \"finished\", or any completion language after delegating — delegation is NOT completion. Only report completion when ALL task results have been delivered to the user\n") + sb.WriteString("- Do NOT phrase delegation as a question or request (\"nha?\", \"nhé?\", \"okay?\"). State it declaratively: \"Đã giao X cho Y\" not \"Để em giao cho Y nha anh\"\n") + sb.WriteString("- After creating tasks, briefly announce what was delegated and to whom — then STOP. Do not add filler, confirmations, or closing remarks\n") sb.WriteString("- Results arrive automatically — do NOT present partial results\n") sb.WriteString("- **Prefer delegation** — if the user asks to involve the team, delegate tasks immediately. Do NOT do the work yourself first then hand off to members\n") sb.WriteString("- **Do NOT block on completed tasks** — if a dependency task is already done, pass its result in the new task's description instead of using blocked_by\n") @@ -113,7 +115,6 @@ func buildTeamMD(team *store.TeamData, members []store.TeamMemberData, selfID uu sb.WriteString("The system auto-dispatches blocked tasks when their dependencies complete.\n") sb.WriteString("Do NOT wait for results to create follow-up tasks — plan the full pipeline ahead.\n\n") sb.WriteString("After results: present to user (if done) or continue orchestrating.\n") - sb.WriteString("Vary announcement phrasing between delegation rounds.\n") sb.WriteString("\n## Follow-up Reminders\n\n") sb.WriteString("When you need user input/decision: create+claim task, then `ask_user` with text=. ONLY use when you have a question for the user — NOT for waiting on teammates or status updates.\n") @@ -125,7 +126,8 @@ func buildTeamMD(team *store.TeamData, members []store.TeamMemberData, selfID uu sb.WriteString("Rules:\n") sb.WriteString("- Always specify `assignee` when creating tasks\n") sb.WriteString("- Create all tasks first, then briefly tell the user what you delegated\n") - sb.WriteString("- Do NOT add confirmations (\"Done!\", \"Got it!\") — just state what was assigned\n") + sb.WriteString("- Do NOT say \"done\", \"xong\", \"finished\", or any completion language after delegating — delegation is NOT completion\n") + sb.WriteString("- Do NOT phrase delegation as a question or request (\"nha?\", \"nhé?\", \"okay?\"). State it declaratively\n") sb.WriteString("- Results arrive automatically — do NOT present partial results\n") } diff --git a/internal/agent/systemprompt.go b/internal/agent/systemprompt.go index 52f431f7..db1e9907 100644 --- a/internal/agent/systemprompt.go +++ b/internal/agent/systemprompt.go @@ -250,6 +250,11 @@ func BuildSystemPrompt(cfg SystemPromptConfig) string { lines = append(lines, hint...) } + // 9.6. Group chat reply hint — remind bot to check reply content, not just reply context + if cfg.PeerKind == "group" { + lines = append(lines, buildGroupChatReplyHint()...) + } + // 10. Extra system prompt (wrapped in tags for context isolation) if cfg.ExtraPrompt != "" { header := "## Additional Context" diff --git a/internal/agent/systemprompt_sections.go b/internal/agent/systemprompt_sections.go index e7858554..8f263fd9 100644 --- a/internal/agent/systemprompt_sections.go +++ b/internal/agent/systemprompt_sections.go @@ -262,6 +262,18 @@ func buildChannelFormattingHint(channelType string) []string { } } +// buildGroupChatReplyHint returns guidance for group chats about not responding +// to replies that are directed at other people, not the bot. +func buildGroupChatReplyHint() []string { + return []string{ + "## Reply Context", + "", + "A reply to your message does NOT always mean they are talking to you.", + "If someone replies to your message but the content addresses or @mentions another person and doesn't ask you anything, use NO_REPLY — it's not your conversation.", + "", + } +} + // personaFileNames are the context files that define agent identity/behavior. // These are injected early in the system prompt (primacy zone) and reinforced // at the end (recency zone) to prevent persona drift in long conversations. diff --git a/internal/bootstrap/templates/AGENTS.md b/internal/bootstrap/templates/AGENTS.md index e03fff10..4f452478 100644 --- a/internal/bootstrap/templates/AGENTS.md +++ b/internal/bootstrap/templates/AGENTS.md @@ -57,6 +57,7 @@ You start fresh each session. Use tools to maintain continuity: - The conversation flows fine without you - Adding a message would interrupt the vibe + **The rule:** Humans don't respond to every message. Neither should you. Quality > quantity. **Avoid the triple-tap:** Don't respond multiple times to the same message. One thoughtful response beats three fragments.