/** * Per-Teams-message streamed-by-edit state machine. * * Teams' baseline streaming model (the one the M365 Agents Playground and the * Bot Framework connector support without native token streaming) is * **post-then-edit**: send one message activity, then `updateActivity` it as the * text grows. This wraps a single such message and lets a caller feed it the * growing buffer of a streaming reply. * * Edits are throttled (Teams rate-limits activity updates) and *serialised* * through a per-message promise queue so an in-flight edit of "AL" can't be * overtaken by a later edit of "ALPHA" and leave the message reading "AL". * * Nothing here knows about AG-UI or the M365 SDK. It's a pure primitive: * "give me text, I'll keep one Teams message in sync with it." The caller * supplies `post` (first send, returns the activity id), `update` (subsequent * edits), and an optional `typing` hook fired once before the first post. */ export interface TeamsMessageStreamConfig { /** First send. Returns the posted activity id (used for later edits). */ post: (text: string) => Promise; /** Edit the posted activity to `text`. */ update: (id: string, text: string) => Promise; /** Send the final edit through a priority transport lane. */ finalize?: (id: string, text: string) => Promise; /** Optional: fire a typing indicator once, before the first post. */ typing?: () => Promise; /** Minimum gap between consecutive flushes, in ms (defaults to 700). */ minIntervalMs?: number; } export declare class TeamsMessageStream { private buffer; private posted; private id; private queue; private lastFlushedAt; private flushTimer; private readonly minIntervalMs; private readonly config; constructor(config: TeamsMessageStreamConfig); /** Replace the in-flight buffer (callers pass the accumulated text). */ append(text: string): void; /** * Mark the stream done: cancel any pending throttled flush, drain the in-flight * queue, then perform the FINAL send fail-loud. The posted activity then * reflects the final buffer. Returns the activity id (or `undefined` if nothing * was ever posted, e.g. an empty stream). * * Unlike the throttled mid-stream flushes (which tolerate a dropped edit and * retry on the next append), the final send **rejects** if the transport call * fails: the buffer was never delivered, so the caller must be able to * fail/retry the turn rather than silently mark it "sent". */ finish(): Promise; private scheduleFlush; private enqueueFlush; /** * Send the latest buffer: first send via `post` (capturing the activity id), * subsequent sends via `update`. `posted` is advanced only AFTER the transport * call succeeds, so a throw leaves it unchanged and the next (or final) flush * retries the same buffer. Throws on transport failure — callers decide whether * to tolerate (mid-stream) or propagate (final). */ private doSend; /** Throttled mid-stream flush: tolerate a dropped edit (log + retry later). */ private flushNow; /** Final flush at {@link finish}: propagate a transport failure fail-loud. */ private flushFinal; } //# sourceMappingURL=message-stream.d.ts.map