Skip to content

feat: add FLUX.3 Image Klein and Klein Base support - #2143

Merged
leejet merged 1 commit into
masterfrom
feat/flux3-image-klein
Oct 15, 2026
Merged

leejet merged 1 commit into
masterfrom
feat/flux3-image-klein

Conversation

@leejet

@leejet leejet commented Oct 15, 2026 •

Copy link
Copy Markdown
Owner

Summary

Add FLUX.3 Image Klein and Klein Base support.

Related Issue / Discussion

N/A

Additional Information

.\bin\Release\sd-cli.exe --diffusion-model ..\models\diffusion_models\flux-3-image-klein.safetensors --llm ..\models\text_encoders\Qwen3-VL-4B-Instruct-Q4_K_M.gguf --vae ..\models\vae\flux2_ae.safetensors -p "a lovely cat holding a sign says 'flux3.cpp'" --cfg-scale 1.0 --steps 16 --sampling-method euler -v --offload-to-cpu
flux3-image-klein
.\bin\Release\sd-cli.exe --diffusion-model ..\models\diffusion_models\flux-3-image-klein-base.safetensors --llm ..\models\text_encoders\Qwen3-VL-4B-Instruct-Q4_K_M.gguf --vae ..\models\vae\flux2_ae.safetensors -p "a lovely cat holding a sign says 'flux3.cpp'" --cfg-scale 3.5 --steps 20 --sampling-method euler -v --offload-to-cpu
flux3-image-klein-edit

Checklist

Summary by CodeRabbit

  • New Features
    • Added support for FLUX.3 Image Klein and Klein Base, including model detection, prompt handling, image generation, and reference-image editing.
    • Added usage instructions and examples for both models. Their default discrete scheduler uses a flow shift of 6.93, which can be overridden with --flow-shift.
    • Added FLUX.3 to the supported image-model list.

@coderabbitai

coderabbitai Bot commented Oct 15, 2026 •

Copy link
Copy Markdown

Review in Change Stack →

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration
  • Configuration used: Repository UI
  • Review profile: CHILL
  • Plan: Advanced
  • Run ID: 79368a79-182c-46ff-97e6-6ea5ef173ce6
📥 Commits

Reviewing files that changed from the base of the PR and between e47426c and 6d6ff75.

