feat(agent): include platform self identities in system prompts

Give bots their known per-channel account handles in the system prompt so they can reason about platform-specific self references consistently. Reuse persisted channel self_identity data across chat, discuss, schedule, heartbeat, and subagent prompts.
This commit is contained in:
Acbox
2026-04-16 16:44:29 +08:00
parent e0fc2f514e
commit 9f10033f63
13 changed files with 409 additions and 19 deletions
+15 -12
View File
@@ -47,6 +47,7 @@ func init() {
"_memory": mustReadPrompt("prompts/_memory.md"),
"_tools": mustReadPrompt("prompts/_tools.md"),
"_contacts": mustReadPrompt("prompts/_contacts.md"),
"_identities": mustReadPrompt("prompts/_identities.md"),
"_schedule_task": mustReadPrompt("prompts/_schedule_task.md"),
"_subagent": mustReadPrompt("prompts/_subagent.md"),
}
@@ -144,23 +145,25 @@ func GenerateSystemPrompt(params SystemPromptParams) string {
tmpl := selectSystemTemplate(params.SessionType)
return render(tmpl, map[string]string{
"home": home,
"currentTime": now.Format(time.RFC3339),
"timezone": timezoneName,
"basicTools": strings.Join(basicTools, "\n"),
"skillsSection": skillsSection,
"fileSections": fileSections,
"home": home,
"currentTime": now.Format(time.RFC3339),
"timezone": timezoneName,
"basicTools": strings.Join(basicTools, "\n"),
"skillsSection": skillsSection,
"platformIdentitiesSection": strings.TrimSpace(params.PlatformIdentitiesSection),
"fileSections": fileSections,
})
}
// SystemPromptParams holds all inputs for system prompt generation.
type SystemPromptParams struct {
SessionType string
Skills []SkillEntry
Files []SystemFile
Now time.Time
Timezone string
SupportsImageInput bool
SessionType string
Skills []SkillEntry
Files []SystemFile
Now time.Time
Timezone string
SupportsImageInput bool
PlatformIdentitiesSection string
}
// GenerateSchedulePrompt builds the user message for a scheduled task trigger.
+43
View File
@@ -0,0 +1,43 @@
package agent
import (
"strings"
"testing"
"time"
)
func TestGenerateSystemPromptIncludesPlatformIdentitiesInChat(t *testing.T) {
t.Parallel()
prompt := GenerateSystemPrompt(SystemPromptParams{
SessionType: "chat",
Now: time.Unix(1, 0).UTC(),
Timezone: "UTC",
PlatformIdentitiesSection: "## Platform Identities\n\n<identity channel=\"telegram\" username=\"@memoh\"/>",
})
if !strings.Contains(prompt, "## Platform Identities") {
t.Fatalf("expected platform identities heading in prompt")
}
if !strings.Contains(prompt, `<identity channel="telegram" username="@memoh"/>`) {
t.Fatalf("expected platform identity XML in prompt")
}
}
func TestGenerateSystemPromptIncludesPlatformIdentitiesInDiscuss(t *testing.T) {
t.Parallel()
prompt := GenerateSystemPrompt(SystemPromptParams{
SessionType: "discuss",
Now: time.Unix(1, 0).UTC(),
Timezone: "UTC",
PlatformIdentitiesSection: "## Platform Identities\n\n<identity channel=\"discord\" username=\"@memoh\"/>",
})
if !strings.Contains(prompt, "## Platform Identities") {
t.Fatalf("expected platform identities heading in discuss prompt")
}
if !strings.Contains(prompt, `<identity channel="discord" username="@memoh"/>`) {
t.Fatalf("expected platform identity XML in discuss prompt")
}
}
+1
View File
@@ -0,0 +1 @@
{{platformIdentitiesSection}}
+2
View File
@@ -43,6 +43,8 @@ You are in **chat mode** — your text output IS your reply. Whatever you write
{{include:_contacts}}
{{include:_identities}}
## Message Format
User messages are wrapped in `<message>` XML tags with metadata attributes:
+2
View File
@@ -60,6 +60,8 @@ Not every message needs a response. Staying silent is valid and often appropriat
{{include:_contacts}}
{{include:_identities}}
## Message Format
Chat history appears as XML in your conversation. Each message looks like:
@@ -20,6 +20,8 @@ You are in **heartbeat mode** — a periodic system-triggered check. There is no
{{include:_contacts}}
{{include:_identities}}
## The HEARTBEAT_OK Contract
- If nothing needs attention, reply with exactly `HEARTBEAT_OK`.
@@ -20,6 +20,8 @@ You are in **schedule mode** — executing a scheduled task. There is no active
{{include:_contacts}}
{{include:_identities}}
## How to Deliver Results
Use `send` to deliver results to the intended channel — there is no active conversation to reply to. Use `get_contacts` to find the right target.
@@ -18,3 +18,5 @@ You have access to:
- Do NOT create schedules or manage memory
- Keep private data private
- Don't run destructive commands without necessity
{{include:_identities}}