service

package
v0.2.4 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Nov 12, 2026 License: MIT Imports: 21 Imported by: 0

Documentation

Index

Constants

View Source
const (
	// DefaultSessionMessageLimit 是会话详情默认返回的消息条数。
	DefaultSessionMessageLimit = 20
	// MaxSessionMessageLimit 是单次可请求的最大消息条数(防止前端一次拉全量)。
	MaxSessionMessageLimit = 200
)

会话详情分页参数默认值与上限。

Variables

This section is empty.

Functions

func AllowAllPermissionPolicy

func AllowAllPermissionPolicy() PermissionPolicy

AllowAllPermissionPolicy 返回一个“全部放行”的策略实例。

func BuiltinProfiles

func BuiltinProfiles() []*Profile

BuiltinProfiles 返回框架内置 Profile 的种子数据。新增内置 Profile 时在此追加。

func DefaultPermissionPolicy

func DefaultPermissionPolicy() PermissionPolicy

DefaultPermissionPolicy 返回框架内置的默认策略实例。

func EnsureBuiltinProfiles

func EnsureBuiltinProfiles(ctx context.Context, repo ProfileRepository) error

EnsureBuiltinProfiles 把内置 Profile 同步到仓库(数据库初始化工具)。

func MessageBlockContent

func MessageBlockContent(data any) (string, bool)

MessageBlockContent 从 StreamEventMessage 的 Data 中提取完整 assistant 文本。

投影与轮末兜底共用它,保证「什么算一条 assistant 文本」只有一个口径。

func NewEventBus

func NewEventBus() EventBus

NewEventBus 创建一个内存事件总线。

func NewHistoryService

func NewHistoryService(store HistoryStore) HistoryService

NewHistoryService 基于 Store 构建文件历史服务。

func NewMessageService

func NewMessageService(store MessageStore) MessageService

NewMessageService 创建消息服务。

func NewSessionService

func NewSessionService(store SessionStore) SessionService

NewSessionService 创建会话服务。

func NewTaskRuntime

func NewTaskRuntime(svc *AgentService, task *Task, opts ...RuntimeOption) Runtime

func NewUserPermissionPolicy

func NewUserPermissionPolicy(provider UserAgentConfigProvider) PermissionPolicy

NewUserPermissionPolicy 创建用户感知的权限策略。

func ProjectTimelineEvent

func ProjectTimelineEvent(sessionID, taskID int64, event StreamEvent) (MessageCreateParams, bool)

ProjectTimelineEvent 把一条流式完整块事件投影为可持久化的会话消息。

sessionID / taskID 写入消息归属;taskID 为 0 表示不属于 agent_tasks(如子 Agent 会话)。 返回 ok=false 表示该事件不应落库。

func ReadBuiltinPrompt

func ReadBuiltinPrompt(name string) (string, error)

ReadBuiltinPrompt 按提示词名读取内置提示词文件。

func ReasoningBlockContent

func ReasoningBlockContent(data any) (string, bool)

ReasoningBlockContent 从 reasoning 事件体中提取完整思考文本。

func SetBuiltinPromptDir

func SetBuiltinPromptDir(dir string)

SetBuiltinPromptDir 覆盖内置提示词目录(空串表示恢复默认:相对当前工作目录)。

func TimelineEventSummary

func TimelineEventSummary(prefix string, data any) string

TimelineEventSummary 把事件体序列化为消息正文(序列化失败时退化为 "<prefix> event")。

Types

type AgentService

type AgentService struct {
	// contains filtered or unexported fields
}

AgentService 是 Agent 执行架构的编排层(即 design.md 中的 AgentTaskManager)。

它把 Client(Provider 门面)、TaskRepository、PermissionManager、 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

func (s *AgentService) AnswerQuestion(ctx context.Context, id int64, answer AskUserAnswer, by int64) error

AnswerQuestion 提交用户对一次提问的作答(供 UI / HTTP 层调用)。

