diff --git a/src/common/Configuration/KnownSettings.cs b/src/common/Configuration/KnownSettings.cs index d5e2c9249..a050f0cba 100644 --- a/src/common/Configuration/KnownSettings.cs +++ b/src/common/Configuration/KnownSettings.cs @@ -13,13 +13,13 @@ public static class KnownSettings // Anthropic settings public const string AnthropicApiKey = "Anthropic.ApiKey"; public const string AnthropicModelName = "Anthropic.ModelName"; - + // AWS Bedrock settings public const string AWSBedrockAccessKey = "AWS.Bedrock.AccessKey"; public const string AWSBedrockSecretKey = "AWS.Bedrock.SecretKey"; public const string AWSBedrockRegion = "AWS.Bedrock.Region"; public const string AWSBedrockModelId = "AWS.Bedrock.ModelId"; - + // Google Gemini settings public const string GoogleGeminiApiKey = "Google.Gemini.ApiKey"; public const string GoogleGeminiModelId = "Google.Gemini.ModelId"; @@ -33,15 +33,19 @@ public static class KnownSettings public const string AzureOpenAIApiKey = "Azure.OpenAI.ApiKey"; public const string AzureOpenAIEndpoint = "Azure.OpenAI.Endpoint"; public const string AzureOpenAIChatDeployment = "Azure.OpenAI.ChatDeployment"; - + // OpenAI settings public const string OpenAIApiKey = "OpenAI.ApiKey"; public const string OpenAIEndpoint = "OpenAI.Endpoint"; public const string OpenAIChatModelName = "OpenAI.ChatModelName"; - + + //Ollama settings + public const string OllamaBaseUrl = "Ollama.BaseUrl"; + public const string OllamaModelId = "Ollama.ModelId"; + // GitHub settings public const string GitHubToken = "GitHub.Token"; - + // Copilot settings public const string CopilotModelName = "Copilot.ModelName"; public const string CopilotApiEndpoint = "Copilot.ApiEndpoint"; @@ -59,11 +63,11 @@ public static class KnownSettings public const string AppChatCompletionTimeout = "App.ChatCompletionTimeout"; public const string AppAutoApprove = "App.AutoApprove"; public const string AppAutoDeny = "App.AutoDeny"; - + #endregion - + #region Secret Settings - + /// /// Collection of known setting names that should be treated as secrets. /// @@ -91,11 +95,11 @@ public static class KnownSettings // GitHub secrets GitHubToken, }; - + #endregion - + #region Setting Format Mappings - + /// /// Mapping from dot notation to environment variable format. /// @@ -129,6 +133,10 @@ public static class KnownSettings { OpenAIApiKey, "OPENAI_API_KEY" }, { OpenAIEndpoint, "OPENAI_ENDPOINT" }, { OpenAIChatModelName, "OPENAI_CHAT_MODEL_NAME" }, + + //Ollama mappings + { OllamaBaseUrl, "OLLAMA_BASE_URL" }, + { OllamaModelId, "OLLAMA_MODEL_ID" }, // GitHub mappings { GitHubToken, "GITHUB_TOKEN" }, @@ -151,7 +159,7 @@ public static class KnownSettings { AppAutoApprove, "CYCOD_AUTO_APPROVE" }, { AppAutoDeny, "CYCOD_AUTO_DENY" } }; - + /// /// Mapping from dot notation to CLI option format. /// @@ -185,6 +193,10 @@ public static class KnownSettings { OpenAIApiKey, "--openai-api-key" }, { OpenAIEndpoint, "--openai-endpoint" }, { OpenAIChatModelName, "--openai-chat-model-name" }, + + // Ollama mappings + { OllamaBaseUrl, "--ollama-base-url" }, + { OllamaModelId, "--ollama-model-id" }, // GitHub mappings { GitHubToken, "--github-token" }, @@ -206,12 +218,12 @@ public static class KnownSettings { AppAutoApprove, "--auto-approve" }, { AppAutoDeny, "--auto-deny" } }; - + /// /// Mapping from environment variable format to dot notation. /// private static readonly Dictionary _envVarToDotMap; - + /// /// Mapping from CLI option format to dot notation. /// @@ -237,7 +249,7 @@ public static class KnownSettings AnthropicApiKey, AnthropicModelName }; - + /// /// Collection of settings for AWS Bedrock integration. /// @@ -248,7 +260,7 @@ public static class KnownSettings AWSBedrockRegion, AWSBedrockModelId }; - + /// /// Collection of settings for Google Gemini integration. /// @@ -257,7 +269,7 @@ public static class KnownSettings GoogleGeminiApiKey, GoogleGeminiModelId }; - + /// /// Collection of settings for Grok integration. /// @@ -277,7 +289,7 @@ public static class KnownSettings AzureOpenAIEndpoint, AzureOpenAIChatDeployment }; - + /// /// Collection of settings for OpenAI integration. /// @@ -287,7 +299,16 @@ public static class KnownSettings OpenAIEndpoint, OpenAIChatModelName }; - + + /// + /// Collection of settings for Ollama integration. + /// + public static readonly HashSet OllamaSettings = new(StringComparer.OrdinalIgnoreCase) + { + OllamaBaseUrl, + OllamaModelId + }; + /// /// Collection of settings for GitHub integration. /// @@ -295,7 +316,7 @@ public static class KnownSettings { GitHubToken }; - + /// /// Collection of settings for Copilot integration. /// @@ -306,7 +327,7 @@ public static class KnownSettings CopilotIntegrationId, CopilotEditorVersion }; - + /// /// Collection of settings for application configuration. /// @@ -323,16 +344,16 @@ public static class KnownSettings AppAutoApprove, AppAutoDeny }; - + #endregion - + static KnownSettings() { // Initialize reverse mappings _envVarToDotMap = _dotToEnvVarMap.ToDictionary(kvp => kvp.Value, kvp => kvp.Key, StringComparer.OrdinalIgnoreCase); _cliOptionToDotMap = _dotToCLIOptionMap.ToDictionary(kvp => kvp.Value, kvp => kvp.Key, StringComparer.OrdinalIgnoreCase); } - + /// /// Checks if the given key is a known setting. /// @@ -345,7 +366,7 @@ public static bool IsKnown(string key) if (_cliOptionToDotMap.ContainsKey(key)) return true; return false; } - + /// /// Checks if the given key is a secret value that should be obfuscated. /// @@ -356,7 +377,7 @@ public static bool IsSecret(string key) var dotNotationKey = ToDotNotation(key); return _secretSettings.Contains(dotNotationKey); } - + /// /// Gets all known setting names in dot notation format. /// @@ -376,7 +397,7 @@ public static bool IsMultiValue(string key) var dotNotationKey = ToDotNotation(key); return _multiValueSettings.Contains(dotNotationKey, StringComparer.OrdinalIgnoreCase); } - + /// /// Gets the canonical form of a known setting key. /// @@ -418,7 +439,7 @@ public static string ToEnvironmentVariable(string key) // Otherwise, just return it return key; } - + /// /// Converts a setting name to CLI option format. /// @@ -427,20 +448,20 @@ public static string ToEnvironmentVariable(string key) public static string ToCLIOption(string key) { if (IsCLIOptionFormat(key)) return key; - + // Try to map to a CLI option var dotNotationKey = ToDotNotation(key); if (_dotToCLIOptionMap.TryGetValue(dotNotationKey, out string? cliOption)) { return cliOption; } - + // Otherwise, use a general algorithm var parts = dotNotationKey.Split('.'); var kebabParts = parts.Select(p => ToKebabCase(p)); return "--" + string.Join("-", kebabParts).ToLowerInvariant(); } - + /// /// Converts a setting name to dot notation format. /// @@ -456,7 +477,7 @@ public static string ToDotNotation(string key) return dotNotation; } } - + // If it's a CLI option format if (IsCLIOptionFormat(key)) { @@ -464,7 +485,7 @@ public static string ToDotNotation(string key) { return dotNotation; } - + // Remove leading -- and convert kebab-case to PascalCase with dots var trimmed = key.TrimStart('-'); var parts = trimmed.Split('-'); @@ -475,13 +496,13 @@ public static string ToDotNotation(string key) parts[i] = char.ToUpper(parts[i][0]) + parts[i].Substring(1).ToLower(); } } - + return string.Join(".", parts); } return key; } - + /// /// Determines if the given key is in environment variable format. /// @@ -491,7 +512,7 @@ public static bool IsEnvironmentVariableFormat(string key) { return Regex.IsMatch(key, "^[A-Z0-9_]+$"); } - + /// /// Determines if the given key is in CLI option format. /// @@ -501,7 +522,7 @@ public static bool IsCLIOptionFormat(string key) { return key.StartsWith("--"); } - + /// /// Converts a string from PascalCase to kebab-case. /// @@ -511,7 +532,7 @@ private static string ToKebabCase(string input) { if (string.IsNullOrEmpty(input)) return input; - + // Insert a hyphen before each uppercase letter that follows a lowercase letter var result = Regex.Replace(input, "(? line.Trim())); diff --git a/src/cycod/ChatClient/FunctionCallingChat.cs b/src/cycod/ChatClient/FunctionCallingChat.cs index 732f8a975..e9280fa36 100644 --- a/src/cycod/ChatClient/FunctionCallingChat.cs +++ b/src/cycod/ChatClient/FunctionCallingChat.cs @@ -13,6 +13,8 @@ public FunctionCallingChat(IChatClient chatClient, string systemPrompt, Function ? chatClient.AsBuilder().UseFunctionInvocation().Build() : chatClient; + var toolsDisabled = (options?.ToolMode ?? ChatToolMode.Auto) == ChatToolMode.None; + var tools = _functionFactory.GetAITools().ToList(); ConsoleHelpers.WriteDebugLine($"FunctionCallingChat: Found {tools.Count} tools in FunctionFactory"); @@ -20,8 +22,8 @@ public FunctionCallingChat(IChatClient chatClient, string systemPrompt, Function _options = new ChatOptions() { ModelId = options?.ModelId, - ToolMode = options?.ToolMode, - Tools = tools, + ToolMode = toolsDisabled ? ChatToolMode.None : (options?.ToolMode ?? ChatToolMode.Auto), + Tools = toolsDisabled ? new List() : tools, MaxOutputTokens = maxOutputTokens.HasValue ? maxOutputTokens.Value : options?.MaxOutputTokens, @@ -51,7 +53,7 @@ public void AddUserMessage(string userMessage, int maxPromptTokenTarget = 0, int maxPromptTokenTarget: maxPromptTokenTarget, maxChatTokenTarget: maxChatTokenTarget); } - + public void AddUserMessages(IEnumerable userMessages, int maxPromptTokenTarget = 0, int maxChatTokenTarget = 0) { foreach (var userMessage in userMessages) @@ -109,12 +111,16 @@ public async Task CompleteChatStreamingAsync( messageCallback?.Invoke(_messages); var contentToReturn = string.Empty; + var toolsDisabled = (_options.ToolMode ?? ChatToolMode.Auto) == ChatToolMode.None; while (true) { var responseContent = string.Empty; await foreach (var update in _chatClient.GetStreamingResponseAsync(_messages, _options)) { - _functionCallDetector.CheckForFunctionCall(update); + if (!toolsDisabled) + { + _functionCallDetector.CheckForFunctionCall(update); + } var content = string.Join("", update.Contents .Where(c => c is TextContent) @@ -133,7 +139,7 @@ public async Task CompleteChatStreamingAsync( streamingCallback?.Invoke(update); } - if (TryCallFunctions(responseContent, approveFunctionCall, functionCallCallback, messageCallback)) + if (!toolsDisabled && TryCallFunctions(responseContent, approveFunctionCall, functionCallCallback, messageCallback)) { _functionCallDetector.Clear(); continue; @@ -150,7 +156,7 @@ private bool TryCallFunctions(string responseContent, Func + + - out of memory / slow generation + Try a smaller model (e.g., qwen2.5:0.5b or llama3:8b), close other GPU apps, + or use a quantized/compact variant if available.