You've already forked agentic-coding-workflow
194 lines
6.2 KiB
Go
194 lines
6.2 KiB
Go
// Package acp 实现 ACP(Agent Client Protocol)Client 模块。
|
|
// 模块结构(spec §13 决策 #12):单 package + 多文件,与现有 chat/jobs/workspace 一致。
|
|
//
|
|
// 三个聚合根:
|
|
// - AgentKind:admin 注册的 agent 类型(claude_code/gemini/...),含加密 env
|
|
// - Session:用户启动的一个 ACP 会话,绑定 workspace + agent kind + (issue/req?)
|
|
// - Event:JSON-RPC 双向消息流,每条入库
|
|
package acp
|
|
|
|
import (
|
|
"context"
|
|
"time"
|
|
|
|
"github.com/google/uuid"
|
|
)
|
|
|
|
// SessionStatus 是 acp_sessions.status 枚举。
|
|
type SessionStatus string
|
|
|
|
const (
|
|
SessionStarting SessionStatus = "starting"
|
|
SessionRunning SessionStatus = "running"
|
|
SessionCrashed SessionStatus = "crashed"
|
|
SessionExited SessionStatus = "exited"
|
|
)
|
|
|
|
// IsActive 判定 session 是否仍占资源(worktree、subprocess、限流计数)。
|
|
func (s SessionStatus) IsActive() bool {
|
|
return s == SessionStarting || s == SessionRunning
|
|
}
|
|
|
|
// EventDirection 标识事件流向。in = client→agent,out = agent→client。
|
|
type EventDirection string
|
|
|
|
const (
|
|
DirectionIn EventDirection = "in"
|
|
DirectionOut EventDirection = "out"
|
|
)
|
|
|
|
// RPCKind 标识 JSON-RPC 消息类型。
|
|
type RPCKind string
|
|
|
|
const (
|
|
RPCRequest RPCKind = "request"
|
|
RPCResponse RPCKind = "response"
|
|
RPCNotification RPCKind = "notification"
|
|
RPCError RPCKind = "error"
|
|
)
|
|
|
|
// AgentKind 是 admin 注册的 agent 类型记录。EncryptedEnv 是 AES-GCM 密文,
|
|
// 仅 supervisor spawn 时解密为 map 注入子进程。其他场景不解密、不出 API。
|
|
type AgentKind struct {
|
|
ID uuid.UUID
|
|
Name string
|
|
DisplayName string
|
|
Description string
|
|
BinaryPath string
|
|
Args []string
|
|
EncryptedEnv []byte
|
|
Enabled bool
|
|
ToolAllowlist []string // 命中的工具调用自动放行;含 "*" 表示全部放行
|
|
CreatedBy uuid.UUID
|
|
CreatedAt time.Time
|
|
UpdatedAt time.Time
|
|
}
|
|
|
|
// Session 是一次 ACP 会话。AgentSessionID 是 agent 侧的 session 标识(来自
|
|
// session/new response),与本表 ID 不同,仅用于 ACP 协议 method 内填充。
|
|
type Session struct {
|
|
ID uuid.UUID
|
|
WorkspaceID uuid.UUID
|
|
ProjectID uuid.UUID
|
|
AgentKindID uuid.UUID
|
|
UserID uuid.UUID
|
|
IssueID *uuid.UUID
|
|
RequirementID *uuid.UUID
|
|
AgentSessionID *string
|
|
Branch string
|
|
CwdPath string
|
|
IsMainWorktree bool
|
|
Status SessionStatus
|
|
PID *int32
|
|
ExitCode *int32
|
|
LastError *string
|
|
StartedAt time.Time
|
|
EndedAt *time.Time
|
|
}
|
|
|
|
// Event 是一条入库的 JSON-RPC 消息。Payload 是 JSON-RPC envelope 完整 JSON
|
|
// 字节(不解析为结构体,便于无损 replay);超过 64KB 的会按 §3.5 规则裁剪。
|
|
type Event struct {
|
|
ID int64
|
|
SessionID uuid.UUID
|
|
Direction EventDirection
|
|
RPCKind RPCKind
|
|
Method *string
|
|
Payload []byte
|
|
PayloadSize int32
|
|
Truncated bool
|
|
CreatedAt time.Time
|
|
}
|
|
|
|
// Caller 表示发起请求的用户上下文,与 PM 模块的 Caller 同语义。
|
|
type Caller struct {
|
|
UserID uuid.UUID
|
|
IsAdmin bool
|
|
}
|
|
|
|
// AgentKindService 暴露 AgentKind 的应用服务方法。env 走"完整 map 替换"
|
|
// 语义:每次 PATCH 传完整 env,nil 表示不修改;非 nil 整体加密重写。
|
|
type AgentKindService interface {
|
|
Create(ctx context.Context, c Caller, in CreateAgentKindInput) (*AgentKind, error)
|
|
List(ctx context.Context, c Caller) ([]*AgentKind, error)
|
|
Get(ctx context.Context, c Caller, id uuid.UUID) (*AgentKind, error)
|
|
Update(ctx context.Context, c Caller, id uuid.UUID, in UpdateAgentKindInput) (*AgentKind, error)
|
|
Delete(ctx context.Context, c Caller, id uuid.UUID) error
|
|
}
|
|
|
|
// SessionService 暴露 Session 聚合根的应用服务方法。
|
|
type SessionService interface {
|
|
Create(ctx context.Context, c Caller, in CreateSessionInput) (*Session, error)
|
|
Get(ctx context.Context, c Caller, id uuid.UUID) (*Session, error)
|
|
List(ctx context.Context, c Caller, f SessionListFilter) ([]*Session, error)
|
|
Terminate(ctx context.Context, c Caller, id uuid.UUID) error
|
|
}
|
|
|
|
// SessionListFilter 控制 sessions 列表的过滤维度。
|
|
// All 仅 admin 可用(查看全部用户);RequirementID nil 表示不按需求过滤。
|
|
type SessionListFilter struct {
|
|
All bool
|
|
RequirementID *uuid.UUID
|
|
}
|
|
|
|
// CreateSessionInput 是创建 session 的入参。
|
|
// branch / issue_number / requirement_number 三选一或全空(spec §8.1)。
|
|
type CreateSessionInput struct {
|
|
WorkspaceID uuid.UUID
|
|
AgentKindID uuid.UUID
|
|
Branch *string
|
|
IssueNumber *int
|
|
RequirementNumber *int
|
|
InitialPrompt *string
|
|
}
|
|
|
|
// CreateAgentKindInput 携带创建必需字段。Args / Env 可为 nil。
|
|
type CreateAgentKindInput struct {
|
|
Name string
|
|
DisplayName string
|
|
Description string
|
|
BinaryPath string
|
|
Args []string
|
|
Env map[string]string
|
|
Enabled bool
|
|
ToolAllowlist []string
|
|
}
|
|
|
|
// UpdateAgentKindInput 是 patch 输入。Name 不可改(创建后稳定,引用约束)。
|
|
// Env 三态:nil = 不修改;空 map = 清空全部 env;非空 = 整体替换。
|
|
type UpdateAgentKindInput struct {
|
|
DisplayName *string
|
|
Description *string
|
|
BinaryPath *string
|
|
Args []string // nil = 不改;非 nil = 替换
|
|
Env map[string]string // nil = 不改;非 nil(含空)= 替换
|
|
Enabled *bool
|
|
ToolAllowlist []string // nil = 不改;非 nil(含空)= 替换
|
|
}
|
|
|
|
// PermissionStatus 是 acp_permission_requests.status 枚举。
|
|
type PermissionStatus string
|
|
|
|
const (
|
|
PermissionPending PermissionStatus = "pending"
|
|
PermissionApproved PermissionStatus = "approved"
|
|
PermissionDenied PermissionStatus = "denied"
|
|
PermissionAuto PermissionStatus = "auto"
|
|
PermissionExpired PermissionStatus = "expired"
|
|
)
|
|
|
|
// PermissionRequest 是一条代理发起的工具调用授权请求记录。
|
|
type PermissionRequest struct {
|
|
ID uuid.UUID
|
|
SessionID uuid.UUID
|
|
AgentRequestID string
|
|
ToolName string
|
|
ToolCall []byte // 原始 toolCall JSON
|
|
Options []byte // 原始 options JSON
|
|
Status PermissionStatus
|
|
ChosenOptionID *string
|
|
DecidedBy *uuid.UUID
|
|
DecidedAt *time.Time
|
|
CreatedAt time.Time
|
|
}
|