openai/openai-dotnet

Public

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

CodeCommitsIssuesPull requestsActionsInsightsSecurity
copilot/create-responses-client-options-type

Branches

Tags

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

Clone

HTTPS

Download ZIP

examples/Responses/Example04_FunctionCallingStreamingAsync.cs

109lines · 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(apiKey: Environment.GetEnvironmentVariable("OPENAI_API_KEY"));
24
25 CreateResponseOptions options = new("gpt-5", [ResponseItem.CreateUserMessageItem("What's the weather like today for my current location?")])
26 {
27 Tools = { getCurrentLocationTool, getCurrentWeatherTool },
28 StreamingEnabled = true,
29 };
30
31 PrintMessageItems(options.InputItems.OfType<MessageResponseItem>());
32
33 bool requiresAction;
34
35 do
36 {
37 requiresAction = false;
38
39 AsyncCollectionResult<StreamingResponseUpdate> responseUpdates = client.CreateResponseStreamingAsync(options);
40
41 await foreach (StreamingResponseUpdate update in responseUpdates)
42 {
43 if (update is StreamingResponseOutputItemAddedUpdate outputItemAddedUpdated)
44 {
45 if (outputItemAddedUpdated.Item is MessageResponseItem message && message.Role == MessageRole.Assistant)
46 {
47 Console.WriteLine($"[ASSISTANT]:");
48 }
49 }
50
51 if (update is StreamingResponseOutputTextDeltaUpdate outputTextUpdate)
52 {
53 Console.Write(outputTextUpdate.Delta);
54 }
55
56 if (update is StreamingResponseOutputItemDoneUpdate outputItemDoneUpdate)
57 {
58 options.InputItems.Add(outputItemDoneUpdate.Item);
59
60 if (outputItemDoneUpdate.Item is FunctionCallResponseItem functionCall)
61 {
62 switch (functionCall.FunctionName)
63 {
64 case nameof(GetCurrentLocation):
65 {
66 string functionOutput = GetCurrentLocation();
67 options.InputItems.Add(new FunctionCallOutputResponseItem(functionCall.CallId, functionOutput));
68 break;
69 }
70
71 case nameof(GetCurrentWeather):
72 {
73 // The arguments that the model wants to use to call the function are specified as a
74 // stringified JSON object based on the schema defined in the tool definition. Note that
75 // the model may hallucinate arguments too. Consequently, it is important to do the
76 // appropriate parsing and validation before calling the function.
77 using JsonDocument argumentsJson = JsonDocument.Parse(functionCall.FunctionArguments);
78 bool hasLocation = argumentsJson.RootElement.TryGetProperty("location", out JsonElement location);
79 bool hasUnit = argumentsJson.RootElement.TryGetProperty("unit", out JsonElement unit);
80
81 if (!hasLocation)
82 {
83 throw new ArgumentNullException(nameof(location), "The location argument is required.");
84 }
85
86 string functionOutput = hasUnit
87 ? GetCurrentWeather(location.GetString(), unit.GetString())
88 : GetCurrentWeather(location.GetString());
89 options.InputItems.Add(new FunctionCallOutputResponseItem(functionCall.CallId, functionOutput));
90 break;
91 }
92
93 default:
94 {
95 // Handle other unexpected calls.
96 throw new NotImplementedException();
97 }
98 }
99
100 requiresAction = true;
101 break;
102 }
103 }
104 }
105 } while (requiresAction);
106 }
107}
108
109#pragma warning restore OPENAI001