diff --git a/src/AgentNet.Tests/PollyInProcessTests.fs b/src/AgentNet.Tests/PollyInProcessTests.fs index 0ededb7..87acd87 100644 --- a/src/AgentNet.Tests/PollyInProcessTests.fs +++ b/src/AgentNet.Tests/PollyInProcessTests.fs @@ -131,7 +131,7 @@ let ``Policy forwards CancellationToken through TypedAgent to ChatAgent``() = // Arrange: A ChatAgent whose Chat function observes the cancellation token let mutable tokenWasCancelled = false - let config = { Name = Some "TestAgent"; Instructions = "test"; Tools = [] } + let config = { Name = Some "TestAgent"; Instructions = "test"; Tools = []; ChatOptions = None } let chatFn msg ct = task { try diff --git a/src/AgentNet/AgentFramework.fs b/src/AgentNet/AgentFramework.fs index d1d4b80..5a66289 100644 --- a/src/AgentNet/AgentFramework.fs +++ b/src/AgentNet/AgentFramework.fs @@ -25,6 +25,39 @@ module MAF = // The explicit annotation ensures correct overload resolution AIFunctionFactory.Create(method = tool.MethodInfo, target = null, options = options) + /// Wraps an IChatClient to merge default ChatOptions into every call. + /// Defaults are the base; per-call options override where present. + let private withDefaultOptions (defaults: ChatOptions) (inner: IChatClient) = + let mergeOptions (callOptions: ChatOptions) = + let merged = defaults.Clone() + if callOptions <> null then + if callOptions.Temperature.HasValue then merged.Temperature <- callOptions.Temperature + if callOptions.TopP.HasValue then merged.TopP <- callOptions.TopP + if callOptions.TopK.HasValue then merged.TopK <- callOptions.TopK + if callOptions.MaxOutputTokens.HasValue then merged.MaxOutputTokens <- callOptions.MaxOutputTokens + if callOptions.FrequencyPenalty.HasValue then merged.FrequencyPenalty <- callOptions.FrequencyPenalty + if callOptions.PresencePenalty.HasValue then merged.PresencePenalty <- callOptions.PresencePenalty + if callOptions.Seed.HasValue then merged.Seed <- callOptions.Seed + if callOptions.ModelId <> null then merged.ModelId <- callOptions.ModelId + if callOptions.ResponseFormat <> null then merged.ResponseFormat <- callOptions.ResponseFormat + if callOptions.StopSequences <> null && callOptions.StopSequences.Count > 0 then + merged.StopSequences <- ResizeArray(callOptions.StopSequences) + for tool in callOptions.Tools do merged.Tools.Add(tool) + if callOptions.AdditionalProperties <> null then + if merged.AdditionalProperties = null then + merged.AdditionalProperties <- AdditionalPropertiesDictionary() + for kvp in callOptions.AdditionalProperties do + merged.AdditionalProperties.[kvp.Key] <- kvp.Value + merged + { new IChatClient with + member _.GetResponseAsync(messages, options, ct) = + inner.GetResponseAsync(messages, mergeOptions options, ct) + member _.GetStreamingResponseAsync(messages, options, ct) = + inner.GetStreamingResponseAsync(messages, mergeOptions options, ct) + member _.GetService(serviceType, serviceKey) = + inner.GetService(serviceType, serviceKey) + member _.Dispose() = () } + /// Creates a ChatClientAgent from an AgentNet ChatAgent config let createAgent (chatClient: IChatClient) (config: ChatAgentConfig) : AIAgent = // Convert tools to AIFunctions and cast to AITool @@ -34,9 +67,14 @@ module MAF = |> ResizeArray :> IList + let client = + match config.ChatOptions with + | Some opts -> withDefaultOptions opts chatClient + | None -> chatClient + // Create the agent using the constructor with named parameters ChatClientAgent( - chatClient, + client, name = (config.Name |> Option.defaultValue "Agent"), instructions = config.Instructions, tools = tools) :> AIAgent diff --git a/src/AgentNet/ChatAgent.fs b/src/AgentNet/ChatAgent.fs index 152f299..82c7187 100644 --- a/src/AgentNet/ChatAgent.fs +++ b/src/AgentNet/ChatAgent.fs @@ -3,12 +3,14 @@ namespace AgentNet open System.Collections.Generic open System.Threading open System.Threading.Tasks +open Microsoft.Extensions.AI /// Configuration for a chat agent type ChatAgentConfig = { Name: string option Instructions: string Tools: ToolDef list + ChatOptions: ChatOptions option } /// Role of a participant in a chat conversation @@ -75,7 +77,7 @@ type ChatAgent with /// Creates an agent config with the given instructions static member create (instructions: string) : ChatAgentConfig = - { Name = None; Instructions = instructions; Tools = [] } + { Name = None; Instructions = instructions; Tools = []; ChatOptions = None } /// Sets the agent's name static member withName (name: string) (config: ChatAgentConfig) : ChatAgentConfig = @@ -88,3 +90,7 @@ type ChatAgent with /// Adds a list of tools to the agent static member withTools (tools: ToolDef list) (config: ChatAgentConfig) : ChatAgentConfig = { config with Tools = config.Tools @ tools } + + /// Sets ChatOptions (temperature, top-p, model, etc.) for the agent + static member withChatOptions (options: ChatOptions) (config: ChatAgentConfig) : ChatAgentConfig = + { config with ChatOptions = Some options }