Skip to content

Conversation

@adityachoudhari26
Copy link
Member

@adityachoudhari26 adityachoudhari26 commented Jan 29, 2026

Summary by CodeRabbit

  • New Features

    • Workflows now automatically progress through steps as jobs complete.
    • Job agents are now integrated into workflow execution and scheduling.
  • Bug Fixes

    • Workflow steps are now properly ordered by index.
  • Tests

    • Added comprehensive test coverage for workflow creation, progression, and state management.

✏️ Tip: You can customize this high-level summary in your review settings.

@coderabbitai
Copy link
Contributor

coderabbitai bot commented Jan 29, 2026

📝 Walkthrough

Walkthrough

The pull request integrates job agent registry functionality into the workflow manager, refactoring the job dispatch flow to look up and instantiate jobs with proper configurations. Tests validate the complete workflow lifecycle including step continuation and active job tracking. Workflow views now track per-step jobs and expose active job status determination.

Changes

Cohort / File(s) Summary
Core Workflow Manager
apps/workspace-engine/pkg/workspace/workflowmanager/manager.go
Adds jobAgentRegistry dependency; refactors dispatchStep to look up job agents from store, merge configurations, and create Job objects with timestamps and status; introduces mergeJobAgentConfig and deepMerge helpers; updates ReconcileWorkflow to check HasActiveJobs instead of HasPendingJobs; triggers reconciliation immediately in CreateWorkflow.
Workflow View & Step Tracking
apps/workspace-engine/pkg/workspace/workflowmanager/workflow_view.go, apps/workspace-engine/pkg/workspace/store/workflow_step.go
Adds stepJobs field to WorkflowView and public HasActiveJobs() method; refactors completion/next-step logic to use IsInTerminalState semantics; adds isStepInProgress helper; sorts workflow steps by Index before returning in GetByWorkflowId.
Test Suite
apps/workspace-engine/pkg/workspace/workflowmanager/manager_test.go
Introduces comprehensive test suite with three test cases validating workflow creation, automatic step continuation after completion, and prevention of progression when steps are in progress; covers job agent registration, configuration propagation, and state transitions.

Sequence Diagram

sequenceDiagram
    actor User
    participant Manager
    participant Store
    participant Registry as JobAgentRegistry
    participant Workflow as Workflow State

    User->>Manager: CreateWorkflow(templateId, inputs)
    Manager->>Store: GetWorkflowTemplate
    Store-->>Manager: template with steps
    Manager->>Workflow: Create workflow instance
    Manager->>Manager: ReconcileWorkflow
    Manager->>Workflow: GetNextStep
    Workflow-->>Manager: step 1
    Manager->>Store: GetJobAgent(agentId)
    Store-->>Manager: jobAgent config
    Manager->>Manager: mergeJobAgentConfig
    Manager->>Registry: dispatchStep(step, job)
    Registry-->>Manager: job created & dispatched
    Workflow->>Workflow: Update with active job
    
    Note over Workflow: Step in progress...
    User->>Manager: ReconcileWorkflow
    Manager->>Workflow: HasActiveJobs()
    Workflow-->>Manager: true
    Manager->>Manager: Wait - step still active
    
    Note over Workflow: Step completes...
    User->>Manager: ReconcileWorkflow
    Manager->>Workflow: HasActiveJobs()
    Workflow-->>Manager: false
    Manager->>Workflow: GetNextStep
    Workflow-->>Manager: step 2
    Manager->>Registry: dispatchStep(step 2, job)
    Registry-->>Manager: job created & dispatched
Loading

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~25 minutes

Suggested reviewers

  • jsbroks

Poem

🐰 Hop-hop! The workflows now flow so fine,
Each job lined up in ordered line,
Steps sorted, agents reconciled with glee,
Active jobs dance in harmony! ✨

