You've already forked agentic-coding-workflow
bugfix
This commit is contained in:
@@ -118,6 +118,12 @@ type AgentKind struct {
|
||||
CreatedBy uuid.UUID
|
||||
CreatedAt time.Time
|
||||
UpdatedAt time.Time
|
||||
// 成本核算:关联的 llm_models 行(价格来源)+ 每 kind 默认预算上限。
|
||||
// 全部 NULLABLE:未配置 model 时成本按 0/agent 自报;未配置上限时无限制。
|
||||
ModelID *uuid.UUID
|
||||
MaxCostUSD *float64
|
||||
MaxTokens *int64
|
||||
MaxWallClockSeconds *int32
|
||||
}
|
||||
|
||||
// ConfigFile 是 AgentKind 维度的 agent CLI 配置文件(如 .claude/settings.json、
|
||||
@@ -153,6 +159,191 @@ type Session struct {
|
||||
LastError *string
|
||||
StartedAt time.Time
|
||||
EndedAt *time.Time
|
||||
// LastStopReason 是 agent 最近一次回合完成时上报的 stopReason 原始字符串
|
||||
// (nil = 尚无完成的回合)。归一化枚举见 NormalizeStopReason,但落库为原值。
|
||||
LastStopReason *string
|
||||
// OrchestratorStepID 非 nil 时表示该 session 由编排器某个 step 驱动;onExit /
|
||||
// 启动 reaper 据此把崩溃 session 映射回 step 并触发再驱动。manual session 为 nil。
|
||||
OrchestratorStepID *uuid.UUID
|
||||
// 成本核算运行时累加器(落库快照)。
|
||||
PromptTokens int64
|
||||
CompletionTokens int64
|
||||
ThinkingTokens int64
|
||||
TotalCostUSD float64
|
||||
LastActivityAt time.Time
|
||||
// 创建时快照的有效预算上限(session 覆盖 > agent-kind 默认 > 全局默认)。
|
||||
BudgetMaxCostUSD *float64
|
||||
BudgetMaxTokens *int64
|
||||
BudgetMaxWallClockSeconds *int32
|
||||
// TerminatedReason 非 nil 时记录会话被强制终止的原因(budget_*/reaper_*/manual)。
|
||||
TerminatedReason *string
|
||||
}
|
||||
|
||||
// BudgetCaps 是一次会话的有效预算上限快照。nil 字段 = 该维度无限制。
|
||||
type BudgetCaps struct {
|
||||
MaxCostUSD *float64
|
||||
MaxTokens *int64
|
||||
MaxWallClockSeconds *int32
|
||||
}
|
||||
|
||||
// BreachReason 标识预算被突破的维度,落 acp_sessions.terminated_reason。
|
||||
type BreachReason string
|
||||
|
||||
const (
|
||||
BreachCost BreachReason = "budget_cost"
|
||||
BreachTokens BreachReason = "budget_tokens"
|
||||
BreachWallClock BreachReason = "budget_wall_clock"
|
||||
)
|
||||
|
||||
// SessionUsageRecord 是 acp_session_usage 表一行(per-turn 账目,镜像 llm_usage)。
|
||||
type SessionUsageRecord struct {
|
||||
ID int64
|
||||
SessionID uuid.UUID
|
||||
UserID uuid.UUID
|
||||
ProjectID uuid.UUID
|
||||
AgentKindID uuid.UUID
|
||||
ModelID *uuid.UUID
|
||||
PromptTokens int64
|
||||
CompletionTokens int64
|
||||
ThinkingTokens int64
|
||||
CostUSD float64
|
||||
SourceEventID *int64
|
||||
CreatedAt time.Time
|
||||
}
|
||||
|
||||
// AcpUsageUserRow 按用户聚合的 ACP 用量。
|
||||
type AcpUsageUserRow struct {
|
||||
UserID uuid.UUID
|
||||
PromptTokens, CompletionTokens, ThinkingTokens int64
|
||||
CostUSD float64
|
||||
}
|
||||
|
||||
// AcpUsageModelRow 按模型聚合的 ACP 用量。
|
||||
type AcpUsageModelRow struct {
|
||||
ModelID uuid.UUID
|
||||
PromptTokens, CompletionTokens, ThinkingTokens int64
|
||||
CostUSD float64
|
||||
}
|
||||
|
||||
// AcpUsageDayRow 按天聚合的 ACP 用量。
|
||||
type AcpUsageDayRow struct {
|
||||
Day time.Time
|
||||
PromptTokens, CompletionTokens, ThinkingTokens int64
|
||||
CostUSD float64
|
||||
}
|
||||
|
||||
// ===== run-history dashboard 读模型 =====
|
||||
|
||||
// DashboardFilter 限定 run-history 汇总的范围。UserID 非 nil 时仅统计该用户的
|
||||
// 会话(owner scope);nil 表示全量(admin scope)。ProjectID/RequirementID
|
||||
// 为可选过滤;From/To 为半开时间窗 [From, To)。
|
||||
type DashboardFilter struct {
|
||||
UserID *uuid.UUID
|
||||
ProjectID *uuid.UUID
|
||||
RequirementID *uuid.UUID
|
||||
From time.Time
|
||||
To time.Time
|
||||
}
|
||||
|
||||
// SessionRollup 是 run-history 汇总:会话计数 + 成功率 + 总成本 + 平均时长。
|
||||
type SessionRollup struct {
|
||||
Total int64
|
||||
Succeeded int64
|
||||
Crashed int64
|
||||
Active int64
|
||||
TotalCostUSD float64
|
||||
TotalTokens int64
|
||||
AvgDurationSeconds float64
|
||||
}
|
||||
|
||||
// SuccessRate 返回 succeeded/total(total=0 时为 0),便于 handler/MCP 直接使用。
|
||||
func (r SessionRollup) SuccessRate() float64 {
|
||||
if r.Total == 0 {
|
||||
return 0
|
||||
}
|
||||
return float64(r.Succeeded) / float64(r.Total)
|
||||
}
|
||||
|
||||
// SessionDayRow 是 run-history 按天的时间序列一行。
|
||||
type SessionDayRow struct {
|
||||
Day time.Time
|
||||
Total int64
|
||||
Succeeded int64
|
||||
Crashed int64
|
||||
TotalCostUSD float64
|
||||
}
|
||||
|
||||
// SessionTimelineBucket 是单会话事件按 (direction, rpc_kind, method) 分桶的一行。
|
||||
type SessionTimelineBucket struct {
|
||||
Direction string
|
||||
RPCKind string
|
||||
Method string
|
||||
EventCount int64
|
||||
FirstAt time.Time
|
||||
LastAt time.Time
|
||||
}
|
||||
|
||||
// ReaperSession 是 reaper 需要的最小 session 投影。
|
||||
type ReaperSession struct {
|
||||
ID uuid.UUID
|
||||
UserID uuid.UUID
|
||||
StartedAt time.Time
|
||||
LastActivityAt time.Time
|
||||
MaxWallClockSeconds *int32
|
||||
}
|
||||
|
||||
// StopReason 是回合完成的归一化原因枚举。agent 可能上报枚举外的 vendor-specific
|
||||
// 值;这些值归一化为 StopOther,但原始字符串仍会原样落库(stop_reason /
|
||||
// last_stop_reason),避免信息丢失。
|
||||
type StopReason string
|
||||
|
||||
const (
|
||||
StopEndTurn StopReason = "end_turn"
|
||||
StopMaxTokens StopReason = "max_tokens"
|
||||
StopRefusal StopReason = "refusal"
|
||||
StopCancelled StopReason = "cancelled"
|
||||
StopOther StopReason = "other"
|
||||
)
|
||||
|
||||
// NormalizeStopReason 把 agent 上报的原始 stopReason 映射到归一化枚举。
|
||||
// 未知值(含空串)映射为 StopOther。
|
||||
func NormalizeStopReason(raw string) StopReason {
|
||||
switch StopReason(raw) {
|
||||
case StopEndTurn:
|
||||
return StopEndTurn
|
||||
case StopMaxTokens:
|
||||
return StopMaxTokens
|
||||
case StopRefusal:
|
||||
return StopRefusal
|
||||
case StopCancelled:
|
||||
return StopCancelled
|
||||
default:
|
||||
return StopOther
|
||||
}
|
||||
}
|
||||
|
||||
// TurnStatus 是 acp_turns.status 枚举。
|
||||
type TurnStatus string
|
||||
|
||||
const (
|
||||
TurnInProgress TurnStatus = "in_progress"
|
||||
TurnCompleted TurnStatus = "completed"
|
||||
TurnAborted TurnStatus = "aborted"
|
||||
)
|
||||
|
||||
// Turn 是一次 agent 回合的审计记录。一个 session 内 turn_index 单调递增(0-based)。
|
||||
// PromptRequestID 是发起该回合的 session/prompt 的 JSON-RPC id(用于响应相关联)。
|
||||
// StopReason 在完成前为 nil;存储 agent 上报的原始字符串。
|
||||
type Turn struct {
|
||||
ID int64
|
||||
SessionID uuid.UUID
|
||||
TurnIndex int
|
||||
PromptRequestID *string
|
||||
Status TurnStatus
|
||||
StopReason *string
|
||||
UpdateCount int
|
||||
StartedAt time.Time
|
||||
CompletedAt *time.Time
|
||||
}
|
||||
|
||||
// Event 是一条入库的 JSON-RPC 消息。Payload 是 JSON-RPC envelope 完整 JSON
|
||||
@@ -204,6 +395,39 @@ type SessionService interface {
|
||||
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
|
||||
|
||||
// Dashboard 返回 run-history 汇总 + 按天序列。非 admin 调用强制按 caller
|
||||
// scope(UserID 覆盖为 caller),admin 才能查看全量。
|
||||
Dashboard(ctx context.Context, c Caller, in DashboardInput) (*DashboardResult, error)
|
||||
// Timeline 返回单会话的事件时间线(先经 Get 做 owner/admin 访问校验)。
|
||||
Timeline(ctx context.Context, c Caller, sessionID uuid.UUID) ([]SessionTimelineBucket, error)
|
||||
}
|
||||
|
||||
// DashboardInput 是 run-history 汇总的入参(过滤维度由 service 在 scope 内归一化)。
|
||||
type DashboardInput struct {
|
||||
ProjectID *uuid.UUID
|
||||
RequirementID *uuid.UUID
|
||||
From time.Time
|
||||
To time.Time
|
||||
}
|
||||
|
||||
// DashboardResult 是 run-history 汇总响应:总览 + 按天序列。
|
||||
type DashboardResult struct {
|
||||
Rollup SessionRollup
|
||||
ByDay []SessionDayRow
|
||||
From time.Time
|
||||
To time.Time
|
||||
}
|
||||
|
||||
// TurnRunner 是编排器驱动一个阻塞回合所需的窄接口(不扩大 SessionService 的
|
||||
// HTTP/MCP 暴露面)。sessionService 同时实现 SessionService 与 TurnRunner。
|
||||
//
|
||||
// - SendPromptAndWait 发送一条 session/prompt 并阻塞等待回合完成,返回原始
|
||||
// stopReason(来自 relay.Call 的 server-initiated 请求响应)。
|
||||
// - ResumeSession 在崩溃 session 的同一 cwd/worktree 上重新拉起 agent。
|
||||
type TurnRunner interface {
|
||||
SendPromptAndWait(ctx context.Context, sessionID uuid.UUID, prompt string) (stopReason string, err error)
|
||||
ResumeSession(ctx context.Context, c Caller, sessionID uuid.UUID) (*Session, error)
|
||||
}
|
||||
|
||||
// SessionListFilter 控制 sessions 列表的过滤维度。
|
||||
@@ -222,6 +446,9 @@ type CreateSessionInput struct {
|
||||
IssueNumber *int
|
||||
RequirementNumber *int
|
||||
InitialPrompt *string
|
||||
// OrchestratorStepID 非 nil 时把 session 与编排器 step 反向关联(仅由 orchestrator
|
||||
// 内部调用设置;HTTP/MCP 入口不暴露)。
|
||||
OrchestratorStepID *uuid.UUID
|
||||
}
|
||||
|
||||
// CreateAgentKindInput 携带创建必需字段。Args / Env 可为 nil。
|
||||
@@ -237,6 +464,11 @@ type CreateAgentKindInput struct {
|
||||
ToolAllowlist []string
|
||||
ClientType ClientType
|
||||
MCPServers []McpServerSpec
|
||||
// 成本核算:model 价格来源 + 默认预算上限(均可选)。
|
||||
ModelID *uuid.UUID
|
||||
MaxCostUSD *float64
|
||||
MaxTokens *int64
|
||||
MaxWallClockSeconds *int32
|
||||
}
|
||||
|
||||
// UpdateAgentKindInput 是 patch 输入。Name 不可改(创建后稳定,引用约束)。
|
||||
@@ -251,6 +483,16 @@ type UpdateAgentKindInput struct {
|
||||
ToolAllowlist []string // nil = 不改;非 nil(含空)= 替换
|
||||
ClientType *ClientType // nil = 不改
|
||||
MCPServers []McpServerSpec // nil = 不改;非 nil(含空)= 替换
|
||||
// 成本核算字段:三态指针,nil = 不改。SetModelID 控制 ModelID 是否参与更新
|
||||
// (ModelID 本身可被显式置空,故用独立 flag 区分"不改"与"清空")。
|
||||
SetModelID bool
|
||||
ModelID *uuid.UUID
|
||||
SetMaxCostUSD bool
|
||||
MaxCostUSD *float64
|
||||
SetMaxTokens bool
|
||||
MaxTokens *int64
|
||||
SetMaxWallClock bool
|
||||
MaxWallClockSeconds *int32
|
||||
}
|
||||
|
||||
// PermissionStatus 是 acp_permission_requests.status 枚举。
|
||||
|
||||
Reference in New Issue
Block a user