Documentation
¶
Overview ¶
Package agent 定义 AI Agent 调用的统一抽象层。
它屏蔽了具体第三方 Agent(Claude Code / Codex / Copilot)与后续自研 Agent 的差异, 向上层业务(AISummaryWorker、LLMHandler 等)统一暴露两种调用语义:
- Invoke:一次性任务调用,同步等待最终结果。适合 AI 摘要、后台任务等场景。
- Stream:流式调用,通过 Runtime.Emit 逐块输出事件。适合前端聊天等场景。
除“调用”本身外,本包还实现了 design.md 中描述的“执行架构”:
- Agent:执行层,负责产生文本 / 推理 / 工具调用等事件,并在需要时请求权限。
- Runtime:Agent 执行期的运行时环境(Emit / RequestPermission / WaitPermission)。
- Operation / PermissionPolicy:描述“要做什么”以及“能不能做”。
- PermissionManager / PermissionRequest:持久化的权限请求与批准 / 拒绝。
- Task / TaskManager(AgentService):任务状态机与编排。
- EventBus / AgentEvent:实时通知层(带 sequence,可恢复)。
- Repository:持久化抽象(默认提供内存实现,后续可替换为 DB)。
各 Provider 通过 Registry 注册,运行时按名称解析;Client 是统一门面,负责 解析请求应使用的 Provider 并转发 Invoke / Stream。
Package agent 中的 memory 层:Agent 的「长期记忆」子系统。
与 conversation.go 中的「短期上下文」(单次会话的多轮历史)不同,memory 负责跨轮次、 跨会话、跨任务的持久化记忆,例如用户偏好、已确认的事实、任务摘要等。它遵循与权限 子系统一致的架构原则:Repository 是状态源,Manager 负责编排,检索 / 提取可插拔。
Index ¶
- Constants
- Variables
- func AskUserToolDefinition() tool.Definition
- func BuildMemoryContext(memories []*Memory) string
- func EnsureBuiltinProfiles(ctx context.Context, repo ProfileRepository) error
- func IsBuiltinProfileID(id int64) bool
- func RenderSystemPromptTemplate(template string, vars map[string]any) (string, error)
- type Agent
- type AgentEvent
- type AgentEventType
- type AgentService
- func (s *AgentService) AnswerQuestion(ctx context.Context, id int64, answer AskUserAnswer, by string) error
- func (s *AgentService) ApprovePermission(ctx context.Context, id int64, by string) error
- func (s *AgentService) CancelTask(ctx context.Context, taskID int64) error
- func (s *AgentService) CreateTask(ctx context.Context, req Request) (*Task, error)
- func (s *AgentService) DeleteMemory(ctx context.Context, id string) error
- func (s *AgentService) DeleteProfile(ctx context.Context, userID string, id int64) error
- func (s *AgentService) DenyPermission(ctx context.Context, id int64, by string) error
- func (s *AgentService) GetEvents(ctx context.Context, taskID int64, after int64) ([]*AgentEvent, error)
- func (s *AgentService) GetMemory(ctx context.Context, id string) (*Memory, error)
- func (s *AgentService) GetPendingPermissions(ctx context.Context, taskID int64) ([]*PermissionRequest, error)
- func (s *AgentService) GetPendingQuestions(ctx context.Context, taskID int64) ([]*QuestionRequest, error)
- func (s *AgentService) GetProfile(ctx context.Context, userID string, id int64) (*Profile, error)
- func (s *AgentService) GetSystemSpromptByProfile(ctx context.Context, profile *Profile, vars map[string]any, userID string, ...) string
- func (s *AgentService) GetTask(ctx context.Context, id int64) (*Task, error)
- func (s *AgentService) GetTaskRequest(ctx context.Context, taskID int64) (*Request, error)
- func (s *AgentService) ListMemory(ctx context.Context, userID string, offset, limit int, kinds ...MemoryKind) ([]*Memory, int64, error)
- func (s *AgentService) ListProfiles(ctx context.Context, userID string) ([]*Profile, error)
- func (s *AgentService) PageEvents(ctx context.Context, offset, limit int, taskID int64) ([]*AgentEvent, int64, error)
- func (s *AgentService) PagePermissions(ctx context.Context, offset, limit int, taskID int64, ...) ([]*PermissionRequest, int64, error)
- func (s *AgentService) PageQuestions(ctx context.Context, offset, limit int, taskID int64, ...) ([]*QuestionRequest, int64, error)
- func (s *AgentService) PageTasks(ctx context.Context, offset, limit int, statuses ...TaskStatus) ([]*Task, int64, error)
- func (s *AgentService) ProjectContext(ctx context.Context, userID string) (string, error)
- func (s *AgentService) Recover(ctx context.Context) error
- func (s *AgentService) RenderSystemPrompt(ctx context.Context, userID string, profileID int64, vars map[string]any) (*Profile, string, error)
- func (s *AgentService) ResolveProfile(ctx context.Context, id int64) (*Profile, error)
- func (s *AgentService) RetrieveMemory(ctx context.Context, userID, query string, limit int) ([]*Memory, error)
- func (s *AgentService) RunTask(ctx context.Context, req Request, handler StreamHandler) (*Task, error)
- func (s *AgentService) RunTaskSync(ctx context.Context, req Request) (*Result, error)
- func (s *AgentService) RunTaskSyncByID(ctx context.Context, taskID int64) (*Result, error)
- func (s *AgentService) SaveMemory(ctx context.Context, memory *Memory) error
- func (s *AgentService) SaveProfile(ctx context.Context, profile *Profile) error
- func (s *AgentService) StartTask(ctx context.Context, taskID int64, handler StreamHandler) error
- func (s *AgentService) Subscribe(taskID int64, handler EventHandler) func()
- type AskUserAnswer
- type AskUserInput
- type Client
- type ContextConfig
- type Conversation
- type ConversationMessage
- type ConversationRepository
- type ConversationService
- func (s *ConversationService) CreateTurn(ctx context.Context, in TurnInput) (*Task, *Conversation, error)
- func (s *ConversationService) GetConversation(ctx context.Context, id int64) (*Conversation, error)
- func (s *ConversationService) PageConversations(ctx context.Context, userID string, offset, limit int) ([]*Conversation, int64, error)
- func (s *ConversationService) StartTurn(ctx context.Context, taskID int64) error
- type EventBus
- type EventHandler
- type EventRepository
- type Memory
- type MemoryConfig
- type MemoryExtractor
- type MemoryExtractorFunc
- type MemoryKind
- type MemoryManager
- func (m *MemoryManager) Delete(ctx context.Context, id string) error
- func (m *MemoryManager) Extract(ctx context.Context, turn MemoryTurn) ([]*Memory, error)
- func (m *MemoryManager) Get(ctx context.Context, id string) (*Memory, error)
- func (m *MemoryManager) List(ctx context.Context, userID string, offset, limit int, kinds ...MemoryKind) ([]*Memory, int64, error)
- func (m *MemoryManager) Retrieve(ctx context.Context, userID, query string, limit int) ([]*Memory, error)
- func (m *MemoryManager) Save(ctx context.Context, memory *Memory) error
- func (m *MemoryManager) Touch(ctx context.Context, id string) error
- type MemoryRepository
- type MemoryRetriever
- type MemoryTurn
- type Message
- type MessageBlock
- type ModelProviderConfig
- type Operation
- type OperationType
- type Options
- type PermissionDecision
- type PermissionManager
- func (m *PermissionManager) Approve(ctx context.Context, id int64, by string) (*PermissionRequest, error)
- func (m *PermissionManager) Create(ctx context.Context, taskID int64, sessionID string, operation Operation) (*PermissionRequest, error)
- func (m *PermissionManager) Deny(ctx context.Context, id int64, by string) (*PermissionRequest, error)
- func (m *PermissionManager) Get(ctx context.Context, id int64) (*PermissionRequest, error)
- func (m *PermissionManager) GetPending(ctx context.Context, taskID int64) ([]*PermissionRequest, error)
- func (m *PermissionManager) Page(ctx context.Context, offset, limit int, taskID int64, ...) ([]*PermissionRequest, int64, error)
- func (m *PermissionManager) Wait(ctx context.Context, id int64) (PermissionDecision, error)
- type PermissionPolicy
- type PermissionRepository
- type PermissionRequest
- type PermissionStatus
- type Profile
- type ProfileManager
- func (m *ProfileManager) Delete(ctx context.Context, userID string, id int64) error
- func (m *ProfileManager) Get(ctx context.Context, userID string, id int64) (*Profile, error)
- func (m *ProfileManager) List(ctx context.Context, userID string) ([]*Profile, error)
- func (m *ProfileManager) Resolve(ctx context.Context, id int64) (*Profile, error)
- func (m *ProfileManager) Save(ctx context.Context, p *Profile) error
- type ProfileRepository
- type ProjectContextProvider
- type Provider
- type Question
- type QuestionAnswer
- type QuestionManager
- func (m *QuestionManager) Answer(ctx context.Context, id int64, answer AskUserAnswer, by string) (*QuestionRequest, error)
- func (m *QuestionManager) Cancel(ctx context.Context, id int64) (*QuestionRequest, error)
- func (m *QuestionManager) Create(ctx context.Context, taskID int64, sessionID string, input AskUserInput) (*QuestionRequest, error)
- func (m *QuestionManager) Get(ctx context.Context, id int64) (*QuestionRequest, error)
- func (m *QuestionManager) GetPending(ctx context.Context, taskID int64) ([]*QuestionRequest, error)
- func (m *QuestionManager) Page(ctx context.Context, offset, limit int, taskID int64, ...) ([]*QuestionRequest, int64, error)
- func (m *QuestionManager) Wait(ctx context.Context, id int64) (AskUserAnswer, error)
- type QuestionOption
- type QuestionRepository
- type QuestionRequest
- type QuestionStatus
- type ReasoningBlock
- type Registry
- type Request
- type Result
- type Runtime
- type ServiceConfig
- type StreamEvent
- type StreamEventType
- type StreamHandler
- type Task
- type TaskRepository
- type TaskStatus
- type ToolCall
- type ToolCallProvider
- type ToolLoop
- type ToolPermissionResolver
- type ToolResultEvent
- type ToolRunner
- type TurnBlock
- type TurnInput
- type Usage
- type UserAgentConfig
- type UserAgentConfigProvider
Constants ¶
const ( ProviderMock = "mock" // 自研 mock,用于保证链路可跑通 ProviderClaudeCode = "claude_code" // Anthropic Claude Code CLI ProviderCodex = "codex" // OpenAI Codex CLI ProviderCopilot = "copilot" // GitHub Copilot CLI ProviderCustom = "custom" // 预留:后续自研 Agent )
Provider 名称常量。新增第三方 Agent 或自研 Agent 时在此登记一个唯一名称。
const ( RoleSystem = "system" RoleUser = "user" RoleAssistant = "assistant" RoleTool = "tool" )
MessageRole 常量。
const ( MessageKindUser = "user" MessageKindAssistant = "assistant" MessageKindAssistantFinal = "assistant_final" MessageKindReasoning = "reasoning" MessageKindToolCall = "tool_call" MessageKindToolResult = "tool_result" )
MessageKind 定义会话层可回放的消息类型。
const ( BuiltinDefaultProfileID int64 = -1 // 内置默认 Profile BuiltinAnalysisCoderID int64 = -2 // 内置「分析代码编写」Profile BuiltinArticleWriterID int64 = -3 // 内置「科研文章撰写」Profile BuiltinSummaryProfileID int64 = -4 // 内置「摘要总结」Profile )
内置 Profile 使用固定的负数 ID,避免与雪花算法生成的正整数主键冲突。 Profile 的查询 / 引用一律使用 ID;Name 仅用于展示。
const ( QuestionTypeSingleChoice = "single_choice" QuestionTypeMultipleChoice = "multiple_choice" QuestionTypeText = "text" )
问题类型常量。
const AskUserToolName = "ask_user"
AskUserToolName 是 ask_user 工具名(模型据此发起调用)。
const BuiltinDefaultProfileName = "通用助手"
BuiltinDefaultProfileName 是内置默认 Profile 的展示名。用于无需查询数据库即可获得 展示名的场景(如 DefaultUserAgentConfig)。
const DefaultProvider = ProviderMock
DefaultProvider 是未配置时的兜底 Provider。
Variables ¶
var ( // ErrMemoryNotFound 表示记忆不存在。 ErrMemoryNotFound = errors.New("agent: memory not found") // ErrMemoryNotConfigured 表示 AgentService 未配置记忆管理器。 ErrMemoryNotConfigured = errors.New("agent: memory manager not configured") )
记忆相关错误。
var ( // ErrPermissionDenied 表示权限请求被拒绝,或策略直接判定为 deny。 ErrPermissionDenied = errors.New("agent: permission denied") // ErrPermissionNotFound 表示权限请求不存在。 ErrPermissionNotFound = errors.New("agent: permission request not found") // ErrPermissionNotPending 表示尝试对非 pending 状态的权限请求做批准 / 拒绝。 ErrPermissionNotPending = errors.New("agent: permission request is not pending") // ErrPermissionExpired 表示等待的权限请求已过期。 ErrPermissionExpired = errors.New("agent: permission request expired") // ErrPermissionCanceled 表示等待的权限请求已取消。 ErrPermissionCanceled = errors.New("agent: permission request canceled") // ErrInvalidPermissionTransition 表示非法的权限状态迁移。 ErrInvalidPermissionTransition = errors.New("agent: invalid permission state transition") )
权限相关错误。
var ( // ErrProfileNotFound 表示 Profile 不存在。 ErrProfileNotFound = errors.New("agent: profile not found") // ErrProfileNameRequired 表示 Profile 名称缺失。 ErrProfileNameRequired = errors.New("agent: profile name is required") )
Profile 相关错误。
var ( // ErrQuestionNotFound 表示提问请求不存在。 ErrQuestionNotFound = errors.New("agent: question request not found") // ErrQuestionNotPending 表示尝试对非 pending 的提问请求作答。 ErrQuestionNotPending = errors.New("agent: question request is not pending") // ErrQuestionCanceled 表示等待的提问已被取消。 ErrQuestionCanceled = errors.New("agent: question request canceled") // ErrQuestionExpired 表示等待的提问已过期。 ErrQuestionExpired = errors.New("agent: question request expired") // ErrInvalidQuestionTransition 表示非法的提问状态迁移。 ErrInvalidQuestionTransition = errors.New("agent: invalid question state transition") // ErrNoUserInputResolver 表示当前 Runtime 无法向用户提问(无 UI)。 ErrNoUserInputResolver = errors.New("agent: no user input resolver in runtime") )
提问相关错误。
var ( // ErrTaskNotFound 表示任务不存在。 ErrTaskNotFound = errors.New("agent: task not found") // ErrTaskAlreadyRunning 表示任务已经在执行中。 ErrTaskAlreadyRunning = errors.New("agent: task already running") // ErrInvalidTaskTransition 表示非法的任务状态迁移。 ErrInvalidTaskTransition = errors.New("agent: invalid task state transition") )
任务相关错误。
var ( // ErrConversationNotFound 表示会话不存在。 ErrConversationNotFound = errors.New("agent: conversation not found") )
会话相关错误。
var ErrNoPermissionResolver = errors.New("agent: no permission resolver in runtime")
ErrNoPermissionResolver 表示当前 Runtime 没有绑定权限解析器(无法等待人工决策)。
var ErrNotImplemented = errors.New("agent: provider not implemented yet")
ErrNotImplemented 表示某个 Provider 尚未实现真实调用。
Functions ¶
func AskUserToolDefinition ¶ added in v0.1.5
func AskUserToolDefinition() tool.Definition
AskUserToolDefinition 返回 ask_user 工具的定义(名称 / 描述 / 入参 schema)。
各 Provider 用它把 ask_user 暴露给模型:模型发起调用时,Provider 解析入参为 AskUserInput,并调用 Runtime.AskUser 阻塞等待用户作答,再把结果回填给模型。
func BuildMemoryContext ¶
BuildMemoryContext 把检索到的记忆格式化为注入上下文的文本块。
用于 AgentService 在调用前把相关记忆注入 SystemPrompt,让 Agent「记得」相关背景。 无记忆时返回空字符串。
func EnsureBuiltinProfiles ¶ added in v0.1.4
func EnsureBuiltinProfiles(ctx context.Context, repo ProfileRepository) error
EnsureBuiltinProfiles 把内置 Profile 同步到仓库(数据库初始化工具)。
系统启动时调用:按 ID 判断,记录不存在则新增、已存在则跳过,从而允许管理端 对内置 Profile 的修改在重启后得以保留。repo 为空时无操作。
func IsBuiltinProfileID ¶ added in v0.1.4
IsBuiltinProfileID 判断给定 ID 是否为内置 Profile。 内置 Profile 使用固定的负数 ID,用户自定义 Profile 使用雪花算法生成的正整数 ID。
func RenderSystemPromptTemplate ¶ added in v0.1.5
RenderSystemPromptTemplate 用 vars 渲染 AgentProfile 的系统提示词模板。
Profile.SystemPrompt 是一段 pongo2 模板(例如 "workspace_directory: {{ workspace_directory }}"), 其中可引用由 Handler 依据业务 env(type,id) 解析出的变量。未定义的变量按 pongo2 默认行为 渲染为空串(配合 {% if %} 可让整行按需出现),因此调用方无需保证变量齐全。
template 为空时返回空串;模板语法错误或渲染失败时返回错误。
Types ¶
type Agent ¶
type Agent interface {
// Name 返回 Provider 唯一标识。
Name() string
// Invoke 执行一次性任务并同步返回最终结果。
Invoke(ctx context.Context, req Request, rt Runtime) (*Result, error)
// Stream 执行流式请求,通过 rt.Emit 逐块输出事件,返回最终聚合结果。
Stream(ctx context.Context, req Request, rt Runtime) (*Result, error)
}
Agent 是统一 Agent 调用接口。 每个 Provider(claude_code / codex / copilot / custom ...)都需要实现该接口。
type AgentEvent ¶
type AgentEvent struct {
ID int64 `json:"id,string" gorm:"column:id;primaryKey;type:bigint;autoIncrement:false"`
TaskID int64 `json:"task_id,string" gorm:"column:task_id;type:bigint;index:idx_agent_events_task_seq,priority:1"`
Sequence int64 `json:"sequence" gorm:"column:sequence;index:idx_agent_events_task_seq,priority:2"`
Type AgentEventType `json:"type" gorm:"column:type;type:varchar(32)"`
Payload any `json:"payload,omitempty" gorm:"serializer:json"`
CreatedAt time.Time `json:"created_at" gorm:"column:created_at"`
}
AgentEvent 是发布到 EventBus 的单个事件,带单调递增的 sequence。
sequence 使事件可被“增量拉取”(如 GET /tasks/{id}/events?after=3), 因此浏览器刷新后无需依赖 WS 历史即可恢复。
func (*AgentEvent) BeforeCreate ¶ added in v0.1.3
func (e *AgentEvent) BeforeCreate(_ *gorm.DB) error
BeforeCreate 在写入数据库前用雪花 ID 初始化主键。
type AgentEventType ¶
type AgentEventType string
AgentEventType 枚举任务生命周期与实时通知事件。
流式内容事件统一使用 EventStream,具体细分见 StreamEvent.Type; 权限与任务状态变化使用独立类型,便于前端按类型订阅与恢复。
const ( EventTaskCreated AgentEventType = "task.created" // 任务已创建 EventTaskStarted AgentEventType = "task.started" // 任务开始执行 EventTaskWaiting AgentEventType = "task.waiting" // 任务进入等待权限状态 EventTaskCompleted AgentEventType = "task.completed" // 任务完成 EventTaskFailed AgentEventType = "task.failed" // 任务失败 EventTaskCanceled AgentEventType = "task.canceled" // 任务取消 EventPermissionCreated AgentEventType = "permission.created" // 新增待确认权限 EventPermissionResolved AgentEventType = "permission.resolved" // 权限已被批准 / 拒绝 EventQuestionCreated AgentEventType = "question.created" // 新增待作答提问(Payload 为 QuestionRequest) EventQuestionResolved AgentEventType = "question.resolved" // 提问已作答 / 取消(Payload 为 QuestionRequest) EventMemorySaved AgentEventType = "memory.saved" // 记忆已保存(Payload 为 Memory) EventMemoryDeleted AgentEventType = "memory.deleted" // 记忆已删除(Payload 为 Memory) EventStream AgentEventType = "stream" // 透传的流式事件(Payload 为 StreamEvent) )
type AgentService ¶
type AgentService struct {
// contains filtered or unexported fields
}
AgentService 是 Agent 执行架构的编排层(即 design.md 中的 AgentTaskManager)。
它把 Client(Provider 门面)、TaskRepository、PermissionManager、EventRepository、 EventBus 与 PermissionPolicy 组合成一条完整的调用链路:
RunTask 创建任务 → 启动 goroutine 执行 Agent → Agent 通过 Runtime.Emit 输出事件(持久化 + 广播) → Agent 通过 Runtime.RequestPermission 请求权限(持久化 pending + 任务置为 waiting) → UI 调用 ApprovePermission / DenyPermission(更新 DB + 唤醒 Agent) → Agent 恢复执行,直至 completed / failed
Recover 用于后端重启后重建运行态。
func NewService ¶
func NewService(cfg ServiceConfig) *AgentService
NewService 创建 AgentService,未提供的依赖使用安全的默认值。
注意:仓库 / 管理器(Tasks / Events / Perms / Questions / Memory / Profiles)由调用方 注入(见 container 的依赖注入配置)。数据库才是状态源,因此这里不再提供内存仓库兜底; 仅 EventBus / PermissionPolicy 这类无状态组件提供默认值。
func (*AgentService) AnswerQuestion ¶ added in v0.1.5
func (s *AgentService) AnswerQuestion(ctx context.Context, id int64, answer AskUserAnswer, by string) error
AnswerQuestion 提交用户对一次提问的作答(供 UI / HTTP 层调用)。
func (*AgentService) ApprovePermission ¶
ApprovePermission 批准权限请求(供 UI / HTTP 层调用)。
func (*AgentService) CancelTask ¶
func (s *AgentService) CancelTask(ctx context.Context, taskID int64) error
CancelTask 取消任务:取消执行上下文并置为 canceled。
func (*AgentService) CreateTask ¶
CreateTask 创建任务(不启动执行)。
供 HTTP 层使用:先拿到 taskID 订阅事件,再调用 StartTask 启动,避免错过 task.created 等早期事件。
func (*AgentService) DeleteMemory ¶
func (s *AgentService) DeleteMemory(ctx context.Context, id string) error
DeleteMemory 删除记忆,并广播记忆事件。
func (*AgentService) DeleteProfile ¶
DeleteProfile 删除用户自定义 Profile(内置 Profile 不可删除)。
func (*AgentService) DenyPermission ¶
DenyPermission 拒绝权限请求(供 UI / HTTP 层调用)。
func (*AgentService) GetEvents ¶
func (s *AgentService) GetEvents(ctx context.Context, taskID int64, after int64) ([]*AgentEvent, error)
GetEvents 增量拉取任务事件(after 为上次收到的最大 sequence)。
func (*AgentService) GetPendingPermissions ¶
func (s *AgentService) GetPendingPermissions(ctx context.Context, taskID int64) ([]*PermissionRequest, error)
GetPendingPermissions 查询任务当前待确认的权限请求。
func (*AgentService) GetPendingQuestions ¶ added in v0.1.5
func (s *AgentService) GetPendingQuestions(ctx context.Context, taskID int64) ([]*QuestionRequest, error)
GetPendingQuestions 查询任务当前待作答的提问请求。
func (*AgentService) GetProfile ¶
GetProfile 按 ID 返回 Profile(内置 Profile 全局共享、任意用户可读)。
func (*AgentService) GetSystemSpromptByProfile ¶ added in v0.1.5
func (s *AgentService) GetSystemSpromptByProfile(ctx context.Context, profile *Profile, vars map[string]any, userID string, selectedSkills []string) string
applyProfile 依据 Profile 生成本轮最终的 SystemPrompt。
入参:
- profile:已解析的 Agent Profile(为 nil 时返回空提示词,表示不附加系统提示词);
- vars:渲染 Profile.SystemPrompt(pongo2 模板)所用的变量,通常为 Request.SystemPromptVars;
- userID:记忆 / 项目上下文的归属用户(为空时不注入背景);
- selectedSkills:本轮启用的技能名(为空表示全部);据此把技能指令正文注入提示词。
处理顺序:渲染 Profile 模板 → 注入技能指令 → 按 Profile.Context 开关注入记忆 / 项目上下文。 模板渲染失败时退回原始模板,保证调用仍可进行。
func (*AgentService) GetTaskRequest ¶ added in v0.1.3
GetTaskRequest 按任务 ID 加载任务,返回任务持久化的 Request 内容。
供 UI 调试 / 审计使用。注意:这里返回的是任务创建时的原始请求,未应用 Agent Profile; 真正发送给 Provider 的系统提示词在任务执行时由 run 经 resolveProfile / applyProfile 渲染(Profile 模板 + SystemPromptVars + 背景注入)。
func (*AgentService) ListMemory ¶
func (s *AgentService) ListMemory(ctx context.Context, userID string, offset, limit int, kinds ...MemoryKind) ([]*Memory, int64, error)
ListMemory 分页查询某用户的记忆;kinds 为空表示全部类别。
func (*AgentService) ListProfiles ¶
ListProfiles 返回内置与当前用户自定义的 Profile 列表(合并视图)。
func (*AgentService) PageEvents ¶
func (s *AgentService) PageEvents(ctx context.Context, offset, limit int, taskID int64) ([]*AgentEvent, int64, error)
PageEvents 分页查询事件;taskID 为 0 表示全部任务。
func (*AgentService) PagePermissions ¶
func (s *AgentService) PagePermissions(ctx context.Context, offset, limit int, taskID int64, statuses ...PermissionStatus) ([]*PermissionRequest, int64, error)
PagePermissions 分页查询权限请求;taskID 为 0 表示全部任务,statuses 为空表示全部状态。
func (*AgentService) PageQuestions ¶ added in v0.1.5
func (s *AgentService) PageQuestions(ctx context.Context, offset, limit int, taskID int64, statuses ...QuestionStatus) ([]*QuestionRequest, int64, error)
PageQuestions 分页查询提问请求;taskID 为 0 表示全部任务,statuses 为空表示全部状态。
func (*AgentService) PageTasks ¶
func (s *AgentService) PageTasks(ctx context.Context, offset, limit int, statuses ...TaskStatus) ([]*Task, int64, error)
PageTasks 分页查询任务(offset/limit 由上层根据 types.Pagination 计算)。
func (*AgentService) ProjectContext ¶
ProjectContext 返回当前用户激活项目下的上下文文本块(例如已完成的分析节点)。
未配置项目上下文提供者或用户为空时返回空串;查询失败时返回错误。 供 HTTP 层直接向用户展示注入 Agent 系统提示词的项目背景。
func (*AgentService) Recover ¶
func (s *AgentService) Recover(ctx context.Context) error
Recover 在后端重启后重建运行态(见 design.md 第 6 / 19 节)。
当前内存实现下:
- 没有活跃 goroutine 的 running 任务:无法恢复执行,标记为 failed(interrupted)。
- 没有活跃 goroutine 的 waiting_permission 任务:pending 权限已持久化, UI 仍可通过 GetPendingPermissions 拉取并批准 / 拒绝(更新 DB); 但 Agent 进程已丢失,真正“恢复执行”依赖各 Provider 的 checkpoint / resume 能力。
func (*AgentService) RenderSystemPrompt ¶ added in v0.1.5
func (s *AgentService) RenderSystemPrompt(ctx context.Context, userID string, profileID int64, vars map[string]any) (*Profile, string, error)
RenderSystemPrompt 按 Profile ID 解析 Profile,并用 vars 渲染其系统提示词模板, 返回真正的系统提示词(供 DescribeEnv 等前端展示 / 调试场景使用)。
Profile 不存在或未配置系统提示词时返回空串、nil 错误。
func (*AgentService) ResolveProfile ¶ added in v0.1.5
ResolveProfile 按 ID 解析 Profile,与 run 内应用 Profile 的解析路径保持一致 (id 为 0 时回退到内置默认 Profile)。
与 GetProfile 的区别:GetProfile 会校验自定义 Profile 的归属(仅所属用户可读), 而 ResolveProfile 仅按 ID 解析,适合“已经知道要用的 Profile ID、只取其配置”的场景。
func (*AgentService) RetrieveMemory ¶
func (s *AgentService) RetrieveMemory(ctx context.Context, userID, query string, limit int) ([]*Memory, error)
RetrieveMemory 检索与 query 相关的记忆。
func (*AgentService) RunTask ¶
func (s *AgentService) RunTask(ctx context.Context, req Request, handler StreamHandler) (*Task, error)
RunTask 创建任务并异步执行(流式语义)。
执行与调用方 ctx 解耦:任务在独立 goroutine 中运行,可跨多次 HTTP 请求存活, 通过权限确认 / 取消 / 恢复驱动其生命周期。返回的任务对象用于前端轮询 / 订阅。
func (*AgentService) RunTaskSync ¶
RunTaskSync 同步执行一次性任务:创建 → 运行 → 返回聚合结果。
供需要一次性拿到结果的业务(如 AISummaryWorker)使用,替代直接调用 agent.Client.Invoke。 与 RunTask / StartTask 不同,它不启动 goroutine,直接在调用方同步执行。
若调用方需要在任务创建后、执行前拿到 taskID(例如把摘要记录立即关联到任务), 请改用 CreateTask + RunTaskSyncByID 的两步形式。
func (*AgentService) RunTaskSyncByID ¶ added in v0.1.4
RunTaskSyncByID 同步执行已创建的任务,返回聚合结果。
与 RunTaskSync 的区别在于任务创建被前置:调用方可以先 CreateTask 拿到 taskID 并完成 关联(例如 AISummaryWorker 在生成前把摘要与任务绑定),再调用本方法执行。
func (*AgentService) SaveMemory ¶
func (s *AgentService) SaveMemory(ctx context.Context, memory *Memory) error
SaveMemory 创建或更新一条记忆,并广播记忆事件(实时通知层)。
func (*AgentService) SaveProfile ¶
func (s *AgentService) SaveProfile(ctx context.Context, profile *Profile) error
SaveProfile 创建或更新 Profile(内置 Profile 也允许更新)。
func (*AgentService) StartTask ¶
func (s *AgentService) StartTask(ctx context.Context, taskID int64, handler StreamHandler) error
StartTask 启动已创建任务的异步执行。
func (*AgentService) Subscribe ¶
func (s *AgentService) Subscribe(taskID int64, handler EventHandler) func()
Subscribe 订阅任务事件(taskID 为 0 表示订阅全部任务),返回取消订阅函数。 供 WS / SSE 实时推送层使用;刷新恢复历史请使用 GetEvents。
type AskUserAnswer ¶ added in v0.1.5
type AskUserAnswer struct {
RequestID string `json:"request_id,omitempty"`
Answers []QuestionAnswer `json:"answers"`
}
AskUserAnswer 是用户对一次提问的全部作答,也是 ask_user 工具回传给模型的结果。
type AskUserInput ¶ added in v0.1.5
type AskUserInput struct {
RequestID string `json:"request_id,omitempty"` // 模型侧请求 ID(可选,用于回填)
Title string `json:"title,omitempty"` // 提问卡片标题
Description string `json:"description,omitempty"` // 补充说明
Questions []Question `json:"questions"` // 需要用户回答的问题列表
}
AskUserInput 是 ask_user 工具的入参,也是持久化到 QuestionRequest 的提问内容。
结构对齐前端的提问卡片:一个 request 可携带多个 questions,每个 question 支持单选 / 多选 / 文本,并可允许用户自定义输入。
type Client ¶
type Client struct {
// contains filtered or unexported fields
}
Client 是 Agent 调用的统一门面(Facade)。
上层业务(AISummaryWorker、LLMHandler 等)只依赖 Client,不直接感知具体 Provider。 Client 负责:按请求中的 Provider(或默认 Provider)解析 Agent 实例,并转发 Invoke / Stream。
func (*Client) InvokeRuntime ¶
InvokeRuntime 使用调用方提供的 Runtime 执行一次性任务(供 AgentService 任务模式使用)。
type ContextConfig ¶
type ContextConfig struct {
InjectMemory bool `json:"inject_memory"`
InjectProject bool `json:"inject_project"`
}
ContextConfig 控制 AgentService 在调用前注入哪些背景。
- InjectMemory:检索长期记忆并拼进 SystemPrompt;
- InjectProject:把当前项目已完成的分析节点等背景拼进 SystemPrompt。 (只有撰写文章 / 报告一类的任务才需要项目背景,因此默认关闭。)
type Conversation ¶
type Conversation struct {
ID int64 `json:"id,string" gorm:"column:id;primaryKey;type:bigint;autoIncrement:false"`
UserID string `json:"user_id" gorm:"column:user_id;type:varchar(64);index"`
Provider string `json:"provider" gorm:"column:provider;type:varchar(64)"`
Model string `json:"model" gorm:"column:model;type:varchar(128)"`
// Messages 保存完整历史(system 提示词之外的 user/assistant 消息)。
// 关系由 Repository 自行维护(独立表 agent_conversation_messages),
// 不使用 GORM 的 HasMany 关联,因此标记为 gorm:"-"。
Messages []Message `json:"messages" gorm:"-"`
// CurrentTaskID 记录当前活跃轮次(running / waiting_permission)的任务 ID;
// 轮次结束时置空。供前端刷新 / 切换会话时恢复实时流。
CurrentTaskID int64 `json:"current_task_id,string" gorm:"column:current_task_id;type:bigint"`
CreatedAt time.Time `json:"created_at" gorm:"column:created_at"`
UpdatedAt time.Time `json:"updated_at" gorm:"column:updated_at"`
}
Conversation 是一次多轮对话的持久化对象。
Messages 保存完整历史(system 提示词之外的 user/assistant 消息), 每一轮执行前把历史拼进 Request.Messages,执行结束后把 assistant 回复写回历史。
func NewConversation ¶
func NewConversation(userID, provider, model string) *Conversation
NewConversation 创建一个空的会话。
func (*Conversation) BeforeCreate ¶ added in v0.1.3
func (c *Conversation) BeforeCreate(_ *gorm.DB) error
BeforeCreate 在写入数据库前用雪花 ID 初始化主键。
type ConversationMessage ¶
type ConversationMessage struct {
ID int64 `json:"id,string" gorm:"column:id;primaryKey;type:bigint;autoIncrement:false"`
ConversationID int64 `json:"conversation_id,string" gorm:"column:conversation_id;type:bigint;index"`
Seq int `json:"seq" gorm:"column:seq;index"`
Role string `json:"role" gorm:"column:role;type:varchar(32)"`
Kind string `json:"kind,omitempty" gorm:"column:kind;type:varchar(32);index"`
TaskID int64 `json:"task_id,string,omitempty" gorm:"column:task_id;type:bigint;index"`
Content string `json:"content" gorm:"column:content;type:text"`
Data any `json:"data,omitempty" gorm:"serializer:json"`
CreatedAt time.Time `json:"created_at" gorm:"column:created_at"`
}
ConversationMessage 是会话中的一条消息,以独立表持久化。
与 Conversation 的关系(ConversationID 外键)由 Repository 自行维护, 不使用 GORM 的 HasMany / Preload 关联机制。
func (*ConversationMessage) BeforeCreate ¶ added in v0.1.3
func (m *ConversationMessage) BeforeCreate(_ *gorm.DB) error
BeforeCreate 在写入数据库前用雪花 ID 初始化主键。
func (ConversationMessage) TableName ¶
func (ConversationMessage) TableName() string
TableName 返回会话消息表的表名。
type ConversationRepository ¶
type ConversationRepository interface {
Get(ctx context.Context, id int64) (*Conversation, error)
Create(ctx context.Context, conv *Conversation) error
Update(ctx context.Context, conv *Conversation) error
// Page 分页查询会话(按 UpdatedAt 降序);userID 为空表示全部用户。
Page(ctx context.Context, userID string, offset, limit int) ([]*Conversation, int64, error)
}
ConversationRepository 持久化会话。
实现见 internal/agent/repository 子包(基于 GORM 的数据库实现)。
type ConversationService ¶
type ConversationService struct {
// contains filtered or unexported fields
}
ConversationService 编排多轮对话:负责历史拼接 + 复用 AgentService 执行每一轮。
func NewConversationService ¶
func NewConversationService(agent *AgentService, repo ConversationRepository) *ConversationService
NewConversationService 创建 ConversationService。
func (*ConversationService) CreateTurn ¶
func (s *ConversationService) CreateTurn(ctx context.Context, in TurnInput) (*Task, *Conversation, error)
CreateTurn 准备一轮执行(不启动):
- 取得会话级锁(保证同一会话轮次串行);
- 加载 / 创建会话,追加 user 消息并持久化;
- 用完整历史组装 Request(SessionID = 会话 ID),交给 AgentService.CreateTask;
- 登记本轮中间态,返回 task 供上层(handler)在启动前订阅 WS。
锁在本轮结束时由 finishTurn 释放。
func (*ConversationService) GetConversation ¶
func (s *ConversationService) GetConversation(ctx context.Context, id int64) (*Conversation, error)
GetConversation 查询会话(含完整历史消息)。
func (*ConversationService) PageConversations ¶
func (s *ConversationService) PageConversations(ctx context.Context, userID string, offset, limit int) ([]*Conversation, int64, error)
PageConversations 分页查询会话;userID 为空表示全部用户。
type EventBus ¶
type EventBus interface {
// Publish 发布一个事件给订阅了该任务(或全部任务)的订阅者。
Publish(ctx context.Context, event AgentEvent)
// Subscribe 订阅某任务的事件;taskID 为空表示订阅全部任务。
// 返回的 unsubscribe 用于取消订阅。
Subscribe(taskID int64, handler EventHandler) (unsubscribe func())
}
EventBus 是实时通知层接口:只负责“告诉 UI 状态发生了变化”,不承担状态存储。
数据库(Repository)才是状态源;EventBus 之上可以接 WS / SSE 做实时推送。
type EventHandler ¶
type EventHandler func(ctx context.Context, event AgentEvent) error
EventHandler 是事件订阅回调。 返回 error 表示处理失败;EventBus 目前采用同步分发,回调应避免阻塞。
type EventRepository ¶
type EventRepository interface {
// Append 为事件分配 sequence 并追加到任务事件流。
Append(ctx context.Context, event *AgentEvent) error
// ListByTask 返回任务中 sequence 大于 after 的事件(升序)。
ListByTask(ctx context.Context, taskID int64, after int64) ([]*AgentEvent, error)
// Page 分页查询事件(按 CreatedAt 升序);taskID 为 0 表示全部任务。
Page(ctx context.Context, taskID int64, offset, limit int) ([]*AgentEvent, int64, error)
}
EventRepository 持久化任务事件(带 per-task 单调递增 sequence)。
type Memory ¶
type Memory struct {
ID string `json:"id" gorm:"column:id;primaryKey;type:varchar(64)"`
UserID string `json:"user_id" gorm:"column:user_id;type:varchar(64);index:idx_agent_memories_user_kind,priority:1"`
SessionID string `json:"session_id,omitempty" gorm:"column:session_id;type:varchar(64);index"`
Kind MemoryKind `json:"kind" gorm:"column:kind;type:varchar(32);index:idx_agent_memories_user_kind,priority:2"`
Content string `json:"content" gorm:"column:content;type:text"`
// Importance 表示记忆重要度(0-10),检索排序时权重更高。
Importance int `json:"importance" gorm:"column:importance"`
// Metadata 承载扩展信息(来源、标签等),由序列化为 JSON 持久化。
Metadata map[string]any `json:"metadata,omitempty" gorm:"column:metadata;serializer:json"`
CreatedAt time.Time `json:"created_at" gorm:"column:created_at"`
UpdatedAt time.Time `json:"updated_at" gorm:"column:updated_at"`
LastAccessedAt *time.Time `json:"last_accessed_at,omitempty" gorm:"column:last_accessed_at"`
}
Memory 是一条可跨轮次 / 跨会话检索的持久化记忆。
UserID 是记忆的主归属维度(长期记忆按用户隔离);SessionID 可选,用于把记忆 与某个具体会话关联(例如该会话的摘要)。
type MemoryConfig ¶
type MemoryConfig struct {
Repo MemoryRepository
Retriever MemoryRetriever
Extractor MemoryExtractor
}
MemoryConfig 是 MemoryManager 的依赖配置。
type MemoryExtractor ¶
type MemoryExtractor interface {
Extract(ctx context.Context, turn MemoryTurn) ([]*Memory, error)
}
MemoryExtractor 从一轮完成的对话 / 任务结果中提取值得长期记住的记忆。
这是一个可选钩子:AgentService 在任务完成后调用,把提取出的记忆写入 Repository。 返回 nil 表示本轮无需写入任何记忆。默认不配置(不提取);可由上层注入基于规则 或基于 LLM 的实现。
func MockMemoryExtractor ¶
func MockMemoryExtractor() MemoryExtractor
MockMemoryExtractor 返回一个模拟的记忆提取器:把本轮的用户提问与助手回复 组合成一条 summary 记忆(内容做截断防止过长)。
用于演示 / 测试「任务完成 → 提取 → 落库」的调用链,不接入真实 LLM 或规则引擎; 生产环境应替换为基于规则或基于 LLM 的 MemoryExtractor 实现。
type MemoryExtractorFunc ¶
type MemoryExtractorFunc func(ctx context.Context, turn MemoryTurn) ([]*Memory, error)
MemoryExtractorFunc 是把普通函数适配为 MemoryExtractor 的辅助类型。
func (MemoryExtractorFunc) Extract ¶
func (f MemoryExtractorFunc) Extract(ctx context.Context, turn MemoryTurn) ([]*Memory, error)
Extract 实现 MemoryExtractor 接口。
type MemoryKind ¶
type MemoryKind string
MemoryKind 描述记忆的类别,用于检索排序与前端展示。
const ( MemoryKindFact MemoryKind = "fact" // 用户偏好 / 事实(长期有效) MemoryKindSummary MemoryKind = "summary" // 会话 / 任务摘要 MemoryKindNote MemoryKind = "note" // 通用备注 MemoryKindEvent MemoryKind = "event" // 事件记录(带时间语义) )
type MemoryManager ¶
type MemoryManager struct {
// contains filtered or unexported fields
}
MemoryManager 负责记忆的创建、查询、检索与提取编排。
它是 memory 域的「门面」:上层(AgentService / HTTP 层)只依赖 MemoryManager, 不直接感知 Repository / Retriever / Extractor 的具体实现。
func NewMemoryManager ¶
func NewMemoryManager(cfg MemoryConfig) *MemoryManager
NewMemoryManager 创建记忆管理器;未提供的依赖使用安全默认值。
func (*MemoryManager) Delete ¶
func (m *MemoryManager) Delete(ctx context.Context, id string) error
Delete 删除记忆。
func (*MemoryManager) Extract ¶
func (m *MemoryManager) Extract(ctx context.Context, turn MemoryTurn) ([]*Memory, error)
Extract 调用已配置的提取器,从一轮执行中提取待写入的记忆。 未配置提取器时返回空(不提取)。
func (*MemoryManager) List ¶
func (m *MemoryManager) List(ctx context.Context, userID string, offset, limit int, kinds ...MemoryKind) ([]*Memory, int64, error)
List 分页查询某用户的记忆;kinds 为空表示全部类别。
func (*MemoryManager) Retrieve ¶
func (m *MemoryManager) Retrieve(ctx context.Context, userID, query string, limit int) ([]*Memory, error)
Retrieve 检索与 query 相关的记忆,并刷新这些记忆的访问时间(Touch)。
type MemoryRepository ¶
type MemoryRepository interface {
Create(ctx context.Context, memory *Memory) error
Get(ctx context.Context, id string) (*Memory, error)
Update(ctx context.Context, memory *Memory) error
Delete(ctx context.Context, id string) error
// ListByUser 分页查询某用户的记忆(按 UpdatedAt 降序);kinds 为空表示全部类别。
ListByUser(ctx context.Context, userID string, offset, limit int, kinds ...MemoryKind) ([]*Memory, int64, error)
// Search 按关键词检索某用户的记忆(返回按相关度 + 重要度排序)。
// 基础实现为子串 / LIKE 匹配,可被更高级的检索器(向量 / 语义)替换。
Search(ctx context.Context, userID, query string, limit int) ([]*Memory, error)
}
MemoryRepository 持久化记忆。
实现见 internal/agent/repository 子包(基于 GORM 的数据库实现)。
type MemoryRetriever ¶
type MemoryRetriever interface {
// Retrieve 返回与 query 相关的记忆,按相关度降序,最多 limit 条。
Retrieve(ctx context.Context, userID, query string, limit int) ([]*Memory, error)
}
MemoryRetriever 从记忆中检索与查询相关的内容。
与 Repository.Search 的区别:Retriever 是可插拔的「检索策略」抽象, 默认实现退化为关键词匹配(委托 Repository.Search);后续可接入向量检索 / 语义检索, 而无须改动 AgentService 的注入逻辑。
type MemoryTurn ¶
MemoryTurn 描述一轮已完成执行的上下文,供 MemoryExtractor 提取记忆。
type Message ¶
type Message struct {
Role string `json:"role"` // system / user / assistant / tool
Content string `json:"content"` // 文本内容
Kind string `json:"kind,omitempty"`
TaskID int64 `json:"task_id,string,omitempty"`
Data any `json:"data,omitempty"`
}
Message 是一条对话消息。
type MessageBlock ¶
type MessageBlock struct {
ID string `json:"id"` // messageId
TurnID string `json:"turn_id,omitempty"` // 所属 turn
Content string `json:"content"`
ToolCalls []ToolCall `json:"tool_calls,omitempty"`
}
MessageBlock 是一条完整的 assistant 消息(对应 AssistantMessageData), 包含它发起的工具调用列表。
type ModelProviderConfig ¶ added in v0.1.4
type ModelProviderConfig struct {
Model string `json:"model"`
BaseURL string `json:"base_url"`
APIKey string `json:"api_key"`
BearerToken string `json:"bearer_token"`
WorkingDir string `json:"working_dir"`
Extra map[string]string `json:"extra"`
}
ModelProviderConfig 描述一个「模型提供商」的连接配置(base_url / api_key / 类型等)。
与 config.ModelProviderConfig 一一对应,由容器启动时从配置映射而来。Provider 在每次 调用时按 Profile 指定的模型名(req.Model)从此表解析出本次调用所需的 LLM 配置。
type Operation ¶
type Operation struct {
ID string `json:"id,omitempty"`
Type OperationType `json:"type"`
// read / write / delete / move
Path string `json:"path,omitempty"`
// write
Content string `json:"content,omitempty"`
// execute
Command string `json:"command,omitempty"`
// Metadata 承载操作相关的扩展信息(如命令参数、网络地址等)。
Metadata map[string]any `json:"metadata,omitempty"`
}
Operation 描述 Agent 想要执行的一个原子操作。
它刻意与 PermissionRequest 分离:Operation 只描述“要做什么”, PermissionRequest 记录“这个操作是否被允许、当前处于什么状态”。
type OperationType ¶
type OperationType string
OperationType 描述 Agent 想要执行的操作类别。
未来可继续扩展(install_package / git_push / docker / kubernetes ...), 权限策略按类型决定 allow / deny / ask。
const ( OperationRead OperationType = "read" // 读取文件 OperationWrite OperationType = "write" // 写入 / 修改文件 OperationDelete OperationType = "delete" // 删除文件 OperationMove OperationType = "move" // 移动 / 重命名文件 OperationExecute OperationType = "execute" // 执行命令 / 脚本 OperationNetwork OperationType = "network" // 网络访问 )
type Options ¶
type Options struct {
WorkingDir string `json:"working_dir"`
Extra map[string]string `json:"extra"`
// Providers 是模型提供商配置表(key 为模型名,与 Profile.Model 对应)。
//
// Provider 据此按请求解析出的模型名查找 base_url / api_key / 类型等 LLM 配置,
// 用于构建 session / provider 配置。为 nil 表示无自定义模型提供商。
Providers map[string]ModelProviderConfig `json:"-"`
// Tools 是本次调用可用的工具注册表。
//
// Provider 据此向模型暴露工具定义(tool.List()),并通过 ToolRunner /
// tool.Executor 执行模型发起的工具调用。为 nil 表示本次调用不启用工具。
Tools *tool.Registry `json:"-"`
}
Options 是构建 Agent 实例所需的通用配置;具体 Provider 按需读取。
模型相关的连接配置(base_url / api_key / 类型等)不再作为单值字段存在,而是由 Providers(模型名 → 配置)承载:一次请求使用的模型由 Profile.Model 决定,Provider 据此按模型名解析出本次调用所需的 LLM 配置。
type PermissionDecision ¶
type PermissionDecision string
PermissionDecision 是权限策略 / 决策结果。
const ( DecisionAllow PermissionDecision = "allow" // 允许执行 DecisionDeny PermissionDecision = "deny" // 拒绝执行 DecisionAsk PermissionDecision = "ask" // 需要人工确认 )
type PermissionManager ¶
type PermissionManager struct {
// contains filtered or unexported fields
}
PermissionManager 负责权限请求的创建、持久化与决策流转。
它是“数据库才是状态源”的核心实现:
- Create:把权限请求写入 Repository(pending),等待 UI 确认;
- Approve / Deny:更新 Repository 状态,并唤醒正在阻塞等待的 Agent;
- Wait:Agent 侧阻塞等待决策(内存 channel 只是运行时同步机制,真正状态在 Repository)。
注意:事件广播由上层 AgentService 负责(单一事件出口),PermissionManager 只维护状态。 Approve / Deny 与 Wait 通过互斥锁 + waiter channel 协同,避免“决策先于等待注册”的竞态。
func NewPermissionManager ¶
func NewPermissionManager(repo PermissionRepository) *PermissionManager
NewPermissionManager 创建权限管理器。
func (*PermissionManager) Approve ¶
func (m *PermissionManager) Approve(ctx context.Context, id int64, by string) (*PermissionRequest, error)
Approve 批准权限请求,返回更新后的权限请求;并唤醒正在等待的 Agent。
func (*PermissionManager) Create ¶
func (m *PermissionManager) Create(ctx context.Context, taskID int64, sessionID string, operation Operation) (*PermissionRequest, error)
Create 创建一个 pending 状态的权限请求并返回。
func (*PermissionManager) Deny ¶
func (m *PermissionManager) Deny(ctx context.Context, id int64, by string) (*PermissionRequest, error)
Deny 拒绝权限请求,返回更新后的权限请求;并唤醒正在等待的 Agent。
func (*PermissionManager) Get ¶
func (m *PermissionManager) Get(ctx context.Context, id int64) (*PermissionRequest, error)
Get 按 ID 查询权限请求。
func (*PermissionManager) GetPending ¶
func (m *PermissionManager) GetPending(ctx context.Context, taskID int64) ([]*PermissionRequest, error)
GetPending 返回某任务当前全部待确认的权限请求。
func (*PermissionManager) Page ¶
func (m *PermissionManager) Page(ctx context.Context, offset, limit int, taskID int64, statuses ...PermissionStatus) ([]*PermissionRequest, int64, error)
Page 分页查询权限请求;taskID 为 0 表示全部任务,statuses 为空表示全部状态。
func (*PermissionManager) Wait ¶
func (m *PermissionManager) Wait(ctx context.Context, id int64) (PermissionDecision, error)
Wait 阻塞等待权限请求的决策。
返回:
- DecisionAllow:已批准(批准后立即把请求标记为 consumed);
- DecisionDeny:已拒绝 / 过期 / 取消;
- error:ctx 取消等。
type PermissionPolicy ¶
type PermissionPolicy interface {
Check(ctx context.Context, userID string, operation Operation) PermissionDecision
}
PermissionPolicy 判断一个 Operation 应被允许、拒绝,还是需要人工确认。
Agent 在执行前把 Operation 交给策略;策略返回 ask 时,由 PermissionManager 持久化一个 pending 的 PermissionRequest 并等待 UI 确认。
func AllowAllPermissionPolicy ¶
func AllowAllPermissionPolicy() PermissionPolicy
AllowAllPermissionPolicy 返回一个“全部放行”的策略实例。
func DefaultPermissionPolicy ¶
func DefaultPermissionPolicy() PermissionPolicy
DefaultPermissionPolicy 返回框架内置的默认策略实例。
func NewUserPermissionPolicy ¶ added in v0.1.4
func NewUserPermissionPolicy(provider UserAgentConfigProvider) PermissionPolicy
NewUserPermissionPolicy 创建用户感知的权限策略。
- provider 为 nil 时退化为空配置(全部走默认策略);
- Check 读取 userID 对应的 UserAgentConfig.Permissions,命中则采用该决策, 否则(无配置 / 无该类型条目 / 读取失败)回退到 defaultPermissionPolicy。
type PermissionRepository ¶
type PermissionRepository interface {
Create(ctx context.Context, permission *PermissionRequest) error
Get(ctx context.Context, id int64) (*PermissionRequest, error)
Update(ctx context.Context, permission *PermissionRequest) error
ListPendingByTask(ctx context.Context, taskID int64) ([]*PermissionRequest, error)
// Page 分页查询权限请求(按 CreatedAt 升序);taskID 为 0 表示全部任务,statuses 为空表示全部状态。
Page(ctx context.Context, offset, limit int, taskID int64, statuses ...PermissionStatus) ([]*PermissionRequest, int64, error)
}
PermissionRepository 持久化权限请求。
type PermissionRequest ¶
type PermissionRequest struct {
ID int64 `json:"id,string" gorm:"column:id;primaryKey;type:bigint;autoIncrement:false"`
TaskID int64 `json:"task_id,string" gorm:"column:task_id;type:bigint;index"`
SessionID string `json:"session_id,omitempty" gorm:"column:session_id;type:varchar(64)"`
Operation Operation `json:"operation" gorm:"serializer:json"`
Status PermissionStatus `json:"status" gorm:"column:status;type:varchar(32);index"`
CreatedAt time.Time `json:"created_at" gorm:"column:created_at"`
UpdatedAt time.Time `json:"updated_at" gorm:"column:updated_at"`
ResolvedAt *time.Time `json:"resolved_at,omitempty" gorm:"column:resolved_at"`
ResolvedBy *string `json:"resolved_by,omitempty" gorm:"column:resolved_by;type:varchar(64)"`
}
PermissionRequest 记录一次权限请求及其决策结果,是权限域的持久化对象。
它是“数据库才是状态源”这一原则的载体:Agent 阻塞等待的只是内存中的 channel, 真正的状态始终保存在 Repository 中,因此浏览器刷新 / 后端重启后仍可恢复。
func NewPermissionRequest ¶
func NewPermissionRequest(taskID int64, sessionID string, operation Operation) *PermissionRequest
NewPermissionRequest 构建一个 pending 状态的权限请求。
func (*PermissionRequest) BeforeCreate ¶ added in v0.1.3
func (p *PermissionRequest) BeforeCreate(_ *gorm.DB) error
BeforeCreate 在写入数据库前用雪花 ID 初始化主键。
func (*PermissionRequest) Decision ¶
func (p *PermissionRequest) Decision() PermissionDecision
Decision 把当前状态映射为 Agent 可消费的决策结果。
func (PermissionRequest) TableName ¶
func (PermissionRequest) TableName() string
TableName 返回权限请求表的表名。
func (*PermissionRequest) TransitionTo ¶
func (p *PermissionRequest) TransitionTo(next PermissionStatus) bool
TransitionTo 校验并执行权限状态迁移;非法迁移返回 false 且不改变状态。
type PermissionStatus ¶
type PermissionStatus string
PermissionStatus 是权限请求的生命周期状态。
状态机(详见 design.md 第 8 节):
pending → approved → consumed pending → denied / expired / canceled
const ( PermissionPending PermissionStatus = "pending" // 等待人工确认 PermissionApproved PermissionStatus = "approved" // 已批准 PermissionDenied PermissionStatus = "denied" // 已拒绝 PermissionExpired PermissionStatus = "expired" // 已过期 PermissionCanceled PermissionStatus = "canceled" // 已取消(任务被取消等) PermissionConsumed PermissionStatus = "consumed" // 已消费:Agent 已恢复并继续执行 )
type Profile ¶
type Profile struct {
ID int64 `json:"id,string" gorm:"column:id;primaryKey;type:bigint;autoIncrement:false"`
// Name 仅作为展示名使用,不参与任何查询。
Name string `json:"name" gorm:"column:name;type:varchar(128)"`
Description string `json:"description" gorm:"column:description;type:text"`
UserID string `json:"user_id" gorm:"column:user_id;type:varchar(64);index:idx_agent_profiles_user"`
IsDefault bool `json:"is_default" gorm:"column:is_default"`
IsBuiltin bool `json:"is_builtin" gorm:"column:is_builtin"`
SystemPrompt string `json:"system_prompt" gorm:"column:system_prompt;type:text"`
// Model 指定本 Profile 使用的模型名(对应 config.agent.providers 的 key)。
// 为空时回退到请求级 req.Model(若仍未指定则由 Provider 兜底)。
Model string `json:"model" gorm:"column:model;type:varchar(128)"`
// Provider 指定本 Profile 使用的 Agent(Provider)名称(mock | claude_code | codex | copilot | custom)。
// 为空时回退到请求级 req.Provider(若仍未指定则由 Client 的默认 Provider 兜底)。
Provider string `json:"provider" gorm:"column:provider;type:varchar(64)"`
Skills []string `json:"skills" gorm:"column:skills;serializer:json"`
Context ContextConfig `json:"context" gorm:"column:context;serializer:json"`
CreatedAt time.Time `json:"created_at" gorm:"column:created_at"`
UpdatedAt time.Time `json:"updated_at" gorm:"column:updated_at"`
}
Profile 描述一类任务的 Agent 配置(系统提示词 + 技能 + 上下文注入开关)。
与 Options / Request(每次调用的动态参数)不同,Profile 是「按任务类型选择」的静态 配置快照:HTTP 层或前端在发起调用时通过 Request.ProfileID 指定 Profile,AgentService 在调用前按 ID 解析并应用(合并系统提示词、过滤技能、按开关注入背景)。
Name 仅用于展示;Profile 的查询 / 引用一律使用 ID。 UserID 为空表示系统级(内置)Profile;非空表示某用户的自定义 Profile。
func BuiltinProfiles ¶
func BuiltinProfiles() []*Profile
BuiltinProfiles 返回框架内置 Profile 的种子数据。新增内置 Profile 时在此追加。
内置 Profile 仅作为数据库初始化工具:系统启动时由 EnsureBuiltinProfiles 按 ID 同步到数据库(不存在则新增、已存在则保留)。所有 Profile 的读取 / 写入 / 解析均 走数据库(ProfileRepository),内置 Profile 与用户自定义 Profile 统一存储。
func (*Profile) BeforeCreate ¶ added in v0.1.3
BeforeCreate 在写入数据库前用雪花 ID 初始化主键(仅 ID 为 0 时)。
type ProfileManager ¶
type ProfileManager struct {
// contains filtered or unexported fields
}
ProfileManager 负责 Profile 的解析、列表与增删改查编排。
内置 Profile 与用户自定义 Profile 均持久化在数据库(ProfileRepository)中,本管理器 只做统一视图的编排:所有解析 / 读取均按 ID 进行(Name 仅用于展示)。内置 Profile 与 用户自定义 Profile 统一存储。
func NewProfileManager ¶
func NewProfileManager(repo ProfileRepository) *ProfileManager
NewProfileManager 创建 Profile 管理器。
type ProfileRepository ¶
type ProfileRepository interface {
Create(ctx context.Context, profile *Profile) error
Get(ctx context.Context, id int64) (*Profile, error)
Update(ctx context.Context, profile *Profile) error
Delete(ctx context.Context, id int64) error
// ListByUser 返回某用户全部自定义 Profile(按名称升序)。
ListByUser(ctx context.Context, userID string) ([]*Profile, error)
// ListBuiltin 返回全部内置 Profile(按名称升序)。
ListBuiltin(ctx context.Context) ([]*Profile, error)
// GetDefault 返回某用户的默认自定义 Profile;不存在时返回 (nil, nil)。
GetDefault(ctx context.Context, userID string) (*Profile, error)
// ClearDefault 清除某用户除 exceptID 外的默认标记。
ClearDefault(ctx context.Context, userID string, exceptID int64) error
}
ProfileRepository 持久化用户自定义 AgentProfile。
与 TaskRepository / MemoryRepository 一致:内置 Profile 由代码定义(不落库), 仅用户自定义 Profile 通过该接口持久化。实现见 internal/agent/repository 子包。
type ProjectContextProvider ¶
type ProjectContextProvider interface {
// ProjectContext 返回当前用户激活项目下的上下文文本块;无可用内容时返回空串。
//
// 返回的文本会作为独立段落追加到 SystemPrompt 末尾。
ProjectContext(ctx context.Context, userID string) (string, error)
}
ProjectContextProvider 是可选的领域上下文提供者。
AgentService 在调用前通过它把当前项目相关的背景(例如已完成的分析节点)注入 SystemPrompt,让 Agent「知道」当前项目的进展与可用结果。它保持 agent 包与领域层 (project / analysis)的解耦:agent 只依赖这个窄接口,具体实现由上层(manager / container)注入。
type Provider ¶
type Provider interface {
// Name 返回 Provider 唯一标识(小写,如 claude_code / codex / copilot / custom)。
Name() string
// New 基于 Options 构建 Agent 实例。
New(opts Options) (Agent, error)
}
Provider 是 Agent 的工厂接口:根据 Options 构建一个 Agent 实例。 这样同一 Provider 可以有不同的配置(不同模型 / 不同 endpoint)。
type Question ¶ added in v0.1.5
type Question struct {
ID string `json:"id"` // 问题标识(答案按此 ID 回填)
Type string `json:"type"` // single_choice / multiple_choice / text
Title string `json:"title"` // 问题文本
Description string `json:"description,omitempty"` // 问题补充说明
Required bool `json:"required,omitempty"` // 是否必答
Options []QuestionOption `json:"options,omitempty"` // 选项(choice 类型)
AllowCustom bool `json:"allow_custom,omitempty"` // 是否允许自定义输入
Placeholder string `json:"placeholder,omitempty"` // 自定义 / 文本输入的占位提示
}
Question 是单个问题。
type QuestionAnswer ¶ added in v0.1.5
type QuestionAnswer struct {
ID string `json:"id"`
Value string `json:"value,omitempty"`
Values []string `json:"values,omitempty"`
Custom string `json:"custom,omitempty"`
}
QuestionAnswer 是单个问题的答案。
- choice:单选填 Value,多选填 Values;
- text:填 Value(Text 为兼容别名,等价于 Value);
- 自定义输入:填 Custom。
type QuestionManager ¶ added in v0.1.5
type QuestionManager struct {
// contains filtered or unexported fields
}
QuestionManager 负责用户提问(AskUser)的创建、持久化与作答流转。
与 PermissionManager 完全同构,是“数据库才是状态源”的又一实现:
- Create:把提问写入 Repository(pending),等待 UI 作答;
- Answer:更新 Repository 状态并唤醒正在阻塞等待的 Agent;
- Wait:Agent 侧阻塞等待作答(内存 channel 只做运行时同步,真正状态在 Repository)。
事件广播由上层 AgentService 负责(单一事件出口),QuestionManager 只维护状态。
func NewQuestionManager ¶ added in v0.1.5
func NewQuestionManager(repo QuestionRepository) *QuestionManager
NewQuestionManager 创建提问管理器。
func (*QuestionManager) Answer ¶ added in v0.1.5
func (m *QuestionManager) Answer(ctx context.Context, id int64, answer AskUserAnswer, by string) (*QuestionRequest, error)
Answer 提交用户作答,返回更新后的提问请求;并唤醒正在等待的 Agent。
func (*QuestionManager) Cancel ¶ added in v0.1.5
func (m *QuestionManager) Cancel(ctx context.Context, id int64) (*QuestionRequest, error)
Cancel 取消一个待作答的提问(任务被取消等);被取消的等待返回 ErrQuestionCanceled。
func (*QuestionManager) Create ¶ added in v0.1.5
func (m *QuestionManager) Create(ctx context.Context, taskID int64, sessionID string, input AskUserInput) (*QuestionRequest, error)
Create 创建一个 pending 状态的提问请求并返回。
func (*QuestionManager) Get ¶ added in v0.1.5
func (m *QuestionManager) Get(ctx context.Context, id int64) (*QuestionRequest, error)
Get 按 ID 查询提问请求。
func (*QuestionManager) GetPending ¶ added in v0.1.5
func (m *QuestionManager) GetPending(ctx context.Context, taskID int64) ([]*QuestionRequest, error)
GetPending 返回某任务当前全部待作答的提问请求。
func (*QuestionManager) Page ¶ added in v0.1.5
func (m *QuestionManager) Page(ctx context.Context, offset, limit int, taskID int64, statuses ...QuestionStatus) ([]*QuestionRequest, int64, error)
Page 分页查询提问请求;taskID 为 0 表示全部任务,statuses 为空表示全部状态。
func (*QuestionManager) Wait ¶ added in v0.1.5
func (m *QuestionManager) Wait(ctx context.Context, id int64) (AskUserAnswer, error)
Wait 阻塞等待提问的作答。
返回:
- AskUserAnswer:用户已作答(快路径可直接从 Repository 读取);
- error:ctx 取消 / 提问被取消等。
type QuestionOption ¶ added in v0.1.5
type QuestionOption struct {
Label string `json:"label"` // 展示文案
Value string `json:"value"` // 提交值
Description string `json:"description,omitempty"` // 选项说明
}
QuestionOption 是单个选项。
type QuestionRepository ¶ added in v0.1.5
type QuestionRepository interface {
Create(ctx context.Context, question *QuestionRequest) error
Get(ctx context.Context, id int64) (*QuestionRequest, error)
Update(ctx context.Context, question *QuestionRequest) error
ListPendingByTask(ctx context.Context, taskID int64) ([]*QuestionRequest, error)
// Page 分页查询提问请求(按 CreatedAt 升序);taskID 为 0 表示全部任务,statuses 为空表示全部状态。
Page(ctx context.Context, offset, limit int, taskID int64, statuses ...QuestionStatus) ([]*QuestionRequest, int64, error)
}
QuestionRepository 持久化用户提问(AskUser)。与 PermissionRepository 同构。
type QuestionRequest ¶ added in v0.1.5
type QuestionRequest struct {
ID int64 `json:"id,string" gorm:"column:id;primaryKey;type:bigint;autoIncrement:false"`
TaskID int64 `json:"task_id,string" gorm:"column:task_id;type:bigint;index"`
SessionID string `json:"session_id,omitempty" gorm:"column:session_id;type:varchar(64)"`
RequestID string `json:"request_id,omitempty" gorm:"column:request_id;type:varchar(64)"`
Title string `json:"title,omitempty" gorm:"column:title;type:text"`
Description string `json:"description,omitempty" gorm:"column:description;type:text"`
Questions []Question `json:"questions" gorm:"serializer:json"`
Status QuestionStatus `json:"status" gorm:"column:status;type:varchar(32);index"`
Answer *AskUserAnswer `json:"answer,omitempty" gorm:"serializer:json"`
CreatedAt time.Time `json:"created_at" gorm:"column:created_at"`
UpdatedAt time.Time `json:"updated_at" gorm:"column:updated_at"`
ResolvedAt *time.Time `json:"resolved_at,omitempty" gorm:"column:resolved_at"`
ResolvedBy *string `json:"resolved_by,omitempty" gorm:"column:resolved_by;type:varchar(64)"`
}
QuestionRequest 记录一次用户提问及其作答结果,是提问域的持久化对象。
与 PermissionRequest 一样遵循“数据库才是状态源”原则:Agent 阻塞等待的只是内存 channel,真正的状态保存在 Repository 中,因此浏览器刷新 / 后端重启后仍可恢复。
func NewQuestionRequest ¶ added in v0.1.5
func NewQuestionRequest(taskID int64, sessionID string, input AskUserInput) *QuestionRequest
NewQuestionRequest 构建一个 pending 状态的提问请求。
func (*QuestionRequest) BeforeCreate ¶ added in v0.1.5
func (q *QuestionRequest) BeforeCreate(_ *gorm.DB) error
BeforeCreate 在写入数据库前用雪花 ID 初始化主键。
func (QuestionRequest) TableName ¶ added in v0.1.5
func (QuestionRequest) TableName() string
TableName 返回提问请求表的表名。
func (*QuestionRequest) TransitionTo ¶ added in v0.1.5
func (q *QuestionRequest) TransitionTo(next QuestionStatus) bool
TransitionTo 校验并执行提问状态迁移;非法迁移返回 false 且不改变状态。
type QuestionStatus ¶ added in v0.1.5
type QuestionStatus string
QuestionStatus 是用户提问(AskUser)的生命周期状态。
状态机与 PermissionStatus 同构:
pending → answered pending → canceled / expired
const ( QuestionPending QuestionStatus = "pending" // 等待用户作答 QuestionAnswered QuestionStatus = "answered" // 用户已作答 QuestionCanceled QuestionStatus = "canceled" // 已取消(任务被取消等) QuestionExpired QuestionStatus = "expired" // 已过期 )
type ReasoningBlock ¶
type ReasoningBlock struct {
ID string `json:"id"` // reasoningId
Content string `json:"content"` // 完整思考文本
}
ReasoningBlock 是一段完整的思考内容(对应 Provider 的完整 reasoning 事件)。
type Registry ¶
type Registry struct {
// contains filtered or unexported fields
}
Registry 负责注册与解析 Provider。 容器启动时把全部 Provider 注册进来,运行时按名称解析。
func NewRegistry ¶
NewRegistry 创建 Registry 并注册传入的 Provider。
type Request ¶
type Request struct {
// Provider 可选:强制指定 Provider 名称;为空则使用 Client 的默认 Provider。
Provider string `json:"provider"`
// Model 可选:模型名称,为空时由 Provider 自行决定。
Model string `json:"model"`
// SessionID 可选:会话标识,用于把多次调用关联到同一会话(与权限 / 任务联动)。
SessionID string `json:"session_id"`
// UserID 可选:发起调用的用户,用于记忆(memory)的归属隔离与检索。
UserID string `json:"user_id,omitempty"`
// ProfileID 可选:AgentProfile ID,AgentService 据此解析系统提示词、技能与上下文注入开关。
ProfileID int64 `json:"profile_id,omitempty,string"`
// Skills 可选:本次调用启用的技能名列表;为空表示使用默认全部技能。
Skills []string `json:"skills,omitempty"`
// SystemPromptVars 是渲染 Profile 系统提示词模板所用的变量(业务上下文)。
//
// 调用方(HTTP Handler)解析 env(type,id) 后把变量放进这里,AgentService 在
// applyProfile 中用它与 Profile.SystemPrompt(pongo2 模板)合成最终系统提示词。
SystemPromptVars map[string]any `json:"system_prompt_vars,omitempty"`
// SystemPrompt 是最终发送给 Provider 的系统提示词。
//
// 注意:它不再由调用方直接设置,而是 AgentService 依据 Profile.SystemPrompt 模板 +
// SystemPromptVars 渲染后写入(见 applyProfile);Provider 只读该字段。
SystemPrompt string `json:"system_prompt,omitempty"`
// Messages 对话上下文(不含 SystemPrompt)。
Messages []Message `json:"messages"`
// WorkingDir 可选:Agent 执行的工作目录。
WorkingDir string `json:"working_dir"`
// Env 可选:额外环境变量(也可携带 Provider 特有开关)。
Env map[string]string `json:"env"`
// MaxTokens 可选:最大输出 token 数,0 表示不限制。
MaxTokens int `json:"max_tokens"`
// Stream 可选:任务模式下是否使用流式调用;默认 false 使用 Invoke。
Stream bool `json:"stream"`
// Timeout 可选:单次调用超时,0 表示不限制。
Timeout time.Duration `json:"-"`
}
Request 描述一次 Agent 调用请求,与具体 Provider 无关。
type Result ¶
type Result struct {
// TaskID 本次调用对应的 Agent 任务 ID(agent_tasks 表),仅任务模式(RunTaskSync)下返回。
TaskID int64 `json:"task_id,string,omitempty"`
Content string `json:"content"`
Usage Usage `json:"usage"`
Raw json.RawMessage `json:"raw,omitempty"` // Provider 原始返回,便于调试与扩展
}
Result 是一次 Invoke / Stream 调用的最终聚合结果。
type Runtime ¶
type Runtime interface {
// Emit 输出一个流式事件。
Emit(ctx context.Context, event StreamEvent) error
// RequestPermission 创建权限请求并阻塞等待决策(allow / deny)。
// userID 用于按用户读取其自定义的许可策略(空表示无用户,走默认策略)。
RequestPermission(ctx context.Context, userID string, operation Operation) (PermissionDecision, error)
// WaitPermission 等待一个已存在权限请求(permissionID)的决策。
WaitPermission(ctx context.Context, permissionID int64) (PermissionDecision, error)
// AskUser 向用户提问并阻塞等待作答(提问卡片由 UI 渲染)。
// userID 用于提问归属;无 UI 的独立调用返回 ErrNoUserInputResolver。
AskUser(ctx context.Context, userID string, input AskUserInput) (AskUserAnswer, error)
}
Runtime 是 Agent 执行期间的运行时环境,由上层(Client 或 AgentService)注入。
Agent 通过它完成三件事:
- Emit:向外输出流式事件(文本 / 推理 / 工具调用 / 权限通知等);
- RequestPermission:创建一个权限请求并阻塞等待用户 / 策略决策;
- WaitPermission:等待一个已存在的权限请求的决策(用于恢复场景)。
该接口把 Agent 与“持久化、通知、权限决策”等业务关注点解耦: Agent 只描述“要做什么”,具体“能不能做”由 Runtime 背后的 PermissionManager / Policy 决定。
func NewStandaloneRuntime ¶
func NewStandaloneRuntime(handler StreamHandler) Runtime
NewStandaloneRuntime 返回一个独立于任务上下文的 Runtime,用于 Client.Invoke / Client.Stream 这类“无任务、无 UI”的一次性调用。
行为约定:
- Emit:直接把事件交给 handler(handler 为 nil 时丢弃);
- RequestPermission:应用默认策略,ask 降级为 allow(宽松放行),保证链路可跑通;
- WaitPermission:无解析器,直接返回 ErrNoPermissionResolver。
func NewTaskRuntime ¶ added in v0.1.4
func NewTaskRuntime(svc *AgentService, taskID int64, handler StreamHandler) Runtime
type ServiceConfig ¶
type ServiceConfig struct {
Client *Client
Tasks TaskRepository
Perms *PermissionManager
Questions *QuestionManager
Events EventRepository
Bus EventBus
Policy PermissionPolicy
Memory *MemoryManager
Project ProjectContextProvider
Profiles *ProfileManager
Skills *skill.Registry
}
ServiceConfig 是 AgentService 的依赖配置。
type StreamEvent ¶
type StreamEvent struct {
Type StreamEventType `json:"type"`
Content string `json:"content,omitempty"` // 仅增量事件使用
Data any `json:"data,omitempty"` // 完整块的结构化数据(reasoning/message/tool_call/turn)
Err error `json:"-"` // 仅当 Type == StreamEventError 时有效
}
StreamEvent 是一次流式输出过程中的单个事件。
type StreamEventType ¶
type StreamEventType string
StreamEventType 枚举流式事件类型。
事件分为两类:
- 增量(delta):text / reasoning_delta,用于前端实时渲染,默认不落库(仅走 WS/SSE 广播);
- 完整块(block):turn_start / turn_end / reasoning / message / tool_call / tool_result, 是时间线的 source of truth,会持久化到 EventRepository。
const ( // —— 增量(delta)—— StreamEventText StreamEventType = "text" // 文本增量 StreamEventReasoningDelta StreamEventType = "reasoning_delta" // 思维链/推理增量 // —— 完整块(block)—— StreamEventTurnStart StreamEventType = "turn_start" // 一轮开始(Data 为 TurnBlock) StreamEventTurnEnd StreamEventType = "turn_end" // 一轮结束(Data 为 TurnBlock) StreamEventReasoning StreamEventType = "reasoning" // 完整思考块(Data 为 ReasoningBlock) StreamEventMessage StreamEventType = "message" // 完整 assistant 消息(Data 为 MessageBlock) StreamEventToolCall StreamEventType = "tool_call" // 完整工具调用(Data 为 ToolCall) StreamEventToolResult StreamEventType = "tool_result" // 工具调用结果 StreamEventPermission StreamEventType = "permission" // 权限请求通知(真正状态见 PermissionRequest) StreamEventPermissionResult StreamEventType = "permission_result" // 权限决策结果通知 StreamEventDone StreamEventType = "done" // 正常结束 StreamEventError StreamEventType = "error" // 出错结束 )
type StreamHandler ¶
type StreamHandler func(ctx context.Context, event StreamEvent) error
StreamHandler 消费流式事件;返回非 nil 错误时中断流式调用。
type Task ¶
type Task struct {
ID int64 `json:"id,string" gorm:"column:id;primaryKey;type:bigint;autoIncrement:false"`
SessionID string `json:"session_id,omitempty" gorm:"column:session_id;type:varchar(64);index"`
Provider string `json:"provider" gorm:"column:provider;type:varchar(64)"`
Model string `json:"model,omitempty" gorm:"column:model;type:varchar(128)"`
Status TaskStatus `json:"status" gorm:"column:status;type:varchar(32);index"`
WorkingDir string `json:"working_dir,omitempty" gorm:"column:working_dir;type:text"`
// Request 保存原始请求,用于恢复时重建上下文。
Request Request `json:"request,omitempty" gorm:"serializer:json"`
// Error 保存最近一次错误信息(Status == failed 时有效)。
Error string `json:"error,omitempty" gorm:"column:error;type:text"`
CreatedAt time.Time `json:"created_at" gorm:"column:created_at"`
UpdatedAt time.Time `json:"updated_at" gorm:"column:updated_at"`
StartedAt *time.Time `json:"started_at,omitempty" gorm:"column:started_at"`
FinishedAt *time.Time `json:"finished_at,omitempty" gorm:"column:finished_at"`
}
Task 是一次 Agent 调用的持久化对象。
它与 PermissionRequest 形成两级状态机:Task 记录“整体执行到哪一步”, PermissionRequest 记录“某个具体操作是否被允许”。后端重启后,可根据 Task.Status 与 pending 的 PermissionRequest 重建运行态(见 Recovery)。
func (*Task) BeforeCreate ¶ added in v0.1.3
BeforeCreate 在写入数据库前用雪花 ID 初始化主键。
func (*Task) TransitionTo ¶
func (t *Task) TransitionTo(next TaskStatus) bool
TransitionTo 校验并执行任务状态迁移;非法迁移返回 false 且不改变状态。
type TaskRepository ¶
type TaskRepository interface {
Create(ctx context.Context, task *Task) error
Get(ctx context.Context, id int64) (*Task, error)
Update(ctx context.Context, task *Task) error
ListByStatus(ctx context.Context, statuses ...TaskStatus) ([]*Task, error)
// Page 分页查询任务(按 CreatedAt 升序);statuses 为空表示全部状态。
Page(ctx context.Context, offset, limit int, statuses ...TaskStatus) ([]*Task, int64, error)
}
TaskRepository 持久化 Agent 任务。
type TaskStatus ¶
type TaskStatus string
TaskStatus 是 Agent 任务的生命周期状态。
状态机(详见 design.md 第 7 节):
created → running → completed
↘ failed / canceled
running → waiting_permission → running
const ( TaskCreated TaskStatus = "created" // 已创建,尚未开始 TaskRunning TaskStatus = "running" // 正在执行 TaskWaitingPermission TaskStatus = "waiting_permission" // 等待权限确认 TaskCompleted TaskStatus = "completed" // 已完成 TaskFailed TaskStatus = "failed" // 失败 TaskCanceled TaskStatus = "canceled" // 已取消 )
type ToolCall ¶
type ToolCall struct {
ID string `json:"id"` // toolCallId
Name string `json:"name"` // 工具名
Arguments any `json:"arguments,omitempty"`
}
ToolCall 是一次完整的工具调用(对应 AssistantMessageToolRequest)。
type ToolCallProvider ¶
ToolCallProvider 由 Provider 提供:根据上一轮结果决定下一批待执行的工具调用。 返回空切片表示不再有工具调用,循环结束。
type ToolLoop ¶
type ToolLoop struct {
// contains filtered or unexported fields
}
ToolLoop 驱动标准的 tool-call 循环:执行 → 回传结果 → 再执行,直至无更多工具调用。
Provider 侧通常这样配合:
resp := model(messages, tools)
for resp.hasToolCalls() {
results := loop.Run(ctx, func(ctx, last) ([]agent.ToolCall, error) {
messages = appendToolResults(messages, last) // 把结果回填
resp = model(messages, tools)
return resp.toolCalls(), nil
})
}
type ToolPermissionResolver ¶
ToolPermissionResolver 把一次工具调用映射为需要授权的 Operation。
返回 (op, true) 表示该工具需要权限确认(执行前阻塞等待决策); 返回 (op, false) 表示直接放行。
type ToolResultEvent ¶
type ToolResultEvent struct {
CallID string `json:"call_id"`
Name string `json:"name"`
Content string `json:"content"`
IsError bool `json:"is_error"`
}
ToolResultEvent 是 tool_result 事件的结构化载荷。
type ToolRunner ¶
type ToolRunner struct {
// contains filtered or unexported fields
}
ToolRunner 把 tool.Executor 与 Runtime 桥接:执行工具调用并输出事件, 同时承载可选的权限门禁(把工具调用映射为 Operation,执行前请求授权)。
func NewToolRunner ¶
func NewToolRunner(exec *tool.Executor, rt Runtime) *ToolRunner
NewToolRunner 创建工具执行器;exec 为 nil 时使用空注册表的执行器。
func (*ToolRunner) Run ¶
Run 执行一次工具调用:
- 输出 tool_call 事件(完整块,落库);
- 若配置了权限映射,执行前通过 Runtime.RequestPermission 阻塞等待决策;
- 执行工具;
- 输出 tool_result 事件并返回结果。
func (*ToolRunner) SetPermissionResolver ¶
func (r *ToolRunner) SetPermissionResolver(resolver ToolPermissionResolver) *ToolRunner
SetPermissionResolver 设置权限映射(可选),返回自身便于链式调用。
func (*ToolRunner) SetUserID ¶ added in v0.1.4
func (r *ToolRunner) SetUserID(userID string) *ToolRunner
SetUserID 设置权限决策所使用的用户标识(用于按用户读取许可策略)。
type TurnInput ¶
type TurnInput struct {
UserID string
ConversationID int64 // 为 0 则创建新会话
Message string // 本轮用户输入
Provider string
Model string
// SystemPromptVars 是渲染 Profile 系统提示词模板所用的变量(业务上下文),
// 由 HTTP 层解析 env(type,id) 得到;系统提示词本身由 AgentService 渲染。
SystemPromptVars map[string]any
ProfileID int64 // AgentProfile ID(为 0 取默认)
WorkingDir string
}
TurnInput 是一次「轮次」的输入,由 HTTP 层构造。
type Usage ¶
type Usage struct {
InputTokens int64 `json:"input_tokens"`
OutputTokens int64 `json:"output_tokens"`
}
Usage 统计 token 用量。
type UserAgentConfig ¶ added in v0.1.4
type UserAgentConfig struct {
ProfileID int64 `json:"profile_id,omitempty,string"`
Permissions map[OperationType]PermissionDecision `json:"permissions,omitempty"`
}
UserAgentConfig 是存储在用户记录中的 Agent 配置快照(以 JSON 形式落库)。
它把「用户选择的 Profile」与「用户自定义的权限策略」合并为一处:
- ProfileID:该用户选中的 AgentProfile ID(0 表示未选择,解析时走默认);
- Permissions:按 OperationType 配置的决策。空 / 未命中某项时,该项回退到 defaultPermissionPolicy 的默认决策。
func DefaultUserAgentConfig ¶ added in v0.1.4
func DefaultUserAgentConfig() UserAgentConfig
DefaultUserAgentConfig 返回默认用户配置(选中内置默认 Profile、权限全部走默认策略)。
type UserAgentConfigProvider ¶ added in v0.1.4
type UserAgentConfigProvider interface {
GetAgentConfig(ctx context.Context, userID string) (UserAgentConfig, error)
}
UserAgentConfigProvider 按 userID 读取用户的 Agent 配置(用于权限决策)。
Source Files
¶
Directories
¶
| Path | Synopsis |
|---|---|
|
Package providers 提供 agent.Provider 的内置实现。
|
Package providers 提供 agent.Provider 的内置实现。 |
|
Package repository 提供 agent 域各持久化端口的基于数据库(GORM)的实现。
|
Package repository 提供 agent 域各持久化端口的基于数据库(GORM)的实现。 |
|
Package skill 实现 Agent Skills 开放标准(https://agentskills.io)。
|
Package skill 实现 Agent Skills 开放标准(https://agentskills.io)。 |
|
Package tool 定义 Agent 工具调用(function calling)的基础设施。
|
Package tool 定义 Agent 工具调用(function calling)的基础设施。 |
|
builtin
Package builtin 提供框架内置的工具(如 get_weather)。
|
Package builtin 提供框架内置的工具(如 get_weather)。 |