fix(web): preserve workspace automation output summary on orchestrator finish#1122
Conversation
|
The latest updates on your projects. Learn more about Vercel for GitHub. 1 Skipped Deployment
|
Greptile SummaryThis PR fixes a duplicate-draft bug in workspace automations by ensuring that tool-persisted fields (
Confidence Score: 5/5Safe to merge — the fix is well-scoped, all three mutation sites are covered, and the retry paths are backed by tests. The root cause (stale snapshot overwriting tool-persisted fields) is cleanly addressed: No files require special attention.
|
| Filename | Overview |
|---|---|
| apps/hyperlocalise-web/src/agents/automations/workspace/agent/run-workspace-orchestrator.ts | Replaces inline spread with buildWorkspaceOrchestratorOutputSummary on both the success and catch paths, using session.run.outputSummary (live in-memory copy) instead of the stale startup snapshot. |
| apps/hyperlocalise-web/src/agents/automations/workspace/agent/workspace-orchestrator-output-summary.ts | New module: merges tool-persisted fields (contentfulTranslationRunId, createTranslationJobs) from step results and prior orchestratorStepResults into the final output summary; exports mergeToolOutputSummaryIntoSessionRun for in-memory patching. |
| apps/hyperlocalise-web/src/agents/automations/workspace/agent/tools/resolve-existing-contentful-translation-run.ts | New module: four-source lookup for an existing Contentful translation run ID (outputSummary, current stepResults, prior orchestratorStepResults, DB), plus loadCompletedContentfulTranslationRunSummary for skip-re-execution logic. |
| apps/hyperlocalise-web/src/agents/automations/workspace/agent/tools/run_contentful_translation.ts | Adds idempotency guard: resolves any existing Contentful run ID, returns the completed summary without re-running the agent; calls mergeToolOutputSummaryIntoSessionRun immediately after creating a new Contentful run so the ID is durable before the agent executes. |
| apps/hyperlocalise-web/src/agents/automations/workspace/agent/tools/create_translation_jobs.ts | Adds idempotency early-return using readCreateTranslationJobs; calls mergeToolOutputSummaryIntoSessionRun after job creation to keep the in-memory snapshot consistent. |
| apps/hyperlocalise-web/src/agents/automations/workspace/agent/workspace-orchestrator-output-summary.test.ts | Three focused unit tests covering current step results, prior orchestratorStepResults fallback, and top-level field preservation for buildWorkspaceOrchestratorOutputSummary. |
| apps/hyperlocalise-web/src/agents/automations/workspace/agent/tools/resolve-existing-contentful-translation-run.test.ts | New test file: covers in-memory resolution from prior orchestratorStepResults and the DB fallback path for resolveExistingContentfulTranslationRunId. |
| apps/hyperlocalise-web/src/agents/automations/workspace/agent/tools/run_contentful_translation.test.ts | Adds DB mock infrastructure and a regression test for the completed-run early-return path; all pre-existing tests are guarded with mockEmptyContentfulRunLookup. |
Sequence Diagram
%%{init: {'theme': 'neutral'}}%%
sequenceDiagram
participant Orch as Orchestrator
participant Tool as run_contentful_translation
participant Resolve as resolveExistingContentfulTranslationRunId
participant DB as Database
participant Agent as runContentfulAgent
Orch->>Tool: execute()
Tool->>Resolve: resolveExistingContentfulTranslationRunId(session)
Resolve->>Resolve: check outputSummary.contentfulTranslationRunId
Resolve->>Resolve: check session.stepResults
Resolve->>Resolve: check outputSummary.orchestratorStepResults
alt not found in memory
Resolve->>DB: "SELECT id FROM contentfulTranslationRuns WHERE workspaceAutomationRunId=..."
DB-->>Resolve: existingRunId (or null)
end
Resolve-->>Tool: existingRunId
alt existingRunId found
Tool->>DB: loadCompletedContentfulTranslationRunSummary(existingRunId)
DB-->>Tool: completedSummary (or null if running/failed)
alt completedSummary present (succeeded)
Tool->>Orch: mergeToolOutputSummaryIntoSessionRun + return summary (SKIP re-run)
else run not yet complete
Tool->>Agent: runContentfulAgent(existingRunId)
end
else no existingRunId
Tool->>DB: createContentfulTranslationRun(...)
DB-->>Tool: translationRun.id
Tool->>DB: updateWorkspaceAutomationRun (persist contentfulTranslationRunId)
Tool->>Orch: mergeToolOutputSummaryIntoSessionRun (in-memory update)
Tool->>Agent: runContentfulAgent(translationRun.id)
end
Agent-->>Tool: result
Tool-->>Orch: stepResult
Orch->>Orch: buildWorkspaceOrchestratorOutputSummary(session.run.outputSummary, session.stepResults)
Orch->>DB: updateWorkspaceAutomationRun (final output)
%%{init: {'theme': 'base', 'themeVariables': {"darkMode": true, "background": "#0d1117", "primaryColor": "#21262d", "primaryTextColor": "#e6edf3", "primaryBorderColor": "#8b949e", "lineColor": "#8b949e", "textColor": "#e6edf3", "edgeLabelBackground": "#161b22", "actorBkg": "#21262d", "actorBorder": "#8b949e", "actorTextColor": "#e6edf3", "actorLineColor": "#8b949e", "signalColor": "#8b949e", "signalTextColor": "#e6edf3", "noteBkgColor": "#373320", "noteBorderColor": "#d4a72c", "noteTextColor": "#f0e6c0", "labelBoxBkgColor": "#21262d", "labelBoxBorderColor": "#8b949e", "labelTextColor": "#e6edf3", "loopTextColor": "#e6edf3", "activationBkgColor": "#30363d", "activationBorderColor": "#8b949e"}}}%%
sequenceDiagram
participant Orch as Orchestrator
participant Tool as run_contentful_translation
participant Resolve as resolveExistingContentfulTranslationRunId
participant DB as Database
participant Agent as runContentfulAgent
Orch->>Tool: execute()
Tool->>Resolve: resolveExistingContentfulTranslationRunId(session)
Resolve->>Resolve: check outputSummary.contentfulTranslationRunId
Resolve->>Resolve: check session.stepResults
Resolve->>Resolve: check outputSummary.orchestratorStepResults
alt not found in memory
Resolve->>DB: "SELECT id FROM contentfulTranslationRuns WHERE workspaceAutomationRunId=..."
DB-->>Resolve: existingRunId (or null)
end
Resolve-->>Tool: existingRunId
alt existingRunId found
Tool->>DB: loadCompletedContentfulTranslationRunSummary(existingRunId)
DB-->>Tool: completedSummary (or null if running/failed)
alt completedSummary present (succeeded)
Tool->>Orch: mergeToolOutputSummaryIntoSessionRun + return summary (SKIP re-run)
else run not yet complete
Tool->>Agent: runContentfulAgent(existingRunId)
end
else no existingRunId
Tool->>DB: createContentfulTranslationRun(...)
DB-->>Tool: translationRun.id
Tool->>DB: updateWorkspaceAutomationRun (persist contentfulTranslationRunId)
Tool->>Orch: mergeToolOutputSummaryIntoSessionRun (in-memory update)
Tool->>Agent: runContentfulAgent(translationRun.id)
end
Agent-->>Tool: result
Tool-->>Orch: stepResult
Orch->>Orch: buildWorkspaceOrchestratorOutputSummary(session.run.outputSummary, session.stepResults)
Orch->>DB: updateWorkspaceAutomationRun (final output)
Reviews (2): Last reviewed commit: "fix(web): address orchestrator output su..." | Re-trigger Greptile
|
@cursoragent rebase main, fix conflicts and Fix the following 3 code review issues. Work through them one at a time, proposing concise fixes. Issue 1 of 3apps/hyperlocalise-web/src/agents/automations/workspace/agent/run-workspace-orchestrator.ts:280-283 The catch block calls Issue 2 of 3apps/hyperlocalise-web/src/agents/automations/workspace/agent/tools/create_translation_jobs.ts:10-50 Issue 3 of 3apps/hyperlocalise-web/src/agents/automations/workspace/agent/tools/run_contentful_translation.test.ts:147-157 The mocks for |
|
Rebased onto RebaseRebased Issue 1 — stale
|
…r finish Prevent the orchestrator from overwriting tool-written outputSummary fields with the stale run snapshot. Reuse completed Contentful translation runs on workflow step retries instead of creating duplicate writebacks. Co-authored-by: Minh Cung <cungminh2710@users.noreply.github.com>
Co-authored-by: Minh Cung <cungminh2710@users.noreply.github.com>
Co-authored-by: Minh Cung <cungminh2710@users.noreply.github.com>
Use session.run.outputSummary as the merge base on both success and error paths so mid-run tool patches are not erased on failure. Reuse readCreateTranslationJobs in create_translation_jobs for consistent non-empty jobId validation, and add execute-path coverage for the Contentful translation retry idempotency early return. Co-authored-by: Minh Cung <cungminh2710@users.noreply.github.com>
9d066d0 to
86763b2
Compare


Bug and impact
Workspace automations that run Contentful translation could write duplicate drafts to Contentful when the workflow step retried after a successful translation.
The orchestrator captured
run.outputSummaryat the start of execution. Mid-run tools (run_contentful_translation,create_translation_jobs) persisted fields likecontentfulTranslationRunIdto the database, but the orchestrator's final update spread the stale snapshot and erased those fields. On step retry, the Contentful tool could not find the prior translation run and created a new one, re-executing the writeback.Root cause
run-workspace-orchestrator.tsfinalized runs with{ ...run.outputSummary, orchestratorStepResults }, overwriting tool-written summary fields.run_contentful_translationonly checked the top-levelcontentfulTranslationRunIdwhen deciding whether to reuse an existing Contentful translation run.Fix
buildWorkspaceOrchestratorOutputSummary()to merge tool-written fields (contentfulTranslationRunId,createTranslationJobs) from step results (and prior step results) into the finaloutputSummary.resolveExistingContentfulTranslationRunId()with DB fallback byworkspaceAutomationRunId, and skip re-execution when the linked Contentful run already succeeded.create_translation_jobswhencreateTranslationJobs/ step results already exist.Validation
vp teston new/updated workspace orchestrator and Contentful tool tests (14 tests)vp check --fix