1
>
/*---------------------------------------------------------------------------------------------
chatStreamStats.ts
2
>
* Copyright (c) Microsoft Corporation. All rights reserved.
3
>
* Licensed under the MIT License. See License.txt in the project root for license information.
4
>
*--------------------------------------------------------------------------------------------*/
5
>
6
>
import { ILogService } from '../../../../../platform/log/common/log.js';
7
>
8
>
export interface IChatStreamStats {
9
>
impliedWordLoadRate: number;
10
>
lastWordCount: number;
11
>
}
12
>
13
>
export interface IChatStreamStatsInternal extends IChatStreamStats {
14
>
totalTime: number;
15
>
lastUpdateTime: number;
16
>
firstMarkdownTime: number | undefined;
17
>
bootstrapActive: boolean;
18
>
wordCountAtBootstrapExit: number | undefined;
19
>
updatesWithNewWords: number;
20
>
}
21
>
22
>
export interface IChatStreamUpdate {
23
>
totalWordCount: number;
24
>
}
25
>
26
>
const MIN_BOOTSTRAP_TOTAL_TIME = 250;
27
>
const LARGE_BOOTSTRAP_MIN_TOTAL_TIME = 500;
28
>
const MAX_INTERVAL_TIME = 250;
29
>
const LARGE_UPDATE_MAX_INTERVAL_TIME = 1000;
30
>
const WORDS_FOR_LARGE_CHUNK = 10;
31
>
const MIN_UPDATES_FOR_STABLE_RATE = 2;
32
>
33
>
/**
34
>
* Estimates the loading rate of a chat response stream so that we can try to match the rendering rate to
35
>
* the rate at which text is actually produced by the model. This can only be an estimate for various reasons-
36
>
* reasoning summaries don't represent real generated tokens, we don't have full visibility into tool calls,
37
>
* some model providers send text in large chunks rather than a steady stream, e.g. Gemini, we don't know about
38
>
* latency between agent requests, etc.
39
>
*
40
>
* When the first text is received, we don't know how long it actually took to generate. So we apply an assumed
41
>
* minimum time, until we have received enough data to make a stable estimate. This is the "bootstrap" phase.
42
>
*
43
>
* Since we don't have visibility into when the model started generated tool call args, or when the client was running
44
>
* a tool, we ignore long pauses. The ignore period is longer for large chunks, since those naturally take longer
45
>
* to generate anyway.
46
>
*
47
>
* After that, the word load rate is estimated using the words received since the end of the bootstrap phase.
48
>
*/
49
>
export class ChatStreamStatsTracker {
50
>
private _data: IChatStreamStatsInternal;
51
>
private _publicData: IChatStreamStats;
52
>
53
>
constructor(
54
@ILogService private readonly logService: ILogService
55
) {