Skip to content

fix(config): Fix inquiry ceiling inheritance and fields() gaps - #928

Open
JeanMertz wants to merge 7 commits into
mainfrom
config-fix
Open

fix(config): Fix inquiry ceiling inheritance and fields() gaps#928
JeanMertz wants to merge 7 commits into
mainfrom
config-fix

Conversation

@JeanMertz

Copy link
Copy Markdown
Collaborator

conversation.inquiry.assistant.request.max_response_bytes no longer silently disables the output ceiling when only a sibling field (e.g. cache) is set in that block. The inquiry assistant block now mirrors the full assistant config and inherits every unset field from it during resolution, rather than resolving unset fields to Rust's Default. Users can still disable the ceiling for inquiries alone with an explicit 0/"disabled", independent of the parent assistant's setting.

max_response_bytes itself is now a MaxResponseBytes value instead of a bare u32, accepting a byte count or 0, "disabled", "off", false to turn the ceiling off, e.g.
jp config set assistant.request.max_response_bytes disabled. This removes the previous ambiguity where 0 had a different meaning depending on which config layer it appeared in.

AppConfig::fields() (and therefore envs()) now descends into Option<T> nested configs and into unions that describe one value written multiple ways (a shorthand plus its expanded table form), so keys like style.reasoning.summary_model.id,
editor.cmd.program/args/shell, and
conversation.tools.*.enable.state are reported and assignable via env vars, where before the containing block was reported as an opaque leaf. editor.cmd and conversation.tools.*.enable keep their shorthand form addressable too: writing editor.cmd.args after editor.cmd = "code --wait" now expands the shorthand and keeps the named program instead of being rejected.

Schema support for this (schema_union_with, UnionType::expanded_index) lives in schematic_macros/schematic_types, letting a derived struct schema be unioned with hand-declared shapes for types whose Deserialize accepts more than their fields describe.

A query now aborts once a response's generated content passes
`assistant.request.max_response_bytes` (default 1 MiB, `0` disables
it). The turn ends with an error, but any content already streamed
stays in the conversation, and the response is not retried, since
retrying would just regenerate the same runaway. This bounds the cost
of a model that gets stuck generating without end while nobody is
watching the terminal, and applies equally to interactive queries and
to no-terminal collect calls such as title generation and
summarization.

The ceiling wraps the stream outside any provider-level continuation
logic, so a response Anthropic assembles from several chained
`MaxTokens` continuations counts as one response against the limit
rather than resetting per link. Anthropic's own continuation chaining
is separately bounded to 5 links (`MAX_CHAIN_DEPTH`), so a model that
keeps hitting the token ceiling can no longer chain requests forever.

Bytes are counted rather than tokens, since tokens can't be counted
locally; roughly four bytes per token is a reasonable guide when
tuning the value. Set it from the CLI, e.g.
`jp config set assistant.request.max_response_bytes 4096`.

Signed-off-by: Jean Mertz <git@jeanmertz.com>
Signed-off-by: Jean Mertz <git@jeanmertz.com>
Signed-off-by: Jean Mertz <git@jeanmertz.com>
Signed-off-by: Jean Mertz <git@jeanmertz.com>
Signed-off-by: Jean Mertz <git@jeanmertz.com>
`conversation.inquiry.assistant.request.max_response_bytes` no longer
silently disables the output ceiling when only a sibling field (e.g.
`cache`) is set in that block. The inquiry `assistant` block now
mirrors the full `assistant` config and inherits every unset field
from it during resolution, rather than resolving unset fields to
Rust's `Default`. Users can still disable the ceiling for inquiries
alone with an explicit `0`/`"disabled"`, independent of the parent
assistant's setting.

`max_response_bytes` itself is now a `MaxResponseBytes` value instead
of a bare `u32`, accepting a byte count or `0`, `"disabled"`, `"off"`,
`false` to turn the ceiling off, e.g.
`jp config set assistant.request.max_response_bytes disabled`. This
removes the previous ambiguity where `0` had a different meaning
depending on which config layer it appeared in.

`AppConfig::fields()` (and therefore `envs()`) now descends into
`Option<T>` nested configs and into unions that describe one value
written multiple ways (a shorthand plus its expanded table form), so
keys like `style.reasoning.summary_model.id`,
`editor.cmd.program`/`args`/`shell`, and
`conversation.tools.*.enable.state` are reported and assignable via
env vars, where before the containing block was reported as an
opaque leaf. `editor.cmd` and `conversation.tools.*.enable` keep
their shorthand form addressable too: writing `editor.cmd.args` after
`editor.cmd = "code --wait"` now expands the shorthand and keeps the
named program instead of being rejected.

Schema support for this (`schema_union_with`, `UnionType::expanded_index`)
lives in `schematic_macros`/`schematic_types`, letting a derived
struct schema be unioned with hand-declared shapes for types whose
`Deserialize` accepts more than their fields describe.

Signed-off-by: Jean Mertz <git@jeanmertz.com>
Base automatically changed from opus-bat-sht-crazy to main July 31, 2026 17:58
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