openai/openai-dotnet

Public

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

CodeCommitsIssuesPull requestsActionsInsightsSecurity
copilot/update-dotnet-version-to-10

Branches

Tags

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

Clone

HTTPS

Download ZIP

examples/Responses/Example04_FunctionCallingStreamingAsync.cs

114lines · modecode

1using NUnit.Framework;
2using OpenAI.Responses;
3using System;
4using System.ClientModel;
5using System.Collections.Generic;
6using System.Linq;
7using System.Text.Json;
8using System.Threading.Tasks;
9
10namespace OpenAI.Examples;
11
12// This example uses experimental APIs which are subject to change. To use experimental APIs,
13// please acknowledge their experimental status by suppressing the corresponding warning.
14#pragma warning disable OPENAI001
15
16public partial class ResponseExamples
17{
18 // See Example03_FunctionCalling.cs for the tool and function definitions.
19
20 [Test]
21 public async Task Example04_FunctionCallingStreamingAsync()
22 {
23 ResponsesClient client = new(model: "gpt-5", apiKey: Environment.GetEnvironmentVariable("OPENAI_API_KEY"));
24
25 List<ResponseItem> inputItems =
26 [
27 ResponseItem.CreateUserMessageItem("What's the weather like today for my current location?"),
28 ];
29
30 PrintMessageItems(inputItems.OfType<MessageResponseItem>());
31
32 bool requiresAction;
33
34 do
35 {
36 requiresAction = false;
37
38 CreateResponseOptions options = new(inputItems)
39 {
40 Tools = { getCurrentLocationTool, getCurrentWeatherTool },
41 StreamingEnabled = true,
42 };
43
44 AsyncCollectionResult<StreamingResponseUpdate> responseUpdates = client.CreateResponseStreamingAsync(options);
45
46 await foreach (StreamingResponseUpdate update in responseUpdates)
47 {
48 if (update is StreamingResponseOutputItemAddedUpdate outputItemAddedUpdated)
49 {
50 if (outputItemAddedUpdated.Item is MessageResponseItem message && message.Role == MessageRole.Assistant)
51 {
52 Console.WriteLine($"[ASSISTANT]:");
53 }
54 }
55
56 if (update is StreamingResponseOutputTextDeltaUpdate outputTextUpdate)
57 {
58 Console.Write(outputTextUpdate.Delta);
59 }
60
61 if (update is StreamingResponseOutputItemDoneUpdate outputItemDoneUpdate)
62 {
63 inputItems.Add(outputItemDoneUpdate.Item);
64
65 if (outputItemDoneUpdate.Item is FunctionCallResponseItem functionCall)
66 {
67 switch (functionCall.FunctionName)
68 {
69 case nameof(GetCurrentLocation):
70 {
71 string functionOutput = GetCurrentLocation();
72 inputItems.Add(new FunctionCallOutputResponseItem(functionCall.CallId, functionOutput));
73 break;
74 }
75
76 case nameof(GetCurrentWeather):
77 {
78 // The arguments that the model wants to use to call the function are specified as a
79 // stringified JSON object based on the schema defined in the tool definition. Note that
80 // the model may hallucinate arguments too. Consequently, it is important to do the
81 // appropriate parsing and validation before calling the function.
82 using JsonDocument argumentsJson = JsonDocument.Parse(functionCall.FunctionArguments);
83 bool hasLocation = argumentsJson.RootElement.TryGetProperty("location", out JsonElement location);
84 bool hasUnit = argumentsJson.RootElement.TryGetProperty("unit", out JsonElement unit);
85
86 if (!hasLocation)
87 {
88 throw new ArgumentNullException(nameof(location), "The location argument is required.");
89 }
90
91 string functionOutput = hasUnit
92 ? GetCurrentWeather(location.GetString(), unit.GetString())
93 : GetCurrentWeather(location.GetString());
94 inputItems.Add(new FunctionCallOutputResponseItem(functionCall.CallId, functionOutput));
95 break;
96 }
97
98 default:
99 {
100 // Handle other unexpected calls.
101 throw new NotImplementedException();
102 }
103 }
104
105 requiresAction = true;
106 break;
107 }
108 }
109 }
110 } while (requiresAction);
111 }
112}
113
114#pragma warning restore OPENAI001