From 549bc57df2bdd294d325de04c94314055b247d06 Mon Sep 17 00:00:00 2001 From: Frank Date: Fri, 11 Sep 2026 15:56:38 -0700 Subject: [PATCH] fix(hermes): give title generation a working route on frank-small MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Hermes hardcodes response_format=json_schema on its title call. No local back-end implements constrained decoding — frank-small and frank-large both answer 400 'response_format json_object/json_schema is not supported' — so every session logged a title failure and fell back to a message-derived title. The NPU endpoint that used to absorb this call was retired on 2026-09-11. The call now goes out over the Responses transport (the only one that does not forward response_format) with thinking off. A 64-token cap cannot hold a thinking pass plus a title: with the default reasoning effort the model spent all 64 tokens thinking and returned empty content, which is why disabling reasoning is part of the fix and not decoration. Verified against the live endpoint with the real prompt and the real extraction path: raw {"title": "Friendly greeting"} -> title 'Friendly greeting' in 3.4s, where the previous configuration returned 400. --- dankclaw/hermes/config.yaml.example | 14 +++++++++++++- 1 file changed, 13 insertions(+), 1 deletion(-) diff --git a/dankclaw/hermes/config.yaml.example b/dankclaw/hermes/config.yaml.example index 098e5d6..f29234c 100644 --- a/dankclaw/hermes/config.yaml.example +++ b/dankclaw/hermes/config.yaml.example @@ -35,7 +35,19 @@ auxiliary: skills_hub: {provider: dankserver-small, model: frank-small} approval: {provider: dankserver-small, model: frank-small} mcp: {provider: dankserver-small, model: frank-small} - title_generation: {provider: dankserver-small, model: frank-small} + # Title generation goes out over the Responses transport on purpose: Hermes + # hardcodes response_format=json_schema on this one call, no local back-end + # implements constrained decoding (it is a 400), and this transport is the + # only one that drops the field. reasoning.effort=none is required with it — + # the call caps output at 64 tokens, which a thinking pass would consume + # entirely, leaving an empty title. + title_generation: + provider: dankserver-small + model: frank-small + api_mode: codex_responses + extra_body: + reasoning: + effort: none memory_query_rewrite: {provider: custom, model: frank-small, base_url: http://192.168.0.235:7770/v1} tts_audio_tags: {provider: custom, model: frank-small, base_url: http://192.168.0.235:7770/v1} triage_specifier: {provider: dankclaw-large, model: frank-large}