createQuestionService
@forge/monorepo / backend/src / createQuestionService
Function: createQuestionService()
createQuestionService(
deps):object
Defined in: backend/src/hitl/service.ts:61
Parameters
deps
clock?
Clock
dispatcher
idFactory?
IdFactory
interactions
runs?
The run store, so answering can put the run back to queued (#144).
Optional only so an existing caller keeps compiling; without it the resume enqueues a run the worker cannot
claim, and the run waits forever. See resumeRun below.
Returns
answer()
answer(
input):Promise<{resumed:boolean; }>
Record answers and queue the continuation — exactly once. A second answer to the same interaction is a no-op and does NOT re-enqueue, so the run never resumes twice.
Parameters
input
TenantScopeInput & object
Returns
Promise<{ resumed: boolean; }>
answered()
answered(
input):Promise<PendingQuestion|null>
The answer a resumed run has to tell the model about — #163.
Returns null when nothing was asked, or when the answer was already part of an earlier turn's history:
both mean "say nothing new". The engine calls this on resume, the way it calls approvals.resume.
Parameters
input
runId
tenantId
Returns
Promise<PendingQuestion | null>
ask()
ask(
context,runId,questions):Promise<PendingQuestion>
Persist a pending question. The run is paused into waiting-for-question by the worker.
That last sentence was aspirational until #163: the worker does pause on a question.requested event,
but nothing emitted one, so a tool that called ask had its question stored and the run ran on to
completion. See questionPending below for the signal that closes the loop.
Parameters
context
runId
questions
readonly QuestionSpec[]
Returns
Promise<PendingQuestion>
pending()
pending(
input):Promise<PendingQuestion|null>
The question a run is parked on, or null — the read side of answer (#163).
The service had ask and answer and no way to look at what was asked, so the only client that could
render a picker was one that had also raised the question and kept it in memory. A worker raises it and a
browser renders it, which are different processes; the browser had the interaction id from the event and
nothing else, and drew an empty text box.
Parameters
input
runId
tenantId
Returns
Promise<PendingQuestion | null>