Skip to content

Commit 433d609

Browse files
committed
refactor: rename thought-signature to external-id and remove skip validator
Renames internal usage of `thought-signature` to `external-id` to align with other providers. Removes `skipThoughtSignatureValidator` configuration as it is no longer needed. Addresses PR comments.
1 parent cf89b17 commit 433d609

File tree

6 files changed

+30
-97
lines changed

6 files changed

+30
-97
lines changed

docs/configuration.md

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -582,7 +582,6 @@ To configure, add your OTLP collector config via `:otlp` map following [otlp aut
582582
completionUrlRelativePath?: string;
583583
thinkTagStart?: string;
584584
thinkTagEnd?: string;
585-
skipThoughtSignatureValidator?: boolean;
586585
models: {[key: string]: {
587586
modelName?: string;
588587
extraPayload?: {[key: string]: any}

src/eca/features/chat.clj

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -560,7 +560,7 @@
560560
:server (:server event-data)
561561
:arguments (:arguments event-data)
562562
:origin (:origin event-data)
563-
:thought-signature (:thought-signature event-data)
563+
:external-id (:external-id event-data)
564564
:decision-reason {:code :none
565565
:text "No reason"})
566566

@@ -1125,7 +1125,7 @@
11251125
:finish (do (add-to-history! {:role "assistant"
11261126
:content [{:type :text :text @received-msgs*}]})
11271127
(finish-chat-prompt! :idle chat-ctx))))
1128-
:on-prepare-tool-call (fn [{:keys [id full-name arguments-text thought-signature]}]
1128+
:on-prepare-tool-call (fn [{:keys [id full-name arguments-text external-id]}]
11291129
(assert-chat-not-stopped! chat-ctx)
11301130
(let [tool (tool-by-full-name full-name all-tools)]
11311131
(transition-tool-call! db* chat-ctx id :tool-prepare
@@ -1134,7 +1134,7 @@
11341134
:full-name full-name
11351135
:origin (:origin tool)
11361136
:arguments-text arguments-text
1137-
:thought-signature thought-signature
1137+
:external-id external-id
11381138
:summary (f.tools/tool-call-summary all-tools full-name nil config)})))
11391139
:on-tools-called (on-tools-called! chat-ctx received-msgs* add-to-history!)
11401140
:on-reason (fn [{:keys [status id text external-id]}]

src/eca/llm_api.clj

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -160,7 +160,6 @@
160160
:tools tools
161161
:think-tag-start "<thought>"
162162
:think-tag-end "</thought>"
163-
:skip-thought-signature-validator? (get-in provider-config [:skipThoughtSignatureValidator])
164163
:extra-payload (merge {:parallel_tool_calls false}
165164
(when reason?
166165
{:extra_body {:google {:thinking_config {:include_thoughts true}}}})

src/eca/llm_providers/openai_chat.clj

Lines changed: 17 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -70,13 +70,13 @@
7070
(let [tools-to-call (->> (:choices body)
7171
(mapcat (comp :tool_calls :message))
7272
(map (fn [tool-call]
73-
(cond-> {:id (:id tool-call)
74-
:full-name (:name (:function tool-call))
75-
:arguments (json/parse-string (:arguments (:function tool-call)))}
76-
;; Preserve Google Gemini thought signatures
77-
(get-in tool-call [:extra_content :google :thought_signature])
78-
(assoc :thought-signature
79-
(get-in tool-call [:extra_content :google :thought_signature]))))))]
73+
(cond-> {:id (:id tool-call)
74+
:full-name (:name (:function tool-call))
75+
:arguments (json/parse-string (:arguments (:function tool-call)))}
76+
;; Preserve Google Gemini thought signatures
77+
(get-in tool-call [:extra_content :google :thought_signature])
78+
(assoc :external-id
79+
(get-in tool-call [:extra_content :google :thought_signature]))))))]
8080
{:usage (parse-usage (:usage body))
8181
:reason-id (str (random-uuid))
8282
:tools-to-call tools-to-call
@@ -133,22 +133,17 @@
133133

134134
(defn ^:private transform-message
135135
"Transform a single ECA message to OpenAI format. Returns nil for unsupported roles."
136-
[{:keys [role content] :as _msg} supports-image? think-tag-start think-tag-end skip-thought-signature-validator?]
136+
[{:keys [role content] :as _msg} supports-image? think-tag-start think-tag-end]
137137
(case role
138138
"tool_call" {:type :tool-call ; Special marker for accumulation
139139
:data (cond-> {:id (:id content)
140140
:type "function"
141141
:function {:name (:full-name content)
142142
:arguments (json/generate-string (:arguments content))}}
143143
;; Preserve Google Gemini thought signatures if present
144-
(:thought-signature content)
144+
(:external-id content)
145145
(assoc-in [:extra_content :google :thought_signature]
146-
(:thought-signature content))
147-
;; Use bypass signature when thought signature is missing and bypass is enabled
148-
(and skip-thought-signature-validator?
149-
(not (:thought-signature content)))
150-
(assoc-in [:extra_content :google :thought_signature]
151-
"skip_thought_signature_validator"))}
146+
(:external-id content)))}
152147
"tool_call_output" {:role "tool"
153148
:tool_call_id (:id content)
154149
:content (llm-util/stringfy-tool-result content)}
@@ -209,9 +204,9 @@
209204
'assistant' role message, not as separate messages. This function ensures compliance
210205
with that requirement by accumulating tool calls and flushing them into assistant
211206
messages when a non-tool_call message is encountered."
212-
[messages supports-image? think-tag-start think-tag-end skip-thought-signature-validator?]
207+
[messages supports-image? think-tag-start think-tag-end]
213208
(->> messages
214-
(map #(transform-message % supports-image? think-tag-start think-tag-end skip-thought-signature-validator?))
209+
(map #(transform-message % supports-image? think-tag-start think-tag-end))
215210
(remove nil?)
216211
accumulate-tool-calls
217212
(filter valid-message?)))
@@ -308,15 +303,15 @@
308303
Compatible with OpenRouter and other OpenAI-compatible providers."
309304
[{:keys [model user-messages instructions temperature api-key api-url url-relative-path
310305
past-messages tools extra-payload extra-headers supports-image?
311-
think-tag-start think-tag-end skip-thought-signature-validator? http-client]}
306+
think-tag-start think-tag-end http-client]}
312307
{:keys [on-message-received on-error on-prepare-tool-call on-tools-called on-reason on-usage-updated] :as callbacks}]
313308
(let [think-tag-start (or think-tag-start "<think>")
314309
think-tag-end (or think-tag-end "</think>")
315310
stream? (boolean callbacks)
316311
messages (vec (concat
317312
(when instructions [{:role "system" :content instructions}])
318-
(normalize-messages past-messages supports-image? think-tag-start think-tag-end skip-thought-signature-validator?)
319-
(normalize-messages user-messages supports-image? think-tag-start think-tag-end skip-thought-signature-validator?)))
313+
(normalize-messages past-messages supports-image? think-tag-start think-tag-end)
314+
(normalize-messages user-messages supports-image? think-tag-start think-tag-end)))
320315

