Skip to content

feat(client): resume + getScreen on the automation SDK surface (#3528)#3552

Merged
os-zhuang merged 2 commits into
mainfrom
claude/screen-flow-submit-resume-v9dqjx
Jul 27, 2026
Merged

feat(client): resume + getScreen on the automation SDK surface (#3528)#3552
os-zhuang merged 2 commits into
mainfrom
claude/screen-flow-submit-resume-v9dqjx

Conversation

@os-zhuang

Copy link
Copy Markdown
Contributor

Closes the SDK half of #3528. The Console half is objectui#(companion PR on the same branch name).

What was actually wrong

The issue reports that Submit on a screen-flow step never calls the resume endpoint. I reproduced the whole path against a real server with the published @objectstack/console 16.1.0 build (dropped into packages/console/dist, .objectui-sha cf2d56e), driving it in Chromium:

Surface Result
List row action (showcase_bulk_reassign → flat-field screen) trigger → screen → resume 200, record updated
Record page action (same flow, record_section) trigger → screen → resume 200
Record page action → crm_convert_lead_wizard (two object-form steps, the lead-conversion shape) trigger → form → account created → resume 200 → step 2
Developer → Flow Runs → Test Run trigger only. Paused envelope rendered as JSON. No screen, no Submit, no resume — the run is orphaned.

So the resume call does exist on the record/list surfaces, but the reporter's diagnosis — "@objectstack/client's automation surface exposes getFlow, execute, listRuns, getRun but no resume … the SDK the Console builds on has no way to express the call" — is correct, and it is exactly what dead-ends the fourth row. Every test run of a screen flow there leaves a paused row behind with no way to finish it.

This PR

  • automation.resume(flowName, runId, signal?) — posts the collected screen values as inputs (applied as bare flow variables), plus the approval-style output / branchLabel the dispatcher already accepts. Returns the next { status: 'paused', screen } of a multi-step wizard, or the terminal AutomationResult.
  • automation.getScreen(flowName, runId) — the screen a paused run is waiting on, so a client that did not launch the run (a reload, another tab, an inbox) can render the pending step before resuming.
  • Both on the environment-scoped client (client.project(id).automation.*) as well as the unscoped one.
  • Dispatcher route testsPOST /:name/runs/:runId/resume and GET /:name/runs/:runId/screen had zero coverage. Now covered: inputs / variables aliasing, output + branchLabel, the empty-signal body, the pause-again envelope, the 501 when the service cannot resume, the 404 when no screen is pending, and the ordering guard that keeps /runs/:runId/screen from being swallowed by the /runs/:runId run lookup.

No route or engine changes — the server side of ADR-0019 already worked, confirmed by hand over HTTP before touching anything.

Test plan

  • pnpm --filter @objectstack/client test — 116 passed (11 new automation assertions incl. the scoped client's first automation tests).
  • pnpm --filter @objectstack/runtime exec vitest run src/http-dispatcher.test.ts — 193 passed (9 new).
  • Manual HTTP round-trip against examples/app-showcase on a live dev server: trigger → status: paused → resume → success: true, record updated.

Not in this PR

Two adjacent gaps found while tracing every UI path that can dispatch a type: 'flow' action — both are launch-side, not resume-side, and want their own change:

  • DashboardRenderer header actions only branch on url / modal / script; a type: 'flow' header action falls through to console.warn("Unknown header actionType") and never dispatches. It also has no ActionProvider in its subtree, so even routed it would report "Flow handler not registered".
  • The console-root <ActionProvider> (ConsoleShell) is mounted with no handlers map, so any action:button outside ObjectView / RecordDetailView / PageView / DeclaredActionsBar binds to a runner with no flow handler.

🤖 Generated with Claude Code

https://claude.ai/code/session_01LX9ut3MK3KykE11S9bJmv5


Generated by Claude Code

A `type: 'screen'` flow suspends at its `screen` node — `execute()` returns
`{ status: 'paused', runId, screen }` and the run waits for input. The
dispatcher has served the other half of that contract since ADR-0019
(`POST /automation/:flow/runs/:runId/resume`, `GET .../screen`), but the client
SDK's automation surface stopped at getFlow / execute / listRuns / getRun. Any
consumer built on the SDK could therefore start a screen flow and never finish
it: the run stayed suspended and the only way out was hand-rolling the HTTP
call. That is what dead-ended the Console's developer "Flow Runs" test runner,
where every test run of a screen flow orphaned a `paused` row.

- `automation.resume(flowName, runId, signal?)` posts the collected screen
  values as `inputs`, plus the approval-style `output` / `branchLabel` the
  dispatcher already accepts, and returns either the next paused screen of a
  multi-step wizard or the terminal AutomationResult.
- `automation.getScreen(flowName, runId)` returns the screen a paused run is
  waiting on, so a client that did not launch the run (a reload, another tab,
  an inbox) can render the pending step before resuming.
- Both land on the environment-scoped client as well as the unscoped one.

The two dispatcher routes had no test coverage at all; they now cover the
`inputs` / `variables` aliasing, approval-style output + branchLabel, the
pause-again envelope, the 501 when the service cannot resume, and the ordering
guard that keeps `/runs/:runId/screen` from being swallowed by the run lookup.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01LX9ut3MK3KykE11S9bJmv5
@vercel

vercel Bot commented Jul 27, 2026

Copy link
Copy Markdown

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Actions Updated (UTC)
spec Building Building Preview, Comment Jul 27, 2026 4:23am
1 Skipped Deployment
Project Deployment Actions Updated (UTC)
objectstack Ignored Ignored Jul 27, 2026 4:23am

Request Review

@github-actions github-actions Bot added documentation Improvements or additions to documentation tests tooling size/m labels Jul 27, 2026
@github-actions

Copy link
Copy Markdown
Contributor

📓 Docs Drift Check

This PR changes 2 package(s): @objectstack/client, @objectstack/runtime.

26 hand-written doc(s) reference the affected code and may need an implementation-accuracy re-verification:

  • content/docs/ai/skills-reference.mdx (via packages/client)
  • content/docs/api/client-sdk.mdx (via @objectstack/client)
  • content/docs/api/data-flow.mdx (via @objectstack/client)
  • content/docs/api/environment-routing.mdx (via @objectstack/client)
  • content/docs/api/error-catalog.mdx (via @objectstack/client)
  • content/docs/api/index.mdx (via @objectstack/runtime)
  • content/docs/api/wire-format.mdx (via @objectstack/runtime)
  • content/docs/automation/hook-bodies.mdx (via @objectstack/runtime)
  • content/docs/concepts/north-star.mdx (via packages/runtime)
  • content/docs/data-modeling/drivers.mdx (via @objectstack/runtime)
  • content/docs/deployment/index.mdx (via @objectstack/runtime)
  • content/docs/deployment/production-readiness.mdx (via @objectstack/runtime)
  • content/docs/deployment/single-project-mode.mdx (via @objectstack/runtime)
  • content/docs/deployment/vercel.mdx (via @objectstack/runtime)
  • content/docs/getting-started/your-first-project.mdx (via @objectstack/client, @objectstack/runtime)
  • content/docs/kernel/runtime-services/data-service.mdx (via packages/client)
  • content/docs/kernel/runtime-services/index.mdx (via packages/client)
  • content/docs/permissions/authentication.mdx (via @objectstack/client, @objectstack/runtime)
  • content/docs/permissions/authorization.mdx (via packages/runtime)
  • content/docs/plugins/packages.mdx (via @objectstack/client, @objectstack/runtime)
  • content/docs/protocol/kernel/http-protocol.mdx (via @objectstack/runtime)
  • content/docs/protocol/kernel/index.mdx (via @objectstack/runtime)
  • content/docs/protocol/kernel/lifecycle.mdx (via @objectstack/runtime)
  • content/docs/protocol/kernel/realtime-protocol.mdx (via @objectstack/client)
  • content/docs/releases/implementation-status.mdx (via @objectstack/client, @objectstack/runtime)
  • content/docs/releases/v16.mdx (via @objectstack/client)

Advisory only. To re-verify, run the docs-accuracy-audit workflow scoped to these files:
node scripts/docs-audit/affected-docs.mjs origin/main → pass the list as args.docs.

…uide (#3528)

The SDK page's automation example stopped at `trigger()`, which is exactly the
gap the issue reports: a reader had no way to learn that `execute()` on a
screen flow returns a paused run, or how to finish it. Adds the
execute → paused → resume round-trip and `getScreen()` for a client that did
not launch the run.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01LX9ut3MK3KykE11S9bJmv5
@os-zhuang
os-zhuang marked this pull request as ready for review July 27, 2026 04:51
@os-zhuang
os-zhuang merged commit 0cdb57a into main Jul 27, 2026
16 checks passed
@os-zhuang
os-zhuang deleted the claude/screen-flow-submit-resume-v9dqjx branch July 27, 2026 04:51
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

documentation Improvements or additions to documentation size/m tests tooling

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants