Skip to content

fix(aux): downgrade json_schema response_format for json_object-only providers - #82372

Closed
hetong12345 wants to merge 1 commit into
NousResearch:mainfrom
hetong12345:fix/aux-response-format-downgrade
Closed

hetong12345 wants to merge 1 commit into
NousResearch:mainfrom
hetong12345:fix/aux-response-format-downgrade

Conversation

@hetong12345

Copy link
Copy Markdown

Problem

Since commit f726090 ("feat(sessions): name a session the moment it starts"), title generation sends a strict response_format: {type: json_schema, ...} on every auto-title call. DeepSeek and Moonshot/Kimi Chat Completions endpoints reject json_schema with HTTP 400:

⚠ Auxiliary title generation failed: HTTP 400: This response_format_type is unavailable now

These providers only accept response_format: {type: json_object} (DeepSeek API docs list only json_object; Moonshot/Kimi the same). The failure is silent-ish: the instant derived title remains, but every session on these providers loses its LLM-refined title and the user sees the ⚠ warning on each new session.

Fix

In _call_llm_impl, after the provider is fully resolved (including auto-detection), downgrade the wire response_format from json_schema to json_object when the resolved provider is documented json_object-only (deepseek, moonshot, kimi — substring match, so labels like kimi-coding-cn are caught).

Why this is safe:

  • The title prompt already embeds the expected JSON shape (Reply with JSON only: {"title": "..."}) and callers parse locally (_extract_title_text has JSON + prose fallbacks), so structured output is preserved.
  • Unknown providers fail open (schema is kept) — only providers with documented json_object-only support are downgraded, so no new provider loses schema-constrained output because of this list.
  • json_object mode on DeepSeek requires "json" to appear in the prompt, which the title prompt satisfies.

Verification

  • 18 new unit tests: _provider_rejects_json_schema param matrix + wire-level assertions that call_llm sends json_object for deepseek/kimi-coding-cn and keeps json_schema for openai/openrouter/zai, plus an extra_body non-clobber check.
  • Full tests/agent/test_auxiliary_client.py + tests/agent/test_title_generator.py: 213 passed.
  • Live DeepSeek check: generate_title("帮我查一下之前提的 PR 状态怎么样") returns 查询 PR 状态 — no 400.

…providers

DeepSeek and Moonshot/Kimi Chat Completions endpoints reject response_format
type=json_schema with HTTP 400 ("This response_format_type is unavailable
now"); they only accept json_object. Since commit f726090, title
generation sends a strict json_schema, so every auto-title call on these
providers fails and falls back to the instant derived title.

Downgrade the wire response_format to json_object when the resolved
provider is documented json_object-only. The prompt already pins the JSON
shape and callers parse locally (_extract_title_text), so structured
output is preserved. Unknown providers fail open — the schema is kept.

Verified: new unit tests (18) + full test_auxiliary_client.py and
test_title_generator.py (213 passed); live DeepSeek title generation
returns a title with no 400.
@alt-glitch alt-glitch added type/bug Something isn't working P3 Low — cosmetic, nice to have comp/agent Core agent runtime: loop, agent_init, prompt builder, context-compression, responses endpoint provider/deepseek DeepSeek API provider/kimi Kimi / Moonshot labels Aug 9, 2026
viz-A-viz added a commit to viz-A-viz/hermes-agent that referenced this pull request Aug 10, 2026
Title generation hardcodes a strict json_schema response_format with no
fallback. Providers without structured-output support (DeepSeek returns
HTTP 400 "This response_format type is unavailable now") fail the whole
call and the session keeps its truncated derived name.

Walk a constraint ladder instead: json_schema -> json_object -> no
response_format, pinning thinking off on retries so default-on reasoning
models (DeepSeek V4) don't burn the 64-token budget on reasoning and
return an empty content field. Failures unrelated to response_format
(auth, quota, network) break out immediately - a different format cannot
fix those.

Unlike the other open PRs for this bug (NousResearch#82073, NousResearch#82372, NousResearch#82751, NousResearch#82868,
NousResearch#82890), the retried calls also send thinking: {"type": "disabled"} -
without it DeepSeek answers with an empty content and the title still
never appears, even though the 400 is gone.
@teknium1

Copy link
Copy Markdown
Collaborator

Thanks @hetong12345 for working on the json_schema rejection. This landed on main through #89589 (primary-path retry) and #113966 (5cc8177: DeepSeek profile flag + per-route memo + fallback path), which covers the same symptom on the primary and fallback auxiliary paths and omits the field up front for providers known to reject it. Closing as superseded by the landed fix — the tracking issue (#83390 cluster) is closed with the same references.

@teknium1 teknium1 closed this Sep 17, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

comp/agent Core agent runtime: loop, agent_init, prompt builder, context-compression, responses endpoint P3 Low — cosmetic, nice to have provider/deepseek DeepSeek API provider/kimi Kimi / Moonshot type/bug Something isn't working

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants