rig icon indicating copy to clipboard operation
rig copied to clipboard

feat: Re-think streaming events

Open Sytten opened this issue 1 month ago • 1 comments

  • [x] I have looked for existing issues (including closed) about this

Feature Request

I think we should completely re-think events and use the model provided by the Vercel AI SDK:

type LanguageModelV2StreamPart = {
    type: 'text-start';
    providerMetadata?: SharedV2ProviderMetadata;
    id: string;
} | {
    type: 'text-delta';
    id: string;
    providerMetadata?: SharedV2ProviderMetadata;
    delta: string;
} | {
    type: 'text-end';
    providerMetadata?: SharedV2ProviderMetadata;
    id: string;
} | {
    type: 'reasoning-start';
    providerMetadata?: SharedV2ProviderMetadata;
    id: string;
} | {
    type: 'reasoning-delta';
    id: string;
    providerMetadata?: SharedV2ProviderMetadata;
    delta: string;
} | {
    type: 'reasoning-end';
    id: string;
    providerMetadata?: SharedV2ProviderMetadata;
} | {
    type: 'tool-input-start';
    id: string;
    toolName: string;
    providerMetadata?: SharedV2ProviderMetadata;
    providerExecuted?: boolean;
} | {
    type: 'tool-input-delta';
    id: string;
    delta: string;
    providerMetadata?: SharedV2ProviderMetadata;
} | {
    type: 'tool-input-end';
    id: string;
    providerMetadata?: SharedV2ProviderMetadata;
} | LanguageModelV2ToolCall | LanguageModelV2ToolResult | LanguageModelV2File | LanguageModelV2Source | {
    type: 'stream-start';
    warnings: Array<LanguageModelV2CallWarning>;
} | ({
    type: 'response-metadata';
} & LanguageModelV2ResponseMetadata) | {
    type: 'finish';
    usage: LanguageModelV2Usage;
    finishReason: LanguageModelV2FinishReason;
    providerMetadata?: SharedV2ProviderMetadata;
} | {
    type: 'raw';
    rawValue: unknown;
} | {
    type: 'error';
    error: unknown;
};

Motivation

Right now different providers behave differently, some will send a final message like anthropic with the full content. This is because the events have historically been used in different context. It is also very unclear if an event Text is the whole previous text or just the new delta. IMO it should just be the delta. We can create an accumulation abstraction but it should not be the default.

Proposal

I propose we refactor the enum of streaming event to something like:

#[derive(Debug, Clone)]
pub enum RawStreamingChoice<R>
where
    R: Clone,
{
    TextStart { ... },
    TextDelta { ... },
    TextEnd { ... },
    ReasoningStart { ... },
    ReasoningDelta { ... },
    ReasoningEnd { ... },
    ...
}

Alternatives

Sytten avatar Nov 15 '25 17:11 Sytten

RIG-1043

linear[bot] avatar Nov 15 '25 17:11 linear[bot]