func (*AgentService) ApprovePermission

func (s *AgentService) ApprovePermission(ctx context.Context, id int64, by int64) error

ApprovePermission 批准权限请求(供 UI / HTTP 层调用)。

两种情形:

  • 任务仍在本进程执行(存在 waiter):Approve 会唤醒 Wait,无需额外动作;
  • 任务因进程重启而失去 goroutine:批准后立即从持久化检查点真正续跑(ResumeTask)。

func (*AgentService) CancelTask

func (s *AgentService) CancelTask(ctx context.Context, taskID int64) error

CancelTask 取消任务:取消执行上下文并置为 canceled。

func (*AgentService) CreateTask

func (s *AgentService) CreateTask(ctx context.Context, req Request, facts TaskFacts) (*Task, error)

CreateTask 创建任务(不启动执行)。

facts 是任务的生命周期属性(用户 / 会话 / 项目),由调用方显式提供, 不再从 Request 或 RuntimeContext 推导。

供 HTTP 层使用:先拿到 taskID 订阅事件,再调用 StartTask 启动,避免错过 task.created 等早期事件。

func (*AgentService) DeleteMemory

func (s *AgentService) DeleteMemory(ctx context.Context, id int64) error

DeleteMemory 删除记忆,并广播记忆事件。

func (*AgentService) DeleteProfile

func (s *AgentService) DeleteProfile(ctx context.Context, id int64) error

DeleteProfile 删除自定义 Profile(内置 Profile 不可删除)。

func (*AgentService) DenyPermission

func (s *AgentService) DenyPermission(ctx context.Context, id int64, by int64) error

DenyPermission 拒绝权限请求(供 UI / HTTP 层调用)。

若任务已无活跃 goroutine(后端重启),拒绝后直接把等待中的任务置为 failed, 保证会话轮次能正常收尾(onTaskFinished),而不是永远停在 waiting_permission。

func (*AgentService) GetMemory

func (s *AgentService) GetMemory(ctx context.Context, id int64) (*Memory, error)

GetMemory 按 ID 查询单条记忆。

func (*AgentService) GetPendingPermissions

func (s *AgentService) GetPendingPermissions(ctx context.Context, taskID int64) ([]*PermissionRequest, error)

GetPendingPermissions 查询任务当前待确认的权限请求。

func (*AgentService) GetPendingQuestions

func (s *AgentService) GetPendingQuestions(ctx context.Context, taskID int64) ([]*QuestionRequest, error)

GetPendingQuestions 查询任务当前待作答的提问请求。

func (*AgentService) GetProfile

func (s *AgentService) GetProfile(ctx context.Context, id int64) (*Profile, error)

GetProfile 按 ID 返回 Profile(全局可见)。

func (*AgentService) GetSystemPromptByProfileWithContext

func (s *AgentService) GetSystemPromptByProfileWithContext(ctx context.Context, profile *Profile, rc *runtimecontext.RuntimeContext, facts TaskFacts, selectedSkills []string) string

GetSystemPromptByProfileWithContext 按 Profile 渲染系统提示词,并带上本次调用的 运行时上下文(模板变量)与执行事实(用户 / 项目 / 会话),使记忆注入优先命中 所属上下文。rc / facts 均可为零值。

func (*AgentService) GetSystemSpromptByProfile

func (s *AgentService) GetSystemSpromptByProfile(ctx context.Context, profile *Profile, vars map[string]any, selectedSkills []string) string

applyProfile 依据 Profile 生成本轮最终的 SystemPrompt。

入参:

  • profile:已解析的 Agent Profile(为 nil 时返回空提示词,表示不附加系统提示词);
  • vars:渲染 Profile.SystemPrompt(pongo2 模板)所用的变量,通常为 RuntimeContext.SystemPromptVars;
  • userID:记忆的归属用户(为空时不注入背景);
  • selectedSkills:本轮启用的技能名(为空表示全部);据此把技能元信息(name / description)注入提示词,正文由模型调用 get_skill 工具按需加载。

