From e1cbf90a286250f37178a3429bf2ae730dfb34df Mon Sep 17 00:00:00 2001 From: Daishan Peng Date: Fri, 10 Oct 2025 12:17:58 -0700 Subject: [PATCH] Enhance: Allow project to be upgraded when drift changes detected Signed-off-by: Daishan Peng --- apiclient/types/project.go | 21 +++++---- pkg/api/handlers/projects.go | 26 ++++------- pkg/controller/handlers/threads/template.go | 11 +++-- pkg/storage/apis/obot.obot.ai/v1/thread.go | 3 ++ .../openapi/generated/openapi_generated.go | 13 ++++++ .../edit/ProjectConfiguration.svelte | 46 ++++++++++++++----- ui/user/src/lib/services/chat/types.ts | 1 + 7 files changed, 80 insertions(+), 41 deletions(-) diff --git a/apiclient/types/project.go b/apiclient/types/project.go index 030a2f95b..3a9d2b66d 100644 --- a/apiclient/types/project.go +++ b/apiclient/types/project.go @@ -3,16 +3,17 @@ package types type Project struct { Metadata ProjectManifest - AssistantID string `json:"assistantID,omitempty"` - Editor bool `json:"editor"` - ParentID string `json:"parentID,omitempty"` - SourceProjectID string `json:"sourceProjectID,omitempty"` - UserID string `json:"userID,omitempty"` - WorkflowNamesFromIntegration WorkflowNamesFromIntegration `json:"workflowNamesFromIntegration,omitempty"` - TemplateUpgradeAvailable bool `json:"templateUpgradeAvailable,omitempty"` - TemplateUpgradeInProgress bool `json:"templateUpgradeInProgress,omitempty"` - TemplateLastUpgraded *Time `json:"templateLastUpgraded,omitempty"` - TemplatePublicID string `json:"templatePublicID,omitempty"` + AssistantID string `json:"assistantID,omitempty"` + Editor bool `json:"editor"` + ParentID string `json:"parentID,omitempty"` + SourceProjectID string `json:"sourceProjectID,omitempty"` + UserID string `json:"userID,omitempty"` + WorkflowNamesFromIntegration WorkflowNamesFromIntegration `json:"workflowNamesFromIntegration,omitempty"` + TemplateUpgradeAvailable bool `json:"templateUpgradeAvailable,omitempty"` + TemplateForceUpgradeAvailable bool `json:"templateForceUpgradeAvailable,omitempty"` + TemplateUpgradeInProgress bool `json:"templateUpgradeInProgress,omitempty"` + TemplateLastUpgraded *Time `json:"templateLastUpgraded,omitempty"` + TemplatePublicID string `json:"templatePublicID,omitempty"` } type WorkflowNamesFromIntegration struct { diff --git a/pkg/api/handlers/projects.go b/pkg/api/handlers/projects.go index 4ea215b6b..a27edcc33 100644 --- a/pkg/api/handlers/projects.go +++ b/pkg/api/handlers/projects.go @@ -268,13 +268,6 @@ func (h *ProjectsHandler) UpgradeFromTemplate(req api.Context) error { return types.NewErrHTTP(http.StatusTooEarly, "project upgrade already in progress") } - if !thread.Status.UpgradeAvailable { - // Project is ineligable for an upgrade due to one of the following reasons: - // - the project is already at the latest revision of the project snapshot - // - the user has manually modified the project - return types.NewErrBadRequest("project not eligible for an upgrade") - } - if thread.Spec.UpgradeApproved { // Project is already approved for an upgrade, nothing to do return nil @@ -518,15 +511,16 @@ func convertProject(thread *v1.Thread, parentThread *v1.Thread) types.Project { Models: thread.Spec.Models, Capabilities: convertProjectCapabilities(thread.Spec.Capabilities), }, - ParentID: strings.Replace(thread.Spec.ParentThreadName, system.ThreadPrefix, system.ProjectPrefix, 1), - SourceProjectID: strings.Replace(thread.Spec.SourceThreadName, system.ThreadPrefix, system.ProjectPrefix, 1), - AssistantID: thread.Spec.AgentName, - Editor: thread.IsEditor(), - UserID: thread.Spec.UserID, - WorkflowNamesFromIntegration: thread.Status.WorkflowNamesFromIntegration, - TemplateUpgradeAvailable: (thread.Status.UpgradeAvailable && !thread.Spec.UpgradeApproved), - TemplateUpgradeInProgress: thread.Status.UpgradeInProgress, - TemplatePublicID: thread.Status.UpgradePublicID, + ParentID: strings.Replace(thread.Spec.ParentThreadName, system.ThreadPrefix, system.ProjectPrefix, 1), + SourceProjectID: strings.Replace(thread.Spec.SourceThreadName, system.ThreadPrefix, system.ProjectPrefix, 1), + AssistantID: thread.Spec.AgentName, + Editor: thread.IsEditor(), + UserID: thread.Spec.UserID, + WorkflowNamesFromIntegration: thread.Status.WorkflowNamesFromIntegration, + TemplateUpgradeAvailable: (thread.Status.UpgradeAvailable && !thread.Spec.UpgradeApproved), + TemplateForceUpgradeAvailable: thread.Status.ForceUpgradeAvailable, + TemplateUpgradeInProgress: thread.Status.UpgradeInProgress, + TemplatePublicID: thread.Status.UpgradePublicID, } if !thread.Status.LastUpgraded.IsZero() { diff --git a/pkg/controller/handlers/threads/template.go b/pkg/controller/handlers/threads/template.go index db4db84a2..da7ed5ef3 100644 --- a/pkg/controller/handlers/threads/template.go +++ b/pkg/controller/handlers/threads/template.go @@ -32,8 +32,9 @@ func (t *Handler) EnsureUpgradeAvailable(req router.Request, _ router.Response) } var ( - source v1.Thread - upgradeAvailable bool + source v1.Thread + upgradeAvailable bool + forceUpgradeAvailable bool ) if err := req.Client.Get(req.Ctx, router.Key(thread.Namespace, thread.Spec.SourceThreadName), &source); err != nil { if !apierrors.IsNotFound(err) { @@ -53,18 +54,22 @@ func (t *Handler) EnsureUpgradeAvailable(req router.Request, _ router.Response) // If we find the revision, but it's the latest revision, there's no new upgrade available. found, latest := source.HasRevision(thread.GetLatestConfigRevision()) upgradeAvailable = found && !latest + + // if the thread's latest revision is not in the source thread's history, then we provide a status to show option to force upgrade + forceUpgradeAvailable = !found } upgradeAvailable = !source.Status.UpgradeInProgress && upgradeAvailable } - if thread.Status.UpgradeAvailable == upgradeAvailable { + if thread.Status.UpgradeAvailable == upgradeAvailable && thread.Status.ForceUpgradeAvailable == forceUpgradeAvailable { // No change, bail out return nil } // Update the status with the new value thread.Status.UpgradeAvailable = upgradeAvailable + thread.Status.ForceUpgradeAvailable = forceUpgradeAvailable return req.Client.Status().Update(req.Ctx, thread) } diff --git a/pkg/storage/apis/obot.obot.ai/v1/thread.go b/pkg/storage/apis/obot.obot.ai/v1/thread.go index 4c5be3188..d77565376 100644 --- a/pkg/storage/apis/obot.obot.ai/v1/thread.go +++ b/pkg/storage/apis/obot.obot.ai/v1/thread.go @@ -330,6 +330,9 @@ type ThreadStatus struct { // into this thread AND the thread's configuration has not changed since it was copied. UpgradeAvailable bool `json:"upgradeAvailable,omitempty"` + // ForceUpgradeAvailable is a flag to indicate if an force upgrade is available from the source thread. + ForceUpgradeAvailable bool `json:"forceUpgradeAvailable,omitempty"` + // UpgradeInProgress indicates if an upgrade from the source thread is in progress. UpgradeInProgress bool `json:"upgradeInProgress,omitempty"` diff --git a/pkg/storage/openapi/generated/openapi_generated.go b/pkg/storage/openapi/generated/openapi_generated.go index 2aa106666..f4e450965 100644 --- a/pkg/storage/openapi/generated/openapi_generated.go +++ b/pkg/storage/openapi/generated/openapi_generated.go @@ -5988,6 +5988,12 @@ func schema_obot_platform_obot_apiclient_types_Project(ref common.ReferenceCallb Format: "", }, }, + "templateForceUpgradeAvailable": { + SchemaProps: spec.SchemaProps{ + Type: []string{"boolean"}, + Format: "", + }, + }, "templateUpgradeInProgress": { SchemaProps: spec.SchemaProps{ Type: []string{"boolean"}, @@ -15510,6 +15516,13 @@ func schema_storage_apis_obotobotai_v1_ThreadStatus(ref common.ReferenceCallback Format: "", }, }, + "forceUpgradeAvailable": { + SchemaProps: spec.SchemaProps{ + Description: "ForceUpgradeAvailable is a flag to indicate if an force upgrade is available from the source thread.", + Type: []string{"boolean"}, + Format: "", + }, + }, "upgradeInProgress": { SchemaProps: spec.SchemaProps{ Description: "UpgradeInProgress indicates if an upgrade from the source thread is in progress.", diff --git a/ui/user/src/lib/components/edit/ProjectConfiguration.svelte b/ui/user/src/lib/components/edit/ProjectConfiguration.svelte index 1e52aebd7..60bdca65e 100644 --- a/ui/user/src/lib/components/edit/ProjectConfiguration.svelte +++ b/ui/user/src/lib/components/edit/ProjectConfiguration.svelte @@ -1,7 +1,7 @@