@blade-hq/agent-client 2610.0.0-beta.76 → 2610.0.0-beta.78
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.js +7 -2
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/auth-login.ts","../src/rest.ts","../src/resources/auth.ts","../src/shared/type-guards.ts","../src/resources/headless.ts","../src/resources/computers.ts","../src/resources/models.ts","../src/schemas/session.ts","../src/session/definition.ts","../src/shared/projection/helpers.ts","../src/schemas/message.ts","../src/shared/projection/state.ts","../src/schemas/context.ts","../src/shared/projection/context.ts","../src/shared/projection/builder.ts","../src/shared/projection/history.ts","../src/resources/sessions.ts","../src/resources/plugins.ts","../src/resources/chat-groups.ts","../src/resources/site-visits.ts","../src/shared/auth-busy.ts","../src/commands/registry.ts","../src/session/events.ts","../src/session/history-page.ts","../src/session/queue.ts","../src/schemas/mcp-app.ts","../src/shared/tool-ui-card.ts","../src/schemas/message-utils.ts","../src/session/state.ts","../src/session/agent-session.ts","../src/session/hub.ts","../src/socket.ts","../src/auth.ts","../src/blade-client.ts","../src/polling-backoff.ts","../src/platform-endpoints.ts","../src/version.ts","../src/commands/protocol.ts","../src/commands/embedded.ts","../src/schemas/projection-utils.ts","../src/schemas/solution.ts","../src/schemas/task.ts"],"sourcesContent":["import type { BladeClient } from \"./blade-client\"\n\n/**\n * 弹窗授权登录,与 Chrome 扩展共用同一套后端授权内核(见 server/routes/sdk_auth.py):\n *\n * 1. 弹窗打开 `GET /api/auth/sdk/authorize?client_origin=<本页 origin>&state=<随机值>`\n * 2. 用户点击「许可授权」→ 回调页把 `{ type: \"blade-agent:sdk-auth\", state, code }`\n * postMessage 定向发回本页(code 一次性、5 分钟有效)\n * 3. SDK 用 `POST /api/auth/sdk/token`(code + state + client_origin)换取 PAT,\n * 存储并热挂载(REST 与 Socket.IO 同时生效)\n */\n\nexport interface LoginOptions {\n /** 弹窗尺寸,默认 480x640。 */\n width?: number\n height?: number\n /** 超时毫秒数,默认 5 分钟(与后端授权码有效期一致)。 */\n timeoutMs?: number\n}\n\nexport interface LoginResult {\n token: string\n user?: { id?: string; username?: string; display_name?: string }\n}\n\n/** 回调页 postMessage 的消息契约(对齐后端 _completion_page)。 */\ninterface AuthCallbackMessage {\n type: \"blade-agent:sdk-auth\"\n version: number\n status: \"success\" | \"denied\" | \"error\"\n state: string\n code?: string\n error?: string\n}\n\nfunction isAuthCallbackMessage(value: unknown): value is AuthCallbackMessage {\n return (\n typeof value === \"object\" &&\n value !== null &&\n (value as Record<string, unknown>).type === \"blade-agent:sdk-auth\"\n )\n}\n\n/** 后端下发的是错误码,直接抛给用户看不懂;这里翻成能照着做的话。 */\nconst AUTH_ERROR_HINTS: Record<string, string> = {\n pat_unavailable: \"没能为你准备访问凭据。请退出后重新登录 Blade 再试一次;若仍然失败,请联系管理员。\",\n}\n\nfunction randomState(): string {\n const bytes = new Uint8Array(24)\n crypto.getRandomValues(bytes)\n return Array.from(bytes, (b) => b.toString(16).padStart(2, \"0\")).join(\"\")\n}\n\nexport type TokenStorageMode = \"local\" | \"memory\"\n\nconst storageKeyFor = (baseUrl: string) => `blade-sdk-token:${baseUrl}`\n\nexport function readStoredToken(baseUrl: string): string | null {\n if (typeof localStorage === \"undefined\") return null\n try {\n return localStorage.getItem(storageKeyFor(baseUrl))\n } catch {\n return null\n }\n}\n\nexport function writeStoredToken(baseUrl: string, token: string | null, mode: TokenStorageMode): void {\n if (mode !== \"local\" || typeof localStorage === \"undefined\") return\n try {\n if (token) {\n localStorage.setItem(storageKeyFor(baseUrl), token)\n } else {\n localStorage.removeItem(storageKeyFor(baseUrl))\n }\n } catch {\n // 隐私模式等场景写入失败时静默降级为内存态\n }\n}\n\nexport async function loginWithPopup(\n client: BladeClient,\n options: LoginOptions = {},\n): Promise<LoginResult> {\n if (typeof window === \"undefined\") {\n throw new Error(\"client.auth.login() 只能在浏览器中调用;Node.js 场景请直接传入 token。\")\n }\n // file:// 打开的本地 HTML(智能体生成的交付物被双击打开)没有可声明的\n // origin,按 opaque(\"null\")走:授权页会向用户展示「本地文件页面」,\n // 回传的一次性 code 由 \"*\" 投递给本窗口,state 校验不变。\n const rawOrigin = window.location.origin\n const clientOrigin = /^https?:\\/\\//.test(rawOrigin) ? rawOrigin : \"null\"\n\n const width = options.width ?? 480\n const height = options.height ?? 640\n const left = Math.max(0, (window.screen.width - width) / 2)\n const top = Math.max(0, (window.screen.height - height) / 2)\n const state = randomState()\n const authorizeUrl = new URL(\n \"/api/auth/sdk/authorize\",\n client.options.baseUrl || window.location.origin,\n )\n authorizeUrl.searchParams.set(\"client_origin\", clientOrigin)\n authorizeUrl.searchParams.set(\"state\", state)\n\n const popup = window.open(\n \"about:blank\",\n `blade-sdk-login-${state}`,\n `popup=yes,width=${width},height=${height},left=${left},top=${top}`,\n )\n if (!popup) {\n throw new Error(\"登录弹窗被浏览器拦截了。请允许本站打开弹窗后重试。\")\n }\n\n const expectedOrigin = new URL(client.options.baseUrl || window.location.origin).origin\n\n return new Promise<LoginResult>((resolve, reject) => {\n const timeoutMs = options.timeoutMs ?? 5 * 60 * 1000\n let settled = false\n let closeTimer: ReturnType<typeof globalThis.setTimeout> | undefined\n\n // 收到合法回调之后弹窗是由回调页和 SDK 自己关掉的,不能再当成「用户放弃」,\n // 否则换取令牌的请求稍慢一点就会被误判成失败。\n const stopCloseWatch = () => {\n globalThis.clearInterval(closeWatcher)\n if (closeTimer !== undefined) globalThis.clearTimeout(closeTimer)\n }\n\n const cleanup = () => {\n window.removeEventListener(\"message\", onMessage)\n stopCloseWatch()\n globalThis.clearTimeout(timeoutHandle)\n }\n const settle = (fn: () => void) => {\n if (settled) return\n settled = true\n cleanup()\n fn()\n }\n\n const onMessage = (event: MessageEvent) => {\n // 回调页部署在后端域名下,只信任来自后端 origin、且 state 匹配的消息\n if (event.origin !== expectedOrigin) return\n if (event.source !== popup) return\n if (!isAuthCallbackMessage(event.data)) return\n if (event.data.state !== state) return\n const message = event.data\n stopCloseWatch()\n // 失败时不要关窗:授权页在那一屏上写了失败原因和下一步怎么做,关掉之后\n // 用户手里只剩一个错误码。成功和取消照旧关掉。\n const closePopup = () => {\n try {\n popup.close()\n } catch {\n // 跨域限制下 close 可能失败,忽略\n }\n }\n if (message.status === \"denied\") {\n closePopup()\n settle(() => reject(new Error(\"你取消了授权,未完成登录。\")))\n return\n }\n if (message.status !== \"success\" || !message.code) {\n settle(() => reject(new Error(AUTH_ERROR_HINTS[message.error ?? \"\"] ?? message.error ?? \"登录失败,未取得授权码。\")))\n return\n }\n closePopup()\n // code 一次性、5 分钟有效;连同 state 与 client_origin 一起换取 PAT\n client\n .json<{\n access_token: string\n user?: LoginResult[\"user\"]\n }>(\"POST\", \"/api/auth/sdk/token\", {\n code: message.code,\n state,\n client_origin: clientOrigin,\n })\n .then((response) => {\n settle(() => resolve({ token: response.access_token, user: response.user }))\n })\n .catch((error) => {\n settle(() =>\n reject(error instanceof Error ? error : new Error(\"授权码换取令牌失败,请重试。\")),\n )\n })\n }\n\n const closeWatcher = globalThis.setInterval(() => {\n if (!popup.closed || settled || closeTimer !== undefined) return\n // 回调消息可能仍在路上,稍等一拍再判定为用户关窗\n closeTimer = globalThis.setTimeout(() => {\n settle(() => reject(new Error(\"登录窗口已关闭,未完成授权。\")))\n }, 400)\n }, 500)\n\n const timeoutHandle = globalThis.setTimeout(() => {\n settle(() => reject(new Error(\"登录超时,请重试。\")))\n }, timeoutMs)\n\n window.addEventListener(\"message\", onMessage)\n // 先装监听器再导航,避免本地/沙盒自动授权过快返回时丢失回调消息。\n popup.location.replace(authorizeUrl.toString())\n })\n}\n","const DOCS_URL = \"https://blade-hq.github.io/public-skills/\"\n\nexport class BladeApiError extends Error {\n readonly response: Response\n readonly status: number\n readonly statusText: string\n\n constructor(response: Response, message?: string) {\n super(message ?? `请求失败(${response.status} ${response.statusText})`)\n this.name = \"BladeApiError\"\n this.response = response\n this.status = response.status\n this.statusText = response.statusText\n }\n}\n\n/**\n * 从 FastAPI 风格的错误响应中提取 detail 字段,作为用户可读的中文错误文案。\n * 失败时返回 undefined,调用方会回退到默认提示。\n */\nexport async function extractErrorDetail(response: Response): Promise<string | undefined> {\n try {\n const cloned = response.clone()\n const contentType = cloned.headers.get(\"content-type\") ?? \"\"\n if (contentType.includes(\"application/json\")) {\n const data = (await cloned.json()) as { detail?: unknown }\n const detail = data?.detail\n if (typeof detail === \"string\" && detail.trim()) return detail\n if (Array.isArray(detail) && detail.length > 0) {\n const first = detail[0] as { msg?: unknown }\n if (first && typeof first.msg === \"string\") return first.msg\n }\n } else {\n const text = (await cloned.text()).trim()\n if (text) return text\n }\n } catch {\n // 读取失败时忽略,使用默认提示\n }\n return undefined\n}\n\n/** 401/403 补充\"怎么办\"的指引,避免初级开发者对着裸状态码发呆。 */\nexport function decorateAuthError(error: unknown): unknown {\n if (!(error instanceof BladeApiError)) return error\n if (error.status === 401) {\n error.message =\n `${error.message}(未登录或凭证已失效。浏览器场景调用 client.auth.login() 弹窗登录,` +\n `自动化场景在 new BladeClient({ token }) 传入 PAT。接入指南:${DOCS_URL})`\n } else if (error.status === 403) {\n error.message = `${error.message}(当前账号无权访问该资源。接入指南:${DOCS_URL})`\n }\n return error\n}\n\nexport type HttpMethod = \"DELETE\" | \"GET\" | \"PATCH\" | \"POST\" | \"PUT\" | (string & {})\n\nexport interface BladeFetchInit {\n body?: BodyInit | null\n credentials?: RequestCredentials\n expectOk?: boolean\n headers?: HeadersInit\n signal?: AbortSignal | null\n}\n\n/**\n * 按客户端规则把后端路径拼成绝对 URL:`baseUrl` 自带路径前缀时保留前缀,\n * 路径里的前导 `/` 只表示\"从后端根开始\",不会被解释成站点根目录。\n *\n * 单独放在传输层,是为了让不走 `fetch()` 鉴权通道的资源(例如匿名的站点统计)\n * 落到同一个后端地址上,不必各自再写一份 URL 规则。\n */\nexport function buildBackendUrl(baseUrl: string, path: string): URL {\n const base = baseUrl.endsWith(\"/\") ? baseUrl : `${baseUrl}/`\n return new URL(path.startsWith(\"/\") ? path.slice(1) : path, base)\n}\n","import type { BladeClient } from \"../blade-client\"\nimport type { LoginOptions, LoginResult } from \"../auth-login\"\n\nexport interface UserInfo {\n id: string\n username: string\n display_name?: string | null\n avatar_url: string | null\n token: string\n auth_type: \"casdoor\"\n is_admin?: boolean\n}\n\nexport interface ProvidersResponse {\n providers: Array<{\n name: string\n authorize_url: string\n }>\n password_enabled: boolean\n}\n\nexport interface ExchangeCodeParams {\n /** 授权回调页 postMessage 回来的一次性 code。 */\n code: string\n /** 发起授权时用的 state,必须原样传回。 */\n state: string\n /** 发起授权的页面 origin,要和 authorize 时传的 `client_origin` 完全一致。 */\n clientOrigin: string\n}\n\nexport interface ExchangeCodeResult {\n access_token: string\n token_type: string\n user: {\n id: string\n username: string\n display_name: string\n avatar_url: string | null\n }\n}\n\nexport class AuthResource {\n constructor(private client: BladeClient) {}\n\n /**\n * 弹窗授权登录(浏览器专用):弹出后端授权页,用户点击\"许可授权\"后\n * 自动取得 PAT 并热挂载到当前 client。等价于 client.login()。\n */\n login(options?: LoginOptions): Promise<LoginResult> {\n return this.client.login(options)\n }\n\n /**\n * 用一次性 code 换 PAT。给**服务端**用:浏览器把 code 交给你自己的后端,\n * 后端换到的 PAT 不进浏览器。浏览器里直接用 `login()` 就够了。\n *\n * 服务端调用时会自己补上 `Origin` 头(浏览器会自动带,服务端不会,缺了\n * 后端报 `missing_request_origin`)。\n */\n exchangeCode(params: ExchangeCodeParams): Promise<ExchangeCodeResult> {\n return this.client.jsonFromInit(\"/api/auth/sdk/token\", {\n method: \"POST\",\n headers: { Origin: params.clientOrigin },\n body: JSON.stringify({\n code: params.code,\n state: params.state,\n client_origin: params.clientOrigin,\n }),\n })\n }\n\n /** 清除 login() 存储的令牌。 */\n logoutToken(): void {\n this.client.logoutToken()\n }\n\n getProviders(): Promise<ProvidersResponse> {\n return this.client.json(\"GET\", \"/api/auth/providers\")\n }\n\n getMe(): Promise<UserInfo> {\n return this.client.json(\"GET\", \"/api/auth/me\")\n }\n\n logout(): Promise<{ logout_url: string }> {\n return this.client.json(\"POST\", \"/api/auth/logout\")\n }\n}\n","/** Return true for non-null, non-array objects. */\nexport function isRecord(value: unknown): value is Record<string, unknown> {\n return typeof value === \"object\" && value !== null && !Array.isArray(value)\n}\n","import type { BladeClient } from \"../blade-client\"\nimport type { ChatEndPayload, ChatSendPayload, ChatStartPayload, SystemErrorPayload } from \"../types/socket-events\"\nimport { isRecord } from \"../shared/type-guards\"\n\nexport type JsonSchemaObject = Record<string, unknown>\n\nexport interface HeadlessRunOptions {\n schema?: JsonSchemaObject | null\n model?: string | null\n timeoutMs?: number\n}\n\nexport interface HeadlessRunInSessionResult<T = unknown> {\n session_id: string\n chat_run_id: string | null\n result: T | string\n}\n\nexport class HeadlessError extends Error {\n constructor(\n message: string,\n readonly detail?: unknown,\n ) {\n super(message)\n this.name = \"HeadlessError\"\n }\n}\n\nconst SYSTEM_ERROR_CHAT_END_GRACE_MS = 1_000\n\nexport class HeadlessResource {\n constructor(private client: BladeClient) {}\n\n async run<T = unknown>(prompt: string, options: HeadlessRunOptions & { schema: JsonSchemaObject }): Promise<T>\n async run(prompt: string, options?: HeadlessRunOptions): Promise<string>\n async run<T = unknown>(prompt: string, options: HeadlessRunOptions = {}): Promise<T | string> {\n const { session_id } = await this.client.sessions.createSessionWithRequest({\n intent: prompt,\n model: options.model ?? null,\n })\n return this.runTracked<T>(session_id, prompt, options, false) as Promise<T | string>\n }\n\n async runInSession<T = unknown>(\n sessionId: string,\n prompt: string,\n options: HeadlessRunOptions & { schema: JsonSchemaObject },\n ): Promise<T>\n async runInSession(sessionId: string, prompt: string, options?: HeadlessRunOptions): Promise<string>\n async runInSession<T = unknown>(\n sessionId: string,\n prompt: string,\n options: HeadlessRunOptions = {},\n ): Promise<T | string> {\n return this.runTracked<T>(sessionId, prompt, options, false) as Promise<T | string>\n }\n\n async runWithSession<T = unknown>(\n prompt: string,\n options: HeadlessRunOptions & { schema: JsonSchemaObject },\n ): Promise<HeadlessRunInSessionResult<T>>\n async runWithSession(prompt: string, options?: HeadlessRunOptions): Promise<HeadlessRunInSessionResult<string>>\n async runWithSession<T = unknown>(\n prompt: string,\n options: HeadlessRunOptions = {},\n ): Promise<HeadlessRunInSessionResult<T>> {\n const { session_id } = await this.client.sessions.createSessionWithRequest({\n intent: prompt,\n model: options.model ?? null,\n })\n return this.runTracked<T>(session_id, prompt, options, true) as Promise<HeadlessRunInSessionResult<T>>\n }\n\n private async runTracked<T = unknown>(\n sessionId: string,\n prompt: string,\n options: HeadlessRunOptions,\n returnEnvelope: boolean,\n ): Promise<T | string | HeadlessRunInSessionResult<T>> {\n const timeoutMs = options.timeoutMs ?? 300_000\n const session_id = sessionId\n const socket = this.client.socket()\n await ensureSocketConnected(socket, timeoutMs, { session_id })\n\n return new Promise<T | string | HeadlessRunInSessionResult<T>>((resolve, reject) => {\n let settled = false\n let stopSent = false\n let started = false\n let chatRunId: string | null = null\n let systemErrorTimeout: ReturnType<typeof setTimeout> | null = null\n const timeout = setTimeout(() => {\n fail(new HeadlessError(`headless run timed out after ${timeoutMs}ms`, { session_id, chat_run_id: chatRunId }))\n }, timeoutMs)\n\n const cleanup = (sendStop: boolean) => {\n clearTimeout(timeout)\n if (systemErrorTimeout) {\n clearTimeout(systemErrorTimeout)\n systemErrorTimeout = null\n }\n socket.off(\"chat:start\", onChatStart)\n socket.off(\"chat:end\", onChatEnd)\n socket.off(\"system:error\", onSystemError)\n if (sendStop && !stopSent) {\n stopSent = true\n socket.emit(\"chat:stop\", { session_id }, () => undefined)\n }\n socket.emit(\"session:unsubscribe\", { session_id })\n }\n\n const finish = (value: T | string) => {\n if (settled) return\n settled = true\n cleanup(false)\n if (returnEnvelope) {\n resolve({ session_id, chat_run_id: chatRunId, result: value })\n return\n }\n resolve(value)\n }\n const fail = (error: unknown) => {\n if (settled) return\n settled = true\n cleanup(true)\n reject(error)\n }\n const failWithoutStop = (error: unknown) => {\n if (settled) return\n settled = true\n cleanup(false)\n reject(error)\n }\n const rejectAfterChatEnd = (error: unknown) => {\n if (settled) return\n settled = true\n cleanup(false)\n reject(error)\n }\n\n function onChatStart(payload: ChatStartPayload) {\n if (payload.session_id && payload.session_id !== session_id) return\n started = true\n }\n\n function onSystemError(payload: SystemErrorPayload) {\n if (payload.session_id !== session_id) return\n if (!started) {\n failWithoutStop(new HeadlessError(payload.message || \"headless run failed\", {\n session_id,\n chat_run_id: chatRunId,\n event: payload,\n }))\n return\n }\n if (systemErrorTimeout) {\n clearTimeout(systemErrorTimeout)\n }\n systemErrorTimeout = setTimeout(() => {\n systemErrorTimeout = null\n fail(new HeadlessError(payload.message || \"headless run failed\", {\n session_id,\n chat_run_id: chatRunId,\n event: payload,\n }))\n }, SYSTEM_ERROR_CHAT_END_GRACE_MS)\n }\n\n function onChatEnd(payload: ChatEndPayload) {\n if (payload.session_id && payload.session_id !== session_id) return\n chatRunId = typeof payload.chat_run_id === \"string\" ? payload.chat_run_id : chatRunId\n const result = payload.result\n if (payload.status === \"failed\") {\n rejectAfterChatEnd(new HeadlessError(errorMessageFromResult(result) ?? \"headless run failed\", {\n session_id,\n chat_run_id: chatRunId,\n event: payload,\n }))\n return\n }\n try {\n finish(normalizeResult<T>(result, Boolean(options.schema)))\n } catch (error) {\n rejectAfterChatEnd(error)\n }\n }\n\n socket.on(\"chat:start\", onChatStart)\n socket.on(\"chat:end\", onChatEnd)\n socket.on(\"system:error\", onSystemError)\n socket.emit(\"session:subscribe\", {\n session_id,\n event_format: \"raw\",\n })\n socket.emit(\n \"chat:send\",\n {\n session_id,\n message: prompt as unknown as ChatSendPayload[\"message\"],\n headless: true,\n output_schema: options.schema ?? null,\n model: options.model ?? null,\n },\n (response) => {\n if (response.status === \"accepted\") return\n rejectAfterChatEnd(\n new HeadlessError(response.message ?? \"headless run was not accepted\", response),\n )\n },\n )\n })\n }\n}\n\nfunction normalizeResult<T>(result: unknown, hasSchema: boolean): T | string {\n if (!isRecord(result)) {\n throw new HeadlessError(\"headless run finished without a result\", result)\n }\n const errMsg = typeof result.err_msg === \"string\" ? result.err_msg : \"\"\n if (errMsg) {\n throw new HeadlessError(errMsg, result)\n }\n if (!hasSchema) {\n const text = result.result\n return typeof text === \"string\" ? text : String(text ?? \"\")\n }\n const { err_msg: _errMsg, ...businessResult } = result\n return businessResult as T\n}\n\nfunction errorMessageFromResult(result: unknown): string | null {\n if (isRecord(result) && typeof result.err_msg === \"string\" && result.err_msg) {\n return result.err_msg\n }\n return null\n}\n\nfunction ensureSocketConnected(\n socket: ReturnType<BladeClient[\"socket\"]>,\n timeoutMs: number,\n detail: Record<string, unknown>,\n): Promise<void> {\n if (socket.connected) {\n return Promise.resolve()\n }\n return new Promise((resolve, reject) => {\n let settled = false\n const timeout = setTimeout(() => {\n finish(() => reject(new HeadlessError(`socket connection timed out after ${timeoutMs}ms`, detail)))\n }, timeoutMs)\n const onConnect = () => finish(resolve)\n const onConnectError = (error: unknown) => {\n finish(() => reject(new HeadlessError(\"socket connection failed\", { ...detail, event: error })))\n }\n const finish = (callback: () => void) => {\n if (settled) return\n settled = true\n clearTimeout(timeout)\n socket.off(\"connect\", onConnect)\n socket.off(\"connect_error\", onConnectError)\n callback()\n }\n socket.on(\"connect\", onConnect)\n socket.on(\"connect_error\", onConnectError)\n socket.connect()\n })\n}\n","import type { BladeClient } from \"../blade-client\"\n\n/** 一台远程电脑在某个会话眼里的样子。 */\nexport interface SessionComputer {\n id: string\n label: string\n hostname?: string | null\n os?: string | null\n arch?: string | null\n /** 那台机器的用户主目录,命令默认在这里执行。 */\n home?: string | null\n /** daemon 启动时所在的目录。 */\n workspace?: string | null\n blade_home?: string | null\n allowed_paths?: string[]\n agent_runtimes?: unknown[]\n daemon_version?: string | null\n created_at: string\n last_seen_at?: string | null\n /** 这台电脑此刻连着后端。由服务端读心跳时间判定,不做实时探测。 */\n online: boolean\n /** 这次会话已经启动了它。和 `online` 互相独立。 */\n enabled: boolean\n /** 这次会话本身就跑在这台电脑上。 */\n is_primary: boolean\n}\n\nexport interface SessionComputerList {\n computers: SessionComputer[]\n}\n\n/**\n * 账号级电脑目录里的一台机器。\n *\n * 只有「这台机器登记过、此刻在不在线」这类账号事实,**没有**会话授权状态——\n * 「本次会话能不能用它」是另一件事,由会话接口回答。两者混在一起说,用户就会\n * 把「在线」当成「已授权」,或者反过来。\n */\nexport interface AccountComputer {\n id: string\n label: string\n hostname?: string | null\n os?: string | null\n arch?: string | null\n blade_home?: string | null\n workspace?: string | null\n daemon_version?: string | null\n created_at: string\n last_seen_at?: string | null\n online: boolean\n}\n\nexport interface AccountComputerList {\n computers: AccountComputer[]\n}\n\n/**\n * 一台电脑在界面上该显示成什么状态。\n *\n * - `primary` 会话自己就住在这台机器上,恒为可用且不能停用\n * - `enabled` 本次会话已启动\n * - `offline` 没启动且当前离线\n * - `idle` 没启动,在线\n *\n * 判定只写这一份,界面只管样式和排版——两边各写一份必然会分叉,\n * 然后其中一边的兜底会把另一边的错误盖住。\n */\nexport type ComputerState = \"primary\" | \"enabled\" | \"offline\" | \"idle\"\n\nexport function computerState(computer: SessionComputer): ComputerState {\n if (computer.is_primary) return \"primary\"\n if (computer.enabled) return \"enabled\"\n return computer.online ? \"idle\" : \"offline\"\n}\n\n/**\n * 这台电脑跑的是哪一类系统。\n *\n * 判定放这里、图标映射留给界面:`os` 是 daemon 上报的 `runtime.GOOS`,\n * 各处自己 `startsWith` 一遍必然会分叉。\n */\nexport type ComputerOS = \"macos\" | \"windows\" | \"linux\" | \"unknown\"\n\nexport function computerOS(computer: SessionComputer): ComputerOS {\n const os = (computer.os ?? \"\").toLowerCase()\n if (os.startsWith(\"darwin\") || os.startsWith(\"mac\")) return \"macos\"\n if (os.startsWith(\"windows\")) return \"windows\"\n if (os.startsWith(\"linux\")) return \"linux\"\n return \"unknown\"\n}\n\n/** 系统与架构,例如 `darwin/arm64`。信息不全时尽量给出已知的那部分。 */\nexport function computerPlatformLabel(computer: SessionComputer): string {\n const os = (computer.os ?? \"\").trim()\n const arch = (computer.arch ?? \"\").trim()\n if (os && arch) return `${os}/${arch}`\n return os || arch || \"\"\n}\n\n/**\n * 那台电脑上 blade daemon 的版本。\n *\n * 服务端存的就是 daemon 上报的完整串(dev 构建带 commit),这里原样用,\n * 不在前端另拼一套格式——拼两份迟早对不上。\n */\nexport function computerDaemonVersion(computer: SessionComputer): string {\n return (computer.daemon_version ?? \"\").trim()\n}\n\n/** 这台电脑的勾选框能不能动。主运行时不能停用——那是会话自己的工作目录所在。 */\nexport function canToggleComputer(computer: SessionComputer): boolean {\n return !computer.is_primary\n}\n\n/**\n * 列表顺序:按接入时间,稳定不变。\n *\n * **刻意不按在线/可用排序。** 那样排看着\"手边的在前面\",代价是电脑上下线、\n * 勾选状态一变,整个列表就重排——用户正要点的那一项会在手指底下跑掉。\n * 一个会自己动的列表比一个排序不那么聪明的列表难用得多。\n *\n * 用 `created_at` 而不是名字:改名不会让位置变,新接入的稳定排在末尾。\n */\nexport function sortComputers(computers: SessionComputer[]): SessionComputer[] {\n return [...computers].sort((a, b) => {\n const byCreated = (a.created_at ?? \"\").localeCompare(b.created_at ?? \"\")\n if (byCreated !== 0) return byCreated\n // created_at 相同时才用名字兜底,保证顺序确定\n return a.label.localeCompare(b.label)\n })\n}\n\n/** 会话可以操作哪些远程电脑。 */\nexport class ComputersResource {\n constructor(private client: BladeClient) {}\n\n /**\n * 列出当前账号登记过的全部电脑及其在线状态。\n *\n * 首页还没有会话,也要能看到同一份清单——判定各写一份必然分叉,一边的兜底会把\n * 另一边的错误盖住(#1597)。所以账号事实只从这一个接口读。\n */\n async listAccount(): Promise<AccountComputerList> {\n const data = await this.client.json<{\n instances: Array<Omit<AccountComputer, \"online\"> & { online?: boolean }>\n }>(\"GET\", \"/api/daemon/instances\")\n return {\n computers: (data.instances ?? []).map((instance) => ({\n ...instance,\n online: Boolean(instance.online),\n })),\n }\n }\n\n /**\n * 列出当前用户的全部电脑,带上\"在不在线\"和\"这次会话能不能用\"。\n * 服务端只查库,电脑离线时同样返回,所以拿得到\"它离线了\"这个结论。\n */\n list(sessionId: string): Promise<SessionComputerList> {\n return this.client.json(\n \"GET\",\n `/api/sessions/${encodeURIComponent(sessionId)}/computers`,\n )\n }\n\n /**\n * 启动或停止一台电脑。只改这次会话的可用范围,不会碰远程机器,\n * 电脑离线时同样能登记,等它上线就直接可用。\n */\n setEnabled(\n sessionId: string,\n computer: string,\n enabled: boolean,\n ): Promise<SessionComputer> {\n return this.client.json(\n \"PUT\",\n `/api/sessions/${encodeURIComponent(sessionId)}/computers/${encodeURIComponent(computer)}/enabled`,\n { enabled },\n )\n }\n}\n","import type { BladeClient } from \"../blade-client\"\n\nexport interface ModelOption {\n id: string\n label: string\n /**\n * 把这个模型发给 `baseUrl` 时该用的名字。`id` 是平台内部标识,接了多个模型服务时\n * 形如 `provider-xxx::name`,直接发过去会被拒。不在 `baseUrl` 那个服务上的模型\n * 这里是空串——自己做模型选择器时据此过滤。\n */\n serviceModelId?: string\n}\n\nexport interface ModelCatalog {\n default: string\n models: ModelOption[]\n unavailableProviderIds?: string[]\n unavailableModelIds?: string[]\n /**\n * 平台默认模型服务的 OpenAI 兼容地址(Server ≥ 提供 `baseUrl` 的版本才有,否则为空)。\n * 自建应用可以带用户的 PAT 直接调它,不必让用户自己填地址——网关端口各部署不同,\n * 推算不出来。\n *\n * 这是**服务端视角**的地址:平台可能配的是 `http://127.0.0.1:30000/v1`,从自己后端\n * 转发没问题,直接丢给浏览器就指向用户自己的机器了。默认形态是后端透传(密钥也不该\n * 进浏览器),浏览器直连只适合这个地址对浏览器同样可达的场景。\n */\n baseUrl?: string\n /**\n * 直接调 `baseUrl` 时该用的默认模型名。**不要用 `default`**——那是平台内部标识,\n * 平台默认模型来自额外接的模型服务时它带 `provider-xxx::` 前缀,发过去只会得到\n * 「模型不存在」。没有可直调的模型时为空串。\n */\n defaultServiceModel?: string\n}\n\n/** Server 可供当前用户选择的模型目录。 */\nexport class ModelsResource {\n constructor(private client: BladeClient) {}\n\n list(): Promise<ModelCatalog> {\n return this.client.json(\"GET\", \"/api/config/models\")\n }\n}\n","import { type } from \"arktype\"\nimport type { Solution } from \"./solution\"\n\nexport const SessionStatus = type(\n \"'created' | 'running' | 'completed' | 'failed' | 'interrupted' | 'waiting_for_input'\",\n)\nexport type SessionStatus = typeof SessionStatus.infer\n\nexport type TemplateId =\n | \"default\"\n | \"skill_editor\"\n // ship-attack v2:用户从 ship-attack 页面点\"新建 session\"创建的会话。\n // 后端 _maybe_bind_first_skill 只对此模板触发首次绑定。\n | \"ship_attack\"\n\nexport type SkillEditorTemplateId = \"skill_editor\"\n\nexport type ModeId = \"planning\" | \"executing\"\n\nexport type PublishedSolutionRef =\n | { source: \"builtin\"; name: string }\n | { source: \"hub\"; org: string; name: string }\n\n/** 回放时录制内容的播放倍速。 */\nexport type ReplaySpeed = 1 | 2 | 5\n\n/**\n * 新建回放会话时的默认倍速。\n *\n * 所有创建入口都用它——曾经侧栏走 API 默认 5x、设置菜单初始化成 1x,\n * 同一个源对话从不同入口开出来速度不一样。\n */\nexport const DEFAULT_REPLAY_SPEED: ReplaySpeed = 5\n\nexport interface ReplayState {\n source_session_id?: string\n status?: \"replay\" | \"autonomous\"\n speed?: ReplaySpeed\n next_source_entry_id?: string | null\n ended_at?: string | null\n autonomous_reason?: string | null\n}\n\n/** 某个会话能否作为回放来源。 */\nexport interface ReplayPreview {\n session_id: string\n intent?: string | null\n supported: boolean\n /** supported 为 false 时给出的原因,可直接展示给用户。 */\n reason?: string | null\n}\n\nexport interface SessionPortMapping {\n container_port: number\n host_port: number\n}\n\n/**\n * 列表搜索时单条会话的命中信息。\n * - field='title':关键词出现在 intent 里,snippet 为 null(标题本身就在 UI 上)\n * - field='content':关键词出现在历史消息里,snippet 含截窗预览与角色\n */\nexport interface SessionSearchMatch {\n field: \"title\" | \"content\"\n snippet: { role: string; text: string } | null\n}\n\nexport const SessionInfo = type({\n id: \"string\",\n intent: \"string\",\n status: SessionStatus,\n created_at: \"string\",\n updated_at: \"string\",\n \"shared?\": \"boolean\",\n \"memory_enabled?\": \"boolean\",\n \"is_persistent?\": \"boolean\",\n \"is_headless?\": \"boolean\",\n \"viewer_role?\": \"'owner' | 'viewer'\",\n \"template_id?\": \"string | null\",\n \"model?\": \"string | null\",\n \"enable_thinking?\": \"boolean | null\",\n \"solution_id?\": \"string | null\",\n \"solution_ref?\": \"unknown\",\n \"biz_role_id?\": \"string | null\",\n \"solution?\": \"unknown\",\n \"plan_summary?\": \"string | null\",\n \"primary_skill_id?\": \"string | null\",\n // ship-attack v2:后端 engine.set_bound_skill 写入的\"绑定 skill id\"。\n // 未绑定 / 非 ship-attack session 为 null。\n \"bound_skill_id?\": \"string | null\",\n \"replay_state?\": \"unknown\",\n \"is_pinned?\": \"boolean\",\n \"pinned_at?\": \"string | null\",\n \"is_example?\": \"boolean\",\n \"ports?\": \"unknown\",\n \"disable_tools?\": \"string[]\",\n \"runtime_type?\": \"string | null\",\n \"daemon_id?\": \"string | null\",\n \"agent_runtime_id?\": \"string | null\",\n \"workspace_path?\": \"string | null\",\n \"ba_version?\": \"string | null\",\n \"sandbox_version?\": \"string | null\",\n \"chat_group_id?\": \"string | null\",\n \"match?\": \"unknown\",\n})\nexport type SessionInfo = Omit<\n typeof SessionInfo.infer,\n \"template_id\" | \"solution\" | \"ports\" | \"match\"\n> & {\n shared?: boolean\n memory_enabled?: boolean\n is_persistent?: boolean\n is_headless?: boolean\n viewer_role?: \"owner\" | \"viewer\"\n template_id?: TemplateId | null\n model?: string | null\n enable_thinking?: boolean | null\n solution_id?: string | null\n solution_ref?: PublishedSolutionRef | null\n biz_role_id?: string | null\n solution?: Solution | null\n primary_skill_id?: string | null\n bound_skill_id?: string | null\n replay_state?: ReplayState | null\n is_pinned?: boolean\n pinned_at?: string | null\n is_example?: boolean\n ports?: SessionPortMapping[]\n disable_tools?: string[]\n runtime_type?: \"sandbox\" | \"daemon\" | \"native\" | string | null\n daemon_id?: string | null\n agent_runtime_id?: string | null\n workspace_path?: string | null\n ba_version?: string | null\n sandbox_version?: string | null\n chat_group_id?: string | null\n /** 仅在带 q 搜索的列表响应中出现;普通列表里此字段缺省。 */\n match?: SessionSearchMatch | null\n}\n\n/**\n * 主 skill 配置快照(v2)。创建 session 时从 SKILL.md frontmatter 抽出并\n * 固化到 session_root/.blade/primary-skill.json;ship-attack 页面骨架的唯\n * 一数据源。\n */\nexport interface PrimarySkillStepSpec {\n n: number\n label: string\n}\n\nexport interface PrimarySkillStageSpec {\n id: string\n name: string\n steps: PrimarySkillStepSpec[]\n}\n\nexport interface PrimarySkillParallelMode {\n id: string\n name: string\n prompt_hint: string\n}\n\nexport interface PrimarySkillSnapshot {\n version: number\n skill_id: string\n title: string\n description: string\n stages: PrimarySkillStageSpec[]\n parallel_modes: PrimarySkillParallelMode[]\n captured_at: string\n}\n\n/**\n * 单 session detail(GET /api/sessions/:id)。列表接口返回 SessionInfo,\n * detail 在此基础上附加 primary_skill_snapshot。\n */\nexport interface SessionDetail extends SessionInfo {\n primary_skill_snapshot?: PrimarySkillSnapshot | null\n preview_url?: string | null\n /**\n * 会话级环境变量(owner-only)。后端仅在 GET detail 和 PUT /env 响应中返回,\n * 列表/搜索响应不带此字段。调用 setSessionEnv 后可类型安全地读回。\n */\n env?: Record<string, string>\n}\n","export type TextFile = {\n path: string\n content: string\n}\n\nexport type SolutionDefinition =\n | { id: string; role?: string }\n /** 自定义 Solution:文本文件路径均相对于 Solution 根目录。 */\n | { files: TextFile[]; role?: string }\n\nexport interface SkillDefinition {\n /** 会话内安装名,格式为 `组织/名称`。 */\n name: string\n /** 必须包含根目录的 SKILL.md。 */\n files: TextFile[]\n}\n\nexport interface SessionConfig {\n /** Server 模型目录中的 model ID。 */\n model?: string\n enableThinking?: boolean\n memoryEnabled?: boolean\n compactionRatio?: number\n env?: Record<string, string>\n disableTools?: string[]\n}\n\n/**\n * 声明一个待创建的会话。传给 `client.sessions.create(...)` 后,SDK 会先准备\n * Solution,再创建会话并安装 Skill;Promise resolve 时会话已经可以使用。\n */\nexport interface SessionDefinition {\n intent?: string\n solution?: SolutionDefinition\n skills?: SkillDefinition[]\n config?: SessionConfig\n}\n\nexport type SessionSetupStage = \"solution\" | \"session\" | \"skill\" | \"connection\"\n\n/** 声明式会话准备失败;stage 和 sessionId 可直接用于界面提示或日志。 */\nexport class SessionSetupError extends Error {\n readonly name = \"SessionSetupError\"\n readonly cause?: unknown\n\n constructor(\n message: string,\n readonly stage: SessionSetupStage,\n readonly sessionId?: string,\n options?: { cause?: unknown },\n ) {\n super(message)\n this.cause = options?.cause\n }\n}\n","import type {\n ContentBlock,\n PendingQuestionRef,\n ToolCallProjection,\n TurnProjection,\n} from \"../../schemas/projection\"\nimport type { TurnState } from \"./state\"\n\n// --- Tool call upsert ---\n\nexport function upsertToolCall(\n state: TurnState,\n toolCallId: string,\n toolName: string,\n displayName: string,\n args: string,\n): void {\n if (!toolCallId) return\n\n let found = false\n for (let i = 0; i < state.toolCalls.length; i++) {\n if (state.toolCalls[i].id !== toolCallId) continue\n const tc = state.toolCalls[i]\n state.toolCalls[i] = {\n ...tc,\n tool_name: toolName || tc.tool_name,\n display_name: displayName || tc.display_name,\n arguments: args || tc.arguments,\n }\n found = true\n break\n }\n if (!found) {\n state.toolCalls.push({\n id: toolCallId,\n tool_name: toolName,\n display_name: displayName,\n arguments: args,\n status: \"pending\",\n })\n }\n\n let blockFound = false\n for (let i = 0; i < state.blocks.length; i++) {\n const b = state.blocks[i]\n if (b.type !== \"tool_use\" || b.tool_call_id !== toolCallId) continue\n state.blocks[i] = {\n ...b,\n content: args || b.content,\n tool_name: toolName || b.tool_name,\n display_name: displayName || b.display_name,\n }\n blockFound = true\n break\n }\n if (!blockFound) {\n state.blocks.push({\n type: \"tool_use\",\n content: args,\n tool_call_id: toolCallId,\n tool_name: toolName || null,\n display_name: displayName || null,\n })\n }\n}\n\n// --- Tool result application ---\n\nexport function applyToolResult(\n state: TurnState,\n toolCallId: string,\n result: unknown,\n status: ToolCallProjection[\"status\"],\n durationMs: number | null,\n ranInParallel: boolean | null,\n sourceLoop: { loop_name: string; description: string } | null,\n startedAt: string | null = null,\n): void {\n let toolName = \"\"\n let displayName = \"\"\n let finalResult = result\n\n for (let i = 0; i < state.toolCalls.length; i++) {\n const tc = state.toolCalls[i]\n if (tc.id !== toolCallId) continue\n\n if (typeof result === \"string\") {\n finalResult = maybeEnrichAskUserResult(tc.tool_name, result, sourceLoop)\n }\n\n const update: Partial<ToolCallProjection> = { status, result: finalResult }\n if (durationMs != null) update.duration_ms = durationMs\n if (ranInParallel != null) update.ran_in_parallel = ranInParallel\n if (startedAt != null) update.started_at = startedAt\n state.toolCalls[i] = { ...tc, ...update }\n toolName = tc.tool_name\n displayName = tc.display_name\n break\n }\n\n upsertToolResultBlock(state, toolCallId, finalResult, toolName, displayName)\n}\n\nexport function appendToolResultDelta(\n state: TurnState,\n toolCallId: string,\n delta: string,\n reset = false,\n): void {\n if (!toolCallId || !delta) return\n\n let toolName = \"\"\n let displayName = \"\"\n let currentResult = \"\"\n\n for (let i = 0; i < state.toolCalls.length; i++) {\n const tc = state.toolCalls[i]\n if (tc.id !== toolCallId) continue\n toolName = tc.tool_name\n displayName = tc.display_name\n if (!reset && typeof tc.result === \"string\") currentResult = tc.result\n state.toolCalls[i] = { ...tc, result: currentResult + delta }\n break\n }\n\n for (const block of state.blocks) {\n if (block.type !== \"tool_result\" || block.tool_call_id !== toolCallId) continue\n if (!reset && typeof block.content === \"string\") currentResult = block.content\n break\n }\n\n upsertToolResultBlock(state, toolCallId, currentResult + delta, toolName, displayName)\n}\n\nfunction upsertToolResultBlock(\n state: TurnState,\n toolCallId: string,\n content: unknown,\n toolName: string,\n displayName: string,\n): void {\n for (let i = 0; i < state.blocks.length; i++) {\n const block = state.blocks[i]\n if (block.type !== \"tool_result\" || block.tool_call_id !== toolCallId) continue\n state.blocks[i] = {\n ...block,\n content,\n tool_name: toolName || block.tool_name,\n display_name: displayName || block.display_name,\n }\n return\n }\n\n state.blocks.push({\n type: \"tool_result\",\n content,\n tool_call_id: toolCallId,\n tool_name: toolName || null,\n display_name: displayName || null,\n })\n}\n\n// --- Text block append ---\n\nexport function appendTextBlock(\n state: TurnState,\n blockType: ContentBlock[\"type\"],\n content: unknown,\n): void {\n if (content == null || content === \"\") return\n const text = String(content)\n const lastBlock = state.blocks[state.blocks.length - 1]\n if (lastBlock && lastBlock.type === blockType && typeof lastBlock.content === \"string\") {\n state.blocks[state.blocks.length - 1] = {\n ...lastBlock,\n content: lastBlock.content + text,\n }\n return\n }\n state.blocks.push({ type: blockType, content: text })\n}\n\n// --- Tool call arguments append ---\n\nexport function appendToolCallArguments(\n state: TurnState,\n toolCallId: string,\n delta: string,\n): void {\n let newArgs = \"\"\n for (let i = 0; i < state.toolCalls.length; i++) {\n const tc = state.toolCalls[i]\n if (tc.id === toolCallId) {\n newArgs = tc.arguments + delta\n state.toolCalls[i] = { ...tc, arguments: newArgs }\n break\n }\n }\n if (!newArgs) return\n\n for (let i = 0; i < state.blocks.length; i++) {\n const b = state.blocks[i]\n if (b.type === \"tool_use\" && b.tool_call_id === toolCallId) {\n state.blocks[i] = { ...b, content: newArgs }\n break\n }\n }\n}\n\n// --- AskUserQuestion enrichment ---\n\nfunction maybeEnrichAskUserResult(\n toolName: string,\n result: string,\n sourceLoop: { loop_name: string; description: string } | null,\n): string {\n if (!sourceLoop) return result\n const normalized = toolName.includes(\":\") ? toolName.split(\":\").pop()! : toolName\n if (normalized !== \"AskUserQuestion\") return result\n try {\n const payload = JSON.parse(result)\n if (typeof payload !== \"object\" || payload === null) return result\n payload.source_loop = sourceLoop\n return JSON.stringify(payload)\n } catch {\n return result\n }\n}\n\n// --- System notification ---\n\nexport function buildSystemNotificationTurn(\n sequence: number,\n turnId: string,\n loopId: string,\n notificationType: string,\n status: string,\n title: string,\n detail: string | null,\n metadata: Record<string, unknown>,\n): TurnProjection {\n return {\n id: turnId,\n sequence,\n turn_id: turnId,\n loop_id: loopId,\n kind: \"message\",\n role: \"system\",\n status: \"completed\",\n blocks: [\n {\n type: \"system_notification\",\n content: {\n notification_type: notificationType,\n status,\n title,\n detail,\n metadata,\n },\n },\n ],\n tool_calls: [],\n model: null,\n usage: null,\n duration_ms: 0,\n }\n}\n\nexport function buildSystemNotificationBlock(\n notificationType: string,\n status: string,\n title: string,\n detail: string | null,\n metadata: Record<string, unknown>,\n): ContentBlock {\n return {\n type: \"system_notification\",\n content: {\n notification_type: notificationType,\n status,\n title,\n detail,\n metadata,\n },\n }\n}\n\n// --- Marker turn ---\n\nexport function buildMarkerTurn(\n sequence: number,\n turnId: string,\n loopId: string,\n blockType: ContentBlock[\"type\"],\n content: unknown,\n): TurnProjection {\n return {\n id: turnId,\n sequence,\n turn_id: turnId,\n loop_id: loopId,\n kind: \"message\",\n role: \"assistant\",\n status: \"completed\",\n blocks: [{ type: blockType, content }],\n tool_calls: [],\n model: null,\n usage: null,\n duration_ms: 0,\n }\n}\n\n// --- Compaction turn ---\n\nexport function buildCompactionTurn(\n sequence: number,\n compactionId: string,\n loopId: string,\n status: TurnProjection[\"status\"],\n data: Record<string, unknown>,\n): TurnProjection {\n const tokensBefore = asInt(data.tokens_before)\n const tokensAfter = asInt(data.tokens_after)\n let savedRatio: number | null = null\n if (tokensBefore && tokensBefore > 0 && tokensAfter != null) {\n savedRatio = 1 - tokensAfter / tokensBefore\n } else {\n savedRatio = asFloat(data.saved_ratio)\n }\n let archivedCount = asInt(data.archived_count)\n if (archivedCount == null && Array.isArray(data.archived_files)) {\n archivedCount = data.archived_files.length\n }\n\n const content = data.content\n const summaryFull = compactionSummaryFull(content)\n const summaryPreview = summaryFull\n ? summaryFull\n .split(\"\\n\")\n .map((l) => l.trim())\n .filter(Boolean)\n .join(\" \")\n .slice(0, 200)\n : null\n\n return {\n id: `compaction:${compactionId}`,\n sequence,\n turn_id: `compaction:${compactionId}`,\n loop_id: loopId,\n kind: \"compaction\",\n role: \"system\",\n status,\n blocks: [],\n tool_calls: [],\n model: null,\n usage: null,\n duration_ms: 0,\n compaction_id: compactionId,\n summary_preview: summaryPreview,\n summary_full: summaryFull,\n archived_count: archivedCount,\n archived_files: Array.isArray(data.archived_files)\n ? data.archived_files.filter(\n (item): item is Record<string, unknown> =>\n typeof item === \"object\" && item !== null && !Array.isArray(item),\n )\n : null,\n archived_tool_calls: Array.isArray(data.archived_tool_calls)\n ? data.archived_tool_calls.filter(\n (item): item is Record<string, unknown> =>\n typeof item === \"object\" && item !== null && !Array.isArray(item),\n )\n : null,\n tokens_before: tokensBefore,\n tokens_after: tokensAfter,\n saved_ratio: savedRatio,\n trigger: asTrigger(data.trigger),\n failure_reason: [data.failure_reason, data.fallback_reason, data.reason]\n .find((value): value is string => typeof value === \"string\" && value.length > 0) ?? null,\n fallback_applied: typeof data.fallback_applied === \"boolean\" ? data.fallback_applied : null,\n }\n}\n\nfunction compactionSummaryFull(content: unknown): string | null {\n const text = String(content ?? \"\")\n if (!text) return null\n const cleaned = text\n .replace(\"<compaction-summary>\", \"\")\n .replace(\"</compaction-summary>\", \"\")\n .replace(/\\r\\n/g, \"\\n\")\n .replace(/\\r/g, \"\\n\")\n .trim()\n return cleaned || null\n}\n\nfunction asInt(value: unknown): number | null {\n if (typeof value === \"boolean\") return null\n if (typeof value === \"number\") return Math.trunc(value)\n return null\n}\n\nfunction asFloat(value: unknown): number | null {\n if (typeof value === \"boolean\") return null\n if (typeof value === \"number\") return value\n return null\n}\n\nfunction asTrigger(value: unknown): \"auto\" | \"manual\" | \"forced_retry\" | null {\n if (value === \"auto\" || value === \"manual\" || value === \"forced_retry\") return value\n return null\n}\n\n// --- Child pause helpers ---\n\nexport interface ChildPauseInfo {\n parentLoopName: string\n parentToolCallId: string\n childLoopName: string\n childToolCallId: string\n description: string\n}\n\nexport function setToolCallStatus(\n turn: TurnState | TurnProjection | null | undefined,\n toolCallId: string,\n status: ToolCallProjection[\"status\"],\n result: unknown,\n pendingQuestionRef: PendingQuestionRef | null,\n): void {\n if (!turn || !toolCallId) return\n const toolCalls = \"toolCalls\" in turn ? turn.toolCalls : turn.tool_calls\n for (let i = 0; i < toolCalls.length; i++) {\n if (toolCalls[i].id !== toolCallId) continue\n toolCalls[i] = {\n ...toolCalls[i],\n status,\n result,\n pending_question_ref: pendingQuestionRef,\n }\n return\n }\n}\n\nexport function applyAskUserPauseToTurn(\n turn: TurnState | TurnProjection | null | undefined,\n pauseToolData: Record<string, unknown>,\n toolCallId: string,\n childLoopName: string,\n description: string,\n displayNameResolver: (name: string) => string,\n): void {\n if (!turn || !toolCallId) return\n\n const sourceLoop = childLoopName\n ? { loop_name: childLoopName, description }\n : null\n const toolName = String(pauseToolData.name ?? \"AskUserQuestion\")\n const args = JSON.stringify(pauseToolData.arguments ?? {})\n const result = askUserResultFromPausePayload(pauseToolData, sourceLoop)\n\n const isTurnState = \"toolCalls\" in turn\n const toolCalls = isTurnState ? turn.toolCalls : turn.tool_calls\n const blocks = turn.blocks\n\n // upsert tool call\n const displayName = displayNameResolver(toolName)\n let found = false\n for (let i = 0; i < toolCalls.length; i++) {\n if (toolCalls[i].id !== toolCallId) continue\n toolCalls[i] = {\n ...toolCalls[i],\n tool_name: toolName || toolCalls[i].tool_name,\n display_name: displayName || toolCalls[i].display_name,\n arguments: args || toolCalls[i].arguments,\n }\n found = true\n break\n }\n if (!found) {\n toolCalls.push({\n id: toolCallId,\n tool_name: toolName,\n display_name: displayName,\n arguments: args,\n status: \"pending\",\n })\n }\n\n // upsert tool_use block\n let blockFound = false\n for (let i = 0; i < blocks.length; i++) {\n if (blocks[i].type !== \"tool_use\" || blocks[i].tool_call_id !== toolCallId) continue\n blocks[i] = { ...blocks[i], content: args, tool_name: toolName, display_name: displayName }\n blockFound = true\n break\n }\n if (!blockFound) {\n blocks.push({\n type: \"tool_use\",\n content: args,\n tool_call_id: toolCallId,\n tool_name: toolName,\n display_name: displayName,\n })\n }\n\n // set status\n setToolCallStatus(turn, toolCallId, \"awaiting_answer\", result, null)\n\n // upsert tool_result block\n let resultBlockFound = false\n for (let i = 0; i < blocks.length; i++) {\n if (blocks[i].type !== \"tool_result\" || blocks[i].tool_call_id !== toolCallId) continue\n blocks[i] = { ...blocks[i], content: result }\n resultBlockFound = true\n break\n }\n if (!resultBlockFound) {\n blocks.push({\n type: \"tool_result\",\n content: result,\n tool_call_id: toolCallId,\n tool_name: toolName,\n display_name: displayName,\n })\n }\n}\n\nexport function applyChildPauseToParent(\n parentTurn: TurnState | TurnProjection | null | undefined,\n parentToolCallId: string,\n childLoopName: string,\n childToolCallId: string,\n description: string,\n displayNameResolver: (name: string) => string,\n): void {\n if (!parentTurn || !parentToolCallId) return\n\n const toolCalls = \"toolCalls\" in parentTurn ? parentTurn.toolCalls : parentTurn.tool_calls\n const blocks = parentTurn.blocks\n\n const displayName = displayNameResolver(\"Agent\")\n let found = false\n for (let i = 0; i < toolCalls.length; i++) {\n if (toolCalls[i].id !== parentToolCallId) continue\n toolCalls[i] = {\n ...toolCalls[i],\n tool_name: \"Agent\",\n display_name: displayName || toolCalls[i].display_name,\n }\n found = true\n break\n }\n if (!found) {\n toolCalls.push({\n id: parentToolCallId,\n tool_name: \"Agent\",\n display_name: displayName,\n arguments: \"\",\n status: \"pending\",\n })\n }\n\n // upsert tool_use block\n let blockFound = false\n for (let i = 0; i < blocks.length; i++) {\n if (blocks[i].type !== \"tool_use\" || blocks[i].tool_call_id !== parentToolCallId) continue\n blockFound = true\n break\n }\n if (!blockFound) {\n blocks.push({\n type: \"tool_use\",\n content: \"\",\n tool_call_id: parentToolCallId,\n tool_name: \"Agent\",\n display_name: displayName,\n })\n }\n\n setToolCallStatus(parentTurn, parentToolCallId, \"awaiting_answer\", null, {\n child_loop_name: childLoopName,\n child_tool_call_id: childToolCallId,\n description: description || null,\n })\n}\n\nfunction askUserResultFromPausePayload(\n pauseToolData: Record<string, unknown>,\n sourceLoop: { loop_name: string; description: string } | null,\n): string {\n const args =\n typeof pauseToolData.arguments === \"object\" && pauseToolData.arguments !== null\n ? (pauseToolData.arguments as Record<string, unknown>)\n : {}\n const payload: Record<string, unknown> = { questions: args.questions ?? [] }\n if (sourceLoop) payload.source_loop = sourceLoop\n return JSON.stringify(payload)\n}\n\nexport function sourceLoopFor(\n loopId: string,\n loopDescriptions: Map<string, string>,\n): { loop_name: string; description: string } | null {\n if (loopId === \"root\") return null\n const description = loopDescriptions.get(loopId)\n if (!description) return null\n return { loop_name: loopId, description }\n}\n\n/** 本轮交付给用户的成果:工作区里的文件,或可以打开的网址。 */\nexport interface FinalArtifact {\n kind: \"file\" | \"link\"\n /** file 是文件路径(相对工作目录或容器内绝对路径);link 是 http/https 网址。 */\n target: string\n label: string\n}\n\nconst MAX_FINAL_ARTIFACTS = 20\n\n/**\n * 服务端已经清洗过一遍,这里只挡住渲染不了的形态。绝对路径要留着:会话的真实\n * 工作目录可能是项目目录或用户自己切过的目录,取文件那一层认绝对路径,在这里\n * 拦掉反而会让对的卡片消失。\n */\nfunction normalizeFinalArtifacts(raw: unknown): FinalArtifact[] {\n if (!Array.isArray(raw)) return []\n const artifacts: FinalArtifact[] = []\n const seen = new Set<string>()\n for (const item of raw) {\n if (typeof item !== \"object\" || item === null) continue\n const record = item as Record<string, unknown>\n const target = String(record.target ?? \"\").trim()\n if (!target || seen.has(target)) continue\n const isLink = /^https?:\\/\\//i.test(target)\n // 越界路径没有能打开它的形态,留下来只会变成点了报错的卡片。\n if (!isLink && target.split(\"/\").includes(\"..\")) continue\n seen.add(target)\n artifacts.push({\n kind: isLink ? \"link\" : \"file\",\n target,\n label: String(record.label ?? \"\").trim(),\n })\n if (artifacts.length === MAX_FINAL_ARTIFACTS) break\n }\n return artifacts\n}\n\n/**\n * Shared by the streaming and history channels — both must decide \"is this\n * follow-up showable\" identically. Returns null when there is nothing to show.\n */\nexport function normalizePostChatFollowup(\n data: Record<string, unknown>,\n assistantEntryId: string,\n): {\n assistant_entry_id: string\n recaption: string\n suggestions: string[]\n final_artifacts: FinalArtifact[]\n feedback_eligible: boolean\n feedback_scope: \"latest_result\"\n} | null {\n const raw = data.suggestions\n const suggestions: string[] = []\n if (Array.isArray(raw)) {\n for (const value of raw) {\n if (typeof value !== \"string\") continue\n const text = value.trim()\n if (text && !suggestions.includes(text)) suggestions.push(text)\n }\n }\n const recaption = String(data.recaption ?? \"\")\n const finalArtifacts = normalizeFinalArtifacts(data.final_artifacts)\n const feedbackEligible = data.feedback_eligible === true\n if (suggestions.length === 0 && !recaption && finalArtifacts.length === 0 && !feedbackEligible)\n return null\n return {\n assistant_entry_id: assistantEntryId,\n recaption,\n suggestions: suggestions.slice(0, 3),\n final_artifacts: finalArtifacts,\n feedback_eligible: feedbackEligible,\n feedback_scope: \"latest_result\",\n }\n}\n\nexport function normalizeChildPause(\n pausePayload: Record<string, unknown>,\n): {\n pauseToolData: Record<string, unknown>\n childLoopName: string\n childToolCallId: string\n description: string\n} {\n const rawPtd = pausePayload.pause_tool_data\n const pauseToolData: Record<string, unknown> =\n typeof rawPtd === \"object\" && rawPtd !== null\n ? { ...(rawPtd as Record<string, unknown>) }\n : { ...pausePayload }\n\n let sourceLoop = pauseToolData.source_loop as Record<string, unknown> | undefined\n if (typeof sourceLoop !== \"object\" || sourceLoop === null) {\n sourceLoop = pausePayload.source_loop as Record<string, unknown> | undefined\n }\n\n const childLoopName =\n String(pausePayload.child_loop_name ?? \"\") ||\n (typeof sourceLoop === \"object\" && sourceLoop ? String(sourceLoop.name ?? \"\") : \"\")\n\n const childToolCallId =\n String(\n pausePayload.child_pause_tool_call_id ?? pauseToolData.tool_call_id ?? \"\",\n )\n\n const description =\n typeof sourceLoop === \"object\" && sourceLoop ? String(sourceLoop.description ?? \"\") : \"\"\n\n if (childLoopName && description) {\n pauseToolData.source_loop = { name: childLoopName, description }\n }\n\n return { pauseToolData, childLoopName, childToolCallId, description }\n}\n","import type { ContentBlock, PendingQuestionRef, ToolBridgeContent } from \"./projection\"\nimport type { ContextProjectionData } from \"./context\"\n\nexport interface TextContentPart {\n type: \"text\"\n text: string\n}\n\nexport interface ImageUrlContentPart {\n type: \"image_url\"\n image_url: {\n url: string\n }\n}\n\nexport interface FileContentPart {\n type: \"file\"\n name: string\n data: string\n}\n\nexport type MessageContentPart = TextContentPart | ImageUrlContentPart | FileContentPart\nexport type MessageContent = string | MessageContentPart[]\n\nexport interface ToolCallInfo {\n id: string\n name: string\n display_name?: string | null\n arguments: string\n result?: unknown\n status?: \"pending\" | \"done\" | \"error\" | \"cancelled\" | \"awaiting_answer\"\n duration_ms?: number | null\n pending_question_ref?: PendingQuestionRef | null\n}\n\nexport type { ToolBridgeContent }\n\n/** Derive tool status from the result content string. */\nexport function inferToolStatus(\n resultStr: string,\n): \"done\" | \"error\" | \"cancelled\" {\n if (resultStr.includes('\"Cancelled by user\"')) return \"cancelled\"\n try {\n const parsed = JSON.parse(resultStr)\n if (typeof parsed === \"object\" && parsed !== null) {\n // Direct error: {\"error\": \"...\"}\n if (\"error\" in parsed && parsed.error) return \"error\"\n // 部分工具把输出包装为 {\"result\": {\"error\": \"...\"}, ...}\n const nested = parsed.result\n if (typeof nested === \"object\" && nested !== null && \"error\" in nested && nested.error) {\n return \"error\"\n }\n }\n } catch {\n // not JSON, treat as success\n }\n return \"done\"\n}\n\nexport interface MemoryRefInfo {\n id: number\n content_preview: string\n skill_name?: string | null\n}\n\nexport interface CompactionInfo {\n compaction_id: string\n summary_preview?: string | null\n summary_full?: string | null\n archived_count?: number | null\n archived_files?: ArchivedFileInfo[] | null\n archived_tool_calls?: ArchivedToolCallInfo[] | null\n tokens_before?: number | null\n tokens_after?: number | null\n saved_ratio?: number | null\n trigger?: \"auto\" | \"manual\" | \"forced_retry\" | null\n failure_reason?: string | null\n fallback_applied?: boolean | null\n}\n\nexport interface ArchivedFileInfo {\n tool_name?: string | null\n filename?: string | null\n relative_path?: string | null\n size_bytes?: number | null\n}\n\nexport interface ArchivedToolCallInfo {\n tool_call_id?: string | null\n tool_name?: string | null\n archive_path?: string | null\n replacement_content?: string | null\n entry_id?: string | null\n}\n\nexport interface ChatMessage {\n role: \"user\" | \"assistant\" | \"tool\" | \"error\"\n content: MessageContent\n reasoning?: string\n tool_calls?: ToolCallInfo[]\n status?: \"streaming\" | \"completed\" | \"paused\" | \"failed\" | \"interrupted\"\n duration_ms?: number\n timestamp?: string\n entry_id?: string\n /** Stable React key retained when an optimistic user message is confirmed. */\n render_id?: string\n parent_id?: string | null\n loop_name?: string\n /** Entry kind from backend -- present for non-message entries like mode changes. */\n kind?: string\n /** Memory references injected into this turn's context */\n memory_refs?: MemoryRefInfo[]\n /** Raw projection blocks for block-level UI rendering. */\n blocks?: ContentBlock[]\n /** Compaction metadata for compaction turns. */\n compaction?: CompactionInfo\n /** Sourced Context metadata for rendering or headless consumers. */\n context?: ContextProjectionData\n}\n","import { inferToolStatus } from \"../../schemas/message\"\nimport type {\n ContentBlock,\n MemoryRef,\n ToolCallProjection,\n TurnProjection,\n} from \"../../schemas/projection\"\n\nexport interface TurnState {\n turnId: string\n loopId: string\n role: \"user\" | \"assistant\" | \"system\"\n model: string | null\n startedAt: number\n contextWindow: number\n blocks: ContentBlock[]\n toolCalls: ToolCallProjection[]\n usage: Record<string, unknown> | null\n responseDone: boolean\n firstTokenMs: number | null\n streamDurationMs: number | null\n firstTokenDeliveryMs: number | null\n /** 生产者上报的模型请求时序;缺失时保持 null,不用浏览器时间补(#2581 A1/I1)。 */\n modelStartedAt: string | null\n modelDurationMs: number | null\n modelStartedAtReported: boolean\n memoryRefs: MemoryRef[] | null\n parentForkToolCallId: string | null\n}\n\nexport function createTurnState(\n turnId: string,\n loopId: string,\n opts: {\n model?: string | null\n contextWindow?: number\n memoryRefs?: MemoryRef[] | null\n } = {},\n): TurnState {\n return {\n turnId,\n loopId,\n role: \"assistant\",\n model: opts.model ?? null,\n startedAt: Date.now(),\n contextWindow: opts.contextWindow ?? 0,\n blocks: [],\n toolCalls: [],\n usage: null,\n responseDone: false,\n firstTokenMs: null,\n streamDurationMs: null,\n firstTokenDeliveryMs: null,\n modelStartedAt: null,\n modelDurationMs: null,\n modelStartedAtReported: false,\n memoryRefs: opts.memoryRefs ?? null,\n parentForkToolCallId: null,\n }\n}\n\nexport function snapshot(\n state: TurnState,\n sequence: number,\n status: TurnProjection[\"status\"],\n): TurnProjection {\n return {\n id: state.turnId,\n sequence,\n turn_id: state.turnId,\n loop_id: state.loopId,\n kind: \"message\",\n role: state.role,\n status,\n blocks: [...state.blocks],\n tool_calls: [...state.toolCalls],\n model: state.model,\n usage: state.usage ? { ...state.usage } : null,\n duration_ms: state.modelDurationMs,\n first_token_ms: state.firstTokenMs,\n stream_duration_ms: state.streamDurationMs,\n first_token_delivery_ms: state.firstTokenDeliveryMs,\n started_at: state.modelStartedAt ?? new Date(state.startedAt).toISOString(),\n // 没有 payload 上报时用的是 loop:turn 的浏览器事件时间,标记出来供瀑布区分。\n has_reported_timing: state.modelStartedAtReported,\n context_window: state.contextWindow,\n memory_refs: state.memoryRefs,\n parent_fork_tool_call_id: state.parentForkToolCallId,\n }\n}\n\nexport const PAUSE_TOOL_NAMES = new Set([\"AskUserQuestion\", \"ExitPlanMode\"])\n\nexport function toolStatusFromResult(result: unknown): ToolCallProjection[\"status\"] {\n const text =\n typeof result === \"string\"\n ? result\n : Array.isArray(result)\n ? result\n .filter(\n (p): p is { type: string; text: string } =>\n typeof p === \"object\" && p !== null && p.type === \"text\",\n )\n .map((p) => p.text ?? \"\")\n .join(\"\\n\")\n : String(result ?? \"\")\n return inferToolStatus(text)\n}\n","export type ContextAction = \"published\" | \"retained\" | \"removed\"\n\n/** Safe display-source metadata retained for headless consumers. */\nexport type ContextSourceInfo = Record<string, unknown>\n\nexport interface ContextProjectionData {\n context_kind: string\n context_key: string\n context_name: string\n context_order: number\n context_action: ContextAction\n context_revision: string\n display_title?: string | null\n display_summary?: string | null\n sources: ContextSourceInfo[]\n}\n\nexport interface ContextProjectionFields {\n context_kind?: string | null\n context_key?: string | null\n context_name?: string | null\n context_order?: number | null\n context_action?: ContextAction | null\n context_revision?: string | null\n display_title?: string | null\n display_summary?: string | null\n sources?: ContextSourceInfo[] | null\n}\n\nexport interface ContextDisplayState {\n title: string\n summary: string\n detail: string\n isRemoved: boolean\n}\n\nexport interface ContextGroupDisplayState {\n title: string\n summary: string\n count: number\n}\n\nconst BUILTIN_CONTEXT_TITLES: Record<string, string> = {\n \"agent-instructions\": \"项目说明\",\n \"skill-catalog\": \"可用能力\",\n \"runtime-context\": \"当前工作环境\",\n \"workspace-context\": \"当前工作区环境\",\n}\n\nconst BUILTIN_CONTEXT_DETAILS: Record<string, string> = {\n \"agent-instructions\": \"这些说明会帮助智能体理解当前项目和工作要求。\",\n \"skill-catalog\": \"这些能力会帮助智能体选择合适的方式完成任务。\",\n \"runtime-context\": \"这些信息会帮助智能体了解当前文件夹和运行条件。\",\n \"workspace-context\": \"这些信息会帮助智能体了解当前工作目录、文件和运行环境。\",\n}\n\nfunction nonEmptyString(value: unknown): string | null {\n return typeof value === \"string\" && value.trim() ? value.trim() : null\n}\n\nexport function contextProjectionData(\n fields: ContextProjectionFields,\n): ContextProjectionData | null {\n const contextKind = nonEmptyString(fields.context_kind)\n const contextKey = nonEmptyString(fields.context_key)\n const contextName = nonEmptyString(fields.context_name)\n const contextRevision = nonEmptyString(fields.context_revision)\n if (\n !contextKind ||\n !contextKey ||\n !contextName ||\n !contextRevision ||\n typeof fields.context_order !== \"number\" ||\n !Number.isFinite(fields.context_order) ||\n !fields.context_action\n ) {\n return null\n }\n return {\n context_kind: contextKind,\n context_key: contextKey,\n context_name: contextName,\n context_order: fields.context_order,\n context_action: fields.context_action,\n context_revision: contextRevision,\n display_title: nonEmptyString(fields.display_title),\n display_summary: nonEmptyString(fields.display_summary),\n sources: Array.isArray(fields.sources) ? fields.sources : [],\n }\n}\n\n/** The single status-to-display mapping used by both React chat surfaces. */\nexport function getContextDisplayState(\n context: ContextProjectionData,\n): ContextDisplayState {\n // 后端为每个原子给了具体标题,优先用它。按 kind 查的表只是老历史条目的兜底:\n // 同一个 kind 下现在有多个原子(三份说明、两块运行环境),标题不能再按 kind 定。\n const title =\n nonEmptyString(context.display_title) ??\n BUILTIN_CONTEXT_TITLES[context.context_kind] ??\n \"对话背景\"\n const isRemoved = context.context_action === \"removed\"\n const summary =\n nonEmptyString(context.display_summary) ??\n (isRemoved\n ? \"已停止用于后续对话\"\n : context.context_action === \"retained\"\n ? \"继续用于后续对话\"\n : context.context_kind === \"agent-instructions\"\n ? \"已更新本次对话使用的项目说明\"\n : context.context_kind === \"skill-catalog\"\n ? \"已更新本次可用能力\"\n : context.context_kind === \"runtime-context\"\n ? \"已更新本次工作环境\"\n : context.context_kind === \"workspace-context\"\n ? \"已更新本次工作区环境\"\n : \"已更新本次对话背景\")\n const detail = isRemoved\n ? `${title}已不再用于后续对话。`\n : (BUILTIN_CONTEXT_DETAILS[context.context_kind] ??\n \"这些信息会帮助智能体理解当前任务。\")\n return { title, summary, detail, isRemoved }\n}\n\n/**\n * 把一段渲染序列里连续的 Context 归成组。\n *\n * 入参是序列里每一项的 context kind,非 Context 项传 null;返回每一段连续\n * Context 的下标数组。纯下标运算,不认识任何 UI 类型,所以调试日志、Lite 视图\n * 和 SDK 卡片可以共用同一份分组判定,各自只管排版。\n */\nexport function groupAdjacentContextRuns(\n kinds: readonly (string | null)[],\n): readonly (readonly number[])[] {\n const runs: number[][] = []\n let current: number[] | null = null\n kinds.forEach((kind, index) => {\n if (kind === null) {\n current = null\n return\n }\n if (current === null) {\n current = []\n runs.push(current)\n }\n current.push(index)\n })\n return runs\n}\n\n/** 折叠行的文案。展开后才逐条显示各自的标题与状态。 */\nexport function getContextGroupDisplayState(\n contexts: readonly ContextProjectionData[],\n): ContextGroupDisplayState {\n const count = contexts.length\n if (count === 1) {\n const single = getContextDisplayState(contexts[0])\n return { title: single.title, summary: single.summary, count }\n }\n const removed = contexts.filter(\n (context) => context.context_action === \"removed\",\n ).length\n const updated = count - removed\n const parts: string[] = []\n if (updated > 0) parts.push(`${updated} 项已更新`)\n if (removed > 0) parts.push(`${removed} 项已停用`)\n return {\n title: \"对话背景\",\n summary: parts.join(\" · \") || `${count} 项`,\n count,\n }\n}\n","import { contextProjectionData } from \"../../schemas/context\"\nimport type { TurnProjection } from \"../../schemas/projection\"\nimport { isRecord } from \"../type-guards\"\n\n/** Build one Context turn from the canonical entry used by live and history paths. */\nexport function buildContextTurn(\n entry: Record<string, unknown>,\n sequence: number,\n): TurnProjection | null {\n if (entry.kind !== \"context\" || !isRecord(entry.source) || !isRecord(entry.data)) {\n return null\n }\n const display = isRecord(entry.data.display) ? entry.data.display : {}\n const message = isRecord(entry.message) ? entry.message : {}\n const context = contextProjectionData({\n context_kind: typeof entry.source.kind === \"string\" ? entry.source.kind : null,\n context_key: typeof entry.source.key === \"string\" ? entry.source.key : null,\n context_name: typeof entry.data.contribution_name === \"string\" ? entry.data.contribution_name : null,\n context_order: typeof entry.data.order === \"number\" ? entry.data.order : null,\n context_action:\n entry.data.action === \"published\" || entry.data.action === \"retained\" || entry.data.action === \"removed\"\n ? entry.data.action\n : null,\n context_revision: typeof entry.data.revision === \"string\" ? entry.data.revision : null,\n display_title: typeof display.title === \"string\" ? display.title : null,\n display_summary: typeof display.summary === \"string\" ? display.summary : null,\n sources: Array.isArray(display.sources) ? display.sources.filter(isRecord) : [],\n })\n if (!context) return null\n const turnId = typeof entry.id === \"string\" && entry.id ? entry.id : `context-${sequence}`\n return {\n id: turnId,\n sequence,\n turn_id: turnId,\n loop_id: typeof entry.loop_name === \"string\" && entry.loop_name ? entry.loop_name : \"root\",\n kind: \"context\",\n role: \"system\",\n status: \"completed\",\n blocks: [],\n tool_calls: [],\n model: null,\n usage: null,\n duration_ms: 0,\n context_content: Object.hasOwn(message, \"content\") ? message.content : null,\n ...context,\n }\n}\n","import type { MemoryRef, RunTiming, TurnProjection } from \"../../schemas/projection\"\nimport {\n applyAskUserPauseToTurn,\n applyChildPauseToParent,\n appendTextBlock,\n appendToolCallArguments,\n appendToolResultDelta,\n applyToolResult,\n buildCompactionTurn,\n buildMarkerTurn,\n buildSystemNotificationBlock,\n buildSystemNotificationTurn,\n type ChildPauseInfo,\n normalizeChildPause,\n normalizePostChatFollowup,\n setToolCallStatus,\n sourceLoopFor,\n upsertToolCall,\n} from \"./helpers\"\nimport { isRecord } from \"../type-guards\"\nimport { createTurnState, PAUSE_TOOL_NAMES, snapshot, toolStatusFromResult, type TurnState } from \"./state\"\nimport { buildContextTurn } from \"./context\"\n\nexport interface RawEvent {\n type: string\n payload: Record<string, unknown>\n}\n\n/** 在任何事件处理前确认 Socket.IO 批次已到达客户端。 */\nexport function acknowledgeTurnEvents(acknowledge?: () => void): void {\n acknowledge?.()\n}\n\nexport type ProjectionUpdate =\n | { kind: \"upsert\"; turn: TurnProjection }\n | {\n kind: \"workspace_changed\"\n loopId: string\n toolCallId?: string\n toolName?: string\n workspacePath?: string\n }\n\n/** 是否包含会改变聊天运行生命周期的事件。纯观测/整理事件不启动新一轮。 */\nexport function hasChatRunEvent(events: RawEvent[]): boolean {\n return events.some(\n (event) =>\n event.type !== \"llm:first_token:delivered\" &&\n event.type !== \"session:post_chat_followup\" &&\n !event.type.startsWith(\"compaction:\"),\n )\n}\n\n/**\n * 缺失 chat:end 时的终态兜底。只有被投影接受到当前 assistant turn 的 followup\n * 才能结束流式态;陈旧 followup 或其后已有新轮事件时均返回 false。\n */\nexport function acceptedPostChatFollowupCompletesLatestRun(\n events: RawEvent[],\n updates: ProjectionUpdate[],\n): boolean {\n const acceptedAssistantEntryIds = new Set(\n updates.flatMap((update) => {\n if (update.kind !== \"upsert\") return []\n const followup = update.turn.post_chat_followup\n return followup?.assistant_entry_id ? [followup.assistant_entry_id] : []\n }),\n )\n for (let index = events.length - 1; index >= 0; index -= 1) {\n const event = events[index]\n if (event?.type !== \"session:post_chat_followup\") continue\n const assistantEntryId = String(event.payload.assistant_entry_id ?? \"\")\n return (\n acceptedAssistantEntryIds.has(assistantEntryId) &&\n !hasChatRunEvent(events.slice(index + 1))\n )\n }\n return false\n}\n\ntype FollowupTurn = TurnProjection\n\nfunction isConversationTurn(turn: TurnProjection): boolean {\n return (\n (turn.role === \"user\" || turn.role === \"assistant\") &&\n (turn.kind ?? \"message\") === \"message\" &&\n !turn.blocks.some(\n (block) =>\n block.type === \"mode_change\" ||\n block.type === \"plan_status\" ||\n block.type === \"ask_user_answer\",\n )\n )\n}\n\nfunction completedResponseText(content: unknown): string {\n if (typeof content === \"string\") return content\n if (!Array.isArray(content)) return content == null ? \"\" : String(content)\n return content\n .filter(\n (part): part is Record<string, unknown> =>\n typeof part === \"object\" && part !== null && !Array.isArray(part),\n )\n .filter((part) => part.type === \"text\")\n .map((part) => String(part.text ?? \"\"))\n .join(\"\")\n}\n\nfunction replaceTextContent(state: TurnState, content: string): void {\n const currentContent = state.blocks\n .filter((block) => block.type === \"text\")\n .map((block) => String(block.content ?? \"\"))\n .join(\"\")\n if (currentContent === content) return\n const replacement = { type: \"text\" as const, content }\n const blocks: TurnState[\"blocks\"] = []\n let inserted = false\n for (const block of state.blocks) {\n if (block.type === \"text\") {\n if (content && !inserted) {\n blocks.push(replacement)\n inserted = true\n }\n continue\n }\n blocks.push(block)\n }\n if (content && !inserted) {\n const toolIndex = blocks.findIndex((block) => block.type === \"tool_use\")\n blocks.splice(toolIndex < 0 ? blocks.length : toolIndex, 0, replacement)\n }\n state.blocks = blocks\n}\n\nfunction applyResponseBlockOrder(state: TurnState, value: unknown): boolean {\n // Keep this decision path aligned with ProjectionBuilder._apply_response_block_order.\n if (!Array.isArray(value)) return false\n const ordered: TurnState[\"blocks\"] = []\n for (const item of value) {\n if (typeof item !== \"object\" || item === null || Array.isArray(item)) continue\n const block = item as Record<string, unknown>\n if (block.type === \"text\" || block.type === \"thinking\") {\n const content = String(block[block.type] ?? \"\")\n if (content) ordered.push({ type: block.type, content })\n continue\n }\n if (block.type !== \"tool_call\") continue\n const toolCallId = String(block.id ?? \"\")\n const toolBlock = state.blocks.find(\n (candidate) =>\n candidate.type === \"tool_use\" && candidate.tool_call_id === toolCallId,\n )\n if (toolBlock) ordered.push(toolBlock)\n }\n if (ordered.length === 0 && value.length > 0) return false\n const unrelatedBlocks = state.blocks.filter(\n (block) =>\n block.type !== \"text\" && block.type !== \"thinking\" && block.type !== \"tool_use\",\n )\n state.blocks = [...ordered, ...unrelatedBlocks]\n return true\n}\n\nexport class ClientProjectionBuilder {\n private activeTurns = new Map<string, TurnState>()\n private lastTurnIds = new Map<string, string>()\n private latestTurns = new Map<string, TurnProjection>()\n private turnsById = new Map<string, TurnProjection>()\n private loopDescriptions = new Map<string, string>()\n /** loop_name → 正在运行的子智能体起点,agent:end 结算并挂到父工具调用上。 */\n private activeSubagentRuns = new Map<string, { runId: string; startedAt: string }>()\n private pendingChildPauses = new Map<string, ChildPauseInfo>()\n private pendingMemoryRefs = new Map<string, { turnId: string; refs: MemoryRef[] }>()\n private activeCompactions = new Map<string, Record<string, unknown>>()\n private failedCompactions = new Map<string, Record<string, unknown>>()\n private seq = 0\n private syntheticCounter = 0\n private displayNameResolver: (name: string) => string\n\n constructor(displayNameResolver?: (name: string) => string) {\n this.displayNameResolver = displayNameResolver ?? ((n) => n)\n }\n\n processBatch(events: RawEvent[]): ProjectionUpdate[] {\n const lastUpsertByTurn = new Map<string, ProjectionUpdate & { kind: \"upsert\" }>()\n const nonUpserts: ProjectionUpdate[] = []\n for (const event of events) {\n const updates = this.processEvent(event)\n if (!updates) continue\n for (const u of updates) {\n if (u.kind === \"upsert\") {\n lastUpsertByTurn.set(u.turn.turn_id, u)\n } else {\n nonUpserts.push(u)\n }\n }\n }\n return [...nonUpserts, ...lastUpsertByTurn.values()]\n }\n\n processEvent(event: RawEvent): ProjectionUpdate[] | null {\n const payload = event.payload\n const loopId = String(payload.loop_name ?? \"root\")\n\n switch (event.type) {\n case \"memory:inject:done\":\n return this.onMemoryInject(loopId, payload)\n case \"memory:inject:none\":\n return null\n case \"context:entry\":\n return this.onContextEntry(payload)\n case \"loop:turn\":\n return this.onLoopTurn(loopId, payload)\n case \"mode:change\":\n return this.onModeChange(loopId, payload)\n case \"plan:status:update\":\n return this.onPlanStatusUpdate(loopId, payload)\n case \"workspace:changed\":\n return this.onWorkspaceChanged(loopId, payload)\n case \"agent:start\":\n return this.onAgentStart(loopId, payload)\n case \"bg:started\":\n return this.onBgStarted(loopId, payload)\n case \"bg:tasks_completed\":\n return this.onBgTasksCompleted(loopId, payload)\n case \"loop:ask_user_answer\":\n return this.onAskUserAnswer(loopId, payload)\n case \"user:message\":\n return this.onUserMessage(loopId, payload)\n case \"session:post_chat_followup\":\n return this.onPostChatFollowup(payload)\n }\n\n if (event.type.startsWith(\"compaction:\"))\n return this.onCompaction(event.type, loopId, payload)\n\n if (event.type === \"llm:first_token:delivered\") {\n const targetTurnId = String(payload.turn_id ?? \"\")\n const active = this.activeTurns.get(loopId)\n if (active && (!targetTurnId || active.turnId === targetTurnId)) {\n this.applyFirstTokenDelivery(active, payload)\n return this.syncPatch(active)\n }\n const latest = targetTurnId\n ? this.turnsById.get(targetTurnId)\n : this.latestTurns.get(loopId)\n const duration = payload.first_token_delivery_ms\n if (!latest || latest.role !== \"assistant\" || typeof duration !== \"number\" || duration < 0) {\n return null\n }\n const turn = { ...latest, first_token_delivery_ms: duration }\n this.turnsById.set(turn.turn_id, turn)\n if (this.latestTurns.get(loopId)?.turn_id === turn.turn_id) {\n this.latestTurns.set(loopId, turn)\n }\n return [{ kind: \"upsert\", turn }]\n }\n\n const state = this.activeTurns.get(loopId)\n if (!state) {\n if (event.type === \"chat:end\") {\n this.pendingMemoryRefs.delete(loopId)\n return null\n }\n if (event.type === \"agent:end\") return this.onAgentEnd(null, loopId, payload)\n return null\n }\n\n switch (event.type) {\n case \"llm:stream:reset\":\n state.blocks = []\n state.toolCalls = []\n state.usage = null\n state.responseDone = false\n state.firstTokenMs = null\n state.streamDurationMs = null\n state.firstTokenDeliveryMs = null\n return this.syncPatch(state)\n case \"llm:thinking:delta\":\n this.applyFirstTokenDelivery(state, payload)\n return this.onDelta(state, \"thinking\", \"\", String(payload.content ?? \"\"))\n case \"llm:content:delta\":\n this.applyFirstTokenDelivery(state, payload)\n return this.onDelta(state, \"text\", \"\", String(payload.content ?? \"\"))\n case \"llm:content:complete\":\n replaceTextContent(state, String(payload.content ?? \"\"))\n return this.syncPatch(state)\n case \"llm:content:done\":\n this.applyStreamTiming(state, payload)\n return this.syncPatch(state)\n case \"llm:tool_call:created\":\n this.applyFirstTokenDelivery(state, payload)\n return this.onToolCallCreated(state, payload)\n case \"llm:tool_call:arguments:delta\":\n this.applyFirstTokenDelivery(state, payload)\n return this.onToolCallArgumentsDelta(state, payload)\n case \"llm:response:done\":\n return this.onResponseDone(state, loopId, payload)\n case \"tool:result:delta\":\n return this.onToolResultDelta(state, payload)\n case \"tool:result:done\":\n return this.onToolResultDone(state, loopId, payload)\n case \"loop:tool_ui\":\n return this.onToolUi(state, payload)\n case \"loop:tool_bridge\":\n return this.onToolBridge(state, payload)\n case \"tool:approval:required\":\n return this.onToolApprovalRequired(state, payload)\n case \"loop:child_pause\":\n return this.onChildPause(state, loopId, payload)\n case \"chat:end\":\n return this.onChatEnd(state, loopId, payload)\n case \"agent:end\":\n return this.onAgentEnd(state, loopId, payload)\n default:\n return null\n }\n }\n\n reset(): void {\n this.activeTurns.clear()\n this.lastTurnIds.clear()\n this.latestTurns.clear()\n this.turnsById.clear()\n this.loopDescriptions.clear()\n this.activeSubagentRuns.clear()\n this.pendingChildPauses.clear()\n this.pendingMemoryRefs.clear()\n this.activeCompactions.clear()\n this.failedCompactions.clear()\n this.seq = 0\n this.syntheticCounter = 0\n }\n\n seedSequence(maxSeq: number): void {\n if (maxSeq > this.seq) {\n this.seq = maxSeq\n }\n }\n\n _seedTurns(turns: TurnProjection[]): void {\n const latestTurns = new Map<string, TurnProjection>()\n const turnsById = new Map<string, TurnProjection>()\n for (const turn of turns) {\n this.seedSequence(turn.sequence)\n if (!isConversationTurn(turn)) continue\n turnsById.set(turn.turn_id, turn)\n const current = latestTurns.get(turn.loop_id)\n if (!current || turn.sequence >= current.sequence) {\n latestTurns.set(turn.loop_id, turn)\n }\n }\n this.latestTurns = latestTurns\n this.turnsById = turnsById\n }\n\n // --- Event handlers ---\n\n private onMemoryInject(\n loopId: string,\n payload: Record<string, unknown>,\n ): null {\n const refs = payload.memory_refs\n const turnId = String(payload.turn_id ?? \"\")\n if (Array.isArray(refs) && refs.length > 0) {\n this.pendingMemoryRefs.set(loopId, {\n turnId,\n refs: refs.map((r: Record<string, unknown>) => ({\n id: Number(r.id),\n content_preview: String(r.content_preview ?? \"\"),\n skill_name: r.skill_name != null ? String(r.skill_name) : null,\n })),\n })\n }\n return null\n }\n\n private onContextEntry(\n payload: Record<string, unknown>,\n ): ProjectionUpdate[] | null {\n if (!isRecord(payload.entry)) return null\n const turn = buildContextTurn(payload.entry, this.nextSeq())\n return turn ? [{ kind: \"upsert\", turn }] : null\n }\n\n private onLoopTurn(\n loopId: string,\n payload: Record<string, unknown>,\n ): ProjectionUpdate[] {\n let turnId = String(payload.turn_id ?? this.nextTurnId(`turn:${loopId}`))\n let memoryRefs: MemoryRef[] | null = null\n\n // 记忆锚点只认它自己那一轮(和后端 `ProjectionBuilder._consume_memory_inject`\n // 同一套规则):memory:inject:done 带的 turn_id 就是本次 chat 首个模型回合的 id。\n // 无条件让「下一个 loop:turn」领走的话,首个模型回合之前插入的 turn(例如\n // @知识库 时系统发起的那次 kb_search 预检索)会被改写成同一个 id,随后真正的\n // 首轮回合按 id 替换,检索卡片就被回答覆盖了。老事件里 turn_id 可能为空,那时\n // 保留「下一个回合领走」的旧行为。\n const pending = this.pendingMemoryRefs.get(loopId)\n if (pending && (!pending.turnId || pending.turnId === turnId)) {\n this.pendingMemoryRefs.delete(loopId)\n if (pending.turnId) turnId = pending.turnId\n memoryRefs = pending.refs\n }\n\n const rawCw = payload.context_window\n const contextWindow =\n typeof rawCw === \"number\" && rawCw > 0 ? Math.trunc(rawCw) : 0\n\n const state = createTurnState(turnId, loopId, {\n model: optStr(payload.model),\n contextWindow,\n memoryRefs,\n })\n\n this.activeTurns.set(loopId, state)\n this.lastTurnIds.set(loopId, turnId)\n\n const turn = snapshot(state, this.nextSeq(), \"streaming\")\n this.latestTurns.set(loopId, turn)\n this.turnsById.set(turn.turn_id, turn)\n return [{ kind: \"upsert\", turn }]\n }\n\n private onModeChange(\n loopId: string,\n payload: Record<string, unknown>,\n ): ProjectionUpdate[] {\n const content: Record<string, string> = {}\n if (payload.from != null && payload.from !== \"\") content.from = String(payload.from)\n if (payload.to != null && payload.to !== \"\") content.to = String(payload.to)\n const turn = buildMarkerTurn(\n this.nextSeq(),\n this.nextTurnId(\"mode_change\"),\n loopId,\n \"mode_change\",\n content,\n )\n return [{ kind: \"upsert\", turn }]\n }\n\n private onPlanStatusUpdate(\n loopId: string,\n payload: Record<string, unknown>,\n ): ProjectionUpdate[] {\n let statuses = payload.statuses\n if (typeof statuses !== \"object\" || statuses === null) {\n statuses = payload._statuses ?? {}\n }\n const turn = buildMarkerTurn(\n this.nextSeq(),\n this.nextTurnId(\"plan_status\"),\n loopId,\n \"plan_status\",\n { plan_yaml: payload.plan_yaml ?? \"\", statuses },\n )\n return [{ kind: \"upsert\", turn }]\n }\n\n private onWorkspaceChanged(\n loopId: string,\n payload: Record<string, unknown>,\n ): ProjectionUpdate[] {\n const updates: ProjectionUpdate[] = [\n {\n kind: \"workspace_changed\",\n loopId,\n toolCallId: optStr(payload.tool_call_id) ?? undefined,\n toolName: toolNameFromPayload(payload) ?? undefined,\n workspacePath: isRecord(payload.workspace_change)\n ? optStr(payload.workspace_change.to) ?? undefined\n : undefined,\n },\n ]\n const change = payload.workspace_change\n if (isRecord(change)) {\n const source = optStr(change.source) ?? \"\"\n const projectName = optStr(change.project_name) ?? \"\"\n const fromPath = optStr(change.from) ?? \"\"\n const toPath = optStr(change.to) ?? \"\"\n const filesCopied =\n typeof change.files_copied === \"number\" ? change.files_copied : 0\n updates.unshift({\n kind: \"upsert\",\n turn: buildSystemNotificationTurn(\n this.nextSeq(),\n this.nextTurnId(\"workspace_change\"),\n loopId,\n \"workspace_change\",\n \"done\",\n source === \"cli:blade\" && projectName\n ? `项目「${projectName}」已创建`\n : \"工作目录已切换\",\n source === \"cli:blade\" && projectName\n ? `${filesCopied > 0 ? `已复制 ${filesCopied} 项当前文件。` : \"已原地使用当前文件夹。\"} 后续工作将在 ${toPath} 进行。`\n : `工作目录已从 ${fromPath} 切换到 ${toPath}。后续工作将在新目录进行。`,\n { ...change },\n ),\n })\n }\n const state = this.activeTurns.get(loopId)\n if (state) {\n const turn = snapshot(state, this.nextSeq(), \"streaming\")\n this.latestTurns.set(loopId, turn)\n this.lastTurnIds.set(loopId, turn.turn_id)\n updates.push({ kind: \"upsert\", turn })\n }\n return updates\n }\n\n private onAgentStart(\n loopId: string,\n payload: Record<string, unknown>,\n ): ProjectionUpdate[] {\n const description = optStr(payload.description)\n if (description) this.loopDescriptions.set(loopId, description)\n const subagentStartedAt = optStr(payload.started_at)\n if (subagentStartedAt) {\n this.activeSubagentRuns.set(loopId, {\n runId: optStr(payload.run_id) ?? loopId,\n startedAt: subagentStartedAt,\n })\n }\n const turn = buildSystemNotificationTurn(\n this.nextSeq(),\n this.nextTurnId(\"agent:start\"),\n loopId,\n \"agent:start\",\n \"running\",\n `Agent: ${payload.description ?? payload.skill_id ?? \"agent\"}`,\n optStr(payload.prompt),\n {\n skill_id: optStr(payload.skill_id),\n description: optStr(payload.description),\n parent_fork_tool_call_id: optStr(payload.parent_fork_tool_call_id),\n },\n )\n return [{ kind: \"upsert\", turn }]\n }\n\n private onBgStarted(\n loopId: string,\n payload: Record<string, unknown>,\n ): ProjectionUpdate[] {\n const taskId = optStr(payload.task_id) ?? \"\"\n const command = optStr(payload.command)\n const description = optStr(payload.description)\n const turn = buildSystemNotificationTurn(\n this.nextSeq(),\n this.nextTurnId(\"bg:started\"),\n loopId,\n \"bg:started\",\n \"running\",\n description ?? `Background: ${taskId || \"task\"}`,\n command,\n { task_id: taskId, command, description },\n )\n return [{ kind: \"upsert\", turn }]\n }\n\n private onBgTasksCompleted(\n loopId: string,\n payload: Record<string, unknown>,\n ): ProjectionUpdate[] {\n const taskIds = Array.isArray(payload.task_ids) ? payload.task_ids : []\n const count = typeof payload.count === \"number\" ? payload.count : taskIds.length\n const detail = taskIds.map(String).join(\", \")\n const turn = buildSystemNotificationTurn(\n this.nextSeq(),\n this.nextTurnId(\"bg:tasks_completed\"),\n loopId,\n \"bg:tasks_completed\",\n \"done\",\n `Background tasks completed (${count})`,\n detail || null,\n { task_ids: taskIds, count },\n )\n return [{ kind: \"upsert\", turn }]\n }\n\n private onAskUserAnswer(\n loopId: string,\n payload: Record<string, unknown>,\n ): ProjectionUpdate[] {\n const toolCallId = String(payload.tool_call_id ?? \"\")\n const pending = this.pendingChildPauses.get(toolCallId)\n const parentLoopId = pending?.parentLoopName\n\n // clear child pause\n if (pending) {\n this.pendingChildPauses.delete(toolCallId)\n const childTurn =\n this.activeTurns.get(pending.childLoopName) ??\n this.latestTurns.get(pending.childLoopName)\n setToolCallStatus(childTurn, pending.childToolCallId, \"done\", null, null)\n const parentTurn =\n this.activeTurns.get(pending.parentLoopName) ??\n this.latestTurns.get(pending.parentLoopName)\n setToolCallStatus(parentTurn, pending.parentToolCallId, \"done\", null, null)\n }\n\n // clear direct ask-user pause\n const directTurn = this.activeTurns.get(loopId) ?? this.latestTurns.get(loopId)\n setToolCallStatus(directTurn, toolCallId, \"done\", null, null)\n\n const updates = this.collectLoopUpdates(loopId, parentLoopId)\n const entryId = typeof payload.entry_id === \"string\" ? payload.entry_id : \"\"\n if (!entryId) return updates\n const answerData = isRecord(payload.answer_data) ? payload.answer_data : {}\n const answerTurn: TurnProjection = {\n id: entryId,\n sequence: this.nextSeq(),\n turn_id: entryId,\n loop_id: loopId,\n kind: \"message\",\n role: \"assistant\",\n status: \"completed\",\n blocks: [\n {\n type: \"ask_user_answer\",\n content: answerData,\n tool_call_id: toolCallId || null,\n },\n ],\n tool_calls: [],\n model: null,\n usage: null,\n duration_ms: 0,\n client_request_id:\n typeof payload.client_request_id === \"string\" ? payload.client_request_id : null,\n }\n return [...updates, { kind: \"upsert\", turn: answerTurn }]\n }\n\n private onUserMessage(\n _loopId: string,\n payload: Record<string, unknown>,\n ): ProjectionUpdate[] {\n const entryId = String(payload.entry_id ?? this.nextTurnId(\"user\"))\n const displayContent = payload.display_content ?? payload.content ?? \"\"\n const turn: TurnProjection = {\n id: entryId,\n sequence: this.nextSeq(),\n turn_id: entryId,\n loop_id: \"root\",\n kind: \"message\",\n role: \"user\",\n status: \"completed\",\n blocks: [{ type: \"text\", content: displayContent }],\n tool_calls: [],\n model: null,\n usage: null,\n duration_ms: 0,\n client_request_id:\n typeof payload.client_request_id === \"string\" ? payload.client_request_id : null,\n }\n this.latestTurns.set(\"root\", turn)\n return [{ kind: \"upsert\", turn }]\n }\n\n private onPostChatFollowup(\n payload: Record<string, unknown>,\n ): ProjectionUpdate[] | null {\n const assistantEntryId = String(payload.assistant_entry_id ?? \"\")\n const latest = this.latestTurns.get(\"root\") as FollowupTurn | undefined\n if (\n !latest ||\n latest.role !== \"assistant\" ||\n latest.turn_id !== assistantEntryId\n ) {\n return null\n }\n\n const postChatFollowup = normalizePostChatFollowup(payload, assistantEntryId)\n if (!postChatFollowup) return null\n const turn: FollowupTurn = {\n ...latest,\n post_chat_followup: postChatFollowup,\n }\n this.latestTurns.set(\"root\", turn)\n return [{ kind: \"upsert\", turn }]\n }\n\n // --- Delta / streaming events ---\n\n private onDelta(\n state: TurnState,\n blockType: \"thinking\" | \"text\",\n _toolCallId: string,\n content: string,\n ): ProjectionUpdate[] | null {\n if (!content) return null\n appendTextBlock(state, blockType, content)\n return this.syncPatch(state)\n }\n\n private onToolCallCreated(\n state: TurnState,\n payload: Record<string, unknown>,\n ): ProjectionUpdate[] | null {\n // Compatibility with servers that used created for argument fragments.\n if (\"arguments_delta\" in payload) {\n return this.onToolCallArgumentsDelta(state, payload)\n }\n const toolCallId = String(payload.id ?? \"\")\n const toolName = toolNameFromPayload(payload)\n const displayName = String(payload.display_name ?? \"\") || this.displayNameResolver(toolName)\n const args = toolArgsFromPayload(payload)\n upsertToolCall(state, toolCallId, toolName, displayName, args)\n return this.syncPatch(state)\n }\n\n private onToolCallArgumentsDelta(\n state: TurnState,\n payload: Record<string, unknown>,\n ): ProjectionUpdate[] | null {\n const delta = String(payload.arguments_delta ?? \"\")\n const toolCallId = String(payload.id ?? \"\")\n if (!delta || !toolCallId) return null\n appendToolCallArguments(state, toolCallId, delta)\n return this.syncPatch(state)\n }\n\n private onResponseDone(\n state: TurnState,\n loopId: string,\n payload: Record<string, unknown>,\n ): ProjectionUpdate[] | null {\n state.responseDone = true\n this.applyStreamTiming(state, payload)\n const model = optStr(payload.model)\n if (model) state.model = model\n if (typeof payload.usage === \"object\" && payload.usage !== null) {\n state.usage = { ...(payload.usage as Record<string, unknown>) }\n }\n // apply tool calls from full response\n const toolCalls = payload.tool_calls\n if (Array.isArray(toolCalls)) {\n for (const raw of toolCalls) {\n if (typeof raw !== \"object\" || raw === null) continue\n const tc = raw as Record<string, unknown>\n const fn = (tc.function ?? {}) as Record<string, unknown>\n const toolName = String(fn.name ?? \"\")\n const displayName =\n String(tc.display_name ?? \"\") || this.displayNameResolver(toolName)\n upsertToolCall(\n state,\n String(tc.id ?? \"\"),\n toolName,\n displayName,\n String(fn.arguments ?? \"\"),\n )\n }\n }\n\n if (!applyResponseBlockOrder(state, payload.response_blocks) && \"content\" in payload) {\n replaceTextContent(state, completedResponseText(payload.content))\n }\n\n const isNativeProviderResponse = typeof payload.provider === \"string\" && payload.provider !== \"\"\n if (\n state.toolCalls.length === 0 ||\n (isNativeProviderResponse &&\n state.toolCalls.every(\n (toolCall) => toolCall.status !== \"pending\" && toolCall.status !== \"awaiting_answer\",\n ))\n ) {\n return this.finalize(loopId, \"completed\")\n }\n return this.syncPatch(state)\n }\n\n private applyFirstTokenDelivery(\n state: TurnState,\n payload: Record<string, unknown>,\n ): void {\n const firstTokenMs = payload.first_token_ms\n if (state.firstTokenMs === null && typeof firstTokenMs === \"number\" && firstTokenMs >= 0) {\n state.firstTokenMs = Math.round(firstTokenMs)\n }\n const duration = payload.first_token_delivery_ms\n if (state.firstTokenDeliveryMs === null && typeof duration === \"number\" && duration >= 0) {\n state.firstTokenDeliveryMs = duration\n }\n }\n\n private applyStreamTiming(\n state: TurnState,\n payload: Record<string, unknown>,\n ): void {\n if (typeof payload.first_token_ms === \"number\" && payload.first_token_ms >= 0) {\n state.firstTokenMs = Math.round(payload.first_token_ms)\n }\n if (\n typeof payload.stream_duration_ms === \"number\" &&\n payload.stream_duration_ms >= 0\n ) {\n state.streamDurationMs = Math.round(payload.stream_duration_ms)\n }\n // 只有生产者上报的真实请求区间才写进投影;缺失时保持 null(#2581 A1/I1)。\n if (typeof payload.started_at === \"string\" && payload.started_at) {\n state.modelStartedAt = payload.started_at\n state.modelStartedAtReported = true\n }\n if (typeof payload.duration_ms === \"number\" && payload.duration_ms >= 0) {\n state.modelDurationMs = Math.round(payload.duration_ms)\n }\n }\n\n private onToolResultDone(\n state: TurnState,\n loopId: string,\n payload: Record<string, unknown>,\n ): ProjectionUpdate[] | null {\n const toolCallId = String(payload.tool_call_id ?? \"\")\n const streamedResult = state.toolCalls.find((toolCall) => toolCall.id === toolCallId)?.result\n const content =\n payload.content_from_deltas === true ? (streamedResult ?? \"\") : payload.content ?? \"\"\n const status = toolStatusFromResult(content)\n const rawDuration = payload.duration_ms\n const durationMs =\n typeof rawDuration === \"number\" && rawDuration >= 0\n ? Math.round(rawDuration)\n : null\n const ranInParallel =\n typeof payload.ran_in_parallel === \"boolean\" ? payload.ran_in_parallel : null\n\n const sl = sourceLoopFor(state.loopId, this.loopDescriptions)\n const startedAt = typeof payload.started_at === \"string\" && payload.started_at ? payload.started_at : null\n applyToolResult(state, toolCallId, content, status, durationMs, ranInParallel, sl, startedAt)\n\n // Native providers may emit a completed tool item before the final text\n // item of the same turn. Their explicit llm:response:done is the terminal\n // event; finalizing here would drop the following content delta.\n const isNativeProviderResult = typeof payload.provider === \"string\" && payload.provider !== \"\"\n if (!isNativeProviderResult && this.shouldFinalizeAfterToolResults(state)) {\n return this.finalize(loopId, \"completed\")\n }\n return this.syncPatch(state)\n }\n\n private onToolResultDelta(\n state: TurnState,\n payload: Record<string, unknown>,\n ): ProjectionUpdate[] | null {\n appendToolResultDelta(\n state,\n String(payload.tool_call_id ?? \"\"),\n String(payload.content ?? \"\"),\n payload.content_reset === true,\n )\n return this.syncPatch(state)\n }\n\n private onToolUi(\n state: TurnState,\n payload: Record<string, unknown>,\n ): ProjectionUpdate[] | null {\n const toolCallId = String(payload.tool_call_id ?? \"\")\n const ui = payload.ui\n if (toolCallId && typeof ui === \"object\" && ui !== null) {\n state.blocks.push({\n type: \"tool_ui\",\n content: ui,\n tool_call_id: toolCallId,\n })\n }\n return this.syncPatch(state)\n }\n\n private onToolBridge(\n state: TurnState,\n payload: Record<string, unknown>,\n ): ProjectionUpdate[] | null {\n const bridge = payload.bridge\n if (typeof bridge !== \"object\" || bridge === null) return null\n const toolCallId = String(payload.tool_call_id ?? \"\")\n // A command without an owning tool call is still delivered by\n // AgentSession from the raw event, but it has no chat display projection.\n if (!toolCallId || !state.toolCalls.some((toolCall) => toolCall.id === toolCallId)) return null\n state.blocks.push({\n type: \"tool_bridge\",\n content: bridge,\n delivery_id: String(payload.delivery_id ?? \"\") || null,\n tool_call_id: toolCallId,\n })\n return this.syncPatch(state)\n }\n\n private onToolApprovalRequired(\n state: TurnState,\n payload: Record<string, unknown>,\n ): ProjectionUpdate[] | null {\n const toolCallId = String(payload.tool_call_id ?? \"\")\n const toolName = String(payload.tool_name ?? \"\")\n const displayName = this.displayNameResolver(toolName)\n upsertToolCall(state, toolCallId, toolName, displayName, \"\")\n const relatedToolCallId = String(payload.related_tool_call_id ?? \"\")\n if (relatedToolCallId && relatedToolCallId !== toolCallId) {\n const related = state.toolCalls.find((toolCall) => toolCall.id === relatedToolCallId)\n if (related) related.status = \"awaiting_answer\"\n }\n return this.syncPatch(state)\n }\n\n private onChildPause(\n state: TurnState,\n loopId: string,\n payload: Record<string, unknown>,\n ): ProjectionUpdate[] | null {\n const pauseToolData = payload.pause_tool_data\n if (typeof pauseToolData !== \"object\" || pauseToolData === null)\n return this.syncPatch(state)\n\n const ptd = pauseToolData as Record<string, unknown>\n const sourceLoop = ptd.source_loop as Record<string, unknown> | undefined\n if (typeof sourceLoop === \"object\" && sourceLoop) {\n const slName = String(sourceLoop.name ?? \"\")\n const slDesc = optStr(sourceLoop.description)\n if (slName && slDesc) this.loopDescriptions.set(slName, slDesc)\n }\n\n const { childLoopName, childToolCallId, description } =\n normalizeChildPause(payload as Record<string, unknown>)\n\n if (!childToolCallId) return this.syncPatch(state)\n\n const existing = this.pendingChildPauses.get(childToolCallId)\n const parentLoopName = String(\n payload.parent_loop_name ?? existing?.parentLoopName ?? \"root\",\n )\n const parentToolCallId = String(\n payload.parent_fork_tool_call_id ?? existing?.parentToolCallId ?? \"\",\n )\n const resolvedChildLoopName =\n String(payload.child_loop_name ?? \"\") || existing?.childLoopName || childLoopName || loopId\n\n this.pendingChildPauses.set(childToolCallId, {\n parentLoopName,\n parentToolCallId,\n childLoopName: resolvedChildLoopName,\n childToolCallId,\n description: description || existing?.description || \"\",\n })\n\n // apply to child\n applyAskUserPauseToTurn(\n state,\n ptd,\n childToolCallId,\n resolvedChildLoopName,\n this.pendingChildPauses.get(childToolCallId)!.description,\n this.displayNameResolver,\n )\n\n // apply to parent\n const parentTurn =\n this.activeTurns.get(parentLoopName) ?? this.latestTurns.get(parentLoopName)\n if (parentTurn) {\n applyChildPauseToParent(\n parentTurn,\n parentToolCallId,\n resolvedChildLoopName,\n childToolCallId,\n this.pendingChildPauses.get(childToolCallId)!.description,\n this.displayNameResolver,\n )\n }\n\n return this.collectLoopUpdates(loopId, parentLoopName)\n }\n\n private onChatEnd(\n state: TurnState,\n loopId: string,\n payload: Record<string, unknown>,\n ): ProjectionUpdate[] | null {\n const status = String(payload.status ?? \"completed\")\n\n const pauseToolData = payload.pause_tool_data\n if (typeof pauseToolData === \"object\" && pauseToolData !== null) {\n const ptd = pauseToolData as Record<string, unknown>\n const pauseToolName = String(ptd.name ?? \"\")\n const normalized = pauseToolName.includes(\":\")\n ? pauseToolName.split(\":\").pop()!\n : pauseToolName\n const sourceLoop = ptd.source_loop as Record<string, unknown> | undefined\n\n if (typeof sourceLoop === \"object\" && sourceLoop) {\n const slName = String(sourceLoop.name ?? \"\")\n const slDesc = optStr(sourceLoop.description)\n if (slName && slDesc) this.loopDescriptions.set(slName, slDesc)\n\n if (status === \"paused\" && slName) {\n applyChildPauseToParent(\n state,\n String(ptd.parent_fork_tool_call_id ?? \"\"),\n slName,\n String(ptd.tool_call_id ?? \"\"),\n slDesc ?? \"\",\n this.displayNameResolver,\n )\n\n const childTurn = this.activeTurns.get(slName)\n if (childTurn) {\n applyAskUserPauseToTurn(\n childTurn,\n ptd,\n String(ptd.tool_call_id ?? \"\"),\n slName,\n slDesc ?? \"\",\n this.displayNameResolver,\n )\n }\n }\n } else if (status === \"paused\" && normalized === \"AskUserQuestion\") {\n applyAskUserPauseToTurn(\n state,\n ptd,\n String(ptd.tool_call_id ?? \"\"),\n \"\",\n \"\",\n this.displayNameResolver,\n )\n }\n }\n\n const finalStatus = (\n { completed: \"completed\", paused: \"paused\", failed: \"failed\", interrupted: \"interrupted\" } as Record<string, TurnProjection[\"status\"]>\n )[status]\n\n if (!finalStatus) return null\n if (finalStatus === \"failed\") this.dropIncompleteToolCalls(state)\n if (!this.activeTurns.has(loopId)) {\n this.pendingMemoryRefs.delete(loopId)\n }\n return this.finalize(loopId, finalStatus)\n }\n\n private onAgentEnd(\n state: TurnState | null,\n loopId: string,\n payload: Record<string, unknown>,\n ): ProjectionUpdate[] | null {\n const ok = payload.ok !== false\n this.settleSubagentRun(loopId, payload)\n const status = ok ? \"done\" : \"error\"\n const title = `Agent: ${payload.description ?? payload.skill_id ?? \"agent\"}`\n const detail = optStr(payload.error)\n const metadata = {\n skill_id: optStr(payload.skill_id),\n description: optStr(payload.description),\n parent_fork_tool_call_id: optStr(payload.parent_fork_tool_call_id),\n ok,\n }\n if (state) {\n if (!ok) this.dropIncompleteToolCalls(state)\n state.blocks.push(buildSystemNotificationBlock(\"agent:end\", status, title, detail, metadata))\n return this.finalize(loopId, ok ? \"completed\" : \"failed\")\n }\n const turn = buildSystemNotificationTurn(\n this.nextSeq(), this.nextTurnId(\"agent:end\"), loopId, \"agent:end\", status, title, detail, metadata,\n )\n return [{ kind: \"upsert\", turn }]\n }\n\n private settleSubagentRun(\n loopId: string,\n payload: Record<string, unknown>,\n ): void {\n const active = this.activeSubagentRuns.get(loopId)\n this.activeSubagentRuns.delete(loopId)\n const parentToolCallId = optStr(payload.parent_fork_tool_call_id)\n if (!parentToolCallId) return\n const rawDuration = payload.run_duration_ms\n const durationMs =\n typeof rawDuration === \"number\" && rawDuration >= 0 ? Math.round(rawDuration) : null\n const rawStatus = optStr(payload.run_status)\n const status: RunTiming[\"status\"] =\n rawStatus === \"failed\" ||\n rawStatus === \"cancelled\" ||\n rawStatus === \"paused\" ||\n rawStatus === \"incomplete\"\n ? rawStatus\n : payload.ok === false\n ? \"failed\"\n : \"completed\"\n const run: RunTiming = {\n run_id: active?.runId ?? optStr(payload.run_id) ?? loopId,\n scope: \"subagent\",\n loop_id: loopId,\n started_at: active?.startedAt ?? optStr(payload.run_started_at),\n duration_ms: durationMs,\n status,\n }\n const seen = new Set<TurnProjection>()\n for (const turn of [...this.latestTurns.values(), ...this.turnsById.values()]) {\n if (seen.has(turn)) continue\n seen.add(turn)\n const toolCall = turn.tool_calls.find((item) => item.id === parentToolCallId)\n if (!toolCall) continue\n toolCall.subagent_runs = [...(toolCall.subagent_runs ?? []), run]\n }\n }\n\n private dropIncompleteToolCalls(state: TurnState): void {\n if (state.responseDone) return\n state.toolCalls = []\n state.blocks = state.blocks.filter((block) => block.type !== \"tool_use\")\n }\n\n private onCompaction(\n eventType: string,\n loopId: string,\n payload: Record<string, unknown>,\n ): ProjectionUpdate[] | null {\n const compactionId = String(payload.compaction_id ?? \"\")\n if (!compactionId) return null\n\n let current = {\n ...(this.activeCompactions.get(compactionId) ?? {}),\n ...payload,\n loop_id: loopId,\n }\n\n let status: TurnProjection[\"status\"]\n switch (eventType) {\n case \"compaction:start\":\n status = \"streaming\"\n this.activeCompactions.set(compactionId, current)\n this.failedCompactions.delete(compactionId)\n break\n case \"compaction:end\":\n status = \"completed\"\n this.activeCompactions.delete(compactionId)\n break\n case \"compaction:abort\":\n status = \"interrupted\"\n this.activeCompactions.delete(compactionId)\n break\n case \"compaction:error\":\n status = \"failed\"\n this.activeCompactions.delete(compactionId)\n this.failedCompactions.set(compactionId, { ...current })\n break\n default:\n status = \"streaming\"\n this.activeCompactions.set(compactionId, current)\n }\n\n // 降级为截断时 compaction:error 后面紧跟着 compaction:end,若让 end 覆盖,\n // 用户就再也看不到这次整理失败过。failed 是终态:同一个 compaction_id 一旦\n // 失败就保持失败,下一轮压缩是新的 compaction_id,不受影响。\n const failed = this.failedCompactions.get(compactionId)\n if (failed && status !== \"failed\") {\n current = { ...failed, ...current }\n status = \"failed\"\n }\n\n const turn = buildCompactionTurn(this.nextSeq(), compactionId, loopId, status, current)\n return [{ kind: \"upsert\", turn }]\n }\n\n // --- Internal helpers ---\n\n private syncPatch(state: TurnState): ProjectionUpdate[] {\n const turn = snapshot(state, this.nextSeq(), \"streaming\")\n this.latestTurns.set(state.loopId, turn)\n this.turnsById.set(turn.turn_id, turn)\n this.lastTurnIds.set(state.loopId, turn.turn_id)\n return [{ kind: \"upsert\", turn }]\n }\n\n private finalize(\n loopId: string,\n status: TurnProjection[\"status\"],\n ): ProjectionUpdate[] | null {\n const state = this.activeTurns.get(loopId)\n if (!state) return null\n this.activeTurns.delete(loopId)\n const turn = snapshot(state, this.nextSeq(), status)\n this.lastTurnIds.set(loopId, turn.turn_id)\n this.latestTurns.set(loopId, turn)\n this.turnsById.set(turn.turn_id, turn)\n return [{ kind: \"upsert\", turn }]\n }\n\n private shouldFinalizeAfterToolResults(state: TurnState): boolean {\n if (state.toolCalls.length === 0) return true\n if (state.toolCalls.some((tc) => tc.status === \"pending\")) return false\n return !state.toolCalls.some((tc) => {\n const normalized = tc.tool_name.includes(\":\")\n ? tc.tool_name.split(\":\").pop()!\n : tc.tool_name\n return PAUSE_TOOL_NAMES.has(normalized)\n })\n }\n\n private collectLoopUpdates(\n ...loopIds: (string | undefined | null)[]\n ): ProjectionUpdate[] {\n const updates: ProjectionUpdate[] = []\n for (const loopId of loopIds) {\n if (!loopId) continue\n const state = this.activeTurns.get(loopId)\n if (state) {\n updates.push(...this.syncPatch(state))\n continue\n }\n const proj = this.latestTurns.get(loopId)\n if (proj) {\n const updated = { ...proj, sequence: this.nextSeq() }\n this.latestTurns.set(loopId, updated)\n updates.push({ kind: \"upsert\", turn: updated })\n }\n }\n return updates\n }\n\n private nextSeq(): number {\n return ++this.seq\n }\n\n private nextTurnId(prefix: string): string {\n this.syntheticCounter++\n const hex = Math.random().toString(16).slice(2, 10)\n return `${prefix}:${this.syntheticCounter}:${hex}`\n }\n}\n\n// --- Utility functions ---\n\nfunction optStr(value: unknown): string | null {\n if (value == null || value === \"\") return null\n return String(value)\n}\n\nfunction toolNameFromPayload(payload: Record<string, unknown>): string {\n const fn = payload.function\n if (typeof fn === \"object\" && fn !== null) {\n return String((fn as Record<string, unknown>).name ?? \"\")\n }\n return String(payload.tool_name ?? \"\")\n}\n\nfunction toolArgsFromPayload(payload: Record<string, unknown>): string {\n const fn = payload.function\n if (typeof fn === \"object\" && fn !== null) {\n return String((fn as Record<string, unknown>).arguments ?? \"\")\n }\n return \"\"\n}\n","import type {\n ContentBlock,\n RunTiming,\n ToolCallProjection,\n TurnProjection,\n} from \"../../schemas/projection\"\nimport { inferToolStatus } from \"../../schemas/message\"\nimport { buildContextTurn } from \"./context\"\nimport { isRecord } from \"../type-guards\"\nimport {\n applyAskUserPauseToTurn,\n applyChildPauseToParent,\n buildCompactionTurn,\n buildSystemNotificationTurn,\n normalizePostChatFollowup,\n setToolCallStatus,\n} from \"./helpers\"\n\nexport interface RawHistoryEntry {\n id?: string\n kind?: string\n loop_name?: string\n message?: Record<string, unknown>\n source?: Record<string, unknown>\n data?: Record<string, unknown>\n timestamp?: string\n [key: string]: unknown\n}\n\ntype FollowupTurn = TurnProjection\n\n/** Rebuild completed UI turns from raw persisted history entries. */\nexport function projectHistory(entries: RawHistoryEntry[]): TurnProjection[] {\n const turns: TurnProjection[] = []\n const toolOwners = new Map<string, TurnProjection>()\n const latestAssistantByLoop = new Map<string, TurnProjection>()\n const pendingChildPauses = new Map<\n string,\n { childLoopId: string; parentLoopId: string; parentToolCallId: string }\n >()\n const answeredToolCallIds = new Set<string>()\n // Native daemon providers persist their tool item and final assistant text\n // as separate history entries. Keep track of those tool-item turns so the\n // refresh projection can restore the same assistant turn shown by the live\n // event stream.\n const nativeToolTurns = new Set<TurnProjection>()\n const turnEntryAliases = new Map<string, TurnProjection>()\n let latestRootMessage: FollowupTurn | null = null\n // root loop 最后一条 assistant turn,用于收尾时恢复未作答的提问。\n // 用户发言会清空它:此时提问已经被文字回复带过去了,不该再变回可作答。\n let latestRootAssistant: TurnProjection | null = null\n let sequence = 0\n\n for (const entry of entries) {\n const kind = String(entry.kind ?? \"\")\n const loopId = String(entry.loop_name ?? \"root\")\n const id = String(entry.id ?? `history-${sequence + 1}`)\n if (kind === \"turn_timing\" && isRecord(entry.data)) {\n const turnId = typeof entry.data.turn_id === \"string\" ? entry.data.turn_id : \"\"\n const duration = numberOrNull(entry.data.first_token_delivery_ms)\n const target = turnEntryAliases.get(turnId)\n if (target && duration !== null) target.first_token_delivery_ms = duration\n continue\n }\n if (kind === \"run_timing\" && isRecord(entry.data)) {\n const data = entry.data\n // 子运行区间挂在父工具调用上,仅作外层展示;用户轮区间只供统计折叠使用。\n if (data.scope === \"subagent\") {\n const parentToolCallId = String(data.parent_fork_tool_call_id ?? \"\")\n const duration = numberOrNull(data.duration_ms)\n const rawStatus = String(data.status ?? \"completed\")\n const status: RunTiming[\"status\"] =\n rawStatus === \"failed\" ||\n rawStatus === \"cancelled\" ||\n rawStatus === \"paused\" ||\n rawStatus === \"incomplete\"\n ? rawStatus\n : \"completed\"\n for (const turn of turns) {\n const toolCall = turn.tool_calls.find((item) => item.id === parentToolCallId)\n if (!toolCall) continue\n toolCall.subagent_runs = [\n ...(toolCall.subagent_runs ?? []),\n {\n run_id: String(data.run_id ?? \"\"),\n scope: \"subagent\",\n loop_id: loopId,\n started_at:\n typeof data.started_at === \"string\" ? data.started_at : null,\n duration_ms: duration,\n status,\n },\n ]\n break\n }\n }\n continue\n }\n if (kind === \"post_chat_followup\" && isRecord(entry.data)) {\n const assistantEntryId = String(entry.data.assistant_entry_id ?? \"\")\n if (\n latestRootMessage?.role === \"assistant\" &&\n latestRootMessage.turn_id === assistantEntryId\n ) {\n const followup = normalizePostChatFollowup(entry.data, assistantEntryId)\n if (followup) latestRootMessage.post_chat_followup = followup\n }\n continue\n }\n if (kind === \"context\") {\n const turn = buildContextTurn(entry, sequence + 1)\n if (turn) {\n sequence += 1\n turns.push(turn)\n }\n continue\n }\n if (kind === \"message\" && isRecord(entry.message)) {\n const message = entry.message\n const role = String(message.role ?? \"\")\n if (role === \"tool\") {\n const toolCallId = String(message.tool_call_id ?? \"\")\n const owner = toolOwners.get(toolCallId)\n const toolCall = owner?.tool_calls.find((item) => item.id === toolCallId)\n if (owner && toolCall) {\n toolCall.status = message._error\n ? \"error\"\n : inferToolStatus(String(message.content ?? \"\"))\n toolCall.result = message.content ?? \"\"\n const duration = numberOrNull(message._duration_ms)\n if (duration !== null) toolCall.duration_ms = duration\n if (typeof message._started_at === \"string\") {\n toolCall.started_at = message._started_at\n }\n if (message._ran_in_parallel === true) toolCall.ran_in_parallel = true\n owner.blocks.push({\n type: \"tool_result\",\n content: message.content ?? \"\",\n tool_call_id: toolCallId,\n })\n }\n continue\n }\n if (role !== \"user\" && role !== \"assistant\" && role !== \"system\") continue\n\n // _error 只属于 LLM 断流时保存的部分 assistant 消息,里面的\n // canonical tool_calls 可能仍是半截参数。和 live chat:end failed\n // 保持一致,不把它们恢复成待执行工具;正文、reasoning 和耗时仍保留。\n const toolCalls = role === \"assistant\" && !message._error\n ? buildToolCalls(message.tool_calls)\n : []\n const blocks = buildBlocks(message, toolCalls)\n const turn: FollowupTurn = {\n id,\n sequence: ++sequence,\n turn_id: id,\n loop_id: loopId,\n kind: \"message\",\n role,\n status: message._error\n ? \"failed\"\n : message._interrupted\n ? \"interrupted\"\n : \"completed\",\n blocks,\n tool_calls: toolCalls,\n model: stringOrNull(message.model),\n usage: isRecord(message._usage) ? { ...message._usage } : null,\n // 模型请求区间来自持久化字段;旧会话缺失时为 null,不用落盘时刻冒充(#2581 A1)。\n duration_ms: numberOrNull(message._duration_ms),\n first_token_ms: numberOrNull(message._first_token_ms),\n stream_duration_ms: numberOrNull(message._stream_duration_ms),\n started_at:\n typeof message._started_at === \"string\"\n ? message._started_at\n : typeof entry.timestamp === \"string\"\n ? entry.timestamp\n : undefined,\n has_reported_timing: typeof message._started_at === \"string\",\n // fork 子会话的父锚点:历史里落在消息级 _parent_fork_tool_call_id。丢掉它,\n // 刷新后工作流步骤 fork 就配不回 workflow:run 工具调用(普通 Agent fork 有\n // root Agent 工具调用兜底配对,工作流 fork 没有,子智能体卡会整体消失)。\n parent_fork_tool_call_id: stringOrNull(message._parent_fork_tool_call_id),\n }\n\n const isNativeToolEntry =\n role === \"assistant\" &&\n Array.isArray(message.tool_calls) &&\n message.tool_calls.some(\n (toolCall) => isRecord(toolCall) && typeof toolCall.provider === \"string\",\n )\n const previousTurn = turns[turns.length - 1]\n if (\n role === \"assistant\" &&\n previousTurn?.role === \"assistant\" &&\n previousTurn.loop_id === loopId &&\n nativeToolTurns.has(previousTurn)\n ) {\n nativeToolTurns.delete(previousTurn)\n previousTurn.blocks.push(...turn.blocks)\n previousTurn.tool_calls.push(...turn.tool_calls)\n previousTurn.status = turn.status\n previousTurn.model = turn.model ?? previousTurn.model\n previousTurn.usage = turn.usage ?? previousTurn.usage\n // 与 Python 侧 build_turns_from_history 的折叠规则保持一致,否则流式与\n // 历史会给出不同的时长和起点。时长用「非空且非 0 才覆盖」,Python/Go 的\n // `or` 语义如此,`??` 会让一个已测量的 0ms 覆盖掉真实时长。\n if (turn.duration_ms) previousTurn.duration_ms = turn.duration_ms\n previousTurn.first_token_ms = turn.first_token_ms ?? previousTurn.first_token_ms\n previousTurn.stream_duration_ms =\n turn.stream_duration_ms ?? previousTurn.stream_duration_ms\n // 起点优先取生产者上报的真实值;先到的条目可能只有落盘回落。\n if (turn.has_reported_timing) {\n previousTurn.started_at = turn.started_at\n previousTurn.has_reported_timing = true\n } else if (!previousTurn.has_reported_timing) {\n previousTurn.started_at = previousTurn.started_at ?? turn.started_at\n }\n // A folded native turn is identified by its terminal persisted entry,\n // matching post-chat follow-up and feedback keys. Earlier entry IDs\n // stay private aliases for annotations such as turn timing.\n previousTurn.id = turn.id\n previousTurn.turn_id = turn.turn_id\n if (isNativeToolEntry) nativeToolTurns.add(previousTurn)\n turnEntryAliases.set(id, previousTurn)\n if (loopId === \"root\") latestRootMessage = previousTurn as FollowupTurn\n latestAssistantByLoop.set(loopId, previousTurn)\n continue\n }\n\n if (\n loopId === \"root\" &&\n (role === \"user\" || role === \"assistant\")\n ) {\n latestRootMessage = turn\n }\n turns.push(turn)\n turnEntryAliases.set(id, turn)\n if (isNativeToolEntry) nativeToolTurns.add(turn)\n if (role === \"assistant\") latestAssistantByLoop.set(loopId, turn)\n if (loopId === \"root\") {\n if (role === \"assistant\") latestRootAssistant = turn\n else if (role === \"user\") latestRootAssistant = null\n }\n for (const toolCall of toolCalls) toolOwners.set(toolCall.id, turn)\n continue\n }\n\n if (kind === \"tool_result\") {\n const data = entry.data ?? {}\n const toolCallId = String(data.tool_call_id ?? \"\")\n const owner = toolOwners.get(toolCallId) ?? findLatestAssistant(turns, loopId)\n if (owner && toolCallId) {\n const rawContent = data.content\n const content =\n typeof rawContent === \"string\"\n ? rawContent\n : Array.isArray(rawContent)\n ? rawContent\n : String(rawContent ?? \"\")\n const status = data.is_error === true\n ? \"error\"\n : inferToolStatus(typeof content === \"string\" ? content : JSON.stringify(content))\n setToolCallStatus(owner, toolCallId, status, content, null)\n if (!owner.blocks.some((block) => block.type === \"tool_result\" && block.tool_call_id === toolCallId)) {\n owner.blocks.push({ type: \"tool_result\", content, tool_call_id: toolCallId })\n }\n }\n continue\n }\n\n if (kind === \"mode_change\") {\n turns.push(markerTurn(id, ++sequence, loopId, \"mode_change\", entry.data ?? {}))\n } else if (kind === \"workspace_change\") {\n const change = isRecord(entry.data) ? entry.data : {}\n const source = stringOrNull(change.source) ?? \"\"\n const projectName = stringOrNull(change.project_name) ?? \"\"\n const fromPath = stringOrNull(change.from) ?? \"\"\n const toPath = stringOrNull(change.to) ?? \"\"\n const filesCopied =\n typeof change.files_copied === \"number\" ? change.files_copied : 0\n turns.push(\n buildSystemNotificationTurn(\n ++sequence,\n id,\n loopId,\n \"workspace_change\",\n \"done\",\n source === \"cli:blade\" && projectName\n ? `项目「${projectName}」已创建`\n : \"工作目录已切换\",\n source === \"cli:blade\" && projectName\n ? `${filesCopied > 0 ? `已复制 ${filesCopied} 项当前文件。` : \"已原地使用当前文件夹。\"} 后续工作将在 ${toPath} 进行。`\n : `工作目录已从 ${fromPath} 切换到 ${toPath}。后续工作将在新目录进行。`,\n { ...change },\n ),\n )\n } else if (kind === \"plan_status\") {\n const data = entry.data ?? {}\n turns.push(\n markerTurn(id, ++sequence, loopId, \"plan_status\", {\n plan_yaml: data.plan_yaml ?? \"\",\n statuses: data.statuses ?? data._statuses ?? {},\n }),\n )\n } else if (kind === \"tool_ui\" || kind === \"tool_bridge\") {\n const data = entry.data ?? {}\n const toolCallId = String(data.tool_call_id ?? \"\")\n // Standalone bridge commands have no display owner. They are restored\n // through the command log and must not be attached to an unrelated\n // latest assistant turn merely because it happens to be nearby.\n const owner = kind === \"tool_bridge\"\n ? (toolCallId ? toolOwners.get(toolCallId) : undefined)\n : toolOwners.get(toolCallId) ?? findLatestAssistant(turns, loopId)\n const rawContent = kind === \"tool_ui\" ? data.ui : data.bridge\n // History is a pure replay: archived HTML may be rendered again, but a\n // resource URI must never trigger a fresh MCP/resource fetch on refresh.\n const content = kind === \"tool_ui\" && isRecord(rawContent)\n ? { ...rawContent, archived: true }\n : rawContent\n if (owner && content !== undefined) {\n owner.blocks.push({\n type: kind,\n content,\n ...(kind === \"tool_bridge\" ? { delivery_id: id } : {}),\n tool_call_id: toolCallId || null,\n })\n }\n } else if (kind === \"compaction\" || kind === \"tool_result_archive\") {\n const data = entry.data ?? {}\n const compactionId = String(data.compaction_id ?? entry.id ?? `history-${sequence + 1}`)\n let content = isRecord(entry.message) ? entry.message.content : undefined\n if (kind === \"tool_result_archive\") {\n const archivedCount = Array.isArray(data.archived_files) ? data.archived_files.length : 0\n content = `<compaction-summary>\\n已归档 ${archivedCount} 个大型工具结果。\\n</compaction-summary>`\n }\n turns.push(\n buildCompactionTurn(++sequence, compactionId, loopId,\n data.status === \"failed\" ? \"failed\" : \"completed\", {\n ...data,\n content,\n }),\n )\n } else if (kind === \"child_pause\") {\n const data = entry.data ?? {}\n const sourceLoop = isRecord(data.source_loop) ? data.source_loop : {}\n const childLoopId = String(data.child_loop_name ?? sourceLoop.name ?? \"\")\n const childToolCallId = String(data.child_pause_tool_call_id ?? \"\")\n const parentToolCallId = String(data.parent_fork_tool_call_id ?? \"\")\n const pauseToolData = isRecord(data.pause_tool_data) ? data.pause_tool_data : {}\n const description = String(sourceLoop.description ?? \"\")\n applyAskUserPauseToTurn(\n latestAssistantByLoop.get(childLoopId),\n pauseToolData,\n childToolCallId,\n childLoopId,\n description,\n (name) => name,\n )\n applyChildPauseToParent(\n latestAssistantByLoop.get(loopId),\n parentToolCallId,\n childLoopId,\n childToolCallId,\n description,\n (name) => name,\n )\n if (childToolCallId) {\n pendingChildPauses.set(childToolCallId, {\n childLoopId,\n parentLoopId: loopId,\n parentToolCallId,\n })\n }\n } else if (kind === \"ask_user_answer\") {\n const data = entry.data ?? {}\n const toolCallId = String(data.tool_call_id ?? \"\")\n if (toolCallId) answeredToolCallIds.add(toolCallId)\n const pending = pendingChildPauses.get(toolCallId)\n if (pending) {\n setToolCallStatus(latestAssistantByLoop.get(pending.childLoopId), toolCallId, \"done\", null, null)\n setToolCallStatus(\n latestAssistantByLoop.get(pending.parentLoopId),\n pending.parentToolCallId,\n \"done\",\n null,\n null,\n )\n pendingChildPauses.delete(toolCallId)\n } else {\n setToolCallStatus(latestAssistantByLoop.get(loopId), toolCallId, \"done\", null, null)\n }\n turns.push(\n markerTurn(\n id,\n ++sequence,\n loopId,\n \"ask_user_answer\",\n data,\n toolCallId || null,\n ),\n )\n }\n }\n\n // AskUserQuestion 暂停时历史里会留下一条 tool 结果消息,重建时被 inferToolStatus 判成 done。\n // 未作答的提问必须还原成 awaiting_answer,否则卡片渲染成已作答、选项点不动。\n // 与后端 _history_dispatch.py 的 build_turns_from_history 收尾保持一致——两边算不出同一个\n // 结果时,流式刚置好的状态会在 chat:end 拉历史时被覆盖掉。\n const rootAssistant = latestRootAssistant\n if (rootAssistant) {\n for (const toolCall of rootAssistant.tool_calls) {\n if (answeredToolCallIds.has(toolCall.id)) continue\n if (toolCall.tool_name.split(\":\").pop() !== \"AskUserQuestion\") continue\n if (toolCall.status === \"error\" || toolCall.status === \"cancelled\") continue\n const pauseArguments = parseToolArguments(toolCall.arguments)\n if (typeof toolCall.result === \"string\") {\n const resultArguments = parseToolArguments(toolCall.result)\n if (Array.isArray(resultArguments.questions)) {\n pauseArguments.questions = resultArguments.questions\n }\n }\n applyAskUserPauseToTurn(\n rootAssistant,\n {\n name: toolCall.tool_name,\n tool_call_id: toolCall.id,\n arguments: pauseArguments,\n },\n toolCall.id,\n \"\",\n \"\",\n (name) => name,\n )\n }\n }\n\n return turns\n}\n\nfunction parseToolArguments(value: string): Record<string, unknown> {\n if (!value) return {}\n try {\n const parsed = JSON.parse(value)\n return isRecord(parsed) ? parsed : {}\n } catch {\n return {}\n }\n}\n\nfunction buildToolCalls(value: unknown): ToolCallProjection[] {\n if (!Array.isArray(value)) return []\n return value.filter(isRecord).map((raw) => {\n const fn = isRecord(raw.function) ? raw.function : {}\n const name = String(fn.name ?? \"\")\n return {\n id: String(raw.id ?? \"\"),\n tool_name: name,\n display_name: String(raw.display_name ?? name),\n arguments: typeof fn.arguments === \"string\" ? fn.arguments : JSON.stringify(fn.arguments ?? {}),\n status: \"running\",\n result: null,\n }\n })\n}\n\nfunction buildBlocks(\n message: Record<string, unknown>,\n toolCalls: ToolCallProjection[],\n): ContentBlock[] {\n // 平台注入的用户消息(如 Factory 项目初始化指引)会带 _display_content:\n // 完整指令给 LLM,用户只看展示文案。缺了这条会把内部提醒整段泄露到聊天区。\n const displayContent = message.role === \"user\" ? message._display_content : undefined\n const stored = message._blocks\n const blocks: ContentBlock[] = []\n const storedToolCallIds = new Set<string>()\n if (displayContent !== undefined) {\n blocks.push({ type: \"text\", content: displayContent })\n } else if (Array.isArray(stored)) {\n for (const raw of stored) {\n if (!isRecord(raw)) continue\n const type = String(raw.type ?? \"\")\n if (type === \"thinking\") blocks.push({ type, content: raw.thinking ?? raw.content ?? \"\" })\n if (type === \"text\") blocks.push({ type, content: raw.text ?? raw.content ?? \"\" })\n if (type === \"tool_call\") {\n const toolCallId = String(raw.id ?? \"\")\n const toolCall = toolCalls.find((candidate) => candidate.id === toolCallId)\n if (!toolCall) continue\n storedToolCallIds.add(toolCallId)\n blocks.push({\n type: \"tool_use\",\n content: toolCall.arguments,\n tool_call_id: toolCall.id,\n tool_name: toolCall.tool_name,\n display_name: toolCall.display_name,\n })\n }\n }\n } else if (message.content !== undefined && message.content !== \"\") {\n blocks.push({ type: \"text\", content: message.content })\n }\n for (const toolCall of toolCalls) {\n if (storedToolCallIds.has(toolCall.id)) continue\n blocks.push({\n type: \"tool_use\",\n content: toolCall.arguments,\n tool_call_id: toolCall.id,\n tool_name: toolCall.tool_name,\n display_name: toolCall.display_name,\n })\n }\n return blocks\n}\n\nfunction markerTurn(\n id: string,\n sequence: number,\n loopId: string,\n type: \"mode_change\" | \"plan_status\" | \"ask_user_answer\",\n content: Record<string, unknown>,\n toolCallId: string | null = null,\n): TurnProjection {\n return {\n id,\n sequence,\n turn_id: id,\n loop_id: loopId,\n kind: type as TurnProjection[\"kind\"],\n role: \"system\",\n status: \"completed\",\n blocks: [{ type, content, tool_call_id: toolCallId }],\n tool_calls: [],\n model: null,\n usage: null,\n duration_ms: 0,\n }\n}\n\nfunction stringOrNull(value: unknown): string | null {\n return typeof value === \"string\" ? value : null\n}\n\nfunction numberOrNull(value: unknown): number | null {\n return typeof value === \"number\" && value >= 0 ? value : null\n}\n\nfunction findLatestAssistant(\n turns: TurnProjection[],\n loopId: string,\n): TurnProjection | undefined {\n for (let index = turns.length - 1; index >= 0; index -= 1) {\n const turn = turns[index]\n if (turn?.role === \"assistant\" && turn.loop_id === loopId) return turn\n }\n return undefined\n}\n","import type { BackgroundTask, BackgroundTaskStopResult } from \"../schemas/background\"\nimport type { TurnProjection } from \"../schemas/projection\"\nimport type { McpAppArchive } from \"../schemas/mcp-app\"\nimport { DEFAULT_REPLAY_SPEED } from \"../schemas/session\"\nimport type {\n PublishedSolutionRef,\n ReplayPreview,\n ReplaySpeed,\n SessionDetail,\n SessionInfo,\n TemplateId,\n} from \"../schemas/session\"\nimport type {\n McpAppContextState,\n McpAppContextUpdate,\n} from \"../schemas/mcp-app\"\nimport type { Task } from \"../schemas/task\"\nimport type { BladeClient, UploadProgress } from \"../blade-client\"\nimport type { AgentSession } from \"../session/agent-session\"\nimport {\n SessionSetupError,\n type SessionDefinition,\n type SkillDefinition,\n type SolutionDefinition,\n} from \"../session/definition\"\nimport type { SessionProfile } from \"../types/sdk-profile\"\nimport { projectHistory, type RawHistoryEntry } from \"../shared/projection\"\n\nexport interface SessionPlugin {\n /** Technical ID: always used for paths, authorization, caching and calls. */\n name: string\n /** Business name declared by the package; null falls back to `name`. */\n display_name?: string | null\n /**\n * Opaque content token for the package-local icon, or null when the plugin\n * ships none. Pass it to `fetchSessionPluginIcon`; never used as a path.\n */\n icon?: string | null\n /** Whether BH lists this plugin for the current user; null means BH was unavailable. */\n installed: boolean | null\n /**\n * Configuration standing as the list could determine it without reading the\n * user's Home: `unchecked` means nobody has looked yet, never \"configured\".\n */\n config?: SessionPluginConfigSummary\n /** Persisted session choice, independent of preparation success. */\n active: boolean\n /** Previously prepared skills may remain after deselection. */\n projected: boolean\n projection_source?: string | null\n status: string\n reason?: string | null\n}\n\n/** Selection/preparation result; installed facts are obtained from the BH-backed list. */\nexport type SessionPluginActivation = Pick<SessionPlugin, \"name\" | \"active\" | \"status\" | \"reason\">\n\n/**\n * How a plugin's user configuration stands.\n *\n * `not_required` — the package ships no config schema, the plugin keeps its old\n * behaviour. `required` — a schema exists but the stored configuration is\n * missing or does not validate. `configured` — stored configuration validates.\n * `error` — the declaration itself is unusable.\n */\nexport type SessionPluginConfigStateName = \"not_required\" | \"required\" | \"configured\" | \"error\"\n\n/** List-level view: `unchecked` means nobody has read this user's file yet. */\nexport type SessionPluginConfigSummary =\n | SessionPluginConfigStateName\n | \"unchecked\"\n\nexport interface SessionPluginConfigError {\n /** JSON Pointer of the offending field. */\n path: string\n /** Value-free message; the platform never echoes submitted secrets. */\n message: string\n}\n\nexport interface SessionPluginConfigState {\n state: SessionPluginConfigStateName\n reason: string | null\n /** The package-declared JSON Schema (Draft 2020-12), or null. */\n schema: Record<string, unknown> | null\n /** Stored values with `writeOnly` properties removed. */\n values: Record<string, unknown>\n /** JSON Pointers of `writeOnly` properties that currently hold a value. */\n write_only: string[]\n /** Opaque revision for optimistic concurrency; null when nothing is stored. */\n revision: string | null\n errors: SessionPluginConfigError[]\n}\n\nexport interface SessionPluginConfigSet {\n /** JSON Pointer; arrays are replaced as a whole. */\n path: string\n value: unknown\n}\n\nexport interface SessionPluginConfigUpdate {\n /** Omit (or pass null) to publish unconditionally. */\n expected_revision?: string | null\n set?: SessionPluginConfigSet[]\n remove?: string[]\n}\n\nexport interface CreateSessionRequest {\n intent?: string\n template_id?: TemplateId\n /** 正式 Solution 来源。Hub 使用 { source: \"hub\", org, name }。 */\n solution_ref?: PublishedSolutionRef\n /** @deprecated 请使用结构化的 solution_ref;继续支持以保证现有 SDK 调用无感升级。 */\n solution_id?: string\n /** 从已有会话复制其不可变 Solution 与 Skill 运行快照。 */\n solution_snapshot_session_id?: string\n biz_role_id?: string | null\n primary_skill_id?: string | null\n model?: string | null\n enable_thinking?: boolean | null\n memory_enabled?: boolean | null\n env?: Record<string, string>\n disable_tools?: string[] | null\n session_solution_asset_id?: string | null\n compaction_ratio?: number | null\n runtime_type?: \"sandbox\" | \"daemon\" | \"native\" | null\n daemon_id?: string | null\n /** runtime_type 为 \"native\" 时必填:daemon 上要用哪个原生智能体(如 rt_codex)。 */\n agent_runtime_id?: string | null\n chat_group_id?: string | null\n}\n\nexport interface CheckpointNode {\n id: string\n parent_id: string | null\n content_preview: string\n content: string\n timestamp: string\n}\n\nexport type ContentPart =\n | { type: \"text\"; text: string }\n | { type: \"image_url\"; image_url: { url: string; detail?: string } }\n\nexport interface HistoryNode {\n id: string\n parent_id: string | null\n kind: string\n role: string\n timestamp: string\n preview: string\n content: string | ContentPart[]\n tool_calls: Array<{\n id?: string\n type?: string\n function?: { name?: string; arguments?: string }\n }> | null\n usage: { prompt_tokens?: number; completion_tokens?: number; total_tokens?: number } | null\n total_tokens: number\n token_diff: number\n is_deprecated: boolean\n loop_name: string\n}\n\nexport interface SessionHistory {\n nodes: HistoryNode[]\n active_branch: string | null\n branches: string[]\n system_prompt_tokens?: number | null\n tools_tokens?: number | null\n tokenizer_model?: string | null\n}\n\nexport interface TokenizeResult {\n model: string\n prompt_tokens: number\n prompt: string\n}\n\nexport interface PaginatedSessionsResult {\n items: SessionInfo[]\n total: number\n limit: number\n offset: number\n content_match_truncated?: boolean\n}\n\nexport interface GlobalSearchConversationResult {\n type: \"conversation\"\n session: SessionInfo\n snippet: string\n matched: \"title\" | \"content\"\n}\n\nexport interface GlobalSearchFileResult {\n type: \"file\"\n session: SessionInfo\n path: string\n name: string\n snippet: string\n matched: \"name\" | \"path\"\n}\n\nexport type GlobalSearchResultItem =\n | GlobalSearchConversationResult\n | GlobalSearchFileResult\n\nexport interface GlobalSearchResult {\n items: GlobalSearchResultItem[]\n truncated: boolean\n indexing: boolean\n}\n\ninterface ListSessionsPageParams {\n limit: number\n offset: number\n template_id_prefix?: string\n solution_id?: string\n solution_registry_id?: string\n q?: string\n chat_group_id?: string\n}\n\nexport interface SkillDevSession {\n session: SessionInfo\n skill_id: string\n display_name: string\n skill_description: string\n}\n\nexport interface ShareLinkResult {\n token: string\n url: string\n expires_at: string | null\n}\n\nexport interface SessionContextStats {\n tokens_used: number\n context_window: number\n compaction_ratio: number\n}\n\nexport interface SessionTurnsPage {\n turns: TurnProjection[]\n nextBefore: string | null\n currentMode: \"planning\" | \"executing\"\n}\n\n/** `getSessionTurnsPage` 的取数参数:向后翻页(before)或从某条发言定位(fromEntryId)。 */\nexport interface SessionTurnsQuery {\n limit?: number\n before?: string\n /**\n * 从这条用户发言开始、一直到最新。服务端按当前分支校验它,命中不了不会回空页\n * (`entry_not_found` / `entry_not_in_branch`),窗口首条就是这条发言,它的\n * `nextBefore` 可以继续当 `before` 往上翻。\n */\n fromEntryId?: string\n}\n\n/**\n * 服务端明确说这条发言不在当前分支上(`entry_not_found` / `entry_not_in_branch`),\n * 和\"这次没取到\"(网络 / 5xx / 鉴权)分开:前者说明这个定位目标已经没了,后者只说明这次失败。\n */\nexport function isEntryGoneError(error: unknown): boolean {\n const status = (error as { status?: unknown } | null)?.status\n return status === 404 || status === 409\n}\n\n/** 侧栏「消息历史」的一条:只有 id、标题和时间,没有消息体。 */\nexport interface SessionTurnIndexItem {\n entryId: string\n preview: string\n createdAt: string | null\n}\n\nexport interface SessionTurnIndex {\n sessionId: string\n items: SessionTurnIndexItem[]\n}\n\nexport interface HistoricalCommand {\n deliveryId: string\n toolCallId?: string\n action: string\n payload?: unknown\n}\n\nexport type ResultFeedbackReason =\n | \"not_solved\"\n | \"inaccurate\"\n | \"incomplete\"\n | \"needs_major_changes\"\n | \"too_slow\"\n | \"other\"\n\nexport interface ResultFeedback {\n session_id: string\n assistant_entry_id: string\n surface: \"chat\" | \"software_factory\" | \"unknown\"\n project_id: string | null\n helpful: boolean\n reason: ResultFeedbackReason | null\n created_at: string\n updated_at: string\n}\n\nexport interface FileEntry {\n name: string\n path: string\n is_dir: boolean\n created_at: number\n tags?: string[]\n}\n\nexport type UploadFileEntry = File | { file: File; name: string }\n\nexport interface UploadFilesOptions {\n onProgress?: (progress: UploadProgress) => void\n}\n\nexport interface AppCliDefinition {\n /** 智能体在 Bash 中直接执行的业务命令名,例如 `library`。 */\n command: string\n /** Python 脚本由沙盒系统 Python 执行;executable 必须是 Linux 可执行文件。 */\n runtime: \"python\" | \"executable\"\n /** CLI 文件本身,或浏览器可以读取的 URL。 */\n source: Blob | string | URL\n /** source 是普通 Blob 时使用的上传文件名。 */\n filename?: string\n}\n\nexport interface AppCliAttachment {\n command: string\n runtime: \"python\" | \"executable\"\n digest: string\n}\n\nexport interface ImportPreviewSkill {\n name: string\n description: string\n path: string\n}\n\nexport interface ImportPreviewScenario {\n scenario?: { name?: string }\n skills?: string[]\n preview_urls?: string[]\n init_script?: string\n generated_at?: string\n}\n\nexport interface ImportPreview {\n user_messages: string[]\n turn_count: number\n skills: ImportPreviewSkill[]\n scenario: ImportPreviewScenario | null\n}\n\nexport interface ImportSessionOptions {\n /** 导入后改用这个正式 Solution 的最新版。 */\n solution_ref?: PublishedSolutionRef\n /** 导入后改用已有会话的完整运行快照。 */\n solution_snapshot_session_id?: string\n}\n\nfunction toCreateSessionPayload(request: CreateSessionRequest) {\n const solutionRef = request.solution_ref ?? externalSolutionRef(request.solution_id)\n return {\n intent: request.intent ?? \"\",\n template_id: request.template_id,\n solution_id: solutionRef ? undefined : request.solution_id,\n solution_ref: solutionRef,\n biz_role_id: request.biz_role_id ?? null,\n model: request.model ?? null,\n enable_thinking: request.enable_thinking ?? null,\n memory_enabled: request.memory_enabled ?? null,\n primary_skill_id: request.primary_skill_id ?? null,\n env: request.env,\n disable_tools: request.disable_tools ?? null,\n session_solution_asset_id: request.session_solution_asset_id ?? null,\n solution_snapshot_session_id: request.solution_snapshot_session_id ?? null,\n compaction_ratio: request.compaction_ratio ?? null,\n ...(request.runtime_type ? { runtime_type: request.runtime_type } : {}),\n ...(request.daemon_id ? { daemon_id: request.daemon_id } : {}),\n ...(request.agent_runtime_id ? { agent_runtime_id: request.agent_runtime_id } : {}),\n ...(request.chat_group_id ? { chat_group_id: request.chat_group_id } : {}),\n }\n}\n\nconst builtinSolutionIds = new Set([\n \"app-dev\",\n \"general_chat\",\n \"night_build\",\n \"skill_editor\",\n \"smart_bid\",\n \"solution_generate\",\n])\n\nfunction externalSolutionRef(\n solutionId: string | undefined,\n): PublishedSolutionRef | undefined {\n if (!solutionId) return undefined\n const normalized = solutionId === \"default\" ? \"general_chat\" : solutionId.trim()\n if (builtinSolutionIds.has(normalized)) {\n return { source: \"builtin\", name: normalized }\n }\n const parts = normalized.split(\"/\")\n if (parts.length === 2 && parts.every(Boolean)) {\n return { source: \"hub\", org: parts[0], name: parts[1] }\n }\n // Let the Server compatibility adapter return the canonical, actionable error.\n return undefined\n}\n\nexport class SessionsResource {\n constructor(private client: BladeClient) {}\n\n getMcpApp(sessionId: string, sourceId: string, init?: RequestInit): Promise<McpAppArchive> {\n return this.client.jsonFromInit(`/api/sessions/${encodeURIComponent(sessionId)}/mcp-apps/${encodeURIComponent(sourceId)}`, init)\n }\n\n onMcpAppChanged(sessionId: string, sourceId: string, listener: () => void): () => void {\n let socket = this.client.socket()\n const changed = (payload: { session_id: string; source_id: string }) => {\n if (payload.session_id === sessionId && payload.source_id === sourceId) listener()\n }\n socket.on(\"mcp-app:changed\", changed)\n socket.on(\"connect\", listener)\n const off = this.client.onSocketReplaced(() => {\n socket.off(\"mcp-app:changed\", changed)\n socket.off(\"connect\", listener)\n socket = this.client.socket()\n socket.on(\"mcp-app:changed\", changed)\n socket.on(\"connect\", listener)\n })\n return () => {\n off()\n socket.off(\"mcp-app:changed\", changed)\n socket.off(\"connect\", listener)\n }\n }\n\n callMcpApp(sessionId: string, sourceId: string, request: {\n request_id: string; name: string; arguments: Record<string, unknown>\n }, init?: RequestInit): Promise<{ response: Record<string, unknown>; replayed: boolean }> {\n return this.client.jsonFromInit(`/api/sessions/${encodeURIComponent(sessionId)}/mcp-apps/${encodeURIComponent(sourceId)}/calls`, {\n ...init, method: \"POST\", body: JSON.stringify(request),\n })\n }\n\n /**\n * 连接一个已存在的会话,返回实时会话对象 AgentSession\n * (自动完成历史加载、Socket.IO 订阅、断线重连补数)。\n */\n connect(sessionId: string): Promise<AgentSession> {\n return this.client.hub.connect(sessionId)\n }\n\n listSessionPlugins(sessionId: string, init?: RequestInit): Promise<{ plugins: SessionPlugin[]; sync_version: number; sync_pending: boolean }> {\n return this.client.jsonFromInit(`/api/sessions/${encodeURIComponent(sessionId)}/plugins`, init)\n }\n\n setSessionPluginActivation(sessionId: string, name: string, active: boolean, init?: RequestInit): Promise<{ plugin: SessionPluginActivation; sync_version: number }> {\n return this.client.jsonFromInit(`/api/sessions/${encodeURIComponent(sessionId)}/plugins/${encodeURIComponent(name)}:activation`, { method: \"POST\", body: JSON.stringify({ active }), ...init })\n }\n\n /**\n * Fetch a plugin's package-local icon as bytes.\n *\n * The request carries the client's own bearer credentials, so callers turn\n * the blob into an object URL instead of pointing `<img>` at an API path and\n * hoping the request is authenticated.\n */\n fetchSessionPluginIcon(sessionId: string, name: string): Promise<Blob> {\n return this.client.blob(\"GET\", `/api/sessions/${encodeURIComponent(sessionId)}/plugins/${encodeURIComponent(name)}/icon`)\n }\n\n /** Authenticated URL for the icon; useful where a blob URL cannot be used. */\n sessionPluginIconUrl(sessionId: string, name: string): string {\n return this.client.buildAuthedUrl(`/api/sessions/${encodeURIComponent(sessionId)}/plugins/${encodeURIComponent(name)}/icon`)\n }\n\n /**\n * 准备一个插件的配置:把包准备好并读出用户的配置契约,**不启用**它。\n *\n * 开启插件前必须先走这一步:缺配置时用户只会看到配置表单,服务端不会先把\n * active 持久化成 true 再靠补偿关掉。它不修改会话的插件选择、不连接 MCP。\n */\n prepareSessionPluginConfig(sessionId: string, name: string, init?: RequestInit): Promise<{ plugin: string; config: SessionPluginConfigState }> {\n return this.client.jsonFromInit(\n `/api/sessions/${encodeURIComponent(sessionId)}/plugins/${encodeURIComponent(name)}:prepare-config`,\n { method: \"POST\", ...init },\n )\n }\n\n /**\n * Read a plugin's configuration contract and the user's stored values.\n *\n * Secrets are never returned: `write_only` lists the pointers that hold one.\n */\n getSessionPluginConfig(sessionId: string, name: string, init?: RequestInit): Promise<{ plugin: string; config: SessionPluginConfigState }> {\n return this.client.jsonFromInit(`/api/sessions/${encodeURIComponent(sessionId)}/plugins/${encodeURIComponent(name)}/config`, init)\n }\n\n /**\n * Publish explicit set/remove operations to the user's keychain file.\n *\n * Fields absent from both lists keep their stored value, so a form never has\n * to round-trip a secret. Rejections leave the previous file untouched; the\n * call never restarts MCP servers.\n */\n updateSessionPluginConfig(sessionId: string, name: string, update: SessionPluginConfigUpdate, init?: RequestInit): Promise<{ plugin: string; config: SessionPluginConfigState }> {\n return this.client.jsonFromInit(`/api/sessions/${encodeURIComponent(sessionId)}/plugins/${encodeURIComponent(name)}/config`, { method: \"PUT\", body: JSON.stringify(update), ...init })\n }\n\n /** 创建新会话并直接连接,返回可收发消息的 AgentSession。 */\n async create(request: CreateSessionRequest | SessionDefinition = {}): Promise<AgentSession> {\n if (isSessionDefinition(request)) {\n return this.createDeclared(request)\n }\n const { session_id } = await this.createSessionWithRequest(request)\n return this.connect(session_id)\n }\n\n private async createDeclared(definition: SessionDefinition): Promise<AgentSession> {\n const { intent, solution, skills = [], config } = definition\n validateDefinition(definition)\n let solutionRequest: Pick<CreateSessionRequest, \"solution_id\" | \"session_solution_asset_id\" | \"biz_role_id\"> = {}\n try {\n solutionRequest = solution ? await this.prepareSolution(solution) : {}\n } catch (error) {\n throw setupError(\"solution\", \"Solution 准备失败\", error)\n }\n\n let session_id: string\n try {\n const created = await this.createSessionWithRequest({\n intent,\n ...solutionRequest,\n model: config?.model,\n enable_thinking: config?.enableThinking,\n memory_enabled: config?.memoryEnabled,\n compaction_ratio: config?.compactionRatio,\n env: config?.env,\n disable_tools: config?.disableTools,\n })\n session_id = created.session_id\n } catch (error) {\n const assetId = solutionRequest.session_solution_asset_id\n const assetCleaned = await this.cleanupSolutionAsset(assetId)\n const cleanupMessage = assetId\n ? assetCleaned\n ? \";临时 Solution 已清理\"\n : `;临时 Solution ${assetId} 清理失败`\n : \"\"\n throw setupError(\"session\", `会话创建失败${cleanupMessage}`, error)\n }\n\n let installingSkill = \"\"\n try {\n for (const skill of skills) {\n installingSkill = skill.name\n await this.client.json(\"POST\", `/api/sessions/${encodeURIComponent(session_id)}/skills:upload`, {\n name: skill.name,\n files: skill.files,\n })\n }\n } catch (error) {\n const sessionCleaned = await this.deleteSession(session_id).then(\n () => true,\n () => false,\n )\n const assetCleaned = await this.cleanupSolutionAsset(solutionRequest.session_solution_asset_id)\n const cleanupMessage = sessionCleaned ? \"未完成的会话已清理\" : `请手动删除会话 ${session_id}`\n const assetCleanupMessage = assetCleaned ? \"\" : \";临时 Solution 清理失败\"\n throw setupError(\n \"skill\",\n `Skill \"${installingSkill}\" 安装失败;${cleanupMessage}${assetCleanupMessage}`,\n error,\n session_id,\n )\n }\n\n // 会话创建时 Server 已把声明式 Solution 持久化到会话目录,临时资产不再需要。\n await this.cleanupSolutionAsset(solutionRequest.session_solution_asset_id)\n\n try {\n return await this.connect(session_id)\n } catch (error) {\n throw setupError(\"connection\", `会话连接失败;可使用 sessionId ${session_id} 重试`, error, session_id)\n }\n }\n\n private async prepareSolution(\n solution: SolutionDefinition,\n ): Promise<Pick<CreateSessionRequest, \"solution_id\" | \"session_solution_asset_id\" | \"biz_role_id\">> {\n if (\"id\" in solution) {\n return { solution_id: solution.id, biz_role_id: solution.role ?? null }\n }\n\n const prepared = await this.client.json<{ asset_id: string }>(\n \"POST\",\n \"/api/session-assets/solutions\",\n { files: solution.files },\n )\n return {\n session_solution_asset_id: prepared.asset_id,\n biz_role_id: solution.role ?? null,\n }\n }\n\n private async cleanupSolutionAsset(assetId?: string | null): Promise<boolean> {\n if (!assetId) return true\n try {\n await this.client.json(\"DELETE\", `/api/session-assets/solutions/${encodeURIComponent(assetId)}`)\n return true\n } catch {\n return false\n }\n }\n\n private fetchSessionsPage({\n limit,\n offset,\n template_id_prefix,\n solution_id,\n solution_registry_id,\n q,\n chat_group_id,\n }: ListSessionsPageParams): Promise<PaginatedSessionsResult> {\n const searchParams = new URLSearchParams()\n searchParams.set(\"limit\", String(limit))\n searchParams.set(\"offset\", String(offset))\n if (template_id_prefix) searchParams.set(\"template_id_prefix\", template_id_prefix)\n if (solution_registry_id) {\n searchParams.set(\"solution_registry_id\", solution_registry_id)\n } else if (solution_id) {\n searchParams.set(\"solution_id\", solution_id)\n }\n const trimmedQuery = q?.trim()\n if (trimmedQuery) searchParams.set(\"q\", trimmedQuery)\n if (chat_group_id) searchParams.set(\"chat_group_id\", chat_group_id)\n return this.client.json(\"GET\", `/api/sessions?${searchParams.toString()}`)\n }\n\n async listSessions(template_id_prefix?: string, solution_id?: string): Promise<SessionInfo[]> {\n const pageSize = 100\n const sessions: SessionInfo[] = []\n let offset = 0\n while (true) {\n const page = await this.fetchSessionsPage({ limit: pageSize, offset, template_id_prefix, solution_id })\n sessions.push(...page.items)\n if (sessions.length >= page.total || page.items.length === 0) return sessions\n offset += page.items.length\n }\n }\n\n listSessionsPaginated(params: {\n limit: number\n offset: number\n template_id_prefix?: string\n solution_id?: string\n solution_registry_id?: string\n q?: string\n chat_group_id?: string\n }): Promise<PaginatedSessionsResult> {\n return this.fetchSessionsPage(params)\n }\n\n listSessionsWithSkillData(): Promise<SkillDevSession[]> {\n return this.client.json(\"GET\", \"/api/sessions/with-skill-data\")\n }\n\n searchOwnedContent(params: { q: string; limit?: number }): Promise<GlobalSearchResult> {\n const searchParams = new URLSearchParams({ q: params.q.trim() })\n if (params.limit !== undefined) searchParams.set(\"limit\", String(params.limit))\n return this.client.json(\"GET\", `/api/search?${searchParams.toString()}`)\n }\n\n createSession(\n intent?: string,\n template_id?: TemplateId,\n primary_skill_id?: string | null,\n ): Promise<{ session_id: string }> {\n return this.createSessionWithRequest({ intent, template_id, primary_skill_id })\n }\n\n createSessionWithRequest(request: CreateSessionRequest): Promise<{ session_id: string }> {\n return this.client.json(\"POST\", \"/api/sessions\", toCreateSessionPayload(request))\n }\n\n createWithProfile(params: {\n intent: string\n profile: SessionProfile\n }): Promise<{ session_id: string }> {\n const { intent, profile } = params\n return this.createSessionWithRequest({\n intent,\n ...profileToCreateSessionRequest(profile),\n })\n }\n\n getSession(sessionId: string, init?: RequestInit): Promise<SessionDetail> {\n return this.client.jsonFromInit(`/api/sessions/${sessionId}`, init)\n }\n\n updateSession(sessionId: string, payload: { intent?: string; chat_group_id?: string | null }): Promise<SessionDetail> {\n return this.client.json(\"PATCH\", `/api/sessions/${sessionId}`, payload)\n }\n\n setSessionEnv(sessionId: string, env: Record<string, string>): Promise<SessionDetail> {\n return this.client.json(\"PUT\", `/api/sessions/${sessionId}/env`, { env })\n }\n\n pinSession(sessionId: string, pinned: boolean): Promise<SessionInfo> {\n return this.client.json(\"PATCH\", `/api/sessions/${sessionId}/pin`, { pinned })\n }\n\n startReplaySession(\n sourceSessionId: string,\n speed: ReplaySpeed = DEFAULT_REPLAY_SPEED,\n ): Promise<{ session_id: string }> {\n return this.client.json(\"POST\", `/api/sessions/${sourceSessionId}/replay`, { speed })\n }\n\n updateReplaySession(\n sessionId: string,\n payload: { speed?: ReplaySpeed; status?: \"autonomous\" },\n ): Promise<{ replay_state: SessionInfo[\"replay_state\"] }> {\n return this.client.json(\"PATCH\", `/api/sessions/${sessionId}/replay`, payload)\n }\n\n /** 查询会话能否作为回放来源;不支持时 reason 可直接展示,用来提前禁用入口。 */\n getReplayPreview(sessionId: string): Promise<ReplayPreview> {\n return this.client.json(\"GET\", `/api/sessions/${sessionId}/replay/preview`)\n }\n\n updateSharing(sessionId: string, shared: boolean): Promise<{ shared: boolean }> {\n return this.client.json(\"PATCH\", `/api/sessions/${sessionId}/sharing`, { shared })\n }\n\n updateSessionMemory(sessionId: string, memoryEnabled: boolean): Promise<{ memory_enabled: boolean }> {\n return this.client.json(\"PATCH\", `/api/sessions/${sessionId}/memory`, {\n memory_enabled: memoryEnabled,\n })\n }\n\n createShare(sessionId: string): Promise<ShareLinkResult> {\n return this.client.json(\"POST\", `/api/sessions/${sessionId}/share`, {})\n }\n\n revokeShare(sessionId: string, token: string): Promise<{ revoked: boolean }> {\n return this.client.json(\"DELETE\", `/api/sessions/${sessionId}/share/${encodeURIComponent(token)}`)\n }\n\n async getSharedSession(token: string): Promise<TurnProjection[]> {\n const entries = await this.client.jsonFromInit<RawHistoryEntry[]>(`/api/share/${encodeURIComponent(token)}`, {\n credentials: \"omit\",\n headers: { Accept: \"application/json\" },\n })\n return projectHistory(entries)\n }\n\n getSessionTasks(sessionId: string): Promise<Task[]> {\n return this.client.json(\"GET\", `/api/sessions/${sessionId}/tasks`)\n }\n\n async getSessionTurns(sessionId: string): Promise<TurnProjection[]> {\n const entries = await this.client.json<RawHistoryEntry[]>(\n \"GET\",\n `/api/sessions/${sessionId}/messages`,\n )\n return projectHistory(entries)\n }\n\n async getSessionTurnsPage(\n sessionId: string,\n options: SessionTurnsQuery = {},\n init: RequestInit = {},\n ): Promise<SessionTurnsPage> {\n const query = new URLSearchParams()\n if (options.limit !== undefined) query.set(\"limit\", String(options.limit))\n if (options.before !== undefined) query.set(\"before\", options.before)\n if (options.fromEntryId !== undefined) query.set(\"from_entry_id\", options.fromEntryId)\n const suffix = query.size ? `?${query}` : \"\"\n // 走 jsonFromInit 而不是 json:定位要能在用户改选下一条时中止在途请求\n // (排队中的新一次不该等着它),所以这里要把调用方的 AbortSignal 带下去。\n const page = await this.client.jsonFromInit<{\n turns: TurnProjection[]\n next_before: string | null\n current_mode: \"planning\" | \"executing\"\n }>(`/api/sessions/${encodeURIComponent(sessionId)}/turns${suffix}`, init)\n return {\n turns: page.turns,\n nextBefore: page.next_before,\n currentMode: page.current_mode,\n }\n }\n\n /**\n * 当前分支上可导航的用户发言目录(消息导航侧栏)。\n *\n * 只回 id、标题和时间:侧栏要列的是**整条会话**的发言,而窗口外的发言 id 只能\n * 从服务端拿;消息体仍然走 `/turns`。\n */\n async getSessionTurnIndex(sessionId: string): Promise<SessionTurnIndex> {\n const index = await this.client.json<{\n session_id: string\n items: Array<{ entry_id: string; preview: string; created_at: string | null }>\n }>(\"GET\", `/api/sessions/${encodeURIComponent(sessionId)}/turn-index`)\n return {\n sessionId: index.session_id,\n items: index.items.map((item) => ({\n entryId: item.entry_id,\n preview: item.preview,\n createdAt: item.created_at,\n })),\n }\n }\n\n getMcpAppContext(sessionId: string, sourceId: string, init?: RequestInit): Promise<McpAppContextState> {\n return this.client.jsonFromInit(`/api/sessions/${encodeURIComponent(sessionId)}/mcp-apps/${encodeURIComponent(sourceId)}/context`, init)\n }\n\n updateMcpAppContext(sessionId: string, sourceId: string, body: McpAppContextUpdate, init?: RequestInit): Promise<{ status: \"accepted\"; revision: string }> {\n return this.client.jsonFromInit(`/api/sessions/${encodeURIComponent(sessionId)}/mcp-apps/${encodeURIComponent(sourceId)}/context`, {\n ...init, method: \"POST\", body: JSON.stringify(body),\n })\n }\n\n async getSessionTurnCommands(sessionId: string): Promise<HistoricalCommand[]> {\n const commands = await this.client.json<Array<{\n delivery_id: string\n tool_call_id?: string | null\n action: string\n payload?: unknown\n }>>(\"GET\", `/api/sessions/${encodeURIComponent(sessionId)}/turn-commands`)\n return commands.map((command) => ({\n deliveryId: command.delivery_id,\n toolCallId: command.tool_call_id ?? undefined,\n action: command.action,\n payload: command.payload,\n }))\n }\n\n listResultFeedback(sessionId: string): Promise<ResultFeedback[]> {\n return this.client.json(\"GET\", `/api/sessions/${encodeURIComponent(sessionId)}/feedback`)\n }\n\n putResultFeedback(\n sessionId: string,\n assistantEntryId: string,\n feedback: { helpful: boolean; reason?: ResultFeedbackReason | null },\n ): Promise<ResultFeedback> {\n return this.client.json(\n \"PUT\",\n `/api/sessions/${encodeURIComponent(sessionId)}/turns/${encodeURIComponent(assistantEntryId)}/feedback`,\n feedback,\n )\n }\n\n getSessionContextStats(sessionId: string, init?: RequestInit): Promise<SessionContextStats> {\n return this.client.jsonFromInit(`/api/sessions/${sessionId}/context-stats`, init)\n }\n\n getSessionHistory(sessionId: string, init?: RequestInit): Promise<SessionHistory> {\n return this.client.jsonFromInit(`/api/sessions/${sessionId}/history`, init)\n }\n\n tokenizePrompt(prompt: string, model?: string): Promise<TokenizeResult> {\n return this.client.json(\"POST\", \"/api/sessions/tokenize/prompt\", { prompt, model })\n }\n\n tokenizeMessages(\n messages: Array<Record<string, unknown>>,\n options?: {\n model?: string\n add_generation_prompt?: boolean\n enable_thinking?: boolean | null\n tools?: Array<Record<string, unknown>>\n },\n ): Promise<TokenizeResult> {\n return this.client.json(\"POST\", \"/api/sessions/tokenize/messages\", {\n messages,\n model: options?.model,\n add_generation_prompt: options?.add_generation_prompt ?? true,\n enable_thinking: options?.enable_thinking ?? null,\n tools: options?.tools ?? null,\n })\n }\n\n getSessionCheckpoints(\n sessionId: string,\n init?: RequestInit,\n ): Promise<{ nodes: CheckpointNode[]; leaf_id: string | null }> {\n return this.client.jsonFromInit(`/api/sessions/${sessionId}/checkpoints`, init)\n }\n\n checkoutSession(\n sessionId: string,\n checkpointId: string,\n position: \"before\" | \"turn_end\",\n mode?: \"both\" | \"conversation\" | \"code\",\n linear?: boolean,\n ): Promise<{\n id: string\n content: string\n position: string\n mode?: string\n files_restored?: boolean\n linear?: boolean\n }> {\n return this.client.json(\"POST\", `/api/sessions/${sessionId}/checkout`, {\n checkpoint_id: checkpointId,\n position,\n ...(mode ? { mode } : {}),\n ...(linear ? { linear } : {}),\n })\n }\n\n async rewindSession(sessionId: string, checkpointId: string): Promise<{ id: string; content: string }> {\n const result = await this.checkoutSession(sessionId, checkpointId, \"before\")\n return { id: result.id, content: result.content }\n }\n\n switchBranch(sessionId: string, checkpointId: string): Promise<{ id: string; leaf_id: string }> {\n return this.client.json(\"POST\", `/api/sessions/${sessionId}/switch-branch`, {\n checkpoint_id: checkpointId,\n })\n }\n\n deleteSession(\n sessionId: string,\n options?: { deleteWorkspace?: boolean },\n ): Promise<{ deleted: boolean; workspace_deleted?: boolean }> {\n const query = options?.deleteWorkspace ? \"?delete_workspace=true\" : \"\"\n return this.client.json(\"DELETE\", `/api/sessions/${sessionId}${query}`)\n }\n\n listBackgroundTasks(sessionId: string, init?: RequestInit): Promise<BackgroundTask[]> {\n return this.client.jsonFromInit(`/api/sessions/${sessionId}/background-tasks`, init)\n }\n\n getBackgroundTask(\n sessionId: string,\n taskId: string,\n tail = 100,\n init?: RequestInit,\n ): Promise<BackgroundTask> {\n return this.client.jsonFromInit(`/api/sessions/${sessionId}/background-tasks/${taskId}?tail=${tail}`, init)\n }\n\n stopBackgroundTask(\n sessionId: string,\n taskId: string,\n ): Promise<BackgroundTaskStopResult> {\n return this.client.json(\"POST\", `/api/sessions/${sessionId}/background-tasks/${taskId}/stop`)\n }\n\n\n probeSessionUrl(\n sessionId: string,\n url: string,\n ): Promise<{ reachable: boolean; requires_proxy: boolean }> {\n return this.client.json(\n \"GET\",\n `/api/sessions/${sessionId}/probe-url?url=${encodeURIComponent(url)}`,\n )\n }\n\n listDir(sessionId: string, dirPath: string): Promise<FileEntry[]> {\n return this.client.json(\"GET\", `/api/sessions/${sessionId}/ls/${encodeURIComponent(dirPath)}`)\n }\n\n async countFiles(sessionId: string, dirPath = \"\"): Promise<number> {\n const entries = await this.listDir(sessionId, dirPath)\n let count = 0\n for (const entry of entries) {\n count += entry.is_dir ? await this.countFiles(sessionId, entry.path) : 1\n }\n return count\n }\n\n /** 在浏览器中下载一个会话文件。 */\n async downloadFile(sessionId: string, filePath: string, downloadName?: string): Promise<void> {\n if (typeof document === \"undefined\") {\n throw new Error(\"downloadFile 只能在浏览器中使用\")\n }\n const response = await this.client.fetch(\n \"GET\",\n `/api/sessions/${encodeURIComponent(sessionId)}/files/${encodeURIComponent(filePath)}`,\n )\n const objectUrl = URL.createObjectURL(await response.blob())\n const anchor = document.createElement(\"a\")\n anchor.href = objectUrl\n anchor.download = downloadName || filePath.split(\"/\").pop() || \"download\"\n anchor.style.display = \"none\"\n document.body.appendChild(anchor)\n anchor.click()\n anchor.remove()\n globalThis.setTimeout(() => URL.revokeObjectURL(objectUrl), 1_000)\n }\n\n async uploadFiles(\n sessionId: string,\n dirPath: string,\n files: FileList | File[] | UploadFileEntry[],\n options: UploadFilesOptions = {},\n ): Promise<{ uploaded: string[]; failed: string[] }> {\n const formData = new FormData()\n const entries = Array.from(files).map((f) =>\n f instanceof File ? { file: f, name: f.name } : (f as { file: File; name: string }),\n )\n for (const entry of entries) {\n formData.append(\"files\", entry.file, entry.name)\n }\n // webkitdirectory 选择的文件带 webkitRelativePath;拖入的文件夹把相对路径放在 name 里。\n // 任一形式包含目录分隔符时都发送 paths,供服务端重建目录结构。\n const relativePaths = entries.map((e) => e.file.webkitRelativePath || e.name)\n if (relativePaths.some((p) => p.includes(\"/\"))) {\n formData.append(\"paths\", JSON.stringify(relativePaths))\n }\n const response = await this.client.formData(\n \"POST\",\n `/api/sessions/${sessionId}/upload/${encodeURIComponent(dirPath)}`,\n formData,\n { expectOk: false, onUploadProgress: options.onProgress },\n )\n return response.json()\n }\n\n /** 把应用自己的业务 CLI 安装到会话沙盒,并保留开发者声明的命令名。 */\n async attachAppCli(\n sessionId: string,\n definition: AppCliDefinition,\n ): Promise<AppCliAttachment> {\n let source: Blob\n if (definition.source instanceof Blob) {\n source = definition.source\n } else {\n const response = await globalThis.fetch(definition.source.toString())\n if (!response.ok) {\n throw new Error(`读取应用 CLI 失败:HTTP ${response.status}`)\n }\n source = await response.blob()\n }\n const filename =\n definition.filename ??\n (typeof File !== \"undefined\" && definition.source instanceof File\n ? definition.source.name\n : undefined) ??\n (definition.runtime === \"python\" ? \"app-cli.py\" : \"app-cli\")\n const form = new FormData()\n form.append(\"command\", definition.command)\n form.append(\"runtime\", definition.runtime)\n form.append(\"file\", source, filename)\n const response = await this.client.formData(\n \"POST\",\n `/api/sessions/${sessionId}/app-cli`,\n form,\n )\n return response.json()\n }\n\n async deleteFile(sessionId: string, filePath: string): Promise<void> {\n await this.client.json(\"DELETE\", `/api/sessions/${sessionId}/files/${encodeURIComponent(filePath)}`)\n }\n\n writeFile(sessionId: string, filePath: string, content: string): Promise<{ success: boolean }> {\n return this.client.json(\"PUT\", `/api/sessions/${sessionId}/files/${encodeURIComponent(filePath)}`, {\n content,\n })\n }\n\n renameFile(sessionId: string, filePath: string, newName: string): Promise<{ path: string }> {\n return this.client.json(\"POST\", `/api/sessions/${sessionId}/files/${encodeURIComponent(filePath)}/rename`, {\n new_name: newName,\n })\n }\n\n copyFile(sessionId: string, filePath: string): Promise<{ path: string }> {\n return this.client.json(\"POST\", `/api/sessions/${sessionId}/files/${encodeURIComponent(filePath)}/copy`)\n }\n\n shareFile(\n sessionId: string,\n sourcePath: string,\n linkName?: string,\n shareFolder?: string,\n ): Promise<{ path: string; target: string }> {\n return this.client.json(\"POST\", `/api/sessions/${sessionId}/share-file`, {\n source_path: sourcePath,\n link_name: linkName ?? \"\",\n share_folder: shareFolder ?? \"\",\n })\n }\n\n getDownloadDirUrl(sessionId: string, dirPath: string): string {\n return this.client.buildAuthedUrl(`/api/sessions/${sessionId}/download-dir/${encodeURIComponent(dirPath)}`)\n }\n\n async exportSession(sessionId: string): Promise<void> {\n await this.getSession(sessionId)\n const a = document.createElement(\"a\")\n a.href = this.client.buildAuthedUrl(`/api/sessions/${sessionId}/export`)\n a.download = `${sessionId}.zip`\n document.body.appendChild(a)\n a.click()\n a.remove()\n }\n\n async previewImport(file: File): Promise<ImportPreview> {\n const form = new FormData()\n form.append(\"file\", file)\n const res = await this.client.formData(\"POST\", \"/api/sessions/preview-import\", form)\n return res.json()\n }\n\n async importSession(\n file: File,\n name?: string,\n solutionOverride?: string | null | ImportSessionOptions,\n ): Promise<{ session_id: string }> {\n const form = new FormData()\n form.append(\"file\", file)\n if (name) form.append(\"name\", name)\n if (typeof solutionOverride === \"string\") {\n if (solutionOverride) form.append(\"solution_id\", solutionOverride)\n } else if (solutionOverride) {\n if (solutionOverride.solution_ref) {\n form.append(\"solution_ref\", JSON.stringify(solutionOverride.solution_ref))\n }\n if (solutionOverride.solution_snapshot_session_id) {\n form.append(\n \"solution_snapshot_session_id\",\n solutionOverride.solution_snapshot_session_id,\n )\n }\n }\n const res = await this.client.formData(\"POST\", \"/api/sessions/import\", form)\n return res.json()\n }\n}\n\nfunction isSessionDefinition(request: CreateSessionRequest | SessionDefinition): request is SessionDefinition {\n return \"solution\" in request || \"skills\" in request || \"config\" in request\n}\n\nfunction validateDefinition(definition: SessionDefinition): void {\n if (definition.solution) {\n if (\"id\" in definition.solution) {\n if (!definition.solution.id.trim()) {\n throw new SessionSetupError(\"Solution id 不能为空\", \"solution\")\n }\n } else {\n validateTextFiles(definition.solution.files, \"solution\", \"Solution\")\n if (!definition.solution.files.some((file) => file.path === \"solution.yaml\")) {\n throw new SessionSetupError(\"Solution 缺少根目录 solution.yaml\", \"solution\")\n }\n }\n }\n for (const skill of definition.skills ?? []) validateSkill(skill)\n}\n\nfunction validateSkill(skill: SkillDefinition): void {\n if (!/^[a-z0-9-]+\\/[a-z0-9-]+$/.test(skill.name)) {\n throw new SessionSetupError(`Skill name \"${skill.name}\" 必须是小写的 组织/名称`, \"skill\")\n }\n validateTextFiles(skill.files, \"skill\", `Skill \"${skill.name}\"`)\n if (!skill.files.some((file) => file.path === \"SKILL.md\")) {\n throw new SessionSetupError(`Skill \"${skill.name}\" 缺少根目录 SKILL.md`, \"skill\")\n }\n}\n\nfunction validateTextFiles(\n files: Array<{ path: string; content: string }>,\n stage: ConstructorParameters<typeof SessionSetupError>[1],\n label: string,\n): void {\n if (files.length === 0) throw new SessionSetupError(`${label} files 不能为空`, stage)\n const paths = new Set<string>()\n for (const file of files) {\n const path = file.path\n if (\n !path\n || path !== path.trim()\n || path.startsWith(\"/\")\n || path.includes(\"\\\\\")\n || path.split(\"/\").some((part) => !part || part === \".\" || part === \"..\")\n || /^[a-zA-Z]:/.test(path)\n ) {\n throw new SessionSetupError(`${label} 文件路径不安全:\"${path}\"`, stage)\n }\n if (paths.has(path)) {\n throw new SessionSetupError(`${label} 文件路径重复:\"${path}\"`, stage)\n }\n paths.add(path)\n }\n}\n\nfunction setupError(\n stage: ConstructorParameters<typeof SessionSetupError>[1],\n message: string,\n cause: unknown,\n sessionId?: string,\n): SessionSetupError {\n const detail = cause instanceof Error ? cause.message : String(cause)\n return new SessionSetupError(`${message}:${detail}`, stage, sessionId, { cause })\n}\n\nfunction profileToCreateSessionRequest(profile: SessionProfile): CreateSessionRequest {\n const solution = profile.solution\n return {\n solution_id: solution?.kind === \"existing\" ? solution.solutionId : undefined,\n session_solution_asset_id: solution?.kind === \"prepared\" ? solution.assetId : undefined,\n biz_role_id: solution?.bizRoleId ?? null,\n model: profile.model ?? null,\n compaction_ratio: profile.compactionRatio ?? null,\n enable_thinking: profile.enableThinking ?? null,\n memory_enabled: profile.memoryEnabled ?? null,\n disable_tools: profile.disableTools ?? null,\n env: profile.env,\n }\n}\n","import type { BladeClient } from \"../blade-client\"\n\n/**\n * 一个插件在当前用户眼里的展示信息,**与会话无关**。\n *\n * 连接器面板在首页(还没有 sessionId)也要显示插件名称和图标,所以这份目录\n * 只能依赖用户身份:它不激活任何插件、不启动沙盒、不读用户配置。\n */\nexport interface PluginCatalogEntry {\n /** 技术 ID:路径、授权、缓存与调用一律用它。 */\n name: string\n /** 包声明的业务名称;null 时界面回退到 `name`。 */\n display_name: string | null\n /**\n * 包内图标的 opaque token,没有可用图标时为 null。\n * 交给 `fetchPluginIcon`,**不是**路径,也不能直接当 URL 用。\n */\n icon: string | null\n /** 当前用户是否安装了它。 */\n installed: boolean\n}\n\n/**\n * 按用户读取的插件目录(无会话)。\n *\n * 图标只能通过带凭据的请求取字节,再转成 object URL——把 `<img>` 指向 API\n * 路径要靠 cookie,token 用户会拿到 401/403。\n */\nexport class PluginsResource {\n constructor(private client: BladeClient) {}\n\n /**\n * 列出当前用户安装的插件及其展示信息。\n *\n * 服务端可能为了补齐名称/图标惰性获取包内容,但绝不激活插件、不连 MCP;\n * 单个插件的展示信息读不出来只会降级成占位,不会让整份目录失败。\n */\n catalog(init?: RequestInit): Promise<{ plugins: PluginCatalogEntry[] }> {\n return this.client.jsonFromInit(\"/api/plugins/catalog\", init)\n }\n\n /** 取一个插件的包内图标字节(用户级,不需要会话)。 */\n fetchIcon(name: string): Promise<Blob> {\n return this.client.blob(\"GET\", `/api/plugins/${encodeURIComponent(name)}/icon`)\n }\n\n /** 带凭据的图标地址;能直接用 blob URL 的地方优先用 `fetchIcon`。 */\n iconUrl(name: string): string {\n return this.client.buildAuthedUrl(`/api/plugins/${encodeURIComponent(name)}/icon`)\n }\n}\n","import type { BladeClient } from \"../blade-client\"\n\nexport interface ChatGroup {\n id: string\n name: string\n instructions: string\n created_at: string\n updated_at: string\n session_count: number\n workspace_path: string\n}\n\nexport class ChatGroupsResource {\n constructor(private readonly client: BladeClient) {}\n\n list(): Promise<ChatGroup[]> {\n return this.client.json(\"GET\", \"/api/chat-groups\")\n }\n\n create(payload: { name: string; instructions?: string }): Promise<ChatGroup> {\n return this.client.json(\"POST\", \"/api/chat-groups\", payload)\n }\n\n update(groupId: string, payload: { name?: string; instructions?: string }): Promise<ChatGroup> {\n return this.client.json(\"PATCH\", `/api/chat-groups/${encodeURIComponent(groupId)}`, payload)\n }\n\n delete(groupId: string, options?: { deleteWorkspace?: boolean }): Promise<{ deleted: boolean; deleted_sessions: number }> {\n const query = options?.deleteWorkspace ? \"?delete_workspace=true\" : \"\"\n return this.client.json(\"DELETE\", `/api/chat-groups/${encodeURIComponent(groupId)}${query}`)\n }\n\n}\n","import { BladeApiError, buildBackendUrl, extractErrorDetail } from \"../rest\"\nimport type { BladeClient } from \"../blade-client\"\n\nconst SITE_VISITS_PATH = \"/api/site-visits\"\nconst REQUEST_TIMEOUT_MS = 5_000\n\n/** 全站访问统计快照。每个数字都来自真实请求,没有基数、系数或回填。 */\nexport interface SiteVisitsSummary {\n /** 统计日期,按北京时间切日(`YYYY-MM-DD`)。 */\n date: string\n /** 统计时区,固定为 `Asia/Shanghai`。 */\n timezone: string\n /** 当天出现过的匿名访客数:按天去重,不是实时在线人数。 */\n today_uv: number\n /** 当天的页面访问次数。 */\n today_pv: number\n /** 功能上线以来累计的页面访问次数。 */\n total_pv: number\n /** 快照生成时间(RFC3339 UTC)。并发响应可能倒序到达,用它丢弃旧快照。 */\n as_of: string\n}\n\n/**\n * 全站访问统计(内置 Web 的匿名计数)。\n *\n * 这两个操作刻意走独立传输:不带 bearer、不触发 401 登录刷新,也不读登录\n * Cookie——计数只依赖匿名访客 Cookie,因此登录态失效时统计依然可用。它们\n * 只在同源的内置 Web 里使用,不是给第三方宿主页面用的。\n */\nexport class SiteVisitsResource {\n constructor(private readonly client: BladeClient) {}\n\n /** 上报一次页面访问,返回当前快照;不承诺本次已计入或已落盘。 */\n record(): Promise<SiteVisitsSummary> {\n return this.request(\"POST\")\n }\n\n /** 只读快照:不设置访客 Cookie,也不增加任何计数。 */\n summary(): Promise<SiteVisitsSummary> {\n return this.request(\"GET\")\n }\n\n private async request(method: \"GET\" | \"POST\"): Promise<SiteVisitsSummary> {\n const url = buildBackendUrl(this.client.options.baseUrl, SITE_VISITS_PATH)\n const controller = new AbortController()\n const timeout = setTimeout(() => controller.abort(), REQUEST_TIMEOUT_MS)\n try {\n const response = await (this.client.options.fetchImpl ?? fetch)(url.toString(), {\n method,\n // 访客 Cookie 是唯一的去重依据,必须随请求往返。\n credentials: \"include\",\n signal: controller.signal,\n })\n if (!response.ok) {\n throw new BladeApiError(response, await extractErrorDetail(response))\n }\n return (await response.json()) as SiteVisitsSummary\n } finally {\n clearTimeout(timeout)\n }\n }\n}\n","const DEFAULT_RETRY_AFTER_SECONDS = 1\nconst MAX_TIMER_DELAY_MS = 2_147_483_647\n\ntype AuthBusyData = {\n code?: unknown\n status?: unknown\n retry_after?: unknown\n}\n\nfunction errorData(error: unknown): AuthBusyData | null {\n if (typeof error !== \"object\" || error === null || !(\"data\" in error)) return null\n const data = error.data\n return typeof data === \"object\" && data !== null ? (data as AuthBusyData) : null\n}\n\n/** Return the server-requested delay for a typed temporary auth rejection. */\nexport function authBusyRetryDelayMs(error: unknown): number | null {\n const data = errorData(error)\n if (data?.code !== \"auth_busy\" || Number(data.status) !== 429) return null\n const rawRetryAfter = data.retry_after\n const seconds = rawRetryAfter == null || String(rawRetryAfter).trim() === \"\"\n ? Number.NaN\n : Number(rawRetryAfter)\n const delaySeconds = Number.isFinite(seconds) && seconds >= 0\n ? seconds\n : DEFAULT_RETRY_AFTER_SECONDS\n return Math.min(delaySeconds * 1000, MAX_TIMER_DELAY_MS)\n}\n\n/** One pending manual reconnect for Socket.IO CONNECT_ERROR auth overloads. */\nexport class AuthBusyReconnect {\n private timer: ReturnType<typeof globalThis.setTimeout> | null = null\n\n get pending(): boolean {\n return this.timer !== null\n }\n\n schedule(error: unknown, reconnect: () => void): boolean {\n const delay = authBusyRetryDelayMs(error)\n if (delay === null) {\n this.cancel()\n return false\n }\n this.cancel()\n this.timer = globalThis.setTimeout(() => {\n this.timer = null\n reconnect()\n }, delay)\n return true\n }\n\n cancel(): void {\n if (this.timer === null) return\n globalThis.clearTimeout(this.timer)\n this.timer = null\n }\n}\n","export type CommandHandler = (payload: unknown, meta: { toolCallId?: string }) => void\n\ninterface BufferedCommand {\n payload: unknown\n meta: { toolCallId?: string }\n}\n\n/** 每个 action 在 handler 注册前最多缓冲的指令条数,超出丢最旧的。 */\nconst BUFFER_LIMIT_PER_ACTION = 20\n\n/**\n * 指令注册表:onCommand 事后注册 + 注册前缓冲补投。\n *\n * action 的来源见 ./protocol.ts 顶部说明——它由技能作者在工具返回值的\n * `_meta.bridge` 字段里写入,是技能作者与宿主页面开发者的业务契约。\n * 缓冲的意义:指令可能在页面还没来得及调用 onCommand 时就到达(比如\n * 历史回放),先存起来、注册时立刻补投,消除\"注册晚了漏事件\"的坑。\n */\nexport class CommandRegistry {\n private handlers = new Map<string, Set<CommandHandler>>()\n private buffered = new Map<string, BufferedCommand[]>()\n\n onCommand(action: string, handler: CommandHandler): () => void {\n let set = this.handlers.get(action)\n if (!set) {\n set = new Set()\n this.handlers.set(action, set)\n }\n set.add(handler)\n\n const pending = this.buffered.get(action)\n if (pending?.length) {\n this.buffered.delete(action)\n for (const command of pending) {\n this.invoke(handler, action, command)\n }\n }\n return () => {\n this.handlers.get(action)?.delete(handler)\n }\n }\n\n dispatch(action: string, payload: unknown, meta: { toolCallId?: string } = {}): void {\n const set = this.handlers.get(action)\n if (set && set.size > 0) {\n for (const handler of [...set]) {\n this.invoke(handler, action, { payload, meta })\n }\n return\n }\n let pending = this.buffered.get(action)\n if (!pending) {\n pending = []\n this.buffered.set(action, pending)\n }\n pending.push({ payload, meta })\n if (pending.length > BUFFER_LIMIT_PER_ACTION) {\n pending.shift()\n console.warn(\n `[agent-client] 指令 \"${action}\" 无人处理且缓冲已满,最旧的一条已丢弃。` +\n `请调用 onCommand(\"${action}\", handler) 注册处理函数。`,\n )\n }\n }\n\n private invoke(handler: CommandHandler, action: string, command: BufferedCommand): void {\n try {\n handler(command.payload, command.meta)\n } catch (error) {\n console.warn(`[agent-client] 指令 \"${action}\" 的处理函数抛出异常:`, error)\n }\n }\n\n clear(): void {\n this.handlers.clear()\n this.buffered.clear()\n }\n}\n","import type { ChatMessage, ToolCallInfo } from \"../schemas/message\"\nimport type { McpAppData } from \"../schemas/mcp-app\"\nimport type { TurnProjection } from \"../schemas/projection\"\nimport type { SessionStatus } from \"../schemas/session\"\n\n/**\n * AgentSession 的语义事件表。\n *\n * 这是\"底层逃生舱\"(L1):React 使用者优先用 useChat() 的响应式状态(L2)\n * 或 <ChatView onToolCall/commands> 的声明式入口(L3),一般不需要直接监听。\n * Vue / 无框架集成者用 session.on(...) 精确订阅。\n */\nexport interface AgentSessionEvents {\n /** 一条消息物化完成(turn 离开 streaming 状态)。 */\n message: { message: ChatMessage; turn: TurnProjection }\n /** 智能体发起了一次工具调用(首次出现)。 */\n toolCall: { toolCall: ToolCallInfo; turn: TurnProjection }\n /** 一次工具调用出结果(done / error / cancelled)。 */\n toolResult: {\n toolCall: ToolCallInfo\n turn: TurnProjection\n /** 实时到达,或首次连接/断线重连时由服务端回放。 */\n source: \"live\" | \"bootstrap_replay\" | \"reconnect_replay\"\n }\n /** 一轮回复结束。status: completed / paused / interrupted / failed。 */\n chatEnd: { status: string }\n /** 运行错误(system:error、发送失败等)。 */\n error: { message: string }\n /** planning / executing 模式切换。 */\n modeChange: { mode: \"planning\" | \"executing\" }\n /**\n * 智能体给宿主页面下发指令。\n *\n * action 的来源:技能作者在工具实现的返回值 JSON 里写 `_meta.bridge:\n * { action, payload }`,后端剥离后经事件流送达前端。action 是技能作者与\n * 宿主页面开发者约定的业务契约字符串(如 \"map.highlight\"),LLM 不参与、\n * SDK 不做枚举。一般用 session.onCommand(action, fn) 消费,而不是监听本事件。\n */\n command: { action: string; payload: unknown; toolCallId?: string }\n /** 系统通知(技能阶段提示、后台任务启动等)。 */\n notification: {\n type: string\n title: string\n detail?: string\n status: \"info\" | \"running\" | \"done\" | \"error\"\n loopId?: string\n metadata?: Record<string, unknown>\n }\n /** 工作区文件发生变化(写文件、重命名等)。 */\n workspaceChanged: { filePath?: string }\n /** 智能体产出了文件成果(artifact:created / artifact:updated)。 */\n artifact: {\n filePath: string\n contentType: string\n title: string\n content: string\n oldString?: string\n newString?: string\n kind: \"created\" | \"updated\"\n }\n /** 工具返回值带 _meta.ui 的可视化预览(resource HTML / URI)。 */\n toolPreview: {\n toolCallId: string\n type: \"resource-html\" | \"resource-uri\"\n content: string\n title: string\n mcpApp?: McpAppData\n }\n /** 任务清单(TaskCreate 等)更新。 */\n taskListUpdated: { tasks: unknown[] }\n /** 沙盒后台命令状态更新。 */\n backgroundTask: {\n id: string\n command: string\n description?: string\n /**\n * 与 REST 一致的真实状态。不要在客户端合并这些值:把 cancelled / lost\n * 显示成\"完成\"会让订阅方拿到与 REST 相反的结论。\n * lost 表示平台跟丢了这个进程,不代表它失败,也可能仍在运行。\n */\n status:\n | \"starting\"\n | \"running\"\n | \"cancelling\"\n | \"succeeded\"\n | \"failed\"\n | \"cancelled\"\n | \"lost\"\n /** failed 时说明原因,如 start_failed、log_budget_exceeded。 */\n failureReason?: string | null\n exitCode?: number | null\n elapsedSeconds: number\n output?: string\n }\n /** 会话被回溯到某个检查点。 */\n rewind: { checkpointId: string }\n /** 会话属性(名称、状态、绑定技能等)被服务端更新。 */\n sessionUpdated: {\n workspacePath?: string\n chatGroupId?: string | null\n intent?: string\n status?: SessionStatus\n model?: string | null\n boundSkillId?: string | null\n replayState?: Record<string, unknown> | null\n }\n /** 回放输入不匹配,需要决定保持回放还是转自主模式。 */\n replayMismatch: {\n actualMessage?: string\n expectedMessage?: string\n respond: (decision: \"keep_replay\" | \"continue_replay\") => void\n }\n /** 沙盒内存超限自动重启。 */\n sandboxOom: { toolCallId: string }\n /** session.attach() 被调用,渲染层(ChatView/useChat)应把它显示为输入框附件。 */\n attachRequested: { label: string; content: string }\n /** session.insertText() 被调用,渲染层应把文字追加到输入框。 */\n insertTextRequested: { text: string }\n}\n\nexport type AgentSessionEventName = keyof AgentSessionEvents\n\ntype Handler<E> = (event: E) => void\n\nexport class Emitter<Events> {\n private handlers = new Map<keyof Events, Set<Handler<never>>>()\n\n on<K extends keyof Events>(name: K, handler: Handler<Events[K]>): () => void {\n let set = this.handlers.get(name)\n if (!set) {\n set = new Set()\n this.handlers.set(name, set)\n }\n set.add(handler as Handler<never>)\n return () => this.off(name, handler)\n }\n\n off<K extends keyof Events>(name: K, handler: Handler<Events[K]>): void {\n this.handlers.get(name)?.delete(handler as Handler<never>)\n }\n\n emit<K extends keyof Events>(name: K, event: Events[K]): void {\n const set = this.handlers.get(name)\n if (!set) return\n for (const handler of [...set]) {\n try {\n ;(handler as Handler<Events[K]>)(event)\n } catch (error) {\n // handler 异常只告警,不中断会话流\n console.warn(`[agent-client] \"${String(name)}\" 事件处理器抛出异常:`, error)\n }\n }\n }\n\n /**\n * 只把事件交给最先注册的处理器。用于必须由单一交互入口作答的事件,\n * 避免多个 UI 同时弹窗并提交相互冲突的决定。\n */\n emitFirst<K extends keyof Events>(name: K, event: Events[K]): boolean {\n const handler = this.handlers.get(name)?.values().next().value\n if (!handler) return false\n try {\n ;(handler as Handler<Events[K]>)(event)\n } catch (error) {\n console.warn(`[agent-client] \"${String(name)}\" 事件处理器抛出异常:`, error)\n return false\n }\n return true\n }\n\n listenerCount(name: keyof Events): number {\n return this.handlers.get(name)?.size ?? 0\n }\n\n clear(): void {\n this.handlers.clear()\n }\n}\n","import type { TurnProjection } from \"../schemas/projection\"\n\nexport interface LiveRevisionState {\n current: number\n byTurnId: ReadonlyMap<string, number>\n}\n\nfunction sortedUnique(turns: TurnProjection[]): TurnProjection[] {\n const byId = new Map<string, TurnProjection>()\n for (const turn of turns) byId.set(turn.turn_id, turn)\n return [...byId.values()].sort((left, right) => left.sequence - right.sequence)\n}\n\n/** Add an older authoritative slice without allowing it to roll back live content. */\nexport function prependOlder(\n current: TurnProjection[],\n page: TurnProjection[],\n): TurnProjection[] {\n const currentById = new Map(current.map((turn) => [turn.turn_id, turn]))\n return sortedUnique([\n ...current,\n ...page.map((turn) => {\n const live = currentById.get(turn.turn_id)\n return live ? { ...live, sequence: turn.sequence } : turn\n }),\n ])\n}\n\n/** Install a new authoritative window, retaining only live writes newer than the request. */\nexport function replaceWindow(\n current: TurnProjection[],\n page: TurnProjection[],\n liveRevisionAtStart: number,\n liveRevisions: LiveRevisionState,\n): TurnProjection[] {\n const pageById = new Map(page.map((turn) => [turn.turn_id, turn]))\n const newerLive = current.filter(\n (turn) =>\n turn.turn_id.startsWith(\"local-user-\") ||\n (liveRevisions.byTurnId.get(turn.turn_id) ?? 0) > liveRevisionAtStart,\n )\n return sortedUnique([\n ...page,\n ...newerLive.map((turn) => {\n const snapshot = pageById.get(turn.turn_id)\n return snapshot ? { ...turn, sequence: snapshot.sequence } : turn\n }),\n ])\n}\n","import { isRecord } from \"../shared/type-guards\"\n\n/**\n * 会话消息队列的共享领域模型:类型、快照合并规则与中文文案。\n *\n * 这里是**单一定义处**:AgentSession 的状态机、agent-react 与内置 Web 的队列 UI\n * 都只用这一份判定,避免\"能不能编辑 / 旧快照要不要覆盖\"各写一遍后各自演进。\n * 服务端语义见 issue #2529 与 local://frontend-queue-contract.md。\n */\n\n/** 等待消息的服务端生命周期状态。 */\nexport type QueuedMessageStatus = \"pending\" | \"delivering\" | \"claimed\" | \"consumed\" | \"cancelled\"\n\n/** 队列里的一条等待消息;权威快照只包含 pending(等待执行)与 delivering(等待接收)。 */\nexport interface QueuedMessage {\n id: string\n content: string\n position: number\n version: number\n status: QueuedMessageStatus\n created_at: string\n updated_at: string\n /** 立即补充指向的当前运行 id;普通等待条目没有。 */\n target_run_id?: string\n /** 领取或投递失败的原因。 */\n error?: string\n}\n\n/** 服务端权威队列快照。`revision` 单调递增,客户端据此丢弃过期快照。 */\nexport interface SessionQueueSnapshot {\n session_id: string\n revision: number\n paused: boolean\n pause_reason: string | null\n items: QueuedMessage[]\n}\n\n/**\n * 还没有拿到服务端快照时的占位。\n *\n * `session_id` 为空表示\"身份未知\":`shouldApplySnapshot` 会跳过会话身份校验、\n * 只比较 revision,这样第一份快照(哪怕 revision 为 0 的暂停态)也能装进来。\n */\nexport const EMPTY_SESSION_QUEUE: SessionQueueSnapshot = {\n session_id: \"\",\n revision: 0,\n paused: false,\n pause_reason: null,\n items: [],\n}\n\n/**\n * 队列命令的 ack 线格式。\n *\n * `conflict` 表示乐观并发或状态校验失败,此时快照字段是服务端最新值,客户端必须\n * 据此刷新本地并保留用户草稿;`error` 时快照字段可能缺失(如鉴权失败),此时只报错、\n * 不改动本地队列。\n */\nexport interface QueueAck {\n /** `queued` 只出现在 `chat:send` 的运行中改道:消息已进等待队列,不是失败。 */\n status: \"ok\" | \"conflict\" | \"error\" | \"queued\"\n /**\n * 只有 `queued` 会带:服务端判定这次改道时该会话是否有运行。\n * 客户端据此对齐流式标记,不用自己的猜测。\n */\n running?: boolean\n message?: string | null\n session_id?: string\n revision?: number\n paused?: boolean\n pause_reason?: string | null\n items?: QueuedMessage[]\n}\n\n/** 解析后的队列操作结果;UI 只看这一个结构。 */\nexport interface QueueOperationResult {\n ok: boolean\n conflict: boolean\n /** 服务端快照;缺失时为 null,调用方不得据此清空本地队列。 */\n snapshot: SessionQueueSnapshot | null\n message: string | null\n}\n\nconst QUEUE_FAILURE_MESSAGE = \"队列操作失败\"\n\nconst QUEUED_MESSAGE_STATUSES: readonly string[] = [\n \"pending\",\n \"delivering\",\n \"claimed\",\n \"consumed\",\n \"cancelled\",\n]\n\nfunction toQueuedMessage(value: unknown): QueuedMessage | null {\n if (!isRecord(value)) return null\n const status =\n typeof value.status === \"string\" && QUEUED_MESSAGE_STATUSES.includes(value.status)\n ? (value.status as QueuedMessageStatus)\n : null\n if (\n typeof value.id !== \"string\" ||\n typeof value.content !== \"string\" ||\n typeof value.position !== \"number\" ||\n typeof value.version !== \"number\" ||\n typeof value.created_at !== \"string\" ||\n typeof value.updated_at !== \"string\" ||\n status === null\n ) {\n return null\n }\n const item: QueuedMessage = {\n id: value.id,\n content: value.content,\n position: value.position,\n version: value.version,\n status,\n created_at: value.created_at,\n updated_at: value.updated_at,\n }\n if (typeof value.target_run_id === \"string\") item.target_run_id = value.target_run_id\n if (typeof value.error === \"string\") item.error = value.error\n return item\n}\n\n/**\n * 把一份线格式载荷归一化成快照;结构不合法返回 null。\n * `session_id` 缺失时用 `fallbackSessionId` 补(ack 与广播都会带上它,补值只为防御)。\n */\nfunction toQueueSnapshot(value: unknown, fallbackSessionId: string): SessionQueueSnapshot | null {\n if (!isRecord(value)) return null\n if (\n typeof value.revision !== \"number\" ||\n !Number.isInteger(value.revision) ||\n value.revision < 0\n ) {\n return null\n }\n if (typeof value.paused !== \"boolean\") return null\n if (!Array.isArray(value.items)) return null\n const pauseReason = value.pause_reason\n if (pauseReason !== null && pauseReason !== undefined && typeof pauseReason !== \"string\") {\n return null\n }\n const items: QueuedMessage[] = []\n for (const raw of value.items) {\n const item = toQueuedMessage(raw)\n if (!item) return null\n items.push(item)\n }\n return {\n session_id:\n typeof value.session_id === \"string\" && value.session_id\n ? value.session_id\n : fallbackSessionId,\n revision: value.revision,\n paused: value.paused,\n pause_reason: typeof pauseReason === \"string\" ? pauseReason : null,\n items,\n }\n}\n\n/** 判定一份载荷是不是完整的权威队列快照(广播事件用)。 */\nexport function isSessionQueueSnapshot(value: unknown): value is SessionQueueSnapshot {\n if (!isRecord(value) || typeof value.session_id !== \"string\") return false\n return toQueueSnapshot(value, value.session_id) !== null\n}\n\n/**\n * 是否用 `next` 覆盖 `current`。\n *\n * 规则只有两条:会话身份必须一致(还没拿到过快照时不校验),且 revision 必须严格\n * 更新——相等或更旧一律不采纳,乱序到达的旧快照不会把新状态顶回去。\n */\nexport function shouldApplySnapshot(\n current: SessionQueueSnapshot | undefined,\n next: SessionQueueSnapshot,\n): boolean {\n if (!isSessionQueueSnapshot(next)) return false\n if (current?.session_id && next.session_id !== current.session_id) return false\n return next.revision > (current?.revision ?? -1)\n}\n\n/**\n * 解析 `emitWithAck` 的返回值。\n *\n * - `ok` / `queued` / `conflict` 且能解析成快照 → `snapshot` 有值;\n * - `queued` → `ok=true`:`chat:send` 在运行中改道进了等待队列,调用方要撤掉乐观消息;\n * - `conflict` → `ok=false, conflict=true`(快照可能仍缺失,调用方按 null 处理);\n * - `error` 或结构不合法 → `ok=false, conflict=false`,`message` 为服务端文案或兜底。\n */\nexport function parseQueueAck(response: unknown, fallbackSessionId: string): QueueOperationResult {\n if (!isRecord(response)) {\n return { ok: false, conflict: false, snapshot: null, message: QUEUE_FAILURE_MESSAGE }\n }\n const message =\n typeof response.message === \"string\" && response.message ? response.message : null\n const status = response.status\n if (status !== \"ok\" && status !== \"conflict\" && status !== \"queued\") {\n return { ok: false, conflict: false, snapshot: null, message: message ?? QUEUE_FAILURE_MESSAGE }\n }\n const snapshot = toQueueSnapshot(response, fallbackSessionId)\n if (status === \"conflict\") {\n return { ok: false, conflict: true, snapshot, message: message ?? QUEUE_FAILURE_MESSAGE }\n }\n if (!snapshot) {\n return { ok: false, conflict: false, snapshot: null, message: message ?? QUEUE_FAILURE_MESSAGE }\n }\n return { ok: true, conflict: false, snapshot, message }\n}\n\n/** 等待中的条目才能改正文;已经交给运行或开始执行的条目不再可编辑。 */\nexport function canEditQueuedMessage(item: QueuedMessage): boolean {\n return item.status === \"pending\"\n}\n\n/** 等待中的条目才能删除。 */\nexport function canCancelQueuedMessage(item: QueuedMessage): boolean {\n return item.status === \"pending\"\n}\n\n/**\n * 能否立即补充。条目本身必须是等待中的;\"会话是否正在运行\"由调用方判断——\n * 服务端会在没有可接收补充的任务时返回冲突。\n */\nexport function canDeliverQueuedMessage(item: QueuedMessage): boolean {\n return item.status === \"pending\"\n}\n\nconst QUEUED_MESSAGE_STATUS_LABELS: Record<QueuedMessageStatus, string> = {\n pending: \"待执行\",\n delivering: \"等待接收\",\n claimed: \"\",\n consumed: \"\",\n cancelled: \"\",\n}\n\n/** 面向前端展示的状态文案;已离开队列视图的状态没有文案。 */\nexport function queuedMessageStatusLabel(status: QueuedMessageStatus): string {\n return QUEUED_MESSAGE_STATUS_LABELS[status] ?? \"\"\n}\n\nconst QUEUE_PAUSE_REASON_LABELS: Record<string, string> = {\n user_stop: \"已暂停\",\n run_failed: \"任务异常已暂停\",\n run_unknown: \"任务结束状态未知,已暂停\",\n server_restart: \"服务重启已暂停\",\n}\n\n/** 暂停原因文案;未知原因原样透出,没有原因返回 null。 */\nexport function queuePauseReasonLabel(reason: string | null | undefined): string | null {\n if (!reason) return null\n return QUEUE_PAUSE_REASON_LABELS[reason] ?? reason\n}\n","import { isRecord } from \"../shared/type-guards\"\n\n/** Archived MCP App data. Credentials and executable server configuration are excluded. */\nexport interface McpAppData {\n sourceId: string\n resourceUri: string\n mimeType: string\n resourceMeta: Record<string, unknown>\n toolInput: Record<string, unknown>\n toolResult: Record<string, unknown>\n}\n\nexport interface McpAppArchive extends McpAppData {\n html: string\n plugin: string\n /** Restore the last successful view before delivering a saved failure. */\n previousToolInput?: Record<string, unknown>\n previousToolResult?: Record<string, unknown>\n}\n\nexport function isMcpAppData(value: unknown): value is McpAppData {\n return (\n isRecord(value) &&\n typeof value.sourceId === \"string\" && value.sourceId.length > 0 &&\n typeof value.resourceUri === \"string\" && value.resourceUri.startsWith(\"ui://\") &&\n typeof value.mimeType === \"string\" &&\n isRecord(value.resourceMeta) && isRecord(value.toolInput) && isRecord(value.toolResult)\n )\n}\n\n\n/** Latest model-context state one MCP App saved for its own card. */\nexport interface McpAppContextState {\n revision: string\n content: string\n plugin: string | null\n server_alias: string | null\n}\n\nexport interface McpAppContextUpdate {\n request_id: string\n /** null on the first save; the server rejects a stale revision. */\n expected_revision: string | null\n content: string\n}\n","import type { ChatMessage, ToolCallInfo } from \"../schemas/message\"\nimport type { ContentBlock } from \"../schemas/projection\"\nimport { isMcpAppData, type McpAppData } from \"../schemas/mcp-app\"\n\n/**\n * MCP App 卡片(`_meta.ui` → `tool_ui` block)的共享判定层。\n *\n * 判定逻辑不许各写一份(仓库 CLAUDE.md):agent-react 与 apps/web 都从这里消费卡片的\n * 实例、可见性、身份和终态规则;样式与状态容器(侧栏页签栈等)两侧各自实现。\n */\n\nexport interface ToolUiCard {\n resourceUri?: string\n resourceURI?: string\n resourceHTML?: string\n /** 历史投影标记:绝不重新解析 resourceUri(刷新不重放 MCP/资源读取)。 */\n archived?: boolean\n target: \"inline\" | \"preview\"\n height: number\n title?: string\n /** 留档的 MCP App 来源身份与调用数据(来源 server、ui:// 资源、CSP 元数据)。 */\n mcpApp?: McpAppData\n}\n\nfunction isNonEmptyString(value: unknown): value is string {\n return typeof value === \"string\" && value.trim().length > 0\n}\n\nfunction isPositiveNumber(value: unknown): value is number {\n return typeof value === \"number\" && Number.isFinite(value) && value > 0\n}\n\n/** 严格守卫:target/height 缺失、archived 无留档 HTML、或 mcpApp 来源身份残缺的\n * 卡片一律判无效,消息流、侧栏、toolPreview 事件三处一致降级(不渲染、不发事件、\n * 不推送)。后端 `_tool_ui_meta.py` 总会补齐 target/height 默认值,判无效即数据畸形。 */\nexport function isToolUiCard(value: unknown): value is ToolUiCard {\n if (typeof value !== \"object\" || value === null || Array.isArray(value)) {\n return false\n }\n const raw = value as Record<string, unknown>\n if (raw.target !== \"inline\" && raw.target !== \"preview\") {\n return false\n }\n if (!isPositiveNumber(raw.height)) {\n return false\n }\n if (raw.archived === true && !isNonEmptyString(raw.resourceHTML)) {\n return false\n }\n if (\n !isNonEmptyString(raw.resourceHTML) &&\n !isNonEmptyString(raw.resourceUri) &&\n !isNonEmptyString(raw.resourceURI)\n ) {\n return false\n }\n if (raw.title != null && !isNonEmptyString(raw.title)) {\n return false\n }\n if (raw.mcpApp !== undefined && !isMcpAppData(raw.mcpApp)) {\n return false\n }\n return true\n}\n\nexport type ToolUiCardContentType = \"resource-html\" | \"resource-uri\"\n\n/** 解析卡片实际要渲染的内容。archived 卡片只认留档 HTML,绝不回退到\n * resourceUri——历史恢复/浏览器刷新不得因此重新发起 MCP 资源读取。 */\nexport function resolveToolUiCardContent(\n card: ToolUiCard,\n): { type: ToolUiCardContentType; content: string } | null {\n if (isNonEmptyString(card.resourceHTML)) {\n return { type: \"resource-html\", content: card.resourceHTML }\n }\n if (card.archived) return null\n const uri = isNonEmptyString(card.resourceUri) ? card.resourceUri : card.resourceURI\n return isNonEmptyString(uri) ? { type: \"resource-uri\", content: uri } : null\n}\n\n/** 卡片实例身份/去重键:uri 卡片按内容去重(同一 URI 多次产出只留一份),\n * html 卡片按 toolCallId 去重(同一调用的新 HTML 覆盖旧内容)。 */\nexport function buildToolUiCardKey(\n toolCallId: string,\n type: ToolUiCardContentType,\n content: string,\n): string {\n if (type === \"resource-uri\") {\n return `tool-preview-uri:${content}`\n }\n return `tool-preview:${toolCallId}`\n}\n\n/** 内部「阶段进度」卡片不对用户展示入口。 */\nexport function isInternalStatusToolUiCard(card: { title?: string | null } | null): boolean {\n return card?.title?.trim() === \"阶段进度\"\n}\n\n/** app-dev 会话里的应用预览卡片:走专门的预览页签,不开普通侧栏 artifact。 */\nexport function isAppDevToolUiCard(card: ToolUiCard, isAppDev: boolean): boolean {\n return (\n isAppDev &&\n card.target === \"preview\" &&\n !card.resourceHTML &&\n Boolean(card.resourceUri || card.resourceURI)\n )\n}\n\nexport interface InlineToolUiCardEntry {\n key: string\n toolCallId: string\n card: ToolUiCard\n}\n\n/** 从一轮消息里收集 target=inline 的卡片(渲染进消息流)。 */\nexport function collectInlineToolUiCards(messages: ChatMessage[]): InlineToolUiCardEntry[] {\n return messages.flatMap((message) =>\n (message.blocks ?? []).flatMap((block, index) =>\n block.type === \"tool_ui\" &&\n block.tool_call_id &&\n isToolUiCard(block.content) &&\n block.content.target === \"inline\"\n ? [\n {\n key: `${message.entry_id ?? message.timestamp ?? \"message\"}-${block.tool_call_id}-${index}`,\n toolCallId: block.tool_call_id,\n card: block.content,\n },\n ]\n : [],\n ),\n )\n}\n\nexport interface PreviewToolUiCardEntry {\n key: string\n toolCall: ToolCallInfo\n card: ToolUiCard\n /** 所属消息的 blocks;调用方需要还原卡片所在 block 上下文时用。 */\n blocks: ContentBlock[]\n}\n\n/** 从一轮消息里收集 target=preview 的卡片(进侧栏/面板,不进消息流),\n * 并绑定回所属的 toolCall。 */\nexport function collectPreviewToolUiCards(messages: ChatMessage[]): PreviewToolUiCardEntry[] {\n return messages.flatMap((message) =>\n (message.blocks ?? []).flatMap((block, index) => {\n if (\n block.type !== \"tool_ui\" ||\n !block.tool_call_id ||\n !isToolUiCard(block.content) ||\n block.content.target !== \"preview\"\n ) {\n return []\n }\n const toolCall = (message.tool_calls ?? []).find(\n (candidate) => candidate.id === block.tool_call_id,\n )\n return toolCall\n ? [\n {\n key: `${message.entry_id ?? message.timestamp ?? \"message\"}-${block.tool_call_id}-${index}`,\n toolCall,\n card: block.content,\n blocks: message.blocks ?? [],\n },\n ]\n : []\n }),\n )\n}\n","import type {\n ChatMessage,\n FileContentPart,\n ImageUrlContentPart,\n MessageContent,\n MessageContentPart,\n} from \"./message\"\n\nconst SYSTEM_REMINDER_PATTERN = /^<system-reminder>\\s*[\\s\\S]*?\\s*<\\/system-reminder>$/i\nconst SYSTEM_NOTIFICATION_PATTERN =\n /^<system-notification>\\s*[\\s\\S]*?\\s*<\\/system-notification>$/i\nconst LEGACY_FORK_CONTEXT_MARKERS = [\n \"父智能体在派生你之前已经完成了一些操作。\",\n \"可通过 `read_file` 读取。\",\n \"# 你的任务\",\n]\nconst INTERNAL_CHAT_ERROR_PATTERNS = [\n /\\b(?:ENOENT|EACCES|EPERM)\\b/i,\n /\\[(?:Errno -?\\d+|WinError \\d+)\\]/i,\n /\\b(?:ECONNRESET|ECONNREFUSED|ETIMEDOUT|EHOSTUNREACH|ENETUNREACH|ENOTFOUND|EAI_AGAIN)\\b/i,\n /\\b(?:Connection refused|Connection reset by peer|All connection attempts failed|getaddrinfo failed)\\b/i,\n /(?:^|[\\s(\"'`])\\/(?:root|home|Users|tmp|var|opt|etc)\\//,\n /[A-Za-z]:\\\\(?:Users|Windows|Program Files|AppData)\\\\/i,\n /(?:^|\\n)Traceback \\(most recent call last\\):/,\n /(?:^|\\n)\\s*at\\s+\\S+(?:\\s+\\(|:\\d+:\\d+)/,\n /(?:^|\\n)File \"[^\"]+\", line \\d+/,\n]\nconst SAFE_CHAT_ERROR_PREFIXES = [\n \"沙盒运行环境暂时不可用,请稍后重试。\",\n \"模型服务暂时不可用,请检查模型配置后重试。\",\n]\nconst GENERIC_CHAT_ERROR = \"消息发送失败,请重试。\"\n\n/** Ordinary chat uses business copy; developer mode may retain diagnostics. */\nexport function chatErrorForDisplay(message: string, developer = false): string {\n const normalized = message.trim()\n if (!developer) {\n const safePrefix = SAFE_CHAT_ERROR_PREFIXES.find((prefix) => normalized.startsWith(prefix))\n if (safePrefix) return safePrefix\n }\n if (!developer && /no source matches this model/i.test(normalized)) {\n return \"当前模型暂时不可用,请稍后重试或重新选择模型。\"\n }\n if (!developer && INTERNAL_CHAT_ERROR_PATTERNS.some((pattern) => pattern.test(normalized))) {\n return GENERIC_CHAT_ERROR\n }\n return normalized || GENERIC_CHAT_ERROR\n}\n\nexport function normalizeMessageContent(content: unknown): MessageContent {\n if (typeof content === \"string\") return content\n if (Array.isArray(content)) return content as MessageContentPart[]\n return String(content ?? \"\")\n}\n\nexport function getTextContent(content: MessageContent): string {\n if (typeof content === \"string\") return content\n return content\n .filter((part) => part.type === \"text\")\n .map((part) => part.text)\n .join(\"\")\n}\n\nexport function isSystemReminderText(text: string): boolean {\n return SYSTEM_REMINDER_PATTERN.test(text.trim())\n}\n\nfunction isSystemNotificationText(text: string): boolean {\n return SYSTEM_NOTIFICATION_PATTERN.test(text.trim())\n}\n\nexport function isLegacyForkContextText(text: string): boolean {\n const normalized = text.trim()\n return LEGACY_FORK_CONTEXT_MARKERS.every((marker) => normalized.includes(marker))\n}\n\n/**\n * 平台自己写进去、不该露给用户的内部提示。\n *\n * 服务端的消息导航目录有一份同名同语义的 Python 实现\n * (`server/.../routes/sessions.py` 的 `_is_hidden_internal_message`):客户端靠它决定\n * 渲染不渲染,服务端靠它决定进不进目录。改这里必须同时改那边,否则目录会列出没有对应\n * 行的死条目,或者把内部提示原文当标题露出去。\n */\nexport function isHiddenInternalMessage(\n message: Pick<ChatMessage, \"role\" | \"content\">,\n options: { includeLegacyForkContext?: boolean } = {},\n): boolean {\n if (message.role !== \"user\") return false\n const text = getTextContent(normalizeMessageContent(message.content))\n return (\n isSystemReminderText(text) ||\n isSystemNotificationText(text) ||\n ((options.includeLegacyForkContext ?? true) && isLegacyForkContextText(text))\n )\n}\n\nexport function buildMessageContent(\n text: string,\n attachments: Array<{\n kind: \"file\"\n name: string\n uploadedPath?: string\n textContent?: string | null\n mimeType?: string\n }>,\n): MessageContent {\n if (attachments.length === 0) return text\n const textSegments: string[] = []\n\n if (text.trim()) {\n textSegments.push(text)\n }\n\n for (const attachment of attachments) {\n let fileText: string\n if (attachment.uploadedPath) {\n const displayName = attachment.uploadedPath.split(\"/\").pop() || attachment.name\n fileText = `[附件: ${displayName}] 已上传到工作区路径: ${attachment.uploadedPath}`\n } else if (attachment.textContent) {\n const MAX_TEXT_CHARS = 100_000\n const content =\n attachment.textContent.length > MAX_TEXT_CHARS\n ? `${attachment.textContent.slice(0, MAX_TEXT_CHARS)}\\n\\n[内容已截断,原始共 ${attachment.textContent.length} 字符]`\n : attachment.textContent\n fileText = `[附件: ${attachment.name}]\\n${content}`\n } else {\n fileText = `[附件: ${attachment.name}]`\n }\n textSegments.push(fileText)\n }\n\n return textSegments.join(\"\\n\\n\")\n}\n\nexport function contentPreview(content: MessageContent, maxLen = 80): string {\n const text = getTextContent(content).trim()\n return text.length > maxLen ? `${text.slice(0, maxLen)}…` : text\n}\n\n/** `/` 选中的技能当前处于什么状态,决定智能体要不要先装、先加载。 */\nexport interface SkillMentionAvailability {\n /** 本地已有(内置 / 技能目录 / 会话已加载),直接可用。 */\n local?: boolean\n /** Blade Hub 上该账号是否已安装。本地技能恒为 true。 */\n installed?: boolean\n}\n\n/**\n * Transform a skill mention into a natural language skill invocation.\n * Strips the `<skill>name</skill>` tag from the raw input and prepends the instruction.\n *\n * Hub 技能装没装、加载没加载,用户不需要知道,但智能体需要——所以把状态翻译\n * 成它能直接照做的 CLI 步骤。不传 availability 时按本地技能处理,与旧行为一致。\n */\nexport function transformSlashCommand(\n skillName: string,\n rawInput: string,\n { local = true, installed = true }: SkillMentionAvailability = {},\n): string {\n const prompt = rawInput.replace(`<skill>${skillName}</skill>`, \"\").trim()\n\n if (local) {\n return prompt\n ? `请使用 ${skillName} skill 完成任务\\n${prompt}`\n : `请使用 ${skillName} skill 完成任务`\n }\n\n const steps = installed\n ? `请先运行 blade hub skill use ${skillName} 加载技能`\n : `该技能尚未安装。请先运行 blade hub skill install ${skillName} 安装,` +\n `再运行 blade hub skill use ${skillName} 加载`\n return prompt ? `${steps},然后完成任务:\\n${prompt}` : `${steps},然后使用它完成任务`\n}\n\nconst ATTACHMENT_TAG_RE = /\\[附件:\\s*([^\\]]+)\\](?:[ \\t]*已上传到工作区路径:[ \\t]*([^\\r\\n]+))?/g\n// 来自 addContext 的 context 在发送时序列化为独立 text part:`[上下文: LABEL]\\nCONTENT`\n// 整块 part 匹配而非行内替换,避免破坏正文中可能出现的\"[上下文:\"字样\nconst CONTEXT_PART_RE = /^\\[上下文:\\s*([^\\]]+)\\]\\n([\\s\\S]*)$/\n\nexport interface ParsedTextAttachment {\n name: string\n uploadedPath?: string\n}\n\nexport interface ParsedTextContext {\n label: string\n content: string\n}\n\n/**\n * Extract `[附件: name]` and `[上下文: label]` tags from text parts and return\n * the cleaned text plus the collected attachment / context metadata. 每个 text\n * part 独立匹配,以避免跨 part 拼接打乱正则。\n */\nexport function extractTextAttachments(content: MessageContent): {\n cleanText: string\n attachments: ParsedTextAttachment[]\n contexts: ParsedTextContext[]\n} {\n if (typeof content === \"string\") {\n const attachments: ParsedTextAttachment[] = []\n const contexts: ParsedTextContext[] = []\n const ctxMatch = CONTEXT_PART_RE.exec(content)\n let working = content\n if (ctxMatch) {\n contexts.push({ label: ctxMatch[1].trim(), content: ctxMatch[2].trim() })\n working = \"\"\n }\n for (const match of working.matchAll(ATTACHMENT_TAG_RE)) {\n attachments.push({\n name: match[1].trim(),\n uploadedPath: match[2]?.trim() || undefined,\n })\n }\n return {\n cleanText: working.replace(ATTACHMENT_TAG_RE, \"\"),\n attachments,\n contexts,\n }\n }\n\n const attachments: ParsedTextAttachment[] = []\n const contexts: ParsedTextContext[] = []\n const cleanParts: string[] = []\n\n for (const part of content) {\n if (part.type !== \"text\") continue\n\n const ctxMatch = CONTEXT_PART_RE.exec(part.text)\n if (ctxMatch) {\n contexts.push({ label: ctxMatch[1].trim(), content: ctxMatch[2].trim() })\n continue\n }\n\n let hasAttachment = false\n for (const match of part.text.matchAll(ATTACHMENT_TAG_RE)) {\n attachments.push({\n name: match[1].trim(),\n uploadedPath: match[2]?.trim() || undefined,\n })\n hasAttachment = true\n }\n if (hasAttachment) {\n const remaining = part.text.replace(ATTACHMENT_TAG_RE, \"\")\n if (remaining.trim()) cleanParts.push(remaining)\n } else {\n cleanParts.push(part.text)\n }\n }\n\n return { cleanText: cleanParts.join(\"\\n\"), attachments, contexts }\n}\n\nexport function getImageParts(content: MessageContent): ImageUrlContentPart[] {\n if (typeof content === \"string\") return []\n return content.filter((part): part is ImageUrlContentPart => part.type === \"image_url\")\n}\n\nexport function getFileParts(content: MessageContent): FileContentPart[] {\n if (typeof content === \"string\") return []\n return content.filter((part): part is FileContentPart => part.type === \"file\")\n}\n\ninterface MessageGroup {\n root: ChatMessage | null\n childLoops: { loopName: string; messages: ChatMessage[] }[]\n}\n\nexport function groupMessagesByLoop(messages: ChatMessage[]): MessageGroup[] {\n const groups: MessageGroup[] = []\n let currentGroup: MessageGroup | null = null\n\n for (const msg of messages) {\n const loop = msg.loop_name ?? \"root\"\n\n if (loop === \"root\") {\n currentGroup = { root: msg, childLoops: [] }\n groups.push(currentGroup)\n } else {\n if (!currentGroup) {\n currentGroup = { root: null, childLoops: [] }\n groups.push(currentGroup)\n }\n const existingLoop = currentGroup.childLoops.find((l) => l.loopName === loop)\n if (existingLoop) {\n existingLoop.messages.push(msg)\n } else {\n currentGroup.childLoops.push({ loopName: loop, messages: [msg] })\n }\n }\n }\n\n return groups\n}\n","import type { ChatMessage, CompactionInfo, MessageContent, ToolCallInfo } from \"../schemas/message\"\nimport { normalizeMessageContent } from \"../schemas/message-utils\"\nimport type { ContentBlock, PatchEnvelope, TurnProjection } from \"../schemas/projection\"\nimport { contextProjectionData } from \"../schemas/context\"\nimport type { ReplaySpeed, ReplayState, SessionStatus } from \"../schemas/session\"\nimport { isRecord } from \"../shared/type-guards\"\nimport { EMPTY_SESSION_QUEUE, shouldApplySnapshot, type SessionQueueSnapshot } from \"./queue\"\n\n/** 一次 AskUserQuestion 的用户作答(选项选择 + 自定义输入 + 可选补充)。 */\nexport interface AskUserAnswerData {\n selections: Record<number, number[]>\n custom: Record<number, string>\n /** 选完选项后的自由补充,空着就是没有。 */\n note?: string\n}\n\nexport interface AgentLoopInfo {\n toolCallId: string\n description: string\n status: \"running\" | \"done\" | \"error\" | \"cancelled\" | \"awaiting_answer\"\n}\n\nexport interface ActiveCompactionState extends CompactionInfo {\n turn_id: string\n status: \"streaming\" | \"completed\" | \"paused\" | \"failed\" | \"interrupted\"\n}\n\nexport type ConnectionStatus = \"connecting\" | \"connected\" | \"reconnecting\" | \"disconnected\"\n\n/**\n * 一个会话的完整快照。引用不可变:任何变更都会产生新对象,\n * 满足 React `useSyncExternalStore` / Vue `shallowRef` 的订阅契约。\n */\nexport interface SessionState {\n sessionId: string\n /** 服务端投影的原始 turn 列表(按 sequence 有序)。 */\n turns: TurnProjection[]\n /** 由 turns 物化出的聊天消息列表,UI 直接渲染。 */\n messages: ChatMessage[]\n /** 智能体是否正在流式回复。 */\n isStreaming: boolean\n /** 会话状态(running / completed / failed / waiting_for_input / interrupted …)。 */\n status: SessionStatus | null\n /** 当前模式(planning / executing),来自 mode_change 事件。 */\n mode: \"planning\" | \"executing\" | null\n /** Socket.IO 连接状态(同一 client 下所有会话共享)。 */\n connection: ConnectionStatus\n /** 最近一次运行错误消息(system:error 等)。 */\n errorMessage: string | null\n askAnswers: Record<string, AskUserAnswerData>\n agentLoops: Record<string, AgentLoopInfo>\n activeCompaction: ActiveCompactionState | null\n /** 回放(演示 / 彩排)状态;不是回放会话时为 null。 */\n replay: ReplaySnapshot | null\n /** 服务端持久化的等待消息队列快照;只在 revision 更新时替换。 */\n queue: SessionQueueSnapshot\n /** 当前身份对这个会话的权限;\"viewer\" 表示只读(分享链接打开的)。 */\n viewerRole: \"owner\" | \"viewer\" | null\n /** Stable anchor for the next older projected page. */\n nextBefore: string | null\n loadingOlder: boolean\n}\n\n/** 回放会话的快照视图,由服务端的 replay_state 归一化而来。 */\nexport interface ReplaySnapshot {\n /** 仍在按录制内容走;转自主运行后为 false。 */\n isReplay: boolean\n speed: ReplaySpeed\n sourceSessionId: string | null\n}\n\n/** 把服务端的 replay_state 归一化成快照;不是回放会话时返回 null。 */\nexport function toReplaySnapshot(raw: ReplayState | null | undefined): ReplaySnapshot | null {\n if (!raw || !raw.status) return null\n return {\n isReplay: raw.status === \"replay\",\n speed: raw.speed ?? 1,\n sourceSessionId: raw.source_session_id ?? null,\n }\n}\n\nexport function createInitialSessionState(sessionId: string): SessionState {\n return {\n sessionId,\n turns: [],\n messages: [],\n isStreaming: false,\n status: null,\n mode: null,\n connection: \"disconnected\",\n errorMessage: null,\n askAnswers: {},\n agentLoops: {},\n activeCompaction: null,\n replay: null,\n queue: EMPTY_SESSION_QUEUE,\n viewerRole: null,\n nextBefore: null,\n loadingOlder: false,\n }\n}\n\nfunction parseAgentDescription(argumentsJson: string): string {\n try {\n return JSON.parse(argumentsJson)?.description ?? \"子智能体\"\n } catch {\n return \"子智能体\"\n }\n}\n\n/** 与 react 端 display-utils.formatToolName 保持一致:去掉 provider 前缀(如 \"fork:Agent\" → \"Agent\")。 */\nfunction normalizedToolName(name: string): string {\n const separatorIndex = name.lastIndexOf(\":\")\n return separatorIndex >= 0 ? name.slice(separatorIndex + 1) : name\n}\n\nfunction inferLoopStatusFromMessages(messages: ChatMessage[]): AgentLoopInfo[\"status\"] {\n const toolCalls = messages.flatMap((message) => message.tool_calls ?? [])\n if (messages.some((message) => message.status === \"streaming\")) return \"running\"\n if (messages.some((message) => message.status === \"failed\")) return \"error\"\n if (toolCalls.some((toolCall) => toolCall.status === \"awaiting_answer\")) return \"awaiting_answer\"\n if (toolCalls.some((toolCall) => toolCall.status === \"error\")) return \"error\"\n if (toolCalls.some((toolCall) => toolCall.status === \"cancelled\")) return \"cancelled\"\n if (toolCalls.some((toolCall) => toolCall.status === \"pending\")) return \"running\"\n return \"done\"\n}\n\nfunction inferLoopStatusFromTurns(\n turns: TurnProjection[],\n messages: ChatMessage[],\n): AgentLoopInfo[\"status\"] {\n const latestAgentNotification = [...turns]\n .reverse()\n .flatMap((turn) => turn.blocks)\n .find((block) => {\n if (block.type !== \"system_notification\" || !isRecord(block.content)) return false\n return (\n block.content.notification_type === \"agent:start\" ||\n block.content.notification_type === \"agent:end\"\n )\n })\n if (\n latestAgentNotification?.type === \"system_notification\" &&\n isRecord(latestAgentNotification.content)\n ) {\n const notificationType = latestAgentNotification.content.notification_type\n const status = latestAgentNotification.content.status\n if (notificationType === \"agent:start\" || status === \"running\") return \"running\"\n if (status === \"error\") return \"error\"\n if (status === \"cancelled\") return \"cancelled\"\n }\n return inferLoopStatusFromMessages(messages)\n}\n\nfunction toSelectionMap(value: unknown): Record<number, number[]> {\n if (!isRecord(value)) return {}\n const entries = Object.entries(value)\n .map(([questionKey, optionIndexes]) => {\n if (!Array.isArray(optionIndexes)) return null\n const parsedIndexes = optionIndexes\n .map((item) => (typeof item === \"number\" ? item : Number(item)))\n .filter((item) => Number.isInteger(item))\n return [Number(questionKey), parsedIndexes] as const\n })\n .filter((entry): entry is readonly [number, number[]] => entry !== null)\n return Object.fromEntries(entries) as Record<number, number[]>\n}\n\nfunction toCustomMap(value: unknown): Record<number, string> {\n if (!isRecord(value)) return {}\n const entries = Object.entries(value)\n .filter(([, text]) => typeof text === \"string\")\n .map(([questionKey, text]) => [Number(questionKey), text] as const)\n return Object.fromEntries(entries) as Record<number, string>\n}\n\nfunction extractAskAnswers(turns: TurnProjection[]): Record<string, AskUserAnswerData> {\n const answers: Record<string, AskUserAnswerData> = {}\n for (const turn of turns) {\n for (const block of turn.blocks) {\n if (block.type !== \"ask_user_answer\" || typeof block.tool_call_id !== \"string\") continue\n if (!isRecord(block.content)) continue\n const note = typeof block.content.note === \"string\" ? block.content.note.trim() : \"\"\n answers[block.tool_call_id] = {\n selections: toSelectionMap(block.content.selections),\n custom: toCustomMap(block.content.custom),\n ...(note ? { note } : {}),\n }\n }\n }\n return answers\n}\n\nfunction parentForkToolCallIdFromTurn(turn: TurnProjection): string | null {\n if (\n typeof turn.parent_fork_tool_call_id === \"string\" &&\n turn.parent_fork_tool_call_id.length > 0\n ) {\n return turn.parent_fork_tool_call_id\n }\n for (const block of turn.blocks) {\n if (block.type !== \"system_notification\" || !isRecord(block.content)) continue\n const metadata = block.content.metadata\n if (!isRecord(metadata)) continue\n const parentId = metadata.parent_fork_tool_call_id\n if (typeof parentId === \"string\" && parentId.length > 0) return parentId\n }\n return null\n}\n\nfunction buildMessageContent(turn: TurnProjection): MessageContent {\n const textBlocks = turn.blocks.filter((block) => block.type === \"text\")\n if (textBlocks.length === 0) return \"\"\n if (textBlocks.length === 1) return normalizeMessageContent(textBlocks[0].content)\n return textBlocks\n .map((block) => {\n if (typeof block.content === \"string\") return block.content\n return JSON.stringify(block.content)\n })\n .join(\"\")\n}\n\nfunction workspaceNotificationContent(turn: TurnProjection): string {\n const block = turn.blocks.find(\n (candidate) =>\n candidate.type === \"system_notification\" &&\n isRecord(candidate.content) &&\n candidate.content.notification_type === \"workspace_change\",\n )\n if (!block || !isRecord(block.content)) return \"\"\n const title = typeof block.content.title === \"string\" ? block.content.title.trim() : \"\"\n const detail = typeof block.content.detail === \"string\" ? block.content.detail.trim() : \"\"\n return [title ? `**${title}**` : \"\", detail].filter(Boolean).join(\"\\n\\n\")\n}\n\nfunction askUserAnswerContent(turn: TurnProjection): string | null {\n const answerBlock = turn.blocks.find((block) => block.type === \"ask_user_answer\")\n if (!answerBlock || !isRecord(answerBlock.content)) return null\n const answer = answerBlock.content.answer\n return typeof answer === \"string\" && answer.trim().length > 0 ? answer : null\n}\n\nfunction buildReasoning(turn: TurnProjection): string | undefined {\n const thinking = turn.blocks\n .filter((block) => block.type === \"thinking\")\n .map((block) => (typeof block.content === \"string\" ? block.content : JSON.stringify(block.content)))\n .filter(Boolean)\n if (thinking.length === 0) return undefined\n return thinking.join(\"\\n\\n\")\n}\n\nfunction isModeChangeContent(value: unknown): value is { from: string; to: string } {\n return (\n typeof value === \"object\" &&\n value !== null &&\n typeof (value as { from?: unknown }).from === \"string\" &&\n typeof (value as { to?: unknown }).to === \"string\"\n )\n}\n\nexport function extractModeFromBlocks(blocks: ContentBlock[]): \"planning\" | \"executing\" | null {\n const modeBlock = blocks.find((block) => block.type === \"mode_change\")\n if (modeBlock && isModeChangeContent(modeBlock.content)) {\n return modeBlock.content.to === \"planning\" || modeBlock.content.to === \"executing\"\n ? modeBlock.content.to\n : null\n }\n return null\n}\n\nfunction projectionToMessage(turn: TurnProjection): ChatMessage | null {\n if (turn.kind === \"context\") {\n const context = contextProjectionData(turn)\n if (!context) return null\n return {\n role: \"assistant\",\n content: \"\",\n kind: \"context\",\n context,\n loop_name: turn.loop_id,\n entry_id: turn.turn_id,\n status: turn.status,\n }\n }\n if (turn.kind === \"compaction\" && turn.compaction_id) {\n return {\n role: \"assistant\",\n content: turn.summary_preview ?? \"\",\n kind: \"compaction\",\n loop_name: turn.loop_id,\n entry_id: turn.turn_id,\n status: turn.status,\n compaction: {\n compaction_id: turn.compaction_id,\n summary_preview: turn.summary_preview,\n summary_full: turn.summary_full,\n archived_count: turn.archived_count,\n archived_files: turn.archived_files,\n archived_tool_calls: turn.archived_tool_calls,\n tokens_before: turn.tokens_before,\n tokens_after: turn.tokens_after,\n saved_ratio: turn.saved_ratio,\n trigger: turn.trigger,\n failure_reason: turn.failure_reason,\n fallback_applied: turn.fallback_applied,\n },\n }\n }\n\n const planningBlock = turn.blocks.find(\n (block) => block.type === \"mode_change\" || block.type === \"plan_status\",\n )\n if (planningBlock) {\n if (planningBlock.type === \"plan_status\") {\n return {\n role: \"tool\",\n content:\n typeof planningBlock.content === \"string\"\n ? planningBlock.content\n : JSON.stringify(planningBlock.content ?? {}, null, 2),\n kind: \"plan_status\",\n loop_name: turn.loop_id,\n entry_id: turn.turn_id,\n status: turn.status,\n }\n }\n return {\n role: \"assistant\",\n content:\n typeof planningBlock.content === \"string\"\n ? planningBlock.content\n : JSON.stringify(planningBlock.content ?? {}),\n kind: planningBlock.type,\n loop_name: turn.loop_id,\n entry_id: turn.turn_id,\n status: turn.status,\n }\n }\n\n const askAnswer = askUserAnswerContent(turn)\n if (askAnswer !== null) {\n return {\n role: \"user\",\n content: askAnswer,\n blocks: turn.blocks,\n loop_name: turn.loop_id,\n entry_id: turn.turn_id,\n status: turn.status,\n ...(typeof turn.duration_ms === \"number\" ? { duration_ms: turn.duration_ms } : {}),\n ...(turn.started_at ? { timestamp: turn.started_at } : {}),\n }\n }\n\n const content = buildMessageContent(turn) || workspaceNotificationContent(turn)\n const reasoning = buildReasoning(turn)\n const toolCalls: ToolCallInfo[] | undefined =\n turn.tool_calls.length > 0\n ? turn.tool_calls.map((toolCall) => ({\n id: toolCall.id,\n name: toolCall.tool_name,\n display_name: toolCall.display_name,\n arguments: toolCall.arguments,\n result: toolCall.result ?? undefined,\n pending_question_ref: toolCall.pending_question_ref ?? undefined,\n status:\n toolCall.status === \"pending\" ||\n toolCall.status === \"awaiting_answer\" ||\n toolCall.status === \"done\" ||\n toolCall.status === \"error\" ||\n toolCall.status === \"cancelled\"\n ? toolCall.status\n : \"pending\",\n ...(typeof toolCall.duration_ms === \"number\" ? { duration_ms: toolCall.duration_ms } : {}),\n }))\n : undefined\n\n if (turn.role === \"system\" && !content && !toolCalls?.length) {\n return null\n }\n\n return {\n role: turn.role === \"system\" ? \"assistant\" : turn.role,\n content,\n blocks: turn.blocks,\n ...(reasoning ? { reasoning } : {}),\n ...(toolCalls ? { tool_calls: toolCalls } : {}),\n loop_name: turn.loop_id,\n entry_id: turn.turn_id,\n status: turn.status,\n ...(typeof turn.duration_ms === \"number\" ? { duration_ms: turn.duration_ms } : {}),\n ...(turn.started_at ? { timestamp: turn.started_at } : {}),\n ...(turn.memory_refs?.length ? { memory_refs: turn.memory_refs } : {}),\n }\n}\n\nconst messageProjectionCache = new WeakMap<TurnProjection, ChatMessage | null>()\n\nfunction cachedProjectionToMessage(turn: TurnProjection): ChatMessage | null {\n if (messageProjectionCache.has(turn)) {\n return messageProjectionCache.get(turn) ?? null\n }\n const message = projectionToMessage(turn)\n messageProjectionCache.set(turn, message)\n return message\n}\n\nfunction rebuildAgentLoops(\n turns: TurnProjection[],\n messages: ChatMessage[],\n): Record<string, AgentLoopInfo> {\n const childLoopNames = [\n ...new Set(turns.map((turn) => turn.loop_id).filter((name) => name !== \"root\")),\n ]\n if (childLoopNames.length === 0) return {}\n\n const agentToolCalls = messages\n .filter((message) => message.role === \"assistant\" && (message.loop_name ?? \"root\") === \"root\")\n .flatMap((message) => message.tool_calls ?? [])\n .filter((toolCall) => normalizedToolName(toolCall.name) === \"Agent\")\n\n const loops: Record<string, AgentLoopInfo> = {}\n const agentToolCallsById = new Map(agentToolCalls.map((toolCall) => [toolCall.id, toolCall]))\n const explicitParentToolCallIds = new Set(\n turns.map(parentForkToolCallIdFromTurn).filter((id): id is string => id !== null),\n )\n const usedToolCallIds = new Set<string>()\n for (const loopName of childLoopNames) {\n const loopMessages = messages.filter((message) => (message.loop_name ?? \"root\") === loopName)\n const loopTurns = turns.filter((turn) => turn.loop_id === loopName)\n const parentToolCallId = loopTurns.map(parentForkToolCallIdFromTurn).find(Boolean)\n const explicitToolCall =\n parentToolCallId && !usedToolCallIds.has(parentToolCallId)\n ? (agentToolCallsById.get(parentToolCallId) ?? null)\n : null\n const fallbackToolCall =\n explicitToolCall === null\n ? agentToolCalls.find(\n (toolCall) =>\n !usedToolCallIds.has(toolCall.id) && !explicitParentToolCallIds.has(toolCall.id),\n )\n : null\n const toolCall = explicitToolCall ?? fallbackToolCall\n if (!toolCall) continue\n usedToolCallIds.add(toolCall.id)\n loops[loopName] = {\n toolCallId: toolCall.id,\n description: parseAgentDescription(toolCall.arguments),\n status: inferLoopStatusFromTurns(loopTurns, loopMessages),\n }\n }\n return loops\n}\n\nfunction materialize(turns: TurnProjection[]) {\n const projectedMessages = turns\n .map(cachedProjectionToMessage)\n .filter((message): message is ChatMessage => message !== null)\n const messages = projectedMessages.filter((message, index, allMessages) => {\n if (!message.blocks?.some((block) => block.type === \"ask_user_answer\")) return true\n const next = allMessages[index + 1]\n return !(next?.role === \"user\" && next.content === message.content)\n })\n const activeCompaction = [...turns]\n .reverse()\n .find(\n (turn): turn is TurnProjection =>\n turn.kind === \"compaction\" &&\n turn.status === \"streaming\" &&\n typeof turn.compaction_id === \"string\",\n )\n return {\n messages,\n agentLoops: rebuildAgentLoops(turns, projectedMessages),\n activeCompaction: activeCompaction\n ? {\n turn_id: activeCompaction.turn_id,\n status: activeCompaction.status,\n compaction_id: activeCompaction.compaction_id!,\n summary_preview: activeCompaction.summary_preview,\n summary_full: activeCompaction.summary_full,\n archived_count: activeCompaction.archived_count,\n archived_files: activeCompaction.archived_files,\n archived_tool_calls: activeCompaction.archived_tool_calls,\n tokens_before: activeCompaction.tokens_before,\n tokens_after: activeCompaction.tokens_after,\n saved_ratio: activeCompaction.saved_ratio,\n trigger: activeCompaction.trigger,\n failure_reason: activeCompaction.failure_reason,\n fallback_applied: activeCompaction.fallback_applied,\n }\n : null,\n }\n}\n\nconst ERROR_ANCHOR_PREFIX = \"error-anchor:\"\n\nfunction orderTurns(turns: TurnProjection[]) {\n for (let index = 1; index < turns.length; index += 1) {\n if (turns[index - 1].sequence > turns[index].sequence) {\n return [...turns].sort((left, right) => left.sequence - right.sequence)\n }\n }\n return turns\n}\n\nexport function reconcileOptimisticUserTurns(\n currentTurns: TurnProjection[],\n incomingTurns: TurnProjection[],\n): TurnProjection[] {\n return reconcileUserTurns(currentTurns, incomingTurns, true, false)\n}\n\n/** Reconcile a bulk authoritative window only by an echoed request identity.\n * Positional fallback is reserved for a single live turn from an older server. */\nexport function reconcileHistoricalUserTurns(\n currentTurns: TurnProjection[],\n incomingTurns: TurnProjection[],\n): TurnProjection[] {\n // keepUnclaimedOptimistic=true:这批全量快照可能是在本地刚发出一条新\n // 乐观发言之前就拍下的,还不知道它的存在。只按 incomingTurns 重建整个\n // 列表会把这条还没被任何一批快照/事件认领过的本地发言直接丢掉,直到\n // 下一次增量事件到达才重新出现——这段\"消失又出现\"的窗口期会让消费方\n // (比如 MessageList.tsx 的\"新发言顶置\")把\"最新用户发言\"短暂退回上一条,\n // 误判成锚点回滚而提前释放顶置。没被这批快照认领的本地乐观发言应该原样\n // 保留在结果里,等真正的确认/回滚事件到达时再处理。\n return reconcileUserTurns(currentTurns, incomingTurns, false, true)\n}\n\nfunction reconcileUserTurns(\n currentTurns: TurnProjection[],\n incomingTurns: TurnProjection[],\n allowLiveFallback: boolean,\n keepUnclaimedOptimistic: boolean,\n): TurnProjection[] {\n const preservedTurns = preserveClientRenderIds(currentTurns, incomingTurns)\n const optimisticUserTurns = currentTurns.filter(\n (turn) =>\n turn.role === \"user\" &&\n (turn.kind ?? \"message\") === \"message\" &&\n turn.turn_id.startsWith(\"local-user-\"),\n )\n const optimisticByRequestId = new Map(\n optimisticUserTurns.map((turn) => [\n turn.turn_id.slice(\"local-user-\".length),\n turn,\n ]),\n )\n const currentTurnIds = new Set(currentTurns.map((turn) => turn.turn_id))\n const claimedOptimisticIds = new Set<string>()\n const reconciled = preservedTurns.map((turn) => {\n const exactOptimistic =\n typeof turn.client_request_id === \"string\"\n ? optimisticByRequestId.get(turn.client_request_id)\n : undefined\n if (\n exactOptimistic &&\n !claimedOptimisticIds.has(exactOptimistic.turn_id) &&\n isUserConfirmation(turn)\n ) {\n claimedOptimisticIds.add(exactOptimistic.turn_id)\n return { ...turn, client_render_id: exactOptimistic.turn_id }\n }\n const fallbackOptimistic = optimisticUserTurns.find(\n (candidate) => !claimedOptimisticIds.has(candidate.turn_id),\n )\n if (\n allowLiveFallback &&\n typeof turn.client_request_id !== \"string\" &&\n fallbackOptimistic &&\n isUserConfirmation(turn) &&\n !turn.turn_id.startsWith(\"local-user-\") &&\n !currentTurnIds.has(turn.turn_id)\n ) {\n claimedOptimisticIds.add(fallbackOptimistic.turn_id)\n return { ...turn, client_render_id: fallbackOptimistic.turn_id }\n }\n return turn\n })\n const result =\n claimedOptimisticIds.size === 0\n ? reconciled\n : reconciled.filter((turn) => !claimedOptimisticIds.has(turn.turn_id))\n if (!keepUnclaimedOptimistic) return result\n // 只补回真正从结果里缺席的乐观 turn——claimedOptimisticIds 只覆盖\"这次调用\n // 里用 client_request_id/位置兜底重新认领过\"的情况,reconcile 一个已经\n // 包含这条乐观 turn 本身的列表(比如 upsertTurn 认领替换完之后,\n // withTurns 内部拿最终列表对自己再 reconcile 一遍)时,它既没被这次调用\n // 认领、也已经原样出现在 result 里,不能再重复拼一份。\n const resultIds = new Set(result.map((turn) => turn.turn_id))\n const unclaimedOptimisticTurns = optimisticUserTurns.filter(\n (turn) => !claimedOptimisticIds.has(turn.turn_id) && !resultIds.has(turn.turn_id),\n )\n return unclaimedOptimisticTurns.length === 0\n ? result\n : orderTurns([...result, ...unclaimedOptimisticTurns])\n}\n\nfunction isUserConfirmation(turn: TurnProjection): boolean {\n return (\n (turn.role === \"user\" && (turn.kind ?? \"message\") === \"message\") ||\n turn.blocks.some((block) => block.type === \"ask_user_answer\")\n )\n}\n\n/** Preserve render identity only for the same authoritative turn. Bulk history\n * replacement must not infer that an unrelated historical user confirms a\n * retained optimistic user turn. */\nfunction preserveClientRenderIds(\n currentTurns: TurnProjection[],\n incomingTurns: TurnProjection[],\n): TurnProjection[] {\n const currentById = new Map(currentTurns.map((turn) => [turn.turn_id, turn]))\n return incomingTurns.map((turn) => {\n const current = currentById.get(turn.turn_id)\n if (current) {\n const currentRenderId = current.client_render_id\n return turn.client_render_id || !currentRenderId\n ? turn\n : { ...turn, client_render_id: currentRenderId }\n }\n return turn\n })\n}\n\nfunction areAgentLoopsEqual(\n left: Record<string, AgentLoopInfo> | undefined,\n right: Record<string, AgentLoopInfo>,\n) {\n if (!left) return Object.keys(right).length === 0\n const leftEntries = Object.entries(left)\n const rightKeys = Object.keys(right)\n if (leftEntries.length !== rightKeys.length) return false\n return leftEntries.every(([key, value]) => {\n const next = right[key]\n return (\n next !== undefined &&\n value.toolCallId === next.toolCallId &&\n value.description === next.description &&\n value.status === next.status\n )\n })\n}\n\n/**\n * 用一份新的 turn 列表重建会话状态。\n * addErrorMessage 注入的 role===\"error\" 消息不在 turns 里,默认会被物化过程抹掉;\n * 这里沿用锚点策略:只保留锚定在\"当前最后一个 turn\"上的错误气泡,\n * turn 推进(新消息 / rewind / 重连)时旧错误自动消失。\n */\nexport function withTurns(state: SessionState, turns: TurnProjection[]): SessionState {\n const orderedTurns = orderTurns(reconcileHistoricalUserTurns(state.turns, turns))\n const { messages, agentLoops, activeCompaction } = materialize(orderedTurns)\n const isWaitingForInput = orderedTurns.some((turn) =>\n turn.tool_calls.some((toolCall) => toolCall.status === \"awaiting_answer\"),\n )\n const stableAgentLoops = areAgentLoopsEqual(state.agentLoops, agentLoops)\n ? state.agentLoops\n : agentLoops\n const lastTurnId = orderedTurns[orderedTurns.length - 1]?.turn_id ?? null\n const preservedErrors = lastTurnId\n ? state.messages.filter(\n (m) =>\n m.role === \"error\" &&\n typeof m.entry_id === \"string\" &&\n m.entry_id.startsWith(`${ERROR_ANCHOR_PREFIX}${lastTurnId}:`),\n )\n : []\n const turnById = new Map(orderedTurns.map((turn) => [turn.turn_id, turn]))\n const messagesWithRenderIds = messages.map((message) => {\n if (!message.entry_id) return message\n const renderId = turnById.get(message.entry_id)?.client_render_id\n return renderId ? { ...message, render_id: renderId } : message\n })\n const mergedMessages =\n preservedErrors.length > 0\n ? [...messagesWithRenderIds, ...preservedErrors]\n : messagesWithRenderIds\n const latestMode = [...orderedTurns]\n .reverse()\n .map((turn) => extractModeFromBlocks(turn.blocks))\n .find((mode): mode is \"planning\" | \"executing\" => mode !== null)\n const askAnswersFromHistory = extractAskAnswers(orderedTurns)\n const presentToolCallIds = new Set(\n orderedTurns.flatMap((turn) => turn.tool_calls.map((toolCall) => toolCall.id)),\n )\n const askAnswers: Record<string, AskUserAnswerData> = { ...askAnswersFromHistory }\n for (const [toolCallId, answer] of Object.entries(state.askAnswers)) {\n if (!(toolCallId in askAnswers) && presentToolCallIds.has(toolCallId)) {\n askAnswers[toolCallId] = answer\n }\n }\n return {\n ...state,\n turns: orderedTurns,\n messages: mergedMessages,\n agentLoops: stableAgentLoops,\n activeCompaction,\n askAnswers,\n mode: latestMode ?? state.mode,\n // 历史恢复时 chat:end(paused) 可能已不在 socket replay 缓存中;\n // awaiting_answer 是投影里的持久权威状态,必须据此恢复问答交互。\n status: isWaitingForInput ? \"waiting_for_input\" : state.status,\n }\n}\n\n/**\n * 安装一份服务端权威队列快照。旧 revision、别的会话或结构不合法的快照一律不采纳,\n * 直接返回原 state——引用不变,订阅者不会收到多余通知。\n */\nexport function withQueue(state: SessionState, snapshot: SessionQueueSnapshot): SessionState {\n if (!shouldApplySnapshot(state.queue, snapshot)) return state\n return { ...state, queue: snapshot }\n}\n\nlet localTurnCounter = 0\n\nexport function addUserMessage(\n state: SessionState,\n content: MessageContent,\n clientRequestId?: string,\n): SessionState {\n localTurnCounter += 1\n const turnId = `local-user-${clientRequestId ?? `${Date.now()}-${localTurnCounter}`}`\n const optimisticTurn: TurnProjection = {\n id: turnId,\n sequence: Math.max(0, ...state.turns.map((turn) => turn.sequence)) + 1,\n turn_id: turnId,\n // 乐观态就自赋,跟服务端确认后 reconcileUserTurns 补上的\n // client_render_id(= 乐观 turn 自己的 turn_id)保持同一个值,\n // 消费方才能拿它当\"确认前后不变\"的稳定标识使用。\n client_render_id: turnId,\n loop_id: \"root\",\n role: \"user\",\n status: \"streaming\",\n blocks: [{ type: \"text\", content }],\n tool_calls: [],\n model: null,\n usage: null,\n duration_ms: 0,\n }\n return withTurns(state, [...state.turns, optimisticTurn])\n}\n\nexport function upsertTurn(state: SessionState, turn: TurnProjection): SessionState {\n let existing = [...state.turns]\n const [nextTurn] = reconcileOptimisticUserTurns(existing, [turn])\n const claimedOptimisticId = nextTurn.client_render_id\n if (claimedOptimisticId?.startsWith(\"local-user-\")) {\n existing = existing.filter((item) => item.turn_id !== claimedOptimisticId)\n }\n const index = existing.findIndex((item) => item.turn_id === nextTurn.turn_id)\n if (index >= 0) {\n existing[index] = nextTurn\n } else {\n existing.push(nextTurn)\n }\n // 传 { ...state, turns: existing } 而不是原始 state:上面已经把这条乐观\n // turn 从 existing 里认领/替换掉了,但 state.turns 本身还留着旧的那条。\n // withTurns 内部会用 reconcileHistoricalUserTurns 把\"没被这批 incoming\n // 认领的本地乐观 turn\"保留下来(针对真正的全量快照场景,见该函数注释);\n // 如果这里传原始 state,它会把 state.turns 里这条已经被上面处理过、但\n // 这次传的 incoming(existing)里已查不到匹配 client_request_id 的旧乐观\n // turn 误判成\"还没被认领\",重新拼回去,造成同一条发言重复两份。\n return withTurns({ ...state, turns: existing }, existing)\n}\n\nexport function applyTurnPatch(state: SessionState, patch: PatchEnvelope): SessionState {\n const turn = patch.data.turn\n if (!turn) return state\n\n const existing = [...state.turns]\n const index = existing.findIndex((item) => item.turn_id === turn.turn_id)\n const lastSequence = index >= 0 ? existing[index].sequence : null\n if (lastSequence !== null && patch.sequence <= lastSequence) {\n return state\n }\n\n return upsertTurn(state, { ...turn, sequence: patch.sequence })\n}\n\nexport function addErrorMessage(state: SessionState, content: string): SessionState {\n const anchorTurnId = state.turns[state.turns.length - 1]?.turn_id ?? null\n const entry_id = anchorTurnId\n ? `${ERROR_ANCHOR_PREFIX}${anchorTurnId}:${Date.now()}`\n : undefined\n return {\n ...state,\n messages: [...state.messages, { role: \"error\", content, loop_name: \"root\", entry_id }],\n }\n}\n\nexport function markInterrupted(state: SessionState): SessionState {\n return markStreamingTurns(state, \"interrupted\", \"cancelled\")\n}\n\nexport function markFailed(state: SessionState): SessionState {\n return markStreamingTurns(state, \"failed\", \"error\")\n}\n\nfunction markStreamingTurns(\n state: SessionState,\n turnStatus: \"interrupted\" | \"failed\",\n toolCallStatus: \"cancelled\" | \"error\",\n): SessionState {\n const turns = state.turns.map((turn) => {\n if (turn.status !== \"streaming\") return turn\n return {\n ...turn,\n status: turnStatus,\n tool_calls: turn.tool_calls.map((toolCall) =>\n toolCall.status === \"pending\" || toolCall.status === \"awaiting_answer\"\n ? { ...toolCall, status: toolCallStatus }\n : toolCall,\n ),\n }\n })\n return withTurns(state, turns)\n}\n","import {\n acceptedPostChatFollowupCompletesLatestRun,\n ClientProjectionBuilder,\n hasChatRunEvent,\n type RawEvent,\n} from \"../shared/projection\"\nimport type { MessageContent, ToolBridgeContent, ToolCallInfo } from \"../schemas/message\"\nimport type { ContentBlock, PatchEnvelope, TurnProjection } from \"../schemas/projection\"\nimport type { ReplaySpeed, ReplayState, SessionStatus } from \"../schemas/session\"\nimport { CommandRegistry, type CommandHandler } from \"../commands/registry\"\nimport { Emitter, type AgentSessionEvents } from \"./events\"\nimport type {\n AppCliAttachment,\n AppCliDefinition,\n FileEntry,\n HistoricalCommand,\n SessionTurnIndex,\n SessionTurnIndexItem,\n SessionTurnsPage,\n SessionTurnsQuery,\n} from \"../resources/sessions\"\nimport { prependOlder, replaceWindow } from \"./history-page\"\nimport {\n canEditQueuedMessage,\n isSessionQueueSnapshot,\n parseQueueAck,\n type QueueOperationResult,\n} from \"./queue\"\nimport { isEntryGoneError } from \"../resources/sessions\"\nimport { isRecord } from \"../shared/type-guards\"\nimport {\n buildToolUiCardKey,\n isToolUiCard,\n resolveToolUiCardContent,\n} from \"../shared/tool-ui-card\"\nimport {\n addErrorMessage,\n addUserMessage,\n applyTurnPatch,\n createInitialSessionState,\n extractModeFromBlocks,\n markFailed,\n markInterrupted,\n toReplaySnapshot,\n upsertTurn,\n withQueue,\n withTurns,\n type AskUserAnswerData,\n type ConnectionStatus,\n type SessionState,\n} from \"./state\"\n\n/** SessionHub 注入给 AgentSession 的运行时依赖(socket 收发 + REST 补数)。 */\nexport interface SessionRuntime {\n emitEvent(event: string, data: unknown): void\n emitWithAck(\n event: string,\n data: unknown,\n timeoutMs: number,\n ): Promise<Record<string, unknown> | undefined>\n ensureConnected(): void\n fetchTurnsPage(\n sessionId: string,\n query?: SessionTurnsQuery,\n init?: RequestInit,\n ): Promise<SessionTurnsPage>\n fetchTurnIndex(sessionId: string): Promise<SessionTurnIndex>\n fetchCommands(sessionId: string): Promise<HistoricalCommand[]>\n /** 会话详情,目前只用来取回放状态。 */\n fetchSessionInfo(\n sessionId: string,\n ): Promise<{ replay_state?: ReplayState | null; viewer_role?: \"owner\" | \"viewer\" }>\n updateReplay(\n sessionId: string,\n payload: { speed?: ReplaySpeed; status?: \"autonomous\" },\n ): Promise<ReplayState | null>\n listDir(sessionId: string, dirPath: string): Promise<FileEntry[]>\n countFiles(sessionId: string, dirPath?: string): Promise<number>\n downloadFile(sessionId: string, filePath: string, downloadName?: string): Promise<void>\n attachAppCli(sessionId: string, definition: AppCliDefinition): Promise<AppCliAttachment>\n /**\n * 归还一份持有。返回 true 表示这是最后一份、实例可以真正释放;\n * 返回 false 表示还有别的持有者,实例必须继续工作。\n */\n onDispose(session: AgentSession): boolean\n}\n\nexport interface AttachAppOptions {\n /** 可选;只需要页面上下文时无需提供 CLI。 */\n cli?: AppCliDefinition\n /** 每次发送前执行一次;返回当前页面状态的 JSON 对象快照。 */\n getContext: () => Record<string, unknown> | Promise<Record<string, unknown>>\n}\n\nexport interface SendOptions {\n /** planning / executing 模式。 */\n mode?: string\n /** AskUserQuestion 的作答(tool_call_id + 选项)。 */\n askUserAnswer?: Record<string, unknown>\n /** 本次运行的模型覆盖。 */\n model?: string\n /** 本次运行是否强制开/关思考。 */\n thinkingOverride?: boolean\n whatif?: {\n from_step: number\n quotes: Array<Record<string, unknown>>\n deprecate_entry_ids: string[]\n }\n replayDecision?: \"keep_replay\" | \"continue_replay\"\n /** 用户显式选择的知识库 id;后端将元信息作为 once Context 提供给模型。 */\n kbIds?: number[]\n /**\n * 声明\"会话在跑就把这条消息放进等待队列\"。默认不排队、运行中直接报错:\n * 是否真的入队由服务端按运行状态判定(等待回答时发送即作答,不会被误排队)。\n */\n queueWhenRunning?: boolean\n}\n\nconst OOM_MESSAGE = \"沙盒内存使用超出限制,已自动重启。如果经常触发,可以联系管理员调整额度。\"\nconst COMMAND_RESTORE_RETRY_BASE_MS = 1_000\nconst COMMAND_RESTORE_RETRY_MAX_MS = 30_000\n/** 队列命令的 ack 超时:操作会改变服务端状态,等太久不如尽早把\"结果未知\"交给 UI。 */\nconst QUEUE_ACK_TIMEOUT_MS = 10_000\nlet fallbackRequestCounter = 0\n\nfunction createClientRequestId(): string {\n if (typeof globalThis.crypto?.randomUUID === \"function\") {\n return globalThis.crypto.randomUUID()\n }\n fallbackRequestCounter += 1\n return `${Date.now()}-${Math.random().toString(36).slice(2)}-${fallbackRequestCounter}`\n}\n\n// ASCII 关键词用 \\b;中文\"退出码\"不能依赖 \\b(CJK 在 JS 正则里不算 word),\n// 137 两端用 (?<!\\d)(?!\\d) 锚定,避免 1370 之类误判。\nconst OOM_KEYWORDS_RE = /(?:\\b(?:exit_code|ExitedWith|exited with)|退出码)\\D*(?<!\\d)137(?!\\d)/i\n\nfunction isOomText(value: unknown): boolean {\n return typeof value === \"string\" && OOM_KEYWORDS_RE.test(value)\n}\n\nfunction parseJsonRecord(value: unknown): Record<string, unknown> | null {\n if (isRecord(value)) return value\n if (typeof value !== \"string\") return null\n try {\n const parsed = JSON.parse(value)\n return isRecord(parsed) ? parsed : null\n } catch {\n return null\n }\n}\n\nfunction isOomResult(value: unknown): boolean {\n if (Array.isArray(value)) {\n return value.some((part) => isOomResult(part))\n }\n if (typeof value === \"object\" && value !== null) {\n const record = value as Record<string, unknown>\n if (record.exit_code === 137) return true\n if (typeof record.text === \"string\" && isOomText(record.text)) return true\n if (typeof record.content === \"string\" && isOomText(record.content)) return true\n return false\n }\n if (typeof value === \"string\") {\n const parsed = parseJsonRecord(value)\n if (parsed?.exit_code === 137) return true\n return isOomText(value)\n }\n return false\n}\n\nfunction isToolBridgeContent(value: unknown): value is ToolBridgeContent {\n return (\n typeof value === \"object\" &&\n value !== null &&\n !Array.isArray(value) &&\n typeof (value as { action?: unknown }).action === \"string\"\n )\n}\n\nfunction isCursorInvalidError(error: unknown): boolean {\n return (\n typeof error === \"object\" &&\n error !== null &&\n \"status\" in error &&\n (error as { status?: unknown }).status === 409\n )\n}\n\n/** 队列命令的传输层失败(超时 / 断线):结果未知,UI 应保留草稿并提示重试。 */\nfunction queueRequestFailure(error: unknown): QueueOperationResult {\n return {\n ok: false,\n conflict: false,\n snapshot: null,\n message: error instanceof Error && error.message ? error.message : \"队列操作失败\",\n }\n}\n\nfunction commandDeliveryKey(deliveryId: string): string {\n return `tool-command:${deliveryId}`\n}\n\ninterface PendingCommandDelivery {\n deliveryKey: string\n action: string\n payload: unknown\n toolCallId: string | undefined\n}\n\nexport function sessionStatusFromChatEnd(status: string | undefined): SessionStatus {\n if (status === \"paused\") return \"waiting_for_input\"\n if (status === \"interrupted\") return \"interrupted\"\n if (status === \"failed\") return \"failed\"\n return \"completed\"\n}\n\nfunction extractTerminalChatEndStatus(events: RawEvent[]): string | null {\n for (let i = events.length - 1; i >= 0; i--) {\n const event = events[i]\n if (event?.type !== \"chat:end\") continue\n const status = event.payload?.status\n return typeof status === \"string\" ? status : \"completed\"\n }\n return null\n}\n\n/**\n * 一个会话的实时状态机:封装 Socket.IO 订阅、历史 + 流式合流、断线补数,\n * 对外只有三样东西——状态快照(getState/subscribe)、动作(send/stop/…)、\n * 语义事件(on/onCommand)。\n *\n * 状态完全归属实例:同一页面创建多个 AgentSession 互不干扰。\n */\nexport class AgentSession {\n readonly sessionId: string\n\n private state: SessionState\n private readonly listeners = new Set<() => void>()\n private readonly emitter = new Emitter<AgentSessionEvents>()\n private readonly commands = new CommandRegistry()\n private readonly runtime: SessionRuntime\n private readonly projectionBuilder = new ClientProjectionBuilder()\n\n private readonly pendingTurnPatches = new Map<string, PatchEnvelope>()\n private patchFlushHandle: number | ReturnType<typeof globalThis.setTimeout> | null = null\n private patchFlushCancel: (() => void) | null = null\n\n private joined = false\n private joinPending: Promise<void> | null = null\n // bootstrap 与每次 reconnect 共用一条订阅生命周期队列。它们都会重置 join\n // 状态并临时设置 replay source,禁止并发,否则较早操作的 finally 会清掉\n // 较晚操作仍在使用的来源上下文。\n private subscriptionQueue: Promise<unknown> = Promise.resolve()\n private replaceQueue: Promise<unknown> = Promise.resolve()\n private timelineEpoch = 0\n /** 定位请求的流水号:被后一次选择取代的那次定位不再提交窗口(见 locateEntry)。 */\n private locateToken = 0\n /** 在途那次定位的请求句柄。**只**服务定位:权威刷新不共用它(见 cancelPendingLocate)。 */\n private locateAbort: AbortController | null = null\n private pagingGeneration = 0\n private liveRevision = 0\n private modeRevision = 0\n private readonly liveRevisions = new Map<string, number>()\n private readonly pendingOptimisticTurnIds = new Set<string>()\n private olderPending: Promise<void> | null = null\n private replaceInFlight = 0\n // 回放控制请求排成一条队列。连着点\"5x\"再点\"退出回放\"时,并发发出去的两个\n // 请求响应可能乱序回来,晚到的旧值会把已经退出的会话又显示成回放中;用\n // 序号丢弃过期响应又会在失败时留下中间态。串行执行就没有这些情况:每个\n // 响应都是当时最新的,失败也只影响自己。\n private replayQueue: Promise<unknown> = Promise.resolve()\n // Historical snapshots and live commands share one delivery barrier. A\n // repair closes the barrier before joining, snapshots the raw command log\n // after the join, then releases buffered commands in socket arrival order.\n private commandRestoreQueue: Promise<unknown> = Promise.resolve()\n private commandRecoveryGeneration = 0\n private commandRestoreRetryAttempt = 0\n private commandRestoreRetryHandle: ReturnType<typeof globalThis.setTimeout> | null = null\n private bufferedCommandDeliveries: PendingCommandDelivery[] | null = null\n private pendingReplayMessage: MessageContent | null = null\n private pendingReplayMode: string | undefined\n private pendingReplayKbIds: number[] | undefined\n private recentChatEndAt = 0\n private subscriptionReplaySource: \"bootstrap_replay\" | \"reconnect_replay\" | null = null\n private disposed = false\n private getAppContext: AttachAppOptions[\"getContext\"] | null = null\n private sendPending = false\n private manualCompactionPending = false\n\n private readonly deliveredCommandKeys = new Set<string>()\n private readonly deliveredToolPreviews = new Map<string, string>()\n private readonly oomNotifiedKeys = new Set<string>()\n private readonly seenToolCallIds = new Set<string>()\n private readonly finishedToolCallIds = new Set<string>()\n private readonly emittedMessageTurnIds = new Set<string>()\n\n constructor(\n sessionId: string,\n runtime: SessionRuntime,\n connection: ConnectionStatus,\n options: { staticHistory?: boolean } = {},\n ) {\n this.sessionId = sessionId\n this.runtime = runtime\n this.state = { ...createInitialSessionState(sessionId), connection }\n this.isStatic = options.staticHistory === true\n }\n\n /**\n * 静态历史(分享页 / `fromTurns`):没有目录接口,也**没有**\"目录还没到位\"这个中间态。\n *\n * 宿主据此决定要不要拿已加载窗口当兜底条目——真实会话在 timeline 被重写后,窗口里还是\n * 旧分支的发言,拿它兜底会把已经失效的 entry id 重新摆到轨道上,点了必然找不到。\n */\n readonly isStatic: boolean\n\n /** 从一份静态 turn 快照构造只展示历史的会话(例如公开分享页)。 */\n static fromTurns(sessionId: string, turns: TurnProjection[]): AgentSession {\n const readonlyError = () => {\n throw new Error(\"静态会话只用于展示历史,不能执行会话操作\")\n }\n const session = new AgentSession(\n sessionId,\n {\n emitEvent: readonlyError,\n emitWithAck: async () => readonlyError(),\n ensureConnected: readonlyError,\n fetchTurnsPage: async () => ({ turns, nextBefore: null, currentMode: \"executing\" }),\n // 静态会话(分享页)没有会话目录接口,宿主用已加载的历史兜底条目。\n fetchTurnIndex: async () => ({ sessionId, items: [] }),\n fetchCommands: async () => [],\n // 静态历史没有回放身份可言,给个空详情即可,不要抛错——_bootstrap\n // 不会跑到这里,但保持只读语义一致。\n fetchSessionInfo: async () => ({ replay_state: null }),\n updateReplay: async () => readonlyError(),\n listDir: async () => readonlyError(),\n countFiles: async () => readonlyError(),\n downloadFile: async () => readonlyError(),\n attachAppCli: async () => readonlyError(),\n onDispose: () => true,\n },\n \"connected\",\n { staticHistory: true },\n )\n session.state = {\n ...withTurns(session.state, turns),\n status: \"completed\",\n }\n return session\n }\n\n // ---------------------------------------------------------------- 状态订阅\n\n /** 返回当前会话快照。引用稳定:状态未变化时返回同一对象。 */\n getState(): SessionState {\n return this.state\n }\n\n get hasOlderHistory(): boolean {\n return this.state.nextBefore !== null\n }\n\n /** Load the page immediately preceding the current display window. */\n loadOlderHistory(options: { beforeCommit?: () => void } = {}): Promise<void> {\n if (this.disposed) return Promise.resolve()\n if (this.olderPending) return this.olderPending\n if (this.replaceInFlight > 0) {\n // A sentinel may fire for an intermediate successful repair while a\n // later queued repair is still pending. Carry that one-shot trigger to\n // the final authoritative window instead of requiring a new\n // intersection transition.\n return this.replaceQueue.then(() => this.loadOlderHistory(options))\n }\n const before = this.state.nextBefore\n if (!before) return Promise.resolve()\n const epoch = this.timelineEpoch\n const generation = this.pagingGeneration\n this.update((state) => ({ ...state, loadingOlder: true }))\n const request = this.runtime\n .fetchTurnsPage(this.sessionId, { before })\n .then((page) => {\n if (\n epoch !== this.timelineEpoch ||\n generation !== this.pagingGeneration ||\n this.state.nextBefore !== before\n ) return\n options.beforeCommit?.()\n this.update((state) => ({\n ...withTurns(state, prependOlder(state.turns, page.turns)),\n nextBefore: page.nextBefore,\n loadingOlder: false,\n }))\n })\n .catch(async (error) => {\n if (\n isCursorInvalidError(error) &&\n epoch === this.timelineEpoch &&\n generation === this.pagingGeneration &&\n this.state.nextBefore === before\n ) {\n this.invalidateTimeline()\n await this.replaceFromHistory()\n return\n }\n // Keep the current window and cursor. A later sentinel entry or an\n // explicit caller retry can safely try the same stable anchor again.\n })\n .finally(() => {\n if (this.olderPending !== request) return\n this.olderPending = null\n this.update((state) => ({ ...state, loadingOlder: false }))\n })\n this.olderPending = request\n return request\n }\n\n /**\n * 定位到一条窗口外的历史发言:请服务端返回\"从这条发言到最新\"的窗口并整窗替换。\n *\n * 返回 false 表示这次定位没有落地(请求失败,或期间 timeline 被重写、会话已释放),\n * 当前窗口保持不变,调用方可以原样重试。已加载的发言不要走这里——宿主直接滚动,\n * 一次网络请求都不该发。\n */\n async locateEntry(entryId: string): Promise<boolean> {\n const token = ++this.locateToken\n const controller = new AbortController()\n this.locateAbort?.abort()\n this.locateAbort = controller\n try {\n return await this.replaceFromHistory({\n suppressErrors: false,\n fromEntryId: entryId,\n signal: controller.signal,\n isStale: () => this.locateToken !== token,\n })\n } catch {\n return false\n } finally {\n if (this.locateAbort === controller) this.locateAbort = null\n }\n }\n\n /**\n * 取消在途定位:用户改选了另一条发言(哪怕那条已经加载、不需要请求),\n * 先前那次定位既不该再落地,也不该继续占着替换队列——排队中的下一次定位\n * 不然要等它跑完(用户看到的是\"点了新目标一直转圈\")。\n *\n * **只**中止定位自己的请求:权威刷新(运行结束 / 重连补数)不共用这个 controller,\n * 否则\"运行刚结束时点一下侧栏\"就会把终态对账一起中止,流式与历史对不上。\n */\n cancelPendingLocate(): void {\n this.locateToken += 1\n this.locateAbort?.abort()\n this.locateAbort = null\n }\n\n /**\n * timeline 被整体改写(rewind / checkout / 释放):推进纪元,并把在途定位请求一并中止\n * ——它已经属于旧 timeline,却还占着替换队列,会让改写后的权威窗口排在后面等它跑完。\n * 作废号仍然保留:中止只是让它更早结束。\n */\n private invalidateTimeline(): void {\n this.timelineEpoch += 1\n this.locateAbort?.abort()\n this.locateAbort = null\n }\n\n /**\n * 拉取当前分支的用户发言目录(消息导航侧栏用)。\n *\n * 不在这里缓存:什么时候该刷新只有调用方知道(会话切换、历史被替换、新发言),\n * 缓存只会让旧条目在 rewind 之后继续可点。\n */\n async loadTurnIndex(): Promise<SessionTurnIndexItem[]> {\n const index = await this.runtime.fetchTurnIndex(this.sessionId)\n return index.items\n }\n\n /** 订阅状态变化。返回取消订阅函数。 */\n subscribe(listener: () => void): () => void {\n this.listeners.add(listener)\n return () => {\n this.listeners.delete(listener)\n }\n }\n\n private setState(next: SessionState): void {\n if (next === this.state) return\n this.state = next\n for (const listener of [...this.listeners]) {\n try {\n listener()\n } catch (error) {\n console.warn(\"[agent-client] 状态订阅回调抛出异常:\", error)\n }\n }\n }\n\n private update(fn: (state: SessionState) => SessionState): void {\n this.setState(fn(this.state))\n }\n\n // ---------------------------------------------------------------- 语义事件\n\n /** 监听语义事件(底层逃生舱,见 events.ts)。返回取消函数。 */\n on<K extends keyof AgentSessionEvents>(\n name: K,\n handler: (event: AgentSessionEvents[K]) => void,\n ): () => void {\n return this.emitter.on(name, handler)\n }\n\n off<K extends keyof AgentSessionEvents>(\n name: K,\n handler: (event: AgentSessionEvents[K]) => void,\n ): void {\n this.emitter.off(name, handler)\n }\n\n /**\n * 监听智能体下发给宿主页面的指令。\n *\n * action 是技能作者在工具返回值 `_meta.bridge` 里写的契约字符串(如\n * \"map.highlight\"),由你和技能作者约定;注册前到达的指令会被缓冲补投。\n */\n onCommand(action: string, handler: CommandHandler): () => void {\n return this.commands.onCommand(action, handler)\n }\n\n // ---------------------------------------------------------------- 动作\n\n /**\n * 声明当前应用提供的页面上下文和业务 CLI。\n *\n * CLI 安装成功后才保存 getContext;之后每次 send 前恰好读取一次。\n */\n async attachApp(options: AttachAppOptions): Promise<AppCliAttachment | null> {\n const attachment = options.cli\n ? await this.runtime.attachAppCli(this.sessionId, options.cli)\n : null\n this.getAppContext = options.getContext\n return attachment\n }\n\n /** 发送一条消息。字符串或多模态内容均可。 */\n async send(content: MessageContent, options: SendOptions = {}): Promise<boolean> {\n this.runtime.ensureConnected()\n // 只有声明了 queueWhenRunning 的调用方才能把运行中提交交给服务端;其余调用方\n // 维持原有的本地拒绝,不把运行中的一轮打成失败。\n if (\n (this.state.isStreaming && options.queueWhenRunning !== true) ||\n this.state.activeCompaction ||\n this.sendPending ||\n this.manualCompactionPending\n ) {\n this.update((s) =>\n addErrorMessage(s, \"当前回复尚未结束或对话正在整理,请稍后再发送。\"),\n )\n return false\n }\n this.sendPending = true\n try {\n return await this.sendUnlocked(content, options)\n } finally {\n this.sendPending = false\n }\n }\n\n /**\n * 入队一条等待消息(运行中排队 / 暂停期间照常入队)。\n *\n * ack 超时或传输失败时结果未知:用**同一个** `client_request_id` 重试一次,\n * 服务端按 `(session_id, client_request_id)` 幂等,不会制造第二条。\n */\n async queueMessage(content: string): Promise<QueueOperationResult> {\n const text = content.trim()\n if (!text) {\n return { ok: false, conflict: false, snapshot: null, message: \"消息不能为空\" }\n }\n const payload = {\n session_id: this.sessionId,\n message: text,\n client_request_id: createClientRequestId(),\n }\n try {\n return await this.requestQueueAck(\"chat:append\", payload)\n } catch {\n try {\n return await this.requestQueueAck(\"chat:append\", payload)\n } catch (error) {\n return queueRequestFailure(error)\n }\n }\n }\n\n /** 修改一条等待消息的正文;`expectedVersion` 是客户端看到的条目版本。 */\n async updateQueuedMessage(\n itemId: string,\n expectedVersion: number,\n content: string,\n ): Promise<QueueOperationResult> {\n return this.runQueueCommand(\"chat:queue:update\", {\n session_id: this.sessionId,\n item_id: itemId,\n expected_version: expectedVersion,\n message: content,\n })\n }\n\n /**\n * 重排等待消息。`orderedIds` 必须是当前 pending 条目 id 的**完整集合**(顺序任意),\n * 服务端按 `expectedRevision` 校验后整体替换顺序。\n *\n * 拖动排序就该像本地操作一样落地:版本冲突(运行中的任务刚领走一条 / 另一个端也在\n * 动队列)不甩给用户「刷新后重试」,而是拿冲突响应里那份**最新快照**重算一次再提交\n * ——掉队的条目(已经被领取执行的)从顺序里剔除,剩下的保持用户拖出来的相对次序。\n * 最多补两次;仍旧冲突才把结果交回调用方。\n */\n async reorderQueuedMessages(\n expectedRevision: number,\n orderedIds: string[],\n ): Promise<QueueOperationResult> {\n let revision = expectedRevision\n let ids = orderedIds\n let result = await this.runQueueCommand(\"chat:queue:reorder\", {\n session_id: this.sessionId,\n expected_revision: revision,\n ordered_ids: ids,\n })\n for (let attempt = 0; attempt < 2 && !result.ok && result.conflict; attempt++) {\n const snapshot = result.snapshot\n if (!snapshot) break\n const pending = snapshot.items.filter(canEditQueuedMessage)\n const live = new Set(pending.map((item) => item.id))\n // 用户拖出来的次序优先,只保留还在队列里的;服务端新出现的条目补在后面。\n const next = ids.filter((id) => live.has(id))\n for (const item of pending) if (!next.includes(item.id)) next.push(item.id)\n if (next.length === 0) {\n // 队列已经被清空(条目都开始执行了):这次拖动没有可排的东西,按成功返回\n // 最新快照让界面同步,而不是给用户报一句他无法处理的「刷新后重试」。\n return { ok: true, conflict: false, snapshot, message: null }\n }\n revision = snapshot.revision\n ids = next\n result = await this.runQueueCommand(\"chat:queue:reorder\", {\n session_id: this.sessionId,\n expected_revision: revision,\n ordered_ids: ids,\n })\n }\n return result\n }\n\n /** 删除一条等待消息;不传版本时由服务端自行判定。 */\n async cancelQueuedMessage(\n itemId: string,\n expectedVersion?: number,\n ): Promise<QueueOperationResult> {\n return this.runQueueCommand(\"chat:queue:cancel\", {\n session_id: this.sessionId,\n item_id: itemId,\n expected_version: expectedVersion,\n })\n }\n\n /** 立即补充:把等待消息交给当前运行,在下一个接收点消费,不停止也不另起一轮。 */\n async deliverQueuedMessage(\n itemId: string,\n expectedVersion: number,\n ): Promise<QueueOperationResult> {\n return this.runQueueCommand(\"chat:queue:deliver\", {\n session_id: this.sessionId,\n item_id: itemId,\n expected_version: expectedVersion,\n })\n }\n\n /** 继续执行:清除暂停,并按当前顺序恢复逐条接续。 */\n async resumeQueue(): Promise<QueueOperationResult> {\n return this.runQueueCommand(\"chat:queue:resume\", { session_id: this.sessionId })\n }\n\n /** 拉取一份权威队列快照。首次连接与每次重连后由实例自动调用,也可以手动刷新。 */\n async refreshQueue(): Promise<QueueOperationResult> {\n return this.runQueueCommand(\"chat:queue:list\", { session_id: this.sessionId })\n }\n\n /**\n * 发出一条队列命令并安装 ack 里的快照。\n * 传输层失败(超时 / 断线)会 reject,由调用方决定是否重试。\n */\n private async requestQueueAck(\n event: string,\n payload: Record<string, unknown>,\n ): Promise<QueueOperationResult> {\n this.runtime.ensureConnected()\n const response = await this.runtime.emitWithAck(event, payload, QUEUE_ACK_TIMEOUT_MS)\n const result = parseQueueAck(response, this.sessionId)\n const snapshot = result.snapshot\n if (snapshot) this.update((state) => withQueue(state, snapshot))\n return result\n }\n\n /** 队列命令的对外入口:传输失败只体现为失败结果,不向调用方抛异常。 */\n private async runQueueCommand(\n event: string,\n payload: Record<string, unknown>,\n ): Promise<QueueOperationResult> {\n try {\n return await this.requestQueueAck(event, payload)\n } catch (error) {\n return queueRequestFailure(error)\n }\n }\n\n private async sendUnlocked(content: MessageContent, options: SendOptions): Promise<boolean> {\n await this.ensureIdleBeforeSend()\n if (\n (this.state.isStreaming && options.queueWhenRunning !== true) ||\n this.state.activeCompaction ||\n this.manualCompactionPending\n ) {\n this.update((s) =>\n addErrorMessage(s, \"当前回复尚未结束或对话正在整理,请稍后再发送。\"),\n )\n return false\n }\n let appContext: Record<string, unknown> | undefined\n if (this.getAppContext) {\n try {\n const rawContext = await this.getAppContext()\n if (!isRecord(rawContext)) {\n throw new Error(\"getContext 必须返回 JSON 对象\")\n }\n const serialized = JSON.stringify(rawContext)\n if (serialized === undefined) {\n throw new Error(\"getContext 必须返回可序列化的 JSON 对象\")\n }\n const normalized = JSON.parse(serialized)\n if (!isRecord(normalized)) {\n throw new Error(\"getContext 必须返回 JSON 对象\")\n }\n appContext = normalized\n } catch (error) {\n const message =\n error instanceof Error && error.message\n ? `读取应用上下文失败:${error.message}`\n : \"读取应用上下文失败,消息未发送\"\n this.update((s) => addErrorMessage(s, message))\n return false\n }\n }\n const wasStreaming = this.state.isStreaming\n const askUserAnswer = options.askUserAnswer\n let optimisticTurnId: string | null = null\n const clientRequestId = createClientRequestId()\n let optimisticAskAnswer: AskUserAnswerData | undefined\n let previousAskAnswer: AskUserAnswerData | undefined\n this.update((state) => {\n const next = addUserMessage(state, content, clientRequestId)\n optimisticTurnId = next.turns.at(-1)?.turn_id ?? null\n return next\n })\n if (optimisticTurnId) this.markOptimisticTurnPending(optimisticTurnId)\n this.update((s) => ({ ...s, isStreaming: true }))\n if (askUserAnswer && typeof askUserAnswer.tool_call_id === \"string\") {\n const { tool_call_id, ...rest } = askUserAnswer\n previousAskAnswer = this.state.askAnswers[tool_call_id]\n optimisticAskAnswer = rest as unknown as AskUserAnswerData\n this.update((s) => ({\n ...s,\n askAnswers: { ...s.askAnswers, [tool_call_id as string]: optimisticAskAnswer! },\n }))\n }\n if (!options.replayDecision) {\n this.pendingReplayMessage = content\n this.pendingReplayMode = options.mode\n this.pendingReplayKbIds = options.kbIds\n }\n const payload = {\n session_id: this.sessionId,\n message: content,\n client_request_id: clientRequestId,\n mode: options.mode,\n askuser_answer: askUserAnswer,\n model: options.model,\n thinking_override: options.thinkingOverride,\n whatif: options.whatif,\n replay_decision: options.replayDecision,\n app_context: appContext,\n kb_ids: options.kbIds,\n // 运行中提交不必由客户端挑命令:服务端按会话运行状态决定直接执行还是入队。\n queue_when_running: options.queueWhenRunning === true,\n }\n try {\n await this.ensureJoined()\n } catch (error) {\n this.rollbackOptimisticSend(\n optimisticTurnId,\n askUserAnswer,\n optimisticAskAnswer,\n previousAskAnswer,\n wasStreaming,\n error instanceof Error && error.message ? error.message : \"会话订阅失败,消息未发送\",\n )\n return false\n }\n try {\n const response = await this.runtime.emitWithAck(\"chat:send\", payload, 30_000)\n if (response?.status === \"queued\") {\n // 服务端按运行状态把这条消息改道进了等待队列:撤掉乐观消息交给队列面板。\n // ack 里的 running 是服务端判定那一刻的快照,可能已经被这期间到达的\n // chat:end 顶掉,所以只拿它撤销我们的乐观流式置位(确认没有运行),\n // 不用它把流式标记顶上去——那会留下\"正在生成\"却没有运行可收尾。\n this.discardOptimisticSend(\n optimisticTurnId,\n askUserAnswer,\n optimisticAskAnswer,\n previousAskAnswer,\n )\n const snapshot = parseQueueAck(response, this.sessionId).snapshot\n const running = response.running === true\n this.update((current) => {\n const next = running ? current : { ...current, isStreaming: false }\n return snapshot ? withQueue(next, snapshot) : next\n })\n return true\n }\n if (response?.status !== \"accepted\") {\n throw new Error(\n typeof response?.message === \"string\"\n ? response.message\n : \"消息未被服务端接受\",\n )\n }\n return true\n } catch (error) {\n this.rollbackOptimisticSend(\n optimisticTurnId,\n askUserAnswer,\n optimisticAskAnswer,\n previousAskAnswer,\n wasStreaming,\n error instanceof Error && error.message ? error.message : \"消息发送失败,请重试\",\n )\n return false\n }\n }\n\n private rollbackOptimisticSend(\n optimisticTurnId: string | null,\n askUserAnswer: Record<string, unknown> | undefined,\n optimisticAskAnswer: AskUserAnswerData | undefined,\n previousAskAnswer: AskUserAnswerData | undefined,\n wasStreaming: boolean,\n message: string,\n ): void {\n this.discardOptimisticSend(\n optimisticTurnId,\n askUserAnswer,\n optimisticAskAnswer,\n previousAskAnswer,\n )\n // 同内置 Web AgentSocket.send:只撤销本次提交设置的乐观运行状态。\n // 已有运行的状态交给事件更新,既不误停,也不复活已结束的运行。\n this.update((current) =>\n addErrorMessage(wasStreaming ? current : { ...current, isStreaming: false }, message),\n )\n }\n\n /** 撤回一次乐观提交:移除乐观消息、恢复提问作答、清掉回放草稿。 */\n private discardOptimisticSend(\n optimisticTurnId: string | null,\n askUserAnswer: Record<string, unknown> | undefined,\n optimisticAskAnswer: AskUserAnswerData | undefined,\n previousAskAnswer: AskUserAnswerData | undefined,\n ): void {\n this.pendingReplayMessage = null\n this.pendingReplayMode = undefined\n this.pendingReplayKbIds = undefined\n this.update((current) => {\n // withTurns 第一个参数要传已经去掉这条乐观 turn 的 current(而不是原始\n // current):withTurns 内部会把\"这批 incoming 没认领的本地乐观 turn\"\n // 保留下来(应对真正的全量快照场景),如果这里传原始 current,它会把\n // 我们刚刚主动要撤回的这条乐观 turn 当成\"还没被认领\"重新拼回去,等于\n // 撤回失败。\n const filtered = optimisticTurnId\n ? current.turns.filter((turn) => turn.turn_id !== optimisticTurnId)\n : current.turns\n let next = optimisticTurnId\n ? withTurns({ ...current, turns: filtered }, filtered)\n : current\n const toolCallId =\n askUserAnswer && typeof askUserAnswer.tool_call_id === \"string\"\n ? askUserAnswer.tool_call_id\n : null\n if (toolCallId && next.askAnswers[toolCallId] === optimisticAskAnswer) {\n const askAnswers = { ...next.askAnswers }\n if (previousAskAnswer === undefined) {\n delete askAnswers[toolCallId]\n } else {\n askAnswers[toolCallId] = previousAskAnswer\n }\n next = { ...next, askAnswers }\n }\n return next\n })\n if (optimisticTurnId) {\n this.pendingOptimisticTurnIds.delete(optimisticTurnId)\n this.liveRevisions.delete(optimisticTurnId)\n }\n }\n\n /** 停止当前回复。 */\n stop(): Promise<Record<string, unknown>> {\n return this.runtime\n .emitWithAck(\"chat:stop\", { session_id: this.sessionId }, 35_000)\n .then((response) => {\n const result = response ?? {}\n if (result.status !== \"accepted\") this.manualCompactionPending = false\n return result\n })\n }\n\n /** 手动触发上下文压缩。 */\n compact(): Promise<Record<string, unknown>> {\n if (this.state.isStreaming || this.state.activeCompaction || this.manualCompactionPending) {\n return Promise.resolve({\n status: \"error\",\n message: \"当前回复尚未结束或对话正在整理,请稍后再试。\",\n })\n }\n this.manualCompactionPending = true\n this.update((state) => ({\n ...state,\n activeCompaction: {\n turn_id: \"pending-manual-compaction\",\n compaction_id: \"pending-manual-compaction\",\n status: \"streaming\",\n trigger: \"manual\",\n },\n }))\n return this.runtime\n .emitWithAck(\"chat:compact\", { session_id: this.sessionId }, 30_000)\n .then((response) => response ?? {})\n .catch((error) => {\n this.manualCompactionPending = false\n throw error\n })\n .finally(() => {\n if (this.state.activeCompaction?.compaction_id === \"pending-manual-compaction\") {\n this.update((state) => ({ ...state, activeCompaction: null }))\n }\n })\n }\n\n /**\n * 把一段业务数据作为附件放进聊天输入框(比如地图上选中的点位)。\n * 附件随下一条消息一起发给智能体。需要 ChatView / useChat 渲染层配合展示;\n * 无 UI 场景可直接用 send()。\n */\n attach(label: string, data: unknown): void {\n const content = typeof data === \"string\" ? data : JSON.stringify(data, null, 2)\n this.emitter.emit(\"attachRequested\", { label, content })\n }\n\n /** 往聊天输入框追加一段文字(不发送)。 */\n insertText(text: string): void {\n this.emitter.emit(\"insertTextRequested\", { text })\n }\n\n /** 列出工作区的一层目录。 */\n listDir(dirPath = \"\"): Promise<FileEntry[]> {\n return this.runtime.listDir(this.sessionId, dirPath)\n }\n\n /** 递归统计工作区文件数(不含目录)。 */\n countFiles(dirPath = \"\"): Promise<number> {\n return this.runtime.countFiles(this.sessionId, dirPath)\n }\n\n /** 在浏览器中下载一个工作区文件。 */\n downloadFile(filePath: string, downloadName?: string): Promise<void> {\n return this.runtime.downloadFile(this.sessionId, filePath, downloadName)\n }\n\n /**\n * 归还一份持有。同一个会话被多处 connect 时按引用计数释放:只有最后\n * 一份归还才真正断开订阅与监听器,之前的归还不影响仍在使用的一方。\n */\n dispose(): void {\n if (this.disposed) return\n if (!this.runtime.onDispose(this)) return\n this.disposed = true\n this.invalidateTimeline()\n this.invalidateOlderPaging()\n this.state = { ...this.state, nextBefore: null, loadingOlder: false }\n this.cancelPatchFlush()\n this.listeners.clear()\n this.emitter.clear()\n this.commands.clear()\n this.commandRecoveryGeneration += 1\n this.commandRestoreRetryAttempt = 0\n this.bufferedCommandDeliveries = null\n if (this.commandRestoreRetryHandle !== null) {\n globalThis.clearTimeout(this.commandRestoreRetryHandle)\n this.commandRestoreRetryHandle = null\n }\n }\n\n get isDisposed(): boolean {\n return this.disposed\n }\n\n // ------------------------------------------------------- Hub 回调(内部)\n\n /** @internal 连接状态变化(同 client 下所有会话共享一条连接)。 */\n _setConnection(connection: ConnectionStatus): void {\n if (this.state.connection === connection) return\n this.update((s) => ({ ...s, connection }))\n }\n\n /**\n * @internal 服务端广播的权威队列快照。\n * 结构不合法或 revision 不新的一律丢弃,绝不用旧快照覆盖新状态。\n */\n _handleQueueUpdated(payload: unknown): void {\n if (!isSessionQueueSnapshot(payload)) return\n const snapshot = payload\n this.update((state) => withQueue(state, snapshot))\n }\n\n /** @internal socket 重连后由 Hub 调用:重新加入房间并补数。 */\n _rejoinAfterReconnect(): Promise<void> {\n // 边界快照必须在收到 connect 时同步取得。队列实际开始前到达的 live turn\n // 也属于本次重连后的新变化,历史补数不能把它清掉。\n //\n // **不推进 timeline 纪元**:重连不是 timeline 被改写(分支没变,只是补一次数),推进了\n // 在途定位的结果就会被丢掉——用户点了没反应。补数本来就按它落地后的窗口取窗口。\n this.invalidateOlderPaging()\n this.update((state) => ({ ...state, nextBefore: null, loadingOlder: false }))\n const reconnectLiveRevision = this.liveRevision\n const reconnectModeRevision = this.modeRevision\n const commandRecoveryGeneration = this.beginCommandRecovery()\n return this.enqueueSubscription(async () => {\n this.joined = false\n this.joinPending = null\n try {\n this.subscriptionReplaySource = \"reconnect_replay\"\n try {\n await this.ensureJoined(reconnectLiveRevision)\n } finally {\n this.subscriptionReplaySource = null\n this.scheduleHistoricalCommandRestore(commandRecoveryGeneration)\n }\n // 回放状态和历史一起补:断线期间错过的 session:updated(别处退出了回放、\n // 改了倍速)不补的话,快照会一直停在旧值。\n await Promise.all([\n this.refreshAuthoritativeHistory({\n liveRevisionAtStart: reconnectLiveRevision,\n modeRevisionAtStart: reconnectModeRevision,\n }),\n this.syncReplayFromSession(),\n ])\n } catch {\n // 重连补数尽力而为;后续 Socket 重连仍会再次尝试\n }\n })\n }\n\n /** @internal 首次连接:加载历史 + 加入房间。 */\n _bootstrap(): Promise<void> {\n const commandRecoveryGeneration = this.beginCommandRecovery()\n return this.enqueueSubscription(async () => {\n await this.replaceFromHistory({ suppressErrors: false })\n this.subscriptionReplaySource = \"bootstrap_replay\"\n try {\n await this.ensureJoined()\n } finally {\n this.subscriptionReplaySource = null\n }\n this.scheduleHistoricalCommandRestore(commandRecoveryGeneration)\n // 必须在进房间之后再拉回放状态:反过来的话,两者之间别的标签页改了倍速或\n // 退出了回放,那条 session:updated 我们还没订阅、收不到,快照会一直停在旧值。\n // 拉一次而不是等推送,是为了让 connect() 返回时第一帧就知道自己在不在回放。\n await Promise.all([this.syncReplayFromSession(), this.refreshQueue()])\n })\n }\n\n /** 订阅生命周期串行执行;一次失败只由自己的调用方观察,不截断后续重连。 */\n private enqueueSubscription(operation: () => Promise<void>): Promise<void> {\n const run = this.subscriptionQueue.then(operation)\n this.subscriptionQueue = run.catch(() => undefined)\n return run\n }\n\n /** 改回放是 owner 专属(服务端 PATCH 走 _get_owned_session)。 */\n private get canControlReplay(): boolean {\n return this.state.viewerRole !== \"viewer\"\n }\n\n /** 拉一次会话详情,填回放状态和只读身份;失败按非回放会话处理,不挡启动。 */\n private async syncReplayFromSession(): Promise<void> {\n try {\n const info = await this.runtime.fetchSessionInfo(this.sessionId)\n const replay = toReplaySnapshot(info.replay_state)\n const viewerRole = info.viewer_role ?? null\n this.update((s) => ({ ...s, replay, viewerRole }))\n } catch {\n // 会话详情拿不到不影响对话本身,回放控件不显示即可。\n }\n }\n\n /** 调整回放倍速;不是回放会话、或只读身份时什么都不做。 */\n async setReplaySpeed(speed: ReplaySpeed): Promise<void> {\n if (!this.state.replay?.isReplay || !this.canControlReplay) return\n await this.applyReplayControl({ speed })\n }\n\n /** 退出回放,之后的对话交给真实模型运行;不是回放会话、或只读身份时什么都不做。 */\n async exitReplay(): Promise<void> {\n if (!this.state.replay?.isReplay || !this.canControlReplay) return\n await this.applyReplayControl({ status: \"autonomous\" })\n }\n\n /** 把一次回放控制请求排进队列;前一个完成后才发出,响应直接安装。 */\n private applyReplayControl(\n payload: { speed?: ReplaySpeed; status?: \"autonomous\" },\n ): Promise<void> {\n const run = this.replayQueue.then(async () => {\n const result = await this.runtime.updateReplay(this.sessionId, payload)\n this.update((s) => ({ ...s, replay: toReplaySnapshot(result) }))\n })\n // 队列本身不能被一次失败打断,否则后续控制永远排不上。\n this.replayQueue = run.catch(() => undefined)\n return run\n }\n\n /** @internal */\n _handleTurnStart(turn: TurnProjection): void {\n this.markRunningIfIdle()\n this.applyTurn(turn)\n }\n\n /** @internal */\n _handleTurnPatch(patch: PatchEnvelope): void {\n this.markRunningIfIdle()\n if (patch.data.workspace_changed) {\n this.emitter.emit(\"workspaceChanged\", {})\n }\n const current = this.pendingTurnPatches.get(patch.turn_id)\n if (!current || patch.sequence >= current.sequence) {\n this.pendingTurnPatches.set(patch.turn_id, patch)\n }\n this.schedulePatchFlush()\n }\n\n /** @internal */\n _handleTurnEnd(turn: TurnProjection): void {\n this.applyTurn(turn)\n }\n\n /** @internal 历史回放通道(event_format: raw)。 */\n _handleTurnEvents(events: RawEvent[], replayed = false): void {\n if (!events.length) return\n if (events.some((event) =>\n event.type === \"compaction:end\" ||\n event.type === \"compaction:error\" ||\n event.type === \"compaction:abort\"\n )) {\n this.manualCompactionPending = false\n }\n // Commands are transport semantics, not display semantics. Consume the\n // canonical raw delivery before projection so standalone commands (no\n // tool_call_id/display owner) still reach the host page. If a visible\n // block is projected afterwards, the same delivery id deduplicates it.\n this.dispatchRawCommands(events)\n const terminalChatEndStatus = extractTerminalChatEndStatus(events)\n if (\n !terminalChatEndStatus &&\n hasChatRunEvent(events) &&\n this.state.status !== \"waiting_for_input\"\n ) {\n this.markRunningIfIdle()\n }\n if (this.state.turns.length) {\n this.projectionBuilder._seedTurns(this.state.turns)\n }\n const updates = this.projectionBuilder.processBatch(events)\n for (const update of updates) {\n if (update.kind === \"upsert\") {\n this.applyTurn(\n update.turn,\n replayed ? (this.subscriptionReplaySource ?? \"bootstrap_replay\") : \"live\",\n )\n } else if (update.kind === \"workspace_changed\") {\n this.emitter.emit(\"workspaceChanged\", {})\n }\n }\n if (\n terminalChatEndStatus ||\n acceptedPostChatFollowupCompletesLatestRun(events, updates)\n ) {\n this.completeChat(terminalChatEndStatus ?? \"completed\")\n }\n }\n\n /** @internal */\n _handleChatStart(): void {\n this.update((s) => ({ ...s, status: \"running\", errorMessage: null, isStreaming: true }))\n }\n\n /** @internal */\n _handleChatEnd(status: string): void {\n this.flushPatches()\n this.completeChat(status)\n }\n\n /** @internal */\n _handleSystemError(message: string): void {\n this.flushPatches()\n const finalMessage = isOomText(message) ? OOM_MESSAGE : message\n this.update((s) =>\n addErrorMessage(markFailed({ ...s, status: \"failed\", errorMessage: finalMessage, isStreaming: false }), finalMessage),\n )\n this.recentChatEndAt = Date.now()\n this.emitter.emit(\"error\", { message: finalMessage })\n }\n\n /** @internal */\n _handleTaskUpdated(tasks: unknown[]): void {\n this.emitter.emit(\"taskListUpdated\", { tasks })\n }\n\n /** @internal */\n _handleWorkspaceFilesChanged(filePath?: string): void {\n this.emitter.emit(\"workspaceChanged\", { filePath })\n }\n\n /** @internal */\n _handleSessionUpdated(data: {\n workspace_path?: string\n chat_group_id?: string | null\n intent?: string\n status?: SessionStatus\n model?: string | null\n bound_skill_id?: string | null\n replay_state?: Record<string, unknown> | null\n }): void {\n if (data.status) {\n this.update((s) => ({ ...s, status: data.status ?? s.status }))\n }\n if (data.replay_state !== undefined) {\n const replay = toReplaySnapshot(data.replay_state as ReplayState | null)\n this.update((s) => ({ ...s, replay }))\n }\n this.emitter.emit(\"sessionUpdated\", {\n workspacePath: data.workspace_path,\n chatGroupId: data.chat_group_id,\n intent: data.intent,\n status: data.status,\n model: data.model,\n boundSkillId: data.bound_skill_id,\n replayState: data.replay_state,\n })\n }\n\n /** @internal */\n _handleRewind(checkpointId: string): void {\n this.invalidateTimeline()\n this.invalidateOlderPaging()\n this.update((s) => ({\n ...s,\n mode: null,\n errorMessage: null,\n nextBefore: null,\n loadingOlder: false,\n }))\n void this.replaceFromHistory()\n this.emitter.emit(\"rewind\", { checkpointId })\n }\n\n /** @internal */\n _handleReplayMismatch(data: { actual_message?: string; expected_message?: string }): void {\n const message = this.pendingReplayMessage ?? data.actual_message ?? \"\"\n const mode = this.pendingReplayMode\n const kbIds = this.pendingReplayKbIds\n this.pendingReplayMessage = null\n this.pendingReplayMode = undefined\n this.pendingReplayKbIds = undefined\n const respond = (decision: \"keep_replay\" | \"continue_replay\") => {\n void this.runtime\n .emitWithAck(\n \"chat:send\",\n {\n session_id: this.sessionId,\n message,\n mode,\n replay_decision: decision,\n kb_ids: kbIds,\n },\n 30_000,\n )\n .then((response) => {\n if (response?.status === \"accepted\") return\n this.update((state) =>\n addErrorMessage(\n { ...state, isStreaming: false },\n typeof response?.message === \"string\"\n ? response.message\n : \"消息未被服务端接受\",\n ),\n )\n })\n .catch((error) => {\n this.update((state) =>\n addErrorMessage(\n { ...state, isStreaming: false },\n error instanceof Error && error.message ? error.message : \"消息发送失败,请重试\",\n ),\n )\n })\n }\n const handled = this.emitter.emitFirst(\"replayMismatch\", {\n actualMessage: data.actual_message,\n expectedMessage: data.expected_message,\n respond,\n })\n if (!handled) {\n respond(\"continue_replay\")\n }\n }\n\n /** @internal */\n _handleSystemNotification(loopId: string, notification: Record<string, unknown>): void {\n const notificationType =\n typeof notification.notification_type === \"string\"\n ? notification.notification_type\n : \"system_notification\"\n const title = typeof notification.title === \"string\" ? notification.title : notificationType\n const detail =\n typeof notification.detail === \"string\"\n ? notification.detail\n : notification.detail == null\n ? undefined\n : JSON.stringify(notification.detail)\n const status =\n notification.status === \"running\" || notification.status === \"done\" || notification.status === \"error\"\n ? notification.status\n : \"info\"\n this.emitter.emit(\"notification\", {\n type: notificationType,\n title,\n detail,\n status,\n loopId,\n metadata: isRecord(notification.metadata) ? notification.metadata : undefined,\n })\n if (notificationType === \"bg:started\" && isRecord(notification.metadata)) {\n const taskId =\n typeof notification.metadata.task_id === \"string\" ? notification.metadata.task_id : \"\"\n if (taskId) {\n this.emitter.emit(\"backgroundTask\", {\n id: taskId,\n command:\n typeof notification.metadata.command === \"string\" ? notification.metadata.command : \"\",\n description:\n typeof notification.metadata.description === \"string\"\n ? notification.metadata.description\n : undefined,\n status: \"running\",\n elapsedSeconds: 0,\n })\n }\n }\n }\n\n /** @internal */\n _handleBackgroundTask(task: AgentSessionEvents[\"backgroundTask\"]): void {\n this.emitter.emit(\"backgroundTask\", task)\n }\n\n /** @internal */\n _handleArtifact(event: AgentSessionEvents[\"artifact\"]): void {\n this.emitter.emit(\"artifact\", event)\n }\n\n /** @internal 加入房间的应答里带 is_running,据此校准流式状态。 */\n _applyRunningState(isRunning: boolean, liveRevisionAtJoin = this.liveRevision): void {\n if (isRunning) {\n this.update((s) => ({ ...s, status: \"running\", isStreaming: true }))\n } else if (this.state.isStreaming) {\n this.update((s) => ({ ...s, isStreaming: false }))\n // 这也是一次权威刷新(\"我看它还在跑,其实已经结束了\"):同样要按用户的窗口意图取窗口,\n // 否则它排在重连补数前面先把窗口换成最新一页,把用户正在看的那段挤出去。\n void this.refreshAuthoritativeHistory({ liveRevisionAtStart: liveRevisionAtJoin })\n }\n }\n\n // ---------------------------------------------------------------- 内部实现\n\n private markRunningIfIdle(): void {\n if (!this.state.isStreaming) {\n this.update((s) => ({ ...s, status: \"running\", isStreaming: true }))\n }\n }\n\n private finishStreaming(status: string): void {\n const sessionStatus = sessionStatusFromChatEnd(status)\n this.update((s) => {\n let next: SessionState = { ...s, status: sessionStatus, isStreaming: false }\n if (status === \"interrupted\") next = markInterrupted(next)\n else if (status === \"failed\") next = markFailed(next)\n return next\n })\n }\n\n private completeChat(status: string): void {\n this.finishStreaming(status)\n this.recentChatEndAt = Date.now()\n // 运行结束的对账不能把用户刚定位到的那段历史挤出去(见 refreshAuthoritativeHistory)。\n void this.refreshAuthoritativeHistory()\n this.emitter.emit(\"chatEnd\", { status })\n }\n\n private markTurnFresh(turnId: string): void {\n this.liveRevision += 1\n this.liveRevisions.set(turnId, this.liveRevision)\n }\n\n private markOptimisticTurnPending(turnId: string): void {\n this.pendingOptimisticTurnIds.add(turnId)\n this.markTurnFresh(turnId)\n }\n\n private pruneOptimisticLiveRevisions(): void {\n const retained = new Set(\n this.state.turns\n .map((turn) => turn.turn_id)\n .filter((turnId) => turnId.startsWith(\"local-user-\")),\n )\n for (const turnId of this.liveRevisions.keys()) {\n if (turnId.startsWith(\"local-user-\") && !retained.has(turnId)) {\n this.pendingOptimisticTurnIds.delete(turnId)\n this.liveRevisions.delete(turnId)\n }\n }\n }\n\n private applyTurn(\n turn: TurnProjection,\n source: AgentSessionEvents[\"toolResult\"][\"source\"] = \"live\",\n ): void {\n this.flushPatches()\n this.markTurnFresh(turn.turn_id)\n if (extractModeFromBlocks(turn.blocks)) this.modeRevision += 1\n const previous = this.state\n this.update((s) => upsertTurn(s, turn))\n this.pruneOptimisticLiveRevisions()\n this.emitTurnDerivedEvents(previous, turn, source)\n }\n\n private schedulePatchFlush(): void {\n if (this.patchFlushHandle != null) return\n const flush = () => {\n this.patchFlushHandle = null\n this.patchFlushCancel = null\n this.flushPatches()\n }\n if (typeof window !== \"undefined\" && typeof window.requestAnimationFrame === \"function\") {\n const handle = window.requestAnimationFrame(flush)\n this.patchFlushHandle = handle\n this.patchFlushCancel = () => window.cancelAnimationFrame(handle)\n return\n }\n const handle = globalThis.setTimeout(flush, 33)\n this.patchFlushHandle = handle\n this.patchFlushCancel = () => globalThis.clearTimeout(handle)\n }\n\n private cancelPatchFlush(): void {\n this.patchFlushCancel?.()\n this.patchFlushHandle = null\n this.patchFlushCancel = null\n this.pendingTurnPatches.clear()\n }\n\n private flushPatches(): void {\n if (this.pendingTurnPatches.size === 0) return\n const patches = [...this.pendingTurnPatches.values()].sort(\n (left, right) => left.sequence - right.sequence,\n )\n this.pendingTurnPatches.clear()\n for (const patch of patches) {\n const previous = this.state\n const next = applyTurnPatch(previous, patch)\n if (next === previous) continue\n this.liveRevision += 1\n this.liveRevisions.set(patch.turn_id, this.liveRevision)\n const turn = patch.data.turn\n if (turn && extractModeFromBlocks(turn.blocks)) this.modeRevision += 1\n this.setState(next)\n this.pruneOptimisticLiveRevisions()\n if (turn) this.emitTurnDerivedEvents(previous, turn)\n }\n if (this.patchFlushCancel) {\n this.patchFlushCancel()\n this.patchFlushHandle = null\n this.patchFlushCancel = null\n }\n }\n\n /** turn 数据落地后统一派生语义事件(指令 / 工具调用 / 消息 / 模式 / 预览 / OOM)。 */\n private emitTurnDerivedEvents(\n previous: SessionState,\n turn: TurnProjection,\n source: AgentSessionEvents[\"toolResult\"][\"source\"] = \"live\",\n ): void {\n const mode = extractModeFromBlocks(turn.blocks)\n if (mode && previous.mode !== mode) {\n this.emitter.emit(\"modeChange\", { mode })\n }\n\n for (const block of turn.blocks) {\n if (block.type === \"tool_result\" && isOomResult(block.content)) {\n this.notifySandboxOom(block.tool_call_id ?? turn.id)\n }\n if (block.type === \"tool_bridge\" && isToolBridgeContent(block.content)) {\n this.dispatchCommand(turn, block)\n continue\n }\n if (block.type === \"tool_ui\" && block.tool_call_id && isToolUiCard(block.content)) {\n const ui = block.content\n if (ui.target !== \"preview\") continue\n const resolved = resolveToolUiCardContent(ui)\n if (!resolved) continue\n const key = buildToolUiCardKey(block.tool_call_id, resolved.type, resolved.content)\n const fingerprint = JSON.stringify([resolved.content, ui.mcpApp?.sourceId])\n if (this.deliveredToolPreviews.get(key) === fingerprint) continue\n this.deliveredToolPreviews.set(key, fingerprint)\n this.emitter.emit(\"toolPreview\", {\n toolCallId: block.tool_call_id,\n type: resolved.type,\n content: resolved.content,\n title: ui.title ?? \"工具预览\",\n ...(ui.mcpApp ? { mcpApp: ui.mcpApp } : {}),\n })\n }\n if (block.type === \"system_notification\" && isRecord(block.content)) {\n this._handleSystemNotification(turn.loop_id, block.content)\n }\n }\n\n for (const toolCall of turn.tool_calls) {\n const info: ToolCallInfo = {\n id: toolCall.id,\n name: toolCall.tool_name,\n display_name: toolCall.display_name,\n arguments: toolCall.arguments,\n result: toolCall.result ?? undefined,\n status:\n toolCall.status === \"pending\" ||\n toolCall.status === \"awaiting_answer\" ||\n toolCall.status === \"done\" ||\n toolCall.status === \"error\" ||\n toolCall.status === \"cancelled\"\n ? toolCall.status\n : (\"pending\" as const),\n }\n if (!this.seenToolCallIds.has(toolCall.id)) {\n this.seenToolCallIds.add(toolCall.id)\n this.emitter.emit(\"toolCall\", { toolCall: info, turn })\n }\n const finished =\n toolCall.status === \"done\" || toolCall.status === \"error\" || toolCall.status === \"cancelled\"\n if (finished && !this.finishedToolCallIds.has(toolCall.id)) {\n this.finishedToolCallIds.add(toolCall.id)\n this.emitter.emit(\"toolResult\", { toolCall: info, turn, source })\n if (isOomResult(toolCall.result)) {\n this.notifySandboxOom(toolCall.id)\n }\n }\n }\n\n if (turn.status !== \"streaming\" && !this.emittedMessageTurnIds.has(turn.turn_id)) {\n const message = this.state.messages.find((m) => m.entry_id === turn.turn_id)\n if (message) {\n this.emittedMessageTurnIds.add(turn.turn_id)\n this.emitter.emit(\"message\", { message, turn })\n }\n }\n }\n\n private dispatchCommand(\n turn: TurnProjection,\n block: ContentBlock,\n ): void {\n if (!isToolBridgeContent(block.content)) return\n const { action, payload } = block.content\n const deliveryKey = block.delivery_id\n ? commandDeliveryKey(block.delivery_id)\n : `legacy-tool-command:${turn.turn_id}:${block.tool_call_id ?? \"\"}:${action}:${JSON.stringify(payload)}`\n this.deliverCommand(deliveryKey, action, payload, block.tool_call_id ?? undefined)\n }\n\n private dispatchRawCommands(events: RawEvent[]): void {\n for (const event of events) {\n if (event.type !== \"loop:tool_bridge\") continue\n const deliveryId = String(event.payload.delivery_id ?? \"\")\n const bridge = event.payload.bridge\n if (!deliveryId || !isToolBridgeContent(bridge)) continue\n this.deliverCommand(\n commandDeliveryKey(deliveryId),\n bridge.action,\n bridge.payload,\n String(event.payload.tool_call_id ?? \"\") || undefined,\n )\n }\n }\n\n private deliverCommand(\n deliveryKey: string,\n action: string,\n payload: unknown,\n toolCallId: string | undefined,\n ): void {\n if (this.bufferedCommandDeliveries) {\n this.bufferedCommandDeliveries.push({ deliveryKey, action, payload, toolCallId })\n return\n }\n this.deliverCommandNow({ deliveryKey, action, payload, toolCallId })\n }\n\n private deliverCommandNow(command: PendingCommandDelivery): void {\n const { deliveryKey, action, payload, toolCallId } = command\n if (this.deliveredCommandKeys.has(deliveryKey)) return\n this.deliveredCommandKeys.add(deliveryKey)\n const meta = { toolCallId }\n this.emitter.emit(\"command\", { action, payload, toolCallId })\n this.commands.dispatch(action, payload, meta)\n }\n\n private notifySandboxOom(key: string): void {\n if (this.oomNotifiedKeys.has(key)) return\n this.oomNotifiedKeys.add(key)\n this.update((s) => addErrorMessage(s, OOM_MESSAGE))\n this.emitter.emit(\"sandboxOom\", { toolCallId: key })\n }\n\n /**\n * 权威刷新(运行结束 / 重连补数):**按当前窗口第一条发言取窗口**,不再另记\"用户想看哪段\"。\n *\n * 窗口本身就是\"用户在看哪段\":首屏就是最新一页,向上翻页 / 定位之后首条就是用户滚到的位置。\n * 直接拿 `from_entry_id = 当前窗口第一条 turn_id` 去取,运行结束、重连补数、翻页之后的对账\n * 是同一条规则,不需要意图、锚点、已落地锚点这些状态;窗口首条已经不在分支上(404 / 409)时\n * 回落到最新一页。\n */\n private refreshAuthoritativeHistory(options: {\n liveRevisionAtStart?: number\n modeRevisionAtStart?: number\n } = {}): Promise<boolean> {\n let entryGone = false\n const locateTokenAtStart = this.locateToken\n return this.replaceFromHistory({\n ...options,\n // 锚点在**这次操作真正开始**时采样:排队期间用户可能刚定位过,那时窗口首条才是他要的。\n fromEntryId: () => this.state.turns[0]?.turn_id,\n onError: (error) => {\n entryGone = isEntryGoneError(error)\n },\n }).then((located) => {\n if (located || !entryGone) return located\n // 期间用户又点了别的(流水号变了):这次回落不再插队——队列里已经有新的定位,\n // 它提交之后我再拿最新一页盖上去,用户那次点击就白点了。\n if (this.locateToken !== locateTokenAtStart) return false\n // 窗口首条已经不在当前分支上了(rewind / checkout 换了分支):回落到最新一页。\n return this.replaceFromHistory(options)\n })\n }\n\n private replaceFromHistory(options: {\n suppressErrors?: boolean\n liveRevisionAtStart?: number\n modeRevisionAtStart?: number\n /** 按这条发言定位:服务端返回\"从它到最新\"的窗口,而不是最新一页。传函数则在实际取数时求值。 */\n fromEntryId?: string | (() => string | undefined)\n /** 这次替换是否已被取代(用户改选了别的发言);返回 true 时整条丢弃。 */\n isStale?: () => boolean\n /** 中止在途请求(用户改选下一条时用);中止后同样整条丢弃。 */\n signal?: AbortSignal\n /** 取数失败时上报原始错误(调用方要区分\"目标没了\"和\"这次没取到\")。 */\n onError?: (error: unknown) => void\n } = {}): Promise<boolean> {\n if (this.disposed) return Promise.resolve(false)\n const operationEpoch = this.timelineEpoch\n const liveRevisionAtStart = options.liveRevisionAtStart ?? this.liveRevision\n const modeRevisionAtStart = options.modeRevisionAtStart ?? this.modeRevision\n // Invalidate immediately so the current window cannot accept a late\n // older page while this replacement waits in the queue, and release its\n // dedupe ownership before a repaired cursor can become visible.\n this.invalidateOlderPaging()\n this.replaceInFlight += 1\n const operation = async (): Promise<boolean> => {\n let previousNextBefore: string | null = null\n // 这次替换被作废(会话已释放 / timeline 被重写 / 被更新的定位取代)时,游标在下面\n // 已经被清成 null:还回去,否则窗口还在、向上翻页却没了锚点。\n const restoreCursor = () => {\n if (this.disposed || previousNextBefore === null) return\n this.update((state) => ({\n ...state,\n nextBefore: previousNextBefore,\n loadingOlder: false,\n }))\n }\n try {\n if (this.disposed || operationEpoch !== this.timelineEpoch) return false\n if (options.isStale?.()) return false\n // A previous queued replace may have committed after this replace was\n // requested. Re-establish the boundary when this operation actually\n // starts so its window cannot leak an older request into this one.\n this.invalidateOlderPaging()\n previousNextBefore = this.state.nextBefore\n this.update((state) => ({ ...state, nextBefore: null, loadingOlder: false }))\n const signal = options.signal\n const fromEntryId =\n typeof options.fromEntryId === \"function\" ? options.fromEntryId() : options.fromEntryId\n const page = await this.runtime.fetchTurnsPage(\n this.sessionId,\n fromEntryId ? { fromEntryId } : undefined,\n signal ? { signal } : undefined,\n )\n // 定位期间 timeline 被重写(rewind / checkout)时这份窗口已经属于旧分支:\n // 丢掉它,当前列表保持原样。用户在途中改选了别的发言同理。\n if (this.disposed || operationEpoch !== this.timelineEpoch) {\n restoreCursor()\n return false\n }\n if (options.isStale?.()) {\n restoreCursor()\n return false\n }\n if (!this.joined) this.seedToolCallDeliveryBaseline(page.turns)\n this.update((state) => {\n const next = withTurns(\n state,\n replaceWindow(state.turns, page.turns, liveRevisionAtStart, {\n current: this.liveRevision,\n byTurnId: this.liveRevisions,\n }),\n )\n return {\n ...next,\n mode:\n this.modeRevision === modeRevisionAtStart\n ? page.currentMode\n : state.mode,\n nextBefore: page.nextBefore,\n loadingOlder: false,\n }\n })\n this.pruneOptimisticLiveRevisions()\n this.projectionBuilder._seedTurns(this.state.turns)\n return true\n } catch (error) {\n options.onError?.(error)\n if (!this.disposed && operationEpoch === this.timelineEpoch) {\n this.update((state) => ({\n ...state,\n nextBefore: previousNextBefore,\n loadingOlder: false,\n }))\n }\n if (options.suppressErrors === false) throw error\n // Keep the visible snapshot. Reconnect, terminal repair, or explicit\n // reload will enqueue another authoritative replace.\n return false\n } finally {\n this.replaceInFlight -= 1\n }\n }\n const run = this.replaceQueue.then(operation)\n this.replaceQueue = run.catch(() => undefined)\n return run\n }\n\n private invalidateOlderPaging(): void {\n this.pagingGeneration += 1\n this.olderPending = null\n }\n\n private beginCommandRecovery(): number {\n this.commandRecoveryGeneration += 1\n this.commandRestoreRetryAttempt = 0\n this.bufferedCommandDeliveries ??= []\n if (this.commandRestoreRetryHandle !== null) {\n globalThis.clearTimeout(this.commandRestoreRetryHandle)\n this.commandRestoreRetryHandle = null\n }\n return this.commandRecoveryGeneration\n }\n\n private scheduleHistoricalCommandRestore(generation: number): void {\n const restore = async () => {\n if (this.disposed || generation !== this.commandRecoveryGeneration) return\n try {\n const commands = await this.runtime.fetchCommands(this.sessionId)\n if (this.disposed) return\n for (const command of commands) {\n if (this.disposed) return\n this.deliverCommandNow({\n deliveryKey: commandDeliveryKey(command.deliveryId),\n action: command.action,\n payload: command.payload,\n toolCallId: command.toolCallId,\n })\n }\n // A newer reconnect has already installed another observation\n // boundary. Its snapshot must decide when the shared live suffix is\n // safe to release; an older response may only seed dedupe state.\n if (generation !== this.commandRecoveryGeneration) return\n this.commandRestoreRetryAttempt = 0\n this.flushBufferedCommands(generation)\n } catch {\n // Keep the barrier closed: releasing its live suffix would make a\n // later authoritative prefix arrive out of order. Retry this\n // generation in the background so a healthy socket does not leave the\n // command lane frozen forever.\n if (\n !this.disposed &&\n generation === this.commandRecoveryGeneration &&\n this.commandRestoreRetryHandle === null\n ) {\n const retryDelay = Math.min(\n COMMAND_RESTORE_RETRY_BASE_MS * 2 ** this.commandRestoreRetryAttempt,\n COMMAND_RESTORE_RETRY_MAX_MS,\n )\n this.commandRestoreRetryAttempt += 1\n this.commandRestoreRetryHandle = globalThis.setTimeout(() => {\n this.commandRestoreRetryHandle = null\n if (!this.disposed && generation === this.commandRecoveryGeneration) {\n this.scheduleHistoricalCommandRestore(generation)\n }\n }, retryDelay)\n }\n }\n }\n const run = this.commandRestoreQueue.then(restore)\n this.commandRestoreQueue = run.catch(() => undefined)\n }\n\n private flushBufferedCommands(generation: number): void {\n const pending = [...(this.bufferedCommandDeliveries ?? [])]\n // Keep a barrier installed while invoking user handlers: they may\n // synchronously emit another command, reconnect, or dispose this session.\n this.bufferedCommandDeliveries = []\n let index = 0\n while (index < pending.length) {\n if (this.disposed) return\n if (generation !== this.commandRecoveryGeneration) {\n const currentGenerationBuffer = this.bufferedCommandDeliveries ?? []\n this.bufferedCommandDeliveries = [\n ...pending.slice(index),\n ...currentGenerationBuffer,\n ]\n return\n }\n this.deliverCommandNow(pending[index]!)\n index += 1\n const reentrantBuffer = this.bufferedCommandDeliveries\n if (index === pending.length && reentrantBuffer && reentrantBuffer.length > 0) {\n pending.push(...reentrantBuffer)\n this.bufferedCommandDeliveries = []\n }\n }\n if (!this.disposed && generation === this.commandRecoveryGeneration) {\n this.bufferedCommandDeliveries = null\n }\n }\n\n /** 首次订阅前的 REST 历史建立语义事件基线,随后同一工具的订阅回放不再投递。 */\n private seedToolCallDeliveryBaseline(turns: TurnProjection[]): void {\n for (const turn of turns) {\n for (const toolCall of turn.tool_calls) {\n this.seenToolCallIds.add(toolCall.id)\n if (\n toolCall.status === \"done\" ||\n toolCall.status === \"error\" ||\n toolCall.status === \"cancelled\"\n ) {\n this.finishedToolCallIds.add(toolCall.id)\n }\n }\n }\n }\n\n private ensureJoined(liveRevisionBoundary = this.liveRevision): Promise<void> {\n if (this.joined) return Promise.resolve()\n if (this.joinPending) return this.joinPending\n\n const join = this.runtime\n .emitWithAck(\n \"session:subscribe\",\n {\n session_id: this.sessionId,\n event_format: \"raw\",\n resume: true,\n },\n 5_000,\n )\n .then((response) => {\n if (response && response.ok === false) {\n throw new Error(\n typeof response.message === \"string\" && response.message\n ? response.message\n : \"Session subscription failed\",\n )\n }\n this.joined = true\n this._applyRunningState(Boolean(response?.is_running), liveRevisionBoundary)\n })\n .finally(() => {\n this.joinPending = null\n })\n\n this.joinPending = join\n return join\n }\n\n private async ensureIdleBeforeSend(): Promise<void> {\n // 客户端已知有运行在跑时不能走这段\"修好上一轮收尾\"的停止逻辑:它发的 chat:stop\n // 会取消正在跑的那一轮并暂停消息队列。运行中提交交给服务端判定排队即可。\n if (this.state.isStreaming) return\n if (Date.now() - this.recentChatEndAt > 3000) return\n const deadline = Date.now() + 3000\n while (Date.now() < deadline) {\n const response = await this.stop()\n const status = String(response.status ?? \"\")\n if (status !== \"stopping\") return\n await new Promise((resolve) => globalThis.setTimeout(resolve, 150))\n }\n }\n}\n","import type { BladeClient } from \"../blade-client\"\nimport type { PatchEnvelope, TurnProjection } from \"../schemas/projection\"\nimport { AuthBusyReconnect } from \"../shared/auth-busy\"\nimport { acknowledgeTurnEvents, type RawEvent } from \"../shared/projection\"\nimport { AgentSession, type SessionRuntime } from \"./agent-session\"\nimport type { ConnectionStatus } from \"./state\"\n\nconst BACKGROUND_STATUSES = [\n \"starting\",\n \"running\",\n \"cancelling\",\n \"succeeded\",\n \"failed\",\n \"cancelled\",\n \"lost\",\n] as const\n\ntype BackgroundStatus = (typeof BACKGROUND_STATUSES)[number]\n\n/** Keep an unknown status honest instead of guessing success. */\nfunction normalizeBackgroundStatus(value: unknown): BackgroundStatus {\n return (BACKGROUND_STATUSES as readonly string[]).includes(value as string)\n ? (value as BackgroundStatus)\n : \"running\"\n}\n\ntype BackgroundTaskEvent = {\n id?: string\n task_id?: string\n command?: string\n description?: string\n status?: string\n failure_reason?: string | null\n exit_code?: number | null\n elapsed_seconds?: number\n output_lines_count?: number\n output_preview?: string[]\n}\n\nexport interface SessionConnectOptions {\n /**\n * 在会话进入事件路由后、历史加载与房间订阅开始前同步执行。\n * 适合安装不能漏掉 bootstrap 回放事件的监听器。\n */\n setup?: (session: AgentSession) => void\n}\n\n/**\n * 每个 BladeClient 一个:管理一条 Socket.IO 连接,按 session_id 把事件\n * 路由给各 AgentSession 实例。多会话共享连接、状态互不干扰。\n */\nexport class SessionHub {\n private readonly client: BladeClient\n private readonly sessions = new Map<string, AgentSession>()\n private readonly bootstrapPending = new Map<string, Promise<AgentSession>>()\n /** 每个会话当前有多少方持有(connect 一次 +1,dispose 一次 -1)。 */\n private readonly holdCounts = new Map<string, number>()\n private connection: ConnectionStatus = \"disconnected\"\n private readonly connectionListeners = new Set<(status: ConnectionStatus) => void>()\n private bound = false\n private hasConnected = false\n private readonly authBusyReconnect = new AuthBusyReconnect()\n\n constructor(client: BladeClient) {\n this.client = client\n }\n\n /** 当前 Socket.IO 连接状态。 */\n getConnection(): ConnectionStatus {\n return this.connection\n }\n\n /** 订阅连接状态变化。 */\n onConnectionChange(listener: (status: ConnectionStatus) => void): () => void {\n this.connectionListeners.add(listener)\n return () => {\n this.connectionListeners.delete(listener)\n }\n }\n\n /**\n * 取得(或复用)一个会话的 AgentSession,并完成历史加载 + 房间订阅。\n *\n * 每次调用都算一份持有,调用方用完必须 `dispose()` 归还。复用同一实例时\n * 只有最后一份归还才退订房间——否则 StrictMode 双跑、路由抖动这类\"连两次\n * 只释放一次\"的场景会把仍在用的会话退订掉,之后所有 turn/chat 事件静默丢失。\n */\n async connect(sessionId: string, options: SessionConnectOptions = {}): Promise<AgentSession> {\n const existing = this.sessions.get(sessionId)\n if (existing && !existing.isDisposed) {\n this.hold(sessionId)\n try {\n options.setup?.(existing)\n } catch (error) {\n // setup 属于本次持有;失败只归还这一份,不影响其它使用方。\n existing.dispose()\n throw error\n }\n return this.bootstrapPending.get(sessionId) ?? existing\n }\n this.ensureBound()\n const session = new AgentSession(sessionId, this.runtimeFor(), this.connection)\n this.sessions.set(sessionId, session)\n this.hold(sessionId)\n try {\n options.setup?.(session)\n } catch (error) {\n session.dispose()\n throw error\n }\n this.ensureConnected()\n const bootstrap = session._bootstrap().then(() => session)\n this.bootstrapPending.set(sessionId, bootstrap)\n try {\n return await bootstrap\n } catch (error) {\n // 启动失败的会话不留给任何人,连同其它在途持有一起清掉\n this.forceRelease(session)\n throw error\n } finally {\n if (this.bootstrapPending.get(sessionId) === bootstrap) {\n this.bootstrapPending.delete(sessionId)\n }\n }\n }\n\n /** 已有实例则返回,不触发网络请求。 */\n peek(sessionId: string): AgentSession | undefined {\n if (this.bootstrapPending.has(sessionId)) return undefined\n const session = this.sessions.get(sessionId)\n return session && !session.isDisposed ? session : undefined\n }\n\n /** 手动重连(例如登录态变化后)。 */\n reconnect(): void {\n // 登录态可能早于首个 AgentSession 初始化;必须先绑定连接监听,\n // 否则 connect 事件会在 hub 尚未监听时丢失,状态永久停在 connecting。\n this.ensureBound()\n this.authBusyReconnect.cancel()\n const socket = this.client.socket()\n socket.disconnect()\n this.setConnection(\"connecting\")\n socket.connect()\n }\n\n /** 断开连接(不清理 session 实例)。 */\n disconnect(): void {\n this.authBusyReconnect.cancel()\n this.client.socket().disconnect()\n this.setConnection(\"disconnected\")\n }\n\n /** 清理当前身份下缓存的全部会话,避免切换登录身份后复用旧快照。 */\n disposeAll(): void {\n this.authBusyReconnect.cancel()\n this.bootstrapPending.clear()\n for (const session of [...this.sessions.values()]) {\n // 换身份后旧会话一律作废,不看还有几方持有\n this.forceRelease(session)\n }\n }\n\n /**\n * @internal 底层 socket 被换掉时由 BladeClient 调用(如 setBaseUrl)。\n * 事件监听器绑在旧 socket 实例上,换新实例后必须重绑,否则所有\n * turn:* / chat:* 事件都会静默丢弃。\n */\n _handleSocketReplaced(): void {\n this.authBusyReconnect.cancel()\n this.bound = false\n this.setConnection(\"disconnected\")\n if (this.sessions.size === 0) return\n // 已有会话:在新 socket 上重建监听;连接成功事件会重新加入房间并补数\n this.ensureBound()\n this.ensureConnected()\n }\n\n private runtimeFor(): SessionRuntime {\n return {\n emitEvent: (event, data) => {\n // biome-ignore lint/suspicious/noExplicitAny: 泛化 emit,事件名由调用方保证\n ;(this.client.socket() as any).emit(event, data)\n },\n emitWithAck: (event, data, timeoutMs) =>\n new Promise((resolve, reject) => {\n // biome-ignore lint/suspicious/noExplicitAny: 泛化 emit,事件名由调用方保证\n ;(this.client.socket() as any)\n .timeout(timeoutMs)\n .emit(event, data, (err: Error | null, response?: Record<string, unknown>) => {\n if (err) {\n reject(err)\n return\n }\n resolve(response)\n })\n }),\n ensureConnected: () => this.ensureConnected(),\n fetchTurnsPage: (sessionId, query, init) =>\n this.client.sessions.getSessionTurnsPage(sessionId, query, init),\n fetchTurnIndex: (sessionId) => this.client.sessions.getSessionTurnIndex(sessionId),\n fetchCommands: (sessionId) => this.client.sessions.getSessionTurnCommands(sessionId),\n fetchSessionInfo: (sessionId) => this.client.sessions.getSession(sessionId),\n updateReplay: (sessionId, payload) =>\n this.client.sessions\n .updateReplaySession(sessionId, payload)\n .then((result) => result.replay_state ?? null),\n listDir: (sessionId, dirPath) => this.client.sessions.listDir(sessionId, dirPath),\n countFiles: (sessionId, dirPath) => this.client.sessions.countFiles(sessionId, dirPath),\n downloadFile: (sessionId, filePath, downloadName) =>\n this.client.sessions.downloadFile(sessionId, filePath, downloadName),\n attachAppCli: (sessionId, definition) =>\n this.client.sessions.attachAppCli(sessionId, definition),\n onDispose: (session) => this.release(session),\n }\n }\n\n /** 记一份持有。 */\n private hold(sessionId: string): void {\n this.holdCounts.set(sessionId, (this.holdCounts.get(sessionId) ?? 0) + 1)\n }\n\n /**\n * 归还一份持有;还剩别的持有者时返回 false,让 AgentSession 保持可用。\n * 归零才退订房间并从路由表移除。\n */\n private release(session: AgentSession): boolean {\n const remaining = (this.holdCounts.get(session.sessionId) ?? 0) - 1\n if (remaining > 0) {\n this.holdCounts.set(session.sessionId, remaining)\n return false\n }\n this.holdCounts.delete(session.sessionId)\n if (this.sessions.get(session.sessionId) === session) {\n this.sessions.delete(session.sessionId)\n }\n if (this.sessions.size === 0) {\n this.authBusyReconnect.cancel()\n }\n // biome-ignore lint/suspicious/noExplicitAny: session:unsubscribe 是后端自定义事件\n ;(this.client.socket() as any).emit(\"session:unsubscribe\", { session_id: session.sessionId })\n return true\n }\n\n /** 不管还有几方持有都立即释放(启动失败、切换身份)。 */\n private forceRelease(session: AgentSession): void {\n this.holdCounts.delete(session.sessionId)\n session.dispose()\n if (this.sessions.size === 0) {\n this.authBusyReconnect.cancel()\n }\n }\n\n private ensureConnected(): void {\n const socket = this.client.socket()\n if (socket.connected || socket.active || this.authBusyReconnect.pending) return\n this.setConnection(\"connecting\")\n socket.connect()\n }\n\n private setConnection(status: ConnectionStatus): void {\n if (this.connection === status) return\n this.connection = status\n for (const session of this.sessions.values()) {\n session._setConnection(status)\n }\n for (const listener of [...this.connectionListeners]) {\n try {\n listener(status)\n } catch (error) {\n console.warn(\"[agent-client] 连接状态回调抛出异常:\", error)\n }\n }\n }\n\n /** 事件带 session_id 时精确路由;缺省时按当前唯一活跃会话兜底。 */\n private route(sessionId: string | null | undefined): AgentSession[] {\n if (sessionId) {\n const session = this.sessions.get(sessionId)\n return session && !session.isDisposed ? [session] : []\n }\n const active = [...this.sessions.values()].filter((session) => !session.isDisposed)\n return active.length === 1 ? active : []\n }\n\n private ensureBound(): void {\n if (this.bound) return\n this.bound = true\n // biome-ignore lint/suspicious/noExplicitAny: 事件桥接层统一收敛混合 payload\n const socket = this.client.socket() as any\n\n socket.on(\"connect\", () => {\n this.authBusyReconnect.cancel()\n const isReconnect = this.hasConnected\n this.hasConnected = true\n this.setConnection(\"connected\")\n if (isReconnect) {\n for (const session of this.sessions.values()) {\n void session._rejoinAfterReconnect()\n // 队列广播不会重放:断线期间错过的入队 / 编辑只能主动补一次。\n // 不放进 _rejoinAfterReconnect 的订阅串行队列,避免慢 ack 拖住重订阅。\n void session.refreshQueue()\n }\n }\n })\n socket.on(\"connect_error\", (error: unknown) => {\n this.setConnection(\"disconnected\")\n if (this.sessions.size === 0) {\n this.authBusyReconnect.cancel()\n return\n }\n if (this.authBusyReconnect.schedule(error, () => {\n const current = this.client.socket()\n if (current !== socket || current.connected || current.active) return\n this.setConnection(\"connecting\")\n current.connect()\n })) return\n this.authBusyReconnect.cancel()\n })\n socket.on(\"disconnect\", () => {\n this.authBusyReconnect.cancel()\n this.setConnection(\"disconnected\")\n })\n socket.io.on(\"reconnect_attempt\", () => this.setConnection(\"reconnecting\"))\n\n socket.on(\"turn:start\", (data: TurnProjection & { session_id?: string }) => {\n for (const session of this.route(data.session_id)) session._handleTurnStart(data)\n })\n socket.on(\"turn:patch\", (data: PatchEnvelope & { session_id?: string }) => {\n for (const session of this.route(data.session_id)) session._handleTurnPatch(data)\n })\n socket.on(\"turn:end\", (data: TurnProjection & { session_id?: string }) => {\n for (const session of this.route(data.session_id)) session._handleTurnEnd(data)\n })\n socket.on(\n \"turn:timing\",\n (data: {\n session_id?: string\n loop_name?: string\n turn_id?: string\n first_token_delivery_ms?: number\n }) => {\n for (const session of this.route(data.session_id)) {\n session._handleTurnEvents([\n { type: \"llm:first_token:delivered\", payload: data },\n ])\n }\n },\n )\n socket.on(\n \"turn:events\",\n (\n data: { session_id?: string; events: RawEvent[]; replayed?: boolean },\n acknowledge?: () => void,\n ) => {\n acknowledgeTurnEvents(acknowledge)\n for (const session of this.route(data.session_id)) {\n session._handleTurnEvents(data.events ?? [], data.replayed === true)\n }\n },\n )\n socket.on(\"chat:start\", (data?: { session_id?: string }) => {\n for (const session of this.route(data?.session_id)) session._handleChatStart()\n })\n socket.on(\"chat:end\", (data?: { status?: string; session_id?: string }) => {\n for (const session of this.route(data?.session_id)) {\n session._handleChatEnd(data?.status ?? \"completed\")\n }\n })\n socket.on(\"system:error\", (data: { message: string; session_id?: string }) => {\n for (const session of this.route(data.session_id)) session._handleSystemError(data.message)\n })\n // 队列广播只发给 owner 房间;快照本体就是载荷,旧 revision 由会话实例丢弃。\n socket.on(\"chat:queue:updated\", (data: Record<string, unknown> & { session_id?: string }) => {\n for (const session of this.route(data?.session_id)) session._handleQueueUpdated(data)\n })\n socket.on(\n \"system:notification\",\n (data: { session_id?: string } & Record<string, unknown>) => {\n for (const session of this.route(data.session_id)) {\n session._handleSystemNotification(\"root\", data)\n }\n },\n )\n socket.on(\"task:updated\", (data: { tasks: unknown[]; session_id?: string }) => {\n for (const session of this.route(data.session_id)) session._handleTaskUpdated(data.tasks)\n })\n socket.on(\"task:synced\", (data: { tasks: unknown[]; session_id?: string }) => {\n for (const session of this.route(data.session_id)) session._handleTaskUpdated(data.tasks)\n })\n socket.on(\n \"workspace:files_changed\",\n (data: { session_id?: string; file_path?: string }) => {\n for (const session of this.route(data.session_id)) {\n session._handleWorkspaceFilesChanged(data.file_path)\n }\n },\n )\n socket.on(\n \"session:updated\",\n (data: {\n session_id?: string\n workspace_path?: string\n chat_group_id?: string | null\n intent?: string\n status?: import(\"../schemas/session\").SessionStatus\n model?: string | null\n bound_skill_id?: string | null\n replay_state?: Record<string, unknown> | null\n }) => {\n for (const session of this.route(data.session_id)) {\n session._handleSessionUpdated(data)\n }\n },\n )\n socket.on(\"session:rewind\", (data: { checkpoint_id: string; session_id?: string }) => {\n for (const session of this.route(data.session_id)) {\n session._handleRewind(data.checkpoint_id)\n }\n })\n socket.on(\n \"replay:input_mismatch\",\n (data: { session_id?: string; actual_message?: string; expected_message?: string }) => {\n for (const session of this.route(data.session_id)) session._handleReplayMismatch(data)\n },\n )\n socket.on(\"artifact:created\", (data: Record<string, unknown> & { session_id?: string }) => {\n this.routeArtifact(data, \"created\")\n })\n socket.on(\"artifact:updated\", (data: Record<string, unknown> & { session_id?: string }) => {\n this.routeArtifact(data, \"updated\")\n })\n socket.on(\"bg:started\", (data: BackgroundTaskEvent & { session_id?: string }) => {\n const taskId =\n typeof data.task_id === \"string\" ? data.task_id : typeof data.id === \"string\" ? data.id : \"\"\n if (!taskId) return\n for (const session of this.route(data.session_id)) {\n session._handleBackgroundTask({\n id: taskId,\n command: typeof data.command === \"string\" ? data.command : \"\",\n description: typeof data.description === \"string\" ? data.description : undefined,\n status: \"running\",\n elapsedSeconds: typeof data.elapsed_seconds === \"number\" ? data.elapsed_seconds : 0,\n })\n }\n })\n socket.on(\n \"bg:tasks_completed\",\n (data: { tasks?: BackgroundTaskEvent[]; session_id?: string }) => {\n for (const session of this.route(data.session_id)) {\n for (const task of data.tasks ?? []) {\n const taskId =\n typeof task.id === \"string\"\n ? task.id\n : typeof task.task_id === \"string\"\n ? task.task_id\n : \"\"\n if (!taskId) continue\n session._handleBackgroundTask({\n id: taskId,\n command: typeof task.command === \"string\" ? task.command : \"\",\n description: typeof task.description === \"string\" ? task.description : undefined,\n // Pass the server's status through unchanged. Collapsing it here\n // made subscribers see a successful-looking \"done\" for tasks the\n // REST API correctly reported as cancelled or lost.\n status: normalizeBackgroundStatus(task.status),\n failureReason:\n typeof task.failure_reason === \"string\" ? task.failure_reason : undefined,\n exitCode:\n typeof task.exit_code === \"number\" || task.exit_code === null\n ? task.exit_code\n : undefined,\n elapsedSeconds: typeof task.elapsed_seconds === \"number\" ? task.elapsed_seconds : 0,\n output:\n Array.isArray(task.output_preview) && task.output_preview.length > 0\n ? task.output_preview.join(\"\\n\")\n : undefined,\n })\n }\n }\n },\n )\n }\n\n private routeArtifact(\n data: Record<string, unknown> & { session_id?: string },\n kind: \"created\" | \"updated\",\n ): void {\n const filePath = typeof data.file_path === \"string\" ? data.file_path : \"\"\n if (!filePath) return\n for (const session of this.route(data.session_id)) {\n session._handleWorkspaceFilesChanged(filePath)\n session._handleArtifact({\n filePath,\n contentType: typeof data.content_type === \"string\" ? data.content_type : \"\",\n title: typeof data.title === \"string\" ? data.title : filePath,\n content: typeof data.content === \"string\" ? data.content : \"\",\n oldString: typeof data.old_string === \"string\" ? data.old_string : undefined,\n newString: typeof data.new_string === \"string\" ? data.new_string : undefined,\n kind,\n })\n }\n }\n}\n","import { io, type Socket } from \"socket.io-client\"\nimport { buildSocketAuth, resolveAuthToken, type AuthOptions } from \"./auth\"\nimport type { ClientToServerEvents, ServerToClientEvents } from \"./types/socket-events\"\n\nexport type TypedSocket = Socket<ServerToClientEvents, ClientToServerEvents>\n\nexport interface CreateSocketOptions extends AuthOptions {\n baseUrl: string\n path?: string\n}\n\nexport function createSocket(options: CreateSocketOptions): TypedSocket {\n const token = resolveAuthToken(options)\n return io(options.baseUrl, {\n path: options.path ?? \"/socket.io\",\n withCredentials: true,\n query: token ? { token } : undefined,\n auth:\n typeof options.token === \"function\"\n ? (cb) => cb(buildSocketAuth(options) ?? {})\n : (buildSocketAuth(options) ?? {}),\n autoConnect: false,\n })\n}\n","export interface AuthOptions {\n token?: string | (() => string | null | undefined)\n}\n\nexport function buildSocketAuth(options: AuthOptions): { token: string } | undefined {\n const token = resolveAuthToken(options)\n return token ? { token } : undefined\n}\n\nexport function resolveAuthToken(options: AuthOptions): string | null {\n const token = typeof options.token === \"function\" ? options.token() : options.token\n return token ? token : null\n}\n","import {\n loginWithPopup,\n readStoredToken,\n writeStoredToken,\n type LoginOptions,\n type LoginResult,\n type TokenStorageMode,\n} from \"./auth-login\"\nimport {\n BladeApiError,\n type BladeFetchInit,\n type HttpMethod,\n buildBackendUrl,\n decorateAuthError,\n extractErrorDetail,\n} from \"./rest\"\nimport { AuthResource } from \"./resources/auth\"\nimport { HeadlessResource } from \"./resources/headless\"\nimport { ComputersResource } from \"./resources/computers\"\nimport { ModelsResource } from \"./resources/models\"\nimport { SessionsResource } from \"./resources/sessions\"\nimport { PluginsResource } from \"./resources/plugins\"\nimport { ChatGroupsResource } from \"./resources/chat-groups\"\nimport { SiteVisitsResource } from \"./resources/site-visits\"\nimport { SessionHub } from \"./session/hub\"\nimport { createSocket, type TypedSocket } from \"./socket\"\n\nexport interface BladeClientOptions {\n /** 后端地址,如 \"https://blade.example.com\"。浏览器里传空字符串则使用当前域名。 */\n baseUrl: string\n /**\n * 访问令牌(PAT)。不传时按 cookie 会话模式工作;\n * 浏览器场景也可以不传,改用 client.auth.login() 弹窗登录。\n */\n token?: string | (() => string | null | undefined)\n /**\n * Socket.IO 专用令牌。第一方应用可在 REST 继续使用 cookie 刷新的同时,\n * 把 cookie 换得的短期令牌只用于实时连接;不传时复用 token。\n */\n socketToken?: string | (() => string | null | undefined)\n /** login() 取得的令牌存放位置,默认 \"local\"(localStorage,刷新页面不掉登录)。 */\n tokenStorage?: TokenStorageMode\n fetchImpl?: typeof fetch\n onRefreshSuccess?: () => void | Promise<void>\n}\n\nconst REFRESH_PATH = \"/api/auth/refresh\"\n\nexport class BladeClient {\n private refreshPromise: Promise<boolean> | null = null\n private socketInstance: TypedSocket | null = null\n private readonly socketReplacementListeners = new Set<() => void>()\n /** login() / setToken() 热挂载的令牌,优先级高于构造参数。 */\n private runtimeToken: string | null = null\n readonly options: BladeClientOptions\n readonly auth: AuthResource\n readonly headless: HeadlessResource\n readonly computers: ComputersResource\n readonly models: ModelsResource\n readonly sessions: SessionsResource\n /** 按用户读取的插件目录与图标;没有会话时也能用。 */\n readonly plugins: PluginsResource\n readonly chatGroups: ChatGroupsResource\n /**\n * 全站访问统计:匿名读写,不带 bearer 也不触发登录刷新。\n * 只有内置 Web 的同源页面使用,第三方宿主页面不会被自动统计。\n */\n readonly siteVisits: SiteVisitsResource\n /** 实时会话中枢:client.sessions.connect() 内部使用,一般不直接访问。 */\n readonly hub: SessionHub\n\n constructor(options: BladeClientOptions) {\n this.options = {\n ...options,\n baseUrl: normalizeBaseUrl(options.baseUrl),\n }\n this.auth = new AuthResource(this)\n this.headless = new HeadlessResource(this)\n this.computers = new ComputersResource(this)\n this.models = new ModelsResource(this)\n this.sessions = new SessionsResource(this)\n this.plugins = new PluginsResource(this)\n this.chatGroups = new ChatGroupsResource(this)\n this.siteVisits = new SiteVisitsResource(this)\n this.hub = new SessionHub(this)\n if (this.options.token === undefined) {\n this.runtimeToken = readStoredToken(this.options.baseUrl)\n }\n }\n\n /**\n * 弹窗授权登录:用户在弹出的授权页点击\"许可授权\"后自动取得 PAT,\n * REST 与 Socket.IO 立即生效。只在浏览器可用。\n */\n async login(options?: LoginOptions): Promise<LoginResult> {\n const result = await loginWithPopup(this, options)\n this.setToken(result.token)\n return result\n }\n\n /** 退出登录:清除 login() 存储的令牌并断开实时连接。 */\n logoutToken(): void {\n this.setToken(null)\n this.hub.disconnect()\n }\n\n /** 热挂载访问令牌(null 表示清除)。会重建 Socket.IO 连接以携带新凭证。 */\n setToken(token: string | null): void {\n const previousToken = this.resolveToken()\n this.runtimeToken = token\n const nextToken = this.resolveToken()\n if (previousToken !== nextToken) {\n this.hub.disposeAll()\n }\n writeStoredToken(this.options.baseUrl, token, this.options.tokenStorage ?? \"local\")\n if (this.socketInstance) {\n const wasConnected = this.socketInstance.connected || this.socketInstance.active\n this.socketInstance.disconnect()\n if (wasConnected || token) {\n this.socketInstance.connect()\n }\n }\n }\n\n /** 当前是否持有访问令牌(不代表令牌一定有效)。 */\n hasToken(): boolean {\n return Boolean(this.resolveRestToken())\n }\n\n /**\n * 当前访问令牌(PAT),未登录时为 null。\n *\n * SDK 只封装会话相关接口;其余长尾接口对照后端 Swagger(`<baseUrl>/docs`)\n * 用原生 fetch 自行调用,把本令牌填入 Authorization 头即可:\n *\n * ```ts\n * fetch(`${baseUrl}/api/memories/search?q=xxx`, {\n * headers: { Authorization: `Bearer ${client.token}` },\n * })\n * ```\n *\n * 安全约束:该令牌只应发往 baseUrl 同源接口,不要附加到第三方域名的请求上。\n */\n get token(): string | null {\n return this.resolveRestToken()\n }\n\n setBaseUrl(baseUrl: string): void {\n const nextBaseUrl = normalizeBaseUrl(baseUrl)\n if (nextBaseUrl === this.options.baseUrl) {\n return\n }\n // 后端地址是会话身份边界,不是普通传输重连。旧 session_id、历史快照\n // 和房间订阅都不能带到另一个后端;先在旧 socket 上释放并驱逐缓存。\n this.hub.disposeAll()\n this.options.baseUrl = nextBaseUrl\n if (this.socketInstance) {\n this.socketInstance.removeAllListeners()\n this.socketInstance.disconnect()\n this.socketInstance = null\n // 换掉 socket 实例后必须让 hub 重绑监听:监听器绑在旧实例上,\n // 不重绑的话新连接上的事件全部收不到。\n this.hub._handleSocketReplaced()\n for (const listener of [...this.socketReplacementListeners]) {\n try {\n listener()\n } catch (error) {\n console.warn(\"[agent-client] socket 替换回调抛出异常:\", error)\n }\n }\n }\n }\n\n /** 底层 Socket.IO 实例因后端地址变化而被替换时通知高级集成层。 */\n onSocketReplaced(listener: () => void): () => void {\n this.socketReplacementListeners.add(listener)\n return () => {\n this.socketReplacementListeners.delete(listener)\n }\n }\n\n socket(): TypedSocket {\n if (!this.socketInstance) {\n this.socketInstance = createSocket({\n baseUrl: this.options.baseUrl,\n token: () => this.resolveSocketToken(),\n })\n }\n return this.socketInstance\n }\n\n async json<T>(method: HttpMethod, path: string, body?: unknown): Promise<T> {\n const response = await this.fetch(method, path, {\n body: body === undefined ? undefined : JSON.stringify(body),\n headers: body === undefined ? undefined : { \"content-type\": \"application/json\" },\n })\n return readJsonResponse(response)\n }\n\n async jsonFromInit<T>(path: string, init: RequestInit = {}): Promise<T> {\n const method = (init.method ?? \"GET\").toUpperCase() as HttpMethod\n const headers = new Headers(init.headers)\n if (init.body != null && !isFormData(init.body) && !headers.has(\"content-type\")) {\n headers.set(\"content-type\", \"application/json\")\n }\n const response = await this.fetch(method, path, {\n body: init.body,\n credentials: init.credentials,\n headers,\n signal: init.signal,\n })\n return readJsonResponse(response)\n }\n\n async text(method: HttpMethod, path: string): Promise<string> {\n const response = await this.fetch(method, path)\n return response.text()\n }\n\n async textFromInit(path: string, init: RequestInit = {}): Promise<string> {\n const method = (init.method ?? \"GET\").toUpperCase() as HttpMethod\n const response = await this.fetch(method, path, {\n body: init.body,\n credentials: init.credentials,\n headers: init.headers,\n signal: init.signal,\n })\n return response.text()\n }\n\n async responseFromInit(path: string, init: RequestInit = {}): Promise<Response> {\n const method = (init.method ?? \"GET\").toUpperCase() as HttpMethod\n return this.fetch(method, path, {\n body: init.body,\n credentials: init.credentials,\n headers: init.headers,\n signal: init.signal,\n })\n }\n\n async blob(method: HttpMethod, path: string): Promise<Blob> {\n const response = await this.fetch(method, path)\n return response.blob()\n }\n\n async formData(\n method: HttpMethod,\n path: string,\n form: FormData,\n options: { expectOk?: boolean; onUploadProgress?: (progress: UploadProgress) => void } = {},\n ): Promise<Response> {\n if (options.onUploadProgress && !this.options.fetchImpl && typeof XMLHttpRequest !== \"undefined\") {\n return this.formDataWithUploadProgress(method, path, form, options)\n }\n return this.fetch(method, path, { body: form, expectOk: options.expectOk })\n }\n\n async fetch(\n method: HttpMethod,\n path: string,\n init: BladeFetchInit = {},\n isRetry = false,\n ): Promise<Response> {\n const url = this.buildUrl(path)\n const response = await (this.options.fetchImpl ?? fetch)(url.toString(), {\n method,\n body: init.body,\n credentials: init.credentials ?? \"include\",\n headers: this.buildHeaders(url, init.headers),\n signal: init.signal,\n })\n\n if (response.status === 401 && !isRetry && this.shouldRefreshFor401(url)) {\n const refreshed = await this.tryRefreshUnlessAborted(init.signal)\n if (refreshed) {\n return this.fetch(method, path, init, true)\n }\n }\n\n if (init.expectOk !== false && !response.ok) {\n const detail = await extractErrorDetail(response)\n throw decorateAuthError(new BladeApiError(response, detail))\n }\n return response\n }\n\n buildAuthedUrl(path: string): string {\n const url = buildBackendUrl(this.options.baseUrl, path)\n const token = this.resolveTokenForUrl(url)\n if (token) {\n url.searchParams.set(\"token\", token)\n }\n return url.toString()\n }\n\n private buildHeaders(url: URL, headers?: HeadersInit): Headers {\n const result = new Headers(headers)\n if (!this.isSameBackendUrl(url)) {\n return result\n }\n // REST 不做版本校验:SDK 身份只在 Socket.IO 握手声明(见 socket.ts)。\n // 长尾接口设计上就让第三方用原生 fetch 直接调,这里不该塞额外标头。\n const token = this.resolveRestToken()\n if (token) {\n result.set(\"Authorization\", `Bearer ${token}`)\n }\n return result\n }\n\n private buildUrl(path: string): URL {\n return buildBackendUrl(this.options.baseUrl, path)\n }\n\n private baseUrlWithTrailingSlash(): string {\n return this.options.baseUrl.endsWith(\"/\") ? this.options.baseUrl : `${this.options.baseUrl}/`\n }\n\n private isSameBackendUrl(url: URL): boolean {\n const base = new URL(this.baseUrlWithTrailingSlash())\n if (url.origin !== base.origin) {\n return false\n }\n const basePath = base.pathname.replace(/\\/+$/, \"\")\n if (basePath === \"\") {\n return true\n }\n return url.pathname === basePath || url.pathname.startsWith(`${basePath}/`)\n }\n\n private shouldRefreshFor401(url: URL): boolean {\n const refreshUrl = this.buildUrl(REFRESH_PATH)\n return (\n this.isSameBackendUrl(url) &&\n url.pathname !== refreshUrl.pathname &&\n !this.hasExplicitBearerToken()\n )\n }\n\n private hasExplicitBearerToken(): boolean {\n return Boolean(this.resolveRestToken())\n }\n\n /**\n * 等一次令牌刷新,但调用方中止请求时不再等下去。\n *\n * 刷新本身是共享的(`refreshPromise`,别的请求也在等它),这里只是让这次已被取消的\n * 请求尽早结束——否则它会一直挂在调用方(定位)的串行队列里,用户改选的新目标要等到\n * 刷新结束才轮得到。\n */\n private async tryRefreshUnlessAborted(signal?: AbortSignal | null): Promise<boolean> {\n if (!signal) return this.tryRefresh()\n if (signal.aborted) throw new DOMException(\"The operation was aborted.\", \"AbortError\")\n let onAbort: (() => void) | undefined\n const aborted = new Promise<never>((_resolve, reject) => {\n onAbort = () => reject(new DOMException(\"The operation was aborted.\", \"AbortError\"))\n signal.addEventListener(\"abort\", onAbort, { once: true })\n })\n try {\n return await Promise.race([this.tryRefresh(), aborted])\n } finally {\n if (onAbort) signal.removeEventListener(\"abort\", onAbort)\n }\n }\n\n private async tryRefresh(): Promise<boolean> {\n if (this.refreshPromise) {\n return this.refreshPromise\n }\n\n this.refreshPromise = (async () => {\n try {\n const response = await (this.options.fetchImpl ?? fetch)(\n this.buildUrl(REFRESH_PATH).toString(),\n {\n method: \"POST\",\n credentials: \"include\",\n },\n )\n if (!response.ok) {\n return false\n }\n await this.options.onRefreshSuccess?.()\n return true\n } catch {\n return false\n } finally {\n this.refreshPromise = null\n }\n })()\n\n return this.refreshPromise\n }\n\n private resolveTokenForUrl(url: URL): string | null {\n if (!this.isSameBackendUrl(url)) {\n return null\n }\n return this.resolveRestToken()\n }\n\n private resolveRestToken(): string | null {\n return this.resolveToken()\n }\n\n private resolveSocketToken(): string | null {\n if (this.runtimeToken) return this.runtimeToken\n return resolveTokenOption(this.options.socketToken ?? this.options.token)\n }\n\n private resolveToken(): string | null {\n if (this.runtimeToken) return this.runtimeToken\n return resolveTokenOption(this.options.token)\n }\n\n private formDataWithUploadProgress(\n method: HttpMethod,\n path: string,\n form: FormData,\n options: { expectOk?: boolean; onUploadProgress?: (progress: UploadProgress) => void },\n isRetry = false,\n ): Promise<Response> {\n const url = this.buildUrl(path)\n const headers = this.buildHeaders(url)\n\n return new Promise((resolve, reject) => {\n const xhr = new XMLHttpRequest()\n xhr.open(method, url.toString(), true)\n xhr.withCredentials = true\n\n headers.forEach((value, key) => {\n xhr.setRequestHeader(key, value)\n })\n\n xhr.upload.onprogress = (event) => {\n options.onUploadProgress?.({\n loaded: event.loaded,\n total: event.lengthComputable ? event.total : undefined,\n percent: event.lengthComputable && event.total > 0 ? event.loaded / event.total : undefined,\n })\n }\n\n xhr.onerror = () => reject(new TypeError(\"Network request failed\"))\n xhr.ontimeout = () => reject(new TypeError(\"Network request timed out\"))\n xhr.onabort = () => reject(new DOMException(\"Request aborted\", \"AbortError\"))\n xhr.onload = async () => {\n if (xhr.status === 401 && !isRetry && this.shouldRefreshFor401(url)) {\n const refreshed = await this.tryRefresh()\n if (refreshed) {\n resolve(this.formDataWithUploadProgress(method, path, form, options, true))\n return\n }\n }\n\n const response = new Response(xhr.responseText, {\n status: xhr.status,\n statusText: xhr.statusText,\n headers: parseXhrHeaders(xhr.getAllResponseHeaders()),\n })\n if (options.expectOk !== false && !response.ok) {\n const detail = await extractErrorDetail(response.clone())\n reject(new BladeApiError(response, detail))\n return\n }\n options.onUploadProgress?.({ loaded: 1, total: 1, percent: 1 })\n resolve(response)\n }\n\n xhr.send(form)\n })\n }\n}\n\nfunction resolveTokenOption(\n tokenOption: string | (() => string | null | undefined) | undefined,\n): string | null {\n const token = typeof tokenOption === \"function\" ? tokenOption() : tokenOption\n return token ? token : null\n}\n\nexport interface UploadProgress {\n loaded: number\n total?: number\n percent?: number\n}\n\n/** Docker 给容器用的宿主机别名。浏览器里没有这条 DNS,怎么都解析不到。 */\nconst SANDBOX_ONLY_HOST = \"host.docker.internal\"\n\nfunction normalizeBaseUrl(baseUrl: string): string {\n const normalized = baseUrl.trim().replace(/\\/+$/, \"\")\n if (typeof window === \"undefined\") {\n // 沙盒里的 Node SDK 就该用 host.docker.internal,那是它唯一能连到宿主的地址。\n return normalized\n }\n if (!normalized) {\n return window.location.origin\n }\n assertBrowserReachable(normalized)\n return normalized\n}\n\n/**\n * 浏览器里拿到 `host.docker.internal` 就当场报错,不猜、不改、不静默降级。\n *\n * 智能体在沙盒里开发应用时,手边的后端地址是 `BLADE_API_URL`\n * (`http://host.docker.internal:8020`),很容易被原样写进前端配置。这个地址只有\n * 容器里解析得到,用户浏览器打不开——登录授权页会直接白屏,而 `client_origin` 却是\n * 真实 IP,故障看起来毫无头绪。与其替换主机名去猜一个\"可能对\"的地址,不如立刻把\n * 原因说清楚:这类配置错误必须在开发阶段就暴露出来。\n */\nfunction assertBrowserReachable(baseUrl: string): void {\n let hostname: string\n try {\n hostname = new URL(baseUrl, window.location.href).hostname\n } catch {\n return\n }\n if (hostname !== SANDBOX_ONLY_HOST) {\n return\n }\n throw new Error(\n `Blade Agent 地址 ${baseUrl} 只有沙盒内部解析得到,浏览器打不开。请把它改成用户浏览器能访问的地址(通常是访问这个应用时用的主机名 + Blade Server 端口)。`,\n )\n}\n\nfunction isFormData(value: BodyInit): boolean {\n return typeof FormData !== \"undefined\" && value instanceof FormData\n}\n\nfunction readJsonResponse<T>(response: Response): Promise<T> {\n if (response.status === 204 || response.headers.get(\"content-length\") === \"0\") {\n return Promise.resolve(undefined as T)\n }\n return response.json() as Promise<T>\n}\n\nfunction parseXhrHeaders(rawHeaders: string): Headers {\n const headers = new Headers()\n for (const line of rawHeaders.trim().split(/[\\r\\n]+/)) {\n const separatorIndex = line.indexOf(\":\")\n if (separatorIndex <= 0) continue\n headers.append(line.slice(0, separatorIndex).trim(), line.slice(separatorIndex + 1).trim())\n }\n return headers\n}\n","import { BladeApiError } from \"./rest\"\n\nconst MAX_BACKOFF_MS = 60_000\nconst MAX_TIMER_MS = 2_147_483_647\n\n/** Scheduling policy for read-only polling; never sends or replays a request. */\nexport class PollingBackoff {\n private failures = 0\n private nextAt: number | false = 0\n\n constructor(private readonly intervalMs: number) {\n if (!Number.isFinite(intervalMs) || intervalMs <= 0 || intervalMs > MAX_BACKOFF_MS) {\n throw new RangeError(\"Polling interval must be between 0 and 60000 ms\")\n }\n }\n\n reset(): void {\n this.failures = 0\n this.nextAt = 0\n }\n\n failed(error: unknown): void {\n if (\n (error instanceof Error && error.name === \"AbortError\") ||\n (error instanceof BladeApiError && error.status < 500 &&\n error.status !== 408 && error.status !== 429)\n ) {\n this.nextAt = false\n return\n }\n this.failures = Math.min(this.failures + 1, 10)\n const ceiling = Math.min(MAX_BACKOFF_MS, this.intervalMs * 2 ** this.failures)\n const backoff = Math.max(this.intervalMs, ceiling * (0.5 + Math.random() * 0.5))\n const header = error instanceof BladeApiError\n ? error.response.headers.get(\"Retry-After\")?.trim()\n : undefined\n const retryAfter = header\n ? /^\\d+$/.test(header) ? Number(header) * 1000 : Date.parse(header) - Date.now()\n : 0\n const delay = Math.max(backoff, Number.isNaN(retryAfter) ? 0 : retryAfter)\n // Oversized server delays must not overflow browser timers into a hot loop.\n this.nextAt = delay > MAX_TIMER_MS ? false : Date.now() + delay\n }\n\n /** Zero means ready, false means stop, otherwise wait at least this many ms. */\n waitMs(): number | false {\n return this.nextAt === false ? false : Math.max(0, this.nextAt - Date.now())\n }\n}\n","import { isRecord } from \"./shared/type-guards\"\n\nexport const PLATFORM_SERVICE_NAMES = [\n \"os\",\n \"hub\",\n \"agent\",\n \"oauth\",\n \"llmGateway\",\n \"gitea\",\n \"tile\",\n] as const\n\nexport type PlatformServiceName = (typeof PLATFORM_SERVICE_NAMES)[number]\n\nexport interface PlatformEndpoints {\n services: Partial<Record<PlatformServiceName, string>>\n}\n\nexport const EMPTY_PLATFORM_ENDPOINTS: PlatformEndpoints = Object.freeze({\n services: Object.freeze({}),\n})\n\nexport interface LoadPlatformEndpointsOptions {\n baseUrl?: string\n fetchImpl?: typeof fetch\n timeoutMs?: number\n}\n\nfunction defaultDocumentBaseUrl(): string | undefined {\n if (typeof document === \"undefined\") return undefined\n if (document.querySelector(\"base[href]\")) return document.baseURI\n if (typeof location !== \"undefined\" && location.origin) return `${location.origin}/`\n return document.baseURI\n}\n\nfunction normalizeServiceUrl(value: unknown): string | null {\n if (typeof value !== \"string\" || !value.trim()) return null\n if (value.includes(\"?\") || value.includes(\"#\")) return null\n try {\n const url = new URL(value.trim())\n if (url.protocol !== \"http:\" && url.protocol !== \"https:\") return null\n if (url.username || url.password || url.search || url.hash) return null\n return url.toString().replace(/\\/$/, \"\")\n } catch {\n return null\n }\n}\n\nexport function parsePlatformEndpoints(value: unknown): PlatformEndpoints | null {\n if (!isRecord(value) || !isRecord(value.services)) return null\n\n const services: Partial<Record<PlatformServiceName, string>> = {}\n for (const name of PLATFORM_SERVICE_NAMES) {\n if (!(name in value.services)) continue\n const url = normalizeServiceUrl(value.services[name])\n if (!url) return null\n if (name === \"agent\" && new URL(url).pathname !== \"/\") return null\n services[name] = url\n }\n\n return { services }\n}\n\nexport async function loadPlatformEndpoints(\n options: LoadPlatformEndpointsOptions = {},\n): Promise<PlatformEndpoints> {\n const fetchImpl = options.fetchImpl ?? globalThis.fetch\n const baseUrl = options.baseUrl ?? defaultDocumentBaseUrl()\n if (!fetchImpl || !baseUrl) return EMPTY_PLATFORM_ENDPOINTS\n\n const controller = new AbortController()\n const timeout = globalThis.setTimeout(() => controller.abort(), options.timeoutMs ?? 3_000)\n try {\n const response = await fetchImpl(new URL(\"config.json\", baseUrl), {\n cache: \"no-store\",\n credentials: \"same-origin\",\n headers: { Accept: \"application/json\" },\n signal: controller.signal,\n })\n if (!response.ok) return EMPTY_PLATFORM_ENDPOINTS\n return parsePlatformEndpoints(await response.json()) ?? EMPTY_PLATFORM_ENDPOINTS\n } catch {\n return EMPTY_PLATFORM_ENDPOINTS\n } finally {\n globalThis.clearTimeout(timeout)\n }\n}\n\nexport function resolveServiceUrl(\n endpoints: PlatformEndpoints,\n name: PlatformServiceName,\n path = \"\",\n): string | null {\n const baseUrl = endpoints.services[name]\n if (!baseUrl) return null\n if (!path) return baseUrl\n const pathReference = path.trimStart()\n if (\n path.includes(\"\\\\\") ||\n pathReference.startsWith(\"//\") ||\n /^[a-z][a-z0-9+.-]*:/i.test(pathReference)\n ) {\n return null\n }\n const base = new URL(`${baseUrl}/`)\n const target = new URL(path.replace(/^\\/+/, \"\"), base)\n if (target.origin !== base.origin || !target.pathname.startsWith(base.pathname)) {\n return null\n }\n return target.toString()\n}\n","/** Socket.IO 握手使用的 SDK 身份。Server 只校验 1.1.1 这次破坏性变更。 */\n\ndeclare const __BLADE_SDK_VERSION__: string | undefined\n\n/**\n * 本 SDK 的 npm 包版本,随 Socket.IO 握手一并声明。\n * Release 构建由 Git Tag 注入;本地开发回退到当前源码版本。\n */\nexport const SDK_NAME = \"agent-client\"\nexport const SDK_VERSION =\n typeof __BLADE_SDK_VERSION__ === \"string\" ? __BLADE_SDK_VERSION__ : \"1.1.1\"\n","/**\n * 页面协作协议(对应后端 `_meta.bridge` 通道,见 docs/specs/260417-embed-bridge)。\n *\n * ## action 从哪里来\n *\n * 智能体 → 宿主方向的每一条指令,都源自**技能作者写的工具代码**:工具返回值\n * JSON 里带 `_meta.bridge: { action, payload }`,后端在持久化前把它剥离成独立\n * 事件送达前端(LLM 的对话历史里读不到它)。因此:\n *\n * - action 字符串(如 \"map.highlight\")是**技能作者与宿主页面开发者之间的业务\n * 契约**,LLM 不参与协议、SDK 不做枚举校验;\n * - 宿主页面用 `session.onCommand(\"map.highlight\", fn)` 消费;\n * - 未注册 handler 的 action 会进入有限缓冲等待注册,超限后丢弃并 console 告警。\n *\n * 宿主 → 智能体方向只有三个白名单动作:attach(附件入输入框)/ insertText\n * (追加输入文本)/ send(直接发消息),对应协议层的 addContext / appendInput /\n * sendMessage。\n */\n\nexport interface CommandEnvelope {\n __bladeBridge: true\n direction: \"agent-to-host\"\n action: string\n payload: unknown\n meta: {\n sessionId: string\n toolCallId?: string\n timestamp: number\n }\n}\n\nexport type InboundAction = \"addContext\" | \"appendInput\" | \"sendMessage\"\n\nexport interface InboundEnvelope {\n __bladeBridge: true\n direction: \"host-to-agent\"\n action: InboundAction\n payload: unknown\n}\n\nexport function isCommandEnvelope(value: unknown): value is CommandEnvelope {\n if (typeof value !== \"object\" || value === null) return false\n const record = value as Record<string, unknown>\n return (\n record.__bladeBridge === true &&\n record.direction === \"agent-to-host\" &&\n typeof record.action === \"string\"\n )\n}\n\nexport function isInboundEnvelope(value: unknown): value is InboundEnvelope {\n if (typeof value !== \"object\" || value === null) return false\n const record = value as Record<string, unknown>\n return (\n record.__bladeBridge === true &&\n record.direction === \"host-to-agent\" &&\n (record.action === \"addContext\" || record.action === \"appendInput\" || record.action === \"sendMessage\")\n )\n}\n","import { CommandRegistry, type CommandHandler } from \"./registry\"\nimport { isCommandEnvelope, type InboundAction } from \"./protocol\"\n\n/**\n * iframe 嵌入形态的宿主端协作对象:当你把 Blade 的聊天页面用 iframe 嵌进\n * 自己的系统时,用它与 iframe 里的智能体互通——API 与同页嵌入的\n * AgentSession 完全一致(onCommand / attach / insertText / send)。\n *\n * action 的来源与同页形态相同:技能作者在工具返回值 JSON 的 `_meta.bridge`\n * 字段里写 `{ action, payload }`,Blade 页面检测到自己处于 iframe 中时会把\n * 它 postMessage 给宿主页面(见 docs/specs/260417-embed-bridge)。\n */\nexport interface EmbeddedChatOptions {\n /** 嵌入 Blade 页面的 iframe 元素。不传则监听来自任意子窗口的消息。 */\n iframe?: HTMLIFrameElement\n /**\n * 允许接收消息的来源(Blade 页面的 origin,如 \"https://blade.example.com\")。\n * 必填:不校验来源会让任意第三方页面伪造智能体指令。\n */\n allowedOrigins: string[]\n}\n\nexport interface EmbeddedChat {\n /** 监听智能体下发的指令(注册前到达的会缓冲补投)。返回取消函数。 */\n onCommand(action: string, handler: CommandHandler): () => void\n /** 把业务数据作为附件放进 iframe 里的聊天输入框。 */\n attach(label: string, data: unknown): void\n /** 往 iframe 里的聊天输入框追加文字。 */\n insertText(text: string): void\n /** 直接代用户发送一条消息。 */\n send(text: string): void\n /** 停止监听并释放资源。 */\n dispose(): void\n}\n\nexport function connectEmbedded(options: EmbeddedChatOptions): EmbeddedChat {\n if (typeof window === \"undefined\") {\n throw new Error(\"connectEmbedded() 只能在浏览器中使用。\")\n }\n if (!options.allowedOrigins?.length) {\n throw new Error(\n \"connectEmbedded() 需要 allowedOrigins(Blade 页面的 origin),否则无法安全接收消息。\",\n )\n }\n const registry = new CommandRegistry()\n const allowed = new Set(options.allowedOrigins)\n\n const onMessage = (event: MessageEvent) => {\n if (!allowed.has(event.origin)) return\n if (options.iframe && event.source !== options.iframe.contentWindow) return\n if (!isCommandEnvelope(event.data)) return\n registry.dispatch(event.data.action, event.data.payload, {\n toolCallId: event.data.meta?.toolCallId,\n })\n }\n window.addEventListener(\"message\", onMessage)\n\n const post = (action: InboundAction, payload: unknown) => {\n const target = options.iframe?.contentWindow\n if (!target) {\n console.warn(\"[agent-client] connectEmbedded 未绑定 iframe,无法向智能体发送消息。\")\n return\n }\n // 发往 iframe 的 targetOrigin 用配置的第一个 origin,避免 \"*\"\n target.postMessage(\n { __bladeBridge: true, direction: \"host-to-agent\", action, payload },\n options.allowedOrigins[0],\n )\n }\n\n return {\n onCommand: (action, handler) => registry.onCommand(action, handler),\n attach: (label, data) => {\n const content = typeof data === \"string\" ? data : JSON.stringify(data, null, 2)\n post(\"addContext\", { label, content })\n },\n insertText: (text) => post(\"appendInput\", { text }),\n send: (text) => post(\"sendMessage\", { text }),\n dispose: () => {\n window.removeEventListener(\"message\", onMessage)\n registry.clear()\n },\n }\n}\n","import type { PostChatFollowup, TurnProjection } from \"./projection\"\n\n/** 返回最新根会话轮次的小结;新用户消息到达后旧小结立即失效。 */\nexport function latestPostChatFollowup(turns: TurnProjection[]): PostChatFollowup | null {\n for (let index = turns.length - 1; index >= 0; index -= 1) {\n const turn = turns[index]\n if (\n turn.loop_id === \"root\" &&\n (turn.role === \"user\" || turn.role === \"assistant\") &&\n (turn.kind ?? \"message\") === \"message\" &&\n !turn.blocks.some((block) =>\n [\"mode_change\", \"plan_status\", \"ask_user_answer\"].includes(block.type),\n )\n ) {\n return turn.role === \"assistant\" ? (turn.post_chat_followup ?? null) : null\n }\n }\n return null\n}\n","export enum LayoutType {\n Default = \"default\",\n SkillEditor = \"skill-editor\",\n BladeCoa = \"blade-coa\",\n SolutionEditor = \"solution-editor\",\n SolutionEditor2 = \"solution-editor2\",\n ChatPreview = \"chat-preview\",\n ChatOnly = \"chat-only\",\n SolutionApp = \"solution-app\",\n Custom = \"custom\",\n}\n\nexport interface Solution {\n id: string\n name: string\n version: string\n description?: string | null\n source?: \"builtin\" | \"personal\" | string | null\n layout_type: LayoutType | string\n initial_mode?: \"planning\" | \"executing\" | string | null\n initial_message?: string | null\n preview?: { url: string; title?: string | null } | null\n layout?: {\n available?: boolean\n source_dir?: string\n entry?: string\n export?: string\n } | null\n roles?: BizRole[] | null\n data?: Record<string, unknown> | null\n ui_config?: SolutionAppUiConfig | null\n}\n\nexport interface SolutionAppUiConfig {\n branding: {\n name: string\n subtitle?: string\n icon_text: string\n icon_gradient?: string\n }\n list: {\n title: string\n create_button: string\n card?: {\n subtitle?: string\n stats?: Array<{\n label: string\n value: string\n color?: string\n }>\n }\n }\n create: {\n title: string\n description?: string\n submit_button: string\n sections: Array<{\n id: string\n title: string\n description?: string\n fields: Array<SolutionAppField>\n }>\n }\n}\n\nexport type SolutionAppField =\n | {\n id: string\n kind: \"textarea\"\n label: string\n placeholder?: string\n }\n | {\n id: string\n kind: \"file-upload\"\n accept?: string[]\n categories?: Array<{\n label: string\n description: string\n color: string\n }>\n }\n\nexport interface SolutionAppState {\n pipeline: Array<{\n id: string\n label: string\n status: \"done\" | \"active\" | \"pending\" | \"error\"\n }>\n meta: Record<\n string,\n {\n label: string\n value: string\n color?: string\n }\n >\n}\n\nexport interface BizRole {\n id: string\n name: string\n description?: string | null\n preview?: { url: string; title?: string | null } | null\n}\n","import { type } from \"arktype\"\n\nexport const TaskStatus = type(\"'pending' | 'in_progress' | 'done' | 'failed' | 'skipped'\")\nexport type TaskStatus = typeof TaskStatus.infer\n\nexport const Task = type({\n id: \"string\",\n goal: \"string\",\n skills: \"string[]\",\n depends_on: \"string[]\",\n status: TaskStatus,\n result_summary: \"string\",\n number: \"string\",\n})\nexport type Task = typeof Task.infer\n"],"mappings":"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","names":["type","response","snapshot","snapshot","type","attachments","contexts","buildMessageContent","toolCall","snapshot","snapshot","handle","LayoutType","type"]}
|
|
1
|
+
{"version":3,"sources":["../src/auth-login.ts","../src/rest.ts","../src/resources/auth.ts","../src/shared/type-guards.ts","../src/resources/headless.ts","../src/resources/computers.ts","../src/resources/models.ts","../src/schemas/session.ts","../src/session/definition.ts","../src/shared/projection/helpers.ts","../src/schemas/message.ts","../src/shared/projection/state.ts","../src/schemas/context.ts","../src/shared/projection/context.ts","../src/shared/projection/builder.ts","../src/shared/projection/history.ts","../src/resources/sessions.ts","../src/resources/plugins.ts","../src/resources/chat-groups.ts","../src/resources/site-visits.ts","../src/shared/auth-busy.ts","../src/commands/registry.ts","../src/session/events.ts","../src/session/history-page.ts","../src/session/queue.ts","../src/schemas/mcp-app.ts","../src/shared/tool-ui-card.ts","../src/schemas/message-utils.ts","../src/session/state.ts","../src/session/agent-session.ts","../src/session/hub.ts","../src/socket.ts","../src/auth.ts","../src/blade-client.ts","../src/polling-backoff.ts","../src/platform-endpoints.ts","../src/version.ts","../src/commands/protocol.ts","../src/commands/embedded.ts","../src/schemas/projection-utils.ts","../src/schemas/solution.ts","../src/schemas/task.ts"],"sourcesContent":["import type { BladeClient } from \"./blade-client\"\n\n/**\n * 弹窗授权登录,与 Chrome 扩展共用同一套后端授权内核(见 server/routes/sdk_auth.py):\n *\n * 1. 弹窗打开 `GET /api/auth/sdk/authorize?client_origin=<本页 origin>&state=<随机值>`\n * 2. 用户点击「许可授权」→ 回调页把 `{ type: \"blade-agent:sdk-auth\", state, code }`\n * postMessage 定向发回本页(code 一次性、5 分钟有效)\n * 3. SDK 用 `POST /api/auth/sdk/token`(code + state + client_origin)换取 PAT,\n * 存储并热挂载(REST 与 Socket.IO 同时生效)\n */\n\nexport interface LoginOptions {\n /** 弹窗尺寸,默认 480x640。 */\n width?: number\n height?: number\n /** 超时毫秒数,默认 5 分钟(与后端授权码有效期一致)。 */\n timeoutMs?: number\n}\n\nexport interface LoginResult {\n token: string\n user?: { id?: string; username?: string; display_name?: string }\n}\n\n/** 回调页 postMessage 的消息契约(对齐后端 _completion_page)。 */\ninterface AuthCallbackMessage {\n type: \"blade-agent:sdk-auth\"\n version: number\n status: \"success\" | \"denied\" | \"error\"\n state: string\n code?: string\n error?: string\n}\n\nfunction isAuthCallbackMessage(value: unknown): value is AuthCallbackMessage {\n return (\n typeof value === \"object\" &&\n value !== null &&\n (value as Record<string, unknown>).type === \"blade-agent:sdk-auth\"\n )\n}\n\n/** 后端下发的是错误码,直接抛给用户看不懂;这里翻成能照着做的话。 */\nconst AUTH_ERROR_HINTS: Record<string, string> = {\n pat_unavailable: \"没能为你准备访问凭据。请退出后重新登录 Blade 再试一次;若仍然失败,请联系管理员。\",\n}\n\nfunction randomState(): string {\n const bytes = new Uint8Array(24)\n crypto.getRandomValues(bytes)\n return Array.from(bytes, (b) => b.toString(16).padStart(2, \"0\")).join(\"\")\n}\n\nexport type TokenStorageMode = \"local\" | \"memory\"\n\nconst storageKeyFor = (baseUrl: string) => `blade-sdk-token:${baseUrl}`\n\nexport function readStoredToken(baseUrl: string): string | null {\n if (typeof localStorage === \"undefined\") return null\n try {\n return localStorage.getItem(storageKeyFor(baseUrl))\n } catch {\n return null\n }\n}\n\nexport function writeStoredToken(baseUrl: string, token: string | null, mode: TokenStorageMode): void {\n if (mode !== \"local\" || typeof localStorage === \"undefined\") return\n try {\n if (token) {\n localStorage.setItem(storageKeyFor(baseUrl), token)\n } else {\n localStorage.removeItem(storageKeyFor(baseUrl))\n }\n } catch {\n // 隐私模式等场景写入失败时静默降级为内存态\n }\n}\n\nexport async function loginWithPopup(\n client: BladeClient,\n options: LoginOptions = {},\n): Promise<LoginResult> {\n if (typeof window === \"undefined\") {\n throw new Error(\"client.auth.login() 只能在浏览器中调用;Node.js 场景请直接传入 token。\")\n }\n // file:// 打开的本地 HTML(智能体生成的交付物被双击打开)没有可声明的\n // origin,按 opaque(\"null\")走:授权页会向用户展示「本地文件页面」,\n // 回传的一次性 code 由 \"*\" 投递给本窗口,state 校验不变。\n const rawOrigin = window.location.origin\n const clientOrigin = /^https?:\\/\\//.test(rawOrigin) ? rawOrigin : \"null\"\n\n const width = options.width ?? 480\n const height = options.height ?? 640\n const left = Math.max(0, (window.screen.width - width) / 2)\n const top = Math.max(0, (window.screen.height - height) / 2)\n const state = randomState()\n const authorizeUrl = new URL(\n \"/api/auth/sdk/authorize\",\n client.options.baseUrl || window.location.origin,\n )\n authorizeUrl.searchParams.set(\"client_origin\", clientOrigin)\n authorizeUrl.searchParams.set(\"state\", state)\n\n const popup = window.open(\n \"about:blank\",\n `blade-sdk-login-${state}`,\n `popup=yes,width=${width},height=${height},left=${left},top=${top}`,\n )\n if (!popup) {\n throw new Error(\"登录弹窗被浏览器拦截了。请允许本站打开弹窗后重试。\")\n }\n\n const expectedOrigin = new URL(client.options.baseUrl || window.location.origin).origin\n\n return new Promise<LoginResult>((resolve, reject) => {\n const timeoutMs = options.timeoutMs ?? 5 * 60 * 1000\n let settled = false\n let closeTimer: ReturnType<typeof globalThis.setTimeout> | undefined\n\n // 收到合法回调之后弹窗是由回调页和 SDK 自己关掉的,不能再当成「用户放弃」,\n // 否则换取令牌的请求稍慢一点就会被误判成失败。\n const stopCloseWatch = () => {\n globalThis.clearInterval(closeWatcher)\n if (closeTimer !== undefined) globalThis.clearTimeout(closeTimer)\n }\n\n const cleanup = () => {\n window.removeEventListener(\"message\", onMessage)\n stopCloseWatch()\n globalThis.clearTimeout(timeoutHandle)\n }\n const settle = (fn: () => void) => {\n if (settled) return\n settled = true\n cleanup()\n fn()\n }\n\n const onMessage = (event: MessageEvent) => {\n // 回调页部署在后端域名下,只信任来自后端 origin、且 state 匹配的消息\n if (event.origin !== expectedOrigin) return\n if (event.source !== popup) return\n if (!isAuthCallbackMessage(event.data)) return\n if (event.data.state !== state) return\n const message = event.data\n stopCloseWatch()\n // 失败时不要关窗:授权页在那一屏上写了失败原因和下一步怎么做,关掉之后\n // 用户手里只剩一个错误码。成功和取消照旧关掉。\n const closePopup = () => {\n try {\n popup.close()\n } catch {\n // 跨域限制下 close 可能失败,忽略\n }\n }\n if (message.status === \"denied\") {\n closePopup()\n settle(() => reject(new Error(\"你取消了授权,未完成登录。\")))\n return\n }\n if (message.status !== \"success\" || !message.code) {\n settle(() => reject(new Error(AUTH_ERROR_HINTS[message.error ?? \"\"] ?? message.error ?? \"登录失败,未取得授权码。\")))\n return\n }\n closePopup()\n // code 一次性、5 分钟有效;连同 state 与 client_origin 一起换取 PAT\n client\n .json<{\n access_token: string\n user?: LoginResult[\"user\"]\n }>(\"POST\", \"/api/auth/sdk/token\", {\n code: message.code,\n state,\n client_origin: clientOrigin,\n })\n .then((response) => {\n settle(() => resolve({ token: response.access_token, user: response.user }))\n })\n .catch((error) => {\n settle(() =>\n reject(error instanceof Error ? error : new Error(\"授权码换取令牌失败,请重试。\")),\n )\n })\n }\n\n const closeWatcher = globalThis.setInterval(() => {\n if (!popup.closed || settled || closeTimer !== undefined) return\n // 回调消息可能仍在路上,稍等一拍再判定为用户关窗\n closeTimer = globalThis.setTimeout(() => {\n settle(() => reject(new Error(\"登录窗口已关闭,未完成授权。\")))\n }, 400)\n }, 500)\n\n const timeoutHandle = globalThis.setTimeout(() => {\n settle(() => reject(new Error(\"登录超时,请重试。\")))\n }, timeoutMs)\n\n window.addEventListener(\"message\", onMessage)\n // 先装监听器再导航,避免本地/沙盒自动授权过快返回时丢失回调消息。\n popup.location.replace(authorizeUrl.toString())\n })\n}\n","const DOCS_URL = \"https://blade-hq.github.io/public-skills/\"\n\nexport class BladeApiError extends Error {\n readonly response: Response\n readonly status: number\n readonly statusText: string\n\n constructor(response: Response, message?: string) {\n super(message ?? `请求失败(${response.status} ${response.statusText})`)\n this.name = \"BladeApiError\"\n this.response = response\n this.status = response.status\n this.statusText = response.statusText\n }\n}\n\n/**\n * 从 FastAPI 风格的错误响应中提取 detail 字段,作为用户可读的中文错误文案。\n * 失败时返回 undefined,调用方会回退到默认提示。\n */\nexport async function extractErrorDetail(response: Response): Promise<string | undefined> {\n try {\n const cloned = response.clone()\n const contentType = cloned.headers.get(\"content-type\") ?? \"\"\n if (contentType.includes(\"application/json\")) {\n const data = (await cloned.json()) as { detail?: unknown }\n const detail = data?.detail\n if (typeof detail === \"string\" && detail.trim()) return detail\n if (Array.isArray(detail) && detail.length > 0) {\n const first = detail[0] as { msg?: unknown }\n if (first && typeof first.msg === \"string\") return first.msg\n }\n } else {\n const text = (await cloned.text()).trim()\n if (text) return text\n }\n } catch {\n // 读取失败时忽略,使用默认提示\n }\n return undefined\n}\n\n/** 401/403 补充\"怎么办\"的指引,避免初级开发者对着裸状态码发呆。 */\nexport function decorateAuthError(error: unknown): unknown {\n if (!(error instanceof BladeApiError)) return error\n if (error.status === 401) {\n error.message =\n `${error.message}(未登录或凭证已失效。浏览器场景调用 client.auth.login() 弹窗登录,` +\n `自动化场景在 new BladeClient({ token }) 传入 PAT。接入指南:${DOCS_URL})`\n } else if (error.status === 403) {\n error.message = `${error.message}(当前账号无权访问该资源。接入指南:${DOCS_URL})`\n }\n return error\n}\n\nexport type HttpMethod = \"DELETE\" | \"GET\" | \"PATCH\" | \"POST\" | \"PUT\" | (string & {})\n\nexport interface BladeFetchInit {\n body?: BodyInit | null\n credentials?: RequestCredentials\n expectOk?: boolean\n headers?: HeadersInit\n signal?: AbortSignal | null\n}\n\n/**\n * 按客户端规则把后端路径拼成绝对 URL:`baseUrl` 自带路径前缀时保留前缀,\n * 路径里的前导 `/` 只表示\"从后端根开始\",不会被解释成站点根目录。\n *\n * 单独放在传输层,是为了让不走 `fetch()` 鉴权通道的资源(例如匿名的站点统计)\n * 落到同一个后端地址上,不必各自再写一份 URL 规则。\n */\nexport function buildBackendUrl(baseUrl: string, path: string): URL {\n const base = baseUrl.endsWith(\"/\") ? baseUrl : `${baseUrl}/`\n return new URL(path.startsWith(\"/\") ? path.slice(1) : path, base)\n}\n","import type { BladeClient } from \"../blade-client\"\nimport type { LoginOptions, LoginResult } from \"../auth-login\"\n\nexport interface UserInfo {\n id: string\n username: string\n display_name?: string | null\n avatar_url: string | null\n token: string\n auth_type: \"casdoor\"\n is_admin?: boolean\n}\n\nexport interface ProvidersResponse {\n providers: Array<{\n name: string\n authorize_url: string\n }>\n password_enabled: boolean\n}\n\nexport interface ExchangeCodeParams {\n /** 授权回调页 postMessage 回来的一次性 code。 */\n code: string\n /** 发起授权时用的 state,必须原样传回。 */\n state: string\n /** 发起授权的页面 origin,要和 authorize 时传的 `client_origin` 完全一致。 */\n clientOrigin: string\n}\n\nexport interface ExchangeCodeResult {\n access_token: string\n token_type: string\n user: {\n id: string\n username: string\n display_name: string\n avatar_url: string | null\n }\n}\n\nexport class AuthResource {\n constructor(private client: BladeClient) {}\n\n /**\n * 弹窗授权登录(浏览器专用):弹出后端授权页,用户点击\"许可授权\"后\n * 自动取得 PAT 并热挂载到当前 client。等价于 client.login()。\n */\n login(options?: LoginOptions): Promise<LoginResult> {\n return this.client.login(options)\n }\n\n /**\n * 用一次性 code 换 PAT。给**服务端**用:浏览器把 code 交给你自己的后端,\n * 后端换到的 PAT 不进浏览器。浏览器里直接用 `login()` 就够了。\n *\n * 服务端调用时会自己补上 `Origin` 头(浏览器会自动带,服务端不会,缺了\n * 后端报 `missing_request_origin`)。\n */\n exchangeCode(params: ExchangeCodeParams): Promise<ExchangeCodeResult> {\n return this.client.jsonFromInit(\"/api/auth/sdk/token\", {\n method: \"POST\",\n headers: { Origin: params.clientOrigin },\n body: JSON.stringify({\n code: params.code,\n state: params.state,\n client_origin: params.clientOrigin,\n }),\n })\n }\n\n /** 清除 login() 存储的令牌。 */\n logoutToken(): void {\n this.client.logoutToken()\n }\n\n getProviders(): Promise<ProvidersResponse> {\n return this.client.json(\"GET\", \"/api/auth/providers\")\n }\n\n getMe(): Promise<UserInfo> {\n return this.client.json(\"GET\", \"/api/auth/me\")\n }\n\n logout(): Promise<{ logout_url: string }> {\n return this.client.json(\"POST\", \"/api/auth/logout\")\n }\n}\n","/** Return true for non-null, non-array objects. */\nexport function isRecord(value: unknown): value is Record<string, unknown> {\n return typeof value === \"object\" && value !== null && !Array.isArray(value)\n}\n","import type { BladeClient } from \"../blade-client\"\nimport type { ChatEndPayload, ChatSendPayload, ChatStartPayload, SystemErrorPayload } from \"../types/socket-events\"\nimport { isRecord } from \"../shared/type-guards\"\n\nexport type JsonSchemaObject = Record<string, unknown>\n\nexport interface HeadlessRunOptions {\n schema?: JsonSchemaObject | null\n model?: string | null\n timeoutMs?: number\n}\n\nexport interface HeadlessRunInSessionResult<T = unknown> {\n session_id: string\n chat_run_id: string | null\n result: T | string\n}\n\nexport class HeadlessError extends Error {\n constructor(\n message: string,\n readonly detail?: unknown,\n ) {\n super(message)\n this.name = \"HeadlessError\"\n }\n}\n\nconst SYSTEM_ERROR_CHAT_END_GRACE_MS = 1_000\n\nexport class HeadlessResource {\n constructor(private client: BladeClient) {}\n\n async run<T = unknown>(prompt: string, options: HeadlessRunOptions & { schema: JsonSchemaObject }): Promise<T>\n async run(prompt: string, options?: HeadlessRunOptions): Promise<string>\n async run<T = unknown>(prompt: string, options: HeadlessRunOptions = {}): Promise<T | string> {\n const { session_id } = await this.client.sessions.createSessionWithRequest({\n intent: prompt,\n model: options.model ?? null,\n })\n return this.runTracked<T>(session_id, prompt, options, false) as Promise<T | string>\n }\n\n async runInSession<T = unknown>(\n sessionId: string,\n prompt: string,\n options: HeadlessRunOptions & { schema: JsonSchemaObject },\n ): Promise<T>\n async runInSession(sessionId: string, prompt: string, options?: HeadlessRunOptions): Promise<string>\n async runInSession<T = unknown>(\n sessionId: string,\n prompt: string,\n options: HeadlessRunOptions = {},\n ): Promise<T | string> {\n return this.runTracked<T>(sessionId, prompt, options, false) as Promise<T | string>\n }\n\n async runWithSession<T = unknown>(\n prompt: string,\n options: HeadlessRunOptions & { schema: JsonSchemaObject },\n ): Promise<HeadlessRunInSessionResult<T>>\n async runWithSession(prompt: string, options?: HeadlessRunOptions): Promise<HeadlessRunInSessionResult<string>>\n async runWithSession<T = unknown>(\n prompt: string,\n options: HeadlessRunOptions = {},\n ): Promise<HeadlessRunInSessionResult<T>> {\n const { session_id } = await this.client.sessions.createSessionWithRequest({\n intent: prompt,\n model: options.model ?? null,\n })\n return this.runTracked<T>(session_id, prompt, options, true) as Promise<HeadlessRunInSessionResult<T>>\n }\n\n private async runTracked<T = unknown>(\n sessionId: string,\n prompt: string,\n options: HeadlessRunOptions,\n returnEnvelope: boolean,\n ): Promise<T | string | HeadlessRunInSessionResult<T>> {\n const timeoutMs = options.timeoutMs ?? 300_000\n const session_id = sessionId\n const socket = this.client.socket()\n await ensureSocketConnected(socket, timeoutMs, { session_id })\n\n return new Promise<T | string | HeadlessRunInSessionResult<T>>((resolve, reject) => {\n let settled = false\n let stopSent = false\n let started = false\n let chatRunId: string | null = null\n let systemErrorTimeout: ReturnType<typeof setTimeout> | null = null\n const timeout = setTimeout(() => {\n fail(new HeadlessError(`headless run timed out after ${timeoutMs}ms`, { session_id, chat_run_id: chatRunId }))\n }, timeoutMs)\n\n const cleanup = (sendStop: boolean) => {\n clearTimeout(timeout)\n if (systemErrorTimeout) {\n clearTimeout(systemErrorTimeout)\n systemErrorTimeout = null\n }\n socket.off(\"chat:start\", onChatStart)\n socket.off(\"chat:end\", onChatEnd)\n socket.off(\"system:error\", onSystemError)\n if (sendStop && !stopSent) {\n stopSent = true\n socket.emit(\"chat:stop\", { session_id }, () => undefined)\n }\n socket.emit(\"session:unsubscribe\", { session_id })\n }\n\n const finish = (value: T | string) => {\n if (settled) return\n settled = true\n cleanup(false)\n if (returnEnvelope) {\n resolve({ session_id, chat_run_id: chatRunId, result: value })\n return\n }\n resolve(value)\n }\n const fail = (error: unknown) => {\n if (settled) return\n settled = true\n cleanup(true)\n reject(error)\n }\n const failWithoutStop = (error: unknown) => {\n if (settled) return\n settled = true\n cleanup(false)\n reject(error)\n }\n const rejectAfterChatEnd = (error: unknown) => {\n if (settled) return\n settled = true\n cleanup(false)\n reject(error)\n }\n\n function onChatStart(payload: ChatStartPayload) {\n if (payload.session_id && payload.session_id !== session_id) return\n started = true\n }\n\n function onSystemError(payload: SystemErrorPayload) {\n if (payload.session_id !== session_id) return\n if (!started) {\n failWithoutStop(new HeadlessError(payload.message || \"headless run failed\", {\n session_id,\n chat_run_id: chatRunId,\n event: payload,\n }))\n return\n }\n if (systemErrorTimeout) {\n clearTimeout(systemErrorTimeout)\n }\n systemErrorTimeout = setTimeout(() => {\n systemErrorTimeout = null\n fail(new HeadlessError(payload.message || \"headless run failed\", {\n session_id,\n chat_run_id: chatRunId,\n event: payload,\n }))\n }, SYSTEM_ERROR_CHAT_END_GRACE_MS)\n }\n\n function onChatEnd(payload: ChatEndPayload) {\n if (payload.session_id && payload.session_id !== session_id) return\n chatRunId = typeof payload.chat_run_id === \"string\" ? payload.chat_run_id : chatRunId\n const result = payload.result\n if (payload.status === \"failed\") {\n rejectAfterChatEnd(new HeadlessError(errorMessageFromResult(result) ?? \"headless run failed\", {\n session_id,\n chat_run_id: chatRunId,\n event: payload,\n }))\n return\n }\n try {\n finish(normalizeResult<T>(result, Boolean(options.schema)))\n } catch (error) {\n rejectAfterChatEnd(error)\n }\n }\n\n socket.on(\"chat:start\", onChatStart)\n socket.on(\"chat:end\", onChatEnd)\n socket.on(\"system:error\", onSystemError)\n socket.emit(\"session:subscribe\", {\n session_id,\n event_format: \"raw\",\n })\n socket.emit(\n \"chat:send\",\n {\n session_id,\n message: prompt as unknown as ChatSendPayload[\"message\"],\n headless: true,\n output_schema: options.schema ?? null,\n model: options.model ?? null,\n },\n (response) => {\n if (response.status === \"accepted\") return\n rejectAfterChatEnd(\n new HeadlessError(response.message ?? \"headless run was not accepted\", response),\n )\n },\n )\n })\n }\n}\n\nfunction normalizeResult<T>(result: unknown, hasSchema: boolean): T | string {\n if (!isRecord(result)) {\n throw new HeadlessError(\"headless run finished without a result\", result)\n }\n const errMsg = typeof result.err_msg === \"string\" ? result.err_msg : \"\"\n if (errMsg) {\n throw new HeadlessError(errMsg, result)\n }\n if (!hasSchema) {\n const text = result.result\n return typeof text === \"string\" ? text : String(text ?? \"\")\n }\n const { err_msg: _errMsg, ...businessResult } = result\n return businessResult as T\n}\n\nfunction errorMessageFromResult(result: unknown): string | null {\n if (isRecord(result) && typeof result.err_msg === \"string\" && result.err_msg) {\n return result.err_msg\n }\n return null\n}\n\nfunction ensureSocketConnected(\n socket: ReturnType<BladeClient[\"socket\"]>,\n timeoutMs: number,\n detail: Record<string, unknown>,\n): Promise<void> {\n if (socket.connected) {\n return Promise.resolve()\n }\n return new Promise((resolve, reject) => {\n let settled = false\n const timeout = setTimeout(() => {\n finish(() => reject(new HeadlessError(`socket connection timed out after ${timeoutMs}ms`, detail)))\n }, timeoutMs)\n const onConnect = () => finish(resolve)\n const onConnectError = (error: unknown) => {\n finish(() => reject(new HeadlessError(\"socket connection failed\", { ...detail, event: error })))\n }\n const finish = (callback: () => void) => {\n if (settled) return\n settled = true\n clearTimeout(timeout)\n socket.off(\"connect\", onConnect)\n socket.off(\"connect_error\", onConnectError)\n callback()\n }\n socket.on(\"connect\", onConnect)\n socket.on(\"connect_error\", onConnectError)\n socket.connect()\n })\n}\n","import type { BladeClient } from \"../blade-client\"\n\n/** 一台远程电脑在某个会话眼里的样子。 */\nexport interface SessionComputer {\n id: string\n label: string\n hostname?: string | null\n os?: string | null\n arch?: string | null\n /** 那台机器的用户主目录,命令默认在这里执行。 */\n home?: string | null\n /** daemon 启动时所在的目录。 */\n workspace?: string | null\n blade_home?: string | null\n allowed_paths?: string[]\n agent_runtimes?: unknown[]\n daemon_version?: string | null\n created_at: string\n last_seen_at?: string | null\n /** 这台电脑此刻连着后端。由服务端读心跳时间判定,不做实时探测。 */\n online: boolean\n /** 这次会话已经启动了它。和 `online` 互相独立。 */\n enabled: boolean\n /** 这次会话本身就跑在这台电脑上。 */\n is_primary: boolean\n}\n\nexport interface SessionComputerList {\n computers: SessionComputer[]\n}\n\n/**\n * 账号级电脑目录里的一台机器。\n *\n * 只有「这台机器登记过、此刻在不在线」这类账号事实,**没有**会话授权状态——\n * 「本次会话能不能用它」是另一件事,由会话接口回答。两者混在一起说,用户就会\n * 把「在线」当成「已授权」,或者反过来。\n */\nexport interface AccountComputer {\n id: string\n label: string\n hostname?: string | null\n os?: string | null\n arch?: string | null\n blade_home?: string | null\n workspace?: string | null\n daemon_version?: string | null\n created_at: string\n last_seen_at?: string | null\n online: boolean\n}\n\nexport interface AccountComputerList {\n computers: AccountComputer[]\n}\n\n/**\n * 一台电脑在界面上该显示成什么状态。\n *\n * - `primary` 会话自己就住在这台机器上,恒为可用且不能停用\n * - `enabled` 本次会话已启动\n * - `offline` 没启动且当前离线\n * - `idle` 没启动,在线\n *\n * 判定只写这一份,界面只管样式和排版——两边各写一份必然会分叉,\n * 然后其中一边的兜底会把另一边的错误盖住。\n */\nexport type ComputerState = \"primary\" | \"enabled\" | \"offline\" | \"idle\"\n\nexport function computerState(computer: SessionComputer): ComputerState {\n if (computer.is_primary) return \"primary\"\n if (computer.enabled) return \"enabled\"\n return computer.online ? \"idle\" : \"offline\"\n}\n\n/**\n * 这台电脑跑的是哪一类系统。\n *\n * 判定放这里、图标映射留给界面:`os` 是 daemon 上报的 `runtime.GOOS`,\n * 各处自己 `startsWith` 一遍必然会分叉。\n */\nexport type ComputerOS = \"macos\" | \"windows\" | \"linux\" | \"unknown\"\n\nexport function computerOS(computer: SessionComputer): ComputerOS {\n const os = (computer.os ?? \"\").toLowerCase()\n if (os.startsWith(\"darwin\") || os.startsWith(\"mac\")) return \"macos\"\n if (os.startsWith(\"windows\")) return \"windows\"\n if (os.startsWith(\"linux\")) return \"linux\"\n return \"unknown\"\n}\n\n/** 系统与架构,例如 `darwin/arm64`。信息不全时尽量给出已知的那部分。 */\nexport function computerPlatformLabel(computer: SessionComputer): string {\n const os = (computer.os ?? \"\").trim()\n const arch = (computer.arch ?? \"\").trim()\n if (os && arch) return `${os}/${arch}`\n return os || arch || \"\"\n}\n\n/**\n * 那台电脑上 blade daemon 的版本。\n *\n * 服务端存的就是 daemon 上报的完整串(dev 构建带 commit),这里原样用,\n * 不在前端另拼一套格式——拼两份迟早对不上。\n */\nexport function computerDaemonVersion(computer: SessionComputer): string {\n return (computer.daemon_version ?? \"\").trim()\n}\n\n/** 这台电脑的勾选框能不能动。主运行时不能停用——那是会话自己的工作目录所在。 */\nexport function canToggleComputer(computer: SessionComputer): boolean {\n return !computer.is_primary\n}\n\n/**\n * 列表顺序:按接入时间,稳定不变。\n *\n * **刻意不按在线/可用排序。** 那样排看着\"手边的在前面\",代价是电脑上下线、\n * 勾选状态一变,整个列表就重排——用户正要点的那一项会在手指底下跑掉。\n * 一个会自己动的列表比一个排序不那么聪明的列表难用得多。\n *\n * 用 `created_at` 而不是名字:改名不会让位置变,新接入的稳定排在末尾。\n */\nexport function sortComputers(computers: SessionComputer[]): SessionComputer[] {\n return [...computers].sort((a, b) => {\n const byCreated = (a.created_at ?? \"\").localeCompare(b.created_at ?? \"\")\n if (byCreated !== 0) return byCreated\n // created_at 相同时才用名字兜底,保证顺序确定\n return a.label.localeCompare(b.label)\n })\n}\n\n/** 会话可以操作哪些远程电脑。 */\nexport class ComputersResource {\n constructor(private client: BladeClient) {}\n\n /**\n * 列出当前账号登记过的全部电脑及其在线状态。\n *\n * 首页还没有会话,也要能看到同一份清单——判定各写一份必然分叉,一边的兜底会把\n * 另一边的错误盖住(#1597)。所以账号事实只从这一个接口读。\n */\n async listAccount(): Promise<AccountComputerList> {\n const data = await this.client.json<{\n instances: Array<Omit<AccountComputer, \"online\"> & { online?: boolean }>\n }>(\"GET\", \"/api/daemon/instances\")\n return {\n computers: (data.instances ?? []).map((instance) => ({\n ...instance,\n online: Boolean(instance.online),\n })),\n }\n }\n\n /**\n * 列出当前用户的全部电脑,带上\"在不在线\"和\"这次会话能不能用\"。\n * 服务端只查库,电脑离线时同样返回,所以拿得到\"它离线了\"这个结论。\n */\n list(sessionId: string): Promise<SessionComputerList> {\n return this.client.json(\n \"GET\",\n `/api/sessions/${encodeURIComponent(sessionId)}/computers`,\n )\n }\n\n /**\n * 启动或停止一台电脑。只改这次会话的可用范围,不会碰远程机器,\n * 电脑离线时同样能登记,等它上线就直接可用。\n */\n setEnabled(\n sessionId: string,\n computer: string,\n enabled: boolean,\n ): Promise<SessionComputer> {\n return this.client.json(\n \"PUT\",\n `/api/sessions/${encodeURIComponent(sessionId)}/computers/${encodeURIComponent(computer)}/enabled`,\n { enabled },\n )\n }\n}\n","import type { BladeClient } from \"../blade-client\"\n\nexport interface ModelOption {\n id: string\n label: string\n /**\n * 把这个模型发给 `baseUrl` 时该用的名字。`id` 是平台内部标识,接了多个模型服务时\n * 形如 `provider-xxx::name`,直接发过去会被拒。不在 `baseUrl` 那个服务上的模型\n * 这里是空串——自己做模型选择器时据此过滤。\n */\n serviceModelId?: string\n}\n\nexport interface ModelCatalog {\n default: string\n models: ModelOption[]\n unavailableProviderIds?: string[]\n unavailableModelIds?: string[]\n /**\n * 平台默认模型服务的 OpenAI 兼容地址(Server ≥ 提供 `baseUrl` 的版本才有,否则为空)。\n * 自建应用可以带用户的 PAT 直接调它,不必让用户自己填地址——网关端口各部署不同,\n * 推算不出来。\n *\n * 这是**服务端视角**的地址:平台可能配的是 `http://127.0.0.1:30000/v1`,从自己后端\n * 转发没问题,直接丢给浏览器就指向用户自己的机器了。默认形态是后端透传(密钥也不该\n * 进浏览器),浏览器直连只适合这个地址对浏览器同样可达的场景。\n */\n baseUrl?: string\n /**\n * 直接调 `baseUrl` 时该用的默认模型名。**不要用 `default`**——那是平台内部标识,\n * 平台默认模型来自额外接的模型服务时它带 `provider-xxx::` 前缀,发过去只会得到\n * 「模型不存在」。没有可直调的模型时为空串。\n */\n defaultServiceModel?: string\n}\n\n/** Server 可供当前用户选择的模型目录。 */\nexport class ModelsResource {\n constructor(private client: BladeClient) {}\n\n list(): Promise<ModelCatalog> {\n return this.client.json(\"GET\", \"/api/config/models\")\n }\n}\n","import { type } from \"arktype\"\nimport type { Solution } from \"./solution\"\n\nexport const SessionStatus = type(\n \"'created' | 'running' | 'completed' | 'failed' | 'interrupted' | 'waiting_for_input'\",\n)\nexport type SessionStatus = typeof SessionStatus.infer\n\nexport type TemplateId =\n | \"default\"\n | \"skill_editor\"\n // ship-attack v2:用户从 ship-attack 页面点\"新建 session\"创建的会话。\n // 后端 _maybe_bind_first_skill 只对此模板触发首次绑定。\n | \"ship_attack\"\n\nexport type SkillEditorTemplateId = \"skill_editor\"\n\nexport type ModeId = \"planning\" | \"executing\"\n\nexport type PublishedSolutionRef =\n | { source: \"builtin\"; name: string }\n | { source: \"hub\"; org: string; name: string }\n\n/** 回放时录制内容的播放倍速。 */\nexport type ReplaySpeed = 1 | 2 | 5\n\n/**\n * 新建回放会话时的默认倍速。\n *\n * 所有创建入口都用它——曾经侧栏走 API 默认 5x、设置菜单初始化成 1x,\n * 同一个源对话从不同入口开出来速度不一样。\n */\nexport const DEFAULT_REPLAY_SPEED: ReplaySpeed = 5\n\nexport interface ReplayState {\n source_session_id?: string\n status?: \"replay\" | \"autonomous\"\n speed?: ReplaySpeed\n next_source_entry_id?: string | null\n ended_at?: string | null\n autonomous_reason?: string | null\n}\n\n/** 某个会话能否作为回放来源。 */\nexport interface ReplayPreview {\n session_id: string\n intent?: string | null\n supported: boolean\n /** supported 为 false 时给出的原因,可直接展示给用户。 */\n reason?: string | null\n}\n\nexport interface SessionPortMapping {\n container_port: number\n host_port: number\n}\n\n/**\n * 列表搜索时单条会话的命中信息。\n * - field='title':关键词出现在 intent 里,snippet 为 null(标题本身就在 UI 上)\n * - field='content':关键词出现在历史消息里,snippet 含截窗预览与角色\n */\nexport interface SessionSearchMatch {\n field: \"title\" | \"content\"\n snippet: { role: string; text: string } | null\n}\n\nexport const SessionInfo = type({\n id: \"string\",\n intent: \"string\",\n status: SessionStatus,\n created_at: \"string\",\n updated_at: \"string\",\n \"shared?\": \"boolean\",\n \"memory_enabled?\": \"boolean\",\n \"is_persistent?\": \"boolean\",\n \"is_headless?\": \"boolean\",\n \"viewer_role?\": \"'owner' | 'viewer'\",\n \"template_id?\": \"string | null\",\n \"model?\": \"string | null\",\n \"enable_thinking?\": \"boolean | null\",\n \"solution_id?\": \"string | null\",\n \"solution_ref?\": \"unknown\",\n \"biz_role_id?\": \"string | null\",\n \"solution?\": \"unknown\",\n \"plan_summary?\": \"string | null\",\n \"primary_skill_id?\": \"string | null\",\n // ship-attack v2:后端 engine.set_bound_skill 写入的\"绑定 skill id\"。\n // 未绑定 / 非 ship-attack session 为 null。\n \"bound_skill_id?\": \"string | null\",\n \"replay_state?\": \"unknown\",\n \"is_pinned?\": \"boolean\",\n \"pinned_at?\": \"string | null\",\n \"is_example?\": \"boolean\",\n \"ports?\": \"unknown\",\n \"disable_tools?\": \"string[]\",\n \"runtime_type?\": \"string | null\",\n \"daemon_id?\": \"string | null\",\n \"agent_runtime_id?\": \"string | null\",\n \"workspace_path?\": \"string | null\",\n \"ba_version?\": \"string | null\",\n \"sandbox_version?\": \"string | null\",\n \"chat_group_id?\": \"string | null\",\n \"match?\": \"unknown\",\n})\nexport type SessionInfo = Omit<\n typeof SessionInfo.infer,\n \"template_id\" | \"solution\" | \"ports\" | \"match\"\n> & {\n shared?: boolean\n memory_enabled?: boolean\n is_persistent?: boolean\n is_headless?: boolean\n viewer_role?: \"owner\" | \"viewer\"\n template_id?: TemplateId | null\n model?: string | null\n enable_thinking?: boolean | null\n solution_id?: string | null\n solution_ref?: PublishedSolutionRef | null\n biz_role_id?: string | null\n solution?: Solution | null\n primary_skill_id?: string | null\n bound_skill_id?: string | null\n replay_state?: ReplayState | null\n is_pinned?: boolean\n pinned_at?: string | null\n is_example?: boolean\n ports?: SessionPortMapping[]\n disable_tools?: string[]\n runtime_type?: \"sandbox\" | \"daemon\" | \"native\" | string | null\n daemon_id?: string | null\n agent_runtime_id?: string | null\n workspace_path?: string | null\n ba_version?: string | null\n sandbox_version?: string | null\n chat_group_id?: string | null\n /** 仅在带 q 搜索的列表响应中出现;普通列表里此字段缺省。 */\n match?: SessionSearchMatch | null\n}\n\n/**\n * 主 skill 配置快照(v2)。创建 session 时从 SKILL.md frontmatter 抽出并\n * 固化到 session_root/.blade/primary-skill.json;ship-attack 页面骨架的唯\n * 一数据源。\n */\nexport interface PrimarySkillStepSpec {\n n: number\n label: string\n}\n\nexport interface PrimarySkillStageSpec {\n id: string\n name: string\n steps: PrimarySkillStepSpec[]\n}\n\nexport interface PrimarySkillParallelMode {\n id: string\n name: string\n prompt_hint: string\n}\n\nexport interface PrimarySkillSnapshot {\n version: number\n skill_id: string\n title: string\n description: string\n stages: PrimarySkillStageSpec[]\n parallel_modes: PrimarySkillParallelMode[]\n captured_at: string\n}\n\n/**\n * 单 session detail(GET /api/sessions/:id)。列表接口返回 SessionInfo,\n * detail 在此基础上附加 primary_skill_snapshot。\n */\nexport interface SessionDetail extends SessionInfo {\n primary_skill_snapshot?: PrimarySkillSnapshot | null\n preview_url?: string | null\n /**\n * 会话级环境变量(owner-only)。后端仅在 GET detail 和 PUT /env 响应中返回,\n * 列表/搜索响应不带此字段。调用 setSessionEnv 后可类型安全地读回。\n */\n env?: Record<string, string>\n}\n","export type TextFile = {\n path: string\n content: string\n}\n\nexport type SolutionDefinition =\n | { id: string; role?: string }\n /** 自定义 Solution:文本文件路径均相对于 Solution 根目录。 */\n | { files: TextFile[]; role?: string }\n\nexport interface SkillDefinition {\n /** 会话内安装名,格式为 `组织/名称`。 */\n name: string\n /** 必须包含根目录的 SKILL.md。 */\n files: TextFile[]\n}\n\nexport interface SessionConfig {\n /** Server 模型目录中的 model ID。 */\n model?: string\n enableThinking?: boolean\n memoryEnabled?: boolean\n compactionRatio?: number\n env?: Record<string, string>\n disableTools?: string[]\n}\n\n/**\n * 声明一个待创建的会话。传给 `client.sessions.create(...)` 后,SDK 会先准备\n * Solution,再创建会话并安装 Skill;Promise resolve 时会话已经可以使用。\n */\nexport interface SessionDefinition {\n intent?: string\n solution?: SolutionDefinition\n skills?: SkillDefinition[]\n config?: SessionConfig\n}\n\nexport type SessionSetupStage = \"solution\" | \"session\" | \"skill\" | \"connection\"\n\n/** 声明式会话准备失败;stage 和 sessionId 可直接用于界面提示或日志。 */\nexport class SessionSetupError extends Error {\n readonly name = \"SessionSetupError\"\n readonly cause?: unknown\n\n constructor(\n message: string,\n readonly stage: SessionSetupStage,\n readonly sessionId?: string,\n options?: { cause?: unknown },\n ) {\n super(message)\n this.cause = options?.cause\n }\n}\n","import type {\n ContentBlock,\n PendingQuestionRef,\n ToolCallProjection,\n TurnProjection,\n} from \"../../schemas/projection\"\nimport type { TurnState } from \"./state\"\n\n// --- Tool call upsert ---\n\nexport function upsertToolCall(\n state: TurnState,\n toolCallId: string,\n toolName: string,\n displayName: string,\n args: string,\n): void {\n if (!toolCallId) return\n\n let found = false\n for (let i = 0; i < state.toolCalls.length; i++) {\n if (state.toolCalls[i].id !== toolCallId) continue\n const tc = state.toolCalls[i]\n state.toolCalls[i] = {\n ...tc,\n tool_name: toolName || tc.tool_name,\n display_name: displayName || tc.display_name,\n arguments: args || tc.arguments,\n }\n found = true\n break\n }\n if (!found) {\n state.toolCalls.push({\n id: toolCallId,\n tool_name: toolName,\n display_name: displayName,\n arguments: args,\n status: \"pending\",\n })\n }\n\n let blockFound = false\n for (let i = 0; i < state.blocks.length; i++) {\n const b = state.blocks[i]\n if (b.type !== \"tool_use\" || b.tool_call_id !== toolCallId) continue\n state.blocks[i] = {\n ...b,\n content: args || b.content,\n tool_name: toolName || b.tool_name,\n display_name: displayName || b.display_name,\n }\n blockFound = true\n break\n }\n if (!blockFound) {\n state.blocks.push({\n type: \"tool_use\",\n content: args,\n tool_call_id: toolCallId,\n tool_name: toolName || null,\n display_name: displayName || null,\n })\n }\n}\n\n// --- Tool result application ---\n\nexport function applyToolResult(\n state: TurnState,\n toolCallId: string,\n result: unknown,\n status: ToolCallProjection[\"status\"],\n durationMs: number | null,\n ranInParallel: boolean | null,\n sourceLoop: { loop_name: string; description: string } | null,\n startedAt: string | null = null,\n): void {\n let toolName = \"\"\n let displayName = \"\"\n let finalResult = result\n\n for (let i = 0; i < state.toolCalls.length; i++) {\n const tc = state.toolCalls[i]\n if (tc.id !== toolCallId) continue\n\n if (typeof result === \"string\") {\n finalResult = maybeEnrichAskUserResult(tc.tool_name, result, sourceLoop)\n }\n\n const update: Partial<ToolCallProjection> = { status, result: finalResult }\n if (durationMs != null) update.duration_ms = durationMs\n if (ranInParallel != null) update.ran_in_parallel = ranInParallel\n if (startedAt != null) update.started_at = startedAt\n state.toolCalls[i] = { ...tc, ...update }\n toolName = tc.tool_name\n displayName = tc.display_name\n break\n }\n\n upsertToolResultBlock(state, toolCallId, finalResult, toolName, displayName)\n}\n\nexport function appendToolResultDelta(\n state: TurnState,\n toolCallId: string,\n delta: string,\n reset = false,\n): void {\n if (!toolCallId || !delta) return\n\n let toolName = \"\"\n let displayName = \"\"\n let currentResult = \"\"\n\n for (let i = 0; i < state.toolCalls.length; i++) {\n const tc = state.toolCalls[i]\n if (tc.id !== toolCallId) continue\n toolName = tc.tool_name\n displayName = tc.display_name\n if (!reset && typeof tc.result === \"string\") currentResult = tc.result\n state.toolCalls[i] = { ...tc, result: currentResult + delta }\n break\n }\n\n for (const block of state.blocks) {\n if (block.type !== \"tool_result\" || block.tool_call_id !== toolCallId) continue\n if (!reset && typeof block.content === \"string\") currentResult = block.content\n break\n }\n\n upsertToolResultBlock(state, toolCallId, currentResult + delta, toolName, displayName)\n}\n\nfunction upsertToolResultBlock(\n state: TurnState,\n toolCallId: string,\n content: unknown,\n toolName: string,\n displayName: string,\n): void {\n for (let i = 0; i < state.blocks.length; i++) {\n const block = state.blocks[i]\n if (block.type !== \"tool_result\" || block.tool_call_id !== toolCallId) continue\n state.blocks[i] = {\n ...block,\n content,\n tool_name: toolName || block.tool_name,\n display_name: displayName || block.display_name,\n }\n return\n }\n\n state.blocks.push({\n type: \"tool_result\",\n content,\n tool_call_id: toolCallId,\n tool_name: toolName || null,\n display_name: displayName || null,\n })\n}\n\n// --- Text block append ---\n\nexport function appendTextBlock(\n state: TurnState,\n blockType: ContentBlock[\"type\"],\n content: unknown,\n): void {\n if (content == null || content === \"\") return\n const text = String(content)\n const lastBlock = state.blocks[state.blocks.length - 1]\n if (lastBlock && lastBlock.type === blockType && typeof lastBlock.content === \"string\") {\n state.blocks[state.blocks.length - 1] = {\n ...lastBlock,\n content: lastBlock.content + text,\n }\n return\n }\n state.blocks.push({ type: blockType, content: text })\n}\n\n// --- Tool call arguments append ---\n\nexport function appendToolCallArguments(\n state: TurnState,\n toolCallId: string,\n delta: string,\n): void {\n let newArgs = \"\"\n for (let i = 0; i < state.toolCalls.length; i++) {\n const tc = state.toolCalls[i]\n if (tc.id === toolCallId) {\n newArgs = tc.arguments + delta\n state.toolCalls[i] = { ...tc, arguments: newArgs }\n break\n }\n }\n if (!newArgs) return\n\n for (let i = 0; i < state.blocks.length; i++) {\n const b = state.blocks[i]\n if (b.type === \"tool_use\" && b.tool_call_id === toolCallId) {\n state.blocks[i] = { ...b, content: newArgs }\n break\n }\n }\n}\n\n// --- AskUserQuestion enrichment ---\n\nfunction maybeEnrichAskUserResult(\n toolName: string,\n result: string,\n sourceLoop: { loop_name: string; description: string } | null,\n): string {\n if (!sourceLoop) return result\n const normalized = toolName.includes(\":\") ? toolName.split(\":\").pop()! : toolName\n if (normalized !== \"AskUserQuestion\") return result\n try {\n const payload = JSON.parse(result)\n if (typeof payload !== \"object\" || payload === null) return result\n payload.source_loop = sourceLoop\n return JSON.stringify(payload)\n } catch {\n return result\n }\n}\n\n// --- System notification ---\n\nexport function buildSystemNotificationTurn(\n sequence: number,\n turnId: string,\n loopId: string,\n notificationType: string,\n status: string,\n title: string,\n detail: string | null,\n metadata: Record<string, unknown>,\n): TurnProjection {\n return {\n id: turnId,\n sequence,\n turn_id: turnId,\n loop_id: loopId,\n kind: \"message\",\n role: \"system\",\n status: \"completed\",\n blocks: [\n {\n type: \"system_notification\",\n content: {\n notification_type: notificationType,\n status,\n title,\n detail,\n metadata,\n },\n },\n ],\n tool_calls: [],\n model: null,\n usage: null,\n duration_ms: 0,\n }\n}\n\nexport function buildSystemNotificationBlock(\n notificationType: string,\n status: string,\n title: string,\n detail: string | null,\n metadata: Record<string, unknown>,\n): ContentBlock {\n return {\n type: \"system_notification\",\n content: {\n notification_type: notificationType,\n status,\n title,\n detail,\n metadata,\n },\n }\n}\n\n// --- Marker turn ---\n\nexport function buildMarkerTurn(\n sequence: number,\n turnId: string,\n loopId: string,\n blockType: ContentBlock[\"type\"],\n content: unknown,\n): TurnProjection {\n return {\n id: turnId,\n sequence,\n turn_id: turnId,\n loop_id: loopId,\n kind: \"message\",\n role: \"assistant\",\n status: \"completed\",\n blocks: [{ type: blockType, content }],\n tool_calls: [],\n model: null,\n usage: null,\n duration_ms: 0,\n }\n}\n\n// --- Compaction turn ---\n\nexport function buildCompactionTurn(\n sequence: number,\n compactionId: string,\n loopId: string,\n status: TurnProjection[\"status\"],\n data: Record<string, unknown>,\n): TurnProjection {\n const tokensBefore = asInt(data.tokens_before)\n const tokensAfter = asInt(data.tokens_after)\n let savedRatio: number | null = null\n if (tokensBefore && tokensBefore > 0 && tokensAfter != null) {\n savedRatio = 1 - tokensAfter / tokensBefore\n } else {\n savedRatio = asFloat(data.saved_ratio)\n }\n let archivedCount = asInt(data.archived_count)\n if (archivedCount == null && Array.isArray(data.archived_files)) {\n archivedCount = data.archived_files.length\n }\n\n const content = data.content\n const summaryFull = compactionSummaryFull(content)\n const summaryPreview = summaryFull\n ? summaryFull\n .split(\"\\n\")\n .map((l) => l.trim())\n .filter(Boolean)\n .join(\" \")\n .slice(0, 200)\n : null\n\n return {\n id: `compaction:${compactionId}`,\n sequence,\n turn_id: `compaction:${compactionId}`,\n loop_id: loopId,\n kind: \"compaction\",\n role: \"system\",\n status,\n blocks: [],\n tool_calls: [],\n model: null,\n usage: null,\n duration_ms: 0,\n compaction_id: compactionId,\n summary_preview: summaryPreview,\n summary_full: summaryFull,\n archived_count: archivedCount,\n archived_files: Array.isArray(data.archived_files)\n ? data.archived_files.filter(\n (item): item is Record<string, unknown> =>\n typeof item === \"object\" && item !== null && !Array.isArray(item),\n )\n : null,\n archived_tool_calls: Array.isArray(data.archived_tool_calls)\n ? data.archived_tool_calls.filter(\n (item): item is Record<string, unknown> =>\n typeof item === \"object\" && item !== null && !Array.isArray(item),\n )\n : null,\n tokens_before: tokensBefore,\n tokens_after: tokensAfter,\n saved_ratio: savedRatio,\n trigger: asTrigger(data.trigger),\n failure_reason: [data.failure_reason, data.fallback_reason, data.reason]\n .find((value): value is string => typeof value === \"string\" && value.length > 0) ?? null,\n fallback_applied: typeof data.fallback_applied === \"boolean\" ? data.fallback_applied : null,\n }\n}\n\nfunction compactionSummaryFull(content: unknown): string | null {\n const text = String(content ?? \"\")\n if (!text) return null\n const cleaned = text\n .replace(\"<compaction-summary>\", \"\")\n .replace(\"</compaction-summary>\", \"\")\n .replace(/\\r\\n/g, \"\\n\")\n .replace(/\\r/g, \"\\n\")\n .trim()\n return cleaned || null\n}\n\nfunction asInt(value: unknown): number | null {\n if (typeof value === \"boolean\") return null\n if (typeof value === \"number\") return Math.trunc(value)\n return null\n}\n\nfunction asFloat(value: unknown): number | null {\n if (typeof value === \"boolean\") return null\n if (typeof value === \"number\") return value\n return null\n}\n\nfunction asTrigger(value: unknown): \"auto\" | \"manual\" | \"forced_retry\" | null {\n if (value === \"auto\" || value === \"manual\" || value === \"forced_retry\") return value\n return null\n}\n\n// --- Child pause helpers ---\n\nexport interface ChildPauseInfo {\n parentLoopName: string\n parentToolCallId: string\n childLoopName: string\n childToolCallId: string\n description: string\n}\n\nexport function setToolCallStatus(\n turn: TurnState | TurnProjection | null | undefined,\n toolCallId: string,\n status: ToolCallProjection[\"status\"],\n result: unknown,\n pendingQuestionRef: PendingQuestionRef | null,\n): void {\n if (!turn || !toolCallId) return\n const toolCalls = \"toolCalls\" in turn ? turn.toolCalls : turn.tool_calls\n for (let i = 0; i < toolCalls.length; i++) {\n if (toolCalls[i].id !== toolCallId) continue\n toolCalls[i] = {\n ...toolCalls[i],\n status,\n result,\n pending_question_ref: pendingQuestionRef,\n }\n return\n }\n}\n\nexport function applyAskUserPauseToTurn(\n turn: TurnState | TurnProjection | null | undefined,\n pauseToolData: Record<string, unknown>,\n toolCallId: string,\n childLoopName: string,\n description: string,\n displayNameResolver: (name: string) => string,\n): void {\n if (!turn || !toolCallId) return\n\n const sourceLoop = childLoopName\n ? { loop_name: childLoopName, description }\n : null\n const toolName = String(pauseToolData.name ?? \"AskUserQuestion\")\n const args = JSON.stringify(pauseToolData.arguments ?? {})\n const result = askUserResultFromPausePayload(pauseToolData, sourceLoop)\n\n const isTurnState = \"toolCalls\" in turn\n const toolCalls = isTurnState ? turn.toolCalls : turn.tool_calls\n const blocks = turn.blocks\n\n // upsert tool call\n const displayName = displayNameResolver(toolName)\n let found = false\n for (let i = 0; i < toolCalls.length; i++) {\n if (toolCalls[i].id !== toolCallId) continue\n toolCalls[i] = {\n ...toolCalls[i],\n tool_name: toolName || toolCalls[i].tool_name,\n display_name: displayName || toolCalls[i].display_name,\n arguments: args || toolCalls[i].arguments,\n }\n found = true\n break\n }\n if (!found) {\n toolCalls.push({\n id: toolCallId,\n tool_name: toolName,\n display_name: displayName,\n arguments: args,\n status: \"pending\",\n })\n }\n\n // upsert tool_use block\n let blockFound = false\n for (let i = 0; i < blocks.length; i++) {\n if (blocks[i].type !== \"tool_use\" || blocks[i].tool_call_id !== toolCallId) continue\n blocks[i] = { ...blocks[i], content: args, tool_name: toolName, display_name: displayName }\n blockFound = true\n break\n }\n if (!blockFound) {\n blocks.push({\n type: \"tool_use\",\n content: args,\n tool_call_id: toolCallId,\n tool_name: toolName,\n display_name: displayName,\n })\n }\n\n // set status\n setToolCallStatus(turn, toolCallId, \"awaiting_answer\", result, null)\n\n // upsert tool_result block\n let resultBlockFound = false\n for (let i = 0; i < blocks.length; i++) {\n if (blocks[i].type !== \"tool_result\" || blocks[i].tool_call_id !== toolCallId) continue\n blocks[i] = { ...blocks[i], content: result }\n resultBlockFound = true\n break\n }\n if (!resultBlockFound) {\n blocks.push({\n type: \"tool_result\",\n content: result,\n tool_call_id: toolCallId,\n tool_name: toolName,\n display_name: displayName,\n })\n }\n}\n\nexport function applyChildPauseToParent(\n parentTurn: TurnState | TurnProjection | null | undefined,\n parentToolCallId: string,\n childLoopName: string,\n childToolCallId: string,\n description: string,\n displayNameResolver: (name: string) => string,\n): void {\n if (!parentTurn || !parentToolCallId) return\n\n const toolCalls = \"toolCalls\" in parentTurn ? parentTurn.toolCalls : parentTurn.tool_calls\n const blocks = parentTurn.blocks\n\n const displayName = displayNameResolver(\"Agent\")\n let found = false\n for (let i = 0; i < toolCalls.length; i++) {\n if (toolCalls[i].id !== parentToolCallId) continue\n toolCalls[i] = {\n ...toolCalls[i],\n tool_name: \"Agent\",\n display_name: displayName || toolCalls[i].display_name,\n }\n found = true\n break\n }\n if (!found) {\n toolCalls.push({\n id: parentToolCallId,\n tool_name: \"Agent\",\n display_name: displayName,\n arguments: \"\",\n status: \"pending\",\n })\n }\n\n // upsert tool_use block\n let blockFound = false\n for (let i = 0; i < blocks.length; i++) {\n if (blocks[i].type !== \"tool_use\" || blocks[i].tool_call_id !== parentToolCallId) continue\n blockFound = true\n break\n }\n if (!blockFound) {\n blocks.push({\n type: \"tool_use\",\n content: \"\",\n tool_call_id: parentToolCallId,\n tool_name: \"Agent\",\n display_name: displayName,\n })\n }\n\n setToolCallStatus(parentTurn, parentToolCallId, \"awaiting_answer\", null, {\n child_loop_name: childLoopName,\n child_tool_call_id: childToolCallId,\n description: description || null,\n })\n}\n\nfunction askUserResultFromPausePayload(\n pauseToolData: Record<string, unknown>,\n sourceLoop: { loop_name: string; description: string } | null,\n): string {\n const args =\n typeof pauseToolData.arguments === \"object\" && pauseToolData.arguments !== null\n ? (pauseToolData.arguments as Record<string, unknown>)\n : {}\n const payload: Record<string, unknown> = { questions: args.questions ?? [] }\n if (sourceLoop) payload.source_loop = sourceLoop\n return JSON.stringify(payload)\n}\n\nexport function sourceLoopFor(\n loopId: string,\n loopDescriptions: Map<string, string>,\n): { loop_name: string; description: string } | null {\n if (loopId === \"root\") return null\n const description = loopDescriptions.get(loopId)\n if (!description) return null\n return { loop_name: loopId, description }\n}\n\n/** 本轮交付给用户的成果:工作区里的文件,或可以打开的网址。 */\nexport interface FinalArtifact {\n kind: \"file\" | \"link\"\n /** file 是文件路径(相对工作目录或容器内绝对路径);link 是 http/https 网址。 */\n target: string\n label: string\n}\n\nconst MAX_FINAL_ARTIFACTS = 20\n\n/**\n * 服务端已经清洗过一遍,这里只挡住渲染不了的形态。绝对路径要留着:会话的真实\n * 工作目录可能是项目目录或用户自己切过的目录,取文件那一层认绝对路径,在这里\n * 拦掉反而会让对的卡片消失。\n */\nfunction normalizeFinalArtifacts(raw: unknown): FinalArtifact[] {\n if (!Array.isArray(raw)) return []\n const artifacts: FinalArtifact[] = []\n const seen = new Set<string>()\n for (const item of raw) {\n if (typeof item !== \"object\" || item === null) continue\n const record = item as Record<string, unknown>\n const target = String(record.target ?? \"\").trim()\n if (!target || seen.has(target)) continue\n const isLink = /^https?:\\/\\//i.test(target)\n // 越界路径没有能打开它的形态,留下来只会变成点了报错的卡片。\n if (!isLink && target.split(\"/\").includes(\"..\")) continue\n seen.add(target)\n artifacts.push({\n kind: isLink ? \"link\" : \"file\",\n target,\n label: String(record.label ?? \"\").trim(),\n })\n if (artifacts.length === MAX_FINAL_ARTIFACTS) break\n }\n return artifacts\n}\n\n/**\n * Shared by the streaming and history channels — both must decide \"is this\n * follow-up showable\" identically. Returns null when there is nothing to show.\n */\nexport function normalizePostChatFollowup(\n data: Record<string, unknown>,\n assistantEntryId: string,\n): {\n assistant_entry_id: string\n recaption: string\n suggestions: string[]\n final_artifacts: FinalArtifact[]\n feedback_eligible: boolean\n feedback_scope: \"latest_result\"\n} | null {\n const raw = data.suggestions\n const suggestions: string[] = []\n if (Array.isArray(raw)) {\n for (const value of raw) {\n if (typeof value !== \"string\") continue\n const text = value.trim()\n if (text && !suggestions.includes(text)) suggestions.push(text)\n }\n }\n const recaption = String(data.recaption ?? \"\")\n const finalArtifacts = normalizeFinalArtifacts(data.final_artifacts)\n const feedbackEligible = data.feedback_eligible === true\n if (suggestions.length === 0 && !recaption && finalArtifacts.length === 0 && !feedbackEligible)\n return null\n return {\n assistant_entry_id: assistantEntryId,\n recaption,\n suggestions: suggestions.slice(0, 3),\n final_artifacts: finalArtifacts,\n feedback_eligible: feedbackEligible,\n feedback_scope: \"latest_result\",\n }\n}\n\nexport function normalizeChildPause(\n pausePayload: Record<string, unknown>,\n): {\n pauseToolData: Record<string, unknown>\n childLoopName: string\n childToolCallId: string\n description: string\n} {\n const rawPtd = pausePayload.pause_tool_data\n const pauseToolData: Record<string, unknown> =\n typeof rawPtd === \"object\" && rawPtd !== null\n ? { ...(rawPtd as Record<string, unknown>) }\n : { ...pausePayload }\n\n let sourceLoop = pauseToolData.source_loop as Record<string, unknown> | undefined\n if (typeof sourceLoop !== \"object\" || sourceLoop === null) {\n sourceLoop = pausePayload.source_loop as Record<string, unknown> | undefined\n }\n\n const childLoopName =\n String(pausePayload.child_loop_name ?? \"\") ||\n (typeof sourceLoop === \"object\" && sourceLoop ? String(sourceLoop.name ?? \"\") : \"\")\n\n const childToolCallId =\n String(\n pausePayload.child_pause_tool_call_id ?? pauseToolData.tool_call_id ?? \"\",\n )\n\n const description =\n typeof sourceLoop === \"object\" && sourceLoop ? String(sourceLoop.description ?? \"\") : \"\"\n\n if (childLoopName && description) {\n pauseToolData.source_loop = { name: childLoopName, description }\n }\n\n return { pauseToolData, childLoopName, childToolCallId, description }\n}\n","import type { ContentBlock, PendingQuestionRef, ToolBridgeContent } from \"./projection\"\nimport type { ContextProjectionData } from \"./context\"\n\nexport interface TextContentPart {\n type: \"text\"\n text: string\n}\n\nexport interface ImageUrlContentPart {\n type: \"image_url\"\n image_url: {\n url: string\n }\n}\n\nexport interface FileContentPart {\n type: \"file\"\n name: string\n data: string\n}\n\nexport type MessageContentPart = TextContentPart | ImageUrlContentPart | FileContentPart\nexport type MessageContent = string | MessageContentPart[]\n\nexport interface ToolCallInfo {\n id: string\n name: string\n display_name?: string | null\n arguments: string\n result?: unknown\n status?: \"pending\" | \"done\" | \"error\" | \"cancelled\" | \"awaiting_answer\"\n duration_ms?: number | null\n pending_question_ref?: PendingQuestionRef | null\n}\n\nexport type { ToolBridgeContent }\n\n/** Derive tool status from the result content string. */\nexport function inferToolStatus(\n resultStr: string,\n): \"done\" | \"error\" | \"cancelled\" {\n if (resultStr.includes('\"Cancelled by user\"')) return \"cancelled\"\n try {\n const parsed = JSON.parse(resultStr)\n if (typeof parsed === \"object\" && parsed !== null) {\n // Direct error: {\"error\": \"...\"}\n if (\"error\" in parsed && parsed.error) return \"error\"\n // 部分工具把输出包装为 {\"result\": {\"error\": \"...\"}, ...}\n const nested = parsed.result\n if (typeof nested === \"object\" && nested !== null && \"error\" in nested && nested.error) {\n return \"error\"\n }\n }\n } catch {\n // not JSON, treat as success\n }\n return \"done\"\n}\n\nexport interface MemoryRefInfo {\n id: number\n content_preview: string\n skill_name?: string | null\n}\n\nexport interface CompactionInfo {\n compaction_id: string\n summary_preview?: string | null\n summary_full?: string | null\n archived_count?: number | null\n archived_files?: ArchivedFileInfo[] | null\n archived_tool_calls?: ArchivedToolCallInfo[] | null\n tokens_before?: number | null\n tokens_after?: number | null\n saved_ratio?: number | null\n trigger?: \"auto\" | \"manual\" | \"forced_retry\" | null\n failure_reason?: string | null\n fallback_applied?: boolean | null\n}\n\nexport interface ArchivedFileInfo {\n tool_name?: string | null\n filename?: string | null\n relative_path?: string | null\n size_bytes?: number | null\n}\n\nexport interface ArchivedToolCallInfo {\n tool_call_id?: string | null\n tool_name?: string | null\n archive_path?: string | null\n replacement_content?: string | null\n entry_id?: string | null\n}\n\nexport interface ChatMessage {\n role: \"user\" | \"assistant\" | \"tool\" | \"error\"\n content: MessageContent\n reasoning?: string\n tool_calls?: ToolCallInfo[]\n status?: \"streaming\" | \"completed\" | \"paused\" | \"failed\" | \"interrupted\"\n duration_ms?: number\n timestamp?: string\n entry_id?: string\n /** Stable React key retained when an optimistic user message is confirmed. */\n render_id?: string\n parent_id?: string | null\n loop_name?: string\n /** Entry kind from backend -- present for non-message entries like mode changes. */\n kind?: string\n /** Memory references injected into this turn's context */\n memory_refs?: MemoryRefInfo[]\n /** Raw projection blocks for block-level UI rendering. */\n blocks?: ContentBlock[]\n /** Compaction metadata for compaction turns. */\n compaction?: CompactionInfo\n /** Sourced Context metadata for rendering or headless consumers. */\n context?: ContextProjectionData\n}\n","import { inferToolStatus } from \"../../schemas/message\"\nimport type {\n ContentBlock,\n MemoryRef,\n ToolCallProjection,\n TurnProjection,\n} from \"../../schemas/projection\"\n\nexport interface TurnState {\n turnId: string\n loopId: string\n role: \"user\" | \"assistant\" | \"system\"\n model: string | null\n startedAt: number\n contextWindow: number\n blocks: ContentBlock[]\n toolCalls: ToolCallProjection[]\n usage: Record<string, unknown> | null\n responseDone: boolean\n firstTokenMs: number | null\n streamDurationMs: number | null\n firstTokenDeliveryMs: number | null\n /** 生产者上报的模型请求时序;缺失时保持 null,不用浏览器时间补(#2581 A1/I1)。 */\n modelStartedAt: string | null\n modelDurationMs: number | null\n modelStartedAtReported: boolean\n memoryRefs: MemoryRef[] | null\n parentForkToolCallId: string | null\n}\n\nexport function createTurnState(\n turnId: string,\n loopId: string,\n opts: {\n model?: string | null\n contextWindow?: number\n memoryRefs?: MemoryRef[] | null\n } = {},\n): TurnState {\n return {\n turnId,\n loopId,\n role: \"assistant\",\n model: opts.model ?? null,\n startedAt: Date.now(),\n contextWindow: opts.contextWindow ?? 0,\n blocks: [],\n toolCalls: [],\n usage: null,\n responseDone: false,\n firstTokenMs: null,\n streamDurationMs: null,\n firstTokenDeliveryMs: null,\n modelStartedAt: null,\n modelDurationMs: null,\n modelStartedAtReported: false,\n memoryRefs: opts.memoryRefs ?? null,\n parentForkToolCallId: null,\n }\n}\n\nexport function snapshot(\n state: TurnState,\n sequence: number,\n status: TurnProjection[\"status\"],\n): TurnProjection {\n return {\n id: state.turnId,\n sequence,\n turn_id: state.turnId,\n loop_id: state.loopId,\n kind: \"message\",\n role: state.role,\n status,\n blocks: [...state.blocks],\n tool_calls: [...state.toolCalls],\n model: state.model,\n usage: state.usage ? { ...state.usage } : null,\n duration_ms: state.modelDurationMs,\n first_token_ms: state.firstTokenMs,\n stream_duration_ms: state.streamDurationMs,\n first_token_delivery_ms: state.firstTokenDeliveryMs,\n started_at: state.modelStartedAt ?? new Date(state.startedAt).toISOString(),\n // 没有 payload 上报时用的是 loop:turn 的浏览器事件时间,标记出来供瀑布区分。\n has_reported_timing: state.modelStartedAtReported,\n context_window: state.contextWindow,\n memory_refs: state.memoryRefs,\n parent_fork_tool_call_id: state.parentForkToolCallId,\n }\n}\n\nexport const PAUSE_TOOL_NAMES = new Set([\"AskUserQuestion\", \"ExitPlanMode\"])\n\nexport function toolStatusFromResult(result: unknown): ToolCallProjection[\"status\"] {\n const text =\n typeof result === \"string\"\n ? result\n : Array.isArray(result)\n ? result\n .filter(\n (p): p is { type: string; text: string } =>\n typeof p === \"object\" && p !== null && p.type === \"text\",\n )\n .map((p) => p.text ?? \"\")\n .join(\"\\n\")\n : String(result ?? \"\")\n return inferToolStatus(text)\n}\n","export type ContextAction = \"published\" | \"retained\" | \"removed\"\n\n/** Safe display-source metadata retained for headless consumers. */\nexport type ContextSourceInfo = Record<string, unknown>\n\nexport interface ContextProjectionData {\n context_kind: string\n context_key: string\n context_name: string\n context_order: number\n context_action: ContextAction\n context_revision: string\n display_title?: string | null\n display_summary?: string | null\n sources: ContextSourceInfo[]\n}\n\nexport interface ContextProjectionFields {\n context_kind?: string | null\n context_key?: string | null\n context_name?: string | null\n context_order?: number | null\n context_action?: ContextAction | null\n context_revision?: string | null\n display_title?: string | null\n display_summary?: string | null\n sources?: ContextSourceInfo[] | null\n}\n\nexport interface ContextDisplayState {\n title: string\n summary: string\n detail: string\n isRemoved: boolean\n}\n\nexport interface ContextGroupDisplayState {\n title: string\n summary: string\n count: number\n}\n\nconst BUILTIN_CONTEXT_TITLES: Record<string, string> = {\n \"agent-instructions\": \"项目说明\",\n \"skill-catalog\": \"可用能力\",\n \"runtime-context\": \"当前工作环境\",\n \"workspace-context\": \"当前工作区环境\",\n}\n\nconst BUILTIN_CONTEXT_DETAILS: Record<string, string> = {\n \"agent-instructions\": \"这些说明会帮助智能体理解当前项目和工作要求。\",\n \"skill-catalog\": \"这些能力会帮助智能体选择合适的方式完成任务。\",\n \"runtime-context\": \"这些信息会帮助智能体了解当前文件夹和运行条件。\",\n \"workspace-context\": \"这些信息会帮助智能体了解当前工作目录、文件和运行环境。\",\n}\n\nfunction nonEmptyString(value: unknown): string | null {\n return typeof value === \"string\" && value.trim() ? value.trim() : null\n}\n\nexport function contextProjectionData(\n fields: ContextProjectionFields,\n): ContextProjectionData | null {\n const contextKind = nonEmptyString(fields.context_kind)\n const contextKey = nonEmptyString(fields.context_key)\n const contextName = nonEmptyString(fields.context_name)\n const contextRevision = nonEmptyString(fields.context_revision)\n if (\n !contextKind ||\n !contextKey ||\n !contextName ||\n !contextRevision ||\n typeof fields.context_order !== \"number\" ||\n !Number.isFinite(fields.context_order) ||\n !fields.context_action\n ) {\n return null\n }\n return {\n context_kind: contextKind,\n context_key: contextKey,\n context_name: contextName,\n context_order: fields.context_order,\n context_action: fields.context_action,\n context_revision: contextRevision,\n display_title: nonEmptyString(fields.display_title),\n display_summary: nonEmptyString(fields.display_summary),\n sources: Array.isArray(fields.sources) ? fields.sources : [],\n }\n}\n\n/** The single status-to-display mapping used by both React chat surfaces. */\nexport function getContextDisplayState(\n context: ContextProjectionData,\n): ContextDisplayState {\n // 后端为每个原子给了具体标题,优先用它。按 kind 查的表只是老历史条目的兜底:\n // 同一个 kind 下现在有多个原子(三份说明、两块运行环境),标题不能再按 kind 定。\n const title =\n nonEmptyString(context.display_title) ??\n BUILTIN_CONTEXT_TITLES[context.context_kind] ??\n \"对话背景\"\n const isRemoved = context.context_action === \"removed\"\n const summary =\n nonEmptyString(context.display_summary) ??\n (isRemoved\n ? \"已停止用于后续对话\"\n : context.context_action === \"retained\"\n ? \"继续用于后续对话\"\n : context.context_kind === \"agent-instructions\"\n ? \"已更新本次对话使用的项目说明\"\n : context.context_kind === \"skill-catalog\"\n ? \"已更新本次可用能力\"\n : context.context_kind === \"runtime-context\"\n ? \"已更新本次工作环境\"\n : context.context_kind === \"workspace-context\"\n ? \"已更新本次工作区环境\"\n : \"已更新本次对话背景\")\n const detail = isRemoved\n ? `${title}已不再用于后续对话。`\n : (BUILTIN_CONTEXT_DETAILS[context.context_kind] ??\n \"这些信息会帮助智能体理解当前任务。\")\n return { title, summary, detail, isRemoved }\n}\n\n/**\n * 把一段渲染序列里连续的 Context 归成组。\n *\n * 入参是序列里每一项的 context kind,非 Context 项传 null;返回每一段连续\n * Context 的下标数组。纯下标运算,不认识任何 UI 类型,所以调试日志、Lite 视图\n * 和 SDK 卡片可以共用同一份分组判定,各自只管排版。\n */\nexport function groupAdjacentContextRuns(\n kinds: readonly (string | null)[],\n): readonly (readonly number[])[] {\n const runs: number[][] = []\n let current: number[] | null = null\n kinds.forEach((kind, index) => {\n if (kind === null) {\n current = null\n return\n }\n if (current === null) {\n current = []\n runs.push(current)\n }\n current.push(index)\n })\n return runs\n}\n\n/** 折叠行的文案。展开后才逐条显示各自的标题与状态。 */\nexport function getContextGroupDisplayState(\n contexts: readonly ContextProjectionData[],\n): ContextGroupDisplayState {\n const count = contexts.length\n if (count === 1) {\n const single = getContextDisplayState(contexts[0])\n return { title: single.title, summary: single.summary, count }\n }\n const removed = contexts.filter(\n (context) => context.context_action === \"removed\",\n ).length\n const updated = count - removed\n const parts: string[] = []\n if (updated > 0) parts.push(`${updated} 项已更新`)\n if (removed > 0) parts.push(`${removed} 项已停用`)\n return {\n title: \"对话背景\",\n summary: parts.join(\" · \") || `${count} 项`,\n count,\n }\n}\n","import { contextProjectionData } from \"../../schemas/context\"\nimport type { TurnProjection } from \"../../schemas/projection\"\nimport { isRecord } from \"../type-guards\"\n\n/** Build one Context turn from the canonical entry used by live and history paths. */\nexport function buildContextTurn(\n entry: Record<string, unknown>,\n sequence: number,\n): TurnProjection | null {\n if (entry.kind !== \"context\" || !isRecord(entry.source) || !isRecord(entry.data)) {\n return null\n }\n const display = isRecord(entry.data.display) ? entry.data.display : {}\n const message = isRecord(entry.message) ? entry.message : {}\n const context = contextProjectionData({\n context_kind: typeof entry.source.kind === \"string\" ? entry.source.kind : null,\n context_key: typeof entry.source.key === \"string\" ? entry.source.key : null,\n context_name: typeof entry.data.contribution_name === \"string\" ? entry.data.contribution_name : null,\n context_order: typeof entry.data.order === \"number\" ? entry.data.order : null,\n context_action:\n entry.data.action === \"published\" || entry.data.action === \"retained\" || entry.data.action === \"removed\"\n ? entry.data.action\n : null,\n context_revision: typeof entry.data.revision === \"string\" ? entry.data.revision : null,\n display_title: typeof display.title === \"string\" ? display.title : null,\n display_summary: typeof display.summary === \"string\" ? display.summary : null,\n sources: Array.isArray(display.sources) ? display.sources.filter(isRecord) : [],\n })\n if (!context) return null\n const turnId = typeof entry.id === \"string\" && entry.id ? entry.id : `context-${sequence}`\n return {\n id: turnId,\n sequence,\n turn_id: turnId,\n loop_id: typeof entry.loop_name === \"string\" && entry.loop_name ? entry.loop_name : \"root\",\n kind: \"context\",\n role: \"system\",\n status: \"completed\",\n blocks: [],\n tool_calls: [],\n model: null,\n usage: null,\n duration_ms: 0,\n context_content: Object.hasOwn(message, \"content\") ? message.content : null,\n ...context,\n }\n}\n","import type { MemoryRef, RunTiming, TurnProjection } from \"../../schemas/projection\"\nimport {\n applyAskUserPauseToTurn,\n applyChildPauseToParent,\n appendTextBlock,\n appendToolCallArguments,\n appendToolResultDelta,\n applyToolResult,\n buildCompactionTurn,\n buildMarkerTurn,\n buildSystemNotificationBlock,\n buildSystemNotificationTurn,\n type ChildPauseInfo,\n normalizeChildPause,\n normalizePostChatFollowup,\n setToolCallStatus,\n sourceLoopFor,\n upsertToolCall,\n} from \"./helpers\"\nimport { isRecord } from \"../type-guards\"\nimport { createTurnState, PAUSE_TOOL_NAMES, snapshot, toolStatusFromResult, type TurnState } from \"./state\"\nimport { buildContextTurn } from \"./context\"\n\n// Keep aligned with host/projections/_notifications.py::background_task_status.\nfunction backgroundTaskStatus(payload: Record<string, unknown>): \"done\" | \"error\" {\n const tasks = Array.isArray(payload.tasks) ? payload.tasks : []\n return tasks.some((task) => isRecord(task) && (\n [\"failed\", \"cancelled\", \"lost\"].includes(String(task.status)) ||\n (typeof task.exit_code === \"number\" && task.exit_code !== 0)\n )) ? \"error\" : \"done\"\n}\n\nexport interface RawEvent {\n type: string\n payload: Record<string, unknown>\n}\n\n/** 在任何事件处理前确认 Socket.IO 批次已到达客户端。 */\nexport function acknowledgeTurnEvents(acknowledge?: () => void): void {\n acknowledge?.()\n}\n\nexport type ProjectionUpdate =\n | { kind: \"upsert\"; turn: TurnProjection }\n | {\n kind: \"workspace_changed\"\n loopId: string\n toolCallId?: string\n toolName?: string\n workspacePath?: string\n }\n\n/** 是否包含会改变聊天运行生命周期的事件。纯观测/整理事件不启动新一轮。 */\nexport function hasChatRunEvent(events: RawEvent[]): boolean {\n return events.some(\n (event) =>\n event.type !== \"llm:first_token:delivered\" &&\n event.type !== \"session:post_chat_followup\" &&\n !event.type.startsWith(\"compaction:\"),\n )\n}\n\n/**\n * 缺失 chat:end 时的终态兜底。只有被投影接受到当前 assistant turn 的 followup\n * 才能结束流式态;陈旧 followup 或其后已有新轮事件时均返回 false。\n */\nexport function acceptedPostChatFollowupCompletesLatestRun(\n events: RawEvent[],\n updates: ProjectionUpdate[],\n): boolean {\n const acceptedAssistantEntryIds = new Set(\n updates.flatMap((update) => {\n if (update.kind !== \"upsert\") return []\n const followup = update.turn.post_chat_followup\n return followup?.assistant_entry_id ? [followup.assistant_entry_id] : []\n }),\n )\n for (let index = events.length - 1; index >= 0; index -= 1) {\n const event = events[index]\n if (event?.type !== \"session:post_chat_followup\") continue\n const assistantEntryId = String(event.payload.assistant_entry_id ?? \"\")\n return (\n acceptedAssistantEntryIds.has(assistantEntryId) &&\n !hasChatRunEvent(events.slice(index + 1))\n )\n }\n return false\n}\n\ntype FollowupTurn = TurnProjection\n\nfunction isConversationTurn(turn: TurnProjection): boolean {\n return (\n (turn.role === \"user\" || turn.role === \"assistant\") &&\n (turn.kind ?? \"message\") === \"message\" &&\n !turn.blocks.some(\n (block) =>\n block.type === \"mode_change\" ||\n block.type === \"plan_status\" ||\n block.type === \"ask_user_answer\",\n )\n )\n}\n\nfunction completedResponseText(content: unknown): string {\n if (typeof content === \"string\") return content\n if (!Array.isArray(content)) return content == null ? \"\" : String(content)\n return content\n .filter(\n (part): part is Record<string, unknown> =>\n typeof part === \"object\" && part !== null && !Array.isArray(part),\n )\n .filter((part) => part.type === \"text\")\n .map((part) => String(part.text ?? \"\"))\n .join(\"\")\n}\n\nfunction replaceTextContent(state: TurnState, content: string): void {\n const currentContent = state.blocks\n .filter((block) => block.type === \"text\")\n .map((block) => String(block.content ?? \"\"))\n .join(\"\")\n if (currentContent === content) return\n const replacement = { type: \"text\" as const, content }\n const blocks: TurnState[\"blocks\"] = []\n let inserted = false\n for (const block of state.blocks) {\n if (block.type === \"text\") {\n if (content && !inserted) {\n blocks.push(replacement)\n inserted = true\n }\n continue\n }\n blocks.push(block)\n }\n if (content && !inserted) {\n const toolIndex = blocks.findIndex((block) => block.type === \"tool_use\")\n blocks.splice(toolIndex < 0 ? blocks.length : toolIndex, 0, replacement)\n }\n state.blocks = blocks\n}\n\nfunction applyResponseBlockOrder(state: TurnState, value: unknown): boolean {\n // Keep this decision path aligned with ProjectionBuilder._apply_response_block_order.\n if (!Array.isArray(value)) return false\n const ordered: TurnState[\"blocks\"] = []\n for (const item of value) {\n if (typeof item !== \"object\" || item === null || Array.isArray(item)) continue\n const block = item as Record<string, unknown>\n if (block.type === \"text\" || block.type === \"thinking\") {\n const content = String(block[block.type] ?? \"\")\n if (content) ordered.push({ type: block.type, content })\n continue\n }\n if (block.type !== \"tool_call\") continue\n const toolCallId = String(block.id ?? \"\")\n const toolBlock = state.blocks.find(\n (candidate) =>\n candidate.type === \"tool_use\" && candidate.tool_call_id === toolCallId,\n )\n if (toolBlock) ordered.push(toolBlock)\n }\n if (ordered.length === 0 && value.length > 0) return false\n const unrelatedBlocks = state.blocks.filter(\n (block) =>\n block.type !== \"text\" && block.type !== \"thinking\" && block.type !== \"tool_use\",\n )\n state.blocks = [...ordered, ...unrelatedBlocks]\n return true\n}\n\nexport class ClientProjectionBuilder {\n private activeTurns = new Map<string, TurnState>()\n private lastTurnIds = new Map<string, string>()\n private latestTurns = new Map<string, TurnProjection>()\n private turnsById = new Map<string, TurnProjection>()\n private loopDescriptions = new Map<string, string>()\n /** loop_name → 正在运行的子智能体起点,agent:end 结算并挂到父工具调用上。 */\n private activeSubagentRuns = new Map<string, { runId: string; startedAt: string }>()\n private pendingChildPauses = new Map<string, ChildPauseInfo>()\n private pendingMemoryRefs = new Map<string, { turnId: string; refs: MemoryRef[] }>()\n private activeCompactions = new Map<string, Record<string, unknown>>()\n private failedCompactions = new Map<string, Record<string, unknown>>()\n private seq = 0\n private syntheticCounter = 0\n private displayNameResolver: (name: string) => string\n\n constructor(displayNameResolver?: (name: string) => string) {\n this.displayNameResolver = displayNameResolver ?? ((n) => n)\n }\n\n processBatch(events: RawEvent[]): ProjectionUpdate[] {\n const lastUpsertByTurn = new Map<string, ProjectionUpdate & { kind: \"upsert\" }>()\n const nonUpserts: ProjectionUpdate[] = []\n for (const event of events) {\n const updates = this.processEvent(event)\n if (!updates) continue\n for (const u of updates) {\n if (u.kind === \"upsert\") {\n lastUpsertByTurn.set(u.turn.turn_id, u)\n } else {\n nonUpserts.push(u)\n }\n }\n }\n return [...nonUpserts, ...lastUpsertByTurn.values()]\n }\n\n processEvent(event: RawEvent): ProjectionUpdate[] | null {\n const payload = event.payload\n const loopId = String(payload.loop_name ?? \"root\")\n\n switch (event.type) {\n case \"memory:inject:done\":\n return this.onMemoryInject(loopId, payload)\n case \"memory:inject:none\":\n return null\n case \"context:entry\":\n return this.onContextEntry(payload)\n case \"loop:turn\":\n return this.onLoopTurn(loopId, payload)\n case \"mode:change\":\n return this.onModeChange(loopId, payload)\n case \"plan:status:update\":\n return this.onPlanStatusUpdate(loopId, payload)\n case \"workspace:changed\":\n return this.onWorkspaceChanged(loopId, payload)\n case \"agent:start\":\n return this.onAgentStart(loopId, payload)\n case \"bg:started\":\n return this.onBgStarted(loopId, payload)\n case \"bg:tasks_completed\":\n return this.onBgTasksCompleted(loopId, payload)\n case \"loop:ask_user_answer\":\n return this.onAskUserAnswer(loopId, payload)\n case \"user:message\":\n return this.onUserMessage(loopId, payload)\n case \"session:post_chat_followup\":\n return this.onPostChatFollowup(payload)\n }\n\n if (event.type.startsWith(\"compaction:\"))\n return this.onCompaction(event.type, loopId, payload)\n\n if (event.type === \"llm:first_token:delivered\") {\n const targetTurnId = String(payload.turn_id ?? \"\")\n const active = this.activeTurns.get(loopId)\n if (active && (!targetTurnId || active.turnId === targetTurnId)) {\n this.applyFirstTokenDelivery(active, payload)\n return this.syncPatch(active)\n }\n const latest = targetTurnId\n ? this.turnsById.get(targetTurnId)\n : this.latestTurns.get(loopId)\n const duration = payload.first_token_delivery_ms\n if (!latest || latest.role !== \"assistant\" || typeof duration !== \"number\" || duration < 0) {\n return null\n }\n const turn = { ...latest, first_token_delivery_ms: duration }\n this.turnsById.set(turn.turn_id, turn)\n if (this.latestTurns.get(loopId)?.turn_id === turn.turn_id) {\n this.latestTurns.set(loopId, turn)\n }\n return [{ kind: \"upsert\", turn }]\n }\n\n const state = this.activeTurns.get(loopId)\n if (!state) {\n if (event.type === \"chat:end\") {\n this.pendingMemoryRefs.delete(loopId)\n return null\n }\n if (event.type === \"agent:end\") return this.onAgentEnd(null, loopId, payload)\n return null\n }\n\n switch (event.type) {\n case \"llm:stream:reset\":\n state.blocks = []\n state.toolCalls = []\n state.usage = null\n state.responseDone = false\n state.firstTokenMs = null\n state.streamDurationMs = null\n state.firstTokenDeliveryMs = null\n return this.syncPatch(state)\n case \"llm:thinking:delta\":\n this.applyFirstTokenDelivery(state, payload)\n return this.onDelta(state, \"thinking\", \"\", String(payload.content ?? \"\"))\n case \"llm:content:delta\":\n this.applyFirstTokenDelivery(state, payload)\n return this.onDelta(state, \"text\", \"\", String(payload.content ?? \"\"))\n case \"llm:content:complete\":\n replaceTextContent(state, String(payload.content ?? \"\"))\n return this.syncPatch(state)\n case \"llm:content:done\":\n this.applyStreamTiming(state, payload)\n return this.syncPatch(state)\n case \"llm:tool_call:created\":\n this.applyFirstTokenDelivery(state, payload)\n return this.onToolCallCreated(state, payload)\n case \"llm:tool_call:arguments:delta\":\n this.applyFirstTokenDelivery(state, payload)\n return this.onToolCallArgumentsDelta(state, payload)\n case \"llm:response:done\":\n return this.onResponseDone(state, loopId, payload)\n case \"tool:result:delta\":\n return this.onToolResultDelta(state, payload)\n case \"tool:result:done\":\n return this.onToolResultDone(state, loopId, payload)\n case \"loop:tool_ui\":\n return this.onToolUi(state, payload)\n case \"loop:tool_bridge\":\n return this.onToolBridge(state, payload)\n case \"tool:approval:required\":\n return this.onToolApprovalRequired(state, payload)\n case \"loop:child_pause\":\n return this.onChildPause(state, loopId, payload)\n case \"chat:end\":\n return this.onChatEnd(state, loopId, payload)\n case \"agent:end\":\n return this.onAgentEnd(state, loopId, payload)\n default:\n return null\n }\n }\n\n reset(): void {\n this.activeTurns.clear()\n this.lastTurnIds.clear()\n this.latestTurns.clear()\n this.turnsById.clear()\n this.loopDescriptions.clear()\n this.activeSubagentRuns.clear()\n this.pendingChildPauses.clear()\n this.pendingMemoryRefs.clear()\n this.activeCompactions.clear()\n this.failedCompactions.clear()\n this.seq = 0\n this.syntheticCounter = 0\n }\n\n seedSequence(maxSeq: number): void {\n if (maxSeq > this.seq) {\n this.seq = maxSeq\n }\n }\n\n _seedTurns(turns: TurnProjection[]): void {\n const latestTurns = new Map<string, TurnProjection>()\n const turnsById = new Map<string, TurnProjection>()\n for (const turn of turns) {\n this.seedSequence(turn.sequence)\n if (!isConversationTurn(turn)) continue\n turnsById.set(turn.turn_id, turn)\n const current = latestTurns.get(turn.loop_id)\n if (!current || turn.sequence >= current.sequence) {\n latestTurns.set(turn.loop_id, turn)\n }\n }\n this.latestTurns = latestTurns\n this.turnsById = turnsById\n }\n\n // --- Event handlers ---\n\n private onMemoryInject(\n loopId: string,\n payload: Record<string, unknown>,\n ): null {\n const refs = payload.memory_refs\n const turnId = String(payload.turn_id ?? \"\")\n if (Array.isArray(refs) && refs.length > 0) {\n this.pendingMemoryRefs.set(loopId, {\n turnId,\n refs: refs.map((r: Record<string, unknown>) => ({\n id: Number(r.id),\n content_preview: String(r.content_preview ?? \"\"),\n skill_name: r.skill_name != null ? String(r.skill_name) : null,\n })),\n })\n }\n return null\n }\n\n private onContextEntry(\n payload: Record<string, unknown>,\n ): ProjectionUpdate[] | null {\n if (!isRecord(payload.entry)) return null\n const turn = buildContextTurn(payload.entry, this.nextSeq())\n return turn ? [{ kind: \"upsert\", turn }] : null\n }\n\n private onLoopTurn(\n loopId: string,\n payload: Record<string, unknown>,\n ): ProjectionUpdate[] {\n let turnId = String(payload.turn_id ?? this.nextTurnId(`turn:${loopId}`))\n let memoryRefs: MemoryRef[] | null = null\n\n // 记忆锚点只认它自己那一轮(和后端 `ProjectionBuilder._consume_memory_inject`\n // 同一套规则):memory:inject:done 带的 turn_id 就是本次 chat 首个模型回合的 id。\n // 无条件让「下一个 loop:turn」领走的话,首个模型回合之前插入的 turn(例如\n // @知识库 时系统发起的那次 kb_search 预检索)会被改写成同一个 id,随后真正的\n // 首轮回合按 id 替换,检索卡片就被回答覆盖了。老事件里 turn_id 可能为空,那时\n // 保留「下一个回合领走」的旧行为。\n const pending = this.pendingMemoryRefs.get(loopId)\n if (pending && (!pending.turnId || pending.turnId === turnId)) {\n this.pendingMemoryRefs.delete(loopId)\n if (pending.turnId) turnId = pending.turnId\n memoryRefs = pending.refs\n }\n\n const rawCw = payload.context_window\n const contextWindow =\n typeof rawCw === \"number\" && rawCw > 0 ? Math.trunc(rawCw) : 0\n\n const state = createTurnState(turnId, loopId, {\n model: optStr(payload.model),\n contextWindow,\n memoryRefs,\n })\n\n this.activeTurns.set(loopId, state)\n this.lastTurnIds.set(loopId, turnId)\n\n const turn = snapshot(state, this.nextSeq(), \"streaming\")\n this.latestTurns.set(loopId, turn)\n this.turnsById.set(turn.turn_id, turn)\n return [{ kind: \"upsert\", turn }]\n }\n\n private onModeChange(\n loopId: string,\n payload: Record<string, unknown>,\n ): ProjectionUpdate[] {\n const content: Record<string, string> = {}\n if (payload.from != null && payload.from !== \"\") content.from = String(payload.from)\n if (payload.to != null && payload.to !== \"\") content.to = String(payload.to)\n const turn = buildMarkerTurn(\n this.nextSeq(),\n this.nextTurnId(\"mode_change\"),\n loopId,\n \"mode_change\",\n content,\n )\n return [{ kind: \"upsert\", turn }]\n }\n\n private onPlanStatusUpdate(\n loopId: string,\n payload: Record<string, unknown>,\n ): ProjectionUpdate[] {\n let statuses = payload.statuses\n if (typeof statuses !== \"object\" || statuses === null) {\n statuses = payload._statuses ?? {}\n }\n const turn = buildMarkerTurn(\n this.nextSeq(),\n this.nextTurnId(\"plan_status\"),\n loopId,\n \"plan_status\",\n { plan_yaml: payload.plan_yaml ?? \"\", statuses },\n )\n return [{ kind: \"upsert\", turn }]\n }\n\n private onWorkspaceChanged(\n loopId: string,\n payload: Record<string, unknown>,\n ): ProjectionUpdate[] {\n const updates: ProjectionUpdate[] = [\n {\n kind: \"workspace_changed\",\n loopId,\n toolCallId: optStr(payload.tool_call_id) ?? undefined,\n toolName: toolNameFromPayload(payload) ?? undefined,\n workspacePath: isRecord(payload.workspace_change)\n ? optStr(payload.workspace_change.to) ?? undefined\n : undefined,\n },\n ]\n const change = payload.workspace_change\n if (isRecord(change)) {\n const source = optStr(change.source) ?? \"\"\n const projectName = optStr(change.project_name) ?? \"\"\n const fromPath = optStr(change.from) ?? \"\"\n const toPath = optStr(change.to) ?? \"\"\n const filesCopied =\n typeof change.files_copied === \"number\" ? change.files_copied : 0\n updates.unshift({\n kind: \"upsert\",\n turn: buildSystemNotificationTurn(\n this.nextSeq(),\n this.nextTurnId(\"workspace_change\"),\n loopId,\n \"workspace_change\",\n \"done\",\n source === \"cli:blade\" && projectName\n ? `项目「${projectName}」已创建`\n : \"工作目录已切换\",\n source === \"cli:blade\" && projectName\n ? `${filesCopied > 0 ? `已复制 ${filesCopied} 项当前文件。` : \"已原地使用当前文件夹。\"} 后续工作将在 ${toPath} 进行。`\n : `工作目录已从 ${fromPath} 切换到 ${toPath}。后续工作将在新目录进行。`,\n { ...change },\n ),\n })\n }\n const state = this.activeTurns.get(loopId)\n if (state) {\n const turn = snapshot(state, this.nextSeq(), \"streaming\")\n this.latestTurns.set(loopId, turn)\n this.lastTurnIds.set(loopId, turn.turn_id)\n updates.push({ kind: \"upsert\", turn })\n }\n return updates\n }\n\n private onAgentStart(\n loopId: string,\n payload: Record<string, unknown>,\n ): ProjectionUpdate[] {\n const description = optStr(payload.description)\n if (description) this.loopDescriptions.set(loopId, description)\n const subagentStartedAt = optStr(payload.started_at)\n if (subagentStartedAt) {\n this.activeSubagentRuns.set(loopId, {\n runId: optStr(payload.run_id) ?? loopId,\n startedAt: subagentStartedAt,\n })\n }\n const turn = buildSystemNotificationTurn(\n this.nextSeq(),\n this.nextTurnId(\"agent:start\"),\n loopId,\n \"agent:start\",\n \"running\",\n `Agent: ${payload.description ?? payload.skill_id ?? \"agent\"}`,\n optStr(payload.prompt),\n {\n skill_id: optStr(payload.skill_id),\n description: optStr(payload.description),\n parent_fork_tool_call_id: optStr(payload.parent_fork_tool_call_id),\n },\n )\n return [{ kind: \"upsert\", turn }]\n }\n\n private onBgStarted(\n loopId: string,\n payload: Record<string, unknown>,\n ): ProjectionUpdate[] {\n const taskId = optStr(payload.task_id) ?? \"\"\n const command = optStr(payload.command)\n const description = optStr(payload.description)\n const turn = buildSystemNotificationTurn(\n this.nextSeq(),\n this.nextTurnId(\"bg:started\"),\n loopId,\n \"bg:started\",\n \"running\",\n description ?? `Background: ${taskId || \"task\"}`,\n command,\n { task_id: taskId, command, description },\n )\n return [{ kind: \"upsert\", turn }]\n }\n\n private onBgTasksCompleted(\n loopId: string,\n payload: Record<string, unknown>,\n ): ProjectionUpdate[] {\n const taskIds = Array.isArray(payload.task_ids) ? payload.task_ids : []\n const count = typeof payload.count === \"number\" ? payload.count : taskIds.length\n const detail = taskIds.map(String).join(\", \")\n const turn = buildSystemNotificationTurn(\n this.nextSeq(),\n this.nextTurnId(\"bg:tasks_completed\"),\n loopId,\n \"bg:tasks_completed\",\n backgroundTaskStatus(payload),\n `Background tasks completed (${count})`,\n detail || null,\n { task_ids: taskIds, count },\n )\n return [{ kind: \"upsert\", turn }]\n }\n\n private onAskUserAnswer(\n loopId: string,\n payload: Record<string, unknown>,\n ): ProjectionUpdate[] {\n const toolCallId = String(payload.tool_call_id ?? \"\")\n const pending = this.pendingChildPauses.get(toolCallId)\n const parentLoopId = pending?.parentLoopName\n\n // clear child pause\n if (pending) {\n this.pendingChildPauses.delete(toolCallId)\n const childTurn =\n this.activeTurns.get(pending.childLoopName) ??\n this.latestTurns.get(pending.childLoopName)\n setToolCallStatus(childTurn, pending.childToolCallId, \"done\", null, null)\n const parentTurn =\n this.activeTurns.get(pending.parentLoopName) ??\n this.latestTurns.get(pending.parentLoopName)\n setToolCallStatus(parentTurn, pending.parentToolCallId, \"done\", null, null)\n }\n\n // clear direct ask-user pause\n const directTurn = this.activeTurns.get(loopId) ?? this.latestTurns.get(loopId)\n setToolCallStatus(directTurn, toolCallId, \"done\", null, null)\n\n const updates = this.collectLoopUpdates(loopId, parentLoopId)\n const entryId = typeof payload.entry_id === \"string\" ? payload.entry_id : \"\"\n if (!entryId) return updates\n const answerData = isRecord(payload.answer_data) ? payload.answer_data : {}\n const answerTurn: TurnProjection = {\n id: entryId,\n sequence: this.nextSeq(),\n turn_id: entryId,\n loop_id: loopId,\n kind: \"message\",\n role: \"assistant\",\n status: \"completed\",\n blocks: [\n {\n type: \"ask_user_answer\",\n content: answerData,\n tool_call_id: toolCallId || null,\n },\n ],\n tool_calls: [],\n model: null,\n usage: null,\n duration_ms: 0,\n client_request_id:\n typeof payload.client_request_id === \"string\" ? payload.client_request_id : null,\n }\n return [...updates, { kind: \"upsert\", turn: answerTurn }]\n }\n\n private onUserMessage(\n _loopId: string,\n payload: Record<string, unknown>,\n ): ProjectionUpdate[] {\n const entryId = String(payload.entry_id ?? this.nextTurnId(\"user\"))\n const displayContent = payload.display_content ?? payload.content ?? \"\"\n const turn: TurnProjection = {\n id: entryId,\n sequence: this.nextSeq(),\n turn_id: entryId,\n loop_id: \"root\",\n kind: \"message\",\n role: \"user\",\n status: \"completed\",\n blocks: [{ type: \"text\", content: displayContent }],\n tool_calls: [],\n model: null,\n usage: null,\n duration_ms: 0,\n client_request_id:\n typeof payload.client_request_id === \"string\" ? payload.client_request_id : null,\n }\n this.latestTurns.set(\"root\", turn)\n return [{ kind: \"upsert\", turn }]\n }\n\n private onPostChatFollowup(\n payload: Record<string, unknown>,\n ): ProjectionUpdate[] | null {\n const assistantEntryId = String(payload.assistant_entry_id ?? \"\")\n const latest = this.latestTurns.get(\"root\") as FollowupTurn | undefined\n if (\n !latest ||\n latest.role !== \"assistant\" ||\n latest.turn_id !== assistantEntryId\n ) {\n return null\n }\n\n const postChatFollowup = normalizePostChatFollowup(payload, assistantEntryId)\n if (!postChatFollowup) return null\n const turn: FollowupTurn = {\n ...latest,\n post_chat_followup: postChatFollowup,\n }\n this.latestTurns.set(\"root\", turn)\n return [{ kind: \"upsert\", turn }]\n }\n\n // --- Delta / streaming events ---\n\n private onDelta(\n state: TurnState,\n blockType: \"thinking\" | \"text\",\n _toolCallId: string,\n content: string,\n ): ProjectionUpdate[] | null {\n if (!content) return null\n appendTextBlock(state, blockType, content)\n return this.syncPatch(state)\n }\n\n private onToolCallCreated(\n state: TurnState,\n payload: Record<string, unknown>,\n ): ProjectionUpdate[] | null {\n // Compatibility with servers that used created for argument fragments.\n if (\"arguments_delta\" in payload) {\n return this.onToolCallArgumentsDelta(state, payload)\n }\n const toolCallId = String(payload.id ?? \"\")\n const toolName = toolNameFromPayload(payload)\n const displayName = String(payload.display_name ?? \"\") || this.displayNameResolver(toolName)\n const args = toolArgsFromPayload(payload)\n upsertToolCall(state, toolCallId, toolName, displayName, args)\n return this.syncPatch(state)\n }\n\n private onToolCallArgumentsDelta(\n state: TurnState,\n payload: Record<string, unknown>,\n ): ProjectionUpdate[] | null {\n const delta = String(payload.arguments_delta ?? \"\")\n const toolCallId = String(payload.id ?? \"\")\n if (!delta || !toolCallId) return null\n appendToolCallArguments(state, toolCallId, delta)\n return this.syncPatch(state)\n }\n\n private onResponseDone(\n state: TurnState,\n loopId: string,\n payload: Record<string, unknown>,\n ): ProjectionUpdate[] | null {\n state.responseDone = true\n this.applyStreamTiming(state, payload)\n const model = optStr(payload.model)\n if (model) state.model = model\n if (typeof payload.usage === \"object\" && payload.usage !== null) {\n state.usage = { ...(payload.usage as Record<string, unknown>) }\n }\n // apply tool calls from full response\n const toolCalls = payload.tool_calls\n if (Array.isArray(toolCalls)) {\n for (const raw of toolCalls) {\n if (typeof raw !== \"object\" || raw === null) continue\n const tc = raw as Record<string, unknown>\n const fn = (tc.function ?? {}) as Record<string, unknown>\n const toolName = String(fn.name ?? \"\")\n const displayName =\n String(tc.display_name ?? \"\") || this.displayNameResolver(toolName)\n upsertToolCall(\n state,\n String(tc.id ?? \"\"),\n toolName,\n displayName,\n String(fn.arguments ?? \"\"),\n )\n }\n }\n\n if (!applyResponseBlockOrder(state, payload.response_blocks) && \"content\" in payload) {\n replaceTextContent(state, completedResponseText(payload.content))\n }\n\n const isNativeProviderResponse = typeof payload.provider === \"string\" && payload.provider !== \"\"\n if (\n state.toolCalls.length === 0 ||\n (isNativeProviderResponse &&\n state.toolCalls.every(\n (toolCall) => toolCall.status !== \"pending\" && toolCall.status !== \"awaiting_answer\",\n ))\n ) {\n return this.finalize(loopId, \"completed\")\n }\n return this.syncPatch(state)\n }\n\n private applyFirstTokenDelivery(\n state: TurnState,\n payload: Record<string, unknown>,\n ): void {\n const firstTokenMs = payload.first_token_ms\n if (state.firstTokenMs === null && typeof firstTokenMs === \"number\" && firstTokenMs >= 0) {\n state.firstTokenMs = Math.round(firstTokenMs)\n }\n const duration = payload.first_token_delivery_ms\n if (state.firstTokenDeliveryMs === null && typeof duration === \"number\" && duration >= 0) {\n state.firstTokenDeliveryMs = duration\n }\n }\n\n private applyStreamTiming(\n state: TurnState,\n payload: Record<string, unknown>,\n ): void {\n if (typeof payload.first_token_ms === \"number\" && payload.first_token_ms >= 0) {\n state.firstTokenMs = Math.round(payload.first_token_ms)\n }\n if (\n typeof payload.stream_duration_ms === \"number\" &&\n payload.stream_duration_ms >= 0\n ) {\n state.streamDurationMs = Math.round(payload.stream_duration_ms)\n }\n // 只有生产者上报的真实请求区间才写进投影;缺失时保持 null(#2581 A1/I1)。\n if (typeof payload.started_at === \"string\" && payload.started_at) {\n state.modelStartedAt = payload.started_at\n state.modelStartedAtReported = true\n }\n if (typeof payload.duration_ms === \"number\" && payload.duration_ms >= 0) {\n state.modelDurationMs = Math.round(payload.duration_ms)\n }\n }\n\n private onToolResultDone(\n state: TurnState,\n loopId: string,\n payload: Record<string, unknown>,\n ): ProjectionUpdate[] | null {\n const toolCallId = String(payload.tool_call_id ?? \"\")\n const streamedResult = state.toolCalls.find((toolCall) => toolCall.id === toolCallId)?.result\n const content =\n payload.content_from_deltas === true ? (streamedResult ?? \"\") : payload.content ?? \"\"\n const status = toolStatusFromResult(content)\n const rawDuration = payload.duration_ms\n const durationMs =\n typeof rawDuration === \"number\" && rawDuration >= 0\n ? Math.round(rawDuration)\n : null\n const ranInParallel =\n typeof payload.ran_in_parallel === \"boolean\" ? payload.ran_in_parallel : null\n\n const sl = sourceLoopFor(state.loopId, this.loopDescriptions)\n const startedAt = typeof payload.started_at === \"string\" && payload.started_at ? payload.started_at : null\n applyToolResult(state, toolCallId, content, status, durationMs, ranInParallel, sl, startedAt)\n\n // Native providers may emit a completed tool item before the final text\n // item of the same turn. Their explicit llm:response:done is the terminal\n // event; finalizing here would drop the following content delta.\n const isNativeProviderResult = typeof payload.provider === \"string\" && payload.provider !== \"\"\n if (!isNativeProviderResult && this.shouldFinalizeAfterToolResults(state)) {\n return this.finalize(loopId, \"completed\")\n }\n return this.syncPatch(state)\n }\n\n private onToolResultDelta(\n state: TurnState,\n payload: Record<string, unknown>,\n ): ProjectionUpdate[] | null {\n appendToolResultDelta(\n state,\n String(payload.tool_call_id ?? \"\"),\n String(payload.content ?? \"\"),\n payload.content_reset === true,\n )\n return this.syncPatch(state)\n }\n\n private onToolUi(\n state: TurnState,\n payload: Record<string, unknown>,\n ): ProjectionUpdate[] | null {\n const toolCallId = String(payload.tool_call_id ?? \"\")\n const ui = payload.ui\n if (toolCallId && typeof ui === \"object\" && ui !== null) {\n state.blocks.push({\n type: \"tool_ui\",\n content: ui,\n tool_call_id: toolCallId,\n })\n }\n return this.syncPatch(state)\n }\n\n private onToolBridge(\n state: TurnState,\n payload: Record<string, unknown>,\n ): ProjectionUpdate[] | null {\n const bridge = payload.bridge\n if (typeof bridge !== \"object\" || bridge === null) return null\n const toolCallId = String(payload.tool_call_id ?? \"\")\n // A command without an owning tool call is still delivered by\n // AgentSession from the raw event, but it has no chat display projection.\n if (!toolCallId || !state.toolCalls.some((toolCall) => toolCall.id === toolCallId)) return null\n state.blocks.push({\n type: \"tool_bridge\",\n content: bridge,\n delivery_id: String(payload.delivery_id ?? \"\") || null,\n tool_call_id: toolCallId,\n })\n return this.syncPatch(state)\n }\n\n private onToolApprovalRequired(\n state: TurnState,\n payload: Record<string, unknown>,\n ): ProjectionUpdate[] | null {\n const toolCallId = String(payload.tool_call_id ?? \"\")\n const toolName = String(payload.tool_name ?? \"\")\n const displayName = this.displayNameResolver(toolName)\n upsertToolCall(state, toolCallId, toolName, displayName, \"\")\n const relatedToolCallId = String(payload.related_tool_call_id ?? \"\")\n if (relatedToolCallId && relatedToolCallId !== toolCallId) {\n const related = state.toolCalls.find((toolCall) => toolCall.id === relatedToolCallId)\n if (related) related.status = \"awaiting_answer\"\n }\n return this.syncPatch(state)\n }\n\n private onChildPause(\n state: TurnState,\n loopId: string,\n payload: Record<string, unknown>,\n ): ProjectionUpdate[] | null {\n const pauseToolData = payload.pause_tool_data\n if (typeof pauseToolData !== \"object\" || pauseToolData === null)\n return this.syncPatch(state)\n\n const ptd = pauseToolData as Record<string, unknown>\n const sourceLoop = ptd.source_loop as Record<string, unknown> | undefined\n if (typeof sourceLoop === \"object\" && sourceLoop) {\n const slName = String(sourceLoop.name ?? \"\")\n const slDesc = optStr(sourceLoop.description)\n if (slName && slDesc) this.loopDescriptions.set(slName, slDesc)\n }\n\n const { childLoopName, childToolCallId, description } =\n normalizeChildPause(payload as Record<string, unknown>)\n\n if (!childToolCallId) return this.syncPatch(state)\n\n const existing = this.pendingChildPauses.get(childToolCallId)\n const parentLoopName = String(\n payload.parent_loop_name ?? existing?.parentLoopName ?? \"root\",\n )\n const parentToolCallId = String(\n payload.parent_fork_tool_call_id ?? existing?.parentToolCallId ?? \"\",\n )\n const resolvedChildLoopName =\n String(payload.child_loop_name ?? \"\") || existing?.childLoopName || childLoopName || loopId\n\n this.pendingChildPauses.set(childToolCallId, {\n parentLoopName,\n parentToolCallId,\n childLoopName: resolvedChildLoopName,\n childToolCallId,\n description: description || existing?.description || \"\",\n })\n\n // apply to child\n applyAskUserPauseToTurn(\n state,\n ptd,\n childToolCallId,\n resolvedChildLoopName,\n this.pendingChildPauses.get(childToolCallId)!.description,\n this.displayNameResolver,\n )\n\n // apply to parent\n const parentTurn =\n this.activeTurns.get(parentLoopName) ?? this.latestTurns.get(parentLoopName)\n if (parentTurn) {\n applyChildPauseToParent(\n parentTurn,\n parentToolCallId,\n resolvedChildLoopName,\n childToolCallId,\n this.pendingChildPauses.get(childToolCallId)!.description,\n this.displayNameResolver,\n )\n }\n\n return this.collectLoopUpdates(loopId, parentLoopName)\n }\n\n private onChatEnd(\n state: TurnState,\n loopId: string,\n payload: Record<string, unknown>,\n ): ProjectionUpdate[] | null {\n const status = String(payload.status ?? \"completed\")\n\n const pauseToolData = payload.pause_tool_data\n if (typeof pauseToolData === \"object\" && pauseToolData !== null) {\n const ptd = pauseToolData as Record<string, unknown>\n const pauseToolName = String(ptd.name ?? \"\")\n const normalized = pauseToolName.includes(\":\")\n ? pauseToolName.split(\":\").pop()!\n : pauseToolName\n const sourceLoop = ptd.source_loop as Record<string, unknown> | undefined\n\n if (typeof sourceLoop === \"object\" && sourceLoop) {\n const slName = String(sourceLoop.name ?? \"\")\n const slDesc = optStr(sourceLoop.description)\n if (slName && slDesc) this.loopDescriptions.set(slName, slDesc)\n\n if (status === \"paused\" && slName) {\n applyChildPauseToParent(\n state,\n String(ptd.parent_fork_tool_call_id ?? \"\"),\n slName,\n String(ptd.tool_call_id ?? \"\"),\n slDesc ?? \"\",\n this.displayNameResolver,\n )\n\n const childTurn = this.activeTurns.get(slName)\n if (childTurn) {\n applyAskUserPauseToTurn(\n childTurn,\n ptd,\n String(ptd.tool_call_id ?? \"\"),\n slName,\n slDesc ?? \"\",\n this.displayNameResolver,\n )\n }\n }\n } else if (status === \"paused\" && normalized === \"AskUserQuestion\") {\n applyAskUserPauseToTurn(\n state,\n ptd,\n String(ptd.tool_call_id ?? \"\"),\n \"\",\n \"\",\n this.displayNameResolver,\n )\n }\n }\n\n const finalStatus = (\n { completed: \"completed\", paused: \"paused\", failed: \"failed\", interrupted: \"interrupted\" } as Record<string, TurnProjection[\"status\"]>\n )[status]\n\n if (!finalStatus) return null\n if (finalStatus === \"failed\") this.dropIncompleteToolCalls(state)\n if (!this.activeTurns.has(loopId)) {\n this.pendingMemoryRefs.delete(loopId)\n }\n return this.finalize(loopId, finalStatus)\n }\n\n private onAgentEnd(\n state: TurnState | null,\n loopId: string,\n payload: Record<string, unknown>,\n ): ProjectionUpdate[] | null {\n const ok = payload.ok !== false\n this.settleSubagentRun(loopId, payload)\n const status = ok ? \"done\" : \"error\"\n const title = `Agent: ${payload.description ?? payload.skill_id ?? \"agent\"}`\n const detail = optStr(payload.error)\n const metadata = {\n skill_id: optStr(payload.skill_id),\n description: optStr(payload.description),\n parent_fork_tool_call_id: optStr(payload.parent_fork_tool_call_id),\n ...(typeof payload.run_status === \"string\" ? { run_status: payload.run_status } : {}),\n ok,\n }\n if (state) {\n if (!ok) this.dropIncompleteToolCalls(state)\n state.blocks.push(buildSystemNotificationBlock(\"agent:end\", status, title, detail, metadata))\n return this.finalize(loopId, ok ? \"completed\" : \"failed\")\n }\n const turn = buildSystemNotificationTurn(\n this.nextSeq(), this.nextTurnId(\"agent:end\"), loopId, \"agent:end\", status, title, detail, metadata,\n )\n return [{ kind: \"upsert\", turn }]\n }\n\n private settleSubagentRun(\n loopId: string,\n payload: Record<string, unknown>,\n ): void {\n const active = this.activeSubagentRuns.get(loopId)\n this.activeSubagentRuns.delete(loopId)\n const parentToolCallId = optStr(payload.parent_fork_tool_call_id)\n if (!parentToolCallId) return\n const rawDuration = payload.run_duration_ms\n const durationMs =\n typeof rawDuration === \"number\" && rawDuration >= 0 ? Math.round(rawDuration) : null\n const rawStatus = optStr(payload.run_status)\n const status: RunTiming[\"status\"] =\n rawStatus === \"failed\" ||\n rawStatus === \"cancelled\" ||\n rawStatus === \"paused\" ||\n rawStatus === \"incomplete\"\n ? rawStatus\n : payload.ok === false\n ? \"failed\"\n : \"completed\"\n const run: RunTiming = {\n run_id: active?.runId ?? optStr(payload.run_id) ?? loopId,\n scope: \"subagent\",\n loop_id: loopId,\n started_at: active?.startedAt ?? optStr(payload.run_started_at),\n duration_ms: durationMs,\n status,\n }\n const seen = new Set<TurnProjection>()\n for (const turn of [...this.latestTurns.values(), ...this.turnsById.values()]) {\n if (seen.has(turn)) continue\n seen.add(turn)\n const toolCall = turn.tool_calls.find((item) => item.id === parentToolCallId)\n if (!toolCall) continue\n toolCall.subagent_runs = [...(toolCall.subagent_runs ?? []), run]\n }\n }\n\n private dropIncompleteToolCalls(state: TurnState): void {\n if (state.responseDone) return\n state.toolCalls = []\n state.blocks = state.blocks.filter((block) => block.type !== \"tool_use\")\n }\n\n private onCompaction(\n eventType: string,\n loopId: string,\n payload: Record<string, unknown>,\n ): ProjectionUpdate[] | null {\n const compactionId = String(payload.compaction_id ?? \"\")\n if (!compactionId) return null\n\n let current = {\n ...(this.activeCompactions.get(compactionId) ?? {}),\n ...payload,\n loop_id: loopId,\n }\n\n let status: TurnProjection[\"status\"]\n switch (eventType) {\n case \"compaction:start\":\n status = \"streaming\"\n this.activeCompactions.set(compactionId, current)\n this.failedCompactions.delete(compactionId)\n break\n case \"compaction:end\":\n status = \"completed\"\n this.activeCompactions.delete(compactionId)\n break\n case \"compaction:abort\":\n status = \"interrupted\"\n this.activeCompactions.delete(compactionId)\n break\n case \"compaction:error\":\n status = \"failed\"\n this.activeCompactions.delete(compactionId)\n this.failedCompactions.set(compactionId, { ...current })\n break\n default:\n status = \"streaming\"\n this.activeCompactions.set(compactionId, current)\n }\n\n // 降级为截断时 compaction:error 后面紧跟着 compaction:end,若让 end 覆盖,\n // 用户就再也看不到这次整理失败过。failed 是终态:同一个 compaction_id 一旦\n // 失败就保持失败,下一轮压缩是新的 compaction_id,不受影响。\n const failed = this.failedCompactions.get(compactionId)\n if (failed && status !== \"failed\") {\n current = { ...failed, ...current }\n status = \"failed\"\n }\n\n const turn = buildCompactionTurn(this.nextSeq(), compactionId, loopId, status, current)\n return [{ kind: \"upsert\", turn }]\n }\n\n // --- Internal helpers ---\n\n private syncPatch(state: TurnState): ProjectionUpdate[] {\n const turn = snapshot(state, this.nextSeq(), \"streaming\")\n this.latestTurns.set(state.loopId, turn)\n this.turnsById.set(turn.turn_id, turn)\n this.lastTurnIds.set(state.loopId, turn.turn_id)\n return [{ kind: \"upsert\", turn }]\n }\n\n private finalize(\n loopId: string,\n status: TurnProjection[\"status\"],\n ): ProjectionUpdate[] | null {\n const state = this.activeTurns.get(loopId)\n if (!state) return null\n this.activeTurns.delete(loopId)\n const turn = snapshot(state, this.nextSeq(), status)\n this.lastTurnIds.set(loopId, turn.turn_id)\n this.latestTurns.set(loopId, turn)\n this.turnsById.set(turn.turn_id, turn)\n return [{ kind: \"upsert\", turn }]\n }\n\n private shouldFinalizeAfterToolResults(state: TurnState): boolean {\n if (state.toolCalls.length === 0) return true\n if (state.toolCalls.some((tc) => tc.status === \"pending\")) return false\n return !state.toolCalls.some((tc) => {\n const normalized = tc.tool_name.includes(\":\")\n ? tc.tool_name.split(\":\").pop()!\n : tc.tool_name\n return PAUSE_TOOL_NAMES.has(normalized)\n })\n }\n\n private collectLoopUpdates(\n ...loopIds: (string | undefined | null)[]\n ): ProjectionUpdate[] {\n const updates: ProjectionUpdate[] = []\n for (const loopId of loopIds) {\n if (!loopId) continue\n const state = this.activeTurns.get(loopId)\n if (state) {\n updates.push(...this.syncPatch(state))\n continue\n }\n const proj = this.latestTurns.get(loopId)\n if (proj) {\n const updated = { ...proj, sequence: this.nextSeq() }\n this.latestTurns.set(loopId, updated)\n updates.push({ kind: \"upsert\", turn: updated })\n }\n }\n return updates\n }\n\n private nextSeq(): number {\n return ++this.seq\n }\n\n private nextTurnId(prefix: string): string {\n this.syntheticCounter++\n const hex = Math.random().toString(16).slice(2, 10)\n return `${prefix}:${this.syntheticCounter}:${hex}`\n }\n}\n\n// --- Utility functions ---\n\nfunction optStr(value: unknown): string | null {\n if (value == null || value === \"\") return null\n return String(value)\n}\n\nfunction toolNameFromPayload(payload: Record<string, unknown>): string {\n const fn = payload.function\n if (typeof fn === \"object\" && fn !== null) {\n return String((fn as Record<string, unknown>).name ?? \"\")\n }\n return String(payload.tool_name ?? \"\")\n}\n\nfunction toolArgsFromPayload(payload: Record<string, unknown>): string {\n const fn = payload.function\n if (typeof fn === \"object\" && fn !== null) {\n return String((fn as Record<string, unknown>).arguments ?? \"\")\n }\n return \"\"\n}\n","import type {\n ContentBlock,\n RunTiming,\n ToolCallProjection,\n TurnProjection,\n} from \"../../schemas/projection\"\nimport { inferToolStatus } from \"../../schemas/message\"\nimport { buildContextTurn } from \"./context\"\nimport { isRecord } from \"../type-guards\"\nimport {\n applyAskUserPauseToTurn,\n applyChildPauseToParent,\n buildCompactionTurn,\n buildSystemNotificationTurn,\n normalizePostChatFollowup,\n setToolCallStatus,\n} from \"./helpers\"\n\nexport interface RawHistoryEntry {\n id?: string\n kind?: string\n loop_name?: string\n message?: Record<string, unknown>\n source?: Record<string, unknown>\n data?: Record<string, unknown>\n timestamp?: string\n [key: string]: unknown\n}\n\ntype FollowupTurn = TurnProjection\n\n/** Rebuild completed UI turns from raw persisted history entries. */\nexport function projectHistory(entries: RawHistoryEntry[]): TurnProjection[] {\n const turns: TurnProjection[] = []\n const toolOwners = new Map<string, TurnProjection>()\n const latestAssistantByLoop = new Map<string, TurnProjection>()\n const pendingChildPauses = new Map<\n string,\n { childLoopId: string; parentLoopId: string; parentToolCallId: string }\n >()\n const answeredToolCallIds = new Set<string>()\n // Native daemon providers persist their tool item and final assistant text\n // as separate history entries. Keep track of those tool-item turns so the\n // refresh projection can restore the same assistant turn shown by the live\n // event stream.\n const nativeToolTurns = new Set<TurnProjection>()\n const turnEntryAliases = new Map<string, TurnProjection>()\n let latestRootMessage: FollowupTurn | null = null\n // root loop 最后一条 assistant turn,用于收尾时恢复未作答的提问。\n // 用户发言会清空它:此时提问已经被文字回复带过去了,不该再变回可作答。\n let latestRootAssistant: TurnProjection | null = null\n let sequence = 0\n\n for (const entry of entries) {\n const kind = String(entry.kind ?? \"\")\n const loopId = String(entry.loop_name ?? \"root\")\n const id = String(entry.id ?? `history-${sequence + 1}`)\n if (kind === \"turn_timing\" && isRecord(entry.data)) {\n const turnId = typeof entry.data.turn_id === \"string\" ? entry.data.turn_id : \"\"\n const duration = numberOrNull(entry.data.first_token_delivery_ms)\n const target = turnEntryAliases.get(turnId)\n if (target && duration !== null) target.first_token_delivery_ms = duration\n continue\n }\n if (kind === \"run_timing\" && isRecord(entry.data)) {\n const data = entry.data\n // 子运行区间挂在父工具调用上,仅作外层展示;用户轮区间只供统计折叠使用。\n if (data.scope === \"subagent\") {\n const parentToolCallId = String(data.parent_fork_tool_call_id ?? \"\")\n const duration = numberOrNull(data.duration_ms)\n const rawStatus = String(data.status ?? \"completed\")\n const status: RunTiming[\"status\"] =\n rawStatus === \"failed\" ||\n rawStatus === \"cancelled\" ||\n rawStatus === \"paused\" ||\n rawStatus === \"incomplete\"\n ? rawStatus\n : \"completed\"\n for (const turn of turns) {\n const toolCall = turn.tool_calls.find((item) => item.id === parentToolCallId)\n if (!toolCall) continue\n toolCall.subagent_runs = [\n ...(toolCall.subagent_runs ?? []),\n {\n run_id: String(data.run_id ?? \"\"),\n scope: \"subagent\",\n loop_id: loopId,\n started_at:\n typeof data.started_at === \"string\" ? data.started_at : null,\n duration_ms: duration,\n status,\n },\n ]\n break\n }\n }\n continue\n }\n if (kind === \"post_chat_followup\" && isRecord(entry.data)) {\n const assistantEntryId = String(entry.data.assistant_entry_id ?? \"\")\n if (\n latestRootMessage?.role === \"assistant\" &&\n latestRootMessage.turn_id === assistantEntryId\n ) {\n const followup = normalizePostChatFollowup(entry.data, assistantEntryId)\n if (followup) latestRootMessage.post_chat_followup = followup\n }\n continue\n }\n if (kind === \"context\") {\n const turn = buildContextTurn(entry, sequence + 1)\n if (turn) {\n sequence += 1\n turns.push(turn)\n }\n continue\n }\n if (kind === \"message\" && isRecord(entry.message)) {\n const message = entry.message\n const role = String(message.role ?? \"\")\n if (role === \"tool\") {\n const toolCallId = String(message.tool_call_id ?? \"\")\n const owner = toolOwners.get(toolCallId)\n const toolCall = owner?.tool_calls.find((item) => item.id === toolCallId)\n if (owner && toolCall) {\n toolCall.status = message._error\n ? \"error\"\n : inferToolStatus(String(message.content ?? \"\"))\n toolCall.result = message.content ?? \"\"\n const duration = numberOrNull(message._duration_ms)\n if (duration !== null) toolCall.duration_ms = duration\n if (typeof message._started_at === \"string\") {\n toolCall.started_at = message._started_at\n }\n if (message._ran_in_parallel === true) toolCall.ran_in_parallel = true\n owner.blocks.push({\n type: \"tool_result\",\n content: message.content ?? \"\",\n tool_call_id: toolCallId,\n })\n }\n continue\n }\n if (role !== \"user\" && role !== \"assistant\" && role !== \"system\") continue\n\n // _error 只属于 LLM 断流时保存的部分 assistant 消息,里面的\n // canonical tool_calls 可能仍是半截参数。和 live chat:end failed\n // 保持一致,不把它们恢复成待执行工具;正文、reasoning 和耗时仍保留。\n const toolCalls = role === \"assistant\" && !message._error\n ? buildToolCalls(message.tool_calls)\n : []\n const blocks = buildBlocks(message, toolCalls)\n const turn: FollowupTurn = {\n id,\n sequence: ++sequence,\n turn_id: id,\n loop_id: loopId,\n kind: \"message\",\n role,\n status: message._error\n ? \"failed\"\n : message._interrupted\n ? \"interrupted\"\n : \"completed\",\n blocks,\n tool_calls: toolCalls,\n model: stringOrNull(message.model),\n usage: isRecord(message._usage) ? { ...message._usage } : null,\n // 模型请求区间来自持久化字段;旧会话缺失时为 null,不用落盘时刻冒充(#2581 A1)。\n duration_ms: numberOrNull(message._duration_ms),\n first_token_ms: numberOrNull(message._first_token_ms),\n stream_duration_ms: numberOrNull(message._stream_duration_ms),\n started_at:\n typeof message._started_at === \"string\"\n ? message._started_at\n : typeof entry.timestamp === \"string\"\n ? entry.timestamp\n : undefined,\n has_reported_timing: typeof message._started_at === \"string\",\n // fork 子会话的父锚点:历史里落在消息级 _parent_fork_tool_call_id。丢掉它,\n // 刷新后工作流步骤 fork 就配不回 workflow:run 工具调用(普通 Agent fork 有\n // root Agent 工具调用兜底配对,工作流 fork 没有,子智能体卡会整体消失)。\n parent_fork_tool_call_id: stringOrNull(message._parent_fork_tool_call_id),\n }\n\n const isNativeToolEntry =\n role === \"assistant\" &&\n Array.isArray(message.tool_calls) &&\n message.tool_calls.some(\n (toolCall) => isRecord(toolCall) && typeof toolCall.provider === \"string\",\n )\n const previousTurn = turns[turns.length - 1]\n if (\n role === \"assistant\" &&\n previousTurn?.role === \"assistant\" &&\n previousTurn.loop_id === loopId &&\n nativeToolTurns.has(previousTurn)\n ) {\n nativeToolTurns.delete(previousTurn)\n previousTurn.blocks.push(...turn.blocks)\n previousTurn.tool_calls.push(...turn.tool_calls)\n previousTurn.status = turn.status\n previousTurn.model = turn.model ?? previousTurn.model\n previousTurn.usage = turn.usage ?? previousTurn.usage\n // 与 Python 侧 build_turns_from_history 的折叠规则保持一致,否则流式与\n // 历史会给出不同的时长和起点。时长用「非空且非 0 才覆盖」,Python/Go 的\n // `or` 语义如此,`??` 会让一个已测量的 0ms 覆盖掉真实时长。\n if (turn.duration_ms) previousTurn.duration_ms = turn.duration_ms\n previousTurn.first_token_ms = turn.first_token_ms ?? previousTurn.first_token_ms\n previousTurn.stream_duration_ms =\n turn.stream_duration_ms ?? previousTurn.stream_duration_ms\n // 起点优先取生产者上报的真实值;先到的条目可能只有落盘回落。\n if (turn.has_reported_timing) {\n previousTurn.started_at = turn.started_at\n previousTurn.has_reported_timing = true\n } else if (!previousTurn.has_reported_timing) {\n previousTurn.started_at = previousTurn.started_at ?? turn.started_at\n }\n // A folded native turn is identified by its terminal persisted entry,\n // matching post-chat follow-up and feedback keys. Earlier entry IDs\n // stay private aliases for annotations such as turn timing.\n previousTurn.id = turn.id\n previousTurn.turn_id = turn.turn_id\n if (isNativeToolEntry) nativeToolTurns.add(previousTurn)\n turnEntryAliases.set(id, previousTurn)\n if (loopId === \"root\") latestRootMessage = previousTurn as FollowupTurn\n latestAssistantByLoop.set(loopId, previousTurn)\n continue\n }\n\n if (\n loopId === \"root\" &&\n (role === \"user\" || role === \"assistant\")\n ) {\n latestRootMessage = turn\n }\n turns.push(turn)\n turnEntryAliases.set(id, turn)\n if (isNativeToolEntry) nativeToolTurns.add(turn)\n if (role === \"assistant\") latestAssistantByLoop.set(loopId, turn)\n if (loopId === \"root\") {\n if (role === \"assistant\") latestRootAssistant = turn\n else if (role === \"user\") latestRootAssistant = null\n }\n for (const toolCall of toolCalls) toolOwners.set(toolCall.id, turn)\n continue\n }\n\n if (kind === \"tool_result\") {\n const data = entry.data ?? {}\n const toolCallId = String(data.tool_call_id ?? \"\")\n const owner = toolOwners.get(toolCallId) ?? findLatestAssistant(turns, loopId)\n if (owner && toolCallId) {\n const rawContent = data.content\n const content =\n typeof rawContent === \"string\"\n ? rawContent\n : Array.isArray(rawContent)\n ? rawContent\n : String(rawContent ?? \"\")\n const status = data.is_error === true\n ? \"error\"\n : inferToolStatus(typeof content === \"string\" ? content : JSON.stringify(content))\n setToolCallStatus(owner, toolCallId, status, content, null)\n if (!owner.blocks.some((block) => block.type === \"tool_result\" && block.tool_call_id === toolCallId)) {\n owner.blocks.push({ type: \"tool_result\", content, tool_call_id: toolCallId })\n }\n }\n continue\n }\n\n if (kind === \"mode_change\") {\n turns.push(markerTurn(id, ++sequence, loopId, \"mode_change\", entry.data ?? {}))\n } else if (kind === \"workspace_change\") {\n const change = isRecord(entry.data) ? entry.data : {}\n const source = stringOrNull(change.source) ?? \"\"\n const projectName = stringOrNull(change.project_name) ?? \"\"\n const fromPath = stringOrNull(change.from) ?? \"\"\n const toPath = stringOrNull(change.to) ?? \"\"\n const filesCopied =\n typeof change.files_copied === \"number\" ? change.files_copied : 0\n turns.push(\n buildSystemNotificationTurn(\n ++sequence,\n id,\n loopId,\n \"workspace_change\",\n \"done\",\n source === \"cli:blade\" && projectName\n ? `项目「${projectName}」已创建`\n : \"工作目录已切换\",\n source === \"cli:blade\" && projectName\n ? `${filesCopied > 0 ? `已复制 ${filesCopied} 项当前文件。` : \"已原地使用当前文件夹。\"} 后续工作将在 ${toPath} 进行。`\n : `工作目录已从 ${fromPath} 切换到 ${toPath}。后续工作将在新目录进行。`,\n { ...change },\n ),\n )\n } else if (kind === \"plan_status\") {\n const data = entry.data ?? {}\n turns.push(\n markerTurn(id, ++sequence, loopId, \"plan_status\", {\n plan_yaml: data.plan_yaml ?? \"\",\n statuses: data.statuses ?? data._statuses ?? {},\n }),\n )\n } else if (kind === \"tool_ui\" || kind === \"tool_bridge\") {\n const data = entry.data ?? {}\n const toolCallId = String(data.tool_call_id ?? \"\")\n // Standalone bridge commands have no display owner. They are restored\n // through the command log and must not be attached to an unrelated\n // latest assistant turn merely because it happens to be nearby.\n const owner = kind === \"tool_bridge\"\n ? (toolCallId ? toolOwners.get(toolCallId) : undefined)\n : toolOwners.get(toolCallId) ?? findLatestAssistant(turns, loopId)\n const rawContent = kind === \"tool_ui\" ? data.ui : data.bridge\n // History is a pure replay: archived HTML may be rendered again, but a\n // resource URI must never trigger a fresh MCP/resource fetch on refresh.\n const content = kind === \"tool_ui\" && isRecord(rawContent)\n ? { ...rawContent, archived: true }\n : rawContent\n if (owner && content !== undefined) {\n owner.blocks.push({\n type: kind,\n content,\n ...(kind === \"tool_bridge\" ? { delivery_id: id } : {}),\n tool_call_id: toolCallId || null,\n })\n }\n } else if (kind === \"compaction\" || kind === \"tool_result_archive\") {\n const data = entry.data ?? {}\n const compactionId = String(data.compaction_id ?? entry.id ?? `history-${sequence + 1}`)\n let content = isRecord(entry.message) ? entry.message.content : undefined\n if (kind === \"tool_result_archive\") {\n const archivedCount = Array.isArray(data.archived_files) ? data.archived_files.length : 0\n content = `<compaction-summary>\\n已归档 ${archivedCount} 个大型工具结果。\\n</compaction-summary>`\n }\n turns.push(\n buildCompactionTurn(++sequence, compactionId, loopId,\n data.status === \"failed\" ? \"failed\" : \"completed\", {\n ...data,\n content,\n }),\n )\n } else if (kind === \"child_pause\") {\n const data = entry.data ?? {}\n const sourceLoop = isRecord(data.source_loop) ? data.source_loop : {}\n const childLoopId = String(data.child_loop_name ?? sourceLoop.name ?? \"\")\n const childToolCallId = String(data.child_pause_tool_call_id ?? \"\")\n const parentToolCallId = String(data.parent_fork_tool_call_id ?? \"\")\n const pauseToolData = isRecord(data.pause_tool_data) ? data.pause_tool_data : {}\n const description = String(sourceLoop.description ?? \"\")\n applyAskUserPauseToTurn(\n latestAssistantByLoop.get(childLoopId),\n pauseToolData,\n childToolCallId,\n childLoopId,\n description,\n (name) => name,\n )\n applyChildPauseToParent(\n latestAssistantByLoop.get(loopId),\n parentToolCallId,\n childLoopId,\n childToolCallId,\n description,\n (name) => name,\n )\n if (childToolCallId) {\n pendingChildPauses.set(childToolCallId, {\n childLoopId,\n parentLoopId: loopId,\n parentToolCallId,\n })\n }\n } else if (kind === \"ask_user_answer\") {\n const data = entry.data ?? {}\n const toolCallId = String(data.tool_call_id ?? \"\")\n if (toolCallId) answeredToolCallIds.add(toolCallId)\n const pending = pendingChildPauses.get(toolCallId)\n if (pending) {\n setToolCallStatus(latestAssistantByLoop.get(pending.childLoopId), toolCallId, \"done\", null, null)\n setToolCallStatus(\n latestAssistantByLoop.get(pending.parentLoopId),\n pending.parentToolCallId,\n \"done\",\n null,\n null,\n )\n pendingChildPauses.delete(toolCallId)\n } else {\n setToolCallStatus(latestAssistantByLoop.get(loopId), toolCallId, \"done\", null, null)\n }\n turns.push(\n markerTurn(\n id,\n ++sequence,\n loopId,\n \"ask_user_answer\",\n data,\n toolCallId || null,\n ),\n )\n }\n }\n\n // AskUserQuestion 暂停时历史里会留下一条 tool 结果消息,重建时被 inferToolStatus 判成 done。\n // 未作答的提问必须还原成 awaiting_answer,否则卡片渲染成已作答、选项点不动。\n // 与后端 _history_dispatch.py 的 build_turns_from_history 收尾保持一致——两边算不出同一个\n // 结果时,流式刚置好的状态会在 chat:end 拉历史时被覆盖掉。\n const rootAssistant = latestRootAssistant\n if (rootAssistant) {\n for (const toolCall of rootAssistant.tool_calls) {\n if (answeredToolCallIds.has(toolCall.id)) continue\n if (toolCall.tool_name.split(\":\").pop() !== \"AskUserQuestion\") continue\n if (toolCall.status === \"error\" || toolCall.status === \"cancelled\") continue\n const pauseArguments = parseToolArguments(toolCall.arguments)\n if (typeof toolCall.result === \"string\") {\n const resultArguments = parseToolArguments(toolCall.result)\n if (Array.isArray(resultArguments.questions)) {\n pauseArguments.questions = resultArguments.questions\n }\n }\n applyAskUserPauseToTurn(\n rootAssistant,\n {\n name: toolCall.tool_name,\n tool_call_id: toolCall.id,\n arguments: pauseArguments,\n },\n toolCall.id,\n \"\",\n \"\",\n (name) => name,\n )\n }\n }\n\n return turns\n}\n\nfunction parseToolArguments(value: string): Record<string, unknown> {\n if (!value) return {}\n try {\n const parsed = JSON.parse(value)\n return isRecord(parsed) ? parsed : {}\n } catch {\n return {}\n }\n}\n\nfunction buildToolCalls(value: unknown): ToolCallProjection[] {\n if (!Array.isArray(value)) return []\n return value.filter(isRecord).map((raw) => {\n const fn = isRecord(raw.function) ? raw.function : {}\n const name = String(fn.name ?? \"\")\n return {\n id: String(raw.id ?? \"\"),\n tool_name: name,\n display_name: String(raw.display_name ?? name),\n arguments: typeof fn.arguments === \"string\" ? fn.arguments : JSON.stringify(fn.arguments ?? {}),\n status: \"running\",\n result: null,\n }\n })\n}\n\nfunction buildBlocks(\n message: Record<string, unknown>,\n toolCalls: ToolCallProjection[],\n): ContentBlock[] {\n // 平台注入的用户消息(如 Factory 项目初始化指引)会带 _display_content:\n // 完整指令给 LLM,用户只看展示文案。缺了这条会把内部提醒整段泄露到聊天区。\n const displayContent = message.role === \"user\" ? message._display_content : undefined\n const stored = message._blocks\n const blocks: ContentBlock[] = []\n const storedToolCallIds = new Set<string>()\n if (displayContent !== undefined) {\n blocks.push({ type: \"text\", content: displayContent })\n } else if (Array.isArray(stored)) {\n for (const raw of stored) {\n if (!isRecord(raw)) continue\n const type = String(raw.type ?? \"\")\n if (type === \"thinking\") blocks.push({ type, content: raw.thinking ?? raw.content ?? \"\" })\n if (type === \"text\") blocks.push({ type, content: raw.text ?? raw.content ?? \"\" })\n if (type === \"tool_call\") {\n const toolCallId = String(raw.id ?? \"\")\n const toolCall = toolCalls.find((candidate) => candidate.id === toolCallId)\n if (!toolCall) continue\n storedToolCallIds.add(toolCallId)\n blocks.push({\n type: \"tool_use\",\n content: toolCall.arguments,\n tool_call_id: toolCall.id,\n tool_name: toolCall.tool_name,\n display_name: toolCall.display_name,\n })\n }\n }\n } else if (message.content !== undefined && message.content !== \"\") {\n blocks.push({ type: \"text\", content: message.content })\n }\n for (const toolCall of toolCalls) {\n if (storedToolCallIds.has(toolCall.id)) continue\n blocks.push({\n type: \"tool_use\",\n content: toolCall.arguments,\n tool_call_id: toolCall.id,\n tool_name: toolCall.tool_name,\n display_name: toolCall.display_name,\n })\n }\n return blocks\n}\n\nfunction markerTurn(\n id: string,\n sequence: number,\n loopId: string,\n type: \"mode_change\" | \"plan_status\" | \"ask_user_answer\",\n content: Record<string, unknown>,\n toolCallId: string | null = null,\n): TurnProjection {\n return {\n id,\n sequence,\n turn_id: id,\n loop_id: loopId,\n kind: type as TurnProjection[\"kind\"],\n role: \"system\",\n status: \"completed\",\n blocks: [{ type, content, tool_call_id: toolCallId }],\n tool_calls: [],\n model: null,\n usage: null,\n duration_ms: 0,\n }\n}\n\nfunction stringOrNull(value: unknown): string | null {\n return typeof value === \"string\" ? value : null\n}\n\nfunction numberOrNull(value: unknown): number | null {\n return typeof value === \"number\" && value >= 0 ? value : null\n}\n\nfunction findLatestAssistant(\n turns: TurnProjection[],\n loopId: string,\n): TurnProjection | undefined {\n for (let index = turns.length - 1; index >= 0; index -= 1) {\n const turn = turns[index]\n if (turn?.role === \"assistant\" && turn.loop_id === loopId) return turn\n }\n return undefined\n}\n","import type { BackgroundTask, BackgroundTaskStopResult } from \"../schemas/background\"\nimport type { TurnProjection } from \"../schemas/projection\"\nimport type { McpAppArchive } from \"../schemas/mcp-app\"\nimport { DEFAULT_REPLAY_SPEED } from \"../schemas/session\"\nimport type {\n PublishedSolutionRef,\n ReplayPreview,\n ReplaySpeed,\n SessionDetail,\n SessionInfo,\n TemplateId,\n} from \"../schemas/session\"\nimport type {\n McpAppContextState,\n McpAppContextUpdate,\n} from \"../schemas/mcp-app\"\nimport type { Task } from \"../schemas/task\"\nimport type { BladeClient, UploadProgress } from \"../blade-client\"\nimport type { AgentSession } from \"../session/agent-session\"\nimport {\n SessionSetupError,\n type SessionDefinition,\n type SkillDefinition,\n type SolutionDefinition,\n} from \"../session/definition\"\nimport type { SessionProfile } from \"../types/sdk-profile\"\nimport { projectHistory, type RawHistoryEntry } from \"../shared/projection\"\n\nexport interface SessionPlugin {\n /** Technical ID: always used for paths, authorization, caching and calls. */\n name: string\n /** Business name declared by the package; null falls back to `name`. */\n display_name?: string | null\n /**\n * Opaque content token for the package-local icon, or null when the plugin\n * ships none. Pass it to `fetchSessionPluginIcon`; never used as a path.\n */\n icon?: string | null\n /** Whether BH lists this plugin for the current user; null means BH was unavailable. */\n installed: boolean | null\n /**\n * Configuration standing as the list could determine it without reading the\n * user's Home: `unchecked` means nobody has looked yet, never \"configured\".\n */\n config?: SessionPluginConfigSummary\n /** Persisted session choice, independent of preparation success. */\n active: boolean\n /** Previously prepared skills may remain after deselection. */\n projected: boolean\n projection_source?: string | null\n status: string\n reason?: string | null\n}\n\n/** Selection/preparation result; installed facts are obtained from the BH-backed list. */\nexport type SessionPluginActivation = Pick<SessionPlugin, \"name\" | \"active\" | \"status\" | \"reason\">\n\n/**\n * How a plugin's user configuration stands.\n *\n * `not_required` — the package ships no config schema, the plugin keeps its old\n * behaviour. `required` — a schema exists but the stored configuration is\n * missing or does not validate. `configured` — stored configuration validates.\n * `error` — the declaration itself is unusable.\n */\nexport type SessionPluginConfigStateName = \"not_required\" | \"required\" | \"configured\" | \"error\"\n\n/** List-level view: `unchecked` means nobody has read this user's file yet. */\nexport type SessionPluginConfigSummary =\n | SessionPluginConfigStateName\n | \"unchecked\"\n\nexport interface SessionPluginConfigError {\n /** JSON Pointer of the offending field. */\n path: string\n /** Value-free message; the platform never echoes submitted secrets. */\n message: string\n}\n\nexport interface SessionPluginConfigState {\n state: SessionPluginConfigStateName\n reason: string | null\n /** The package-declared JSON Schema (Draft 2020-12), or null. */\n schema: Record<string, unknown> | null\n /** Stored values with `writeOnly` properties removed. */\n values: Record<string, unknown>\n /** JSON Pointers of `writeOnly` properties that currently hold a value. */\n write_only: string[]\n /** Opaque revision for optimistic concurrency; null when nothing is stored. */\n revision: string | null\n errors: SessionPluginConfigError[]\n}\n\nexport interface SessionPluginConfigSet {\n /** JSON Pointer; arrays are replaced as a whole. */\n path: string\n value: unknown\n}\n\nexport interface SessionPluginConfigUpdate {\n /** Omit (or pass null) to publish unconditionally. */\n expected_revision?: string | null\n set?: SessionPluginConfigSet[]\n remove?: string[]\n}\n\nexport interface CreateSessionRequest {\n intent?: string\n template_id?: TemplateId\n /** 正式 Solution 来源。Hub 使用 { source: \"hub\", org, name }。 */\n solution_ref?: PublishedSolutionRef\n /** @deprecated 请使用结构化的 solution_ref;继续支持以保证现有 SDK 调用无感升级。 */\n solution_id?: string\n /** 从已有会话复制其不可变 Solution 与 Skill 运行快照。 */\n solution_snapshot_session_id?: string\n biz_role_id?: string | null\n primary_skill_id?: string | null\n model?: string | null\n enable_thinking?: boolean | null\n memory_enabled?: boolean | null\n env?: Record<string, string>\n disable_tools?: string[] | null\n session_solution_asset_id?: string | null\n compaction_ratio?: number | null\n runtime_type?: \"sandbox\" | \"daemon\" | \"native\" | null\n daemon_id?: string | null\n /** runtime_type 为 \"native\" 时必填:daemon 上要用哪个原生智能体(如 rt_codex)。 */\n agent_runtime_id?: string | null\n chat_group_id?: string | null\n}\n\nexport interface CheckpointNode {\n id: string\n parent_id: string | null\n content_preview: string\n content: string\n timestamp: string\n}\n\nexport type ContentPart =\n | { type: \"text\"; text: string }\n | { type: \"image_url\"; image_url: { url: string; detail?: string } }\n\nexport interface HistoryNode {\n id: string\n parent_id: string | null\n kind: string\n role: string\n timestamp: string\n preview: string\n content: string | ContentPart[]\n tool_calls: Array<{\n id?: string\n type?: string\n function?: { name?: string; arguments?: string }\n }> | null\n usage: { prompt_tokens?: number; completion_tokens?: number; total_tokens?: number } | null\n total_tokens: number\n token_diff: number\n is_deprecated: boolean\n loop_name: string\n}\n\nexport interface SessionHistory {\n nodes: HistoryNode[]\n active_branch: string | null\n branches: string[]\n system_prompt_tokens?: number | null\n tools_tokens?: number | null\n tokenizer_model?: string | null\n}\n\nexport interface TokenizeResult {\n model: string\n prompt_tokens: number\n prompt: string\n}\n\nexport interface PaginatedSessionsResult {\n items: SessionInfo[]\n total: number\n limit: number\n offset: number\n content_match_truncated?: boolean\n}\n\nexport interface GlobalSearchConversationResult {\n type: \"conversation\"\n session: SessionInfo\n snippet: string\n matched: \"title\" | \"content\"\n}\n\nexport interface GlobalSearchFileResult {\n type: \"file\"\n session: SessionInfo\n path: string\n name: string\n snippet: string\n matched: \"name\" | \"path\"\n}\n\nexport type GlobalSearchResultItem =\n | GlobalSearchConversationResult\n | GlobalSearchFileResult\n\nexport interface GlobalSearchResult {\n items: GlobalSearchResultItem[]\n truncated: boolean\n indexing: boolean\n}\n\ninterface ListSessionsPageParams {\n limit: number\n offset: number\n template_id_prefix?: string\n solution_id?: string\n solution_registry_id?: string\n q?: string\n chat_group_id?: string\n}\n\nexport interface SkillDevSession {\n session: SessionInfo\n skill_id: string\n display_name: string\n skill_description: string\n}\n\nexport interface ShareLinkResult {\n token: string\n url: string\n expires_at: string | null\n}\n\nexport interface SessionContextStats {\n tokens_used: number\n context_window: number\n compaction_ratio: number\n}\n\nexport interface SessionTurnsPage {\n turns: TurnProjection[]\n nextBefore: string | null\n currentMode: \"planning\" | \"executing\"\n}\n\n/** `getSessionTurnsPage` 的取数参数:向后翻页(before)或从某条发言定位(fromEntryId)。 */\nexport interface SessionTurnsQuery {\n limit?: number\n before?: string\n /**\n * 从这条用户发言开始、一直到最新。服务端按当前分支校验它,命中不了不会回空页\n * (`entry_not_found` / `entry_not_in_branch`),窗口首条就是这条发言,它的\n * `nextBefore` 可以继续当 `before` 往上翻。\n */\n fromEntryId?: string\n}\n\n/**\n * 服务端明确说这条发言不在当前分支上(`entry_not_found` / `entry_not_in_branch`),\n * 和\"这次没取到\"(网络 / 5xx / 鉴权)分开:前者说明这个定位目标已经没了,后者只说明这次失败。\n */\nexport function isEntryGoneError(error: unknown): boolean {\n const status = (error as { status?: unknown } | null)?.status\n return status === 404 || status === 409\n}\n\n/** 侧栏「消息历史」的一条:只有 id、标题和时间,没有消息体。 */\nexport interface SessionTurnIndexItem {\n entryId: string\n preview: string\n createdAt: string | null\n}\n\nexport interface SessionTurnIndex {\n sessionId: string\n items: SessionTurnIndexItem[]\n}\n\nexport interface HistoricalCommand {\n deliveryId: string\n toolCallId?: string\n action: string\n payload?: unknown\n}\n\nexport type ResultFeedbackReason =\n | \"not_solved\"\n | \"inaccurate\"\n | \"incomplete\"\n | \"needs_major_changes\"\n | \"too_slow\"\n | \"other\"\n\nexport interface ResultFeedback {\n session_id: string\n assistant_entry_id: string\n surface: \"chat\" | \"software_factory\" | \"unknown\"\n project_id: string | null\n helpful: boolean\n reason: ResultFeedbackReason | null\n created_at: string\n updated_at: string\n}\n\nexport interface FileEntry {\n name: string\n path: string\n is_dir: boolean\n created_at: number\n tags?: string[]\n}\n\nexport type UploadFileEntry = File | { file: File; name: string }\n\nexport interface UploadFilesOptions {\n onProgress?: (progress: UploadProgress) => void\n}\n\nexport interface AppCliDefinition {\n /** 智能体在 Bash 中直接执行的业务命令名,例如 `library`。 */\n command: string\n /** Python 脚本由沙盒系统 Python 执行;executable 必须是 Linux 可执行文件。 */\n runtime: \"python\" | \"executable\"\n /** CLI 文件本身,或浏览器可以读取的 URL。 */\n source: Blob | string | URL\n /** source 是普通 Blob 时使用的上传文件名。 */\n filename?: string\n}\n\nexport interface AppCliAttachment {\n command: string\n runtime: \"python\" | \"executable\"\n digest: string\n}\n\nexport interface ImportPreviewSkill {\n name: string\n description: string\n path: string\n}\n\nexport interface ImportPreviewScenario {\n scenario?: { name?: string }\n skills?: string[]\n preview_urls?: string[]\n init_script?: string\n generated_at?: string\n}\n\nexport interface ImportPreview {\n user_messages: string[]\n turn_count: number\n skills: ImportPreviewSkill[]\n scenario: ImportPreviewScenario | null\n}\n\nexport interface ImportSessionOptions {\n /** 导入后改用这个正式 Solution 的最新版。 */\n solution_ref?: PublishedSolutionRef\n /** 导入后改用已有会话的完整运行快照。 */\n solution_snapshot_session_id?: string\n}\n\nfunction toCreateSessionPayload(request: CreateSessionRequest) {\n const solutionRef = request.solution_ref ?? externalSolutionRef(request.solution_id)\n return {\n intent: request.intent ?? \"\",\n template_id: request.template_id,\n solution_id: solutionRef ? undefined : request.solution_id,\n solution_ref: solutionRef,\n biz_role_id: request.biz_role_id ?? null,\n model: request.model ?? null,\n enable_thinking: request.enable_thinking ?? null,\n memory_enabled: request.memory_enabled ?? null,\n primary_skill_id: request.primary_skill_id ?? null,\n env: request.env,\n disable_tools: request.disable_tools ?? null,\n session_solution_asset_id: request.session_solution_asset_id ?? null,\n solution_snapshot_session_id: request.solution_snapshot_session_id ?? null,\n compaction_ratio: request.compaction_ratio ?? null,\n ...(request.runtime_type ? { runtime_type: request.runtime_type } : {}),\n ...(request.daemon_id ? { daemon_id: request.daemon_id } : {}),\n ...(request.agent_runtime_id ? { agent_runtime_id: request.agent_runtime_id } : {}),\n ...(request.chat_group_id ? { chat_group_id: request.chat_group_id } : {}),\n }\n}\n\nconst builtinSolutionIds = new Set([\n \"app-dev\",\n \"general_chat\",\n \"night_build\",\n \"skill_editor\",\n \"smart_bid\",\n \"solution_generate\",\n])\n\nfunction externalSolutionRef(\n solutionId: string | undefined,\n): PublishedSolutionRef | undefined {\n if (!solutionId) return undefined\n const normalized = solutionId === \"default\" ? \"general_chat\" : solutionId.trim()\n if (builtinSolutionIds.has(normalized)) {\n return { source: \"builtin\", name: normalized }\n }\n const parts = normalized.split(\"/\")\n if (parts.length === 2 && parts.every(Boolean)) {\n return { source: \"hub\", org: parts[0], name: parts[1] }\n }\n // Let the Server compatibility adapter return the canonical, actionable error.\n return undefined\n}\n\nexport class SessionsResource {\n constructor(private client: BladeClient) {}\n\n getMcpApp(sessionId: string, sourceId: string, init?: RequestInit): Promise<McpAppArchive> {\n return this.client.jsonFromInit(`/api/sessions/${encodeURIComponent(sessionId)}/mcp-apps/${encodeURIComponent(sourceId)}`, init)\n }\n\n onMcpAppChanged(sessionId: string, sourceId: string, listener: () => void): () => void {\n let socket = this.client.socket()\n const changed = (payload: { session_id: string; source_id: string }) => {\n if (payload.session_id === sessionId && payload.source_id === sourceId) listener()\n }\n socket.on(\"mcp-app:changed\", changed)\n socket.on(\"connect\", listener)\n const off = this.client.onSocketReplaced(() => {\n socket.off(\"mcp-app:changed\", changed)\n socket.off(\"connect\", listener)\n socket = this.client.socket()\n socket.on(\"mcp-app:changed\", changed)\n socket.on(\"connect\", listener)\n })\n return () => {\n off()\n socket.off(\"mcp-app:changed\", changed)\n socket.off(\"connect\", listener)\n }\n }\n\n callMcpApp(sessionId: string, sourceId: string, request: {\n request_id: string; name: string; arguments: Record<string, unknown>\n }, init?: RequestInit): Promise<{ response: Record<string, unknown>; replayed: boolean }> {\n return this.client.jsonFromInit(`/api/sessions/${encodeURIComponent(sessionId)}/mcp-apps/${encodeURIComponent(sourceId)}/calls`, {\n ...init, method: \"POST\", body: JSON.stringify(request),\n })\n }\n\n /**\n * 连接一个已存在的会话,返回实时会话对象 AgentSession\n * (自动完成历史加载、Socket.IO 订阅、断线重连补数)。\n */\n connect(sessionId: string): Promise<AgentSession> {\n return this.client.hub.connect(sessionId)\n }\n\n listSessionPlugins(sessionId: string, init?: RequestInit): Promise<{ plugins: SessionPlugin[]; sync_version: number; sync_pending: boolean }> {\n return this.client.jsonFromInit(`/api/sessions/${encodeURIComponent(sessionId)}/plugins`, init)\n }\n\n setSessionPluginActivation(sessionId: string, name: string, active: boolean, init?: RequestInit): Promise<{ plugin: SessionPluginActivation; sync_version: number }> {\n return this.client.jsonFromInit(`/api/sessions/${encodeURIComponent(sessionId)}/plugins/${encodeURIComponent(name)}:activation`, { method: \"POST\", body: JSON.stringify({ active }), ...init })\n }\n\n /**\n * Fetch a plugin's package-local icon as bytes.\n *\n * The request carries the client's own bearer credentials, so callers turn\n * the blob into an object URL instead of pointing `<img>` at an API path and\n * hoping the request is authenticated.\n */\n fetchSessionPluginIcon(sessionId: string, name: string): Promise<Blob> {\n return this.client.blob(\"GET\", `/api/sessions/${encodeURIComponent(sessionId)}/plugins/${encodeURIComponent(name)}/icon`)\n }\n\n /** Authenticated URL for the icon; useful where a blob URL cannot be used. */\n sessionPluginIconUrl(sessionId: string, name: string): string {\n return this.client.buildAuthedUrl(`/api/sessions/${encodeURIComponent(sessionId)}/plugins/${encodeURIComponent(name)}/icon`)\n }\n\n /**\n * 准备一个插件的配置:把包准备好并读出用户的配置契约,**不启用**它。\n *\n * 开启插件前必须先走这一步:缺配置时用户只会看到配置表单,服务端不会先把\n * active 持久化成 true 再靠补偿关掉。它不修改会话的插件选择、不连接 MCP。\n */\n prepareSessionPluginConfig(sessionId: string, name: string, init?: RequestInit): Promise<{ plugin: string; config: SessionPluginConfigState }> {\n return this.client.jsonFromInit(\n `/api/sessions/${encodeURIComponent(sessionId)}/plugins/${encodeURIComponent(name)}:prepare-config`,\n { method: \"POST\", ...init },\n )\n }\n\n /**\n * Read a plugin's configuration contract and the user's stored values.\n *\n * Secrets are never returned: `write_only` lists the pointers that hold one.\n */\n getSessionPluginConfig(sessionId: string, name: string, init?: RequestInit): Promise<{ plugin: string; config: SessionPluginConfigState }> {\n return this.client.jsonFromInit(`/api/sessions/${encodeURIComponent(sessionId)}/plugins/${encodeURIComponent(name)}/config`, init)\n }\n\n /**\n * Publish explicit set/remove operations to the user's keychain file.\n *\n * Fields absent from both lists keep their stored value, so a form never has\n * to round-trip a secret. Rejections leave the previous file untouched; the\n * call never restarts MCP servers.\n */\n updateSessionPluginConfig(sessionId: string, name: string, update: SessionPluginConfigUpdate, init?: RequestInit): Promise<{ plugin: string; config: SessionPluginConfigState }> {\n return this.client.jsonFromInit(`/api/sessions/${encodeURIComponent(sessionId)}/plugins/${encodeURIComponent(name)}/config`, { method: \"PUT\", body: JSON.stringify(update), ...init })\n }\n\n /** 创建新会话并直接连接,返回可收发消息的 AgentSession。 */\n async create(request: CreateSessionRequest | SessionDefinition = {}): Promise<AgentSession> {\n if (isSessionDefinition(request)) {\n return this.createDeclared(request)\n }\n const { session_id } = await this.createSessionWithRequest(request)\n return this.connect(session_id)\n }\n\n private async createDeclared(definition: SessionDefinition): Promise<AgentSession> {\n const { intent, solution, skills = [], config } = definition\n validateDefinition(definition)\n let solutionRequest: Pick<CreateSessionRequest, \"solution_id\" | \"session_solution_asset_id\" | \"biz_role_id\"> = {}\n try {\n solutionRequest = solution ? await this.prepareSolution(solution) : {}\n } catch (error) {\n throw setupError(\"solution\", \"Solution 准备失败\", error)\n }\n\n let session_id: string\n try {\n const created = await this.createSessionWithRequest({\n intent,\n ...solutionRequest,\n model: config?.model,\n enable_thinking: config?.enableThinking,\n memory_enabled: config?.memoryEnabled,\n compaction_ratio: config?.compactionRatio,\n env: config?.env,\n disable_tools: config?.disableTools,\n })\n session_id = created.session_id\n } catch (error) {\n const assetId = solutionRequest.session_solution_asset_id\n const assetCleaned = await this.cleanupSolutionAsset(assetId)\n const cleanupMessage = assetId\n ? assetCleaned\n ? \";临时 Solution 已清理\"\n : `;临时 Solution ${assetId} 清理失败`\n : \"\"\n throw setupError(\"session\", `会话创建失败${cleanupMessage}`, error)\n }\n\n let installingSkill = \"\"\n try {\n for (const skill of skills) {\n installingSkill = skill.name\n await this.client.json(\"POST\", `/api/sessions/${encodeURIComponent(session_id)}/skills:upload`, {\n name: skill.name,\n files: skill.files,\n })\n }\n } catch (error) {\n const sessionCleaned = await this.deleteSession(session_id).then(\n () => true,\n () => false,\n )\n const assetCleaned = await this.cleanupSolutionAsset(solutionRequest.session_solution_asset_id)\n const cleanupMessage = sessionCleaned ? \"未完成的会话已清理\" : `请手动删除会话 ${session_id}`\n const assetCleanupMessage = assetCleaned ? \"\" : \";临时 Solution 清理失败\"\n throw setupError(\n \"skill\",\n `Skill \"${installingSkill}\" 安装失败;${cleanupMessage}${assetCleanupMessage}`,\n error,\n session_id,\n )\n }\n\n // 会话创建时 Server 已把声明式 Solution 持久化到会话目录,临时资产不再需要。\n await this.cleanupSolutionAsset(solutionRequest.session_solution_asset_id)\n\n try {\n return await this.connect(session_id)\n } catch (error) {\n throw setupError(\"connection\", `会话连接失败;可使用 sessionId ${session_id} 重试`, error, session_id)\n }\n }\n\n private async prepareSolution(\n solution: SolutionDefinition,\n ): Promise<Pick<CreateSessionRequest, \"solution_id\" | \"session_solution_asset_id\" | \"biz_role_id\">> {\n if (\"id\" in solution) {\n return { solution_id: solution.id, biz_role_id: solution.role ?? null }\n }\n\n const prepared = await this.client.json<{ asset_id: string }>(\n \"POST\",\n \"/api/session-assets/solutions\",\n { files: solution.files },\n )\n return {\n session_solution_asset_id: prepared.asset_id,\n biz_role_id: solution.role ?? null,\n }\n }\n\n private async cleanupSolutionAsset(assetId?: string | null): Promise<boolean> {\n if (!assetId) return true\n try {\n await this.client.json(\"DELETE\", `/api/session-assets/solutions/${encodeURIComponent(assetId)}`)\n return true\n } catch {\n return false\n }\n }\n\n private fetchSessionsPage({\n limit,\n offset,\n template_id_prefix,\n solution_id,\n solution_registry_id,\n q,\n chat_group_id,\n }: ListSessionsPageParams): Promise<PaginatedSessionsResult> {\n const searchParams = new URLSearchParams()\n searchParams.set(\"limit\", String(limit))\n searchParams.set(\"offset\", String(offset))\n if (template_id_prefix) searchParams.set(\"template_id_prefix\", template_id_prefix)\n if (solution_registry_id) {\n searchParams.set(\"solution_registry_id\", solution_registry_id)\n } else if (solution_id) {\n searchParams.set(\"solution_id\", solution_id)\n }\n const trimmedQuery = q?.trim()\n if (trimmedQuery) searchParams.set(\"q\", trimmedQuery)\n if (chat_group_id) searchParams.set(\"chat_group_id\", chat_group_id)\n return this.client.json(\"GET\", `/api/sessions?${searchParams.toString()}`)\n }\n\n async listSessions(template_id_prefix?: string, solution_id?: string): Promise<SessionInfo[]> {\n const pageSize = 100\n const sessions: SessionInfo[] = []\n let offset = 0\n while (true) {\n const page = await this.fetchSessionsPage({ limit: pageSize, offset, template_id_prefix, solution_id })\n sessions.push(...page.items)\n if (sessions.length >= page.total || page.items.length === 0) return sessions\n offset += page.items.length\n }\n }\n\n listSessionsPaginated(params: {\n limit: number\n offset: number\n template_id_prefix?: string\n solution_id?: string\n solution_registry_id?: string\n q?: string\n chat_group_id?: string\n }): Promise<PaginatedSessionsResult> {\n return this.fetchSessionsPage(params)\n }\n\n listSessionsWithSkillData(): Promise<SkillDevSession[]> {\n return this.client.json(\"GET\", \"/api/sessions/with-skill-data\")\n }\n\n searchOwnedContent(params: { q: string; limit?: number }): Promise<GlobalSearchResult> {\n const searchParams = new URLSearchParams({ q: params.q.trim() })\n if (params.limit !== undefined) searchParams.set(\"limit\", String(params.limit))\n return this.client.json(\"GET\", `/api/search?${searchParams.toString()}`)\n }\n\n createSession(\n intent?: string,\n template_id?: TemplateId,\n primary_skill_id?: string | null,\n ): Promise<{ session_id: string }> {\n return this.createSessionWithRequest({ intent, template_id, primary_skill_id })\n }\n\n createSessionWithRequest(request: CreateSessionRequest): Promise<{ session_id: string }> {\n return this.client.json(\"POST\", \"/api/sessions\", toCreateSessionPayload(request))\n }\n\n createWithProfile(params: {\n intent: string\n profile: SessionProfile\n }): Promise<{ session_id: string }> {\n const { intent, profile } = params\n return this.createSessionWithRequest({\n intent,\n ...profileToCreateSessionRequest(profile),\n })\n }\n\n getSession(sessionId: string, init?: RequestInit): Promise<SessionDetail> {\n return this.client.jsonFromInit(`/api/sessions/${sessionId}`, init)\n }\n\n updateSession(sessionId: string, payload: { intent?: string; chat_group_id?: string | null }): Promise<SessionDetail> {\n return this.client.json(\"PATCH\", `/api/sessions/${sessionId}`, payload)\n }\n\n setSessionEnv(sessionId: string, env: Record<string, string>): Promise<SessionDetail> {\n return this.client.json(\"PUT\", `/api/sessions/${sessionId}/env`, { env })\n }\n\n pinSession(sessionId: string, pinned: boolean): Promise<SessionInfo> {\n return this.client.json(\"PATCH\", `/api/sessions/${sessionId}/pin`, { pinned })\n }\n\n startReplaySession(\n sourceSessionId: string,\n speed: ReplaySpeed = DEFAULT_REPLAY_SPEED,\n ): Promise<{ session_id: string }> {\n return this.client.json(\"POST\", `/api/sessions/${sourceSessionId}/replay`, { speed })\n }\n\n updateReplaySession(\n sessionId: string,\n payload: { speed?: ReplaySpeed; status?: \"autonomous\" },\n ): Promise<{ replay_state: SessionInfo[\"replay_state\"] }> {\n return this.client.json(\"PATCH\", `/api/sessions/${sessionId}/replay`, payload)\n }\n\n /** 查询会话能否作为回放来源;不支持时 reason 可直接展示,用来提前禁用入口。 */\n getReplayPreview(sessionId: string): Promise<ReplayPreview> {\n return this.client.json(\"GET\", `/api/sessions/${sessionId}/replay/preview`)\n }\n\n updateSharing(sessionId: string, shared: boolean): Promise<{ shared: boolean }> {\n return this.client.json(\"PATCH\", `/api/sessions/${sessionId}/sharing`, { shared })\n }\n\n updateSessionMemory(sessionId: string, memoryEnabled: boolean): Promise<{ memory_enabled: boolean }> {\n return this.client.json(\"PATCH\", `/api/sessions/${sessionId}/memory`, {\n memory_enabled: memoryEnabled,\n })\n }\n\n createShare(sessionId: string): Promise<ShareLinkResult> {\n return this.client.json(\"POST\", `/api/sessions/${sessionId}/share`, {})\n }\n\n revokeShare(sessionId: string, token: string): Promise<{ revoked: boolean }> {\n return this.client.json(\"DELETE\", `/api/sessions/${sessionId}/share/${encodeURIComponent(token)}`)\n }\n\n async getSharedSession(token: string): Promise<TurnProjection[]> {\n const entries = await this.client.jsonFromInit<RawHistoryEntry[]>(`/api/share/${encodeURIComponent(token)}`, {\n credentials: \"omit\",\n headers: { Accept: \"application/json\" },\n })\n return projectHistory(entries)\n }\n\n getSessionTasks(sessionId: string): Promise<Task[]> {\n return this.client.json(\"GET\", `/api/sessions/${sessionId}/tasks`)\n }\n\n async getSessionTurns(sessionId: string): Promise<TurnProjection[]> {\n const entries = await this.client.json<RawHistoryEntry[]>(\n \"GET\",\n `/api/sessions/${sessionId}/messages`,\n )\n return projectHistory(entries)\n }\n\n async getSessionTurnsPage(\n sessionId: string,\n options: SessionTurnsQuery = {},\n init: RequestInit = {},\n ): Promise<SessionTurnsPage> {\n const query = new URLSearchParams()\n if (options.limit !== undefined) query.set(\"limit\", String(options.limit))\n if (options.before !== undefined) query.set(\"before\", options.before)\n if (options.fromEntryId !== undefined) query.set(\"from_entry_id\", options.fromEntryId)\n const suffix = query.size ? `?${query}` : \"\"\n // 走 jsonFromInit 而不是 json:定位要能在用户改选下一条时中止在途请求\n // (排队中的新一次不该等着它),所以这里要把调用方的 AbortSignal 带下去。\n const page = await this.client.jsonFromInit<{\n turns: TurnProjection[]\n next_before: string | null\n current_mode: \"planning\" | \"executing\"\n }>(`/api/sessions/${encodeURIComponent(sessionId)}/turns${suffix}`, init)\n return {\n turns: page.turns,\n nextBefore: page.next_before,\n currentMode: page.current_mode,\n }\n }\n\n /**\n * 当前分支上可导航的用户发言目录(消息导航侧栏)。\n *\n * 只回 id、标题和时间:侧栏要列的是**整条会话**的发言,而窗口外的发言 id 只能\n * 从服务端拿;消息体仍然走 `/turns`。\n */\n async getSessionTurnIndex(sessionId: string): Promise<SessionTurnIndex> {\n const index = await this.client.json<{\n session_id: string\n items: Array<{ entry_id: string; preview: string; created_at: string | null }>\n }>(\"GET\", `/api/sessions/${encodeURIComponent(sessionId)}/turn-index`)\n return {\n sessionId: index.session_id,\n items: index.items.map((item) => ({\n entryId: item.entry_id,\n preview: item.preview,\n createdAt: item.created_at,\n })),\n }\n }\n\n getMcpAppContext(sessionId: string, sourceId: string, init?: RequestInit): Promise<McpAppContextState> {\n return this.client.jsonFromInit(`/api/sessions/${encodeURIComponent(sessionId)}/mcp-apps/${encodeURIComponent(sourceId)}/context`, init)\n }\n\n updateMcpAppContext(sessionId: string, sourceId: string, body: McpAppContextUpdate, init?: RequestInit): Promise<{ status: \"accepted\"; revision: string }> {\n return this.client.jsonFromInit(`/api/sessions/${encodeURIComponent(sessionId)}/mcp-apps/${encodeURIComponent(sourceId)}/context`, {\n ...init, method: \"POST\", body: JSON.stringify(body),\n })\n }\n\n async getSessionTurnCommands(sessionId: string): Promise<HistoricalCommand[]> {\n const commands = await this.client.json<Array<{\n delivery_id: string\n tool_call_id?: string | null\n action: string\n payload?: unknown\n }>>(\"GET\", `/api/sessions/${encodeURIComponent(sessionId)}/turn-commands`)\n return commands.map((command) => ({\n deliveryId: command.delivery_id,\n toolCallId: command.tool_call_id ?? undefined,\n action: command.action,\n payload: command.payload,\n }))\n }\n\n listResultFeedback(sessionId: string): Promise<ResultFeedback[]> {\n return this.client.json(\"GET\", `/api/sessions/${encodeURIComponent(sessionId)}/feedback`)\n }\n\n putResultFeedback(\n sessionId: string,\n assistantEntryId: string,\n feedback: { helpful: boolean; reason?: ResultFeedbackReason | null },\n ): Promise<ResultFeedback> {\n return this.client.json(\n \"PUT\",\n `/api/sessions/${encodeURIComponent(sessionId)}/turns/${encodeURIComponent(assistantEntryId)}/feedback`,\n feedback,\n )\n }\n\n getSessionContextStats(sessionId: string, init?: RequestInit): Promise<SessionContextStats> {\n return this.client.jsonFromInit(`/api/sessions/${sessionId}/context-stats`, init)\n }\n\n getSessionHistory(sessionId: string, init?: RequestInit): Promise<SessionHistory> {\n return this.client.jsonFromInit(`/api/sessions/${sessionId}/history`, init)\n }\n\n tokenizePrompt(prompt: string, model?: string): Promise<TokenizeResult> {\n return this.client.json(\"POST\", \"/api/sessions/tokenize/prompt\", { prompt, model })\n }\n\n tokenizeMessages(\n messages: Array<Record<string, unknown>>,\n options?: {\n model?: string\n add_generation_prompt?: boolean\n enable_thinking?: boolean | null\n tools?: Array<Record<string, unknown>>\n },\n ): Promise<TokenizeResult> {\n return this.client.json(\"POST\", \"/api/sessions/tokenize/messages\", {\n messages,\n model: options?.model,\n add_generation_prompt: options?.add_generation_prompt ?? true,\n enable_thinking: options?.enable_thinking ?? null,\n tools: options?.tools ?? null,\n })\n }\n\n getSessionCheckpoints(\n sessionId: string,\n init?: RequestInit,\n ): Promise<{ nodes: CheckpointNode[]; leaf_id: string | null }> {\n return this.client.jsonFromInit(`/api/sessions/${sessionId}/checkpoints`, init)\n }\n\n checkoutSession(\n sessionId: string,\n checkpointId: string,\n position: \"before\" | \"turn_end\",\n mode?: \"both\" | \"conversation\" | \"code\",\n linear?: boolean,\n ): Promise<{\n id: string\n content: string\n position: string\n mode?: string\n files_restored?: boolean\n linear?: boolean\n }> {\n return this.client.json(\"POST\", `/api/sessions/${sessionId}/checkout`, {\n checkpoint_id: checkpointId,\n position,\n ...(mode ? { mode } : {}),\n ...(linear ? { linear } : {}),\n })\n }\n\n async rewindSession(sessionId: string, checkpointId: string): Promise<{ id: string; content: string }> {\n const result = await this.checkoutSession(sessionId, checkpointId, \"before\")\n return { id: result.id, content: result.content }\n }\n\n switchBranch(sessionId: string, checkpointId: string): Promise<{ id: string; leaf_id: string }> {\n return this.client.json(\"POST\", `/api/sessions/${sessionId}/switch-branch`, {\n checkpoint_id: checkpointId,\n })\n }\n\n deleteSession(\n sessionId: string,\n options?: { deleteWorkspace?: boolean },\n ): Promise<{ deleted: boolean; workspace_deleted?: boolean }> {\n const query = options?.deleteWorkspace ? \"?delete_workspace=true\" : \"\"\n return this.client.json(\"DELETE\", `/api/sessions/${sessionId}${query}`)\n }\n\n listBackgroundTasks(sessionId: string, init?: RequestInit): Promise<BackgroundTask[]> {\n return this.client.jsonFromInit(`/api/sessions/${sessionId}/background-tasks`, init)\n }\n\n getBackgroundTask(\n sessionId: string,\n taskId: string,\n tail = 100,\n init?: RequestInit,\n ): Promise<BackgroundTask> {\n return this.client.jsonFromInit(`/api/sessions/${sessionId}/background-tasks/${taskId}?tail=${tail}`, init)\n }\n\n stopBackgroundTask(\n sessionId: string,\n taskId: string,\n ): Promise<BackgroundTaskStopResult> {\n return this.client.json(\"POST\", `/api/sessions/${sessionId}/background-tasks/${taskId}/stop`)\n }\n\n\n probeSessionUrl(\n sessionId: string,\n url: string,\n ): Promise<{ reachable: boolean; requires_proxy: boolean }> {\n return this.client.json(\n \"GET\",\n `/api/sessions/${sessionId}/probe-url?url=${encodeURIComponent(url)}`,\n )\n }\n\n listDir(sessionId: string, dirPath: string): Promise<FileEntry[]> {\n return this.client.json(\"GET\", `/api/sessions/${sessionId}/ls/${encodeURIComponent(dirPath)}`)\n }\n\n async countFiles(sessionId: string, dirPath = \"\"): Promise<number> {\n const entries = await this.listDir(sessionId, dirPath)\n let count = 0\n for (const entry of entries) {\n count += entry.is_dir ? await this.countFiles(sessionId, entry.path) : 1\n }\n return count\n }\n\n /** 在浏览器中下载一个会话文件。 */\n async downloadFile(sessionId: string, filePath: string, downloadName?: string): Promise<void> {\n if (typeof document === \"undefined\") {\n throw new Error(\"downloadFile 只能在浏览器中使用\")\n }\n const response = await this.client.fetch(\n \"GET\",\n `/api/sessions/${encodeURIComponent(sessionId)}/files/${encodeURIComponent(filePath)}`,\n )\n const objectUrl = URL.createObjectURL(await response.blob())\n const anchor = document.createElement(\"a\")\n anchor.href = objectUrl\n anchor.download = downloadName || filePath.split(\"/\").pop() || \"download\"\n anchor.style.display = \"none\"\n document.body.appendChild(anchor)\n anchor.click()\n anchor.remove()\n globalThis.setTimeout(() => URL.revokeObjectURL(objectUrl), 1_000)\n }\n\n async uploadFiles(\n sessionId: string,\n dirPath: string,\n files: FileList | File[] | UploadFileEntry[],\n options: UploadFilesOptions = {},\n ): Promise<{ uploaded: string[]; failed: string[] }> {\n const formData = new FormData()\n const entries = Array.from(files).map((f) =>\n f instanceof File ? { file: f, name: f.name } : (f as { file: File; name: string }),\n )\n for (const entry of entries) {\n formData.append(\"files\", entry.file, entry.name)\n }\n // webkitdirectory 选择的文件带 webkitRelativePath;拖入的文件夹把相对路径放在 name 里。\n // 任一形式包含目录分隔符时都发送 paths,供服务端重建目录结构。\n const relativePaths = entries.map((e) => e.file.webkitRelativePath || e.name)\n if (relativePaths.some((p) => p.includes(\"/\"))) {\n formData.append(\"paths\", JSON.stringify(relativePaths))\n }\n const response = await this.client.formData(\n \"POST\",\n `/api/sessions/${sessionId}/upload/${encodeURIComponent(dirPath)}`,\n formData,\n { expectOk: false, onUploadProgress: options.onProgress },\n )\n return response.json()\n }\n\n /** 把应用自己的业务 CLI 安装到会话沙盒,并保留开发者声明的命令名。 */\n async attachAppCli(\n sessionId: string,\n definition: AppCliDefinition,\n ): Promise<AppCliAttachment> {\n let source: Blob\n if (definition.source instanceof Blob) {\n source = definition.source\n } else {\n const response = await globalThis.fetch(definition.source.toString())\n if (!response.ok) {\n throw new Error(`读取应用 CLI 失败:HTTP ${response.status}`)\n }\n source = await response.blob()\n }\n const filename =\n definition.filename ??\n (typeof File !== \"undefined\" && definition.source instanceof File\n ? definition.source.name\n : undefined) ??\n (definition.runtime === \"python\" ? \"app-cli.py\" : \"app-cli\")\n const form = new FormData()\n form.append(\"command\", definition.command)\n form.append(\"runtime\", definition.runtime)\n form.append(\"file\", source, filename)\n const response = await this.client.formData(\n \"POST\",\n `/api/sessions/${sessionId}/app-cli`,\n form,\n )\n return response.json()\n }\n\n async deleteFile(sessionId: string, filePath: string): Promise<void> {\n await this.client.json(\"DELETE\", `/api/sessions/${sessionId}/files/${encodeURIComponent(filePath)}`)\n }\n\n writeFile(sessionId: string, filePath: string, content: string): Promise<{ success: boolean }> {\n return this.client.json(\"PUT\", `/api/sessions/${sessionId}/files/${encodeURIComponent(filePath)}`, {\n content,\n })\n }\n\n renameFile(sessionId: string, filePath: string, newName: string): Promise<{ path: string }> {\n return this.client.json(\"POST\", `/api/sessions/${sessionId}/files/${encodeURIComponent(filePath)}/rename`, {\n new_name: newName,\n })\n }\n\n copyFile(sessionId: string, filePath: string): Promise<{ path: string }> {\n return this.client.json(\"POST\", `/api/sessions/${sessionId}/files/${encodeURIComponent(filePath)}/copy`)\n }\n\n shareFile(\n sessionId: string,\n sourcePath: string,\n linkName?: string,\n shareFolder?: string,\n ): Promise<{ path: string; target: string }> {\n return this.client.json(\"POST\", `/api/sessions/${sessionId}/share-file`, {\n source_path: sourcePath,\n link_name: linkName ?? \"\",\n share_folder: shareFolder ?? \"\",\n })\n }\n\n getDownloadDirUrl(sessionId: string, dirPath: string): string {\n return this.client.buildAuthedUrl(`/api/sessions/${sessionId}/download-dir/${encodeURIComponent(dirPath)}`)\n }\n\n async exportSession(sessionId: string): Promise<void> {\n await this.getSession(sessionId)\n const a = document.createElement(\"a\")\n a.href = this.client.buildAuthedUrl(`/api/sessions/${sessionId}/export`)\n a.download = `${sessionId}.zip`\n document.body.appendChild(a)\n a.click()\n a.remove()\n }\n\n async previewImport(file: File): Promise<ImportPreview> {\n const form = new FormData()\n form.append(\"file\", file)\n const res = await this.client.formData(\"POST\", \"/api/sessions/preview-import\", form)\n return res.json()\n }\n\n async importSession(\n file: File,\n name?: string,\n solutionOverride?: string | null | ImportSessionOptions,\n ): Promise<{ session_id: string }> {\n const form = new FormData()\n form.append(\"file\", file)\n if (name) form.append(\"name\", name)\n if (typeof solutionOverride === \"string\") {\n if (solutionOverride) form.append(\"solution_id\", solutionOverride)\n } else if (solutionOverride) {\n if (solutionOverride.solution_ref) {\n form.append(\"solution_ref\", JSON.stringify(solutionOverride.solution_ref))\n }\n if (solutionOverride.solution_snapshot_session_id) {\n form.append(\n \"solution_snapshot_session_id\",\n solutionOverride.solution_snapshot_session_id,\n )\n }\n }\n const res = await this.client.formData(\"POST\", \"/api/sessions/import\", form)\n return res.json()\n }\n}\n\nfunction isSessionDefinition(request: CreateSessionRequest | SessionDefinition): request is SessionDefinition {\n return \"solution\" in request || \"skills\" in request || \"config\" in request\n}\n\nfunction validateDefinition(definition: SessionDefinition): void {\n if (definition.solution) {\n if (\"id\" in definition.solution) {\n if (!definition.solution.id.trim()) {\n throw new SessionSetupError(\"Solution id 不能为空\", \"solution\")\n }\n } else {\n validateTextFiles(definition.solution.files, \"solution\", \"Solution\")\n if (!definition.solution.files.some((file) => file.path === \"solution.yaml\")) {\n throw new SessionSetupError(\"Solution 缺少根目录 solution.yaml\", \"solution\")\n }\n }\n }\n for (const skill of definition.skills ?? []) validateSkill(skill)\n}\n\nfunction validateSkill(skill: SkillDefinition): void {\n if (!/^[a-z0-9-]+\\/[a-z0-9-]+$/.test(skill.name)) {\n throw new SessionSetupError(`Skill name \"${skill.name}\" 必须是小写的 组织/名称`, \"skill\")\n }\n validateTextFiles(skill.files, \"skill\", `Skill \"${skill.name}\"`)\n if (!skill.files.some((file) => file.path === \"SKILL.md\")) {\n throw new SessionSetupError(`Skill \"${skill.name}\" 缺少根目录 SKILL.md`, \"skill\")\n }\n}\n\nfunction validateTextFiles(\n files: Array<{ path: string; content: string }>,\n stage: ConstructorParameters<typeof SessionSetupError>[1],\n label: string,\n): void {\n if (files.length === 0) throw new SessionSetupError(`${label} files 不能为空`, stage)\n const paths = new Set<string>()\n for (const file of files) {\n const path = file.path\n if (\n !path\n || path !== path.trim()\n || path.startsWith(\"/\")\n || path.includes(\"\\\\\")\n || path.split(\"/\").some((part) => !part || part === \".\" || part === \"..\")\n || /^[a-zA-Z]:/.test(path)\n ) {\n throw new SessionSetupError(`${label} 文件路径不安全:\"${path}\"`, stage)\n }\n if (paths.has(path)) {\n throw new SessionSetupError(`${label} 文件路径重复:\"${path}\"`, stage)\n }\n paths.add(path)\n }\n}\n\nfunction setupError(\n stage: ConstructorParameters<typeof SessionSetupError>[1],\n message: string,\n cause: unknown,\n sessionId?: string,\n): SessionSetupError {\n const detail = cause instanceof Error ? cause.message : String(cause)\n return new SessionSetupError(`${message}:${detail}`, stage, sessionId, { cause })\n}\n\nfunction profileToCreateSessionRequest(profile: SessionProfile): CreateSessionRequest {\n const solution = profile.solution\n return {\n solution_id: solution?.kind === \"existing\" ? solution.solutionId : undefined,\n session_solution_asset_id: solution?.kind === \"prepared\" ? solution.assetId : undefined,\n biz_role_id: solution?.bizRoleId ?? null,\n model: profile.model ?? null,\n compaction_ratio: profile.compactionRatio ?? null,\n enable_thinking: profile.enableThinking ?? null,\n memory_enabled: profile.memoryEnabled ?? null,\n disable_tools: profile.disableTools ?? null,\n env: profile.env,\n }\n}\n","import type { BladeClient } from \"../blade-client\"\n\n/**\n * 一个插件在当前用户眼里的展示信息,**与会话无关**。\n *\n * 连接器面板在首页(还没有 sessionId)也要显示插件名称和图标,所以这份目录\n * 只能依赖用户身份:它不激活任何插件、不启动沙盒、不读用户配置。\n */\nexport interface PluginCatalogEntry {\n /** 技术 ID:路径、授权、缓存与调用一律用它。 */\n name: string\n /** 包声明的业务名称;null 时界面回退到 `name`。 */\n display_name: string | null\n /**\n * 包内图标的 opaque token,没有可用图标时为 null。\n * 交给 `fetchPluginIcon`,**不是**路径,也不能直接当 URL 用。\n */\n icon: string | null\n /** 当前用户是否安装了它。 */\n installed: boolean\n}\n\n/**\n * 按用户读取的插件目录(无会话)。\n *\n * 图标只能通过带凭据的请求取字节,再转成 object URL——把 `<img>` 指向 API\n * 路径要靠 cookie,token 用户会拿到 401/403。\n */\nexport class PluginsResource {\n constructor(private client: BladeClient) {}\n\n /**\n * 列出当前用户安装的插件及其展示信息。\n *\n * 服务端可能为了补齐名称/图标惰性获取包内容,但绝不激活插件、不连 MCP;\n * 单个插件的展示信息读不出来只会降级成占位,不会让整份目录失败。\n */\n catalog(init?: RequestInit): Promise<{ plugins: PluginCatalogEntry[] }> {\n return this.client.jsonFromInit(\"/api/plugins/catalog\", init)\n }\n\n /** 取一个插件的包内图标字节(用户级,不需要会话)。 */\n fetchIcon(name: string): Promise<Blob> {\n return this.client.blob(\"GET\", `/api/plugins/${encodeURIComponent(name)}/icon`)\n }\n\n /** 带凭据的图标地址;能直接用 blob URL 的地方优先用 `fetchIcon`。 */\n iconUrl(name: string): string {\n return this.client.buildAuthedUrl(`/api/plugins/${encodeURIComponent(name)}/icon`)\n }\n}\n","import type { BladeClient } from \"../blade-client\"\n\nexport interface ChatGroup {\n id: string\n name: string\n instructions: string\n created_at: string\n updated_at: string\n session_count: number\n workspace_path: string\n}\n\nexport class ChatGroupsResource {\n constructor(private readonly client: BladeClient) {}\n\n list(): Promise<ChatGroup[]> {\n return this.client.json(\"GET\", \"/api/chat-groups\")\n }\n\n create(payload: { name: string; instructions?: string }): Promise<ChatGroup> {\n return this.client.json(\"POST\", \"/api/chat-groups\", payload)\n }\n\n update(groupId: string, payload: { name?: string; instructions?: string }): Promise<ChatGroup> {\n return this.client.json(\"PATCH\", `/api/chat-groups/${encodeURIComponent(groupId)}`, payload)\n }\n\n delete(groupId: string, options?: { deleteWorkspace?: boolean }): Promise<{ deleted: boolean; deleted_sessions: number }> {\n const query = options?.deleteWorkspace ? \"?delete_workspace=true\" : \"\"\n return this.client.json(\"DELETE\", `/api/chat-groups/${encodeURIComponent(groupId)}${query}`)\n }\n\n}\n","import { BladeApiError, buildBackendUrl, extractErrorDetail } from \"../rest\"\nimport type { BladeClient } from \"../blade-client\"\n\nconst SITE_VISITS_PATH = \"/api/site-visits\"\nconst REQUEST_TIMEOUT_MS = 5_000\n\n/** 全站访问统计快照。每个数字都来自真实请求,没有基数、系数或回填。 */\nexport interface SiteVisitsSummary {\n /** 统计日期,按北京时间切日(`YYYY-MM-DD`)。 */\n date: string\n /** 统计时区,固定为 `Asia/Shanghai`。 */\n timezone: string\n /** 当天出现过的匿名访客数:按天去重,不是实时在线人数。 */\n today_uv: number\n /** 当天的页面访问次数。 */\n today_pv: number\n /** 功能上线以来累计的页面访问次数。 */\n total_pv: number\n /** 快照生成时间(RFC3339 UTC)。并发响应可能倒序到达,用它丢弃旧快照。 */\n as_of: string\n}\n\n/**\n * 全站访问统计(内置 Web 的匿名计数)。\n *\n * 这两个操作刻意走独立传输:不带 bearer、不触发 401 登录刷新,也不读登录\n * Cookie——计数只依赖匿名访客 Cookie,因此登录态失效时统计依然可用。它们\n * 只在同源的内置 Web 里使用,不是给第三方宿主页面用的。\n */\nexport class SiteVisitsResource {\n constructor(private readonly client: BladeClient) {}\n\n /** 上报一次页面访问,返回当前快照;不承诺本次已计入或已落盘。 */\n record(): Promise<SiteVisitsSummary> {\n return this.request(\"POST\")\n }\n\n /** 只读快照:不设置访客 Cookie,也不增加任何计数。 */\n summary(): Promise<SiteVisitsSummary> {\n return this.request(\"GET\")\n }\n\n private async request(method: \"GET\" | \"POST\"): Promise<SiteVisitsSummary> {\n const url = buildBackendUrl(this.client.options.baseUrl, SITE_VISITS_PATH)\n const controller = new AbortController()\n const timeout = setTimeout(() => controller.abort(), REQUEST_TIMEOUT_MS)\n try {\n const response = await (this.client.options.fetchImpl ?? fetch)(url.toString(), {\n method,\n // 访客 Cookie 是唯一的去重依据,必须随请求往返。\n credentials: \"include\",\n signal: controller.signal,\n })\n if (!response.ok) {\n throw new BladeApiError(response, await extractErrorDetail(response))\n }\n return (await response.json()) as SiteVisitsSummary\n } finally {\n clearTimeout(timeout)\n }\n }\n}\n","const DEFAULT_RETRY_AFTER_SECONDS = 1\nconst MAX_TIMER_DELAY_MS = 2_147_483_647\n\ntype AuthBusyData = {\n code?: unknown\n status?: unknown\n retry_after?: unknown\n}\n\nfunction errorData(error: unknown): AuthBusyData | null {\n if (typeof error !== \"object\" || error === null || !(\"data\" in error)) return null\n const data = error.data\n return typeof data === \"object\" && data !== null ? (data as AuthBusyData) : null\n}\n\n/** Return the server-requested delay for a typed temporary auth rejection. */\nexport function authBusyRetryDelayMs(error: unknown): number | null {\n const data = errorData(error)\n if (data?.code !== \"auth_busy\" || Number(data.status) !== 429) return null\n const rawRetryAfter = data.retry_after\n const seconds = rawRetryAfter == null || String(rawRetryAfter).trim() === \"\"\n ? Number.NaN\n : Number(rawRetryAfter)\n const delaySeconds = Number.isFinite(seconds) && seconds >= 0\n ? seconds\n : DEFAULT_RETRY_AFTER_SECONDS\n return Math.min(delaySeconds * 1000, MAX_TIMER_DELAY_MS)\n}\n\n/** One pending manual reconnect for Socket.IO CONNECT_ERROR auth overloads. */\nexport class AuthBusyReconnect {\n private timer: ReturnType<typeof globalThis.setTimeout> | null = null\n\n get pending(): boolean {\n return this.timer !== null\n }\n\n schedule(error: unknown, reconnect: () => void): boolean {\n const delay = authBusyRetryDelayMs(error)\n if (delay === null) {\n this.cancel()\n return false\n }\n this.cancel()\n this.timer = globalThis.setTimeout(() => {\n this.timer = null\n reconnect()\n }, delay)\n return true\n }\n\n cancel(): void {\n if (this.timer === null) return\n globalThis.clearTimeout(this.timer)\n this.timer = null\n }\n}\n","export type CommandHandler = (payload: unknown, meta: { toolCallId?: string }) => void\n\ninterface BufferedCommand {\n payload: unknown\n meta: { toolCallId?: string }\n}\n\n/** 每个 action 在 handler 注册前最多缓冲的指令条数,超出丢最旧的。 */\nconst BUFFER_LIMIT_PER_ACTION = 20\n\n/**\n * 指令注册表:onCommand 事后注册 + 注册前缓冲补投。\n *\n * action 的来源见 ./protocol.ts 顶部说明——它由技能作者在工具返回值的\n * `_meta.bridge` 字段里写入,是技能作者与宿主页面开发者的业务契约。\n * 缓冲的意义:指令可能在页面还没来得及调用 onCommand 时就到达(比如\n * 历史回放),先存起来、注册时立刻补投,消除\"注册晚了漏事件\"的坑。\n */\nexport class CommandRegistry {\n private handlers = new Map<string, Set<CommandHandler>>()\n private buffered = new Map<string, BufferedCommand[]>()\n\n onCommand(action: string, handler: CommandHandler): () => void {\n let set = this.handlers.get(action)\n if (!set) {\n set = new Set()\n this.handlers.set(action, set)\n }\n set.add(handler)\n\n const pending = this.buffered.get(action)\n if (pending?.length) {\n this.buffered.delete(action)\n for (const command of pending) {\n this.invoke(handler, action, command)\n }\n }\n return () => {\n this.handlers.get(action)?.delete(handler)\n }\n }\n\n dispatch(action: string, payload: unknown, meta: { toolCallId?: string } = {}): void {\n const set = this.handlers.get(action)\n if (set && set.size > 0) {\n for (const handler of [...set]) {\n this.invoke(handler, action, { payload, meta })\n }\n return\n }\n let pending = this.buffered.get(action)\n if (!pending) {\n pending = []\n this.buffered.set(action, pending)\n }\n pending.push({ payload, meta })\n if (pending.length > BUFFER_LIMIT_PER_ACTION) {\n pending.shift()\n console.warn(\n `[agent-client] 指令 \"${action}\" 无人处理且缓冲已满,最旧的一条已丢弃。` +\n `请调用 onCommand(\"${action}\", handler) 注册处理函数。`,\n )\n }\n }\n\n private invoke(handler: CommandHandler, action: string, command: BufferedCommand): void {\n try {\n handler(command.payload, command.meta)\n } catch (error) {\n console.warn(`[agent-client] 指令 \"${action}\" 的处理函数抛出异常:`, error)\n }\n }\n\n clear(): void {\n this.handlers.clear()\n this.buffered.clear()\n }\n}\n","import type { ChatMessage, ToolCallInfo } from \"../schemas/message\"\nimport type { McpAppData } from \"../schemas/mcp-app\"\nimport type { TurnProjection } from \"../schemas/projection\"\nimport type { SessionStatus } from \"../schemas/session\"\n\n/**\n * AgentSession 的语义事件表。\n *\n * 这是\"底层逃生舱\"(L1):React 使用者优先用 useChat() 的响应式状态(L2)\n * 或 <ChatView onToolCall/commands> 的声明式入口(L3),一般不需要直接监听。\n * Vue / 无框架集成者用 session.on(...) 精确订阅。\n */\nexport interface AgentSessionEvents {\n /** 一条消息物化完成(turn 离开 streaming 状态)。 */\n message: { message: ChatMessage; turn: TurnProjection }\n /** 智能体发起了一次工具调用(首次出现)。 */\n toolCall: { toolCall: ToolCallInfo; turn: TurnProjection }\n /** 一次工具调用出结果(done / error / cancelled)。 */\n toolResult: {\n toolCall: ToolCallInfo\n turn: TurnProjection\n /** 实时到达,或首次连接/断线重连时由服务端回放。 */\n source: \"live\" | \"bootstrap_replay\" | \"reconnect_replay\"\n }\n /** 一轮回复结束。status: completed / paused / interrupted / failed。 */\n chatEnd: { status: string }\n /** 运行错误(system:error、发送失败等)。 */\n error: { message: string }\n /** planning / executing 模式切换。 */\n modeChange: { mode: \"planning\" | \"executing\" }\n /**\n * 智能体给宿主页面下发指令。\n *\n * action 的来源:技能作者在工具实现的返回值 JSON 里写 `_meta.bridge:\n * { action, payload }`,后端剥离后经事件流送达前端。action 是技能作者与\n * 宿主页面开发者约定的业务契约字符串(如 \"map.highlight\"),LLM 不参与、\n * SDK 不做枚举。一般用 session.onCommand(action, fn) 消费,而不是监听本事件。\n */\n command: { action: string; payload: unknown; toolCallId?: string }\n /** 系统通知(技能阶段提示、后台任务启动等)。 */\n notification: {\n type: string\n title: string\n detail?: string\n status: \"info\" | \"running\" | \"done\" | \"error\"\n loopId?: string\n metadata?: Record<string, unknown>\n }\n /** 工作区文件发生变化(写文件、重命名等)。 */\n workspaceChanged: { filePath?: string }\n /** 智能体产出了文件成果(artifact:created / artifact:updated)。 */\n artifact: {\n filePath: string\n contentType: string\n title: string\n content: string\n oldString?: string\n newString?: string\n kind: \"created\" | \"updated\"\n }\n /** 工具返回值带 _meta.ui 的可视化预览(resource HTML / URI)。 */\n toolPreview: {\n toolCallId: string\n type: \"resource-html\" | \"resource-uri\"\n content: string\n title: string\n mcpApp?: McpAppData\n }\n /** 任务清单(TaskCreate 等)更新。 */\n taskListUpdated: { tasks: unknown[] }\n /** 沙盒后台命令状态更新。 */\n backgroundTask: {\n id: string\n command: string\n description?: string\n /**\n * 与 REST 一致的真实状态。不要在客户端合并这些值:把 cancelled / lost\n * 显示成\"完成\"会让订阅方拿到与 REST 相反的结论。\n * lost 表示平台跟丢了这个进程,不代表它失败,也可能仍在运行。\n */\n status:\n | \"starting\"\n | \"running\"\n | \"cancelling\"\n | \"succeeded\"\n | \"failed\"\n | \"cancelled\"\n | \"lost\"\n /** failed 时说明原因,如 start_failed、log_budget_exceeded。 */\n failureReason?: string | null\n exitCode?: number | null\n elapsedSeconds: number\n output?: string\n }\n /** 会话被回溯到某个检查点。 */\n rewind: { checkpointId: string }\n /** 会话属性(名称、状态、绑定技能等)被服务端更新。 */\n sessionUpdated: {\n workspacePath?: string\n chatGroupId?: string | null\n intent?: string\n status?: SessionStatus\n model?: string | null\n boundSkillId?: string | null\n replayState?: Record<string, unknown> | null\n }\n /** 回放输入不匹配,需要决定保持回放还是转自主模式。 */\n replayMismatch: {\n actualMessage?: string\n expectedMessage?: string\n respond: (decision: \"keep_replay\" | \"continue_replay\") => void\n }\n /** 沙盒内存超限自动重启。 */\n sandboxOom: { toolCallId: string }\n /** session.attach() 被调用,渲染层(ChatView/useChat)应把它显示为输入框附件。 */\n attachRequested: { label: string; content: string }\n /** session.insertText() 被调用,渲染层应把文字追加到输入框。 */\n insertTextRequested: { text: string }\n}\n\nexport type AgentSessionEventName = keyof AgentSessionEvents\n\ntype Handler<E> = (event: E) => void\n\nexport class Emitter<Events> {\n private handlers = new Map<keyof Events, Set<Handler<never>>>()\n\n on<K extends keyof Events>(name: K, handler: Handler<Events[K]>): () => void {\n let set = this.handlers.get(name)\n if (!set) {\n set = new Set()\n this.handlers.set(name, set)\n }\n set.add(handler as Handler<never>)\n return () => this.off(name, handler)\n }\n\n off<K extends keyof Events>(name: K, handler: Handler<Events[K]>): void {\n this.handlers.get(name)?.delete(handler as Handler<never>)\n }\n\n emit<K extends keyof Events>(name: K, event: Events[K]): void {\n const set = this.handlers.get(name)\n if (!set) return\n for (const handler of [...set]) {\n try {\n ;(handler as Handler<Events[K]>)(event)\n } catch (error) {\n // handler 异常只告警,不中断会话流\n console.warn(`[agent-client] \"${String(name)}\" 事件处理器抛出异常:`, error)\n }\n }\n }\n\n /**\n * 只把事件交给最先注册的处理器。用于必须由单一交互入口作答的事件,\n * 避免多个 UI 同时弹窗并提交相互冲突的决定。\n */\n emitFirst<K extends keyof Events>(name: K, event: Events[K]): boolean {\n const handler = this.handlers.get(name)?.values().next().value\n if (!handler) return false\n try {\n ;(handler as Handler<Events[K]>)(event)\n } catch (error) {\n console.warn(`[agent-client] \"${String(name)}\" 事件处理器抛出异常:`, error)\n return false\n }\n return true\n }\n\n listenerCount(name: keyof Events): number {\n return this.handlers.get(name)?.size ?? 0\n }\n\n clear(): void {\n this.handlers.clear()\n }\n}\n","import type { TurnProjection } from \"../schemas/projection\"\n\nexport interface LiveRevisionState {\n current: number\n byTurnId: ReadonlyMap<string, number>\n}\n\nfunction sortedUnique(turns: TurnProjection[]): TurnProjection[] {\n const byId = new Map<string, TurnProjection>()\n for (const turn of turns) byId.set(turn.turn_id, turn)\n return [...byId.values()].sort((left, right) => left.sequence - right.sequence)\n}\n\n/** Add an older authoritative slice without allowing it to roll back live content. */\nexport function prependOlder(\n current: TurnProjection[],\n page: TurnProjection[],\n): TurnProjection[] {\n const currentById = new Map(current.map((turn) => [turn.turn_id, turn]))\n return sortedUnique([\n ...current,\n ...page.map((turn) => {\n const live = currentById.get(turn.turn_id)\n return live ? { ...live, sequence: turn.sequence } : turn\n }),\n ])\n}\n\n/** Install a new authoritative window, retaining only live writes newer than the request. */\nexport function replaceWindow(\n current: TurnProjection[],\n page: TurnProjection[],\n liveRevisionAtStart: number,\n liveRevisions: LiveRevisionState,\n): TurnProjection[] {\n const pageById = new Map(page.map((turn) => [turn.turn_id, turn]))\n const newerLive = current.filter(\n (turn) =>\n turn.turn_id.startsWith(\"local-user-\") ||\n (liveRevisions.byTurnId.get(turn.turn_id) ?? 0) > liveRevisionAtStart,\n )\n return sortedUnique([\n ...page,\n ...newerLive.map((turn) => {\n const snapshot = pageById.get(turn.turn_id)\n return snapshot ? { ...turn, sequence: snapshot.sequence } : turn\n }),\n ])\n}\n","import { isRecord } from \"../shared/type-guards\"\n\n/**\n * 会话消息队列的共享领域模型:类型、快照合并规则与中文文案。\n *\n * 这里是**单一定义处**:AgentSession 的状态机、agent-react 与内置 Web 的队列 UI\n * 都只用这一份判定,避免\"能不能编辑 / 旧快照要不要覆盖\"各写一遍后各自演进。\n * 服务端语义见 issue #2529 与 local://frontend-queue-contract.md。\n */\n\n/** 等待消息的服务端生命周期状态。 */\nexport type QueuedMessageStatus = \"pending\" | \"delivering\" | \"claimed\" | \"consumed\" | \"cancelled\"\n\n/** 队列里的一条等待消息;权威快照只包含 pending(等待执行)与 delivering(等待接收)。 */\nexport interface QueuedMessage {\n id: string\n content: string\n position: number\n version: number\n status: QueuedMessageStatus\n created_at: string\n updated_at: string\n /** 立即补充指向的当前运行 id;普通等待条目没有。 */\n target_run_id?: string\n /** 领取或投递失败的原因。 */\n error?: string\n}\n\n/** 服务端权威队列快照。`revision` 单调递增,客户端据此丢弃过期快照。 */\nexport interface SessionQueueSnapshot {\n session_id: string\n revision: number\n paused: boolean\n pause_reason: string | null\n items: QueuedMessage[]\n}\n\n/**\n * 还没有拿到服务端快照时的占位。\n *\n * `session_id` 为空表示\"身份未知\":`shouldApplySnapshot` 会跳过会话身份校验、\n * 只比较 revision,这样第一份快照(哪怕 revision 为 0 的暂停态)也能装进来。\n */\nexport const EMPTY_SESSION_QUEUE: SessionQueueSnapshot = {\n session_id: \"\",\n revision: 0,\n paused: false,\n pause_reason: null,\n items: [],\n}\n\n/**\n * 队列命令的 ack 线格式。\n *\n * `conflict` 表示乐观并发或状态校验失败,此时快照字段是服务端最新值,客户端必须\n * 据此刷新本地并保留用户草稿;`error` 时快照字段可能缺失(如鉴权失败),此时只报错、\n * 不改动本地队列。\n */\nexport interface QueueAck {\n /** `queued` 只出现在 `chat:send` 的运行中改道:消息已进等待队列,不是失败。 */\n status: \"ok\" | \"conflict\" | \"error\" | \"queued\"\n /**\n * 只有 `queued` 会带:服务端判定这次改道时该会话是否有运行。\n * 客户端据此对齐流式标记,不用自己的猜测。\n */\n running?: boolean\n message?: string | null\n session_id?: string\n revision?: number\n paused?: boolean\n pause_reason?: string | null\n items?: QueuedMessage[]\n}\n\n/** 解析后的队列操作结果;UI 只看这一个结构。 */\nexport interface QueueOperationResult {\n ok: boolean\n conflict: boolean\n /** 服务端快照;缺失时为 null,调用方不得据此清空本地队列。 */\n snapshot: SessionQueueSnapshot | null\n message: string | null\n}\n\nconst QUEUE_FAILURE_MESSAGE = \"队列操作失败\"\n\nconst QUEUED_MESSAGE_STATUSES: readonly string[] = [\n \"pending\",\n \"delivering\",\n \"claimed\",\n \"consumed\",\n \"cancelled\",\n]\n\nfunction toQueuedMessage(value: unknown): QueuedMessage | null {\n if (!isRecord(value)) return null\n const status =\n typeof value.status === \"string\" && QUEUED_MESSAGE_STATUSES.includes(value.status)\n ? (value.status as QueuedMessageStatus)\n : null\n if (\n typeof value.id !== \"string\" ||\n typeof value.content !== \"string\" ||\n typeof value.position !== \"number\" ||\n typeof value.version !== \"number\" ||\n typeof value.created_at !== \"string\" ||\n typeof value.updated_at !== \"string\" ||\n status === null\n ) {\n return null\n }\n const item: QueuedMessage = {\n id: value.id,\n content: value.content,\n position: value.position,\n version: value.version,\n status,\n created_at: value.created_at,\n updated_at: value.updated_at,\n }\n if (typeof value.target_run_id === \"string\") item.target_run_id = value.target_run_id\n if (typeof value.error === \"string\") item.error = value.error\n return item\n}\n\n/**\n * 把一份线格式载荷归一化成快照;结构不合法返回 null。\n * `session_id` 缺失时用 `fallbackSessionId` 补(ack 与广播都会带上它,补值只为防御)。\n */\nfunction toQueueSnapshot(value: unknown, fallbackSessionId: string): SessionQueueSnapshot | null {\n if (!isRecord(value)) return null\n if (\n typeof value.revision !== \"number\" ||\n !Number.isInteger(value.revision) ||\n value.revision < 0\n ) {\n return null\n }\n if (typeof value.paused !== \"boolean\") return null\n if (!Array.isArray(value.items)) return null\n const pauseReason = value.pause_reason\n if (pauseReason !== null && pauseReason !== undefined && typeof pauseReason !== \"string\") {\n return null\n }\n const items: QueuedMessage[] = []\n for (const raw of value.items) {\n const item = toQueuedMessage(raw)\n if (!item) return null\n items.push(item)\n }\n return {\n session_id:\n typeof value.session_id === \"string\" && value.session_id\n ? value.session_id\n : fallbackSessionId,\n revision: value.revision,\n paused: value.paused,\n pause_reason: typeof pauseReason === \"string\" ? pauseReason : null,\n items,\n }\n}\n\n/** 判定一份载荷是不是完整的权威队列快照(广播事件用)。 */\nexport function isSessionQueueSnapshot(value: unknown): value is SessionQueueSnapshot {\n if (!isRecord(value) || typeof value.session_id !== \"string\") return false\n return toQueueSnapshot(value, value.session_id) !== null\n}\n\n/**\n * 是否用 `next` 覆盖 `current`。\n *\n * 规则只有两条:会话身份必须一致(还没拿到过快照时不校验),且 revision 必须严格\n * 更新——相等或更旧一律不采纳,乱序到达的旧快照不会把新状态顶回去。\n */\nexport function shouldApplySnapshot(\n current: SessionQueueSnapshot | undefined,\n next: SessionQueueSnapshot,\n): boolean {\n if (!isSessionQueueSnapshot(next)) return false\n if (current?.session_id && next.session_id !== current.session_id) return false\n return next.revision > (current?.revision ?? -1)\n}\n\n/**\n * 解析 `emitWithAck` 的返回值。\n *\n * - `ok` / `queued` / `conflict` 且能解析成快照 → `snapshot` 有值;\n * - `queued` → `ok=true`:`chat:send` 在运行中改道进了等待队列,调用方要撤掉乐观消息;\n * - `conflict` → `ok=false, conflict=true`(快照可能仍缺失,调用方按 null 处理);\n * - `error` 或结构不合法 → `ok=false, conflict=false`,`message` 为服务端文案或兜底。\n */\nexport function parseQueueAck(response: unknown, fallbackSessionId: string): QueueOperationResult {\n if (!isRecord(response)) {\n return { ok: false, conflict: false, snapshot: null, message: QUEUE_FAILURE_MESSAGE }\n }\n const message =\n typeof response.message === \"string\" && response.message ? response.message : null\n const status = response.status\n if (status !== \"ok\" && status !== \"conflict\" && status !== \"queued\") {\n return { ok: false, conflict: false, snapshot: null, message: message ?? QUEUE_FAILURE_MESSAGE }\n }\n const snapshot = toQueueSnapshot(response, fallbackSessionId)\n if (status === \"conflict\") {\n return { ok: false, conflict: true, snapshot, message: message ?? QUEUE_FAILURE_MESSAGE }\n }\n if (!snapshot) {\n return { ok: false, conflict: false, snapshot: null, message: message ?? QUEUE_FAILURE_MESSAGE }\n }\n return { ok: true, conflict: false, snapshot, message }\n}\n\n/** 等待中的条目才能改正文;已经交给运行或开始执行的条目不再可编辑。 */\nexport function canEditQueuedMessage(item: QueuedMessage): boolean {\n return item.status === \"pending\"\n}\n\n/** 等待中的条目才能删除。 */\nexport function canCancelQueuedMessage(item: QueuedMessage): boolean {\n return item.status === \"pending\"\n}\n\n/**\n * 能否立即补充。条目本身必须是等待中的;\"会话是否正在运行\"由调用方判断——\n * 服务端会在没有可接收补充的任务时返回冲突。\n */\nexport function canDeliverQueuedMessage(item: QueuedMessage): boolean {\n return item.status === \"pending\"\n}\n\nconst QUEUED_MESSAGE_STATUS_LABELS: Record<QueuedMessageStatus, string> = {\n pending: \"待执行\",\n delivering: \"等待接收\",\n claimed: \"\",\n consumed: \"\",\n cancelled: \"\",\n}\n\n/** 面向前端展示的状态文案;已离开队列视图的状态没有文案。 */\nexport function queuedMessageStatusLabel(status: QueuedMessageStatus): string {\n return QUEUED_MESSAGE_STATUS_LABELS[status] ?? \"\"\n}\n\nconst QUEUE_PAUSE_REASON_LABELS: Record<string, string> = {\n user_stop: \"已暂停\",\n run_failed: \"任务异常已暂停\",\n run_unknown: \"任务结束状态未知,已暂停\",\n server_restart: \"服务重启已暂停\",\n}\n\n/** 暂停原因文案;未知原因原样透出,没有原因返回 null。 */\nexport function queuePauseReasonLabel(reason: string | null | undefined): string | null {\n if (!reason) return null\n return QUEUE_PAUSE_REASON_LABELS[reason] ?? reason\n}\n","import { isRecord } from \"../shared/type-guards\"\n\n/** Archived MCP App data. Credentials and executable server configuration are excluded. */\nexport interface McpAppData {\n sourceId: string\n resourceUri: string\n mimeType: string\n resourceMeta: Record<string, unknown>\n toolInput: Record<string, unknown>\n toolResult: Record<string, unknown>\n}\n\nexport interface McpAppArchive extends McpAppData {\n html: string\n plugin: string\n /** Restore the last successful view before delivering a saved failure. */\n previousToolInput?: Record<string, unknown>\n previousToolResult?: Record<string, unknown>\n}\n\nexport function isMcpAppData(value: unknown): value is McpAppData {\n return (\n isRecord(value) &&\n typeof value.sourceId === \"string\" && value.sourceId.length > 0 &&\n typeof value.resourceUri === \"string\" && value.resourceUri.startsWith(\"ui://\") &&\n typeof value.mimeType === \"string\" &&\n isRecord(value.resourceMeta) && isRecord(value.toolInput) && isRecord(value.toolResult)\n )\n}\n\n\n/** Latest model-context state one MCP App saved for its own card. */\nexport interface McpAppContextState {\n revision: string\n content: string\n plugin: string | null\n server_alias: string | null\n}\n\nexport interface McpAppContextUpdate {\n request_id: string\n /** null on the first save; the server rejects a stale revision. */\n expected_revision: string | null\n content: string\n}\n","import type { ChatMessage, ToolCallInfo } from \"../schemas/message\"\nimport type { ContentBlock } from \"../schemas/projection\"\nimport { isMcpAppData, type McpAppData } from \"../schemas/mcp-app\"\n\n/**\n * MCP App 卡片(`_meta.ui` → `tool_ui` block)的共享判定层。\n *\n * 判定逻辑不许各写一份(仓库 CLAUDE.md):agent-react 与 apps/web 都从这里消费卡片的\n * 实例、可见性、身份和终态规则;样式与状态容器(侧栏页签栈等)两侧各自实现。\n */\n\nexport interface ToolUiCard {\n resourceUri?: string\n resourceURI?: string\n resourceHTML?: string\n /** 历史投影标记:绝不重新解析 resourceUri(刷新不重放 MCP/资源读取)。 */\n archived?: boolean\n target: \"inline\" | \"preview\"\n height: number\n title?: string\n /** 留档的 MCP App 来源身份与调用数据(来源 server、ui:// 资源、CSP 元数据)。 */\n mcpApp?: McpAppData\n}\n\nfunction isNonEmptyString(value: unknown): value is string {\n return typeof value === \"string\" && value.trim().length > 0\n}\n\nfunction isPositiveNumber(value: unknown): value is number {\n return typeof value === \"number\" && Number.isFinite(value) && value > 0\n}\n\n/** 严格守卫:target/height 缺失、archived 无留档 HTML、或 mcpApp 来源身份残缺的\n * 卡片一律判无效,消息流、侧栏、toolPreview 事件三处一致降级(不渲染、不发事件、\n * 不推送)。后端 `_tool_ui_meta.py` 总会补齐 target/height 默认值,判无效即数据畸形。 */\nexport function isToolUiCard(value: unknown): value is ToolUiCard {\n if (typeof value !== \"object\" || value === null || Array.isArray(value)) {\n return false\n }\n const raw = value as Record<string, unknown>\n if (raw.target !== \"inline\" && raw.target !== \"preview\") {\n return false\n }\n if (!isPositiveNumber(raw.height)) {\n return false\n }\n if (raw.archived === true && !isNonEmptyString(raw.resourceHTML)) {\n return false\n }\n if (\n !isNonEmptyString(raw.resourceHTML) &&\n !isNonEmptyString(raw.resourceUri) &&\n !isNonEmptyString(raw.resourceURI)\n ) {\n return false\n }\n if (raw.title != null && !isNonEmptyString(raw.title)) {\n return false\n }\n if (raw.mcpApp !== undefined && !isMcpAppData(raw.mcpApp)) {\n return false\n }\n return true\n}\n\nexport type ToolUiCardContentType = \"resource-html\" | \"resource-uri\"\n\n/** 解析卡片实际要渲染的内容。archived 卡片只认留档 HTML,绝不回退到\n * resourceUri——历史恢复/浏览器刷新不得因此重新发起 MCP 资源读取。 */\nexport function resolveToolUiCardContent(\n card: ToolUiCard,\n): { type: ToolUiCardContentType; content: string } | null {\n if (isNonEmptyString(card.resourceHTML)) {\n return { type: \"resource-html\", content: card.resourceHTML }\n }\n if (card.archived) return null\n const uri = isNonEmptyString(card.resourceUri) ? card.resourceUri : card.resourceURI\n return isNonEmptyString(uri) ? { type: \"resource-uri\", content: uri } : null\n}\n\n/** 卡片实例身份/去重键:uri 卡片按内容去重(同一 URI 多次产出只留一份),\n * html 卡片按 toolCallId 去重(同一调用的新 HTML 覆盖旧内容)。 */\nexport function buildToolUiCardKey(\n toolCallId: string,\n type: ToolUiCardContentType,\n content: string,\n): string {\n if (type === \"resource-uri\") {\n return `tool-preview-uri:${content}`\n }\n return `tool-preview:${toolCallId}`\n}\n\n/** 内部「阶段进度」卡片不对用户展示入口。 */\nexport function isInternalStatusToolUiCard(card: { title?: string | null } | null): boolean {\n return card?.title?.trim() === \"阶段进度\"\n}\n\n/** app-dev 会话里的应用预览卡片:走专门的预览页签,不开普通侧栏 artifact。 */\nexport function isAppDevToolUiCard(card: ToolUiCard, isAppDev: boolean): boolean {\n return (\n isAppDev &&\n card.target === \"preview\" &&\n !card.resourceHTML &&\n Boolean(card.resourceUri || card.resourceURI)\n )\n}\n\nexport interface InlineToolUiCardEntry {\n key: string\n toolCallId: string\n card: ToolUiCard\n}\n\n/** 从一轮消息里收集 target=inline 的卡片(渲染进消息流)。 */\nexport function collectInlineToolUiCards(messages: ChatMessage[]): InlineToolUiCardEntry[] {\n return messages.flatMap((message) =>\n (message.blocks ?? []).flatMap((block, index) =>\n block.type === \"tool_ui\" &&\n block.tool_call_id &&\n isToolUiCard(block.content) &&\n block.content.target === \"inline\"\n ? [\n {\n key: `${message.entry_id ?? message.timestamp ?? \"message\"}-${block.tool_call_id}-${index}`,\n toolCallId: block.tool_call_id,\n card: block.content,\n },\n ]\n : [],\n ),\n )\n}\n\nexport interface PreviewToolUiCardEntry {\n key: string\n toolCall: ToolCallInfo\n card: ToolUiCard\n /** 所属消息的 blocks;调用方需要还原卡片所在 block 上下文时用。 */\n blocks: ContentBlock[]\n}\n\n/** 从一轮消息里收集 target=preview 的卡片(进侧栏/面板,不进消息流),\n * 并绑定回所属的 toolCall。 */\nexport function collectPreviewToolUiCards(messages: ChatMessage[]): PreviewToolUiCardEntry[] {\n return messages.flatMap((message) =>\n (message.blocks ?? []).flatMap((block, index) => {\n if (\n block.type !== \"tool_ui\" ||\n !block.tool_call_id ||\n !isToolUiCard(block.content) ||\n block.content.target !== \"preview\"\n ) {\n return []\n }\n const toolCall = (message.tool_calls ?? []).find(\n (candidate) => candidate.id === block.tool_call_id,\n )\n return toolCall\n ? [\n {\n key: `${message.entry_id ?? message.timestamp ?? \"message\"}-${block.tool_call_id}-${index}`,\n toolCall,\n card: block.content,\n blocks: message.blocks ?? [],\n },\n ]\n : []\n }),\n )\n}\n","import type {\n ChatMessage,\n FileContentPart,\n ImageUrlContentPart,\n MessageContent,\n MessageContentPart,\n} from \"./message\"\n\nconst SYSTEM_REMINDER_PATTERN = /^<system-reminder>\\s*[\\s\\S]*?\\s*<\\/system-reminder>$/i\nconst SYSTEM_NOTIFICATION_PATTERN =\n /^<system-notification>\\s*[\\s\\S]*?\\s*<\\/system-notification>$/i\nconst LEGACY_FORK_CONTEXT_MARKERS = [\n \"父智能体在派生你之前已经完成了一些操作。\",\n \"可通过 `read_file` 读取。\",\n \"# 你的任务\",\n]\nconst INTERNAL_CHAT_ERROR_PATTERNS = [\n /\\b(?:ENOENT|EACCES|EPERM)\\b/i,\n /\\[(?:Errno -?\\d+|WinError \\d+)\\]/i,\n /\\b(?:ECONNRESET|ECONNREFUSED|ETIMEDOUT|EHOSTUNREACH|ENETUNREACH|ENOTFOUND|EAI_AGAIN)\\b/i,\n /\\b(?:Connection refused|Connection reset by peer|All connection attempts failed|getaddrinfo failed)\\b/i,\n /(?:^|[\\s(\"'`])\\/(?:root|home|Users|tmp|var|opt|etc)\\//,\n /[A-Za-z]:\\\\(?:Users|Windows|Program Files|AppData)\\\\/i,\n /(?:^|\\n)Traceback \\(most recent call last\\):/,\n /(?:^|\\n)\\s*at\\s+\\S+(?:\\s+\\(|:\\d+:\\d+)/,\n /(?:^|\\n)File \"[^\"]+\", line \\d+/,\n]\nconst SAFE_CHAT_ERROR_PREFIXES = [\n \"沙盒运行环境暂时不可用,请稍后重试。\",\n \"模型服务暂时不可用,请检查模型配置后重试。\",\n]\nconst GENERIC_CHAT_ERROR = \"消息发送失败,请重试。\"\n\n/** Ordinary chat uses business copy; developer mode may retain diagnostics. */\nexport function chatErrorForDisplay(message: string, developer = false): string {\n const normalized = message.trim()\n if (!developer) {\n const safePrefix = SAFE_CHAT_ERROR_PREFIXES.find((prefix) => normalized.startsWith(prefix))\n if (safePrefix) return safePrefix\n }\n if (!developer && /no source matches this model/i.test(normalized)) {\n return \"当前模型暂时不可用,请稍后重试或重新选择模型。\"\n }\n if (!developer && INTERNAL_CHAT_ERROR_PATTERNS.some((pattern) => pattern.test(normalized))) {\n return GENERIC_CHAT_ERROR\n }\n return normalized || GENERIC_CHAT_ERROR\n}\n\nexport function normalizeMessageContent(content: unknown): MessageContent {\n if (typeof content === \"string\") return content\n if (Array.isArray(content)) return content as MessageContentPart[]\n return String(content ?? \"\")\n}\n\nexport function getTextContent(content: MessageContent): string {\n if (typeof content === \"string\") return content\n return content\n .filter((part) => part.type === \"text\")\n .map((part) => part.text)\n .join(\"\")\n}\n\nexport function isSystemReminderText(text: string): boolean {\n return SYSTEM_REMINDER_PATTERN.test(text.trim())\n}\n\nfunction isSystemNotificationText(text: string): boolean {\n return SYSTEM_NOTIFICATION_PATTERN.test(text.trim())\n}\n\nexport function isLegacyForkContextText(text: string): boolean {\n const normalized = text.trim()\n return LEGACY_FORK_CONTEXT_MARKERS.every((marker) => normalized.includes(marker))\n}\n\n/**\n * 平台自己写进去、不该露给用户的内部提示。\n *\n * 服务端的消息导航目录有一份同名同语义的 Python 实现\n * (`server/.../routes/sessions.py` 的 `_is_hidden_internal_message`):客户端靠它决定\n * 渲染不渲染,服务端靠它决定进不进目录。改这里必须同时改那边,否则目录会列出没有对应\n * 行的死条目,或者把内部提示原文当标题露出去。\n */\nexport function isHiddenInternalMessage(\n message: Pick<ChatMessage, \"role\" | \"content\">,\n options: { includeLegacyForkContext?: boolean } = {},\n): boolean {\n if (message.role !== \"user\") return false\n const text = getTextContent(normalizeMessageContent(message.content))\n return (\n isSystemReminderText(text) ||\n isSystemNotificationText(text) ||\n ((options.includeLegacyForkContext ?? true) && isLegacyForkContextText(text))\n )\n}\n\nexport function buildMessageContent(\n text: string,\n attachments: Array<{\n kind: \"file\"\n name: string\n uploadedPath?: string\n textContent?: string | null\n mimeType?: string\n }>,\n): MessageContent {\n if (attachments.length === 0) return text\n const textSegments: string[] = []\n\n if (text.trim()) {\n textSegments.push(text)\n }\n\n for (const attachment of attachments) {\n let fileText: string\n if (attachment.uploadedPath) {\n const displayName = attachment.uploadedPath.split(\"/\").pop() || attachment.name\n fileText = `[附件: ${displayName}] 已上传到工作区路径: ${attachment.uploadedPath}`\n } else if (attachment.textContent) {\n const MAX_TEXT_CHARS = 100_000\n const content =\n attachment.textContent.length > MAX_TEXT_CHARS\n ? `${attachment.textContent.slice(0, MAX_TEXT_CHARS)}\\n\\n[内容已截断,原始共 ${attachment.textContent.length} 字符]`\n : attachment.textContent\n fileText = `[附件: ${attachment.name}]\\n${content}`\n } else {\n fileText = `[附件: ${attachment.name}]`\n }\n textSegments.push(fileText)\n }\n\n return textSegments.join(\"\\n\\n\")\n}\n\nexport function contentPreview(content: MessageContent, maxLen = 80): string {\n const text = getTextContent(content).trim()\n return text.length > maxLen ? `${text.slice(0, maxLen)}…` : text\n}\n\n/** `/` 选中的技能当前处于什么状态,决定智能体要不要先装、先加载。 */\nexport interface SkillMentionAvailability {\n /** 本地已有(内置 / 技能目录 / 会话已加载),直接可用。 */\n local?: boolean\n /** Blade Hub 上该账号是否已安装。本地技能恒为 true。 */\n installed?: boolean\n}\n\n/**\n * Transform a skill mention into a natural language skill invocation.\n * Strips the `<skill>name</skill>` tag from the raw input and prepends the instruction.\n *\n * Hub 技能装没装、加载没加载,用户不需要知道,但智能体需要——所以把状态翻译\n * 成它能直接照做的 CLI 步骤。不传 availability 时按本地技能处理,与旧行为一致。\n */\nexport function transformSlashCommand(\n skillName: string,\n rawInput: string,\n { local = true, installed = true }: SkillMentionAvailability = {},\n): string {\n const prompt = rawInput.replace(`<skill>${skillName}</skill>`, \"\").trim()\n\n if (local) {\n return prompt\n ? `请使用 ${skillName} skill 完成任务\\n${prompt}`\n : `请使用 ${skillName} skill 完成任务`\n }\n\n const steps = installed\n ? `请先运行 blade hub skill use ${skillName} 加载技能`\n : `该技能尚未安装。请先运行 blade hub skill install ${skillName} 安装,` +\n `再运行 blade hub skill use ${skillName} 加载`\n return prompt ? `${steps},然后完成任务:\\n${prompt}` : `${steps},然后使用它完成任务`\n}\n\nconst ATTACHMENT_TAG_RE = /\\[附件:\\s*([^\\]]+)\\](?:[ \\t]*已上传到工作区路径:[ \\t]*([^\\r\\n]+))?/g\n// 来自 addContext 的 context 在发送时序列化为独立 text part:`[上下文: LABEL]\\nCONTENT`\n// 整块 part 匹配而非行内替换,避免破坏正文中可能出现的\"[上下文:\"字样\nconst CONTEXT_PART_RE = /^\\[上下文:\\s*([^\\]]+)\\]\\n([\\s\\S]*)$/\n\nexport interface ParsedTextAttachment {\n name: string\n uploadedPath?: string\n}\n\nexport interface ParsedTextContext {\n label: string\n content: string\n}\n\n/**\n * Extract `[附件: name]` and `[上下文: label]` tags from text parts and return\n * the cleaned text plus the collected attachment / context metadata. 每个 text\n * part 独立匹配,以避免跨 part 拼接打乱正则。\n */\nexport function extractTextAttachments(content: MessageContent): {\n cleanText: string\n attachments: ParsedTextAttachment[]\n contexts: ParsedTextContext[]\n} {\n if (typeof content === \"string\") {\n const attachments: ParsedTextAttachment[] = []\n const contexts: ParsedTextContext[] = []\n const ctxMatch = CONTEXT_PART_RE.exec(content)\n let working = content\n if (ctxMatch) {\n contexts.push({ label: ctxMatch[1].trim(), content: ctxMatch[2].trim() })\n working = \"\"\n }\n for (const match of working.matchAll(ATTACHMENT_TAG_RE)) {\n attachments.push({\n name: match[1].trim(),\n uploadedPath: match[2]?.trim() || undefined,\n })\n }\n return {\n cleanText: working.replace(ATTACHMENT_TAG_RE, \"\"),\n attachments,\n contexts,\n }\n }\n\n const attachments: ParsedTextAttachment[] = []\n const contexts: ParsedTextContext[] = []\n const cleanParts: string[] = []\n\n for (const part of content) {\n if (part.type !== \"text\") continue\n\n const ctxMatch = CONTEXT_PART_RE.exec(part.text)\n if (ctxMatch) {\n contexts.push({ label: ctxMatch[1].trim(), content: ctxMatch[2].trim() })\n continue\n }\n\n let hasAttachment = false\n for (const match of part.text.matchAll(ATTACHMENT_TAG_RE)) {\n attachments.push({\n name: match[1].trim(),\n uploadedPath: match[2]?.trim() || undefined,\n })\n hasAttachment = true\n }\n if (hasAttachment) {\n const remaining = part.text.replace(ATTACHMENT_TAG_RE, \"\")\n if (remaining.trim()) cleanParts.push(remaining)\n } else {\n cleanParts.push(part.text)\n }\n }\n\n return { cleanText: cleanParts.join(\"\\n\"), attachments, contexts }\n}\n\nexport function getImageParts(content: MessageContent): ImageUrlContentPart[] {\n if (typeof content === \"string\") return []\n return content.filter((part): part is ImageUrlContentPart => part.type === \"image_url\")\n}\n\nexport function getFileParts(content: MessageContent): FileContentPart[] {\n if (typeof content === \"string\") return []\n return content.filter((part): part is FileContentPart => part.type === \"file\")\n}\n\ninterface MessageGroup {\n root: ChatMessage | null\n childLoops: { loopName: string; messages: ChatMessage[] }[]\n}\n\nexport function groupMessagesByLoop(messages: ChatMessage[]): MessageGroup[] {\n const groups: MessageGroup[] = []\n let currentGroup: MessageGroup | null = null\n\n for (const msg of messages) {\n const loop = msg.loop_name ?? \"root\"\n\n if (loop === \"root\") {\n currentGroup = { root: msg, childLoops: [] }\n groups.push(currentGroup)\n } else {\n if (!currentGroup) {\n currentGroup = { root: null, childLoops: [] }\n groups.push(currentGroup)\n }\n const existingLoop = currentGroup.childLoops.find((l) => l.loopName === loop)\n if (existingLoop) {\n existingLoop.messages.push(msg)\n } else {\n currentGroup.childLoops.push({ loopName: loop, messages: [msg] })\n }\n }\n }\n\n return groups\n}\n","import type { ChatMessage, CompactionInfo, MessageContent, ToolCallInfo } from \"../schemas/message\"\nimport { normalizeMessageContent } from \"../schemas/message-utils\"\nimport type { ContentBlock, PatchEnvelope, TurnProjection } from \"../schemas/projection\"\nimport { contextProjectionData } from \"../schemas/context\"\nimport type { ReplaySpeed, ReplayState, SessionStatus } from \"../schemas/session\"\nimport { isRecord } from \"../shared/type-guards\"\nimport { EMPTY_SESSION_QUEUE, shouldApplySnapshot, type SessionQueueSnapshot } from \"./queue\"\n\n/** 一次 AskUserQuestion 的用户作答(选项选择 + 自定义输入 + 可选补充)。 */\nexport interface AskUserAnswerData {\n selections: Record<number, number[]>\n custom: Record<number, string>\n /** 选完选项后的自由补充,空着就是没有。 */\n note?: string\n}\n\nexport interface AgentLoopInfo {\n toolCallId: string\n description: string\n status: \"running\" | \"done\" | \"error\" | \"cancelled\" | \"awaiting_answer\"\n}\n\nexport interface ActiveCompactionState extends CompactionInfo {\n turn_id: string\n status: \"streaming\" | \"completed\" | \"paused\" | \"failed\" | \"interrupted\"\n}\n\nexport type ConnectionStatus = \"connecting\" | \"connected\" | \"reconnecting\" | \"disconnected\"\n\n/**\n * 一个会话的完整快照。引用不可变:任何变更都会产生新对象,\n * 满足 React `useSyncExternalStore` / Vue `shallowRef` 的订阅契约。\n */\nexport interface SessionState {\n sessionId: string\n /** 服务端投影的原始 turn 列表(按 sequence 有序)。 */\n turns: TurnProjection[]\n /** 由 turns 物化出的聊天消息列表,UI 直接渲染。 */\n messages: ChatMessage[]\n /** 智能体是否正在流式回复。 */\n isStreaming: boolean\n /** 会话状态(running / completed / failed / waiting_for_input / interrupted …)。 */\n status: SessionStatus | null\n /** 当前模式(planning / executing),来自 mode_change 事件。 */\n mode: \"planning\" | \"executing\" | null\n /** Socket.IO 连接状态(同一 client 下所有会话共享)。 */\n connection: ConnectionStatus\n /** 最近一次运行错误消息(system:error 等)。 */\n errorMessage: string | null\n askAnswers: Record<string, AskUserAnswerData>\n agentLoops: Record<string, AgentLoopInfo>\n activeCompaction: ActiveCompactionState | null\n /** 回放(演示 / 彩排)状态;不是回放会话时为 null。 */\n replay: ReplaySnapshot | null\n /** 服务端持久化的等待消息队列快照;只在 revision 更新时替换。 */\n queue: SessionQueueSnapshot\n /** 当前身份对这个会话的权限;\"viewer\" 表示只读(分享链接打开的)。 */\n viewerRole: \"owner\" | \"viewer\" | null\n /** Stable anchor for the next older projected page. */\n nextBefore: string | null\n loadingOlder: boolean\n}\n\n/** 回放会话的快照视图,由服务端的 replay_state 归一化而来。 */\nexport interface ReplaySnapshot {\n /** 仍在按录制内容走;转自主运行后为 false。 */\n isReplay: boolean\n speed: ReplaySpeed\n sourceSessionId: string | null\n}\n\n/** 把服务端的 replay_state 归一化成快照;不是回放会话时返回 null。 */\nexport function toReplaySnapshot(raw: ReplayState | null | undefined): ReplaySnapshot | null {\n if (!raw || !raw.status) return null\n return {\n isReplay: raw.status === \"replay\",\n speed: raw.speed ?? 1,\n sourceSessionId: raw.source_session_id ?? null,\n }\n}\n\nexport function createInitialSessionState(sessionId: string): SessionState {\n return {\n sessionId,\n turns: [],\n messages: [],\n isStreaming: false,\n status: null,\n mode: null,\n connection: \"disconnected\",\n errorMessage: null,\n askAnswers: {},\n agentLoops: {},\n activeCompaction: null,\n replay: null,\n queue: EMPTY_SESSION_QUEUE,\n viewerRole: null,\n nextBefore: null,\n loadingOlder: false,\n }\n}\n\nfunction parseAgentDescription(argumentsJson: string): string {\n try {\n return JSON.parse(argumentsJson)?.description ?? \"子智能体\"\n } catch {\n return \"子智能体\"\n }\n}\n\n/** 与 react 端 display-utils.formatToolName 保持一致:去掉 provider 前缀(如 \"fork:Agent\" → \"Agent\")。 */\nfunction normalizedToolName(name: string): string {\n const separatorIndex = name.lastIndexOf(\":\")\n return separatorIndex >= 0 ? name.slice(separatorIndex + 1) : name\n}\n\nfunction inferLoopStatusFromMessages(messages: ChatMessage[]): AgentLoopInfo[\"status\"] {\n const toolCalls = messages.flatMap((message) => message.tool_calls ?? [])\n if (messages.some((message) => message.status === \"streaming\")) return \"running\"\n if (messages.some((message) => message.status === \"failed\")) return \"error\"\n if (toolCalls.some((toolCall) => toolCall.status === \"awaiting_answer\")) return \"awaiting_answer\"\n if (toolCalls.some((toolCall) => toolCall.status === \"error\")) return \"error\"\n if (toolCalls.some((toolCall) => toolCall.status === \"cancelled\")) return \"cancelled\"\n if (toolCalls.some((toolCall) => toolCall.status === \"pending\")) return \"running\"\n return \"done\"\n}\n\nfunction inferLoopStatusFromTurns(\n turns: TurnProjection[],\n messages: ChatMessage[],\n): AgentLoopInfo[\"status\"] {\n const latestAgentNotification = [...turns]\n .reverse()\n .flatMap((turn) => turn.blocks)\n .find((block) => {\n if (block.type !== \"system_notification\" || !isRecord(block.content)) return false\n return (\n block.content.notification_type === \"agent:start\" ||\n block.content.notification_type === \"agent:end\"\n )\n })\n if (\n latestAgentNotification?.type === \"system_notification\" &&\n isRecord(latestAgentNotification.content)\n ) {\n const notificationType = latestAgentNotification.content.notification_type\n const status = latestAgentNotification.content.status\n if (notificationType === \"agent:start\" || status === \"running\") return \"running\"\n if (status === \"error\") return \"error\"\n if (status === \"cancelled\") return \"cancelled\"\n }\n return inferLoopStatusFromMessages(messages)\n}\n\nfunction toSelectionMap(value: unknown): Record<number, number[]> {\n if (!isRecord(value)) return {}\n const entries = Object.entries(value)\n .map(([questionKey, optionIndexes]) => {\n if (!Array.isArray(optionIndexes)) return null\n const parsedIndexes = optionIndexes\n .map((item) => (typeof item === \"number\" ? item : Number(item)))\n .filter((item) => Number.isInteger(item))\n return [Number(questionKey), parsedIndexes] as const\n })\n .filter((entry): entry is readonly [number, number[]] => entry !== null)\n return Object.fromEntries(entries) as Record<number, number[]>\n}\n\nfunction toCustomMap(value: unknown): Record<number, string> {\n if (!isRecord(value)) return {}\n const entries = Object.entries(value)\n .filter(([, text]) => typeof text === \"string\")\n .map(([questionKey, text]) => [Number(questionKey), text] as const)\n return Object.fromEntries(entries) as Record<number, string>\n}\n\nfunction extractAskAnswers(turns: TurnProjection[]): Record<string, AskUserAnswerData> {\n const answers: Record<string, AskUserAnswerData> = {}\n for (const turn of turns) {\n for (const block of turn.blocks) {\n if (block.type !== \"ask_user_answer\" || typeof block.tool_call_id !== \"string\") continue\n if (!isRecord(block.content)) continue\n const note = typeof block.content.note === \"string\" ? block.content.note.trim() : \"\"\n answers[block.tool_call_id] = {\n selections: toSelectionMap(block.content.selections),\n custom: toCustomMap(block.content.custom),\n ...(note ? { note } : {}),\n }\n }\n }\n return answers\n}\n\nfunction parentForkToolCallIdFromTurn(turn: TurnProjection): string | null {\n if (\n typeof turn.parent_fork_tool_call_id === \"string\" &&\n turn.parent_fork_tool_call_id.length > 0\n ) {\n return turn.parent_fork_tool_call_id\n }\n for (const block of turn.blocks) {\n if (block.type !== \"system_notification\" || !isRecord(block.content)) continue\n const metadata = block.content.metadata\n if (!isRecord(metadata)) continue\n const parentId = metadata.parent_fork_tool_call_id\n if (typeof parentId === \"string\" && parentId.length > 0) return parentId\n }\n return null\n}\n\nfunction buildMessageContent(turn: TurnProjection): MessageContent {\n const textBlocks = turn.blocks.filter((block) => block.type === \"text\")\n if (textBlocks.length === 0) return \"\"\n if (textBlocks.length === 1) return normalizeMessageContent(textBlocks[0].content)\n return textBlocks\n .map((block) => {\n if (typeof block.content === \"string\") return block.content\n return JSON.stringify(block.content)\n })\n .join(\"\")\n}\n\nfunction workspaceNotificationContent(turn: TurnProjection): string {\n const block = turn.blocks.find(\n (candidate) =>\n candidate.type === \"system_notification\" &&\n isRecord(candidate.content) &&\n candidate.content.notification_type === \"workspace_change\",\n )\n if (!block || !isRecord(block.content)) return \"\"\n const title = typeof block.content.title === \"string\" ? block.content.title.trim() : \"\"\n const detail = typeof block.content.detail === \"string\" ? block.content.detail.trim() : \"\"\n return [title ? `**${title}**` : \"\", detail].filter(Boolean).join(\"\\n\\n\")\n}\n\nfunction askUserAnswerContent(turn: TurnProjection): string | null {\n const answerBlock = turn.blocks.find((block) => block.type === \"ask_user_answer\")\n if (!answerBlock || !isRecord(answerBlock.content)) return null\n const answer = answerBlock.content.answer\n return typeof answer === \"string\" && answer.trim().length > 0 ? answer : null\n}\n\nfunction buildReasoning(turn: TurnProjection): string | undefined {\n const thinking = turn.blocks\n .filter((block) => block.type === \"thinking\")\n .map((block) => (typeof block.content === \"string\" ? block.content : JSON.stringify(block.content)))\n .filter(Boolean)\n if (thinking.length === 0) return undefined\n return thinking.join(\"\\n\\n\")\n}\n\nfunction isModeChangeContent(value: unknown): value is { from: string; to: string } {\n return (\n typeof value === \"object\" &&\n value !== null &&\n typeof (value as { from?: unknown }).from === \"string\" &&\n typeof (value as { to?: unknown }).to === \"string\"\n )\n}\n\nexport function extractModeFromBlocks(blocks: ContentBlock[]): \"planning\" | \"executing\" | null {\n const modeBlock = blocks.find((block) => block.type === \"mode_change\")\n if (modeBlock && isModeChangeContent(modeBlock.content)) {\n return modeBlock.content.to === \"planning\" || modeBlock.content.to === \"executing\"\n ? modeBlock.content.to\n : null\n }\n return null\n}\n\nfunction projectionToMessage(turn: TurnProjection): ChatMessage | null {\n if (turn.kind === \"context\") {\n const context = contextProjectionData(turn)\n if (!context) return null\n return {\n role: \"assistant\",\n content: \"\",\n kind: \"context\",\n context,\n loop_name: turn.loop_id,\n entry_id: turn.turn_id,\n status: turn.status,\n }\n }\n if (turn.kind === \"compaction\" && turn.compaction_id) {\n return {\n role: \"assistant\",\n content: turn.summary_preview ?? \"\",\n kind: \"compaction\",\n loop_name: turn.loop_id,\n entry_id: turn.turn_id,\n status: turn.status,\n compaction: {\n compaction_id: turn.compaction_id,\n summary_preview: turn.summary_preview,\n summary_full: turn.summary_full,\n archived_count: turn.archived_count,\n archived_files: turn.archived_files,\n archived_tool_calls: turn.archived_tool_calls,\n tokens_before: turn.tokens_before,\n tokens_after: turn.tokens_after,\n saved_ratio: turn.saved_ratio,\n trigger: turn.trigger,\n failure_reason: turn.failure_reason,\n fallback_applied: turn.fallback_applied,\n },\n }\n }\n\n const planningBlock = turn.blocks.find(\n (block) => block.type === \"mode_change\" || block.type === \"plan_status\",\n )\n if (planningBlock) {\n if (planningBlock.type === \"plan_status\") {\n return {\n role: \"tool\",\n content:\n typeof planningBlock.content === \"string\"\n ? planningBlock.content\n : JSON.stringify(planningBlock.content ?? {}, null, 2),\n kind: \"plan_status\",\n loop_name: turn.loop_id,\n entry_id: turn.turn_id,\n status: turn.status,\n }\n }\n return {\n role: \"assistant\",\n content:\n typeof planningBlock.content === \"string\"\n ? planningBlock.content\n : JSON.stringify(planningBlock.content ?? {}),\n kind: planningBlock.type,\n loop_name: turn.loop_id,\n entry_id: turn.turn_id,\n status: turn.status,\n }\n }\n\n const askAnswer = askUserAnswerContent(turn)\n if (askAnswer !== null) {\n return {\n role: \"user\",\n content: askAnswer,\n blocks: turn.blocks,\n loop_name: turn.loop_id,\n entry_id: turn.turn_id,\n status: turn.status,\n ...(typeof turn.duration_ms === \"number\" ? { duration_ms: turn.duration_ms } : {}),\n ...(turn.started_at ? { timestamp: turn.started_at } : {}),\n }\n }\n\n const content = buildMessageContent(turn) || workspaceNotificationContent(turn)\n const reasoning = buildReasoning(turn)\n const toolCalls: ToolCallInfo[] | undefined =\n turn.tool_calls.length > 0\n ? turn.tool_calls.map((toolCall) => ({\n id: toolCall.id,\n name: toolCall.tool_name,\n display_name: toolCall.display_name,\n arguments: toolCall.arguments,\n result: toolCall.result ?? undefined,\n pending_question_ref: toolCall.pending_question_ref ?? undefined,\n status:\n toolCall.status === \"pending\" ||\n toolCall.status === \"awaiting_answer\" ||\n toolCall.status === \"done\" ||\n toolCall.status === \"error\" ||\n toolCall.status === \"cancelled\"\n ? toolCall.status\n : \"pending\",\n ...(typeof toolCall.duration_ms === \"number\" ? { duration_ms: toolCall.duration_ms } : {}),\n }))\n : undefined\n\n if (turn.role === \"system\" && !content && !toolCalls?.length) {\n return null\n }\n\n return {\n role: turn.role === \"system\" ? \"assistant\" : turn.role,\n content,\n blocks: turn.blocks,\n ...(reasoning ? { reasoning } : {}),\n ...(toolCalls ? { tool_calls: toolCalls } : {}),\n loop_name: turn.loop_id,\n entry_id: turn.turn_id,\n status: turn.status,\n ...(typeof turn.duration_ms === \"number\" ? { duration_ms: turn.duration_ms } : {}),\n ...(turn.started_at ? { timestamp: turn.started_at } : {}),\n ...(turn.memory_refs?.length ? { memory_refs: turn.memory_refs } : {}),\n }\n}\n\nconst messageProjectionCache = new WeakMap<TurnProjection, ChatMessage | null>()\n\nfunction cachedProjectionToMessage(turn: TurnProjection): ChatMessage | null {\n if (messageProjectionCache.has(turn)) {\n return messageProjectionCache.get(turn) ?? null\n }\n const message = projectionToMessage(turn)\n messageProjectionCache.set(turn, message)\n return message\n}\n\nfunction rebuildAgentLoops(\n turns: TurnProjection[],\n messages: ChatMessage[],\n): Record<string, AgentLoopInfo> {\n const childLoopNames = [\n ...new Set(turns.map((turn) => turn.loop_id).filter((name) => name !== \"root\")),\n ]\n if (childLoopNames.length === 0) return {}\n\n const agentToolCalls = messages\n .filter((message) => message.role === \"assistant\" && (message.loop_name ?? \"root\") === \"root\")\n .flatMap((message) => message.tool_calls ?? [])\n .filter((toolCall) => normalizedToolName(toolCall.name) === \"Agent\")\n\n const loops: Record<string, AgentLoopInfo> = {}\n const agentToolCallsById = new Map(agentToolCalls.map((toolCall) => [toolCall.id, toolCall]))\n const explicitParentToolCallIds = new Set(\n turns.map(parentForkToolCallIdFromTurn).filter((id): id is string => id !== null),\n )\n const usedToolCallIds = new Set<string>()\n for (const loopName of childLoopNames) {\n const loopMessages = messages.filter((message) => (message.loop_name ?? \"root\") === loopName)\n const loopTurns = turns.filter((turn) => turn.loop_id === loopName)\n const parentToolCallId = loopTurns.map(parentForkToolCallIdFromTurn).find(Boolean)\n const explicitToolCall =\n parentToolCallId && !usedToolCallIds.has(parentToolCallId)\n ? (agentToolCallsById.get(parentToolCallId) ?? null)\n : null\n const fallbackToolCall =\n explicitToolCall === null\n ? agentToolCalls.find(\n (toolCall) =>\n !usedToolCallIds.has(toolCall.id) && !explicitParentToolCallIds.has(toolCall.id),\n )\n : null\n const toolCall = explicitToolCall ?? fallbackToolCall\n if (!toolCall) continue\n usedToolCallIds.add(toolCall.id)\n loops[loopName] = {\n toolCallId: toolCall.id,\n description: parseAgentDescription(toolCall.arguments),\n status: inferLoopStatusFromTurns(loopTurns, loopMessages),\n }\n }\n return loops\n}\n\nfunction materialize(turns: TurnProjection[]) {\n const projectedMessages = turns\n .map(cachedProjectionToMessage)\n .filter((message): message is ChatMessage => message !== null)\n const messages = projectedMessages.filter((message, index, allMessages) => {\n if (!message.blocks?.some((block) => block.type === \"ask_user_answer\")) return true\n const next = allMessages[index + 1]\n return !(next?.role === \"user\" && next.content === message.content)\n })\n const activeCompaction = [...turns]\n .reverse()\n .find(\n (turn): turn is TurnProjection =>\n turn.kind === \"compaction\" &&\n turn.status === \"streaming\" &&\n typeof turn.compaction_id === \"string\",\n )\n return {\n messages,\n agentLoops: rebuildAgentLoops(turns, projectedMessages),\n activeCompaction: activeCompaction\n ? {\n turn_id: activeCompaction.turn_id,\n status: activeCompaction.status,\n compaction_id: activeCompaction.compaction_id!,\n summary_preview: activeCompaction.summary_preview,\n summary_full: activeCompaction.summary_full,\n archived_count: activeCompaction.archived_count,\n archived_files: activeCompaction.archived_files,\n archived_tool_calls: activeCompaction.archived_tool_calls,\n tokens_before: activeCompaction.tokens_before,\n tokens_after: activeCompaction.tokens_after,\n saved_ratio: activeCompaction.saved_ratio,\n trigger: activeCompaction.trigger,\n failure_reason: activeCompaction.failure_reason,\n fallback_applied: activeCompaction.fallback_applied,\n }\n : null,\n }\n}\n\nconst ERROR_ANCHOR_PREFIX = \"error-anchor:\"\n\nfunction orderTurns(turns: TurnProjection[]) {\n for (let index = 1; index < turns.length; index += 1) {\n if (turns[index - 1].sequence > turns[index].sequence) {\n return [...turns].sort((left, right) => left.sequence - right.sequence)\n }\n }\n return turns\n}\n\nexport function reconcileOptimisticUserTurns(\n currentTurns: TurnProjection[],\n incomingTurns: TurnProjection[],\n): TurnProjection[] {\n return reconcileUserTurns(currentTurns, incomingTurns, true, false)\n}\n\n/** Reconcile a bulk authoritative window only by an echoed request identity.\n * Positional fallback is reserved for a single live turn from an older server. */\nexport function reconcileHistoricalUserTurns(\n currentTurns: TurnProjection[],\n incomingTurns: TurnProjection[],\n): TurnProjection[] {\n // keepUnclaimedOptimistic=true:这批全量快照可能是在本地刚发出一条新\n // 乐观发言之前就拍下的,还不知道它的存在。只按 incomingTurns 重建整个\n // 列表会把这条还没被任何一批快照/事件认领过的本地发言直接丢掉,直到\n // 下一次增量事件到达才重新出现——这段\"消失又出现\"的窗口期会让消费方\n // (比如 MessageList.tsx 的\"新发言顶置\")把\"最新用户发言\"短暂退回上一条,\n // 误判成锚点回滚而提前释放顶置。没被这批快照认领的本地乐观发言应该原样\n // 保留在结果里,等真正的确认/回滚事件到达时再处理。\n return reconcileUserTurns(currentTurns, incomingTurns, false, true)\n}\n\nfunction reconcileUserTurns(\n currentTurns: TurnProjection[],\n incomingTurns: TurnProjection[],\n allowLiveFallback: boolean,\n keepUnclaimedOptimistic: boolean,\n): TurnProjection[] {\n const preservedTurns = preserveClientRenderIds(currentTurns, incomingTurns)\n const optimisticUserTurns = currentTurns.filter(\n (turn) =>\n turn.role === \"user\" &&\n (turn.kind ?? \"message\") === \"message\" &&\n turn.turn_id.startsWith(\"local-user-\"),\n )\n const optimisticByRequestId = new Map(\n optimisticUserTurns.map((turn) => [\n turn.turn_id.slice(\"local-user-\".length),\n turn,\n ]),\n )\n const currentTurnIds = new Set(currentTurns.map((turn) => turn.turn_id))\n const claimedOptimisticIds = new Set<string>()\n const reconciled = preservedTurns.map((turn) => {\n const exactOptimistic =\n typeof turn.client_request_id === \"string\"\n ? optimisticByRequestId.get(turn.client_request_id)\n : undefined\n if (\n exactOptimistic &&\n !claimedOptimisticIds.has(exactOptimistic.turn_id) &&\n isUserConfirmation(turn)\n ) {\n claimedOptimisticIds.add(exactOptimistic.turn_id)\n return { ...turn, client_render_id: exactOptimistic.turn_id }\n }\n const fallbackOptimistic = optimisticUserTurns.find(\n (candidate) => !claimedOptimisticIds.has(candidate.turn_id),\n )\n if (\n allowLiveFallback &&\n typeof turn.client_request_id !== \"string\" &&\n fallbackOptimistic &&\n isUserConfirmation(turn) &&\n !turn.turn_id.startsWith(\"local-user-\") &&\n !currentTurnIds.has(turn.turn_id)\n ) {\n claimedOptimisticIds.add(fallbackOptimistic.turn_id)\n return { ...turn, client_render_id: fallbackOptimistic.turn_id }\n }\n return turn\n })\n const result =\n claimedOptimisticIds.size === 0\n ? reconciled\n : reconciled.filter((turn) => !claimedOptimisticIds.has(turn.turn_id))\n if (!keepUnclaimedOptimistic) return result\n // 只补回真正从结果里缺席的乐观 turn——claimedOptimisticIds 只覆盖\"这次调用\n // 里用 client_request_id/位置兜底重新认领过\"的情况,reconcile 一个已经\n // 包含这条乐观 turn 本身的列表(比如 upsertTurn 认领替换完之后,\n // withTurns 内部拿最终列表对自己再 reconcile 一遍)时,它既没被这次调用\n // 认领、也已经原样出现在 result 里,不能再重复拼一份。\n const resultIds = new Set(result.map((turn) => turn.turn_id))\n const unclaimedOptimisticTurns = optimisticUserTurns.filter(\n (turn) => !claimedOptimisticIds.has(turn.turn_id) && !resultIds.has(turn.turn_id),\n )\n return unclaimedOptimisticTurns.length === 0\n ? result\n : orderTurns([...result, ...unclaimedOptimisticTurns])\n}\n\nfunction isUserConfirmation(turn: TurnProjection): boolean {\n return (\n (turn.role === \"user\" && (turn.kind ?? \"message\") === \"message\") ||\n turn.blocks.some((block) => block.type === \"ask_user_answer\")\n )\n}\n\n/** Preserve render identity only for the same authoritative turn. Bulk history\n * replacement must not infer that an unrelated historical user confirms a\n * retained optimistic user turn. */\nfunction preserveClientRenderIds(\n currentTurns: TurnProjection[],\n incomingTurns: TurnProjection[],\n): TurnProjection[] {\n const currentById = new Map(currentTurns.map((turn) => [turn.turn_id, turn]))\n return incomingTurns.map((turn) => {\n const current = currentById.get(turn.turn_id)\n if (current) {\n const currentRenderId = current.client_render_id\n return turn.client_render_id || !currentRenderId\n ? turn\n : { ...turn, client_render_id: currentRenderId }\n }\n return turn\n })\n}\n\nfunction areAgentLoopsEqual(\n left: Record<string, AgentLoopInfo> | undefined,\n right: Record<string, AgentLoopInfo>,\n) {\n if (!left) return Object.keys(right).length === 0\n const leftEntries = Object.entries(left)\n const rightKeys = Object.keys(right)\n if (leftEntries.length !== rightKeys.length) return false\n return leftEntries.every(([key, value]) => {\n const next = right[key]\n return (\n next !== undefined &&\n value.toolCallId === next.toolCallId &&\n value.description === next.description &&\n value.status === next.status\n )\n })\n}\n\n/**\n * 用一份新的 turn 列表重建会话状态。\n * addErrorMessage 注入的 role===\"error\" 消息不在 turns 里,默认会被物化过程抹掉;\n * 这里沿用锚点策略:只保留锚定在\"当前最后一个 turn\"上的错误气泡,\n * turn 推进(新消息 / rewind / 重连)时旧错误自动消失。\n */\nexport function withTurns(state: SessionState, turns: TurnProjection[]): SessionState {\n const orderedTurns = orderTurns(reconcileHistoricalUserTurns(state.turns, turns))\n const { messages, agentLoops, activeCompaction } = materialize(orderedTurns)\n const isWaitingForInput = orderedTurns.some((turn) =>\n turn.tool_calls.some((toolCall) => toolCall.status === \"awaiting_answer\"),\n )\n const stableAgentLoops = areAgentLoopsEqual(state.agentLoops, agentLoops)\n ? state.agentLoops\n : agentLoops\n const lastTurnId = orderedTurns[orderedTurns.length - 1]?.turn_id ?? null\n const preservedErrors = lastTurnId\n ? state.messages.filter(\n (m) =>\n m.role === \"error\" &&\n typeof m.entry_id === \"string\" &&\n m.entry_id.startsWith(`${ERROR_ANCHOR_PREFIX}${lastTurnId}:`),\n )\n : []\n const turnById = new Map(orderedTurns.map((turn) => [turn.turn_id, turn]))\n const messagesWithRenderIds = messages.map((message) => {\n if (!message.entry_id) return message\n const renderId = turnById.get(message.entry_id)?.client_render_id\n return renderId ? { ...message, render_id: renderId } : message\n })\n const mergedMessages =\n preservedErrors.length > 0\n ? [...messagesWithRenderIds, ...preservedErrors]\n : messagesWithRenderIds\n const latestMode = [...orderedTurns]\n .reverse()\n .map((turn) => extractModeFromBlocks(turn.blocks))\n .find((mode): mode is \"planning\" | \"executing\" => mode !== null)\n const askAnswersFromHistory = extractAskAnswers(orderedTurns)\n const presentToolCallIds = new Set(\n orderedTurns.flatMap((turn) => turn.tool_calls.map((toolCall) => toolCall.id)),\n )\n const askAnswers: Record<string, AskUserAnswerData> = { ...askAnswersFromHistory }\n for (const [toolCallId, answer] of Object.entries(state.askAnswers)) {\n if (!(toolCallId in askAnswers) && presentToolCallIds.has(toolCallId)) {\n askAnswers[toolCallId] = answer\n }\n }\n return {\n ...state,\n turns: orderedTurns,\n messages: mergedMessages,\n agentLoops: stableAgentLoops,\n activeCompaction,\n askAnswers,\n mode: latestMode ?? state.mode,\n // 历史恢复时 chat:end(paused) 可能已不在 socket replay 缓存中;\n // awaiting_answer 是投影里的持久权威状态,必须据此恢复问答交互。\n status: isWaitingForInput ? \"waiting_for_input\" : state.status,\n }\n}\n\n/**\n * 安装一份服务端权威队列快照。旧 revision、别的会话或结构不合法的快照一律不采纳,\n * 直接返回原 state——引用不变,订阅者不会收到多余通知。\n */\nexport function withQueue(state: SessionState, snapshot: SessionQueueSnapshot): SessionState {\n if (!shouldApplySnapshot(state.queue, snapshot)) return state\n return { ...state, queue: snapshot }\n}\n\nlet localTurnCounter = 0\n\nexport function addUserMessage(\n state: SessionState,\n content: MessageContent,\n clientRequestId?: string,\n): SessionState {\n localTurnCounter += 1\n const turnId = `local-user-${clientRequestId ?? `${Date.now()}-${localTurnCounter}`}`\n const optimisticTurn: TurnProjection = {\n id: turnId,\n sequence: Math.max(0, ...state.turns.map((turn) => turn.sequence)) + 1,\n turn_id: turnId,\n // 乐观态就自赋,跟服务端确认后 reconcileUserTurns 补上的\n // client_render_id(= 乐观 turn 自己的 turn_id)保持同一个值,\n // 消费方才能拿它当\"确认前后不变\"的稳定标识使用。\n client_render_id: turnId,\n loop_id: \"root\",\n role: \"user\",\n status: \"streaming\",\n blocks: [{ type: \"text\", content }],\n tool_calls: [],\n model: null,\n usage: null,\n duration_ms: 0,\n }\n return withTurns(state, [...state.turns, optimisticTurn])\n}\n\nexport function upsertTurn(state: SessionState, turn: TurnProjection): SessionState {\n let existing = [...state.turns]\n const [nextTurn] = reconcileOptimisticUserTurns(existing, [turn])\n const claimedOptimisticId = nextTurn.client_render_id\n if (claimedOptimisticId?.startsWith(\"local-user-\")) {\n existing = existing.filter((item) => item.turn_id !== claimedOptimisticId)\n }\n const index = existing.findIndex((item) => item.turn_id === nextTurn.turn_id)\n if (index >= 0) {\n existing[index] = nextTurn\n } else {\n existing.push(nextTurn)\n }\n // 传 { ...state, turns: existing } 而不是原始 state:上面已经把这条乐观\n // turn 从 existing 里认领/替换掉了,但 state.turns 本身还留着旧的那条。\n // withTurns 内部会用 reconcileHistoricalUserTurns 把\"没被这批 incoming\n // 认领的本地乐观 turn\"保留下来(针对真正的全量快照场景,见该函数注释);\n // 如果这里传原始 state,它会把 state.turns 里这条已经被上面处理过、但\n // 这次传的 incoming(existing)里已查不到匹配 client_request_id 的旧乐观\n // turn 误判成\"还没被认领\",重新拼回去,造成同一条发言重复两份。\n return withTurns({ ...state, turns: existing }, existing)\n}\n\nexport function applyTurnPatch(state: SessionState, patch: PatchEnvelope): SessionState {\n const turn = patch.data.turn\n if (!turn) return state\n\n const existing = [...state.turns]\n const index = existing.findIndex((item) => item.turn_id === turn.turn_id)\n const lastSequence = index >= 0 ? existing[index].sequence : null\n if (lastSequence !== null && patch.sequence <= lastSequence) {\n return state\n }\n\n return upsertTurn(state, { ...turn, sequence: patch.sequence })\n}\n\nexport function addErrorMessage(state: SessionState, content: string): SessionState {\n const anchorTurnId = state.turns[state.turns.length - 1]?.turn_id ?? null\n const entry_id = anchorTurnId\n ? `${ERROR_ANCHOR_PREFIX}${anchorTurnId}:${Date.now()}`\n : undefined\n return {\n ...state,\n messages: [...state.messages, { role: \"error\", content, loop_name: \"root\", entry_id }],\n }\n}\n\nexport function markInterrupted(state: SessionState): SessionState {\n return markStreamingTurns(state, \"interrupted\", \"cancelled\")\n}\n\nexport function markFailed(state: SessionState): SessionState {\n return markStreamingTurns(state, \"failed\", \"error\")\n}\n\nfunction markStreamingTurns(\n state: SessionState,\n turnStatus: \"interrupted\" | \"failed\",\n toolCallStatus: \"cancelled\" | \"error\",\n): SessionState {\n const turns = state.turns.map((turn) => {\n if (turn.status !== \"streaming\") return turn\n return {\n ...turn,\n status: turnStatus,\n tool_calls: turn.tool_calls.map((toolCall) =>\n toolCall.status === \"pending\" || toolCall.status === \"awaiting_answer\"\n ? { ...toolCall, status: toolCallStatus }\n : toolCall,\n ),\n }\n })\n return withTurns(state, turns)\n}\n","import {\n acceptedPostChatFollowupCompletesLatestRun,\n ClientProjectionBuilder,\n hasChatRunEvent,\n type RawEvent,\n} from \"../shared/projection\"\nimport type { MessageContent, ToolBridgeContent, ToolCallInfo } from \"../schemas/message\"\nimport type { ContentBlock, PatchEnvelope, TurnProjection } from \"../schemas/projection\"\nimport type { ReplaySpeed, ReplayState, SessionStatus } from \"../schemas/session\"\nimport { CommandRegistry, type CommandHandler } from \"../commands/registry\"\nimport { Emitter, type AgentSessionEvents } from \"./events\"\nimport type {\n AppCliAttachment,\n AppCliDefinition,\n FileEntry,\n HistoricalCommand,\n SessionTurnIndex,\n SessionTurnIndexItem,\n SessionTurnsPage,\n SessionTurnsQuery,\n} from \"../resources/sessions\"\nimport { prependOlder, replaceWindow } from \"./history-page\"\nimport {\n canEditQueuedMessage,\n isSessionQueueSnapshot,\n parseQueueAck,\n type QueueOperationResult,\n} from \"./queue\"\nimport { isEntryGoneError } from \"../resources/sessions\"\nimport { isRecord } from \"../shared/type-guards\"\nimport {\n buildToolUiCardKey,\n isToolUiCard,\n resolveToolUiCardContent,\n} from \"../shared/tool-ui-card\"\nimport {\n addErrorMessage,\n addUserMessage,\n applyTurnPatch,\n createInitialSessionState,\n extractModeFromBlocks,\n markFailed,\n markInterrupted,\n toReplaySnapshot,\n upsertTurn,\n withQueue,\n withTurns,\n type AskUserAnswerData,\n type ConnectionStatus,\n type SessionState,\n} from \"./state\"\n\n/** SessionHub 注入给 AgentSession 的运行时依赖(socket 收发 + REST 补数)。 */\nexport interface SessionRuntime {\n emitEvent(event: string, data: unknown): void\n emitWithAck(\n event: string,\n data: unknown,\n timeoutMs: number,\n ): Promise<Record<string, unknown> | undefined>\n ensureConnected(): void\n fetchTurnsPage(\n sessionId: string,\n query?: SessionTurnsQuery,\n init?: RequestInit,\n ): Promise<SessionTurnsPage>\n fetchTurnIndex(sessionId: string): Promise<SessionTurnIndex>\n fetchCommands(sessionId: string): Promise<HistoricalCommand[]>\n /** 会话详情,目前只用来取回放状态。 */\n fetchSessionInfo(\n sessionId: string,\n ): Promise<{ replay_state?: ReplayState | null; viewer_role?: \"owner\" | \"viewer\" }>\n updateReplay(\n sessionId: string,\n payload: { speed?: ReplaySpeed; status?: \"autonomous\" },\n ): Promise<ReplayState | null>\n listDir(sessionId: string, dirPath: string): Promise<FileEntry[]>\n countFiles(sessionId: string, dirPath?: string): Promise<number>\n downloadFile(sessionId: string, filePath: string, downloadName?: string): Promise<void>\n attachAppCli(sessionId: string, definition: AppCliDefinition): Promise<AppCliAttachment>\n /**\n * 归还一份持有。返回 true 表示这是最后一份、实例可以真正释放;\n * 返回 false 表示还有别的持有者,实例必须继续工作。\n */\n onDispose(session: AgentSession): boolean\n}\n\nexport interface AttachAppOptions {\n /** 可选;只需要页面上下文时无需提供 CLI。 */\n cli?: AppCliDefinition\n /** 每次发送前执行一次;返回当前页面状态的 JSON 对象快照。 */\n getContext: () => Record<string, unknown> | Promise<Record<string, unknown>>\n}\n\nexport interface SendOptions {\n /** planning / executing 模式。 */\n mode?: string\n /** AskUserQuestion 的作答(tool_call_id + 选项)。 */\n askUserAnswer?: Record<string, unknown>\n /** 本次运行的模型覆盖。 */\n model?: string\n /** 本次运行是否强制开/关思考。 */\n thinkingOverride?: boolean\n whatif?: {\n from_step: number\n quotes: Array<Record<string, unknown>>\n deprecate_entry_ids: string[]\n }\n replayDecision?: \"keep_replay\" | \"continue_replay\"\n /** 用户显式选择的知识库 id;后端将元信息作为 once Context 提供给模型。 */\n kbIds?: number[]\n /**\n * 声明\"会话在跑就把这条消息放进等待队列\"。默认不排队、运行中直接报错:\n * 是否真的入队由服务端按运行状态判定(等待回答时发送即作答,不会被误排队)。\n */\n queueWhenRunning?: boolean\n}\n\nconst OOM_MESSAGE = \"沙盒内存使用超出限制,已自动重启。如果经常触发,可以联系管理员调整额度。\"\nconst COMMAND_RESTORE_RETRY_BASE_MS = 1_000\nconst COMMAND_RESTORE_RETRY_MAX_MS = 30_000\n/** 队列命令的 ack 超时:操作会改变服务端状态,等太久不如尽早把\"结果未知\"交给 UI。 */\nconst QUEUE_ACK_TIMEOUT_MS = 10_000\nlet fallbackRequestCounter = 0\n\nfunction createClientRequestId(): string {\n if (typeof globalThis.crypto?.randomUUID === \"function\") {\n return globalThis.crypto.randomUUID()\n }\n fallbackRequestCounter += 1\n return `${Date.now()}-${Math.random().toString(36).slice(2)}-${fallbackRequestCounter}`\n}\n\n// ASCII 关键词用 \\b;中文\"退出码\"不能依赖 \\b(CJK 在 JS 正则里不算 word),\n// 137 两端用 (?<!\\d)(?!\\d) 锚定,避免 1370 之类误判。\nconst OOM_KEYWORDS_RE = /(?:\\b(?:exit_code|ExitedWith|exited with)|退出码)\\D*(?<!\\d)137(?!\\d)/i\n\nfunction isOomText(value: unknown): boolean {\n return typeof value === \"string\" && OOM_KEYWORDS_RE.test(value)\n}\n\nfunction parseJsonRecord(value: unknown): Record<string, unknown> | null {\n if (isRecord(value)) return value\n if (typeof value !== \"string\") return null\n try {\n const parsed = JSON.parse(value)\n return isRecord(parsed) ? parsed : null\n } catch {\n return null\n }\n}\n\nfunction isOomResult(value: unknown): boolean {\n if (Array.isArray(value)) {\n return value.some((part) => isOomResult(part))\n }\n if (typeof value === \"object\" && value !== null) {\n const record = value as Record<string, unknown>\n if (record.exit_code === 137) return true\n if (typeof record.text === \"string\" && isOomText(record.text)) return true\n if (typeof record.content === \"string\" && isOomText(record.content)) return true\n return false\n }\n if (typeof value === \"string\") {\n const parsed = parseJsonRecord(value)\n if (parsed?.exit_code === 137) return true\n return isOomText(value)\n }\n return false\n}\n\nfunction isToolBridgeContent(value: unknown): value is ToolBridgeContent {\n return (\n typeof value === \"object\" &&\n value !== null &&\n !Array.isArray(value) &&\n typeof (value as { action?: unknown }).action === \"string\"\n )\n}\n\nfunction isCursorInvalidError(error: unknown): boolean {\n return (\n typeof error === \"object\" &&\n error !== null &&\n \"status\" in error &&\n (error as { status?: unknown }).status === 409\n )\n}\n\n/** 队列命令的传输层失败(超时 / 断线):结果未知,UI 应保留草稿并提示重试。 */\nfunction queueRequestFailure(error: unknown): QueueOperationResult {\n return {\n ok: false,\n conflict: false,\n snapshot: null,\n message: error instanceof Error && error.message ? error.message : \"队列操作失败\",\n }\n}\n\nfunction commandDeliveryKey(deliveryId: string): string {\n return `tool-command:${deliveryId}`\n}\n\ninterface PendingCommandDelivery {\n deliveryKey: string\n action: string\n payload: unknown\n toolCallId: string | undefined\n}\n\nexport function sessionStatusFromChatEnd(status: string | undefined): SessionStatus {\n if (status === \"paused\") return \"waiting_for_input\"\n if (status === \"interrupted\") return \"interrupted\"\n if (status === \"failed\") return \"failed\"\n return \"completed\"\n}\n\nfunction extractTerminalChatEndStatus(events: RawEvent[]): string | null {\n for (let i = events.length - 1; i >= 0; i--) {\n const event = events[i]\n if (event?.type !== \"chat:end\") continue\n const status = event.payload?.status\n return typeof status === \"string\" ? status : \"completed\"\n }\n return null\n}\n\n/**\n * 一个会话的实时状态机:封装 Socket.IO 订阅、历史 + 流式合流、断线补数,\n * 对外只有三样东西——状态快照(getState/subscribe)、动作(send/stop/…)、\n * 语义事件(on/onCommand)。\n *\n * 状态完全归属实例:同一页面创建多个 AgentSession 互不干扰。\n */\nexport class AgentSession {\n readonly sessionId: string\n\n private state: SessionState\n private readonly listeners = new Set<() => void>()\n private readonly emitter = new Emitter<AgentSessionEvents>()\n private readonly commands = new CommandRegistry()\n private readonly runtime: SessionRuntime\n private readonly projectionBuilder = new ClientProjectionBuilder()\n\n private readonly pendingTurnPatches = new Map<string, PatchEnvelope>()\n private patchFlushHandle: number | ReturnType<typeof globalThis.setTimeout> | null = null\n private patchFlushCancel: (() => void) | null = null\n\n private joined = false\n private joinPending: Promise<void> | null = null\n // bootstrap 与每次 reconnect 共用一条订阅生命周期队列。它们都会重置 join\n // 状态并临时设置 replay source,禁止并发,否则较早操作的 finally 会清掉\n // 较晚操作仍在使用的来源上下文。\n private subscriptionQueue: Promise<unknown> = Promise.resolve()\n private replaceQueue: Promise<unknown> = Promise.resolve()\n private timelineEpoch = 0\n /** 定位请求的流水号:被后一次选择取代的那次定位不再提交窗口(见 locateEntry)。 */\n private locateToken = 0\n /** 在途那次定位的请求句柄。**只**服务定位:权威刷新不共用它(见 cancelPendingLocate)。 */\n private locateAbort: AbortController | null = null\n private pagingGeneration = 0\n private liveRevision = 0\n private modeRevision = 0\n private readonly liveRevisions = new Map<string, number>()\n private readonly pendingOptimisticTurnIds = new Set<string>()\n private olderPending: Promise<void> | null = null\n private replaceInFlight = 0\n // 回放控制请求排成一条队列。连着点\"5x\"再点\"退出回放\"时,并发发出去的两个\n // 请求响应可能乱序回来,晚到的旧值会把已经退出的会话又显示成回放中;用\n // 序号丢弃过期响应又会在失败时留下中间态。串行执行就没有这些情况:每个\n // 响应都是当时最新的,失败也只影响自己。\n private replayQueue: Promise<unknown> = Promise.resolve()\n // Historical snapshots and live commands share one delivery barrier. A\n // repair closes the barrier before joining, snapshots the raw command log\n // after the join, then releases buffered commands in socket arrival order.\n private commandRestoreQueue: Promise<unknown> = Promise.resolve()\n private commandRecoveryGeneration = 0\n private commandRestoreRetryAttempt = 0\n private commandRestoreRetryHandle: ReturnType<typeof globalThis.setTimeout> | null = null\n private bufferedCommandDeliveries: PendingCommandDelivery[] | null = null\n private pendingReplayMessage: MessageContent | null = null\n private pendingReplayMode: string | undefined\n private pendingReplayKbIds: number[] | undefined\n private recentChatEndAt = 0\n private subscriptionReplaySource: \"bootstrap_replay\" | \"reconnect_replay\" | null = null\n private disposed = false\n private getAppContext: AttachAppOptions[\"getContext\"] | null = null\n private sendPending = false\n private manualCompactionPending = false\n\n private readonly deliveredCommandKeys = new Set<string>()\n private readonly deliveredToolPreviews = new Map<string, string>()\n private readonly oomNotifiedKeys = new Set<string>()\n private readonly seenToolCallIds = new Set<string>()\n private readonly finishedToolCallIds = new Set<string>()\n private readonly emittedMessageTurnIds = new Set<string>()\n\n constructor(\n sessionId: string,\n runtime: SessionRuntime,\n connection: ConnectionStatus,\n options: { staticHistory?: boolean } = {},\n ) {\n this.sessionId = sessionId\n this.runtime = runtime\n this.state = { ...createInitialSessionState(sessionId), connection }\n this.isStatic = options.staticHistory === true\n }\n\n /**\n * 静态历史(分享页 / `fromTurns`):没有目录接口,也**没有**\"目录还没到位\"这个中间态。\n *\n * 宿主据此决定要不要拿已加载窗口当兜底条目——真实会话在 timeline 被重写后,窗口里还是\n * 旧分支的发言,拿它兜底会把已经失效的 entry id 重新摆到轨道上,点了必然找不到。\n */\n readonly isStatic: boolean\n\n /** 从一份静态 turn 快照构造只展示历史的会话(例如公开分享页)。 */\n static fromTurns(sessionId: string, turns: TurnProjection[]): AgentSession {\n const readonlyError = () => {\n throw new Error(\"静态会话只用于展示历史,不能执行会话操作\")\n }\n const session = new AgentSession(\n sessionId,\n {\n emitEvent: readonlyError,\n emitWithAck: async () => readonlyError(),\n ensureConnected: readonlyError,\n fetchTurnsPage: async () => ({ turns, nextBefore: null, currentMode: \"executing\" }),\n // 静态会话(分享页)没有会话目录接口,宿主用已加载的历史兜底条目。\n fetchTurnIndex: async () => ({ sessionId, items: [] }),\n fetchCommands: async () => [],\n // 静态历史没有回放身份可言,给个空详情即可,不要抛错——_bootstrap\n // 不会跑到这里,但保持只读语义一致。\n fetchSessionInfo: async () => ({ replay_state: null }),\n updateReplay: async () => readonlyError(),\n listDir: async () => readonlyError(),\n countFiles: async () => readonlyError(),\n downloadFile: async () => readonlyError(),\n attachAppCli: async () => readonlyError(),\n onDispose: () => true,\n },\n \"connected\",\n { staticHistory: true },\n )\n session.state = {\n ...withTurns(session.state, turns),\n status: \"completed\",\n }\n return session\n }\n\n // ---------------------------------------------------------------- 状态订阅\n\n /** 返回当前会话快照。引用稳定:状态未变化时返回同一对象。 */\n getState(): SessionState {\n return this.state\n }\n\n get hasOlderHistory(): boolean {\n return this.state.nextBefore !== null\n }\n\n /** Load the page immediately preceding the current display window. */\n loadOlderHistory(options: { beforeCommit?: () => void } = {}): Promise<void> {\n if (this.disposed) return Promise.resolve()\n if (this.olderPending) return this.olderPending\n if (this.replaceInFlight > 0) {\n // A sentinel may fire for an intermediate successful repair while a\n // later queued repair is still pending. Carry that one-shot trigger to\n // the final authoritative window instead of requiring a new\n // intersection transition.\n return this.replaceQueue.then(() => this.loadOlderHistory(options))\n }\n const before = this.state.nextBefore\n if (!before) return Promise.resolve()\n const epoch = this.timelineEpoch\n const generation = this.pagingGeneration\n this.update((state) => ({ ...state, loadingOlder: true }))\n const request = this.runtime\n .fetchTurnsPage(this.sessionId, { before })\n .then((page) => {\n if (\n epoch !== this.timelineEpoch ||\n generation !== this.pagingGeneration ||\n this.state.nextBefore !== before\n ) return\n options.beforeCommit?.()\n this.update((state) => ({\n ...withTurns(state, prependOlder(state.turns, page.turns)),\n nextBefore: page.nextBefore,\n loadingOlder: false,\n }))\n })\n .catch(async (error) => {\n if (\n isCursorInvalidError(error) &&\n epoch === this.timelineEpoch &&\n generation === this.pagingGeneration &&\n this.state.nextBefore === before\n ) {\n this.invalidateTimeline()\n await this.replaceFromHistory()\n return\n }\n // Keep the current window and cursor. A later sentinel entry or an\n // explicit caller retry can safely try the same stable anchor again.\n })\n .finally(() => {\n if (this.olderPending !== request) return\n this.olderPending = null\n this.update((state) => ({ ...state, loadingOlder: false }))\n })\n this.olderPending = request\n return request\n }\n\n /**\n * 定位到一条窗口外的历史发言:请服务端返回\"从这条发言到最新\"的窗口并整窗替换。\n *\n * 返回 false 表示这次定位没有落地(请求失败,或期间 timeline 被重写、会话已释放),\n * 当前窗口保持不变,调用方可以原样重试。已加载的发言不要走这里——宿主直接滚动,\n * 一次网络请求都不该发。\n */\n async locateEntry(entryId: string): Promise<boolean> {\n const token = ++this.locateToken\n const controller = new AbortController()\n this.locateAbort?.abort()\n this.locateAbort = controller\n try {\n return await this.replaceFromHistory({\n suppressErrors: false,\n fromEntryId: entryId,\n signal: controller.signal,\n isStale: () => this.locateToken !== token,\n })\n } catch {\n return false\n } finally {\n if (this.locateAbort === controller) this.locateAbort = null\n }\n }\n\n /**\n * 取消在途定位:用户改选了另一条发言(哪怕那条已经加载、不需要请求),\n * 先前那次定位既不该再落地,也不该继续占着替换队列——排队中的下一次定位\n * 不然要等它跑完(用户看到的是\"点了新目标一直转圈\")。\n *\n * **只**中止定位自己的请求:权威刷新(运行结束 / 重连补数)不共用这个 controller,\n * 否则\"运行刚结束时点一下侧栏\"就会把终态对账一起中止,流式与历史对不上。\n */\n cancelPendingLocate(): void {\n this.locateToken += 1\n this.locateAbort?.abort()\n this.locateAbort = null\n }\n\n /**\n * timeline 被整体改写(rewind / checkout / 释放):推进纪元,并把在途定位请求一并中止\n * ——它已经属于旧 timeline,却还占着替换队列,会让改写后的权威窗口排在后面等它跑完。\n * 作废号仍然保留:中止只是让它更早结束。\n */\n private invalidateTimeline(): void {\n this.timelineEpoch += 1\n this.locateAbort?.abort()\n this.locateAbort = null\n }\n\n /**\n * 拉取当前分支的用户发言目录(消息导航侧栏用)。\n *\n * 不在这里缓存:什么时候该刷新只有调用方知道(会话切换、历史被替换、新发言),\n * 缓存只会让旧条目在 rewind 之后继续可点。\n */\n async loadTurnIndex(): Promise<SessionTurnIndexItem[]> {\n const index = await this.runtime.fetchTurnIndex(this.sessionId)\n return index.items\n }\n\n /** 订阅状态变化。返回取消订阅函数。 */\n subscribe(listener: () => void): () => void {\n this.listeners.add(listener)\n return () => {\n this.listeners.delete(listener)\n }\n }\n\n private setState(next: SessionState): void {\n if (next === this.state) return\n this.state = next\n for (const listener of [...this.listeners]) {\n try {\n listener()\n } catch (error) {\n console.warn(\"[agent-client] 状态订阅回调抛出异常:\", error)\n }\n }\n }\n\n private update(fn: (state: SessionState) => SessionState): void {\n this.setState(fn(this.state))\n }\n\n // ---------------------------------------------------------------- 语义事件\n\n /** 监听语义事件(底层逃生舱,见 events.ts)。返回取消函数。 */\n on<K extends keyof AgentSessionEvents>(\n name: K,\n handler: (event: AgentSessionEvents[K]) => void,\n ): () => void {\n return this.emitter.on(name, handler)\n }\n\n off<K extends keyof AgentSessionEvents>(\n name: K,\n handler: (event: AgentSessionEvents[K]) => void,\n ): void {\n this.emitter.off(name, handler)\n }\n\n /**\n * 监听智能体下发给宿主页面的指令。\n *\n * action 是技能作者在工具返回值 `_meta.bridge` 里写的契约字符串(如\n * \"map.highlight\"),由你和技能作者约定;注册前到达的指令会被缓冲补投。\n */\n onCommand(action: string, handler: CommandHandler): () => void {\n return this.commands.onCommand(action, handler)\n }\n\n // ---------------------------------------------------------------- 动作\n\n /**\n * 声明当前应用提供的页面上下文和业务 CLI。\n *\n * CLI 安装成功后才保存 getContext;之后每次 send 前恰好读取一次。\n */\n async attachApp(options: AttachAppOptions): Promise<AppCliAttachment | null> {\n const attachment = options.cli\n ? await this.runtime.attachAppCli(this.sessionId, options.cli)\n : null\n this.getAppContext = options.getContext\n return attachment\n }\n\n /** 发送一条消息。字符串或多模态内容均可。 */\n async send(content: MessageContent, options: SendOptions = {}): Promise<boolean> {\n this.runtime.ensureConnected()\n // 只有声明了 queueWhenRunning 的调用方才能把运行中提交交给服务端;其余调用方\n // 维持原有的本地拒绝,不把运行中的一轮打成失败。\n if (\n (this.state.isStreaming && options.queueWhenRunning !== true) ||\n this.state.activeCompaction ||\n this.sendPending ||\n this.manualCompactionPending\n ) {\n this.update((s) =>\n addErrorMessage(s, \"当前回复尚未结束或对话正在整理,请稍后再发送。\"),\n )\n return false\n }\n this.sendPending = true\n try {\n return await this.sendUnlocked(content, options)\n } finally {\n this.sendPending = false\n }\n }\n\n /**\n * 入队一条等待消息(运行中排队 / 暂停期间照常入队)。\n *\n * ack 超时或传输失败时结果未知:用**同一个** `client_request_id` 重试一次,\n * 服务端按 `(session_id, client_request_id)` 幂等,不会制造第二条。\n */\n async queueMessage(content: string): Promise<QueueOperationResult> {\n const text = content.trim()\n if (!text) {\n return { ok: false, conflict: false, snapshot: null, message: \"消息不能为空\" }\n }\n const payload = {\n session_id: this.sessionId,\n message: text,\n client_request_id: createClientRequestId(),\n }\n try {\n return await this.requestQueueAck(\"chat:append\", payload)\n } catch {\n try {\n return await this.requestQueueAck(\"chat:append\", payload)\n } catch (error) {\n return queueRequestFailure(error)\n }\n }\n }\n\n /** 修改一条等待消息的正文;`expectedVersion` 是客户端看到的条目版本。 */\n async updateQueuedMessage(\n itemId: string,\n expectedVersion: number,\n content: string,\n ): Promise<QueueOperationResult> {\n return this.runQueueCommand(\"chat:queue:update\", {\n session_id: this.sessionId,\n item_id: itemId,\n expected_version: expectedVersion,\n message: content,\n })\n }\n\n /**\n * 重排等待消息。`orderedIds` 必须是当前 pending 条目 id 的**完整集合**(顺序任意),\n * 服务端按 `expectedRevision` 校验后整体替换顺序。\n *\n * 拖动排序就该像本地操作一样落地:版本冲突(运行中的任务刚领走一条 / 另一个端也在\n * 动队列)不甩给用户「刷新后重试」,而是拿冲突响应里那份**最新快照**重算一次再提交\n * ——掉队的条目(已经被领取执行的)从顺序里剔除,剩下的保持用户拖出来的相对次序。\n * 最多补两次;仍旧冲突才把结果交回调用方。\n */\n async reorderQueuedMessages(\n expectedRevision: number,\n orderedIds: string[],\n ): Promise<QueueOperationResult> {\n let revision = expectedRevision\n let ids = orderedIds\n let result = await this.runQueueCommand(\"chat:queue:reorder\", {\n session_id: this.sessionId,\n expected_revision: revision,\n ordered_ids: ids,\n })\n for (let attempt = 0; attempt < 2 && !result.ok && result.conflict; attempt++) {\n const snapshot = result.snapshot\n if (!snapshot) break\n const pending = snapshot.items.filter(canEditQueuedMessage)\n const live = new Set(pending.map((item) => item.id))\n // 用户拖出来的次序优先,只保留还在队列里的;服务端新出现的条目补在后面。\n const next = ids.filter((id) => live.has(id))\n for (const item of pending) if (!next.includes(item.id)) next.push(item.id)\n if (next.length === 0) {\n // 队列已经被清空(条目都开始执行了):这次拖动没有可排的东西,按成功返回\n // 最新快照让界面同步,而不是给用户报一句他无法处理的「刷新后重试」。\n return { ok: true, conflict: false, snapshot, message: null }\n }\n revision = snapshot.revision\n ids = next\n result = await this.runQueueCommand(\"chat:queue:reorder\", {\n session_id: this.sessionId,\n expected_revision: revision,\n ordered_ids: ids,\n })\n }\n return result\n }\n\n /** 删除一条等待消息;不传版本时由服务端自行判定。 */\n async cancelQueuedMessage(\n itemId: string,\n expectedVersion?: number,\n ): Promise<QueueOperationResult> {\n return this.runQueueCommand(\"chat:queue:cancel\", {\n session_id: this.sessionId,\n item_id: itemId,\n expected_version: expectedVersion,\n })\n }\n\n /** 立即补充:把等待消息交给当前运行,在下一个接收点消费,不停止也不另起一轮。 */\n async deliverQueuedMessage(\n itemId: string,\n expectedVersion: number,\n ): Promise<QueueOperationResult> {\n return this.runQueueCommand(\"chat:queue:deliver\", {\n session_id: this.sessionId,\n item_id: itemId,\n expected_version: expectedVersion,\n })\n }\n\n /** 继续执行:清除暂停,并按当前顺序恢复逐条接续。 */\n async resumeQueue(): Promise<QueueOperationResult> {\n return this.runQueueCommand(\"chat:queue:resume\", { session_id: this.sessionId })\n }\n\n /** 拉取一份权威队列快照。首次连接与每次重连后由实例自动调用,也可以手动刷新。 */\n async refreshQueue(): Promise<QueueOperationResult> {\n return this.runQueueCommand(\"chat:queue:list\", { session_id: this.sessionId })\n }\n\n /**\n * 发出一条队列命令并安装 ack 里的快照。\n * 传输层失败(超时 / 断线)会 reject,由调用方决定是否重试。\n */\n private async requestQueueAck(\n event: string,\n payload: Record<string, unknown>,\n ): Promise<QueueOperationResult> {\n this.runtime.ensureConnected()\n const response = await this.runtime.emitWithAck(event, payload, QUEUE_ACK_TIMEOUT_MS)\n const result = parseQueueAck(response, this.sessionId)\n const snapshot = result.snapshot\n if (snapshot) this.update((state) => withQueue(state, snapshot))\n return result\n }\n\n /** 队列命令的对外入口:传输失败只体现为失败结果,不向调用方抛异常。 */\n private async runQueueCommand(\n event: string,\n payload: Record<string, unknown>,\n ): Promise<QueueOperationResult> {\n try {\n return await this.requestQueueAck(event, payload)\n } catch (error) {\n return queueRequestFailure(error)\n }\n }\n\n private async sendUnlocked(content: MessageContent, options: SendOptions): Promise<boolean> {\n await this.ensureIdleBeforeSend()\n if (\n (this.state.isStreaming && options.queueWhenRunning !== true) ||\n this.state.activeCompaction ||\n this.manualCompactionPending\n ) {\n this.update((s) =>\n addErrorMessage(s, \"当前回复尚未结束或对话正在整理,请稍后再发送。\"),\n )\n return false\n }\n let appContext: Record<string, unknown> | undefined\n if (this.getAppContext) {\n try {\n const rawContext = await this.getAppContext()\n if (!isRecord(rawContext)) {\n throw new Error(\"getContext 必须返回 JSON 对象\")\n }\n const serialized = JSON.stringify(rawContext)\n if (serialized === undefined) {\n throw new Error(\"getContext 必须返回可序列化的 JSON 对象\")\n }\n const normalized = JSON.parse(serialized)\n if (!isRecord(normalized)) {\n throw new Error(\"getContext 必须返回 JSON 对象\")\n }\n appContext = normalized\n } catch (error) {\n const message =\n error instanceof Error && error.message\n ? `读取应用上下文失败:${error.message}`\n : \"读取应用上下文失败,消息未发送\"\n this.update((s) => addErrorMessage(s, message))\n return false\n }\n }\n const wasStreaming = this.state.isStreaming\n const askUserAnswer = options.askUserAnswer\n let optimisticTurnId: string | null = null\n const clientRequestId = createClientRequestId()\n let optimisticAskAnswer: AskUserAnswerData | undefined\n let previousAskAnswer: AskUserAnswerData | undefined\n this.update((state) => {\n const next = addUserMessage(state, content, clientRequestId)\n optimisticTurnId = next.turns.at(-1)?.turn_id ?? null\n return next\n })\n if (optimisticTurnId) this.markOptimisticTurnPending(optimisticTurnId)\n this.update((s) => ({ ...s, isStreaming: true }))\n if (askUserAnswer && typeof askUserAnswer.tool_call_id === \"string\") {\n const { tool_call_id, ...rest } = askUserAnswer\n previousAskAnswer = this.state.askAnswers[tool_call_id]\n optimisticAskAnswer = rest as unknown as AskUserAnswerData\n this.update((s) => ({\n ...s,\n askAnswers: { ...s.askAnswers, [tool_call_id as string]: optimisticAskAnswer! },\n }))\n }\n if (!options.replayDecision) {\n this.pendingReplayMessage = content\n this.pendingReplayMode = options.mode\n this.pendingReplayKbIds = options.kbIds\n }\n const payload = {\n session_id: this.sessionId,\n message: content,\n client_request_id: clientRequestId,\n mode: options.mode,\n askuser_answer: askUserAnswer,\n model: options.model,\n thinking_override: options.thinkingOverride,\n whatif: options.whatif,\n replay_decision: options.replayDecision,\n app_context: appContext,\n kb_ids: options.kbIds,\n // 运行中提交不必由客户端挑命令:服务端按会话运行状态决定直接执行还是入队。\n queue_when_running: options.queueWhenRunning === true,\n }\n try {\n await this.ensureJoined()\n } catch (error) {\n this.rollbackOptimisticSend(\n optimisticTurnId,\n askUserAnswer,\n optimisticAskAnswer,\n previousAskAnswer,\n wasStreaming,\n error instanceof Error && error.message ? error.message : \"会话订阅失败,消息未发送\",\n )\n return false\n }\n try {\n const response = await this.runtime.emitWithAck(\"chat:send\", payload, 30_000)\n if (response?.status === \"queued\") {\n // 服务端按运行状态把这条消息改道进了等待队列:撤掉乐观消息交给队列面板。\n // ack 里的 running 是服务端判定那一刻的快照,可能已经被这期间到达的\n // chat:end 顶掉,所以只拿它撤销我们的乐观流式置位(确认没有运行),\n // 不用它把流式标记顶上去——那会留下\"正在生成\"却没有运行可收尾。\n this.discardOptimisticSend(\n optimisticTurnId,\n askUserAnswer,\n optimisticAskAnswer,\n previousAskAnswer,\n )\n const snapshot = parseQueueAck(response, this.sessionId).snapshot\n const running = response.running === true\n this.update((current) => {\n const next = running ? current : { ...current, isStreaming: false }\n return snapshot ? withQueue(next, snapshot) : next\n })\n return true\n }\n if (response?.status !== \"accepted\") {\n throw new Error(\n typeof response?.message === \"string\"\n ? response.message\n : \"消息未被服务端接受\",\n )\n }\n return true\n } catch (error) {\n this.rollbackOptimisticSend(\n optimisticTurnId,\n askUserAnswer,\n optimisticAskAnswer,\n previousAskAnswer,\n wasStreaming,\n error instanceof Error && error.message ? error.message : \"消息发送失败,请重试\",\n )\n return false\n }\n }\n\n private rollbackOptimisticSend(\n optimisticTurnId: string | null,\n askUserAnswer: Record<string, unknown> | undefined,\n optimisticAskAnswer: AskUserAnswerData | undefined,\n previousAskAnswer: AskUserAnswerData | undefined,\n wasStreaming: boolean,\n message: string,\n ): void {\n this.discardOptimisticSend(\n optimisticTurnId,\n askUserAnswer,\n optimisticAskAnswer,\n previousAskAnswer,\n )\n // 同内置 Web AgentSocket.send:只撤销本次提交设置的乐观运行状态。\n // 已有运行的状态交给事件更新,既不误停,也不复活已结束的运行。\n this.update((current) =>\n addErrorMessage(wasStreaming ? current : { ...current, isStreaming: false }, message),\n )\n }\n\n /** 撤回一次乐观提交:移除乐观消息、恢复提问作答、清掉回放草稿。 */\n private discardOptimisticSend(\n optimisticTurnId: string | null,\n askUserAnswer: Record<string, unknown> | undefined,\n optimisticAskAnswer: AskUserAnswerData | undefined,\n previousAskAnswer: AskUserAnswerData | undefined,\n ): void {\n this.pendingReplayMessage = null\n this.pendingReplayMode = undefined\n this.pendingReplayKbIds = undefined\n this.update((current) => {\n // withTurns 第一个参数要传已经去掉这条乐观 turn 的 current(而不是原始\n // current):withTurns 内部会把\"这批 incoming 没认领的本地乐观 turn\"\n // 保留下来(应对真正的全量快照场景),如果这里传原始 current,它会把\n // 我们刚刚主动要撤回的这条乐观 turn 当成\"还没被认领\"重新拼回去,等于\n // 撤回失败。\n const filtered = optimisticTurnId\n ? current.turns.filter((turn) => turn.turn_id !== optimisticTurnId)\n : current.turns\n let next = optimisticTurnId\n ? withTurns({ ...current, turns: filtered }, filtered)\n : current\n const toolCallId =\n askUserAnswer && typeof askUserAnswer.tool_call_id === \"string\"\n ? askUserAnswer.tool_call_id\n : null\n if (toolCallId && next.askAnswers[toolCallId] === optimisticAskAnswer) {\n const askAnswers = { ...next.askAnswers }\n if (previousAskAnswer === undefined) {\n delete askAnswers[toolCallId]\n } else {\n askAnswers[toolCallId] = previousAskAnswer\n }\n next = { ...next, askAnswers }\n }\n return next\n })\n if (optimisticTurnId) {\n this.pendingOptimisticTurnIds.delete(optimisticTurnId)\n this.liveRevisions.delete(optimisticTurnId)\n }\n }\n\n /** 停止当前回复。 */\n stop(): Promise<Record<string, unknown>> {\n return this.runtime\n .emitWithAck(\"chat:stop\", { session_id: this.sessionId }, 35_000)\n .then((response) => {\n const result = response ?? {}\n if (result.status !== \"accepted\") this.manualCompactionPending = false\n return result\n })\n }\n\n /** 手动触发上下文压缩。 */\n compact(): Promise<Record<string, unknown>> {\n if (this.state.isStreaming || this.state.activeCompaction || this.manualCompactionPending) {\n return Promise.resolve({\n status: \"error\",\n message: \"当前回复尚未结束或对话正在整理,请稍后再试。\",\n })\n }\n this.manualCompactionPending = true\n this.update((state) => ({\n ...state,\n activeCompaction: {\n turn_id: \"pending-manual-compaction\",\n compaction_id: \"pending-manual-compaction\",\n status: \"streaming\",\n trigger: \"manual\",\n },\n }))\n return this.runtime\n .emitWithAck(\"chat:compact\", { session_id: this.sessionId }, 30_000)\n .then((response) => response ?? {})\n .catch((error) => {\n this.manualCompactionPending = false\n throw error\n })\n .finally(() => {\n if (this.state.activeCompaction?.compaction_id === \"pending-manual-compaction\") {\n this.update((state) => ({ ...state, activeCompaction: null }))\n }\n })\n }\n\n /**\n * 把一段业务数据作为附件放进聊天输入框(比如地图上选中的点位)。\n * 附件随下一条消息一起发给智能体。需要 ChatView / useChat 渲染层配合展示;\n * 无 UI 场景可直接用 send()。\n */\n attach(label: string, data: unknown): void {\n const content = typeof data === \"string\" ? data : JSON.stringify(data, null, 2)\n this.emitter.emit(\"attachRequested\", { label, content })\n }\n\n /** 往聊天输入框追加一段文字(不发送)。 */\n insertText(text: string): void {\n this.emitter.emit(\"insertTextRequested\", { text })\n }\n\n /** 列出工作区的一层目录。 */\n listDir(dirPath = \"\"): Promise<FileEntry[]> {\n return this.runtime.listDir(this.sessionId, dirPath)\n }\n\n /** 递归统计工作区文件数(不含目录)。 */\n countFiles(dirPath = \"\"): Promise<number> {\n return this.runtime.countFiles(this.sessionId, dirPath)\n }\n\n /** 在浏览器中下载一个工作区文件。 */\n downloadFile(filePath: string, downloadName?: string): Promise<void> {\n return this.runtime.downloadFile(this.sessionId, filePath, downloadName)\n }\n\n /**\n * 归还一份持有。同一个会话被多处 connect 时按引用计数释放:只有最后\n * 一份归还才真正断开订阅与监听器,之前的归还不影响仍在使用的一方。\n */\n dispose(): void {\n if (this.disposed) return\n if (!this.runtime.onDispose(this)) return\n this.disposed = true\n this.invalidateTimeline()\n this.invalidateOlderPaging()\n this.state = { ...this.state, nextBefore: null, loadingOlder: false }\n this.cancelPatchFlush()\n this.listeners.clear()\n this.emitter.clear()\n this.commands.clear()\n this.commandRecoveryGeneration += 1\n this.commandRestoreRetryAttempt = 0\n this.bufferedCommandDeliveries = null\n if (this.commandRestoreRetryHandle !== null) {\n globalThis.clearTimeout(this.commandRestoreRetryHandle)\n this.commandRestoreRetryHandle = null\n }\n }\n\n get isDisposed(): boolean {\n return this.disposed\n }\n\n // ------------------------------------------------------- Hub 回调(内部)\n\n /** @internal 连接状态变化(同 client 下所有会话共享一条连接)。 */\n _setConnection(connection: ConnectionStatus): void {\n if (this.state.connection === connection) return\n this.update((s) => ({ ...s, connection }))\n }\n\n /**\n * @internal 服务端广播的权威队列快照。\n * 结构不合法或 revision 不新的一律丢弃,绝不用旧快照覆盖新状态。\n */\n _handleQueueUpdated(payload: unknown): void {\n if (!isSessionQueueSnapshot(payload)) return\n const snapshot = payload\n this.update((state) => withQueue(state, snapshot))\n }\n\n /** @internal socket 重连后由 Hub 调用:重新加入房间并补数。 */\n _rejoinAfterReconnect(): Promise<void> {\n // 边界快照必须在收到 connect 时同步取得。队列实际开始前到达的 live turn\n // 也属于本次重连后的新变化,历史补数不能把它清掉。\n //\n // **不推进 timeline 纪元**:重连不是 timeline 被改写(分支没变,只是补一次数),推进了\n // 在途定位的结果就会被丢掉——用户点了没反应。补数本来就按它落地后的窗口取窗口。\n this.invalidateOlderPaging()\n this.update((state) => ({ ...state, nextBefore: null, loadingOlder: false }))\n const reconnectLiveRevision = this.liveRevision\n const reconnectModeRevision = this.modeRevision\n const commandRecoveryGeneration = this.beginCommandRecovery()\n return this.enqueueSubscription(async () => {\n this.joined = false\n this.joinPending = null\n try {\n this.subscriptionReplaySource = \"reconnect_replay\"\n try {\n await this.ensureJoined(reconnectLiveRevision)\n } finally {\n this.subscriptionReplaySource = null\n this.scheduleHistoricalCommandRestore(commandRecoveryGeneration)\n }\n // 回放状态和历史一起补:断线期间错过的 session:updated(别处退出了回放、\n // 改了倍速)不补的话,快照会一直停在旧值。\n await Promise.all([\n this.refreshAuthoritativeHistory({\n liveRevisionAtStart: reconnectLiveRevision,\n modeRevisionAtStart: reconnectModeRevision,\n }),\n this.syncReplayFromSession(),\n ])\n } catch {\n // 重连补数尽力而为;后续 Socket 重连仍会再次尝试\n }\n })\n }\n\n /** @internal 首次连接:加载历史 + 加入房间。 */\n _bootstrap(): Promise<void> {\n const commandRecoveryGeneration = this.beginCommandRecovery()\n return this.enqueueSubscription(async () => {\n await this.replaceFromHistory({ suppressErrors: false })\n this.subscriptionReplaySource = \"bootstrap_replay\"\n try {\n await this.ensureJoined()\n } finally {\n this.subscriptionReplaySource = null\n }\n this.scheduleHistoricalCommandRestore(commandRecoveryGeneration)\n // 必须在进房间之后再拉回放状态:反过来的话,两者之间别的标签页改了倍速或\n // 退出了回放,那条 session:updated 我们还没订阅、收不到,快照会一直停在旧值。\n // 拉一次而不是等推送,是为了让 connect() 返回时第一帧就知道自己在不在回放。\n await Promise.all([this.syncReplayFromSession(), this.refreshQueue()])\n })\n }\n\n /** 订阅生命周期串行执行;一次失败只由自己的调用方观察,不截断后续重连。 */\n private enqueueSubscription(operation: () => Promise<void>): Promise<void> {\n const run = this.subscriptionQueue.then(operation)\n this.subscriptionQueue = run.catch(() => undefined)\n return run\n }\n\n /** 改回放是 owner 专属(服务端 PATCH 走 _get_owned_session)。 */\n private get canControlReplay(): boolean {\n return this.state.viewerRole !== \"viewer\"\n }\n\n /** 拉一次会话详情,填回放状态和只读身份;失败按非回放会话处理,不挡启动。 */\n private async syncReplayFromSession(): Promise<void> {\n try {\n const info = await this.runtime.fetchSessionInfo(this.sessionId)\n const replay = toReplaySnapshot(info.replay_state)\n const viewerRole = info.viewer_role ?? null\n this.update((s) => ({ ...s, replay, viewerRole }))\n } catch {\n // 会话详情拿不到不影响对话本身,回放控件不显示即可。\n }\n }\n\n /** 调整回放倍速;不是回放会话、或只读身份时什么都不做。 */\n async setReplaySpeed(speed: ReplaySpeed): Promise<void> {\n if (!this.state.replay?.isReplay || !this.canControlReplay) return\n await this.applyReplayControl({ speed })\n }\n\n /** 退出回放,之后的对话交给真实模型运行;不是回放会话、或只读身份时什么都不做。 */\n async exitReplay(): Promise<void> {\n if (!this.state.replay?.isReplay || !this.canControlReplay) return\n await this.applyReplayControl({ status: \"autonomous\" })\n }\n\n /** 把一次回放控制请求排进队列;前一个完成后才发出,响应直接安装。 */\n private applyReplayControl(\n payload: { speed?: ReplaySpeed; status?: \"autonomous\" },\n ): Promise<void> {\n const run = this.replayQueue.then(async () => {\n const result = await this.runtime.updateReplay(this.sessionId, payload)\n this.update((s) => ({ ...s, replay: toReplaySnapshot(result) }))\n })\n // 队列本身不能被一次失败打断,否则后续控制永远排不上。\n this.replayQueue = run.catch(() => undefined)\n return run\n }\n\n /** @internal */\n _handleTurnStart(turn: TurnProjection): void {\n this.markRunningIfIdle()\n this.applyTurn(turn)\n }\n\n /** @internal */\n _handleTurnPatch(patch: PatchEnvelope): void {\n this.markRunningIfIdle()\n if (patch.data.workspace_changed) {\n this.emitter.emit(\"workspaceChanged\", {})\n }\n const current = this.pendingTurnPatches.get(patch.turn_id)\n if (!current || patch.sequence >= current.sequence) {\n this.pendingTurnPatches.set(patch.turn_id, patch)\n }\n this.schedulePatchFlush()\n }\n\n /** @internal */\n _handleTurnEnd(turn: TurnProjection): void {\n this.applyTurn(turn)\n }\n\n /** @internal 历史回放通道(event_format: raw)。 */\n _handleTurnEvents(events: RawEvent[], replayed = false): void {\n if (!events.length) return\n if (events.some((event) =>\n event.type === \"compaction:end\" ||\n event.type === \"compaction:error\" ||\n event.type === \"compaction:abort\"\n )) {\n this.manualCompactionPending = false\n }\n // Commands are transport semantics, not display semantics. Consume the\n // canonical raw delivery before projection so standalone commands (no\n // tool_call_id/display owner) still reach the host page. If a visible\n // block is projected afterwards, the same delivery id deduplicates it.\n this.dispatchRawCommands(events)\n const terminalChatEndStatus = extractTerminalChatEndStatus(events)\n if (\n !terminalChatEndStatus &&\n hasChatRunEvent(events) &&\n this.state.status !== \"waiting_for_input\"\n ) {\n this.markRunningIfIdle()\n }\n if (this.state.turns.length) {\n this.projectionBuilder._seedTurns(this.state.turns)\n }\n const updates = this.projectionBuilder.processBatch(events)\n for (const update of updates) {\n if (update.kind === \"upsert\") {\n this.applyTurn(\n update.turn,\n replayed ? (this.subscriptionReplaySource ?? \"bootstrap_replay\") : \"live\",\n )\n } else if (update.kind === \"workspace_changed\") {\n this.emitter.emit(\"workspaceChanged\", {})\n }\n }\n if (\n terminalChatEndStatus ||\n acceptedPostChatFollowupCompletesLatestRun(events, updates)\n ) {\n this.completeChat(terminalChatEndStatus ?? \"completed\")\n }\n }\n\n /** @internal */\n _handleChatStart(): void {\n this.update((s) => ({ ...s, status: \"running\", errorMessage: null, isStreaming: true }))\n }\n\n /** @internal */\n _handleChatEnd(status: string): void {\n this.flushPatches()\n this.completeChat(status)\n }\n\n /** @internal */\n _handleSystemError(message: string): void {\n this.flushPatches()\n const finalMessage = isOomText(message) ? OOM_MESSAGE : message\n this.update((s) =>\n addErrorMessage(markFailed({ ...s, status: \"failed\", errorMessage: finalMessage, isStreaming: false }), finalMessage),\n )\n this.recentChatEndAt = Date.now()\n this.emitter.emit(\"error\", { message: finalMessage })\n }\n\n /** @internal */\n _handleTaskUpdated(tasks: unknown[]): void {\n this.emitter.emit(\"taskListUpdated\", { tasks })\n }\n\n /** @internal */\n _handleWorkspaceFilesChanged(filePath?: string): void {\n this.emitter.emit(\"workspaceChanged\", { filePath })\n }\n\n /** @internal */\n _handleSessionUpdated(data: {\n workspace_path?: string\n chat_group_id?: string | null\n intent?: string\n status?: SessionStatus\n model?: string | null\n bound_skill_id?: string | null\n replay_state?: Record<string, unknown> | null\n }): void {\n if (data.status) {\n this.update((s) => ({ ...s, status: data.status ?? s.status }))\n }\n if (data.replay_state !== undefined) {\n const replay = toReplaySnapshot(data.replay_state as ReplayState | null)\n this.update((s) => ({ ...s, replay }))\n }\n this.emitter.emit(\"sessionUpdated\", {\n workspacePath: data.workspace_path,\n chatGroupId: data.chat_group_id,\n intent: data.intent,\n status: data.status,\n model: data.model,\n boundSkillId: data.bound_skill_id,\n replayState: data.replay_state,\n })\n }\n\n /** @internal */\n _handleRewind(checkpointId: string): void {\n this.invalidateTimeline()\n this.invalidateOlderPaging()\n this.update((s) => ({\n ...s,\n mode: null,\n errorMessage: null,\n nextBefore: null,\n loadingOlder: false,\n }))\n void this.replaceFromHistory()\n this.emitter.emit(\"rewind\", { checkpointId })\n }\n\n /** @internal */\n _handleReplayMismatch(data: { actual_message?: string; expected_message?: string }): void {\n const message = this.pendingReplayMessage ?? data.actual_message ?? \"\"\n const mode = this.pendingReplayMode\n const kbIds = this.pendingReplayKbIds\n this.pendingReplayMessage = null\n this.pendingReplayMode = undefined\n this.pendingReplayKbIds = undefined\n const respond = (decision: \"keep_replay\" | \"continue_replay\") => {\n void this.runtime\n .emitWithAck(\n \"chat:send\",\n {\n session_id: this.sessionId,\n message,\n mode,\n replay_decision: decision,\n kb_ids: kbIds,\n },\n 30_000,\n )\n .then((response) => {\n if (response?.status === \"accepted\") return\n this.update((state) =>\n addErrorMessage(\n { ...state, isStreaming: false },\n typeof response?.message === \"string\"\n ? response.message\n : \"消息未被服务端接受\",\n ),\n )\n })\n .catch((error) => {\n this.update((state) =>\n addErrorMessage(\n { ...state, isStreaming: false },\n error instanceof Error && error.message ? error.message : \"消息发送失败,请重试\",\n ),\n )\n })\n }\n const handled = this.emitter.emitFirst(\"replayMismatch\", {\n actualMessage: data.actual_message,\n expectedMessage: data.expected_message,\n respond,\n })\n if (!handled) {\n respond(\"continue_replay\")\n }\n }\n\n /** @internal */\n _handleSystemNotification(loopId: string, notification: Record<string, unknown>): void {\n const notificationType =\n typeof notification.notification_type === \"string\"\n ? notification.notification_type\n : \"system_notification\"\n const title = typeof notification.title === \"string\" ? notification.title : notificationType\n const detail =\n typeof notification.detail === \"string\"\n ? notification.detail\n : notification.detail == null\n ? undefined\n : JSON.stringify(notification.detail)\n const status =\n notification.status === \"running\" || notification.status === \"done\" || notification.status === \"error\"\n ? notification.status\n : \"info\"\n this.emitter.emit(\"notification\", {\n type: notificationType,\n title,\n detail,\n status,\n loopId,\n metadata: isRecord(notification.metadata) ? notification.metadata : undefined,\n })\n if (notificationType === \"bg:started\" && isRecord(notification.metadata)) {\n const taskId =\n typeof notification.metadata.task_id === \"string\" ? notification.metadata.task_id : \"\"\n if (taskId) {\n this.emitter.emit(\"backgroundTask\", {\n id: taskId,\n command:\n typeof notification.metadata.command === \"string\" ? notification.metadata.command : \"\",\n description:\n typeof notification.metadata.description === \"string\"\n ? notification.metadata.description\n : undefined,\n status: \"running\",\n elapsedSeconds: 0,\n })\n }\n }\n }\n\n /** @internal */\n _handleBackgroundTask(task: AgentSessionEvents[\"backgroundTask\"]): void {\n this.emitter.emit(\"backgroundTask\", task)\n }\n\n /** @internal */\n _handleArtifact(event: AgentSessionEvents[\"artifact\"]): void {\n this.emitter.emit(\"artifact\", event)\n }\n\n /** @internal 加入房间的应答里带 is_running,据此校准流式状态。 */\n _applyRunningState(isRunning: boolean, liveRevisionAtJoin = this.liveRevision): void {\n if (isRunning) {\n this.update((s) => ({ ...s, status: \"running\", isStreaming: true }))\n } else if (this.state.isStreaming) {\n this.update((s) => ({ ...s, isStreaming: false }))\n // 这也是一次权威刷新(\"我看它还在跑,其实已经结束了\"):同样要按用户的窗口意图取窗口,\n // 否则它排在重连补数前面先把窗口换成最新一页,把用户正在看的那段挤出去。\n void this.refreshAuthoritativeHistory({ liveRevisionAtStart: liveRevisionAtJoin })\n }\n }\n\n // ---------------------------------------------------------------- 内部实现\n\n private markRunningIfIdle(): void {\n if (!this.state.isStreaming) {\n this.update((s) => ({ ...s, status: \"running\", isStreaming: true }))\n }\n }\n\n private finishStreaming(status: string): void {\n const sessionStatus = sessionStatusFromChatEnd(status)\n this.update((s) => {\n let next: SessionState = { ...s, status: sessionStatus, isStreaming: false }\n if (status === \"interrupted\") next = markInterrupted(next)\n else if (status === \"failed\") next = markFailed(next)\n return next\n })\n }\n\n private completeChat(status: string): void {\n this.finishStreaming(status)\n this.recentChatEndAt = Date.now()\n // 运行结束的对账不能把用户刚定位到的那段历史挤出去(见 refreshAuthoritativeHistory)。\n void this.refreshAuthoritativeHistory()\n this.emitter.emit(\"chatEnd\", { status })\n }\n\n private markTurnFresh(turnId: string): void {\n this.liveRevision += 1\n this.liveRevisions.set(turnId, this.liveRevision)\n }\n\n private markOptimisticTurnPending(turnId: string): void {\n this.pendingOptimisticTurnIds.add(turnId)\n this.markTurnFresh(turnId)\n }\n\n private pruneOptimisticLiveRevisions(): void {\n const retained = new Set(\n this.state.turns\n .map((turn) => turn.turn_id)\n .filter((turnId) => turnId.startsWith(\"local-user-\")),\n )\n for (const turnId of this.liveRevisions.keys()) {\n if (turnId.startsWith(\"local-user-\") && !retained.has(turnId)) {\n this.pendingOptimisticTurnIds.delete(turnId)\n this.liveRevisions.delete(turnId)\n }\n }\n }\n\n private applyTurn(\n turn: TurnProjection,\n source: AgentSessionEvents[\"toolResult\"][\"source\"] = \"live\",\n ): void {\n this.flushPatches()\n this.markTurnFresh(turn.turn_id)\n if (extractModeFromBlocks(turn.blocks)) this.modeRevision += 1\n const previous = this.state\n this.update((s) => upsertTurn(s, turn))\n this.pruneOptimisticLiveRevisions()\n this.emitTurnDerivedEvents(previous, turn, source)\n }\n\n private schedulePatchFlush(): void {\n if (this.patchFlushHandle != null) return\n const flush = () => {\n this.patchFlushHandle = null\n this.patchFlushCancel = null\n this.flushPatches()\n }\n if (typeof window !== \"undefined\" && typeof window.requestAnimationFrame === \"function\") {\n const handle = window.requestAnimationFrame(flush)\n this.patchFlushHandle = handle\n this.patchFlushCancel = () => window.cancelAnimationFrame(handle)\n return\n }\n const handle = globalThis.setTimeout(flush, 33)\n this.patchFlushHandle = handle\n this.patchFlushCancel = () => globalThis.clearTimeout(handle)\n }\n\n private cancelPatchFlush(): void {\n this.patchFlushCancel?.()\n this.patchFlushHandle = null\n this.patchFlushCancel = null\n this.pendingTurnPatches.clear()\n }\n\n private flushPatches(): void {\n if (this.pendingTurnPatches.size === 0) return\n const patches = [...this.pendingTurnPatches.values()].sort(\n (left, right) => left.sequence - right.sequence,\n )\n this.pendingTurnPatches.clear()\n for (const patch of patches) {\n const previous = this.state\n const next = applyTurnPatch(previous, patch)\n if (next === previous) continue\n this.liveRevision += 1\n this.liveRevisions.set(patch.turn_id, this.liveRevision)\n const turn = patch.data.turn\n if (turn && extractModeFromBlocks(turn.blocks)) this.modeRevision += 1\n this.setState(next)\n this.pruneOptimisticLiveRevisions()\n if (turn) this.emitTurnDerivedEvents(previous, turn)\n }\n if (this.patchFlushCancel) {\n this.patchFlushCancel()\n this.patchFlushHandle = null\n this.patchFlushCancel = null\n }\n }\n\n /** turn 数据落地后统一派生语义事件(指令 / 工具调用 / 消息 / 模式 / 预览 / OOM)。 */\n private emitTurnDerivedEvents(\n previous: SessionState,\n turn: TurnProjection,\n source: AgentSessionEvents[\"toolResult\"][\"source\"] = \"live\",\n ): void {\n const mode = extractModeFromBlocks(turn.blocks)\n if (mode && previous.mode !== mode) {\n this.emitter.emit(\"modeChange\", { mode })\n }\n\n for (const block of turn.blocks) {\n if (block.type === \"tool_result\" && isOomResult(block.content)) {\n this.notifySandboxOom(block.tool_call_id ?? turn.id)\n }\n if (block.type === \"tool_bridge\" && isToolBridgeContent(block.content)) {\n this.dispatchCommand(turn, block)\n continue\n }\n if (block.type === \"tool_ui\" && block.tool_call_id && isToolUiCard(block.content)) {\n const ui = block.content\n if (ui.target !== \"preview\") continue\n const resolved = resolveToolUiCardContent(ui)\n if (!resolved) continue\n const key = buildToolUiCardKey(block.tool_call_id, resolved.type, resolved.content)\n const fingerprint = JSON.stringify([resolved.content, ui.mcpApp?.sourceId])\n if (this.deliveredToolPreviews.get(key) === fingerprint) continue\n this.deliveredToolPreviews.set(key, fingerprint)\n this.emitter.emit(\"toolPreview\", {\n toolCallId: block.tool_call_id,\n type: resolved.type,\n content: resolved.content,\n title: ui.title ?? \"工具预览\",\n ...(ui.mcpApp ? { mcpApp: ui.mcpApp } : {}),\n })\n }\n if (block.type === \"system_notification\" && isRecord(block.content)) {\n this._handleSystemNotification(turn.loop_id, block.content)\n }\n }\n\n for (const toolCall of turn.tool_calls) {\n const info: ToolCallInfo = {\n id: toolCall.id,\n name: toolCall.tool_name,\n display_name: toolCall.display_name,\n arguments: toolCall.arguments,\n result: toolCall.result ?? undefined,\n status:\n toolCall.status === \"pending\" ||\n toolCall.status === \"awaiting_answer\" ||\n toolCall.status === \"done\" ||\n toolCall.status === \"error\" ||\n toolCall.status === \"cancelled\"\n ? toolCall.status\n : (\"pending\" as const),\n }\n if (!this.seenToolCallIds.has(toolCall.id)) {\n this.seenToolCallIds.add(toolCall.id)\n this.emitter.emit(\"toolCall\", { toolCall: info, turn })\n }\n const finished =\n toolCall.status === \"done\" || toolCall.status === \"error\" || toolCall.status === \"cancelled\"\n if (finished && !this.finishedToolCallIds.has(toolCall.id)) {\n this.finishedToolCallIds.add(toolCall.id)\n this.emitter.emit(\"toolResult\", { toolCall: info, turn, source })\n if (isOomResult(toolCall.result)) {\n this.notifySandboxOom(toolCall.id)\n }\n }\n }\n\n if (turn.status !== \"streaming\" && !this.emittedMessageTurnIds.has(turn.turn_id)) {\n const message = this.state.messages.find((m) => m.entry_id === turn.turn_id)\n if (message) {\n this.emittedMessageTurnIds.add(turn.turn_id)\n this.emitter.emit(\"message\", { message, turn })\n }\n }\n }\n\n private dispatchCommand(\n turn: TurnProjection,\n block: ContentBlock,\n ): void {\n if (!isToolBridgeContent(block.content)) return\n const { action, payload } = block.content\n const deliveryKey = block.delivery_id\n ? commandDeliveryKey(block.delivery_id)\n : `legacy-tool-command:${turn.turn_id}:${block.tool_call_id ?? \"\"}:${action}:${JSON.stringify(payload)}`\n this.deliverCommand(deliveryKey, action, payload, block.tool_call_id ?? undefined)\n }\n\n private dispatchRawCommands(events: RawEvent[]): void {\n for (const event of events) {\n if (event.type !== \"loop:tool_bridge\") continue\n const deliveryId = String(event.payload.delivery_id ?? \"\")\n const bridge = event.payload.bridge\n if (!deliveryId || !isToolBridgeContent(bridge)) continue\n this.deliverCommand(\n commandDeliveryKey(deliveryId),\n bridge.action,\n bridge.payload,\n String(event.payload.tool_call_id ?? \"\") || undefined,\n )\n }\n }\n\n private deliverCommand(\n deliveryKey: string,\n action: string,\n payload: unknown,\n toolCallId: string | undefined,\n ): void {\n if (this.bufferedCommandDeliveries) {\n this.bufferedCommandDeliveries.push({ deliveryKey, action, payload, toolCallId })\n return\n }\n this.deliverCommandNow({ deliveryKey, action, payload, toolCallId })\n }\n\n private deliverCommandNow(command: PendingCommandDelivery): void {\n const { deliveryKey, action, payload, toolCallId } = command\n if (this.deliveredCommandKeys.has(deliveryKey)) return\n this.deliveredCommandKeys.add(deliveryKey)\n const meta = { toolCallId }\n this.emitter.emit(\"command\", { action, payload, toolCallId })\n this.commands.dispatch(action, payload, meta)\n }\n\n private notifySandboxOom(key: string): void {\n if (this.oomNotifiedKeys.has(key)) return\n this.oomNotifiedKeys.add(key)\n this.update((s) => addErrorMessage(s, OOM_MESSAGE))\n this.emitter.emit(\"sandboxOom\", { toolCallId: key })\n }\n\n /**\n * 权威刷新(运行结束 / 重连补数):**按当前窗口第一条发言取窗口**,不再另记\"用户想看哪段\"。\n *\n * 窗口本身就是\"用户在看哪段\":首屏就是最新一页,向上翻页 / 定位之后首条就是用户滚到的位置。\n * 直接拿 `from_entry_id = 当前窗口第一条 turn_id` 去取,运行结束、重连补数、翻页之后的对账\n * 是同一条规则,不需要意图、锚点、已落地锚点这些状态;窗口首条已经不在分支上(404 / 409)时\n * 回落到最新一页。\n */\n private refreshAuthoritativeHistory(options: {\n liveRevisionAtStart?: number\n modeRevisionAtStart?: number\n } = {}): Promise<boolean> {\n let entryGone = false\n const locateTokenAtStart = this.locateToken\n return this.replaceFromHistory({\n ...options,\n // 锚点在**这次操作真正开始**时采样:排队期间用户可能刚定位过,那时窗口首条才是他要的。\n fromEntryId: () => this.state.turns[0]?.turn_id,\n onError: (error) => {\n entryGone = isEntryGoneError(error)\n },\n }).then((located) => {\n if (located || !entryGone) return located\n // 期间用户又点了别的(流水号变了):这次回落不再插队——队列里已经有新的定位,\n // 它提交之后我再拿最新一页盖上去,用户那次点击就白点了。\n if (this.locateToken !== locateTokenAtStart) return false\n // 窗口首条已经不在当前分支上了(rewind / checkout 换了分支):回落到最新一页。\n return this.replaceFromHistory(options)\n })\n }\n\n private replaceFromHistory(options: {\n suppressErrors?: boolean\n liveRevisionAtStart?: number\n modeRevisionAtStart?: number\n /** 按这条发言定位:服务端返回\"从它到最新\"的窗口,而不是最新一页。传函数则在实际取数时求值。 */\n fromEntryId?: string | (() => string | undefined)\n /** 这次替换是否已被取代(用户改选了别的发言);返回 true 时整条丢弃。 */\n isStale?: () => boolean\n /** 中止在途请求(用户改选下一条时用);中止后同样整条丢弃。 */\n signal?: AbortSignal\n /** 取数失败时上报原始错误(调用方要区分\"目标没了\"和\"这次没取到\")。 */\n onError?: (error: unknown) => void\n } = {}): Promise<boolean> {\n if (this.disposed) return Promise.resolve(false)\n const operationEpoch = this.timelineEpoch\n const liveRevisionAtStart = options.liveRevisionAtStart ?? this.liveRevision\n const modeRevisionAtStart = options.modeRevisionAtStart ?? this.modeRevision\n // Invalidate immediately so the current window cannot accept a late\n // older page while this replacement waits in the queue, and release its\n // dedupe ownership before a repaired cursor can become visible.\n this.invalidateOlderPaging()\n this.replaceInFlight += 1\n const operation = async (): Promise<boolean> => {\n let previousNextBefore: string | null = null\n // 这次替换被作废(会话已释放 / timeline 被重写 / 被更新的定位取代)时,游标在下面\n // 已经被清成 null:还回去,否则窗口还在、向上翻页却没了锚点。\n const restoreCursor = () => {\n if (this.disposed || previousNextBefore === null) return\n this.update((state) => ({\n ...state,\n nextBefore: previousNextBefore,\n loadingOlder: false,\n }))\n }\n try {\n if (this.disposed || operationEpoch !== this.timelineEpoch) return false\n if (options.isStale?.()) return false\n // A previous queued replace may have committed after this replace was\n // requested. Re-establish the boundary when this operation actually\n // starts so its window cannot leak an older request into this one.\n this.invalidateOlderPaging()\n previousNextBefore = this.state.nextBefore\n this.update((state) => ({ ...state, nextBefore: null, loadingOlder: false }))\n const signal = options.signal\n const fromEntryId =\n typeof options.fromEntryId === \"function\" ? options.fromEntryId() : options.fromEntryId\n const page = await this.runtime.fetchTurnsPage(\n this.sessionId,\n fromEntryId ? { fromEntryId } : undefined,\n signal ? { signal } : undefined,\n )\n // 定位期间 timeline 被重写(rewind / checkout)时这份窗口已经属于旧分支:\n // 丢掉它,当前列表保持原样。用户在途中改选了别的发言同理。\n if (this.disposed || operationEpoch !== this.timelineEpoch) {\n restoreCursor()\n return false\n }\n if (options.isStale?.()) {\n restoreCursor()\n return false\n }\n if (!this.joined) this.seedToolCallDeliveryBaseline(page.turns)\n this.update((state) => {\n const next = withTurns(\n state,\n replaceWindow(state.turns, page.turns, liveRevisionAtStart, {\n current: this.liveRevision,\n byTurnId: this.liveRevisions,\n }),\n )\n return {\n ...next,\n mode:\n this.modeRevision === modeRevisionAtStart\n ? page.currentMode\n : state.mode,\n nextBefore: page.nextBefore,\n loadingOlder: false,\n }\n })\n this.pruneOptimisticLiveRevisions()\n this.projectionBuilder._seedTurns(this.state.turns)\n return true\n } catch (error) {\n options.onError?.(error)\n if (!this.disposed && operationEpoch === this.timelineEpoch) {\n this.update((state) => ({\n ...state,\n nextBefore: previousNextBefore,\n loadingOlder: false,\n }))\n }\n if (options.suppressErrors === false) throw error\n // Keep the visible snapshot. Reconnect, terminal repair, or explicit\n // reload will enqueue another authoritative replace.\n return false\n } finally {\n this.replaceInFlight -= 1\n }\n }\n const run = this.replaceQueue.then(operation)\n this.replaceQueue = run.catch(() => undefined)\n return run\n }\n\n private invalidateOlderPaging(): void {\n this.pagingGeneration += 1\n this.olderPending = null\n }\n\n private beginCommandRecovery(): number {\n this.commandRecoveryGeneration += 1\n this.commandRestoreRetryAttempt = 0\n this.bufferedCommandDeliveries ??= []\n if (this.commandRestoreRetryHandle !== null) {\n globalThis.clearTimeout(this.commandRestoreRetryHandle)\n this.commandRestoreRetryHandle = null\n }\n return this.commandRecoveryGeneration\n }\n\n private scheduleHistoricalCommandRestore(generation: number): void {\n const restore = async () => {\n if (this.disposed || generation !== this.commandRecoveryGeneration) return\n try {\n const commands = await this.runtime.fetchCommands(this.sessionId)\n if (this.disposed) return\n for (const command of commands) {\n if (this.disposed) return\n this.deliverCommandNow({\n deliveryKey: commandDeliveryKey(command.deliveryId),\n action: command.action,\n payload: command.payload,\n toolCallId: command.toolCallId,\n })\n }\n // A newer reconnect has already installed another observation\n // boundary. Its snapshot must decide when the shared live suffix is\n // safe to release; an older response may only seed dedupe state.\n if (generation !== this.commandRecoveryGeneration) return\n this.commandRestoreRetryAttempt = 0\n this.flushBufferedCommands(generation)\n } catch {\n // Keep the barrier closed: releasing its live suffix would make a\n // later authoritative prefix arrive out of order. Retry this\n // generation in the background so a healthy socket does not leave the\n // command lane frozen forever.\n if (\n !this.disposed &&\n generation === this.commandRecoveryGeneration &&\n this.commandRestoreRetryHandle === null\n ) {\n const retryDelay = Math.min(\n COMMAND_RESTORE_RETRY_BASE_MS * 2 ** this.commandRestoreRetryAttempt,\n COMMAND_RESTORE_RETRY_MAX_MS,\n )\n this.commandRestoreRetryAttempt += 1\n this.commandRestoreRetryHandle = globalThis.setTimeout(() => {\n this.commandRestoreRetryHandle = null\n if (!this.disposed && generation === this.commandRecoveryGeneration) {\n this.scheduleHistoricalCommandRestore(generation)\n }\n }, retryDelay)\n }\n }\n }\n const run = this.commandRestoreQueue.then(restore)\n this.commandRestoreQueue = run.catch(() => undefined)\n }\n\n private flushBufferedCommands(generation: number): void {\n const pending = [...(this.bufferedCommandDeliveries ?? [])]\n // Keep a barrier installed while invoking user handlers: they may\n // synchronously emit another command, reconnect, or dispose this session.\n this.bufferedCommandDeliveries = []\n let index = 0\n while (index < pending.length) {\n if (this.disposed) return\n if (generation !== this.commandRecoveryGeneration) {\n const currentGenerationBuffer = this.bufferedCommandDeliveries ?? []\n this.bufferedCommandDeliveries = [\n ...pending.slice(index),\n ...currentGenerationBuffer,\n ]\n return\n }\n this.deliverCommandNow(pending[index]!)\n index += 1\n const reentrantBuffer = this.bufferedCommandDeliveries\n if (index === pending.length && reentrantBuffer && reentrantBuffer.length > 0) {\n pending.push(...reentrantBuffer)\n this.bufferedCommandDeliveries = []\n }\n }\n if (!this.disposed && generation === this.commandRecoveryGeneration) {\n this.bufferedCommandDeliveries = null\n }\n }\n\n /** 首次订阅前的 REST 历史建立语义事件基线,随后同一工具的订阅回放不再投递。 */\n private seedToolCallDeliveryBaseline(turns: TurnProjection[]): void {\n for (const turn of turns) {\n for (const toolCall of turn.tool_calls) {\n this.seenToolCallIds.add(toolCall.id)\n if (\n toolCall.status === \"done\" ||\n toolCall.status === \"error\" ||\n toolCall.status === \"cancelled\"\n ) {\n this.finishedToolCallIds.add(toolCall.id)\n }\n }\n }\n }\n\n private ensureJoined(liveRevisionBoundary = this.liveRevision): Promise<void> {\n if (this.joined) return Promise.resolve()\n if (this.joinPending) return this.joinPending\n\n const join = this.runtime\n .emitWithAck(\n \"session:subscribe\",\n {\n session_id: this.sessionId,\n event_format: \"raw\",\n resume: true,\n },\n 5_000,\n )\n .then((response) => {\n if (response && response.ok === false) {\n throw new Error(\n typeof response.message === \"string\" && response.message\n ? response.message\n : \"Session subscription failed\",\n )\n }\n this.joined = true\n this._applyRunningState(Boolean(response?.is_running), liveRevisionBoundary)\n })\n .finally(() => {\n this.joinPending = null\n })\n\n this.joinPending = join\n return join\n }\n\n private async ensureIdleBeforeSend(): Promise<void> {\n // 客户端已知有运行在跑时不能走这段\"修好上一轮收尾\"的停止逻辑:它发的 chat:stop\n // 会取消正在跑的那一轮并暂停消息队列。运行中提交交给服务端判定排队即可。\n if (this.state.isStreaming) return\n if (Date.now() - this.recentChatEndAt > 3000) return\n const deadline = Date.now() + 3000\n while (Date.now() < deadline) {\n const response = await this.stop()\n const status = String(response.status ?? \"\")\n if (status !== \"stopping\") return\n await new Promise((resolve) => globalThis.setTimeout(resolve, 150))\n }\n }\n}\n","import type { BladeClient } from \"../blade-client\"\nimport type { PatchEnvelope, TurnProjection } from \"../schemas/projection\"\nimport { AuthBusyReconnect } from \"../shared/auth-busy\"\nimport { acknowledgeTurnEvents, type RawEvent } from \"../shared/projection\"\nimport { AgentSession, type SessionRuntime } from \"./agent-session\"\nimport type { ConnectionStatus } from \"./state\"\n\nconst BACKGROUND_STATUSES = [\n \"starting\",\n \"running\",\n \"cancelling\",\n \"succeeded\",\n \"failed\",\n \"cancelled\",\n \"lost\",\n] as const\n\ntype BackgroundStatus = (typeof BACKGROUND_STATUSES)[number]\n\n/** Keep an unknown status honest instead of guessing success. */\nfunction normalizeBackgroundStatus(value: unknown): BackgroundStatus {\n return (BACKGROUND_STATUSES as readonly string[]).includes(value as string)\n ? (value as BackgroundStatus)\n : \"running\"\n}\n\ntype BackgroundTaskEvent = {\n id?: string\n task_id?: string\n command?: string\n description?: string\n status?: string\n failure_reason?: string | null\n exit_code?: number | null\n elapsed_seconds?: number\n output_lines_count?: number\n output_preview?: string[]\n}\n\nexport interface SessionConnectOptions {\n /**\n * 在会话进入事件路由后、历史加载与房间订阅开始前同步执行。\n * 适合安装不能漏掉 bootstrap 回放事件的监听器。\n */\n setup?: (session: AgentSession) => void\n}\n\n/**\n * 每个 BladeClient 一个:管理一条 Socket.IO 连接,按 session_id 把事件\n * 路由给各 AgentSession 实例。多会话共享连接、状态互不干扰。\n */\nexport class SessionHub {\n private readonly client: BladeClient\n private readonly sessions = new Map<string, AgentSession>()\n private readonly bootstrapPending = new Map<string, Promise<AgentSession>>()\n /** 每个会话当前有多少方持有(connect 一次 +1,dispose 一次 -1)。 */\n private readonly holdCounts = new Map<string, number>()\n private connection: ConnectionStatus = \"disconnected\"\n private readonly connectionListeners = new Set<(status: ConnectionStatus) => void>()\n private bound = false\n private hasConnected = false\n private readonly authBusyReconnect = new AuthBusyReconnect()\n\n constructor(client: BladeClient) {\n this.client = client\n }\n\n /** 当前 Socket.IO 连接状态。 */\n getConnection(): ConnectionStatus {\n return this.connection\n }\n\n /** 订阅连接状态变化。 */\n onConnectionChange(listener: (status: ConnectionStatus) => void): () => void {\n this.connectionListeners.add(listener)\n return () => {\n this.connectionListeners.delete(listener)\n }\n }\n\n /**\n * 取得(或复用)一个会话的 AgentSession,并完成历史加载 + 房间订阅。\n *\n * 每次调用都算一份持有,调用方用完必须 `dispose()` 归还。复用同一实例时\n * 只有最后一份归还才退订房间——否则 StrictMode 双跑、路由抖动这类\"连两次\n * 只释放一次\"的场景会把仍在用的会话退订掉,之后所有 turn/chat 事件静默丢失。\n */\n async connect(sessionId: string, options: SessionConnectOptions = {}): Promise<AgentSession> {\n const existing = this.sessions.get(sessionId)\n if (existing && !existing.isDisposed) {\n this.hold(sessionId)\n try {\n options.setup?.(existing)\n } catch (error) {\n // setup 属于本次持有;失败只归还这一份,不影响其它使用方。\n existing.dispose()\n throw error\n }\n return this.bootstrapPending.get(sessionId) ?? existing\n }\n this.ensureBound()\n const session = new AgentSession(sessionId, this.runtimeFor(), this.connection)\n this.sessions.set(sessionId, session)\n this.hold(sessionId)\n try {\n options.setup?.(session)\n } catch (error) {\n session.dispose()\n throw error\n }\n this.ensureConnected()\n const bootstrap = session._bootstrap().then(() => session)\n this.bootstrapPending.set(sessionId, bootstrap)\n try {\n return await bootstrap\n } catch (error) {\n // 启动失败的会话不留给任何人,连同其它在途持有一起清掉\n this.forceRelease(session)\n throw error\n } finally {\n if (this.bootstrapPending.get(sessionId) === bootstrap) {\n this.bootstrapPending.delete(sessionId)\n }\n }\n }\n\n /** 已有实例则返回,不触发网络请求。 */\n peek(sessionId: string): AgentSession | undefined {\n if (this.bootstrapPending.has(sessionId)) return undefined\n const session = this.sessions.get(sessionId)\n return session && !session.isDisposed ? session : undefined\n }\n\n /** 手动重连(例如登录态变化后)。 */\n reconnect(): void {\n // 登录态可能早于首个 AgentSession 初始化;必须先绑定连接监听,\n // 否则 connect 事件会在 hub 尚未监听时丢失,状态永久停在 connecting。\n this.ensureBound()\n this.authBusyReconnect.cancel()\n const socket = this.client.socket()\n socket.disconnect()\n this.setConnection(\"connecting\")\n socket.connect()\n }\n\n /** 断开连接(不清理 session 实例)。 */\n disconnect(): void {\n this.authBusyReconnect.cancel()\n this.client.socket().disconnect()\n this.setConnection(\"disconnected\")\n }\n\n /** 清理当前身份下缓存的全部会话,避免切换登录身份后复用旧快照。 */\n disposeAll(): void {\n this.authBusyReconnect.cancel()\n this.bootstrapPending.clear()\n for (const session of [...this.sessions.values()]) {\n // 换身份后旧会话一律作废,不看还有几方持有\n this.forceRelease(session)\n }\n }\n\n /**\n * @internal 底层 socket 被换掉时由 BladeClient 调用(如 setBaseUrl)。\n * 事件监听器绑在旧 socket 实例上,换新实例后必须重绑,否则所有\n * turn:* / chat:* 事件都会静默丢弃。\n */\n _handleSocketReplaced(): void {\n this.authBusyReconnect.cancel()\n this.bound = false\n this.setConnection(\"disconnected\")\n if (this.sessions.size === 0) return\n // 已有会话:在新 socket 上重建监听;连接成功事件会重新加入房间并补数\n this.ensureBound()\n this.ensureConnected()\n }\n\n private runtimeFor(): SessionRuntime {\n return {\n emitEvent: (event, data) => {\n // biome-ignore lint/suspicious/noExplicitAny: 泛化 emit,事件名由调用方保证\n ;(this.client.socket() as any).emit(event, data)\n },\n emitWithAck: (event, data, timeoutMs) =>\n new Promise((resolve, reject) => {\n // biome-ignore lint/suspicious/noExplicitAny: 泛化 emit,事件名由调用方保证\n ;(this.client.socket() as any)\n .timeout(timeoutMs)\n .emit(event, data, (err: Error | null, response?: Record<string, unknown>) => {\n if (err) {\n reject(err)\n return\n }\n resolve(response)\n })\n }),\n ensureConnected: () => this.ensureConnected(),\n fetchTurnsPage: (sessionId, query, init) =>\n this.client.sessions.getSessionTurnsPage(sessionId, query, init),\n fetchTurnIndex: (sessionId) => this.client.sessions.getSessionTurnIndex(sessionId),\n fetchCommands: (sessionId) => this.client.sessions.getSessionTurnCommands(sessionId),\n fetchSessionInfo: (sessionId) => this.client.sessions.getSession(sessionId),\n updateReplay: (sessionId, payload) =>\n this.client.sessions\n .updateReplaySession(sessionId, payload)\n .then((result) => result.replay_state ?? null),\n listDir: (sessionId, dirPath) => this.client.sessions.listDir(sessionId, dirPath),\n countFiles: (sessionId, dirPath) => this.client.sessions.countFiles(sessionId, dirPath),\n downloadFile: (sessionId, filePath, downloadName) =>\n this.client.sessions.downloadFile(sessionId, filePath, downloadName),\n attachAppCli: (sessionId, definition) =>\n this.client.sessions.attachAppCli(sessionId, definition),\n onDispose: (session) => this.release(session),\n }\n }\n\n /** 记一份持有。 */\n private hold(sessionId: string): void {\n this.holdCounts.set(sessionId, (this.holdCounts.get(sessionId) ?? 0) + 1)\n }\n\n /**\n * 归还一份持有;还剩别的持有者时返回 false,让 AgentSession 保持可用。\n * 归零才退订房间并从路由表移除。\n */\n private release(session: AgentSession): boolean {\n const remaining = (this.holdCounts.get(session.sessionId) ?? 0) - 1\n if (remaining > 0) {\n this.holdCounts.set(session.sessionId, remaining)\n return false\n }\n this.holdCounts.delete(session.sessionId)\n if (this.sessions.get(session.sessionId) === session) {\n this.sessions.delete(session.sessionId)\n }\n if (this.sessions.size === 0) {\n this.authBusyReconnect.cancel()\n }\n // biome-ignore lint/suspicious/noExplicitAny: session:unsubscribe 是后端自定义事件\n ;(this.client.socket() as any).emit(\"session:unsubscribe\", { session_id: session.sessionId })\n return true\n }\n\n /** 不管还有几方持有都立即释放(启动失败、切换身份)。 */\n private forceRelease(session: AgentSession): void {\n this.holdCounts.delete(session.sessionId)\n session.dispose()\n if (this.sessions.size === 0) {\n this.authBusyReconnect.cancel()\n }\n }\n\n private ensureConnected(): void {\n const socket = this.client.socket()\n if (socket.connected || socket.active || this.authBusyReconnect.pending) return\n this.setConnection(\"connecting\")\n socket.connect()\n }\n\n private setConnection(status: ConnectionStatus): void {\n if (this.connection === status) return\n this.connection = status\n for (const session of this.sessions.values()) {\n session._setConnection(status)\n }\n for (const listener of [...this.connectionListeners]) {\n try {\n listener(status)\n } catch (error) {\n console.warn(\"[agent-client] 连接状态回调抛出异常:\", error)\n }\n }\n }\n\n /** 事件带 session_id 时精确路由;缺省时按当前唯一活跃会话兜底。 */\n private route(sessionId: string | null | undefined): AgentSession[] {\n if (sessionId) {\n const session = this.sessions.get(sessionId)\n return session && !session.isDisposed ? [session] : []\n }\n const active = [...this.sessions.values()].filter((session) => !session.isDisposed)\n return active.length === 1 ? active : []\n }\n\n private ensureBound(): void {\n if (this.bound) return\n this.bound = true\n // biome-ignore lint/suspicious/noExplicitAny: 事件桥接层统一收敛混合 payload\n const socket = this.client.socket() as any\n\n socket.on(\"connect\", () => {\n this.authBusyReconnect.cancel()\n const isReconnect = this.hasConnected\n this.hasConnected = true\n this.setConnection(\"connected\")\n if (isReconnect) {\n for (const session of this.sessions.values()) {\n void session._rejoinAfterReconnect()\n // 队列广播不会重放:断线期间错过的入队 / 编辑只能主动补一次。\n // 不放进 _rejoinAfterReconnect 的订阅串行队列,避免慢 ack 拖住重订阅。\n void session.refreshQueue()\n }\n }\n })\n socket.on(\"connect_error\", (error: unknown) => {\n this.setConnection(\"disconnected\")\n if (this.sessions.size === 0) {\n this.authBusyReconnect.cancel()\n return\n }\n if (this.authBusyReconnect.schedule(error, () => {\n const current = this.client.socket()\n if (current !== socket || current.connected || current.active) return\n this.setConnection(\"connecting\")\n current.connect()\n })) return\n this.authBusyReconnect.cancel()\n })\n socket.on(\"disconnect\", () => {\n this.authBusyReconnect.cancel()\n this.setConnection(\"disconnected\")\n })\n socket.io.on(\"reconnect_attempt\", () => this.setConnection(\"reconnecting\"))\n\n socket.on(\"turn:start\", (data: TurnProjection & { session_id?: string }) => {\n for (const session of this.route(data.session_id)) session._handleTurnStart(data)\n })\n socket.on(\"turn:patch\", (data: PatchEnvelope & { session_id?: string }) => {\n for (const session of this.route(data.session_id)) session._handleTurnPatch(data)\n })\n socket.on(\"turn:end\", (data: TurnProjection & { session_id?: string }) => {\n for (const session of this.route(data.session_id)) session._handleTurnEnd(data)\n })\n socket.on(\n \"turn:timing\",\n (data: {\n session_id?: string\n loop_name?: string\n turn_id?: string\n first_token_delivery_ms?: number\n }) => {\n for (const session of this.route(data.session_id)) {\n session._handleTurnEvents([\n { type: \"llm:first_token:delivered\", payload: data },\n ])\n }\n },\n )\n socket.on(\n \"turn:events\",\n (\n data: { session_id?: string; events: RawEvent[]; replayed?: boolean },\n acknowledge?: () => void,\n ) => {\n acknowledgeTurnEvents(acknowledge)\n for (const session of this.route(data.session_id)) {\n session._handleTurnEvents(data.events ?? [], data.replayed === true)\n }\n },\n )\n socket.on(\"chat:start\", (data?: { session_id?: string }) => {\n for (const session of this.route(data?.session_id)) session._handleChatStart()\n })\n socket.on(\"chat:end\", (data?: { status?: string; session_id?: string }) => {\n for (const session of this.route(data?.session_id)) {\n session._handleChatEnd(data?.status ?? \"completed\")\n }\n })\n socket.on(\"system:error\", (data: { message: string; session_id?: string }) => {\n for (const session of this.route(data.session_id)) session._handleSystemError(data.message)\n })\n // 队列广播只发给 owner 房间;快照本体就是载荷,旧 revision 由会话实例丢弃。\n socket.on(\"chat:queue:updated\", (data: Record<string, unknown> & { session_id?: string }) => {\n for (const session of this.route(data?.session_id)) session._handleQueueUpdated(data)\n })\n socket.on(\n \"system:notification\",\n (data: { session_id?: string } & Record<string, unknown>) => {\n for (const session of this.route(data.session_id)) {\n session._handleSystemNotification(\"root\", data)\n }\n },\n )\n socket.on(\"task:updated\", (data: { tasks: unknown[]; session_id?: string }) => {\n for (const session of this.route(data.session_id)) session._handleTaskUpdated(data.tasks)\n })\n socket.on(\"task:synced\", (data: { tasks: unknown[]; session_id?: string }) => {\n for (const session of this.route(data.session_id)) session._handleTaskUpdated(data.tasks)\n })\n socket.on(\n \"workspace:files_changed\",\n (data: { session_id?: string; file_path?: string }) => {\n for (const session of this.route(data.session_id)) {\n session._handleWorkspaceFilesChanged(data.file_path)\n }\n },\n )\n socket.on(\n \"session:updated\",\n (data: {\n session_id?: string\n workspace_path?: string\n chat_group_id?: string | null\n intent?: string\n status?: import(\"../schemas/session\").SessionStatus\n model?: string | null\n bound_skill_id?: string | null\n replay_state?: Record<string, unknown> | null\n }) => {\n for (const session of this.route(data.session_id)) {\n session._handleSessionUpdated(data)\n }\n },\n )\n socket.on(\"session:rewind\", (data: { checkpoint_id: string; session_id?: string }) => {\n for (const session of this.route(data.session_id)) {\n session._handleRewind(data.checkpoint_id)\n }\n })\n socket.on(\n \"replay:input_mismatch\",\n (data: { session_id?: string; actual_message?: string; expected_message?: string }) => {\n for (const session of this.route(data.session_id)) session._handleReplayMismatch(data)\n },\n )\n socket.on(\"artifact:created\", (data: Record<string, unknown> & { session_id?: string }) => {\n this.routeArtifact(data, \"created\")\n })\n socket.on(\"artifact:updated\", (data: Record<string, unknown> & { session_id?: string }) => {\n this.routeArtifact(data, \"updated\")\n })\n socket.on(\"bg:started\", (data: BackgroundTaskEvent & { session_id?: string }) => {\n const taskId =\n typeof data.task_id === \"string\" ? data.task_id : typeof data.id === \"string\" ? data.id : \"\"\n if (!taskId) return\n for (const session of this.route(data.session_id)) {\n session._handleBackgroundTask({\n id: taskId,\n command: typeof data.command === \"string\" ? data.command : \"\",\n description: typeof data.description === \"string\" ? data.description : undefined,\n status: \"running\",\n elapsedSeconds: typeof data.elapsed_seconds === \"number\" ? data.elapsed_seconds : 0,\n })\n }\n })\n socket.on(\n \"bg:tasks_completed\",\n (data: { tasks?: BackgroundTaskEvent[]; session_id?: string }) => {\n for (const session of this.route(data.session_id)) {\n for (const task of data.tasks ?? []) {\n const taskId =\n typeof task.id === \"string\"\n ? task.id\n : typeof task.task_id === \"string\"\n ? task.task_id\n : \"\"\n if (!taskId) continue\n session._handleBackgroundTask({\n id: taskId,\n command: typeof task.command === \"string\" ? task.command : \"\",\n description: typeof task.description === \"string\" ? task.description : undefined,\n // Pass the server's status through unchanged. Collapsing it here\n // made subscribers see a successful-looking \"done\" for tasks the\n // REST API correctly reported as cancelled or lost.\n status: normalizeBackgroundStatus(task.status),\n failureReason:\n typeof task.failure_reason === \"string\" ? task.failure_reason : undefined,\n exitCode:\n typeof task.exit_code === \"number\" || task.exit_code === null\n ? task.exit_code\n : undefined,\n elapsedSeconds: typeof task.elapsed_seconds === \"number\" ? task.elapsed_seconds : 0,\n output:\n Array.isArray(task.output_preview) && task.output_preview.length > 0\n ? task.output_preview.join(\"\\n\")\n : undefined,\n })\n }\n }\n },\n )\n }\n\n private routeArtifact(\n data: Record<string, unknown> & { session_id?: string },\n kind: \"created\" | \"updated\",\n ): void {\n const filePath = typeof data.file_path === \"string\" ? data.file_path : \"\"\n if (!filePath) return\n for (const session of this.route(data.session_id)) {\n session._handleWorkspaceFilesChanged(filePath)\n session._handleArtifact({\n filePath,\n contentType: typeof data.content_type === \"string\" ? data.content_type : \"\",\n title: typeof data.title === \"string\" ? data.title : filePath,\n content: typeof data.content === \"string\" ? data.content : \"\",\n oldString: typeof data.old_string === \"string\" ? data.old_string : undefined,\n newString: typeof data.new_string === \"string\" ? data.new_string : undefined,\n kind,\n })\n }\n }\n}\n","import { io, type Socket } from \"socket.io-client\"\nimport { buildSocketAuth, resolveAuthToken, type AuthOptions } from \"./auth\"\nimport type { ClientToServerEvents, ServerToClientEvents } from \"./types/socket-events\"\n\nexport type TypedSocket = Socket<ServerToClientEvents, ClientToServerEvents>\n\nexport interface CreateSocketOptions extends AuthOptions {\n baseUrl: string\n path?: string\n}\n\nexport function createSocket(options: CreateSocketOptions): TypedSocket {\n const token = resolveAuthToken(options)\n return io(options.baseUrl, {\n path: options.path ?? \"/socket.io\",\n withCredentials: true,\n query: token ? { token } : undefined,\n auth:\n typeof options.token === \"function\"\n ? (cb) => cb(buildSocketAuth(options) ?? {})\n : (buildSocketAuth(options) ?? {}),\n autoConnect: false,\n })\n}\n","export interface AuthOptions {\n token?: string | (() => string | null | undefined)\n}\n\nexport function buildSocketAuth(options: AuthOptions): { token: string } | undefined {\n const token = resolveAuthToken(options)\n return token ? { token } : undefined\n}\n\nexport function resolveAuthToken(options: AuthOptions): string | null {\n const token = typeof options.token === \"function\" ? options.token() : options.token\n return token ? token : null\n}\n","import {\n loginWithPopup,\n readStoredToken,\n writeStoredToken,\n type LoginOptions,\n type LoginResult,\n type TokenStorageMode,\n} from \"./auth-login\"\nimport {\n BladeApiError,\n type BladeFetchInit,\n type HttpMethod,\n buildBackendUrl,\n decorateAuthError,\n extractErrorDetail,\n} from \"./rest\"\nimport { AuthResource } from \"./resources/auth\"\nimport { HeadlessResource } from \"./resources/headless\"\nimport { ComputersResource } from \"./resources/computers\"\nimport { ModelsResource } from \"./resources/models\"\nimport { SessionsResource } from \"./resources/sessions\"\nimport { PluginsResource } from \"./resources/plugins\"\nimport { ChatGroupsResource } from \"./resources/chat-groups\"\nimport { SiteVisitsResource } from \"./resources/site-visits\"\nimport { SessionHub } from \"./session/hub\"\nimport { createSocket, type TypedSocket } from \"./socket\"\n\nexport interface BladeClientOptions {\n /** 后端地址,如 \"https://blade.example.com\"。浏览器里传空字符串则使用当前域名。 */\n baseUrl: string\n /**\n * 访问令牌(PAT)。不传时按 cookie 会话模式工作;\n * 浏览器场景也可以不传,改用 client.auth.login() 弹窗登录。\n */\n token?: string | (() => string | null | undefined)\n /**\n * Socket.IO 专用令牌。第一方应用可在 REST 继续使用 cookie 刷新的同时,\n * 把 cookie 换得的短期令牌只用于实时连接;不传时复用 token。\n */\n socketToken?: string | (() => string | null | undefined)\n /** login() 取得的令牌存放位置,默认 \"local\"(localStorage,刷新页面不掉登录)。 */\n tokenStorage?: TokenStorageMode\n fetchImpl?: typeof fetch\n onRefreshSuccess?: () => void | Promise<void>\n}\n\nconst REFRESH_PATH = \"/api/auth/refresh\"\n\nexport class BladeClient {\n private refreshPromise: Promise<boolean> | null = null\n private socketInstance: TypedSocket | null = null\n private readonly socketReplacementListeners = new Set<() => void>()\n /** login() / setToken() 热挂载的令牌,优先级高于构造参数。 */\n private runtimeToken: string | null = null\n readonly options: BladeClientOptions\n readonly auth: AuthResource\n readonly headless: HeadlessResource\n readonly computers: ComputersResource\n readonly models: ModelsResource\n readonly sessions: SessionsResource\n /** 按用户读取的插件目录与图标;没有会话时也能用。 */\n readonly plugins: PluginsResource\n readonly chatGroups: ChatGroupsResource\n /**\n * 全站访问统计:匿名读写,不带 bearer 也不触发登录刷新。\n * 只有内置 Web 的同源页面使用,第三方宿主页面不会被自动统计。\n */\n readonly siteVisits: SiteVisitsResource\n /** 实时会话中枢:client.sessions.connect() 内部使用,一般不直接访问。 */\n readonly hub: SessionHub\n\n constructor(options: BladeClientOptions) {\n this.options = {\n ...options,\n baseUrl: normalizeBaseUrl(options.baseUrl),\n }\n this.auth = new AuthResource(this)\n this.headless = new HeadlessResource(this)\n this.computers = new ComputersResource(this)\n this.models = new ModelsResource(this)\n this.sessions = new SessionsResource(this)\n this.plugins = new PluginsResource(this)\n this.chatGroups = new ChatGroupsResource(this)\n this.siteVisits = new SiteVisitsResource(this)\n this.hub = new SessionHub(this)\n if (this.options.token === undefined) {\n this.runtimeToken = readStoredToken(this.options.baseUrl)\n }\n }\n\n /**\n * 弹窗授权登录:用户在弹出的授权页点击\"许可授权\"后自动取得 PAT,\n * REST 与 Socket.IO 立即生效。只在浏览器可用。\n */\n async login(options?: LoginOptions): Promise<LoginResult> {\n const result = await loginWithPopup(this, options)\n this.setToken(result.token)\n return result\n }\n\n /** 退出登录:清除 login() 存储的令牌并断开实时连接。 */\n logoutToken(): void {\n this.setToken(null)\n this.hub.disconnect()\n }\n\n /** 热挂载访问令牌(null 表示清除)。会重建 Socket.IO 连接以携带新凭证。 */\n setToken(token: string | null): void {\n const previousToken = this.resolveToken()\n this.runtimeToken = token\n const nextToken = this.resolveToken()\n if (previousToken !== nextToken) {\n this.hub.disposeAll()\n }\n writeStoredToken(this.options.baseUrl, token, this.options.tokenStorage ?? \"local\")\n if (this.socketInstance) {\n const wasConnected = this.socketInstance.connected || this.socketInstance.active\n this.socketInstance.disconnect()\n if (wasConnected || token) {\n this.socketInstance.connect()\n }\n }\n }\n\n /** 当前是否持有访问令牌(不代表令牌一定有效)。 */\n hasToken(): boolean {\n return Boolean(this.resolveRestToken())\n }\n\n /**\n * 当前访问令牌(PAT),未登录时为 null。\n *\n * SDK 只封装会话相关接口;其余长尾接口对照后端 Swagger(`<baseUrl>/docs`)\n * 用原生 fetch 自行调用,把本令牌填入 Authorization 头即可:\n *\n * ```ts\n * fetch(`${baseUrl}/api/memories/search?q=xxx`, {\n * headers: { Authorization: `Bearer ${client.token}` },\n * })\n * ```\n *\n * 安全约束:该令牌只应发往 baseUrl 同源接口,不要附加到第三方域名的请求上。\n */\n get token(): string | null {\n return this.resolveRestToken()\n }\n\n setBaseUrl(baseUrl: string): void {\n const nextBaseUrl = normalizeBaseUrl(baseUrl)\n if (nextBaseUrl === this.options.baseUrl) {\n return\n }\n // 后端地址是会话身份边界,不是普通传输重连。旧 session_id、历史快照\n // 和房间订阅都不能带到另一个后端;先在旧 socket 上释放并驱逐缓存。\n this.hub.disposeAll()\n this.options.baseUrl = nextBaseUrl\n if (this.socketInstance) {\n this.socketInstance.removeAllListeners()\n this.socketInstance.disconnect()\n this.socketInstance = null\n // 换掉 socket 实例后必须让 hub 重绑监听:监听器绑在旧实例上,\n // 不重绑的话新连接上的事件全部收不到。\n this.hub._handleSocketReplaced()\n for (const listener of [...this.socketReplacementListeners]) {\n try {\n listener()\n } catch (error) {\n console.warn(\"[agent-client] socket 替换回调抛出异常:\", error)\n }\n }\n }\n }\n\n /** 底层 Socket.IO 实例因后端地址变化而被替换时通知高级集成层。 */\n onSocketReplaced(listener: () => void): () => void {\n this.socketReplacementListeners.add(listener)\n return () => {\n this.socketReplacementListeners.delete(listener)\n }\n }\n\n socket(): TypedSocket {\n if (!this.socketInstance) {\n this.socketInstance = createSocket({\n baseUrl: this.options.baseUrl,\n token: () => this.resolveSocketToken(),\n })\n }\n return this.socketInstance\n }\n\n async json<T>(method: HttpMethod, path: string, body?: unknown): Promise<T> {\n const response = await this.fetch(method, path, {\n body: body === undefined ? undefined : JSON.stringify(body),\n headers: body === undefined ? undefined : { \"content-type\": \"application/json\" },\n })\n return readJsonResponse(response)\n }\n\n async jsonFromInit<T>(path: string, init: RequestInit = {}): Promise<T> {\n const method = (init.method ?? \"GET\").toUpperCase() as HttpMethod\n const headers = new Headers(init.headers)\n if (init.body != null && !isFormData(init.body) && !headers.has(\"content-type\")) {\n headers.set(\"content-type\", \"application/json\")\n }\n const response = await this.fetch(method, path, {\n body: init.body,\n credentials: init.credentials,\n headers,\n signal: init.signal,\n })\n return readJsonResponse(response)\n }\n\n async text(method: HttpMethod, path: string): Promise<string> {\n const response = await this.fetch(method, path)\n return response.text()\n }\n\n async textFromInit(path: string, init: RequestInit = {}): Promise<string> {\n const method = (init.method ?? \"GET\").toUpperCase() as HttpMethod\n const response = await this.fetch(method, path, {\n body: init.body,\n credentials: init.credentials,\n headers: init.headers,\n signal: init.signal,\n })\n return response.text()\n }\n\n async responseFromInit(path: string, init: RequestInit = {}): Promise<Response> {\n const method = (init.method ?? \"GET\").toUpperCase() as HttpMethod\n return this.fetch(method, path, {\n body: init.body,\n credentials: init.credentials,\n headers: init.headers,\n signal: init.signal,\n })\n }\n\n async blob(method: HttpMethod, path: string): Promise<Blob> {\n const response = await this.fetch(method, path)\n return response.blob()\n }\n\n async formData(\n method: HttpMethod,\n path: string,\n form: FormData,\n options: { expectOk?: boolean; onUploadProgress?: (progress: UploadProgress) => void } = {},\n ): Promise<Response> {\n if (options.onUploadProgress && !this.options.fetchImpl && typeof XMLHttpRequest !== \"undefined\") {\n return this.formDataWithUploadProgress(method, path, form, options)\n }\n return this.fetch(method, path, { body: form, expectOk: options.expectOk })\n }\n\n async fetch(\n method: HttpMethod,\n path: string,\n init: BladeFetchInit = {},\n isRetry = false,\n ): Promise<Response> {\n const url = this.buildUrl(path)\n const response = await (this.options.fetchImpl ?? fetch)(url.toString(), {\n method,\n body: init.body,\n credentials: init.credentials ?? \"include\",\n headers: this.buildHeaders(url, init.headers),\n signal: init.signal,\n })\n\n if (response.status === 401 && !isRetry && this.shouldRefreshFor401(url)) {\n const refreshed = await this.tryRefreshUnlessAborted(init.signal)\n if (refreshed) {\n return this.fetch(method, path, init, true)\n }\n }\n\n if (init.expectOk !== false && !response.ok) {\n const detail = await extractErrorDetail(response)\n throw decorateAuthError(new BladeApiError(response, detail))\n }\n return response\n }\n\n buildAuthedUrl(path: string): string {\n const url = buildBackendUrl(this.options.baseUrl, path)\n const token = this.resolveTokenForUrl(url)\n if (token) {\n url.searchParams.set(\"token\", token)\n }\n return url.toString()\n }\n\n private buildHeaders(url: URL, headers?: HeadersInit): Headers {\n const result = new Headers(headers)\n if (!this.isSameBackendUrl(url)) {\n return result\n }\n // REST 不做版本校验:SDK 身份只在 Socket.IO 握手声明(见 socket.ts)。\n // 长尾接口设计上就让第三方用原生 fetch 直接调,这里不该塞额外标头。\n const token = this.resolveRestToken()\n if (token) {\n result.set(\"Authorization\", `Bearer ${token}`)\n }\n return result\n }\n\n private buildUrl(path: string): URL {\n return buildBackendUrl(this.options.baseUrl, path)\n }\n\n private baseUrlWithTrailingSlash(): string {\n return this.options.baseUrl.endsWith(\"/\") ? this.options.baseUrl : `${this.options.baseUrl}/`\n }\n\n private isSameBackendUrl(url: URL): boolean {\n const base = new URL(this.baseUrlWithTrailingSlash())\n if (url.origin !== base.origin) {\n return false\n }\n const basePath = base.pathname.replace(/\\/+$/, \"\")\n if (basePath === \"\") {\n return true\n }\n return url.pathname === basePath || url.pathname.startsWith(`${basePath}/`)\n }\n\n private shouldRefreshFor401(url: URL): boolean {\n const refreshUrl = this.buildUrl(REFRESH_PATH)\n return (\n this.isSameBackendUrl(url) &&\n url.pathname !== refreshUrl.pathname &&\n !this.hasExplicitBearerToken()\n )\n }\n\n private hasExplicitBearerToken(): boolean {\n return Boolean(this.resolveRestToken())\n }\n\n /**\n * 等一次令牌刷新,但调用方中止请求时不再等下去。\n *\n * 刷新本身是共享的(`refreshPromise`,别的请求也在等它),这里只是让这次已被取消的\n * 请求尽早结束——否则它会一直挂在调用方(定位)的串行队列里,用户改选的新目标要等到\n * 刷新结束才轮得到。\n */\n private async tryRefreshUnlessAborted(signal?: AbortSignal | null): Promise<boolean> {\n if (!signal) return this.tryRefresh()\n if (signal.aborted) throw new DOMException(\"The operation was aborted.\", \"AbortError\")\n let onAbort: (() => void) | undefined\n const aborted = new Promise<never>((_resolve, reject) => {\n onAbort = () => reject(new DOMException(\"The operation was aborted.\", \"AbortError\"))\n signal.addEventListener(\"abort\", onAbort, { once: true })\n })\n try {\n return await Promise.race([this.tryRefresh(), aborted])\n } finally {\n if (onAbort) signal.removeEventListener(\"abort\", onAbort)\n }\n }\n\n private async tryRefresh(): Promise<boolean> {\n if (this.refreshPromise) {\n return this.refreshPromise\n }\n\n this.refreshPromise = (async () => {\n try {\n const response = await (this.options.fetchImpl ?? fetch)(\n this.buildUrl(REFRESH_PATH).toString(),\n {\n method: \"POST\",\n credentials: \"include\",\n },\n )\n if (!response.ok) {\n return false\n }\n await this.options.onRefreshSuccess?.()\n return true\n } catch {\n return false\n } finally {\n this.refreshPromise = null\n }\n })()\n\n return this.refreshPromise\n }\n\n private resolveTokenForUrl(url: URL): string | null {\n if (!this.isSameBackendUrl(url)) {\n return null\n }\n return this.resolveRestToken()\n }\n\n private resolveRestToken(): string | null {\n return this.resolveToken()\n }\n\n private resolveSocketToken(): string | null {\n if (this.runtimeToken) return this.runtimeToken\n return resolveTokenOption(this.options.socketToken ?? this.options.token)\n }\n\n private resolveToken(): string | null {\n if (this.runtimeToken) return this.runtimeToken\n return resolveTokenOption(this.options.token)\n }\n\n private formDataWithUploadProgress(\n method: HttpMethod,\n path: string,\n form: FormData,\n options: { expectOk?: boolean; onUploadProgress?: (progress: UploadProgress) => void },\n isRetry = false,\n ): Promise<Response> {\n const url = this.buildUrl(path)\n const headers = this.buildHeaders(url)\n\n return new Promise((resolve, reject) => {\n const xhr = new XMLHttpRequest()\n xhr.open(method, url.toString(), true)\n xhr.withCredentials = true\n\n headers.forEach((value, key) => {\n xhr.setRequestHeader(key, value)\n })\n\n xhr.upload.onprogress = (event) => {\n options.onUploadProgress?.({\n loaded: event.loaded,\n total: event.lengthComputable ? event.total : undefined,\n percent: event.lengthComputable && event.total > 0 ? event.loaded / event.total : undefined,\n })\n }\n\n xhr.onerror = () => reject(new TypeError(\"Network request failed\"))\n xhr.ontimeout = () => reject(new TypeError(\"Network request timed out\"))\n xhr.onabort = () => reject(new DOMException(\"Request aborted\", \"AbortError\"))\n xhr.onload = async () => {\n if (xhr.status === 401 && !isRetry && this.shouldRefreshFor401(url)) {\n const refreshed = await this.tryRefresh()\n if (refreshed) {\n resolve(this.formDataWithUploadProgress(method, path, form, options, true))\n return\n }\n }\n\n const response = new Response(xhr.responseText, {\n status: xhr.status,\n statusText: xhr.statusText,\n headers: parseXhrHeaders(xhr.getAllResponseHeaders()),\n })\n if (options.expectOk !== false && !response.ok) {\n const detail = await extractErrorDetail(response.clone())\n reject(new BladeApiError(response, detail))\n return\n }\n options.onUploadProgress?.({ loaded: 1, total: 1, percent: 1 })\n resolve(response)\n }\n\n xhr.send(form)\n })\n }\n}\n\nfunction resolveTokenOption(\n tokenOption: string | (() => string | null | undefined) | undefined,\n): string | null {\n const token = typeof tokenOption === \"function\" ? tokenOption() : tokenOption\n return token ? token : null\n}\n\nexport interface UploadProgress {\n loaded: number\n total?: number\n percent?: number\n}\n\n/** Docker 给容器用的宿主机别名。浏览器里没有这条 DNS,怎么都解析不到。 */\nconst SANDBOX_ONLY_HOST = \"host.docker.internal\"\n\nfunction normalizeBaseUrl(baseUrl: string): string {\n const normalized = baseUrl.trim().replace(/\\/+$/, \"\")\n if (typeof window === \"undefined\") {\n // 沙盒里的 Node SDK 就该用 host.docker.internal,那是它唯一能连到宿主的地址。\n return normalized\n }\n if (!normalized) {\n return window.location.origin\n }\n assertBrowserReachable(normalized)\n return normalized\n}\n\n/**\n * 浏览器里拿到 `host.docker.internal` 就当场报错,不猜、不改、不静默降级。\n *\n * 智能体在沙盒里开发应用时,手边的后端地址是 `BLADE_API_URL`\n * (`http://host.docker.internal:8020`),很容易被原样写进前端配置。这个地址只有\n * 容器里解析得到,用户浏览器打不开——登录授权页会直接白屏,而 `client_origin` 却是\n * 真实 IP,故障看起来毫无头绪。与其替换主机名去猜一个\"可能对\"的地址,不如立刻把\n * 原因说清楚:这类配置错误必须在开发阶段就暴露出来。\n */\nfunction assertBrowserReachable(baseUrl: string): void {\n let hostname: string\n try {\n hostname = new URL(baseUrl, window.location.href).hostname\n } catch {\n return\n }\n if (hostname !== SANDBOX_ONLY_HOST) {\n return\n }\n throw new Error(\n `Blade Agent 地址 ${baseUrl} 只有沙盒内部解析得到,浏览器打不开。请把它改成用户浏览器能访问的地址(通常是访问这个应用时用的主机名 + Blade Server 端口)。`,\n )\n}\n\nfunction isFormData(value: BodyInit): boolean {\n return typeof FormData !== \"undefined\" && value instanceof FormData\n}\n\nfunction readJsonResponse<T>(response: Response): Promise<T> {\n if (response.status === 204 || response.headers.get(\"content-length\") === \"0\") {\n return Promise.resolve(undefined as T)\n }\n return response.json() as Promise<T>\n}\n\nfunction parseXhrHeaders(rawHeaders: string): Headers {\n const headers = new Headers()\n for (const line of rawHeaders.trim().split(/[\\r\\n]+/)) {\n const separatorIndex = line.indexOf(\":\")\n if (separatorIndex <= 0) continue\n headers.append(line.slice(0, separatorIndex).trim(), line.slice(separatorIndex + 1).trim())\n }\n return headers\n}\n","import { BladeApiError } from \"./rest\"\n\nconst MAX_BACKOFF_MS = 60_000\nconst MAX_TIMER_MS = 2_147_483_647\n\n/** Scheduling policy for read-only polling; never sends or replays a request. */\nexport class PollingBackoff {\n private failures = 0\n private nextAt: number | false = 0\n\n constructor(private readonly intervalMs: number) {\n if (!Number.isFinite(intervalMs) || intervalMs <= 0 || intervalMs > MAX_BACKOFF_MS) {\n throw new RangeError(\"Polling interval must be between 0 and 60000 ms\")\n }\n }\n\n reset(): void {\n this.failures = 0\n this.nextAt = 0\n }\n\n failed(error: unknown): void {\n if (\n (error instanceof Error && error.name === \"AbortError\") ||\n (error instanceof BladeApiError && error.status < 500 &&\n error.status !== 408 && error.status !== 429)\n ) {\n this.nextAt = false\n return\n }\n this.failures = Math.min(this.failures + 1, 10)\n const ceiling = Math.min(MAX_BACKOFF_MS, this.intervalMs * 2 ** this.failures)\n const backoff = Math.max(this.intervalMs, ceiling * (0.5 + Math.random() * 0.5))\n const header = error instanceof BladeApiError\n ? error.response.headers.get(\"Retry-After\")?.trim()\n : undefined\n const retryAfter = header\n ? /^\\d+$/.test(header) ? Number(header) * 1000 : Date.parse(header) - Date.now()\n : 0\n const delay = Math.max(backoff, Number.isNaN(retryAfter) ? 0 : retryAfter)\n // Oversized server delays must not overflow browser timers into a hot loop.\n this.nextAt = delay > MAX_TIMER_MS ? false : Date.now() + delay\n }\n\n /** Zero means ready, false means stop, otherwise wait at least this many ms. */\n waitMs(): number | false {\n return this.nextAt === false ? false : Math.max(0, this.nextAt - Date.now())\n }\n}\n","import { isRecord } from \"./shared/type-guards\"\n\nexport const PLATFORM_SERVICE_NAMES = [\n \"os\",\n \"hub\",\n \"agent\",\n \"oauth\",\n \"llmGateway\",\n \"gitea\",\n \"tile\",\n] as const\n\nexport type PlatformServiceName = (typeof PLATFORM_SERVICE_NAMES)[number]\n\nexport interface PlatformEndpoints {\n services: Partial<Record<PlatformServiceName, string>>\n}\n\nexport const EMPTY_PLATFORM_ENDPOINTS: PlatformEndpoints = Object.freeze({\n services: Object.freeze({}),\n})\n\nexport interface LoadPlatformEndpointsOptions {\n baseUrl?: string\n fetchImpl?: typeof fetch\n timeoutMs?: number\n}\n\nfunction defaultDocumentBaseUrl(): string | undefined {\n if (typeof document === \"undefined\") return undefined\n if (document.querySelector(\"base[href]\")) return document.baseURI\n if (typeof location !== \"undefined\" && location.origin) return `${location.origin}/`\n return document.baseURI\n}\n\nfunction normalizeServiceUrl(value: unknown): string | null {\n if (typeof value !== \"string\" || !value.trim()) return null\n if (value.includes(\"?\") || value.includes(\"#\")) return null\n try {\n const url = new URL(value.trim())\n if (url.protocol !== \"http:\" && url.protocol !== \"https:\") return null\n if (url.username || url.password || url.search || url.hash) return null\n return url.toString().replace(/\\/$/, \"\")\n } catch {\n return null\n }\n}\n\nexport function parsePlatformEndpoints(value: unknown): PlatformEndpoints | null {\n if (!isRecord(value) || !isRecord(value.services)) return null\n\n const services: Partial<Record<PlatformServiceName, string>> = {}\n for (const name of PLATFORM_SERVICE_NAMES) {\n if (!(name in value.services)) continue\n const url = normalizeServiceUrl(value.services[name])\n if (!url) return null\n if (name === \"agent\" && new URL(url).pathname !== \"/\") return null\n services[name] = url\n }\n\n return { services }\n}\n\nexport async function loadPlatformEndpoints(\n options: LoadPlatformEndpointsOptions = {},\n): Promise<PlatformEndpoints> {\n const fetchImpl = options.fetchImpl ?? globalThis.fetch\n const baseUrl = options.baseUrl ?? defaultDocumentBaseUrl()\n if (!fetchImpl || !baseUrl) return EMPTY_PLATFORM_ENDPOINTS\n\n const controller = new AbortController()\n const timeout = globalThis.setTimeout(() => controller.abort(), options.timeoutMs ?? 3_000)\n try {\n const response = await fetchImpl(new URL(\"config.json\", baseUrl), {\n cache: \"no-store\",\n credentials: \"same-origin\",\n headers: { Accept: \"application/json\" },\n signal: controller.signal,\n })\n if (!response.ok) return EMPTY_PLATFORM_ENDPOINTS\n return parsePlatformEndpoints(await response.json()) ?? EMPTY_PLATFORM_ENDPOINTS\n } catch {\n return EMPTY_PLATFORM_ENDPOINTS\n } finally {\n globalThis.clearTimeout(timeout)\n }\n}\n\nexport function resolveServiceUrl(\n endpoints: PlatformEndpoints,\n name: PlatformServiceName,\n path = \"\",\n): string | null {\n const baseUrl = endpoints.services[name]\n if (!baseUrl) return null\n if (!path) return baseUrl\n const pathReference = path.trimStart()\n if (\n path.includes(\"\\\\\") ||\n pathReference.startsWith(\"//\") ||\n /^[a-z][a-z0-9+.-]*:/i.test(pathReference)\n ) {\n return null\n }\n const base = new URL(`${baseUrl}/`)\n const target = new URL(path.replace(/^\\/+/, \"\"), base)\n if (target.origin !== base.origin || !target.pathname.startsWith(base.pathname)) {\n return null\n }\n return target.toString()\n}\n","/** Socket.IO 握手使用的 SDK 身份。Server 只校验 1.1.1 这次破坏性变更。 */\n\ndeclare const __BLADE_SDK_VERSION__: string | undefined\n\n/**\n * 本 SDK 的 npm 包版本,随 Socket.IO 握手一并声明。\n * Release 构建由 Git Tag 注入;本地开发回退到当前源码版本。\n */\nexport const SDK_NAME = \"agent-client\"\nexport const SDK_VERSION =\n typeof __BLADE_SDK_VERSION__ === \"string\" ? __BLADE_SDK_VERSION__ : \"1.1.1\"\n","/**\n * 页面协作协议(对应后端 `_meta.bridge` 通道,见 docs/specs/260417-embed-bridge)。\n *\n * ## action 从哪里来\n *\n * 智能体 → 宿主方向的每一条指令,都源自**技能作者写的工具代码**:工具返回值\n * JSON 里带 `_meta.bridge: { action, payload }`,后端在持久化前把它剥离成独立\n * 事件送达前端(LLM 的对话历史里读不到它)。因此:\n *\n * - action 字符串(如 \"map.highlight\")是**技能作者与宿主页面开发者之间的业务\n * 契约**,LLM 不参与协议、SDK 不做枚举校验;\n * - 宿主页面用 `session.onCommand(\"map.highlight\", fn)` 消费;\n * - 未注册 handler 的 action 会进入有限缓冲等待注册,超限后丢弃并 console 告警。\n *\n * 宿主 → 智能体方向只有三个白名单动作:attach(附件入输入框)/ insertText\n * (追加输入文本)/ send(直接发消息),对应协议层的 addContext / appendInput /\n * sendMessage。\n */\n\nexport interface CommandEnvelope {\n __bladeBridge: true\n direction: \"agent-to-host\"\n action: string\n payload: unknown\n meta: {\n sessionId: string\n toolCallId?: string\n timestamp: number\n }\n}\n\nexport type InboundAction = \"addContext\" | \"appendInput\" | \"sendMessage\"\n\nexport interface InboundEnvelope {\n __bladeBridge: true\n direction: \"host-to-agent\"\n action: InboundAction\n payload: unknown\n}\n\nexport function isCommandEnvelope(value: unknown): value is CommandEnvelope {\n if (typeof value !== \"object\" || value === null) return false\n const record = value as Record<string, unknown>\n return (\n record.__bladeBridge === true &&\n record.direction === \"agent-to-host\" &&\n typeof record.action === \"string\"\n )\n}\n\nexport function isInboundEnvelope(value: unknown): value is InboundEnvelope {\n if (typeof value !== \"object\" || value === null) return false\n const record = value as Record<string, unknown>\n return (\n record.__bladeBridge === true &&\n record.direction === \"host-to-agent\" &&\n (record.action === \"addContext\" || record.action === \"appendInput\" || record.action === \"sendMessage\")\n )\n}\n","import { CommandRegistry, type CommandHandler } from \"./registry\"\nimport { isCommandEnvelope, type InboundAction } from \"./protocol\"\n\n/**\n * iframe 嵌入形态的宿主端协作对象:当你把 Blade 的聊天页面用 iframe 嵌进\n * 自己的系统时,用它与 iframe 里的智能体互通——API 与同页嵌入的\n * AgentSession 完全一致(onCommand / attach / insertText / send)。\n *\n * action 的来源与同页形态相同:技能作者在工具返回值 JSON 的 `_meta.bridge`\n * 字段里写 `{ action, payload }`,Blade 页面检测到自己处于 iframe 中时会把\n * 它 postMessage 给宿主页面(见 docs/specs/260417-embed-bridge)。\n */\nexport interface EmbeddedChatOptions {\n /** 嵌入 Blade 页面的 iframe 元素。不传则监听来自任意子窗口的消息。 */\n iframe?: HTMLIFrameElement\n /**\n * 允许接收消息的来源(Blade 页面的 origin,如 \"https://blade.example.com\")。\n * 必填:不校验来源会让任意第三方页面伪造智能体指令。\n */\n allowedOrigins: string[]\n}\n\nexport interface EmbeddedChat {\n /** 监听智能体下发的指令(注册前到达的会缓冲补投)。返回取消函数。 */\n onCommand(action: string, handler: CommandHandler): () => void\n /** 把业务数据作为附件放进 iframe 里的聊天输入框。 */\n attach(label: string, data: unknown): void\n /** 往 iframe 里的聊天输入框追加文字。 */\n insertText(text: string): void\n /** 直接代用户发送一条消息。 */\n send(text: string): void\n /** 停止监听并释放资源。 */\n dispose(): void\n}\n\nexport function connectEmbedded(options: EmbeddedChatOptions): EmbeddedChat {\n if (typeof window === \"undefined\") {\n throw new Error(\"connectEmbedded() 只能在浏览器中使用。\")\n }\n if (!options.allowedOrigins?.length) {\n throw new Error(\n \"connectEmbedded() 需要 allowedOrigins(Blade 页面的 origin),否则无法安全接收消息。\",\n )\n }\n const registry = new CommandRegistry()\n const allowed = new Set(options.allowedOrigins)\n\n const onMessage = (event: MessageEvent) => {\n if (!allowed.has(event.origin)) return\n if (options.iframe && event.source !== options.iframe.contentWindow) return\n if (!isCommandEnvelope(event.data)) return\n registry.dispatch(event.data.action, event.data.payload, {\n toolCallId: event.data.meta?.toolCallId,\n })\n }\n window.addEventListener(\"message\", onMessage)\n\n const post = (action: InboundAction, payload: unknown) => {\n const target = options.iframe?.contentWindow\n if (!target) {\n console.warn(\"[agent-client] connectEmbedded 未绑定 iframe,无法向智能体发送消息。\")\n return\n }\n // 发往 iframe 的 targetOrigin 用配置的第一个 origin,避免 \"*\"\n target.postMessage(\n { __bladeBridge: true, direction: \"host-to-agent\", action, payload },\n options.allowedOrigins[0],\n )\n }\n\n return {\n onCommand: (action, handler) => registry.onCommand(action, handler),\n attach: (label, data) => {\n const content = typeof data === \"string\" ? data : JSON.stringify(data, null, 2)\n post(\"addContext\", { label, content })\n },\n insertText: (text) => post(\"appendInput\", { text }),\n send: (text) => post(\"sendMessage\", { text }),\n dispose: () => {\n window.removeEventListener(\"message\", onMessage)\n registry.clear()\n },\n }\n}\n","import type { PostChatFollowup, TurnProjection } from \"./projection\"\n\n/** 返回最新根会话轮次的小结;新用户消息到达后旧小结立即失效。 */\nexport function latestPostChatFollowup(turns: TurnProjection[]): PostChatFollowup | null {\n for (let index = turns.length - 1; index >= 0; index -= 1) {\n const turn = turns[index]\n if (\n turn.loop_id === \"root\" &&\n (turn.role === \"user\" || turn.role === \"assistant\") &&\n (turn.kind ?? \"message\") === \"message\" &&\n !turn.blocks.some((block) =>\n [\"mode_change\", \"plan_status\", \"ask_user_answer\"].includes(block.type),\n )\n ) {\n return turn.role === \"assistant\" ? (turn.post_chat_followup ?? null) : null\n }\n }\n return null\n}\n","export enum LayoutType {\n Default = \"default\",\n SkillEditor = \"skill-editor\",\n BladeCoa = \"blade-coa\",\n SolutionEditor = \"solution-editor\",\n SolutionEditor2 = \"solution-editor2\",\n ChatPreview = \"chat-preview\",\n ChatOnly = \"chat-only\",\n SolutionApp = \"solution-app\",\n Custom = \"custom\",\n}\n\nexport interface Solution {\n id: string\n name: string\n version: string\n description?: string | null\n source?: \"builtin\" | \"personal\" | string | null\n layout_type: LayoutType | string\n initial_mode?: \"planning\" | \"executing\" | string | null\n initial_message?: string | null\n preview?: { url: string; title?: string | null } | null\n layout?: {\n available?: boolean\n source_dir?: string\n entry?: string\n export?: string\n } | null\n roles?: BizRole[] | null\n data?: Record<string, unknown> | null\n ui_config?: SolutionAppUiConfig | null\n}\n\nexport interface SolutionAppUiConfig {\n branding: {\n name: string\n subtitle?: string\n icon_text: string\n icon_gradient?: string\n }\n list: {\n title: string\n create_button: string\n card?: {\n subtitle?: string\n stats?: Array<{\n label: string\n value: string\n color?: string\n }>\n }\n }\n create: {\n title: string\n description?: string\n submit_button: string\n sections: Array<{\n id: string\n title: string\n description?: string\n fields: Array<SolutionAppField>\n }>\n }\n}\n\nexport type SolutionAppField =\n | {\n id: string\n kind: \"textarea\"\n label: string\n placeholder?: string\n }\n | {\n id: string\n kind: \"file-upload\"\n accept?: string[]\n categories?: Array<{\n label: string\n description: string\n color: string\n }>\n }\n\nexport interface SolutionAppState {\n pipeline: Array<{\n id: string\n label: string\n status: \"done\" | \"active\" | \"pending\" | \"error\"\n }>\n meta: Record<\n string,\n {\n label: string\n value: string\n color?: string\n }\n >\n}\n\nexport interface BizRole {\n id: string\n name: string\n description?: string | null\n preview?: { url: string; title?: string | null } | null\n}\n","import { type } from \"arktype\"\n\nexport const TaskStatus = type(\"'pending' | 'in_progress' | 'done' | 'failed' | 'skipped'\")\nexport type TaskStatus = typeof TaskStatus.infer\n\nexport const Task = type({\n id: \"string\",\n goal: \"string\",\n skills: \"string[]\",\n depends_on: \"string[]\",\n status: TaskStatus,\n result_summary: \"string\",\n number: \"string\",\n})\nexport type Task = typeof Task.infer\n"],"mappings":"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","names":["type","response","snapshot","snapshot","type","attachments","contexts","buildMessageContent","toolCall","snapshot","snapshot","handle","LayoutType","type"]}
|