chore(teams): remove deprecated delegation tools

Remove delegate_search, evaluate_loop, handoff from:
- Seed data, system prompt, i18n keys/catalogs, channel events
- Consumer handler (handleHandoffAnnounce), handoff route lookup
- HandoffRouteData struct + PG implementation
- Protocol events, MCP bridge comment
- Web UI locale files (en/vi/zh)
This commit is contained in:
viettranx committed 2026-03-16 22:46:18 +07:00
1 parent 514c5e0bfc
commit 3f2b6e258e
17 files changed
+38 -205

No files matched your search

-14
View File
@@ -106,20 +106,6 @@ func builtinToolSeedData() []store.BuiltinToolDef {
{Name: "use_skill", DisplayName: "Use Skill", Description: "Activate a skill to use its specialized capabilities (tracing marker)", Category: "skills", Enabled: true},
{Name: "publish_skill", DisplayName: "Publish Skill", Description: "Register a skill directory (created via skill-creator) in the system database, making it discoverable and grantable to agents", Category: "skills", Enabled: true},
// delegation (deprecated — team_tasks is the coordination mechanism now)
{Name: "delegate_search", DisplayName: "Delegate Search", Description: "Search for available delegation targets by keyword (deprecated)", Category: "delegation", Enabled: false,
Requires: []string{"managed_mode", "agent_links"},
Metadata: json.RawMessage(`{"deprecated":true}`),
},
{Name: "evaluate_loop", DisplayName: "Evaluate Loop", Description: "Run a generate→evaluate→revise loop between two agents (deprecated)", Category: "delegation", Enabled: false,
Requires: []string{"managed_mode", "agent_links"},
Metadata: json.RawMessage(`{"deprecated":true}`),
},
{Name: "handoff", DisplayName: "Handoff", Description: "Transfer the conversation to another agent (deprecated)", Category: "delegation", Enabled: false,
Requires: []string{"managed_mode", "agent_links"},
Metadata: json.RawMessage(`{"deprecated":true}`),
},
// teams
{Name: "team_tasks", DisplayName: "Team Tasks", Description: "View, create, update, and complete tasks on the team task board", Category: "teams", Enabled: true,
Requires: []string{"managed_mode", "teams"},
-3
View File
@@ -101,9 +101,6 @@ func consumeInboundMessages(ctx context.Context, msgBus *bus.MessageBus, agents
if handleDelegateAnnounce(ctx, msg, cfg, sched, channelMgr, msgBus, getAnnounceMu) {
continue
}
if handleHandoffAnnounce(ctx, msg, cfg, sched, channelMgr, msgBus) {
continue
}
if handleTeammateMessage(ctx, msg, cfg, sched, channelMgr, teamStore, agentStore, msgBus, postTurn, &taskRunSessions) {
continue
}
+36 -89
View File
@@ -309,88 +309,6 @@ func handleDelegateAnnounce(
return true
}
// handleHandoffAnnounce processes handoff announce messages: route initial message
// to target agent session using the "delegate" lane.
// Returns true if the message was handled (caller should continue).
func handleHandoffAnnounce(
ctx context.Context,
msg bus.InboundMessage,
cfg *config.Config,
sched *scheduler.Scheduler,
channelMgr *channels.Manager,
msgBus *bus.MessageBus,
) bool {
if !(msg.Channel == tools.ChannelSystem && strings.HasPrefix(msg.SenderID, "handoff:")) {
return false
}
origChannel := msg.Metadata["origin_channel"]
origPeerKind := msg.Metadata["origin_peer_kind"]
origLocalKey := msg.Metadata["origin_local_key"]
origChannelType := resolveChannelType(channelMgr, origChannel)
targetAgent := msg.AgentID
if targetAgent == "" {
targetAgent = cfg.ResolveDefaultAgentID()
}
if origPeerKind == "" {
origPeerKind = string(sessions.PeerDirect)
}
if origChannel == "" || msg.ChatID == "" {
slog.Warn("handoff announce: missing origin", "sender", msg.SenderID)
return true
}
sessionKey := sessions.BuildScopedSessionKey(targetAgent, origChannel, sessions.PeerKind(origPeerKind), msg.ChatID, cfg.Sessions.Scope, cfg.Sessions.DmScope, cfg.Sessions.MainKey)
sessionKey = overrideSessionKeyFromLocalKey(sessionKey, origLocalKey, targetAgent, origChannel, msg.ChatID, origPeerKind)
slog.Info("handoff announce → scheduler (delegate lane)",
"handoff", msg.SenderID,
"to", targetAgent,
"session", sessionKey,
)
announceUserID := msg.UserID
if origPeerKind == string(sessions.PeerGroup) && msg.ChatID != "" {
announceUserID = fmt.Sprintf("group:%s:%s", origChannel, msg.ChatID)
}
outMeta := buildAnnounceOutMeta(origLocalKey)
outCh := sched.Schedule(ctx, scheduler.LaneDelegate, agent.RunRequest{
SessionKey: sessionKey,
Message: msg.Content,
Channel: origChannel,
ChannelType: origChannelType,
ChatID: msg.ChatID,
PeerKind: origPeerKind,
LocalKey: origLocalKey,
UserID: announceUserID,
RunID: fmt.Sprintf("handoff-%s", msg.Metadata["handoff_id"]),
Stream: false,
})
go func(origCh, chatID string, meta map[string]string) {
outcome := <-outCh
if outcome.Err != nil {
slog.Error("handoff announce: agent run failed", "error", outcome.Err)
return
}
if (outcome.Result.Content == "" && len(outcome.Result.Media) == 0) || agent.IsSilentReply(outcome.Result.Content) {
return
}
outMsg := bus.OutboundMessage{
Channel: origCh,
ChatID: chatID,
Content: outcome.Result.Content,
Metadata: meta,
}
appendMediaToOutbound(&outMsg, outcome.Result.Media)
msgBus.PublishOutbound(outMsg)
}(origChannel, msg.ChatID, outMeta)
return true
}
// handleTeammateMessage processes teammate messages: bypass debounce, route to target
// agent session using the "delegate" lane, then announce result back to lead.
@@ -548,6 +466,21 @@ func handleTeammateMessage(
if !alreadyTerminal {
toAgent := inMeta["to_agent"]
now := time.Now().UTC().Format("2006-01-02T15:04:05Z")
// Enrich event payload with task details for notifications.
taskSubject := ""
taskNumber := 0
taskChannel := inMeta["origin_channel"]
taskChatID := inMeta["origin_chat_id"]
if currentTask != nil {
taskSubject = currentTask.Subject
taskNumber = currentTask.TaskNumber
if currentTask.Channel != "" {
taskChannel = currentTask.Channel
}
if currentTask.ChatID != "" {
taskChatID = currentTask.ChatID
}
}
if outcome.Err != nil {
if err := teamStore.FailTask(ctx, teamTaskID, teamID, outcome.Err.Error()); err != nil {
slog.Warn("auto-complete: FailTask error", "task_id", teamTaskID, "error", err)
@@ -555,12 +488,17 @@ func handleTeammateMessage(
msgBus.Broadcast(bus.Event{
Name: protocol.EventTeamTaskFailed,
Payload: protocol.TeamTaskEventPayload{
TeamID: teamID.String(),
TaskID: teamTaskID.String(),
Status: store.TeamTaskStatusFailed,
Timestamp: now,
ActorType: "agent",
ActorID: toAgent,
TeamID: teamID.String(),
TaskID: teamTaskID.String(),
TaskNumber: taskNumber,
Subject: taskSubject,
Status: store.TeamTaskStatusFailed,
Reason: outcome.Err.Error(),
Channel: taskChannel,
ChatID: taskChatID,
Timestamp: now,
ActorType: "agent",
ActorID: toAgent,
},
})
}
@@ -580,8 +518,12 @@ func handleTeammateMessage(
Payload: protocol.TeamTaskEventPayload{
TeamID: teamID.String(),
TaskID: teamTaskID.String(),
TaskNumber: taskNumber,
Subject: taskSubject,
Status: store.TeamTaskStatusCompleted,
OwnerAgentKey: toAgent,
Channel: taskChannel,
ChatID: taskChatID,
Timestamp: now,
ActorType: "agent",
ActorID: toAgent,
@@ -865,7 +807,12 @@ func buildTaskBoardSnapshot(ctx context.Context, teamStore store.TeamStore, team
if teamStore == nil || originTraceID == "" {
return ""
}
allTasks, err := teamStore.ListTasks(ctx, teamID, "", store.TeamTaskFilterAll, "", "", chatID, 0)
// Shared workspace: show all tasks across chats.
snapshotChatID := chatID
if team, err := teamStore.GetTeam(ctx, teamID); err == nil && tools.IsSharedWorkspace(team.Settings) {
snapshotChatID = ""
}
allTasks, err := teamStore.ListTasks(ctx, teamID, "", store.TeamTaskFilterAll, "", "", snapshotChatID, 0)
if err != nil || len(allTasks) == 0 {
return ""
}
-9
View File
@@ -43,15 +43,6 @@ func processNormalMessage(
agentID = resolveAgentRoute(cfg, msg.Channel, msg.ChatID, msg.PeerKind)
}
// Check handoff routing override
if teamStore != nil && msg.AgentID == "" {
if route, _ := teamStore.GetHandoffRoute(ctx, msg.Channel, msg.ChatID); route != nil {
agentID = route.ToAgentKey
slog.Info("inbound: handoff route active",
"channel", msg.Channel, "chat", msg.ChatID, "to", agentID)
}
}
agentLoop, err := agents.Get(agentID)
if err != nil {
slog.Warn("inbound: agent not found", "agent", agentID, "channel", msg.Channel)
-3
View File
@@ -89,9 +89,6 @@ var coreToolSummaries = map[string]string{
"create_image": "Generate images from text descriptions using AI",
"create_audio": "Generate music or sound effects from text descriptions using AI",
"knowledge_graph_search": "Find people, projects, and their connections — use for relationship questions (who works with whom, project dependencies) that memory_search may miss",
"handoff": "Transfer conversation to another agent (ONLY when user explicitly asks to switch agents — NOT for task delegation)",
"evaluate_loop": "Run a generate→evaluate→revise loop between two agents for quality-critical tasks",
"delegate_search": "Search for agents by expertise to find the right delegation target",
"team_tasks": "Team task board — track progress, manage dependencies (spawn auto-creates delegation tasks)",
"team_message": "Send messages to teammates (progress updates, questions)",
-3
View File
@@ -375,7 +375,6 @@ var toolStatusMap = map[string]string{
"browser": "🌐 Browsing...",
// Delegation & teams
"spawn": "👥 Delegating task...",
"handoff": "🔄 Handing off...",
"team_tasks": "📋 Managing team tasks...",
"team_message": "💬 Sending team message...",
// Sessions
@@ -388,8 +387,6 @@ var toolStatusMap = map[string]string{
"cron": "⏰ Managing schedule...",
"skill_search": "🔍 Searching skills...",
"use_skill": "🧩 Using skill...",
"delegate_search": "🔍 Searching delegates...",
"evaluate_loop": "🔄 Evaluating...",
"mcp_tool_search": "🔌 Searching MCP tools...",
}
+1 -1
View File
@@ -7,7 +7,7 @@ type ctxKey string
const skipHooksKey ctxKey = "skip_hooks"
// WithSkipHooks returns a context that signals hook evaluation should be skipped.
// Used by evaluate_loop and agent evaluator to prevent recursive hook firing.
// Used by agent evaluator to prevent recursive hook firing.
func WithSkipHooks(ctx context.Context, skip bool) context.Context {
return context.WithValue(ctx, skipHooksKey, skip)
}
-3
View File
@@ -169,9 +169,6 @@ func init() {
MsgToolSpawn: "Spawn a subagent for background work or delegate a task to a linked agent",
MsgToolSkillSearch: "Search for available skills by keyword or description to find relevant capabilities",
MsgToolUseSkill: "Activate a skill to use its specialized capabilities (tracing marker)",
MsgToolDelegateSearch: "Search for available delegation targets by keyword when there are too many linked agents to list",
MsgToolEvaluateLoop: "Run a generate→evaluate→revise loop between two agents for quality-critical output",
MsgToolHandoff: "Transfer the conversation to another agent — the user will talk directly to that agent",
MsgToolTeamTasks: "View, create, update, and complete tasks on the team task board",
MsgToolTeamMessage: "Send a direct message or broadcast to teammates in the agent team",
})
-3
View File
@@ -169,9 +169,6 @@ func init() {
MsgToolSpawn: "Tạo subagent chạy nền hoặc giao việc cho agent đã liên kết",
MsgToolSkillSearch: "Tìm kiếm kỹ năng có sẵn theo từ khóa hoặc mô tả",
MsgToolUseSkill: "Kích hoạt kỹ năng để sử dụng khả năng chuyên biệt (đánh dấu tracing)",
MsgToolDelegateSearch: "Tìm kiếm agent mục tiêu ủy quyền theo từ khóa khi có quá nhiều agent liên kết",
MsgToolEvaluateLoop: "Chạy vòng lặp tạo→đánh giá→sửa đổi giữa hai agent cho nội dung cần chất lượng cao",
MsgToolHandoff: "Chuyển cuộc hội thoại sang agent khác — người dùng sẽ nói chuyện trực tiếp với agent đó",
MsgToolTeamTasks: "Xem, tạo, cập nhật và hoàn thành tác vụ trên bảng tác vụ nhóm",
MsgToolTeamMessage: "Gửi tin nhắn trực tiếp hoặc broadcast đến đồng đội trong nhóm agent",
})
-3
View File
@@ -169,9 +169,6 @@ func init() {
MsgToolSpawn: "创建子代理执行后台工作或将任务委派给已链接的代理",
MsgToolSkillSearch: "按关键字或描述搜索可用技能以查找相关功能",
MsgToolUseSkill: "激活技能以使用其专门功能(追踪标记)",
MsgToolDelegateSearch: "当链接代理过多时,按关键字搜索可用的委派目标",
MsgToolEvaluateLoop: "在两个代理之间运行生成→评估→修改循环,用于高质量输出",
MsgToolHandoff: "将对话转移给另一个代理——用户将直接与该代理交谈",
MsgToolTeamTasks: "查看、创建、更新和完成团队任务板上的任务",
MsgToolTeamMessage: "向代理团队中的队友发送直接消息或广播",
})
-3
View File
@@ -170,9 +170,6 @@ const (
MsgToolSpawn = "core.tool.spawn"
MsgToolSkillSearch = "core.tool.skill_search"
MsgToolUseSkill = "core.tool.use_skill"
MsgToolDelegateSearch = "core.tool.delegate_search"
MsgToolEvaluateLoop = "core.tool.evaluate_loop"
MsgToolHandoff = "core.tool.handoff"
MsgToolTeamTasks = "core.tool.team_tasks"
MsgToolTeamMessage = "core.tool.team_message"
)
+1 -2
View File
@@ -16,8 +16,7 @@ import (
)
// BridgeToolNames is the subset of GoClaw tools exposed via the MCP bridge.
// Excluded: spawn (agent loop), create_forum_topic (channels),
// handoff/delegate_search/evaluate_loop (require agent loop context).
// Excluded: spawn (agent loop), create_forum_topic (channels).
var BridgeToolNames = map[string]bool{
// Filesystem
"read_file": true,
-57
View File
@@ -267,63 +267,6 @@ func (s *PGTeamStore) KnownUserIDs(ctx context.Context, teamID uuid.UUID, limit
return users, rows.Err()
}
// ============================================================
// Handoff routing
// ============================================================
func (s *PGTeamStore) SetHandoffRoute(ctx context.Context, route *store.HandoffRouteData) error {
if route.ID == uuid.Nil {
route.ID = store.GenNewID()
}
route.CreatedAt = time.Now()
var teamID *uuid.UUID
if route.TeamID != uuid.Nil {
teamID = &route.TeamID
}
_, err := s.db.ExecContext(ctx,
`INSERT INTO handoff_routes (id, channel, chat_id, from_agent_key, to_agent_key, reason, created_by, created_at, team_id)
VALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9)
ON CONFLICT (channel, chat_id)
DO UPDATE SET to_agent_key = EXCLUDED.to_agent_key, from_agent_key = EXCLUDED.from_agent_key,
reason = EXCLUDED.reason, created_by = EXCLUDED.created_by, created_at = EXCLUDED.created_at,
team_id = EXCLUDED.team_id`,
route.ID, route.Channel, route.ChatID, route.FromAgentKey, route.ToAgentKey,
route.Reason, route.CreatedBy, route.CreatedAt, teamID,
)
return err
}
func (s *PGTeamStore) GetHandoffRoute(ctx context.Context, channel, chatID string) (*store.HandoffRouteData, error) {
var d store.HandoffRouteData
var teamID *uuid.UUID
err := s.db.QueryRowContext(ctx,
`SELECT id, channel, chat_id, from_agent_key, to_agent_key, reason, created_by, created_at, team_id
FROM handoff_routes WHERE channel = $1 AND chat_id = $2`,
channel, chatID).Scan(
&d.ID, &d.Channel, &d.ChatID, &d.FromAgentKey, &d.ToAgentKey,
&d.Reason, &d.CreatedBy, &d.CreatedAt, &teamID,
)
if errors.Is(err, sql.ErrNoRows) {
return nil, nil
}
if err != nil {
return nil, err
}
if teamID != nil {
d.TeamID = *teamID
}
return &d, nil
}
func (s *PGTeamStore) ClearHandoffRoute(ctx context.Context, channel, chatID string) error {
_, err := s.db.ExecContext(ctx,
`DELETE FROM handoff_routes WHERE channel = $1 AND chat_id = $2`,
channel, chatID)
return err
}
// ============================================================
// Scan helpers
// ============================================================
-3
View File
@@ -22,9 +22,6 @@ const (
// Agent summoning events (predefined agent setup via LLM).
EventAgentSummoning = "agent.summoning"
// Agent handoff event (payload: from_agent, to_agent, reason).
EventHandoff = "handoff"
// Team activity events (real-time team workflow visibility).
EventTeamTaskCreated = "team.task.created"
EventTeamTaskCompleted = "team.task.completed"
-3
View File
@@ -183,9 +183,6 @@
"spawn": "Spawn a subagent to handle a task in the background",
"skill_search": "Search for available skills by keyword or description to find relevant capabilities",
"use_skill": "Activate a skill to use its specialized capabilities (tracing marker)",
"delegate_search": "Search for available delegation targets (deprecated)",
"evaluate_loop": "Run a generate→evaluate→revise loop between two agents (deprecated)",
"handoff": "Transfer the conversation to another agent (deprecated)",
"team_tasks": "View, create, update, and complete tasks on the team task board",
"team_message": "Send a direct message or broadcast to teammates in the agent team"
}
-3
View File
@@ -183,9 +183,6 @@
"spawn": "Tạo subagent cho công việc nền",
"skill_search": "Tìm kiếm skill khả dụng theo từ khóa hoặc mô tả để tìm khả năng phù hợp",
"use_skill": "Kích hoạt skill để sử dụng khả năng chuyên biệt (đánh dấu tracing)",
"delegate_search": "Tìm kiếm mục tiêu ủy quyền (ngừng sử dụng)",
"evaluate_loop": "Chạy vòng lặp tạo→đánh giá→chỉnh sửa giữa hai agent (ngừng sử dụng)",
"handoff": "Chuyển cuộc hội thoại sang agent khác (ngừng sử dụng)",
"team_tasks": "Xem, tạo, cập nhật và hoàn thành tác vụ trên bảng tác vụ nhóm",
"team_message": "Gửi tin nhắn trực tiếp hoặc broadcast đến đồng đội trong nhóm agent"
}
-3
View File
@@ -119,9 +119,6 @@
"spawn": "生成子Agent进行后台工作",
"skill_search": "按关键字或描述搜索可用Skill以找到相关能力",
"use_skill": "激活Skill以使用其专业能力(追踪标记)",
"delegate_search": "按关键字搜索可用委托目标(已弃用)",
"evaluate_loop": "在两个Agent之间运行生成→评估→修订循环(已弃用)",
"handoff": "将对话转移给另一个Agent(已弃用)",
"team_tasks": "查看、创建、更新和完成团队任务板上的任务",
"team_message": "向Agent团队中的队友发送直接消息或广播"
}