Repository navigation
AbstractCore v2.30.0
First published release since 2.26.3: it also ships the changes listed under 2.26.4
through 2.29.0 below. The AbstractVoice, AbstractVision, AbstractMusic and Abstract3D
plugins are pinned to their latest releases.
Added
-
Voice navigation by engine and language:
llm.voice.list_voices(provider=..., model=..., language=...),list_cloned_voices(...)andvoice_catalog(language=...);GET /v1/audio/voices
and the newGET /v1/voice/clonestakelanguage. Every voice record carriesvoice_id(the
value forvoice=),name,kind(profile|clone),provider,model,languagesand the native
languagewhen known; native speakers of the requested language come first. -
Languages per engine:
llm.voice.list_languages(kind=..., provider=...)and
GET /v1/audio/languageslist the languages of every TTS, STT and cloning engine without loading
a model. -
Cloned-voice management:
llm.voice.get_cloned_voice,rename_cloned_voice,
set_cloned_voice_reference_text,delete_cloned_voice, andGET|PATCH|DELETE /v1/voice/clones/{voice_id}. Built-in voices are read-only (422); an unknown id is404.
PATCH,DELETEandPOST /v1/voice/designneed server authentication (or
ABSTRACTCORE_SERVER_ALLOW_UNAUTHENTICATED=1); a provider key does not authorize them. -
Voice design:
llm.voice.design_voice(description, name=..., language=..., text=...)and
POST /v1/voice/designcreate a reusable voice from a written description (Qwen3-TTS
VoiceDesign, then cloned; needs theqwen3-ttsandsttextras of AbstractVoice, included in
abstractcore[apple]andabstractcore[gpu]). -
one_shoton/v1/audio/speech: the whole text as one generation, so the take keeps one
voice (Qwen3-TTS voices, up to 1000 characters). The stream route and remote models answer422. -
llm.voice.compatibility_catalog(): feature support per provider and model. -
Guide: choosing a model for knowledge-graph extraction:
a measured comparison of local and hosted models on ontology-constrained entity and relationship
extraction (precision, coverage, time), the prompt rules and second-pass strategies that change
results, and recommendations. -
Registry entries:
claude-haiku-5-5(1M context, 128K output, adaptive thinking, effort
low..xhigh plusmax) andgpt-6-luna(1,050,000 context, 128,000 output,
reasoning_effortnone..xhigh plusmax), from the vendors' model pages (2026-10-25). -
Mailbox access is an explicit choice:
EmailAccount.access,"read"(Read only) or"write"
(Read and write), stored into_dict()/from_dict();access_textsays it in words.
can_writeis the choice (it was "IMAP and SMTP");can_sendiscan_writeand an outgoing
server set. An account stored without it keeps what it could do:"write"with an outgoing
server, else"read".EmailAccountStore.set_access(access, *, smtp=None, test=True)changes it
without connecting again (a new outgoing server is signed in to first with the stored sign-in);
public()hasaccess/access_text;abstractcore email statusand the terminal console's
Email line say "Read only" / "Read and write".
Changed
- Plugin floors:
abstractvoice>=0.18.2,abstractvision>=0.3.34,abstractmusic>=0.1.17,
abstract3d>=0.3.2(base install and theapple,gpu,all-apple,all-gpuandvision-*
extras). POST /v1/voice/clonereturns the stored record of a local clone undervoice(name, engine,
reference text, meta).- A
one_shotTTS request the voice backend refuses (too long, unsupported engine) answers422
with the backend's reason. - A voice request for an engine missing from this install (AbstractVoice names the extra to
install) answers501with the install command instead of500. - A read-only mailbox refuses changes and sends in plain words: "The mailbox is
read-only: automations only read it." / "Turn on Read and write for to change it or
send from it." (email_mailbox_read_only).guarded_sendon a read-only account with an
outgoing server now refuses withEmailMailboxReadOnlybefore connecting.
Fixed
- The HuggingFace provider's MoE experts fallback no longer raises
ModuleNotFoundErrorwhen
transformersis not installed; it answers "not applicable" as intended. - A configured reasoning default overrode the caller's
reasoning_effort=: with
reasoning: minimalon the text route,generate(..., reasoning_effort="high")(or"none")
ran asthinking="minimal", mapped to the model's"low", and sentreasoning_effort: "low". Precedence is nowthinking=>
a provider-native field on the call (reasoning_effort=,reasoning=,think=, sent as
given) > the configured effort > nothing. The configured effort also applies only to an
instance the route describes (same provider or endpoint profile, same model; a reasoning-only
route applies everywhere): it used to reach every model on the machine. The planner behind
prompt_cache_prepare_modules(thinking=None)follows the same rule. Metadata gains
thinking_source(thinking|reasoning_effort|configured_default); a raw
reasoning_effort=is reported asthinking_requested, and asthinking_effectiveon
providers that forward it verbatim; the route summary reports an unapplied default as
reasoning: None,reasoning_source: not_applied:<reason>. - An explicit output budget was cut to a guessed ceiling on unregistered models:
max_tokens=12000on a model missing frommodel_capabilities.jsonwas clamped to the
4096default_capabilitiesguess, truncating JSON output. For an unregistered model the per-call
budget is now sent as given and the server enforces its real limit; registered models and
constructor caps still clamp, with the warning naming the actual source. A GGUF n_ctx clamp
stays in force for unregistered local models. - LM Studio
thinking=reached the model only for "off": the control rode
chat_template_kwargs, which LM Studio's OpenAI-compatible endpoint ignores, while metadata
reportedthinking_effective="on". The unified control now travels as the top-level
reasoning_effort("none"= off, the declared level, or"medium"for on), which LM Studio
maps into the chat template on plain, message-history and tool-history requests, sync and
async.thinking="off"no longer appends the assistant
no-think prefill on top (it rendered the empty think block twice); the prefill remains the
off switch only after the server rejectedreasoning_effort. Models without a surface LM
Studio can drive (Kimithinkingparam, budget-only, surface-less) are no longer claimed.
thinking=no longer routes to the native/api/v1/chatendpoint, which dropped the control
for history/tool/async requests while still claiming it;reasoning=keeps that lane. - vLLM thinking controls never reached the server: they were posted inside a literal
extra_bodyJSON field, which vLLM ignores.chat_template_kwargs,reasoning_effort,
thinking_token_budgetand the other vLLM extensions are now sent at the top level, and a
caller'sreasoning_effort=/chat_template_kwargs=are forwarded. The template switch is
sent under the name the model declares (no guessedenable_thinkingclaimed for models that
have none); models with levels and no switch (DeepSeek V4, Mistral Small 4) get
reasoning_effort; GPT-OSS getsreasoning_effort; Seed-OSS getsthinking_budget;
Nemotronlow_effortis sent; a token budget alone is no longer reported as an applied level. - OpenRouter ignored
thinking=: it is now sent as OpenRouter'sreasoningobject
(effort/enabled), with the lowest declared effort (warned) for models whose reasoning
cannot be disabled. - MLX text-lane usage counted the prompt with a character estimate although the tokenizer
was loaded. The prompt is now counted with
the loaded tokenizer exactly as mlx_lm tokenizes it; the estimate is used only when no
tokenizer can count.