@@ -11,6 +11,78 @@ target.
1111
1212## [ Unreleased]
1313
14+ ## [ 3.4.0] — 2026-10-11
15+
16+ Conversations with reasoning models behind Chat-format upstreams keep their
17+ reasoning from turn to turn, Gemini's tool loops keep their thought
18+ signatures through a conversion, and a tool call that a Chat-format model
19+ writes into its answer text reaches the caller as a tool call. The
20+ thinkwatch-core crates move from v0.68.0 to v0.69.0.
21+
22+ ### Read before upgrading
23+
24+ - ** Converted answers from Chat-format upstreams can carry tool calls that
25+ arrived as text before.** Self-hosted and relayed Chat-format models
26+ (DeepSeek, GLM, Qwen, Llama and others) sometimes write a tool call into
27+ ` content ` in the template they were trained on instead of answering with
28+ ` tool_calls ` . On a route that converts the request to the Chat format,
29+ such a call to a tool the request defined now reaches the caller as a
30+ structured tool call, which the caller executes, where it used to be a
31+ tagged piece of prose the caller showed and did nothing with. Tool-call
32+ inspection sees these calls like any other and refuses or cuts them under
33+ the same rules; the request log's response body records them as tool
34+ calls, and a recovered call ends the answer with the tool-use stop reason
35+ instead of ` stop ` . A request that defined no tools, a name the request
36+ did not define, and a bare JSON object in prose stay text. A Chat caller
37+ on a Chat-format route is forwarded as sent and unchanged. No setting,
38+ schema, API route, Helm value or Redis key changes.
39+
40+ ### Fixed
41+
42+ - ** Gemini thought signatures are not counted as answer text.** When a
43+ request's usage has to be estimated (` usage_estimated ` ), the
44+ ` thoughtSignature ` on a Gemini thought or function call — an opaque blob
45+ of up to several kilobytes — was counted as output text; it is left out
46+ now, as the other formats' reasoning signatures were.
47+
48+ ### Changed
49+
50+ - thinkwatch-core crates (tw-bedrock, tw-breaker, tw-dialect, tw-guard)
51+ v0.68.0 → v0.69.0. Only tw-dialect changes:
52+ - ** Reasoning from a Chat-format upstream round-trips** (tw-dialect).
53+ Reasoning a Chat-format upstream returned (` reasoning_content ` , or
54+ ` reasoning ` as OpenRouter and vLLM call it) was dropped from the next
55+ turn's request on every route, so a Claude Code or Codex conversation
56+ with tools against DeepSeek, which requires the reasoning of a
57+ tool-calling turn on the following requests of that turn, lost it every
58+ turn. Such reasoning is now carried in the caller's own format with a
59+ ` tw1.ch. ` signature, read back on the next turn, and written as
60+ ` reasoning_content ` only to a Chat-format upstream; to an upstream of
61+ another format it is left out as before, and reasoning another vendor
62+ signed is still not sent to a Chat-format upstream. Consecutive
63+ assistant messages are merged before a request is written in the Chat
64+ format, so a Responses caller's reasoning, text and tool call of one
65+ turn arrive as one message. The reasoning history a request carries
66+ back counts as its input, so the input tokens of those turns grow by
67+ it, as the upstream charges them.
68+ - ** Gemini thought signatures on function calls are kept** (tw-dialect).
69+ Gemini with thinking puts a turn's thought signature on the first
70+ ` functionCall ` part, and the conversion only read signatures from
71+ thought parts, so a converted Gemini tool loop lost the signature and
72+ with it the model's reasoning continuity. The signature on a function
73+ call is now carried through a conversion and written back on the
74+ ` functionCall ` part; a call with no real signature gets the
75+ ` skip_thought_signature_validator ` placeholder as before. A Gemini
76+ request forwarded as sent that carries a signature from another route
77+ on a ` functionCall ` part keeps the part with the placeholder, where the
78+ part was removed and the tool loop broke.
79+ - ** Tool calls written into a Chat-format upstream's answer text are
80+ recognised** (tw-dialect): see Read before upgrading. In this edition
81+ the answer assembled for the request log and the cache of a Chat
82+ caller's stream forwarded as sent to a Chat-format upstream keeps such
83+ a call as the text the caller received, rather than the structured call
84+ the conversion would have made of it.
85+
1486## [ 3.3.1] — 2026-10-10
1587
1688Streams are logged as they ended. A caller that hangs up once it has read
@@ -1696,7 +1768,8 @@ unreleased builds should: stop the gateway, run `db/schema.sql`
16961768against PostgreSQL, restart against this tag. The schema is
16971769idempotent end-to-end, so the apply is safe to repeat.
16981770
1699- [ Unreleased ] : https://github.com/ThinkWatchProject/ThinkWatch/compare/v3.3.1...HEAD
1771+ [ Unreleased ] : https://github.com/ThinkWatchProject/ThinkWatch/compare/v3.4.0...HEAD
1772+ [ 3.4.0 ] : https://github.com/ThinkWatchProject/ThinkWatch/releases/tag/v3.4.0
17001773[ 3.3.1 ] : https://github.com/ThinkWatchProject/ThinkWatch/releases/tag/v3.3.1
17011774[ 3.3.0 ] : https://github.com/ThinkWatchProject/ThinkWatch/releases/tag/v3.3.0
17021775[ 3.2.1 ] : https://github.com/ThinkWatchProject/ThinkWatch/releases/tag/v3.2.1
0 commit comments