⛔ Files ignored due to path filters: 3
  • assets/flux3/flux3-image-klein-base.png is excluded by !**/*.png
  • assets/flux3/flux3-image-klein-edit.png is excluded by !**/*.png
  • assets/flux3/flux3-image-klein.png is excluded by !**/*.png
📒 Files selected for processing: 12
  • README.md
  • docs/edit.md
  • docs/flux3.md
  • src/conditioning/conditioner.hpp
  • src/model.h
  • src/model/diffusion/flux3.hpp
  • src/model/diffusion/model.hpp
  • src/model/te/llm.hpp
  • src/model_loader.cpp
  • src/pipeline/diffusion_engine.cpp
  • src/pipeline/model_builders.cpp
  • src/runtime/denoiser.hpp

Included review availability: This review used your included allowance. Your plan provides up to 10 included reviews per hour; 9 remain after this review.

📝 Walkthrough

The pull request adds FLUX.3 Image Klein and Klein Base support, including model detection, prompt conditioning, diffusion execution, scheduler behavior, and usage documentation.

Changes: FLUX.3 Image Klein support

Layer / File(s) Summary
Model recognition and prompt conditioning
src/model.h, src/model_loader.cpp, src/conditioning/conditioner.hpp, src/model/te/llm.hpp
The model version and loader recognize FLUX.3. Its prompt path selects QWEN3_VL, pads token sequences to multiples of 80, and passes custom position IDs to LLMRunner.
Flux3 diffusion runner and wiring
src/model/diffusion/model.hpp, src/model/diffusion/flux3.hpp, src/pipeline/model_builders.cpp
The new runner processes image, reference-image, and text streams. The model builder constructs the Flux3 conditioner and runner. Diffusion parameters can carry a target timestep.
Sampling and documented usage
src/runtime/denoiser.hpp, src/pipeline/diffusion_engine.cpp, README.md, docs/edit.md, docs/flux3.md
Flux3 sampling uses a dedicated flow denoiser and passes target timesteps to the runner. The documentation lists model sources, generation and editing examples, and the default flow shift of 6.93.

Priority: ⬇️ Low

Estimated code review effort: 4 (Complex) | ~60 minutes

Change: Feature

Sequence Diagram(s)

sequenceDiagram
  participant ModelLoader
  participant build_core_runners
  participant LLMEmbedder
  participant LLMRunner
  participant diffusion_engine
  participant Flux3FlowDenoiser
  participant Flux3Runner
  ModelLoader->>build_core_runners: identifies VERSION_FLUX3
  build_core_runners->>LLMEmbedder: creates Flux3 conditioner
  LLMEmbedder->>LLMRunner: passes position_ids
  diffusion_engine->>Flux3FlowDenoiser: requests Flux3 sigmas
  diffusion_engine->>Flux3Runner: passes target_timestep
Loading

Suggested reviewers: fszontagh

Merge Risk: ⚪ Minimal · up to 6d6ff

The reported crashes are not reachable through the supported FLUX.3 paths; no identified issue needs resolution before merging.

Security architecture risk: 🔵 Low · up to 6d6ff

The new inference path has no demonstrated increase in access or privileges. Input-compatibility assumptions and incomplete integration coverage leave some uncertainty.

Retained concerns
No architecture-level concerns identified.

Security review details

Security Blast Radius

  • inferred — The demonstrated exposure is the inference process and its backend allocations when callers select the new model path. The inspected changes do not establish additional service, tenant, credential, or environment authority; deployment-level exposure remains unspecified.

Trust Boundaries and Controls

  • inferred — Model weights influence dimensions, block counts, and allocations. The new runner has limited explicit cross-model shape validation, but standard prompt and image producers constrain runtime inputs. This extends the existing local model-file trust pattern; the inspected evidence does not demonstrate a newly attacker-reachable boundary bypass or memory-corruption outcome.

Resilience and Maintainability Implications

  • inferred — Repeated serialized execution preserves the common runner's cleanup and ownership behavior. Concurrent use of one runner remains an inherited unsupported assumption, rather than an established regression introduced by this PR.
Pre-merge checks: Passed 4 · Failed 1

Failed Failed checks: 1 warning

Check name Status Explanation Resolution
Docstring Coverage Warning Docstring coverage is 0.00% which is insufficient. The required threshold is 80.00%. Docstring coverage is scoped to functions touched by this diff. Analyzed 31 functions across 9 files. (3 skipped: 3… Write docstrings for the functions missing them to satisfy the coverage threshold.
Passed Passed checks: 4 passed
Check name Status Explanation
Title check Passed The title clearly and concisely describes the main change: adding FLUX.3 Image Klein and Klein Base support.
Description check Passed The description includes all required template sections. It states the change, marks related discussion as not applicable, provides verification commands and output images, and confirms the contributi…
Linked Issues check Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check Passed Check skipped because no linked issues were found for this pull request.
Full details: Docstring Coverage

Explanation

Docstring coverage is 0.00% which is insufficient. The required threshold is 80.00%. Docstring coverage is scoped to functions touched by this diff. Analyzed 31 functions across 9 files. (3 skipped: 3 unsupported.)

  • Fix all pre-merge checks with AI
✨ Finishing Touches: 💡 1
📝 Generate docstrings: 💡
  • Commit to this branch
  • Create a new PR
🧪 Generate unit tests (beta)
  • Commit to this branch
  • Create a new PR
  • Autofix · Keep fixing CodeRabbit findings and required CI, and resolving merge conflicts

Warning

Some tools did not complete. Review the errors below.

🔧 Cppcheck (2.22.0)
src/pipeline/diffusion_engine.cpp

Cppcheck timed out; analysis of this file is incomplete

src/pipeline/model_builders.cpp

Cppcheck timed out; analysis of this file is incomplete

Comment @coderabbitai help to get the list of available commands.

@leejet
leejet merged commit 8cd731e into master Oct 15, 2026
11 checks passed
@leejet
leejet deleted the feat/flux3-image-klein branch October 15, 2026 18:42
valarauca pushed a commit to valarauca/stable-diffusion.cpp that referenced this pull request Oct 16, 2026
chynggi added a commit to chynggi/koharu-ft that referenced this pull request Oct 17, 2026
The release carries leejet/stable-diffusion.cpp#2143 (FLUX.3 Image Klein).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
notforu777 added a commit to AtomicBot-ai/stable-diffusion.cpp that referenced this pull request Oct 20, 2026
…leejet#2143) and 35 more upstream commits

atomic stays upstream master plus atomic/ and release-atomic.yml only; no file overlaps.

Assisted-by: Claude
Vect0rM added a commit to AtomicBot-ai/Atomic-Chat that referenced this pull request Oct 21, 2026
The catalog entry is AtomicBot-ai/atomic-chat-conf#36; until now the app
dropped the id. It joins DiffusionFamilyId and DIFFUSION_FAMILY_IDS, draws
the BFL mark and runs Create only (sd.cpp runs its reference edits, but
they are not measured yet).

FLUX.3 arrived upstream in build 968 (leejet/stable-diffusion.cpp#2143),
so the engine gate is now per family: requiredEngineTag names
master-968-8cd731e for Klein and master-883-137f740 for Qwen Image 2.1,
its Turbo and Krea 2 Turbo. The load refusal and the update offer name
the family's own floor instead of always 883.

Refs #372

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Vect0rM added a commit to AtomicBot-ai/atomic-chat-core that referenced this pull request Oct 21, 2026
checkEngineCompatibility holds flux.3-klein to master-968-8cd731e, the
build that added FLUX.3 upstream (leejet/stable-diffusion.cpp#2143), and
names it in the refusal; the 883 families keep their floor and message.
workflowsForFamily gives it Create only: sd.cpp runs its reference edits,
but they are not measured yet.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Vect0rM added a commit to AtomicBot-ai/Atomic-Chat that referenced this pull request Oct 21, 2026
…oud) + secure project environments (#365) + Bonsai PrismML build; core 0.18.5 (#369)

* app: file and folder pickers open above the window that asked for them

open_dialog and save_dialog built rfd dialogs without a parent. On Windows an
ownerless picker started from a worker thread cannot take the foreground, so it
opened behind the app: a click on Add folder (or any picker) looked like it did
nothing while the dialog waited out of sight. Both now take the calling window
as the dialog's owner.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* app: Foundry Local tool calls streamed as text run as tool calls

Foundry Local passes tools to the model but never parses its answer: a Qwen3.5
call arrives as content (`<function=run_command>…</function>`) with no
tool_calls, so the chat showed the XML and ran nothing. A middleware on the
Foundry Local model turns that text — the XML form and the JSON `<tool_call>`
form — into real tool calls, only for tools the request offered; anything it
cannot parse passes through unchanged.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* app: secure environment projects confine a chat's commands to chosen folders

A project can be a secure environment (Windows, where MXC passes its probe):
a list of folders, each read-only or editable, an internet switch and a list
of allowed MCP servers. Its chats' run_command / run_script run inside MXC
with only the chat folder and those folders granted; without MXC they do not
run. The backend owns the policy (secure-environments.json) and looks it up
from the thread's own thread.json, so a frontend that forgets to pass it
cannot widen a run.

- MCP servers run outside the sandbox, so a secure project offers only the
  ones it ticks, and call_tool refuses the rest for that thread.
- The MXC policy grants no directory enumeration: MXC applies it to the whole
  subtree and `dir` needs every ancestor up to the volume root, so the old
  ancestor grants listed every folder on the drive. The probe lists with
  `for` and checks the folder around it stays unlisted.
- Ordinary chats no longer go through MXC: their commands run on the host on
  Windows too, gated by the approval mode, as on macOS and Linux.
- The project dialog gets the section (folders, internet, allowed MCPs),
  starts a new project with the default assistant, and a long folder path no
  longer pushes the dialog past its edge. The composer's web search and
  plugins follow the project's policy.

ADR: docs/decisions/2026-10-17-confine-secure-projects-commands-to-their-folders-with-mxc.md

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* app: Gemma 4 calls tools on Foundry Local

Foundry Local hands a model's template the tools (and the conversation's tool
calls) without their `function` wrapper, so Gemma 4's template, which reads
tool['function']['name'], failed every request that offered tools and the chat
got a 502. Before a Foundry model loads, the extension now has the app rewrite
its chat_template.jinja once: every x['function'] becomes
(x['function'] if x['function'] else x), and the refusal of string arguments
prints them instead. Templates that never index ['function'] stay untouched.

Gemma's call then streams back as bare text, call:run_command{command:dir},
its markers and quotes being dropped special tokens. The text tool call
middleware reads that form too, cutting each value at the next argument name
the tool's schema knows.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* app: a file or folder picker that fails to open says so instead of doing nothing

rfd turns a failed IFileDialog::Show into "nothing chosen", indistinguishable
from Cancel: a click on Add folder then did nothing and left no trace (seen on
a Windows 2.2.16 install that had run for 36 hours; a restart cured it).

open_dialog and save_dialog now log every call with its duration (never the
paths), and an empty answer within 300 ms, faster than a dialog can be drawn,
is returned as an error. The dialog service shows a toast for it and still
hands its caller null; log export reports it through its own error toast.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* app: navigate with an icon rail and a contextual sidebar

First iteration of the new design: the navigation shell only, pages keep
their current look.

- A 60px icon rail picks Workspace, Server, Models Hub or Settings (Help
  above Settings); one floating sidebar shows that section's navigation,
  and a 42px title bar row above both holds the sidebar toggle. On macOS
  the native traffic lights move into that row.
- Workspace: New Chat, Images, Video, Pinned (the thread's isFavorite, in a
  drag order kept by useSidebarLists), Projects (+) and Recents (+).
- Server: a live Start/Stop/Restart panel on useLocalApiServerControl with
  the served engine and model, Overview, Integrations, HTTPS Proxy and the
  integration agents with an installed dot (detected once per session).
- Models Hub: Downloads (/hub?installed=true), Local models, Cloud
  providers, Custom Endpoint (/cloud?add=custom), the local engines with
  Media and Voice. The Hub's installed filter and the Cloud page's custom
  dialog are now search params.
- Settings: General, Attachments, Interface, Shortcuts, Hardware, then
  Assistants, MCP connectors and Skills. The in-page SettingsMenu column is
  gone from all 15 settings pages; HeaderPage no longer draws a toggle.
- Desktop E2E navigates through the rail (harness/navigation.ts).

ADR: docs/decisions/2026-10-19-navigate-with-an-icon-rail-and-a-contextual-sidebar.md

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* app 7.1: pin atomic-chat-core 0.18.4

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* app 7.2: a Bonsai plan installs the PrismML build core picks for the file's requirements

The plan asks POST /backends/atomic-prism/catalog with the verdict's
requires and min_build and installs its recommended build; the local
choosePrismPack is gone. BACKEND_BUILD_UNAVAILABLE blocks the plan with
no_engine_build, so nothing is installed or downloaded.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* app 7.2: the no-requirements catalog test checks the plan too

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* app: the MCP thread-id test checks the tool output too

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* app: a secure project's commands start in its editable folder

On a demo a model asked to "put 4 txt files in ...\ClientC" ran
`echo Hello > file1.txt`: the files landed in the chat's scratch folder, the
project folder stayed empty, and the model, listing it, concluded the folder
was not accessible. The sandbox had done its job; the working directory was
the wrong place.

A secure project's command now starts in the project's first editable folder
(the MXC policy gains a separate `cwd`; the chat folder stays writable for
.tmp and packages). Projects with read-only folders only keep the chat
folder. The tool description names the folder, and the tool row's button
reads "Open folder", since it opens where the command ran.

Checked on Windows 11 25H2 with the installed MXC 1.0: with the project
folder as cwd a relative write lands there, the chat folder stays writable,
a write next to them is denied, and `for` lists the new file.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* app: desktop e2e reaches the API page through the Server section

Iteration 1 removed the sidebar's "API" link, so five steps that clicked
`a=API` (local-api, api-inspector, image-api, cloud-provider) could no
longer open the page. They now go through the rail with `openServerPage`
(Server section, then the "Overview" row); later page work only has to
change the row label.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* app: put every control on a 36/24/40 px scale

Second iteration of the new design starts with the prototype's control
scale, so the pages that follow are built on it.

- index.css: --control-height (36), --control-height-compact (24) and
  --control-height-large (40). Inside .app-shell, unlayered rules force the
  scale by data-size and on inputs, native selects and mode buttons, so a
  call site's own h-*/size-* no longer drifts. Sidebar rows become 36px.
- Button: default, sm and icon-sm read --control-height (sm and icon-sm
  32 -> 36px everywhere, overlays included); new `import` variant for the
  Hub's Import and the Server's Start.
- Beyond the prototype: icon buttons stay square, and the title bar's
  sidebar toggle stays 28px beside the new-chat control.
- ModelDownloadAction's download icon is icon-xs and RouteRow's icon-only
  action is icon-sm, so both stay square.

ADR: docs/decisions/2026-10-20-put-every-control-on-a-36-24-40-px-scale.md

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* app: Server configuration and remote access get their own pages

Next page of the new design: the Server section's Configuration and Remote
access move off the API screen, as in the approved prototype.

- Configuration (/settings/local-api-server) edits a draft of
  useLocalApiServer: host, port, prefix, API key (Show/Hide once there is
  one, Generate, Copy), autostart, and timeout/trusted hosts under Advanced.
  Save writes it; while the server runs "Apply & restart" restarts it through
  restartLocalApiServer when a setting it read at start changed. Invalid
  input is named in the save bar and blocks Save; a key generated elsewhere
  flows into an untouched form.
- Remote access (/settings/remote-lan) is the existing tunnel and local
  network cards on useRemoteAccess/useLanAccess, restyled and stacked; their
  state machine, errors, no-key dialog, QR, telemetry and gating are kept.
  Labels follow the prototype ("Start remote access", "Connected").
