@@ -46,7 +46,7 @@ class Message:
4646 def to_api (self ) -> dict [str , Any ]:
4747 d : dict [str , Any ] = {"role" : self .role }
4848 if self .content is not None :
49- d ["content" ] = self .content
49+ d ["content" ] = self ._api_content ()
5050 if self .tool_calls :
5151 d ["tool_calls" ] = [
5252 {
@@ -67,6 +67,27 @@ def to_api(self) -> dict[str, Any]:
6767 d ["name" ] = self .name
6868 return d
6969
70+ def _api_content (self ) -> str | list [Any ] | None :
71+ """Content as sent over the wire, with the reasoning preamble removed.
72+
73+ The client merges streamed ``reasoning_content`` ahead of the
74+ answer into ``content`` (so the live stream and stored history
75+ show the model's thinking). That reasoning is bookkeeping for
76+ the current turn only — re-sending it on later turns just
77+ inflates the context (and skews token estimation) and can
78+ confuse the model, so it is stripped here at the API boundary.
79+ The stored ``content`` is left untouched (the TUI collapses the
80+ reasoning for display via its own helper).
81+ """
82+ content = self .content
83+ if self .reasoning and isinstance (content , str ):
84+ if content .startswith (self .reasoning ):
85+ return content [len (self .reasoning ):].lstrip ("\n " )
86+ stripped = content .lstrip ()
87+ if stripped .startswith (self .reasoning ):
88+ return stripped [len (self .reasoning ):].lstrip ("\n " )
89+ return content
90+
7091 def text (self ) -> str :
7192 """Plain text of the message; empty when no text parts exist."""
7293 if isinstance (self .content , str ):
0 commit comments