feat(workflows): flow directives + sub-workflow invocation (lobster.run)#27
feat(workflows): flow directives + sub-workflow invocation (lobster.run)#27rendrag-git wants to merge 9 commits intoopenclaw:mainfrom
Conversation
- New src/query.ts with listRuns, getRunDetail, cancelRun functions - New test/query.test.ts with 11 unit tests covering all query operations - CLI subcommands: list, status, cancel added to src/cli.ts - Updated help text with new commands - All 58 tests passing
…isons Adds deep property access ($step.json.field.sub), comparison operators (==, !=, >, <, >=, <=), and truthiness checks to evaluateCondition(). Exports evaluateCondition and resolveDeepRef for testing. Fully backward compatible with existing $step.approved/$step.skipped patterns. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Adds FlowRule type, flow/max_iterations fields to WorkflowStep. loadWorkflowFile() now validates flow rule shapes, goto targets exist, default is last, and max_iterations is a positive integer. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
…anching Replaces the for-loop executor with a while-loop that honors flow rules. Adds stepIndexMap for O(1) goto resolution, visitCounts (persisted across halt/resume), and evaluateFlowRules(). Supports flowPending on resume (skip re-execution when only flow evaluation is needed after approval). Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
parseLobsterRunCommand() extracts --name/--file/--args-json from a command string. resolveWorkflowByName() searches parent dir, then LOBSTER_WORKFLOW_PATH dirs, then cwd, trying .lobster/.yaml/.yml/.json. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
…opagation executeChildWorkflow() runs child workflows in-process via recursive runWorkflowFile(). Child halt bubbles to parent via childStateKey in resume state. Depth limit enforced via LOBSTER_MAX_WORKFLOW_DEPTH (default 10). Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Tests cover: sub-workflow in a flow loop, three-level nesting, nested halt inside a loop with resume, flow routing, and combined flow + approval + lobster.run scenarios. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: e1242bce44
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
| resumeToken: encodeToken({ | ||
| filePath: state.filePath, | ||
| resumeAtIndex: state.resumeAtIndex, | ||
| steps: state.steps, | ||
| args: state.args, |
There was a problem hiding this comment.
Include protocol/version fields in generated status resume tokens
getRunDetail() builds resumeToken without protocolVersion, v, or kind, but resume decoding requires those fields (src/resume.ts checks protocolVersion and v before accepting any token). In practice, the token returned by lobster status cannot be passed to lobster resume because it is rejected as an unsupported token format, so this new status/detail path exposes a non-functional resume token.
Useful? React with 👍 / 👎.
| const visits = (visitCounts.get(step.id) ?? 0) + 1; | ||
| const maxIter = step.max_iterations ?? 10; | ||
| if (visits > maxIter) { | ||
| throw new Error(`Step '${step.id}' exceeded max_iterations (${maxIter})`); |
There was a problem hiding this comment.
Skip visit-count increment when resuming halted sub-workflow
The step visit counter is incremented before resuming a halted child workflow, so any resume with childStateKey consumes an extra iteration even though the parent step is just continuing prior work. This causes false max_iterations failures for lobster.run steps that halt for approval (for example, max_iterations: 1 will fail on the first resume), which breaks resumable sub-workflows under tighter iteration limits.
Useful? React with 👍 / 👎.
What
Two features that transform Lobster's workflow file runtime from a linear step executor into a control-flow engine:
1. Flow Directives — branching, loops, skip-ahead
gotoforward (skip-ahead) or backward (loops)defaultunconditional fallbackmax_iterationsper step (default 10) — hard error on breach$step.json.field.sub), comparison operators (==,!=,>,<,>=,<=), truthiness checks2. Sub-workflow Invocation (
lobster.run)runWorkflowFile()— not a subprocess$LOBSTER_WORKFLOW_PATH→ cwd--args-json(template-resolved)$LOBSTER_MAX_WORKFLOW_DEPTH)--name(search) and--file(explicit path)Stats
src/workflows/file.tsflowfield = linear execution as beforeTest files
test/condition-evaluator.test.ts— extended condition evaluatortest/workflow-flow-validation.test.ts— load-time flow validationtest/workflow-flow.test.ts— flow execution (loops, branches, max_iterations)test/workflow-subworkflow-parsing.test.ts— lobster.run command parsing + file resolutiontest/workflow-subworkflow.test.ts— sub-workflow execution + halt propagationtest/workflow-integration.test.ts— combined feature tests