fix: reasoning_field на каждом assistant-сообщении (не только с tool_calls)
Build LLM Proxy / Build and push (release) Successful in 41s
Build LLM Proxy / Build and push (release) Successful in 41s
Console Go (deepseek в thinking-режиме) в stateful-сессиях требует reasoning_content на КАЖДОМ assistant-сообщении истории — живые 400 «The reasoning_content in the thinking mode must be passed back to the API» (19:01, session 890fc602) шли именно на чистых ассистент-турах без tool_calls, которые старый гейт пропускал. Снял гейт: поле дописывается на каждом assistant-сообщении (текст из reasoning / reasoning_details, пустая строка при reasoning_empty_ok) — как это делает сам opencode («Deepseek requires all assistant messages to have reasoning on them»). Тесты переписаны под новое поведение.
This commit is contained in:
@@ -710,11 +710,14 @@ internal fun transformThinkMessage(obj: JsonObject, thinkMode: String): String?
|
||||
/**
|
||||
* Достроить нативное поле рассуждений для апстримов, которые его требуют
|
||||
* (Console Go / deepseek в thinking-режиме): если у провайдера объявлено
|
||||
* `reasoningField`, то в каждом assistant-сообщении с непустым `tool_calls`
|
||||
* добавляем это поле, ЕСЛИ его там ещё нет. Текст берём из `reasoning`
|
||||
* `reasoningField`, то в каждом assistant-сообщении добавляем это поле,
|
||||
* ЕСЛИ его там ещё нет (не только в тех, что с tool_calls — deepseek
|
||||
* требует `reasoning_content` на КАЖДОМ ассистент-сообщении в thinking-режиме,
|
||||
* см. «must be passed back to the API»). Текст берём из `reasoning`
|
||||
* (строка) или из `reasoning_details` (элементы с `type == "reasoning.text"`).
|
||||
* Существующее непустое поле НЕ перезаписываем. При полном отсутствии текста
|
||||
* пишем пустую строку, только если `emptyOk`.
|
||||
* пишем пустую строку, только если `emptyOk` — апстрим требует самого
|
||||
* НАЛИЧИЯ поля, даже пустого (так делает и сам opencode).
|
||||
* Тело возвращается без изменений (тот же объект), если менять нечего.
|
||||
*/
|
||||
internal fun applyReasoningField(body: JsonObject, field: String?, emptyOk: Boolean): JsonObject {
|
||||
@@ -725,8 +728,6 @@ internal fun applyReasoningField(body: JsonObject, field: String?, emptyOk: Bool
|
||||
val msg = el as? JsonObject ?: return@map el
|
||||
val role = (msg["role"] as? JsonPrimitive)?.takeIf { it.isString }?.content
|
||||
if (role != "assistant") return@map el
|
||||
val toolCalls = msg["tool_calls"] as? JsonArray
|
||||
if (toolCalls == null || toolCalls.isEmpty()) return@map el
|
||||
val existing = (msg[field] as? JsonPrimitive)?.takeIf { it.isString }?.content
|
||||
if (existing != null && existing.isNotEmpty()) return@map el
|
||||
val text = reasoningTextOf(msg)
|
||||
|
||||
Reference in New Issue
Block a user