fix(canvas): Agent 模型调用 - 修复关闭思考被误判为开启
This commit is contained in:
@@ -132,7 +132,7 @@ async function run() {
|
|||||||
description: tool.description,
|
description: tool.description,
|
||||||
parameters: tool.parameters,
|
parameters: tool.parameters,
|
||||||
})),
|
})),
|
||||||
thinkingLevel: options?.reasoning,
|
thinkingLevel: options?.reasoning ?? "off",
|
||||||
}, options?.signal);
|
}, options?.signal);
|
||||||
for (const text of result.steeringMessages ?? []) {
|
for (const text of result.steeringMessages ?? []) {
|
||||||
await session.steer(text);
|
await session.steer(text);
|
||||||
|
|||||||
@@ -135,7 +135,7 @@ func (s *Service) runCloudAgentModelStep(ctx context.Context, userID, runID stri
|
|||||||
},
|
},
|
||||||
"textOptions": map[string]any{
|
"textOptions": map[string]any{
|
||||||
"stream": true,
|
"stream": true,
|
||||||
"thinking": thinkingLevel != "off",
|
"thinking": cloudAgentPiThinkingEnabled(thinkingLevel),
|
||||||
"maxOutputTokens": cloudAgentStepOutputBudget(state.StepLimits, state.BoostStepOutputBudget),
|
"maxOutputTokens": cloudAgentStepOutputBudget(state.StepLimits, state.BoostStepOutputBudget),
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
@@ -198,6 +198,13 @@ func (s *Service) runCloudAgentModelStep(ctx context.Context, userID, runID stri
|
|||||||
return map[string]any{"text": result.Text, "reasoning": result.Reasoning, "toolCalls": runtimeToolCalls(result.ToolCalls)}, false, nil
|
return map[string]any{"text": result.Text, "reasoning": result.Reasoning, "toolCalls": runtimeToolCalls(result.ToolCalls)}, false, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// cloudAgentPiThinkingEnabled treats an omitted thinking level the same as Pi's
|
||||||
|
// explicit "off" value. Pi omits the field when thinking is disabled, and the
|
||||||
|
// Go JSON decoder represents that omitted field as an empty string.
|
||||||
|
func cloudAgentPiThinkingEnabled(thinkingLevel string) bool {
|
||||||
|
return thinkingLevel != "" && thinkingLevel != "off"
|
||||||
|
}
|
||||||
|
|
||||||
// cloudAgentModelTaskRetryable 按上游真实 HTTP 状态判断失败是否是临时性的:
|
// cloudAgentModelTaskRetryable 按上游真实 HTTP 状态判断失败是否是临时性的:
|
||||||
// 5xx、429、408 与没有拿到任何响应的网络错误可以重试;空回复也可以重试。
|
// 5xx、429、408 与没有拿到任何响应的网络错误可以重试;空回复也可以重试。
|
||||||
// 其余 4xx(参数、鉴权、模型不存在)重试结果不会变,直接失败。
|
// 其余 4xx(参数、鉴权、模型不存在)重试结果不会变,直接失败。
|
||||||
|
|||||||
@@ -10,6 +10,25 @@ import (
|
|||||||
"infinite-canvas/backend/internal/model"
|
"infinite-canvas/backend/internal/model"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
func TestCloudAgentPiThinkingEnabled(t *testing.T) {
|
||||||
|
tests := []struct {
|
||||||
|
name string
|
||||||
|
level string
|
||||||
|
want bool
|
||||||
|
}{
|
||||||
|
{name: "omitted", level: "", want: false},
|
||||||
|
{name: "off", level: "off", want: false},
|
||||||
|
{name: "enabled", level: "medium", want: true},
|
||||||
|
}
|
||||||
|
for _, tt := range tests {
|
||||||
|
t.Run(tt.name, func(t *testing.T) {
|
||||||
|
if got := cloudAgentPiThinkingEnabled(tt.level); got != tt.want {
|
||||||
|
t.Fatalf("cloudAgentPiThinkingEnabled(%q) = %v, want %v", tt.level, got, tt.want)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// 线上复现(诊断号 ag5865c256d9fb9bcbf2f1719a4ec1023c):模型一次写了很长的工具参数,
|
// 线上复现(诊断号 ag5865c256d9fb9bcbf2f1719a4ec1023c):模型一次写了很长的工具参数,
|
||||||
// 流式拼出来的 JSON 多了一个括号,任务报"Agent 工具参数不是完整 JSON"。Go 执行循环
|
// 流式拼出来的 JSON 多了一个括号,任务报"Agent 工具参数不是完整 JSON"。Go 执行循环
|
||||||
// 会带 truncated_tool_arguments 纠偏重做,但 Pi 模型桥接把它当成不可重试的失败,整轮
|
// 会带 truncated_tool_arguments 纠偏重做,但 Pi 模型桥接把它当成不可重试的失败,整轮
|
||||||
@@ -64,6 +83,21 @@ func TestCloudAgentPiModelRetriesTruncatedToolArguments(t *testing.T) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
first := nextStep("")
|
first := nextStep("")
|
||||||
|
var firstTask model.Task
|
||||||
|
if err := db.First(&firstTask, "id = ?", first).Error; err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
var firstInput map[string]any
|
||||||
|
if err := json.Unmarshal([]byte(firstTask.InputJSON), &firstInput); err != nil {
|
||||||
|
t.Fatalf("decode first model task input: %v", err)
|
||||||
|
}
|
||||||
|
textOptions, ok := firstInput["textOptions"].(map[string]any)
|
||||||
|
if !ok {
|
||||||
|
t.Fatalf("first model task textOptions = %#v", firstInput["textOptions"])
|
||||||
|
}
|
||||||
|
if thinking, ok := textOptions["thinking"].(bool); !ok || thinking {
|
||||||
|
t.Fatalf("disabled thinking should be false, got %#v", textOptions["thinking"])
|
||||||
|
}
|
||||||
if err := db.Model(&model.Task{}).Where("id = ?", first).Updates(map[string]any{
|
if err := db.Model(&model.Task{}).Where("id = ?", first).Updates(map[string]any{
|
||||||
"status": model.TaskStatusFailed,
|
"status": model.TaskStatusFailed,
|
||||||
"error": "Agent 工具参数不是完整 JSON:invalid character '}' after array element",
|
"error": "Agent 工具参数不是完整 JSON:invalid character '}' after array element",
|
||||||
|
|||||||
Reference in New Issue
Block a user