Narrower update to StreamingClientResult/SSE#68
Conversation
| /// </summary> | ||
| /// <typeparam name="T"> The data type representative of distinct, streamable items. </typeparam> | ||
| public class StreamingClientResult<T> | ||
| : IDisposable |
There was a problem hiding this comment.
Should not implement IDisposable - see discussion in Azure/azure-sdk-for-net#43392 and related email thread.
| /// <returns> A new instance of <see cref="StreamingClientResult{T}"/>. </returns> | ||
| public static StreamingClientResult<T> Create( | ||
| PipelineResponse response, | ||
| Func<JsonElement, IEnumerable<T>> multiElementJsonDeserializerFunc, |
There was a problem hiding this comment.
We wouldn't take a Func in a ClientModel API - I found an alternate approach that works when you constrain T to IJsonModel that is illustrated in #49
There was a problem hiding this comment.
Ah, just saw you added this below.
There was a problem hiding this comment.
Got it; I was considering something similar; having an internal "collection of updates" type (that's the thing actually deserialized per chunk, StreamingChatResult in your PR) and doing the public enumeration from there does indeed get us out of the business of doing weird T : IJsonModel<IEnumerable<T>> things. I will snap to the clearer pattern with the intermediate internal type.
| /// The optional cancellation token used to control the enumeration. | ||
| /// </param> | ||
| /// <returns> A new instance of <see cref="StreamingClientResult{T}"/>. </returns> | ||
| public static StreamingClientResult<U> Create<U>( |
There was a problem hiding this comment.
Why wouldn't this be T?
There was a problem hiding this comment.
Strangely, can't apply where clauses without making the method specifically generic (Create<T>) and then making the method generic emits an analyzer warning that's effectively "hey, that's a different T, FYI."
| finally | ||
| { | ||
| // Always dispose the stream immediately once enumeration is complete for any reason | ||
| contentStream.Dispose(); |
There was a problem hiding this comment.
Disposal should be handled by the enumerator, not the enumerable.
| try | ||
| { | ||
| response = requestMessage.ExtractResponse(); | ||
| ClientResult genericResult = ClientResult.FromResponse(response); |
There was a problem hiding this comment.
Do you need this genericResult? It does not seem to be used anywhere.
There was a problem hiding this comment.
Without it (and exposure via GetRawResponse()), is there another mechanism by which we'd allow customers to query for response headers, etc.?
There was a problem hiding this comment.
but you are not returning this genericResult to the user, and so they cannot read the headers anyway.
| finishReason = null; | ||
| continue; | ||
| } | ||
| finishReason = choiceProperty.Value.GetString() switch |
There was a problem hiding this comment.
this is lower pri, but would it be better to stay in UTF8 span world and use a sequence of if statements (like for top level properties)
| /// <returns> A new instance of <see cref="StreamingClientResult{T}"/>. </returns> | ||
| public static StreamingClientResult<T> Create( | ||
| PipelineResponse response, | ||
| Func<JsonElement, IEnumerable<T>> multiElementJsonDeserializerFunc, |
There was a problem hiding this comment.
Why do we need this parameter? Why the method below (with the constraint to IJsonModel) is not enoughl? In addition, we would need a Create method overload that returns StreamingClientResult for the protocol method case, i.e. when the caller want to get access to raw bytes of each event data so they can deserialize additional properties themselves.
There was a problem hiding this comment.
The complexity arises because StreamingChatUpdate has a many-to-one relationship with the wire payload, since we "splat" the uncommon case of multiple choices on a single SSE into separate update instances.
Anne's suggestion to just add an internal intermediate type that implements the canonical T : IJsonModel<T> pattern should get around the need for this; StreamingChatUpdate will then not be directly serializable. (Open question from that: does that mean we should actually make the StreamingChatUpdateCollection type public, despite it not being directly consumed or produced by operations?)
| /// The optional cancellation token used to control the enumeration. | ||
| /// </param> | ||
| /// <returns> A new instance of <see cref="StreamingClientResult{T}"/>. </returns> | ||
| public static StreamingClientResult<U> Create<U>(PipelineResponse response, CancellationToken cancellationToken = default) |
There was a problem hiding this comment.
Curious: is this used anywhere in the OAI client?
| return new(response, GetServerSentEventDeserializationEnumerator<U>); | ||
| } | ||
|
|
||
| public static StreamingClientResult<TInstanceType> Create<TInstanceType, TJsonDataType>(PipelineResponse response, CancellationToken cancellationToken = default) |
There was a problem hiding this comment.
Curious: is the TJsonDataType strictly required? I notice that it is an internal collection type in your implementation. Is it only to represent a collection? Is the collection format part of the SSE spec? If so, I am wondering if the factory method could just be Create<T> somehow and the collection could be left as an internal implementation detail.
…entation (#43840) * Add async and sync enumerable client results * Implement IAsyncDisposable * Remove constrant and disposable; update ClientResult so response can be replaced in a polling paradigm * rename and upate tests * initial addition of files from joseharriaga/openai-in-typespec#68 * make it build * hello world test * bootstrap more tests * more internal tests * adding enumerator tests; haven't figured out the batch piece yet * Make batch test pass * remove collection-event functionality and add tests for public type * reshuffle * Add mock convenience SSE type to give POC of lazy request sending * add tests of delayed request * Add BinaryData factory method * remove funcs for creating enumerators * renames * postpone call to protocol method from convenience APIs * implement IAsyncDisposable correctly * initial pass over cancellation token * Per FDG, throw OperationCanceledException if cancellation token is cancelled. * remove factory method taking Func<T> and provide example of layering convenience implementation in a way that postpones sending the request * rename internal types and WIP adding reader tests * nits * parameterize terminal event; TBD to provide virtual method on collection type * WIP: nits * WIP: added concatenation of data lines per SSE spec * updates and bug fixes * add tests and update per SSE spec * WIP: refactor to reuse field processing across sync and async methods * make look a little more like the BCL type proposal * simplify field implementation a bit * cosmetic reworking of creating an event from a pending event * Remove factory method from public API; move MockSseClient to Tests.Internal to access internal SSE types * update API; reimplement mock client implementations without internal BinaryData enumerable * Add sync client result collection abstraction * tidy up and add tests * add default constructor to ClientResult * more tidy-up * rename and add refdocs * comments * pr fb * rework last event id and retry per BCL design shift * add CHANGELOG entry
* Add async and sync enumerable client results * Implement IAsyncDisposable * Remove constrant and disposable; update ClientResult so response can be replaced in a polling paradigm * rename and upate tests * initial addition of files from joseharriaga/openai-in-typespec#68 * make it build * hello world test * bootstrap more tests * more internal tests * adding enumerator tests; haven't figured out the batch piece yet * Make batch test pass * remove collection-event functionality and add tests for public type * reshuffle * Add mock convenience SSE type to give POC of lazy request sending * add tests of delayed request * Add BinaryData factory method * remove funcs for creating enumerators * renames * postpone call to protocol method from convenience APIs * implement IAsyncDisposable correctly * initial pass over cancellation token * Per FDG, throw OperationCanceledException if cancellation token is cancelled. * remove factory method taking Func<T> and provide example of layering convenience implementation in a way that postpones sending the request * rename internal types and WIP adding reader tests * nits * parameterize terminal event; TBD to provide virtual method on collection type * WIP: nits * WIP: added concatenation of data lines per SSE spec * updates and bug fixes * add tests and update per SSE spec * WIP: refactor to reuse field processing across sync and async methods * make look a little more like the BCL type proposal * simplify field implementation a bit * cosmetic reworking of creating an event from a pending event * Remove factory method from public API; move MockSseClient to Tests.Internal to access internal SSE types * update API; reimplement mock client implementations without internal BinaryData enumerable * Add sync client result collection abstraction * tidy up and add tests * add default constructor to ClientResult * more tidy-up * rename and add refdocs * comments * Add pageables * add ClientPage<T> * pageables implement enumerators * give page a response constructor * updates post merging main branch * Add hello world test for pageable collections * wip: tests * some API updates * make page non-abstract * add test for continuation token * add tests for async pageable * remove nonnull constraint from T on pageables * add comments to public types * thread through response updates * export API * update comments per pr fb * Expose factory method for creating ResultPage instead of constructor * update CHANGELOG * nit
No description provided.