diff --git a/packages/ai/src/api/lazy.ts b/packages/ai/src/api/lazy.ts index 2f9cf0a35..33ca2ac25 100644 --- a/packages/ai/src/api/lazy.ts +++ b/packages/ai/src/api/lazy.ts @@ -47,12 +47,13 @@ export function lazyStream( model: Model, setup: () => Promise>, ): AssistantMessageEventStream { + const startedAt = Date.now(); const outer = new AssistantMessageEventStream(); setup() .then((inner) => forwardStream(outer, inner)) .catch((error) => { - const message = createSetupErrorMessage(model, error, outer.startedAt); + const message = createSetupErrorMessage(model, error, startedAt); outer.push({ type: "error", reason: "error", error: message }); outer.end(message); }); diff --git a/packages/ai/src/utils/event-stream.ts b/packages/ai/src/utils/event-stream.ts index 669deeaf3..83faa6f63 100644 --- a/packages/ai/src/utils/event-stream.ts +++ b/packages/ai/src/utils/event-stream.ts @@ -88,6 +88,9 @@ export class EventStream implements AsyncIterable { } } +/** Start of each assistant stream, kept outside the class so it stays structurally a plain `EventStream`. */ +const streamStarts = new WeakMap(); + /** * Event stream of one assistant response. It also times the response: the final message (`done` or `error` event, or * the result passed to `end()`) gets `durationMs`, measured with a monotonic clock from the stream's creation, unless @@ -95,9 +98,6 @@ export class EventStream implements AsyncIterable { * elsewhere, such as a deferred result fetched later, therefore leaves it untimed. */ export class AssistantMessageEventStream extends EventStream { - readonly #startedAt = Date.now(); - readonly #startedAtMonotonic = performance.now(); - constructor() { super( (event) => event.type === "done" || event.type === "error", @@ -110,28 +110,25 @@ export class AssistantMessageEventStream extends EventStream