Configuration — core API
Generated reference for @aparte/core. aparteGlobalConfig, the class behind it, and the provider, renderer and locale types it takes.
On this page
- Overview
- Classes
- Functions
- Variables
- Interfaces
-
Type Aliases
- AparteActionZone
- AparteMarkdownProvider
- AparteHighlightProvider
- AparteSystemPromptVarsProvider
- AparteKeyProvider
- AparteStreamingMarkdownProvider
- AparteAttachmentRenderer
- AparteBubbleShellRenderer
- AparteElicitationFieldRenderer
- AparteErrorRenderer
- AparteIconName
- AparteLocale
- AparteLocaleExtensions
- AparteSanitizer
- AparteSiblingNavRenderer
- AparteStatusRenderer
- Event details
Classes
Section titled “Classes”AparteConfig
Section titled “AparteConfig”Defined in: packages/core/src/config/aparte-config.ts:143
Everything a chat is configured with: the providers and the selected model, the transport and the keys, the tools, the renderers and render hooks, the Markdown and highlight providers, the locale, the icons, the avatars, the actions.
aparteGlobalConfig is the one every chat on the page reads. A chat that needs a
configuration of its own takes a new AparteConfig() attached to its element or to an
ancestor with attachConfig; the framework wrappers take it as their config prop.
A change to what is drawn — providers, the model, the locale, icons, avatars, actions,
renderers — reaches the components already on the page: subscribe() listeners are
called, and aparte-config-change is dispatched on window with the instance that changed.
The Markdown, streaming-Markdown and highlight providers, the sanitizer, segment defaults,
tools, tool renderers and summaries apply to what is drawn after they are set, so set them
before the chat renders; the transport, the keys and the system prompt apply from the next
request.
Constructors
Section titled “Constructors”Constructor
Section titled “Constructor”new AparteConfig(): AparteConfig;Returns
Section titled “Returns”Methods
Section titled “Methods”registerAction()
Section titled “registerAction()”registerAction(action): void;Defined in: packages/core/src/config/aparte-config.ts:270
Register a custom action button. zones places it in the message (bubble)
toolbar. Re-registering the same id overwrites it. Notifies mounted elements
so they re-render. A button in the composer is an <aparte-composer-action>
element you write in your markup, not a registry entry.
Parameters
Section titled “Parameters”| Parameter | Type |
|---|---|
action | AparteAction |
Returns
Section titled “Returns”void
getActions()
Section titled “getActions()”getActions(zone): AparteAction[];Defined in: packages/core/src/config/aparte-config.ts:282
All registered actions for a zone, sorted by order (lower first).
Parameters
Section titled “Parameters”| Parameter | Type |
|---|---|
zone | "bubble" |
Returns
Section titled “Returns”unregisterAction()
Section titled “unregisterAction()”unregisterAction(id): void;Defined in: packages/core/src/config/aparte-config.ts:289
Remove a custom action by id (from every zone); notifies mounted elements if it existed.
Parameters
Section titled “Parameters”| Parameter | Type |
|---|---|
id | string |
Returns
Section titled “Returns”void
setBubbleActions()
Section titled “setBubbleActions()”setBubbleActions(config): void;Defined in: packages/core/src/config/aparte-config.ts:307
Configure which action buttons appear in message bubbles.
Unset keys keep their defaults — see APARTE_DEFAULT_BUBBLE_ACTIONS: copy
only, because every other button needs a host to honor it.
Parameters
Section titled “Parameters”| Parameter | Type |
|---|---|
config | AparteBubbleActionsConfig |
Returns
Section titled “Returns”void
Example
Section titled “Example”aparteGlobalConfig.setBubbleActions({ retry: true, edit: true }) // you run AparteClient
aparteGlobalConfig.setBubbleActions({ feedback: true }) // you listen for aparte-feedback
aparteGlobalConfig.setBubbleActions({ copy: false }) // hides copy; calls merge, so anything turned on above stays on
// Explicit per-role ordered sets (replace the flag defaults for that role):
aparteGlobalConfig.setBubbleActions({ user: ['edit', 'copy'], assistant: ['copy', 'thumbUp', 'thumbDown', 'retry'] })setHostHandlers()
Section titled “setHostHandlers()”setHostHandlers(config): void;Defined in: packages/core/src/config/aparte-config.ts:319
Declare which host-dependent affordances your app handles. Core renders the trigger only for the ones you claim — see AparteHostHandlersConfig.
Parameters
Section titled “Parameters”| Parameter | Type |
|---|---|
config | AparteHostHandlersConfig |
Returns
Section titled “Returns”void
Example
Section titled “Example”aparteGlobalConfig.setHostHandlers({ attachmentPreview: true });getHostHandlers()
Section titled “getHostHandlers()”getHostHandlers(): Required<AparteHostHandlersConfig>;Defined in: packages/core/src/config/aparte-config.ts:330
Returns the resolved host-handler declarations (undeclared = false).
Returns
Section titled “Returns”Required<AparteHostHandlersConfig>
getBubbleActions()
Section titled “getBubbleActions()”getBubbleActions(): {
copy: boolean;
retry: boolean;
edit: boolean;
feedback: boolean;
info: boolean;
user?: AparteBubbleActionName[];
assistant?: AparteBubbleActionName[];
};Defined in: packages/core/src/config/aparte-config.ts:337
Returns the resolved bubble actions config (flag defaults applied; per-role sets passed through).
Returns
Section titled “Returns”{
copy: boolean;
retry: boolean;
edit: boolean;
feedback: boolean;
info: boolean;
user?: AparteBubbleActionName[];
assistant?: AparteBubbleActionName[];
}copy: boolean;retry: boolean;edit: boolean;feedback
Section titled “feedback”feedback: boolean;info: boolean;optional user?: AparteBubbleActionName[];assistant?
Section titled “assistant?”optional assistant?: AparteBubbleActionName[];setMarkdownProvider()
Section titled “setMarkdownProvider()”setMarkdownProvider(fn): void;Defined in: packages/core/src/config/aparte-config.ts:360
Set a custom Markdown renderer (e.g., marked, maritime-it)
Parameters
Section titled “Parameters”| Parameter | Type |
|---|---|
fn | AparteMarkdownProvider |
Returns
Section titled “Returns”void
setStreamingMarkdownProvider()
Section titled “setStreamingMarkdownProvider()”setStreamingMarkdownProvider(fn): void;Defined in: packages/core/src/config/aparte-config.ts:375
Set an incremental (streaming) Markdown renderer provider. Optional —
when set, the chat bubble uses it to render the assistant message
token-by-token DURING streaming (incremental parse + DOM append, O(n)),
instead of re-parsing the whole string on every token. With no one-shot
setMarkdownProvider registered, it also renders a COMPLETE string
(renderMarkdown): a restored reply, a non-streaming provider’s answer, a
stored segment — so a reply renders the same however it arrived. A registered
one-shot provider takes over for those, and re-renders the finished message
at full fidelity.
Parameters
Section titled “Parameters”| Parameter | Type |
|---|---|
fn | AparteStreamingMarkdownProvider |
Returns
Section titled “Returns”void
createStreamingMarkdownRenderer()
Section titled “createStreamingMarkdownRenderer()”createStreamingMarkdownRenderer(target):
| AparteStreamingMarkdownRenderer
| null;Defined in: packages/core/src/config/aparte-config.ts:384
Create an incremental Markdown renderer bound to target, or null when
no streaming-markdown provider is registered (the caller then falls back
to the one-shot renderMarkdown).
Parameters
Section titled “Parameters”| Parameter | Type |
|---|---|
target | HTMLElement |
Returns
Section titled “Returns”| AparteStreamingMarkdownRenderer
| null
setHighlightProvider()
Section titled “setHighlightProvider()”setHighlightProvider(fn): void;Defined in: packages/core/src/config/aparte-config.ts:392
Set a custom Syntax Highlighter (e.g., prism, highlight.js, shiki) Supports both synchronous and asynchronous renderers.
Parameters
Section titled “Parameters”| Parameter | Type |
|---|---|
fn | AparteHighlightProvider |
Returns
Section titled “Returns”void
hasHighlightProvider()
Section titled “hasHighlightProvider()”hasHighlightProvider(): boolean;Defined in: packages/core/src/config/aparte-config.ts:401
Whether a syntax-highlight provider is registered. Lets consumers (e.g. the bubble) skip the highlight pass — and avoid replacing already-rendered code blocks with the plain fallback — when no highlighter is installed.
Returns
Section titled “Returns”boolean
setHtmlSanitizer()
Section titled “setHtmlSanitizer()”setHtmlSanitizer(sanitizer): void;Defined in: packages/core/src/config/aparte-config.ts:416
Replace or disable the HTML sanitizer applied to markdown/highlight provider output before it is injected into the DOM. Defaults to a built-in zero-dependency allowlist sanitizer.
Parameters
Section titled “Parameters”| Parameter | Type | Description |
|---|---|---|
sanitizer | AparteSanitizer | null | A sanitizer function (e.g. a DOMPurify wrapper) for hardened coverage, or null to DISABLE sanitization. Disabling exposes you to XSS from LLM-authored content — only do so for content you fully trust and have already sanitized upstream. null prints a console warning, once. |
Returns
Section titled “Returns”void
Example
Section titled “Example”aparteGlobalConfig.setHtmlSanitizer((html) => DOMPurify.sanitize(html));sanitizeHtml()
Section titled “sanitizeHtml()”sanitizeHtml(html): string;Defined in: packages/core/src/config/aparte-config.ts:440
Run the active sanitizer over provider-produced HTML. Public so a
streaming-markdown provider (which appends DOM directly, bypassing
renderMarkdown) can apply the same policy. Returns the input unchanged
only when sanitization was disabled via setHtmlSanitizer(null).
Parameters
Section titled “Parameters”| Parameter | Type |
|---|---|
html | string |
Returns
Section titled “Returns”string
setSystemPrompt()
Section titled “setSystemPrompt()”setSystemPrompt(template): void;Defined in: packages/core/src/config/aparte-config.ts:448
Set the system prompt template. Supports {{key}} placeholders resolved via setSystemPromptVarsProvider.
Pass undefined to clear.
Parameters
Section titled “Parameters”| Parameter | Type |
|---|---|
template | string | undefined |
Returns
Section titled “Returns”void
getSystemPromptTemplate()
Section titled “getSystemPromptTemplate()”getSystemPromptTemplate(): string | undefined;Defined in: packages/core/src/config/aparte-config.ts:453
Get the raw system prompt template (with unresolved placeholders).
Returns
Section titled “Returns”string | undefined
setSystemPromptVarsProvider()
Section titled “setSystemPromptVarsProvider()”setSystemPromptVarsProvider(fn): void;Defined in: packages/core/src/config/aparte-config.ts:462
Register a function that returns a map of variable name → value.
Called at request time to resolve {{key}} placeholders in the system prompt.
Example: () => ({ ‘settings.lang’: ‘French’ })
Parameters
Section titled “Parameters”| Parameter | Type |
|---|---|
fn | AparteSystemPromptVarsProvider |
Returns
Section titled “Returns”void
resolveSystemPrompt()
Section titled “resolveSystemPrompt()”resolveSystemPrompt(): string | null;Defined in: packages/core/src/config/aparte-config.ts:470
Resolve the system prompt template by substituting all {{key}} placeholders.
Returns null if no template is set or the template is empty after trimming.
Returns
Section titled “Returns”string | null
setIconProvider()
Section titled “setIconProvider()”setIconProvider(provider): void;Defined in: packages/core/src/config/aparte-config.ts:481
Set a custom Icon provider (e.g., Lucide, FontAwesome, Material)
Parameters
Section titled “Parameters”| Parameter | Type | Description |
|---|---|---|
provider | AparteIconProvider | Object implementing AparteIconProvider interface |
Returns
Section titled “Returns”void
getIconProvider()
Section titled “getIconProvider()”getIconProvider(): Required<AparteIconProvider>;Defined in: packages/core/src/config/aparte-config.ts:501
The icon set as a complete provider: every name resolves, falling back
to APARTE_DEFAULT_ICON_FALLBACKS for anything the registered provider doesn’t
implement. Callers (bubble action bar, composer controls) can therefore
invoke icons.copy() unconditionally.
It used to hand back the registered provider verbatim, so a provider that
implemented a subset — which getIcon() has always supported, and which
the type now states — crashed every other icon with
“icons.retry is not a function”.
Returns
Section titled “Returns”Required<AparteIconProvider>
setAvatarProvider()
Section titled “setAvatarProvider()”setAvatarProvider(provider): void;Defined in: packages/core/src/config/aparte-config.ts:516
Set a custom avatar renderer. Lets framework consumers (Angular,
React, Vue, …) mount live components in place of the default
avatar text/image. Cleared by passing null.
Parameters
Section titled “Parameters”| Parameter | Type |
|---|---|
provider | AparteAvatarProvider | null |
Returns
Section titled “Returns”void
getAvatarProvider()
Section titled “getAvatarProvider()”getAvatarProvider(): AparteAvatarProvider | null;Defined in: packages/core/src/config/aparte-config.ts:523
Returns the registered avatar provider, or null if none.
Returns
Section titled “Returns”AparteAvatarProvider | null
setStatusRenderer()
Section titled “setStatusRenderer()”setStatusRenderer(renderer): void;Defined in: packages/core/src/config/aparte-config.ts:533
Set a custom typing-indicator renderer. Replaces the inner markup of
<aparte-chat-status> (avatar + animated dots + text) while the element keeps
owning show/hide. Return a string or an HTMLElement. Cleared by passing
null. Notifies mounted components so a live skin switch re-renders.
Parameters
Section titled “Parameters”| Parameter | Type |
|---|---|
renderer | AparteStatusRenderer | null |
Returns
Section titled “Returns”void
getStatusRenderer()
Section titled “getStatusRenderer()”getStatusRenderer(): AparteStatusRenderer | null;Defined in: packages/core/src/config/aparte-config.ts:539
Returns the registered status renderer, or null if none.
Returns
Section titled “Returns”AparteStatusRenderer | null
setErrorRenderer()
Section titled “setErrorRenderer()”setErrorRenderer(renderer): void;Defined in: packages/core/src/config/aparte-config.ts:550
Set a custom error renderer. Drives the content of error bubbles (the
built-in error segment) — return a string or an HTMLElement, e.g. a
friendly message with a retry button. The bubble also carries data-error
on its .aparte-message while errored, for CSS theming. Cleared with null.
Notifies mounted components so a live change re-renders.
Parameters
Section titled “Parameters”| Parameter | Type |
|---|---|
renderer | AparteErrorRenderer | null |
Returns
Section titled “Returns”void
getErrorRenderer()
Section titled “getErrorRenderer()”getErrorRenderer(): AparteErrorRenderer | null;Defined in: packages/core/src/config/aparte-config.ts:556
Returns the registered error renderer, or null if none.
Returns
Section titled “Returns”AparteErrorRenderer | null
setAttachmentRenderer()
Section titled “setAttachmentRenderer()”setAttachmentRenderer(renderer): void;Defined in: packages/core/src/config/aparte-config.ts:567
Set a custom attachment renderer. Replaces the chip rendered for each
attachment on a user message (default: image thumbnail / file chip) — return
a string or an HTMLElement, e.g. a PDF preview. You own the interactions for
custom output (see AparteAttachmentRenderer). Cleared with null.
Notifies mounted components so a live change re-renders.
Parameters
Section titled “Parameters”| Parameter | Type |
|---|---|
renderer | AparteAttachmentRenderer | null |
Returns
Section titled “Returns”void
getAttachmentRenderer()
Section titled “getAttachmentRenderer()”getAttachmentRenderer(): AparteAttachmentRenderer | null;Defined in: packages/core/src/config/aparte-config.ts:573
Returns the registered attachment renderer, or null if none.
Returns
Section titled “Returns”AparteAttachmentRenderer | null
setSiblingNavRenderer()
Section titled “setSiblingNavRenderer()”setSiblingNavRenderer(renderer): void;Defined in: packages/core/src/config/aparte-config.ts:583
Set a custom sibling (branch) position indicator. Replaces the ‹ N / M ›
counter between the prev/next arrows — e.g. dots. Return a string or an
HTMLElement (see AparteSiblingNavRenderer); the arrows keep their
behavior. Cleared with null. Notifies mounted components.
Parameters
Section titled “Parameters”| Parameter | Type |
|---|---|
renderer | AparteSiblingNavRenderer | null |
Returns
Section titled “Returns”void
getSiblingNavRenderer()
Section titled “getSiblingNavRenderer()”getSiblingNavRenderer(): AparteSiblingNavRenderer | null;Defined in: packages/core/src/config/aparte-config.ts:589
Returns the registered sibling-nav renderer, or null if none.
Returns
Section titled “Returns”AparteSiblingNavRenderer | null
setBubbleShellRenderer()
Section titled “setBubbleShellRenderer()”setBubbleShellRenderer(renderer): void;Defined in: packages/core/src/config/aparte-config.ts:600
Set a custom bubble shell renderer (advanced) — replaces the structural
skeleton of <aparte-chat-bubble> while keeping its behavior. The shell must
honor the class-hook contract (root .aparte-message, region hooks) — see
AparteBubbleShellRenderer. For a fully custom element use renderBubble
(wrapper) instead. Cleared with null. Notifies mounted components.
Parameters
Section titled “Parameters”| Parameter | Type |
|---|---|
renderer | AparteBubbleShellRenderer | null |
Returns
Section titled “Returns”void
getBubbleShellRenderer()
Section titled “getBubbleShellRenderer()”getBubbleShellRenderer(): AparteBubbleShellRenderer | null;Defined in: packages/core/src/config/aparte-config.ts:606
Returns the registered bubble-shell renderer, or null if none.
Returns
Section titled “Returns”AparteBubbleShellRenderer | null
setLocale()
Section titled “setLocale()”setLocale(locale): void;Defined in: packages/core/src/config/aparte-config.ts:614
Set the current locale
Parameters
Section titled “Parameters”| Parameter | Type | Description |
|---|---|---|
locale | AparteLocale & AparteLocaleExtensions | AparteLocale object defining all strings |
Returns
Section titled “Returns”void
resetLocale()
Section titled “resetLocale()”resetLocale(): void;Defined in: packages/core/src/config/aparte-config.ts:626
Restore the built-in English locale (the same APARTE_DEFAULT_LOCALE core ships
with). Counterpart of setLocale for language toggles — avoids
having to import APARTE_DEFAULT_LOCALE yourself.
Returns
Section titled “Returns”void
getLocale()
Section titled “getLocale()”getLocale(): AparteLocale & AparteLocaleExtensions;Defined in: packages/core/src/config/aparte-config.ts:644
Get the current locale.
Typed as the closed list PLUS the open half, and the asymmetry is the point:
t() keys on AparteLocale alone — a typo there is a compile error — while a
plugin reading its OWN key off this object gets string | undefined and
supplies its own default at the call site.
t() is the one that has to be narrow, because it is the one that fails
silently: it returns '' for a key nobody declared, and an empty label is
invisible on screen and in the console. A misspelt read here is undefined,
which the ?? 'fallback' every caller already writes turns into the default.
Returns
Section titled “Returns”AparteLocale & AparteLocaleExtensions
extendLocale()
Section titled “extendLocale()”extendLocale(translations): void;Defined in: packages/core/src/config/aparte-config.ts:653
Extend the current locale with partial translations. Useful for plugins to register their own strings.
Parameters
Section titled “Parameters”| Parameter | Type | Description |
|---|---|---|
translations | Partial<AparteLocale> & AparteLocaleExtensions | Partial locale object to merge |
Returns
Section titled “Returns”void
getIcon()
Section titled “getIcon()”getIcon(name): string;Defined in: packages/core/src/config/aparte-config.ts:662
Get icon HTML string by name Falls back to textual representation if no provider is set
Parameters
Section titled “Parameters”| Parameter | Type |
|---|---|
name | keyof AparteIconProvider |
Returns
Section titled “Returns”string
setKeyProvider()
Section titled “setKeyProvider()”setKeyProvider(provider): void;Defined in: packages/core/src/config/aparte-config.ts:671
Set a custom Key provider (e.g., AparteVault override)
Parameters
Section titled “Parameters”| Parameter | Type |
|---|---|
provider | AparteKeyProvider |
Returns
Section titled “Returns”void
registerKeyProvider()
Section titled “registerKeyProvider()”registerKeyProvider(provider): () => void;Defined in: packages/core/src/config/aparte-config.ts:687
Add a key source beside the one setKeyProvider()
holds, and return the function that removes it. The sources are asked in the order they
were added, then setKeyProvider’s, and the first answer wins. AparteClient’s
keyResolver is registered this way, so the model selector can list a cloud provider’s
models too. Each call is a source of its own, even with the same function.
Parameters
Section titled “Parameters”| Parameter | Type |
|---|---|
provider | AparteKeyProvider |
Returns
Section titled “Returns”() => void
Example
Section titled “Example”const release = aparteGlobalConfig.registerKeyProvider((providerId) =>
providerId === 'openrouter' ? localStorage.getItem('openrouter-key') : undefined);
// when what owns the key goes away:
release();getKey()
Section titled “getKey()”getKey(providerId): Promise<string | Record<string, string> | undefined>;Defined in: packages/core/src/config/aparte-config.ts:713
The credentials for a provider: a key, or the { apiKey, endpoint } record
the transport and fetchModels both read.
ONE resolution order, so the chat and the model list cannot disagree about
what an endpoint is: a registered resolver (AparteClient’s keyResolver)
first — which is the precedence the client has always documented — then
setKeyProvider.
Registered sources answer NEWEST first. A page that mounts a second chat, or remounts one to swap its options — the swap the wrappers document — leaves more than one source here, and insertion order made the first resolver the page ever registered answer for every later one, so the key could not be changed. The snapshot is deliberate too: a source torn down while an earlier one is being awaited must not shift the iteration underneath it.
Parameters
Section titled “Parameters”| Parameter | Type |
|---|---|
providerId | string |
Returns
Section titled “Returns”Promise<string | Record<string, string> | undefined>
refreshProviderModels()
Section titled “refreshProviderModels()”refreshProviderModels(providerId): Promise<AparteAIModel[]>;Defined in: packages/core/src/config/aparte-config.ts:730
Fetch a provider’s models, with the key and endpoint its key sources answer, so a
component that lists models never handles a key. The list is kept, and
getCurrentModel() reads the selected model’s capabilities from it. Answers [] for an
unknown provider, one with no fetchModels, or a fetch that fails (with a console warning).
Parameters
Section titled “Parameters”| Parameter | Type |
|---|---|
providerId | string |
Returns
Section titled “Returns”Promise<AparteAIModel[]>
registerAIProvider()
Section titled “registerAIProvider()”registerAIProvider(...providers): void;Defined in: packages/core/src/config/aparte-config.ts:768
Register one or more AI providers (e.g., OpenRouter, Gemini, Anthropic).
When this leaves exactly one provider registered, offering exactly one model it knows
without a request (a scripted or an in-browser provider), and no model is selected,
that model is selected. A provider that lists its models over the network selects
nothing: name one with setModelConfig(), or let the
person pick in <aparte-model-selector>.
Parameters
Section titled “Parameters”| Parameter | Type | Description |
|---|---|---|
…providers | AparteAIProvider[] | AparteAIProvider implementations |
Returns
Section titled “Returns”void
Example
Section titled “Example”aparteGlobalConfig.registerAIProvider(OpenRouterProvider);
aparteGlobalConfig.registerAIProvider(GeminiProvider, AnthropicProvider);unregisterAIProvider()
Section titled “unregisterAIProvider()”unregisterAIProvider(id): void;Defined in: packages/core/src/config/aparte-config.ts:798
Unregister an AI provider
Parameters
Section titled “Parameters”| Parameter | Type |
|---|---|
id | string |
Returns
Section titled “Returns”void
getAIProviders()
Section titled “getAIProviders()”getAIProviders(): AparteAIProvider[];Defined in: packages/core/src/config/aparte-config.ts:809
Get all registered AI providers Optionally filtered by enabled providers in config
Returns
Section titled “Returns”getAIProvider()
Section titled “getAIProvider()”getAIProvider(id): AparteAIProvider | undefined;Defined in: packages/core/src/config/aparte-config.ts:822
Get a specific AI provider by ID
Parameters
Section titled “Parameters”| Parameter | Type |
|---|---|
id | string |
Returns
Section titled “Returns”AparteAIProvider | undefined
setTransport()
Section titled “setTransport()”setTransport(transport): void;Defined in: packages/core/src/config/aparte-config.ts:832
Set the transport that decides where chat requests go and how auth is
handled. Defaults to AparteDirectTransport (browser-direct — BYOK/local).
Use a AparteBackendTransport to keep API keys server-side (recommended for
production).
Parameters
Section titled “Parameters”| Parameter | Type |
|---|---|
transport | AparteTransport |
Returns
Section titled “Returns”void
getTransport()
Section titled “getTransport()”getTransport(): AparteTransport;Defined in: packages/core/src/config/aparte-config.ts:837
Get the active transport (AparteDirectTransport by default).
Returns
Section titled “Returns”setModelPreferenceProvider()
Section titled “setModelPreferenceProvider()”setModelPreferenceProvider(provider): void;Defined in: packages/core/src/config/aparte-config.ts:850
Register a model preference provider for agnostic persistence. The host app decides how/where to store the selected provider & model.
Parameters
Section titled “Parameters”| Parameter | Type |
|---|---|
provider | AparteModelPreferenceProvider |
Returns
Section titled “Returns”void
Example
Section titled “Example”aparteGlobalConfig.setModelPreferenceProvider({
save: (p, m) => localStorage.setItem('model', JSON.stringify({p, m})),
load: () => JSON.parse(localStorage.getItem('model') ?? 'null')
});setApprovalPolicy()
Section titled “setApprovalPolicy()”setApprovalPolicy(policy): void;Defined in: packages/core/src/config/aparte-config.ts:876
Decide per CALL whether a tool runs, asks, or is refused — a mode, not a flag.
With a policy registered, the client’s default approval channel evaluates it for
every tool call: allow runs without asking, ask puts the call to the person
exactly as a needsApproval tool is, deny refuses it with the policy’s own
reason as what the model reads. undefined leaves the tool’s needsApproval
to decide, as before. null removes the policy.
@aparte/plugin-approval builds one from a classification of your tool names and
a switchable mode (plan / ask / auto-edit / auto); a host that owns its own
approvalResolver on AparteClientOptions is not affected — that resolver
already decides everything.
Parameters
Section titled “Parameters”| Parameter | Type |
|---|---|
policy | AparteApprovalPolicy | null |
Returns
Section titled “Returns”void
Example
Section titled “Example”aparteGlobalConfig.setApprovalPolicy((call) =>
call.name === 'run_command'
? { verdict: 'ask' }
: { verdict: 'allow' });getApprovalPolicy()
Section titled “getApprovalPolicy()”getApprovalPolicy(): AparteApprovalPolicy | null;Defined in: packages/core/src/config/aparte-config.ts:884
The registered approval policy, or null.
Returns
Section titled “Returns”AparteApprovalPolicy | null
ruleOnToolCall()
Section titled “ruleOnToolCall()”ruleOnToolCall(call): AparteApprovalRuling;Defined in: packages/core/src/config/aparte-config.ts:893
What the policy says about one call, with the tool’s own needsApproval as the
answer when it has no opinion. The one place the two are combined, so the client’s
gate predicate and its approval channel cannot disagree.
Parameters
Section titled “Parameters”| Parameter | Type |
|---|---|
call | AparteToolCall |
Returns
Section titled “Returns”restoreModelPreference()
Section titled “restoreModelPreference()”restoreModelPreference(): AparteModelPreference | null;Defined in: packages/core/src/config/aparte-config.ts:906
Restore previously saved model preference via the registered provider. Should be called once at app startup, before any component mounts. No-op if no provider is registered or nothing was saved. The saved selection is applied without being saved again.
Returns
Section titled “Returns”AparteModelPreference | null
setModelConfig()
Section titled “setModelConfig()”setModelConfig(config): void;Defined in: packages/core/src/config/aparte-config.ts:922
Select the default provider and model, merged over the current selection. With a model-preference provider registered and both set, the selection is saved through it.
Parameters
Section titled “Parameters”| Parameter | Type |
|---|---|
config | AparteModelConfig |
Returns
Section titled “Returns”void
subscribe()
Section titled “subscribe()”subscribe(callback): () => void;Defined in: packages/core/src/config/aparte-config.ts:937
Subscribe to configuration changes
Parameters
Section titled “Parameters”| Parameter | Type |
|---|---|
callback | () => void |
Returns
Section titled “Returns”Unsubscribe function
() => void
getModelConfig()
Section titled “getModelConfig()”getModelConfig(): AparteModelConfig;Defined in: packages/core/src/config/aparte-config.ts:964
Get current model configuration
Returns
Section titled “Returns”hasSelectedModel()
Section titled “hasSelectedModel()”hasSelectedModel(): boolean;Defined in: packages/core/src/config/aparte-config.ts:972
True when the model config has BOTH a provider and a model selected — i.e.
the chat can actually send. Used by the composer’s require-model gate.
Returns
Section titled “Returns”boolean
setElicitationOptions()
Section titled “setElicitationOptions()”setElicitationOptions(options): void;Defined in: packages/core/src/config/aparte-config.ts:1009
Elicitation policy: whether a choice offers a free-text “Other…” escape.
This is the HOST’s decision, not the model’s. ask_user used to carry an
allow_other field in the schema it hands the model, which meant the model
decided your UX — and a small model fills a field it does not understand: one
sent two questions with allow_other: true and no options at all, so the
panel rendered a radio list whose only entry was “Other…”, twice.
Every serious implementation of this pattern makes the escape hatch a property
of the surface rather than of the request. Default true, which is what the
panel did before, so nothing a user sees changes — only who gets to say so.
A direct requestUserInput caller can still set allowOther per field; that
is the app talking, and it wins.
layout decides how a form of SEVERAL questions is presented.
'stepped' (default) asks them one at a time with a chip per question;
'stacked' puts them all in the panel at once. Stacked was the only shape,
inherited unexamined from MCP elicitation — which describes a FORM for
collecting structured data, not two different questions asked mid-conversation.
No product asks a person two questions by stacking them in one box; it is kept
as an option because the form case is real, not because it was the right default.
answerOnClick decides how a question asked ON ITS OWN with a single choice — an
enum without multiple or a default, a boolean without a default — is
answered. true (default) renders the options as buttons and the click is the
answer: one decision, one gesture, the shape every chat product uses for “which
one?”. false keeps the radios and the composer’s button, so a person can
change their mind before committing — the shape a form or a screen reader
flow may prefer, and the one a host that wants a uniform “select, then send”
across every question asks for. A form of several questions always collects and
submits, whatever this says.
Parameters
Section titled “Parameters”| Parameter | Type |
|---|---|
options | { allowOther?: boolean; layout?: "stepped" | "stacked"; answerOnClick?: boolean; } |
options.allowOther? | boolean |
options.layout? | "stepped" | "stacked" |
options.answerOnClick? | boolean |
Returns
Section titled “Returns”void
getElicitationOptions()
Section titled “getElicitationOptions()”getElicitationOptions(): {
allowOther: boolean;
layout: "stepped" | "stacked";
answerOnClick: boolean;
};Defined in: packages/core/src/config/aparte-config.ts:1017
The elicitation policy (see setElicitationOptions).
Returns
Section titled “Returns”{
allowOther: boolean;
layout: "stepped" | "stacked";
answerOnClick: boolean;
}allowOther
Section titled “allowOther”allowOther: boolean;layout
Section titled “layout”layout: "stepped" | "stacked";answerOnClick
Section titled “answerOnClick”answerOnClick: boolean;setElicitationFieldRenderer()
Section titled “setElicitationFieldRenderer()”setElicitationFieldRenderer(fn): void;Defined in: packages/core/src/config/aparte-config.ts:1028
Render one field of the question panel yourself.
See AparteElicitationFieldRenderer. Return null for a field to let
the built-in render it, which is what makes overriding a single kind practical.
Pass null here to remove the renderer.
Parameters
Section titled “Parameters”| Parameter | Type |
|---|---|
fn | | AparteElicitationFieldRenderer | null |
Returns
Section titled “Returns”void
getElicitationFieldRenderer()
Section titled “getElicitationFieldRenderer()”getElicitationFieldRenderer():
| AparteElicitationFieldRenderer
| undefined;Defined in: packages/core/src/config/aparte-config.ts:1034
The custom field renderer, if one is registered.
Returns
Section titled “Returns”| AparteElicitationFieldRenderer
| undefined
setRequireModelSelection()
Section titled “setRequireModelSelection()”setRequireModelSelection(required): void;Defined in: packages/core/src/config/aparte-config.ts:1044
Opt-in UX: when enabled, <aparte-composer> blocks sending and greys out
until hasSelectedModel is true (e.g. while the model selector is
still fetching its list). Off by default so single-model / backend setups
that never select a model are unaffected.
Parameters
Section titled “Parameters”| Parameter | Type |
|---|---|
required | boolean |
Returns
Section titled “Returns”void
getRequireModelSelection()
Section titled “getRequireModelSelection()”getRequireModelSelection(): boolean;Defined in: packages/core/src/config/aparte-config.ts:1051
Whether the composer should gate on model selection (see setRequireModelSelection).
Returns
Section titled “Returns”boolean
getCurrentModel()
Section titled “getCurrentModel()”getCurrentModel(): AparteAIModel | undefined;Defined in: packages/core/src/config/aparte-config.ts:1060
Get the currently selected model object, if available synchronously. Returns undefined if no provider/model is selected, or if the provider’s models are only available asynchronously (fetchModels).
Returns
Section titled “Returns”AparteAIModel | undefined
t(key): string;Defined in: packages/core/src/config/aparte-config.ts:1093
The locale’s string for key, or the default (English) locale’s when the locale
leaves it out; '' for a key neither declares.
Parameters
Section titled “Parameters”| Parameter | Type |
|---|---|
key | keyof AparteLocale |
Returns
Section titled “Returns”string
renderMarkdown()
Section titled “renderMarkdown()”renderMarkdown(raw): string;Defined in: packages/core/src/config/aparte-config.ts:1112
Render a complete Markdown string to HTML: the one-shot provider when one is
registered, else the incremental provider run over the whole string, else core’s
default (escape + <br>).
The middle step is what makes the incremental provider enough on its own. Without
it a reply rendered two ways depending on how it arrived: rich while it streamed,
escaped source once it came back complete — a restored conversation, a
non-streaming provider, a stored segment. Same parser, same sanitizer, so the two
cannot disagree. It needs a document to write into; without one (a server render)
the default answers, as before.
Parameters
Section titled “Parameters”| Parameter | Type |
|---|---|
raw | string |
Returns
Section titled “Returns”string
highlightCode()
Section titled “highlightCode()”highlightCode(code, lang): Promise<string>;Defined in: packages/core/src/config/aparte-config.ts:1141
Highlight code block
Fallback: Returns raw code wrapped in <pre><code>
Supports Promise if provider is async/streaming
Parameters
Section titled “Parameters”| Parameter | Type |
|---|---|
code | string |
lang | string |
Returns
Section titled “Returns”Promise<string>
registerTool()
Section titled “registerTool()”registerTool(tool, handler): void;Defined in: packages/core/src/config/aparte-config.ts:1165
Register a tool and its handler together. The handler is called when the AI invokes the tool during streaming.
Parameters
Section titled “Parameters”| Parameter | Type |
|---|---|
tool | AparteTool |
handler | AparteToolHandler |
Returns
Section titled “Returns”void
Example
Section titled “Example”aparteGlobalConfig.registerTool(askUserTool, askUserHandler);unregisterTool()
Section titled “unregisterTool()”unregisterTool(name): void;Defined in: packages/core/src/config/aparte-config.ts:1170
Unregister a tool by name
Parameters
Section titled “Parameters”| Parameter | Type |
|---|---|
name | string |
Returns
Section titled “Returns”void
getTools()
Section titled “getTools()”getTools(): AparteTool[];Defined in: packages/core/src/config/aparte-config.ts:1175
Get all registered tool definitions (to pass in AparteChatRequest)
Returns
Section titled “Returns”resolveToolSystemPrompts()
Section titled “resolveToolSystemPrompts()”resolveToolSystemPrompts(): string | null;Defined in: packages/core/src/config/aparte-config.ts:1186
The registered tools’ own systemPrompts, in registration order with a blank line
between, or null if none sets one. AparteClient sends them with every request, as a
system message after the app’s own (resolveSystemPrompt());
a request you assemble yourself should send them the same way, or the model loses the
tools’ instructions.
Returns
Section titled “Returns”string | null
getToolHandler()
Section titled “getToolHandler()”getToolHandler(name): AparteToolHandler | undefined;Defined in: packages/core/src/config/aparte-config.ts:1194
Get the handler for a tool by name
Parameters
Section titled “Parameters”| Parameter | Type |
|---|---|
name | string |
Returns
Section titled “Returns”AparteToolHandler | undefined
registerToolRenderer()
Section titled “registerToolRenderer()”registerToolRenderer(toolName, renderer): void;Defined in: packages/core/src/config/aparte-config.ts:1218
Register a per-tool segment renderer.
Controls what appears in the chat bubble when the AI calls this tool.
Use this instead of the generic tool_call segment renderer for tool-specific UI.
A renderer that needs a popover (a <aparte-select>, a menu) cannot open one
inside the row: the bubble is content-visibility: auto, which makes it the
containing block for position: fixed descendants and clips a popover to its
own box. Mount it on document.body and position it from the trigger’s rect
instead — see Custom tool
renderer.
Parameters
Section titled “Parameters”| Parameter | Type |
|---|---|
toolName | string |
renderer | AparteToolRenderer |
Returns
Section titled “Returns”void
Examples
Section titled “Examples”// Hide the segment entirely (UI-only tool like ask_user)
aparteGlobalConfig.registerToolRenderer('ask_user', { render: () => '' });// Custom pill for a web-search tool
aparteGlobalConfig.registerToolRenderer('web_search', { render: (seg) => `<div class="aparte-tool-label">Searching...</div>` });setSegmentDefaults()
Section titled “setSegmentDefaults()”setSegmentDefaults(type, defaults): void;Defined in: packages/core/src/config/aparte-config.ts:1249
Field defaults for a segment TYPE, filled in when a segment enters a message.
One function for every type rather than one per field: a setThinkingOpen()
would need a sibling the next time any type wanted a default, and the type key
is a string, so a consumer’s own segment type is covered by the same call.
The problem it solves: a consumer streaming a reply does not CONSTRUCT its segments — the parser does — so there was no hook at all for “reasoning blocks open in my app”. Per-segment fields only reach segments you build yourself.
Applied where identity is stamped (utils/segments.ts), so it covers every
path a segment can arrive by — the parser, addSegment, and the segments
seeded on an appendMessage — and no renderer has to look anything up.
A field the producer set always wins, and identity is never defaulted. Read at insertion and baked in: changing a default later does not reach segments already on screen, because a block the reader opened has state the data does not.
Parameters
Section titled “Parameters”| Parameter | Type |
|---|---|
type | string |
defaults | AparteSegmentDefaults |
Returns
Section titled “Returns”void
Examples
Section titled “Examples”// Reasoning blocks arrive open in this app, streaming or settled.
aparteGlobalConfig.setSegmentDefaults('thinking', { collapsed: false });// A consumer's own type, same call.
aparteGlobalConfig.setSegmentDefaults('my-chart', { theme: 'dark' });getSegmentDefaults()
Section titled “getSegmentDefaults()”getSegmentDefaults(type): Readonly<Record<string, unknown>> | undefined;Defined in: packages/core/src/config/aparte-config.ts:1256
The defaults registered for a type, or undefined.
Parameters
Section titled “Parameters”| Parameter | Type |
|---|---|
type | string |
Returns
Section titled “Returns”Readonly<Record<string, unknown>> | undefined
clearSegmentDefaults()
Section titled “clearSegmentDefaults()”clearSegmentDefaults(type): void;Defined in: packages/core/src/config/aparte-config.ts:1261
Drop the defaults for a type.
Parameters
Section titled “Parameters”| Parameter | Type |
|---|---|
type | string |
Returns
Section titled “Returns”void
unregisterToolRenderer()
Section titled “unregisterToolRenderer()”unregisterToolRenderer(toolName): void;Defined in: packages/core/src/config/aparte-config.ts:1266
Unregister a per-tool renderer
Parameters
Section titled “Parameters”| Parameter | Type |
|---|---|
toolName | string |
Returns
Section titled “Returns”void
getToolRenderer()
Section titled “getToolRenderer()”getToolRenderer(toolName): AparteToolRenderer | undefined;Defined in: packages/core/src/config/aparte-config.ts:1271
Get the renderer for a specific tool name. Returns undefined if none registered.
Parameters
Section titled “Parameters”| Parameter | Type |
|---|---|
toolName | string |
Returns
Section titled “Returns”AparteToolRenderer | undefined
registerToolSummary()
Section titled “registerToolSummary()”registerToolSummary(toolName, summary): void;Defined in: packages/core/src/config/aparte-config.ts:1295
Say what a call targets, in the default row, after the tool’s name.
The default row names the tool and keeps its arguments behind a disclosure, so a
reader saw that a file was read, not which one. Replacing the row with
registerToolRenderer for that one line meant re-implementing its six states,
the spinner, the disclosure and the relabel contract. This keeps all of them and
adds the line. A tool with its own renderer draws its own row, so its summary is
never read.
The text is written as text, never parsed as HTML. It is read when the row renders, on every update to the call (its arguments may still be arriving), and on every config change — so registering one after a row is on screen shows up on that row’s next update.
Parameters
Section titled “Parameters”| Parameter | Type |
|---|---|
toolName | string |
summary | AparteToolSummary |
Returns
Section titled “Returns”void
Example
Section titled “Example”// read_file skills.json
aparteGlobalConfig.registerToolSummary('read_file', (segment) =>
String(segment.toolCall.input['path'] ?? ''));unregisterToolSummary()
Section titled “unregisterToolSummary()”unregisterToolSummary(toolName): void;Defined in: packages/core/src/config/aparte-config.ts:1300
Unregister a per-tool summary.
Parameters
Section titled “Parameters”| Parameter | Type |
|---|---|
toolName | string |
Returns
Section titled “Returns”void
getToolSummary()
Section titled “getToolSummary()”getToolSummary(toolName): AparteToolSummary | undefined;Defined in: packages/core/src/config/aparte-config.ts:1305
Get the summary for a specific tool name. Returns undefined if none registered.
Parameters
Section titled “Parameters”| Parameter | Type |
|---|---|
toolName | string |
Returns
Section titled “Returns”AparteToolSummary | undefined
registerStreamBlock()
Section titled “registerStreamBlock()”registerStreamBlock(block): void;Defined in: packages/core/src/config/aparte-config.ts:1329
Teach the stream parser a tagged block: <tag attr="…">…</tag> in the model’s
prose becomes the segment toSegment builds, streamed delta by delta.
The parser does the work once for every grammar — the earliest opening tag wins
against a code fence and a reasoning delimiter, a tag cut at a chunk boundary is
held back, attributes are parsed quoted or bare, and the block is closed at
</tag> or at the end of the stream. What the segment IS is yours: a type of
your own with a renderer from registerSegmentRenderer, or a built-in one. One
grammar per tag; registering the same tag again replaces it.
Read by the stream adapter when a turn starts, so a block registered mid-turn applies from the next turn. See AparteStreamBlock.
Parameters
Section titled “Parameters”| Parameter | Type |
|---|---|
block | AparteStreamBlock |
Returns
Section titled “Returns”void
Example
Section titled “Example”aparteGlobalConfig.registerStreamBlock({
tag: 'cite',
toSegment: ({ attrs, id }) => ({ id, type: 'citation', url: attrs['url'] ?? '', content: '' }),
});unregisterStreamBlock()
Section titled “unregisterStreamBlock()”unregisterStreamBlock(tag): void;Defined in: packages/core/src/config/aparte-config.ts:1335
Forget a block grammar by its tag.
Parameters
Section titled “Parameters”| Parameter | Type |
|---|---|
tag | string |
Returns
Section titled “Returns”void
getStreamBlocks()
Section titled “getStreamBlocks()”getStreamBlocks(): AparteStreamBlock[];Defined in: packages/core/src/config/aparte-config.ts:1340
The registered block grammars, in registration order.
Returns
Section titled “Returns”setConversationManager()
Section titled “setConversationManager()”setConversationManager(manager): void;Defined in: packages/core/src/config/aparte-config.ts:1352
Register a AparteConversationManager so any UI controller can persist & load conversations without coupling to a framework wrapper.
Parameters
Section titled “Parameters”| Parameter | Type |
|---|---|
manager | AparteConversationManager |
Returns
Section titled “Returns”void
getConversationManager()
Section titled “getConversationManager()”getConversationManager(): AparteConversationManager | undefined;Defined in: packages/core/src/config/aparte-config.ts:1357
Returns the registered AparteConversationManager, or undefined if none.
Returns
Section titled “Returns”AparteConversationManager | undefined
setElicitationPresenter()
Section titled “setElicitationPresenter()”setElicitationPresenter(presenter, owner?): void;Defined in: packages/core/src/config/aparte-config.ts:1377
Register the presenter that renders typed input requests (a choice, a
confirmation, a text field, a form) and resolves with the user’s answer.
The <aparte-elicitation> Web Component registers itself here; an app can
override with its own framework-native presenter. Pass null to clear.
Several can be registered, one per chat: owner is an element of the chat the
presenter belongs to (<aparte-elicitation> passes itself). A request whose target
is inside that chat reaches its presenter; a request with no target, or from a chat
with no presenter of its own, reaches the most recently registered one. Registering a
presenter again makes it the most recent.
Parameters
Section titled “Parameters”| Parameter | Type |
|---|---|
presenter | AparteElicitationPresenter | null |
owner? | HTMLElement |
Returns
Section titled “Returns”void
removeElicitationPresenter()
Section titled “removeElicitationPresenter()”removeElicitationPresenter(presenter): void;Defined in: packages/core/src/config/aparte-config.ts:1397
Withdraw ONE presenter, named, leaving any others registered.
This is what an unmounting <aparte-elicitation> needs and what
setElicitationPresenter(null) could not express: clearing the slot took every
other mounted chat’s presenter down with it. Removing a presenter that is not
registered is a no-op.
Parameters
Section titled “Parameters”| Parameter | Type |
|---|---|
presenter | AparteElicitationPresenter |
Returns
Section titled “Returns”void
getElicitationPresenter()
Section titled “getElicitationPresenter()”getElicitationPresenter(): AparteElicitationPresenter | undefined;Defined in: packages/core/src/config/aparte-config.ts:1405
The presenter a request with no target would reach — the most recently
registered one. Kept for the callers that ask “is anybody able to present?”.
Returns
Section titled “Returns”AparteElicitationPresenter | undefined
requestUserInput()
Section titled “requestUserInput()”requestUserInput(request): Promise<AparteElicitationResult>;Defined in: packages/core/src/config/aparte-config.ts:1451
Ask the person for typed input in the middle of a run, and wait for the answer. The
primitive behind ask_user and tool approval: the kind of question is its schema.
Resolves accept with the value, or decline when the person declines.
Rejects, with no answer, with an AparteElicitationAbortError (its name is
'AbortError') whose reason is 'aborted' — the turn was stopped, the signal fired,
or another request took the question away — or 'no-presenter', when nothing is mounted
to ask it (with a console warning, once). await it in a try, or attach a .catch().
The question goes to the presenter of the chat that holds request.target (see
setElicitationPresenter());
<aparte-elicitation> is the default one, and registers itself once it is in the DOM.
A chat shows one question at a time: a second request in the same chat waits until the
first is answered or ends, and requests with no target share one queue.
Parameters
Section titled “Parameters”| Parameter | Type |
|---|---|
request | AparteElicitationRequest |
Returns
Section titled “Returns”Promise<AparteElicitationResult>
reset()
Section titled “reset()”reset(): void;Defined in: packages/core/src/config/aparte-config.ts:1536
Put the configuration back to its defaults: the providers and the selected model,
the tools with their renderers and summaries, the renderers and render hooks, the
Markdown and highlight providers, the sanitizer, the system prompt, the locale, icons,
avatars, actions and host handlers, the conversation manager, the question presenters
and their queue. Three things stay: the transport, the key sources added with
registerKeyProvider() (an AparteClient’s
keyResolver among them), and the subscribe() listeners.
Returns
Section titled “Returns”void
Functions
Section titled “Functions”attachConfig()
Section titled “attachConfig()”function attachConfig(el, config): void;Defined in: packages/core/src/config/config-context.ts:83
Attach an instance config to el, making it a resolution boundary: every
component inside el resolves to config instead of the global singleton.
Idempotent; pass the same element to replace its config.
Anything already mounted inside el that implements AparteConfigAware
is told, because attaching a boundary silently rewrites what those children
resolve to and a registration they already made is now on the wrong object.
Parameters
Section titled “Parameters”| Parameter | Type |
|---|---|
el | HTMLElement |
config | AparteConfig |
Returns
Section titled “Returns”void
detachConfig()
Section titled “detachConfig()”function detachConfig(el): void;Defined in: packages/core/src/config/config-context.ts:101
Remove the instance-config boundary from el (e.g. in disconnectedCallback).
Components under el fall back to the next boundary up, or the global.
Registrants are told BEFORE they would silently re-resolve elsewhere, which is
the half that leaked: a wrapper’s unbind() detaches the boundary before the
framework removes the DOM, so by the time disconnectedCallback ran, the
element’s own resolveConfig(this) already returned the global — its
“am I still the registered one?” guard compared against the wrong config, found
no match, and left the instance config holding a removed element for good.
Parameters
Section titled “Parameters”| Parameter | Type |
|---|---|
el | HTMLElement |
Returns
Section titled “Returns”void
resolveConfig()
Section titled “resolveConfig()”function resolveConfig(el): AparteConfig;Defined in: packages/core/src/config/config-context.ts:134
Resolve the config governing el: the nearest ancestor boundary’s instance
config (including el itself), or aparteGlobalConfig when none is
present. Cheap — a single closest().
DO NOT cache this at connectedCallback. An earlier version of this comment
advised exactly that, and two elements followed it into a real bug: a framework
wrapper calls AparteChatHost.bind() — which is what runs attachConfig — from
its POST-mount hook (React useEffect, Vue onMounted, Svelte onMount,
Angular ngAfterViewInit), so children mounted in the same commit connect
BEFORE the boundary exists. A connect-time cache therefore freezes the global
config forever, and the config prop every wrapper advertises silently does
nothing for that element.
Resolve it live, in a getter. closest() on a shallow tree is not a cost worth
a correctness bug — aparte-chat-bubble has done it that way from the start, and
it is the one element that was never affected.
That advice covers READERS, and it is not enough on its own. An element that WRITES to its config — registering a presenter, a renderer, a keyed listener — cannot fix the ordering by resolving live, because the write already happened. Those implement AparteConfigAware and re-register when told. The reader/writer distinction is the one this file missed the first time round: the sweep that applied the advice above fixed every reader and left both writers broken.
Parameters
Section titled “Parameters”| Parameter | Type |
|---|---|
el | Element | null | undefined |
Returns
Section titled “Returns”runWithConfig()
Section titled “runWithConfig()”function runWithConfig<T>(config, fn): T;Defined in: packages/core/src/config/config-context.ts:149
Run fn with config as the ambient render config (restored after).
Type Parameters
Section titled “Type Parameters”| Type Parameter |
|---|
T |
Parameters
Section titled “Parameters”| Parameter | Type |
|---|---|
config | AparteConfig |
fn | () => T |
Returns
Section titled “Returns”T
contextConfig()
Section titled “contextConfig()”function contextConfig(el?): AparteConfig;Defined in: packages/core/src/config/config-context.ts:164
The ambient render config set by runWithConfig, else the config
resolved from el (when provided), else the global singleton. Capture it
synchronously at the top of a renderer — never after an await.
Parameters
Section titled “Parameters”| Parameter | Type |
|---|---|
el? | Element | null |
Returns
Section titled “Returns”subscribeConfigChange()
Section titled “subscribeConfigChange()”function subscribeConfigChange(el, handler): () => void;Defined in: packages/core/src/config/config-subscribe.ts:36
Parameters
Section titled “Parameters”| Parameter | Type |
|---|---|
el | Element |
handler | () => void |
Returns
Section titled “Returns”() => void
isSafeUrl()
Section titled “isSafeUrl()”function isSafeUrl(value, tag): boolean;Defined in: packages/core/src/config/sanitize.ts:166
Parameters
Section titled “Parameters”| Parameter | Type |
|---|---|
value | string |
tag | string |
Returns
Section titled “Returns”boolean
Variables
Section titled “Variables”APARTE_DEFAULT_BUBBLE_ACTIONS
Section titled “APARTE_DEFAULT_BUBBLE_ACTIONS”const APARTE_DEFAULT_BUBBLE_ACTIONS: {
copy: true;
retry: false;
edit: false;
feedback: false;
info: false;
};Defined in: packages/core/src/config/aparte-config.ts:70
The bubble-action defaults — copy on, everything else off.
The rule: an affordance core cannot honor end-to-end does not appear by
default. Core can copy text by itself; retry and edit only do something when a
host (AparteClient) re-sends and rewrites, and feedback/info only when the app
listens for aparte-feedback / aparte-message-info. Rendering them
unconditionally showed dead buttons in every display-only integration — ours
included, which is how we found it.
Exported so a consumer can read the defaults instead of hard-coding them.
Type Declaration
Section titled “Type Declaration”readonly copy: true = true;readonly retry: false = false;readonly edit: false = false;feedback
Section titled “feedback”readonly feedback: false = false;readonly info: false = false;APARTE_DEFAULT_HOST_HANDLERS
Section titled “APARTE_DEFAULT_HOST_HANDLERS”const APARTE_DEFAULT_HOST_HANDLERS: {
attachmentPreview: false;
};Defined in: packages/core/src/config/aparte-config.ts:86
The host-handler declarations — nothing declared.
Same rule as APARTE_DEFAULT_BUBBLE_ACTIONS, applied outside the action bar: an image tile you can click is a request core forwards to the app. Undeclared, it is not rendered (and the tile is not even signalled as clickable) instead of doing nothing.
Type Declaration
Section titled “Type Declaration”attachmentPreview
Section titled “attachmentPreview”readonly attachmentPreview: false = false;aparteGlobalConfig
Section titled “aparteGlobalConfig”const aparteGlobalConfig: AparteConfig;Defined in: packages/core/src/config/aparte-config.ts:1641
The page-wide configuration: every chat reads it unless an ancestor carries an instance of
its own (attachConfig). There is one per window, kept on window, so two copies of
the package on one page share it; off the browser (a server render, a test) each import
creates its own.
APARTE_HOST_ATTR
Section titled “APARTE_HOST_ATTR”const APARTE_HOST_ATTR: "data-aparte-host" = 'data-aparte-host';Defined in: packages/core/src/config/config-context.ts:22
Marks an element as an instance-config boundary (used by closest()).
APARTE_CONFIG_CHANGE
Section titled “APARTE_CONFIG_CHANGE”const APARTE_CONFIG_CHANGE: "aparte-config-change" = 'aparte-config-change';Defined in: packages/core/src/config/config-subscribe.ts:34
The event AparteConfig._notify() dispatches on window.
APARTE_DEFAULT_ICON_FALLBACKS
Section titled “APARTE_DEFAULT_ICON_FALLBACKS”const APARTE_DEFAULT_ICON_FALLBACKS: Record<AparteIconName, string> = APARTE_ICON_GLYPHS;Defined in: packages/core/src/config/icon-provider.ts:99
The default drawing for every name, assembled from icons/glyphs.ts.
getIcon() reads this by a COMPUTED key, so a bundler cannot tell which entries a
build reaches and keeps the object whole. That is the constraint that shapes the icon
set: what belongs here is what core itself draws, and nothing else — an icon nobody
renders would still ship to everybody. Extra glyphs are individual exports a consumer
imports by name, never members of this record.
APARTE_DEFAULT_LOCALE
Section titled “APARTE_DEFAULT_LOCALE”const APARTE_DEFAULT_LOCALE: AparteLocale;Defined in: packages/core/src/config/locale.ts:461
Default English Locale (Zero-dependency) Hardcoded to ensure the core works out-of-the-box.
defaultSanitizer
Section titled “defaultSanitizer”const defaultSanitizer: AparteSanitizer;Defined in: packages/core/src/config/sanitize.ts:423
The built-in sanitizer. Parses html with the platform DOMParser, rebuilds an
allowlisted tree, and re-serializes it. Falls back to a regex scrub only when
no DOMParser exists (non-browser runtime).
Interfaces
Section titled “Interfaces”AparteAction
Section titled “AparteAction”Defined in: packages/core/src/config/action-provider.ts:34
A custom action button, registered once via aparteGlobalConfig.registerAction(...)
and placed in the message (bubble) toolbar via zones.
Declarative and framework-agnostic: clicking it emits an aparte-action
CustomEvent (bubbles, composed) carrying { actionId, zone, … }, exactly like
the built-in retry/feedback buttons — so you wire it the same way in
React/Vue/Svelte/Angular and in vanilla. An optional onClick callback fires
alongside the event for imperative convenience.
For a button in the composer, write an <aparte-composer-action> in your markup and
listen for aparte-action-click — see that element’s docs.
Example
Section titled “Example”aparteGlobalConfig.registerAction({
id: 'share', icon: '<svg>…</svg>', label: 'Share',
zones: ['bubble'], bubble: { roles: ['assistant'] },
});
chatEl.addEventListener('aparte-action', (e) => {
if (e.detail.actionId === 'share') share(e.detail.messageId);
});Properties
Section titled “Properties”id: string;Defined in: packages/core/src/config/action-provider.ts:36
Stable id — echoed as actionId in the aparte-action event.
icon: string;Defined in: packages/core/src/config/action-provider.ts:43
Icon for the button:
- If it starts with
<, it is treated as raw HTML/SVG and used directly. - Otherwise it is treated as a key for
aparteGlobalConfig.getIcon(). If the provider doesn’t have the key, falls back toiconFallbackorid.
iconFallback?
Section titled “iconFallback?”optional iconFallback?: string;Defined in: packages/core/src/config/action-provider.ts:45
Inline SVG/HTML fallback used when the icon provider doesn’t have the key.
label: string;Defined in: packages/core/src/config/action-provider.ts:47
Accessible label (sets aria-label + title) — a locale key or a raw string.
order?
Section titled “order?”optional order?: number;Defined in: packages/core/src/config/action-provider.ts:49
Lower renders first among custom actions (they follow the built-ins).
zones: "bubble"[];Defined in: packages/core/src/config/action-provider.ts:51
Which zones this action appears in.
bubble?
Section titled “bubble?”optional bubble?: {
roles?: ("user" | "assistant")[];
};Defined in: packages/core/src/config/action-provider.ts:53
Bubble-toolbar placement (used when zones includes 'bubble').
roles?
Section titled “roles?”optional roles?: ("user" | "assistant")[];Bubble roles this action shows on. Default: both user and assistant.
onClick?
Section titled “onClick?”optional onClick?: (event, context?) => void;Defined in: packages/core/src/config/action-provider.ts:58
Optional imperative callback, fired alongside the aparte-action event.
Parameters
Section titled “Parameters”| Parameter | Type |
|---|---|
event | Event |
context? | unknown |
Returns
Section titled “Returns”void
AparteModelPreference
Section titled “AparteModelPreference”Defined in: packages/core/src/config/aparte-config.ts:90
Properties
Section titled “Properties”provider
Section titled “provider”provider: string;Defined in: packages/core/src/config/aparte-config.ts:91
model: string;Defined in: packages/core/src/config/aparte-config.ts:92
AparteModelPreferenceProvider
Section titled “AparteModelPreferenceProvider”Defined in: packages/core/src/config/aparte-config.ts:95
Properties
Section titled “Properties”save: (provider, model) => void;Defined in: packages/core/src/config/aparte-config.ts:97
Called whenever the selected provider+model changes
Parameters
Section titled “Parameters”| Parameter | Type |
|---|---|
provider | string |
model | string |
Returns
Section titled “Returns”void
load: () => AparteModelPreference | null;Defined in: packages/core/src/config/aparte-config.ts:99
Called on init to restore the previously saved selection. Return null if nothing stored.
Returns
Section titled “Returns”AparteModelPreference | null
AparteStreamingMarkdownRenderer
Section titled “AparteStreamingMarkdownRenderer”Defined in: packages/core/src/config/aparte-config.ts:108
Incremental Markdown renderer bound to a target element. Created once per
streaming message: tokens are fed via write() and parsed + appended to the
DOM incrementally (O(n) total — no full re-parse / innerHTML rebuild on every
token). end() flushes any pending text when the stream completes.
Methods
Section titled “Methods”write()
Section titled “write()”write(chunk): void;Defined in: packages/core/src/config/aparte-config.ts:110
Append a chunk of Markdown text — parsed incrementally, appended as DOM nodes.
Parameters
Section titled “Parameters”| Parameter | Type |
|---|---|
chunk | string |
Returns
Section titled “Returns”void
end(): void;Defined in: packages/core/src/config/aparte-config.ts:112
Finalize the stream (flush any pending text).
Returns
Section titled “Returns”void
AparteAvatarProvider
Section titled “AparteAvatarProvider”Defined in: packages/core/src/config/avatar-provider.ts:22
Avatar Provider Interface
Defines the contract for plugging custom avatar rendering into chat messages. Unlike the icon provider (which returns HTML strings), the avatar provider receives the live host element and fills it with whatever DOM the consumer wants — including framework components mounted via createComponent (Angular), createRoot (React), etc.
Example
Section titled “Example”aparteGlobalConfig.setAvatarProvider({
render: (role, host) => {
if (role === 'assistant') {
const ref = createComponent(MascotComponent, { hostElement: host });
ref.setInput('variant', 'classic');
return () => ref.destroy();
}
host.textContent = 'You';
},
});Methods
Section titled “Methods”render()
Section titled “render()”render(role, host): void | (() => void);Defined in: packages/core/src/config/avatar-provider.ts:33
Fill the avatar host element with custom DOM.
Parameters
Section titled “Parameters”| Parameter | Type | Description |
|---|---|---|
role | "user" | "assistant" | The message role this avatar represents. |
host | HTMLElement | The .aparte-avatar element. Already styled (size, radius) via CSS variables. The provider owns its inner content. |
Returns
Section titled “Returns”void | (() => void)
- Optional cleanup function. Called when the message is detached or re-rendered, so live components can be disposed cleanly.
AparteConfigAware
Section titled “AparteConfigAware”Defined in: packages/core/src/config/config-context.ts:52
Implemented by an element that REGISTERS something on its config rather than only reading from it — an elicitation presenter, a renderer, a listener keyed on the config object.
Reading is safe without this hook: resolveConfig(this) at every use site
always sees the current boundary. WRITING is not. A write happens once, into
whichever config was resolvable at that moment — and under all four wrappers
that moment is before the boundary exists, because AparteChatHost.bind()
runs from a post-mount hook. So the write lands on the global singleton and
the instance config never gets it.
That is not hypothetical: <aparte-elicitation> registered its presenter at
connect, so under every wrapper requestUserInput() found no presenter on the
instance config and answered the model cancel — the model was told the user
refused while the user was shown nothing at all.
Implement this and re-do the registration: move it off previous, put it on
next. Both attachConfig and detachConfig call it, so the same
method handles teardown, which is where the mirror-image leak lived.
Methods
Section titled “Methods”aparteConfigChanged()
Section titled “aparteConfigChanged()”aparteConfigChanged(next, previous): void;Defined in: packages/core/src/config/config-context.ts:53
Parameters
Section titled “Parameters”| Parameter | Type |
|---|---|
next | AparteConfig |
previous | AparteConfig |
Returns
Section titled “Returns”void
AparteElicitationFieldContext
Section titled “AparteElicitationFieldContext”Defined in: packages/core/src/config/elicitation-field-renderer.ts:6
What the panel gives a custom field renderer.
Properties
Section titled “Properties”readonly optional key?: string;Defined in: packages/core/src/config/elicitation-field-renderer.ts:12
The form key this field answers, in an object (multi-question) schema.
undefined for a single-field request, where the panel’s message is the
question.
Methods
Section titled “Methods”notifyChange()
Section titled “notifyChange()”notifyChange(): void;Defined in: packages/core/src/config/elicitation-field-renderer.ts:20
Call whenever your field’s value changes.
The panel re-reads isComplete() on every change to enable or disable the
send button — a field that never notifies is a field whose answer can never
be submitted.
Returns
Section titled “Returns”void
AparteElicitationFieldControl
Section titled “AparteElicitationFieldControl”Defined in: packages/core/src/config/elicitation-field-renderer.ts:26
A field you rendered, and the three things the panel needs from it.
Properties
Section titled “Properties”readonly el: HTMLElement;Defined in: packages/core/src/config/elicitation-field-renderer.ts:28
The element to place in the panel.
Methods
Section titled “Methods”getValue()
Section titled “getValue()”getValue(): unknown;Defined in: packages/core/src/config/elicitation-field-renderer.ts:30
The current answer, shaped as the field’s schema kind implies.
Returns
Section titled “Returns”unknown
isComplete()
Section titled “isComplete()”isComplete(): boolean;Defined in: packages/core/src/config/elicitation-field-renderer.ts:32
Whether the answer is usable — gates the send button.
Returns
Section titled “Returns”boolean
focus()?
Section titled “focus()?”optional focus(): void;Defined in: packages/core/src/config/elicitation-field-renderer.ts:34
Focus the input. Called when the panel opens on this field.
Returns
Section titled “Returns”void
AparteIconProvider
Section titled “AparteIconProvider”Defined in: packages/core/src/config/icon-provider.ts:17
Properties
Section titled “Properties”optional copy?: () => string;Defined in: packages/core/src/config/icon-provider.ts:24
Copy button icon
Returns
Section titled “Returns”string
check?
Section titled “check?”optional check?: () => string;Defined in: packages/core/src/config/icon-provider.ts:26
Success/check icon
Returns
Section titled “Returns”string
optional send?: () => string;Defined in: packages/core/src/config/icon-provider.ts:28
Send message icon
Returns
Section titled “Returns”string
loading?
Section titled “loading?”optional loading?: () => string;Defined in: packages/core/src/config/icon-provider.ts:30
Loading/spinner indicator
Returns
Section titled “Returns”string
error?
Section titled “error?”optional error?: () => string;Defined in: packages/core/src/config/icon-provider.ts:32
Error indicator
Returns
Section titled “Returns”string
expand?
Section titled “expand?”optional expand?: () => string;Defined in: packages/core/src/config/icon-provider.ts:34
Expand/show more icon
Returns
Section titled “Returns”string
collapse?
Section titled “collapse?”optional collapse?: () => string;Defined in: packages/core/src/config/icon-provider.ts:36
Collapse/show less icon
Returns
Section titled “Returns”string
terminal?
Section titled “terminal?”optional terminal?: () => string;Defined in: packages/core/src/config/icon-provider.ts:38
Terminal/command prompt icon
Returns
Section titled “Returns”string
paperclip?
Section titled “paperclip?”optional paperclip?: () => string;Defined in: packages/core/src/config/icon-provider.ts:40
File attachment / paperclip icon (used by upload plugin)
Returns
Section titled “Returns”string
image?
Section titled “image?”optional image?: () => string;Defined in: packages/core/src/config/icon-provider.ts:42
Image file icon (used by upload plugin)
Returns
Section titled “Returns”string
optional file?: () => string;Defined in: packages/core/src/config/icon-provider.ts:44
Generic file icon (used by upload plugin)
Returns
Section titled “Returns”string
scrollDown?
Section titled “scrollDown?”optional scrollDown?: () => string;Defined in: packages/core/src/config/icon-provider.ts:46
Scroll to bottom button icon
Returns
Section titled “Returns”string
retry?
Section titled “retry?”optional retry?: () => string;Defined in: packages/core/src/config/icon-provider.ts:48
Retry / regenerate icon
Returns
Section titled “Returns”string
optional edit?: () => string;Defined in: packages/core/src/config/icon-provider.ts:50
Edit / pencil icon
Returns
Section titled “Returns”string
thumbUp?
Section titled “thumbUp?”optional thumbUp?: () => string;Defined in: packages/core/src/config/icon-provider.ts:52
Thumbs up / positive feedback icon
Returns
Section titled “Returns”string
thumbDown?
Section titled “thumbDown?”optional thumbDown?: () => string;Defined in: packages/core/src/config/icon-provider.ts:54
Thumbs down / negative feedback icon
Returns
Section titled “Returns”string
prevBranch?
Section titled “prevBranch?”optional prevBranch?: () => string;Defined in: packages/core/src/config/icon-provider.ts:56
Previous branch arrow
Returns
Section titled “Returns”string
nextBranch?
Section titled “nextBranch?”optional nextBranch?: () => string;Defined in: packages/core/src/config/icon-provider.ts:58
Next branch arrow
Returns
Section titled “Returns”string
optional tool?: () => string;Defined in: packages/core/src/config/icon-provider.ts:60
Tool call indicator (wrench)
Returns
Section titled “Returns”string
close?
Section titled “close?”optional close?: () => string;Defined in: packages/core/src/config/icon-provider.ts:62
Close / failed / rejected (✕)
Returns
Section titled “Returns”string
optional stop?: () => string;Defined in: packages/core/src/config/icon-provider.ts:64
Stop / halt streaming (■)
Returns
Section titled “Returns”string
optional info?: () => string;Defined in: packages/core/src/config/icon-provider.ts:66
Informational notice (ⓘ)
Returns
Section titled “Returns”string
archive?
Section titled “archive?”optional archive?: () => string;Defined in: packages/core/src/config/icon-provider.ts:68
Archive a conversation
Returns
Section titled “Returns”string
unarchive?
Section titled “unarchive?”optional unarchive?: () => string;Defined in: packages/core/src/config/icon-provider.ts:70
Restore an archived conversation
Returns
Section titled “Returns”string
download?
Section titled “download?”optional download?: () => string;Defined in: packages/core/src/config/icon-provider.ts:72
Download / save to disk
Returns
Section titled “Returns”string
optional more?: () => string;Defined in: packages/core/src/config/icon-provider.ts:74
A row’s actions button (⋯)
Returns
Section titled “Returns”string
optional pin?: () => string;Defined in: packages/core/src/config/icon-provider.ts:76
Pin a conversation
Returns
Section titled “Returns”string
trash?
Section titled “trash?”optional trash?: () => string;Defined in: packages/core/src/config/icon-provider.ts:78
Delete (a bin)
Returns
Section titled “Returns”string
optional menu?: () => string;Defined in: packages/core/src/config/icon-provider.ts:80
Open a navigation drawer (☰) — the app header’s toggle
Returns
Section titled “Returns”string
alertTriangle?
Section titled “alertTriangle?”optional alertTriangle?: () => string;Defined in: packages/core/src/config/icon-provider.ts:82
A warning triangle — the alert recipe’s icon
Returns
Section titled “Returns”string
pause?
Section titled “pause?”optional pause?: () => string;Defined in: packages/core/src/config/icon-provider.ts:84
Paused — the tool row’s state while a person is asked to decide
Returns
Section titled “Returns”string
Type Aliases
Section titled “Type Aliases”AparteActionZone
Section titled “AparteActionZone”type AparteActionZone = "bubble";Defined in: packages/core/src/config/action-provider.ts:10
Zones where a custom action can appear — the message (bubble) toolbar, and only it.
The type is a single member on purpose: a composer button is an element the consumer
writes in their own markup (<aparte-composer-action>), not a registry entry, so the
composer never asked the registry for anything. The zone stays a named type rather
than the bare literal because getActions(zone) reads as a lookup, and a second zone
(a toolbar of core’s own, say) would be added here.
AparteMarkdownProvider
Section titled “AparteMarkdownProvider”type AparteMarkdownProvider = (raw) => string;Defined in: packages/core/src/config/aparte-config.ts:38
Parameters
Section titled “Parameters”| Parameter | Type |
|---|---|
raw | string |
Returns
Section titled “Returns”string
AparteHighlightProvider
Section titled “AparteHighlightProvider”type AparteHighlightProvider =
| ((code, lang) => string)
| ((code, lang) => Promise<string>);Defined in: packages/core/src/config/aparte-config.ts:39
AparteSystemPromptVarsProvider
Section titled “AparteSystemPromptVarsProvider”type AparteSystemPromptVarsProvider = () => Record<string, string>;Defined in: packages/core/src/config/aparte-config.ts:42
Returns
Section titled “Returns”Record<string, string>
AparteKeyProvider
Section titled “AparteKeyProvider”type AparteKeyProvider = (providerId) =>
| string
| Record<string, string>
| undefined
| null
| Promise<string | Record<string, string> | undefined | null>;Defined in: packages/core/src/config/aparte-config.ts:54
How the page answers “what are this provider’s credentials?”.
A bare key, or the same { apiKey, endpoint } record the transport reads
(readAuth) and fetchModels accepts. The record is not a nicety: a consumer
who points a preset at their own host — a corporate proxy, a self-hosted vLLM,
an LM Studio box — configures it as endpoint, and while this channel could
only carry a string, refreshProviderModels sent GET {vendor default}/models
with the key that host had been given.
Parameters
Section titled “Parameters”| Parameter | Type |
|---|---|
providerId | string |
Returns
Section titled “Returns”| string
| Record<string, string>
| undefined
| null
| Promise<string | Record<string, string> | undefined | null>
AparteStreamingMarkdownProvider
Section titled “AparteStreamingMarkdownProvider”type AparteStreamingMarkdownProvider = (target) => AparteStreamingMarkdownRenderer;Defined in: packages/core/src/config/aparte-config.ts:121
Factory for an AparteStreamingMarkdownRenderer: given a target element,
returns a renderer that appends parsed Markdown into it. Supplied by an
opt-in provider package (e.g. @aparte/provider-streaming-markdown); when none
is registered the chat falls back to the one-shot AparteMarkdownProvider.
Parameters
Section titled “Parameters”| Parameter | Type |
|---|---|
target | HTMLElement |
Returns
Section titled “Returns”AparteStreamingMarkdownRenderer
AparteAttachmentRenderer
Section titled “AparteAttachmentRenderer”type AparteAttachmentRenderer = (attachment) => string | HTMLElement;Defined in: packages/core/src/config/attachment-renderer.ts:28
Attachment Renderer
Replace the chip rendered for each attachment on a user message — the default
is an image thumbnail or a file chip (extension + name). Return an HTML
string or a ready HTMLElement (charter §6 render hooks:
string | HTMLElement), e.g. a PDF page preview, an audio player, or a richer
card. Called once per attachment.
When you provide a renderer you own the markup AND the interactions: the
built-in image-tile click that dispatches aparte-attachment-preview is NOT
wired for custom output — dispatch it yourself (bubbles, composed) or handle
clicks your own way.
Parameters
Section titled “Parameters”| Parameter | Type |
|---|---|
attachment | AparteAttachment |
Returns
Section titled “Returns”string | HTMLElement
Example
Section titled “Example”aparteGlobalConfig.setAttachmentRenderer((att) => {
if (att.type === 'application/pdf') {
const el = document.createElement('div');
el.className = 'my-pdf-chip';
el.textContent = att.name;
return el;
}
return `<div class="my-file">${att.name}</div>`;
});AparteBubbleShellRenderer
Section titled “AparteBubbleShellRenderer”type AparteBubbleShellRenderer = (ctx) => string | HTMLElement;Defined in: packages/core/src/config/bubble-shell-renderer.ts:74
Bubble-Shell Renderer (advanced)
Replace the structural skeleton of <aparte-chat-bubble> — the markup the
bubble renders once and then populates — while keeping all of its behavior
(segments, streaming, action bar, avatar, branch picker). This is the
whole-structure override that renderBubble (wrapper-level,
replaces the element entirely) is not: here the native bubble stays in charge.
Return an HTML string or a ready HTMLElement (charter §6:
string | HTMLElement). Because the bubble queries known class hooks after
rendering the shell, your shell MUST honor this contract:
- Root element must be
.aparte-message(it carriesdata-roleand receivesdata-streaming/data-error; the styles target it). - Include the region hooks you want the bubble to populate, in the order the default
shell renders them. Any you omit simply stay empty (every lookup is null-guarded —
graceful degradation):
.aparte-avatar— filled by the avatar provider / initial.aparte-name— the display name (you set it fromctx.name).aparte-timestamp— the formatted time.aparte-attachments— user-message attachment chips.aparte-message-content— the painted content box, and it HOLDS the next three (.aparte-segments,.aparte-content,.aparte-waiting): the background, the radius and the padding of a user message are declared on this box, so rendering the three as its siblings leaves a message with no bubble — every behaviour intact, the look gone. The bubble hides the box when the turn has nothing to show, so an attachments-only message does not draw an empty coloured rectangle.aparte-segments— streamed/structured segments.aparte-content— simple markdown content.aparte-waiting— the dots between “user sends” and the first token. The bubble only SHOWS and HIDES this region; the markup that paints is yours: a.aparte-dotsspan holding three.aparte-dotspans (the stylesheet animates them), and a.aparte-sr-onlyspan for the label the screen reader hears. With the label alone the region has nothing to draw and the reader watches an empty box while the model composes.aparte-footer— the row that holds the branch picker and the actions.aparte-branch-picker— with.aparte-branch-prev/.aparte-branch-label/.aparte-branch-nextfor sibling navigation, and.aparte-branch-status(a.aparte-sr-onlyspan witharia-live="polite") for the announcement.aparte-action-bar— copy/retry/edit/… + custom actions
Omitting most of these costs you something you can see. The two that fail silently
are .aparte-waiting and .aparte-branch-status: without the first there is no
“thinking” state at all while the model composes, and without the second a
screen-reader user gets no word that the branch moved — the arrows deliberately do
not take focus, so nothing else announces it.
ARIA is the one thing this list does NOT ask of you. A shell is markup, and a contract
that also demanded a role and a name would lose both the first time an author forgot
one, silently. So the bubble writes role="article" and the accessible name onto your
root itself, after your shell renders — unless the root already carries a role, which
is how you override it: the bubble then leaves the accessible name to you as well.
Two more classes carry the DEFAULT LAYOUT and nothing else — the bubble never queries
them, so a shell that lays itself out differently is free to drop both: .aparte-body
(the column beside the avatar, and the containing block the footer floats in) and
.aparte-header (the name and time row). Keep them and the default stylesheet lays
your shell out like the native bubble.
Prefer renderBubble (wrapper) when you want a fully custom element; use this
when you want to keep the native bubble’s machinery but reshape its layout.
Parameters
Section titled “Parameters”| Parameter | Type | Description |
|---|---|---|
ctx | { role: "user" | "assistant"; name: string; avatarInitial: string; } | - |
ctx.role | "user" | "assistant" | ’user' |
ctx.name | string | Display name for the header. |
ctx.avatarInitial | string | Default one-letter avatar fallback. |
Returns
Section titled “Returns”string | HTMLElement
HTML string or a DOM element whose root is .aparte-message.
AparteElicitationFieldRenderer
Section titled “AparteElicitationFieldRenderer”type AparteElicitationFieldRenderer = (field, ctx) =>
| AparteElicitationFieldControl
| null;Defined in: packages/core/src/config/elicitation-field-renderer.ts:75
Elicitation Field Renderer
Replace ONE field of the question panel — a choice, a yes/no, a free-text answer — while the panel keeps everything around it: placement in the composer, the accept/decline/cancel contract, the send-button gating, focus, and the teardown when a turn is stopped.
Until this existed the surface was all-or-nothing: the built-in panel, or
setElicitationPresenter and you reimplemented every one of those. Every other
customisation point in this library is a hook (charter §6), and this one was
missing.
Return null to let the built-in render that field, which is what makes it
practical to override a single kind:
Parameters
Section titled “Parameters”| Parameter | Type |
|---|---|
field | AparteElicitationField |
ctx | AparteElicitationFieldContext |
Returns
Section titled “Returns”| AparteElicitationFieldControl
| null
Example
Section titled “Example”aparteGlobalConfig.setElicitationFieldRenderer((field, ctx) => {
if (field.type !== 'enum') return null; // built-in handles the rest
const el = document.createElement('div');
el.className = 'my-chips';
let picked = '';
for (const opt of field.options) {
const b = document.createElement('button');
b.type = 'button';
b.textContent = opt.label ?? opt.value;
b.onclick = () => { picked = opt.value; ctx.notifyChange(); };
el.appendChild(b);
}
return { el, getValue: () => picked, isComplete: () => picked !== '' };
});
**Why this returns a control and not `string | HTMLElement`** like the render
hooks in charter §6: a field has to hand back a VALUE. A hook that must also read
the user's input is a control, not a decoration, and pretending otherwise would
mean the panel scraping your markup for inputs by convention — which is a
contract that breaks silently the first time someone styles it differently.AparteErrorRenderer
Section titled “AparteErrorRenderer”type AparteErrorRenderer = (ctx) => string | HTMLElement;Defined in: packages/core/src/config/error-renderer.ts:20
Error Renderer
Replace the content of an error bubble — the default is an icon + “Error” title
- message (+ details). Return an HTML string or a ready HTMLElement
(charter §6 render hooks:
string | HTMLElement), e.g. a friendly message with your own “Try again” button. This drives the built-inerrorsegment renderer, so it’s the one place to customize error UI (rather than registering a segment renderer for theerrortype yourself). The bubble also reflectsdata-erroron its.aparte-messagewhile an error segment is present, for CSS theming.
Parameters
Section titled “Parameters”| Parameter | Type | Description |
|---|---|---|
ctx | { message: string; details?: string; } | - |
ctx.message | string | Human-readable error message (the error segment’s content). |
ctx.details? | string | Optional error code/details (the error segment’s details). |
Returns
Section titled “Returns”string | HTMLElement
Example
Section titled “Example”aparteGlobalConfig.setErrorRenderer(({ message }) => {
const el = document.createElement('div');
el.className = 'my-error';
el.textContent = `Something went wrong: ${message}`;
return el;
});AparteIconName
Section titled “AparteIconName”type AparteIconName = keyof AparteIconProvider;Defined in: packages/core/src/config/icon-provider.ts:88
Icon names available in the provider
AparteLocale
Section titled “AparteLocale”type AparteLocale = {
inputPlaceholder: string;
sendButton: string;
copy: string;
copied: string;
retry: string;
thinking: string;
typing: string;
error: string;
running: string;
run: string;
file: string;
roleNameUser: string;
roleNameAssistant: string;
yourMessage: string;
assistantResponse: string;
messageActions: string;
edit: string;
editConfirm: string;
editCancel: string;
feedbackPositive: string;
feedbackNegative: string;
previousResponse: string;
nextResponse: string;
approveTool?: string;
rejectTool?: string;
messageInfo?: string;
newChat: string;
loadingConversations: string;
conversationList?: string;
loadingConversation: string;
deleteConversation: string;
archiveConversation?: string;
unarchiveConversation?: string;
conversationActions?: string;
renameConversation?: string;
conversationTitle?: string;
pinConversation?: string;
unpinConversation?: string;
deleteConversationConfirm?: string;
cancel?: string;
conversationGroupPinned?: string;
conversationGroupToday?: string;
conversationGroupYesterday?: string;
conversationGroupWeek?: string;
conversationGroupMonth?: string;
scrollRailLabel?: string;
sidebarLabel?: string;
splitHandleLabel?: string;
transcript?: string;
elicitationOther?: string;
elicitationOtherPlaceholder?: string;
elicitationOtherLabel?: string;
submitButton?: string;
stopButton?: string;
elicitationRecommended?: string;
elicitationSkip?: string;
elicitationYes?: string;
elicitationNo?: string;
elicitationAnswerLabel?: string;
approvalInstructionPlaceholder?: string;
approvalAsk?: string;
scrollToBottom?: string;
suggestionsLabel?: string;
contextLabel?: string;
compactionSummaryTitle?: string;
approvalWaiting?: string;
toolRunning?: string;
toolCompleted?: string;
toolRejected?: string;
toolStopped?: string;
toolFailed?: string;
toolInput?: string;
toolOutput?: string;
approvalOptionsLabel?: string;
approvalArgsLabel?: string;
actionUpload?: string;
removeAttachment?: string;
selectSearchPlaceholder?: string;
selectSearchLabel?: string;
loading?: string;
modelSelectorPlaceholder?: string;
approvalModeLabel?: string;
download?: string;
preview?: string;
code?: string;
generating?: string;
rebuildingPreview?: string;
previewPending?: string;
sandboxError?: string;
sandboxErrorHint?: string;
tag?: string;
direction?: "ltr" | "rtl";
};Defined in: packages/core/src/config/locale.ts:33
Every translatable string core itself renders — the CLOSED list.
Core keeps only the English default in memory (APARTE_DEFAULT_LOCALE); other
languages arrive through aparteGlobalConfig.setLocale().
Closed, and an alias rather than an interface, on purpose. This used to end with
[key: string]: string | undefined, and that one line disabled the only
compile-time check the locale had: AparteConfig.t(key: keyof AparteLocale) looks
airtight, but with an index signature keyof widens to string and EVERY literal
typechecks. A renamed key compiled clean, t() returned '' at runtime, and the UI
rendered an empty label with no error and no warning — which is how submitButton,
stopButton and actionUpload each shipped read-but-never-declared, the last one
reported by a user from a live language switcher.
The open half is AparteLocaleExtensions, and an ALIAS is what lets the two
meet: TypeScript gives a type alias an implicit index signature and an interface
none, so only this form is assignable to the extensions record that
setLocale/extendLocale accept and getLocale returns.
Eleven keys here are rendered by no core file — the artifact card’s six, its two
sandbox lines, the compaction summary’s title, the approval mode picker’s label and the
model selector’s placeholder, all drawn by a plugin. They belong in this bag anyway: the
locale is one flat object every package shares, so a translator fills one record and
@aparte/locale-fr needs no companion per plugin. They are the
exception rather than the pattern, though, and a closed one: a plugin of your own
reads its strings off getLocale() and defaults them at the call site (the
localization guide shows it), and check:locale-keys holds those eleven in
PLUGIN_OWNED and refuses a twelfth. The reason is that a key here is a published name
before it is a word: it ships in every locale package, and the frozen surface then
keeps it for two releases.
Properties
Section titled “Properties”inputPlaceholder
Section titled “inputPlaceholder”inputPlaceholder: string;Defined in: packages/core/src/config/locale.ts:35
sendButton
Section titled “sendButton”sendButton: string;Defined in: packages/core/src/config/locale.ts:36
copy: string;Defined in: packages/core/src/config/locale.ts:39
copied
Section titled “copied”copied: string;Defined in: packages/core/src/config/locale.ts:40
retry: string;Defined in: packages/core/src/config/locale.ts:41
thinking
Section titled “thinking”thinking: string;Defined in: packages/core/src/config/locale.ts:45
The label of a reasoning block, live or settled (default: “Thinking”)
typing
Section titled “typing”typing: string;Defined in: packages/core/src/config/locale.ts:47
What the status line says while a reply is being written, when it carries no text (default: “Typing”)
error: string;Defined in: packages/core/src/config/locale.ts:48
running
Section titled “running”running: string;Defined in: packages/core/src/config/locale.ts:49
run: string;Defined in: packages/core/src/config/locale.ts:52
file: string;Defined in: packages/core/src/config/locale.ts:55
roleNameUser
Section titled “roleNameUser”roleNameUser: string;Defined in: packages/core/src/config/locale.ts:59
Display name shown above the user’s messages (default: “You”)
roleNameAssistant
Section titled “roleNameAssistant”roleNameAssistant: string;Defined in: packages/core/src/config/locale.ts:61
Display name shown above the assistant’s messages (default: “Assistant”)
yourMessage
Section titled “yourMessage”yourMessage: string;Defined in: packages/core/src/config/locale.ts:64
assistantResponse
Section titled “assistantResponse”assistantResponse: string;Defined in: packages/core/src/config/locale.ts:65
messageActions
Section titled “messageActions”messageActions: string;Defined in: packages/core/src/config/locale.ts:66
edit: string;Defined in: packages/core/src/config/locale.ts:69
editConfirm
Section titled “editConfirm”editConfirm: string;Defined in: packages/core/src/config/locale.ts:70
editCancel
Section titled “editCancel”editCancel: string;Defined in: packages/core/src/config/locale.ts:71
feedbackPositive
Section titled “feedbackPositive”feedbackPositive: string;Defined in: packages/core/src/config/locale.ts:72
feedbackNegative
Section titled “feedbackNegative”feedbackNegative: string;Defined in: packages/core/src/config/locale.ts:73
previousResponse
Section titled “previousResponse”previousResponse: string;Defined in: packages/core/src/config/locale.ts:74
nextResponse
Section titled “nextResponse”nextResponse: string;Defined in: packages/core/src/config/locale.ts:75
approveTool?
Section titled “approveTool?”optional approveTool?: string;Defined in: packages/core/src/config/locale.ts:77
Approve button on a tool awaiting human approval (default: “Approve”)
rejectTool?
Section titled “rejectTool?”optional rejectTool?: string;Defined in: packages/core/src/config/locale.ts:79
Reject button on a tool awaiting human approval (default: “Reject”)
messageInfo?
Section titled “messageInfo?”optional messageInfo?: string;Defined in: packages/core/src/config/locale.ts:81
Aria-label / tooltip for the message info (“i”) action button (default: “Details”)
newChat
Section titled “newChat”newChat: string;Defined in: packages/core/src/config/locale.ts:85
Default title for a new conversation (default: “New Chat”)
loadingConversations
Section titled “loadingConversations”loadingConversations: string;Defined in: packages/core/src/config/locale.ts:87
Read by a screen reader while the conversation list is on its way (default: “Loading conversations”)
conversationList?
Section titled “conversationList?”optional conversationList?: string;Defined in: packages/core/src/config/locale.ts:89
Accessible name of the conversation list, a navigation landmark (default: “Conversations”)
loadingConversation
Section titled “loadingConversation”loadingConversation: string;Defined in: packages/core/src/config/locale.ts:91
Read by a screen reader while a conversation’s messages are on their way (default: “Loading the conversation”)
deleteConversation
Section titled “deleteConversation”deleteConversation: string;Defined in: packages/core/src/config/locale.ts:97
The “Delete” item of a row’s menu (default: “Delete”). Used to be the aria-label of a permanent ✕ on every row (“Delete conversation”); the menu is named after the row, so the item carries only the verb.
archiveConversation?
Section titled “archiveConversation?”optional archiveConversation?: string;Defined in: packages/core/src/config/locale.ts:99
The “Archive” item of a row’s menu (default: “Archive”)
unarchiveConversation?
Section titled “unarchiveConversation?”optional unarchiveConversation?: string;Defined in: packages/core/src/config/locale.ts:101
The same item on an archived row (default: “Unarchive”)
conversationActions?
Section titled “conversationActions?”optional conversationActions?: string;Defined in: packages/core/src/config/locale.ts:103
Accessible name of the ⋯ button that opens a row’s menu (default: “Conversation actions”)
renameConversation?
Section titled “renameConversation?”optional renameConversation?: string;Defined in: packages/core/src/config/locale.ts:105
The “Rename” item of a row’s menu (default: “Rename”)
conversationTitle?
Section titled “conversationTitle?”optional conversationTitle?: string;Defined in: packages/core/src/config/locale.ts:107
Accessible name of the inline input a rename opens (default: “Conversation title”)
pinConversation?
Section titled “pinConversation?”optional pinConversation?: string;Defined in: packages/core/src/config/locale.ts:109
The “Pin” item of a row’s menu (default: “Pin”)
unpinConversation?
Section titled “unpinConversation?”optional unpinConversation?: string;Defined in: packages/core/src/config/locale.ts:111
The same item on a pinned row (default: “Unpin”)
deleteConversationConfirm?
Section titled “deleteConversationConfirm?”optional deleteConversationConfirm?: string;Defined in: packages/core/src/config/locale.ts:117
The question asked before a delete (default: “Delete “{title}”?”). {title} is
replaced with the row’s title; a delete is the one action of the menu that asks
first, because it is the one that cannot be undone.
cancel?
Section titled “cancel?”optional cancel?: string;Defined in: packages/core/src/config/locale.ts:119
The button that declines that question (default: “Cancel”)
conversationGroupPinned?
Section titled “conversationGroupPinned?”optional conversationGroupPinned?: string;Defined in: packages/core/src/config/locale.ts:121
Heading of the pinned rows, which come first (default: “Pinned”)
conversationGroupToday?
Section titled “conversationGroupToday?”optional conversationGroupToday?: string;Defined in: packages/core/src/config/locale.ts:123
Heading of the rows updated today (default: “Today”)
conversationGroupYesterday?
Section titled “conversationGroupYesterday?”optional conversationGroupYesterday?: string;Defined in: packages/core/src/config/locale.ts:125
… yesterday (default: “Yesterday”)
conversationGroupWeek?
Section titled “conversationGroupWeek?”optional conversationGroupWeek?: string;Defined in: packages/core/src/config/locale.ts:127
… in the seven days before that (default: “Previous 7 days”)
conversationGroupMonth?
Section titled “conversationGroupMonth?”optional conversationGroupMonth?: string;Defined in: packages/core/src/config/locale.ts:129
… in the thirty days before that (default: “Previous 30 days”). Older rows are headed by their month, formatted with tag.
scrollRailLabel?
Section titled “scrollRailLabel?”optional scrollRailLabel?: string;Defined in: packages/core/src/config/locale.ts:133
Accessible name of <aparte-scroll-rail>, the ticks beside the transcript (default: “Conversation outline”)
sidebarLabel?
Section titled “sidebarLabel?”optional sidebarLabel?: string;Defined in: packages/core/src/config/locale.ts:135
Accessible name of <aparte-sidebar> (default: “Conversations”)
splitHandleLabel?
Section titled “splitHandleLabel?”optional splitHandleLabel?: string;Defined in: packages/core/src/config/locale.ts:137
Accessible name of the seam between a split’s two panes (default: “Resize the panes”)
transcript?
Section titled “transcript?”optional transcript?: string;Defined in: packages/core/src/config/locale.ts:145
Accessible name of the transcript itself (default: “Transcript”).
The scroll surface is a tab stop, because in WebKit a scrollable region that is not focusable cannot be scrolled from the keyboard at all. A tab stop with no name is announced as “group”, so the name ships with the tab stop, not after it.
elicitationOther?
Section titled “elicitationOther?”optional elicitationOther?: string;Defined in: packages/core/src/config/locale.ts:149
The free-text fallback option in a choice (default: “Other…“)
elicitationOtherPlaceholder?
Section titled “elicitationOtherPlaceholder?”optional elicitationOtherPlaceholder?: string;Defined in: packages/core/src/config/locale.ts:151
Placeholder of the free-text input that option reveals (default: “Type your answer…“)
elicitationOtherLabel?
Section titled “elicitationOtherLabel?”optional elicitationOtherLabel?: string;Defined in: packages/core/src/config/locale.ts:153
Accessible name of that input, which has no visible label (default: “Custom answer”)
submitButton?
Section titled “submitButton?”optional submitButton?: string;Defined in: packages/core/src/config/locale.ts:162
The send button while a question panel is open, where it submits an ANSWER rather than sending a message (default: “Submit”).
The component has been reading this key since the panel API existed; it was
never declared, so t() returned "" and the hardcoded fallback showed. A key
read and never declared is worse than a literal: it looks translated.
stopButton?
Section titled “stopButton?”optional stopButton?: string;Defined in: packages/core/src/config/locale.ts:178
The cancel/stop button that replaces send while a turn is streaming (default: “Stop”).
aparte-composer-cancel has been reading this key since it existed and it was
never declared — the same defect this file already records for submitButton
one entry up, found again while auditing a different question. So it has never
been translatable in ANY language, not even after a full reload: t() returned
nothing and the || 'Stop' fallback rendered every time.
The button carries no visible text — this string is its aria-label and its
title. Which is exactly why the gap survived: nothing on screen was in the
wrong language, so only a screen-reader user or someone hovering would ever
have met it. Most of the composer’s translatable surface is like this.
elicitationRecommended?
Section titled “elicitationRecommended?”optional elicitationRecommended?: string;Defined in: packages/core/src/config/locale.ts:188
The tag a recommended option wears beside its label (default: “Recommended”).
Said, not only tinted: a tint is a hint the eye may miss and a screen reader
never gets.
(elicitationNext lived here until 2026-08-28, for the composer’s button while a
form had questions ahead. That meaning is gone with the button’s “advance” mode
— the chips are the navigation — so the key went with it, not deprecated.)
elicitationSkip?
Section titled “elicitationSkip?”optional elicitationSkip?: string;Defined in: packages/core/src/config/locale.ts:199
The affordance that declines the request (default: “Skip”).
“Skip” reads as “skip THIS one” on a form of several questions, while it
declines the whole request — including questions already answered. That is MCP’s
decline and the right behaviour. It was briefly renamed to carry the warning;
reverted, because the RECEIPT now shows the outcome unambiguously (one declined
row, no question attached), so the label no longer has to do that work — and
“Skip” is the short conventional word for it.
elicitationYes?
Section titled “elicitationYes?”optional elicitationYes?: string;Defined in: packages/core/src/config/locale.ts:201
Affirmative choice of a yes/no question (default: “Yes”)
elicitationNo?
Section titled “elicitationNo?”optional elicitationNo?: string;Defined in: packages/core/src/config/locale.ts:203
Negative choice of a yes/no question (default: “No”)
elicitationAnswerLabel?
Section titled “elicitationAnswerLabel?”optional elicitationAnswerLabel?: string;Defined in: packages/core/src/config/locale.ts:205
Last-resort accessible name for a free-text answer (default: “Your answer”)
approvalInstructionPlaceholder?
Section titled “approvalInstructionPlaceholder?”optional approvalInstructionPlaceholder?: string;Defined in: packages/core/src/config/locale.ts:213
Placeholder for the free-text arm of an approval (default: “Or tell it what to do instead…”).
The refusal’s REASON, in the user’s words, which the model now reads because a refusal hands it a turn. Before that this text had nowhere to go.
approvalAsk?
Section titled “approvalAsk?”optional approvalAsk?: string;Defined in: packages/core/src/config/locale.ts:221
The question an approval asks (default: “Run {tool}?”).
{tool} is replaced with the tool’s name. A placeholder rather than three
concatenated fragments, because word order is the first thing a translation
changes and “Run” + name + ”?” only works in English.
scrollToBottom?
Section titled “scrollToBottom?”optional scrollToBottom?: string;Defined in: packages/core/src/config/locale.ts:231
Accessible name of the viewport’s scroll-to-bottom button (default: “Scroll to bottom”).
It was hardcoded English at both sites that build the button — the one chrome string a screen-reader user in another language always met. Same class of defect as the undeclared-key trio (submitButton, stopButton, actionUpload): the component looked done, the locale looked complete.
suggestionsLabel?
Section titled “suggestionsLabel?”optional suggestionsLabel?: string;Defined in: packages/core/src/config/locale.ts:237
Accessible name of the <aparte-suggestions> group of prompt starters. Optional
for the same reason as the keys above: a locale written before the element existed
keeps working, and the built-in English fills the gap.
contextLabel?
Section titled “contextLabel?”optional contextLabel?: string;Defined in: packages/core/src/config/locale.ts:239
Accessible name of the <aparte-context> gauge. Optional, like the keys above.
compactionSummaryTitle?
Section titled “compactionSummaryTitle?”optional compactionSummaryTitle?: string;Defined in: packages/core/src/config/locale.ts:247
Title line of the summary message @aparte/plugin-compaction injects in place
of the summarised turns (default: “Conversation summary”). The plugin reads it
through config.t(), so the notice follows the locale like every other string
the user reads — it used to be hardcoded, with an emoji, so a French chat
compacted into an English header.
approvalWaiting?
Section titled “approvalWaiting?”optional approvalWaiting?: string;Defined in: packages/core/src/config/locale.ts:256
What the pill says while the decision is being made elsewhere (default: “Waiting”).
The pill is the anchor, not the control — so it has to say WHY nothing is happening. A pill that just sits there while the answer is expected at the composer is the one thing this placement can get wrong.
toolRunning?
Section titled “toolRunning?”optional toolRunning?: string;Defined in: packages/core/src/config/locale.ts:265
The words in a tool call’s state badge.
A WORD and not only a glyph, which is what every current implementation shows (“Pending”, “Running”, “Completed”, “Error”). A bare cross beside a name reads as a button that removes something — the state was being mistaken for an affordance, which is ratified decision #8 read backwards.
toolCompleted?
Section titled “toolCompleted?”optional toolCompleted?: string;Defined in: packages/core/src/config/locale.ts:266
toolRejected?
Section titled “toolRejected?”optional toolRejected?: string;Defined in: packages/core/src/config/locale.ts:267
toolStopped?
Section titled “toolStopped?”optional toolStopped?: string;Defined in: packages/core/src/config/locale.ts:268
toolFailed?
Section titled “toolFailed?”optional toolFailed?: string;Defined in: packages/core/src/config/locale.ts:270
The tool row’s word when the handler threw — a crash, not a refusal nor a stop (default: “Failed”).
toolInput?
Section titled “toolInput?”optional toolInput?: string;Defined in: packages/core/src/config/locale.ts:272
Label above a tool call’s arguments (default: “Input”)
toolOutput?
Section titled “toolOutput?”optional toolOutput?: string;Defined in: packages/core/src/config/locale.ts:274
Label above a tool call’s result (default: “Output”)
approvalOptionsLabel?
Section titled “approvalOptionsLabel?”optional approvalOptionsLabel?: string;Defined in: packages/core/src/config/locale.ts:276
Accessible name for the group of approval options (default: “Your decision”)
approvalArgsLabel?
Section titled “approvalArgsLabel?”optional approvalArgsLabel?: string;Defined in: packages/core/src/config/locale.ts:285
Heading over the call’s arguments in the approval panel (default: “Arguments”).
The panel named the tool and nothing else, while the arguments — the thing actually being approved — stayed in the transcript row behind a closed disclosure. Same word family as toolInput and deliberately not that key: that one heads a section of a transcript row, this one heads a decision.
actionUpload?
Section titled “actionUpload?”optional actionUpload?: string;Defined in: packages/core/src/config/locale.ts:301
The composer’s attach-file button (default: “Attach file”).
aparte-composer-add-attachment has been READING t('actionUpload') since it
existed, and the key was never declared — so t() returned ” and the
|| 'Attach file' fallback rendered in every language, after every reload.
The third instance of this exact defect in this file, after submitButton and
stopButton, and the one a user reported from the live language switcher.
A key that is read and not declared cannot be found by reading either side: the
component looks correct, the locale looks complete. Cross-checking the two
lists is what finds them — t() calls and getLocale().x reads on one side,
these declarations on the other.
removeAttachment?
Section titled “removeAttachment?”optional removeAttachment?: string;Defined in: packages/core/src/config/locale.ts:310
The ✕ on a pending attachment, named after the file it drops (default: “Remove {name}”).
{name} is substituted with the file’s own name — the convention
approvalAsk and deleteConversationConfirm already use. The button is
icon-only, so this string is the whole of what a screen-reader user hears.
selectSearchPlaceholder?
Section titled “selectSearchPlaceholder?”optional selectSearchPlaceholder?: string;Defined in: packages/core/src/config/locale.ts:320
Placeholder of a searchable select’s filter field (default: “Search…”).
VISIBLE text, which is what separates it from most of this file: it was a literal in the primitive, so a French page opened the model picker and read “Search…” in the box.
selectSearchLabel?
Section titled “selectSearchLabel?”optional selectSearchLabel?: string;Defined in: packages/core/src/config/locale.ts:322
Accessible name of that filter field, which has no visible label (default: “Search options”)
loading?
Section titled “loading?”optional loading?: string;Defined in: packages/core/src/config/locale.ts:324
What an option group shows while its options are being fetched (default: “Loading…“)
modelSelectorPlaceholder?
Section titled “modelSelectorPlaceholder?”optional modelSelectorPlaceholder?: string;Defined in: packages/core/src/config/locale.ts:336
The <aparte-model-selector> trigger before a model is picked (default:
“Select a model…”). The one string that element takes from the locale.
approvalModeLabel?
Section titled “approvalModeLabel?”optional approvalModeLabel?: string;Defined in: packages/core/src/config/locale.ts:342
Accessible name of @aparte/plugin-approval’s mode switch (default: “Approval
mode”). The switch is an <aparte-select> with no visible label, so this string
is the whole of what a screen-reader user hears there.
download?
Section titled “download?”optional download?: string;Defined in: packages/core/src/config/locale.ts:355
The artifact card’s download button (default: “Download”).
Like stopButton, this string is a title and an aria-label on an
icon-only button — which is why it stayed English through every locale this
project shipped. Nothing on screen was in the wrong language.
preview?
Section titled “preview?”optional preview?: string;Defined in: packages/core/src/config/locale.ts:363
The artifact card’s two tabs (defaults: “Preview” / “Code”).
These two ARE visible text, on a card the landing page leads with, and they were still literals. The card was written before the locale had a home for anything but chrome.
optional code?: string;Defined in: packages/core/src/config/locale.ts:364
generating?
Section titled “generating?”optional generating?: string;Defined in: packages/core/src/config/locale.ts:373
A binary artifact being produced, and the same artifact’s preview being rebuilt after a reload (defaults: “Generating…” / “Rebuilding preview…”).
generating was also the aria-label of the former pipeline-waiting segment, which
is the ONLY thing a screen-reader user hears while a turn is in flight. It was
hardcoded, so that announcement was English in every locale.
rebuildingPreview?
Section titled “rebuildingPreview?”optional rebuildingPreview?: string;Defined in: packages/core/src/config/locale.ts:374
previewPending?
Section titled “previewPending?”optional previewPending?: string;Defined in: packages/core/src/config/locale.ts:383
What the preview pane says before anybody presses Preview (default: “Press Preview to run this artifact.”).
The pane is empty on purpose — a previewable artifact is model-authored code and mounting it unasked would execute it (ratified decision #8) — so this sentence is the whole of what the reader sees there, and it was a literal.
sandboxError?
Section titled “sandboxError?”optional sandboxError?: string;Defined in: packages/core/src/config/locale.ts:391
A binary artifact whose sandbox run failed: the heading, and the hint under it (defaults: “The sandbox failed during generation.” / “Common cause: …”).
The message BETWEEN them is the sandbox’s own error text and stays untranslated on purpose — it is the tool’s output, not the library’s copy.
sandboxErrorHint?
Section titled “sandboxErrorHint?”optional sandboxErrorHint?: string;Defined in: packages/core/src/config/locale.ts:392
optional tag?: string;Defined in: packages/core/src/config/locale.ts:416
BCP-47 language tag for Intl formatting — 'fr-FR', 'ja-JP', 'en-US'.
A locale is otherwise a bag of STRINGS, and a clock is not a string: it is a
format. So setLocale(fr) moved fifty strings and left the timestamp above
every message reading 7:32 PM, because the only Intl call in the library
passed undefined — “use the BROWSER’s locale” — which is not the locale the
app just chose. French is 24-hour; the browser was not asked.
A tag and NOT an hour12 flag, deliberately. A flag answers one question for
one call site; a tag answers every question Intl can be asked — hour cycle,
date order, month names, decimal separator, relative time, list joining — for
every locale, including the ones nobody here can enumerate. direction next
door is the precedent: this section holds how a language BEHAVES, not what its
words are.
Undefined on purpose in the English default: undefined means “follow the
browser”, which is the right default for a library and the behaviour every
consumer has today. A locale that declares a tag pins the formatting — if you
have chosen French strings, French formatting is what you meant.
direction?
Section titled “direction?”optional direction?: "ltr" | "rtl";Defined in: packages/core/src/config/locale.ts:434
Reading direction — 'ltr' or 'rtl'. Written as dir onto the viewport’s
scroll container and onto <aparte-composer>, so everything inside inherits it.
Undefined on purpose in the English default, for the reason tag above is:
undefined means “follow the host”. The default used to be the literal
'ltr', which meant core wrote dir="ltr" on its own DOM — so a page that
had said <html dir="rtl"> got a mirrored app shell around a chat that was
still left-to-right, and nothing said why. Not declaring it lets the host’s
direction inherit, which is what a library should do with a decision the page
has already taken.
A locale that wants the direction PINNED still declares it, and that is the
case it exists for: @aparte/locale-ar would say 'rtl' whatever the page
around it does. setLocale replaces the object wholesale, so nothing merges a
default back in.
AparteLocaleExtensions
Section titled “AparteLocaleExtensions”type AparteLocaleExtensions = Record<string, string | undefined>;Defined in: packages/core/src/config/locale.ts:455
The extension half: any other key a plugin or an app wants to carry.
This used to be an index signature ON AparteLocale — [key: string]: string | undefined — and it silently disabled the only compile-time check the locale had.
AparteConfig.t(key: keyof AparteLocale) looks airtight; with an index signature,
keyof widens to string and EVERY literal typechecks. A renamed key
(t('copy') typed as t('copyCodeBlock')) compiled clean, t() returned ''
at runtime, and the UI rendered an empty label with no error and no warning. It was
one of the six deliberate mistakes an audit planted, and the only guard that could
have caught it was this type.
So the two halves are separate now: AparteLocale is CLOSED — it is the list
t() keys on — and this is the open bag beside it. AparteConfig.setLocale
and AparteConfig.extendLocale accept the intersection, so a plugin still
ships its own strings in the same object; only t() stays narrow, which is where
the typo has to be caught.
AparteSanitizer
Section titled “AparteSanitizer”type AparteSanitizer = (html) => string;Defined in: packages/core/src/config/sanitize.ts:18
Zero-dependency HTML sanitizer for provider output.
Aparte renders LLM-authored content: a markdown or highlight provider turns the
assistant’s text into HTML that is then injected via innerHTML. Prompt
injection can make a model emit arbitrary markup (<img onerror=…>,
<script>, javascript: URLs), so that HTML is untrusted and must be
scrubbed before it touches the DOM.
This is an allowlist sanitizer built on the browser’s own parser: the HTML is
parsed into an inert document (scripts never execute during
DOMParser.parseFromString), the tree is rebuilt keeping only known-safe tags
and attributes, then re-serialized. It is deliberately conservative and covers
the realistic threat model (LLM-emitted markup). For hardened, audited
coverage, register DOMPurify via aparteGlobalConfig.setHtmlSanitizer.
Parameters
Section titled “Parameters”| Parameter | Type |
|---|---|
html | string |
Returns
Section titled “Returns”string
AparteSiblingNavRenderer
Section titled “AparteSiblingNavRenderer”type AparteSiblingNavRenderer = (ctx) => string | HTMLElement;Defined in: packages/core/src/config/sibling-nav-renderer.ts:23
Sibling-Nav Renderer
Replace the branch position indicator — the default ‹ N / M › counter between
the prev/next arrows — e.g. with a row of dots. Return an HTML string
(multiple roots allowed, set via innerHTML) or a single HTMLElement
(charter §6 render hooks: string | HTMLElement). Called whenever the active
sibling / count changes.
The prev/next arrows and their behavior (dispatching aparte-branch-navigate) are
kept — this hook customizes only the indicator. For click-to-jump navigation,
dispatch your own events / use the imperative API from your rendered output.
Parameters
Section titled “Parameters”| Parameter | Type | Description |
|---|---|---|
ctx | { count: number; index: number; } | - |
ctx.count | number | Total number of siblings (> 1 when a picker shows). |
ctx.index | number | 0-based index of the active sibling. |
Returns
Section titled “Returns”string | HTMLElement
HTML string or a DOM element for the indicator.
Example
Section titled “Example”aparteGlobalConfig.setSiblingNavRenderer(({ count, index }) =>
Array.from({ length: count }, (_, i) =>
`<span class="dot${i === index ? ' active' : ''}"></span>`).join(''));AparteStatusRenderer
Section titled “AparteStatusRenderer”type AparteStatusRenderer = (text) => string | HTMLElement;Defined in: packages/core/src/config/status-renderer.ts:22
Status Renderer
Replace the typing indicator’s inner markup — the default is an assistant
avatar slot + animated dots + optional text. Return an HTML string or a
ready HTMLElement (charter §6 render hooks: string | HTMLElement). The
<aparte-chat-status> container keeps owning show/hide (via the visible
attribute) and the accessible name, so you supply only the visual.
Parameters
Section titled “Parameters”| Parameter | Type | Description |
|---|---|---|
text | string | The typing text (from the text attribute, default “Typing”). |
Returns
Section titled “Returns”string | HTMLElement
HTML string or a DOM element to place inside the status container.
Example
Section titled “Example”// A custom spinner, driven by the typing text.
aparteGlobalConfig.setStatusRenderer((text) => {
const el = document.createElement('div');
el.className = 'my-typing';
el.textContent = text;
return el;
});Event details
Section titled “Event details”AparteConfigChangeEventDetail
Section titled “AparteConfigChangeEventDetail”Defined in: packages/core/src/config/aparte-config.ts:1657
Detail payload for aparte-config-change, dispatched on window whenever any
provider, locale, action or model setting changes.
Five core components listen for it — the widest listener footprint of any event
that had no declared type. config is what makes per-instance config work: a
component resolving to a different instance compares it and skips the rebuild
instead of every chat on the page reacting to every config’s change.
aparte-config-change
Properties
Section titled “Properties”config
Section titled “config”config: AparteConfig;Defined in: packages/core/src/config/aparte-config.ts:1659
The config instance that changed — compare against your own before reacting.
modelConfig
Section titled “modelConfig”modelConfig: AparteModelConfig;Defined in: packages/core/src/config/aparte-config.ts:1661
Its model configuration, after the change.