feat: split session_timeout into access_timeout + completion_timeout#21
Open
synacktraa wants to merge 9 commits into
Open
feat: split session_timeout into access_timeout + completion_timeout#21synacktraa wants to merge 9 commits into
synacktraa wants to merge 9 commits into
Conversation
The single session_timeout knob conflated orphan defense (operator
never connects) with the human's work budget (operator connected
but is taking too long). With one number both jobs share, late
clicks silently shrink the work window — invisible to the
operator.
Replace with two timers, each at both ServerConfig (house default)
and per-call (override) layers:
access_timeout — start of wait → first WS connect.
Defends against orphaned sessions.
completion_timeout — first WS connect → detection match.
Bounds work time.
None per-call inherits from ServerConfig; None on ServerConfig
means truly no timeout. Defaults: 600s access, 1800s completion.
In handoff.py, the single asyncio.wait_for becomes a three-way
race (_await_timeout_cause) between detection-match, access
deadline, and completion deadline. Returns the cause name
("access" / "completion") or None for a clean match — fed
directly into HandoffResult.timeout_cause for diagnostics.
Lazy listener install (substrate-URL leak defense) moves to a
side task armed on first connect; the race itself starts
immediately so access_timeout begins counting from the call,
not from connect.
Handoff.run(timeout=...) renamed to trigger_timeout=...; the new
access_timeout / completion_timeout kwargs are forwarded into
wait_for_completion on match.
WS upgrade rejects late operator clicks with 1008
access_timeout_expired once the access timer fires; the wrapper
handles that close code → expired card.
session_state WS message gains completion_deadline_ms (epoch
millis) anchored on first accept, reused across reconnects so
the wrapper countdown is reconnect-safe.
Breaking: ServerConfig.session_timeout and the deprecated
ServerConfig.completion_timeout alias are removed. Anyone still
passing them gets TypeError from the dataclass at construction.
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
Renders the remaining completion_timeout in the toolbar against the absolute completion_deadline_ms from the session_state WS message. Switches to a warning style under 60s; hides when no deadline is set; reconnect-safe because the deadline is absolute. Handles the new WS close code (1008 access_timeout_expired) by rendering the expired card on load — the operator clicked past the access window. Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
Same countdown + expired-card handling as the screencast template, ported to the passthrough proxy wrapper. Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
Update the How-it-works and ServerConfig snippets to the new access_timeout / completion_timeout names. trigger_timeout replaces timeout on Handoff.run. Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
…opping/local.py Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
…opping/using_kernel.py Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
…off/in_daytona.py Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
Rename timeout to trigger_timeout, and rewire the error message to read result.timeout_cause instead of the removed handoff.server.completion_timeout. Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
examples/**/temp* — local scratch test scripts that shouldn't land in the repo. Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Why
One
session_timeoutknob did two unrelated jobs — orphan defense (operator never connects) and human work budget (operator connected but slow). Late clicks silently shrank the work window. Operators couldn't tell whether they ran out of time because nobody clicked or because the human took too long.What changes
ServerConfigand per-call kwargs each gainaccess_timeout(start → first WS connect) andcompletion_timeout(first connect → detection match).Noneper-call inherits fromServerConfig;NoneonServerConfigmeans truly no timeout.Handoff.wait_for_completionresolves the two timers and races detection-match against both deadlines via_await_timeout_cause, returning the cause name orNonefor a clean match.Handoff.rungainstrigger_timeout(rename oftimeout) plus the two new kwargs, which forward intowait_for_completionon match.HandoffResult.timeout_cause: Literal["access", "completion"] | Nonetells callers which timer fired (or that detection matched cleanly).1008reasonaccess_timeout_expired; the wrapper renders the expired card on that close code.completion_deadline_ms-driven countdown pill, switching to a warning style under 60s. The deadline is anchored once on first connect so the countdown is reconnect-safe.Defaults
ServerConfig.access_timeout = 600.0(10 min)ServerConfig.completion_timeout = 1800.0(30 min)Handoff.run(trigger_timeout=30.0)unchanged from the priortimeout=.Breaking
ServerConfig.session_timeoutremoved.ServerConfig.completion_timeout(previously a deprecated alias) reclaimed with new semantics — per-call work budget, not total lifetime.Handoff.run(timeout=...)removed; passtrigger_timeout=....TypeErrorat construction.