Interface: IHumanGate
Defined in: internal/human-gate/types.ts:41
Pause and resume mechanics for runs.
Implemented by HumanGate; the type of IAIGatewayDeps.humanGate, so a host may pass its own in overrides.
Methods
assertResumable()
assertResumable(
args):void
Defined in: internal/human-gate/types.ts:116
assertResumable -- the checks of resume on a run already loaded, without I/O
About
Refuse early what
resumewould refuse anyway.
Throws what resume throws for a run that cannot take these decisions: 409 when the run is not paused or pauseId names
another pause of it, 410 when the pause
has expired, 400 when the decisions do not answer the pause — every envelope needs exactly one decision, named by the
envelope's callId (a single-envelope pause takes one decision without it), with an action among that envelope's allowed.
Returns nothing when the decisions may go through; matchDecisions gives the pairs.
AIGateway.resume calls it first, so a resume that is doomed pays no judge call for the answer screen (D71) and no
repository reads; resume calls it again on the run it reloads, right before the atomic transition.
Pitfalls
It does not reserve anything: another caller can still win the transition in resume.
Parameters
args
decisions
pauseId
string
run
Returns
void
cancel()
cancel(
args):Promise<void>
Defined in: internal/human-gate/types.ts:174
cancel -- closes a paused run the user gave up on
About
PAUSED to CANCELLED, atomically; a run that is not paused is a 409.
Who needs it
AIGateway.cancelRun, before closeRun rejects the pending tool calls.
Parameters
args
runId
string
tenantId
string
Returns
Promise<void>
expirePaused()
expirePaused(
args):Promise<IRun[]>
Defined in: internal/human-gate/types.ts:199
expirePaused -- cancels the pauses nobody answered in time
About
Every paused run of the tenant whose
expiresAthas passed becomes CANCELLED; the cancelled runs come back, with the envelopes of their pause.
A PAUSED run without an envelope counts as due too (D80): nothing can resume it (assertResumable is a 409 without a
pending envelope), so it would hold its thread for ever; the job is the only way out of that state. The envelopes of one
pause share their expiresAt, so the first one speaks for all.
Each run leaves PAUSED through the atomic transition (D69), so a resume racing with the job loses cleanly.
The gate only moves the runs: closing their tool calls in the thread and reopening the thread is the gateway's
part (AIGateway.expirePausedRuns), which needs the runs, hence the return value (D75). The transition clears pending,
so each returned run carries the envelopes of its pause again: the gateway closes every call with its own rejection text (D87).
Who needs it
AIGateway.expirePausedRuns, called by a scheduled job of the application.
Parameters
args
tenantId
string
Returns
Promise<IRun[]>
listPaused()
listPaused(
args):Promise<IRun[]>
Defined in: internal/human-gate/types.ts:158
listPaused -- the paused runs of a tenant
About
The inbox, as the store has it.
RunStore.listPaused: the tenant's PAUSED runs, one user's when userId is given.
Who needs it
AIGateway.listPausedRuns, which strips the reviewer's draft before the asker sees the list (D111).
Parameters
args
tenantId
string
userId?
string
Returns
Promise<IRun[]>
matchDecisions()
matchDecisions(
args):object[]
Defined in: internal/human-gate/types.ts:138
matchDecisions -- pairs every decision of a resume with the envelope it answers
About
Which card does this answer belong to.
The pairs in the order of the envelopes. Throws what assertResumable throws: 409 when the run is not paused or pauseId
is not the pause it waits on (a decision meant for an earlier pause of the same run), 410 when
the pause has expired, 400 when a decision names no envelope of the pause (callId), an envelope gets no decision or
two, or an action is not among its envelope's allowed. A pause of one envelope takes a single decision without callId.
Who needs it
assertResumable, and AIGateway.resume to read each decision next to its envelope (the answer screen, the rejection texts).
Parameters
args
decisions
pauseId
string
The pause the decisions are for (envelope.pauseId).
run
Returns
object[]
pause()
pause(
args):Promise<TPauseEnvelope[]>
Defined in: internal/human-gate/types.ts:59
pause -- stores the run as PAUSED with the cards of its pause
About
The run stops here; these are the cards the UI shows.
Stamps every draft with the run's id, one fresh pauseId and one expiresAt (now + timeoutMs), saves the run as
PAUSED with them as pending and returns them. One envelope per tool call of the step that waits for a human (D102),
or the one envelope of a result review (D99). An empty list is a 500 (error 5376634521017): a pause without a card
could never be answered.
Who needs it
settleRun, when the loop stopped on tool calls that need a human; settleReviewPause, when the answer waits for a
reviewer.
Parameters
args
envelopes
(Omit<IToolApprovalEnvelope, "runId" | "pauseId" | "expiresAt"> | Omit<IResultReviewEnvelope, "runId" | "pauseId" | "expiresAt"> | Omit<IUserQuestionEnvelope, "runId" | "pauseId" | "expiresAt">)[]
run
tenantId
string
Returns
Promise<TPauseEnvelope[]>
resume()
resume(
args):Promise<IRun>
Defined in: internal/human-gate/types.ts:88
resume -- lets the decisions through and marks the run RUNNING
About
One pause, one answer: a decision per envelope, and the first caller wins, every other one is refused.
Validates the decisions (assertResumable), then moves the run PAUSED to RUNNING in one atomic step (D69) and returns it.
The LLMClient applies the decisions (run.resume).
- 409 when the run is not paused, when
pauseIdis not the pause the run waits on, or another caller resumed or cancelled it first. - 410 when the pause has expired.
- 400 when a decision names no envelope, an envelope gets no decision or two, or an action is not allowed on its envelope.
Who needs it
AIGateway.resume, after the profile, tool and answer checks, before the LLMClient continues the run.
Pitfalls
Two resumes at once (a double click, two tabs) reach this method together; the atomic transition admits one, so a side-effect tool never runs twice for one approval.
Parameters
args
decisions
pauseId
string
The pause the decisions are for (envelope.pauseId).
runId
string
tenantId
string
Returns
Promise<IRun>