Skip to content

Update long-running operation APIs to use LRO subclient pattern #129

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
154 commits
Select commit Hold shift + click to select a range
f4ab277
Add project reference to SCM; move to new paging types
annelo-msft Jun 25, 2024
38dd09d
wire return values and stub out implementations
annelo-msft Jun 25, 2024
17c4078
update page collection to use new page token contract
annelo-msft Jun 26, 2024
9cf0447
Update tests and samples
annelo-msft Jun 26, 2024
7679061
fix page token serialization logic
annelo-msft Jun 26, 2024
6acd48b
add async page collections
annelo-msft Jun 26, 2024
6327af6
Add rehydration overload
annelo-msft Jun 26, 2024
e0c14eb
Add async rehydration overload
annelo-msft Jun 26, 2024
2d46435
backup WIP on generalized implementation
annelo-msft Jun 26, 2024
bae625a
backup WIP on generalized implementation
annelo-msft Jun 26, 2024
03e17b6
remove Assistant-specific page collection implementations in favor of…
annelo-msft Jun 26, 2024
1f150ea
remove Assistant-specific page collection implementations in favor of…
annelo-msft Jun 26, 2024
6ba8dbd
Backup of generalized protocol paging idea
annelo-msft Jun 26, 2024
7c1f74d
remove Assistant-specific page result enumerator implementations in f…
annelo-msft Jun 26, 2024
bc2004e
take BinaryData instead of ClientToken, which cannot be constructed a…
annelo-msft Jun 26, 2024
6138636
rework rehydration methods to use new ClientToken pattern
annelo-msft Jun 26, 2024
bae34b9
add test for rehydration method
annelo-msft Jun 26, 2024
5283bc5
add a second test for rehydration method
annelo-msft Jun 26, 2024
e0305ea
SCM renames
annelo-msft Jun 26, 2024
64bea2b
updates from mini pr review
annelo-msft Jun 26, 2024
ea8db96
rework RequestOptions
annelo-msft Jun 26, 2024
bcfed80
bug fix
annelo-msft Jun 26, 2024
e365566
GetPageCore
annelo-msft Jun 27, 2024
1ed51af
backup of initial thinking on operation-specific page token idea
annelo-msft Jun 27, 2024
2ad6dc1
extend operation-specific page token idea to protocol methods
annelo-msft Jun 27, 2024
5b236a6
rename ClientToken to ContinuationToken
annelo-msft Jun 27, 2024
444bee0
nits: tidy
annelo-msft Jun 27, 2024
0060d5f
add test to illustrate convenience/protocol interop
annelo-msft Jun 28, 2024
0aca908
updates based on feedback from Krzysztof
annelo-msft Jul 1, 2024
c4a8a63
add protocol implementations of all Assistant-related paged methods
annelo-msft Jul 1, 2024
4a9d6af
add convenience implementations of Assistant-related paged methods
annelo-msft Jul 1, 2024
f91969f
move to CurrentPageToken instead of FirstPageToken
annelo-msft Jul 1, 2024
90eed11
starting idea around client as enumerator; backing up
annelo-msft Jul 1, 2024
313753e
more backup
annelo-msft Jul 1, 2024
a8e17e3
tidy up before taking inventory
annelo-msft Jul 1, 2024
c5261d1
backup prior to attempt to converge around single internal collection…
annelo-msft Jul 1, 2024
9c05fc2
more refining
annelo-msft Jul 1, 2024
209b71d
implement interface explicitly
annelo-msft Jul 1, 2024
b0d5f04
more tidy
annelo-msft Jul 1, 2024
c5b568d
Make it work for async
annelo-msft Jul 1, 2024
e07fb0b
restructure to look more like mini-client
annelo-msft Jul 2, 2024
f3c5e96
simplify
annelo-msft Jul 2, 2024
8b762e2
more nits and simplify
annelo-msft Jul 2, 2024
7cd2e92
nits
annelo-msft Jul 2, 2024
67d70fa
renames and a little rework
annelo-msft Jul 2, 2024
daab108
move page tokens
annelo-msft Jul 2, 2024
818b6bd
Implement remaining Assistants endpoings
annelo-msft Jul 2, 2024
34264b5
Implement vector store paginated endpoints
annelo-msft Jul 2, 2024
74e8b34
follow-ups to convenience and tests for vector stores
annelo-msft Jul 2, 2024
827cf2b
bug fix
annelo-msft Jul 2, 2024
891ccf5
temp bug fix
annelo-msft Jul 2, 2024
b15bd18
Proof of concept of PageEnumerator pattern for MessageCollection
annelo-msft Jul 2, 2024
34175dc
Refactor to PageEnumerator pattern
annelo-msft Jul 2, 2024
4a175d8
bug fix
annelo-msft Jul 2, 2024
8656f12
nit
annelo-msft Jul 2, 2024
4d2bf33
updates from SCM polish work
annelo-msft Jul 3, 2024
73faa95
Implement new LRO pattern on top of page collection implementatino
annelo-msft Jul 5, 2024
fc5d7ed
add missed files
annelo-msft Jul 5, 2024
529b399
add async overloads and rework poller a bit
annelo-msft Jul 5, 2024
a1422d1
fix some bugs
annelo-msft Jul 6, 2024
d338ec8
back up WIP
annelo-msft Jul 6, 2024
80dbcfa
more backup WIP
annelo-msft Jul 9, 2024
1ea8036
back up WIP
annelo-msft Jul 9, 2024
b2b3556
more backup of WIP - idea of protocol methods returning OperationResu…
annelo-msft Jul 10, 2024
415fff5
re-impl of polling LRO
annelo-msft Jul 10, 2024
c7d0870
nits
annelo-msft Jul 10, 2024
9ef8fc8
backup of streaming LRO WIP
annelo-msft Jul 10, 2024
e8886a3
intial e2e of async streaming ThreadRunLRO
annelo-msft Jul 10, 2024
279b3e7
backup while testing
annelo-msft Jul 10, 2024
4eeffaf
backup
annelo-msft Jul 11, 2024
e860fee
protocol operation implementation and polling test succeeds
annelo-msft Jul 11, 2024
aa94594
Streaming protocol implementation and test; one case open to solve still
annelo-msft Jul 11, 2024
46ffefc
handle IsCompleted for protocol/streaming by throwing, since we can't…
annelo-msft Jul 11, 2024
b1602b2
add test for streaming cancellation
annelo-msft Jul 11, 2024
05254c9
Initially implement StreamingThreadRunOperation.WaitAsync; with test …
annelo-msft Jul 11, 2024
4d5b0ef
add GetUpdatesStreaming method to StreamingThreadRunOperation
annelo-msft Jul 11, 2024
4482369
add SubmitToolOutputsToRunStreaming convenience method
annelo-msft Jul 11, 2024
5c384f3
add basic test for streaming SubmitToolOutput method; fix to Required…
annelo-msft Jul 12, 2024
67b0bdb
backup idea of ContinuableEnumerator
annelo-msft Jul 12, 2024
bd1722b
backup successful implementation of stream replacement ida
annelo-msft Jul 12, 2024
10ff848
add functional implementation of WaitAsync for streaming LRO
annelo-msft Jul 12, 2024
465b893
rewrite in terms of UpdateStatus
annelo-msft Jul 12, 2024
8f35fa6
move initialization to constructor
annelo-msft Jul 13, 2024
d8a6829
updates from SCM changes and some more comments and TODOs
annelo-msft Jul 13, 2024
f068567
Merge remote-tracking branch 'upstream/main' into oai-pageenumerator-…
annelo-msft Jul 15, 2024
4008584
move to SCM beta.5 package
annelo-msft Jul 15, 2024
b3d4fd7
Merge remote-tracking branch 'upstream/main' into oai-streamlroinherits
annelo-msft Jul 15, 2024
2e97ef7
move over update for protocol-convenience cast
annelo-msft Jul 15, 2024
1ee0486
some fixes
annelo-msft Jul 15, 2024
4ce3888
updates from SCM code
annelo-msft Jul 15, 2024
0622853
fix tests
annelo-msft Jul 15, 2024
e492b7c
remove internal protocol method implementations that have moved to in…
annelo-msft Jul 15, 2024
f811de1
nits
annelo-msft Jul 15, 2024
e7e3de7
add refdocs for paginated endpoint service methods
annelo-msft Jul 15, 2024
88319b8
add refdocs for options types
annelo-msft Jul 15, 2024
7118d13
add refdocs for collection rehydration overloads
annelo-msft Jul 15, 2024
e275801
add test and fix bugs
annelo-msft Jul 15, 2024
8d66ade
add a test for vector store
annelo-msft Jul 15, 2024
e1bdc4e
Merge remote-tracking branch 'upstream/main' into oai-streamlroinherits
annelo-msft Jul 16, 2024
8c77af5
Merge branch 'oai-streamlroinherits' of https://github.com/annelo-msf…
annelo-msft Jul 16, 2024
cfae419
updates from SCM changes
annelo-msft Jul 16, 2024
e99b2ba
Merge remote-tracking branch 'upstream/main' into oai-streamlroinherits
annelo-msft Jul 16, 2024
ae6eb9d
bug fix
annelo-msft Jul 16, 2024
d0417ae
back up WIP in adding convenience overloads to ThreadRunOperation min…
annelo-msft Jul 16, 2024
1666794
backup prior to running tests
annelo-msft Jul 16, 2024
422b594
add ReturnWhen parameter to protocol methods
annelo-msft Jul 16, 2024
1944863
bug fixes
annelo-msft Jul 16, 2024
6c637c7
Merge remote-tracking branch 'upstream/main' into oai-pageenumerator-…
annelo-msft Jul 16, 2024
0813f06
Merge branch 'oai-pageenumerator-pattern' into oai-streamlroinherits
annelo-msft Jul 16, 2024
aacf13b
more updates from paging PR branch
annelo-msft Jul 16, 2024
408bfef
add operation rehydration methods and tests
annelo-msft Jul 16, 2024
9a920f8
nits: backup before enumerable experiment
annelo-msft Jul 16, 2024
5373a8c
experiment with adding GetUpdates API to polling LRO type to enable e…
annelo-msft Jul 16, 2024
ea73b60
Merge remote-tracking branch 'upstream/main' into oai-streamlroinherits
annelo-msft Jul 17, 2024
8d9eadb
name RunId to Id; add GetRun methods back to client
annelo-msft Jul 17, 2024
f231512
Begin experiment around LRO using generated update enumerator
annelo-msft Jul 17, 2024
f98a66f
implement generated enumerator pattern for protocol LRO
annelo-msft Jul 17, 2024
ac99e31
rename ThreadRunOperation and related to RunOperation
annelo-msft Jul 17, 2024
d462a11
implement generated enumerator pattern for convenience polling LRO
annelo-msft Jul 17, 2024
d714a9e
Back up functional implementation of streaming LRO GetUpdates while f…
annelo-msft Jul 17, 2024
7041424
Make streaming convenience submit tools/Wait test pass
annelo-msft Jul 17, 2024
cf7a745
back up idea showing enumerable layering idea won't work
annelo-msft Jul 17, 2024
8bf827f
illustrate polling with custom polling interval
annelo-msft Jul 18, 2024
252d9fe
backup stub test for fine-tuning
annelo-msft Jul 19, 2024
42f5f0c
add initial (untested) fine tuning LRO implementation
annelo-msft Jul 19, 2024
f0103e9
add initial implementation of protocol VectorStoreFileBatchOperation
annelo-msft Jul 19, 2024
54be070
initial checkin of convenience layer for VectorStoreFileBatchOperation
annelo-msft Jul 19, 2024
ef1f94c
update tests to use LRO type
annelo-msft Jul 19, 2024
a3dfbb7
add back tests
annelo-msft Jul 20, 2024
2f42e22
add examples back
annelo-msft Jul 20, 2024
843fb97
make examples green
annelo-msft Jul 20, 2024
1c03389
Merge remote-tracking branch 'upstream/main' into oai-lro-updateenume…
annelo-msft Jul 22, 2024
08fee67
Add implementations where throwing NotImplementedException
annelo-msft Jul 22, 2024
dccc488
have streaming LRO override GetUpdates on polling type
annelo-msft Jul 22, 2024
b5adec2
updates
annelo-msft Jul 22, 2024
2b8f481
cleanup in progress
annelo-msft Jul 22, 2024
d6bee73
more cleanup and rename rehydration methods to ContinueRun
annelo-msft Jul 23, 2024
363a17a
Merge remote-tracking branch 'upstream/main' into oai-lro-updateenume…
annelo-msft Jul 23, 2024
e2605df
post-merge
annelo-msft Jul 23, 2024
f2745f6
revert file with bad merge
annelo-msft Jul 23, 2024
47f68d6
public API updates from looking at the APIView
annelo-msft Jul 23, 2024
18d389a
Merge remote-tracking branch 'upstream/main' into oai-lro-updateenume…
annelo-msft Jul 24, 2024
042b904
updates from merge
annelo-msft Jul 24, 2024
c17fa59
more post-merge updates
annelo-msft Jul 24, 2024
c7daa98
add EBN to RunOperation protocol methods
annelo-msft Jul 25, 2024
facf668
fix bug in polling implementation; rework meta enumerator to not crea…
annelo-msft Jul 25, 2024
3bdb145
Look at what WaitReturnReason enum implementation might look like
annelo-msft Jul 25, 2024
032441e
back out WaitReturnReason change
annelo-msft Jul 26, 2024
974e19a
initial add of BatchOperation for Batch protocol methods
annelo-msft Jul 26, 2024
36a98d9
update with final SCM 1.1.0-beta.6 APIs
annelo-msft Jul 26, 2024
e374436
Add CancellationTokens back to RunOperation for consistency with SCM …
annelo-msft Jul 26, 2024
978a5e2
make protocol methods for LROs take ReturnWhen parameter
annelo-msft Jul 26, 2024
fcd664d
nits
annelo-msft Jul 26, 2024
f0fb0ff
Merge remote-tracking branch 'upstream/main' into oai-lro-updateenume…
annelo-msft Aug 5, 2024
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 8 additions & 2 deletions OpenAI.sln
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,9 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "OpenAI", "src\OpenAI.csproj
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "OpenAI.Examples", "examples\OpenAI.Examples.csproj", "{1F1CD1D4-9932-4B73-99D8-C252A67D4B46}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "OpenAI.Tests", "tests\OpenAI.Tests.csproj", "{6F156401-2544-41D7-B204-3148C51C1D09}"
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "OpenAI.Tests", "tests\OpenAI.Tests.csproj", "{6F156401-2544-41D7-B204-3148C51C1D09}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "System.ClientModel", "..\azure-sdk-for-net\sdk\core\System.ClientModel\src\System.ClientModel.csproj", "{8316F2D5-21A7-468B-97DB-B14C44B4F50C}"
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should be able to update this to SCM 1.1.0-beta.6 when it ships next week.

EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Expand All @@ -26,11 +28,15 @@ Global
{6F156401-2544-41D7-B204-3148C51C1D09}.Debug|Any CPU.Build.0 = Debug|Any CPU
{6F156401-2544-41D7-B204-3148C51C1D09}.Release|Any CPU.ActiveCfg = Release|Any CPU
{6F156401-2544-41D7-B204-3148C51C1D09}.Release|Any CPU.Build.0 = Release|Any CPU
{8316F2D5-21A7-468B-97DB-B14C44B4F50C}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{8316F2D5-21A7-468B-97DB-B14C44B4F50C}.Debug|Any CPU.Build.0 = Debug|Any CPU
{8316F2D5-21A7-468B-97DB-B14C44B4F50C}.Release|Any CPU.ActiveCfg = Release|Any CPU
{8316F2D5-21A7-468B-97DB-B14C44B4F50C}.Release|Any CPU.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
EndGlobalSection
GlobalSection(ExtensibilityGlobals) = postSolution
SolutionGuid = {A97F4B90-2591-4689-B1F8-5F21FE6D6CAE}
EndGlobalSection
EndGlobal
EndGlobal
15 changes: 4 additions & 11 deletions examples/Assistants/Example01_RetrievalAugmentedGeneration.cs
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,6 @@
using System.ClientModel;
using System.Collections.Generic;
using System.IO;
using System.Threading;

