openai/openai-dotnet

Public

mirrored from https://github.com/openai/openai-dotnetAvailable

CodeCommitsIssuesPull requestsActionsInsightsSecurity
OpenAI_2.6.0

Branches

Tags

  • No tags available.
0Branches0Tags
Go to file
Add file
Code

Clone

HTTPS

Download ZIP

examples/Responses/Example03_FunctionCalling.cs

165lines · modecode

1using NUnit.Framework;
2using OpenAI.Responses;
3using System;
4using System.Collections.Generic;
5using System.Linq;
6using System.Text.Json;
7
8namespace OpenAI.Examples;
9
10// This example uses experimental APIs which are subject to change. To use experimental APIs,
11// please acknowledge their experimental status by suppressing the corresponding warning.
12#pragma warning disable OPENAI001
13
14public partial class ResponseExamples
15{
16 #region
17 private static string GetCurrentLocation()
18 {
19 // Call the location API here.
20 return "San Francisco";
21 }
22
23 private static string GetCurrentWeather(string location, string unit = "celsius")
24 {
25 // Call the weather API here.
26 return $"31 {unit}";
27 }
28 #endregion
29
30 #region
31 private static readonly FunctionTool getCurrentLocationTool = ResponseTool.CreateFunctionTool(
32 functionName: nameof(GetCurrentLocation),
33 functionDescription: "Get the user's current location",
34 functionParameters: null,
35 strictModeEnabled: false
36 );
37
38 private static readonly FunctionTool getCurrentWeatherTool = ResponseTool.CreateFunctionTool(
39 functionName: nameof(GetCurrentWeather),
40 functionDescription: "Get the current weather in a given location",
41 functionParameters: BinaryData.FromBytes("""
42 {
43 "type": "object",
44 "properties": {
45 "location": {
46 "type": "string",
47 "description": "The city and state, e.g. Boston, MA"
48 },
49 "unit": {
50 "type": "string",
51 "enum": [ "celsius", "fahrenheit" ],
52 "description": "The temperature unit to use. Infer this from the specified location."
53 }
54 },
55 "required": [ "location" ]
56 }
57 """u8.ToArray()),
58 strictModeEnabled: false
59 );
60 #endregion
61
62 [Test]
63 public void Example03_FunctionCalling()
64 {
65 OpenAIResponseClient client = new("gpt-5", Environment.GetEnvironmentVariable("OPENAI_API_KEY"));
66
67 List<ResponseItem> inputItems =
68 [
69 ResponseItem.CreateUserMessageItem("What's the weather like today for my current location?"),
70 ];
71
72 ResponseCreationOptions options = new()
73 {
74 Tools = { getCurrentLocationTool, getCurrentWeatherTool },
75 };
76
77 PrintMessageItems(inputItems.OfType<MessageResponseItem>());
78
79 bool requiresAction;
80
81 do
82 {
83 requiresAction = false;
84 OpenAIResponse response = client.CreateResponse(inputItems, options);
85
86 inputItems.AddRange(response.OutputItems);
87
88 foreach (ResponseItem outputItem in response.OutputItems)
89 {
90 if (outputItem is FunctionCallResponseItem functionCall)
91 {
92 switch (functionCall.FunctionName)
93 {
94 case nameof(GetCurrentLocation):
95 {
96 string functionOutput = GetCurrentLocation();
97 inputItems.Add(new FunctionCallOutputResponseItem(functionCall.CallId, functionOutput));
98 break;
99 }
100
101 case nameof(GetCurrentWeather):
102 {
103 // The arguments that the model wants to use to call the function are specified as a
104 // stringified JSON object based on the schema defined in the tool definition. Note that
105 // the model may hallucinate arguments too. Consequently, it is important to do the
106 // appropriate parsing and validation before calling the function.
107 using JsonDocument argumentsJson = JsonDocument.Parse(functionCall.FunctionArguments);
108 bool hasLocation = argumentsJson.RootElement.TryGetProperty("location", out JsonElement location);
109 bool hasUnit = argumentsJson.RootElement.TryGetProperty("unit", out JsonElement unit);
110
111 if (!hasLocation)
112 {
113 throw new ArgumentNullException(nameof(location), "The location argument is required.");
114 }
115
116 string functionOutput = hasUnit
117 ? GetCurrentWeather(location.GetString(), unit.GetString())
118 : GetCurrentWeather(location.GetString());
119 inputItems.Add(new FunctionCallOutputResponseItem(functionCall.CallId, functionOutput));
120 break;
121 }
122
123 default:
124 {
125 // Handle other unexpected calls.
126 throw new NotImplementedException();
127 }
128 }
129
130 requiresAction = true;
131 break;
132 }
133 }
134
135 PrintMessageItems(response.OutputItems.OfType<MessageResponseItem>());
136
137 } while (requiresAction);
138 }
139
140 private void PrintMessageItems(IEnumerable<ResponseItem> messageItems)
141 {
142 foreach (MessageResponseItem messageItem in messageItems)
143 {
144 switch (messageItem.Role)
145 {
146 case MessageRole.User:
147 Console.WriteLine($"[USER]:");
148 Console.WriteLine($"{messageItem.Content[0].Text}");
149 Console.WriteLine();
150 break;
151
152 case MessageRole.Assistant:
153 Console.WriteLine($"[ASSISTANT]:");
154 Console.WriteLine($"{messageItem.Content[0].Text}");
155 Console.WriteLine();
156 break;
157
158 default:
159 break;
160 }
161 }
162 }
163}
164
165#pragma warning restore OPENAI001