- /api keeps the connection strip, stats and inspector; the API settings
  popover, its field components and the Remote & LAN cards leave it.
- Page styles ported from the prototype into containers/server/ServerPage.css
  on theme tokens, scaled by --font-size-base.
- Server sidebar gains Configuration and Remote access; desktop E2E reaches
  the page with openServerPage(browser, 'Remote access').

ADR: docs/decisions/2026-10-20-give-server-configuration-and-remote-access-their-own-pages.md

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* app: Server Overview, Activity, Connections and Engine & model pages

The rest of the old API screen moves to the prototype's Server pages.

- Activity (/api/activity, new sidebar row): the stat tiles, request list,
  inspector, Refresh and Clear log under the section's title block. Start
  and Stop are the sidebar panel's alone.
- Connections (/api/connections, from the panel): the address to copy, the
  server's state and facts (loaded model, who can reach it, whether it wants
  a key, the decision and embedding models with their copy commands, moved
  from the connection strip), cURL/Python examples and a real "Send test
  request": one GET {base}/models through get_local_http with the saved key.
- Engine & model (/api/model, from the panel's Engine and Model): engine
  first, then one of its downloaded chat models; Save sets the server's
  default model, "Apply & restart" restarts it with that model loaded.
- Overview (/api): the ready strip and "Server activity & logs" (latest
  rows, link to Activity); agents and the setup guide come next.
- restartLocalApiServer takes { ensureModel }; the panel's Restart uses it,
  so a sidebar restart also restores an online tunnel.
- useLocalApiServerControl.start reads port and default model from the
  store at call time: Apply & restart no longer warns about a "different
  port" or starts the previous model.
- Desktop E2E starts and stops the server from the sidebar panel, reads the
  inspector on Activity and the Ready state on Connections.

ADR: docs/decisions/2026-10-20-split-the-api-screen-into-overview-activity-connections-and-model.md

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* app: pin atomic-chat-core 0.18.5

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* app: set up the Server from Overview with a guide that does the real work

The prototype's Overview: a first-visit setup guide, every agent as a card,
and Integrations moved out of the sidebar.

- The guide (Agent or Endpoint, review engine and model, preparing, done)
  checks the engine, saves the model as the server's (and a new port for an
  endpoint), starts the server with it or restarts it with ensureModel when
  it serves another model, then writes the agent's own config through the
  same configure_* call as All integrations (lib/integration-agent-setup.ts,
  extracted from the Launch page). Progress is the steps that finished; a
  failed step says why and Retry runs from it.
