Files
Agent-Native/runtime/llm/reasoning_split_test.go
T
weichen 1f25049492
ci / vet-and-test (pull_request) Successful in 50s
ci / docker-checkout-hostgateway (pull_request) Successful in 1s
Carry tool CallID in loop events and add reasoning_split to the chat client
Why: Parallel tool execution makes same-turn tool events interleave, so
consumers can no longer pair starts and ends by order; the kernel Event
needs the call ID. MiniMax interleaved-thinking models stream their
reasoning inside content <think> blocks unless the OpenAI-compatible
request opts in with reasoning_split=true, which forces reasoning into
the dedicated reasoning_content field the SSE layer already captures.

Evidence: go test ./... green; new tests TestLoopToolEventsCarryCallID
and TestOpenAIChatBodyReasoningSplit pin both behaviors (regression
anchors for the backend parallel-work change).

Impact: Additive Event.CallID (empty for non-tool events; existing
consumers unaffected) and an opt-in Client.ReasoningSplit flag that only
adds a request field when set. No default behavior change.

Refs: Agent-System-Dev proposal 2026-10-10-agent-delegation-routing-sandbox.md
(F2/F5), Dev task feature/agent-e1-parallel-fixes.
2026-10-10 08:33:53 +00:00

48 lines
1.3 KiB
Go

package llm
import (
"context"
"encoding/json"
"io"
"net/http"
"net/http/httptest"
"strings"
"testing"
)
// TestOpenAIChatBodyReasoningSplit 验证 Client.ReasoningSplit 置位时
// openai-chat 请求体带 "reasoning_split": true,未置位时不带(未知字段
// 不外溢给别的提供商)。
func TestOpenAIChatBodyReasoningSplit(t *testing.T) {
var bodies []string
srv := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
raw, _ := io.ReadAll(r.Body)
bodies = append(bodies, string(raw))
w.Header().Set("Content-Type", "text/event-stream")
_, _ = io.WriteString(w, "data: [DONE]\n\n")
}))
defer srv.Close()
drain := func(c *Client) {
for range c.Stream(context.Background(), "MiniMax-M3",
[]Message{{Role: RoleUser, Content: "hi"}}, nil, StreamOptions{}) {
}
}
drain(&Client{BaseURL: srv.URL, APIKey: "k"})
drain(&Client{BaseURL: srv.URL, APIKey: "k", ReasoningSplit: true})
if len(bodies) != 2 {
t.Fatalf("requests = %d", len(bodies))
}
if strings.Contains(bodies[0], "reasoning_split") {
t.Fatalf("flag off must not leak the field: %s", bodies[0])
}
var got map[string]any
if err := json.Unmarshal([]byte(bodies[1]), &got); err != nil {
t.Fatal(err)
}
if v, ok := got["reasoning_split"].(bool); !ok || !v {
t.Fatalf("flag on must set reasoning_split=true: %s", bodies[1])
}
}