处理顺序:渲染 Profile 模板 → 注入技能指令 → 按 Profile.Context 开关注入记忆。 模板渲染失败时退回原始模板,保证调用仍可进行。 GetSystemSpromptByProfile 按 Profile 渲染系统提示词,并按需注入技能说明与记忆背景。

vars 是模板变量(来自 RuntimeContext.SystemPromptVars);记忆注入的用户 / 上下文维度 需要 TaskFacts,因此没有业务场景的调用请使用 GetSystemPromptByProfileWithContext(或 RenderSystemPrompt)。

func (*AgentService) GetTask

func (s *AgentService) GetTask(ctx context.Context, id int64) (*Task, error)

GetTask 查询任务。

func (*AgentService) GetTaskRequest

func (s *AgentService) GetTaskRequest(ctx context.Context, taskID int64) (*Request, error)

GetTaskRequest 按任务 ID 加载任务,返回任务持久化的 Request 内容。

供 UI 调试 / 审计使用。注意:这里返回的是任务创建时的原始请求,未应用 Agent Profile; 真正发送给 Provider 的系统提示词在任务执行时由 run 经 applyProfile 渲染 (Profile 模板 + RuntimeContext.SystemPromptVars + 背景注入)。

func (*AgentService) ListMemory

func (s *AgentService) ListMemory(ctx context.Context, userID int64, offset, limit int, kinds ...MemoryKind) ([]*Memory, int64, error)

ListMemory 分页查询某用户的记忆;kinds 为空表示全部类别。

func (*AgentService) ListProfiles

func (s *AgentService) ListProfiles(ctx context.Context) ([]*Profile, error)

ListProfiles 返回全部 Profile(内置 + 自定义,全局可见)。

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

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) Recover

func (s *AgentService) Recover(ctx context.Context) error

Recover 在后端重启后重建运行态(见 design.md 第 6 / 19 节)。

行为:

  • running 且无活跃 goroutine:执行循环已随进程消失,置为 failed(保留检查点, 用户可通过 ResumeTask 手动续跑;错误信息标注 resumable);
  • waiting_permission 且无活跃 goroutine:保留状态与 pending 权限,等待用户操作; 批准后 ApprovePermission 会自动 ResumeTask,拒绝则直接置为 failed。

注意:running → failed 会触发 onTaskFinished。ChatService 的收尾逻辑不依赖 内存 turns 表(重启后为空),而是用 Task.SessionID 从数据库恢复收尾,因此 会话的 CurrentTaskID / 错误消息仍能被正确清理。

func (*AgentService) RenderSystemPrompt

func (s *AgentService) RenderSystemPrompt(ctx context.Context, userID int64, profileID int64, vars map[string]any) (*Profile, string, error)

RenderSystemPrompt 按 Profile ID 解析 Profile,并用 vars 渲染其系统提示词模板, 返回真正的系统提示词(供 DescribeEnv 等前端展示 / 调试场景使用)。

vars 是模板变量(通常为 RuntimeContext.SystemPromptVars),必须透传给 buildSystemPrompt,否则模板里的 {{...}} 变量会渲染成空值。

Profile 不存在时返回 nil Profile、空串与 nil 错误。

func (*AgentService) ResolveProfile

func (s *AgentService) ResolveProfile(ctx context.Context, id int64) (*Profile, error)

ResolveProfile 按 ID 解析 Profile,与 run 内应用 Profile 的解析路径保持一致 (id 为 0 时回退到内置默认 Profile)。

func (*AgentService) ResumeTask

func (s *AgentService) ResumeTask(ctx context.Context, taskID int64) error

ResumeTask 从持久化检查点续跑任务(供 UI 手动触发,或权限 / 提问决策后自动触发)。

