Capture OpenAI-compatible reasoning and replay it in assistant history
Why: Interleaved-thinking models (MiniMax, DeepSeek R1) require the assistant's thinking to be passed back verbatim in message history; dropping it degrades later turns. The product's P2-I1 replayed thinking only into the request-side rebuild; with the session transcript becoming the authoritative context (quality P2-I2), capture must live in the kernel so thinking persists in the transcript and replays on every request. Evidence: SELF - TestReasoningCaptureAndReplay covers capture (SSE reasoning_content into Message.Thinking, content unpolluted) and replay (<think> prefix on thinking assistants, untouched non-thinking messages); go vet + go test ./... pass. Impact: sse.go accumulates reasoning deltas into the terminal message's Thinking; client.go toProviderMessages renders captured thinking as a <think> block prefix for assistant messages. Anthropic path unchanged; messages without thinking serialize exactly as before.
This commit is contained in:
+9
-1
@@ -52,6 +52,7 @@ func ParseSSE(ctx context.Context, r io.Reader) <-chan Event {
|
||||
|
||||
func emitParsed(ctx context.Context, r io.Reader, out chan<- Event) {
|
||||
var content strings.Builder
|
||||
var reasoning strings.Builder
|
||||
calls := map[int]*ToolCall{}
|
||||
order := []int{}
|
||||
var usage Usage
|
||||
@@ -108,8 +109,12 @@ func emitParsed(ctx context.Context, r io.Reader, out chan<- Event) {
|
||||
}
|
||||
// reasoning_content(国产 OpenAI 兼容模型的思考链)与正文分流:
|
||||
// 只作为 reasoning_delta 事件外发,不计入 Message.Content(与 runner
|
||||
// stripThinkBlocks"正文无 think"语义对齐)。
|
||||
// stripThinkBlocks"正文无 think"语义对齐)。同时累计进 reasoning——
|
||||
// 交错思考模型(MiniMax/DeepSeek R1 等)要求历史 assistant 原样带回
|
||||
// 思考内容,丢弃会降低后续轮质量;捕获进 Message.Thinking 随会话
|
||||
// 转录持久化,请求序列化侧按需回放。
|
||||
if choice.Delta.Reasoning != "" {
|
||||
reasoning.WriteString(choice.Delta.Reasoning)
|
||||
select {
|
||||
case <-ctx.Done():
|
||||
emitAbort(out, content.String(), ctx.Err())
|
||||
@@ -166,6 +171,9 @@ func emitParsed(ctx context.Context, r io.Reader, out chan<- Event) {
|
||||
order = nil
|
||||
}
|
||||
msg := Message{Role: RoleAssistant, Content: content.String(), StopReason: mapFinish(finished, len(order) > 0)}
|
||||
if reasoning.Len() > 0 {
|
||||
msg.Thinking = []ThinkingBlock{{Thinking: reasoning.String()}}
|
||||
}
|
||||
for _, idx := range order {
|
||||
msg.ToolCalls = append(msg.ToolCalls, *calls[idx])
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user