Skip to content

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.

  • DOMException
ts
new AparteElicitationAbortError(reason?): AparteElicitationAbortError;

Defined in: packages/core/src/elicitation/types.ts:261

ParameterTypeDefault value
reason"aborted" | "no-presenter"'aborted'

AparteElicitationAbortError

ts
DOMException.constructor
ts
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.


ts
function buildApprovalPanel(
   message, 
   options, 
   onChange, 
   details?): BuiltApprovalPanel;

Defined in: packages/core/src/elicitation/approval-panel.ts:59

ParameterType
messagestring | (() => string)
optionsreadonly AparteApprovalOption[]
onChange() => void
details?string

BuiltApprovalPanel


ts
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.

ParameterType
requestAparteElicitationRequest

Promise<AparteElicitationResult>


ts
function buildElicitationPanel(
   message, 
   schema, 
   onChange): BuiltElicitationPanel;

Defined in: packages/core/src/elicitation/panel.ts:590

ParameterType
messagestring | (() => string)
schemaAparteElicitationSchema
onChange() => void

BuiltElicitationPanel


Defined in: packages/core/src/elicitation/approval-panel.ts:31

What the presenter drives. A superset of the question panel’s useful half.

ts
readonly el: HTMLElement;

Defined in: packages/core/src/elicitation/approval-panel.ts:32

ts
readonly dismiss: HTMLElement;

Defined in: packages/core/src/elicitation/approval-panel.ts:34

The corner escape — see BuiltElicitationPanel.dismiss for why a corner.

ts
onSettle(cb): void;

Defined in: packages/core/src/elicitation/approval-panel.ts:36

Settled from inside the panel: an option was clicked.

ParameterType
cb(answer) => void

void

ts
getContent(): AparteApprovalAnswer;

Defined in: packages/core/src/elicitation/approval-panel.ts:38

The instruction typed so far, for the composer’s submit path.

AparteApprovalAnswer

ts
isComplete(): boolean;

Defined in: packages/core/src/elicitation/approval-panel.ts:40

True once there is an instruction worth sending.

boolean

ts
focus(): void;

Defined in: packages/core/src/elicitation/approval-panel.ts:41

void

ts
relabel(): void;

Defined in: packages/core/src/elicitation/approval-panel.ts:43

Re-apply every string taken from the locale, in place.

void


Defined in: packages/core/src/elicitation/panel.ts:25

ts
readonly el: HTMLElement;

Defined in: packages/core/src/elicitation/panel.ts:26

ts
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.

ts
getContent(): unknown;

Defined in: packages/core/src/elicitation/panel.ts:45

The current response content, shaped to match the schema.

unknown

ts
isComplete(): boolean;

Defined in: packages/core/src/elicitation/panel.ts:47

True when every required field has a usable value.

boolean

ts
focus(): void;

Defined in: packages/core/src/elicitation/panel.ts:49

Focus the first input (called after mount).

void

ts
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.

"none" | "submit"

ts
canProceed(): boolean;

Defined in: packages/core/src/elicitation/panel.ts:71

Whether that button is enabled: every required question answered.

boolean

ts
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.

void

ts
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.

ParameterType
cb(content) => void

void

ts
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.

void


Defined in: packages/core/src/elicitation/types.ts:11

A single choice field: radios (default) or checkboxes (multiple).

ts
type: "enum";

Defined in: packages/core/src/elicitation/types.ts:12

ts
optional title?: string;

Defined in: packages/core/src/elicitation/types.ts:13

ts
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.

ts
optional description?: string;

Defined in: packages/core/src/elicitation/types.ts:23

ts
options: {
  value: string;
  label?: string;
  description?: string;
  recommended?: boolean;
}[];

Defined in: packages/core/src/elicitation/types.ts:24

ts
value: string;
ts
optional label?: string;
ts
optional description?: string;
ts
optional recommended?: boolean;
ts
optional multiple?: boolean;

Defined in: packages/core/src/elicitation/types.ts:26

Checkboxes (multi-select) instead of radios.

ts
optional allowOther?: boolean;

Defined in: packages/core/src/elicitation/types.ts:28

Offer a free-text “Other…” fallback. Default true.

ts
optional default?: string | string[];

Defined in: packages/core/src/elicitation/types.ts:30

Pre-selected value (or values, when multiple).


Defined in: packages/core/src/elicitation/types.ts:34

A yes/no field, rendered as two choices.

ts
type: "boolean";

Defined in: packages/core/src/elicitation/types.ts:35

ts
optional title?: string;

Defined in: packages/core/src/elicitation/types.ts:36

ts
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.

ts
optional description?: string;

Defined in: packages/core/src/elicitation/types.ts:46

ts
optional default?: boolean;

Defined in: packages/core/src/elicitation/types.ts:47

ts
optional trueLabel?: string;

Defined in: packages/core/src/elicitation/types.ts:49

Labels for the two choices (fall back to the locale yes/no).

ts
optional falseLabel?: string;

Defined in: packages/core/src/elicitation/types.ts:50


Defined in: packages/core/src/elicitation/types.ts:54

A free-text field.

ts
type: "string";

Defined in: packages/core/src/elicitation/types.ts:55

ts
optional title?: string;

Defined in: packages/core/src/elicitation/types.ts:56

ts
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.

ts
optional description?: string;

Defined in: packages/core/src/elicitation/types.ts:66

ts
optional placeholder?: string;

Defined in: packages/core/src/elicitation/types.ts:67

ts
optional default?: string;

Defined in: packages/core/src/elicitation/types.ts:68

ts
optional multiline?: boolean;

Defined in: packages/core/src/elicitation/types.ts:70

Render a multi-line textarea.

ts
optional required?: boolean;

Defined in: packages/core/src/elicitation/types.ts:72

Required to accept. Default true.

ts
optional minLength?: number;

Defined in: packages/core/src/elicitation/types.ts:73

ts
optional maxLength?: number;

Defined in: packages/core/src/elicitation/types.ts:74


Defined in: packages/core/src/elicitation/types.ts:84

A multi-field form: one labelled field per property.

ts
type: "object";

Defined in: packages/core/src/elicitation/types.ts:85

ts
properties: Record<string, AparteElicitationField>;

Defined in: packages/core/src/elicitation/types.ts:86

ts
optional required?: string[];

Defined in: packages/core/src/elicitation/types.ts:88

Which keys must be filled to accept. Default: all of them.


Defined in: packages/core/src/elicitation/types.ts:94

ts
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.

ts
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.

ts
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.

ts
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.

ts
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.

ts
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.

ts
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.


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.

ts
value: string;

Defined in: packages/core/src/elicitation/types.ts:175

What AparteApprovalAnswer.option reports when this one is chosen.

ts
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.

ts
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.

ts
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'.


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.

ts
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.

ts
optional instruction?: string;

Defined in: packages/core/src/elicitation/types.ts:223

What the user typed instead, if they typed anything.


ts
type AparteElicitationField = 
  | AparteElicitationEnumField
  | AparteElicitationBooleanField
  | AparteElicitationStringField;

Defined in: packages/core/src/elicitation/types.ts:78

A single input field.


ts
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.


ts
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>.


ts
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).

ParameterType
requestAparteElicitationRequest

Promise<AparteElicitationResult>