agents
Version:
A home for your AI agents
234 lines (232 loc) • 9.12 kB
TypeScript
import { ChatTransport, UIMessage, UIMessageChunk } from "ai";
//#region src/chat/replay-dedupe.d.ts
/**
* Replay de-duplication for continuation streams (#1951).
*
* A continuation appends to an assistant message this client may already have
* rendered live. After a reconnect the server replays the continuation's
* whole buffer, and applying it on top of the live-rendered bytes would
* duplicate them. Every live and replayed chunk frame carries its index in
* the stream (`seq`), so a client that records how far it applied each
* stream can drop the replayed chunks it already has.
*
* Non-continuation replays are left alone: the client resets the message and
* rebuilds it from chunk 0 for those.
*/
type ChunkFrame = {
body?: string;
continuation?: boolean;
replay?: boolean;
seq?: number;
};
/** Highest chunk `seq` this client applied, per request id. */
declare class AppliedChunkLedger {
private readonly applied;
record(requestId: string, seq: number | undefined): void;
/** Whether `frame` replays a continuation chunk this client already applied. */
isAppliedReplay(requestId: string, frame: ChunkFrame): boolean;
forget(requestId: string): void;
clear(): void;
}
//#endregion
//#region src/chat/ws-chat-transport.d.ts
/**
* Agent-like interface for sending/receiving WebSocket messages.
* Matches `AgentClient` from `agents/client` and the connection returned by
* `useAgent` from `agents/react`.
*/
interface AgentConnection {
send: (data: string) => boolean | void;
addEventListener: (
type: string,
listener: (event: MessageEvent) => void,
options?: {
signal?: AbortSignal;
}
) => void;
removeEventListener: (
type: string,
listener: (event: MessageEvent) => void
) => void;
}
type WebSocketChatTransportOptions<ChatMessage extends UIMessage = UIMessage> =
{
/** The framework-neutral AgentClient or useAgent connection. */ agent: AgentConnection;
/**
* Callback to add custom fields to the request body before sending.
*/
prepareBody?: (options: {
messages: ChatMessage[];
trigger: "submit-message" | "regenerate-message";
messageId?: string;
}) => Promise<Record<string, unknown>> | Record<string, unknown>;
/**
* Optional set to track active request IDs.
* IDs are added when a request starts and removed when it completes.
* Used by the onAgentMessage handler to skip messages already handled by the transport.
*/
activeRequestIds?: Set<string>;
/**
* Whether generic client-side abort/cancel lifecycle should cancel the
* server turn. Explicit cancellation via cancelActiveServerTurn() always
* sends CF_AGENT_CHAT_REQUEST_CANCEL.
* @default false
*/
cancelOnClientAbort?: boolean;
/**
* Called when a `submit-message` request frame was buffered rather than sent
* immediately (the socket was not OPEN, so PartySocket queued it for the next
* reconnect). The hook uses this to preserve the optimistic message across the
* reconnect transcript replay. `messageId` is the submitted user message's id.
*/
onRequestBuffered?: (messageId: string | undefined) => void;
};
/**
* ChatTransport that sends messages over WebSocket and returns a
* ReadableStream<UIMessageChunk> that the AI SDK's useChat consumes directly.
*
* This low-level transport handles new and regenerated request streams plus
* cancellation. Higher-level protocol coordination such as automatic reconnect
* resume, cross-tab transcript synchronization, and client-tool continuations
* is provided by integrations such as `useAgentChat`.
*/
declare class WebSocketChatTransport<
ChatMessage extends UIMessage = UIMessage
> implements ChatTransport<ChatMessage> {
agent: AgentConnection;
private prepareBody?;
private activeRequestIds?;
private cancelOnClientAbort;
private onRequestBuffered?;
private _resumeResolver;
/**
* Continuation chunks this client applied, shared with the hook's fallback
* observer so a replay after reconnect skips them on either path (#1951).
*/
readonly appliedChunks: AppliedChunkLedger;
private _resumeNoneResolver;
private _onStreamPending;
private _retryResumeProbe;
private _expectToolContinuation;
private _abortToolContinuation;
private _activeServerTurnId;
private _cancelAttachedStream;
private _detachResumeStream;
constructor(options: WebSocketChatTransportOptions<ChatMessage>);
/**
* Point the singleton transport at a new Agent connection. A pending resolver
* belongs to the old Chat/socket generation and must settle before messages
* from the replacement connection can be consumed (#1914 review).
*/
setAgent(agent: AgentConnection): void;
setCancelOnClientAbort(cancelOnClientAbort: boolean): void;
/**
* Explicitly cancel the active server turn, if any.
* This is separate from generic client-side abort/cancel lifecycle so
* clients can detach locally without stopping server work.
*/
cancelActiveServerTurn(): boolean;
/**
* The server turn this transport last attached to that has not reported a
* terminal frame. A socket close ends the local stream but keeps this set,
* since the server keeps running the turn.
*/
get activeServerTurnId(): string | null;
private sendCancelFrame;
private setActiveServerTurn;
private clearActiveServerTurn;
/**
* Mark that the next reconnectToStream() call should attach to a
* server-initiated tool continuation rather than a page-load resume.
*/
expectToolContinuation(): void;
/**
* Abort the active client-side tool continuation stream, if one is attached
* to a server request id.
*/
abortActiveToolContinuation(): boolean;
/**
* True when the transport is waiting for a resume handshake.
*/
isAwaitingResume(): boolean;
/**
* Settle and detach the current handshake without interpreting it as a
* server-idle response. Used when the owning hook/agent generation changes.
*/
cancelPendingResume(): boolean;
/**
* Invalidate all client-side resume state for an obsolete hook/agent
* generation without cancelling its durable server turn.
*/
resetResumeState(): void;
/**
* Re-send the active handshake request on the latest socket generation. This
* preserves one AI SDK resume operation while recovering a request/reply lost
* with the previous WebSocket.
*/
retryPendingResume(): boolean;
/**
* Called by onAgentMessage when it receives CF_AGENT_STREAM_RESUMING.
* If reconnectToStream is waiting, this handles the resume handshake
* (ACK + stream creation) and returns true. Otherwise returns false
* so the caller can use its own fallback path.
*/
handleStreamResuming(data: { id: string }): boolean;
/**
* Called by onAgentMessage when it receives CF_AGENT_STREAM_RESUME_NONE.
* If reconnectToStream is waiting, resolves the promise with null
* immediately (no 5-second timeout). Returns true if handled.
*/
handleStreamResumeNone(data?: { probeId?: string }): boolean;
/**
* Called by onAgentMessage when it receives CF_AGENT_STREAM_PENDING (#1784):
* the server accepted a turn but its stream has not started yet. If a resume
* path is awaiting, extend its probe timeout (so it keeps waiting for the
* eventual STREAM_RESUMING / STREAM_RESUME_NONE instead of resolving null
* after the short window). Returns true if a waiting path consumed it.
*/
handleStreamPending(): boolean;
/**
* Called by the hook's shared message handler when a server turn finishes
* outside the currently attached transport stream, such as after local-only
* client cleanup.
*/
handleServerTurnCompleted(requestId: string): void;
/**
* Register a server turn that is being rendered outside a transport-owned
* stream, such as the hook's fallback cross-tab/resume observer path.
*/
observeServerTurn(requestId: string): void;
sendMessages(options: {
chatId: string;
messages: ChatMessage[];
abortSignal: AbortSignal | undefined;
trigger: "submit-message" | "regenerate-message";
messageId?: string;
body?: object;
headers?: Record<string, string> | Headers;
metadata?: unknown;
}): Promise<ReadableStream<UIMessageChunk>>;
reconnectToStream(_options: {
chatId: string;
}): Promise<ReadableStream<UIMessageChunk> | null>;
/**
* Creates a deferred ReadableStream for client-side tool continuations.
* The stream is returned immediately so AI SDK status becomes "submitted"
* right after addToolOutput()/addToolApprovalResponse(), then it waits for
* the server to announce the continuation via STREAM_RESUMING.
*/
private _createToolContinuationStream;
/**
* Creates a ReadableStream that receives resumed stream chunks
* and forwards them to useChat as UIMessageChunk objects.
*/
private _createResumeStream;
}
//#endregion
export {
WebSocketChatTransport as n,
WebSocketChatTransportOptions as r,
AgentConnection as t
};
//# sourceMappingURL=ws-chat-transport-BbT1A5Lc.d.ts.map