namespace OpenAI.Examples;

Expand Down Expand Up @@ -88,18 +87,12 @@ public void Example01_RetrievalAugmentedGeneration()
InitialMessages = { "How well did product 113045 sell in February? Graph its trend over time." }
};

ThreadRun threadRun = assistantClient.CreateThreadAndRun(assistant.Id, threadOptions);

// Check back to see when the run is done
do
{
Thread.Sleep(TimeSpan.FromSeconds(1));
threadRun = assistantClient.GetRun(threadRun.ThreadId, threadRun.Id);
} while (!threadRun.Status.IsTerminal);
// Passing ReturnWhen.Completed means CreateThreadAndRun will return control after the run is complete.
RunOperation runOperation = assistantClient.CreateThreadAndRun(ReturnWhen.Completed, assistant.Id, threadOptions);

// Finally, we'll print out the full history for the thread that includes the augmented generation
PageCollection<ThreadMessage> messagePages
= assistantClient.GetMessages(threadRun.ThreadId, new MessageCollectionOptions() { Order = ListOrder.OldestFirst });
= assistantClient.GetMessages(runOperation.ThreadId, new MessageCollectionOptions() { Order = ListOrder.OldestFirst });
IEnumerable<ThreadMessage> messages = messagePages.GetAllValues();

foreach (ThreadMessage message in messages)
Expand Down Expand Up @@ -143,7 +136,7 @@ PageCollection<ThreadMessage> messagePages
}

// Optionally, delete any persistent resources you no longer need.
_ = assistantClient.DeleteThread(threadRun.ThreadId);
_ = assistantClient.DeleteThread(runOperation.ThreadId);
_ = assistantClient.DeleteAssistant(assistant);
_ = fileClient.DeleteFile(salesFile);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,6 @@
using System.ClientModel;
using System.Collections.Generic;
using System.IO;
using System.Threading;
using System.Threading.Tasks;

namespace OpenAI.Examples;
Expand Down Expand Up @@ -89,18 +88,11 @@ public async Task Example01_RetrievalAugmentedGenerationAsync()
InitialMessages = { "How well did product 113045 sell in February? Graph its trend over time." }
};

ThreadRun threadRun = await assistantClient.CreateThreadAndRunAsync(assistant.Id, threadOptions);

// Check back to see when the run is done
do
{
Thread.Sleep(TimeSpan.FromSeconds(1));
threadRun = assistantClient.GetRun(threadRun.ThreadId, threadRun.Id);
} while (!threadRun.Status.IsTerminal);
RunOperation runOperation = await assistantClient.CreateThreadAndRunAsync(ReturnWhen.Completed, assistant.Id, threadOptions);

