package inbox // message.go 定义 Agent 间通信的统一消息格式. // // 模块定位: // // Inbox 消息传输层 -- 定义消息类型,结构体和构造函数. // 这是 Agent 间通信的"信封规范",不涉及传输机制(传输由 Inbox/Router 负责). // // 核心设计决策: // 1. Payload 为 json.RawMessage--消息路由层无需解码具体载荷,保持低耦合. // 精妙之处(CLEVER): 路由器像邮局,只看"收件人",不拆信封内容. // 替代方案:Payload 为 any(需要类型断言,破坏静态类型安全). // 2. 消息 ID = 时间戳(ns) + 随机 4 字节 hex--单节点内唯一,跨节点概率唯一. // 精妙之处(CLEVER): 时间戳前缀使 ID 自带排序语义,调试时一眼看出时序. // 替代方案:UUID v4(纯随机,无时序语义). // 3. From/To 为字符串(agent 名称)而非强类型 AgentID-- // 减少依赖,方便测试(不需要创建 Agent 实例就能发消息). import ( "crypto/rand" "encoding/hex" "encoding/json" "fmt" "time" ) // MessageType 是消息类型枚举. type MessageType string const ( // MsgPermissionRequest Worker 向 Leader 申请工具执行权限 MsgPermissionRequest MessageType = "permission_request" // MsgPermissionResponse Leader 向 Worker 回应权限请求 MsgPermissionResponse MessageType = "permission_response" // MsgIdleNotification Worker 完成或空闲时通知 Leader MsgIdleNotification MessageType = "idle_notification" // MsgTaskAssignment Leader 向 Worker 分配新任务 MsgTaskAssignment MessageType = "task_assignment" // MsgShutdownRequest 请求关闭 Agent MsgShutdownRequest MessageType = "shutdown_request" // MsgShutdownApproved 批准关闭请求 MsgShutdownApproved MessageType = "shutdown_approved" // MsgModeSetRequest 请求切换运行模式 MsgModeSetRequest MessageType = "mode_set_request" // MsgTeamPermUpdate 更新 Team 权限配置 MsgTeamPermUpdate MessageType = "team_permission_update" ) // Message 是统一的消息格式. // 所有 Agent 间通信都通过此结构体传递,保证格式统一可追踪. // // 升华改进(ELEVATED): 统一消息格式使得 Inbox 可以无感知地 // 做消息持久化,审计,重放--运维工具的基础设施. // 跨行业扩展:金融场景的交易指令,医疗场景的诊断请求都可复用此格式. // 替代方案:每种消息类型独立 channel(类型安全但无法统一路由/审计). type Message struct { ID string `json:"id"` Type MessageType `json:"type"` From string `json:"from"` // 发送方 agent 名称 To string `json:"to"` // 接收方 agent 名称 Timestamp time.Time `json:"timestamp"` Payload json.RawMessage `json:"payload"` // 类型特定的数据 } // NewMessage 构造一条消息,自动生成 ID 和 Timestamp. // // payload 会被 JSON 序列化为 json.RawMessage; // 若 payload 本身已是 json.RawMessage,直接使用(避免二次编码). // // 精妙之处(CLEVER): payload 已是 json.RawMessage 时直接赋值-- // 避免 json.Marshal(json.RawMessage) 再次编码导致字节串被当作 base64 处理的陷阱. // 替代方案:始终 json.Marshal(会导致 RawMessage 被双重编码). func NewMessage(from, to string, msgType MessageType, payload any) (*Message, error) { var rawPayload json.RawMessage switch p := payload.(type) { case json.RawMessage: rawPayload = p case []byte: rawPayload = json.RawMessage(p) default: encoded, err := json.Marshal(payload) if err != nil { return nil, fmt.Errorf("inbox: marshal payload: %w", err) } rawPayload = json.RawMessage(encoded) } id, err := generateMessageID() if err != nil { return nil, fmt.Errorf("inbox: generate id: %w", err) } return &Message{ ID: id, Type: msgType, From: from, To: to, Timestamp: time.Now(), Payload: rawPayload, }, nil } // generateMessageID 生成消息唯一 ID:时间戳(ns) + 随机 4 字节 hex. // // 格式:"1736000000000000000-a1b2c3d4"(时间戳纳秒 + 随机后缀) // 精妙之处(CLEVER): 纳秒时间戳前缀保证同一 goroutine 内严格有序; // 4 字节随机后缀处理纳秒级并发冲突(概率 < 1/4G). // 替代方案:原子计数器(单节点唯一但跨进程不唯一). func generateMessageID() (string, error) { buf := make([]byte, 4) if _, err := rand.Read(buf); err != nil { return "", err } return fmt.Sprintf("%d-%s", time.Now().UnixNano(), hex.EncodeToString(buf)), nil } // --- Payload 结构体 --- // PermissionRequestPayload 是权限请求消息的载荷. // Worker 工具执行前向 Leader 申请权限时使用. type PermissionRequestPayload struct { RequestID string `json:"request_id"` ToolName string `json:"tool_name"` ToolUseID string `json:"tool_use_id"` Description string `json:"description"` Input map[string]any `json:"input"` } // PermissionResponsePayload 是权限响应消息的载荷. // Leader 审批/拒绝 Worker 的权限请求时使用. type PermissionResponsePayload struct { RequestID string `json:"request_id"` Approved bool `json:"approved"` UpdatedInput map[string]any `json:"updated_input,omitempty"` Reason string `json:"reason,omitempty"` } // IdleNotificationPayload 是空闲通知消息的载荷. // Worker 完成任务或进入空闲状态时通知 Leader. // // 升华改进(ELEVATED): IdleReason 区分"完成"/"中断"/"失败"三种状态-- // Leader 可以根据状态决定下一步动作(分配新任务/重试/告警). // 替代方案:布尔 Completed 字段(无法区分中断和失败). type IdleNotificationPayload struct { IdleReason string `json:"idle_reason"` // "available" | "interrupted" | "failed" Summary string `json:"summary,omitempty"` CompletedTaskID string `json:"completed_task_id,omitempty"` CompletedStatus string `json:"completed_status,omitempty"` // "resolved" | "blocked" | "failed" FailureReason string `json:"failure_reason,omitempty"` } // TaskAssignmentPayload 是任务分配消息的载荷. // Leader 向 Worker 分配具体任务时使用. type TaskAssignmentPayload struct { TaskID string `json:"task_id"` Subject string `json:"subject"` Description string `json:"description"` AssignedBy string `json:"assigned_by"` }