workflows/interview¶
Source: src/workflows/interview.ts
interview: a conversation with the user, ending in a brief.
Every other combinator here composes agents. This one puts a human in the loop: an agent asks one question at a time through the {@link AskUser} port, and turns the answers into the specification the rest of the pipeline works from.
Why one question at a time rather than a form: a good second question depends on the first answer. A form has to guess all of them up front, and guesses wrong the moment the first answer surprises it.
interview¶
function
export async function interview(options: InterviewOptions): Promise<InterviewResult> { /* … */ }
Interviews the user, then asks the agent to write the brief.
The lifetime defaults to "workflow", and that is not an arbitrary choice: an
interview is a conversation. A "task" interviewer would forget the answer
it just received and ask around it forever.
The interview ends when the agent says {@link READY}, when the user submits
(ask returns undefined), or at maxQuestions - and in all three cases the
agent still writes a brief from what it has. Stopping early is a legitimate
outcome, not a failure: a brief written from two answers is worth more than
an interrogation nobody finished.
InterviewOptions¶
type
export type InterviewOptions = WorkflowOptions & {
/** The agent conducting the interview. */
agent: Agent;
/** What the user asked for, in their own words. */
input: string;
/** How questions reach the user. See {@link AskUser}. */
ask: AskUser;
/**
* Hard cap on questions. Defaults to 6.
*
* The same reasoning as `loop`'s `maxIterations`, with a human on the other
* end: an agent that keeps finding one more thing to clarify is the normal
* failure mode, and being interrogated forever is worse than a slightly
* under-specified brief.
*/
maxQuestions?: number;
/** Overrides how a question is read. See {@link parseQuestion}. */
parse?: (output: string) => Question | undefined;
};
Who asks, what about, how it reaches the user, and when it must stop.
InterviewResult¶
type
export type InterviewResult = WorkflowResult & {
/** The consolidated specification - `output`, under the name the rest of the pipeline reads. */
brief: string;
/** Everything the user answered, in order. */
answers: Answer[];
/** True when the user submitted before the agent said it was done. */
submitted: boolean;
};
The brief, and everything that led to it.
As a Result: the interviewer’s last turn, whose output is the brief.
usage covers every turn, the brief included; ok says every turn ran, and
a short brief can still be true.
parseQuestion¶
function
export function parseQuestion(output: string): Question | undefined { /* … */ }
Reads one question out of whatever the agent actually wrote.
Same decision as parsePlan, for the same reason: the input is a language
model, so this is lenient about shape - fenced, wrapped in prose, an array
with one object in it - and strict about content. No question string, or no
usable option, means no question: the caller moves on to the brief rather
than putting a malformed card in front of the user.
READY¶
const
export const READY = "READY";
The agent says this - alone - when it has enough to write the brief.