feat(service): report and bound approvals on service turns - #1113
Merged
Conversation
A turn stopped at a tool approval was indistinguishable from a slow turn: the result reported only that no reply was ready. The caller had no way to learn that progress depended on a person it could not reach, and polled a session that would not move until someone acted. Report the wait instead — which tool, what it would do, how long it has been pending — and let a service bound it. When the bound elapses the call is denied on the caller's behalf, the turn resumes, and the reply says the action was refused rather than continuing to look unfinished. The bound defaults to waiting indefinitely, so an operator who has not asked for a deadline stays the only one who can decide, and automatic approval is never offered. Pending state is derived from the transcript: a request is pending exactly while it is the last thing of consequence, since resolutions are not recorded and the turn appends past the request once answered.
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.
The problem
A service turn stopped at a tool approval looks exactly like a slow turn from outside — the result reports only
ready: false. The caller cannot learn that progress now depends on a human it has no way to reach, so it polls a session that will not move.Observed on a live daemon: a request that triggered a file write parked on approval and stayed
runningindefinitely, with nothing in the response explaining why.The change
Report the wait, and let a service bound it.
{ "ready": false, "status": "running", "approval": { "outcome": "awaiting_operator", "tool": "edit_file", "summary": "1 edit in hello.txt: create `hi`", "waited_seconds": 5 } }With
approval_timeout_secsset, an unanswered call is denied on the caller's behalf when the bound elapses; the turn resumes and the reply says the action was refused rather than continuing to look unfinished.The bound defaults to
0(wait forever). Denying by default would refuse work an operator would have approved. Automatic approval is never offered — the party who would benefit is the party who cannot be trusted to ask for it.Pending state is derived from the transcript rather than tracked separately: a request is pending exactly while it is the last thing of consequence, since resolutions are never recorded and the turn appends past the request once answered. No second source of truth, and it survives daemon restart for free.
Verification
Live daemon,
approval_timeout_secs = 45, request triggering a gated write:Tests: 4 new (trailing request is pending; an answered one is not; no-approval turns; the timeout default and its override).
construct-daemon --lib489,construct-cli --bins1314, workspace builds clean.Spec:
0171-service-approvals-are-visible-and-bounded. Follows #1111 — rebased onto it, so this diff is additive only.Touches
crates/daemon→ the relevant binary isconstruct.