Skip to content

Add a type: wait step that pauses workflow execution for a duration #218

@jrob5756

Description

@jrob5756

Summary

Add a step type that pauses the workflow for a fixed duration (seconds, minutes, or hours) before continuing. Pure in-process sleep — no durability requirement.

Motivation

A handful of small but recurring needs:

  • Rate-limit cooldown — after a burst of API calls, wait 60s before the next batch instead of hitting 429s.
  • Polling — call an endpoint, check status, wait 30s, call again (combined with routing loop-backs).
  • External system catch-up — "I just published the doc; wait 10s for the CDN to invalidate before fetching it back to verify."
  • Demos and reproductions — pace a workflow so a human can follow along in the dashboard.

Today these all require type: script with command: sleep (which doesn't work on Windows without a shim) or sticking a time.sleep() inside a tool. Native support is cleaner and cross-platform.

Proposed shape

agents:
  - name: cooldown
    type: wait
    duration: 60s     # or: "5m", "1h", or a plain number (seconds)
    reason: "Cooling down after rate-limited burst"  # optional, shown in dashboard

  - name: poll_loop
    type: wait
    duration: "{{ workflow.input.poll_interval_seconds }}s"  # templated
    routes:
      - to: check_status   # loop back

Duration accepts:

  • Plain int/float — seconds
  • String suffix: s, m, h (e.g. "500ms", "2.5m", "1h")
  • Jinja2 template that evaluates to one of the above

Behavior

  • Pure asyncio.sleep in the engine dispatch loop. No worker pool, no persistence.
  • The workflow-level limits.timeout_seconds continues to count — a wait step inside a tight wall-clock limit will still trigger WorkflowTimeoutError.
  • Interrupt key (Esc/Ctrl+G) cancels the wait immediately, same as it interrupts an agent.
  • Emits agent_started / agent_completed events with type: wait so the dashboard can render a "sleeping…" pill with a countdown.
  • The step's output is { "waited_seconds": <actual elapsed> } so downstream routes can branch on it if needed (rarely useful, but free).

Why now

  • Tiny implementation, big convenience win for workflows that interact with external systems.
  • Cross-platform (no shell sleep dependency).
  • Composes with our existing routing loop-back pattern to build polling workflows without writing any Python.

Open questions

  • Maximum allowed duration? Suggest 24h cap — anything longer probably wants limits.timeout_seconds reconsidered first. Reject at schema validation with a clear message.
  • Should wait counts against agent iteration counters (max_agent_iterations)? No — it's not an agent execution. Counts as a step for routing purposes only.
  • Visibility: dashboard should show a live countdown? Nice-to-have, not required for v1.

Acceptance criteria

  • type: wait accepted by the YAML schema with duration (templated) and optional reason
  • Duration parser accepts s / m / h suffixes and plain numbers
  • Schema rejects durations > 24h and durations <= 0
  • Step pauses for the resolved duration using asyncio.sleep
  • Esc / Ctrl+G interrupt cancels an in-progress wait immediately
  • Workflow-level timeout cancels an in-progress wait
  • Output is { "waited_seconds": float } and available to routes / downstream steps
  • Example under examples/ (polling pattern with route loop-back)
  • Tests for: fixed sleep, templated sleep, interrupt cancellation, timeout cancellation, schema rejection of invalid durations

Metadata

Metadata

Assignees

No one assigned

    Labels

    area:configYAML schema, loader, validatorarea:engineWorkflow engine, routing, context, limitsenhancementNew feature or requestideaSpeculative feature proposal — not yet committed

    Type

    No type
    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions