Skip to content
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Prev Previous commit
Next Next commit
docs
  • Loading branch information
christothes committed May 1, 2025
commit 93f94c688b525973808cedd2bdf3dfbff0dcf87c
35 changes: 34 additions & 1 deletion src/Utility/ChatTools.cs
Original file line number Diff line number Diff line change
Expand Up @@ -10,12 +10,21 @@
namespace OpenAI;

/// <summary>
/// The service client for OpenAI Chat Completions endpoint tools.
/// Provides functionality to manage and execute OpenAI function tools for chat completions.
/// </summary>
public class ChatTools : ToolsBase<ChatTool>
{
/// <summary>
/// Initializes a new instance of the ChatTools class with an optional embedding client.
/// </summary>
/// <param name="client">The embedding client used for tool vectorization, or null to disable vectorization.</param>
public ChatTools(EmbeddingClient client = null) : base(client) { }

/// <summary>
/// Initializes a new instance of the ChatTools class with the specified tool types.
/// </summary>
/// <param name="tool">The primary tool type to add.</param>
/// <param name="additionalTools">Additional tool types to add.</param>
public ChatTools(Type tool, params Type[] additionalTools) : this((EmbeddingClient)null)
{
Add(tool);
Expand Down Expand Up @@ -86,6 +95,10 @@ protected override ChatTool ParseToolDefinition(BinaryData data)
BinaryData.FromString(root.GetProperty("inputSchema").GetRawText()));
}

/// <summary>
/// Converts the tools collection to chat completion options.
/// </summary>
/// <returns>A new ChatCompletionOptions containing all defined tools.</returns>
public ChatCompletionOptions ToOptions()
{
var options = new ChatCompletionOptions();
Expand All @@ -94,6 +107,12 @@ public ChatCompletionOptions ToOptions()
return options;
}

/// <summary>
/// Converts the tools collection to <see cref="ChatCompletionOptions"/>, filtered by relevance to the given prompt.
/// </summary>
/// <param name="prompt">The prompt to find relevant tools for.</param>
/// <param name="options">Options for filtering tools, including maximum number of tools to return.</param>
/// <returns>A new <see cref="ChatCompletionOptions"/> containing the most relevant tools.</returns>
public ChatCompletionOptions ToOptions(string prompt, ToolFindOptions options = null)
{
if (!CanFilterTools)
Expand All @@ -105,6 +124,10 @@ public ChatCompletionOptions ToOptions(string prompt, ToolFindOptions options =
return completionOptions;
}

/// <summary>
/// Implicitly converts ChatTools to <see cref="ChatCompletionOptions"/>.
/// </summary>
/// <param name="tools">The ChatTools instance to convert.</param>
public static implicit operator ChatCompletionOptions(ChatTools tools) => tools.ToOptions();

internal string CallLocal(ChatToolCall call)
Expand Down Expand Up @@ -143,6 +166,11 @@ internal async Task<string> CallMcpAsync(ChatToolCall call)
return result.ToString();
}

/// <summary>
/// Executes all tool calls and returns their results.
/// </summary>
/// <param name="toolCalls">The collection of tool calls to execute.</param>
/// <returns>A collection of tool chat messages containing the results.</returns>
public async Task<IEnumerable<ToolChatMessage>> CallAllAsync(IEnumerable<ChatToolCall> toolCalls)
{
var messages = new List<ToolChatMessage>();
Expand All @@ -168,6 +196,11 @@ public async Task<IEnumerable<ToolChatMessage>> CallAllAsync(IEnumerable<ChatToo
return messages;
}

/// <summary>
/// Executes all tool calls and returns both results and any failed tool names.
/// </summary>
/// <param name="toolCalls">The collection of tool calls to execute.</param>
/// <returns>A result object containing successful tool messages and failed tool names.</returns>
public async Task<ToolCallChatResult> CallAllWithErrorsAsync(IEnumerable<ChatToolCall> toolCalls)
{
List<string> failed = null;
Expand Down
32 changes: 30 additions & 2 deletions src/Utility/ResponseTools.cs
Original file line number Diff line number Diff line change
Expand Up @@ -10,12 +10,21 @@
namespace OpenAI;

/// <summary>
/// The service client for OpenAI Responses endpoint tools.
/// Provides functionality to manage and execute OpenAI function tools for responses.
/// </summary>
public class ResponseTools : ToolsBase<ResponseTool>
{
/// <summary>
/// Initializes a new instance of the ResponseTools class with an optional embedding client.
/// </summary>
/// <param name="client">The embedding client used for tool vectorization, or null to disable vectorization.</param>
public ResponseTools(EmbeddingClient client = null) : base(client) { }

/// <summary>
/// Initializes a new instance of the ResponseTools class with the specified tool types.
/// </summary>
/// <param name="tool">The primary tool type to add.</param>
/// <param name="additionalTools">Additional tool types to add.</param>
public ResponseTools(Type tool, params Type[] additionalTools) : this((EmbeddingClient)null)
{
Add(tool);
Expand Down Expand Up @@ -87,6 +96,10 @@ protected override ResponseTool ParseToolDefinition(BinaryData data)
BinaryData.FromString(root.GetProperty("inputSchema").GetRawText()));
}

/// <summary>
/// Converts the tools collection to <see cref="ResponseCreationOptions"> configured with the tools contained in this instance..
/// </summary>
/// <returns>A new ResponseCreationOptions containing all defined tools.</returns>
public ResponseCreationOptions ToOptions()
{
var options = new ResponseCreationOptions();
Expand All @@ -95,6 +108,12 @@ public ResponseCreationOptions ToOptions()
return options;
}

/// <summary>
/// Converts the tools collection to <see cref="ResponseCreationOptions">, filtered by relevance to the given prompt. Filtering is only applied if <see cref="CanFilterTools"/> is true.
/// </summary>
/// <param name="prompt">The prompt to find relevant tools for.</param>
/// <param name="options">Options for filtering tools, including maximum number of tools to return.</param>
/// <returns>A new ResponseCreationOptions containing the most relevant tools.</returns>
public ResponseCreationOptions ToOptions(string prompt, ToolFindOptions options = null)
{
if (!CanFilterTools)
Expand All @@ -106,6 +125,10 @@ public ResponseCreationOptions ToOptions(string prompt, ToolFindOptions options
return completionOptions;
}

/// <summary>
/// Implicitly converts ResponseTools to ResponseCreationOptions.
/// </summary>
/// <param name="tools">The ResponseTools instance to convert.</param>
public static implicit operator ResponseCreationOptions(ResponseTools tools) => tools.ToOptions();

internal string CallLocal(FunctionCallResponseItem call)
Expand Down Expand Up @@ -144,6 +167,11 @@ internal async Task<string> CallMcpAsync(FunctionCallResponseItem call)
return result.ToString();
}

/// <summary>
/// Executes a function call and returns its result as a FunctionCallOutputResponseItem.
/// </summary>
/// <param name="toolCall">The function call to execute.</param>
/// <returns>A task that represents the asynchronous operation and contains the function call result.</returns>
public async Task<FunctionCallOutputResponseItem> CallAsync(FunctionCallResponseItem toolCall)
{
bool isMcpTool = false;
Expand All @@ -155,7 +183,7 @@ public async Task<FunctionCallOutputResponseItem> CallAsync(FunctionCallResponse
}
else
{
return new FunctionCallOutputResponseItem(toolCall.Id, $"I don't have a tool called {toolCall.FunctionName}");
return new FunctionCallOutputResponseItem(toolCall.CallId, $"I don't have a tool called {toolCall.FunctionName}");
}
}

Expand Down
39 changes: 36 additions & 3 deletions src/Utility/ToolsBase.cs
Original file line number Diff line number Diff line change
Expand Up @@ -4,18 +4,16 @@
using System.IO;
using System.Linq;
using System.Reflection;
using System.Text;
using System.Text.Json;
using System.Threading.Tasks;
using OpenAI.Chat;
using OpenAI.Embeddings;

namespace OpenAI;

/// <summary>
/// Base class containing common functionality for tool management.
/// </summary>
/// <typeparam name="TTool">The concrete tool type (ChatTool or ResponseTool)</typeparam>
/// <typeparam name="TTool">The concrete tool type (<see cref="ChatTool"/> or <see cref="ResponseTool"/>)</typeparam>
public abstract class ToolsBase<TTool> where TTool : class
{
protected static readonly BinaryData s_noparams = BinaryData.FromString("""{ "type" : "object", "properties" : {} }""");
Expand All @@ -35,15 +33,31 @@ protected ToolsBase(EmbeddingClient client = null)
_client = client;
}

/// <summary>
/// Gets the list of defined tools.
/// </summary>
public IList<TTool> Definitions => _definitions;

/// <summary>
/// Gets whether tools can be filtered using embeddings provided by the provided <see cref="EmbeddingClient"/> .
/// </summary>
public bool CanFilterTools => _client != null;

/// <summary>
/// Adds local tool implementations from the provided types.
/// </summary>
/// <param name="tools">Types containing static methods to be used as tools.</param>
public void AddLocalTools(params Type[] tools)
{
foreach (Type functionHolder in tools)
Add(functionHolder);
}

/// <summary>
/// Adds a remote MCP server as a tool provider.
/// </summary>
/// <param name="client">The MCP client instance.</param>
/// <returns>A task representing the asynchronous operation.</returns>
internal async Task AddMcpServerAsync(McpClient client)
{
if (client == null) throw new ArgumentNullException(nameof(client));
Expand All @@ -54,12 +68,21 @@ internal async Task AddMcpServerAsync(McpClient client)
_mcpClients.Add(client);
}

/// <summary>
/// Adds a remote MCP server as a tool provider.
/// </summary>
/// <param name="serverEndpoint">The URI endpoint of the MCP server.</param>
/// <returns>A task representing the asynchronous operation.</returns>
public async Task AddMcpServerAsync(Uri serverEndpoint)
{
var client = new McpClient(serverEndpoint);
await AddMcpServerAsync(client).ConfigureAwait(false);
}

/// <summary>
/// Adds all public static methods from the specified type as tools.
/// </summary>
/// <param name="functions">The type containing tool methods.</param>
public void Add(Type functions)
{
#pragma warning disable IL2070
Expand Down Expand Up @@ -230,9 +253,19 @@ private static float CosineSimilarity(ReadOnlySpan<float> x, ReadOnlySpan<float>
protected abstract BinaryData SerializeTool(TTool tool);
protected abstract TTool ParseToolDefinition(BinaryData data);

/// <summary>
/// Options for finding related tools.
/// </summary>
public class ToolFindOptions
{
/// <summary>
/// Gets or sets the maximum number of tools to return. Default is 3.
/// </summary>
public int MaxEntries { get; set; } = 3;

/// <summary>
/// Gets or sets the similarity threshold for including tools. Default is 0.29.
/// </summary>
public float Threshold { get; set; } = 0.29f;
}
}