前置条件:

  • 任务存在检查点(Provider 在执行期写入);
  • 任务无活跃 goroutine(否则返回 ErrTaskAlreadyRunning);
  • 任务不是 completed / canceled(终态不可续跑)。

执行链:MarkResumed → 持久化 running → 启动 goroutine → Provider 读取检查点, 重放未完成的工具调用(已批准的权限会被 consume 后直接放行),随后继续 Agent 循环。

func (*AgentService) RetrieveMemory

func (s *AgentService) RetrieveMemory(ctx context.Context, userID int64, query string, limit int) ([]*Memory, error)

RetrieveMemory 检索与 query 相关的记忆。

func (*AgentService) RunTask

func (s *AgentService) RunTask(ctx context.Context, req Request, facts TaskFacts) (*Task, error)

RunTask 创建任务并异步执行。

执行与调用方 ctx 解耦:任务在独立 goroutine 中运行,可跨多次 HTTP 请求存活, 通过权限确认 / 取消 / 恢复驱动其生命周期。返回的任务对象用于前端轮询 / 订阅。

事件消费只有两条通路:实时推送走 EventBus(Subscribe),历史落库走 TimelineRecorder(agent_messages);不再接受同步 handler。

func (*AgentService) RunTaskSync

func (s *AgentService) RunTaskSync(ctx context.Context, req Request, facts TaskFacts, opts ...RuntimeOption) (*Result, error)

RunTaskSync 同步执行一次性任务:创建 → 运行 → 返回聚合结果。

供需要一次性拿到结果的业务(如 AISummaryWorker)使用,替代直接调用 agent.Client.Invoke。 与 RunTask / StartTask 不同,它不启动 goroutine,直接在调用方同步执行。

同步执行没有 UI 承接权限确认,因此默认无人值守:权限 ask 直接放行(见 RunTaskSyncByID)。 如需保留原有的人工确认语义,可传 WithAutoApprove(false)。

若调用方需要在任务创建后、执行前拿到 taskID(例如把摘要记录立即关联到任务), 请改用 CreateTask + RunTaskSyncByID 的两步形式。

func (*AgentService) RunTaskSyncByID

func (s *AgentService) RunTaskSyncByID(ctx context.Context, taskID int64, opts ...RuntimeOption) (*Result, error)

RunTaskSyncByID 同步执行已创建的任务,返回聚合结果。

与 RunTaskSync 的区别在于任务创建被前置:调用方可以先 CreateTask 拿到 taskID 并完成 关联(例如 AISummaryWorker 在生成前把摘要与任务绑定),再调用本方法执行。

权限:同步执行没有 UI 承接权限确认,默认以「无人值守」方式执行——策略判定为 ask 的操作 直接放行,不会持久化 pending 权限请求、也不会把任务置为 waiting_permission 阻塞等待; 策略明确 deny 的操作仍会被拒绝。调用方可用 opts 覆盖(如 WithAutoApprove(false) 恢复人工确认)。

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) SetTaskFinishedHandler

func (s *AgentService) SetTaskFinishedHandler(h TaskFinishedHandler)

SetTaskFinishedHandler 注册任务终态回调(completed / failed / canceled)。

典型用法:ChatService 在构造时把自己的「轮次收尾」挂到这里,使会话锁释放、 最终回答落库不再依赖 Provider 是否补发 done / error 流事件。 回调在任务终态写库后、终态事件广播前同步执行;重复注册会覆盖前一个。

func (*AgentService) StartTask

func (s *AgentService) StartTask(ctx context.Context, taskID int64) error

StartTask 启动已创建任务的异步执行。

func (*AgentService) Subscribe

func (s *AgentService) Subscribe(taskID int64, handler EventHandler) func()

Subscribe 订阅任务事件(taskID 为 0 表示订阅全部任务),返回取消订阅函数。 供 WS / SSE 实时推送层使用;刷新后的历史请从 agent_messages 读取 (事件流仅用于实时广播,不再持久化)。

