@dudousxd/nestjs-agent-react 0.35.1 → 0.35.3
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/{generative-ui-D1efzu_K.d.ts → generative-ui-DySIh0up.d.ts} +3 -0
- package/dist/{generative-ui-ClYT7OgL.d.cts → generative-ui-Pz1t-Ap3.d.cts} +3 -0
- package/dist/genui-json-render.cjs +88 -45
- package/dist/genui-json-render.cjs.map +1 -1
- package/dist/genui-json-render.d.cts +1 -1
- package/dist/genui-json-render.d.ts +1 -1
- package/dist/genui-json-render.js +91 -46
- package/dist/genui-json-render.js.map +1 -1
- package/dist/genui.cjs +88 -45
- package/dist/genui.cjs.map +1 -1
- package/dist/genui.d.cts +1 -1
- package/dist/genui.d.ts +1 -1
- package/dist/genui.js +91 -46
- package/dist/genui.js.map +1 -1
- package/dist/index.cjs +172 -84
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +7 -2
- package/dist/index.d.ts +7 -2
- package/dist/index.js +251 -161
- package/dist/index.js.map +1 -1
- package/package.json +2 -2
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/http-error.ts","../src/client.ts","../src/reasoning/timing.ts","../src/agent-chat-transport.ts","../src/attachments/files.ts","../src/attachments/use-attachments.ts","../src/backend.ts","../src/config/use-agent-config.ts","../src/provider.tsx","../src/components/ambient-ui.ts","../src/genui/generative-ui.tsx","../src/genui/use-generative-ui.ts","../src/genui/types.ts","../src/ag-ui-backend.ts","../src/catalog/use-agents.ts","../src/catalog/use-resource.ts","../src/catalog/use-models.ts","../src/quota/use-quota.ts","../src/threads/threads-events.ts","../src/feedback/use-message-feedback.ts","../src/threads/use-threads.ts","../src/background-runs.ts","../src/components/chat-input.tsx","../src/components/use-speech-recognition.ts","../src/components/message-item.tsx","../src/transcript/use-chat-transcript.ts","../src/transcript/model.ts","../src/elicitation/answers.ts","../src/presentation/tool-activity.ts","../src/presentation/phrasing.ts","../src/presentation/result-view.ts","../src/transcript/use-stick-to-bottom.ts","../src/components/message-list.tsx","../src/components/speech-languages.ts","../src/composer/model.ts","../src/composer/skills-source.ts","../src/composer/use-composer-autocomplete.ts","../src/presentation/use-tool-catalog.ts","../src/approvals/countdown.ts","../src/stored-message-to-ui-message.ts","../src/stored-thread-to-ui-messages.ts","../src/use-agent-chat.ts","../src/approvals/use-action-proposals.ts","../src/approvals/proposals.ts","../src/run-errors.ts"],"sourcesContent":["/**\n * What a server said when it refused a request, read once so every error class of this package\n * reports it the same way. Bundled into each entry that throws (the root and `/media`), which is\n * why it holds no class of its own.\n */\nexport interface ErrorAnswer {\n /** The body, parsed as JSON when it is JSON, else the raw text; `undefined` when empty. */\n body: unknown;\n /** `body.message` — a string, or NestJS's list of validation messages joined with `; `. */\n message: string | undefined;\n /** `body.code`, the machine-readable reason (`quota_exceeded`, …), when the server sent one. */\n code: string | undefined;\n}\n\n/** Read an error answer's body text. Never throws: a body that cannot be read is just absent. */\nexport function readErrorAnswer(text: string | null | undefined): ErrorAnswer {\n if (text == null || text === '') return { body: undefined, message: undefined, code: undefined };\n let body: unknown = text;\n try {\n body = JSON.parse(text);\n } catch {\n return { body: text, message: undefined, code: undefined };\n }\n if (body === null || typeof body !== 'object')\n return { body, message: undefined, code: undefined };\n const record = body as { message?: unknown; code?: unknown };\n const message =\n typeof record.message === 'string' && record.message !== ''\n ? record.message\n : Array.isArray(record.message) &&\n record.message.length > 0 &&\n record.message.every((each) => typeof each === 'string')\n ? record.message.join('; ')\n : undefined;\n const code = typeof record.code === 'string' && record.code !== '' ? record.code : undefined;\n return { body, message, code };\n}\n\n/** {@link readErrorAnswer} over a `Response` whose status is not 2xx. */\nexport async function readErrorResponse(response: Response): Promise<ErrorAnswer> {\n let text: string | undefined;\n try {\n text = await response.text();\n } catch {\n text = undefined;\n }\n return readErrorAnswer(text);\n}\n\n/**\n * The shape both {@link import('./client.js').AgentHttpError} and `MediaUploadError` share, for\n * code that handles either without an `instanceof` (the two live in separate bundles).\n */\nexport interface AgentRequestError extends Error {\n status: number;\n method: string;\n path: string;\n body: unknown;\n code: string | undefined;\n}\n\n/** Called with every error answer before it is thrown — for app-wide reactions (401, 402, …). */\nexport type HttpErrorListener = (error: AgentRequestError) => void;\n\n/** Tell `listener` about `error`; a listener that throws never replaces the error itself. */\nexport function reportHttpError(\n listener: HttpErrorListener | undefined,\n error: AgentRequestError,\n): void {\n if (listener === undefined) return;\n try {\n listener(error);\n } catch {\n /* the request's own error is what the caller gets */\n }\n}\n","import type {\n ActionProposalMutationView,\n ActionProposalView,\n AgentCatalogEntry,\n AgentClientConfig,\n ChatQueueState,\n MessageAttachment,\n MessageFeedback,\n ModelCatalogView,\n QuotaReport,\n SkillCatalogEntry,\n ThreadDetail,\n ThreadSummary,\n ToolCatalogEntry,\n} from '@dudousxd/nestjs-agent-core';\nimport type {\n AgentBackend,\n AgentConnection,\n AttachmentUploadStrategy,\n ChatStreamRequest,\n ChatStreamResponse,\n MessageFeedbackInput,\n QueuedMessageUpdate,\n QueuedSendResult,\n ResumeStreamRequest,\n ThreadPatch,\n UploadAttachmentOptions,\n} from './backend.js';\n\nimport {\n type AgentRequestError,\n type ErrorAnswer,\n type HttpErrorListener,\n readErrorAnswer,\n readErrorResponse,\n reportHttpError,\n} from './http-error.js';\n\nexport type { ThreadPatch } from './backend.js';\nexport type { AgentRequestError, HttpErrorListener } from './http-error.js';\n\n/**\n * Thrown by {@link AgentClient} on a non-2xx response. Carries the HTTP `status` so callers can\n * branch (e.g. 403 → \"not your thread\", 429 → quota) instead of string-matching a generic Error,\n * and what the server said: `message` is the body's `message` when it sent one (so a hook that\n * shows `error.message` shows the server's words), `code` its machine-readable `code`, and `body`\n * the whole answer, parsed when it is JSON.\n */\nexport class AgentHttpError extends Error implements AgentRequestError {\n /** The answer's body: parsed JSON, else its text; `undefined` when empty. */\n readonly body: unknown;\n /** The body's `code` (`quota_exceeded`, …), when the server sent one. */\n readonly code: string | undefined;\n\n constructor(\n readonly status: number,\n readonly method: string,\n readonly path: string,\n statusText: string,\n answer: ErrorAnswer = { body: undefined, message: undefined, code: undefined },\n ) {\n super(answer.message ?? `Agent request failed: ${method} ${path} → ${status} ${statusText}`);\n this.name = 'AgentHttpError';\n this.body = answer.body;\n this.code = answer.code;\n }\n\n /** Read a refused `response`'s body into an error. */\n static async from(response: Response, method: string, path: string): Promise<AgentHttpError> {\n return new AgentHttpError(\n response.status,\n method,\n path,\n response.statusText,\n await readErrorResponse(response),\n );\n }\n}\n\nexport interface CancelResult {\n aborted: boolean;\n}\n\nexport interface OkResult {\n ok: boolean;\n}\n\nexport interface AgentClientOptions {\n /**\n * The server's origin, e.g. `https://api.example.com`. Defaults to `''` (same origin). The\n * agent's route prefix is {@link AgentClientOptions.path}, not part of this.\n */\n baseUrl?: string;\n /**\n * The agent's route prefix — `AgentModule`'s `path`, with any global prefix in front\n * (`'api/agent'`). Leading/trailing slashes are optional. Defaults to `'agent'`.\n */\n path?: string;\n /** Static headers merged into every request. */\n headers?: Record<string, string>;\n /**\n * Resolved per request — for short-lived bearer tokens, or a CSRF header read from a cookie\n * (`{ 'X-XSRF-TOKEN': readCookie('XSRF-TOKEN') }`), which has to be read at request time because\n * the server may rotate it.\n */\n getHeaders?: () => Record<string, string> | Promise<Record<string, string>>;\n /**\n * Forwarded to fetch so cookie auth works. Same-origin requests send cookies by default; set\n * `'include'` when the API lives on another origin (and have it answer with credentialed CORS).\n */\n credentials?: RequestCredentials;\n /** Injectable for tests / non-browser runtimes. */\n fetch?: typeof fetch;\n /**\n * Called with every error answer (an {@link AgentHttpError}, or a `MediaUploadError` from a\n * `mediaAttachments()` upload) right before it is thrown — the place for app-wide reactions such\n * as \"401 → sign in again\". The error still reaches the caller. Not called for the `404` a\n * resume answers when nothing is streaming, which is an answer, not a failure.\n */\n onHttpError?: HttpErrorListener;\n /** Attachment uploads. */\n attachments?: {\n /**\n * How `uploadAttachment` uploads. Omitted → `POST <path>/attachments` (multipart). Pass\n * `mediaAttachments()` from `@dudousxd/nestjs-agent-react/media` for resumable uploads through\n * nestjs-media, or your own {@link AttachmentUploadStrategy}.\n */\n upload?: AttachmentUploadStrategy;\n };\n}\n\n/** `'/api/agent'` from `'api/agent'`, `'/api/agent/'`, …; `''` for an empty path. */\nexport function normalizeAgentPath(path: string | undefined): string {\n const trimmed = (path ?? 'agent').replace(/^\\/+|\\/+$/g, '');\n return trimmed === '' ? '' : `/${trimmed}`;\n}\n\nconst HEADER_RUN_ID = 'x-agent-run-id';\nconst HEADER_THREAD_ID = 'x-agent-thread-id';\n\n/**\n * Framework-agnostic REST client for the nestjs-agent endpoints — the default {@link AgentBackend}.\n * Used by `useAgentChat`, but standalone-usable (vanilla fetch, no React).\n */\nexport class AgentClient implements AgentBackend {\n constructor(private readonly options: AgentClientOptions = {}) {}\n\n /** `POST <path>/chat` → the turn's SSE stream. Throws {@link AgentHttpError} on a non-2xx. */\n async openChatStream(request: ChatStreamRequest): Promise<ChatStreamResponse> {\n const response = await this.fetchImpl()(`${this.root()}/chat`, {\n method: 'POST',\n headers: {\n 'content-type': 'application/json',\n accept: 'text/event-stream',\n ...(await this.resolveHeaders()),\n ...request.headers,\n },\n body: JSON.stringify(request.body),\n ...this.credentials(),\n ...(request.signal !== undefined ? { signal: request.signal } : {}),\n });\n if (response.status === 202) {\n // Queued behind a turn already running on the thread: JSON, not a stream.\n return { body: emptyStream(), queued: (await response.json()) as QueuedSendResult };\n }\n if (response.ok && response.headers.get('content-type')?.includes('application/json')) {\n const decision = (await response.json()) as NonNullable<\n ChatStreamResponse['proposalDecision']\n >;\n if (decision.proposalDecision !== undefined && typeof decision.threadId === 'string')\n return { body: emptyStream(), threadId: decision.threadId, proposalDecision: decision };\n throw new Error('Unexpected JSON chat response');\n }\n if (!response.ok || !response.body) {\n throw await this.failure(response, 'POST', `${this.agentPath()}/chat`);\n }\n return streamResponse(response);\n }\n\n /**\n * `POST <path>/chat` for a message that should wait in the thread's queue — the body carries\n * `mode: 'queue'` (or `'interrupt'`), which the server always answers with `202` JSON.\n */\n enqueueMessage(request: ChatStreamRequest): Promise<QueuedSendResult> {\n return this.request<QueuedSendResult>('POST', '/chat', {\n mode: 'queue',\n ...request.body,\n });\n }\n\n /** `GET <path>/threads/:id/queue` — the thread's waiting messages, and whether it drains. */\n getQueue(threadId: string): Promise<ChatQueueState> {\n return this.request<ChatQueueState>('GET', `/threads/${encodeURIComponent(threadId)}/queue`);\n }\n\n /** `PATCH <path>/queue/:messageId` — change a waiting message's text/attachments, or move it. */\n updateQueuedMessage(messageId: string, update: QueuedMessageUpdate): Promise<ChatQueueState> {\n return this.request<ChatQueueState>('PATCH', `/queue/${encodeURIComponent(messageId)}`, update);\n }\n\n /** `DELETE <path>/queue/:messageId`. */\n removeQueuedMessage(messageId: string): Promise<ChatQueueState> {\n return this.request<ChatQueueState>('DELETE', `/queue/${encodeURIComponent(messageId)}`);\n }\n\n /**\n * `POST <path>/queue/:messageId/interrupt` — run a waiting message now, cancelling the running\n * turn for it. `runId` when nothing was running and it started; else `interrupting`.\n */\n interruptQueuedMessage(\n messageId: string,\n ): Promise<ChatQueueState & { runId?: string; interrupting?: string }> {\n return this.request<ChatQueueState & { runId?: string; interrupting?: string }>(\n 'POST',\n `/queue/${encodeURIComponent(messageId)}/interrupt`,\n );\n }\n\n /** `DELETE <path>/threads/:id/queue` — drop every waiting message. */\n clearQueue(threadId: string): Promise<ChatQueueState> {\n return this.request<ChatQueueState>('DELETE', `/threads/${encodeURIComponent(threadId)}/queue`);\n }\n\n /** `POST <path>/threads/:id/queue/resume` — lift a pause; `runId` when the head started. */\n resumeQueue(threadId: string): Promise<ChatQueueState & { runId?: string }> {\n return this.request<ChatQueueState & { runId?: string }>(\n 'POST',\n `/threads/${encodeURIComponent(threadId)}/queue/resume`,\n );\n }\n\n /**\n * `GET <path>/chat/:runId/stream[?after=<seq>]` → the run's SSE stream, or `null` when nothing is\n * streaming under that id (404).\n */\n async resumeChatStream(request: ResumeStreamRequest): Promise<ChatStreamResponse | null> {\n const path = `/chat/${encodeURIComponent(request.runId)}/stream`;\n const query = request.after !== undefined && request.after > 0 ? `?after=${request.after}` : '';\n const response = await this.fetchImpl()(`${this.root()}${path}${query}`, {\n method: 'GET',\n headers: {\n accept: 'text/event-stream',\n ...(await this.resolveHeaders()),\n ...request.headers,\n },\n ...this.credentials(),\n ...(request.signal !== undefined ? { signal: request.signal } : {}),\n });\n if (response.status === 404) {\n return null;\n }\n if (!response.ok || !response.body) {\n throw await this.failure(response, 'GET', `${this.agentPath()}${path}`);\n }\n return streamResponse(response);\n }\n\n /**\n * Rate a message (`'up'`/`'down'`, optional comment) or clear its rating (`value: null`). Answers\n * the stored rating.\n */\n setMessageFeedback(\n messageId: string,\n input: MessageFeedbackInput,\n ): Promise<{ feedback: MessageFeedback | null }> {\n return this.request<{ feedback: MessageFeedback | null }>(\n 'POST',\n `/messages/${encodeURIComponent(messageId)}/feedback`,\n input,\n );\n }\n\n listThreads(): Promise<ThreadSummary[]> {\n return this.request<ThreadSummary[]>('GET', '/threads');\n }\n\n /**\n * The skills this caller can invoke right now, scope-resolved — the same list, built by the same\n * call, that the model is offered, so what a user can type after a `/` and what the agent can\n * reach cannot drift apart. `threadId` reaches the host's own resolver, which may scope a skill to\n * one conversation; omitted, the server reads it as a brand-new thread.\n */\n listSkills(threadId?: string): Promise<SkillCatalogEntry[]> {\n const query = threadId === undefined ? '' : `?threadId=${encodeURIComponent(threadId)}`;\n return this.request<SkillCatalogEntry[]>('GET', `/skills${query}`);\n }\n\n /**\n * The tools this caller can reach through `agent` (the default agent when omitted), each with the\n * server-declared `presentation` a chat narrates it by — the same list the model is offered.\n * Prefer {@link useToolCatalog}, which fetches it once and shares it.\n */\n listTools(agent?: string): Promise<ToolCatalogEntry[]> {\n const query = agent === undefined ? '' : `?agent=${encodeURIComponent(agent)}`;\n return this.request<ToolCatalogEntry[]>('GET', `/tools${query}`);\n }\n\n getThread(id: string): Promise<ThreadDetail> {\n return this.request<ThreadDetail>('GET', `/threads/${encodeURIComponent(id)}`);\n }\n\n deleteThread(id: string): Promise<void> {\n return this.request<void>('DELETE', `/threads/${encodeURIComponent(id)}`);\n }\n\n forkFromMessage(threadId: string, messageId: string): Promise<ThreadSummary> {\n return this.request<ThreadSummary>(\n 'POST',\n `/threads/${encodeURIComponent(threadId)}/fork-from/${encodeURIComponent(messageId)}`,\n );\n }\n\n /** General `PATCH <path>/threads/:threadId` — title and/or the thread's pinned default agent. */\n updateThread(id: string, patch: ThreadPatch): Promise<OkResult> {\n return this.request<OkResult>('PATCH', `/threads/${encodeURIComponent(id)}`, patch);\n }\n\n /**\n * Uploads a file (image/PDF) for a vision-capable model turn. Multipart, field name `file` —\n * mirrors the backend's `POST <path>/attachments`. The returned {@link MessageAttachment} is\n * what a caller then rides on `sendMessage({ text }, { body: { attachments: [...] } })`.\n */\n async uploadAttachment(\n file: File,\n options: UploadAttachmentOptions = {},\n ): Promise<MessageAttachment> {\n const upload = this.options.attachments?.upload;\n if (upload !== undefined) {\n return upload(file, options, this.connection());\n }\n // `fetch` cannot observe an upload's progress; XHR can. Only when someone is listening, and\n // never when a `fetch` was injected (tests, non-browser runtimes).\n if (\n options.onProgress !== undefined &&\n this.options.fetch === undefined &&\n typeof XMLHttpRequest !== 'undefined'\n ) {\n return this.uploadWithProgress(file, options);\n }\n const formData = new FormData();\n formData.append('file', file);\n const response = await this.fetchImpl()(`${this.root()}/attachments`, {\n method: 'POST',\n headers: {\n accept: 'application/json',\n ...(await this.resolveHeaders()),\n },\n body: formData,\n ...this.credentials(),\n ...(options.signal !== undefined ? { signal: options.signal } : {}),\n });\n const attachment = await this.handleResponse<MessageAttachment>(\n response,\n 'POST',\n `${this.agentPath()}/attachments`,\n );\n options.onProgress?.(1);\n return attachment;\n }\n\n private async uploadWithProgress(\n file: File,\n { signal, onProgress }: UploadAttachmentOptions,\n ): Promise<MessageAttachment> {\n const headers: Record<string, string> = {\n accept: 'application/json',\n ...(await this.resolveHeaders()),\n };\n const url = `${this.root()}/attachments`;\n return new Promise<MessageAttachment>((resolve, reject) => {\n const xhr = new XMLHttpRequest();\n xhr.open('POST', url);\n for (const [name, value] of Object.entries(headers)) xhr.setRequestHeader(name, value);\n // Same-origin requests carry cookies regardless; this is the cross-origin opt-in.\n xhr.withCredentials = this.options.credentials === 'include';\n xhr.upload.onprogress = (event) => {\n if (event.lengthComputable && event.total > 0) onProgress?.(event.loaded / event.total);\n };\n xhr.onload = () => {\n if (xhr.status < 200 || xhr.status >= 300) {\n const error = new AgentHttpError(\n xhr.status,\n 'POST',\n `${this.agentPath()}/attachments`,\n xhr.statusText,\n readErrorAnswer(xhr.responseText),\n );\n reportHttpError(this.options.onHttpError, error);\n reject(error);\n return;\n }\n onProgress?.(1);\n resolve(JSON.parse(xhr.responseText) as MessageAttachment);\n };\n xhr.onerror = () => reject(new TypeError('Network error while uploading the attachment'));\n xhr.onabort = () => reject(new DOMException('The upload was aborted', 'AbortError'));\n if (signal !== undefined) {\n if (signal.aborted) {\n reject(new DOMException('The upload was aborted', 'AbortError'));\n return;\n }\n signal.addEventListener('abort', () => xhr.abort(), { once: true });\n }\n const formData = new FormData();\n formData.append('file', file);\n xhr.send(formData);\n });\n }\n\n promoteThread(id: string): Promise<OkResult> {\n return this.request<OkResult>('POST', `/threads/${encodeURIComponent(id)}/promote`);\n }\n\n truncateFromMessage(threadId: string, messageId: string): Promise<OkResult> {\n return this.request<OkResult>(\n 'DELETE',\n `/threads/${encodeURIComponent(threadId)}/from/${encodeURIComponent(messageId)}`,\n );\n }\n\n /** `GET <path>/models?agent=` — the models this caller may pick, grouped by provider. */\n listModels(agent?: string): Promise<ModelCatalogView> {\n const query = agent === undefined ? '' : `?agent=${encodeURIComponent(agent)}`;\n return this.request<ModelCatalogView>('GET', `/models${query}`);\n }\n\n /** `GET <path>/agents` — the registered agents, the default one flagged. */\n listAgents(): Promise<AgentCatalogEntry[]> {\n return this.request<AgentCatalogEntry[]>('GET', '/agents');\n }\n\n /** `GET <path>/config` — attachment limits and upload mode, and which features are on. */\n getConfig(): Promise<AgentClientConfig> {\n return this.request<AgentClientConfig>('GET', '/config');\n }\n\n /** `GET <path>/quota` — the caller's budget windows and the one blocking sends, if any. */\n getQuota(): Promise<QuotaReport> {\n return this.request<QuotaReport>('GET', '/quota');\n }\n\n cancelStream(runId: string): Promise<CancelResult> {\n return this.request<CancelResult>('POST', `/chat/${encodeURIComponent(runId)}/cancel`);\n }\n\n /**\n * `remember` approves later calls of the same tool in the same thread; `via` names the surface\n * the decision came through (the server records `'web'` when omitted).\n */\n async listActionProposals({ threadId }: { threadId: string }): Promise<ActionProposalView[]> {\n const proposals = new Map<string, ActionProposalView>();\n let after: { createdAt: number; id: string } | undefined;\n for (;;) {\n const route = `/threads/${encodeURIComponent(threadId)}/action-proposals${\n after === undefined ? '' : `?after=${encodeURIComponent(JSON.stringify(after))}`\n }`;\n const response = await this.requestResponse('GET', route);\n const page = await this.handleResponse<unknown>(\n response,\n 'GET',\n `${this.agentPath()}${route}`,\n );\n if (!Array.isArray(page)) throw new TypeError('Invalid action proposal page');\n for (const proposal of page) proposals.set(proposal.id, proposal);\n const header = response.headers.get('X-Action-Proposals-Next');\n if (header === null) return [...proposals.values()];\n let next: unknown;\n try {\n next = JSON.parse(decodeURIComponent(header));\n } catch {\n throw new TypeError('Invalid action proposal cursor');\n }\n if (\n typeof next !== 'object' ||\n next === null ||\n !('createdAt' in next) ||\n typeof next.createdAt !== 'number' ||\n !Number.isSafeInteger(next.createdAt) ||\n !('id' in next) ||\n typeof next.id !== 'string' ||\n next.id.length === 0 ||\n next.id.length > 255 ||\n (after !== undefined &&\n (next.createdAt < after.createdAt ||\n (next.createdAt === after.createdAt && next.id <= after.id)))\n )\n throw new TypeError('Invalid or non-advancing action proposal cursor');\n after = { createdAt: next.createdAt, id: next.id };\n }\n }\n approveActionProposal({\n threadId,\n proposalId,\n remember,\n }: {\n threadId: string;\n proposalId: string;\n remember?: boolean;\n }): Promise<ActionProposalMutationView> {\n return this.request(\n 'POST',\n `/threads/${encodeURIComponent(threadId)}/action-proposals/${encodeURIComponent(proposalId)}/approve`,\n remember === undefined ? {} : { remember },\n );\n }\n rejectActionProposal({\n threadId,\n proposalId,\n reason,\n }: {\n threadId: string;\n proposalId: string;\n reason?: string;\n }): Promise<ActionProposalMutationView> {\n return this.request(\n 'POST',\n `/threads/${encodeURIComponent(threadId)}/action-proposals/${encodeURIComponent(proposalId)}/reject`,\n reason === undefined ? {} : { reason },\n );\n }\n\n approveToolCall(input: { toolCallId: string; remember?: boolean; via?: string }): Promise<void> {\n return this.request<void>('POST', '/tool-call/approve', input);\n }\n\n rejectToolCall(input: { toolCallId: string; reason?: string; via?: string }): Promise<void> {\n return this.request<void>('POST', '/tool-call/reject', input);\n }\n\n /**\n * Settle a parked question set. `answers` is questionId → chosen option values; a question left\n * out takes the pre-picked default the request carried, resolved server-side against the request\n * the run already holds. Omit the whole object and the user has confirmed every pre-picked\n * answer — which is the point of the surface, so it is a valid submission rather than a blank.\n * `via` names the surface the answer came through (the server records `'web'` when omitted).\n */\n answerToolCall(input: {\n toolCallId: string;\n answers?: Record<string, string[]>;\n via?: string;\n }): Promise<void> {\n return this.request<void>('POST', '/tool-call/answer', input);\n }\n\n /**\n * Decline to answer and let the agent proceed on its own pre-picked values. Lands on the same\n * values a confirmation would, and persists differently on purpose — only one of them is\n * evidence the user chose them.\n */\n skipToolCall(input: { toolCallId: string; via?: string }): Promise<void> {\n return this.request<void>('POST', '/tool-call/skip', input);\n }\n\n private fetchImpl(): typeof fetch {\n return this.options.fetch ?? globalThis.fetch;\n }\n\n /** This client's connection, for an {@link AttachmentUploadStrategy}. */\n private connection(): AgentConnection {\n return {\n baseUrl: this.baseUrl(),\n path: this.agentPath(),\n headers: () => this.resolveHeaders(),\n fetch: this.fetchImpl(),\n ...this.credentials(),\n ...(this.options.onHttpError !== undefined ? { onHttpError: this.options.onHttpError } : {}),\n };\n }\n\n private baseUrl(): string {\n return (this.options.baseUrl ?? '').replace(/\\/+$/, '');\n }\n\n private agentPath(): string {\n return normalizeAgentPath(this.options.path);\n }\n\n /** Origin + agent path: what every route hangs off. */\n private root(): string {\n return `${this.baseUrl()}${this.agentPath()}`;\n }\n\n private async resolveHeaders(): Promise<Record<string, string>> {\n const dynamic = (await this.options.getHeaders?.()) ?? {};\n return { ...this.options.headers, ...dynamic };\n }\n\n private credentials(): { credentials?: RequestCredentials } {\n return this.options.credentials !== undefined ? { credentials: this.options.credentials } : {};\n }\n\n private async request<T>(method: string, route: string, body?: unknown): Promise<T> {\n const response = await this.requestResponse(method, route, body);\n return this.handleResponse<T>(response, method, `${this.agentPath()}${route}`);\n }\n\n private async requestResponse(method: string, route: string, body?: unknown): Promise<Response> {\n const path = `${this.agentPath()}${route}`;\n const response = await this.fetchImpl()(`${this.baseUrl()}${path}`, {\n method,\n headers: {\n accept: 'application/json',\n ...(body !== undefined ? { 'content-type': 'application/json' } : {}),\n ...(await this.resolveHeaders()),\n },\n ...(body !== undefined ? { body: JSON.stringify(body) } : {}),\n ...this.credentials(),\n });\n return response;\n }\n\n /** The error for a refused `response`, already reported to `onHttpError`. */\n private async failure(response: Response, method: string, path: string): Promise<AgentHttpError> {\n const error = await AgentHttpError.from(response, method, path);\n reportHttpError(this.options.onHttpError, error);\n return error;\n }\n\n private async handleResponse<T>(response: Response, method: string, path: string): Promise<T> {\n if (!response.ok) {\n throw await this.failure(response, method, path);\n }\n if (response.status === 204) return undefined as T;\n const text = await response.text();\n if (!text) return undefined as T;\n return JSON.parse(text) as T;\n }\n}\n\nfunction emptyStream(): ReadableStream<Uint8Array> {\n return new ReadableStream<Uint8Array>({\n start(controller) {\n controller.close();\n },\n });\n}\n\nfunction streamResponse(response: Response): ChatStreamResponse {\n const body = response.body as ReadableStream<Uint8Array>;\n const runId = response.headers?.get(HEADER_RUN_ID) ?? undefined;\n const threadId = response.headers?.get(HEADER_THREAD_ID) ?? undefined;\n return {\n body,\n ...(runId ? { runId } : {}),\n ...(threadId ? { threadId } : {}),\n };\n}\n","import { useEffect, useRef, useState } from 'react';\n\n/**\n * Where a reasoning part carries how long the model thought, in ms. Both producers write it here —\n * the transport on the live `reasoning-end` chunk, `storedMessageToUiMessage` on a replayed part —\n * so a reader has one place to look whichever way the message arrived.\n */\nexport const REASONING_METADATA_KEY = 'agent';\n\n/** The `providerMetadata` a reasoning part is stamped with. */\nexport function reasoningDurationMetadata(reasoningMs: number): {\n [REASONING_METADATA_KEY]: { reasoningMs: number };\n} {\n return { [REASONING_METADATA_KEY]: { reasoningMs } };\n}\n\n/** The thinking time stamped on a reasoning part, or `null` when it carries none. */\nexport function readReasoningMs(part: { providerMetadata?: unknown }): number | null {\n const metadata = part.providerMetadata;\n if (typeof metadata !== 'object' || metadata === null) return null;\n const scoped = (metadata as Record<string, unknown>)[REASONING_METADATA_KEY];\n if (typeof scoped !== 'object' || scoped === null) return null;\n const value = (scoped as Record<string, unknown>).reasoningMs;\n return typeof value === 'number' && Number.isFinite(value) && value >= 0 ? value : null;\n}\n\nexport interface UseElapsedOptions {\n /** How often the value re-renders while running. Default 1000 — a seconds label needs no more. */\n intervalMs?: number;\n /** Injectable clock for tests. */\n now?: () => number;\n}\n\n/**\n * Milliseconds since `running` last turned true — ticking while it stays true, frozen at the final\n * value once it turns false, `0` before it has ever run. Headless: pair it with\n * {@link formatElapsed} or any label of your own.\n *\n * For a reasoning block, prefer the duration the block already carries (`block.durationMs`, the\n * server's own measurement) and fall back to this only while the block streams:\n * `block.durationMs ?? elapsed`.\n */\nexport function useElapsed(running: boolean, options: UseElapsedOptions = {}): number {\n const { intervalMs = 1000 } = options;\n const nowRef = useRef(options.now ?? Date.now);\n nowRef.current = options.now ?? Date.now;\n const startedAt = useRef<number | null>(null);\n const [elapsed, setElapsed] = useState(0);\n\n useEffect(() => {\n if (!running) {\n if (startedAt.current !== null) {\n setElapsed(nowRef.current() - startedAt.current);\n startedAt.current = null;\n }\n return;\n }\n startedAt.current = nowRef.current();\n setElapsed(0);\n const timer = setInterval(() => {\n if (startedAt.current !== null) setElapsed(nowRef.current() - startedAt.current);\n }, intervalMs);\n return () => clearInterval(timer);\n }, [running, intervalMs]);\n\n return elapsed;\n}\n\n/**\n * `\"<1s\"`, `\"4s\"`, `\"1m 5s\"`, `\"1h 2m\"` — whole units, the shape a \"Thought for …\" label wants.\n * Negative or non-finite input reads as `\"<1s\"` rather than a nonsense figure.\n */\nexport function formatElapsed(ms: number): string {\n if (!Number.isFinite(ms) || ms < 1000) return '<1s';\n const totalSeconds = Math.floor(ms / 1000);\n const hours = Math.floor(totalSeconds / 3600);\n const minutes = Math.floor((totalSeconds % 3600) / 60);\n const seconds = totalSeconds % 60;\n if (hours > 0) return minutes > 0 ? `${hours}h ${minutes}m` : `${hours}h`;\n if (minutes > 0) return seconds > 0 ? `${minutes}m ${seconds}s` : `${minutes}m`;\n return `${seconds}s`;\n}\n","import type { AgentStreamEvent } from '@dudousxd/nestjs-agent-core';\nimport type { ChatTransport, UIMessage, UIMessageChunk } from 'ai';\nimport type { AgentBackend, ChatStreamResponse, QueuedSendResult } from './backend.js';\nimport { AgentClient } from './client.js';\nimport { reasoningDurationMetadata } from './reasoning/timing.js';\nimport type { AgentRunFailure } from './run-errors.js';\n\n/** JSON-safe metadata, as the SDK's `toolMetadata` requires (its `JSONObject` is not exported). */\ntype ToolMetadata = { [key: string]: string };\n\n/** Identity surfaced by the backend's `meta` SSE frame / response headers. */\nexport interface AgentStreamMeta {\n runId: string;\n threadId: string;\n}\n\n/**\n * How the transport retries a stream that dropped mid-run. It reconnects only to a server that\n * numbers its frames (SSE `id:`) — without a cursor a reconnect would replay the run into the\n * message it is already writing.\n */\nexport interface ReconnectOptions {\n /** Attempts before giving up with an error chunk. Default 6. */\n maxAttempts?: number;\n /** Delay before the first attempt, doubled each attempt. Default 500 ms. */\n baseDelayMs?: number;\n /** Cap on the delay between attempts. Default 8000 ms. */\n maxDelayMs?: number;\n}\n\n/** Where a live stream stands. `reconnecting` → it dropped and the transport is retrying. */\nexport type StreamConnectionState =\n | { status: 'live' }\n | { status: 'reconnecting'; runId: string; attempt: number; after: number }\n /** The run ended while the client was away (the resume answered 404): reload the thread. */\n | { status: 'gone'; runId: string }\n /** Every attempt failed; the stream ended with an error chunk. */\n | { status: 'failed'; runId: string };\n\nexport interface AgentChatTransportOptions {\n /**\n * What the transport talks to. Default: an {@link AgentClient} built from `baseUrl`, `headers`,\n * `getHeaders`, `credentials` and `fetch` below — which are ignored when a backend is given.\n */\n backend?: AgentBackend;\n /** Retry a dropped stream from its last frame. Default on; `false` turns it off. */\n reconnect?: ReconnectOptions | false;\n /** Fires as a stream drops, reconnects, or gives up. */\n onConnectionChange?: (state: StreamConnectionState) => void;\n /** The server's origin, e.g. `https://api.example.com`. Defaults to `''` (same origin). */\n baseUrl?: string;\n /** The agent's route prefix (`AgentModule`'s `path`, global prefix included). Default `'agent'`. */\n path?: string;\n /** Static headers merged into every request (e.g. a tenant ref). */\n headers?: Record<string, string>;\n /**\n * Resolved at request time — use for short-lived bearer tokens that\n * must not be captured once at construction. Merged over `headers`.\n */\n getHeaders?: () => Record<string, string> | Promise<Record<string, string>>;\n /** Forwarded to `fetch` so cookie-based auth/impersonation works. */\n credentials?: RequestCredentials;\n /** Named agent to run the turn (backend `agent` field). */\n agent?: string;\n /** One of the agent's personas to answer as (backend `persona` field). */\n persona?: string;\n /**\n * Extra body fields evaluated per send — the hook injects `threadId`\n * and `pageContext` through this. Returned object is spread into the\n * request body after the SDK's own `body`.\n */\n getBody?: () => Record<string, unknown>;\n /**\n * The run id to resume on mount, if any. Returning `undefined` makes\n * `reconnectToStream` resolve to `null` WITHOUT hitting the network —\n * this is the generalized fix for \"useChat fires a doomed GET on mount\n * and surfaces its 404\". Wire this to the thread's `activeRunId`.\n */\n getResumeRunId?: () => string | undefined;\n /**\n * Fires once `reconnectToStream` has attached to a run's stream, with that run's id. A resumed\n * stream replays frames but opens with no `meta` frame, so this is the only place a caller learns\n * which run it is now reading — what a Stop pressed after a reload has to cancel.\n */\n onResumeAttached?: (runId: string) => void;\n /** Fires whenever a stream emits its `meta` frame. */\n onMeta?: (meta: AgentStreamMeta) => void;\n /**\n * Fires synchronously at the very start of `sendMessages`/`reconnectToStream`, before any network\n * call — i.e. strictly before that attempt's own `onMeta` (if any) can fire. Lets a caller reset\n * \"which run is THIS attempt settling\" state without racing React's render/effect timing: a\n * consumer that also read `onMeta` to learn the current run id would otherwise risk misattributing\n * an early failure (no meta ever arrives) to a PRIOR attempt's id.\n */\n onAttemptStart?: () => void;\n /**\n * A resume found nothing streaming under the run id (the backend answered 404): the run already\n * ended. The SDK is told there is nothing to resume, so the caller is the one that has to reload\n * what the run wrote — `useAgentChat` re-reads the thread.\n */\n onResumeGone?: (runId: string) => void;\n /**\n * The run's stream ended with the backend's `event: error` frame — called with its `code` and\n * `message` right before the stream is closed with an error chunk. The chunk can only carry the\n * text; this is where the `code` reaches a caller, so it can word the failure itself.\n */\n onRunError?: (failure: AgentRunFailure) => void;\n /** Injectable for tests / non-browser runtimes. Defaults to global fetch. */\n fetch?: typeof fetch;\n}\n\nconst DEFAULT_RECONNECT: Required<ReconnectOptions> = {\n maxAttempts: 6,\n baseDelayMs: 500,\n maxDelayMs: 8000,\n};\n\n/**\n * The tool name BOTH elicitation surfaces persist their question set under (core's\n * `ASK_TOOL_NAME`), so a synthesized part and a replayed `tool-ask` row are the same part type.\n * Spelled out rather than imported: every other core import in this package is type-only, and a\n * value import would pull the agent loop into a browser bundle for a three-letter string.\n */\nconst ASK_TOOL_NAME = 'ask';\n\n/**\n * AI SDK v7 `ChatTransport` for the nestjs-agent backend. POSTs\n * `/agent/chat`, parses the backend's `meta` + `{delta}` + `done` SSE\n * frames, and re-emits them as the v7 UI-message chunk stream\n * (`start` → `text-start` → `text-delta`* → `text-end` → `finish`).\n *\n * The backend hydrates prior history from its store, so only the latest\n * user message text is sent each turn — keeping payloads tiny and\n * preventing the client from corrupting replayed history.\n *\n * Attachments (image/PDF for a vision-capable model) ride the per-send body:\n * `sendMessage({ text }, { body: { attachments: MessageAttachment[] } })`. They\n * flow to the backend as the turn's `attachments`, get persisted on the user\n * message, and are rendered as native model content parts. Optimistic display of\n * the user's own attachment thumbnails is the consumer's concern (it stages the\n * upload), the same way history rendering reads `StoredMessage.attachments`.\n *\n * Frames beyond text/reasoning/tools become AI SDK data parts (seen by `useChat`'s `onData`):\n * - `ui` → `data-ui` part, `id` = the component id (a repeat id updates it in place)\n * - `approval-requested` → `data-approval-requested` part keyed by the call id, plus the SDK's\n * native `tool-approval-request` (the part moves to `approval-requested`)\n * - `approval-settled` → `data-approval-settled` part keyed by the call id (who decided, through\n * what, remembered or not); the outcome still rides the call's own output\n * - `title`, `cancelled`, `queue` → transient `data-title` / `data-cancelled` / `data-queue` (never\n * stored on the message). A send the server queued (`202`) is reported\n * as a transient `data-queue` too, carrying `queuedSend`\n * - any other kind → `data-<kind>` part carrying the frame minus `kind`, keyed by its `id`\n * when it has one — forwarded, never dropped\n * `parentId` on a tool frame rides the part's `toolMetadata` next to `toolKind`.\n */\nexport class AgentChatTransport implements ChatTransport<UIMessage> {\n private currentRunId: string | undefined;\n private currentThreadId: string | undefined;\n\n /**\n * One attempt at a time. The AI SDK keeps a single in-flight response per chat and decides\n * whether its streamed message REPLACES the list's last entry or is appended by comparing that\n * response's message id against the last entry alone. Two attempts writing into one chat\n * therefore append alternating copies of each other's message, and the list ends up holding\n * several entries under each id — which React renders as duplicate keys.\n */\n private attemptLive = false;\n\n private readonly backend: AgentBackend;\n\n constructor(private readonly options: AgentChatTransportOptions = {}) {\n this.backend =\n options.backend ??\n new AgentClient({\n ...(options.baseUrl !== undefined ? { baseUrl: options.baseUrl } : {}),\n ...(options.path !== undefined ? { path: options.path } : {}),\n ...(options.headers !== undefined ? { headers: options.headers } : {}),\n ...(options.getHeaders !== undefined ? { getHeaders: options.getHeaders } : {}),\n ...(options.credentials !== undefined ? { credentials: options.credentials } : {}),\n ...(options.fetch !== undefined ? { fetch: options.fetch } : {}),\n });\n }\n\n /** Run id of the most recent stream — HITL approve/reject target this. */\n get runId(): string | undefined {\n return this.currentRunId;\n }\n\n /** Thread id of the most recent stream. */\n get threadId(): string | undefined {\n return this.currentThreadId;\n }\n\n /**\n * True from the moment a send or resume attempt starts until its chunk stream terminates. A\n * caller that can refuse a turn BEFORE the SDK commits to one — `useAgentChat` wrapping\n * `sendMessage` — reads this; the transport itself can only refuse a resume, which is the one\n * attempt the SDK lets a transport decline.\n */\n get isAttemptLive(): boolean {\n return this.attemptLive;\n }\n\n async sendMessages(\n options: Parameters<ChatTransport<UIMessage>['sendMessages']>[0],\n ): Promise<ReadableStream<UIMessageChunk>> {\n this.options.onAttemptStart?.();\n this.attemptLive = true;\n try {\n const lastMessage = options.messages.at(-1);\n const message = lastMessage ? extractText(lastMessage) : '';\n const body: Record<string, unknown> = {\n ...(this.options.agent !== undefined ? { agent: this.options.agent } : {}),\n ...(this.options.persona !== undefined ? { persona: this.options.persona } : {}),\n ...(this.options.getBody?.() ?? {}),\n ...((options.body as Record<string, unknown> | undefined) ?? {}),\n message,\n };\n const headers = headerRecord(options.headers);\n const response = await this.backend.openChatStream({\n body,\n ...(headers !== undefined ? { headers } : {}),\n ...(options.abortSignal ? { signal: options.abortSignal } : {}),\n });\n if (response.queued !== undefined) {\n // The thread already had a turn running (another tab, another device): the server queued\n // the message instead. Nothing streams; the chat learns it through a transient part.\n this.attemptLive = false;\n return queuedChunkStream(response.queued);\n }\n this.captureHeaderMeta(response);\n if (response.proposalDecision !== undefined) {\n this.attemptLive = false;\n return proposalDecisionChunkStream(response.proposalDecision);\n }\n return this.toChunkStream(response, {\n ...(headers !== undefined ? { headers } : {}),\n ...(options.abortSignal ? { signal: options.abortSignal } : {}),\n });\n } catch (error) {\n this.attemptLive = false;\n throw error;\n }\n }\n\n async reconnectToStream(\n options: Parameters<ChatTransport<UIMessage>['reconnectToStream']>[0],\n ): Promise<ReadableStream<UIMessageChunk> | null> {\n // Already attached: a second reconnect replays the SAME buffered frames into the SAME chat, so\n // it adds a duplicate of the message the first attempt is writing rather than a second turn.\n // React StrictMode runs the SDK's resume effect twice on mount, which makes this the ordinary\n // case and not an edge one. `null` is the SDK's own \"nothing to resume\" answer and, unlike a\n // throw, leaves it holding no state for an attempt that never happened.\n if (this.attemptLive) return null;\n this.options.onAttemptStart?.();\n const runId = this.options.getResumeRunId?.();\n // No buffered run → resolve null without a network round-trip so we\n // never surface a 404 from a doomed resume GET.\n if (runId === undefined) return null;\n this.attemptLive = true;\n try {\n const headers = headerRecord(options.headers);\n const response = await this.backend.resumeChatStream({\n runId,\n ...(headers !== undefined ? { headers } : {}),\n });\n if (response === null) {\n this.attemptLive = false;\n this.options.onResumeGone?.(runId);\n return null;\n }\n this.captureHeaderMeta(response);\n this.options.onResumeAttached?.(response.runId ?? runId);\n return this.toChunkStream(response, {\n runId,\n ...(headers !== undefined ? { headers } : {}),\n });\n } catch (error) {\n this.attemptLive = false;\n throw error;\n }\n }\n\n private captureHeaderMeta(response: ChatStreamResponse): void {\n if (response.runId) this.currentRunId = response.runId;\n if (response.threadId) this.currentThreadId = response.threadId;\n }\n\n private reconnectPolicy(): Required<ReconnectOptions> | null {\n const configured = this.options.reconnect;\n if (configured === false) return null;\n return { ...DEFAULT_RECONNECT, ...configured };\n }\n\n private recordMeta(meta: AgentStreamMeta): void {\n this.currentRunId = meta.runId;\n this.currentThreadId = meta.threadId;\n this.options.onMeta?.(meta);\n }\n\n /**\n * Parse the backend's SSE byte stream and re-emit it as a valid v7 UI-message chunk stream.\n * Recognized frames:\n * - `event: meta` `data: {\"runId\",\"threadId\"}` → records identity\n * - `data: <AgentStreamEvent JSON>` → mapped to UI chunks (text / reasoning / tool /\n * `data-*`; see {@link AgentChatTransport} docs)\n * - `event: done` `data: {}` → terminates\n * - `event: error` `data: {code,message}` → error chunk\n *\n * A run is ONE UI message with N steps. Each `step-start`/`step-finish` pair brackets a model\n * call plus its tool execution; text and reasoning open lazily and close at the step boundary, so\n * tool-call cards (input streaming → output) render live between the prose.\n */\n private toChunkStream(\n source: ChatStreamResponse,\n context: { runId?: string; headers?: Record<string, string>; signal?: AbortSignal },\n ): ReadableStream<UIMessageChunk> {\n let reader = source.body.getReader();\n let decoder = new TextDecoder();\n let buffer = '';\n // Resuming a dropped stream: the run it belongs to, and the sequence number (SSE `id:`) of the\n // last frame this stream has taken in. Only a server that numbers its frames can be resumed.\n let streamRunId = source.runId ?? context.runId;\n let lastSeq: number | undefined;\n let cancelled = false;\n const backend = this.backend;\n const policy = this.reconnectPolicy();\n const notify = (state: StreamConnectionState) => this.options.onConnectionChange?.(state);\n const reportRunError = (failure: { code: string | undefined; message: string }) => {\n try {\n this.options.onRunError?.({\n ...failure,\n ...(streamRunId !== undefined ? { runId: streamRunId } : {}),\n });\n } catch {\n /* a listener that throws must not replace the stream's own terminal */\n }\n };\n const aborted = () => cancelled || context.signal?.aborted === true;\n const canResume = () =>\n policy !== null && lastSeq !== undefined && streamRunId !== undefined && !aborted();\n /**\n * Re-attach after a drop: `GET …/stream?after=<lastSeq>`, backing off between attempts. The\n * chunk state (open step, text run, announced calls) is kept, so the resumed frames continue\n * the message instead of starting another.\n */\n const resume = async (): Promise<'resumed' | 'gone' | 'failed' | 'aborted'> => {\n const runId = streamRunId as string;\n const after = lastSeq ?? 0;\n const { maxAttempts, baseDelayMs, maxDelayMs } = policy as Required<ReconnectOptions>;\n for (let attempt = 1; attempt <= maxAttempts; attempt += 1) {\n notify({ status: 'reconnecting', runId, attempt, after });\n await delay(Math.min(maxDelayMs, baseDelayMs * 2 ** (attempt - 1)), context.signal);\n if (aborted()) return 'aborted';\n try {\n const next = await backend.resumeChatStream({\n runId,\n after,\n ...(context.headers !== undefined ? { headers: context.headers } : {}),\n ...(context.signal !== undefined ? { signal: context.signal } : {}),\n });\n if (next === null) {\n notify({ status: 'gone', runId });\n return 'gone';\n }\n reader = next.body.getReader();\n decoder = new TextDecoder();\n buffer = '';\n notify({ status: 'live' });\n return 'resumed';\n } catch {\n if (aborted()) return 'aborted';\n }\n }\n notify({ status: 'failed', runId });\n return 'failed';\n };\n let started = false;\n let stepOpen = false;\n let stepIndex = 0;\n let textId: string | null = null;\n let reasoningId: string | null = null;\n // When the open reasoning run started, for the duration stamped on its end when the backend\n // does not report one (see `closeRuns`).\n let reasoningStartedAt = 0;\n // Text/reasoning runs opened within the current step. A pushed UI component closes the open run\n // so prose after it lands AFTER it; the next run then needs an id of its own.\n let textSeq = 0;\n let reasoningSeq = 0;\n // Tool calls this STREAM has already announced. The AI SDK settles a tool part by looking it\n // up by call id and throws — dropping the whole message — when there is none, so an outcome\n // must never be the first a client hears of a call. Per stream, not per transport: a resumed\n // run replays its buffered frames from the beginning.\n const announced = new Set<string>();\n // What each call's tool part carries as `toolMetadata`. The SDK REPLACES a part's metadata with\n // whatever the latest chunk carries, so a `parentId` learnt from `tool-input-start` would be\n // wiped by the `tool-input-available` that follows unless every chunk restates the merge.\n const toolMetadata = new Map<string, ToolMetadata>();\n const record = (meta: AgentStreamMeta) => {\n streamRunId = meta.runId;\n this.recordMeta(meta);\n };\n // Every way out of the read loop below passes through here: the attempt is over the moment its\n // chunk stream terminates, and a latch left set would refuse every later turn.\n const endAttempt = () => {\n this.attemptLive = false;\n };\n\n return new ReadableStream<UIMessageChunk>({\n async pull(controller) {\n function ensureStarted() {\n if (started) return;\n started = true;\n // The run rides the message's metadata, so a later call about THIS message (feedback,\n // a resync) can find the rows the server persisted for it.\n // `createdAt` so a live message has a timestamp the way a replayed one does.\n controller.enqueue({\n type: 'start',\n messageMetadata: {\n ...(streamRunId !== undefined ? { runId: streamRunId } : {}),\n createdAt: new Date().toISOString(),\n },\n });\n }\n function openStep() {\n ensureStarted();\n if (stepOpen) closeStep();\n stepOpen = true;\n stepIndex += 1;\n textId = null;\n reasoningId = null;\n textSeq = 0;\n reasoningSeq = 0;\n controller.enqueue({ type: 'start-step' });\n }\n function ensureStep() {\n if (!stepOpen) openStep();\n }\n /**\n * `reasoningMs` is the backend's own measurement (`step-finish.reasoningMs`) — the number the\n * store persists, so a reloaded thread reads the same duration. Without one, the time this\n * client watched the run stream, which is what the reader saw but reads ~0 on a replay.\n */\n function closeRuns(reasoningMs?: number) {\n if (textId !== null) {\n controller.enqueue({ type: 'text-end', id: textId });\n textId = null;\n }\n if (reasoningId !== null) {\n controller.enqueue({\n type: 'reasoning-end',\n id: reasoningId,\n providerMetadata: reasoningDurationMetadata(\n reasoningMs ?? Math.max(0, Date.now() - reasoningStartedAt),\n ),\n });\n reasoningId = null;\n }\n }\n function closeStep(reasoningMs?: number) {\n if (!stepOpen) return;\n closeRuns(reasoningMs);\n controller.enqueue({ type: 'finish-step' });\n stepOpen = false;\n }\n /** Merge what this frame says about a call into what earlier frames said, and return it. */\n function metadataFor(\n id: string,\n toolKind: string | undefined,\n parentId: string | undefined,\n ): ToolMetadata | undefined {\n const merged: ToolMetadata = { ...toolMetadata.get(id) };\n if (toolKind !== undefined) merged.toolKind = toolKind;\n // A call's parent is fixed by the first frame that names one.\n if (parentId !== undefined && merged.parentId === undefined) merged.parentId = parentId;\n if (Object.keys(merged).length === 0) return undefined;\n toolMetadata.set(id, merged);\n return merged;\n }\n /** Forward a frame this transport has no dedicated mapping for as an AI SDK data part. */\n function forwardAsData(event: { kind: string }, transient: boolean) {\n ensureStarted();\n const { kind, ...data } = event as { kind: string } & Record<string, unknown>;\n controller.enqueue({\n type: `data-${kind}`,\n ...(typeof data.id === 'string' ? { id: data.id } : {}),\n data,\n ...(transient ? { transient: true } : {}),\n });\n }\n function emit(event: AgentStreamEvent) {\n switch (event.kind) {\n case 'step-start':\n openStep();\n break;\n case 'step-finish':\n closeStep(event.reasoningMs);\n // `costUsd` rides the step boundary once the backend reports it (older backends omit\n // it entirely — `undefined`, never a crash). `null` means \"priced provider/estimate\n // unavailable\", distinct from a real $0 turn — surfaced verbatim as message metadata\n // (merged onto `message.metadata` by the AI SDK) so a UI can render running cost\n // without polling `GET /quota`.\n if (event.costUsd !== undefined) {\n controller.enqueue({\n type: 'message-metadata',\n messageMetadata: { costUsd: event.costUsd },\n });\n }\n break;\n case 'text':\n ensureStep();\n if (textId === null) {\n textId = textSeq === 0 ? `txt-${stepIndex}` : `txt-${stepIndex}.${textSeq}`;\n textSeq += 1;\n controller.enqueue({ type: 'text-start', id: textId });\n }\n controller.enqueue({ type: 'text-delta', id: textId, delta: event.text });\n break;\n case 'reasoning':\n ensureStep();\n if (reasoningId === null) {\n reasoningId =\n reasoningSeq === 0 ? `rsn-${stepIndex}` : `rsn-${stepIndex}.${reasoningSeq}`;\n reasoningSeq += 1;\n reasoningStartedAt = Date.now();\n controller.enqueue({ type: 'reasoning-start', id: reasoningId });\n }\n controller.enqueue({ type: 'reasoning-delta', id: reasoningId, delta: event.text });\n break;\n case 'tool-input-start': {\n ensureStep();\n announced.add(event.id);\n // `toolKind` is absent on older backends — omitted (not `undefined`-valued) so\n // `toolMetadata` itself is only present when there's something to say, letting a\n // UI gate approval affordances on `kind === 'action'` without hardcoding tool names.\n // `parentId` nests the call under another one (see `TranscriptToolCall.children`).\n const metadata = metadataFor(event.id, event.toolKind, event.parentId);\n controller.enqueue({\n type: 'tool-input-start',\n toolCallId: event.id,\n toolName: event.name,\n ...(metadata !== undefined ? { toolMetadata: metadata } : {}),\n });\n break;\n }\n case 'tool-input-delta':\n ensureStep();\n controller.enqueue({\n type: 'tool-input-delta',\n toolCallId: event.id,\n inputTextDelta: event.delta,\n });\n break;\n case 'tool-input-available': {\n ensureStep();\n announced.add(event.id);\n const metadata = metadataFor(event.id, event.toolKind, event.parentId);\n controller.enqueue({\n type: 'tool-input-available',\n toolCallId: event.id,\n toolName: event.name,\n input: event.input,\n ...(metadata !== undefined ? { toolMetadata: metadata } : {}),\n });\n break;\n }\n case 'elicitation':\n ensureStep();\n // An authored intake asks before the turn's first model call, so nothing announced\n // the call this question set is parked under — open it here, carrying the request as\n // the part's input, which is exactly what the store persists as the call's input and\n // therefore what a reloaded thread replays. The model's own `ask` announced its call\n // itself, and re-stating it would fire a consumer's `onToolCall` twice.\n if (!announced.has(event.id)) {\n announced.add(event.id);\n controller.enqueue({\n type: 'tool-input-available',\n toolCallId: event.id,\n toolName: ASK_TOOL_NAME,\n input: {\n ...(event.request.preamble !== undefined\n ? { preamble: event.request.preamble }\n : {}),\n questions: event.request.questions,\n },\n });\n }\n break;\n case 'tool-output':\n ensureStep();\n controller.enqueue({\n type: 'tool-output-available',\n toolCallId: event.id,\n output: event.output,\n });\n break;\n case 'tool-output-error':\n ensureStep();\n controller.enqueue({\n type: 'tool-output-error',\n toolCallId: event.id,\n errorText: event.error,\n });\n break;\n case 'tool-output-denied':\n ensureStep();\n // The SDK's own state for \"a person said no\": it keeps the part's input and metadata\n // and only moves its state, so a card can say the decision was carried out instead of\n // drawing the red treatment an error gets. The reason (when one was given) rides the\n // persisted call, not this chunk — the SDK's shape carries no room for it.\n controller.enqueue({ type: 'tool-output-denied', toolCallId: event.id });\n break;\n case 'approval-requested':\n ensureStep();\n // Who decides and until when rides a `data-approval-requested` part keyed by the call\n // id — the SDK's approval chunk has no room for it, and restating the call's input\n // chunk to widen its metadata would fire a consumer's `onToolCall` a second time.\n forwardAsData(event, false);\n // The SDK settles an approval against a part it already holds and throws — dropping\n // the whole message — when there is none, so only a call this stream announced moves\n // into the native state. The approval id IS the call id: the lib settles approvals\n // by tool-call id, so a second identifier would only have to be mapped back.\n if (announced.has(event.id)) {\n controller.enqueue({\n type: 'tool-approval-request',\n approvalId: event.id,\n toolCallId: event.id,\n });\n }\n break;\n case 'approval-settled':\n ensureStep();\n // Metadata about a call, like the request: the transcript folds it into that call's\n // `approval`. The call's own state moves on its output frame, not on this one.\n forwardAsData(event, false);\n break;\n case 'ui':\n ensureStep();\n // Positioned content: close the open prose so text written after the component\n // renders after it instead of growing the paragraph above it.\n closeRuns();\n controller.enqueue({\n type: 'data-ui',\n id: event.id,\n data: {\n id: event.id,\n component: event.component,\n props: event.props,\n ...(event.version !== undefined ? { version: event.version } : {}),\n ...(event.toolCallId !== undefined ? { toolCallId: event.toolCallId } : {}),\n // A preview of a layout the model is still writing: the final push (same id)\n // replaces this part in place.\n ...(event.partial === true ? { partial: true } : {}),\n },\n });\n break;\n case 'message-metadata':\n ensureStarted();\n controller.enqueue({ type: 'message-metadata', messageMetadata: event.metadata });\n break;\n case 'title':\n case 'cancelled':\n // The thread's queue changed, or this run handed the thread to the next queued message\n // (`started`). Thread-level, like the title.\n case 'queue':\n // Thread- and run-level facts, not message content: seen by `onData`, never stored\n // as a part of the message.\n forwardAsData(event, true);\n break;\n default:\n // A kind this version does not know (a newer server, a runner that is not this\n // library's loop). Forwarded rather than dropped, so a host can render it from\n // `message.parts` / `onData` without waiting for a release that maps it.\n // `proposal-decision` (an AG-UI consumer's re-framing of a text decision) is the same\n // transient `data-proposal-decision` part a native decision answers with.\n forwardAsData(\n event as { kind: string },\n (event as { kind: string }).kind === 'proposal-decision',\n );\n break;\n }\n }\n function finish() {\n ensureStarted();\n closeStep();\n controller.enqueue({ type: 'finish' });\n controller.close();\n endAttempt();\n }\n function fail(errorText: string, start = true) {\n if (start) ensureStarted();\n controller.enqueue({ type: 'error', errorText });\n controller.close();\n endAttempt();\n }\n /** The stream dropped (or ended without `done`): resume it, or report how it ended. */\n async function recover(error: unknown): Promise<boolean> {\n if (!canResume()) {\n if (error === undefined) {\n finish();\n } else {\n fail(error instanceof Error ? error.message : 'Agent stream error', false);\n }\n return false;\n }\n const outcome = await resume();\n if (outcome === 'resumed') return true;\n if (outcome === 'failed') {\n fail('Lost the connection to the agent stream');\n } else {\n // Gone: the run ended while we were away — what we have is all this stream will get,\n // and the persisted thread holds the rest. Aborted: the user stopped the turn.\n finish();\n }\n return false;\n }\n try {\n while (true) {\n let result: ReadableStreamReadResult<Uint8Array>;\n try {\n result = await reader.read();\n } catch (error) {\n if (await recover(error)) continue;\n return;\n }\n if (result.done) {\n if (await recover(undefined)) continue;\n return;\n }\n buffer += decoder.decode(result.value, { stream: true });\n let separator = buffer.indexOf('\\n\\n');\n while (separator !== -1) {\n const rawEvent = buffer.slice(0, separator);\n buffer = buffer.slice(separator + 2);\n separator = buffer.indexOf('\\n\\n');\n const frame = parseSseFrame(rawEvent);\n if (frame.id !== undefined) {\n // Already taken in before a reconnect — a server that ignored `after` resends it.\n if (lastSeq !== undefined && frame.id <= lastSeq) continue;\n lastSeq = frame.id;\n }\n if (frame.event === 'done') {\n finish();\n return;\n }\n if (frame.event === 'error') {\n const failure = parseErrorFrame(frame.data);\n reportRunError(failure);\n fail(failure.message);\n return;\n }\n if (frame.event === 'meta') {\n const meta = parseMeta(frame.data);\n if (meta) record(meta);\n } else if (frame.data) {\n const event = parseEvent(frame.data);\n if (event) emit(event);\n }\n }\n }\n } catch (error) {\n fail(error instanceof Error ? error.message : 'Agent stream error', false);\n }\n },\n cancel() {\n cancelled = true;\n // A stop aborts the request first, which errors the body: cancelling an errored stream\n // rejects with that same AbortError, and nobody is left to hear it.\n reader.cancel().catch(() => undefined);\n endAttempt();\n },\n });\n }\n}\n\n/** The chunk stream for a send the server queued: one transient `data-queue` part, then the end. */\nfunction queuedChunkStream(queued: QueuedSendResult): ReadableStream<UIMessageChunk> {\n return new ReadableStream<UIMessageChunk>({\n start(controller) {\n controller.enqueue({\n type: 'data-queue',\n data: { queue: queued.queue, queuedSend: queued },\n transient: true,\n });\n controller.close();\n },\n });\n}\n\ninterface SseFrame {\n event: string | undefined;\n data: string | undefined;\n /** The frame's sequence number (SSE `id:`), when the server numbers its frames. */\n id: number | undefined;\n}\n\n/** Split one `event:`/`data:` SSE block into its fields. */\nfunction parseSseFrame(raw: string): SseFrame {\n let event: string | undefined;\n let id: number | undefined;\n const dataLines: string[] = [];\n for (const line of raw.split('\\n')) {\n if (line.startsWith('event:')) {\n event = line.slice('event:'.length).trim();\n } else if (line.startsWith('id:')) {\n const parsed = Number(line.slice('id:'.length).trim());\n if (Number.isSafeInteger(parsed) && parsed > 0) id = parsed;\n } else if (line.startsWith('data:')) {\n dataLines.push(line.slice('data:'.length).trimStart());\n }\n }\n return {\n event,\n data: dataLines.length > 0 ? dataLines.join('\\n') : undefined,\n id,\n };\n}\n\nfunction parseMeta(data: string | undefined): AgentStreamMeta | null {\n if (!data) return null;\n try {\n const parsed: unknown = JSON.parse(data);\n if (\n parsed !== null &&\n typeof parsed === 'object' &&\n 'runId' in parsed &&\n 'threadId' in parsed &&\n typeof parsed.runId === 'string' &&\n typeof parsed.threadId === 'string'\n ) {\n return { runId: parsed.runId, threadId: parsed.threadId };\n }\n } catch {\n /* malformed meta frame — ignore */\n }\n return null;\n}\n\n/** Read the backend's `event: error` frame (`{code,message}`); a malformed one is a bare failure. */\nfunction parseErrorFrame(data: string | undefined): { code: string | undefined; message: string } {\n const fallback = { code: undefined, message: 'Agent run failed' };\n if (!data) return fallback;\n try {\n const parsed: unknown = JSON.parse(data);\n if (parsed !== null && typeof parsed === 'object') {\n const record = parsed as { code?: unknown; message?: unknown };\n return {\n code: typeof record.code === 'string' && record.code !== '' ? record.code : undefined,\n message:\n typeof record.message === 'string' && record.message !== ''\n ? record.message\n : fallback.message,\n };\n }\n } catch {\n /* malformed error frame — fall through to the default */\n }\n return fallback;\n}\n\n/** Parse a `data:` frame as an `AgentStreamEvent`. Returns null for anything without a `kind`. */\nfunction parseEvent(data: string): AgentStreamEvent | null {\n try {\n const parsed: unknown = JSON.parse(data);\n if (parsed !== null && typeof parsed === 'object' && 'kind' in parsed) {\n return parsed as AgentStreamEvent;\n }\n } catch {\n /* not an event frame — ignore */\n }\n return null;\n}\n\n/** Collect all text parts of a UI message into a single string. */\nfunction extractText(message: UIMessage): string {\n let text = '';\n for (const part of message.parts ?? []) {\n if (part.type === 'text') text += part.text;\n }\n return text;\n}\n\n/** Per-request headers as the AI SDK hands them over, as a plain record (or nothing). */\nfunction headerRecord(\n headers: Record<string, string> | Headers | undefined,\n): Record<string, string> | undefined {\n if (headers === undefined) return undefined;\n return headers instanceof Headers ? Object.fromEntries(headers.entries()) : headers;\n}\n\n/** Wait `ms`, resolving early when `signal` aborts. */\nfunction delay(ms: number, signal: AbortSignal | undefined): Promise<void> {\n if (ms <= 0 || signal?.aborted) return Promise.resolve();\n return new Promise((resolve) => {\n const timer = setTimeout(done, ms);\n function done() {\n clearTimeout(timer);\n signal?.removeEventListener('abort', done);\n resolve();\n }\n signal?.addEventListener('abort', done, { once: true });\n });\n}\n\nfunction proposalDecisionChunkStream(\n decision: NonNullable<ChatStreamResponse['proposalDecision']>,\n): ReadableStream<UIMessageChunk> {\n return new ReadableStream({\n start(controller) {\n controller.enqueue({ type: 'start', messageId: `decision:${crypto.randomUUID()}` });\n controller.enqueue({ type: 'data-proposal-decision', data: decision, transient: true });\n if (decision.text !== undefined && decision.text.length > 0) {\n controller.enqueue({ type: 'text-start', id: 'decision' });\n controller.enqueue({ type: 'text-delta', id: 'decision', delta: decision.text });\n controller.enqueue({ type: 'text-end', id: 'decision' });\n }\n controller.enqueue({ type: 'finish', finishReason: 'stop' });\n controller.close();\n },\n });\n}\n","import type { MessageAttachment } from '@dudousxd/nestjs-agent-core';\nimport type { FileUIPart, UIMessage } from 'ai';\n\n/** How a renderer is likely to show a file. */\nexport type MessageFileKind = 'image' | 'pdf' | 'text' | 'audio' | 'video' | 'other';\n\n/** One file on a message, live or replayed, with what a renderer needs to decide how to show it. */\nexport interface MessageFile {\n url: string;\n mediaType: string;\n /** The original name, or `null` when the part carried none. */\n filename: string | null;\n kind: MessageFileKind;\n /** Lower-case extension from the name (`'pdf'`), or `null`. */\n extension: string | null;\n /** The stored media id — present on files replayed from history (`StoredMessage.attachments`). */\n mediaId: string | null;\n}\n\n/** The {@link MessageFileKind} of a MIME type. */\nexport function fileKind(mediaType: string): MessageFileKind {\n const type = mediaType.toLowerCase();\n if (type.startsWith('image/')) return 'image';\n if (type === 'application/pdf') return 'pdf';\n if (type.startsWith('text/') || type === 'application/json') return 'text';\n if (type.startsWith('audio/')) return 'audio';\n if (type.startsWith('video/')) return 'video';\n return 'other';\n}\n\nfunction messageFile(url: string, mediaType: string, name: string | null, mediaId: string | null) {\n const dot = name?.lastIndexOf('.') ?? -1;\n const file: MessageFile = {\n url,\n mediaType,\n filename: name,\n kind: fileKind(mediaType),\n extension: name !== null && dot > 0 ? name.slice(dot + 1).toLowerCase() : null,\n mediaId,\n };\n return file;\n}\n\n/**\n * An uploaded attachment as the {@link MessageFile} it is once its message is sent — so a message\n * still waiting (in the queue, in the composer) draws its files with the same code a sent one does.\n */\nexport function attachmentFile(attachment: MessageAttachment): MessageFile {\n return messageFile(attachment.url, attachment.contentType, attachment.name, attachment.mediaId);\n}\n\n/**\n * The files on a message — the user's attachments (live, or replayed from `StoredMessage.attachments`\n * by `storedMessageToUiMessage`) and any the model produced — in part order. Data only: pair it with\n * your own thumbnails/links.\n */\nexport function messageFiles(message: Pick<UIMessage, 'parts'>): MessageFile[] {\n const files: MessageFile[] = [];\n for (const part of message.parts) {\n if (part.type !== 'file') continue;\n const file = part as FileUIPart;\n const mediaId = (file.providerMetadata?.agent as { mediaId?: unknown } | undefined)?.mediaId;\n files.push(\n messageFile(\n file.url,\n file.mediaType,\n file.filename ?? null,\n typeof mediaId === 'string' ? mediaId : null,\n ),\n );\n }\n return files;\n}\n\n/**\n * Whether `file` matches an `accept` list in the `<input accept>` grammar: MIME types\n * (`application/pdf`), wildcards (`image/*`) and extensions (`.csv`). An empty list accepts all.\n */\nexport function acceptsFile(\n accept: string | readonly string[] | undefined,\n file: Pick<File, 'name' | 'type'>,\n): boolean {\n const rules = (typeof accept === 'string' ? accept.split(',') : (accept ?? []))\n .map((rule) => rule.trim().toLowerCase())\n .filter((rule) => rule.length > 0);\n if (rules.length === 0) return true;\n const type = file.type.toLowerCase();\n const name = file.name.toLowerCase();\n return rules.some((rule) => {\n if (rule.startsWith('.')) return name.endsWith(rule);\n if (rule.endsWith('/*')) return type.startsWith(rule.slice(0, -1));\n return type === rule;\n });\n}\n\n/** Files carried by a paste — screenshots and copied files. Text-only pastes give `[]`. */\nexport function filesFromClipboard(data: DataTransfer | null | undefined): File[] {\n if (!data) return [];\n const files: File[] = [];\n for (const item of Array.from(data.items ?? [])) {\n if (item.kind !== 'file') continue;\n const file = item.getAsFile();\n if (file !== null) files.push(file);\n }\n return files.length > 0 ? files : Array.from(data.files ?? []);\n}\n\n/** Whether a drag carries files (as opposed to text or a link) — gate your drop highlight on it. */\nexport function dragHasFiles(data: DataTransfer | null | undefined): boolean {\n return Array.from(data?.types ?? []).includes('Files');\n}\n","import type { MessageAttachment } from '@dudousxd/nestjs-agent-core';\nimport { useCallback, useEffect, useMemo, useRef, useState } from 'react';\nimport type { AgentBackend, UploadAttachmentOptions } from '../backend.js';\nimport { AgentBackendUnsupportedError } from '../backend.js';\nimport { useAgentConfig } from '../config/use-agent-config.js';\nimport { useAgentBackend } from '../provider.js';\nimport { acceptsFile, dragHasFiles, filesFromClipboard } from './files.js';\n\n/** Where one staged file stands. `rejected` never uploaded (validation); `error` can be retried. */\nexport type StagedAttachmentStatus = 'uploading' | 'ready' | 'error' | 'rejected';\n\nexport interface StagedAttachment {\n /** Local id, stable for the item's life — use it as the React key and for `remove`/`retry`. */\n id: string;\n file: File;\n name: string;\n size: number;\n type: string;\n status: StagedAttachmentStatus;\n /** 0..1 while uploading (0 until the backend reports progress), 1 once ready. */\n progress: number;\n /** Why it was rejected or failed. */\n error?: string;\n /** What the server returned — present once `ready`. */\n attachment?: MessageAttachment;\n /** An object URL for image previews (revoked on remove/unmount), when the runtime has one. */\n previewUrl?: string;\n}\n\n/** Why a file was turned away before any upload. */\nexport type AttachmentRejection = 'type' | 'size' | 'count';\n\nexport interface UseAttachmentsOptions {\n /**\n * Upload one file — defaults to `backend.uploadAttachment`. Resolve with what the server\n * answered; honour `signal` so `remove` can cancel; call `onProgress(0..1)` if you can.\n */\n upload?: (file: File, options: UploadAttachmentOptions) => Promise<MessageAttachment>;\n /** Used for the default `upload`. Default: the enclosing `<AgentProvider>`'s. */\n backend?: AgentBackend;\n /**\n * `<input accept>` grammar: `'image/*,.pdf'` or `['image/*', 'application/pdf']`. Default: the\n * server's allowed content types (`GET <base>/config`).\n */\n accept?: string | readonly string[];\n /** Per-file ceiling, in bytes. Default: the server's (`GET <base>/config`). */\n maxBytes?: number;\n /**\n * How many files may be staged at once (rejected ones do not count). Default: how many one\n * message may carry, per the server (`GET <base>/config`).\n */\n maxFiles?: number;\n /** Words for a rejection; default English. */\n describeRejection?: (reason: AttachmentRejection, file: File) => string;\n}\n\nexport interface AttachmentsState {\n items: StagedAttachment[];\n /** Stage files: validate, then upload each that passes. */\n add: (files: Iterable<File> | ArrayLike<File> | null | undefined) => void;\n /** Drop an item, cancelling its upload. */\n remove: (id: string) => void;\n /** Upload a failed item again. */\n retry: (id: string) => void;\n /** Drop everything — call after a send. */\n clear: () => void;\n /** An upload is still running — hold the send button. */\n isUploading: boolean;\n /** What to send: the ready uploads, in order, as the `{ mediaId }` refs `POST <base>/chat` takes. */\n refs: Array<{ mediaId: string }>;\n /** Props for a hidden `<input type=\"file\">`: `accept`, `multiple`, `onChange`. */\n inputProps: {\n type: 'file';\n accept: string | undefined;\n multiple: boolean;\n onChange: (event: { currentTarget: HTMLInputElement }) => void;\n };\n /** Handlers for any element that should take dropped files. */\n dropZoneProps: {\n onDragEnter: (event: DragLikeEvent) => void;\n onDragOver: (event: DragLikeEvent) => void;\n onDragLeave: (event: DragLikeEvent) => void;\n onDrop: (event: DragLikeEvent) => void;\n };\n /** Files are being dragged over the drop zone — for a highlight. */\n isDragging: boolean;\n /** Paste handler for the composer: stages pasted files (screenshots), leaves text alone. */\n onPaste: (event: ClipboardLikeEvent) => void;\n}\n\n/** The slice of a React/DOM drag event these handlers read. */\nexport interface DragLikeEvent {\n dataTransfer: DataTransfer | null;\n preventDefault: () => void;\n}\n\n/** The slice of a React/DOM clipboard event `onPaste` reads. */\nexport interface ClipboardLikeEvent {\n clipboardData: DataTransfer | null;\n preventDefault: () => void;\n}\n\nconst DEFAULT_REJECTION: Record<AttachmentRejection, (file: File) => string> = {\n type: (file) => `${file.name} is not a supported file type`,\n size: (file) => `${file.name} is too large`,\n count: () => 'Too many files',\n};\n\nlet sequence = 0;\n\n/**\n * Staged attachments for a composer, headless: validation (`accept`, `maxBytes`, `maxFiles`),\n * one upload per file with progress and cancel, retry, previews, and the event handlers for a file\n * input, a drop zone and paste — no markup, no styles. Send `refs` with the\n * message, then `clear()`:\n *\n * ```ts\n * await chat.sendMessage({ text }, { body: { attachments: files.refs } });\n * files.clear();\n * ```\n */\nexport function useAttachments(options: UseAttachmentsOptions = {}): AttachmentsState {\n const backend = useAgentBackend(options.backend);\n // The server's limits are the defaults, so a composer never repeats (and drifts from) them.\n const { config } = useAgentConfig({ backend });\n const limits = config?.attachments;\n const accept = options.accept ?? limits?.allowedContentTypes;\n const maxBytes = options.maxBytes ?? limits?.maxBytes;\n const maxFiles = options.maxFiles ?? limits?.maxPerMessage;\n const effective = {\n ...options,\n backend,\n ...(accept !== undefined ? { accept } : {}),\n ...(maxBytes !== undefined ? { maxBytes } : {}),\n ...(maxFiles !== undefined ? { maxFiles } : {}),\n };\n const latest = useRef(effective);\n latest.current = effective;\n const [items, setItems] = useState<StagedAttachment[]>([]);\n const itemsRef = useRef(items);\n itemsRef.current = items;\n const controllers = useRef(new Map<string, AbortController>());\n const [dragDepth, setDragDepth] = useState(0);\n\n const patch = useCallback((id: string, change: Partial<StagedAttachment>) => {\n setItems((current) => current.map((item) => (item.id === id ? { ...item, ...change } : item)));\n }, []);\n\n const start = useCallback(\n (item: StagedAttachment) => {\n const { upload, backend } = latest.current;\n const run =\n upload ??\n (backend.uploadAttachment !== undefined\n ? backend.uploadAttachment.bind(backend)\n : undefined);\n if (run === undefined) {\n patch(item.id, {\n status: 'error',\n error: new AgentBackendUnsupportedError('uploadAttachment').message,\n });\n return;\n }\n const controller = new AbortController();\n controllers.current.set(item.id, controller);\n run(item.file, {\n signal: controller.signal,\n onProgress: (fraction) => patch(item.id, { progress: Math.max(0, Math.min(1, fraction)) }),\n }).then(\n (attachment) => {\n if (controller.signal.aborted) return;\n controllers.current.delete(item.id);\n patch(item.id, { status: 'ready', progress: 1, attachment });\n },\n (error: unknown) => {\n if (controller.signal.aborted) return;\n controllers.current.delete(item.id);\n patch(item.id, {\n status: 'error',\n error: error instanceof Error ? error.message : String(error),\n });\n },\n );\n },\n [patch],\n );\n\n const add = useCallback(\n (files: Iterable<File> | ArrayLike<File> | null | undefined) => {\n if (files == null) return;\n const { accept, maxBytes, maxFiles, describeRejection } = latest.current;\n const describe = (reason: AttachmentRejection, file: File) =>\n describeRejection?.(reason, file) ?? DEFAULT_REJECTION[reason](file);\n let room =\n maxFiles === undefined\n ? Number.POSITIVE_INFINITY\n : maxFiles - itemsRef.current.filter((item) => item.status !== 'rejected').length;\n const staged: StagedAttachment[] = [];\n for (const file of Array.from(files as ArrayLike<File>)) {\n sequence += 1;\n const base = {\n id: `att-${sequence}`,\n file,\n name: file.name,\n size: file.size,\n type: file.type,\n progress: 0,\n };\n const reason: AttachmentRejection | undefined = !acceptsFile(accept, file)\n ? 'type'\n : maxBytes !== undefined && file.size > maxBytes\n ? 'size'\n : room <= 0\n ? 'count'\n : undefined;\n if (reason !== undefined) {\n staged.push({ ...base, status: 'rejected', error: describe(reason, file) });\n continue;\n }\n room -= 1;\n const previewUrl =\n file.type.startsWith('image/') && typeof URL.createObjectURL === 'function'\n ? URL.createObjectURL(file)\n : undefined;\n staged.push({ ...base, status: 'uploading', ...(previewUrl ? { previewUrl } : {}) });\n }\n if (staged.length === 0) return;\n setItems((current) => [...current, ...staged]);\n for (const item of staged) {\n if (item.status === 'uploading') start(item);\n }\n },\n [start],\n );\n\n const release = useCallback((item: StagedAttachment | undefined) => {\n if (item === undefined) return;\n controllers.current.get(item.id)?.abort();\n controllers.current.delete(item.id);\n if (item.previewUrl !== undefined && typeof URL.revokeObjectURL === 'function') {\n URL.revokeObjectURL(item.previewUrl);\n }\n }, []);\n\n const remove = useCallback(\n (id: string) => {\n release(itemsRef.current.find((item) => item.id === id));\n setItems((current) => current.filter((item) => item.id !== id));\n },\n [release],\n );\n\n const clear = useCallback(() => {\n for (const item of itemsRef.current) release(item);\n setItems([]);\n }, [release]);\n\n const retry = useCallback(\n (id: string) => {\n const item = itemsRef.current.find((candidate) => candidate.id === id);\n if (item === undefined || item.status !== 'error') return;\n const { error: _previous, ...rest } = item;\n const again: StagedAttachment = { ...rest, status: 'uploading', progress: 0 };\n setItems((current) => current.map((candidate) => (candidate.id === id ? again : candidate)));\n start(again);\n },\n [start],\n );\n\n // Unmount: cancel what is in flight and free the previews.\n useEffect(\n () => () => {\n for (const item of itemsRef.current) release(item);\n },\n [release],\n );\n\n const onPaste = useCallback(\n (event: ClipboardLikeEvent) => {\n const files = filesFromClipboard(event.clipboardData);\n if (files.length === 0) return;\n event.preventDefault();\n add(files);\n },\n [add],\n );\n\n const dropZoneProps = useMemo(\n () => ({\n onDragEnter: (event: DragLikeEvent) => {\n if (!dragHasFiles(event.dataTransfer)) return;\n event.preventDefault();\n setDragDepth((depth) => depth + 1);\n },\n onDragOver: (event: DragLikeEvent) => {\n // Without this the browser never fires `drop` — it opens the file instead.\n if (dragHasFiles(event.dataTransfer)) event.preventDefault();\n },\n onDragLeave: (event: DragLikeEvent) => {\n if (!dragHasFiles(event.dataTransfer)) return;\n setDragDepth((depth) => Math.max(0, depth - 1));\n },\n onDrop: (event: DragLikeEvent) => {\n if (!dragHasFiles(event.dataTransfer)) return;\n event.preventDefault();\n setDragDepth(0);\n add(event.dataTransfer?.files);\n },\n }),\n [add],\n );\n\n const inputProps = useMemo(\n () => ({\n type: 'file' as const,\n accept: typeof accept === 'string' ? accept : accept?.join(','),\n multiple: maxFiles === undefined || maxFiles > 1,\n onChange: (event: { currentTarget: HTMLInputElement }) => {\n const input = event.currentTarget;\n add(input.files);\n // Let the same file be picked again after a remove.\n input.value = '';\n },\n }),\n [accept, maxFiles, add],\n );\n\n return useMemo(() => {\n const ready = items.filter(\n (item): item is StagedAttachment & { attachment: MessageAttachment } =>\n item.status === 'ready' && item.attachment !== undefined,\n );\n return {\n items,\n add,\n remove,\n retry,\n clear,\n isUploading: items.some((item) => item.status === 'uploading'),\n refs: ready.map((item) => ({ mediaId: item.attachment.mediaId })),\n inputProps,\n dropZoneProps,\n isDragging: dragDepth > 0,\n onPaste,\n };\n }, [items, add, remove, retry, clear, inputProps, dropZoneProps, dragDepth, onPaste]);\n}\n","import type {\n ActionProposalMutationView,\n ActionProposalView,\n AgentCatalogEntry,\n AgentClientConfig,\n ChatQueueState,\n MessageAttachment,\n MessageFeedback,\n MessageFeedbackValue,\n ModelCatalogView,\n QuotaReport,\n SkillCatalogEntry,\n ThreadDetail,\n ThreadSummary,\n ToolCatalogEntry,\n} from '@dudousxd/nestjs-agent-core';\nimport type { HttpErrorListener } from './http-error.js';\n\n/**\n * Partial update accepted by `PATCH <base>/threads/:threadId`. `defaultAgent: null` clears a\n * previously-set default back to the module's own default; omitting it leaves the thread's\n * current default untouched.\n */\nexport interface ThreadPatch {\n title?: string;\n defaultAgent?: string | null;\n /** Pin a catalog model on the thread; `null` unpins it. */\n model?: string | null;\n /** Pin one of the agent's personas on the thread; `null` clears it (the agent's default applies). */\n persona?: string | null;\n}\n\n/** Starting a turn: the body `POST <base>/chat` takes (see docs/stream-protocol.md). */\nexport interface ChatStreamRequest {\n /** `{ message, threadId?, agent?, persona?, model?, attachments?, pageContext?, regenerate?, … }`. */\n body: Record<string, unknown>;\n /** Per-request headers the AI SDK was handed for this send. */\n headers?: Record<string, string>;\n /** Aborted when the user stops the turn. */\n signal?: AbortSignal;\n}\n\n/** Attaching to a run that is already streaming: `GET <base>/chat/:runId/stream?after=<seq>`. */\nexport interface ResumeStreamRequest {\n runId: string;\n /**\n * The sequence number (SSE `id:`) of the last frame the client already has. Omitted → replay\n * from the first frame. A backend that cannot skip may ignore it: the transport also drops frames\n * at or below it.\n */\n after?: number;\n headers?: Record<string, string>;\n signal?: AbortSignal;\n}\n\n/**\n * An open chat stream: the raw `text/event-stream` bytes in the stream-protocol framing, plus the\n * identity a backend may learn before the first frame (the `X-Agent-Run-Id` / `X-Agent-Thread-Id`\n * headers). The body's own `event: meta` frame supplies them otherwise.\n */\nexport interface ChatStreamResponse {\n proposalDecision?: {\n threadId: string;\n proposalDecision: ActionProposalMutationView | { status: 'ambiguous'; proposalIds: string[] };\n text?: string;\n };\n body: ReadableStream<Uint8Array>;\n runId?: string;\n threadId?: string;\n /**\n * The server queued the message instead of starting a turn (`202`): the thread already had one\n * running — another tab, another device. `body` is then empty; the transport reports this as a\n * transient `data-queue` part and `useAgentChat` moves the message into `chat.queue`.\n */\n queued?: QueuedSendResult;\n}\n\n/**\n * `POST <base>/chat` answered `202`: the message waits in the thread's queue (see\n * docs/stream-protocol.md, \"Message queue\").\n */\nexport interface QueuedSendResult {\n queued: true;\n threadId: string;\n /** The queued message's id — also the id of the run it will start. */\n messageId: string;\n /** 0-based place in the queue when it was queued. */\n position: number;\n queue: ChatQueueState;\n /** Set when it started straight away (the thread was idle after all): attach to this run. */\n runId?: string;\n /** The run an interrupt cancelled to make room for it. */\n interrupting?: string;\n}\n\n/** What `PATCH <base>/queue/:messageId` takes. */\nexport interface QueuedMessageUpdate {\n message?: string;\n /** `[{ mediaId }]` refs replacing the message's attachments; `null` drops them. */\n attachments?: Array<{ mediaId: string }> | null;\n /** Move it to this 0-based place in the queue. */\n position?: number;\n}\n\n/** What `POST <base>/messages/:id/feedback` takes. `value: null` clears the rating. */\nexport interface MessageFeedbackInput {\n value: MessageFeedbackValue | null;\n comment?: string;\n}\n\nexport interface UploadAttachmentOptions {\n signal?: AbortSignal;\n /** Called with 0..1 as the upload progresses, when the backend can observe it. */\n onProgress?: (fraction: number) => void;\n}\n\n/** How {@link AgentClient} reaches the server — handed to an {@link AttachmentUploadStrategy}. */\nexport interface AgentConnection {\n /** The server's origin, trailing slash removed (`''` for same-origin). */\n baseUrl: string;\n /** The agent's route prefix, normalized to a leading slash (`'/agent'`), or `''`. */\n path: string;\n /** The client's static + per-request headers, resolved now (auth, CSRF). */\n headers: () => Promise<Record<string, string>>;\n credentials?: RequestCredentials;\n fetch: typeof fetch;\n /** The client's `onHttpError` — call it with an upload's error answer before throwing it. */\n onHttpError?: HttpErrorListener;\n}\n\n/**\n * Replaces {@link AgentClient}'s own `uploadAttachment` (`POST <path>/attachments`) — e.g.\n * `mediaAttachments()` from `@dudousxd/nestjs-agent-react/media`, or your own storage. Gets the\n * client's connection so it needs no configuration of its own. Resolve with the attachment your\n * server's `AGENT_ATTACHMENT_STAGING` recognises by `mediaId`.\n */\nexport type AttachmentUploadStrategy = (\n file: File,\n options: UploadAttachmentOptions,\n connection: AgentConnection,\n) => Promise<MessageAttachment>;\n\n/**\n * Everything the React layer asks of a server — the seam between `useAgentChat` (and the other\n * hooks) and whatever serves the agent. {@link AgentClient} is the default implementation, over the\n * library's own REST routes with `fetch`. An app with its own client — a generated one, a different\n * auth scheme (cookie session + CSRF header), a backend that is not this library at all but speaks\n * docs/stream-protocol.md — implements this instead and passes it as `<AgentProvider backend>` (or\n * per hook, `useAgentChat({ backend })`).\n *\n * The streaming, thread and cancel members are required: without them there is no chat. The rest\n * are optional; a hook that needs one the backend does not have throws\n * {@link AgentBackendUnsupportedError} when it is called, so a backend only implements what its\n * server supports.\n */\nexport interface AgentBackend {\n /** Start a turn and return its SSE stream. Throw on a non-2xx answer. */\n openChatStream(request: ChatStreamRequest): Promise<ChatStreamResponse>;\n /** Attach to a streaming run. Resolve `null` when nothing is streaming under that id (HTTP 404). */\n resumeChatStream(request: ResumeStreamRequest): Promise<ChatStreamResponse | null>;\n /** Hard-stop a run server-side. */\n cancelStream(runId: string): Promise<unknown>;\n\n listThreads(): Promise<ThreadSummary[]>;\n getThread(id: string): Promise<ThreadDetail>;\n updateThread(id: string, patch: ThreadPatch): Promise<unknown>;\n deleteThread(id: string): Promise<unknown>;\n\n /**\n * Queue a message on a thread (`POST <base>/chat` with `mode: 'queue'` or `'interrupt'`), which\n * the server answers with `202` JSON rather than a stream. What `chat.queue` sends through; a\n * backend without it keeps the composer blocked while a turn runs.\n */\n enqueueMessage?(request: ChatStreamRequest): Promise<QueuedSendResult>;\n /** `GET <base>/threads/:id/queue`. */\n getQueue?(threadId: string): Promise<ChatQueueState>;\n /** `PATCH <base>/queue/:messageId` — edit and/or move a waiting message. */\n updateQueuedMessage?(messageId: string, update: QueuedMessageUpdate): Promise<ChatQueueState>;\n /** `DELETE <base>/queue/:messageId`. */\n removeQueuedMessage?(messageId: string): Promise<ChatQueueState>;\n /**\n * `POST <base>/queue/:messageId/interrupt` — run a waiting message now: it moves to the head as an\n * interrupt and the running turn is cancelled for it. `interrupting` is the run that was\n * cancelled; `runId` is set instead when nothing was running and the message started at once.\n * What `chat.queue.interrupt(id)` calls.\n */\n interruptQueuedMessage?(\n messageId: string,\n ): Promise<ChatQueueState & { runId?: string; interrupting?: string }>;\n /** `DELETE <base>/threads/:id/queue`. */\n clearQueue?(threadId: string): Promise<ChatQueueState>;\n /** `POST <base>/threads/:id/queue/resume` — `runId` when the head started. */\n resumeQueue?(threadId: string): Promise<ChatQueueState & { runId?: string }>;\n\n forkFromMessage?(threadId: string, messageId: string): Promise<ThreadSummary>;\n promoteThread?(id: string): Promise<unknown>;\n truncateFromMessage?(threadId: string, messageId: string): Promise<unknown>;\n\n listActionProposals?(input: { threadId: string }): Promise<ActionProposalView[]>;\n approveActionProposal?(input: {\n threadId: string;\n proposalId: string;\n remember?: boolean;\n }): Promise<ActionProposalMutationView>;\n rejectActionProposal?(input: {\n threadId: string;\n proposalId: string;\n reason?: string;\n }): Promise<ActionProposalMutationView>;\n\n approveToolCall?(input: {\n toolCallId: string;\n remember?: boolean;\n via?: string;\n }): Promise<unknown>;\n rejectToolCall?(input: { toolCallId: string; reason?: string; via?: string }): Promise<unknown>;\n answerToolCall?(input: {\n toolCallId: string;\n answers?: Record<string, string[]>;\n via?: string;\n }): Promise<unknown>;\n skipToolCall?(input: { toolCallId: string; via?: string }): Promise<unknown>;\n\n uploadAttachment?(file: File, options?: UploadAttachmentOptions): Promise<MessageAttachment>;\n listTools?(agent?: string): Promise<ToolCatalogEntry[]>;\n listSkills?(threadId?: string): Promise<SkillCatalogEntry[]>;\n /** `GET <base>/quota` — every budget window, and which one blocks sends, if any. */\n getQuota?(): Promise<QuotaReport>;\n /** `GET <base>/models?agent=` — what a model picker offers. */\n listModels?(agent?: string): Promise<ModelCatalogView>;\n /** `GET <base>/agents` — what an agent picker offers. */\n listAgents?(): Promise<AgentCatalogEntry[]>;\n /** `GET <base>/config` — attachment limits and upload mode, and which features are on. */\n getConfig?(): Promise<AgentClientConfig>;\n setMessageFeedback?(\n messageId: string,\n input: MessageFeedbackInput,\n ): Promise<{ feedback: MessageFeedback | null }>;\n}\n\n/** An optional {@link AgentBackend} member the bound backend does not implement was called. */\nexport class AgentBackendUnsupportedError extends Error {\n constructor(readonly method: string) {\n super(`The agent backend does not implement ${method}()`);\n this.name = 'AgentBackendUnsupportedError';\n }\n}\n\ntype OptionalMethod = {\n [K in keyof AgentBackend]-?: undefined extends AgentBackend[K] ? K : never;\n}[keyof AgentBackend];\n\n/**\n * The optional backend method `name`, bound — or a throw naming it. For hook code that has to call\n * something a backend may not offer.\n */\nexport function requireBackendMethod<K extends OptionalMethod>(\n backend: AgentBackend,\n name: K,\n): NonNullable<AgentBackend[K]> {\n const method = backend[name];\n if (typeof method !== 'function') {\n throw new AgentBackendUnsupportedError(name);\n }\n return (method as (...args: never[]) => unknown).bind(backend) as NonNullable<AgentBackend[K]>;\n}\n","import type { AgentClientConfig } from '@dudousxd/nestjs-agent-core';\nimport { useEffect, useState } from 'react';\nimport type { AgentBackend } from '../backend.js';\nimport { useAgentBackend } from '../provider.js';\n\nexport interface UseAgentConfigOptions {\n /** Default: the enclosing `<AgentProvider>`'s. Without `getConfig` the config stays `undefined`. */\n backend?: AgentBackend;\n /** `false` holds the request. Default `true`. */\n enabled?: boolean;\n}\n\nexport interface AgentConfigState {\n /** `GET <base>/config`, once loaded — `undefined` before, on a failure, or on a backend without it. */\n config: AgentClientConfig | undefined;\n isLoading: boolean;\n error: Error | null;\n}\n\n// One request per backend for the whole page: the config is a deployment constant. A failure is\n// forgotten so the next mount retries.\nconst shared = new WeakMap<AgentBackend, Promise<AgentClientConfig>>();\n\nfunction load(backend: AgentBackend): Promise<AgentClientConfig> | undefined {\n const getConfig = backend.getConfig;\n if (typeof getConfig !== 'function') return undefined;\n let pending = shared.get(backend);\n if (pending === undefined) {\n pending = getConfig.call(backend).catch((error: unknown) => {\n shared.delete(backend);\n throw error;\n });\n shared.set(backend, pending);\n }\n return pending;\n}\n\n/**\n * The server's client config (`GET <base>/config`): attachment limits and upload mode, and whether a\n * model picker, a quota and anonymous identities are in play. Fetched once per backend and shared;\n * `useAttachments` takes its defaults from it.\n */\nexport function useAgentConfig(options: UseAgentConfigOptions = {}): AgentConfigState {\n const backend = useAgentBackend(options.backend);\n const enabled = options.enabled !== false;\n const [config, setConfig] = useState<AgentClientConfig | undefined>(undefined);\n const [isLoading, setLoading] = useState(false);\n const [error, setError] = useState<Error | null>(null);\n\n useEffect(() => {\n if (!enabled) return;\n const pending = load(backend);\n if (pending === undefined) return;\n let cancelled = false;\n setLoading(true);\n pending.then(\n (loaded) => {\n if (cancelled) return;\n setConfig(loaded !== null && typeof loaded === 'object' ? loaded : undefined);\n setError(null);\n setLoading(false);\n },\n (failure: unknown) => {\n if (cancelled) return;\n setError(failure instanceof Error ? failure : new Error(String(failure)));\n setLoading(false);\n },\n );\n return () => {\n cancelled = true;\n };\n }, [backend, enabled]);\n\n return { config, isLoading, error };\n}\n","import type { UiCapabilities } from '@dudousxd/nestjs-agent-core/genui';\nimport { type Context, type ReactNode, useContext, useMemo, useRef } from 'react';\nimport type { AgentBackend, AttachmentUploadStrategy } from './backend.js';\nimport { AgentClient } from './client.js';\nimport { sharedContext } from './components/ambient-ui.js';\nimport { GenuiProvider, type GenuiProviderValue } from './genui/generative-ui.js';\nimport type { HttpErrorListener } from './http-error.js';\n\n// Shared by key, like the genui contexts: `/media` and `/genui` are separate bundles.\nconst AgentBackendContext: Context<AgentBackend | null> = sharedContext<AgentBackend>(\n '@dudousxd/nestjs-agent-react:agent-backend',\n);\n\nexport interface AgentProviderProps {\n /** Advertise exact supported component versions; omission keeps legacy support, [] is text only. */\n uiCapabilities?: UiCapabilities;\n /**\n * A backend of your own — see {@link AgentBackend}. Omitted → an {@link AgentClient} over this\n * library's REST routes, built from the connection props below (which are ignored when a backend\n * is given). Must be stable across renders.\n */\n backend?: AgentBackend;\n /** The server's origin, e.g. `https://api.example.com`. Default `''` (same origin). */\n baseUrl?: string;\n /** `AgentModule`'s `path`, global prefix included (`'api/agent'`). Default `'agent'`. */\n path?: string;\n /** Static headers on every request. */\n headers?: Record<string, string>;\n /**\n * Read at every request — a short-lived bearer token, or a CSRF header read from a cookie\n * (`{ 'X-XSRF-TOKEN': readCookie('XSRF-TOKEN') }`).\n */\n getHeaders?: () => Record<string, string> | Promise<Record<string, string>>;\n /** `'include'` when the API is on another origin and authenticates by cookie. */\n credentials?: RequestCredentials;\n /** Injectable for tests / non-browser runtimes. */\n fetch?: typeof fetch;\n /**\n * Every error answer of the built-in client (an `AgentHttpError`, or a `MediaUploadError` from\n * `mediaAttachments()`), right before it is thrown — for app-wide reactions such as \"401 → sign\n * in again\". Read at call time, so it may change between renders.\n */\n onHttpError?: HttpErrorListener;\n /** Attachment uploads of the built-in client. */\n attachments?: {\n /** e.g. `mediaAttachments()` from `@dudousxd/nestjs-agent-react/media`. */\n upload?: AttachmentUploadStrategy;\n };\n /**\n * Set generative UI up here — the same settings `<GenuiProvider>` takes (registry, catalog,\n * resolver, fallback, …). Every message then draws pushed components with them.\n */\n genui?: GenuiProviderValue;\n children?: ReactNode;\n}\n\n/**\n * The agent connection, once, at the app root. Every hook below it — `useAgentChat`, `useThreads`,\n * `useModels`, `useAgents`, `useQuota`, `useToolCatalog`, `useMessageFeedback`, `useAttachments` —\n * talks to it unless handed a `backend` of its own.\n *\n * ```tsx\n * <AgentProvider baseUrl=\"https://api.example.com\" credentials=\"include\">\n * <App />\n * </AgentProvider>\n * ```\n *\n * Without a provider every hook shares one same-origin client on `/agent`.\n */\nexport function AgentProvider({\n backend,\n uiCapabilities,\n baseUrl,\n path,\n headers,\n getHeaders,\n credentials,\n fetch,\n onHttpError,\n attachments,\n genui,\n children,\n}: AgentProviderProps) {\n // Headers are read per request, so a re-render with new ones reaches the same client.\n const latestHeaders = useRef({ headers, getHeaders, onHttpError });\n latestHeaders.current = { headers, getHeaders, onHttpError };\n const upload = attachments?.upload;\n const value = useMemo(\n () =>\n backend ??\n new AgentClient({\n ...(baseUrl !== undefined ? { baseUrl } : {}),\n ...(path !== undefined ? { path } : {}),\n ...(credentials !== undefined ? { credentials } : {}),\n ...(fetch !== undefined ? { fetch } : {}),\n ...(upload !== undefined ? { attachments: { upload } } : {}),\n onHttpError: (error) => latestHeaders.current.onHttpError?.(error),\n getHeaders: async () => {\n const current = latestHeaders.current;\n const dynamic = (await current.getHeaders?.()) ?? {};\n return { ...current.headers, ...dynamic };\n },\n }),\n [backend, baseUrl, path, credentials, fetch, upload],\n );\n const content =\n genui !== undefined ? <GenuiProvider {...genui}>{children}</GenuiProvider> : children;\n return (\n <AgentUiCapabilitiesContext.Provider value={uiCapabilities ?? null}>\n <AgentBackendContext.Provider value={value}>{content}</AgentBackendContext.Provider>\n </AgentUiCapabilitiesContext.Provider>\n );\n}\n\nlet fallback: AgentClient | undefined;\n\n/** The client every hook uses outside an {@link AgentProvider}: same origin, `/agent`. */\nfunction defaultBackend(): AgentClient {\n fallback ??= new AgentClient();\n return fallback;\n}\n\n/**\n * The backend a hook talks to: `own` when given, else the enclosing {@link AgentProvider}'s, else a\n * shared same-origin client on `/agent`. For your own hooks over the same connection.\n */\nexport function useAgentBackend<B extends AgentBackend = AgentBackend>(own?: B): B {\n const provided = useContext(AgentBackendContext);\n return (own ?? provided ?? defaultBackend()) as B;\n}\n\nconst AgentUiCapabilitiesContext = sharedContext<UiCapabilities>(\n '@dudousxd/nestjs-agent-react:ui-capabilities',\n);\n/**\n * The UI capabilities the nearest `<AgentProvider uiCapabilities>` declared, or `undefined` when it\n * declared none. `useAgentChat` reads this unless given its own `uiCapabilities`; read it too when a\n * hook of yours talks to the agent outside `useAgentChat`.\n */\nexport function useAgentUiCapabilities(): UiCapabilities | undefined {\n return useContext(AgentUiCapabilitiesContext) ?? undefined;\n}\n","import { type Context, type ReactNode, createContext, useContext } from 'react';\nimport type { TranscriptUiBlock } from '../transcript/model.js';\n\n/** Draws a server-pushed component block. */\nexport type AmbientRenderUi = (block: TranscriptUiBlock) => ReactNode;\n\n/**\n * A context stored on `globalThis` under a registered symbol. Each entry point (`.`, `/genui`,\n * `/genui/json-render`) is its own bundle with its own copy of every module, so a context one entry\n * provides and another reads has to be found by key, not by module identity.\n */\nexport function sharedContext<T>(key: string): Context<T | null> {\n const symbol = Symbol.for(key);\n const holder = globalThis as Record<symbol, Context<T | null> | undefined>;\n const existing = holder[symbol];\n if (existing !== undefined) return existing;\n const created = createContext<T | null>(null);\n holder[symbol] = created;\n return created;\n}\n\n/**\n * How pushed components are drawn when no `renderUi` is passed — set by `<GenuiProvider>` (the\n * `/genui` subpath) and read by `MessageItem`.\n */\nexport const AmbientRenderUiContext: Context<AmbientRenderUi | null> =\n sharedContext<AmbientRenderUi>('@dudousxd/nestjs-agent-react:ambient-render-ui');\n\n/**\n * The renderer `<GenuiProvider>` installed for pushed components, or `null` outside one. For a\n * custom transcript built on `useTranscriptItem`: draw a `ui` block with it and you get what\n * `MessageItem` draws.\n */\nexport function useAmbientRenderUi(): AmbientRenderUi | null {\n return useContext(AmbientRenderUiContext);\n}\n","import {\n Component,\n type Context,\n type ErrorInfo,\n type ReactNode,\n createContext,\n useCallback,\n useContext,\n useMemo,\n} from 'react';\nimport { AmbientRenderUiContext, sharedContext } from '../components/ambient-ui.js';\nimport type { TranscriptUiBlock } from '../transcript/model.js';\nimport type {\n GenerativeUIElement,\n GenerativeUIItem,\n GenerativeUIOptions,\n GenerativeUIProblem,\n GenerativeUIState,\n GenuiNodeState,\n GenuiPlaceholder,\n GenuiRegistry,\n GenuiRenderer,\n} from './types.js';\nimport {\n useGenerativeUIState,\n useResolvedComponent,\n useValidatedProps,\n} from './use-generative-ui.js';\n\n/** What to draw instead of a component that did not render. Default: nothing. */\nexport type GenerativeUIFallback = ReactNode | ((problem: GenerativeUIProblem) => ReactNode);\n\ninterface TreeScope {\n fallbackText?: string;\n componentVersions?: Record<string, number>;\n options: GenerativeUIOptions;\n fallback: GenerativeUIFallback | undefined;\n loading: ReactNode;\n placeholder: GenuiPlaceholder | undefined;\n onError: ((error: unknown, item: GenerativeUIItem) => void) | undefined;\n}\n\nconst TreeScopeContext = createContext<TreeScope | null>(null);\n\n// Shared by key, like the provider's: a renderer imports the hook from `/genui` while the tree may\n// be drawn by the `/genui/json-render` bundle's copy of this module.\nconst GenuiNodeContext: Context<GenuiNodeState | null> = sharedContext<GenuiNodeState>(\n '@dudousxd/nestjs-agent-react:genui-node',\n);\n\n/**\n * The tree node being rendered — read it in a renderer to draw a skeleton while the model is still\n * writing the node (`incomplete`), e.g. a chart's axes before its data. `null` outside a tree.\n *\n * ```tsx\n * function Chart(props: ChartProps) {\n * const node = useGenuiNode();\n * if (node?.incomplete && !props.data?.length) return <ChartSkeleton title={props.title} />;\n * return <BarChart {...props} />;\n * }\n * ```\n */\nexport function useGenuiNode(): GenuiNodeState | null {\n return useContext(GenuiNodeContext);\n}\n\nfunction renderPlaceholder(scope: TreeScope, node: GenuiNodeState): ReactNode {\n const { placeholder } = scope;\n if (typeof placeholder === 'function') return placeholder(node);\n return placeholder !== undefined ? placeholder : scope.loading;\n}\n\nfunction renderFallback(fallback: GenerativeUIFallback | undefined, problem: GenerativeUIProblem) {\n if (typeof fallback === 'function') return fallback(problem);\n if (fallback !== undefined) return fallback;\n return problem.item.fallbackText !== undefined ? (\n <span style={{ whiteSpace: 'pre-wrap' }}>{problem.item.fallbackText}</span>\n ) : null;\n}\n\ninterface BoundaryProps {\n item: GenerativeUIItem;\n fallback: GenerativeUIFallback | undefined;\n onError: ((error: unknown, item: GenerativeUIItem) => void) | undefined;\n children: ReactNode;\n}\n\n/** One failing renderer takes down its own item, never the message around it. */\nclass ItemBoundary extends Component<BoundaryProps, { error: unknown; failed: boolean }> {\n override state = { error: undefined as unknown, failed: false };\n\n static getDerivedStateFromError(error: unknown) {\n return { error, failed: true };\n }\n\n override componentDidCatch(error: unknown, _info: ErrorInfo) {\n this.props.onError?.(error, this.props.item);\n }\n\n override componentDidUpdate(previous: BoundaryProps) {\n // New props for the same item (a streamed update) get a fresh chance to render.\n if (this.state.failed && previous.item !== this.props.item) {\n this.setState({ error: undefined, failed: false });\n }\n }\n\n override render() {\n if (this.state.failed) {\n return renderFallback(this.props.fallback, {\n reason: 'error',\n item: this.props.item,\n error: this.state.error,\n });\n }\n return this.props.children;\n }\n}\n\nfunction nodeItem(node: GenerativeUIElement, id: string): GenerativeUIItem {\n return { id, component: node.type, props: node.props ?? {}, version: null, toolCallId: null };\n}\n\n/** One tree node: resolved and validated like a top-level item, children rendered as its `children`. */\nfunction TreeNode({ node, id }: { node: GenerativeUIElement; id: string }) {\n const scope = useContext(TreeScopeContext);\n const item = useMemo(() => nodeItem(node, id), [node, id]);\n // A node of a preview the model is still writing: its props are half there, so they are not\n // validated (the final frame is) — the renderer is told instead, through `useGenuiNode`.\n const incomplete = node.incomplete === true;\n const held = node.held === true;\n const state = useMemo<GenuiNodeState>(\n () => ({ id, type: node.type, incomplete, held }),\n [id, node.type, incomplete, held],\n );\n const storedVersion = scope?.componentVersions?.[node.type];\n const definition = scope?.options.catalog?.get?.(node.type);\n const incompatible =\n storedVersion !== undefined &&\n definition !== undefined &&\n storedVersion !== (definition.version ?? 1);\n const resolution = useResolvedComponent(\n node.type,\n storedVersion ?? null,\n incompatible ? {} : (scope?.options.registry ?? {}),\n scope?.options.resolveComponent,\n );\n const validation = useValidatedProps(\n incompatible || incomplete ? undefined : scope?.options.catalog,\n node.type,\n item.props,\n );\n if (scope === null) return null;\n if (held) {\n return (\n <GenuiNodeContext.Provider value={state}>\n {renderPlaceholder(scope, state)}\n </GenuiNodeContext.Provider>\n );\n }\n if (resolution.status === 'loading' || validation.status === 'pending') return scope.loading;\n if (resolution.status === 'unknown') {\n if (scope.fallback === undefined && scope.fallbackText !== undefined)\n throw new Error('Unknown tree component');\n return renderFallback(scope.fallback, { reason: 'unknown', item });\n }\n if (resolution.status === 'error') {\n if (scope.fallback === undefined && scope.fallbackText !== undefined) throw resolution.error;\n return renderFallback(scope.fallback, { reason: 'error', item, error: resolution.error });\n }\n if (validation.status === 'invalid') {\n if (scope.fallback === undefined && scope.fallbackText !== undefined)\n throw new Error('Invalid tree component');\n return renderFallback(scope.fallback, { reason: 'invalid', item, issues: validation.issues });\n }\n const Renderer = resolution.Component;\n const children = Array.isArray(node.children) ? node.children : [];\n return (\n <GenuiNodeContext.Provider value={state}>\n <Renderer {...validation.props}>\n {children.length > 0\n ? children.map((child, index) => {\n const childId = `${id}.${index}`;\n if (scope.fallback === undefined && scope.fallbackText !== undefined)\n return <TreeNode key={childId} node={child} id={childId} />;\n return (\n <ItemBoundary\n key={childId}\n item={nodeItem(child, childId)}\n fallback={scope.fallback}\n onError={scope.onError}\n >\n <TreeNode node={child} id={childId} />\n </ItemBoundary>\n );\n })\n : undefined}\n </Renderer>\n </GenuiNodeContext.Provider>\n );\n}\n\n/**\n * Renders a `genui:tree` frame's `{ root }` node by node through the same registry, catalog and\n * resolver as top-level components. Used automatically for tree frames unless a `treeRenderer`\n * (e.g. the json-render one) or a registry entry for `genui:tree` takes over.\n */\nexport function GenuiTree({ root }: { root?: GenerativeUIElement }) {\n if (root === undefined || root === null || typeof root.type !== 'string') return null;\n return <TreeNode node={root} id=\"root\" />;\n}\n\nexport interface GenerativeUIScopeProps extends GenerativeUIOptions {\n fallbackText?: string;\n componentVersions?: Record<string, number>;\n fallback?: GenerativeUIFallback;\n loading?: ReactNode;\n /** Drawn for a tree node held back while the model writes it. Default: `loading`. */\n placeholder?: GenuiPlaceholder;\n onError?: (error: unknown, item: GenerativeUIItem) => void;\n children?: ReactNode;\n}\n\n/**\n * The registry, catalog and fallbacks tree nodes render with. `<GenerativeUI>` provides it; wrap\n * your own chrome in it when you draw `useGenerativeUI`'s `Component` yourself and it may be a tree.\n */\nexport function GenerativeUIScope({\n registry,\n catalog,\n resolveComponent,\n fallback,\n fallbackText,\n componentVersions,\n loading = null,\n placeholder,\n onError,\n children,\n}: GenerativeUIScopeProps) {\n const scope = useMemo<TreeScope>(\n () => ({\n options: {\n registry,\n ...(catalog !== undefined ? { catalog } : {}),\n ...(resolveComponent !== undefined ? { resolveComponent } : {}),\n },\n fallback,\n ...(componentVersions !== undefined ? { componentVersions } : {}),\n ...(fallbackText !== undefined ? { fallbackText } : {}),\n loading,\n placeholder,\n onError,\n }),\n [\n registry,\n catalog,\n resolveComponent,\n fallback,\n fallbackText,\n componentVersions,\n loading,\n placeholder,\n onError,\n ],\n );\n return <TreeScopeContext.Provider value={scope}>{children}</TreeScopeContext.Provider>;\n}\n\n/** What `<GenuiProvider>` hands every `<GenerativeUI>` / `useGenerativeUI` below it. */\nexport interface GenuiProviderValue extends Partial<GenerativeUIOptions> {\n fallback?: GenerativeUIFallback;\n loading?: ReactNode;\n /** Drawn for a tree node held back while the model writes it (`streaming: 'complete'`). */\n placeholder?: GenuiPlaceholder;\n onError?: (error: unknown, item: GenerativeUIItem) => void;\n}\n\n// Shared by key: `/genui` and `/genui/json-render` are separate bundles, and a provider from one\n// must reach a `<GenerativeUI>` from the other.\nconst GenuiContext: Context<GenuiProviderValue | null> = sharedContext<GenuiProviderValue>(\n '@dudousxd/nestjs-agent-react:genui-provider',\n);\n\n/** The enclosing `<GenuiProvider>`'s settings, or `null` outside one. */\nexport function useGenuiProvider(): GenuiProviderValue | null {\n return useContext(GenuiContext);\n}\n\nexport interface GenuiProviderProps extends GenuiProviderValue {\n children?: ReactNode;\n}\n\n/**\n * Set generative UI up once, at the app root: the registry of your renderers, the catalog to\n * validate against, a resolver for components the registry lacks, and what to draw when one does\n * not render. Every `<GenerativeUI>` below reads it (its own props still win), and `MessageItem` /\n * `MessageList` draw pushed components with it — no `renderUi` per message.\n *\n * ```tsx\n * <GenuiProvider registry={registry} catalog={catalog} fallback={({ item }) => <Unknown name={item.component} />}>\n * <App />\n * </GenuiProvider>\n * ```\n */\nexport function GenuiProvider({\n registry,\n catalog,\n resolveComponent,\n treeRenderer,\n fallback,\n loading,\n placeholder,\n onError,\n children,\n}: GenuiProviderProps) {\n const value = useMemo<GenuiProviderValue>(\n () => ({\n ...(registry !== undefined ? { registry } : {}),\n ...(catalog !== undefined ? { catalog } : {}),\n ...(resolveComponent !== undefined ? { resolveComponent } : {}),\n ...(treeRenderer !== undefined ? { treeRenderer } : {}),\n ...(fallback !== undefined ? { fallback } : {}),\n ...(loading !== undefined ? { loading } : {}),\n ...(placeholder !== undefined ? { placeholder } : {}),\n ...(onError !== undefined ? { onError } : {}),\n }),\n [registry, catalog, resolveComponent, treeRenderer, fallback, loading, placeholder, onError],\n );\n const renderUi = useCallback((block: TranscriptUiBlock) => <GenerativeUI part={block} />, []);\n return (\n <GenuiContext.Provider value={value}>\n <AmbientRenderUiContext.Provider value={renderUi}>{children}</AmbientRenderUiContext.Provider>\n </GenuiContext.Provider>\n );\n}\n\nconst NO_REGISTRY: GenuiRegistry = {};\n\n/** Provider settings overlaid with explicit ones (explicit wins), memoized on their parts. */\nfunction useMergedOptions(own: Partial<GenerativeUIOptions>): GenerativeUIOptions {\n const provided = useContext(GenuiContext);\n const registry = own.registry ?? provided?.registry ?? NO_REGISTRY;\n const catalog = own.catalog ?? provided?.catalog;\n const resolveComponent = own.resolveComponent ?? provided?.resolveComponent;\n const treeRenderer = own.treeRenderer ?? provided?.treeRenderer;\n return useMemo(\n () => ({\n registry,\n ...(catalog !== undefined ? { catalog } : {}),\n ...(resolveComponent !== undefined ? { resolveComponent } : {}),\n ...(treeRenderer !== undefined ? { treeRenderer } : {}),\n }),\n [registry, catalog, resolveComponent, treeRenderer],\n );\n}\n\n/**\n * The headless half of {@link GenerativeUI}: what to draw for one pushed component, or `null` when\n * `part` is not one. Options default to the enclosing `<GenuiProvider>`'s.\n */\nexport function useGenerativeUI(\n part: unknown,\n options: Partial<GenerativeUIOptions> = {},\n): GenerativeUIState | null {\n const merged = useMergedOptions(options);\n return useGenerativeUIState(part, merged, merged.treeRenderer ?? (GenuiTree as GenuiRenderer));\n}\n\nexport interface GenerativeUIProps extends Partial<GenerativeUIOptions> {\n /** A transcript `ui` block, a `data-ui` message part, or a stored `{ id, component, props, version? }`. */\n part: TranscriptUiBlock | GenerativeUIItem | unknown;\n /** Drawn for an unknown component, invalid props, or a renderer that threw. Default: the provider's, then the item's persisted text. */\n fallback?: GenerativeUIFallback;\n /** Drawn while a resolver or an async validation is pending. Default: the provider's, else nothing. */\n loading?: ReactNode;\n /**\n * Drawn for a tree node held back while the model writes it (its component streams `complete`).\n * Default: the provider's, else `loading`.\n */\n placeholder?: GenuiPlaceholder;\n /** A renderer threw (the item shows `fallback`). */\n onError?: (error: unknown, item: GenerativeUIItem) => void;\n}\n\n/**\n * Draws one server-pushed component with the app's own renderer. Headless: it adds no element and\n * no style of its own — only what the registry's component renders (and whatever `fallback` /\n * `loading` you pass). Everything but `part` defaults to the enclosing `<GenuiProvider>`.\n *\n * ```tsx\n * <GenerativeUI part={block} />\n * ```\n */\nexport function GenerativeUI({\n part,\n registry,\n catalog,\n resolveComponent,\n treeRenderer,\n fallback: ownFallback,\n loading: ownLoading,\n placeholder: ownPlaceholder,\n onError: ownOnError,\n}: GenerativeUIProps) {\n const provided = useContext(GenuiContext);\n const fallback = ownFallback !== undefined ? ownFallback : provided?.fallback;\n const loading = ownLoading ?? provided?.loading ?? null;\n const placeholder = ownPlaceholder !== undefined ? ownPlaceholder : provided?.placeholder;\n const onError = ownOnError ?? provided?.onError;\n const options = useMergedOptions({\n ...(registry !== undefined ? { registry } : {}),\n ...(catalog !== undefined ? { catalog } : {}),\n ...(resolveComponent !== undefined ? { resolveComponent } : {}),\n ...(treeRenderer !== undefined ? { treeRenderer } : {}),\n });\n const state = useGenerativeUIState(\n part,\n options,\n options.treeRenderer ?? (GenuiTree as GenuiRenderer),\n );\n if (state === null) return null;\n if (state.status === 'loading') return loading;\n if (state.status === 'problem') {\n const { status: _status, ...problem } = state;\n return renderFallback(fallback, problem);\n }\n const Renderer = state.Component;\n return (\n <GenerativeUIScope\n {...options}\n {...(state.item.componentVersions !== undefined\n ? { componentVersions: state.item.componentVersions }\n : {})}\n {...(state.item.fallbackText !== undefined ? { fallbackText: state.item.fallbackText } : {})}\n fallback={fallback}\n loading={loading}\n {...(placeholder !== undefined ? { placeholder } : {})}\n {...(onError !== undefined ? { onError } : {})}\n >\n <ItemBoundary item={state.item} fallback={fallback} onError={onError}>\n <Renderer {...state.props} />\n </ItemBoundary>\n </GenerativeUIScope>\n );\n}\n","import { useEffect, useMemo, useState } from 'react';\nimport {\n GENUI_TREE_COMPONENT,\n type GenerativeUIItem,\n type GenerativeUIOptions,\n type GenerativeUIState,\n type GenuiCatalogLike,\n type GenuiIssueLike,\n type GenuiRegistry,\n type GenuiRenderer,\n type ResolveComponent,\n} from './types.js';\n\nfunction isRecord(value: unknown): value is Record<string, unknown> {\n return typeof value === 'object' && value !== null && !Array.isArray(value);\n}\n\n/**\n * Normalize whatever carries a pushed component: a transcript `ui` block, a `data-ui` message part\n * (`{ type: 'data-ui', id, data }`), a stored `{ id, component, props, version? }` entry. `null` for\n * anything else.\n */\nexport function toGenerativeUIItem(part: unknown): GenerativeUIItem | null {\n if (!isRecord(part)) return null;\n const source = part.type === 'data-ui' && isRecord(part.data) ? part.data : part;\n if (typeof source.component !== 'string') return null;\n const id =\n typeof source.id === 'string' ? source.id : typeof part.id === 'string' ? part.id : null;\n if (id === null) return null;\n return {\n id,\n component: source.component,\n ...(isRecord(source.componentVersions) &&\n Object.values(source.componentVersions).every(\n (version) => typeof version === 'number' && Number.isSafeInteger(version) && version > 0,\n )\n ? { componentVersions: { ...source.componentVersions } as Record<string, number> }\n : {}),\n ...(typeof source.fallbackText === 'string' ? { fallbackText: source.fallbackText } : {}),\n props: isRecord(source.props) ? source.props : {},\n version: typeof source.version === 'number' ? source.version : null,\n toolCallId: typeof source.toolCallId === 'string' ? source.toolCallId : null,\n ...(source.partial === true ? { partial: true as const } : {}),\n };\n}\n\ntype Resolution =\n | { status: 'ready'; Component: GenuiRenderer }\n | { status: 'loading' }\n | { status: 'unknown' }\n | { status: 'error'; error: unknown };\n\ninterface CacheEntry {\n resolution: Resolution;\n settled: Promise<void> | null;\n}\n\nconst resolverCaches = new WeakMap<ResolveComponent, Map<string, CacheEntry>>();\n\nfunction resolveCached(\n resolve: ResolveComponent,\n name: string,\n version: number | null,\n): CacheEntry {\n let cache = resolverCaches.get(resolve);\n if (cache === undefined) {\n cache = new Map();\n resolverCaches.set(resolve, cache);\n }\n const key = `${name}@${version ?? ''}`;\n const hit = cache.get(key);\n if (hit !== undefined) return hit;\n let entry: CacheEntry;\n try {\n const result = resolve(name, version);\n if (result instanceof Promise) {\n entry = { resolution: { status: 'loading' }, settled: null };\n entry.settled = result.then(\n (Component) => {\n entry.resolution = Component ? { status: 'ready', Component } : { status: 'unknown' };\n },\n (error: unknown) => {\n entry.resolution = { status: 'error', error };\n },\n );\n } else {\n entry = {\n resolution: result ? { status: 'ready', Component: result } : { status: 'unknown' },\n settled: null,\n };\n }\n } catch (error) {\n entry = { resolution: { status: 'error', error }, settled: null };\n }\n cache.set(key, entry);\n return entry;\n}\n\n/**\n * Which renderer draws `name`: the registry first, then `resolveComponent` (cached; async results\n * re-render the caller when they land). `fallbackTree` answers the tree component when the\n * registry does not override it.\n */\nexport function useResolvedComponent(\n name: string,\n version: number | null,\n registry: GenuiRegistry,\n resolve: ResolveComponent | undefined,\n fallbackTree?: GenuiRenderer,\n): Resolution {\n const [, setTick] = useState(0);\n const own = registry[name];\n const entry =\n own !== undefined || resolve === undefined ? null : resolveCached(resolve, name, version);\n const pending = entry?.resolution.status === 'loading' ? entry.settled : null;\n useEffect(() => {\n if (pending === null) return;\n let live = true;\n void pending.then(() => {\n if (live) setTick((tick) => tick + 1);\n });\n return () => {\n live = false;\n };\n }, [pending]);\n if (own !== undefined) return { status: 'ready', Component: own };\n if (entry !== null && entry.resolution.status !== 'unknown') return entry.resolution;\n if (name === GENUI_TREE_COMPONENT && fallbackTree !== undefined) {\n return { status: 'ready', Component: fallbackTree };\n }\n return { status: 'unknown' };\n}\n\ntype Validation =\n | { status: 'ok'; props: Record<string, unknown> }\n | { status: 'pending' }\n | { status: 'invalid'; issues: GenuiIssueLike[] };\n\n/**\n * Props checked against the catalog: synchronously when the catalog can (`validateSync`), else\n * after the async check settles. A component the catalog does not know passes through unchecked.\n */\nexport function useValidatedProps(\n catalog: GenuiCatalogLike | undefined,\n name: string,\n props: Record<string, unknown>,\n): Validation {\n const checked = catalog?.has(name) === true;\n const immediate = useMemo<Validation | null>(() => {\n if (!checked || catalog === undefined) return { status: 'ok', props };\n const result = catalog.validateSync?.(name, props);\n if (result === undefined) return null;\n return result.ok\n ? { status: 'ok', props: result.value }\n : { status: 'invalid', issues: result.issues };\n }, [checked, catalog, name, props]);\n const [late, setLate] = useState<{ props: Record<string, unknown>; result: Validation } | null>(\n null,\n );\n useEffect(() => {\n if (immediate !== null || catalog === undefined) return;\n let live = true;\n catalog.validate(name, props).then(\n (result) => {\n if (!live) return;\n setLate({\n props,\n result: result.ok\n ? { status: 'ok', props: result.value }\n : { status: 'invalid', issues: result.issues },\n });\n },\n (error: unknown) => {\n if (!live) return;\n setLate({\n props,\n result: {\n status: 'invalid',\n issues: [{ path: [], message: error instanceof Error ? error.message : String(error) }],\n },\n });\n },\n );\n return () => {\n live = false;\n };\n }, [immediate, catalog, name, props]);\n if (immediate !== null) return immediate;\n return late !== null && late.props === props ? late.result : { status: 'pending' };\n}\n\n/** {@link import('./generative-ui.js').useGenerativeUI}, with the tree renderer handed in (avoids an import cycle). */\nexport function useGenerativeUIState(\n part: unknown,\n options: GenerativeUIOptions,\n fallbackTree: GenuiRenderer | undefined,\n): GenerativeUIState | null {\n const item = useMemo(() => toGenerativeUIItem(part), [part]);\n const name = item?.component ?? '';\n const definition = options.catalog?.get?.(name);\n const incompatible =\n item?.fallbackText !== undefined &&\n item.version !== null &&\n definition !== undefined &&\n item.version !== (definition.version ?? 1);\n const resolution = useResolvedComponent(\n name,\n item?.version ?? null,\n incompatible ? {} : options.registry,\n item === null ? undefined : options.resolveComponent,\n fallbackTree,\n );\n const empty = useMemo<Record<string, unknown>>(() => ({}), []);\n // A tree is validated node by node as it renders, not as one component.\n const validation = useValidatedProps(\n item === null || name === GENUI_TREE_COMPONENT || incompatible ? undefined : options.catalog,\n name,\n item?.props ?? empty,\n );\n if (item === null) return null;\n // A withdrawn preview (partial, nothing to draw): the call will not replace it.\n if (item.partial === true && Object.keys(item.props).length === 0) return null;\n if (\n name === GENUI_TREE_COMPONENT &&\n item.fallbackText !== undefined &&\n (!isRecord(item.props.root) || typeof item.props.root.type !== 'string')\n )\n return {\n status: 'problem',\n reason: 'invalid',\n item,\n issues: [{ path: ['root'], message: 'Invalid UI tree root' }],\n };\n if (resolution.status === 'loading') return { status: 'loading', item };\n if (resolution.status === 'unknown') return { status: 'problem', reason: 'unknown', item };\n if (resolution.status === 'error') {\n return { status: 'problem', reason: 'error', item, error: resolution.error };\n }\n if (validation.status === 'pending') return { status: 'loading', item };\n if (validation.status === 'invalid') {\n return { status: 'problem', reason: 'invalid', item, issues: validation.issues };\n }\n return { status: 'ready', item, Component: resolution.Component, props: validation.props };\n}\n","import type { ComponentType, ReactNode } from 'react';\n\n/** The `ui` frame component a composed tree is pushed under (`GENUI_TREE_COMPONENT` of `@dudousxd/nestjs-agent-core/genui`). */\nexport const GENUI_TREE_COMPONENT = 'genui:tree';\n\n/** One pushed component, normalized from whatever carried it (a transcript block, a `data-ui` part, a stored entry). */\nexport interface GenerativeUIItem {\n fallbackText?: string;\n componentVersions?: Record<string, number>;\n id: string;\n component: string;\n props: Record<string, unknown>;\n version: number | null;\n toolCallId: string | null;\n /**\n * A preview drawn while the model is still writing the call (genui `streaming: 'partial'`):\n * unvalidated, and replaced in place by the final frame under the same `id`.\n */\n partial?: true;\n}\n\n/** A node of a composed tree (`genui:tree` frames): `{ type, props, children? }`. */\nexport interface GenerativeUIElement {\n type: string;\n props: Record<string, unknown>;\n children?: GenerativeUIElement[];\n /**\n * The node's position (`root`, `root.0`, `root.0.2`), carried by partial frames. Stable as the\n * tree grows, and the same rule names the final tree's nodes.\n */\n id?: string;\n /** Partial frames only: the model has not finished writing this node. */\n incomplete?: true;\n /** Partial frames only: a `streaming: 'complete'` component held back until it closes (no props). */\n held?: true;\n}\n\n/**\n * What a tree node's renderer can learn about its node ({@link useGenuiNode}): which node it is,\n * and whether the model is still writing it. Room is left for more states (data a node is bound\n * to, loading) as separate fields — `incomplete` only ever means \"still being written\".\n */\nexport interface GenuiNodeState {\n /** The node's position id (`root`, `root.1.0`): stable from the first preview to the final frame. */\n id: string;\n type: string;\n /** The model has not finished writing this node: props (and children) may still grow. */\n incomplete: boolean;\n /** The node is a placeholder for a component that is only drawn whole (`streaming: 'complete'`). */\n held: boolean;\n}\n\n/**\n * An app's renderer for one component: it receives the component's props spread, plus `children`\n * when it is a layout node in a tree. Any React component — the library never styles anything.\n */\nexport type GenuiRenderer<P = any> = ComponentType<P & { children?: ReactNode }>;\n\n/** Component name → the app's renderer. */\nexport type GenuiRegistry = Record<string, GenuiRenderer>;\n\n/**\n * Resolve a component the registry does not have — typically a tenant's own component, fetched for\n * the exact `version` a message was rendered with. Return `null`/`undefined` for \"no such\n * component\". May be async; results are cached per resolver, name and version.\n */\nexport type ResolveComponent = (\n name: string,\n version: number | null,\n) => GenuiRenderer | null | undefined | Promise<GenuiRenderer | null | undefined>;\n\nexport interface GenuiIssueLike {\n path: (string | number)[];\n message: string;\n}\n\ntype ValidationLike =\n | { ok: true; value: Record<string, unknown> }\n | { ok: false; issues: GenuiIssueLike[] };\n\n/**\n * What the renderer needs from a catalog to validate props before drawing them. A `Catalog` from\n * `@dudousxd/nestjs-agent-core/genui` satisfies it; declared structurally so any catalog-shaped\n * object does too.\n */\nexport interface GenuiCatalogLike {\n get?(name: string): { version?: number } | undefined;\n has(name: string): boolean;\n validate(name: string, props: unknown): Promise<ValidationLike>;\n validateSync?(name: string, props: unknown): ValidationLike | undefined;\n}\n\nexport interface GenerativeUIOptions {\n registry: GenuiRegistry;\n /** Validate props against it before rendering. Components the catalog does not know render unvalidated. */\n catalog?: GenuiCatalogLike;\n resolveComponent?: ResolveComponent;\n /**\n * Draws a composed tree frame (`genui:tree`) whole — e.g. through json-render (see the\n * `/genui/json-render` subpath's `GenuiProvider`). Omitted → trees render node by node through\n * `registry`.\n */\n treeRenderer?: GenuiRenderer<{ root?: GenerativeUIElement }>;\n}\n\n/**\n * Drawn in place of a tree node that is not drawable yet — a `held` node (its component streams\n * `complete`) while the model writes it. Default: the `loading` element.\n */\nexport type GenuiPlaceholder = ReactNode | ((node: GenuiNodeState) => ReactNode);\n\n/** Why an item did not render. */\nexport type GenerativeUIProblem =\n | { reason: 'unknown'; item: GenerativeUIItem }\n | { reason: 'invalid'; item: GenerativeUIItem; issues: GenuiIssueLike[] }\n | { reason: 'error'; item: GenerativeUIItem; error: unknown };\n\nexport type GenerativeUIState =\n | {\n status: 'ready';\n item: GenerativeUIItem;\n Component: GenuiRenderer;\n props: Record<string, unknown>;\n }\n | { status: 'loading'; item: GenerativeUIItem }\n | ({ status: 'problem' } & GenerativeUIProblem);\n","import type { AgentStreamEvent, ElicitationRequest } from '@dudousxd/nestjs-agent-core';\nimport type { ChatStreamRequest, ChatStreamResponse } from './backend.js';\n\n/**\n * Talk to an AG-UI 1.0 producer (https://docs.ag-ui.com/spec/1.0) through `useAgentChat`.\n *\n * `agUiChatStream` POSTs a `RunAgentInput` and hands the transport the answer re-framed in this\n * library's stream protocol, so everything built on `useAgentChat` — the transcript, tool activity,\n * generative UI — renders an AG-UI agent unchanged. Put it behind `openChatStream` of any backend:\n *\n * ```ts\n * const backend: AgentBackend = {\n * ...httpBackend,\n * openChatStream: (request) => agUiChatStream(request, { url: '/agent/ag-ui' }),\n * }\n * ```\n *\n * What maps where (the inverse of the producer in `@adonis-agora/agent/ag-ui`):\n * - `TEXT_MESSAGE_*` → `text`; `REASONING_MESSAGE_*` → `reasoning`; `STEP_*` → `step-start` /\n * `step-finish`;\n * - `TOOL_CALL_START` / `ARGS` / `END` → `tool-input-start` / `-delta` / `-available`, with the\n * `toolKind` and `parentId` from `metadata['agora.toolKind']` / `['agora.parentId']` (a call\n * without them is a `read`); `TOOL_CALL_RESULT` → `tool-output` (or `tool-output-error` /\n * `-denied`, from `metadata['agora.outcome']`);\n * - `ACTIVITY_SNAPSHOT` / `ACTIVITY_DELTA` → a `ui` part named `AgUiActivity`, id\n * `activity:<messageId>`, props `{ activityType, content }` — the whole content each time (the\n * delta's JSON Patch applied here), so a repeat replaces the widget in place;\n * - `RUN_ERROR` → the stream's `event: error`; `RUN_FINISHED` → `event: done` (a cancelled\n * outcome writes `cancelled` first). An interrupt outcome whose every interrupt this stream\n * already showed (`agora.approval-requested` / `agora.elicitation`) ends the stream WITHOUT\n * `done`: the run is parked, not over, so the transport re-attaches to it on the native route\n * (`chat/:runId/stream?after=`) and the rest of the run — after the person decides through the\n * native `tool-call` routes — streams into the same message. An interrupt nothing showed (another\n * producer's) becomes a `ui` part named `AgUiInterrupt` carrying it, for the app to render;\n * - the producer's SSE `id:` (the run's own sequence number, which this library's producer writes)\n * is passed on as the cursor the transport re-attaches with; frames of a producer that numbers\n * nothing carry no id, and the transport then does not try to re-attach;\n * - `CUSTOM` events a producer of this family writes (`agora.ui`, `agora.title`, `agora.queue`,\n * `agora.approval-requested` / `-settled`, `agora.elicitation`, `agora.run`) → the frames they\n * stand for; `agora.step-usage` (right after a `STEP_FINISHED`) → that step's `usage`, `costUsd`\n * and `reasoningMs` on its `step-finish`; `agora.action-proposal-decision` → the\n * `data-proposal-decision` part a native decision answers with (`{ threadId, proposalDecision,\n * text }`). Any other `CUSTOM` is ignored, as the protocol requires of a consumer that does not\n * know it.\n *\n * And on the way in: the send's staged `attachments` (`{ mediaId }`) become `file` content parts\n * the producer resolves for the caller, and `regenerate: true` rides `forwardedProps`.\n */\nexport interface AgUiChatStreamOptions {\n /** The producer's endpoint (`POST`, `RunAgentInput` in, `text/event-stream` out). */\n url: string;\n /** Headers for every request (auth, CSRF). Per-request headers from the send win. */\n headers?: Record<string, string>;\n /** Defaults to the global `fetch`, with `credentials: 'same-origin'`. */\n fetch?: typeof fetch;\n /**\n * Shape `forwardedProps` from the send's body. Default: `{ pageContext, agent, model, persona,\n * uiCapabilities, regenerate }` from the body, whichever are present.\n */\n forwardedProps?: (body: Record<string, unknown>) => unknown;\n /** Read the refusal of a non-2xx answer. Default: the JSON body's `message`, else the status. */\n refusal?: (response: Response) => Promise<Error>;\n /**\n * The user message's `content` for the send. Default: the body's `message` as a string — or,\n * when the send carries staged `attachments` (`{ mediaId, contentType? }`, what the composer\n * uploads), a `text` part followed by one `file` part per attachment\n * (`source: { type: 'file', value: <mediaId>, provider: 'nestjs-agent' }`), which this library's\n * producer resolves for the caller. Return your own list of AG-UI content parts to send inline\n * bytes instead — `{ type: 'image' | 'document' | …, source: { type: 'data', value: <base64>,\n * mimeType } }`.\n */\n content?: (body: Record<string, unknown>) => string | AgUiContentPart[];\n}\n\n/** One AG-UI content part of a user message (text, or media by inline data, url or file handle). */\nexport type AgUiContentPart =\n | { type: 'text'; text: string }\n | {\n type: 'image' | 'audio' | 'video' | 'document';\n source:\n | { type: 'data'; value: string; mimeType: string }\n | { type: 'url'; value: string; mimeType?: string }\n | { type: 'file'; value: string; provider?: string; mimeType?: string };\n metadata?: Record<string, unknown>;\n };\n\n/** The ids of an AG-UI run this consumer invented, when the send did not name a thread. */\nfunction newId(): string {\n return globalThis.crypto.randomUUID();\n}\n\nfunction isRecord(value: unknown): value is Record<string, unknown> {\n return typeof value === 'object' && value !== null && !Array.isArray(value);\n}\n\nasync function defaultRefusal(response: Response): Promise<Error> {\n try {\n const body = (await response.json()) as { message?: unknown };\n if (typeof body.message === 'string' && body.message.length > 0) return new Error(body.message);\n } catch {\n // not JSON: fall through to the status\n }\n return new Error(`The agent refused the request (${response.status}).`);\n}\n\nfunction defaultForwardedProps(body: Record<string, unknown>): unknown {\n const out: Record<string, unknown> = {};\n for (const key of ['pageContext', 'agent', 'model', 'persona', 'uiCapabilities']) {\n if (body[key] !== undefined && body[key] !== null) out[key] = body[key];\n }\n // Re-run the last exchange instead of appending one (`useAgentChat`'s regenerate).\n if (body.regenerate === true) out.regenerate = true;\n return Object.keys(out).length > 0 ? out : undefined;\n}\n\n/**\n * The `provider` that marks a `file` part's `value` as a mediaId staged with this library\n * (`AG_UI_MEDIA_PROVIDER` in `@dudousxd/nestjs-agent-core/ag-ui`).\n */\nconst MEDIA_PROVIDER = 'nestjs-agent';\n\nfunction partTypeFor(contentType: string | undefined): 'image' | 'audio' | 'video' | 'document' {\n const major = contentType?.split('/')[0]?.toLowerCase();\n return major === 'image' || major === 'audio' || major === 'video' ? major : 'document';\n}\n\n/** The message text, then one `file` part per staged attachment the send carries. */\nfunction defaultContent(\n body: Record<string, unknown>,\n message: string,\n): string | AgUiContentPart[] {\n const attachments = Array.isArray(body.attachments) ? body.attachments : [];\n const files: AgUiContentPart[] = [];\n for (const attachment of attachments) {\n if (!isRecord(attachment) || typeof attachment.mediaId !== 'string') continue;\n const contentType =\n typeof attachment.contentType === 'string' ? attachment.contentType : undefined;\n files.push({\n type: partTypeFor(contentType),\n source: {\n type: 'file',\n value: attachment.mediaId,\n provider: MEDIA_PROVIDER,\n ...(contentType !== undefined ? { mimeType: contentType } : {}),\n },\n });\n }\n if (files.length === 0) return message;\n return [...(message.length > 0 ? [{ type: 'text' as const, text: message }] : []), ...files];\n}\n\n/** Start a turn against an AG-UI producer; the stream comes back in this library's framing. */\nexport async function agUiChatStream(\n request: ChatStreamRequest,\n options: AgUiChatStreamOptions,\n): Promise<ChatStreamResponse> {\n const body = request.body;\n const threadId = typeof body.threadId === 'string' ? body.threadId : newId();\n const message = typeof body.message === 'string' ? body.message : '';\n const forwarded = (options.forwardedProps ?? defaultForwardedProps)(body);\n const input = {\n threadId,\n runId: newId(),\n protocolVersion: '1.0',\n messages: [\n {\n id: newId(),\n role: 'user',\n content: options.content?.(body) ?? defaultContent(body, message),\n },\n ],\n ...(forwarded !== undefined ? { forwardedProps: forwarded } : {}),\n };\n const doFetch = options.fetch ?? globalThis.fetch.bind(globalThis);\n const response = await doFetch(options.url, {\n method: 'POST',\n credentials: 'same-origin',\n headers: {\n 'content-type': 'application/json',\n accept: 'text/event-stream',\n ...options.headers,\n ...request.headers,\n },\n body: JSON.stringify(input),\n ...(request.signal !== undefined ? { signal: request.signal } : {}),\n });\n if (!response.ok || response.body === null) {\n throw await (options.refusal ?? defaultRefusal)(response);\n }\n const runId = response.headers.get('x-agent-run-id') ?? undefined;\n return {\n body: reframeAgUiStream(response.body, { threadId }),\n threadId,\n ...(runId !== undefined ? { runId } : {}),\n };\n}\n\ntype AgUiEvent = { type: string; [key: string]: unknown };\n\ninterface Reframer {\n /** The frames (already SSE-encoded) one AG-UI event stands for; `id` is its SSE `id:`, if any. */\n push(event: AgUiEvent, id?: number): string;\n /** What is still held back (a step's end waiting for its usage), at the end of the stream. */\n flush(): string;\n /** Set when the run ended; nothing is written after it. */\n closed: boolean;\n}\n\n/**\n * Re-frame an AG-UI event stream (SSE, one event per `data:`) in this library's stream protocol:\n * `event: meta`, `data:` frames of {@link AgentStreamEvent} (numbered with the run's own sequence\n * when the producer numbers its events), then `event: done` or `event: error`. Exported for a backend that fetches the stream itself.\n */\nexport function reframeAgUiStream(\n source: ReadableStream<Uint8Array>,\n ids: { threadId: string },\n): ReadableStream<Uint8Array> {\n const encoder = new TextEncoder();\n const decoder = new TextDecoder();\n const reframer = createReframer(ids.threadId);\n const reader = source.getReader();\n let buffer = '';\n return new ReadableStream<Uint8Array>({\n async pull(controller) {\n for (;;) {\n const { value, done } = await reader.read();\n if (done) {\n // A stream that stopped without a terminal event is a truncated run: end it plainly, and\n // the transport reads the stored thread for the rest.\n const rest = reframer.flush();\n if (rest.length > 0) controller.enqueue(encoder.encode(rest));\n controller.close();\n return;\n }\n buffer += decoder.decode(value, { stream: true }).replace(/\\r\\n?/g, '\\n');\n let out = '';\n let separator = buffer.indexOf('\\n\\n');\n while (separator !== -1) {\n const block = buffer.slice(0, separator);\n buffer = buffer.slice(separator + 2);\n separator = buffer.indexOf('\\n\\n');\n const lines = block.split('\\n');\n const idLine = lines.find((line) => line.startsWith('id:'));\n const id = idLine === undefined ? undefined : Number(idLine.slice(3).trim());\n const data = lines\n .filter((line) => line.startsWith('data:'))\n .map((line) => line.slice(5).trimStart())\n .join('\\n');\n if (data.length === 0) continue;\n let event: unknown;\n try {\n event = JSON.parse(data);\n } catch {\n continue;\n }\n if (isRecord(event) && typeof event.type === 'string') {\n out += reframer.push(\n event as AgUiEvent,\n id !== undefined && Number.isSafeInteger(id) && id > 0 ? id : undefined,\n );\n }\n if (reframer.closed) break;\n }\n if (out.length > 0) controller.enqueue(encoder.encode(out));\n if (reframer.closed) {\n void reader.cancel().catch(() => undefined);\n controller.close();\n return;\n }\n if (out.length > 0) return;\n }\n },\n cancel(reason) {\n return reader.cancel(reason).catch(() => undefined);\n },\n });\n}\n\nfunction createReframer(threadId: string): Reframer {\n const activities = new Map<string, { activityType: string; content: Record<string, unknown> }>();\n let metaSent = false;\n const tools = new Map<\n string,\n { name: string; args: string; toolKind: 'read' | 'action'; parentId?: string }\n >();\n /**\n * A step's end is held until the next event: a producer of this family follows `STEP_FINISHED`\n * with `agora.step-usage`, whose usage, cost and reasoning time belong on that `step-finish`.\n */\n let pendingStep: Record<string, unknown> | undefined;\n const encodeFrame = (streamEvent: AgentStreamEvent | Record<string, unknown>) =>\n `data: ${JSON.stringify(streamEvent)}\\n\\n`;\n const flushStep = (): string => {\n if (pendingStep === undefined) return '';\n const step = pendingStep;\n pendingStep = undefined;\n return encodeFrame(step);\n };\n /**\n * The run's sequence number of the events being read, and the last one written out as a cursor.\n * Several AG-UI events stand for one frame of the run, so the cursor (an `id:`-only SSE block the\n * transport records) moves only once every event of a frame was re-framed — re-attaching\n * `?after=` it then neither skips nor repeats anything.\n */\n let current: number | undefined;\n let written: number | undefined;\n const cursor = (): string => {\n if (current === undefined || current === written) return '';\n written = current;\n return `${flushStep()}id: ${current}\\n\\n`;\n };\n /** The tool calls whose approval or question set this stream already showed. */\n const shown = new Set<string>();\n /** An independent proposal decided with no run: written at the run's end, with its text. */\n let decision: { threadId: unknown; proposalDecision: unknown; text: string } | undefined;\n const state: Reframer = {\n closed: false,\n flush() {\n return state.closed ? '' : `${flushStep()}${cursor()}`;\n },\n push(event, id) {\n if (state.closed) return '';\n let out = '';\n if (id !== undefined) {\n if (current !== undefined && id > current) out += cursor();\n current = id;\n }\n const frame = (streamEvent: AgentStreamEvent | Record<string, unknown>) => {\n out += encodeFrame(streamEvent);\n };\n if (\n event.type === 'CUSTOM' &&\n event.name === 'agora.step-usage' &&\n pendingStep !== undefined &&\n isRecord(event.value)\n ) {\n const value = event.value;\n if (isRecord(value.usage)) pendingStep.usage = value.usage;\n if (typeof value.costUsd === 'number' || value.costUsd === null) {\n pendingStep.costUsd = value.costUsd;\n }\n if (typeof value.reasoningMs === 'number') pendingStep.reasoningMs = value.reasoningMs;\n out += flushStep();\n return out;\n }\n out += flushStep();\n const meta = (runId: unknown, thread: unknown) => {\n if (metaSent) return;\n metaSent = true;\n out += `event: meta\\ndata: ${JSON.stringify({\n runId: typeof runId === 'string' ? runId : '',\n threadId: typeof thread === 'string' ? thread : threadId,\n })}\\n\\n`;\n };\n switch (event.type) {\n case 'RUN_STARTED':\n // `agora.run` (next) names the library's own run; wait a beat for it only if it follows\n // at once — otherwise the protocol's own ids do.\n pendingStart = { runId: event.runId, threadId: event.threadId };\n return out;\n case 'CUSTOM': {\n const value = event.value;\n if (event.name === 'agora.run' && isRecord(value)) {\n meta(value.runId, pendingStart?.threadId ?? value.threadId);\n pendingStart = undefined;\n return out;\n }\n flushStart();\n if (!isRecord(value)) return out;\n if (event.name === 'agora.ui') frame({ kind: 'ui', ...value });\n else if (event.name === 'agora.title' && typeof value.title === 'string') {\n frame({ kind: 'title', title: value.title });\n } else if (event.name === 'agora.queue') frame({ kind: 'queue', ...value });\n else if (event.name === 'agora.approval-requested') {\n if (typeof value.id === 'string') shown.add(value.id);\n frame({ ...value, kind: 'approval-requested' });\n } else if (event.name === 'agora.approval-settled') {\n frame({ ...value, kind: 'approval-settled' });\n } else if (\n event.name === 'agora.elicitation' &&\n typeof value.id === 'string' &&\n isRecord(value.request) &&\n Array.isArray(value.request.questions)\n ) {\n // The question set the run parked on, under the tool-call id an answer settles.\n shown.add(value.id);\n if (typeof value.request.id === 'string') shown.add(value.request.id);\n frame({\n kind: 'elicitation',\n id: value.id,\n request: value.request as unknown as ElicitationRequest,\n });\n } else if (event.name === 'agora.action-proposal-decision') {\n decision = {\n threadId: value.threadId,\n proposalDecision: value.proposalDecision,\n text: '',\n };\n }\n return out;\n }\n default:\n flushStart();\n }\n switch (event.type) {\n case 'TEXT_MESSAGE_CONTENT':\n case 'TEXT_MESSAGE_CHUNK':\n if (decision !== undefined && typeof event.delta === 'string') {\n decision.text += event.delta;\n }\n if (typeof event.delta === 'string' && event.delta.length > 0) {\n frame({ kind: 'text', text: event.delta });\n }\n break;\n case 'REASONING_MESSAGE_CONTENT':\n case 'REASONING_MESSAGE_CHUNK':\n if (typeof event.delta === 'string' && event.delta.length > 0) {\n frame({ kind: 'reasoning', text: event.delta });\n }\n break;\n case 'STEP_STARTED':\n frame({ kind: 'step-start' });\n break;\n case 'STEP_FINISHED':\n pendingStep = { kind: 'step-finish' };\n break;\n case 'TOOL_CALL_START':\n case 'TOOL_CALL_CHUNK': {\n const id = String(event.toolCallId ?? '');\n if (id === '') break;\n if (!tools.has(id)) {\n const name = typeof event.toolCallName === 'string' ? event.toolCallName : '';\n const metadata = isRecord(event.metadata) ? event.metadata : {};\n // A producer of this family says whether the call is an action (it may wait for an\n // approval); a call nobody classified is read-only, as AG-UI has no notion of either.\n const toolKind = metadata['agora.toolKind'] === 'action' ? 'action' : 'read';\n const parentId =\n typeof metadata['agora.parentId'] === 'string'\n ? metadata['agora.parentId']\n : undefined;\n tools.set(id, {\n name,\n args: '',\n toolKind,\n ...(parentId !== undefined ? { parentId } : {}),\n });\n frame({\n kind: 'tool-input-start',\n id,\n name,\n toolKind,\n ...(parentId !== undefined ? { parentId } : {}),\n });\n }\n if (event.type === 'TOOL_CALL_CHUNK' && typeof event.delta === 'string') {\n (tools.get(id) as { args: string }).args += event.delta;\n frame({ kind: 'tool-input-delta', id, delta: event.delta });\n }\n break;\n }\n case 'TOOL_CALL_ARGS': {\n const call = tools.get(String(event.toolCallId));\n if (call === undefined || typeof event.delta !== 'string') break;\n call.args += event.delta;\n frame({ kind: 'tool-input-delta', id: String(event.toolCallId), delta: event.delta });\n break;\n }\n case 'TOOL_CALL_END': {\n const id = String(event.toolCallId);\n const call = tools.get(id);\n if (call === undefined) break;\n frame({\n kind: 'tool-input-available',\n id,\n name: call.name,\n input: parseJson(call.args, {}),\n toolKind: call.toolKind,\n ...(call.parentId !== undefined ? { parentId: call.parentId } : {}),\n });\n break;\n }\n case 'TOOL_CALL_RESULT': {\n const id = String(event.toolCallId);\n const content = contentText(event.content);\n const outcome = isRecord(event.metadata) ? event.metadata['agora.outcome'] : undefined;\n if (outcome === 'error') frame({ kind: 'tool-output-error', id, error: content });\n else if (outcome === 'denied') frame({ kind: 'tool-output-denied', id, reason: content });\n else frame({ kind: 'tool-output', id, output: parseJson(content, content) });\n break;\n }\n case 'ACTIVITY_SNAPSHOT':\n case 'ACTIVITY_DELTA': {\n const messageId = typeof event.messageId === 'string' ? event.messageId : '';\n if (messageId === '') break;\n const known = activities.get(messageId);\n const activityType =\n typeof event.activityType === 'string'\n ? event.activityType\n : (known?.activityType ?? '');\n let content: Record<string, unknown> | undefined;\n if (event.type === 'ACTIVITY_SNAPSHOT') {\n // `replace: false` leaves an existing activity as it stands\n if (known !== undefined && event.replace === false) break;\n content = isRecord(event.content) ? event.content : {};\n } else {\n // a delta for an activity nothing created is skipped, never fatal\n if (known === undefined || !Array.isArray(event.patch)) break;\n content = applyPatch(known.content, event.patch);\n if (content === undefined) break;\n }\n activities.set(messageId, { activityType, content });\n frame({\n kind: 'ui',\n id: `activity:${messageId}`,\n component: 'AgUiActivity',\n props: { activityType, content },\n });\n break;\n }\n case 'RUN_ERROR':\n state.closed = true;\n out += `event: error\\ndata: ${JSON.stringify({\n code: typeof event.code === 'string' ? event.code : 'run_failed',\n message: typeof event.message === 'string' ? event.message : 'The run failed.',\n })}\\n\\n`;\n break;\n case 'RUN_FINISHED': {\n const outcome = isRecord(event.outcome) ? event.outcome : undefined;\n if (decision !== undefined) {\n // What a native decision answers with: a `data-proposal-decision` part.\n frame({ kind: 'proposal-decision', ...decision });\n decision = undefined;\n }\n if (outcome?.type === 'cancelled') frame({ kind: 'cancelled' });\n if (outcome?.type === 'interrupt' && Array.isArray(outcome.interrupts)) {\n const unseen = outcome.interrupts.filter((interrupt) => !isShown(interrupt, shown));\n if (unseen.length === 0) {\n // Parked on what this stream already showed: not over. End without `done`, at the\n // cursor, so the transport re-attaches and follows the rest of the run.\n out += cursor();\n state.closed = true;\n break;\n }\n frame({\n kind: 'ui',\n id: `ag-ui:interrupt:${String(event.runId ?? '')}`,\n component: 'AgUiInterrupt',\n props: { interrupts: unseen },\n });\n }\n out += cursor();\n state.closed = true;\n out += 'event: done\\ndata: {}\\n\\n';\n break;\n }\n default:\n // Everything else (message and span brackets, state, activity, raw) carries nothing this\n // framing does not already say.\n break;\n }\n return out;\n\n function flushStart() {\n if (pendingStart !== undefined) {\n meta(pendingStart.runId, pendingStart.threadId);\n pendingStart = undefined;\n }\n }\n },\n };\n let pendingStart: { runId: unknown; threadId: unknown } | undefined;\n return state;\n}\n\n/** Did the stream already show what this interrupt asks — an approval card or a question form? */\nfunction isShown(interrupt: unknown, shown: ReadonlySet<string>): boolean {\n if (!isRecord(interrupt)) return false;\n if (typeof interrupt.toolCallId === 'string' && shown.has(interrupt.toolCallId)) return true;\n const metadata = isRecord(interrupt.metadata) ? interrupt.metadata : undefined;\n const request = isRecord(metadata?.['agora.request']) ? metadata['agora.request'] : undefined;\n return typeof request?.id === 'string' && shown.has(request.id);\n}\n\nfunction parseJson(text: string, fallback: unknown): unknown {\n if (text.trim().length === 0) return fallback;\n try {\n return JSON.parse(text) as unknown;\n } catch {\n return fallback;\n }\n}\n\n/** A result's content as text: a string, or its text parts in order (other parts carry no text). */\nfunction contentText(content: unknown): string {\n if (typeof content === 'string') return content;\n if (!Array.isArray(content)) return '';\n return content\n .filter((part) => isRecord(part) && part.type === 'text' && typeof part.text === 'string')\n .map((part) => (part as { text: string }).text)\n .join('');\n}\n\n/**\n * RFC 6902 on a copy: `add`, `replace`, `remove` (and `test`, which fails the patch). `undefined`\n * when the patch does not apply — the activity then keeps its last good content until a snapshot.\n */\nfunction applyPatch(\n target: Record<string, unknown>,\n patch: unknown[],\n): Record<string, unknown> | undefined {\n const doc = structuredClone(target) as Record<string, unknown>;\n for (const operation of patch) {\n if (!isRecord(operation) || typeof operation.path !== 'string') return undefined;\n const tokens = operation.path\n .split('/')\n .slice(1)\n .map((token) => token.replace(/~1/g, '/').replace(/~0/g, '~'));\n const key = tokens.pop();\n if (key === undefined) return undefined;\n let parent: unknown = doc;\n for (const token of tokens) {\n parent = Array.isArray(parent)\n ? parent[Number(token)]\n : isRecord(parent)\n ? parent[token]\n : undefined;\n if (parent === undefined) return undefined;\n }\n if (Array.isArray(parent)) {\n const index = key === '-' ? parent.length : Number(key);\n if (!Number.isInteger(index) || index < 0 || index > parent.length) return undefined;\n if (operation.op === 'add') parent.splice(index, 0, operation.value);\n else if (operation.op === 'replace' && index < parent.length) parent[index] = operation.value;\n else if (operation.op === 'remove' && index < parent.length) parent.splice(index, 1);\n else if (operation.op === 'test') {\n if (JSON.stringify(parent[index]) !== JSON.stringify(operation.value)) return undefined;\n } else return undefined;\n } else if (isRecord(parent)) {\n if (operation.op === 'add' || (operation.op === 'replace' && key in parent)) {\n parent[key] = operation.value;\n } else if (operation.op === 'remove' && key in parent) delete parent[key];\n else if (operation.op === 'test') {\n if (JSON.stringify(parent[key]) !== JSON.stringify(operation.value)) return undefined;\n } else return undefined;\n } else return undefined;\n }\n return doc;\n}\n","import type { AgentCatalogEntry, PersonaCatalogEntry } from '@dudousxd/nestjs-agent-core';\nimport { useCallback, useMemo } from 'react';\nimport { type AgentBackend, requireBackendMethod } from '../backend.js';\nimport { useAgentBackend } from '../provider.js';\nimport { useResource } from './use-resource.js';\n\nexport interface UseAgentsOptions {\n /** Default: the enclosing `<AgentProvider>`'s. Must implement `listAgents`. */\n backend?: AgentBackend;\n /** `false` holds the request. Default `true`. */\n enabled?: boolean;\n}\n\nexport interface AgentsState {\n /** `[]` until loaded. */\n agents: AgentCatalogEntry[];\n /** The agent a turn runs as when none is named. */\n defaultAgent: string | null;\n /**\n * An agent's personas — the data behind a persona picker. `agent` omitted → the default agent's.\n * `[]` for an agent that declares none (or before the list loads).\n */\n personasOf: (agent?: string) => PersonaCatalogEntry[];\n /** The persona `agent` (default: the default agent) runs under when a send names none, or `null`. */\n defaultPersonaOf: (agent?: string) => string | null;\n isLoading: boolean;\n error: Error | null;\n refresh: () => Promise<void>;\n}\n\n/**\n * The registered agents (`GET <base>/agents`) — the data behind an agent picker, and each agent's\n * personas behind a persona picker. Send the pick as `useAgentChat({ agent, persona })`, or pin it on\n * a thread with `PATCH <base>/threads/:id { defaultAgent, persona }`.\n */\nexport function useAgents(options: UseAgentsOptions = {}): AgentsState {\n const { enabled = true } = options;\n const backend = useAgentBackend(options.backend);\n const { data, isLoading, error, refresh } = useResource<AgentCatalogEntry[]>(\n () => requireBackendMethod(backend, 'listAgents')(),\n '',\n enabled,\n );\n const find = useCallback(\n (name?: string): AgentCatalogEntry | undefined =>\n (data ?? []).find((agent) =>\n name === undefined ? agent.isDefault === true : agent.name === name,\n ),\n [data],\n );\n return useMemo(() => {\n const agents = data ?? [];\n return {\n agents,\n defaultAgent: agents.find((agent) => agent.isDefault === true)?.name ?? null,\n personasOf: (agent?: string) => find(agent)?.personas ?? [],\n defaultPersonaOf: (agent?: string) => find(agent)?.defaultPersona ?? null,\n isLoading,\n error,\n refresh,\n };\n }, [data, find, isLoading, error, refresh]);\n}\n","import { useCallback, useEffect, useRef, useState } from 'react';\n\nexport interface ResourceState<T> {\n data: T | undefined;\n isLoading: boolean;\n error: Error | null;\n refresh: () => Promise<void>;\n}\n\n/**\n * One read, re-run when `key` changes, with only the newest response allowed to land. The shared\n * shape behind `useModels` / `useAgents`.\n */\nexport function useResource<T>(\n load: () => Promise<T>,\n key: string,\n enabled: boolean,\n): ResourceState<T> {\n const [data, setData] = useState<T | undefined>(undefined);\n const [isLoading, setIsLoading] = useState(enabled);\n const [error, setError] = useState<Error | null>(null);\n const loadRef = useRef(load);\n loadRef.current = load;\n const generation = useRef(0);\n\n const refresh = useCallback(async (): Promise<void> => {\n const mine = ++generation.current;\n setIsLoading(true);\n try {\n const value = await loadRef.current();\n if (mine !== generation.current) return;\n setData(value);\n setError(null);\n } catch (caught) {\n if (mine !== generation.current) return;\n setError(caught instanceof Error ? caught : new Error(String(caught)));\n } finally {\n if (mine === generation.current) setIsLoading(false);\n }\n }, []);\n\n // biome-ignore lint/correctness/useExhaustiveDependencies: `key` names what `load` reads\n useEffect(() => {\n if (!enabled) return;\n void refresh();\n }, [enabled, key, refresh]);\n\n return { data, isLoading, error, refresh };\n}\n","import type {\n ModelCatalogEntry,\n ModelCatalogLock,\n ModelCatalogView,\n} from '@dudousxd/nestjs-agent-core';\nimport { useMemo } from 'react';\nimport { type AgentBackend, requireBackendMethod } from '../backend.js';\nimport { useAgentBackend } from '../provider.js';\nimport { useResource } from './use-resource.js';\n\nexport interface UseModelsOptions {\n /** Default: the enclosing `<AgentProvider>`'s. Must implement `listModels`. */\n backend?: AgentBackend;\n /** The agent to list models for; omitted → the default agent. */\n agent?: string;\n /** `false` holds the request. Default `true`. */\n enabled?: boolean;\n}\n\n/** A catalog entry with the provider it sits under, for a flat list or a search. */\nexport interface ModelOption extends ModelCatalogEntry {\n providerId: string;\n providerLabel: string;\n}\n\nexport interface ModelsState {\n /** Grouped as the server sent them. `[]` until loaded. */\n providers: ModelCatalogView['providers'];\n /** Every model, flattened in provider order. */\n models: ModelOption[];\n /** The model a turn runs on when none is picked, or `null` when the provider decides. */\n defaultModel: string | null;\n /**\n * The agent always runs on one model (`{ model, reason? }`), or `null`. A picker shows it\n * read-only: the server runs every turn on it and refuses any other.\n */\n locked: ModelCatalogLock | null;\n /** The entry for `id`, or `undefined`. */\n find: (id: string | null | undefined) => ModelOption | undefined;\n isLoading: boolean;\n error: Error | null;\n refresh: () => Promise<void>;\n}\n\n/**\n * The models this caller may pick (`GET <base>/models?agent=`), with badges and availability — the\n * data behind a model picker. Headless: render the options however you like, then send the pick\n * as `useAgentChat({ model })` or `sendMessage(msg, { body: { model } })` (that turn only), or\n * pin it on the thread with `chat.models.pinToThread(id)`.\n */\nexport function useModels(options: UseModelsOptions = {}): ModelsState {\n const { agent, enabled = true } = options;\n const backend = useAgentBackend(options.backend);\n const { data, isLoading, error, refresh } = useResource<ModelCatalogView>(\n () => requireBackendMethod(backend, 'listModels')(agent),\n `${agent ?? ''}`,\n enabled,\n );\n return useMemo(() => {\n const providers = data?.providers ?? [];\n const models = providers.flatMap((provider) =>\n provider.models.map((model) => ({\n ...model,\n providerId: provider.id,\n providerLabel: provider.label,\n })),\n );\n const byId = new Map(models.map((model) => [model.id, model]));\n return {\n providers,\n models,\n defaultModel: data?.default ?? null,\n locked: data?.locked ?? null,\n find: (id) => (id == null ? undefined : byId.get(id)),\n isLoading,\n error,\n refresh,\n };\n }, [data, isLoading, error, refresh]);\n}\n","import {\n type QuotaBlock,\n type QuotaReport,\n type QuotaWarning,\n type QuotaWindow,\n quotaWarning,\n} from '@dudousxd/nestjs-agent-core';\nimport { useEffect, useMemo } from 'react';\nimport { type AgentBackend, requireBackendMethod } from '../backend.js';\nimport { useResource } from '../catalog/use-resource.js';\nimport { useAgentBackend } from '../provider.js';\nimport { onThreadsEvent } from '../threads/threads-events.js';\n\nexport interface UseQuotaOptions {\n /** Default: the enclosing `<AgentProvider>`'s. Must implement `getQuota`. */\n backend?: AgentBackend;\n /** `false` holds the request. Default `true`. */\n enabled?: boolean;\n /** Re-read every `pollMs` ms as well. Default: only on mount, after runs, and on `refresh`. */\n pollMs?: number;\n}\n\nexport interface QuotaState {\n /** The full report, once loaded. */\n report: QuotaReport | undefined;\n windows: QuotaWindow[];\n /** The `day` / `month` windows, when the server reports them. */\n day: QuotaWindow | undefined;\n month: QuotaWindow | undefined;\n /** The window that blocks sends, or `null` — pass it to `useAgentChat({ blocked })`. */\n blocked: QuotaBlock | null;\n /**\n * The soft limit: the fullest window past its `warnAt` (`{ period, ratio, reason? }`), or `null`.\n * The server's `warning`, else derived from the windows; never set while `blocked`.\n */\n warning: QuotaWarning | null;\n isLoading: boolean;\n error: Error | null;\n refresh: () => Promise<void>;\n}\n\n/**\n * The caller's budget (`GET <base>/quota`): every window's usage against its ceilings, and which\n * one — if any — blocks sends. Re-read after every run a chat on the same backend settles, so a\n * meter moves with the conversation. Headless: draw the meter yourself.\n */\nexport function useQuota(options: UseQuotaOptions = {}): QuotaState {\n const { enabled = true, pollMs } = options;\n const backend = useAgentBackend(options.backend);\n const { data, isLoading, error, refresh } = useResource<QuotaReport>(\n () => requireBackendMethod(backend, 'getQuota')(),\n '',\n enabled,\n );\n\n useEffect(() => {\n if (!enabled) return;\n return onThreadsEvent(backend, (event) => {\n if (event.type === 'changed') void refresh();\n });\n }, [backend, enabled, refresh]);\n\n useEffect(() => {\n if (!enabled || pollMs === undefined || pollMs <= 0) return;\n const timer = setInterval(() => void refresh(), pollMs);\n return () => clearInterval(timer);\n }, [enabled, pollMs, refresh]);\n\n return useMemo(() => {\n const windows = data?.windows ?? [];\n return {\n report: data,\n windows,\n day: windows.find((window) => window.period === 'day'),\n month: windows.find((window) => window.period === 'month'),\n blocked: data?.blocked ?? null,\n warning:\n data === undefined || data.blocked !== undefined\n ? null\n : (data.warning ?? quotaWarning(windows) ?? null),\n isLoading,\n error,\n refresh,\n };\n }, [data, isLoading, error, refresh]);\n}\n","import type { AgentBackend } from '../backend.js';\n\n/**\n * What changed about a backend's thread list. `changed` → refetch (a thread was created, or a run\n * settled and the server wrote its title); `title` → the stream announced a title, patch in place.\n */\nexport type ThreadsEvent =\n | { type: 'changed' }\n | { type: 'title'; threadId: string; title: string }\n | { type: 'removed'; threadId: string };\n\ntype Listener = (event: ThreadsEvent) => void;\n\n// Keyed by backend so two chats on two servers never refresh each other's sidebars.\nconst listeners = new WeakMap<AgentBackend, Set<Listener>>();\n\n/** Tell every {@link useThreads} on `backend` that its list moved. */\nexport function notifyThreads(backend: AgentBackend, event: ThreadsEvent): void {\n for (const listener of listeners.get(backend) ?? []) {\n listener(event);\n }\n}\n\n/** Subscribe to {@link notifyThreads} for `backend`; returns the unsubscribe. */\nexport function onThreadsEvent(backend: AgentBackend, listener: Listener): () => void {\n let set = listeners.get(backend);\n if (set === undefined) {\n set = new Set();\n listeners.set(backend, set);\n }\n set.add(listener);\n return () => {\n set.delete(listener);\n };\n}\n","import type { MessageFeedback, MessageFeedbackValue } from '@dudousxd/nestjs-agent-core';\nimport type { UIMessage } from 'ai';\nimport { useCallback, useRef, useState } from 'react';\nimport { type AgentBackend, requireBackendMethod } from '../backend.js';\nimport { useAgentBackend } from '../provider.js';\nimport type { AgentMessageMetadata } from '../stored-thread-to-ui-messages.js';\n\nexport interface UseMessageFeedbackOptions {\n /** Default: the enclosing `<AgentProvider>`'s. Must implement `setMessageFeedback`. */\n backend?: AgentBackend;\n /**\n * The thread the messages belong to — `useAgentChat(...).getThreadId`, or an id. Needed to rate a\n * message streamed in this session: its id is the client's own, so the persisted row it became is\n * looked up by the run that wrote it.\n */\n threadId?: string | (() => string | undefined);\n}\n\nexport interface MessageFeedbackState {\n /** The rating to show: the one set in this session, else the persisted one, else `null`. */\n feedbackOf: (message: UIMessage) => MessageFeedback | null;\n /** A rating for this message is on its way to the server. */\n isPending: (message: UIMessage) => boolean;\n /** Set `'up'`/`'down'` (optionally with a comment), or clear with `null`. Optimistic. */\n rate: (message: UIMessage, value: MessageFeedbackValue | null, comment?: string) => Promise<void>;\n /** Thumbs-button semantics: the same value again clears it, another value replaces it. */\n toggle: (message: UIMessage, value: MessageFeedbackValue) => Promise<void>;\n /** The last failure; cleared by the next successful rating. */\n error: Error | null;\n}\n\ntype Local = { feedback: MessageFeedback | null };\n\n/**\n * Thumbs-up/down (+ comment) on assistant messages, over `POST <base>/messages/:id/feedback`.\n * Headless: it holds the state and the calls, the host draws the buttons. A rating shows at once\n * and rolls back if the server refuses it.\n */\nexport function useMessageFeedback(options: UseMessageFeedbackOptions = {}): MessageFeedbackState {\n const backend = useAgentBackend(options.backend);\n const latest = useRef({ ...options, backend });\n latest.current = { ...options, backend };\n const [local, setLocal] = useState<ReadonlyMap<string, Local>>(new Map());\n const [pending, setPending] = useState<ReadonlySet<string>>(new Set());\n const [error, setError] = useState<Error | null>(null);\n const localRef = useRef(local);\n localRef.current = local;\n // Live message id → the persisted row it resolved to, so a message is looked up once.\n const resolved = useRef(new Map<string, string>());\n\n const feedbackOf = useCallback(\n (message: UIMessage): MessageFeedback | null => {\n const mine = local.get(message.id);\n if (mine !== undefined) return mine.feedback;\n return metadataOf(message).feedback ?? null;\n },\n [local],\n );\n\n const isPending = useCallback((message: UIMessage) => pending.has(message.id), [pending]);\n\n const storedIdFor = useCallback(async (message: UIMessage): Promise<string> => {\n const runId = metadataOf(message).runId;\n if (runId === undefined) return message.id;\n const known = resolved.current.get(message.id);\n if (known !== undefined) return known;\n const { backend, threadId } = latest.current;\n const thread = typeof threadId === 'function' ? threadId() : threadId;\n if (thread === undefined) {\n throw new Error('useMessageFeedback: a streamed message needs `threadId` to be rated');\n }\n const detail = await backend.getThread(thread);\n const row = [...detail.messages]\n .reverse()\n .find((candidate) => candidate.role === 'assistant' && candidate.runId === runId);\n if (row === undefined) {\n throw new Error(`useMessageFeedback: run ${runId} has no persisted answer yet`);\n }\n resolved.current.set(message.id, row.id);\n return row.id;\n }, []);\n\n const rate = useCallback(\n async (message: UIMessage, value: MessageFeedbackValue | null, comment?: string) => {\n const setFeedback = requireBackendMethod(latest.current.backend, 'setMessageFeedback');\n const had = localRef.current.get(message.id);\n const optimistic: MessageFeedback | null =\n value === null\n ? null\n : {\n value,\n ...(comment !== undefined && comment.trim().length > 0\n ? { comment: comment.trim() }\n : {}),\n updatedAt: new Date().toISOString(),\n };\n setLocal((current) => new Map(current).set(message.id, { feedback: optimistic }));\n setPending((current) => new Set(current).add(message.id));\n try {\n const storedId = await storedIdFor(message);\n const { feedback } = await setFeedback(storedId, {\n value,\n ...(comment !== undefined ? { comment } : {}),\n });\n setLocal((current) => new Map(current).set(message.id, { feedback }));\n setError(null);\n } catch (caught) {\n setLocal((current) => {\n const next = new Map(current);\n if (had === undefined) next.delete(message.id);\n else next.set(message.id, had);\n return next;\n });\n const failure = caught instanceof Error ? caught : new Error(String(caught));\n setError(failure);\n throw failure;\n } finally {\n setPending((current) => {\n const next = new Set(current);\n next.delete(message.id);\n return next;\n });\n }\n },\n [storedIdFor],\n );\n\n const toggle = useCallback(\n (message: UIMessage, value: MessageFeedbackValue) => {\n const mine = localRef.current.get(message.id);\n const current = mine !== undefined ? mine.feedback : (metadataOf(message).feedback ?? null);\n return rate(message, current?.value === value ? null : value);\n },\n [rate],\n );\n\n return { feedbackOf, isPending, rate, toggle, error };\n}\n\nfunction metadataOf(message: UIMessage): AgentMessageMetadata {\n const metadata = message.metadata;\n return metadata !== null && typeof metadata === 'object'\n ? (metadata as AgentMessageMetadata)\n : {};\n}\n","import type { ThreadSummary } from '@dudousxd/nestjs-agent-core';\nimport { useCallback, useEffect, useRef, useState } from 'react';\nimport type { AgentBackend } from '../backend.js';\nimport { useAgentBackend } from '../provider.js';\nimport { notifyThreads, onThreadsEvent } from './threads-events.js';\n\nexport interface UseThreadsOptions {\n /**\n * The backend to list. Default: the enclosing `<AgentProvider>`'s. Must be STABLE across renders:\n * the list refreshes itself when a chat on the SAME backend creates a thread, settles a run or\n * streams a title.\n */\n backend?: AgentBackend;\n /** `false` holds the first request (e.g. until the user is signed in). Default `true`. */\n enabled?: boolean;\n}\n\nexport interface ThreadsState {\n /** Newest first, as the server orders them. `[]` until loaded. */\n threads: ThreadSummary[];\n isLoading: boolean;\n error: Error | null;\n /** Ask the server again. */\n refresh: () => Promise<void>;\n /** Rename on the server; the list shows the new title at once and rolls back on failure. */\n rename: (id: string, title: string) => Promise<void>;\n /** Delete on the server; the thread leaves the list at once and comes back on failure. */\n remove: (id: string) => Promise<void>;\n}\n\n/**\n * The actor's conversations, kept current without the host wiring refetches: a chat on the same\n * backend reports thread creation and settled runs (refetch) and streamed titles (patched in\n * place). Headless — it renders nothing.\n */\nexport function useThreads(options: UseThreadsOptions = {}): ThreadsState {\n const { enabled = true } = options;\n const backend = useAgentBackend(options.backend);\n const [threads, setThreads] = useState<ThreadSummary[]>([]);\n const [isLoading, setIsLoading] = useState(enabled);\n const [error, setError] = useState<Error | null>(null);\n const threadsRef = useRef(threads);\n threadsRef.current = threads;\n // Only the newest request may write: a slow response must not overwrite a newer one.\n const generation = useRef(0);\n\n const refresh = useCallback(async (): Promise<void> => {\n const mine = ++generation.current;\n setIsLoading(true);\n try {\n const list = await backend.listThreads();\n if (mine !== generation.current) return;\n setThreads(list);\n setError(null);\n } catch (caught) {\n if (mine !== generation.current) return;\n setError(caught instanceof Error ? caught : new Error(String(caught)));\n } finally {\n if (mine === generation.current) setIsLoading(false);\n }\n }, [backend]);\n\n useEffect(() => {\n if (!enabled) return;\n void refresh();\n return onThreadsEvent(backend, (event) => {\n if (event.type === 'title') {\n setThreads((current) =>\n current.map((thread) =>\n thread.id === event.threadId ? { ...thread, title: event.title } : thread,\n ),\n );\n } else if (event.type === 'removed') {\n setThreads((current) => current.filter((thread) => thread.id !== event.threadId));\n } else {\n void refresh();\n }\n });\n }, [backend, enabled, refresh]);\n\n const rename = useCallback(\n async (id: string, title: string): Promise<void> => {\n const before = threadsRef.current;\n setThreads((current) =>\n current.map((thread) => (thread.id === id ? { ...thread, title } : thread)),\n );\n try {\n await backend.updateThread(id, { title });\n notifyThreads(backend, { type: 'title', threadId: id, title });\n } catch (caught) {\n setThreads(before);\n throw caught;\n }\n },\n [backend],\n );\n\n const remove = useCallback(\n async (id: string): Promise<void> => {\n const before = threadsRef.current;\n setThreads((current) => current.filter((thread) => thread.id !== id));\n try {\n await backend.deleteThread(id);\n notifyThreads(backend, { type: 'removed', threadId: id });\n } catch (caught) {\n setThreads(before);\n throw caught;\n }\n },\n [backend],\n );\n\n return { threads, isLoading, error, refresh, rename, remove };\n}\n","import type { StoredMessage } from '@dudousxd/nestjs-agent-core';\n\n/**\n * A sub-agent the conversation started and did not wait for. The chat is free while it works, so a\n * client has to be able to say what is still running and to show the answer when it lands — neither\n * of which the turn that started it can report, because that turn is over.\n */\nexport interface BackgroundRun {\n /** The run doing the work. Also what stamps the message it eventually posts. */\n runId: string;\n /** The agent working on it. */\n agent: string;\n /** The `agent`-kind call that started it — what a UI keys its card off. */\n toolCallId: string;\n toolName: string;\n /**\n * `delivered` the moment the thread holds a message stamped with this run. A run that FAILED\n * reads as delivered too: it posts a message saying so, which is the point — there is no third\n * state a reader could act on differently, and \"running\" for ever is the state to avoid.\n */\n status: 'running' | 'delivered';\n /** The message it posted, once it did. */\n message?: StoredMessage;\n}\n\n/** A detached delegation's receipt, as it appears in a message's `toolResults`. */\ninterface Receipt {\n detached: true;\n status: 'started';\n agent: string;\n runId: string;\n}\n\nfunction asReceipt(output: unknown): Receipt | null {\n if (typeof output !== 'object' || output === null) {\n return null;\n }\n const candidate = output as Partial<Receipt>;\n if (\n candidate.detached !== true ||\n candidate.status !== 'started' ||\n typeof candidate.agent !== 'string' ||\n typeof candidate.runId !== 'string'\n ) {\n return null;\n }\n return { detached: true, status: 'started', agent: candidate.agent, runId: candidate.runId };\n}\n\n/**\n * Every sub-agent this thread started in the background, and whether each has reported back.\n *\n * Derived from the transcript rather than tracked in session state, so it survives a reload and a\n * second tab: the receipt is a persisted tool result, and the answer is a persisted message stamped\n * with the run that wrote it. Nothing here needs a live connection to be true.\n */\nexport function backgroundRunsFromThread(messages: readonly StoredMessage[]): BackgroundRun[] {\n const byRun = new Map<string, BackgroundRun>();\n for (const message of messages) {\n for (const result of message.toolResults ?? []) {\n const receipt = asReceipt(result.output);\n if (receipt === null || byRun.has(receipt.runId)) {\n continue;\n }\n byRun.set(receipt.runId, {\n runId: receipt.runId,\n agent: receipt.agent,\n toolCallId: result.id,\n toolName: result.name,\n status: 'running',\n });\n }\n }\n for (const message of messages) {\n const run = message.runId === undefined ? undefined : byRun.get(message.runId);\n if (run !== undefined) {\n run.status = 'delivered';\n run.message = message;\n }\n }\n return [...byRun.values()];\n}\n","import React, { useEffect, useState } from 'react';\nimport { useSpeechRecognition } from './use-speech-recognition.js';\n\nexport interface ChatInputProps {\n onSubmit: (text: string) => void;\n disabled?: boolean;\n placeholder?: string;\n rows?: number;\n /** Enable the dictation mic button (Web Speech API). Default `true`. */\n enableSpeech?: boolean;\n /** BCP-47 locale for dictation. Default `en-US`. */\n speechLang?: string;\n /** Label/content for the send button. Default `\"Send\"`. */\n sendLabel?: React.ReactNode;\n /**\n * Cancel the turn in flight — wire to `useAgentChat`'s `cancel`. Rendered only alongside\n * `isStreaming`, so the affordance exists exactly while there is something to cancel.\n */\n onStop?: () => void | Promise<void>;\n /** Whether a turn is currently in flight. Gates the stop affordance. */\n isStreaming?: boolean;\n /** Label/content for the stop button. Default `\"Stop generating\"` — the mic's own is `\"Stop\"`. */\n stopLabel?: React.ReactNode;\n /** Wrapper class. The component ships no styles of its own. */\n className?: string;\n textareaClassName?: string;\n sendButtonClassName?: string;\n micButtonClassName?: string;\n stopButtonClassName?: string;\n /**\n * Custom mic affordance. Receives `isListening`; return any node. When\n * omitted a plain text button (\"Speak\" / \"Stop\") is rendered.\n */\n renderMic?: (state: { isListening: boolean }) => React.ReactNode;\n}\n\n/**\n * Styling-agnostic chat composer. Enter submits, Shift+Enter inserts a\n * newline. Optional dictation streams interim transcripts into the draft\n * and commits finalized chunks, and `onStop` surfaces the backend's\n * cancel next to send. No design-system or icon-library deps —\n * style it entirely through the `*ClassName` props.\n */\nexport function ChatInput({\n onSubmit,\n disabled,\n placeholder,\n rows = 2,\n enableSpeech = true,\n speechLang = 'en-US',\n sendLabel = 'Send',\n onStop,\n isStreaming = false,\n stopLabel = 'Stop generating',\n className,\n textareaClassName,\n sendButtonClassName,\n micButtonClassName,\n stopButtonClassName,\n renderMic,\n}: ChatInputProps) {\n const [value, setValue] = useState('');\n // Interim dictation transcript shown appended to the draft until the\n // engine finalizes it — kept out of `value` so editing the rest of the\n // text doesn't persist a partial guess.\n const [interim, setInterim] = useState('');\n\n const speech = useSpeechRecognition({\n lang: speechLang,\n onFinalTranscript: (text) => {\n const trimmed = text.trim();\n if (!trimmed) return;\n setValue((prev) => (prev.length === 0 ? trimmed : `${prev.trimEnd()} ${trimmed}`));\n setInterim('');\n },\n onInterimTranscript: (text) => setInterim(text),\n });\n\n useEffect(() => {\n if (!speech.isListening) setInterim('');\n }, [speech.isListening]);\n\n function submit() {\n const trimmed = value.trim();\n if (!trimmed) return;\n onSubmit(trimmed);\n setValue('');\n setInterim('');\n }\n\n function handleKeyDown(event: React.KeyboardEvent<HTMLTextAreaElement>) {\n if (event.key === 'Enter' && !event.shiftKey) {\n event.preventDefault();\n submit();\n }\n }\n\n function toggleMic() {\n if (speech.isListening) speech.stop();\n else speech.start();\n }\n\n const displayValue =\n speech.isListening && interim\n ? `${value}${value && !value.endsWith(' ') ? ' ' : ''}${interim}`\n : value;\n\n const showMic = enableSpeech && speech.isSupported;\n const showStop = isStreaming && onStop !== undefined;\n\n return (\n <div className={className}>\n <textarea\n className={textareaClassName}\n rows={rows}\n value={displayValue}\n disabled={disabled}\n onChange={(event) => {\n // Ignore changes while interim text is injected — the engine\n // overwrites it on the next result. Editing works when idle.\n if (speech.isListening && interim) return;\n setValue(event.target.value);\n }}\n onKeyDown={handleKeyDown}\n placeholder={placeholder ?? 'Ask something (Enter to send, Shift+Enter for newline)'}\n />\n <button\n type=\"button\"\n className={sendButtonClassName}\n onClick={submit}\n disabled={disabled || !value.trim()}\n >\n {sendLabel}\n </button>\n {showStop ? (\n <button\n type=\"button\"\n className={stopButtonClassName}\n onClick={() => void onStop()}\n aria-label=\"Stop generating\"\n >\n {stopLabel}\n </button>\n ) : null}\n {showMic ? (\n <button\n type=\"button\"\n className={micButtonClassName}\n onClick={toggleMic}\n disabled={disabled}\n aria-label={speech.isListening ? 'Stop dictating' : 'Start dictating'}\n >\n {renderMic\n ? renderMic({ isListening: speech.isListening })\n : speech.isListening\n ? 'Stop'\n : 'Speak'}\n </button>\n ) : null}\n </div>\n );\n}\n","import { useCallback, useEffect, useMemo, useRef, useState } from 'react';\n\n/**\n * Minimal subset of the Web Speech API we use. The real types live\n * behind `webkit*` prefixes in some browsers and aren't in TS lib.dom,\n * so we declare just what we need.\n */\ninterface SpeechResultAlternative {\n transcript: string;\n}\ninterface SpeechRecognitionResult {\n readonly length: number;\n readonly isFinal: boolean;\n item(index: number): SpeechResultAlternative;\n [index: number]: SpeechResultAlternative;\n}\ninterface SpeechRecognitionResultList {\n readonly length: number;\n item(index: number): SpeechRecognitionResult;\n [index: number]: SpeechRecognitionResult;\n}\ninterface SpeechRecognitionEvent {\n results: SpeechRecognitionResultList;\n resultIndex: number;\n}\ninterface SpeechRecognitionErrorEvent {\n error: string;\n}\ninterface SpeechRecognitionInstance {\n lang: string;\n continuous: boolean;\n interimResults: boolean;\n onresult: ((event: SpeechRecognitionEvent) => void) | null;\n onerror: ((event: SpeechRecognitionErrorEvent) => void) | null;\n onend: (() => void) | null;\n start(): void;\n stop(): void;\n}\ntype SpeechRecognitionCtor = new () => SpeechRecognitionInstance;\n\nfunction getRecognitionCtor(): SpeechRecognitionCtor | null {\n if (typeof window === 'undefined') return null;\n const scope = window as unknown as {\n SpeechRecognition?: SpeechRecognitionCtor;\n webkitSpeechRecognition?: SpeechRecognitionCtor;\n };\n return scope.SpeechRecognition ?? scope.webkitSpeechRecognition ?? null;\n}\n\nexport interface UseSpeechRecognitionOptions {\n lang?: string;\n onFinalTranscript: (text: string) => void;\n onInterimTranscript?: (text: string) => void;\n}\n\nexport interface SpeechRecognitionHook {\n isSupported: boolean;\n isListening: boolean;\n start(): void;\n stop(): void;\n}\n\n/**\n * Tiny wrapper around the Web Speech API. `start()` opens the mic and\n * streams interim transcripts via `onInterimTranscript`; on a finalized\n * chunk it fires `onFinalTranscript`. `isSupported` is false where the\n * API is missing (e.g. Firefox) — callers should hide the mic button.\n */\nexport function useSpeechRecognition({\n lang = 'en-US',\n onFinalTranscript,\n onInterimTranscript,\n}: UseSpeechRecognitionOptions): SpeechRecognitionHook {\n const recognitionRef = useRef<SpeechRecognitionInstance | null>(null);\n const [isListening, setIsListening] = useState(false);\n\n const ctor = useMemo(() => getRecognitionCtor(), []);\n const isSupported = ctor !== null;\n\n // Keep latest callbacks in refs so we don't tear down the recognition\n // object when they change identity each render.\n const finalRef = useRef(onFinalTranscript);\n const interimRef = useRef(onInterimTranscript);\n finalRef.current = onFinalTranscript;\n interimRef.current = onInterimTranscript;\n\n useEffect(() => {\n if (!ctor) return;\n const recognition = new ctor();\n recognition.lang = lang;\n recognition.continuous = false;\n recognition.interimResults = true;\n\n recognition.onresult = (event) => {\n let interim = '';\n for (let i = event.resultIndex; i < event.results.length; i++) {\n const result = event.results[i];\n if (!result) continue;\n const text = result[0]?.transcript ?? '';\n if (result.isFinal) {\n finalRef.current(text);\n } else {\n interim += text;\n }\n }\n if (interim && interimRef.current) interimRef.current(interim);\n };\n recognition.onerror = (event) => {\n if (event.error !== 'no-speech' && event.error !== 'aborted') {\n console.warn('SpeechRecognition error', event.error);\n }\n setIsListening(false);\n };\n recognition.onend = () => setIsListening(false);\n\n recognitionRef.current = recognition;\n return () => {\n try {\n recognition.stop();\n } catch {\n /* engine already stopped */\n }\n recognitionRef.current = null;\n };\n }, [ctor, lang]);\n\n const start = useCallback(() => {\n const recognition = recognitionRef.current;\n if (!recognition) return;\n try {\n recognition.start();\n setIsListening(true);\n } catch (error) {\n console.warn('SpeechRecognition start failed', error);\n }\n }, []);\n\n const stop = useCallback(() => {\n const recognition = recognitionRef.current;\n if (!recognition) return;\n try {\n recognition.stop();\n } catch {\n /* already stopped */\n }\n }, []);\n\n return { isSupported, isListening, start, stop };\n}\n","import type { UIMessage } from 'ai';\nimport React from 'react';\nimport type {\n AnyToolUIPart,\n MessageUsageInfo,\n TranscriptBlock,\n TranscriptFile,\n TranscriptUiBlock,\n} from '../transcript/model.js';\nimport {\n type EditSubmitInput,\n type MessageActionInput,\n type TranscriptItem,\n useTranscriptItem,\n} from '../transcript/use-chat-transcript.js';\nimport { useAmbientRenderUi } from './ambient-ui.js';\n\nexport type { AnyToolUIPart, MessageUsageInfo } from '../transcript/model.js';\nexport { formatRelativeTime } from '../transcript/model.js';\n\nexport type RenderToolPartFn = (part: AnyToolUIPart, key: string) => React.ReactNode;\n\n/** Render a run of consecutive tool parts as one block (e.g. a collapsible tool group). */\nexport type RenderToolGroupFn = (parts: AnyToolUIPart[], key: string) => React.ReactNode;\n\n/** Render a message's text — pass a markdown renderer (e.g. `AgentMarkdown`) here if desired. */\nexport type RenderTextFn = (text: string, ctx: { isStreaming: boolean }) => React.ReactNode;\n\n/** Render a run of files — attachments on a user turn, or files the model produced. */\nexport type RenderFilesFn = (files: TranscriptFile[]) => React.ReactNode;\n\n/**\n * Render a component the server pushed into the message — look `block.component` up in your own\n * registry. Omitted → drawn by the enclosing `<GenuiProvider>` (`/genui`) if there is one, else not\n * drawn (there is no sensible default for an app's own component).\n */\nexport type RenderUiFn = (block: TranscriptUiBlock) => React.ReactNode;\n\n/** Render the body of a reasoning run; the disclosure toggle around it stays this component's. */\nexport type RenderReasoningFn = (\n text: string,\n ctx: { isStreaming: boolean; isOpen: boolean },\n) => React.ReactNode;\n\nexport interface MessageItemClassNames {\n root?: string;\n /** Resolved per role so user/assistant/system bubbles can differ. */\n byRole?: Partial<Record<UIMessage['role'], string>>;\n text?: string;\n /** The action row under the bubble (copy / fork / regenerate / usage / timestamp). */\n actions?: string;\n actionButton?: string;\n usage?: string;\n timestamp?: string;\n editTextarea?: string;\n editActions?: string;\n reasoning?: string;\n reasoningToggle?: string;\n reasoningText?: string;\n files?: string;\n file?: string;\n fileImage?: string;\n}\n\ninterface MessageRenderSlots {\n renderToolPart?: RenderToolPartFn;\n /** Takes precedence over `renderToolPart` for a run of consecutive tool parts. */\n renderToolGroup?: RenderToolGroupFn;\n renderText?: RenderTextFn;\n renderReasoning?: RenderReasoningFn;\n /** Draw files yourself — a gallery, a viewer. Omitted → images inline, everything else a link. */\n renderFiles?: RenderFilesFn;\n /**\n * Draw a server-pushed component (a `ui` stream frame). Omitted → the enclosing `<GenuiProvider>`\n * draws it; without one, not drawn.\n */\n renderUi?: RenderUiFn;\n /**\n * Extra content for the action row, after the built-in affordances and before usage — a badge\n * naming which agent answered, a status pill. Rendered for every message that has an action row.\n */\n meta?: React.ReactNode;\n /** Label on the reasoning disclosure toggle. Default `\"Reasoning\"`. */\n reasoningLabel?: React.ReactNode;\n classNames?: MessageItemClassNames;\n}\n\nexport interface MessageItemProps extends MessageRenderSlots {\n message: UIMessage;\n /** Marks the in-flight assistant bubble (e.g. for a caret animation / deferred markdown render). */\n isStreaming?: boolean;\n /** User bubble gets a pencil → inline textarea; submitting calls back with the new text. */\n editable?: boolean;\n onEditSubmit?: (input: EditSubmitInput) => void | Promise<void>;\n /** Assistant bubble gets a \"Regenerate\" affordance. */\n regeneratable?: boolean;\n onRegenerate?: (input: MessageActionInput) => void | Promise<void>;\n /** When provided, a \"Fork\" affordance calls back with this message's id. */\n onFork?: (input: MessageActionInput) => void | Promise<void>;\n /** Server-aggregated usage for this assistant turn (cost + tokens line). */\n usage?: MessageUsageInfo | null;\n /** ISO timestamp of the persisted message; rendered as a relative-time line when set. */\n createdAt?: string | null;\n}\n\nexport interface MessageItemViewProps extends MessageRenderSlots {\n item: TranscriptItem;\n}\n\n/**\n * Styling-agnostic renderer for a single v7 `UIMessage`. Ports flip's full chat-item UX —\n * copy, fork, regenerate, inline edit-and-resubmit, collapsible reasoning, usage line, relative\n * timestamp, and tool grouping — but with ALL styling left to `classNames` and every action\n * surfaced as a callback, so no design-system / icon / date library is pulled in (relative time\n * uses Intl.RelativeTimeFormat).\n *\n * All of the logic lives in `useTranscriptItem`; this is one rendering of it. An app that wants\n * different markup drives that hook and writes its own.\n */\nexport function MessageItem({\n message,\n isStreaming = false,\n editable,\n onEditSubmit,\n regeneratable,\n onRegenerate,\n onFork,\n usage,\n createdAt,\n ...slots\n}: MessageItemProps) {\n const item = useTranscriptItem({\n message,\n isStreaming,\n ...(editable !== undefined ? { editable } : {}),\n ...(onEditSubmit ? { onEditSubmit } : {}),\n ...(onFork ? { onFork } : {}),\n ...(regeneratable !== undefined ? { regeneratable } : {}),\n ...(onRegenerate ? { onRegenerate } : {}),\n ...(usage != null ? { getUsage: () => usage } : {}),\n ...(createdAt != null ? { getCreatedAt: () => createdAt } : {}),\n });\n return <MessageItemView item={item} {...slots} />;\n}\n\n/** The default markup for one modelled message — what `MessageItem` renders once it has an item. */\nexport function MessageItemView({ item, ...given }: MessageItemViewProps) {\n // Inside a `<GenuiProvider>`, pushed components draw without a `renderUi` of their own.\n const ambientRenderUi = useAmbientRenderUi();\n const slots: MessageRenderSlots =\n given.renderUi === undefined && ambientRenderUi !== null\n ? { ...given, renderUi: ambientRenderUi }\n : given;\n const { classNames } = slots;\n const actionRow = (\n <div className={classNames?.actions} data-actions-for={item.role}>\n {item.copy.available ? (\n <button\n type=\"button\"\n onClick={item.copy.copy}\n className={classNames?.actionButton}\n title={item.copy.copied ? 'Copied!' : 'Copy message text'}\n >\n {item.copy.copied ? 'Copied' : 'Copy'}\n </button>\n ) : null}\n {item.fork.available ? (\n <button\n type=\"button\"\n onClick={item.fork.run}\n className={classNames?.actionButton}\n title=\"Fork thread from this message\"\n >\n Fork\n </button>\n ) : null}\n {item.regenerate.available ? (\n <button\n type=\"button\"\n onClick={item.regenerate.run}\n className={classNames?.actionButton}\n title=\"Regenerate response\"\n >\n Regenerate\n </button>\n ) : null}\n {slots.meta}\n {!item.isUser && item.usage ? (\n <span\n className={classNames?.usage}\n title={`Input ${item.usage.inputTokens.toLocaleString()} · Output ${item.usage.outputTokens.toLocaleString()} tokens`}\n >\n {item.usage.costLabel} · {item.usage.tokensLabel}\n </span>\n ) : null}\n {item.timestamp ? (\n <span className={classNames?.timestamp} title={item.timestamp.absolute}>\n {item.timestamp.relative}\n </span>\n ) : null}\n </div>\n );\n\n if (item.edit.available) {\n return <EditableUserBubble item={item} slots={slots} actions={actionRow} />;\n }\n\n const className = joinClasses(classNames?.root, classNames?.byRole?.[item.role]);\n\n return (\n <div\n className={className}\n data-role={item.role}\n data-streaming={item.isStreaming ? 'true' : undefined}\n >\n <div>{renderBlocks(item, slots)}</div>\n {actionRow}\n </div>\n );\n}\n\n/** Blocks the model has no opinion on are skipped — a renderer only draws what it can draw. */\nfunction renderBlocks(item: TranscriptItem, slots: MessageRenderSlots): React.ReactNode[] {\n const nodes: React.ReactNode[] = [];\n for (const block of item.blocks) {\n if (block.kind === 'text') {\n nodes.push(\n <div key={block.key} className={slots.classNames?.text}>\n {slots.renderText\n ? slots.renderText(block.text, { isStreaming: item.isStreaming })\n : block.text}\n </div>,\n );\n continue;\n }\n if (block.kind === 'reasoning') {\n nodes.push(renderReasoningBlock(block, slots));\n continue;\n }\n if (block.kind === 'files') {\n nodes.push(renderFilesBlock(block, slots));\n continue;\n }\n if (block.kind === 'tools') {\n nodes.push(...renderToolBlock(item, block, slots));\n continue;\n }\n if (block.kind === 'ui' && slots.renderUi) {\n nodes.push(\n <div key={block.key} data-slot=\"ui\" data-component={block.component}>\n {slots.renderUi(block)}\n </div>,\n );\n }\n }\n return nodes;\n}\n\n/**\n * Files as content. An image is shown; anything else is a labelled link, because a renderer that\n * cannot display a format is more useful pointing at it than guessing.\n */\nfunction renderFilesBlock(\n block: Extract<TranscriptBlock, { kind: 'files' }>,\n slots: MessageRenderSlots,\n): React.ReactNode {\n return (\n <div key={block.key} className={slots.classNames?.files} data-files=\"true\">\n {slots.renderFiles\n ? slots.renderFiles(block.files)\n : block.files.map((file) => (\n <a\n key={file.url}\n href={file.url}\n target=\"_blank\"\n rel=\"noreferrer\"\n className={slots.classNames?.file}\n title={file.filename ?? file.mediaType}\n >\n {file.isImage ? (\n <img\n src={file.url}\n alt={file.filename ?? 'image'}\n className={slots.classNames?.fileImage}\n />\n ) : (\n (file.filename ?? file.mediaType)\n )}\n </a>\n ))}\n </div>\n );\n}\n\nfunction renderReasoningBlock(\n block: Extract<TranscriptBlock, { kind: 'reasoning' }>,\n slots: MessageRenderSlots,\n): React.ReactNode {\n return (\n <div\n key={block.key}\n className={slots.classNames?.reasoning}\n data-reasoning=\"true\"\n data-streaming={block.isStreaming ? 'true' : undefined}\n >\n <button\n type=\"button\"\n className={slots.classNames?.reasoningToggle}\n onClick={() => block.toggle()}\n aria-expanded={block.isOpen}\n >\n {slots.reasoningLabel ?? 'Reasoning'}\n </button>\n {block.isOpen ? (\n <div className={slots.classNames?.reasoningText}>\n {slots.renderReasoning\n ? slots.renderReasoning(block.text, {\n isStreaming: block.isStreaming,\n isOpen: block.isOpen,\n })\n : block.text}\n </div>\n ) : null}\n </div>\n );\n}\n\nfunction renderToolBlock(\n item: TranscriptItem,\n block: Extract<TranscriptBlock, { kind: 'tools' }>,\n slots: MessageRenderSlots,\n): React.ReactNode[] {\n if (slots.renderToolGroup) {\n return [\n <React.Fragment key={block.key}>\n {slots.renderToolGroup(block.parts, block.key)}\n </React.Fragment>,\n ];\n }\n if (!slots.renderToolPart) {\n return [];\n }\n const renderToolPart = slots.renderToolPart;\n return block.parts.map((part) => {\n const partKey = `${item.id}-${part.toolCallId}`;\n return <React.Fragment key={partKey}>{renderToolPart(part, partKey)}</React.Fragment>;\n });\n}\n\ninterface EditableUserBubbleProps {\n item: TranscriptItem;\n slots: MessageRenderSlots;\n actions: React.ReactNode;\n}\n\nfunction EditableUserBubble({ item, slots, actions }: EditableUserBubbleProps) {\n const { classNames } = slots;\n const { edit } = item;\n\n if (!edit.isEditing) {\n return (\n <div className={joinClasses(classNames?.root, classNames?.byRole?.user)} data-role=\"user\">\n <div className={classNames?.text}>\n {slots.renderText ? slots.renderText(item.text, { isStreaming: false }) : item.text}\n </div>\n <button\n type=\"button\"\n onClick={edit.start}\n className={classNames?.actionButton}\n title=\"Edit & resubmit\"\n >\n Edit\n </button>\n {actions}\n </div>\n );\n }\n\n const textareaProps = edit.getTextareaProps();\n return (\n <div data-editing=\"true\">\n <textarea\n {...textareaProps}\n rows={Math.min(8, edit.draft.split('\\n').length + 1)}\n className={classNames?.editTextarea}\n />\n <div className={classNames?.editActions}>\n <button type=\"button\" onClick={edit.cancel}>\n Cancel\n </button>\n <button type=\"button\" onClick={edit.save} disabled={!edit.canSave}>\n Resend\n </button>\n </div>\n </div>\n );\n}\n\nfunction joinClasses(...entries: Array<string | undefined>): string | undefined {\n const joined = entries.filter((entry) => entry).join(' ');\n return joined === '' ? undefined : joined;\n}\n","import type { QueuePause } from '@dudousxd/nestjs-agent-core';\nimport type { UIMessage } from 'ai';\nimport type React from 'react';\nimport { useCallback, useEffect, useRef, useState } from 'react';\nimport type { ApprovalTarget } from '../approvals/proposals.js';\nimport { type MessageFile, attachmentFile } from '../attachments/files.js';\nimport { type AgentBackend, requireBackendMethod } from '../backend.js';\nimport type { ToolCatalog } from '../presentation/phrasing.js';\nimport { useAgentBackend } from '../provider.js';\nimport type { QueuedChatMessage } from '../queue/model.js';\nimport type { AgentMessageMetadata } from '../stored-thread-to-ui-messages.js';\nimport {\n type ApproveOptions,\n type ChatStatus,\n type MessageUsageInfo,\n type SettleAction,\n type TimestampInfo,\n type TranscriptBlock,\n type TranscriptFile,\n type UsageSummary,\n buildTranscriptBlocks,\n describeTimestamp,\n describeUsage,\n extractMessageText,\n} from './model.js';\nimport { type StickToBottom, useStickToBottom } from './use-stick-to-bottom.js';\n\n/** Most-recent messages mounted up front; older ones wait behind `window.loadEarlier`. */\nconst DEFAULT_VISIBLE_COUNT = 50;\nconst DEFAULT_LOAD_EARLIER_STEP = 50;\nconst DEFAULT_COPY_RESET_MS = 1500;\n\nexport interface TranscriptCopyState {\n /** False when the message has no prose to put on the clipboard. */\n available: boolean;\n copied: boolean;\n copy: () => void;\n}\n\nexport interface TranscriptEditState {\n available: boolean;\n isEditing: boolean;\n draft: string;\n /** Whitespace-only drafts are refused, so an empty resubmit can never be sent. */\n canSave: boolean;\n start: () => void;\n cancel: () => void;\n setDraft: (value: string) => void;\n save: () => void;\n /** Controlled-textarea wiring: focus with the caret at the end, Enter saves, Escape cancels. */\n getTextareaProps: () => {\n ref: (element: HTMLTextAreaElement | null) => void;\n value: string;\n onChange: (event: React.ChangeEvent<HTMLTextAreaElement>) => void;\n onKeyDown: (event: React.KeyboardEvent<HTMLTextAreaElement>) => void;\n };\n}\n\nexport interface TranscriptActionState {\n available: boolean;\n run: () => void;\n}\n\nexport interface TranscriptItem {\n id: string;\n message: UIMessage;\n role: UIMessage['role'];\n /** Index in the FULL message array, not in the rendered window. */\n index: number;\n isUser: boolean;\n isAssistant: boolean;\n isLastAssistant: boolean;\n isStreaming: boolean;\n blocks: TranscriptBlock[];\n /** The prose alone — what `copy` puts on the clipboard and what an edit starts from. */\n text: string;\n usage: UsageSummary | null;\n timestamp: TimestampInfo | null;\n copy: TranscriptCopyState;\n edit: TranscriptEditState;\n fork: TranscriptActionState;\n regenerate: TranscriptActionState;\n}\n\n/** What an edit-and-resubmit sends. */\nexport interface EditSubmitInput {\n messageId: string;\n text: string;\n}\n\n/** Names the message an action is about. */\nexport interface MessageActionInput {\n messageId: string;\n}\n\n/** Settling a parked question set. `answers` holds only the questions the user touched. */\nexport interface AnswerInput {\n toolCallId: string;\n answers?: Record<string, string[]>;\n /** The surface the answer came through; the server records `'web'` when omitted. */\n via?: string;\n}\n\n/** Declining a parked question set. */\nexport interface SkipInput {\n toolCallId: string;\n /** The surface the skip came through; the server records `'web'` when omitted. */\n via?: string;\n}\n\n/** Approving a tool call parked on a human. */\nexport interface ApproveInput extends ApproveOptions {\n target?: ApprovalTarget;\n toolCallId: string;\n /** The surface the decision came through; the server records `'web'` when omitted. */\n via?: string;\n}\n\n/** Rejecting a tool call parked on a human. */\nexport interface RejectInput {\n target?: ApprovalTarget;\n toolCallId: string;\n reason?: string;\n via?: string;\n}\n\nexport interface TranscriptItemOptions {\n /**\n * A transcript nobody acts on (an audit view, a shared or archived conversation): no approve /\n * reject, answer / skip, edit, fork, regenerate or stop — whatever handlers or backend are in\n * scope. Parked approvals and question sets still render, with their actions unavailable.\n *\n * Without it the decision handlers DEFAULT to the in-scope backend (`<AgentProvider>`'s), so a\n * parked call is actionable with no wiring; a read-only surface would otherwise have to pass\n * `onApprove: null`, `onReject: null`, `onAnswer: null` and `onSkip: null` one by one.\n */\n readOnly?: boolean;\n /** User messages get an inline edit-and-resubmit machine. */\n editable?: boolean;\n onEditSubmit?: (input: EditSubmitInput) => void | Promise<void>;\n onFork?: (input: MessageActionInput) => void | Promise<void>;\n /** Only the LAST assistant message gets a regenerate machine. */\n regeneratable?: boolean;\n onRegenerate?: (input: MessageActionInput) => void | Promise<void>;\n /** Default: `metadata.usage` (replayed turns; see `AgentMessageMetadata`). */\n getUsage?: (message: UIMessage) => MessageUsageInfo | null;\n /** Default: `metadata.createdAt` (replayed and streamed messages). */\n getCreatedAt?: (message: UIMessage) => string | null;\n /** How long `copy.copied` stays true. Default 1500ms. */\n copyResetMs?: number;\n /** Clipboard writer; defaults to `navigator.clipboard.writeText`. */\n writeClipboard?: (text: string) => Promise<void>;\n /**\n * Lift retrieval tool parts into their own `sources` block instead of leaving them in the tool\n * run. Off by default, so a renderer already drawing tool cards keeps drawing them.\n */\n sources?: boolean;\n /**\n * Server-declared tool presentations (`useToolCatalog(...).catalog`). Given → each tool call's\n * `description` and each tool block's `activity` speak in the tool's own words; omitted → generic.\n */\n toolCatalog?: ToolCatalog;\n /**\n * Settle a parked question set. Default: the in-scope backend's `answerToolCall` (the enclosing\n * `<AgentProvider>`'s), so a question set is an `elicitation` block the user can act on without\n * any wiring. `null` turns question sets back into plain tool calls.\n *\n * `answers` holds ONLY the questions the user touched. An omitted one takes its own pre-picked\n * default server-side, which is what keeps \"just confirmed\" and \"picked exactly what was\n * pre-picked\" distinguishable in the settled row.\n */\n onAnswer?: ((input: AnswerInput) => void | Promise<void>) | null;\n /** Decline the question set and let the agent proceed on its own picks. Default: the backend's. */\n onSkip?: ((input: SkipInput) => void | Promise<void>) | null;\n /**\n * Settle a tool call parked on a human. Default: the in-scope backend's `approveToolCall` /\n * `rejectToolCall`. `remember` is what `call.approve.run({ remember: true })` passed. `null`\n * leaves the call without the affordance.\n */\n onApprove?: ((input: ApproveInput) => void | Promise<void>) | null;\n onReject?: ((input: RejectInput) => void | Promise<void>) | null;\n}\n\nexport interface TranscriptWindow {\n visibleCount: number;\n /** How many older messages are not mounted. */\n hiddenCount: number;\n canLoadEarlier: boolean;\n loadEarlier: () => void;\n showAll: () => void;\n}\n\nexport interface TranscriptStopState {\n available: boolean;\n /** True from the click until the turn actually leaves a busy status. */\n isStopping: boolean;\n stop: () => void;\n}\n\nexport interface UseChatTranscriptOptions extends TranscriptItemOptions {\n messages: UIMessage[];\n status: ChatStatus;\n initialVisibleCount?: number;\n loadEarlierStep?: number;\n /** Cancel the in-flight turn — wire to `useAgentChat`'s `cancel`. */\n onStop?: () => void | Promise<void>;\n /** Suggested follow-ups. The model only decides WHETHER they belong on screen. */\n followUps?: string[] | null;\n stickToBottomThreshold?: number;\n /**\n * Messages waiting in the thread's queue — `chat.queue` (`useAgentChat` wires it). They render\n * after the transcript as {@link ChatTranscript.queued}: pending user messages, not yet sent.\n */\n queue?: {\n /** `files` may be left out by a host that builds these itself: it is derived from `attachments`. */\n items: Array<Omit<QueuedChatMessage, 'files'> & { files?: MessageFile[] }>;\n paused: QueuePause | null;\n remove?: (id: string) => void | Promise<void>;\n } | null;\n}\n\n/** One file on a waiting message: a sent message's {@link MessageFile}, and a `TranscriptFile`. */\nexport type TranscriptQueuedFile = MessageFile & TranscriptFile;\n\n/**\n * A message waiting in the thread's queue, as the transcript shows it: a user message that has not\n * been sent to the model yet. Render it after {@link ChatTranscript.items}, dimmed or tagged.\n */\nexport interface TranscriptQueuedItem {\n id: string;\n role: 'user';\n text: string;\n /**\n * The message's files, in the shape a sent message's have: a {@link MessageFile} (what\n * `messageFiles()` gives — `kind`, `extension`, `mediaId`) that is also a `TranscriptFile`\n * (`isImage`), so either renderer takes it as it is.\n */\n files: TranscriptQueuedFile[];\n /**\n * `'sending'` — on its way to the server. `'queued'` — waiting for the running turn.\n * `'paused'` — waiting, but the queue is paused (see {@link ChatTranscript.queuePaused}).\n */\n state: 'sending' | 'queued' | 'paused';\n /** 0-based place in the queue. */\n position: number;\n /** Runs next. */\n isNext: boolean;\n /** Queued by an interrupt — it runs as soon as the cancelled turn settles. */\n interrupt: boolean;\n remove: TranscriptActionState;\n}\n\nexport interface ChatTranscript {\n /** The mounted window, oldest first. `window.hiddenCount` says what is held back. */\n items: TranscriptItem[];\n status: ChatStatus;\n isEmpty: boolean;\n /** A turn is in flight: sent but not settled. */\n isBusy: boolean;\n isStreaming: boolean;\n showEmptyState: boolean;\n /** Waiting on the first token of a turn that has no assistant message yet. */\n showTypingIndicator: boolean;\n showFollowUps: boolean;\n lastAssistantId: string | null;\n window: TranscriptWindow;\n scroll: StickToBottom;\n stop: TranscriptStopState;\n /** Messages waiting in the thread's queue, in run order — render after `items`. */\n queued: TranscriptQueuedItem[];\n /** Why the queue is not draining, or `null`. */\n queuePaused: QueuePause | null;\n}\n\n/**\n * The model behind a chat transcript: messages normalized into items with their parts grouped into\n * runs, per-message derived values (copyable text, usage labels, relative time), each action as a\n * state machine rather than a button, list windowing, and stick-to-bottom. It renders nothing and\n * names no class — `MessageList`/`MessageItem` are one renderer over it, and an app with its own\n * design system writes another without reimplementing any of this.\n */\nexport function useChatTranscript(options: UseChatTranscriptOptions): ChatTranscript {\n const {\n messages,\n status,\n initialVisibleCount = DEFAULT_VISIBLE_COUNT,\n loadEarlierStep = DEFAULT_LOAD_EARLIER_STEP,\n followUps,\n stickToBottomThreshold,\n } = options;\n\n const latest = useRef(options);\n latest.current = options;\n\n const [visibleCount, setVisibleCount] = useState(initialVisibleCount);\n const [stopRequested, setStopRequested] = useState(false);\n\n // A reconnecting stream is still the turn in flight, and its message is still being written.\n const isStreaming = status === 'streaming' || status === 'reconnecting';\n const isBusy = status === 'submitted' || isStreaming;\n const isEmpty = messages.length === 0;\n\n // A settled turn clears a pending stop, so the next turn's button starts from rest.\n useEffect(() => {\n if (!isBusy) {\n setStopRequested(false);\n }\n }, [isBusy]);\n\n const lastMessage = messages.at(-1);\n const lastAssistant = findLastAssistant(messages);\n const streamingMessageId = isStreaming ? (lastAssistant?.id ?? null) : null;\n\n const visibleStart = Math.max(0, messages.length - visibleCount);\n const items = useTranscriptItems({\n messages,\n visibleStart,\n streamingMessageId,\n options,\n });\n\n const stop = useCallback(() => {\n const current = latest.current;\n if (\n current.status !== 'submitted' &&\n current.status !== 'streaming' &&\n current.status !== 'reconnecting'\n ) {\n return;\n }\n setStopRequested(true);\n void current.onStop?.();\n }, []);\n\n const loadEarlier = useCallback(\n () =>\n setVisibleCount(\n (count) => count + (latest.current.loadEarlierStep ?? DEFAULT_LOAD_EARLIER_STEP),\n ),\n [],\n );\n const showAll = useCallback(() => setVisibleCount(latest.current.messages.length), []);\n\n const scroll = useStickToBottom({\n contentKey: contentSignature(messages),\n ...(stickToBottomThreshold !== undefined ? { threshold: stickToBottomThreshold } : {}),\n });\n\n const showTypingIndicator = isBusy && lastMessage?.role !== 'assistant';\n const queued = useQueuedItems(options.queue ?? null, options.readOnly === true);\n\n return {\n items,\n status,\n isEmpty,\n isBusy,\n isStreaming,\n showEmptyState: isEmpty && status === 'ready',\n showTypingIndicator,\n showFollowUps:\n status === 'ready' &&\n !showTypingIndicator &&\n lastMessage?.role === 'assistant' &&\n !!followUps &&\n followUps.length > 0,\n lastAssistantId: lastAssistant?.id ?? null,\n window: {\n visibleCount,\n hiddenCount: visibleStart,\n canLoadEarlier: visibleStart > 0,\n loadEarlier,\n showAll,\n },\n scroll,\n stop: {\n available: isBusy && options.readOnly !== true && options.onStop !== undefined,\n isStopping: stopRequested,\n stop,\n },\n queued,\n queuePaused: options.queue?.paused ?? null,\n };\n}\n\n/** The queue as transcript items. `remove` is cached per id, like every other item action. */\nfunction useQueuedItems(\n queue: UseChatTranscriptOptions['queue'],\n readOnly: boolean,\n): TranscriptQueuedItem[] {\n const latestQueue = useRef(queue);\n latestQueue.current = queue;\n const removers = useRef(new Map<string, () => void>());\n const removerFor = useCallback((id: string) => {\n let remover = removers.current.get(id);\n if (remover === undefined) {\n remover = () => {\n void latestQueue.current?.remove?.(id);\n };\n removers.current.set(id, remover);\n }\n return remover;\n }, []);\n if (queue === null || queue === undefined) {\n return [];\n }\n return queue.items.map((message, position) => {\n const state: TranscriptQueuedItem['state'] =\n message.state === 'sending' ? 'sending' : queue.paused !== null ? 'paused' : 'queued';\n return {\n id: message.id,\n role: 'user',\n text: message.text,\n files: (message.files ?? message.attachments.map(attachmentFile)).map((file) => ({\n ...file,\n isImage: file.kind === 'image',\n })),\n state,\n position,\n isNext: position === 0,\n interrupt: message.interrupt,\n remove: {\n available: !readOnly && state !== 'sending' && queue.remove !== undefined,\n run: removerFor(message.id),\n },\n };\n });\n}\n\nexport interface UseTranscriptItemOptions extends TranscriptItemOptions {\n message: UIMessage;\n isStreaming?: boolean;\n}\n\n/**\n * The single-message half of {@link useChatTranscript}, for a renderer that owns the list itself.\n * `regeneratable` applies directly here: one assistant message is trivially the last one.\n */\nexport function useTranscriptItem(options: UseTranscriptItemOptions): TranscriptItem {\n const { message, isStreaming = false } = options;\n const messagesRef = useRef<UIMessage[]>([message]);\n // A fresh array each render would re-key nothing but does churn the items memo; the identity is\n // kept stable while the message itself is unchanged.\n if (messagesRef.current[0] !== message) {\n messagesRef.current = [message];\n }\n const items = useTranscriptItems({\n messages: messagesRef.current,\n visibleStart: 0,\n streamingMessageId: isStreaming ? message.id : null,\n options,\n });\n // One message in, exactly one item out.\n return items[0] as TranscriptItem;\n}\n\ninterface TranscriptItemsParams {\n messages: UIMessage[];\n visibleStart: number;\n streamingMessageId: string | null;\n options: TranscriptItemOptions;\n}\n\n/**\n * All per-message UI state lives here, keyed by message id, because the number of messages is not\n * known at render time — a hook per item would break the rules of hooks the moment a turn arrives.\n * Each item's callbacks are cached per id so a controlled `<textarea>`'s ref identity survives every\n * keystroke; without that, React detaches and re-attaches the node on each render and the focus\n * effect drags the caret back to the end mid-edit.\n */\nfunction useTranscriptItems({\n messages,\n visibleStart,\n streamingMessageId,\n options,\n}: TranscriptItemsParams): TranscriptItem[] {\n const [drafts, setDrafts] = useState<ReadonlyMap<string, string>>(() => new Map());\n const [copied, setCopied] = useState<ReadonlySet<string>>(() => new Set());\n const [openReasoning, setOpenReasoning] = useState<ReadonlyMap<string, boolean>>(() => new Map());\n // A question's picks, under `toolCallId|questionId`. Presence IS \"the user touched this\n // question\" — an absent entry is what makes the submission omit it and take the server's default.\n const [picks, setPicks] = useState<ReadonlyMap<string, string[]>>(() => new Map());\n // Which decision each parked call is sending, not merely that one is: the two affordances on a\n // call are never in flight together, and only the pressed one should report progress.\n const [settling, setSettling] = useState<ReadonlyMap<string, SettleAction>>(() => new Map());\n const [settleErrors, setSettleErrors] = useState<\n ReadonlyMap<string, { message: string; code: string | null }>\n >(() => new Map());\n\n const backend = useAgentBackend();\n const handlers = settleHandlers(options, backend);\n const latest = useRef({ options, handlers, drafts, picks, messages });\n latest.current = { options, handlers, drafts, picks, messages };\n\n const copyTimers = useRef(new Map<string, ReturnType<typeof setTimeout>>());\n useEffect(\n () => () => {\n for (const timer of copyTimers.current.values()) {\n clearTimeout(timer);\n }\n copyTimers.current.clear();\n },\n [],\n );\n\n const callbackCache = useRef(new Map<string, ItemCallbacks>());\n const reasoningToggleCache = useRef(new Map<string, (open?: boolean) => void>());\n\n const toggleReasoning = useCallback((key: string, open?: boolean) => {\n setOpenReasoning((current) => {\n const next = new Map(current);\n next.set(key, open ?? !(current.get(key) ?? false));\n return next;\n });\n }, []);\n\n const stableToggle = useCallback(\n (key: string) => {\n let cached = reasoningToggleCache.current.get(key);\n if (!cached) {\n cached = (open?: boolean) => toggleReasoning(key, open);\n reasoningToggleCache.current.set(key, cached);\n }\n return cached;\n },\n [toggleReasoning],\n );\n\n const pick = useCallback((toolCallId: string, questionId: string, values: string[]) => {\n setPicks((current) => new Map(current).set(pickKey(toolCallId, questionId), values));\n }, []);\n\n /**\n * Run one decision against the server. A rejection has to land somewhere the user can see: the\n * call stays parked either way, and a form that silently does nothing on submit is\n * indistinguishable from a broken button.\n */\n const settle = useCallback(\n (toolCallId: string, action: SettleAction, send: () => void | Promise<void>) => {\n setSettleErrors((current) => {\n if (!current.has(toolCallId)) {\n return current;\n }\n const next = new Map(current);\n next.delete(toolCallId);\n return next;\n });\n setSettling((current) => new Map(current).set(toolCallId, action));\n const failed = (error: unknown) => {\n setSettling((current) => {\n const next = new Map(current);\n next.delete(toolCallId);\n return next;\n });\n setSettleErrors((current) =>\n new Map(current).set(toolCallId, {\n message: error instanceof Error ? error.message : 'Could not settle this',\n code: settleErrorCode(error),\n }),\n );\n };\n // Sent in the click's own tick, not a microtask later — a synchronous throw and a rejected\n // promise are the same failure to the person looking at the form.\n try {\n void Promise.resolve(send()).catch(failed);\n } catch (error) {\n failed(error);\n }\n },\n [],\n );\n\n const answer = useCallback(\n (toolCallId: string) => {\n const current = latest.current;\n const onAnswer = current.handlers.onAnswer;\n if (!onAnswer) {\n return;\n }\n settle(toolCallId, 'answer', () =>\n onAnswer({ toolCallId, answers: answersFor(current.picks, toolCallId) }),\n );\n },\n [settle],\n );\n\n const skip = useCallback(\n (toolCallId: string) => {\n const onSkip = latest.current.handlers.onSkip;\n if (onSkip) {\n settle(toolCallId, 'skip', () => onSkip({ toolCallId }));\n }\n },\n [settle],\n );\n\n const approve = useCallback(\n (toolCallId: string, options?: ApproveOptions, target?: ApprovalTarget) => {\n const onApprove = latest.current.handlers.onApprove;\n if (onApprove) {\n settle(toolCallId, 'approve', () =>\n onApprove({\n toolCallId,\n ...(target === undefined ? {} : { target }),\n ...(options?.remember === true ? { remember: true } : {}),\n }),\n );\n }\n },\n [settle],\n );\n\n const reject = useCallback(\n (toolCallId: string, target?: ApprovalTarget) => {\n const onReject = latest.current.handlers.onReject;\n if (onReject) {\n settle(toolCallId, 'reject', () =>\n onReject({ toolCallId, ...(target === undefined ? {} : { target }) }),\n );\n }\n },\n [settle],\n );\n\n const callbacksFor = useCallback((id: string): ItemCallbacks => {\n const cached = callbackCache.current.get(id);\n if (cached) {\n return cached;\n }\n const textFor = () =>\n extractMessageText(latest.current.messages.find((message) => message.id === id)?.parts);\n const created: ItemCallbacks = {\n copy: () => {\n const text = textFor();\n if (!text) {\n return;\n }\n const write =\n latest.current.options.writeClipboard ??\n ((value: string) => navigator.clipboard.writeText(value));\n void Promise.resolve()\n .then(() => write(text))\n .then(() => {\n setCopied((current) => new Set(current).add(id));\n const existing = copyTimers.current.get(id);\n if (existing) {\n clearTimeout(existing);\n }\n copyTimers.current.set(\n id,\n setTimeout(() => {\n copyTimers.current.delete(id);\n setCopied((current) => {\n const next = new Set(current);\n next.delete(id);\n return next;\n });\n }, latest.current.options.copyResetMs ?? DEFAULT_COPY_RESET_MS),\n );\n })\n .catch(() => {\n // Clipboard can be unavailable (insecure context / denied permission) — fail quietly.\n });\n },\n startEdit: () => {\n const text = textFor();\n setDrafts((current) => new Map(current).set(id, text));\n },\n cancelEdit: () => {\n setDrafts((current) => {\n const next = new Map(current);\n next.delete(id);\n return next;\n });\n },\n setDraft: (value: string) => {\n setDrafts((current) => new Map(current).set(id, value));\n },\n save: () => {\n const next = (latest.current.drafts.get(id) ?? '').trim();\n if (!next) {\n return;\n }\n created.cancelEdit();\n void latest.current.options.onEditSubmit?.({ messageId: id, text: next });\n },\n fork: () => {\n void latest.current.options.onFork?.({ messageId: id });\n },\n regenerate: () => {\n void latest.current.options.onRegenerate?.({ messageId: id });\n },\n textareaRef: (element: HTMLTextAreaElement | null) => {\n if (!element) {\n return;\n }\n element.focus();\n element.setSelectionRange(element.value.length, element.value.length);\n },\n onTextareaChange: (event: React.ChangeEvent<HTMLTextAreaElement>) => {\n created.setDraft(event.target.value);\n },\n onTextareaKeyDown: (event: React.KeyboardEvent<HTMLTextAreaElement>) => {\n if (event.key === 'Enter' && !event.shiftKey) {\n event.preventDefault();\n created.save();\n }\n if (event.key === 'Escape') {\n event.preventDefault();\n created.cancelEdit();\n }\n },\n };\n callbackCache.current.set(id, created);\n return created;\n }, []);\n\n const lastAssistantId = findLastAssistant(messages)?.id ?? null;\n const items: TranscriptItem[] = [];\n\n for (let index = visibleStart; index < messages.length; index++) {\n const message = messages[index];\n if (!message) {\n continue;\n }\n const callbacks = callbacksFor(message.id);\n const draft = drafts.get(message.id);\n const isEditing = draft !== undefined;\n const text = extractMessageText(message.parts);\n const usage = (options.getUsage ?? usageFromMetadata)(message);\n const isUser = message.role === 'user';\n const isAssistant = message.role === 'assistant';\n const isLastAssistant = isAssistant && message.id === lastAssistantId;\n\n items.push({\n id: message.id,\n message,\n role: message.role,\n index,\n isUser,\n isAssistant,\n isLastAssistant,\n isStreaming: message.id === streamingMessageId,\n blocks: buildTranscriptBlocks(message, {\n isReasoningOpen: (key, isStreamingRun) => openReasoning.get(key) ?? isStreamingRun,\n toggleReasoning: (key, open) => stableToggle(key)(open),\n ...(options.sources !== undefined ? { sources: options.sources } : {}),\n ...(options.toolCatalog !== undefined ? { toolCatalog: options.toolCatalog } : {}),\n // Read-only still lifts question sets into their block, so the outcome shows.\n ...(handlers.onAnswer !== undefined ||\n (options.readOnly === true && options.onAnswer !== null)\n ? {\n elicitation: {\n picked: (toolCallId, questionId) => picks.get(pickKey(toolCallId, questionId)),\n pick,\n canAnswer: handlers.onAnswer !== undefined,\n canSkip: handlers.onSkip !== undefined,\n answer,\n skip,\n submitting: (toolCallId) => settling.get(toolCallId) ?? null,\n errorOf: (toolCallId) => settleErrors.get(toolCallId)?.message ?? null,\n errorCodeOf: (toolCallId) => settleErrors.get(toolCallId)?.code ?? null,\n },\n }\n : {}),\n ...(handlers.onApprove !== undefined || handlers.onReject !== undefined\n ? {\n approval: {\n canApprove: handlers.onApprove !== undefined,\n canReject: handlers.onReject !== undefined,\n approve,\n reject,\n submitting: (toolCallId) => settling.get(toolCallId) ?? null,\n errorOf: (toolCallId) => settleErrors.get(toolCallId)?.message ?? null,\n errorCodeOf: (toolCallId) => settleErrors.get(toolCallId)?.code ?? null,\n },\n }\n : {}),\n }),\n text,\n usage: usage ? describeUsage(usage) : null,\n timestamp: describeTimestamp((options.getCreatedAt ?? createdAtFromMetadata)(message)),\n copy: {\n available: text.length > 0,\n copied: copied.has(message.id),\n copy: callbacks.copy,\n },\n edit: {\n available:\n isUser &&\n options.readOnly !== true &&\n options.editable === true &&\n options.onEditSubmit !== undefined,\n isEditing,\n draft: draft ?? text,\n canSave: (draft ?? '').trim().length > 0,\n start: callbacks.startEdit,\n cancel: callbacks.cancelEdit,\n setDraft: callbacks.setDraft,\n save: callbacks.save,\n getTextareaProps: () => ({\n ref: callbacks.textareaRef,\n value: draft ?? text,\n onChange: callbacks.onTextareaChange,\n onKeyDown: callbacks.onTextareaKeyDown,\n }),\n },\n fork: {\n available: options.readOnly !== true && options.onFork !== undefined,\n run: callbacks.fork,\n },\n regenerate: {\n available:\n isLastAssistant &&\n options.readOnly !== true &&\n options.regeneratable === true &&\n options.onRegenerate !== undefined,\n run: callbacks.regenerate,\n },\n });\n }\n\n return items;\n}\n\ninterface ItemCallbacks {\n copy: () => void;\n startEdit: () => void;\n cancelEdit: () => void;\n setDraft: (value: string) => void;\n save: () => void;\n fork: () => void;\n regenerate: () => void;\n textareaRef: (element: HTMLTextAreaElement | null) => void;\n onTextareaChange: (event: React.ChangeEvent<HTMLTextAreaElement>) => void;\n onTextareaKeyDown: (event: React.KeyboardEvent<HTMLTextAreaElement>) => void;\n}\n\ninterface SettleHandlers {\n onAnswer: ((input: AnswerInput) => void | Promise<void>) | undefined;\n onSkip: ((input: SkipInput) => void | Promise<void>) | undefined;\n onApprove: ((input: ApproveInput) => void | Promise<void>) | undefined;\n onReject: ((input: RejectInput) => void | Promise<void>) | undefined;\n}\n\n/**\n * The handler for each human decision: the caller's, else the backend's own call — so a parked\n * approval or question set is never a card nobody can act on. `null` opts a decision out.\n */\nfunction settleHandlers(options: TranscriptItemOptions, backend: AgentBackend): SettleHandlers {\n const pick = <T>(own: T | null | undefined, fallback: T | undefined): T | undefined =>\n options.readOnly === true || own === null ? undefined : (own ?? fallback);\n return {\n onAnswer: pick(\n options.onAnswer,\n backend.answerToolCall\n ? async (input) => {\n await backend.answerToolCall?.(input);\n }\n : undefined,\n ),\n onSkip: pick(\n options.onSkip,\n backend.skipToolCall\n ? async (input) => {\n await backend.skipToolCall?.(input);\n }\n : undefined,\n ),\n onApprove: pick(\n options.onApprove,\n backend.approveToolCall || backend.approveActionProposal\n ? async (input) => {\n if (input.target?.kind === 'proposal') {\n if (input.target.threadId === undefined)\n throw new Error('A proposal decision requires its thread scope');\n await requireBackendMethod(\n backend,\n 'approveActionProposal',\n )({\n threadId: input.target.threadId,\n proposalId: input.target.proposalId,\n ...(input.remember === undefined ? {} : { remember: input.remember }),\n });\n } else await requireBackendMethod(backend, 'approveToolCall')(input);\n }\n : undefined,\n ),\n onReject: pick(\n options.onReject,\n backend.rejectToolCall || backend.rejectActionProposal\n ? async (input) => {\n if (input.target?.kind === 'proposal') {\n if (input.target.threadId === undefined)\n throw new Error('A proposal decision requires its thread scope');\n await requireBackendMethod(\n backend,\n 'rejectActionProposal',\n )({\n threadId: input.target.threadId,\n proposalId: input.target.proposalId,\n ...(input.reason === undefined ? {} : { reason: input.reason }),\n });\n } else await requireBackendMethod(backend, 'rejectToolCall')(input);\n }\n : undefined,\n ),\n };\n}\n\nfunction metadataOf(message: UIMessage): AgentMessageMetadata {\n const metadata = message.metadata;\n return metadata !== null && typeof metadata === 'object'\n ? (metadata as AgentMessageMetadata)\n : {};\n}\n\n/** The default `getUsage`: what the library stamps on `metadata.usage`. */\nfunction usageFromMetadata(message: UIMessage): MessageUsageInfo | null {\n const usage = metadataOf(message).usage;\n if (usage === undefined) return null;\n return {\n inputTokens: usage.inputTokens,\n outputTokens: usage.outputTokens,\n costUsd: usage.costUsd ?? null,\n };\n}\n\n/** The default `getCreatedAt`: what the library stamps on `metadata.createdAt`. */\nfunction createdAtFromMetadata(message: UIMessage): string | null {\n return metadataOf(message).createdAt ?? null;\n}\n\n/** `|` never appears in either half: a tool-call id and a question id are both opaque tokens. */\nfunction pickKey(toolCallId: string, questionId: string): string {\n return `${toolCallId}|${questionId}`;\n}\n\n/** The picks belonging to one question set, as the answers a submission carries. */\nfunction answersFor(\n picks: ReadonlyMap<string, string[]>,\n toolCallId: string,\n): Record<string, string[]> {\n const prefix = `${toolCallId}|`;\n const answers: Record<string, string[]> = {};\n for (const [key, values] of picks) {\n if (key.startsWith(prefix)) {\n answers[key.slice(prefix.length)] = values;\n }\n }\n return answers;\n}\n\nfunction findLastAssistant(messages: UIMessage[]): UIMessage | undefined {\n for (let index = messages.length - 1; index >= 0; index--) {\n const message = messages[index];\n if (message?.role === 'assistant') {\n return message;\n }\n }\n return undefined;\n}\n\n/**\n * Changes as the transcript grows, including WITHIN the message being streamed — the array is\n * mutated in place while tokens arrive, so its length alone never moves during a turn.\n */\nfunction contentSignature(messages: UIMessage[]): string {\n const last = messages.at(-1);\n if (!last) {\n return '0';\n }\n let length = 0;\n for (const part of last.parts ?? []) {\n if ('text' in part && typeof part.text === 'string') {\n length += part.text.length;\n }\n }\n return `${messages.length}|${last.id}|${last.parts?.length ?? 0}|${length}`;\n}\n\n/** The server's machine-readable reason for refusing a decision (`run_not_active`, …), if any. */\nfunction settleErrorCode(error: unknown): string | null {\n const code = (error as { code?: unknown } | null)?.code;\n return typeof code === 'string' && code !== '' ? code : null;\n}\n","import {\n type ElicitationInput,\n type ToolConfirmation,\n readElicitationInput,\n validateElicitationAnswer,\n} from '@dudousxd/nestjs-agent-core';\nimport {\n type DataUIPart,\n type DynamicToolUIPart,\n type FileUIPart,\n type ToolUIPart,\n type UIMessage,\n getToolName,\n isDataUIPart,\n isFileUIPart,\n isReasoningUIPart,\n isTextUIPart,\n isToolUIPart,\n} from 'ai';\nimport type { ApprovalTarget } from '../approvals/proposals.js';\nimport { type RawAnswer, coerceAnswer } from '../elicitation/answers.js';\nimport type { ToolCatalog } from '../presentation/phrasing.js';\nimport {\n type ToolActivityGroup,\n type ToolCallDescription,\n describeToolCall,\n groupToolActivity,\n} from '../presentation/tool-activity.js';\nimport { readReasoningMs } from '../reasoning/timing.js';\n\n/** A tool UI part on a `UIMessage` — a static `tool-*` part or the `dynamic-tool` part. */\nexport type AnyToolUIPart = ToolUIPart | DynamicToolUIPart;\n\n/**\n * The AI SDK's chat status, plus `reconnecting`: a turn is in flight and its stream dropped, and the\n * transport is re-attaching (`useAgentChat`). A busy status, like `streaming`.\n */\nexport type ChatStatus = 'ready' | 'submitted' | 'streaming' | 'reconnecting' | 'error';\n\n/** Server-aggregated usage for an assistant turn. */\nexport interface MessageUsageInfo {\n inputTokens: number;\n outputTokens: number;\n /**\n * `null` when no price is on record for the model that ran the turn. Distinct from `0`, which is\n * a turn that genuinely cost nothing — printing `$0` for an unpriced turn states a number the\n * store never had.\n */\n costUsd: number | null;\n}\n\n/** A run of contiguous prose. `isStreaming` is the PART's own state, not the message's. */\nexport interface TranscriptTextBlock {\n kind: 'text';\n key: string;\n text: string;\n isStreaming: boolean;\n}\n\n/** One file on a message — an uploaded attachment, or one the model produced. */\nexport interface TranscriptFile {\n /** Presigned or otherwise directly fetchable. Display-only: the model reads its own copy. */\n url: string;\n mediaType: string;\n filename: string | null;\n /** `image/*`, which a renderer can show inline rather than as a link. */\n isImage: boolean;\n}\n\n/** A run of contiguous files. Grouped so a renderer can lay several out as one strip. */\nexport interface TranscriptFilesBlock {\n kind: 'files';\n key: string;\n files: TranscriptFile[];\n}\n\n/**\n * A run of contiguous reasoning. Carries its own disclosure state because a thread can hold many\n * of them and each is toggled independently; `isOpen` defaults to `isStreaming` (thinking is worth\n * watching live, worth folding away once answered) until `toggle` is called for that run.\n */\nexport interface TranscriptReasoningBlock {\n kind: 'reasoning';\n key: string;\n text: string;\n isStreaming: boolean;\n /**\n * How long the model thought, in ms — the backend's measurement once the run closed (live) or as\n * persisted (reloaded). `null` while it still streams, or when nothing was recorded: pair it with\n * `useElapsed(block.isStreaming)` for a ticking label (`block.durationMs ?? elapsed`).\n */\n durationMs: number | null;\n isOpen: boolean;\n toggle: (open?: boolean) => void;\n}\n\n/**\n * A decision a run is waiting on a human for, and which one a parked call is currently sending.\n *\n * One call settles one way at a time, and WHICH one is what lets a surface report progress on the\n * affordance the person pressed instead of on all of them.\n */\nexport type SettleAction = 'approve' | 'reject' | 'answer' | 'skip';\n\n/** One such decision: whether it can be made, whether it is on its way, and how to send it. */\nexport interface TranscriptSettleState {\n available: boolean;\n /** True from the click until the run resumes and settles the call. */\n isSubmitting: boolean;\n run: () => void;\n}\n\n/** How an approval stands. */\nexport type TranscriptApprovalStatus =\n | 'pending'\n | 'approved'\n | 'rejected'\n | 'expired'\n | 'superseded';\n\n/**\n * Who has to settle a parked call, until when, and — once it settled — how. From the stream's\n * `approval-requested` / `approval-settled` frames, or the same parts a reloaded thread carries.\n * `null` on a call whose runner never said (the call can still be awaiting approval).\n */\nexport interface TranscriptApproval {\n target?: ApprovalTarget;\n executionStatus?: 'queued' | 'executing' | 'succeeded' | 'failed' | null;\n confirmation?: ToolConfirmation;\n /** Open vocabulary the host defines: `'requester'`, `'admin'`, a role… */\n approver: string;\n /** ISO-8601; `null` when the request never lapses. Pair with `useApprovalCountdown`. */\n expiresAt: string | null;\n /** Why the call needs a person, when the runner said. */\n reason: string | null;\n /**\n * `pending` until a settlement arrives; then what it said. Falls back to the call's own state\n * (denied → `rejected`, an output → `approved`) for a runner that streams no settlement.\n */\n status: TranscriptApprovalStatus;\n /** The approval also covers later calls of this tool in this thread. */\n remember: boolean;\n /** Opaque ref of who decided; `null` while pending, on an expiry, or when the runner did not say. */\n decidedBy: string | null;\n /** The surface the decision came through (`'web'`, `'slack'`, `'remembered'`, …). */\n decidedVia: string | null;\n /** What the person said when declining. */\n decisionReason: string | null;\n}\n\n/** What an approval can carry beyond yes. */\nexport interface ApproveOptions {\n /** Approve later calls of the same tool in the same thread without asking again. */\n remember?: boolean;\n}\n\n/** One call in a tool run, with whatever human decision it is parked on. */\nexport interface TranscriptToolCall {\n part: AnyToolUIPart;\n toolCallId: string;\n name: string;\n /** `read` / `action` as the stream classified the call; `null` when the backend did not say. */\n toolKind: string | null;\n /** The call this one ran inside (a code-mode `execute`, a delegated agent); `null` for a top-level call. */\n parentId: string | null;\n /**\n * Calls nested under this one within the same block, in stream order. Always empty for a call\n * nothing names as its parent.\n */\n children: TranscriptToolCall[];\n /** Who has to decide, when the runner said so. See {@link TranscriptApproval}. */\n approval: TranscriptApproval | null;\n /**\n * How to talk about this call without naming it — status, phrase, label, icon, approval prompt,\n * resolved result — from the server's presentation when `toolCatalog` was given, generic otherwise.\n */\n description: ToolCallDescription;\n /**\n * Parked on a person. An `action` tool's input lands and its output never follows on its own —\n * the loop waits for an approval between the two — so a settled-looking card that never settles\n * IS the pending approval.\n */\n isAwaitingApproval: boolean;\n /** `run({ remember: true })` approves this tool for the rest of the thread. */\n approve: TranscriptSettleState & { run: (options?: ApproveOptions) => void };\n reject: TranscriptSettleState;\n /** A failed decision — the call is still parked, so the affordance stays live. */\n error: string | null;\n /**\n * The server's machine-readable reason for {@link error}, when it gave one. `run_not_active`\n * means the turn that asked has ended: nothing is waiting for the decision, and pressing again\n * will be refused again — word it yourself and let the person send the message again.\n */\n errorCode: string | null;\n}\n\n/**\n * A run of CONSECUTIVE tool parts, grouped so a UI can collapse \"5 tools ran\" into one affordance.\n * Any non-tool part between two tool parts ends the run — including the AI SDK's `step-start`\n * markers, so tools from different steps never merge into one group.\n */\nexport interface TranscriptToolBlock {\n kind: 'tools';\n key: string;\n parts: AnyToolUIPart[];\n /** The same calls, each with its human-decision state. Same order as `parts`. */\n calls: TranscriptToolCall[];\n /**\n * The same calls as a tree: every call whose parent is NOT in this block, each carrying its\n * nested calls in `children`. Equal to `calls` when nothing is nested.\n */\n roots: TranscriptToolCall[];\n /**\n * The run folded into activity groups (\"Database query ×3\"), over `roots`, keyed by each tool's\n * presentation label (else its name). For another grouping, call `groupToolActivity` yourself.\n */\n activity: ToolActivityGroup[];\n}\n\n/**\n * A component the server pushed into the message (the stream's `ui` frame, or a persisted\n * `data-ui` part). Rendered by looking `component` up in the host's own registry.\n */\nexport interface TranscriptUiBlock {\n kind: 'ui';\n key: string;\n /** The component's identity within the message. */\n id: string;\n component: string;\n props: Record<string, unknown>;\n /** Schema version of `props`; `null` when the server did not stamp one. */\n version: number | null;\n fallbackText?: string;\n componentVersions?: Record<string, number>;\n /** The tool call that pushed it (`ctx.emitUi`); `null` for a component pushed outside a tool. */\n toolCallId: string | null;\n /**\n * A preview drawn while the model writes the call's arguments (genui `streaming: 'partial'`):\n * unvalidated, replaced in place by the final push. Absent on a final component.\n */\n partial?: true;\n}\n\n/** One choice a question offers, with its live selection state. */\nexport interface TranscriptQuestionOption {\n value: string;\n label: string;\n /** A single character the request suggested as a shortcut; `null` when it suggested none. */\n hotkey: string | null;\n isSelected: boolean;\n /** Pre-picked by the agent — what an untouched question submits as. */\n isDefault: boolean;\n /** Single choice: replaces the selection. Multiple: adds or removes this value. */\n select: () => void;\n}\n\n/** One question of a set, numbered against the whole. */\nexport interface TranscriptQuestion {\n id: string;\n prompt: string;\n /** A line of help under the prompt; `null` when the request gave none. */\n description: string | null;\n /**\n * How the answer is typed — `{ type, placeholder?, required?, min?, max?, pattern? }` — or `null`\n * for a plain pick from `options`. Render the control from `input.type`; `select` still picks\n * from `options`.\n */\n input: ElicitationInput | null;\n multiple: boolean;\n /** 1-based. The request carries every question up front, so \"Question 1 of N\" is honest. */\n position: number;\n options: TranscriptQuestionOption[];\n selected: string[];\n /**\n * The user has not touched this question, so a submission leaves it out and the server applies\n * the same defaults it showed. Distinct from \"selected happens to equal the defaults\": only the\n * first is recorded as `defaulted` rather than as a choice the user made.\n */\n isPristine: boolean;\n /** The first selected value, or `''` — what a single text/number/date field shows. */\n value: string;\n /**\n * Set a typed answer from whatever the control produced (a string, a number, a checkbox's\n * boolean, a `Date`, a list); coerced to the question's canonical strings with `coerceAnswer`.\n * `null`/`''` clears it. Does nothing once the set settled.\n */\n setValue: (raw: RawAnswer) => void;\n /**\n * Why the current selection would be refused (the server's own rules — `validateAnswer`), or\n * `null`. A pristine required question with no default reads `requires an answer`; show it once\n * the user tried to submit, or right away — the model does not decide that for you.\n */\n error: string | null;\n}\n\n/** How a question set settled, once it did. */\nexport interface TranscriptElicitationOutcome {\n answers: Record<string, string[]>;\n /** The user declined to answer and let the agent proceed on its own picks. */\n skipped: boolean;\n /** Questions filled from their own defaults rather than by the human. */\n defaulted: string[];\n /** The questions against the chosen labels, as the model read them back. */\n summary: string | null;\n /** Who answered (or skipped) — an approval's `decidedBy`. `null` when the run did not record it. */\n answeredBy: string | null;\n /** The surface it came through (`'web'`, `'slack'`, …) — an approval's `decidedVia`. */\n answeredVia: string | null;\n}\n\n/**\n * A question set the run put to the user, parked until someone settles it — the intake an agent\n * declares and the model's own `ask` produce the same block, because the loop streams the same\n * frame for both.\n */\nexport interface TranscriptElicitationBlock {\n kind: 'elicitation';\n key: string;\n /** The parked tool call — what `answer`/`skip` route by. */\n toolCallId: string;\n preamble: string | null;\n questions: TranscriptQuestion[];\n questionCount: number;\n /** Still waiting on a human. */\n isPending: boolean;\n /** Every question's current selection is acceptable (no question has an `error`). */\n isValid: boolean;\n outcome: TranscriptElicitationOutcome | null;\n /** A failed submission — the run is still parked, so the form stays live. */\n error: string | null;\n /** The server's machine-readable reason for {@link error} (`run_not_active`, …), when it gave one. */\n errorCode: string | null;\n answer: TranscriptSettleState;\n skip: TranscriptSettleState;\n}\n\n/** One retrieved passage, as it rides a retrieval tool call's output. Mirrors core's `Passage`. */\nexport interface RetrievedPassage {\n id: string;\n text: string;\n score: number;\n /** Citation-facing origin — a document title, URL or row id. */\n source?: string;\n metadata?: Record<string, unknown>;\n}\n\n/** The passages of one origin, folded together so a citation line reads once per source. */\nexport interface TranscriptSource {\n /** The `source` string the retriever stamped, falling back to the passage id when it stamped none. */\n id: string;\n label: string;\n passageCount: number;\n /** Highest relevance among this source's passages; the scale is the retriever's. */\n topScore: number;\n passages: RetrievedPassage[];\n}\n\n/**\n * The provenance behind an answer: a run of CONSECUTIVE retrieval tool parts, aggregated by origin.\n * Detection is structural — a tool output shaped `{ passages: [{ id, text, ... }] }` — because the\n * tool's NAME is not fixed: inject-mode retrieval persists as `retrieve`, and `createRetrievalTool`\n * lets the host rename `search_knowledge` to anything.\n */\nexport interface TranscriptSourcesBlock {\n kind: 'sources';\n key: string;\n /** What was searched, when the tool call recorded a `{ query }` input. */\n query: string | null;\n sources: TranscriptSource[];\n passageCount: number;\n}\n\nexport type TranscriptBlock =\n | TranscriptTextBlock\n | TranscriptFilesBlock\n | TranscriptReasoningBlock\n | TranscriptToolBlock\n | TranscriptSourcesBlock\n | TranscriptElicitationBlock\n | TranscriptUiBlock;\n\n/** Where a question set's selection state is held, and where its settlement is sent. */\nexport interface ElicitationBlockOptions {\n /** The values a question is showing, or `undefined` while the user has not touched it. */\n picked: (toolCallId: string, questionId: string) => string[] | undefined;\n pick: (toolCallId: string, questionId: string, values: string[]) => void;\n canAnswer: boolean;\n canSkip: boolean;\n answer: (toolCallId: string) => void;\n skip: (toolCallId: string) => void;\n /** Which decision this call is sending, or `null` for none. */\n submitting: (toolCallId: string) => SettleAction | null;\n errorOf: (toolCallId: string) => string | null;\n /** The `code` of the error `errorOf` reports, when the server sent one. */\n errorCodeOf?: (toolCallId: string) => string | null;\n}\n\n/** Where an approval decision is sent, and what the last one did. */\nexport interface ApprovalBlockOptions {\n canApprove: boolean;\n canReject: boolean;\n approve: (toolCallId: string, options?: ApproveOptions, target?: ApprovalTarget) => void;\n reject: (toolCallId: string, target?: ApprovalTarget) => void;\n /** Which decision this call is sending, or `null` for none. */\n submitting: (toolCallId: string) => SettleAction | null;\n errorOf: (toolCallId: string) => string | null;\n /** The `code` of the error `errorOf` reports, when the server sent one. */\n errorCodeOf?: (toolCallId: string) => string | null;\n}\n\nexport interface BuildBlocksOptions {\n /** Disclosure lookup for a reasoning run; `isStreaming` is the fallback when untouched. */\n isReasoningOpen: (key: string, isStreaming: boolean) => boolean;\n toggleReasoning: (key: string, open?: boolean) => void;\n /**\n * Lift retrieval tool parts out of the tool run into a `sources` block. Off by default, so a\n * renderer wired to draw tool cards keeps receiving them as the tool calls they are.\n */\n sources?: boolean;\n /**\n * Lift a question set out of the tool run into an `elicitation` block. Omitted → it stays a tool\n * card, which is all a host that has nowhere to send an answer could render anyway.\n */\n elicitation?: ElicitationBlockOptions;\n /** Wire approve/reject onto the calls parked on a human. Omitted → they are reported, not actionable. */\n approval?: ApprovalBlockOptions;\n /** Server-declared tool presentations (`useToolCatalog`), for each call's `description`. */\n toolCatalog?: ToolCatalog;\n}\n\n/**\n * Walk a message's parts into renderable blocks, buffering consecutive tool parts into one run and\n * consecutive files into one strip. A `data-ui` part becomes a `ui` block. A\n * `data-approval-requested` part is metadata about a call — it is folded into that call's\n * `approval` and takes no position of its own. Other `data-*` parts are dropped rather than guessed\n * at, but they still terminate a tool run — their position in the transcript is meaningful even\n * when their content is not modelled here.\n */\nexport function buildTranscriptBlocks(\n message: UIMessage,\n options: BuildBlocksOptions,\n): TranscriptBlock[] {\n const blocks: TranscriptBlock[] = [];\n let toolBuffer: AnyToolUIPart[] = [];\n let retrievalBuffer: AnyToolUIPart[] = [];\n let fileBuffer: FileUIPart[] = [];\n let toolCounter = 0;\n let textCounter = 0;\n let fileCounter = 0;\n let reasoningCounter = 0;\n let sourcesCounter = 0;\n let elicitationCounter = 0;\n const approvals = readApprovals(message.parts ?? []);\n\n function flushTools() {\n if (toolBuffer.length === 0) {\n return;\n }\n const calls = toolBuffer.map((part) =>\n buildToolCall(\n part,\n options.approval,\n approvalOf(approvals.get(part.toolCallId), part),\n options.toolCatalog,\n ),\n );\n const roots = nestToolCalls(calls);\n blocks.push({\n kind: 'tools',\n key: `${message.id}-tools-${toolCounter++}`,\n parts: toolBuffer,\n calls,\n roots,\n activity: groupToolActivity(roots, {\n ...(options.toolCatalog !== undefined ? { catalog: options.toolCatalog } : {}),\n }),\n });\n toolBuffer = [];\n }\n\n function flushSources() {\n if (retrievalBuffer.length === 0) {\n return;\n }\n blocks.push(buildSourcesBlock(`${message.id}-sources-${sourcesCounter++}`, retrievalBuffer));\n retrievalBuffer = [];\n }\n\n function flushFiles() {\n if (fileBuffer.length === 0) {\n return;\n }\n blocks.push({\n kind: 'files',\n key: `${message.id}-files-${fileCounter++}`,\n files: fileBuffer.map((part) => ({\n url: part.url,\n mediaType: part.mediaType,\n filename: part.filename ?? null,\n isImage: part.mediaType.startsWith('image/'),\n })),\n });\n fileBuffer = [];\n }\n\n function flushAll() {\n flushTools();\n flushSources();\n flushFiles();\n }\n\n // Calls whose outcome has arrived: a preview of their input still standing is not the answer.\n const settledCalls = new Set<string>();\n for (const part of message.parts ?? []) {\n if (\n isToolUIPart(part) &&\n (part.state === 'output-available' ||\n part.state === 'output-error' ||\n part.state === 'output-denied')\n ) {\n settledCalls.add(part.toolCallId);\n }\n }\n\n for (const part of message.parts ?? []) {\n if (isToolUIPart(part)) {\n const elicitation = options.elicitation;\n if (elicitation !== undefined) {\n const request = readElicitationRequest(part);\n if (request !== null) {\n flushAll();\n blocks.push(\n buildElicitationBlock(\n `${message.id}-elicitation-${elicitationCounter++}`,\n part,\n request,\n elicitation,\n ),\n );\n continue;\n }\n }\n if (options.sources === true && readPassages(part) !== null) {\n flushTools();\n retrievalBuffer.push(part);\n continue;\n }\n flushSources();\n flushFiles();\n toolBuffer.push(part);\n continue;\n }\n if (isFileUIPart(part)) {\n flushTools();\n flushSources();\n fileBuffer.push(part);\n continue;\n }\n if (part.type === APPROVAL_PART || part.type === SETTLED_PART) {\n continue;\n }\n flushAll();\n if (isDataUIPart(part)) {\n const ui = part.type === UI_PART ? readUiComponent(part) : null;\n // A preview stands only while its call is being written: withdrawn (no props), or left by a\n // call that settled without replacing it, it is nothing to draw.\n if (\n ui?.partial === true &&\n (Object.keys(ui.props).length === 0 ||\n (ui.toolCallId !== null && settledCalls.has(ui.toolCallId)))\n ) {\n continue;\n }\n if (ui !== null) {\n blocks.push({ kind: 'ui', key: `${message.id}-ui-${ui.id}`, ...ui });\n }\n continue;\n }\n if (isTextUIPart(part)) {\n blocks.push({\n kind: 'text',\n key: `${message.id}-text-${textCounter++}`,\n text: part.text,\n isStreaming: part.state === 'streaming',\n });\n continue;\n }\n if (isReasoningUIPart(part)) {\n const key = `${message.id}-reasoning-${reasoningCounter++}`;\n const isStreaming = part.state === 'streaming';\n blocks.push({\n kind: 'reasoning',\n key,\n text: part.text,\n isStreaming,\n durationMs: readReasoningMs(part),\n isOpen: options.isReasoningOpen(key, isStreaming),\n toggle: (open?: boolean) => options.toggleReasoning(key, open),\n });\n }\n }\n flushAll();\n return blocks;\n}\n\n/**\n * Fold a run of retrieval parts into one provenance block. Sources keep the order the retriever\n * returned them in — that order IS the ranking — and the query is taken from the first call that\n * recorded one.\n */\nfunction buildSourcesBlock(key: string, parts: AnyToolUIPart[]): TranscriptSourcesBlock {\n const byId = new Map<string, TranscriptSource>();\n let query: string | null = null;\n let passageCount = 0;\n\n for (const part of parts) {\n query ??= readQuery(part);\n for (const passage of readPassages(part) ?? []) {\n passageCount++;\n const id = passage.source ?? passage.id;\n const existing = byId.get(id);\n if (existing) {\n existing.passageCount++;\n existing.topScore = Math.max(existing.topScore, passage.score);\n existing.passages.push(passage);\n continue;\n }\n byId.set(id, {\n id,\n label: passage.source ?? passage.id,\n passageCount: 1,\n topScore: passage.score,\n passages: [passage],\n });\n }\n }\n\n return { kind: 'sources', key, query, sources: [...byId.values()], passageCount };\n}\n\n/** A call whose output has landed one way or another is nobody's decision any more. */\nfunction isSettled(state: string): boolean {\n return state === 'output-available' || state === 'output-error' || state === 'output-denied';\n}\n\nfunction toolKind(part: AnyToolUIPart): string | undefined {\n const metadata = (part as { toolMetadata?: unknown }).toolMetadata;\n return isRecord(metadata) && typeof metadata.toolKind === 'string'\n ? metadata.toolKind\n : undefined;\n}\n\n/**\n * An `action` tool's input lands and then nothing follows: the loop waits on a person between the\n * call and its execution. So a call classified `action` and stuck at `input-available` IS the\n * pending approval — there is no separate frame that says so.\n */\nfunction isAwaitingApproval(part: AnyToolUIPart): boolean {\n if (part.state === 'approval-requested') {\n return true;\n }\n if (part.state !== 'input-available') {\n return false;\n }\n // A question set parks the same way and is persisted as an action, but it is settled by\n // answering it, not by approving it.\n return toolKind(part) === 'action' && readElicitationRequest(part) === null;\n}\n\nfunction toolParentId(part: AnyToolUIPart): string | null {\n const metadata = (part as { toolMetadata?: unknown }).toolMetadata;\n return isRecord(metadata) && typeof metadata.parentId === 'string' ? metadata.parentId : null;\n}\n\n/**\n * Arrange a block's calls into a tree by `parentId`. A call whose parent is not in the block (or\n * that names itself, or would close a cycle) stays a root, so nothing a runner sends is ever lost\n * from the tree — at worst it is shown flat.\n */\nfunction nestToolCalls(calls: TranscriptToolCall[]): TranscriptToolCall[] {\n const byId = new Map(calls.map((call) => [call.toolCallId, call]));\n const roots: TranscriptToolCall[] = [];\n for (const call of calls) {\n const parent = call.parentId !== null ? byId.get(call.parentId) : undefined;\n if (parent === undefined || isAncestor(call, parent, byId)) {\n roots.push(call);\n continue;\n }\n parent.children.push(call);\n }\n return roots;\n}\n\n/** True when `candidate` is `call` itself or sits under it — attaching would close a cycle. */\nfunction isAncestor(\n call: TranscriptToolCall,\n candidate: TranscriptToolCall,\n byId: Map<string, TranscriptToolCall>,\n): boolean {\n const seen = new Set<string>();\n let current: TranscriptToolCall | undefined = candidate;\n while (current !== undefined && !seen.has(current.toolCallId)) {\n if (current.toolCallId === call.toolCallId) {\n return true;\n }\n seen.add(current.toolCallId);\n current = current.parentId !== null ? byId.get(current.parentId) : undefined;\n }\n return false;\n}\n\nfunction buildToolCall(\n part: AnyToolUIPart,\n options: ApprovalBlockOptions | undefined,\n approval: TranscriptApproval | null,\n catalog: ToolCatalog | undefined,\n): TranscriptToolCall {\n const toolCallId = part.toolCallId;\n const awaiting =\n approval?.target?.kind === 'proposal'\n ? approval.status === 'pending'\n : isAwaitingApproval(part);\n // Per decision, not per call: the two are never in flight together, and a surface that read one\n // flag for both would report the refusal it is carrying out as an approval in progress.\n const sending = awaiting ? (options?.submitting(toolCallId) ?? null) : null;\n return {\n part,\n toolCallId,\n name: getToolName(part),\n toolKind: toolKind(part) ?? null,\n parentId: toolParentId(part),\n children: [],\n approval,\n description: proposalDescription(\n describeToolCall(\n part,\n catalog,\n approval?.confirmation === undefined ? {} : { confirmation: approval.confirmation },\n ),\n approval,\n ),\n isAwaitingApproval: awaiting,\n approve: {\n available: awaiting && options?.canApprove === true,\n isSubmitting: sending === 'approve',\n // Read by field, not passed through: `onClick={call.approve.run}` hands this a click event,\n // and a host's handler must not receive that as its options.\n run: (approveOptions?: ApproveOptions) =>\n approval?.target === undefined\n ? approveOptions?.remember === true\n ? options?.approve(toolCallId, { remember: true })\n : options?.approve(toolCallId)\n : options?.approve(\n toolCallId,\n approveOptions?.remember === true ? { remember: true } : undefined,\n approval.target,\n ),\n },\n reject: {\n available: awaiting && options?.canReject === true,\n isSubmitting: sending === 'reject',\n run: () =>\n approval?.target === undefined\n ? options?.reject(toolCallId)\n : options?.reject(toolCallId, approval.target),\n },\n error: options?.errorOf(toolCallId) ?? null,\n errorCode: options?.errorCodeOf?.(toolCallId) ?? null,\n };\n}\n\n/** A question as the request wrote it, before any of the user's picks are applied. */\ninterface ElicitationQuestionData {\n id: string;\n prompt: string;\n description: string | null;\n input: ElicitationInput | null;\n multiple: boolean;\n allowFreeText: boolean;\n defaults: string[];\n options: { value: string; label: string; hotkey: string | null }[];\n}\n\n/**\n * The question set a tool call carries, or `null` for any other tool. Read from the call's INPUT\n * and by shape rather than by tool name: the same set is authored by an agent's intake and by the\n * model's own `ask`, it replays from the store under whatever name the row holds, and a client\n * that learned to recognise one name would render only half of them.\n */\nfunction readElicitationRequest(\n part: AnyToolUIPart,\n): { preamble: string | null; questions: ElicitationQuestionData[] } | null {\n const input = (part as { input?: unknown }).input;\n if (!isRecord(input) || !Array.isArray(input.questions) || input.questions.length === 0) {\n return null;\n }\n const questions: ElicitationQuestionData[] = [];\n for (const candidate of input.questions) {\n if (\n !isRecord(candidate) ||\n typeof candidate.id !== 'string' ||\n typeof candidate.prompt !== 'string'\n ) {\n return null;\n }\n // A typed question may carry no options; anything else is a pick and must offer some.\n const input = readElicitationInput(candidate.input) ?? null;\n const rawOptions = Array.isArray(candidate.options) ? candidate.options : [];\n if (rawOptions.length === 0 && (input === null || input.type === 'select')) {\n return null;\n }\n const options: ElicitationQuestionData['options'] = [];\n for (const option of rawOptions) {\n if (\n !isRecord(option) ||\n typeof option.value !== 'string' ||\n typeof option.label !== 'string'\n ) {\n return null;\n }\n options.push({\n value: option.value,\n label: option.label,\n hotkey: typeof option.hotkey === 'string' ? option.hotkey : null,\n });\n }\n questions.push({\n id: candidate.id,\n prompt: candidate.prompt,\n description: typeof candidate.description === 'string' ? candidate.description : null,\n input,\n multiple: candidate.multiple === true,\n allowFreeText: candidate.allowFreeText === true,\n defaults: Array.isArray(candidate.defaults)\n ? candidate.defaults.filter((value): value is string => typeof value === 'string')\n : [],\n options,\n });\n }\n return {\n preamble: typeof input.preamble === 'string' ? input.preamble : null,\n questions,\n };\n}\n\n/** What the run recorded for a settled question set, or `null` when it settled as something else. */\nfunction readElicitationOutcome(part: AnyToolUIPart): TranscriptElicitationOutcome | null {\n const output = (part as { output?: unknown }).output;\n if (!isRecord(output) || !isRecord(output.answers) || typeof output.skipped !== 'boolean') {\n return null;\n }\n const answers: Record<string, string[]> = {};\n for (const [id, values] of Object.entries(output.answers)) {\n answers[id] = Array.isArray(values)\n ? values.filter((value): value is string => typeof value === 'string')\n : [];\n }\n return {\n answers,\n skipped: output.skipped,\n defaulted: Array.isArray(output.defaulted)\n ? output.defaulted.filter((id): id is string => typeof id === 'string')\n : [],\n summary: typeof output.summary === 'string' ? output.summary : null,\n answeredBy: typeof output.answeredBy === 'string' ? output.answeredBy : null,\n answeredVia: typeof output.answeredVia === 'string' ? output.answeredVia : null,\n };\n}\n\nfunction buildElicitationBlock(\n key: string,\n part: AnyToolUIPart,\n request: { preamble: string | null; questions: ElicitationQuestionData[] },\n options: ElicitationBlockOptions,\n): TranscriptElicitationBlock {\n const toolCallId = part.toolCallId;\n const isPending = !isSettled(part.state);\n const outcome = isPending ? null : readElicitationOutcome(part);\n const questions = request.questions.map((question, index) => {\n const picked = isPending ? options.picked(toolCallId, question.id) : undefined;\n const selected = picked ?? outcome?.answers[question.id] ?? question.defaults;\n const pick = (values: string[]) => options.pick(toolCallId, question.id, values);\n // The same rules the answer route applies, over the same question shape core reads.\n const error = isPending\n ? validateElicitationAnswer(\n {\n id: question.id,\n prompt: question.prompt,\n options: question.options.map(({ value, label }) => ({ value, label })),\n ...(question.input !== null ? { input: question.input } : {}),\n ...(question.multiple ? { multiple: true } : {}),\n ...(question.allowFreeText ? { allowFreeText: true } : {}),\n },\n selected,\n )\n : null;\n return {\n id: question.id,\n prompt: question.prompt,\n description: question.description,\n input: question.input,\n multiple: question.multiple,\n position: index + 1,\n selected,\n value: selected[0] ?? '',\n error,\n setValue: (raw: RawAnswer) => {\n if (isPending) {\n pick(coerceAnswer(question, raw));\n }\n },\n isPristine: isPending\n ? picked === undefined\n : (outcome?.defaulted.includes(question.id) ?? true),\n options: question.options.map((option) => ({\n value: option.value,\n label: option.label,\n hotkey: option.hotkey,\n isSelected: selected.includes(option.value),\n isDefault: question.defaults.includes(option.value),\n select: () => {\n if (!isPending) {\n return;\n }\n if (!question.multiple) {\n pick([option.value]);\n return;\n }\n pick(\n selected.includes(option.value)\n ? selected.filter((value) => value !== option.value)\n : [...selected, option.value],\n );\n },\n })),\n };\n });\n const sending = isPending ? options.submitting(toolCallId) : null;\n return {\n kind: 'elicitation',\n key,\n toolCallId,\n preamble: request.preamble,\n questions,\n questionCount: questions.length,\n isPending,\n isValid: questions.every((question) => question.error === null),\n outcome,\n error: options.errorOf(toolCallId),\n errorCode: options.errorCodeOf?.(toolCallId) ?? null,\n answer: {\n available: isPending && options.canAnswer,\n isSubmitting: sending === 'answer',\n run: () => options.answer(toolCallId),\n },\n skip: {\n available: isPending && options.canSkip,\n isSubmitting: sending === 'skip',\n run: () => options.skip(toolCallId),\n },\n };\n}\n\nconst UI_PART = 'data-ui';\nconst APPROVAL_PART = 'data-approval-requested';\nconst SETTLED_PART = 'data-approval-settled';\n\n/** What the approval parts of a message say about one call, before its own state is consulted. */\ninterface ApprovalParts {\n target?: ApprovalTarget;\n executionStatus?: TranscriptApproval['executionStatus'];\n confirmation?: ToolConfirmation;\n approver: string | null;\n expiresAt: string | null;\n reason: string | null;\n status: Exclude<TranscriptApprovalStatus, 'pending'> | null;\n remember: boolean;\n decidedBy: string | null;\n decidedVia: string | null;\n decisionReason: string | null;\n}\n\nconst SETTLED_STATUSES: readonly string[] = ['approved', 'rejected', 'expired', 'superseded'];\n\n/** The approval metadata on a message, by call id. The latest frame of each kind for a call wins. */\nfunction readApprovals(parts: UIMessage['parts']): Map<string, ApprovalParts> {\n const out = new Map<string, ApprovalParts>();\n const entry = (id: string): ApprovalParts => {\n let found = out.get(id);\n if (found === undefined) {\n found = {\n approver: null,\n expiresAt: null,\n reason: null,\n status: null,\n remember: false,\n decidedBy: null,\n decidedVia: null,\n decisionReason: null,\n };\n out.set(id, found);\n }\n return found;\n };\n for (const part of parts) {\n if (\n part.type !== APPROVAL_PART &&\n part.type !== SETTLED_PART &&\n part.type !== 'data-action-proposal'\n ) {\n continue;\n }\n const data = (part as DataUIPart<Record<string, unknown>>).data;\n if (!isRecord(data) || typeof data.id !== 'string') {\n continue;\n }\n const approval = entry(data.id);\n if (part.type === APPROVAL_PART || part.type === 'data-action-proposal') {\n if (\n isRecord(data.target) &&\n data.target.kind === 'proposal' &&\n typeof data.target.proposalId === 'string'\n ) {\n approval.target = {\n kind: 'proposal',\n proposalId: data.target.proposalId,\n ...(typeof data.target.threadId === 'string' ? { threadId: data.target.threadId } : {}),\n };\n }\n if (part.type === 'data-action-proposal') {\n if (\n typeof data.status === 'string' &&\n ['pending', 'approved', 'rejected', 'expired', 'superseded'].includes(data.status)\n )\n approval.status =\n data.status === 'pending'\n ? null\n : (data.status as Exclude<TranscriptApprovalStatus, 'pending'>);\n if (\n data.executionStatus === null ||\n data.executionStatus === 'queued' ||\n data.executionStatus === 'executing' ||\n data.executionStatus === 'succeeded' ||\n data.executionStatus === 'failed'\n )\n approval.executionStatus = data.executionStatus;\n approval.remember = data.remember === true;\n approval.decidedBy = typeof data.decidedBy === 'string' ? data.decidedBy : null;\n approval.decidedVia = typeof data.decidedVia === 'string' ? data.decidedVia : null;\n }\n if (typeof data.approver !== 'string') {\n continue;\n }\n approval.approver = data.approver;\n approval.expiresAt = typeof data.expiresAt === 'string' ? data.expiresAt : null;\n if (\n isRecord(data.confirmation) &&\n typeof data.confirmation.title === 'string' &&\n typeof data.confirmation.verb === 'string' &&\n (data.confirmation.detail === undefined || typeof data.confirmation.detail === 'string')\n ) {\n approval.confirmation = {\n title: data.confirmation.title,\n verb: data.confirmation.verb,\n ...(typeof data.confirmation.detail === 'string'\n ? { detail: data.confirmation.detail }\n : {}),\n };\n }\n approval.reason = typeof data.reason === 'string' ? data.reason : null;\n continue;\n }\n if (typeof data.status !== 'string' || !SETTLED_STATUSES.includes(data.status)) {\n continue;\n }\n approval.status = data.status as ApprovalParts['status'];\n if (approval.approver === null && typeof data.approver === 'string') {\n approval.approver = data.approver;\n }\n approval.remember = data.remember === true;\n approval.decidedBy = typeof data.decidedBy === 'string' ? data.decidedBy : null;\n approval.decidedVia = typeof data.decidedVia === 'string' ? data.decidedVia : null;\n approval.decisionReason = typeof data.reason === 'string' ? data.reason : null;\n }\n return out;\n}\n\n/**\n * One call's approval: its parts, with the status completed from the call's own state when no\n * settlement was streamed. `null` when nothing on the message says who decides.\n */\nfunction approvalOf(\n parts: ApprovalParts | undefined,\n call: AnyToolUIPart,\n): TranscriptApproval | null {\n if (parts === undefined || parts.approver === null) {\n return null;\n }\n return {\n approver: parts.approver,\n ...(parts.target === undefined ? {} : { target: parts.target }),\n ...(parts.executionStatus === undefined ? {} : { executionStatus: parts.executionStatus }),\n ...(parts.confirmation !== undefined ? { confirmation: parts.confirmation } : {}),\n expiresAt: parts.expiresAt,\n reason: parts.reason,\n status: parts.status ?? (parts.target?.kind === 'proposal' ? 'pending' : statusFromPart(call)),\n remember: parts.remember,\n decidedBy: parts.decidedBy,\n decidedVia: parts.decidedVia,\n decisionReason: parts.decisionReason,\n };\n}\n\nfunction statusFromPart(call: AnyToolUIPart): TranscriptApprovalStatus {\n if (call.state === 'output-denied') {\n return 'rejected';\n }\n if (call.state === 'output-available' || call.state === 'output-error') {\n return 'approved';\n }\n return 'pending';\n}\n\n/** A pushed component, or `null` when the part does not carry one this model can address. */\nfunction readUiComponent(\n part: DataUIPart<Record<string, unknown>>,\n): Omit<TranscriptUiBlock, 'kind' | 'key'> | null {\n const data = part.data;\n if (!isRecord(data) || typeof data.component !== 'string') {\n return null;\n }\n const id = typeof data.id === 'string' ? data.id : part.id;\n if (id === undefined) {\n return null;\n }\n return {\n id,\n component: data.component,\n props: isRecord(data.props) ? data.props : {},\n version: typeof data.version === 'number' ? data.version : null,\n ...(isRecord(data.componentVersions) &&\n Object.values(data.componentVersions).every(\n (version) => typeof version === 'number' && Number.isSafeInteger(version) && version > 0,\n )\n ? { componentVersions: { ...data.componentVersions } as Record<string, number> }\n : {}),\n ...(typeof data.fallbackText === 'string' ? { fallbackText: data.fallbackText } : {}),\n toolCallId: typeof data.toolCallId === 'string' ? data.toolCallId : null,\n ...(data.partial === true ? { partial: true as const } : {}),\n };\n}\n\nfunction isRecord(value: unknown): value is Record<string, unknown> {\n return typeof value === 'object' && value !== null;\n}\n\nfunction readQuery(part: AnyToolUIPart): string | null {\n const input = (part as { input?: unknown }).input;\n if (!isRecord(input) || typeof input.query !== 'string') {\n return null;\n }\n return input.query;\n}\n\n/**\n * The passages on a settled retrieval tool call, or `null` for any other tool. A call still in\n * flight, or one whose output is not a non-empty list of `{ id, text }` passages, is not provenance\n * yet and stays an ordinary tool part.\n */\nfunction readPassages(part: AnyToolUIPart): RetrievedPassage[] | null {\n const output = (part as { output?: unknown }).output;\n if (!isRecord(output) || !Array.isArray(output.passages) || output.passages.length === 0) {\n return null;\n }\n const passages: RetrievedPassage[] = [];\n for (const candidate of output.passages) {\n if (\n !isRecord(candidate) ||\n typeof candidate.id !== 'string' ||\n typeof candidate.text !== 'string'\n ) {\n return null;\n }\n passages.push({\n id: candidate.id,\n text: candidate.text,\n score: typeof candidate.score === 'number' ? candidate.score : 0,\n ...(typeof candidate.source === 'string' ? { source: candidate.source } : {}),\n ...(isRecord(candidate.metadata) ? { metadata: candidate.metadata } : {}),\n });\n }\n return passages;\n}\n\n/** The message's prose, joined for the clipboard. Reasoning is excluded — it is not the answer. */\nexport function extractMessageText(parts: UIMessage['parts'] | undefined): string {\n const out: string[] = [];\n for (const part of parts ?? []) {\n if (isTextUIPart(part)) {\n out.push(part.text);\n }\n }\n return out.join('\\n\\n').trim();\n}\n\nexport interface UsageSummary extends MessageUsageInfo {\n totalTokens: number;\n /** `$0`, `$0.0123`, `$0.012`, `$1.23` — precision follows magnitude so sub-cent turns stay legible. */\n costLabel: string;\n tokensLabel: string;\n}\n\nexport function describeUsage(usage: MessageUsageInfo): UsageSummary {\n const totalTokens = usage.inputTokens + usage.outputTokens;\n return {\n ...usage,\n totalTokens,\n costLabel: formatCostUsd(usage.costUsd),\n tokensLabel: formatTokensShort(totalTokens),\n };\n}\n\nexport interface TimestampInfo {\n iso: string;\n date: Date;\n /** \"just now\" / \"5 min. ago\" / \"Mar 3\" — see {@link formatRelativeTime}. */\n relative: string;\n absolute: string;\n}\n\n/** `null` for an unparseable stamp, so a bad `created_at` renders nothing instead of \"Invalid Date\". */\nexport function describeTimestamp(createdAt: string | null | undefined): TimestampInfo | null {\n if (createdAt == null) {\n return null;\n }\n const date = new Date(createdAt);\n if (Number.isNaN(date.getTime())) {\n return null;\n }\n return {\n iso: createdAt,\n date,\n relative: formatRelativeTime(date),\n absolute: date.toLocaleString(undefined, { dateStyle: 'medium', timeStyle: 'short' }),\n };\n}\n\nconst RELATIVE_TIME = new Intl.RelativeTimeFormat(undefined, { numeric: 'auto', style: 'narrow' });\nconst ONE_WEEK_MS = 7 * 24 * 60 * 60 * 1000;\n\n/**\n * \"just now\" within ±10s (server `created_at` can land a few ms ahead of the client clock), a\n * relative phrase up to a week, then a calendar date. Uses Intl.RelativeTimeFormat — no date-fns.\n */\nexport function formatRelativeTime(date: Date): string {\n const diffMs = Date.now() - date.getTime();\n if (Math.abs(diffMs) < 10_000) {\n return 'just now';\n }\n if (diffMs > ONE_WEEK_MS) {\n return date.toLocaleDateString(undefined, { month: 'short', day: 'numeric' });\n }\n const minutes = Math.round(-diffMs / 60_000);\n if (Math.abs(minutes) < 60) {\n return RELATIVE_TIME.format(minutes, 'minute');\n }\n const hours = Math.round(-diffMs / 3_600_000);\n if (Math.abs(hours) < 24) {\n return RELATIVE_TIME.format(hours, 'hour');\n }\n return RELATIVE_TIME.format(Math.round(-diffMs / 86_400_000), 'day');\n}\n\nfunction formatTokensShort(n: number): string {\n if (n < 1_000) {\n return `${n} tokens`;\n }\n if (n < 10_000) {\n return `${(n / 1_000).toFixed(1)}k tokens`;\n }\n return `${Math.round(n / 1_000)}k tokens`;\n}\n\nfunction formatCostUsd(cost: number | null): string {\n if (cost === null) {\n return '—';\n }\n if (cost === 0) {\n return '$0';\n }\n if (cost < 0.01) {\n return `$${cost.toFixed(4)}`;\n }\n if (cost < 1) {\n return `$${cost.toFixed(3)}`;\n }\n return `$${cost.toFixed(2)}`;\n}\n\nfunction proposalDescription(\n description: TranscriptToolCall['description'],\n approval: TranscriptApproval | null,\n): TranscriptToolCall['description'] {\n if (approval?.target?.kind !== 'proposal') return description;\n const status =\n approval.status === 'pending'\n ? 'awaiting-approval'\n : approval.status === 'approved'\n ? (approval.executionStatus ?? 'queued')\n : 'denied';\n const phrase =\n status === 'awaiting-approval'\n ? 'Awaiting approval'\n : status === 'queued'\n ? 'Queued'\n : status === 'executing'\n ? 'Executing'\n : status === 'succeeded'\n ? 'Succeeded'\n : status === 'failed'\n ? 'Failed'\n : approval.status === 'expired'\n ? 'Expired'\n : approval.status === 'superseded'\n ? 'Replaced'\n : 'Rejected';\n return { ...description, status, phrase, result: null };\n}\n","import type { ElicitationInputType, ElicitationQuestion } from '@dudousxd/nestjs-agent-core';\n\nexport {\n type ElicitationInput,\n type ElicitationInputType,\n validateElicitationAnswer as validateAnswer,\n validateElicitationValue as validateAnswerValue,\n} from '@dudousxd/nestjs-agent-core';\n\n/** What a form control can hand over: a field's value, a checkbox's state, a picked date, a list. */\nexport type RawAnswer = string | number | boolean | Date | null | undefined | readonly RawAnswer[];\n\n/** The question fields {@link coerceAnswer} reads. A transcript question and a core one both fit. */\nexport type CoercibleQuestion = Pick<ElicitationQuestion, 'multiple'> & {\n input?: { type: ElicitationInputType } | null;\n};\n\nfunction pad(value: number): string {\n return String(value).padStart(2, '0');\n}\n\n/** A `Date` as the calendar day the person picked — local time, which is the day they saw. */\nfunction toDay(date: Date): string | null {\n if (Number.isNaN(date.getTime())) {\n return null;\n }\n return `${date.getFullYear()}-${pad(date.getMonth() + 1)}-${pad(date.getDate())}`;\n}\n\nfunction coerceOne(type: ElicitationInputType | undefined, raw: RawAnswer): string | null {\n if (raw === null || raw === undefined) {\n return null;\n }\n if (Array.isArray(raw)) {\n return null;\n }\n if (raw instanceof Date) {\n return type === 'date' || type === undefined ? toDay(raw) : raw.toISOString();\n }\n if (typeof raw === 'boolean') {\n return raw ? 'true' : 'false';\n }\n if (typeof raw === 'number') {\n return Number.isFinite(raw) ? String(raw) : null;\n }\n const text = raw as string;\n switch (type) {\n case 'number':\n case 'email':\n case 'url':\n case 'date':\n return text.trim() === '' ? null : text.trim();\n case 'boolean': {\n const lowered = text.trim().toLowerCase();\n if (lowered === 'true' || lowered === 'on' || lowered === 'yes') return 'true';\n if (lowered === 'false' || lowered === 'off' || lowered === 'no') return 'false';\n return lowered === '' ? null : text;\n }\n default:\n return text === '' ? null : text;\n }\n}\n\n/**\n * Turn whatever a form control produced into the `string[]` the answer route takes, in the\n * question's canonical form: numbers as decimals, booleans as `\"true\"`/`\"false\"`, dates as\n * `YYYY-MM-DD` (a `Date` is read as the local calendar day), trimmed where whitespace means\n * nothing. An empty value becomes `[]` — no answer, not an empty string. A single-choice question\n * keeps the first value.\n *\n * Coercion never judges: pair it with {@link validateAnswer} (the same rules the server applies) to\n * say what is wrong before sending.\n */\nexport function coerceAnswer(question: CoercibleQuestion, raw: RawAnswer): string[] {\n const type = question.input?.type;\n const items: readonly RawAnswer[] = Array.isArray(raw) ? raw : [raw];\n const values = items\n .map((item) => coerceOne(type, item))\n .filter((value): value is string => value !== null);\n return question.multiple === true ? values : values.slice(0, 1);\n}\n","import type {\n ToolConfirmation,\n ToolPresentation,\n ToolPresentationTone,\n} from '@dudousxd/nestjs-agent-core';\nimport { getToolName } from 'ai';\nimport type { AnyToolUIPart, TranscriptToolCall } from '../transcript/model.js';\nimport { type ToolCatalog, fillTemplate, phraseFor } from './phrasing.js';\nimport { type ResolvedResultView, resolveResultView } from './result-view.js';\n\n/**\n * Where one call stands, as a person reads it:\n * - `running` — input streaming or the tool executing;\n * - `awaiting-approval` — an `action` call parked on a person;\n * - `done` / `failed` / `denied` — settled. A tool that RETURNS `{ error }` has failed just as much\n * as one that threw; the two arrive differently and read the same to a person.\n */\nexport type ToolCallStatus =\n | 'running'\n | 'awaiting-approval'\n | 'done'\n | 'failed'\n | 'denied'\n | 'queued'\n | 'executing'\n | 'succeeded';\n\nexport interface ToolCallState {\n status: ToolCallStatus;\n isSettled: boolean;\n isFailed: boolean;\n isDenied: boolean;\n output: unknown;\n error: string | null;\n}\n\n/** Whether the stream classified this call as an `action` (it parks for approval before it runs). */\nexport function isActionCall(part: AnyToolUIPart): boolean {\n const metadata = (part as { toolMetadata?: unknown }).toolMetadata;\n return (\n typeof metadata === 'object' &&\n metadata !== null &&\n (metadata as Record<string, unknown>).toolKind === 'action'\n );\n}\n\nexport function toolCallState(part: AnyToolUIPart): ToolCallState {\n const output = 'output' in part ? part.output : undefined;\n if (\n output !== null &&\n typeof output === 'object' &&\n 'proposalId' in output &&\n 'executed' in output &&\n output.executed === false\n )\n return {\n status: 'awaiting-approval',\n isSettled: false,\n isFailed: false,\n isDenied: false,\n output,\n error: null,\n };\n const errorText = 'errorText' in part ? part.errorText : undefined;\n const outputError =\n output !== null && typeof output === 'object' && 'error' in output\n ? String((output as { error: unknown }).error)\n : undefined;\n const isDenied = part.state === 'output-denied';\n const isFailed = part.state === 'output-error' || (outputError !== undefined && !isDenied);\n const isSettled = part.state === 'output-available' || part.state === 'output-error' || isDenied;\n const isAwaiting =\n part.state === 'approval-requested' || (part.state === 'input-available' && isActionCall(part));\n const status: ToolCallStatus = isDenied\n ? 'denied'\n : isFailed\n ? 'failed'\n : isSettled\n ? 'done'\n : isAwaiting\n ? 'awaiting-approval'\n : 'running';\n return {\n status,\n isSettled,\n isFailed,\n isDenied,\n output,\n error: errorText ?? outputError ?? null,\n };\n}\n\n/**\n * Which failed calls the model went on to correct, by call id: a call that failed and was followed,\n * in the same run, by a SUCCESS of the same tool. The operator wants to know a retry happened, not\n * to read every attempt. A failed read is not corrected by a successful query.\n */\nexport function correctedCallIds(parts: readonly AnyToolUIPart[]): Set<string> {\n const corrected = new Set<string>();\n const lastSuccessByTool = new Map<string, number>();\n parts.forEach((part, index) => {\n if (part.state === 'output-available' && !toolCallState(part).isFailed) {\n lastSuccessByTool.set(getToolName(part), index);\n }\n });\n parts.forEach((part, index) => {\n const successAt = lastSuccessByTool.get(getToolName(part));\n if (successAt !== undefined && index < successAt && toolCallState(part).isFailed) {\n corrected.add(part.toolCallId);\n }\n });\n return corrected;\n}\n\n/** Everything a surface needs to talk about one call without naming it. */\nexport interface ToolCallDescription {\n status: ToolCallStatus;\n /** \"Querying orders\" / \"Queried orders\" — or the generic fallback when the tool declared nothing. */\n phrase: string;\n /** The server's noun phrase for the tool; `null` when it declared no presentation. */\n label: string | null;\n icon: string | null;\n tone: ToolPresentationTone;\n detail: string | null;\n /** The approval prompt, templated over the call's input; `null` when the tool declared none. */\n confirm: { title: string; verb: string; detail: string | null } | null;\n /** The output read through its view, once the call is `done`; `null` otherwise or when nothing to draw. */\n result: ResolvedResultView | null;\n error: string | null;\n presentation: ToolPresentation | null;\n}\n\nexport interface DescribeToolCallOptions {\n /** Resolved strings from the call preflight override the tool catalog templates. */\n confirmation?: ToolConfirmation;\n /** Words for a tool the catalog does not describe. Default `Working` / `Done`. */\n fallback?: { running: string; done: string };\n /** Infer a result view from the output's shape when the tool declared none. Default `false`. */\n inferResult?: boolean;\n}\n\nexport function describeToolCall(\n part: AnyToolUIPart,\n catalog: ToolCatalog | undefined,\n options: DescribeToolCallOptions = {},\n): ToolCallDescription {\n const presentation = catalog?.[getToolName(part)];\n const state = toolCallState(part);\n const input = (part as { input?: unknown }).input;\n const confirm = presentation?.confirm;\n return {\n status: state.status,\n phrase: phraseFor(presentation, input, state.isSettled, options.fallback),\n label: presentation?.label ?? null,\n icon: presentation?.icon ?? null,\n tone: presentation?.tone ?? 'neutral',\n detail: presentation?.detail ?? null,\n confirm:\n options.confirmation !== undefined\n ? {\n title: options.confirmation.title,\n verb: options.confirmation.verb,\n detail: options.confirmation.detail ?? null,\n }\n : confirm === undefined\n ? null\n : {\n title: fillTemplate(confirm.title, input),\n verb: confirm.verb,\n detail: confirm.detail !== undefined ? fillTemplate(confirm.detail, input) : null,\n },\n result:\n state.status === 'done'\n ? resolveResultView(state.output, presentation?.result, {\n ...(options.inferResult !== undefined ? { infer: options.inferResult } : {}),\n })\n : null,\n error: state.error,\n presentation: presentation ?? null,\n };\n}\n\n/**\n * Calls folded under one key — \"Database query ×3\" — with the state that matters most across them.\n */\nexport interface ToolActivityGroup {\n key: string;\n /** The server's label for the group's tool; `null` when it declared no presentation. */\n label: string | null;\n icon: string | null;\n /** Worst-first across the calls: running › awaiting-approval › failed › denied › done. */\n status: ToolCallStatus;\n count: number;\n /** The phrase of the group's LATEST call — what is happening now. */\n phrase: string;\n calls: TranscriptToolCall[];\n /** Calls nested under the group's calls (all depths), when nesting was not expanded. */\n innerCount: number;\n}\n\nexport interface GroupToolActivityOptions {\n catalog?: ToolCatalog;\n /**\n * What makes two calls \"the same activity\". Default: the tool's presentation `label`, else its\n * name. Flippy-style source grouping passes its own (e.g. `github:search`).\n */\n keyOf?: (call: TranscriptToolCall, presentation: ToolPresentation | undefined) => string;\n /**\n * Replace a call that has nested calls with those calls (recursively), so the activity reads as\n * what the code-mode run DID rather than \"ran code\". Default `false`: groups are built over the\n * top-level calls, and `innerCount` says how much ran beneath them.\n */\n expandNested?: boolean;\n /** Drop failed calls the model corrected with a later success of the same tool. Default `false`. */\n hideCorrected?: boolean;\n fallback?: { running: string; done: string };\n}\n\nconst STATUS_WEIGHT: Record<ToolCallStatus, number> = {\n running: 4,\n queued: 4,\n executing: 4,\n succeeded: 0,\n 'awaiting-approval': 3,\n failed: 2,\n denied: 1,\n done: 0,\n};\n\nfunction descendants(call: TranscriptToolCall): TranscriptToolCall[] {\n return call.children.flatMap((child) => [child, ...descendants(child)]);\n}\n\nfunction leaves(call: TranscriptToolCall): TranscriptToolCall[] {\n return call.children.length === 0 ? [call] : call.children.flatMap(leaves);\n}\n\n/**\n * Fold a tool run into activity groups, in order of first appearance. Pass `block.roots` (the\n * transcript's call tree) so nesting is honoured; a flat `block.calls` works too and simply has\n * nothing nested.\n */\nexport function groupToolActivity(\n calls: readonly TranscriptToolCall[],\n options: GroupToolActivityOptions = {},\n): ToolActivityGroup[] {\n const expanded = options.expandNested === true ? calls.flatMap(leaves) : [...calls];\n const corrected =\n options.hideCorrected === true\n ? correctedCallIds(expanded.map((call) => call.part))\n : new Set<string>();\n const groups = new Map<string, ToolActivityGroup>();\n for (const call of expanded) {\n if (corrected.has(call.toolCallId)) continue;\n const presentation = options.catalog?.[call.name];\n const key = options.keyOf?.(call, presentation) ?? presentation?.label ?? call.name;\n const status = call.description.status;\n const phrase = phraseFor(\n presentation,\n (call.part as { input?: unknown }).input,\n status !== 'running' && status !== 'awaiting-approval',\n options.fallback,\n );\n const inner = options.expandNested === true ? 0 : descendants(call).length;\n const existing = groups.get(key);\n if (existing === undefined) {\n groups.set(key, {\n key,\n label: presentation?.label ?? null,\n icon: presentation?.icon ?? null,\n status,\n count: 1,\n phrase,\n calls: [call],\n innerCount: inner,\n });\n continue;\n }\n existing.count += 1;\n existing.calls.push(call);\n existing.phrase = phrase;\n existing.innerCount += inner;\n if (STATUS_WEIGHT[status] > STATUS_WEIGHT[existing.status]) existing.status = status;\n }\n return [...groups.values()];\n}\n","import type { ToolCatalogEntry, ToolPresentation } from '@dudousxd/nestjs-agent-core';\n\n/** Tool name → how the server said it is spoken about. */\nexport type ToolCatalog = Record<string, ToolPresentation>;\n\n/** Index `GET <base>/tools` by tool name, keeping only the tools that declared a presentation. */\nexport function toolCatalogFrom(entries: readonly ToolCatalogEntry[]): ToolCatalog {\n const catalog: ToolCatalog = {};\n for (const entry of entries) {\n if (entry.presentation !== undefined) catalog[entry.name] = entry.presentation;\n }\n return catalog;\n}\n\n/** Dotted-path read. `undefined` rather than a throw, so a template can outlive a field. */\nexport function readPath(value: unknown, path: string): unknown {\n return path.split('.').reduce<unknown>((current, key) => {\n if (current === null || typeof current !== 'object') return undefined;\n return (current as Record<string, unknown>)[key];\n }, value);\n}\n\nfunction renderValue(value: unknown): string {\n if (value === null || value === undefined) return '';\n if (typeof value === 'string') return value;\n if (typeof value === 'number' || typeof value === 'boolean') return String(value);\n if (Array.isArray(value)) return value.map(renderValue).filter(Boolean).join(', ');\n return '';\n}\n\n/**\n * Fill `{dotted.path}` placeholders from `context`. A placeholder with nothing behind it collapses\n * along with the whitespace in front of it, so \"Reading {key}\" degrades to \"Reading\" rather than\n * printing braces at a person; a filled one keeps the whitespace the author wrote (\"({n} files)\").\n */\nexport function fillTemplate(template: string, context: unknown): string {\n return template\n .replace(/(\\s*)\\{([\\w.]+)\\}/g, (_match, space: string, path: string) => {\n const rendered = renderValue(readPath(context, path));\n return rendered === '' ? '' : `${space}${rendered}`;\n })\n .replace(/\\s{2,}/g, ' ')\n .trim();\n}\n\n/**\n * The sentence for one call: the presentation's `running` or `done` template over the call's input.\n *\n * Nothing here reads the tool's name. A tool the catalog does not describe — added since the catalog\n * loaded, or declared without a presentation — is narrated generically (`fallback`), because the only\n * other thing available to say is its identifier.\n */\nexport function phraseFor(\n presentation: ToolPresentation | undefined,\n input: unknown,\n isSettled: boolean,\n fallback: { running: string; done: string } = { running: 'Working', done: 'Done' },\n): string {\n if (presentation === undefined) return isSettled ? fallback.done : fallback.running;\n const filled = fillTemplate(isSettled ? presentation.done : presentation.running, input);\n // A sentence made only of slots, called before those fields have streamed, leaves nothing. The\n // label is still the server's word for this tool, and a blank line reads as nothing happening.\n return filled === '' ? presentation.label : filled;\n}\n","import type { ToolResultField, ToolResultView } from '@dudousxd/nestjs-agent-core';\nimport { fillTemplate, readPath } from './phrasing.js';\n\n/** One labelled reading of a `metrics` view. */\nexport interface ResolvedReading {\n label: string;\n /** The value as text (`—` for nothing). */\n value: string;\n unit: string | null;\n}\n\n/**\n * A tool's output resolved through its view into plain data a renderer draws — never the payload\n * itself. `null` from {@link resolveResultView} means \"draw nothing\".\n */\nexport type ResolvedResultView =\n | { kind: 'metrics'; readings: ResolvedReading[] }\n | { kind: 'table'; columns: ToolResultField[]; rows: string[][]; empty: string | null }\n | { kind: 'log'; lines: string[] }\n | { kind: 'note'; text: string };\n\nfunction isRecord(value: unknown): value is Record<string, unknown> {\n return typeof value === 'object' && value !== null && !Array.isArray(value);\n}\n\nfunction toText(value: unknown): string {\n if (value === null || value === undefined) return '—';\n if (typeof value === 'string' || typeof value === 'number' || typeof value === 'boolean') {\n return String(value);\n }\n if (Array.isArray(value)) return value.map(toText).join(', ');\n return '—';\n}\n\n/**\n * A view for an output whose tool declared none, from its shape: an array of flat records is a\n * table, an array of strings a log, a flat record a set of readings. `undefined` when nothing fits —\n * a serialized payload is what a person-facing surface exists to avoid, so failing to infer must not\n * fall back to one.\n */\nexport function inferResultView(output: unknown): ToolResultView | undefined {\n if (!isRecord(output)) return undefined;\n for (const [key, value] of Object.entries(output)) {\n if (!Array.isArray(value) || value.length === 0) continue;\n if (value.every((entry) => typeof entry === 'string')) {\n return { kind: 'log', lines: key };\n }\n if (value.every(isRecord)) {\n const first = value[0] as Record<string, unknown>;\n return {\n kind: 'table',\n rows: key,\n columns: Object.keys(first)\n .filter((column) => !isRecord(first[column]))\n .map((column) => ({ path: column, label: column })),\n };\n }\n }\n const fields = Object.entries(output)\n .filter(([, value]) => ['string', 'number', 'boolean'].includes(typeof value))\n .map(([key]) => ({ path: key, label: key }));\n return fields.length > 0 ? { kind: 'metrics', fields } : undefined;\n}\n\n/**\n * Read `output` through `view` (or one inferred from its shape when `view` is omitted and `infer` is\n * on). `null` when there is nothing to draw: an `elsewhere` view, an empty reading set, a missing\n * array. A table whose rows array is present but empty resolves with no rows and its `empty` line.\n */\nexport function resolveResultView(\n output: unknown,\n view: ToolResultView | undefined,\n options: { infer?: boolean } = {},\n): ResolvedResultView | null {\n const resolved = view ?? (options.infer === true ? inferResultView(output) : undefined);\n if (resolved === undefined || resolved.kind === 'elsewhere') return null;\n switch (resolved.kind) {\n case 'note': {\n const text = fillTemplate(resolved.text, output);\n return text === '' ? null : { kind: 'note', text };\n }\n case 'metrics': {\n const readings = resolved.fields\n .map((field) => ({ field, value: readPath(output, field.path) }))\n .filter((entry) => entry.value !== undefined && entry.value !== null)\n .map(({ field, value }) => ({\n label: field.label,\n value: toText(value),\n unit: field.unit ?? null,\n }));\n return readings.length === 0 ? null : { kind: 'metrics', readings };\n }\n case 'log': {\n const lines = readPath(output, resolved.lines);\n if (!Array.isArray(lines) || lines.length === 0) return null;\n return { kind: 'log', lines: lines.map(toText) };\n }\n case 'table': {\n const rows = readPath(output, resolved.rows);\n if (!Array.isArray(rows)) return null;\n return {\n kind: 'table',\n columns: resolved.columns,\n rows: rows.map((row) =>\n resolved.columns.map((column) => toText(readPath(row, column.path))),\n ),\n empty: rows.length === 0 ? (resolved.empty ?? null) : null,\n };\n }\n }\n}\n","import { useCallback, useEffect, useRef, useState } from 'react';\n\nexport interface StickToBottomOptions {\n /**\n * Changes whenever the rendered content grows — the signal to re-pin. A string rather than the\n * message array because a streaming turn mutates in place: the array identity is stable while its\n * last part's text keeps growing.\n */\n contentKey: string;\n /**\n * How far off the bottom (px) still counts as \"at the bottom\". Sub-pixel layout and fractional\n * device ratios leave a residue of a pixel or two after a programmatic scroll, so an exact\n * comparison unpins the view on the very scroll event it just caused.\n */\n threshold?: number;\n}\n\nexport interface StickToBottom {\n /** While true, new content scrolls into view; the user scrolling up turns it off. */\n isAtBottom: boolean;\n /** Whether a \"jump to latest\" affordance is warranted. */\n showJumpToLatest: boolean;\n scrollToBottom: () => void;\n /** Spread onto the scrolling element. Behaviour only — no classes, no styles. */\n getContainerProps: () => {\n ref: (element: HTMLElement | null) => void;\n onScroll: () => void;\n };\n}\n\n/**\n * Follow a streaming transcript only while the reader is already at the bottom. Reading back\n * through history during a stream is the case this exists for: an unconditional scroll-to-bottom\n * yanks the viewport away mid-sentence on every token.\n */\nexport function useStickToBottom({\n contentKey,\n threshold = 32,\n}: StickToBottomOptions): StickToBottom {\n const containerRef = useRef<HTMLElement | null>(null);\n const [isAtBottom, setIsAtBottom] = useState(true);\n\n const measure = useCallback(() => {\n const element = containerRef.current;\n if (!element) {\n return;\n }\n const distance = element.scrollHeight - element.scrollTop - element.clientHeight;\n setIsAtBottom(distance <= threshold);\n }, [threshold]);\n\n const scrollToBottom = useCallback(() => {\n const element = containerRef.current;\n if (!element) {\n return;\n }\n element.scrollTop = element.scrollHeight;\n setIsAtBottom(true);\n }, []);\n\n const setContainer = useCallback(\n (element: HTMLElement | null) => {\n containerRef.current = element;\n if (element) {\n measure();\n }\n },\n [measure],\n );\n\n // Re-pin as content arrives. Guarded on `isAtBottom` so a reader who scrolled up keeps their\n // position for the rest of the stream, and re-pins the moment they scroll back down.\n // biome-ignore lint/correctness/useExhaustiveDependencies: `contentKey` IS the content dependency\n useEffect(() => {\n if (isAtBottom) {\n scrollToBottom();\n }\n }, [contentKey, isAtBottom, scrollToBottom]);\n\n const getContainerProps = useCallback(\n () => ({ ref: setContainer, onScroll: measure }),\n [setContainer, measure],\n );\n\n return {\n isAtBottom,\n showJumpToLatest: !isAtBottom,\n scrollToBottom,\n getContainerProps,\n };\n}\n","import type { UIMessage } from 'ai';\nimport type React from 'react';\nimport type { ChatQueue } from '../queue/model.js';\nimport type { ChatStatus, MessageUsageInfo } from '../transcript/model.js';\nimport {\n type EditSubmitInput,\n type MessageActionInput,\n useChatTranscript,\n} from '../transcript/use-chat-transcript.js';\nimport {\n type MessageItemClassNames,\n MessageItemView,\n type RenderFilesFn,\n type RenderReasoningFn,\n type RenderTextFn,\n type RenderToolGroupFn,\n type RenderToolPartFn,\n type RenderUiFn,\n} from './message-item.js';\n\nexport type { ChatStatus } from '../transcript/model.js';\n\nexport interface MessageListClassNames {\n root?: string;\n empty?: string;\n loadEarlier?: string;\n typing?: string;\n error?: string;\n errorRetry?: string;\n followUps?: string;\n followUpChip?: string;\n /** The block of waiting (queued) messages after the transcript. */\n queue?: string;\n /** One waiting message; it also carries `data-state=\"sending|queued|paused\"`. */\n queuedItem?: string;\n queuedRemove?: string;\n /** The \"queue paused\" line and its resume button. */\n queuePaused?: string;\n queueResume?: string;\n message?: MessageItemClassNames;\n}\n\nexport interface MessageListProps {\n messages: UIMessage[];\n status: ChatStatus;\n renderToolPart?: RenderToolPartFn;\n renderToolGroup?: RenderToolGroupFn;\n renderText?: RenderTextFn;\n /** Render the body of a reasoning run; the disclosure toggle is the list's. */\n renderReasoning?: RenderReasoningFn;\n /** Draw a message's files yourself. Omitted → images inline, everything else a link. */\n renderFiles?: RenderFilesFn;\n /** Draw a server-pushed component (a `ui` stream frame). Omitted → not drawn. */\n renderUi?: RenderUiFn;\n reasoningLabel?: React.ReactNode;\n /** Extra content for one message's action row — e.g. a badge naming which agent answered. */\n getMeta?: (message: UIMessage) => React.ReactNode;\n /**\n * Nobody acts on this list (an audit or shared view): parked approvals and question sets render\n * without their actions, and no fork / edit / regenerate — see `useChatTranscript({ readOnly })`.\n */\n readOnly?: boolean;\n /** When set, every message gets a \"Fork\" affordance calling back with its id. */\n onFork?: (input: MessageActionInput) => void | Promise<void>;\n /** User messages get an inline edit-and-resubmit affordance. */\n editable?: boolean;\n onEditSubmit?: (input: EditSubmitInput) => void | Promise<void>;\n /** The last assistant message gets a \"Regenerate\" affordance. */\n regeneratable?: boolean;\n onRegenerate?: (input: MessageActionInput) => void | Promise<void>;\n /** Per-message resolvers for the usage line and the persisted timestamp. */\n getUsage?: (message: UIMessage) => MessageUsageInfo | null;\n getCreatedAt?: (message: UIMessage) => string | null;\n /** Shown (with example/follow-up chips) when idle and empty. */\n emptyState?: React.ReactNode;\n /** Node rendered while waiting for the first assistant token. */\n typingIndicator?: React.ReactNode;\n /** AI-generated follow-up prompts under the last assistant message. */\n followUps?: string[] | null;\n onFollowUpClick?: (text: string) => void;\n /** Last turn's error — paired with `onRetry`, renders a retry banner. */\n error?: Error | null;\n onRetry?: () => void | Promise<void>;\n /**\n * `chat.queue` — messages sent while a turn was running, drawn after the transcript as pending\n * user messages (with a remove button), and a resume button while the queue is paused.\n */\n queue?: ChatQueue;\n classNames?: MessageListClassNames;\n}\n\n/**\n * Styling-agnostic message list. Keeps the proven UX — windowed render\n * with \"load earlier\", a typing indicator, an inline error+retry banner,\n * and follow-up chips — but ships no styles: drive everything through\n * `classNames` and the `emptyState`/`typingIndicator` slots.\n *\n * Every decision here comes from `useChatTranscript`; the file below it is markup. A host that\n * wants a different layout drives that hook directly and never imports this component.\n */\nexport function MessageList({\n messages,\n status,\n renderToolPart,\n renderToolGroup,\n renderText,\n renderReasoning,\n renderFiles,\n renderUi,\n reasoningLabel,\n getMeta,\n readOnly,\n onFork,\n editable,\n onEditSubmit,\n regeneratable,\n onRegenerate,\n getUsage,\n getCreatedAt,\n emptyState,\n typingIndicator,\n followUps,\n onFollowUpClick,\n error,\n onRetry,\n queue,\n classNames,\n}: MessageListProps) {\n const transcript = useChatTranscript({\n messages,\n status,\n ...(readOnly !== undefined ? { readOnly } : {}),\n ...(onFork ? { onFork } : {}),\n ...(editable !== undefined ? { editable } : {}),\n ...(onEditSubmit ? { onEditSubmit } : {}),\n ...(regeneratable !== undefined ? { regeneratable } : {}),\n ...(onRegenerate ? { onRegenerate } : {}),\n ...(getUsage ? { getUsage } : {}),\n ...(getCreatedAt ? { getCreatedAt } : {}),\n ...(followUps !== undefined ? { followUps } : {}),\n ...(queue !== undefined\n ? { queue: { items: queue.items, paused: queue.paused, remove: queue.remove } }\n : {}),\n });\n\n if (transcript.showEmptyState && transcript.queued.length === 0) {\n return <div className={classNames?.empty}>{emptyState}</div>;\n }\n\n const slots = {\n ...(renderToolPart ? { renderToolPart } : {}),\n ...(renderToolGroup ? { renderToolGroup } : {}),\n ...(renderText ? { renderText } : {}),\n ...(renderReasoning ? { renderReasoning } : {}),\n ...(renderFiles ? { renderFiles } : {}),\n ...(renderUi ? { renderUi } : {}),\n ...(reasoningLabel !== undefined ? { reasoningLabel } : {}),\n ...(classNames?.message ? { classNames: classNames.message } : {}),\n };\n\n return (\n <div className={classNames?.root}>\n {transcript.window.canLoadEarlier ? (\n <button\n type=\"button\"\n className={classNames?.loadEarlier}\n onClick={transcript.window.loadEarlier}\n >\n Load earlier ({transcript.window.hiddenCount} more)\n </button>\n ) : null}\n {transcript.items.map((item) => (\n <MessageItemView\n key={item.id}\n item={item}\n {...slots}\n {...(getMeta ? { meta: getMeta(item.message) } : {})}\n />\n ))}\n {transcript.queued.length > 0 ? (\n <div className={classNames?.queue}>\n {transcript.queued.map((item) => (\n <div key={item.id} className={classNames?.queuedItem} data-state={item.state}>\n <span>{item.text}</span>\n {item.remove.available ? (\n <button\n type=\"button\"\n className={classNames?.queuedRemove}\n onClick={item.remove.run}\n >\n Remove\n </button>\n ) : null}\n </div>\n ))}\n {transcript.queuePaused !== null && queue !== undefined ? (\n <div className={classNames?.queuePaused}>\n <span>Queue paused</span>\n <button\n type=\"button\"\n className={classNames?.queueResume}\n onClick={() => void queue.resume()}\n >\n Resume\n </button>\n </div>\n ) : null}\n </div>\n ) : null}\n {transcript.showTypingIndicator ? (\n <div className={classNames?.typing}>{typingIndicator ?? 'Thinking…'}</div>\n ) : null}\n {error && onRetry ? (\n <div className={classNames?.error}>\n <span>{error.message || \"The assistant didn't respond.\"}</span>\n <button type=\"button\" className={classNames?.errorRetry} onClick={() => void onRetry()}>\n Retry\n </button>\n </div>\n ) : null}\n {transcript.showFollowUps && onFollowUpClick && followUps ? (\n <div className={classNames?.followUps}>\n {followUps.map((text) => (\n <button\n key={text}\n type=\"button\"\n className={classNames?.followUpChip}\n onClick={() => onFollowUpClick(text)}\n >\n {text}\n </button>\n ))}\n </div>\n ) : null}\n </div>\n );\n}\n","/**\n * Languages the dictation mic offers. The Web Speech API expects a\n * BCP-47 tag and does NOT auto-detect — the engine forces incoming\n * audio onto the phonemes of whatever `recognition.lang` is set to, so\n * the host app picks the locale explicitly.\n */\nexport interface SpeechLanguage {\n /** BCP-47 tag fed straight into `SpeechRecognition.lang`. */\n tag: string;\n /** Human label for a dropdown. */\n label: string;\n}\n\nexport const DEFAULT_SPEECH_LANG = 'en-US';\n\nexport const SPEECH_LANGUAGES: ReadonlyArray<SpeechLanguage> = [\n { tag: 'en-US', label: 'English (US)' },\n { tag: 'en-GB', label: 'English (UK)' },\n { tag: 'pt-BR', label: 'Portuguese (Brazil)' },\n { tag: 'es-ES', label: 'Spanish (Spain)' },\n];\n\nconst STORAGE_KEY = 'nestjs-agent-chat-speech-lang';\n\n/**\n * Recover the last picked language from localStorage (sync — safe at\n * `useState` init). Falls back to the default if nothing's stored or the\n * stored tag isn't in the offered list.\n */\nexport function loadStoredSpeechLang(): string {\n if (typeof window === 'undefined') return DEFAULT_SPEECH_LANG;\n try {\n const raw = window.localStorage.getItem(STORAGE_KEY);\n if (raw && SPEECH_LANGUAGES.some((language) => language.tag === raw)) {\n return raw;\n }\n } catch {\n /* localStorage disabled (private window / webview) — use the default */\n }\n return DEFAULT_SPEECH_LANG;\n}\n\nexport function persistSpeechLang(tag: string): void {\n if (typeof window === 'undefined') return;\n try {\n window.localStorage.setItem(STORAGE_KEY, tag);\n } catch {\n /* same fallback — silently skip persistence */\n }\n}\n","/** One completion a source offers. */\nexport interface AutocompleteItem {\n /** Unique within its source. */\n id: string;\n /** What the reader sees, and what the default filter matches against. */\n label: string;\n /** What replaces the typed token. Defaults to `label` — set it when the label is prose. */\n value?: string;\n description?: string;\n /**\n * A short trailing note a renderer right-aligns — where this came from, a keyboard shortcut, a\n * type. Deliberately outside the default filter: typing a query should narrow by what the item\n * IS, not by an aside about it.\n */\n hint?: string;\n /** Whatever the host's renderer needs: an icon key, a scope, the row this came from. */\n data?: unknown;\n}\n\n/**\n * Where a trigger character is allowed to open the menu.\n *\n * - `'start'` — only as the very first character of the input. This is the rule a slash command\n * wants: `/deploy` is a command, `src/foo` and `and/or` are not.\n * - `'word'` — at the start of any word: the input's start, or immediately after whitespace. This\n * is the rule a mention wants: `@ada` in the middle of a sentence is a mention, `ada@example` is\n * an address.\n *\n * There is no default on purpose. Which rule a trigger takes is the difference between an\n * autocomplete that feels invisible and one that fires while somebody types a file path.\n */\nexport type TriggerPosition = 'start' | 'word';\n\nexport interface AutocompleteSource {\n /** Identifies the source to the host; also names the listbox when `label` is omitted. */\n id: string;\n /** Human-facing name for the open menu. */\n label?: string;\n /** The single character that opens this source. Two sources never share one. */\n trigger: string;\n position: TriggerPosition;\n /**\n * The candidates for `query`. May be async; a result that arrives after the query moved on is\n * discarded, and `signal` aborts the request that produced it. Throwing is allowed — the menu\n * reports the failure and typing carries on.\n */\n getItems: (\n query: string,\n signal: AbortSignal,\n ) => AutocompleteItem[] | Promise<AutocompleteItem[]>;\n /**\n * Narrow what `getItems` returned. Defaults to {@link filterAutocompleteItems}. A source that\n * already filtered server-side — a fuzzy match this one would undo — passes `(items) => items`.\n */\n filter?: (items: AutocompleteItem[], query: string) => AutocompleteItem[];\n /**\n * Appended after the inserted value. Defaults to a single space, which both closes the menu and\n * puts the caret where the command's argument goes.\n */\n insertSuffix?: string;\n}\n\n/** A trigger character found before the caret, with the token being typed after it. */\nexport interface TriggerMatch {\n source: AutocompleteSource;\n /** Index of the trigger character itself. */\n index: number;\n /** The text between the trigger and the caret. Never contains whitespace. */\n query: string;\n}\n\nexport interface CompletionEdit {\n text: string;\n caret: number;\n}\n\nconst WHITESPACE = /\\s/;\n\n/**\n * The trigger token the caret currently sits in, or `null`. Scans backwards from the caret and\n * stops at the first whitespace, so a token is always one unbroken word: typing a space is what\n * ends a command and hands the rest of the line back to the user as prose.\n */\nexport function findActiveTrigger(\n text: string,\n caret: number,\n sources: readonly AutocompleteSource[],\n): TriggerMatch | null {\n const end = Math.max(0, Math.min(caret, text.length));\n for (let index = end - 1; index >= 0; index--) {\n const char = text[index];\n if (char === undefined || WHITESPACE.test(char)) {\n return null;\n }\n const source = sources.find((candidate) => candidate.trigger === char);\n // A trigger that fails its own position rule is just a character in the token — `@ad/x` is one\n // mention query, not a command — so the scan continues past it rather than giving up.\n if (source && isAllowedAt(text, index, source.position)) {\n return { source, index, query: text.slice(index + 1, end) };\n }\n }\n return null;\n}\n\nfunction isAllowedAt(text: string, index: number, position: TriggerPosition): boolean {\n if (index === 0) {\n return true;\n }\n if (position === 'start') {\n return false;\n }\n const previous = text[index - 1];\n return previous !== undefined && WHITESPACE.test(previous);\n}\n\n/** Case-insensitive substring over label and description. The default when a source names none. */\nexport function filterAutocompleteItems(\n items: readonly AutocompleteItem[],\n query: string,\n): AutocompleteItem[] {\n // An empty needle is a substring of everything, so it needs no branch of its own.\n const needle = query.trim().toLowerCase();\n return items.filter(\n (item) =>\n item.label.toLowerCase().includes(needle) ||\n (item.description?.toLowerCase().includes(needle) ?? false),\n );\n}\n\n/**\n * The text and caret after accepting `item`. The trigger character stays — `/deploy ` is what the\n * user meant to type — and everything after the caret is left untouched, so completing a token in\n * the middle of a sentence does not eat the rest of it.\n */\nexport function applyCompletion(\n text: string,\n caret: number,\n match: TriggerMatch,\n item: AutocompleteItem,\n): CompletionEdit {\n const end = Math.max(match.index, Math.min(caret, text.length));\n const inserted = `${match.source.trigger}${item.value ?? item.label}${match.source.insertSuffix ?? ' '}`;\n return {\n text: text.slice(0, match.index) + inserted + text.slice(end),\n caret: match.index + inserted.length,\n };\n}\n","import type { SkillCatalogEntry } from '@dudousxd/nestjs-agent-core';\nimport { type AgentBackend, AgentBackendUnsupportedError } from '../backend.js';\nimport type { AutocompleteItem, AutocompleteSource } from './model.js';\n\n/** What each item carries on `data`, so a renderer can show where a skill came from. */\nexport interface SkillSuggestionData {\n /** The scope token it resolved from — the provenance a user is entitled to see. */\n scope: string;\n /** Scope tokens of same-named skills this one outranks, widest last. */\n shadows?: string[];\n}\n\nexport interface SkillsSourceOptions {\n /** Any backend with `listSkills` — `useAgentBackend()`, or `useAgentChat().backend`. */\n backend: Pick<AgentBackend, 'listSkills'>;\n /**\n * Read at query time, not captured once: a threadless chat learns its id only when the backend\n * creates one on the first send, and a skill may be scoped to a conversation.\n */\n getThreadId?: () => string | undefined;\n /** Default `/`. */\n trigger?: string;\n /** Default `Skills`. */\n label?: string;\n}\n\n/**\n * `GET /agent/skills` as an autocomplete source — the concrete one behind `/`, and an example of\n * the shape any other takes. `position: 'start'` because a skill is a command: `/deploy` is one and\n * `src/foo` is a path.\n */\nexport function createSkillsSource(options: SkillsSourceOptions): AutocompleteSource {\n // One read per thread. The endpoint answers with the whole scope-resolved list rather than a\n // search, so asking again per keystroke would fetch identical rows only to filter them locally.\n // A failed read is forgotten, so the next keystroke retries instead of caching the outage.\n //\n // The order it arrives in IS the precedence — most specific scope first, then alphabetical — and\n // is passed through untouched. The type-ahead filter narrows this list by what the user typed; it\n // never re-derives which skills apply, which is the server's answer and the model's too.\n const byThread = new Map<string, Promise<AutocompleteItem[]>>();\n\n return {\n id: 'skills',\n label: options.label ?? 'Skills',\n trigger: options.trigger ?? '/',\n position: 'start',\n getItems: () => {\n const threadId = options.getThreadId?.();\n const key = threadId ?? '';\n const cached = byThread.get(key);\n if (cached) {\n return cached;\n }\n const listSkills = options.backend.listSkills;\n if (listSkills === undefined) {\n return Promise.reject(new AgentBackendUnsupportedError('listSkills'));\n }\n const pending = listSkills\n .call(options.backend, threadId)\n .then((entries) => entries.map(toItem))\n .catch((error: unknown) => {\n byThread.delete(key);\n throw error;\n });\n byThread.set(key, pending);\n return pending;\n },\n };\n}\n\nfunction toItem(entry: SkillCatalogEntry): AutocompleteItem {\n const data: SkillSuggestionData = {\n scope: entry.scope,\n ...(entry.shadows !== undefined ? { shadows: entry.shadows } : {}),\n };\n return {\n id: entry.name,\n label: entry.name,\n description: entry.description,\n // `shadows` is present only on a conflict, so saying \"overrides\" is never noise: without it a\n // user cannot tell \"there is no org default\" from \"there is one and mine wins\".\n hint:\n entry.shadows === undefined\n ? entry.scope\n : `${entry.scope} · overrides ${entry.shadows.join(', ')}`,\n data,\n };\n}\n","import type React from 'react';\nimport { useCallback, useEffect, useId, useLayoutEffect, useMemo, useRef, useState } from 'react';\nimport {\n type AutocompleteItem,\n type AutocompleteSource,\n type TriggerMatch,\n applyCompletion,\n filterAutocompleteItems,\n findActiveTrigger,\n} from './model.js';\n\nexport interface UseComposerAutocompleteOptions {\n /** The composer's draft. Accepting an item rewrites it through `onValueChange`. */\n value: string;\n onValueChange: (next: string) => void;\n /**\n * What can be completed, and after which character. The composer knows nothing about what a\n * source offers — a skills list and an agent mention are the same shape.\n */\n sources: readonly AutocompleteSource[];\n /** A source that threw. The menu reports it; typing is unaffected either way. */\n onError?: (error: unknown, source: AutocompleteSource) => void;\n /** Tab accepts the highlighted item, as Enter does. Default `true`. */\n acceptOnTab?: boolean;\n /** Base for the generated `id`s the ARIA wiring points at. */\n id?: string;\n}\n\nexport interface AutocompleteInputProps {\n ref: (element: HTMLTextAreaElement | HTMLInputElement | null) => void;\n onChange: (event: React.ChangeEvent<HTMLTextAreaElement | HTMLInputElement>) => void;\n onKeyDown: (event: React.KeyboardEvent<HTMLTextAreaElement | HTMLInputElement>) => void;\n onSelect: (event: React.SyntheticEvent<HTMLTextAreaElement | HTMLInputElement>) => void;\n onClick: (event: React.MouseEvent<HTMLTextAreaElement | HTMLInputElement>) => void;\n role: 'combobox';\n 'aria-expanded': boolean;\n 'aria-autocomplete': 'list';\n 'aria-haspopup': 'listbox';\n 'aria-controls'?: string;\n 'aria-activedescendant'?: string;\n}\n\nexport interface AutocompleteListboxProps {\n id: string;\n role: 'listbox';\n 'aria-label': string;\n}\n\nexport interface AutocompleteOptionProps {\n id: string;\n role: 'option';\n 'aria-selected': boolean;\n}\n\nexport interface ComposerAutocomplete {\n isOpen: boolean;\n /** The source behind the open menu, so a renderer can group or label by it. */\n source: AutocompleteSource | null;\n trigger: string | null;\n /** The text between the trigger and the caret. */\n query: string;\n items: AutocompleteItem[];\n activeIndex: number;\n activeItem: AutocompleteItem | null;\n /** An async source has been asked and has not answered yet. */\n isLoading: boolean;\n /** The message from a source that threw. The menu stays open and empty. */\n error: string | null;\n highlight: (index: number) => void;\n /** Wraps at both ends, so ↓ from the last item lands on the first. */\n moveHighlight: (delta: number) => void;\n /** Insert an item — the highlighted one by default. A click handler calls this directly. */\n accept: (item?: AutocompleteItem) => void;\n /** Close for the token being typed, without touching the text. */\n dismiss: () => void;\n getInputProps: () => AutocompleteInputProps;\n getListboxProps: () => AutocompleteListboxProps;\n getOptionProps: (index: number) => AutocompleteOptionProps;\n}\n\n/**\n * The state machine behind a `/`-style autocomplete in a chat composer: which trigger the caret is\n * inside, what the query is, which items answer it, which one is highlighted, and what accepting\n * one does to the text and the caret. It renders nothing and knows nothing about skills, agents or\n * threads — a host supplies sources, and the same machine drives `@` as drives `/`.\n *\n * The keys the open menu owns (↑ ↓ Enter Tab Escape) are consumed with `preventDefault`, which is\n * how a composer that sends on Enter knows to stand down: call this handler first and return early\n * when the event comes back `defaultPrevented`.\n */\nexport function useComposerAutocomplete(\n options: UseComposerAutocompleteOptions,\n): ComposerAutocomplete {\n const { value, sources, acceptOnTab = true } = options;\n\n const latest = useRef(options);\n latest.current = options;\n\n const inputRef = useRef<HTMLTextAreaElement | HTMLInputElement | null>(null);\n const [caret, setCaret] = useState(value.length);\n const [items, setItems] = useState<AutocompleteItem[]>([]);\n const [isLoading, setLoading] = useState(false);\n const [error, setError] = useState<string | null>(null);\n const [activeIndex, setActiveIndex] = useState(0);\n // The trigger index Escape closed. Cleared the moment the caret leaves that token, so deleting\n // the trigger and typing it again offers the menu rather than staying silently dismissed.\n const [dismissedIndex, setDismissedIndex] = useState<number | null>(null);\n\n // Clamped: a host that resets the draft externally leaves the caret past the end of the text.\n const safeCaret = Math.min(caret, value.length);\n const match = useMemo(\n () => findActiveTrigger(value, safeCaret, sources),\n [value, safeCaret, sources],\n );\n const isActive = match !== null && dismissedIndex !== match.index;\n\n const matchRef = useRef<TriggerMatch | null>(match);\n matchRef.current = match;\n const caretRef = useRef(safeCaret);\n caretRef.current = safeCaret;\n const itemsRef = useRef(items);\n itemsRef.current = items;\n const activeIndexRef = useRef(activeIndex);\n activeIndexRef.current = activeIndex;\n\n // Identifies the question being asked, so a re-render that changes neither the source nor the\n // query does not re-ask — an async source would otherwise fetch on every unrelated render. The\n // NUL separator cannot appear in either half, so no pair of them collides.\n const requestKey = isActive && match ? `${match.source.id}\\u0000${match.query}` : null;\n\n useEffect(() => {\n const current = matchRef.current;\n if (requestKey === null || current === null) {\n setItems([]);\n setLoading(false);\n setError(null);\n return;\n }\n const { source, query } = current;\n const controller = new AbortController();\n // The cleanup below runs before the next query's effect, so a slow answer to an abandoned\n // query finds `superseded` already true and is dropped instead of overwriting a newer list.\n let superseded = false;\n const settle = (next: AutocompleteItem[]) => {\n if (superseded) return;\n setItems((source.filter ?? filterAutocompleteItems)(next, query));\n setActiveIndex(0);\n setLoading(false);\n setError(null);\n };\n const failed = (cause: unknown) => {\n if (superseded) return;\n setItems([]);\n setLoading(false);\n setError(cause instanceof Error ? cause.message : 'Could not load suggestions');\n latest.current.onError?.(cause, source);\n };\n\n let result: AutocompleteItem[] | Promise<AutocompleteItem[]>;\n try {\n result = source.getItems(query, controller.signal);\n } catch (cause) {\n failed(cause);\n return;\n }\n // A static source answers in the same tick: settling synchronously spares the list a frame of\n // emptiness between the trigger being typed and its items appearing.\n if (!isPromise(result)) {\n settle(result);\n return;\n }\n setLoading(true);\n setError(null);\n result.then(settle, failed);\n return () => {\n superseded = true;\n controller.abort();\n };\n }, [requestKey]);\n\n // Open the moment the caret is inside a live trigger token, before any items are in: an empty\n // menu that says \"no matches\" is an answer, whereas a menu that never appears reads as broken.\n // The keys the menu owns are still only taken when there is something to take them for.\n const isOpen = isActive;\n const activeItem = isOpen ? (items[activeIndex] ?? null) : null;\n\n const reactId = useId();\n const listboxId = options.id ?? `agent-autocomplete-${reactId}`;\n const optionId = useCallback((index: number) => `${listboxId}-option-${index}`, [listboxId]);\n\n const highlight = useCallback((index: number) => {\n const total = itemsRef.current.length;\n if (total === 0) return;\n setActiveIndex(((index % total) + total) % total);\n }, []);\n\n const moveHighlight = useCallback(\n (delta: number) => highlight(activeIndexRef.current + delta),\n [highlight],\n );\n\n const dismiss = useCallback(() => {\n const current = matchRef.current;\n if (current) setDismissedIndex(current.index);\n }, []);\n\n // Set after an accept and consumed on the next commit: the textarea is controlled, so React\n // writes the new value only once this render lands and any caret set before that is overwritten.\n const pendingCaret = useRef<number | null>(null);\n\n const accept = useCallback((item?: AutocompleteItem) => {\n const current = matchRef.current;\n if (!current) return;\n const chosen = item ?? itemsRef.current[activeIndexRef.current];\n if (!chosen) return;\n const edit = applyCompletion(latest.current.value, caretRef.current, current, chosen);\n latest.current.onValueChange(edit.text);\n setCaret(edit.caret);\n setDismissedIndex(null);\n pendingCaret.current = edit.caret;\n }, []);\n\n useLayoutEffect(() => {\n const position = pendingCaret.current;\n if (position === null) return;\n pendingCaret.current = null;\n inputRef.current?.setSelectionRange(position, position);\n });\n\n const readCaret = useCallback((element: HTMLTextAreaElement | HTMLInputElement) => {\n setCaret(element.selectionStart ?? element.value.length);\n }, []);\n\n const onKeyDown = useCallback(\n (event: React.KeyboardEvent<HTMLTextAreaElement | HTMLInputElement>) => {\n if (!isOpen) return;\n const hasItems = itemsRef.current.length > 0;\n switch (event.key) {\n case 'ArrowDown':\n if (!hasItems) return;\n event.preventDefault();\n moveHighlight(1);\n return;\n case 'ArrowUp':\n if (!hasItems) return;\n event.preventDefault();\n moveHighlight(-1);\n return;\n case 'Enter':\n if (!hasItems) return;\n event.preventDefault();\n accept();\n return;\n case 'Tab':\n // Shift+Tab stays a backwards focus move: a completion menu is not a focus trap.\n if (!acceptOnTab || event.shiftKey || !hasItems) return;\n event.preventDefault();\n accept();\n return;\n case 'Escape':\n event.preventDefault();\n dismiss();\n return;\n default:\n return;\n }\n },\n [isOpen, acceptOnTab, accept, dismiss, moveHighlight],\n );\n\n const onChange = useCallback(\n (event: React.ChangeEvent<HTMLTextAreaElement | HTMLInputElement>) => {\n readCaret(event.target);\n // A token the user has walked away from is no longer dismissed — it is gone.\n const next = findActiveTrigger(\n event.target.value,\n event.target.selectionStart ?? event.target.value.length,\n latest.current.sources,\n );\n setDismissedIndex((current) =>\n current !== null && next?.index === current ? current : null,\n );\n },\n [readCaret],\n );\n\n const onSelect = useCallback(\n (event: React.SyntheticEvent<HTMLTextAreaElement | HTMLInputElement>) =>\n readCaret(event.currentTarget),\n [readCaret],\n );\n\n const onClick = useCallback(\n (event: React.MouseEvent<HTMLTextAreaElement | HTMLInputElement>) =>\n readCaret(event.currentTarget),\n [readCaret],\n );\n\n const setInput = useCallback((element: HTMLTextAreaElement | HTMLInputElement | null) => {\n inputRef.current = element;\n }, []);\n\n const getInputProps = useCallback(\n (): AutocompleteInputProps => ({\n ref: setInput,\n onChange,\n onKeyDown,\n onSelect,\n onClick,\n role: 'combobox',\n 'aria-expanded': isOpen,\n 'aria-autocomplete': 'list',\n 'aria-haspopup': 'listbox',\n ...(isOpen ? { 'aria-controls': listboxId } : {}),\n ...(activeItem ? { 'aria-activedescendant': optionId(activeIndex) } : {}),\n }),\n [\n setInput,\n onChange,\n onKeyDown,\n onSelect,\n onClick,\n isOpen,\n listboxId,\n activeItem,\n activeIndex,\n optionId,\n ],\n );\n\n const getListboxProps = useCallback(\n (): AutocompleteListboxProps => ({\n id: listboxId,\n role: 'listbox',\n 'aria-label': match?.source.label ?? match?.source.id ?? 'Suggestions',\n }),\n [listboxId, match],\n );\n\n const getOptionProps = useCallback(\n (index: number): AutocompleteOptionProps => ({\n id: optionId(index),\n role: 'option',\n 'aria-selected': index === activeIndex,\n }),\n [optionId, activeIndex],\n );\n\n return {\n isOpen,\n source: isOpen && match ? match.source : null,\n trigger: isOpen && match ? match.source.trigger : null,\n query: match?.query ?? '',\n items,\n activeIndex,\n activeItem,\n isLoading,\n error,\n highlight,\n moveHighlight,\n accept,\n dismiss,\n getInputProps,\n getListboxProps,\n getOptionProps,\n };\n}\n\nfunction isPromise<T>(value: T[] | Promise<T[]>): value is Promise<T[]> {\n return typeof (value as Promise<T[]>).then === 'function';\n}\n","import { ALL_AGENTS, type ToolCatalogEntry } from '@dudousxd/nestjs-agent-core';\n\nexport { ALL_AGENTS };\nimport { useCallback, useEffect, useMemo, useState } from 'react';\nimport { type AgentBackend, AgentBackendUnsupportedError } from '../backend.js';\nimport { useAgentBackend } from '../provider.js';\nimport { type ToolCatalog, toolCatalogFrom } from './phrasing.js';\n\n/** What the catalog needs of a backend. */\ntype ToolsBackend = Pick<AgentBackend, 'listTools'>;\n\nexport interface UseToolCatalogOptions {\n /**\n * The backend to ask. Default: the enclosing `<AgentProvider>`'s. Must be STABLE across renders\n * (the shared copy is keyed by it): a backend constructed inline refetches every render.\n */\n backend?: ToolsBackend;\n /**\n * The agent whose tools to list. Omitted → the server's default agent. {@link ALL_AGENTS} (`'*'`)\n * → every tool the actor reaches through any agent, each once — for an app with several agents\n * whose conversations one surface shows.\n */\n agent?: string;\n /** `false` holds the request (e.g. until the user is signed in). Default `true`. */\n enabled?: boolean;\n}\n\nexport interface ToolCatalogState {\n /** Tool name → presentation, for the tools that declared one. `{}` until loaded. */\n catalog: ToolCatalog;\n /** Everything `GET <base>/tools` returned, kinds included. */\n entries: ToolCatalogEntry[];\n isLoading: boolean;\n error: Error | null;\n /** Drop the shared copy and ask again. */\n refresh: () => void;\n}\n\n/**\n * One request per backend + agent for the whole page: the catalog is a deployment-time constant, so\n * every component that narrates a tool call can call this hook and share the answer instead of\n * putting a request between a tool starting and the sentence that describes it. A failed request\n * is not cached, so the next mount retries.\n */\nconst shared = new WeakMap<ToolsBackend, Map<string, Promise<ToolCatalogEntry[]>>>();\n\nfunction load(client: ToolsBackend, agent: string | undefined): Promise<ToolCatalogEntry[]> {\n let byAgent = shared.get(client);\n if (byAgent === undefined) {\n byAgent = new Map();\n shared.set(client, byAgent);\n }\n const key = agent ?? '';\n const cached = byAgent.get(key);\n if (cached !== undefined) return cached;\n if (client.listTools === undefined) {\n return Promise.reject(new AgentBackendUnsupportedError('listTools'));\n }\n const request = client.listTools(agent).catch((error: unknown) => {\n byAgent.delete(key);\n throw error;\n });\n byAgent.set(key, request);\n return request;\n}\n\n/**\n * The server-declared presentation of the tools this actor can reach (`GET <base>/tools`), for\n * `phraseFor`, `describeToolCall` and `groupToolActivity` — or pass `catalog` to\n * `useChatTranscript({ toolCatalog })` and read the phrases off the transcript's calls.\n */\nexport function useToolCatalog(options: UseToolCatalogOptions = {}): ToolCatalogState {\n const { agent, enabled = true } = options;\n const client = useAgentBackend(options.backend as AgentBackend | undefined);\n const [entries, setEntries] = useState<ToolCatalogEntry[]>([]);\n const [isLoading, setLoading] = useState(enabled);\n const [error, setError] = useState<Error | null>(null);\n const [generation, setGeneration] = useState(0);\n\n // biome-ignore lint/correctness/useExhaustiveDependencies: `generation` is the refresh trigger\n useEffect(() => {\n if (!enabled) {\n setLoading(false);\n return;\n }\n let cancelled = false;\n setLoading(true);\n load(client, agent).then(\n (loaded) => {\n if (cancelled) return;\n setEntries(Array.isArray(loaded) ? loaded : []);\n setError(null);\n setLoading(false);\n },\n (failure: unknown) => {\n if (cancelled) return;\n setError(failure instanceof Error ? failure : new Error(String(failure)));\n setLoading(false);\n },\n );\n return () => {\n cancelled = true;\n };\n }, [client, agent, enabled, generation]);\n\n const refresh = useCallback(() => {\n shared.get(client)?.delete(agent ?? '');\n setGeneration((current) => current + 1);\n }, [client, agent]);\n\n const catalog = useMemo(() => toolCatalogFrom(entries), [entries]);\n return { catalog, entries, isLoading, error, refresh };\n}\n","import { useEffect, useRef, useState } from 'react';\n\nexport interface ApprovalCountdown {\n /** Milliseconds until the request lapses, floored at 0; `null` when it never does. */\n remainingMs: number | null;\n /** The instant has passed. Always `false` for a request with no expiry. */\n isExpired: boolean;\n}\n\nexport interface UseApprovalCountdownOptions {\n /** How often the value re-renders while counting. Default 1000 — a seconds label needs no more. */\n intervalMs?: number;\n /** Injectable clock for tests. */\n now?: () => number;\n}\n\n/** What {@link useApprovalCountdown} reads for `expiresAt` at `now`, without the ticking. */\nexport function approvalCountdown(\n expiresAt: string | null | undefined,\n now: number = Date.now(),\n): ApprovalCountdown {\n const deadline = expiresAt == null ? Number.NaN : Date.parse(expiresAt);\n if (!Number.isFinite(deadline)) {\n return { remainingMs: null, isExpired: false };\n }\n const remainingMs = Math.max(0, deadline - now);\n return { remainingMs, isExpired: remainingMs === 0 };\n}\n\n/**\n * Time left on an approval request (`call.approval.expiresAt`), ticking until it lapses and then\n * holding at zero. Headless: pair `remainingMs` with `formatElapsed` or any label of your own, and\n * use `isExpired` to stop offering buttons the server would refuse (`410 Gone`). The server stays\n * the authority — a lapse is final only once the call settles `expired`.\n */\nexport function useApprovalCountdown(\n expiresAt: string | null | undefined,\n options: UseApprovalCountdownOptions = {},\n): ApprovalCountdown {\n const { intervalMs = 1000 } = options;\n const nowRef = useRef(options.now ?? Date.now);\n nowRef.current = options.now ?? Date.now;\n const [state, setState] = useState(() => approvalCountdown(expiresAt, nowRef.current()));\n\n useEffect(() => {\n const read = () => approvalCountdown(expiresAt, nowRef.current());\n const first = read();\n setState(first);\n if (first.remainingMs === null || first.isExpired) {\n return;\n }\n const timer = setInterval(() => {\n const next = read();\n setState(next);\n if (next.isExpired) clearInterval(timer);\n }, intervalMs);\n return () => clearInterval(timer);\n }, [expiresAt, intervalMs]);\n\n return state;\n}\n","import { DEFAULT_REFUSAL_REASON } from '@dudousxd/nestjs-agent-core';\nimport type { StoredMessage, ToolResult } from '@dudousxd/nestjs-agent-core';\nimport type { UIMessage } from 'ai';\nimport { reasoningDurationMetadata } from './reasoning/timing.js';\nimport type { AgentMessageMetadata } from './stored-thread-to-ui-messages.js';\n\n/**\n * Convert a persisted `StoredMessage` (the agent-lib's on-disk shape) into an AI SDK v7\n * `UIMessage` so a loaded thread can seed `useChat`'s `initialMessages` / `messages`.\n *\n * The lib stores a message as flat `content` text plus `toolCalls`/`toolResults` arrays; the SDK\n * renders from `parts`. This maps, in this order:\n * - `reasoning` → a `reasoning` part (state `done`) BEFORE the text, as it streamed; its\n * `reasoningMs` rides `providerMetadata.agent.reasoningMs`, where the\n * live transport stamps it too.\n * - `content` → a single `text` part (skipped when empty).\n * - each `attachment` → a `file` part (image/PDF) so the user bubble re-renders its\n * thumbnails on a reloaded thread.\n * - each `ui` component → a `data-ui` part keyed by the component id — the same part a live\n * `ui` stream frame becomes.\n * - each `approval` → a `data-approval-requested` part keyed by the call id (who decides,\n * until when) and, once decided, a `data-approval-settled` one — the\n * same parts the live `approval-requested`/`approval-settled` frames\n * become, so the transcript folds both into `call.approval` either way.\n * - each `toolCall` → a `tool-<name>` part, pairing its `toolResult` (matched by id):\n * - a result found → `output-available` state, carrying `output`; `output-denied` when a\n * person declined it; `output-error` (carrying `errorText`) when it\n * failed — the states the live stream leaves the part in.\n * - no result found → `input-available` state (the call never finished, e.g. the run was\n * interrupted) — `output` is omitted, never a fabricated value.\n * When the store reports the tool's kind (`'read' | 'action'`), it rides along as\n * `toolMetadata.toolKind` so a UI can render an approval affordance for `action` tools\n * without hardcoding tool-name sets, matching how live-streamed tool parts carry it.\n *\n * Live streaming still arrives as fully-typed SDK tool parts (see `AgentChatTransport`); this\n * converter only feeds replayed history, so the tool cards render the same either way.\n */\n/**\n * Did a person decline this call? `denied` is what the loop sets today. The `output.rejected` shape\n * is how a refusal was recorded before that flag existed, and threads holding those are still read\n * back — so both count, and a thread from either era reloads as the same part.\n */\nfunction isRefusal(result: ToolResult): boolean {\n if (result.denied === true) {\n return true;\n }\n const { output } = result;\n return (\n output !== null &&\n typeof output === 'object' &&\n 'rejected' in output &&\n (output as { rejected: unknown }).rejected === true\n );\n}\n\n/** The reason given when declining, when one was given. */\nfunction refusalReason(result: ToolResult): string | undefined {\n const { output } = result;\n if (output !== null && typeof output === 'object' && 'reason' in output) {\n const reason = (output as { reason: unknown }).reason;\n return typeof reason === 'string' && reason !== DEFAULT_REFUSAL_REASON ? reason : undefined;\n }\n return undefined;\n}\n\nexport function storedMessageToUiMessage(message: StoredMessage): UIMessage {\n const parts: UIMessage['parts'] = [];\n\n if (message.reasoning) {\n parts.push({\n type: 'reasoning',\n text: message.reasoning,\n state: 'done',\n ...(message.reasoningMs !== undefined\n ? { providerMetadata: reasoningDurationMetadata(message.reasoningMs) }\n : {}),\n });\n }\n\n if (message.content) {\n parts.push({ type: 'text', text: message.content });\n }\n\n for (const attachment of message.attachments ?? []) {\n parts.push({\n type: 'file',\n mediaType: attachment.contentType,\n filename: attachment.name,\n url: attachment.url,\n // The stored id rides along, so a replayed file can be referenced again (`messageFiles`).\n providerMetadata: { agent: { mediaId: attachment.mediaId } },\n });\n }\n\n // A component a tool pushed (`toolCallId`) goes right after that call's tool part, where the live\n // stream put it; the rest keep their place ahead of the calls.\n const toolCallIds = new Set((message.toolCalls ?? []).map((call) => call.id));\n const pushedByCall = new Map<string, UIMessage['parts']>();\n for (const component of message.ui ?? []) {\n const part: UIMessage['parts'][number] = {\n type: 'data-ui',\n id: component.id,\n data: {\n id: component.id,\n component: component.component,\n props: component.props,\n ...(component.componentVersions !== undefined\n ? { componentVersions: component.componentVersions }\n : {}),\n ...(component.fallbackText !== undefined ? { fallbackText: component.fallbackText } : {}),\n ...(component.version !== undefined ? { version: component.version } : {}),\n ...(component.toolCallId !== undefined ? { toolCallId: component.toolCallId } : {}),\n },\n };\n if (component.toolCallId !== undefined && toolCallIds.has(component.toolCallId)) {\n const list = pushedByCall.get(component.toolCallId) ?? [];\n list.push(part);\n pushedByCall.set(component.toolCallId, list);\n } else {\n parts.push(part);\n }\n }\n\n for (const approval of message.approvals ?? []) {\n parts.push({\n type: 'data-approval-requested',\n id: approval.toolCallId,\n data: {\n id: approval.toolCallId,\n approver: approval.approver,\n ...(approval.target !== undefined\n ? { target: approval.target }\n : approval.proposalId !== undefined\n ? { target: { kind: 'proposal', proposalId: approval.proposalId } }\n : {}),\n ...(approval.confirmation !== undefined ? { confirmation: approval.confirmation } : {}),\n ...(approval.expiresAt !== undefined ? { expiresAt: approval.expiresAt } : {}),\n },\n });\n if (approval.status !== 'pending') {\n parts.push({\n type: 'data-approval-settled',\n id: approval.toolCallId,\n data: {\n id: approval.toolCallId,\n status: approval.status,\n ...(approval.decidedBy !== undefined ? { decidedBy: approval.decidedBy } : {}),\n ...(approval.decidedVia !== undefined ? { decidedVia: approval.decidedVia } : {}),\n ...(approval.remember === true ? { remember: true } : {}),\n ...(approval.reason !== undefined ? { reason: approval.reason } : {}),\n },\n });\n }\n }\n\n for (const call of message.toolCalls ?? []) {\n const result = message.toolResults?.find((candidate) => candidate.id === call.id);\n // `call.kind` — the store's `'read' | 'action'` classification, once it lands there\n // (parallel to `RecordToolCallInput.toolType` and the stream's `toolKind`).\n const toolKind = call.kind;\n // `parentId` nests a replayed call under its parent, as the live frames did.\n const toolMetadata = {\n ...(toolKind !== undefined ? { toolKind } : {}),\n ...(call.parentId !== undefined ? { parentId: call.parentId } : {}),\n };\n parts.push({\n type: `tool-${call.name}`,\n toolCallId: call.id,\n ...(Object.keys(toolMetadata).length > 0 ? { toolMetadata } : {}),\n ...(result !== undefined\n ? isRefusal(result)\n ? {\n // A declined action is NOT an available output. Reloading a thread used to bring one\n // back as `output-available` carrying `{ rejected: true }`, which a card reads as a\n // result — so the action a person refused was drawn, after a refresh, as one that\n // had been carried out.\n state: 'output-denied',\n input: call.input,\n approval: {\n id: call.id,\n approved: false,\n ...(refusalReason(result) !== undefined\n ? { reason: refusalReason(result) as string }\n : {}),\n },\n }\n : typeof result.error === 'string' && result.error !== ''\n ? {\n // A call that FAILED — the tool threw, its input was refused, or its turn died\n // before it was settled — is not an available output either. The live stream says\n // so with `tool-output-error`; a reloaded thread has to say the same, or the card of\n // an action that never ran comes back reading as one that completed.\n state: 'output-error',\n input: call.input,\n errorText: result.error,\n }\n : { state: 'output-available', input: call.input, output: result.output }\n : { state: 'input-available', input: call.input }),\n });\n parts.push(...(pushedByCall.get(call.id) ?? []));\n }\n\n const metadata: AgentMessageMetadata = {\n // The host's own facts first: the library's keys win on a clash.\n ...message.metadata,\n ...(message.actionProposalOutcome === undefined\n ? {}\n : { actionProposalOutcomeId: message.actionProposalOutcome.id }),\n ...(message.feedback !== undefined ? { feedback: message.feedback } : {}),\n ...(message.createdAt ? { createdAt: message.createdAt } : {}),\n ...(message.agentName !== undefined ? { agentName: message.agentName } : {}),\n ...(message.persona !== undefined ? { persona: message.persona } : {}),\n ...(message.usage !== undefined\n ? {\n usage: {\n inputTokens: message.usage.inputTokens,\n outputTokens: message.usage.outputTokens,\n costUsd: message.usage.costUsd ?? null,\n },\n }\n : {}),\n };\n return {\n id: message.id,\n role: message.role,\n parts,\n ...(Object.keys(metadata).length > 0 ? { metadata } : {}),\n };\n}\n","import type { MessageFeedback, StoredMessage } from '@dudousxd/nestjs-agent-core';\nimport type { UIMessage } from 'ai';\nimport { storedMessageToUiMessage } from './stored-message-to-ui-message.js';\n\n/**\n * Summed usage/cost across the stored-message rows merged into one turn (see\n * {@link storedThreadToUiMessages}). Mirrors `MessageUsage`, but `costUsd` is always present\n * (never omitted) since it's a computed aggregate, not a single provider report.\n */\nexport interface AggregatedTurnUsage {\n inputTokens: number;\n outputTokens: number;\n /**\n * `null` only when EVERY merged row reports a null/absent cost (no pricing store bound, or an\n * unpriced model) — same \"unknown, not a real $0\" distinction `MessageUsage.costUsd` makes for a\n * single row. A null cost on SOME rows (mixed with priced ones) contributes `0` to the sum\n * instead of poisoning the whole turn's total to `null` — the tokens are still real and summed\n * either way, so only the cost figure would be understated, never wrong in a \"$0 turn\" sense.\n */\n costUsd: number | null;\n}\n\n/** Metadata the grouped `UIMessage` carries on `.metadata.usage` — see {@link AggregatedTurnUsage}. */\nexport interface StoredTurnMetadata {\n usage: AggregatedTurnUsage;\n}\n\n/**\n * Everything a message's `metadata` may carry from this library: `usage` on a merged replayed turn,\n * `feedback` on a replayed message that was rated (a merged turn is rated through its last row,\n * whose id it carries), `runId` on a live-streamed one, `costUsd` from the stream's step ends.\n */\nexport interface AgentMessageMetadata extends Partial<StoredTurnMetadata> {\n feedback?: MessageFeedback;\n runId?: string;\n costUsd?: number | null;\n /** ISO timestamp: the stored row's `createdAt` (a merged turn: its first row's), or when a live turn started streaming. */\n createdAt?: string;\n /** The agent that wrote a replayed message, when the row names one (`StoredMessage.agentName`). */\n agentName?: string;\n /** The persona the turn that wrote a replayed message ran under (`StoredMessage.persona`). */\n persona?: string;\n /** Host-defined keys: `StoredMessage.metadata` and the stream's `message-metadata` frames. */\n [key: string]: unknown;\n}\n\n/**\n * Convert a thread's full `StoredMessage[]` history into `UIMessage[]`, merging consecutive\n * assistant rows (no user message between them) into ONE `UIMessage` per turn.\n *\n * Why: the agent loop persists one row per model iteration (see `agent-loop.ts`'s per-step\n * `persist:assistant:${i}`) — a turn with tool calls appends \"I'll check that...\" + tool calls,\n * then a separate final-answer row. `storedMessageToUiMessage` maps 1:1, so a reloaded thread\n * renders 2-3 assistant bubbles (each with its own cost/tokens footer) for what the LIVE stream\n * renders as one continuous response (one `UIMessage`, stepped internally — see\n * `AgentChatTransport.toChunkStream`'s `start-step`/`finish-step` bracketing). This closes that gap\n * for replayed history.\n *\n * Merge shape: each row is mapped via `storedMessageToUiMessage` (unchanged — same text-then-tool\n * part ordering per row) and the parts are concatenated in row order, so the grouped message's parts\n * read as `[row1 text?, row1 tools?, row2 text?, row2 tools?, ...]` — exactly the sequence the live\n * transport streams for the same turn. The group's `id` is the LAST row's id (the final-answer row —\n * it's the one carrying `followUps`, and what a host keys turn-level actions like \"fork\" or\n * \"regenerate\" on). Non-assistant rows (user/system) pass through `storedMessageToUiMessage`\n * unchanged, one row → one message, same as today.\n *\n * A lone assistant row between two user rows (the common case: no tool calls, or already a single\n * iteration) has nothing to merge with, so it comes back byte-for-byte identical to calling\n * `storedMessageToUiMessage` directly — no `metadata` is added for that case either, preserving\n * exact backward compatibility for hosts that read stored usage some other way.\n *\n * Only an ACTUAL merge (2+ rows) attaches `metadata.usage` — the {@link AggregatedTurnUsage} summed\n * across the merged rows' `usage` (rows without a `usage` at all, e.g. an older/test fixture, are\n * skipped rather than treated as zero-and-priced).\n *\n * Deliberately NOT reproduced: the live transport's `{type: 'step-start'}` UI parts (one per model\n * call, emitted by the AI SDK for every `start-step` chunk — see `repro-real-frames.spec.ts` for a\n * captured wire dump). Those are structural brackets `MessageItem`'s `renderBlocks` never renders\n * (it draws only text, reasoning, files and tool blocks), and `storedMessageToUiMessage` has never\n * emitted them for a single row either — inventing them here would make a merged turn diverge from\n * a same-shaped unmerged one instead of converging on it. \"Indistinguishable from the live stream\"\n * is scoped to what actually renders: the text/tool-call content in step order, not the step\n * brackets around it.\n */\nexport function storedThreadToUiMessages(messages: StoredMessage[]): UIMessage[] {\n const turns: StoredMessage[][] = [];\n for (const message of messages) {\n const currentTurn = turns.at(-1);\n const previousRow = currentTurn?.at(-1);\n if (\n message.role === 'assistant' &&\n previousRow?.role === 'assistant' &&\n currentTurn &&\n sameRun(previousRow, message)\n ) {\n currentTurn.push(message);\n } else {\n turns.push([message]);\n }\n }\n return turns.map(mergeTurn);\n}\n\n/**\n * Two assistant rows belong to the same TURN, not merely to the same side of the conversation.\n * Consecutive is the right test only while one run at a time writes to a thread: a detached\n * sub-agent posts its answer whenever it lands, so a thread whose last row is an assistant reply can\n * gain another from a different run entirely — merged, that reads as the assistant having said both.\n *\n * Rows that carry no `runId` (written before it was recorded, or by a host outside a run) merge as\n * they always did: there is nothing to tell them apart with, and splitting on absence would\n * un-merge every old thread.\n */\nfunction sameRun(previous: StoredMessage, next: StoredMessage): boolean {\n if (previous.actionProposalOutcome !== undefined || next.actionProposalOutcome !== undefined)\n return false;\n return previous.runId === undefined || next.runId === undefined || previous.runId === next.runId;\n}\n\nfunction mergeTurn(rows: StoredMessage[]): UIMessage {\n const lastRow = rows.at(-1);\n if (lastRow === undefined) {\n // Unreachable: `storedThreadToUiMessages` never pushes an empty turn.\n throw new Error('storedThreadToUiMessages: encountered an empty turn');\n }\n if (rows.length === 1) {\n return storedMessageToUiMessage(lastRow);\n }\n\n const parts: UIMessage['parts'] = rows.flatMap((row) => storedMessageToUiMessage(row).parts);\n const usage = sumUsage(rows);\n // A turn is rated through its last row — the id this message carries.\n const feedback = lastRow.feedback;\n const createdAt = rows[0]?.createdAt;\n const metadata: AgentMessageMetadata = {\n // Host facts of every row, a later row's winning (the turn's final state), under the library's.\n ...Object.assign({}, ...rows.map((row) => row.metadata ?? {})),\n ...(usage !== undefined ? { usage } : {}),\n ...(feedback !== undefined ? { feedback } : {}),\n ...(createdAt ? { createdAt } : {}),\n ...(lastRow.agentName !== undefined ? { agentName: lastRow.agentName } : {}),\n ...(lastRow.persona !== undefined ? { persona: lastRow.persona } : {}),\n };\n\n return {\n id: lastRow.id,\n role: lastRow.role,\n parts,\n ...(Object.keys(metadata).length > 0 ? { metadata } : {}),\n };\n}\n\nfunction sumUsage(rows: StoredMessage[]): AggregatedTurnUsage | undefined {\n const usages = rows\n .map((row) => row.usage)\n .filter((usage): usage is NonNullable<typeof usage> => usage !== undefined);\n if (usages.length === 0) {\n return undefined;\n }\n const allCostsUnknown = usages.every(\n (usage) => usage.costUsd === null || usage.costUsd === undefined,\n );\n return {\n inputTokens: usages.reduce((sum, usage) => sum + usage.inputTokens, 0),\n outputTokens: usages.reduce((sum, usage) => sum + usage.outputTokens, 0),\n costUsd: allCostsUnknown ? null : usages.reduce((sum, usage) => sum + (usage.costUsd ?? 0), 0),\n };\n}\n","import { useChat } from '@ai-sdk/react';\nimport type {\n ChatQueueState,\n MessageAttachment,\n QuotaBlock,\n StoredMessage,\n ThreadDetail,\n ThreadSummary,\n} from '@dudousxd/nestjs-agent-core';\nimport type { UiCapabilities } from '@dudousxd/nestjs-agent-core/genui';\nimport type { DataUIPart, UIDataTypes, UIMessage } from 'ai';\nimport { useCallback, useEffect, useMemo, useRef, useState } from 'react';\nimport {\n AgentChatTransport,\n type AgentStreamMeta,\n type ReconnectOptions,\n type StreamConnectionState,\n} from './agent-chat-transport.js';\nimport { useActionProposals } from './approvals/use-action-proposals.js';\nimport { attachmentFile } from './attachments/files.js';\nimport {\n type AttachmentsState,\n type UseAttachmentsOptions,\n useAttachments,\n} from './attachments/use-attachments.js';\nimport {\n type AgentBackend,\n AgentBackendUnsupportedError,\n type QueuedSendResult,\n requireBackendMethod,\n} from './backend.js';\nimport { type BackgroundRun, backgroundRunsFromThread } from './background-runs.js';\nimport { type ModelOption, type ModelsState, useModels } from './catalog/use-models.js';\nimport { useToolCatalog } from './presentation/use-tool-catalog.js';\nimport { useAgentBackend, useAgentUiCapabilities } from './provider.js';\nimport type {\n ChatQueue,\n QueuedChatMessage,\n SendWhileRunning,\n WhileRunning,\n} from './queue/model.js';\nimport { type QuotaState, useQuota } from './quota/use-quota.js';\nimport type { AgentRunFailure } from './run-errors.js';\nimport { storedMessageToUiMessage } from './stored-message-to-ui-message.js';\nimport {\n type AgentMessageMetadata,\n storedThreadToUiMessages,\n} from './stored-thread-to-ui-messages.js';\nimport { notifyThreads } from './threads/threads-events.js';\nimport type { ChatStatus } from './transcript/model.js';\nimport {\n type AnswerInput,\n type ApproveInput,\n type ChatTranscript,\n type MessageActionInput,\n type RejectInput,\n type SkipInput,\n type UseChatTranscriptOptions,\n useChatTranscript,\n} from './transcript/use-chat-transcript.js';\n\nexport interface UseAgentChatOptions<B extends AgentBackend = AgentBackend> {\n uiCapabilities?: UiCapabilities;\n proposalPollMs?: number;\n /** Enable proposal reads even when history and resume are both disabled. */\n proposals?: boolean;\n /**\n * What the chat talks to — see {@link AgentBackend}. Omitted → the enclosing `<AgentProvider>`'s,\n * else a same-origin client on `/agent`. Must be stable across renders.\n */\n backend?: B;\n /**\n * Retry a stream that dropped mid-run from its last frame (`GET <base>/chat/:runId/stream?after=`),\n * with exponential backoff. `status` reads `'reconnecting'` meanwhile. Default on; `false` turns\n * it off.\n */\n reconnect?: ReconnectOptions | false;\n /** Named agent to run each turn. */\n agent?: string;\n /**\n * One of the agent's personas (`GET <base>/agents` lists them) to answer as. Read per send, so a\n * picker can switch it between messages; the server pins it on the thread, and `threadPersona`\n * reports it back. Omitted → the thread's pinned persona, else the agent's default. A single send\n * can name its own: `sendMessage(message, { body: { persona } })`.\n */\n persona?: string;\n /**\n * Thread this chat is bound to. Omitted → the backend creates one on the first send\n * ({@link UseAgentChatOptions.onThreadCreated}). Changing it switches the chat to that thread:\n * its history loads and a turn still streaming on it is re-attached. Switching to the thread this\n * chat just created (syncing a URL) keeps the live conversation as it is.\n */\n threadId?: string;\n /**\n * Load a `threadId`'s persisted history into the chat (`GET <base>/threads/:id`). Default `true`;\n * skipped when {@link UseAgentChatOptions.initialMessages} is given. `false` opts out.\n */\n history?: boolean;\n /** Persisted history you already have — seeds the chat instead of loading it (read per thread). */\n initialMessages?: UIMessage[];\n /**\n * Re-attach to a turn that was still streaming on `threadId` when the page (re)loaded — read off\n * the thread's `activeRunId`, so a reload mid-answer keeps streaming it. Default `true`; `false`\n * opts out.\n */\n resume?: boolean;\n /**\n * A run id you already know is streaming — attached to on mount without reading the thread first.\n * Rarely needed: {@link UseAgentChatOptions.resume} finds it by itself.\n */\n resumeRunId?: string;\n /**\n * The model every turn runs on, controlled by you. Omitted → `chat.models.selected` (what\n * `chat.models.select(id)` picked), else the thread's pinned model, else the server default. A\n * single send can still override it with `sendMessage(msg, { body: { model } })`. Sent as the\n * turn's `model`, which the server applies to that turn only — pinning a model on the thread is\n * `chat.models.pinToThread(id)`.\n */\n model?: string;\n /**\n * Read the caller's budget (`GET <base>/quota`) and refuse sends while a window is exhausted.\n * Default `true` when the backend implements `getQuota`; `false` skips the request.\n */\n quota?: boolean;\n /**\n * Override the quota gate: `null` never blocks, a {@link QuotaBlock} always does. Omitted → the\n * gate follows {@link UseAgentChatOptions.quota}'s report. While blocked, `sendMessage` and\n * `regenerate` refuse with {@link QuotaBlockedError}.\n */\n blocked?: QuotaBlock | null;\n /** Validation and upload for `chat.composer.files` — see `useAttachments`. */\n composer?: Omit<UseAttachmentsOptions, 'backend'>;\n /**\n * What `composer.submit()` and `sendMessage` do while a turn is still running. Default `'queue'`:\n * the message waits in the thread's queue (server-side — it survives a reload) and runs when the\n * turn settles; `chat.queue` lists and edits what is waiting. `'interrupt'` cancels the running\n * turn and runs the message next. `'block'` refuses the send (`composer.blockedBy === 'busy'`).\n * A backend without `enqueueMessage` behaves as `'block'`. One send can answer differently:\n * `composer.submit({ mode })`, `sendMessage(message, { mode })`.\n */\n whileRunning?: WhileRunning;\n /**\n * Overrides for `chat.transcript` — anything `useChatTranscript` takes (`sources`, `editable` +\n * `onEditSubmit`, `followUps`, `getUsage`, a `toolCatalog` of your own, `onApprove: null`, …).\n * Yours win over the chat's own wiring.\n */\n transcript?: Partial<Omit<UseChatTranscriptOptions, 'messages' | 'status'>>;\n /** Read at every send to capture a page snapshot for the page-assistant. */\n getPageContext?: () => Record<string, unknown> | null;\n /** Fired after each streamed turn finishes (e.g. to refetch the sidebar). */\n onFinish?: () => void;\n /**\n * Fired when this chat moves to a thread it created: the first send of a threadless chat (the\n * backend created one), or `chat.fork(…)`. Carries the id so the host can sync its URL/router.\n * The hook already remembers a created thread, so every later send reuses it even before the\n * host navigates.\n */\n onThreadCreated?: (threadId: string) => void;\n /**\n * Fired exactly once per run when its stream settles — normally (`'completed'`) or via a thrown\n * failure / the backend's `event: error` frame (`'failed'`) — including a RESUMED stream's own\n * completion. By the time this fires, the server has already derived and persisted the thread's\n * title (and the run's terminal state).\n *\n * Skipped when the attempt never got far enough to learn a run id. A user-initiated `cancel()`\n * reports `'completed'` (the server-side cancel records its own terminal state).\n */\n onRunSettled?: (outcome: { runId: string; status: 'completed' | 'failed' }) => void;\n /**\n * Every data part the stream delivers, as it arrives — including transient ones that are never\n * stored on a message (`data-title`, `data-cancelled`). Pushed components arrive as `data-ui`,\n * approval metadata as `data-approval-requested`, and a frame kind this version does not map as\n * `data-<kind>`. See `AgentChatTransport` for the full mapping.\n */\n onData?: (part: DataUIPart<UIDataTypes>) => void;\n /** The server set or changed the thread's title while a turn streamed. */\n onTitle?: (title: string) => void;\n /**\n * Track DETACHED sub-agents this conversation started: which are still working, and their answers\n * as they land (see {@link ChatBackground}). Default `false`.\n */\n background?: boolean;\n /**\n * How often to re-read the thread while a detached sub-agent is still working, in ms. Default\n * 5000; `0` turns the interval off, leaving {@link ChatBackground.refresh} as the only trigger.\n */\n backgroundPollMs?: number;\n}\n\n/** Sub-agents this conversation started and did not wait for. See {@link BackgroundRun}. */\nexport interface ChatBackground {\n runs: BackgroundRun[];\n /** True while any of them is still working — what a \"2 agents running\" affordance reads. */\n isWorking: boolean;\n /** Re-read the thread now, instead of waiting for the next poll. */\n refresh: () => Promise<void>;\n}\n\n/**\n * The chat's model picker state. Loaded the first time `list`/`providers`/`defaultModel`/`locked`\n * is read.\n *\n * Two different choices: `select(id)` picks the model this chat's following sends name — each send\n * carries it as `model`, which the server applies to that turn only and never stores; the pick is\n * this conversation's, so switching threads drops it. `pinToThread(id)` stores a model on the\n * thread (`PATCH threads/:id { model }`), which every later turn without a `model` of its own runs\n * on, across reloads and devices.\n */\nexport interface ChatModels {\n /** Every model the caller may pick, flattened (`[]` until loaded). */\n readonly list: ModelOption[];\n /** The same, grouped by provider. */\n readonly providers: ModelsState['providers'];\n /**\n * What the next turn runs on: the lock, the `model` option, the pick, the thread's pin, else the\n * default.\n */\n selected: string | null;\n /** The model pinned on the thread (`null` when none, or before the thread is read). */\n pinned: string | null;\n /** The catalog's default — what a turn runs on when nothing is picked or pinned (`null` until loaded). */\n readonly defaultModel: string | null;\n /**\n * The agent always runs on one model (`{ model, reason? }`), or `null`. While locked, `select`\n * does nothing and `selected` is the locked model.\n */\n readonly locked: ModelsState['locked'];\n /** Run this chat's following sends on `id` — each send's `model`, that turn only. */\n select: (id: string) => void;\n /**\n * Pin `id` on the thread (`null` unpins) — every later turn without its own `model` runs on it,\n * across reloads. Replaces the pick, so the next send runs on the pin. On a chat with no thread\n * yet, the pin lands when the first send creates one.\n */\n pinToThread: (id: string | null) => Promise<void>;\n isLoading: boolean;\n error: Error | null;\n}\n\n/** A queued message that became the thread's running turn, which this chat attaches to. */\ninterface StartedQueuedTurn {\n messageId: string;\n runId: string;\n text: string;\n attachments: MessageAttachment[];\n}\n\nconst EMPTY_QUEUE: ChatQueueState = { items: [], paused: null };\n\nlet localQueueSequence = 0;\n\n/** The user message a queued message becomes once its turn starts. */\nfunction queuedUserMessage(turn: StartedQueuedTurn): UIMessage {\n return {\n id: turn.messageId,\n role: 'user',\n metadata: { createdAt: new Date().toISOString() },\n parts: [\n ...turn.attachments.map((attachment) => ({\n type: 'file' as const,\n mediaType: attachment.contentType,\n filename: attachment.name,\n url: attachment.url,\n providerMetadata: { agent: { mediaId: attachment.mediaId } },\n })),\n ...(turn.text.length > 0 ? [{ type: 'text' as const, text: turn.text }] : []),\n ],\n };\n}\n\n/** The text and staged files of whatever `sendMessage` was handed, for a send that is queued. */\nfunction draftOf(message: unknown): { text: string; attachments: MessageAttachment[] } {\n if (typeof message !== 'object' || message === null) {\n return { text: '', attachments: [] };\n }\n const draft = message as {\n text?: unknown;\n files?: unknown;\n parts?: Array<{ type?: string; text?: unknown }>;\n };\n let text = typeof draft.text === 'string' ? draft.text : '';\n if (text === '' && Array.isArray(draft.parts)) {\n text = draft.parts\n .filter((part) => part.type === 'text' && typeof part.text === 'string')\n .map((part) => part.text as string)\n .join('');\n }\n const files = Array.isArray(draft.files)\n ? (draft.files as Array<Record<string, unknown>>)\n : Array.isArray(draft.parts)\n ? (draft.parts as Array<Record<string, unknown>>).filter((part) => part.type === 'file')\n : [];\n const attachments = files.flatMap((file): MessageAttachment[] => {\n const mediaId = (file.providerMetadata as { agent?: { mediaId?: unknown } } | undefined)?.agent\n ?.mediaId;\n return typeof mediaId === 'string'\n ? [\n {\n mediaId,\n url: String(file.url ?? ''),\n contentType: String(file.mediaType ?? 'application/octet-stream'),\n name: String(file.filename ?? mediaId),\n },\n ]\n : [];\n });\n return { text, attachments };\n}\n\nfunction lastUserIndex(messages: UIMessage[]): number {\n for (let index = messages.length - 1; index >= 0; index -= 1) {\n if (messages[index]?.role === 'user') return index;\n }\n return -1;\n}\n\n/** Why the composer cannot send right now. */\nexport type ComposerBlock = 'empty' | 'busy' | 'uploading' | 'quota';\n\n/** A headless composer: the draft, its files, and whether (and why not) it can send. */\nexport interface ChatComposer {\n text: string;\n setText: (text: string) => void;\n /** The staged attachments — `useAttachments` state on the chat's backend. */\n files: AttachmentsState;\n canSend: boolean;\n /** Why `canSend` is false, or `null`. */\n blockedBy: ComposerBlock | null;\n /**\n * Send the draft with the ready files attached, then clear both. A no-op while blocked.\n *\n * `submit({ mode })` says what to do if a turn is running, for this send only — `'interrupt'`\n * for a \"send now\" button next to a plain send that queues. It overrides `whileRunning`\n * (`'block'` included) and clears the draft like any other submit.\n */\n submit: (options?: SendWhileRunning) => Promise<void>;\n}\n\ninterface AddToolResultArgs {\n tool: string;\n toolCallId: string;\n output: unknown;\n}\n\nlet localChatSequence = 0;\nfunction localChatId(): string {\n localChatSequence += 1;\n return `local-chat-${localChatSequence}`;\n}\n\n/**\n * The agent chat, wired: the AI SDK v7 `useChat` over `AgentChatTransport`, a thread's history\n * loaded and a streaming turn re-attached on its own, a quota send gate, a model picker, a headless\n * composer with attachments, and a transcript whose approve/reject/answer/skip/stop/fork/regenerate\n * are already bound. Every piece is also a hook of its own (`useChatTranscript`, `useAttachments`,\n * `useModels`, `useQuota`, `useThreads`) for a host that wants to wire it differently.\n */\nexport function useAgentChat<B extends AgentBackend = AgentBackend>(\n options: UseAgentChatOptions<B> = {},\n) {\n const providerCapabilities = useAgentUiCapabilities();\n const capabilitiesRef = useRef(providerCapabilities);\n capabilitiesRef.current = providerCapabilities;\n const latest = useRef(options);\n latest.current = options;\n\n // Identity-stable: the first backend this chat mounted with is the one it keeps.\n const resolved = useAgentBackend<B>(options.backend);\n const client = useRef(resolved).current;\n\n // The thread the backend created for a threadless chat (or a fork moved to), captured from the\n // `meta` frame. Every send after the first reuses it; an explicit `threadId` option always wins.\n const createdThreadId = useRef<string | undefined>(undefined);\n\n // Which conversation `useChat` holds. A new `threadId` is a different conversation — except the\n // one this chat itself created, which a host passes back once it syncs its URL.\n const chatIdRef = useRef<string>(options.threadId ?? localChatId());\n const boundThreadRef = useRef(options.threadId);\n if (options.threadId !== boundThreadRef.current) {\n boundThreadRef.current = options.threadId;\n const adopting = options.threadId !== undefined && options.threadId === createdThreadId.current;\n if (!adopting) {\n chatIdRef.current = options.threadId ?? localChatId();\n createdThreadId.current = undefined;\n }\n }\n const chatId = chatIdRef.current;\n\n const [runId, setRunId] = useState<string | undefined>(options.resumeRunId);\n const runIdRef = useRef<string | undefined>(runId);\n runIdRef.current = runId;\n\n // The run id learned (via the `meta` frame) during the CURRENT in-flight attempt only — reset by\n // the transport's `onAttemptStart`. `onRunSettled` reads THIS so an attempt that fails before\n // learning a run id never misattributes its outcome to the previous run.\n const settlingRunIdRef = useRef<string | undefined>(undefined);\n\n // The run id discovered from the thread's `activeRunId`, read by the transport's\n // `getResumeRunId` alongside the explicit `resumeRunId` option.\n const autoResumeRunIdRef = useRef<string | undefined>(undefined);\n // The loaded thread's active run, if any — `null` once read with none.\n const [activeRunId, setActiveRunId] = useState<string | null>(null);\n // The thread whose history read has settled (loaded or failed). The history is loading until it\n // is the bound thread — derived, so it already reads `true` on the first render, before the\n // effect below has asked for anything, and a page never flashes its empty state.\n const [historyFor, setHistoryFor] = useState<string | undefined>(undefined);\n const [historyError, setHistoryError] = useState<Error | null>(null);\n // How the last run's stream said it failed (`event: error`), until the next attempt starts.\n const [runError, setRunError] = useState<AgentRunFailure | null>(null);\n // The model pinned on the loaded thread.\n const [threadModel, setThreadModel] = useState<string | null>(null);\n // The persona pinned on the thread — read with its history, and mirrored from each send that\n // names one. `null` → none pinned (the agent's default persona applies).\n const [threadPersona, setThreadPersona] = useState<string | null>(null);\n const [pickedModel, setPickedModel] = useState<string | undefined>(undefined);\n const pickedModelRef = useRef(pickedModel);\n pickedModelRef.current = pickedModel;\n // The agent is locked to one model (read off the catalog once it loads).\n const lockedRef = useRef(false);\n // A pin asked for before the chat had a thread — sent once the first send creates one.\n const pendingPin = useRef<{ model: string | null } | undefined>(undefined);\n\n // One-shot flag read (and cleared) by the transport's getBody so the next send carries\n // `regenerate: true` — telling the backend to re-run the last exchange instead of appending.\n const regenerateNext = useRef(false);\n\n const currentThreadId = useCallback(\n (): string | undefined => latest.current.threadId ?? createdThreadId.current,\n [],\n );\n\n // ---- queue state (declared early: the transport's callbacks feed it) ------------------------\n const [queueState, setQueueState] = useState<ChatQueueState>(EMPTY_QUEUE);\n const queueStateRef = useRef(queueState);\n const applyQueue = useCallback((next: ChatQueueState) => {\n queueStateRef.current = next;\n setQueueState(next);\n }, []);\n // Sends on their way to the server, shown in the queue until it answers.\n const [pendingSends, setPendingSends] = useState<QueuedChatMessage[]>([]);\n const [queueError, setQueueError] = useState<Error | null>(null);\n // The queued message the running turn handed the thread to — attached to once that turn settles.\n const handoff = useRef<StartedQueuedTurn | undefined>(undefined);\n // A plain send the server queued instead of starting (another tab's turn was running).\n const queuedSend = useRef<QueuedSendResult | undefined>(undefined);\n const proposalRefreshRef = useRef<() => Promise<void>>(async () => {});\n // Queue sends made before a new chat's first turn named its thread.\n const threadWaiters = useRef<Array<(threadId: string) => void>>([]);\n\n /** The body fields every send carries: agent, persona, thread, model, page context. */\n const turnBody = useCallback((): Record<string, unknown> => {\n const current = latest.current;\n // The server pins a persona a send names; mirror it so a picker reads the thread's state.\n if (current.persona !== undefined) setThreadPersona(current.persona);\n const pageContext = current.getPageContext?.() ?? null;\n const threadId = currentThreadId();\n // A locked agent runs on its own model: a pick is not sent (the server would refuse it).\n const model = current.model ?? (lockedRef.current ? undefined : pickedModelRef.current);\n return {\n // Read per send: a host that switches agents before the first message (a picker on a new\n // chat) sends the one picked now, not the one this chat mounted with.\n ...(current.agent !== undefined ? { agent: current.agent } : {}),\n ...(current.persona !== undefined ? { persona: current.persona } : {}),\n ...(threadId !== undefined ? { threadId } : {}),\n ...(model !== undefined ? { model } : {}),\n ...(pageContext ? { pageContext } : {}),\n ...((current.uiCapabilities ?? capabilitiesRef.current) === undefined\n ? {}\n : { uiCapabilities: current.uiCapabilities ?? capabilitiesRef.current }),\n };\n }, [currentThreadId]);\n\n // Where the live stream stands — `reconnecting` while the transport retries a dropped one.\n const [connection, setConnection] = useState<StreamConnectionState>({ status: 'live' });\n // The run ended while the stream was away: what streamed is incomplete, the thread is not.\n const resyncAfterSettle = useRef(false);\n\n // Identity-stable: per-render config is read through `latest`.\n // biome-ignore lint/correctness/useExhaustiveDependencies: stable by design\n const transport = useMemo(() => {\n function onMeta(meta: AgentStreamMeta): void {\n settlingRunIdRef.current = meta.runId;\n setRunId(meta.runId);\n if (meta.threadId) {\n const waiting = threadWaiters.current;\n threadWaiters.current = [];\n for (const resolve of waiting) resolve(meta.threadId);\n }\n if (\n latest.current.threadId === undefined &&\n meta.threadId &&\n createdThreadId.current !== meta.threadId\n ) {\n createdThreadId.current = meta.threadId;\n const pin = pendingPin.current;\n if (pin !== undefined) {\n pendingPin.current = undefined;\n void client.updateThread(meta.threadId, { model: pin.model }).catch(() => undefined);\n }\n latest.current.onThreadCreated?.(meta.threadId);\n notifyThreads(client, { type: 'changed' });\n }\n }\n return new AgentChatTransport({\n backend: client,\n ...(options.reconnect !== undefined ? { reconnect: options.reconnect } : {}),\n onConnectionChange: (state) => {\n if (state.status === 'gone') resyncAfterSettle.current = true;\n setConnection(state.status === 'gone' ? { status: 'live' } : state);\n },\n ...(options.agent !== undefined ? { agent: options.agent } : {}),\n getBody: () => {\n const regenerate = regenerateNext.current;\n regenerateNext.current = false;\n return { ...turnBody(), ...(regenerate ? { regenerate: true } : {}) };\n },\n getResumeRunId: () => latest.current.resumeRunId ?? autoResumeRunIdRef.current,\n // A stream attached to after a reload carries no `meta` frame: without this the chat would\n // be reading a run it cannot name, and `cancel()` would stop nothing.\n onResumeAttached: (resumedRunId) => {\n settlingRunIdRef.current = resumedRunId;\n setRunId(resumedRunId);\n },\n onMeta,\n onAttemptStart: () => {\n settlingRunIdRef.current = undefined;\n setRunError(null);\n },\n onRunError: (failure) => setRunError(failure),\n // A queued turn this chat went to attach to had already finished: read what it wrote.\n onResumeGone: () => {\n void resyncFromThread();\n },\n });\n }, []);\n\n // Assigned once `refreshBackground` exists below.\n const backgroundRef = useRef<() => Promise<void>>(() => Promise.resolve());\n\n const chat = useChat({\n transport,\n id: chatId,\n resume: options.resumeRunId !== undefined,\n ...(options.initialMessages !== undefined ? { messages: options.initialMessages } : {}),\n onData: (part) => {\n latest.current.onData?.(part);\n if (part.type === 'data-proposal-decision') void proposalRefreshRef.current();\n if (part.type === 'data-queue') {\n onQueueData(part.data);\n }\n if (part.type === 'data-title') {\n const title = (part.data as { title?: unknown } | null)?.title;\n if (typeof title === 'string') {\n latest.current.onTitle?.(title);\n const threadId = currentThreadId();\n if (threadId !== undefined) notifyThreads(client, { type: 'title', threadId, title });\n }\n }\n },\n onFinish: ({ isError }) => {\n latest.current.onFinish?.();\n if (latest.current.background === true) {\n void backgroundRef.current();\n }\n const settledRunId = settlingRunIdRef.current;\n if (settledRunId !== undefined) {\n latest.current.onRunSettled?.({\n runId: settledRunId,\n status: isError ? 'failed' : 'completed',\n });\n notifyThreads(client, { type: 'changed' });\n }\n setConnection({ status: 'live' });\n const queuedInstead = queuedSend.current;\n if (queuedInstead !== undefined) {\n queuedSend.current = undefined;\n // The SDK already showed the send as a user message; it is waiting in the queue instead.\n chatRef.current.setMessages((current) => {\n const last = lastUserIndex(current);\n return last === -1 ? current : current.slice(0, last);\n });\n }\n const next = handoff.current;\n handoff.current = undefined;\n if (next !== undefined) {\n attachTo(next);\n return;\n }\n if (resyncAfterSettle.current) {\n resyncAfterSettle.current = false;\n void resyncFromThread();\n }\n },\n });\n\n const chatRef = useRef(chat);\n chatRef.current = chat;\n\n /** A `data-queue` part: the queue as it now stands, and maybe the turn this run handed over to. */\n function onQueueData(data: unknown): void {\n const frame = (data ?? {}) as {\n queue?: ChatQueueState;\n started?: { messageId: string; runId: string };\n queuedSend?: QueuedSendResult;\n };\n const before = queueStateRef.current;\n if (frame.queue !== undefined) applyQueue(frame.queue);\n const started = frame.started;\n // A run's own stream may open by announcing itself (a queue kicked while idle): not a handoff.\n if (started !== undefined && started.runId !== settlingRunIdRef.current) {\n const waiting = before.items.find((item) => item.id === started.messageId);\n handoff.current = {\n ...started,\n text: waiting?.content ?? '',\n attachments: waiting?.attachments ?? [],\n };\n }\n if (frame.queuedSend !== undefined) {\n queuedSend.current = frame.queuedSend;\n if (frame.queuedSend.runId !== undefined) {\n handoff.current = {\n messageId: frame.queuedSend.messageId,\n runId: frame.queuedSend.runId,\n ...draftOf(chatRef.current.messages[lastUserIndex(chatRef.current.messages)]),\n };\n }\n }\n }\n\n /**\n * Show a queued message as the user message it now is, and attach to the turn it started. After\n * the SDK has fully settled the previous response — resuming from inside its `onFinish` would\n * have that response's cleanup clobber this one.\n */\n function attachTo(turn: StartedQueuedTurn): void {\n setTimeout(() => {\n if (turn.text.length > 0 || turn.attachments.length > 0) {\n chatRef.current.setMessages((current) =>\n current.some((message) => message.id === turn.messageId)\n ? current\n : [...current, queuedUserMessage(turn)],\n );\n } else {\n // Queued somewhere this chat never saw: the thread has it, once the turn has run.\n resyncAfterSettle.current = true;\n }\n autoResumeRunIdRef.current = turn.runId;\n void chatRef.current.resumeStream();\n }, 0);\n }\n\n /** Replace the transcript with the persisted thread — after a run finished while we were away. */\n async function resyncFromThread(): Promise<void> {\n const threadId = currentThreadId();\n if (threadId === undefined) return;\n try {\n const thread = await client.getThread(threadId);\n chatRef.current.setMessages(storedThreadToUiMessages(thread.messages));\n } catch {\n /* best-effort: the partial answer stays until the next load */\n }\n }\n\n // A new conversation starts from rest: nothing of the previous thread's run state carries over.\n const firstChatId = useRef(chatId);\n // biome-ignore lint/correctness/useExhaustiveDependencies: `applyQueue` is stable; `chatId` names the conversation\n useEffect(() => {\n if (chatId === firstChatId.current) return;\n firstChatId.current = chatId;\n setRunId(undefined);\n setActiveRunId(null);\n setThreadModel(null);\n setThreadPersona(null);\n setPickedModel(undefined);\n setBackgroundRuns([]);\n setHistoryError(null);\n setRunError(null);\n autoResumeRunIdRef.current = undefined;\n pendingPin.current = undefined;\n applyQueue(EMPTY_QUEUE);\n setPendingSends([]);\n setQueueError(null);\n handoff.current = undefined;\n queuedSend.current = undefined;\n }, [chatId]);\n\n // A thread's history and its still-streaming turn, in one read. Re-runs per conversation; a\n // stale response (the thread changed mid-flight) is dropped.\n // biome-ignore lint/correctness/useExhaustiveDependencies: `chatId` names the conversation\n useEffect(() => {\n const threadId = options.threadId;\n if (threadId === undefined) return;\n // Adopted: this chat created the thread, and its messages are the live ones.\n if (threadId === createdThreadId.current) return;\n const current = latest.current;\n const wantHistory = current.history !== false && current.initialMessages === undefined;\n const wantResume = current.resume !== false && current.resumeRunId === undefined;\n if (!wantHistory && !wantResume) return;\n let cancelled = false;\n client\n .getThread(threadId)\n .then(\n (thread: ThreadDetail | undefined) => {\n if (cancelled || thread == null) return;\n const active = thread.activeRunId ?? null;\n const stored = Array.isArray(thread.messages) ? thread.messages : [];\n setActiveRunId(active);\n setThreadModel(thread.model ?? null);\n setThreadPersona(thread.persona ?? null);\n setHistoryError(null);\n const queue = thread.queue ?? EMPTY_QUEUE;\n applyQueue(queue);\n // Messages left waiting with nothing running and nothing pausing them — the process\n // that would have started them went away. Start the head now.\n if (\n queue.items.length > 0 &&\n queue.paused === null &&\n active === null &&\n typeof client.resumeQueue === 'function'\n ) {\n void resumeQueueRef.current().catch(() => undefined);\n }\n const resuming = wantResume && active !== null;\n if (wantHistory && chatRef.current.messages.length === 0) {\n // The run being resumed replays from its first frame, so its rows are left to the stream.\n const rows = resuming\n ? stored.filter(\n (message: StoredMessage) =>\n !(message.role === 'assistant' && message.runId === active),\n )\n : stored;\n chatRef.current.setMessages(storedThreadToUiMessages(rows));\n }\n if (resuming) {\n autoResumeRunIdRef.current = active;\n void chatRef.current.resumeStream();\n }\n },\n (error: unknown) => {\n if (cancelled) return;\n setHistoryError(error instanceof Error ? error : new Error(String(error)));\n },\n )\n .finally(() => {\n if (!cancelled) setHistoryFor(threadId);\n });\n return () => {\n cancelled = true;\n };\n }, [client, chatId, options.threadId]);\n\n const isLoadingHistory =\n options.threadId !== undefined &&\n options.threadId !== createdThreadId.current &&\n options.history !== false &&\n options.initialMessages === undefined &&\n historyFor !== options.threadId;\n\n /**\n * One turn in flight per chat. The SDK commits its single in-flight response BEFORE it reaches\n * the transport, so a second overlapping turn cannot be untangled downstream. The ref rather than\n * `chat.status`: a double-submitted composer arrives in the same tick, before status moves.\n */\n const turnInFlight = useRef(false);\n const isTurnInFlight = useCallback(\n () => turnInFlight.current || transport.isAttemptLive,\n [transport],\n );\n\n // ---- quota ---------------------------------------------------------------------------------\n const quota: QuotaState = useQuota({\n backend: client,\n enabled: options.quota !== false && typeof client.getQuota === 'function',\n });\n const blocked: QuotaBlock | null =\n options.blocked !== undefined ? options.blocked : quota.blocked;\n const blockedRef = useRef(blocked);\n blockedRef.current = blocked;\n\n // ---- queue ---------------------------------------------------------------------------------\n const whileRunning: WhileRunning =\n typeof client.enqueueMessage === 'function' ? (options.whileRunning ?? 'queue') : 'block';\n const whileRunningRef = useRef(whileRunning);\n whileRunningRef.current = whileRunning;\n const canQueueRef = useRef(false);\n canQueueRef.current = typeof client.enqueueMessage === 'function';\n\n /** This chat's thread — waiting for a new chat's first turn to name it, when one is in flight. */\n const threadForQueue = useCallback(async (): Promise<string> => {\n const known = currentThreadId();\n if (known !== undefined) return known;\n if (!isTurnInFlight()) throw new Error('queue: this chat has no thread yet');\n return new Promise<string>((resolve) => threadWaiters.current.push(resolve));\n }, [currentThreadId, isTurnInFlight]);\n\n /** Run a queue operation, keeping the last failure on `chat.queue.error`. */\n const queueCall = useCallback(async <T>(run: () => Promise<T>): Promise<T> => {\n try {\n const result = await run();\n setQueueError(null);\n return result;\n } catch (error) {\n setQueueError(error instanceof Error ? error : new Error(String(error)));\n throw error;\n }\n }, []);\n\n // biome-ignore lint/correctness/useExhaustiveDependencies: `attachTo` reads refs only\n const enqueue = useCallback(\n async (\n text: string,\n {\n attachments = [],\n mode = 'queue',\n }: { attachments?: MessageAttachment[]; mode?: 'queue' | 'interrupt' } = {},\n ): Promise<void> => {\n const block = blockedRef.current;\n if (block != null) throw new QuotaBlockedError(block);\n const send = client.enqueueMessage;\n if (typeof send !== 'function') throw new AgentBackendUnsupportedError('enqueueMessage');\n localQueueSequence += 1;\n const localId = `local-queued-${localQueueSequence}`;\n setPendingSends((current) => [\n ...current,\n {\n id: localId,\n text,\n attachments,\n files: attachments.map(attachmentFile),\n state: 'sending',\n interrupt: mode === 'interrupt',\n createdAt: new Date().toISOString(),\n },\n ]);\n try {\n await queueCall(async () => {\n const threadId = await threadForQueue();\n const result = await send.call(client, {\n body: {\n ...turnBody(),\n threadId,\n message: text,\n mode,\n ...(attachments.length > 0\n ? { attachments: attachments.map(({ mediaId }) => ({ mediaId })) }\n : {}),\n },\n });\n applyQueue(result.queue);\n if (result.runId !== undefined) {\n // Nothing was running after all: it started at once.\n const turn = { messageId: result.messageId, runId: result.runId, text, attachments };\n if (isTurnInFlight()) handoff.current = turn;\n else attachTo(turn);\n }\n });\n } finally {\n setPendingSends((current) => current.filter((item) => item.id !== localId));\n }\n },\n [client, queueCall, threadForQueue, turnBody, applyQueue, isTurnInFlight],\n );\n\n type SdkSendMessage = typeof chat.sendMessage;\n const sendMessage = useCallback(\n async (\n message?: Parameters<SdkSendMessage>[0],\n options?: Parameters<SdkSendMessage>[1] & SendWhileRunning,\n ): Promise<void> => {\n const block = blockedRef.current;\n if (block != null) throw new QuotaBlockedError(block);\n // `mode` is this hook's, not the SDK's: it never reaches the request.\n const { mode: ownMode, ...sdkOptions } = options ?? {};\n if (isTurnInFlight()) {\n // Mid-turn: the message waits in the thread's queue — unless this chat blocks instead. A\n // backend that cannot queue blocks whatever was asked for.\n const mode = canQueueRef.current ? (ownMode ?? whileRunningRef.current) : 'block';\n if (mode === 'block') return;\n const draft = draftOf(message);\n await enqueue(draft.text, { attachments: draft.attachments, mode });\n return;\n }\n turnInFlight.current = true;\n try {\n await chatRef.current.sendMessage(\n message as Parameters<SdkSendMessage>[0],\n options === undefined ? undefined : (sdkOptions as Parameters<SdkSendMessage>[1]),\n );\n } finally {\n turnInFlight.current = false;\n }\n },\n [isTurnInFlight, enqueue],\n );\n\n const removeQueued = useCallback(\n async (id: string): Promise<void> => {\n const previous = queueStateRef.current;\n applyQueue({ ...previous, items: previous.items.filter((item) => item.id !== id) });\n try {\n applyQueue(await queueCall(() => requireBackendMethod(client, 'removeQueuedMessage')(id)));\n } catch (error) {\n applyQueue(previous);\n throw error;\n }\n },\n [client, queueCall, applyQueue],\n );\n\n // biome-ignore lint/correctness/useExhaustiveDependencies: `attachTo` reads refs only\n const interruptQueued = useCallback(\n async (id: string): Promise<void> => {\n const previous = queueStateRef.current;\n const moving = previous.items.find((item) => item.id === id);\n if (moving !== undefined) {\n // Shown where it will be at once: at the head, as the interrupt, the pause lifted.\n applyQueue({\n paused: null,\n items: [\n { ...moving, interrupt: true },\n ...previous.items.filter((item) => item.id !== id),\n ],\n });\n }\n try {\n const result = await queueCall(() =>\n requireBackendMethod(client, 'interruptQueuedMessage')(id),\n );\n applyQueue({ items: result.items, paused: result.paused });\n if (result.runId !== undefined) {\n // Nothing was running: it started at once.\n const turn = {\n messageId: result.runId,\n runId: result.runId,\n text: moving?.content ?? '',\n attachments: moving?.attachments ?? [],\n };\n if (isTurnInFlight()) handoff.current = turn;\n else attachTo(turn);\n }\n } catch (error) {\n applyQueue(previous);\n throw error;\n }\n },\n [client, queueCall, applyQueue, isTurnInFlight],\n );\n\n const editQueued = useCallback(\n async (id: string, text: string): Promise<void> => {\n applyQueue(\n await queueCall(() =>\n requireBackendMethod(client, 'updateQueuedMessage')(id, { message: text }),\n ),\n );\n },\n [client, queueCall, applyQueue],\n );\n\n const moveQueued = useCallback(\n async (id: string, index: number): Promise<void> => {\n const previous = queueStateRef.current;\n const moving = previous.items.find((item) => item.id === id);\n if (moving !== undefined) {\n const rest = previous.items.filter((item) => item.id !== id);\n rest.splice(Math.max(0, Math.min(rest.length, index)), 0, moving);\n applyQueue({ ...previous, items: rest });\n }\n try {\n applyQueue(\n await queueCall(() =>\n requireBackendMethod(client, 'updateQueuedMessage')(id, { position: index }),\n ),\n );\n } catch (error) {\n applyQueue(previous);\n throw error;\n }\n },\n [client, queueCall, applyQueue],\n );\n\n const clearQueue = useCallback(async (): Promise<void> => {\n const threadId = currentThreadId();\n if (threadId === undefined) return;\n applyQueue(await queueCall(() => requireBackendMethod(client, 'clearQueue')(threadId)));\n }, [client, queueCall, currentThreadId, applyQueue]);\n\n // biome-ignore lint/correctness/useExhaustiveDependencies: `attachTo` reads refs only\n const resumeQueue = useCallback(async (): Promise<void> => {\n const threadId = currentThreadId();\n if (threadId === undefined) return;\n const before = queueStateRef.current;\n const result = await queueCall(() => requireBackendMethod(client, 'resumeQueue')(threadId));\n applyQueue({ items: result.items, paused: result.paused });\n if (result.runId !== undefined) {\n const head = before.items.find((item) => item.id === result.runId) ?? before.items[0];\n const turn = {\n messageId: result.runId,\n runId: result.runId,\n text: head?.content ?? '',\n attachments: head?.attachments ?? [],\n };\n if (isTurnInFlight()) handoff.current = turn;\n else attachTo(turn);\n }\n }, [client, queueCall, currentThreadId, applyQueue, isTurnInFlight]);\n const resumeQueueRef = useRef(resumeQueue);\n resumeQueueRef.current = resumeQueue;\n\n const queuedItems: QueuedChatMessage[] = [\n ...pendingSends.filter((item) => item.interrupt),\n ...queueState.items.map(\n (item): QueuedChatMessage => ({\n id: item.id,\n text: item.content,\n attachments: item.attachments ?? [],\n files: (item.attachments ?? []).map(attachmentFile),\n state: 'queued',\n interrupt: item.interrupt === true,\n createdAt: item.createdAt,\n }),\n ),\n ...pendingSends.filter((item) => !item.interrupt),\n ];\n const queue: ChatQueue = {\n items: queuedItems,\n paused: queueState.paused,\n isSupported: typeof client.enqueueMessage === 'function',\n add: enqueue,\n remove: removeQueued,\n interrupt: interruptQueued,\n edit: editQueued,\n move: moveQueued,\n clear: clearQueue,\n resume: resumeQueue,\n error: queueError,\n };\n\n // chat.addToolResult is generic over the backend's tool registry, which we don't statically type\n // here. Expose a string-keyed adapter and narrow once at the SDK boundary.\n type SdkAddToolResult = typeof chat.addToolResult;\n type SdkArgs = Parameters<SdkAddToolResult>[0];\n const addToolResult = useCallback(\n ({ tool, toolCallId, output }: AddToolResultArgs) =>\n chatRef.current.addToolResult({\n tool,\n toolCallId,\n output,\n } as unknown as SdkArgs),\n [],\n );\n\n // ---- background runs -----------------------------------------------------------------------\n const [backgroundRuns, setBackgroundRuns] = useState<BackgroundRun[]>([]);\n\n /** Re-derive what is running in the background, and pull in anything that has landed since. */\n const refreshBackground = useCallback(async (): Promise<void> => {\n const threadId = currentThreadId();\n if (threadId === undefined) {\n return;\n }\n const thread = await client.getThread(threadId);\n const runs = backgroundRunsFromThread(thread.messages);\n setBackgroundRuns(runs);\n const landed = runs\n .map((run) => run.message)\n .filter((message): message is NonNullable<typeof message> => message !== undefined);\n if (landed.length === 0) {\n return;\n }\n // Appended rather than re-seeding the list: the session's own messages hold live stream state\n // that the persisted rows do not carry.\n chatRef.current.setMessages((current) => {\n const known = new Set(current.map((message) => message.id));\n const missing = landed.filter((message) => !known.has(message.id));\n return missing.length === 0\n ? current\n : [...current, ...missing.map((message) => storedMessageToUiMessage(message))];\n });\n }, [client, currentThreadId]);\n\n backgroundRef.current = refreshBackground;\n\n const isWorking = backgroundRuns.some((run) => run.status === 'running');\n\n // biome-ignore lint/correctness/useExhaustiveDependencies: `chatId` names the conversation\n useEffect(() => {\n if (options.background !== true || options.threadId === undefined) {\n return;\n }\n void refreshBackground();\n }, [options.background, options.threadId, chatId, refreshBackground]);\n\n useEffect(() => {\n const every = latest.current.backgroundPollMs ?? 5000;\n if (latest.current.background !== true || !isWorking || every <= 0) {\n return;\n }\n const timer = setInterval(() => void refreshBackground(), every);\n return () => clearInterval(timer);\n }, [isWorking, refreshBackground]);\n\n const proposals = useActionProposals(\n client,\n options.proposals === false ||\n (options.proposals !== true && options.history === false && options.resume === false)\n ? undefined\n : currentThreadId(),\n (update) => chatRef.current.setMessages(update),\n `${chat.status}:${connection.status}`,\n options.proposalPollMs,\n );\n\n proposalRefreshRef.current = proposals.refresh;\n\n // ---- actions -------------------------------------------------------------------------------\n const cancel = useCallback(async (): Promise<void> => {\n // Close the SSE on the client first so the UI flips out of streaming, then hard-abort\n // server-side (a late terminal step can outlive the connection close alone).\n chatRef.current.stop();\n const active = runIdRef.current;\n if (active) {\n try {\n await client.cancelStream(active);\n } catch {\n /* best-effort — the SDK stop already flipped the UI */\n }\n }\n // The stream that would have carried the `queue` frame was closed above, so a queue the stop\n // just paused is read back: otherwise its messages keep saying \"up next\" with nothing coming.\n const threadId = currentThreadId();\n if (\n threadId !== undefined &&\n queueStateRef.current.items.length > 0 &&\n typeof client.getQueue === 'function'\n ) {\n try {\n applyQueue(await client.getQueue(threadId));\n } catch {\n /* best-effort — the next thread read brings it */\n }\n }\n }, [client, currentThreadId, applyQueue]);\n\n // Approve / reject / answer / skip route by tool-call id alone — the server derives the run\n // awaiting it (a sub-agent's own run when the call belongs to a delegated agent).\n const approve = useCallback(\n async ({ toolCallId, target, remember, via }: ApproveInput): Promise<void> => {\n if (target?.kind === 'proposal') {\n const threadId = target.threadId ?? currentThreadId();\n if (threadId === undefined)\n throw new Error('A proposal decision requires its thread scope');\n await requireBackendMethod(\n client,\n 'approveActionProposal',\n )({\n threadId,\n proposalId: target.proposalId,\n ...(remember === true ? { remember: true } : {}),\n });\n await proposals.refresh();\n return;\n }\n await requireBackendMethod(\n client,\n 'approveToolCall',\n )({\n toolCallId,\n ...(remember === true ? { remember: true } : {}),\n ...(via !== undefined ? { via } : {}),\n });\n },\n [client, currentThreadId, proposals.refresh],\n );\n\n const reject = useCallback(\n async ({ toolCallId, target, reason, via }: RejectInput): Promise<void> => {\n if (target?.kind === 'proposal') {\n const threadId = target.threadId ?? currentThreadId();\n if (threadId === undefined)\n throw new Error('A proposal decision requires its thread scope');\n await requireBackendMethod(\n client,\n 'rejectActionProposal',\n )({\n threadId,\n proposalId: target.proposalId,\n ...(reason === undefined ? {} : { reason }),\n });\n await proposals.refresh();\n return;\n }\n await requireBackendMethod(\n client,\n 'rejectToolCall',\n )({\n toolCallId,\n ...(reason !== undefined ? { reason } : {}),\n ...(via !== undefined ? { via } : {}),\n });\n },\n [client, currentThreadId, proposals.refresh],\n );\n\n const answer = useCallback(\n async ({ toolCallId, answers, via }: AnswerInput): Promise<void> => {\n await requireBackendMethod(\n client,\n 'answerToolCall',\n )({\n toolCallId,\n ...(answers !== undefined ? { answers } : {}),\n ...(via !== undefined ? { via } : {}),\n });\n },\n [client],\n );\n\n const skip = useCallback(\n async ({ toolCallId, via }: SkipInput): Promise<void> => {\n await requireBackendMethod(\n client,\n 'skipToolCall',\n )({ toolCallId, ...(via !== undefined ? { via } : {}) });\n },\n [client],\n );\n\n // Re-run the last exchange: flag the next request as a regenerate (so the backend truncates and\n // re-answers instead of appending) and let the SDK re-issue it.\n const regenerate = useCallback(\n (_input?: Partial<MessageActionInput>): void => {\n const block = blockedRef.current;\n if (block != null) throw new QuotaBlockedError(block);\n if (isTurnInFlight()) return;\n regenerateNext.current = true;\n turnInFlight.current = true;\n void chatRef.current.regenerate().finally(() => {\n turnInFlight.current = false;\n });\n },\n [isTurnInFlight],\n );\n\n /**\n * The persisted id of a message on screen. A message streamed in this session carries the\n * client's own id, so the row it became is found by the run that wrote it.\n */\n const storedIdOf = useCallback(\n async (messageId: string, threadId: string): Promise<string> => {\n const message = chatRef.current.messages.find((candidate) => candidate.id === messageId);\n const runOf = (message?.metadata as AgentMessageMetadata | undefined)?.runId;\n if (runOf === undefined) return messageId;\n const thread = await client.getThread(threadId);\n const row = [...thread.messages]\n .reverse()\n .find((candidate) => candidate.role === 'assistant' && candidate.runId === runOf);\n return row?.id ?? messageId;\n },\n [client],\n );\n\n /**\n * Branch the conversation at `messageId` into a new thread (`onThreadCreated` gets its id).\n * Defaults to this chat's thread.\n */\n const fork = useCallback(\n async ({\n messageId,\n threadId,\n }: MessageActionInput & { threadId?: string }): Promise<ThreadSummary> => {\n const source = threadId ?? currentThreadId();\n if (source === undefined) throw new Error('fork: this chat has no thread yet');\n const stored = await storedIdOf(messageId, source);\n const forked = await requireBackendMethod(client, 'forkFromMessage')(source, stored);\n notifyThreads(client, { type: 'changed' });\n latest.current.onThreadCreated?.(forked.id);\n return forked;\n },\n [client, currentThreadId, storedIdOf],\n );\n\n /** Delete `messageId` and everything after it on the thread (default: this chat's). */\n const truncateFrom = useCallback(\n async ({ messageId, threadId }: MessageActionInput & { threadId?: string }): Promise<void> => {\n const target = threadId ?? currentThreadId();\n if (target === undefined) throw new Error('truncateFrom: this chat has no thread yet');\n const stored = await storedIdOf(messageId, target);\n await requireBackendMethod(client, 'truncateFromMessage')(target, stored);\n },\n [client, currentThreadId, storedIdOf],\n );\n\n /** Make a transient thread (default: this chat's) a regular one, listed by `useThreads`. */\n const promote = useCallback(\n async ({ threadId }: { threadId?: string } = {}): Promise<void> => {\n const target = threadId ?? currentThreadId();\n if (target === undefined) throw new Error('promote: this chat has no thread yet');\n await requireBackendMethod(client, 'promoteThread')(target);\n notifyThreads(client, { type: 'changed' });\n },\n [client, currentThreadId],\n );\n\n // ---- models --------------------------------------------------------------------------------\n const [modelsWanted, setModelsWanted] = useState(false);\n const modelsWantedRef = useRef(modelsWanted);\n modelsWantedRef.current = modelsWanted;\n const catalog = useModels({\n backend: client,\n ...(options.agent !== undefined ? { agent: options.agent } : {}),\n enabled: modelsWanted && typeof client.listModels === 'function',\n });\n const wantModels = useCallback(() => {\n if (modelsWantedRef.current) return;\n modelsWantedRef.current = true;\n // After render: the getter may be read while a child renders.\n queueMicrotask(() => setModelsWanted(true));\n }, []);\n lockedRef.current = catalog.locked !== null;\n const selectModel = useCallback((id: string) => {\n if (!lockedRef.current) setPickedModel(id);\n }, []);\n const pinToThread = useCallback(\n async (model: string | null): Promise<void> => {\n const threadId = currentThreadId();\n setThreadModel(model);\n // The pin is what later turns run on: a pick would override it on every send.\n setPickedModel(undefined);\n if (threadId === undefined) {\n pendingPin.current = { model };\n return;\n }\n await client.updateThread(threadId, { model });\n notifyThreads(client, { type: 'changed' });\n },\n [client, currentThreadId],\n );\n const models: ChatModels = {\n get list() {\n wantModels();\n return catalog.models;\n },\n get providers() {\n wantModels();\n return catalog.providers;\n },\n selected:\n catalog.locked?.model ??\n options.model ??\n pickedModel ??\n threadModel ??\n catalog.defaultModel ??\n null,\n pinned: threadModel,\n get defaultModel() {\n wantModels();\n return catalog.defaultModel;\n },\n get locked() {\n wantModels();\n return catalog.locked;\n },\n select: selectModel,\n pinToThread,\n isLoading: modelsWanted && catalog.isLoading,\n error: catalog.error,\n };\n\n // A dropped stream the transport is retrying reads as its own status; every other moment is the\n // SDK's. `reconnecting` is still a busy status to the transcript model (see `ChatStatus`).\n const status: ChatStatus = connection.status === 'reconnecting' ? 'reconnecting' : chat.status;\n const isBusy = status === 'submitted' || status === 'streaming' || status === 'reconnecting';\n const isBusyRef = useRef(isBusy);\n isBusyRef.current = isBusy;\n\n // ---- composer ------------------------------------------------------------------------------\n const files = useAttachments({ ...options.composer, backend: client });\n const [text, setText] = useState('');\n const blockedBy: ComposerBlock | null =\n blocked != null\n ? 'quota'\n : files.isUploading\n ? 'uploading'\n : isBusy && whileRunning === 'block'\n ? 'busy'\n : text.trim().length === 0 && files.refs.length === 0\n ? 'empty'\n : null;\n const composerRef = useRef({ text, files, blockedBy });\n composerRef.current = { text, files, blockedBy };\n const submit = useCallback(\n async (options?: SendWhileRunning): Promise<void> => {\n const current = composerRef.current;\n // A mode named for this call is an answer to \"a turn is running\": it lifts that one block.\n const asked = canQueueRef.current ? options?.mode : undefined;\n if (current.blockedBy !== null && !(current.blockedBy === 'busy' && asked !== undefined)) {\n return;\n }\n if (current.text.trim().length === 0 && current.files.refs.length === 0) return;\n const refs = current.files.refs;\n // The sent message shows its files right away, as the reloaded thread will (`messageFiles`).\n const files = current.files.items.flatMap((item) =>\n item.status === 'ready' && item.attachment !== undefined\n ? [\n {\n type: 'file' as const,\n mediaType: item.attachment.contentType,\n filename: item.attachment.name,\n url: item.attachment.url,\n providerMetadata: { agent: { mediaId: item.attachment.mediaId } },\n },\n ]\n : [],\n );\n const draft = current.text.trim();\n setText('');\n current.files.clear();\n const mode = asked ?? whileRunningRef.current;\n if (mode !== 'block' && (isTurnInFlight() || isBusyRef.current)) {\n // Mid-turn: wait in the thread's queue (or, `interrupt`, cut in) instead of refusing.\n const attachments = current.files.items.flatMap((item) =>\n item.status === 'ready' && item.attachment !== undefined ? [item.attachment] : [],\n );\n await enqueue(draft, { attachments, mode });\n return;\n }\n await sendMessage(\n files.length > 0 ? { text: draft, files } : { text: draft },\n refs.length > 0 ? { body: { attachments: refs } } : undefined,\n );\n },\n [sendMessage, enqueue, isTurnInFlight],\n );\n const composer: ChatComposer = {\n text,\n setText,\n files,\n canSend: blockedBy === null,\n blockedBy,\n submit,\n };\n\n // ---- transcript ----------------------------------------------------------------------------\n const ownCatalog = options.transcript?.toolCatalog;\n const tools = useToolCatalog({\n backend: client,\n ...(options.agent !== undefined ? { agent: options.agent } : {}),\n enabled: ownCatalog === undefined && typeof client.listTools === 'function',\n });\n const canFork = typeof client.forkFromMessage === 'function';\n const transcript: ChatTranscript = useChatTranscript({\n messages: chat.messages,\n status,\n onStop: cancel,\n onApprove: approve,\n onReject: reject,\n onAnswer: answer,\n onSkip: skip,\n regeneratable: true,\n onRegenerate: regenerate,\n ...(canFork\n ? { onFork: (input: MessageActionInput) => fork(input).then(() => undefined) }\n : {}),\n ...(ownCatalog === undefined ? { toolCatalog: tools.catalog } : {}),\n queue: { items: queue.items, paused: queue.paused, remove: removeQueued },\n ...options.transcript,\n });\n\n const background: ChatBackground = {\n runs: backgroundRuns,\n isWorking,\n refresh: refreshBackground,\n };\n\n return {\n ...chat,\n status,\n /** Where the live stream stands — see {@link StreamConnectionState}. */\n connection,\n sendMessage,\n addToolResult,\n /** Sub-agents this conversation started and did not wait for. */\n background,\n proposals,\n runId,\n /** The loaded thread's running turn, or `null` once read with none. */\n activeRunId,\n /** The thread's history is being read. */\n isLoadingHistory,\n /** Reading the thread's history failed. */\n historyError,\n /**\n * How the last run's stream said it failed — the `event: error` frame's `code` and `message` —\n * or `null`. Cleared when the next attempt starts and when the chat moves to another thread.\n * `chat.error` still carries the message; this is where the `code` is, so the app can word each\n * failure itself (`replay_diverged`, `model_no_output`, `run_failed`, `quota_exceeded`, …).\n */\n runError,\n /**\n * The thread this chat is on right now: the `threadId` option, else the one the backend created\n * on the first send. A getter, because the created id is learned mid-stream.\n */\n getThreadId: currentThreadId,\n /** The backend this chat talks to — the same one every other hook under the provider uses. */\n backend: client,\n /** The transcript model, with every action already bound to this chat. */\n transcript,\n /** A headless composer: draft, files, send gate, `submit()`. */\n composer,\n /**\n * Messages sent while a turn was running, waiting their turn (server-side): list, edit, move,\n * remove, clear, and resume a paused queue.\n */\n queue,\n /** The model picker: `list`, `selected`, `select(id)`, `pinToThread(id)`. */\n models,\n /**\n * The persona pinned on this thread (`ThreadSummary.persona`), or `null` when none is — what a\n * persona picker on a reopened thread starts from (`?? agent.defaultPersona`).\n */\n threadPersona,\n /** The caller's budget (`GET <base>/quota`); `quota.blocked` gates sends. */\n quota,\n /** The window blocking sends right now (the `blocked` option, else the quota report's). */\n blocked,\n cancel,\n approve,\n reject,\n answer,\n skip,\n regenerate,\n fork,\n truncateFrom,\n promote,\n };\n}\n\n/** A send refused on the client because a quota window is exhausted. */\nexport class QuotaBlockedError extends Error {\n constructor(readonly block: QuotaBlock) {\n super(block.reason ?? `The ${block.period === 'day' ? 'daily' : 'monthly'} quota is used up`);\n this.name = 'QuotaBlockedError';\n }\n}\n","import type { ActionProposalView } from '@dudousxd/nestjs-agent-core';\nimport type { UIMessage } from 'ai';\nimport { useCallback, useEffect, useRef, useState } from 'react';\nimport type { AgentBackend } from '../backend.js';\nimport { proposalNeedsPolling, reconcileProposalMessages } from './proposals.js';\n\nexport interface ActionProposalsState {\n items: ActionProposalView[];\n error: Error | null;\n refresh(): Promise<void>;\n}\n\nexport function useActionProposals(\n backend: AgentBackend,\n threadId: string | undefined,\n setMessages: (update: (current: UIMessage[]) => UIMessage[]) => void,\n refreshKey: string,\n pollMs = 1000,\n): ActionProposalsState {\n const [items, setItems] = useState<ActionProposalView[]>([]);\n const [error, setError] = useState<Error | null>(null);\n const latest = useRef({ threadId, setMessages });\n latest.current = { threadId, setMessages };\n const mounted = useRef(true);\n const requests = useRef(new Map<string, Promise<void>>());\n useEffect(() => {\n mounted.current = true;\n return () => {\n mounted.current = false;\n };\n }, []);\n const refresh = useCallback(async () => {\n if (threadId === undefined || backend.listActionProposals === undefined) return;\n const pending = requests.current.get(threadId);\n if (pending) return pending;\n const request = (async () => {\n try {\n const proposals = await backend.listActionProposals?.({ threadId });\n if (!mounted.current || latest.current.threadId !== threadId || !Array.isArray(proposals))\n return;\n const admitted = proposals.some(\n (proposal) => proposal.outcomeDelivery?.status === 'admitted',\n );\n const facts = admitted\n ? (await backend.getThread(threadId)).messages.filter(\n (message) => message.actionProposalOutcome !== undefined,\n )\n : [];\n if (!mounted.current || latest.current.threadId !== threadId) return;\n setItems(proposals);\n setError(null);\n latest.current.setMessages((current) =>\n reconcileProposalMessages(current, proposals, facts),\n );\n } catch (cause) {\n if (mounted.current && latest.current.threadId === threadId)\n setError(cause instanceof Error ? cause : new Error(String(cause)));\n }\n })();\n requests.current.set(threadId, request);\n try {\n await request;\n } finally {\n requests.current.delete(threadId);\n }\n }, [backend, threadId]);\n // biome-ignore lint/correctness/useExhaustiveDependencies: A changed thread clears the prior scoped state.\n useEffect(() => {\n setItems([]);\n setError(null);\n }, [threadId]);\n // biome-ignore lint/correctness/useExhaustiveDependencies: Stream completion/reconnection triggers a scoped read.\n useEffect(() => {\n void refresh();\n }, [refresh, refreshKey]);\n useEffect(() => {\n if (!items.some(proposalNeedsPolling) || pollMs <= 0) return;\n const timer = setInterval(() => {\n void refresh();\n }, pollMs);\n return () => clearInterval(timer);\n }, [items, pollMs, refresh]);\n useEffect(() => {\n const refetch = () => {\n void refresh();\n };\n const visible = () => {\n if (document.visibilityState === 'visible') refetch();\n };\n window.addEventListener('focus', refetch);\n window.addEventListener('online', refetch);\n document.addEventListener('visibilitychange', visible);\n return () => {\n window.removeEventListener('focus', refetch);\n window.removeEventListener('online', refetch);\n document.removeEventListener('visibilitychange', visible);\n };\n }, [refresh]);\n return { items, error, refresh };\n}\n","import type { ActionProposalView, StoredMessage } from '@dudousxd/nestjs-agent-core';\nimport type { UIMessage } from 'ai';\nimport { storedMessageToUiMessage } from '../stored-message-to-ui-message.js';\n\nexport type ApprovalTarget =\n | { kind: 'legacy'; toolCallId: string }\n | { kind: 'proposal'; proposalId: string; threadId?: string };\n\nexport function proposalNeedsPolling(proposal: ActionProposalView): boolean {\n return (\n proposal.decision === 'pending' ||\n proposal.execution?.status === 'queued' ||\n proposal.execution?.status === 'executing' ||\n proposal.outcomeDelivery?.status === 'pending'\n );\n}\n\n/** Patch proposal metadata and append outcome facts; never replace live text with stored rows. */\nexport function reconcileProposalMessages(\n current: UIMessage[],\n proposals: ActionProposalView[],\n facts: StoredMessage[],\n): UIMessage[] {\n const messages = current.map((message) => {\n const relevant = proposals.filter((proposal) =>\n message.parts.some((part) => {\n if (\n 'data' in part &&\n record(part.data) &&\n record(part.data.target) &&\n part.data.target.kind === 'proposal'\n )\n return part.data.target.proposalId === proposal.id;\n if ('toolCallId' in part && part.toolCallId === proposal.originToolCallId) {\n if ('output' in part && record(part.output) && typeof part.output.proposalId === 'string')\n return part.output.proposalId === proposal.id;\n return record(message.metadata) && message.metadata.runId === proposal.originRunId;\n }\n return false;\n }),\n );\n if (relevant.length === 0) return message;\n const ids = new Set(relevant.map((proposal) => proposal.originToolCallId));\n const parts = message.parts.filter(\n (part) =>\n !(\n part.type === 'data-action-proposal' &&\n 'id' in part &&\n typeof part.id === 'string' &&\n ids.has(part.id)\n ),\n );\n for (const proposal of relevant)\n parts.push({\n type: 'data-action-proposal',\n id: proposal.originToolCallId,\n data: {\n id: proposal.originToolCallId,\n target: { kind: 'proposal', proposalId: proposal.id, threadId: proposal.threadId },\n approver: proposal.approver,\n confirmation: proposal.confirmation,\n expiresAt:\n proposal.expiresAt === null\n ? null\n : Math.abs(proposal.expiresAt) <= 8.64e15\n ? new Date(proposal.expiresAt).toISOString()\n : null,\n status: proposal.decision,\n executionStatus: proposal.execution?.status ?? null,\n remember: proposal.decisionAudit?.remember === true,\n decidedBy: proposal.decisionAudit?.actorRef ?? null,\n decidedVia: proposal.decisionAudit?.via ?? null,\n reason: proposal.decisionAudit?.reason ?? null,\n },\n });\n return { ...message, parts };\n });\n const knownMessages = new Set(messages.map((message) => message.id));\n const knownOutcomes = new Set(\n messages.map((message) => outcomeId(message.metadata)).filter(Boolean),\n );\n for (const fact of facts) {\n const id = fact.actionProposalOutcome?.id;\n if (id === undefined || knownMessages.has(fact.id) || knownOutcomes.has(id)) continue;\n const message = storedMessageToUiMessage(fact);\n messages.push({\n ...message,\n metadata: {\n ...(record(message.metadata) ? message.metadata : {}),\n actionProposalOutcomeId: id,\n },\n });\n knownMessages.add(fact.id);\n knownOutcomes.add(id);\n }\n return messages;\n}\nfunction record(value: unknown): value is Record<string, unknown> {\n return typeof value === 'object' && value !== null && !Array.isArray(value);\n}\nfunction outcomeId(value: unknown): string | undefined {\n return record(value) && typeof value.actionProposalOutcomeId === 'string'\n ? value.actionProposalOutcomeId\n : undefined;\n}\n","import type { AgentRequestError } from './http-error.js';\n\n/**\n * The `code`s this library's own loop closes a failed run's stream with (`event: error`). A client\n * branches on the code and words the failure itself — the frame's `message` is a sentence in\n * English, and for a crash deliberately a generic one.\n *\n * - `quota_exceeded` — the actor's budget is spent; `message` says which.\n * - `output_rejected` — an output processor refused the answer.\n * - `structured_output_invalid` — the answer never satisfied the agent's output schema.\n * - `replay_diverged` — the durable runtime refused to resume the run (its journal and the\n * deployed code disagree). The turn is over; sending again starts a new one.\n * - `model_no_output` — a model call ended without producing anything.\n * - `run_failed` — anything else.\n *\n * A host's own runner may send codes of its own, which is why {@link AgentRunFailure.code} is a\n * plain string.\n */\nexport const AGENT_RUN_ERROR_CODES = [\n 'quota_exceeded',\n 'output_rejected',\n 'structured_output_invalid',\n 'replay_diverged',\n 'model_no_output',\n 'run_failed',\n] as const;\n\nexport type AgentRunErrorCode = (typeof AGENT_RUN_ERROR_CODES)[number];\n\n/** How a run's stream said it failed: the `event: error` frame, read. */\nexport interface AgentRunFailure {\n /** The frame's machine-readable `code`; `undefined` when the server sent none. */\n code: AgentRunErrorCode | (string & {}) | undefined;\n /** The frame's `message` — the server's words, safe to show but not translated. */\n message: string;\n /** The run that failed, when the stream had named it. */\n runId?: string;\n}\n\n/** The `code` a decision is refused with when the run it was for has ended (`409`). */\nexport const RUN_NOT_ACTIVE_CODE = 'run_not_active';\n\n/**\n * Whether `error` is the server refusing an approve / reject / answer / skip because the turn that\n * asked is over (`409 { code: 'run_not_active' }`): nothing is waiting for the decision, and nothing\n * will run. The card it was made on is stale — say so, and let the person send the message again.\n */\nexport function isRunNotActiveError(error: unknown): error is AgentRequestError {\n return (\n error instanceof Error &&\n (error as Partial<AgentRequestError>).status === 409 &&\n (error as Partial<AgentRequestError>).code === RUN_NOT_ACTIVE_CODE\n );\n}\n"],"mappings":"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","names":["record","record","toolKind","fallback","useCallback","useEffect","useMemo","useRef","useState","useEffect","useState","useContext","useMemo","useRef","createContext","useContext","useMemo","useEffect","useState","Component","useState","useEffect","createContext","fallback","useContext","useMemo","fallback","useMemo","useContext","useContext","fallback","jsx","useRef","useMemo","useContext","useState","useEffect","useRef","useState","useCallback","backend","accept","maxBytes","maxFiles","useEffect","useMemo","isRecord","id","toolKind","fallback","useCallback","useMemo","useCallback","useEffect","useRef","useState","load","useCallback","useMemo","useMemo","useMemo","useEffect","useMemo","useEffect","useMemo","window","useCallback","useRef","useState","useRef","useState","useCallback","backend","useCallback","useEffect","useRef","useState","useState","useRef","useCallback","useEffect","useEffect","useState","useCallback","useEffect","useMemo","useRef","useState","jsx","useState","useEffect","React","useCallback","useEffect","useRef","useState","validateElicitationAnswer","getToolName","isSettled","fallback","isRecord","isSettled","isRecord","getToolName","input","validateElicitationAnswer","useCallback","useEffect","useRef","useState","useRef","useState","useEffect","useCallback","options","fallback","metadataOf","jsx","jsxs","React","jsx","jsxs","useCallback","useEffect","useMemo","useRef","useState","useRef","useState","useMemo","useEffect","useCallback","useCallback","useEffect","useMemo","useState","shared","load","useState","useEffect","useCallback","useMemo","useEffect","useRef","useState","toolKind","useCallback","useEffect","useMemo","useRef","useState","useCallback","useEffect","useRef","useState","useState","useRef","useEffect","useCallback","useRef","useState","useCallback","useMemo","regenerate","useEffect","queue","text","options","files"]}
|
|
1
|
+
{"version":3,"sources":["../src/http-error.ts","../src/client.ts","../src/reasoning/timing.ts","../src/agent-chat-transport.ts","../src/attachments/files.ts","../src/attachments/use-attachments.ts","../src/backend.ts","../src/config/use-agent-config.ts","../src/provider.tsx","../src/components/ambient-ui.ts","../src/genui/generative-ui.tsx","../src/genui/share-structure.ts","../src/genui/use-generative-ui.ts","../src/genui/types.ts","../src/ag-ui-backend.ts","../src/catalog/use-agents.ts","../src/catalog/use-resource.ts","../src/catalog/use-models.ts","../src/quota/use-quota.ts","../src/threads/threads-events.ts","../src/feedback/use-message-feedback.ts","../src/threads/use-threads.ts","../src/background-runs.ts","../src/components/chat-input.tsx","../src/components/use-speech-recognition.ts","../src/components/message-item.tsx","../src/transcript/use-chat-transcript.ts","../src/transcript/model.ts","../src/elicitation/answers.ts","../src/presentation/tool-activity.ts","../src/presentation/phrasing.ts","../src/presentation/result-view.ts","../src/transcript/use-stick-to-bottom.ts","../src/components/message-list.tsx","../src/components/speech-languages.ts","../src/composer/model.ts","../src/composer/skills-source.ts","../src/composer/use-composer-autocomplete.ts","../src/presentation/use-tool-catalog.ts","../src/approvals/countdown.ts","../src/stored-message-to-ui-message.ts","../src/stored-thread-to-ui-messages.ts","../src/use-agent-chat.ts","../src/approvals/use-action-proposals.ts","../src/approvals/proposals.ts","../src/run-errors.ts"],"sourcesContent":["/**\n * What a server said when it refused a request, read once so every error class of this package\n * reports it the same way. Bundled into each entry that throws (the root and `/media`), which is\n * why it holds no class of its own.\n */\nexport interface ErrorAnswer {\n /** The body, parsed as JSON when it is JSON, else the raw text; `undefined` when empty. */\n body: unknown;\n /** `body.message` — a string, or NestJS's list of validation messages joined with `; `. */\n message: string | undefined;\n /** `body.code`, the machine-readable reason (`quota_exceeded`, …), when the server sent one. */\n code: string | undefined;\n}\n\n/** Read an error answer's body text. Never throws: a body that cannot be read is just absent. */\nexport function readErrorAnswer(text: string | null | undefined): ErrorAnswer {\n if (text == null || text === '') return { body: undefined, message: undefined, code: undefined };\n let body: unknown = text;\n try {\n body = JSON.parse(text);\n } catch {\n return { body: text, message: undefined, code: undefined };\n }\n if (body === null || typeof body !== 'object')\n return { body, message: undefined, code: undefined };\n const record = body as { message?: unknown; code?: unknown };\n const message =\n typeof record.message === 'string' && record.message !== ''\n ? record.message\n : Array.isArray(record.message) &&\n record.message.length > 0 &&\n record.message.every((each) => typeof each === 'string')\n ? record.message.join('; ')\n : undefined;\n const code = typeof record.code === 'string' && record.code !== '' ? record.code : undefined;\n return { body, message, code };\n}\n\n/** {@link readErrorAnswer} over a `Response` whose status is not 2xx. */\nexport async function readErrorResponse(response: Response): Promise<ErrorAnswer> {\n let text: string | undefined;\n try {\n text = await response.text();\n } catch {\n text = undefined;\n }\n return readErrorAnswer(text);\n}\n\n/**\n * The shape both {@link import('./client.js').AgentHttpError} and `MediaUploadError` share, for\n * code that handles either without an `instanceof` (the two live in separate bundles).\n */\nexport interface AgentRequestError extends Error {\n status: number;\n method: string;\n path: string;\n body: unknown;\n code: string | undefined;\n}\n\n/** Called with every error answer before it is thrown — for app-wide reactions (401, 402, …). */\nexport type HttpErrorListener = (error: AgentRequestError) => void;\n\n/** Tell `listener` about `error`; a listener that throws never replaces the error itself. */\nexport function reportHttpError(\n listener: HttpErrorListener | undefined,\n error: AgentRequestError,\n): void {\n if (listener === undefined) return;\n try {\n listener(error);\n } catch {\n /* the request's own error is what the caller gets */\n }\n}\n","import type {\n ActionProposalMutationView,\n ActionProposalView,\n AgentCatalogEntry,\n AgentClientConfig,\n ChatQueueState,\n MessageAttachment,\n MessageFeedback,\n ModelCatalogView,\n QuotaReport,\n SkillCatalogEntry,\n ThreadDetail,\n ThreadSummary,\n ToolCatalogEntry,\n} from '@dudousxd/nestjs-agent-core';\nimport type {\n AgentBackend,\n AgentConnection,\n AttachmentUploadStrategy,\n ChatStreamRequest,\n ChatStreamResponse,\n MessageFeedbackInput,\n QueuedMessageUpdate,\n QueuedSendResult,\n ResumeStreamRequest,\n ThreadPatch,\n UploadAttachmentOptions,\n} from './backend.js';\n\nimport {\n type AgentRequestError,\n type ErrorAnswer,\n type HttpErrorListener,\n readErrorAnswer,\n readErrorResponse,\n reportHttpError,\n} from './http-error.js';\n\nexport type { ThreadPatch } from './backend.js';\nexport type { AgentRequestError, HttpErrorListener } from './http-error.js';\n\n/**\n * Thrown by {@link AgentClient} on a non-2xx response. Carries the HTTP `status` so callers can\n * branch (e.g. 403 → \"not your thread\", 429 → quota) instead of string-matching a generic Error,\n * and what the server said: `message` is the body's `message` when it sent one (so a hook that\n * shows `error.message` shows the server's words), `code` its machine-readable `code`, and `body`\n * the whole answer, parsed when it is JSON.\n */\nexport class AgentHttpError extends Error implements AgentRequestError {\n /** The answer's body: parsed JSON, else its text; `undefined` when empty. */\n readonly body: unknown;\n /** The body's `code` (`quota_exceeded`, …), when the server sent one. */\n readonly code: string | undefined;\n\n constructor(\n readonly status: number,\n readonly method: string,\n readonly path: string,\n statusText: string,\n answer: ErrorAnswer = { body: undefined, message: undefined, code: undefined },\n ) {\n super(answer.message ?? `Agent request failed: ${method} ${path} → ${status} ${statusText}`);\n this.name = 'AgentHttpError';\n this.body = answer.body;\n this.code = answer.code;\n }\n\n /** Read a refused `response`'s body into an error. */\n static async from(response: Response, method: string, path: string): Promise<AgentHttpError> {\n return new AgentHttpError(\n response.status,\n method,\n path,\n response.statusText,\n await readErrorResponse(response),\n );\n }\n}\n\nexport interface CancelResult {\n aborted: boolean;\n}\n\nexport interface OkResult {\n ok: boolean;\n}\n\nexport interface AgentClientOptions {\n /**\n * The server's origin, e.g. `https://api.example.com`. Defaults to `''` (same origin). The\n * agent's route prefix is {@link AgentClientOptions.path}, not part of this.\n */\n baseUrl?: string;\n /**\n * The agent's route prefix — `AgentModule`'s `path`, with any global prefix in front\n * (`'api/agent'`). Leading/trailing slashes are optional. Defaults to `'agent'`.\n */\n path?: string;\n /** Static headers merged into every request. */\n headers?: Record<string, string>;\n /**\n * Resolved per request — for short-lived bearer tokens, or a CSRF header read from a cookie\n * (`{ 'X-XSRF-TOKEN': readCookie('XSRF-TOKEN') }`), which has to be read at request time because\n * the server may rotate it.\n */\n getHeaders?: () => Record<string, string> | Promise<Record<string, string>>;\n /**\n * Forwarded to fetch so cookie auth works. Same-origin requests send cookies by default; set\n * `'include'` when the API lives on another origin (and have it answer with credentialed CORS).\n */\n credentials?: RequestCredentials;\n /** Injectable for tests / non-browser runtimes. */\n fetch?: typeof fetch;\n /**\n * Called with every error answer (an {@link AgentHttpError}, or a `MediaUploadError` from a\n * `mediaAttachments()` upload) right before it is thrown — the place for app-wide reactions such\n * as \"401 → sign in again\". The error still reaches the caller. Not called for the `404` a\n * resume answers when nothing is streaming, which is an answer, not a failure.\n */\n onHttpError?: HttpErrorListener;\n /** Attachment uploads. */\n attachments?: {\n /**\n * How `uploadAttachment` uploads. Omitted → `POST <path>/attachments` (multipart). Pass\n * `mediaAttachments()` from `@dudousxd/nestjs-agent-react/media` for resumable uploads through\n * nestjs-media, or your own {@link AttachmentUploadStrategy}.\n */\n upload?: AttachmentUploadStrategy;\n };\n}\n\n/** `'/api/agent'` from `'api/agent'`, `'/api/agent/'`, …; `''` for an empty path. */\nexport function normalizeAgentPath(path: string | undefined): string {\n const trimmed = (path ?? 'agent').replace(/^\\/+|\\/+$/g, '');\n return trimmed === '' ? '' : `/${trimmed}`;\n}\n\nconst HEADER_RUN_ID = 'x-agent-run-id';\nconst HEADER_THREAD_ID = 'x-agent-thread-id';\n\n/**\n * Framework-agnostic REST client for the nestjs-agent endpoints — the default {@link AgentBackend}.\n * Used by `useAgentChat`, but standalone-usable (vanilla fetch, no React).\n */\nexport class AgentClient implements AgentBackend {\n constructor(private readonly options: AgentClientOptions = {}) {}\n\n /** `POST <path>/chat` → the turn's SSE stream. Throws {@link AgentHttpError} on a non-2xx. */\n async openChatStream(request: ChatStreamRequest): Promise<ChatStreamResponse> {\n const response = await this.fetchImpl()(`${this.root()}/chat`, {\n method: 'POST',\n headers: {\n 'content-type': 'application/json',\n accept: 'text/event-stream',\n ...(await this.resolveHeaders()),\n ...request.headers,\n },\n body: JSON.stringify(request.body),\n ...this.credentials(),\n ...(request.signal !== undefined ? { signal: request.signal } : {}),\n });\n if (response.status === 202) {\n // Queued behind a turn already running on the thread: JSON, not a stream.\n return { body: emptyStream(), queued: (await response.json()) as QueuedSendResult };\n }\n if (response.ok && response.headers.get('content-type')?.includes('application/json')) {\n const decision = (await response.json()) as NonNullable<\n ChatStreamResponse['proposalDecision']\n >;\n if (decision.proposalDecision !== undefined && typeof decision.threadId === 'string')\n return { body: emptyStream(), threadId: decision.threadId, proposalDecision: decision };\n throw new Error('Unexpected JSON chat response');\n }\n if (!response.ok || !response.body) {\n throw await this.failure(response, 'POST', `${this.agentPath()}/chat`);\n }\n return streamResponse(response);\n }\n\n /**\n * `POST <path>/chat` for a message that should wait in the thread's queue — the body carries\n * `mode: 'queue'` (or `'interrupt'`), which the server always answers with `202` JSON.\n */\n enqueueMessage(request: ChatStreamRequest): Promise<QueuedSendResult> {\n return this.request<QueuedSendResult>('POST', '/chat', {\n mode: 'queue',\n ...request.body,\n });\n }\n\n /** `GET <path>/threads/:id/queue` — the thread's waiting messages, and whether it drains. */\n getQueue(threadId: string): Promise<ChatQueueState> {\n return this.request<ChatQueueState>('GET', `/threads/${encodeURIComponent(threadId)}/queue`);\n }\n\n /** `PATCH <path>/queue/:messageId` — change a waiting message's text/attachments, or move it. */\n updateQueuedMessage(messageId: string, update: QueuedMessageUpdate): Promise<ChatQueueState> {\n return this.request<ChatQueueState>('PATCH', `/queue/${encodeURIComponent(messageId)}`, update);\n }\n\n /** `DELETE <path>/queue/:messageId`. */\n removeQueuedMessage(messageId: string): Promise<ChatQueueState> {\n return this.request<ChatQueueState>('DELETE', `/queue/${encodeURIComponent(messageId)}`);\n }\n\n /**\n * `POST <path>/queue/:messageId/interrupt` — run a waiting message now, cancelling the running\n * turn for it. `runId` when nothing was running and it started; else `interrupting`.\n */\n interruptQueuedMessage(\n messageId: string,\n ): Promise<ChatQueueState & { runId?: string; interrupting?: string }> {\n return this.request<ChatQueueState & { runId?: string; interrupting?: string }>(\n 'POST',\n `/queue/${encodeURIComponent(messageId)}/interrupt`,\n );\n }\n\n /** `DELETE <path>/threads/:id/queue` — drop every waiting message. */\n clearQueue(threadId: string): Promise<ChatQueueState> {\n return this.request<ChatQueueState>('DELETE', `/threads/${encodeURIComponent(threadId)}/queue`);\n }\n\n /** `POST <path>/threads/:id/queue/resume` — lift a pause; `runId` when the head started. */\n resumeQueue(threadId: string): Promise<ChatQueueState & { runId?: string }> {\n return this.request<ChatQueueState & { runId?: string }>(\n 'POST',\n `/threads/${encodeURIComponent(threadId)}/queue/resume`,\n );\n }\n\n /**\n * `GET <path>/chat/:runId/stream[?after=<seq>]` → the run's SSE stream, or `null` when nothing is\n * streaming under that id (404).\n */\n async resumeChatStream(request: ResumeStreamRequest): Promise<ChatStreamResponse | null> {\n const path = `/chat/${encodeURIComponent(request.runId)}/stream`;\n const query = request.after !== undefined && request.after > 0 ? `?after=${request.after}` : '';\n const response = await this.fetchImpl()(`${this.root()}${path}${query}`, {\n method: 'GET',\n headers: {\n accept: 'text/event-stream',\n ...(await this.resolveHeaders()),\n ...request.headers,\n },\n ...this.credentials(),\n ...(request.signal !== undefined ? { signal: request.signal } : {}),\n });\n if (response.status === 404) {\n return null;\n }\n if (!response.ok || !response.body) {\n throw await this.failure(response, 'GET', `${this.agentPath()}${path}`);\n }\n return streamResponse(response);\n }\n\n /**\n * Rate a message (`'up'`/`'down'`, optional comment) or clear its rating (`value: null`). Answers\n * the stored rating.\n */\n setMessageFeedback(\n messageId: string,\n input: MessageFeedbackInput,\n ): Promise<{ feedback: MessageFeedback | null }> {\n return this.request<{ feedback: MessageFeedback | null }>(\n 'POST',\n `/messages/${encodeURIComponent(messageId)}/feedback`,\n input,\n );\n }\n\n listThreads(): Promise<ThreadSummary[]> {\n return this.request<ThreadSummary[]>('GET', '/threads');\n }\n\n /**\n * The skills this caller can invoke right now, scope-resolved — the same list, built by the same\n * call, that the model is offered, so what a user can type after a `/` and what the agent can\n * reach cannot drift apart. `threadId` reaches the host's own resolver, which may scope a skill to\n * one conversation; omitted, the server reads it as a brand-new thread.\n */\n listSkills(threadId?: string): Promise<SkillCatalogEntry[]> {\n const query = threadId === undefined ? '' : `?threadId=${encodeURIComponent(threadId)}`;\n return this.request<SkillCatalogEntry[]>('GET', `/skills${query}`);\n }\n\n /**\n * The tools this caller can reach through `agent` (the default agent when omitted), each with the\n * server-declared `presentation` a chat narrates it by — the same list the model is offered.\n * Prefer {@link useToolCatalog}, which fetches it once and shares it.\n */\n listTools(agent?: string): Promise<ToolCatalogEntry[]> {\n const query = agent === undefined ? '' : `?agent=${encodeURIComponent(agent)}`;\n return this.request<ToolCatalogEntry[]>('GET', `/tools${query}`);\n }\n\n getThread(id: string): Promise<ThreadDetail> {\n return this.request<ThreadDetail>('GET', `/threads/${encodeURIComponent(id)}`);\n }\n\n deleteThread(id: string): Promise<void> {\n return this.request<void>('DELETE', `/threads/${encodeURIComponent(id)}`);\n }\n\n forkFromMessage(threadId: string, messageId: string): Promise<ThreadSummary> {\n return this.request<ThreadSummary>(\n 'POST',\n `/threads/${encodeURIComponent(threadId)}/fork-from/${encodeURIComponent(messageId)}`,\n );\n }\n\n /** General `PATCH <path>/threads/:threadId` — title and/or the thread's pinned default agent. */\n updateThread(id: string, patch: ThreadPatch): Promise<OkResult> {\n return this.request<OkResult>('PATCH', `/threads/${encodeURIComponent(id)}`, patch);\n }\n\n /**\n * Uploads a file (image/PDF) for a vision-capable model turn. Multipart, field name `file` —\n * mirrors the backend's `POST <path>/attachments`. The returned {@link MessageAttachment} is\n * what a caller then rides on `sendMessage({ text }, { body: { attachments: [...] } })`.\n */\n async uploadAttachment(\n file: File,\n options: UploadAttachmentOptions = {},\n ): Promise<MessageAttachment> {\n const upload = this.options.attachments?.upload;\n if (upload !== undefined) {\n return upload(file, options, this.connection());\n }\n // `fetch` cannot observe an upload's progress; XHR can. Only when someone is listening, and\n // never when a `fetch` was injected (tests, non-browser runtimes).\n if (\n options.onProgress !== undefined &&\n this.options.fetch === undefined &&\n typeof XMLHttpRequest !== 'undefined'\n ) {\n return this.uploadWithProgress(file, options);\n }\n const formData = new FormData();\n formData.append('file', file);\n const response = await this.fetchImpl()(`${this.root()}/attachments`, {\n method: 'POST',\n headers: {\n accept: 'application/json',\n ...(await this.resolveHeaders()),\n },\n body: formData,\n ...this.credentials(),\n ...(options.signal !== undefined ? { signal: options.signal } : {}),\n });\n const attachment = await this.handleResponse<MessageAttachment>(\n response,\n 'POST',\n `${this.agentPath()}/attachments`,\n );\n options.onProgress?.(1);\n return attachment;\n }\n\n private async uploadWithProgress(\n file: File,\n { signal, onProgress }: UploadAttachmentOptions,\n ): Promise<MessageAttachment> {\n const headers: Record<string, string> = {\n accept: 'application/json',\n ...(await this.resolveHeaders()),\n };\n const url = `${this.root()}/attachments`;\n return new Promise<MessageAttachment>((resolve, reject) => {\n const xhr = new XMLHttpRequest();\n xhr.open('POST', url);\n for (const [name, value] of Object.entries(headers)) xhr.setRequestHeader(name, value);\n // Same-origin requests carry cookies regardless; this is the cross-origin opt-in.\n xhr.withCredentials = this.options.credentials === 'include';\n xhr.upload.onprogress = (event) => {\n if (event.lengthComputable && event.total > 0) onProgress?.(event.loaded / event.total);\n };\n xhr.onload = () => {\n if (xhr.status < 200 || xhr.status >= 300) {\n const error = new AgentHttpError(\n xhr.status,\n 'POST',\n `${this.agentPath()}/attachments`,\n xhr.statusText,\n readErrorAnswer(xhr.responseText),\n );\n reportHttpError(this.options.onHttpError, error);\n reject(error);\n return;\n }\n onProgress?.(1);\n resolve(JSON.parse(xhr.responseText) as MessageAttachment);\n };\n xhr.onerror = () => reject(new TypeError('Network error while uploading the attachment'));\n xhr.onabort = () => reject(new DOMException('The upload was aborted', 'AbortError'));\n if (signal !== undefined) {\n if (signal.aborted) {\n reject(new DOMException('The upload was aborted', 'AbortError'));\n return;\n }\n signal.addEventListener('abort', () => xhr.abort(), { once: true });\n }\n const formData = new FormData();\n formData.append('file', file);\n xhr.send(formData);\n });\n }\n\n promoteThread(id: string): Promise<OkResult> {\n return this.request<OkResult>('POST', `/threads/${encodeURIComponent(id)}/promote`);\n }\n\n truncateFromMessage(threadId: string, messageId: string): Promise<OkResult> {\n return this.request<OkResult>(\n 'DELETE',\n `/threads/${encodeURIComponent(threadId)}/from/${encodeURIComponent(messageId)}`,\n );\n }\n\n /** `GET <path>/models?agent=` — the models this caller may pick, grouped by provider. */\n listModels(agent?: string): Promise<ModelCatalogView> {\n const query = agent === undefined ? '' : `?agent=${encodeURIComponent(agent)}`;\n return this.request<ModelCatalogView>('GET', `/models${query}`);\n }\n\n /** `GET <path>/agents` — the registered agents, the default one flagged. */\n listAgents(): Promise<AgentCatalogEntry[]> {\n return this.request<AgentCatalogEntry[]>('GET', '/agents');\n }\n\n /** `GET <path>/config` — attachment limits and upload mode, and which features are on. */\n getConfig(): Promise<AgentClientConfig> {\n return this.request<AgentClientConfig>('GET', '/config');\n }\n\n /** `GET <path>/quota` — the caller's budget windows and the one blocking sends, if any. */\n getQuota(): Promise<QuotaReport> {\n return this.request<QuotaReport>('GET', '/quota');\n }\n\n cancelStream(runId: string): Promise<CancelResult> {\n return this.request<CancelResult>('POST', `/chat/${encodeURIComponent(runId)}/cancel`);\n }\n\n /**\n * `remember` approves later calls of the same tool in the same thread; `via` names the surface\n * the decision came through (the server records `'web'` when omitted).\n */\n async listActionProposals({ threadId }: { threadId: string }): Promise<ActionProposalView[]> {\n const proposals = new Map<string, ActionProposalView>();\n let after: { createdAt: number; id: string } | undefined;\n for (;;) {\n const route = `/threads/${encodeURIComponent(threadId)}/action-proposals${\n after === undefined ? '' : `?after=${encodeURIComponent(JSON.stringify(after))}`\n }`;\n const response = await this.requestResponse('GET', route);\n const page = await this.handleResponse<unknown>(\n response,\n 'GET',\n `${this.agentPath()}${route}`,\n );\n if (!Array.isArray(page)) throw new TypeError('Invalid action proposal page');\n for (const proposal of page) proposals.set(proposal.id, proposal);\n const header = response.headers.get('X-Action-Proposals-Next');\n if (header === null) return [...proposals.values()];\n let next: unknown;\n try {\n next = JSON.parse(decodeURIComponent(header));\n } catch {\n throw new TypeError('Invalid action proposal cursor');\n }\n if (\n typeof next !== 'object' ||\n next === null ||\n !('createdAt' in next) ||\n typeof next.createdAt !== 'number' ||\n !Number.isSafeInteger(next.createdAt) ||\n !('id' in next) ||\n typeof next.id !== 'string' ||\n next.id.length === 0 ||\n next.id.length > 255 ||\n (after !== undefined &&\n (next.createdAt < after.createdAt ||\n (next.createdAt === after.createdAt && next.id <= after.id)))\n )\n throw new TypeError('Invalid or non-advancing action proposal cursor');\n after = { createdAt: next.createdAt, id: next.id };\n }\n }\n approveActionProposal({\n threadId,\n proposalId,\n remember,\n }: {\n threadId: string;\n proposalId: string;\n remember?: boolean;\n }): Promise<ActionProposalMutationView> {\n return this.request(\n 'POST',\n `/threads/${encodeURIComponent(threadId)}/action-proposals/${encodeURIComponent(proposalId)}/approve`,\n remember === undefined ? {} : { remember },\n );\n }\n rejectActionProposal({\n threadId,\n proposalId,\n reason,\n }: {\n threadId: string;\n proposalId: string;\n reason?: string;\n }): Promise<ActionProposalMutationView> {\n return this.request(\n 'POST',\n `/threads/${encodeURIComponent(threadId)}/action-proposals/${encodeURIComponent(proposalId)}/reject`,\n reason === undefined ? {} : { reason },\n );\n }\n\n approveToolCall(input: { toolCallId: string; remember?: boolean; via?: string }): Promise<void> {\n return this.request<void>('POST', '/tool-call/approve', input);\n }\n\n rejectToolCall(input: { toolCallId: string; reason?: string; via?: string }): Promise<void> {\n return this.request<void>('POST', '/tool-call/reject', input);\n }\n\n /**\n * Settle a parked question set. `answers` is questionId → chosen option values; a question left\n * out takes the pre-picked default the request carried, resolved server-side against the request\n * the run already holds. Omit the whole object and the user has confirmed every pre-picked\n * answer — which is the point of the surface, so it is a valid submission rather than a blank.\n * `via` names the surface the answer came through (the server records `'web'` when omitted).\n */\n answerToolCall(input: {\n toolCallId: string;\n answers?: Record<string, string[]>;\n via?: string;\n }): Promise<void> {\n return this.request<void>('POST', '/tool-call/answer', input);\n }\n\n /**\n * Decline to answer and let the agent proceed on its own pre-picked values. Lands on the same\n * values a confirmation would, and persists differently on purpose — only one of them is\n * evidence the user chose them.\n */\n skipToolCall(input: { toolCallId: string; via?: string }): Promise<void> {\n return this.request<void>('POST', '/tool-call/skip', input);\n }\n\n private fetchImpl(): typeof fetch {\n return this.options.fetch ?? globalThis.fetch;\n }\n\n /** This client's connection, for an {@link AttachmentUploadStrategy}. */\n private connection(): AgentConnection {\n return {\n baseUrl: this.baseUrl(),\n path: this.agentPath(),\n headers: () => this.resolveHeaders(),\n fetch: this.fetchImpl(),\n ...this.credentials(),\n ...(this.options.onHttpError !== undefined ? { onHttpError: this.options.onHttpError } : {}),\n };\n }\n\n private baseUrl(): string {\n return (this.options.baseUrl ?? '').replace(/\\/+$/, '');\n }\n\n private agentPath(): string {\n return normalizeAgentPath(this.options.path);\n }\n\n /** Origin + agent path: what every route hangs off. */\n private root(): string {\n return `${this.baseUrl()}${this.agentPath()}`;\n }\n\n private async resolveHeaders(): Promise<Record<string, string>> {\n const dynamic = (await this.options.getHeaders?.()) ?? {};\n return { ...this.options.headers, ...dynamic };\n }\n\n private credentials(): { credentials?: RequestCredentials } {\n return this.options.credentials !== undefined ? { credentials: this.options.credentials } : {};\n }\n\n private async request<T>(method: string, route: string, body?: unknown): Promise<T> {\n const response = await this.requestResponse(method, route, body);\n return this.handleResponse<T>(response, method, `${this.agentPath()}${route}`);\n }\n\n private async requestResponse(method: string, route: string, body?: unknown): Promise<Response> {\n const path = `${this.agentPath()}${route}`;\n const response = await this.fetchImpl()(`${this.baseUrl()}${path}`, {\n method,\n headers: {\n accept: 'application/json',\n ...(body !== undefined ? { 'content-type': 'application/json' } : {}),\n ...(await this.resolveHeaders()),\n },\n ...(body !== undefined ? { body: JSON.stringify(body) } : {}),\n ...this.credentials(),\n });\n return response;\n }\n\n /** The error for a refused `response`, already reported to `onHttpError`. */\n private async failure(response: Response, method: string, path: string): Promise<AgentHttpError> {\n const error = await AgentHttpError.from(response, method, path);\n reportHttpError(this.options.onHttpError, error);\n return error;\n }\n\n private async handleResponse<T>(response: Response, method: string, path: string): Promise<T> {\n if (!response.ok) {\n throw await this.failure(response, method, path);\n }\n if (response.status === 204) return undefined as T;\n const text = await response.text();\n if (!text) return undefined as T;\n return JSON.parse(text) as T;\n }\n}\n\nfunction emptyStream(): ReadableStream<Uint8Array> {\n return new ReadableStream<Uint8Array>({\n start(controller) {\n controller.close();\n },\n });\n}\n\nfunction streamResponse(response: Response): ChatStreamResponse {\n const body = response.body as ReadableStream<Uint8Array>;\n const runId = response.headers?.get(HEADER_RUN_ID) ?? undefined;\n const threadId = response.headers?.get(HEADER_THREAD_ID) ?? undefined;\n return {\n body,\n ...(runId ? { runId } : {}),\n ...(threadId ? { threadId } : {}),\n };\n}\n","import { useEffect, useRef, useState } from 'react';\n\n/**\n * Where a reasoning part carries how long the model thought, in ms. Both producers write it here —\n * the transport on the live `reasoning-end` chunk, `storedMessageToUiMessage` on a replayed part —\n * so a reader has one place to look whichever way the message arrived.\n */\nexport const REASONING_METADATA_KEY = 'agent';\n\n/** The `providerMetadata` a reasoning part is stamped with. */\nexport function reasoningDurationMetadata(reasoningMs: number): {\n [REASONING_METADATA_KEY]: { reasoningMs: number };\n} {\n return { [REASONING_METADATA_KEY]: { reasoningMs } };\n}\n\n/** The thinking time stamped on a reasoning part, or `null` when it carries none. */\nexport function readReasoningMs(part: { providerMetadata?: unknown }): number | null {\n const metadata = part.providerMetadata;\n if (typeof metadata !== 'object' || metadata === null) return null;\n const scoped = (metadata as Record<string, unknown>)[REASONING_METADATA_KEY];\n if (typeof scoped !== 'object' || scoped === null) return null;\n const value = (scoped as Record<string, unknown>).reasoningMs;\n return typeof value === 'number' && Number.isFinite(value) && value >= 0 ? value : null;\n}\n\nexport interface UseElapsedOptions {\n /** How often the value re-renders while running. Default 1000 — a seconds label needs no more. */\n intervalMs?: number;\n /** Injectable clock for tests. */\n now?: () => number;\n}\n\n/**\n * Milliseconds since `running` last turned true — ticking while it stays true, frozen at the final\n * value once it turns false, `0` before it has ever run. Headless: pair it with\n * {@link formatElapsed} or any label of your own.\n *\n * For a reasoning block, prefer the duration the block already carries (`block.durationMs`, the\n * server's own measurement) and fall back to this only while the block streams:\n * `block.durationMs ?? elapsed`.\n */\nexport function useElapsed(running: boolean, options: UseElapsedOptions = {}): number {\n const { intervalMs = 1000 } = options;\n const nowRef = useRef(options.now ?? Date.now);\n nowRef.current = options.now ?? Date.now;\n const startedAt = useRef<number | null>(null);\n const [elapsed, setElapsed] = useState(0);\n\n useEffect(() => {\n if (!running) {\n if (startedAt.current !== null) {\n setElapsed(nowRef.current() - startedAt.current);\n startedAt.current = null;\n }\n return;\n }\n startedAt.current = nowRef.current();\n setElapsed(0);\n const timer = setInterval(() => {\n if (startedAt.current !== null) setElapsed(nowRef.current() - startedAt.current);\n }, intervalMs);\n return () => clearInterval(timer);\n }, [running, intervalMs]);\n\n return elapsed;\n}\n\n/**\n * `\"<1s\"`, `\"4s\"`, `\"1m 5s\"`, `\"1h 2m\"` — whole units, the shape a \"Thought for …\" label wants.\n * Negative or non-finite input reads as `\"<1s\"` rather than a nonsense figure.\n */\nexport function formatElapsed(ms: number): string {\n if (!Number.isFinite(ms) || ms < 1000) return '<1s';\n const totalSeconds = Math.floor(ms / 1000);\n const hours = Math.floor(totalSeconds / 3600);\n const minutes = Math.floor((totalSeconds % 3600) / 60);\n const seconds = totalSeconds % 60;\n if (hours > 0) return minutes > 0 ? `${hours}h ${minutes}m` : `${hours}h`;\n if (minutes > 0) return seconds > 0 ? `${minutes}m ${seconds}s` : `${minutes}m`;\n return `${seconds}s`;\n}\n","import type { AgentStreamEvent } from '@dudousxd/nestjs-agent-core';\nimport type { ChatTransport, UIMessage, UIMessageChunk } from 'ai';\nimport type { AgentBackend, ChatStreamResponse, QueuedSendResult } from './backend.js';\nimport { AgentClient } from './client.js';\nimport { reasoningDurationMetadata } from './reasoning/timing.js';\nimport type { AgentRunFailure } from './run-errors.js';\n\n/** JSON-safe metadata, as the SDK's `toolMetadata` requires (its `JSONObject` is not exported). */\ntype ToolMetadata = { [key: string]: string };\n\n/** Identity surfaced by the backend's `meta` SSE frame / response headers. */\nexport interface AgentStreamMeta {\n runId: string;\n threadId: string;\n}\n\n/**\n * How the transport retries a stream that dropped mid-run. It reconnects only to a server that\n * numbers its frames (SSE `id:`) — without a cursor a reconnect would replay the run into the\n * message it is already writing.\n */\nexport interface ReconnectOptions {\n /** Attempts before giving up with an error chunk. Default 6. */\n maxAttempts?: number;\n /** Delay before the first attempt, doubled each attempt. Default 500 ms. */\n baseDelayMs?: number;\n /** Cap on the delay between attempts. Default 8000 ms. */\n maxDelayMs?: number;\n}\n\n/** Where a live stream stands. `reconnecting` → it dropped and the transport is retrying. */\nexport type StreamConnectionState =\n | { status: 'live' }\n | { status: 'reconnecting'; runId: string; attempt: number; after: number }\n /** The run ended while the client was away (the resume answered 404): reload the thread. */\n | { status: 'gone'; runId: string }\n /** Every attempt failed; the stream ended with an error chunk. */\n | { status: 'failed'; runId: string };\n\nexport interface AgentChatTransportOptions {\n /**\n * What the transport talks to. Default: an {@link AgentClient} built from `baseUrl`, `headers`,\n * `getHeaders`, `credentials` and `fetch` below — which are ignored when a backend is given.\n */\n backend?: AgentBackend;\n /** Retry a dropped stream from its last frame. Default on; `false` turns it off. */\n reconnect?: ReconnectOptions | false;\n /** Fires as a stream drops, reconnects, or gives up. */\n onConnectionChange?: (state: StreamConnectionState) => void;\n /** The server's origin, e.g. `https://api.example.com`. Defaults to `''` (same origin). */\n baseUrl?: string;\n /** The agent's route prefix (`AgentModule`'s `path`, global prefix included). Default `'agent'`. */\n path?: string;\n /** Static headers merged into every request (e.g. a tenant ref). */\n headers?: Record<string, string>;\n /**\n * Resolved at request time — use for short-lived bearer tokens that\n * must not be captured once at construction. Merged over `headers`.\n */\n getHeaders?: () => Record<string, string> | Promise<Record<string, string>>;\n /** Forwarded to `fetch` so cookie-based auth/impersonation works. */\n credentials?: RequestCredentials;\n /** Named agent to run the turn (backend `agent` field). */\n agent?: string;\n /** One of the agent's personas to answer as (backend `persona` field). */\n persona?: string;\n /**\n * Extra body fields evaluated per send — the hook injects `threadId`\n * and `pageContext` through this. Returned object is spread into the\n * request body after the SDK's own `body`.\n */\n getBody?: () => Record<string, unknown>;\n /**\n * The run id to resume on mount, if any. Returning `undefined` makes\n * `reconnectToStream` resolve to `null` WITHOUT hitting the network —\n * this is the generalized fix for \"useChat fires a doomed GET on mount\n * and surfaces its 404\". Wire this to the thread's `activeRunId`.\n */\n getResumeRunId?: () => string | undefined;\n /**\n * Fires once `reconnectToStream` has attached to a run's stream, with that run's id. A resumed\n * stream replays frames but opens with no `meta` frame, so this is the only place a caller learns\n * which run it is now reading — what a Stop pressed after a reload has to cancel.\n */\n onResumeAttached?: (runId: string) => void;\n /** Fires whenever a stream emits its `meta` frame. */\n onMeta?: (meta: AgentStreamMeta) => void;\n /**\n * Fires synchronously at the very start of `sendMessages`/`reconnectToStream`, before any network\n * call — i.e. strictly before that attempt's own `onMeta` (if any) can fire. Lets a caller reset\n * \"which run is THIS attempt settling\" state without racing React's render/effect timing: a\n * consumer that also read `onMeta` to learn the current run id would otherwise risk misattributing\n * an early failure (no meta ever arrives) to a PRIOR attempt's id.\n */\n onAttemptStart?: () => void;\n /**\n * A resume found nothing streaming under the run id (the backend answered 404): the run already\n * ended. The SDK is told there is nothing to resume, so the caller is the one that has to reload\n * what the run wrote — `useAgentChat` re-reads the thread.\n */\n onResumeGone?: (runId: string) => void;\n /**\n * The run's stream ended with the backend's `event: error` frame — called with its `code` and\n * `message` right before the stream is closed with an error chunk. The chunk can only carry the\n * text; this is where the `code` reaches a caller, so it can word the failure itself.\n */\n onRunError?: (failure: AgentRunFailure) => void;\n /** Injectable for tests / non-browser runtimes. Defaults to global fetch. */\n fetch?: typeof fetch;\n}\n\nconst DEFAULT_RECONNECT: Required<ReconnectOptions> = {\n maxAttempts: 6,\n baseDelayMs: 500,\n maxDelayMs: 8000,\n};\n\n/**\n * The tool name BOTH elicitation surfaces persist their question set under (core's\n * `ASK_TOOL_NAME`), so a synthesized part and a replayed `tool-ask` row are the same part type.\n * Spelled out rather than imported: every other core import in this package is type-only, and a\n * value import would pull the agent loop into a browser bundle for a three-letter string.\n */\nconst ASK_TOOL_NAME = 'ask';\n\n/**\n * AI SDK v7 `ChatTransport` for the nestjs-agent backend. POSTs\n * `/agent/chat`, parses the backend's `meta` + `{delta}` + `done` SSE\n * frames, and re-emits them as the v7 UI-message chunk stream\n * (`start` → `text-start` → `text-delta`* → `text-end` → `finish`).\n *\n * The backend hydrates prior history from its store, so only the latest\n * user message text is sent each turn — keeping payloads tiny and\n * preventing the client from corrupting replayed history.\n *\n * Attachments (image/PDF for a vision-capable model) ride the per-send body:\n * `sendMessage({ text }, { body: { attachments: MessageAttachment[] } })`. They\n * flow to the backend as the turn's `attachments`, get persisted on the user\n * message, and are rendered as native model content parts. Optimistic display of\n * the user's own attachment thumbnails is the consumer's concern (it stages the\n * upload), the same way history rendering reads `StoredMessage.attachments`.\n *\n * Frames beyond text/reasoning/tools become AI SDK data parts (seen by `useChat`'s `onData`):\n * - `ui` → `data-ui` part, `id` = the component id (a repeat id updates it in place)\n * - `approval-requested` → `data-approval-requested` part keyed by the call id, plus the SDK's\n * native `tool-approval-request` (the part moves to `approval-requested`)\n * - `approval-settled` → `data-approval-settled` part keyed by the call id (who decided, through\n * what, remembered or not); the outcome still rides the call's own output\n * - `title`, `cancelled`, `queue` → transient `data-title` / `data-cancelled` / `data-queue` (never\n * stored on the message). A send the server queued (`202`) is reported\n * as a transient `data-queue` too, carrying `queuedSend`\n * - any other kind → `data-<kind>` part carrying the frame minus `kind`, keyed by its `id`\n * when it has one — forwarded, never dropped\n * `parentId` on a tool frame rides the part's `toolMetadata` next to `toolKind`.\n */\nexport class AgentChatTransport implements ChatTransport<UIMessage> {\n private currentRunId: string | undefined;\n private currentThreadId: string | undefined;\n\n /**\n * One attempt at a time. The AI SDK keeps a single in-flight response per chat and decides\n * whether its streamed message REPLACES the list's last entry or is appended by comparing that\n * response's message id against the last entry alone. Two attempts writing into one chat\n * therefore append alternating copies of each other's message, and the list ends up holding\n * several entries under each id — which React renders as duplicate keys.\n */\n private attemptLive = false;\n\n private readonly backend: AgentBackend;\n\n constructor(private readonly options: AgentChatTransportOptions = {}) {\n this.backend =\n options.backend ??\n new AgentClient({\n ...(options.baseUrl !== undefined ? { baseUrl: options.baseUrl } : {}),\n ...(options.path !== undefined ? { path: options.path } : {}),\n ...(options.headers !== undefined ? { headers: options.headers } : {}),\n ...(options.getHeaders !== undefined ? { getHeaders: options.getHeaders } : {}),\n ...(options.credentials !== undefined ? { credentials: options.credentials } : {}),\n ...(options.fetch !== undefined ? { fetch: options.fetch } : {}),\n });\n }\n\n /** Run id of the most recent stream — HITL approve/reject target this. */\n get runId(): string | undefined {\n return this.currentRunId;\n }\n\n /** Thread id of the most recent stream. */\n get threadId(): string | undefined {\n return this.currentThreadId;\n }\n\n /**\n * True from the moment a send or resume attempt starts until its chunk stream terminates. A\n * caller that can refuse a turn BEFORE the SDK commits to one — `useAgentChat` wrapping\n * `sendMessage` — reads this; the transport itself can only refuse a resume, which is the one\n * attempt the SDK lets a transport decline.\n */\n get isAttemptLive(): boolean {\n return this.attemptLive;\n }\n\n async sendMessages(\n options: Parameters<ChatTransport<UIMessage>['sendMessages']>[0],\n ): Promise<ReadableStream<UIMessageChunk>> {\n this.options.onAttemptStart?.();\n this.attemptLive = true;\n try {\n const lastMessage = options.messages.at(-1);\n const message = lastMessage ? extractText(lastMessage) : '';\n const body: Record<string, unknown> = {\n ...(this.options.agent !== undefined ? { agent: this.options.agent } : {}),\n ...(this.options.persona !== undefined ? { persona: this.options.persona } : {}),\n ...(this.options.getBody?.() ?? {}),\n ...((options.body as Record<string, unknown> | undefined) ?? {}),\n message,\n };\n const headers = headerRecord(options.headers);\n const response = await this.backend.openChatStream({\n body,\n ...(headers !== undefined ? { headers } : {}),\n ...(options.abortSignal ? { signal: options.abortSignal } : {}),\n });\n if (response.queued !== undefined) {\n // The thread already had a turn running (another tab, another device): the server queued\n // the message instead. Nothing streams; the chat learns it through a transient part.\n this.attemptLive = false;\n return queuedChunkStream(response.queued);\n }\n this.captureHeaderMeta(response);\n if (response.proposalDecision !== undefined) {\n this.attemptLive = false;\n return proposalDecisionChunkStream(response.proposalDecision);\n }\n return this.toChunkStream(response, {\n ...(headers !== undefined ? { headers } : {}),\n ...(options.abortSignal ? { signal: options.abortSignal } : {}),\n });\n } catch (error) {\n this.attemptLive = false;\n throw error;\n }\n }\n\n async reconnectToStream(\n options: Parameters<ChatTransport<UIMessage>['reconnectToStream']>[0],\n ): Promise<ReadableStream<UIMessageChunk> | null> {\n // Already attached: a second reconnect replays the SAME buffered frames into the SAME chat, so\n // it adds a duplicate of the message the first attempt is writing rather than a second turn.\n // React StrictMode runs the SDK's resume effect twice on mount, which makes this the ordinary\n // case and not an edge one. `null` is the SDK's own \"nothing to resume\" answer and, unlike a\n // throw, leaves it holding no state for an attempt that never happened.\n if (this.attemptLive) return null;\n this.options.onAttemptStart?.();\n const runId = this.options.getResumeRunId?.();\n // No buffered run → resolve null without a network round-trip so we\n // never surface a 404 from a doomed resume GET.\n if (runId === undefined) return null;\n this.attemptLive = true;\n try {\n const headers = headerRecord(options.headers);\n const response = await this.backend.resumeChatStream({\n runId,\n ...(headers !== undefined ? { headers } : {}),\n });\n if (response === null) {\n this.attemptLive = false;\n this.options.onResumeGone?.(runId);\n return null;\n }\n this.captureHeaderMeta(response);\n this.options.onResumeAttached?.(response.runId ?? runId);\n return this.toChunkStream(response, {\n runId,\n ...(headers !== undefined ? { headers } : {}),\n });\n } catch (error) {\n this.attemptLive = false;\n throw error;\n }\n }\n\n private captureHeaderMeta(response: ChatStreamResponse): void {\n if (response.runId) this.currentRunId = response.runId;\n if (response.threadId) this.currentThreadId = response.threadId;\n }\n\n private reconnectPolicy(): Required<ReconnectOptions> | null {\n const configured = this.options.reconnect;\n if (configured === false) return null;\n return { ...DEFAULT_RECONNECT, ...configured };\n }\n\n private recordMeta(meta: AgentStreamMeta): void {\n this.currentRunId = meta.runId;\n this.currentThreadId = meta.threadId;\n this.options.onMeta?.(meta);\n }\n\n /**\n * Parse the backend's SSE byte stream and re-emit it as a valid v7 UI-message chunk stream.\n * Recognized frames:\n * - `event: meta` `data: {\"runId\",\"threadId\"}` → records identity\n * - `data: <AgentStreamEvent JSON>` → mapped to UI chunks (text / reasoning / tool /\n * `data-*`; see {@link AgentChatTransport} docs)\n * - `event: done` `data: {}` → terminates\n * - `event: error` `data: {code,message}` → error chunk\n *\n * A run is ONE UI message with N steps. Each `step-start`/`step-finish` pair brackets a model\n * call plus its tool execution; text and reasoning open lazily and close at the step boundary, so\n * tool-call cards (input streaming → output) render live between the prose.\n */\n private toChunkStream(\n source: ChatStreamResponse,\n context: { runId?: string; headers?: Record<string, string>; signal?: AbortSignal },\n ): ReadableStream<UIMessageChunk> {\n let reader = source.body.getReader();\n let decoder = new TextDecoder();\n let buffer = '';\n // Resuming a dropped stream: the run it belongs to, and the sequence number (SSE `id:`) of the\n // last frame this stream has taken in. Only a server that numbers its frames can be resumed.\n let streamRunId = source.runId ?? context.runId;\n let lastSeq: number | undefined;\n let cancelled = false;\n const backend = this.backend;\n const policy = this.reconnectPolicy();\n const notify = (state: StreamConnectionState) => this.options.onConnectionChange?.(state);\n const reportRunError = (failure: { code: string | undefined; message: string }) => {\n try {\n this.options.onRunError?.({\n ...failure,\n ...(streamRunId !== undefined ? { runId: streamRunId } : {}),\n });\n } catch {\n /* a listener that throws must not replace the stream's own terminal */\n }\n };\n const aborted = () => cancelled || context.signal?.aborted === true;\n const canResume = () =>\n policy !== null && lastSeq !== undefined && streamRunId !== undefined && !aborted();\n /**\n * Re-attach after a drop: `GET …/stream?after=<lastSeq>`, backing off between attempts. The\n * chunk state (open step, text run, announced calls) is kept, so the resumed frames continue\n * the message instead of starting another.\n */\n const resume = async (): Promise<'resumed' | 'gone' | 'failed' | 'aborted'> => {\n const runId = streamRunId as string;\n const after = lastSeq ?? 0;\n const { maxAttempts, baseDelayMs, maxDelayMs } = policy as Required<ReconnectOptions>;\n for (let attempt = 1; attempt <= maxAttempts; attempt += 1) {\n notify({ status: 'reconnecting', runId, attempt, after });\n await delay(Math.min(maxDelayMs, baseDelayMs * 2 ** (attempt - 1)), context.signal);\n if (aborted()) return 'aborted';\n try {\n const next = await backend.resumeChatStream({\n runId,\n after,\n ...(context.headers !== undefined ? { headers: context.headers } : {}),\n ...(context.signal !== undefined ? { signal: context.signal } : {}),\n });\n if (next === null) {\n notify({ status: 'gone', runId });\n return 'gone';\n }\n reader = next.body.getReader();\n decoder = new TextDecoder();\n buffer = '';\n notify({ status: 'live' });\n return 'resumed';\n } catch {\n if (aborted()) return 'aborted';\n }\n }\n notify({ status: 'failed', runId });\n return 'failed';\n };\n let started = false;\n let stepOpen = false;\n let stepIndex = 0;\n let textId: string | null = null;\n let reasoningId: string | null = null;\n // When the open reasoning run started, for the duration stamped on its end when the backend\n // does not report one (see `closeRuns`).\n let reasoningStartedAt = 0;\n // Text/reasoning runs opened within the current step. A pushed UI component closes the open run\n // so prose after it lands AFTER it; the next run then needs an id of its own.\n let textSeq = 0;\n let reasoningSeq = 0;\n // Tool calls this STREAM has already announced. The AI SDK settles a tool part by looking it\n // up by call id and throws — dropping the whole message — when there is none, so an outcome\n // must never be the first a client hears of a call. Per stream, not per transport: a resumed\n // run replays its buffered frames from the beginning.\n const announced = new Set<string>();\n // What each call's tool part carries as `toolMetadata`. The SDK REPLACES a part's metadata with\n // whatever the latest chunk carries, so a `parentId` learnt from `tool-input-start` would be\n // wiped by the `tool-input-available` that follows unless every chunk restates the merge.\n const toolMetadata = new Map<string, ToolMetadata>();\n const record = (meta: AgentStreamMeta) => {\n streamRunId = meta.runId;\n this.recordMeta(meta);\n };\n // Every way out of the read loop below passes through here: the attempt is over the moment its\n // chunk stream terminates, and a latch left set would refuse every later turn.\n const endAttempt = () => {\n this.attemptLive = false;\n };\n\n return new ReadableStream<UIMessageChunk>({\n async pull(controller) {\n function ensureStarted() {\n if (started) return;\n started = true;\n // The run rides the message's metadata, so a later call about THIS message (feedback,\n // a resync) can find the rows the server persisted for it.\n // `createdAt` so a live message has a timestamp the way a replayed one does.\n controller.enqueue({\n type: 'start',\n messageMetadata: {\n ...(streamRunId !== undefined ? { runId: streamRunId } : {}),\n createdAt: new Date().toISOString(),\n },\n });\n }\n function openStep() {\n ensureStarted();\n if (stepOpen) closeStep();\n stepOpen = true;\n stepIndex += 1;\n textId = null;\n reasoningId = null;\n textSeq = 0;\n reasoningSeq = 0;\n controller.enqueue({ type: 'start-step' });\n }\n function ensureStep() {\n if (!stepOpen) openStep();\n }\n /**\n * `reasoningMs` is the backend's own measurement (`step-finish.reasoningMs`) — the number the\n * store persists, so a reloaded thread reads the same duration. Without one, the time this\n * client watched the run stream, which is what the reader saw but reads ~0 on a replay.\n */\n function closeRuns(reasoningMs?: number) {\n if (textId !== null) {\n controller.enqueue({ type: 'text-end', id: textId });\n textId = null;\n }\n if (reasoningId !== null) {\n controller.enqueue({\n type: 'reasoning-end',\n id: reasoningId,\n providerMetadata: reasoningDurationMetadata(\n reasoningMs ?? Math.max(0, Date.now() - reasoningStartedAt),\n ),\n });\n reasoningId = null;\n }\n }\n function closeStep(reasoningMs?: number) {\n if (!stepOpen) return;\n closeRuns(reasoningMs);\n controller.enqueue({ type: 'finish-step' });\n stepOpen = false;\n }\n /** Merge what this frame says about a call into what earlier frames said, and return it. */\n function metadataFor(\n id: string,\n toolKind: string | undefined,\n parentId: string | undefined,\n ): ToolMetadata | undefined {\n const merged: ToolMetadata = { ...toolMetadata.get(id) };\n if (toolKind !== undefined) merged.toolKind = toolKind;\n // A call's parent is fixed by the first frame that names one.\n if (parentId !== undefined && merged.parentId === undefined) merged.parentId = parentId;\n if (Object.keys(merged).length === 0) return undefined;\n toolMetadata.set(id, merged);\n return merged;\n }\n /** Forward a frame this transport has no dedicated mapping for as an AI SDK data part. */\n function forwardAsData(event: { kind: string }, transient: boolean) {\n ensureStarted();\n const { kind, ...data } = event as { kind: string } & Record<string, unknown>;\n controller.enqueue({\n type: `data-${kind}`,\n ...(typeof data.id === 'string' ? { id: data.id } : {}),\n data,\n ...(transient ? { transient: true } : {}),\n });\n }\n function emit(event: AgentStreamEvent) {\n switch (event.kind) {\n case 'step-start':\n openStep();\n break;\n case 'step-finish':\n closeStep(event.reasoningMs);\n // `costUsd` rides the step boundary once the backend reports it (older backends omit\n // it entirely — `undefined`, never a crash). `null` means \"priced provider/estimate\n // unavailable\", distinct from a real $0 turn — surfaced verbatim as message metadata\n // (merged onto `message.metadata` by the AI SDK) so a UI can render running cost\n // without polling `GET /quota`.\n if (event.costUsd !== undefined) {\n controller.enqueue({\n type: 'message-metadata',\n messageMetadata: { costUsd: event.costUsd },\n });\n }\n break;\n case 'text':\n ensureStep();\n if (textId === null) {\n textId = textSeq === 0 ? `txt-${stepIndex}` : `txt-${stepIndex}.${textSeq}`;\n textSeq += 1;\n controller.enqueue({ type: 'text-start', id: textId });\n }\n controller.enqueue({ type: 'text-delta', id: textId, delta: event.text });\n break;\n case 'reasoning':\n ensureStep();\n if (reasoningId === null) {\n reasoningId =\n reasoningSeq === 0 ? `rsn-${stepIndex}` : `rsn-${stepIndex}.${reasoningSeq}`;\n reasoningSeq += 1;\n reasoningStartedAt = Date.now();\n controller.enqueue({ type: 'reasoning-start', id: reasoningId });\n }\n controller.enqueue({ type: 'reasoning-delta', id: reasoningId, delta: event.text });\n break;\n case 'tool-input-start': {\n ensureStep();\n announced.add(event.id);\n // `toolKind` is absent on older backends — omitted (not `undefined`-valued) so\n // `toolMetadata` itself is only present when there's something to say, letting a\n // UI gate approval affordances on `kind === 'action'` without hardcoding tool names.\n // `parentId` nests the call under another one (see `TranscriptToolCall.children`).\n const metadata = metadataFor(event.id, event.toolKind, event.parentId);\n controller.enqueue({\n type: 'tool-input-start',\n toolCallId: event.id,\n toolName: event.name,\n ...(metadata !== undefined ? { toolMetadata: metadata } : {}),\n });\n break;\n }\n case 'tool-input-delta':\n ensureStep();\n controller.enqueue({\n type: 'tool-input-delta',\n toolCallId: event.id,\n inputTextDelta: event.delta,\n });\n break;\n case 'tool-input-available': {\n ensureStep();\n announced.add(event.id);\n const metadata = metadataFor(event.id, event.toolKind, event.parentId);\n controller.enqueue({\n type: 'tool-input-available',\n toolCallId: event.id,\n toolName: event.name,\n input: event.input,\n ...(metadata !== undefined ? { toolMetadata: metadata } : {}),\n });\n break;\n }\n case 'elicitation':\n ensureStep();\n // An authored intake asks before the turn's first model call, so nothing announced\n // the call this question set is parked under — open it here, carrying the request as\n // the part's input, which is exactly what the store persists as the call's input and\n // therefore what a reloaded thread replays. The model's own `ask` announced its call\n // itself, and re-stating it would fire a consumer's `onToolCall` twice.\n if (!announced.has(event.id)) {\n announced.add(event.id);\n controller.enqueue({\n type: 'tool-input-available',\n toolCallId: event.id,\n toolName: ASK_TOOL_NAME,\n input: {\n ...(event.request.preamble !== undefined\n ? { preamble: event.request.preamble }\n : {}),\n questions: event.request.questions,\n },\n });\n }\n break;\n case 'tool-output':\n ensureStep();\n controller.enqueue({\n type: 'tool-output-available',\n toolCallId: event.id,\n output: event.output,\n });\n break;\n case 'tool-output-error':\n ensureStep();\n controller.enqueue({\n type: 'tool-output-error',\n toolCallId: event.id,\n errorText: event.error,\n });\n break;\n case 'tool-output-denied':\n ensureStep();\n // The SDK's own state for \"a person said no\": it keeps the part's input and metadata\n // and only moves its state, so a card can say the decision was carried out instead of\n // drawing the red treatment an error gets. The reason (when one was given) rides the\n // persisted call, not this chunk — the SDK's shape carries no room for it.\n controller.enqueue({ type: 'tool-output-denied', toolCallId: event.id });\n break;\n case 'approval-requested':\n ensureStep();\n // Who decides and until when rides a `data-approval-requested` part keyed by the call\n // id — the SDK's approval chunk has no room for it, and restating the call's input\n // chunk to widen its metadata would fire a consumer's `onToolCall` a second time.\n forwardAsData(event, false);\n // The SDK settles an approval against a part it already holds and throws — dropping\n // the whole message — when there is none, so only a call this stream announced moves\n // into the native state. The approval id IS the call id: the lib settles approvals\n // by tool-call id, so a second identifier would only have to be mapped back.\n if (announced.has(event.id)) {\n controller.enqueue({\n type: 'tool-approval-request',\n approvalId: event.id,\n toolCallId: event.id,\n });\n }\n break;\n case 'approval-settled':\n ensureStep();\n // Metadata about a call, like the request: the transcript folds it into that call's\n // `approval`. The call's own state moves on its output frame, not on this one.\n forwardAsData(event, false);\n break;\n case 'ui':\n ensureStep();\n // Positioned content: close the open prose so text written after the component\n // renders after it instead of growing the paragraph above it.\n closeRuns();\n controller.enqueue({\n type: 'data-ui',\n id: event.id,\n data: {\n id: event.id,\n component: event.component,\n props: event.props,\n ...(event.version !== undefined ? { version: event.version } : {}),\n ...(event.toolCallId !== undefined ? { toolCallId: event.toolCallId } : {}),\n // A preview of a layout the model is still writing: the final push (same id)\n // replaces this part in place.\n ...(event.partial === true ? { partial: true } : {}),\n },\n });\n break;\n case 'message-metadata':\n ensureStarted();\n controller.enqueue({ type: 'message-metadata', messageMetadata: event.metadata });\n break;\n case 'title':\n case 'cancelled':\n // The thread's queue changed, or this run handed the thread to the next queued message\n // (`started`). Thread-level, like the title.\n case 'queue':\n // Thread- and run-level facts, not message content: seen by `onData`, never stored\n // as a part of the message.\n forwardAsData(event, true);\n break;\n default:\n // A kind this version does not know (a newer server, a runner that is not this\n // library's loop). Forwarded rather than dropped, so a host can render it from\n // `message.parts` / `onData` without waiting for a release that maps it.\n // `proposal-decision` (an AG-UI consumer's re-framing of a text decision) is the same\n // transient `data-proposal-decision` part a native decision answers with.\n forwardAsData(\n event as { kind: string },\n (event as { kind: string }).kind === 'proposal-decision',\n );\n break;\n }\n }\n function finish() {\n ensureStarted();\n closeStep();\n controller.enqueue({ type: 'finish' });\n controller.close();\n endAttempt();\n }\n function fail(errorText: string, start = true) {\n if (start) ensureStarted();\n controller.enqueue({ type: 'error', errorText });\n controller.close();\n endAttempt();\n }\n /** The stream dropped (or ended without `done`): resume it, or report how it ended. */\n async function recover(error: unknown): Promise<boolean> {\n if (!canResume()) {\n if (error === undefined) {\n finish();\n } else {\n fail(error instanceof Error ? error.message : 'Agent stream error', false);\n }\n return false;\n }\n const outcome = await resume();\n if (outcome === 'resumed') return true;\n if (outcome === 'failed') {\n fail('Lost the connection to the agent stream');\n } else {\n // Gone: the run ended while we were away — what we have is all this stream will get,\n // and the persisted thread holds the rest. Aborted: the user stopped the turn.\n finish();\n }\n return false;\n }\n try {\n while (true) {\n let result: ReadableStreamReadResult<Uint8Array>;\n try {\n result = await reader.read();\n } catch (error) {\n if (await recover(error)) continue;\n return;\n }\n if (result.done) {\n if (await recover(undefined)) continue;\n return;\n }\n buffer += decoder.decode(result.value, { stream: true });\n let separator = buffer.indexOf('\\n\\n');\n while (separator !== -1) {\n const rawEvent = buffer.slice(0, separator);\n buffer = buffer.slice(separator + 2);\n separator = buffer.indexOf('\\n\\n');\n const frame = parseSseFrame(rawEvent);\n if (frame.id !== undefined) {\n // Already taken in before a reconnect — a server that ignored `after` resends it.\n if (lastSeq !== undefined && frame.id <= lastSeq) continue;\n lastSeq = frame.id;\n }\n if (frame.event === 'done') {\n finish();\n return;\n }\n if (frame.event === 'error') {\n const failure = parseErrorFrame(frame.data);\n reportRunError(failure);\n fail(failure.message);\n return;\n }\n if (frame.event === 'meta') {\n const meta = parseMeta(frame.data);\n if (meta) record(meta);\n } else if (frame.data) {\n const event = parseEvent(frame.data);\n if (event) emit(event);\n }\n }\n }\n } catch (error) {\n fail(error instanceof Error ? error.message : 'Agent stream error', false);\n }\n },\n cancel() {\n cancelled = true;\n // A stop aborts the request first, which errors the body: cancelling an errored stream\n // rejects with that same AbortError, and nobody is left to hear it.\n reader.cancel().catch(() => undefined);\n endAttempt();\n },\n });\n }\n}\n\n/** The chunk stream for a send the server queued: one transient `data-queue` part, then the end. */\nfunction queuedChunkStream(queued: QueuedSendResult): ReadableStream<UIMessageChunk> {\n return new ReadableStream<UIMessageChunk>({\n start(controller) {\n controller.enqueue({\n type: 'data-queue',\n data: { queue: queued.queue, queuedSend: queued },\n transient: true,\n });\n controller.close();\n },\n });\n}\n\ninterface SseFrame {\n event: string | undefined;\n data: string | undefined;\n /** The frame's sequence number (SSE `id:`), when the server numbers its frames. */\n id: number | undefined;\n}\n\n/** Split one `event:`/`data:` SSE block into its fields. */\nfunction parseSseFrame(raw: string): SseFrame {\n let event: string | undefined;\n let id: number | undefined;\n const dataLines: string[] = [];\n for (const line of raw.split('\\n')) {\n if (line.startsWith('event:')) {\n event = line.slice('event:'.length).trim();\n } else if (line.startsWith('id:')) {\n const parsed = Number(line.slice('id:'.length).trim());\n if (Number.isSafeInteger(parsed) && parsed > 0) id = parsed;\n } else if (line.startsWith('data:')) {\n dataLines.push(line.slice('data:'.length).trimStart());\n }\n }\n return {\n event,\n data: dataLines.length > 0 ? dataLines.join('\\n') : undefined,\n id,\n };\n}\n\nfunction parseMeta(data: string | undefined): AgentStreamMeta | null {\n if (!data) return null;\n try {\n const parsed: unknown = JSON.parse(data);\n if (\n parsed !== null &&\n typeof parsed === 'object' &&\n 'runId' in parsed &&\n 'threadId' in parsed &&\n typeof parsed.runId === 'string' &&\n typeof parsed.threadId === 'string'\n ) {\n return { runId: parsed.runId, threadId: parsed.threadId };\n }\n } catch {\n /* malformed meta frame — ignore */\n }\n return null;\n}\n\n/** Read the backend's `event: error` frame (`{code,message}`); a malformed one is a bare failure. */\nfunction parseErrorFrame(data: string | undefined): { code: string | undefined; message: string } {\n const fallback = { code: undefined, message: 'Agent run failed' };\n if (!data) return fallback;\n try {\n const parsed: unknown = JSON.parse(data);\n if (parsed !== null && typeof parsed === 'object') {\n const record = parsed as { code?: unknown; message?: unknown };\n return {\n code: typeof record.code === 'string' && record.code !== '' ? record.code : undefined,\n message:\n typeof record.message === 'string' && record.message !== ''\n ? record.message\n : fallback.message,\n };\n }\n } catch {\n /* malformed error frame — fall through to the default */\n }\n return fallback;\n}\n\n/** Parse a `data:` frame as an `AgentStreamEvent`. Returns null for anything without a `kind`. */\nfunction parseEvent(data: string): AgentStreamEvent | null {\n try {\n const parsed: unknown = JSON.parse(data);\n if (parsed !== null && typeof parsed === 'object' && 'kind' in parsed) {\n return parsed as AgentStreamEvent;\n }\n } catch {\n /* not an event frame — ignore */\n }\n return null;\n}\n\n/** Collect all text parts of a UI message into a single string. */\nfunction extractText(message: UIMessage): string {\n let text = '';\n for (const part of message.parts ?? []) {\n if (part.type === 'text') text += part.text;\n }\n return text;\n}\n\n/** Per-request headers as the AI SDK hands them over, as a plain record (or nothing). */\nfunction headerRecord(\n headers: Record<string, string> | Headers | undefined,\n): Record<string, string> | undefined {\n if (headers === undefined) return undefined;\n return headers instanceof Headers ? Object.fromEntries(headers.entries()) : headers;\n}\n\n/** Wait `ms`, resolving early when `signal` aborts. */\nfunction delay(ms: number, signal: AbortSignal | undefined): Promise<void> {\n if (ms <= 0 || signal?.aborted) return Promise.resolve();\n return new Promise((resolve) => {\n const timer = setTimeout(done, ms);\n function done() {\n clearTimeout(timer);\n signal?.removeEventListener('abort', done);\n resolve();\n }\n signal?.addEventListener('abort', done, { once: true });\n });\n}\n\nfunction proposalDecisionChunkStream(\n decision: NonNullable<ChatStreamResponse['proposalDecision']>,\n): ReadableStream<UIMessageChunk> {\n return new ReadableStream({\n start(controller) {\n controller.enqueue({ type: 'start', messageId: `decision:${crypto.randomUUID()}` });\n controller.enqueue({ type: 'data-proposal-decision', data: decision, transient: true });\n if (decision.text !== undefined && decision.text.length > 0) {\n controller.enqueue({ type: 'text-start', id: 'decision' });\n controller.enqueue({ type: 'text-delta', id: 'decision', delta: decision.text });\n controller.enqueue({ type: 'text-end', id: 'decision' });\n }\n controller.enqueue({ type: 'finish', finishReason: 'stop' });\n controller.close();\n },\n });\n}\n","import type { MessageAttachment } from '@dudousxd/nestjs-agent-core';\nimport type { FileUIPart, UIMessage } from 'ai';\n\n/** How a renderer is likely to show a file. */\nexport type MessageFileKind = 'image' | 'pdf' | 'text' | 'audio' | 'video' | 'other';\n\n/** One file on a message, live or replayed, with what a renderer needs to decide how to show it. */\nexport interface MessageFile {\n url: string;\n mediaType: string;\n /** The original name, or `null` when the part carried none. */\n filename: string | null;\n kind: MessageFileKind;\n /** Lower-case extension from the name (`'pdf'`), or `null`. */\n extension: string | null;\n /** The stored media id — present on files replayed from history (`StoredMessage.attachments`). */\n mediaId: string | null;\n}\n\n/** The {@link MessageFileKind} of a MIME type. */\nexport function fileKind(mediaType: string): MessageFileKind {\n const type = mediaType.toLowerCase();\n if (type.startsWith('image/')) return 'image';\n if (type === 'application/pdf') return 'pdf';\n if (type.startsWith('text/') || type === 'application/json') return 'text';\n if (type.startsWith('audio/')) return 'audio';\n if (type.startsWith('video/')) return 'video';\n return 'other';\n}\n\nfunction messageFile(url: string, mediaType: string, name: string | null, mediaId: string | null) {\n const dot = name?.lastIndexOf('.') ?? -1;\n const file: MessageFile = {\n url,\n mediaType,\n filename: name,\n kind: fileKind(mediaType),\n extension: name !== null && dot > 0 ? name.slice(dot + 1).toLowerCase() : null,\n mediaId,\n };\n return file;\n}\n\n/**\n * An uploaded attachment as the {@link MessageFile} it is once its message is sent — so a message\n * still waiting (in the queue, in the composer) draws its files with the same code a sent one does.\n */\nexport function attachmentFile(attachment: MessageAttachment): MessageFile {\n return messageFile(attachment.url, attachment.contentType, attachment.name, attachment.mediaId);\n}\n\n/**\n * The files on a message — the user's attachments (live, or replayed from `StoredMessage.attachments`\n * by `storedMessageToUiMessage`) and any the model produced — in part order. Data only: pair it with\n * your own thumbnails/links.\n */\nexport function messageFiles(message: Pick<UIMessage, 'parts'>): MessageFile[] {\n const files: MessageFile[] = [];\n for (const part of message.parts) {\n if (part.type !== 'file') continue;\n const file = part as FileUIPart;\n const mediaId = (file.providerMetadata?.agent as { mediaId?: unknown } | undefined)?.mediaId;\n files.push(\n messageFile(\n file.url,\n file.mediaType,\n file.filename ?? null,\n typeof mediaId === 'string' ? mediaId : null,\n ),\n );\n }\n return files;\n}\n\n/**\n * Whether `file` matches an `accept` list in the `<input accept>` grammar: MIME types\n * (`application/pdf`), wildcards (`image/*`) and extensions (`.csv`). An empty list accepts all.\n */\nexport function acceptsFile(\n accept: string | readonly string[] | undefined,\n file: Pick<File, 'name' | 'type'>,\n): boolean {\n const rules = (typeof accept === 'string' ? accept.split(',') : (accept ?? []))\n .map((rule) => rule.trim().toLowerCase())\n .filter((rule) => rule.length > 0);\n if (rules.length === 0) return true;\n const type = file.type.toLowerCase();\n const name = file.name.toLowerCase();\n return rules.some((rule) => {\n if (rule.startsWith('.')) return name.endsWith(rule);\n if (rule.endsWith('/*')) return type.startsWith(rule.slice(0, -1));\n return type === rule;\n });\n}\n\n/** Files carried by a paste — screenshots and copied files. Text-only pastes give `[]`. */\nexport function filesFromClipboard(data: DataTransfer | null | undefined): File[] {\n if (!data) return [];\n const files: File[] = [];\n for (const item of Array.from(data.items ?? [])) {\n if (item.kind !== 'file') continue;\n const file = item.getAsFile();\n if (file !== null) files.push(file);\n }\n return files.length > 0 ? files : Array.from(data.files ?? []);\n}\n\n/** Whether a drag carries files (as opposed to text or a link) — gate your drop highlight on it. */\nexport function dragHasFiles(data: DataTransfer | null | undefined): boolean {\n return Array.from(data?.types ?? []).includes('Files');\n}\n","import type { MessageAttachment } from '@dudousxd/nestjs-agent-core';\nimport { useCallback, useEffect, useMemo, useRef, useState } from 'react';\nimport type { AgentBackend, UploadAttachmentOptions } from '../backend.js';\nimport { AgentBackendUnsupportedError } from '../backend.js';\nimport { useAgentConfig } from '../config/use-agent-config.js';\nimport { useAgentBackend } from '../provider.js';\nimport { acceptsFile, dragHasFiles, filesFromClipboard } from './files.js';\n\n/** Where one staged file stands. `rejected` never uploaded (validation); `error` can be retried. */\nexport type StagedAttachmentStatus = 'uploading' | 'ready' | 'error' | 'rejected';\n\nexport interface StagedAttachment {\n /** Local id, stable for the item's life — use it as the React key and for `remove`/`retry`. */\n id: string;\n file: File;\n name: string;\n size: number;\n type: string;\n status: StagedAttachmentStatus;\n /** 0..1 while uploading (0 until the backend reports progress), 1 once ready. */\n progress: number;\n /** Why it was rejected or failed. */\n error?: string;\n /** What the server returned — present once `ready`. */\n attachment?: MessageAttachment;\n /** An object URL for image previews (revoked on remove/unmount), when the runtime has one. */\n previewUrl?: string;\n}\n\n/** Why a file was turned away before any upload. */\nexport type AttachmentRejection = 'type' | 'size' | 'count';\n\nexport interface UseAttachmentsOptions {\n /**\n * Upload one file — defaults to `backend.uploadAttachment`. Resolve with what the server\n * answered; honour `signal` so `remove` can cancel; call `onProgress(0..1)` if you can.\n */\n upload?: (file: File, options: UploadAttachmentOptions) => Promise<MessageAttachment>;\n /** Used for the default `upload`. Default: the enclosing `<AgentProvider>`'s. */\n backend?: AgentBackend;\n /**\n * `<input accept>` grammar: `'image/*,.pdf'` or `['image/*', 'application/pdf']`. Default: the\n * server's allowed content types (`GET <base>/config`).\n */\n accept?: string | readonly string[];\n /** Per-file ceiling, in bytes. Default: the server's (`GET <base>/config`). */\n maxBytes?: number;\n /**\n * How many files may be staged at once (rejected ones do not count). Default: how many one\n * message may carry, per the server (`GET <base>/config`).\n */\n maxFiles?: number;\n /** Words for a rejection; default English. */\n describeRejection?: (reason: AttachmentRejection, file: File) => string;\n}\n\nexport interface AttachmentsState {\n items: StagedAttachment[];\n /** Stage files: validate, then upload each that passes. */\n add: (files: Iterable<File> | ArrayLike<File> | null | undefined) => void;\n /** Drop an item, cancelling its upload. */\n remove: (id: string) => void;\n /** Upload a failed item again. */\n retry: (id: string) => void;\n /** Drop everything — call after a send. */\n clear: () => void;\n /** An upload is still running — hold the send button. */\n isUploading: boolean;\n /** What to send: the ready uploads, in order, as the `{ mediaId }` refs `POST <base>/chat` takes. */\n refs: Array<{ mediaId: string }>;\n /** Props for a hidden `<input type=\"file\">`: `accept`, `multiple`, `onChange`. */\n inputProps: {\n type: 'file';\n accept: string | undefined;\n multiple: boolean;\n onChange: (event: { currentTarget: HTMLInputElement }) => void;\n };\n /** Handlers for any element that should take dropped files. */\n dropZoneProps: {\n onDragEnter: (event: DragLikeEvent) => void;\n onDragOver: (event: DragLikeEvent) => void;\n onDragLeave: (event: DragLikeEvent) => void;\n onDrop: (event: DragLikeEvent) => void;\n };\n /** Files are being dragged over the drop zone — for a highlight. */\n isDragging: boolean;\n /** Paste handler for the composer: stages pasted files (screenshots), leaves text alone. */\n onPaste: (event: ClipboardLikeEvent) => void;\n}\n\n/** The slice of a React/DOM drag event these handlers read. */\nexport interface DragLikeEvent {\n dataTransfer: DataTransfer | null;\n preventDefault: () => void;\n}\n\n/** The slice of a React/DOM clipboard event `onPaste` reads. */\nexport interface ClipboardLikeEvent {\n clipboardData: DataTransfer | null;\n preventDefault: () => void;\n}\n\nconst DEFAULT_REJECTION: Record<AttachmentRejection, (file: File) => string> = {\n type: (file) => `${file.name} is not a supported file type`,\n size: (file) => `${file.name} is too large`,\n count: () => 'Too many files',\n};\n\nlet sequence = 0;\n\n/**\n * Staged attachments for a composer, headless: validation (`accept`, `maxBytes`, `maxFiles`),\n * one upload per file with progress and cancel, retry, previews, and the event handlers for a file\n * input, a drop zone and paste — no markup, no styles. Send `refs` with the\n * message, then `clear()`:\n *\n * ```ts\n * await chat.sendMessage({ text }, { body: { attachments: files.refs } });\n * files.clear();\n * ```\n */\nexport function useAttachments(options: UseAttachmentsOptions = {}): AttachmentsState {\n const backend = useAgentBackend(options.backend);\n // The server's limits are the defaults, so a composer never repeats (and drifts from) them.\n const { config } = useAgentConfig({ backend });\n const limits = config?.attachments;\n const accept = options.accept ?? limits?.allowedContentTypes;\n const maxBytes = options.maxBytes ?? limits?.maxBytes;\n const maxFiles = options.maxFiles ?? limits?.maxPerMessage;\n const effective = {\n ...options,\n backend,\n ...(accept !== undefined ? { accept } : {}),\n ...(maxBytes !== undefined ? { maxBytes } : {}),\n ...(maxFiles !== undefined ? { maxFiles } : {}),\n };\n const latest = useRef(effective);\n latest.current = effective;\n const [items, setItems] = useState<StagedAttachment[]>([]);\n const itemsRef = useRef(items);\n itemsRef.current = items;\n const controllers = useRef(new Map<string, AbortController>());\n const [dragDepth, setDragDepth] = useState(0);\n\n const patch = useCallback((id: string, change: Partial<StagedAttachment>) => {\n setItems((current) => current.map((item) => (item.id === id ? { ...item, ...change } : item)));\n }, []);\n\n const start = useCallback(\n (item: StagedAttachment) => {\n const { upload, backend } = latest.current;\n const run =\n upload ??\n (backend.uploadAttachment !== undefined\n ? backend.uploadAttachment.bind(backend)\n : undefined);\n if (run === undefined) {\n patch(item.id, {\n status: 'error',\n error: new AgentBackendUnsupportedError('uploadAttachment').message,\n });\n return;\n }\n const controller = new AbortController();\n controllers.current.set(item.id, controller);\n run(item.file, {\n signal: controller.signal,\n onProgress: (fraction) => patch(item.id, { progress: Math.max(0, Math.min(1, fraction)) }),\n }).then(\n (attachment) => {\n if (controller.signal.aborted) return;\n controllers.current.delete(item.id);\n patch(item.id, { status: 'ready', progress: 1, attachment });\n },\n (error: unknown) => {\n if (controller.signal.aborted) return;\n controllers.current.delete(item.id);\n patch(item.id, {\n status: 'error',\n error: error instanceof Error ? error.message : String(error),\n });\n },\n );\n },\n [patch],\n );\n\n const add = useCallback(\n (files: Iterable<File> | ArrayLike<File> | null | undefined) => {\n if (files == null) return;\n const { accept, maxBytes, maxFiles, describeRejection } = latest.current;\n const describe = (reason: AttachmentRejection, file: File) =>\n describeRejection?.(reason, file) ?? DEFAULT_REJECTION[reason](file);\n let room =\n maxFiles === undefined\n ? Number.POSITIVE_INFINITY\n : maxFiles - itemsRef.current.filter((item) => item.status !== 'rejected').length;\n const staged: StagedAttachment[] = [];\n for (const file of Array.from(files as ArrayLike<File>)) {\n sequence += 1;\n const base = {\n id: `att-${sequence}`,\n file,\n name: file.name,\n size: file.size,\n type: file.type,\n progress: 0,\n };\n const reason: AttachmentRejection | undefined = !acceptsFile(accept, file)\n ? 'type'\n : maxBytes !== undefined && file.size > maxBytes\n ? 'size'\n : room <= 0\n ? 'count'\n : undefined;\n if (reason !== undefined) {\n staged.push({ ...base, status: 'rejected', error: describe(reason, file) });\n continue;\n }\n room -= 1;\n const previewUrl =\n file.type.startsWith('image/') && typeof URL.createObjectURL === 'function'\n ? URL.createObjectURL(file)\n : undefined;\n staged.push({ ...base, status: 'uploading', ...(previewUrl ? { previewUrl } : {}) });\n }\n if (staged.length === 0) return;\n setItems((current) => [...current, ...staged]);\n for (const item of staged) {\n if (item.status === 'uploading') start(item);\n }\n },\n [start],\n );\n\n const release = useCallback((item: StagedAttachment | undefined) => {\n if (item === undefined) return;\n controllers.current.get(item.id)?.abort();\n controllers.current.delete(item.id);\n if (item.previewUrl !== undefined && typeof URL.revokeObjectURL === 'function') {\n URL.revokeObjectURL(item.previewUrl);\n }\n }, []);\n\n const remove = useCallback(\n (id: string) => {\n release(itemsRef.current.find((item) => item.id === id));\n setItems((current) => current.filter((item) => item.id !== id));\n },\n [release],\n );\n\n const clear = useCallback(() => {\n for (const item of itemsRef.current) release(item);\n setItems([]);\n }, [release]);\n\n const retry = useCallback(\n (id: string) => {\n const item = itemsRef.current.find((candidate) => candidate.id === id);\n if (item === undefined || item.status !== 'error') return;\n const { error: _previous, ...rest } = item;\n const again: StagedAttachment = { ...rest, status: 'uploading', progress: 0 };\n setItems((current) => current.map((candidate) => (candidate.id === id ? again : candidate)));\n start(again);\n },\n [start],\n );\n\n // Unmount: cancel what is in flight and free the previews.\n useEffect(\n () => () => {\n for (const item of itemsRef.current) release(item);\n },\n [release],\n );\n\n const onPaste = useCallback(\n (event: ClipboardLikeEvent) => {\n const files = filesFromClipboard(event.clipboardData);\n if (files.length === 0) return;\n event.preventDefault();\n add(files);\n },\n [add],\n );\n\n const dropZoneProps = useMemo(\n () => ({\n onDragEnter: (event: DragLikeEvent) => {\n if (!dragHasFiles(event.dataTransfer)) return;\n event.preventDefault();\n setDragDepth((depth) => depth + 1);\n },\n onDragOver: (event: DragLikeEvent) => {\n // Without this the browser never fires `drop` — it opens the file instead.\n if (dragHasFiles(event.dataTransfer)) event.preventDefault();\n },\n onDragLeave: (event: DragLikeEvent) => {\n if (!dragHasFiles(event.dataTransfer)) return;\n setDragDepth((depth) => Math.max(0, depth - 1));\n },\n onDrop: (event: DragLikeEvent) => {\n if (!dragHasFiles(event.dataTransfer)) return;\n event.preventDefault();\n setDragDepth(0);\n add(event.dataTransfer?.files);\n },\n }),\n [add],\n );\n\n const inputProps = useMemo(\n () => ({\n type: 'file' as const,\n accept: typeof accept === 'string' ? accept : accept?.join(','),\n multiple: maxFiles === undefined || maxFiles > 1,\n onChange: (event: { currentTarget: HTMLInputElement }) => {\n const input = event.currentTarget;\n add(input.files);\n // Let the same file be picked again after a remove.\n input.value = '';\n },\n }),\n [accept, maxFiles, add],\n );\n\n return useMemo(() => {\n const ready = items.filter(\n (item): item is StagedAttachment & { attachment: MessageAttachment } =>\n item.status === 'ready' && item.attachment !== undefined,\n );\n return {\n items,\n add,\n remove,\n retry,\n clear,\n isUploading: items.some((item) => item.status === 'uploading'),\n refs: ready.map((item) => ({ mediaId: item.attachment.mediaId })),\n inputProps,\n dropZoneProps,\n isDragging: dragDepth > 0,\n onPaste,\n };\n }, [items, add, remove, retry, clear, inputProps, dropZoneProps, dragDepth, onPaste]);\n}\n","import type {\n ActionProposalMutationView,\n ActionProposalView,\n AgentCatalogEntry,\n AgentClientConfig,\n ChatQueueState,\n MessageAttachment,\n MessageFeedback,\n MessageFeedbackValue,\n ModelCatalogView,\n QuotaReport,\n SkillCatalogEntry,\n ThreadDetail,\n ThreadSummary,\n ToolCatalogEntry,\n} from '@dudousxd/nestjs-agent-core';\nimport type { HttpErrorListener } from './http-error.js';\n\n/**\n * Partial update accepted by `PATCH <base>/threads/:threadId`. `defaultAgent: null` clears a\n * previously-set default back to the module's own default; omitting it leaves the thread's\n * current default untouched.\n */\nexport interface ThreadPatch {\n title?: string;\n defaultAgent?: string | null;\n /** Pin a catalog model on the thread; `null` unpins it. */\n model?: string | null;\n /** Pin one of the agent's personas on the thread; `null` clears it (the agent's default applies). */\n persona?: string | null;\n}\n\n/** Starting a turn: the body `POST <base>/chat` takes (see docs/stream-protocol.md). */\nexport interface ChatStreamRequest {\n /** `{ message, threadId?, agent?, persona?, model?, attachments?, pageContext?, regenerate?, … }`. */\n body: Record<string, unknown>;\n /** Per-request headers the AI SDK was handed for this send. */\n headers?: Record<string, string>;\n /** Aborted when the user stops the turn. */\n signal?: AbortSignal;\n}\n\n/** Attaching to a run that is already streaming: `GET <base>/chat/:runId/stream?after=<seq>`. */\nexport interface ResumeStreamRequest {\n runId: string;\n /**\n * The sequence number (SSE `id:`) of the last frame the client already has. Omitted → replay\n * from the first frame. A backend that cannot skip may ignore it: the transport also drops frames\n * at or below it.\n */\n after?: number;\n headers?: Record<string, string>;\n signal?: AbortSignal;\n}\n\n/**\n * An open chat stream: the raw `text/event-stream` bytes in the stream-protocol framing, plus the\n * identity a backend may learn before the first frame (the `X-Agent-Run-Id` / `X-Agent-Thread-Id`\n * headers). The body's own `event: meta` frame supplies them otherwise.\n */\nexport interface ChatStreamResponse {\n proposalDecision?: {\n threadId: string;\n proposalDecision: ActionProposalMutationView | { status: 'ambiguous'; proposalIds: string[] };\n text?: string;\n };\n body: ReadableStream<Uint8Array>;\n runId?: string;\n threadId?: string;\n /**\n * The server queued the message instead of starting a turn (`202`): the thread already had one\n * running — another tab, another device. `body` is then empty; the transport reports this as a\n * transient `data-queue` part and `useAgentChat` moves the message into `chat.queue`.\n */\n queued?: QueuedSendResult;\n}\n\n/**\n * `POST <base>/chat` answered `202`: the message waits in the thread's queue (see\n * docs/stream-protocol.md, \"Message queue\").\n */\nexport interface QueuedSendResult {\n queued: true;\n threadId: string;\n /** The queued message's id — also the id of the run it will start. */\n messageId: string;\n /** 0-based place in the queue when it was queued. */\n position: number;\n queue: ChatQueueState;\n /** Set when it started straight away (the thread was idle after all): attach to this run. */\n runId?: string;\n /** The run an interrupt cancelled to make room for it. */\n interrupting?: string;\n}\n\n/** What `PATCH <base>/queue/:messageId` takes. */\nexport interface QueuedMessageUpdate {\n message?: string;\n /** `[{ mediaId }]` refs replacing the message's attachments; `null` drops them. */\n attachments?: Array<{ mediaId: string }> | null;\n /** Move it to this 0-based place in the queue. */\n position?: number;\n}\n\n/** What `POST <base>/messages/:id/feedback` takes. `value: null` clears the rating. */\nexport interface MessageFeedbackInput {\n value: MessageFeedbackValue | null;\n comment?: string;\n}\n\nexport interface UploadAttachmentOptions {\n signal?: AbortSignal;\n /** Called with 0..1 as the upload progresses, when the backend can observe it. */\n onProgress?: (fraction: number) => void;\n}\n\n/** How {@link AgentClient} reaches the server — handed to an {@link AttachmentUploadStrategy}. */\nexport interface AgentConnection {\n /** The server's origin, trailing slash removed (`''` for same-origin). */\n baseUrl: string;\n /** The agent's route prefix, normalized to a leading slash (`'/agent'`), or `''`. */\n path: string;\n /** The client's static + per-request headers, resolved now (auth, CSRF). */\n headers: () => Promise<Record<string, string>>;\n credentials?: RequestCredentials;\n fetch: typeof fetch;\n /** The client's `onHttpError` — call it with an upload's error answer before throwing it. */\n onHttpError?: HttpErrorListener;\n}\n\n/**\n * Replaces {@link AgentClient}'s own `uploadAttachment` (`POST <path>/attachments`) — e.g.\n * `mediaAttachments()` from `@dudousxd/nestjs-agent-react/media`, or your own storage. Gets the\n * client's connection so it needs no configuration of its own. Resolve with the attachment your\n * server's `AGENT_ATTACHMENT_STAGING` recognises by `mediaId`.\n */\nexport type AttachmentUploadStrategy = (\n file: File,\n options: UploadAttachmentOptions,\n connection: AgentConnection,\n) => Promise<MessageAttachment>;\n\n/**\n * Everything the React layer asks of a server — the seam between `useAgentChat` (and the other\n * hooks) and whatever serves the agent. {@link AgentClient} is the default implementation, over the\n * library's own REST routes with `fetch`. An app with its own client — a generated one, a different\n * auth scheme (cookie session + CSRF header), a backend that is not this library at all but speaks\n * docs/stream-protocol.md — implements this instead and passes it as `<AgentProvider backend>` (or\n * per hook, `useAgentChat({ backend })`).\n *\n * The streaming, thread and cancel members are required: without them there is no chat. The rest\n * are optional; a hook that needs one the backend does not have throws\n * {@link AgentBackendUnsupportedError} when it is called, so a backend only implements what its\n * server supports.\n */\nexport interface AgentBackend {\n /** Start a turn and return its SSE stream. Throw on a non-2xx answer. */\n openChatStream(request: ChatStreamRequest): Promise<ChatStreamResponse>;\n /** Attach to a streaming run. Resolve `null` when nothing is streaming under that id (HTTP 404). */\n resumeChatStream(request: ResumeStreamRequest): Promise<ChatStreamResponse | null>;\n /** Hard-stop a run server-side. */\n cancelStream(runId: string): Promise<unknown>;\n\n listThreads(): Promise<ThreadSummary[]>;\n getThread(id: string): Promise<ThreadDetail>;\n updateThread(id: string, patch: ThreadPatch): Promise<unknown>;\n deleteThread(id: string): Promise<unknown>;\n\n /**\n * Queue a message on a thread (`POST <base>/chat` with `mode: 'queue'` or `'interrupt'`), which\n * the server answers with `202` JSON rather than a stream. What `chat.queue` sends through; a\n * backend without it keeps the composer blocked while a turn runs.\n */\n enqueueMessage?(request: ChatStreamRequest): Promise<QueuedSendResult>;\n /** `GET <base>/threads/:id/queue`. */\n getQueue?(threadId: string): Promise<ChatQueueState>;\n /** `PATCH <base>/queue/:messageId` — edit and/or move a waiting message. */\n updateQueuedMessage?(messageId: string, update: QueuedMessageUpdate): Promise<ChatQueueState>;\n /** `DELETE <base>/queue/:messageId`. */\n removeQueuedMessage?(messageId: string): Promise<ChatQueueState>;\n /**\n * `POST <base>/queue/:messageId/interrupt` — run a waiting message now: it moves to the head as an\n * interrupt and the running turn is cancelled for it. `interrupting` is the run that was\n * cancelled; `runId` is set instead when nothing was running and the message started at once.\n * What `chat.queue.interrupt(id)` calls.\n */\n interruptQueuedMessage?(\n messageId: string,\n ): Promise<ChatQueueState & { runId?: string; interrupting?: string }>;\n /** `DELETE <base>/threads/:id/queue`. */\n clearQueue?(threadId: string): Promise<ChatQueueState>;\n /** `POST <base>/threads/:id/queue/resume` — `runId` when the head started. */\n resumeQueue?(threadId: string): Promise<ChatQueueState & { runId?: string }>;\n\n forkFromMessage?(threadId: string, messageId: string): Promise<ThreadSummary>;\n promoteThread?(id: string): Promise<unknown>;\n truncateFromMessage?(threadId: string, messageId: string): Promise<unknown>;\n\n listActionProposals?(input: { threadId: string }): Promise<ActionProposalView[]>;\n approveActionProposal?(input: {\n threadId: string;\n proposalId: string;\n remember?: boolean;\n }): Promise<ActionProposalMutationView>;\n rejectActionProposal?(input: {\n threadId: string;\n proposalId: string;\n reason?: string;\n }): Promise<ActionProposalMutationView>;\n\n approveToolCall?(input: {\n toolCallId: string;\n remember?: boolean;\n via?: string;\n }): Promise<unknown>;\n rejectToolCall?(input: { toolCallId: string; reason?: string; via?: string }): Promise<unknown>;\n answerToolCall?(input: {\n toolCallId: string;\n answers?: Record<string, string[]>;\n via?: string;\n }): Promise<unknown>;\n skipToolCall?(input: { toolCallId: string; via?: string }): Promise<unknown>;\n\n uploadAttachment?(file: File, options?: UploadAttachmentOptions): Promise<MessageAttachment>;\n listTools?(agent?: string): Promise<ToolCatalogEntry[]>;\n listSkills?(threadId?: string): Promise<SkillCatalogEntry[]>;\n /** `GET <base>/quota` — every budget window, and which one blocks sends, if any. */\n getQuota?(): Promise<QuotaReport>;\n /** `GET <base>/models?agent=` — what a model picker offers. */\n listModels?(agent?: string): Promise<ModelCatalogView>;\n /** `GET <base>/agents` — what an agent picker offers. */\n listAgents?(): Promise<AgentCatalogEntry[]>;\n /** `GET <base>/config` — attachment limits and upload mode, and which features are on. */\n getConfig?(): Promise<AgentClientConfig>;\n setMessageFeedback?(\n messageId: string,\n input: MessageFeedbackInput,\n ): Promise<{ feedback: MessageFeedback | null }>;\n}\n\n/** An optional {@link AgentBackend} member the bound backend does not implement was called. */\nexport class AgentBackendUnsupportedError extends Error {\n constructor(readonly method: string) {\n super(`The agent backend does not implement ${method}()`);\n this.name = 'AgentBackendUnsupportedError';\n }\n}\n\ntype OptionalMethod = {\n [K in keyof AgentBackend]-?: undefined extends AgentBackend[K] ? K : never;\n}[keyof AgentBackend];\n\n/**\n * The optional backend method `name`, bound — or a throw naming it. For hook code that has to call\n * something a backend may not offer.\n */\nexport function requireBackendMethod<K extends OptionalMethod>(\n backend: AgentBackend,\n name: K,\n): NonNullable<AgentBackend[K]> {\n const method = backend[name];\n if (typeof method !== 'function') {\n throw new AgentBackendUnsupportedError(name);\n }\n return (method as (...args: never[]) => unknown).bind(backend) as NonNullable<AgentBackend[K]>;\n}\n","import type { AgentClientConfig } from '@dudousxd/nestjs-agent-core';\nimport { useEffect, useState } from 'react';\nimport type { AgentBackend } from '../backend.js';\nimport { useAgentBackend } from '../provider.js';\n\nexport interface UseAgentConfigOptions {\n /** Default: the enclosing `<AgentProvider>`'s. Without `getConfig` the config stays `undefined`. */\n backend?: AgentBackend;\n /** `false` holds the request. Default `true`. */\n enabled?: boolean;\n}\n\nexport interface AgentConfigState {\n /** `GET <base>/config`, once loaded — `undefined` before, on a failure, or on a backend without it. */\n config: AgentClientConfig | undefined;\n isLoading: boolean;\n error: Error | null;\n}\n\n// One request per backend for the whole page: the config is a deployment constant. A failure is\n// forgotten so the next mount retries.\nconst shared = new WeakMap<AgentBackend, Promise<AgentClientConfig>>();\n\nfunction load(backend: AgentBackend): Promise<AgentClientConfig> | undefined {\n const getConfig = backend.getConfig;\n if (typeof getConfig !== 'function') return undefined;\n let pending = shared.get(backend);\n if (pending === undefined) {\n pending = getConfig.call(backend).catch((error: unknown) => {\n shared.delete(backend);\n throw error;\n });\n shared.set(backend, pending);\n }\n return pending;\n}\n\n/**\n * The server's client config (`GET <base>/config`): attachment limits and upload mode, and whether a\n * model picker, a quota and anonymous identities are in play. Fetched once per backend and shared;\n * `useAttachments` takes its defaults from it.\n */\nexport function useAgentConfig(options: UseAgentConfigOptions = {}): AgentConfigState {\n const backend = useAgentBackend(options.backend);\n const enabled = options.enabled !== false;\n const [config, setConfig] = useState<AgentClientConfig | undefined>(undefined);\n const [isLoading, setLoading] = useState(false);\n const [error, setError] = useState<Error | null>(null);\n\n useEffect(() => {\n if (!enabled) return;\n const pending = load(backend);\n if (pending === undefined) return;\n let cancelled = false;\n setLoading(true);\n pending.then(\n (loaded) => {\n if (cancelled) return;\n setConfig(loaded !== null && typeof loaded === 'object' ? loaded : undefined);\n setError(null);\n setLoading(false);\n },\n (failure: unknown) => {\n if (cancelled) return;\n setError(failure instanceof Error ? failure : new Error(String(failure)));\n setLoading(false);\n },\n );\n return () => {\n cancelled = true;\n };\n }, [backend, enabled]);\n\n return { config, isLoading, error };\n}\n","import type { UiCapabilities } from '@dudousxd/nestjs-agent-core/genui';\nimport { type Context, type ReactNode, useContext, useMemo, useRef } from 'react';\nimport type { AgentBackend, AttachmentUploadStrategy } from './backend.js';\nimport { AgentClient } from './client.js';\nimport { sharedContext } from './components/ambient-ui.js';\nimport { GenuiProvider, type GenuiProviderValue } from './genui/generative-ui.js';\nimport type { HttpErrorListener } from './http-error.js';\n\n// Shared by key, like the genui contexts: `/media` and `/genui` are separate bundles.\nconst AgentBackendContext: Context<AgentBackend | null> = sharedContext<AgentBackend>(\n '@dudousxd/nestjs-agent-react:agent-backend',\n);\n\nexport interface AgentProviderProps {\n /** Advertise exact supported component versions; omission keeps legacy support, [] is text only. */\n uiCapabilities?: UiCapabilities;\n /**\n * A backend of your own — see {@link AgentBackend}. Omitted → an {@link AgentClient} over this\n * library's REST routes, built from the connection props below (which are ignored when a backend\n * is given). Must be stable across renders.\n */\n backend?: AgentBackend;\n /** The server's origin, e.g. `https://api.example.com`. Default `''` (same origin). */\n baseUrl?: string;\n /** `AgentModule`'s `path`, global prefix included (`'api/agent'`). Default `'agent'`. */\n path?: string;\n /** Static headers on every request. */\n headers?: Record<string, string>;\n /**\n * Read at every request — a short-lived bearer token, or a CSRF header read from a cookie\n * (`{ 'X-XSRF-TOKEN': readCookie('XSRF-TOKEN') }`).\n */\n getHeaders?: () => Record<string, string> | Promise<Record<string, string>>;\n /** `'include'` when the API is on another origin and authenticates by cookie. */\n credentials?: RequestCredentials;\n /** Injectable for tests / non-browser runtimes. */\n fetch?: typeof fetch;\n /**\n * Every error answer of the built-in client (an `AgentHttpError`, or a `MediaUploadError` from\n * `mediaAttachments()`), right before it is thrown — for app-wide reactions such as \"401 → sign\n * in again\". Read at call time, so it may change between renders.\n */\n onHttpError?: HttpErrorListener;\n /** Attachment uploads of the built-in client. */\n attachments?: {\n /** e.g. `mediaAttachments()` from `@dudousxd/nestjs-agent-react/media`. */\n upload?: AttachmentUploadStrategy;\n };\n /**\n * Set generative UI up here — the same settings `<GenuiProvider>` takes (registry, catalog,\n * resolver, fallback, …). Every message then draws pushed components with them.\n */\n genui?: GenuiProviderValue;\n children?: ReactNode;\n}\n\n/**\n * The agent connection, once, at the app root. Every hook below it — `useAgentChat`, `useThreads`,\n * `useModels`, `useAgents`, `useQuota`, `useToolCatalog`, `useMessageFeedback`, `useAttachments` —\n * talks to it unless handed a `backend` of its own.\n *\n * ```tsx\n * <AgentProvider baseUrl=\"https://api.example.com\" credentials=\"include\">\n * <App />\n * </AgentProvider>\n * ```\n *\n * Without a provider every hook shares one same-origin client on `/agent`.\n */\nexport function AgentProvider({\n backend,\n uiCapabilities,\n baseUrl,\n path,\n headers,\n getHeaders,\n credentials,\n fetch,\n onHttpError,\n attachments,\n genui,\n children,\n}: AgentProviderProps) {\n // Headers are read per request, so a re-render with new ones reaches the same client.\n const latestHeaders = useRef({ headers, getHeaders, onHttpError });\n latestHeaders.current = { headers, getHeaders, onHttpError };\n const upload = attachments?.upload;\n const value = useMemo(\n () =>\n backend ??\n new AgentClient({\n ...(baseUrl !== undefined ? { baseUrl } : {}),\n ...(path !== undefined ? { path } : {}),\n ...(credentials !== undefined ? { credentials } : {}),\n ...(fetch !== undefined ? { fetch } : {}),\n ...(upload !== undefined ? { attachments: { upload } } : {}),\n onHttpError: (error) => latestHeaders.current.onHttpError?.(error),\n getHeaders: async () => {\n const current = latestHeaders.current;\n const dynamic = (await current.getHeaders?.()) ?? {};\n return { ...current.headers, ...dynamic };\n },\n }),\n [backend, baseUrl, path, credentials, fetch, upload],\n );\n const content =\n genui !== undefined ? <GenuiProvider {...genui}>{children}</GenuiProvider> : children;\n return (\n <AgentUiCapabilitiesContext.Provider value={uiCapabilities ?? null}>\n <AgentBackendContext.Provider value={value}>{content}</AgentBackendContext.Provider>\n </AgentUiCapabilitiesContext.Provider>\n );\n}\n\nlet fallback: AgentClient | undefined;\n\n/** The client every hook uses outside an {@link AgentProvider}: same origin, `/agent`. */\nfunction defaultBackend(): AgentClient {\n fallback ??= new AgentClient();\n return fallback;\n}\n\n/**\n * The backend a hook talks to: `own` when given, else the enclosing {@link AgentProvider}'s, else a\n * shared same-origin client on `/agent`. For your own hooks over the same connection.\n */\nexport function useAgentBackend<B extends AgentBackend = AgentBackend>(own?: B): B {\n const provided = useContext(AgentBackendContext);\n return (own ?? provided ?? defaultBackend()) as B;\n}\n\nconst AgentUiCapabilitiesContext = sharedContext<UiCapabilities>(\n '@dudousxd/nestjs-agent-react:ui-capabilities',\n);\n/**\n * The UI capabilities the nearest `<AgentProvider uiCapabilities>` declared, or `undefined` when it\n * declared none. `useAgentChat` reads this unless given its own `uiCapabilities`; read it too when a\n * hook of yours talks to the agent outside `useAgentChat`.\n */\nexport function useAgentUiCapabilities(): UiCapabilities | undefined {\n return useContext(AgentUiCapabilitiesContext) ?? undefined;\n}\n","import { type Context, type ReactNode, createContext, useContext } from 'react';\nimport type { TranscriptUiBlock } from '../transcript/model.js';\n\n/** Draws a server-pushed component block. */\nexport type AmbientRenderUi = (block: TranscriptUiBlock) => ReactNode;\n\n/**\n * A context stored on `globalThis` under a registered symbol. Each entry point (`.`, `/genui`,\n * `/genui/json-render`) is its own bundle with its own copy of every module, so a context one entry\n * provides and another reads has to be found by key, not by module identity.\n */\nexport function sharedContext<T>(key: string): Context<T | null> {\n const symbol = Symbol.for(key);\n const holder = globalThis as Record<symbol, Context<T | null> | undefined>;\n const existing = holder[symbol];\n if (existing !== undefined) return existing;\n const created = createContext<T | null>(null);\n holder[symbol] = created;\n return created;\n}\n\n/**\n * How pushed components are drawn when no `renderUi` is passed — set by `<GenuiProvider>` (the\n * `/genui` subpath) and read by `MessageItem`.\n */\nexport const AmbientRenderUiContext: Context<AmbientRenderUi | null> =\n sharedContext<AmbientRenderUi>('@dudousxd/nestjs-agent-react:ambient-render-ui');\n\n/**\n * The renderer `<GenuiProvider>` installed for pushed components, or `null` outside one. For a\n * custom transcript built on `useTranscriptItem`: draw a `ui` block with it and you get what\n * `MessageItem` draws.\n */\nexport function useAmbientRenderUi(): AmbientRenderUi | null {\n return useContext(AmbientRenderUiContext);\n}\n","import {\n Component,\n type Context,\n type ErrorInfo,\n type ReactNode,\n createContext,\n memo,\n useCallback,\n useContext,\n useMemo,\n useRef,\n} from 'react';\nimport { AmbientRenderUiContext, sharedContext } from '../components/ambient-ui.js';\nimport type { TranscriptUiBlock } from '../transcript/model.js';\nimport { shareStructure } from './share-structure.js';\nimport type {\n GenerativeUIElement,\n GenerativeUIItem,\n GenerativeUIOptions,\n GenerativeUIProblem,\n GenerativeUIState,\n GenuiNodeState,\n GenuiPlaceholder,\n GenuiRegistry,\n GenuiRenderer,\n} from './types.js';\nimport {\n useGenerativeUIState,\n useResolvedComponent,\n useValidatedProps,\n} from './use-generative-ui.js';\n\n/** What to draw instead of a component that did not render. Default: nothing. */\nexport type GenerativeUIFallback = ReactNode | ((problem: GenerativeUIProblem) => ReactNode);\n\n/** How a tree draws what is not a node: read when a node renders, never a reason to re-render one. */\ninterface TreeLook {\n fallback: GenerativeUIFallback | undefined;\n loading: ReactNode;\n placeholder: GenuiPlaceholder | undefined;\n onError: ((error: unknown, item: GenerativeUIItem) => void) | undefined;\n}\n\ninterface TreeScope {\n fallbackText?: string;\n componentVersions?: Record<string, number>;\n options: GenerativeUIOptions;\n /** A fallback was given: a failing node draws it rather than failing the whole tree. */\n hasFallback: boolean;\n /**\n * The latest fallback, loading, placeholder and onError. Behind a ref so an inline element or\n * callback from a host that re-renders on every token does not re-render every node with it.\n */\n look: { readonly current: TreeLook };\n}\n\nconst TreeScopeContext = createContext<TreeScope | null>(null);\n\n// Shared by key, like the provider's: a renderer imports the hook from `/genui` while the tree may\n// be drawn by the `/genui/json-render` bundle's copy of this module.\nconst GenuiNodeContext: Context<GenuiNodeState | null> = sharedContext<GenuiNodeState>(\n '@dudousxd/nestjs-agent-react:genui-node',\n);\n\n/**\n * The tree node being rendered — read it in a renderer to draw a skeleton while the model is still\n * writing the node (`incomplete`), e.g. a chart's axes before its data. `null` outside a tree.\n *\n * ```tsx\n * function Chart(props: ChartProps) {\n * const node = useGenuiNode();\n * if (node?.incomplete && !props.data?.length) return <ChartSkeleton title={props.title} />;\n * return <BarChart {...props} />;\n * }\n * ```\n */\nexport function useGenuiNode(): GenuiNodeState | null {\n return useContext(GenuiNodeContext);\n}\n\nfunction renderPlaceholder(look: TreeLook, node: GenuiNodeState): ReactNode {\n const { placeholder } = look;\n if (typeof placeholder === 'function') return placeholder(node);\n return placeholder !== undefined ? placeholder : look.loading;\n}\n\nfunction renderFallback(fallback: GenerativeUIFallback | undefined, problem: GenerativeUIProblem) {\n if (typeof fallback === 'function') return fallback(problem);\n if (fallback !== undefined) return fallback;\n return problem.item.fallbackText !== undefined ? (\n <span style={{ whiteSpace: 'pre-wrap' }}>{problem.item.fallbackText}</span>\n ) : null;\n}\n\ninterface BoundaryProps {\n item: GenerativeUIItem;\n fallback: GenerativeUIFallback | undefined;\n onError: ((error: unknown, item: GenerativeUIItem) => void) | undefined;\n children: ReactNode;\n}\n\n/** One failing renderer takes down its own item, never the message around it. */\nclass ItemBoundary extends Component<BoundaryProps, { error: unknown; failed: boolean }> {\n override state = { error: undefined as unknown, failed: false };\n\n static getDerivedStateFromError(error: unknown) {\n return { error, failed: true };\n }\n\n override componentDidCatch(error: unknown, _info: ErrorInfo) {\n this.props.onError?.(error, this.props.item);\n }\n\n override componentDidUpdate(previous: BoundaryProps) {\n // New props for the same item (a streamed update) get a fresh chance to render.\n if (this.state.failed && previous.item !== this.props.item) {\n this.setState({ error: undefined, failed: false });\n }\n }\n\n override render() {\n if (this.state.failed) {\n return renderFallback(this.props.fallback, {\n reason: 'error',\n item: this.props.item,\n error: this.state.error,\n });\n }\n return this.props.children;\n }\n}\n\nfunction nodeItem(node: GenerativeUIElement, id: string): GenerativeUIItem {\n return { id, component: node.type, props: node.props ?? {}, version: null, toolCallId: null };\n}\n\n/** A failing node takes the whole tree to the item's fallback text — no fallback of its own given. */\nfunction failsWhole(scope: TreeScope): boolean {\n return !scope.hasFallback && scope.fallbackText !== undefined;\n}\n\ninterface TreeNodeProps {\n node: GenerativeUIElement;\n id: string;\n /** Wrap the node in its own error boundary (every node but the root, which its item's has). */\n bounded: boolean;\n}\n\n/**\n * One tree node, re-rendered only when its node is a different object (or the scope changed).\n * {@link GenuiTree} keeps an unchanged node the same object from frame to frame, so as a preview\n * streams in only the nodes that grew — and their ancestors — render again; a node turning from\n * `incomplete`/`held` to final is a changed node and renders.\n */\nconst TreeNode = memo(\n function TreeNode({ node, id, bounded }: TreeNodeProps) {\n const scope = useContext(TreeScopeContext);\n const item = useMemo(() => nodeItem(node, id), [node, id]);\n if (scope === null) return null;\n if (!bounded || failsWhole(scope)) return <TreeNodeBody node={node} id={id} item={item} />;\n return (\n <ItemBoundary\n item={item}\n fallback={scope.look.current.fallback}\n onError={scope.look.current.onError}\n >\n <TreeNodeBody node={node} id={id} item={item} />\n </ItemBoundary>\n );\n },\n (previous, next) =>\n previous.node === next.node && previous.id === next.id && previous.bounded === next.bounded,\n);\n\n/** A tree node resolved and validated like a top-level item, children rendered as its `children`. */\nfunction TreeNodeBody({\n node,\n id,\n item,\n}: {\n node: GenerativeUIElement;\n id: string;\n item: GenerativeUIItem;\n}) {\n const scope = useContext(TreeScopeContext);\n // A node of a preview the model is still writing: its props are half there, so they are not\n // validated (the final frame is) — the renderer is told instead, through `useGenuiNode`.\n const incomplete = node.incomplete === true;\n const held = node.held === true;\n const state = useMemo<GenuiNodeState>(\n () => ({ id, type: node.type, incomplete, held }),\n [id, node.type, incomplete, held],\n );\n const storedVersion = scope?.componentVersions?.[node.type];\n const definition = scope?.options.catalog?.get?.(node.type);\n const incompatible =\n storedVersion !== undefined &&\n definition !== undefined &&\n storedVersion !== (definition.version ?? 1);\n const resolution = useResolvedComponent(\n node.type,\n storedVersion ?? null,\n incompatible ? {} : (scope?.options.registry ?? {}),\n scope?.options.resolveComponent,\n );\n const validation = useValidatedProps(\n incompatible || incomplete ? undefined : scope?.options.catalog,\n node.type,\n item.props,\n );\n if (scope === null) return null;\n const look = scope.look.current;\n if (held) {\n return (\n <GenuiNodeContext.Provider value={state}>\n {renderPlaceholder(look, state)}\n </GenuiNodeContext.Provider>\n );\n }\n if (resolution.status === 'loading' || validation.status === 'pending') return look.loading;\n if (resolution.status === 'unknown') {\n if (failsWhole(scope)) throw new Error('Unknown tree component');\n return renderFallback(look.fallback, { reason: 'unknown', item });\n }\n if (resolution.status === 'error') {\n if (failsWhole(scope)) throw resolution.error;\n return renderFallback(look.fallback, { reason: 'error', item, error: resolution.error });\n }\n if (validation.status === 'invalid') {\n if (failsWhole(scope)) throw new Error('Invalid tree component');\n return renderFallback(look.fallback, { reason: 'invalid', item, issues: validation.issues });\n }\n const Renderer = resolution.Component;\n const children = Array.isArray(node.children) ? node.children : [];\n return (\n <GenuiNodeContext.Provider value={state}>\n <Renderer {...validation.props}>\n {children.length > 0\n ? children.map((child, index) => {\n const childId = `${id}.${index}`;\n return <TreeNode key={childId} node={child} id={childId} bounded />;\n })\n : undefined}\n </Renderer>\n </GenuiNodeContext.Provider>\n );\n}\n\n/**\n * Renders a `genui:tree` frame's `{ root }` node by node through the same registry, catalog and\n * resolver as top-level components. Used automatically for tree frames unless a `treeRenderer`\n * (e.g. the json-render one) or a registry entry for `genui:tree` takes over.\n *\n * Each frame's tree is structurally shared with the previous one: a node equal to the one before\n * keeps that object, and its renderer does not run again.\n */\nexport function GenuiTree({ root }: { root?: GenerativeUIElement }) {\n const previous = useRef<GenerativeUIElement | undefined>(undefined);\n const valid = root !== undefined && root !== null && typeof root.type === 'string';\n const shared = valid ? shareStructure(previous.current, root) : undefined;\n previous.current = shared;\n if (shared === undefined) return null;\n return <TreeNode node={shared} id=\"root\" bounded={false} />;\n}\n\nexport interface GenerativeUIScopeProps extends GenerativeUIOptions {\n fallbackText?: string;\n componentVersions?: Record<string, number>;\n fallback?: GenerativeUIFallback;\n loading?: ReactNode;\n /** Drawn for a tree node held back while the model writes it. Default: `loading`. */\n placeholder?: GenuiPlaceholder;\n onError?: (error: unknown, item: GenerativeUIItem) => void;\n children?: ReactNode;\n}\n\n/**\n * The registry, catalog and fallbacks tree nodes render with. `<GenerativeUI>` provides it; wrap\n * your own chrome in it when you draw `useGenerativeUI`'s `Component` yourself and it may be a tree.\n */\nexport function GenerativeUIScope({\n registry,\n catalog,\n resolveComponent,\n fallback,\n fallbackText,\n componentVersions,\n loading = null,\n placeholder,\n onError,\n children,\n}: GenerativeUIScopeProps) {\n // Read afresh from every frame of the item that carries them: kept the same object while equal.\n const versionsRef = useRef<Record<string, number> | undefined>(undefined);\n const versions = shareStructure(versionsRef.current, componentVersions);\n versionsRef.current = versions;\n const look = useRef<TreeLook>({ fallback, loading, placeholder, onError });\n look.current = { fallback, loading, placeholder, onError };\n const hasFallback = fallback !== undefined;\n const scope = useMemo<TreeScope>(\n () => ({\n options: {\n registry,\n ...(catalog !== undefined ? { catalog } : {}),\n ...(resolveComponent !== undefined ? { resolveComponent } : {}),\n },\n hasFallback,\n ...(versions !== undefined ? { componentVersions: versions } : {}),\n ...(fallbackText !== undefined ? { fallbackText } : {}),\n look,\n }),\n [registry, catalog, resolveComponent, hasFallback, fallbackText, versions],\n );\n return <TreeScopeContext.Provider value={scope}>{children}</TreeScopeContext.Provider>;\n}\n\n/** What `<GenuiProvider>` hands every `<GenerativeUI>` / `useGenerativeUI` below it. */\nexport interface GenuiProviderValue extends Partial<GenerativeUIOptions> {\n fallback?: GenerativeUIFallback;\n loading?: ReactNode;\n /** Drawn for a tree node held back while the model writes it (`streaming: 'complete'`). */\n placeholder?: GenuiPlaceholder;\n onError?: (error: unknown, item: GenerativeUIItem) => void;\n}\n\n// Shared by key: `/genui` and `/genui/json-render` are separate bundles, and a provider from one\n// must reach a `<GenerativeUI>` from the other.\nconst GenuiContext: Context<GenuiProviderValue | null> = sharedContext<GenuiProviderValue>(\n '@dudousxd/nestjs-agent-react:genui-provider',\n);\n\n/** The enclosing `<GenuiProvider>`'s settings, or `null` outside one. */\nexport function useGenuiProvider(): GenuiProviderValue | null {\n return useContext(GenuiContext);\n}\n\nexport interface GenuiProviderProps extends GenuiProviderValue {\n children?: ReactNode;\n}\n\n/**\n * Set generative UI up once, at the app root: the registry of your renderers, the catalog to\n * validate against, a resolver for components the registry lacks, and what to draw when one does\n * not render. Every `<GenerativeUI>` below reads it (its own props still win), and `MessageItem` /\n * `MessageList` draw pushed components with it — no `renderUi` per message.\n *\n * ```tsx\n * <GenuiProvider registry={registry} catalog={catalog} fallback={({ item }) => <Unknown name={item.component} />}>\n * <App />\n * </GenuiProvider>\n * ```\n */\nexport function GenuiProvider({\n registry,\n catalog,\n resolveComponent,\n treeRenderer,\n fallback,\n loading,\n placeholder,\n onError,\n children,\n}: GenuiProviderProps) {\n const value = useMemo<GenuiProviderValue>(\n () => ({\n ...(registry !== undefined ? { registry } : {}),\n ...(catalog !== undefined ? { catalog } : {}),\n ...(resolveComponent !== undefined ? { resolveComponent } : {}),\n ...(treeRenderer !== undefined ? { treeRenderer } : {}),\n ...(fallback !== undefined ? { fallback } : {}),\n ...(loading !== undefined ? { loading } : {}),\n ...(placeholder !== undefined ? { placeholder } : {}),\n ...(onError !== undefined ? { onError } : {}),\n }),\n [registry, catalog, resolveComponent, treeRenderer, fallback, loading, placeholder, onError],\n );\n const renderUi = useCallback((block: TranscriptUiBlock) => <GenerativeUI part={block} />, []);\n return (\n <GenuiContext.Provider value={value}>\n <AmbientRenderUiContext.Provider value={renderUi}>{children}</AmbientRenderUiContext.Provider>\n </GenuiContext.Provider>\n );\n}\n\nconst NO_REGISTRY: GenuiRegistry = {};\n\n/** Provider settings overlaid with explicit ones (explicit wins), memoized on their parts. */\nfunction useMergedOptions(own: Partial<GenerativeUIOptions>): GenerativeUIOptions {\n const provided = useContext(GenuiContext);\n const registry = own.registry ?? provided?.registry ?? NO_REGISTRY;\n const catalog = own.catalog ?? provided?.catalog;\n const resolveComponent = own.resolveComponent ?? provided?.resolveComponent;\n const treeRenderer = own.treeRenderer ?? provided?.treeRenderer;\n return useMemo(\n () => ({\n registry,\n ...(catalog !== undefined ? { catalog } : {}),\n ...(resolveComponent !== undefined ? { resolveComponent } : {}),\n ...(treeRenderer !== undefined ? { treeRenderer } : {}),\n }),\n [registry, catalog, resolveComponent, treeRenderer],\n );\n}\n\n/**\n * The headless half of {@link GenerativeUI}: what to draw for one pushed component, or `null` when\n * `part` is not one. Options default to the enclosing `<GenuiProvider>`'s.\n */\nexport function useGenerativeUI(\n part: unknown,\n options: Partial<GenerativeUIOptions> = {},\n): GenerativeUIState | null {\n const merged = useMergedOptions(options);\n return useGenerativeUIState(part, merged, merged.treeRenderer ?? (GenuiTree as GenuiRenderer));\n}\n\nexport interface GenerativeUIProps extends Partial<GenerativeUIOptions> {\n /** A transcript `ui` block, a `data-ui` message part, or a stored `{ id, component, props, version? }`. */\n part: TranscriptUiBlock | GenerativeUIItem | unknown;\n /** Drawn for an unknown component, invalid props, or a renderer that threw. Default: the provider's, then the item's persisted text. */\n fallback?: GenerativeUIFallback;\n /** Drawn while a resolver or an async validation is pending. Default: the provider's, else nothing. */\n loading?: ReactNode;\n /**\n * Drawn for a tree node held back while the model writes it (its component streams `complete`).\n * Default: the provider's, else `loading`.\n */\n placeholder?: GenuiPlaceholder;\n /** A renderer threw (the item shows `fallback`). */\n onError?: (error: unknown, item: GenerativeUIItem) => void;\n}\n\n/**\n * Draws one server-pushed component with the app's own renderer. Headless: it adds no element and\n * no style of its own — only what the registry's component renders (and whatever `fallback` /\n * `loading` you pass). Everything but `part` defaults to the enclosing `<GenuiProvider>`.\n *\n * ```tsx\n * <GenerativeUI part={block} />\n * ```\n */\nexport function GenerativeUI({\n part,\n registry,\n catalog,\n resolveComponent,\n treeRenderer,\n fallback: ownFallback,\n loading: ownLoading,\n placeholder: ownPlaceholder,\n onError: ownOnError,\n}: GenerativeUIProps) {\n const provided = useContext(GenuiContext);\n const fallback = ownFallback !== undefined ? ownFallback : provided?.fallback;\n const loading = ownLoading ?? provided?.loading ?? null;\n const placeholder = ownPlaceholder !== undefined ? ownPlaceholder : provided?.placeholder;\n const onError = ownOnError ?? provided?.onError;\n const options = useMergedOptions({\n ...(registry !== undefined ? { registry } : {}),\n ...(catalog !== undefined ? { catalog } : {}),\n ...(resolveComponent !== undefined ? { resolveComponent } : {}),\n ...(treeRenderer !== undefined ? { treeRenderer } : {}),\n });\n const state = useGenerativeUIState(\n part,\n options,\n options.treeRenderer ?? (GenuiTree as GenuiRenderer),\n );\n if (state === null) return null;\n if (state.status === 'loading') return loading;\n if (state.status === 'problem') {\n const { status: _status, ...problem } = state;\n return renderFallback(fallback, problem);\n }\n const Renderer = state.Component;\n return (\n <GenerativeUIScope\n {...options}\n {...(state.item.componentVersions !== undefined\n ? { componentVersions: state.item.componentVersions }\n : {})}\n {...(state.item.fallbackText !== undefined ? { fallbackText: state.item.fallbackText } : {})}\n fallback={fallback}\n loading={loading}\n {...(placeholder !== undefined ? { placeholder } : {})}\n {...(onError !== undefined ? { onError } : {})}\n >\n <ItemBoundary item={state.item} fallback={fallback} onError={onError}>\n <Renderer {...state.props} />\n </ItemBoundary>\n </GenerativeUIScope>\n );\n}\n","function isPlainObject(value: unknown): value is Record<string, unknown> {\n if (typeof value !== 'object' || value === null || Array.isArray(value)) return false;\n const prototype = Object.getPrototypeOf(value);\n return prototype === Object.prototype || prototype === null;\n}\n\n/**\n * `next`, with every part structurally equal to the same part of `previous` replaced by that part\n * of `previous` — `previous` itself when the two are equal throughout. Plain objects and arrays are\n * compared member by member (arrays by position); anything else by `Object.is`.\n *\n * The chat reaches React as a fresh deep copy on every update (the AI SDK clones the streaming\n * message on each chunk), so a pushed component's props and a tree's nodes are new objects on every\n * token even when nothing in them changed. Run through this, an unchanged node keeps its identity\n * and a memoized renderer skips it; a changed one (more props, `incomplete` → final) is new, and so\n * is every ancestor of it, which is what re-renders.\n */\nexport function shareStructure<T>(previous: unknown, next: T): T {\n if (Object.is(previous, next)) return next;\n if (Array.isArray(next)) {\n if (!Array.isArray(previous)) return next;\n let same = previous.length === next.length;\n const shared = next.map((value, index) => {\n const kept = shareStructure(previous[index], value);\n if (kept !== previous[index]) same = false;\n return kept;\n });\n return (same ? previous : shared) as T;\n }\n if (isPlainObject(next)) {\n if (!isPlainObject(previous)) return next;\n const keys = Object.keys(next);\n let same = keys.length === Object.keys(previous).length;\n const shared: Record<string, unknown> = {};\n for (const key of keys) {\n const kept = shareStructure(previous[key], next[key]);\n if (kept !== previous[key] || !Object.hasOwn(previous, key)) same = false;\n shared[key] = kept;\n }\n return (same ? previous : shared) as T;\n }\n return next;\n}\n","import { useEffect, useMemo, useState } from 'react';\nimport {\n GENUI_TREE_COMPONENT,\n type GenerativeUIItem,\n type GenerativeUIOptions,\n type GenerativeUIState,\n type GenuiCatalogLike,\n type GenuiIssueLike,\n type GenuiRegistry,\n type GenuiRenderer,\n type ResolveComponent,\n} from './types.js';\n\nfunction isRecord(value: unknown): value is Record<string, unknown> {\n return typeof value === 'object' && value !== null && !Array.isArray(value);\n}\n\n/**\n * Normalize whatever carries a pushed component: a transcript `ui` block, a `data-ui` message part\n * (`{ type: 'data-ui', id, data }`), a stored `{ id, component, props, version? }` entry. `null` for\n * anything else.\n */\nexport function toGenerativeUIItem(part: unknown): GenerativeUIItem | null {\n if (!isRecord(part)) return null;\n const source = part.type === 'data-ui' && isRecord(part.data) ? part.data : part;\n if (typeof source.component !== 'string') return null;\n const id =\n typeof source.id === 'string' ? source.id : typeof part.id === 'string' ? part.id : null;\n if (id === null) return null;\n return {\n id,\n component: source.component,\n ...(isRecord(source.componentVersions) &&\n Object.values(source.componentVersions).every(\n (version) => typeof version === 'number' && Number.isSafeInteger(version) && version > 0,\n )\n ? { componentVersions: { ...source.componentVersions } as Record<string, number> }\n : {}),\n ...(typeof source.fallbackText === 'string' ? { fallbackText: source.fallbackText } : {}),\n props: isRecord(source.props) ? source.props : {},\n version: typeof source.version === 'number' ? source.version : null,\n toolCallId: typeof source.toolCallId === 'string' ? source.toolCallId : null,\n ...(source.partial === true ? { partial: true as const } : {}),\n };\n}\n\ntype Resolution =\n | { status: 'ready'; Component: GenuiRenderer }\n | { status: 'loading' }\n | { status: 'unknown' }\n | { status: 'error'; error: unknown };\n\ninterface CacheEntry {\n resolution: Resolution;\n settled: Promise<void> | null;\n}\n\nconst resolverCaches = new WeakMap<ResolveComponent, Map<string, CacheEntry>>();\n\nfunction resolveCached(\n resolve: ResolveComponent,\n name: string,\n version: number | null,\n): CacheEntry {\n let cache = resolverCaches.get(resolve);\n if (cache === undefined) {\n cache = new Map();\n resolverCaches.set(resolve, cache);\n }\n const key = `${name}@${version ?? ''}`;\n const hit = cache.get(key);\n if (hit !== undefined) return hit;\n let entry: CacheEntry;\n try {\n const result = resolve(name, version);\n if (result instanceof Promise) {\n entry = { resolution: { status: 'loading' }, settled: null };\n entry.settled = result.then(\n (Component) => {\n entry.resolution = Component ? { status: 'ready', Component } : { status: 'unknown' };\n },\n (error: unknown) => {\n entry.resolution = { status: 'error', error };\n },\n );\n } else {\n entry = {\n resolution: result ? { status: 'ready', Component: result } : { status: 'unknown' },\n settled: null,\n };\n }\n } catch (error) {\n entry = { resolution: { status: 'error', error }, settled: null };\n }\n cache.set(key, entry);\n return entry;\n}\n\n/**\n * Which renderer draws `name`: the registry first, then `resolveComponent` (cached; async results\n * re-render the caller when they land). `fallbackTree` answers the tree component when the\n * registry does not override it.\n */\nexport function useResolvedComponent(\n name: string,\n version: number | null,\n registry: GenuiRegistry,\n resolve: ResolveComponent | undefined,\n fallbackTree?: GenuiRenderer,\n): Resolution {\n const [, setTick] = useState(0);\n const own = registry[name];\n const entry =\n own !== undefined || resolve === undefined ? null : resolveCached(resolve, name, version);\n const pending = entry?.resolution.status === 'loading' ? entry.settled : null;\n useEffect(() => {\n if (pending === null) return;\n let live = true;\n void pending.then(() => {\n if (live) setTick((tick) => tick + 1);\n });\n return () => {\n live = false;\n };\n }, [pending]);\n if (own !== undefined) return { status: 'ready', Component: own };\n if (entry !== null && entry.resolution.status !== 'unknown') return entry.resolution;\n if (name === GENUI_TREE_COMPONENT && fallbackTree !== undefined) {\n return { status: 'ready', Component: fallbackTree };\n }\n return { status: 'unknown' };\n}\n\ntype Validation =\n | { status: 'ok'; props: Record<string, unknown> }\n | { status: 'pending' }\n | { status: 'invalid'; issues: GenuiIssueLike[] };\n\n/**\n * Props checked against the catalog: synchronously when the catalog can (`validateSync`), else\n * after the async check settles. A component the catalog does not know passes through unchecked.\n */\nexport function useValidatedProps(\n catalog: GenuiCatalogLike | undefined,\n name: string,\n props: Record<string, unknown>,\n): Validation {\n const checked = catalog?.has(name) === true;\n const immediate = useMemo<Validation | null>(() => {\n if (!checked || catalog === undefined) return { status: 'ok', props };\n const result = catalog.validateSync?.(name, props);\n if (result === undefined) return null;\n return result.ok\n ? { status: 'ok', props: result.value }\n : { status: 'invalid', issues: result.issues };\n }, [checked, catalog, name, props]);\n const [late, setLate] = useState<{ props: Record<string, unknown>; result: Validation } | null>(\n null,\n );\n useEffect(() => {\n if (immediate !== null || catalog === undefined) return;\n let live = true;\n catalog.validate(name, props).then(\n (result) => {\n if (!live) return;\n setLate({\n props,\n result: result.ok\n ? { status: 'ok', props: result.value }\n : { status: 'invalid', issues: result.issues },\n });\n },\n (error: unknown) => {\n if (!live) return;\n setLate({\n props,\n result: {\n status: 'invalid',\n issues: [{ path: [], message: error instanceof Error ? error.message : String(error) }],\n },\n });\n },\n );\n return () => {\n live = false;\n };\n }, [immediate, catalog, name, props]);\n if (immediate !== null) return immediate;\n return late !== null && late.props === props ? late.result : { status: 'pending' };\n}\n\n/** {@link import('./generative-ui.js').useGenerativeUI}, with the tree renderer handed in (avoids an import cycle). */\nexport function useGenerativeUIState(\n part: unknown,\n options: GenerativeUIOptions,\n fallbackTree: GenuiRenderer | undefined,\n): GenerativeUIState | null {\n const item = useMemo(() => toGenerativeUIItem(part), [part]);\n const name = item?.component ?? '';\n const definition = options.catalog?.get?.(name);\n const incompatible =\n item?.fallbackText !== undefined &&\n item.version !== null &&\n definition !== undefined &&\n item.version !== (definition.version ?? 1);\n const resolution = useResolvedComponent(\n name,\n item?.version ?? null,\n incompatible ? {} : options.registry,\n item === null ? undefined : options.resolveComponent,\n fallbackTree,\n );\n const empty = useMemo<Record<string, unknown>>(() => ({}), []);\n // A tree is validated node by node as it renders, not as one component.\n const validation = useValidatedProps(\n item === null || name === GENUI_TREE_COMPONENT || incompatible ? undefined : options.catalog,\n name,\n item?.props ?? empty,\n );\n if (item === null) return null;\n // A withdrawn preview (partial, nothing to draw): the call will not replace it.\n if (item.partial === true && Object.keys(item.props).length === 0) return null;\n if (\n name === GENUI_TREE_COMPONENT &&\n item.fallbackText !== undefined &&\n (!isRecord(item.props.root) || typeof item.props.root.type !== 'string')\n )\n return {\n status: 'problem',\n reason: 'invalid',\n item,\n issues: [{ path: ['root'], message: 'Invalid UI tree root' }],\n };\n if (resolution.status === 'loading') return { status: 'loading', item };\n if (resolution.status === 'unknown') return { status: 'problem', reason: 'unknown', item };\n if (resolution.status === 'error') {\n return { status: 'problem', reason: 'error', item, error: resolution.error };\n }\n if (validation.status === 'pending') return { status: 'loading', item };\n if (validation.status === 'invalid') {\n return { status: 'problem', reason: 'invalid', item, issues: validation.issues };\n }\n return { status: 'ready', item, Component: resolution.Component, props: validation.props };\n}\n","import type { ComponentType, ReactNode } from 'react';\n\n/** The `ui` frame component a composed tree is pushed under (`GENUI_TREE_COMPONENT` of `@dudousxd/nestjs-agent-core/genui`). */\nexport const GENUI_TREE_COMPONENT = 'genui:tree';\n\n/** One pushed component, normalized from whatever carried it (a transcript block, a `data-ui` part, a stored entry). */\nexport interface GenerativeUIItem {\n fallbackText?: string;\n componentVersions?: Record<string, number>;\n id: string;\n component: string;\n props: Record<string, unknown>;\n version: number | null;\n toolCallId: string | null;\n /**\n * A preview drawn while the model is still writing the call (genui `streaming: 'partial'`):\n * unvalidated, and replaced in place by the final frame under the same `id`.\n */\n partial?: true;\n}\n\n/** A node of a composed tree (`genui:tree` frames): `{ type, props, children? }`. */\nexport interface GenerativeUIElement {\n type: string;\n props: Record<string, unknown>;\n children?: GenerativeUIElement[];\n /**\n * The node's position (`root`, `root.0`, `root.0.2`), carried by partial frames. Stable as the\n * tree grows, and the same rule names the final tree's nodes.\n */\n id?: string;\n /** Partial frames only: the model has not finished writing this node. */\n incomplete?: true;\n /** Partial frames only: a `streaming: 'complete'` component held back until it closes (no props). */\n held?: true;\n}\n\n/**\n * What a tree node's renderer can learn about its node ({@link useGenuiNode}): which node it is,\n * and whether the model is still writing it. Room is left for more states (data a node is bound\n * to, loading) as separate fields — `incomplete` only ever means \"still being written\".\n */\nexport interface GenuiNodeState {\n /** The node's position id (`root`, `root.1.0`): stable from the first preview to the final frame. */\n id: string;\n type: string;\n /** The model has not finished writing this node: props (and children) may still grow. */\n incomplete: boolean;\n /** The node is a placeholder for a component that is only drawn whole (`streaming: 'complete'`). */\n held: boolean;\n}\n\n/**\n * An app's renderer for one component: it receives the component's props spread, plus `children`\n * when it is a layout node in a tree. Any React component — the library never styles anything.\n */\nexport type GenuiRenderer<P = any> = ComponentType<P & { children?: ReactNode }>;\n\n/** Component name → the app's renderer. */\nexport type GenuiRegistry = Record<string, GenuiRenderer>;\n\n/**\n * Resolve a component the registry does not have — typically a tenant's own component, fetched for\n * the exact `version` a message was rendered with. Return `null`/`undefined` for \"no such\n * component\". May be async; results are cached per resolver, name and version.\n */\nexport type ResolveComponent = (\n name: string,\n version: number | null,\n) => GenuiRenderer | null | undefined | Promise<GenuiRenderer | null | undefined>;\n\nexport interface GenuiIssueLike {\n path: (string | number)[];\n message: string;\n}\n\ntype ValidationLike =\n | { ok: true; value: Record<string, unknown> }\n | { ok: false; issues: GenuiIssueLike[] };\n\n/**\n * What the renderer needs from a catalog to validate props before drawing them. A `Catalog` from\n * `@dudousxd/nestjs-agent-core/genui` satisfies it; declared structurally so any catalog-shaped\n * object does too.\n */\nexport interface GenuiCatalogLike {\n get?(name: string): { version?: number } | undefined;\n has(name: string): boolean;\n validate(name: string, props: unknown): Promise<ValidationLike>;\n validateSync?(name: string, props: unknown): ValidationLike | undefined;\n}\n\nexport interface GenerativeUIOptions {\n registry: GenuiRegistry;\n /** Validate props against it before rendering. Components the catalog does not know render unvalidated. */\n catalog?: GenuiCatalogLike;\n resolveComponent?: ResolveComponent;\n /**\n * Draws a composed tree frame (`genui:tree`) whole — e.g. through json-render (see the\n * `/genui/json-render` subpath's `GenuiProvider`). Omitted → trees render node by node through\n * `registry`.\n */\n treeRenderer?: GenuiRenderer<{ root?: GenerativeUIElement }>;\n}\n\n/**\n * Drawn in place of a tree node that is not drawable yet — a `held` node (its component streams\n * `complete`) while the model writes it. Default: the `loading` element.\n */\nexport type GenuiPlaceholder = ReactNode | ((node: GenuiNodeState) => ReactNode);\n\n/** Why an item did not render. */\nexport type GenerativeUIProblem =\n | { reason: 'unknown'; item: GenerativeUIItem }\n | { reason: 'invalid'; item: GenerativeUIItem; issues: GenuiIssueLike[] }\n | { reason: 'error'; item: GenerativeUIItem; error: unknown };\n\nexport type GenerativeUIState =\n | {\n status: 'ready';\n item: GenerativeUIItem;\n Component: GenuiRenderer;\n props: Record<string, unknown>;\n }\n | { status: 'loading'; item: GenerativeUIItem }\n | ({ status: 'problem' } & GenerativeUIProblem);\n","import type { AgentStreamEvent, ElicitationRequest } from '@dudousxd/nestjs-agent-core';\nimport type { ChatStreamRequest, ChatStreamResponse } from './backend.js';\n\n/**\n * Talk to an AG-UI 1.0 producer (https://docs.ag-ui.com/spec/1.0) through `useAgentChat`.\n *\n * `agUiChatStream` POSTs a `RunAgentInput` and hands the transport the answer re-framed in this\n * library's stream protocol, so everything built on `useAgentChat` — the transcript, tool activity,\n * generative UI — renders an AG-UI agent unchanged. Put it behind `openChatStream` of any backend:\n *\n * ```ts\n * const backend: AgentBackend = {\n * ...httpBackend,\n * openChatStream: (request) => agUiChatStream(request, { url: '/agent/ag-ui' }),\n * }\n * ```\n *\n * What maps where (the inverse of the producer in `@adonis-agora/agent/ag-ui`):\n * - `TEXT_MESSAGE_*` → `text`; `REASONING_MESSAGE_*` → `reasoning`; `STEP_*` → `step-start` /\n * `step-finish`;\n * - `TOOL_CALL_START` / `ARGS` / `END` → `tool-input-start` / `-delta` / `-available`, with the\n * `toolKind` and `parentId` from `metadata['agora.toolKind']` / `['agora.parentId']` (a call\n * without them is a `read`); `TOOL_CALL_RESULT` → `tool-output` (or `tool-output-error` /\n * `-denied`, from `metadata['agora.outcome']`);\n * - `ACTIVITY_SNAPSHOT` / `ACTIVITY_DELTA` → a `ui` part named `AgUiActivity`, id\n * `activity:<messageId>`, props `{ activityType, content }` — the whole content each time (the\n * delta's JSON Patch applied here), so a repeat replaces the widget in place;\n * - `RUN_ERROR` → the stream's `event: error`; `RUN_FINISHED` → `event: done` (a cancelled\n * outcome writes `cancelled` first). An interrupt outcome whose every interrupt this stream\n * already showed (`agora.approval-requested` / `agora.elicitation`) ends the stream WITHOUT\n * `done`: the run is parked, not over, so the transport re-attaches to it on the native route\n * (`chat/:runId/stream?after=`) and the rest of the run — after the person decides through the\n * native `tool-call` routes — streams into the same message. An interrupt nothing showed (another\n * producer's) becomes a `ui` part named `AgUiInterrupt` carrying it, for the app to render;\n * - the producer's SSE `id:` (the run's own sequence number, which this library's producer writes)\n * is passed on as the cursor the transport re-attaches with; frames of a producer that numbers\n * nothing carry no id, and the transport then does not try to re-attach;\n * - `CUSTOM` events a producer of this family writes (`agora.ui`, `agora.title`, `agora.queue`,\n * `agora.approval-requested` / `-settled`, `agora.elicitation`, `agora.run`) → the frames they\n * stand for; `agora.step-usage` (right after a `STEP_FINISHED`) → that step's `usage`, `costUsd`\n * and `reasoningMs` on its `step-finish`; `agora.action-proposal-decision` → the\n * `data-proposal-decision` part a native decision answers with (`{ threadId, proposalDecision,\n * text }`). Any other `CUSTOM` is ignored, as the protocol requires of a consumer that does not\n * know it.\n *\n * And on the way in: the send's staged `attachments` (`{ mediaId }`) become `file` content parts\n * the producer resolves for the caller, and `regenerate: true` rides `forwardedProps`.\n */\nexport interface AgUiChatStreamOptions {\n /** The producer's endpoint (`POST`, `RunAgentInput` in, `text/event-stream` out). */\n url: string;\n /** Headers for every request (auth, CSRF). Per-request headers from the send win. */\n headers?: Record<string, string>;\n /** Defaults to the global `fetch`, with `credentials: 'same-origin'`. */\n fetch?: typeof fetch;\n /**\n * Shape `forwardedProps` from the send's body. Default: `{ pageContext, agent, model, persona,\n * uiCapabilities, regenerate }` from the body, whichever are present.\n */\n forwardedProps?: (body: Record<string, unknown>) => unknown;\n /** Read the refusal of a non-2xx answer. Default: the JSON body's `message`, else the status. */\n refusal?: (response: Response) => Promise<Error>;\n /**\n * The user message's `content` for the send. Default: the body's `message` as a string — or,\n * when the send carries staged `attachments` (`{ mediaId, contentType? }`, what the composer\n * uploads), a `text` part followed by one `file` part per attachment\n * (`source: { type: 'file', value: <mediaId>, provider: 'nestjs-agent' }`), which this library's\n * producer resolves for the caller. Return your own list of AG-UI content parts to send inline\n * bytes instead — `{ type: 'image' | 'document' | …, source: { type: 'data', value: <base64>,\n * mimeType } }`.\n */\n content?: (body: Record<string, unknown>) => string | AgUiContentPart[];\n}\n\n/** One AG-UI content part of a user message (text, or media by inline data, url or file handle). */\nexport type AgUiContentPart =\n | { type: 'text'; text: string }\n | {\n type: 'image' | 'audio' | 'video' | 'document';\n source:\n | { type: 'data'; value: string; mimeType: string }\n | { type: 'url'; value: string; mimeType?: string }\n | { type: 'file'; value: string; provider?: string; mimeType?: string };\n metadata?: Record<string, unknown>;\n };\n\n/** The ids of an AG-UI run this consumer invented, when the send did not name a thread. */\nfunction newId(): string {\n return globalThis.crypto.randomUUID();\n}\n\nfunction isRecord(value: unknown): value is Record<string, unknown> {\n return typeof value === 'object' && value !== null && !Array.isArray(value);\n}\n\nasync function defaultRefusal(response: Response): Promise<Error> {\n try {\n const body = (await response.json()) as { message?: unknown };\n if (typeof body.message === 'string' && body.message.length > 0) return new Error(body.message);\n } catch {\n // not JSON: fall through to the status\n }\n return new Error(`The agent refused the request (${response.status}).`);\n}\n\nfunction defaultForwardedProps(body: Record<string, unknown>): unknown {\n const out: Record<string, unknown> = {};\n for (const key of ['pageContext', 'agent', 'model', 'persona', 'uiCapabilities']) {\n if (body[key] !== undefined && body[key] !== null) out[key] = body[key];\n }\n // Re-run the last exchange instead of appending one (`useAgentChat`'s regenerate).\n if (body.regenerate === true) out.regenerate = true;\n return Object.keys(out).length > 0 ? out : undefined;\n}\n\n/**\n * The `provider` that marks a `file` part's `value` as a mediaId staged with this library\n * (`AG_UI_MEDIA_PROVIDER` in `@dudousxd/nestjs-agent-core/ag-ui`).\n */\nconst MEDIA_PROVIDER = 'nestjs-agent';\n\nfunction partTypeFor(contentType: string | undefined): 'image' | 'audio' | 'video' | 'document' {\n const major = contentType?.split('/')[0]?.toLowerCase();\n return major === 'image' || major === 'audio' || major === 'video' ? major : 'document';\n}\n\n/** The message text, then one `file` part per staged attachment the send carries. */\nfunction defaultContent(\n body: Record<string, unknown>,\n message: string,\n): string | AgUiContentPart[] {\n const attachments = Array.isArray(body.attachments) ? body.attachments : [];\n const files: AgUiContentPart[] = [];\n for (const attachment of attachments) {\n if (!isRecord(attachment) || typeof attachment.mediaId !== 'string') continue;\n const contentType =\n typeof attachment.contentType === 'string' ? attachment.contentType : undefined;\n files.push({\n type: partTypeFor(contentType),\n source: {\n type: 'file',\n value: attachment.mediaId,\n provider: MEDIA_PROVIDER,\n ...(contentType !== undefined ? { mimeType: contentType } : {}),\n },\n });\n }\n if (files.length === 0) return message;\n return [...(message.length > 0 ? [{ type: 'text' as const, text: message }] : []), ...files];\n}\n\n/** Start a turn against an AG-UI producer; the stream comes back in this library's framing. */\nexport async function agUiChatStream(\n request: ChatStreamRequest,\n options: AgUiChatStreamOptions,\n): Promise<ChatStreamResponse> {\n const body = request.body;\n const threadId = typeof body.threadId === 'string' ? body.threadId : newId();\n const message = typeof body.message === 'string' ? body.message : '';\n const forwarded = (options.forwardedProps ?? defaultForwardedProps)(body);\n const input = {\n threadId,\n runId: newId(),\n protocolVersion: '1.0',\n messages: [\n {\n id: newId(),\n role: 'user',\n content: options.content?.(body) ?? defaultContent(body, message),\n },\n ],\n ...(forwarded !== undefined ? { forwardedProps: forwarded } : {}),\n };\n const doFetch = options.fetch ?? globalThis.fetch.bind(globalThis);\n const response = await doFetch(options.url, {\n method: 'POST',\n credentials: 'same-origin',\n headers: {\n 'content-type': 'application/json',\n accept: 'text/event-stream',\n ...options.headers,\n ...request.headers,\n },\n body: JSON.stringify(input),\n ...(request.signal !== undefined ? { signal: request.signal } : {}),\n });\n if (!response.ok || response.body === null) {\n throw await (options.refusal ?? defaultRefusal)(response);\n }\n const runId = response.headers.get('x-agent-run-id') ?? undefined;\n return {\n body: reframeAgUiStream(response.body, { threadId }),\n threadId,\n ...(runId !== undefined ? { runId } : {}),\n };\n}\n\ntype AgUiEvent = { type: string; [key: string]: unknown };\n\ninterface Reframer {\n /** The frames (already SSE-encoded) one AG-UI event stands for; `id` is its SSE `id:`, if any. */\n push(event: AgUiEvent, id?: number): string;\n /** What is still held back (a step's end waiting for its usage), at the end of the stream. */\n flush(): string;\n /** Set when the run ended; nothing is written after it. */\n closed: boolean;\n}\n\n/**\n * Re-frame an AG-UI event stream (SSE, one event per `data:`) in this library's stream protocol:\n * `event: meta`, `data:` frames of {@link AgentStreamEvent} (numbered with the run's own sequence\n * when the producer numbers its events), then `event: done` or `event: error`. Exported for a backend that fetches the stream itself.\n */\nexport function reframeAgUiStream(\n source: ReadableStream<Uint8Array>,\n ids: { threadId: string },\n): ReadableStream<Uint8Array> {\n const encoder = new TextEncoder();\n const decoder = new TextDecoder();\n const reframer = createReframer(ids.threadId);\n const reader = source.getReader();\n let buffer = '';\n return new ReadableStream<Uint8Array>({\n async pull(controller) {\n for (;;) {\n const { value, done } = await reader.read();\n if (done) {\n // A stream that stopped without a terminal event is a truncated run: end it plainly, and\n // the transport reads the stored thread for the rest.\n const rest = reframer.flush();\n if (rest.length > 0) controller.enqueue(encoder.encode(rest));\n controller.close();\n return;\n }\n buffer += decoder.decode(value, { stream: true }).replace(/\\r\\n?/g, '\\n');\n let out = '';\n let separator = buffer.indexOf('\\n\\n');\n while (separator !== -1) {\n const block = buffer.slice(0, separator);\n buffer = buffer.slice(separator + 2);\n separator = buffer.indexOf('\\n\\n');\n const lines = block.split('\\n');\n const idLine = lines.find((line) => line.startsWith('id:'));\n const id = idLine === undefined ? undefined : Number(idLine.slice(3).trim());\n const data = lines\n .filter((line) => line.startsWith('data:'))\n .map((line) => line.slice(5).trimStart())\n .join('\\n');\n if (data.length === 0) continue;\n let event: unknown;\n try {\n event = JSON.parse(data);\n } catch {\n continue;\n }\n if (isRecord(event) && typeof event.type === 'string') {\n out += reframer.push(\n event as AgUiEvent,\n id !== undefined && Number.isSafeInteger(id) && id > 0 ? id : undefined,\n );\n }\n if (reframer.closed) break;\n }\n if (out.length > 0) controller.enqueue(encoder.encode(out));\n if (reframer.closed) {\n void reader.cancel().catch(() => undefined);\n controller.close();\n return;\n }\n if (out.length > 0) return;\n }\n },\n cancel(reason) {\n return reader.cancel(reason).catch(() => undefined);\n },\n });\n}\n\nfunction createReframer(threadId: string): Reframer {\n const activities = new Map<string, { activityType: string; content: Record<string, unknown> }>();\n let metaSent = false;\n const tools = new Map<\n string,\n { name: string; args: string; toolKind: 'read' | 'action'; parentId?: string }\n >();\n /**\n * A step's end is held until the next event: a producer of this family follows `STEP_FINISHED`\n * with `agora.step-usage`, whose usage, cost and reasoning time belong on that `step-finish`.\n */\n let pendingStep: Record<string, unknown> | undefined;\n const encodeFrame = (streamEvent: AgentStreamEvent | Record<string, unknown>) =>\n `data: ${JSON.stringify(streamEvent)}\\n\\n`;\n const flushStep = (): string => {\n if (pendingStep === undefined) return '';\n const step = pendingStep;\n pendingStep = undefined;\n return encodeFrame(step);\n };\n /**\n * The run's sequence number of the events being read, and the last one written out as a cursor.\n * Several AG-UI events stand for one frame of the run, so the cursor (an `id:`-only SSE block the\n * transport records) moves only once every event of a frame was re-framed — re-attaching\n * `?after=` it then neither skips nor repeats anything.\n */\n let current: number | undefined;\n let written: number | undefined;\n const cursor = (): string => {\n if (current === undefined || current === written) return '';\n written = current;\n return `${flushStep()}id: ${current}\\n\\n`;\n };\n /** The tool calls whose approval or question set this stream already showed. */\n const shown = new Set<string>();\n /** An independent proposal decided with no run: written at the run's end, with its text. */\n let decision: { threadId: unknown; proposalDecision: unknown; text: string } | undefined;\n const state: Reframer = {\n closed: false,\n flush() {\n return state.closed ? '' : `${flushStep()}${cursor()}`;\n },\n push(event, id) {\n if (state.closed) return '';\n let out = '';\n if (id !== undefined) {\n if (current !== undefined && id > current) out += cursor();\n current = id;\n }\n const frame = (streamEvent: AgentStreamEvent | Record<string, unknown>) => {\n out += encodeFrame(streamEvent);\n };\n if (\n event.type === 'CUSTOM' &&\n event.name === 'agora.step-usage' &&\n pendingStep !== undefined &&\n isRecord(event.value)\n ) {\n const value = event.value;\n if (isRecord(value.usage)) pendingStep.usage = value.usage;\n if (typeof value.costUsd === 'number' || value.costUsd === null) {\n pendingStep.costUsd = value.costUsd;\n }\n if (typeof value.reasoningMs === 'number') pendingStep.reasoningMs = value.reasoningMs;\n out += flushStep();\n return out;\n }\n out += flushStep();\n const meta = (runId: unknown, thread: unknown) => {\n if (metaSent) return;\n metaSent = true;\n out += `event: meta\\ndata: ${JSON.stringify({\n runId: typeof runId === 'string' ? runId : '',\n threadId: typeof thread === 'string' ? thread : threadId,\n })}\\n\\n`;\n };\n switch (event.type) {\n case 'RUN_STARTED':\n // `agora.run` (next) names the library's own run; wait a beat for it only if it follows\n // at once — otherwise the protocol's own ids do.\n pendingStart = { runId: event.runId, threadId: event.threadId };\n return out;\n case 'CUSTOM': {\n const value = event.value;\n if (event.name === 'agora.run' && isRecord(value)) {\n meta(value.runId, pendingStart?.threadId ?? value.threadId);\n pendingStart = undefined;\n return out;\n }\n flushStart();\n if (!isRecord(value)) return out;\n if (event.name === 'agora.ui') frame({ kind: 'ui', ...value });\n else if (event.name === 'agora.title' && typeof value.title === 'string') {\n frame({ kind: 'title', title: value.title });\n } else if (event.name === 'agora.queue') frame({ kind: 'queue', ...value });\n else if (event.name === 'agora.approval-requested') {\n if (typeof value.id === 'string') shown.add(value.id);\n frame({ ...value, kind: 'approval-requested' });\n } else if (event.name === 'agora.approval-settled') {\n frame({ ...value, kind: 'approval-settled' });\n } else if (\n event.name === 'agora.elicitation' &&\n typeof value.id === 'string' &&\n isRecord(value.request) &&\n Array.isArray(value.request.questions)\n ) {\n // The question set the run parked on, under the tool-call id an answer settles.\n shown.add(value.id);\n if (typeof value.request.id === 'string') shown.add(value.request.id);\n frame({\n kind: 'elicitation',\n id: value.id,\n request: value.request as unknown as ElicitationRequest,\n });\n } else if (event.name === 'agora.action-proposal-decision') {\n decision = {\n threadId: value.threadId,\n proposalDecision: value.proposalDecision,\n text: '',\n };\n }\n return out;\n }\n default:\n flushStart();\n }\n switch (event.type) {\n case 'TEXT_MESSAGE_CONTENT':\n case 'TEXT_MESSAGE_CHUNK':\n if (decision !== undefined && typeof event.delta === 'string') {\n decision.text += event.delta;\n }\n if (typeof event.delta === 'string' && event.delta.length > 0) {\n frame({ kind: 'text', text: event.delta });\n }\n break;\n case 'REASONING_MESSAGE_CONTENT':\n case 'REASONING_MESSAGE_CHUNK':\n if (typeof event.delta === 'string' && event.delta.length > 0) {\n frame({ kind: 'reasoning', text: event.delta });\n }\n break;\n case 'STEP_STARTED':\n frame({ kind: 'step-start' });\n break;\n case 'STEP_FINISHED':\n pendingStep = { kind: 'step-finish' };\n break;\n case 'TOOL_CALL_START':\n case 'TOOL_CALL_CHUNK': {\n const id = String(event.toolCallId ?? '');\n if (id === '') break;\n if (!tools.has(id)) {\n const name = typeof event.toolCallName === 'string' ? event.toolCallName : '';\n const metadata = isRecord(event.metadata) ? event.metadata : {};\n // A producer of this family says whether the call is an action (it may wait for an\n // approval); a call nobody classified is read-only, as AG-UI has no notion of either.\n const toolKind = metadata['agora.toolKind'] === 'action' ? 'action' : 'read';\n const parentId =\n typeof metadata['agora.parentId'] === 'string'\n ? metadata['agora.parentId']\n : undefined;\n tools.set(id, {\n name,\n args: '',\n toolKind,\n ...(parentId !== undefined ? { parentId } : {}),\n });\n frame({\n kind: 'tool-input-start',\n id,\n name,\n toolKind,\n ...(parentId !== undefined ? { parentId } : {}),\n });\n }\n if (event.type === 'TOOL_CALL_CHUNK' && typeof event.delta === 'string') {\n (tools.get(id) as { args: string }).args += event.delta;\n frame({ kind: 'tool-input-delta', id, delta: event.delta });\n }\n break;\n }\n case 'TOOL_CALL_ARGS': {\n const call = tools.get(String(event.toolCallId));\n if (call === undefined || typeof event.delta !== 'string') break;\n call.args += event.delta;\n frame({ kind: 'tool-input-delta', id: String(event.toolCallId), delta: event.delta });\n break;\n }\n case 'TOOL_CALL_END': {\n const id = String(event.toolCallId);\n const call = tools.get(id);\n if (call === undefined) break;\n frame({\n kind: 'tool-input-available',\n id,\n name: call.name,\n input: parseJson(call.args, {}),\n toolKind: call.toolKind,\n ...(call.parentId !== undefined ? { parentId: call.parentId } : {}),\n });\n break;\n }\n case 'TOOL_CALL_RESULT': {\n const id = String(event.toolCallId);\n const content = contentText(event.content);\n const outcome = isRecord(event.metadata) ? event.metadata['agora.outcome'] : undefined;\n if (outcome === 'error') frame({ kind: 'tool-output-error', id, error: content });\n else if (outcome === 'denied') frame({ kind: 'tool-output-denied', id, reason: content });\n else frame({ kind: 'tool-output', id, output: parseJson(content, content) });\n break;\n }\n case 'ACTIVITY_SNAPSHOT':\n case 'ACTIVITY_DELTA': {\n const messageId = typeof event.messageId === 'string' ? event.messageId : '';\n if (messageId === '') break;\n const known = activities.get(messageId);\n const activityType =\n typeof event.activityType === 'string'\n ? event.activityType\n : (known?.activityType ?? '');\n let content: Record<string, unknown> | undefined;\n if (event.type === 'ACTIVITY_SNAPSHOT') {\n // `replace: false` leaves an existing activity as it stands\n if (known !== undefined && event.replace === false) break;\n content = isRecord(event.content) ? event.content : {};\n } else {\n // a delta for an activity nothing created is skipped, never fatal\n if (known === undefined || !Array.isArray(event.patch)) break;\n content = applyPatch(known.content, event.patch);\n if (content === undefined) break;\n }\n activities.set(messageId, { activityType, content });\n frame({\n kind: 'ui',\n id: `activity:${messageId}`,\n component: 'AgUiActivity',\n props: { activityType, content },\n });\n break;\n }\n case 'RUN_ERROR':\n state.closed = true;\n out += `event: error\\ndata: ${JSON.stringify({\n code: typeof event.code === 'string' ? event.code : 'run_failed',\n message: typeof event.message === 'string' ? event.message : 'The run failed.',\n })}\\n\\n`;\n break;\n case 'RUN_FINISHED': {\n const outcome = isRecord(event.outcome) ? event.outcome : undefined;\n if (decision !== undefined) {\n // What a native decision answers with: a `data-proposal-decision` part.\n frame({ kind: 'proposal-decision', ...decision });\n decision = undefined;\n }\n if (outcome?.type === 'cancelled') frame({ kind: 'cancelled' });\n if (outcome?.type === 'interrupt' && Array.isArray(outcome.interrupts)) {\n const unseen = outcome.interrupts.filter((interrupt) => !isShown(interrupt, shown));\n if (unseen.length === 0) {\n // Parked on what this stream already showed: not over. End without `done`, at the\n // cursor, so the transport re-attaches and follows the rest of the run.\n out += cursor();\n state.closed = true;\n break;\n }\n frame({\n kind: 'ui',\n id: `ag-ui:interrupt:${String(event.runId ?? '')}`,\n component: 'AgUiInterrupt',\n props: { interrupts: unseen },\n });\n }\n out += cursor();\n state.closed = true;\n out += 'event: done\\ndata: {}\\n\\n';\n break;\n }\n default:\n // Everything else (message and span brackets, state, activity, raw) carries nothing this\n // framing does not already say.\n break;\n }\n return out;\n\n function flushStart() {\n if (pendingStart !== undefined) {\n meta(pendingStart.runId, pendingStart.threadId);\n pendingStart = undefined;\n }\n }\n },\n };\n let pendingStart: { runId: unknown; threadId: unknown } | undefined;\n return state;\n}\n\n/** Did the stream already show what this interrupt asks — an approval card or a question form? */\nfunction isShown(interrupt: unknown, shown: ReadonlySet<string>): boolean {\n if (!isRecord(interrupt)) return false;\n if (typeof interrupt.toolCallId === 'string' && shown.has(interrupt.toolCallId)) return true;\n const metadata = isRecord(interrupt.metadata) ? interrupt.metadata : undefined;\n const request = isRecord(metadata?.['agora.request']) ? metadata['agora.request'] : undefined;\n return typeof request?.id === 'string' && shown.has(request.id);\n}\n\nfunction parseJson(text: string, fallback: unknown): unknown {\n if (text.trim().length === 0) return fallback;\n try {\n return JSON.parse(text) as unknown;\n } catch {\n return fallback;\n }\n}\n\n/** A result's content as text: a string, or its text parts in order (other parts carry no text). */\nfunction contentText(content: unknown): string {\n if (typeof content === 'string') return content;\n if (!Array.isArray(content)) return '';\n return content\n .filter((part) => isRecord(part) && part.type === 'text' && typeof part.text === 'string')\n .map((part) => (part as { text: string }).text)\n .join('');\n}\n\n/**\n * RFC 6902 on a copy: `add`, `replace`, `remove` (and `test`, which fails the patch). `undefined`\n * when the patch does not apply — the activity then keeps its last good content until a snapshot.\n */\nfunction applyPatch(\n target: Record<string, unknown>,\n patch: unknown[],\n): Record<string, unknown> | undefined {\n const doc = structuredClone(target) as Record<string, unknown>;\n for (const operation of patch) {\n if (!isRecord(operation) || typeof operation.path !== 'string') return undefined;\n const tokens = operation.path\n .split('/')\n .slice(1)\n .map((token) => token.replace(/~1/g, '/').replace(/~0/g, '~'));\n const key = tokens.pop();\n if (key === undefined) return undefined;\n let parent: unknown = doc;\n for (const token of tokens) {\n parent = Array.isArray(parent)\n ? parent[Number(token)]\n : isRecord(parent)\n ? parent[token]\n : undefined;\n if (parent === undefined) return undefined;\n }\n if (Array.isArray(parent)) {\n const index = key === '-' ? parent.length : Number(key);\n if (!Number.isInteger(index) || index < 0 || index > parent.length) return undefined;\n if (operation.op === 'add') parent.splice(index, 0, operation.value);\n else if (operation.op === 'replace' && index < parent.length) parent[index] = operation.value;\n else if (operation.op === 'remove' && index < parent.length) parent.splice(index, 1);\n else if (operation.op === 'test') {\n if (JSON.stringify(parent[index]) !== JSON.stringify(operation.value)) return undefined;\n } else return undefined;\n } else if (isRecord(parent)) {\n if (operation.op === 'add' || (operation.op === 'replace' && key in parent)) {\n parent[key] = operation.value;\n } else if (operation.op === 'remove' && key in parent) delete parent[key];\n else if (operation.op === 'test') {\n if (JSON.stringify(parent[key]) !== JSON.stringify(operation.value)) return undefined;\n } else return undefined;\n } else return undefined;\n }\n return doc;\n}\n","import type { AgentCatalogEntry, PersonaCatalogEntry } from '@dudousxd/nestjs-agent-core';\nimport { useCallback, useMemo } from 'react';\nimport { type AgentBackend, requireBackendMethod } from '../backend.js';\nimport { useAgentBackend } from '../provider.js';\nimport { useResource } from './use-resource.js';\n\nexport interface UseAgentsOptions {\n /** Default: the enclosing `<AgentProvider>`'s. Must implement `listAgents`. */\n backend?: AgentBackend;\n /** `false` holds the request. Default `true`. */\n enabled?: boolean;\n}\n\nexport interface AgentsState {\n /** `[]` until loaded. */\n agents: AgentCatalogEntry[];\n /** The agent a turn runs as when none is named. */\n defaultAgent: string | null;\n /**\n * An agent's personas — the data behind a persona picker. `agent` omitted → the default agent's.\n * `[]` for an agent that declares none (or before the list loads).\n */\n personasOf: (agent?: string) => PersonaCatalogEntry[];\n /** The persona `agent` (default: the default agent) runs under when a send names none, or `null`. */\n defaultPersonaOf: (agent?: string) => string | null;\n isLoading: boolean;\n error: Error | null;\n refresh: () => Promise<void>;\n}\n\n/**\n * The registered agents (`GET <base>/agents`) — the data behind an agent picker, and each agent's\n * personas behind a persona picker. Send the pick as `useAgentChat({ agent, persona })`, or pin it on\n * a thread with `PATCH <base>/threads/:id { defaultAgent, persona }`.\n */\nexport function useAgents(options: UseAgentsOptions = {}): AgentsState {\n const { enabled = true } = options;\n const backend = useAgentBackend(options.backend);\n const { data, isLoading, error, refresh } = useResource<AgentCatalogEntry[]>(\n () => requireBackendMethod(backend, 'listAgents')(),\n '',\n enabled,\n );\n const find = useCallback(\n (name?: string): AgentCatalogEntry | undefined =>\n (data ?? []).find((agent) =>\n name === undefined ? agent.isDefault === true : agent.name === name,\n ),\n [data],\n );\n return useMemo(() => {\n const agents = data ?? [];\n return {\n agents,\n defaultAgent: agents.find((agent) => agent.isDefault === true)?.name ?? null,\n personasOf: (agent?: string) => find(agent)?.personas ?? [],\n defaultPersonaOf: (agent?: string) => find(agent)?.defaultPersona ?? null,\n isLoading,\n error,\n refresh,\n };\n }, [data, find, isLoading, error, refresh]);\n}\n","import { useCallback, useEffect, useRef, useState } from 'react';\n\nexport interface ResourceState<T> {\n data: T | undefined;\n isLoading: boolean;\n error: Error | null;\n refresh: () => Promise<void>;\n}\n\n/**\n * One read, re-run when `key` changes, with only the newest response allowed to land. The shared\n * shape behind `useModels` / `useAgents`.\n */\nexport function useResource<T>(\n load: () => Promise<T>,\n key: string,\n enabled: boolean,\n): ResourceState<T> {\n const [data, setData] = useState<T | undefined>(undefined);\n const [isLoading, setIsLoading] = useState(enabled);\n const [error, setError] = useState<Error | null>(null);\n const loadRef = useRef(load);\n loadRef.current = load;\n const generation = useRef(0);\n\n const refresh = useCallback(async (): Promise<void> => {\n const mine = ++generation.current;\n setIsLoading(true);\n try {\n const value = await loadRef.current();\n if (mine !== generation.current) return;\n setData(value);\n setError(null);\n } catch (caught) {\n if (mine !== generation.current) return;\n setError(caught instanceof Error ? caught : new Error(String(caught)));\n } finally {\n if (mine === generation.current) setIsLoading(false);\n }\n }, []);\n\n // biome-ignore lint/correctness/useExhaustiveDependencies: `key` names what `load` reads\n useEffect(() => {\n if (!enabled) return;\n void refresh();\n }, [enabled, key, refresh]);\n\n return { data, isLoading, error, refresh };\n}\n","import type {\n ModelCatalogEntry,\n ModelCatalogLock,\n ModelCatalogView,\n} from '@dudousxd/nestjs-agent-core';\nimport { useMemo } from 'react';\nimport { type AgentBackend, requireBackendMethod } from '../backend.js';\nimport { useAgentBackend } from '../provider.js';\nimport { useResource } from './use-resource.js';\n\nexport interface UseModelsOptions {\n /** Default: the enclosing `<AgentProvider>`'s. Must implement `listModels`. */\n backend?: AgentBackend;\n /** The agent to list models for; omitted → the default agent. */\n agent?: string;\n /** `false` holds the request. Default `true`. */\n enabled?: boolean;\n}\n\n/** A catalog entry with the provider it sits under, for a flat list or a search. */\nexport interface ModelOption extends ModelCatalogEntry {\n providerId: string;\n providerLabel: string;\n}\n\nexport interface ModelsState {\n /** Grouped as the server sent them. `[]` until loaded. */\n providers: ModelCatalogView['providers'];\n /** Every model, flattened in provider order. */\n models: ModelOption[];\n /** The model a turn runs on when none is picked, or `null` when the provider decides. */\n defaultModel: string | null;\n /**\n * The agent always runs on one model (`{ model, reason? }`), or `null`. A picker shows it\n * read-only: the server runs every turn on it and refuses any other.\n */\n locked: ModelCatalogLock | null;\n /** The entry for `id`, or `undefined`. */\n find: (id: string | null | undefined) => ModelOption | undefined;\n isLoading: boolean;\n error: Error | null;\n refresh: () => Promise<void>;\n}\n\n/**\n * The models this caller may pick (`GET <base>/models?agent=`), with badges and availability — the\n * data behind a model picker. Headless: render the options however you like, then send the pick\n * as `useAgentChat({ model })` or `sendMessage(msg, { body: { model } })` (that turn only), or\n * pin it on the thread with `chat.models.pinToThread(id)`.\n */\nexport function useModels(options: UseModelsOptions = {}): ModelsState {\n const { agent, enabled = true } = options;\n const backend = useAgentBackend(options.backend);\n const { data, isLoading, error, refresh } = useResource<ModelCatalogView>(\n () => requireBackendMethod(backend, 'listModels')(agent),\n `${agent ?? ''}`,\n enabled,\n );\n return useMemo(() => {\n const providers = data?.providers ?? [];\n const models = providers.flatMap((provider) =>\n provider.models.map((model) => ({\n ...model,\n providerId: provider.id,\n providerLabel: provider.label,\n })),\n );\n const byId = new Map(models.map((model) => [model.id, model]));\n return {\n providers,\n models,\n defaultModel: data?.default ?? null,\n locked: data?.locked ?? null,\n find: (id) => (id == null ? undefined : byId.get(id)),\n isLoading,\n error,\n refresh,\n };\n }, [data, isLoading, error, refresh]);\n}\n","import {\n type QuotaBlock,\n type QuotaReport,\n type QuotaWarning,\n type QuotaWindow,\n quotaWarning,\n} from '@dudousxd/nestjs-agent-core';\nimport { useEffect, useMemo } from 'react';\nimport { type AgentBackend, requireBackendMethod } from '../backend.js';\nimport { useResource } from '../catalog/use-resource.js';\nimport { useAgentBackend } from '../provider.js';\nimport { onThreadsEvent } from '../threads/threads-events.js';\n\nexport interface UseQuotaOptions {\n /** Default: the enclosing `<AgentProvider>`'s. Must implement `getQuota`. */\n backend?: AgentBackend;\n /** `false` holds the request. Default `true`. */\n enabled?: boolean;\n /** Re-read every `pollMs` ms as well. Default: only on mount, after runs, and on `refresh`. */\n pollMs?: number;\n}\n\nexport interface QuotaState {\n /** The full report, once loaded. */\n report: QuotaReport | undefined;\n windows: QuotaWindow[];\n /** The `day` / `month` windows, when the server reports them. */\n day: QuotaWindow | undefined;\n month: QuotaWindow | undefined;\n /** The window that blocks sends, or `null` — pass it to `useAgentChat({ blocked })`. */\n blocked: QuotaBlock | null;\n /**\n * The soft limit: the fullest window past its `warnAt` (`{ period, ratio, reason? }`), or `null`.\n * The server's `warning`, else derived from the windows; never set while `blocked`.\n */\n warning: QuotaWarning | null;\n isLoading: boolean;\n error: Error | null;\n refresh: () => Promise<void>;\n}\n\n/**\n * The caller's budget (`GET <base>/quota`): every window's usage against its ceilings, and which\n * one — if any — blocks sends. Re-read after every run a chat on the same backend settles, so a\n * meter moves with the conversation. Headless: draw the meter yourself.\n */\nexport function useQuota(options: UseQuotaOptions = {}): QuotaState {\n const { enabled = true, pollMs } = options;\n const backend = useAgentBackend(options.backend);\n const { data, isLoading, error, refresh } = useResource<QuotaReport>(\n () => requireBackendMethod(backend, 'getQuota')(),\n '',\n enabled,\n );\n\n useEffect(() => {\n if (!enabled) return;\n return onThreadsEvent(backend, (event) => {\n if (event.type === 'changed') void refresh();\n });\n }, [backend, enabled, refresh]);\n\n useEffect(() => {\n if (!enabled || pollMs === undefined || pollMs <= 0) return;\n const timer = setInterval(() => void refresh(), pollMs);\n return () => clearInterval(timer);\n }, [enabled, pollMs, refresh]);\n\n return useMemo(() => {\n const windows = data?.windows ?? [];\n return {\n report: data,\n windows,\n day: windows.find((window) => window.period === 'day'),\n month: windows.find((window) => window.period === 'month'),\n blocked: data?.blocked ?? null,\n warning:\n data === undefined || data.blocked !== undefined\n ? null\n : (data.warning ?? quotaWarning(windows) ?? null),\n isLoading,\n error,\n refresh,\n };\n }, [data, isLoading, error, refresh]);\n}\n","import type { AgentBackend } from '../backend.js';\n\n/**\n * What changed about a backend's thread list. `changed` → refetch (a thread was created, or a run\n * settled and the server wrote its title); `title` → the stream announced a title, patch in place.\n */\nexport type ThreadsEvent =\n | { type: 'changed' }\n | { type: 'title'; threadId: string; title: string }\n | { type: 'removed'; threadId: string };\n\ntype Listener = (event: ThreadsEvent) => void;\n\n// Keyed by backend so two chats on two servers never refresh each other's sidebars.\nconst listeners = new WeakMap<AgentBackend, Set<Listener>>();\n\n/** Tell every {@link useThreads} on `backend` that its list moved. */\nexport function notifyThreads(backend: AgentBackend, event: ThreadsEvent): void {\n for (const listener of listeners.get(backend) ?? []) {\n listener(event);\n }\n}\n\n/** Subscribe to {@link notifyThreads} for `backend`; returns the unsubscribe. */\nexport function onThreadsEvent(backend: AgentBackend, listener: Listener): () => void {\n let set = listeners.get(backend);\n if (set === undefined) {\n set = new Set();\n listeners.set(backend, set);\n }\n set.add(listener);\n return () => {\n set.delete(listener);\n };\n}\n","import type { MessageFeedback, MessageFeedbackValue } from '@dudousxd/nestjs-agent-core';\nimport type { UIMessage } from 'ai';\nimport { useCallback, useRef, useState } from 'react';\nimport { type AgentBackend, requireBackendMethod } from '../backend.js';\nimport { useAgentBackend } from '../provider.js';\nimport type { AgentMessageMetadata } from '../stored-thread-to-ui-messages.js';\n\nexport interface UseMessageFeedbackOptions {\n /** Default: the enclosing `<AgentProvider>`'s. Must implement `setMessageFeedback`. */\n backend?: AgentBackend;\n /**\n * The thread the messages belong to — `useAgentChat(...).getThreadId`, or an id. Needed to rate a\n * message streamed in this session: its id is the client's own, so the persisted row it became is\n * looked up by the run that wrote it.\n */\n threadId?: string | (() => string | undefined);\n}\n\nexport interface MessageFeedbackState {\n /** The rating to show: the one set in this session, else the persisted one, else `null`. */\n feedbackOf: (message: UIMessage) => MessageFeedback | null;\n /** A rating for this message is on its way to the server. */\n isPending: (message: UIMessage) => boolean;\n /** Set `'up'`/`'down'` (optionally with a comment), or clear with `null`. Optimistic. */\n rate: (message: UIMessage, value: MessageFeedbackValue | null, comment?: string) => Promise<void>;\n /** Thumbs-button semantics: the same value again clears it, another value replaces it. */\n toggle: (message: UIMessage, value: MessageFeedbackValue) => Promise<void>;\n /** The last failure; cleared by the next successful rating. */\n error: Error | null;\n}\n\ntype Local = { feedback: MessageFeedback | null };\n\n/**\n * Thumbs-up/down (+ comment) on assistant messages, over `POST <base>/messages/:id/feedback`.\n * Headless: it holds the state and the calls, the host draws the buttons. A rating shows at once\n * and rolls back if the server refuses it.\n */\nexport function useMessageFeedback(options: UseMessageFeedbackOptions = {}): MessageFeedbackState {\n const backend = useAgentBackend(options.backend);\n const latest = useRef({ ...options, backend });\n latest.current = { ...options, backend };\n const [local, setLocal] = useState<ReadonlyMap<string, Local>>(new Map());\n const [pending, setPending] = useState<ReadonlySet<string>>(new Set());\n const [error, setError] = useState<Error | null>(null);\n const localRef = useRef(local);\n localRef.current = local;\n // Live message id → the persisted row it resolved to, so a message is looked up once.\n const resolved = useRef(new Map<string, string>());\n\n const feedbackOf = useCallback(\n (message: UIMessage): MessageFeedback | null => {\n const mine = local.get(message.id);\n if (mine !== undefined) return mine.feedback;\n return metadataOf(message).feedback ?? null;\n },\n [local],\n );\n\n const isPending = useCallback((message: UIMessage) => pending.has(message.id), [pending]);\n\n const storedIdFor = useCallback(async (message: UIMessage): Promise<string> => {\n const runId = metadataOf(message).runId;\n if (runId === undefined) return message.id;\n const known = resolved.current.get(message.id);\n if (known !== undefined) return known;\n const { backend, threadId } = latest.current;\n const thread = typeof threadId === 'function' ? threadId() : threadId;\n if (thread === undefined) {\n throw new Error('useMessageFeedback: a streamed message needs `threadId` to be rated');\n }\n const detail = await backend.getThread(thread);\n const row = [...detail.messages]\n .reverse()\n .find((candidate) => candidate.role === 'assistant' && candidate.runId === runId);\n if (row === undefined) {\n throw new Error(`useMessageFeedback: run ${runId} has no persisted answer yet`);\n }\n resolved.current.set(message.id, row.id);\n return row.id;\n }, []);\n\n const rate = useCallback(\n async (message: UIMessage, value: MessageFeedbackValue | null, comment?: string) => {\n const setFeedback = requireBackendMethod(latest.current.backend, 'setMessageFeedback');\n const had = localRef.current.get(message.id);\n const optimistic: MessageFeedback | null =\n value === null\n ? null\n : {\n value,\n ...(comment !== undefined && comment.trim().length > 0\n ? { comment: comment.trim() }\n : {}),\n updatedAt: new Date().toISOString(),\n };\n setLocal((current) => new Map(current).set(message.id, { feedback: optimistic }));\n setPending((current) => new Set(current).add(message.id));\n try {\n const storedId = await storedIdFor(message);\n const { feedback } = await setFeedback(storedId, {\n value,\n ...(comment !== undefined ? { comment } : {}),\n });\n setLocal((current) => new Map(current).set(message.id, { feedback }));\n setError(null);\n } catch (caught) {\n setLocal((current) => {\n const next = new Map(current);\n if (had === undefined) next.delete(message.id);\n else next.set(message.id, had);\n return next;\n });\n const failure = caught instanceof Error ? caught : new Error(String(caught));\n setError(failure);\n throw failure;\n } finally {\n setPending((current) => {\n const next = new Set(current);\n next.delete(message.id);\n return next;\n });\n }\n },\n [storedIdFor],\n );\n\n const toggle = useCallback(\n (message: UIMessage, value: MessageFeedbackValue) => {\n const mine = localRef.current.get(message.id);\n const current = mine !== undefined ? mine.feedback : (metadataOf(message).feedback ?? null);\n return rate(message, current?.value === value ? null : value);\n },\n [rate],\n );\n\n return { feedbackOf, isPending, rate, toggle, error };\n}\n\nfunction metadataOf(message: UIMessage): AgentMessageMetadata {\n const metadata = message.metadata;\n return metadata !== null && typeof metadata === 'object'\n ? (metadata as AgentMessageMetadata)\n : {};\n}\n","import type { ThreadSummary } from '@dudousxd/nestjs-agent-core';\nimport { useCallback, useEffect, useRef, useState } from 'react';\nimport type { AgentBackend } from '../backend.js';\nimport { useAgentBackend } from '../provider.js';\nimport { notifyThreads, onThreadsEvent } from './threads-events.js';\n\nexport interface UseThreadsOptions {\n /**\n * The backend to list. Default: the enclosing `<AgentProvider>`'s. Must be STABLE across renders:\n * the list refreshes itself when a chat on the SAME backend creates a thread, settles a run or\n * streams a title.\n */\n backend?: AgentBackend;\n /** `false` holds the first request (e.g. until the user is signed in). Default `true`. */\n enabled?: boolean;\n}\n\nexport interface ThreadsState {\n /** Newest first, as the server orders them. `[]` until loaded. */\n threads: ThreadSummary[];\n isLoading: boolean;\n error: Error | null;\n /** Ask the server again. */\n refresh: () => Promise<void>;\n /** Rename on the server; the list shows the new title at once and rolls back on failure. */\n rename: (id: string, title: string) => Promise<void>;\n /** Delete on the server; the thread leaves the list at once and comes back on failure. */\n remove: (id: string) => Promise<void>;\n}\n\n/**\n * The actor's conversations, kept current without the host wiring refetches: a chat on the same\n * backend reports thread creation and settled runs (refetch) and streamed titles (patched in\n * place). Headless — it renders nothing.\n */\nexport function useThreads(options: UseThreadsOptions = {}): ThreadsState {\n const { enabled = true } = options;\n const backend = useAgentBackend(options.backend);\n const [threads, setThreads] = useState<ThreadSummary[]>([]);\n const [isLoading, setIsLoading] = useState(enabled);\n const [error, setError] = useState<Error | null>(null);\n const threadsRef = useRef(threads);\n threadsRef.current = threads;\n // Only the newest request may write: a slow response must not overwrite a newer one.\n const generation = useRef(0);\n\n const refresh = useCallback(async (): Promise<void> => {\n const mine = ++generation.current;\n setIsLoading(true);\n try {\n const list = await backend.listThreads();\n if (mine !== generation.current) return;\n setThreads(list);\n setError(null);\n } catch (caught) {\n if (mine !== generation.current) return;\n setError(caught instanceof Error ? caught : new Error(String(caught)));\n } finally {\n if (mine === generation.current) setIsLoading(false);\n }\n }, [backend]);\n\n useEffect(() => {\n if (!enabled) return;\n void refresh();\n return onThreadsEvent(backend, (event) => {\n if (event.type === 'title') {\n setThreads((current) =>\n current.map((thread) =>\n thread.id === event.threadId ? { ...thread, title: event.title } : thread,\n ),\n );\n } else if (event.type === 'removed') {\n setThreads((current) => current.filter((thread) => thread.id !== event.threadId));\n } else {\n void refresh();\n }\n });\n }, [backend, enabled, refresh]);\n\n const rename = useCallback(\n async (id: string, title: string): Promise<void> => {\n const before = threadsRef.current;\n setThreads((current) =>\n current.map((thread) => (thread.id === id ? { ...thread, title } : thread)),\n );\n try {\n await backend.updateThread(id, { title });\n notifyThreads(backend, { type: 'title', threadId: id, title });\n } catch (caught) {\n setThreads(before);\n throw caught;\n }\n },\n [backend],\n );\n\n const remove = useCallback(\n async (id: string): Promise<void> => {\n const before = threadsRef.current;\n setThreads((current) => current.filter((thread) => thread.id !== id));\n try {\n await backend.deleteThread(id);\n notifyThreads(backend, { type: 'removed', threadId: id });\n } catch (caught) {\n setThreads(before);\n throw caught;\n }\n },\n [backend],\n );\n\n return { threads, isLoading, error, refresh, rename, remove };\n}\n","import type { StoredMessage } from '@dudousxd/nestjs-agent-core';\n\n/**\n * A sub-agent the conversation started and did not wait for. The chat is free while it works, so a\n * client has to be able to say what is still running and to show the answer when it lands — neither\n * of which the turn that started it can report, because that turn is over.\n */\nexport interface BackgroundRun {\n /** The run doing the work. Also what stamps the message it eventually posts. */\n runId: string;\n /** The agent working on it. */\n agent: string;\n /** The `agent`-kind call that started it — what a UI keys its card off. */\n toolCallId: string;\n toolName: string;\n /**\n * `delivered` the moment the thread holds a message stamped with this run. A run that FAILED\n * reads as delivered too: it posts a message saying so, which is the point — there is no third\n * state a reader could act on differently, and \"running\" for ever is the state to avoid.\n */\n status: 'running' | 'delivered';\n /** The message it posted, once it did. */\n message?: StoredMessage;\n}\n\n/** A detached delegation's receipt, as it appears in a message's `toolResults`. */\ninterface Receipt {\n detached: true;\n status: 'started';\n agent: string;\n runId: string;\n}\n\nfunction asReceipt(output: unknown): Receipt | null {\n if (typeof output !== 'object' || output === null) {\n return null;\n }\n const candidate = output as Partial<Receipt>;\n if (\n candidate.detached !== true ||\n candidate.status !== 'started' ||\n typeof candidate.agent !== 'string' ||\n typeof candidate.runId !== 'string'\n ) {\n return null;\n }\n return { detached: true, status: 'started', agent: candidate.agent, runId: candidate.runId };\n}\n\n/**\n * Every sub-agent this thread started in the background, and whether each has reported back.\n *\n * Derived from the transcript rather than tracked in session state, so it survives a reload and a\n * second tab: the receipt is a persisted tool result, and the answer is a persisted message stamped\n * with the run that wrote it. Nothing here needs a live connection to be true.\n */\nexport function backgroundRunsFromThread(messages: readonly StoredMessage[]): BackgroundRun[] {\n const byRun = new Map<string, BackgroundRun>();\n for (const message of messages) {\n for (const result of message.toolResults ?? []) {\n const receipt = asReceipt(result.output);\n if (receipt === null || byRun.has(receipt.runId)) {\n continue;\n }\n byRun.set(receipt.runId, {\n runId: receipt.runId,\n agent: receipt.agent,\n toolCallId: result.id,\n toolName: result.name,\n status: 'running',\n });\n }\n }\n for (const message of messages) {\n const run = message.runId === undefined ? undefined : byRun.get(message.runId);\n if (run !== undefined) {\n run.status = 'delivered';\n run.message = message;\n }\n }\n return [...byRun.values()];\n}\n","import React, { useEffect, useState } from 'react';\nimport { useSpeechRecognition } from './use-speech-recognition.js';\n\nexport interface ChatInputProps {\n onSubmit: (text: string) => void;\n disabled?: boolean;\n placeholder?: string;\n rows?: number;\n /** Enable the dictation mic button (Web Speech API). Default `true`. */\n enableSpeech?: boolean;\n /** BCP-47 locale for dictation. Default `en-US`. */\n speechLang?: string;\n /** Label/content for the send button. Default `\"Send\"`. */\n sendLabel?: React.ReactNode;\n /**\n * Cancel the turn in flight — wire to `useAgentChat`'s `cancel`. Rendered only alongside\n * `isStreaming`, so the affordance exists exactly while there is something to cancel.\n */\n onStop?: () => void | Promise<void>;\n /** Whether a turn is currently in flight. Gates the stop affordance. */\n isStreaming?: boolean;\n /** Label/content for the stop button. Default `\"Stop generating\"` — the mic's own is `\"Stop\"`. */\n stopLabel?: React.ReactNode;\n /** Wrapper class. The component ships no styles of its own. */\n className?: string;\n textareaClassName?: string;\n sendButtonClassName?: string;\n micButtonClassName?: string;\n stopButtonClassName?: string;\n /**\n * Custom mic affordance. Receives `isListening`; return any node. When\n * omitted a plain text button (\"Speak\" / \"Stop\") is rendered.\n */\n renderMic?: (state: { isListening: boolean }) => React.ReactNode;\n}\n\n/**\n * Styling-agnostic chat composer. Enter submits, Shift+Enter inserts a\n * newline. Optional dictation streams interim transcripts into the draft\n * and commits finalized chunks, and `onStop` surfaces the backend's\n * cancel next to send. No design-system or icon-library deps —\n * style it entirely through the `*ClassName` props.\n */\nexport function ChatInput({\n onSubmit,\n disabled,\n placeholder,\n rows = 2,\n enableSpeech = true,\n speechLang = 'en-US',\n sendLabel = 'Send',\n onStop,\n isStreaming = false,\n stopLabel = 'Stop generating',\n className,\n textareaClassName,\n sendButtonClassName,\n micButtonClassName,\n stopButtonClassName,\n renderMic,\n}: ChatInputProps) {\n const [value, setValue] = useState('');\n // Interim dictation transcript shown appended to the draft until the\n // engine finalizes it — kept out of `value` so editing the rest of the\n // text doesn't persist a partial guess.\n const [interim, setInterim] = useState('');\n\n const speech = useSpeechRecognition({\n lang: speechLang,\n onFinalTranscript: (text) => {\n const trimmed = text.trim();\n if (!trimmed) return;\n setValue((prev) => (prev.length === 0 ? trimmed : `${prev.trimEnd()} ${trimmed}`));\n setInterim('');\n },\n onInterimTranscript: (text) => setInterim(text),\n });\n\n useEffect(() => {\n if (!speech.isListening) setInterim('');\n }, [speech.isListening]);\n\n function submit() {\n const trimmed = value.trim();\n if (!trimmed) return;\n onSubmit(trimmed);\n setValue('');\n setInterim('');\n }\n\n function handleKeyDown(event: React.KeyboardEvent<HTMLTextAreaElement>) {\n if (event.key === 'Enter' && !event.shiftKey) {\n event.preventDefault();\n submit();\n }\n }\n\n function toggleMic() {\n if (speech.isListening) speech.stop();\n else speech.start();\n }\n\n const displayValue =\n speech.isListening && interim\n ? `${value}${value && !value.endsWith(' ') ? ' ' : ''}${interim}`\n : value;\n\n const showMic = enableSpeech && speech.isSupported;\n const showStop = isStreaming && onStop !== undefined;\n\n return (\n <div className={className}>\n <textarea\n className={textareaClassName}\n rows={rows}\n value={displayValue}\n disabled={disabled}\n onChange={(event) => {\n // Ignore changes while interim text is injected — the engine\n // overwrites it on the next result. Editing works when idle.\n if (speech.isListening && interim) return;\n setValue(event.target.value);\n }}\n onKeyDown={handleKeyDown}\n placeholder={placeholder ?? 'Ask something (Enter to send, Shift+Enter for newline)'}\n />\n <button\n type=\"button\"\n className={sendButtonClassName}\n onClick={submit}\n disabled={disabled || !value.trim()}\n >\n {sendLabel}\n </button>\n {showStop ? (\n <button\n type=\"button\"\n className={stopButtonClassName}\n onClick={() => void onStop()}\n aria-label=\"Stop generating\"\n >\n {stopLabel}\n </button>\n ) : null}\n {showMic ? (\n <button\n type=\"button\"\n className={micButtonClassName}\n onClick={toggleMic}\n disabled={disabled}\n aria-label={speech.isListening ? 'Stop dictating' : 'Start dictating'}\n >\n {renderMic\n ? renderMic({ isListening: speech.isListening })\n : speech.isListening\n ? 'Stop'\n : 'Speak'}\n </button>\n ) : null}\n </div>\n );\n}\n","import { useCallback, useEffect, useMemo, useRef, useState } from 'react';\n\n/**\n * Minimal subset of the Web Speech API we use. The real types live\n * behind `webkit*` prefixes in some browsers and aren't in TS lib.dom,\n * so we declare just what we need.\n */\ninterface SpeechResultAlternative {\n transcript: string;\n}\ninterface SpeechRecognitionResult {\n readonly length: number;\n readonly isFinal: boolean;\n item(index: number): SpeechResultAlternative;\n [index: number]: SpeechResultAlternative;\n}\ninterface SpeechRecognitionResultList {\n readonly length: number;\n item(index: number): SpeechRecognitionResult;\n [index: number]: SpeechRecognitionResult;\n}\ninterface SpeechRecognitionEvent {\n results: SpeechRecognitionResultList;\n resultIndex: number;\n}\ninterface SpeechRecognitionErrorEvent {\n error: string;\n}\ninterface SpeechRecognitionInstance {\n lang: string;\n continuous: boolean;\n interimResults: boolean;\n onresult: ((event: SpeechRecognitionEvent) => void) | null;\n onerror: ((event: SpeechRecognitionErrorEvent) => void) | null;\n onend: (() => void) | null;\n start(): void;\n stop(): void;\n}\ntype SpeechRecognitionCtor = new () => SpeechRecognitionInstance;\n\nfunction getRecognitionCtor(): SpeechRecognitionCtor | null {\n if (typeof window === 'undefined') return null;\n const scope = window as unknown as {\n SpeechRecognition?: SpeechRecognitionCtor;\n webkitSpeechRecognition?: SpeechRecognitionCtor;\n };\n return scope.SpeechRecognition ?? scope.webkitSpeechRecognition ?? null;\n}\n\nexport interface UseSpeechRecognitionOptions {\n lang?: string;\n onFinalTranscript: (text: string) => void;\n onInterimTranscript?: (text: string) => void;\n}\n\nexport interface SpeechRecognitionHook {\n isSupported: boolean;\n isListening: boolean;\n start(): void;\n stop(): void;\n}\n\n/**\n * Tiny wrapper around the Web Speech API. `start()` opens the mic and\n * streams interim transcripts via `onInterimTranscript`; on a finalized\n * chunk it fires `onFinalTranscript`. `isSupported` is false where the\n * API is missing (e.g. Firefox) — callers should hide the mic button.\n */\nexport function useSpeechRecognition({\n lang = 'en-US',\n onFinalTranscript,\n onInterimTranscript,\n}: UseSpeechRecognitionOptions): SpeechRecognitionHook {\n const recognitionRef = useRef<SpeechRecognitionInstance | null>(null);\n const [isListening, setIsListening] = useState(false);\n\n const ctor = useMemo(() => getRecognitionCtor(), []);\n const isSupported = ctor !== null;\n\n // Keep latest callbacks in refs so we don't tear down the recognition\n // object when they change identity each render.\n const finalRef = useRef(onFinalTranscript);\n const interimRef = useRef(onInterimTranscript);\n finalRef.current = onFinalTranscript;\n interimRef.current = onInterimTranscript;\n\n useEffect(() => {\n if (!ctor) return;\n const recognition = new ctor();\n recognition.lang = lang;\n recognition.continuous = false;\n recognition.interimResults = true;\n\n recognition.onresult = (event) => {\n let interim = '';\n for (let i = event.resultIndex; i < event.results.length; i++) {\n const result = event.results[i];\n if (!result) continue;\n const text = result[0]?.transcript ?? '';\n if (result.isFinal) {\n finalRef.current(text);\n } else {\n interim += text;\n }\n }\n if (interim && interimRef.current) interimRef.current(interim);\n };\n recognition.onerror = (event) => {\n if (event.error !== 'no-speech' && event.error !== 'aborted') {\n console.warn('SpeechRecognition error', event.error);\n }\n setIsListening(false);\n };\n recognition.onend = () => setIsListening(false);\n\n recognitionRef.current = recognition;\n return () => {\n try {\n recognition.stop();\n } catch {\n /* engine already stopped */\n }\n recognitionRef.current = null;\n };\n }, [ctor, lang]);\n\n const start = useCallback(() => {\n const recognition = recognitionRef.current;\n if (!recognition) return;\n try {\n recognition.start();\n setIsListening(true);\n } catch (error) {\n console.warn('SpeechRecognition start failed', error);\n }\n }, []);\n\n const stop = useCallback(() => {\n const recognition = recognitionRef.current;\n if (!recognition) return;\n try {\n recognition.stop();\n } catch {\n /* already stopped */\n }\n }, []);\n\n return { isSupported, isListening, start, stop };\n}\n","import type { UIMessage } from 'ai';\nimport React from 'react';\nimport type {\n AnyToolUIPart,\n MessageUsageInfo,\n TranscriptBlock,\n TranscriptFile,\n TranscriptUiBlock,\n} from '../transcript/model.js';\nimport {\n type EditSubmitInput,\n type MessageActionInput,\n type TranscriptItem,\n useTranscriptItem,\n} from '../transcript/use-chat-transcript.js';\nimport { useAmbientRenderUi } from './ambient-ui.js';\n\nexport type { AnyToolUIPart, MessageUsageInfo } from '../transcript/model.js';\nexport { formatRelativeTime } from '../transcript/model.js';\n\nexport type RenderToolPartFn = (part: AnyToolUIPart, key: string) => React.ReactNode;\n\n/** Render a run of consecutive tool parts as one block (e.g. a collapsible tool group). */\nexport type RenderToolGroupFn = (parts: AnyToolUIPart[], key: string) => React.ReactNode;\n\n/** Render a message's text — pass a markdown renderer (e.g. `AgentMarkdown`) here if desired. */\nexport type RenderTextFn = (text: string, ctx: { isStreaming: boolean }) => React.ReactNode;\n\n/** Render a run of files — attachments on a user turn, or files the model produced. */\nexport type RenderFilesFn = (files: TranscriptFile[]) => React.ReactNode;\n\n/**\n * Render a component the server pushed into the message — look `block.component` up in your own\n * registry. Omitted → drawn by the enclosing `<GenuiProvider>` (`/genui`) if there is one, else not\n * drawn (there is no sensible default for an app's own component).\n */\nexport type RenderUiFn = (block: TranscriptUiBlock) => React.ReactNode;\n\n/** Render the body of a reasoning run; the disclosure toggle around it stays this component's. */\nexport type RenderReasoningFn = (\n text: string,\n ctx: { isStreaming: boolean; isOpen: boolean },\n) => React.ReactNode;\n\nexport interface MessageItemClassNames {\n root?: string;\n /** Resolved per role so user/assistant/system bubbles can differ. */\n byRole?: Partial<Record<UIMessage['role'], string>>;\n text?: string;\n /** The action row under the bubble (copy / fork / regenerate / usage / timestamp). */\n actions?: string;\n actionButton?: string;\n usage?: string;\n timestamp?: string;\n editTextarea?: string;\n editActions?: string;\n reasoning?: string;\n reasoningToggle?: string;\n reasoningText?: string;\n files?: string;\n file?: string;\n fileImage?: string;\n}\n\ninterface MessageRenderSlots {\n renderToolPart?: RenderToolPartFn;\n /** Takes precedence over `renderToolPart` for a run of consecutive tool parts. */\n renderToolGroup?: RenderToolGroupFn;\n renderText?: RenderTextFn;\n renderReasoning?: RenderReasoningFn;\n /** Draw files yourself — a gallery, a viewer. Omitted → images inline, everything else a link. */\n renderFiles?: RenderFilesFn;\n /**\n * Draw a server-pushed component (a `ui` stream frame). Omitted → the enclosing `<GenuiProvider>`\n * draws it; without one, not drawn.\n */\n renderUi?: RenderUiFn;\n /**\n * Extra content for the action row, after the built-in affordances and before usage — a badge\n * naming which agent answered, a status pill. Rendered for every message that has an action row.\n */\n meta?: React.ReactNode;\n /** Label on the reasoning disclosure toggle. Default `\"Reasoning\"`. */\n reasoningLabel?: React.ReactNode;\n classNames?: MessageItemClassNames;\n}\n\nexport interface MessageItemProps extends MessageRenderSlots {\n message: UIMessage;\n /** Marks the in-flight assistant bubble (e.g. for a caret animation / deferred markdown render). */\n isStreaming?: boolean;\n /** User bubble gets a pencil → inline textarea; submitting calls back with the new text. */\n editable?: boolean;\n onEditSubmit?: (input: EditSubmitInput) => void | Promise<void>;\n /** Assistant bubble gets a \"Regenerate\" affordance. */\n regeneratable?: boolean;\n onRegenerate?: (input: MessageActionInput) => void | Promise<void>;\n /** When provided, a \"Fork\" affordance calls back with this message's id. */\n onFork?: (input: MessageActionInput) => void | Promise<void>;\n /** Server-aggregated usage for this assistant turn (cost + tokens line). */\n usage?: MessageUsageInfo | null;\n /** ISO timestamp of the persisted message; rendered as a relative-time line when set. */\n createdAt?: string | null;\n}\n\nexport interface MessageItemViewProps extends MessageRenderSlots {\n item: TranscriptItem;\n}\n\n/**\n * Styling-agnostic renderer for a single v7 `UIMessage`. Ports flip's full chat-item UX —\n * copy, fork, regenerate, inline edit-and-resubmit, collapsible reasoning, usage line, relative\n * timestamp, and tool grouping — but with ALL styling left to `classNames` and every action\n * surfaced as a callback, so no design-system / icon / date library is pulled in (relative time\n * uses Intl.RelativeTimeFormat).\n *\n * All of the logic lives in `useTranscriptItem`; this is one rendering of it. An app that wants\n * different markup drives that hook and writes its own.\n */\nexport function MessageItem({\n message,\n isStreaming = false,\n editable,\n onEditSubmit,\n regeneratable,\n onRegenerate,\n onFork,\n usage,\n createdAt,\n ...slots\n}: MessageItemProps) {\n const item = useTranscriptItem({\n message,\n isStreaming,\n ...(editable !== undefined ? { editable } : {}),\n ...(onEditSubmit ? { onEditSubmit } : {}),\n ...(onFork ? { onFork } : {}),\n ...(regeneratable !== undefined ? { regeneratable } : {}),\n ...(onRegenerate ? { onRegenerate } : {}),\n ...(usage != null ? { getUsage: () => usage } : {}),\n ...(createdAt != null ? { getCreatedAt: () => createdAt } : {}),\n });\n return <MessageItemView item={item} {...slots} />;\n}\n\n/** The default markup for one modelled message — what `MessageItem` renders once it has an item. */\nexport function MessageItemView({ item, ...given }: MessageItemViewProps) {\n // Inside a `<GenuiProvider>`, pushed components draw without a `renderUi` of their own.\n const ambientRenderUi = useAmbientRenderUi();\n const slots: MessageRenderSlots =\n given.renderUi === undefined && ambientRenderUi !== null\n ? { ...given, renderUi: ambientRenderUi }\n : given;\n const { classNames } = slots;\n const actionRow = (\n <div className={classNames?.actions} data-actions-for={item.role}>\n {item.copy.available ? (\n <button\n type=\"button\"\n onClick={item.copy.copy}\n className={classNames?.actionButton}\n title={item.copy.copied ? 'Copied!' : 'Copy message text'}\n >\n {item.copy.copied ? 'Copied' : 'Copy'}\n </button>\n ) : null}\n {item.fork.available ? (\n <button\n type=\"button\"\n onClick={item.fork.run}\n className={classNames?.actionButton}\n title=\"Fork thread from this message\"\n >\n Fork\n </button>\n ) : null}\n {item.regenerate.available ? (\n <button\n type=\"button\"\n onClick={item.regenerate.run}\n className={classNames?.actionButton}\n title=\"Regenerate response\"\n >\n Regenerate\n </button>\n ) : null}\n {slots.meta}\n {!item.isUser && item.usage ? (\n <span\n className={classNames?.usage}\n title={`Input ${item.usage.inputTokens.toLocaleString()} · Output ${item.usage.outputTokens.toLocaleString()} tokens`}\n >\n {item.usage.costLabel} · {item.usage.tokensLabel}\n </span>\n ) : null}\n {item.timestamp ? (\n <span className={classNames?.timestamp} title={item.timestamp.absolute}>\n {item.timestamp.relative}\n </span>\n ) : null}\n </div>\n );\n\n if (item.edit.available) {\n return <EditableUserBubble item={item} slots={slots} actions={actionRow} />;\n }\n\n const className = joinClasses(classNames?.root, classNames?.byRole?.[item.role]);\n\n return (\n <div\n className={className}\n data-role={item.role}\n data-streaming={item.isStreaming ? 'true' : undefined}\n >\n <div>{renderBlocks(item, slots)}</div>\n {actionRow}\n </div>\n );\n}\n\n/** Blocks the model has no opinion on are skipped — a renderer only draws what it can draw. */\nfunction renderBlocks(item: TranscriptItem, slots: MessageRenderSlots): React.ReactNode[] {\n const nodes: React.ReactNode[] = [];\n for (const block of item.blocks) {\n if (block.kind === 'text') {\n nodes.push(\n <div key={block.key} className={slots.classNames?.text}>\n {slots.renderText\n ? slots.renderText(block.text, { isStreaming: item.isStreaming })\n : block.text}\n </div>,\n );\n continue;\n }\n if (block.kind === 'reasoning') {\n nodes.push(renderReasoningBlock(block, slots));\n continue;\n }\n if (block.kind === 'files') {\n nodes.push(renderFilesBlock(block, slots));\n continue;\n }\n if (block.kind === 'tools') {\n nodes.push(...renderToolBlock(item, block, slots));\n continue;\n }\n if (block.kind === 'ui' && slots.renderUi) {\n nodes.push(\n <div key={block.key} data-slot=\"ui\" data-component={block.component}>\n {slots.renderUi(block)}\n </div>,\n );\n }\n }\n return nodes;\n}\n\n/**\n * Files as content. An image is shown; anything else is a labelled link, because a renderer that\n * cannot display a format is more useful pointing at it than guessing.\n */\nfunction renderFilesBlock(\n block: Extract<TranscriptBlock, { kind: 'files' }>,\n slots: MessageRenderSlots,\n): React.ReactNode {\n return (\n <div key={block.key} className={slots.classNames?.files} data-files=\"true\">\n {slots.renderFiles\n ? slots.renderFiles(block.files)\n : block.files.map((file) => (\n <a\n key={file.url}\n href={file.url}\n target=\"_blank\"\n rel=\"noreferrer\"\n className={slots.classNames?.file}\n title={file.filename ?? file.mediaType}\n >\n {file.isImage ? (\n <img\n src={file.url}\n alt={file.filename ?? 'image'}\n className={slots.classNames?.fileImage}\n />\n ) : (\n (file.filename ?? file.mediaType)\n )}\n </a>\n ))}\n </div>\n );\n}\n\nfunction renderReasoningBlock(\n block: Extract<TranscriptBlock, { kind: 'reasoning' }>,\n slots: MessageRenderSlots,\n): React.ReactNode {\n return (\n <div\n key={block.key}\n className={slots.classNames?.reasoning}\n data-reasoning=\"true\"\n data-streaming={block.isStreaming ? 'true' : undefined}\n >\n <button\n type=\"button\"\n className={slots.classNames?.reasoningToggle}\n onClick={() => block.toggle()}\n aria-expanded={block.isOpen}\n >\n {slots.reasoningLabel ?? 'Reasoning'}\n </button>\n {block.isOpen ? (\n <div className={slots.classNames?.reasoningText}>\n {slots.renderReasoning\n ? slots.renderReasoning(block.text, {\n isStreaming: block.isStreaming,\n isOpen: block.isOpen,\n })\n : block.text}\n </div>\n ) : null}\n </div>\n );\n}\n\nfunction renderToolBlock(\n item: TranscriptItem,\n block: Extract<TranscriptBlock, { kind: 'tools' }>,\n slots: MessageRenderSlots,\n): React.ReactNode[] {\n if (slots.renderToolGroup) {\n return [\n <React.Fragment key={block.key}>\n {slots.renderToolGroup(block.parts, block.key)}\n </React.Fragment>,\n ];\n }\n if (!slots.renderToolPart) {\n return [];\n }\n const renderToolPart = slots.renderToolPart;\n return block.parts.map((part) => {\n const partKey = `${item.id}-${part.toolCallId}`;\n return <React.Fragment key={partKey}>{renderToolPart(part, partKey)}</React.Fragment>;\n });\n}\n\ninterface EditableUserBubbleProps {\n item: TranscriptItem;\n slots: MessageRenderSlots;\n actions: React.ReactNode;\n}\n\nfunction EditableUserBubble({ item, slots, actions }: EditableUserBubbleProps) {\n const { classNames } = slots;\n const { edit } = item;\n\n if (!edit.isEditing) {\n return (\n <div className={joinClasses(classNames?.root, classNames?.byRole?.user)} data-role=\"user\">\n <div className={classNames?.text}>\n {slots.renderText ? slots.renderText(item.text, { isStreaming: false }) : item.text}\n </div>\n <button\n type=\"button\"\n onClick={edit.start}\n className={classNames?.actionButton}\n title=\"Edit & resubmit\"\n >\n Edit\n </button>\n {actions}\n </div>\n );\n }\n\n const textareaProps = edit.getTextareaProps();\n return (\n <div data-editing=\"true\">\n <textarea\n {...textareaProps}\n rows={Math.min(8, edit.draft.split('\\n').length + 1)}\n className={classNames?.editTextarea}\n />\n <div className={classNames?.editActions}>\n <button type=\"button\" onClick={edit.cancel}>\n Cancel\n </button>\n <button type=\"button\" onClick={edit.save} disabled={!edit.canSave}>\n Resend\n </button>\n </div>\n </div>\n );\n}\n\nfunction joinClasses(...entries: Array<string | undefined>): string | undefined {\n const joined = entries.filter((entry) => entry).join(' ');\n return joined === '' ? undefined : joined;\n}\n","import type { QueuePause } from '@dudousxd/nestjs-agent-core';\nimport type { UIMessage } from 'ai';\nimport type React from 'react';\nimport { useCallback, useEffect, useRef, useState } from 'react';\nimport type { ApprovalTarget } from '../approvals/proposals.js';\nimport { type MessageFile, attachmentFile } from '../attachments/files.js';\nimport { type AgentBackend, requireBackendMethod } from '../backend.js';\nimport { shareStructure } from '../genui/share-structure.js';\nimport type { ToolCatalog } from '../presentation/phrasing.js';\nimport { useAgentBackend } from '../provider.js';\nimport type { QueuedChatMessage } from '../queue/model.js';\nimport type { AgentMessageMetadata } from '../stored-thread-to-ui-messages.js';\nimport {\n type ApproveOptions,\n type ChatStatus,\n type MessageUsageInfo,\n type SettleAction,\n type TimestampInfo,\n type TranscriptBlock,\n type TranscriptFile,\n type UsageSummary,\n buildTranscriptBlocks,\n describeTimestamp,\n describeUsage,\n extractMessageText,\n} from './model.js';\nimport { type StickToBottom, useStickToBottom } from './use-stick-to-bottom.js';\n\n/** Most-recent messages mounted up front; older ones wait behind `window.loadEarlier`. */\nconst DEFAULT_VISIBLE_COUNT = 50;\nconst DEFAULT_LOAD_EARLIER_STEP = 50;\nconst DEFAULT_COPY_RESET_MS = 1500;\n\nexport interface TranscriptCopyState {\n /** False when the message has no prose to put on the clipboard. */\n available: boolean;\n copied: boolean;\n copy: () => void;\n}\n\nexport interface TranscriptEditState {\n available: boolean;\n isEditing: boolean;\n draft: string;\n /** Whitespace-only drafts are refused, so an empty resubmit can never be sent. */\n canSave: boolean;\n start: () => void;\n cancel: () => void;\n setDraft: (value: string) => void;\n save: () => void;\n /** Controlled-textarea wiring: focus with the caret at the end, Enter saves, Escape cancels. */\n getTextareaProps: () => {\n ref: (element: HTMLTextAreaElement | null) => void;\n value: string;\n onChange: (event: React.ChangeEvent<HTMLTextAreaElement>) => void;\n onKeyDown: (event: React.KeyboardEvent<HTMLTextAreaElement>) => void;\n };\n}\n\nexport interface TranscriptActionState {\n available: boolean;\n run: () => void;\n}\n\nexport interface TranscriptItem {\n id: string;\n message: UIMessage;\n role: UIMessage['role'];\n /** Index in the FULL message array, not in the rendered window. */\n index: number;\n isUser: boolean;\n isAssistant: boolean;\n isLastAssistant: boolean;\n isStreaming: boolean;\n blocks: TranscriptBlock[];\n /** The prose alone — what `copy` puts on the clipboard and what an edit starts from. */\n text: string;\n usage: UsageSummary | null;\n timestamp: TimestampInfo | null;\n copy: TranscriptCopyState;\n edit: TranscriptEditState;\n fork: TranscriptActionState;\n regenerate: TranscriptActionState;\n}\n\n/** What an edit-and-resubmit sends. */\nexport interface EditSubmitInput {\n messageId: string;\n text: string;\n}\n\n/** Names the message an action is about. */\nexport interface MessageActionInput {\n messageId: string;\n}\n\n/** Settling a parked question set. `answers` holds only the questions the user touched. */\nexport interface AnswerInput {\n toolCallId: string;\n answers?: Record<string, string[]>;\n /** The surface the answer came through; the server records `'web'` when omitted. */\n via?: string;\n}\n\n/** Declining a parked question set. */\nexport interface SkipInput {\n toolCallId: string;\n /** The surface the skip came through; the server records `'web'` when omitted. */\n via?: string;\n}\n\n/** Approving a tool call parked on a human. */\nexport interface ApproveInput extends ApproveOptions {\n target?: ApprovalTarget;\n toolCallId: string;\n /** The surface the decision came through; the server records `'web'` when omitted. */\n via?: string;\n}\n\n/** Rejecting a tool call parked on a human. */\nexport interface RejectInput {\n target?: ApprovalTarget;\n toolCallId: string;\n reason?: string;\n via?: string;\n}\n\nexport interface TranscriptItemOptions {\n /**\n * A transcript nobody acts on (an audit view, a shared or archived conversation): no approve /\n * reject, answer / skip, edit, fork, regenerate or stop — whatever handlers or backend are in\n * scope. Parked approvals and question sets still render, with their actions unavailable.\n *\n * Without it the decision handlers DEFAULT to the in-scope backend (`<AgentProvider>`'s), so a\n * parked call is actionable with no wiring; a read-only surface would otherwise have to pass\n * `onApprove: null`, `onReject: null`, `onAnswer: null` and `onSkip: null` one by one.\n */\n readOnly?: boolean;\n /** User messages get an inline edit-and-resubmit machine. */\n editable?: boolean;\n onEditSubmit?: (input: EditSubmitInput) => void | Promise<void>;\n onFork?: (input: MessageActionInput) => void | Promise<void>;\n /** Only the LAST assistant message gets a regenerate machine. */\n regeneratable?: boolean;\n onRegenerate?: (input: MessageActionInput) => void | Promise<void>;\n /** Default: `metadata.usage` (replayed turns; see `AgentMessageMetadata`). */\n getUsage?: (message: UIMessage) => MessageUsageInfo | null;\n /** Default: `metadata.createdAt` (replayed and streamed messages). */\n getCreatedAt?: (message: UIMessage) => string | null;\n /** How long `copy.copied` stays true. Default 1500ms. */\n copyResetMs?: number;\n /** Clipboard writer; defaults to `navigator.clipboard.writeText`. */\n writeClipboard?: (text: string) => Promise<void>;\n /**\n * Lift retrieval tool parts into their own `sources` block instead of leaving them in the tool\n * run. Off by default, so a renderer already drawing tool cards keeps drawing them.\n */\n sources?: boolean;\n /**\n * Server-declared tool presentations (`useToolCatalog(...).catalog`). Given → each tool call's\n * `description` and each tool block's `activity` speak in the tool's own words; omitted → generic.\n */\n toolCatalog?: ToolCatalog;\n /**\n * Settle a parked question set. Default: the in-scope backend's `answerToolCall` (the enclosing\n * `<AgentProvider>`'s), so a question set is an `elicitation` block the user can act on without\n * any wiring. `null` turns question sets back into plain tool calls.\n *\n * `answers` holds ONLY the questions the user touched. An omitted one takes its own pre-picked\n * default server-side, which is what keeps \"just confirmed\" and \"picked exactly what was\n * pre-picked\" distinguishable in the settled row.\n */\n onAnswer?: ((input: AnswerInput) => void | Promise<void>) | null;\n /** Decline the question set and let the agent proceed on its own picks. Default: the backend's. */\n onSkip?: ((input: SkipInput) => void | Promise<void>) | null;\n /**\n * Settle a tool call parked on a human. Default: the in-scope backend's `approveToolCall` /\n * `rejectToolCall`. `remember` is what `call.approve.run({ remember: true })` passed. `null`\n * leaves the call without the affordance.\n */\n onApprove?: ((input: ApproveInput) => void | Promise<void>) | null;\n onReject?: ((input: RejectInput) => void | Promise<void>) | null;\n}\n\nexport interface TranscriptWindow {\n visibleCount: number;\n /** How many older messages are not mounted. */\n hiddenCount: number;\n canLoadEarlier: boolean;\n loadEarlier: () => void;\n showAll: () => void;\n}\n\nexport interface TranscriptStopState {\n available: boolean;\n /** True from the click until the turn actually leaves a busy status. */\n isStopping: boolean;\n stop: () => void;\n}\n\nexport interface UseChatTranscriptOptions extends TranscriptItemOptions {\n messages: UIMessage[];\n status: ChatStatus;\n initialVisibleCount?: number;\n loadEarlierStep?: number;\n /** Cancel the in-flight turn — wire to `useAgentChat`'s `cancel`. */\n onStop?: () => void | Promise<void>;\n /** Suggested follow-ups. The model only decides WHETHER they belong on screen. */\n followUps?: string[] | null;\n stickToBottomThreshold?: number;\n /**\n * Messages waiting in the thread's queue — `chat.queue` (`useAgentChat` wires it). They render\n * after the transcript as {@link ChatTranscript.queued}: pending user messages, not yet sent.\n */\n queue?: {\n /** `files` may be left out by a host that builds these itself: it is derived from `attachments`. */\n items: Array<Omit<QueuedChatMessage, 'files'> & { files?: MessageFile[] }>;\n paused: QueuePause | null;\n remove?: (id: string) => void | Promise<void>;\n } | null;\n}\n\n/** One file on a waiting message: a sent message's {@link MessageFile}, and a `TranscriptFile`. */\nexport type TranscriptQueuedFile = MessageFile & TranscriptFile;\n\n/**\n * A message waiting in the thread's queue, as the transcript shows it: a user message that has not\n * been sent to the model yet. Render it after {@link ChatTranscript.items}, dimmed or tagged.\n */\nexport interface TranscriptQueuedItem {\n id: string;\n role: 'user';\n text: string;\n /**\n * The message's files, in the shape a sent message's have: a {@link MessageFile} (what\n * `messageFiles()` gives — `kind`, `extension`, `mediaId`) that is also a `TranscriptFile`\n * (`isImage`), so either renderer takes it as it is.\n */\n files: TranscriptQueuedFile[];\n /**\n * `'sending'` — on its way to the server. `'queued'` — waiting for the running turn.\n * `'paused'` — waiting, but the queue is paused (see {@link ChatTranscript.queuePaused}).\n */\n state: 'sending' | 'queued' | 'paused';\n /** 0-based place in the queue. */\n position: number;\n /** Runs next. */\n isNext: boolean;\n /** Queued by an interrupt — it runs as soon as the cancelled turn settles. */\n interrupt: boolean;\n remove: TranscriptActionState;\n}\n\nexport interface ChatTranscript {\n /** The mounted window, oldest first. `window.hiddenCount` says what is held back. */\n items: TranscriptItem[];\n status: ChatStatus;\n isEmpty: boolean;\n /** A turn is in flight: sent but not settled. */\n isBusy: boolean;\n isStreaming: boolean;\n showEmptyState: boolean;\n /** Waiting on the first token of a turn that has no assistant message yet. */\n showTypingIndicator: boolean;\n showFollowUps: boolean;\n lastAssistantId: string | null;\n window: TranscriptWindow;\n scroll: StickToBottom;\n stop: TranscriptStopState;\n /** Messages waiting in the thread's queue, in run order — render after `items`. */\n queued: TranscriptQueuedItem[];\n /** Why the queue is not draining, or `null`. */\n queuePaused: QueuePause | null;\n}\n\n/**\n * The model behind a chat transcript: messages normalized into items with their parts grouped into\n * runs, per-message derived values (copyable text, usage labels, relative time), each action as a\n * state machine rather than a button, list windowing, and stick-to-bottom. It renders nothing and\n * names no class — `MessageList`/`MessageItem` are one renderer over it, and an app with its own\n * design system writes another without reimplementing any of this.\n */\nexport function useChatTranscript(options: UseChatTranscriptOptions): ChatTranscript {\n const {\n messages,\n status,\n initialVisibleCount = DEFAULT_VISIBLE_COUNT,\n loadEarlierStep = DEFAULT_LOAD_EARLIER_STEP,\n followUps,\n stickToBottomThreshold,\n } = options;\n\n const latest = useRef(options);\n latest.current = options;\n\n const [visibleCount, setVisibleCount] = useState(initialVisibleCount);\n const [stopRequested, setStopRequested] = useState(false);\n\n // A reconnecting stream is still the turn in flight, and its message is still being written.\n const isStreaming = status === 'streaming' || status === 'reconnecting';\n const isBusy = status === 'submitted' || isStreaming;\n const isEmpty = messages.length === 0;\n\n // A settled turn clears a pending stop, so the next turn's button starts from rest.\n useEffect(() => {\n if (!isBusy) {\n setStopRequested(false);\n }\n }, [isBusy]);\n\n const lastMessage = messages.at(-1);\n const lastAssistant = findLastAssistant(messages);\n const streamingMessageId = isStreaming ? (lastAssistant?.id ?? null) : null;\n\n const visibleStart = Math.max(0, messages.length - visibleCount);\n const items = useTranscriptItems({\n messages,\n visibleStart,\n streamingMessageId,\n options,\n });\n\n const stop = useCallback(() => {\n const current = latest.current;\n if (\n current.status !== 'submitted' &&\n current.status !== 'streaming' &&\n current.status !== 'reconnecting'\n ) {\n return;\n }\n setStopRequested(true);\n void current.onStop?.();\n }, []);\n\n const loadEarlier = useCallback(\n () =>\n setVisibleCount(\n (count) => count + (latest.current.loadEarlierStep ?? DEFAULT_LOAD_EARLIER_STEP),\n ),\n [],\n );\n const showAll = useCallback(() => setVisibleCount(latest.current.messages.length), []);\n\n const scroll = useStickToBottom({\n contentKey: contentSignature(messages),\n ...(stickToBottomThreshold !== undefined ? { threshold: stickToBottomThreshold } : {}),\n });\n\n const showTypingIndicator = isBusy && lastMessage?.role !== 'assistant';\n const queued = useQueuedItems(options.queue ?? null, options.readOnly === true);\n\n return {\n items,\n status,\n isEmpty,\n isBusy,\n isStreaming,\n showEmptyState: isEmpty && status === 'ready',\n showTypingIndicator,\n showFollowUps:\n status === 'ready' &&\n !showTypingIndicator &&\n lastMessage?.role === 'assistant' &&\n !!followUps &&\n followUps.length > 0,\n lastAssistantId: lastAssistant?.id ?? null,\n window: {\n visibleCount,\n hiddenCount: visibleStart,\n canLoadEarlier: visibleStart > 0,\n loadEarlier,\n showAll,\n },\n scroll,\n stop: {\n available: isBusy && options.readOnly !== true && options.onStop !== undefined,\n isStopping: stopRequested,\n stop,\n },\n queued,\n queuePaused: options.queue?.paused ?? null,\n };\n}\n\n/** The queue as transcript items. `remove` is cached per id, like every other item action. */\nfunction useQueuedItems(\n queue: UseChatTranscriptOptions['queue'],\n readOnly: boolean,\n): TranscriptQueuedItem[] {\n const latestQueue = useRef(queue);\n latestQueue.current = queue;\n const removers = useRef(new Map<string, () => void>());\n const removerFor = useCallback((id: string) => {\n let remover = removers.current.get(id);\n if (remover === undefined) {\n remover = () => {\n void latestQueue.current?.remove?.(id);\n };\n removers.current.set(id, remover);\n }\n return remover;\n }, []);\n if (queue === null || queue === undefined) {\n return [];\n }\n return queue.items.map((message, position) => {\n const state: TranscriptQueuedItem['state'] =\n message.state === 'sending' ? 'sending' : queue.paused !== null ? 'paused' : 'queued';\n return {\n id: message.id,\n role: 'user',\n text: message.text,\n files: (message.files ?? message.attachments.map(attachmentFile)).map((file) => ({\n ...file,\n isImage: file.kind === 'image',\n })),\n state,\n position,\n isNext: position === 0,\n interrupt: message.interrupt,\n remove: {\n available: !readOnly && state !== 'sending' && queue.remove !== undefined,\n run: removerFor(message.id),\n },\n };\n });\n}\n\nexport interface UseTranscriptItemOptions extends TranscriptItemOptions {\n message: UIMessage;\n isStreaming?: boolean;\n}\n\n/**\n * The single-message half of {@link useChatTranscript}, for a renderer that owns the list itself.\n * `regeneratable` applies directly here: one assistant message is trivially the last one.\n */\nexport function useTranscriptItem(options: UseTranscriptItemOptions): TranscriptItem {\n const { message, isStreaming = false } = options;\n const messagesRef = useRef<UIMessage[]>([message]);\n // A fresh array each render would re-key nothing but does churn the items memo; the identity is\n // kept stable while the message itself is unchanged.\n if (messagesRef.current[0] !== message) {\n messagesRef.current = [message];\n }\n const items = useTranscriptItems({\n messages: messagesRef.current,\n visibleStart: 0,\n streamingMessageId: isStreaming ? message.id : null,\n options,\n });\n // One message in, exactly one item out.\n return items[0] as TranscriptItem;\n}\n\ninterface TranscriptItemsParams {\n messages: UIMessage[];\n visibleStart: number;\n streamingMessageId: string | null;\n options: TranscriptItemOptions;\n}\n\n/**\n * All per-message UI state lives here, keyed by message id, because the number of messages is not\n * known at render time — a hook per item would break the rules of hooks the moment a turn arrives.\n * Each item's callbacks are cached per id so a controlled `<textarea>`'s ref identity survives every\n * keystroke; without that, React detaches and re-attaches the node on each render and the focus\n * effect drags the caret back to the end mid-edit.\n */\nfunction useTranscriptItems({\n messages,\n visibleStart,\n streamingMessageId,\n options,\n}: TranscriptItemsParams): TranscriptItem[] {\n const [drafts, setDrafts] = useState<ReadonlyMap<string, string>>(() => new Map());\n const [copied, setCopied] = useState<ReadonlySet<string>>(() => new Set());\n const [openReasoning, setOpenReasoning] = useState<ReadonlyMap<string, boolean>>(() => new Map());\n // A question's picks, under `toolCallId|questionId`. Presence IS \"the user touched this\n // question\" — an absent entry is what makes the submission omit it and take the server's default.\n const [picks, setPicks] = useState<ReadonlyMap<string, string[]>>(() => new Map());\n // Which decision each parked call is sending, not merely that one is: the two affordances on a\n // call are never in flight together, and only the pressed one should report progress.\n const [settling, setSettling] = useState<ReadonlyMap<string, SettleAction>>(() => new Map());\n const [settleErrors, setSettleErrors] = useState<\n ReadonlyMap<string, { message: string; code: string | null }>\n >(() => new Map());\n\n const backend = useAgentBackend();\n const handlers = settleHandlers(options, backend);\n const latest = useRef({ options, handlers, drafts, picks, messages });\n latest.current = { options, handlers, drafts, picks, messages };\n\n const copyTimers = useRef(new Map<string, ReturnType<typeof setTimeout>>());\n useEffect(\n () => () => {\n for (const timer of copyTimers.current.values()) {\n clearTimeout(timer);\n }\n copyTimers.current.clear();\n },\n [],\n );\n\n const callbackCache = useRef(new Map<string, ItemCallbacks>());\n const reasoningToggleCache = useRef(new Map<string, (open?: boolean) => void>());\n const uiBlocks = useRef(new Map<string, TranscriptBlock>());\n\n const toggleReasoning = useCallback((key: string, open?: boolean) => {\n setOpenReasoning((current) => {\n const next = new Map(current);\n next.set(key, open ?? !(current.get(key) ?? false));\n return next;\n });\n }, []);\n\n const stableToggle = useCallback(\n (key: string) => {\n let cached = reasoningToggleCache.current.get(key);\n if (!cached) {\n cached = (open?: boolean) => toggleReasoning(key, open);\n reasoningToggleCache.current.set(key, cached);\n }\n return cached;\n },\n [toggleReasoning],\n );\n\n const pick = useCallback((toolCallId: string, questionId: string, values: string[]) => {\n setPicks((current) => new Map(current).set(pickKey(toolCallId, questionId), values));\n }, []);\n\n /**\n * Run one decision against the server. A rejection has to land somewhere the user can see: the\n * call stays parked either way, and a form that silently does nothing on submit is\n * indistinguishable from a broken button.\n */\n const settle = useCallback(\n (toolCallId: string, action: SettleAction, send: () => void | Promise<void>) => {\n setSettleErrors((current) => {\n if (!current.has(toolCallId)) {\n return current;\n }\n const next = new Map(current);\n next.delete(toolCallId);\n return next;\n });\n setSettling((current) => new Map(current).set(toolCallId, action));\n const failed = (error: unknown) => {\n setSettling((current) => {\n const next = new Map(current);\n next.delete(toolCallId);\n return next;\n });\n setSettleErrors((current) =>\n new Map(current).set(toolCallId, {\n message: error instanceof Error ? error.message : 'Could not settle this',\n code: settleErrorCode(error),\n }),\n );\n };\n // Sent in the click's own tick, not a microtask later — a synchronous throw and a rejected\n // promise are the same failure to the person looking at the form.\n try {\n void Promise.resolve(send()).catch(failed);\n } catch (error) {\n failed(error);\n }\n },\n [],\n );\n\n const answer = useCallback(\n (toolCallId: string) => {\n const current = latest.current;\n const onAnswer = current.handlers.onAnswer;\n if (!onAnswer) {\n return;\n }\n settle(toolCallId, 'answer', () =>\n onAnswer({ toolCallId, answers: answersFor(current.picks, toolCallId) }),\n );\n },\n [settle],\n );\n\n const skip = useCallback(\n (toolCallId: string) => {\n const onSkip = latest.current.handlers.onSkip;\n if (onSkip) {\n settle(toolCallId, 'skip', () => onSkip({ toolCallId }));\n }\n },\n [settle],\n );\n\n const approve = useCallback(\n (toolCallId: string, options?: ApproveOptions, target?: ApprovalTarget) => {\n const onApprove = latest.current.handlers.onApprove;\n if (onApprove) {\n settle(toolCallId, 'approve', () =>\n onApprove({\n toolCallId,\n ...(target === undefined ? {} : { target }),\n ...(options?.remember === true ? { remember: true } : {}),\n }),\n );\n }\n },\n [settle],\n );\n\n const reject = useCallback(\n (toolCallId: string, target?: ApprovalTarget) => {\n const onReject = latest.current.handlers.onReject;\n if (onReject) {\n settle(toolCallId, 'reject', () =>\n onReject({ toolCallId, ...(target === undefined ? {} : { target }) }),\n );\n }\n },\n [settle],\n );\n\n const callbacksFor = useCallback((id: string): ItemCallbacks => {\n const cached = callbackCache.current.get(id);\n if (cached) {\n return cached;\n }\n const textFor = () =>\n extractMessageText(latest.current.messages.find((message) => message.id === id)?.parts);\n const created: ItemCallbacks = {\n copy: () => {\n const text = textFor();\n if (!text) {\n return;\n }\n const write =\n latest.current.options.writeClipboard ??\n ((value: string) => navigator.clipboard.writeText(value));\n void Promise.resolve()\n .then(() => write(text))\n .then(() => {\n setCopied((current) => new Set(current).add(id));\n const existing = copyTimers.current.get(id);\n if (existing) {\n clearTimeout(existing);\n }\n copyTimers.current.set(\n id,\n setTimeout(() => {\n copyTimers.current.delete(id);\n setCopied((current) => {\n const next = new Set(current);\n next.delete(id);\n return next;\n });\n }, latest.current.options.copyResetMs ?? DEFAULT_COPY_RESET_MS),\n );\n })\n .catch(() => {\n // Clipboard can be unavailable (insecure context / denied permission) — fail quietly.\n });\n },\n startEdit: () => {\n const text = textFor();\n setDrafts((current) => new Map(current).set(id, text));\n },\n cancelEdit: () => {\n setDrafts((current) => {\n const next = new Map(current);\n next.delete(id);\n return next;\n });\n },\n setDraft: (value: string) => {\n setDrafts((current) => new Map(current).set(id, value));\n },\n save: () => {\n const next = (latest.current.drafts.get(id) ?? '').trim();\n if (!next) {\n return;\n }\n created.cancelEdit();\n void latest.current.options.onEditSubmit?.({ messageId: id, text: next });\n },\n fork: () => {\n void latest.current.options.onFork?.({ messageId: id });\n },\n regenerate: () => {\n void latest.current.options.onRegenerate?.({ messageId: id });\n },\n textareaRef: (element: HTMLTextAreaElement | null) => {\n if (!element) {\n return;\n }\n element.focus();\n element.setSelectionRange(element.value.length, element.value.length);\n },\n onTextareaChange: (event: React.ChangeEvent<HTMLTextAreaElement>) => {\n created.setDraft(event.target.value);\n },\n onTextareaKeyDown: (event: React.KeyboardEvent<HTMLTextAreaElement>) => {\n if (event.key === 'Enter' && !event.shiftKey) {\n event.preventDefault();\n created.save();\n }\n if (event.key === 'Escape') {\n event.preventDefault();\n created.cancelEdit();\n }\n },\n };\n callbackCache.current.set(id, created);\n return created;\n }, []);\n\n const lastAssistantId = findLastAssistant(messages)?.id ?? null;\n const items: TranscriptItem[] = [];\n // Pushed components of the last render, by block key: an unchanged one keeps its object.\n const previousUi = uiBlocks.current;\n const keptUi = new Map<string, TranscriptBlock>();\n const keepUiIdentity = (blocks: TranscriptBlock[]): TranscriptBlock[] =>\n blocks.map((block) => {\n if (block.kind !== 'ui') return block;\n const kept = shareStructure(previousUi.get(block.key), block);\n keptUi.set(block.key, kept);\n return kept;\n });\n\n for (let index = visibleStart; index < messages.length; index++) {\n const message = messages[index];\n if (!message) {\n continue;\n }\n const callbacks = callbacksFor(message.id);\n const draft = drafts.get(message.id);\n const isEditing = draft !== undefined;\n const text = extractMessageText(message.parts);\n const usage = (options.getUsage ?? usageFromMetadata)(message);\n const isUser = message.role === 'user';\n const isAssistant = message.role === 'assistant';\n const isLastAssistant = isAssistant && message.id === lastAssistantId;\n\n items.push({\n id: message.id,\n message,\n role: message.role,\n index,\n isUser,\n isAssistant,\n isLastAssistant,\n isStreaming: message.id === streamingMessageId,\n blocks: keepUiIdentity(\n buildTranscriptBlocks(message, {\n isReasoningOpen: (key, isStreamingRun) => openReasoning.get(key) ?? isStreamingRun,\n toggleReasoning: (key, open) => stableToggle(key)(open),\n ...(options.sources !== undefined ? { sources: options.sources } : {}),\n ...(options.toolCatalog !== undefined ? { toolCatalog: options.toolCatalog } : {}),\n // Read-only still lifts question sets into their block, so the outcome shows.\n ...(handlers.onAnswer !== undefined ||\n (options.readOnly === true && options.onAnswer !== null)\n ? {\n elicitation: {\n picked: (toolCallId, questionId) => picks.get(pickKey(toolCallId, questionId)),\n pick,\n canAnswer: handlers.onAnswer !== undefined,\n canSkip: handlers.onSkip !== undefined,\n answer,\n skip,\n submitting: (toolCallId) => settling.get(toolCallId) ?? null,\n errorOf: (toolCallId) => settleErrors.get(toolCallId)?.message ?? null,\n errorCodeOf: (toolCallId) => settleErrors.get(toolCallId)?.code ?? null,\n },\n }\n : {}),\n ...(handlers.onApprove !== undefined || handlers.onReject !== undefined\n ? {\n approval: {\n canApprove: handlers.onApprove !== undefined,\n canReject: handlers.onReject !== undefined,\n approve,\n reject,\n submitting: (toolCallId) => settling.get(toolCallId) ?? null,\n errorOf: (toolCallId) => settleErrors.get(toolCallId)?.message ?? null,\n errorCodeOf: (toolCallId) => settleErrors.get(toolCallId)?.code ?? null,\n },\n }\n : {}),\n }),\n ),\n text,\n usage: usage ? describeUsage(usage) : null,\n timestamp: describeTimestamp((options.getCreatedAt ?? createdAtFromMetadata)(message)),\n copy: {\n available: text.length > 0,\n copied: copied.has(message.id),\n copy: callbacks.copy,\n },\n edit: {\n available:\n isUser &&\n options.readOnly !== true &&\n options.editable === true &&\n options.onEditSubmit !== undefined,\n isEditing,\n draft: draft ?? text,\n canSave: (draft ?? '').trim().length > 0,\n start: callbacks.startEdit,\n cancel: callbacks.cancelEdit,\n setDraft: callbacks.setDraft,\n save: callbacks.save,\n getTextareaProps: () => ({\n ref: callbacks.textareaRef,\n value: draft ?? text,\n onChange: callbacks.onTextareaChange,\n onKeyDown: callbacks.onTextareaKeyDown,\n }),\n },\n fork: {\n available: options.readOnly !== true && options.onFork !== undefined,\n run: callbacks.fork,\n },\n regenerate: {\n available:\n isLastAssistant &&\n options.readOnly !== true &&\n options.regeneratable === true &&\n options.onRegenerate !== undefined,\n run: callbacks.regenerate,\n },\n });\n }\n\n uiBlocks.current = keptUi;\n return items;\n}\n\ninterface ItemCallbacks {\n copy: () => void;\n startEdit: () => void;\n cancelEdit: () => void;\n setDraft: (value: string) => void;\n save: () => void;\n fork: () => void;\n regenerate: () => void;\n textareaRef: (element: HTMLTextAreaElement | null) => void;\n onTextareaChange: (event: React.ChangeEvent<HTMLTextAreaElement>) => void;\n onTextareaKeyDown: (event: React.KeyboardEvent<HTMLTextAreaElement>) => void;\n}\n\ninterface SettleHandlers {\n onAnswer: ((input: AnswerInput) => void | Promise<void>) | undefined;\n onSkip: ((input: SkipInput) => void | Promise<void>) | undefined;\n onApprove: ((input: ApproveInput) => void | Promise<void>) | undefined;\n onReject: ((input: RejectInput) => void | Promise<void>) | undefined;\n}\n\n/**\n * The handler for each human decision: the caller's, else the backend's own call — so a parked\n * approval or question set is never a card nobody can act on. `null` opts a decision out.\n */\nfunction settleHandlers(options: TranscriptItemOptions, backend: AgentBackend): SettleHandlers {\n const pick = <T>(own: T | null | undefined, fallback: T | undefined): T | undefined =>\n options.readOnly === true || own === null ? undefined : (own ?? fallback);\n return {\n onAnswer: pick(\n options.onAnswer,\n backend.answerToolCall\n ? async (input) => {\n await backend.answerToolCall?.(input);\n }\n : undefined,\n ),\n onSkip: pick(\n options.onSkip,\n backend.skipToolCall\n ? async (input) => {\n await backend.skipToolCall?.(input);\n }\n : undefined,\n ),\n onApprove: pick(\n options.onApprove,\n backend.approveToolCall || backend.approveActionProposal\n ? async (input) => {\n if (input.target?.kind === 'proposal') {\n if (input.target.threadId === undefined)\n throw new Error('A proposal decision requires its thread scope');\n await requireBackendMethod(\n backend,\n 'approveActionProposal',\n )({\n threadId: input.target.threadId,\n proposalId: input.target.proposalId,\n ...(input.remember === undefined ? {} : { remember: input.remember }),\n });\n } else await requireBackendMethod(backend, 'approveToolCall')(input);\n }\n : undefined,\n ),\n onReject: pick(\n options.onReject,\n backend.rejectToolCall || backend.rejectActionProposal\n ? async (input) => {\n if (input.target?.kind === 'proposal') {\n if (input.target.threadId === undefined)\n throw new Error('A proposal decision requires its thread scope');\n await requireBackendMethod(\n backend,\n 'rejectActionProposal',\n )({\n threadId: input.target.threadId,\n proposalId: input.target.proposalId,\n ...(input.reason === undefined ? {} : { reason: input.reason }),\n });\n } else await requireBackendMethod(backend, 'rejectToolCall')(input);\n }\n : undefined,\n ),\n };\n}\n\nfunction metadataOf(message: UIMessage): AgentMessageMetadata {\n const metadata = message.metadata;\n return metadata !== null && typeof metadata === 'object'\n ? (metadata as AgentMessageMetadata)\n : {};\n}\n\n/** The default `getUsage`: what the library stamps on `metadata.usage`. */\nfunction usageFromMetadata(message: UIMessage): MessageUsageInfo | null {\n const usage = metadataOf(message).usage;\n if (usage === undefined) return null;\n return {\n inputTokens: usage.inputTokens,\n outputTokens: usage.outputTokens,\n costUsd: usage.costUsd ?? null,\n };\n}\n\n/** The default `getCreatedAt`: what the library stamps on `metadata.createdAt`. */\nfunction createdAtFromMetadata(message: UIMessage): string | null {\n return metadataOf(message).createdAt ?? null;\n}\n\n/** `|` never appears in either half: a tool-call id and a question id are both opaque tokens. */\nfunction pickKey(toolCallId: string, questionId: string): string {\n return `${toolCallId}|${questionId}`;\n}\n\n/** The picks belonging to one question set, as the answers a submission carries. */\nfunction answersFor(\n picks: ReadonlyMap<string, string[]>,\n toolCallId: string,\n): Record<string, string[]> {\n const prefix = `${toolCallId}|`;\n const answers: Record<string, string[]> = {};\n for (const [key, values] of picks) {\n if (key.startsWith(prefix)) {\n answers[key.slice(prefix.length)] = values;\n }\n }\n return answers;\n}\n\nfunction findLastAssistant(messages: UIMessage[]): UIMessage | undefined {\n for (let index = messages.length - 1; index >= 0; index--) {\n const message = messages[index];\n if (message?.role === 'assistant') {\n return message;\n }\n }\n return undefined;\n}\n\n/**\n * Changes as the transcript grows, including WITHIN the message being streamed — the array is\n * mutated in place while tokens arrive, so its length alone never moves during a turn.\n */\nfunction contentSignature(messages: UIMessage[]): string {\n const last = messages.at(-1);\n if (!last) {\n return '0';\n }\n let length = 0;\n for (const part of last.parts ?? []) {\n if ('text' in part && typeof part.text === 'string') {\n length += part.text.length;\n }\n }\n return `${messages.length}|${last.id}|${last.parts?.length ?? 0}|${length}`;\n}\n\n/** The server's machine-readable reason for refusing a decision (`run_not_active`, …), if any. */\nfunction settleErrorCode(error: unknown): string | null {\n const code = (error as { code?: unknown } | null)?.code;\n return typeof code === 'string' && code !== '' ? code : null;\n}\n","import {\n type ElicitationInput,\n type ToolConfirmation,\n readElicitationInput,\n validateElicitationAnswer,\n} from '@dudousxd/nestjs-agent-core';\nimport {\n type DataUIPart,\n type DynamicToolUIPart,\n type FileUIPart,\n type ToolUIPart,\n type UIMessage,\n getToolName,\n isDataUIPart,\n isFileUIPart,\n isReasoningUIPart,\n isTextUIPart,\n isToolUIPart,\n} from 'ai';\nimport type { ApprovalTarget } from '../approvals/proposals.js';\nimport { type RawAnswer, coerceAnswer } from '../elicitation/answers.js';\nimport type { ToolCatalog } from '../presentation/phrasing.js';\nimport {\n type ToolActivityGroup,\n type ToolCallDescription,\n describeToolCall,\n groupToolActivity,\n} from '../presentation/tool-activity.js';\nimport { readReasoningMs } from '../reasoning/timing.js';\n\n/** A tool UI part on a `UIMessage` — a static `tool-*` part or the `dynamic-tool` part. */\nexport type AnyToolUIPart = ToolUIPart | DynamicToolUIPart;\n\n/**\n * The AI SDK's chat status, plus `reconnecting`: a turn is in flight and its stream dropped, and the\n * transport is re-attaching (`useAgentChat`). A busy status, like `streaming`.\n */\nexport type ChatStatus = 'ready' | 'submitted' | 'streaming' | 'reconnecting' | 'error';\n\n/** Server-aggregated usage for an assistant turn. */\nexport interface MessageUsageInfo {\n inputTokens: number;\n outputTokens: number;\n /**\n * `null` when no price is on record for the model that ran the turn. Distinct from `0`, which is\n * a turn that genuinely cost nothing — printing `$0` for an unpriced turn states a number the\n * store never had.\n */\n costUsd: number | null;\n}\n\n/** A run of contiguous prose. `isStreaming` is the PART's own state, not the message's. */\nexport interface TranscriptTextBlock {\n kind: 'text';\n key: string;\n text: string;\n isStreaming: boolean;\n}\n\n/** One file on a message — an uploaded attachment, or one the model produced. */\nexport interface TranscriptFile {\n /** Presigned or otherwise directly fetchable. Display-only: the model reads its own copy. */\n url: string;\n mediaType: string;\n filename: string | null;\n /** `image/*`, which a renderer can show inline rather than as a link. */\n isImage: boolean;\n}\n\n/** A run of contiguous files. Grouped so a renderer can lay several out as one strip. */\nexport interface TranscriptFilesBlock {\n kind: 'files';\n key: string;\n files: TranscriptFile[];\n}\n\n/**\n * A run of contiguous reasoning. Carries its own disclosure state because a thread can hold many\n * of them and each is toggled independently; `isOpen` defaults to `isStreaming` (thinking is worth\n * watching live, worth folding away once answered) until `toggle` is called for that run.\n */\nexport interface TranscriptReasoningBlock {\n kind: 'reasoning';\n key: string;\n text: string;\n isStreaming: boolean;\n /**\n * How long the model thought, in ms — the backend's measurement once the run closed (live) or as\n * persisted (reloaded). `null` while it still streams, or when nothing was recorded: pair it with\n * `useElapsed(block.isStreaming)` for a ticking label (`block.durationMs ?? elapsed`).\n */\n durationMs: number | null;\n isOpen: boolean;\n toggle: (open?: boolean) => void;\n}\n\n/**\n * A decision a run is waiting on a human for, and which one a parked call is currently sending.\n *\n * One call settles one way at a time, and WHICH one is what lets a surface report progress on the\n * affordance the person pressed instead of on all of them.\n */\nexport type SettleAction = 'approve' | 'reject' | 'answer' | 'skip';\n\n/** One such decision: whether it can be made, whether it is on its way, and how to send it. */\nexport interface TranscriptSettleState {\n available: boolean;\n /** True from the click until the run resumes and settles the call. */\n isSubmitting: boolean;\n run: () => void;\n}\n\n/** How an approval stands. */\nexport type TranscriptApprovalStatus =\n | 'pending'\n | 'approved'\n | 'rejected'\n | 'expired'\n | 'superseded';\n\n/**\n * Who has to settle a parked call, until when, and — once it settled — how. From the stream's\n * `approval-requested` / `approval-settled` frames, or the same parts a reloaded thread carries.\n * `null` on a call whose runner never said (the call can still be awaiting approval).\n */\nexport interface TranscriptApproval {\n target?: ApprovalTarget;\n executionStatus?: 'queued' | 'executing' | 'succeeded' | 'failed' | null;\n confirmation?: ToolConfirmation;\n /** Open vocabulary the host defines: `'requester'`, `'admin'`, a role… */\n approver: string;\n /** ISO-8601; `null` when the request never lapses. Pair with `useApprovalCountdown`. */\n expiresAt: string | null;\n /** Why the call needs a person, when the runner said. */\n reason: string | null;\n /**\n * `pending` until a settlement arrives; then what it said. Falls back to the call's own state\n * (denied → `rejected`, an output → `approved`) for a runner that streams no settlement.\n */\n status: TranscriptApprovalStatus;\n /** The approval also covers later calls of this tool in this thread. */\n remember: boolean;\n /** Opaque ref of who decided; `null` while pending, on an expiry, or when the runner did not say. */\n decidedBy: string | null;\n /** The surface the decision came through (`'web'`, `'slack'`, `'remembered'`, …). */\n decidedVia: string | null;\n /** What the person said when declining. */\n decisionReason: string | null;\n}\n\n/** What an approval can carry beyond yes. */\nexport interface ApproveOptions {\n /** Approve later calls of the same tool in the same thread without asking again. */\n remember?: boolean;\n}\n\n/** One call in a tool run, with whatever human decision it is parked on. */\nexport interface TranscriptToolCall {\n part: AnyToolUIPart;\n toolCallId: string;\n name: string;\n /** `read` / `action` as the stream classified the call; `null` when the backend did not say. */\n toolKind: string | null;\n /** The call this one ran inside (a code-mode `execute`, a delegated agent); `null` for a top-level call. */\n parentId: string | null;\n /**\n * Calls nested under this one within the same block, in stream order. Always empty for a call\n * nothing names as its parent.\n */\n children: TranscriptToolCall[];\n /** Who has to decide, when the runner said so. See {@link TranscriptApproval}. */\n approval: TranscriptApproval | null;\n /**\n * How to talk about this call without naming it — status, phrase, label, icon, approval prompt,\n * resolved result — from the server's presentation when `toolCatalog` was given, generic otherwise.\n */\n description: ToolCallDescription;\n /**\n * Parked on a person. An `action` tool's input lands and its output never follows on its own —\n * the loop waits for an approval between the two — so a settled-looking card that never settles\n * IS the pending approval.\n */\n isAwaitingApproval: boolean;\n /** `run({ remember: true })` approves this tool for the rest of the thread. */\n approve: TranscriptSettleState & { run: (options?: ApproveOptions) => void };\n reject: TranscriptSettleState;\n /** A failed decision — the call is still parked, so the affordance stays live. */\n error: string | null;\n /**\n * The server's machine-readable reason for {@link error}, when it gave one. `run_not_active`\n * means the turn that asked has ended: nothing is waiting for the decision, and pressing again\n * will be refused again — word it yourself and let the person send the message again.\n */\n errorCode: string | null;\n}\n\n/**\n * A run of CONSECUTIVE tool parts, grouped so a UI can collapse \"5 tools ran\" into one affordance.\n * Any non-tool part between two tool parts ends the run — including the AI SDK's `step-start`\n * markers, so tools from different steps never merge into one group.\n */\nexport interface TranscriptToolBlock {\n kind: 'tools';\n key: string;\n parts: AnyToolUIPart[];\n /** The same calls, each with its human-decision state. Same order as `parts`. */\n calls: TranscriptToolCall[];\n /**\n * The same calls as a tree: every call whose parent is NOT in this block, each carrying its\n * nested calls in `children`. Equal to `calls` when nothing is nested.\n */\n roots: TranscriptToolCall[];\n /**\n * The run folded into activity groups (\"Database query ×3\"), over `roots`, keyed by each tool's\n * presentation label (else its name). For another grouping, call `groupToolActivity` yourself.\n */\n activity: ToolActivityGroup[];\n}\n\n/**\n * A component the server pushed into the message (the stream's `ui` frame, or a persisted\n * `data-ui` part). Rendered by looking `component` up in the host's own registry.\n */\nexport interface TranscriptUiBlock {\n kind: 'ui';\n key: string;\n /** The component's identity within the message. */\n id: string;\n component: string;\n props: Record<string, unknown>;\n /** Schema version of `props`; `null` when the server did not stamp one. */\n version: number | null;\n fallbackText?: string;\n componentVersions?: Record<string, number>;\n /** The tool call that pushed it (`ctx.emitUi`); `null` for a component pushed outside a tool. */\n toolCallId: string | null;\n /**\n * A preview drawn while the model writes the call's arguments (genui `streaming: 'partial'`):\n * unvalidated, replaced in place by the final push. Absent on a final component.\n */\n partial?: true;\n}\n\n/** One choice a question offers, with its live selection state. */\nexport interface TranscriptQuestionOption {\n value: string;\n label: string;\n /** A single character the request suggested as a shortcut; `null` when it suggested none. */\n hotkey: string | null;\n isSelected: boolean;\n /** Pre-picked by the agent — what an untouched question submits as. */\n isDefault: boolean;\n /** Single choice: replaces the selection. Multiple: adds or removes this value. */\n select: () => void;\n}\n\n/** One question of a set, numbered against the whole. */\nexport interface TranscriptQuestion {\n id: string;\n prompt: string;\n /** A line of help under the prompt; `null` when the request gave none. */\n description: string | null;\n /**\n * How the answer is typed — `{ type, placeholder?, required?, min?, max?, pattern? }` — or `null`\n * for a plain pick from `options`. Render the control from `input.type`; `select` still picks\n * from `options`.\n */\n input: ElicitationInput | null;\n multiple: boolean;\n /** 1-based. The request carries every question up front, so \"Question 1 of N\" is honest. */\n position: number;\n options: TranscriptQuestionOption[];\n selected: string[];\n /**\n * The user has not touched this question, so a submission leaves it out and the server applies\n * the same defaults it showed. Distinct from \"selected happens to equal the defaults\": only the\n * first is recorded as `defaulted` rather than as a choice the user made.\n */\n isPristine: boolean;\n /** The first selected value, or `''` — what a single text/number/date field shows. */\n value: string;\n /**\n * Set a typed answer from whatever the control produced (a string, a number, a checkbox's\n * boolean, a `Date`, a list); coerced to the question's canonical strings with `coerceAnswer`.\n * `null`/`''` clears it. Does nothing once the set settled.\n */\n setValue: (raw: RawAnswer) => void;\n /**\n * Why the current selection would be refused (the server's own rules — `validateAnswer`), or\n * `null`. A pristine required question with no default reads `requires an answer`; show it once\n * the user tried to submit, or right away — the model does not decide that for you.\n */\n error: string | null;\n}\n\n/** How a question set settled, once it did. */\nexport interface TranscriptElicitationOutcome {\n answers: Record<string, string[]>;\n /** The user declined to answer and let the agent proceed on its own picks. */\n skipped: boolean;\n /** Questions filled from their own defaults rather than by the human. */\n defaulted: string[];\n /** The questions against the chosen labels, as the model read them back. */\n summary: string | null;\n /** Who answered (or skipped) — an approval's `decidedBy`. `null` when the run did not record it. */\n answeredBy: string | null;\n /** The surface it came through (`'web'`, `'slack'`, …) — an approval's `decidedVia`. */\n answeredVia: string | null;\n}\n\n/**\n * A question set the run put to the user, parked until someone settles it — the intake an agent\n * declares and the model's own `ask` produce the same block, because the loop streams the same\n * frame for both.\n */\nexport interface TranscriptElicitationBlock {\n kind: 'elicitation';\n key: string;\n /** The parked tool call — what `answer`/`skip` route by. */\n toolCallId: string;\n preamble: string | null;\n questions: TranscriptQuestion[];\n questionCount: number;\n /** Still waiting on a human. */\n isPending: boolean;\n /** Every question's current selection is acceptable (no question has an `error`). */\n isValid: boolean;\n outcome: TranscriptElicitationOutcome | null;\n /** A failed submission — the run is still parked, so the form stays live. */\n error: string | null;\n /** The server's machine-readable reason for {@link error} (`run_not_active`, …), when it gave one. */\n errorCode: string | null;\n answer: TranscriptSettleState;\n skip: TranscriptSettleState;\n}\n\n/** One retrieved passage, as it rides a retrieval tool call's output. Mirrors core's `Passage`. */\nexport interface RetrievedPassage {\n id: string;\n text: string;\n score: number;\n /** Citation-facing origin — a document title, URL or row id. */\n source?: string;\n metadata?: Record<string, unknown>;\n}\n\n/** The passages of one origin, folded together so a citation line reads once per source. */\nexport interface TranscriptSource {\n /** The `source` string the retriever stamped, falling back to the passage id when it stamped none. */\n id: string;\n label: string;\n passageCount: number;\n /** Highest relevance among this source's passages; the scale is the retriever's. */\n topScore: number;\n passages: RetrievedPassage[];\n}\n\n/**\n * The provenance behind an answer: a run of CONSECUTIVE retrieval tool parts, aggregated by origin.\n * Detection is structural — a tool output shaped `{ passages: [{ id, text, ... }] }` — because the\n * tool's NAME is not fixed: inject-mode retrieval persists as `retrieve`, and `createRetrievalTool`\n * lets the host rename `search_knowledge` to anything.\n */\nexport interface TranscriptSourcesBlock {\n kind: 'sources';\n key: string;\n /** What was searched, when the tool call recorded a `{ query }` input. */\n query: string | null;\n sources: TranscriptSource[];\n passageCount: number;\n}\n\nexport type TranscriptBlock =\n | TranscriptTextBlock\n | TranscriptFilesBlock\n | TranscriptReasoningBlock\n | TranscriptToolBlock\n | TranscriptSourcesBlock\n | TranscriptElicitationBlock\n | TranscriptUiBlock;\n\n/** Where a question set's selection state is held, and where its settlement is sent. */\nexport interface ElicitationBlockOptions {\n /** The values a question is showing, or `undefined` while the user has not touched it. */\n picked: (toolCallId: string, questionId: string) => string[] | undefined;\n pick: (toolCallId: string, questionId: string, values: string[]) => void;\n canAnswer: boolean;\n canSkip: boolean;\n answer: (toolCallId: string) => void;\n skip: (toolCallId: string) => void;\n /** Which decision this call is sending, or `null` for none. */\n submitting: (toolCallId: string) => SettleAction | null;\n errorOf: (toolCallId: string) => string | null;\n /** The `code` of the error `errorOf` reports, when the server sent one. */\n errorCodeOf?: (toolCallId: string) => string | null;\n}\n\n/** Where an approval decision is sent, and what the last one did. */\nexport interface ApprovalBlockOptions {\n canApprove: boolean;\n canReject: boolean;\n approve: (toolCallId: string, options?: ApproveOptions, target?: ApprovalTarget) => void;\n reject: (toolCallId: string, target?: ApprovalTarget) => void;\n /** Which decision this call is sending, or `null` for none. */\n submitting: (toolCallId: string) => SettleAction | null;\n errorOf: (toolCallId: string) => string | null;\n /** The `code` of the error `errorOf` reports, when the server sent one. */\n errorCodeOf?: (toolCallId: string) => string | null;\n}\n\nexport interface BuildBlocksOptions {\n /** Disclosure lookup for a reasoning run; `isStreaming` is the fallback when untouched. */\n isReasoningOpen: (key: string, isStreaming: boolean) => boolean;\n toggleReasoning: (key: string, open?: boolean) => void;\n /**\n * Lift retrieval tool parts out of the tool run into a `sources` block. Off by default, so a\n * renderer wired to draw tool cards keeps receiving them as the tool calls they are.\n */\n sources?: boolean;\n /**\n * Lift a question set out of the tool run into an `elicitation` block. Omitted → it stays a tool\n * card, which is all a host that has nowhere to send an answer could render anyway.\n */\n elicitation?: ElicitationBlockOptions;\n /** Wire approve/reject onto the calls parked on a human. Omitted → they are reported, not actionable. */\n approval?: ApprovalBlockOptions;\n /** Server-declared tool presentations (`useToolCatalog`), for each call's `description`. */\n toolCatalog?: ToolCatalog;\n}\n\n/**\n * Walk a message's parts into renderable blocks, buffering consecutive tool parts into one run and\n * consecutive files into one strip. A `data-ui` part becomes a `ui` block. A\n * `data-approval-requested` part is metadata about a call — it is folded into that call's\n * `approval` and takes no position of its own. Other `data-*` parts are dropped rather than guessed\n * at, but they still terminate a tool run — their position in the transcript is meaningful even\n * when their content is not modelled here.\n */\nexport function buildTranscriptBlocks(\n message: UIMessage,\n options: BuildBlocksOptions,\n): TranscriptBlock[] {\n const blocks: TranscriptBlock[] = [];\n let toolBuffer: AnyToolUIPart[] = [];\n let retrievalBuffer: AnyToolUIPart[] = [];\n let fileBuffer: FileUIPart[] = [];\n let toolCounter = 0;\n let textCounter = 0;\n let fileCounter = 0;\n let reasoningCounter = 0;\n let sourcesCounter = 0;\n let elicitationCounter = 0;\n const approvals = readApprovals(message.parts ?? []);\n\n function flushTools() {\n if (toolBuffer.length === 0) {\n return;\n }\n const calls = toolBuffer.map((part) =>\n buildToolCall(\n part,\n options.approval,\n approvalOf(approvals.get(part.toolCallId), part),\n options.toolCatalog,\n ),\n );\n const roots = nestToolCalls(calls);\n blocks.push({\n kind: 'tools',\n key: `${message.id}-tools-${toolCounter++}`,\n parts: toolBuffer,\n calls,\n roots,\n activity: groupToolActivity(roots, {\n ...(options.toolCatalog !== undefined ? { catalog: options.toolCatalog } : {}),\n }),\n });\n toolBuffer = [];\n }\n\n function flushSources() {\n if (retrievalBuffer.length === 0) {\n return;\n }\n blocks.push(buildSourcesBlock(`${message.id}-sources-${sourcesCounter++}`, retrievalBuffer));\n retrievalBuffer = [];\n }\n\n function flushFiles() {\n if (fileBuffer.length === 0) {\n return;\n }\n blocks.push({\n kind: 'files',\n key: `${message.id}-files-${fileCounter++}`,\n files: fileBuffer.map((part) => ({\n url: part.url,\n mediaType: part.mediaType,\n filename: part.filename ?? null,\n isImage: part.mediaType.startsWith('image/'),\n })),\n });\n fileBuffer = [];\n }\n\n function flushAll() {\n flushTools();\n flushSources();\n flushFiles();\n }\n\n // Calls whose outcome has arrived: a preview of their input still standing is not the answer.\n const settledCalls = new Set<string>();\n for (const part of message.parts ?? []) {\n if (\n isToolUIPart(part) &&\n (part.state === 'output-available' ||\n part.state === 'output-error' ||\n part.state === 'output-denied')\n ) {\n settledCalls.add(part.toolCallId);\n }\n }\n\n for (const part of message.parts ?? []) {\n if (isToolUIPart(part)) {\n const elicitation = options.elicitation;\n if (elicitation !== undefined) {\n const request = readElicitationRequest(part);\n if (request !== null) {\n flushAll();\n blocks.push(\n buildElicitationBlock(\n `${message.id}-elicitation-${elicitationCounter++}`,\n part,\n request,\n elicitation,\n ),\n );\n continue;\n }\n }\n if (options.sources === true && readPassages(part) !== null) {\n flushTools();\n retrievalBuffer.push(part);\n continue;\n }\n flushSources();\n flushFiles();\n toolBuffer.push(part);\n continue;\n }\n if (isFileUIPart(part)) {\n flushTools();\n flushSources();\n fileBuffer.push(part);\n continue;\n }\n if (part.type === APPROVAL_PART || part.type === SETTLED_PART) {\n continue;\n }\n flushAll();\n if (isDataUIPart(part)) {\n const ui = part.type === UI_PART ? readUiComponent(part) : null;\n // A preview stands only while its call is being written: withdrawn (no props), or left by a\n // call that settled without replacing it, it is nothing to draw.\n if (\n ui?.partial === true &&\n (Object.keys(ui.props).length === 0 ||\n (ui.toolCallId !== null && settledCalls.has(ui.toolCallId)))\n ) {\n continue;\n }\n if (ui !== null) {\n blocks.push({ kind: 'ui', key: `${message.id}-ui-${ui.id}`, ...ui });\n }\n continue;\n }\n if (isTextUIPart(part)) {\n blocks.push({\n kind: 'text',\n key: `${message.id}-text-${textCounter++}`,\n text: part.text,\n isStreaming: part.state === 'streaming',\n });\n continue;\n }\n if (isReasoningUIPart(part)) {\n const key = `${message.id}-reasoning-${reasoningCounter++}`;\n const isStreaming = part.state === 'streaming';\n blocks.push({\n kind: 'reasoning',\n key,\n text: part.text,\n isStreaming,\n durationMs: readReasoningMs(part),\n isOpen: options.isReasoningOpen(key, isStreaming),\n toggle: (open?: boolean) => options.toggleReasoning(key, open),\n });\n }\n }\n flushAll();\n return blocks;\n}\n\n/**\n * Fold a run of retrieval parts into one provenance block. Sources keep the order the retriever\n * returned them in — that order IS the ranking — and the query is taken from the first call that\n * recorded one.\n */\nfunction buildSourcesBlock(key: string, parts: AnyToolUIPart[]): TranscriptSourcesBlock {\n const byId = new Map<string, TranscriptSource>();\n let query: string | null = null;\n let passageCount = 0;\n\n for (const part of parts) {\n query ??= readQuery(part);\n for (const passage of readPassages(part) ?? []) {\n passageCount++;\n const id = passage.source ?? passage.id;\n const existing = byId.get(id);\n if (existing) {\n existing.passageCount++;\n existing.topScore = Math.max(existing.topScore, passage.score);\n existing.passages.push(passage);\n continue;\n }\n byId.set(id, {\n id,\n label: passage.source ?? passage.id,\n passageCount: 1,\n topScore: passage.score,\n passages: [passage],\n });\n }\n }\n\n return { kind: 'sources', key, query, sources: [...byId.values()], passageCount };\n}\n\n/** A call whose output has landed one way or another is nobody's decision any more. */\nfunction isSettled(state: string): boolean {\n return state === 'output-available' || state === 'output-error' || state === 'output-denied';\n}\n\nfunction toolKind(part: AnyToolUIPart): string | undefined {\n const metadata = (part as { toolMetadata?: unknown }).toolMetadata;\n return isRecord(metadata) && typeof metadata.toolKind === 'string'\n ? metadata.toolKind\n : undefined;\n}\n\n/**\n * An `action` tool's input lands and then nothing follows: the loop waits on a person between the\n * call and its execution. So a call classified `action` and stuck at `input-available` IS the\n * pending approval — there is no separate frame that says so.\n */\nfunction isAwaitingApproval(part: AnyToolUIPart): boolean {\n if (part.state === 'approval-requested') {\n return true;\n }\n if (part.state !== 'input-available') {\n return false;\n }\n // A question set parks the same way and is persisted as an action, but it is settled by\n // answering it, not by approving it.\n return toolKind(part) === 'action' && readElicitationRequest(part) === null;\n}\n\nfunction toolParentId(part: AnyToolUIPart): string | null {\n const metadata = (part as { toolMetadata?: unknown }).toolMetadata;\n return isRecord(metadata) && typeof metadata.parentId === 'string' ? metadata.parentId : null;\n}\n\n/**\n * Arrange a block's calls into a tree by `parentId`. A call whose parent is not in the block (or\n * that names itself, or would close a cycle) stays a root, so nothing a runner sends is ever lost\n * from the tree — at worst it is shown flat.\n */\nfunction nestToolCalls(calls: TranscriptToolCall[]): TranscriptToolCall[] {\n const byId = new Map(calls.map((call) => [call.toolCallId, call]));\n const roots: TranscriptToolCall[] = [];\n for (const call of calls) {\n const parent = call.parentId !== null ? byId.get(call.parentId) : undefined;\n if (parent === undefined || isAncestor(call, parent, byId)) {\n roots.push(call);\n continue;\n }\n parent.children.push(call);\n }\n return roots;\n}\n\n/** True when `candidate` is `call` itself or sits under it — attaching would close a cycle. */\nfunction isAncestor(\n call: TranscriptToolCall,\n candidate: TranscriptToolCall,\n byId: Map<string, TranscriptToolCall>,\n): boolean {\n const seen = new Set<string>();\n let current: TranscriptToolCall | undefined = candidate;\n while (current !== undefined && !seen.has(current.toolCallId)) {\n if (current.toolCallId === call.toolCallId) {\n return true;\n }\n seen.add(current.toolCallId);\n current = current.parentId !== null ? byId.get(current.parentId) : undefined;\n }\n return false;\n}\n\nfunction buildToolCall(\n part: AnyToolUIPart,\n options: ApprovalBlockOptions | undefined,\n approval: TranscriptApproval | null,\n catalog: ToolCatalog | undefined,\n): TranscriptToolCall {\n const toolCallId = part.toolCallId;\n const awaiting =\n approval?.target?.kind === 'proposal'\n ? approval.status === 'pending'\n : isAwaitingApproval(part);\n // Per decision, not per call: the two are never in flight together, and a surface that read one\n // flag for both would report the refusal it is carrying out as an approval in progress.\n const sending = awaiting ? (options?.submitting(toolCallId) ?? null) : null;\n return {\n part,\n toolCallId,\n name: getToolName(part),\n toolKind: toolKind(part) ?? null,\n parentId: toolParentId(part),\n children: [],\n approval,\n description: proposalDescription(\n describeToolCall(\n part,\n catalog,\n approval?.confirmation === undefined ? {} : { confirmation: approval.confirmation },\n ),\n approval,\n ),\n isAwaitingApproval: awaiting,\n approve: {\n available: awaiting && options?.canApprove === true,\n isSubmitting: sending === 'approve',\n // Read by field, not passed through: `onClick={call.approve.run}` hands this a click event,\n // and a host's handler must not receive that as its options.\n run: (approveOptions?: ApproveOptions) =>\n approval?.target === undefined\n ? approveOptions?.remember === true\n ? options?.approve(toolCallId, { remember: true })\n : options?.approve(toolCallId)\n : options?.approve(\n toolCallId,\n approveOptions?.remember === true ? { remember: true } : undefined,\n approval.target,\n ),\n },\n reject: {\n available: awaiting && options?.canReject === true,\n isSubmitting: sending === 'reject',\n run: () =>\n approval?.target === undefined\n ? options?.reject(toolCallId)\n : options?.reject(toolCallId, approval.target),\n },\n error: options?.errorOf(toolCallId) ?? null,\n errorCode: options?.errorCodeOf?.(toolCallId) ?? null,\n };\n}\n\n/** A question as the request wrote it, before any of the user's picks are applied. */\ninterface ElicitationQuestionData {\n id: string;\n prompt: string;\n description: string | null;\n input: ElicitationInput | null;\n multiple: boolean;\n allowFreeText: boolean;\n defaults: string[];\n options: { value: string; label: string; hotkey: string | null }[];\n}\n\n/**\n * The question set a tool call carries, or `null` for any other tool. Read from the call's INPUT\n * and by shape rather than by tool name: the same set is authored by an agent's intake and by the\n * model's own `ask`, it replays from the store under whatever name the row holds, and a client\n * that learned to recognise one name would render only half of them.\n */\nfunction readElicitationRequest(\n part: AnyToolUIPart,\n): { preamble: string | null; questions: ElicitationQuestionData[] } | null {\n const input = (part as { input?: unknown }).input;\n if (!isRecord(input) || !Array.isArray(input.questions) || input.questions.length === 0) {\n return null;\n }\n const questions: ElicitationQuestionData[] = [];\n for (const candidate of input.questions) {\n if (\n !isRecord(candidate) ||\n typeof candidate.id !== 'string' ||\n typeof candidate.prompt !== 'string'\n ) {\n return null;\n }\n // A typed question may carry no options; anything else is a pick and must offer some.\n const input = readElicitationInput(candidate.input) ?? null;\n const rawOptions = Array.isArray(candidate.options) ? candidate.options : [];\n if (rawOptions.length === 0 && (input === null || input.type === 'select')) {\n return null;\n }\n const options: ElicitationQuestionData['options'] = [];\n for (const option of rawOptions) {\n if (\n !isRecord(option) ||\n typeof option.value !== 'string' ||\n typeof option.label !== 'string'\n ) {\n return null;\n }\n options.push({\n value: option.value,\n label: option.label,\n hotkey: typeof option.hotkey === 'string' ? option.hotkey : null,\n });\n }\n questions.push({\n id: candidate.id,\n prompt: candidate.prompt,\n description: typeof candidate.description === 'string' ? candidate.description : null,\n input,\n multiple: candidate.multiple === true,\n allowFreeText: candidate.allowFreeText === true,\n defaults: Array.isArray(candidate.defaults)\n ? candidate.defaults.filter((value): value is string => typeof value === 'string')\n : [],\n options,\n });\n }\n return {\n preamble: typeof input.preamble === 'string' ? input.preamble : null,\n questions,\n };\n}\n\n/** What the run recorded for a settled question set, or `null` when it settled as something else. */\nfunction readElicitationOutcome(part: AnyToolUIPart): TranscriptElicitationOutcome | null {\n const output = (part as { output?: unknown }).output;\n if (!isRecord(output) || !isRecord(output.answers) || typeof output.skipped !== 'boolean') {\n return null;\n }\n const answers: Record<string, string[]> = {};\n for (const [id, values] of Object.entries(output.answers)) {\n answers[id] = Array.isArray(values)\n ? values.filter((value): value is string => typeof value === 'string')\n : [];\n }\n return {\n answers,\n skipped: output.skipped,\n defaulted: Array.isArray(output.defaulted)\n ? output.defaulted.filter((id): id is string => typeof id === 'string')\n : [],\n summary: typeof output.summary === 'string' ? output.summary : null,\n answeredBy: typeof output.answeredBy === 'string' ? output.answeredBy : null,\n answeredVia: typeof output.answeredVia === 'string' ? output.answeredVia : null,\n };\n}\n\nfunction buildElicitationBlock(\n key: string,\n part: AnyToolUIPart,\n request: { preamble: string | null; questions: ElicitationQuestionData[] },\n options: ElicitationBlockOptions,\n): TranscriptElicitationBlock {\n const toolCallId = part.toolCallId;\n const isPending = !isSettled(part.state);\n const outcome = isPending ? null : readElicitationOutcome(part);\n const questions = request.questions.map((question, index) => {\n const picked = isPending ? options.picked(toolCallId, question.id) : undefined;\n const selected = picked ?? outcome?.answers[question.id] ?? question.defaults;\n const pick = (values: string[]) => options.pick(toolCallId, question.id, values);\n // The same rules the answer route applies, over the same question shape core reads.\n const error = isPending\n ? validateElicitationAnswer(\n {\n id: question.id,\n prompt: question.prompt,\n options: question.options.map(({ value, label }) => ({ value, label })),\n ...(question.input !== null ? { input: question.input } : {}),\n ...(question.multiple ? { multiple: true } : {}),\n ...(question.allowFreeText ? { allowFreeText: true } : {}),\n },\n selected,\n )\n : null;\n return {\n id: question.id,\n prompt: question.prompt,\n description: question.description,\n input: question.input,\n multiple: question.multiple,\n position: index + 1,\n selected,\n value: selected[0] ?? '',\n error,\n setValue: (raw: RawAnswer) => {\n if (isPending) {\n pick(coerceAnswer(question, raw));\n }\n },\n isPristine: isPending\n ? picked === undefined\n : (outcome?.defaulted.includes(question.id) ?? true),\n options: question.options.map((option) => ({\n value: option.value,\n label: option.label,\n hotkey: option.hotkey,\n isSelected: selected.includes(option.value),\n isDefault: question.defaults.includes(option.value),\n select: () => {\n if (!isPending) {\n return;\n }\n if (!question.multiple) {\n pick([option.value]);\n return;\n }\n pick(\n selected.includes(option.value)\n ? selected.filter((value) => value !== option.value)\n : [...selected, option.value],\n );\n },\n })),\n };\n });\n const sending = isPending ? options.submitting(toolCallId) : null;\n return {\n kind: 'elicitation',\n key,\n toolCallId,\n preamble: request.preamble,\n questions,\n questionCount: questions.length,\n isPending,\n isValid: questions.every((question) => question.error === null),\n outcome,\n error: options.errorOf(toolCallId),\n errorCode: options.errorCodeOf?.(toolCallId) ?? null,\n answer: {\n available: isPending && options.canAnswer,\n isSubmitting: sending === 'answer',\n run: () => options.answer(toolCallId),\n },\n skip: {\n available: isPending && options.canSkip,\n isSubmitting: sending === 'skip',\n run: () => options.skip(toolCallId),\n },\n };\n}\n\nconst UI_PART = 'data-ui';\nconst APPROVAL_PART = 'data-approval-requested';\nconst SETTLED_PART = 'data-approval-settled';\n\n/** What the approval parts of a message say about one call, before its own state is consulted. */\ninterface ApprovalParts {\n target?: ApprovalTarget;\n executionStatus?: TranscriptApproval['executionStatus'];\n confirmation?: ToolConfirmation;\n approver: string | null;\n expiresAt: string | null;\n reason: string | null;\n status: Exclude<TranscriptApprovalStatus, 'pending'> | null;\n remember: boolean;\n decidedBy: string | null;\n decidedVia: string | null;\n decisionReason: string | null;\n}\n\nconst SETTLED_STATUSES: readonly string[] = ['approved', 'rejected', 'expired', 'superseded'];\n\n/** The approval metadata on a message, by call id. The latest frame of each kind for a call wins. */\nfunction readApprovals(parts: UIMessage['parts']): Map<string, ApprovalParts> {\n const out = new Map<string, ApprovalParts>();\n const entry = (id: string): ApprovalParts => {\n let found = out.get(id);\n if (found === undefined) {\n found = {\n approver: null,\n expiresAt: null,\n reason: null,\n status: null,\n remember: false,\n decidedBy: null,\n decidedVia: null,\n decisionReason: null,\n };\n out.set(id, found);\n }\n return found;\n };\n for (const part of parts) {\n if (\n part.type !== APPROVAL_PART &&\n part.type !== SETTLED_PART &&\n part.type !== 'data-action-proposal'\n ) {\n continue;\n }\n const data = (part as DataUIPart<Record<string, unknown>>).data;\n if (!isRecord(data) || typeof data.id !== 'string') {\n continue;\n }\n const approval = entry(data.id);\n if (part.type === APPROVAL_PART || part.type === 'data-action-proposal') {\n if (\n isRecord(data.target) &&\n data.target.kind === 'proposal' &&\n typeof data.target.proposalId === 'string'\n ) {\n approval.target = {\n kind: 'proposal',\n proposalId: data.target.proposalId,\n ...(typeof data.target.threadId === 'string' ? { threadId: data.target.threadId } : {}),\n };\n }\n if (part.type === 'data-action-proposal') {\n if (\n typeof data.status === 'string' &&\n ['pending', 'approved', 'rejected', 'expired', 'superseded'].includes(data.status)\n )\n approval.status =\n data.status === 'pending'\n ? null\n : (data.status as Exclude<TranscriptApprovalStatus, 'pending'>);\n if (\n data.executionStatus === null ||\n data.executionStatus === 'queued' ||\n data.executionStatus === 'executing' ||\n data.executionStatus === 'succeeded' ||\n data.executionStatus === 'failed'\n )\n approval.executionStatus = data.executionStatus;\n approval.remember = data.remember === true;\n approval.decidedBy = typeof data.decidedBy === 'string' ? data.decidedBy : null;\n approval.decidedVia = typeof data.decidedVia === 'string' ? data.decidedVia : null;\n }\n if (typeof data.approver !== 'string') {\n continue;\n }\n approval.approver = data.approver;\n approval.expiresAt = typeof data.expiresAt === 'string' ? data.expiresAt : null;\n if (\n isRecord(data.confirmation) &&\n typeof data.confirmation.title === 'string' &&\n typeof data.confirmation.verb === 'string' &&\n (data.confirmation.detail === undefined || typeof data.confirmation.detail === 'string')\n ) {\n approval.confirmation = {\n title: data.confirmation.title,\n verb: data.confirmation.verb,\n ...(typeof data.confirmation.detail === 'string'\n ? { detail: data.confirmation.detail }\n : {}),\n };\n }\n approval.reason = typeof data.reason === 'string' ? data.reason : null;\n continue;\n }\n if (typeof data.status !== 'string' || !SETTLED_STATUSES.includes(data.status)) {\n continue;\n }\n approval.status = data.status as ApprovalParts['status'];\n if (approval.approver === null && typeof data.approver === 'string') {\n approval.approver = data.approver;\n }\n approval.remember = data.remember === true;\n approval.decidedBy = typeof data.decidedBy === 'string' ? data.decidedBy : null;\n approval.decidedVia = typeof data.decidedVia === 'string' ? data.decidedVia : null;\n approval.decisionReason = typeof data.reason === 'string' ? data.reason : null;\n }\n return out;\n}\n\n/**\n * One call's approval: its parts, with the status completed from the call's own state when no\n * settlement was streamed. `null` when nothing on the message says who decides.\n */\nfunction approvalOf(\n parts: ApprovalParts | undefined,\n call: AnyToolUIPart,\n): TranscriptApproval | null {\n if (parts === undefined || parts.approver === null) {\n return null;\n }\n return {\n approver: parts.approver,\n ...(parts.target === undefined ? {} : { target: parts.target }),\n ...(parts.executionStatus === undefined ? {} : { executionStatus: parts.executionStatus }),\n ...(parts.confirmation !== undefined ? { confirmation: parts.confirmation } : {}),\n expiresAt: parts.expiresAt,\n reason: parts.reason,\n status: parts.status ?? (parts.target?.kind === 'proposal' ? 'pending' : statusFromPart(call)),\n remember: parts.remember,\n decidedBy: parts.decidedBy,\n decidedVia: parts.decidedVia,\n decisionReason: parts.decisionReason,\n };\n}\n\nfunction statusFromPart(call: AnyToolUIPart): TranscriptApprovalStatus {\n if (call.state === 'output-denied') {\n return 'rejected';\n }\n if (call.state === 'output-available' || call.state === 'output-error') {\n return 'approved';\n }\n return 'pending';\n}\n\n/** A pushed component, or `null` when the part does not carry one this model can address. */\nfunction readUiComponent(\n part: DataUIPart<Record<string, unknown>>,\n): Omit<TranscriptUiBlock, 'kind' | 'key'> | null {\n const data = part.data;\n if (!isRecord(data) || typeof data.component !== 'string') {\n return null;\n }\n const id = typeof data.id === 'string' ? data.id : part.id;\n if (id === undefined) {\n return null;\n }\n return {\n id,\n component: data.component,\n props: isRecord(data.props) ? data.props : {},\n version: typeof data.version === 'number' ? data.version : null,\n ...(isRecord(data.componentVersions) &&\n Object.values(data.componentVersions).every(\n (version) => typeof version === 'number' && Number.isSafeInteger(version) && version > 0,\n )\n ? { componentVersions: { ...data.componentVersions } as Record<string, number> }\n : {}),\n ...(typeof data.fallbackText === 'string' ? { fallbackText: data.fallbackText } : {}),\n toolCallId: typeof data.toolCallId === 'string' ? data.toolCallId : null,\n ...(data.partial === true ? { partial: true as const } : {}),\n };\n}\n\nfunction isRecord(value: unknown): value is Record<string, unknown> {\n return typeof value === 'object' && value !== null;\n}\n\nfunction readQuery(part: AnyToolUIPart): string | null {\n const input = (part as { input?: unknown }).input;\n if (!isRecord(input) || typeof input.query !== 'string') {\n return null;\n }\n return input.query;\n}\n\n/**\n * The passages on a settled retrieval tool call, or `null` for any other tool. A call still in\n * flight, or one whose output is not a non-empty list of `{ id, text }` passages, is not provenance\n * yet and stays an ordinary tool part.\n */\nfunction readPassages(part: AnyToolUIPart): RetrievedPassage[] | null {\n const output = (part as { output?: unknown }).output;\n if (!isRecord(output) || !Array.isArray(output.passages) || output.passages.length === 0) {\n return null;\n }\n const passages: RetrievedPassage[] = [];\n for (const candidate of output.passages) {\n if (\n !isRecord(candidate) ||\n typeof candidate.id !== 'string' ||\n typeof candidate.text !== 'string'\n ) {\n return null;\n }\n passages.push({\n id: candidate.id,\n text: candidate.text,\n score: typeof candidate.score === 'number' ? candidate.score : 0,\n ...(typeof candidate.source === 'string' ? { source: candidate.source } : {}),\n ...(isRecord(candidate.metadata) ? { metadata: candidate.metadata } : {}),\n });\n }\n return passages;\n}\n\n/** The message's prose, joined for the clipboard. Reasoning is excluded — it is not the answer. */\nexport function extractMessageText(parts: UIMessage['parts'] | undefined): string {\n const out: string[] = [];\n for (const part of parts ?? []) {\n if (isTextUIPart(part)) {\n out.push(part.text);\n }\n }\n return out.join('\\n\\n').trim();\n}\n\nexport interface UsageSummary extends MessageUsageInfo {\n totalTokens: number;\n /** `$0`, `$0.0123`, `$0.012`, `$1.23` — precision follows magnitude so sub-cent turns stay legible. */\n costLabel: string;\n tokensLabel: string;\n}\n\nexport function describeUsage(usage: MessageUsageInfo): UsageSummary {\n const totalTokens = usage.inputTokens + usage.outputTokens;\n return {\n ...usage,\n totalTokens,\n costLabel: formatCostUsd(usage.costUsd),\n tokensLabel: formatTokensShort(totalTokens),\n };\n}\n\nexport interface TimestampInfo {\n iso: string;\n date: Date;\n /** \"just now\" / \"5 min. ago\" / \"Mar 3\" — see {@link formatRelativeTime}. */\n relative: string;\n absolute: string;\n}\n\n/** `null` for an unparseable stamp, so a bad `created_at` renders nothing instead of \"Invalid Date\". */\nexport function describeTimestamp(createdAt: string | null | undefined): TimestampInfo | null {\n if (createdAt == null) {\n return null;\n }\n const date = new Date(createdAt);\n if (Number.isNaN(date.getTime())) {\n return null;\n }\n return {\n iso: createdAt,\n date,\n relative: formatRelativeTime(date),\n absolute: date.toLocaleString(undefined, { dateStyle: 'medium', timeStyle: 'short' }),\n };\n}\n\nconst RELATIVE_TIME = new Intl.RelativeTimeFormat(undefined, { numeric: 'auto', style: 'narrow' });\nconst ONE_WEEK_MS = 7 * 24 * 60 * 60 * 1000;\n\n/**\n * \"just now\" within ±10s (server `created_at` can land a few ms ahead of the client clock), a\n * relative phrase up to a week, then a calendar date. Uses Intl.RelativeTimeFormat — no date-fns.\n */\nexport function formatRelativeTime(date: Date): string {\n const diffMs = Date.now() - date.getTime();\n if (Math.abs(diffMs) < 10_000) {\n return 'just now';\n }\n if (diffMs > ONE_WEEK_MS) {\n return date.toLocaleDateString(undefined, { month: 'short', day: 'numeric' });\n }\n const minutes = Math.round(-diffMs / 60_000);\n if (Math.abs(minutes) < 60) {\n return RELATIVE_TIME.format(minutes, 'minute');\n }\n const hours = Math.round(-diffMs / 3_600_000);\n if (Math.abs(hours) < 24) {\n return RELATIVE_TIME.format(hours, 'hour');\n }\n return RELATIVE_TIME.format(Math.round(-diffMs / 86_400_000), 'day');\n}\n\nfunction formatTokensShort(n: number): string {\n if (n < 1_000) {\n return `${n} tokens`;\n }\n if (n < 10_000) {\n return `${(n / 1_000).toFixed(1)}k tokens`;\n }\n return `${Math.round(n / 1_000)}k tokens`;\n}\n\nfunction formatCostUsd(cost: number | null): string {\n if (cost === null) {\n return '—';\n }\n if (cost === 0) {\n return '$0';\n }\n if (cost < 0.01) {\n return `$${cost.toFixed(4)}`;\n }\n if (cost < 1) {\n return `$${cost.toFixed(3)}`;\n }\n return `$${cost.toFixed(2)}`;\n}\n\nfunction proposalDescription(\n description: TranscriptToolCall['description'],\n approval: TranscriptApproval | null,\n): TranscriptToolCall['description'] {\n if (approval?.target?.kind !== 'proposal') return description;\n const status =\n approval.status === 'pending'\n ? 'awaiting-approval'\n : approval.status === 'approved'\n ? (approval.executionStatus ?? 'queued')\n : 'denied';\n const phrase =\n status === 'awaiting-approval'\n ? 'Awaiting approval'\n : status === 'queued'\n ? 'Queued'\n : status === 'executing'\n ? 'Executing'\n : status === 'succeeded'\n ? 'Succeeded'\n : status === 'failed'\n ? 'Failed'\n : approval.status === 'expired'\n ? 'Expired'\n : approval.status === 'superseded'\n ? 'Replaced'\n : 'Rejected';\n return { ...description, status, phrase, result: null };\n}\n","import type { ElicitationInputType, ElicitationQuestion } from '@dudousxd/nestjs-agent-core';\n\nexport {\n type ElicitationInput,\n type ElicitationInputType,\n validateElicitationAnswer as validateAnswer,\n validateElicitationValue as validateAnswerValue,\n} from '@dudousxd/nestjs-agent-core';\n\n/** What a form control can hand over: a field's value, a checkbox's state, a picked date, a list. */\nexport type RawAnswer = string | number | boolean | Date | null | undefined | readonly RawAnswer[];\n\n/** The question fields {@link coerceAnswer} reads. A transcript question and a core one both fit. */\nexport type CoercibleQuestion = Pick<ElicitationQuestion, 'multiple'> & {\n input?: { type: ElicitationInputType } | null;\n};\n\nfunction pad(value: number): string {\n return String(value).padStart(2, '0');\n}\n\n/** A `Date` as the calendar day the person picked — local time, which is the day they saw. */\nfunction toDay(date: Date): string | null {\n if (Number.isNaN(date.getTime())) {\n return null;\n }\n return `${date.getFullYear()}-${pad(date.getMonth() + 1)}-${pad(date.getDate())}`;\n}\n\nfunction coerceOne(type: ElicitationInputType | undefined, raw: RawAnswer): string | null {\n if (raw === null || raw === undefined) {\n return null;\n }\n if (Array.isArray(raw)) {\n return null;\n }\n if (raw instanceof Date) {\n return type === 'date' || type === undefined ? toDay(raw) : raw.toISOString();\n }\n if (typeof raw === 'boolean') {\n return raw ? 'true' : 'false';\n }\n if (typeof raw === 'number') {\n return Number.isFinite(raw) ? String(raw) : null;\n }\n const text = raw as string;\n switch (type) {\n case 'number':\n case 'email':\n case 'url':\n case 'date':\n return text.trim() === '' ? null : text.trim();\n case 'boolean': {\n const lowered = text.trim().toLowerCase();\n if (lowered === 'true' || lowered === 'on' || lowered === 'yes') return 'true';\n if (lowered === 'false' || lowered === 'off' || lowered === 'no') return 'false';\n return lowered === '' ? null : text;\n }\n default:\n return text === '' ? null : text;\n }\n}\n\n/**\n * Turn whatever a form control produced into the `string[]` the answer route takes, in the\n * question's canonical form: numbers as decimals, booleans as `\"true\"`/`\"false\"`, dates as\n * `YYYY-MM-DD` (a `Date` is read as the local calendar day), trimmed where whitespace means\n * nothing. An empty value becomes `[]` — no answer, not an empty string. A single-choice question\n * keeps the first value.\n *\n * Coercion never judges: pair it with {@link validateAnswer} (the same rules the server applies) to\n * say what is wrong before sending.\n */\nexport function coerceAnswer(question: CoercibleQuestion, raw: RawAnswer): string[] {\n const type = question.input?.type;\n const items: readonly RawAnswer[] = Array.isArray(raw) ? raw : [raw];\n const values = items\n .map((item) => coerceOne(type, item))\n .filter((value): value is string => value !== null);\n return question.multiple === true ? values : values.slice(0, 1);\n}\n","import type {\n ToolConfirmation,\n ToolPresentation,\n ToolPresentationTone,\n} from '@dudousxd/nestjs-agent-core';\nimport { getToolName } from 'ai';\nimport type { AnyToolUIPart, TranscriptToolCall } from '../transcript/model.js';\nimport { type ToolCatalog, fillTemplate, phraseFor } from './phrasing.js';\nimport { type ResolvedResultView, resolveResultView } from './result-view.js';\n\n/**\n * Where one call stands, as a person reads it:\n * - `running` — input streaming or the tool executing;\n * - `awaiting-approval` — an `action` call parked on a person;\n * - `done` / `failed` / `denied` — settled. A tool that RETURNS `{ error }` has failed just as much\n * as one that threw; the two arrive differently and read the same to a person.\n */\nexport type ToolCallStatus =\n | 'running'\n | 'awaiting-approval'\n | 'done'\n | 'failed'\n | 'denied'\n | 'queued'\n | 'executing'\n | 'succeeded';\n\nexport interface ToolCallState {\n status: ToolCallStatus;\n isSettled: boolean;\n isFailed: boolean;\n isDenied: boolean;\n output: unknown;\n error: string | null;\n}\n\n/** Whether the stream classified this call as an `action` (it parks for approval before it runs). */\nexport function isActionCall(part: AnyToolUIPart): boolean {\n const metadata = (part as { toolMetadata?: unknown }).toolMetadata;\n return (\n typeof metadata === 'object' &&\n metadata !== null &&\n (metadata as Record<string, unknown>).toolKind === 'action'\n );\n}\n\nexport function toolCallState(part: AnyToolUIPart): ToolCallState {\n const output = 'output' in part ? part.output : undefined;\n if (\n output !== null &&\n typeof output === 'object' &&\n 'proposalId' in output &&\n 'executed' in output &&\n output.executed === false\n )\n return {\n status: 'awaiting-approval',\n isSettled: false,\n isFailed: false,\n isDenied: false,\n output,\n error: null,\n };\n const errorText = 'errorText' in part ? part.errorText : undefined;\n const outputError =\n output !== null && typeof output === 'object' && 'error' in output\n ? String((output as { error: unknown }).error)\n : undefined;\n const isDenied = part.state === 'output-denied';\n const isFailed = part.state === 'output-error' || (outputError !== undefined && !isDenied);\n const isSettled = part.state === 'output-available' || part.state === 'output-error' || isDenied;\n const isAwaiting =\n part.state === 'approval-requested' || (part.state === 'input-available' && isActionCall(part));\n const status: ToolCallStatus = isDenied\n ? 'denied'\n : isFailed\n ? 'failed'\n : isSettled\n ? 'done'\n : isAwaiting\n ? 'awaiting-approval'\n : 'running';\n return {\n status,\n isSettled,\n isFailed,\n isDenied,\n output,\n error: errorText ?? outputError ?? null,\n };\n}\n\n/**\n * Which failed calls the model went on to correct, by call id: a call that failed and was followed,\n * in the same run, by a SUCCESS of the same tool. The operator wants to know a retry happened, not\n * to read every attempt. A failed read is not corrected by a successful query.\n */\nexport function correctedCallIds(parts: readonly AnyToolUIPart[]): Set<string> {\n const corrected = new Set<string>();\n const lastSuccessByTool = new Map<string, number>();\n parts.forEach((part, index) => {\n if (part.state === 'output-available' && !toolCallState(part).isFailed) {\n lastSuccessByTool.set(getToolName(part), index);\n }\n });\n parts.forEach((part, index) => {\n const successAt = lastSuccessByTool.get(getToolName(part));\n if (successAt !== undefined && index < successAt && toolCallState(part).isFailed) {\n corrected.add(part.toolCallId);\n }\n });\n return corrected;\n}\n\n/** Everything a surface needs to talk about one call without naming it. */\nexport interface ToolCallDescription {\n status: ToolCallStatus;\n /** \"Querying orders\" / \"Queried orders\" — or the generic fallback when the tool declared nothing. */\n phrase: string;\n /** The server's noun phrase for the tool; `null` when it declared no presentation. */\n label: string | null;\n icon: string | null;\n tone: ToolPresentationTone;\n detail: string | null;\n /** The approval prompt, templated over the call's input; `null` when the tool declared none. */\n confirm: { title: string; verb: string; detail: string | null } | null;\n /** The output read through its view, once the call is `done`; `null` otherwise or when nothing to draw. */\n result: ResolvedResultView | null;\n error: string | null;\n presentation: ToolPresentation | null;\n}\n\nexport interface DescribeToolCallOptions {\n /** Resolved strings from the call preflight override the tool catalog templates. */\n confirmation?: ToolConfirmation;\n /** Words for a tool the catalog does not describe. Default `Working` / `Done`. */\n fallback?: { running: string; done: string };\n /** Infer a result view from the output's shape when the tool declared none. Default `false`. */\n inferResult?: boolean;\n}\n\nexport function describeToolCall(\n part: AnyToolUIPart,\n catalog: ToolCatalog | undefined,\n options: DescribeToolCallOptions = {},\n): ToolCallDescription {\n const presentation = catalog?.[getToolName(part)];\n const state = toolCallState(part);\n const input = (part as { input?: unknown }).input;\n const confirm = presentation?.confirm;\n return {\n status: state.status,\n phrase: phraseFor(presentation, input, state.isSettled, options.fallback),\n label: presentation?.label ?? null,\n icon: presentation?.icon ?? null,\n tone: presentation?.tone ?? 'neutral',\n detail: presentation?.detail ?? null,\n confirm:\n options.confirmation !== undefined\n ? {\n title: options.confirmation.title,\n verb: options.confirmation.verb,\n detail: options.confirmation.detail ?? null,\n }\n : confirm === undefined\n ? null\n : {\n title: fillTemplate(confirm.title, input),\n verb: confirm.verb,\n detail: confirm.detail !== undefined ? fillTemplate(confirm.detail, input) : null,\n },\n result:\n state.status === 'done'\n ? resolveResultView(state.output, presentation?.result, {\n ...(options.inferResult !== undefined ? { infer: options.inferResult } : {}),\n })\n : null,\n error: state.error,\n presentation: presentation ?? null,\n };\n}\n\n/**\n * Calls folded under one key — \"Database query ×3\" — with the state that matters most across them.\n */\nexport interface ToolActivityGroup {\n key: string;\n /** The server's label for the group's tool; `null` when it declared no presentation. */\n label: string | null;\n icon: string | null;\n /** Worst-first across the calls: running › awaiting-approval › failed › denied › done. */\n status: ToolCallStatus;\n count: number;\n /** The phrase of the group's LATEST call — what is happening now. */\n phrase: string;\n calls: TranscriptToolCall[];\n /** Calls nested under the group's calls (all depths), when nesting was not expanded. */\n innerCount: number;\n}\n\nexport interface GroupToolActivityOptions {\n catalog?: ToolCatalog;\n /**\n * What makes two calls \"the same activity\". Default: the tool's presentation `label`, else its\n * name. Flippy-style source grouping passes its own (e.g. `github:search`).\n */\n keyOf?: (call: TranscriptToolCall, presentation: ToolPresentation | undefined) => string;\n /**\n * Replace a call that has nested calls with those calls (recursively), so the activity reads as\n * what the code-mode run DID rather than \"ran code\". Default `false`: groups are built over the\n * top-level calls, and `innerCount` says how much ran beneath them.\n */\n expandNested?: boolean;\n /** Drop failed calls the model corrected with a later success of the same tool. Default `false`. */\n hideCorrected?: boolean;\n fallback?: { running: string; done: string };\n}\n\nconst STATUS_WEIGHT: Record<ToolCallStatus, number> = {\n running: 4,\n queued: 4,\n executing: 4,\n succeeded: 0,\n 'awaiting-approval': 3,\n failed: 2,\n denied: 1,\n done: 0,\n};\n\nfunction descendants(call: TranscriptToolCall): TranscriptToolCall[] {\n return call.children.flatMap((child) => [child, ...descendants(child)]);\n}\n\nfunction leaves(call: TranscriptToolCall): TranscriptToolCall[] {\n return call.children.length === 0 ? [call] : call.children.flatMap(leaves);\n}\n\n/**\n * Fold a tool run into activity groups, in order of first appearance. Pass `block.roots` (the\n * transcript's call tree) so nesting is honoured; a flat `block.calls` works too and simply has\n * nothing nested.\n */\nexport function groupToolActivity(\n calls: readonly TranscriptToolCall[],\n options: GroupToolActivityOptions = {},\n): ToolActivityGroup[] {\n const expanded = options.expandNested === true ? calls.flatMap(leaves) : [...calls];\n const corrected =\n options.hideCorrected === true\n ? correctedCallIds(expanded.map((call) => call.part))\n : new Set<string>();\n const groups = new Map<string, ToolActivityGroup>();\n for (const call of expanded) {\n if (corrected.has(call.toolCallId)) continue;\n const presentation = options.catalog?.[call.name];\n const key = options.keyOf?.(call, presentation) ?? presentation?.label ?? call.name;\n const status = call.description.status;\n const phrase = phraseFor(\n presentation,\n (call.part as { input?: unknown }).input,\n status !== 'running' && status !== 'awaiting-approval',\n options.fallback,\n );\n const inner = options.expandNested === true ? 0 : descendants(call).length;\n const existing = groups.get(key);\n if (existing === undefined) {\n groups.set(key, {\n key,\n label: presentation?.label ?? null,\n icon: presentation?.icon ?? null,\n status,\n count: 1,\n phrase,\n calls: [call],\n innerCount: inner,\n });\n continue;\n }\n existing.count += 1;\n existing.calls.push(call);\n existing.phrase = phrase;\n existing.innerCount += inner;\n if (STATUS_WEIGHT[status] > STATUS_WEIGHT[existing.status]) existing.status = status;\n }\n return [...groups.values()];\n}\n","import type { ToolCatalogEntry, ToolPresentation } from '@dudousxd/nestjs-agent-core';\n\n/** Tool name → how the server said it is spoken about. */\nexport type ToolCatalog = Record<string, ToolPresentation>;\n\n/** Index `GET <base>/tools` by tool name, keeping only the tools that declared a presentation. */\nexport function toolCatalogFrom(entries: readonly ToolCatalogEntry[]): ToolCatalog {\n const catalog: ToolCatalog = {};\n for (const entry of entries) {\n if (entry.presentation !== undefined) catalog[entry.name] = entry.presentation;\n }\n return catalog;\n}\n\n/** Dotted-path read. `undefined` rather than a throw, so a template can outlive a field. */\nexport function readPath(value: unknown, path: string): unknown {\n return path.split('.').reduce<unknown>((current, key) => {\n if (current === null || typeof current !== 'object') return undefined;\n return (current as Record<string, unknown>)[key];\n }, value);\n}\n\nfunction renderValue(value: unknown): string {\n if (value === null || value === undefined) return '';\n if (typeof value === 'string') return value;\n if (typeof value === 'number' || typeof value === 'boolean') return String(value);\n if (Array.isArray(value)) return value.map(renderValue).filter(Boolean).join(', ');\n return '';\n}\n\n/**\n * Fill `{dotted.path}` placeholders from `context`. A placeholder with nothing behind it collapses\n * along with the whitespace in front of it, so \"Reading {key}\" degrades to \"Reading\" rather than\n * printing braces at a person; a filled one keeps the whitespace the author wrote (\"({n} files)\").\n */\nexport function fillTemplate(template: string, context: unknown): string {\n return template\n .replace(/(\\s*)\\{([\\w.]+)\\}/g, (_match, space: string, path: string) => {\n const rendered = renderValue(readPath(context, path));\n return rendered === '' ? '' : `${space}${rendered}`;\n })\n .replace(/\\s{2,}/g, ' ')\n .trim();\n}\n\n/**\n * The sentence for one call: the presentation's `running` or `done` template over the call's input.\n *\n * Nothing here reads the tool's name. A tool the catalog does not describe — added since the catalog\n * loaded, or declared without a presentation — is narrated generically (`fallback`), because the only\n * other thing available to say is its identifier.\n */\nexport function phraseFor(\n presentation: ToolPresentation | undefined,\n input: unknown,\n isSettled: boolean,\n fallback: { running: string; done: string } = { running: 'Working', done: 'Done' },\n): string {\n if (presentation === undefined) return isSettled ? fallback.done : fallback.running;\n const filled = fillTemplate(isSettled ? presentation.done : presentation.running, input);\n // A sentence made only of slots, called before those fields have streamed, leaves nothing. The\n // label is still the server's word for this tool, and a blank line reads as nothing happening.\n return filled === '' ? presentation.label : filled;\n}\n","import type { ToolResultField, ToolResultView } from '@dudousxd/nestjs-agent-core';\nimport { fillTemplate, readPath } from './phrasing.js';\n\n/** One labelled reading of a `metrics` view. */\nexport interface ResolvedReading {\n label: string;\n /** The value as text (`—` for nothing). */\n value: string;\n unit: string | null;\n}\n\n/**\n * A tool's output resolved through its view into plain data a renderer draws — never the payload\n * itself. `null` from {@link resolveResultView} means \"draw nothing\".\n */\nexport type ResolvedResultView =\n | { kind: 'metrics'; readings: ResolvedReading[] }\n | { kind: 'table'; columns: ToolResultField[]; rows: string[][]; empty: string | null }\n | { kind: 'log'; lines: string[] }\n | { kind: 'note'; text: string };\n\nfunction isRecord(value: unknown): value is Record<string, unknown> {\n return typeof value === 'object' && value !== null && !Array.isArray(value);\n}\n\nfunction toText(value: unknown): string {\n if (value === null || value === undefined) return '—';\n if (typeof value === 'string' || typeof value === 'number' || typeof value === 'boolean') {\n return String(value);\n }\n if (Array.isArray(value)) return value.map(toText).join(', ');\n return '—';\n}\n\n/**\n * A view for an output whose tool declared none, from its shape: an array of flat records is a\n * table, an array of strings a log, a flat record a set of readings. `undefined` when nothing fits —\n * a serialized payload is what a person-facing surface exists to avoid, so failing to infer must not\n * fall back to one.\n */\nexport function inferResultView(output: unknown): ToolResultView | undefined {\n if (!isRecord(output)) return undefined;\n for (const [key, value] of Object.entries(output)) {\n if (!Array.isArray(value) || value.length === 0) continue;\n if (value.every((entry) => typeof entry === 'string')) {\n return { kind: 'log', lines: key };\n }\n if (value.every(isRecord)) {\n const first = value[0] as Record<string, unknown>;\n return {\n kind: 'table',\n rows: key,\n columns: Object.keys(first)\n .filter((column) => !isRecord(first[column]))\n .map((column) => ({ path: column, label: column })),\n };\n }\n }\n const fields = Object.entries(output)\n .filter(([, value]) => ['string', 'number', 'boolean'].includes(typeof value))\n .map(([key]) => ({ path: key, label: key }));\n return fields.length > 0 ? { kind: 'metrics', fields } : undefined;\n}\n\n/**\n * Read `output` through `view` (or one inferred from its shape when `view` is omitted and `infer` is\n * on). `null` when there is nothing to draw: an `elsewhere` view, an empty reading set, a missing\n * array. A table whose rows array is present but empty resolves with no rows and its `empty` line.\n */\nexport function resolveResultView(\n output: unknown,\n view: ToolResultView | undefined,\n options: { infer?: boolean } = {},\n): ResolvedResultView | null {\n const resolved = view ?? (options.infer === true ? inferResultView(output) : undefined);\n if (resolved === undefined || resolved.kind === 'elsewhere') return null;\n switch (resolved.kind) {\n case 'note': {\n const text = fillTemplate(resolved.text, output);\n return text === '' ? null : { kind: 'note', text };\n }\n case 'metrics': {\n const readings = resolved.fields\n .map((field) => ({ field, value: readPath(output, field.path) }))\n .filter((entry) => entry.value !== undefined && entry.value !== null)\n .map(({ field, value }) => ({\n label: field.label,\n value: toText(value),\n unit: field.unit ?? null,\n }));\n return readings.length === 0 ? null : { kind: 'metrics', readings };\n }\n case 'log': {\n const lines = readPath(output, resolved.lines);\n if (!Array.isArray(lines) || lines.length === 0) return null;\n return { kind: 'log', lines: lines.map(toText) };\n }\n case 'table': {\n const rows = readPath(output, resolved.rows);\n if (!Array.isArray(rows)) return null;\n return {\n kind: 'table',\n columns: resolved.columns,\n rows: rows.map((row) =>\n resolved.columns.map((column) => toText(readPath(row, column.path))),\n ),\n empty: rows.length === 0 ? (resolved.empty ?? null) : null,\n };\n }\n }\n}\n","import { useCallback, useEffect, useRef, useState } from 'react';\n\nexport interface StickToBottomOptions {\n /**\n * Changes whenever the rendered content grows — the signal to re-pin. A string rather than the\n * message array because a streaming turn mutates in place: the array identity is stable while its\n * last part's text keeps growing.\n */\n contentKey: string;\n /**\n * How far off the bottom (px) still counts as \"at the bottom\". Sub-pixel layout and fractional\n * device ratios leave a residue of a pixel or two after a programmatic scroll, so an exact\n * comparison unpins the view on the very scroll event it just caused.\n */\n threshold?: number;\n}\n\nexport interface StickToBottom {\n /** While true, new content scrolls into view; the user scrolling up turns it off. */\n isAtBottom: boolean;\n /** Whether a \"jump to latest\" affordance is warranted. */\n showJumpToLatest: boolean;\n scrollToBottom: () => void;\n /** Spread onto the scrolling element. Behaviour only — no classes, no styles. */\n getContainerProps: () => {\n ref: (element: HTMLElement | null) => void;\n onScroll: () => void;\n };\n}\n\n/**\n * Follow a streaming transcript only while the reader is already at the bottom. Reading back\n * through history during a stream is the case this exists for: an unconditional scroll-to-bottom\n * yanks the viewport away mid-sentence on every token.\n */\nexport function useStickToBottom({\n contentKey,\n threshold = 32,\n}: StickToBottomOptions): StickToBottom {\n const containerRef = useRef<HTMLElement | null>(null);\n const [isAtBottom, setIsAtBottom] = useState(true);\n\n const measure = useCallback(() => {\n const element = containerRef.current;\n if (!element) {\n return;\n }\n const distance = element.scrollHeight - element.scrollTop - element.clientHeight;\n setIsAtBottom(distance <= threshold);\n }, [threshold]);\n\n const scrollToBottom = useCallback(() => {\n const element = containerRef.current;\n if (!element) {\n return;\n }\n element.scrollTop = element.scrollHeight;\n setIsAtBottom(true);\n }, []);\n\n const setContainer = useCallback(\n (element: HTMLElement | null) => {\n containerRef.current = element;\n if (element) {\n measure();\n }\n },\n [measure],\n );\n\n // Re-pin as content arrives. Guarded on `isAtBottom` so a reader who scrolled up keeps their\n // position for the rest of the stream, and re-pins the moment they scroll back down.\n // biome-ignore lint/correctness/useExhaustiveDependencies: `contentKey` IS the content dependency\n useEffect(() => {\n if (isAtBottom) {\n scrollToBottom();\n }\n }, [contentKey, isAtBottom, scrollToBottom]);\n\n const getContainerProps = useCallback(\n () => ({ ref: setContainer, onScroll: measure }),\n [setContainer, measure],\n );\n\n return {\n isAtBottom,\n showJumpToLatest: !isAtBottom,\n scrollToBottom,\n getContainerProps,\n };\n}\n","import type { UIMessage } from 'ai';\nimport type React from 'react';\nimport type { ChatQueue } from '../queue/model.js';\nimport type { ChatStatus, MessageUsageInfo } from '../transcript/model.js';\nimport {\n type EditSubmitInput,\n type MessageActionInput,\n useChatTranscript,\n} from '../transcript/use-chat-transcript.js';\nimport {\n type MessageItemClassNames,\n MessageItemView,\n type RenderFilesFn,\n type RenderReasoningFn,\n type RenderTextFn,\n type RenderToolGroupFn,\n type RenderToolPartFn,\n type RenderUiFn,\n} from './message-item.js';\n\nexport type { ChatStatus } from '../transcript/model.js';\n\nexport interface MessageListClassNames {\n root?: string;\n empty?: string;\n loadEarlier?: string;\n typing?: string;\n error?: string;\n errorRetry?: string;\n followUps?: string;\n followUpChip?: string;\n /** The block of waiting (queued) messages after the transcript. */\n queue?: string;\n /** One waiting message; it also carries `data-state=\"sending|queued|paused\"`. */\n queuedItem?: string;\n queuedRemove?: string;\n /** The \"queue paused\" line and its resume button. */\n queuePaused?: string;\n queueResume?: string;\n message?: MessageItemClassNames;\n}\n\nexport interface MessageListProps {\n messages: UIMessage[];\n status: ChatStatus;\n renderToolPart?: RenderToolPartFn;\n renderToolGroup?: RenderToolGroupFn;\n renderText?: RenderTextFn;\n /** Render the body of a reasoning run; the disclosure toggle is the list's. */\n renderReasoning?: RenderReasoningFn;\n /** Draw a message's files yourself. Omitted → images inline, everything else a link. */\n renderFiles?: RenderFilesFn;\n /** Draw a server-pushed component (a `ui` stream frame). Omitted → not drawn. */\n renderUi?: RenderUiFn;\n reasoningLabel?: React.ReactNode;\n /** Extra content for one message's action row — e.g. a badge naming which agent answered. */\n getMeta?: (message: UIMessage) => React.ReactNode;\n /**\n * Nobody acts on this list (an audit or shared view): parked approvals and question sets render\n * without their actions, and no fork / edit / regenerate — see `useChatTranscript({ readOnly })`.\n */\n readOnly?: boolean;\n /** When set, every message gets a \"Fork\" affordance calling back with its id. */\n onFork?: (input: MessageActionInput) => void | Promise<void>;\n /** User messages get an inline edit-and-resubmit affordance. */\n editable?: boolean;\n onEditSubmit?: (input: EditSubmitInput) => void | Promise<void>;\n /** The last assistant message gets a \"Regenerate\" affordance. */\n regeneratable?: boolean;\n onRegenerate?: (input: MessageActionInput) => void | Promise<void>;\n /** Per-message resolvers for the usage line and the persisted timestamp. */\n getUsage?: (message: UIMessage) => MessageUsageInfo | null;\n getCreatedAt?: (message: UIMessage) => string | null;\n /** Shown (with example/follow-up chips) when idle and empty. */\n emptyState?: React.ReactNode;\n /** Node rendered while waiting for the first assistant token. */\n typingIndicator?: React.ReactNode;\n /** AI-generated follow-up prompts under the last assistant message. */\n followUps?: string[] | null;\n onFollowUpClick?: (text: string) => void;\n /** Last turn's error — paired with `onRetry`, renders a retry banner. */\n error?: Error | null;\n onRetry?: () => void | Promise<void>;\n /**\n * `chat.queue` — messages sent while a turn was running, drawn after the transcript as pending\n * user messages (with a remove button), and a resume button while the queue is paused.\n */\n queue?: ChatQueue;\n classNames?: MessageListClassNames;\n}\n\n/**\n * Styling-agnostic message list. Keeps the proven UX — windowed render\n * with \"load earlier\", a typing indicator, an inline error+retry banner,\n * and follow-up chips — but ships no styles: drive everything through\n * `classNames` and the `emptyState`/`typingIndicator` slots.\n *\n * Every decision here comes from `useChatTranscript`; the file below it is markup. A host that\n * wants a different layout drives that hook directly and never imports this component.\n */\nexport function MessageList({\n messages,\n status,\n renderToolPart,\n renderToolGroup,\n renderText,\n renderReasoning,\n renderFiles,\n renderUi,\n reasoningLabel,\n getMeta,\n readOnly,\n onFork,\n editable,\n onEditSubmit,\n regeneratable,\n onRegenerate,\n getUsage,\n getCreatedAt,\n emptyState,\n typingIndicator,\n followUps,\n onFollowUpClick,\n error,\n onRetry,\n queue,\n classNames,\n}: MessageListProps) {\n const transcript = useChatTranscript({\n messages,\n status,\n ...(readOnly !== undefined ? { readOnly } : {}),\n ...(onFork ? { onFork } : {}),\n ...(editable !== undefined ? { editable } : {}),\n ...(onEditSubmit ? { onEditSubmit } : {}),\n ...(regeneratable !== undefined ? { regeneratable } : {}),\n ...(onRegenerate ? { onRegenerate } : {}),\n ...(getUsage ? { getUsage } : {}),\n ...(getCreatedAt ? { getCreatedAt } : {}),\n ...(followUps !== undefined ? { followUps } : {}),\n ...(queue !== undefined\n ? { queue: { items: queue.items, paused: queue.paused, remove: queue.remove } }\n : {}),\n });\n\n if (transcript.showEmptyState && transcript.queued.length === 0) {\n return <div className={classNames?.empty}>{emptyState}</div>;\n }\n\n const slots = {\n ...(renderToolPart ? { renderToolPart } : {}),\n ...(renderToolGroup ? { renderToolGroup } : {}),\n ...(renderText ? { renderText } : {}),\n ...(renderReasoning ? { renderReasoning } : {}),\n ...(renderFiles ? { renderFiles } : {}),\n ...(renderUi ? { renderUi } : {}),\n ...(reasoningLabel !== undefined ? { reasoningLabel } : {}),\n ...(classNames?.message ? { classNames: classNames.message } : {}),\n };\n\n return (\n <div className={classNames?.root}>\n {transcript.window.canLoadEarlier ? (\n <button\n type=\"button\"\n className={classNames?.loadEarlier}\n onClick={transcript.window.loadEarlier}\n >\n Load earlier ({transcript.window.hiddenCount} more)\n </button>\n ) : null}\n {transcript.items.map((item) => (\n <MessageItemView\n key={item.id}\n item={item}\n {...slots}\n {...(getMeta ? { meta: getMeta(item.message) } : {})}\n />\n ))}\n {transcript.queued.length > 0 ? (\n <div className={classNames?.queue}>\n {transcript.queued.map((item) => (\n <div key={item.id} className={classNames?.queuedItem} data-state={item.state}>\n <span>{item.text}</span>\n {item.remove.available ? (\n <button\n type=\"button\"\n className={classNames?.queuedRemove}\n onClick={item.remove.run}\n >\n Remove\n </button>\n ) : null}\n </div>\n ))}\n {transcript.queuePaused !== null && queue !== undefined ? (\n <div className={classNames?.queuePaused}>\n <span>Queue paused</span>\n <button\n type=\"button\"\n className={classNames?.queueResume}\n onClick={() => void queue.resume()}\n >\n Resume\n </button>\n </div>\n ) : null}\n </div>\n ) : null}\n {transcript.showTypingIndicator ? (\n <div className={classNames?.typing}>{typingIndicator ?? 'Thinking…'}</div>\n ) : null}\n {error && onRetry ? (\n <div className={classNames?.error}>\n <span>{error.message || \"The assistant didn't respond.\"}</span>\n <button type=\"button\" className={classNames?.errorRetry} onClick={() => void onRetry()}>\n Retry\n </button>\n </div>\n ) : null}\n {transcript.showFollowUps && onFollowUpClick && followUps ? (\n <div className={classNames?.followUps}>\n {followUps.map((text) => (\n <button\n key={text}\n type=\"button\"\n className={classNames?.followUpChip}\n onClick={() => onFollowUpClick(text)}\n >\n {text}\n </button>\n ))}\n </div>\n ) : null}\n </div>\n );\n}\n","/**\n * Languages the dictation mic offers. The Web Speech API expects a\n * BCP-47 tag and does NOT auto-detect — the engine forces incoming\n * audio onto the phonemes of whatever `recognition.lang` is set to, so\n * the host app picks the locale explicitly.\n */\nexport interface SpeechLanguage {\n /** BCP-47 tag fed straight into `SpeechRecognition.lang`. */\n tag: string;\n /** Human label for a dropdown. */\n label: string;\n}\n\nexport const DEFAULT_SPEECH_LANG = 'en-US';\n\nexport const SPEECH_LANGUAGES: ReadonlyArray<SpeechLanguage> = [\n { tag: 'en-US', label: 'English (US)' },\n { tag: 'en-GB', label: 'English (UK)' },\n { tag: 'pt-BR', label: 'Portuguese (Brazil)' },\n { tag: 'es-ES', label: 'Spanish (Spain)' },\n];\n\nconst STORAGE_KEY = 'nestjs-agent-chat-speech-lang';\n\n/**\n * Recover the last picked language from localStorage (sync — safe at\n * `useState` init). Falls back to the default if nothing's stored or the\n * stored tag isn't in the offered list.\n */\nexport function loadStoredSpeechLang(): string {\n if (typeof window === 'undefined') return DEFAULT_SPEECH_LANG;\n try {\n const raw = window.localStorage.getItem(STORAGE_KEY);\n if (raw && SPEECH_LANGUAGES.some((language) => language.tag === raw)) {\n return raw;\n }\n } catch {\n /* localStorage disabled (private window / webview) — use the default */\n }\n return DEFAULT_SPEECH_LANG;\n}\n\nexport function persistSpeechLang(tag: string): void {\n if (typeof window === 'undefined') return;\n try {\n window.localStorage.setItem(STORAGE_KEY, tag);\n } catch {\n /* same fallback — silently skip persistence */\n }\n}\n","/** One completion a source offers. */\nexport interface AutocompleteItem {\n /** Unique within its source. */\n id: string;\n /** What the reader sees, and what the default filter matches against. */\n label: string;\n /** What replaces the typed token. Defaults to `label` — set it when the label is prose. */\n value?: string;\n description?: string;\n /**\n * A short trailing note a renderer right-aligns — where this came from, a keyboard shortcut, a\n * type. Deliberately outside the default filter: typing a query should narrow by what the item\n * IS, not by an aside about it.\n */\n hint?: string;\n /** Whatever the host's renderer needs: an icon key, a scope, the row this came from. */\n data?: unknown;\n}\n\n/**\n * Where a trigger character is allowed to open the menu.\n *\n * - `'start'` — only as the very first character of the input. This is the rule a slash command\n * wants: `/deploy` is a command, `src/foo` and `and/or` are not.\n * - `'word'` — at the start of any word: the input's start, or immediately after whitespace. This\n * is the rule a mention wants: `@ada` in the middle of a sentence is a mention, `ada@example` is\n * an address.\n *\n * There is no default on purpose. Which rule a trigger takes is the difference between an\n * autocomplete that feels invisible and one that fires while somebody types a file path.\n */\nexport type TriggerPosition = 'start' | 'word';\n\nexport interface AutocompleteSource {\n /** Identifies the source to the host; also names the listbox when `label` is omitted. */\n id: string;\n /** Human-facing name for the open menu. */\n label?: string;\n /** The single character that opens this source. Two sources never share one. */\n trigger: string;\n position: TriggerPosition;\n /**\n * The candidates for `query`. May be async; a result that arrives after the query moved on is\n * discarded, and `signal` aborts the request that produced it. Throwing is allowed — the menu\n * reports the failure and typing carries on.\n */\n getItems: (\n query: string,\n signal: AbortSignal,\n ) => AutocompleteItem[] | Promise<AutocompleteItem[]>;\n /**\n * Narrow what `getItems` returned. Defaults to {@link filterAutocompleteItems}. A source that\n * already filtered server-side — a fuzzy match this one would undo — passes `(items) => items`.\n */\n filter?: (items: AutocompleteItem[], query: string) => AutocompleteItem[];\n /**\n * Appended after the inserted value. Defaults to a single space, which both closes the menu and\n * puts the caret where the command's argument goes.\n */\n insertSuffix?: string;\n}\n\n/** A trigger character found before the caret, with the token being typed after it. */\nexport interface TriggerMatch {\n source: AutocompleteSource;\n /** Index of the trigger character itself. */\n index: number;\n /** The text between the trigger and the caret. Never contains whitespace. */\n query: string;\n}\n\nexport interface CompletionEdit {\n text: string;\n caret: number;\n}\n\nconst WHITESPACE = /\\s/;\n\n/**\n * The trigger token the caret currently sits in, or `null`. Scans backwards from the caret and\n * stops at the first whitespace, so a token is always one unbroken word: typing a space is what\n * ends a command and hands the rest of the line back to the user as prose.\n */\nexport function findActiveTrigger(\n text: string,\n caret: number,\n sources: readonly AutocompleteSource[],\n): TriggerMatch | null {\n const end = Math.max(0, Math.min(caret, text.length));\n for (let index = end - 1; index >= 0; index--) {\n const char = text[index];\n if (char === undefined || WHITESPACE.test(char)) {\n return null;\n }\n const source = sources.find((candidate) => candidate.trigger === char);\n // A trigger that fails its own position rule is just a character in the token — `@ad/x` is one\n // mention query, not a command — so the scan continues past it rather than giving up.\n if (source && isAllowedAt(text, index, source.position)) {\n return { source, index, query: text.slice(index + 1, end) };\n }\n }\n return null;\n}\n\nfunction isAllowedAt(text: string, index: number, position: TriggerPosition): boolean {\n if (index === 0) {\n return true;\n }\n if (position === 'start') {\n return false;\n }\n const previous = text[index - 1];\n return previous !== undefined && WHITESPACE.test(previous);\n}\n\n/** Case-insensitive substring over label and description. The default when a source names none. */\nexport function filterAutocompleteItems(\n items: readonly AutocompleteItem[],\n query: string,\n): AutocompleteItem[] {\n // An empty needle is a substring of everything, so it needs no branch of its own.\n const needle = query.trim().toLowerCase();\n return items.filter(\n (item) =>\n item.label.toLowerCase().includes(needle) ||\n (item.description?.toLowerCase().includes(needle) ?? false),\n );\n}\n\n/**\n * The text and caret after accepting `item`. The trigger character stays — `/deploy ` is what the\n * user meant to type — and everything after the caret is left untouched, so completing a token in\n * the middle of a sentence does not eat the rest of it.\n */\nexport function applyCompletion(\n text: string,\n caret: number,\n match: TriggerMatch,\n item: AutocompleteItem,\n): CompletionEdit {\n const end = Math.max(match.index, Math.min(caret, text.length));\n const inserted = `${match.source.trigger}${item.value ?? item.label}${match.source.insertSuffix ?? ' '}`;\n return {\n text: text.slice(0, match.index) + inserted + text.slice(end),\n caret: match.index + inserted.length,\n };\n}\n","import type { SkillCatalogEntry } from '@dudousxd/nestjs-agent-core';\nimport { type AgentBackend, AgentBackendUnsupportedError } from '../backend.js';\nimport type { AutocompleteItem, AutocompleteSource } from './model.js';\n\n/** What each item carries on `data`, so a renderer can show where a skill came from. */\nexport interface SkillSuggestionData {\n /** The scope token it resolved from — the provenance a user is entitled to see. */\n scope: string;\n /** Scope tokens of same-named skills this one outranks, widest last. */\n shadows?: string[];\n}\n\nexport interface SkillsSourceOptions {\n /** Any backend with `listSkills` — `useAgentBackend()`, or `useAgentChat().backend`. */\n backend: Pick<AgentBackend, 'listSkills'>;\n /**\n * Read at query time, not captured once: a threadless chat learns its id only when the backend\n * creates one on the first send, and a skill may be scoped to a conversation.\n */\n getThreadId?: () => string | undefined;\n /** Default `/`. */\n trigger?: string;\n /** Default `Skills`. */\n label?: string;\n}\n\n/**\n * `GET /agent/skills` as an autocomplete source — the concrete one behind `/`, and an example of\n * the shape any other takes. `position: 'start'` because a skill is a command: `/deploy` is one and\n * `src/foo` is a path.\n */\nexport function createSkillsSource(options: SkillsSourceOptions): AutocompleteSource {\n // One read per thread. The endpoint answers with the whole scope-resolved list rather than a\n // search, so asking again per keystroke would fetch identical rows only to filter them locally.\n // A failed read is forgotten, so the next keystroke retries instead of caching the outage.\n //\n // The order it arrives in IS the precedence — most specific scope first, then alphabetical — and\n // is passed through untouched. The type-ahead filter narrows this list by what the user typed; it\n // never re-derives which skills apply, which is the server's answer and the model's too.\n const byThread = new Map<string, Promise<AutocompleteItem[]>>();\n\n return {\n id: 'skills',\n label: options.label ?? 'Skills',\n trigger: options.trigger ?? '/',\n position: 'start',\n getItems: () => {\n const threadId = options.getThreadId?.();\n const key = threadId ?? '';\n const cached = byThread.get(key);\n if (cached) {\n return cached;\n }\n const listSkills = options.backend.listSkills;\n if (listSkills === undefined) {\n return Promise.reject(new AgentBackendUnsupportedError('listSkills'));\n }\n const pending = listSkills\n .call(options.backend, threadId)\n .then((entries) => entries.map(toItem))\n .catch((error: unknown) => {\n byThread.delete(key);\n throw error;\n });\n byThread.set(key, pending);\n return pending;\n },\n };\n}\n\nfunction toItem(entry: SkillCatalogEntry): AutocompleteItem {\n const data: SkillSuggestionData = {\n scope: entry.scope,\n ...(entry.shadows !== undefined ? { shadows: entry.shadows } : {}),\n };\n return {\n id: entry.name,\n label: entry.name,\n description: entry.description,\n // `shadows` is present only on a conflict, so saying \"overrides\" is never noise: without it a\n // user cannot tell \"there is no org default\" from \"there is one and mine wins\".\n hint:\n entry.shadows === undefined\n ? entry.scope\n : `${entry.scope} · overrides ${entry.shadows.join(', ')}`,\n data,\n };\n}\n","import type React from 'react';\nimport { useCallback, useEffect, useId, useLayoutEffect, useMemo, useRef, useState } from 'react';\nimport {\n type AutocompleteItem,\n type AutocompleteSource,\n type TriggerMatch,\n applyCompletion,\n filterAutocompleteItems,\n findActiveTrigger,\n} from './model.js';\n\nexport interface UseComposerAutocompleteOptions {\n /** The composer's draft. Accepting an item rewrites it through `onValueChange`. */\n value: string;\n onValueChange: (next: string) => void;\n /**\n * What can be completed, and after which character. The composer knows nothing about what a\n * source offers — a skills list and an agent mention are the same shape.\n */\n sources: readonly AutocompleteSource[];\n /** A source that threw. The menu reports it; typing is unaffected either way. */\n onError?: (error: unknown, source: AutocompleteSource) => void;\n /** Tab accepts the highlighted item, as Enter does. Default `true`. */\n acceptOnTab?: boolean;\n /** Base for the generated `id`s the ARIA wiring points at. */\n id?: string;\n}\n\nexport interface AutocompleteInputProps {\n ref: (element: HTMLTextAreaElement | HTMLInputElement | null) => void;\n onChange: (event: React.ChangeEvent<HTMLTextAreaElement | HTMLInputElement>) => void;\n onKeyDown: (event: React.KeyboardEvent<HTMLTextAreaElement | HTMLInputElement>) => void;\n onSelect: (event: React.SyntheticEvent<HTMLTextAreaElement | HTMLInputElement>) => void;\n onClick: (event: React.MouseEvent<HTMLTextAreaElement | HTMLInputElement>) => void;\n role: 'combobox';\n 'aria-expanded': boolean;\n 'aria-autocomplete': 'list';\n 'aria-haspopup': 'listbox';\n 'aria-controls'?: string;\n 'aria-activedescendant'?: string;\n}\n\nexport interface AutocompleteListboxProps {\n id: string;\n role: 'listbox';\n 'aria-label': string;\n}\n\nexport interface AutocompleteOptionProps {\n id: string;\n role: 'option';\n 'aria-selected': boolean;\n}\n\nexport interface ComposerAutocomplete {\n isOpen: boolean;\n /** The source behind the open menu, so a renderer can group or label by it. */\n source: AutocompleteSource | null;\n trigger: string | null;\n /** The text between the trigger and the caret. */\n query: string;\n items: AutocompleteItem[];\n activeIndex: number;\n activeItem: AutocompleteItem | null;\n /** An async source has been asked and has not answered yet. */\n isLoading: boolean;\n /** The message from a source that threw. The menu stays open and empty. */\n error: string | null;\n highlight: (index: number) => void;\n /** Wraps at both ends, so ↓ from the last item lands on the first. */\n moveHighlight: (delta: number) => void;\n /** Insert an item — the highlighted one by default. A click handler calls this directly. */\n accept: (item?: AutocompleteItem) => void;\n /** Close for the token being typed, without touching the text. */\n dismiss: () => void;\n getInputProps: () => AutocompleteInputProps;\n getListboxProps: () => AutocompleteListboxProps;\n getOptionProps: (index: number) => AutocompleteOptionProps;\n}\n\n/**\n * The state machine behind a `/`-style autocomplete in a chat composer: which trigger the caret is\n * inside, what the query is, which items answer it, which one is highlighted, and what accepting\n * one does to the text and the caret. It renders nothing and knows nothing about skills, agents or\n * threads — a host supplies sources, and the same machine drives `@` as drives `/`.\n *\n * The keys the open menu owns (↑ ↓ Enter Tab Escape) are consumed with `preventDefault`, which is\n * how a composer that sends on Enter knows to stand down: call this handler first and return early\n * when the event comes back `defaultPrevented`.\n */\nexport function useComposerAutocomplete(\n options: UseComposerAutocompleteOptions,\n): ComposerAutocomplete {\n const { value, sources, acceptOnTab = true } = options;\n\n const latest = useRef(options);\n latest.current = options;\n\n const inputRef = useRef<HTMLTextAreaElement | HTMLInputElement | null>(null);\n const [caret, setCaret] = useState(value.length);\n const [items, setItems] = useState<AutocompleteItem[]>([]);\n const [isLoading, setLoading] = useState(false);\n const [error, setError] = useState<string | null>(null);\n const [activeIndex, setActiveIndex] = useState(0);\n // The trigger index Escape closed. Cleared the moment the caret leaves that token, so deleting\n // the trigger and typing it again offers the menu rather than staying silently dismissed.\n const [dismissedIndex, setDismissedIndex] = useState<number | null>(null);\n\n // Clamped: a host that resets the draft externally leaves the caret past the end of the text.\n const safeCaret = Math.min(caret, value.length);\n const match = useMemo(\n () => findActiveTrigger(value, safeCaret, sources),\n [value, safeCaret, sources],\n );\n const isActive = match !== null && dismissedIndex !== match.index;\n\n const matchRef = useRef<TriggerMatch | null>(match);\n matchRef.current = match;\n const caretRef = useRef(safeCaret);\n caretRef.current = safeCaret;\n const itemsRef = useRef(items);\n itemsRef.current = items;\n const activeIndexRef = useRef(activeIndex);\n activeIndexRef.current = activeIndex;\n\n // Identifies the question being asked, so a re-render that changes neither the source nor the\n // query does not re-ask — an async source would otherwise fetch on every unrelated render. The\n // NUL separator cannot appear in either half, so no pair of them collides.\n const requestKey = isActive && match ? `${match.source.id}\\u0000${match.query}` : null;\n\n useEffect(() => {\n const current = matchRef.current;\n if (requestKey === null || current === null) {\n setItems([]);\n setLoading(false);\n setError(null);\n return;\n }\n const { source, query } = current;\n const controller = new AbortController();\n // The cleanup below runs before the next query's effect, so a slow answer to an abandoned\n // query finds `superseded` already true and is dropped instead of overwriting a newer list.\n let superseded = false;\n const settle = (next: AutocompleteItem[]) => {\n if (superseded) return;\n setItems((source.filter ?? filterAutocompleteItems)(next, query));\n setActiveIndex(0);\n setLoading(false);\n setError(null);\n };\n const failed = (cause: unknown) => {\n if (superseded) return;\n setItems([]);\n setLoading(false);\n setError(cause instanceof Error ? cause.message : 'Could not load suggestions');\n latest.current.onError?.(cause, source);\n };\n\n let result: AutocompleteItem[] | Promise<AutocompleteItem[]>;\n try {\n result = source.getItems(query, controller.signal);\n } catch (cause) {\n failed(cause);\n return;\n }\n // A static source answers in the same tick: settling synchronously spares the list a frame of\n // emptiness between the trigger being typed and its items appearing.\n if (!isPromise(result)) {\n settle(result);\n return;\n }\n setLoading(true);\n setError(null);\n result.then(settle, failed);\n return () => {\n superseded = true;\n controller.abort();\n };\n }, [requestKey]);\n\n // Open the moment the caret is inside a live trigger token, before any items are in: an empty\n // menu that says \"no matches\" is an answer, whereas a menu that never appears reads as broken.\n // The keys the menu owns are still only taken when there is something to take them for.\n const isOpen = isActive;\n const activeItem = isOpen ? (items[activeIndex] ?? null) : null;\n\n const reactId = useId();\n const listboxId = options.id ?? `agent-autocomplete-${reactId}`;\n const optionId = useCallback((index: number) => `${listboxId}-option-${index}`, [listboxId]);\n\n const highlight = useCallback((index: number) => {\n const total = itemsRef.current.length;\n if (total === 0) return;\n setActiveIndex(((index % total) + total) % total);\n }, []);\n\n const moveHighlight = useCallback(\n (delta: number) => highlight(activeIndexRef.current + delta),\n [highlight],\n );\n\n const dismiss = useCallback(() => {\n const current = matchRef.current;\n if (current) setDismissedIndex(current.index);\n }, []);\n\n // Set after an accept and consumed on the next commit: the textarea is controlled, so React\n // writes the new value only once this render lands and any caret set before that is overwritten.\n const pendingCaret = useRef<number | null>(null);\n\n const accept = useCallback((item?: AutocompleteItem) => {\n const current = matchRef.current;\n if (!current) return;\n const chosen = item ?? itemsRef.current[activeIndexRef.current];\n if (!chosen) return;\n const edit = applyCompletion(latest.current.value, caretRef.current, current, chosen);\n latest.current.onValueChange(edit.text);\n setCaret(edit.caret);\n setDismissedIndex(null);\n pendingCaret.current = edit.caret;\n }, []);\n\n useLayoutEffect(() => {\n const position = pendingCaret.current;\n if (position === null) return;\n pendingCaret.current = null;\n inputRef.current?.setSelectionRange(position, position);\n });\n\n const readCaret = useCallback((element: HTMLTextAreaElement | HTMLInputElement) => {\n setCaret(element.selectionStart ?? element.value.length);\n }, []);\n\n const onKeyDown = useCallback(\n (event: React.KeyboardEvent<HTMLTextAreaElement | HTMLInputElement>) => {\n if (!isOpen) return;\n const hasItems = itemsRef.current.length > 0;\n switch (event.key) {\n case 'ArrowDown':\n if (!hasItems) return;\n event.preventDefault();\n moveHighlight(1);\n return;\n case 'ArrowUp':\n if (!hasItems) return;\n event.preventDefault();\n moveHighlight(-1);\n return;\n case 'Enter':\n if (!hasItems) return;\n event.preventDefault();\n accept();\n return;\n case 'Tab':\n // Shift+Tab stays a backwards focus move: a completion menu is not a focus trap.\n if (!acceptOnTab || event.shiftKey || !hasItems) return;\n event.preventDefault();\n accept();\n return;\n case 'Escape':\n event.preventDefault();\n dismiss();\n return;\n default:\n return;\n }\n },\n [isOpen, acceptOnTab, accept, dismiss, moveHighlight],\n );\n\n const onChange = useCallback(\n (event: React.ChangeEvent<HTMLTextAreaElement | HTMLInputElement>) => {\n readCaret(event.target);\n // A token the user has walked away from is no longer dismissed — it is gone.\n const next = findActiveTrigger(\n event.target.value,\n event.target.selectionStart ?? event.target.value.length,\n latest.current.sources,\n );\n setDismissedIndex((current) =>\n current !== null && next?.index === current ? current : null,\n );\n },\n [readCaret],\n );\n\n const onSelect = useCallback(\n (event: React.SyntheticEvent<HTMLTextAreaElement | HTMLInputElement>) =>\n readCaret(event.currentTarget),\n [readCaret],\n );\n\n const onClick = useCallback(\n (event: React.MouseEvent<HTMLTextAreaElement | HTMLInputElement>) =>\n readCaret(event.currentTarget),\n [readCaret],\n );\n\n const setInput = useCallback((element: HTMLTextAreaElement | HTMLInputElement | null) => {\n inputRef.current = element;\n }, []);\n\n const getInputProps = useCallback(\n (): AutocompleteInputProps => ({\n ref: setInput,\n onChange,\n onKeyDown,\n onSelect,\n onClick,\n role: 'combobox',\n 'aria-expanded': isOpen,\n 'aria-autocomplete': 'list',\n 'aria-haspopup': 'listbox',\n ...(isOpen ? { 'aria-controls': listboxId } : {}),\n ...(activeItem ? { 'aria-activedescendant': optionId(activeIndex) } : {}),\n }),\n [\n setInput,\n onChange,\n onKeyDown,\n onSelect,\n onClick,\n isOpen,\n listboxId,\n activeItem,\n activeIndex,\n optionId,\n ],\n );\n\n const getListboxProps = useCallback(\n (): AutocompleteListboxProps => ({\n id: listboxId,\n role: 'listbox',\n 'aria-label': match?.source.label ?? match?.source.id ?? 'Suggestions',\n }),\n [listboxId, match],\n );\n\n const getOptionProps = useCallback(\n (index: number): AutocompleteOptionProps => ({\n id: optionId(index),\n role: 'option',\n 'aria-selected': index === activeIndex,\n }),\n [optionId, activeIndex],\n );\n\n return {\n isOpen,\n source: isOpen && match ? match.source : null,\n trigger: isOpen && match ? match.source.trigger : null,\n query: match?.query ?? '',\n items,\n activeIndex,\n activeItem,\n isLoading,\n error,\n highlight,\n moveHighlight,\n accept,\n dismiss,\n getInputProps,\n getListboxProps,\n getOptionProps,\n };\n}\n\nfunction isPromise<T>(value: T[] | Promise<T[]>): value is Promise<T[]> {\n return typeof (value as Promise<T[]>).then === 'function';\n}\n","import { ALL_AGENTS, type ToolCatalogEntry } from '@dudousxd/nestjs-agent-core';\n\nexport { ALL_AGENTS };\nimport { useCallback, useEffect, useMemo, useState } from 'react';\nimport { type AgentBackend, AgentBackendUnsupportedError } from '../backend.js';\nimport { useAgentBackend } from '../provider.js';\nimport { type ToolCatalog, toolCatalogFrom } from './phrasing.js';\n\n/** What the catalog needs of a backend. */\ntype ToolsBackend = Pick<AgentBackend, 'listTools'>;\n\nexport interface UseToolCatalogOptions {\n /**\n * The backend to ask. Default: the enclosing `<AgentProvider>`'s. Must be STABLE across renders\n * (the shared copy is keyed by it): a backend constructed inline refetches every render.\n */\n backend?: ToolsBackend;\n /**\n * The agent whose tools to list. Omitted → the server's default agent. {@link ALL_AGENTS} (`'*'`)\n * → every tool the actor reaches through any agent, each once — for an app with several agents\n * whose conversations one surface shows.\n */\n agent?: string;\n /** `false` holds the request (e.g. until the user is signed in). Default `true`. */\n enabled?: boolean;\n}\n\nexport interface ToolCatalogState {\n /** Tool name → presentation, for the tools that declared one. `{}` until loaded. */\n catalog: ToolCatalog;\n /** Everything `GET <base>/tools` returned, kinds included. */\n entries: ToolCatalogEntry[];\n isLoading: boolean;\n error: Error | null;\n /** Drop the shared copy and ask again. */\n refresh: () => void;\n}\n\n/**\n * One request per backend + agent for the whole page: the catalog is a deployment-time constant, so\n * every component that narrates a tool call can call this hook and share the answer instead of\n * putting a request between a tool starting and the sentence that describes it. A failed request\n * is not cached, so the next mount retries.\n */\nconst shared = new WeakMap<ToolsBackend, Map<string, Promise<ToolCatalogEntry[]>>>();\n\nfunction load(client: ToolsBackend, agent: string | undefined): Promise<ToolCatalogEntry[]> {\n let byAgent = shared.get(client);\n if (byAgent === undefined) {\n byAgent = new Map();\n shared.set(client, byAgent);\n }\n const key = agent ?? '';\n const cached = byAgent.get(key);\n if (cached !== undefined) return cached;\n if (client.listTools === undefined) {\n return Promise.reject(new AgentBackendUnsupportedError('listTools'));\n }\n const request = client.listTools(agent).catch((error: unknown) => {\n byAgent.delete(key);\n throw error;\n });\n byAgent.set(key, request);\n return request;\n}\n\n/**\n * The server-declared presentation of the tools this actor can reach (`GET <base>/tools`), for\n * `phraseFor`, `describeToolCall` and `groupToolActivity` — or pass `catalog` to\n * `useChatTranscript({ toolCatalog })` and read the phrases off the transcript's calls.\n */\nexport function useToolCatalog(options: UseToolCatalogOptions = {}): ToolCatalogState {\n const { agent, enabled = true } = options;\n const client = useAgentBackend(options.backend as AgentBackend | undefined);\n const [entries, setEntries] = useState<ToolCatalogEntry[]>([]);\n const [isLoading, setLoading] = useState(enabled);\n const [error, setError] = useState<Error | null>(null);\n const [generation, setGeneration] = useState(0);\n\n // biome-ignore lint/correctness/useExhaustiveDependencies: `generation` is the refresh trigger\n useEffect(() => {\n if (!enabled) {\n setLoading(false);\n return;\n }\n let cancelled = false;\n setLoading(true);\n load(client, agent).then(\n (loaded) => {\n if (cancelled) return;\n setEntries(Array.isArray(loaded) ? loaded : []);\n setError(null);\n setLoading(false);\n },\n (failure: unknown) => {\n if (cancelled) return;\n setError(failure instanceof Error ? failure : new Error(String(failure)));\n setLoading(false);\n },\n );\n return () => {\n cancelled = true;\n };\n }, [client, agent, enabled, generation]);\n\n const refresh = useCallback(() => {\n shared.get(client)?.delete(agent ?? '');\n setGeneration((current) => current + 1);\n }, [client, agent]);\n\n const catalog = useMemo(() => toolCatalogFrom(entries), [entries]);\n return { catalog, entries, isLoading, error, refresh };\n}\n","import { useEffect, useRef, useState } from 'react';\n\nexport interface ApprovalCountdown {\n /** Milliseconds until the request lapses, floored at 0; `null` when it never does. */\n remainingMs: number | null;\n /** The instant has passed. Always `false` for a request with no expiry. */\n isExpired: boolean;\n}\n\nexport interface UseApprovalCountdownOptions {\n /** How often the value re-renders while counting. Default 1000 — a seconds label needs no more. */\n intervalMs?: number;\n /** Injectable clock for tests. */\n now?: () => number;\n}\n\n/** What {@link useApprovalCountdown} reads for `expiresAt` at `now`, without the ticking. */\nexport function approvalCountdown(\n expiresAt: string | null | undefined,\n now: number = Date.now(),\n): ApprovalCountdown {\n const deadline = expiresAt == null ? Number.NaN : Date.parse(expiresAt);\n if (!Number.isFinite(deadline)) {\n return { remainingMs: null, isExpired: false };\n }\n const remainingMs = Math.max(0, deadline - now);\n return { remainingMs, isExpired: remainingMs === 0 };\n}\n\n/**\n * Time left on an approval request (`call.approval.expiresAt`), ticking until it lapses and then\n * holding at zero. Headless: pair `remainingMs` with `formatElapsed` or any label of your own, and\n * use `isExpired` to stop offering buttons the server would refuse (`410 Gone`). The server stays\n * the authority — a lapse is final only once the call settles `expired`.\n */\nexport function useApprovalCountdown(\n expiresAt: string | null | undefined,\n options: UseApprovalCountdownOptions = {},\n): ApprovalCountdown {\n const { intervalMs = 1000 } = options;\n const nowRef = useRef(options.now ?? Date.now);\n nowRef.current = options.now ?? Date.now;\n const [state, setState] = useState(() => approvalCountdown(expiresAt, nowRef.current()));\n\n useEffect(() => {\n const read = () => approvalCountdown(expiresAt, nowRef.current());\n const first = read();\n setState(first);\n if (first.remainingMs === null || first.isExpired) {\n return;\n }\n const timer = setInterval(() => {\n const next = read();\n setState(next);\n if (next.isExpired) clearInterval(timer);\n }, intervalMs);\n return () => clearInterval(timer);\n }, [expiresAt, intervalMs]);\n\n return state;\n}\n","import { DEFAULT_REFUSAL_REASON } from '@dudousxd/nestjs-agent-core';\nimport type { StoredMessage, ToolResult } from '@dudousxd/nestjs-agent-core';\nimport type { UIMessage } from 'ai';\nimport { reasoningDurationMetadata } from './reasoning/timing.js';\nimport type { AgentMessageMetadata } from './stored-thread-to-ui-messages.js';\n\n/**\n * Convert a persisted `StoredMessage` (the agent-lib's on-disk shape) into an AI SDK v7\n * `UIMessage` so a loaded thread can seed `useChat`'s `initialMessages` / `messages`.\n *\n * The lib stores a message as flat `content` text plus `toolCalls`/`toolResults` arrays; the SDK\n * renders from `parts`. This maps, in this order:\n * - `reasoning` → a `reasoning` part (state `done`) BEFORE the text, as it streamed; its\n * `reasoningMs` rides `providerMetadata.agent.reasoningMs`, where the\n * live transport stamps it too.\n * - `content` → a single `text` part (skipped when empty).\n * - each `attachment` → a `file` part (image/PDF) so the user bubble re-renders its\n * thumbnails on a reloaded thread.\n * - each `ui` component → a `data-ui` part keyed by the component id — the same part a live\n * `ui` stream frame becomes.\n * - each `approval` → a `data-approval-requested` part keyed by the call id (who decides,\n * until when) and, once decided, a `data-approval-settled` one — the\n * same parts the live `approval-requested`/`approval-settled` frames\n * become, so the transcript folds both into `call.approval` either way.\n * - each `toolCall` → a `tool-<name>` part, pairing its `toolResult` (matched by id):\n * - a result found → `output-available` state, carrying `output`; `output-denied` when a\n * person declined it; `output-error` (carrying `errorText`) when it\n * failed — the states the live stream leaves the part in.\n * - no result found → `input-available` state (the call never finished, e.g. the run was\n * interrupted) — `output` is omitted, never a fabricated value.\n * When the store reports the tool's kind (`'read' | 'action'`), it rides along as\n * `toolMetadata.toolKind` so a UI can render an approval affordance for `action` tools\n * without hardcoding tool-name sets, matching how live-streamed tool parts carry it.\n *\n * Live streaming still arrives as fully-typed SDK tool parts (see `AgentChatTransport`); this\n * converter only feeds replayed history, so the tool cards render the same either way.\n */\n/**\n * Did a person decline this call? `denied` is what the loop sets today. The `output.rejected` shape\n * is how a refusal was recorded before that flag existed, and threads holding those are still read\n * back — so both count, and a thread from either era reloads as the same part.\n */\nfunction isRefusal(result: ToolResult): boolean {\n if (result.denied === true) {\n return true;\n }\n const { output } = result;\n return (\n output !== null &&\n typeof output === 'object' &&\n 'rejected' in output &&\n (output as { rejected: unknown }).rejected === true\n );\n}\n\n/** The reason given when declining, when one was given. */\nfunction refusalReason(result: ToolResult): string | undefined {\n const { output } = result;\n if (output !== null && typeof output === 'object' && 'reason' in output) {\n const reason = (output as { reason: unknown }).reason;\n return typeof reason === 'string' && reason !== DEFAULT_REFUSAL_REASON ? reason : undefined;\n }\n return undefined;\n}\n\nexport function storedMessageToUiMessage(message: StoredMessage): UIMessage {\n const parts: UIMessage['parts'] = [];\n\n if (message.reasoning) {\n parts.push({\n type: 'reasoning',\n text: message.reasoning,\n state: 'done',\n ...(message.reasoningMs !== undefined\n ? { providerMetadata: reasoningDurationMetadata(message.reasoningMs) }\n : {}),\n });\n }\n\n if (message.content) {\n parts.push({ type: 'text', text: message.content });\n }\n\n for (const attachment of message.attachments ?? []) {\n parts.push({\n type: 'file',\n mediaType: attachment.contentType,\n filename: attachment.name,\n url: attachment.url,\n // The stored id rides along, so a replayed file can be referenced again (`messageFiles`).\n providerMetadata: { agent: { mediaId: attachment.mediaId } },\n });\n }\n\n // A component a tool pushed (`toolCallId`) goes right after that call's tool part, where the live\n // stream put it; the rest keep their place ahead of the calls.\n const toolCallIds = new Set((message.toolCalls ?? []).map((call) => call.id));\n const pushedByCall = new Map<string, UIMessage['parts']>();\n for (const component of message.ui ?? []) {\n const part: UIMessage['parts'][number] = {\n type: 'data-ui',\n id: component.id,\n data: {\n id: component.id,\n component: component.component,\n props: component.props,\n ...(component.componentVersions !== undefined\n ? { componentVersions: component.componentVersions }\n : {}),\n ...(component.fallbackText !== undefined ? { fallbackText: component.fallbackText } : {}),\n ...(component.version !== undefined ? { version: component.version } : {}),\n ...(component.toolCallId !== undefined ? { toolCallId: component.toolCallId } : {}),\n },\n };\n if (component.toolCallId !== undefined && toolCallIds.has(component.toolCallId)) {\n const list = pushedByCall.get(component.toolCallId) ?? [];\n list.push(part);\n pushedByCall.set(component.toolCallId, list);\n } else {\n parts.push(part);\n }\n }\n\n for (const approval of message.approvals ?? []) {\n parts.push({\n type: 'data-approval-requested',\n id: approval.toolCallId,\n data: {\n id: approval.toolCallId,\n approver: approval.approver,\n ...(approval.target !== undefined\n ? { target: approval.target }\n : approval.proposalId !== undefined\n ? { target: { kind: 'proposal', proposalId: approval.proposalId } }\n : {}),\n ...(approval.confirmation !== undefined ? { confirmation: approval.confirmation } : {}),\n ...(approval.expiresAt !== undefined ? { expiresAt: approval.expiresAt } : {}),\n },\n });\n if (approval.status !== 'pending') {\n parts.push({\n type: 'data-approval-settled',\n id: approval.toolCallId,\n data: {\n id: approval.toolCallId,\n status: approval.status,\n ...(approval.decidedBy !== undefined ? { decidedBy: approval.decidedBy } : {}),\n ...(approval.decidedVia !== undefined ? { decidedVia: approval.decidedVia } : {}),\n ...(approval.remember === true ? { remember: true } : {}),\n ...(approval.reason !== undefined ? { reason: approval.reason } : {}),\n },\n });\n }\n }\n\n for (const call of message.toolCalls ?? []) {\n const result = message.toolResults?.find((candidate) => candidate.id === call.id);\n // `call.kind` — the store's `'read' | 'action'` classification, once it lands there\n // (parallel to `RecordToolCallInput.toolType` and the stream's `toolKind`).\n const toolKind = call.kind;\n // `parentId` nests a replayed call under its parent, as the live frames did.\n const toolMetadata = {\n ...(toolKind !== undefined ? { toolKind } : {}),\n ...(call.parentId !== undefined ? { parentId: call.parentId } : {}),\n };\n parts.push({\n type: `tool-${call.name}`,\n toolCallId: call.id,\n ...(Object.keys(toolMetadata).length > 0 ? { toolMetadata } : {}),\n ...(result !== undefined\n ? isRefusal(result)\n ? {\n // A declined action is NOT an available output. Reloading a thread used to bring one\n // back as `output-available` carrying `{ rejected: true }`, which a card reads as a\n // result — so the action a person refused was drawn, after a refresh, as one that\n // had been carried out.\n state: 'output-denied',\n input: call.input,\n approval: {\n id: call.id,\n approved: false,\n ...(refusalReason(result) !== undefined\n ? { reason: refusalReason(result) as string }\n : {}),\n },\n }\n : typeof result.error === 'string' && result.error !== ''\n ? {\n // A call that FAILED — the tool threw, its input was refused, or its turn died\n // before it was settled — is not an available output either. The live stream says\n // so with `tool-output-error`; a reloaded thread has to say the same, or the card of\n // an action that never ran comes back reading as one that completed.\n state: 'output-error',\n input: call.input,\n errorText: result.error,\n }\n : { state: 'output-available', input: call.input, output: result.output }\n : { state: 'input-available', input: call.input }),\n });\n parts.push(...(pushedByCall.get(call.id) ?? []));\n }\n\n const metadata: AgentMessageMetadata = {\n // The host's own facts first: the library's keys win on a clash.\n ...message.metadata,\n ...(message.actionProposalOutcome === undefined\n ? {}\n : { actionProposalOutcomeId: message.actionProposalOutcome.id }),\n ...(message.feedback !== undefined ? { feedback: message.feedback } : {}),\n ...(message.createdAt ? { createdAt: message.createdAt } : {}),\n ...(message.agentName !== undefined ? { agentName: message.agentName } : {}),\n ...(message.persona !== undefined ? { persona: message.persona } : {}),\n ...(message.usage !== undefined\n ? {\n usage: {\n inputTokens: message.usage.inputTokens,\n outputTokens: message.usage.outputTokens,\n costUsd: message.usage.costUsd ?? null,\n },\n }\n : {}),\n };\n return {\n id: message.id,\n role: message.role,\n parts,\n ...(Object.keys(metadata).length > 0 ? { metadata } : {}),\n };\n}\n","import type { MessageFeedback, StoredMessage } from '@dudousxd/nestjs-agent-core';\nimport type { UIMessage } from 'ai';\nimport { storedMessageToUiMessage } from './stored-message-to-ui-message.js';\n\n/**\n * Summed usage/cost across the stored-message rows merged into one turn (see\n * {@link storedThreadToUiMessages}). Mirrors `MessageUsage`, but `costUsd` is always present\n * (never omitted) since it's a computed aggregate, not a single provider report.\n */\nexport interface AggregatedTurnUsage {\n inputTokens: number;\n outputTokens: number;\n /**\n * `null` only when EVERY merged row reports a null/absent cost (no pricing store bound, or an\n * unpriced model) — same \"unknown, not a real $0\" distinction `MessageUsage.costUsd` makes for a\n * single row. A null cost on SOME rows (mixed with priced ones) contributes `0` to the sum\n * instead of poisoning the whole turn's total to `null` — the tokens are still real and summed\n * either way, so only the cost figure would be understated, never wrong in a \"$0 turn\" sense.\n */\n costUsd: number | null;\n}\n\n/** Metadata the grouped `UIMessage` carries on `.metadata.usage` — see {@link AggregatedTurnUsage}. */\nexport interface StoredTurnMetadata {\n usage: AggregatedTurnUsage;\n}\n\n/**\n * Everything a message's `metadata` may carry from this library: `usage` on a merged replayed turn,\n * `feedback` on a replayed message that was rated (a merged turn is rated through its last row,\n * whose id it carries), `runId` on a live-streamed one, `costUsd` from the stream's step ends.\n */\nexport interface AgentMessageMetadata extends Partial<StoredTurnMetadata> {\n feedback?: MessageFeedback;\n runId?: string;\n costUsd?: number | null;\n /** ISO timestamp: the stored row's `createdAt` (a merged turn: its first row's), or when a live turn started streaming. */\n createdAt?: string;\n /** The agent that wrote a replayed message, when the row names one (`StoredMessage.agentName`). */\n agentName?: string;\n /** The persona the turn that wrote a replayed message ran under (`StoredMessage.persona`). */\n persona?: string;\n /** Host-defined keys: `StoredMessage.metadata` and the stream's `message-metadata` frames. */\n [key: string]: unknown;\n}\n\n/**\n * Convert a thread's full `StoredMessage[]` history into `UIMessage[]`, merging consecutive\n * assistant rows (no user message between them) into ONE `UIMessage` per turn.\n *\n * Why: the agent loop persists one row per model iteration (see `agent-loop.ts`'s per-step\n * `persist:assistant:${i}`) — a turn with tool calls appends \"I'll check that...\" + tool calls,\n * then a separate final-answer row. `storedMessageToUiMessage` maps 1:1, so a reloaded thread\n * renders 2-3 assistant bubbles (each with its own cost/tokens footer) for what the LIVE stream\n * renders as one continuous response (one `UIMessage`, stepped internally — see\n * `AgentChatTransport.toChunkStream`'s `start-step`/`finish-step` bracketing). This closes that gap\n * for replayed history.\n *\n * Merge shape: each row is mapped via `storedMessageToUiMessage` (unchanged — same text-then-tool\n * part ordering per row) and the parts are concatenated in row order, so the grouped message's parts\n * read as `[row1 text?, row1 tools?, row2 text?, row2 tools?, ...]` — exactly the sequence the live\n * transport streams for the same turn. The group's `id` is the LAST row's id (the final-answer row —\n * it's the one carrying `followUps`, and what a host keys turn-level actions like \"fork\" or\n * \"regenerate\" on). Non-assistant rows (user/system) pass through `storedMessageToUiMessage`\n * unchanged, one row → one message, same as today.\n *\n * A lone assistant row between two user rows (the common case: no tool calls, or already a single\n * iteration) has nothing to merge with, so it comes back byte-for-byte identical to calling\n * `storedMessageToUiMessage` directly — no `metadata` is added for that case either, preserving\n * exact backward compatibility for hosts that read stored usage some other way.\n *\n * Only an ACTUAL merge (2+ rows) attaches `metadata.usage` — the {@link AggregatedTurnUsage} summed\n * across the merged rows' `usage` (rows without a `usage` at all, e.g. an older/test fixture, are\n * skipped rather than treated as zero-and-priced).\n *\n * Deliberately NOT reproduced: the live transport's `{type: 'step-start'}` UI parts (one per model\n * call, emitted by the AI SDK for every `start-step` chunk — see `repro-real-frames.spec.ts` for a\n * captured wire dump). Those are structural brackets `MessageItem`'s `renderBlocks` never renders\n * (it draws only text, reasoning, files and tool blocks), and `storedMessageToUiMessage` has never\n * emitted them for a single row either — inventing them here would make a merged turn diverge from\n * a same-shaped unmerged one instead of converging on it. \"Indistinguishable from the live stream\"\n * is scoped to what actually renders: the text/tool-call content in step order, not the step\n * brackets around it.\n */\nexport function storedThreadToUiMessages(messages: StoredMessage[]): UIMessage[] {\n const turns: StoredMessage[][] = [];\n for (const message of messages) {\n const currentTurn = turns.at(-1);\n const previousRow = currentTurn?.at(-1);\n if (\n message.role === 'assistant' &&\n previousRow?.role === 'assistant' &&\n currentTurn &&\n sameRun(previousRow, message)\n ) {\n currentTurn.push(message);\n } else {\n turns.push([message]);\n }\n }\n return turns.map(mergeTurn);\n}\n\n/**\n * Two assistant rows belong to the same TURN, not merely to the same side of the conversation.\n * Consecutive is the right test only while one run at a time writes to a thread: a detached\n * sub-agent posts its answer whenever it lands, so a thread whose last row is an assistant reply can\n * gain another from a different run entirely — merged, that reads as the assistant having said both.\n *\n * Rows that carry no `runId` (written before it was recorded, or by a host outside a run) merge as\n * they always did: there is nothing to tell them apart with, and splitting on absence would\n * un-merge every old thread.\n */\nfunction sameRun(previous: StoredMessage, next: StoredMessage): boolean {\n if (previous.actionProposalOutcome !== undefined || next.actionProposalOutcome !== undefined)\n return false;\n return previous.runId === undefined || next.runId === undefined || previous.runId === next.runId;\n}\n\nfunction mergeTurn(rows: StoredMessage[]): UIMessage {\n const lastRow = rows.at(-1);\n if (lastRow === undefined) {\n // Unreachable: `storedThreadToUiMessages` never pushes an empty turn.\n throw new Error('storedThreadToUiMessages: encountered an empty turn');\n }\n if (rows.length === 1) {\n return storedMessageToUiMessage(lastRow);\n }\n\n const parts: UIMessage['parts'] = rows.flatMap((row) => storedMessageToUiMessage(row).parts);\n const usage = sumUsage(rows);\n // A turn is rated through its last row — the id this message carries.\n const feedback = lastRow.feedback;\n const createdAt = rows[0]?.createdAt;\n const metadata: AgentMessageMetadata = {\n // Host facts of every row, a later row's winning (the turn's final state), under the library's.\n ...Object.assign({}, ...rows.map((row) => row.metadata ?? {})),\n ...(usage !== undefined ? { usage } : {}),\n ...(feedback !== undefined ? { feedback } : {}),\n ...(createdAt ? { createdAt } : {}),\n ...(lastRow.agentName !== undefined ? { agentName: lastRow.agentName } : {}),\n ...(lastRow.persona !== undefined ? { persona: lastRow.persona } : {}),\n };\n\n return {\n id: lastRow.id,\n role: lastRow.role,\n parts,\n ...(Object.keys(metadata).length > 0 ? { metadata } : {}),\n };\n}\n\nfunction sumUsage(rows: StoredMessage[]): AggregatedTurnUsage | undefined {\n const usages = rows\n .map((row) => row.usage)\n .filter((usage): usage is NonNullable<typeof usage> => usage !== undefined);\n if (usages.length === 0) {\n return undefined;\n }\n const allCostsUnknown = usages.every(\n (usage) => usage.costUsd === null || usage.costUsd === undefined,\n );\n return {\n inputTokens: usages.reduce((sum, usage) => sum + usage.inputTokens, 0),\n outputTokens: usages.reduce((sum, usage) => sum + usage.outputTokens, 0),\n costUsd: allCostsUnknown ? null : usages.reduce((sum, usage) => sum + (usage.costUsd ?? 0), 0),\n };\n}\n","import { useChat } from '@ai-sdk/react';\nimport type {\n ChatQueueState,\n MessageAttachment,\n QuotaBlock,\n StoredMessage,\n ThreadDetail,\n ThreadSummary,\n} from '@dudousxd/nestjs-agent-core';\nimport type { UiCapabilities } from '@dudousxd/nestjs-agent-core/genui';\nimport type { DataUIPart, UIDataTypes, UIMessage } from 'ai';\nimport { useCallback, useEffect, useMemo, useRef, useState } from 'react';\nimport {\n AgentChatTransport,\n type AgentStreamMeta,\n type ReconnectOptions,\n type StreamConnectionState,\n} from './agent-chat-transport.js';\nimport { useActionProposals } from './approvals/use-action-proposals.js';\nimport { attachmentFile } from './attachments/files.js';\nimport {\n type AttachmentsState,\n type UseAttachmentsOptions,\n useAttachments,\n} from './attachments/use-attachments.js';\nimport {\n type AgentBackend,\n AgentBackendUnsupportedError,\n type QueuedSendResult,\n requireBackendMethod,\n} from './backend.js';\nimport { type BackgroundRun, backgroundRunsFromThread } from './background-runs.js';\nimport { type ModelOption, type ModelsState, useModels } from './catalog/use-models.js';\nimport { useToolCatalog } from './presentation/use-tool-catalog.js';\nimport { useAgentBackend, useAgentUiCapabilities } from './provider.js';\nimport type {\n ChatQueue,\n QueuedChatMessage,\n SendWhileRunning,\n WhileRunning,\n} from './queue/model.js';\nimport { type QuotaState, useQuota } from './quota/use-quota.js';\nimport type { AgentRunFailure } from './run-errors.js';\nimport { storedMessageToUiMessage } from './stored-message-to-ui-message.js';\nimport {\n type AgentMessageMetadata,\n storedThreadToUiMessages,\n} from './stored-thread-to-ui-messages.js';\nimport { notifyThreads } from './threads/threads-events.js';\nimport type { ChatStatus } from './transcript/model.js';\nimport {\n type AnswerInput,\n type ApproveInput,\n type ChatTranscript,\n type MessageActionInput,\n type RejectInput,\n type SkipInput,\n type UseChatTranscriptOptions,\n useChatTranscript,\n} from './transcript/use-chat-transcript.js';\n\nexport interface UseAgentChatOptions<B extends AgentBackend = AgentBackend> {\n uiCapabilities?: UiCapabilities;\n proposalPollMs?: number;\n /** Enable proposal reads even when history and resume are both disabled. */\n proposals?: boolean;\n /**\n * What the chat talks to — see {@link AgentBackend}. Omitted → the enclosing `<AgentProvider>`'s,\n * else a same-origin client on `/agent`. Must be stable across renders.\n */\n backend?: B;\n /**\n * Retry a stream that dropped mid-run from its last frame (`GET <base>/chat/:runId/stream?after=`),\n * with exponential backoff. `status` reads `'reconnecting'` meanwhile. Default on; `false` turns\n * it off.\n */\n reconnect?: ReconnectOptions | false;\n /** Named agent to run each turn. */\n agent?: string;\n /**\n * One of the agent's personas (`GET <base>/agents` lists them) to answer as. Read per send, so a\n * picker can switch it between messages; the server pins it on the thread, and `threadPersona`\n * reports it back. Omitted → the thread's pinned persona, else the agent's default. A single send\n * can name its own: `sendMessage(message, { body: { persona } })`.\n */\n persona?: string;\n /**\n * Thread this chat is bound to. Omitted → the backend creates one on the first send\n * ({@link UseAgentChatOptions.onThreadCreated}). Changing it switches the chat to that thread:\n * its history loads and a turn still streaming on it is re-attached. Switching to the thread this\n * chat just created (syncing a URL) keeps the live conversation as it is.\n */\n threadId?: string;\n /**\n * Load a `threadId`'s persisted history into the chat (`GET <base>/threads/:id`). Default `true`;\n * skipped when {@link UseAgentChatOptions.initialMessages} is given. `false` opts out.\n */\n history?: boolean;\n /** Persisted history you already have — seeds the chat instead of loading it (read per thread). */\n initialMessages?: UIMessage[];\n /**\n * Re-attach to a turn that was still streaming on `threadId` when the page (re)loaded — read off\n * the thread's `activeRunId`, so a reload mid-answer keeps streaming it. Default `true`; `false`\n * opts out.\n */\n resume?: boolean;\n /**\n * A run id you already know is streaming — attached to on mount without reading the thread first.\n * Rarely needed: {@link UseAgentChatOptions.resume} finds it by itself.\n */\n resumeRunId?: string;\n /**\n * The model every turn runs on, controlled by you. Omitted → `chat.models.selected` (what\n * `chat.models.select(id)` picked), else the thread's pinned model, else the server default. A\n * single send can still override it with `sendMessage(msg, { body: { model } })`. Sent as the\n * turn's `model`, which the server applies to that turn only — pinning a model on the thread is\n * `chat.models.pinToThread(id)`.\n */\n model?: string;\n /**\n * Read the caller's budget (`GET <base>/quota`) and refuse sends while a window is exhausted.\n * Default `true` when the backend implements `getQuota`; `false` skips the request.\n */\n quota?: boolean;\n /**\n * Override the quota gate: `null` never blocks, a {@link QuotaBlock} always does. Omitted → the\n * gate follows {@link UseAgentChatOptions.quota}'s report. While blocked, `sendMessage` and\n * `regenerate` refuse with {@link QuotaBlockedError}.\n */\n blocked?: QuotaBlock | null;\n /** Validation and upload for `chat.composer.files` — see `useAttachments`. */\n composer?: Omit<UseAttachmentsOptions, 'backend'>;\n /**\n * What `composer.submit()` and `sendMessage` do while a turn is still running. Default `'queue'`:\n * the message waits in the thread's queue (server-side — it survives a reload) and runs when the\n * turn settles; `chat.queue` lists and edits what is waiting. `'interrupt'` cancels the running\n * turn and runs the message next. `'block'` refuses the send (`composer.blockedBy === 'busy'`).\n * A backend without `enqueueMessage` behaves as `'block'`. One send can answer differently:\n * `composer.submit({ mode })`, `sendMessage(message, { mode })`.\n */\n whileRunning?: WhileRunning;\n /**\n * Overrides for `chat.transcript` — anything `useChatTranscript` takes (`sources`, `editable` +\n * `onEditSubmit`, `followUps`, `getUsage`, a `toolCatalog` of your own, `onApprove: null`, …).\n * Yours win over the chat's own wiring.\n */\n transcript?: Partial<Omit<UseChatTranscriptOptions, 'messages' | 'status'>>;\n /** Read at every send to capture a page snapshot for the page-assistant. */\n getPageContext?: () => Record<string, unknown> | null;\n /** Fired after each streamed turn finishes (e.g. to refetch the sidebar). */\n onFinish?: () => void;\n /**\n * Fired when this chat moves to a thread it created: the first send of a threadless chat (the\n * backend created one), or `chat.fork(…)`. Carries the id so the host can sync its URL/router.\n * The hook already remembers a created thread, so every later send reuses it even before the\n * host navigates.\n */\n onThreadCreated?: (threadId: string) => void;\n /**\n * Fired exactly once per run when its stream settles — normally (`'completed'`) or via a thrown\n * failure / the backend's `event: error` frame (`'failed'`) — including a RESUMED stream's own\n * completion. By the time this fires, the server has already derived and persisted the thread's\n * title (and the run's terminal state).\n *\n * Skipped when the attempt never got far enough to learn a run id. A user-initiated `cancel()`\n * reports `'completed'` (the server-side cancel records its own terminal state).\n */\n onRunSettled?: (outcome: { runId: string; status: 'completed' | 'failed' }) => void;\n /**\n * Every data part the stream delivers, as it arrives — including transient ones that are never\n * stored on a message (`data-title`, `data-cancelled`). Pushed components arrive as `data-ui`,\n * approval metadata as `data-approval-requested`, and a frame kind this version does not map as\n * `data-<kind>`. See `AgentChatTransport` for the full mapping.\n */\n onData?: (part: DataUIPart<UIDataTypes>) => void;\n /** The server set or changed the thread's title while a turn streamed. */\n onTitle?: (title: string) => void;\n /**\n * Track DETACHED sub-agents this conversation started: which are still working, and their answers\n * as they land (see {@link ChatBackground}). Default `false`.\n */\n background?: boolean;\n /**\n * How often to re-read the thread while a detached sub-agent is still working, in ms. Default\n * 5000; `0` turns the interval off, leaving {@link ChatBackground.refresh} as the only trigger.\n */\n backgroundPollMs?: number;\n}\n\n/** Sub-agents this conversation started and did not wait for. See {@link BackgroundRun}. */\nexport interface ChatBackground {\n runs: BackgroundRun[];\n /** True while any of them is still working — what a \"2 agents running\" affordance reads. */\n isWorking: boolean;\n /** Re-read the thread now, instead of waiting for the next poll. */\n refresh: () => Promise<void>;\n}\n\n/**\n * The chat's model picker state. Loaded the first time `list`/`providers`/`defaultModel`/`locked`\n * is read.\n *\n * Two different choices: `select(id)` picks the model this chat's following sends name — each send\n * carries it as `model`, which the server applies to that turn only and never stores; the pick is\n * this conversation's, so switching threads drops it. `pinToThread(id)` stores a model on the\n * thread (`PATCH threads/:id { model }`), which every later turn without a `model` of its own runs\n * on, across reloads and devices.\n */\nexport interface ChatModels {\n /** Every model the caller may pick, flattened (`[]` until loaded). */\n readonly list: ModelOption[];\n /** The same, grouped by provider. */\n readonly providers: ModelsState['providers'];\n /**\n * What the next turn runs on: the lock, the `model` option, the pick, the thread's pin, else the\n * default.\n */\n selected: string | null;\n /** The model pinned on the thread (`null` when none, or before the thread is read). */\n pinned: string | null;\n /** The catalog's default — what a turn runs on when nothing is picked or pinned (`null` until loaded). */\n readonly defaultModel: string | null;\n /**\n * The agent always runs on one model (`{ model, reason? }`), or `null`. While locked, `select`\n * does nothing and `selected` is the locked model.\n */\n readonly locked: ModelsState['locked'];\n /** Run this chat's following sends on `id` — each send's `model`, that turn only. */\n select: (id: string) => void;\n /**\n * Pin `id` on the thread (`null` unpins) — every later turn without its own `model` runs on it,\n * across reloads. Replaces the pick, so the next send runs on the pin. On a chat with no thread\n * yet, the pin lands when the first send creates one.\n */\n pinToThread: (id: string | null) => Promise<void>;\n isLoading: boolean;\n error: Error | null;\n}\n\n/** A queued message that became the thread's running turn, which this chat attaches to. */\ninterface StartedQueuedTurn {\n messageId: string;\n runId: string;\n text: string;\n attachments: MessageAttachment[];\n}\n\nconst EMPTY_QUEUE: ChatQueueState = { items: [], paused: null };\n\nlet localQueueSequence = 0;\n\n/** The user message a queued message becomes once its turn starts. */\nfunction queuedUserMessage(turn: StartedQueuedTurn): UIMessage {\n return {\n id: turn.messageId,\n role: 'user',\n metadata: { createdAt: new Date().toISOString() },\n parts: [\n ...turn.attachments.map((attachment) => ({\n type: 'file' as const,\n mediaType: attachment.contentType,\n filename: attachment.name,\n url: attachment.url,\n providerMetadata: { agent: { mediaId: attachment.mediaId } },\n })),\n ...(turn.text.length > 0 ? [{ type: 'text' as const, text: turn.text }] : []),\n ],\n };\n}\n\n/** The text and staged files of whatever `sendMessage` was handed, for a send that is queued. */\nfunction draftOf(message: unknown): { text: string; attachments: MessageAttachment[] } {\n if (typeof message !== 'object' || message === null) {\n return { text: '', attachments: [] };\n }\n const draft = message as {\n text?: unknown;\n files?: unknown;\n parts?: Array<{ type?: string; text?: unknown }>;\n };\n let text = typeof draft.text === 'string' ? draft.text : '';\n if (text === '' && Array.isArray(draft.parts)) {\n text = draft.parts\n .filter((part) => part.type === 'text' && typeof part.text === 'string')\n .map((part) => part.text as string)\n .join('');\n }\n const files = Array.isArray(draft.files)\n ? (draft.files as Array<Record<string, unknown>>)\n : Array.isArray(draft.parts)\n ? (draft.parts as Array<Record<string, unknown>>).filter((part) => part.type === 'file')\n : [];\n const attachments = files.flatMap((file): MessageAttachment[] => {\n const mediaId = (file.providerMetadata as { agent?: { mediaId?: unknown } } | undefined)?.agent\n ?.mediaId;\n return typeof mediaId === 'string'\n ? [\n {\n mediaId,\n url: String(file.url ?? ''),\n contentType: String(file.mediaType ?? 'application/octet-stream'),\n name: String(file.filename ?? mediaId),\n },\n ]\n : [];\n });\n return { text, attachments };\n}\n\nfunction lastUserIndex(messages: UIMessage[]): number {\n for (let index = messages.length - 1; index >= 0; index -= 1) {\n if (messages[index]?.role === 'user') return index;\n }\n return -1;\n}\n\n/** Why the composer cannot send right now. */\nexport type ComposerBlock = 'empty' | 'busy' | 'uploading' | 'quota';\n\n/** A headless composer: the draft, its files, and whether (and why not) it can send. */\nexport interface ChatComposer {\n text: string;\n setText: (text: string) => void;\n /** The staged attachments — `useAttachments` state on the chat's backend. */\n files: AttachmentsState;\n canSend: boolean;\n /** Why `canSend` is false, or `null`. */\n blockedBy: ComposerBlock | null;\n /**\n * Send the draft with the ready files attached, then clear both. A no-op while blocked.\n *\n * `submit({ mode })` says what to do if a turn is running, for this send only — `'interrupt'`\n * for a \"send now\" button next to a plain send that queues. It overrides `whileRunning`\n * (`'block'` included) and clears the draft like any other submit.\n */\n submit: (options?: SendWhileRunning) => Promise<void>;\n}\n\ninterface AddToolResultArgs {\n tool: string;\n toolCallId: string;\n output: unknown;\n}\n\nlet localChatSequence = 0;\nfunction localChatId(): string {\n localChatSequence += 1;\n return `local-chat-${localChatSequence}`;\n}\n\n/**\n * The agent chat, wired: the AI SDK v7 `useChat` over `AgentChatTransport`, a thread's history\n * loaded and a streaming turn re-attached on its own, a quota send gate, a model picker, a headless\n * composer with attachments, and a transcript whose approve/reject/answer/skip/stop/fork/regenerate\n * are already bound. Every piece is also a hook of its own (`useChatTranscript`, `useAttachments`,\n * `useModels`, `useQuota`, `useThreads`) for a host that wants to wire it differently.\n */\nexport function useAgentChat<B extends AgentBackend = AgentBackend>(\n options: UseAgentChatOptions<B> = {},\n) {\n const providerCapabilities = useAgentUiCapabilities();\n const capabilitiesRef = useRef(providerCapabilities);\n capabilitiesRef.current = providerCapabilities;\n const latest = useRef(options);\n latest.current = options;\n\n // Identity-stable: the first backend this chat mounted with is the one it keeps.\n const resolved = useAgentBackend<B>(options.backend);\n const client = useRef(resolved).current;\n\n // The thread the backend created for a threadless chat (or a fork moved to), captured from the\n // `meta` frame. Every send after the first reuses it; an explicit `threadId` option always wins.\n const createdThreadId = useRef<string | undefined>(undefined);\n\n // Which conversation `useChat` holds. A new `threadId` is a different conversation — except the\n // one this chat itself created, which a host passes back once it syncs its URL.\n const chatIdRef = useRef<string>(options.threadId ?? localChatId());\n const boundThreadRef = useRef(options.threadId);\n if (options.threadId !== boundThreadRef.current) {\n boundThreadRef.current = options.threadId;\n const adopting = options.threadId !== undefined && options.threadId === createdThreadId.current;\n if (!adopting) {\n chatIdRef.current = options.threadId ?? localChatId();\n createdThreadId.current = undefined;\n }\n }\n const chatId = chatIdRef.current;\n\n const [runId, setRunId] = useState<string | undefined>(options.resumeRunId);\n const runIdRef = useRef<string | undefined>(runId);\n runIdRef.current = runId;\n\n // The run id learned (via the `meta` frame) during the CURRENT in-flight attempt only — reset by\n // the transport's `onAttemptStart`. `onRunSettled` reads THIS so an attempt that fails before\n // learning a run id never misattributes its outcome to the previous run.\n const settlingRunIdRef = useRef<string | undefined>(undefined);\n\n // The run id discovered from the thread's `activeRunId`, read by the transport's\n // `getResumeRunId` alongside the explicit `resumeRunId` option.\n const autoResumeRunIdRef = useRef<string | undefined>(undefined);\n // The loaded thread's active run, if any — `null` once read with none.\n const [activeRunId, setActiveRunId] = useState<string | null>(null);\n // The thread whose history read has settled (loaded or failed). The history is loading until it\n // is the bound thread — derived, so it already reads `true` on the first render, before the\n // effect below has asked for anything, and a page never flashes its empty state.\n const [historyFor, setHistoryFor] = useState<string | undefined>(undefined);\n const [historyError, setHistoryError] = useState<Error | null>(null);\n // How the last run's stream said it failed (`event: error`), until the next attempt starts.\n const [runError, setRunError] = useState<AgentRunFailure | null>(null);\n // The model pinned on the loaded thread.\n const [threadModel, setThreadModel] = useState<string | null>(null);\n // The persona pinned on the thread — read with its history, and mirrored from each send that\n // names one. `null` → none pinned (the agent's default persona applies).\n const [threadPersona, setThreadPersona] = useState<string | null>(null);\n const [pickedModel, setPickedModel] = useState<string | undefined>(undefined);\n const pickedModelRef = useRef(pickedModel);\n pickedModelRef.current = pickedModel;\n // The agent is locked to one model (read off the catalog once it loads).\n const lockedRef = useRef(false);\n // A pin asked for before the chat had a thread — sent once the first send creates one.\n const pendingPin = useRef<{ model: string | null } | undefined>(undefined);\n\n // One-shot flag read (and cleared) by the transport's getBody so the next send carries\n // `regenerate: true` — telling the backend to re-run the last exchange instead of appending.\n const regenerateNext = useRef(false);\n\n const currentThreadId = useCallback(\n (): string | undefined => latest.current.threadId ?? createdThreadId.current,\n [],\n );\n\n // ---- queue state (declared early: the transport's callbacks feed it) ------------------------\n const [queueState, setQueueState] = useState<ChatQueueState>(EMPTY_QUEUE);\n const queueStateRef = useRef(queueState);\n const applyQueue = useCallback((next: ChatQueueState) => {\n queueStateRef.current = next;\n setQueueState(next);\n }, []);\n // Sends on their way to the server, shown in the queue until it answers.\n const [pendingSends, setPendingSends] = useState<QueuedChatMessage[]>([]);\n const [queueError, setQueueError] = useState<Error | null>(null);\n // The queued message the running turn handed the thread to — attached to once that turn settles.\n const handoff = useRef<StartedQueuedTurn | undefined>(undefined);\n // A plain send the server queued instead of starting (another tab's turn was running).\n const queuedSend = useRef<QueuedSendResult | undefined>(undefined);\n const proposalRefreshRef = useRef<() => Promise<void>>(async () => {});\n // Queue sends made before a new chat's first turn named its thread.\n const threadWaiters = useRef<Array<(threadId: string) => void>>([]);\n\n /** The body fields every send carries: agent, persona, thread, model, page context. */\n const turnBody = useCallback((): Record<string, unknown> => {\n const current = latest.current;\n // The server pins a persona a send names; mirror it so a picker reads the thread's state.\n if (current.persona !== undefined) setThreadPersona(current.persona);\n const pageContext = current.getPageContext?.() ?? null;\n const threadId = currentThreadId();\n // A locked agent runs on its own model: a pick is not sent (the server would refuse it).\n const model = current.model ?? (lockedRef.current ? undefined : pickedModelRef.current);\n return {\n // Read per send: a host that switches agents before the first message (a picker on a new\n // chat) sends the one picked now, not the one this chat mounted with.\n ...(current.agent !== undefined ? { agent: current.agent } : {}),\n ...(current.persona !== undefined ? { persona: current.persona } : {}),\n ...(threadId !== undefined ? { threadId } : {}),\n ...(model !== undefined ? { model } : {}),\n ...(pageContext ? { pageContext } : {}),\n ...((current.uiCapabilities ?? capabilitiesRef.current) === undefined\n ? {}\n : { uiCapabilities: current.uiCapabilities ?? capabilitiesRef.current }),\n };\n }, [currentThreadId]);\n\n // Where the live stream stands — `reconnecting` while the transport retries a dropped one.\n const [connection, setConnection] = useState<StreamConnectionState>({ status: 'live' });\n // The run ended while the stream was away: what streamed is incomplete, the thread is not.\n const resyncAfterSettle = useRef(false);\n\n // Identity-stable: per-render config is read through `latest`.\n // biome-ignore lint/correctness/useExhaustiveDependencies: stable by design\n const transport = useMemo(() => {\n function onMeta(meta: AgentStreamMeta): void {\n settlingRunIdRef.current = meta.runId;\n setRunId(meta.runId);\n if (meta.threadId) {\n const waiting = threadWaiters.current;\n threadWaiters.current = [];\n for (const resolve of waiting) resolve(meta.threadId);\n }\n if (\n latest.current.threadId === undefined &&\n meta.threadId &&\n createdThreadId.current !== meta.threadId\n ) {\n createdThreadId.current = meta.threadId;\n const pin = pendingPin.current;\n if (pin !== undefined) {\n pendingPin.current = undefined;\n void client.updateThread(meta.threadId, { model: pin.model }).catch(() => undefined);\n }\n latest.current.onThreadCreated?.(meta.threadId);\n notifyThreads(client, { type: 'changed' });\n }\n }\n return new AgentChatTransport({\n backend: client,\n ...(options.reconnect !== undefined ? { reconnect: options.reconnect } : {}),\n onConnectionChange: (state) => {\n if (state.status === 'gone') resyncAfterSettle.current = true;\n setConnection(state.status === 'gone' ? { status: 'live' } : state);\n },\n ...(options.agent !== undefined ? { agent: options.agent } : {}),\n getBody: () => {\n const regenerate = regenerateNext.current;\n regenerateNext.current = false;\n return { ...turnBody(), ...(regenerate ? { regenerate: true } : {}) };\n },\n getResumeRunId: () => latest.current.resumeRunId ?? autoResumeRunIdRef.current,\n // A stream attached to after a reload carries no `meta` frame: without this the chat would\n // be reading a run it cannot name, and `cancel()` would stop nothing.\n onResumeAttached: (resumedRunId) => {\n settlingRunIdRef.current = resumedRunId;\n setRunId(resumedRunId);\n },\n onMeta,\n onAttemptStart: () => {\n settlingRunIdRef.current = undefined;\n setRunError(null);\n },\n onRunError: (failure) => setRunError(failure),\n // A queued turn this chat went to attach to had already finished: read what it wrote.\n onResumeGone: () => {\n void resyncFromThread();\n },\n });\n }, []);\n\n // Assigned once `refreshBackground` exists below.\n const backgroundRef = useRef<() => Promise<void>>(() => Promise.resolve());\n\n const chat = useChat({\n transport,\n id: chatId,\n resume: options.resumeRunId !== undefined,\n ...(options.initialMessages !== undefined ? { messages: options.initialMessages } : {}),\n onData: (part) => {\n latest.current.onData?.(part);\n if (part.type === 'data-proposal-decision') void proposalRefreshRef.current();\n if (part.type === 'data-queue') {\n onQueueData(part.data);\n }\n if (part.type === 'data-title') {\n const title = (part.data as { title?: unknown } | null)?.title;\n if (typeof title === 'string') {\n latest.current.onTitle?.(title);\n const threadId = currentThreadId();\n if (threadId !== undefined) notifyThreads(client, { type: 'title', threadId, title });\n }\n }\n },\n onFinish: ({ isError }) => {\n latest.current.onFinish?.();\n if (latest.current.background === true) {\n void backgroundRef.current();\n }\n const settledRunId = settlingRunIdRef.current;\n if (settledRunId !== undefined) {\n latest.current.onRunSettled?.({\n runId: settledRunId,\n status: isError ? 'failed' : 'completed',\n });\n notifyThreads(client, { type: 'changed' });\n }\n setConnection({ status: 'live' });\n const queuedInstead = queuedSend.current;\n if (queuedInstead !== undefined) {\n queuedSend.current = undefined;\n // The SDK already showed the send as a user message; it is waiting in the queue instead.\n chatRef.current.setMessages((current) => {\n const last = lastUserIndex(current);\n return last === -1 ? current : current.slice(0, last);\n });\n }\n const next = handoff.current;\n handoff.current = undefined;\n if (next !== undefined) {\n attachTo(next);\n return;\n }\n if (resyncAfterSettle.current) {\n resyncAfterSettle.current = false;\n void resyncFromThread();\n }\n },\n });\n\n const chatRef = useRef(chat);\n chatRef.current = chat;\n\n /** A `data-queue` part: the queue as it now stands, and maybe the turn this run handed over to. */\n function onQueueData(data: unknown): void {\n const frame = (data ?? {}) as {\n queue?: ChatQueueState;\n started?: { messageId: string; runId: string };\n queuedSend?: QueuedSendResult;\n };\n const before = queueStateRef.current;\n if (frame.queue !== undefined) applyQueue(frame.queue);\n const started = frame.started;\n // A run's own stream may open by announcing itself (a queue kicked while idle): not a handoff.\n if (started !== undefined && started.runId !== settlingRunIdRef.current) {\n const waiting = before.items.find((item) => item.id === started.messageId);\n handoff.current = {\n ...started,\n text: waiting?.content ?? '',\n attachments: waiting?.attachments ?? [],\n };\n }\n if (frame.queuedSend !== undefined) {\n queuedSend.current = frame.queuedSend;\n if (frame.queuedSend.runId !== undefined) {\n handoff.current = {\n messageId: frame.queuedSend.messageId,\n runId: frame.queuedSend.runId,\n ...draftOf(chatRef.current.messages[lastUserIndex(chatRef.current.messages)]),\n };\n }\n }\n }\n\n /**\n * Show a queued message as the user message it now is, and attach to the turn it started. After\n * the SDK has fully settled the previous response — resuming from inside its `onFinish` would\n * have that response's cleanup clobber this one.\n */\n function attachTo(turn: StartedQueuedTurn): void {\n setTimeout(() => {\n if (turn.text.length > 0 || turn.attachments.length > 0) {\n chatRef.current.setMessages((current) =>\n current.some((message) => message.id === turn.messageId)\n ? current\n : [...current, queuedUserMessage(turn)],\n );\n } else {\n // Queued somewhere this chat never saw: the thread has it, once the turn has run.\n resyncAfterSettle.current = true;\n }\n autoResumeRunIdRef.current = turn.runId;\n void chatRef.current.resumeStream();\n }, 0);\n }\n\n /** Replace the transcript with the persisted thread — after a run finished while we were away. */\n async function resyncFromThread(): Promise<void> {\n const threadId = currentThreadId();\n if (threadId === undefined) return;\n try {\n const thread = await client.getThread(threadId);\n chatRef.current.setMessages(storedThreadToUiMessages(thread.messages));\n } catch {\n /* best-effort: the partial answer stays until the next load */\n }\n }\n\n // A new conversation starts from rest: nothing of the previous thread's run state carries over.\n const firstChatId = useRef(chatId);\n // biome-ignore lint/correctness/useExhaustiveDependencies: `applyQueue` is stable; `chatId` names the conversation\n useEffect(() => {\n if (chatId === firstChatId.current) return;\n firstChatId.current = chatId;\n setRunId(undefined);\n setActiveRunId(null);\n setThreadModel(null);\n setThreadPersona(null);\n setPickedModel(undefined);\n setBackgroundRuns([]);\n setHistoryError(null);\n setRunError(null);\n autoResumeRunIdRef.current = undefined;\n pendingPin.current = undefined;\n applyQueue(EMPTY_QUEUE);\n setPendingSends([]);\n setQueueError(null);\n handoff.current = undefined;\n queuedSend.current = undefined;\n }, [chatId]);\n\n // A thread's history and its still-streaming turn, in one read. Re-runs per conversation; a\n // stale response (the thread changed mid-flight) is dropped.\n // biome-ignore lint/correctness/useExhaustiveDependencies: `chatId` names the conversation\n useEffect(() => {\n const threadId = options.threadId;\n if (threadId === undefined) return;\n // Adopted: this chat created the thread, and its messages are the live ones.\n if (threadId === createdThreadId.current) return;\n const current = latest.current;\n const wantHistory = current.history !== false && current.initialMessages === undefined;\n const wantResume = current.resume !== false && current.resumeRunId === undefined;\n if (!wantHistory && !wantResume) return;\n let cancelled = false;\n client\n .getThread(threadId)\n .then(\n (thread: ThreadDetail | undefined) => {\n if (cancelled || thread == null) return;\n const active = thread.activeRunId ?? null;\n const stored = Array.isArray(thread.messages) ? thread.messages : [];\n setActiveRunId(active);\n setThreadModel(thread.model ?? null);\n setThreadPersona(thread.persona ?? null);\n setHistoryError(null);\n const queue = thread.queue ?? EMPTY_QUEUE;\n applyQueue(queue);\n // Messages left waiting with nothing running and nothing pausing them — the process\n // that would have started them went away. Start the head now.\n if (\n queue.items.length > 0 &&\n queue.paused === null &&\n active === null &&\n typeof client.resumeQueue === 'function'\n ) {\n void resumeQueueRef.current().catch(() => undefined);\n }\n const resuming = wantResume && active !== null;\n if (wantHistory && chatRef.current.messages.length === 0) {\n // The run being resumed replays from its first frame, so its rows are left to the stream.\n const rows = resuming\n ? stored.filter(\n (message: StoredMessage) =>\n !(message.role === 'assistant' && message.runId === active),\n )\n : stored;\n chatRef.current.setMessages(storedThreadToUiMessages(rows));\n }\n if (resuming) {\n autoResumeRunIdRef.current = active;\n void chatRef.current.resumeStream();\n }\n },\n (error: unknown) => {\n if (cancelled) return;\n setHistoryError(error instanceof Error ? error : new Error(String(error)));\n },\n )\n .finally(() => {\n if (!cancelled) setHistoryFor(threadId);\n });\n return () => {\n cancelled = true;\n };\n }, [client, chatId, options.threadId]);\n\n const isLoadingHistory =\n options.threadId !== undefined &&\n options.threadId !== createdThreadId.current &&\n options.history !== false &&\n options.initialMessages === undefined &&\n historyFor !== options.threadId;\n\n /**\n * One turn in flight per chat. The SDK commits its single in-flight response BEFORE it reaches\n * the transport, so a second overlapping turn cannot be untangled downstream. The ref rather than\n * `chat.status`: a double-submitted composer arrives in the same tick, before status moves.\n */\n const turnInFlight = useRef(false);\n const isTurnInFlight = useCallback(\n () => turnInFlight.current || transport.isAttemptLive,\n [transport],\n );\n\n // ---- quota ---------------------------------------------------------------------------------\n const quota: QuotaState = useQuota({\n backend: client,\n enabled: options.quota !== false && typeof client.getQuota === 'function',\n });\n const blocked: QuotaBlock | null =\n options.blocked !== undefined ? options.blocked : quota.blocked;\n const blockedRef = useRef(blocked);\n blockedRef.current = blocked;\n\n // ---- queue ---------------------------------------------------------------------------------\n const whileRunning: WhileRunning =\n typeof client.enqueueMessage === 'function' ? (options.whileRunning ?? 'queue') : 'block';\n const whileRunningRef = useRef(whileRunning);\n whileRunningRef.current = whileRunning;\n const canQueueRef = useRef(false);\n canQueueRef.current = typeof client.enqueueMessage === 'function';\n\n /** This chat's thread — waiting for a new chat's first turn to name it, when one is in flight. */\n const threadForQueue = useCallback(async (): Promise<string> => {\n const known = currentThreadId();\n if (known !== undefined) return known;\n if (!isTurnInFlight()) throw new Error('queue: this chat has no thread yet');\n return new Promise<string>((resolve) => threadWaiters.current.push(resolve));\n }, [currentThreadId, isTurnInFlight]);\n\n /** Run a queue operation, keeping the last failure on `chat.queue.error`. */\n const queueCall = useCallback(async <T>(run: () => Promise<T>): Promise<T> => {\n try {\n const result = await run();\n setQueueError(null);\n return result;\n } catch (error) {\n setQueueError(error instanceof Error ? error : new Error(String(error)));\n throw error;\n }\n }, []);\n\n // biome-ignore lint/correctness/useExhaustiveDependencies: `attachTo` reads refs only\n const enqueue = useCallback(\n async (\n text: string,\n {\n attachments = [],\n mode = 'queue',\n }: { attachments?: MessageAttachment[]; mode?: 'queue' | 'interrupt' } = {},\n ): Promise<void> => {\n const block = blockedRef.current;\n if (block != null) throw new QuotaBlockedError(block);\n const send = client.enqueueMessage;\n if (typeof send !== 'function') throw new AgentBackendUnsupportedError('enqueueMessage');\n localQueueSequence += 1;\n const localId = `local-queued-${localQueueSequence}`;\n setPendingSends((current) => [\n ...current,\n {\n id: localId,\n text,\n attachments,\n files: attachments.map(attachmentFile),\n state: 'sending',\n interrupt: mode === 'interrupt',\n createdAt: new Date().toISOString(),\n },\n ]);\n try {\n await queueCall(async () => {\n const threadId = await threadForQueue();\n const result = await send.call(client, {\n body: {\n ...turnBody(),\n threadId,\n message: text,\n mode,\n ...(attachments.length > 0\n ? { attachments: attachments.map(({ mediaId }) => ({ mediaId })) }\n : {}),\n },\n });\n applyQueue(result.queue);\n if (result.runId !== undefined) {\n // Nothing was running after all: it started at once.\n const turn = { messageId: result.messageId, runId: result.runId, text, attachments };\n if (isTurnInFlight()) handoff.current = turn;\n else attachTo(turn);\n }\n });\n } finally {\n setPendingSends((current) => current.filter((item) => item.id !== localId));\n }\n },\n [client, queueCall, threadForQueue, turnBody, applyQueue, isTurnInFlight],\n );\n\n type SdkSendMessage = typeof chat.sendMessage;\n const sendMessage = useCallback(\n async (\n message?: Parameters<SdkSendMessage>[0],\n options?: Parameters<SdkSendMessage>[1] & SendWhileRunning,\n ): Promise<void> => {\n const block = blockedRef.current;\n if (block != null) throw new QuotaBlockedError(block);\n // `mode` is this hook's, not the SDK's: it never reaches the request.\n const { mode: ownMode, ...sdkOptions } = options ?? {};\n if (isTurnInFlight()) {\n // Mid-turn: the message waits in the thread's queue — unless this chat blocks instead. A\n // backend that cannot queue blocks whatever was asked for.\n const mode = canQueueRef.current ? (ownMode ?? whileRunningRef.current) : 'block';\n if (mode === 'block') return;\n const draft = draftOf(message);\n await enqueue(draft.text, { attachments: draft.attachments, mode });\n return;\n }\n turnInFlight.current = true;\n try {\n await chatRef.current.sendMessage(\n message as Parameters<SdkSendMessage>[0],\n options === undefined ? undefined : (sdkOptions as Parameters<SdkSendMessage>[1]),\n );\n } finally {\n turnInFlight.current = false;\n }\n },\n [isTurnInFlight, enqueue],\n );\n\n const removeQueued = useCallback(\n async (id: string): Promise<void> => {\n const previous = queueStateRef.current;\n applyQueue({ ...previous, items: previous.items.filter((item) => item.id !== id) });\n try {\n applyQueue(await queueCall(() => requireBackendMethod(client, 'removeQueuedMessage')(id)));\n } catch (error) {\n applyQueue(previous);\n throw error;\n }\n },\n [client, queueCall, applyQueue],\n );\n\n // biome-ignore lint/correctness/useExhaustiveDependencies: `attachTo` reads refs only\n const interruptQueued = useCallback(\n async (id: string): Promise<void> => {\n const previous = queueStateRef.current;\n const moving = previous.items.find((item) => item.id === id);\n if (moving !== undefined) {\n // Shown where it will be at once: at the head, as the interrupt, the pause lifted.\n applyQueue({\n paused: null,\n items: [\n { ...moving, interrupt: true },\n ...previous.items.filter((item) => item.id !== id),\n ],\n });\n }\n try {\n const result = await queueCall(() =>\n requireBackendMethod(client, 'interruptQueuedMessage')(id),\n );\n applyQueue({ items: result.items, paused: result.paused });\n if (result.runId !== undefined) {\n // Nothing was running: it started at once.\n const turn = {\n messageId: result.runId,\n runId: result.runId,\n text: moving?.content ?? '',\n attachments: moving?.attachments ?? [],\n };\n if (isTurnInFlight()) handoff.current = turn;\n else attachTo(turn);\n }\n } catch (error) {\n applyQueue(previous);\n throw error;\n }\n },\n [client, queueCall, applyQueue, isTurnInFlight],\n );\n\n const editQueued = useCallback(\n async (id: string, text: string): Promise<void> => {\n applyQueue(\n await queueCall(() =>\n requireBackendMethod(client, 'updateQueuedMessage')(id, { message: text }),\n ),\n );\n },\n [client, queueCall, applyQueue],\n );\n\n const moveQueued = useCallback(\n async (id: string, index: number): Promise<void> => {\n const previous = queueStateRef.current;\n const moving = previous.items.find((item) => item.id === id);\n if (moving !== undefined) {\n const rest = previous.items.filter((item) => item.id !== id);\n rest.splice(Math.max(0, Math.min(rest.length, index)), 0, moving);\n applyQueue({ ...previous, items: rest });\n }\n try {\n applyQueue(\n await queueCall(() =>\n requireBackendMethod(client, 'updateQueuedMessage')(id, { position: index }),\n ),\n );\n } catch (error) {\n applyQueue(previous);\n throw error;\n }\n },\n [client, queueCall, applyQueue],\n );\n\n const clearQueue = useCallback(async (): Promise<void> => {\n const threadId = currentThreadId();\n if (threadId === undefined) return;\n applyQueue(await queueCall(() => requireBackendMethod(client, 'clearQueue')(threadId)));\n }, [client, queueCall, currentThreadId, applyQueue]);\n\n // biome-ignore lint/correctness/useExhaustiveDependencies: `attachTo` reads refs only\n const resumeQueue = useCallback(async (): Promise<void> => {\n const threadId = currentThreadId();\n if (threadId === undefined) return;\n const before = queueStateRef.current;\n const result = await queueCall(() => requireBackendMethod(client, 'resumeQueue')(threadId));\n applyQueue({ items: result.items, paused: result.paused });\n if (result.runId !== undefined) {\n const head = before.items.find((item) => item.id === result.runId) ?? before.items[0];\n const turn = {\n messageId: result.runId,\n runId: result.runId,\n text: head?.content ?? '',\n attachments: head?.attachments ?? [],\n };\n if (isTurnInFlight()) handoff.current = turn;\n else attachTo(turn);\n }\n }, [client, queueCall, currentThreadId, applyQueue, isTurnInFlight]);\n const resumeQueueRef = useRef(resumeQueue);\n resumeQueueRef.current = resumeQueue;\n\n const queuedItems: QueuedChatMessage[] = [\n ...pendingSends.filter((item) => item.interrupt),\n ...queueState.items.map(\n (item): QueuedChatMessage => ({\n id: item.id,\n text: item.content,\n attachments: item.attachments ?? [],\n files: (item.attachments ?? []).map(attachmentFile),\n state: 'queued',\n interrupt: item.interrupt === true,\n createdAt: item.createdAt,\n }),\n ),\n ...pendingSends.filter((item) => !item.interrupt),\n ];\n const queue: ChatQueue = {\n items: queuedItems,\n paused: queueState.paused,\n isSupported: typeof client.enqueueMessage === 'function',\n add: enqueue,\n remove: removeQueued,\n interrupt: interruptQueued,\n edit: editQueued,\n move: moveQueued,\n clear: clearQueue,\n resume: resumeQueue,\n error: queueError,\n };\n\n // chat.addToolResult is generic over the backend's tool registry, which we don't statically type\n // here. Expose a string-keyed adapter and narrow once at the SDK boundary.\n type SdkAddToolResult = typeof chat.addToolResult;\n type SdkArgs = Parameters<SdkAddToolResult>[0];\n const addToolResult = useCallback(\n ({ tool, toolCallId, output }: AddToolResultArgs) =>\n chatRef.current.addToolResult({\n tool,\n toolCallId,\n output,\n } as unknown as SdkArgs),\n [],\n );\n\n // ---- background runs -----------------------------------------------------------------------\n const [backgroundRuns, setBackgroundRuns] = useState<BackgroundRun[]>([]);\n\n /** Re-derive what is running in the background, and pull in anything that has landed since. */\n const refreshBackground = useCallback(async (): Promise<void> => {\n const threadId = currentThreadId();\n if (threadId === undefined) {\n return;\n }\n const thread = await client.getThread(threadId);\n const runs = backgroundRunsFromThread(thread.messages);\n setBackgroundRuns(runs);\n const landed = runs\n .map((run) => run.message)\n .filter((message): message is NonNullable<typeof message> => message !== undefined);\n if (landed.length === 0) {\n return;\n }\n // Appended rather than re-seeding the list: the session's own messages hold live stream state\n // that the persisted rows do not carry.\n chatRef.current.setMessages((current) => {\n const known = new Set(current.map((message) => message.id));\n const missing = landed.filter((message) => !known.has(message.id));\n return missing.length === 0\n ? current\n : [...current, ...missing.map((message) => storedMessageToUiMessage(message))];\n });\n }, [client, currentThreadId]);\n\n backgroundRef.current = refreshBackground;\n\n const isWorking = backgroundRuns.some((run) => run.status === 'running');\n\n // biome-ignore lint/correctness/useExhaustiveDependencies: `chatId` names the conversation\n useEffect(() => {\n if (options.background !== true || options.threadId === undefined) {\n return;\n }\n void refreshBackground();\n }, [options.background, options.threadId, chatId, refreshBackground]);\n\n useEffect(() => {\n const every = latest.current.backgroundPollMs ?? 5000;\n if (latest.current.background !== true || !isWorking || every <= 0) {\n return;\n }\n const timer = setInterval(() => void refreshBackground(), every);\n return () => clearInterval(timer);\n }, [isWorking, refreshBackground]);\n\n const proposals = useActionProposals(\n client,\n options.proposals === false ||\n (options.proposals !== true && options.history === false && options.resume === false)\n ? undefined\n : currentThreadId(),\n (update) => chatRef.current.setMessages(update),\n `${chat.status}:${connection.status}`,\n options.proposalPollMs,\n );\n\n proposalRefreshRef.current = proposals.refresh;\n\n // ---- actions -------------------------------------------------------------------------------\n const cancel = useCallback(async (): Promise<void> => {\n // Close the SSE on the client first so the UI flips out of streaming, then hard-abort\n // server-side (a late terminal step can outlive the connection close alone).\n chatRef.current.stop();\n const active = runIdRef.current;\n if (active) {\n try {\n await client.cancelStream(active);\n } catch {\n /* best-effort — the SDK stop already flipped the UI */\n }\n }\n // The stream that would have carried the `queue` frame was closed above, so a queue the stop\n // just paused is read back: otherwise its messages keep saying \"up next\" with nothing coming.\n const threadId = currentThreadId();\n if (\n threadId !== undefined &&\n queueStateRef.current.items.length > 0 &&\n typeof client.getQueue === 'function'\n ) {\n try {\n applyQueue(await client.getQueue(threadId));\n } catch {\n /* best-effort — the next thread read brings it */\n }\n }\n }, [client, currentThreadId, applyQueue]);\n\n // Approve / reject / answer / skip route by tool-call id alone — the server derives the run\n // awaiting it (a sub-agent's own run when the call belongs to a delegated agent).\n const approve = useCallback(\n async ({ toolCallId, target, remember, via }: ApproveInput): Promise<void> => {\n if (target?.kind === 'proposal') {\n const threadId = target.threadId ?? currentThreadId();\n if (threadId === undefined)\n throw new Error('A proposal decision requires its thread scope');\n await requireBackendMethod(\n client,\n 'approveActionProposal',\n )({\n threadId,\n proposalId: target.proposalId,\n ...(remember === true ? { remember: true } : {}),\n });\n await proposals.refresh();\n return;\n }\n await requireBackendMethod(\n client,\n 'approveToolCall',\n )({\n toolCallId,\n ...(remember === true ? { remember: true } : {}),\n ...(via !== undefined ? { via } : {}),\n });\n },\n [client, currentThreadId, proposals.refresh],\n );\n\n const reject = useCallback(\n async ({ toolCallId, target, reason, via }: RejectInput): Promise<void> => {\n if (target?.kind === 'proposal') {\n const threadId = target.threadId ?? currentThreadId();\n if (threadId === undefined)\n throw new Error('A proposal decision requires its thread scope');\n await requireBackendMethod(\n client,\n 'rejectActionProposal',\n )({\n threadId,\n proposalId: target.proposalId,\n ...(reason === undefined ? {} : { reason }),\n });\n await proposals.refresh();\n return;\n }\n await requireBackendMethod(\n client,\n 'rejectToolCall',\n )({\n toolCallId,\n ...(reason !== undefined ? { reason } : {}),\n ...(via !== undefined ? { via } : {}),\n });\n },\n [client, currentThreadId, proposals.refresh],\n );\n\n const answer = useCallback(\n async ({ toolCallId, answers, via }: AnswerInput): Promise<void> => {\n await requireBackendMethod(\n client,\n 'answerToolCall',\n )({\n toolCallId,\n ...(answers !== undefined ? { answers } : {}),\n ...(via !== undefined ? { via } : {}),\n });\n },\n [client],\n );\n\n const skip = useCallback(\n async ({ toolCallId, via }: SkipInput): Promise<void> => {\n await requireBackendMethod(\n client,\n 'skipToolCall',\n )({ toolCallId, ...(via !== undefined ? { via } : {}) });\n },\n [client],\n );\n\n // Re-run the last exchange: flag the next request as a regenerate (so the backend truncates and\n // re-answers instead of appending) and let the SDK re-issue it.\n const regenerate = useCallback(\n (_input?: Partial<MessageActionInput>): void => {\n const block = blockedRef.current;\n if (block != null) throw new QuotaBlockedError(block);\n if (isTurnInFlight()) return;\n regenerateNext.current = true;\n turnInFlight.current = true;\n void chatRef.current.regenerate().finally(() => {\n turnInFlight.current = false;\n });\n },\n [isTurnInFlight],\n );\n\n /**\n * The persisted id of a message on screen. A message streamed in this session carries the\n * client's own id, so the row it became is found by the run that wrote it.\n */\n const storedIdOf = useCallback(\n async (messageId: string, threadId: string): Promise<string> => {\n const message = chatRef.current.messages.find((candidate) => candidate.id === messageId);\n const runOf = (message?.metadata as AgentMessageMetadata | undefined)?.runId;\n if (runOf === undefined) return messageId;\n const thread = await client.getThread(threadId);\n const row = [...thread.messages]\n .reverse()\n .find((candidate) => candidate.role === 'assistant' && candidate.runId === runOf);\n return row?.id ?? messageId;\n },\n [client],\n );\n\n /**\n * Branch the conversation at `messageId` into a new thread (`onThreadCreated` gets its id).\n * Defaults to this chat's thread.\n */\n const fork = useCallback(\n async ({\n messageId,\n threadId,\n }: MessageActionInput & { threadId?: string }): Promise<ThreadSummary> => {\n const source = threadId ?? currentThreadId();\n if (source === undefined) throw new Error('fork: this chat has no thread yet');\n const stored = await storedIdOf(messageId, source);\n const forked = await requireBackendMethod(client, 'forkFromMessage')(source, stored);\n notifyThreads(client, { type: 'changed' });\n latest.current.onThreadCreated?.(forked.id);\n return forked;\n },\n [client, currentThreadId, storedIdOf],\n );\n\n /** Delete `messageId` and everything after it on the thread (default: this chat's). */\n const truncateFrom = useCallback(\n async ({ messageId, threadId }: MessageActionInput & { threadId?: string }): Promise<void> => {\n const target = threadId ?? currentThreadId();\n if (target === undefined) throw new Error('truncateFrom: this chat has no thread yet');\n const stored = await storedIdOf(messageId, target);\n await requireBackendMethod(client, 'truncateFromMessage')(target, stored);\n },\n [client, currentThreadId, storedIdOf],\n );\n\n /** Make a transient thread (default: this chat's) a regular one, listed by `useThreads`. */\n const promote = useCallback(\n async ({ threadId }: { threadId?: string } = {}): Promise<void> => {\n const target = threadId ?? currentThreadId();\n if (target === undefined) throw new Error('promote: this chat has no thread yet');\n await requireBackendMethod(client, 'promoteThread')(target);\n notifyThreads(client, { type: 'changed' });\n },\n [client, currentThreadId],\n );\n\n // ---- models --------------------------------------------------------------------------------\n const [modelsWanted, setModelsWanted] = useState(false);\n const modelsWantedRef = useRef(modelsWanted);\n modelsWantedRef.current = modelsWanted;\n const catalog = useModels({\n backend: client,\n ...(options.agent !== undefined ? { agent: options.agent } : {}),\n enabled: modelsWanted && typeof client.listModels === 'function',\n });\n const wantModels = useCallback(() => {\n if (modelsWantedRef.current) return;\n modelsWantedRef.current = true;\n // After render: the getter may be read while a child renders.\n queueMicrotask(() => setModelsWanted(true));\n }, []);\n lockedRef.current = catalog.locked !== null;\n const selectModel = useCallback((id: string) => {\n if (!lockedRef.current) setPickedModel(id);\n }, []);\n const pinToThread = useCallback(\n async (model: string | null): Promise<void> => {\n const threadId = currentThreadId();\n setThreadModel(model);\n // The pin is what later turns run on: a pick would override it on every send.\n setPickedModel(undefined);\n if (threadId === undefined) {\n pendingPin.current = { model };\n return;\n }\n await client.updateThread(threadId, { model });\n notifyThreads(client, { type: 'changed' });\n },\n [client, currentThreadId],\n );\n const models: ChatModels = {\n get list() {\n wantModels();\n return catalog.models;\n },\n get providers() {\n wantModels();\n return catalog.providers;\n },\n selected:\n catalog.locked?.model ??\n options.model ??\n pickedModel ??\n threadModel ??\n catalog.defaultModel ??\n null,\n pinned: threadModel,\n get defaultModel() {\n wantModels();\n return catalog.defaultModel;\n },\n get locked() {\n wantModels();\n return catalog.locked;\n },\n select: selectModel,\n pinToThread,\n isLoading: modelsWanted && catalog.isLoading,\n error: catalog.error,\n };\n\n // A dropped stream the transport is retrying reads as its own status; every other moment is the\n // SDK's. `reconnecting` is still a busy status to the transcript model (see `ChatStatus`).\n const status: ChatStatus = connection.status === 'reconnecting' ? 'reconnecting' : chat.status;\n const isBusy = status === 'submitted' || status === 'streaming' || status === 'reconnecting';\n const isBusyRef = useRef(isBusy);\n isBusyRef.current = isBusy;\n\n // ---- composer ------------------------------------------------------------------------------\n const files = useAttachments({ ...options.composer, backend: client });\n const [text, setText] = useState('');\n const blockedBy: ComposerBlock | null =\n blocked != null\n ? 'quota'\n : files.isUploading\n ? 'uploading'\n : isBusy && whileRunning === 'block'\n ? 'busy'\n : text.trim().length === 0 && files.refs.length === 0\n ? 'empty'\n : null;\n const composerRef = useRef({ text, files, blockedBy });\n composerRef.current = { text, files, blockedBy };\n const submit = useCallback(\n async (options?: SendWhileRunning): Promise<void> => {\n const current = composerRef.current;\n // A mode named for this call is an answer to \"a turn is running\": it lifts that one block.\n const asked = canQueueRef.current ? options?.mode : undefined;\n if (current.blockedBy !== null && !(current.blockedBy === 'busy' && asked !== undefined)) {\n return;\n }\n if (current.text.trim().length === 0 && current.files.refs.length === 0) return;\n const refs = current.files.refs;\n // The sent message shows its files right away, as the reloaded thread will (`messageFiles`).\n const files = current.files.items.flatMap((item) =>\n item.status === 'ready' && item.attachment !== undefined\n ? [\n {\n type: 'file' as const,\n mediaType: item.attachment.contentType,\n filename: item.attachment.name,\n url: item.attachment.url,\n providerMetadata: { agent: { mediaId: item.attachment.mediaId } },\n },\n ]\n : [],\n );\n const draft = current.text.trim();\n setText('');\n current.files.clear();\n const mode = asked ?? whileRunningRef.current;\n if (mode !== 'block' && (isTurnInFlight() || isBusyRef.current)) {\n // Mid-turn: wait in the thread's queue (or, `interrupt`, cut in) instead of refusing.\n const attachments = current.files.items.flatMap((item) =>\n item.status === 'ready' && item.attachment !== undefined ? [item.attachment] : [],\n );\n await enqueue(draft, { attachments, mode });\n return;\n }\n await sendMessage(\n files.length > 0 ? { text: draft, files } : { text: draft },\n refs.length > 0 ? { body: { attachments: refs } } : undefined,\n );\n },\n [sendMessage, enqueue, isTurnInFlight],\n );\n const composer: ChatComposer = {\n text,\n setText,\n files,\n canSend: blockedBy === null,\n blockedBy,\n submit,\n };\n\n // ---- transcript ----------------------------------------------------------------------------\n const ownCatalog = options.transcript?.toolCatalog;\n const tools = useToolCatalog({\n backend: client,\n ...(options.agent !== undefined ? { agent: options.agent } : {}),\n enabled: ownCatalog === undefined && typeof client.listTools === 'function',\n });\n const canFork = typeof client.forkFromMessage === 'function';\n const transcript: ChatTranscript = useChatTranscript({\n messages: chat.messages,\n status,\n onStop: cancel,\n onApprove: approve,\n onReject: reject,\n onAnswer: answer,\n onSkip: skip,\n regeneratable: true,\n onRegenerate: regenerate,\n ...(canFork\n ? { onFork: (input: MessageActionInput) => fork(input).then(() => undefined) }\n : {}),\n ...(ownCatalog === undefined ? { toolCatalog: tools.catalog } : {}),\n queue: { items: queue.items, paused: queue.paused, remove: removeQueued },\n ...options.transcript,\n });\n\n const background: ChatBackground = {\n runs: backgroundRuns,\n isWorking,\n refresh: refreshBackground,\n };\n\n return {\n ...chat,\n status,\n /** Where the live stream stands — see {@link StreamConnectionState}. */\n connection,\n sendMessage,\n addToolResult,\n /** Sub-agents this conversation started and did not wait for. */\n background,\n proposals,\n runId,\n /** The loaded thread's running turn, or `null` once read with none. */\n activeRunId,\n /** The thread's history is being read. */\n isLoadingHistory,\n /** Reading the thread's history failed. */\n historyError,\n /**\n * How the last run's stream said it failed — the `event: error` frame's `code` and `message` —\n * or `null`. Cleared when the next attempt starts and when the chat moves to another thread.\n * `chat.error` still carries the message; this is where the `code` is, so the app can word each\n * failure itself (`replay_diverged`, `model_no_output`, `run_failed`, `quota_exceeded`, …).\n */\n runError,\n /**\n * The thread this chat is on right now: the `threadId` option, else the one the backend created\n * on the first send. A getter, because the created id is learned mid-stream.\n */\n getThreadId: currentThreadId,\n /** The backend this chat talks to — the same one every other hook under the provider uses. */\n backend: client,\n /** The transcript model, with every action already bound to this chat. */\n transcript,\n /** A headless composer: draft, files, send gate, `submit()`. */\n composer,\n /**\n * Messages sent while a turn was running, waiting their turn (server-side): list, edit, move,\n * remove, clear, and resume a paused queue.\n */\n queue,\n /** The model picker: `list`, `selected`, `select(id)`, `pinToThread(id)`. */\n models,\n /**\n * The persona pinned on this thread (`ThreadSummary.persona`), or `null` when none is — what a\n * persona picker on a reopened thread starts from (`?? agent.defaultPersona`).\n */\n threadPersona,\n /** The caller's budget (`GET <base>/quota`); `quota.blocked` gates sends. */\n quota,\n /** The window blocking sends right now (the `blocked` option, else the quota report's). */\n blocked,\n cancel,\n approve,\n reject,\n answer,\n skip,\n regenerate,\n fork,\n truncateFrom,\n promote,\n };\n}\n\n/** A send refused on the client because a quota window is exhausted. */\nexport class QuotaBlockedError extends Error {\n constructor(readonly block: QuotaBlock) {\n super(block.reason ?? `The ${block.period === 'day' ? 'daily' : 'monthly'} quota is used up`);\n this.name = 'QuotaBlockedError';\n }\n}\n","import type { ActionProposalView } from '@dudousxd/nestjs-agent-core';\nimport type { UIMessage } from 'ai';\nimport { useCallback, useEffect, useRef, useState } from 'react';\nimport type { AgentBackend } from '../backend.js';\nimport { proposalNeedsPolling, reconcileProposalMessages } from './proposals.js';\n\nexport interface ActionProposalsState {\n items: ActionProposalView[];\n error: Error | null;\n /**\n * The server does not serve proposals: its `action-proposals` route answered `404`, `405` or\n * `501`. Nothing is read again for the rest of the session — no polling, no refetch on focus.\n */\n unsupported: boolean;\n refresh(): Promise<void>;\n}\n\n/** Statuses meaning the server has no proposals route, rather than that this read failed. */\nconst UNSUPPORTED_STATUSES = new Set([404, 405, 501]);\n/** What the libraries' own route answers for a thread it does not know (yet): not \"unsupported\". */\nconst UNKNOWN_THREAD = new Set(['Thread not found', 'Unknown thread']);\n/** The longest wait between two reads after failed ones (the wait doubles per failure). */\nconst MAX_BACKOFF_MS = 30_000;\n\n/** Backends whose server answered that it serves no proposals — for the rest of the session. */\nconst unsupportedBackends = new WeakSet<object>();\n\nfunction statusOf(cause: unknown): number | undefined {\n const status = (cause as { status?: unknown } | null)?.status;\n return typeof status === 'number' ? status : undefined;\n}\n\n/** `cause` says the proposals route is not there at all (not a transient failure of one read). */\nexport function isProposalsUnsupported(cause: unknown): boolean {\n const status = statusOf(cause);\n if (status === undefined || !UNSUPPORTED_STATUSES.has(status)) return false;\n return !(status === 404 && cause instanceof Error && UNKNOWN_THREAD.has(cause.message));\n}\n\nexport function useActionProposals(\n backend: AgentBackend,\n threadId: string | undefined,\n setMessages: (update: (current: UIMessage[]) => UIMessage[]) => void,\n refreshKey: string,\n pollMs = 1000,\n): ActionProposalsState {\n const [items, setItems] = useState<ActionProposalView[]>([]);\n const [error, setError] = useState<Error | null>(null);\n const [unsupported, setUnsupported] = useState(() => unsupportedBackends.has(backend));\n // Reads that failed in a row: each one doubles the wait before the next poll.\n const [failures, setFailures] = useState(0);\n const latest = useRef({ threadId, setMessages });\n latest.current = { threadId, setMessages };\n const mounted = useRef(true);\n const requests = useRef(new Map<string, Promise<void>>());\n useEffect(() => {\n mounted.current = true;\n return () => {\n mounted.current = false;\n };\n }, []);\n const refresh = useCallback(async () => {\n if (threadId === undefined || backend.listActionProposals === undefined) return;\n if (unsupportedBackends.has(backend)) return;\n const pending = requests.current.get(threadId);\n if (pending) return pending;\n const request = (async () => {\n try {\n const proposals = await backend.listActionProposals?.({ threadId });\n if (!mounted.current || latest.current.threadId !== threadId || !Array.isArray(proposals))\n return;\n const admitted = proposals.some(\n (proposal) => proposal.outcomeDelivery?.status === 'admitted',\n );\n const facts = admitted\n ? (await backend.getThread(threadId)).messages.filter(\n (message) => message.actionProposalOutcome !== undefined,\n )\n : [];\n if (!mounted.current || latest.current.threadId !== threadId) return;\n setItems(proposals);\n setError(null);\n setFailures(0);\n latest.current.setMessages((current) =>\n reconcileProposalMessages(current, proposals, facts),\n );\n } catch (cause) {\n if (isProposalsUnsupported(cause)) {\n // Not this read failing: the server has no such route. Stop asking, quietly.\n unsupportedBackends.add(backend);\n if (mounted.current) {\n setUnsupported(true);\n setError(null);\n }\n return;\n }\n if (mounted.current && latest.current.threadId === threadId) {\n setError(cause instanceof Error ? cause : new Error(String(cause)));\n setFailures((count) => count + 1);\n }\n }\n })();\n requests.current.set(threadId, request);\n try {\n await request;\n } finally {\n requests.current.delete(threadId);\n }\n }, [backend, threadId]);\n // biome-ignore lint/correctness/useExhaustiveDependencies: A changed thread clears the prior scoped state.\n useEffect(() => {\n setItems([]);\n setError(null);\n setFailures(0);\n }, [threadId]);\n // A backend another chat already found unsupported (or a new backend that may not be).\n useEffect(() => {\n setUnsupported(unsupportedBackends.has(backend));\n }, [backend]);\n // biome-ignore lint/correctness/useExhaustiveDependencies: Stream completion/reconnection triggers a scoped read.\n useEffect(() => {\n void refresh();\n }, [refresh, refreshKey]);\n // One read per wait while a proposal is still moving; every read (its new `items`, or one more\n // failure) schedules the next. Failed reads back off: pollMs, ×2, ×4, … up to 30 s.\n useEffect(() => {\n if (unsupported || !items.some(proposalNeedsPolling) || pollMs <= 0) return;\n const wait = failures === 0 ? pollMs : Math.min(pollMs * 2 ** failures, MAX_BACKOFF_MS);\n const timer = setTimeout(() => {\n void refresh();\n }, wait);\n return () => clearTimeout(timer);\n }, [items, failures, unsupported, pollMs, refresh]);\n useEffect(() => {\n if (unsupported) return;\n const refetch = () => {\n void refresh();\n };\n const visible = () => {\n if (document.visibilityState === 'visible') refetch();\n };\n window.addEventListener('focus', refetch);\n window.addEventListener('online', refetch);\n document.addEventListener('visibilitychange', visible);\n return () => {\n window.removeEventListener('focus', refetch);\n window.removeEventListener('online', refetch);\n document.removeEventListener('visibilitychange', visible);\n };\n }, [refresh, unsupported]);\n return { items, error, unsupported, refresh };\n}\n","import type { ActionProposalView, StoredMessage } from '@dudousxd/nestjs-agent-core';\nimport type { UIMessage } from 'ai';\nimport { storedMessageToUiMessage } from '../stored-message-to-ui-message.js';\n\nexport type ApprovalTarget =\n | { kind: 'legacy'; toolCallId: string }\n | { kind: 'proposal'; proposalId: string; threadId?: string };\n\nexport function proposalNeedsPolling(proposal: ActionProposalView): boolean {\n return (\n proposal.decision === 'pending' ||\n proposal.execution?.status === 'queued' ||\n proposal.execution?.status === 'executing' ||\n proposal.outcomeDelivery?.status === 'pending'\n );\n}\n\n/** Patch proposal metadata and append outcome facts; never replace live text with stored rows. */\nexport function reconcileProposalMessages(\n current: UIMessage[],\n proposals: ActionProposalView[],\n facts: StoredMessage[],\n): UIMessage[] {\n const messages = current.map((message) => {\n const relevant = proposals.filter((proposal) =>\n message.parts.some((part) => {\n if (\n 'data' in part &&\n record(part.data) &&\n record(part.data.target) &&\n part.data.target.kind === 'proposal'\n )\n return part.data.target.proposalId === proposal.id;\n if ('toolCallId' in part && part.toolCallId === proposal.originToolCallId) {\n if ('output' in part && record(part.output) && typeof part.output.proposalId === 'string')\n return part.output.proposalId === proposal.id;\n return record(message.metadata) && message.metadata.runId === proposal.originRunId;\n }\n return false;\n }),\n );\n if (relevant.length === 0) return message;\n const ids = new Set(relevant.map((proposal) => proposal.originToolCallId));\n const parts = message.parts.filter(\n (part) =>\n !(\n part.type === 'data-action-proposal' &&\n 'id' in part &&\n typeof part.id === 'string' &&\n ids.has(part.id)\n ),\n );\n for (const proposal of relevant)\n parts.push({\n type: 'data-action-proposal',\n id: proposal.originToolCallId,\n data: {\n id: proposal.originToolCallId,\n target: { kind: 'proposal', proposalId: proposal.id, threadId: proposal.threadId },\n approver: proposal.approver,\n confirmation: proposal.confirmation,\n expiresAt:\n proposal.expiresAt === null\n ? null\n : Math.abs(proposal.expiresAt) <= 8.64e15\n ? new Date(proposal.expiresAt).toISOString()\n : null,\n status: proposal.decision,\n executionStatus: proposal.execution?.status ?? null,\n remember: proposal.decisionAudit?.remember === true,\n decidedBy: proposal.decisionAudit?.actorRef ?? null,\n decidedVia: proposal.decisionAudit?.via ?? null,\n reason: proposal.decisionAudit?.reason ?? null,\n },\n });\n return { ...message, parts };\n });\n const knownMessages = new Set(messages.map((message) => message.id));\n const knownOutcomes = new Set(\n messages.map((message) => outcomeId(message.metadata)).filter(Boolean),\n );\n for (const fact of facts) {\n const id = fact.actionProposalOutcome?.id;\n if (id === undefined || knownMessages.has(fact.id) || knownOutcomes.has(id)) continue;\n const message = storedMessageToUiMessage(fact);\n messages.push({\n ...message,\n metadata: {\n ...(record(message.metadata) ? message.metadata : {}),\n actionProposalOutcomeId: id,\n },\n });\n knownMessages.add(fact.id);\n knownOutcomes.add(id);\n }\n return messages;\n}\nfunction record(value: unknown): value is Record<string, unknown> {\n return typeof value === 'object' && value !== null && !Array.isArray(value);\n}\nfunction outcomeId(value: unknown): string | undefined {\n return record(value) && typeof value.actionProposalOutcomeId === 'string'\n ? value.actionProposalOutcomeId\n : undefined;\n}\n","import type { AgentRequestError } from './http-error.js';\n\n/**\n * The `code`s this library's own loop closes a failed run's stream with (`event: error`). A client\n * branches on the code and words the failure itself — the frame's `message` is a sentence in\n * English, and for a crash deliberately a generic one.\n *\n * - `quota_exceeded` — the actor's budget is spent; `message` says which.\n * - `output_rejected` — an output processor refused the answer.\n * - `structured_output_invalid` — the answer never satisfied the agent's output schema.\n * - `replay_diverged` — the durable runtime refused to resume the run (its journal and the\n * deployed code disagree). The turn is over; sending again starts a new one.\n * - `model_no_output` — a model call ended without producing anything.\n * - `run_failed` — anything else.\n *\n * A host's own runner may send codes of its own, which is why {@link AgentRunFailure.code} is a\n * plain string.\n */\nexport const AGENT_RUN_ERROR_CODES = [\n 'quota_exceeded',\n 'output_rejected',\n 'structured_output_invalid',\n 'replay_diverged',\n 'model_no_output',\n 'run_failed',\n] as const;\n\nexport type AgentRunErrorCode = (typeof AGENT_RUN_ERROR_CODES)[number];\n\n/** How a run's stream said it failed: the `event: error` frame, read. */\nexport interface AgentRunFailure {\n /** The frame's machine-readable `code`; `undefined` when the server sent none. */\n code: AgentRunErrorCode | (string & {}) | undefined;\n /** The frame's `message` — the server's words, safe to show but not translated. */\n message: string;\n /** The run that failed, when the stream had named it. */\n runId?: string;\n}\n\n/** The `code` a decision is refused with when the run it was for has ended (`409`). */\nexport const RUN_NOT_ACTIVE_CODE = 'run_not_active';\n\n/**\n * Whether `error` is the server refusing an approve / reject / answer / skip because the turn that\n * asked is over (`409 { code: 'run_not_active' }`): nothing is waiting for the decision, and nothing\n * will run. The card it was made on is stale — say so, and let the person send the message again.\n */\nexport function isRunNotActiveError(error: unknown): error is AgentRequestError {\n return (\n error instanceof Error &&\n (error as Partial<AgentRequestError>).status === 409 &&\n (error as Partial<AgentRequestError>).code === RUN_NOT_ACTIVE_CODE\n );\n}\n"],"mappings":";AAeO,SAAS,gBAAgB,MAA8C;AAC5E,MAAI,QAAQ,QAAQ,SAAS,GAAI,QAAO,EAAE,MAAM,QAAW,SAAS,QAAW,MAAM,OAAU;AAC/F,MAAI,OAAgB;AACpB,MAAI;AACF,WAAO,KAAK,MAAM,IAAI;AAAA,EACxB,QAAQ;AACN,WAAO,EAAE,MAAM,MAAM,SAAS,QAAW,MAAM,OAAU;AAAA,EAC3D;AACA,MAAI,SAAS,QAAQ,OAAO,SAAS;AACnC,WAAO,EAAE,MAAM,SAAS,QAAW,MAAM,OAAU;AACrD,QAAMA,UAAS;AACf,QAAM,UACJ,OAAOA,QAAO,YAAY,YAAYA,QAAO,YAAY,KACrDA,QAAO,UACP,MAAM,QAAQA,QAAO,OAAO,KAC1BA,QAAO,QAAQ,SAAS,KACxBA,QAAO,QAAQ,MAAM,CAAC,SAAS,OAAO,SAAS,QAAQ,IACvDA,QAAO,QAAQ,KAAK,IAAI,IACxB;AACR,QAAM,OAAO,OAAOA,QAAO,SAAS,YAAYA,QAAO,SAAS,KAAKA,QAAO,OAAO;AACnF,SAAO,EAAE,MAAM,SAAS,KAAK;AAC/B;AAGA,eAAsB,kBAAkB,UAA0C;AAChF,MAAI;AACJ,MAAI;AACF,WAAO,MAAM,SAAS,KAAK;AAAA,EAC7B,QAAQ;AACN,WAAO;AAAA,EACT;AACA,SAAO,gBAAgB,IAAI;AAC7B;AAkBO,SAAS,gBACd,UACA,OACM;AACN,MAAI,aAAa,OAAW;AAC5B,MAAI;AACF,aAAS,KAAK;AAAA,EAChB,QAAQ;AAAA,EAER;AACF;;;AC3BO,IAAM,iBAAN,MAAM,wBAAuB,MAAmC;AAAA,EAMrE,YACW,QACA,QACA,MACT,YACA,SAAsB,EAAE,MAAM,QAAW,SAAS,QAAW,MAAM,OAAU,GAC7E;AACA,UAAM,OAAO,WAAW,yBAAyB,MAAM,IAAI,IAAI,WAAM,MAAM,IAAI,UAAU,EAAE;AANlF;AACA;AACA;AAKT,SAAK,OAAO;AACZ,SAAK,OAAO,OAAO;AACnB,SAAK,OAAO,OAAO;AAAA,EACrB;AAAA,EAVW;AAAA,EACA;AAAA,EACA;AAAA;AAAA,EAPF;AAAA;AAAA,EAEA;AAAA;AAAA,EAgBT,aAAa,KAAK,UAAoB,QAAgB,MAAuC;AAC3F,WAAO,IAAI;AAAA,MACT,SAAS;AAAA,MACT;AAAA,MACA;AAAA,MACA,SAAS;AAAA,MACT,MAAM,kBAAkB,QAAQ;AAAA,IAClC;AAAA,EACF;AACF;AAuDO,SAAS,mBAAmB,MAAkC;AACnE,QAAM,WAAW,QAAQ,SAAS,QAAQ,cAAc,EAAE;AAC1D,SAAO,YAAY,KAAK,KAAK,IAAI,OAAO;AAC1C;AAEA,IAAM,gBAAgB;AACtB,IAAM,mBAAmB;AAMlB,IAAM,cAAN,MAA0C;AAAA,EAC/C,YAA6B,UAA8B,CAAC,GAAG;AAAlC;AAAA,EAAmC;AAAA,EAAnC;AAAA;AAAA,EAG7B,MAAM,eAAe,SAAyD;AAC5E,UAAM,WAAW,MAAM,KAAK,UAAU,EAAE,GAAG,KAAK,KAAK,CAAC,SAAS;AAAA,MAC7D,QAAQ;AAAA,MACR,SAAS;AAAA,QACP,gBAAgB;AAAA,QAChB,QAAQ;AAAA,QACR,GAAI,MAAM,KAAK,eAAe;AAAA,QAC9B,GAAG,QAAQ;AAAA,MACb;AAAA,MACA,MAAM,KAAK,UAAU,QAAQ,IAAI;AAAA,MACjC,GAAG,KAAK,YAAY;AAAA,MACpB,GAAI,QAAQ,WAAW,SAAY,EAAE,QAAQ,QAAQ,OAAO,IAAI,CAAC;AAAA,IACnE,CAAC;AACD,QAAI,SAAS,WAAW,KAAK;AAE3B,aAAO,EAAE,MAAM,YAAY,GAAG,QAAS,MAAM,SAAS,KAAK,EAAuB;AAAA,IACpF;AACA,QAAI,SAAS,MAAM,SAAS,QAAQ,IAAI,cAAc,GAAG,SAAS,kBAAkB,GAAG;AACrF,YAAM,WAAY,MAAM,SAAS,KAAK;AAGtC,UAAI,SAAS,qBAAqB,UAAa,OAAO,SAAS,aAAa;AAC1E,eAAO,EAAE,MAAM,YAAY,GAAG,UAAU,SAAS,UAAU,kBAAkB,SAAS;AACxF,YAAM,IAAI,MAAM,+BAA+B;AAAA,IACjD;AACA,QAAI,CAAC,SAAS,MAAM,CAAC,SAAS,MAAM;AAClC,YAAM,MAAM,KAAK,QAAQ,UAAU,QAAQ,GAAG,KAAK,UAAU,CAAC,OAAO;AAAA,IACvE;AACA,WAAO,eAAe,QAAQ;AAAA,EAChC;AAAA;AAAA;AAAA;AAAA;AAAA,EAMA,eAAe,SAAuD;AACpE,WAAO,KAAK,QAA0B,QAAQ,SAAS;AAAA,MACrD,MAAM;AAAA,MACN,GAAG,QAAQ;AAAA,IACb,CAAC;AAAA,EACH;AAAA;AAAA,EAGA,SAAS,UAA2C;AAClD,WAAO,KAAK,QAAwB,OAAO,YAAY,mBAAmB,QAAQ,CAAC,QAAQ;AAAA,EAC7F;AAAA;AAAA,EAGA,oBAAoB,WAAmB,QAAsD;AAC3F,WAAO,KAAK,QAAwB,SAAS,UAAU,mBAAmB,SAAS,CAAC,IAAI,MAAM;AAAA,EAChG;AAAA;AAAA,EAGA,oBAAoB,WAA4C;AAC9D,WAAO,KAAK,QAAwB,UAAU,UAAU,mBAAmB,SAAS,CAAC,EAAE;AAAA,EACzF;AAAA;AAAA;AAAA;AAAA;AAAA,EAMA,uBACE,WACqE;AACrE,WAAO,KAAK;AAAA,MACV;AAAA,MACA,UAAU,mBAAmB,SAAS,CAAC;AAAA,IACzC;AAAA,EACF;AAAA;AAAA,EAGA,WAAW,UAA2C;AACpD,WAAO,KAAK,QAAwB,UAAU,YAAY,mBAAmB,QAAQ,CAAC,QAAQ;AAAA,EAChG;AAAA;AAAA,EAGA,YAAY,UAAgE;AAC1E,WAAO,KAAK;AAAA,MACV;AAAA,MACA,YAAY,mBAAmB,QAAQ,CAAC;AAAA,IAC1C;AAAA,EACF;AAAA;AAAA;AAAA;AAAA;AAAA,EAMA,MAAM,iBAAiB,SAAkE;AACvF,UAAM,OAAO,SAAS,mBAAmB,QAAQ,KAAK,CAAC;AACvD,UAAM,QAAQ,QAAQ,UAAU,UAAa,QAAQ,QAAQ,IAAI,UAAU,QAAQ,KAAK,KAAK;AAC7F,UAAM,WAAW,MAAM,KAAK,UAAU,EAAE,GAAG,KAAK,KAAK,CAAC,GAAG,IAAI,GAAG,KAAK,IAAI;AAAA,MACvE,QAAQ;AAAA,MACR,SAAS;AAAA,QACP,QAAQ;AAAA,QACR,GAAI,MAAM,KAAK,eAAe;AAAA,QAC9B,GAAG,QAAQ;AAAA,MACb;AAAA,MACA,GAAG,KAAK,YAAY;AAAA,MACpB,GAAI,QAAQ,WAAW,SAAY,EAAE,QAAQ,QAAQ,OAAO,IAAI,CAAC;AAAA,IACnE,CAAC;AACD,QAAI,SAAS,WAAW,KAAK;AAC3B,aAAO;AAAA,IACT;AACA,QAAI,CAAC,SAAS,MAAM,CAAC,SAAS,MAAM;AAClC,YAAM,MAAM,KAAK,QAAQ,UAAU,OAAO,GAAG,KAAK,UAAU,CAAC,GAAG,IAAI,EAAE;AAAA,IACxE;AACA,WAAO,eAAe,QAAQ;AAAA,EAChC;AAAA;AAAA;AAAA;AAAA;AAAA,EAMA,mBACE,WACA,OAC+C;AAC/C,WAAO,KAAK;AAAA,MACV;AAAA,MACA,aAAa,mBAAmB,SAAS,CAAC;AAAA,MAC1C;AAAA,IACF;AAAA,EACF;AAAA,EAEA,cAAwC;AACtC,WAAO,KAAK,QAAyB,OAAO,UAAU;AAAA,EACxD;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAQA,WAAW,UAAiD;AAC1D,UAAM,QAAQ,aAAa,SAAY,KAAK,aAAa,mBAAmB,QAAQ,CAAC;AACrF,WAAO,KAAK,QAA6B,OAAO,UAAU,KAAK,EAAE;AAAA,EACnE;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAOA,UAAU,OAA6C;AACrD,UAAM,QAAQ,UAAU,SAAY,KAAK,UAAU,mBAAmB,KAAK,CAAC;AAC5E,WAAO,KAAK,QAA4B,OAAO,SAAS,KAAK,EAAE;AAAA,EACjE;AAAA,EAEA,UAAU,IAAmC;AAC3C,WAAO,KAAK,QAAsB,OAAO,YAAY,mBAAmB,EAAE,CAAC,EAAE;AAAA,EAC/E;AAAA,EAEA,aAAa,IAA2B;AACtC,WAAO,KAAK,QAAc,UAAU,YAAY,mBAAmB,EAAE,CAAC,EAAE;AAAA,EAC1E;AAAA,EAEA,gBAAgB,UAAkB,WAA2C;AAC3E,WAAO,KAAK;AAAA,MACV;AAAA,MACA,YAAY,mBAAmB,QAAQ,CAAC,cAAc,mBAAmB,SAAS,CAAC;AAAA,IACrF;AAAA,EACF;AAAA;AAAA,EAGA,aAAa,IAAY,OAAuC;AAC9D,WAAO,KAAK,QAAkB,SAAS,YAAY,mBAAmB,EAAE,CAAC,IAAI,KAAK;AAAA,EACpF;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAOA,MAAM,iBACJ,MACA,UAAmC,CAAC,GACR;AAC5B,UAAM,SAAS,KAAK,QAAQ,aAAa;AACzC,QAAI,WAAW,QAAW;AACxB,aAAO,OAAO,MAAM,SAAS,KAAK,WAAW,CAAC;AAAA,IAChD;AAGA,QACE,QAAQ,eAAe,UACvB,KAAK,QAAQ,UAAU,UACvB,OAAO,mBAAmB,aAC1B;AACA,aAAO,KAAK,mBAAmB,MAAM,OAAO;AAAA,IAC9C;AACA,UAAM,WAAW,IAAI,SAAS;AAC9B,aAAS,OAAO,QAAQ,IAAI;AAC5B,UAAM,WAAW,MAAM,KAAK,UAAU,EAAE,GAAG,KAAK,KAAK,CAAC,gBAAgB;AAAA,MACpE,QAAQ;AAAA,MACR,SAAS;AAAA,QACP,QAAQ;AAAA,QACR,GAAI,MAAM,KAAK,eAAe;AAAA,MAChC;AAAA,MACA,MAAM;AAAA,MACN,GAAG,KAAK,YAAY;AAAA,MACpB,GAAI,QAAQ,WAAW,SAAY,EAAE,QAAQ,QAAQ,OAAO,IAAI,CAAC;AAAA,IACnE,CAAC;AACD,UAAM,aAAa,MAAM,KAAK;AAAA,MAC5B;AAAA,MACA;AAAA,MACA,GAAG,KAAK,UAAU,CAAC;AAAA,IACrB;AACA,YAAQ,aAAa,CAAC;AACtB,WAAO;AAAA,EACT;AAAA,EAEA,MAAc,mBACZ,MACA,EAAE,QAAQ,WAAW,GACO;AAC5B,UAAM,UAAkC;AAAA,MACtC,QAAQ;AAAA,MACR,GAAI,MAAM,KAAK,eAAe;AAAA,IAChC;AACA,UAAM,MAAM,GAAG,KAAK,KAAK,CAAC;AAC1B,WAAO,IAAI,QAA2B,CAAC,SAAS,WAAW;AACzD,YAAM,MAAM,IAAI,eAAe;AAC/B,UAAI,KAAK,QAAQ,GAAG;AACpB,iBAAW,CAAC,MAAM,KAAK,KAAK,OAAO,QAAQ,OAAO,EAAG,KAAI,iBAAiB,MAAM,KAAK;AAErF,UAAI,kBAAkB,KAAK,QAAQ,gBAAgB;AACnD,UAAI,OAAO,aAAa,CAAC,UAAU;AACjC,YAAI,MAAM,oBAAoB,MAAM,QAAQ,EAAG,cAAa,MAAM,SAAS,MAAM,KAAK;AAAA,MACxF;AACA,UAAI,SAAS,MAAM;AACjB,YAAI,IAAI,SAAS,OAAO,IAAI,UAAU,KAAK;AACzC,gBAAM,QAAQ,IAAI;AAAA,YAChB,IAAI;AAAA,YACJ;AAAA,YACA,GAAG,KAAK,UAAU,CAAC;AAAA,YACnB,IAAI;AAAA,YACJ,gBAAgB,IAAI,YAAY;AAAA,UAClC;AACA,0BAAgB,KAAK,QAAQ,aAAa,KAAK;AAC/C,iBAAO,KAAK;AACZ;AAAA,QACF;AACA,qBAAa,CAAC;AACd,gBAAQ,KAAK,MAAM,IAAI,YAAY,CAAsB;AAAA,MAC3D;AACA,UAAI,UAAU,MAAM,OAAO,IAAI,UAAU,8CAA8C,CAAC;AACxF,UAAI,UAAU,MAAM,OAAO,IAAI,aAAa,0BAA0B,YAAY,CAAC;AACnF,UAAI,WAAW,QAAW;AACxB,YAAI,OAAO,SAAS;AAClB,iBAAO,IAAI,aAAa,0BAA0B,YAAY,CAAC;AAC/D;AAAA,QACF;AACA,eAAO,iBAAiB,SAAS,MAAM,IAAI,MAAM,GAAG,EAAE,MAAM,KAAK,CAAC;AAAA,MACpE;AACA,YAAM,WAAW,IAAI,SAAS;AAC9B,eAAS,OAAO,QAAQ,IAAI;AAC5B,UAAI,KAAK,QAAQ;AAAA,IACnB,CAAC;AAAA,EACH;AAAA,EAEA,cAAc,IAA+B;AAC3C,WAAO,KAAK,QAAkB,QAAQ,YAAY,mBAAmB,EAAE,CAAC,UAAU;AAAA,EACpF;AAAA,EAEA,oBAAoB,UAAkB,WAAsC;AAC1E,WAAO,KAAK;AAAA,MACV;AAAA,MACA,YAAY,mBAAmB,QAAQ,CAAC,SAAS,mBAAmB,SAAS,CAAC;AAAA,IAChF;AAAA,EACF;AAAA;AAAA,EAGA,WAAW,OAA2C;AACpD,UAAM,QAAQ,UAAU,SAAY,KAAK,UAAU,mBAAmB,KAAK,CAAC;AAC5E,WAAO,KAAK,QAA0B,OAAO,UAAU,KAAK,EAAE;AAAA,EAChE;AAAA;AAAA,EAGA,aAA2C;AACzC,WAAO,KAAK,QAA6B,OAAO,SAAS;AAAA,EAC3D;AAAA;AAAA,EAGA,YAAwC;AACtC,WAAO,KAAK,QAA2B,OAAO,SAAS;AAAA,EACzD;AAAA;AAAA,EAGA,WAAiC;AAC/B,WAAO,KAAK,QAAqB,OAAO,QAAQ;AAAA,EAClD;AAAA,EAEA,aAAa,OAAsC;AACjD,WAAO,KAAK,QAAsB,QAAQ,SAAS,mBAAmB,KAAK,CAAC,SAAS;AAAA,EACvF;AAAA;AAAA;AAAA;AAAA;AAAA,EAMA,MAAM,oBAAoB,EAAE,SAAS,GAAwD;AAC3F,UAAM,YAAY,oBAAI,IAAgC;AACtD,QAAI;AACJ,eAAS;AACP,YAAM,QAAQ,YAAY,mBAAmB,QAAQ,CAAC,oBACpD,UAAU,SAAY,KAAK,UAAU,mBAAmB,KAAK,UAAU,KAAK,CAAC,CAAC,EAChF;AACA,YAAM,WAAW,MAAM,KAAK,gBAAgB,OAAO,KAAK;AACxD,YAAM,OAAO,MAAM,KAAK;AAAA,QACtB;AAAA,QACA;AAAA,QACA,GAAG,KAAK,UAAU,CAAC,GAAG,KAAK;AAAA,MAC7B;AACA,UAAI,CAAC,MAAM,QAAQ,IAAI,EAAG,OAAM,IAAI,UAAU,8BAA8B;AAC5E,iBAAW,YAAY,KAAM,WAAU,IAAI,SAAS,IAAI,QAAQ;AAChE,YAAM,SAAS,SAAS,QAAQ,IAAI,yBAAyB;AAC7D,UAAI,WAAW,KAAM,QAAO,CAAC,GAAG,UAAU,OAAO,CAAC;AAClD,UAAI;AACJ,UAAI;AACF,eAAO,KAAK,MAAM,mBAAmB,MAAM,CAAC;AAAA,MAC9C,QAAQ;AACN,cAAM,IAAI,UAAU,gCAAgC;AAAA,MACtD;AACA,UACE,OAAO,SAAS,YAChB,SAAS,QACT,EAAE,eAAe,SACjB,OAAO,KAAK,cAAc,YAC1B,CAAC,OAAO,cAAc,KAAK,SAAS,KACpC,EAAE,QAAQ,SACV,OAAO,KAAK,OAAO,YACnB,KAAK,GAAG,WAAW,KACnB,KAAK,GAAG,SAAS,OAChB,UAAU,WACR,KAAK,YAAY,MAAM,aACrB,KAAK,cAAc,MAAM,aAAa,KAAK,MAAM,MAAM;AAE5D,cAAM,IAAI,UAAU,iDAAiD;AACvE,cAAQ,EAAE,WAAW,KAAK,WAAW,IAAI,KAAK,GAAG;AAAA,IACnD;AAAA,EACF;AAAA,EACA,sBAAsB;AAAA,IACpB;AAAA,IACA;AAAA,IACA;AAAA,EACF,GAIwC;AACtC,WAAO,KAAK;AAAA,MACV;AAAA,MACA,YAAY,mBAAmB,QAAQ,CAAC,qBAAqB,mBAAmB,UAAU,CAAC;AAAA,MAC3F,aAAa,SAAY,CAAC,IAAI,EAAE,SAAS;AAAA,IAC3C;AAAA,EACF;AAAA,EACA,qBAAqB;AAAA,IACnB;AAAA,IACA;AAAA,IACA;AAAA,EACF,GAIwC;AACtC,WAAO,KAAK;AAAA,MACV;AAAA,MACA,YAAY,mBAAmB,QAAQ,CAAC,qBAAqB,mBAAmB,UAAU,CAAC;AAAA,MAC3F,WAAW,SAAY,CAAC,IAAI,EAAE,OAAO;AAAA,IACvC;AAAA,EACF;AAAA,EAEA,gBAAgB,OAAgF;AAC9F,WAAO,KAAK,QAAc,QAAQ,sBAAsB,KAAK;AAAA,EAC/D;AAAA,EAEA,eAAe,OAA6E;AAC1F,WAAO,KAAK,QAAc,QAAQ,qBAAqB,KAAK;AAAA,EAC9D;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EASA,eAAe,OAIG;AAChB,WAAO,KAAK,QAAc,QAAQ,qBAAqB,KAAK;AAAA,EAC9D;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAOA,aAAa,OAA4D;AACvE,WAAO,KAAK,QAAc,QAAQ,mBAAmB,KAAK;AAAA,EAC5D;AAAA,EAEQ,YAA0B;AAChC,WAAO,KAAK,QAAQ,SAAS,WAAW;AAAA,EAC1C;AAAA;AAAA,EAGQ,aAA8B;AACpC,WAAO;AAAA,MACL,SAAS,KAAK,QAAQ;AAAA,MACtB,MAAM,KAAK,UAAU;AAAA,MACrB,SAAS,MAAM,KAAK,eAAe;AAAA,MACnC,OAAO,KAAK,UAAU;AAAA,MACtB,GAAG,KAAK,YAAY;AAAA,MACpB,GAAI,KAAK,QAAQ,gBAAgB,SAAY,EAAE,aAAa,KAAK,QAAQ,YAAY,IAAI,CAAC;AAAA,IAC5F;AAAA,EACF;AAAA,EAEQ,UAAkB;AACxB,YAAQ,KAAK,QAAQ,WAAW,IAAI,QAAQ,QAAQ,EAAE;AAAA,EACxD;AAAA,EAEQ,YAAoB;AAC1B,WAAO,mBAAmB,KAAK,QAAQ,IAAI;AAAA,EAC7C;AAAA;AAAA,EAGQ,OAAe;AACrB,WAAO,GAAG,KAAK,QAAQ,CAAC,GAAG,KAAK,UAAU,CAAC;AAAA,EAC7C;AAAA,EAEA,MAAc,iBAAkD;AAC9D,UAAM,UAAW,MAAM,KAAK,QAAQ,aAAa,KAAM,CAAC;AACxD,WAAO,EAAE,GAAG,KAAK,QAAQ,SAAS,GAAG,QAAQ;AAAA,EAC/C;AAAA,EAEQ,cAAoD;AAC1D,WAAO,KAAK,QAAQ,gBAAgB,SAAY,EAAE,aAAa,KAAK,QAAQ,YAAY,IAAI,CAAC;AAAA,EAC/F;AAAA,EAEA,MAAc,QAAW,QAAgB,OAAe,MAA4B;AAClF,UAAM,WAAW,MAAM,KAAK,gBAAgB,QAAQ,OAAO,IAAI;AAC/D,WAAO,KAAK,eAAkB,UAAU,QAAQ,GAAG,KAAK,UAAU,CAAC,GAAG,KAAK,EAAE;AAAA,EAC/E;AAAA,EAEA,MAAc,gBAAgB,QAAgB,OAAe,MAAmC;AAC9F,UAAM,OAAO,GAAG,KAAK,UAAU,CAAC,GAAG,KAAK;AACxC,UAAM,WAAW,MAAM,KAAK,UAAU,EAAE,GAAG,KAAK,QAAQ,CAAC,GAAG,IAAI,IAAI;AAAA,MAClE;AAAA,MACA,SAAS;AAAA,QACP,QAAQ;AAAA,QACR,GAAI,SAAS,SAAY,EAAE,gBAAgB,mBAAmB,IAAI,CAAC;AAAA,QACnE,GAAI,MAAM,KAAK,eAAe;AAAA,MAChC;AAAA,MACA,GAAI,SAAS,SAAY,EAAE,MAAM,KAAK,UAAU,IAAI,EAAE,IAAI,CAAC;AAAA,MAC3D,GAAG,KAAK,YAAY;AAAA,IACtB,CAAC;AACD,WAAO;AAAA,EACT;AAAA;AAAA,EAGA,MAAc,QAAQ,UAAoB,QAAgB,MAAuC;AAC/F,UAAM,QAAQ,MAAM,eAAe,KAAK,UAAU,QAAQ,IAAI;AAC9D,oBAAgB,KAAK,QAAQ,aAAa,KAAK;AAC/C,WAAO;AAAA,EACT;AAAA,EAEA,MAAc,eAAkB,UAAoB,QAAgB,MAA0B;AAC5F,QAAI,CAAC,SAAS,IAAI;AAChB,YAAM,MAAM,KAAK,QAAQ,UAAU,QAAQ,IAAI;AAAA,IACjD;AACA,QAAI,SAAS,WAAW,IAAK,QAAO;AACpC,UAAM,OAAO,MAAM,SAAS,KAAK;AACjC,QAAI,CAAC,KAAM,QAAO;AAClB,WAAO,KAAK,MAAM,IAAI;AAAA,EACxB;AACF;AAEA,SAAS,cAA0C;AACjD,SAAO,IAAI,eAA2B;AAAA,IACpC,MAAM,YAAY;AAChB,iBAAW,MAAM;AAAA,IACnB;AAAA,EACF,CAAC;AACH;AAEA,SAAS,eAAe,UAAwC;AAC9D,QAAM,OAAO,SAAS;AACtB,QAAM,QAAQ,SAAS,SAAS,IAAI,aAAa,KAAK;AACtD,QAAM,WAAW,SAAS,SAAS,IAAI,gBAAgB,KAAK;AAC5D,SAAO;AAAA,IACL;AAAA,IACA,GAAI,QAAQ,EAAE,MAAM,IAAI,CAAC;AAAA,IACzB,GAAI,WAAW,EAAE,SAAS,IAAI,CAAC;AAAA,EACjC;AACF;;;ACtoBA,SAAS,WAAW,QAAQ,gBAAgB;AAOrC,IAAM,yBAAyB;AAG/B,SAAS,0BAA0B,aAExC;AACA,SAAO,EAAE,CAAC,sBAAsB,GAAG,EAAE,YAAY,EAAE;AACrD;AAGO,SAAS,gBAAgB,MAAqD;AACnF,QAAM,WAAW,KAAK;AACtB,MAAI,OAAO,aAAa,YAAY,aAAa,KAAM,QAAO;AAC9D,QAAM,SAAU,SAAqC,sBAAsB;AAC3E,MAAI,OAAO,WAAW,YAAY,WAAW,KAAM,QAAO;AAC1D,QAAM,QAAS,OAAmC;AAClD,SAAO,OAAO,UAAU,YAAY,OAAO,SAAS,KAAK,KAAK,SAAS,IAAI,QAAQ;AACrF;AAkBO,SAAS,WAAW,SAAkB,UAA6B,CAAC,GAAW;AACpF,QAAM,EAAE,aAAa,IAAK,IAAI;AAC9B,QAAM,SAAS,OAAO,QAAQ,OAAO,KAAK,GAAG;AAC7C,SAAO,UAAU,QAAQ,OAAO,KAAK;AACrC,QAAM,YAAY,OAAsB,IAAI;AAC5C,QAAM,CAAC,SAAS,UAAU,IAAI,SAAS,CAAC;AAExC,YAAU,MAAM;AACd,QAAI,CAAC,SAAS;AACZ,UAAI,UAAU,YAAY,MAAM;AAC9B,mBAAW,OAAO,QAAQ,IAAI,UAAU,OAAO;AAC/C,kBAAU,UAAU;AAAA,MACtB;AACA;AAAA,IACF;AACA,cAAU,UAAU,OAAO,QAAQ;AACnC,eAAW,CAAC;AACZ,UAAM,QAAQ,YAAY,MAAM;AAC9B,UAAI,UAAU,YAAY,KAAM,YAAW,OAAO,QAAQ,IAAI,UAAU,OAAO;AAAA,IACjF,GAAG,UAAU;AACb,WAAO,MAAM,cAAc,KAAK;AAAA,EAClC,GAAG,CAAC,SAAS,UAAU,CAAC;AAExB,SAAO;AACT;AAMO,SAAS,cAAc,IAAoB;AAChD,MAAI,CAAC,OAAO,SAAS,EAAE,KAAK,KAAK,IAAM,QAAO;AAC9C,QAAM,eAAe,KAAK,MAAM,KAAK,GAAI;AACzC,QAAM,QAAQ,KAAK,MAAM,eAAe,IAAI;AAC5C,QAAM,UAAU,KAAK,MAAO,eAAe,OAAQ,EAAE;AACrD,QAAM,UAAU,eAAe;AAC/B,MAAI,QAAQ,EAAG,QAAO,UAAU,IAAI,GAAG,KAAK,KAAK,OAAO,MAAM,GAAG,KAAK;AACtE,MAAI,UAAU,EAAG,QAAO,UAAU,IAAI,GAAG,OAAO,KAAK,OAAO,MAAM,GAAG,OAAO;AAC5E,SAAO,GAAG,OAAO;AACnB;;;AC8BA,IAAM,oBAAgD;AAAA,EACpD,aAAa;AAAA,EACb,aAAa;AAAA,EACb,YAAY;AACd;AAQA,IAAM,gBAAgB;AAgCf,IAAM,qBAAN,MAA6D;AAAA,EAelE,YAA6B,UAAqC,CAAC,GAAG;AAAzC;AAC3B,SAAK,UACH,QAAQ,WACR,IAAI,YAAY;AAAA,MACd,GAAI,QAAQ,YAAY,SAAY,EAAE,SAAS,QAAQ,QAAQ,IAAI,CAAC;AAAA,MACpE,GAAI,QAAQ,SAAS,SAAY,EAAE,MAAM,QAAQ,KAAK,IAAI,CAAC;AAAA,MAC3D,GAAI,QAAQ,YAAY,SAAY,EAAE,SAAS,QAAQ,QAAQ,IAAI,CAAC;AAAA,MACpE,GAAI,QAAQ,eAAe,SAAY,EAAE,YAAY,QAAQ,WAAW,IAAI,CAAC;AAAA,MAC7E,GAAI,QAAQ,gBAAgB,SAAY,EAAE,aAAa,QAAQ,YAAY,IAAI,CAAC;AAAA,MAChF,GAAI,QAAQ,UAAU,SAAY,EAAE,OAAO,QAAQ,MAAM,IAAI,CAAC;AAAA,IAChE,CAAC;AAAA,EACL;AAAA,EAX6B;AAAA,EAdrB;AAAA,EACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EASA,cAAc;AAAA,EAEL;AAAA;AAAA,EAgBjB,IAAI,QAA4B;AAC9B,WAAO,KAAK;AAAA,EACd;AAAA;AAAA,EAGA,IAAI,WAA+B;AACjC,WAAO,KAAK;AAAA,EACd;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAQA,IAAI,gBAAyB;AAC3B,WAAO,KAAK;AAAA,EACd;AAAA,EAEA,MAAM,aACJ,SACyC;AACzC,SAAK,QAAQ,iBAAiB;AAC9B,SAAK,cAAc;AACnB,QAAI;AACF,YAAM,cAAc,QAAQ,SAAS,GAAG,EAAE;AAC1C,YAAM,UAAU,cAAc,YAAY,WAAW,IAAI;AACzD,YAAM,OAAgC;AAAA,QACpC,GAAI,KAAK,QAAQ,UAAU,SAAY,EAAE,OAAO,KAAK,QAAQ,MAAM,IAAI,CAAC;AAAA,QACxE,GAAI,KAAK,QAAQ,YAAY,SAAY,EAAE,SAAS,KAAK,QAAQ,QAAQ,IAAI,CAAC;AAAA,QAC9E,GAAI,KAAK,QAAQ,UAAU,KAAK,CAAC;AAAA,QACjC,GAAK,QAAQ,QAAgD,CAAC;AAAA,QAC9D;AAAA,MACF;AACA,YAAM,UAAU,aAAa,QAAQ,OAAO;AAC5C,YAAM,WAAW,MAAM,KAAK,QAAQ,eAAe;AAAA,QACjD;AAAA,QACA,GAAI,YAAY,SAAY,EAAE,QAAQ,IAAI,CAAC;AAAA,QAC3C,GAAI,QAAQ,cAAc,EAAE,QAAQ,QAAQ,YAAY,IAAI,CAAC;AAAA,MAC/D,CAAC;AACD,UAAI,SAAS,WAAW,QAAW;AAGjC,aAAK,cAAc;AACnB,eAAO,kBAAkB,SAAS,MAAM;AAAA,MAC1C;AACA,WAAK,kBAAkB,QAAQ;AAC/B,UAAI,SAAS,qBAAqB,QAAW;AAC3C,aAAK,cAAc;AACnB,eAAO,4BAA4B,SAAS,gBAAgB;AAAA,MAC9D;AACA,aAAO,KAAK,cAAc,UAAU;AAAA,QAClC,GAAI,YAAY,SAAY,EAAE,QAAQ,IAAI,CAAC;AAAA,QAC3C,GAAI,QAAQ,cAAc,EAAE,QAAQ,QAAQ,YAAY,IAAI,CAAC;AAAA,MAC/D,CAAC;AAAA,IACH,SAAS,OAAO;AACd,WAAK,cAAc;AACnB,YAAM;AAAA,IACR;AAAA,EACF;AAAA,EAEA,MAAM,kBACJ,SACgD;AAMhD,QAAI,KAAK,YAAa,QAAO;AAC7B,SAAK,QAAQ,iBAAiB;AAC9B,UAAM,QAAQ,KAAK,QAAQ,iBAAiB;AAG5C,QAAI,UAAU,OAAW,QAAO;AAChC,SAAK,cAAc;AACnB,QAAI;AACF,YAAM,UAAU,aAAa,QAAQ,OAAO;AAC5C,YAAM,WAAW,MAAM,KAAK,QAAQ,iBAAiB;AAAA,QACnD;AAAA,QACA,GAAI,YAAY,SAAY,EAAE,QAAQ,IAAI,CAAC;AAAA,MAC7C,CAAC;AACD,UAAI,aAAa,MAAM;AACrB,aAAK,cAAc;AACnB,aAAK,QAAQ,eAAe,KAAK;AACjC,eAAO;AAAA,MACT;AACA,WAAK,kBAAkB,QAAQ;AAC/B,WAAK,QAAQ,mBAAmB,SAAS,SAAS,KAAK;AACvD,aAAO,KAAK,cAAc,UAAU;AAAA,QAClC;AAAA,QACA,GAAI,YAAY,SAAY,EAAE,QAAQ,IAAI,CAAC;AAAA,MAC7C,CAAC;AAAA,IACH,SAAS,OAAO;AACd,WAAK,cAAc;AACnB,YAAM;AAAA,IACR;AAAA,EACF;AAAA,EAEQ,kBAAkB,UAAoC;AAC5D,QAAI,SAAS,MAAO,MAAK,eAAe,SAAS;AACjD,QAAI,SAAS,SAAU,MAAK,kBAAkB,SAAS;AAAA,EACzD;AAAA,EAEQ,kBAAqD;AAC3D,UAAM,aAAa,KAAK,QAAQ;AAChC,QAAI,eAAe,MAAO,QAAO;AACjC,WAAO,EAAE,GAAG,mBAAmB,GAAG,WAAW;AAAA,EAC/C;AAAA,EAEQ,WAAW,MAA6B;AAC9C,SAAK,eAAe,KAAK;AACzB,SAAK,kBAAkB,KAAK;AAC5B,SAAK,QAAQ,SAAS,IAAI;AAAA,EAC5B;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAeQ,cACN,QACA,SACgC;AAChC,QAAI,SAAS,OAAO,KAAK,UAAU;AACnC,QAAI,UAAU,IAAI,YAAY;AAC9B,QAAI,SAAS;AAGb,QAAI,cAAc,OAAO,SAAS,QAAQ;AAC1C,QAAI;AACJ,QAAI,YAAY;AAChB,UAAM,UAAU,KAAK;AACrB,UAAM,SAAS,KAAK,gBAAgB;AACpC,UAAM,SAAS,CAAC,UAAiC,KAAK,QAAQ,qBAAqB,KAAK;AACxF,UAAM,iBAAiB,CAAC,YAA2D;AACjF,UAAI;AACF,aAAK,QAAQ,aAAa;AAAA,UACxB,GAAG;AAAA,UACH,GAAI,gBAAgB,SAAY,EAAE,OAAO,YAAY,IAAI,CAAC;AAAA,QAC5D,CAAC;AAAA,MACH,QAAQ;AAAA,MAER;AAAA,IACF;AACA,UAAM,UAAU,MAAM,aAAa,QAAQ,QAAQ,YAAY;AAC/D,UAAM,YAAY,MAChB,WAAW,QAAQ,YAAY,UAAa,gBAAgB,UAAa,CAAC,QAAQ;AAMpF,UAAM,SAAS,YAAgE;AAC7E,YAAM,QAAQ;AACd,YAAM,QAAQ,WAAW;AACzB,YAAM,EAAE,aAAa,aAAa,WAAW,IAAI;AACjD,eAAS,UAAU,GAAG,WAAW,aAAa,WAAW,GAAG;AAC1D,eAAO,EAAE,QAAQ,gBAAgB,OAAO,SAAS,MAAM,CAAC;AACxD,cAAM,MAAM,KAAK,IAAI,YAAY,cAAc,MAAM,UAAU,EAAE,GAAG,QAAQ,MAAM;AAClF,YAAI,QAAQ,EAAG,QAAO;AACtB,YAAI;AACF,gBAAM,OAAO,MAAM,QAAQ,iBAAiB;AAAA,YAC1C;AAAA,YACA;AAAA,YACA,GAAI,QAAQ,YAAY,SAAY,EAAE,SAAS,QAAQ,QAAQ,IAAI,CAAC;AAAA,YACpE,GAAI,QAAQ,WAAW,SAAY,EAAE,QAAQ,QAAQ,OAAO,IAAI,CAAC;AAAA,UACnE,CAAC;AACD,cAAI,SAAS,MAAM;AACjB,mBAAO,EAAE,QAAQ,QAAQ,MAAM,CAAC;AAChC,mBAAO;AAAA,UACT;AACA,mBAAS,KAAK,KAAK,UAAU;AAC7B,oBAAU,IAAI,YAAY;AAC1B,mBAAS;AACT,iBAAO,EAAE,QAAQ,OAAO,CAAC;AACzB,iBAAO;AAAA,QACT,QAAQ;AACN,cAAI,QAAQ,EAAG,QAAO;AAAA,QACxB;AAAA,MACF;AACA,aAAO,EAAE,QAAQ,UAAU,MAAM,CAAC;AAClC,aAAO;AAAA,IACT;AACA,QAAI,UAAU;AACd,QAAI,WAAW;AACf,QAAI,YAAY;AAChB,QAAI,SAAwB;AAC5B,QAAI,cAA6B;AAGjC,QAAI,qBAAqB;AAGzB,QAAI,UAAU;AACd,QAAI,eAAe;AAKnB,UAAM,YAAY,oBAAI,IAAY;AAIlC,UAAM,eAAe,oBAAI,IAA0B;AACnD,UAAMC,UAAS,CAAC,SAA0B;AACxC,oBAAc,KAAK;AACnB,WAAK,WAAW,IAAI;AAAA,IACtB;AAGA,UAAM,aAAa,MAAM;AACvB,WAAK,cAAc;AAAA,IACrB;AAEA,WAAO,IAAI,eAA+B;AAAA,MACxC,MAAM,KAAK,YAAY;AACrB,iBAAS,gBAAgB;AACvB,cAAI,QAAS;AACb,oBAAU;AAIV,qBAAW,QAAQ;AAAA,YACjB,MAAM;AAAA,YACN,iBAAiB;AAAA,cACf,GAAI,gBAAgB,SAAY,EAAE,OAAO,YAAY,IAAI,CAAC;AAAA,cAC1D,YAAW,oBAAI,KAAK,GAAE,YAAY;AAAA,YACpC;AAAA,UACF,CAAC;AAAA,QACH;AACA,iBAAS,WAAW;AAClB,wBAAc;AACd,cAAI,SAAU,WAAU;AACxB,qBAAW;AACX,uBAAa;AACb,mBAAS;AACT,wBAAc;AACd,oBAAU;AACV,yBAAe;AACf,qBAAW,QAAQ,EAAE,MAAM,aAAa,CAAC;AAAA,QAC3C;AACA,iBAAS,aAAa;AACpB,cAAI,CAAC,SAAU,UAAS;AAAA,QAC1B;AAMA,iBAAS,UAAU,aAAsB;AACvC,cAAI,WAAW,MAAM;AACnB,uBAAW,QAAQ,EAAE,MAAM,YAAY,IAAI,OAAO,CAAC;AACnD,qBAAS;AAAA,UACX;AACA,cAAI,gBAAgB,MAAM;AACxB,uBAAW,QAAQ;AAAA,cACjB,MAAM;AAAA,cACN,IAAI;AAAA,cACJ,kBAAkB;AAAA,gBAChB,eAAe,KAAK,IAAI,GAAG,KAAK,IAAI,IAAI,kBAAkB;AAAA,cAC5D;AAAA,YACF,CAAC;AACD,0BAAc;AAAA,UAChB;AAAA,QACF;AACA,iBAAS,UAAU,aAAsB;AACvC,cAAI,CAAC,SAAU;AACf,oBAAU,WAAW;AACrB,qBAAW,QAAQ,EAAE,MAAM,cAAc,CAAC;AAC1C,qBAAW;AAAA,QACb;AAEA,iBAAS,YACP,IACAC,WACA,UAC0B;AAC1B,gBAAM,SAAuB,EAAE,GAAG,aAAa,IAAI,EAAE,EAAE;AACvD,cAAIA,cAAa,OAAW,QAAO,WAAWA;AAE9C,cAAI,aAAa,UAAa,OAAO,aAAa,OAAW,QAAO,WAAW;AAC/E,cAAI,OAAO,KAAK,MAAM,EAAE,WAAW,EAAG,QAAO;AAC7C,uBAAa,IAAI,IAAI,MAAM;AAC3B,iBAAO;AAAA,QACT;AAEA,iBAAS,cAAc,OAAyB,WAAoB;AAClE,wBAAc;AACd,gBAAM,EAAE,MAAM,GAAG,KAAK,IAAI;AAC1B,qBAAW,QAAQ;AAAA,YACjB,MAAM,QAAQ,IAAI;AAAA,YAClB,GAAI,OAAO,KAAK,OAAO,WAAW,EAAE,IAAI,KAAK,GAAG,IAAI,CAAC;AAAA,YACrD;AAAA,YACA,GAAI,YAAY,EAAE,WAAW,KAAK,IAAI,CAAC;AAAA,UACzC,CAAC;AAAA,QACH;AACA,iBAAS,KAAK,OAAyB;AACrC,kBAAQ,MAAM,MAAM;AAAA,YAClB,KAAK;AACH,uBAAS;AACT;AAAA,YACF,KAAK;AACH,wBAAU,MAAM,WAAW;AAM3B,kBAAI,MAAM,YAAY,QAAW;AAC/B,2BAAW,QAAQ;AAAA,kBACjB,MAAM;AAAA,kBACN,iBAAiB,EAAE,SAAS,MAAM,QAAQ;AAAA,gBAC5C,CAAC;AAAA,cACH;AACA;AAAA,YACF,KAAK;AACH,yBAAW;AACX,kBAAI,WAAW,MAAM;AACnB,yBAAS,YAAY,IAAI,OAAO,SAAS,KAAK,OAAO,SAAS,IAAI,OAAO;AACzE,2BAAW;AACX,2BAAW,QAAQ,EAAE,MAAM,cAAc,IAAI,OAAO,CAAC;AAAA,cACvD;AACA,yBAAW,QAAQ,EAAE,MAAM,cAAc,IAAI,QAAQ,OAAO,MAAM,KAAK,CAAC;AACxE;AAAA,YACF,KAAK;AACH,yBAAW;AACX,kBAAI,gBAAgB,MAAM;AACxB,8BACE,iBAAiB,IAAI,OAAO,SAAS,KAAK,OAAO,SAAS,IAAI,YAAY;AAC5E,gCAAgB;AAChB,qCAAqB,KAAK,IAAI;AAC9B,2BAAW,QAAQ,EAAE,MAAM,mBAAmB,IAAI,YAAY,CAAC;AAAA,cACjE;AACA,yBAAW,QAAQ,EAAE,MAAM,mBAAmB,IAAI,aAAa,OAAO,MAAM,KAAK,CAAC;AAClF;AAAA,YACF,KAAK,oBAAoB;AACvB,yBAAW;AACX,wBAAU,IAAI,MAAM,EAAE;AAKtB,oBAAM,WAAW,YAAY,MAAM,IAAI,MAAM,UAAU,MAAM,QAAQ;AACrE,yBAAW,QAAQ;AAAA,gBACjB,MAAM;AAAA,gBACN,YAAY,MAAM;AAAA,gBAClB,UAAU,MAAM;AAAA,gBAChB,GAAI,aAAa,SAAY,EAAE,cAAc,SAAS,IAAI,CAAC;AAAA,cAC7D,CAAC;AACD;AAAA,YACF;AAAA,YACA,KAAK;AACH,yBAAW;AACX,yBAAW,QAAQ;AAAA,gBACjB,MAAM;AAAA,gBACN,YAAY,MAAM;AAAA,gBAClB,gBAAgB,MAAM;AAAA,cACxB,CAAC;AACD;AAAA,YACF,KAAK,wBAAwB;AAC3B,yBAAW;AACX,wBAAU,IAAI,MAAM,EAAE;AACtB,oBAAM,WAAW,YAAY,MAAM,IAAI,MAAM,UAAU,MAAM,QAAQ;AACrE,yBAAW,QAAQ;AAAA,gBACjB,MAAM;AAAA,gBACN,YAAY,MAAM;AAAA,gBAClB,UAAU,MAAM;AAAA,gBAChB,OAAO,MAAM;AAAA,gBACb,GAAI,aAAa,SAAY,EAAE,cAAc,SAAS,IAAI,CAAC;AAAA,cAC7D,CAAC;AACD;AAAA,YACF;AAAA,YACA,KAAK;AACH,yBAAW;AAMX,kBAAI,CAAC,UAAU,IAAI,MAAM,EAAE,GAAG;AAC5B,0BAAU,IAAI,MAAM,EAAE;AACtB,2BAAW,QAAQ;AAAA,kBACjB,MAAM;AAAA,kBACN,YAAY,MAAM;AAAA,kBAClB,UAAU;AAAA,kBACV,OAAO;AAAA,oBACL,GAAI,MAAM,QAAQ,aAAa,SAC3B,EAAE,UAAU,MAAM,QAAQ,SAAS,IACnC,CAAC;AAAA,oBACL,WAAW,MAAM,QAAQ;AAAA,kBAC3B;AAAA,gBACF,CAAC;AAAA,cACH;AACA;AAAA,YACF,KAAK;AACH,yBAAW;AACX,yBAAW,QAAQ;AAAA,gBACjB,MAAM;AAAA,gBACN,YAAY,MAAM;AAAA,gBAClB,QAAQ,MAAM;AAAA,cAChB,CAAC;AACD;AAAA,YACF,KAAK;AACH,yBAAW;AACX,yBAAW,QAAQ;AAAA,gBACjB,MAAM;AAAA,gBACN,YAAY,MAAM;AAAA,gBAClB,WAAW,MAAM;AAAA,cACnB,CAAC;AACD;AAAA,YACF,KAAK;AACH,yBAAW;AAKX,yBAAW,QAAQ,EAAE,MAAM,sBAAsB,YAAY,MAAM,GAAG,CAAC;AACvE;AAAA,YACF,KAAK;AACH,yBAAW;AAIX,4BAAc,OAAO,KAAK;AAK1B,kBAAI,UAAU,IAAI,MAAM,EAAE,GAAG;AAC3B,2BAAW,QAAQ;AAAA,kBACjB,MAAM;AAAA,kBACN,YAAY,MAAM;AAAA,kBAClB,YAAY,MAAM;AAAA,gBACpB,CAAC;AAAA,cACH;AACA;AAAA,YACF,KAAK;AACH,yBAAW;AAGX,4BAAc,OAAO,KAAK;AAC1B;AAAA,YACF,KAAK;AACH,yBAAW;AAGX,wBAAU;AACV,yBAAW,QAAQ;AAAA,gBACjB,MAAM;AAAA,gBACN,IAAI,MAAM;AAAA,gBACV,MAAM;AAAA,kBACJ,IAAI,MAAM;AAAA,kBACV,WAAW,MAAM;AAAA,kBACjB,OAAO,MAAM;AAAA,kBACb,GAAI,MAAM,YAAY,SAAY,EAAE,SAAS,MAAM,QAAQ,IAAI,CAAC;AAAA,kBAChE,GAAI,MAAM,eAAe,SAAY,EAAE,YAAY,MAAM,WAAW,IAAI,CAAC;AAAA;AAAA;AAAA,kBAGzE,GAAI,MAAM,YAAY,OAAO,EAAE,SAAS,KAAK,IAAI,CAAC;AAAA,gBACpD;AAAA,cACF,CAAC;AACD;AAAA,YACF,KAAK;AACH,4BAAc;AACd,yBAAW,QAAQ,EAAE,MAAM,oBAAoB,iBAAiB,MAAM,SAAS,CAAC;AAChF;AAAA,YACF,KAAK;AAAA,YACL,KAAK;AAAA;AAAA;AAAA,YAGL,KAAK;AAGH,4BAAc,OAAO,IAAI;AACzB;AAAA,YACF;AAME;AAAA,gBACE;AAAA,gBACC,MAA2B,SAAS;AAAA,cACvC;AACA;AAAA,UACJ;AAAA,QACF;AACA,iBAAS,SAAS;AAChB,wBAAc;AACd,oBAAU;AACV,qBAAW,QAAQ,EAAE,MAAM,SAAS,CAAC;AACrC,qBAAW,MAAM;AACjB,qBAAW;AAAA,QACb;AACA,iBAAS,KAAK,WAAmB,QAAQ,MAAM;AAC7C,cAAI,MAAO,eAAc;AACzB,qBAAW,QAAQ,EAAE,MAAM,SAAS,UAAU,CAAC;AAC/C,qBAAW,MAAM;AACjB,qBAAW;AAAA,QACb;AAEA,uBAAe,QAAQ,OAAkC;AACvD,cAAI,CAAC,UAAU,GAAG;AAChB,gBAAI,UAAU,QAAW;AACvB,qBAAO;AAAA,YACT,OAAO;AACL,mBAAK,iBAAiB,QAAQ,MAAM,UAAU,sBAAsB,KAAK;AAAA,YAC3E;AACA,mBAAO;AAAA,UACT;AACA,gBAAM,UAAU,MAAM,OAAO;AAC7B,cAAI,YAAY,UAAW,QAAO;AAClC,cAAI,YAAY,UAAU;AACxB,iBAAK,yCAAyC;AAAA,UAChD,OAAO;AAGL,mBAAO;AAAA,UACT;AACA,iBAAO;AAAA,QACT;AACA,YAAI;AACF,iBAAO,MAAM;AACX,gBAAI;AACJ,gBAAI;AACF,uBAAS,MAAM,OAAO,KAAK;AAAA,YAC7B,SAAS,OAAO;AACd,kBAAI,MAAM,QAAQ,KAAK,EAAG;AAC1B;AAAA,YACF;AACA,gBAAI,OAAO,MAAM;AACf,kBAAI,MAAM,QAAQ,MAAS,EAAG;AAC9B;AAAA,YACF;AACA,sBAAU,QAAQ,OAAO,OAAO,OAAO,EAAE,QAAQ,KAAK,CAAC;AACvD,gBAAI,YAAY,OAAO,QAAQ,MAAM;AACrC,mBAAO,cAAc,IAAI;AACvB,oBAAM,WAAW,OAAO,MAAM,GAAG,SAAS;AAC1C,uBAAS,OAAO,MAAM,YAAY,CAAC;AACnC,0BAAY,OAAO,QAAQ,MAAM;AACjC,oBAAM,QAAQ,cAAc,QAAQ;AACpC,kBAAI,MAAM,OAAO,QAAW;AAE1B,oBAAI,YAAY,UAAa,MAAM,MAAM,QAAS;AAClD,0BAAU,MAAM;AAAA,cAClB;AACA,kBAAI,MAAM,UAAU,QAAQ;AAC1B,uBAAO;AACP;AAAA,cACF;AACA,kBAAI,MAAM,UAAU,SAAS;AAC3B,sBAAM,UAAU,gBAAgB,MAAM,IAAI;AAC1C,+BAAe,OAAO;AACtB,qBAAK,QAAQ,OAAO;AACpB;AAAA,cACF;AACA,kBAAI,MAAM,UAAU,QAAQ;AAC1B,sBAAM,OAAO,UAAU,MAAM,IAAI;AACjC,oBAAI,KAAM,CAAAD,QAAO,IAAI;AAAA,cACvB,WAAW,MAAM,MAAM;AACrB,sBAAM,QAAQ,WAAW,MAAM,IAAI;AACnC,oBAAI,MAAO,MAAK,KAAK;AAAA,cACvB;AAAA,YACF;AAAA,UACF;AAAA,QACF,SAAS,OAAO;AACd,eAAK,iBAAiB,QAAQ,MAAM,UAAU,sBAAsB,KAAK;AAAA,QAC3E;AAAA,MACF;AAAA,MACA,SAAS;AACP,oBAAY;AAGZ,eAAO,OAAO,EAAE,MAAM,MAAM,MAAS;AACrC,mBAAW;AAAA,MACb;AAAA,IACF,CAAC;AAAA,EACH;AACF;AAGA,SAAS,kBAAkB,QAA0D;AACnF,SAAO,IAAI,eAA+B;AAAA,IACxC,MAAM,YAAY;AAChB,iBAAW,QAAQ;AAAA,QACjB,MAAM;AAAA,QACN,MAAM,EAAE,OAAO,OAAO,OAAO,YAAY,OAAO;AAAA,QAChD,WAAW;AAAA,MACb,CAAC;AACD,iBAAW,MAAM;AAAA,IACnB;AAAA,EACF,CAAC;AACH;AAUA,SAAS,cAAc,KAAuB;AAC5C,MAAI;AACJ,MAAI;AACJ,QAAM,YAAsB,CAAC;AAC7B,aAAW,QAAQ,IAAI,MAAM,IAAI,GAAG;AAClC,QAAI,KAAK,WAAW,QAAQ,GAAG;AAC7B,cAAQ,KAAK,MAAM,SAAS,MAAM,EAAE,KAAK;AAAA,IAC3C,WAAW,KAAK,WAAW,KAAK,GAAG;AACjC,YAAM,SAAS,OAAO,KAAK,MAAM,MAAM,MAAM,EAAE,KAAK,CAAC;AACrD,UAAI,OAAO,cAAc,MAAM,KAAK,SAAS,EAAG,MAAK;AAAA,IACvD,WAAW,KAAK,WAAW,OAAO,GAAG;AACnC,gBAAU,KAAK,KAAK,MAAM,QAAQ,MAAM,EAAE,UAAU,CAAC;AAAA,IACvD;AAAA,EACF;AACA,SAAO;AAAA,IACL;AAAA,IACA,MAAM,UAAU,SAAS,IAAI,UAAU,KAAK,IAAI,IAAI;AAAA,IACpD;AAAA,EACF;AACF;AAEA,SAAS,UAAU,MAAkD;AACnE,MAAI,CAAC,KAAM,QAAO;AAClB,MAAI;AACF,UAAM,SAAkB,KAAK,MAAM,IAAI;AACvC,QACE,WAAW,QACX,OAAO,WAAW,YAClB,WAAW,UACX,cAAc,UACd,OAAO,OAAO,UAAU,YACxB,OAAO,OAAO,aAAa,UAC3B;AACA,aAAO,EAAE,OAAO,OAAO,OAAO,UAAU,OAAO,SAAS;AAAA,IAC1D;AAAA,EACF,QAAQ;AAAA,EAER;AACA,SAAO;AACT;AAGA,SAAS,gBAAgB,MAAyE;AAChG,QAAME,YAAW,EAAE,MAAM,QAAW,SAAS,mBAAmB;AAChE,MAAI,CAAC,KAAM,QAAOA;AAClB,MAAI;AACF,UAAM,SAAkB,KAAK,MAAM,IAAI;AACvC,QAAI,WAAW,QAAQ,OAAO,WAAW,UAAU;AACjD,YAAMF,UAAS;AACf,aAAO;AAAA,QACL,MAAM,OAAOA,QAAO,SAAS,YAAYA,QAAO,SAAS,KAAKA,QAAO,OAAO;AAAA,QAC5E,SACE,OAAOA,QAAO,YAAY,YAAYA,QAAO,YAAY,KACrDA,QAAO,UACPE,UAAS;AAAA,MACjB;AAAA,IACF;AAAA,EACF,QAAQ;AAAA,EAER;AACA,SAAOA;AACT;AAGA,SAAS,WAAW,MAAuC;AACzD,MAAI;AACF,UAAM,SAAkB,KAAK,MAAM,IAAI;AACvC,QAAI,WAAW,QAAQ,OAAO,WAAW,YAAY,UAAU,QAAQ;AACrE,aAAO;AAAA,IACT;AAAA,EACF,QAAQ;AAAA,EAER;AACA,SAAO;AACT;AAGA,SAAS,YAAY,SAA4B;AAC/C,MAAI,OAAO;AACX,aAAW,QAAQ,QAAQ,SAAS,CAAC,GAAG;AACtC,QAAI,KAAK,SAAS,OAAQ,SAAQ,KAAK;AAAA,EACzC;AACA,SAAO;AACT;AAGA,SAAS,aACP,SACoC;AACpC,MAAI,YAAY,OAAW,QAAO;AAClC,SAAO,mBAAmB,UAAU,OAAO,YAAY,QAAQ,QAAQ,CAAC,IAAI;AAC9E;AAGA,SAAS,MAAM,IAAY,QAAgD;AACzE,MAAI,MAAM,KAAK,QAAQ,QAAS,QAAO,QAAQ,QAAQ;AACvD,SAAO,IAAI,QAAQ,CAAC,YAAY;AAC9B,UAAM,QAAQ,WAAW,MAAM,EAAE;AACjC,aAAS,OAAO;AACd,mBAAa,KAAK;AAClB,cAAQ,oBAAoB,SAAS,IAAI;AACzC,cAAQ;AAAA,IACV;AACA,YAAQ,iBAAiB,SAAS,MAAM,EAAE,MAAM,KAAK,CAAC;AAAA,EACxD,CAAC;AACH;AAEA,SAAS,4BACP,UACgC;AAChC,SAAO,IAAI,eAAe;AAAA,IACxB,MAAM,YAAY;AAChB,iBAAW,QAAQ,EAAE,MAAM,SAAS,WAAW,YAAY,OAAO,WAAW,CAAC,GAAG,CAAC;AAClF,iBAAW,QAAQ,EAAE,MAAM,0BAA0B,MAAM,UAAU,WAAW,KAAK,CAAC;AACtF,UAAI,SAAS,SAAS,UAAa,SAAS,KAAK,SAAS,GAAG;AAC3D,mBAAW,QAAQ,EAAE,MAAM,cAAc,IAAI,WAAW,CAAC;AACzD,mBAAW,QAAQ,EAAE,MAAM,cAAc,IAAI,YAAY,OAAO,SAAS,KAAK,CAAC;AAC/E,mBAAW,QAAQ,EAAE,MAAM,YAAY,IAAI,WAAW,CAAC;AAAA,MACzD;AACA,iBAAW,QAAQ,EAAE,MAAM,UAAU,cAAc,OAAO,CAAC;AAC3D,iBAAW,MAAM;AAAA,IACnB;AAAA,EACF,CAAC;AACH;;;ACp4BO,SAAS,SAAS,WAAoC;AAC3D,QAAM,OAAO,UAAU,YAAY;AACnC,MAAI,KAAK,WAAW,QAAQ,EAAG,QAAO;AACtC,MAAI,SAAS,kBAAmB,QAAO;AACvC,MAAI,KAAK,WAAW,OAAO,KAAK,SAAS,mBAAoB,QAAO;AACpE,MAAI,KAAK,WAAW,QAAQ,EAAG,QAAO;AACtC,MAAI,KAAK,WAAW,QAAQ,EAAG,QAAO;AACtC,SAAO;AACT;AAEA,SAAS,YAAY,KAAa,WAAmB,MAAqB,SAAwB;AAChG,QAAM,MAAM,MAAM,YAAY,GAAG,KAAK;AACtC,QAAM,OAAoB;AAAA,IACxB;AAAA,IACA;AAAA,IACA,UAAU;AAAA,IACV,MAAM,SAAS,SAAS;AAAA,IACxB,WAAW,SAAS,QAAQ,MAAM,IAAI,KAAK,MAAM,MAAM,CAAC,EAAE,YAAY,IAAI;AAAA,IAC1E;AAAA,EACF;AACA,SAAO;AACT;AAMO,SAAS,eAAe,YAA4C;AACzE,SAAO,YAAY,WAAW,KAAK,WAAW,aAAa,WAAW,MAAM,WAAW,OAAO;AAChG;AAOO,SAAS,aAAa,SAAkD;AAC7E,QAAM,QAAuB,CAAC;AAC9B,aAAW,QAAQ,QAAQ,OAAO;AAChC,QAAI,KAAK,SAAS,OAAQ;AAC1B,UAAM,OAAO;AACb,UAAM,UAAW,KAAK,kBAAkB,OAA6C;AACrF,UAAM;AAAA,MACJ;AAAA,QACE,KAAK;AAAA,QACL,KAAK;AAAA,QACL,KAAK,YAAY;AAAA,QACjB,OAAO,YAAY,WAAW,UAAU;AAAA,MAC1C;AAAA,IACF;AAAA,EACF;AACA,SAAO;AACT;AAMO,SAAS,YACd,QACA,MACS;AACT,QAAM,SAAS,OAAO,WAAW,WAAW,OAAO,MAAM,GAAG,IAAK,UAAU,CAAC,GACzE,IAAI,CAAC,SAAS,KAAK,KAAK,EAAE,YAAY,CAAC,EACvC,OAAO,CAAC,SAAS,KAAK,SAAS,CAAC;AACnC,MAAI,MAAM,WAAW,EAAG,QAAO;AAC/B,QAAM,OAAO,KAAK,KAAK,YAAY;AACnC,QAAM,OAAO,KAAK,KAAK,YAAY;AACnC,SAAO,MAAM,KAAK,CAAC,SAAS;AAC1B,QAAI,KAAK,WAAW,GAAG,EAAG,QAAO,KAAK,SAAS,IAAI;AACnD,QAAI,KAAK,SAAS,IAAI,EAAG,QAAO,KAAK,WAAW,KAAK,MAAM,GAAG,EAAE,CAAC;AACjE,WAAO,SAAS;AAAA,EAClB,CAAC;AACH;AAGO,SAAS,mBAAmB,MAA+C;AAChF,MAAI,CAAC,KAAM,QAAO,CAAC;AACnB,QAAM,QAAgB,CAAC;AACvB,aAAW,QAAQ,MAAM,KAAK,KAAK,SAAS,CAAC,CAAC,GAAG;AAC/C,QAAI,KAAK,SAAS,OAAQ;AAC1B,UAAM,OAAO,KAAK,UAAU;AAC5B,QAAI,SAAS,KAAM,OAAM,KAAK,IAAI;AAAA,EACpC;AACA,SAAO,MAAM,SAAS,IAAI,QAAQ,MAAM,KAAK,KAAK,SAAS,CAAC,CAAC;AAC/D;AAGO,SAAS,aAAa,MAAgD;AAC3E,SAAO,MAAM,KAAK,MAAM,SAAS,CAAC,CAAC,EAAE,SAAS,OAAO;AACvD;;;AC7GA,SAAS,eAAAC,cAAa,aAAAC,YAAW,WAAAC,UAAS,UAAAC,SAAQ,YAAAC,iBAAgB;;;ACgP3D,IAAM,+BAAN,cAA2C,MAAM;AAAA,EACtD,YAAqB,QAAgB;AACnC,UAAM,wCAAwC,MAAM,IAAI;AADrC;AAEnB,SAAK,OAAO;AAAA,EACd;AAAA,EAHqB;AAIvB;AAUO,SAAS,qBACd,SACA,MAC8B;AAC9B,QAAM,SAAS,QAAQ,IAAI;AAC3B,MAAI,OAAO,WAAW,YAAY;AAChC,UAAM,IAAI,6BAA6B,IAAI;AAAA,EAC7C;AACA,SAAQ,OAAyC,KAAK,OAAO;AAC/D;;;ACxQA,SAAS,aAAAC,YAAW,YAAAC,iBAAgB;;;ACApC,SAAuC,cAAAC,aAAY,WAAAC,UAAS,UAAAC,eAAc;;;ACD1E,SAAuC,eAAe,kBAAkB;AAWjE,SAAS,cAAiB,KAAgC;AAC/D,QAAM,SAAS,OAAO,IAAI,GAAG;AAC7B,QAAM,SAAS;AACf,QAAM,WAAW,OAAO,MAAM;AAC9B,MAAI,aAAa,OAAW,QAAO;AACnC,QAAM,UAAU,cAAwB,IAAI;AAC5C,SAAO,MAAM,IAAI;AACjB,SAAO;AACT;AAMO,IAAM,yBACX,cAA+B,gDAAgD;AAO1E,SAAS,qBAA6C;AAC3D,SAAO,WAAW,sBAAsB;AAC1C;;;ACnCA;AAAA,EACE;AAAA,EAIA,iBAAAC;AAAA,EACA;AAAA,EACA;AAAA,EACA,cAAAC;AAAA,EACA,WAAAC;AAAA,EACA,UAAAC;AAAA,OACK;;;ACXP,SAAS,cAAc,OAAkD;AACvE,MAAI,OAAO,UAAU,YAAY,UAAU,QAAQ,MAAM,QAAQ,KAAK,EAAG,QAAO;AAChF,QAAM,YAAY,OAAO,eAAe,KAAK;AAC7C,SAAO,cAAc,OAAO,aAAa,cAAc;AACzD;AAaO,SAAS,eAAkB,UAAmB,MAAY;AAC/D,MAAI,OAAO,GAAG,UAAU,IAAI,EAAG,QAAO;AACtC,MAAI,MAAM,QAAQ,IAAI,GAAG;AACvB,QAAI,CAAC,MAAM,QAAQ,QAAQ,EAAG,QAAO;AACrC,QAAI,OAAO,SAAS,WAAW,KAAK;AACpC,UAAMC,UAAS,KAAK,IAAI,CAAC,OAAO,UAAU;AACxC,YAAM,OAAO,eAAe,SAAS,KAAK,GAAG,KAAK;AAClD,UAAI,SAAS,SAAS,KAAK,EAAG,QAAO;AACrC,aAAO;AAAA,IACT,CAAC;AACD,WAAQ,OAAO,WAAWA;AAAA,EAC5B;AACA,MAAI,cAAc,IAAI,GAAG;AACvB,QAAI,CAAC,cAAc,QAAQ,EAAG,QAAO;AACrC,UAAM,OAAO,OAAO,KAAK,IAAI;AAC7B,QAAI,OAAO,KAAK,WAAW,OAAO,KAAK,QAAQ,EAAE;AACjD,UAAMA,UAAkC,CAAC;AACzC,eAAW,OAAO,MAAM;AACtB,YAAM,OAAO,eAAe,SAAS,GAAG,GAAG,KAAK,GAAG,CAAC;AACpD,UAAI,SAAS,SAAS,GAAG,KAAK,CAAC,OAAO,OAAO,UAAU,GAAG,EAAG,QAAO;AACpE,MAAAA,QAAO,GAAG,IAAI;AAAA,IAChB;AACA,WAAQ,OAAO,WAAWA;AAAA,EAC5B;AACA,SAAO;AACT;;;AC1CA,SAAS,aAAAC,YAAW,SAAS,YAAAC,iBAAgB;;;ACGtC,IAAM,uBAAuB;;;ADUpC,SAAS,SAAS,OAAkD;AAClE,SAAO,OAAO,UAAU,YAAY,UAAU,QAAQ,CAAC,MAAM,QAAQ,KAAK;AAC5E;AAOO,SAAS,mBAAmB,MAAwC;AACzE,MAAI,CAAC,SAAS,IAAI,EAAG,QAAO;AAC5B,QAAM,SAAS,KAAK,SAAS,aAAa,SAAS,KAAK,IAAI,IAAI,KAAK,OAAO;AAC5E,MAAI,OAAO,OAAO,cAAc,SAAU,QAAO;AACjD,QAAM,KACJ,OAAO,OAAO,OAAO,WAAW,OAAO,KAAK,OAAO,KAAK,OAAO,WAAW,KAAK,KAAK;AACtF,MAAI,OAAO,KAAM,QAAO;AACxB,SAAO;AAAA,IACL;AAAA,IACA,WAAW,OAAO;AAAA,IAClB,GAAI,SAAS,OAAO,iBAAiB,KACrC,OAAO,OAAO,OAAO,iBAAiB,EAAE;AAAA,MACtC,CAAC,YAAY,OAAO,YAAY,YAAY,OAAO,cAAc,OAAO,KAAK,UAAU;AAAA,IACzF,IACI,EAAE,mBAAmB,EAAE,GAAG,OAAO,kBAAkB,EAA4B,IAC/E,CAAC;AAAA,IACL,GAAI,OAAO,OAAO,iBAAiB,WAAW,EAAE,cAAc,OAAO,aAAa,IAAI,CAAC;AAAA,IACvF,OAAO,SAAS,OAAO,KAAK,IAAI,OAAO,QAAQ,CAAC;AAAA,IAChD,SAAS,OAAO,OAAO,YAAY,WAAW,OAAO,UAAU;AAAA,IAC/D,YAAY,OAAO,OAAO,eAAe,WAAW,OAAO,aAAa;AAAA,IACxE,GAAI,OAAO,YAAY,OAAO,EAAE,SAAS,KAAc,IAAI,CAAC;AAAA,EAC9D;AACF;AAaA,IAAM,iBAAiB,oBAAI,QAAmD;AAE9E,SAAS,cACP,SACA,MACA,SACY;AACZ,MAAI,QAAQ,eAAe,IAAI,OAAO;AACtC,MAAI,UAAU,QAAW;AACvB,YAAQ,oBAAI,IAAI;AAChB,mBAAe,IAAI,SAAS,KAAK;AAAA,EACnC;AACA,QAAM,MAAM,GAAG,IAAI,IAAI,WAAW,EAAE;AACpC,QAAM,MAAM,MAAM,IAAI,GAAG;AACzB,MAAI,QAAQ,OAAW,QAAO;AAC9B,MAAI;AACJ,MAAI;AACF,UAAM,SAAS,QAAQ,MAAM,OAAO;AACpC,QAAI,kBAAkB,SAAS;AAC7B,cAAQ,EAAE,YAAY,EAAE,QAAQ,UAAU,GAAG,SAAS,KAAK;AAC3D,YAAM,UAAU,OAAO;AAAA,QACrB,CAACC,eAAc;AACb,gBAAM,aAAaA,aAAY,EAAE,QAAQ,SAAS,WAAAA,WAAU,IAAI,EAAE,QAAQ,UAAU;AAAA,QACtF;AAAA,QACA,CAAC,UAAmB;AAClB,gBAAM,aAAa,EAAE,QAAQ,SAAS,MAAM;AAAA,QAC9C;AAAA,MACF;AAAA,IACF,OAAO;AACL,cAAQ;AAAA,QACN,YAAY,SAAS,EAAE,QAAQ,SAAS,WAAW,OAAO,IAAI,EAAE,QAAQ,UAAU;AAAA,QAClF,SAAS;AAAA,MACX;AAAA,IACF;AAAA,EACF,SAAS,OAAO;AACd,YAAQ,EAAE,YAAY,EAAE,QAAQ,SAAS,MAAM,GAAG,SAAS,KAAK;AAAA,EAClE;AACA,QAAM,IAAI,KAAK,KAAK;AACpB,SAAO;AACT;AAOO,SAAS,qBACd,MACA,SACA,UACA,SACA,cACY;AACZ,QAAM,CAAC,EAAE,OAAO,IAAIC,UAAS,CAAC;AAC9B,QAAM,MAAM,SAAS,IAAI;AACzB,QAAM,QACJ,QAAQ,UAAa,YAAY,SAAY,OAAO,cAAc,SAAS,MAAM,OAAO;AAC1F,QAAM,UAAU,OAAO,WAAW,WAAW,YAAY,MAAM,UAAU;AACzE,EAAAC,WAAU,MAAM;AACd,QAAI,YAAY,KAAM;AACtB,QAAI,OAAO;AACX,SAAK,QAAQ,KAAK,MAAM;AACtB,UAAI,KAAM,SAAQ,CAAC,SAAS,OAAO,CAAC;AAAA,IACtC,CAAC;AACD,WAAO,MAAM;AACX,aAAO;AAAA,IACT;AAAA,EACF,GAAG,CAAC,OAAO,CAAC;AACZ,MAAI,QAAQ,OAAW,QAAO,EAAE,QAAQ,SAAS,WAAW,IAAI;AAChE,MAAI,UAAU,QAAQ,MAAM,WAAW,WAAW,UAAW,QAAO,MAAM;AAC1E,MAAI,SAAS,wBAAwB,iBAAiB,QAAW;AAC/D,WAAO,EAAE,QAAQ,SAAS,WAAW,aAAa;AAAA,EACpD;AACA,SAAO,EAAE,QAAQ,UAAU;AAC7B;AAWO,SAAS,kBACd,SACA,MACA,OACY;AACZ,QAAM,UAAU,SAAS,IAAI,IAAI,MAAM;AACvC,QAAM,YAAY,QAA2B,MAAM;AACjD,QAAI,CAAC,WAAW,YAAY,OAAW,QAAO,EAAE,QAAQ,MAAM,MAAM;AACpE,UAAM,SAAS,QAAQ,eAAe,MAAM,KAAK;AACjD,QAAI,WAAW,OAAW,QAAO;AACjC,WAAO,OAAO,KACV,EAAE,QAAQ,MAAM,OAAO,OAAO,MAAM,IACpC,EAAE,QAAQ,WAAW,QAAQ,OAAO,OAAO;AAAA,EACjD,GAAG,CAAC,SAAS,SAAS,MAAM,KAAK,CAAC;AAClC,QAAM,CAAC,MAAM,OAAO,IAAID;AAAA,IACtB;AAAA,EACF;AACA,EAAAC,WAAU,MAAM;AACd,QAAI,cAAc,QAAQ,YAAY,OAAW;AACjD,QAAI,OAAO;AACX,YAAQ,SAAS,MAAM,KAAK,EAAE;AAAA,MAC5B,CAAC,WAAW;AACV,YAAI,CAAC,KAAM;AACX,gBAAQ;AAAA,UACN;AAAA,UACA,QAAQ,OAAO,KACX,EAAE,QAAQ,MAAM,OAAO,OAAO,MAAM,IACpC,EAAE,QAAQ,WAAW,QAAQ,OAAO,OAAO;AAAA,QACjD,CAAC;AAAA,MACH;AAAA,MACA,CAAC,UAAmB;AAClB,YAAI,CAAC,KAAM;AACX,gBAAQ;AAAA,UACN;AAAA,UACA,QAAQ;AAAA,YACN,QAAQ;AAAA,YACR,QAAQ,CAAC,EAAE,MAAM,CAAC,GAAG,SAAS,iBAAiB,QAAQ,MAAM,UAAU,OAAO,KAAK,EAAE,CAAC;AAAA,UACxF;AAAA,QACF,CAAC;AAAA,MACH;AAAA,IACF;AACA,WAAO,MAAM;AACX,aAAO;AAAA,IACT;AAAA,EACF,GAAG,CAAC,WAAW,SAAS,MAAM,KAAK,CAAC;AACpC,MAAI,cAAc,KAAM,QAAO;AAC/B,SAAO,SAAS,QAAQ,KAAK,UAAU,QAAQ,KAAK,SAAS,EAAE,QAAQ,UAAU;AACnF;AAGO,SAAS,qBACd,MACA,SACA,cAC0B;AAC1B,QAAM,OAAO,QAAQ,MAAM,mBAAmB,IAAI,GAAG,CAAC,IAAI,CAAC;AAC3D,QAAM,OAAO,MAAM,aAAa;AAChC,QAAM,aAAa,QAAQ,SAAS,MAAM,IAAI;AAC9C,QAAM,eACJ,MAAM,iBAAiB,UACvB,KAAK,YAAY,QACjB,eAAe,UACf,KAAK,aAAa,WAAW,WAAW;AAC1C,QAAM,aAAa;AAAA,IACjB;AAAA,IACA,MAAM,WAAW;AAAA,IACjB,eAAe,CAAC,IAAI,QAAQ;AAAA,IAC5B,SAAS,OAAO,SAAY,QAAQ;AAAA,IACpC;AAAA,EACF;AACA,QAAM,QAAQ,QAAiC,OAAO,CAAC,IAAI,CAAC,CAAC;AAE7D,QAAM,aAAa;AAAA,IACjB,SAAS,QAAQ,SAAS,wBAAwB,eAAe,SAAY,QAAQ;AAAA,IACrF;AAAA,IACA,MAAM,SAAS;AAAA,EACjB;AACA,MAAI,SAAS,KAAM,QAAO;AAE1B,MAAI,KAAK,YAAY,QAAQ,OAAO,KAAK,KAAK,KAAK,EAAE,WAAW,EAAG,QAAO;AAC1E,MACE,SAAS,wBACT,KAAK,iBAAiB,WACrB,CAAC,SAAS,KAAK,MAAM,IAAI,KAAK,OAAO,KAAK,MAAM,KAAK,SAAS;AAE/D,WAAO;AAAA,MACL,QAAQ;AAAA,MACR,QAAQ;AAAA,MACR;AAAA,MACA,QAAQ,CAAC,EAAE,MAAM,CAAC,MAAM,GAAG,SAAS,uBAAuB,CAAC;AAAA,IAC9D;AACF,MAAI,WAAW,WAAW,UAAW,QAAO,EAAE,QAAQ,WAAW,KAAK;AACtE,MAAI,WAAW,WAAW,UAAW,QAAO,EAAE,QAAQ,WAAW,QAAQ,WAAW,KAAK;AACzF,MAAI,WAAW,WAAW,SAAS;AACjC,WAAO,EAAE,QAAQ,WAAW,QAAQ,SAAS,MAAM,OAAO,WAAW,MAAM;AAAA,EAC7E;AACA,MAAI,WAAW,WAAW,UAAW,QAAO,EAAE,QAAQ,WAAW,KAAK;AACtE,MAAI,WAAW,WAAW,WAAW;AACnC,WAAO,EAAE,QAAQ,WAAW,QAAQ,WAAW,MAAM,QAAQ,WAAW,OAAO;AAAA,EACjF;AACA,SAAO,EAAE,QAAQ,SAAS,MAAM,WAAW,WAAW,WAAW,OAAO,WAAW,MAAM;AAC3F;;;AFzJI;AAlCJ,IAAM,mBAAmBC,eAAgC,IAAI;AAI7D,IAAM,mBAAmD;AAAA,EACvD;AACF;AAkBA,SAAS,kBAAkB,MAAgB,MAAiC;AAC1E,QAAM,EAAE,YAAY,IAAI;AACxB,MAAI,OAAO,gBAAgB,WAAY,QAAO,YAAY,IAAI;AAC9D,SAAO,gBAAgB,SAAY,cAAc,KAAK;AACxD;AAEA,SAAS,eAAeC,WAA4C,SAA8B;AAChG,MAAI,OAAOA,cAAa,WAAY,QAAOA,UAAS,OAAO;AAC3D,MAAIA,cAAa,OAAW,QAAOA;AACnC,SAAO,QAAQ,KAAK,iBAAiB,SACnC,oBAAC,UAAK,OAAO,EAAE,YAAY,WAAW,GAAI,kBAAQ,KAAK,cAAa,IAClE;AACN;AAUA,IAAM,eAAN,cAA2B,UAA8D;AAAA,EAC9E,QAAQ,EAAE,OAAO,QAAsB,QAAQ,MAAM;AAAA,EAE9D,OAAO,yBAAyB,OAAgB;AAC9C,WAAO,EAAE,OAAO,QAAQ,KAAK;AAAA,EAC/B;AAAA,EAES,kBAAkB,OAAgB,OAAkB;AAC3D,SAAK,MAAM,UAAU,OAAO,KAAK,MAAM,IAAI;AAAA,EAC7C;AAAA,EAES,mBAAmB,UAAyB;AAEnD,QAAI,KAAK,MAAM,UAAU,SAAS,SAAS,KAAK,MAAM,MAAM;AAC1D,WAAK,SAAS,EAAE,OAAO,QAAW,QAAQ,MAAM,CAAC;AAAA,IACnD;AAAA,EACF;AAAA,EAES,SAAS;AAChB,QAAI,KAAK,MAAM,QAAQ;AACrB,aAAO,eAAe,KAAK,MAAM,UAAU;AAAA,QACzC,QAAQ;AAAA,QACR,MAAM,KAAK,MAAM;AAAA,QACjB,OAAO,KAAK,MAAM;AAAA,MACpB,CAAC;AAAA,IACH;AACA,WAAO,KAAK,MAAM;AAAA,EACpB;AACF;AAEA,SAAS,SAAS,MAA2B,IAA8B;AACzE,SAAO,EAAE,IAAI,WAAW,KAAK,MAAM,OAAO,KAAK,SAAS,CAAC,GAAG,SAAS,MAAM,YAAY,KAAK;AAC9F;AAGA,SAAS,WAAW,OAA2B;AAC7C,SAAO,CAAC,MAAM,eAAe,MAAM,iBAAiB;AACtD;AAeA,IAAM,WAAW;AAAA,EACf,SAASC,UAAS,EAAE,MAAM,IAAI,QAAQ,GAAkB;AACtD,UAAM,QAAQC,YAAW,gBAAgB;AACzC,UAAM,OAAOC,SAAQ,MAAM,SAAS,MAAM,EAAE,GAAG,CAAC,MAAM,EAAE,CAAC;AACzD,QAAI,UAAU,KAAM,QAAO;AAC3B,QAAI,CAAC,WAAW,WAAW,KAAK,EAAG,QAAO,oBAAC,gBAAa,MAAY,IAAQ,MAAY;AACxF,WACE;AAAA,MAAC;AAAA;AAAA,QACC;AAAA,QACA,UAAU,MAAM,KAAK,QAAQ;AAAA,QAC7B,SAAS,MAAM,KAAK,QAAQ;AAAA,QAE5B,8BAAC,gBAAa,MAAY,IAAQ,MAAY;AAAA;AAAA,IAChD;AAAA,EAEJ;AAAA,EACA,CAAC,UAAU,SACT,SAAS,SAAS,KAAK,QAAQ,SAAS,OAAO,KAAK,MAAM,SAAS,YAAY,KAAK;AACxF;AAGA,SAAS,aAAa;AAAA,EACpB;AAAA,EACA;AAAA,EACA;AACF,GAIG;AACD,QAAM,QAAQD,YAAW,gBAAgB;AAGzC,QAAM,aAAa,KAAK,eAAe;AACvC,QAAM,OAAO,KAAK,SAAS;AAC3B,QAAM,QAAQC;AAAA,IACZ,OAAO,EAAE,IAAI,MAAM,KAAK,MAAM,YAAY,KAAK;AAAA,IAC/C,CAAC,IAAI,KAAK,MAAM,YAAY,IAAI;AAAA,EAClC;AACA,QAAM,gBAAgB,OAAO,oBAAoB,KAAK,IAAI;AAC1D,QAAM,aAAa,OAAO,QAAQ,SAAS,MAAM,KAAK,IAAI;AAC1D,QAAM,eACJ,kBAAkB,UAClB,eAAe,UACf,mBAAmB,WAAW,WAAW;AAC3C,QAAM,aAAa;AAAA,IACjB,KAAK;AAAA,IACL,iBAAiB;AAAA,IACjB,eAAe,CAAC,IAAK,OAAO,QAAQ,YAAY,CAAC;AAAA,IACjD,OAAO,QAAQ;AAAA,EACjB;AACA,QAAM,aAAa;AAAA,IACjB,gBAAgB,aAAa,SAAY,OAAO,QAAQ;AAAA,IACxD,KAAK;AAAA,IACL,KAAK;AAAA,EACP;AACA,MAAI,UAAU,KAAM,QAAO;AAC3B,QAAM,OAAO,MAAM,KAAK;AACxB,MAAI,MAAM;AACR,WACE,oBAAC,iBAAiB,UAAjB,EAA0B,OAAO,OAC/B,4BAAkB,MAAM,KAAK,GAChC;AAAA,EAEJ;AACA,MAAI,WAAW,WAAW,aAAa,WAAW,WAAW,UAAW,QAAO,KAAK;AACpF,MAAI,WAAW,WAAW,WAAW;AACnC,QAAI,WAAW,KAAK,EAAG,OAAM,IAAI,MAAM,wBAAwB;AAC/D,WAAO,eAAe,KAAK,UAAU,EAAE,QAAQ,WAAW,KAAK,CAAC;AAAA,EAClE;AACA,MAAI,WAAW,WAAW,SAAS;AACjC,QAAI,WAAW,KAAK,EAAG,OAAM,WAAW;AACxC,WAAO,eAAe,KAAK,UAAU,EAAE,QAAQ,SAAS,MAAM,OAAO,WAAW,MAAM,CAAC;AAAA,EACzF;AACA,MAAI,WAAW,WAAW,WAAW;AACnC,QAAI,WAAW,KAAK,EAAG,OAAM,IAAI,MAAM,wBAAwB;AAC/D,WAAO,eAAe,KAAK,UAAU,EAAE,QAAQ,WAAW,MAAM,QAAQ,WAAW,OAAO,CAAC;AAAA,EAC7F;AACA,QAAM,WAAW,WAAW;AAC5B,QAAM,WAAW,MAAM,QAAQ,KAAK,QAAQ,IAAI,KAAK,WAAW,CAAC;AACjE,SACE,oBAAC,iBAAiB,UAAjB,EAA0B,OAAO,OAChC,8BAAC,YAAU,GAAG,WAAW,OACtB,mBAAS,SAAS,IACf,SAAS,IAAI,CAAC,OAAO,UAAU;AAC7B,UAAM,UAAU,GAAG,EAAE,IAAI,KAAK;AAC9B,WAAO,oBAAC,YAAuB,MAAM,OAAO,IAAI,SAAS,SAAO,QAA1C,OAA2C;AAAA,EACnE,CAAC,IACD,QACN,GACF;AAEJ;AAUO,SAAS,UAAU,EAAE,KAAK,GAAmC;AAClE,QAAM,WAAWC,QAAwC,MAAS;AAClE,QAAM,QAAQ,SAAS,UAAa,SAAS,QAAQ,OAAO,KAAK,SAAS;AAC1E,QAAMC,UAAS,QAAQ,eAAe,SAAS,SAAS,IAAI,IAAI;AAChE,WAAS,UAAUA;AACnB,MAAIA,YAAW,OAAW,QAAO;AACjC,SAAO,oBAAC,YAAS,MAAMA,SAAQ,IAAG,QAAO,SAAS,OAAO;AAC3D;AAiBO,SAAS,kBAAkB;AAAA,EAChC;AAAA,EACA;AAAA,EACA;AAAA,EACA,UAAAL;AAAA,EACA;AAAA,EACA;AAAA,EACA,UAAU;AAAA,EACV;AAAA,EACA;AAAA,EACA;AACF,GAA2B;AAEzB,QAAM,cAAcI,QAA2C,MAAS;AACxE,QAAM,WAAW,eAAe,YAAY,SAAS,iBAAiB;AACtE,cAAY,UAAU;AACtB,QAAM,OAAOA,QAAiB,EAAE,UAAAJ,WAAU,SAAS,aAAa,QAAQ,CAAC;AACzE,OAAK,UAAU,EAAE,UAAAA,WAAU,SAAS,aAAa,QAAQ;AACzD,QAAM,cAAcA,cAAa;AACjC,QAAM,QAAQG;AAAA,IACZ,OAAO;AAAA,MACL,SAAS;AAAA,QACP;AAAA,QACA,GAAI,YAAY,SAAY,EAAE,QAAQ,IAAI,CAAC;AAAA,QAC3C,GAAI,qBAAqB,SAAY,EAAE,iBAAiB,IAAI,CAAC;AAAA,MAC/D;AAAA,MACA;AAAA,MACA,GAAI,aAAa,SAAY,EAAE,mBAAmB,SAAS,IAAI,CAAC;AAAA,MAChE,GAAI,iBAAiB,SAAY,EAAE,aAAa,IAAI,CAAC;AAAA,MACrD;AAAA,IACF;AAAA,IACA,CAAC,UAAU,SAAS,kBAAkB,aAAa,cAAc,QAAQ;AAAA,EAC3E;AACA,SAAO,oBAAC,iBAAiB,UAAjB,EAA0B,OAAO,OAAQ,UAAS;AAC5D;AAaA,IAAM,eAAmD;AAAA,EACvD;AACF;AAuBO,SAAS,cAAc;AAAA,EAC5B;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA,UAAAG;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AACF,GAAuB;AACrB,QAAM,QAAQC;AAAA,IACZ,OAAO;AAAA,MACL,GAAI,aAAa,SAAY,EAAE,SAAS,IAAI,CAAC;AAAA,MAC7C,GAAI,YAAY,SAAY,EAAE,QAAQ,IAAI,CAAC;AAAA,MAC3C,GAAI,qBAAqB,SAAY,EAAE,iBAAiB,IAAI,CAAC;AAAA,MAC7D,GAAI,iBAAiB,SAAY,EAAE,aAAa,IAAI,CAAC;AAAA,MACrD,GAAID,cAAa,SAAY,EAAE,UAAAA,UAAS,IAAI,CAAC;AAAA,MAC7C,GAAI,YAAY,SAAY,EAAE,QAAQ,IAAI,CAAC;AAAA,MAC3C,GAAI,gBAAgB,SAAY,EAAE,YAAY,IAAI,CAAC;AAAA,MACnD,GAAI,YAAY,SAAY,EAAE,QAAQ,IAAI,CAAC;AAAA,IAC7C;AAAA,IACA,CAAC,UAAU,SAAS,kBAAkB,cAAcA,WAAU,SAAS,aAAa,OAAO;AAAA,EAC7F;AACA,QAAM,WAAW,YAAY,CAAC,UAA6B,oBAAC,gBAAa,MAAM,OAAO,GAAI,CAAC,CAAC;AAC5F,SACE,oBAAC,aAAa,UAAb,EAAsB,OACrB,8BAAC,uBAAuB,UAAvB,EAAgC,OAAO,UAAW,UAAS,GAC9D;AAEJ;AAEA,IAAM,cAA6B,CAAC;AAGpC,SAAS,iBAAiB,KAAwD;AAChF,QAAM,WAAWE,YAAW,YAAY;AACxC,QAAM,WAAW,IAAI,YAAY,UAAU,YAAY;AACvD,QAAM,UAAU,IAAI,WAAW,UAAU;AACzC,QAAM,mBAAmB,IAAI,oBAAoB,UAAU;AAC3D,QAAM,eAAe,IAAI,gBAAgB,UAAU;AACnD,SAAOD;AAAA,IACL,OAAO;AAAA,MACL;AAAA,MACA,GAAI,YAAY,SAAY,EAAE,QAAQ,IAAI,CAAC;AAAA,MAC3C,GAAI,qBAAqB,SAAY,EAAE,iBAAiB,IAAI,CAAC;AAAA,MAC7D,GAAI,iBAAiB,SAAY,EAAE,aAAa,IAAI,CAAC;AAAA,IACvD;AAAA,IACA,CAAC,UAAU,SAAS,kBAAkB,YAAY;AAAA,EACpD;AACF;AAuCO,SAAS,aAAa;AAAA,EAC3B;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA,UAAU;AAAA,EACV,SAAS;AAAA,EACT,aAAa;AAAA,EACb,SAAS;AACX,GAAsB;AACpB,QAAM,WAAWE,YAAW,YAAY;AACxC,QAAMC,YAAW,gBAAgB,SAAY,cAAc,UAAU;AACrE,QAAM,UAAU,cAAc,UAAU,WAAW;AACnD,QAAM,cAAc,mBAAmB,SAAY,iBAAiB,UAAU;AAC9E,QAAM,UAAU,cAAc,UAAU;AACxC,QAAM,UAAU,iBAAiB;AAAA,IAC/B,GAAI,aAAa,SAAY,EAAE,SAAS,IAAI,CAAC;AAAA,IAC7C,GAAI,YAAY,SAAY,EAAE,QAAQ,IAAI,CAAC;AAAA,IAC3C,GAAI,qBAAqB,SAAY,EAAE,iBAAiB,IAAI,CAAC;AAAA,IAC7D,GAAI,iBAAiB,SAAY,EAAE,aAAa,IAAI,CAAC;AAAA,EACvD,CAAC;AACD,QAAM,QAAQ;AAAA,IACZ;AAAA,IACA;AAAA,IACA,QAAQ,gBAAiB;AAAA,EAC3B;AACA,MAAI,UAAU,KAAM,QAAO;AAC3B,MAAI,MAAM,WAAW,UAAW,QAAO;AACvC,MAAI,MAAM,WAAW,WAAW;AAC9B,UAAM,EAAE,QAAQ,SAAS,GAAG,QAAQ,IAAI;AACxC,WAAO,eAAeA,WAAU,OAAO;AAAA,EACzC;AACA,QAAM,WAAW,MAAM;AACvB,SACE;AAAA,IAAC;AAAA;AAAA,MACE,GAAG;AAAA,MACH,GAAI,MAAM,KAAK,sBAAsB,SAClC,EAAE,mBAAmB,MAAM,KAAK,kBAAkB,IAClD,CAAC;AAAA,MACJ,GAAI,MAAM,KAAK,iBAAiB,SAAY,EAAE,cAAc,MAAM,KAAK,aAAa,IAAI,CAAC;AAAA,MAC1F,UAAUA;AAAA,MACV;AAAA,MACC,GAAI,gBAAgB,SAAY,EAAE,YAAY,IAAI,CAAC;AAAA,MACnD,GAAI,YAAY,SAAY,EAAE,QAAQ,IAAI,CAAC;AAAA,MAE5C,8BAAC,gBAAa,MAAM,MAAM,MAAM,UAAUA,WAAU,SAClD,8BAAC,YAAU,GAAG,MAAM,OAAO,GAC7B;AAAA;AAAA,EACF;AAEJ;;;AFlY0B,gBAAAC,YAAA;AAjG1B,IAAM,sBAAoD;AAAA,EACxD;AACF;AA0DO,SAAS,cAAc;AAAA,EAC5B;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AACF,GAAuB;AAErB,QAAM,gBAAgBC,QAAO,EAAE,SAAS,YAAY,YAAY,CAAC;AACjE,gBAAc,UAAU,EAAE,SAAS,YAAY,YAAY;AAC3D,QAAM,SAAS,aAAa;AAC5B,QAAM,QAAQC;AAAA,IACZ,MACE,WACA,IAAI,YAAY;AAAA,MACd,GAAI,YAAY,SAAY,EAAE,QAAQ,IAAI,CAAC;AAAA,MAC3C,GAAI,SAAS,SAAY,EAAE,KAAK,IAAI,CAAC;AAAA,MACrC,GAAI,gBAAgB,SAAY,EAAE,YAAY,IAAI,CAAC;AAAA,MACnD,GAAI,UAAU,SAAY,EAAE,MAAM,IAAI,CAAC;AAAA,MACvC,GAAI,WAAW,SAAY,EAAE,aAAa,EAAE,OAAO,EAAE,IAAI,CAAC;AAAA,MAC1D,aAAa,CAAC,UAAU,cAAc,QAAQ,cAAc,KAAK;AAAA,MACjE,YAAY,YAAY;AACtB,cAAM,UAAU,cAAc;AAC9B,cAAM,UAAW,MAAM,QAAQ,aAAa,KAAM,CAAC;AACnD,eAAO,EAAE,GAAG,QAAQ,SAAS,GAAG,QAAQ;AAAA,MAC1C;AAAA,IACF,CAAC;AAAA,IACH,CAAC,SAAS,SAAS,MAAM,aAAa,OAAO,MAAM;AAAA,EACrD;AACA,QAAM,UACJ,UAAU,SAAY,gBAAAF,KAAC,iBAAe,GAAG,OAAQ,UAAS,IAAmB;AAC/E,SACE,gBAAAA,KAAC,2BAA2B,UAA3B,EAAoC,OAAO,kBAAkB,MAC5D,0BAAAA,KAAC,oBAAoB,UAApB,EAA6B,OAAe,mBAAQ,GACvD;AAEJ;AAEA,IAAI;AAGJ,SAAS,iBAA8B;AACrC,eAAa,IAAI,YAAY;AAC7B,SAAO;AACT;AAMO,SAAS,gBAAuD,KAAY;AACjF,QAAM,WAAWG,YAAW,mBAAmB;AAC/C,SAAQ,OAAO,YAAY,eAAe;AAC5C;AAEA,IAAM,6BAA6B;AAAA,EACjC;AACF;AAMO,SAAS,yBAAqD;AACnE,SAAOA,YAAW,0BAA0B,KAAK;AACnD;;;ADxHA,IAAM,SAAS,oBAAI,QAAkD;AAErE,SAAS,KAAK,SAA+D;AAC3E,QAAM,YAAY,QAAQ;AAC1B,MAAI,OAAO,cAAc,WAAY,QAAO;AAC5C,MAAI,UAAU,OAAO,IAAI,OAAO;AAChC,MAAI,YAAY,QAAW;AACzB,cAAU,UAAU,KAAK,OAAO,EAAE,MAAM,CAAC,UAAmB;AAC1D,aAAO,OAAO,OAAO;AACrB,YAAM;AAAA,IACR,CAAC;AACD,WAAO,IAAI,SAAS,OAAO;AAAA,EAC7B;AACA,SAAO;AACT;AAOO,SAAS,eAAe,UAAiC,CAAC,GAAqB;AACpF,QAAM,UAAU,gBAAgB,QAAQ,OAAO;AAC/C,QAAM,UAAU,QAAQ,YAAY;AACpC,QAAM,CAAC,QAAQ,SAAS,IAAIC,UAAwC,MAAS;AAC7E,QAAM,CAAC,WAAW,UAAU,IAAIA,UAAS,KAAK;AAC9C,QAAM,CAAC,OAAO,QAAQ,IAAIA,UAAuB,IAAI;AAErD,EAAAC,WAAU,MAAM;AACd,QAAI,CAAC,QAAS;AACd,UAAM,UAAU,KAAK,OAAO;AAC5B,QAAI,YAAY,OAAW;AAC3B,QAAI,YAAY;AAChB,eAAW,IAAI;AACf,YAAQ;AAAA,MACN,CAAC,WAAW;AACV,YAAI,UAAW;AACf,kBAAU,WAAW,QAAQ,OAAO,WAAW,WAAW,SAAS,MAAS;AAC5E,iBAAS,IAAI;AACb,mBAAW,KAAK;AAAA,MAClB;AAAA,MACA,CAAC,YAAqB;AACpB,YAAI,UAAW;AACf,iBAAS,mBAAmB,QAAQ,UAAU,IAAI,MAAM,OAAO,OAAO,CAAC,CAAC;AACxE,mBAAW,KAAK;AAAA,MAClB;AAAA,IACF;AACA,WAAO,MAAM;AACX,kBAAY;AAAA,IACd;AAAA,EACF,GAAG,CAAC,SAAS,OAAO,CAAC;AAErB,SAAO,EAAE,QAAQ,WAAW,MAAM;AACpC;;;AF4BA,IAAM,oBAAyE;AAAA,EAC7E,MAAM,CAAC,SAAS,GAAG,KAAK,IAAI;AAAA,EAC5B,MAAM,CAAC,SAAS,GAAG,KAAK,IAAI;AAAA,EAC5B,OAAO,MAAM;AACf;AAEA,IAAI,WAAW;AAaR,SAAS,eAAe,UAAiC,CAAC,GAAqB;AACpF,QAAM,UAAU,gBAAgB,QAAQ,OAAO;AAE/C,QAAM,EAAE,OAAO,IAAI,eAAe,EAAE,QAAQ,CAAC;AAC7C,QAAM,SAAS,QAAQ;AACvB,QAAM,SAAS,QAAQ,UAAU,QAAQ;AACzC,QAAM,WAAW,QAAQ,YAAY,QAAQ;AAC7C,QAAM,WAAW,QAAQ,YAAY,QAAQ;AAC7C,QAAM,YAAY;AAAA,IAChB,GAAG;AAAA,IACH;AAAA,IACA,GAAI,WAAW,SAAY,EAAE,OAAO,IAAI,CAAC;AAAA,IACzC,GAAI,aAAa,SAAY,EAAE,SAAS,IAAI,CAAC;AAAA,IAC7C,GAAI,aAAa,SAAY,EAAE,SAAS,IAAI,CAAC;AAAA,EAC/C;AACA,QAAM,SAASC,QAAO,SAAS;AAC/B,SAAO,UAAU;AACjB,QAAM,CAAC,OAAO,QAAQ,IAAIC,UAA6B,CAAC,CAAC;AACzD,QAAM,WAAWD,QAAO,KAAK;AAC7B,WAAS,UAAU;AACnB,QAAM,cAAcA,QAAO,oBAAI,IAA6B,CAAC;AAC7D,QAAM,CAAC,WAAW,YAAY,IAAIC,UAAS,CAAC;AAE5C,QAAM,QAAQC,aAAY,CAAC,IAAY,WAAsC;AAC3E,aAAS,CAAC,YAAY,QAAQ,IAAI,CAAC,SAAU,KAAK,OAAO,KAAK,EAAE,GAAG,MAAM,GAAG,OAAO,IAAI,IAAK,CAAC;AAAA,EAC/F,GAAG,CAAC,CAAC;AAEL,QAAM,QAAQA;AAAA,IACZ,CAAC,SAA2B;AAC1B,YAAM,EAAE,QAAQ,SAAAC,SAAQ,IAAI,OAAO;AACnC,YAAM,MACJ,WACCA,SAAQ,qBAAqB,SAC1BA,SAAQ,iBAAiB,KAAKA,QAAO,IACrC;AACN,UAAI,QAAQ,QAAW;AACrB,cAAM,KAAK,IAAI;AAAA,UACb,QAAQ;AAAA,UACR,OAAO,IAAI,6BAA6B,kBAAkB,EAAE;AAAA,QAC9D,CAAC;AACD;AAAA,MACF;AACA,YAAM,aAAa,IAAI,gBAAgB;AACvC,kBAAY,QAAQ,IAAI,KAAK,IAAI,UAAU;AAC3C,UAAI,KAAK,MAAM;AAAA,QACb,QAAQ,WAAW;AAAA,QACnB,YAAY,CAAC,aAAa,MAAM,KAAK,IAAI,EAAE,UAAU,KAAK,IAAI,GAAG,KAAK,IAAI,GAAG,QAAQ,CAAC,EAAE,CAAC;AAAA,MAC3F,CAAC,EAAE;AAAA,QACD,CAAC,eAAe;AACd,cAAI,WAAW,OAAO,QAAS;AAC/B,sBAAY,QAAQ,OAAO,KAAK,EAAE;AAClC,gBAAM,KAAK,IAAI,EAAE,QAAQ,SAAS,UAAU,GAAG,WAAW,CAAC;AAAA,QAC7D;AAAA,QACA,CAAC,UAAmB;AAClB,cAAI,WAAW,OAAO,QAAS;AAC/B,sBAAY,QAAQ,OAAO,KAAK,EAAE;AAClC,gBAAM,KAAK,IAAI;AAAA,YACb,QAAQ;AAAA,YACR,OAAO,iBAAiB,QAAQ,MAAM,UAAU,OAAO,KAAK;AAAA,UAC9D,CAAC;AAAA,QACH;AAAA,MACF;AAAA,IACF;AAAA,IACA,CAAC,KAAK;AAAA,EACR;AAEA,QAAM,MAAMD;AAAA,IACV,CAAC,UAA+D;AAC9D,UAAI,SAAS,KAAM;AACnB,YAAM,EAAE,QAAAE,SAAQ,UAAAC,WAAU,UAAAC,WAAU,kBAAkB,IAAI,OAAO;AACjE,YAAM,WAAW,CAAC,QAA6B,SAC7C,oBAAoB,QAAQ,IAAI,KAAK,kBAAkB,MAAM,EAAE,IAAI;AACrE,UAAI,OACFA,cAAa,SACT,OAAO,oBACPA,YAAW,SAAS,QAAQ,OAAO,CAAC,SAAS,KAAK,WAAW,UAAU,EAAE;AAC/E,YAAM,SAA6B,CAAC;AACpC,iBAAW,QAAQ,MAAM,KAAK,KAAwB,GAAG;AACvD,oBAAY;AACZ,cAAM,OAAO;AAAA,UACX,IAAI,OAAO,QAAQ;AAAA,UACnB;AAAA,UACA,MAAM,KAAK;AAAA,UACX,MAAM,KAAK;AAAA,UACX,MAAM,KAAK;AAAA,UACX,UAAU;AAAA,QACZ;AACA,cAAM,SAA0C,CAAC,YAAYF,SAAQ,IAAI,IACrE,SACAC,cAAa,UAAa,KAAK,OAAOA,YACpC,SACA,QAAQ,IACN,UACA;AACR,YAAI,WAAW,QAAW;AACxB,iBAAO,KAAK,EAAE,GAAG,MAAM,QAAQ,YAAY,OAAO,SAAS,QAAQ,IAAI,EAAE,CAAC;AAC1E;AAAA,QACF;AACA,gBAAQ;AACR,cAAM,aACJ,KAAK,KAAK,WAAW,QAAQ,KAAK,OAAO,IAAI,oBAAoB,aAC7D,IAAI,gBAAgB,IAAI,IACxB;AACN,eAAO,KAAK,EAAE,GAAG,MAAM,QAAQ,aAAa,GAAI,aAAa,EAAE,WAAW,IAAI,CAAC,EAAG,CAAC;AAAA,MACrF;AACA,UAAI,OAAO,WAAW,EAAG;AACzB,eAAS,CAAC,YAAY,CAAC,GAAG,SAAS,GAAG,MAAM,CAAC;AAC7C,iBAAW,QAAQ,QAAQ;AACzB,YAAI,KAAK,WAAW,YAAa,OAAM,IAAI;AAAA,MAC7C;AAAA,IACF;AAAA,IACA,CAAC,KAAK;AAAA,EACR;AAEA,QAAM,UAAUH,aAAY,CAAC,SAAuC;AAClE,QAAI,SAAS,OAAW;AACxB,gBAAY,QAAQ,IAAI,KAAK,EAAE,GAAG,MAAM;AACxC,gBAAY,QAAQ,OAAO,KAAK,EAAE;AAClC,QAAI,KAAK,eAAe,UAAa,OAAO,IAAI,oBAAoB,YAAY;AAC9E,UAAI,gBAAgB,KAAK,UAAU;AAAA,IACrC;AAAA,EACF,GAAG,CAAC,CAAC;AAEL,QAAM,SAASA;AAAA,IACb,CAAC,OAAe;AACd,cAAQ,SAAS,QAAQ,KAAK,CAAC,SAAS,KAAK,OAAO,EAAE,CAAC;AACvD,eAAS,CAAC,YAAY,QAAQ,OAAO,CAAC,SAAS,KAAK,OAAO,EAAE,CAAC;AAAA,IAChE;AAAA,IACA,CAAC,OAAO;AAAA,EACV;AAEA,QAAM,QAAQA,aAAY,MAAM;AAC9B,eAAW,QAAQ,SAAS,QAAS,SAAQ,IAAI;AACjD,aAAS,CAAC,CAAC;AAAA,EACb,GAAG,CAAC,OAAO,CAAC;AAEZ,QAAM,QAAQA;AAAA,IACZ,CAAC,OAAe;AACd,YAAM,OAAO,SAAS,QAAQ,KAAK,CAAC,cAAc,UAAU,OAAO,EAAE;AACrE,UAAI,SAAS,UAAa,KAAK,WAAW,QAAS;AACnD,YAAM,EAAE,OAAO,WAAW,GAAG,KAAK,IAAI;AACtC,YAAM,QAA0B,EAAE,GAAG,MAAM,QAAQ,aAAa,UAAU,EAAE;AAC5E,eAAS,CAAC,YAAY,QAAQ,IAAI,CAAC,cAAe,UAAU,OAAO,KAAK,QAAQ,SAAU,CAAC;AAC3F,YAAM,KAAK;AAAA,IACb;AAAA,IACA,CAAC,KAAK;AAAA,EACR;AAGA,EAAAK;AAAA,IACE,MAAM,MAAM;AACV,iBAAW,QAAQ,SAAS,QAAS,SAAQ,IAAI;AAAA,IACnD;AAAA,IACA,CAAC,OAAO;AAAA,EACV;AAEA,QAAM,UAAUL;AAAA,IACd,CAAC,UAA8B;AAC7B,YAAM,QAAQ,mBAAmB,MAAM,aAAa;AACpD,UAAI,MAAM,WAAW,EAAG;AACxB,YAAM,eAAe;AACrB,UAAI,KAAK;AAAA,IACX;AAAA,IACA,CAAC,GAAG;AAAA,EACN;AAEA,QAAM,gBAAgBM;AAAA,IACpB,OAAO;AAAA,MACL,aAAa,CAAC,UAAyB;AACrC,YAAI,CAAC,aAAa,MAAM,YAAY,EAAG;AACvC,cAAM,eAAe;AACrB,qBAAa,CAAC,UAAU,QAAQ,CAAC;AAAA,MACnC;AAAA,MACA,YAAY,CAAC,UAAyB;AAEpC,YAAI,aAAa,MAAM,YAAY,EAAG,OAAM,eAAe;AAAA,MAC7D;AAAA,MACA,aAAa,CAAC,UAAyB;AACrC,YAAI,CAAC,aAAa,MAAM,YAAY,EAAG;AACvC,qBAAa,CAAC,UAAU,KAAK,IAAI,GAAG,QAAQ,CAAC,CAAC;AAAA,MAChD;AAAA,MACA,QAAQ,CAAC,UAAyB;AAChC,YAAI,CAAC,aAAa,MAAM,YAAY,EAAG;AACvC,cAAM,eAAe;AACrB,qBAAa,CAAC;AACd,YAAI,MAAM,cAAc,KAAK;AAAA,MAC/B;AAAA,IACF;AAAA,IACA,CAAC,GAAG;AAAA,EACN;AAEA,QAAM,aAAaA;AAAA,IACjB,OAAO;AAAA,MACL,MAAM;AAAA,MACN,QAAQ,OAAO,WAAW,WAAW,SAAS,QAAQ,KAAK,GAAG;AAAA,MAC9D,UAAU,aAAa,UAAa,WAAW;AAAA,MAC/C,UAAU,CAAC,UAA+C;AACxD,cAAM,QAAQ,MAAM;AACpB,YAAI,MAAM,KAAK;AAEf,cAAM,QAAQ;AAAA,MAChB;AAAA,IACF;AAAA,IACA,CAAC,QAAQ,UAAU,GAAG;AAAA,EACxB;AAEA,SAAOA,SAAQ,MAAM;AACnB,UAAM,QAAQ,MAAM;AAAA,MAClB,CAAC,SACC,KAAK,WAAW,WAAW,KAAK,eAAe;AAAA,IACnD;AACA,WAAO;AAAA,MACL;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA,aAAa,MAAM,KAAK,CAAC,SAAS,KAAK,WAAW,WAAW;AAAA,MAC7D,MAAM,MAAM,IAAI,CAAC,UAAU,EAAE,SAAS,KAAK,WAAW,QAAQ,EAAE;AAAA,MAChE;AAAA,MACA;AAAA,MACA,YAAY,YAAY;AAAA,MACxB;AAAA,IACF;AAAA,EACF,GAAG,CAAC,OAAO,KAAK,QAAQ,OAAO,OAAO,YAAY,eAAe,WAAW,OAAO,CAAC;AACtF;;;ASnQA,SAAS,QAAgB;AACvB,SAAO,WAAW,OAAO,WAAW;AACtC;AAEA,SAASC,UAAS,OAAkD;AAClE,SAAO,OAAO,UAAU,YAAY,UAAU,QAAQ,CAAC,MAAM,QAAQ,KAAK;AAC5E;AAEA,eAAe,eAAe,UAAoC;AAChE,MAAI;AACF,UAAM,OAAQ,MAAM,SAAS,KAAK;AAClC,QAAI,OAAO,KAAK,YAAY,YAAY,KAAK,QAAQ,SAAS,EAAG,QAAO,IAAI,MAAM,KAAK,OAAO;AAAA,EAChG,QAAQ;AAAA,EAER;AACA,SAAO,IAAI,MAAM,kCAAkC,SAAS,MAAM,IAAI;AACxE;AAEA,SAAS,sBAAsB,MAAwC;AACrE,QAAM,MAA+B,CAAC;AACtC,aAAW,OAAO,CAAC,eAAe,SAAS,SAAS,WAAW,gBAAgB,GAAG;AAChF,QAAI,KAAK,GAAG,MAAM,UAAa,KAAK,GAAG,MAAM,KAAM,KAAI,GAAG,IAAI,KAAK,GAAG;AAAA,EACxE;AAEA,MAAI,KAAK,eAAe,KAAM,KAAI,aAAa;AAC/C,SAAO,OAAO,KAAK,GAAG,EAAE,SAAS,IAAI,MAAM;AAC7C;AAMA,IAAM,iBAAiB;AAEvB,SAAS,YAAY,aAA2E;AAC9F,QAAM,QAAQ,aAAa,MAAM,GAAG,EAAE,CAAC,GAAG,YAAY;AACtD,SAAO,UAAU,WAAW,UAAU,WAAW,UAAU,UAAU,QAAQ;AAC/E;AAGA,SAAS,eACP,MACA,SAC4B;AAC5B,QAAM,cAAc,MAAM,QAAQ,KAAK,WAAW,IAAI,KAAK,cAAc,CAAC;AAC1E,QAAM,QAA2B,CAAC;AAClC,aAAW,cAAc,aAAa;AACpC,QAAI,CAACA,UAAS,UAAU,KAAK,OAAO,WAAW,YAAY,SAAU;AACrE,UAAM,cACJ,OAAO,WAAW,gBAAgB,WAAW,WAAW,cAAc;AACxE,UAAM,KAAK;AAAA,MACT,MAAM,YAAY,WAAW;AAAA,MAC7B,QAAQ;AAAA,QACN,MAAM;AAAA,QACN,OAAO,WAAW;AAAA,QAClB,UAAU;AAAA,QACV,GAAI,gBAAgB,SAAY,EAAE,UAAU,YAAY,IAAI,CAAC;AAAA,MAC/D;AAAA,IACF,CAAC;AAAA,EACH;AACA,MAAI,MAAM,WAAW,EAAG,QAAO;AAC/B,SAAO,CAAC,GAAI,QAAQ,SAAS,IAAI,CAAC,EAAE,MAAM,QAAiB,MAAM,QAAQ,CAAC,IAAI,CAAC,GAAI,GAAG,KAAK;AAC7F;AAGA,eAAsB,eACpB,SACA,SAC6B;AAC7B,QAAM,OAAO,QAAQ;AACrB,QAAM,WAAW,OAAO,KAAK,aAAa,WAAW,KAAK,WAAW,MAAM;AAC3E,QAAM,UAAU,OAAO,KAAK,YAAY,WAAW,KAAK,UAAU;AAClE,QAAM,aAAa,QAAQ,kBAAkB,uBAAuB,IAAI;AACxE,QAAM,QAAQ;AAAA,IACZ;AAAA,IACA,OAAO,MAAM;AAAA,IACb,iBAAiB;AAAA,IACjB,UAAU;AAAA,MACR;AAAA,QACE,IAAI,MAAM;AAAA,QACV,MAAM;AAAA,QACN,SAAS,QAAQ,UAAU,IAAI,KAAK,eAAe,MAAM,OAAO;AAAA,MAClE;AAAA,IACF;AAAA,IACA,GAAI,cAAc,SAAY,EAAE,gBAAgB,UAAU,IAAI,CAAC;AAAA,EACjE;AACA,QAAM,UAAU,QAAQ,SAAS,WAAW,MAAM,KAAK,UAAU;AACjE,QAAM,WAAW,MAAM,QAAQ,QAAQ,KAAK;AAAA,IAC1C,QAAQ;AAAA,IACR,aAAa;AAAA,IACb,SAAS;AAAA,MACP,gBAAgB;AAAA,MAChB,QAAQ;AAAA,MACR,GAAG,QAAQ;AAAA,MACX,GAAG,QAAQ;AAAA,IACb;AAAA,IACA,MAAM,KAAK,UAAU,KAAK;AAAA,IAC1B,GAAI,QAAQ,WAAW,SAAY,EAAE,QAAQ,QAAQ,OAAO,IAAI,CAAC;AAAA,EACnE,CAAC;AACD,MAAI,CAAC,SAAS,MAAM,SAAS,SAAS,MAAM;AAC1C,UAAM,OAAO,QAAQ,WAAW,gBAAgB,QAAQ;AAAA,EAC1D;AACA,QAAM,QAAQ,SAAS,QAAQ,IAAI,gBAAgB,KAAK;AACxD,SAAO;AAAA,IACL,MAAM,kBAAkB,SAAS,MAAM,EAAE,SAAS,CAAC;AAAA,IACnD;AAAA,IACA,GAAI,UAAU,SAAY,EAAE,MAAM,IAAI,CAAC;AAAA,EACzC;AACF;AAkBO,SAAS,kBACd,QACA,KAC4B;AAC5B,QAAM,UAAU,IAAI,YAAY;AAChC,QAAM,UAAU,IAAI,YAAY;AAChC,QAAM,WAAW,eAAe,IAAI,QAAQ;AAC5C,QAAM,SAAS,OAAO,UAAU;AAChC,MAAI,SAAS;AACb,SAAO,IAAI,eAA2B;AAAA,IACpC,MAAM,KAAK,YAAY;AACrB,iBAAS;AACP,cAAM,EAAE,OAAO,KAAK,IAAI,MAAM,OAAO,KAAK;AAC1C,YAAI,MAAM;AAGR,gBAAM,OAAO,SAAS,MAAM;AAC5B,cAAI,KAAK,SAAS,EAAG,YAAW,QAAQ,QAAQ,OAAO,IAAI,CAAC;AAC5D,qBAAW,MAAM;AACjB;AAAA,QACF;AACA,kBAAU,QAAQ,OAAO,OAAO,EAAE,QAAQ,KAAK,CAAC,EAAE,QAAQ,UAAU,IAAI;AACxE,YAAI,MAAM;AACV,YAAI,YAAY,OAAO,QAAQ,MAAM;AACrC,eAAO,cAAc,IAAI;AACvB,gBAAM,QAAQ,OAAO,MAAM,GAAG,SAAS;AACvC,mBAAS,OAAO,MAAM,YAAY,CAAC;AACnC,sBAAY,OAAO,QAAQ,MAAM;AACjC,gBAAM,QAAQ,MAAM,MAAM,IAAI;AAC9B,gBAAM,SAAS,MAAM,KAAK,CAAC,SAAS,KAAK,WAAW,KAAK,CAAC;AAC1D,gBAAM,KAAK,WAAW,SAAY,SAAY,OAAO,OAAO,MAAM,CAAC,EAAE,KAAK,CAAC;AAC3E,gBAAM,OAAO,MACV,OAAO,CAAC,SAAS,KAAK,WAAW,OAAO,CAAC,EACzC,IAAI,CAAC,SAAS,KAAK,MAAM,CAAC,EAAE,UAAU,CAAC,EACvC,KAAK,IAAI;AACZ,cAAI,KAAK,WAAW,EAAG;AACvB,cAAI;AACJ,cAAI;AACF,oBAAQ,KAAK,MAAM,IAAI;AAAA,UACzB,QAAQ;AACN;AAAA,UACF;AACA,cAAIA,UAAS,KAAK,KAAK,OAAO,MAAM,SAAS,UAAU;AACrD,mBAAO,SAAS;AAAA,cACd;AAAA,cACA,OAAO,UAAa,OAAO,cAAc,EAAE,KAAK,KAAK,IAAI,KAAK;AAAA,YAChE;AAAA,UACF;AACA,cAAI,SAAS,OAAQ;AAAA,QACvB;AACA,YAAI,IAAI,SAAS,EAAG,YAAW,QAAQ,QAAQ,OAAO,GAAG,CAAC;AAC1D,YAAI,SAAS,QAAQ;AACnB,eAAK,OAAO,OAAO,EAAE,MAAM,MAAM,MAAS;AAC1C,qBAAW,MAAM;AACjB;AAAA,QACF;AACA,YAAI,IAAI,SAAS,EAAG;AAAA,MACtB;AAAA,IACF;AAAA,IACA,OAAO,QAAQ;AACb,aAAO,OAAO,OAAO,MAAM,EAAE,MAAM,MAAM,MAAS;AAAA,IACpD;AAAA,EACF,CAAC;AACH;AAEA,SAAS,eAAe,UAA4B;AAClD,QAAM,aAAa,oBAAI,IAAwE;AAC/F,MAAI,WAAW;AACf,QAAM,QAAQ,oBAAI,IAGhB;AAKF,MAAI;AACJ,QAAM,cAAc,CAAC,gBACnB,SAAS,KAAK,UAAU,WAAW,CAAC;AAAA;AAAA;AACtC,QAAM,YAAY,MAAc;AAC9B,QAAI,gBAAgB,OAAW,QAAO;AACtC,UAAM,OAAO;AACb,kBAAc;AACd,WAAO,YAAY,IAAI;AAAA,EACzB;AAOA,MAAI;AACJ,MAAI;AACJ,QAAM,SAAS,MAAc;AAC3B,QAAI,YAAY,UAAa,YAAY,QAAS,QAAO;AACzD,cAAU;AACV,WAAO,GAAG,UAAU,CAAC,OAAO,OAAO;AAAA;AAAA;AAAA,EACrC;AAEA,QAAM,QAAQ,oBAAI,IAAY;AAE9B,MAAI;AACJ,QAAM,QAAkB;AAAA,IACtB,QAAQ;AAAA,IACR,QAAQ;AACN,aAAO,MAAM,SAAS,KAAK,GAAG,UAAU,CAAC,GAAG,OAAO,CAAC;AAAA,IACtD;AAAA,IACA,KAAK,OAAO,IAAI;AACd,UAAI,MAAM,OAAQ,QAAO;AACzB,UAAI,MAAM;AACV,UAAI,OAAO,QAAW;AACpB,YAAI,YAAY,UAAa,KAAK,QAAS,QAAO,OAAO;AACzD,kBAAU;AAAA,MACZ;AACA,YAAM,QAAQ,CAAC,gBAA4D;AACzE,eAAO,YAAY,WAAW;AAAA,MAChC;AACA,UACE,MAAM,SAAS,YACf,MAAM,SAAS,sBACf,gBAAgB,UAChBA,UAAS,MAAM,KAAK,GACpB;AACA,cAAM,QAAQ,MAAM;AACpB,YAAIA,UAAS,MAAM,KAAK,EAAG,aAAY,QAAQ,MAAM;AACrD,YAAI,OAAO,MAAM,YAAY,YAAY,MAAM,YAAY,MAAM;AAC/D,sBAAY,UAAU,MAAM;AAAA,QAC9B;AACA,YAAI,OAAO,MAAM,gBAAgB,SAAU,aAAY,cAAc,MAAM;AAC3E,eAAO,UAAU;AACjB,eAAO;AAAA,MACT;AACA,aAAO,UAAU;AACjB,YAAM,OAAO,CAAC,OAAgB,WAAoB;AAChD,YAAI,SAAU;AACd,mBAAW;AACX,eAAO;AAAA,QAAsB,KAAK,UAAU;AAAA,UAC1C,OAAO,OAAO,UAAU,WAAW,QAAQ;AAAA,UAC3C,UAAU,OAAO,WAAW,WAAW,SAAS;AAAA,QAClD,CAAC,CAAC;AAAA;AAAA;AAAA,MACJ;AACA,cAAQ,MAAM,MAAM;AAAA,QAClB,KAAK;AAGH,yBAAe,EAAE,OAAO,MAAM,OAAO,UAAU,MAAM,SAAS;AAC9D,iBAAO;AAAA,QACT,KAAK,UAAU;AACb,gBAAM,QAAQ,MAAM;AACpB,cAAI,MAAM,SAAS,eAAeA,UAAS,KAAK,GAAG;AACjD,iBAAK,MAAM,OAAO,cAAc,YAAY,MAAM,QAAQ;AAC1D,2BAAe;AACf,mBAAO;AAAA,UACT;AACA,qBAAW;AACX,cAAI,CAACA,UAAS,KAAK,EAAG,QAAO;AAC7B,cAAI,MAAM,SAAS,WAAY,OAAM,EAAE,MAAM,MAAM,GAAG,MAAM,CAAC;AAAA,mBACpD,MAAM,SAAS,iBAAiB,OAAO,MAAM,UAAU,UAAU;AACxE,kBAAM,EAAE,MAAM,SAAS,OAAO,MAAM,MAAM,CAAC;AAAA,UAC7C,WAAW,MAAM,SAAS,cAAe,OAAM,EAAE,MAAM,SAAS,GAAG,MAAM,CAAC;AAAA,mBACjE,MAAM,SAAS,4BAA4B;AAClD,gBAAI,OAAO,MAAM,OAAO,SAAU,OAAM,IAAI,MAAM,EAAE;AACpD,kBAAM,EAAE,GAAG,OAAO,MAAM,qBAAqB,CAAC;AAAA,UAChD,WAAW,MAAM,SAAS,0BAA0B;AAClD,kBAAM,EAAE,GAAG,OAAO,MAAM,mBAAmB,CAAC;AAAA,UAC9C,WACE,MAAM,SAAS,uBACf,OAAO,MAAM,OAAO,YACpBA,UAAS,MAAM,OAAO,KACtB,MAAM,QAAQ,MAAM,QAAQ,SAAS,GACrC;AAEA,kBAAM,IAAI,MAAM,EAAE;AAClB,gBAAI,OAAO,MAAM,QAAQ,OAAO,SAAU,OAAM,IAAI,MAAM,QAAQ,EAAE;AACpE,kBAAM;AAAA,cACJ,MAAM;AAAA,cACN,IAAI,MAAM;AAAA,cACV,SAAS,MAAM;AAAA,YACjB,CAAC;AAAA,UACH,WAAW,MAAM,SAAS,kCAAkC;AAC1D,uBAAW;AAAA,cACT,UAAU,MAAM;AAAA,cAChB,kBAAkB,MAAM;AAAA,cACxB,MAAM;AAAA,YACR;AAAA,UACF;AACA,iBAAO;AAAA,QACT;AAAA,QACA;AACE,qBAAW;AAAA,MACf;AACA,cAAQ,MAAM,MAAM;AAAA,QAClB,KAAK;AAAA,QACL,KAAK;AACH,cAAI,aAAa,UAAa,OAAO,MAAM,UAAU,UAAU;AAC7D,qBAAS,QAAQ,MAAM;AAAA,UACzB;AACA,cAAI,OAAO,MAAM,UAAU,YAAY,MAAM,MAAM,SAAS,GAAG;AAC7D,kBAAM,EAAE,MAAM,QAAQ,MAAM,MAAM,MAAM,CAAC;AAAA,UAC3C;AACA;AAAA,QACF,KAAK;AAAA,QACL,KAAK;AACH,cAAI,OAAO,MAAM,UAAU,YAAY,MAAM,MAAM,SAAS,GAAG;AAC7D,kBAAM,EAAE,MAAM,aAAa,MAAM,MAAM,MAAM,CAAC;AAAA,UAChD;AACA;AAAA,QACF,KAAK;AACH,gBAAM,EAAE,MAAM,aAAa,CAAC;AAC5B;AAAA,QACF,KAAK;AACH,wBAAc,EAAE,MAAM,cAAc;AACpC;AAAA,QACF,KAAK;AAAA,QACL,KAAK,mBAAmB;AACtB,gBAAMC,MAAK,OAAO,MAAM,cAAc,EAAE;AACxC,cAAIA,QAAO,GAAI;AACf,cAAI,CAAC,MAAM,IAAIA,GAAE,GAAG;AAClB,kBAAM,OAAO,OAAO,MAAM,iBAAiB,WAAW,MAAM,eAAe;AAC3E,kBAAM,WAAWD,UAAS,MAAM,QAAQ,IAAI,MAAM,WAAW,CAAC;AAG9D,kBAAME,YAAW,SAAS,gBAAgB,MAAM,WAAW,WAAW;AACtE,kBAAM,WACJ,OAAO,SAAS,gBAAgB,MAAM,WAClC,SAAS,gBAAgB,IACzB;AACN,kBAAM,IAAID,KAAI;AAAA,cACZ;AAAA,cACA,MAAM;AAAA,cACN,UAAAC;AAAA,cACA,GAAI,aAAa,SAAY,EAAE,SAAS,IAAI,CAAC;AAAA,YAC/C,CAAC;AACD,kBAAM;AAAA,cACJ,MAAM;AAAA,cACN,IAAAD;AAAA,cACA;AAAA,cACA,UAAAC;AAAA,cACA,GAAI,aAAa,SAAY,EAAE,SAAS,IAAI,CAAC;AAAA,YAC/C,CAAC;AAAA,UACH;AACA,cAAI,MAAM,SAAS,qBAAqB,OAAO,MAAM,UAAU,UAAU;AACvE,YAAC,MAAM,IAAID,GAAE,EAAuB,QAAQ,MAAM;AAClD,kBAAM,EAAE,MAAM,oBAAoB,IAAAA,KAAI,OAAO,MAAM,MAAM,CAAC;AAAA,UAC5D;AACA;AAAA,QACF;AAAA,QACA,KAAK,kBAAkB;AACrB,gBAAM,OAAO,MAAM,IAAI,OAAO,MAAM,UAAU,CAAC;AAC/C,cAAI,SAAS,UAAa,OAAO,MAAM,UAAU,SAAU;AAC3D,eAAK,QAAQ,MAAM;AACnB,gBAAM,EAAE,MAAM,oBAAoB,IAAI,OAAO,MAAM,UAAU,GAAG,OAAO,MAAM,MAAM,CAAC;AACpF;AAAA,QACF;AAAA,QACA,KAAK,iBAAiB;AACpB,gBAAMA,MAAK,OAAO,MAAM,UAAU;AAClC,gBAAM,OAAO,MAAM,IAAIA,GAAE;AACzB,cAAI,SAAS,OAAW;AACxB,gBAAM;AAAA,YACJ,MAAM;AAAA,YACN,IAAAA;AAAA,YACA,MAAM,KAAK;AAAA,YACX,OAAO,UAAU,KAAK,MAAM,CAAC,CAAC;AAAA,YAC9B,UAAU,KAAK;AAAA,YACf,GAAI,KAAK,aAAa,SAAY,EAAE,UAAU,KAAK,SAAS,IAAI,CAAC;AAAA,UACnE,CAAC;AACD;AAAA,QACF;AAAA,QACA,KAAK,oBAAoB;AACvB,gBAAMA,MAAK,OAAO,MAAM,UAAU;AAClC,gBAAM,UAAU,YAAY,MAAM,OAAO;AACzC,gBAAM,UAAUD,UAAS,MAAM,QAAQ,IAAI,MAAM,SAAS,eAAe,IAAI;AAC7E,cAAI,YAAY,QAAS,OAAM,EAAE,MAAM,qBAAqB,IAAAC,KAAI,OAAO,QAAQ,CAAC;AAAA,mBACvE,YAAY,SAAU,OAAM,EAAE,MAAM,sBAAsB,IAAAA,KAAI,QAAQ,QAAQ,CAAC;AAAA,cACnF,OAAM,EAAE,MAAM,eAAe,IAAAA,KAAI,QAAQ,UAAU,SAAS,OAAO,EAAE,CAAC;AAC3E;AAAA,QACF;AAAA,QACA,KAAK;AAAA,QACL,KAAK,kBAAkB;AACrB,gBAAM,YAAY,OAAO,MAAM,cAAc,WAAW,MAAM,YAAY;AAC1E,cAAI,cAAc,GAAI;AACtB,gBAAM,QAAQ,WAAW,IAAI,SAAS;AACtC,gBAAM,eACJ,OAAO,MAAM,iBAAiB,WAC1B,MAAM,eACL,OAAO,gBAAgB;AAC9B,cAAI;AACJ,cAAI,MAAM,SAAS,qBAAqB;AAEtC,gBAAI,UAAU,UAAa,MAAM,YAAY,MAAO;AACpD,sBAAUD,UAAS,MAAM,OAAO,IAAI,MAAM,UAAU,CAAC;AAAA,UACvD,OAAO;AAEL,gBAAI,UAAU,UAAa,CAAC,MAAM,QAAQ,MAAM,KAAK,EAAG;AACxD,sBAAU,WAAW,MAAM,SAAS,MAAM,KAAK;AAC/C,gBAAI,YAAY,OAAW;AAAA,UAC7B;AACA,qBAAW,IAAI,WAAW,EAAE,cAAc,QAAQ,CAAC;AACnD,gBAAM;AAAA,YACJ,MAAM;AAAA,YACN,IAAI,YAAY,SAAS;AAAA,YACzB,WAAW;AAAA,YACX,OAAO,EAAE,cAAc,QAAQ;AAAA,UACjC,CAAC;AACD;AAAA,QACF;AAAA,QACA,KAAK;AACH,gBAAM,SAAS;AACf,iBAAO;AAAA,QAAuB,KAAK,UAAU;AAAA,YAC3C,MAAM,OAAO,MAAM,SAAS,WAAW,MAAM,OAAO;AAAA,YACpD,SAAS,OAAO,MAAM,YAAY,WAAW,MAAM,UAAU;AAAA,UAC/D,CAAC,CAAC;AAAA;AAAA;AACF;AAAA,QACF,KAAK,gBAAgB;AACnB,gBAAM,UAAUA,UAAS,MAAM,OAAO,IAAI,MAAM,UAAU;AAC1D,cAAI,aAAa,QAAW;AAE1B,kBAAM,EAAE,MAAM,qBAAqB,GAAG,SAAS,CAAC;AAChD,uBAAW;AAAA,UACb;AACA,cAAI,SAAS,SAAS,YAAa,OAAM,EAAE,MAAM,YAAY,CAAC;AAC9D,cAAI,SAAS,SAAS,eAAe,MAAM,QAAQ,QAAQ,UAAU,GAAG;AACtE,kBAAM,SAAS,QAAQ,WAAW,OAAO,CAAC,cAAc,CAAC,QAAQ,WAAW,KAAK,CAAC;AAClF,gBAAI,OAAO,WAAW,GAAG;AAGvB,qBAAO,OAAO;AACd,oBAAM,SAAS;AACf;AAAA,YACF;AACA,kBAAM;AAAA,cACJ,MAAM;AAAA,cACN,IAAI,mBAAmB,OAAO,MAAM,SAAS,EAAE,CAAC;AAAA,cAChD,WAAW;AAAA,cACX,OAAO,EAAE,YAAY,OAAO;AAAA,YAC9B,CAAC;AAAA,UACH;AACA,iBAAO,OAAO;AACd,gBAAM,SAAS;AACf,iBAAO;AACP;AAAA,QACF;AAAA,QACA;AAGE;AAAA,MACJ;AACA,aAAO;AAEP,eAAS,aAAa;AACpB,YAAI,iBAAiB,QAAW;AAC9B,eAAK,aAAa,OAAO,aAAa,QAAQ;AAC9C,yBAAe;AAAA,QACjB;AAAA,MACF;AAAA,IACF;AAAA,EACF;AACA,MAAI;AACJ,SAAO;AACT;AAGA,SAAS,QAAQ,WAAoB,OAAqC;AACxE,MAAI,CAACA,UAAS,SAAS,EAAG,QAAO;AACjC,MAAI,OAAO,UAAU,eAAe,YAAY,MAAM,IAAI,UAAU,UAAU,EAAG,QAAO;AACxF,QAAM,WAAWA,UAAS,UAAU,QAAQ,IAAI,UAAU,WAAW;AACrE,QAAM,UAAUA,UAAS,WAAW,eAAe,CAAC,IAAI,SAAS,eAAe,IAAI;AACpF,SAAO,OAAO,SAAS,OAAO,YAAY,MAAM,IAAI,QAAQ,EAAE;AAChE;AAEA,SAAS,UAAU,MAAcG,WAA4B;AAC3D,MAAI,KAAK,KAAK,EAAE,WAAW,EAAG,QAAOA;AACrC,MAAI;AACF,WAAO,KAAK,MAAM,IAAI;AAAA,EACxB,QAAQ;AACN,WAAOA;AAAA,EACT;AACF;AAGA,SAAS,YAAY,SAA0B;AAC7C,MAAI,OAAO,YAAY,SAAU,QAAO;AACxC,MAAI,CAAC,MAAM,QAAQ,OAAO,EAAG,QAAO;AACpC,SAAO,QACJ,OAAO,CAAC,SAASH,UAAS,IAAI,KAAK,KAAK,SAAS,UAAU,OAAO,KAAK,SAAS,QAAQ,EACxF,IAAI,CAAC,SAAU,KAA0B,IAAI,EAC7C,KAAK,EAAE;AACZ;AAMA,SAAS,WACP,QACA,OACqC;AACrC,QAAM,MAAM,gBAAgB,MAAM;AAClC,aAAW,aAAa,OAAO;AAC7B,QAAI,CAACA,UAAS,SAAS,KAAK,OAAO,UAAU,SAAS,SAAU,QAAO;AACvE,UAAM,SAAS,UAAU,KACtB,MAAM,GAAG,EACT,MAAM,CAAC,EACP,IAAI,CAAC,UAAU,MAAM,QAAQ,OAAO,GAAG,EAAE,QAAQ,OAAO,GAAG,CAAC;AAC/D,UAAM,MAAM,OAAO,IAAI;AACvB,QAAI,QAAQ,OAAW,QAAO;AAC9B,QAAI,SAAkB;AACtB,eAAW,SAAS,QAAQ;AAC1B,eAAS,MAAM,QAAQ,MAAM,IACzB,OAAO,OAAO,KAAK,CAAC,IACpBA,UAAS,MAAM,IACb,OAAO,KAAK,IACZ;AACN,UAAI,WAAW,OAAW,QAAO;AAAA,IACnC;AACA,QAAI,MAAM,QAAQ,MAAM,GAAG;AACzB,YAAM,QAAQ,QAAQ,MAAM,OAAO,SAAS,OAAO,GAAG;AACtD,UAAI,CAAC,OAAO,UAAU,KAAK,KAAK,QAAQ,KAAK,QAAQ,OAAO,OAAQ,QAAO;AAC3E,UAAI,UAAU,OAAO,MAAO,QAAO,OAAO,OAAO,GAAG,UAAU,KAAK;AAAA,eAC1D,UAAU,OAAO,aAAa,QAAQ,OAAO,OAAQ,QAAO,KAAK,IAAI,UAAU;AAAA,eAC/E,UAAU,OAAO,YAAY,QAAQ,OAAO,OAAQ,QAAO,OAAO,OAAO,CAAC;AAAA,eAC1E,UAAU,OAAO,QAAQ;AAChC,YAAI,KAAK,UAAU,OAAO,KAAK,CAAC,MAAM,KAAK,UAAU,UAAU,KAAK,EAAG,QAAO;AAAA,MAChF,MAAO,QAAO;AAAA,IAChB,WAAWA,UAAS,MAAM,GAAG;AAC3B,UAAI,UAAU,OAAO,SAAU,UAAU,OAAO,aAAa,OAAO,QAAS;AAC3E,eAAO,GAAG,IAAI,UAAU;AAAA,MAC1B,WAAW,UAAU,OAAO,YAAY,OAAO,OAAQ,QAAO,OAAO,GAAG;AAAA,eAC/D,UAAU,OAAO,QAAQ;AAChC,YAAI,KAAK,UAAU,OAAO,GAAG,CAAC,MAAM,KAAK,UAAU,UAAU,KAAK,EAAG,QAAO;AAAA,MAC9E,MAAO,QAAO;AAAA,IAChB,MAAO,QAAO;AAAA,EAChB;AACA,SAAO;AACT;;;ACtoBA,SAAS,eAAAI,cAAa,WAAAC,gBAAe;;;ACDrC,SAAS,eAAAC,cAAa,aAAAC,YAAW,UAAAC,SAAQ,YAAAC,iBAAgB;AAalD,SAAS,YACdC,OACA,KACA,SACkB;AAClB,QAAM,CAAC,MAAM,OAAO,IAAID,UAAwB,MAAS;AACzD,QAAM,CAAC,WAAW,YAAY,IAAIA,UAAS,OAAO;AAClD,QAAM,CAAC,OAAO,QAAQ,IAAIA,UAAuB,IAAI;AACrD,QAAM,UAAUD,QAAOE,KAAI;AAC3B,UAAQ,UAAUA;AAClB,QAAM,aAAaF,QAAO,CAAC;AAE3B,QAAM,UAAUF,aAAY,YAA2B;AACrD,UAAM,OAAO,EAAE,WAAW;AAC1B,iBAAa,IAAI;AACjB,QAAI;AACF,YAAM,QAAQ,MAAM,QAAQ,QAAQ;AACpC,UAAI,SAAS,WAAW,QAAS;AACjC,cAAQ,KAAK;AACb,eAAS,IAAI;AAAA,IACf,SAAS,QAAQ;AACf,UAAI,SAAS,WAAW,QAAS;AACjC,eAAS,kBAAkB,QAAQ,SAAS,IAAI,MAAM,OAAO,MAAM,CAAC,CAAC;AAAA,IACvE,UAAE;AACA,UAAI,SAAS,WAAW,QAAS,cAAa,KAAK;AAAA,IACrD;AAAA,EACF,GAAG,CAAC,CAAC;AAGL,EAAAC,WAAU,MAAM;AACd,QAAI,CAAC,QAAS;AACd,SAAK,QAAQ;AAAA,EACf,GAAG,CAAC,SAAS,KAAK,OAAO,CAAC;AAE1B,SAAO,EAAE,MAAM,WAAW,OAAO,QAAQ;AAC3C;;;ADbO,SAAS,UAAU,UAA4B,CAAC,GAAgB;AACrE,QAAM,EAAE,UAAU,KAAK,IAAI;AAC3B,QAAM,UAAU,gBAAgB,QAAQ,OAAO;AAC/C,QAAM,EAAE,MAAM,WAAW,OAAO,QAAQ,IAAI;AAAA,IAC1C,MAAM,qBAAqB,SAAS,YAAY,EAAE;AAAA,IAClD;AAAA,IACA;AAAA,EACF;AACA,QAAM,OAAOI;AAAA,IACX,CAAC,UACE,QAAQ,CAAC,GAAG;AAAA,MAAK,CAAC,UACjB,SAAS,SAAY,MAAM,cAAc,OAAO,MAAM,SAAS;AAAA,IACjE;AAAA,IACF,CAAC,IAAI;AAAA,EACP;AACA,SAAOC,SAAQ,MAAM;AACnB,UAAM,SAAS,QAAQ,CAAC;AACxB,WAAO;AAAA,MACL;AAAA,MACA,cAAc,OAAO,KAAK,CAAC,UAAU,MAAM,cAAc,IAAI,GAAG,QAAQ;AAAA,MACxE,YAAY,CAAC,UAAmB,KAAK,KAAK,GAAG,YAAY,CAAC;AAAA,MAC1D,kBAAkB,CAAC,UAAmB,KAAK,KAAK,GAAG,kBAAkB;AAAA,MACrE;AAAA,MACA;AAAA,MACA;AAAA,IACF;AAAA,EACF,GAAG,CAAC,MAAM,MAAM,WAAW,OAAO,OAAO,CAAC;AAC5C;;;AEzDA,SAAS,WAAAC,gBAAe;AA6CjB,SAAS,UAAU,UAA4B,CAAC,GAAgB;AACrE,QAAM,EAAE,OAAO,UAAU,KAAK,IAAI;AAClC,QAAM,UAAU,gBAAgB,QAAQ,OAAO;AAC/C,QAAM,EAAE,MAAM,WAAW,OAAO,QAAQ,IAAI;AAAA,IAC1C,MAAM,qBAAqB,SAAS,YAAY,EAAE,KAAK;AAAA,IACvD,GAAG,SAAS,EAAE;AAAA,IACd;AAAA,EACF;AACA,SAAOC,SAAQ,MAAM;AACnB,UAAM,YAAY,MAAM,aAAa,CAAC;AACtC,UAAM,SAAS,UAAU;AAAA,MAAQ,CAAC,aAChC,SAAS,OAAO,IAAI,CAAC,WAAW;AAAA,QAC9B,GAAG;AAAA,QACH,YAAY,SAAS;AAAA,QACrB,eAAe,SAAS;AAAA,MAC1B,EAAE;AAAA,IACJ;AACA,UAAM,OAAO,IAAI,IAAI,OAAO,IAAI,CAAC,UAAU,CAAC,MAAM,IAAI,KAAK,CAAC,CAAC;AAC7D,WAAO;AAAA,MACL;AAAA,MACA;AAAA,MACA,cAAc,MAAM,WAAW;AAAA,MAC/B,QAAQ,MAAM,UAAU;AAAA,MACxB,MAAM,CAAC,OAAQ,MAAM,OAAO,SAAY,KAAK,IAAI,EAAE;AAAA,MACnD;AAAA,MACA;AAAA,MACA;AAAA,IACF;AAAA,EACF,GAAG,CAAC,MAAM,WAAW,OAAO,OAAO,CAAC;AACtC;;;AC/EA;AAAA,EAKE;AAAA,OACK;AACP,SAAS,aAAAC,YAAW,WAAAC,gBAAe;;;ACOnC,IAAM,YAAY,oBAAI,QAAqC;AAGpD,SAAS,cAAc,SAAuB,OAA2B;AAC9E,aAAW,YAAY,UAAU,IAAI,OAAO,KAAK,CAAC,GAAG;AACnD,aAAS,KAAK;AAAA,EAChB;AACF;AAGO,SAAS,eAAe,SAAuB,UAAgC;AACpF,MAAI,MAAM,UAAU,IAAI,OAAO;AAC/B,MAAI,QAAQ,QAAW;AACrB,UAAM,oBAAI,IAAI;AACd,cAAU,IAAI,SAAS,GAAG;AAAA,EAC5B;AACA,MAAI,IAAI,QAAQ;AAChB,SAAO,MAAM;AACX,QAAI,OAAO,QAAQ;AAAA,EACrB;AACF;;;ADYO,SAAS,SAAS,UAA2B,CAAC,GAAe;AAClE,QAAM,EAAE,UAAU,MAAM,OAAO,IAAI;AACnC,QAAM,UAAU,gBAAgB,QAAQ,OAAO;AAC/C,QAAM,EAAE,MAAM,WAAW,OAAO,QAAQ,IAAI;AAAA,IAC1C,MAAM,qBAAqB,SAAS,UAAU,EAAE;AAAA,IAChD;AAAA,IACA;AAAA,EACF;AAEA,EAAAC,WAAU,MAAM;AACd,QAAI,CAAC,QAAS;AACd,WAAO,eAAe,SAAS,CAAC,UAAU;AACxC,UAAI,MAAM,SAAS,UAAW,MAAK,QAAQ;AAAA,IAC7C,CAAC;AAAA,EACH,GAAG,CAAC,SAAS,SAAS,OAAO,CAAC;AAE9B,EAAAA,WAAU,MAAM;AACd,QAAI,CAAC,WAAW,WAAW,UAAa,UAAU,EAAG;AACrD,UAAM,QAAQ,YAAY,MAAM,KAAK,QAAQ,GAAG,MAAM;AACtD,WAAO,MAAM,cAAc,KAAK;AAAA,EAClC,GAAG,CAAC,SAAS,QAAQ,OAAO,CAAC;AAE7B,SAAOC,SAAQ,MAAM;AACnB,UAAM,UAAU,MAAM,WAAW,CAAC;AAClC,WAAO;AAAA,MACL,QAAQ;AAAA,MACR;AAAA,MACA,KAAK,QAAQ,KAAK,CAACC,YAAWA,QAAO,WAAW,KAAK;AAAA,MACrD,OAAO,QAAQ,KAAK,CAACA,YAAWA,QAAO,WAAW,OAAO;AAAA,MACzD,SAAS,MAAM,WAAW;AAAA,MAC1B,SACE,SAAS,UAAa,KAAK,YAAY,SACnC,OACC,KAAK,WAAW,aAAa,OAAO,KAAK;AAAA,MAChD;AAAA,MACA;AAAA,MACA;AAAA,IACF;AAAA,EACF,GAAG,CAAC,MAAM,WAAW,OAAO,OAAO,CAAC;AACtC;;;AEnFA,SAAS,eAAAC,cAAa,UAAAC,SAAQ,YAAAC,iBAAgB;AAoCvC,SAAS,mBAAmB,UAAqC,CAAC,GAAyB;AAChG,QAAM,UAAU,gBAAgB,QAAQ,OAAO;AAC/C,QAAM,SAASC,QAAO,EAAE,GAAG,SAAS,QAAQ,CAAC;AAC7C,SAAO,UAAU,EAAE,GAAG,SAAS,QAAQ;AACvC,QAAM,CAAC,OAAO,QAAQ,IAAIC,UAAqC,oBAAI,IAAI,CAAC;AACxE,QAAM,CAAC,SAAS,UAAU,IAAIA,UAA8B,oBAAI,IAAI,CAAC;AACrE,QAAM,CAAC,OAAO,QAAQ,IAAIA,UAAuB,IAAI;AACrD,QAAM,WAAWD,QAAO,KAAK;AAC7B,WAAS,UAAU;AAEnB,QAAM,WAAWA,QAAO,oBAAI,IAAoB,CAAC;AAEjD,QAAM,aAAaE;AAAA,IACjB,CAAC,YAA+C;AAC9C,YAAM,OAAO,MAAM,IAAI,QAAQ,EAAE;AACjC,UAAI,SAAS,OAAW,QAAO,KAAK;AACpC,aAAO,WAAW,OAAO,EAAE,YAAY;AAAA,IACzC;AAAA,IACA,CAAC,KAAK;AAAA,EACR;AAEA,QAAM,YAAYA,aAAY,CAAC,YAAuB,QAAQ,IAAI,QAAQ,EAAE,GAAG,CAAC,OAAO,CAAC;AAExF,QAAM,cAAcA,aAAY,OAAO,YAAwC;AAC7E,UAAM,QAAQ,WAAW,OAAO,EAAE;AAClC,QAAI,UAAU,OAAW,QAAO,QAAQ;AACxC,UAAM,QAAQ,SAAS,QAAQ,IAAI,QAAQ,EAAE;AAC7C,QAAI,UAAU,OAAW,QAAO;AAChC,UAAM,EAAE,SAAAC,UAAS,SAAS,IAAI,OAAO;AACrC,UAAM,SAAS,OAAO,aAAa,aAAa,SAAS,IAAI;AAC7D,QAAI,WAAW,QAAW;AACxB,YAAM,IAAI,MAAM,qEAAqE;AAAA,IACvF;AACA,UAAM,SAAS,MAAMA,SAAQ,UAAU,MAAM;AAC7C,UAAM,MAAM,CAAC,GAAG,OAAO,QAAQ,EAC5B,QAAQ,EACR,KAAK,CAAC,cAAc,UAAU,SAAS,eAAe,UAAU,UAAU,KAAK;AAClF,QAAI,QAAQ,QAAW;AACrB,YAAM,IAAI,MAAM,2BAA2B,KAAK,8BAA8B;AAAA,IAChF;AACA,aAAS,QAAQ,IAAI,QAAQ,IAAI,IAAI,EAAE;AACvC,WAAO,IAAI;AAAA,EACb,GAAG,CAAC,CAAC;AAEL,QAAM,OAAOD;AAAA,IACX,OAAO,SAAoB,OAAoC,YAAqB;AAClF,YAAM,cAAc,qBAAqB,OAAO,QAAQ,SAAS,oBAAoB;AACrF,YAAM,MAAM,SAAS,QAAQ,IAAI,QAAQ,EAAE;AAC3C,YAAM,aACJ,UAAU,OACN,OACA;AAAA,QACE;AAAA,QACA,GAAI,YAAY,UAAa,QAAQ,KAAK,EAAE,SAAS,IACjD,EAAE,SAAS,QAAQ,KAAK,EAAE,IAC1B,CAAC;AAAA,QACL,YAAW,oBAAI,KAAK,GAAE,YAAY;AAAA,MACpC;AACN,eAAS,CAAC,YAAY,IAAI,IAAI,OAAO,EAAE,IAAI,QAAQ,IAAI,EAAE,UAAU,WAAW,CAAC,CAAC;AAChF,iBAAW,CAAC,YAAY,IAAI,IAAI,OAAO,EAAE,IAAI,QAAQ,EAAE,CAAC;AACxD,UAAI;AACF,cAAM,WAAW,MAAM,YAAY,OAAO;AAC1C,cAAM,EAAE,SAAS,IAAI,MAAM,YAAY,UAAU;AAAA,UAC/C;AAAA,UACA,GAAI,YAAY,SAAY,EAAE,QAAQ,IAAI,CAAC;AAAA,QAC7C,CAAC;AACD,iBAAS,CAAC,YAAY,IAAI,IAAI,OAAO,EAAE,IAAI,QAAQ,IAAI,EAAE,SAAS,CAAC,CAAC;AACpE,iBAAS,IAAI;AAAA,MACf,SAAS,QAAQ;AACf,iBAAS,CAAC,YAAY;AACpB,gBAAM,OAAO,IAAI,IAAI,OAAO;AAC5B,cAAI,QAAQ,OAAW,MAAK,OAAO,QAAQ,EAAE;AAAA,cACxC,MAAK,IAAI,QAAQ,IAAI,GAAG;AAC7B,iBAAO;AAAA,QACT,CAAC;AACD,cAAM,UAAU,kBAAkB,QAAQ,SAAS,IAAI,MAAM,OAAO,MAAM,CAAC;AAC3E,iBAAS,OAAO;AAChB,cAAM;AAAA,MACR,UAAE;AACA,mBAAW,CAAC,YAAY;AACtB,gBAAM,OAAO,IAAI,IAAI,OAAO;AAC5B,eAAK,OAAO,QAAQ,EAAE;AACtB,iBAAO;AAAA,QACT,CAAC;AAAA,MACH;AAAA,IACF;AAAA,IACA,CAAC,WAAW;AAAA,EACd;AAEA,QAAM,SAASA;AAAA,IACb,CAAC,SAAoB,UAAgC;AACnD,YAAM,OAAO,SAAS,QAAQ,IAAI,QAAQ,EAAE;AAC5C,YAAM,UAAU,SAAS,SAAY,KAAK,WAAY,WAAW,OAAO,EAAE,YAAY;AACtF,aAAO,KAAK,SAAS,SAAS,UAAU,QAAQ,OAAO,KAAK;AAAA,IAC9D;AAAA,IACA,CAAC,IAAI;AAAA,EACP;AAEA,SAAO,EAAE,YAAY,WAAW,MAAM,QAAQ,MAAM;AACtD;AAEA,SAAS,WAAW,SAA0C;AAC5D,QAAM,WAAW,QAAQ;AACzB,SAAO,aAAa,QAAQ,OAAO,aAAa,WAC3C,WACD,CAAC;AACP;;;AC/IA,SAAS,eAAAE,cAAa,aAAAC,YAAW,UAAAC,SAAQ,YAAAC,iBAAgB;AAkClD,SAAS,WAAW,UAA6B,CAAC,GAAiB;AACxE,QAAM,EAAE,UAAU,KAAK,IAAI;AAC3B,QAAM,UAAU,gBAAgB,QAAQ,OAAO;AAC/C,QAAM,CAAC,SAAS,UAAU,IAAIC,UAA0B,CAAC,CAAC;AAC1D,QAAM,CAAC,WAAW,YAAY,IAAIA,UAAS,OAAO;AAClD,QAAM,CAAC,OAAO,QAAQ,IAAIA,UAAuB,IAAI;AACrD,QAAM,aAAaC,QAAO,OAAO;AACjC,aAAW,UAAU;AAErB,QAAM,aAAaA,QAAO,CAAC;AAE3B,QAAM,UAAUC,aAAY,YAA2B;AACrD,UAAM,OAAO,EAAE,WAAW;AAC1B,iBAAa,IAAI;AACjB,QAAI;AACF,YAAM,OAAO,MAAM,QAAQ,YAAY;AACvC,UAAI,SAAS,WAAW,QAAS;AACjC,iBAAW,IAAI;AACf,eAAS,IAAI;AAAA,IACf,SAAS,QAAQ;AACf,UAAI,SAAS,WAAW,QAAS;AACjC,eAAS,kBAAkB,QAAQ,SAAS,IAAI,MAAM,OAAO,MAAM,CAAC,CAAC;AAAA,IACvE,UAAE;AACA,UAAI,SAAS,WAAW,QAAS,cAAa,KAAK;AAAA,IACrD;AAAA,EACF,GAAG,CAAC,OAAO,CAAC;AAEZ,EAAAC,WAAU,MAAM;AACd,QAAI,CAAC,QAAS;AACd,SAAK,QAAQ;AACb,WAAO,eAAe,SAAS,CAAC,UAAU;AACxC,UAAI,MAAM,SAAS,SAAS;AAC1B;AAAA,UAAW,CAAC,YACV,QAAQ;AAAA,YAAI,CAAC,WACX,OAAO,OAAO,MAAM,WAAW,EAAE,GAAG,QAAQ,OAAO,MAAM,MAAM,IAAI;AAAA,UACrE;AAAA,QACF;AAAA,MACF,WAAW,MAAM,SAAS,WAAW;AACnC,mBAAW,CAAC,YAAY,QAAQ,OAAO,CAAC,WAAW,OAAO,OAAO,MAAM,QAAQ,CAAC;AAAA,MAClF,OAAO;AACL,aAAK,QAAQ;AAAA,MACf;AAAA,IACF,CAAC;AAAA,EACH,GAAG,CAAC,SAAS,SAAS,OAAO,CAAC;AAE9B,QAAM,SAASD;AAAA,IACb,OAAO,IAAY,UAAiC;AAClD,YAAM,SAAS,WAAW;AAC1B;AAAA,QAAW,CAAC,YACV,QAAQ,IAAI,CAAC,WAAY,OAAO,OAAO,KAAK,EAAE,GAAG,QAAQ,MAAM,IAAI,MAAO;AAAA,MAC5E;AACA,UAAI;AACF,cAAM,QAAQ,aAAa,IAAI,EAAE,MAAM,CAAC;AACxC,sBAAc,SAAS,EAAE,MAAM,SAAS,UAAU,IAAI,MAAM,CAAC;AAAA,MAC/D,SAAS,QAAQ;AACf,mBAAW,MAAM;AACjB,cAAM;AAAA,MACR;AAAA,IACF;AAAA,IACA,CAAC,OAAO;AAAA,EACV;AAEA,QAAM,SAASA;AAAA,IACb,OAAO,OAA8B;AACnC,YAAM,SAAS,WAAW;AAC1B,iBAAW,CAAC,YAAY,QAAQ,OAAO,CAAC,WAAW,OAAO,OAAO,EAAE,CAAC;AACpE,UAAI;AACF,cAAM,QAAQ,aAAa,EAAE;AAC7B,sBAAc,SAAS,EAAE,MAAM,WAAW,UAAU,GAAG,CAAC;AAAA,MAC1D,SAAS,QAAQ;AACf,mBAAW,MAAM;AACjB,cAAM;AAAA,MACR;AAAA,IACF;AAAA,IACA,CAAC,OAAO;AAAA,EACV;AAEA,SAAO,EAAE,SAAS,WAAW,OAAO,SAAS,QAAQ,OAAO;AAC9D;;;AChFA,SAAS,UAAU,QAAiC;AAClD,MAAI,OAAO,WAAW,YAAY,WAAW,MAAM;AACjD,WAAO;AAAA,EACT;AACA,QAAM,YAAY;AAClB,MACE,UAAU,aAAa,QACvB,UAAU,WAAW,aACrB,OAAO,UAAU,UAAU,YAC3B,OAAO,UAAU,UAAU,UAC3B;AACA,WAAO;AAAA,EACT;AACA,SAAO,EAAE,UAAU,MAAM,QAAQ,WAAW,OAAO,UAAU,OAAO,OAAO,UAAU,MAAM;AAC7F;AASO,SAAS,yBAAyB,UAAqD;AAC5F,QAAM,QAAQ,oBAAI,IAA2B;AAC7C,aAAW,WAAW,UAAU;AAC9B,eAAW,UAAU,QAAQ,eAAe,CAAC,GAAG;AAC9C,YAAM,UAAU,UAAU,OAAO,MAAM;AACvC,UAAI,YAAY,QAAQ,MAAM,IAAI,QAAQ,KAAK,GAAG;AAChD;AAAA,MACF;AACA,YAAM,IAAI,QAAQ,OAAO;AAAA,QACvB,OAAO,QAAQ;AAAA,QACf,OAAO,QAAQ;AAAA,QACf,YAAY,OAAO;AAAA,QACnB,UAAU,OAAO;AAAA,QACjB,QAAQ;AAAA,MACV,CAAC;AAAA,IACH;AAAA,EACF;AACA,aAAW,WAAW,UAAU;AAC9B,UAAM,MAAM,QAAQ,UAAU,SAAY,SAAY,MAAM,IAAI,QAAQ,KAAK;AAC7E,QAAI,QAAQ,QAAW;AACrB,UAAI,SAAS;AACb,UAAI,UAAU;AAAA,IAChB;AAAA,EACF;AACA,SAAO,CAAC,GAAG,MAAM,OAAO,CAAC;AAC3B;;;ACjFA,SAAgB,aAAAE,YAAW,YAAAC,iBAAgB;;;ACA3C,SAAS,eAAAC,cAAa,aAAAC,YAAW,WAAAC,UAAS,UAAAC,SAAQ,YAAAC,iBAAgB;AAwClE,SAAS,qBAAmD;AAC1D,MAAI,OAAO,WAAW,YAAa,QAAO;AAC1C,QAAM,QAAQ;AAId,SAAO,MAAM,qBAAqB,MAAM,2BAA2B;AACrE;AAqBO,SAAS,qBAAqB;AAAA,EACnC,OAAO;AAAA,EACP;AAAA,EACA;AACF,GAAuD;AACrD,QAAM,iBAAiBD,QAAyC,IAAI;AACpE,QAAM,CAAC,aAAa,cAAc,IAAIC,UAAS,KAAK;AAEpD,QAAM,OAAOF,SAAQ,MAAM,mBAAmB,GAAG,CAAC,CAAC;AACnD,QAAM,cAAc,SAAS;AAI7B,QAAM,WAAWC,QAAO,iBAAiB;AACzC,QAAM,aAAaA,QAAO,mBAAmB;AAC7C,WAAS,UAAU;AACnB,aAAW,UAAU;AAErB,EAAAF,WAAU,MAAM;AACd,QAAI,CAAC,KAAM;AACX,UAAM,cAAc,IAAI,KAAK;AAC7B,gBAAY,OAAO;AACnB,gBAAY,aAAa;AACzB,gBAAY,iBAAiB;AAE7B,gBAAY,WAAW,CAAC,UAAU;AAChC,UAAI,UAAU;AACd,eAAS,IAAI,MAAM,aAAa,IAAI,MAAM,QAAQ,QAAQ,KAAK;AAC7D,cAAM,SAAS,MAAM,QAAQ,CAAC;AAC9B,YAAI,CAAC,OAAQ;AACb,cAAM,OAAO,OAAO,CAAC,GAAG,cAAc;AACtC,YAAI,OAAO,SAAS;AAClB,mBAAS,QAAQ,IAAI;AAAA,QACvB,OAAO;AACL,qBAAW;AAAA,QACb;AAAA,MACF;AACA,UAAI,WAAW,WAAW,QAAS,YAAW,QAAQ,OAAO;AAAA,IAC/D;AACA,gBAAY,UAAU,CAAC,UAAU;AAC/B,UAAI,MAAM,UAAU,eAAe,MAAM,UAAU,WAAW;AAC5D,gBAAQ,KAAK,2BAA2B,MAAM,KAAK;AAAA,MACrD;AACA,qBAAe,KAAK;AAAA,IACtB;AACA,gBAAY,QAAQ,MAAM,eAAe,KAAK;AAE9C,mBAAe,UAAU;AACzB,WAAO,MAAM;AACX,UAAI;AACF,oBAAY,KAAK;AAAA,MACnB,QAAQ;AAAA,MAER;AACA,qBAAe,UAAU;AAAA,IAC3B;AAAA,EACF,GAAG,CAAC,MAAM,IAAI,CAAC;AAEf,QAAM,QAAQD,aAAY,MAAM;AAC9B,UAAM,cAAc,eAAe;AACnC,QAAI,CAAC,YAAa;AAClB,QAAI;AACF,kBAAY,MAAM;AAClB,qBAAe,IAAI;AAAA,IACrB,SAAS,OAAO;AACd,cAAQ,KAAK,kCAAkC,KAAK;AAAA,IACtD;AAAA,EACF,GAAG,CAAC,CAAC;AAEL,QAAM,OAAOA,aAAY,MAAM;AAC7B,UAAM,cAAc,eAAe;AACnC,QAAI,CAAC,YAAa;AAClB,QAAI;AACF,kBAAY,KAAK;AAAA,IACnB,QAAQ;AAAA,IAER;AAAA,EACF,GAAG,CAAC,CAAC;AAEL,SAAO,EAAE,aAAa,aAAa,OAAO,KAAK;AACjD;;;ADrCI,SACE,OAAAK,MADF;AApEG,SAAS,UAAU;AAAA,EACxB;AAAA,EACA;AAAA,EACA;AAAA,EACA,OAAO;AAAA,EACP,eAAe;AAAA,EACf,aAAa;AAAA,EACb,YAAY;AAAA,EACZ;AAAA,EACA,cAAc;AAAA,EACd,YAAY;AAAA,EACZ;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AACF,GAAmB;AACjB,QAAM,CAAC,OAAO,QAAQ,IAAIC,UAAS,EAAE;AAIrC,QAAM,CAAC,SAAS,UAAU,IAAIA,UAAS,EAAE;AAEzC,QAAM,SAAS,qBAAqB;AAAA,IAClC,MAAM;AAAA,IACN,mBAAmB,CAAC,SAAS;AAC3B,YAAM,UAAU,KAAK,KAAK;AAC1B,UAAI,CAAC,QAAS;AACd,eAAS,CAAC,SAAU,KAAK,WAAW,IAAI,UAAU,GAAG,KAAK,QAAQ,CAAC,IAAI,OAAO,EAAG;AACjF,iBAAW,EAAE;AAAA,IACf;AAAA,IACA,qBAAqB,CAAC,SAAS,WAAW,IAAI;AAAA,EAChD,CAAC;AAED,EAAAC,WAAU,MAAM;AACd,QAAI,CAAC,OAAO,YAAa,YAAW,EAAE;AAAA,EACxC,GAAG,CAAC,OAAO,WAAW,CAAC;AAEvB,WAAS,SAAS;AAChB,UAAM,UAAU,MAAM,KAAK;AAC3B,QAAI,CAAC,QAAS;AACd,aAAS,OAAO;AAChB,aAAS,EAAE;AACX,eAAW,EAAE;AAAA,EACf;AAEA,WAAS,cAAc,OAAiD;AACtE,QAAI,MAAM,QAAQ,WAAW,CAAC,MAAM,UAAU;AAC5C,YAAM,eAAe;AACrB,aAAO;AAAA,IACT;AAAA,EACF;AAEA,WAAS,YAAY;AACnB,QAAI,OAAO,YAAa,QAAO,KAAK;AAAA,QAC/B,QAAO,MAAM;AAAA,EACpB;AAEA,QAAM,eACJ,OAAO,eAAe,UAClB,GAAG,KAAK,GAAG,SAAS,CAAC,MAAM,SAAS,GAAG,IAAI,MAAM,EAAE,GAAG,OAAO,KAC7D;AAEN,QAAM,UAAU,gBAAgB,OAAO;AACvC,QAAM,WAAW,eAAe,WAAW;AAE3C,SACE,qBAAC,SAAI,WACH;AAAA,oBAAAF;AAAA,MAAC;AAAA;AAAA,QACC,WAAW;AAAA,QACX;AAAA,QACA,OAAO;AAAA,QACP;AAAA,QACA,UAAU,CAAC,UAAU;AAGnB,cAAI,OAAO,eAAe,QAAS;AACnC,mBAAS,MAAM,OAAO,KAAK;AAAA,QAC7B;AAAA,QACA,WAAW;AAAA,QACX,aAAa,eAAe;AAAA;AAAA,IAC9B;AAAA,IACA,gBAAAA;AAAA,MAAC;AAAA;AAAA,QACC,MAAK;AAAA,QACL,WAAW;AAAA,QACX,SAAS;AAAA,QACT,UAAU,YAAY,CAAC,MAAM,KAAK;AAAA,QAEjC;AAAA;AAAA,IACH;AAAA,IACC,WACC,gBAAAA;AAAA,MAAC;AAAA;AAAA,QACC,MAAK;AAAA,QACL,WAAW;AAAA,QACX,SAAS,MAAM,KAAK,OAAO;AAAA,QAC3B,cAAW;AAAA,QAEV;AAAA;AAAA,IACH,IACE;AAAA,IACH,UACC,gBAAAA;AAAA,MAAC;AAAA;AAAA,QACC,MAAK;AAAA,QACL,WAAW;AAAA,QACX,SAAS;AAAA,QACT;AAAA,QACA,cAAY,OAAO,cAAc,mBAAmB;AAAA,QAEnD,sBACG,UAAU,EAAE,aAAa,OAAO,YAAY,CAAC,IAC7C,OAAO,cACL,SACA;AAAA;AAAA,IACR,IACE;AAAA,KACN;AAEJ;;;AEhKA,OAAOG,YAAW;;;ACElB,SAAS,eAAAC,cAAa,aAAAC,aAAW,UAAAC,UAAQ,YAAAC,kBAAgB;;;ACHzD;AAAA,EAGE;AAAA,EACA,6BAAAC;AAAA,OACK;AACP;AAAA,EAME,eAAAC;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,OACK;;;AChBP;AAAA,EAG+B;AAAA,EACD;AAAA,OACvB;AAUP,SAAS,IAAI,OAAuB;AAClC,SAAO,OAAO,KAAK,EAAE,SAAS,GAAG,GAAG;AACtC;AAGA,SAAS,MAAM,MAA2B;AACxC,MAAI,OAAO,MAAM,KAAK,QAAQ,CAAC,GAAG;AAChC,WAAO;AAAA,EACT;AACA,SAAO,GAAG,KAAK,YAAY,CAAC,IAAI,IAAI,KAAK,SAAS,IAAI,CAAC,CAAC,IAAI,IAAI,KAAK,QAAQ,CAAC,CAAC;AACjF;AAEA,SAAS,UAAU,MAAwC,KAA+B;AACxF,MAAI,QAAQ,QAAQ,QAAQ,QAAW;AACrC,WAAO;AAAA,EACT;AACA,MAAI,MAAM,QAAQ,GAAG,GAAG;AACtB,WAAO;AAAA,EACT;AACA,MAAI,eAAe,MAAM;AACvB,WAAO,SAAS,UAAU,SAAS,SAAY,MAAM,GAAG,IAAI,IAAI,YAAY;AAAA,EAC9E;AACA,MAAI,OAAO,QAAQ,WAAW;AAC5B,WAAO,MAAM,SAAS;AAAA,EACxB;AACA,MAAI,OAAO,QAAQ,UAAU;AAC3B,WAAO,OAAO,SAAS,GAAG,IAAI,OAAO,GAAG,IAAI;AAAA,EAC9C;AACA,QAAM,OAAO;AACb,UAAQ,MAAM;AAAA,IACZ,KAAK;AAAA,IACL,KAAK;AAAA,IACL,KAAK;AAAA,IACL,KAAK;AACH,aAAO,KAAK,KAAK,MAAM,KAAK,OAAO,KAAK,KAAK;AAAA,IAC/C,KAAK,WAAW;AACd,YAAM,UAAU,KAAK,KAAK,EAAE,YAAY;AACxC,UAAI,YAAY,UAAU,YAAY,QAAQ,YAAY,MAAO,QAAO;AACxE,UAAI,YAAY,WAAW,YAAY,SAAS,YAAY,KAAM,QAAO;AACzE,aAAO,YAAY,KAAK,OAAO;AAAA,IACjC;AAAA,IACA;AACE,aAAO,SAAS,KAAK,OAAO;AAAA,EAChC;AACF;AAYO,SAAS,aAAa,UAA6B,KAA0B;AAClF,QAAM,OAAO,SAAS,OAAO;AAC7B,QAAM,QAA8B,MAAM,QAAQ,GAAG,IAAI,MAAM,CAAC,GAAG;AACnE,QAAM,SAAS,MACZ,IAAI,CAAC,SAAS,UAAU,MAAM,IAAI,CAAC,EACnC,OAAO,CAAC,UAA2B,UAAU,IAAI;AACpD,SAAO,SAAS,aAAa,OAAO,SAAS,OAAO,MAAM,GAAG,CAAC;AAChE;;;AC3EA,SAAS,mBAAmB;;;ACCrB,SAAS,gBAAgB,SAAmD;AACjF,QAAM,UAAuB,CAAC;AAC9B,aAAW,SAAS,SAAS;AAC3B,QAAI,MAAM,iBAAiB,OAAW,SAAQ,MAAM,IAAI,IAAI,MAAM;AAAA,EACpE;AACA,SAAO;AACT;AAGO,SAAS,SAAS,OAAgB,MAAuB;AAC9D,SAAO,KAAK,MAAM,GAAG,EAAE,OAAgB,CAAC,SAAS,QAAQ;AACvD,QAAI,YAAY,QAAQ,OAAO,YAAY,SAAU,QAAO;AAC5D,WAAQ,QAAoC,GAAG;AAAA,EACjD,GAAG,KAAK;AACV;AAEA,SAAS,YAAY,OAAwB;AAC3C,MAAI,UAAU,QAAQ,UAAU,OAAW,QAAO;AAClD,MAAI,OAAO,UAAU,SAAU,QAAO;AACtC,MAAI,OAAO,UAAU,YAAY,OAAO,UAAU,UAAW,QAAO,OAAO,KAAK;AAChF,MAAI,MAAM,QAAQ,KAAK,EAAG,QAAO,MAAM,IAAI,WAAW,EAAE,OAAO,OAAO,EAAE,KAAK,IAAI;AACjF,SAAO;AACT;AAOO,SAAS,aAAa,UAAkB,SAA0B;AACvE,SAAO,SACJ,QAAQ,sBAAsB,CAAC,QAAQ,OAAe,SAAiB;AACtE,UAAM,WAAW,YAAY,SAAS,SAAS,IAAI,CAAC;AACpD,WAAO,aAAa,KAAK,KAAK,GAAG,KAAK,GAAG,QAAQ;AAAA,EACnD,CAAC,EACA,QAAQ,WAAW,GAAG,EACtB,KAAK;AACV;AASO,SAAS,UACd,cACA,OACAC,YACAC,YAA8C,EAAE,SAAS,WAAW,MAAM,OAAO,GACzE;AACR,MAAI,iBAAiB,OAAW,QAAOD,aAAYC,UAAS,OAAOA,UAAS;AAC5E,QAAM,SAAS,aAAaD,aAAY,aAAa,OAAO,aAAa,SAAS,KAAK;AAGvF,SAAO,WAAW,KAAK,aAAa,QAAQ;AAC9C;;;AC1CA,SAASE,UAAS,OAAkD;AAClE,SAAO,OAAO,UAAU,YAAY,UAAU,QAAQ,CAAC,MAAM,QAAQ,KAAK;AAC5E;AAEA,SAAS,OAAO,OAAwB;AACtC,MAAI,UAAU,QAAQ,UAAU,OAAW,QAAO;AAClD,MAAI,OAAO,UAAU,YAAY,OAAO,UAAU,YAAY,OAAO,UAAU,WAAW;AACxF,WAAO,OAAO,KAAK;AAAA,EACrB;AACA,MAAI,MAAM,QAAQ,KAAK,EAAG,QAAO,MAAM,IAAI,MAAM,EAAE,KAAK,IAAI;AAC5D,SAAO;AACT;AAQO,SAAS,gBAAgB,QAA6C;AAC3E,MAAI,CAACA,UAAS,MAAM,EAAG,QAAO;AAC9B,aAAW,CAAC,KAAK,KAAK,KAAK,OAAO,QAAQ,MAAM,GAAG;AACjD,QAAI,CAAC,MAAM,QAAQ,KAAK,KAAK,MAAM,WAAW,EAAG;AACjD,QAAI,MAAM,MAAM,CAAC,UAAU,OAAO,UAAU,QAAQ,GAAG;AACrD,aAAO,EAAE,MAAM,OAAO,OAAO,IAAI;AAAA,IACnC;AACA,QAAI,MAAM,MAAMA,SAAQ,GAAG;AACzB,YAAM,QAAQ,MAAM,CAAC;AACrB,aAAO;AAAA,QACL,MAAM;AAAA,QACN,MAAM;AAAA,QACN,SAAS,OAAO,KAAK,KAAK,EACvB,OAAO,CAAC,WAAW,CAACA,UAAS,MAAM,MAAM,CAAC,CAAC,EAC3C,IAAI,CAAC,YAAY,EAAE,MAAM,QAAQ,OAAO,OAAO,EAAE;AAAA,MACtD;AAAA,IACF;AAAA,EACF;AACA,QAAM,SAAS,OAAO,QAAQ,MAAM,EACjC,OAAO,CAAC,CAAC,EAAE,KAAK,MAAM,CAAC,UAAU,UAAU,SAAS,EAAE,SAAS,OAAO,KAAK,CAAC,EAC5E,IAAI,CAAC,CAAC,GAAG,OAAO,EAAE,MAAM,KAAK,OAAO,IAAI,EAAE;AAC7C,SAAO,OAAO,SAAS,IAAI,EAAE,MAAM,WAAW,OAAO,IAAI;AAC3D;AAOO,SAAS,kBACd,QACA,MACA,UAA+B,CAAC,GACL;AAC3B,QAAM,WAAW,SAAS,QAAQ,UAAU,OAAO,gBAAgB,MAAM,IAAI;AAC7E,MAAI,aAAa,UAAa,SAAS,SAAS,YAAa,QAAO;AACpE,UAAQ,SAAS,MAAM;AAAA,IACrB,KAAK,QAAQ;AACX,YAAM,OAAO,aAAa,SAAS,MAAM,MAAM;AAC/C,aAAO,SAAS,KAAK,OAAO,EAAE,MAAM,QAAQ,KAAK;AAAA,IACnD;AAAA,IACA,KAAK,WAAW;AACd,YAAM,WAAW,SAAS,OACvB,IAAI,CAAC,WAAW,EAAE,OAAO,OAAO,SAAS,QAAQ,MAAM,IAAI,EAAE,EAAE,EAC/D,OAAO,CAAC,UAAU,MAAM,UAAU,UAAa,MAAM,UAAU,IAAI,EACnE,IAAI,CAAC,EAAE,OAAO,MAAM,OAAO;AAAA,QAC1B,OAAO,MAAM;AAAA,QACb,OAAO,OAAO,KAAK;AAAA,QACnB,MAAM,MAAM,QAAQ;AAAA,MACtB,EAAE;AACJ,aAAO,SAAS,WAAW,IAAI,OAAO,EAAE,MAAM,WAAW,SAAS;AAAA,IACpE;AAAA,IACA,KAAK,OAAO;AACV,YAAM,QAAQ,SAAS,QAAQ,SAAS,KAAK;AAC7C,UAAI,CAAC,MAAM,QAAQ,KAAK,KAAK,MAAM,WAAW,EAAG,QAAO;AACxD,aAAO,EAAE,MAAM,OAAO,OAAO,MAAM,IAAI,MAAM,EAAE;AAAA,IACjD;AAAA,IACA,KAAK,SAAS;AACZ,YAAM,OAAO,SAAS,QAAQ,SAAS,IAAI;AAC3C,UAAI,CAAC,MAAM,QAAQ,IAAI,EAAG,QAAO;AACjC,aAAO;AAAA,QACL,MAAM;AAAA,QACN,SAAS,SAAS;AAAA,QAClB,MAAM,KAAK;AAAA,UAAI,CAAC,QACd,SAAS,QAAQ,IAAI,CAAC,WAAW,OAAO,SAAS,KAAK,OAAO,IAAI,CAAC,CAAC;AAAA,QACrE;AAAA,QACA,OAAO,KAAK,WAAW,IAAK,SAAS,SAAS,OAAQ;AAAA,MACxD;AAAA,IACF;AAAA,EACF;AACF;;;AFzEO,SAAS,aAAa,MAA8B;AACzD,QAAM,WAAY,KAAoC;AACtD,SACE,OAAO,aAAa,YACpB,aAAa,QACZ,SAAqC,aAAa;AAEvD;AAEO,SAAS,cAAc,MAAoC;AAChE,QAAM,SAAS,YAAY,OAAO,KAAK,SAAS;AAChD,MACE,WAAW,QACX,OAAO,WAAW,YAClB,gBAAgB,UAChB,cAAc,UACd,OAAO,aAAa;AAEpB,WAAO;AAAA,MACL,QAAQ;AAAA,MACR,WAAW;AAAA,MACX,UAAU;AAAA,MACV,UAAU;AAAA,MACV;AAAA,MACA,OAAO;AAAA,IACT;AACF,QAAM,YAAY,eAAe,OAAO,KAAK,YAAY;AACzD,QAAM,cACJ,WAAW,QAAQ,OAAO,WAAW,YAAY,WAAW,SACxD,OAAQ,OAA8B,KAAK,IAC3C;AACN,QAAM,WAAW,KAAK,UAAU;AAChC,QAAM,WAAW,KAAK,UAAU,kBAAmB,gBAAgB,UAAa,CAAC;AACjF,QAAMC,aAAY,KAAK,UAAU,sBAAsB,KAAK,UAAU,kBAAkB;AACxF,QAAM,aACJ,KAAK,UAAU,wBAAyB,KAAK,UAAU,qBAAqB,aAAa,IAAI;AAC/F,QAAM,SAAyB,WAC3B,WACA,WACE,WACAA,aACE,SACA,aACE,sBACA;AACV,SAAO;AAAA,IACL;AAAA,IACA,WAAAA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA,OAAO,aAAa,eAAe;AAAA,EACrC;AACF;AAOO,SAAS,iBAAiB,OAA8C;AAC7E,QAAM,YAAY,oBAAI,IAAY;AAClC,QAAM,oBAAoB,oBAAI,IAAoB;AAClD,QAAM,QAAQ,CAAC,MAAM,UAAU;AAC7B,QAAI,KAAK,UAAU,sBAAsB,CAAC,cAAc,IAAI,EAAE,UAAU;AACtE,wBAAkB,IAAI,YAAY,IAAI,GAAG,KAAK;AAAA,IAChD;AAAA,EACF,CAAC;AACD,QAAM,QAAQ,CAAC,MAAM,UAAU;AAC7B,UAAM,YAAY,kBAAkB,IAAI,YAAY,IAAI,CAAC;AACzD,QAAI,cAAc,UAAa,QAAQ,aAAa,cAAc,IAAI,EAAE,UAAU;AAChF,gBAAU,IAAI,KAAK,UAAU;AAAA,IAC/B;AAAA,EACF,CAAC;AACD,SAAO;AACT;AA6BO,SAAS,iBACd,MACA,SACA,UAAmC,CAAC,GACf;AACrB,QAAM,eAAe,UAAU,YAAY,IAAI,CAAC;AAChD,QAAM,QAAQ,cAAc,IAAI;AAChC,QAAM,QAAS,KAA6B;AAC5C,QAAM,UAAU,cAAc;AAC9B,SAAO;AAAA,IACL,QAAQ,MAAM;AAAA,IACd,QAAQ,UAAU,cAAc,OAAO,MAAM,WAAW,QAAQ,QAAQ;AAAA,IACxE,OAAO,cAAc,SAAS;AAAA,IAC9B,MAAM,cAAc,QAAQ;AAAA,IAC5B,MAAM,cAAc,QAAQ;AAAA,IAC5B,QAAQ,cAAc,UAAU;AAAA,IAChC,SACE,QAAQ,iBAAiB,SACrB;AAAA,MACE,OAAO,QAAQ,aAAa;AAAA,MAC5B,MAAM,QAAQ,aAAa;AAAA,MAC3B,QAAQ,QAAQ,aAAa,UAAU;AAAA,IACzC,IACA,YAAY,SACV,OACA;AAAA,MACE,OAAO,aAAa,QAAQ,OAAO,KAAK;AAAA,MACxC,MAAM,QAAQ;AAAA,MACd,QAAQ,QAAQ,WAAW,SAAY,aAAa,QAAQ,QAAQ,KAAK,IAAI;AAAA,IAC/E;AAAA,IACR,QACE,MAAM,WAAW,SACb,kBAAkB,MAAM,QAAQ,cAAc,QAAQ;AAAA,MACpD,GAAI,QAAQ,gBAAgB,SAAY,EAAE,OAAO,QAAQ,YAAY,IAAI,CAAC;AAAA,IAC5E,CAAC,IACD;AAAA,IACN,OAAO,MAAM;AAAA,IACb,cAAc,gBAAgB;AAAA,EAChC;AACF;AAsCA,IAAM,gBAAgD;AAAA,EACpD,SAAS;AAAA,EACT,QAAQ;AAAA,EACR,WAAW;AAAA,EACX,WAAW;AAAA,EACX,qBAAqB;AAAA,EACrB,QAAQ;AAAA,EACR,QAAQ;AAAA,EACR,MAAM;AACR;AAEA,SAAS,YAAY,MAAgD;AACnE,SAAO,KAAK,SAAS,QAAQ,CAAC,UAAU,CAAC,OAAO,GAAG,YAAY,KAAK,CAAC,CAAC;AACxE;AAEA,SAAS,OAAO,MAAgD;AAC9D,SAAO,KAAK,SAAS,WAAW,IAAI,CAAC,IAAI,IAAI,KAAK,SAAS,QAAQ,MAAM;AAC3E;AAOO,SAAS,kBACd,OACA,UAAoC,CAAC,GAChB;AACrB,QAAM,WAAW,QAAQ,iBAAiB,OAAO,MAAM,QAAQ,MAAM,IAAI,CAAC,GAAG,KAAK;AAClF,QAAM,YACJ,QAAQ,kBAAkB,OACtB,iBAAiB,SAAS,IAAI,CAAC,SAAS,KAAK,IAAI,CAAC,IAClD,oBAAI,IAAY;AACtB,QAAM,SAAS,oBAAI,IAA+B;AAClD,aAAW,QAAQ,UAAU;AAC3B,QAAI,UAAU,IAAI,KAAK,UAAU,EAAG;AACpC,UAAM,eAAe,QAAQ,UAAU,KAAK,IAAI;AAChD,UAAM,MAAM,QAAQ,QAAQ,MAAM,YAAY,KAAK,cAAc,SAAS,KAAK;AAC/E,UAAM,SAAS,KAAK,YAAY;AAChC,UAAM,SAAS;AAAA,MACb;AAAA,MACC,KAAK,KAA6B;AAAA,MACnC,WAAW,aAAa,WAAW;AAAA,MACnC,QAAQ;AAAA,IACV;AACA,UAAM,QAAQ,QAAQ,iBAAiB,OAAO,IAAI,YAAY,IAAI,EAAE;AACpE,UAAM,WAAW,OAAO,IAAI,GAAG;AAC/B,QAAI,aAAa,QAAW;AAC1B,aAAO,IAAI,KAAK;AAAA,QACd;AAAA,QACA,OAAO,cAAc,SAAS;AAAA,QAC9B,MAAM,cAAc,QAAQ;AAAA,QAC5B;AAAA,QACA,OAAO;AAAA,QACP;AAAA,QACA,OAAO,CAAC,IAAI;AAAA,QACZ,YAAY;AAAA,MACd,CAAC;AACD;AAAA,IACF;AACA,aAAS,SAAS;AAClB,aAAS,MAAM,KAAK,IAAI;AACxB,aAAS,SAAS;AAClB,aAAS,cAAc;AACvB,QAAI,cAAc,MAAM,IAAI,cAAc,SAAS,MAAM,EAAG,UAAS,SAAS;AAAA,EAChF;AACA,SAAO,CAAC,GAAG,OAAO,OAAO,CAAC;AAC5B;;;AFyJO,SAAS,sBACd,SACA,SACmB;AACnB,QAAM,SAA4B,CAAC;AACnC,MAAI,aAA8B,CAAC;AACnC,MAAI,kBAAmC,CAAC;AACxC,MAAI,aAA2B,CAAC;AAChC,MAAI,cAAc;AAClB,MAAI,cAAc;AAClB,MAAI,cAAc;AAClB,MAAI,mBAAmB;AACvB,MAAI,iBAAiB;AACrB,MAAI,qBAAqB;AACzB,QAAM,YAAY,cAAc,QAAQ,SAAS,CAAC,CAAC;AAEnD,WAAS,aAAa;AACpB,QAAI,WAAW,WAAW,GAAG;AAC3B;AAAA,IACF;AACA,UAAM,QAAQ,WAAW;AAAA,MAAI,CAAC,SAC5B;AAAA,QACE;AAAA,QACA,QAAQ;AAAA,QACR,WAAW,UAAU,IAAI,KAAK,UAAU,GAAG,IAAI;AAAA,QAC/C,QAAQ;AAAA,MACV;AAAA,IACF;AACA,UAAM,QAAQ,cAAc,KAAK;AACjC,WAAO,KAAK;AAAA,MACV,MAAM;AAAA,MACN,KAAK,GAAG,QAAQ,EAAE,UAAU,aAAa;AAAA,MACzC,OAAO;AAAA,MACP;AAAA,MACA;AAAA,MACA,UAAU,kBAAkB,OAAO;AAAA,QACjC,GAAI,QAAQ,gBAAgB,SAAY,EAAE,SAAS,QAAQ,YAAY,IAAI,CAAC;AAAA,MAC9E,CAAC;AAAA,IACH,CAAC;AACD,iBAAa,CAAC;AAAA,EAChB;AAEA,WAAS,eAAe;AACtB,QAAI,gBAAgB,WAAW,GAAG;AAChC;AAAA,IACF;AACA,WAAO,KAAK,kBAAkB,GAAG,QAAQ,EAAE,YAAY,gBAAgB,IAAI,eAAe,CAAC;AAC3F,sBAAkB,CAAC;AAAA,EACrB;AAEA,WAAS,aAAa;AACpB,QAAI,WAAW,WAAW,GAAG;AAC3B;AAAA,IACF;AACA,WAAO,KAAK;AAAA,MACV,MAAM;AAAA,MACN,KAAK,GAAG,QAAQ,EAAE,UAAU,aAAa;AAAA,MACzC,OAAO,WAAW,IAAI,CAAC,UAAU;AAAA,QAC/B,KAAK,KAAK;AAAA,QACV,WAAW,KAAK;AAAA,QAChB,UAAU,KAAK,YAAY;AAAA,QAC3B,SAAS,KAAK,UAAU,WAAW,QAAQ;AAAA,MAC7C,EAAE;AAAA,IACJ,CAAC;AACD,iBAAa,CAAC;AAAA,EAChB;AAEA,WAAS,WAAW;AAClB,eAAW;AACX,iBAAa;AACb,eAAW;AAAA,EACb;AAGA,QAAM,eAAe,oBAAI,IAAY;AACrC,aAAW,QAAQ,QAAQ,SAAS,CAAC,GAAG;AACtC,QACE,aAAa,IAAI,MAChB,KAAK,UAAU,sBACd,KAAK,UAAU,kBACf,KAAK,UAAU,kBACjB;AACA,mBAAa,IAAI,KAAK,UAAU;AAAA,IAClC;AAAA,EACF;AAEA,aAAW,QAAQ,QAAQ,SAAS,CAAC,GAAG;AACtC,QAAI,aAAa,IAAI,GAAG;AACtB,YAAM,cAAc,QAAQ;AAC5B,UAAI,gBAAgB,QAAW;AAC7B,cAAM,UAAU,uBAAuB,IAAI;AAC3C,YAAI,YAAY,MAAM;AACpB,mBAAS;AACT,iBAAO;AAAA,YACL;AAAA,cACE,GAAG,QAAQ,EAAE,gBAAgB,oBAAoB;AAAA,cACjD;AAAA,cACA;AAAA,cACA;AAAA,YACF;AAAA,UACF;AACA;AAAA,QACF;AAAA,MACF;AACA,UAAI,QAAQ,YAAY,QAAQ,aAAa,IAAI,MAAM,MAAM;AAC3D,mBAAW;AACX,wBAAgB,KAAK,IAAI;AACzB;AAAA,MACF;AACA,mBAAa;AACb,iBAAW;AACX,iBAAW,KAAK,IAAI;AACpB;AAAA,IACF;AACA,QAAI,aAAa,IAAI,GAAG;AACtB,iBAAW;AACX,mBAAa;AACb,iBAAW,KAAK,IAAI;AACpB;AAAA,IACF;AACA,QAAI,KAAK,SAAS,iBAAiB,KAAK,SAAS,cAAc;AAC7D;AAAA,IACF;AACA,aAAS;AACT,QAAI,aAAa,IAAI,GAAG;AACtB,YAAM,KAAK,KAAK,SAAS,UAAU,gBAAgB,IAAI,IAAI;AAG3D,UACE,IAAI,YAAY,SACf,OAAO,KAAK,GAAG,KAAK,EAAE,WAAW,KAC/B,GAAG,eAAe,QAAQ,aAAa,IAAI,GAAG,UAAU,IAC3D;AACA;AAAA,MACF;AACA,UAAI,OAAO,MAAM;AACf,eAAO,KAAK,EAAE,MAAM,MAAM,KAAK,GAAG,QAAQ,EAAE,OAAO,GAAG,EAAE,IAAI,GAAG,GAAG,CAAC;AAAA,MACrE;AACA;AAAA,IACF;AACA,QAAI,aAAa,IAAI,GAAG;AACtB,aAAO,KAAK;AAAA,QACV,MAAM;AAAA,QACN,KAAK,GAAG,QAAQ,EAAE,SAAS,aAAa;AAAA,QACxC,MAAM,KAAK;AAAA,QACX,aAAa,KAAK,UAAU;AAAA,MAC9B,CAAC;AACD;AAAA,IACF;AACA,QAAI,kBAAkB,IAAI,GAAG;AAC3B,YAAM,MAAM,GAAG,QAAQ,EAAE,cAAc,kBAAkB;AACzD,YAAM,cAAc,KAAK,UAAU;AACnC,aAAO,KAAK;AAAA,QACV,MAAM;AAAA,QACN;AAAA,QACA,MAAM,KAAK;AAAA,QACX;AAAA,QACA,YAAY,gBAAgB,IAAI;AAAA,QAChC,QAAQ,QAAQ,gBAAgB,KAAK,WAAW;AAAA,QAChD,QAAQ,CAAC,SAAmB,QAAQ,gBAAgB,KAAK,IAAI;AAAA,MAC/D,CAAC;AAAA,IACH;AAAA,EACF;AACA,WAAS;AACT,SAAO;AACT;AAOA,SAAS,kBAAkB,KAAa,OAAgD;AACtF,QAAM,OAAO,oBAAI,IAA8B;AAC/C,MAAI,QAAuB;AAC3B,MAAI,eAAe;AAEnB,aAAW,QAAQ,OAAO;AACxB,cAAU,UAAU,IAAI;AACxB,eAAW,WAAW,aAAa,IAAI,KAAK,CAAC,GAAG;AAC9C;AACA,YAAM,KAAK,QAAQ,UAAU,QAAQ;AACrC,YAAM,WAAW,KAAK,IAAI,EAAE;AAC5B,UAAI,UAAU;AACZ,iBAAS;AACT,iBAAS,WAAW,KAAK,IAAI,SAAS,UAAU,QAAQ,KAAK;AAC7D,iBAAS,SAAS,KAAK,OAAO;AAC9B;AAAA,MACF;AACA,WAAK,IAAI,IAAI;AAAA,QACX;AAAA,QACA,OAAO,QAAQ,UAAU,QAAQ;AAAA,QACjC,cAAc;AAAA,QACd,UAAU,QAAQ;AAAA,QAClB,UAAU,CAAC,OAAO;AAAA,MACpB,CAAC;AAAA,IACH;AAAA,EACF;AAEA,SAAO,EAAE,MAAM,WAAW,KAAK,OAAO,SAAS,CAAC,GAAG,KAAK,OAAO,CAAC,GAAG,aAAa;AAClF;AAGA,SAAS,UAAU,OAAwB;AACzC,SAAO,UAAU,sBAAsB,UAAU,kBAAkB,UAAU;AAC/E;AAEA,SAAS,SAAS,MAAyC;AACzD,QAAM,WAAY,KAAoC;AACtD,SAAOC,UAAS,QAAQ,KAAK,OAAO,SAAS,aAAa,WACtD,SAAS,WACT;AACN;AAOA,SAAS,mBAAmB,MAA8B;AACxD,MAAI,KAAK,UAAU,sBAAsB;AACvC,WAAO;AAAA,EACT;AACA,MAAI,KAAK,UAAU,mBAAmB;AACpC,WAAO;AAAA,EACT;AAGA,SAAO,SAAS,IAAI,MAAM,YAAY,uBAAuB,IAAI,MAAM;AACzE;AAEA,SAAS,aAAa,MAAoC;AACxD,QAAM,WAAY,KAAoC;AACtD,SAAOA,UAAS,QAAQ,KAAK,OAAO,SAAS,aAAa,WAAW,SAAS,WAAW;AAC3F;AAOA,SAAS,cAAc,OAAmD;AACxE,QAAM,OAAO,IAAI,IAAI,MAAM,IAAI,CAAC,SAAS,CAAC,KAAK,YAAY,IAAI,CAAC,CAAC;AACjE,QAAM,QAA8B,CAAC;AACrC,aAAW,QAAQ,OAAO;AACxB,UAAM,SAAS,KAAK,aAAa,OAAO,KAAK,IAAI,KAAK,QAAQ,IAAI;AAClE,QAAI,WAAW,UAAa,WAAW,MAAM,QAAQ,IAAI,GAAG;AAC1D,YAAM,KAAK,IAAI;AACf;AAAA,IACF;AACA,WAAO,SAAS,KAAK,IAAI;AAAA,EAC3B;AACA,SAAO;AACT;AAGA,SAAS,WACP,MACA,WACA,MACS;AACT,QAAM,OAAO,oBAAI,IAAY;AAC7B,MAAI,UAA0C;AAC9C,SAAO,YAAY,UAAa,CAAC,KAAK,IAAI,QAAQ,UAAU,GAAG;AAC7D,QAAI,QAAQ,eAAe,KAAK,YAAY;AAC1C,aAAO;AAAA,IACT;AACA,SAAK,IAAI,QAAQ,UAAU;AAC3B,cAAU,QAAQ,aAAa,OAAO,KAAK,IAAI,QAAQ,QAAQ,IAAI;AAAA,EACrE;AACA,SAAO;AACT;AAEA,SAAS,cACP,MACA,SACA,UACA,SACoB;AACpB,QAAM,aAAa,KAAK;AACxB,QAAM,WACJ,UAAU,QAAQ,SAAS,aACvB,SAAS,WAAW,YACpB,mBAAmB,IAAI;AAG7B,QAAM,UAAU,WAAY,SAAS,WAAW,UAAU,KAAK,OAAQ;AACvE,SAAO;AAAA,IACL;AAAA,IACA;AAAA,IACA,MAAMC,aAAY,IAAI;AAAA,IACtB,UAAU,SAAS,IAAI,KAAK;AAAA,IAC5B,UAAU,aAAa,IAAI;AAAA,IAC3B,UAAU,CAAC;AAAA,IACX;AAAA,IACA,aAAa;AAAA,MACX;AAAA,QACE;AAAA,QACA;AAAA,QACA,UAAU,iBAAiB,SAAY,CAAC,IAAI,EAAE,cAAc,SAAS,aAAa;AAAA,MACpF;AAAA,MACA;AAAA,IACF;AAAA,IACA,oBAAoB;AAAA,IACpB,SAAS;AAAA,MACP,WAAW,YAAY,SAAS,eAAe;AAAA,MAC/C,cAAc,YAAY;AAAA;AAAA;AAAA,MAG1B,KAAK,CAAC,mBACJ,UAAU,WAAW,SACjB,gBAAgB,aAAa,OAC3B,SAAS,QAAQ,YAAY,EAAE,UAAU,KAAK,CAAC,IAC/C,SAAS,QAAQ,UAAU,IAC7B,SAAS;AAAA,QACP;AAAA,QACA,gBAAgB,aAAa,OAAO,EAAE,UAAU,KAAK,IAAI;AAAA,QACzD,SAAS;AAAA,MACX;AAAA,IACR;AAAA,IACA,QAAQ;AAAA,MACN,WAAW,YAAY,SAAS,cAAc;AAAA,MAC9C,cAAc,YAAY;AAAA,MAC1B,KAAK,MACH,UAAU,WAAW,SACjB,SAAS,OAAO,UAAU,IAC1B,SAAS,OAAO,YAAY,SAAS,MAAM;AAAA,IACnD;AAAA,IACA,OAAO,SAAS,QAAQ,UAAU,KAAK;AAAA,IACvC,WAAW,SAAS,cAAc,UAAU,KAAK;AAAA,EACnD;AACF;AAoBA,SAAS,uBACP,MAC0E;AAC1E,QAAM,QAAS,KAA6B;AAC5C,MAAI,CAACD,UAAS,KAAK,KAAK,CAAC,MAAM,QAAQ,MAAM,SAAS,KAAK,MAAM,UAAU,WAAW,GAAG;AACvF,WAAO;AAAA,EACT;AACA,QAAM,YAAuC,CAAC;AAC9C,aAAW,aAAa,MAAM,WAAW;AACvC,QACE,CAACA,UAAS,SAAS,KACnB,OAAO,UAAU,OAAO,YACxB,OAAO,UAAU,WAAW,UAC5B;AACA,aAAO;AAAA,IACT;AAEA,UAAME,SAAQ,qBAAqB,UAAU,KAAK,KAAK;AACvD,UAAM,aAAa,MAAM,QAAQ,UAAU,OAAO,IAAI,UAAU,UAAU,CAAC;AAC3E,QAAI,WAAW,WAAW,MAAMA,WAAU,QAAQA,OAAM,SAAS,WAAW;AAC1E,aAAO;AAAA,IACT;AACA,UAAM,UAA8C,CAAC;AACrD,eAAW,UAAU,YAAY;AAC/B,UACE,CAACF,UAAS,MAAM,KAChB,OAAO,OAAO,UAAU,YACxB,OAAO,OAAO,UAAU,UACxB;AACA,eAAO;AAAA,MACT;AACA,cAAQ,KAAK;AAAA,QACX,OAAO,OAAO;AAAA,QACd,OAAO,OAAO;AAAA,QACd,QAAQ,OAAO,OAAO,WAAW,WAAW,OAAO,SAAS;AAAA,MAC9D,CAAC;AAAA,IACH;AACA,cAAU,KAAK;AAAA,MACb,IAAI,UAAU;AAAA,MACd,QAAQ,UAAU;AAAA,MAClB,aAAa,OAAO,UAAU,gBAAgB,WAAW,UAAU,cAAc;AAAA,MACjF,OAAAE;AAAA,MACA,UAAU,UAAU,aAAa;AAAA,MACjC,eAAe,UAAU,kBAAkB;AAAA,MAC3C,UAAU,MAAM,QAAQ,UAAU,QAAQ,IACtC,UAAU,SAAS,OAAO,CAAC,UAA2B,OAAO,UAAU,QAAQ,IAC/E,CAAC;AAAA,MACL;AAAA,IACF,CAAC;AAAA,EACH;AACA,SAAO;AAAA,IACL,UAAU,OAAO,MAAM,aAAa,WAAW,MAAM,WAAW;AAAA,IAChE;AAAA,EACF;AACF;AAGA,SAAS,uBAAuB,MAA0D;AACxF,QAAM,SAAU,KAA8B;AAC9C,MAAI,CAACF,UAAS,MAAM,KAAK,CAACA,UAAS,OAAO,OAAO,KAAK,OAAO,OAAO,YAAY,WAAW;AACzF,WAAO;AAAA,EACT;AACA,QAAM,UAAoC,CAAC;AAC3C,aAAW,CAAC,IAAI,MAAM,KAAK,OAAO,QAAQ,OAAO,OAAO,GAAG;AACzD,YAAQ,EAAE,IAAI,MAAM,QAAQ,MAAM,IAC9B,OAAO,OAAO,CAAC,UAA2B,OAAO,UAAU,QAAQ,IACnE,CAAC;AAAA,EACP;AACA,SAAO;AAAA,IACL;AAAA,IACA,SAAS,OAAO;AAAA,IAChB,WAAW,MAAM,QAAQ,OAAO,SAAS,IACrC,OAAO,UAAU,OAAO,CAAC,OAAqB,OAAO,OAAO,QAAQ,IACpE,CAAC;AAAA,IACL,SAAS,OAAO,OAAO,YAAY,WAAW,OAAO,UAAU;AAAA,IAC/D,YAAY,OAAO,OAAO,eAAe,WAAW,OAAO,aAAa;AAAA,IACxE,aAAa,OAAO,OAAO,gBAAgB,WAAW,OAAO,cAAc;AAAA,EAC7E;AACF;AAEA,SAAS,sBACP,KACA,MACA,SACA,SAC4B;AAC5B,QAAM,aAAa,KAAK;AACxB,QAAM,YAAY,CAAC,UAAU,KAAK,KAAK;AACvC,QAAM,UAAU,YAAY,OAAO,uBAAuB,IAAI;AAC9D,QAAM,YAAY,QAAQ,UAAU,IAAI,CAAC,UAAU,UAAU;AAC3D,UAAM,SAAS,YAAY,QAAQ,OAAO,YAAY,SAAS,EAAE,IAAI;AACrE,UAAM,WAAW,UAAU,SAAS,QAAQ,SAAS,EAAE,KAAK,SAAS;AACrE,UAAM,OAAO,CAAC,WAAqB,QAAQ,KAAK,YAAY,SAAS,IAAI,MAAM;AAE/E,UAAM,QAAQ,YACVG;AAAA,MACE;AAAA,QACE,IAAI,SAAS;AAAA,QACb,QAAQ,SAAS;AAAA,QACjB,SAAS,SAAS,QAAQ,IAAI,CAAC,EAAE,OAAO,MAAM,OAAO,EAAE,OAAO,MAAM,EAAE;AAAA,QACtE,GAAI,SAAS,UAAU,OAAO,EAAE,OAAO,SAAS,MAAM,IAAI,CAAC;AAAA,QAC3D,GAAI,SAAS,WAAW,EAAE,UAAU,KAAK,IAAI,CAAC;AAAA,QAC9C,GAAI,SAAS,gBAAgB,EAAE,eAAe,KAAK,IAAI,CAAC;AAAA,MAC1D;AAAA,MACA;AAAA,IACF,IACA;AACJ,WAAO;AAAA,MACL,IAAI,SAAS;AAAA,MACb,QAAQ,SAAS;AAAA,MACjB,aAAa,SAAS;AAAA,MACtB,OAAO,SAAS;AAAA,MAChB,UAAU,SAAS;AAAA,MACnB,UAAU,QAAQ;AAAA,MAClB;AAAA,MACA,OAAO,SAAS,CAAC,KAAK;AAAA,MACtB;AAAA,MACA,UAAU,CAAC,QAAmB;AAC5B,YAAI,WAAW;AACb,eAAK,aAAa,UAAU,GAAG,CAAC;AAAA,QAClC;AAAA,MACF;AAAA,MACA,YAAY,YACR,WAAW,SACV,SAAS,UAAU,SAAS,SAAS,EAAE,KAAK;AAAA,MACjD,SAAS,SAAS,QAAQ,IAAI,CAAC,YAAY;AAAA,QACzC,OAAO,OAAO;AAAA,QACd,OAAO,OAAO;AAAA,QACd,QAAQ,OAAO;AAAA,QACf,YAAY,SAAS,SAAS,OAAO,KAAK;AAAA,QAC1C,WAAW,SAAS,SAAS,SAAS,OAAO,KAAK;AAAA,QAClD,QAAQ,MAAM;AACZ,cAAI,CAAC,WAAW;AACd;AAAA,UACF;AACA,cAAI,CAAC,SAAS,UAAU;AACtB,iBAAK,CAAC,OAAO,KAAK,CAAC;AACnB;AAAA,UACF;AACA;AAAA,YACE,SAAS,SAAS,OAAO,KAAK,IAC1B,SAAS,OAAO,CAAC,UAAU,UAAU,OAAO,KAAK,IACjD,CAAC,GAAG,UAAU,OAAO,KAAK;AAAA,UAChC;AAAA,QACF;AAAA,MACF,EAAE;AAAA,IACJ;AAAA,EACF,CAAC;AACD,QAAM,UAAU,YAAY,QAAQ,WAAW,UAAU,IAAI;AAC7D,SAAO;AAAA,IACL,MAAM;AAAA,IACN;AAAA,IACA;AAAA,IACA,UAAU,QAAQ;AAAA,IAClB;AAAA,IACA,eAAe,UAAU;AAAA,IACzB;AAAA,IACA,SAAS,UAAU,MAAM,CAAC,aAAa,SAAS,UAAU,IAAI;AAAA,IAC9D;AAAA,IACA,OAAO,QAAQ,QAAQ,UAAU;AAAA,IACjC,WAAW,QAAQ,cAAc,UAAU,KAAK;AAAA,IAChD,QAAQ;AAAA,MACN,WAAW,aAAa,QAAQ;AAAA,MAChC,cAAc,YAAY;AAAA,MAC1B,KAAK,MAAM,QAAQ,OAAO,UAAU;AAAA,IACtC;AAAA,IACA,MAAM;AAAA,MACJ,WAAW,aAAa,QAAQ;AAAA,MAChC,cAAc,YAAY;AAAA,MAC1B,KAAK,MAAM,QAAQ,KAAK,UAAU;AAAA,IACpC;AAAA,EACF;AACF;AAEA,IAAM,UAAU;AAChB,IAAM,gBAAgB;AACtB,IAAM,eAAe;AAiBrB,IAAM,mBAAsC,CAAC,YAAY,YAAY,WAAW,YAAY;AAG5F,SAAS,cAAc,OAAuD;AAC5E,QAAM,MAAM,oBAAI,IAA2B;AAC3C,QAAM,QAAQ,CAAC,OAA8B;AAC3C,QAAI,QAAQ,IAAI,IAAI,EAAE;AACtB,QAAI,UAAU,QAAW;AACvB,cAAQ;AAAA,QACN,UAAU;AAAA,QACV,WAAW;AAAA,QACX,QAAQ;AAAA,QACR,QAAQ;AAAA,QACR,UAAU;AAAA,QACV,WAAW;AAAA,QACX,YAAY;AAAA,QACZ,gBAAgB;AAAA,MAClB;AACA,UAAI,IAAI,IAAI,KAAK;AAAA,IACnB;AACA,WAAO;AAAA,EACT;AACA,aAAW,QAAQ,OAAO;AACxB,QACE,KAAK,SAAS,iBACd,KAAK,SAAS,gBACd,KAAK,SAAS,wBACd;AACA;AAAA,IACF;AACA,UAAM,OAAQ,KAA6C;AAC3D,QAAI,CAACH,UAAS,IAAI,KAAK,OAAO,KAAK,OAAO,UAAU;AAClD;AAAA,IACF;AACA,UAAM,WAAW,MAAM,KAAK,EAAE;AAC9B,QAAI,KAAK,SAAS,iBAAiB,KAAK,SAAS,wBAAwB;AACvE,UACEA,UAAS,KAAK,MAAM,KACpB,KAAK,OAAO,SAAS,cACrB,OAAO,KAAK,OAAO,eAAe,UAClC;AACA,iBAAS,SAAS;AAAA,UAChB,MAAM;AAAA,UACN,YAAY,KAAK,OAAO;AAAA,UACxB,GAAI,OAAO,KAAK,OAAO,aAAa,WAAW,EAAE,UAAU,KAAK,OAAO,SAAS,IAAI,CAAC;AAAA,QACvF;AAAA,MACF;AACA,UAAI,KAAK,SAAS,wBAAwB;AACxC,YACE,OAAO,KAAK,WAAW,YACvB,CAAC,WAAW,YAAY,YAAY,WAAW,YAAY,EAAE,SAAS,KAAK,MAAM;AAEjF,mBAAS,SACP,KAAK,WAAW,YACZ,OACC,KAAK;AACd,YACE,KAAK,oBAAoB,QACzB,KAAK,oBAAoB,YACzB,KAAK,oBAAoB,eACzB,KAAK,oBAAoB,eACzB,KAAK,oBAAoB;AAEzB,mBAAS,kBAAkB,KAAK;AAClC,iBAAS,WAAW,KAAK,aAAa;AACtC,iBAAS,YAAY,OAAO,KAAK,cAAc,WAAW,KAAK,YAAY;AAC3E,iBAAS,aAAa,OAAO,KAAK,eAAe,WAAW,KAAK,aAAa;AAAA,MAChF;AACA,UAAI,OAAO,KAAK,aAAa,UAAU;AACrC;AAAA,MACF;AACA,eAAS,WAAW,KAAK;AACzB,eAAS,YAAY,OAAO,KAAK,cAAc,WAAW,KAAK,YAAY;AAC3E,UACEA,UAAS,KAAK,YAAY,KAC1B,OAAO,KAAK,aAAa,UAAU,YACnC,OAAO,KAAK,aAAa,SAAS,aACjC,KAAK,aAAa,WAAW,UAAa,OAAO,KAAK,aAAa,WAAW,WAC/E;AACA,iBAAS,eAAe;AAAA,UACtB,OAAO,KAAK,aAAa;AAAA,UACzB,MAAM,KAAK,aAAa;AAAA,UACxB,GAAI,OAAO,KAAK,aAAa,WAAW,WACpC,EAAE,QAAQ,KAAK,aAAa,OAAO,IACnC,CAAC;AAAA,QACP;AAAA,MACF;AACA,eAAS,SAAS,OAAO,KAAK,WAAW,WAAW,KAAK,SAAS;AAClE;AAAA,IACF;AACA,QAAI,OAAO,KAAK,WAAW,YAAY,CAAC,iBAAiB,SAAS,KAAK,MAAM,GAAG;AAC9E;AAAA,IACF;AACA,aAAS,SAAS,KAAK;AACvB,QAAI,SAAS,aAAa,QAAQ,OAAO,KAAK,aAAa,UAAU;AACnE,eAAS,WAAW,KAAK;AAAA,IAC3B;AACA,aAAS,WAAW,KAAK,aAAa;AACtC,aAAS,YAAY,OAAO,KAAK,cAAc,WAAW,KAAK,YAAY;AAC3E,aAAS,aAAa,OAAO,KAAK,eAAe,WAAW,KAAK,aAAa;AAC9E,aAAS,iBAAiB,OAAO,KAAK,WAAW,WAAW,KAAK,SAAS;AAAA,EAC5E;AACA,SAAO;AACT;AAMA,SAAS,WACP,OACA,MAC2B;AAC3B,MAAI,UAAU,UAAa,MAAM,aAAa,MAAM;AAClD,WAAO;AAAA,EACT;AACA,SAAO;AAAA,IACL,UAAU,MAAM;AAAA,IAChB,GAAI,MAAM,WAAW,SAAY,CAAC,IAAI,EAAE,QAAQ,MAAM,OAAO;AAAA,IAC7D,GAAI,MAAM,oBAAoB,SAAY,CAAC,IAAI,EAAE,iBAAiB,MAAM,gBAAgB;AAAA,IACxF,GAAI,MAAM,iBAAiB,SAAY,EAAE,cAAc,MAAM,aAAa,IAAI,CAAC;AAAA,IAC/E,WAAW,MAAM;AAAA,IACjB,QAAQ,MAAM;AAAA,IACd,QAAQ,MAAM,WAAW,MAAM,QAAQ,SAAS,aAAa,YAAY,eAAe,IAAI;AAAA,IAC5F,UAAU,MAAM;AAAA,IAChB,WAAW,MAAM;AAAA,IACjB,YAAY,MAAM;AAAA,IAClB,gBAAgB,MAAM;AAAA,EACxB;AACF;AAEA,SAAS,eAAe,MAA+C;AACrE,MAAI,KAAK,UAAU,iBAAiB;AAClC,WAAO;AAAA,EACT;AACA,MAAI,KAAK,UAAU,sBAAsB,KAAK,UAAU,gBAAgB;AACtE,WAAO;AAAA,EACT;AACA,SAAO;AACT;AAGA,SAAS,gBACP,MACgD;AAChD,QAAM,OAAO,KAAK;AAClB,MAAI,CAACA,UAAS,IAAI,KAAK,OAAO,KAAK,cAAc,UAAU;AACzD,WAAO;AAAA,EACT;AACA,QAAM,KAAK,OAAO,KAAK,OAAO,WAAW,KAAK,KAAK,KAAK;AACxD,MAAI,OAAO,QAAW;AACpB,WAAO;AAAA,EACT;AACA,SAAO;AAAA,IACL;AAAA,IACA,WAAW,KAAK;AAAA,IAChB,OAAOA,UAAS,KAAK,KAAK,IAAI,KAAK,QAAQ,CAAC;AAAA,IAC5C,SAAS,OAAO,KAAK,YAAY,WAAW,KAAK,UAAU;AAAA,IAC3D,GAAIA,UAAS,KAAK,iBAAiB,KACnC,OAAO,OAAO,KAAK,iBAAiB,EAAE;AAAA,MACpC,CAAC,YAAY,OAAO,YAAY,YAAY,OAAO,cAAc,OAAO,KAAK,UAAU;AAAA,IACzF,IACI,EAAE,mBAAmB,EAAE,GAAG,KAAK,kBAAkB,EAA4B,IAC7E,CAAC;AAAA,IACL,GAAI,OAAO,KAAK,iBAAiB,WAAW,EAAE,cAAc,KAAK,aAAa,IAAI,CAAC;AAAA,IACnF,YAAY,OAAO,KAAK,eAAe,WAAW,KAAK,aAAa;AAAA,IACpE,GAAI,KAAK,YAAY,OAAO,EAAE,SAAS,KAAc,IAAI,CAAC;AAAA,EAC5D;AACF;AAEA,SAASA,UAAS,OAAkD;AAClE,SAAO,OAAO,UAAU,YAAY,UAAU;AAChD;AAEA,SAAS,UAAU,MAAoC;AACrD,QAAM,QAAS,KAA6B;AAC5C,MAAI,CAACA,UAAS,KAAK,KAAK,OAAO,MAAM,UAAU,UAAU;AACvD,WAAO;AAAA,EACT;AACA,SAAO,MAAM;AACf;AAOA,SAAS,aAAa,MAAgD;AACpE,QAAM,SAAU,KAA8B;AAC9C,MAAI,CAACA,UAAS,MAAM,KAAK,CAAC,MAAM,QAAQ,OAAO,QAAQ,KAAK,OAAO,SAAS,WAAW,GAAG;AACxF,WAAO;AAAA,EACT;AACA,QAAM,WAA+B,CAAC;AACtC,aAAW,aAAa,OAAO,UAAU;AACvC,QACE,CAACA,UAAS,SAAS,KACnB,OAAO,UAAU,OAAO,YACxB,OAAO,UAAU,SAAS,UAC1B;AACA,aAAO;AAAA,IACT;AACA,aAAS,KAAK;AAAA,MACZ,IAAI,UAAU;AAAA,MACd,MAAM,UAAU;AAAA,MAChB,OAAO,OAAO,UAAU,UAAU,WAAW,UAAU,QAAQ;AAAA,MAC/D,GAAI,OAAO,UAAU,WAAW,WAAW,EAAE,QAAQ,UAAU,OAAO,IAAI,CAAC;AAAA,MAC3E,GAAIA,UAAS,UAAU,QAAQ,IAAI,EAAE,UAAU,UAAU,SAAS,IAAI,CAAC;AAAA,IACzE,CAAC;AAAA,EACH;AACA,SAAO;AACT;AAGO,SAAS,mBAAmB,OAA+C;AAChF,QAAM,MAAgB,CAAC;AACvB,aAAW,QAAQ,SAAS,CAAC,GAAG;AAC9B,QAAI,aAAa,IAAI,GAAG;AACtB,UAAI,KAAK,KAAK,IAAI;AAAA,IACpB;AAAA,EACF;AACA,SAAO,IAAI,KAAK,MAAM,EAAE,KAAK;AAC/B;AASO,SAAS,cAAc,OAAuC;AACnE,QAAM,cAAc,MAAM,cAAc,MAAM;AAC9C,SAAO;AAAA,IACL,GAAG;AAAA,IACH;AAAA,IACA,WAAW,cAAc,MAAM,OAAO;AAAA,IACtC,aAAa,kBAAkB,WAAW;AAAA,EAC5C;AACF;AAWO,SAAS,kBAAkB,WAA4D;AAC5F,MAAI,aAAa,MAAM;AACrB,WAAO;AAAA,EACT;AACA,QAAM,OAAO,IAAI,KAAK,SAAS;AAC/B,MAAI,OAAO,MAAM,KAAK,QAAQ,CAAC,GAAG;AAChC,WAAO;AAAA,EACT;AACA,SAAO;AAAA,IACL,KAAK;AAAA,IACL;AAAA,IACA,UAAU,mBAAmB,IAAI;AAAA,IACjC,UAAU,KAAK,eAAe,QAAW,EAAE,WAAW,UAAU,WAAW,QAAQ,CAAC;AAAA,EACtF;AACF;AAEA,IAAM,gBAAgB,IAAI,KAAK,mBAAmB,QAAW,EAAE,SAAS,QAAQ,OAAO,SAAS,CAAC;AACjG,IAAM,cAAc,IAAI,KAAK,KAAK,KAAK;AAMhC,SAAS,mBAAmB,MAAoB;AACrD,QAAM,SAAS,KAAK,IAAI,IAAI,KAAK,QAAQ;AACzC,MAAI,KAAK,IAAI,MAAM,IAAI,KAAQ;AAC7B,WAAO;AAAA,EACT;AACA,MAAI,SAAS,aAAa;AACxB,WAAO,KAAK,mBAAmB,QAAW,EAAE,OAAO,SAAS,KAAK,UAAU,CAAC;AAAA,EAC9E;AACA,QAAM,UAAU,KAAK,MAAM,CAAC,SAAS,GAAM;AAC3C,MAAI,KAAK,IAAI,OAAO,IAAI,IAAI;AAC1B,WAAO,cAAc,OAAO,SAAS,QAAQ;AAAA,EAC/C;AACA,QAAM,QAAQ,KAAK,MAAM,CAAC,SAAS,IAAS;AAC5C,MAAI,KAAK,IAAI,KAAK,IAAI,IAAI;AACxB,WAAO,cAAc,OAAO,OAAO,MAAM;AAAA,EAC3C;AACA,SAAO,cAAc,OAAO,KAAK,MAAM,CAAC,SAAS,KAAU,GAAG,KAAK;AACrE;AAEA,SAAS,kBAAkB,GAAmB;AAC5C,MAAI,IAAI,KAAO;AACb,WAAO,GAAG,CAAC;AAAA,EACb;AACA,MAAI,IAAI,KAAQ;AACd,WAAO,IAAI,IAAI,KAAO,QAAQ,CAAC,CAAC;AAAA,EAClC;AACA,SAAO,GAAG,KAAK,MAAM,IAAI,GAAK,CAAC;AACjC;AAEA,SAAS,cAAc,MAA6B;AAClD,MAAI,SAAS,MAAM;AACjB,WAAO;AAAA,EACT;AACA,MAAI,SAAS,GAAG;AACd,WAAO;AAAA,EACT;AACA,MAAI,OAAO,MAAM;AACf,WAAO,IAAI,KAAK,QAAQ,CAAC,CAAC;AAAA,EAC5B;AACA,MAAI,OAAO,GAAG;AACZ,WAAO,IAAI,KAAK,QAAQ,CAAC,CAAC;AAAA,EAC5B;AACA,SAAO,IAAI,KAAK,QAAQ,CAAC,CAAC;AAC5B;AAEA,SAAS,oBACP,aACA,UACmC;AACnC,MAAI,UAAU,QAAQ,SAAS,WAAY,QAAO;AAClD,QAAM,SACJ,SAAS,WAAW,YAChB,sBACA,SAAS,WAAW,aACjB,SAAS,mBAAmB,WAC7B;AACR,QAAM,SACJ,WAAW,sBACP,sBACA,WAAW,WACT,WACA,WAAW,cACT,cACA,WAAW,cACT,cACA,WAAW,WACT,WACA,SAAS,WAAW,YAClB,YACA,SAAS,WAAW,eAClB,aACA;AAClB,SAAO,EAAE,GAAG,aAAa,QAAQ,QAAQ,QAAQ,KAAK;AACxD;;;AK/yCA,SAAS,eAAAI,cAAa,aAAAC,aAAW,UAAAC,SAAQ,YAAAC,kBAAgB;AAmClD,SAAS,iBAAiB;AAAA,EAC/B;AAAA,EACA,YAAY;AACd,GAAwC;AACtC,QAAM,eAAeD,QAA2B,IAAI;AACpD,QAAM,CAAC,YAAY,aAAa,IAAIC,WAAS,IAAI;AAEjD,QAAM,UAAUH,aAAY,MAAM;AAChC,UAAM,UAAU,aAAa;AAC7B,QAAI,CAAC,SAAS;AACZ;AAAA,IACF;AACA,UAAM,WAAW,QAAQ,eAAe,QAAQ,YAAY,QAAQ;AACpE,kBAAc,YAAY,SAAS;AAAA,EACrC,GAAG,CAAC,SAAS,CAAC;AAEd,QAAM,iBAAiBA,aAAY,MAAM;AACvC,UAAM,UAAU,aAAa;AAC7B,QAAI,CAAC,SAAS;AACZ;AAAA,IACF;AACA,YAAQ,YAAY,QAAQ;AAC5B,kBAAc,IAAI;AAAA,EACpB,GAAG,CAAC,CAAC;AAEL,QAAM,eAAeA;AAAA,IACnB,CAAC,YAAgC;AAC/B,mBAAa,UAAU;AACvB,UAAI,SAAS;AACX,gBAAQ;AAAA,MACV;AAAA,IACF;AAAA,IACA,CAAC,OAAO;AAAA,EACV;AAKA,EAAAC,YAAU,MAAM;AACd,QAAI,YAAY;AACd,qBAAe;AAAA,IACjB;AAAA,EACF,GAAG,CAAC,YAAY,YAAY,cAAc,CAAC;AAE3C,QAAM,oBAAoBD;AAAA,IACxB,OAAO,EAAE,KAAK,cAAc,UAAU,QAAQ;AAAA,IAC9C,CAAC,cAAc,OAAO;AAAA,EACxB;AAEA,SAAO;AAAA,IACL;AAAA,IACA,kBAAkB,CAAC;AAAA,IACnB;AAAA,IACA;AAAA,EACF;AACF;;;AN7DA,IAAM,wBAAwB;AAC9B,IAAM,4BAA4B;AAClC,IAAM,wBAAwB;AA2PvB,SAAS,kBAAkB,SAAmD;AACnF,QAAM;AAAA,IACJ;AAAA,IACA;AAAA,IACA,sBAAsB;AAAA,IACtB,kBAAkB;AAAA,IAClB;AAAA,IACA;AAAA,EACF,IAAI;AAEJ,QAAM,SAASI,SAAO,OAAO;AAC7B,SAAO,UAAU;AAEjB,QAAM,CAAC,cAAc,eAAe,IAAIC,WAAS,mBAAmB;AACpE,QAAM,CAAC,eAAe,gBAAgB,IAAIA,WAAS,KAAK;AAGxD,QAAM,cAAc,WAAW,eAAe,WAAW;AACzD,QAAM,SAAS,WAAW,eAAe;AACzC,QAAM,UAAU,SAAS,WAAW;AAGpC,EAAAC,YAAU,MAAM;AACd,QAAI,CAAC,QAAQ;AACX,uBAAiB,KAAK;AAAA,IACxB;AAAA,EACF,GAAG,CAAC,MAAM,CAAC;AAEX,QAAM,cAAc,SAAS,GAAG,EAAE;AAClC,QAAM,gBAAgB,kBAAkB,QAAQ;AAChD,QAAM,qBAAqB,cAAe,eAAe,MAAM,OAAQ;AAEvE,QAAM,eAAe,KAAK,IAAI,GAAG,SAAS,SAAS,YAAY;AAC/D,QAAM,QAAQ,mBAAmB;AAAA,IAC/B;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,EACF,CAAC;AAED,QAAM,OAAOC,aAAY,MAAM;AAC7B,UAAM,UAAU,OAAO;AACvB,QACE,QAAQ,WAAW,eACnB,QAAQ,WAAW,eACnB,QAAQ,WAAW,gBACnB;AACA;AAAA,IACF;AACA,qBAAiB,IAAI;AACrB,SAAK,QAAQ,SAAS;AAAA,EACxB,GAAG,CAAC,CAAC;AAEL,QAAM,cAAcA;AAAA,IAClB,MACE;AAAA,MACE,CAAC,UAAU,SAAS,OAAO,QAAQ,mBAAmB;AAAA,IACxD;AAAA,IACF,CAAC;AAAA,EACH;AACA,QAAM,UAAUA,aAAY,MAAM,gBAAgB,OAAO,QAAQ,SAAS,MAAM,GAAG,CAAC,CAAC;AAErF,QAAM,SAAS,iBAAiB;AAAA,IAC9B,YAAY,iBAAiB,QAAQ;AAAA,IACrC,GAAI,2BAA2B,SAAY,EAAE,WAAW,uBAAuB,IAAI,CAAC;AAAA,EACtF,CAAC;AAED,QAAM,sBAAsB,UAAU,aAAa,SAAS;AAC5D,QAAM,SAAS,eAAe,QAAQ,SAAS,MAAM,QAAQ,aAAa,IAAI;AAE9E,SAAO;AAAA,IACL;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA,gBAAgB,WAAW,WAAW;AAAA,IACtC;AAAA,IACA,eACE,WAAW,WACX,CAAC,uBACD,aAAa,SAAS,eACtB,CAAC,CAAC,aACF,UAAU,SAAS;AAAA,IACrB,iBAAiB,eAAe,MAAM;AAAA,IACtC,QAAQ;AAAA,MACN;AAAA,MACA,aAAa;AAAA,MACb,gBAAgB,eAAe;AAAA,MAC/B;AAAA,MACA;AAAA,IACF;AAAA,IACA;AAAA,IACA,MAAM;AAAA,MACJ,WAAW,UAAU,QAAQ,aAAa,QAAQ,QAAQ,WAAW;AAAA,MACrE,YAAY;AAAA,MACZ;AAAA,IACF;AAAA,IACA;AAAA,IACA,aAAa,QAAQ,OAAO,UAAU;AAAA,EACxC;AACF;AAGA,SAAS,eACP,OACA,UACwB;AACxB,QAAM,cAAcH,SAAO,KAAK;AAChC,cAAY,UAAU;AACtB,QAAM,WAAWA,SAAO,oBAAI,IAAwB,CAAC;AACrD,QAAM,aAAaG,aAAY,CAAC,OAAe;AAC7C,QAAI,UAAU,SAAS,QAAQ,IAAI,EAAE;AACrC,QAAI,YAAY,QAAW;AACzB,gBAAU,MAAM;AACd,aAAK,YAAY,SAAS,SAAS,EAAE;AAAA,MACvC;AACA,eAAS,QAAQ,IAAI,IAAI,OAAO;AAAA,IAClC;AACA,WAAO;AAAA,EACT,GAAG,CAAC,CAAC;AACL,MAAI,UAAU,QAAQ,UAAU,QAAW;AACzC,WAAO,CAAC;AAAA,EACV;AACA,SAAO,MAAM,MAAM,IAAI,CAAC,SAAS,aAAa;AAC5C,UAAM,QACJ,QAAQ,UAAU,YAAY,YAAY,MAAM,WAAW,OAAO,WAAW;AAC/E,WAAO;AAAA,MACL,IAAI,QAAQ;AAAA,MACZ,MAAM;AAAA,MACN,MAAM,QAAQ;AAAA,MACd,QAAQ,QAAQ,SAAS,QAAQ,YAAY,IAAI,cAAc,GAAG,IAAI,CAAC,UAAU;AAAA,QAC/E,GAAG;AAAA,QACH,SAAS,KAAK,SAAS;AAAA,MACzB,EAAE;AAAA,MACF;AAAA,MACA;AAAA,MACA,QAAQ,aAAa;AAAA,MACrB,WAAW,QAAQ;AAAA,MACnB,QAAQ;AAAA,QACN,WAAW,CAAC,YAAY,UAAU,aAAa,MAAM,WAAW;AAAA,QAChE,KAAK,WAAW,QAAQ,EAAE;AAAA,MAC5B;AAAA,IACF;AAAA,EACF,CAAC;AACH;AAWO,SAAS,kBAAkB,SAAmD;AACnF,QAAM,EAAE,SAAS,cAAc,MAAM,IAAI;AACzC,QAAM,cAAcH,SAAoB,CAAC,OAAO,CAAC;AAGjD,MAAI,YAAY,QAAQ,CAAC,MAAM,SAAS;AACtC,gBAAY,UAAU,CAAC,OAAO;AAAA,EAChC;AACA,QAAM,QAAQ,mBAAmB;AAAA,IAC/B,UAAU,YAAY;AAAA,IACtB,cAAc;AAAA,IACd,oBAAoB,cAAc,QAAQ,KAAK;AAAA,IAC/C;AAAA,EACF,CAAC;AAED,SAAO,MAAM,CAAC;AAChB;AAgBA,SAAS,mBAAmB;AAAA,EAC1B;AAAA,EACA;AAAA,EACA;AAAA,EACA;AACF,GAA4C;AAC1C,QAAM,CAAC,QAAQ,SAAS,IAAIC,WAAsC,MAAM,oBAAI,IAAI,CAAC;AACjF,QAAM,CAAC,QAAQ,SAAS,IAAIA,WAA8B,MAAM,oBAAI,IAAI,CAAC;AACzE,QAAM,CAAC,eAAe,gBAAgB,IAAIA,WAAuC,MAAM,oBAAI,IAAI,CAAC;AAGhG,QAAM,CAAC,OAAO,QAAQ,IAAIA,WAAwC,MAAM,oBAAI,IAAI,CAAC;AAGjF,QAAM,CAAC,UAAU,WAAW,IAAIA,WAA4C,MAAM,oBAAI,IAAI,CAAC;AAC3F,QAAM,CAAC,cAAc,eAAe,IAAIA,WAEtC,MAAM,oBAAI,IAAI,CAAC;AAEjB,QAAM,UAAU,gBAAgB;AAChC,QAAM,WAAW,eAAe,SAAS,OAAO;AAChD,QAAM,SAASD,SAAO,EAAE,SAAS,UAAU,QAAQ,OAAO,SAAS,CAAC;AACpE,SAAO,UAAU,EAAE,SAAS,UAAU,QAAQ,OAAO,SAAS;AAE9D,QAAM,aAAaA,SAAO,oBAAI,IAA2C,CAAC;AAC1E,EAAAE;AAAA,IACE,MAAM,MAAM;AACV,iBAAW,SAAS,WAAW,QAAQ,OAAO,GAAG;AAC/C,qBAAa,KAAK;AAAA,MACpB;AACA,iBAAW,QAAQ,MAAM;AAAA,IAC3B;AAAA,IACA,CAAC;AAAA,EACH;AAEA,QAAM,gBAAgBF,SAAO,oBAAI,IAA2B,CAAC;AAC7D,QAAM,uBAAuBA,SAAO,oBAAI,IAAsC,CAAC;AAC/E,QAAM,WAAWA,SAAO,oBAAI,IAA6B,CAAC;AAE1D,QAAM,kBAAkBG,aAAY,CAAC,KAAa,SAAmB;AACnE,qBAAiB,CAAC,YAAY;AAC5B,YAAM,OAAO,IAAI,IAAI,OAAO;AAC5B,WAAK,IAAI,KAAK,QAAQ,EAAE,QAAQ,IAAI,GAAG,KAAK,MAAM;AAClD,aAAO;AAAA,IACT,CAAC;AAAA,EACH,GAAG,CAAC,CAAC;AAEL,QAAM,eAAeA;AAAA,IACnB,CAAC,QAAgB;AACf,UAAI,SAAS,qBAAqB,QAAQ,IAAI,GAAG;AACjD,UAAI,CAAC,QAAQ;AACX,iBAAS,CAAC,SAAmB,gBAAgB,KAAK,IAAI;AACtD,6BAAqB,QAAQ,IAAI,KAAK,MAAM;AAAA,MAC9C;AACA,aAAO;AAAA,IACT;AAAA,IACA,CAAC,eAAe;AAAA,EAClB;AAEA,QAAM,OAAOA,aAAY,CAAC,YAAoB,YAAoB,WAAqB;AACrF,aAAS,CAAC,YAAY,IAAI,IAAI,OAAO,EAAE,IAAI,QAAQ,YAAY,UAAU,GAAG,MAAM,CAAC;AAAA,EACrF,GAAG,CAAC,CAAC;AAOL,QAAM,SAASA;AAAA,IACb,CAAC,YAAoB,QAAsB,SAAqC;AAC9E,sBAAgB,CAAC,YAAY;AAC3B,YAAI,CAAC,QAAQ,IAAI,UAAU,GAAG;AAC5B,iBAAO;AAAA,QACT;AACA,cAAM,OAAO,IAAI,IAAI,OAAO;AAC5B,aAAK,OAAO,UAAU;AACtB,eAAO;AAAA,MACT,CAAC;AACD,kBAAY,CAAC,YAAY,IAAI,IAAI,OAAO,EAAE,IAAI,YAAY,MAAM,CAAC;AACjE,YAAM,SAAS,CAAC,UAAmB;AACjC,oBAAY,CAAC,YAAY;AACvB,gBAAM,OAAO,IAAI,IAAI,OAAO;AAC5B,eAAK,OAAO,UAAU;AACtB,iBAAO;AAAA,QACT,CAAC;AACD;AAAA,UAAgB,CAAC,YACf,IAAI,IAAI,OAAO,EAAE,IAAI,YAAY;AAAA,YAC/B,SAAS,iBAAiB,QAAQ,MAAM,UAAU;AAAA,YAClD,MAAM,gBAAgB,KAAK;AAAA,UAC7B,CAAC;AAAA,QACH;AAAA,MACF;AAGA,UAAI;AACF,aAAK,QAAQ,QAAQ,KAAK,CAAC,EAAE,MAAM,MAAM;AAAA,MAC3C,SAAS,OAAO;AACd,eAAO,KAAK;AAAA,MACd;AAAA,IACF;AAAA,IACA,CAAC;AAAA,EACH;AAEA,QAAM,SAASA;AAAA,IACb,CAAC,eAAuB;AACtB,YAAM,UAAU,OAAO;AACvB,YAAM,WAAW,QAAQ,SAAS;AAClC,UAAI,CAAC,UAAU;AACb;AAAA,MACF;AACA;AAAA,QAAO;AAAA,QAAY;AAAA,QAAU,MAC3B,SAAS,EAAE,YAAY,SAAS,WAAW,QAAQ,OAAO,UAAU,EAAE,CAAC;AAAA,MACzE;AAAA,IACF;AAAA,IACA,CAAC,MAAM;AAAA,EACT;AAEA,QAAM,OAAOA;AAAA,IACX,CAAC,eAAuB;AACtB,YAAM,SAAS,OAAO,QAAQ,SAAS;AACvC,UAAI,QAAQ;AACV,eAAO,YAAY,QAAQ,MAAM,OAAO,EAAE,WAAW,CAAC,CAAC;AAAA,MACzD;AAAA,IACF;AAAA,IACA,CAAC,MAAM;AAAA,EACT;AAEA,QAAM,UAAUA;AAAA,IACd,CAAC,YAAoBC,UAA0B,WAA4B;AACzE,YAAM,YAAY,OAAO,QAAQ,SAAS;AAC1C,UAAI,WAAW;AACb;AAAA,UAAO;AAAA,UAAY;AAAA,UAAW,MAC5B,UAAU;AAAA,YACR;AAAA,YACA,GAAI,WAAW,SAAY,CAAC,IAAI,EAAE,OAAO;AAAA,YACzC,GAAIA,UAAS,aAAa,OAAO,EAAE,UAAU,KAAK,IAAI,CAAC;AAAA,UACzD,CAAC;AAAA,QACH;AAAA,MACF;AAAA,IACF;AAAA,IACA,CAAC,MAAM;AAAA,EACT;AAEA,QAAM,SAASD;AAAA,IACb,CAAC,YAAoB,WAA4B;AAC/C,YAAM,WAAW,OAAO,QAAQ,SAAS;AACzC,UAAI,UAAU;AACZ;AAAA,UAAO;AAAA,UAAY;AAAA,UAAU,MAC3B,SAAS,EAAE,YAAY,GAAI,WAAW,SAAY,CAAC,IAAI,EAAE,OAAO,EAAG,CAAC;AAAA,QACtE;AAAA,MACF;AAAA,IACF;AAAA,IACA,CAAC,MAAM;AAAA,EACT;AAEA,QAAM,eAAeA,aAAY,CAAC,OAA8B;AAC9D,UAAM,SAAS,cAAc,QAAQ,IAAI,EAAE;AAC3C,QAAI,QAAQ;AACV,aAAO;AAAA,IACT;AACA,UAAM,UAAU,MACd,mBAAmB,OAAO,QAAQ,SAAS,KAAK,CAAC,YAAY,QAAQ,OAAO,EAAE,GAAG,KAAK;AACxF,UAAM,UAAyB;AAAA,MAC7B,MAAM,MAAM;AACV,cAAM,OAAO,QAAQ;AACrB,YAAI,CAAC,MAAM;AACT;AAAA,QACF;AACA,cAAM,QACJ,OAAO,QAAQ,QAAQ,mBACtB,CAAC,UAAkB,UAAU,UAAU,UAAU,KAAK;AACzD,aAAK,QAAQ,QAAQ,EAClB,KAAK,MAAM,MAAM,IAAI,CAAC,EACtB,KAAK,MAAM;AACV,oBAAU,CAAC,YAAY,IAAI,IAAI,OAAO,EAAE,IAAI,EAAE,CAAC;AAC/C,gBAAM,WAAW,WAAW,QAAQ,IAAI,EAAE;AAC1C,cAAI,UAAU;AACZ,yBAAa,QAAQ;AAAA,UACvB;AACA,qBAAW,QAAQ;AAAA,YACjB;AAAA,YACA,WAAW,MAAM;AACf,yBAAW,QAAQ,OAAO,EAAE;AAC5B,wBAAU,CAAC,YAAY;AACrB,sBAAM,OAAO,IAAI,IAAI,OAAO;AAC5B,qBAAK,OAAO,EAAE;AACd,uBAAO;AAAA,cACT,CAAC;AAAA,YACH,GAAG,OAAO,QAAQ,QAAQ,eAAe,qBAAqB;AAAA,UAChE;AAAA,QACF,CAAC,EACA,MAAM,MAAM;AAAA,QAEb,CAAC;AAAA,MACL;AAAA,MACA,WAAW,MAAM;AACf,cAAM,OAAO,QAAQ;AACrB,kBAAU,CAAC,YAAY,IAAI,IAAI,OAAO,EAAE,IAAI,IAAI,IAAI,CAAC;AAAA,MACvD;AAAA,MACA,YAAY,MAAM;AAChB,kBAAU,CAAC,YAAY;AACrB,gBAAM,OAAO,IAAI,IAAI,OAAO;AAC5B,eAAK,OAAO,EAAE;AACd,iBAAO;AAAA,QACT,CAAC;AAAA,MACH;AAAA,MACA,UAAU,CAAC,UAAkB;AAC3B,kBAAU,CAAC,YAAY,IAAI,IAAI,OAAO,EAAE,IAAI,IAAI,KAAK,CAAC;AAAA,MACxD;AAAA,MACA,MAAM,MAAM;AACV,cAAM,QAAQ,OAAO,QAAQ,OAAO,IAAI,EAAE,KAAK,IAAI,KAAK;AACxD,YAAI,CAAC,MAAM;AACT;AAAA,QACF;AACA,gBAAQ,WAAW;AACnB,aAAK,OAAO,QAAQ,QAAQ,eAAe,EAAE,WAAW,IAAI,MAAM,KAAK,CAAC;AAAA,MAC1E;AAAA,MACA,MAAM,MAAM;AACV,aAAK,OAAO,QAAQ,QAAQ,SAAS,EAAE,WAAW,GAAG,CAAC;AAAA,MACxD;AAAA,MACA,YAAY,MAAM;AAChB,aAAK,OAAO,QAAQ,QAAQ,eAAe,EAAE,WAAW,GAAG,CAAC;AAAA,MAC9D;AAAA,MACA,aAAa,CAAC,YAAwC;AACpD,YAAI,CAAC,SAAS;AACZ;AAAA,QACF;AACA,gBAAQ,MAAM;AACd,gBAAQ,kBAAkB,QAAQ,MAAM,QAAQ,QAAQ,MAAM,MAAM;AAAA,MACtE;AAAA,MACA,kBAAkB,CAAC,UAAkD;AACnE,gBAAQ,SAAS,MAAM,OAAO,KAAK;AAAA,MACrC;AAAA,MACA,mBAAmB,CAAC,UAAoD;AACtE,YAAI,MAAM,QAAQ,WAAW,CAAC,MAAM,UAAU;AAC5C,gBAAM,eAAe;AACrB,kBAAQ,KAAK;AAAA,QACf;AACA,YAAI,MAAM,QAAQ,UAAU;AAC1B,gBAAM,eAAe;AACrB,kBAAQ,WAAW;AAAA,QACrB;AAAA,MACF;AAAA,IACF;AACA,kBAAc,QAAQ,IAAI,IAAI,OAAO;AACrC,WAAO;AAAA,EACT,GAAG,CAAC,CAAC;AAEL,QAAM,kBAAkB,kBAAkB,QAAQ,GAAG,MAAM;AAC3D,QAAM,QAA0B,CAAC;AAEjC,QAAM,aAAa,SAAS;AAC5B,QAAM,SAAS,oBAAI,IAA6B;AAChD,QAAM,iBAAiB,CAAC,WACtB,OAAO,IAAI,CAAC,UAAU;AACpB,QAAI,MAAM,SAAS,KAAM,QAAO;AAChC,UAAM,OAAO,eAAe,WAAW,IAAI,MAAM,GAAG,GAAG,KAAK;AAC5D,WAAO,IAAI,MAAM,KAAK,IAAI;AAC1B,WAAO;AAAA,EACT,CAAC;AAEH,WAAS,QAAQ,cAAc,QAAQ,SAAS,QAAQ,SAAS;AAC/D,UAAM,UAAU,SAAS,KAAK;AAC9B,QAAI,CAAC,SAAS;AACZ;AAAA,IACF;AACA,UAAM,YAAY,aAAa,QAAQ,EAAE;AACzC,UAAM,QAAQ,OAAO,IAAI,QAAQ,EAAE;AACnC,UAAM,YAAY,UAAU;AAC5B,UAAM,OAAO,mBAAmB,QAAQ,KAAK;AAC7C,UAAM,SAAS,QAAQ,YAAY,mBAAmB,OAAO;AAC7D,UAAM,SAAS,QAAQ,SAAS;AAChC,UAAM,cAAc,QAAQ,SAAS;AACrC,UAAM,kBAAkB,eAAe,QAAQ,OAAO;AAEtD,UAAM,KAAK;AAAA,MACT,IAAI,QAAQ;AAAA,MACZ;AAAA,MACA,MAAM,QAAQ;AAAA,MACd;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA,aAAa,QAAQ,OAAO;AAAA,MAC5B,QAAQ;AAAA,QACN,sBAAsB,SAAS;AAAA,UAC7B,iBAAiB,CAAC,KAAK,mBAAmB,cAAc,IAAI,GAAG,KAAK;AAAA,UACpE,iBAAiB,CAAC,KAAK,SAAS,aAAa,GAAG,EAAE,IAAI;AAAA,UACtD,GAAI,QAAQ,YAAY,SAAY,EAAE,SAAS,QAAQ,QAAQ,IAAI,CAAC;AAAA,UACpE,GAAI,QAAQ,gBAAgB,SAAY,EAAE,aAAa,QAAQ,YAAY,IAAI,CAAC;AAAA;AAAA,UAEhF,GAAI,SAAS,aAAa,UACzB,QAAQ,aAAa,QAAQ,QAAQ,aAAa,OAC/C;AAAA,YACE,aAAa;AAAA,cACX,QAAQ,CAAC,YAAY,eAAe,MAAM,IAAI,QAAQ,YAAY,UAAU,CAAC;AAAA,cAC7E;AAAA,cACA,WAAW,SAAS,aAAa;AAAA,cACjC,SAAS,SAAS,WAAW;AAAA,cAC7B;AAAA,cACA;AAAA,cACA,YAAY,CAAC,eAAe,SAAS,IAAI,UAAU,KAAK;AAAA,cACxD,SAAS,CAAC,eAAe,aAAa,IAAI,UAAU,GAAG,WAAW;AAAA,cAClE,aAAa,CAAC,eAAe,aAAa,IAAI,UAAU,GAAG,QAAQ;AAAA,YACrE;AAAA,UACF,IACA,CAAC;AAAA,UACL,GAAI,SAAS,cAAc,UAAa,SAAS,aAAa,SAC1D;AAAA,YACE,UAAU;AAAA,cACR,YAAY,SAAS,cAAc;AAAA,cACnC,WAAW,SAAS,aAAa;AAAA,cACjC;AAAA,cACA;AAAA,cACA,YAAY,CAAC,eAAe,SAAS,IAAI,UAAU,KAAK;AAAA,cACxD,SAAS,CAAC,eAAe,aAAa,IAAI,UAAU,GAAG,WAAW;AAAA,cAClE,aAAa,CAAC,eAAe,aAAa,IAAI,UAAU,GAAG,QAAQ;AAAA,YACrE;AAAA,UACF,IACA,CAAC;AAAA,QACP,CAAC;AAAA,MACH;AAAA,MACA;AAAA,MACA,OAAO,QAAQ,cAAc,KAAK,IAAI;AAAA,MACtC,WAAW,mBAAmB,QAAQ,gBAAgB,uBAAuB,OAAO,CAAC;AAAA,MACrF,MAAM;AAAA,QACJ,WAAW,KAAK,SAAS;AAAA,QACzB,QAAQ,OAAO,IAAI,QAAQ,EAAE;AAAA,QAC7B,MAAM,UAAU;AAAA,MAClB;AAAA,MACA,MAAM;AAAA,QACJ,WACE,UACA,QAAQ,aAAa,QACrB,QAAQ,aAAa,QACrB,QAAQ,iBAAiB;AAAA,QAC3B;AAAA,QACA,OAAO,SAAS;AAAA,QAChB,UAAU,SAAS,IAAI,KAAK,EAAE,SAAS;AAAA,QACvC,OAAO,UAAU;AAAA,QACjB,QAAQ,UAAU;AAAA,QAClB,UAAU,UAAU;AAAA,QACpB,MAAM,UAAU;AAAA,QAChB,kBAAkB,OAAO;AAAA,UACvB,KAAK,UAAU;AAAA,UACf,OAAO,SAAS;AAAA,UAChB,UAAU,UAAU;AAAA,UACpB,WAAW,UAAU;AAAA,QACvB;AAAA,MACF;AAAA,MACA,MAAM;AAAA,QACJ,WAAW,QAAQ,aAAa,QAAQ,QAAQ,WAAW;AAAA,QAC3D,KAAK,UAAU;AAAA,MACjB;AAAA,MACA,YAAY;AAAA,QACV,WACE,mBACA,QAAQ,aAAa,QACrB,QAAQ,kBAAkB,QAC1B,QAAQ,iBAAiB;AAAA,QAC3B,KAAK,UAAU;AAAA,MACjB;AAAA,IACF,CAAC;AAAA,EACH;AAEA,WAAS,UAAU;AACnB,SAAO;AACT;AA0BA,SAAS,eAAe,SAAgC,SAAuC;AAC7F,QAAM,OAAO,CAAI,KAA2BE,cAC1C,QAAQ,aAAa,QAAQ,QAAQ,OAAO,SAAa,OAAOA;AAClE,SAAO;AAAA,IACL,UAAU;AAAA,MACR,QAAQ;AAAA,MACR,QAAQ,iBACJ,OAAO,UAAU;AACf,cAAM,QAAQ,iBAAiB,KAAK;AAAA,MACtC,IACA;AAAA,IACN;AAAA,IACA,QAAQ;AAAA,MACN,QAAQ;AAAA,MACR,QAAQ,eACJ,OAAO,UAAU;AACf,cAAM,QAAQ,eAAe,KAAK;AAAA,MACpC,IACA;AAAA,IACN;AAAA,IACA,WAAW;AAAA,MACT,QAAQ;AAAA,MACR,QAAQ,mBAAmB,QAAQ,wBAC/B,OAAO,UAAU;AACf,YAAI,MAAM,QAAQ,SAAS,YAAY;AACrC,cAAI,MAAM,OAAO,aAAa;AAC5B,kBAAM,IAAI,MAAM,+CAA+C;AACjE,gBAAM;AAAA,YACJ;AAAA,YACA;AAAA,UACF,EAAE;AAAA,YACA,UAAU,MAAM,OAAO;AAAA,YACvB,YAAY,MAAM,OAAO;AAAA,YACzB,GAAI,MAAM,aAAa,SAAY,CAAC,IAAI,EAAE,UAAU,MAAM,SAAS;AAAA,UACrE,CAAC;AAAA,QACH,MAAO,OAAM,qBAAqB,SAAS,iBAAiB,EAAE,KAAK;AAAA,MACrE,IACA;AAAA,IACN;AAAA,IACA,UAAU;AAAA,MACR,QAAQ;AAAA,MACR,QAAQ,kBAAkB,QAAQ,uBAC9B,OAAO,UAAU;AACf,YAAI,MAAM,QAAQ,SAAS,YAAY;AACrC,cAAI,MAAM,OAAO,aAAa;AAC5B,kBAAM,IAAI,MAAM,+CAA+C;AACjE,gBAAM;AAAA,YACJ;AAAA,YACA;AAAA,UACF,EAAE;AAAA,YACA,UAAU,MAAM,OAAO;AAAA,YACvB,YAAY,MAAM,OAAO;AAAA,YACzB,GAAI,MAAM,WAAW,SAAY,CAAC,IAAI,EAAE,QAAQ,MAAM,OAAO;AAAA,UAC/D,CAAC;AAAA,QACH,MAAO,OAAM,qBAAqB,SAAS,gBAAgB,EAAE,KAAK;AAAA,MACpE,IACA;AAAA,IACN;AAAA,EACF;AACF;AAEA,SAASC,YAAW,SAA0C;AAC5D,QAAM,WAAW,QAAQ;AACzB,SAAO,aAAa,QAAQ,OAAO,aAAa,WAC3C,WACD,CAAC;AACP;AAGA,SAAS,kBAAkB,SAA6C;AACtE,QAAM,QAAQA,YAAW,OAAO,EAAE;AAClC,MAAI,UAAU,OAAW,QAAO;AAChC,SAAO;AAAA,IACL,aAAa,MAAM;AAAA,IACnB,cAAc,MAAM;AAAA,IACpB,SAAS,MAAM,WAAW;AAAA,EAC5B;AACF;AAGA,SAAS,sBAAsB,SAAmC;AAChE,SAAOA,YAAW,OAAO,EAAE,aAAa;AAC1C;AAGA,SAAS,QAAQ,YAAoB,YAA4B;AAC/D,SAAO,GAAG,UAAU,IAAI,UAAU;AACpC;AAGA,SAAS,WACP,OACA,YAC0B;AAC1B,QAAM,SAAS,GAAG,UAAU;AAC5B,QAAM,UAAoC,CAAC;AAC3C,aAAW,CAAC,KAAK,MAAM,KAAK,OAAO;AACjC,QAAI,IAAI,WAAW,MAAM,GAAG;AAC1B,cAAQ,IAAI,MAAM,OAAO,MAAM,CAAC,IAAI;AAAA,IACtC;AAAA,EACF;AACA,SAAO;AACT;AAEA,SAAS,kBAAkB,UAA8C;AACvE,WAAS,QAAQ,SAAS,SAAS,GAAG,SAAS,GAAG,SAAS;AACzD,UAAM,UAAU,SAAS,KAAK;AAC9B,QAAI,SAAS,SAAS,aAAa;AACjC,aAAO;AAAA,IACT;AAAA,EACF;AACA,SAAO;AACT;AAMA,SAAS,iBAAiB,UAA+B;AACvD,QAAM,OAAO,SAAS,GAAG,EAAE;AAC3B,MAAI,CAAC,MAAM;AACT,WAAO;AAAA,EACT;AACA,MAAI,SAAS;AACb,aAAW,QAAQ,KAAK,SAAS,CAAC,GAAG;AACnC,QAAI,UAAU,QAAQ,OAAO,KAAK,SAAS,UAAU;AACnD,gBAAU,KAAK,KAAK;AAAA,IACtB;AAAA,EACF;AACA,SAAO,GAAG,SAAS,MAAM,IAAI,KAAK,EAAE,IAAI,KAAK,OAAO,UAAU,CAAC,IAAI,MAAM;AAC3E;AAGA,SAAS,gBAAgB,OAA+B;AACtD,QAAM,OAAQ,OAAqC;AACnD,SAAO,OAAO,SAAS,YAAY,SAAS,KAAK,OAAO;AAC1D;;;ADz1BS,gBAAAC,MA8CD,QAAAC,aA9CC;AAvBF,SAAS,YAAY;AAAA,EAC1B;AAAA,EACA,cAAc;AAAA,EACd;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA,GAAG;AACL,GAAqB;AACnB,QAAM,OAAO,kBAAkB;AAAA,IAC7B;AAAA,IACA;AAAA,IACA,GAAI,aAAa,SAAY,EAAE,SAAS,IAAI,CAAC;AAAA,IAC7C,GAAI,eAAe,EAAE,aAAa,IAAI,CAAC;AAAA,IACvC,GAAI,SAAS,EAAE,OAAO,IAAI,CAAC;AAAA,IAC3B,GAAI,kBAAkB,SAAY,EAAE,cAAc,IAAI,CAAC;AAAA,IACvD,GAAI,eAAe,EAAE,aAAa,IAAI,CAAC;AAAA,IACvC,GAAI,SAAS,OAAO,EAAE,UAAU,MAAM,MAAM,IAAI,CAAC;AAAA,IACjD,GAAI,aAAa,OAAO,EAAE,cAAc,MAAM,UAAU,IAAI,CAAC;AAAA,EAC/D,CAAC;AACD,SAAO,gBAAAD,KAAC,mBAAgB,MAAa,GAAG,OAAO;AACjD;AAGO,SAAS,gBAAgB,EAAE,MAAM,GAAG,MAAM,GAAyB;AAExE,QAAM,kBAAkB,mBAAmB;AAC3C,QAAM,QACJ,MAAM,aAAa,UAAa,oBAAoB,OAChD,EAAE,GAAG,OAAO,UAAU,gBAAgB,IACtC;AACN,QAAM,EAAE,WAAW,IAAI;AACvB,QAAM,YACJ,gBAAAC,MAAC,SAAI,WAAW,YAAY,SAAS,oBAAkB,KAAK,MACzD;AAAA,SAAK,KAAK,YACT,gBAAAD;AAAA,MAAC;AAAA;AAAA,QACC,MAAK;AAAA,QACL,SAAS,KAAK,KAAK;AAAA,QACnB,WAAW,YAAY;AAAA,QACvB,OAAO,KAAK,KAAK,SAAS,YAAY;AAAA,QAErC,eAAK,KAAK,SAAS,WAAW;AAAA;AAAA,IACjC,IACE;AAAA,IACH,KAAK,KAAK,YACT,gBAAAA;AAAA,MAAC;AAAA;AAAA,QACC,MAAK;AAAA,QACL,SAAS,KAAK,KAAK;AAAA,QACnB,WAAW,YAAY;AAAA,QACvB,OAAM;AAAA,QACP;AAAA;AAAA,IAED,IACE;AAAA,IACH,KAAK,WAAW,YACf,gBAAAA;AAAA,MAAC;AAAA;AAAA,QACC,MAAK;AAAA,QACL,SAAS,KAAK,WAAW;AAAA,QACzB,WAAW,YAAY;AAAA,QACvB,OAAM;AAAA,QACP;AAAA;AAAA,IAED,IACE;AAAA,IACH,MAAM;AAAA,IACN,CAAC,KAAK,UAAU,KAAK,QACpB,gBAAAC;AAAA,MAAC;AAAA;AAAA,QACC,WAAW,YAAY;AAAA,QACvB,OAAO,SAAS,KAAK,MAAM,YAAY,eAAe,CAAC,gBAAa,KAAK,MAAM,aAAa,eAAe,CAAC;AAAA,QAE3G;AAAA,eAAK,MAAM;AAAA,UAAU;AAAA,UAAI,KAAK,MAAM;AAAA;AAAA;AAAA,IACvC,IACE;AAAA,IACH,KAAK,YACJ,gBAAAD,KAAC,UAAK,WAAW,YAAY,WAAW,OAAO,KAAK,UAAU,UAC3D,eAAK,UAAU,UAClB,IACE;AAAA,KACN;AAGF,MAAI,KAAK,KAAK,WAAW;AACvB,WAAO,gBAAAA,KAAC,sBAAmB,MAAY,OAAc,SAAS,WAAW;AAAA,EAC3E;AAEA,QAAM,YAAY,YAAY,YAAY,MAAM,YAAY,SAAS,KAAK,IAAI,CAAC;AAE/E,SACE,gBAAAC;AAAA,IAAC;AAAA;AAAA,MACC;AAAA,MACA,aAAW,KAAK;AAAA,MAChB,kBAAgB,KAAK,cAAc,SAAS;AAAA,MAE5C;AAAA,wBAAAD,KAAC,SAAK,uBAAa,MAAM,KAAK,GAAE;AAAA,QAC/B;AAAA;AAAA;AAAA,EACH;AAEJ;AAGA,SAAS,aAAa,MAAsB,OAA8C;AACxF,QAAM,QAA2B,CAAC;AAClC,aAAW,SAAS,KAAK,QAAQ;AAC/B,QAAI,MAAM,SAAS,QAAQ;AACzB,YAAM;AAAA,QACJ,gBAAAA,KAAC,SAAoB,WAAW,MAAM,YAAY,MAC/C,gBAAM,aACH,MAAM,WAAW,MAAM,MAAM,EAAE,aAAa,KAAK,YAAY,CAAC,IAC9D,MAAM,QAHF,MAAM,GAIhB;AAAA,MACF;AACA;AAAA,IACF;AACA,QAAI,MAAM,SAAS,aAAa;AAC9B,YAAM,KAAK,qBAAqB,OAAO,KAAK,CAAC;AAC7C;AAAA,IACF;AACA,QAAI,MAAM,SAAS,SAAS;AAC1B,YAAM,KAAK,iBAAiB,OAAO,KAAK,CAAC;AACzC;AAAA,IACF;AACA,QAAI,MAAM,SAAS,SAAS;AAC1B,YAAM,KAAK,GAAG,gBAAgB,MAAM,OAAO,KAAK,CAAC;AACjD;AAAA,IACF;AACA,QAAI,MAAM,SAAS,QAAQ,MAAM,UAAU;AACzC,YAAM;AAAA,QACJ,gBAAAA,KAAC,SAAoB,aAAU,MAAK,kBAAgB,MAAM,WACvD,gBAAM,SAAS,KAAK,KADb,MAAM,GAEhB;AAAA,MACF;AAAA,IACF;AAAA,EACF;AACA,SAAO;AACT;AAMA,SAAS,iBACP,OACA,OACiB;AACjB,SACE,gBAAAA,KAAC,SAAoB,WAAW,MAAM,YAAY,OAAO,cAAW,QACjE,gBAAM,cACH,MAAM,YAAY,MAAM,KAAK,IAC7B,MAAM,MAAM,IAAI,CAAC,SACf,gBAAAA;AAAA,IAAC;AAAA;AAAA,MAEC,MAAM,KAAK;AAAA,MACX,QAAO;AAAA,MACP,KAAI;AAAA,MACJ,WAAW,MAAM,YAAY;AAAA,MAC7B,OAAO,KAAK,YAAY,KAAK;AAAA,MAE5B,eAAK,UACJ,gBAAAA;AAAA,QAAC;AAAA;AAAA,UACC,KAAK,KAAK;AAAA,UACV,KAAK,KAAK,YAAY;AAAA,UACtB,WAAW,MAAM,YAAY;AAAA;AAAA,MAC/B,IAEC,KAAK,YAAY,KAAK;AAAA;AAAA,IAdpB,KAAK;AAAA,EAgBZ,CACD,KAtBG,MAAM,GAuBhB;AAEJ;AAEA,SAAS,qBACP,OACA,OACiB;AACjB,SACE,gBAAAC;AAAA,IAAC;AAAA;AAAA,MAEC,WAAW,MAAM,YAAY;AAAA,MAC7B,kBAAe;AAAA,MACf,kBAAgB,MAAM,cAAc,SAAS;AAAA,MAE7C;AAAA,wBAAAD;AAAA,UAAC;AAAA;AAAA,YACC,MAAK;AAAA,YACL,WAAW,MAAM,YAAY;AAAA,YAC7B,SAAS,MAAM,MAAM,OAAO;AAAA,YAC5B,iBAAe,MAAM;AAAA,YAEpB,gBAAM,kBAAkB;AAAA;AAAA,QAC3B;AAAA,QACC,MAAM,SACL,gBAAAA,KAAC,SAAI,WAAW,MAAM,YAAY,eAC/B,gBAAM,kBACH,MAAM,gBAAgB,MAAM,MAAM;AAAA,UAChC,aAAa,MAAM;AAAA,UACnB,QAAQ,MAAM;AAAA,QAChB,CAAC,IACD,MAAM,MACZ,IACE;AAAA;AAAA;AAAA,IAtBC,MAAM;AAAA,EAuBb;AAEJ;AAEA,SAAS,gBACP,MACA,OACA,OACmB;AACnB,MAAI,MAAM,iBAAiB;AACzB,WAAO;AAAA,MACL,gBAAAA,KAACE,OAAM,UAAN,EACE,gBAAM,gBAAgB,MAAM,OAAO,MAAM,GAAG,KAD1B,MAAM,GAE3B;AAAA,IACF;AAAA,EACF;AACA,MAAI,CAAC,MAAM,gBAAgB;AACzB,WAAO,CAAC;AAAA,EACV;AACA,QAAM,iBAAiB,MAAM;AAC7B,SAAO,MAAM,MAAM,IAAI,CAAC,SAAS;AAC/B,UAAM,UAAU,GAAG,KAAK,EAAE,IAAI,KAAK,UAAU;AAC7C,WAAO,gBAAAF,KAACE,OAAM,UAAN,EAA8B,yBAAe,MAAM,OAAO,KAAtC,OAAwC;AAAA,EACtE,CAAC;AACH;AAQA,SAAS,mBAAmB,EAAE,MAAM,OAAO,QAAQ,GAA4B;AAC7E,QAAM,EAAE,WAAW,IAAI;AACvB,QAAM,EAAE,KAAK,IAAI;AAEjB,MAAI,CAAC,KAAK,WAAW;AACnB,WACE,gBAAAD,MAAC,SAAI,WAAW,YAAY,YAAY,MAAM,YAAY,QAAQ,IAAI,GAAG,aAAU,QACjF;AAAA,sBAAAD,KAAC,SAAI,WAAW,YAAY,MACzB,gBAAM,aAAa,MAAM,WAAW,KAAK,MAAM,EAAE,aAAa,MAAM,CAAC,IAAI,KAAK,MACjF;AAAA,MACA,gBAAAA;AAAA,QAAC;AAAA;AAAA,UACC,MAAK;AAAA,UACL,SAAS,KAAK;AAAA,UACd,WAAW,YAAY;AAAA,UACvB,OAAM;AAAA,UACP;AAAA;AAAA,MAED;AAAA,MACC;AAAA,OACH;AAAA,EAEJ;AAEA,QAAM,gBAAgB,KAAK,iBAAiB;AAC5C,SACE,gBAAAC,MAAC,SAAI,gBAAa,QAChB;AAAA,oBAAAD;AAAA,MAAC;AAAA;AAAA,QACE,GAAG;AAAA,QACJ,MAAM,KAAK,IAAI,GAAG,KAAK,MAAM,MAAM,IAAI,EAAE,SAAS,CAAC;AAAA,QACnD,WAAW,YAAY;AAAA;AAAA,IACzB;AAAA,IACA,gBAAAC,MAAC,SAAI,WAAW,YAAY,aAC1B;AAAA,sBAAAD,KAAC,YAAO,MAAK,UAAS,SAAS,KAAK,QAAQ,oBAE5C;AAAA,MACA,gBAAAA,KAAC,YAAO,MAAK,UAAS,SAAS,KAAK,MAAM,UAAU,CAAC,KAAK,SAAS,oBAEnE;AAAA,OACF;AAAA,KACF;AAEJ;AAEA,SAAS,eAAe,SAAwD;AAC9E,QAAM,SAAS,QAAQ,OAAO,CAAC,UAAU,KAAK,EAAE,KAAK,GAAG;AACxD,SAAO,WAAW,KAAK,SAAY;AACrC;;;AQ/PW,gBAAAG,MAiBH,QAAAC,aAjBG;AA9CJ,SAAS,YAAY;AAAA,EAC1B;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AACF,GAAqB;AACnB,QAAM,aAAa,kBAAkB;AAAA,IACnC;AAAA,IACA;AAAA,IACA,GAAI,aAAa,SAAY,EAAE,SAAS,IAAI,CAAC;AAAA,IAC7C,GAAI,SAAS,EAAE,OAAO,IAAI,CAAC;AAAA,IAC3B,GAAI,aAAa,SAAY,EAAE,SAAS,IAAI,CAAC;AAAA,IAC7C,GAAI,eAAe,EAAE,aAAa,IAAI,CAAC;AAAA,IACvC,GAAI,kBAAkB,SAAY,EAAE,cAAc,IAAI,CAAC;AAAA,IACvD,GAAI,eAAe,EAAE,aAAa,IAAI,CAAC;AAAA,IACvC,GAAI,WAAW,EAAE,SAAS,IAAI,CAAC;AAAA,IAC/B,GAAI,eAAe,EAAE,aAAa,IAAI,CAAC;AAAA,IACvC,GAAI,cAAc,SAAY,EAAE,UAAU,IAAI,CAAC;AAAA,IAC/C,GAAI,UAAU,SACV,EAAE,OAAO,EAAE,OAAO,MAAM,OAAO,QAAQ,MAAM,QAAQ,QAAQ,MAAM,OAAO,EAAE,IAC5E,CAAC;AAAA,EACP,CAAC;AAED,MAAI,WAAW,kBAAkB,WAAW,OAAO,WAAW,GAAG;AAC/D,WAAO,gBAAAD,KAAC,SAAI,WAAW,YAAY,OAAQ,sBAAW;AAAA,EACxD;AAEA,QAAM,QAAQ;AAAA,IACZ,GAAI,iBAAiB,EAAE,eAAe,IAAI,CAAC;AAAA,IAC3C,GAAI,kBAAkB,EAAE,gBAAgB,IAAI,CAAC;AAAA,IAC7C,GAAI,aAAa,EAAE,WAAW,IAAI,CAAC;AAAA,IACnC,GAAI,kBAAkB,EAAE,gBAAgB,IAAI,CAAC;AAAA,IAC7C,GAAI,cAAc,EAAE,YAAY,IAAI,CAAC;AAAA,IACrC,GAAI,WAAW,EAAE,SAAS,IAAI,CAAC;AAAA,IAC/B,GAAI,mBAAmB,SAAY,EAAE,eAAe,IAAI,CAAC;AAAA,IACzD,GAAI,YAAY,UAAU,EAAE,YAAY,WAAW,QAAQ,IAAI,CAAC;AAAA,EAClE;AAEA,SACE,gBAAAC,MAAC,SAAI,WAAW,YAAY,MACzB;AAAA,eAAW,OAAO,iBACjB,gBAAAA;AAAA,MAAC;AAAA;AAAA,QACC,MAAK;AAAA,QACL,WAAW,YAAY;AAAA,QACvB,SAAS,WAAW,OAAO;AAAA,QAC5B;AAAA;AAAA,UACgB,WAAW,OAAO;AAAA,UAAY;AAAA;AAAA;AAAA,IAC/C,IACE;AAAA,IACH,WAAW,MAAM,IAAI,CAAC,SACrB,gBAAAD;AAAA,MAAC;AAAA;AAAA,QAEC;AAAA,QACC,GAAG;AAAA,QACH,GAAI,UAAU,EAAE,MAAM,QAAQ,KAAK,OAAO,EAAE,IAAI,CAAC;AAAA;AAAA,MAH7C,KAAK;AAAA,IAIZ,CACD;AAAA,IACA,WAAW,OAAO,SAAS,IAC1B,gBAAAC,MAAC,SAAI,WAAW,YAAY,OACzB;AAAA,iBAAW,OAAO,IAAI,CAAC,SACtB,gBAAAA,MAAC,SAAkB,WAAW,YAAY,YAAY,cAAY,KAAK,OACrE;AAAA,wBAAAD,KAAC,UAAM,eAAK,MAAK;AAAA,QAChB,KAAK,OAAO,YACX,gBAAAA;AAAA,UAAC;AAAA;AAAA,YACC,MAAK;AAAA,YACL,WAAW,YAAY;AAAA,YACvB,SAAS,KAAK,OAAO;AAAA,YACtB;AAAA;AAAA,QAED,IACE;AAAA,WAVI,KAAK,EAWf,CACD;AAAA,MACA,WAAW,gBAAgB,QAAQ,UAAU,SAC5C,gBAAAC,MAAC,SAAI,WAAW,YAAY,aAC1B;AAAA,wBAAAD,KAAC,UAAK,0BAAY;AAAA,QAClB,gBAAAA;AAAA,UAAC;AAAA;AAAA,YACC,MAAK;AAAA,YACL,WAAW,YAAY;AAAA,YACvB,SAAS,MAAM,KAAK,MAAM,OAAO;AAAA,YAClC;AAAA;AAAA,QAED;AAAA,SACF,IACE;AAAA,OACN,IACE;AAAA,IACH,WAAW,sBACV,gBAAAA,KAAC,SAAI,WAAW,YAAY,QAAS,6BAAmB,kBAAY,IAClE;AAAA,IACH,SAAS,UACR,gBAAAC,MAAC,SAAI,WAAW,YAAY,OAC1B;AAAA,sBAAAD,KAAC,UAAM,gBAAM,WAAW,iCAAgC;AAAA,MACxD,gBAAAA,KAAC,YAAO,MAAK,UAAS,WAAW,YAAY,YAAY,SAAS,MAAM,KAAK,QAAQ,GAAG,mBAExF;AAAA,OACF,IACE;AAAA,IACH,WAAW,iBAAiB,mBAAmB,YAC9C,gBAAAA,KAAC,SAAI,WAAW,YAAY,WACzB,oBAAU,IAAI,CAAC,SACd,gBAAAA;AAAA,MAAC;AAAA;AAAA,QAEC,MAAK;AAAA,QACL,WAAW,YAAY;AAAA,QACvB,SAAS,MAAM,gBAAgB,IAAI;AAAA,QAElC;AAAA;AAAA,MALI;AAAA,IAMP,CACD,GACH,IACE;AAAA,KACN;AAEJ;;;AC/NO,IAAM,sBAAsB;AAE5B,IAAM,mBAAkD;AAAA,EAC7D,EAAE,KAAK,SAAS,OAAO,eAAe;AAAA,EACtC,EAAE,KAAK,SAAS,OAAO,eAAe;AAAA,EACtC,EAAE,KAAK,SAAS,OAAO,sBAAsB;AAAA,EAC7C,EAAE,KAAK,SAAS,OAAO,kBAAkB;AAC3C;AAEA,IAAM,cAAc;AAOb,SAAS,uBAA+B;AAC7C,MAAI,OAAO,WAAW,YAAa,QAAO;AAC1C,MAAI;AACF,UAAM,MAAM,OAAO,aAAa,QAAQ,WAAW;AACnD,QAAI,OAAO,iBAAiB,KAAK,CAAC,aAAa,SAAS,QAAQ,GAAG,GAAG;AACpE,aAAO;AAAA,IACT;AAAA,EACF,QAAQ;AAAA,EAER;AACA,SAAO;AACT;AAEO,SAAS,kBAAkB,KAAmB;AACnD,MAAI,OAAO,WAAW,YAAa;AACnC,MAAI;AACF,WAAO,aAAa,QAAQ,aAAa,GAAG;AAAA,EAC9C,QAAQ;AAAA,EAER;AACF;;;AC2BA,IAAM,aAAa;AAOZ,SAAS,kBACd,MACA,OACA,SACqB;AACrB,QAAM,MAAM,KAAK,IAAI,GAAG,KAAK,IAAI,OAAO,KAAK,MAAM,CAAC;AACpD,WAAS,QAAQ,MAAM,GAAG,SAAS,GAAG,SAAS;AAC7C,UAAM,OAAO,KAAK,KAAK;AACvB,QAAI,SAAS,UAAa,WAAW,KAAK,IAAI,GAAG;AAC/C,aAAO;AAAA,IACT;AACA,UAAM,SAAS,QAAQ,KAAK,CAAC,cAAc,UAAU,YAAY,IAAI;AAGrE,QAAI,UAAU,YAAY,MAAM,OAAO,OAAO,QAAQ,GAAG;AACvD,aAAO,EAAE,QAAQ,OAAO,OAAO,KAAK,MAAM,QAAQ,GAAG,GAAG,EAAE;AAAA,IAC5D;AAAA,EACF;AACA,SAAO;AACT;AAEA,SAAS,YAAY,MAAc,OAAe,UAAoC;AACpF,MAAI,UAAU,GAAG;AACf,WAAO;AAAA,EACT;AACA,MAAI,aAAa,SAAS;AACxB,WAAO;AAAA,EACT;AACA,QAAM,WAAW,KAAK,QAAQ,CAAC;AAC/B,SAAO,aAAa,UAAa,WAAW,KAAK,QAAQ;AAC3D;AAGO,SAAS,wBACd,OACA,OACoB;AAEpB,QAAM,SAAS,MAAM,KAAK,EAAE,YAAY;AACxC,SAAO,MAAM;AAAA,IACX,CAAC,SACC,KAAK,MAAM,YAAY,EAAE,SAAS,MAAM,MACvC,KAAK,aAAa,YAAY,EAAE,SAAS,MAAM,KAAK;AAAA,EACzD;AACF;AAOO,SAAS,gBACd,MACA,OACA,OACA,MACgB;AAChB,QAAM,MAAM,KAAK,IAAI,MAAM,OAAO,KAAK,IAAI,OAAO,KAAK,MAAM,CAAC;AAC9D,QAAM,WAAW,GAAG,MAAM,OAAO,OAAO,GAAG,KAAK,SAAS,KAAK,KAAK,GAAG,MAAM,OAAO,gBAAgB,GAAG;AACtG,SAAO;AAAA,IACL,MAAM,KAAK,MAAM,GAAG,MAAM,KAAK,IAAI,WAAW,KAAK,MAAM,GAAG;AAAA,IAC5D,OAAO,MAAM,QAAQ,SAAS;AAAA,EAChC;AACF;;;ACnHO,SAAS,mBAAmB,SAAkD;AAQnF,QAAM,WAAW,oBAAI,IAAyC;AAE9D,SAAO;AAAA,IACL,IAAI;AAAA,IACJ,OAAO,QAAQ,SAAS;AAAA,IACxB,SAAS,QAAQ,WAAW;AAAA,IAC5B,UAAU;AAAA,IACV,UAAU,MAAM;AACd,YAAM,WAAW,QAAQ,cAAc;AACvC,YAAM,MAAM,YAAY;AACxB,YAAM,SAAS,SAAS,IAAI,GAAG;AAC/B,UAAI,QAAQ;AACV,eAAO;AAAA,MACT;AACA,YAAM,aAAa,QAAQ,QAAQ;AACnC,UAAI,eAAe,QAAW;AAC5B,eAAO,QAAQ,OAAO,IAAI,6BAA6B,YAAY,CAAC;AAAA,MACtE;AACA,YAAM,UAAU,WACb,KAAK,QAAQ,SAAS,QAAQ,EAC9B,KAAK,CAAC,YAAY,QAAQ,IAAI,MAAM,CAAC,EACrC,MAAM,CAAC,UAAmB;AACzB,iBAAS,OAAO,GAAG;AACnB,cAAM;AAAA,MACR,CAAC;AACH,eAAS,IAAI,KAAK,OAAO;AACzB,aAAO;AAAA,IACT;AAAA,EACF;AACF;AAEA,SAAS,OAAO,OAA4C;AAC1D,QAAM,OAA4B;AAAA,IAChC,OAAO,MAAM;AAAA,IACb,GAAI,MAAM,YAAY,SAAY,EAAE,SAAS,MAAM,QAAQ,IAAI,CAAC;AAAA,EAClE;AACA,SAAO;AAAA,IACL,IAAI,MAAM;AAAA,IACV,OAAO,MAAM;AAAA,IACb,aAAa,MAAM;AAAA;AAAA;AAAA,IAGnB,MACE,MAAM,YAAY,SACd,MAAM,QACN,GAAG,MAAM,KAAK,mBAAgB,MAAM,QAAQ,KAAK,IAAI,CAAC;AAAA,IAC5D;AAAA,EACF;AACF;;;ACtFA,SAAS,eAAAE,eAAa,aAAAC,aAAW,OAAO,iBAAiB,WAAAC,UAAS,UAAAC,UAAQ,YAAAC,kBAAgB;AAyFnF,SAAS,wBACd,SACsB;AACtB,QAAM,EAAE,OAAO,SAAS,cAAc,KAAK,IAAI;AAE/C,QAAM,SAASC,SAAO,OAAO;AAC7B,SAAO,UAAU;AAEjB,QAAM,WAAWA,SAAsD,IAAI;AAC3E,QAAM,CAAC,OAAO,QAAQ,IAAIC,WAAS,MAAM,MAAM;AAC/C,QAAM,CAAC,OAAO,QAAQ,IAAIA,WAA6B,CAAC,CAAC;AACzD,QAAM,CAAC,WAAW,UAAU,IAAIA,WAAS,KAAK;AAC9C,QAAM,CAAC,OAAO,QAAQ,IAAIA,WAAwB,IAAI;AACtD,QAAM,CAAC,aAAa,cAAc,IAAIA,WAAS,CAAC;AAGhD,QAAM,CAAC,gBAAgB,iBAAiB,IAAIA,WAAwB,IAAI;AAGxE,QAAM,YAAY,KAAK,IAAI,OAAO,MAAM,MAAM;AAC9C,QAAM,QAAQC;AAAA,IACZ,MAAM,kBAAkB,OAAO,WAAW,OAAO;AAAA,IACjD,CAAC,OAAO,WAAW,OAAO;AAAA,EAC5B;AACA,QAAM,WAAW,UAAU,QAAQ,mBAAmB,MAAM;AAE5D,QAAM,WAAWF,SAA4B,KAAK;AAClD,WAAS,UAAU;AACnB,QAAM,WAAWA,SAAO,SAAS;AACjC,WAAS,UAAU;AACnB,QAAM,WAAWA,SAAO,KAAK;AAC7B,WAAS,UAAU;AACnB,QAAM,iBAAiBA,SAAO,WAAW;AACzC,iBAAe,UAAU;AAKzB,QAAM,aAAa,YAAY,QAAQ,GAAG,MAAM,OAAO,EAAE,KAAS,MAAM,KAAK,KAAK;AAElF,EAAAG,YAAU,MAAM;AACd,UAAM,UAAU,SAAS;AACzB,QAAI,eAAe,QAAQ,YAAY,MAAM;AAC3C,eAAS,CAAC,CAAC;AACX,iBAAW,KAAK;AAChB,eAAS,IAAI;AACb;AAAA,IACF;AACA,UAAM,EAAE,QAAQ,MAAM,IAAI;AAC1B,UAAM,aAAa,IAAI,gBAAgB;AAGvC,QAAI,aAAa;AACjB,UAAM,SAAS,CAAC,SAA6B;AAC3C,UAAI,WAAY;AAChB,gBAAU,OAAO,UAAU,yBAAyB,MAAM,KAAK,CAAC;AAChE,qBAAe,CAAC;AAChB,iBAAW,KAAK;AAChB,eAAS,IAAI;AAAA,IACf;AACA,UAAM,SAAS,CAAC,UAAmB;AACjC,UAAI,WAAY;AAChB,eAAS,CAAC,CAAC;AACX,iBAAW,KAAK;AAChB,eAAS,iBAAiB,QAAQ,MAAM,UAAU,4BAA4B;AAC9E,aAAO,QAAQ,UAAU,OAAO,MAAM;AAAA,IACxC;AAEA,QAAI;AACJ,QAAI;AACF,eAAS,OAAO,SAAS,OAAO,WAAW,MAAM;AAAA,IACnD,SAAS,OAAO;AACd,aAAO,KAAK;AACZ;AAAA,IACF;AAGA,QAAI,CAAC,UAAU,MAAM,GAAG;AACtB,aAAO,MAAM;AACb;AAAA,IACF;AACA,eAAW,IAAI;AACf,aAAS,IAAI;AACb,WAAO,KAAK,QAAQ,MAAM;AAC1B,WAAO,MAAM;AACX,mBAAa;AACb,iBAAW,MAAM;AAAA,IACnB;AAAA,EACF,GAAG,CAAC,UAAU,CAAC;AAKf,QAAM,SAAS;AACf,QAAM,aAAa,SAAU,MAAM,WAAW,KAAK,OAAQ;AAE3D,QAAM,UAAU,MAAM;AACtB,QAAM,YAAY,QAAQ,MAAM,sBAAsB,OAAO;AAC7D,QAAM,WAAWC,cAAY,CAAC,UAAkB,GAAG,SAAS,WAAW,KAAK,IAAI,CAAC,SAAS,CAAC;AAE3F,QAAM,YAAYA,cAAY,CAAC,UAAkB;AAC/C,UAAM,QAAQ,SAAS,QAAQ;AAC/B,QAAI,UAAU,EAAG;AACjB,oBAAiB,QAAQ,QAAS,SAAS,KAAK;AAAA,EAClD,GAAG,CAAC,CAAC;AAEL,QAAM,gBAAgBA;AAAA,IACpB,CAAC,UAAkB,UAAU,eAAe,UAAU,KAAK;AAAA,IAC3D,CAAC,SAAS;AAAA,EACZ;AAEA,QAAM,UAAUA,cAAY,MAAM;AAChC,UAAM,UAAU,SAAS;AACzB,QAAI,QAAS,mBAAkB,QAAQ,KAAK;AAAA,EAC9C,GAAG,CAAC,CAAC;AAIL,QAAM,eAAeJ,SAAsB,IAAI;AAE/C,QAAM,SAASI,cAAY,CAAC,SAA4B;AACtD,UAAM,UAAU,SAAS;AACzB,QAAI,CAAC,QAAS;AACd,UAAM,SAAS,QAAQ,SAAS,QAAQ,eAAe,OAAO;AAC9D,QAAI,CAAC,OAAQ;AACb,UAAM,OAAO,gBAAgB,OAAO,QAAQ,OAAO,SAAS,SAAS,SAAS,MAAM;AACpF,WAAO,QAAQ,cAAc,KAAK,IAAI;AACtC,aAAS,KAAK,KAAK;AACnB,sBAAkB,IAAI;AACtB,iBAAa,UAAU,KAAK;AAAA,EAC9B,GAAG,CAAC,CAAC;AAEL,kBAAgB,MAAM;AACpB,UAAM,WAAW,aAAa;AAC9B,QAAI,aAAa,KAAM;AACvB,iBAAa,UAAU;AACvB,aAAS,SAAS,kBAAkB,UAAU,QAAQ;AAAA,EACxD,CAAC;AAED,QAAM,YAAYA,cAAY,CAAC,YAAoD;AACjF,aAAS,QAAQ,kBAAkB,QAAQ,MAAM,MAAM;AAAA,EACzD,GAAG,CAAC,CAAC;AAEL,QAAM,YAAYA;AAAA,IAChB,CAAC,UAAuE;AACtE,UAAI,CAAC,OAAQ;AACb,YAAM,WAAW,SAAS,QAAQ,SAAS;AAC3C,cAAQ,MAAM,KAAK;AAAA,QACjB,KAAK;AACH,cAAI,CAAC,SAAU;AACf,gBAAM,eAAe;AACrB,wBAAc,CAAC;AACf;AAAA,QACF,KAAK;AACH,cAAI,CAAC,SAAU;AACf,gBAAM,eAAe;AACrB,wBAAc,EAAE;AAChB;AAAA,QACF,KAAK;AACH,cAAI,CAAC,SAAU;AACf,gBAAM,eAAe;AACrB,iBAAO;AACP;AAAA,QACF,KAAK;AAEH,cAAI,CAAC,eAAe,MAAM,YAAY,CAAC,SAAU;AACjD,gBAAM,eAAe;AACrB,iBAAO;AACP;AAAA,QACF,KAAK;AACH,gBAAM,eAAe;AACrB,kBAAQ;AACR;AAAA,QACF;AACE;AAAA,MACJ;AAAA,IACF;AAAA,IACA,CAAC,QAAQ,aAAa,QAAQ,SAAS,aAAa;AAAA,EACtD;AAEA,QAAM,WAAWA;AAAA,IACf,CAAC,UAAqE;AACpE,gBAAU,MAAM,MAAM;AAEtB,YAAM,OAAO;AAAA,QACX,MAAM,OAAO;AAAA,QACb,MAAM,OAAO,kBAAkB,MAAM,OAAO,MAAM;AAAA,QAClD,OAAO,QAAQ;AAAA,MACjB;AACA;AAAA,QAAkB,CAAC,YACjB,YAAY,QAAQ,MAAM,UAAU,UAAU,UAAU;AAAA,MAC1D;AAAA,IACF;AAAA,IACA,CAAC,SAAS;AAAA,EACZ;AAEA,QAAM,WAAWA;AAAA,IACf,CAAC,UACC,UAAU,MAAM,aAAa;AAAA,IAC/B,CAAC,SAAS;AAAA,EACZ;AAEA,QAAM,UAAUA;AAAA,IACd,CAAC,UACC,UAAU,MAAM,aAAa;AAAA,IAC/B,CAAC,SAAS;AAAA,EACZ;AAEA,QAAM,WAAWA,cAAY,CAAC,YAA2D;AACvF,aAAS,UAAU;AAAA,EACrB,GAAG,CAAC,CAAC;AAEL,QAAM,gBAAgBA;AAAA,IACpB,OAA+B;AAAA,MAC7B,KAAK;AAAA,MACL;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA,MAAM;AAAA,MACN,iBAAiB;AAAA,MACjB,qBAAqB;AAAA,MACrB,iBAAiB;AAAA,MACjB,GAAI,SAAS,EAAE,iBAAiB,UAAU,IAAI,CAAC;AAAA,MAC/C,GAAI,aAAa,EAAE,yBAAyB,SAAS,WAAW,EAAE,IAAI,CAAC;AAAA,IACzE;AAAA,IACA;AAAA,MACE;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,IACF;AAAA,EACF;AAEA,QAAM,kBAAkBA;AAAA,IACtB,OAAiC;AAAA,MAC/B,IAAI;AAAA,MACJ,MAAM;AAAA,MACN,cAAc,OAAO,OAAO,SAAS,OAAO,OAAO,MAAM;AAAA,IAC3D;AAAA,IACA,CAAC,WAAW,KAAK;AAAA,EACnB;AAEA,QAAM,iBAAiBA;AAAA,IACrB,CAAC,WAA4C;AAAA,MAC3C,IAAI,SAAS,KAAK;AAAA,MAClB,MAAM;AAAA,MACN,iBAAiB,UAAU;AAAA,IAC7B;AAAA,IACA,CAAC,UAAU,WAAW;AAAA,EACxB;AAEA,SAAO;AAAA,IACL;AAAA,IACA,QAAQ,UAAU,QAAQ,MAAM,SAAS;AAAA,IACzC,SAAS,UAAU,QAAQ,MAAM,OAAO,UAAU;AAAA,IAClD,OAAO,OAAO,SAAS;AAAA,IACvB;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,EACF;AACF;AAEA,SAAS,UAAa,OAAkD;AACtE,SAAO,OAAQ,MAAuB,SAAS;AACjD;;;AClXA,SAAS,kBAAyC;AAGlD,SAAS,eAAAC,eAAa,aAAAC,aAAW,WAAAC,WAAS,YAAAC,kBAAgB;AAyC1D,IAAMC,UAAS,oBAAI,QAAgE;AAEnF,SAASC,MAAK,QAAsB,OAAwD;AAC1F,MAAI,UAAUD,QAAO,IAAI,MAAM;AAC/B,MAAI,YAAY,QAAW;AACzB,cAAU,oBAAI,IAAI;AAClB,IAAAA,QAAO,IAAI,QAAQ,OAAO;AAAA,EAC5B;AACA,QAAM,MAAM,SAAS;AACrB,QAAM,SAAS,QAAQ,IAAI,GAAG;AAC9B,MAAI,WAAW,OAAW,QAAO;AACjC,MAAI,OAAO,cAAc,QAAW;AAClC,WAAO,QAAQ,OAAO,IAAI,6BAA6B,WAAW,CAAC;AAAA,EACrE;AACA,QAAM,UAAU,OAAO,UAAU,KAAK,EAAE,MAAM,CAAC,UAAmB;AAChE,YAAQ,OAAO,GAAG;AAClB,UAAM;AAAA,EACR,CAAC;AACD,UAAQ,IAAI,KAAK,OAAO;AACxB,SAAO;AACT;AAOO,SAAS,eAAe,UAAiC,CAAC,GAAqB;AACpF,QAAM,EAAE,OAAO,UAAU,KAAK,IAAI;AAClC,QAAM,SAAS,gBAAgB,QAAQ,OAAmC;AAC1E,QAAM,CAAC,SAAS,UAAU,IAAIE,WAA6B,CAAC,CAAC;AAC7D,QAAM,CAAC,WAAW,UAAU,IAAIA,WAAS,OAAO;AAChD,QAAM,CAAC,OAAO,QAAQ,IAAIA,WAAuB,IAAI;AACrD,QAAM,CAAC,YAAY,aAAa,IAAIA,WAAS,CAAC;AAG9C,EAAAC,YAAU,MAAM;AACd,QAAI,CAAC,SAAS;AACZ,iBAAW,KAAK;AAChB;AAAA,IACF;AACA,QAAI,YAAY;AAChB,eAAW,IAAI;AACf,IAAAF,MAAK,QAAQ,KAAK,EAAE;AAAA,MAClB,CAAC,WAAW;AACV,YAAI,UAAW;AACf,mBAAW,MAAM,QAAQ,MAAM,IAAI,SAAS,CAAC,CAAC;AAC9C,iBAAS,IAAI;AACb,mBAAW,KAAK;AAAA,MAClB;AAAA,MACA,CAAC,YAAqB;AACpB,YAAI,UAAW;AACf,iBAAS,mBAAmB,QAAQ,UAAU,IAAI,MAAM,OAAO,OAAO,CAAC,CAAC;AACxE,mBAAW,KAAK;AAAA,MAClB;AAAA,IACF;AACA,WAAO,MAAM;AACX,kBAAY;AAAA,IACd;AAAA,EACF,GAAG,CAAC,QAAQ,OAAO,SAAS,UAAU,CAAC;AAEvC,QAAM,UAAUG,cAAY,MAAM;AAChC,IAAAJ,QAAO,IAAI,MAAM,GAAG,OAAO,SAAS,EAAE;AACtC,kBAAc,CAAC,YAAY,UAAU,CAAC;AAAA,EACxC,GAAG,CAAC,QAAQ,KAAK,CAAC;AAElB,QAAM,UAAUK,UAAQ,MAAM,gBAAgB,OAAO,GAAG,CAAC,OAAO,CAAC;AACjE,SAAO,EAAE,SAAS,SAAS,WAAW,OAAO,QAAQ;AACvD;;;AChHA,SAAS,aAAAC,aAAW,UAAAC,UAAQ,YAAAC,kBAAgB;AAiBrC,SAAS,kBACd,WACA,MAAc,KAAK,IAAI,GACJ;AACnB,QAAM,WAAW,aAAa,OAAO,OAAO,MAAM,KAAK,MAAM,SAAS;AACtE,MAAI,CAAC,OAAO,SAAS,QAAQ,GAAG;AAC9B,WAAO,EAAE,aAAa,MAAM,WAAW,MAAM;AAAA,EAC/C;AACA,QAAM,cAAc,KAAK,IAAI,GAAG,WAAW,GAAG;AAC9C,SAAO,EAAE,aAAa,WAAW,gBAAgB,EAAE;AACrD;AAQO,SAAS,qBACd,WACA,UAAuC,CAAC,GACrB;AACnB,QAAM,EAAE,aAAa,IAAK,IAAI;AAC9B,QAAM,SAASD,SAAO,QAAQ,OAAO,KAAK,GAAG;AAC7C,SAAO,UAAU,QAAQ,OAAO,KAAK;AACrC,QAAM,CAAC,OAAO,QAAQ,IAAIC,WAAS,MAAM,kBAAkB,WAAW,OAAO,QAAQ,CAAC,CAAC;AAEvF,EAAAF,YAAU,MAAM;AACd,UAAM,OAAO,MAAM,kBAAkB,WAAW,OAAO,QAAQ,CAAC;AAChE,UAAM,QAAQ,KAAK;AACnB,aAAS,KAAK;AACd,QAAI,MAAM,gBAAgB,QAAQ,MAAM,WAAW;AACjD;AAAA,IACF;AACA,UAAM,QAAQ,YAAY,MAAM;AAC9B,YAAM,OAAO,KAAK;AAClB,eAAS,IAAI;AACb,UAAI,KAAK,UAAW,eAAc,KAAK;AAAA,IACzC,GAAG,UAAU;AACb,WAAO,MAAM,cAAc,KAAK;AAAA,EAClC,GAAG,CAAC,WAAW,UAAU,CAAC;AAE1B,SAAO;AACT;;;AC5DA,SAAS,8BAA8B;AA0CvC,SAAS,UAAU,QAA6B;AAC9C,MAAI,OAAO,WAAW,MAAM;AAC1B,WAAO;AAAA,EACT;AACA,QAAM,EAAE,OAAO,IAAI;AACnB,SACE,WAAW,QACX,OAAO,WAAW,YAClB,cAAc,UACb,OAAiC,aAAa;AAEnD;AAGA,SAAS,cAAc,QAAwC;AAC7D,QAAM,EAAE,OAAO,IAAI;AACnB,MAAI,WAAW,QAAQ,OAAO,WAAW,YAAY,YAAY,QAAQ;AACvE,UAAM,SAAU,OAA+B;AAC/C,WAAO,OAAO,WAAW,YAAY,WAAW,yBAAyB,SAAS;AAAA,EACpF;AACA,SAAO;AACT;AAEO,SAAS,yBAAyB,SAAmC;AAC1E,QAAM,QAA4B,CAAC;AAEnC,MAAI,QAAQ,WAAW;AACrB,UAAM,KAAK;AAAA,MACT,MAAM;AAAA,MACN,MAAM,QAAQ;AAAA,MACd,OAAO;AAAA,MACP,GAAI,QAAQ,gBAAgB,SACxB,EAAE,kBAAkB,0BAA0B,QAAQ,WAAW,EAAE,IACnE,CAAC;AAAA,IACP,CAAC;AAAA,EACH;AAEA,MAAI,QAAQ,SAAS;AACnB,UAAM,KAAK,EAAE,MAAM,QAAQ,MAAM,QAAQ,QAAQ,CAAC;AAAA,EACpD;AAEA,aAAW,cAAc,QAAQ,eAAe,CAAC,GAAG;AAClD,UAAM,KAAK;AAAA,MACT,MAAM;AAAA,MACN,WAAW,WAAW;AAAA,MACtB,UAAU,WAAW;AAAA,MACrB,KAAK,WAAW;AAAA;AAAA,MAEhB,kBAAkB,EAAE,OAAO,EAAE,SAAS,WAAW,QAAQ,EAAE;AAAA,IAC7D,CAAC;AAAA,EACH;AAIA,QAAM,cAAc,IAAI,KAAK,QAAQ,aAAa,CAAC,GAAG,IAAI,CAAC,SAAS,KAAK,EAAE,CAAC;AAC5E,QAAM,eAAe,oBAAI,IAAgC;AACzD,aAAW,aAAa,QAAQ,MAAM,CAAC,GAAG;AACxC,UAAM,OAAmC;AAAA,MACvC,MAAM;AAAA,MACN,IAAI,UAAU;AAAA,MACd,MAAM;AAAA,QACJ,IAAI,UAAU;AAAA,QACd,WAAW,UAAU;AAAA,QACrB,OAAO,UAAU;AAAA,QACjB,GAAI,UAAU,sBAAsB,SAChC,EAAE,mBAAmB,UAAU,kBAAkB,IACjD,CAAC;AAAA,QACL,GAAI,UAAU,iBAAiB,SAAY,EAAE,cAAc,UAAU,aAAa,IAAI,CAAC;AAAA,QACvF,GAAI,UAAU,YAAY,SAAY,EAAE,SAAS,UAAU,QAAQ,IAAI,CAAC;AAAA,QACxE,GAAI,UAAU,eAAe,SAAY,EAAE,YAAY,UAAU,WAAW,IAAI,CAAC;AAAA,MACnF;AAAA,IACF;AACA,QAAI,UAAU,eAAe,UAAa,YAAY,IAAI,UAAU,UAAU,GAAG;AAC/E,YAAM,OAAO,aAAa,IAAI,UAAU,UAAU,KAAK,CAAC;AACxD,WAAK,KAAK,IAAI;AACd,mBAAa,IAAI,UAAU,YAAY,IAAI;AAAA,IAC7C,OAAO;AACL,YAAM,KAAK,IAAI;AAAA,IACjB;AAAA,EACF;AAEA,aAAW,YAAY,QAAQ,aAAa,CAAC,GAAG;AAC9C,UAAM,KAAK;AAAA,MACT,MAAM;AAAA,MACN,IAAI,SAAS;AAAA,MACb,MAAM;AAAA,QACJ,IAAI,SAAS;AAAA,QACb,UAAU,SAAS;AAAA,QACnB,GAAI,SAAS,WAAW,SACpB,EAAE,QAAQ,SAAS,OAAO,IAC1B,SAAS,eAAe,SACtB,EAAE,QAAQ,EAAE,MAAM,YAAY,YAAY,SAAS,WAAW,EAAE,IAChE,CAAC;AAAA,QACP,GAAI,SAAS,iBAAiB,SAAY,EAAE,cAAc,SAAS,aAAa,IAAI,CAAC;AAAA,QACrF,GAAI,SAAS,cAAc,SAAY,EAAE,WAAW,SAAS,UAAU,IAAI,CAAC;AAAA,MAC9E;AAAA,IACF,CAAC;AACD,QAAI,SAAS,WAAW,WAAW;AACjC,YAAM,KAAK;AAAA,QACT,MAAM;AAAA,QACN,IAAI,SAAS;AAAA,QACb,MAAM;AAAA,UACJ,IAAI,SAAS;AAAA,UACb,QAAQ,SAAS;AAAA,UACjB,GAAI,SAAS,cAAc,SAAY,EAAE,WAAW,SAAS,UAAU,IAAI,CAAC;AAAA,UAC5E,GAAI,SAAS,eAAe,SAAY,EAAE,YAAY,SAAS,WAAW,IAAI,CAAC;AAAA,UAC/E,GAAI,SAAS,aAAa,OAAO,EAAE,UAAU,KAAK,IAAI,CAAC;AAAA,UACvD,GAAI,SAAS,WAAW,SAAY,EAAE,QAAQ,SAAS,OAAO,IAAI,CAAC;AAAA,QACrE;AAAA,MACF,CAAC;AAAA,IACH;AAAA,EACF;AAEA,aAAW,QAAQ,QAAQ,aAAa,CAAC,GAAG;AAC1C,UAAM,SAAS,QAAQ,aAAa,KAAK,CAAC,cAAc,UAAU,OAAO,KAAK,EAAE;AAGhF,UAAMG,YAAW,KAAK;AAEtB,UAAM,eAAe;AAAA,MACnB,GAAIA,cAAa,SAAY,EAAE,UAAAA,UAAS,IAAI,CAAC;AAAA,MAC7C,GAAI,KAAK,aAAa,SAAY,EAAE,UAAU,KAAK,SAAS,IAAI,CAAC;AAAA,IACnE;AACA,UAAM,KAAK;AAAA,MACT,MAAM,QAAQ,KAAK,IAAI;AAAA,MACvB,YAAY,KAAK;AAAA,MACjB,GAAI,OAAO,KAAK,YAAY,EAAE,SAAS,IAAI,EAAE,aAAa,IAAI,CAAC;AAAA,MAC/D,GAAI,WAAW,SACX,UAAU,MAAM,IACd;AAAA;AAAA;AAAA;AAAA;AAAA,QAKE,OAAO;AAAA,QACP,OAAO,KAAK;AAAA,QACZ,UAAU;AAAA,UACR,IAAI,KAAK;AAAA,UACT,UAAU;AAAA,UACV,GAAI,cAAc,MAAM,MAAM,SAC1B,EAAE,QAAQ,cAAc,MAAM,EAAY,IAC1C,CAAC;AAAA,QACP;AAAA,MACF,IACA,OAAO,OAAO,UAAU,YAAY,OAAO,UAAU,KACnD;AAAA;AAAA;AAAA;AAAA;AAAA,QAKE,OAAO;AAAA,QACP,OAAO,KAAK;AAAA,QACZ,WAAW,OAAO;AAAA,MACpB,IACA,EAAE,OAAO,oBAAoB,OAAO,KAAK,OAAO,QAAQ,OAAO,OAAO,IAC1E,EAAE,OAAO,mBAAmB,OAAO,KAAK,MAAM;AAAA,IACpD,CAAC;AACD,UAAM,KAAK,GAAI,aAAa,IAAI,KAAK,EAAE,KAAK,CAAC,CAAE;AAAA,EACjD;AAEA,QAAM,WAAiC;AAAA;AAAA,IAErC,GAAG,QAAQ;AAAA,IACX,GAAI,QAAQ,0BAA0B,SAClC,CAAC,IACD,EAAE,yBAAyB,QAAQ,sBAAsB,GAAG;AAAA,IAChE,GAAI,QAAQ,aAAa,SAAY,EAAE,UAAU,QAAQ,SAAS,IAAI,CAAC;AAAA,IACvE,GAAI,QAAQ,YAAY,EAAE,WAAW,QAAQ,UAAU,IAAI,CAAC;AAAA,IAC5D,GAAI,QAAQ,cAAc,SAAY,EAAE,WAAW,QAAQ,UAAU,IAAI,CAAC;AAAA,IAC1E,GAAI,QAAQ,YAAY,SAAY,EAAE,SAAS,QAAQ,QAAQ,IAAI,CAAC;AAAA,IACpE,GAAI,QAAQ,UAAU,SAClB;AAAA,MACE,OAAO;AAAA,QACL,aAAa,QAAQ,MAAM;AAAA,QAC3B,cAAc,QAAQ,MAAM;AAAA,QAC5B,SAAS,QAAQ,MAAM,WAAW;AAAA,MACpC;AAAA,IACF,IACA,CAAC;AAAA,EACP;AACA,SAAO;AAAA,IACL,IAAI,QAAQ;AAAA,IACZ,MAAM,QAAQ;AAAA,IACd;AAAA,IACA,GAAI,OAAO,KAAK,QAAQ,EAAE,SAAS,IAAI,EAAE,SAAS,IAAI,CAAC;AAAA,EACzD;AACF;;;AChJO,SAAS,yBAAyB,UAAwC;AAC/E,QAAM,QAA2B,CAAC;AAClC,aAAW,WAAW,UAAU;AAC9B,UAAM,cAAc,MAAM,GAAG,EAAE;AAC/B,UAAM,cAAc,aAAa,GAAG,EAAE;AACtC,QACE,QAAQ,SAAS,eACjB,aAAa,SAAS,eACtB,eACA,QAAQ,aAAa,OAAO,GAC5B;AACA,kBAAY,KAAK,OAAO;AAAA,IAC1B,OAAO;AACL,YAAM,KAAK,CAAC,OAAO,CAAC;AAAA,IACtB;AAAA,EACF;AACA,SAAO,MAAM,IAAI,SAAS;AAC5B;AAYA,SAAS,QAAQ,UAAyB,MAA8B;AACtE,MAAI,SAAS,0BAA0B,UAAa,KAAK,0BAA0B;AACjF,WAAO;AACT,SAAO,SAAS,UAAU,UAAa,KAAK,UAAU,UAAa,SAAS,UAAU,KAAK;AAC7F;AAEA,SAAS,UAAU,MAAkC;AACnD,QAAM,UAAU,KAAK,GAAG,EAAE;AAC1B,MAAI,YAAY,QAAW;AAEzB,UAAM,IAAI,MAAM,qDAAqD;AAAA,EACvE;AACA,MAAI,KAAK,WAAW,GAAG;AACrB,WAAO,yBAAyB,OAAO;AAAA,EACzC;AAEA,QAAM,QAA4B,KAAK,QAAQ,CAAC,QAAQ,yBAAyB,GAAG,EAAE,KAAK;AAC3F,QAAM,QAAQ,SAAS,IAAI;AAE3B,QAAM,WAAW,QAAQ;AACzB,QAAM,YAAY,KAAK,CAAC,GAAG;AAC3B,QAAM,WAAiC;AAAA;AAAA,IAErC,GAAG,OAAO,OAAO,CAAC,GAAG,GAAG,KAAK,IAAI,CAAC,QAAQ,IAAI,YAAY,CAAC,CAAC,CAAC;AAAA,IAC7D,GAAI,UAAU,SAAY,EAAE,MAAM,IAAI,CAAC;AAAA,IACvC,GAAI,aAAa,SAAY,EAAE,SAAS,IAAI,CAAC;AAAA,IAC7C,GAAI,YAAY,EAAE,UAAU,IAAI,CAAC;AAAA,IACjC,GAAI,QAAQ,cAAc,SAAY,EAAE,WAAW,QAAQ,UAAU,IAAI,CAAC;AAAA,IAC1E,GAAI,QAAQ,YAAY,SAAY,EAAE,SAAS,QAAQ,QAAQ,IAAI,CAAC;AAAA,EACtE;AAEA,SAAO;AAAA,IACL,IAAI,QAAQ;AAAA,IACZ,MAAM,QAAQ;AAAA,IACd;AAAA,IACA,GAAI,OAAO,KAAK,QAAQ,EAAE,SAAS,IAAI,EAAE,SAAS,IAAI,CAAC;AAAA,EACzD;AACF;AAEA,SAAS,SAAS,MAAwD;AACxE,QAAM,SAAS,KACZ,IAAI,CAAC,QAAQ,IAAI,KAAK,EACtB,OAAO,CAAC,UAA8C,UAAU,MAAS;AAC5E,MAAI,OAAO,WAAW,GAAG;AACvB,WAAO;AAAA,EACT;AACA,QAAM,kBAAkB,OAAO;AAAA,IAC7B,CAAC,UAAU,MAAM,YAAY,QAAQ,MAAM,YAAY;AAAA,EACzD;AACA,SAAO;AAAA,IACL,aAAa,OAAO,OAAO,CAAC,KAAK,UAAU,MAAM,MAAM,aAAa,CAAC;AAAA,IACrE,cAAc,OAAO,OAAO,CAAC,KAAK,UAAU,MAAM,MAAM,cAAc,CAAC;AAAA,IACvE,SAAS,kBAAkB,OAAO,OAAO,OAAO,CAAC,KAAK,UAAU,OAAO,MAAM,WAAW,IAAI,CAAC;AAAA,EAC/F;AACF;;;ACvKA,SAAS,eAAe;AAWxB,SAAS,eAAAC,eAAa,aAAAC,aAAW,WAAAC,WAAS,UAAAC,UAAQ,YAAAC,kBAAgB;;;ACTlE,SAAS,eAAAC,eAAa,aAAAC,aAAW,UAAAC,UAAQ,YAAAC,kBAAgB;;;ACMlD,SAAS,qBAAqB,UAAuC;AAC1E,SACE,SAAS,aAAa,aACtB,SAAS,WAAW,WAAW,YAC/B,SAAS,WAAW,WAAW,eAC/B,SAAS,iBAAiB,WAAW;AAEzC;AAGO,SAAS,0BACd,SACA,WACA,OACa;AACb,QAAM,WAAW,QAAQ,IAAI,CAAC,YAAY;AACxC,UAAM,WAAW,UAAU;AAAA,MAAO,CAAC,aACjC,QAAQ,MAAM,KAAK,CAAC,SAAS;AAC3B,YACE,UAAU,QACV,OAAO,KAAK,IAAI,KAChB,OAAO,KAAK,KAAK,MAAM,KACvB,KAAK,KAAK,OAAO,SAAS;AAE1B,iBAAO,KAAK,KAAK,OAAO,eAAe,SAAS;AAClD,YAAI,gBAAgB,QAAQ,KAAK,eAAe,SAAS,kBAAkB;AACzE,cAAI,YAAY,QAAQ,OAAO,KAAK,MAAM,KAAK,OAAO,KAAK,OAAO,eAAe;AAC/E,mBAAO,KAAK,OAAO,eAAe,SAAS;AAC7C,iBAAO,OAAO,QAAQ,QAAQ,KAAK,QAAQ,SAAS,UAAU,SAAS;AAAA,QACzE;AACA,eAAO;AAAA,MACT,CAAC;AAAA,IACH;AACA,QAAI,SAAS,WAAW,EAAG,QAAO;AAClC,UAAM,MAAM,IAAI,IAAI,SAAS,IAAI,CAAC,aAAa,SAAS,gBAAgB,CAAC;AACzE,UAAM,QAAQ,QAAQ,MAAM;AAAA,MAC1B,CAAC,SACC,EACE,KAAK,SAAS,0BACd,QAAQ,QACR,OAAO,KAAK,OAAO,YACnB,IAAI,IAAI,KAAK,EAAE;AAAA,IAErB;AACA,eAAW,YAAY;AACrB,YAAM,KAAK;AAAA,QACT,MAAM;AAAA,QACN,IAAI,SAAS;AAAA,QACb,MAAM;AAAA,UACJ,IAAI,SAAS;AAAA,UACb,QAAQ,EAAE,MAAM,YAAY,YAAY,SAAS,IAAI,UAAU,SAAS,SAAS;AAAA,UACjF,UAAU,SAAS;AAAA,UACnB,cAAc,SAAS;AAAA,UACvB,WACE,SAAS,cAAc,OACnB,OACA,KAAK,IAAI,SAAS,SAAS,KAAK,SAC9B,IAAI,KAAK,SAAS,SAAS,EAAE,YAAY,IACzC;AAAA,UACR,QAAQ,SAAS;AAAA,UACjB,iBAAiB,SAAS,WAAW,UAAU;AAAA,UAC/C,UAAU,SAAS,eAAe,aAAa;AAAA,UAC/C,WAAW,SAAS,eAAe,YAAY;AAAA,UAC/C,YAAY,SAAS,eAAe,OAAO;AAAA,UAC3C,QAAQ,SAAS,eAAe,UAAU;AAAA,QAC5C;AAAA,MACF,CAAC;AACH,WAAO,EAAE,GAAG,SAAS,MAAM;AAAA,EAC7B,CAAC;AACD,QAAM,gBAAgB,IAAI,IAAI,SAAS,IAAI,CAAC,YAAY,QAAQ,EAAE,CAAC;AACnE,QAAM,gBAAgB,IAAI;AAAA,IACxB,SAAS,IAAI,CAAC,YAAY,UAAU,QAAQ,QAAQ,CAAC,EAAE,OAAO,OAAO;AAAA,EACvE;AACA,aAAW,QAAQ,OAAO;AACxB,UAAM,KAAK,KAAK,uBAAuB;AACvC,QAAI,OAAO,UAAa,cAAc,IAAI,KAAK,EAAE,KAAK,cAAc,IAAI,EAAE,EAAG;AAC7E,UAAM,UAAU,yBAAyB,IAAI;AAC7C,aAAS,KAAK;AAAA,MACZ,GAAG;AAAA,MACH,UAAU;AAAA,QACR,GAAI,OAAO,QAAQ,QAAQ,IAAI,QAAQ,WAAW,CAAC;AAAA,QACnD,yBAAyB;AAAA,MAC3B;AAAA,IACF,CAAC;AACD,kBAAc,IAAI,KAAK,EAAE;AACzB,kBAAc,IAAI,EAAE;AAAA,EACtB;AACA,SAAO;AACT;AACA,SAAS,OAAO,OAAkD;AAChE,SAAO,OAAO,UAAU,YAAY,UAAU,QAAQ,CAAC,MAAM,QAAQ,KAAK;AAC5E;AACA,SAAS,UAAU,OAAoC;AACrD,SAAO,OAAO,KAAK,KAAK,OAAO,MAAM,4BAA4B,WAC7D,MAAM,0BACN;AACN;;;ADtFA,IAAM,uBAAuB,oBAAI,IAAI,CAAC,KAAK,KAAK,GAAG,CAAC;AAEpD,IAAM,iBAAiB,oBAAI,IAAI,CAAC,oBAAoB,gBAAgB,CAAC;AAErE,IAAM,iBAAiB;AAGvB,IAAM,sBAAsB,oBAAI,QAAgB;AAEhD,SAAS,SAAS,OAAoC;AACpD,QAAM,SAAU,OAAuC;AACvD,SAAO,OAAO,WAAW,WAAW,SAAS;AAC/C;AAGO,SAAS,uBAAuB,OAAyB;AAC9D,QAAM,SAAS,SAAS,KAAK;AAC7B,MAAI,WAAW,UAAa,CAAC,qBAAqB,IAAI,MAAM,EAAG,QAAO;AACtE,SAAO,EAAE,WAAW,OAAO,iBAAiB,SAAS,eAAe,IAAI,MAAM,OAAO;AACvF;AAEO,SAAS,mBACd,SACA,UACA,aACA,YACA,SAAS,KACa;AACtB,QAAM,CAAC,OAAO,QAAQ,IAAIC,WAA+B,CAAC,CAAC;AAC3D,QAAM,CAAC,OAAO,QAAQ,IAAIA,WAAuB,IAAI;AACrD,QAAM,CAAC,aAAa,cAAc,IAAIA,WAAS,MAAM,oBAAoB,IAAI,OAAO,CAAC;AAErF,QAAM,CAAC,UAAU,WAAW,IAAIA,WAAS,CAAC;AAC1C,QAAM,SAASC,SAAO,EAAE,UAAU,YAAY,CAAC;AAC/C,SAAO,UAAU,EAAE,UAAU,YAAY;AACzC,QAAM,UAAUA,SAAO,IAAI;AAC3B,QAAM,WAAWA,SAAO,oBAAI,IAA2B,CAAC;AACxD,EAAAC,YAAU,MAAM;AACd,YAAQ,UAAU;AAClB,WAAO,MAAM;AACX,cAAQ,UAAU;AAAA,IACpB;AAAA,EACF,GAAG,CAAC,CAAC;AACL,QAAM,UAAUC,cAAY,YAAY;AACtC,QAAI,aAAa,UAAa,QAAQ,wBAAwB,OAAW;AACzE,QAAI,oBAAoB,IAAI,OAAO,EAAG;AACtC,UAAM,UAAU,SAAS,QAAQ,IAAI,QAAQ;AAC7C,QAAI,QAAS,QAAO;AACpB,UAAM,WAAW,YAAY;AAC3B,UAAI;AACF,cAAM,YAAY,MAAM,QAAQ,sBAAsB,EAAE,SAAS,CAAC;AAClE,YAAI,CAAC,QAAQ,WAAW,OAAO,QAAQ,aAAa,YAAY,CAAC,MAAM,QAAQ,SAAS;AACtF;AACF,cAAM,WAAW,UAAU;AAAA,UACzB,CAAC,aAAa,SAAS,iBAAiB,WAAW;AAAA,QACrD;AACA,cAAM,QAAQ,YACT,MAAM,QAAQ,UAAU,QAAQ,GAAG,SAAS;AAAA,UAC3C,CAAC,YAAY,QAAQ,0BAA0B;AAAA,QACjD,IACA,CAAC;AACL,YAAI,CAAC,QAAQ,WAAW,OAAO,QAAQ,aAAa,SAAU;AAC9D,iBAAS,SAAS;AAClB,iBAAS,IAAI;AACb,oBAAY,CAAC;AACb,eAAO,QAAQ;AAAA,UAAY,CAAC,YAC1B,0BAA0B,SAAS,WAAW,KAAK;AAAA,QACrD;AAAA,MACF,SAAS,OAAO;AACd,YAAI,uBAAuB,KAAK,GAAG;AAEjC,8BAAoB,IAAI,OAAO;AAC/B,cAAI,QAAQ,SAAS;AACnB,2BAAe,IAAI;AACnB,qBAAS,IAAI;AAAA,UACf;AACA;AAAA,QACF;AACA,YAAI,QAAQ,WAAW,OAAO,QAAQ,aAAa,UAAU;AAC3D,mBAAS,iBAAiB,QAAQ,QAAQ,IAAI,MAAM,OAAO,KAAK,CAAC,CAAC;AAClE,sBAAY,CAAC,UAAU,QAAQ,CAAC;AAAA,QAClC;AAAA,MACF;AAAA,IACF,GAAG;AACH,aAAS,QAAQ,IAAI,UAAU,OAAO;AACtC,QAAI;AACF,YAAM;AAAA,IACR,UAAE;AACA,eAAS,QAAQ,OAAO,QAAQ;AAAA,IAClC;AAAA,EACF,GAAG,CAAC,SAAS,QAAQ,CAAC;AAEtB,EAAAD,YAAU,MAAM;AACd,aAAS,CAAC,CAAC;AACX,aAAS,IAAI;AACb,gBAAY,CAAC;AAAA,EACf,GAAG,CAAC,QAAQ,CAAC;AAEb,EAAAA,YAAU,MAAM;AACd,mBAAe,oBAAoB,IAAI,OAAO,CAAC;AAAA,EACjD,GAAG,CAAC,OAAO,CAAC;AAEZ,EAAAA,YAAU,MAAM;AACd,SAAK,QAAQ;AAAA,EACf,GAAG,CAAC,SAAS,UAAU,CAAC;AAGxB,EAAAA,YAAU,MAAM;AACd,QAAI,eAAe,CAAC,MAAM,KAAK,oBAAoB,KAAK,UAAU,EAAG;AACrE,UAAM,OAAO,aAAa,IAAI,SAAS,KAAK,IAAI,SAAS,KAAK,UAAU,cAAc;AACtF,UAAM,QAAQ,WAAW,MAAM;AAC7B,WAAK,QAAQ;AAAA,IACf,GAAG,IAAI;AACP,WAAO,MAAM,aAAa,KAAK;AAAA,EACjC,GAAG,CAAC,OAAO,UAAU,aAAa,QAAQ,OAAO,CAAC;AAClD,EAAAA,YAAU,MAAM;AACd,QAAI,YAAa;AACjB,UAAM,UAAU,MAAM;AACpB,WAAK,QAAQ;AAAA,IACf;AACA,UAAM,UAAU,MAAM;AACpB,UAAI,SAAS,oBAAoB,UAAW,SAAQ;AAAA,IACtD;AACA,WAAO,iBAAiB,SAAS,OAAO;AACxC,WAAO,iBAAiB,UAAU,OAAO;AACzC,aAAS,iBAAiB,oBAAoB,OAAO;AACrD,WAAO,MAAM;AACX,aAAO,oBAAoB,SAAS,OAAO;AAC3C,aAAO,oBAAoB,UAAU,OAAO;AAC5C,eAAS,oBAAoB,oBAAoB,OAAO;AAAA,IAC1D;AAAA,EACF,GAAG,CAAC,SAAS,WAAW,CAAC;AACzB,SAAO,EAAE,OAAO,OAAO,aAAa,QAAQ;AAC9C;;;ADgGA,IAAM,cAA8B,EAAE,OAAO,CAAC,GAAG,QAAQ,KAAK;AAE9D,IAAI,qBAAqB;AAGzB,SAAS,kBAAkB,MAAoC;AAC7D,SAAO;AAAA,IACL,IAAI,KAAK;AAAA,IACT,MAAM;AAAA,IACN,UAAU,EAAE,YAAW,oBAAI,KAAK,GAAE,YAAY,EAAE;AAAA,IAChD,OAAO;AAAA,MACL,GAAG,KAAK,YAAY,IAAI,CAAC,gBAAgB;AAAA,QACvC,MAAM;AAAA,QACN,WAAW,WAAW;AAAA,QACtB,UAAU,WAAW;AAAA,QACrB,KAAK,WAAW;AAAA,QAChB,kBAAkB,EAAE,OAAO,EAAE,SAAS,WAAW,QAAQ,EAAE;AAAA,MAC7D,EAAE;AAAA,MACF,GAAI,KAAK,KAAK,SAAS,IAAI,CAAC,EAAE,MAAM,QAAiB,MAAM,KAAK,KAAK,CAAC,IAAI,CAAC;AAAA,IAC7E;AAAA,EACF;AACF;AAGA,SAAS,QAAQ,SAAsE;AACrF,MAAI,OAAO,YAAY,YAAY,YAAY,MAAM;AACnD,WAAO,EAAE,MAAM,IAAI,aAAa,CAAC,EAAE;AAAA,EACrC;AACA,QAAM,QAAQ;AAKd,MAAI,OAAO,OAAO,MAAM,SAAS,WAAW,MAAM,OAAO;AACzD,MAAI,SAAS,MAAM,MAAM,QAAQ,MAAM,KAAK,GAAG;AAC7C,WAAO,MAAM,MACV,OAAO,CAAC,SAAS,KAAK,SAAS,UAAU,OAAO,KAAK,SAAS,QAAQ,EACtE,IAAI,CAAC,SAAS,KAAK,IAAc,EACjC,KAAK,EAAE;AAAA,EACZ;AACA,QAAM,QAAQ,MAAM,QAAQ,MAAM,KAAK,IAClC,MAAM,QACP,MAAM,QAAQ,MAAM,KAAK,IACtB,MAAM,MAAyC,OAAO,CAAC,SAAS,KAAK,SAAS,MAAM,IACrF,CAAC;AACP,QAAM,cAAc,MAAM,QAAQ,CAAC,SAA8B;AAC/D,UAAM,UAAW,KAAK,kBAAoE,OACtF;AACJ,WAAO,OAAO,YAAY,WACtB;AAAA,MACE;AAAA,QACE;AAAA,QACA,KAAK,OAAO,KAAK,OAAO,EAAE;AAAA,QAC1B,aAAa,OAAO,KAAK,aAAa,0BAA0B;AAAA,QAChE,MAAM,OAAO,KAAK,YAAY,OAAO;AAAA,MACvC;AAAA,IACF,IACA,CAAC;AAAA,EACP,CAAC;AACD,SAAO,EAAE,MAAM,YAAY;AAC7B;AAEA,SAAS,cAAc,UAA+B;AACpD,WAAS,QAAQ,SAAS,SAAS,GAAG,SAAS,GAAG,SAAS,GAAG;AAC5D,QAAI,SAAS,KAAK,GAAG,SAAS,OAAQ,QAAO;AAAA,EAC/C;AACA,SAAO;AACT;AA8BA,IAAI,oBAAoB;AACxB,SAAS,cAAsB;AAC7B,uBAAqB;AACrB,SAAO,cAAc,iBAAiB;AACxC;AASO,SAAS,aACd,UAAkC,CAAC,GACnC;AACA,QAAM,uBAAuB,uBAAuB;AACpD,QAAM,kBAAkBE,SAAO,oBAAoB;AACnD,kBAAgB,UAAU;AAC1B,QAAM,SAASA,SAAO,OAAO;AAC7B,SAAO,UAAU;AAGjB,QAAM,WAAW,gBAAmB,QAAQ,OAAO;AACnD,QAAM,SAASA,SAAO,QAAQ,EAAE;AAIhC,QAAM,kBAAkBA,SAA2B,MAAS;AAI5D,QAAM,YAAYA,SAAe,QAAQ,YAAY,YAAY,CAAC;AAClE,QAAM,iBAAiBA,SAAO,QAAQ,QAAQ;AAC9C,MAAI,QAAQ,aAAa,eAAe,SAAS;AAC/C,mBAAe,UAAU,QAAQ;AACjC,UAAM,WAAW,QAAQ,aAAa,UAAa,QAAQ,aAAa,gBAAgB;AACxF,QAAI,CAAC,UAAU;AACb,gBAAU,UAAU,QAAQ,YAAY,YAAY;AACpD,sBAAgB,UAAU;AAAA,IAC5B;AAAA,EACF;AACA,QAAM,SAAS,UAAU;AAEzB,QAAM,CAAC,OAAO,QAAQ,IAAIC,WAA6B,QAAQ,WAAW;AAC1E,QAAM,WAAWD,SAA2B,KAAK;AACjD,WAAS,UAAU;AAKnB,QAAM,mBAAmBA,SAA2B,MAAS;AAI7D,QAAM,qBAAqBA,SAA2B,MAAS;AAE/D,QAAM,CAAC,aAAa,cAAc,IAAIC,WAAwB,IAAI;AAIlE,QAAM,CAAC,YAAY,aAAa,IAAIA,WAA6B,MAAS;AAC1E,QAAM,CAAC,cAAc,eAAe,IAAIA,WAAuB,IAAI;AAEnE,QAAM,CAAC,UAAU,WAAW,IAAIA,WAAiC,IAAI;AAErE,QAAM,CAAC,aAAa,cAAc,IAAIA,WAAwB,IAAI;AAGlE,QAAM,CAAC,eAAe,gBAAgB,IAAIA,WAAwB,IAAI;AACtE,QAAM,CAAC,aAAa,cAAc,IAAIA,WAA6B,MAAS;AAC5E,QAAM,iBAAiBD,SAAO,WAAW;AACzC,iBAAe,UAAU;AAEzB,QAAM,YAAYA,SAAO,KAAK;AAE9B,QAAM,aAAaA,SAA6C,MAAS;AAIzE,QAAM,iBAAiBA,SAAO,KAAK;AAEnC,QAAM,kBAAkBE;AAAA,IACtB,MAA0B,OAAO,QAAQ,YAAY,gBAAgB;AAAA,IACrE,CAAC;AAAA,EACH;AAGA,QAAM,CAAC,YAAY,aAAa,IAAID,WAAyB,WAAW;AACxE,QAAM,gBAAgBD,SAAO,UAAU;AACvC,QAAM,aAAaE,cAAY,CAAC,SAAyB;AACvD,kBAAc,UAAU;AACxB,kBAAc,IAAI;AAAA,EACpB,GAAG,CAAC,CAAC;AAEL,QAAM,CAAC,cAAc,eAAe,IAAID,WAA8B,CAAC,CAAC;AACxE,QAAM,CAAC,YAAY,aAAa,IAAIA,WAAuB,IAAI;AAE/D,QAAM,UAAUD,SAAsC,MAAS;AAE/D,QAAM,aAAaA,SAAqC,MAAS;AACjE,QAAM,qBAAqBA,SAA4B,YAAY;AAAA,EAAC,CAAC;AAErE,QAAM,gBAAgBA,SAA0C,CAAC,CAAC;AAGlE,QAAM,WAAWE,cAAY,MAA+B;AAC1D,UAAM,UAAU,OAAO;AAEvB,QAAI,QAAQ,YAAY,OAAW,kBAAiB,QAAQ,OAAO;AACnE,UAAM,cAAc,QAAQ,iBAAiB,KAAK;AAClD,UAAM,WAAW,gBAAgB;AAEjC,UAAM,QAAQ,QAAQ,UAAU,UAAU,UAAU,SAAY,eAAe;AAC/E,WAAO;AAAA;AAAA;AAAA,MAGL,GAAI,QAAQ,UAAU,SAAY,EAAE,OAAO,QAAQ,MAAM,IAAI,CAAC;AAAA,MAC9D,GAAI,QAAQ,YAAY,SAAY,EAAE,SAAS,QAAQ,QAAQ,IAAI,CAAC;AAAA,MACpE,GAAI,aAAa,SAAY,EAAE,SAAS,IAAI,CAAC;AAAA,MAC7C,GAAI,UAAU,SAAY,EAAE,MAAM,IAAI,CAAC;AAAA,MACvC,GAAI,cAAc,EAAE,YAAY,IAAI,CAAC;AAAA,MACrC,IAAK,QAAQ,kBAAkB,gBAAgB,aAAa,SACxD,CAAC,IACD,EAAE,gBAAgB,QAAQ,kBAAkB,gBAAgB,QAAQ;AAAA,IAC1E;AAAA,EACF,GAAG,CAAC,eAAe,CAAC;AAGpB,QAAM,CAAC,YAAY,aAAa,IAAID,WAAgC,EAAE,QAAQ,OAAO,CAAC;AAEtF,QAAM,oBAAoBD,SAAO,KAAK;AAItC,QAAM,YAAYG,UAAQ,MAAM;AAC9B,aAAS,OAAO,MAA6B;AAC3C,uBAAiB,UAAU,KAAK;AAChC,eAAS,KAAK,KAAK;AACnB,UAAI,KAAK,UAAU;AACjB,cAAM,UAAU,cAAc;AAC9B,sBAAc,UAAU,CAAC;AACzB,mBAAW,WAAW,QAAS,SAAQ,KAAK,QAAQ;AAAA,MACtD;AACA,UACE,OAAO,QAAQ,aAAa,UAC5B,KAAK,YACL,gBAAgB,YAAY,KAAK,UACjC;AACA,wBAAgB,UAAU,KAAK;AAC/B,cAAM,MAAM,WAAW;AACvB,YAAI,QAAQ,QAAW;AACrB,qBAAW,UAAU;AACrB,eAAK,OAAO,aAAa,KAAK,UAAU,EAAE,OAAO,IAAI,MAAM,CAAC,EAAE,MAAM,MAAM,MAAS;AAAA,QACrF;AACA,eAAO,QAAQ,kBAAkB,KAAK,QAAQ;AAC9C,sBAAc,QAAQ,EAAE,MAAM,UAAU,CAAC;AAAA,MAC3C;AAAA,IACF;AACA,WAAO,IAAI,mBAAmB;AAAA,MAC5B,SAAS;AAAA,MACT,GAAI,QAAQ,cAAc,SAAY,EAAE,WAAW,QAAQ,UAAU,IAAI,CAAC;AAAA,MAC1E,oBAAoB,CAAC,UAAU;AAC7B,YAAI,MAAM,WAAW,OAAQ,mBAAkB,UAAU;AACzD,sBAAc,MAAM,WAAW,SAAS,EAAE,QAAQ,OAAO,IAAI,KAAK;AAAA,MACpE;AAAA,MACA,GAAI,QAAQ,UAAU,SAAY,EAAE,OAAO,QAAQ,MAAM,IAAI,CAAC;AAAA,MAC9D,SAAS,MAAM;AACb,cAAMC,cAAa,eAAe;AAClC,uBAAe,UAAU;AACzB,eAAO,EAAE,GAAG,SAAS,GAAG,GAAIA,cAAa,EAAE,YAAY,KAAK,IAAI,CAAC,EAAG;AAAA,MACtE;AAAA,MACA,gBAAgB,MAAM,OAAO,QAAQ,eAAe,mBAAmB;AAAA;AAAA;AAAA,MAGvE,kBAAkB,CAAC,iBAAiB;AAClC,yBAAiB,UAAU;AAC3B,iBAAS,YAAY;AAAA,MACvB;AAAA,MACA;AAAA,MACA,gBAAgB,MAAM;AACpB,yBAAiB,UAAU;AAC3B,oBAAY,IAAI;AAAA,MAClB;AAAA,MACA,YAAY,CAAC,YAAY,YAAY,OAAO;AAAA;AAAA,MAE5C,cAAc,MAAM;AAClB,aAAK,iBAAiB;AAAA,MACxB;AAAA,IACF,CAAC;AAAA,EACH,GAAG,CAAC,CAAC;AAGL,QAAM,gBAAgBJ,SAA4B,MAAM,QAAQ,QAAQ,CAAC;AAEzE,QAAM,OAAO,QAAQ;AAAA,IACnB;AAAA,IACA,IAAI;AAAA,IACJ,QAAQ,QAAQ,gBAAgB;AAAA,IAChC,GAAI,QAAQ,oBAAoB,SAAY,EAAE,UAAU,QAAQ,gBAAgB,IAAI,CAAC;AAAA,IACrF,QAAQ,CAAC,SAAS;AAChB,aAAO,QAAQ,SAAS,IAAI;AAC5B,UAAI,KAAK,SAAS,yBAA0B,MAAK,mBAAmB,QAAQ;AAC5E,UAAI,KAAK,SAAS,cAAc;AAC9B,oBAAY,KAAK,IAAI;AAAA,MACvB;AACA,UAAI,KAAK,SAAS,cAAc;AAC9B,cAAM,QAAS,KAAK,MAAqC;AACzD,YAAI,OAAO,UAAU,UAAU;AAC7B,iBAAO,QAAQ,UAAU,KAAK;AAC9B,gBAAM,WAAW,gBAAgB;AACjC,cAAI,aAAa,OAAW,eAAc,QAAQ,EAAE,MAAM,SAAS,UAAU,MAAM,CAAC;AAAA,QACtF;AAAA,MACF;AAAA,IACF;AAAA,IACA,UAAU,CAAC,EAAE,QAAQ,MAAM;AACzB,aAAO,QAAQ,WAAW;AAC1B,UAAI,OAAO,QAAQ,eAAe,MAAM;AACtC,aAAK,cAAc,QAAQ;AAAA,MAC7B;AACA,YAAM,eAAe,iBAAiB;AACtC,UAAI,iBAAiB,QAAW;AAC9B,eAAO,QAAQ,eAAe;AAAA,UAC5B,OAAO;AAAA,UACP,QAAQ,UAAU,WAAW;AAAA,QAC/B,CAAC;AACD,sBAAc,QAAQ,EAAE,MAAM,UAAU,CAAC;AAAA,MAC3C;AACA,oBAAc,EAAE,QAAQ,OAAO,CAAC;AAChC,YAAM,gBAAgB,WAAW;AACjC,UAAI,kBAAkB,QAAW;AAC/B,mBAAW,UAAU;AAErB,gBAAQ,QAAQ,YAAY,CAAC,YAAY;AACvC,gBAAM,OAAO,cAAc,OAAO;AAClC,iBAAO,SAAS,KAAK,UAAU,QAAQ,MAAM,GAAG,IAAI;AAAA,QACtD,CAAC;AAAA,MACH;AACA,YAAM,OAAO,QAAQ;AACrB,cAAQ,UAAU;AAClB,UAAI,SAAS,QAAW;AACtB,iBAAS,IAAI;AACb;AAAA,MACF;AACA,UAAI,kBAAkB,SAAS;AAC7B,0BAAkB,UAAU;AAC5B,aAAK,iBAAiB;AAAA,MACxB;AAAA,IACF;AAAA,EACF,CAAC;AAED,QAAM,UAAUA,SAAO,IAAI;AAC3B,UAAQ,UAAU;AAGlB,WAAS,YAAY,MAAqB;AACxC,UAAM,QAAS,QAAQ,CAAC;AAKxB,UAAM,SAAS,cAAc;AAC7B,QAAI,MAAM,UAAU,OAAW,YAAW,MAAM,KAAK;AACrD,UAAM,UAAU,MAAM;AAEtB,QAAI,YAAY,UAAa,QAAQ,UAAU,iBAAiB,SAAS;AACvE,YAAM,UAAU,OAAO,MAAM,KAAK,CAAC,SAAS,KAAK,OAAO,QAAQ,SAAS;AACzE,cAAQ,UAAU;AAAA,QAChB,GAAG;AAAA,QACH,MAAM,SAAS,WAAW;AAAA,QAC1B,aAAa,SAAS,eAAe,CAAC;AAAA,MACxC;AAAA,IACF;AACA,QAAI,MAAM,eAAe,QAAW;AAClC,iBAAW,UAAU,MAAM;AAC3B,UAAI,MAAM,WAAW,UAAU,QAAW;AACxC,gBAAQ,UAAU;AAAA,UAChB,WAAW,MAAM,WAAW;AAAA,UAC5B,OAAO,MAAM,WAAW;AAAA,UACxB,GAAG,QAAQ,QAAQ,QAAQ,SAAS,cAAc,QAAQ,QAAQ,QAAQ,CAAC,CAAC;AAAA,QAC9E;AAAA,MACF;AAAA,IACF;AAAA,EACF;AAOA,WAAS,SAAS,MAA+B;AAC/C,eAAW,MAAM;AACf,UAAI,KAAK,KAAK,SAAS,KAAK,KAAK,YAAY,SAAS,GAAG;AACvD,gBAAQ,QAAQ;AAAA,UAAY,CAAC,YAC3B,QAAQ,KAAK,CAAC,YAAY,QAAQ,OAAO,KAAK,SAAS,IACnD,UACA,CAAC,GAAG,SAAS,kBAAkB,IAAI,CAAC;AAAA,QAC1C;AAAA,MACF,OAAO;AAEL,0BAAkB,UAAU;AAAA,MAC9B;AACA,yBAAmB,UAAU,KAAK;AAClC,WAAK,QAAQ,QAAQ,aAAa;AAAA,IACpC,GAAG,CAAC;AAAA,EACN;AAGA,iBAAe,mBAAkC;AAC/C,UAAM,WAAW,gBAAgB;AACjC,QAAI,aAAa,OAAW;AAC5B,QAAI;AACF,YAAM,SAAS,MAAM,OAAO,UAAU,QAAQ;AAC9C,cAAQ,QAAQ,YAAY,yBAAyB,OAAO,QAAQ,CAAC;AAAA,IACvE,QAAQ;AAAA,IAER;AAAA,EACF;AAGA,QAAM,cAAcA,SAAO,MAAM;AAEjC,EAAAK,YAAU,MAAM;AACd,QAAI,WAAW,YAAY,QAAS;AACpC,gBAAY,UAAU;AACtB,aAAS,MAAS;AAClB,mBAAe,IAAI;AACnB,mBAAe,IAAI;AACnB,qBAAiB,IAAI;AACrB,mBAAe,MAAS;AACxB,sBAAkB,CAAC,CAAC;AACpB,oBAAgB,IAAI;AACpB,gBAAY,IAAI;AAChB,uBAAmB,UAAU;AAC7B,eAAW,UAAU;AACrB,eAAW,WAAW;AACtB,oBAAgB,CAAC,CAAC;AAClB,kBAAc,IAAI;AAClB,YAAQ,UAAU;AAClB,eAAW,UAAU;AAAA,EACvB,GAAG,CAAC,MAAM,CAAC;AAKX,EAAAA,YAAU,MAAM;AACd,UAAM,WAAW,QAAQ;AACzB,QAAI,aAAa,OAAW;AAE5B,QAAI,aAAa,gBAAgB,QAAS;AAC1C,UAAM,UAAU,OAAO;AACvB,UAAM,cAAc,QAAQ,YAAY,SAAS,QAAQ,oBAAoB;AAC7E,UAAM,aAAa,QAAQ,WAAW,SAAS,QAAQ,gBAAgB;AACvE,QAAI,CAAC,eAAe,CAAC,WAAY;AACjC,QAAI,YAAY;AAChB,WACG,UAAU,QAAQ,EAClB;AAAA,MACC,CAAC,WAAqC;AACpC,YAAI,aAAa,UAAU,KAAM;AACjC,cAAM,SAAS,OAAO,eAAe;AACrC,cAAM,SAAS,MAAM,QAAQ,OAAO,QAAQ,IAAI,OAAO,WAAW,CAAC;AACnE,uBAAe,MAAM;AACrB,uBAAe,OAAO,SAAS,IAAI;AACnC,yBAAiB,OAAO,WAAW,IAAI;AACvC,wBAAgB,IAAI;AACpB,cAAMC,SAAQ,OAAO,SAAS;AAC9B,mBAAWA,MAAK;AAGhB,YACEA,OAAM,MAAM,SAAS,KACrBA,OAAM,WAAW,QACjB,WAAW,QACX,OAAO,OAAO,gBAAgB,YAC9B;AACA,eAAK,eAAe,QAAQ,EAAE,MAAM,MAAM,MAAS;AAAA,QACrD;AACA,cAAM,WAAW,cAAc,WAAW;AAC1C,YAAI,eAAe,QAAQ,QAAQ,SAAS,WAAW,GAAG;AAExD,gBAAM,OAAO,WACT,OAAO;AAAA,YACL,CAAC,YACC,EAAE,QAAQ,SAAS,eAAe,QAAQ,UAAU;AAAA,UACxD,IACA;AACJ,kBAAQ,QAAQ,YAAY,yBAAyB,IAAI,CAAC;AAAA,QAC5D;AACA,YAAI,UAAU;AACZ,6BAAmB,UAAU;AAC7B,eAAK,QAAQ,QAAQ,aAAa;AAAA,QACpC;AAAA,MACF;AAAA,MACA,CAAC,UAAmB;AAClB,YAAI,UAAW;AACf,wBAAgB,iBAAiB,QAAQ,QAAQ,IAAI,MAAM,OAAO,KAAK,CAAC,CAAC;AAAA,MAC3E;AAAA,IACF,EACC,QAAQ,MAAM;AACb,UAAI,CAAC,UAAW,eAAc,QAAQ;AAAA,IACxC,CAAC;AACH,WAAO,MAAM;AACX,kBAAY;AAAA,IACd;AAAA,EACF,GAAG,CAAC,QAAQ,QAAQ,QAAQ,QAAQ,CAAC;AAErC,QAAM,mBACJ,QAAQ,aAAa,UACrB,QAAQ,aAAa,gBAAgB,WACrC,QAAQ,YAAY,SACpB,QAAQ,oBAAoB,UAC5B,eAAe,QAAQ;AAOzB,QAAM,eAAeN,SAAO,KAAK;AACjC,QAAM,iBAAiBE;AAAA,IACrB,MAAM,aAAa,WAAW,UAAU;AAAA,IACxC,CAAC,SAAS;AAAA,EACZ;AAGA,QAAM,QAAoB,SAAS;AAAA,IACjC,SAAS;AAAA,IACT,SAAS,QAAQ,UAAU,SAAS,OAAO,OAAO,aAAa;AAAA,EACjE,CAAC;AACD,QAAM,UACJ,QAAQ,YAAY,SAAY,QAAQ,UAAU,MAAM;AAC1D,QAAM,aAAaF,SAAO,OAAO;AACjC,aAAW,UAAU;AAGrB,QAAM,eACJ,OAAO,OAAO,mBAAmB,aAAc,QAAQ,gBAAgB,UAAW;AACpF,QAAM,kBAAkBA,SAAO,YAAY;AAC3C,kBAAgB,UAAU;AAC1B,QAAM,cAAcA,SAAO,KAAK;AAChC,cAAY,UAAU,OAAO,OAAO,mBAAmB;AAGvD,QAAM,iBAAiBE,cAAY,YAA6B;AAC9D,UAAM,QAAQ,gBAAgB;AAC9B,QAAI,UAAU,OAAW,QAAO;AAChC,QAAI,CAAC,eAAe,EAAG,OAAM,IAAI,MAAM,oCAAoC;AAC3E,WAAO,IAAI,QAAgB,CAAC,YAAY,cAAc,QAAQ,KAAK,OAAO,CAAC;AAAA,EAC7E,GAAG,CAAC,iBAAiB,cAAc,CAAC;AAGpC,QAAM,YAAYA,cAAY,OAAU,QAAsC;AAC5E,QAAI;AACF,YAAM,SAAS,MAAM,IAAI;AACzB,oBAAc,IAAI;AAClB,aAAO;AAAA,IACT,SAAS,OAAO;AACd,oBAAc,iBAAiB,QAAQ,QAAQ,IAAI,MAAM,OAAO,KAAK,CAAC,CAAC;AACvE,YAAM;AAAA,IACR;AAAA,EACF,GAAG,CAAC,CAAC;AAGL,QAAM,UAAUA;AAAA,IACd,OACEK,OACA;AAAA,MACE,cAAc,CAAC;AAAA,MACf,OAAO;AAAA,IACT,IAAyE,CAAC,MACxD;AAClB,YAAM,QAAQ,WAAW;AACzB,UAAI,SAAS,KAAM,OAAM,IAAI,kBAAkB,KAAK;AACpD,YAAM,OAAO,OAAO;AACpB,UAAI,OAAO,SAAS,WAAY,OAAM,IAAI,6BAA6B,gBAAgB;AACvF,4BAAsB;AACtB,YAAM,UAAU,gBAAgB,kBAAkB;AAClD,sBAAgB,CAAC,YAAY;AAAA,QAC3B,GAAG;AAAA,QACH;AAAA,UACE,IAAI;AAAA,UACJ,MAAAA;AAAA,UACA;AAAA,UACA,OAAO,YAAY,IAAI,cAAc;AAAA,UACrC,OAAO;AAAA,UACP,WAAW,SAAS;AAAA,UACpB,YAAW,oBAAI,KAAK,GAAE,YAAY;AAAA,QACpC;AAAA,MACF,CAAC;AACD,UAAI;AACF,cAAM,UAAU,YAAY;AAC1B,gBAAM,WAAW,MAAM,eAAe;AACtC,gBAAM,SAAS,MAAM,KAAK,KAAK,QAAQ;AAAA,YACrC,MAAM;AAAA,cACJ,GAAG,SAAS;AAAA,cACZ;AAAA,cACA,SAASA;AAAA,cACT;AAAA,cACA,GAAI,YAAY,SAAS,IACrB,EAAE,aAAa,YAAY,IAAI,CAAC,EAAE,QAAQ,OAAO,EAAE,QAAQ,EAAE,EAAE,IAC/D,CAAC;AAAA,YACP;AAAA,UACF,CAAC;AACD,qBAAW,OAAO,KAAK;AACvB,cAAI,OAAO,UAAU,QAAW;AAE9B,kBAAM,OAAO,EAAE,WAAW,OAAO,WAAW,OAAO,OAAO,OAAO,MAAAA,OAAM,YAAY;AACnF,gBAAI,eAAe,EAAG,SAAQ,UAAU;AAAA,gBACnC,UAAS,IAAI;AAAA,UACpB;AAAA,QACF,CAAC;AAAA,MACH,UAAE;AACA,wBAAgB,CAAC,YAAY,QAAQ,OAAO,CAAC,SAAS,KAAK,OAAO,OAAO,CAAC;AAAA,MAC5E;AAAA,IACF;AAAA,IACA,CAAC,QAAQ,WAAW,gBAAgB,UAAU,YAAY,cAAc;AAAA,EAC1E;AAGA,QAAM,cAAcL;AAAA,IAClB,OACE,SACAM,aACkB;AAClB,YAAM,QAAQ,WAAW;AACzB,UAAI,SAAS,KAAM,OAAM,IAAI,kBAAkB,KAAK;AAEpD,YAAM,EAAE,MAAM,SAAS,GAAG,WAAW,IAAIA,YAAW,CAAC;AACrD,UAAI,eAAe,GAAG;AAGpB,cAAM,OAAO,YAAY,UAAW,WAAW,gBAAgB,UAAW;AAC1E,YAAI,SAAS,QAAS;AACtB,cAAM,QAAQ,QAAQ,OAAO;AAC7B,cAAM,QAAQ,MAAM,MAAM,EAAE,aAAa,MAAM,aAAa,KAAK,CAAC;AAClE;AAAA,MACF;AACA,mBAAa,UAAU;AACvB,UAAI;AACF,cAAM,QAAQ,QAAQ;AAAA,UACpB;AAAA,UACAA,aAAY,SAAY,SAAa;AAAA,QACvC;AAAA,MACF,UAAE;AACA,qBAAa,UAAU;AAAA,MACzB;AAAA,IACF;AAAA,IACA,CAAC,gBAAgB,OAAO;AAAA,EAC1B;AAEA,QAAM,eAAeN;AAAA,IACnB,OAAO,OAA8B;AACnC,YAAM,WAAW,cAAc;AAC/B,iBAAW,EAAE,GAAG,UAAU,OAAO,SAAS,MAAM,OAAO,CAAC,SAAS,KAAK,OAAO,EAAE,EAAE,CAAC;AAClF,UAAI;AACF,mBAAW,MAAM,UAAU,MAAM,qBAAqB,QAAQ,qBAAqB,EAAE,EAAE,CAAC,CAAC;AAAA,MAC3F,SAAS,OAAO;AACd,mBAAW,QAAQ;AACnB,cAAM;AAAA,MACR;AAAA,IACF;AAAA,IACA,CAAC,QAAQ,WAAW,UAAU;AAAA,EAChC;AAGA,QAAM,kBAAkBA;AAAA,IACtB,OAAO,OAA8B;AACnC,YAAM,WAAW,cAAc;AAC/B,YAAM,SAAS,SAAS,MAAM,KAAK,CAAC,SAAS,KAAK,OAAO,EAAE;AAC3D,UAAI,WAAW,QAAW;AAExB,mBAAW;AAAA,UACT,QAAQ;AAAA,UACR,OAAO;AAAA,YACL,EAAE,GAAG,QAAQ,WAAW,KAAK;AAAA,YAC7B,GAAG,SAAS,MAAM,OAAO,CAAC,SAAS,KAAK,OAAO,EAAE;AAAA,UACnD;AAAA,QACF,CAAC;AAAA,MACH;AACA,UAAI;AACF,cAAM,SAAS,MAAM;AAAA,UAAU,MAC7B,qBAAqB,QAAQ,wBAAwB,EAAE,EAAE;AAAA,QAC3D;AACA,mBAAW,EAAE,OAAO,OAAO,OAAO,QAAQ,OAAO,OAAO,CAAC;AACzD,YAAI,OAAO,UAAU,QAAW;AAE9B,gBAAM,OAAO;AAAA,YACX,WAAW,OAAO;AAAA,YAClB,OAAO,OAAO;AAAA,YACd,MAAM,QAAQ,WAAW;AAAA,YACzB,aAAa,QAAQ,eAAe,CAAC;AAAA,UACvC;AACA,cAAI,eAAe,EAAG,SAAQ,UAAU;AAAA,cACnC,UAAS,IAAI;AAAA,QACpB;AAAA,MACF,SAAS,OAAO;AACd,mBAAW,QAAQ;AACnB,cAAM;AAAA,MACR;AAAA,IACF;AAAA,IACA,CAAC,QAAQ,WAAW,YAAY,cAAc;AAAA,EAChD;AAEA,QAAM,aAAaA;AAAA,IACjB,OAAO,IAAYK,UAAgC;AACjD;AAAA,QACE,MAAM;AAAA,UAAU,MACd,qBAAqB,QAAQ,qBAAqB,EAAE,IAAI,EAAE,SAASA,MAAK,CAAC;AAAA,QAC3E;AAAA,MACF;AAAA,IACF;AAAA,IACA,CAAC,QAAQ,WAAW,UAAU;AAAA,EAChC;AAEA,QAAM,aAAaL;AAAA,IACjB,OAAO,IAAY,UAAiC;AAClD,YAAM,WAAW,cAAc;AAC/B,YAAM,SAAS,SAAS,MAAM,KAAK,CAAC,SAAS,KAAK,OAAO,EAAE;AAC3D,UAAI,WAAW,QAAW;AACxB,cAAM,OAAO,SAAS,MAAM,OAAO,CAAC,SAAS,KAAK,OAAO,EAAE;AAC3D,aAAK,OAAO,KAAK,IAAI,GAAG,KAAK,IAAI,KAAK,QAAQ,KAAK,CAAC,GAAG,GAAG,MAAM;AAChE,mBAAW,EAAE,GAAG,UAAU,OAAO,KAAK,CAAC;AAAA,MACzC;AACA,UAAI;AACF;AAAA,UACE,MAAM;AAAA,YAAU,MACd,qBAAqB,QAAQ,qBAAqB,EAAE,IAAI,EAAE,UAAU,MAAM,CAAC;AAAA,UAC7E;AAAA,QACF;AAAA,MACF,SAAS,OAAO;AACd,mBAAW,QAAQ;AACnB,cAAM;AAAA,MACR;AAAA,IACF;AAAA,IACA,CAAC,QAAQ,WAAW,UAAU;AAAA,EAChC;AAEA,QAAM,aAAaA,cAAY,YAA2B;AACxD,UAAM,WAAW,gBAAgB;AACjC,QAAI,aAAa,OAAW;AAC5B,eAAW,MAAM,UAAU,MAAM,qBAAqB,QAAQ,YAAY,EAAE,QAAQ,CAAC,CAAC;AAAA,EACxF,GAAG,CAAC,QAAQ,WAAW,iBAAiB,UAAU,CAAC;AAGnD,QAAM,cAAcA,cAAY,YAA2B;AACzD,UAAM,WAAW,gBAAgB;AACjC,QAAI,aAAa,OAAW;AAC5B,UAAM,SAAS,cAAc;AAC7B,UAAM,SAAS,MAAM,UAAU,MAAM,qBAAqB,QAAQ,aAAa,EAAE,QAAQ,CAAC;AAC1F,eAAW,EAAE,OAAO,OAAO,OAAO,QAAQ,OAAO,OAAO,CAAC;AACzD,QAAI,OAAO,UAAU,QAAW;AAC9B,YAAM,OAAO,OAAO,MAAM,KAAK,CAAC,SAAS,KAAK,OAAO,OAAO,KAAK,KAAK,OAAO,MAAM,CAAC;AACpF,YAAM,OAAO;AAAA,QACX,WAAW,OAAO;AAAA,QAClB,OAAO,OAAO;AAAA,QACd,MAAM,MAAM,WAAW;AAAA,QACvB,aAAa,MAAM,eAAe,CAAC;AAAA,MACrC;AACA,UAAI,eAAe,EAAG,SAAQ,UAAU;AAAA,UACnC,UAAS,IAAI;AAAA,IACpB;AAAA,EACF,GAAG,CAAC,QAAQ,WAAW,iBAAiB,YAAY,cAAc,CAAC;AACnE,QAAM,iBAAiBF,SAAO,WAAW;AACzC,iBAAe,UAAU;AAEzB,QAAM,cAAmC;AAAA,IACvC,GAAG,aAAa,OAAO,CAAC,SAAS,KAAK,SAAS;AAAA,IAC/C,GAAG,WAAW,MAAM;AAAA,MAClB,CAAC,UAA6B;AAAA,QAC5B,IAAI,KAAK;AAAA,QACT,MAAM,KAAK;AAAA,QACX,aAAa,KAAK,eAAe,CAAC;AAAA,QAClC,QAAQ,KAAK,eAAe,CAAC,GAAG,IAAI,cAAc;AAAA,QAClD,OAAO;AAAA,QACP,WAAW,KAAK,cAAc;AAAA,QAC9B,WAAW,KAAK;AAAA,MAClB;AAAA,IACF;AAAA,IACA,GAAG,aAAa,OAAO,CAAC,SAAS,CAAC,KAAK,SAAS;AAAA,EAClD;AACA,QAAM,QAAmB;AAAA,IACvB,OAAO;AAAA,IACP,QAAQ,WAAW;AAAA,IACnB,aAAa,OAAO,OAAO,mBAAmB;AAAA,IAC9C,KAAK;AAAA,IACL,QAAQ;AAAA,IACR,WAAW;AAAA,IACX,MAAM;AAAA,IACN,MAAM;AAAA,IACN,OAAO;AAAA,IACP,QAAQ;AAAA,IACR,OAAO;AAAA,EACT;AAMA,QAAM,gBAAgBE;AAAA,IACpB,CAAC,EAAE,MAAM,YAAY,OAAO,MAC1B,QAAQ,QAAQ,cAAc;AAAA,MAC5B;AAAA,MACA;AAAA,MACA;AAAA,IACF,CAAuB;AAAA,IACzB,CAAC;AAAA,EACH;AAGA,QAAM,CAAC,gBAAgB,iBAAiB,IAAID,WAA0B,CAAC,CAAC;AAGxE,QAAM,oBAAoBC,cAAY,YAA2B;AAC/D,UAAM,WAAW,gBAAgB;AACjC,QAAI,aAAa,QAAW;AAC1B;AAAA,IACF;AACA,UAAM,SAAS,MAAM,OAAO,UAAU,QAAQ;AAC9C,UAAM,OAAO,yBAAyB,OAAO,QAAQ;AACrD,sBAAkB,IAAI;AACtB,UAAM,SAAS,KACZ,IAAI,CAAC,QAAQ,IAAI,OAAO,EACxB,OAAO,CAAC,YAAoD,YAAY,MAAS;AACpF,QAAI,OAAO,WAAW,GAAG;AACvB;AAAA,IACF;AAGA,YAAQ,QAAQ,YAAY,CAAC,YAAY;AACvC,YAAM,QAAQ,IAAI,IAAI,QAAQ,IAAI,CAAC,YAAY,QAAQ,EAAE,CAAC;AAC1D,YAAM,UAAU,OAAO,OAAO,CAAC,YAAY,CAAC,MAAM,IAAI,QAAQ,EAAE,CAAC;AACjE,aAAO,QAAQ,WAAW,IACtB,UACA,CAAC,GAAG,SAAS,GAAG,QAAQ,IAAI,CAAC,YAAY,yBAAyB,OAAO,CAAC,CAAC;AAAA,IACjF,CAAC;AAAA,EACH,GAAG,CAAC,QAAQ,eAAe,CAAC;AAE5B,gBAAc,UAAU;AAExB,QAAM,YAAY,eAAe,KAAK,CAAC,QAAQ,IAAI,WAAW,SAAS;AAGvE,EAAAG,YAAU,MAAM;AACd,QAAI,QAAQ,eAAe,QAAQ,QAAQ,aAAa,QAAW;AACjE;AAAA,IACF;AACA,SAAK,kBAAkB;AAAA,EACzB,GAAG,CAAC,QAAQ,YAAY,QAAQ,UAAU,QAAQ,iBAAiB,CAAC;AAEpE,EAAAA,YAAU,MAAM;AACd,UAAM,QAAQ,OAAO,QAAQ,oBAAoB;AACjD,QAAI,OAAO,QAAQ,eAAe,QAAQ,CAAC,aAAa,SAAS,GAAG;AAClE;AAAA,IACF;AACA,UAAM,QAAQ,YAAY,MAAM,KAAK,kBAAkB,GAAG,KAAK;AAC/D,WAAO,MAAM,cAAc,KAAK;AAAA,EAClC,GAAG,CAAC,WAAW,iBAAiB,CAAC;AAEjC,QAAM,YAAY;AAAA,IAChB;AAAA,IACA,QAAQ,cAAc,SACnB,QAAQ,cAAc,QAAQ,QAAQ,YAAY,SAAS,QAAQ,WAAW,QAC7E,SACA,gBAAgB;AAAA,IACpB,CAAC,WAAW,QAAQ,QAAQ,YAAY,MAAM;AAAA,IAC9C,GAAG,KAAK,MAAM,IAAI,WAAW,MAAM;AAAA,IACnC,QAAQ;AAAA,EACV;AAEA,qBAAmB,UAAU,UAAU;AAGvC,QAAM,SAASH,cAAY,YAA2B;AAGpD,YAAQ,QAAQ,KAAK;AACrB,UAAM,SAAS,SAAS;AACxB,QAAI,QAAQ;AACV,UAAI;AACF,cAAM,OAAO,aAAa,MAAM;AAAA,MAClC,QAAQ;AAAA,MAER;AAAA,IACF;AAGA,UAAM,WAAW,gBAAgB;AACjC,QACE,aAAa,UACb,cAAc,QAAQ,MAAM,SAAS,KACrC,OAAO,OAAO,aAAa,YAC3B;AACA,UAAI;AACF,mBAAW,MAAM,OAAO,SAAS,QAAQ,CAAC;AAAA,MAC5C,QAAQ;AAAA,MAER;AAAA,IACF;AAAA,EACF,GAAG,CAAC,QAAQ,iBAAiB,UAAU,CAAC;AAIxC,QAAM,UAAUA;AAAA,IACd,OAAO,EAAE,YAAY,QAAQ,UAAU,IAAI,MAAmC;AAC5E,UAAI,QAAQ,SAAS,YAAY;AAC/B,cAAM,WAAW,OAAO,YAAY,gBAAgB;AACpD,YAAI,aAAa;AACf,gBAAM,IAAI,MAAM,+CAA+C;AACjE,cAAM;AAAA,UACJ;AAAA,UACA;AAAA,QACF,EAAE;AAAA,UACA;AAAA,UACA,YAAY,OAAO;AAAA,UACnB,GAAI,aAAa,OAAO,EAAE,UAAU,KAAK,IAAI,CAAC;AAAA,QAChD,CAAC;AACD,cAAM,UAAU,QAAQ;AACxB;AAAA,MACF;AACA,YAAM;AAAA,QACJ;AAAA,QACA;AAAA,MACF,EAAE;AAAA,QACA;AAAA,QACA,GAAI,aAAa,OAAO,EAAE,UAAU,KAAK,IAAI,CAAC;AAAA,QAC9C,GAAI,QAAQ,SAAY,EAAE,IAAI,IAAI,CAAC;AAAA,MACrC,CAAC;AAAA,IACH;AAAA,IACA,CAAC,QAAQ,iBAAiB,UAAU,OAAO;AAAA,EAC7C;AAEA,QAAM,SAASA;AAAA,IACb,OAAO,EAAE,YAAY,QAAQ,QAAQ,IAAI,MAAkC;AACzE,UAAI,QAAQ,SAAS,YAAY;AAC/B,cAAM,WAAW,OAAO,YAAY,gBAAgB;AACpD,YAAI,aAAa;AACf,gBAAM,IAAI,MAAM,+CAA+C;AACjE,cAAM;AAAA,UACJ;AAAA,UACA;AAAA,QACF,EAAE;AAAA,UACA;AAAA,UACA,YAAY,OAAO;AAAA,UACnB,GAAI,WAAW,SAAY,CAAC,IAAI,EAAE,OAAO;AAAA,QAC3C,CAAC;AACD,cAAM,UAAU,QAAQ;AACxB;AAAA,MACF;AACA,YAAM;AAAA,QACJ;AAAA,QACA;AAAA,MACF,EAAE;AAAA,QACA;AAAA,QACA,GAAI,WAAW,SAAY,EAAE,OAAO,IAAI,CAAC;AAAA,QACzC,GAAI,QAAQ,SAAY,EAAE,IAAI,IAAI,CAAC;AAAA,MACrC,CAAC;AAAA,IACH;AAAA,IACA,CAAC,QAAQ,iBAAiB,UAAU,OAAO;AAAA,EAC7C;AAEA,QAAM,SAASA;AAAA,IACb,OAAO,EAAE,YAAY,SAAS,IAAI,MAAkC;AAClE,YAAM;AAAA,QACJ;AAAA,QACA;AAAA,MACF,EAAE;AAAA,QACA;AAAA,QACA,GAAI,YAAY,SAAY,EAAE,QAAQ,IAAI,CAAC;AAAA,QAC3C,GAAI,QAAQ,SAAY,EAAE,IAAI,IAAI,CAAC;AAAA,MACrC,CAAC;AAAA,IACH;AAAA,IACA,CAAC,MAAM;AAAA,EACT;AAEA,QAAM,OAAOA;AAAA,IACX,OAAO,EAAE,YAAY,IAAI,MAAgC;AACvD,YAAM;AAAA,QACJ;AAAA,QACA;AAAA,MACF,EAAE,EAAE,YAAY,GAAI,QAAQ,SAAY,EAAE,IAAI,IAAI,CAAC,EAAG,CAAC;AAAA,IACzD;AAAA,IACA,CAAC,MAAM;AAAA,EACT;AAIA,QAAM,aAAaA;AAAA,IACjB,CAAC,WAA+C;AAC9C,YAAM,QAAQ,WAAW;AACzB,UAAI,SAAS,KAAM,OAAM,IAAI,kBAAkB,KAAK;AACpD,UAAI,eAAe,EAAG;AACtB,qBAAe,UAAU;AACzB,mBAAa,UAAU;AACvB,WAAK,QAAQ,QAAQ,WAAW,EAAE,QAAQ,MAAM;AAC9C,qBAAa,UAAU;AAAA,MACzB,CAAC;AAAA,IACH;AAAA,IACA,CAAC,cAAc;AAAA,EACjB;AAMA,QAAM,aAAaA;AAAA,IACjB,OAAO,WAAmB,aAAsC;AAC9D,YAAM,UAAU,QAAQ,QAAQ,SAAS,KAAK,CAAC,cAAc,UAAU,OAAO,SAAS;AACvF,YAAM,QAAS,SAAS,UAA+C;AACvE,UAAI,UAAU,OAAW,QAAO;AAChC,YAAM,SAAS,MAAM,OAAO,UAAU,QAAQ;AAC9C,YAAM,MAAM,CAAC,GAAG,OAAO,QAAQ,EAC5B,QAAQ,EACR,KAAK,CAAC,cAAc,UAAU,SAAS,eAAe,UAAU,UAAU,KAAK;AAClF,aAAO,KAAK,MAAM;AAAA,IACpB;AAAA,IACA,CAAC,MAAM;AAAA,EACT;AAMA,QAAM,OAAOA;AAAA,IACX,OAAO;AAAA,MACL;AAAA,MACA;AAAA,IACF,MAA0E;AACxE,YAAM,SAAS,YAAY,gBAAgB;AAC3C,UAAI,WAAW,OAAW,OAAM,IAAI,MAAM,mCAAmC;AAC7E,YAAM,SAAS,MAAM,WAAW,WAAW,MAAM;AACjD,YAAM,SAAS,MAAM,qBAAqB,QAAQ,iBAAiB,EAAE,QAAQ,MAAM;AACnF,oBAAc,QAAQ,EAAE,MAAM,UAAU,CAAC;AACzC,aAAO,QAAQ,kBAAkB,OAAO,EAAE;AAC1C,aAAO;AAAA,IACT;AAAA,IACA,CAAC,QAAQ,iBAAiB,UAAU;AAAA,EACtC;AAGA,QAAM,eAAeA;AAAA,IACnB,OAAO,EAAE,WAAW,SAAS,MAAiE;AAC5F,YAAM,SAAS,YAAY,gBAAgB;AAC3C,UAAI,WAAW,OAAW,OAAM,IAAI,MAAM,2CAA2C;AACrF,YAAM,SAAS,MAAM,WAAW,WAAW,MAAM;AACjD,YAAM,qBAAqB,QAAQ,qBAAqB,EAAE,QAAQ,MAAM;AAAA,IAC1E;AAAA,IACA,CAAC,QAAQ,iBAAiB,UAAU;AAAA,EACtC;AAGA,QAAM,UAAUA;AAAA,IACd,OAAO,EAAE,SAAS,IAA2B,CAAC,MAAqB;AACjE,YAAM,SAAS,YAAY,gBAAgB;AAC3C,UAAI,WAAW,OAAW,OAAM,IAAI,MAAM,sCAAsC;AAChF,YAAM,qBAAqB,QAAQ,eAAe,EAAE,MAAM;AAC1D,oBAAc,QAAQ,EAAE,MAAM,UAAU,CAAC;AAAA,IAC3C;AAAA,IACA,CAAC,QAAQ,eAAe;AAAA,EAC1B;AAGA,QAAM,CAAC,cAAc,eAAe,IAAID,WAAS,KAAK;AACtD,QAAM,kBAAkBD,SAAO,YAAY;AAC3C,kBAAgB,UAAU;AAC1B,QAAM,UAAU,UAAU;AAAA,IACxB,SAAS;AAAA,IACT,GAAI,QAAQ,UAAU,SAAY,EAAE,OAAO,QAAQ,MAAM,IAAI,CAAC;AAAA,IAC9D,SAAS,gBAAgB,OAAO,OAAO,eAAe;AAAA,EACxD,CAAC;AACD,QAAM,aAAaE,cAAY,MAAM;AACnC,QAAI,gBAAgB,QAAS;AAC7B,oBAAgB,UAAU;AAE1B,mBAAe,MAAM,gBAAgB,IAAI,CAAC;AAAA,EAC5C,GAAG,CAAC,CAAC;AACL,YAAU,UAAU,QAAQ,WAAW;AACvC,QAAM,cAAcA,cAAY,CAAC,OAAe;AAC9C,QAAI,CAAC,UAAU,QAAS,gBAAe,EAAE;AAAA,EAC3C,GAAG,CAAC,CAAC;AACL,QAAM,cAAcA;AAAA,IAClB,OAAO,UAAwC;AAC7C,YAAM,WAAW,gBAAgB;AACjC,qBAAe,KAAK;AAEpB,qBAAe,MAAS;AACxB,UAAI,aAAa,QAAW;AAC1B,mBAAW,UAAU,EAAE,MAAM;AAC7B;AAAA,MACF;AACA,YAAM,OAAO,aAAa,UAAU,EAAE,MAAM,CAAC;AAC7C,oBAAc,QAAQ,EAAE,MAAM,UAAU,CAAC;AAAA,IAC3C;AAAA,IACA,CAAC,QAAQ,eAAe;AAAA,EAC1B;AACA,QAAM,SAAqB;AAAA,IACzB,IAAI,OAAO;AACT,iBAAW;AACX,aAAO,QAAQ;AAAA,IACjB;AAAA,IACA,IAAI,YAAY;AACd,iBAAW;AACX,aAAO,QAAQ;AAAA,IACjB;AAAA,IACA,UACE,QAAQ,QAAQ,SAChB,QAAQ,SACR,eACA,eACA,QAAQ,gBACR;AAAA,IACF,QAAQ;AAAA,IACR,IAAI,eAAe;AACjB,iBAAW;AACX,aAAO,QAAQ;AAAA,IACjB;AAAA,IACA,IAAI,SAAS;AACX,iBAAW;AACX,aAAO,QAAQ;AAAA,IACjB;AAAA,IACA,QAAQ;AAAA,IACR;AAAA,IACA,WAAW,gBAAgB,QAAQ;AAAA,IACnC,OAAO,QAAQ;AAAA,EACjB;AAIA,QAAM,SAAqB,WAAW,WAAW,iBAAiB,iBAAiB,KAAK;AACxF,QAAM,SAAS,WAAW,eAAe,WAAW,eAAe,WAAW;AAC9E,QAAM,YAAYF,SAAO,MAAM;AAC/B,YAAU,UAAU;AAGpB,QAAM,QAAQ,eAAe,EAAE,GAAG,QAAQ,UAAU,SAAS,OAAO,CAAC;AACrE,QAAM,CAAC,MAAM,OAAO,IAAIC,WAAS,EAAE;AACnC,QAAM,YACJ,WAAW,OACP,UACA,MAAM,cACJ,cACA,UAAU,iBAAiB,UACzB,SACA,KAAK,KAAK,EAAE,WAAW,KAAK,MAAM,KAAK,WAAW,IAChD,UACA;AACZ,QAAM,cAAcD,SAAO,EAAE,MAAM,OAAO,UAAU,CAAC;AACrD,cAAY,UAAU,EAAE,MAAM,OAAO,UAAU;AAC/C,QAAM,SAASE;AAAA,IACb,OAAOM,aAA8C;AACnD,YAAM,UAAU,YAAY;AAE5B,YAAM,QAAQ,YAAY,UAAUA,UAAS,OAAO;AACpD,UAAI,QAAQ,cAAc,QAAQ,EAAE,QAAQ,cAAc,UAAU,UAAU,SAAY;AACxF;AAAA,MACF;AACA,UAAI,QAAQ,KAAK,KAAK,EAAE,WAAW,KAAK,QAAQ,MAAM,KAAK,WAAW,EAAG;AACzE,YAAM,OAAO,QAAQ,MAAM;AAE3B,YAAMC,SAAQ,QAAQ,MAAM,MAAM;AAAA,QAAQ,CAAC,SACzC,KAAK,WAAW,WAAW,KAAK,eAAe,SAC3C;AAAA,UACE;AAAA,YACE,MAAM;AAAA,YACN,WAAW,KAAK,WAAW;AAAA,YAC3B,UAAU,KAAK,WAAW;AAAA,YAC1B,KAAK,KAAK,WAAW;AAAA,YACrB,kBAAkB,EAAE,OAAO,EAAE,SAAS,KAAK,WAAW,QAAQ,EAAE;AAAA,UAClE;AAAA,QACF,IACA,CAAC;AAAA,MACP;AACA,YAAM,QAAQ,QAAQ,KAAK,KAAK;AAChC,cAAQ,EAAE;AACV,cAAQ,MAAM,MAAM;AACpB,YAAM,OAAO,SAAS,gBAAgB;AACtC,UAAI,SAAS,YAAY,eAAe,KAAK,UAAU,UAAU;AAE/D,cAAM,cAAc,QAAQ,MAAM,MAAM;AAAA,UAAQ,CAAC,SAC/C,KAAK,WAAW,WAAW,KAAK,eAAe,SAAY,CAAC,KAAK,UAAU,IAAI,CAAC;AAAA,QAClF;AACA,cAAM,QAAQ,OAAO,EAAE,aAAa,KAAK,CAAC;AAC1C;AAAA,MACF;AACA,YAAM;AAAA,QACJA,OAAM,SAAS,IAAI,EAAE,MAAM,OAAO,OAAAA,OAAM,IAAI,EAAE,MAAM,MAAM;AAAA,QAC1D,KAAK,SAAS,IAAI,EAAE,MAAM,EAAE,aAAa,KAAK,EAAE,IAAI;AAAA,MACtD;AAAA,IACF;AAAA,IACA,CAAC,aAAa,SAAS,cAAc;AAAA,EACvC;AACA,QAAM,WAAyB;AAAA,IAC7B;AAAA,IACA;AAAA,IACA;AAAA,IACA,SAAS,cAAc;AAAA,IACvB;AAAA,IACA;AAAA,EACF;AAGA,QAAM,aAAa,QAAQ,YAAY;AACvC,QAAM,QAAQ,eAAe;AAAA,IAC3B,SAAS;AAAA,IACT,GAAI,QAAQ,UAAU,SAAY,EAAE,OAAO,QAAQ,MAAM,IAAI,CAAC;AAAA,IAC9D,SAAS,eAAe,UAAa,OAAO,OAAO,cAAc;AAAA,EACnE,CAAC;AACD,QAAM,UAAU,OAAO,OAAO,oBAAoB;AAClD,QAAM,aAA6B,kBAAkB;AAAA,IACnD,UAAU,KAAK;AAAA,IACf;AAAA,IACA,QAAQ;AAAA,IACR,WAAW;AAAA,IACX,UAAU;AAAA,IACV,UAAU;AAAA,IACV,QAAQ;AAAA,IACR,eAAe;AAAA,IACf,cAAc;AAAA,IACd,GAAI,UACA,EAAE,QAAQ,CAAC,UAA8B,KAAK,KAAK,EAAE,KAAK,MAAM,MAAS,EAAE,IAC3E,CAAC;AAAA,IACL,GAAI,eAAe,SAAY,EAAE,aAAa,MAAM,QAAQ,IAAI,CAAC;AAAA,IACjE,OAAO,EAAE,OAAO,MAAM,OAAO,QAAQ,MAAM,QAAQ,QAAQ,aAAa;AAAA,IACxE,GAAG,QAAQ;AAAA,EACb,CAAC;AAED,QAAM,aAA6B;AAAA,IACjC,MAAM;AAAA,IACN;AAAA,IACA,SAAS;AAAA,EACX;AAEA,SAAO;AAAA,IACL,GAAG;AAAA,IACH;AAAA;AAAA,IAEA;AAAA,IACA;AAAA,IACA;AAAA;AAAA,IAEA;AAAA,IACA;AAAA,IACA;AAAA;AAAA,IAEA;AAAA;AAAA,IAEA;AAAA;AAAA,IAEA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,IAOA;AAAA;AAAA;AAAA;AAAA;AAAA,IAKA,aAAa;AAAA;AAAA,IAEb,SAAS;AAAA;AAAA,IAET;AAAA;AAAA,IAEA;AAAA;AAAA;AAAA;AAAA;AAAA,IAKA;AAAA;AAAA,IAEA;AAAA;AAAA;AAAA;AAAA;AAAA,IAKA;AAAA;AAAA,IAEA;AAAA;AAAA,IAEA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,EACF;AACF;AAGO,IAAM,oBAAN,cAAgC,MAAM;AAAA,EAC3C,YAAqB,OAAmB;AACtC,UAAM,MAAM,UAAU,OAAO,MAAM,WAAW,QAAQ,UAAU,SAAS,mBAAmB;AADzE;AAEnB,SAAK,OAAO;AAAA,EACd;AAAA,EAHqB;AAIvB;;;AGv/CO,IAAM,wBAAwB;AAAA,EACnC;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AACF;AAeO,IAAM,sBAAsB;AAO5B,SAAS,oBAAoB,OAA4C;AAC9E,SACE,iBAAiB,SAChB,MAAqC,WAAW,OAChD,MAAqC,SAAS;AAEnD;","names":["record","record","toolKind","fallback","useCallback","useEffect","useMemo","useRef","useState","useEffect","useState","useContext","useMemo","useRef","createContext","useContext","useMemo","useRef","shared","useEffect","useState","Component","useState","useEffect","createContext","fallback","TreeNode","useContext","useMemo","useRef","shared","fallback","useMemo","useContext","useContext","fallback","jsx","useRef","useMemo","useContext","useState","useEffect","useRef","useState","useCallback","backend","accept","maxBytes","maxFiles","useEffect","useMemo","isRecord","id","toolKind","fallback","useCallback","useMemo","useCallback","useEffect","useRef","useState","load","useCallback","useMemo","useMemo","useMemo","useEffect","useMemo","useEffect","useMemo","window","useCallback","useRef","useState","useRef","useState","useCallback","backend","useCallback","useEffect","useRef","useState","useState","useRef","useCallback","useEffect","useEffect","useState","useCallback","useEffect","useMemo","useRef","useState","jsx","useState","useEffect","React","useCallback","useEffect","useRef","useState","validateElicitationAnswer","getToolName","isSettled","fallback","isRecord","isSettled","isRecord","getToolName","input","validateElicitationAnswer","useCallback","useEffect","useRef","useState","useRef","useState","useEffect","useCallback","options","fallback","metadataOf","jsx","jsxs","React","jsx","jsxs","useCallback","useEffect","useMemo","useRef","useState","useRef","useState","useMemo","useEffect","useCallback","useCallback","useEffect","useMemo","useState","shared","load","useState","useEffect","useCallback","useMemo","useEffect","useRef","useState","toolKind","useCallback","useEffect","useMemo","useRef","useState","useCallback","useEffect","useRef","useState","useState","useRef","useEffect","useCallback","useRef","useState","useCallback","useMemo","regenerate","useEffect","queue","text","options","files"]}
|