Questions and approvals — core API
Generated reference for @aparte/core. Asking the person a question, or for an approval, in the middle of a turn.
On this page
Classes
Section titled “Classes”AparteElicitationAbortError
Section titled “AparteElicitationAbortError”Defined in: packages/core/src/elicitation/types.ts:251
The request ended without an answer: the turn was stopped, the signal fired, the question was taken away by another request, or nothing was mounted to ask it.
A THROW, and not a third member of AparteElicitationResult. cancel was a
VALUE, so it was easy to handle as though it were an answer — and that is exactly
what happened: the approval gate treated it as a refusal, stamped the segment
rejected, and told the model “Tool execution was rejected by the user.” The user
had pressed Stop. A rejection cannot be mistaken for a decision by a caller that
forgot a branch, which is the property cancel never had.
name is 'AbortError', so every err.name === 'AbortError' check already written
treats it correctly — including askUserHandler, which used to perform this exact
conversion by hand. That hand-conversion existing is the evidence the shape is
right, and it is gone.
Extends
Section titled “Extends”DOMException
Constructors
Section titled “Constructors”Constructor
Section titled “Constructor”new AparteElicitationAbortError(reason?): AparteElicitationAbortError;Defined in: packages/core/src/elicitation/types.ts:261
Parameters
Section titled “Parameters”| Parameter | Type | Default value |
|---|---|---|
reason | "aborted" | "no-presenter" | 'aborted' |
Returns
Section titled “Returns”Overrides
Section titled “Overrides”DOMException.constructorProperties
Section titled “Properties”reason
Section titled “reason”readonly reason: "aborted" | "no-presenter";Defined in: packages/core/src/elicitation/types.ts:259
Which of the two ways it ended.
'no-presenter' is a developer’s setup problem and 'aborted' is a person
stopping something; a host that reports them the same way reports a bug as a
user action. The distinction is why this carries a field at all.
Functions
Section titled “Functions”buildApprovalPanel()
Section titled “buildApprovalPanel()”function buildApprovalPanel(
message,
options,
onChange,
details?): BuiltApprovalPanel;Defined in: packages/core/src/elicitation/approval-panel.ts:59
Parameters
Section titled “Parameters”| Parameter | Type |
|---|---|
message | string | (() => string) |
options | readonly AparteApprovalOption[] |
onChange | () => void |
details? | string |
Returns
Section titled “Returns”requestUserInput()
Section titled “requestUserInput()”function requestUserInput(request): Promise<AparteElicitationResult>;Defined in: packages/core/src/elicitation/index.ts:42
Ask the user for typed input and await their response, on the config
governing request.target (its instance config, or the global default).
Resolves accept / decline / cancel.
Parameters
Section titled “Parameters”| Parameter | Type |
|---|---|
request | AparteElicitationRequest |
Returns
Section titled “Returns”Promise<AparteElicitationResult>
buildElicitationPanel()
Section titled “buildElicitationPanel()”function buildElicitationPanel(
message,
schema,
onChange): BuiltElicitationPanel;Defined in: packages/core/src/elicitation/panel.ts:590
Parameters
Section titled “Parameters”| Parameter | Type |
|---|---|
message | string | (() => string) |
schema | AparteElicitationSchema |
onChange | () => void |
Returns
Section titled “Returns”Interfaces
Section titled “Interfaces”BuiltApprovalPanel
Section titled “BuiltApprovalPanel”Defined in: packages/core/src/elicitation/approval-panel.ts:31
What the presenter drives. A superset of the question panel’s useful half.
Properties
Section titled “Properties”readonly el: HTMLElement;Defined in: packages/core/src/elicitation/approval-panel.ts:32
dismiss
Section titled “dismiss”readonly dismiss: HTMLElement;Defined in: packages/core/src/elicitation/approval-panel.ts:34
The corner escape — see BuiltElicitationPanel.dismiss for why a corner.
Methods
Section titled “Methods”onSettle()
Section titled “onSettle()”onSettle(cb): void;Defined in: packages/core/src/elicitation/approval-panel.ts:36
Settled from inside the panel: an option was clicked.
Parameters
Section titled “Parameters”| Parameter | Type |
|---|---|
cb | (answer) => void |
Returns
Section titled “Returns”void
getContent()
Section titled “getContent()”getContent(): AparteApprovalAnswer;Defined in: packages/core/src/elicitation/approval-panel.ts:38
The instruction typed so far, for the composer’s submit path.
Returns
Section titled “Returns”isComplete()
Section titled “isComplete()”isComplete(): boolean;Defined in: packages/core/src/elicitation/approval-panel.ts:40
True once there is an instruction worth sending.
Returns
Section titled “Returns”boolean
focus()
Section titled “focus()”focus(): void;Defined in: packages/core/src/elicitation/approval-panel.ts:41
Returns
Section titled “Returns”void
relabel()
Section titled “relabel()”relabel(): void;Defined in: packages/core/src/elicitation/approval-panel.ts:43
Re-apply every string taken from the locale, in place.
Returns
Section titled “Returns”void
BuiltElicitationPanel
Section titled “BuiltElicitationPanel”Defined in: packages/core/src/elicitation/panel.ts:25
Properties
Section titled “Properties”readonly el: HTMLElement;Defined in: packages/core/src/elicitation/panel.ts:26
dismiss
Section titled “dismiss”readonly dismiss: HTMLElement;Defined in: packages/core/src/elicitation/panel.ts:43
The corner where the presenter puts its escape from the WHOLE request.
Top-right, away from anything that answers a question — and the position is the
whole point. This affordance lived in a row at the bottom, beside the button
that advances through the form, and adjacency made a promise the behaviour does
not keep: next to “next question”, “Skip” reads as “skip THIS question”, while
it declines everything (MCP’s decline, including questions already answered).
That is also why the reference implementations put theirs in a corner, which I had read as a preference for the glyph. It is not about the glyph.
A row at the bottom is gone with it, and so is the reserved height it needed: with the composer’s own button carrying advance-then-submit, the panel has no action of its own left to place.
Methods
Section titled “Methods”getContent()
Section titled “getContent()”getContent(): unknown;Defined in: packages/core/src/elicitation/panel.ts:45
The current response content, shaped to match the schema.
Returns
Section titled “Returns”unknown
isComplete()
Section titled “isComplete()”isComplete(): boolean;Defined in: packages/core/src/elicitation/panel.ts:47
True when every required field has a usable value.
Returns
Section titled “Returns”boolean
focus()
Section titled “focus()”focus(): void;Defined in: packages/core/src/elicitation/panel.ts:49
Focus the first input (called after mount).
Returns
Section titled “Returns”void
mode()
Section titled “mode()”mode(): "none" | "submit";Defined in: packages/core/src/elicitation/panel.ts:69
What the composer’s one button means for this panel: 'submit', or 'none'
when the panel has no act for it and it should not be drawn.
It used to have a third value, 'advance', while a form had more questions
ahead: the button turned into a chevron and moved to the next question. That
was a second way to do what a chip already does — the chips ARE the navigation,
forwards and back — and a button that changes meaning under the pointer is one
more thing to explain. The reference products settle it the same way: a click
on a choice selects, a tab switches question, one button submits the lot. So
the button means submit throughout, enabled once every question has an answer,
which is what canProceed() reports.
'none' is for the shape where the button has no meaning at all: a single
question whose options settle on the click. Assignable to the composer’s
AparteComposerPanelMode and deliberately spelled out rather than imported —
this layer describes what the PANEL has, and knows nothing about the element
that presents it.
Returns
Section titled “Returns”"none" | "submit"
canProceed()
Section titled “canProceed()”canProceed(): boolean;Defined in: packages/core/src/elicitation/panel.ts:71
Whether that button is enabled: every required question answered.
Returns
Section titled “Returns”boolean
proceed()
Section titled “proceed()”proceed(): void;Defined in: packages/core/src/elicitation/panel.ts:73
Kept for the presenter’s contract; a form does nothing here — submitting is the presenter’s.
Returns
Section titled “Returns”void
onSettle()
Section titled “onSettle()”onSettle(cb): void;Defined in: packages/core/src/elicitation/panel.ts:87
Settled from INSIDE the panel: an option was clicked and that click is the
whole answer. The value is the content, shaped like getContent().
The same contract BuiltApprovalPanel.onSettle already has, and presented by
the same path — because it is the same act. A single-choice question is one
gesture, not a value you pick and then submit: WCAG’s SC 3.2.2 and its F36
failure are about auto-submitting a form when an INPUT is set, which is why
these options are buttons rather than radios that fire on change.
Only ever called for that shape. A form, a multi-select and a text field all collect a value and resolve through the composer’s button as before.
Parameters
Section titled “Parameters”| Parameter | Type |
|---|---|
cb | (content) => void |
Returns
Section titled “Returns”void
relabel()
Section titled “relabel()”relabel(): void;Defined in: packages/core/src/elicitation/panel.ts:100
Re-apply every string this panel took from the locale, in place.
Bound by the same rule as a segment renderer’s relabel: text and attributes
only, no node added or removed. A panel cannot be rebuilt on a language switch
— the reader may be halfway through typing an answer, or three questions into
a form — so the strings move and the DOM does not.
Only the DEFAULTS move. A label the app supplied (trueLabel, a field’s
title) is the app’s copy and is left alone, which is why the closures are
registered where the default is used rather than at the end.
Returns
Section titled “Returns”void
AparteElicitationEnumField
Section titled “AparteElicitationEnumField”Defined in: packages/core/src/elicitation/types.ts:11
A single choice field: radios (default) or checkboxes (multiple).
Properties
Section titled “Properties”type: "enum";Defined in: packages/core/src/elicitation/types.ts:12
title?
Section titled “title?”optional title?: string;Defined in: packages/core/src/elicitation/types.ts:13
header?
Section titled “header?”optional header?: string;Defined in: packages/core/src/elicitation/types.ts:22
A SHORT label for this question — two or three words, no sentence.
A multi-question form is presented one question at a time, with a chip per
question, and a chip cannot hold a sentence. title is the question as the
user reads it; header is how it is referred to. Omitted, the chip falls back
to the question’s position, which is honest and never truncates badly.
description?
Section titled “description?”optional description?: string;Defined in: packages/core/src/elicitation/types.ts:23
options
Section titled “options”options: {
value: string;
label?: string;
description?: string;
recommended?: boolean;
}[];Defined in: packages/core/src/elicitation/types.ts:24
value: string;label?
Section titled “label?”optional label?: string;description?
Section titled “description?”optional description?: string;recommended?
Section titled “recommended?”optional recommended?: boolean;multiple?
Section titled “multiple?”optional multiple?: boolean;Defined in: packages/core/src/elicitation/types.ts:26
Checkboxes (multi-select) instead of radios.
allowOther?
Section titled “allowOther?”optional allowOther?: boolean;Defined in: packages/core/src/elicitation/types.ts:28
Offer a free-text “Other…” fallback. Default true.
default?
Section titled “default?”optional default?: string | string[];Defined in: packages/core/src/elicitation/types.ts:30
Pre-selected value (or values, when multiple).
AparteElicitationBooleanField
Section titled “AparteElicitationBooleanField”Defined in: packages/core/src/elicitation/types.ts:34
A yes/no field, rendered as two choices.
Properties
Section titled “Properties”type: "boolean";Defined in: packages/core/src/elicitation/types.ts:35
title?
Section titled “title?”optional title?: string;Defined in: packages/core/src/elicitation/types.ts:36
header?
Section titled “header?”optional header?: string;Defined in: packages/core/src/elicitation/types.ts:45
A SHORT label for this question — two or three words, no sentence.
A multi-question form is presented one question at a time, with a chip per
question, and a chip cannot hold a sentence. title is the question as the
user reads it; header is how it is referred to. Omitted, the chip falls back
to the question’s position, which is honest and never truncates badly.
description?
Section titled “description?”optional description?: string;Defined in: packages/core/src/elicitation/types.ts:46
default?
Section titled “default?”optional default?: boolean;Defined in: packages/core/src/elicitation/types.ts:47
trueLabel?
Section titled “trueLabel?”optional trueLabel?: string;Defined in: packages/core/src/elicitation/types.ts:49
Labels for the two choices (fall back to the locale yes/no).
falseLabel?
Section titled “falseLabel?”optional falseLabel?: string;Defined in: packages/core/src/elicitation/types.ts:50
AparteElicitationStringField
Section titled “AparteElicitationStringField”Defined in: packages/core/src/elicitation/types.ts:54
A free-text field.
Properties
Section titled “Properties”type: "string";Defined in: packages/core/src/elicitation/types.ts:55
title?
Section titled “title?”optional title?: string;Defined in: packages/core/src/elicitation/types.ts:56
header?
Section titled “header?”optional header?: string;Defined in: packages/core/src/elicitation/types.ts:65
A SHORT label for this question — two or three words, no sentence.
A multi-question form is presented one question at a time, with a chip per
question, and a chip cannot hold a sentence. title is the question as the
user reads it; header is how it is referred to. Omitted, the chip falls back
to the question’s position, which is honest and never truncates badly.
description?
Section titled “description?”optional description?: string;Defined in: packages/core/src/elicitation/types.ts:66
placeholder?
Section titled “placeholder?”optional placeholder?: string;Defined in: packages/core/src/elicitation/types.ts:67
default?
Section titled “default?”optional default?: string;Defined in: packages/core/src/elicitation/types.ts:68
multiline?
Section titled “multiline?”optional multiline?: boolean;Defined in: packages/core/src/elicitation/types.ts:70
Render a multi-line textarea.
required?
Section titled “required?”optional required?: boolean;Defined in: packages/core/src/elicitation/types.ts:72
Required to accept. Default true.
minLength?
Section titled “minLength?”optional minLength?: number;Defined in: packages/core/src/elicitation/types.ts:73
maxLength?
Section titled “maxLength?”optional maxLength?: number;Defined in: packages/core/src/elicitation/types.ts:74
AparteElicitationObjectSchema
Section titled “AparteElicitationObjectSchema”Defined in: packages/core/src/elicitation/types.ts:84
A multi-field form: one labelled field per property.
Properties
Section titled “Properties”type: "object";Defined in: packages/core/src/elicitation/types.ts:85
properties
Section titled “properties”properties: Record<string, AparteElicitationField>;Defined in: packages/core/src/elicitation/types.ts:86
required?
Section titled “required?”optional required?: string[];Defined in: packages/core/src/elicitation/types.ts:88
Which keys must be filled to accept. Default: all of them.
AparteElicitationRequest
Section titled “AparteElicitationRequest”Defined in: packages/core/src/elicitation/types.ts:94
Properties
Section titled “Properties”message
Section titled “message”message: string | (() => string);Defined in: packages/core/src/elicitation/types.ts:108
The sentence above everything else. A string, or a function re-read on relabel.
Same reason as an option’s label, and I shipped the two an hour apart because I
fixed the choices and left the QUESTION behind — a panel asking “Run delete_file?”
over buttons reading “Approuver” and “Rejeter”. A resolved string has nothing to
re-derive from.
A function only makes sense when the text comes from the LOCALE, which is core’s own approval question. A tool’s question is model-authored: it is a string, and re-reading it would mean nothing.
details?
Section titled “details?”optional details?: string;Defined in: packages/core/src/elicitation/types.ts:125
The body under the question: what is actually being decided.
TEXT, and shown as text — a preformatted block the panel renders through
textContent. It exists because the approval panel used to show the tool’s
NAME and nothing else, while the arguments the model chose — the thing a person
is being asked to approve — stayed in the transcript row behind a closed
disclosure. A decision surface that omits what is being decided is asking for a
signature on a blank page.
Not markup, and not a render hook: the content here is model-authored, so the string arm of a hook would be a model-to-DOM XSS on the highest-stakes control in the library. A host that wants a diff view registers its own presenter.
Ignored on kind: 'question' — a question’s body is its schema.
schema?
Section titled “schema?”optional schema?: AparteElicitationSchema;Defined in: packages/core/src/elicitation/types.ts:131
What value to collect. Required on a 'question', absent on an 'approval' —
a decision is not a value, and a schema there would be a form with nothing in it.
target?
Section titled “target?”optional target?: HTMLElement | null;Defined in: packages/core/src/elicitation/types.ts:136
An element inside the target chat, used to resolve WHICH instance presents the request (its config + composer). Omit for the global/default chat.
optional kind?: "approval" | "question";Defined in: packages/core/src/elicitation/types.ts:145
What kind of request this is, which decides what the panel puts on screen.
'question' (the default) collects a VALUE against schema. 'approval' asks
the user to pick one of options — a decision, not a value — and its answer is
an AparteApprovalAnswer. One mechanism, two presentations: what a person
is being asked for differs, where they answer does not.
options?
Section titled “options?”optional options?: readonly AparteApprovalOption[];Defined in: packages/core/src/elicitation/types.ts:153
The options offered, on kind: 'approval'. Required there, ignored otherwise.
Supplied per request, never fixed by core: a gate that has nowhere to remember a grant offers two, one that does offers three. Rendering an option the host cannot honour is the affordance rule read backwards.
signal?
Section titled “signal?”optional signal?: AbortSignal;Defined in: packages/core/src/elicitation/types.ts:160
Aborts the request — the panel closes and the promise REJECTS with AparteElicitationAbortError. Pass a tool handler’s signal so a client-side timeout or a stopped turn tears the panel down instead of leaving it open.
AparteApprovalOption
Section titled “AparteApprovalOption”Defined in: packages/core/src/elicitation/types.ts:173
One thing the user can pick on an approval.
The requester writes the LABEL, always. Core cannot know that “and always for git
commands” is meaningful, or that this workspace has somewhere to remember it — so an
option offering a scope exists only because the host built it and can honour it
(ratified decision #8). Two options may share a value and differ only in scope,
which is what “Yes” and “Yes, and always for X” are: the same verdict, a different
reach.
Properties
Section titled “Properties”value: string;Defined in: packages/core/src/elicitation/types.ts:175
What AparteApprovalAnswer.option reports when this one is chosen.
label: string | (() => string);Defined in: packages/core/src/elicitation/types.ts:189
What the user reads. A string, or a function re-read on every relabel.
The function arm exists because these are the highest-stakes strings in the library and they have to follow a language switch WHILE the request is open — a person deciding whether to let a tool run should not be reading the choice in a language they did not pick. A plain string cannot: the panel receives it already resolved and has nothing to re-derive it from.
So core’s own two options pass a function that reads the locale, and a host passes whatever it likes: its label is its string, and core has no business translating it.
description?
Section titled “description?”optional description?: string | (() => string);Defined in: packages/core/src/elicitation/types.ts:203
What choosing it commits to, drawn under the label — the scope of an “always”.
A label can say “Always allow” and not what that reaches: one host remembered
the first word of a command (git, for git status) while the button said
“Always allow”, so the user authorised every git command believing they had
authorised one. The panel could not show the difference, because an option had
nowhere to put it. Two options that differ only in reach now differ on screen:
description: 'git status' beside description: 'git *'.
Same two arms as label, for the same reason: it follows a language switch
while the request is open.
optional tone?: "deny" | "affirm";Defined in: packages/core/src/elicitation/types.ts:208
How it is drawn. 'affirm' and 'deny' are the two poles a decision has; a
third would be a preference, not a meaning, so there is no 'neutral'.
AparteApprovalAnswer
Section titled “AparteApprovalAnswer”Defined in: packages/core/src/elicitation/types.ts:219
What an approval resolves with, as content.
instruction is the free-text arm — “no, do this instead” — and it is a separate
field rather than a magic option value because only the host can name its options,
and this text is the user’s. It reaches the model as the refusal’s reason, which is
possible at all only because a refusal now hands the model a turn to read it in.
Properties
Section titled “Properties”option?
Section titled “option?”optional option?: string;Defined in: packages/core/src/elicitation/types.ts:221
The value of the option chosen, or undefined when only text was given.
instruction?
Section titled “instruction?”optional instruction?: string;Defined in: packages/core/src/elicitation/types.ts:223
What the user typed instead, if they typed anything.
Type Aliases
Section titled “Type Aliases”AparteElicitationField
Section titled “AparteElicitationField”type AparteElicitationField =
| AparteElicitationEnumField
| AparteElicitationBooleanField
| AparteElicitationStringField;Defined in: packages/core/src/elicitation/types.ts:78
A single input field.
AparteElicitationSchema
Section titled “AparteElicitationSchema”type AparteElicitationSchema =
| AparteElicitationField
| AparteElicitationObjectSchema;Defined in: packages/core/src/elicitation/types.ts:92
The schema for a request: a single field, or an object (form) of fields.
AparteElicitationResult
Section titled “AparteElicitationResult”type AparteElicitationResult =
| {
action: "accept";
content: unknown;
}
| {
action: "decline";
};Defined in: packages/core/src/elicitation/types.ts:231
The user’s response. content matches the schema:
enum→string, enum+multiple→string[], boolean→boolean, string→string,
object→Record<key, value>.
AparteElicitationPresenter
Section titled “AparteElicitationPresenter”type AparteElicitationPresenter = (request) => Promise<AparteElicitationResult>;Defined in: packages/core/src/elicitation/types.ts:278
Presents an elicitation request and resolves with the user’s response, or rejects
with AparteElicitationAbortError when it ends without one.
Registered per config instance via aparteGlobalConfig.setElicitationPresenter
(the <aparte-elicitation> Web Component is the default presenter).
Parameters
Section titled “Parameters”| Parameter | Type |
|---|---|
request | AparteElicitationRequest |
Returns
Section titled “Returns”Promise<AparteElicitationResult>