🔧 Fix tool calling + capability awareness

Three fixes:
1. OllamaProvider now sends tools[] in native /api/chat requests
2. OllamaProvider parses tool_calls from response (OpenAI-compatible
   format with function.name, function.arguments)
3. System prompt now lists available tools so LLM knows it can use
   bash, curl, read/write files — stops saying "I cannot do that"
This commit is contained in:
2026-06-11 22:55:19 +05:30
parent 5eb86e066b
commit 59ef28ffab
2 changed files with 20 additions and 3 deletions

View File

@@ -196,7 +196,7 @@ impl AgentLoop {
let mut system_prompt = self.config.system_prompt.clone(); let mut system_prompt = self.config.system_prompt.clone();
if !agent_name.is_empty() { if !agent_name.is_empty() {
system_prompt = format!( system_prompt = format!(
"{}\n\n## Your Identity\n- Name: {}\n- Role: {}\n- You are speaking to: {} ({})\n\n## Memory\nYou have a verbatim dialogue log with your user. Use everything from past conversations as context when answering.", "{}\n\n## Your Identity\n- Name: {}\n- Role: {}\n- You are speaking to: {} ({})\n\n## Your Capabilities\nYou have access to tools that let you:\n- Read, write, and edit files\n- Execute shell commands (bash) — use this for curl, git, package managers\n- Search files and directories\n- Use `bash` to run curl for web requests when needed\n\nWhen a user asks you to do something that requires external data, use your tools. Do NOT say you can't do something if you have a tool that can do it.\n\n## Memory\nYou have a verbatim dialogue log with your user. Use everything from past conversations as context when answering.",
system_prompt, system_prompt,
agent_name, agent_name,
if agent_role.is_empty() { "AI Assistant" } else { &agent_role }, if agent_role.is_empty() { "AI Assistant" } else { &agent_role },

View File

@@ -154,7 +154,7 @@ impl Provider for OllamaProvider {
}) })
.collect(); .collect();
let body = serde_json::json!({ let mut body = serde_json::json!({
"model": self.model, "model": self.model,
"messages": messages, "messages": messages,
"stream": false, "stream": false,
@@ -163,6 +163,11 @@ impl Provider for OllamaProvider {
} }
}); });
// Add tools if present (for function calling)
if !context.tools.is_empty() {
body["tools"] = serde_json::to_value(&context.tools).unwrap_or_default();
}
let url = format!("{}/api/chat", self.normalized_base_url()); let url = format!("{}/api/chat", self.normalized_base_url());
let mut request = self let mut request = self
.client .client
@@ -192,9 +197,21 @@ impl Provider for OllamaProvider {
.to_string(); .to_string();
let finish_reason = data["done_reason"].as_str().unwrap_or("stop").to_string(); let finish_reason = data["done_reason"].as_str().unwrap_or("stop").to_string();
// Parse tool calls from response (qwen3.5 returns OpenAI-compatible format)
let tool_calls = data["message"]["tool_calls"].as_array().map(|calls| {
calls.iter().map(|tc| {
let func = &tc["function"];
gyandoot_core::ToolCall {
id: tc["id"].as_str().unwrap_or_default().to_string(),
name: func["name"].as_str().unwrap_or_default().to_string(),
arguments: func["arguments"].clone(),
}
}).collect()
});
Ok(ProviderResponse { Ok(ProviderResponse {
content, content,
tool_calls: None, tool_calls,
finish_reason, finish_reason,
}) })
} }