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
+80 -3
View File
@@ -12,9 +12,16 @@ import (
)
type agentKindService struct {
repo Repository
enc *crypto.Encryptor
audit audit.Recorder
repo Repository
enc *crypto.Encryptor
audit audit.Recorder
modelCheck ModelValidator // 校验 model_id 引用一个启用的 llm_model;可为 nil(跳过校验)
}
// ModelValidator 校验某 model_id 引用一个存在且启用的 llm_model。装配期由 app.go
// 注入一个委托给 chat 的 adapter,避免 acp 构造期直接依赖 chat。
type ModelValidator interface {
IsEnabledModel(ctx context.Context, modelID uuid.UUID) (bool, error)
}
// NewAgentKindService 构造 AgentKindService。
@@ -22,6 +29,9 @@ func NewAgentKindService(repo Repository, enc *crypto.Encryptor, rec audit.Recor
return &agentKindService{repo: repo, enc: enc, audit: rec}
}
// SetModelValidator 注入 model 校验器(装配期回填)。
func (s *agentKindService) SetModelValidator(v ModelValidator) { s.modelCheck = v }
func (s *agentKindService) Create(ctx context.Context, c Caller, in CreateAgentKindInput) (*AgentKind, error) {
if !c.IsAdmin {
return nil, errs.New(errs.CodeForbidden, "admin only")
@@ -52,6 +62,12 @@ func (s *agentKindService) Create(ctx context.Context, c Caller, in CreateAgentK
if allowlist == nil {
allowlist = []string{}
}
if err := s.validateBudget(in.MaxCostUSD, in.MaxTokens, in.MaxWallClockSeconds); err != nil {
return nil, err
}
if err := s.validateModel(ctx, in.ModelID); err != nil {
return nil, err
}
k := &AgentKind{
ID: uuid.New(), Name: in.Name, DisplayName: in.DisplayName, Description: in.Description,
BinaryPath: in.BinaryPath, Args: args, EncryptedEnv: encrypted, Enabled: in.Enabled,
@@ -59,6 +75,10 @@ func (s *agentKindService) Create(ctx context.Context, c Caller, in CreateAgentK
ClientType: clientType,
EncryptedMCPServers: encryptedMCP,
CreatedBy: c.UserID,
ModelID: in.ModelID,
MaxCostUSD: in.MaxCostUSD,
MaxTokens: in.MaxTokens,
MaxWallClockSeconds: in.MaxWallClockSeconds,
}
out, err := s.repo.CreateAgentKind(ctx, k)
if err != nil {
@@ -146,6 +166,34 @@ func (s *agentKindService) Update(ctx context.Context, c Caller, id uuid.UUID, i
cur.Enabled = *in.Enabled
changed["enabled"] = *in.Enabled
}
if in.SetModelID {
if err := s.validateModel(ctx, in.ModelID); err != nil {
return nil, err
}
cur.ModelID = in.ModelID
changed["model_id"] = "<changed>"
}
if in.SetMaxCostUSD {
if err := s.validateBudget(in.MaxCostUSD, nil, nil); err != nil {
return nil, err
}
cur.MaxCostUSD = in.MaxCostUSD
changed["max_cost_usd"] = "<changed>"
}
if in.SetMaxTokens {
if err := s.validateBudget(nil, in.MaxTokens, nil); err != nil {
return nil, err
}
cur.MaxTokens = in.MaxTokens
changed["max_tokens"] = "<changed>"
}
if in.SetMaxWallClock {
if err := s.validateBudget(nil, nil, in.MaxWallClockSeconds); err != nil {
return nil, err
}
cur.MaxWallClockSeconds = in.MaxWallClockSeconds
changed["max_wall_clock_seconds"] = "<changed>"
}
if len(changed) == 0 {
return cur, nil
}
@@ -174,6 +222,35 @@ func (s *agentKindService) Delete(ctx context.Context, c Caller, id uuid.UUID) e
return nil
}
// validateBudget 校验预算上限:非空值必须为正。
func (s *agentKindService) validateBudget(maxCost *float64, maxTokens *int64, maxWall *int32) error {
if maxCost != nil && *maxCost <= 0 {
return errs.New(errs.CodeInvalidInput, "max_cost_usd must be positive")
}
if maxTokens != nil && *maxTokens <= 0 {
return errs.New(errs.CodeInvalidInput, "max_tokens must be positive")
}
if maxWall != nil && *maxWall <= 0 {
return errs.New(errs.CodeInvalidInput, "max_wall_clock_seconds must be positive")
}
return nil
}
// validateModel 校验 model_id 引用一个启用的 llm_model(modelCheck 为 nil 时跳过)。
func (s *agentKindService) validateModel(ctx context.Context, modelID *uuid.UUID) error {
if modelID == nil || s.modelCheck == nil {
return nil
}
ok, err := s.modelCheck.IsEnabledModel(ctx, *modelID)
if err != nil {
return err
}
if !ok {
return errs.New(errs.CodeInvalidInput, "model_id does not reference an enabled model")
}
return nil
}
func (s *agentKindService) recordAudit(ctx context.Context, c Caller, action, targetID string, meta map[string]any) {
if s.audit == nil {
return