Skip to content

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

Description

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

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

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

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions