-
-
Notifications
You must be signed in to change notification settings - Fork 490
Added accumulator response parts and utils to accumulate from stream and normal response parts #5674
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
base: main
Are you sure you want to change the base?
Added accumulator response parts and utils to accumulate from stream and normal response parts #5674
Conversation
added rough documentation added changeset
🦋 Changeset detectedLatest commit: aee4a16 The changes in this PR will be included in the next version bump. This PR includes changesets to release 6 packages
Not sure what this means? Click here to learn what changesets are. Click here if you're a maintainer who wants to add another changeset to this PR |
|
@MrGeniusProgrammer - what is the concrete use case for this? Can you provide an example of how you would use it? |
|
This is valuable to display a UI streaming part for the frontend where accumulated parts are more suited as it is necessary to get the status of the streaming part (are they finished? did it error? did the tool started streaming in?). // rpcClient("ChatGenerate") returns a Stream.Stream<Response.StreamPart[]>
rpcClient("ChatGenerate").pipe(
// throttle the streaming response to not aggresively update the UI
Stream.throttle({
cost: Chunk.size,
duration: "250 millis",
units: 32
}),
// accumulate the stream parts
Stream.scanEffect([], Response.accumulateStreamParts),
// create a UI Assistant message with the accumulated parts
Stream.map((accumulatedParts) =>
UiAssistantMessage.make({
role: "assistant",
content: accumulatedParts
})
)
); |
|
Gotcha ok - that makes sense. Would you be willing to add some test cases to cover these new methods? I'm trying to be more diligent about testing in the AI packages now as I add new functionality. |
…g from stream or normal parts to accumulated parts
…malformed', and 'params-streaming'
|
@IMax153 I believe discussing whether to accumulate parts based on window or by id is needed. As of right now, the current implementation goes with the former for the text and reasoning part and latter for the tool part. For example, |
|
I think, in general, we should accumulate parts based upon ID given that most providers give that information to us as a "stable" way to identify linked parts. Regarding state -> status, I like status I think more. |
|
Sorry for being late (I was sick). I have implemented the suggested changes. Do you mind going through them? |
|
@IMax153 let me know if there are any changes that needs to be implemented? |
| })) | ||
| break | ||
| } | ||
| case "tool": { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Do we really need to add these new parts to the AnyPart interface? To me, it feels like these new parts are more of a utility thing, where you have a streaming response coming in and want to convert between the actual wire format and this new "accumulated" format.
I am thinking it is desirable to keep the two separated. What are your thoughts? Are there use cases I'm not considering here?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The reason mostly stems from convenience. The accumulated parts can be created with makePart and converted to Prompt. But I believe an exposed API for creating these accumulated parts manually would be beneficial.
Another case is that one accumulated part retains the same amount of data as one or more streaming or non-streaming parts.
makePart("text-accumulated", {
text: "Hello, World!",
status: "done",
id: "1",
})
// can be represented in normal form
makePart("text", {
text: "Hello, World!"
})
// or to streaming form as an array
[
makePart("text-start", {
id: "1",
}),
makePart("text-delta", {
id: "1",
delta: "Hello World!",
}),
makePart("text-done", {
id: "1",
})
]This raises the potential use case to convert from accumulated parts to wire parts, streaming or non-streaming parts. For instance, publishing accumulated parts to the Redis pub/sub rather than an array of streaming parts keeps storage low and decreases latency.
Type
Description
This pull request adds 3 new ai response parts--
TextAccumulatedPart,ReasoningAccumulatedPart, andToolPart--and utilities to convert from streaming and normal parts to accumulated parts.TextAccumulatedPart: same asTextPartbut withstatefield representing either"streaming"or"done"ReasoningAccumulatedPart: same asReasoningPartbut withstatefield representing either"streaming"or"done"ToolPartcombines all of the other tool parts into one part, keeping each previous context, and distinguish each state by theirvalue.statefield, where it holds values such as:"params-start": when params are started to streaming in"params-streaming": when params are streaming in"params-malformed": when params are malformed"params-done": when params are done streaming"result-error": when the tool returned an error result"result-done": when the tool call result is returnedThese all accumulated parts and other necessary parts are represented by
AccumulatedPart.utilities:
mergeAccumulatedParts: merges two accumulated parts into one accumulated partsaccumulateParts: accumulate over normal parts given already existing accumulated partsaccumulateStreamParts: accumulate over stream parts given already existing accumulated partsRelated