Skip to main content

createQuestionService

@forge/monorepo


@forge/monorepo / backend/src / createQuestionService

Function: createQuestionService()

createQuestionService(deps): object

Defined in: backend/src/hitl/service.ts:61

Parameters

deps

clock?

Clock

dispatcher

JobDispatcher

idFactory?

IdFactory

interactions

InteractionStore

runs?

RunStore

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

RunId

tenantId

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

ExecutionContext

runId

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

RunId

tenantId

TenantId

Returns

Promise<PendingQuestion | null>