mirror of
https://github.com/tiennm99/goclaw.git
synced 2026-10-11 12:18:59 +00:00
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:
1 parent
514c5e0bfc
commit
3f2b6e258e
17 files changed
+38
-205
No files matched your search
@@ -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"},
|
||||
|
||||
@@ -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
|
||||
}
|
||||
|
||||
@@ -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 ""
|
||||
}
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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)",
|
||||
|
||||
|
||||
@@ -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...",
|
||||
}
|
||||
|
||||
|
||||
@@ -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)
|
||||
}
|
||||
|
||||
@@ -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",
|
||||
})
|
||||
|
||||
@@ -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",
|
||||
})
|
||||
|
||||
@@ -169,9 +169,6 @@ func init() {
|
||||
MsgToolSpawn: "创建子代理执行后台工作或将任务委派给已链接的代理",
|
||||
MsgToolSkillSearch: "按关键字或描述搜索可用技能以查找相关功能",
|
||||
MsgToolUseSkill: "激活技能以使用其专门功能(追踪标记)",
|
||||
MsgToolDelegateSearch: "当链接代理过多时,按关键字搜索可用的委派目标",
|
||||
MsgToolEvaluateLoop: "在两个代理之间运行生成→评估→修改循环,用于高质量输出",
|
||||
MsgToolHandoff: "将对话转移给另一个代理——用户将直接与该代理交谈",
|
||||
MsgToolTeamTasks: "查看、创建、更新和完成团队任务板上的任务",
|
||||
MsgToolTeamMessage: "向代理团队中的队友发送直接消息或广播",
|
||||
})
|
||||
|
||||
@@ -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"
|
||||
)
|
||||
@@ -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,
|
||||
|
||||
@@ -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
|
||||
// ============================================================
|
||||
|
||||
@@ -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"
|
||||
|
||||
@@ -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"
|
||||
}
|
||||
|
||||
@@ -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"
|
||||
}
|
||||
|
||||
@@ -119,9 +119,6 @@
|
||||
"spawn": "生成子Agent进行后台工作",
|
||||
"skill_search": "按关键字或描述搜索可用Skill以找到相关能力",
|
||||
"use_skill": "激活Skill以使用其专业能力(追踪标记)",
|
||||
"delegate_search": "按关键字搜索可用委托目标(已弃用)",
|
||||
"evaluate_loop": "在两个Agent之间运行生成→评估→修订循环(已弃用)",
|
||||
"handoff": "将对话转移给另一个Agent(已弃用)",
|
||||
"team_tasks": "查看、创建、更新和完成团队任务板上的任务",
|
||||
"team_message": "向Agent团队中的队友发送直接消息或广播"
|
||||
}
|
||||
|
||||
Reference in new issue
Block a user