🚥 Pre-merge checks | ✅ 1 | ❌ 2
❌ Failed checks (1 warning, 1 inconclusive)
Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 0.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
Title check ❓ Inconclusive The PR title 'chore: workflow manager unit testing' is overly vague and does not accurately reflect the substantial changes made. The PR implements significant workflow manager refactoring including new dependencies, public API changes, reconciliation logic updates, and job dispatching—treating these critical changes as merely a 'chore' of adding unit tests is misleading about the scope and impact. Consider a more descriptive title that captures the main changes, such as 'refactor: integrate job agent registry into workflow manager' or 'feat: implement workflow job dispatching with job agent registry', followed by separate commit for unit tests.
✅ Passed checks (1 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing touches
  • 📝 Generate docstrings
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch wf-manager-unit-testing

Tip

🧪 Unit Test Generation v2 is now available!

We have significantly improved our unit test generation capabilities.

To enable: Add this to your .coderabbit.yaml configuration:

reviews:
  finishing_touches:
    unit_tests:
      enabled: true

Try it out by using the @coderabbitai generate unit tests command on your code files or under ✨ Finishing Touches on the walkthrough!

Have feedback? Share your thoughts on our Discord thread!


Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
apps/workspace-engine/pkg/workspace/workflowmanager/manager.go (1)

27-55: Propagate reconciliation errors to the caller.

CreateWorkflow ignores ReconcileWorkflow failures, which can hide dispatch/config problems and return a “successful” workflow that never started. At minimum, surface the error so callers can react.

🛠️ Suggested change
-	w.ReconcileWorkflow(ctx, workflow)
-	return workflow, nil
+	if err := w.ReconcileWorkflow(ctx, workflow); err != nil {
+		return workflow, err
+	}
+	return workflow, nil
🤖 Fix all issues with AI agents
In `@apps/workspace-engine/pkg/workspace/workflowmanager/manager.go`:
- Around line 59-90: The dispatchStep function persists a Job as Status=Pending
before calling m.jobAgentRegistry.Dispatch, which can leave a stuck pending job
if Dispatch fails; change the flow to avoid or clean up that state: either (A)
perform m.jobAgentRegistry.Dispatch(ctx, job) before calling
m.store.Jobs.Upsert(ctx, job) so the job is only persisted after a successful
dispatch, or (B) if pre-persist is required, ensure you handle errors from
jobAgentRegistry.Dispatch by updating the persisted job to a terminal/failed
status or deleting it (use m.store.Jobs.Upsert or a delete/update helper) so
HasActiveJobs() won’t block reconciliation. Update the dispatchStep
implementation accordingly (refer to dispatchStep, m.store.Jobs.Upsert, and
m.jobAgentRegistry.Dispatch).
🧹 Nitpick comments (1)
apps/workspace-engine/pkg/workspace/store/workflow_step.go (1)

51-53: Make ordering deterministic when Index values collide.

Sorting only by Index leaves equal-index ordering nondeterministic (map iteration order), which can cause flaky step sequencing if duplicates ever occur. Consider a stable sort with a secondary key (e.g., Id) or enforce unique indices.

🔧 Suggested tweak for deterministic ordering
-	sort.Slice(steps, func(i, j int) bool {
-		return steps[i].Index < steps[j].Index
-	})
+	sort.SliceStable(steps, func(i, j int) bool {
+		if steps[i].Index == steps[j].Index {
+			return steps[i].Id < steps[j].Id
+		}
+		return steps[i].Index < steps[j].Index
+	})

Comment on lines +59 to 90
func (m *Manager) dispatchStep(ctx context.Context, step *oapi.WorkflowStep) error {
jobAgent, ok := m.store.JobAgents.Get(step.JobAgent.Id)
if !ok {
return fmt.Errorf("job agent %s not found", step.JobAgent.Id)
}

mergedConfig, err := mergeJobAgentConfig(
jobAgent.Config,
step.JobAgent.Config,
)
if err != nil {
return fmt.Errorf("failed to merge job agent config: %w", err)
}

job := &oapi.Job{
Id: uuid.New().String(),
WorkflowStepId: step.Id,
JobAgentId: step.JobAgent.Id,
JobAgentConfig: mergedConfig,
CreatedAt: time.Now(),
UpdatedAt: time.Now(),
Metadata: make(map[string]string),
Status: oapi.JobStatusPending,
}

m.store.Jobs.Upsert(ctx, job)
if err := m.jobAgentRegistry.Dispatch(ctx, job); err != nil {
return fmt.Errorf("failed to dispatch job: %w", err)
}

return nil
}
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major

Avoid leaving a pending job when dispatch fails.

The job is persisted as pending before dispatch. If Dispatch fails, HasActiveJobs() will block further reconciliation forever, even though nothing was actually dispatched. Consider dispatching first or rolling back/marking terminal on error.

🧭 One possible approach (if Dispatch doesn’t require pre-persisted jobs)
-	m.store.Jobs.Upsert(ctx, job)
-	if err := m.jobAgentRegistry.Dispatch(ctx, job); err != nil {
-		return fmt.Errorf("failed to dispatch job: %w", err)
-	}
+	if err := m.jobAgentRegistry.Dispatch(ctx, job); err != nil {
+		return fmt.Errorf("failed to dispatch job: %w", err)
+	}
+	m.store.Jobs.Upsert(ctx, job)
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
func (m *Manager) dispatchStep(ctx context.Context, step *oapi.WorkflowStep) error {
jobAgent, ok := m.store.JobAgents.Get(step.JobAgent.Id)
if !ok {
return fmt.Errorf("job agent %s not found", step.JobAgent.Id)
}
mergedConfig, err := mergeJobAgentConfig(
jobAgent.Config,
step.JobAgent.Config,
)
if err != nil {
return fmt.Errorf("failed to merge job agent config: %w", err)
}
job := &oapi.Job{
Id: uuid.New().String(),
WorkflowStepId: step.Id,
JobAgentId: step.JobAgent.Id,
JobAgentConfig: mergedConfig,
CreatedAt: time.Now(),
UpdatedAt: time.Now(),
Metadata: make(map[string]string),
Status: oapi.JobStatusPending,
}
m.store.Jobs.Upsert(ctx, job)
if err := m.jobAgentRegistry.Dispatch(ctx, job); err != nil {
return fmt.Errorf("failed to dispatch job: %w", err)
}
return nil
}
func (m *Manager) dispatchStep(ctx context.Context, step *oapi.WorkflowStep) error {
jobAgent, ok := m.store.JobAgents.Get(step.JobAgent.Id)
if !ok {
return fmt.Errorf("job agent %s not found", step.JobAgent.Id)
}
mergedConfig, err := mergeJobAgentConfig(
jobAgent.Config,
step.JobAgent.Config,
)
if err != nil {
return fmt.Errorf("failed to merge job agent config: %w", err)
}
job := &oapi.Job{
Id: uuid.New().String(),
WorkflowStepId: step.Id,
JobAgentId: step.JobAgent.Id,
JobAgentConfig: mergedConfig,
CreatedAt: time.Now(),
UpdatedAt: time.Now(),
Metadata: make(map[string]string),
Status: oapi.JobStatusPending,
}
if err := m.jobAgentRegistry.Dispatch(ctx, job); err != nil {
return fmt.Errorf("failed to dispatch job: %w", err)
}
m.store.Jobs.Upsert(ctx, job)
return nil
}
🤖 Prompt for AI Agents
In `@apps/workspace-engine/pkg/workspace/workflowmanager/manager.go` around lines
59 - 90, The dispatchStep function persists a Job as Status=Pending before
calling m.jobAgentRegistry.Dispatch, which can leave a stuck pending job if
Dispatch fails; change the flow to avoid or clean up that state: either (A)
perform m.jobAgentRegistry.Dispatch(ctx, job) before calling
m.store.Jobs.Upsert(ctx, job) so the job is only persisted after a successful
dispatch, or (B) if pre-persist is required, ensure you handle errors from
jobAgentRegistry.Dispatch by updating the persisted job to a terminal/failed
status or deleting it (use m.store.Jobs.Upsert or a delete/update helper) so
HasActiveJobs() won’t block reconciliation. Update the dispatchStep
implementation accordingly (refer to dispatchStep, m.store.Jobs.Upsert, and
m.jobAgentRegistry.Dispatch).

@adityachoudhari26 adityachoudhari26 merged commit ad52ab0 into main Jan 30, 2026
9 checks passed
@adityachoudhari26 adityachoudhari26 deleted the wf-manager-unit-testing branch January 30, 2026 17:19
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants