symfonic.platform.continuation¶
continuation ¶
Resuming a paused turn, as contracts (task-1-3-1).
A turn can stop to ask a person. The kernel already treats that as a terminal
rather than an error -- InvocationPaused carries a PendingInterrupt and
InvocationRunner.events turns it into the run's last event, deliberately
not an error and not followed by done, because a pause reported as a
failure tells an adopter's error handling the turn broke, and one reported as
done hands a consumer a result the run never produced.
What is missing is the other half. symfonic.Agent exposes run,
stream and close; there is no way to continue what a pause stopped. So
a paused turn on the migrated route is created and unresumable, and the
only working resume is the compatibility facade's -- which takes a scope per
call, and cannot be what a scaffold uses if the scaffold is to stop naming that
facade.
The stores already exist and are public. SessionService,
CheckpointService, TranscriptService and their ports are all declared
in :mod:symfonic.services.conversation. Nothing here re-declares them; what
these contracts add is the seam that resumes a turn through the host, which
is where the scope and the agent already live.
Where the scope comes from is the whole design. The facade's resume
takes one per call. That cannot be copied here: the published facade decision
forbids per-turn scope on Agent, and a host that took a scope on resume
would have two answers to "which tenant is this" -- the one the token was
issued under and the one the caller passed. A pause token is issued inside a
scope, so the scope is recoverable from the token and the caller states only
the token. A caller who could name a different one could resume another
tenant's paused turn by holding its token.
ContinuationService ¶
Bases: Protocol
Resumes what a pause stopped, over the host's own agents and stores.
Deliberately not a method on Agent. An agent is bound to one scope and
does not know which of its turns are outstanding; resuming needs a token
to be looked up, a scope to be recovered from it, and the agent for that
scope to be found -- three things the host has and an agent does not.
resume
async
¶
Continue the paused turn with answer and return its result.
Idempotency is the contract's hardest clause and it belongs here rather than in a transport: a person answering twice, or a client retrying, must not run the rest of the turn twice. An implementation either completes once and replays the result, or refuses the second attempt by name -- and it must say which, because "the answer was accepted" and "the answer was accepted again" look identical to a caller otherwise. The supported human adapter chooses at most once: it prepares the scoped agent before redemption, then rejects a second use after the durable claim; it does not replay effects if the resumed invocation itself later fails.
Raises:
| Type | Description |
|---|---|
UnknownPauseToken
|
if the token names no resumable turn. |
Source code in src/symfonic/platform/continuation.py
ticket
async
¶
The paused turn token names.
Raises:
| Type | Description |
|---|---|
UnknownPauseToken
|
if it names none, or has expired. |
ContinuationUnavailable ¶
Bases: RuntimeError
Raised when a host was not composed with durable continuation wiring.
PauseTicket ¶
Bases: Protocol
What a paused turn hands back, and what resuming it needs.
The token is the whole of the caller's half. Everything else on this protocol is recovered from it rather than supplied: the scope the pause was issued under, the session it belongs to, and what the turn was waiting for. A caller that supplied any of them could contradict the token, and the contradiction would have to be resolved by trusting one of them.
question
property
¶
What the turn stopped to ask. Shaped by whoever registered the pause point; the platform does not interpret it.
UnknownPauseToken ¶
Bases: LookupError
Raised when a token names no resumable turn.
A distinct type because the caller's correct response differs and cannot be derived from a message: an expired token is an ordinary outcome a transport turns into a 404 or a "this conversation moved on", while a malformed one is a bug in whoever minted it. Both are refusals, and only one is worth waking somebody for.