v2026.07.30
Highlights
Durable Turn Lifecycle and Multi-Worker Runs
Turn state previously lived in process memory and a Redis status blob. Nothing about an in-flight turn outlived the process that started it, and status readers reconstructed state by inference. This release moves that state into Postgres: each run is a row, terminal status is written exactly once through a guarded compare-and-swap, and status, reconnect, admission, and cancel all read the same ledger. The subagent and report-back paths were rebuilt on top of it.
- Report-back is transactional. A job dispatched from Flash to the sandboxed worker, or a background subagent launch, enqueues its completion notification in the same transaction that writes the run's terminal status. Any process can drain that queue, so a restart between "job finished" and "result delivered" no longer strands the result — the previous delivery loop was an in-process task with no boot-time recovery, and a completed job resumed only when a client polled the status endpoint. Delivery is exactly-once by database constraint rather than by an optimistic Redis claim that failed open, and notifications into the same thread are serialized by an ordering key. Background subagents that finish after their parent turn has ended are announced through the same path; previously no mechanism existed for that case and the result waited until something asked for it.
- Subagent status is derived from the run ledger. Task cards previously inferred completion from socket close, so a backgrounded tab or a dropped connection marked a running task Completed; replayed history without status metadata defaulted to completed, and cancelled tasks kept a streaming spinner. Status now comes from the run record — tasks report Stopped or Failed with the reason, and completion is only ever reported positively. A uniqueness constraint on the launching tool call makes a checkpoint replay of the same task a no-op instead of a second spawn.
- One multiplexed stream per thread. Subagent lanes previously opened a connection per task with no cursor, so a reconnect could not resume and replay duplicated content. Threads now stream over a single connection with run-scoped lanes and in-band sequence cursors; the client deduplicates against a per-run high-water mark, and a cursor gap raises a resync rather than continuing across a silent hole.
- Cancellation is durable intent. Stop previously set a Redis flag, marked the thread cancelled immediately regardless of whether work stopped, and signalled only the local process. It is now recorded on the run row and honored by the finalize path, so the state changes when the run actually settles and the intent survives a crash. The stop drain timeout moved from 1.5s to 4s so a subagent's archive is captured before teardown.
- Orphaned runs are recovered. A scanner finds
in_progressruns whose owner is provably gone, classifies them as cancelled, interrupted, or worker-lost, salvages the run's buffered events into the archive, and finalizes them through the same funnel. Previously a hard crash left the Redis status blob reading active indefinitely and no run row was written at all. - Submission is idempotent. Each send carries a client-generated request key, so a retransmitted submission adopts the existing run instead of creating a duplicate turn. Separately, the workflow timeout moved from 3200s to six hours, aligning the graceful timeout with the abandoned-run reaper.
The Redis transport was reworked alongside this. The per-event write drops from a seven-command transaction to a single XADD carrying an explicit entry id that doubles as the write's idempotency fence, which is what makes retry safe: a failure is classified by what the server could have seen, so pool exhaustion replays identically while an ambiguous timeout probes the stream tail and accepts only a byte-identical payload. Previously a single socket timeout on one event raised a transport error that terminated the turn with no retry. Connection pools are now split by lifetime — short cache operations, long blocking reads, and pub/sub — and the per-viewer wake subscription collapses to one pattern subscription per process, so connection demand no longer scales with open tabs. These properties are what make running a thread's work across multiple backend processes safe.
Provider-Scoped Reasoning Payloads
Reasoning blocks are opaque and signed by the provider that produced them. Any mid-thread model change — a manual switch, a retry with a model override, or an automatic fallback after the primary provider returned an error — replayed one provider's reasoning to another, which rejected the request with a 400. That status is classified non-retryable, so the turn exhausted every fallback candidate and re-raised, and the rejected block remained in the thread's checkpoint, causing subsequent turns to fail identically.
The automatic fallback path required no user action. An upstream error was enough to route a turn to a fallback model whose Anthropic-compatible endpoint made its reasoning indistinguishable from the primary's at the client-library level, since the library stamps the same provider name for every Anthropic-shaped route.
Each client is now stamped with the provider route it actually reaches, and routes are grouped into lineages — sets that can verify each other's signatures — declared explicitly in the provider manifest rather than inferred from names, with unrelated routes defaulting to their own lineage. A request gate strips reasoning whose origin lineage does not match the target's, and strips when provenance is ambiguous. Because the filter runs against the outgoing request rather than stored state, threads already carrying a rejected block recover on their next message with no user action. The resilience middleware adds a backstop: a candidate that returns a 400 on a request that carried reasoning gets one retry with reasoning stripped, instead of the failure cascading through the remaining candidates.
Claude Opus 5
Adds claude-opus-5 to the model manifest: 1M-token context, 128k max output tokens, adaptive thinking with summarized display, and text, image, and PDF input. Two entries ship — one for API-key access and one for Claude subscription (OAuth) access. The three Opus 4.8 keys remain visible and unchanged.
Changelog
New Features
- llms: add Claude Opus 5 (#332) (a3335a9)
- adopt Daytona provider-managed Secrets for sandbox egress credential injection (#330) (3f4cbf6)
- durable turn lifecycle — multi-worker runs, subagent run ledger, v2 stream mux (#328) (7997455)
Bug Fixes
- keep reasoning payloads inside the provider that produced them (#336) (11eef61)
- canonicalize the sandbox state so the settings panel stops hiding live tabs (#337) (b1be7ec)
- web: drop black page frame from PDF export (#334) (8f408a0)
- storage: canonical Content-Type resolution across upload and serve (#329) (cd83908)
Performance
Documentation
- point README hosted-product links at langalpha.ai (d4db87c)
Maintenance
- config: raise workflow timeout to 6 hours (eecdeb3)
Full Changelog: v2026.07.22...v2026.07.30
3 features, 4 fixes, 1 performance improvement, 1 doc change, 1 maintenance change — 10 changes total