Conversation
`--cfg assistant.model.parameters.other.presence_penalty=0.5` reaches
the parameter, where before it created a table nested inside itself:
`other = { other = { presence_penalty = 0.5 } }`. Clearing the table
with `--cfg assistant.model.parameters.other=null` empties it, where
before it removed an entry that happened to be named `other` and left
the rest in place.
Unrecognised keys in the parameter block are provider parameters JP
does not model, and the last arm of the block's key-value dispatch
collected them. `other` had no arm of its own, so it fell to that arm
too and addressed an entry rather than the table.
A config file already reserves the name: `KNOWN_KEYS` lists `other`, so
`[assistant.model.parameters] other = 5` is read as the explicit table
and not as a parameter called `other`. `--cfg` now agrees with it.
BREAKING CHANGE: `--cfg` cannot set a provider parameter named `other`
Write it inside the table instead, as a config file already must:
`--cfg assistant.model.parameters.other.other=5`.
Signed-off-by: Jean Mertz <git@jeanmertz.com>
`assistant.model.parameters.other` is where the parameters JP does not model are collected, not a key to write. A provider parameter goes in the block itself: ```toml [assistant.model.parameters] presence_penalty = 0.5 ``` The doc comment advertised `[assistant.model.parameters.other]` as an equally good spelling, which put a field that exists to be invisible in front of the user, in both the generated `config.toml` and the exported JSON schema. Hiding it outright is not available. `#[setting(exclude)]` takes a field out of the schema, and the compat layer strips from every stored config whatever the schema does not name, so excluding this one would discard the provider parameters each existing conversation was created with. A test now writes a parameter, reads it back, and fails if it goes missing, so the next attempt to hide the field is caught here rather than in someone's conversation history. Signed-off-by: Jean Mertz <git@jeanmertz.com>
A provider parameter JP does not model is written in the parameter
block, and reaches the wire the same way:
```toml
[assistant.model.parameters]
presence_penalty = 0.5
```
Before, it was collected into an `other` field that serialized under
its own name, so every stored conversation config carried
`other = { presence_penalty = 0.5 }` and the generated `config.toml`
and JSON schema both offered `other` as a key to write. Flattening the
field makes it what it always was: the bucket, not a key. The generated
TOML skips a flattened field, so it no longer appears there at all.
Existing configs keep working. A nested `other` table, in a config file
or a stored conversation, is hoisted into the block on read, with a
nested entry still winning a collision against a sibling of the same
name exactly as it did when the nested form was documented.
The mechanism the collecting rests on is now serde's rather than ours.
`deserialize_collecting_other` split the block against a hand-kept
`KNOWN_KEYS` list, which a new typed field had to be added to or be
silently forwarded to the provider as a raw parameter; both are gone,
along with the test that guarded the list. `allow_unknown_fields` on
the block is what lets serde flatten a map there, matching
`conversation.tools`.
It is also what keeps the parameters. The compat layer strips from
every stored config whatever the schema does not name, and skips a
struct holding a flattened field for that reason, so a provider
parameter survives a load that would otherwise discard it. A test in
`jp_conversation` reads one back and fails if it goes missing.
BREAKING CHANGE: `assistant.model.parameters.other` is no longer a key
A provider parameter is written directly in the parameter block. The
nested form is still read, so no existing config or conversation needs
changing, but `--cfg assistant.model.parameters.other.presence_penalty`
now sets a parameter named `other` holding an object rather than
reaching `presence_penalty`. Write
`--cfg assistant.model.parameters.presence_penalty=0.5` instead.
Signed-off-by: Jean Mertz <git@jeanmertz.com>
JeanMertz
force-pushed
the
config-parameter-flatten
branch
from
September 8, 2026 08:09
340e8c5 to
8d212f4
Compare
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.
A model parameter JP does not model is collected into
other, whichwas a real key on the wire:
presence_penalty = 0.5was stored asother = { presence_penalty = 0.5 }. It is flattened, so the blockholds the parameter directly and
otheris gone from the generatedconfig.tomland from the schema as a key to write.A config file or stored conversation written with the nested table is
hoisted on read, so nothing needs migrating by hand.
Deleting the hand-rolled collector removes a hand-maintained list of
known keys, so a newly added typed field can no longer be silently
forwarded to the provider as a raw parameter. It also inverts a
data-loss risk: stripping skips a struct holding a flattened field, so
provider parameters survive a load that previously kept them only
because
otherhappened to be named in the schema.BREAKING CHANGE:
otheris no longer a reserved parameter name--cfg ...parameters.othernames a parameter calledother, not thecollector. Write an unrecognized parameter directly:
--cfg ...parameters.presence_penalty=0.5.