- useServerSetup (atomic-server-setup) keeps whether the guide finished or
  was closed, the tools set up through Atomic Chat (guide and All
  integrations) and the prepared endpoint. Cards say Configured / Installed
  / Not installed, never "connected"; Remove on Connections only forgets.
- "Set up" = the guide finished or the server already served a model, so
  existing users skip the first-visit guide; until then the sidebar's Start
  opens it. The panel counts connections; the agent palette opens the guide.
- Overview: guide or ready strip with "Guide me", Agents & tools (search,
  Claude Code / Codex / Atomic Agent first, editors to All integrations),
  endpoint shortcut, activity. Connections lists Connected tools.
- Integrations leaves the sidebar as "All integrations" (linked from
  Overview and the guide); install, custom paths, editors and Run stay there.
- E2E profiles seed the setup as done; new server-setup-guide.spec.ts walks
  the guide (not yet run); launch-integration reaches All integrations from
  Overview.

ADR: docs/decisions/2026-10-20-set-up-the-server-from-overview-with-a-guide.md

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* app: Inference engines get one sidebar row and a grouped overview

The Models Hub sidebar listed every local engine, a "N disabled" fold and
Media and Voice rows. Following the approved prototype, it now has one
"Inference engines" row, and /settings/providers is the overview:

- Language models: the engines the sidebar listed, by the same rules (local
  engines only, MLX on macOS, llamacpp behind TURBOQUANT_ENGINE, managed
  engines once shown). Each card shows the model count, the active build and
  an "Update available" badge from the engine-versions store, a status
  (Running while a model is loaded, Idle, Disabled) and the enable switch
  with the existing stopAllModels logic. The card opens
  /settings/providers/$providerName, unchanged.
