fix(tools): adapt tool prompt framing to ensure reliable tool calls in persona spaces
This commit is contained in:
@@ -436,10 +436,13 @@ func EffectiveUserAgent(r *http.Request) string {
|
||||
// Tool and message processing
|
||||
// ---------------------------------------------------------------------------
|
||||
|
||||
func BuildToolInstruction(tools []Tool) string {
|
||||
func BuildToolInstruction(tools []Tool, toolChoice interface{}) string {
|
||||
if len(tools) == 0 {
|
||||
return ""
|
||||
}
|
||||
if tcStr, ok := toolChoice.(string); ok && tcStr == "none" {
|
||||
return ""
|
||||
}
|
||||
toolsBytes, _ := json.MarshalIndent(tools, "", " ")
|
||||
|
||||
sampleFnName := ""
|
||||
@@ -452,33 +455,30 @@ func BuildToolInstruction(tools []Tool) string {
|
||||
}
|
||||
}
|
||||
if sampleFnName == "" {
|
||||
sampleFnName = "example_tool"
|
||||
sampleFnName = "function_name"
|
||||
}
|
||||
|
||||
return fmt.Sprintf(`# Tool Calling Instructions
|
||||
directive := "If a tool is relevant, emit the tool call XML. If no tools are relevant, answer the query directly."
|
||||
if tcStr, ok := toolChoice.(string); ok && tcStr == "required" {
|
||||
directive = "You MUST call one of the available tools for this query and emit the tool call XML."
|
||||
} else if tcMap, ok := toolChoice.(map[string]interface{}); ok {
|
||||
if fnMap, ok := tcMap["function"].(map[string]interface{}); ok {
|
||||
if fnName, ok := fnMap["name"].(string); ok && fnName != "" {
|
||||
directive = fmt.Sprintf("You MUST call the %s tool for this query and emit the tool call XML.", fnName)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
You are equipped with external tools to assist with user queries.
|
||||
You have access to the following tools:
|
||||
<tools>
|
||||
return fmt.Sprintf(`You are an API router and assistant. Convert the user query into the appropriate tool call XML using the available tools.
|
||||
Available Tools:
|
||||
%s
|
||||
</tools>
|
||||
|
||||
When the user asks a question or makes a request that can be fulfilled, assisted, or answered using any of the tools above, you MUST call the appropriate tool.
|
||||
DO NOT refuse to answer, and DO NOT claim that you lack real-time access, live data, or tool capabilities when a tool is provided for that purpose.
|
||||
|
||||
## Tool Calling Syntax
|
||||
To call a tool, you MUST output a <tool_call> block formatted as:
|
||||
Syntax:
|
||||
<tool_call>
|
||||
{"name": "%s", "arguments": {...}}
|
||||
</tool_call>
|
||||
|
||||
## Rules:
|
||||
1. If an available tool is relevant to the user's request, invoking the tool is MANDATORY.
|
||||
2. When calling a tool, your ENTIRE output must consist ONLY of the <tool_call> block. Do not add introductory text, commentary, or conversational filler.
|
||||
3. If multiple tools are required, output each in its own <tool_call> block.
|
||||
4. Arguments must be a valid JSON object strictly matching the tool's parameter definitions.
|
||||
5. If no tools are relevant to the user's inquiry, respond normally with plain text.
|
||||
6. When tool execution results are provided to you in subsequent turns (via <tool_response> blocks or tool role messages), formulate your final answer to the user based on those results.`, string(toolsBytes), sampleFnName)
|
||||
%s`, string(toolsBytes), sampleFnName, directive)
|
||||
}
|
||||
|
||||
func TransformMessages(req ChatCompletionRequest) (processed []ChatMessage, toolInstruction string, hasSystem bool) {
|
||||
@@ -492,7 +492,7 @@ func TransformMessages(req ChatCompletionRequest) (processed []ChatMessage, tool
|
||||
}
|
||||
}
|
||||
|
||||
toolInstruction = BuildToolInstruction(req.Tools)
|
||||
toolInstruction = BuildToolInstruction(req.Tools, req.ToolChoice)
|
||||
|
||||
// 2. Process and coalesce messages preserving turn parity
|
||||
var staged []ChatMessage
|
||||
@@ -2130,7 +2130,11 @@ func (g *GradioGateway) BuildGradioPayload(disc *SpaceDiscovery, req ChatComplet
|
||||
if disc.SystemIndex == -1 && systemPromptStr != "" && len(nonSystem) > 0 {
|
||||
// If the space supports conversation history, prepend system instructions to the first turn
|
||||
if disc.HistoryIndex != -1 {
|
||||
nonSystem[0].Content = systemPromptStr + "\n\n" + nonSystem[0].GetContentString()
|
||||
if toolInstruction != "" && len(nonSystem) == 1 {
|
||||
nonSystem[0].Content = fmt.Sprintf("%s\n\nQuery: %s", systemPromptStr, nonSystem[0].GetContentString())
|
||||
} else {
|
||||
nonSystem[0].Content = systemPromptStr + "\n\n" + nonSystem[0].GetContentString()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2195,9 +2199,9 @@ func (g *GradioGateway) BuildGradioPayload(disc *SpaceDiscovery, req ChatComplet
|
||||
lastUserMessage = "Please proceed based on the tool results."
|
||||
} else {
|
||||
if toolName != "" {
|
||||
lastUserMessage = fmt.Sprintf("Tool result for %s: %s", toolName, lastContent)
|
||||
lastUserMessage = fmt.Sprintf("Tool result for %s: %s\nPlease answer the user's request based on the tool result.", toolName, lastContent)
|
||||
} else {
|
||||
lastUserMessage = lastContent
|
||||
lastUserMessage = fmt.Sprintf("Tool result: %s\nPlease answer the user's request based on the tool result.", lastContent)
|
||||
}
|
||||
}
|
||||
} else {
|
||||
@@ -2209,16 +2213,32 @@ func (g *GradioGateway) BuildGradioPayload(disc *SpaceDiscovery, req ChatComplet
|
||||
|
||||
var promptMessageText string
|
||||
if disc.HistoryIndex != -1 {
|
||||
if disc.SystemIndex == -1 && len(nonSystem) > 1 && toolInstruction != "" {
|
||||
promptMessageText = fmt.Sprintf("[System Directive: Tool calling mode active. If relevant, output a <tool_call> block.]\n\n%s", lastUserMessage)
|
||||
if disc.SystemIndex == -1 {
|
||||
if len(nonSystem) > 1 && toolInstruction != "" {
|
||||
if !strings.HasPrefix(lastUserMessage, "Tool result") {
|
||||
promptMessageText = fmt.Sprintf("[System Directive: Tool calling mode active.]\n\nQuery: %s", lastUserMessage)
|
||||
} else {
|
||||
promptMessageText = fmt.Sprintf("[System Directive: Tool calling mode active.]\n\n%s", lastUserMessage)
|
||||
}
|
||||
} else {
|
||||
promptMessageText = lastUserMessage
|
||||
}
|
||||
} else {
|
||||
promptMessageText = lastUserMessage
|
||||
if toolInstruction != "" && !strings.HasPrefix(lastUserMessage, "Tool result") {
|
||||
promptMessageText = fmt.Sprintf("Query: %s", lastUserMessage)
|
||||
} else {
|
||||
promptMessageText = lastUserMessage
|
||||
}
|
||||
}
|
||||
} else {
|
||||
// Single message space: compose multi-turn history into the prompt
|
||||
if len(nonSystem) <= 1 {
|
||||
if systemPromptStr != "" && len(nonSystem) == 1 {
|
||||
promptMessageText = systemPromptStr + "\n\n" + lastUserMessage
|
||||
if toolInstruction != "" && !strings.HasPrefix(lastUserMessage, "Tool result") {
|
||||
promptMessageText = fmt.Sprintf("%s\n\nQuery: %s", systemPromptStr, lastUserMessage)
|
||||
} else {
|
||||
promptMessageText = systemPromptStr + "\n\n" + lastUserMessage
|
||||
}
|
||||
} else if systemPromptStr != "" {
|
||||
promptMessageText = systemPromptStr
|
||||
} else {
|
||||
@@ -2242,7 +2262,11 @@ func (g *GradioGateway) BuildGradioPayload(disc *SpaceDiscovery, req ChatComplet
|
||||
if len(nonSystem) > 0 && nonSystem[len(nonSystem)-1].Role == "assistant" {
|
||||
lastRoleLabel = "Assistant"
|
||||
}
|
||||
sb.WriteString(fmt.Sprintf("# Current Request\n%s: %s", lastRoleLabel, lastUserMessage))
|
||||
if toolInstruction != "" && lastRoleLabel == "User" && !strings.HasPrefix(lastUserMessage, "Tool result") {
|
||||
sb.WriteString(fmt.Sprintf("# Current Request\nQuery: %s", lastUserMessage))
|
||||
} else {
|
||||
sb.WriteString(fmt.Sprintf("# Current Request\n%s: %s", lastRoleLabel, lastUserMessage))
|
||||
}
|
||||
promptMessageText = sb.String()
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user