Remove AI config approval flow
This commit is contained in:
@@ -13,10 +13,6 @@ import (
|
||||
"browser.local/platform/validator"
|
||||
)
|
||||
|
||||
const (
|
||||
aiConfigDiffTTL = 30 * time.Minute
|
||||
)
|
||||
|
||||
func (svc *CoreService) ListPluginLifecyclesForSession(sessionID string, filter domain.PluginLifecycleFilter) ([]domain.PluginLifecycleInstallation, error) {
|
||||
user, err := svc.GetCurrentUser(sessionID)
|
||||
if err != nil {
|
||||
@@ -128,84 +124,6 @@ func (svc *CoreService) RunPluginLifecycleForSession(sessionID string, request d
|
||||
return domain.CopyPluginLifecycleResult(domain.PluginLifecycleResult{Installation: installation, Job: job, Status: "queued"}), nil
|
||||
}
|
||||
|
||||
func (svc *CoreService) ListAIConfigDiffsForSession(sessionID string, filter domain.AIConfigDiffFilter) ([]domain.AIConfigDiffPreview, error) {
|
||||
user, err := svc.GetCurrentUser(sessionID)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
previews, err := svc.store.AIConfigDiffs().List(filter)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
visible := make([]domain.AIConfigDiffPreview, 0, len(previews))
|
||||
for _, preview := range previews {
|
||||
instance, err := svc.store.ServerInstances().Get(preview.ServerInstanceID)
|
||||
if err == nil && canAccessServer(user, instance) {
|
||||
visible = append(visible, preview)
|
||||
}
|
||||
}
|
||||
sort.Slice(visible, func(i, j int) bool { return visible[i].CreatedAt.After(visible[j].CreatedAt) })
|
||||
return domain.CopyAIConfigDiffPreviews(visible), nil
|
||||
}
|
||||
|
||||
func (svc *CoreService) ApproveAIConfigDiffForSession(sessionID string, request domain.AIConfigDiffApprovalRequest) (domain.AIConfigDiffApprovalResult, error) {
|
||||
if err := validator.ValidateAIConfigDiffApprovalRequest(request); err != nil {
|
||||
return domain.AIConfigDiffApprovalResult{}, err
|
||||
}
|
||||
user, err := svc.GetCurrentUser(sessionID)
|
||||
if err != nil {
|
||||
return domain.AIConfigDiffApprovalResult{}, err
|
||||
}
|
||||
svc.pluginOperationsMu.Lock()
|
||||
defer svc.pluginOperationsMu.Unlock()
|
||||
preview, err := svc.store.AIConfigDiffs().Get(request.DiffID)
|
||||
if err != nil {
|
||||
return domain.AIConfigDiffApprovalResult{}, err
|
||||
}
|
||||
instance, err := svc.store.ServerInstances().Get(preview.ServerInstanceID)
|
||||
if err != nil {
|
||||
return domain.AIConfigDiffApprovalResult{}, err
|
||||
}
|
||||
if !canAccessServer(user, instance) || (!isPlatformAdmin(user) && preview.CreatedBy != user.ID) {
|
||||
return domain.AIConfigDiffApprovalResult{}, ErrForbidden
|
||||
}
|
||||
if preview.State == domain.AIConfigDiffStateApproved {
|
||||
if preview.ApprovalIdempotencyKey != request.IdempotencyKey {
|
||||
return domain.AIConfigDiffApprovalResult{}, validationError("AI config diff is already approved with another idempotency key")
|
||||
}
|
||||
job, err := svc.store.Jobs().Get(preview.JobID)
|
||||
if err != nil {
|
||||
return domain.AIConfigDiffApprovalResult{}, err
|
||||
}
|
||||
dispatch := domain.ServerConfigWriteDispatch{Job: job, Status: "queued"}
|
||||
return domain.CopyAIConfigDiffApprovalResult(domain.AIConfigDiffApprovalResult{Preview: preview, Dispatch: dispatch}), nil
|
||||
}
|
||||
if preview.State != domain.AIConfigDiffStatePending {
|
||||
return domain.AIConfigDiffApprovalResult{}, validationError("AI config diff is not pending approval")
|
||||
}
|
||||
if !preview.ExpiresAt.After(svc.now()) {
|
||||
preview.State = domain.AIConfigDiffStateExpired
|
||||
preview.UpdatedAt = svc.now()
|
||||
_ = svc.store.AIConfigDiffs().Update(preview)
|
||||
return domain.AIConfigDiffApprovalResult{}, validationError("AI config diff has expired")
|
||||
}
|
||||
dispatch, err := svc.ApproveServerConfigWriteForSession(sessionID, domain.ServerConfigWriteApproval{ServerInstanceID: preview.ServerInstanceID, ExpectedConfigVersion: preview.ConfigVersion, ExpectedChecksum: preview.CurrentConfigChecksum, Key: preview.Key, ProposedContent: preview.ProposedConfig, IdempotencyKey: request.IdempotencyKey})
|
||||
if err != nil {
|
||||
return domain.AIConfigDiffApprovalResult{}, err
|
||||
}
|
||||
stamp := svc.now()
|
||||
preview.State = domain.AIConfigDiffStateApproved
|
||||
preview.ApprovedBy = user.ID
|
||||
preview.ApprovedAt = stamp
|
||||
preview.ApprovalIdempotencyKey = request.IdempotencyKey
|
||||
preview.JobID = dispatch.Job.ID
|
||||
preview.UpdatedAt = stamp
|
||||
if err := svc.store.AIConfigDiffs().Update(preview); err != nil {
|
||||
return domain.AIConfigDiffApprovalResult{}, err
|
||||
}
|
||||
return domain.CopyAIConfigDiffApprovalResult(domain.AIConfigDiffApprovalResult{Preview: preview, Dispatch: dispatch}), nil
|
||||
}
|
||||
|
||||
func (svc *CoreService) projectPluginOperationsJobResult(job domain.Job, stamp time.Time) error {
|
||||
if !strings.HasPrefix(job.ID, "job-plugin-lifecycle-") || job.ExecutionInput.LifecycleOperation == "" || job.ExecutionInput.PluginID == "" {
|
||||
return nil
|
||||
@@ -230,63 +148,6 @@ func (svc *CoreService) projectPluginOperationsJobResult(job domain.Job, stamp t
|
||||
return svc.store.PluginLifecycles().Update(installation)
|
||||
}
|
||||
|
||||
func (svc *CoreService) persistAIConfigDiff(actorID string, provider domain.AIProvider, request domain.AIInvocationRequest, result domain.AIProviderInvocationResult) (domain.AIConfigDiffPreview, error) {
|
||||
config, err := svc.getServerConfigForUser(actorID, request.ServerInstanceID)
|
||||
if err != nil {
|
||||
return domain.AIConfigDiffPreview{}, err
|
||||
}
|
||||
stamp := svc.now()
|
||||
preview := domain.AIConfigDiffPreview{ID: aiConfigDiffID(request.RequestID, request.ServerInstanceID), RequestID: request.RequestID, CreatedBy: actorID, ServerInstanceID: request.ServerInstanceID, PluginID: request.PluginID, ProviderID: provider.ID, Model: result.Usage.Model, Key: config.Key, ConfigVersion: config.ConfigVersion, CurrentConfigChecksum: config.Checksum, ProposedConfig: result.SuggestedConfig, DiffSummary: "review required before config write dispatch", State: domain.AIConfigDiffStatePending, ExpiresAt: stamp.Add(aiConfigDiffTTL), CreatedAt: stamp, UpdatedAt: stamp}
|
||||
if err := validator.ValidateAIConfigDiffPreview(preview); err != nil {
|
||||
return domain.AIConfigDiffPreview{}, err
|
||||
}
|
||||
if err := svc.store.AIConfigDiffs().Create(preview); err != nil {
|
||||
if !errors.Is(err, repo.ErrDuplicate) {
|
||||
return domain.AIConfigDiffPreview{}, err
|
||||
}
|
||||
existing, getErr := svc.store.AIConfigDiffs().Get(preview.ID)
|
||||
if getErr != nil {
|
||||
return domain.AIConfigDiffPreview{}, getErr
|
||||
}
|
||||
if existing.CreatedBy != actorID || existing.ServerInstanceID != request.ServerInstanceID || existing.PluginID != request.PluginID || existing.ProposedConfig != result.SuggestedConfig {
|
||||
return domain.AIConfigDiffPreview{}, validationError("requestId is already used for a different AI config recommendation")
|
||||
}
|
||||
return existing, nil
|
||||
}
|
||||
return preview, nil
|
||||
}
|
||||
|
||||
func (svc *CoreService) getServerConfigForUser(userID, serverInstanceID string) (domain.ServerConfig, error) {
|
||||
instance, err := svc.store.ServerInstances().Get(serverInstanceID)
|
||||
if err != nil {
|
||||
return domain.ServerConfig{}, err
|
||||
}
|
||||
user, err := svc.store.Users().Get(userID)
|
||||
if err != nil {
|
||||
return domain.ServerConfig{}, err
|
||||
}
|
||||
if !canAccessServer(user, instance) {
|
||||
return domain.ServerConfig{}, ErrForbidden
|
||||
}
|
||||
config := domain.ServerConfig{ServerInstanceID: instance.ID, ConfigVersion: instance.ConfigVersion, Format: "properties", Key: instance.ConfigKey, Content: instance.ConfigContent, Checksum: instance.ConfigChecksum, Source: "platform-derived", UpdatedAt: instance.ConfigUpdatedAt}
|
||||
if config.ConfigVersion <= 0 {
|
||||
config.ConfigVersion = 1
|
||||
}
|
||||
if config.Key == "" {
|
||||
config.Key = "server.properties"
|
||||
}
|
||||
if config.Content == "" {
|
||||
config.Content = buildLogicalServerConfig(instance)
|
||||
}
|
||||
if config.Checksum == "" {
|
||||
config.Checksum = validator.BytesChecksum([]byte(config.Content))
|
||||
}
|
||||
if config.UpdatedAt.IsZero() {
|
||||
config.UpdatedAt = svc.now()
|
||||
}
|
||||
return config, validator.ValidateServerConfig(config)
|
||||
}
|
||||
|
||||
func (svc *CoreService) pluginLifecycleDenied(actorID string, instance domain.ServerInstance, plugin domain.GamePlugin, request domain.PluginLifecycleRequest, reason string) (domain.PluginLifecycleResult, error) {
|
||||
svc.pluginOperationsMu.Lock()
|
||||
defer svc.pluginOperationsMu.Unlock()
|
||||
@@ -436,7 +297,7 @@ func pluginLifecycleInstallationID(pluginID, serverInstanceID string) string {
|
||||
return "plugin-lifecycle-" + hex.EncodeToString(sum[:12])
|
||||
}
|
||||
|
||||
func aiConfigDiffID(requestID, serverInstanceID string) string {
|
||||
sum := sha256.Sum256([]byte(requestID + "\x00" + serverInstanceID))
|
||||
return "ai-config-diff-" + hex.EncodeToString(sum[:12])
|
||||
func aiConfigWriteIdempotencyKey(requestID, serverInstanceID string) string {
|
||||
sum := sha256.Sum256([]byte("ai-config-write\x00" + requestID + "\x00" + serverInstanceID))
|
||||
return "ai-config-write-" + hex.EncodeToString(sum[:16])
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user