FunctionCallingStreaming

 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
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());

ThreadObject thread = await api.Assistants.CreateThreadAsync(new CreateThreadRequest
{
    Messages = ["What's the weather like today?"],
});

var streamingUpdates = api.Assistants.CreateRunAsStreamAsync(
    threadId: thread.Id,
    assistantId: assistant.Id);

RunObject? currentRun;
do
{
    currentRun = null;
    List<SubmitToolOutputsRunRequestToolOutput> outputsToSubmit = [];

    await foreach (AssistantStreamEvent streamingUpdate in streamingUpdates)
    {
        if (streamingUpdate.ThreadRunCreated is { Data: {} newRun })
        {
            Console.WriteLine("--- Run created! ---");

            currentRun = newRun;
        }
        if (streamingUpdate.ThreadRunRequiresAction is { Data.RequiredAction: {} requiredAction })
        {
            foreach (RunToolCallObject toolCall in requiredAction.SubmitToolOutputs.ToolCalls)
            {
                var json = await service.CallAsync(
                    functionName: toolCall.Function.Name,
                    argumentsAsJson: toolCall.Function.Arguments);
                outputsToSubmit.Add(new SubmitToolOutputsRunRequestToolOutput
                {
                    ToolCallId = toolCall.Id,
                    Output = json,
                });
            }
        }
        if (streamingUpdate.ThreadMessageDelta is {} delta)
        {
            foreach (var deltaVariation in delta.Data.Delta.Content ?? [])
            {
                if (deltaVariation.ImageFile is {} imageFile)
                {
                    Console.WriteLine();
                    Console.WriteLine(imageFile.ImageFile?.FileId);
                }
                if (deltaVariation.Text is {} text)
                {
                    Console.Write(text.Text?.Value);
                }
                if (deltaVariation.Refusal is {} refusal)
                {
                    Console.WriteLine();
                    Console.WriteLine(refusal.Refusal);
                }
                if (deltaVariation.ImageUrl is {} imageUrl)
                {
                    Console.WriteLine();
                    Console.WriteLine(imageUrl.ImageUrl?.Url);
                }
            }
        }
    }

    if (outputsToSubmit.Count > 0)
    {
        // streamingUpdates = await api.Assistants.SubmitToolOuputsToRunAsStreamAsync(
        //     threadId: currentRun.ThreadId,
        //     runId: currentRun.Id,
        //     outputsToSubmit);
    }
}
while (currentRun?.Status is RunObjectStatus.Queued or RunObjectStatus.InProgress or RunObjectStatus.RequiresAction);

_ = await api.Assistants.DeleteThreadAsync(thread.Id);
_ = await api.Assistants.DeleteAssistantAsync(assistant.Id);