This commit is contained in:
2026-06-22 08:55:57 +08:00
parent dbb87823e8
commit 6ade6e8fa9
325 changed files with 41131 additions and 855 deletions
+171 -3
View File
@@ -21,9 +21,14 @@ type AgentKindAdminDTO struct {
ClientType string `json:"client_type"`
// MCPServers 明文返回(admin only,编辑所需);条目可能含 header/env 密钥。
MCPServers []McpServerSpec `json:"mcp_servers"`
CreatedBy uuid.UUID `json:"created_by"`
CreatedAt string `json:"created_at"`
UpdatedAt string `json:"updated_at"`
// 成本核算:model 价格来源 + 默认预算上限(均可空)。
ModelID *string `json:"model_id"`
MaxCostUSD *float64 `json:"max_cost_usd"`
MaxTokens *int64 `json:"max_tokens"`
MaxWallClockSeconds *int32 `json:"max_wall_clock_seconds"`
CreatedBy uuid.UUID `json:"created_by"`
CreatedAt string `json:"created_at"`
UpdatedAt string `json:"updated_at"`
}
// AgentKindPublicDTO 是普通用户视图,不暴露 binary_path / args / env_keys。
@@ -46,6 +51,11 @@ type CreateAgentKindReq struct {
ToolAllowlist []string `json:"tool_allowlist"`
ClientType string `json:"client_type"`
MCPServers []McpServerSpec `json:"mcp_servers"`
// 成本核算:model_id 为字符串 UUID(空/缺省 = 不设置);预算上限均可选。
ModelID *string `json:"model_id"`
MaxCostUSD *float64 `json:"max_cost_usd"`
MaxTokens *int64 `json:"max_tokens"`
MaxWallClockSeconds *int32 `json:"max_wall_clock_seconds"`
}
type UpdateAgentKindReq struct {
@@ -58,6 +68,12 @@ type UpdateAgentKindReq struct {
ToolAllowlist []string `json:"tool_allowlist,omitempty"`
ClientType *string `json:"client_type,omitempty"`
MCPServers []McpServerSpec `json:"mcp_servers,omitempty"` // nil = 不改;非 nil(含空)= 替换
// 成本核算三态:字段存在(非 nil)= 设置;缺省(nil)= 不改。
// ModelID 空串 = 清空;预算上限值 <=0 = 清空。
ModelID *string `json:"model_id,omitempty"`
MaxCostUSD *float64 `json:"max_cost_usd,omitempty"`
MaxTokens *int64 `json:"max_tokens,omitempty"`
MaxWallClockSeconds *int32 `json:"max_wall_clock_seconds,omitempty"`
}
// ConfigFileDTO 是 AgentKind 配置文件的对外视图(admin only,content 明文)。
@@ -133,6 +149,15 @@ type SessionDTO struct {
LastError *string `json:"last_error"`
StartedAt string `json:"started_at"`
EndedAt *string `json:"ended_at"`
// 成本核算:运行时累计 + 有效预算上限 + 终止原因。
PromptTokens int64 `json:"prompt_tokens"`
CompletionTokens int64 `json:"completion_tokens"`
ThinkingTokens int64 `json:"thinking_tokens"`
TotalCostUSD float64 `json:"total_cost_usd"`
BudgetMaxCostUSD *float64 `json:"budget_max_cost_usd"`
BudgetMaxTokens *int64 `json:"budget_max_tokens"`
BudgetMaxWallClockSeconds *int32 `json:"budget_max_wall_clock_seconds"`
TerminatedReason *string `json:"terminated_reason"`
}
func sessionToDTO(s *Session) SessionDTO {
@@ -167,5 +192,148 @@ func sessionToDTO(s *Session) SessionDTO {
LastError: s.LastError,
StartedAt: s.StartedAt.UTC().Format("2006-01-02T15:04:05Z"),
EndedAt: ended,
PromptTokens: s.PromptTokens,
CompletionTokens: s.CompletionTokens,
ThinkingTokens: s.ThinkingTokens,
TotalCostUSD: s.TotalCostUSD,
BudgetMaxCostUSD: s.BudgetMaxCostUSD,
BudgetMaxTokens: s.BudgetMaxTokens,
BudgetMaxWallClockSeconds: s.BudgetMaxWallClockSeconds,
TerminatedReason: s.TerminatedReason,
}
}
// SessionUsageDTO 是单条 per-turn 账目的对外视图。
type SessionUsageDTO struct {
ID int64 `json:"id"`
ModelID *string `json:"model_id"`
PromptTokens int64 `json:"prompt_tokens"`
CompletionTokens int64 `json:"completion_tokens"`
ThinkingTokens int64 `json:"thinking_tokens"`
CostUSD float64 `json:"cost_usd"`
CreatedAt string `json:"created_at"`
}
// SessionUsageResponse 是 GET /sessions/{id}/usage 的响应:会话累计 + 最近账目。
type SessionUsageResponse struct {
SessionID string `json:"session_id"`
PromptTokens int64 `json:"prompt_tokens"`
CompletionTokens int64 `json:"completion_tokens"`
ThinkingTokens int64 `json:"thinking_tokens"`
TotalCostUSD float64 `json:"total_cost_usd"`
BudgetMaxCostUSD *float64 `json:"budget_max_cost_usd"`
BudgetMaxTokens *int64 `json:"budget_max_tokens"`
Recent []SessionUsageDTO `json:"recent"`
}
// AcpUsageItem 是 admin ACP 用量聚合的一行(镜像 chat AdminUsageItem)。
type AcpUsageItem struct {
Key string `json:"key"`
PromptTokens int64 `json:"prompt_tokens"`
CompletionTokens int64 `json:"completion_tokens"`
ThinkingTokens int64 `json:"thinking_tokens"`
CostUSD float64 `json:"cost_usd"`
}
// AcpUsageResponse 包裹分组用量项。
type AcpUsageResponse struct {
Items []AcpUsageItem `json:"items"`
}
// ===== run-history dashboard DTO =====
// DashboardResponse 是 GET /api/v1/acp/dashboard 的响应:总览 + 按天序列。
type DashboardResponse struct {
From string `json:"from"`
To string `json:"to"`
Rollup SessionRollupDTO `json:"rollup"`
ByDay []SessionDayDTO `json:"by_day"`
}
// SessionRollupDTO 是会话总览(计数 + 成功率 + 成本 + 平均时长)。
type SessionRollupDTO struct {
Total int64 `json:"total"`
Succeeded int64 `json:"succeeded"`
Crashed int64 `json:"crashed"`
Active int64 `json:"active"`
SuccessRate float64 `json:"success_rate"`
TotalCostUSD float64 `json:"total_cost_usd"`
TotalTokens int64 `json:"total_tokens"`
AvgDurationSeconds float64 `json:"avg_duration_seconds"`
}
// SessionDayDTO 是按天的时间序列一行。
type SessionDayDTO struct {
Day string `json:"day"`
Total int64 `json:"total"`
Succeeded int64 `json:"succeeded"`
Crashed int64 `json:"crashed"`
TotalCostUSD float64 `json:"total_cost_usd"`
}
// SessionTimelineDTO 是单会话事件时间线一行(按 method/kind 分桶)。
type SessionTimelineDTO struct {
Direction string `json:"direction"`
Kind string `json:"kind"`
Method string `json:"method"`
EventCount int64 `json:"event_count"`
FirstAt string `json:"first_at"`
LastAt string `json:"last_at"`
}
func dashboardToResponse(r *DashboardResult) DashboardResponse {
resp := DashboardResponse{
From: r.From.UTC().Format(time.RFC3339),
To: r.To.UTC().Format(time.RFC3339),
Rollup: SessionRollupDTO{
Total: r.Rollup.Total,
Succeeded: r.Rollup.Succeeded,
Crashed: r.Rollup.Crashed,
Active: r.Rollup.Active,
SuccessRate: r.Rollup.SuccessRate(),
TotalCostUSD: r.Rollup.TotalCostUSD,
TotalTokens: r.Rollup.TotalTokens,
AvgDurationSeconds: r.Rollup.AvgDurationSeconds,
},
ByDay: make([]SessionDayDTO, 0, len(r.ByDay)),
}
for _, d := range r.ByDay {
resp.ByDay = append(resp.ByDay, SessionDayDTO{
Day: d.Day.UTC().Format(time.RFC3339),
Total: d.Total,
Succeeded: d.Succeeded,
Crashed: d.Crashed,
TotalCostUSD: d.TotalCostUSD,
})
}
return resp
}
func sessionTimelineToDTO(b SessionTimelineBucket) SessionTimelineDTO {
return SessionTimelineDTO{
Direction: b.Direction,
Kind: b.RPCKind,
Method: b.Method,
EventCount: b.EventCount,
FirstAt: b.FirstAt.UTC().Format(time.RFC3339),
LastAt: b.LastAt.UTC().Format(time.RFC3339),
}
}
func sessionUsageToDTO(r *SessionUsageRecord) SessionUsageDTO {
var modelID *string
if r.ModelID != nil {
v := r.ModelID.String()
modelID = &v
}
return SessionUsageDTO{
ID: r.ID,
ModelID: modelID,
PromptTokens: r.PromptTokens,
CompletionTokens: r.CompletionTokens,
ThinkingTokens: r.ThinkingTokens,
CostUSD: r.CostUSD,
CreatedAt: r.CreatedAt.UTC().Format(time.RFC3339),
}
}