feat(codex): add agent.text_verbosity config for GPT-5+ response length control - #59844
feat(codex): add agent.text_verbosity config for GPT-5+ response length control#59844qxxaa wants to merge 3 commits into
Conversation
Resubmission of your closed #59711 (same feature). This also competes with the open #20258 (feat(openai): support Responses text verbosity), which likewise implements #20203. Cross-linking so a maintainer can pick a canonical PR: #20258 is earlier and narrower; this PR adds the GPT-5+ model guard, lifts the |
|
Thanks for the focused opt-in implementation. The current main still rejects top-level Problems
Suggested changes
Automated hermes-sweeper review. |
1090baa to
dc14a6c
Compare
|
Hi @teknium1 , thanks for the review. I've rebased onto current main to absorb the Added a config-to-wire regression test in |
dc14a6c to
09a3aa1
Compare
09a3aa1 to
3160fb9
Compare
03d4bab to
36db2ed
Compare
bb7d721 to
a619783
Compare
7715964 to
c39a56d
Compare
c39a56d to
adf4023
Compare
adf4023 to
8c39198
Compare
8c39198 to
fdb7d56
Compare
fdb7d56 to
9793011
Compare
…th control Closes NousResearch#20203. Based on NousResearch#29574's init_agent() loading approach, with added GPT-5+ model guard (vendor prefix handling) and safe dict merge (preserves text.format from request_overrides). Add agent.text_verbosity config key that injects text.verbosity into OpenAI Responses API payloads for GPT-5+ models. Valid values: low, medium, high, or empty string (default, no injection). - Config loaded inside init_agent() from _agent_section - Gateway hot-reload via cache-bust tuple - GPT-5+ model guard with vendor prefix stripping - Safe merge into existing text dict (preserves text.format) - Preflight whitelist + pass-through in codex_responses_adapter - 22 tests (19 transport + 3 preflight adapter)
… regression Rebase onto current main absorbs the issuer_kind="codex_backend" pinning in test_normalize_codex_response_salvage_is_xai_scoped (8fa8aab, NousResearch#64844), fixing CI. Add config-to-wire regression test per sweeper review: exercises agent.text_verbosity -> chat_completion_helpers -> normalized Codex request payload, covering both the injection and empty-default paths. Addresses feedback from NousResearch#59844 (comment).
9793011 to
088c329
Compare
Problem
OpenAI's Responses API exposes
text.verbosityas a first-class requestparameter for controlling output length on GPT-5+ models. Hermes already
surfaces the companion controls -
reasoning_effortfor thinking depth,service_tierfor priority routing - buttext.verbosityhas no configpath. Users who want concise agent output from GPT-5+ have no way to
request it without patching source.
This is not a cosmetic gap. In agent workflows, verbose output compounds:
every excess token in an assistant response becomes input on the next turn,
inflating both cost and time-to-first-token across the entire session.
Measured on GPT-5.5:
text.verbosity: "low"reduced output from 585 to369 words (37%) on identical prompts. Over a 20-turn session, that
reduction applies to every subsequent API call's input context.
The preflight validator in
codex_responses_adapter.pyalso activelyblocks
textas an unsupported field, so even users who discover theextra_bodyworkaround described in #20203 cannot use the nativetop-level parameter that the SDK expects.
Fix
New config key
agent.text_verbosity:Default is empty string - zero behaviour change unless explicitly
opted in. When set, injects
text: {"verbosity": "<value>"}intoResponses API payloads for GPT-5+ models only.
Prior art
@JiehoonKwak's #29574 identified the cleanest loading approach: reading
text_verbosityinsideinit_agent()directly from_agent_section,avoiding the need to thread the parameter through every CLI/gateway/TUI
startup path. This PR adopts that approach and adds two safety layers:
GPT-5+ model guard with vendor prefix handling. Parses the major
version from the model name and injects only for GPT-5+. Strips vendor
prefixes (
openai/gpt-5.5->gpt-5.5) before matching, so customprovider setups and vendor-prefixed model names work without a
provider-name blocklist. Non-GPT models are silently skipped.
Safe dict merge with
request_overrides. Mergesverbosityintoany existing
textdict rather than replacing it. Without this, settingtext.verbositywould clobbertext.formatfromrequest_overrides-silently breaking structured output for anyone combining both features.
Design decisions
Config loading (from #29574): Loaded inside
init_agent()directlyfrom
_agent_section, consistent withreasoning_effort,service_tier,and
tool_use_enforcement. Every agent creation path converges throughinit_agent(), so no caller plumbing is needed.Gateway hot-reload: Cache-bust tuple
("agent", "text_verbosity")added to
_CACHE_BUSTING_CONFIG_KEYS. Config changes evict the cachedagent and rebuild with the new value. Correct because
text_verbosityhas no runtime command (unlike
service_tierwhich has/fast).Model guard (new): Parses
gpt-X.Y, extracts major version, injectsonly when >= 5. Strips vendor prefixes before matching. Non-GPT models
silently skipped.
Dict merge (new): Merges
verbosityinto any existingtextdict,preserving
text.formatfromrequest_overrides.Preflight pass-through:
"text"added to both theallowed_keyswhitelist and the normalization copy path. The preflight validator
requires both - without the copy block, the field passes validation but
is silently dropped before reaching the API.
Transport scope:
codex_responsesonly. Chat completions andAnthropic transports are untouched.
No validation: Consistent with
reasoning_effort. Invalid valuespass through to the API, which returns a clear error.
Files changed (9)
hermes_cli/config.py""in agent defaultsagent/agent_init.py_agent_sectionagent/chat_completion_helpers.pyagent/codex_responses_adapter.pyagent/transports/codex.pygateway/run.pytests/agent/test_codex_responses_adapter.pytests/agent/transports/test_codex_transport.pywebsite/docs/user-guide/configuration.mdRegression risk
Low. Default is empty string. The
if text_verbosity and isinstance(text_verbosity, str)guard ensures no injection unlessexplicitly configured. Zero behaviour change for existing users.
Tests
22 new tests across two files:
19 transport tests:
gpt-prefix (no version): skiptext.format+text.verbositycoexist3 preflight adapter tests:
textdict survives normalizationtext.format+text.verbositycoexist through preflighttextdict correctly dropped82/82 passed (60 existing + 22 new). Zero regressions.
Closes #20203.