You've already forked agentic-coding-workflow
bugfix
This commit is contained in:
@@ -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
|
||||
|
||||
Reference in New Issue
Block a user