type ChatService

type ChatService struct {
	// contains filtered or unexported fields
}

ChatService 编排多轮对话:负责历史拼接 + 复用 AgentService 执行每一轮。

func NewChatService

func NewChatService(agent *AgentService, sessions SessionService, messages MessageService, projects coreinterfaces.ProjectService) *ChatService

NewChatService 创建 ChatService。

构造时把自己的轮次收尾挂到 AgentService 的任务终态回调上:即使 Provider 没有 补发 done / error 事件,任务进入终态也会释放会话锁、写入兜底消息。

func (*ChatService) CreateTurn

func (s *ChatService) CreateTurn(ctx context.Context, in TurnInput) (*Task, Session, error)

CreateTurn 准备一轮执行(不启动):

  1. 取得会话级锁(保证同一会话轮次串行);
  2. 加载 / 创建会话,追加 user 消息并持久化;
  3. 读取完整历史组装 Request(SessionID = 会话 ID),交给 AgentService.CreateTask;
  4. 登记本轮中间态,返回 task 供上层(handler)在启动前订阅 WS。

锁在本轮结束时由 finishTurn 释放。

func (*ChatService) GetSession

GetSession 查询会话及一页历史消息(默认最新一页,按 Seq 升序)。

历史消息可能非常大(长回复 / 工具输出),因此不再一次返回全部: 首次只取最新一页,用户向上滚动时把上一页返回的 NextCursor 作为 BeforeSeq 继续加载。

func (*ChatService) GetTaskTimeline

func (s *ChatService) GetTaskTimeline(ctx context.Context, taskID, userID int64) ([]Message, error)

GetTaskTimeline 按任务 ID 返回该任务的执行时间线(已落库的事实流)。

校验任务归属:只有任务所属用户才能读取自己的时间线,避免越权。

func (*ChatService) ListMessages

func (s *ChatService) ListMessages(ctx context.Context, sessionID int64) ([]Message, error)

ListMessages 查询某个会话的全部历史消息(按 Seq 升序)。

func (*ChatService) ListSessions

func (s *ChatService) ListSessions(ctx context.Context, userID int64, offset, limit int) ([]Session, int64, error)

ListSessions 分页查询会话。

会话按用户当前激活项目隔离:先用 GetActiveProjectByUserID 取出活动项目, 再按 ProjectID 过滤;userID 为 0 表示全部用户(不做项目过滤)。

func (*ChatService) ListTaskMessages

func (s *ChatService) ListTaskMessages(ctx context.Context, sessionID, taskID int64) ([]Message, error)

ListTaskMessages 查询某个会话中属于指定任务的消息(按 Seq 升序)。

用于「一轮执行的事实流回填」:刷新 / 切换会话后,前端用该任务的已落库时间线 (reasoning / assistant / tool_call / tool_result / error)还原执行过程, 弥补增量事件(text / reasoning_delta)只广播不落库导致的空白。

状态源是 agent_messages;同一会话里其它轮次的消息不会返回。

func (*ChatService) StartTurn

func (s *ChatService) StartTurn(ctx context.Context, taskID int64) error

StartTurn 启动本轮执行。

不再注册流式回调:时间线(reasoning / message / tool_call / tool_result)由 AgentService 的 TimelineRecorder 在轮内即时落库,轮次收尾由任务终态回调驱动。

type MemoryConfig

type MemoryConfig struct {
	Repo      MemoryRepository
	Extractor MemoryExtractor
}

MemoryConfig 是 MemoryManager 的依赖配置。

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 int64) error

Delete 删除记忆。

func (*MemoryManager) Extract

func (m *MemoryManager) Extract(ctx context.Context, turn MemoryTurn) ([]*Memory, error)

Extract 调用已配置的提取器,从一轮执行中提取待写入的记忆。 未配置提取器时返回空(不提取)。

func (*MemoryManager) Get

