Bug in type definition for `TextStreamPart`
Description
The TextStreamPart is a union type of many possible things, including "tool-result". However, when asking TypeScript for the list of possible types of the type field, the "tool-result" does not seem to be included if you do not provide a specific/custom ToolSet type param:
The reason for this is this part of the definition:
export type TextStreamPart<TOOLS extends ToolSet> =
| ...
| ({
type: 'tool-result';
} & ToolResultUnion<TOOLS>)
| ...
This expression: ToolResultUnion<ToolSet> (i.e. when not not providing a specific/typed tool set), evaluates to never, and therefore the intersection with { type: "tool-result" } will also be never.
Possible fix?
A possible fix might be to catch this never case, and return a "generic" shape that is slightly wider (less useful), but at the very least still informative about what fields are available on every tool-result part, i.e.
// 1️⃣ Renamed ToolResultUnion → ToolResultUnionOrNever
type ToolResultUnionOrNever<TOOLS extends ToolSet> = ToToolResultObject<ToToolsWithDefinedExecute<ToToolsWithExecute<TOOLS>>>;
// 2️⃣ Redefine ToolResultUnion to check if ToolResultUnionOrNever is
// never (ie if a specific ToolSet param was not provided), and if so,
// still return a wider type that's still accurate
type ToolResultUnion<TOOLS extends ToolSet> =
[ToolResultUnionOrNever<TOOLS>] extends [never]
? {
type: 'tool-result';
toolCallId: string;
toolName: string;
args: unknown;
result: unknown;
}
: ToolResultUnionOrNever<TOOLS>;
This would at least make the "tool-result" type visible to TypeScript again when handling all possible cases.
Is this on main?
Yes, this seems to be an issue on main.
I ran into this problem a few days ago too. I solved it by given it the ToolSet definition.
Do you mean like how I did it in the screenshot above? That's what I'm doing as well, but it isn't working unfortunately. It works for every case, except "tool-result".
The reason it doesn't work is because of this definition:
type ToolResultUnion<TOOLS extends ToolSet> =
ToToolResultObject<ToToolsWithDefinedExecute<ToToolsWithExecute<TOOLS>>>
Let's put in ToolSet for the TOOLS param:
ToToolsWithExecute<ToolSet>(evaluates to) →{}ToToolsWithDefinedExecute<{}>→{}ToToolResultObject<{}>→never(*)
And therefore:
{ type: "tool-result" } & never→never
And that's why "tool-result" is not part of the union of string literals above.
The issue is here (*). Ideally ToToolResultObject<{}> would return some generic "tool-result" structure, instead of never.
We have changed the inference in the v5 branch a week or so ago. Can you see if this happens on v5 canary releases as well?
I can confirm that we no longer see this issue on 5.0.29.