refactor: rename tool XML wrapper from tool_calls to tool_batch and add schema attention blocks to tool prompts

This commit is contained in:
CJACK
2026-04-05 19:22:43 +08:00
parent b8e9ca2028
commit ade648033d
6 changed files with 165 additions and 15 deletions

View File

@@ -319,7 +319,8 @@ func TestBuildClaudeToolPromptSupportsOpenAIStyleFunctionTool(t *testing.T) {
"name": "search",
"description": "Search via function tool",
"parameters": map[string]any{
"type": "object",
"type": "object",
"required": []any{"q"},
"properties": map[string]any{
"q": map[string]any{"type": "string"},
},
@@ -334,8 +335,8 @@ func TestBuildClaudeToolPromptSupportsOpenAIStyleFunctionTool(t *testing.T) {
if !containsStr(prompt, "Search via function tool") {
t.Fatalf("expected OpenAI-style function tool description in prompt, got: %q", prompt)
}
if !containsStr(prompt, "\"q\"") {
t.Fatalf("expected parameters schema serialized in prompt, got: %q", prompt)
if !containsStr(prompt, "MUST INCLUDE: q") {
t.Fatalf("expected required-field summary in prompt, got: %q", prompt)
}
}

View File

@@ -90,8 +90,7 @@ func buildClaudeToolPrompt(tools []any) string {
continue
}
names = append(names, name)
schema, _ := json.Marshal(schemaObj)
toolSchemas = append(toolSchemas, fmt.Sprintf("Tool: %s\nDescription: %s\nParameters: %s", name, desc, schema))
toolSchemas = append(toolSchemas, util.FormatToolSchemaAttentionBlock(name, desc, schemaObj))
}
if len(toolSchemas) == 0 {
return ""

View File

@@ -2,7 +2,6 @@ package openai
import (
"encoding/json"
"fmt"
"strings"
"github.com/google/uuid"
@@ -44,11 +43,7 @@ func injectToolPrompt(messages []map[string]any, tools []any, policy util.ToolCh
continue
}
names = append(names, name)
if desc == "" {
desc = "No description available"
}
b, _ := json.Marshal(schema)
toolSchemas = append(toolSchemas, fmt.Sprintf("Tool: %s\nDescription: %s\nParameters: %s", name, desc, string(b)))
toolSchemas = append(toolSchemas, util.FormatToolSchemaAttentionBlock(name, desc, schema))
}
if len(toolSchemas) == 0 {
return messages, names

View File

@@ -34,7 +34,11 @@ func TestBuildOpenAIFinalPrompt_HandlerPathIncludesToolRoundtripSemantics(t *tes
"name": "get_weather",
"description": "Get weather",
"parameters": map[string]any{
"type": "object",
"type": "object",
"required": []any{"city"},
"properties": map[string]any{
"city": map[string]any{"type": "string"},
},
},
},
},
@@ -53,6 +57,9 @@ func TestBuildOpenAIFinalPrompt_HandlerPathIncludesToolRoundtripSemantics(t *tes
if !strings.Contains(finalPrompt, "<tool_name>get_weather</tool_name>") {
t.Fatalf("handler finalPrompt should include tool name history: %q", finalPrompt)
}
if !strings.Contains(finalPrompt, "MUST INCLUDE: city") {
t.Fatalf("handler finalPrompt should front-load required fields: %q", finalPrompt)
}
}
func TestBuildOpenAIFinalPrompt_VercelPreparePathKeepsFinalAnswerInstruction(t *testing.T) {
@@ -67,7 +74,11 @@ func TestBuildOpenAIFinalPrompt_VercelPreparePathKeepsFinalAnswerInstruction(t *
"name": "search",
"description": "search docs",
"parameters": map[string]any{
"type": "object",
"type": "object",
"required": []any{"query"},
"properties": map[string]any{
"query": map[string]any{"type": "string"},
},
},
},
},
@@ -83,6 +94,9 @@ func TestBuildOpenAIFinalPrompt_VercelPreparePathKeepsFinalAnswerInstruction(t *
if !strings.Contains(finalPrompt, "TOOL CALL FORMAT") {
t.Fatalf("vercel prepare finalPrompt missing xml format instruction: %q", finalPrompt)
}
if !strings.Contains(finalPrompt, "MUST INCLUDE: query") {
t.Fatalf("vercel prepare finalPrompt missing required-field summary: %q", finalPrompt)
}
if !strings.Contains(finalPrompt, "Do NOT wrap the XML in markdown code fences") {
t.Fatalf("vercel prepare finalPrompt missing no-fence xml instruction: %q", finalPrompt)
}