openai/openai-dotnet

Public

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

CodeCommitsIssuesPull requestsActionsInsightsSecurity
copilot/sub-pr-1026

Branches

Tags

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

Clone

HTTPS

Download ZIP

examples/Assistants/Example04_AllTheTools.cs

209lines · modecode

1using NUnit.Framework;
2using OpenAI.Assistants;
3using OpenAI.Files;
4using System;
5using System.ClientModel;
6using System.Collections.Generic;
7using System.Text.Json;
8using System.Threading;
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 AssistantExamples
17{
18 [Test]
19 public void Example04_AllTheTools()
20 {
21 #region Define a function tool
22 static string GetNameOfFamilyMember(string relation)
23 => relation switch
24 {
25 { } when relation.Contains("father") => "John Doe",
26 { } when relation.Contains("mother") => "Jane Doe",
27 _ => throw new ArgumentException(relation, nameof(relation))
28 };
29
30 FunctionToolDefinition getNameOfFamilyMemberTool = new(nameof(GetNameOfFamilyMember))
31 {
32 Description = "Provided a family relation type like 'father' or 'mother', "
33 + "gets the name of the related person from the user.",
34 Parameters = BinaryData.FromString("""
35 {
36 "type": "object",
37 "properties": {
38 "relation": {
39 "type": "string",
40 "description": "The relation to the user to query, e.g. 'mother' or 'father'"
41 }
42 },
43 "required": [ "relation" ]
44 }
45 """),
46 };
47
48 #region Upload a mock file for use with file search
49 OpenAIFileClient fileClient = new(Environment.GetEnvironmentVariable("OPENAI_API_KEY"));
50 OpenAIFile favoriteNumberFile = fileClient.UploadFile(
51 BinaryData.FromString("""
52 This file contains the favorite numbers for individuals.
53
54 John Doe: 14
55 Bob Doe: 32
56 Jane Doe: 44
57 """).ToStream(),
58 "favorite_numbers.txt",
59 FileUploadPurpose.Assistants);
60 #endregion
61
62 #region Create an assistant with functions, file search, and code interpreter all enabled
63 AssistantClient client = new(Environment.GetEnvironmentVariable("OPENAI_API_KEY"));
64 Assistant assistant = client.CreateAssistant("gpt-4-turbo", new AssistantCreationOptions()
65 {
66 Instructions = "Use functions to resolve family relations into the names of people. Use file search to "
67 + " look up the favorite numbers of people. Use code interpreter to create graphs of lines.",
68 Tools = { getNameOfFamilyMemberTool, new FileSearchToolDefinition(), new CodeInterpreterToolDefinition() },
69 ToolResources = new()
70 {
71 FileSearch = new()
72 {
73 NewVectorStores =
74 {
75 new VectorStoreCreationHelper([favoriteNumberFile.Id]),
76 },
77 },
78 },
79 });
80 #endregion
81
82 #region Create a new thread and start a run
83 AssistantThread thread = client.CreateThread(new ThreadCreationOptions()
84 {
85 InitialMessages =
86 {
87 "Create a graph of a line with a slope that's my father's favorite number "
88 + "and an offset that's my mother's favorite number.",
89 "Include people's names in your response and cite where you found them."
90 }
91 });
92
93 ThreadRun run = client.CreateRun(thread.Id, assistant.Id);
94 #endregion
95
96 #region Complete the run, calling functions as needed
97 // Poll the run until it is no longer queued or in progress.
98 while (!run.Status.IsTerminal)
99 {
100 Thread.Sleep(TimeSpan.FromSeconds(1));
101 run = client.GetRun(run.ThreadId, run.Id);
102
103 // If the run requires action, resolve them.
104 if (run.Status == RunStatus.RequiresAction)
105 {
106 List<ToolOutput> toolOutputs = [];
107
108 foreach (RequiredAction action in run.RequiredActions)
109 {
110 switch (action.FunctionName)
111 {
112 case nameof(GetNameOfFamilyMember):
113 {
114 using JsonDocument argumentsDocument = JsonDocument.Parse(action.FunctionArguments);
115 string relation = argumentsDocument.RootElement.TryGetProperty("relation", out JsonElement relationProperty)
116 ? relationProperty.GetString()
117 : null;
118 string toolResult = GetNameOfFamilyMember(relation);
119 toolOutputs.Add(new ToolOutput(action.ToolCallId, toolResult));
120 break;
121 }
122
123 default:
124 {
125 // Handle other or unexpected calls.
126 throw new NotImplementedException();
127 }
128 }
129 }
130
131 // Submit the tool outputs to the assistant, which returns the run to the queued state.
132 run = client.SubmitToolOutputsToRun(run.ThreadId, run.Id, toolOutputs);
133 }
134 }
135 #endregion
136
137 #region
138 // With the run complete, list the messages and display their content
139 if (run.Status == RunStatus.Completed)
140 {
141 CollectionResult<ThreadMessage> messages
142 = client.GetMessages(run.ThreadId, new MessageCollectionOptions() { Order = MessageCollectionOrder.Ascending });
143 foreach (ThreadMessage message in messages)
144 {
145 Console.WriteLine($"[{message.Role.ToString().ToUpper()}]: ");
146 foreach (MessageContent contentItem in message.Content)
147 {
148 Console.WriteLine($"{contentItem.Text}");
149
150 if (contentItem.ImageFileId is not null)
151 {
152 Console.WriteLine($" <Image File ID> {contentItem.ImageFileId}");
153 }
154
155 // Include annotations, if any.
156 if (contentItem.TextAnnotations.Count > 0)
157 {
158 Console.WriteLine();
159 foreach (TextAnnotation annotation in contentItem.TextAnnotations)
160 {
161 Console.WriteLine($"* File ID used by file_search: {annotation.InputFileId}");
162 Console.WriteLine($"* File ID created by code_interpreter: {annotation.OutputFileId}");
163 Console.WriteLine($"* Text to replace: {annotation.TextToReplace}");
164 Console.WriteLine($"* Message content index range: {annotation.StartIndex}-{annotation.EndIndex}");
165 }
166 }
167
168 }
169 Console.WriteLine();
170 }
171 #endregion
172
173 #region List run steps for details about tool calls
174 CollectionResult<RunStep> runSteps = client.GetRunSteps(
175 run.ThreadId,
176 run.Id,
177 new RunStepCollectionOptions()
178 {
179 Order = RunStepCollectionOrder.Ascending
180 });
181 foreach (RunStep step in runSteps)
182 {
183 Console.WriteLine($"Run step: {step.Status}");
184 foreach (RunStepToolCall toolCall in step.Details.ToolCalls)
185 {
186 Console.WriteLine($" --> Tool call: {toolCall.Kind}");
187 foreach (RunStepCodeInterpreterOutput output in toolCall.CodeInterpreterOutputs)
188 {
189 Console.WriteLine($" --> Output: {output.ImageFileId}");
190 }
191 }
192 }
193 #endregion
194 }
195 else
196 {
197 throw new NotImplementedException(run.Status.ToString());
198 }
199 #endregion
200
201 #region Clean up any temporary resources that are no longer needed
202 _ = client.DeleteThread(thread.Id);
203 _ = client.DeleteAssistant(assistant.Id);
204 _ = fileClient.DeleteFile(favoriteNumberFile.Id);
205 #endregion
206 }
207}
208
209#pragma warning restore OPENAI001