Repository navigation
Conversation
tobocop2
force-pushed
the
feat/settings-resolver
branch
from
September 27, 2026 07:44
77efd5a to
d740362
Compare
tobocop2
marked this pull request as ready for review
September 27, 2026 22:30
Each setting's effective value and the layer that supplies it now come from one function over three layers: a set LILBEE_* variable, a top-level key in config.toml, and the [profile] table's values. An empty value in any layer is unset, except on a model role that can be off (vision_model, reranker_model), where it clears the model. With none of those the pydantic default applies, reported as built_in, or as auto for a field flagged derived (its default means lilbee computes the value at runtime). Config() construction, the data-root overlay used by the CLI and MCP, and settings updates all assign cfg from that resolver, so cfg holds what a fresh Config() for the same root would hold: - An update under a set LILBEE_X persists the value but leaves cfg on the env value, which is what a restart gives. - A null update resolves to the profile value or the built-in, not None. - The overlay for a new data root resets a key that root does not set, instead of keeping the previous root's value. The two pydantic-settings source classes are replaced by one source that yields the resolver's env, user and profile values. The [profile] table is only read by the resolver; it is not a Config field and no settings surface can write it. An unreadable config.toml or LILBEE_SKIP_TOML_CONFIG=1 empties both file layers. CLI flags given before the subcommand are kept and re-applied after the subcommand's own data-root overlay, which previously replaced --model with the persisted chat_model. MCP settings_list and settings_get report each setting's source as env, user, profile, built_in or auto. The schema route builds its list off the event loop, since listing now reads config.toml. The test suite points LILBEE_DATA at each test's own data root instead of setting the skip flag, so a settings write reads back the file it wrote.
A settings update derived the embedder's width from the requested model before the resolver ran. Under LILBEE_EMBEDDING_MODEL the model stayed on the env value while the width took the new model's. The width is now derived after the sync, from the resolved model. When an env var pins an unusable chat or embedding model, TUI startup no longer persists a fallback or announces a swap. The env value wins, so the notice names the variable and says how to clear it. The test suite redirects the platform default data root to a scratch directory, so --global tests never read the developer's config.toml. A guard test fails if any config read reaches the real root. A blank LILBEE_<FIELD> counts as an empty one. main_gpu reports built_in and chat_n_ctx_target reports auto. The config source hands pydantic every resolved value, since the built-ins it filtered out validate to the same defaults.
Every CLI invocation re-resolves each writable setting and model role from env, config.toml and profile, falling back to the built-in value. The interactive integration fixture set its models and tuning on cfg in memory only, so each CLI call reset embedding_model to empty and the search, rebuild and crawl tests failed with no embedding model. The fixture now writes those settings to the test root's config.toml, the layer the CLI reads, and mirrors them on cfg for the in-process sync. Fields the overlay does not touch stay in memory.
PATCH /api/config and MCP settings_set forward raw JSON straight to cfg with no blank-stripping of their own, unlike the resolver's env/TOML layers. A blank string for temperature (or top_p, repeat_penalty, top_k_sampling, num_ctx, seed) still reaches the before-validator, which is the only thing turning it into None instead of a pydantic type error. Add a test through that write boundary so the branch stays covered.
tobocop2
force-pushed
the
feat/settings-resolver
branch
from
September 27, 2026 23:51
de6478c to
558b472
Compare
tobocop2
marked this pull request as draft
September 27, 2026 23:51
Owner
Author
|
This change is now part of #1003, which collects every Profiles pull request on one branch. Review and merge happen there. The branch stays in place. |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Problem
A setting's value can come from an environment variable,
config.toml, or the built-in default, and lilbee worked that out in several places that disagreed. A PATCH changed the running value even while aLILBEE_*variable pinned it. Switching data directories could keep a value from the previous one. A--modelflag was lost when a subcommand reloaded the saved settings. Nothing could say where a value came from, which profiles and the "set by you" markers need.Solution
One resolver computes each setting's value and its source, and every write path goes through it: building the config, reloading saved settings, and settings updates. The running value matches what the resolver answers, apart from per-run CLI flags and two writers (placement and linked folders) that follow in a later change.
The MCP
lilbee_settings_listandlilbee_settings_gettools gain asourcefield:env,user,profile,built_inorauto.automeans the setting is at its built-in value and lilbee computes it at runtime.Notes
GET /api/configkeeps its flat shape. A PATCH that sendsnullnow reads back the value the setting falls back to (the profile's value, else the built-in) instead ofnull.A setting pinned by a
LILBEE_*variable stays pinned. When the pinned chat model cannot be used, the TUI names the variable instead of saving a fallback that would never take effect. The MCPinittool now honoursLILBEE_DOCUMENTS_DIR, as the CLI already did.This stacks on #939.