1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113 | using var api = GetAuthenticatedClient();
var service = new FunctionCallingService();
IList<ChatCompletionTool> tools = service.AsTools().AsOpenAiTools();
AssistantObject assistant = await api.Assistants.CreateAssistantAsync(
model: CreateAssistantRequestModel.Gpt4o,
name: "Example: Function Calling",
instructions: "Don't make assumptions about what values to plug into functions."
+ " Ask for clarification if a user request is ambiguous.",
tools: tools.Select(x => new ToolsItem2(new AssistantToolsFunction
{
Function = x.Function,
})).ToArray());
RunObject run = await api.Assistants.CreateThreadAndRunAsync(
assistantId: assistant.Id,
new CreateThreadRequest
{
Messages = ["What's the weather like today?"],
});
// Poll the run until it is no longer queued or in progress.
while (run.Status is RunObjectStatus.Queued or RunObjectStatus.InProgress or RunObjectStatus.RequiresAction)
{
await Task.Delay(TimeSpan.FromSeconds(1));
run = await api.Assistants.GetRunAsync(run.ThreadId, run.Id);
// If the run requires action, resolve them.
if (run.Status == RunObjectStatus.RequiresAction)
{
List<SubmitToolOutputsRunRequestToolOutput> toolOutputs = [];
foreach (RunToolCallObject toolCall in run.RequiredAction?.SubmitToolOutputs.ToolCalls ?? [])
{
var json = await service.CallAsync(
functionName: toolCall.Function.Name,
argumentsAsJson: toolCall.Function.Arguments);
toolOutputs.Add(new SubmitToolOutputsRunRequestToolOutput
{
ToolCallId = toolCall.Id,
Output = json,
});
}
// Submit the tool outputs to the assistant, which returns the run to the queued state.
run = await api.Assistants.SubmitToolOuputsToRunAsync(
threadId: run.ThreadId,
runId: run.Id,
toolOutputs: toolOutputs);
}
}
// With the run complete, list the messages and display their content
if (run.Status == RunObjectStatus.Completed)
{
ListMessagesResponse messages
= await api.Assistants.ListMessagesAsync(run.ThreadId, order: ListMessagesOrder.Asc);
foreach (MessageObject message in messages.Data)
{
Console.WriteLine($"[{message.Role.ToString().ToUpper()}]: ");
foreach (ContentItem2 contentItem in message.Content)
{
if (contentItem.ImageFile is {} imageFile)
{
Console.WriteLine($" <Image File ID> {imageFile.ImageFile.FileId}");
}
if (contentItem.ImageUrl is {} imageUrl)
{
Console.WriteLine($" <Image URL> {imageUrl.ImageUrl.Url}");
}
if (contentItem.Text is {} text)
{
Console.WriteLine($"{text.Text.Value}");
// Include annotations, if any.
if (text.Text.Annotations.Count > 0)
{
Console.WriteLine();
foreach (AnnotationsItem annotation in text.Text.Annotations)
{
if (annotation.FileCitation is {} fileCitation)
{
Console.WriteLine($"* File citation, file ID: {fileCitation.FileCitation.FileId}");
Console.WriteLine($"* Text to replace: {fileCitation.Text}");
Console.WriteLine($"* Message content index range: {fileCitation.StartIndex}-{fileCitation.EndIndex}");
}
if (annotation.FilePath is {} filePath)
{
Console.WriteLine($"* File output, new file ID: {filePath.FilePath.FileId}");
Console.WriteLine($"* Text to replace: {filePath.Text}");
Console.WriteLine($"* Message content index range: {filePath.StartIndex}-{filePath.EndIndex}");
}
}
}
}
if (contentItem.Refusal is {} refusal)
{
Console.WriteLine($"Refusal: {refusal.Refusal}");
}
}
Console.WriteLine();
}
}
else
{
throw new NotImplementedException(run.Status.ToString());
}
// Optionally, delete any persistent resources you no longer need.
_ = await api.Assistants.DeleteThreadAsync(run.ThreadId);
_ = await api.Assistants.DeleteAssistantAsync(assistant.Id);
|