321316
body (deep-merge
322317
(assoc-some
@@ -346,7 +341,7 @@
346341
(when-let [{:keys [new-messages]} (on-tools-called tools-to-call)]
347342
(let [new-messages-list (vec (concat
348343
(when instructions [{:role "system" :content instructions}])
349-
(normalize-messages new-messages supports-image? think-tag-start think-tag-end skip-thought-signature-validator?)))
344+
(normalize-messages new-messages supports-image? think-tag-start think-tag-end)))
350345
new-rid (llm-util/gen-rid)]
351346
(reset! tool-calls* {})
352347
(base-chat-request!
@@ -438,7 +433,7 @@
438433
name (assoc :full-name name)
439434
args (update :arguments-text (fnil str "") args)
440435
;; Store thought signature for Google Gemini
441-
thought-signature (assoc :thought-signature thought-signature))))
436+
thought-signature (assoc :external-id thought-signature))))
442437
(when-let [updated-tool-call (get @tool-calls* tool-key)]
443438
(when (and (:id updated-tool-call)
444439
(:full-name updated-tool-call)

test/eca/features/chat_tool_call_state_test.clj

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -35,7 +35,7 @@
3535
:server "eca"
3636
:arguments tool-arguments
3737
:origin tool-origin
38-
:thought-signature nil
38+
:external-id nil
3939
:decision-reason {:code :none
4040
:text "No reason"}}
4141
(#'f.chat/get-tool-call-state @db* chat-id tool-call-id))

test/eca/llm_providers/openai_chat_test.clj

Lines changed: 9 additions & 69 deletions
Original file line numberDiff line numberDiff line change
@@ -34,8 +34,7 @@
3434
{:role "assistant" :content "I found 2 files"}]
3535
true
3636
thinking-start-tag
37-
thinking-end-tag
38-
false))))
37+
thinking-end-tag))))
3938

