From 900e05025a41932efc28820e3a9419d80ff18534 Mon Sep 17 00:00:00 2001 From: rcourtman Date: Tue, 3 Feb 2026 11:54:57 +0000 Subject: [PATCH] Fix OpenAI-compatible endpoint support for chat Two issues fixed: 1. Custom base URL wasn't being passed to the OpenAI client in createProviderForModel() - requests went to api.openai.com instead of the configured endpoint (e.g., LM Studio, llama.cpp) 2. Tool schemas were missing the "properties" field when tools had no parameters. OpenAI API requires "properties" to always be present as an object, even if empty. Fixes #1154 --- internal/ai/chat/service.go | 2 +- internal/ai/chat/tools.go | 35 +++++++++++++++++------------------ 2 files changed, 18 insertions(+), 19 deletions(-) diff --git a/internal/ai/chat/service.go b/internal/ai/chat/service.go index c3a438b7b1..c9dd6bdbe5 100644 --- a/internal/ai/chat/service.go +++ b/internal/ai/chat/service.go @@ -728,7 +728,7 @@ func (s *Service) createProviderForModel(modelStr string) (providers.StreamingPr if s.cfg.OpenAIAPIKey == "" { return nil, fmt.Errorf("OpenAI API key not configured") } - return providers.NewOpenAIClient(s.cfg.OpenAIAPIKey, modelName, "", timeout), nil + return providers.NewOpenAIClient(s.cfg.OpenAIAPIKey, modelName, s.cfg.OpenAIBaseURL, timeout), nil case "deepseek": if s.cfg.DeepSeekAPIKey == "" { return nil, fmt.Errorf("DeepSeek API key not configured") diff --git a/internal/ai/chat/tools.go b/internal/ai/chat/tools.go index ae553cad72..0854a25128 100644 --- a/internal/ai/chat/tools.go +++ b/internal/ai/chat/tools.go @@ -14,26 +14,25 @@ func ConvertMCPToolsToProvider(mcpTools []tools.Tool) []providers.Tool { inputSchema := make(map[string]interface{}) inputSchema["type"] = "object" - // Convert properties - if len(t.InputSchema.Properties) > 0 { - props := make(map[string]interface{}) - for name, prop := range t.InputSchema.Properties { - propDef := map[string]interface{}{ - "type": prop.Type, - } - if prop.Description != "" { - propDef["description"] = prop.Description - } - if len(prop.Enum) > 0 { - propDef["enum"] = prop.Enum - } - if prop.Default != nil { - propDef["default"] = prop.Default - } - props[name] = propDef + // Convert properties - always include "properties" even if empty + // OpenAI API requires "properties" to be present as an object + props := make(map[string]interface{}) + for name, prop := range t.InputSchema.Properties { + propDef := map[string]interface{}{ + "type": prop.Type, } - inputSchema["properties"] = props + if prop.Description != "" { + propDef["description"] = prop.Description + } + if len(prop.Enum) > 0 { + propDef["enum"] = prop.Enum + } + if prop.Default != nil { + propDef["default"] = prop.Default + } + props[name] = propDef } + inputSchema["properties"] = props // Add required fields if len(t.InputSchema.Required) > 0 {