Skip to content

v2.0.0b3

Pre-release
Pre-release

Choose a tag to compare

@github-actions github-actions released this 05 Aug 20:23
· 105 commits to dev since this release

A hardening release: no new surface, sturdier runtime. Cancel a run from
another process, answer an approval from either of two servers without the
workflow running twice, and keep telemetry from growing memory or losing
events behind a wedged endpoint. Every guarantee here is enforced by the
event store itself rather than by in-process locks, so it holds when a
second worker joins. The v1 public surface remains byte-for-byte unchanged.

Added

  • Run control (agentdeck.core.ports.control, agentdeck.adapters.control): a
    ControlPort for cross-process cancel signals, backed by an in-memory adapter
    for dev/tests and a SQLite-backed one durable enough for a second OS process to
    reach a run it never held a reference to. The OpenAI Agents engine checks a
    cooperative gate between stream items and stops cleanly on cancel, emitting a
    single run.cancelled and leaving a truncated-but-coherent replay behind (no
    message.completed for the interrupted message). New agentdeck runs signal <run_id> cancel --control-db <path> CLI command to send that signal from a
    second terminal.
  • EventStorePort (not yet part of any stable public API) gains focused
    queries alongside its whole-log reads: last_seq (a run's highest
    recorded seq), run_status (one run's status, derived from its own
    events), list_runs (every run for a tenant, optionally filtered by
    status), and pagination (offset/limit) on read. Both the memory and
    SQLite stores implement all four; the SQLite ones use the existing
    run/log indexes.
  • EventStorePort.claim_resume (not yet part of any stable public API): a
    conditional append that records run.resumed only if the run is still waiting
    on a human answer and the event's seq is still the run's next one, as one
    indivisible step, and reports whether it won. The memory store gets that for
    free; the SQLite store does it in a single BEGIN IMMEDIATE transaction, so
    the events file itself picks the winner.

Changed

  • Internal: the v2 event-log port (not yet part of any stable public API) is
    now named EventStorePort instead of SessionStorePort, to avoid confusion
    with the OpenAI Agents engine's own session-scoped storage. No behavior
    change and nothing outside the package imports this port.
  • Internal: the Runtime's resume path and the /pending listing now use
    EventStorePort's focused queries instead of folding a whole log to answer
    one run's status or find waiting runs. Same results, much less work per call:
    a resume deserializes only its own run's events instead of the whole session's
    (22 instead of 4,400 on a 200-run session), and the pending listing is one
    indexed statement returning each run's last lifecycle event — one event parsed
    per run instead of every event of every log (4.2 ms instead of 32 ms for the
    same 201 runs).
  • Event sinks are now fed from a bounded queue with one worker each, instead of a
    fresh task per event per sink. A wedged sink (telemetry endpoint down, audit
    store backpressured) now costs a fixed backlog and one task rather than growing
    memory for as long as the process runs. A run still never waits on a sink: when a
    sink's queue is full its stalest event is dropped rather than the run delayed — but
    only once the sink has been given a turn to catch up, so a sink that is keeping up
    loses nothing however fast the run produces events. Dropped events and failed
    emits are counted per sink and reported in the logs — never discarded silently, and
    never one stack trace per event — and a sink that raises five times in a row is
    disabled instead of being retried for the rest of the process's life. Two side
    effects worth knowing: each sink's emit is now called one event at a time in
    submission order and is never re-entered, and Runtime.drain() flushes the queues
    and stops the workers. Sinks remain a lossy tap by design; a consumer that must
    see every event reads the event store, which is the complete copy.

Removed

  • EventStorePort.list_log_keys (not yet part of any stable public API), along
    with the log-by-log pending scan that was its only caller. list_runs answers
    the same question without enumerating logs first.

Fixed

  • Duplicate-resume protection now holds between processes, not just between tasks
    in one process. Two servers (or a server and a second tool) sharing one SQLite
    event store can answer the same interrupt at the same instant and exactly one of
    them resumes the run; the other is a clean no-op, not an error. Previously the
    guard was a process-local lock, so each process could claim the same waiting run
    — running the workflow's next node twice and writing two run.resumed events
    with the same seq. A claim that was slow enough to miss a whole
    interrupt-resume-interrupt round of its run now loses too, instead of answering
    the run's second question with the first one's value.
  • The OpenAI Agents engine no longer runs the SDK's default trace exporter on
    keyless/fake-model runs (tests, CI, the M0 demo): it now passes a RunConfig
    with tracing disabled unless AGENTDECK_OPENAI_AGENTS_TRACING_ENABLED=true is
    set, so a bare checkout no longer logs a non-fatal Tracing client error 401
    or attempts an unsanctioned outbound HTTPS call.