func (m *MemoryManager) Get(ctx context.Context, id int64) (*Memory, error)

Get 按 ID 查询记忆。

func (*MemoryManager) List

func (m *MemoryManager) List(ctx context.Context, userID int64, offset, limit int, kinds ...MemoryKind) ([]*Memory, int64, error)

List 分页查询某用户的记忆;kinds 为空表示全部类别。

func (*MemoryManager) Retrieve

func (m *MemoryManager) Retrieve(ctx context.Context, q MemoryQuery) ([]*Memory, error)

Retrieve 按「业务上下文 + 关键词」检索记忆,并刷新这些记忆的访问时间(Touch)。

func (*MemoryManager) Save

func (m *MemoryManager) Save(ctx context.Context, memory *Memory) error

Save 创建或更新一条记忆:ID 为 0(新建)时交给 Repository 创建,主键在写入前由 BeforeCreate 分配;否则更新。

func (*MemoryManager) Touch

func (m *MemoryManager) Touch(ctx context.Context, id int64) error

Touch 更新记忆的最近访问时间(用于淘汰 / 排序策略)。

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 int64) (*PermissionRequest, error)

Approve 批准权限请求,返回更新后的权限请求;并唤醒正在等待的 Agent。

func (*PermissionManager) Consume

func (m *PermissionManager) Consume(ctx context.Context, id int64) error

Consume 把已批准的权限请求标记为 consumed(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 int64) (*PermissionRequest, error)

Deny 拒绝权限请求,返回更新后的权限请求;并唤醒正在等待的 Agent。

func (*PermissionManager) FindByToolCall

func (m *PermissionManager) FindByToolCall(ctx context.Context, taskID int64, toolCallID string) (*PermissionRequest, error)

FindByToolCall 返回某任务下由指定工具调用发起的权限请求(最新一条)。

恢复执行时,Agent 会重新执行未完成的工具调用;该方法让 Runtime 复用重启前 已经落库的权限决策(approved / denied),而不是再弹一次权限确认。 匹配依据是 Operation.Metadata["tool_call_id"](创建权限时由 Runtime 自动写入)。

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 ProfileManager

type ProfileManager struct {
	// contains filtered or unexported fields
}

ProfileManager 负责 Profile 的解析、列表与增删改查编排。

func NewProfileManager

func NewProfileManager(repo ProfileRepository) *ProfileManager

NewProfileManager 创建 Profile 管理器。

func (*ProfileManager) Delete

func (m *ProfileManager) Delete(ctx context.Context, id int64) error

Delete 删除自定义 Profile;内置 Profile 不可删除。

func (*ProfileManager) Get

func (m *ProfileManager) Get(ctx context.Context, id int64) (*Profile, error)

Get 按 ID 返回 Profile(全局可见)。

func (*ProfileManager) List

func (m *ProfileManager) List(ctx context.Context) ([]*Profile, error)

List 返回全部 Profile(内置 + 自定义,按名称升序)。

func (*ProfileManager) Resolve

func (m *ProfileManager) Resolve(ctx context.Context, id int64) (*Profile, error)

Resolve 按 ID 解析 Profile(id 为 0 时回退到内置默认 Profile)。

func (*ProfileManager) Save

func (m *ProfileManager) Save(ctx context.Context, p *Profile) error

Save 创建或更新 Profile;IsDefault 为 true 时清除其他 Profile 的默认标记。

type QuestionManager

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

func NewQuestionManager(repo QuestionRepository) *QuestionManager

NewQuestionManager 创建提问管理器。

func (*QuestionManager) Answer

func (m *QuestionManager) Answer(ctx context.Context, id int64, answer AskUserAnswer, by int64) (*QuestionRequest, error)

Answer 提交用户作答,返回更新后的提问请求。

支持「一题一页」的逐题作答:本次作答会合并进 q.Answer 作为暂存进度并持久化, 提问保持 pending;直到所有必答问题都有答案,才迁移到 answered 并唤醒 Agent。 因此用户可以在未全部答完时翻页、回看并修改之前的答案,界面刷新后进度也不丢失。

提交的问题 ID 必须属于本次提问(防止误把答案提交到别的提问)。

func (*QuestionManager) Cancel

func (m *QuestionManager) Cancel(ctx context.Context, id int64) (*QuestionRequest, error)

Cancel 取消一个待作答的提问(任务被取消等);被取消的等待返回 ErrQuestionCanceled。

func (*QuestionManager) Create

func (m *QuestionManager) Create(ctx context.Context, taskID int64, sessionID string, input AskUserInput) (*QuestionRequest, error)

Create 创建一个 pending 状态的提问请求并返回。

func (*QuestionManager) CreateForToolCall

func (m *QuestionManager) CreateForToolCall(ctx context.Context, taskID int64, sessionID string, input AskUserInput, toolCallID string) (*QuestionRequest, error)

CreateForToolCall 创建提问请求,并记录发起它的工具调用 ID。

func (*QuestionManager) FindByToolCall

func (m *QuestionManager) FindByToolCall(ctx context.Context, taskID int64, toolCallID string) (*QuestionRequest, error)

FindByToolCall 返回某任务下由指定工具调用发起的提问(最新一条)。

恢复执行时用于复用重启前的提问进度 / 已作答结果,避免重复弹出提问。

func (*QuestionManager) Get

func (m *QuestionManager) Get(ctx context.Context, id int64) (*QuestionRequest, error)

Get 按 ID 查询提问请求。

func (*QuestionManager) GetPending

func (m *QuestionManager) GetPending(ctx context.Context, taskID int64) ([]*QuestionRequest, error)

GetPending 返回某任务当前全部待作答的提问请求。

func (*QuestionManager) Page

func (m *QuestionManager) Page(ctx context.Context, offset, limit int, taskID int64, statuses ...QuestionStatus) ([]*QuestionRequest, int64, error)

Page 分页查询提问请求;taskID 为 0 表示全部任务,statuses 为空表示全部状态。

func (*QuestionManager) Wait

func (m *QuestionManager) Wait(ctx context.Context, id int64) (AskUserAnswer, error)

Wait 阻塞等待提问的作答。

返回:

  • AskUserAnswer:用户已作答(快路径可直接从 Repository 读取);
  • error:ctx 取消 / 提问被取消等。

type RuntimeOption

type RuntimeOption func(*taskRuntime)

RuntimeOption 定制 TaskRuntime 的行为(如权限是否自动放行)。

func WithAutoApprove

func WithAutoApprove(auto bool) RuntimeOption

WithAutoApprove 开关「无人值守权限放行」。

开启后:策略判定为 ask(需人工确认)的操作直接按 allow 放行,既不持久化 pending 权限请求,也不把任务置为 waiting_permission;策略明确判定为 deny 的操作仍然拒绝。 关闭(默认)时完全保留原有行为:ask → 持久化 pending → 阻塞等待 UI 决策。

适用场景:没有 UI 承接权限确认的同步调用(RunTaskSync / RunTaskSyncByID)。

type ServiceConfig

type ServiceConfig struct {
	Client    *agentclient.Client
	Tasks     TaskRepository
	Perms     *PermissionManager
	Questions *QuestionManager
	// Messages 是时间线消息(agent_messages)的持久化服务。
	Messages MessageService
	Bus      EventBus
	Policy   PermissionPolicy
	Memory   *MemoryManager
	Profiles *ProfileManager
	Skills   *skill.Registry
}

ServiceConfig 是 AgentService 的依赖配置。

type SessionDetail

type SessionDetail struct {
	Session
	Messages []Message `json:"messages"`
	// HasMore 表示是否还有更早的消息(前端向上滚动时继续加载)。
	HasMore bool `json:"has_more"`
	// NextCursor 是继续向上翻页的游标(本页最小 Seq);HasMore 为 false 时无意义。
	NextCursor int `json:"next_cursor"`
}