4039
(testing "Skips unsupported message types"
4140
(is (match?
@@ -49,8 +48,7 @@
4948
{:role "assistant" :content "Hi"}]
5049
true
5150
thinking-start-tag
52-
thinking-end-tag
53-
false))))))
51+
thinking-end-tag))))))
5452

5553
(deftest extract-content-test
5654
(testing "String input"
@@ -105,8 +103,7 @@
105103
:arguments {:location "NYC"}}}
106104
true
107105
thinking-start-tag
108-
thinking-end-tag
109-
false))))
106+
thinking-end-tag))))
110107

111108
(testing "Tool call output transformation"
112109
(is (match?
@@ -119,17 +116,15 @@
119116
:output {:contents [{:type :text :text "Sunny, 75°F"}]}}}
120117
true
121118
thinking-start-tag
122-
thinking-end-tag
123-
false))))
119+
thinking-end-tag))))
124120

125121
(testing "Unsupported role returns nil"
126122
(is (nil?
127123
(#'llm-providers.openai-chat/transform-message
128124
{:role "unsupported" :content "test"}
129125
true
130126
thinking-start-tag
131-
thinking-end-tag
132-
false)))))
127+
thinking-end-tag)))))
133128

134129
(deftest accumulate-tool-calls-test
135130
(testing "Multiple sequential tool calls get grouped"
@@ -171,8 +166,8 @@
171166
(is (#'llm-providers.openai-chat/valid-message?
172167
{:role "user" :content "Hello world"}))))
173168

174-
(deftest thought-signature-test
175-
(testing "Tool call with thought signature is preserved"
169+
(deftest external-id-test
170+
(testing "Tool call with external-id is preserved"
176171
(is (match?
177172
{:type :tool-call
178173
:data {:id "call-123"
@@ -185,65 +180,10 @@
185180
:content {:id "call-123"
186181
:full-name "eca__get_weather"
187182
:arguments {:location "Paris"}
188-
:thought-signature "signature-abc-123"}}
183+
:external-id "signature-abc-123"}}
189184
true
190185
thinking-start-tag
191-
thinking-end-tag
192-
false))))
193-
194-
(testing "Tool call without thought signature when bypass is disabled"
195-
(is (match?
196-
{:type :tool-call
197-
:data {:id "call-456"
198-
:type "function"
199-
:function {:name "eca__get_weather"
200-
:arguments "{\"location\":\"London\"}"}}}
201-
(#'llm-providers.openai-chat/transform-message
202-
{:role "tool_call"
203-
:content {:id "call-456"
204-
:full-name "eca__get_weather"
205-
:arguments {:location "London"}}}
206-
true
207-
thinking-start-tag
208-
thinking-end-tag
209-
false))))
210-
211-
(testing "Tool call without thought signature gets bypass when enabled"
212-
(is (match?
213-
{:type :tool-call
214-
:data {:id "call-789"
215-
:type "function"
216-
:function {:name "eca__get_weather"
217-
:arguments "{\"location\":\"Tokyo\"}"}
218-
:extra_content {:google {:thought_signature "skip_thought_signature_validator"}}}}
219-
(#'llm-providers.openai-chat/transform-message
220-
{:role "tool_call"
221-
:content {:id "call-789"
222-
:full-name "eca__get_weather"
223-
:arguments {:location "Tokyo"}}}
224-
true
225-
thinking-start-tag
226-
thinking-end-tag
227-
true))))
228-
229-
(testing "Tool call with thought signature is not overridden by bypass"
230-
(is (match?
231-
{:type :tool-call
232-
:data {:id "call-999"
233-
:type "function"
234-
:function {:name "eca__get_weather"
235-
:arguments "{\"location\":\"Berlin\"}"}
236-
:extra_content {:google {:thought_signature "original-signature"}}}}
237-
(#'llm-providers.openai-chat/transform-message
238-
{:role "tool_call"
239-
:content {:id "call-999"
240-
:full-name "eca__get_weather"
241-
:arguments {:location "Berlin"}
242-
:thought-signature "original-signature"}}
243-
true
244-
thinking-start-tag
245-
thinking-end-tag
246-
true)))))
186+
thinking-end-tag)))))
247187

248188
(defn process-text-think-aware [texts]
249189
(let [content-buffer* (atom "")

0 commit comments

Comments
 (0)