From 59ef28ffab4d0c923fcd473d7e32bd4f5c1b2c9e Mon Sep 17 00:00:00 2001 From: Tara Menon Date: Thu, 11 Jun 2026 22:55:19 +0530 Subject: [PATCH] =?UTF-8?q?=F0=9F=94=A7=20Fix=20tool=20calling=20+=20capab?= =?UTF-8?q?ility=20awareness?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 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" --- crates/gyandoot-agent/src/agent_loop.rs | 2 +- crates/gyandoot-providers/src/ollama.rs | 21 +++++++++++++++++++-- 2 files changed, 20 insertions(+), 3 deletions(-) diff --git a/crates/gyandoot-agent/src/agent_loop.rs b/crates/gyandoot-agent/src/agent_loop.rs index 94b6e0e..64c65fd 100644 --- a/crates/gyandoot-agent/src/agent_loop.rs +++ b/crates/gyandoot-agent/src/agent_loop.rs @@ -196,7 +196,7 @@ impl AgentLoop { let mut system_prompt = self.config.system_prompt.clone(); if !agent_name.is_empty() { 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, agent_name, if agent_role.is_empty() { "AI Assistant" } else { &agent_role }, diff --git a/crates/gyandoot-providers/src/ollama.rs b/crates/gyandoot-providers/src/ollama.rs index d9d2a9b..dc9597a 100644 --- a/crates/gyandoot-providers/src/ollama.rs +++ b/crates/gyandoot-providers/src/ollama.rs @@ -154,7 +154,7 @@ impl Provider for OllamaProvider { }) .collect(); - let body = serde_json::json!({ + let mut body = serde_json::json!({ "model": self.model, "messages": messages, "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 mut request = self .client @@ -192,9 +197,21 @@ impl Provider for OllamaProvider { .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 { content, - tool_calls: None, + tool_calls, finish_reason, }) }