UNPKG

@adonis-agora/agent

Version:

Governed, durable-backed AI agent (chat + tool-calling + governance) for AdonisJS — part of the Agora ecosystem.

82 lines • 3.45 kB
import { validateElicitationAnswer } from '../elicitation-input.js'; /** An OpenCode form field as a stream-protocol question (`elicitation`, *Asking the user*). */ export function toQuestion(field) { const required = field.required === true ? { required: true } : {}; const base = { id: field.key, prompt: field.title || field.key, ...(field.description && field.description !== field.title ? { description: field.description } : {}), }; if (field.options !== undefined && field.options.length > 0) { return { ...base, options: field.options.map((option) => ({ value: String(option.value), label: String(option.label ?? option.value), })), input: { type: 'select', ...required }, ...(field.type === 'array' ? { multiple: true } : {}), ...(field.custom === true ? { allowFreeText: true } : {}), }; } const type = field.type === 'number' || field.type === 'integer' ? 'number' : field.type === 'boolean' ? 'boolean' : 'text'; return { ...base, input: { type, ...required } }; } /** The fields of a form, skipping anything that is not one. */ export function formFields(form) { return (form.fields ?? []).filter((field) => typeof field === 'object' && field !== null && typeof field.key === 'string'); } /** The elicitation an OpenCode form streams as, under `id` (the tool-call id it is answered through). */ export function toElicitation(id, form) { const questions = formFields(form).map(toQuestion); const first = questions[0]; // OpenCode titles a one-question form after the question (or just "Questions"): not a preamble. const title = form.title; const preamble = title && title !== 'Questions' && title !== first?.prompt && title !== first?.description ? title : undefined; return { id, source: 'ask', ...(preamble ? { preamble } : {}), questions }; } /** An answer a form field cannot take. */ export class FormAnswerError extends Error { constructor(message) { super(message); this.name = 'FormAnswerError'; } } /** * The protocol's answers (question id → canonical strings) as OpenCode's form reply: numbers as * numbers, booleans as booleans, multiple choice as a list. Questions left out take their defaults; * a value a question can't take throws {@link FormAnswerError}. */ export function toFormAnswer(form, answers = {}) { const out = {}; for (const field of formFields(form)) { const question = toQuestion(field); const values = answers[field.key] ?? question.defaults ?? []; const problem = validateElicitationAnswer(question, values); if (problem !== null) { throw new FormAnswerError(`answers["${field.key}"] ${problem}`); } const present = values.filter((value) => value !== ''); const [value] = present; if (value === undefined) continue; if (question.multiple === true) out[field.key] = present; else if (question.input?.type === 'number') out[field.key] = Number(value); else if (question.input?.type === 'boolean') out[field.key] = value === 'true'; else out[field.key] = value; } return out; } //# sourceMappingURL=forms.js.map