// Finally, we'll print out the full history for the thread that includes the augmented generation
AsyncPageCollection<ThreadMessage> messagePages
= assistantClient.GetMessagesAsync(threadRun.ThreadId, new MessageCollectionOptions() { Order = ListOrder.OldestFirst });
= assistantClient.GetMessagesAsync(runOperation.ThreadId, new MessageCollectionOptions() { Order = ListOrder.OldestFirst });
IAsyncEnumerable<ThreadMessage> messages = messagePages.GetAllValuesAsync();

await foreach (ThreadMessage message in messages)
Expand Down Expand Up @@ -144,7 +136,7 @@ AsyncPageCollection<ThreadMessage> messagePages
}

// Optionally, delete any persistent resources you no longer need.
_ = await assistantClient.DeleteThreadAsync(threadRun.ThreadId);
_ = await assistantClient.DeleteThreadAsync(runOperation.ThreadId);
_ = await assistantClient.DeleteAssistantAsync(assistant);
_ = await fileClient.DeleteFileAsync(salesFile);
}
Expand Down
38 changes: 19 additions & 19 deletions examples/Assistants/Example02_FunctionCalling.cs
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ public partial class AssistantExamples
[Test]
public void Example02_FunctionCalling()
{
#region
#region Define Functions
string GetCurrentLocation()
{
// Call a location API here.
Expand Down Expand Up @@ -64,7 +64,7 @@ string GetCurrentWeather(string location, string unit = "celsius")
#pragma warning disable OPENAI001
AssistantClient client = new(Environment.GetEnvironmentVariable("OPENAI_API_KEY"));

#region
#region Create Assistant
// Create an assistant that can call the function tools.
AssistantCreationOptions assistantOptions = new()
{
Expand All @@ -78,29 +78,27 @@ string GetCurrentWeather(string location, string unit = "celsius")
Assistant assistant = client.CreateAssistant("gpt-4-turbo", assistantOptions);
#endregion

#region
#region Create Thread and Run
// Create a thread with an initial user message and run it.
ThreadCreationOptions threadOptions = new()
{
InitialMessages = { "What's the weather like today?" }
};

ThreadRun run = client.CreateThreadAndRun(assistant.Id, threadOptions);
RunOperation runOperation = client.CreateThreadAndRun(ReturnWhen.Started, assistant.Id, threadOptions);
#endregion

#region
// Poll the run until it is no longer queued or in progress.
while (!run.Status.IsTerminal)
{
Thread.Sleep(TimeSpan.FromSeconds(1));
run = client.GetRun(run.ThreadId, run.Id);
#region Submit tool outputs to run

IEnumerable<ThreadRun> updates = runOperation.GetUpdates();

// If the run requires action, resolve them.
if (run.Status == RunStatus.RequiresAction)
foreach (ThreadRun update in updates)
{
if (update.Status == RunStatus.RequiresAction)
{
List<ToolOutput> toolOutputs = [];

foreach (RequiredAction action in run.RequiredActions)
foreach (RequiredAction action in runOperation.Value.RequiredActions)
{
switch (action.FunctionName)
{
Expand Down Expand Up @@ -142,17 +140,19 @@ string GetCurrentWeather(string location, string unit = "celsius")
}

// Submit the tool outputs to the assistant, which returns the run to the queued state.
run = client.SubmitToolOutputsToRun(run.ThreadId, run.Id, toolOutputs);
runOperation.SubmitToolOutputsToRun(toolOutputs);
}
}

#endregion

#region
// With the run complete, list the messages and display their content
if (run.Status == RunStatus.Completed)
#region Get and display messages

// If the run completed successfully, list the messages and display their content
if (runOperation.Status == RunStatus.Completed)
{
PageCollection<ThreadMessage> messagePages
= client.GetMessages(run.ThreadId, new MessageCollectionOptions() { Order = ListOrder.OldestFirst });
= client.GetMessages(runOperation.ThreadId, new MessageCollectionOptions() { Order = ListOrder.OldestFirst });
IEnumerable<ThreadMessage> messages = messagePages.GetAllValues();

foreach (ThreadMessage message in messages)
Expand Down Expand Up @@ -186,7 +186,7 @@ PageCollection<ThreadMessage> messagePages
}
else
{
throw new NotImplementedException(run.Status.ToString());
throw new NotImplementedException(runOperation.Status.ToString());
}
#endregion
}
Expand Down
24 changes: 12 additions & 12 deletions examples/Assistants/Example02_FunctionCallingAsync.cs
Original file line number Diff line number Diff line change
Expand Up @@ -85,22 +85,22 @@ string GetCurrentWeather(string location, string unit = "celsius")
InitialMessages = { "What's the weather like today?" }
};

ThreadRun run = await client.CreateThreadAndRunAsync(assistant.Id, threadOptions);
RunOperation runOperation = await client.CreateThreadAndRunAsync(ReturnWhen.Started, assistant.Id, threadOptions);
#endregion

#region
// Poll the run until it is no longer queued or in progress.
while (!run.Status.IsTerminal)
{
await Task.Delay(TimeSpan.FromSeconds(1));
run = await client.GetRunAsync(run.ThreadId, run.Id);


IEnumerable<ThreadRun> updates = runOperation.GetUpdates();

foreach (ThreadRun update in updates)
{
// If the run requires action, resolve them.
if (run.Status == RunStatus.RequiresAction)
if (runOperation.Status == RunStatus.RequiresAction)
{
List<ToolOutput> toolOutputs = [];

foreach (RequiredAction action in run.RequiredActions)
foreach (RequiredAction action in runOperation.Value.RequiredActions)
{
switch (action.FunctionName)
{
Expand Down Expand Up @@ -142,17 +142,17 @@ string GetCurrentWeather(string location, string unit = "celsius")
}

// Submit the tool outputs to the assistant, which returns the run to the queued state.
run = await client.SubmitToolOutputsToRunAsync(run.ThreadId, run.Id, toolOutputs);
await runOperation.SubmitToolOutputsToRunAsync(toolOutputs);
}
}
#endregion

#region
// With the run complete, list the messages and display their content
if (run.Status == RunStatus.Completed)
if (runOperation.Status == RunStatus.Completed)
{
AsyncPageCollection<ThreadMessage> messagePages
= client.GetMessagesAsync(run.ThreadId, new MessageCollectionOptions() { Order = ListOrder.OldestFirst });
= client.GetMessagesAsync(runOperation.ThreadId, new MessageCollectionOptions() { Order = ListOrder.OldestFirst });
IAsyncEnumerable<ThreadMessage> messages = messagePages.GetAllValuesAsync();

await foreach (ThreadMessage message in messages)
Expand Down Expand Up @@ -186,7 +186,7 @@ AsyncPageCollection<ThreadMessage> messagePages
}
else
{
throw new NotImplementedException(run.Status.ToString());
throw new NotImplementedException(runOperation.Status.ToString());
}
#endregion
}
Expand Down
40 changes: 15 additions & 25 deletions examples/Assistants/Example02b_FunctionCallingStreaming.cs
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
using NUnit.Framework;
using OpenAI.Assistants;
using System;
using System.ClientModel;
using System.ClientModel.Primitives;
using System.Collections.Generic;
using System.Threading.Tasks;
Expand Down Expand Up @@ -91,43 +90,34 @@ public async Task Example02b_FunctionCallingStreaming()
#endregion

#region Step 3 - Initiate a streaming run
AsyncCollectionResult<StreamingUpdate> asyncUpdates
= client.CreateRunStreamingAsync(thread, assistant);
StreamingRunOperation runOperation = client.CreateRunStreaming(thread, assistant);
IAsyncEnumerable<StreamingUpdate> updates = runOperation.GetUpdatesStreamingAsync();

ThreadRun currentRun = null;
do
await foreach (StreamingUpdate update in updates)
{
currentRun = null;
List<ToolOutput> outputsToSubmit = [];
await foreach (StreamingUpdate update in asyncUpdates)
if (update is RequiredActionUpdate requiredActionUpdate)
{
if (update is RunUpdate runUpdate)
{
currentRun = runUpdate;
}
else if (update is RequiredActionUpdate requiredActionUpdate)
List<ToolOutput> outputsToSubmit = [];

foreach (RequiredAction action in requiredActionUpdate.RequiredActions)
{
if (requiredActionUpdate.FunctionName == getTemperatureTool.FunctionName)
if (action.FunctionName == getTemperatureTool.FunctionName)
{
outputsToSubmit.Add(new ToolOutput(requiredActionUpdate.ToolCallId, "57"));
outputsToSubmit.Add(new ToolOutput(action.ToolCallId, "57"));
}
else if (requiredActionUpdate.FunctionName == getRainProbabilityTool.FunctionName)
else if (action.FunctionName == getRainProbabilityTool.FunctionName)
{
outputsToSubmit.Add(new ToolOutput(requiredActionUpdate.ToolCallId, "25%"));
outputsToSubmit.Add(new ToolOutput(action.ToolCallId, "25%"));
}
}
else if (update is MessageContentUpdate contentUpdate)
{
Console.Write(contentUpdate.Text);
}

await runOperation.SubmitToolOutputsToRunStreamingAsync(outputsToSubmit);
}
if (outputsToSubmit.Count > 0)
else if (update is MessageContentUpdate contentUpdate)
{
asyncUpdates = client.SubmitToolOutputsToRunStreamingAsync(currentRun, outputsToSubmit);
Console.Write(contentUpdate.Text);
}
}
while (currentRun?.Status.IsTerminal == false);

#endregion

// Optionally, delete the resources for tidiness if no longer needed.
Expand Down
Loading