- Media models: stable-diffusion.cpp with its build, badge and status; the
  existing MediaSettingsPanel unfolds inside the card.
- Voice models: Voxtral on llama.cpp; the existing VoiceSettingsPanel
  unfolds inside the card.

No engine Start/Stop/Restart (no such API) and no inline engine settings
(the prototype's bypass providers().updateSettings). /settings/media and
/settings/voice stay as routes and keep the row highlighted. Desktop E2E
reaches engines and Media settings through the overview.

ADR: docs/decisions/2026-10-20-list-inference-engines-on-one-grouped-overview.md

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* app: list everything downloaded on a Downloads page

The Models Hub sidebar's Downloads row opened the Hub's installed filter,
which showed text models only. /downloads now lists every local model
file, image and video checkpoint, embedding and decision model, the voice
model and every engine build, plus running downloads, with total storage,
item count and free space, search and a category filter. Remove asks first
and goes through each owner's own removal; a build the core keeps shows
why and cannot be removed. Engine build sizes read "—" until the core
reports them. /hub?installed=true stays a Hub filter.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* app: Cloud providers in two panes, custom endpoints on their own page

- Cloud (/cloud) lists hosted providers only: a searchable left pane
  (model counts, connection, "Available through N providers" matched on
  the id without its vendor prefix) beside the connection card without
  its dropdown, the subscription, model and media cards.
- A first-visit guide opens until finished or skipped, and only while no
  hosted provider is connected; "Guide me" reopens it.
- Custom Endpoint (/endpoints, new) lists the user's own servers: an
  Add/Configure dialog (name fixed once created, base URL, key) that
  registers the provider and reloads its models, Ping
  (checkProviderEndpoint: one get_local_http, /models then /v1/models,
  8 s) kept for the session, Remove for added endpoints, models and
  media models inline.
- /cloud?add=custom and /cloud?provider=<own server> redirect to
  /endpoints; the sidebar row links there.
- Desktop E2E adds the custom provider on Custom Endpoint.

ADR: docs/decisions/2026-10-20-show-hosted-providers-on-cloud-and-own-servers-on-custom-endpoint.md

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* app: composer attaches with one paperclip and shows Send on demand

- The "+" menu becomes a paperclip: one native picker for every supported
  type, routed like a drop (vision and audio gates, documents to retrieval,
  the Attachments setting); images for a non-vision model still offer the
  vision-model dialog.
- The approval select is the access menu: "Restricted" / "Full access",
  then "Run commands" (and the hidden Agent mode) as switches; the label
  shows in the compact composer too. Add folder sits beside the paperclip in
  agent chats; Plugins stays a compact icon.
- Send appears only with text or while a reply streams (0.24 s, none with
  reduced motion).
- The empty chat shows the animated Atomic mark; Images and Videos drop
  their duplicate title rows; "Videos" in en/ru.
- Desktop E2E wait for Stop to leave instead of Send to appear.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* app: Models Hub lists local models in a table whose rows open in place

Text models get one toolbar row (model type, search, Filters, Sort, Import)
and a sortable table with section heading rows; one row opens in place with
its facts, heart, source link and download options. Fit and RAM come from
estimateFit; the engine filter lasts one launch; hearts persist in
atomic-model-likes; an IntersectionObserver drives paging instead of a
virtualizer. Import file routes .gguf and MLX folders to the existing imports.
Images, Video, Decision and Embedding open rows in place without auto-open,
the README gives way to the source link, and Voice becomes a category.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* app: centre the macOS traffic lights in the title bar row

y 14 left the native buttons about 9 pt above the middle of the 42 pt title
bar, out of line with the sidebar toggle beside them. 23 puts their centres
on the row's centre line, as in the design.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* app: iteration-2 tests check what happened, not only what was called

The test-quality guard flagged 15 tests across seven files whose only
assertions were mock calls, and a test helper named like a production
export. Each now also checks an outcome the user or caller sees:

- ChatInput: a disabled or failed picker leaves the thread's attachments
  empty and the attach button usable.
- Downloads: a build the core refuses to remove stays listed; the local
  `build` helper is `engineBuild`.
- Server setup guide: finishing marks the agent set up and keeps the
  chosen model as the server's model.
- Installed inventory: each removal resolves; removing a decision model
  also drops its resumable download.
- Remote access and agent setup: the restart and the config write resolve.
- Activity: Clear log empties the page; Refresh spins until both the
  server status and the log have answered.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* app: engines follow prototype e4a14d1; the server takes its models down with it

Inference engines (Models Hub), after the prototype's e4a14d1:
- Each engine row says whether its build is current (core's answer),
  offers "Update" while the core has one, and unfolds its settings
  underneath. A language engine's settings are its page's form: the body of
  /settings/providers/$providerName moved to containers/engines/EngineDetail
  with an `embedded` mode (settings only; models stay on the page).
- "Check for updates" in the header forces a check of every engine; on
  Windows and Linux the llama.cpp rows offer "Find optimal backend"
  (useFindOptimalBackend, shared with the engine page).

Server:
- Turning the server off (sidebar Stop, Server pages, tray) goes through
  turnOffLocalApiServer: it unloads the local chat models, an image/video
  model, and switches the embedding and decision models off, which the next
  start switches back on. A restart keeps the models (stop({keepModels})).
- No Restart button in the Server sidebar; "Apply & restart" is now
  "Save changes".
- Server dropdowns are ServerSelect (Radix), which drops under the field
  instead of the macOS select popup sitting over it.
- Engine & model chooses the embedding and decision models beside the chat
  model.

Also in this commit, from the parallel sessions on this checkout:
- Chat commands are always offered; the Run commands switch is gone
  (ADR 2026-10-20-always-offer-chat-commands-without-a-switch).
- Launch-page agents already configured for Atomic Chat are detected from
  their own config on disk (agent_config_detection.rs) and adopted on the
  Server's connections list; removed ones are not brought back.
- Server pages show the save bar only with something to save, and use the
  prototype's page titles.

ADRs: 2026-10-20-unfold-engine-settings-and-offer-engine-updates-on-the-overview,
2026-10-20-turn-the-served-models-off-with-the-server.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* app: Hub table names every row's parameters, loads without jumping, keeps headings on one line

- Seven columns: Context, Est. RAM and Uncensored are gone from the table
  and from the opened row.
- A name without a parameter count gets Hugging Face's, asked for the rows
  on screen two at a time (useHubModelParams); the row and its opened card
  show the same answer, so opening a row changes no number.
- Placeholders hold the place of the count and of a feed row's sizes, fit
  and download options until they arrive; "—"/"Unknown" only after.
- Data columns keep an em minimum and the steps are in em of the table font,
  so "Download size" stays on one line and the sort arrow stays with its
  last word.
- Layout tests' settle() skips looping animations.

ADR: 2026-10-20-name-every-hub-rows-parameters-and-hold-the-place-of-what-loads

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* release: v2.2.21

* app: engine and server tests check what happened, not only what was called

The test-quality guard flagged 11 tests from the engines/server follow-up
(1221bb7) whose only assertions were mock calls. Each now also checks
an outcome the user or caller sees:

- Engine & model: a helper model that would not start leaves the field on
  what runs and the save bar gone.
- Served helper models: choosing None or a decision model forgets that
  kind's paused model, and only that kind's.
- Server control: Stop and a keep-models stop leave the hook not running;
  a start that fails leaves it stopped and not busy, so Start works again.
- Inference engines: a reinstall sent to the engine's page leaves the row
  offering the update; "all current" marks the row up to date; a failed
  check marks no row and leaves the check usable.
- Turn-off: a chat model that will not unload still lets the decision
  model go and be paused; a removed model is forgotten, not switched on.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* app: "Open containing folder" no longer aborts the app on Linux

The opener plugin's async `reveal_item_in_dir` command runs on a tokio
worker and, on Linux, opens a blocking zbus connection. With zbus's
`tokio` feature on, that calls `Runtime::block_on` on the worker and
panics ("Cannot start a runtime from within a runtime"); release builds
abort on panic, so the app closed. Reveal through a new app command,
`reveal_in_file_manager`, which runs the same call in `spawn_blocking`.

Untested: no build or run was done for this change.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
(cherry picked from commit 561cb7e)

* app: test that the opener service reveals files through the app's command

The webview must not reach the opener plugin's own reveal command: on Linux
it blocks on D-Bus inside the async runtime and aborts the app.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* app: a linked safetensors repository opens as a managed checkpoint

`atomic-chat://models/huggingface/<owner>/<repo>` names no format and the
Hub opens on GGUF, so a link to a safetensors repository (e.g.
nvidia/Gemma-4-31B-IT-NVFP4) opened a row with nothing to download.
Wherever a managed engine is offered, such a repository (safetensors
weights, no GGUF quant, no MLX tag) is now a managed checkpoint: its card
asks every visible engine for a verdict. Its row reads as the managed format
the Hub shows, else the first engine offered (LocalModelTableItem.format).

Ported from #352, written for the card layout
before the Hub table.

Co-authored-by: Denis <133139087+xDenside@users.noreply.github.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* app: translations pick the plural form for a count

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* app: the server card names the engine that serves the model

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* app: an engine with builds but none active says "No active build"

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* app: HTTPS Proxy reads as a Server page

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* app: tool activity counts one action in the singular

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* app: short replies render their Markdown

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* app: the composer keeps the model name while there is room for it

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* app: model names read once and keep their quant

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* app: Run settings keeps its header in view and shows decimals with a point

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* app: the UI says chat and Atomic Chat everywhere it speaks to the user

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* app: Hardware names the OS properly; endpoint errors name the provider

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* app: toasts open below the window title bar

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* app: the open project is highlighted in the sidebar

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* app: Hub rows name the repo owner, quote the size the download opens on, and say when they were updated in the UI language

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* app: a cloud provider's card links its model list instead of a generic subtitle

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* app: Downloads lists MLX sizes, drafts and unfinished downloads, and frees them

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* app: Videos controls match Images, and a downloaded video model is picked

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* app: FLUX.3 Image Klein as an image family (flux.3-klein)

The catalog entry is AtomicBot-ai/atomic-chat-conf#36; until now the app
dropped the id. It joins DiffusionFamilyId and DIFFUSION_FAMILY_IDS, draws
the BFL mark and runs Create only (sd.cpp runs its reference edits, but
they are not measured yet).

FLUX.3 arrived upstream in build 968 (leejet/stable-diffusion.cpp#2143),
so the engine gate is now per family: requiredEngineTag names
master-968-8cd731e for Klein and master-883-137f740 for Qwen Image 2.1,
its Turbo and Krea 2 Turbo. The load refusal and the update offer name
the family's own floor instead of always 883.

Refs #372

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* app: pin atomic-chat-core 0.18.7

The core release with:
- FLUX.3 Klein (flux.3-klein) held to stable-diffusion.cpp build 968 and
  served Create only, as the app's own gate and workflows do;
- ATOMIC_DIFFUSION_BACKEND=cpu starting every image load on the CPU
  backend;
- engine-candidate checks for stable-diffusion.cpp and PrismML builds.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

---------

Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
Co-authored-by: Misha Skvortsov <m.skvortsovvv@gmail.com>
Co-authored-by: xDenside <volyaden54@gmail.com>
Co-authored-by: Denis <133139087+xDenside@users.noreply.github.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant