feat(agents): inject team members into system prompt

Team agents now see a ## Team Members section listing all teammates with
agent_key, display_name, role, and frontmatter excerpt. This allows the
agent to correctly assign tasks via team_tasks instead of guessing keys.
This commit is contained in:
viettranx committed 2026-03-18 16:38:03 +07:00
1 parent 1ae5c7641a
commit 1b27fa7a9b
3 files changed
+44

No files matched your search

+9
View File
@@ -159,6 +159,14 @@ func (l *Loop) buildMessages(ctx context.Context, history []providers.Message, s
mcpToolDescs = nil
}
// Resolve team members so agent knows who to assign tasks to.
var teamMembers []store.TeamMemberData
if hasTeamTools && l.teamStore != nil && l.agentUUID != uuid.Nil {
if team, _ := l.teamStore.GetTeamForAgent(ctx, l.agentUUID); team != nil {
teamMembers, _ = l.teamStore.ListMembers(ctx, team.ID)
}
}
systemPrompt := BuildSystemPrompt(SystemPromptConfig{
AgentID: l.id,
Model: l.model,
@@ -174,6 +182,7 @@ func (l *Loop) buildMessages(ctx context.Context, history []providers.Message, s
HasSpawn: l.tools != nil && hasSpawn,
HasTeam: hasTeamTools,
TeamWorkspace: tools.ToolTeamWorkspaceFromCtx(ctx),
TeamMembers: teamMembers,
HasSkillSearch: hasSkillSearch,
HasSkillManage: l.skillEvolve && hasSkillManage,
HasMCPToolSearch: hasMCPToolSearch,
+7
View File
@@ -6,6 +6,7 @@ import (
"strings"
"github.com/nextlevelbuilder/goclaw/internal/bootstrap"
"github.com/nextlevelbuilder/goclaw/internal/store"
"github.com/nextlevelbuilder/goclaw/internal/tools"
)
@@ -35,6 +36,7 @@ type SystemPromptConfig struct {
HasSpawn bool // spawn tool available?
HasTeam bool // agent belongs to a team? (skips generic spawn section)
TeamWorkspace string // absolute path to team shared workspace (empty if not in team)
TeamMembers []store.TeamMemberData // team member roster for task assignment
ContextFiles []bootstrap.ContextFile // bootstrap files for # Project Context
ExtraPrompt string // extra system prompt (subagent context, etc.)
AgentType string // "open" or "predefined" — affects context file framing
@@ -225,6 +227,11 @@ func BuildSystemPrompt(cfg SystemPromptConfig) string {
lines = append(lines, buildTeamWorkspaceSection(cfg.TeamWorkspace)...)
}
// 6.4. ## Team Members — inject roster so agent knows who to assign tasks to
if !cfg.IsBootstrap && len(cfg.TeamMembers) > 0 {
lines = append(lines, buildTeamMembersSection(cfg.TeamMembers)...)
}
// 6.5 ## Sandbox (matching TS sandboxInfo section) — skip during bootstrap
if !cfg.IsBootstrap && cfg.SandboxEnabled {
lines = append(lines, buildSandboxSection(cfg)...)
+28
View File
@@ -8,6 +8,7 @@ import (
"time"
"github.com/nextlevelbuilder/goclaw/internal/bootstrap"
"github.com/nextlevelbuilder/goclaw/internal/store"
)
// mcpToolDescMaxLen is the max character length for MCP tool descriptions
@@ -377,3 +378,30 @@ func buildTeamWorkspaceSection(teamWsPath string) []string {
"",
}
}
// buildTeamMembersSection lists team members so the agent knows who to assign tasks to.
func buildTeamMembersSection(members []store.TeamMemberData) []string {
lines := []string{
"## Team Members",
"",
"Your team (use agent_key as assignee in team_tasks):",
}
for _, m := range members {
entry := fmt.Sprintf("- %s (%s) [%s]", m.AgentKey, m.DisplayName, m.Role)
if m.Frontmatter != "" {
fm := m.Frontmatter
if len([]rune(fm)) > 80 {
fm = string([]rune(fm)[:80]) + "…"
}
entry += " — " + fm
}
lines = append(lines, entry)
}
lines = append(lines,
"",
"When creating tasks with team_tasks, set assignee to the agent_key of the best-suited member.",
"Do NOT invent agent keys — only use the keys listed above.",
"",
)
return lines
}