fix(llm): strip inline <think> reasoning from Dahl/MiniMax streams; dedupe identical parallel tool calls; hermetic config tests
This commit is contained in:
parent
46d98502dd
commit
546a9315d5
6 changed files with 264 additions and 5 deletions
|
|
@ -178,11 +178,20 @@ func (a *Agent) Run(parent context.Context, sessionID, userText string, emit fun
|
|||
if len(resp.ToolCalls) == 0 {
|
||||
return resp.Content, nil
|
||||
}
|
||||
// Some models (seen with GLM/DeepSeek on Dahl) emit the same call several times in
|
||||
// parallel; identical name+arguments run once and share the result.
|
||||
seen := map[string]string{}
|
||||
for _, tc := range resp.ToolCalls {
|
||||
emit(Event{Type: "tool_call", Tool: tc.Name, Args: tc.Arguments, CallID: tc.ID})
|
||||
out := "error: cancelled by user"
|
||||
if !cancelled() {
|
||||
key := tc.Name + "\x00" + tc.Arguments
|
||||
out, dup := seen[key]
|
||||
switch {
|
||||
case dup:
|
||||
case cancelled():
|
||||
out = "error: cancelled by user"
|
||||
default:
|
||||
out = a.Tools.Call(ctx, tc.Name, tc.Arguments)
|
||||
seen[key] = out
|
||||
}
|
||||
emit(Event{Type: "tool_result", Tool: tc.Name, Text: clip(out, 2000), CallID: tc.ID})
|
||||
// Every tool call gets a result so the history stays valid for the provider.
|
||||
|
|
|
|||
|
|
@ -206,3 +206,29 @@ func TestSummarizeNowManual(t *testing.T) {
|
|||
t.Fatalf("%v %v", sm, err)
|
||||
}
|
||||
}
|
||||
|
||||
func TestDuplicateToolCallsRunOnce(t *testing.T) {
|
||||
st := newStore(t)
|
||||
ss, _ := st.CreateSession(context.Background(), "")
|
||||
n := 0
|
||||
now := func() time.Time { n++; return time.Date(2026, 10, 25, 6, 0, 0, 0, time.UTC) }
|
||||
dup := []llm.ToolCall{{ID: "a", Name: "time_now", Arguments: `{"timezone":"UTC"}`}, {ID: "b", Name: "time_now", Arguments: `{"timezone":"UTC"}`}, {ID: "c", Name: "time_now", Arguments: `{}`}}
|
||||
p := &scripted{resps: []llm.Response{{ToolCalls: dup}, {Content: "ok"}}}
|
||||
a := &Agent{LLM: p, Store: st, Tools: tools.NewRegistry(tools.TimeNow{Now: now}), MaxIterations: 3}
|
||||
if _, err := a.Run(context.Background(), ss.ID, "zeit?", nil); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if n != 2 {
|
||||
t.Fatalf("tool executed %d times, want 2", n)
|
||||
}
|
||||
msgs, _ := st.Messages(context.Background(), ss.ID, 0)
|
||||
tools := 0
|
||||
for _, m := range msgs {
|
||||
if m.Role == llm.RoleTool {
|
||||
tools++
|
||||
}
|
||||
}
|
||||
if tools != 3 {
|
||||
t.Fatalf("every call id needs a result, got %d", tools)
|
||||
}
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue