@d-id/client-sdk 3.0.3 → 3.0.4
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/{index-D3V0poNL.js → index-Bg-Bdzun.js} +6 -6
- package/dist/index-Bg-Bdzun.js.map +1 -0
- package/dist/index.d.ts +6 -5
- package/dist/index.js +1 -1
- package/dist/index.umd.cjs +1 -1
- package/dist/{livekit-manager-CWngBsPu.js → livekit-manager-X_uL-Mz1.js} +2 -2
- package/dist/{livekit-manager-CWngBsPu.js.map → livekit-manager-X_uL-Mz1.js.map} +1 -1
- package/package.json +1 -1
- package/dist/index-D3V0poNL.js.map +0 -1
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index-Bg-Bdzun.js","sources":["../src/types/stream/data-channel.ts","../src/types/entities/agents/chat.ts","../src/types/entities/agents/manager.ts","../src/types/entities/avatar.ts","../src/types/stream/stream.ts","../src/types/stream/streams-v2.ts","../src/types/voice/tts.ts","../src/utils/index.ts","../src/auth/get-auth-header.ts","../src/config/consts.ts","../src/config/environment.ts","../src/errors/base-error.ts","../src/errors/chat/chat-creation-failed.ts","../src/errors/chat/chat-mode-downgraded.ts","../src/errors/http-error.ts","../src/errors/network-error.ts","../src/errors/stream-error.ts","../src/errors/validation-error.ts","../src/errors/ws-error.ts","../src/utils/agent.ts","../src/utils/chat.ts","../src/utils/content-parser.ts","../src/utils/retry-operation.ts","../src/api/apiClient.ts","../src/api/agents.ts","../src/utils/analytics.ts","../src/utils/defer.ts","../src/utils/error-analytics.ts","../src/version.ts","../src/services/analytics/mixpanel.ts","../src/services/analytics/timestamp-tracker.ts","../src/services/chat/index.ts","../src/services/chat/intial-messages.ts","../src/services/socket-manager/index.ts","../src/utils/stream-end.ts","../src/services/socket-manager/message-queue.ts","../src/api/streams/streamApi.ts","../src/services/streaming-manager/common.ts","../src/services/streaming-manager/stats/av-sync.ts","../src/services/streaming-manager/stats/report.ts","../src/services/streaming-manager/stats/poll.ts","../src/services/streaming-manager/webrtc-manager.ts","../src/services/streaming-manager/factory.ts","../src/services/agent-manager/connect-to-manager.ts","../src/services/agent-manager/index.ts","../src/utils/tool-calls.ts"],"sourcesContent":["/**\n * Data-channel topics messages can be sent on.\n * V2 (LiveKit) routes by topic; V1 (WebRTC) has no topic concept and ignores it.\n *\n * Internal on purpose: this module is deliberately left out of the `stream`\n * barrel so the topics driven by dedicated methods (`chat`, `speak`,\n * `interrupt`, `setSttLanguage`) never reach the package's public API.\n * Customers get the public `DataChannelTopic` enum instead.\n */\nexport enum InternalDataChannelTopic {\n Chat = 'lk.chat',\n Speak = 'did.speak',\n Interrupt = 'did.interrupt',\n SttLanguage = 'did.stt-language',\n Presentation = 'did.presentation',\n}\n","/**\n * A rating stored against one message of a chat, as the Agents API returns it.\n *\n * Produced by {@link AgentManager.rate | rate()} and returned again by\n * {@link AgentManager.deleteRate | deleteRate()}. Keep {@link Rating.id | id} if the user may\n * change their mind: pass it back to {@link AgentManager.rate | rate()} as `rateId` to update the\n * rating, or to {@link AgentManager.deleteRate | deleteRate()} to remove it.\n *\n * @category Chat\n */\nexport interface Rating {\n /**\n * Id of this rating.\n *\n * Pass it as the `rateId` argument of {@link AgentManager.rate | rate()} to update the rating,\n * or to {@link AgentManager.deleteRate | deleteRate()} to remove it.\n */\n id: string;\n /** Id of the D-ID account that owns the agent the rating was left on. Set by the Agents API. */\n owner_id: string;\n /** Id of the agent whose answer was rated. */\n agent_id: string;\n /**\n * The knowledge citations that were attached to the rated answer, as `[document_id, id]` pairs.\n *\n * The SDK builds them from the {@link Message.matches | matches} of the rated message, so a\n * negative rating can be traced back to the documents the answer was drawn from. Empty when the\n * answer cited nothing.\n */\n matches: [string, string][];\n /**\n * Id of the agent's knowledge base ({@link Agent.knowledge}) at the time of the rating.\n *\n * An empty string when the agent has no knowledge base.\n */\n knowledge_id: string;\n /**\n * The end-user identifier the Agents API recorded for the request.\n *\n * Derived from the credentials the SDK sends, which carry\n * {@link AgentManagerOptions.externalId | externalId} for `type: 'key'` authorization.\n */\n external_id: string;\n /** Identity the Agents API attributed the rating to. Set by the Agents API. */\n created_by: string;\n /** Id of the chat the rated message belongs to — the value\n * {@link AgentManagerCallbacks.onNewChat | onNewChat} reported. */\n chat_id: string;\n /** The score itself: `1` for a positive rating, `-1` for a negative one. */\n score: 1 | -1;\n /** When the rating was created, as an ISO 8601 timestamp. */\n created_at: string;\n /** When the rating was last changed, as an ISO 8601 timestamp. */\n modified_at: string;\n /** {@link Message.id | Id of the message} that was rated. */\n message_id: string;\n}\n\n/**\n * Request payload for rating a chat message, derived from `Rating`.\n * @internal Implementation type; not part of the public SDK surface.\n */\nexport type RatingPayload = Omit<\n Rating,\n 'owner_id' | 'id' | 'created_at' | 'modified_at' | 'created_by' | 'external_id' | 'agent_id' | 'chat_id'\n>;\n\n/**\n * What the Agents API stored when end-of-call feedback was submitted.\n *\n * Returned by {@link AgentManager.submitFeedback | submitFeedback()}, which rates the conversation\n * as a whole rather than a single answer.\n *\n * @category Chat\n */\nexport interface SubmitFeedbackResponse {\n /** Id of the chat the feedback belongs to — the value\n * {@link AgentManagerCallbacks.onNewChat | onNewChat} reported. */\n chat_id: string;\n /** The score that was submitted, on the agent's end-of-call scale of 1 to 5. */\n rating: number;\n /**\n * The follow-up question the user was asked, when one was recorded.\n *\n * Applications pick it from {@link EndOfCallFeedbackConfig.follow_up_messages}.\n */\n question_shown?: string;\n /** When the feedback was stored, as an ISO 8601 timestamp. */\n submitted_at: string;\n}\n\n/**\n * One renderable piece of a message: a run of text, an image, a video or a link.\n *\n * {@link parseMessageParts} splits a message's {@link Message.content | content} into these, and\n * the SDK keeps the result on {@link Message.parts}. Switch on `type` when rendering. Anything the\n * parser did not recognize is preserved verbatim as a `text` part, in its original order, and\n * nothing is dropped or reordered; a recognized image, video or link replaces the markup it was\n * written as, so the parts are not a concatenation of the original string.\n *\n * @category Chat\n */\nexport type MessagePart =\n | {\n /** Discriminant: plain text that the parser found no markup in. */\n type: 'text';\n /** The text itself, exactly as it appeared in {@link Message.content}. */\n text: string;\n }\n | {\n /** Discriminant: an image, from markdown image syntax such as ``. */\n type: 'image';\n /** URL of the image. */\n src: string;\n /** The alt text from the markdown, or an empty string when it had none. */\n alt: string;\n /**\n * `image/gif` when the URL itself ends in `.gif`, ignoring case; absent otherwise.\n *\n * The check looks at the whole URL, so a query string or fragment suppresses it —\n * `cat.gif?v=2` carries no `mimeType`. Video detection differs: it strips both before\n * looking at the extension.\n */\n mimeType?: string;\n }\n | {\n /**\n * Discriminant: a video, either from thumbnail syntax (`[](video)`) or from\n * an image whose URL ends in `.mp4`, `.webm`, `.mkv`, `.mov`, `.m4v` or `.ogv` once any\n * query string and fragment have been stripped.\n */\n type: 'video';\n /** URL of the video file. */\n src: string;\n /** The alt text from the markdown, or an empty string when it had none. */\n alt: string;\n /** URL of the poster image, when the thumbnail syntax supplied one. */\n thumbnail?: string;\n }\n | {\n /** Discriminant: a link, from markdown `[label](url)` or from an HTML `<a href>`. */\n type: 'link';\n /** Target of the link. */\n href: string;\n /** The text shown for the link. */\n label: string;\n };\n\n/**\n * One message of a chat: what the user asked, or what the agent answered.\n *\n * The SDK keeps the whole transcript and hands a fresh copy of it to\n * {@link AgentManagerCallbacks.onNewMessage | onNewMessage} every time a message is added or\n * changed, oldest first. While an answer streams in, the last message's\n * {@link Message.content | content} and {@link Message.parts | parts} are replaced with the latest\n * text on each `partial` callback — not appended to — and are final on `answer`. The same shape is\n * accepted by {@link AgentManagerOptions.initialMessages | initialMessages} to seed a transcript.\n *\n * @category Chat\n */\nexport interface Message {\n /**\n * Id of this message.\n *\n * Pass it to {@link AgentManager.rate | rate()} to rate the answer. The SDK generates a random\n * id for the messages it creates locally, and uses the id sent with the message for those that\n * arrive from the agent.\n */\n id: string;\n /**\n * Who the message is from.\n *\n * The SDK itself only creates `user` (the end user) and `assistant` (the agent) messages; the\n * value on a transcribed or streamed message is whatever the server payload carried. `system`,\n * `function` and `tool` exist because the underlying chat protocol allows them.\n */\n role?: 'system' | 'assistant' | 'user' | 'function' | 'tool';\n /**\n * The message text.\n *\n * Plain text, which for agent answers may contain markdown. It is replaced by the latest text\n * on every `partial` callback while the answer streams in — and the final `answer` may be\n * shorter than the partials before it, which is exactly how the SDK spots an interruption — so\n * render it as it is rather than appending to what you rendered before.\n */\n content: string;\n /**\n * {@link Message.content | content} split into renderable pieces by {@link parseMessageParts}.\n *\n * Kept in step with `content` on every message the SDK creates, including while an answer\n * streams in. Render these instead of the raw string when the agent may answer with images,\n * videos or links; a message with no markup is a single `text` part, and an empty message is\n * an empty array.\n *\n * Optional because {@link AgentManagerOptions.initialMessages | initialMessages} take the same\n * shape, and a transcript restored from your own storage carries only the text: leave `parts`\n * out and the SDK runs the parser over `content` before the message reaches the transcript. A\n * non-empty array you built yourself is kept exactly as given. Every message the SDK delivers\n * through {@link AgentManagerCallbacks.onNewMessage | onNewMessage} has it set, seeded\n * `initialMessages` included, so a handler can read it without a guard.\n */\n parts?: MessagePart[];\n /**\n * When the message was added, as an ISO 8601 timestamp.\n *\n * Optional for the same reason as {@link Message.parts | parts} — a restored transcript need\n * not carry one — but set on every message the SDK builds itself, which is every message that\n * reaches {@link AgentManagerCallbacks.onNewMessage | onNewMessage} other than a seeded\n * {@link AgentManagerOptions.initialMessages | initialMessage} that arrived without one.\n */\n createdAt?: string;\n /**\n * The knowledge citations the answer was drawn from, as {@link RetrievalMetadata} entries.\n *\n * Present on an agent answer when the chat response carried them, so a UI can show its sources;\n * {@link AgentManager.rate | rate()} also sends them with a rating. The SDK strips this field\n * from the transcript it sends back to the Agents API with the next\n * {@link AgentManager.chat | chat()}.\n */\n matches?: ChatResponse['matches'];\n /**\n * The retrieved context the answer was generated from, as\n * {@link ChatResponse.context | the chat response} supplied it.\n *\n * Only ever set on an agent answer, and only when the answer came back from the Agents API.\n * Expressive (V4) agents chat over the data channel instead, so their answers carry no context\n * — except in {@link ChatMode.Playground}, which always takes the Agents API path.\n */\n context?: string;\n /**\n * `true` when the answer was cut short instead of being spoken to the end.\n *\n * Set on the last message by {@link AgentManager.interrupt | interrupt()}, and by the SDK when\n * the final answer turns out to be shorter than the partial text already received — which is\n * how it detects that the agent was interrupted mid-utterance.\n */\n interrupted?: boolean;\n /**\n * `true` when this user message came from speech-to-text rather than from\n * {@link AgentManager.chat | chat()}.\n *\n * It is what distinguishes an utterance the user spoke from one they typed.\n */\n transcribed?: boolean;\n /**\n * The sentiment the agent delivered this answer with, when the stream reported one.\n *\n * Taken from the metadata the server sends with the video it created, and attached to the most\n * recent agent answer. The SDK only ever fills it in from an Expressive (V4) session, and only\n * while {@link AgentManagerOptions.debug | debug} is enabled.\n */\n sentiment?: MessageSentiment;\n}\n\n/**\n * The sentiment an agent answer was delivered with, as the server reported it.\n *\n * The shape of {@link Message.sentiment}. It is an object rather than a string because the server\n * reports both the id of the sentiment it used and its name, where\n * {@link TextStreamScript.sentiment} — the sentiment the application *asks* for — is just the\n * name.\n *\n * @category Chat\n */\nexport interface MessageSentiment {\n /** Id of the sentiment, as the server sent it. */\n id: string;\n /** Name of the sentiment, as the server sent it. */\n name: string;\n}\n\n/**\n * A {@link Message} as the Agents API takes it in a chat request, which names the timestamp `created_at`.\n * @internal Wire type; not part of the public SDK surface.\n */\nexport type ChatPayloadMessage = Omit<Message, 'createdAt' | 'matches'> & { created_at: string };\n\n/**\n * Request payload for sending a chat message to the Agents API.\n * @internal Implementation type; not part of the public SDK surface.\n */\nexport interface ChatPayload {\n messages: ChatPayloadMessage[];\n streamId?: string;\n sessionId?: string;\n chatMode?: ChatMode;\n}\n\n/**\n * One knowledge citation: the passage of the agent's knowledge base an answer was drawn from.\n *\n * The Agents API returns these with an answer and the SDK keeps them on\n * {@link Message.matches | matches}, so a UI can show the sources behind a reply.\n *\n * @category Chat\n */\nexport interface RetrievalMetadata {\n /** Id of this match. Sent back with a rating as the second half of a\n * {@link Rating.matches} pair. */\n id: string;\n /** The matched passage itself, as stored in the knowledge base. */\n data: string;\n /** Title of the document the passage comes from. */\n title: string;\n /** Id of the source document. Sent back with a rating as the first half of a\n * {@link Rating.matches} pair. */\n document_id: string;\n /** Id of the knowledge base the document belongs to — the agent's {@link Agent.knowledge}. */\n knowledge_id: string;\n /** URL of the original source, for linking the citation out of the chat. */\n source_url: string;\n}\n\n/**\n * How the agent answers: with a streamed video, as text only, or not at all.\n *\n * Chosen with {@link AgentManagerOptions.mode | mode} and changed later with\n * {@link AgentManager.changeMode | changeMode()}, which reports the new value through\n * {@link AgentManagerCallbacks.onModeChange | onModeChange}. Switching to anything other than\n * {@link ChatMode.Functional} disconnects the stream, and switching *into*\n * {@link ChatMode.Functional} disconnects it too when the open session cannot carry a conversation\n * — call {@link AgentManager.connect | connect()} again after either.\n *\n * What the mode decides is narrower than it looks: whether a chat is created for the session, and\n * whether {@link AgentManager.connect | connect()} opens the notifications web socket — which is\n * exactly why a session built for one mode may not serve another. The video stream is established\n * in every mode, and every guard reads the mode the session is in at the time of the call, not the\n * one {@link createAgentManager} was given.\n *\n * The server can also answer with a different mode than the one asked for when the chat is created;\n * the SDK then adopts it and reports a {@link ChatModeDowngraded} error through\n * {@link AgentManagerCallbacks.onError | onError}.\n *\n * @category Chat\n */\nexport enum ChatMode {\n /**\n * Chat and video: the agent answers questions with its own LLM, in a streamed video.\n *\n * The default when {@link AgentManagerOptions.mode | mode} is omitted, and the only mode a\n * session can be in while a stream is connected and chat is available at the same time:\n * {@link AgentManager.changeMode | changeMode()} to any other value disconnects the stream.\n */\n Functional = 'Functional',\n /**\n * Text answers only: the chat works over the Agents API, but no video is produced.\n *\n * A fallback the server sets, for example when the account is out of credits; the SDK adopts\n * it and reports it through {@link AgentManagerCallbacks.onModeChange | onModeChange}. Talks\n * (V2) and Clips (V3) agents only.\n */\n TextOnly = 'TextOnly',\n /**\n * The agent is unavailable: {@link AgentManager.chat | chat()} throws a\n * {@link ValidationError}.\n *\n * The SDK switches to it by itself when connecting fails after its retries, so a UI can show\n * that the agent is temporarily out of service; the server can also return it when a chat is\n * created. Like {@link ChatMode.TextOnly} it produces no video.\n */\n Maintenance = 'Maintenance',\n /**\n * A text-only test conversation, used by the agent playground in D-ID Studio.\n *\n * Produces no video, and marks each chat request with a playground header so the Agents API\n * can treat it as a test. Chats in this mode always go over the Agents API, even for\n * Expressive (V4) agents, which otherwise chat over the data channel. Applications normally\n * use {@link ChatMode.Functional} or {@link ChatMode.TextOnly} instead.\n */\n Playground = 'Playground',\n /**\n * Speak-only: no chat is created and no notifications web socket is opened, while video still\n * streams. Use it when the application drives the agent entirely through\n * {@link AgentManager.speak | speak()}.\n *\n * Talks (V2) and Clips (V3) agents only; rejected with a {@link ValidationError} for Expressive\n * (V4) agents. {@link AgentManager.chat | chat()} rejects with a {@link ValidationError} in\n * this mode.\n */\n DirectPlayback = 'DirectPlayback',\n /**\n * Chat is switched off: no chat is created for the session, while video still streams. Unlike\n * {@link ChatMode.DirectPlayback} it keeps the notifications web socket.\n *\n * Talks (V2) and Clips (V3) agents only; rejected with a {@link ValidationError} for Expressive\n * (V4) agents. {@link AgentManager.chat | chat()} rejects with a {@link ValidationError} in\n * this mode.\n */\n Off = 'Off',\n}\n\n/**\n * What the Agents API answers a chat request with.\n *\n * Returned by {@link AgentManager.chat | chat()}. The SDK has already added the answer to the\n * transcript by the time you get it, so most applications render\n * {@link AgentManagerCallbacks.onNewMessage | onNewMessage} instead and use this only for the\n * fields that never reach a {@link Message}. Expressive (V4) agents chat over the data channel\n * rather than over the Agents API — except in {@link ChatMode.Playground} — so for them the\n * object is empty and the answer arrives through the callback.\n *\n * @category Chat\n */\nexport interface ChatResponse {\n /**\n * The agent's answer.\n *\n * Empty or absent when the answer is delivered as it is generated instead, which is what\n * streaming modes do; the SDK then adds no message for it and the text arrives through\n * {@link AgentManagerCallbacks.onNewMessage | onNewMessage}.\n */\n result?: string;\n /**\n * The Agents API's own list of ids for the documents behind the answer. The SDK never reads it;\n * {@link ChatResponse.matches | matches} is what it keeps on the message.\n */\n documentIds?: string[];\n /**\n * The knowledge citations behind the answer.\n *\n * Copied onto the answer as {@link Message.matches | matches}.\n */\n matches?: RetrievalMetadata[];\n /**\n * The {@link ChatMode} the server handled the request in.\n *\n * It can differ from the mode that was asked for — see {@link ChatMode}.\n */\n chatMode?: ChatMode;\n /**\n * The retrieved context the answer was generated from.\n *\n * Copied onto the answer as {@link Message.context | context}.\n */\n context?: string;\n /** Id of the video generated for the answer, when the server reported one. */\n videoId?: string;\n}\n\n/**\n * A conversation with an agent, as the Agents API stores it.\n * @internal Wire type of the Agents API; not part of the public SDK surface. The only part an\n * application sees is the chat id, reported by\n * {@link AgentManagerCallbacks.onNewChat | onNewChat}.\n */\nexport interface Chat {\n /** Id of the chat. The value handed to\n * {@link AgentManagerCallbacks.onNewChat | onNewChat}. */\n id: string;\n /** Id of the agent this conversation is with. */\n agent_id: string;\n /** When the chat was created, as an ISO 8601 timestamp. */\n created: string;\n /** When the chat was last changed, as an ISO 8601 timestamp. */\n modified: string;\n /** Id of the D-ID account that owns the chat. Set by the API; on the synthetic chat the SDK\n * builds for an Expressive (V4) session it is copied from {@link Agent.owner_id}. */\n owner_id: string;\n /**\n * The messages stored with the chat.\n *\n * The SDK never reads this array — the live transcript is the one handed to\n * {@link AgentManagerCallbacks.onNewMessage | onNewMessage} — and it is empty on the chat the\n * SDK builds for an Expressive (V4) session.\n */\n messages: Message[];\n /** A composite sort key the API uses to list an agent's chats by creation time. Not meaningful\n * to clients. */\n agent_id__created_at: string;\n /** A composite sort key the API uses to list an agent's chats by modification time. Not\n * meaningful to clients. */\n agent_id__modified_at: string;\n /**\n * The {@link ChatMode} the chat was created in.\n *\n * {@link AgentManager.connect | connect()} adopts it, which is how the server can downgrade the\n * mode an application asked for.\n */\n chat_mode?: ChatMode;\n}\n\n/**\n * What caused the user to interrupt the agent, passed to\n * {@link AgentManager.interrupt | interrupt()}.\n *\n * @category Chat\n */\nexport interface InterruptOptions {\n /**\n * The cause: `text` when the user typed over the answer, `audio` when they started speaking,\n * `click` when they pressed a stop control, and `manual` for an interruption the application\n * decided on itself.\n *\n * The SDK records it with the interruption for analytics. It changes behavior in one case\n * only: Expressive (V4) agents ignore a `text` interrupt, because their orchestrator does not\n * cancel the answer already in flight. Talks (V2) and Clips (V3) agents interrupt the current\n * video whatever the value.\n */\n type: 'text' | 'audio' | 'click' | 'manual';\n}\n","import { SttTokenResponse } from '@sdk/types';\nimport { Auth } from '@sdk/types/auth';\nimport { ErrorContext } from '@sdk/types/error-context';\nimport {\n AgentActivityState,\n ClientToolHandler,\n CompatibilityMode,\n ConnectionState,\n ConnectivityState,\n DataChannelTopic,\n RunningToolCall,\n SpeakResponse,\n StreamCreatedInfo,\n StreamEvents,\n StreamType,\n StreamingState,\n ToolEventCallback,\n} from '@sdk/types/stream';\nimport { SpeakScript } from '@sdk/types/stream-script';\nimport { Agent } from './agent';\nimport { ChatMode, ChatResponse, InterruptOptions, Message, Rating, SubmitFeedbackResponse } from './chat';\n\n/**\n * Types of events provided in Chat Progress Callback\n * @internal Implementation type; not part of the public SDK surface.\n */\nexport enum ChatProgress {\n /**\n * Chat was successfully embedded\n */\n Embed = 'embed',\n /**\n * Server processing chat message\n */\n Query = 'query',\n /**\n * Server returns a part of the message\n */\n Partial = 'partial',\n /**\n * Server processed message and returned response\n */\n Answer = 'answer',\n /**\n * Audio-transcribed user message\n */\n Transcribe = 'transcribe',\n /**\n * Chat was closed\n */\n Complete = 'done',\n}\n\n/**\n * Callback signature for {@link ChatProgress} events emitted internally during a chat exchange.\n * @internal Implementation type; not part of the public SDK surface.\n */\nexport type ChatProgressCallback = (progress: ChatProgress | StreamEvents, data: any) => void;\n\n/**\n * Handlers the SDK calls as the connection, the video stream and the chat change state.\n *\n * Pass the object as {@link AgentManagerOptions.callbacks}. Every handler is optional in the type,\n * but {@link AgentManagerCallbacks.onSrcObjectReady | onSrcObjectReady} is required in practice\n * for any chat mode that streams video — without it there is nothing to render the agent into, and\n * {@link createAgentManager} rejects. Every handler is called from the SDK's own event handling,\n * so keep the work inside short.\n *\n * The handlers fall into four groups: the connection\n * ({@link AgentManagerCallbacks.onConnectionStateChange | onConnectionStateChange},\n * {@link AgentManagerCallbacks.onConnectivityStateChange | onConnectivityStateChange},\n * {@link AgentManagerCallbacks.onError | onError}), the video stream\n * ({@link AgentManagerCallbacks.onSrcObjectReady | onSrcObjectReady},\n * {@link AgentManagerCallbacks.onStreamCreated | onStreamCreated},\n * {@link AgentManagerCallbacks.onVideoStateChange | onVideoStateChange},\n * {@link AgentManagerCallbacks.onAgentActivityStateChange | onAgentActivityStateChange},\n * {@link AgentManagerCallbacks.onInterruptibleChange | onInterruptibleChange}), the chat\n * ({@link AgentManagerCallbacks.onNewChat | onNewChat}, {@link AgentManagerCallbacks.onNewMessage | onNewMessage},\n * {@link AgentManagerCallbacks.onModeChange | onModeChange}) and client tools\n * ({@link AgentManagerCallbacks.onToolEvent | onToolEvent},\n * {@link AgentManagerCallbacks.onRunningToolCallsChange | onRunningToolCallsChange}). A handler that\n * lives outside the object can be typed with an indexed access such as\n * `AgentManagerCallbacks['onNewMessage']`.\n *\n * The whole object is captured once, by {@link createAgentManager}, and the manager works from its\n * own copy — assigning a handler to the object you passed afterwards has no effect, and neither\n * does replacing {@link AgentManagerOptions.callbacks | options.callbacks}. Give each handler a\n * stable identity that reads the current state rather than closing over it: in React, keep the\n * state in a ref and read `ref.current` inside the handler.\n *\n * @category Callbacks & Events\n */\nexport interface AgentManagerCallbacks {\n /**\n * Called every time the connection to the agent's stream changes state.\n *\n * Triggered by {@link AgentManager.connect | connect()},\n * {@link AgentManager.reconnect | reconnect()} and\n * {@link AgentManager.disconnect | disconnect()}.\n * {@link ConnectionState.Connected | 'connected'} is the point at which\n * {@link AgentManager.chat | chat()} and {@link AgentManager.speak | speak()} can be called.\n *\n * @param state - The state just reached: one of `new`, `connecting`, `connected`, `completed`,\n * `disconnecting`, `disconnected`, `closed` or `fail`. See {@link ConnectionState}.\n * @param reason - Why that state was reached. On `disconnected` it is a\n * {@link StreamEndReason} value when the server ended the stream on purpose, which is how you\n * tell a deliberate end from a dropped connection. Talks (V2) and Clips (V3) agents report\n * only `ok`, `unknown_error`, `network_issue` and `inactivity`; `message_limit`, `time_limit`\n * and `ended_by_agent` come from Expressive (V4) agents. A close reason the SDK does not\n * recognize is forwarded as-is, so compare `reason` against the enum rather than parsing it;\n * any other value is an opaque transport diagnostic.\n * {@link AgentManager.reconnect | reconnect()} still works after a deliberate end; it starts a\n * new stream rather than resuming the old one.\n * @example\n * ```ts\n * import { ConnectionState, type AgentManagerCallbacks } from '@d-id/client-sdk';\n *\n * const callbacks: AgentManagerCallbacks = {\n * onConnectionStateChange(state, reason) {\n * console.log('onConnectionStateChange(): ', state, reason);\n *\n * if (state === ConnectionState.Connected) {\n * console.log(\"I'm ready to go!\");\n * }\n * },\n * };\n * ```\n */\n onConnectionStateChange?: (state: ConnectionState, reason?: string) => void;\n /**\n * Called when the streamed video starts and stops, so the video element can switch source.\n *\n * Triggered by {@link AgentManager.chat | chat()} and {@link AgentManager.speak | speak()}. On\n * `STOP` point the element at the agent's idle video ({@link Agent.idle_video}); on `START` put\n * the stream handed to {@link AgentManagerCallbacks.onSrcObjectReady | onSrcObjectReady} back\n * on it.\n *\n * On a **legacy** stream this is the only \"is the agent speaking\" signal — see\n * {@link AgentManagerCallbacks.onAgentActivityStateChange | onAgentActivityStateChange} for\n * which stream types report which.\n *\n * @param state - {@link StreamingState.Start | START} while the agent is speaking,\n * {@link StreamingState.Stop | STOP} once it has finished.\n * @example\n * ```ts\n * import { StreamingState, type AgentManagerCallbacks } from '@d-id/client-sdk';\n *\n * let srcObject: MediaStream | null = null;\n *\n * const callbacks: AgentManagerCallbacks = {\n * onSrcObjectReady(value) {\n * srcObject = value;\n * videoElement.srcObject = value;\n * },\n * onVideoStateChange(state) {\n * if (state === StreamingState.Stop) {\n * videoElement.srcObject = null;\n * videoElement.src = agentManager.agent.idle_video ?? '';\n * } else {\n * videoElement.src = '';\n * videoElement.srcObject = srcObject;\n * }\n * },\n * };\n * ```\n */\n onVideoStateChange?: (state: StreamingState) => void;\n /**\n * Called with the media stream carrying the agent's video and audio.\n *\n * This is the one callback a video session cannot work without: assign the value to the\n * `srcObject` of your `<video>` element, and keep a reference to it, because\n * {@link AgentManagerCallbacks.onVideoStateChange | onVideoStateChange} has to put it back\n * after the idle video has been shown. Triggered by\n * {@link AgentManager.connect | connect()}, {@link AgentManager.reconnect | reconnect()} and\n * {@link AgentManager.disconnect | disconnect()}.\n *\n * Optional only for the chat modes that never stream video — {@link ChatMode.TextOnly},\n * {@link ChatMode.Playground} and {@link ChatMode.Maintenance} — so a text-only application\n * does not have to supply a stub. {@link createAgentManager} rejects with a\n * {@link ValidationError} when it is missing in any other mode — {@link ChatMode.Off} and\n * {@link ChatMode.DirectPlayback} included, since those create no chat but still stream video.\n * {@link AgentManager.connect | connect()} checks it again against the mode in\n * effect then, so a manager created in a text-only mode and later moved into a video mode with\n * {@link AgentManager.changeMode | changeMode()} rejects rather than opening a stream with\n * nothing to render it into.\n *\n * @param srcObject - The live media stream to render.\n * @example\n * ```ts\n * import type { AgentManagerCallbacks } from '@d-id/client-sdk';\n *\n * // Kept so `onVideoStateChange` can put it back after the idle video.\n * let srcObject: MediaStream | null = null;\n *\n * const callbacks: AgentManagerCallbacks = {\n * onSrcObjectReady(value) {\n * videoElement.srcObject = value;\n * srcObject = value;\n * },\n * };\n * ```\n */\n onSrcObjectReady?: (srcObject: MediaStream) => void;\n /**\n * Called with the whole chat transcript every time a message is added or updated.\n *\n * Triggered by {@link AgentManager.chat | chat()}, by {@link AgentManager.speak | speak()} for\n * text scripts, and as the agent's answer streams in. It also fires once while the manager is\n * created, with whatever {@link AgentManagerOptions.initialMessages | initialMessages} were\n * given, and again on every {@link AgentManager.connect | connect()} after the first — both\n * with type `answer`. The array is a fresh copy on each call, oldest message first; every\n * {@link Message} carries an `id`, a `role` of `user` or `assistant` (the agent), its `content`\n * and a `createdAt` timestamp.\n *\n * @param messages - The chat so far.\n * @param type - `partial` while the agent's answer is still streaming in, `answer` for the full\n * answer spoken in the streamed video, `user` when the message just added is the user's own\n * (a message passed to {@link AgentManager.chat | chat()}, or a transcribed utterance).\n * @example\n * ```ts\n * import type { AgentManagerCallbacks } from '@d-id/client-sdk';\n *\n * const callbacks: AgentManagerCallbacks = {\n * onNewMessage(messages, type) {\n * // `partial` fires repeatedly as the answer streams in; `answer` is the final one.\n * if (type === 'answer') {\n * console.log(messages[messages.length - 1]?.content);\n * }\n * },\n * };\n * ```\n */\n onNewMessage?: (messages: Message[], type: 'answer' | 'partial' | 'user') => void;\n /**\n * Called when a chat is created for this session.\n *\n * A chat is created while {@link AgentManager.connect | connect()} runs, and lazily on the\n * first {@link AgentManager.chat | chat()} when none exists yet. Store the id if you want to\n * correlate the conversation with your own records.\n *\n * On Talks (V2) and Clips (V3) agents the id comes from the Agents API. On Expressive (V4)\n * agents the SDK derives it from the session id as `cht_<sessionId>`, which is the same id the\n * Agents API stores the conversation under — so it correlates with D-ID's own records either\n * way.\n *\n * @param chatId - Id of the chat that was just created.\n * @example\n * ```ts\n * import type { AgentManagerCallbacks } from '@d-id/client-sdk';\n *\n * const callbacks: AgentManagerCallbacks = {\n * onNewChat(chatId) {\n * // Keep it to correlate the conversation with your own records.\n * localStorage.setItem('did-chat-id', chatId);\n * },\n * };\n * ```\n */\n onNewChat?: (chatId: string) => void;\n /**\n * Called when the chat mode changes.\n *\n * Fires after {@link AgentManager.changeMode | changeMode()}, and when the server answers with\n * a different mode than the one requested (for example {@link ChatMode.Maintenance}).\n *\n * @param mode - The {@link ChatMode} now in effect.\n * @example\n * ```ts\n * import { ChatMode, type AgentManagerCallbacks } from '@d-id/client-sdk';\n *\n * const callbacks: AgentManagerCallbacks = {\n * onModeChange(mode) {\n * // `chat()` rejects in Maintenance too, so the composer goes with the banner below.\n * setComposerEnabled(\n * mode !== ChatMode.Off && mode !== ChatMode.DirectPlayback && mode !== ChatMode.Maintenance\n * );\n *\n * if (mode === ChatMode.Maintenance) {\n * showBanner('The agent is temporarily unavailable.');\n * }\n * },\n * };\n * ```\n */\n onModeChange?: (mode: ChatMode) => void;\n /**\n * Called when the quality of the user's internet connection changes.\n *\n * The state is derived from jitter-buffer delay and freeze count on the video stream for\n * Talks (V2) and Clips (V3) agents, and from LiveKit's reported connection quality for\n * Expressive (V4) agents, so it reflects what the session is actually getting rather than the\n * browser's online flag.\n *\n * @param state - {@link ConnectivityState.Strong | STRONG},\n * {@link ConnectivityState.Weak | WEAK} or {@link ConnectivityState.Unknown | UNKNOWN}.\n * @example\n * ```ts\n * import { ConnectivityState, type AgentManagerCallbacks } from '@d-id/client-sdk';\n *\n * const callbacks: AgentManagerCallbacks = {\n * onConnectivityStateChange(state) {\n * setQualityWarningVisible(state === ConnectivityState.Weak);\n * },\n * };\n * ```\n */\n onConnectivityStateChange?: (state: ConnectivityState) => void;\n /**\n * Called when the SDK fails, so the application can surface the problem.\n *\n * Receives failures from the Agents API requests, the stream and the web socket — an\n * {@link HttpError} when a request comes back non-2xx, a {@link NetworkError} when it never\n * reaches the server, a {@link WsError} when the web socket itself fails, and also\n * {@link ChatModeDowngraded} and {@link StreamError}. Two errors do not arrive here:\n * {@link ValidationError} and {@link ChatCreationFailed} are thrown to whoever called the\n * method ({@link AgentManager.chat | chat()}, {@link AgentManager.speak | speak()} and the\n * rating methods), so they surface as a rejected promise rather than through this callback.\n *\n * @param error - The error that occurred. Narrow it with {@link isDIDError} and branch on\n * {@link BaseError.kind | kind}; {@link BaseError.toJson | toJson()} is what to log.\n * @param errorData - Where the failure happened, as an {@link ErrorContext}: the endpoint and\n * method for a failed request, the session or stream id for a failure on the stream. Every\n * field is optional and nothing else is passed — in particular not the request body, which\n * carries the end user's own message.\n * @example\n * ```ts\n * import { isDIDError, type AgentManagerCallbacks } from '@d-id/client-sdk';\n *\n * const callbacks: AgentManagerCallbacks = {\n * onError(error, errorData) {\n * reportToYourErrorService({\n * ...(isDIDError(error) ? error.toJson() : { kind: 'Error', message: error.message }),\n * ...errorData,\n * });\n * },\n * };\n * ```\n */\n onError?: (error: Error, errorData?: ErrorContext) => void;\n /**\n * Called when the agent moves between idle, loading, talking and running a tool.\n *\n * Use it to drive a typing indicator or to disable input while the agent is busy. The full set\n * of states is reported for Expressive (V4) agents only. Talks (V2) and Clips (V3) agents\n * report just {@link AgentActivityState.Talking | Talking} and\n * {@link AgentActivityState.Idle | Idle}, and only on fluent streams, plus a final\n * {@link AgentActivityState.Idle | Idle} when the connection closes.\n *\n * It is the authoritative \"is the agent speaking\" signal wherever it reports at all — an\n * Expressive (V4) session or a fluent stream — because it comes from the agent rather than from\n * the video track, so it also covers thinking and tool calls, which produce no video.\n * On a **legacy** stream it reports nothing, so use\n * {@link AgentManagerCallbacks.onVideoStateChange | onVideoStateChange} there; that is the\n * branch every consumer otherwise writes for itself, keyed on\n * {@link AgentManager.getStreamType | getStreamType()}.\n *\n * @param state - The {@link AgentActivityState} the agent has moved to.\n * @example\n * ```ts\n * import { AgentActivityState, type AgentManagerCallbacks } from '@d-id/client-sdk';\n *\n * const callbacks: AgentManagerCallbacks = {\n * onAgentActivityStateChange(state) {\n * setTypingIndicatorVisible(state === AgentActivityState.Loading);\n * setComposerEnabled(state === AgentActivityState.Idle);\n * },\n * };\n * ```\n */\n onAgentActivityStateChange?: (state: AgentActivityState) => void;\n /**\n * Called once per session when the stream has been created on the server.\n *\n * Fires before the connection reaches {@link ConnectionState.Connected | 'connected'}. The ids\n * are useful when correlating a session with D-ID support or with your own logs.\n *\n * @param stream - The new stream's `streamId`, `sessionId` and `agentId`.\n * @example\n * ```ts\n * import type { AgentManagerCallbacks } from '@d-id/client-sdk';\n *\n * const callbacks: AgentManagerCallbacks = {\n * onStreamCreated({ streamId, sessionId }) {\n * // The two ids D-ID support asks for when a session misbehaves.\n * console.log('stream', streamId, 'session', sessionId);\n * },\n * };\n * ```\n */\n onStreamCreated?: (stream: StreamCreatedInfo) => void;\n /**\n * Called when the agent starts, finishes or fails a tool call.\n *\n * Expressive (V4) agents only. The handler takes two arguments and returns nothing: `event`,\n * one of {@link ToolCallEvent.Started}, {@link ToolCallEvent.Done} or\n * {@link ToolCallEvent.Error}; and `data`, the payload that event carries —\n * {@link ToolCallStartedPayload}, {@link ToolCallDonePayload} or\n * {@link ToolCallErrorPayload} respectively. The signature that does the narrowing is on\n * {@link ToolEventCallback}, which also carries a handler that branches on all three events.\n * @example\n * ```ts\n * import { ToolCallEvent, type AgentManagerCallbacks } from '@d-id/client-sdk';\n *\n * const callbacks: AgentManagerCallbacks = {\n * onToolEvent(event, data) {\n * if (event === ToolCallEvent.Error) {\n * showBanner(`${data.name} failed: ${data.error ?? 'no reason given'}`);\n * }\n * },\n * };\n * ```\n */\n onToolEvent?: ToolEventCallback;\n /**\n * Called when the agent becomes interruptible, or stops being interruptible.\n *\n * Expressive (V4) agents only, and about whether interrupting is allowed *right now*: it goes\n * `false` while any `blocking` tool call is outstanding (client or server), and back to `true`\n * once none is: finished, failed, its turn ended, or the session disconnected. That is a\n * different question from\n * {@link AgentManager.isInterruptAvailable | isInterruptAvailable()}, which says whether\n * the session supports interrupting at all. Use this one to enable or disable an interrupt\n * button. Talks (V2) and Clips (V3) agents never report a change.\n * @example\n * ```ts\n * import type { AgentManagerCallbacks } from '@d-id/client-sdk';\n *\n * const callbacks: AgentManagerCallbacks = {\n * onInterruptibleChange(interruptible) {\n * setStopButtonEnabled(interruptible);\n * },\n * };\n * ```\n */\n onInterruptibleChange?: (\n /** `true` when interrupting is allowed, `false` while a blocking tool call is pending. */\n interruptible: boolean\n ) => void;\n /**\n * Called whenever the set of tool calls running in the session changes.\n *\n * Expressive (V4) agents only. On disconnect it fires with an empty array if any call was\n * still running, so a spinner driven by this callback always clears; with nothing outstanding\n * there is nothing to clear and nothing is emitted. Each entry is a {@link RunningToolCall}.\n * @example\n * ```ts\n * import { isAwaitingTool, type AgentManagerCallbacks } from '@d-id/client-sdk';\n *\n * const callbacks: AgentManagerCallbacks = {\n * onRunningToolCallsChange(calls) {\n * setSpinnerVisible(isAwaitingTool(calls));\n * setStatusText(calls.map(call => call.name).join(', '));\n * },\n * };\n * ```\n */\n onRunningToolCallsChange?: (\n /** Every tool call running right now, empty when none is. */\n calls: readonly RunningToolCall[]\n ) => void;\n}\n\n/**\n * Transport settings applied when the stream is created.\n *\n * Talks (V2) and Clips (V3) agents only. Expressive (V4) agents manage transport settings\n * automatically and ignore these options. Pass the object as\n * {@link AgentManagerOptions.streamOptions}; every field is optional.\n *\n * @category Streaming Options\n */\nexport interface StreamOptions {\n /**\n * Which video codec the stream negotiates.\n *\n * See {@link CompatibilityMode}.\n *\n * @default auto\n */\n compatibilityMode?: CompatibilityMode;\n\n /**\n * Whether the stream plays a warmup video while the connection settles.\n *\n * With it on the server plays a short warmup video as soon as the connection is up, and the\n * SDK holds back {@link ConnectionState.Connected | 'connected'} — and so the resolution of\n * {@link AgentManager.connect | connect()} — until that video has played out. Without it,\n * `'connected'` is reported as soon as the data channel opens. The application sees nothing of\n * the warmup video itself beyond the delay; it is not distinguishable from any other. A fluent\n * stream ignores the option — the warmup only runs on legacy streams (see\n * {@link StreamOptions.fluent | fluent}).\n *\n * @default false\n */\n streamWarmup?: boolean;\n\n /**\n * How long the session may sit idle between messages before the server ends it, in seconds.\n *\n * Up to 300, and only for accounts whose plan allows it. When the session does time out,\n * {@link AgentManagerCallbacks.onConnectionStateChange | onConnectionStateChange} reports\n * {@link ConnectionState.Disconnected | 'disconnected'} with the reason\n * {@link StreamEndReason.Inactivity | 'inactivity'}. Leave it out and the server decides.\n */\n sessionTimeout?: number;\n\n /**\n * Whether to request a fluent stream.\n *\n * `true` streams one video for both the idle and talking states; `false` uses the legacy mode,\n * where the application swaps between two video elements. Clips (V3) agents built on a Pro\n * avatar; always on for Expressive (V4). A fluent stream is also what makes\n * {@link AgentManager.interrupt | interrupt()} available.\n *\n * @default false\n */\n fluent?: boolean;\n}\n\n/**\n * What the SDK reports about the session, and where it goes.\n *\n * Pass it as {@link AgentManagerOptions.analytics}; every field is optional, and leaving the whole\n * object out reports to D-ID's own project.\n *\n * The SDK posts an event to Mixpanel for each step of a session — connect, reconnect and\n * disconnect, every message sent and answered, every {@link AgentManager.speak | speak()}, mode\n * change, rating, feedback, tool call, video start and stop, interrupt and error. Each event\n * carries the agent id, the visitor id derived from\n * {@link AgentManagerOptions.externalId | externalId}, the page URL, the screen size, the user\n * agent, the SDK version and whatever\n * {@link AnalyticsOptions.additionalProperties | additionalProperties} added. **Conversation text\n * is included too:** the agent's answer on `agent-message-received`, and the script on\n * `agent-speak`. Set {@link AnalyticsOptions.enabled | enabled: false} to send nothing at all.\n *\n * Events that fail to post are buffered in memory (at most 50) and retried when the tab comes back\n * online or becomes visible.\n *\n * @example Send the SDK's events to your own project, tagged with your plan\n * ```ts\n * const agentManager = await sdk.createAgentManager('agt_fumf1234', {\n * auth: { type: 'key', clientKey: 'YOUR_CLIENT_KEY' },\n * callbacks,\n * analytics: { mixpanelKey: 'YOUR_MIXPANEL_TOKEN', additionalProperties: { plan: 'pro' } },\n * });\n * ```\n * @category Agent Manager\n */\nexport interface AnalyticsOptions {\n /**\n * Whether the SDK reports usage analytics at all. Set it to `false` to send nothing.\n *\n * @default true\n */\n enabled?: boolean;\n /**\n * Mixpanel project token the SDK's analytics events are sent to.\n *\n * Defaults to D-ID's own project. Set it to send the SDK's events to your Mixpanel project\n * instead.\n */\n mixpanelKey?: string;\n /**\n * Extra properties merged into every analytics event the SDK sends.\n *\n * A flat object — use it to tag events with your own identifiers. More properties can be added\n * later with {@link AgentManager.enrichAnalytics | enrichAnalytics()}. A `plan` property here\n * is also forwarded to the Agents API as end-user data when a Talks (V2) or Clips (V3) stream\n * is created.\n */\n additionalProperties?: Record<string, unknown>;\n}\n\n/**\n * Everything {@link createAgentManager} needs to reach an agent and report back to the application.\n *\n * {@link AgentManagerOptions.auth | auth} and {@link AgentManagerOptions.callbacks | callbacks} are\n * required; the rest have defaults that suit a browser application talking to D-ID production.\n *\n * {@link createAgentManager} reads the object once, at creation, and never writes to it: the\n * manager works from its own copy, so one options object can create two managers, and a property\n * you read back afterwards is still the one you set. The same means a handler assigned to\n * {@link AgentManagerOptions.callbacks | callbacks} after the manager exists is not picked up —\n * give the callback a stable identity and dispatch inside it instead.\n *\n * @category Agent Manager\n */\nexport interface AgentManagerOptions {\n /**\n * Credentials used for every request the SDK makes on the application's behalf.\n *\n * Use `{ type: 'key', clientKey }` in a browser: a client key works for one agent and only from\n * the domains you allowed, so it is the only credential that is safe to ship in a page. See\n * {@link Auth}.\n */\n auth: Auth;\n /**\n * Handlers the SDK calls as the connection, the video stream and the chat change state.\n *\n * See {@link AgentManagerCallbacks}.\n * {@link AgentManagerCallbacks.onSrcObjectReady | onSrcObjectReady} is what connects the\n * streamed media to your video element, so every chat mode that streams video needs it. The\n * handlers are captured at creation, so replacing one on this object later has no effect.\n */\n callbacks: AgentManagerCallbacks;\n /**\n * How the agent answers: with a streamed video, as text only, or not at all.\n *\n * See {@link ChatMode}. It can be changed later with\n * {@link AgentManager.changeMode | changeMode()}. {@link ChatMode.Off} and\n * {@link ChatMode.DirectPlayback} are supported on Talks (V2) and Clips (V3) agents only.\n *\n * @default ChatMode.Functional\n * @throws {@link ValidationError} From {@link createAgentManager}, when the agent is Expressive\n * (V4) and the mode is {@link ChatMode.Off} or {@link ChatMode.DirectPlayback}.\n */\n mode?: ChatMode;\n /**\n * Base URL of the D-ID Agents API.\n *\n * Advanced. Points the SDK at another D-ID environment. Production applications do not set\n * this. Every REST call the manager makes — agent lookup, chat, ratings, stream creation — is\n * addressed against it.\n *\n * @defaultValue D-ID's production Agents API.\n */\n baseURL?: string;\n /**\n * URL of the D-ID notifications web socket.\n *\n * Advanced. Points the SDK at another D-ID environment. Production applications do not set\n * this. Only opened in the chat modes that stream the agent's answer, so it has no effect in\n * {@link ChatMode.DirectPlayback | DirectPlayback} or {@link ChatMode.Off | Off}.\n *\n * @defaultValue D-ID's production notifications web socket.\n */\n wsURL?: string;\n /**\n * Whether the SDK logs its streaming lifecycle to the browser console.\n *\n * It is also switched on for everyone when the agent's `ui_debug_mode` advanced setting is\n * enabled, regardless of the value passed here.\n *\n * @default false\n */\n debug?: boolean;\n /**\n * Whether tool-call events carry the call's input, output, duration and failure details.\n *\n * Without it, {@link AgentManagerCallbacks.onToolEvent | onToolEvent} payloads carry only the\n * call's id, name and timestamp. The Agents API accepts it only from the agent's owner with\n * {@link BasicAuth} or {@link BearerToken} auth, and rejects it with a `403` otherwise, so a\n * browser application on a client key cannot use it. Independent of\n * {@link AgentManagerOptions.debug | debug}. Expressive (V4) agents only.\n *\n * @default false\n */\n verbose?: boolean;\n /**\n * What the SDK reports about the session, and where it goes.\n *\n * See {@link AnalyticsOptions}. Reporting is on unless you turn it off with\n * `analytics: { enabled: false }`.\n */\n analytics?: AnalyticsOptions;\n /**\n * Your own identifier for the end user.\n *\n * It is stored in `localStorage`, sent as part of the `type: 'key'` authorization header and\n * attached to analytics, so the same visitor is recognized across page loads. When it is\n * omitted the SDK generates an id and reuses it.\n */\n externalId?: string;\n /**\n * Transport settings applied when the stream is created.\n *\n * See {@link StreamOptions}. Talks (V2) and Clips (V3) agents only. Expressive (V4) agents\n * manage transport settings automatically.\n */\n streamOptions?: StreamOptions;\n /**\n * Messages the chat starts with, for example a transcript restored from your own storage.\n *\n * They are delivered to {@link AgentManagerCallbacks.onNewMessage | onNewMessage} so the UI can\n * render them. On Talks (V2) and Clips (V3) agents they are also sent as context with the next\n * {@link AgentManager.chat | chat()} request. See {@link Message}.\n *\n * A row from your own storage is enough: {@link Message.parts | parts} and\n * {@link Message.createdAt | createdAt} are optional, and the SDK builds the parts from\n * `content` with {@link parseMessageParts} for every message that arrives without them, so a\n * transcript restored from the text alone still renders. A non-empty `parts` array is kept as\n * given.\n *\n * @example Restoring rows that carry only the message text\n * ```ts\n * const initialMessages = stored.map(({ id, role, content }) => ({ id, role, content }));\n * ```\n */\n initialMessages?: Message[];\n /**\n * Whether the server keeps the chat so it can be resumed in a later session.\n *\n * Without persistence a chat lives only as long as the connection.\n * {@link AgentManager.reconnect | reconnect()} normally continues the same chat either way —\n * see the caveat there for Expressive (V4) agents.\n *\n * Off unless you set it, on every agent type.\n *\n * @default false\n */\n persistentChat?: boolean;\n}\n\n/**\n * A live connection to one agent: its profile, its chat, and the video stream it answers on.\n *\n * Created by {@link createAgentManager}. Nothing happens on the wire until\n * {@link AgentManager.connect | connect()} resolves; after that\n * {@link AgentManager.chat | chat()} makes the agent answer with its own LLM and\n * {@link AgentManager.speak | speak()} makes it say exactly what you give it. Call\n * {@link AgentManager.disconnect | disconnect()} when the user leaves.\n *\n * Two properties, {@link AgentManager.agent | agent} and\n * {@link AgentManager.starterMessages | starterMessages}, are readable as soon as the manager\n * exists; everything else is a method. Some methods work only with some avatar types: each one\n * says so, and {@link AgentAvatar} is where the session's tier is read from.\n *\n * The manager's own state is readable at any time:\n * {@link AgentManager.getChatMode | getChatMode()},\n * {@link AgentManager.getConnectionState | getConnectionState()} and\n * {@link AgentManager.getSessionInfo | getSessionInfo()} answer with what the matching callback\n * last reported, so nothing has to be mirrored in application state.\n *\n * Every method that reaches the Agents API can reject with an {@link HttpError} when the request\n * comes back non-2xx, or a {@link NetworkError} when it never reaches the server; the individual\n * `@throws` entries below name the errors that are specific to each method.\n *\n * @category Agent Manager\n */\nexport interface AgentManager {\n /**\n * The agent this manager is connected to, as the Agents API returned it.\n *\n * Fetched once while the manager is created, so it is available before\n * {@link AgentManager.connect | connect()}. Useful for rendering the agent's name, thumbnail\n * and {@link Agent.idle_video | idle_video}. See {@link Agent}.\n *\n * Read-only: the property cannot be reassigned, and the SDK never replaces it — the manager\n * talks to the agent it was created for, for its whole life.\n * @example\n * ```ts\n * nameElement.textContent = agentManager.agent.name ?? 'Agent';\n * thumbnailElement.src = agentManager.agent.thumbnail ?? '';\n * ```\n */\n readonly agent: Agent;\n /**\n * Returns the kind of stream the current session negotiated.\n *\n * @returns {@link StreamType.Fluent} for a fluent stream (one video for the idle and talking\n * states), {@link StreamType.Legacy} for the two-element legacy mode, or `undefined` before\n * {@link AgentManager.connect | connect()} has established a session.\n * @example\n * ```ts\n * import { StreamType } from '@d-id/client-sdk';\n *\n * // A legacy stream is the one the application swaps the idle video in and out of.\n * const swapsIdleVideo = agentManager.getStreamType() === StreamType.Legacy;\n * ```\n */\n getStreamType(): StreamType | undefined;\n\n /**\n * Returns whether the current stream supports interrupting the agent mid-answer.\n *\n * `true` once connected on a fluent stream (every Expressive (V4) session, or a fluent Clips\n * (V3) one) whose agent has not turned interrupting off in its advanced settings. It reads the\n * session {@link AgentManager.connect | connect()} attached, so ask it after `connect()`\n * resolves. This says the stream supports interrupting at all;\n * {@link AgentManagerCallbacks.onInterruptibleChange | onInterruptibleChange} says whether\n * interrupting is allowed right now.\n *\n * @returns `true` when {@link AgentManager.interrupt | interrupt()} can do anything.\n * @example\n * ```ts\n * await agentManager.connect();\n * setStopButtonVisible(agentManager.isInterruptAvailable());\n * ```\n */\n isInterruptAvailable(): boolean;\n\n /**\n * The agent's starter messages.\n *\n * Suggested openers to offer the user as buttons; empty when the agent defines none. Available\n * before {@link AgentManager.connect | connect()}.\n *\n * Read-only, and a copy of {@link Agent.starter_message} rather than the same array, so\n * sorting or filtering a local copy of it cannot change what\n * {@link AgentManager.agent | agent} reports.\n * @example\n * ```ts\n * for (const message of agentManager.starterMessages) {\n * addSuggestionButton(message, () => void agentManager.chat(message));\n * }\n * ```\n */\n readonly starterMessages: readonly string[];\n /**\n * Fetches a short-lived Azure Speech token, for running your own speech recognition.\n *\n * Works with every {@link Auth} type, connected or not. The agent must be public or belong to\n * the account the credentials are for.\n *\n * @returns The {@link SttTokenResponse}: the token and its Azure region.\n * @throws {@link HttpError} `400` when the agent is neither public nor the caller's, `404` when\n * it does not exist, or any other non-2xx answer.\n * @throws {@link NetworkError} When the request never reaches the server.\n * @example\n * ```ts\n * const { token, region } = await agentManager.getSttToken();\n * startRecognition(token, region);\n * ```\n */\n getSttToken(): Promise<SttTokenResponse>;\n /**\n * Returns the chat mode in effect right now.\n *\n * The same value {@link AgentManagerCallbacks.onModeChange | onModeChange} last reported, and\n * the one every mode guard in the SDK reads. It is not always the mode that was asked for: the\n * server can answer {@link AgentManager.connect | connect()} with a different mode, which the\n * manager adopts, and a failed connection leaves the session in\n * {@link ChatMode.Maintenance | Maintenance}. Use it instead of mirroring `onModeChange` in\n * your own state.\n *\n * @returns The current {@link ChatMode}; before {@link AgentManager.connect | connect()}, the\n * mode the manager was created with ({@link ChatMode.Functional} by default).\n * @example\n * ```ts\n * import { ChatMode } from '@d-id/client-sdk';\n *\n * if (agentManager.getChatMode() === ChatMode.Maintenance) {\n * showBanner('The agent is temporarily unavailable.');\n * }\n * ```\n */\n getChatMode(): ChatMode;\n /**\n * Returns the connection state the manager last reported.\n *\n * The same value\n * {@link AgentManagerCallbacks.onConnectionStateChange | onConnectionStateChange} was last\n * called with, so a component that mounts after the session is up can read the state instead of\n * waiting for the next change.\n *\n * @returns The current {@link ConnectionState}; {@link ConnectionState.New | 'new'} before the\n * first {@link AgentManager.connect | connect()}.\n * @example\n * ```ts\n * const canChat = agentManager.getConnectionState() === 'connected';\n * ```\n */\n getConnectionState(): ConnectionState;\n /**\n * Returns the ids of the session that is open, for support and for your own logs.\n *\n * The same {@link StreamCreatedInfo} that\n * {@link AgentManagerCallbacks.onStreamCreated | onStreamCreated} delivered for this session.\n *\n * @returns The open session's `streamId`, `sessionId` and `agentId`, or `undefined` before\n * {@link AgentManager.connect | connect()} and after\n * {@link AgentManager.disconnect | disconnect()}.\n * @example\n * ```ts\n * const session = agentManager.getSessionInfo();\n * console.log('session', session?.sessionId, 'stream', session?.streamId);\n * ```\n */\n getSessionInfo(): StreamCreatedInfo | undefined;\n /**\n * Opens a new session with the agent: a new WebRTC connection, a new web socket and a new chat.\n *\n * Resolves once the connection reaches {@link ConnectionState.Connected | 'connected'}, by\n * which point {@link AgentManagerCallbacks.onSrcObjectReady | onSrcObjectReady} has been called\n * with the media stream to render.\n *\n * One session at a time: while a call is still in flight a second call returns that same\n * promise rather than opening a second session, and cancels a\n * {@link AgentManager.disconnect | disconnect()} made in between, which is what makes it safe\n * in a React StrictMode effect. While a session is open it rejects instead: call\n * `disconnect()` first to start a fresh conversation, or\n * {@link AgentManager.reconnect | reconnect()} to keep the current one. After the server ended\n * the session (`'disconnected'` with a {@link StreamEndReason}), `connect()` opens a new one. A\n * call that joins an\n * operation a {@link AgentManager.disconnect | disconnect()} later cancels resolves without a\n * session open; read {@link AgentManager.getConnectionState | getConnectionState()} for what\n * happened.\n *\n * @returns Resolves when the agent is connected and ready.\n * @throws {@link ValidationError} When a session is already open, or when\n * {@link AgentManagerCallbacks.onSrcObjectReady | onSrcObjectReady} was not supplied and the\n * current {@link ChatMode} streams video — which a\n * {@link AgentManager.changeMode | changeMode()} out of a text-only mode can bring about.\n * @throws {@link HttpError} When creating the stream or the chat comes back non-2xx — a client\n * key that is not authorized for the agent or the calling domain, an account out of credits, or\n * an agent that is not built yet. The SDK tries the initialization up to three times first,\n * except on `429`, on `409` and on an out-of-credits response.\n * @throws {@link NetworkError} When those requests never reach the server.\n * @example\n * ```ts\n * await agentManager.connect();\n * ```\n */\n connect(): Promise<void>;\n /**\n * Reopens the stream when the session expires, and continues the conversation on the same chat.\n *\n * The chat id normally does not change, so the agent keeps its context. It starts a new stream\n * — including after the server ended the previous one deliberately — rather than resuming the\n * old one. On Expressive (V4) agents the transport is asked to reconnect first; if that fails\n * the SDK falls back to a disconnect and a fresh connect, which starts a new chat id.\n *\n * One session-opening operation runs at a time, teardown included, so this and\n * {@link AgentManager.connect | connect()} cannot interleave — call one or the other rather\n * than racing them. A `connect()` that joins this one continues the existing chat, so\n * {@link AgentManagerCallbacks.onNewChat | onNewChat} does not fire for it.\n *\n * @returns Resolves when the new stream is connected.\n * @throws {@link ValidationError} When a {@link AgentManager.connect | connect()} is still in\n * flight; wait for it to settle first.\n * @throws {@link HttpError} When creating the new stream comes back non-2xx.\n * @throws {@link NetworkError} When that request never reaches the server.\n * @example\n * ```ts\n * try {\n * // The session expired. Start a new stream and keep the conversation.\n * await agentManager.reconnect();\n * } catch {\n * // A connect() or another reconnect() is still in flight; let it settle first.\n * }\n * ```\n */\n reconnect(): Promise<void>;\n /**\n * Closes the existing connection and chat with the agent: the stream and the web socket.\n *\n * Call it when the user leaves the page or the conversation, so the session does not keep\n * running. After it resolves, {@link AgentManager.connect | connect()} is needed before the\n * agent can be used again.\n *\n * @returns Resolves once everything is closed.\n * @example\n * ```ts\n * // The user left the conversation: close the session so it stops running.\n * await agentManager.disconnect();\n *\n * // The manager stays usable — connect() opens a new session with a new chat.\n * await agentManager.connect();\n * ```\n */\n disconnect(): Promise<void>;\n /**\n * Publishes a microphone audio track to the session so the agent can hear the user.\n *\n * Call it after {@link AgentManager.connect | connect()} to enable voice input. Expressive (V4)\n * agents only; on Talks (V2) and Clips (V3) agents, and before `connect()`, the returned\n * promise rejects with a {@link ValidationError}.\n *\n * @param stream - A `MediaStream` whose audio track is published to the session.\n * @returns Resolves once the track is published.\n * @throws {@link ValidationError} When the session is not an Expressive (V4) one, or\n * {@link AgentManager.connect | connect()} has not run yet.\n * @example\n * ```ts\n * const micStream = await navigator.mediaDevices.getUserMedia({ audio: true });\n * await agentManager.publishMicrophoneStream(micStream);\n * ```\n */\n publishMicrophoneStream(stream: MediaStream): Promise<void>;\n /**\n * Removes the published microphone track from the session.\n *\n * The counterpart of {@link AgentManager.publishMicrophoneStream | publishMicrophoneStream()}.\n * The `MediaStreamTrack` is not stopped, because the stream is the caller's: stop it to release\n * the microphone. Expressive (V4) agents only; on Talks (V2) and Clips (V3) agents, and when\n * nothing is published, it resolves without doing anything.\n *\n * @returns Resolves once the track is removed.\n * @example\n * ```ts\n * await agentManager.unpublishMicrophoneStream();\n * ```\n */\n unpublishMicrophoneStream(): Promise<void>;\n /**\n * Swaps the live microphone track without unpublishing it.\n *\n * Use it when the user picks a different input device: the publication is preserved — its\n * LiveKit publication id (SID) and SSRC stay the same, though the `MediaStreamTrack` id\n * changes — so the server sees continuous audio across the swap rather than a stop and a\n * restart. The previous track is not stopped; stop it once the swap resolves. Rejects with a\n * plain `Error` from the transport when there is no active publication: fall back to\n * {@link AgentManager.publishMicrophoneStream | publishMicrophoneStream()} in that case.\n * Expressive (V4) agents only; on Talks (V2) and Clips (V3) agents, and before\n * {@link AgentManager.connect | connect()}, the returned promise rejects with a\n * {@link ValidationError}.\n *\n * @param track - The audio track to send from now on.\n * @returns Resolves once the transport has switched to the new track.\n * @throws {@link ValidationError} When the session is not an Expressive (V4) one, or\n * {@link AgentManager.connect | connect()} has not run yet.\n * @example\n * ```ts\n * const stream = await navigator.mediaDevices.getUserMedia({ audio: { deviceId } });\n * const [track] = stream.getAudioTracks();\n *\n * try {\n * await agentManager.replaceMicrophoneTrack(track);\n * } catch {\n * // Nothing published yet, so there is no track to swap: publish instead.\n * await agentManager.publishMicrophoneStream(stream);\n * }\n * ```\n */\n replaceMicrophoneTrack(track: MediaStreamTrack): Promise<void>;\n /**\n * Publishes a camera video track to the session so the agent can see the user.\n *\n * Call it after {@link AgentManager.connect | connect()} to enable vision. Expressive (V4)\n * agents only; on Talks (V2) and Clips (V3) agents, and before `connect()`, the returned\n * promise rejects with a {@link ValidationError}.\n *\n * @param stream - A `MediaStream` whose video track is published to the session.\n * @returns Resolves once the track is published.\n * @throws {@link ValidationError} When the session is not an Expressive (V4) one, or\n * {@link AgentManager.connect | connect()} has not run yet.\n * @example\n * ```ts\n * if (agentManager.agent.vision?.enabled) {\n * const cameraStream = await navigator.mediaDevices.getUserMedia({ video: true });\n * await agentManager.publishCameraStream(cameraStream);\n * }\n * ```\n */\n publishCameraStream(stream: MediaStream): Promise<void>;\n /**\n * Removes the published camera track from the session.\n *\n * Call it to disable vision. The `MediaStreamTrack` is not stopped, because the stream is the\n * caller's: stop it to release the camera. Expressive (V4) agents only; on Talks (V2) and Clips (V3) agents,\n * and when nothing is published, it resolves without doing anything.\n *\n * @returns Resolves once the track is removed.\n * @example\n * ```ts\n * // No guard needed: a no-op wherever there is nothing published.\n * await agentManager.unpublishCameraStream();\n * ```\n */\n unpublishCameraStream(): Promise<void>;\n /**\n * Sends a message to the agent and gets a streamed video based on its answer (LLM).\n *\n * The answer arrives through {@link AgentManagerCallbacks.onNewMessage | onNewMessage} — first\n * as `partial` chunks, then as the full `answer` — while the video plays it. The chat is\n * created on the first call if the session does not have one yet.\n *\n * @param userMessage - The user's message text to send to the agent.\n * @returns The {@link ChatResponse} for this turn.\n * @throws {@link ValidationError} When the message is empty or too long, when the chat mode has\n * chat disabled or is in maintenance, or when the manager is not connected yet.\n * @throws {@link ChatCreationFailed} On Talks (V2) and Clips (V3) agents, when the session has\n * no chat yet and the Agents API answers the creation request without one.\n * @throws {@link HttpError} On Talks (V2) and Clips (V3) agents, and in\n * {@link ChatMode.Playground}, when the message request comes back non-2xx. Expressive (V4)\n * agents send the message over the data channel instead, so no HTTP request is made.\n * @throws {@link NetworkError} On Talks (V2) and Clips (V3) agents, and in\n * {@link ChatMode.Playground}, when that request never reaches the server.\n * @example\n * ```ts\n * const chat = await agentManager.chat('What is the distance to the moon?');\n * ```\n */\n chat(userMessage: string): Promise<ChatResponse>;\n /**\n * Rates one of the agent's answers in the chat, for future analytics and insights.\n *\n * Pass `rateId` to change a rating the user already gave instead of adding another.\n *\n * Works on every avatar type. On an Expressive (V4) session an answer that arrived over the\n * data channel without a server id is given a locally generated one, which D-ID's records\n * cannot be matched against — rate the answers whose ids came from the server.\n *\n * @param messageId - Id of the message being rated.\n * @param score - 1 for a positive rating, -1 for a negative one.\n * @param rateId - Id of an existing rating to update; omit to create a new one.\n * @returns The created or updated {@link Rating}.\n * @throws {@link ValidationError} When no chat has started, or when no message with that id is\n * in the transcript.\n * @throws {@link HttpError} When the rating request comes back non-2xx.\n * @throws {@link NetworkError} When the rating request never reaches the server.\n * @example\n * ```ts\n * const rating = await agentManager.rate(messageId, 1);\n *\n * // The user changed their mind: pass the rating's id back rather than adding another.\n * await agentManager.rate(messageId, -1, rating.id);\n * ```\n */\n rate(messageId: string, score: 1 | -1, rateId?: string): Promise<Rating>;\n /**\n * Removes a rating the user gave to an answer in the chat.\n *\n * @param id - Id of the rating to remove, as returned by\n * {@link AgentManager.rate | rate()}.\n * @returns The {@link Rating} that was deleted.\n * @throws {@link ValidationError} When no chat has started.\n * @throws {@link HttpError} When the delete request comes back non-2xx.\n * @throws {@link NetworkError} When the delete request never reaches the server.\n * @example\n * ```ts\n * const rating = await agentManager.rate(messageId, 1);\n * await agentManager.deleteRate(rating.id);\n * ```\n */\n deleteRate(id: string): Promise<Rating>;\n /**\n * Submits end-of-call feedback for the whole conversation.\n *\n * Separate from {@link AgentManager.rate | rate()}, which scores a single answer. Collect it\n * when the user ends the call, using the agent's end-of-call feedback configuration.\n *\n * Every avatar type. The agent must have end-of-call feedback switched on\n * ({@link Agent.end_of_call_feedback}, {@link EndOfCallFeedbackConfig.enabled | enabled}) —\n * the Agents API rejects the request otherwise, so read the configuration before offering the\n * form. A second submission for the same conversation replaces the first.\n *\n * @param rating - The user's score for the conversation: 1, 2, 3, 4 or 5. The Agents API\n * rejects anything else, whole numbers outside the range and fractions alike.\n * @param answer - The user's free-text answer to the follow-up question, when one was asked.\n * @returns The stored {@link SubmitFeedbackResponse}.\n * @throws {@link ValidationError} When no chat has started.\n * @throws {@link HttpError} When the feedback request comes back non-2xx — including a `400`\n * when the agent does not have end-of-call feedback enabled.\n * @throws {@link NetworkError} When the feedback request never reaches the server.\n * @example\n * ```ts\n * // The Agents API rejects the request unless the agent has end-of-call feedback on.\n * if (agentManager.agent.end_of_call_feedback?.enabled) {\n * await agentManager.submitFeedback(5, 'The answers were clear and quick.');\n * }\n * ```\n */\n submitFeedback(rating: 1 | 2 | 3 | 4 | 5, answer?: string): Promise<SubmitFeedbackResponse>;\n /**\n * Makes the agent stream back a video based on the text or audio file you provide.\n *\n * Unlike {@link AgentManager.chat | chat()} the agent's LLM is not involved, so this is how you\n * script greetings and canned lines. Pass a plain string as a shorthand for a text script. See\n * {@link SpeakScript}, {@link TextStreamScript} and {@link AudioStreamScript}. Text\n * scripts also accept an optional `sentiment`, for Expressive (V4) agents only; if the\n * requested sentiment is not supported by the agent, the default sentiment is used.\n *\n * @see [Create a video stream](https://docs.d-id.com/reference/createvideoagentstream) — the request\n * sent for Talks (V2) and Clips (V3) agents.\n * @see [Control the Agent](https://docs.d-id.com/docs/livekit-commands) — the `did.speak` command\n * sent over the data channel for Expressive (V4) agents.\n * @param payload - A text or audio script, or a string treated as the text to speak.\n * @returns The {@link SpeakResponse} for the video that was produced, or the same\n * response with `duration` `0` and an empty `videoId` when the call produced no discrete video\n * — on Expressive (V4) agents, and in a text-only chat mode.\n * @throws {@link ValidationError} When the manager is not connected to a stream yet.\n * @throws {@link HttpError} On Talks (V2) and Clips (V3) agents, when the Agents API answers\n * the request non-2xx. Expressive (V4) agents send the script over the data channel instead,\n * so no HTTP request is made.\n * @throws {@link NetworkError} On Talks (V2) and Clips (V3) agents, when that request never\n * reaches the server.\n * @example Text\n * ```ts\n * const speak = await agentManager.speak({\n * type: 'text',\n * input: \"Hi! I'm Alice!\",\n * });\n * ```\n * @example Text with sentiment (Expressive (V4) agents)\n * ```ts\n * const speak = await agentManager.speak({\n * type: 'text',\n * input: \"Hi! I'm Alice!\",\n * sentiment: 'friendly',\n * });\n * ```\n * @example Audio file\n * ```ts\n * const speak = await agentManager.speak({\n * type: 'audio',\n * audio_url: 'https://www.yourwebsite.com/audio.mp3',\n * });\n * ```\n */\n speak(payload: SpeakScript | string): Promise<SpeakResponse>;\n /**\n * Switches the chat to another mode.\n *\n * Any mode but {@link ChatMode.Functional} disconnects the stream, and a change into\n * `Functional` disconnects a session that was not built for a conversation (one opened in\n * {@link ChatMode.DirectPlayback}, for example); call {@link AgentManager.connect | connect()}\n * again after such a change. {@link AgentManagerCallbacks.onModeChange | onModeChange} fires\n * once the change is applied; passing the mode already in effect does nothing.\n *\n * @param mode - The {@link ChatMode} to switch to.\n * @returns A promise resolved when the mode is in effect and any disconnect has completed.\n * @throws {@link ValidationError} Rejects on Expressive (V4) agents for {@link ChatMode.Off} and\n * {@link ChatMode.DirectPlayback}, which those agents do not support.\n * @example\n * ```ts\n * import { ChatMode } from '@d-id/client-sdk';\n *\n * await agentManager.changeMode(ChatMode.Off); // Disconnects the stream.\n *\n * await agentManager.changeMode(ChatMode.Functional);\n * await agentManager.connect();\n * ```\n */\n changeMode(mode: ChatMode): Promise<void>;\n\n /**\n * Adds properties to every analytics event the SDK sends from now on.\n *\n * The same thing\n * {@link AnalyticsOptions.additionalProperties | analytics.additionalProperties} does at\n * creation time, for values you only learn later.\n *\n * Advanced. Calls merge, so a property sent twice takes the later value, and events already\n * sent are not changed. It has no visible effect when analytics is switched off with\n * {@link AnalyticsOptions.enabled | analytics.enabled} set to `false`, because nothing is sent\n * at all.\n *\n * @param properties - A flat JSON object whose properties are added to every analytics event\n * the SDK sends from now on.\n * @example\n * ```ts\n * // The user signed in halfway through the session.\n * agentManager.enrichAnalytics({ plan: 'pro', locale: navigator.language });\n * ```\n */\n enrichAnalytics(properties: Record<string, unknown>): void;\n\n /**\n * Interrupts the current video stream mid-playback, so the user can talk over the agent.\n *\n * Supported on a fluent stream — a Clips (V3) agent built on a Pro avatar, or any Expressive\n * (V4) agent. It never throws: on every agent type it returns without doing anything when\n * interrupting is not available for the session, when it is not allowed right now, and — on\n * Talks (V2) and Clips (V3) agents — when the stream is not a fluent stream or no video is\n * playing. Check {@link AgentManager.isInterruptAvailable | isInterruptAvailable()}\n * before offering the control at all; on Expressive (V4) agents\n * {@link AgentManagerCallbacks.onInterruptibleChange | onInterruptibleChange} tracks whether it\n * is allowed right now.\n *\n * The last message in the transcript is marked `interrupted` in the next\n * {@link AgentManagerCallbacks.onNewMessage | onNewMessage}, but only when an interrupt was\n * actually sent. A call that finds nothing to interrupt leaves the message untouched and fires\n * no callback.\n *\n * @param options - What caused the interruption, as an {@link InterruptOptions}: `text`,\n * `audio`, `click` or `manual`. Optional — a stop button is the common case, so leaving it out\n * means `{ type: 'click' }`. Expressive (V4) agents drop `text` interrupts, because the\n * orchestrator does not cancel the in-flight answer for them.\n * @example\n * ```ts\n * stopButton.onclick = () => agentManager.interrupt();\n *\n * // The user typed over the answer instead of pressing the button.\n * agentManager.interrupt({ type: 'text' });\n * ```\n */\n interrupt(options?: InterruptOptions): void;\n\n /**\n * Switches the speech-to-text language in the middle of a session.\n *\n * Expressive (V4) agents only, after {@link AgentManager.connect | connect()}; otherwise the\n * returned promise rejects with a {@link ValidationError}.\n *\n * @param language - The language to transcribe in, as a name or a BCP-47 code — `\"English\"` or\n * `\"en-US\"`.\n * @returns Resolves once the new language has been sent to the agent. A room that has dropped\n * since {@link AgentManager.connect | connect()} reports a {@link StreamError} through\n * {@link AgentManagerCallbacks.onError | onError} and the promise still resolves.\n * @throws {@link ValidationError} When the session is not an Expressive (V4) one, or\n * {@link AgentManager.connect | connect()} has not run yet.\n * @example\n * ```ts\n * await agentManager.setSttLanguage('en-US');\n * await agentManager.setSttLanguage('Spanish');\n * ```\n */\n setSttLanguage(language: string): Promise<void>;\n\n /**\n * Sends a JSON payload to the agent over a data-channel topic.\n *\n * Use it for application-specific messages that are not speech, such as telling a presentation\n * to change slide. Expressive (V4) agents only, after {@link AgentManager.connect | connect()};\n * otherwise the returned promise rejects with a {@link ValidationError}.\n *\n * @param topic - Data-channel topic to send on. Either a {@link DataChannelTopic} member or\n * its string value — `DataChannelTopic.Presentation` and `'did.presentation'` are both\n * accepted. {@link DataChannelTopic} is exported from the package root and lists every topic\n * this method accepts.\n * @param payload - A plain object, sent as JSON.\n * @returns Resolves once the payload has been sent. A room that has dropped since\n * {@link AgentManager.connect | connect()} reports a {@link StreamError} through\n * {@link AgentManagerCallbacks.onError | onError} and the promise still resolves.\n * @throws {@link ValidationError} When the session is not an Expressive (V4) one, or\n * {@link AgentManager.connect | connect()} has not run yet.\n * @example\n * ```ts\n * import { DataChannelTopic } from '@d-id/client-sdk';\n *\n * await agentManager.sendDataChannelMessage(DataChannelTopic.Presentation, {\n * type: 'navigate',\n * slide: 3,\n * });\n * ```\n */\n sendDataChannelMessage(topic: `${DataChannelTopic}`, payload: Record<string, unknown>): Promise<void>;\n\n /**\n * Registers a handler for a client tool, run in the browser when the agent's LLM calls it.\n *\n * Expressive (V4) agents only: client tools travel on the real-time session's RPC channel,\n * which Talks (V2) and Clips (V3) agents do not have. It throws a {@link ValidationError} on\n * those rather than registering a handler the agent could never call. The check is on the\n * agent, not on the connection, so it applies before\n * {@link AgentManager.connect | connect()} too.\n *\n * The handler executes on the client and its result is returned to the LLM. Register the\n * handlers before {@link AgentManager.connect | connect()} so the agent can call\n * them from the moment the session starts; registering the same name again replaces the\n * handler. Progress is reported through\n * {@link AgentManagerCallbacks.onToolEvent | onToolEvent}.\n *\n * @param name - Name of the tool, which must match the one defined in the agent's\n * configuration.\n * @param handler - The function that runs when the agent calls the tool. It receives the\n * arguments the LLM produced and returns a JSON string of at most 15 KiB — the limit is the\n * transport's, not the SDK's, and a larger result fails the call. See\n * {@link ClientToolHandler}.\n * @throws {@link ValidationError} When the agent is a Talks (V2) or Clips (V3) one.\n * @example\n * ```ts\n * if (agentManager.agent.avatar.type === 'expressive') {\n * agentManager.registerClientTool('get_cart_total', async args => {\n * const total = await cart.total(args.currency as string);\n * return JSON.stringify({ total });\n * });\n * }\n * ```\n */\n registerClientTool(name: string, handler: ClientToolHandler): void;\n\n /**\n * Removes a previously registered client tool handler.\n *\n * After this the agent's calls to that tool fail rather than reaching your code. Unlike\n * {@link AgentManager.registerClientTool | registerClientTool()} it never throws — a name that\n * was never registered, and any agent type, is a no-op — so it is safe in a cleanup path.\n *\n * @param name - Name of the tool whose handler should be removed.\n * @example\n * ```ts\n * // Safe in a cleanup path: it never throws, whatever the agent type.\n * agentManager.unregisterClientTool('get_cart_total');\n * ```\n */\n unregisterClientTool(name: string): void;\n}\n","/**\n * The kind of avatar an agent is built on, which is what decides how its video is produced.\n *\n * It is the `type` of the agent's avatar ({@link Agent.avatar}) and so determines which SDK\n * features a session has: {@link AvatarType.Talk | talk} is Talks (V2),\n * {@link AvatarType.Clip | clip} is Clips (V3), and {@link AvatarType.Expressive | expressive} is\n * Expressive (V4).\n *\n * @category Agent Manager\n */\nexport enum AvatarType {\n /** A Clips (V3) agent: a pre-recorded presenter, driven by the D-ID Clips pipeline. */\n Clip = 'clip',\n /** A Talks (V2) agent: a still photo animated to speak. */\n Talk = 'talk',\n /**\n * An Expressive (V4) avatar: a real-time avatar that also supports microphone and camera\n * publishing, client tools and interruption.\n */\n Expressive = 'expressive',\n /**\n * An image agent: a still photo animated in real time. Streams over the same real-time session\n * as Expressive (V4).\n *\n * @hidden\n */\n Image = 'image',\n}\n","import { Analytics } from '@sdk/services/analytics/mixpanel';\nimport { VideoRTCStatsReport } from '@sdk/services/streaming-manager/stats/report';\nimport { Auth } from '../auth';\nimport { AgentManagerCallbacks, ChatProgressCallback } from '../entities/agents/manager';\nimport { ErrorReporter } from '../error-context';\nimport { CreateClipStreamRequest, CreateTalkStreamRequest, SendClipStreamPayload, SendTalkStreamPayload } from './api';\nimport { ICreateStreamRequestResponse, IceCandidate, SpeakResponse, Status } from './rtc';\n\n/**\n * Which video codec the stream should negotiate.\n *\n * Passed as {@link StreamOptions.compatibilityMode}. `on` forces VP8 and `off` forces H264; with\n * `auto` the SDK forwards the flag and the codec is selected according to the browser. Talks (V2)\n * and Clips (V3) agents only — Expressive (V4) agents negotiate the codec themselves and ignore\n * the setting.\n *\n * @category Streaming Options\n */\nexport type CompatibilityMode = 'on' | 'off' | 'auto';\n\n/**\n * Whether the agent's video is currently playing.\n *\n * The argument of {@link AgentManagerCallbacks.onVideoStateChange | onVideoStateChange}: it tells\n * the application when to show the streamed video and when to fall back to the agent's idle video.\n *\n * @category Callbacks & Events\n */\nexport enum StreamingState {\n /** The agent has started speaking; render the streamed media. */\n Start = 'START',\n /** The agent has finished speaking; the application can switch back to the idle video. */\n Stop = 'STOP',\n}\n\n/**\n * How well the streamed media is reaching the user.\n *\n * The argument of\n * {@link AgentManagerCallbacks.onConnectivityStateChange | onConnectivityStateChange}. It is\n * estimated from the session's own media statistics — jitter-buffer delay and freeze count for\n * Talks (V2) and Clips (V3), the transport's reported connection quality for Expressive (V4) — so\n * it reflects what this stream is actually getting rather than whether the browser is online.\n *\n * @category Callbacks & Events\n */\nexport enum ConnectivityState {\n /** The stream is arriving smoothly. */\n Strong = 'STRONG',\n /** The stream is degraded: video is stalling or arriving late. */\n Weak = 'WEAK',\n /** There is not enough data to judge the connection yet, or the stream stopped arriving. */\n Unknown = 'UNKNOWN',\n}\n\n/**\n * What the agent is doing right now, for driving the application's UI.\n *\n * The argument of\n * {@link AgentManagerCallbacks.onAgentActivityStateChange | onAgentActivityStateChange}. Expressive\n * (V4) agents move through all four states; Talks (V2) and Clips (V3) agents only alternate between\n * {@link AgentActivityState.Talking | TALKING} and {@link AgentActivityState.Idle | IDLE}, and only\n * on fluent streams.\n *\n * @category Callbacks & Events\n */\nexport enum AgentActivityState {\n /** The agent is doing nothing and is waiting for the user — the conversational turn has ended. */\n Idle = 'IDLE',\n /**\n * The agent is working on an answer that has not started streaming yet.\n *\n * Expressive (V4) only: set when a turn starts and when the user's speech has just been\n * transcribed. Use it for a typing or thinking indicator.\n */\n Loading = 'LOADING',\n /** The agent's video has started; the agent is speaking. */\n Talking = 'TALKING',\n /**\n * The agent is running one or more tool calls.\n *\n * Expressive (V4) only: set when a tool call starts, and returned to after the agent finishes\n * speaking while any call is still outstanding (for example a client tool waiting on the user).\n * The individual calls are reported by\n * {@link AgentManagerCallbacks.onRunningToolCallsChange | onRunningToolCallsChange}.\n */\n ToolActive = 'TOOL_ACTIVE',\n}\n\n/**\n * Every event the SDK receives on a stream's data channel or web socket.\n *\n * The three tool-call members are the only ones an application ever sees, and they reach it as\n * {@link ToolCallEvent} instead; the rest are consumed by the SDK and surfaced as callbacks.\n * @internal Implementation type; not part of the public SDK surface.\n */\nexport enum StreamEvents {\n /**\n * The agent's complete answer for this turn; it becomes an `answer` message in the transcript.\n * @internal Consumed by the SDK; it surfaces as onNewMessage.\n */\n ChatAnswer = 'chat/answer',\n /**\n * A fragment of the agent's answer as it is generated; it becomes a `partial` message.\n * @internal Consumed by the SDK; it surfaces as onNewMessage.\n */\n ChatPartial = 'chat/partial',\n /**\n * The user's speech, transcribed by the server; it becomes a `user` message.\n * @internal Consumed by the SDK; it surfaces as onNewMessage.\n */\n ChatAudioTranscribed = 'chat/audio-transcribed',\n /**\n * A video finished playing, or the session ended — which one depends on where it arrives.\n *\n * On the data channel of a Talks (V2) or Clips (V3) stream it closes the video\n * {@link StreamEvents.StreamStarted | 'stream/started'} opened, once per\n * {@link AgentManager.speak | speak()}, and drives\n * {@link AgentManagerCallbacks.onVideoStateChange | onVideoStateChange} with\n * {@link StreamingState.Stop | STOP} and\n * {@link AgentManagerCallbacks.onAgentActivityStateChange | onAgentActivityStateChange} with\n * {@link AgentActivityState.Idle | IDLE}.\n *\n * On the Talks (V2) and Clips (V3) web socket, and on an Expressive (V4) stream, it instead\n * ends the whole session: it carries the reason, which the SDK passes on as the `reason`\n * argument of {@link AgentManagerCallbacks.onConnectionStateChange | onConnectionStateChange}\n * with {@link ConnectionState.Disconnected | 'disconnected'}. See {@link StreamEndReason}.\n * @internal Consumed by the SDK; it surfaces as onVideoStateChange or onConnectionStateChange.\n */\n StreamDone = 'stream/done',\n /**\n * A video started playing on a Talks (V2) or Clips (V3) stream.\n * @internal Consumed by the SDK; it surfaces as onVideoStateChange.\n */\n StreamStarted = 'stream/started',\n /**\n * The session ended because the stream failed.\n *\n * On the Talks (V2) and Clips (V3) web socket it is also reported through\n * {@link AgentManagerCallbacks.onError | onError}, as a {@link StreamError}.\n * @internal Consumed by the SDK; it surfaces as onError.\n */\n StreamFailed = 'stream/error',\n /**\n * The warmup video has finished and the stream is ready for real content.\n *\n * Only sent when {@link StreamOptions.streamWarmup | streamWarmup} was requested.\n * @internal Consumed by the SDK; the application never sees it.\n */\n StreamReady = 'stream/ready',\n /**\n * The video currently playing should stop.\n *\n * Sent by the SDK rather than received: it is the message\n * {@link AgentManager.interrupt | interrupt()} puts on the data channel of a fluent Talks (V2)\n * or Clips (V3) stream.\n * @internal Sent by the SDK; the application calls interrupt() instead.\n */\n StreamInterrupt = 'stream/interrupt',\n /**\n * A video for one utterance started playing.\n * @internal Consumed by the SDK; it surfaces as onVideoStateChange.\n */\n StreamVideoCreated = 'stream-video/started',\n /**\n * The video for one utterance finished playing.\n * @internal Consumed by the SDK; it surfaces as onVideoStateChange.\n */\n StreamVideoDone = 'stream-video/done',\n /**\n * Generating or streaming the video for one utterance failed.\n * @internal Consumed by the SDK; it surfaces as onError.\n */\n StreamVideoError = 'stream-video/error',\n /**\n * The server refused to generate the video for one utterance.\n * @internal Consumed by the SDK; it surfaces as onError.\n */\n StreamVideoRejected = 'stream-video/rejected',\n /** The agent started a tool call; the payload is a {@link ToolCallStartedPayload}. */\n ToolCallStarted = 'tool-call/started',\n /** A tool call finished successfully; the payload is a {@link ToolCallDonePayload}. */\n ToolCallDone = 'tool-call/done',\n /** A tool call failed; the payload is a {@link ToolCallErrorPayload}. */\n ToolCallError = 'tool-call/error',\n /**\n * A conversational turn started. Expressive (V4) only.\n * @internal Consumed by the SDK; it surfaces as onAgentActivityStateChange.\n */\n TurnStarted = 'turn/started',\n /**\n * A conversational turn ended. Expressive (V4) only.\n * @internal Consumed by the SDK; it surfaces as onAgentActivityStateChange.\n */\n TurnEnded = 'turn/ended',\n}\n\n/**\n * The tool-call events delivered to {@link AgentManagerCallbacks.onToolEvent | onToolEvent}.\n *\n * Switch on the first argument of the handler to tell them apart: it narrows the second argument to\n * the payload that event carries — see {@link ToolEventCallback}. The members' values are the wire\n * strings the server sends, so compare against the enum rather than writing the string out.\n * Expressive (V4) agents only.\n *\n * @example\n * ```ts\n * import { AgentManagerCallbacks, ToolCallEvent } from '@d-id/client-sdk';\n *\n * const callbacks: AgentManagerCallbacks = {\n * onToolEvent(event, data) {\n * if (event === ToolCallEvent.Started) {\n * console.log('started', data.name, data.input);\n * }\n * },\n * };\n * ```\n * @category Callbacks & Events\n */\nexport enum ToolCallEvent {\n /**\n * The agent has begun a tool call; the payload is a {@link ToolCallStartedPayload}, carrying the\n * call's id, the tool's name and the arguments the agent's LLM produced.\n */\n Started = 'tool-call/started',\n /**\n * A tool call finished successfully; the payload is a {@link ToolCallDonePayload}, carrying the\n * result the tool returned and how long the call took.\n */\n Done = 'tool-call/done',\n /**\n * A tool call failed; the payload is a {@link ToolCallErrorPayload}, carrying the reason in\n * {@link ToolCallErrorPayload.error | error} when the server gave one. The agent carries on\n * with the conversation.\n */\n Error = 'tool-call/error',\n}\n\n/**\n * The data-channel topics an application may send on with\n * {@link AgentManager.sendDataChannelMessage | sendDataChannelMessage()}.\n *\n * The remaining data-channel topics are driven by their own methods\n * ({@link AgentManager.chat | chat()}, {@link AgentManager.speak | speak()},\n * {@link AgentManager.interrupt | interrupt()},\n * {@link AgentManager.setSttLanguage | setSttLanguage()}), which own the payload shape and\n * bookkeeping those topics expect, so they stay internal.\n *\n * The members' values are the wire strings. Take the value from the enum rather than writing the\n * string out, so the wire string stays in one place. Expressive (V4) agents only.\n *\n * @example\n * ```ts\n * import { DataChannelTopic } from '@d-id/client-sdk';\n *\n * await agentManager.sendDataChannelMessage(DataChannelTopic.Presentation, {\n * type: 'navigate',\n * slide: 3,\n * });\n * ```\n * @category Agent Manager\n */\nexport enum DataChannelTopic {\n /**\n * Tells the agent which slide the user moved to in the deck it is presenting. Sent on the wire\n * as `did.presentation`. The only payload the agent reads is\n * `{ type: 'navigate', slide: <integer> }`; anything else, or any message while the agent has\n * no deck, is ignored.\n */\n Presentation = 'did.presentation',\n}\n\n/**\n * The state of the connection between the browser and the agent's stream.\n *\n * The first argument of\n * {@link AgentManagerCallbacks.onConnectionStateChange | onConnectionStateChange}.\n * {@link ConnectionState.Connected | 'connected'} is the point at which\n * {@link AgentManager.chat | chat()} and {@link AgentManager.speak | speak()} can be called.\n *\n * Every agent type reports `'connecting'`, `'connected'`, `'fail'` and `'disconnected'`; `'new'`,\n * `'completed'` and `'closed'` are WebRTC ICE states that only Talks (V2) and Clips (V3) agents\n * reach, and `'disconnecting'` is Expressive (V4) only.\n *\n * @category Callbacks & Events\n */\nexport enum ConnectionState {\n /** The connection object exists but nothing has been negotiated yet. */\n New = 'new',\n /** The connection could not be established, or dropped irrecoverably. */\n Fail = 'fail',\n /** The stream is live: the agent can be spoken to and its video rendered. */\n Connected = 'connected',\n /** The connection is being established, or re-established after a drop. */\n Connecting = 'connecting',\n /** The connection has been shut down and cannot be used again. */\n Closed = 'closed',\n /**\n * Negotiation finished and the connection is fully established.\n *\n * It is reached after {@link ConnectionState.Connected | 'connected'}, so gate the application\n * on that one instead: it is the state every agent type reports.\n */\n Completed = 'completed',\n /**\n * {@link AgentManager.disconnect | disconnect()} is in progress.\n *\n * Expressive (V4) agents only; Talks (V2) and Clips (V3) go straight from\n * {@link ConnectionState.Connected | 'connected'} to\n * {@link ConnectionState.Disconnected | 'disconnected'}.\n */\n Disconnecting = 'disconnecting',\n /**\n * The stream has ended.\n *\n * The `reason` argument of\n * {@link AgentManagerCallbacks.onConnectionStateChange | onConnectionStateChange} says why —\n * a {@link StreamEndReason} when the server ended the session deliberately. Reconnecting with\n * {@link AgentManager.reconnect | reconnect()} starts a new stream.\n */\n Disconnected = 'disconnected',\n}\n\n/**\n * How the agent's idle and talking video are delivered.\n *\n * Returned by {@link AgentManager.getStreamType | getStreamType()}. Which one a session gets\n * follows from the agent and from {@link StreamOptions.fluent | fluent}.\n *\n * @category Streaming Options\n */\nexport enum StreamType {\n /**\n * Two videos: the agent's idle video, which the application plays itself, and the streamed\n * talking video. Switch between them in\n * {@link AgentManagerCallbacks.onVideoStateChange | onVideoStateChange}.\n */\n Legacy = 'legacy',\n /**\n * One continuous video for both the idle and the talking state, so there is nothing to swap.\n * Expressive (V4) agents always stream this way, and it is what makes\n * {@link AgentManager.interrupt | interrupt()} possible.\n */\n Fluent = 'fluent',\n}\n\n/**\n * Handler for an RPC method registered on the LiveKit room before it connects.\n * @internal Implementation type; not part of the public SDK surface.\n */\nexport type RpcMethodHandler = (data: { payload: string }) => Promise<string>;\n\n/**\n * Identifiers of the stream the SDK has just opened for the session.\n *\n * Handed to {@link AgentManagerCallbacks.onStreamCreated | onStreamCreated} once the server has\n * accepted the stream, before the first video frame arrives. Log the three ids together: they are\n * what identifies the session in D-ID's own records.\n *\n * @category Callbacks & Events\n */\nexport interface StreamCreatedInfo {\n /**\n * Id of the agent the stream was opened for.\n */\n agentId: string;\n\n /**\n * Id of the session; the SDK sends it back on every subsequent request for this stream.\n * On Expressive (V4) agents it is the same value as\n * {@link StreamCreatedInfo.streamId | streamId}.\n */\n sessionId: string;\n\n /**\n * Id of the stream itself.\n */\n streamId: string;\n}\n\n/**\n * Callback set consumed by the streaming managers (WebRTC and LiveKit).\n * The agent manager adapts these into the public {@link AgentManagerCallbacks}.\n * @internal Implementation type; not part of the public SDK surface.\n */\nexport interface StreamingManagerCallbacks {\n onMessage?: ChatProgressCallback;\n onConnectionStateChange?: (state: ConnectionState, reason?: string) => void;\n onVideoStateChange?: (state: StreamingState, report?: VideoRTCStatsReport) => void;\n onSrcObjectReady?: (value: MediaStream) => void;\n onError?: ErrorReporter;\n onConnectivityStateChange?: (state: ConnectivityState) => void;\n onAgentActivityStateChange?: (state: AgentActivityState) => void;\n onVideoIdChange?: (videoId: string | null) => void;\n onStreamCreated?: (stream: StreamCreatedInfo) => void;\n onStreamReady?: () => void;\n onToolEvent?: ToolEventCallback;\n onInterruptibleChange?: AgentManagerCallbacks['onInterruptibleChange'];\n onRunningToolCallsChange?: AgentManagerCallbacks['onRunningToolCallsChange'];\n onFirstAudioDetected?: (metrics: AudioDetectionMetrics) => void;\n}\n\n/**\n * Latency measurements captured when the first audio frame of a stream is detected.\n * @internal Implementation type; not part of the public SDK surface.\n */\nexport interface AudioDetectionMetrics {\n latency?: number;\n networkLatency?: number;\n}\n\n/**\n * Union of callback names accepted by {@link StreamingManagerCallbacks}.\n * @internal Implementation type; not part of the public SDK surface.\n */\nexport type ManagerCallbackKeys = keyof StreamingManagerCallbacks;\n\n/**\n * Custom end-user metadata attached to a stream creation request.\n * @internal Implementation type; not part of the public SDK surface.\n */\nexport interface StreamEndUserData {\n plan?: string;\n}\n\n/**\n * Options for creating a legacy (talk) stream, combining the wire request with fluent-mode extras.\n * @internal Implementation type; not part of the public SDK surface.\n */\nexport interface TalkStreamOptions extends CreateTalkStreamRequest {\n fluent?: boolean;\n end_user_data?: StreamEndUserData;\n}\n\n/**\n * Options for creating a clip stream, combining the wire request with fluent-mode extras.\n * @internal Implementation type; not part of the public SDK surface.\n */\nexport interface ClipStreamOptions extends CreateClipStreamRequest {\n fluent?: boolean;\n end_user_data?: StreamEndUserData;\n}\n\n/**\n * Options accepted when creating a stream, discriminated by the underlying stream type (talk or clip).\n * @internal Implementation type; not part of the public SDK surface.\n */\nexport type CreateStreamOptions = TalkStreamOptions | ClipStreamOptions;\n\n/**\n * Maps a {@link CreateStreamOptions} variant to the payload type sent to drive that stream.\n * @internal Implementation type; not part of the public SDK surface.\n */\nexport type PayloadType<T> = T extends TalkStreamOptions\n ? SendTalkStreamPayload\n : T extends ClipStreamOptions\n ? SendClipStreamPayload\n : never;\n\n/**\n * HTTP client surface used by the streaming managers to create and drive a WebRTC stream.\n * @internal Implementation type; not part of the public SDK surface.\n */\nexport interface RtcApi {\n createStream(options: CreateStreamOptions, signal?: AbortSignal): Promise<ICreateStreamRequestResponse>;\n startConnection(\n streamId: string,\n answer: RTCSessionDescriptionInit,\n sessionId?: string,\n signal?: AbortSignal\n ): Promise<Status>;\n addIceCandidate(\n streamId: string,\n candidate: IceCandidate,\n sessionId: string,\n signal?: AbortSignal\n ): Promise<Status>;\n sendStreamRequest(\n streamId: string,\n sessionId: string,\n payload: SendClipStreamPayload | SendTalkStreamPayload\n ): Promise<SpeakResponse>;\n close(streamId: string, sessionId: string): Promise<Status>;\n}\n\n/**\n * Options used to construct a streaming manager (WebRTC or LiveKit) instance.\n * @internal Implementation type; not part of the public SDK surface.\n */\nexport interface StreamingManagerOptions {\n callbacks: StreamingManagerCallbacks;\n baseURL?: string;\n debug?: boolean;\n verbose?: boolean;\n auth: Auth;\n analytics: Analytics;\n /**\n * RPC methods to register on the room before it connects, so the agent can\n * call them from the moment this participant joins.\n * @internal\n */\n rpcMethods?: ReadonlyMap<string, RpcMethodHandler>;\n}\n\n/**\n * Trimmed set of WebRTC inbound video stats sampled from `RTCStatsReport`, sampled for internal quality analytics.\n * @internal Implementation type; not part of the public SDK surface.\n */\nexport interface SlimRTCStatsReport {\n index: number;\n codec: string;\n rtt: number;\n duration?: number;\n bitrate?: number;\n timestamp: any;\n bytesReceived: any;\n packetsReceived: any;\n packetsLost: any;\n framesDropped: any;\n framesDecoded: any;\n jitter: any;\n jitterBufferDelay: number;\n jitterBufferEmittedCount: number;\n avgJitterDelayInInterval: number;\n frameWidth: any;\n frameHeight: any;\n framesPerSecond: any;\n freezeCount: number;\n freezeDuration: number;\n av?: AvSyncSample;\n}\n\n/**\n * A single audio/video playout timestamp pair sampled during an utterance, used to compute lip-sync drift.\n * @internal Implementation type; not part of the public SDK surface.\n */\nexport interface AvSyncSample {\n /** Audio estimatedPlayoutTimestamp (ms, NTP) — playout time of the audio sample currently being rendered. */\n audioPlayout: number;\n /** Video estimatedPlayoutTimestamp (ms, NTP) — playout time of the video frame currently being rendered. */\n videoPlayout: number;\n /** Local timestamp of this sample (ms) — the video inbound-rtp report timestamp; the utterance time axis. */\n localTs: number;\n}\n\n/**\n * Lip-sync (audio/video) drift analysis computed over an utterance's `AvSyncSample`s.\n * @internal Implementation type; not part of the public SDK surface.\n */\nexport interface AvSyncReport {\n /** Measurable samples in this utterance (both audio and video playout present). Report is null if fewer than 2. */\n sampleCount: number;\n /** Measurement window in milliseconds (first to last sample). */\n durationMs: number;\n /** How long the A/V offset was perceptibly off (audio ahead > 45ms or behind > 100ms) — the \"was there a lip-sync issue, and for how long\" signal. */\n desyncDurationMs: number;\n /** The single worst offset (largest magnitude), signed. Positive = audio ahead of video, negative = video ahead. */\n maxOffsetMs: number;\n /** Settled offset after startup (signed median over the back half). ~0 = recovered; non-zero = persistent lip-sync error. */\n residualOffsetMs: number;\n}\n\n/**\n * WebRTC video stats reported to analytics (Mixpanel) at stream end.\n * @internal Implementation type; not part of the public SDK surface.\n */\nexport interface AnalyticsRTCStatsReport {\n timestamp?: number;\n duration: number;\n bytesReceived: number;\n bitrate: number;\n packetsReceived: number;\n packetsLost: number;\n framesDropped: number;\n framesDecoded: number;\n jitter: number;\n jitterBufferDelay: number;\n jitterBufferEmittedCount: number;\n avgJitterDelayInInterval: number;\n framesPerSecond: number;\n freezeCount: number;\n freezeDuration: number;\n lowFpsCount?: number;\n causes?: string[];\n}\n\n/**\n * Data-channel payload notifying that the current stream utterance was interrupted.\n * @internal Implementation type; not part of the public SDK surface.\n */\nexport interface StreamInterruptPayload {\n type: StreamEvents.StreamInterrupt;\n videoId: string;\n timestamp: number;\n}\n\n/**\n * A client tool's implementation: the function that runs in the browser when the agent calls it.\n *\n * Register it with {@link AgentManager.registerClientTool | registerClientTool()}, under the tool\n * name defined in the agent's configuration. The SDK parses the arguments the agent's LLM produced\n * and passes them in; whatever the handler resolves with is sent back to the agent as the tool's\n * result. Throwing rejects the call, and the error message (at most 256 bytes) is forwarded to the\n * agent. The server gives a handler 10 seconds unless the tool's configuration sets a `timeout`.\n * Expressive (V4) agents only: {@link AgentManager.registerClientTool | registerClientTool()}\n * throws a {@link ValidationError} on a Talks (V2) or Clips (V3) agent.\n *\n * @param args - The arguments the LLM produced for this call, already parsed from JSON.\n * @returns The tool's result as a string, at most 15 KiB (the LiveKit RPC response limit; a larger\n * result fails the call). Return JSON: the server parses it, and passes other text on as it is. A synchronous handler may return the string\n * directly; the SDK awaits the result either way.\n * @example\n * ```ts\n * agentManager.registerClientTool('get_cart_total', async args => {\n * const total = await cart.total(args.currency as string);\n * return JSON.stringify({ total });\n * });\n *\n * // Nothing to await: the string is enough.\n * agentManager.registerClientTool('get_locale', () => JSON.stringify({ locale: navigator.language }));\n * ```\n * @category Callbacks & Events\n */\nexport type ClientToolHandler = (args: Record<string, unknown>) => string | Promise<string>;\n\n/**\n * Whether the agent waits for a tool call to finish before it carries on.\n *\n * Set on the agent's tool configuration, and reported on {@link RunningToolCall.executionMode} and\n * {@link ToolCallStartedPayload.executionMode}. Only a `blocking` call suspends the agent, which\n * is why one being outstanding is what makes the agent uninterruptible — see\n * {@link AgentManagerCallbacks.onInterruptibleChange | onInterruptibleChange}.\n *\n * @category Callbacks & Events\n */\nexport type ToolExecutionMode = 'blocking' | 'async';\n\n/**\n * A tool call currently running in the session.\n *\n * The entries of the array given to\n * {@link AgentManagerCallbacks.onRunningToolCallsChange | onRunningToolCallsChange}. A call appears\n * when it starts and disappears when it finishes, fails, or — for a `blocking` call — when its turn\n * ends; an `async` call outlives its turn.\n *\n * @category Callbacks & Events\n */\nexport interface RunningToolCall {\n /**\n * Id of this call, matching the {@link ToolCallStartedPayload.callId | callId} of the\n * {@link ToolCallStartedPayload} that announced it.\n */\n callId: string;\n /** Name of the tool being called, as configured on the agent. */\n name: string;\n /**\n * Whether the agent is suspended while this call runs.\n *\n * `blocking` means the agent waits for the result before it can continue; `async` means it\n * keeps talking while the call runs. See {@link ToolExecutionMode}.\n */\n executionMode: ToolExecutionMode;\n}\n\n/**\n * The payload of a {@link ToolCallEvent.Started} event: the agent has begun a tool call.\n *\n * Delivered to {@link AgentManagerCallbacks.onToolEvent | onToolEvent} — see\n * {@link ToolEventCallback}.\n *\n * @category Callbacks & Events\n */\nexport interface ToolCallStartedPayload {\n /** Id of this call. The matching done or error payload carries the same id. */\n callId: string;\n /** Name of the tool the agent is calling, as configured on the agent. */\n name: string;\n /** The arguments the agent's LLM produced for this call. Sent only in {@link AgentManagerOptions.verbose | verbose} sessions. */\n input?: Record<string, unknown>;\n /**\n * The tool's result, when the server sent one.\n *\n * The event is emitted before the tool has run, so it is normally absent; read the\n * {@link ToolCallDonePayload.output | output} of the matching done event instead.\n */\n output?: Record<string, unknown>;\n /**\n * Whether the server considers the agent interruptible while this call is outstanding.\n *\n * Informational: the SDK does not forward it.\n * {@link AgentManagerCallbacks.onInterruptibleChange | onInterruptibleChange} is derived from\n * the {@link ToolCallStartedPayload.executionMode | executionMode} of the calls still\n * running, not from this field.\n */\n interruptible: boolean;\n /**\n * Whether the agent waits for this call. See {@link ToolExecutionMode}.\n *\n * Always present: a server event that omits it, or carries anything other than `async`, is\n * reported as `'blocking'` — the same normalization\n * {@link RunningToolCall.executionMode | RunningToolCall.executionMode} applies, so the two\n * agree about the same call.\n */\n executionMode: ToolExecutionMode;\n /** The conversational turn this call belongs to, or `null` when it belongs to no turn. */\n turnId?: number | null;\n /** When the call started, as reported by the server. */\n timestamp: string;\n}\n\n/**\n * The payload of a {@link ToolCallEvent.Done} event: a tool call finished successfully.\n *\n * Delivered to {@link AgentManagerCallbacks.onToolEvent | onToolEvent} — see\n * {@link ToolEventCallback}.\n *\n * @category Callbacks & Events\n */\nexport interface ToolCallDonePayload {\n /** Id of the call that finished, matching the {@link ToolCallStartedPayload} that announced it. */\n callId: string;\n /** Name of the tool that was called. */\n name: string;\n /** The arguments the call was made with. Sent only in {@link AgentManagerOptions.verbose | verbose} sessions. */\n input?: Record<string, unknown>;\n /** The result the tool returned. Sent only in {@link AgentManagerOptions.verbose | verbose} sessions. */\n output?: Record<string, unknown>;\n /** How long the call took, in milliseconds. Sent only in {@link AgentManagerOptions.verbose | verbose} sessions. */\n durationMs?: number;\n /** Any additional metadata the tool reported alongside its result. Sent only in {@link AgentManagerOptions.verbose | verbose} sessions. */\n extra?: Record<string, unknown>;\n /** When the call finished, as reported by the server. */\n timestamp: string;\n}\n\n/**\n * The payload of a {@link ToolCallEvent.Error} event: a tool call failed.\n *\n * Delivered to {@link AgentManagerCallbacks.onToolEvent | onToolEvent} — see\n * {@link ToolEventCallback}. Read {@link ToolCallErrorPayload.error | error} for what went wrong.\n * The agent carries on with the conversation; the SDK does not retry.\n *\n * @category Callbacks & Events\n */\nexport interface ToolCallErrorPayload {\n /** Id of the call that failed, matching the {@link ToolCallStartedPayload} that announced it. */\n callId: string;\n /** Name of the tool that was called. */\n name: string;\n /** The arguments the call was made with. Sent only in {@link AgentManagerOptions.verbose | verbose} sessions. */\n input?: Record<string, unknown>;\n /**\n * Whatever the failed call produced, if anything. Sent only in {@link AgentManagerOptions.verbose | verbose} sessions.\n *\n * Any JSON value — the server's own type for a tool result is unconstrained, and on a failure\n * it is commonly the reason as a plain string rather than a structured result. Narrow it\n * before use. The string case is also given to you as\n * {@link ToolCallErrorPayload.error | error}, which is what to show.\n */\n output?: unknown;\n /** How long the call ran before failing, in milliseconds. Sent only in {@link AgentManagerOptions.verbose | verbose} sessions. */\n durationMs?: number;\n /** Any additional metadata the server reported with the failure. Sent only in {@link AgentManagerOptions.verbose | verbose} sessions. */\n extra?: Record<string, unknown>;\n /**\n * What went wrong, in one line, when the server said. Only verbose sessions carry it.\n *\n * Taken from the failure the server reports in {@link ToolCallErrorPayload.extra | extra}\n * (`extra.error.message`), and from {@link ToolCallErrorPayload.output | output} when that is\n * a plain string instead. Absent when the server sent neither, which is why an application\n * that shows the reason needs a fallback of its own; the full structured failure — its kind,\n * code and any data — is in `extra.error`.\n */\n error?: string;\n /** When the call failed, as reported by the server. */\n timestamp: string;\n}\n\n/**\n * Union of the three tool-call payloads. {@link ToolEventCallback} pairs each one with its event,\n * so a handler never sees this union.\n * @internal Implementation type; not part of the public SDK surface.\n */\nexport type ToolEventPayload = ToolCallStartedPayload | ToolCallDonePayload | ToolCallErrorPayload;\n\n/**\n * Data-channel wire shape of a `tool-call/started` event, converted to\n * {@link ToolCallStartedPayload} before it reaches the application.\n * @internal Wire type of the streaming transport; not part of the public SDK surface.\n */\nexport interface ToolCallStartedWirePayload {\n call_id: string;\n name: string;\n input?: Record<string, unknown>;\n output?: Record<string, unknown>;\n interruptible?: boolean;\n execution_mode?: ToolExecutionMode;\n turn_id?: number | null;\n timestamp: string;\n}\n\n/**\n * Data-channel wire shape of a `tool-call/done` event, converted to {@link ToolCallDonePayload}\n * before it reaches the application.\n * @internal Wire type of the streaming transport; not part of the public SDK surface.\n */\nexport interface ToolCallDoneWirePayload {\n call_id: string;\n name: string;\n input?: Record<string, unknown>;\n output?: Record<string, unknown>;\n duration_ms?: number;\n extra?: Record<string, unknown>;\n timestamp: string;\n}\n\n/**\n * Data-channel wire shape of a `tool-call/error` event, converted to {@link ToolCallErrorPayload}\n * before it reaches the application.\n * @internal Wire type of the streaming transport; not part of the public SDK surface.\n */\nexport interface ToolCallErrorWirePayload extends Omit<ToolCallDoneWirePayload, 'output'> {\n // Any JSON value: the server's `ToolResult.output` is unconstrained, and some failures carry\n // the reason as a plain string here instead of a result.\n output?: unknown;\n}\n\n/**\n * The failure the server describes under a `tool-call/error` event's `extra.error`.\n * @internal Wire type of the streaming transport; not part of the public SDK surface.\n */\nexport interface ToolCallWireError {\n kind?: string;\n code?: number | string;\n message?: string;\n data?: unknown;\n}\n\n/**\n * Data-channel payload identifying the conversational turn a `turn/started` or `turn/ended` event belongs to.\n * @internal Implementation type; not part of the public SDK surface.\n */\nexport interface TurnEventPayload {\n turn_id: number | null;\n}\n\n/**\n * Why the server ended the session.\n *\n * Arrives as the `reason` argument of\n * {@link AgentManagerCallbacks.onConnectionStateChange | onConnectionStateChange} together with\n * {@link ConnectionState.Disconnected | 'disconnected'}, and is how you tell a session the server\n * closed on purpose from a connection that simply dropped — `reason` is an opaque transport\n * diagnostic in the latter case, so compare it against these values rather than parsing it. A\n * close reason the SDK does not recognize is forwarded as-is, which is the other reason to compare\n * against the enum. Which members can arrive depends on the agent type: Talks (V2) and Clips (V3)\n * agents report only {@link StreamEndReason.Ok | Ok},\n * {@link StreamEndReason.UnknownError | UnknownError},\n * {@link StreamEndReason.NetworkIssue | NetworkIssue} and\n * {@link StreamEndReason.Inactivity | Inactivity}.\n * {@link AgentManager.reconnect | reconnect()} still works afterwards; it starts a new stream\n * rather than resuming the ended one.\n *\n * @example Reacting to the limits an Expressive (V4) session reports\n * ```ts\n * import { ConnectionState, StreamEndReason, type AgentManagerCallbacks } from '@d-id/client-sdk';\n *\n * const callbacks: AgentManagerCallbacks = {\n * onConnectionStateChange(state, reason) {\n * if (state !== ConnectionState.Disconnected) return;\n *\n * if (reason === StreamEndReason.TimeLimit || reason === StreamEndReason.MessageLimit) {\n * showMessage('This session has reached its limit.');\n * } else if (reason === StreamEndReason.Inactivity) {\n * showMessage('The session timed out.');\n * }\n * },\n * };\n * ```\n * @category Callbacks & Events\n */\nexport enum StreamEndReason {\n /** The session ended normally, because it was closed deliberately. */\n Ok = 'ok',\n /** The session ended because of a failure the server could not classify. */\n UnknownError = 'unknown_error',\n /** The session ended because the connection to the browser broke down. */\n NetworkIssue = 'network_issue',\n /**\n * The session ended because it reached the message limit configured for the agent.\n *\n * Expressive (V4) agents.\n */\n MessageLimit = 'message_limit',\n /**\n * The session ended because it reached its maximum duration.\n *\n * Expressive (V4) agents.\n */\n TimeLimit = 'time_limit',\n /**\n * The session ended because nothing happened for too long.\n *\n * The window is {@link StreamOptions.sessionTimeout | sessionTimeout} for Talks (V2) and\n * Clips (V3).\n */\n Inactivity = 'inactivity',\n /**\n * The agent itself ended the call.\n *\n * Expressive (V4) agents.\n */\n EndedByAgent = 'ended_by_agent',\n}\n\n/**\n * The handler type for {@link AgentManagerCallbacks.onToolEvent | onToolEvent}: the event argument\n * narrows the payload argument.\n *\n * One signature over three argument pairs, one pair per tool-call event, so the first argument\n * narrows the second: a handler written against this type sees exactly one of\n * {@link ToolCallStartedPayload}, {@link ToolCallDonePayload} and {@link ToolCallErrorPayload},\n * never a union of the three — in an inline `onToolEvent(event, data) { … }` handler as much as in\n * a standalone function annotated with this type. A payload that does not belong to its event is\n * rejected. Expressive (V4) agents only.\n *\n * @param args - The event and the payload it carries, as one pair:\n * {@link ToolCallEvent.Started} with a {@link ToolCallStartedPayload} — the call the agent has just\n * begun, with the arguments its LLM produced; {@link ToolCallEvent.Done} with a\n * {@link ToolCallDonePayload} — the call that has just finished, with the result the tool returned;\n * or {@link ToolCallEvent.Error} with a {@link ToolCallErrorPayload} — the call that has just\n * failed, with the reason in {@link ToolCallErrorPayload.error | error} when the server gave one.\n *\n * @example\n * ```ts\n * import { AgentManagerCallbacks, ToolCallEvent } from '@d-id/client-sdk';\n *\n * const callbacks: AgentManagerCallbacks = {\n * onToolEvent(event, data) {\n * if (event === ToolCallEvent.Started) {\n * console.log('started', data.name, data.input);\n * } else if (event === ToolCallEvent.Done) {\n * console.log('done', data.name, data.output, data.durationMs);\n * } else {\n * console.log('failed', data.name, data.error ?? 'no reason given');\n * }\n * },\n * };\n * ```\n * @category Callbacks & Events\n */\nexport type ToolEventCallback = (\n ...args:\n | [event: ToolCallEvent.Started, data: ToolCallStartedPayload]\n | [event: ToolCallEvent.Done, data: ToolCallDonePayload]\n | [event: ToolCallEvent.Error, data: ToolCallErrorPayload]\n) => void;\n","/**\n * Transport used to establish a session created via the v2 sessions API.\n * @internal Wire type of the streaming transport; not part of the public SDK surface.\n */\nexport enum TransportProvider {\n Livekit = 'livekit',\n}\n\n/**\n * Wire request body for creating a session via the v2 sessions API.\n * @internal Wire type of the streaming transport; not part of the public SDK surface.\n */\nexport interface CreateSessionV2Options {\n transport: {\n provider: TransportProvider.Livekit;\n };\n chat_persist?: boolean;\n verbose?: boolean;\n}\n\n/**\n * Wire response of the v2 sessions API's session-creation request.\n * @internal Wire type of the streaming transport; not part of the public SDK surface.\n */\nexport interface CreateSessionV2Response {\n id: string;\n session_url: string;\n session_token: string;\n interrupt_enabled: boolean;\n}\n","/**\n * The text-to-speech engines a voice in D-ID's catalog can be served by.\n *\n * The value of {@link Voice.provider}, and of the `type` field that discriminates the provider\n * objects a speak script accepts: {@link Providers.Microsoft} selects a {@link MicrosoftTtsProvider},\n * {@link Providers.Elevenlabs} an {@link ElevenlabsTtsProvider} and {@link Providers.AzureOpenAi}\n * an {@link AzureOpenAiTtsProvider}. The other values appear only in the catalog.\n *\n * @category Voice\n */\nexport enum Providers {\n /** Amazon Polly. Catalog only: agents cannot speak with an Amazon voice. */\n Amazon = 'amazon',\n /** Azure OpenAI text-to-speech; see {@link AzureOpenAiTtsProvider}. */\n AzureOpenAi = 'azure-openai',\n /** Microsoft Azure text-to-speech; see {@link MicrosoftTtsProvider}. */\n Microsoft = 'microsoft',\n /** ElevenLabs text-to-speech; see {@link ElevenlabsTtsProvider}. */\n Elevenlabs = 'elevenlabs',\n /** Cartesia text-to-speech. Available as the configured voice of Expressive (V4) agents only. */\n Cartesia = 'cartesia',\n}\n\n/**\n * Who may use a voice.\n *\n * The value of {@link Voice.access}, so an application listing voices can show or hide the ones the\n * account cannot select.\n *\n * @category Voice\n */\nexport enum VoiceAccess {\n /** Available to every account. */\n Public = 'public',\n /** Available to accounts whose plan includes premium voices. */\n Premium = 'premium',\n /** Available only to the account the voice belongs to. */\n Private = 'private',\n /** A voice from the account's own ElevenLabs account, used with its ElevenLabs API key. */\n ExternalPrivate = 'external-private',\n}\n\n/**\n * One voice in D-ID's catalog of text-to-speech voices.\n *\n * The SDK does not fetch voices itself; the type is exported so an application that lists them —\n * to build a voice picker, say — can type the result and then feed {@link Voice.id | id} and\n * {@link Voice.provider | provider} into the provider object it passes as\n * {@link TextStreamScript.provider}. {@link Voice.provider | provider} is the wide\n * {@link Providers} enum, while each provider variant requires its own literal `type`, so switch\n * on it to build the matching variant, for example {@link Providers.Elevenlabs} to an\n * {@link ElevenlabsTtsProvider}. The catalog also lists voices agents cannot speak with (Google\n * voices, for example), so keep only the providers {@link TtsProvider} has a variant for.\n *\n * @category Voice\n */\nexport interface Voice {\n /** Identifier of the voice: the value to pass as a provider object's `voice_id`. */\n id: string;\n /** Display name of the voice. */\n name: string;\n /** The gender the voice is labelled with. */\n gender: string;\n /** Each language the voice speaks, with its locale code such as `en-US`. */\n languages: {\n /** The language, as a name such as `English`. */\n language: string;\n /** Its locale code, such as `en-US`. */\n locale: string;\n /** The accent, when the catalog names one. */\n accent?: string;\n }[];\n /** Which accounts may use the voice. See {@link VoiceAccess}. */\n access: VoiceAccess;\n /** The provider that serves the voice. See {@link Providers}. */\n provider: Providers;\n /** The speaking styles this particular voice offers, for example as a\n * {@link VoiceConfigMicrosoft.style | style}. Styles differ from voice to voice. */\n styles: string[];\n /** The language of the voice, as a name rather than a locale code, when the catalog sets one. */\n language?: string;\n}\n\n/**\n * Selects an ElevenLabs voice for {@link TextStreamScript.provider}. Available on paid plans.\n *\n * @category Voice\n */\nexport interface ElevenlabsTtsProvider {\n /** `'elevenlabs'`, or {@link Providers.Elevenlabs}. */\n type: `${Providers.Elevenlabs}`;\n\n /**\n * Id of the voice to speak with, from D-ID's list of ElevenLabs voices.\n *\n * @example \"21m00Tcm4TlvDq8ikWAM\"\n * @see [ElevenLabs voices](https://docs.d-id.com/docs/tts-elevenlabs)\n */\n voice_id: string;\n\n /** Voice settings; see {@link VoiceConfigElevenlabs}. */\n voice_config?: VoiceConfigElevenlabs;\n}\n\n/**\n * Selects a Microsoft Azure voice for {@link TextStreamScript.provider}.\n *\n * @category Voice\n */\nexport interface MicrosoftTtsProvider {\n /** `'microsoft'`, or {@link Providers.Microsoft}. */\n type: `${Providers.Microsoft}`;\n\n /**\n * Id of the voice to speak with, from D-ID's list of Microsoft Azure voices.\n *\n * @example \"en-US-JennyNeural\"\n * @see [Microsoft Azure voices](https://docs.d-id.com/docs/tts-microsoft)\n */\n voice_id: string;\n\n /**\n * How the voice should deliver the text: style, rate and pitch. See\n * {@link VoiceConfigMicrosoft}.\n */\n voice_config?: VoiceConfigMicrosoft;\n\n /**\n * @internal Not accepted by the Agents API, whose provider schema allows only `type`,\n * `voice_id`, `voice_config` and `language`.\n */\n voice_name?: string;\n\n /**\n * @internal Not accepted by the Agents API, whose provider schema allows only `type`,\n * `voice_id`, `voice_config` and `language`.\n */\n voice_language?: string;\n}\n\n/**\n * Selects an Azure OpenAI voice for {@link TextStreamScript.provider}.\n *\n * The same shape as {@link MicrosoftTtsProvider}, with the `type` naming Azure OpenAI. Azure\n * ignores `voice_config.rate` for these voices.\n *\n * @category Voice\n */\nexport interface AzureOpenAiTtsProvider extends Omit<MicrosoftTtsProvider, 'type'> {\n /** `'azure-openai'`, or {@link Providers.AzureOpenAi}. */\n type: `${Providers.AzureOpenAi}`;\n}\n\n/**\n * How a Microsoft Azure or Azure OpenAI voice should deliver the text.\n *\n * The `voice_config` of {@link MicrosoftTtsProvider} and {@link AzureOpenAiTtsProvider}. Every\n * field is optional; when one is omitted the Agents API applies its own default.\n *\n * @category Voice\n */\nexport interface VoiceConfigMicrosoft {\n /** Speaking style, such as `cheerful`; {@link Voice.styles} lists what a voice offers. */\n style?: string;\n\n /**\n * The speed of the voice.\n * The value is relative to 1, 0.5 being half speed, 2 being twice as fast, etc.\n * Another option is a constant value from x-slow/slow/medium/fast/x-fast.\n * @example \"0.5\"\n */\n rate?: string;\n\n /**\n * The pitch of the voice.\n * Value could be an absolute value in Hz (including units), a relative value in Hz or st(semitones)\n * or a constant value from x-low/low/medium/high/x-high.\n * @example \"+2st\"\n */\n pitch?: string;\n}\n\n/**\n * ElevenLabs voice settings: how stable the voice is and how closely it adheres to the source voice.\n *\n * The `voice_config` of {@link ElevenlabsTtsProvider}. Every field is optional.\n *\n * @see [ElevenLabs on D-ID](https://docs.d-id.com/docs/tts-elevenlabs)\n *\n * @category Voice\n */\nexport interface VoiceConfigElevenlabs {\n /**\n * How stable the voice is, and how much each generation varies.\n *\n * A number from 0 to 1: lower is more expressive and more variable between generations, higher\n * is flatter and more repeatable.\n * @example 0.5\n */\n stability?: number;\n\n /**\n * How closely the synthesized speech should adhere to the original voice it was cloned from.\n *\n * A number from 0 to 1: higher follows the original more strictly.\n * @example 0.5\n */\n similarity_boost?: number;\n}\n\n/**\n * The provider object a speak script accepts.\n *\n * This is the type of {@link TextStreamScript.provider}. Pick the variant for the provider you\n * want and give it the `voice_id` to speak with and an optional `voice_config`; `type`\n * discriminates the union.\n *\n * @example\n * ```ts\n * import { Providers } from '@d-id/client-sdk';\n *\n * const speak = await agentManager.speak({\n * type: 'text',\n * input: \"Hi! I'm Alice!\",\n * provider: { type: Providers.Microsoft, voice_id: 'en-US-JennyNeural' },\n * });\n * ```\n * @category Voice\n */\nexport type TtsProvider = MicrosoftTtsProvider | AzureOpenAiTtsProvider | ElevenlabsTtsProvider;\n","export const noop = (..._args: unknown[]) => {};\nexport const sleep = (ms: number) => new Promise(resolve => setTimeout(resolve, ms));\nexport const getRandom = (length: number = 16) => {\n const arr = new Uint8Array(length);\n globalThis.crypto.getRandomValues(arr);\n return Array.from(arr, byte => byte.toString(16).padStart(2, '0'))\n .join('')\n .slice(0, 13);\n};\n","import { Auth } from '@sdk/types/auth';\nimport { getRandom } from '@sdk/utils';\n\nexport function getExternalId(externalId?: string): string {\n if (externalId !== undefined) {\n window.localStorage.setItem('did_external_key_id', externalId);\n return externalId;\n }\n\n let key = window.localStorage.getItem('did_external_key_id');\n\n if (!key) {\n let newKey = getRandom();\n window.localStorage.setItem('did_external_key_id', newKey);\n key = newKey;\n }\n\n return key;\n}\n\n// Per-connection routing id, shared by WS and HTTP. Rotated by rotateConnectionId().\n// Carried in every auth header so the notifications WS adapter routes messages\n// per-connection instead of collapsing clients that share a bearer/basic credential.\n// Client-Key appends it after the external_id (`_<id>`); bearer/basic append it after\n// a `~` delimiter, which the authorizer strips before validating the token.\n// Generated on first use, not at module evaluation: `getRandom()` needs `crypto`,\n// and importing the package must not depend on a browser being present.\nlet connectionId: string | undefined;\n\nfunction getConnectionId(): string {\n return (connectionId ??= getRandom());\n}\n\nexport function rotateConnectionId() {\n connectionId = getRandom();\n}\n\nexport function getAuthHeader(auth: Auth, externalId?: string) {\n if (auth.type === 'bearer') {\n return `Bearer ${auth.token}~${getConnectionId()}`;\n } else if (auth.type === 'basic') {\n const credentials = 'token' in auth ? auth.token : btoa(`${auth.username}:${auth.password}`);\n return `Basic ${credentials}~${getConnectionId()}`;\n } else if (auth.type === 'key') {\n return `Client-Key ${auth.clientKey}.${getExternalId(externalId)}_${getConnectionId()}`;\n } else {\n throw new Error(`Unknown auth type: ${auth}`);\n }\n}\n","export const CONNECTION_RETRY_TIMEOUT_MS = 45 * 1000;\nexport const PLAYGROUND_HEADER = 'X-Playground-Chat';\nexport const MAX_CHAT_MESSAGE_LENGTH = 2000;\n","export const nodeEnv = import.meta.env.VITE_NODE_ENV as string;\nexport const didApiUrl = import.meta.env.VITE_DID_API_URL as string;\nexport const didSocketApiUrl = import.meta.env.VITE_WS_ENDPOINT as string;\nexport const mixpanelKey = import.meta.env.VITE_MIXPANEL_KEY as string;\nexport const agentId = import.meta.env.VITE_AGENT_ID as string;\n","import type { DIDError } from './did-error';\n\n/**\n * The JSON-safe payload {@link BaseError.toJson | toJson()} produces, for logs and error reports.\n *\n * Only the fields the SDK deliberately exposes are present, so the payload can be forwarded to a\n * logging service as it is. Subclasses add their own keys: {@link HttpError} adds `code` and\n * `httpStatus` and, when the failing call is known, `endpoint` and `method`; {@link NetworkError}\n * adds `endpoint`, `method`, `durationMs`, `online` and `visibility`.\n *\n * @example An HttpError from a request that was refused\n * ```json\n * {\n * \"kind\": \"HttpError\",\n * \"code\": \"InsufficientCreditsError\",\n * \"message\": \"Account has insufficient credits\",\n * \"httpStatus\": 402,\n * \"endpoint\": \"/agt_x/chat/cht_y\",\n * \"method\": \"POST\"\n * }\n * ```\n * @category Errors\n */\nexport interface ErrorJson {\n /**\n * Stable machine-readable code for the failure — the error's {@link BaseError.kind | kind}.\n */\n kind: string;\n /**\n * Human-readable description of the failure — the error's `message`.\n */\n message: string;\n /**\n * Message of the error that caused this one, truncated to 256 characters.\n *\n * Present only when {@link BaseError.originalError | originalError} is an `Error` and its\n * message differs from {@link ErrorJson.message | message}. A cause that is not an `Error` is\n * never serialized, so an arbitrary object carrying credentials cannot end up in the payload.\n */\n cause?: string;\n /**\n * The Agents API's own classification of the failure, from {@link HttpError.code | code}.\n *\n * Present on an {@link HttpError} only.\n */\n code?: string;\n /**\n * Additional fields contributed by a subclass, such as `httpStatus` on {@link HttpError}.\n *\n * Typed `unknown`, so a key that is not declared above has to be narrowed before it is used.\n */\n [key: string]: unknown;\n}\n\n/**\n * Base class of every error the SDK itself raises.\n *\n * Catching `BaseError` catches everything the SDK classified; branch on\n * {@link BaseError.kind | kind}, which is stable, rather than on the message, which is not.\n * Errors reach the application two ways, and each subclass says which applies: some are thrown to\n * the caller of the method, so they reject the promise it returned; others are handed to\n * {@link AgentManagerCallbacks.onError | onError} because no call of yours was in flight when they\n * happened. {@link HttpError} and {@link NetworkError} do both — the request that failed rejects,\n * and the callback is notified as well.\n *\n * Not everything that reaches the application is one of these. The streaming transport is the main\n * exception: a failure LiveKit raises inside a media call on an Expressive (V4) agent — no\n * microphone publication to replace, a room that is not connected — rejects with a plain `Error`,\n * and so do a few low-level guards inside {@link AgentManager.connect | connect()}, such as a\n * `livekit-client` package that is not installed, a transport the SDK does not recognize, or a\n * stream the server created without a session id. An unknown\n * {@link AgentManagerOptions.auth | auth} type is a plain `Error` too. So keep the\n * `else throw error` branch in a handler built on {@link isDIDError}.\n *\n * Subclasses: {@link HttpError}, {@link NetworkError}, {@link WsError}, {@link StreamError},\n * {@link ValidationError}, {@link ChatCreationFailed} and {@link ChatModeDowngraded}. When the\n * caught value is typed `unknown`, {@link isDIDError} narrows it to {@link DIDError}, the union of\n * those seven, so a `switch` on {@link BaseError.kind | kind} then narrows it to one class.\n *\n * @category Errors\n */\nexport class BaseError extends Error {\n /**\n * Creates an SDK error. The SDK builds these itself; applications normally only catch them.\n *\n * @param message - Human-readable description of the failure, used as the `Error` message.\n * @param kind - Stable machine-readable code for the failure.\n * @param originalError - The underlying error or value this one wraps, when there is one.\n */\n constructor(\n message: string,\n /**\n * Stable machine-readable code for this failure, and the value to branch on.\n *\n * Every subclass redeclares it as the literal it always carries, so a `switch` on `kind`\n * narrows a value {@link isDIDError} has recognized to that class: `'HttpError'` on\n * {@link HttpError}, `'NetworkError'` on {@link NetworkError}, `'WSError'` on\n * {@link WsError}, `'StreamError'` on {@link StreamError}, `'ValidationError'` on\n * {@link ValidationError}, `'ChatCreationFailed'` on {@link ChatCreationFailed} and\n * `'ChatModeDowngraded'` on {@link ChatModeDowngraded}. It stays a plain `string` here on\n * the base class: on a `BaseError` built directly it is whatever the caller passed, and\n * `'Error'` when nothing was. The Agents API's own classification of a failed request is\n * {@link HttpError.code | HttpError.code}, not this.\n */\n public readonly kind: string = 'Error',\n /**\n * The error or value that caused this one, when the SDK was wrapping something else.\n *\n * For a {@link NetworkError} this is the browser's own `fetch` rejection. It is not\n * serialized as-is: {@link BaseError.toJson | toJson()} takes only an `Error` cause's\n * message.\n */\n public readonly originalError?: unknown\n ) {\n super(message);\n Object.setPrototypeOf(this, new.target.prototype);\n }\n\n /**\n * Serializes the error into the JSON-safe {@link ErrorJson} payload for logging or reporting.\n *\n * The payload always carries {@link BaseError.kind | kind} and the message. The cause's message\n * is added only when {@link BaseError.originalError | originalError} is an `Error` and says\n * something the message does not, truncated to 256 characters; any other cause is dropped.\n * Subclasses extend the payload with the fields listed on their own pages.\n *\n * @returns The error as plain, JSON-serializable data.\n * @example An HttpError from a request that was refused\n * ```json\n * {\n * \"kind\": \"HttpError\",\n * \"code\": \"InsufficientCreditsError\",\n * \"message\": \"Account has insufficient credits\",\n * \"httpStatus\": 402,\n * \"endpoint\": \"/agt_x/chat/cht_y\",\n * \"method\": \"POST\"\n * }\n * ```\n * @example A NetworkError from a request that never left the browser\n * ```json\n * {\n * \"kind\": \"NetworkError\",\n * \"message\": \"Network request failed\",\n * \"cause\": \"Failed to fetch\",\n * \"endpoint\": \"/agt_x/chat/cht_y\",\n * \"method\": \"POST\",\n * \"durationMs\": 12,\n * \"online\": false,\n * \"visibility\": \"visible\"\n * }\n * ```\n */\n toJson(): ErrorJson {\n // the cause's message — Error causes only, and only when it adds to ours (payload is public)\n const cause = this.originalError instanceof Error ? this.originalError.message.slice(0, 256) : undefined;\n return {\n kind: this.kind,\n message: this.message,\n ...(cause && cause !== this.message ? { cause } : {}),\n };\n }\n}\n\n/**\n * Type guard that reports whether a caught value is an error raised by the SDK.\n *\n * It accepts any `Error` carrying a string `kind`, which every {@link BaseError} has, so it also\n * recognizes SDK errors that crossed a bundle boundary, where `instanceof BaseError` can fail\n * because two copies of the class are loaded. It narrows to {@link DIDError}, the union of the\n * seven subclasses, so a `switch` on {@link BaseError.kind | kind} inside the branch narrows\n * further to one class and its own fields — `error.status` on an {@link HttpError},\n * `error.key` on a {@link ValidationError}.\n *\n * The duck-typing is wider than the union it promises, so keep the `default` branch of a `switch`\n * total — {@link DIDError} says why.\n *\n * @param error - The caught value to test.\n * @returns `true` when `error` is an error the SDK raised.\n * @example\n * ```ts\n * try {\n * await agentManager.chat('What is the distance to the moon?');\n * } catch (error) {\n * if (isDIDError(error)) {\n * console.error(error.kind, error.toJson());\n *\n * if (error.kind === 'HttpError' && error.status === 401) {\n * refreshCredentials();\n * }\n * } else {\n * throw error;\n * }\n * }\n * ```\n * @category Errors\n */\nexport function isDIDError(error: unknown): error is DIDError {\n return error instanceof Error && typeof (error as { kind?: unknown }).kind === 'string';\n}\n","import { ChatMode } from '@sdk/types';\nimport { BaseError } from '../base-error';\n\n/**\n * A chat could not be created for the session.\n *\n * {@link AgentManager.chat | chat()} creates a chat on the first message when the session does not\n * have one yet; this error is thrown when that call comes back without one, so it rejects the\n * promise `chat()` returned and the user's message is not sent. It is not delivered to\n * {@link AgentManagerCallbacks.onError | onError} — catch it around `chat()`. A failing request\n * surfaces as {@link HttpError} or {@link NetworkError} instead; this error is the case where the\n * request succeeded but produced no chat.\n *\n * The message names the {@link ChatMode} in effect and whether a persistent chat was asked for, for\n * example `Failed to create persistent chat, mode: Functional`.\n * {@link BaseError.kind | kind} is `'ChatCreationFailed'`.\n *\n * @category Errors\n */\nexport class ChatCreationFailed extends BaseError {\n /**\n * Always `'ChatCreationFailed'`. Branch on it to tell this failure from the other SDK errors.\n */\n readonly kind: 'ChatCreationFailed' = 'ChatCreationFailed';\n\n /**\n * Builds the error from the attempt that failed.\n * @internal The SDK builds this itself; applications catch the error rather than construct it.\n */\n constructor(mode: ChatMode, persistent: boolean) {\n super(`Failed to create ${persistent ? 'persistent ' : ''}chat, mode: ${mode}`, 'ChatCreationFailed');\n }\n}\n","import { ChatMode } from '@sdk/types';\nimport { BaseError } from '../base-error';\n\n/**\n * The server created the chat in a mode that cannot stream video.\n *\n * Raised while {@link AgentManager.connect | connect()} runs on a Talks (V2) or Clips (V3) agent,\n * when the chat the server created is in a mode other than the session's (`Functional` by default)\n * and that mode is not {@link ChatMode.Functional | Functional}: {@link ChatMode.TextOnly | TextOnly}\n * or {@link ChatMode.Maintenance | Maintenance}, for instance. The SDK\n * disconnects the stream it had just opened and `connect()` resolves anyway, so no video will play\n * and {@link AgentManagerCallbacks.onSrcObjectReady | onSrcObjectReady} will not fire again: the\n * session continues as a text chat.\n *\n * It is delivered to {@link AgentManagerCallbacks.onError | onError} and never thrown, so\n * `connect()` does not reject on it.\n * {@link AgentManagerCallbacks.onModeChange | onModeChange} fires with the new mode just after it.\n * Treat it as a signal to switch the interface to text, not as a connection failure.\n * {@link BaseError.kind | kind} is `'ChatModeDowngraded'`.\n *\n * @category Errors\n */\nexport class ChatModeDowngraded extends BaseError {\n /**\n * Always `'ChatModeDowngraded'`. Branch on it to tell this failure from the other SDK errors.\n */\n readonly kind: 'ChatModeDowngraded' = 'ChatModeDowngraded';\n\n /**\n * Builds the error from the mode the session ended up in.\n * @internal The SDK builds this itself; applications catch the error rather than construct it.\n */\n constructor(mode: ChatMode) {\n super(`Chat mode downgraded to ${mode}`, 'ChatModeDowngraded');\n }\n}\n","import { BaseError, ErrorJson } from './base-error';\nimport { RequestMeta } from './request-meta';\n\ninterface ServerErrorBody {\n kind?: string;\n description?: string;\n}\n\n// The backend serializes errors as `{ kind, description }`; parse it to reuse the server's classification.\nfunction parseServerError(body: string): ServerErrorBody | undefined {\n try {\n const parsed = JSON.parse(body);\n if (parsed && typeof parsed === 'object' && typeof parsed.kind === 'string') {\n return parsed as ServerErrorBody;\n }\n } catch {\n // not a JSON envelope\n }\n return undefined;\n}\n\n/**\n * A request to the Agents API came back with a non-2xx status.\n *\n * Raised for every REST call the SDK makes on the application's behalf: fetching the agent in\n * {@link createAgentManager}, creating the stream and the chat during\n * {@link AgentManager.connect | connect()}, sending a message with\n * {@link AgentManager.chat | chat()}, and the rating and feedback calls. The same error is both\n * handed to {@link AgentManagerCallbacks.onError | onError} and thrown, so it also rejects the\n * promise of whichever method made the request — catch it around that call, or handle it centrally\n * in the callback. For the message-send request behind {@link AgentManager.chat | chat()} the\n * callback may not fire; the error is still thrown. Typical cases are `401` or `403` for a client\n * key that is not authorized for the agent or the calling domain, and `404` for an unknown agent\n * id; an account that is out of credits comes back with {@link HttpError.code | code}\n * `'InsufficientCreditsError'`. An agent that is still being built comes back with `409` and code\n * `'NotReadyError'`, and one whose build failed or was rejected with `409` and code\n * `'ConflictError'`. A `429` is retried twice, one second apart (three attempts in total), before it\n * surfaces.\n *\n * {@link BaseError.kind | kind} is always `'HttpError'`, so a `switch` on it narrows a caught value\n * to this class. The server's own classification lives on {@link HttpError.code | code} — the\n * `'InsufficientCreditsError'` above is one — so a message-independent branch on a specific API\n * failure is possible.\n *\n * The message is the envelope's `description` when the body is that JSON, and the raw body\n * otherwise — truncated to 256 characters either way, because a gateway can answer a 5xx with a\n * whole HTML page.\n *\n * @category Errors\n */\nexport class HttpError extends BaseError {\n /**\n * Always `'HttpError'`. Branch on it to tell this failure from the other SDK errors.\n */\n readonly kind: 'HttpError' = 'HttpError';\n\n /**\n * The Agents API's own classification of the failure — the `kind` from D-ID's\n * `{ kind, description }` error body — and `'HttpError'` when the response was not that\n * envelope.\n *\n * An account out of credits comes back as `'InsufficientCreditsError'`, for instance. It is a\n * plain `string` because the set is the API's, not the SDK's, and grows without an SDK release.\n * Use {@link HttpError.status | status} for the transport-level branch, this for the API-level\n * one, and {@link BaseError.kind | kind} to tell an `HttpError` from the SDK's other errors.\n */\n readonly code: string;\n\n /**\n * HTTP status code of the response, such as `401`, `404` or `500`.\n */\n readonly status: number;\n /**\n * Path of the request that failed, relative to the API client's base path — for example\n * `/agt_x/chat/cht_y` for a message sent to a chat.\n *\n * Absent when the error was constructed without call context. {@link NetworkError.endpoint}\n * is the same value on a transport failure.\n */\n readonly endpoint?: string;\n /**\n * HTTP method of the request that failed, such as `GET` or `POST`.\n *\n * Absent when the error was constructed without call context.\n */\n readonly method?: string;\n\n /**\n * Builds the error from the failing response.\n * @internal The SDK builds this itself; applications catch the error rather than construct it.\n */\n constructor(status: number, body: string, meta: RequestMeta = {}) {\n const parsed = parseServerError(body);\n // Cap the body — a non-JSON 5xx (e.g. a gateway's HTML page) is the only unbounded message source.\n super((parsed?.description ?? body).slice(0, 256), 'HttpError');\n\n this.code = parsed?.kind ?? 'HttpError';\n this.status = status;\n this.endpoint = meta.endpoint;\n this.method = meta.method;\n }\n\n /**\n * Serializes the error, adding the failing call to what\n * {@link BaseError.toJson | BaseError.toJson()} already returns.\n *\n * Adds {@link HttpError.code | code}, `httpStatus` from {@link HttpError.status | status}, and\n * `endpoint` and `method` when the call context is known. The raw `status` property is\n * serialized as `httpStatus`.\n *\n * @returns The error as plain, JSON-serializable data.\n */\n toJson(): ErrorJson {\n return {\n ...super.toJson(),\n code: this.code,\n httpStatus: this.status,\n ...(this.endpoint ? { endpoint: this.endpoint } : {}),\n ...(this.method ? { method: this.method } : {}),\n };\n }\n}\n","import { BaseError, ErrorJson } from './base-error';\n\nimport { RequestMeta } from './request-meta';\n\n/**\n * A request to the Agents API never reached the server, so no response came back.\n *\n * This is the transport failure counterpart of {@link HttpError}, where the server did answer: the\n * browser's `fetch` rejected outright because the device is offline, DNS or TLS failed, the\n * connection was refused or the request was blocked, for instance by CORS or an extension. Like\n * {@link HttpError} it is both handed to {@link AgentManagerCallbacks.onError | onError} and\n * thrown, so it also rejects the promise of the method that made the request; for the message-send\n * request behind {@link AgentManager.chat | chat()} the callback may not fire, but the error is\n * still thrown. A request the SDK cancelled itself is not reported this way — the browser's own\n * `AbortError` is rethrown unchanged.\n *\n * The message is always `'Network request failed'`; the browser's own wording, such as\n * `'Failed to fetch'`, is kept in {@link BaseError.originalError | originalError} and appears as\n * `cause` in {@link NetworkError.toJson | toJson()}. The remaining properties record what was\n * happening at the time, which is usually what distinguishes a dropped connection from a tab that\n * was backgrounded.\n *\n * @category Errors\n */\nexport class NetworkError extends BaseError {\n /**\n * Always `'NetworkError'`. Branch on it to tell this failure from the other SDK errors.\n */\n readonly kind: 'NetworkError' = 'NetworkError';\n\n /**\n * Path of the request that failed, relative to the API client's base path — for example\n * `/agt_x/chat/cht_y`.\n */\n readonly endpoint?: string;\n /**\n * HTTP method of the request that failed, such as `GET` or `POST`.\n */\n readonly method?: string;\n /**\n * How long the request ran before it failed, in milliseconds.\n *\n * A value close to zero usually means the request never left the browser; a large one points\n * at a connection that was established and then lost.\n */\n readonly durationMs?: number;\n /**\n * The browser's `navigator.onLine` at the moment of the failure — `false` when the device\n * reported itself offline.\n */\n readonly online?: boolean;\n /**\n * The page's `document.visibilityState` at the moment of the failure.\n *\n * `'hidden'` means the tab was in the background, where browsers throttle or suspend network\n * activity.\n */\n readonly visibility?: DocumentVisibilityState;\n\n /**\n * Wraps a rejected `fetch` together with what was known about the call.\n * @internal The SDK builds this itself; applications catch the error rather than construct it.\n */\n constructor(originalError?: unknown, meta: RequestMeta = {}) {\n super('Network request failed', 'NetworkError', originalError);\n this.endpoint = meta.endpoint;\n this.method = meta.method;\n this.durationMs = meta.durationMs;\n this.online = meta.online;\n this.visibility = meta.visibility;\n }\n\n /**\n * Serializes the error, adding the captured context to what\n * {@link BaseError.toJson | BaseError.toJson()} already returns.\n *\n * Each of `endpoint`, `method`, `durationMs`, `online` and `visibility` is included only when it\n * was captured.\n *\n * @returns The error as plain, JSON-serializable data.\n */\n toJson(): ErrorJson {\n return {\n ...super.toJson(),\n ...(this.endpoint ? { endpoint: this.endpoint } : {}),\n ...(this.method ? { method: this.method } : {}),\n ...(this.durationMs !== undefined ? { durationMs: this.durationMs } : {}),\n ...(this.online !== undefined ? { online: this.online } : {}),\n ...(this.visibility ? { visibility: this.visibility } : {}),\n };\n }\n}\n","import { BaseError } from './base-error';\n\n/**\n * Something went wrong inside the live audio and video stream.\n *\n * Unlike {@link HttpError} and {@link NetworkError}, which come from REST calls, this one comes\n * from the transport carrying the agent's video, so it is only ever delivered to\n * {@link AgentManagerCallbacks.onError | onError} — no call of yours is necessarily in flight when\n * it happens, and nothing throws it. The SDK raises it when:\n *\n * - no media track is subscribed within the timeout after the LiveKit room used by Expressive (V4)\n * agents connects, after which the SDK disconnects the stream;\n * - the LiveKit room reports a media-device or encryption failure;\n * - a message cannot be put on the data channel — the WebRTC channel used by Talks (V2) and Clips\n * (V3) is not open, or the LiveKit room is not connected or rejects the send;\n * - the server reports that the stream itself failed, with the message\n * `Stream failed with event <event>`.\n *\n * Most of these leave the session unusable, so the useful response is to tell the user and call\n * {@link AgentManager.reconnect | reconnect()}. {@link BaseError.kind | kind} is `'StreamError'`.\n * The message describes the failure, and is the plain `'Stream Error'` when the transport gave no\n * detail; the underlying error, where there was one, is kept as\n * {@link BaseError.originalError | originalError}.\n *\n * @category Errors\n */\nexport class StreamError extends BaseError {\n /**\n * Always `'StreamError'`. Branch on it to tell this failure from the other SDK errors.\n */\n readonly kind: 'StreamError' = 'StreamError';\n\n /**\n * Wraps a streaming failure.\n * @internal The SDK builds this itself; applications catch the error rather than construct it.\n */\n constructor(message: string, originalError?: unknown) {\n super(message, 'StreamError', originalError);\n }\n}\n","import { BaseError } from './base-error';\n\n/**\n * A method was called with arguments, or in a state, that the SDK will not send to the Agents\n * API.\n *\n * This is one of the two SDK errors that only ever reach the caller and are never delivered to\n * {@link AgentManagerCallbacks.onError | onError} (the other is {@link ChatCreationFailed}): it is\n * the direct answer to the call you just made, and every method that raises it rejects the promise\n * it returned, so `await` the call inside a `try`/`catch` or attach a `.catch()`. The SDK raises it\n * from\n * {@link AgentManager.chat | chat()} when the message is empty or 2000 characters or longer, when\n * the session's {@link ChatMode} has chat disabled or is in maintenance, and when the chat or the\n * stream has not been initialized yet; from {@link AgentManager.speak | speak()} when it is called\n * before {@link AgentManager.connect | connect()}; and from\n * {@link AgentManager.rate | rate()}, {@link AgentManager.deleteRate | deleteRate()} and\n * {@link AgentManager.submitFeedback | submitFeedback()} when no chat has started, plus, for\n * `rate()` alone, when no message with the given id is in the transcript. It is also raised from\n * {@link createAgentManager} and {@link AgentManager.changeMode | changeMode()} when an Expressive\n * (V4) agent is asked for {@link ChatMode.Off} or {@link ChatMode.DirectPlayback}, which only Talks\n * (V2) and Clips (V3) agents support. The five Expressive-only media methods —\n * {@link AgentManager.publishMicrophoneStream | publishMicrophoneStream()},\n * {@link AgentManager.replaceMicrophoneTrack | replaceMicrophoneTrack()},\n * {@link AgentManager.publishCameraStream | publishCameraStream()},\n * {@link AgentManager.setSttLanguage | setSttLanguage()} and\n * {@link AgentManager.sendDataChannelMessage | sendDataChannelMessage()} — raise it the other way\n * round: when the session is a Talks (V2) or Clips (V3) one, or\n * {@link AgentManager.connect | connect()} has not run yet.\n *\n * Nothing was sent to the Agents API when this is raised, so the session stays usable: fix the\n * argument or wait for {@link ConnectionState.Connected | 'connected'} and call again.\n * {@link BaseError.kind | kind} is `'ValidationError'`.\n *\n * @category Errors\n */\nexport class ValidationError extends BaseError {\n /**\n * Always `'ValidationError'`. Branch on it to tell this failure from the other SDK errors.\n */\n readonly kind: 'ValidationError' = 'ValidationError';\n\n /**\n * Builds a validation failure. The SDK does this itself before it performs a request.\n *\n * @param message - What was wrong with the call, such as `'Message cannot be empty'`.\n * @param key - Name of the field the failure is about. The SDK's own validations leave it\n * unset.\n */\n constructor(\n message: string,\n /**\n * Name of the field the failure is about.\n *\n * The SDK does not populate it — every validation it raises passes the message alone — so it\n * is only set on a `ValidationError` an application constructed itself. It is also left out\n * of {@link BaseError.toJson | toJson()}, so a serialized validation error carries only its\n * kind and message.\n */\n public readonly key?: string\n ) {\n super(message, 'ValidationError');\n }\n}\n","import { BaseError } from './base-error';\n\n/**\n * The web socket the SDK uses for chat notifications failed to connect.\n *\n * Talks (V2) and Clips (V3) sessions open a web socket alongside the video stream; the agent's\n * answer arrives over it as `partial` and `answer` events, which is what drives\n * {@link AgentManagerCallbacks.onNewMessage | onNewMessage}. This error is raised when that socket\n * emits an `error` event, once per failed attempt while\n * {@link AgentManager.connect | connect()} is retrying. It is only delivered to\n * {@link AgentManagerCallbacks.onError | onError} and never thrown, so there is nothing to catch\n * around `connect()` for it; if every attempt fails, `connect()` rejects with the browser's own\n * socket event instead.\n *\n * The socket is not opened at all for Expressive (V4) agents, which receive the same events over\n * the LiveKit data channel, nor in {@link ChatMode.DirectPlayback | DirectPlayback} mode, so the\n * error cannot occur in either case.\n *\n * {@link BaseError.kind | kind} is `'WSError'`, and the message is\n * `'Websocket failed to connect'`.\n *\n * @category Errors\n */\nexport class WsError extends BaseError {\n /**\n * Always `'WSError'` — note the capitalization, which does not match the class name.\n */\n readonly kind: 'WSError' = 'WSError';\n\n /**\n * Wraps a web socket failure, built from the socket's `error` event.\n * @internal The SDK builds this itself; applications catch the error rather than construct it.\n */\n constructor(message: string) {\n super(message, 'WSError');\n }\n}\n","import { Agent, AvatarType } from '@sdk/types';\n\ntype AgentType = 'clip_v2' | Agent['avatar']['type'];\n\nexport type PresenterType = 'v4' | 'v3-pro' | 'v2' | 'image';\n\nexport const getAgentType = (presenter: Agent['avatar']): AgentType => presenter.type;\n\nexport const getPresenterType = (presenter: Agent['avatar']): PresenterType => {\n // A hand-built `Agent` can carry a value outside the enum at runtime; answer with the least\n // capable tier.\n if (presenter.type === AvatarType.Expressive) return 'v4';\n if (presenter.type === AvatarType.Clip) return 'v3-pro';\n if (presenter.type === AvatarType.Image) return 'image';\n\n return 'v2';\n};\n\nexport const isStreamsV2Agent = (type: AgentType): boolean =>\n type === AvatarType.Expressive || type === AvatarType.Image;\n","import { ChatMode } from '@sdk/types';\n\nexport const isTextualChat = (chatMode: ChatMode) =>\n [ChatMode.TextOnly, ChatMode.Playground, ChatMode.Maintenance].includes(chatMode);\n\nexport const isChatModeWithoutChat = (chatMode: ChatMode | undefined) =>\n chatMode && [ChatMode.DirectPlayback, ChatMode.Off].includes(chatMode);\n","import { MessagePart } from '@sdk/types/entities/agents/chat';\n\n// Video thumbnail syntax: [](video-url)\nconst VIDEO_THUMBNAIL_RE = /\\[!\\[([^\\[\\]]*)\\]\\(([^)\\s]+)\\)\\]\\(([^)\\s]+)\\)/g;\n\n// Standard markdown image: \nconst IMAGE_RE = /!\\[([^\\[\\]]*)\\]\\(([^)\\s]+)\\)/g;\n\nconst VIDEO_EXTENSIONS = ['.mp4', '.webm', '.mkv', '.mov', '.m4v', '.ogv'];\n\nfunction isVideoUrl(url: string): boolean {\n const path = url.split('?')[0].split('#')[0].toLowerCase();\n return VIDEO_EXTENSIONS.some(ext => path.endsWith(ext));\n}\n\n// Standard markdown link: [label](url) — but NOT images (no leading !)\nconst MD_LINK_RE = /(?<!!)\\[([^\\[\\]]+)\\]\\(([^)\\s]+)\\)/g;\n\n// HTML anchor: <a href=\"url\">label</a>\nconst HTML_LINK_RE = /<a\\s+href=\"([^\"]*)\"[^>]*?>([^<]*)<\\/a>/gi;\n\ninterface MatchEntry {\n index: number;\n length: number;\n part: MessagePart;\n}\n\n/**\n * Splits a message's text into the typed {@link MessagePart | parts} a UI can render.\n *\n * The SDK already runs it over every message it builds and keeps the result on\n * {@link Message.parts}, so this is for content that comes from somewhere else — a transcript you\n * render outside the SDK, or text you assembled before handing it to a renderer.\n * {@link AgentManagerOptions.initialMessages | initialMessages} no longer need it: pass `parts: []`\n * and the SDK runs this for you. It recognizes markdown\n * images (``), the video thumbnail form (`[](video)`), markdown links\n * (`[label](url)`) and HTML anchors (`<a href=\"url\">label</a>`); an image whose URL looks like a\n * video becomes a `video` part instead, and a GIF is tagged with a `mimeType`, both under the rules\n * {@link MessagePart} sets out. Everything the parser does not recognize is preserved verbatim as a\n * `text` part, in its original order, and nothing is dropped or reordered; each recognized part\n * replaces the markup it was written as, so the parts are not a concatenation of the input.\n *\n * @param content - The message text to split, as it appears in {@link Message.content}.\n * @returns The parts in the order they appear in `content`: a single `text` part when there is no\n * markup to find, and an empty array for an empty string.\n * @example\n * ```ts\n * import { parseMessageParts } from '@d-id/client-sdk';\n *\n * parseMessageParts('Here it is:  — enjoy!');\n * // [\n * // { type: 'text', text: 'Here it is: ' },\n * // { type: 'image', src: 'https://example.com/cat.png', alt: 'a cat' },\n * // { type: 'text', text: ' — enjoy!' },\n * // ]\n * ```\n * @category Chat\n */\nexport function parseMessageParts(content: string): MessagePart[] {\n if (content.length === 0) {\n return [];\n }\n\n const matches: MatchEntry[] = [];\n\n let m: RegExpExecArray | null;\n\n // 1. Video thumbnail: [](video) — must be matched first\n VIDEO_THUMBNAIL_RE.lastIndex = 0;\n while ((m = VIDEO_THUMBNAIL_RE.exec(content)) !== null) {\n matches.push({\n index: m.index,\n length: m[0].length,\n part: { type: 'video', src: m[3], alt: m[1], thumbnail: m[2] },\n });\n }\n\n // 2. Markdown images:  — skip those already consumed by video thumbnails.\n // A URL with a video extension is classified as video even without thumbnail syntax,\n // since backends frequently emit naked `` for video assets.\n IMAGE_RE.lastIndex = 0;\n while ((m = IMAGE_RE.exec(content)) !== null) {\n const overlaps = matches.some(entry => m!.index >= entry.index && m!.index < entry.index + entry.length);\n if (!overlaps) {\n const src = m[2];\n const alt = m[1];\n let part: MessagePart;\n if (isVideoUrl(src)) {\n part = { type: 'video', src, alt };\n } else {\n part = { type: 'image', src, alt };\n if (src.toLowerCase().endsWith('.gif')) {\n (part as Extract<MessagePart, { type: 'image' }>).mimeType = 'image/gif';\n }\n }\n matches.push({ index: m.index, length: m[0].length, part });\n }\n }\n\n // 3. Markdown links: [label](url) — skip those already consumed\n MD_LINK_RE.lastIndex = 0;\n while ((m = MD_LINK_RE.exec(content)) !== null) {\n const overlaps = matches.some(entry => m!.index >= entry.index && m!.index < entry.index + entry.length);\n if (!overlaps) {\n matches.push({\n index: m.index,\n length: m[0].length,\n part: { type: 'link', href: m[2], label: m[1] },\n });\n }\n }\n\n // 4. HTML links: <a href=\"url\">label</a> — skip those already consumed\n HTML_LINK_RE.lastIndex = 0;\n while ((m = HTML_LINK_RE.exec(content)) !== null) {\n const overlaps = matches.some(entry => m!.index >= entry.index && m!.index < entry.index + entry.length);\n if (!overlaps) {\n matches.push({\n index: m.index,\n length: m[0].length,\n part: { type: 'link', href: m[1], label: m[2] },\n });\n }\n }\n\n // No matches → single text part\n if (matches.length === 0) {\n return [{ type: 'text', text: content }];\n }\n\n // Sort by position\n matches.sort((a, b) => a.index - b.index);\n\n // Build parts array with text gaps\n const parts: MessagePart[] = [];\n let cursor = 0;\n\n for (const entry of matches) {\n if (entry.index > cursor) {\n parts.push({ type: 'text', text: content.slice(cursor, entry.index) });\n }\n parts.push(entry.part);\n cursor = entry.index + entry.length;\n }\n\n if (cursor < content.length) {\n parts.push({ type: 'text', text: content.slice(cursor) });\n }\n\n return parts;\n}\n\n// Single-entry memoization — optimal for streaming where the same content string\n// is checked multiple times per render cycle\nlet memoKey: string = '';\nlet memoValue: MessagePart[] = [];\n\nexport function parseMessagePartsMemo(content: string): MessagePart[] {\n if (content === memoKey) {\n return memoValue;\n }\n memoKey = content;\n memoValue = parseMessageParts(content);\n return memoValue;\n}\n","import { sleep } from '.';\n\ninterface RetryOptions {\n limit?: number;\n delayMs?: number;\n timeout?: number;\n timeoutErrorMessage?: string;\n shouldRetryFn?: (error: any) => boolean;\n onRetry?: (error: any) => void | Promise<void>;\n}\n\nfunction createRacePromise(timeout: number, timeoutErrorMessage: string) {\n let timeId: ReturnType<typeof setTimeout> | undefined;\n\n const promise = new Promise<never>((_, reject) => {\n timeId = setTimeout(() => reject(new Error(timeoutErrorMessage)), timeout);\n });\n\n return {\n promise,\n clear: () => clearTimeout(timeId),\n };\n}\n\n/**\n * Utility function to retry a promise operation with configurable retry logic\n *\n * @param operation - A function that returns a Promise to be retried\n * @param userOptions - Configuration options for retry behavior\n * @param userOptions.limit - Maximum number of retry attempts (default: 3)\n * @param userOptions.delayMs - Delay between retries in milliseconds (default: 0, no delay)\n * @param userOptions.timeout - Timeout for each attempt in milliseconds (default: 30000, set 0 to disable)\n * @param userOptions.timeoutErrorMessage - Custom timeout error message\n * @param userOptions.shouldRetryFn - Function to determine if retry should occur based on error, that will force throw even if limit is not reached when returns \"false\"\n * @param userOptions.onRetry - Called after the delay and before the next attempt; awaited, so an\n * asynchronous handler finishes before the operation runs again\n *\n * @returns Promise that resolves with the operation result or rejects with the last error\n *\n * @throws {Error} Last error encountered after all retries are exhausted\n * @throws {Error} Timeout error if operation exceeds specified timeout\n *\n * @example\n * // With custom options\n * const result = await retryOperation(\n * async () => await fetch(url),\n * {\n * limit: 5,\n * delayMs: 1000,\n * timeout: 5000,\n * shouldRetryFn: (error) => error.status === 429\n * }\n * );\n */\nexport async function retryOperation<T>(operation: () => Promise<T>, userOptions?: RetryOptions): Promise<T> {\n const options: Required<RetryOptions> = {\n limit: userOptions?.limit ?? 3,\n delayMs: userOptions?.delayMs ?? 0,\n timeout: userOptions?.timeout ?? 30000,\n timeoutErrorMessage: userOptions?.timeoutErrorMessage || 'Timeout error',\n shouldRetryFn: userOptions?.shouldRetryFn ?? (() => true),\n onRetry: userOptions?.onRetry ?? (() => {}),\n };\n\n let lastError: any;\n for (let attempt = 1; attempt <= options.limit; attempt++) {\n try {\n if (!options.timeout) {\n return await operation();\n }\n\n const { promise, clear } = createRacePromise(options.timeout, options.timeoutErrorMessage);\n const operationPromise = operation().finally(clear);\n\n return await Promise.race([operationPromise, promise]);\n } catch (error) {\n lastError = error;\n\n if (!options.shouldRetryFn(error) || attempt >= options.limit) {\n throw error;\n }\n\n await sleep(options.delayMs);\n\n // Awaited: the chat retry's `onRetry` tears the session down and opens a new one, and\n // without this the next attempt ran against a session that was still being replaced.\n await options.onRetry(error);\n }\n }\n\n throw lastError;\n}\n","import { HttpError, NetworkError } from '@sdk/errors';\nimport { Auth } from '@sdk/types/auth';\nimport { ErrorReporter } from '@sdk/types/error-context';\nimport { retryOperation } from '@sdk/utils/retry-operation';\nimport { getAuthHeader } from '../auth/get-auth-header';\nimport { didApiUrl } from '../config/environment';\n\nexport type RequestOptions = RequestInit & {\n skipErrorHandler?: boolean;\n};\n\n/**\n * Internal marker thrown from the retried fetch so `retryOperation` sees a 429 as a failure.\n * `fetch` resolves on a 429, so without this the retry predicate would never match.\n */\nclass TooManyRequests {\n readonly status = 429;\n\n constructor(readonly response: Response) {}\n}\n\nconst retryHttpTooManyRequests = <T>(operation: () => Promise<T>): Promise<T> =>\n retryOperation(operation, {\n limit: 3,\n delayMs: 1000,\n timeout: 0,\n shouldRetryFn: error => error.status === 429,\n });\n\nexport function createClient(auth: Auth, host = didApiUrl, onError?: ErrorReporter, externalId?: string) {\n const client = async <T>(url: string, options?: RequestOptions) => {\n const { skipErrorHandler, ...fetchOptions } = options || {};\n const method = fetchOptions.method ?? 'GET';\n const start = performance.now();\n\n let request: Response;\n try {\n request = await retryHttpTooManyRequests(async () => {\n const response = await fetch(host + (url?.startsWith('/') ? url : `/${url}`), {\n ...fetchOptions,\n headers: {\n ...fetchOptions.headers,\n Authorization: getAuthHeader(auth, externalId),\n 'Content-Type': 'application/json',\n },\n });\n\n if (response.status === 429) {\n throw new TooManyRequests(response);\n }\n\n return response;\n });\n } catch (networkError) {\n if (networkError instanceof TooManyRequests) {\n // retries are exhausted; let the rate-limited response take the normal HttpError path\n request = networkError.response;\n } else {\n // no response reached us (offline / DNS / refused / TLS / CORS); AbortError is a cancellation\n const isAbort = (networkError as { name?: string })?.name === 'AbortError';\n if (isAbort) {\n throw networkError;\n }\n\n const error = new NetworkError(networkError, {\n endpoint: url,\n method,\n durationMs: Math.round(performance.now() - start),\n online: typeof navigator !== 'undefined' ? navigator.onLine : undefined,\n visibility: typeof document !== 'undefined' ? document.visibilityState : undefined,\n });\n if (!skipErrorHandler) {\n onError?.(error, { endpoint: url, method });\n }\n throw error;\n }\n }\n\n if (!request.ok) {\n const errorText = await request.text().catch(() => `Failed to fetch with status ${request.status}`);\n const error = new HttpError(request.status, errorText, { endpoint: url, method });\n\n if (!skipErrorHandler) {\n onError?.(error, { endpoint: url, method });\n }\n\n throw error;\n }\n\n return request.json() as Promise<T>;\n };\n\n return {\n get<T = any>(url: string, options?: RequestOptions) {\n return client<T>(url, { ...options, method: 'GET' });\n },\n post<T = any>(url: string, body?: any, options?: RequestOptions) {\n return client<T>(url, { ...options, body: JSON.stringify(body), method: 'POST' });\n },\n delete<T = any>(url: string, body?: any, options?: RequestOptions) {\n return client<T>(url, { ...options, body: JSON.stringify(body), method: 'DELETE' });\n },\n patch<T = any>(url: string, body?: any, options?: RequestOptions) {\n return client<T>(url, { ...options, body: JSON.stringify(body), method: 'PATCH' });\n },\n };\n}\n","import {\n Agent,\n Auth,\n Chat,\n ChatPayload,\n ChatResponse,\n ErrorReporter,\n Rating,\n RatingPayload,\n SttTokenResponse,\n SubmitFeedbackResponse,\n} from '@sdk/types/index';\nimport { didApiUrl } from '../config/environment';\nimport { RequestOptions, createClient } from './apiClient';\n\nexport function createAgentsApi(auth: Auth, host: string = didApiUrl, onError?: ErrorReporter, externalId?: string) {\n const client = createClient(auth, `${host}/agents`, onError, externalId);\n\n return {\n getRuntimeById(id: string, options?: RequestOptions) {\n return client.get<Agent>(`/${id}/runtime`, options);\n },\n newChat(agentId: string, payload: { persist: boolean }, options?: RequestOptions) {\n return client.post<Chat>(`/${agentId}/chat`, payload, options);\n },\n chat(agentId: string, chatId: string, payload: ChatPayload, options?: RequestOptions) {\n return client.post<ChatResponse>(`/${agentId}/chat/${chatId}`, payload, options);\n },\n createRating(agentId: string, chatId: string, payload: RatingPayload, options?: RequestOptions) {\n return client.post<Rating>(`/${agentId}/chat/${chatId}/ratings`, payload, options);\n },\n updateRating(\n agentId: string,\n chatId: string,\n ratingId: string,\n payload: Partial<RatingPayload>,\n options?: RequestOptions\n ) {\n return client.patch<Rating>(`/${agentId}/chat/${chatId}/ratings/${ratingId}`, payload, options);\n },\n deleteRating(agentId: string, chatId: string, ratingId: string, options?: RequestOptions) {\n return client.delete<Rating>(`/${agentId}/chat/${chatId}/ratings/${ratingId}`, options);\n },\n submitFeedback(\n agentId: string,\n chatId: string,\n payload: { rating: number; answer?: string },\n options?: RequestOptions\n ) {\n return client.post<SubmitFeedbackResponse>(`/${agentId}/chat/${chatId}/feedback`, payload, options);\n },\n getSttToken(agentId: string, options?: RequestOptions) {\n return client.get<SttTokenResponse>(`/${agentId}/stt-token`, options);\n },\n };\n}\n","import { Agent } from '@sdk/types/index';\nimport { getAgentType, getPresenterType } from './agent';\n\nexport function getAnalyticsInfo(agent: Agent) {\n const mobileOrDesktop = () => {\n return /Mobi|Android/i.test(navigator.userAgent) ? 'Mobile' : 'Desktop';\n };\n const getUserOS = () => {\n const platform = navigator.platform;\n\n if (platform.toLowerCase().includes('win')) {\n return 'Windows';\n } else if (platform.toLowerCase().includes('mac')) {\n return 'Mac OS X';\n } else if (platform.toLowerCase().includes('linux')) {\n return 'Linux';\n } else {\n return 'Unknown'; // Unable to determine the OS\n }\n };\n const presenter = agent.avatar;\n\n return {\n $os: `${getUserOS()}`,\n isMobile: `${mobileOrDesktop() == 'Mobile'}`,\n browser: navigator.userAgent,\n origin: window.location.origin,\n agentType: getAgentType(presenter),\n agentVoice: {\n language: agent.avatar?.voice?.language,\n },\n };\n}\n\nexport function getAgentInfo(agent: Agent) {\n return {\n agentType: getAgentType(agent.avatar),\n presenterType: getPresenterType(agent.avatar),\n owner_id: agent.owner_id ?? '',\n starterQuestionsCount: agent.starter_message?.length,\n agentId: agent.id,\n agentName: agent.name,\n };\n}\nexport const getErrorMessage = (error: unknown): string => {\n try {\n return String((error as Error)?.message ?? error ?? '').slice(0, 256);\n } catch {\n return 'Unknown error';\n }\n};\n\nexport const sumFunc = (numbers: number[]) => numbers.reduce((total, aNumber) => total + aNumber, 0);\nexport const average = (numbers: number[]) => sumFunc(numbers) / numbers.length;\nexport const min = (numbers: number[]) => Math.min(...numbers);\nexport const max = (numbers: number[]) => Math.max(...numbers);\nexport const round = (value: number, decimals = 0) => {\n const factor = 10 ** decimals;\n return Math.round(value * factor) / factor;\n};\nexport const percentile = (numbers: number[], p: number) => {\n const sorted = [...numbers].sort((a, b) => a - b);\n return sorted[Math.min(sorted.length - 1, Math.floor(p * (sorted.length - 1)))];\n};\nexport const median = (numbers: number[]) => percentile(numbers, 0.5);\n/** Run fn, returning fallback instead of throwing — so a telemetry failure can never break the caller. */\nexport const safe = <T>(fn: () => T, fallback: T): T => {\n try {\n return fn();\n } catch {\n return fallback;\n }\n};\n\nexport function getStreamAnalyticsProps(data: any, agent: Agent, additionalProps: Record<string, any>) {\n const { event, ...baseProps } = data;\n\n const { language } = agent?.avatar?.voice || {};\n\n const props = {\n ...baseProps,\n script: { ...baseProps.script, provider: { ...baseProps?.script?.provider, language } },\n ...additionalProps,\n };\n\n return props;\n}\n","/**\n * Defers function execution until browser is idle to avoid blocking critical path.\n * Uses requestIdleCallback when available, falls back to setTimeout.\n *\n * @param fn - Function to execute when browser is idle\n */\nexport function defer(fn: () => void) {\n if ('requestIdleCallback' in window) {\n requestIdleCallback(fn, { timeout: 2000 });\n } else {\n setTimeout(fn, 0);\n }\n}\n","import { BaseError, ErrorJson } from '@sdk/errors';\nimport { getErrorMessage } from './analytics';\n\nexport type ErrorAnalyticsProps = ErrorJson;\n\nexport function toErrorAnalytics(error: unknown): ErrorAnalyticsProps {\n if (error instanceof BaseError) {\n return error.toJson();\n }\n\n return { kind: 'UnknownError', message: getErrorMessage(error) || 'UnknownError' };\n}\n","// Injected at build time by Vite (see vite.config.ts `define`).\ndeclare const __SDK_VERSION__: string;\n\n/**\n * Published version of the SDK this bundle was built from, `'dev'` when it runs from source.\n * Attached to every analytics event.\n *\n * @internal\n */\nexport const SDK_VERSION: string = typeof __SDK_VERSION__ === 'string' ? __SDK_VERSION__ : 'dev';\n","import { getExternalId } from '@sdk/auth/get-auth-header';\nimport { getRandom } from '@sdk/utils';\nimport { SDK_VERSION } from '@sdk/version';\n\nexport interface AnalyticsOptions {\n token: string;\n agentId: string;\n isEnabled?: boolean;\n externalId?: string;\n mixpanelAdditionalProperties?: Record<string, any>;\n}\n\nexport interface Analytics {\n token: string;\n distinct_id?: string;\n isEnabled: boolean;\n chatId?: string;\n agentId: string;\n owner_id?: string;\n getRandom(): string;\n track(event: string, props?: Record<string, any>, eventTimestamp?: number): Promise<any>;\n linkTrack(mixpanelEvent: string, props: Record<string, any>, event: string, dependencies: string[]): any;\n enrich(props: Record<string, any>): void;\n additionalProperties: Record<string, any>;\n}\n\ninterface MixpanelEvent {\n resolvedDependencies: string[];\n events: {\n [event: string]: { props: Record<string, any> };\n };\n}\n\ninterface MixpanelEvents {\n [mixpanelEvent: string]: MixpanelEvent;\n}\n\nconst mixpanelUrl = 'https://api-js.mixpanel.com/track/?verbose=1&ip=1';\n\n// Re-send analytics that failed to POST (e.g. a network drop) once connectivity returns.\nconst MAX_QUEUE = 50;\nconst failedQueue: Array<Record<string, any>> = [];\nlet flushInFlight = false;\n\nasync function postEvents(events: Array<Record<string, any>>): Promise<void> {\n const response = await fetch(mixpanelUrl, {\n method: 'POST',\n headers: { 'Content-Type': 'application/x-www-form-urlencoded' },\n body: new URLSearchParams({ data: JSON.stringify(events) }),\n });\n if (!response.ok) {\n throw new Error(`Mixpanel responded with ${response.status}`);\n }\n}\n\nfunction enqueueFailed(event: Record<string, any>): void {\n failedQueue.push(event);\n failedQueue.splice(MAX_QUEUE);\n}\n\nfunction flushQueue(): void {\n if (flushInFlight || !failedQueue.length) {\n return;\n }\n flushInFlight = true;\n const batch = failedQueue.splice(0, failedQueue.length);\n postEvents(batch)\n .catch(() => {\n failedQueue.unshift(...batch);\n failedQueue.splice(MAX_QUEUE);\n })\n .finally(() => {\n flushInFlight = false;\n });\n}\n\nif (typeof window !== 'undefined' && typeof window.addEventListener === 'function') {\n window.addEventListener('online', flushQueue);\n if (typeof document !== 'undefined') {\n document.addEventListener('visibilitychange', () => {\n if (document.visibilityState === 'visible') {\n flushQueue();\n }\n });\n }\n}\n\nexport function _resetOfflineBufferForTests(): void {\n failedQueue.length = 0;\n flushInFlight = false;\n}\n\nexport function initializeAnalytics(config: AnalyticsOptions): Analytics {\n const source = window?.hasOwnProperty('DID_AGENTS_API') ? 'agents-ui' : 'agents-sdk';\n const mixpanelEvents: MixpanelEvents = {};\n\n return {\n token: config.token || 'testKey',\n distinct_id: getExternalId(config.externalId),\n agentId: config.agentId,\n additionalProperties: {\n id: getExternalId(config.externalId),\n ...(config.mixpanelAdditionalProperties || {}),\n },\n isEnabled: config.isEnabled ?? true,\n getRandom,\n enrich(props: Record<string, any>) {\n this.additionalProperties = { ...this.additionalProperties, ...props };\n },\n async track(event: string, props?: Record<string, any>, eventTimestamp?: number) {\n if (!this.isEnabled) {\n return Promise.resolve();\n }\n\n // Ignore audioPath event from agent-video\n const { audioPath, ...sendProps } = props || {};\n\n const eventTime = eventTimestamp || Date.now();\n\n const eventData = {\n event,\n properties: {\n ...this.additionalProperties,\n ...sendProps,\n agentId: this.agentId,\n source,\n emittedBy: 'agents-sdk',\n sdkVersion: SDK_VERSION,\n token: this.token,\n time: eventTime,\n $insert_id: this.getRandom(),\n origin: window.location.href,\n 'Screen Height': window.screen.height || window.innerHeight,\n 'Screen Width': window.screen.width || window.innerWidth,\n 'User Agent': navigator.userAgent,\n },\n };\n\n flushQueue();\n postEvents([eventData]).catch(() => enqueueFailed(eventData));\n\n return Promise.resolve();\n },\n linkTrack(mixpanelEvent: string, props: Record<string, any>, event: string, dependencies: string[]) {\n if (!mixpanelEvents[mixpanelEvent]) {\n mixpanelEvents[mixpanelEvent] = { events: {}, resolvedDependencies: [] };\n }\n\n if (!dependencies.includes(event)) {\n dependencies.push(event);\n }\n\n const linkedEvent = mixpanelEvents[mixpanelEvent];\n\n linkedEvent.events[event] = { props };\n linkedEvent.resolvedDependencies.push(event);\n\n const allDependenciesResolved = dependencies.every(value =>\n linkedEvent.resolvedDependencies.includes(value)\n );\n\n if (allDependenciesResolved) {\n const aggregatedProps = dependencies.reduce((acc, curr) => {\n if (linkedEvent.events[curr]) {\n return { ...acc, ...linkedEvent.events[curr].props };\n }\n return acc;\n }, {});\n\n this.track(mixpanelEvent, aggregatedProps);\n\n linkedEvent.resolvedDependencies = linkedEvent.resolvedDependencies.filter(\n event => !dependencies.includes(event)\n );\n dependencies.forEach(event => {\n delete linkedEvent.events[event];\n });\n }\n },\n };\n}\n","function createTimestampTracker() {\n let timestamp = 0;\n\n return {\n reset: () => (timestamp = 0),\n update: () => (timestamp = Date.now()),\n get: (delta: boolean = false) => (delta ? Date.now() - timestamp : timestamp),\n };\n}\n\nexport const latencyTimestampTracker = createTimestampTracker();\nexport const interruptTimestampTracker = createTimestampTracker();\nexport const streamReadyTimestampTracker = createTimestampTracker();\n","import { PLAYGROUND_HEADER } from '@sdk/config/consts';\nimport type { Agent, AgentsAPI, Chat } from '@sdk/types';\nimport { ChatMode } from '@sdk/types';\nimport { isChatModeWithoutChat } from '@sdk/utils/chat';\nimport { Analytics } from '../analytics/mixpanel';\n\nexport function getRequestHeaders(chatMode?: ChatMode): { headers?: Record<string, string> } {\n return chatMode === ChatMode.Playground ? { headers: { [PLAYGROUND_HEADER]: 'true' } } : {};\n}\n\nexport async function createChat(\n agent: Agent,\n agentsApi: AgentsAPI,\n analytics: Analytics,\n chatMode?: ChatMode,\n persist = false,\n chat?: Chat\n) {\n // A chat handed in by the caller is carried over from an earlier connect: it still holds the\n // mode it was created in, which says nothing about this session.\n if (chat) {\n return { chat, chatMode };\n }\n\n if (!isChatModeWithoutChat(chatMode)) {\n chat = await agentsApi.newChat(agent.id, { persist }, getRequestHeaders(chatMode));\n\n analytics.track('agent-chat', {\n event: 'created',\n chatId: chat.id,\n mode: chatMode,\n });\n }\n\n return { chat, chatMode: chat?.chat_mode ?? chatMode };\n}\n","import { Message } from '@sdk/types';\nimport { parseMessageParts } from '@sdk/utils/content-parser';\n\nexport function getInitialMessages(initialMessages?: Message[]): Message[] {\n if (!initialMessages || initialMessages.length === 0) {\n return [];\n }\n\n // A restored transcript usually carries only `content`; without parts a UI that renders parts\n // shows nothing for it. Anything the caller did build itself is left alone.\n return initialMessages.map(message =>\n Array.isArray(message.parts) && message.parts.length > 0\n ? message\n : { ...message, parts: parseMessageParts(typeof message.content === 'string' ? message.content : '') }\n );\n}\n","import { getAuthHeader } from '@sdk/auth/get-auth-header';\nimport { WsError } from '@sdk/errors';\nimport { ChatProgressCallback } from '@sdk/types';\nimport { Auth } from '@sdk/types/auth';\nimport { sleep } from '@sdk/utils';\n\ninterface Options {\n auth: Auth;\n retries?: number;\n externalId?: string;\n callbacks?: {\n onMessage?: (event: MessageEvent) => void;\n onOpen?: (event: Event) => void;\n onClose?: (event: CloseEvent) => void;\n onError?: (error: string, event: Event) => void;\n };\n host?: string;\n}\n\nexport interface SocketManager {\n socket?: WebSocket;\n disconnect: () => void;\n subscribeToEvents: (data: any) => void;\n}\n\nfunction connect(options: Options): Promise<WebSocket> {\n return new Promise<WebSocket>((resolve, reject) => {\n const { callbacks, host, auth, externalId } = options;\n const { onMessage = null, onOpen = null, onClose = null, onError = null } = callbacks || {};\n const socket = new WebSocket(`${host}?authorization=${encodeURIComponent(getAuthHeader(auth, externalId))}`);\n\n socket.onmessage = onMessage;\n socket.onclose = onClose;\n\n socket.onerror = e => {\n console.error(e);\n onError?.('Websocket failed to connect', e);\n reject(e);\n };\n\n socket.onopen = e => {\n onOpen?.(e);\n resolve(socket);\n };\n });\n}\n\nasync function connectWithRetries(options: Options): Promise<WebSocket> {\n const { retries = 1 } = options;\n let socket: WebSocket | null = null;\n\n for (let attempt = 0; socket?.readyState !== WebSocket.OPEN; attempt++) {\n try {\n socket = await connect(options);\n } catch (e) {\n if (attempt === retries) {\n throw e;\n }\n\n await sleep(attempt * 500);\n }\n }\n\n return socket;\n}\n\nexport async function createSocketManager(\n auth: Auth,\n host: string,\n callbacks: {\n onMessage: ChatProgressCallback;\n onError?: (error: Error) => void;\n },\n externalId?: string\n): Promise<SocketManager> {\n const messageCallbacks: ChatProgressCallback[] = callbacks?.onMessage ? [callbacks.onMessage] : [];\n const socket: WebSocket = await connectWithRetries({\n auth,\n host,\n externalId,\n callbacks: {\n onError: error => callbacks.onError?.(new WsError(error)),\n onMessage(event: MessageEvent) {\n const parsedData = JSON.parse(event.data);\n messageCallbacks.forEach(callback => callback(parsedData.event, parsedData));\n },\n },\n });\n\n return {\n socket,\n disconnect: () => socket.close(),\n subscribeToEvents: (callback: ChatProgressCallback) => messageCallbacks.push(callback),\n };\n}\n","import { StreamEndReason } from '@sdk/types';\n\nconst LEGACY_CLOSE_REASON_TO_END_REASON: Record<string, StreamEndReason> = {\n manual: StreamEndReason.Ok,\n inactivity: StreamEndReason.Inactivity,\n peer_disconnected: StreamEndReason.NetworkIssue,\n shutdown: StreamEndReason.UnknownError,\n};\n\n/**\n * Legacy streams report the session end as `stream/done` with a `close_reason`.\n * A reason we do not recognize is forwarded as-is rather than reported as an error.\n */\nexport function toStreamEndReason(data: any): string | undefined {\n return LEGACY_CLOSE_REASON_TO_END_REASON[data.close_reason] ?? data.close_reason;\n}\n","import { StreamError } from '@sdk/errors';\nimport { Agent, AgentManagerOptions, ChatProgress, StreamEvents } from '@sdk/types';\nimport { Message } from '@sdk/types/entities/agents/chat';\nimport { getStreamAnalyticsProps } from '@sdk/utils/analytics';\nimport { parseMessagePartsMemo } from '@sdk/utils/content-parser';\nimport { toStreamEndReason } from '@sdk/utils/stream-end';\nimport { AgentManagerItems } from '../agent-manager';\nimport { Analytics } from '../analytics/mixpanel';\n\nconst COMPLETED_EVENTS = [\n StreamEvents.StreamVideoDone,\n StreamEvents.StreamVideoError,\n StreamEvents.StreamVideoRejected,\n];\nconst FAILED_EVENTS = [StreamEvents.StreamFailed, StreamEvents.StreamVideoError, StreamEvents.StreamVideoRejected];\n\nexport interface ChatEventQueue {\n [sequence: number]: string;\n answer?: string;\n}\n\nfunction getMessageContent(chatEventQueue: ChatEventQueue) {\n if (chatEventQueue['answer'] !== undefined) {\n return chatEventQueue['answer'];\n }\n\n let currentSequence = 0;\n let content = '';\n\n while (currentSequence in chatEventQueue) {\n content += chatEventQueue[currentSequence++];\n }\n\n return content;\n}\n\nfunction handleAudioTranscribedMessage(\n data: any,\n items: AgentManagerItems,\n onNewMessage: AgentManagerOptions['callbacks']['onNewMessage']\n) {\n if (!data.content) {\n return;\n }\n\n const userMessage: Message = {\n id: data.id || `user-${Date.now()}`,\n role: data.role,\n content: data.content,\n parts: parseMessagePartsMemo(data.content),\n createdAt: data.created_at || new Date().toISOString(),\n transcribed: true,\n };\n items.messages.push(userMessage);\n onNewMessage?.([...items.messages], 'user');\n}\n\nfunction processChatEvent(\n event: ChatProgress,\n data: any,\n chatEventQueue: ChatEventQueue,\n items: AgentManagerItems,\n onNewMessage: AgentManagerOptions['callbacks']['onNewMessage'],\n clearQueue: () => void,\n lastAssistantMessageType: 'partial' | 'answer' | null\n) {\n if (event === ChatProgress.Transcribe && data.content) {\n handleAudioTranscribedMessage(data, items, onNewMessage);\n return;\n }\n\n if (!(event === ChatProgress.Partial || event === ChatProgress.Answer)) {\n return;\n }\n\n const lastMessage = items.messages[items.messages.length - 1];\n\n // User sent a new message mid-stream: the orchestrator's shortened closing `answer` for the\n // abandoned reply would otherwise land as a truncated duplicate after the new user message.\n const isLateAnswerFromInterruptedStream =\n event === ChatProgress.Answer && lastMessage?.role === 'user' && lastAssistantMessageType === 'partial';\n\n if (isLateAnswerFromInterruptedStream) {\n return;\n }\n\n // `chat/answer` closes a logical assistant message: the next chat event (Partial or Answer)\n // starts a new one. This covers post-tool replies that follow a pre-tool ack within the same\n // turn, and consecutive answers in clips/talks flows. The orchestrator does not send a\n // message id, so the previous id-mismatch heuristic does not apply.\n const isNewAssistantMessage = lastAssistantMessageType === 'answer';\n\n let currentMessage: Message;\n if (lastMessage?.role === 'assistant' && !isNewAssistantMessage) {\n currentMessage = lastMessage;\n } else if (!lastMessage || lastMessage.role === 'user' || isNewAssistantMessage) {\n if (isNewAssistantMessage) {\n // Reset the streaming buffer so the next message does not inherit the previous one's content.\n clearQueue();\n }\n currentMessage = {\n id: data.id || `assistant-${Date.now()}`,\n role: data.role || 'assistant',\n // Starts empty so the content-change check below fires for this message's first chat\n // event. Seeding it with `data.content` made that check a no-op, so a message carried\n // by a single partial (e.g. a worker `say` greeting) never reached `onNewMessage`.\n content: '',\n parts: [],\n createdAt: data.created_at || new Date().toISOString(),\n };\n items.messages.push(currentMessage);\n } else {\n return;\n }\n\n const { content, sequence } = data;\n\n if (event === ChatProgress.Partial) {\n chatEventQueue[sequence] = content;\n } else {\n // Answer shorter than accumulated partials means the orchestrator cut the segment\n // short — i.e. the user interrupted mid-utterance.\n const partialsContent = getMessageContent(chatEventQueue);\n const isInterrupted = !!(content && content.length < partialsContent.length);\n if (isInterrupted) {\n currentMessage.interrupted = true;\n }\n chatEventQueue['answer'] = content;\n }\n\n const messageContent = getMessageContent(chatEventQueue);\n\n if (currentMessage.content !== messageContent || event === ChatProgress.Answer) {\n currentMessage.content = messageContent;\n currentMessage.parts = parseMessagePartsMemo(messageContent);\n\n onNewMessage?.([...items.messages], event);\n }\n}\n\nexport function createMessageEventQueue(\n analytics: Analytics,\n items: AgentManagerItems,\n options: AgentManagerOptions,\n agentEntity: Agent,\n onStreamDone: (reason?: string) => void\n) {\n const chatEventQueue: ChatEventQueue = {};\n const clearQueue = () => {\n // Mutate the queue object so closures that captured it (e.g. the parameter inside\n // `processChatEvent`) observe the reset — reassigning the outer-scope variable would\n // leave those captured references pointing at the old, populated object.\n for (const key of Object.keys(chatEventQueue)) {\n delete chatEventQueue[key as keyof ChatEventQueue];\n }\n };\n // Tracks the last assistant chat event in the current turn. `null` means \"no assistant stream\n // is in progress\" (initial state, or after a non-assistant event). The flag stays `null` for\n // the first backend partial of the greeting so it adopts the locally-pushed `agent.speak()`\n // entry instead of opening a new message.\n let lastAssistantMessageType: 'partial' | 'answer' | null = null;\n const onNewMessage: AgentManagerOptions['callbacks']['onNewMessage'] = (messages, event) => {\n if (event === 'user') {\n clearQueue();\n }\n options.callbacks.onNewMessage?.(messages, event);\n };\n\n return {\n clearQueue,\n onMessage: (event: ChatProgress | StreamEvents, data: any) => {\n if ('content' in data) {\n const chatEvent =\n event === StreamEvents.ChatAnswer\n ? ChatProgress.Answer\n : event === StreamEvents.ChatAudioTranscribed\n ? ChatProgress.Transcribe\n : (event as ChatProgress);\n processChatEvent(\n chatEvent,\n data,\n chatEventQueue,\n items,\n onNewMessage,\n clearQueue,\n lastAssistantMessageType\n );\n\n // Track the chat-event boundary directly here — relying on `onNewMessage` would\n // miss empty-content partials and the next partial would still see\n // `lastAssistantMessageType === 'answer'` and open yet another message.\n if (chatEvent === ChatProgress.Partial) {\n lastAssistantMessageType = 'partial';\n } else if (chatEvent === ChatProgress.Answer) {\n lastAssistantMessageType = 'answer';\n // Clear the streaming buffer so the next turn's content does not inherit\n // leftover partial slots from this one.\n clearQueue();\n }\n\n if (chatEvent === ChatProgress.Answer) {\n analytics.track('agent-message-received', {\n content: data.content,\n messages: items.messages.length,\n mode: items.chatMode,\n });\n }\n } else {\n const SEvent = StreamEvents;\n\n event = event as StreamEvents;\n\n if (event === SEvent.StreamVideoCreated) {\n const props = getStreamAnalyticsProps(data, agentEntity, { mode: items.chatMode });\n\n analytics.linkTrack('agent-video', props, SEvent.StreamVideoCreated, ['start']);\n\n // Attach sentiment to the last assistant message if present\n if (data.sentiment) {\n const lastMessage = items.messages[items.messages.length - 1];\n if (lastMessage?.role === 'assistant') {\n const updatedMessage = { ...lastMessage, sentiment: data.sentiment };\n items.messages[items.messages.length - 1] = updatedMessage;\n onNewMessage?.([...items.messages], lastAssistantMessageType ?? 'answer');\n }\n }\n }\n\n if (COMPLETED_EVENTS.includes(event)) {\n // Stream video event\n const streamEvent = event.split('/')[1];\n const props = getStreamAnalyticsProps(data, agentEntity, { mode: items.chatMode });\n\n if (FAILED_EVENTS.includes(event)) {\n // Dont depend on video state change if stream failed\n analytics.track('agent-video', { ...props, event: streamEvent });\n } else {\n analytics.linkTrack('agent-video', { ...props, event: streamEvent }, event, ['done']);\n }\n }\n\n if (FAILED_EVENTS.includes(event)) {\n options.callbacks.onError?.(new StreamError(`Stream failed with event ${event}`), {\n streamId: items.streamingManager?.streamId,\n });\n }\n\n if (data.event === SEvent.StreamDone) {\n onStreamDone(toStreamEndReason(data));\n }\n }\n },\n };\n}\n","import {\n Auth,\n CreateStreamOptions,\n ErrorReporter,\n ICreateStreamRequestResponse,\n IceCandidate,\n RtcApi,\n SendClipStreamPayload,\n SendTalkStreamPayload,\n SpeakWireResponse,\n Status,\n} from '@sdk/types/index';\nimport { createClient } from '../apiClient';\n\nexport function createStreamApi(auth: Auth, host: string, agentId: string, onError?: ErrorReporter): RtcApi {\n const client = createClient(auth, `${host}/agents/${agentId}`, onError);\n\n return {\n createStream(options: CreateStreamOptions, signal?: AbortSignal) {\n return client.post<ICreateStreamRequestResponse>('/streams', options, { signal });\n },\n startConnection(streamId: string, answer: RTCSessionDescriptionInit, sessionId?: string, signal?: AbortSignal) {\n return client.post<Status>(\n `/streams/${streamId}/sdp`,\n {\n session_id: sessionId,\n answer,\n },\n { signal }\n );\n },\n addIceCandidate(streamId: string, candidate: IceCandidate, sessionId: string, signal?: AbortSignal) {\n return client.post<Status>(\n `/streams/${streamId}/ice`,\n {\n session_id: sessionId,\n ...candidate,\n },\n { signal }\n );\n },\n async sendStreamRequest(\n streamId: string,\n sessionId: string,\n payload: SendClipStreamPayload | SendTalkStreamPayload\n ) {\n const wire = await client.post<SpeakWireResponse>(`/streams/${streamId}`, {\n session_id: sessionId,\n ...payload,\n });\n\n // The Agents API answers in snake_case; `SpeakResponse` is camelCase.\n return {\n status: wire.status,\n sessionId: wire.session_id,\n duration: wire.duration,\n videoId: wire.video_id,\n };\n },\n close(streamId: string, sessionId: string) {\n // Teardown is best-effort, so it is kept out of `onError`: by the time this runs the\n // session is often already gone server-side - expired while idle, or reaped when the\n // peer connection closed just before - and the `missing or invalid session_id` that\n // comes back is nothing the application can act on. `disconnect()` logs it instead.\n return client.delete<Status>(`/streams/${streamId}`, { session_id: sessionId }, { skipErrorHandler: true });\n },\n };\n}\n","import { CreateSessionV2Options, CreateStreamOptions, InterruptOptions, PayloadType, StreamType } from '@sdk/types';\nimport { InternalDataChannelTopic } from '@sdk/types/stream/data-channel';\n\nexport const createStreamingLogger = (debug: boolean, prefix: string) => (message: string, extra?: any) =>\n debug && console.log(`[${prefix}] ${message}`, extra ?? '');\n\n/**\n * Shared type for all streaming managers (LiveKit, WebRTC, etc.)\n * This type represents the return value of any streaming manager implementation\n */\nexport type StreamingManager<T extends CreateStreamOptions | CreateSessionV2Options> = {\n /**\n * Method to send request to server to get clip or talk depending on payload\n * @param payload The payload to send to the streaming service\n */\n speak(payload: PayloadType<T>): Promise<any>;\n\n /**\n * Method to close the streaming connection\n */\n disconnect(): Promise<void>;\n\n /**\n * The single send primitive: every message leaving the client goes out through here.\n * V2 routes on the topic; V1 has no topic concept and ignores it.\n * The promise tracks the send attempt and never rejects - failures go to `callbacks.onError`.\n * @param topic Data-channel topic to send on\n * @param payload The message payload to send, already serialized\n */\n sendDataChannelMessage(topic: `${InternalDataChannelTopic}`, payload: string): Promise<void>;\n\n /**\n * Publish a microphone stream to the DataChannel\n * Can be called after connection to add microphone input\n * @param stream The MediaStream containing the microphone audio track\n * supported only for livekit manager\n */\n publishMicrophoneStream?(stream: MediaStream): Promise<void>;\n\n /**\n * Unpublish the currently published microphone stream\n * Can be called after connection to remove microphone input\n * supported only for livekit manager\n */\n unpublishMicrophoneStream?(): Promise<void>;\n\n /**\n * Replace the currently published microphone MediaStreamTrack without\n * unpublishing. Preserves the LiveKit publication (SSRC, trackSid) so the\n * server sees continuous audio. Resolves once LiveKit has switched the\n * underlying RTCRtpSender's track. Rejects if no publication exists —\n * caller should fall back to `publishMicrophoneStream` in that case.\n * supported only for livekit manager\n */\n replaceMicrophoneTrack?(track: MediaStreamTrack): Promise<void>;\n\n /**\n * Publish a camera video stream to the LiveKit room.\n * Can be called after connection to enable vision.\n * supported only for livekit manager\n */\n publishCameraStream?(stream: MediaStream): Promise<void>;\n\n /**\n * Unpublish the currently published camera stream.\n * Can be called after connection to disable vision.\n * supported only for livekit manager\n */\n unpublishCameraStream?(): Promise<void>;\n\n /**\n * Session identifier information, should be returned in the body of all streaming requests\n */\n sessionId: string;\n\n /**\n * Id of current streaming session\n */\n streamId: string;\n\n /**\n * Type of streaming implementation being used\n */\n streamType: StreamType;\n\n /**\n * Whether interrupt functionality is available for this stream\n */\n interruptAvailable: boolean;\n\n /**\n * Whether the current stream segment can be interrupted by the user\n */\n isInterruptible: boolean;\n\n /**\n * Send an interrupt for the current stream segment.\n *\n * Returns whether an interrupt was actually sent: `false` when there is nothing to interrupt\n * (the stream does not support it, it is not a Fluent stream, no video is playing, or the\n * interrupt type is one this transport drops), and `false` when the transport could not carry\n * it because the connection or the data channel is not up.\n */\n interrupt(type: InterruptOptions['type']): boolean;\n\n /**\n * Register an RPC method handler on the LiveKit room.\n * Used internally by the agent-manager for client tool delegation.\n * supported only for livekit manager\n */\n registerRpcMethod?(method: string, handler: (data: any) => Promise<string>): void;\n\n /**\n * Unregister a previously registered RPC method.\n * supported only for livekit manager\n */\n unregisterRpcMethod?(method: string): void;\n};\n","import { AvSyncReport, AvSyncSample, SlimRTCStatsReport } from '@sdk/types';\nimport { median, round } from '@sdk/utils/analytics';\n\n// Perceptibility thresholds (ITU/EBU): audio ahead of video is less tolerable than audio behind.\nconst AUDIO_LEAD_PERCEPTIBLE_MS = 45;\nconst AUDIO_LAG_PERCEPTIBLE_MS = 100;\n\nexport function buildAvSyncReport(stats: SlimRTCStatsReport[]): AvSyncReport | null {\n const samples = stats\n .map(stat => stat.av)\n .filter((sample): sample is AvSyncSample => !!sample && sample.audioPlayout > 0 && sample.videoPlayout > 0);\n\n if (samples.length < 2) {\n return null;\n }\n\n const start = samples[0].localTs;\n const durationMs = samples[samples.length - 1].localTs - start;\n const offsets = samples.map(sample => sample.audioPlayout - sample.videoPlayout);\n\n const perceptible = offsets.filter(\n offset => offset > AUDIO_LEAD_PERCEPTIBLE_MS || offset < -AUDIO_LAG_PERCEPTIBLE_MS\n );\n const steady = samples.filter(sample => sample.localTs - start >= Math.min(5000, durationMs / 2));\n const steadyOffsets = (steady.length ? steady : samples).map(sample => sample.audioPlayout - sample.videoPlayout);\n\n return {\n sampleCount: samples.length,\n durationMs: round(durationMs),\n desyncDurationMs: round(durationMs * (perceptible.length / offsets.length)),\n maxOffsetMs: round(offsets.reduce((worst, offset) => (Math.abs(offset) > Math.abs(worst) ? offset : worst))),\n residualOffsetMs: round(median(steadyOffsets)),\n };\n}\n","import { AnalyticsRTCStatsReport, AvSyncReport, SlimRTCStatsReport } from '@sdk/types';\nimport { average, max, min, safe } from '@sdk/utils/analytics';\nimport { buildAvSyncReport } from './av-sync';\n\nexport interface VideoRTCStatsReport {\n webRTCStats: {\n anomalies: AnalyticsRTCStatsReport[];\n avSync: AvSyncReport | null;\n aggregateReport: AnalyticsRTCStatsReport;\n minRtt: number;\n maxRtt: number;\n avgRtt: number;\n minJitterDelayInInterval: number;\n maxJitterDelayInInterval: number;\n avgJitterDelayInInterval: number;\n };\n codec: string;\n resolution: string;\n}\n\nfunction createAggregateReport(\n start: SlimRTCStatsReport,\n end: SlimRTCStatsReport,\n lowFpsCount: number\n): AnalyticsRTCStatsReport {\n const duration = (end.timestamp - start.timestamp) / 1000;\n return {\n duration,\n bytesReceived: end.bytesReceived - start.bytesReceived,\n bitrate: Math.round(((end.bytesReceived - start.bytesReceived) * 8) / duration),\n packetsReceived: end.packetsReceived - start.packetsReceived,\n packetsLost: end.packetsLost - start.packetsLost,\n framesDropped: end.framesDropped - start.framesDropped,\n framesDecoded: end.framesDecoded - start.framesDecoded,\n jitter: end.jitter,\n avgJitterDelayInInterval:\n (end.jitterBufferDelay - start.jitterBufferDelay) /\n (end.jitterBufferEmittedCount - start.jitterBufferEmittedCount),\n jitterBufferEmittedCount: end.jitterBufferEmittedCount - start.jitterBufferEmittedCount,\n jitterBufferDelay: (end.jitterBufferDelay - start.jitterBufferDelay) / duration,\n framesPerSecond: end.framesPerSecond,\n freezeCount: end.freezeCount - start.freezeCount,\n freezeDuration: end.freezeDuration - start.freezeDuration,\n lowFpsCount,\n };\n}\n\nfunction extractAnomalies(stats: AnalyticsRTCStatsReport[]): AnalyticsRTCStatsReport[] {\n return stats\n .filter(\n report =>\n report.freezeCount > 0 ||\n report.framesPerSecond < 21 ||\n report.framesDropped > 0 ||\n report.packetsLost > 0\n )\n .map(report => {\n const { timestamp, ...updatedReport } = report;\n const causes: string[] = [];\n if (report.freezeCount > 0) {\n causes.push('freeze');\n }\n if (report.framesPerSecond < 21) {\n causes.push('low fps');\n }\n if (report.framesDropped > 0) {\n causes.push('frames dropped');\n }\n if (report.packetsLost > 0) {\n causes.push('packet loss');\n }\n return {\n ...updatedReport,\n causes,\n };\n });\n}\n\nexport function formatStats(stats: RTCStatsReport): SlimRTCStatsReport {\n let codec = '';\n let currRtt: number = 0;\n let videoInboundRtp: RTCInboundRtpStreamStats | null = null;\n let audioInboundRtp: RTCInboundRtpStreamStats | null = null;\n const codecIdToMime = new Map<string, string>();\n\n // RTCStatsReport iteration order is not guaranteed across browsers.\n // Walk the full report once to collect codec/rtt/inbound-rtp before returning,\n // otherwise we may return before the codec entry is seen and emit codec=''.\n for (const report of stats.values()) {\n if (!report) continue;\n\n if (report.type === 'codec' && report.mimeType?.startsWith('video')) {\n codecIdToMime.set(report.id, report.mimeType.split('/')[1]);\n } else if (report.type === 'candidate-pair') {\n const pair = report as RTCIceCandidatePairStats;\n const rtt = pair.currentRoundTripTime ?? 0;\n // Prefer RTT from the nominated candidate-pair (the active connection path).\n // Fall back to the first valid pair only until a nominated value arrives.\n if (rtt > 0) {\n if (pair.nominated === true) {\n currRtt = rtt;\n } else if (currRtt === 0) {\n currRtt = rtt;\n }\n }\n } else if (report.type === 'inbound-rtp' && report.kind === 'video') {\n videoInboundRtp = report as RTCInboundRtpStreamStats;\n } else if (report.type === 'inbound-rtp' && report.kind === 'audio') {\n audioInboundRtp = report;\n }\n }\n\n if (!videoInboundRtp) {\n return {} as SlimRTCStatsReport;\n }\n\n // WebRTC marks every numeric field optional, but SlimRTCStatsReport expects\n // required values. Single boundary cast avoids per-field null checks below.\n const inbound = videoInboundRtp as Required<RTCInboundRtpStreamStats>;\n\n if (inbound.codecId && codecIdToMime.has(inbound.codecId)) {\n codec = codecIdToMime.get(inbound.codecId)!;\n } else if (codecIdToMime.size > 0) {\n codec = codecIdToMime.values().next().value ?? '';\n }\n\n const slim = {\n codec,\n rtt: currRtt,\n timestamp: inbound.timestamp,\n bytesReceived: inbound.bytesReceived,\n packetsReceived: inbound.packetsReceived,\n packetsLost: inbound.packetsLost,\n framesDropped: inbound.framesDropped,\n framesDecoded: inbound.framesDecoded,\n jitter: inbound.jitter,\n jitterBufferDelay: inbound.jitterBufferDelay,\n jitterBufferEmittedCount: inbound.jitterBufferEmittedCount,\n avgJitterDelayInInterval: inbound.jitterBufferDelay / inbound.jitterBufferEmittedCount,\n frameWidth: inbound.frameWidth,\n frameHeight: inbound.frameHeight,\n framesPerSecond: inbound.framesPerSecond,\n freezeCount: inbound.freezeCount,\n freezeDuration: inbound.totalFreezesDuration,\n } as SlimRTCStatsReport;\n\n if (audioInboundRtp) {\n slim.av = {\n audioPlayout: audioInboundRtp.estimatedPlayoutTimestamp ?? 0,\n videoPlayout: inbound.estimatedPlayoutTimestamp ?? 0,\n localTs: inbound.timestamp,\n };\n }\n\n return slim;\n}\n\nexport function createVideoStatsReport(\n stats: SlimRTCStatsReport[],\n interval: number,\n previousStats?: SlimRTCStatsReport\n): VideoRTCStatsReport | null {\n // Callers can ask for a report before the first stats sample exists (e.g. a video event\n // arriving right after the track is subscribed). The aggregate below indexes stats[0], so\n // return null instead of throwing into the caller.\n if (stats.length === 0) {\n return null;\n }\n\n const differentialReport = stats.map((report, index) => {\n if (index === 0) {\n if (!previousStats) {\n return {\n timestamp: report.timestamp,\n rtt: report.rtt,\n duration: 0,\n bytesReceived: report.bytesReceived,\n bitrate: (report.bytesReceived * 8) / (interval / 1000),\n packetsReceived: report.packetsReceived,\n packetsLost: report.packetsLost,\n framesDropped: report.framesDropped,\n framesDecoded: report.framesDecoded,\n jitter: report.jitter,\n jitterBufferDelay: report.jitterBufferDelay,\n jitterBufferEmittedCount: report.jitterBufferEmittedCount,\n avgJitterDelayInInterval: report.jitterBufferDelay / report.jitterBufferEmittedCount,\n framesPerSecond: report.framesPerSecond,\n freezeCount: report.freezeCount,\n freezeDuration: report.freezeDuration,\n };\n }\n\n return {\n timestamp: report.timestamp,\n duration: 0,\n rtt: report.rtt,\n bytesReceived: report.bytesReceived - previousStats.bytesReceived,\n bitrate: ((report.bytesReceived - previousStats.bytesReceived) * 8) / (interval / 1000),\n packetsReceived: report.packetsReceived - previousStats.packetsReceived,\n packetsLost: report.packetsLost - previousStats.packetsLost,\n framesDropped: report.framesDropped - previousStats.framesDropped,\n framesDecoded: report.framesDecoded - previousStats.framesDecoded,\n jitter: report.jitter,\n jitterBufferDelay: report.jitterBufferDelay - previousStats.jitterBufferDelay,\n jitterBufferEmittedCount: report.jitterBufferEmittedCount - previousStats.jitterBufferEmittedCount,\n avgJitterDelayInInterval:\n (report.jitterBufferDelay - previousStats.jitterBufferDelay) /\n (report.jitterBufferEmittedCount - previousStats.jitterBufferEmittedCount),\n framesPerSecond: report.framesPerSecond,\n freezeCount: report.freezeCount - previousStats.freezeCount,\n freezeDuration: report.freezeDuration - previousStats.freezeDuration,\n };\n }\n\n return {\n timestamp: report.timestamp,\n duration: (interval * index) / 1000,\n rtt: report.rtt,\n bytesReceived: report.bytesReceived - stats[index - 1].bytesReceived,\n bitrate: ((report.bytesReceived - stats[index - 1].bytesReceived) * 8) / (interval / 1000),\n packetsReceived: report.packetsReceived - stats[index - 1].packetsReceived,\n packetsLost: report.packetsLost - stats[index - 1].packetsLost,\n framesDropped: report.framesDropped - stats[index - 1].framesDropped,\n framesDecoded: report.framesDecoded - stats[index - 1].framesDecoded,\n jitter: report.jitter,\n jitterBufferDelay: report.jitterBufferDelay - stats[index - 1].jitterBufferDelay,\n jitterBufferEmittedCount: report.jitterBufferEmittedCount - stats[index - 1].jitterBufferEmittedCount,\n avgJitterDelayInInterval:\n (report.jitterBufferDelay - stats[index - 1].jitterBufferDelay) /\n (report.jitterBufferEmittedCount - stats[index - 1].jitterBufferEmittedCount),\n framesPerSecond: report.framesPerSecond,\n freezeCount: report.freezeCount - stats[index - 1].freezeCount,\n freezeDuration: report.freezeDuration - stats[index - 1].freezeDuration,\n };\n });\n\n const anomalies = extractAnomalies(differentialReport);\n const lowFpsCount = anomalies.reduce((acc, report) => acc + (report.causes!.includes('low fps') ? 1 : 0), 0);\n\n const avgJittersSamples = differentialReport\n .filter(stat => !!stat.avgJitterDelayInInterval)\n .map(stat => stat.avgJitterDelayInInterval);\n\n const avgRttSamples = differentialReport.filter(stat => !!stat.rtt).map(stat => stat.rtt);\n\n return {\n webRTCStats: {\n anomalies: anomalies,\n avSync: safe(() => buildAvSyncReport(stats), null),\n minRtt: min(avgRttSamples),\n avgRtt: average(avgRttSamples),\n maxRtt: max(avgRttSamples),\n aggregateReport: createAggregateReport(stats[0], stats[stats.length - 1], lowFpsCount),\n minJitterDelayInInterval: min(avgJittersSamples),\n maxJitterDelayInInterval: max(avgJittersSamples),\n avgJitterDelayInInterval: average(avgJittersSamples),\n },\n codec: stats[0].codec,\n resolution: `${stats[0].frameWidth}x${stats[0].frameHeight}`,\n };\n}\n","import { ConnectivityState, SlimRTCStatsReport, StreamingState } from '@sdk/types';\nimport { VideoRTCStatsReport, createVideoStatsReport, formatStats } from './report';\n\nfunction findInboundRtpReport(stats: RTCStatsReport, kind: 'audio' | 'video'): any | null {\n for (const report of stats.values()) {\n if (report?.type === 'inbound-rtp' && (report as any).kind === kind) {\n return report;\n }\n }\n return null;\n}\n\nconst AUDIO_STATS_POLL_INTERVAL_MS = 10;\n\nexport interface AudioArmContext {\n sttLatency?: number;\n serviceLatency?: number;\n}\n\nexport function createAudioStatsDetector(\n getStats: () => Promise<RTCStatsReport | undefined>,\n onFirstAudioDetected: (context: AudioArmContext) => void\n) {\n let armed = false;\n let baselined = false;\n let timerId: ReturnType<typeof setTimeout> | null = null;\n let armTime = 0;\n let prevTotalAudioEnergy = 0;\n let prevTotalSamplesReceived = 0;\n let armContext: AudioArmContext = {};\n\n async function poll() {\n if (!armed) return;\n\n try {\n const stats = await getStats();\n if (!stats) {\n timerId = setTimeout(poll, AUDIO_STATS_POLL_INTERVAL_MS);\n return;\n }\n\n const report = findInboundRtpReport(stats, 'audio');\n if (!report) {\n timerId = setTimeout(poll, AUDIO_STATS_POLL_INTERVAL_MS);\n return;\n }\n\n const totalAudioEnergy: number = report.totalAudioEnergy ?? 0;\n const totalSamplesReceived: number = report.totalSamplesReceived ?? 0;\n\n if (!baselined) {\n prevTotalAudioEnergy = totalAudioEnergy;\n prevTotalSamplesReceived = totalSamplesReceived;\n baselined = true;\n timerId = setTimeout(poll, AUDIO_STATS_POLL_INTERVAL_MS);\n return;\n }\n\n const energyDelta = totalAudioEnergy - prevTotalAudioEnergy;\n const samplesDelta = totalSamplesReceived - prevTotalSamplesReceived;\n prevTotalAudioEnergy = totalAudioEnergy;\n prevTotalSamplesReceived = totalSamplesReceived;\n\n if (samplesDelta > 0 && energyDelta > 0) {\n armed = false;\n onFirstAudioDetected(armContext);\n return;\n }\n } catch {\n // stats not available yet\n }\n\n if (armed) {\n timerId = setTimeout(poll, AUDIO_STATS_POLL_INTERVAL_MS);\n }\n }\n\n return {\n arm(context: AudioArmContext = {}) {\n armContext = context;\n armed = true;\n baselined = false;\n armTime = performance.now();\n if (timerId !== null) clearTimeout(timerId);\n timerId = setTimeout(poll, AUDIO_STATS_POLL_INTERVAL_MS);\n },\n destroy() {\n armed = false;\n if (timerId !== null) {\n clearTimeout(timerId);\n timerId = null;\n }\n },\n };\n}\n\nconst interval = 100;\nconst notReceivingIntervalsThreshold = Math.max(Math.ceil(400 / interval), 1);\nconst LOW_JITTER_TRESHOLD = 0.25;\nconst HIGH_JITTER_TRESHOLD = 0.28;\n\nfunction createVideoStatsAnalyzer() {\n let lastFramesReceived = 0;\n let prevDelay: any;\n let prevCount: any;\n let avgJitterDelayInInterval = 0;\n return (stats: RTCStatsReport) => {\n const report = findInboundRtpReport(stats, 'video');\n if (!report) {\n return { isReceiving: false, avgJitterDelayInInterval };\n }\n\n const delay = report.jitterBufferDelay;\n const count = report.jitterBufferEmittedCount;\n\n if (prevCount && count > prevCount) {\n const deltaDelay = delay - prevDelay;\n const deltaCount = count - prevCount;\n avgJitterDelayInInterval = deltaDelay / deltaCount;\n }\n\n prevDelay = delay;\n prevCount = count;\n\n const currFramesReceived = report.framesDecoded;\n const isReceiving = currFramesReceived - lastFramesReceived > 0;\n lastFramesReceived = currFramesReceived;\n\n return { isReceiving, avgJitterDelayInInterval, freezeCount: report.freezeCount };\n };\n}\n\nexport function createVideoStatsMonitor(\n getStats: () => Promise<RTCStatsReport | undefined>,\n getIsConnected: () => boolean,\n onConnected: () => void,\n onVideoStateChange?: (state: StreamingState, statsReport?: VideoRTCStatsReport) => void,\n onConnectivityStateChange?: (state: ConnectivityState) => void\n) {\n let intervalId: ReturnType<typeof setInterval> | null = null;\n\n let allStats: SlimRTCStatsReport[] = [];\n let previousStats: SlimRTCStatsReport;\n let notReceivingNumIntervals = 0;\n let isStreaming = false;\n let streamsCount = 0;\n let prevLowConnState = ConnectivityState.Unknown;\n let currLowConnState = ConnectivityState.Unknown;\n let currFreezeCount = 0;\n let prevFreezeCount = 0;\n\n const isReceivingVideoBytes = createVideoStatsAnalyzer();\n\n async function getAndAnalyzeVideoStats() {\n const stats = await getStats();\n if (!stats) {\n return;\n }\n\n const { isReceiving, avgJitterDelayInInterval, freezeCount } = isReceivingVideoBytes(stats);\n const slimStats = formatStats(stats);\n\n if (isReceiving) {\n notReceivingNumIntervals = 0;\n currFreezeCount = freezeCount - prevFreezeCount;\n currLowConnState =\n avgJitterDelayInInterval < LOW_JITTER_TRESHOLD\n ? ConnectivityState.Strong\n : avgJitterDelayInInterval > HIGH_JITTER_TRESHOLD && currFreezeCount > 1\n ? ConnectivityState.Weak\n : prevLowConnState;\n\n if (currLowConnState !== prevLowConnState) {\n onConnectivityStateChange?.(currLowConnState);\n prevLowConnState = currLowConnState;\n prevFreezeCount += currFreezeCount;\n currFreezeCount = 0;\n }\n\n if (!isStreaming) {\n onVideoStateChange?.(StreamingState.Start);\n\n previousStats = allStats[allStats.length - 1];\n allStats = [];\n streamsCount++;\n isStreaming = true;\n }\n\n allStats.push(slimStats);\n } else if (isStreaming) {\n notReceivingNumIntervals++;\n\n if (notReceivingNumIntervals >= notReceivingIntervalsThreshold) {\n const statsReport = createVideoStatsReport(allStats, interval, previousStats);\n\n onVideoStateChange?.(StreamingState.Stop, statsReport ?? undefined);\n\n if (!getIsConnected()) {\n onConnected();\n }\n\n prevFreezeCount = freezeCount;\n isStreaming = false;\n }\n }\n }\n\n return {\n start: () => {\n if (intervalId) return;\n\n intervalId = setInterval(getAndAnalyzeVideoStats, interval);\n },\n stop: () => {\n if (!intervalId) return;\n\n clearInterval(intervalId);\n intervalId = null;\n },\n getReport: (): VideoRTCStatsReport | null => {\n return createVideoStatsReport(allStats, interval, previousStats);\n },\n };\n}\n","import { createStreamApi } from '@sdk/api/streams';\nimport { didApiUrl } from '@sdk/config/environment';\nimport { StreamError } from '@sdk/errors';\nimport {\n AgentActivityState,\n ConnectionState,\n CreateStreamOptions,\n InterruptOptions,\n PayloadType,\n StreamEvents,\n StreamingManagerOptions,\n StreamingState,\n StreamInterruptPayload,\n StreamType,\n} from '@sdk/types';\nimport { InternalDataChannelTopic } from '@sdk/types/stream/data-channel';\nimport { createStreamingLogger, StreamingManager } from './common';\nimport { createVideoStatsMonitor } from './stats/poll';\nimport { VideoRTCStatsReport } from './stats/report';\n\n// Resolved on first use, not at module evaluation: importing the package must not\n// touch `window` (server-side rendering evaluates this module in Node).\nconst getRTCPeerConnection = (): typeof RTCPeerConnection => {\n const w = globalThis as any;\n const impl = w.RTCPeerConnection || w.webkitRTCPeerConnection || w.mozRTCPeerConnection;\n\n if (!impl) {\n throw new Error('RTCPeerConnection is not available in this environment');\n }\n\n return impl.bind(w);\n};\n\ntype DataChannelPayload = string | Record<string, unknown>;\ntype DataChannelMessageHandler<S extends StreamEvents> = (subject: S, payload?: DataChannelPayload) => void;\n\nexport function mapConnectionState(state: RTCIceConnectionState): ConnectionState {\n switch (state) {\n case 'connected':\n return ConnectionState.Connected;\n case 'checking':\n return ConnectionState.Connecting;\n case 'failed':\n return ConnectionState.Fail;\n case 'new':\n return ConnectionState.New;\n case 'closed':\n return ConnectionState.Closed;\n case 'disconnected':\n return ConnectionState.Disconnected;\n case 'completed':\n return ConnectionState.Completed;\n default:\n return ConnectionState.New;\n }\n}\n\nexport const createParseDataChannelMessage =\n (log: ReturnType<typeof createStreamingLogger>) =>\n (message: string): { subject: StreamEvents; data: DataChannelPayload } => {\n const [subject, rawData = ''] = message.split(/:(.+)/);\n try {\n const data = JSON.parse(rawData);\n log('parsed data channel message', { subject, data });\n return { subject: subject as StreamEvents, data };\n } catch (e) {\n log('Failed to parse data channel message, returning data as string', { subject, rawData, error: e });\n return { subject: subject as StreamEvents, data: rawData };\n }\n };\n\nfunction handleLegacyStreamState({\n statsSignal,\n dataChannelSignal,\n onVideoStateChange,\n report,\n log,\n}: {\n statsSignal?: StreamingState;\n dataChannelSignal?: StreamingState;\n onVideoStateChange: StreamingManagerOptions['callbacks']['onVideoStateChange'];\n report?: VideoRTCStatsReport;\n log: ReturnType<typeof createStreamingLogger>;\n}) {\n if (statsSignal === StreamingState.Start && dataChannelSignal === StreamingState.Start) {\n log('CALLBACK: onVideoStateChange(Start)');\n onVideoStateChange?.(StreamingState.Start);\n } else if (statsSignal === StreamingState.Stop && dataChannelSignal === StreamingState.Stop) {\n log('CALLBACK: onVideoStateChange(Stop)');\n onVideoStateChange?.(StreamingState.Stop, report);\n }\n}\n\nfunction handleFluentStreamState({\n statsSignal,\n dataChannelSignal,\n onVideoStateChange,\n onAgentActivityStateChange,\n report,\n log,\n}: {\n statsSignal?: StreamingState;\n dataChannelSignal?: StreamingState;\n onVideoStateChange: StreamingManagerOptions['callbacks']['onVideoStateChange'];\n onAgentActivityStateChange?: StreamingManagerOptions['callbacks']['onAgentActivityStateChange'];\n report?: VideoRTCStatsReport;\n log: ReturnType<typeof createStreamingLogger>;\n}) {\n if (statsSignal === StreamingState.Start) {\n log('CALLBACK: onVideoStateChange(Start)');\n onVideoStateChange?.(StreamingState.Start);\n } else if (statsSignal === StreamingState.Stop) {\n log('CALLBACK: onVideoStateChange(Stop)');\n onVideoStateChange?.(StreamingState.Stop, report);\n }\n\n if (dataChannelSignal === StreamingState.Start) {\n onAgentActivityStateChange?.(AgentActivityState.Talking);\n } else if (dataChannelSignal === StreamingState.Stop) {\n onAgentActivityStateChange?.(AgentActivityState.Idle);\n }\n}\n\nfunction handleStreamState({\n statsSignal,\n dataChannelSignal,\n onVideoStateChange,\n onAgentActivityStateChange,\n streamType,\n report,\n log,\n}: {\n statsSignal?: StreamingState;\n dataChannelSignal?: StreamingState;\n onVideoStateChange: StreamingManagerOptions['callbacks']['onVideoStateChange'];\n onAgentActivityStateChange?: StreamingManagerOptions['callbacks']['onAgentActivityStateChange'];\n streamType: StreamType;\n report?: VideoRTCStatsReport;\n log: ReturnType<typeof createStreamingLogger>;\n}) {\n if (streamType === StreamType.Legacy) {\n handleLegacyStreamState({ statsSignal, dataChannelSignal, onVideoStateChange, report, log });\n } else if (streamType === StreamType.Fluent) {\n handleFluentStreamState({\n statsSignal,\n dataChannelSignal,\n onVideoStateChange,\n onAgentActivityStateChange,\n report,\n log,\n });\n }\n}\n\nexport async function createWebRTCStreamingManager<T extends CreateStreamOptions>(\n agentId: string,\n streamOptions: T,\n { debug = false, callbacks, auth, baseURL = didApiUrl, analytics }: StreamingManagerOptions,\n signal?: AbortSignal\n): Promise<StreamingManager<T>> {\n const log = createStreamingLogger(debug, 'WebRTCStreamingManager');\n const parseDataChannelMessage = createParseDataChannelMessage(log);\n\n let srcObject: MediaStream | null = null;\n let isConnected = false;\n let isDatachannelOpen = false;\n let dataChannelSignal: StreamingState = StreamingState.Stop;\n let statsSignal: StreamingState = StreamingState.Stop;\n\n const { startConnection, sendStreamRequest, close, createStream, addIceCandidate } = createStreamApi(\n auth,\n baseURL,\n agentId,\n callbacks.onError\n );\n\n const {\n id: streamIdFromServer,\n offer,\n ice_servers,\n session_id,\n fluent,\n interrupt_enabled: interruptAvailable,\n } = await createStream(streamOptions, signal);\n\n // Guard before the callback: `StreamCreatedInfo.sessionId` is public and declares `string`.\n if (!session_id) {\n throw new Error('Could not create session_id');\n }\n\n callbacks.onStreamCreated?.({ streamId: streamIdFromServer, sessionId: session_id, agentId });\n\n const reportError = (error: Error) => callbacks.onError?.(error, { streamId: streamIdFromServer });\n const peerConnection = new (getRTCPeerConnection())({ iceServers: ice_servers });\n const pcDataChannel = peerConnection.createDataChannel('JanusDataChannel');\n\n const streamType = fluent ? StreamType.Fluent : StreamType.Legacy;\n\n analytics.enrich({\n 'stream-type': streamType,\n });\n\n const warmup = streamOptions.stream_warmup && !fluent;\n\n const getIsConnected = () => isConnected;\n const onConnected = () => {\n isConnected = true;\n\n if (isDatachannelOpen) {\n log('CALLBACK: onConnectionStateChange(Connected)');\n callbacks.onConnectionStateChange?.(ConnectionState.Connected);\n }\n };\n\n const videoStatsMonitor = createVideoStatsMonitor(\n () => peerConnection.getStats(),\n getIsConnected,\n onConnected,\n (state, report) =>\n handleStreamState({\n statsSignal: (statsSignal = state),\n dataChannelSignal: streamType === StreamType.Legacy ? dataChannelSignal : undefined,\n onVideoStateChange: callbacks.onVideoStateChange,\n onAgentActivityStateChange: callbacks.onAgentActivityStateChange,\n report,\n streamType,\n log,\n }),\n state => callbacks.onConnectivityStateChange?.(state)\n );\n videoStatsMonitor.start();\n\n peerConnection.onicecandidate = (event: RTCPeerConnectionIceEvent) => {\n log('peerConnection.onicecandidate', event);\n\n try {\n if (event.candidate && event.candidate.sdpMid && event.candidate.sdpMLineIndex !== null) {\n addIceCandidate(\n streamIdFromServer,\n {\n candidate: event.candidate.candidate,\n sdpMid: event.candidate.sdpMid,\n sdpMLineIndex: event.candidate.sdpMLineIndex,\n },\n session_id,\n signal\n );\n } else {\n addIceCandidate(streamIdFromServer, { candidate: null }, session_id, signal);\n }\n } catch (e: any) {\n reportError(e);\n }\n };\n\n pcDataChannel.onopen = () => {\n isDatachannelOpen = true;\n\n if (!warmup || isConnected) {\n onConnected();\n }\n };\n\n let currentVideoId: string | null = null;\n const handleStreamVideoIdChange = (videoId: string | null) => {\n currentVideoId = videoId;\n callbacks.onVideoIdChange?.(videoId);\n };\n\n function handleStreamVideoEvent(\n subject: StreamEvents.StreamStarted | StreamEvents.StreamDone,\n payload?: DataChannelPayload\n ) {\n if (subject === StreamEvents.StreamStarted && typeof payload === 'object' && 'metadata' in payload) {\n const metadata = payload.metadata as { videoId: string };\n handleStreamVideoIdChange(metadata.videoId);\n }\n\n if (subject === StreamEvents.StreamDone) {\n handleStreamVideoIdChange(null);\n }\n\n dataChannelSignal = subject === StreamEvents.StreamStarted ? StreamingState.Start : StreamingState.Stop;\n\n handleStreamState({\n statsSignal: streamType === StreamType.Legacy ? statsSignal : undefined,\n dataChannelSignal,\n onVideoStateChange: callbacks.onVideoStateChange,\n onAgentActivityStateChange: callbacks.onAgentActivityStateChange,\n streamType,\n log,\n });\n }\n\n function handleStreamReadyEvent(_subject: StreamEvents.StreamReady, payload?: DataChannelPayload) {\n const streamMetadata = typeof payload === 'string' ? payload : payload?.metadata;\n streamMetadata && analytics.enrich({ streamMetadata });\n callbacks.onStreamReady?.();\n }\n\n const dataChannelHandlers = {\n [StreamEvents.StreamStarted]: handleStreamVideoEvent,\n [StreamEvents.StreamDone]: handleStreamVideoEvent,\n [StreamEvents.StreamReady]: handleStreamReadyEvent,\n } satisfies Partial<{ [K in StreamEvents]: DataChannelMessageHandler<K> }>;\n\n pcDataChannel.onmessage = (event: MessageEvent) => {\n const { subject, data } = parseDataChannelMessage(event.data);\n dataChannelHandlers[subject]?.(subject, data);\n };\n\n peerConnection.oniceconnectionstatechange = () => {\n log('peerConnection.oniceconnectionstatechange => ' + peerConnection.iceConnectionState);\n\n const newState = mapConnectionState(peerConnection.iceConnectionState);\n\n if (newState !== ConnectionState.Connected) {\n callbacks.onConnectionStateChange?.(newState, `webrtc:ice-${peerConnection.iceConnectionState}`);\n }\n };\n\n peerConnection.ontrack = (event: RTCTrackEvent) => {\n log('peerConnection.ontrack', event);\n log('CALLBACK: onSrcObjectReady');\n callbacks.onSrcObjectReady?.(event.streams[0]);\n };\n\n await peerConnection.setRemoteDescription(offer);\n log('set remote description OK');\n\n const sessionClientAnswer = await peerConnection.createAnswer();\n log('create answer OK');\n\n await peerConnection.setLocalDescription(sessionClientAnswer);\n log('set local description OK');\n\n await startConnection(streamIdFromServer, sessionClientAnswer, session_id, signal);\n log('start connection OK');\n\n async function sendDataChannelMessage(_topic: `${InternalDataChannelTopic}`, payload: string) {\n if (!isConnected || pcDataChannel.readyState !== 'open') {\n log('Data channel is not ready for sending messages');\n reportError(new StreamError('Data channel is not ready for sending messages'));\n return;\n }\n\n try {\n pcDataChannel.send(payload);\n } catch (e: any) {\n log('Error sending data channel message', e);\n reportError(e);\n }\n }\n\n return {\n /**\n * Method to send request to server to get clip or talk depend on you payload\n * @param payload\n */\n speak(payload: PayloadType<T>) {\n return sendStreamRequest(streamIdFromServer, session_id, payload);\n },\n /**\n * Method to close RTC connection\n */\n async disconnect() {\n if (streamIdFromServer) {\n if (srcObject) {\n srcObject.getTracks().forEach(track => track.stop());\n srcObject = null;\n }\n\n const state = mapConnectionState(peerConnection.iceConnectionState);\n\n if (peerConnection) {\n if (state === ConnectionState.New) {\n // Connection already closed\n videoStatsMonitor.stop();\n return;\n }\n\n peerConnection.close();\n peerConnection.oniceconnectionstatechange = null;\n peerConnection.onnegotiationneeded = null;\n peerConnection.onicecandidate = null;\n peerConnection.ontrack = null;\n }\n\n try {\n if (state === ConnectionState.Connected) {\n await close(streamIdFromServer, session_id);\n }\n } catch (e) {\n log('Error on close stream connection', e);\n }\n\n callbacks.onAgentActivityStateChange?.(AgentActivityState.Idle);\n videoStatsMonitor.stop();\n }\n },\n sendDataChannelMessage,\n /**\n * Session identifier information, should be returned in the body of all streaming requests\n */\n sessionId: session_id,\n /**\n * Id of current RTC stream\n */\n streamId: streamIdFromServer,\n\n streamType,\n interruptAvailable: interruptAvailable ?? false,\n isInterruptible: true,\n\n interrupt(_type: InterruptOptions['type']) {\n // Nothing to interrupt: the stream does not support it, is not fluent, or no video is playing.\n if (!interruptAvailable || streamType !== StreamType.Fluent || !currentVideoId) {\n return false;\n }\n\n // Nothing would reach the agent: sendDataChannelMessage drops the payload in this state.\n if (!isConnected || pcDataChannel.readyState !== 'open') {\n return false;\n }\n\n const payload: StreamInterruptPayload = {\n type: StreamEvents.StreamInterrupt,\n videoId: currentVideoId,\n timestamp: Date.now(),\n };\n // The topic is ignored here - V1 has no topic concept and the interrupt\n // is identified by the payload's `type`.\n sendDataChannelMessage(InternalDataChannelTopic.Interrupt, JSON.stringify(payload));\n\n return true;\n },\n };\n}\n\nexport type WebRTCStreamingManager<T extends CreateStreamOptions> = StreamingManager<T>;\n","import {\n Agent,\n CreateSessionV2Options,\n CreateStreamOptions,\n StreamingManagerOptions,\n TransportProvider,\n} from '@sdk/types';\nimport { StreamingManager } from './common';\nimport { createWebRTCStreamingManager } from './webrtc-manager';\n\nexport enum StreamApiVersion {\n V1 = 'v1',\n V2 = 'v2',\n}\n\nexport type ExtendedStreamOptions =\n | ({ version: StreamApiVersion.V1 } & CreateStreamOptions)\n | ({ version: StreamApiVersion.V2 } & CreateSessionV2Options);\n\nexport async function createStreamingManager(\n agent: Agent,\n streamOptions: ExtendedStreamOptions,\n options: StreamingManagerOptions,\n signal?: AbortSignal\n): Promise<StreamingManager<CreateStreamOptions | CreateSessionV2Options>> {\n const agentId = agent.id;\n\n switch (streamOptions.version) {\n case StreamApiVersion.V1: {\n const { version, ...createStreamOptions } = streamOptions;\n return createWebRTCStreamingManager(agentId, createStreamOptions, options, signal);\n }\n\n case StreamApiVersion.V2: {\n const { version, ...createStreamOptions } = streamOptions;\n\n switch (createStreamOptions.transport.provider) {\n case TransportProvider.Livekit:\n const { createLiveKitStreamingManager } = await import('./livekit-manager');\n return createLiveKitStreamingManager(agentId, createStreamOptions, options);\n default:\n throw new Error(`Unsupported transport provider: ${createStreamOptions.transport.provider}`);\n }\n }\n\n default:\n throw new Error(`Invalid stream version: ${(streamOptions as any).version}`);\n }\n}\n","import { ChatModeDowngraded } from '@sdk/errors';\nimport {\n ExtendedStreamOptions,\n StreamApiVersion,\n StreamingManager,\n createStreamingManager,\n} from '@sdk/services/streaming-manager';\nimport {\n Agent,\n AgentActivityState,\n AgentManagerOptions,\n AgentsAPI,\n AudioDetectionMetrics,\n Chat,\n ChatMode,\n ChatProgressCallback,\n ConnectionState,\n CreateSessionV2Options,\n CreateStreamOptions,\n StreamEvents,\n StreamType,\n StreamingManagerOptions,\n StreamingState,\n ToolCallDonePayload,\n ToolCallErrorPayload,\n ToolCallEvent,\n ToolEventPayload,\n TransportProvider,\n} from '@sdk/types';\nimport { isStreamsV2Agent } from '@sdk/utils/agent';\nimport { Analytics } from '../analytics/mixpanel';\nimport {\n interruptTimestampTracker,\n latencyTimestampTracker,\n streamReadyTimestampTracker,\n} from '../analytics/timestamp-tracker';\nimport { createChat } from '../chat';\n\nconst ChatPrefix = 'cht';\nfunction getAgentStreamV2Options(options?: ConnectToManagerOptions): CreateSessionV2Options {\n return {\n transport: {\n provider: TransportProvider.Livekit,\n },\n ...(options?.persistentChat !== undefined && { chat_persist: options.persistentChat }),\n };\n}\n\nfunction getAgentStreamV1Options(options?: ConnectToManagerOptions): CreateStreamOptions {\n const { streamOptions } = options ?? {};\n\n // `analytics.additionalProperties` is typed `unknown` per value; the API expects `plan` to be\n // a string.\n const endUserData =\n options?.analytics?.additionalProperties?.plan !== undefined\n ? {\n plan: options.analytics.additionalProperties.plan as string,\n }\n : undefined;\n\n const streamArgs = {\n session_timeout: streamOptions?.sessionTimeout,\n stream_warmup: streamOptions?.streamWarmup,\n compatibility_mode: streamOptions?.compatibilityMode,\n fluent: streamOptions?.fluent,\n };\n\n return { ...streamArgs, ...(endUserData && { end_user_data: endUserData }) };\n}\n\nfunction getAgentStreamOptions(agent: Agent, options?: ConnectToManagerOptions): ExtendedStreamOptions {\n return isStreamsV2Agent(agent.avatar.type)\n ? { version: StreamApiVersion.V2, ...getAgentStreamV2Options(options) }\n : { version: StreamApiVersion.V1, ...getAgentStreamV1Options(options) };\n}\n\nfunction trackConnectionStateChangeAnalytics(state: ConnectionState, reason: string | undefined, analytics: Analytics) {\n analytics.track('agent-connection-state-change', { state, ...(reason && { reason }) });\n}\n\nfunction trackVideoStateChangeAnalytics(\n state: StreamingState,\n agent: Agent,\n statsReport: any,\n analytics: Analytics,\n streamType: StreamType\n) {\n if (streamType === StreamType.Fluent) {\n trackVideoStreamAnalytics(state, agent, statsReport, analytics, streamType);\n } else {\n trackLegacyVideoAnalytics(state, agent, statsReport, analytics, streamType);\n }\n}\n\nfunction trackVideoStreamAnalytics(\n state: StreamingState,\n agent: Agent,\n statsReport: any,\n analytics: Analytics,\n streamType: StreamType\n) {\n if (state === StreamingState.Start) {\n analytics.track('stream-session', { event: 'start', 'stream-type': streamType });\n } else if (state === StreamingState.Stop) {\n analytics.track('stream-session', {\n event: 'stop',\n 'stream-type': streamType,\n ...statsReport,\n });\n }\n}\n\nfunction trackAgentActivityAnalytics(\n state: StreamingState,\n agent: Agent,\n analytics: Analytics,\n streamType: StreamType,\n metrics?: AudioDetectionMetrics\n) {\n if (state === StreamingState.Start) {\n analytics.linkTrack('agent-video', { event: 'start', ...metrics, 'stream-type': streamType }, 'start', [\n StreamEvents.StreamVideoCreated,\n ]);\n } else if (state === StreamingState.Stop) {\n analytics.linkTrack(\n 'agent-video',\n {\n event: 'stop',\n 'stream-type': streamType,\n },\n 'done',\n [StreamEvents.StreamVideoDone]\n );\n }\n}\n\nfunction trackLegacyVideoAnalytics(\n state: StreamingState,\n agent: Agent,\n statsReport: any,\n analytics: Analytics,\n streamType: StreamType\n) {\n if (state === StreamingState.Start) {\n analytics.linkTrack(\n 'agent-video',\n { event: 'start', latency: latencyTimestampTracker.get(true), 'stream-type': streamType },\n 'start',\n [StreamEvents.StreamVideoCreated]\n );\n } else if (state === StreamingState.Stop) {\n analytics.linkTrack(\n 'agent-video',\n {\n event: 'stop',\n 'stream-type': streamType,\n ...statsReport,\n },\n 'done',\n [StreamEvents.StreamVideoDone]\n );\n }\n}\n\nfunction trackToolEventAnalytics(event: ToolCallEvent, payload: ToolEventPayload, analytics: Analytics) {\n const baseProps: Record<string, unknown> = {\n call_id: payload.callId,\n name: payload.name,\n };\n\n if (event === ToolCallEvent.Started) {\n analytics.track('agent-tool-call', { ...baseProps, event: 'started' });\n return;\n }\n\n const finishedPayload = payload as ToolCallDonePayload | ToolCallErrorPayload;\n analytics.track('agent-tool-call', {\n ...baseProps,\n event: event === ToolCallEvent.Done ? 'done' : 'error',\n duration_ms: finishedPayload.durationMs,\n extra_keys: finishedPayload.extra ? Object.keys(finishedPayload.extra).length : 0,\n });\n}\n\ntype ConnectToManagerOptions = AgentManagerOptions & {\n callbacks: AgentManagerOptions['callbacks'] & {\n onVideoIdChange?: (videoId: string | null) => void;\n /** Internal callback for livekit-manager data channel events */\n onMessage?: ChatProgressCallback;\n onFirstAudioDetected?: (metrics: AudioDetectionMetrics) => void;\n };\n chatId?: string;\n rpcMethods?: StreamingManagerOptions['rpcMethods'];\n};\n\nfunction connectToManager(\n agent: Agent,\n options: ConnectToManagerOptions,\n analytics: Analytics,\n signal?: AbortSignal\n): Promise<StreamingManager<CreateStreamOptions | CreateSessionV2Options>> {\n latencyTimestampTracker.reset();\n streamReadyTimestampTracker.update();\n\n return new Promise(async (resolve, reject) => {\n try {\n let streamingManager: StreamingManager<CreateStreamOptions | CreateSessionV2Options>;\n let shouldResolveOnComplete = false;\n const streamOptions = getAgentStreamOptions(agent, options);\n\n analytics.enrich({\n 'stream-version': streamOptions.version.toString(),\n });\n\n let pendingStartTrack: ((metrics?: AudioDetectionMetrics) => void) | null = null;\n const isStreamsV2 = streamOptions.version === StreamApiVersion.V2;\n\n streamingManager = await createStreamingManager(\n agent,\n streamOptions,\n {\n ...options,\n analytics,\n callbacks: {\n ...options.callbacks,\n onConnectionStateChange: (state, reason) => {\n options.callbacks.onConnectionStateChange?.(state, reason);\n\n trackConnectionStateChangeAnalytics(state, reason, analytics);\n\n if (state === ConnectionState.Connected) {\n // If manager is ready, resolve immediately\n // Otherwise, mark to resolve after manager is created\n if (streamingManager) {\n resolve(streamingManager);\n } else {\n shouldResolveOnComplete = true;\n }\n }\n },\n onVideoStateChange: (state: StreamingState, statsReport?: any) => {\n options.callbacks.onVideoStateChange?.(state);\n\n trackVideoStateChangeAnalytics(\n state,\n agent,\n statsReport,\n analytics,\n streamingManager.streamType\n );\n },\n onAgentActivityStateChange: (state: AgentActivityState) => {\n options.callbacks.onAgentActivityStateChange?.(state);\n\n if (state === AgentActivityState.Talking) {\n interruptTimestampTracker.update();\n pendingStartTrack = metrics => {\n trackAgentActivityAnalytics(\n StreamingState.Start,\n agent,\n analytics,\n streamingManager.streamType,\n metrics\n );\n pendingStartTrack = null;\n };\n if (!isStreamsV2) {\n pendingStartTrack({ latency: latencyTimestampTracker.get(true) });\n }\n } else {\n interruptTimestampTracker.reset();\n pendingStartTrack = null;\n trackAgentActivityAnalytics(\n StreamingState.Stop,\n agent,\n analytics,\n streamingManager.streamType\n );\n }\n },\n onFirstAudioDetected: metrics => {\n pendingStartTrack?.(metrics);\n },\n onStreamReady: () => {\n const readyLatency = streamReadyTimestampTracker.get(true);\n analytics.track('agent-chat', { event: 'ready', latency: readyLatency });\n },\n onToolEvent: ((event: any, data: any) => {\n options.callbacks.onToolEvent?.(event, data);\n trackToolEventAnalytics(event, data, analytics);\n }) as typeof options.callbacks.onToolEvent,\n },\n },\n signal\n );\n\n if (shouldResolveOnComplete) {\n resolve(streamingManager);\n }\n } catch (error) {\n reject(error);\n }\n });\n}\n\nexport async function initializeStreamAndChat(\n agent: Agent,\n options: ConnectToManagerOptions,\n agentsApi: AgentsAPI,\n analytics: Analytics,\n chat?: Chat\n): Promise<{ chat?: Chat; streamingManager?: StreamingManager<CreateStreamOptions | CreateSessionV2Options> }> {\n const resolveStreamAndChat = async () => {\n if (isStreamsV2Agent(agent.avatar.type)) {\n const streamingManager = await connectToManager(agent, options, analytics);\n const chatId = `${ChatPrefix}_${streamingManager.sessionId}`;\n const now = new Date().toISOString();\n\n const chatResult = {\n chatMode: ChatMode.Functional,\n chat: {\n id: chatId,\n agent_id: agent.id,\n owner_id: agent.owner_id ?? '',\n created: now,\n modified: now,\n agent_id__created_at: now,\n agent_id__modified_at: now,\n chat_mode: ChatMode.Functional,\n messages: [],\n },\n };\n return { chatResult, streamingManager };\n } else {\n const abortController = new AbortController();\n const signal = abortController.signal;\n let streamingManagerRef: StreamingManager<CreateStreamOptions | CreateSessionV2Options> | undefined;\n\n try {\n const createChatPromise = createChat(\n agent,\n agentsApi,\n analytics,\n options.mode,\n options.persistentChat,\n chat\n );\n const connectToManagerPromise = connectToManager(agent, options, analytics, signal).then(manager => {\n streamingManagerRef = manager;\n return manager;\n });\n\n const [chatResult, streamingManager] = await Promise.all([createChatPromise, connectToManagerPromise]);\n return { chatResult, streamingManager };\n } catch (error) {\n abortController.abort();\n\n if (streamingManagerRef) {\n await streamingManagerRef.disconnect().catch(() => {});\n }\n\n throw error;\n }\n }\n };\n\n const { chatResult, streamingManager } = await resolveStreamAndChat();\n const { chat: newChat, chatMode } = chatResult;\n\n if (chatMode && options.mode !== undefined && chatMode !== options.mode) {\n // `onModeChange` fires in the agent manager, which applies this mode — one report, after\n // `getChatMode()` is current.\n if (chatMode !== ChatMode.Functional) {\n options.callbacks.onError?.(new ChatModeDowngraded(chatMode));\n\n streamingManager?.disconnect();\n\n return { chat: newChat };\n }\n }\n\n return { chat: newChat, streamingManager };\n}\n","import { InternalDataChannelTopic } from '@sdk/types/stream/data-channel';\nimport {\n AgentManager,\n AgentManagerCallbacks,\n AgentManagerOptions,\n Chat,\n ChatMode,\n ChatResponse,\n ClientToolHandler,\n ConnectionState,\n CreateStreamOptions,\n DataChannelTopic,\n ErrorContext,\n InterruptOptions,\n Message,\n SpeakScript,\n StreamCreatedInfo,\n StreamScript,\n} from '../../types';\n\nimport { rotateConnectionId } from '@sdk/auth/get-auth-header';\nimport { CONNECTION_RETRY_TIMEOUT_MS, MAX_CHAT_MESSAGE_LENGTH } from '@sdk/config/consts';\nimport { didApiUrl, didSocketApiUrl, mixpanelKey } from '@sdk/config/environment';\nimport { ChatCreationFailed, HttpError, ValidationError } from '@sdk/errors';\nimport { getRandom } from '@sdk/utils';\nimport { isStreamsV2Agent } from '@sdk/utils/agent';\nimport { isChatModeWithoutChat, isTextualChat } from '@sdk/utils/chat';\nimport { parseMessagePartsMemo } from '@sdk/utils/content-parser';\nimport { createAgentsApi } from '../../api/agents';\nimport { getAgentInfo, getAnalyticsInfo } from '../../utils/analytics';\nimport { defer } from '../../utils/defer';\nimport { toErrorAnalytics } from '../../utils/error-analytics';\nimport { retryOperation } from '../../utils/retry-operation';\nimport { initializeAnalytics } from '../analytics/mixpanel';\nimport { interruptTimestampTracker, latencyTimestampTracker } from '../analytics/timestamp-tracker';\nimport { createChat, getRequestHeaders } from '../chat';\nimport { getInitialMessages } from '../chat/intial-messages';\nimport { SocketManager, createSocketManager } from '../socket-manager';\nimport { createMessageEventQueue } from '../socket-manager/message-queue';\nimport { StreamingManager } from '../streaming-manager';\nimport { initializeStreamAndChat } from './connect-to-manager';\n\n/**\n * Mutable state shared between the agent manager's connect/chat/stream helpers.\n * @internal Implementation type; not part of the public SDK surface.\n */\nexport interface AgentManagerItems {\n chat?: Chat;\n streamingManager?: StreamingManager<CreateStreamOptions>;\n socketManager?: SocketManager;\n messages: Message[];\n chatMode: ChatMode;\n}\n\n// The two chat modes that create no chat are a Talks (V2) / Clips (V3) feature.\nconst UNSUPPORTED_CHAT_MODE_FOR_EXPRESSIVE =\n 'ChatMode.Off and ChatMode.DirectPlayback are not supported for Expressive agents';\n\n// `onSrcObjectReady` is what puts the agent on screen, so every mode that streams video needs it.\n// `Off` and `DirectPlayback` are not in the exempt set: they create no chat but do stream video.\nconst MISSING_SRC_OBJECT_READY =\n 'callbacks.onSrcObjectReady is required in every chat mode that streams video; ' +\n 'it is optional only in ChatMode.TextOnly, ChatMode.Playground and ChatMode.Maintenance';\n\n// States a held session can be left in once it is over: the server ended it, or the transport failed.\nconst SESSION_ENDED_STATES = [ConnectionState.Disconnected, ConnectionState.Closed, ConnectionState.Fail];\n\n/**\n * Creates an {@link AgentManager} for one agent: its chat, its video stream and its connections.\n *\n * Fetches the agent from the Agents API before it resolves, so the returned manager already has\n * {@link AgentManager.agent | agent} and {@link AgentManager.starterMessages | starterMessages}\n * filled in. No stream is opened until {@link AgentManager.connect | connect()} is called.\n * Two options are checked here, and both reject with a {@link ValidationError}: an Expressive (V4)\n * agent asked for {@link ChatMode.Off} or {@link ChatMode.DirectPlayback}, which only Talks (V2)\n * and Clips (V3) agents support; and\n * {@link AgentManagerOptions.callbacks | callbacks} without\n * {@link AgentManagerCallbacks.onSrcObjectReady | onSrcObjectReady} in a mode that streams video —\n * that callback is what attaches the streamed media to a video element, and only\n * {@link ChatMode.TextOnly}, {@link ChatMode.Playground} and {@link ChatMode.Maintenance} can do\n * without it. Every other bad argument surfaces later, as a {@link ValidationError} rejected by the\n * method that was called on the returned manager, such as\n * {@link AgentManager.chat | chat()} or {@link AgentManager.speak | speak()}.\n *\n * @param agent - Id of the agent to talk to: the `data-agent-id` from its Embed snippet, or the `id`\n * returned by the Agents API.\n * @param options - Credentials, callbacks and everything else the manager needs. See\n * {@link AgentManagerOptions}.\n * @returns A manager for that agent, ready to {@link AgentManager.connect | connect()}.\n * @throws {@link ValidationError} When an Expressive (V4) agent is created with\n * {@link ChatMode.Off} or {@link ChatMode.DirectPlayback}, or when\n * {@link AgentManagerCallbacks.onSrcObjectReady | onSrcObjectReady} is missing in a mode that\n * streams video.\n * @throws {@link HttpError} When the agent cannot be fetched — an unknown id, or a client key that\n * is not authorized for the agent or the calling domain.\n * @throws {@link NetworkError} When the request for the agent never reaches the server: the browser\n * is offline, DNS or TLS fails, or the request is blocked.\n *\n * @example\n * ```ts\n * import * as sdk from '@d-id/client-sdk';\n *\n * const agentManager = await sdk.createAgentManager('agt_fumf1234', {\n * auth: { type: 'key', clientKey: 'YOUR_CLIENT_KEY' },\n * callbacks: {\n * // Hand the streamed media to your video element. Required in every mode that\n * // streams video, which is every mode but TextOnly, Playground and Maintenance.\n * onSrcObjectReady(value) {\n * videoElement.srcObject = value;\n * },\n * },\n * });\n *\n * await agentManager.connect();\n * await agentManager.chat('What is the distance to the moon?');\n * ```\n *\n * @category Agent Manager\n */\nexport async function createAgentManager(agent: string, options: AgentManagerOptions): Promise<AgentManager> {\n // The caller's handlers, copied once: the options object is never written to, so two managers\n // built from one cannot wrap each other's `callbacks.onError`.\n const appCallbacks: AgentManagerCallbacks = { ...options.callbacks };\n\n let firstConnection = true;\n\n const mxKey = options.analytics?.mixpanelKey || mixpanelKey;\n const wsURL = options.wsURL || didSocketApiUrl;\n const baseURL = options.baseURL || didApiUrl;\n const mode = options.mode || ChatMode.Functional;\n\n if (!appCallbacks.onSrcObjectReady && !isTextualChat(mode)) {\n throw new ValidationError(MISSING_SRC_OBJECT_READY);\n }\n\n const items: AgentManagerItems = {\n messages: [],\n chatMode: mode,\n };\n const analytics = initializeAnalytics({\n token: mxKey,\n agentId: agent,\n isEnabled: options.analytics?.enabled,\n externalId: options.externalId,\n mixpanelAdditionalProperties: options.analytics?.additionalProperties,\n });\n\n const initTimestamp = Date.now();\n defer(() => {\n analytics.track('agent-sdk', { event: 'init' }, initTimestamp);\n });\n\n // The state the getters answer from.\n let connectionState: ConnectionState = ConnectionState.New;\n let sessionInfo: StreamCreatedInfo | undefined;\n\n // One object, built once: every reporter is handed this, so the state above has a single source\n // of truth and no handler is wrapped twice.\n const callbacks: AgentManagerCallbacks = {\n ...appCallbacks,\n onError(error: Error, errorData?: ErrorContext) {\n analytics.track('agent-error', { error: toErrorAnalytics(error) });\n appCallbacks.onError?.(error, errorData);\n },\n onConnectionStateChange(state: ConnectionState, reason?: string) {\n connectionState = state;\n appCallbacks.onConnectionStateChange?.(state, reason);\n },\n onStreamCreated(stream: StreamCreatedInfo) {\n sessionInfo = stream;\n appCallbacks.onStreamCreated?.(stream);\n },\n };\n\n const managerOptions: AgentManagerOptions = { ...options, callbacks };\n\n const agentsApi = createAgentsApi(managerOptions.auth, baseURL, callbacks.onError, managerOptions.externalId);\n\n const agentEntity = await agentsApi.getRuntimeById(agent);\n managerOptions.debug = managerOptions.debug || agentEntity?.advanced_settings?.ui_debug_mode;\n\n const isStreamsV2 = isStreamsV2Agent(agentEntity.avatar.type);\n\n if (isStreamsV2 && isChatModeWithoutChat(mode)) {\n throw new ValidationError(UNSUPPORTED_CHAT_MODE_FOR_EXPRESSIVE);\n }\n\n if (isStreamsV2) {\n // Start the transport downloading now, so `connect()` does not wait for it before it can\n // ask for a session. Dynamically, so a Talks/Clips bundle never pulls LiveKit in; a failed\n // prefetch is ignored, and `connect()` reports the failure if it is still there.\n void import('../streaming-manager/livekit-manager')\n .then(({ preloadLiveKit }) => preloadLiveKit())\n .catch(() => {});\n }\n\n analytics.enrich(getAgentInfo(agentEntity));\n\n const { onMessage, clearQueue } = createMessageEventQueue(analytics, items, managerOptions, agentEntity, reason => {\n items.socketManager?.disconnect();\n callbacks.onConnectionStateChange?.(ConnectionState.Disconnected, reason);\n });\n\n items.messages = getInitialMessages(managerOptions.initialMessages);\n\n if (items.messages.length) {\n callbacks.onNewMessage?.([...items.messages], 'answer');\n }\n\n const updateVideoId = (videoId: string | null) => analytics.enrich({ videoId });\n\n const interrupt = (options?: InterruptOptions) => {\n // A stop button is the common case: `interrupt()` means `{ type: 'click' }`.\n const type = options?.type ?? 'click';\n\n const streamingManager = items.streamingManager;\n if (!streamingManager?.interruptAvailable || !streamingManager.isInterruptible) {\n return;\n }\n\n const sent = streamingManager.interrupt(type);\n if (!sent) {\n return;\n }\n\n analytics.track('agent-video-interrupt', {\n type,\n video_duration_to_interrupt: interruptTimestampTracker.get(true),\n message_duration_to_interrupt: latencyTimestampTracker.get(true),\n });\n\n // Only flag the message once the interrupt was actually sent.\n const lastMessage = items.messages[items.messages.length - 1];\n if (!lastMessage) {\n return;\n }\n\n lastMessage.interrupted = true;\n callbacks.onNewMessage?.([...items.messages], 'answer');\n };\n\n const clientToolHandlers = new Map<string, ClientToolHandler>();\n\n // The reason travels in a plain `Error`: only the LiveKit manager loads `livekit-client`, and\n // it turns this into the `RpcError` the transport forwards to the agent.\n function createRpcHandler(toolName: string) {\n return async (data: { payload: string }): Promise<string> => {\n const handler = clientToolHandlers.get(toolName);\n if (!handler) {\n throw new Error(`No handler registered for client tool: ${toolName}`);\n }\n\n const args = JSON.parse(data.payload);\n\n return handler(args);\n };\n }\n\n function flushClientToolsToRoom() {\n for (const [name] of clientToolHandlers) {\n items.streamingManager?.unregisterRpcMethod?.(name);\n items.streamingManager?.registerRpcMethod?.(name, createRpcHandler(name));\n }\n }\n\n function registerClientTool(name: string, handler: ClientToolHandler): void {\n // Client tools travel over the LiveKit RPC channel, which only an Expressive (V4) session\n // has.\n if (!isStreamsV2) {\n throw new ValidationError('registerClientTool is only available on Expressive (V4) agents');\n }\n\n const isNew = !clientToolHandlers.has(name);\n clientToolHandlers.set(name, handler);\n if (isNew) {\n items.streamingManager?.registerRpcMethod?.(name, createRpcHandler(name));\n }\n }\n\n function unregisterClientTool(name: string): void {\n clientToolHandlers.delete(name);\n items.streamingManager?.unregisterRpcMethod?.(name);\n }\n\n const loadedTimestamp = Date.now();\n defer(() => {\n analytics.track('agent-sdk', { event: 'loaded', ...getAnalyticsInfo(agentEntity) }, loadedTimestamp);\n });\n\n // One session-opening operation at a time: a second run would overwrite\n // `items.streamingManager` and leave the first session open on the server. Every path that\n // opens a session goes through `runOp`, so a racing caller joins the one already running.\n let opInFlight: Promise<void> | undefined;\n\n // Set by `disconnect()` while an operation is running; the operation checks it once it has a\n // session and tears down what it built, so `disconnect()` never waits for a connect.\n let disconnectRequested = false;\n\n function runOp(body: () => Promise<void>): Promise<void> {\n disconnectRequested = false;\n\n // `.then(body)`, not `body()`: `opInFlight` must be set before the body's synchronous\n // prefix runs, or a handler it calls would start a second operation.\n opInFlight = Promise.resolve()\n .then(body)\n .finally(() => {\n opInFlight = undefined;\n });\n\n return opInFlight;\n }\n\n function runConnect(newChat: boolean): Promise<void> {\n if (opInFlight) {\n return opInFlight;\n }\n\n return runOp(() => connect(newChat));\n }\n\n async function connect(newChat: boolean) {\n // A `disconnect()` that arrived before this leg started — the second leg of a `reconnect()`,\n // say. Opening a session now would hand back one the caller believes it closed.\n if (disconnectRequested) {\n return;\n }\n\n // A session the server ended is reported but still held; release it before opening a new one.\n if (items.streamingManager) {\n await disconnect();\n }\n\n rotateConnectionId();\n callbacks.onConnectionStateChange?.(ConnectionState.Connecting);\n\n latencyTimestampTracker.reset();\n\n if (newChat && !firstConnection) {\n delete items.chat;\n\n callbacks.onNewMessage?.([...items.messages], 'answer');\n }\n\n const websocketPromise = sessionNeedsSocket(items.chatMode)\n ? createSocketManager(\n managerOptions.auth,\n wsURL,\n { onMessage, onError: callbacks.onError },\n managerOptions.externalId\n )\n : Promise.resolve(undefined);\n const initPromise = retryOperation(\n () =>\n initializeStreamAndChat(\n agentEntity,\n {\n ...managerOptions,\n mode: items.chatMode,\n callbacks: {\n ...callbacks,\n onVideoIdChange: updateVideoId,\n onMessage,\n },\n rpcMethods: new Map([...clientToolHandlers.keys()].map(name => [name, createRpcHandler(name)])),\n },\n agentsApi,\n analytics,\n items.chat\n ),\n {\n limit: 3,\n timeout: CONNECTION_RETRY_TIMEOUT_MS,\n timeoutErrorMessage: 'Timeout initializing the stream',\n shouldRetryFn: (error: any) =>\n !(\n error instanceof HttpError &&\n (error.status === 429 || error.status === 409 || error.code === 'InsufficientCreditsError')\n ),\n delayMs: 1000,\n }\n ).catch(async e => {\n // `Promise.all` below would discard a socket that has already opened, and nothing else\n // holds a reference to it — `items.socketManager` is only assigned on the happy path.\n websocketPromise.then(socket => socket?.disconnect()).catch(() => {});\n\n // An agent that is still being built can connect in a minute or two, through a new manager.\n if (!(e instanceof HttpError && e.code === 'NotReadyError')) {\n await applyMode(ChatMode.Maintenance);\n }\n callbacks.onConnectionStateChange?.(ConnectionState.Fail);\n throw e;\n });\n\n const previousChatId = items.chat?.id;\n const [socketManager, { streamingManager, chat }] = await Promise.all([websocketPromise, initPromise]);\n\n const isNewChat = !!chat && chat.id !== previousChatId;\n if (chat && isNewChat) {\n callbacks.onNewChat?.(chat.id);\n }\n\n items.streamingManager = streamingManager;\n items.socketManager = socketManager;\n items.chat = chat;\n\n // A `disconnect()` that arrived while this was connecting: tear down what was just built\n // rather than leaving a session the caller believes it closed.\n if (disconnectRequested) {\n await disconnect();\n return;\n }\n\n flushClientToolsToRoom();\n\n firstConnection = false;\n\n analytics.enrich({\n chatId: chat?.id,\n streamId: streamingManager?.streamId,\n mode: items.chatMode,\n });\n\n // Only a chat this connect created says anything about this session's mode; one carried\n // over from an earlier connect still holds the mode it was created in.\n const serverMode = (isNewChat ? chat?.chat_mode : undefined) ?? items.chatMode;\n if (isStreamsV2 && isChatModeWithoutChat(serverMode)) {\n // The session is up; keep the mode we have rather than failing a working connection.\n console.warn(`[AgentManager] Ignoring chat mode \"${serverMode}\": ${UNSUPPORTED_CHAT_MODE_FOR_EXPRESSIVE}`);\n return;\n }\n\n await applyMode(serverMode);\n }\n\n async function disconnect() {\n items.socketManager?.disconnect();\n await items.streamingManager?.disconnect();\n\n delete items.streamingManager;\n delete items.socketManager;\n sessionInfo = undefined;\n\n callbacks.onConnectionStateChange?.(ConnectionState.Disconnected);\n }\n\n // The answers arrive on the notifications web socket, except on an Expressive agent (data\n // channel) and in DirectPlayback (no conversation at all).\n function sessionNeedsSocket(mode: ChatMode): boolean {\n return !isStreamsV2 && mode !== ChatMode.DirectPlayback;\n }\n\n // A session built for one mode can be missing what another needs: `connect()` builds the socket\n // and the chat from the mode it ran in.\n function sessionSupports(mode: ChatMode): boolean {\n const needsChat = !isChatModeWithoutChat(mode);\n\n return (!sessionNeedsSocket(mode) || !!items.socketManager) && (!needsChat || !!items.chat);\n }\n\n // The mode change itself, without the Expressive guard: the modes the server reports go\n // through here too, and those must not fail a connection that is otherwise fine.\n async function applyMode(mode: ChatMode) {\n if (mode !== items.chatMode) {\n analytics.track('agent-mode-change', { mode });\n items.chatMode = mode;\n\n // Every mode but Functional tears the stream down — and so does Functional when the\n // open session cannot carry a conversation (a DirectPlayback session has neither the\n // notifications web socket nor a chat). Only when a session is open at all.\n const hasSession = !!items.streamingManager || !!items.socketManager;\n\n if (mode !== ChatMode.Functional || (hasSession && !sessionSupports(mode))) {\n await disconnect();\n }\n\n callbacks.onModeChange?.(mode);\n }\n }\n\n async function changeMode(mode: ChatMode) {\n if (isStreamsV2 && isChatModeWithoutChat(mode)) {\n throw new ValidationError(UNSUPPORTED_CHAT_MODE_FOR_EXPRESSIVE);\n }\n\n await applyMode(mode);\n }\n\n return {\n agent: agentEntity,\n getStreamType: () => items.streamingManager?.streamType,\n isInterruptAvailable: () => items.streamingManager?.interruptAvailable ?? false,\n // A copy: the same array instance is held by `agent.starter_message`, and handing it out\n // made `manager.starterMessages` an alias the application could write through.\n starterMessages: [...(agentEntity.starter_message ?? [])],\n getSttToken: () => agentsApi.getSttToken(agentEntity.id),\n getChatMode: () => items.chatMode,\n getConnectionState: () => connectionState,\n getSessionInfo: () => sessionInfo,\n changeMode,\n enrichAnalytics: properties => analytics.enrich(properties),\n async connect() {\n // Checked again here, not only at creation: `changeMode()` can move a manager built in\n // a textual mode into one that streams video, and opening that stream with nothing to\n // render it into fails silently — a paid session with no picture.\n if (!callbacks.onSrcObjectReady && !isTextualChat(items.chatMode)) {\n throw new ValidationError(MISSING_SRC_OBJECT_READY);\n }\n\n if (opInFlight) {\n // The latest call wins: connect() after a disconnect() that landed mid-connect (a\n // React StrictMode remount) keeps the session instead of tearing it down.\n disconnectRequested = false;\n return opInFlight;\n }\n\n if (items.streamingManager && !SESSION_ENDED_STATES.includes(connectionState)) {\n throw new ValidationError('Already connected; call disconnect() first');\n }\n\n await runConnect(true);\n\n // Not tracked when a `disconnect()` overtook the attempt: nothing is connected.\n if (items.streamingManager) {\n analytics.track('agent-chat', {\n event: 'connect',\n mode: items.chatMode,\n });\n }\n },\n async reconnect() {\n if (opInFlight) {\n throw new ValidationError('A connect() is in flight; wait for it before calling reconnect()');\n }\n\n // The whole body holds the flag, teardown included, so a `disconnect()` cannot land\n // between the teardown and the new session.\n return runOp(async () => {\n const streamingManager = items.streamingManager as { reconnect?: () => Promise<void> } | undefined;\n let fallbackReason: string | undefined;\n\n if (isStreamsV2 && streamingManager?.reconnect) {\n try {\n await streamingManager.reconnect();\n } catch (error) {\n const analyticsError = toErrorAnalytics(error);\n // Keep the Agents API's own classification where there is one — `kind` is\n // the literal `'HttpError'` for every failed request since 3.0.\n fallbackReason = analyticsError.code ?? analyticsError.kind;\n await disconnect();\n await connect(false);\n }\n } else {\n await disconnect();\n await connect(false);\n }\n\n analytics.track('agent-chat', {\n event: 'reconnect',\n mode: items.chatMode,\n // A mid-flight disconnect, or a server mode that tore the session down, leaves\n // nothing connected.\n success: !!items.streamingManager,\n ...(fallbackReason && { fallbackReason }),\n });\n });\n },\n async disconnect() {\n // Not awaited: a connect can take minutes (three attempts, 45 s each, plus a web\n // socket with no timeout of its own), and an unmount handler must not inherit that.\n // The flag is what closes the race — the operation checks it once it has a session and\n // tears down what it built.\n if (opInFlight) {\n disconnectRequested = true;\n }\n\n await disconnect();\n\n analytics.track('agent-chat', {\n event: 'disconnect',\n mode: items.chatMode,\n });\n },\n publishMicrophoneStream(stream: MediaStream): Promise<void> {\n if (!items.streamingManager?.publishMicrophoneStream) {\n return Promise.reject(\n new ValidationError(\n 'publishMicrophoneStream is only available on Expressive (V4) agents, after connect()'\n )\n );\n }\n return items.streamingManager.publishMicrophoneStream(stream);\n },\n setSttLanguage(language: string): Promise<void> {\n if (!isStreamsV2 || !items.streamingManager) {\n return Promise.reject(\n new ValidationError('setSttLanguage is only available on Expressive (V4) agents, after connect()')\n );\n }\n\n analytics.track('agent-stt-language-change', { language });\n\n return items.streamingManager.sendDataChannelMessage(\n InternalDataChannelTopic.SttLanguage,\n JSON.stringify({ language })\n );\n },\n sendDataChannelMessage(topic: `${DataChannelTopic}`, payload: Record<string, unknown>): Promise<void> {\n if (!isStreamsV2 || !items.streamingManager) {\n return Promise.reject(\n new ValidationError(\n 'sendDataChannelMessage is only available on Expressive (V4) agents, after connect()'\n )\n );\n }\n\n analytics.track('agent-data-message', { topic });\n\n return items.streamingManager.sendDataChannelMessage(topic, JSON.stringify(payload));\n },\n unpublishMicrophoneStream(): Promise<void> {\n if (!items.streamingManager?.unpublishMicrophoneStream) {\n return Promise.resolve();\n }\n return items.streamingManager.unpublishMicrophoneStream();\n },\n replaceMicrophoneTrack(track: MediaStreamTrack): Promise<void> {\n if (!items.streamingManager?.replaceMicrophoneTrack) {\n return Promise.reject(\n new ValidationError(\n 'replaceMicrophoneTrack is only available on Expressive (V4) agents, after connect()'\n )\n );\n }\n return items.streamingManager.replaceMicrophoneTrack(track);\n },\n publishCameraStream(stream: MediaStream): Promise<void> {\n if (!items.streamingManager?.publishCameraStream) {\n return Promise.reject(\n new ValidationError(\n 'publishCameraStream is only available on Expressive (V4) agents, after connect()'\n )\n );\n }\n return items.streamingManager.publishCameraStream(stream);\n },\n unpublishCameraStream(): Promise<void> {\n if (!items.streamingManager?.unpublishCameraStream) {\n return Promise.resolve();\n }\n return items.streamingManager.unpublishCameraStream();\n },\n async chat(userMessage: string) {\n const validateChatRequest = () => {\n if (isChatModeWithoutChat(items.chatMode)) {\n throw new ValidationError(`${items.chatMode} is enabled, chat is disabled`);\n } else if (userMessage.length >= MAX_CHAT_MESSAGE_LENGTH) {\n throw new ValidationError(`Message cannot be more than ${MAX_CHAT_MESSAGE_LENGTH} characters`);\n } else if (userMessage.length === 0) {\n throw new ValidationError('Message cannot be empty');\n } else if (items.chatMode === ChatMode.Maintenance) {\n throw new ValidationError('Chat is in maintenance mode');\n } else if (![ChatMode.TextOnly, ChatMode.Playground].includes(items.chatMode)) {\n if (!items.streamingManager) {\n throw new ValidationError('Streaming manager is not initialized');\n }\n if (!items.chat) {\n throw new ValidationError('Chat is not initialized');\n }\n }\n };\n\n const initializeChat = async () => {\n if (!items.chat) {\n const newChat = await createChat(\n agentEntity,\n agentsApi,\n analytics,\n items.chatMode,\n managerOptions.persistentChat\n );\n\n if (!newChat.chat) {\n throw new ChatCreationFailed(items.chatMode, !!managerOptions.persistentChat);\n }\n\n items.chat = newChat.chat;\n callbacks.onNewChat?.(items.chat.id);\n }\n\n return items.chat.id;\n };\n\n const sendChatRequest = async (messages: Message[], chatId: string) => {\n // For playground mode, always use v1 path\n const isPlayground = items.chatMode === ChatMode.Playground;\n const useV2Path = isStreamsV2 && !isPlayground;\n\n const chatRequestFn = useV2Path\n ? async () => {\n await items.streamingManager?.sendDataChannelMessage(\n InternalDataChannelTopic.Chat,\n userMessage\n );\n return Promise.resolve({} as ChatResponse);\n }\n : async () => {\n return agentsApi.chat(\n agentEntity.id,\n chatId,\n {\n chatMode: items.chatMode,\n streamId: items.streamingManager?.streamId,\n sessionId: items.streamingManager?.sessionId,\n messages: messages.map(({ matches, createdAt, ...message }) => ({\n ...message,\n // A restored `initialMessages` row may carry no timestamp; the API requires one.\n created_at: createdAt ?? new Date().toISOString(),\n })),\n },\n {\n ...getRequestHeaders(items.chatMode),\n skipErrorHandler: true,\n }\n );\n };\n\n return retryOperation(chatRequestFn, {\n limit: 2,\n shouldRetryFn: error => {\n const isInvalidSessionId = error?.message?.includes('missing or invalid session_id');\n const isStreamError = error?.message?.includes('Stream Error');\n\n if (!isStreamError && !isInvalidSessionId) {\n callbacks.onError?.(error);\n return false;\n }\n return true;\n },\n onRetry: async () => {\n await disconnect();\n await runConnect(false);\n },\n });\n };\n\n try {\n clearQueue();\n validateChatRequest();\n\n items.messages.push({\n id: getRandom(),\n role: 'user',\n content: userMessage,\n parts: parseMessagePartsMemo(userMessage),\n createdAt: new Date(latencyTimestampTracker.update()).toISOString(),\n });\n\n callbacks.onNewMessage?.([...items.messages], 'user');\n\n const chatId = await initializeChat();\n const response = await sendChatRequest([...items.messages], chatId);\n\n // Skip the assistant push entirely when `response.result` is empty — streaming\n // modes deliver the actual reply through `chat/partial` + `chat/answer`, so the\n // REST endpoint commonly returns an empty string that would otherwise leave a\n // ghost assistant entry in `items.messages` (a \"\" bubble hidden by CSS but still\n // exported in transcripts).\n if (response.result) {\n items.messages.push({\n id: getRandom(),\n role: 'assistant',\n content: response.result,\n parts: parseMessagePartsMemo(response.result),\n createdAt: new Date().toISOString(),\n context: response.context,\n matches: response.matches,\n });\n }\n\n analytics.track('agent-message-send', {\n event: 'success',\n messages: items.messages.length + 1,\n });\n\n if (response.result) {\n callbacks.onNewMessage?.([...items.messages], 'answer');\n\n analytics.track('agent-message-received', {\n latency: latencyTimestampTracker.get(true),\n messages: items.messages.length,\n });\n }\n\n return response;\n } catch (e) {\n if (items.messages[items.messages.length - 1]?.role === 'assistant') {\n items.messages.pop();\n }\n\n analytics.track('agent-message-send', {\n event: 'error',\n messages: items.messages.length,\n error: toErrorAnalytics(e),\n });\n\n throw e;\n }\n },\n async rate(messageId: string, score: 1 | -1, rateId?: string) {\n const message = items.messages.find(message => message.id === messageId);\n\n if (!items.chat) {\n throw new ValidationError('Chat is not initialized');\n } else if (!message) {\n throw new ValidationError('Message not found');\n }\n\n const matches: [string, string][] = message.matches?.map(match => [match.document_id, match.id]) ?? [];\n\n analytics.track('agent-rate', {\n event: rateId ? 'update' : 'create',\n thumb: score === 1 ? 'up' : 'down',\n knowledge_id: agentEntity.knowledge?.id ?? '',\n matches,\n score,\n });\n\n if (rateId) {\n return agentsApi.updateRating(agentEntity.id, items.chat.id, rateId, {\n knowledge_id: agentEntity.knowledge?.id ?? '',\n message_id: messageId,\n matches,\n score,\n });\n }\n\n return agentsApi.createRating(agentEntity.id, items.chat.id, {\n knowledge_id: agentEntity.knowledge?.id ?? '',\n message_id: messageId,\n matches,\n score,\n });\n },\n async deleteRate(id: string) {\n if (!items.chat) {\n throw new ValidationError('Chat is not initialized');\n }\n\n analytics.track('agent-rate-delete', { type: 'text' });\n\n return agentsApi.deleteRating(agentEntity.id, items.chat.id, id);\n },\n async submitFeedback(rating: 1 | 2 | 3 | 4 | 5, answer?: string) {\n if (!items.chat) {\n throw new ValidationError('Chat is not initialized');\n }\n\n analytics.track('agent-feedback', { rating, hasAnswer: !!answer });\n\n return agentsApi.submitFeedback(agentEntity.id, items.chat.id, { rating, answer });\n },\n async speak(payload: string | SpeakScript) {\n function getScript(): StreamScript {\n if (typeof payload === 'string') {\n return {\n type: 'text',\n input: payload,\n ssml: false,\n };\n }\n\n if (payload.type === 'text' && !payload.provider) {\n return {\n type: 'text',\n input: payload.input,\n ssml: payload.ssml,\n should_queue_speaks: payload.should_queue_speaks,\n sentiment: payload.sentiment,\n };\n }\n\n return payload;\n }\n\n // A textual chat produces no video, so there is nothing to speak.\n const isTextual = isTextualChat(items.chatMode);\n if (!isTextual && !items.streamingManager) {\n throw new ValidationError('Please connect to the agent first');\n }\n\n const script = getScript();\n analytics.track('agent-speak', script);\n latencyTimestampTracker.update();\n\n if (items.messages && script.type === 'text') {\n items.messages.push({\n id: getRandom(),\n role: 'assistant',\n content: script.input,\n parts: parseMessagePartsMemo(script.input),\n createdAt: new Date().toISOString(),\n });\n callbacks.onNewMessage?.([...items.messages], 'answer');\n }\n\n const noVideoResponse = { duration: 0, videoId: '', status: 'success' };\n\n if (isTextual || !items.streamingManager) {\n return noVideoResponse;\n }\n\n const response = await items.streamingManager.speak({\n script,\n metadata: { chat_id: items.chat?.id, agent_id: agentEntity.id },\n });\n\n return response ?? noVideoResponse;\n },\n interrupt,\n registerClientTool,\n unregisterClientTool,\n };\n}\n","import { RunningToolCall } from '@sdk/types';\n\n/**\n * Whether the agent is waiting on a tool call before it can continue.\n *\n * True while any of the running calls is `blocking`; false when nothing is running, or when\n * everything running is `async` and the agent can keep talking. Pass it the array\n * {@link AgentManagerCallbacks.onRunningToolCallsChange | onRunningToolCallsChange} hands you, to\n * decide whether to show the user that the agent is busy.\n *\n * @param calls - The tool calls running right now, as reported by\n * {@link AgentManagerCallbacks.onRunningToolCallsChange | onRunningToolCallsChange}. See\n * {@link RunningToolCall}.\n * @returns `true` while the agent is suspended on a blocking tool call.\n * @example\n * ```ts\n * import { isAwaitingTool, type AgentManagerCallbacks } from '@d-id/client-sdk';\n *\n * const callbacks: AgentManagerCallbacks = {\n * onRunningToolCallsChange(calls) {\n * setSpinnerVisible(isAwaitingTool(calls));\n * },\n * };\n * ```\n * @category Callbacks & Events\n */\nexport function isAwaitingTool(calls: readonly RunningToolCall[]): boolean {\n return calls.some(call => call.executionMode === 'blocking');\n}\n"],"names":["InternalDataChannelTopic","ChatMode","ChatProgress","AvatarType","StreamingState","ConnectivityState","AgentActivityState","StreamEvents","ToolCallEvent","DataChannelTopic","ConnectionState","StreamType","StreamEndReason","TransportProvider","Providers","VoiceAccess","noop","_args","sleep","ms","resolve","getRandom","length","arr","byte","getExternalId","externalId","key","newKey","connectionId","getConnectionId","rotateConnectionId","getAuthHeader","auth","CONNECTION_RETRY_TIMEOUT_MS","PLAYGROUND_HEADER","MAX_CHAT_MESSAGE_LENGTH","didApiUrl","didSocketApiUrl","mixpanelKey","BaseError","message","kind","originalError","cause","isDIDError","error","ChatCreationFailed","mode","persistent","__publicField","ChatModeDowngraded","parseServerError","body","parsed","HttpError","status","meta","NetworkError","StreamError","ValidationError","WsError","getAgentType","presenter","getPresenterType","isStreamsV2Agent","type","isTextualChat","chatMode","isChatModeWithoutChat","VIDEO_THUMBNAIL_RE","IMAGE_RE","VIDEO_EXTENSIONS","isVideoUrl","url","path","ext","MD_LINK_RE","HTML_LINK_RE","parseMessageParts","content","matches","m","entry","src","alt","part","a","b","parts","cursor","memoKey","memoValue","parseMessagePartsMemo","createRacePromise","timeout","timeoutErrorMessage","timeId","_","reject","retryOperation","operation","userOptions","options","lastError","attempt","promise","clear","operationPromise","TooManyRequests","response","retryHttpTooManyRequests","createClient","host","onError","client","skipErrorHandler","fetchOptions","method","start","request","networkError","errorText","createAgentsApi","id","agentId","payload","chatId","ratingId","getAnalyticsInfo","agent","_a","_b","mobileOrDesktop","getUserOS","platform","getAgentInfo","getErrorMessage","sumFunc","numbers","total","aNumber","average","min","max","round","value","decimals","factor","percentile","p","sorted","median","safe","fn","fallback","getStreamAnalyticsProps","data","additionalProps","event","baseProps","language","defer","toErrorAnalytics","SDK_VERSION","mixpanelUrl","MAX_QUEUE","failedQueue","flushInFlight","postEvents","events","enqueueFailed","flushQueue","batch","initializeAnalytics","config","source","mixpanelEvents","props","eventTimestamp","audioPath","sendProps","eventTime","eventData","mixpanelEvent","dependencies","linkedEvent","aggregatedProps","acc","curr","createTimestampTracker","timestamp","delta","latencyTimestampTracker","interruptTimestampTracker","streamReadyTimestampTracker","getRequestHeaders","createChat","agentsApi","analytics","persist","chat","getInitialMessages","initialMessages","connect","callbacks","onMessage","onOpen","onClose","socket","e","connectWithRetries","retries","createSocketManager","messageCallbacks","parsedData","callback","LEGACY_CLOSE_REASON_TO_END_REASON","toStreamEndReason","COMPLETED_EVENTS","FAILED_EVENTS","getMessageContent","chatEventQueue","currentSequence","handleAudioTranscribedMessage","items","onNewMessage","userMessage","processChatEvent","clearQueue","lastAssistantMessageType","lastMessage","isNewAssistantMessage","currentMessage","sequence","partialsContent","messageContent","createMessageEventQueue","agentEntity","onStreamDone","messages","_c","chatEvent","SEvent","updatedMessage","streamEvent","createStreamApi","signal","streamId","answer","sessionId","candidate","wire","createStreamingLogger","debug","prefix","extra","AUDIO_LEAD_PERCEPTIBLE_MS","buildAvSyncReport","stats","samples","stat","sample","durationMs","offsets","perceptible","offset","steady","steadyOffsets","worst","createAggregateReport","end","lowFpsCount","duration","extractAnomalies","report","updatedReport","causes","formatStats","codec","currRtt","videoInboundRtp","audioInboundRtp","codecIdToMime","pair","rtt","inbound","slim","createVideoStatsReport","interval","previousStats","differentialReport","index","anomalies","avgJittersSamples","avgRttSamples","findInboundRtpReport","AUDIO_STATS_POLL_INTERVAL_MS","createAudioStatsDetector","getStats","onFirstAudioDetected","armed","baselined","timerId","prevTotalAudioEnergy","prevTotalSamplesReceived","armContext","poll","totalAudioEnergy","totalSamplesReceived","energyDelta","samplesDelta","context","notReceivingIntervalsThreshold","LOW_JITTER_TRESHOLD","HIGH_JITTER_TRESHOLD","createVideoStatsAnalyzer","lastFramesReceived","prevDelay","prevCount","avgJitterDelayInInterval","delay","count","deltaDelay","deltaCount","currFramesReceived","isReceiving","createVideoStatsMonitor","getIsConnected","onConnected","onVideoStateChange","onConnectivityStateChange","intervalId","allStats","notReceivingNumIntervals","isStreaming","prevLowConnState","currLowConnState","currFreezeCount","prevFreezeCount","isReceivingVideoBytes","getAndAnalyzeVideoStats","freezeCount","slimStats","statsReport","getRTCPeerConnection","w","impl","mapConnectionState","state","createParseDataChannelMessage","log","subject","rawData","handleLegacyStreamState","statsSignal","dataChannelSignal","handleFluentStreamState","onAgentActivityStateChange","handleStreamState","streamType","createWebRTCStreamingManager","streamOptions","baseURL","parseDataChannelMessage","isConnected","isDatachannelOpen","startConnection","sendStreamRequest","close","createStream","addIceCandidate","streamIdFromServer","offer","ice_servers","session_id","fluent","interruptAvailable","reportError","peerConnection","pcDataChannel","warmup","videoStatsMonitor","currentVideoId","handleStreamVideoIdChange","videoId","handleStreamVideoEvent","metadata","handleStreamReadyEvent","_subject","streamMetadata","dataChannelHandlers","newState","sessionClientAnswer","sendDataChannelMessage","_topic","_type","StreamApiVersion","createStreamingManager","version","createStreamOptions","createLiveKitStreamingManager","ChatPrefix","getAgentStreamV2Options","getAgentStreamV1Options","endUserData","getAgentStreamOptions","trackConnectionStateChangeAnalytics","reason","trackVideoStateChangeAnalytics","trackVideoStreamAnalytics","trackLegacyVideoAnalytics","trackAgentActivityAnalytics","metrics","trackToolEventAnalytics","finishedPayload","connectToManager","streamingManager","shouldResolveOnComplete","pendingStartTrack","isStreamsV2","readyLatency","initializeStreamAndChat","resolveStreamAndChat","now","abortController","streamingManagerRef","createChatPromise","connectToManagerPromise","manager","chatResult","newChat","UNSUPPORTED_CHAT_MODE_FOR_EXPRESSIVE","MISSING_SRC_OBJECT_READY","SESSION_ENDED_STATES","createAgentManager","_d","_e","appCallbacks","firstConnection","mxKey","wsURL","initTimestamp","connectionState","sessionInfo","errorData","stream","managerOptions","preloadLiveKit","updateVideoId","interrupt","clientToolHandlers","createRpcHandler","toolName","handler","args","flushClientToolsToRoom","name","registerClientTool","isNew","unregisterClientTool","loadedTimestamp","opInFlight","disconnectRequested","runOp","runConnect","disconnect","websocketPromise","sessionNeedsSocket","initPromise","applyMode","previousChatId","socketManager","isNewChat","serverMode","sessionSupports","needsChat","hasSession","changeMode","properties","fallbackReason","analyticsError","topic","track","validateChatRequest","initializeChat","sendChatRequest","isPlayground","createdAt","isInvalidSessionId","messageId","score","rateId","match","rating","getScript","isTextual","script","noVideoResponse","isAwaitingTool","calls","call"],"mappings":"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"}
|