SessionDetail 是会话详情:会话本体 + 一页历史消息 + 向上翻页游标。

type SessionMessageQuery

type SessionMessageQuery struct {
	// BeforeSeq 是向上翻页游标:只返回 Seq 小于该值的消息;0 表示取最新一页。
	BeforeSeq int
	// Limit 是本页最大条数;<=0 使用 DefaultSessionMessageLimit。
	Limit int
}

SessionMessageQuery 是会话消息的分页参数。

type TimelineRecorder

type TimelineRecorder struct {
	// contains filtered or unexported fields
}

TimelineRecorder 把流式完整块事件即时投影并写入 agent_messages。

它是「事件 → 会话消息」的唯一写入入口,取代原先「轮末从 AgentEvent 回放事件」的做法:

  • 轮内即时落库:Agent 循环中途退出(进程重启 / panic / 长时间等待权限)时, 已经产生的时间线不会丢,为后续恢复留下事实;
  • 投影规则复用 ProjectTimelineEvent,与子 Agent 会话保持同一口径;
  • 只有 EventStream 里可投影的完整块(reasoning / message / tool_call / tool_result)产生消息; 增量(text / reasoning_delta)与生命周期信号(turn_start / done / error ...)不落库;
  • Message.Data 保留事件原始结构,后续可从消息表重建结构化工具调用;
  • RecordResult 是「结果兜底」:Provider 没发完整 message 块时,用最终结果补一条 assistant_final,保证刷新 / 恢复后回答不会丢。

不属于本组件职责的两类消息(它们不是事件流的产物,由 ChatService 直接写入):

  • user 消息:CreateTurn 在启动任务前写入;
  • assistant 最终回答 / error:finishTurn 在轮末写入。

nil receiver 安全:未注入 MessageService 时所有方法都是空操作。

func NewTimelineRecorder

func NewTimelineRecorder(messages MessageService) *TimelineRecorder

NewTimelineRecorder 创建时间线记录器;messages 为 nil 时返回 nil(等价于关闭落库)。

func (*TimelineRecorder) Forget

func (r *TimelineRecorder) Forget(taskID int64)

Forget 在任务进入终态后清理 assistant 记录,避免长期运行下无限增长。

func (*TimelineRecorder) Record

func (r *TimelineRecorder) Record(ctx context.Context, sessionID, taskID int64, payload any)

Record 把一条事件 payload 投影为会话消息并落库;不可投影时静默跳过。

这是 Emit 的热点路径:只处理完整块事件,增量事件在 publish 侧就不会进来; 落库失败只记 Warn,绝不影响 Agent 主流程。

func (*TimelineRecorder) RecordResult

func (r *TimelineRecorder) RecordResult(ctx context.Context, sessionID, taskID int64, content string)

RecordResult 是「Provider 没有发出完整 message 块」时的兜底:用最终结果补一条 assistant_final,保证刷新 / 恢复后回答不会丢。

已经有 KindAssistant 块(Record 落过)时直接跳过,避免历史里出现两份相同文本。 必须在任务进入终态(Forget 清理缓存)之前调用。

type TurnInput

type TurnInput struct {
	UserID    int64
	SessionID int64 // 为 0 则创建新会话
	// ProjectID 是新建会话所属项目(通常取当前用户激活项目),0 时由 ChatService 解析。
	ProjectID int64
	Message   string // 本轮用户输入
	Provider  string
	Model     string
	// RuntimeContext 是本轮调用的运行时上下文(业务类型 / 变量 / 工作目录)。
	RuntimeContext *runtimecontext.RuntimeContext
	ProfileID      int64 // AgentProfile ID(为 0 取默认)
	WorkingDir     string
}

TurnInput 是一次「轮次」的输入,由 HTTP 层构造。

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL