@blade-hq/agent-client 2610.0.0-beta.2 → 2610.0.0-beta.21
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/README.md +29 -3
- package/dist/index.d.ts +5 -1
- package/dist/index.js +324 -55
- package/dist/index.js.map +1 -1
- package/dist/platform-endpoints.d.ts +14 -0
- package/dist/schemas/context.d.ts +34 -0
- package/dist/schemas/event.d.ts +9 -0
- package/dist/schemas/message.d.ts +5 -0
- package/dist/schemas/projection.d.ts +12 -1
- package/dist/session/agent-session.d.ts +2 -0
- package/dist/session/state.d.ts +4 -1
- package/dist/shared/projection/builder.d.ts +2 -0
- package/dist/shared/projection/context.d.ts +3 -0
- package/dist/shared/projection/history.d.ts +1 -0
- package/dist/shared/projection/index.d.ts +1 -0
- package/dist/types/socket-events.d.ts +11 -0
- package/package.json +1 -1
- package/public-api.md +121 -2
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/auth-login.ts","../src/rest.ts","../src/resources/auth.ts","../src/resources/headless.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/shared/projection/builder.ts","../src/shared/projection/history.ts","../src/resources/sessions.ts","../src/commands/registry.ts","../src/session/events.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/version.ts","../src/blade-client.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","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","import type { BladeClient } from \"../blade-client\"\nimport type { ChatEndPayload, ChatSendPayload, ChatStartPayload, SystemErrorPayload } from \"../types/socket-events\"\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 stream_tokens: this.client.options.streamTokens !== false,\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 isRecord(value: unknown): value is Record<string, unknown> {\n return typeof value === \"object\" && value !== null && !Array.isArray(value)\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\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 /**\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 \"workspace_path?\": \"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\" | string | null\n daemon_id?: string | null\n workspace_path?: 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 sourceLoop: { loop_name: string; description: string } | 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 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 tokens_before: tokensBefore,\n tokens_after: tokensAfter,\n saved_ratio: savedRatio,\n trigger: asTrigger(data.trigger),\n failure_reason:\n typeof data.reason === \"string\" && data.reason ? (data.reason as string) : 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\"\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 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}\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 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 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: Math.max(0, Date.now() - state.startedAt),\n started_at: new Date(state.startedAt).toISOString(),\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","import type { MemoryRef, 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 { createTurnState, PAUSE_TOOL_NAMES, snapshot, toolStatusFromResult, type TurnState } from \"./state\"\n\nexport interface RawEvent {\n type: string\n payload: Record<string, unknown>\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\nfunction hasChatRunEvent(events: RawEvent[]): boolean {\n return events.some(\n (event) =>\n event.type !== \"session:post_chat_followup\" && !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 if (state.blocks.some((block) => block.type === \"text\")) 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\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 loopDescriptions = new Map<string, 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 \"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 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 return this.syncPatch(state)\n case \"llm:thinking:delta\":\n return this.onDelta(state, \"thinking\", \"\", String(payload.content ?? \"\"))\n case \"llm:content:delta\":\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:tool_call:created\":\n return this.onToolCallCreated(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.loopDescriptions.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 for (const turn of turns) {\n this.seedSequence(turn.sequence)\n if (!isConversationTurn(turn)) continue\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 }\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 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 const pending = this.pendingMemoryRefs.get(loopId)\n if (pending) {\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 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 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 return this.collectLoopUpdates(loopId, parentLoopId)\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 }\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 if (\"arguments_delta\" in payload) {\n const delta = String(payload.arguments_delta ?? \"\")\n const toolCallId = String(payload.id ?? \"\")\n if (delta && toolCallId) {\n appendToolCallArguments(state, toolCallId, delta)\n return this.syncPatch(state)\n }\n return null\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 onResponseDone(\n state: TurnState,\n loopId: string,\n payload: Record<string, unknown>,\n ): ProjectionUpdate[] | null {\n state.responseDone = true\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 if (\"content\" in payload) {\n replaceTextContent(state, completedResponseText(payload.content))\n }\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 (state.toolCalls.length === 0) {\n return this.finalize(loopId, \"completed\")\n }\n return this.syncPatch(state)\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\n const sl = sourceLoopFor(state.loopId, this.loopDescriptions)\n applyToolResult(state, toolCallId, content, status, durationMs, sl)\n\n if (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 state.blocks.push({\n type: \"tool_bridge\",\n content: bridge,\n tool_call_id: String(payload.tool_call_id ?? \"\") || null,\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 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 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 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.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 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 isRecord(value: unknown): value is Record<string, unknown> {\n return typeof value === \"object\" && value !== null && !Array.isArray(value)\n}\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 ToolCallProjection,\n TurnProjection,\n} from \"../../schemas/projection\"\nimport { inferToolStatus } from \"../../schemas/message\"\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 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 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 === \"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 === \"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 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 const toolCalls = role === \"assistant\" ? buildToolCalls(message.tool_calls) : []\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 duration_ms: numberOrZero(message._duration_ms),\n started_at: typeof entry.timestamp === \"string\" ? entry.timestamp : undefined,\n }\n if (\n loopId === \"root\" &&\n (role === \"user\" || role === \"assistant\")\n ) {\n latestRootMessage = turn\n }\n turns.push(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 === \"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 const owner = toolOwners.get(toolCallId) ?? findLatestAssistant(turns, loopId)\n const content = kind === \"tool_ui\" ? data.ui : data.bridge\n if (owner && content !== undefined) {\n owner.blocks.push({\n type: kind,\n content,\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, \"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 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 }\n } else if (message.content !== undefined && message.content !== \"\") {\n blocks.push({ type: \"text\", content: message.content })\n }\n for (const toolCall of toolCalls) {\n blocks.push({\n type: \"tool_use\",\n content: { name: toolCall.tool_name, arguments: toolCall.arguments },\n tool_call_id: toolCall.id,\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 isRecord(value: unknown): value is Record<string, unknown> {\n return typeof value === \"object\" && value !== null && !Array.isArray(value)\n}\n\nfunction stringOrNull(value: unknown): string | null {\n return typeof value === \"string\" ? value : null\n}\n\nfunction numberOrZero(value: unknown): number {\n return typeof value === \"number\" ? value : 0\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 { 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 { 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 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\" | null\n daemon_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}\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 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 }\n}\n\nconst builtinSolutionIds = new Set([\n \"app-dev\",\n \"general_chat\",\n \"multica\",\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 /**\n * 连接一个已存在的会话,返回实时会话对象 AgentSession\n * (自动完成历史加载、Socket.IO 订阅、断线重连补数)。\n */\n connect(sessionId: string): Promise<AgentSession> {\n return this.client.hub.connect(sessionId)\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 }: 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 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 }): 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 }): 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 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","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 { 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: { toolCall: ToolCallInfo; turn: TurnProjection }\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 }\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 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 {\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]\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\nexport function isHiddenInternalMessage(message: Pick<ChatMessage, \"role\" | \"content\">): boolean {\n if (message.role !== \"user\") return false\n const text = getTextContent(normalizeMessageContent(message.content))\n return (\n isSystemReminderText(text) ||\n isSystemNotificationText(text) ||\n 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 type { ReplaySpeed, ReplayState, SessionStatus } from \"../schemas/session\"\n\n/** 一次 AskUserQuestion 的用户作答(选项选择 + 自定义输入)。 */\nexport interface AskUserAnswerData {\n selections: Record<number, number[]>\n custom: Record<number, 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 /** 当前身份对这个会话的权限;\"viewer\" 表示只读(分享链接打开的)。 */\n viewerRole: \"owner\" | \"viewer\" | null\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 viewerRole: null,\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 isRecord(value: unknown): value is Record<string, unknown> {\n return typeof value === \"object\" && value !== null && !Array.isArray(value)\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 === \"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\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(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 mergedMessages = preservedErrors.length > 0 ? [...messages, ...preservedErrors] : messages\n const latestMode = [...orderedTurns]\n .reverse()\n .map((turn) => extractModeFromBlocks(turn.blocks))\n .find((mode): mode is \"planning\" | \"executing\" => mode !== null)\n return {\n ...state,\n turns: orderedTurns,\n messages: mergedMessages,\n agentLoops: stableAgentLoops,\n activeCompaction,\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\nlet localTurnCounter = 0\n\nexport function addUserMessage(state: SessionState, content: MessageContent): SessionState {\n localTurnCounter += 1\n const turnId = `local-user-${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 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 if (turn.role === \"user\" && !turn.turn_id.startsWith(\"local-user-\")) {\n existing = existing.filter((t) => !t.turn_id.startsWith(\"local-user-\"))\n }\n const index = existing.findIndex((item) => item.turn_id === turn.turn_id)\n if (index >= 0) {\n existing[index] = turn\n } else {\n existing.push(turn)\n }\n return withTurns(state, 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 const nextTurn = { ...turn, sequence: patch.sequence }\n if (index >= 0) {\n existing[index] = nextTurn\n } else {\n existing.push(nextTurn)\n }\n return withTurns(state, existing)\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 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} from \"../resources/sessions\"\nimport {\n addErrorMessage,\n addUserMessage,\n applyTurnPatch,\n createInitialSessionState,\n extractModeFromBlocks,\n markFailed,\n markInterrupted,\n toReplaySnapshot,\n upsertTurn,\n withTurns,\n type AskUserAnswerData,\n type ConnectionStatus,\n type SessionState,\n} from \"./state\"\n\n/** SessionHub 注入给 AgentSession 的运行时依赖(socket 收发 + REST 补数)。 */\nexport interface SessionRuntime {\n streamTokens: boolean\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 fetchTurns(sessionId: string): Promise<TurnProjection[]>\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}\n\nconst OOM_MESSAGE = \"沙盒内存使用超出限制,已自动重启。如果经常触发,可以联系管理员调整额度。\"\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 isRecord(value: unknown): value is Record<string, unknown> {\n return typeof value === \"object\" && value !== null && !Array.isArray(value)\n}\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\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\nfunction hasChatRunEvent(events: RawEvent[]): boolean {\n return events.some(\n (event) =>\n event.type !== \"session:post_chat_followup\" && !event.type.startsWith(\"compaction:\"),\n )\n}\n\ninterface UiMetaLike {\n target?: string\n title?: string\n resourceHTML?: string\n resourceUri?: string\n resourceURI?: string\n}\n\nfunction isUiMetaLike(value: unknown): value is UiMetaLike {\n return isRecord(value) && (\"resourceHTML\" in value || \"resourceUri\" in value || \"resourceURI\" in value)\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 // 回放控制请求排成一条队列。连着点\"5x\"再点\"退出回放\"时,并发发出去的两个\n // 请求响应可能乱序回来,晚到的旧值会把已经退出的会话又显示成回放中;用\n // 序号丢弃过期响应又会在失败时留下中间态。串行执行就没有这些情况:每个\n // 响应都是当时最新的,失败也只影响自己。\n private replayQueue: Promise<unknown> = Promise.resolve()\n private pendingReplayMessage: MessageContent | null = null\n private pendingReplayMode: string | undefined\n private recentChatEndAt = 0\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(sessionId: string, runtime: SessionRuntime, connection: ConnectionStatus) {\n this.sessionId = sessionId\n this.runtime = runtime\n this.state = { ...createInitialSessionState(sessionId), connection }\n }\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 streamTokens: false,\n emitEvent: readonlyError,\n emitWithAck: async () => readonlyError(),\n ensureConnected: readonlyError,\n fetchTurns: async () => turns,\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 )\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 /** 订阅状态变化。返回取消订阅函数。 */\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 if (\n this.state.isStreaming ||\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 private async sendUnlocked(content: MessageContent, options: SendOptions): Promise<boolean> {\n await this.ensureIdleBeforeSend()\n if (this.state.isStreaming || this.state.activeCompaction || this.manualCompactionPending) {\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 askUserAnswer = options.askUserAnswer\n let optimisticTurnId: string | null = null\n let optimisticAskAnswer: AskUserAnswerData | undefined\n let previousAskAnswer: AskUserAnswerData | undefined\n if (!(askUserAnswer && typeof askUserAnswer.tool_call_id === \"string\")) {\n this.update((state) => {\n const next = addUserMessage(state, content)\n optimisticTurnId = next.turns.at(-1)?.turn_id ?? null\n return next\n })\n }\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 }\n const payload = {\n session_id: this.sessionId,\n message: content,\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 }\n try {\n await this.ensureJoined()\n } catch (error) {\n this.rollbackOptimisticSend(\n optimisticTurnId,\n askUserAnswer,\n optimisticAskAnswer,\n previousAskAnswer,\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 !== \"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 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 message: string,\n ): void {\n this.pendingReplayMessage = null\n this.pendingReplayMode = undefined\n this.update((current) => {\n let next = optimisticTurnId\n ? withTurns(\n current,\n current.turns.filter((turn) => turn.turn_id !== optimisticTurnId),\n )\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 addErrorMessage({ ...next, isStreaming: false }, message)\n })\n }\n\n /** 智能体运行期间追加补充说明(不打断当前回复)。 */\n append(text: string): void {\n this.runtime.ensureConnected()\n this.runtime.emitEvent(\"chat:append\", { session_id: this.sessionId, message: text })\n this.update((s) => addUserMessage(s, text))\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) => response ?? {})\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 .finally(() => {\n this.manualCompactionPending = false\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.cancelPatchFlush()\n this.listeners.clear()\n this.emitter.clear()\n this.commands.clear()\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 /** @internal socket 重连后由 Hub 调用:重新加入房间并补数。 */\n async _rejoinAfterReconnect(): Promise<void> {\n const turnsBeforeRejoin = this.state.turns\n this.joined = false\n this.joinPending = null\n try {\n await this.ensureJoined()\n // 回放状态和历史一起补:断线期间错过的 session:updated(别处退出了回放、\n // 改了倍速)不补的话,快照会一直停在旧值。\n await Promise.all([\n this.syncTurnsFromHistory({\n clearOnEmpty: true,\n preserveChangesSince: turnsBeforeRejoin,\n }),\n this.syncReplayFromSession(),\n ])\n } catch {\n // 重连补数尽力而为;后续 Socket 重连仍会再次尝试\n }\n }\n\n /** @internal 首次连接:加载历史 + 加入房间。 */\n async _bootstrap(): Promise<void> {\n await this.syncTurnsFromHistory({ suppressErrors: false })\n await this.ensureJoined()\n // 必须在进房间之后再拉回放状态:反过来的话,两者之间别的标签页改了倍速或\n // 退出了回放,那条 session:updated 我们还没订阅、收不到,快照会一直停在旧值。\n // 拉一次而不是等推送,是为了让 connect() 返回时第一帧就知道自己在不在回放。\n await this.syncReplayFromSession()\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[]): void {\n if (!events.length) return\n const terminalChatEndStatus = extractTerminalChatEndStatus(events)\n if (!terminalChatEndStatus && hasChatRunEvent(events)) {\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(update.turn)\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 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 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.update((s) => ({ ...s, mode: null, errorMessage: null }))\n void this.syncTurnsFromHistory({ clearOnEmpty: true })\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 this.pendingReplayMessage = null\n this.pendingReplayMode = 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 },\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): 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 void this.syncTurnsFromHistory()\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 void this.syncTurnsFromHistory()\n this.emitter.emit(\"chatEnd\", { status })\n }\n\n private applyTurn(turn: TurnProjection): void {\n this.flushPatches()\n const previous = this.state\n this.update((s) => upsertTurn(s, turn))\n this.emitTurnDerivedEvents(previous, turn)\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 this.update((s) => applyTurnPatch(s, patch))\n const turn = patch.data.turn\n if (turn) {\n this.emitTurnDerivedEvents(previous, turn)\n }\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(previous: SessionState, turn: TurnProjection): 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 && isUiMetaLike(block.content)) {\n const ui = block.content\n if (ui.target !== \"preview\") continue\n const previewType = ui.resourceHTML ? (\"resource-html\" as const) : (\"resource-uri\" as const)\n const previewContent = ui.resourceHTML ?? ui.resourceUri ?? ui.resourceURI\n if (!previewContent) continue\n const key = `${block.tool_call_id}:${previewType}`\n if (this.deliveredToolPreviews.get(key) === previewContent) continue\n this.deliveredToolPreviews.set(key, previewContent)\n this.emitter.emit(\"toolPreview\", {\n toolCallId: block.tool_call_id,\n type: previewType,\n content: previewContent,\n title: ui.title ?? \"工具预览\",\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 })\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(turn: TurnProjection, block: ContentBlock): void {\n if (!isToolBridgeContent(block.content)) return\n const { action, payload } = block.content\n let payloadKey = \"\"\n try {\n payloadKey = JSON.stringify(payload ?? null)\n } catch {\n payloadKey = String(payload ?? \"\")\n }\n const deliveryKey = [block.tool_call_id ?? turn.id, action, payloadKey].join(\"\u0000\")\n if (this.deliveredCommandKeys.has(deliveryKey)) return\n this.deliveredCommandKeys.add(deliveryKey)\n const meta = { toolCallId: block.tool_call_id ?? undefined }\n this.emitter.emit(\"command\", { action, payload, toolCallId: meta.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 private async syncTurnsFromHistory(\n options: {\n clearOnEmpty?: boolean\n suppressErrors?: boolean\n preserveChangesSince?: TurnProjection[]\n } = {},\n ): Promise<void> {\n const { clearOnEmpty = false, suppressErrors = true, preserveChangesSince } = options\n const turnsAtRequestStart = this.state.turns\n try {\n const turns = await this.runtime.fetchTurns(this.sessionId)\n if (turns.length === 0 && !clearOnEmpty) return\n this.update((state) => {\n const mergeBaseline = preserveChangesSince ?? turnsAtRequestStart\n if (state.turns === mergeBaseline) return withTurns(state, turns)\n\n const historyById = new Map(turns.map((turn) => [turn.turn_id, turn]))\n let merged = withTurns(state, turns)\n for (const current of state.turns) {\n const fromHistory = historyById.get(current.turn_id)\n if (!fromHistory || current.sequence > fromHistory.sequence) {\n merged = upsertTurn(merged, current)\n }\n }\n return merged\n })\n this.replayCommandsFromTurns(turns)\n } catch (error) {\n if (!suppressErrors) throw error\n // 尽力而为的历史补数,失败时保留现有内存状态\n }\n }\n\n /**\n * 把历史里的指令补投给宿主页面。\n *\n * 重开会话、断线补数时,地图高亮这类\"页面当前状态\"必须能恢复——\n * 否则刷新一次页面,之前智能体让页面做的事就全丢了。\n * 只回放指令:toolCall / message 这些事件如果按历史全量重放,\n * 监听器会在挂载瞬间收到几百条陈年事件。\n * dispatch 内部按 deliveredCommandKeys 去重,重复调用安全。\n */\n private replayCommandsFromTurns(turns: TurnProjection[]): void {\n for (const turn of turns) {\n for (const block of turn.blocks) {\n if (block.type === \"tool_bridge\" && isToolBridgeContent(block.content)) {\n this.dispatchCommand(turn, block)\n }\n }\n }\n }\n\n private ensureJoined(): 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 stream_tokens: this.runtime.streamTokens,\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))\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 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 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\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\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): Promise<AgentSession> {\n const existing = this.sessions.get(sessionId)\n if (existing && !existing.isDisposed) {\n this.hold(sessionId)\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 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 const socket = this.client.socket()\n socket.disconnect()\n this.setConnection(\"connecting\")\n socket.connect()\n }\n\n /** 断开连接(不清理 session 实例)。 */\n disconnect(): void {\n this.client.socket().disconnect()\n this.setConnection(\"disconnected\")\n }\n\n /** 清理当前身份下缓存的全部会话,避免切换登录身份后复用旧快照。 */\n disposeAll(): void {\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.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 streamTokens: this.client.options?.streamTokens !== false,\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 fetchTurns: (sessionId) => this.client.sessions.getSessionTurns(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 // 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 }\n\n private ensureConnected(): void {\n const socket = this.client.socket()\n if (socket.connected || socket.active) 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 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 }\n })\n socket.on(\"connect_error\", () => this.setConnection(\"disconnected\"))\n socket.on(\"disconnect\", () => this.setConnection(\"disconnected\"))\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(\"turn:events\", (data: { session_id?: string; events: RawEvent[] }) => {\n for (const session of this.route(data.session_id)) session._handleTurnEvents(data.events ?? [])\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 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 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\"\nimport { SDK_NAME, SDK_VERSION } from \"./version\"\n\nexport type TypedSocket = Socket<ServerToClientEvents, ClientToServerEvents>\n\nexport interface CreateSocketOptions extends AuthOptions {\n baseUrl: string\n path?: string\n}\n\n/** 握手时声明 SDK 身份,让 Server 能把旧 agent-kit 挡在门外并给出升级提示。 */\nfunction withSdkIdentity(auth: { token: string } | undefined): Record<string, string> {\n return { ...(auth ?? {}), sdk: SDK_NAME, sdk_version: SDK_VERSION }\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(withSdkIdentity(buildSocketAuth(options)))\n : withSdkIdentity(buildSocketAuth(options)),\n autoConnect: false,\n })\n}\n","export interface AuthOptions {\n token?: string | (() => string | null | undefined)\n}\n\nexport function buildAuthHeaders(options: AuthOptions): Record<string, string> {\n const token = resolveAuthToken(options)\n if (!token) {\n return {}\n }\n return {\n Authorization: `Bearer ${token}`,\n }\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","/** 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","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 decorateAuthError,\n extractErrorDetail,\n} from \"./rest\"\nimport { AuthResource } from \"./resources/auth\"\nimport { HeadlessResource } from \"./resources/headless\"\nimport { ModelsResource } from \"./resources/models\"\nimport { SessionsResource } from \"./resources/sessions\"\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 /** 是否订阅逐 token 增量,默认 true。关闭后仍接收完整消息和语义事件。 */\n streamTokens?: boolean\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 models: ModelsResource\n readonly sessions: SessionsResource\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.models = new ModelsResource(this)\n this.sessions = new SessionsResource(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.tryRefresh()\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 = new URL(this.toBaseRelativePath(path), this.baseUrlWithTrailingSlash())\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 new URL(this.toBaseRelativePath(path), this.baseUrlWithTrailingSlash())\n }\n\n private baseUrlWithTrailingSlash(): string {\n return this.options.baseUrl.endsWith(\"/\") ? this.options.baseUrl : `${this.options.baseUrl}/`\n }\n\n private toBaseRelativePath(path: string): string {\n return path.startsWith(\"/\") ? path.slice(1) : path\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 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","/**\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":["isRecord","toolCallId","isRecord","type","response","attachments","contexts","isRecord","buildMessageContent","toolCall","isRecord","hasChatRunEvent","handle","LayoutType","type"]}
|
|
1
|
+
{"version":3,"sources":["../src/auth-login.ts","../src/rest.ts","../src/resources/auth.ts","../src/resources/headless.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/commands/registry.ts","../src/session/events.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/version.ts","../src/blade-client.ts","../src/platform-endpoints.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","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","import type { BladeClient } from \"../blade-client\"\nimport type { ChatEndPayload, ChatSendPayload, ChatStartPayload, SystemErrorPayload } from \"../types/socket-events\"\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 stream_tokens: this.client.options.streamTokens !== false,\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 isRecord(value: unknown): value is Record<string, unknown> {\n return typeof value === \"object\" && value !== null && !Array.isArray(value)\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\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 /**\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 \"workspace_path?\": \"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\" | string | null\n daemon_id?: string | null\n workspace_path?: 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 sourceLoop: { loop_name: string; description: string } | 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 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 tokens_before: tokensBefore,\n tokens_after: tokensAfter,\n saved_ratio: savedRatio,\n trigger: asTrigger(data.trigger),\n failure_reason:\n typeof data.reason === \"string\" && data.reason ? (data.reason as string) : 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 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 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: Math.max(0, Date.now() - state.startedAt),\n started_at: new Date(state.startedAt).toISOString(),\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\nconst BUILTIN_CONTEXT_TITLES: Record<string, string> = {\n \"agent-instructions\": \"项目说明\",\n \"skill-catalog\": \"可用能力\",\n \"runtime-context\": \"当前工作环境\",\n}\n\nconst BUILTIN_CONTEXT_DETAILS: Record<string, string> = {\n \"agent-instructions\": \"这些说明会帮助智能体理解当前项目和工作要求。\",\n \"skill-catalog\": \"这些能力会帮助智能体选择合适的方式完成任务。\",\n \"runtime-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 const title =\n BUILTIN_CONTEXT_TITLES[context.context_kind] ??\n nonEmptyString(context.display_title) ??\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 : \"已更新本次对话背景\")\n const detail = isRemoved\n ? `${title}已不再用于后续对话。`\n : (BUILTIN_CONTEXT_DETAILS[context.context_kind] ??\n \"这些信息会帮助智能体理解当前任务。\")\n return { title, summary, detail, isRemoved }\n}\n","import { contextProjectionData } from \"../../schemas/context\"\nimport type { TurnProjection } from \"../../schemas/projection\"\n\nfunction isRecord(value: unknown): value is Record<string, unknown> {\n return typeof value === \"object\" && value !== null && !Array.isArray(value)\n}\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 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:\n typeof entry.data.contribution_name === \"string\"\n ? entry.data.contribution_name\n : null,\n context_order: typeof entry.data.order === \"number\" ? entry.data.order : null,\n context_action:\n entry.data.action === \"published\" ||\n entry.data.action === \"retained\" ||\n entry.data.action === \"removed\"\n ? entry.data.action\n : null,\n context_revision:\n 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)\n ? display.sources.filter(isRecord)\n : [],\n })\n if (!context) return null\n\n const turnId =\n typeof entry.id === \"string\" && entry.id ? entry.id : `context-${sequence}`\n return {\n id: turnId,\n sequence,\n turn_id: turnId,\n loop_id:\n typeof entry.loop_name === \"string\" && entry.loop_name\n ? entry.loop_name\n : \"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,\n }\n}\n","import type { MemoryRef, 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 { 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\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\nfunction hasChatRunEvent(events: RawEvent[]): boolean {\n return events.some(\n (event) =>\n event.type !== \"session:post_chat_followup\" && !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 if (state.blocks.some((block) => block.type === \"text\")) 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\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 loopDescriptions = new Map<string, 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 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 return this.syncPatch(state)\n case \"llm:thinking:delta\":\n return this.onDelta(state, \"thinking\", \"\", String(payload.content ?? \"\"))\n case \"llm:content:delta\":\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:tool_call:created\":\n return this.onToolCallCreated(state, payload)\n case \"llm:tool_call:arguments:delta\":\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.loopDescriptions.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 for (const turn of turns) {\n this.seedSequence(turn.sequence)\n if (!isConversationTurn(turn)) continue\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 }\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 const pending = this.pendingMemoryRefs.get(loopId)\n if (pending) {\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 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 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 return this.collectLoopUpdates(loopId, parentLoopId)\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 }\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 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 if (\"content\" in payload) {\n replaceTextContent(state, completedResponseText(payload.content))\n }\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 (state.toolCalls.length === 0) {\n return this.finalize(loopId, \"completed\")\n }\n return this.syncPatch(state)\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\n const sl = sourceLoopFor(state.loopId, this.loopDescriptions)\n applyToolResult(state, toolCallId, content, status, durationMs, sl)\n\n if (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 state.blocks.push({\n type: \"tool_bridge\",\n content: bridge,\n tool_call_id: String(payload.tool_call_id ?? \"\") || null,\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 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 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 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.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 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 isRecord(value: unknown): value is Record<string, unknown> {\n return typeof value === \"object\" && value !== null && !Array.isArray(value)\n}\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 ToolCallProjection,\n TurnProjection,\n} from \"../../schemas/projection\"\nimport { inferToolStatus } from \"../../schemas/message\"\nimport { buildContextTurn } from \"./context\"\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 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 === \"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 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 const toolCalls = role === \"assistant\" ? buildToolCalls(message.tool_calls) : []\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 duration_ms: numberOrZero(message._duration_ms),\n started_at: typeof entry.timestamp === \"string\" ? entry.timestamp : undefined,\n }\n if (\n loopId === \"root\" &&\n (role === \"user\" || role === \"assistant\")\n ) {\n latestRootMessage = turn\n }\n turns.push(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 === \"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 const owner = toolOwners.get(toolCallId) ?? findLatestAssistant(turns, loopId)\n const content = kind === \"tool_ui\" ? data.ui : data.bridge\n if (owner && content !== undefined) {\n owner.blocks.push({\n type: kind,\n content,\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, \"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 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 }\n } else if (message.content !== undefined && message.content !== \"\") {\n blocks.push({ type: \"text\", content: message.content })\n }\n for (const toolCall of toolCalls) {\n blocks.push({\n type: \"tool_use\",\n content: { name: toolCall.tool_name, arguments: toolCall.arguments },\n tool_call_id: toolCall.id,\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 isRecord(value: unknown): value is Record<string, unknown> {\n return typeof value === \"object\" && value !== null && !Array.isArray(value)\n}\n\nfunction stringOrNull(value: unknown): string | null {\n return typeof value === \"string\" ? value : null\n}\n\nfunction numberOrZero(value: unknown): number {\n return typeof value === \"number\" ? value : 0\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 { 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 { 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 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\" | null\n daemon_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}\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 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 }\n}\n\nconst builtinSolutionIds = new Set([\n \"app-dev\",\n \"general_chat\",\n \"multica\",\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 /**\n * 连接一个已存在的会话,返回实时会话对象 AgentSession\n * (自动完成历史加载、Socket.IO 订阅、断线重连补数)。\n */\n connect(sessionId: string): Promise<AgentSession> {\n return this.client.hub.connect(sessionId)\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 }: 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 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 }): 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 }): 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 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","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 { 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: { toolCall: ToolCallInfo; turn: TurnProjection }\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 }\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 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 {\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]\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\nexport function isHiddenInternalMessage(message: Pick<ChatMessage, \"role\" | \"content\">): boolean {\n if (message.role !== \"user\") return false\n const text = getTextContent(normalizeMessageContent(message.content))\n return (\n isSystemReminderText(text) ||\n isSystemNotificationText(text) ||\n 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\"\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 /** 当前身份对这个会话的权限;\"viewer\" 表示只读(分享链接打开的)。 */\n viewerRole: \"owner\" | \"viewer\" | null\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 viewerRole: null,\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 isRecord(value: unknown): value is Record<string, unknown> {\n return typeof value === \"object\" && value !== null && !Array.isArray(value)\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 const currentById = new Map(currentTurns.map((turn) => [turn.turn_id, turn]))\n const optimisticUserTurn = currentTurns.find(\n (turn) =>\n turn.role === \"user\" &&\n (turn.kind ?? \"message\") === \"message\" &&\n turn.turn_id.startsWith(\"local-user-\"),\n )\n let optimisticUserMatched = false\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 if (\n !optimisticUserMatched &&\n optimisticUserTurn &&\n turn.role === \"user\" &&\n (turn.kind ?? \"message\") === \"message\" &&\n !turn.turn_id.startsWith(\"local-user-\")\n ) {\n optimisticUserMatched = true\n return { ...turn, client_render_id: optimisticUserTurn.turn_id }\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(reconcileOptimisticUserTurns(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\nlet localTurnCounter = 0\n\nexport function addUserMessage(state: SessionState, content: MessageContent): SessionState {\n localTurnCounter += 1\n const turnId = `local-user-${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 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 if (nextTurn.client_render_id && turn.role === \"user\") {\n existing = existing.filter(\n (item) => !(item.role === \"user\" && item.turn_id.startsWith(\"local-user-\")),\n )\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 return withTurns(state, 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 const nextTurn = { ...turn, sequence: patch.sequence }\n if (index >= 0) {\n existing[index] = nextTurn\n } else {\n existing.push(nextTurn)\n }\n return withTurns(state, existing)\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 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} from \"../resources/sessions\"\nimport {\n addErrorMessage,\n addUserMessage,\n applyTurnPatch,\n createInitialSessionState,\n extractModeFromBlocks,\n markFailed,\n markInterrupted,\n toReplaySnapshot,\n upsertTurn,\n withTurns,\n type AskUserAnswerData,\n type ConnectionStatus,\n type SessionState,\n} from \"./state\"\n\n/** SessionHub 注入给 AgentSession 的运行时依赖(socket 收发 + REST 补数)。 */\nexport interface SessionRuntime {\n streamTokens: boolean\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 fetchTurns(sessionId: string): Promise<TurnProjection[]>\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:后端先用原话在这些库里预检索,本轮 kb_search 也默认限定在这些库。 */\n kbIds?: number[]\n}\n\nconst OOM_MESSAGE = \"沙盒内存使用超出限制,已自动重启。如果经常触发,可以联系管理员调整额度。\"\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 isRecord(value: unknown): value is Record<string, unknown> {\n return typeof value === \"object\" && value !== null && !Array.isArray(value)\n}\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\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\nfunction hasChatRunEvent(events: RawEvent[]): boolean {\n return events.some(\n (event) =>\n event.type !== \"session:post_chat_followup\" && !event.type.startsWith(\"compaction:\"),\n )\n}\n\ninterface UiMetaLike {\n target?: string\n title?: string\n resourceHTML?: string\n resourceUri?: string\n resourceURI?: string\n}\n\nfunction isUiMetaLike(value: unknown): value is UiMetaLike {\n return isRecord(value) && (\"resourceHTML\" in value || \"resourceUri\" in value || \"resourceURI\" in value)\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 // 回放控制请求排成一条队列。连着点\"5x\"再点\"退出回放\"时,并发发出去的两个\n // 请求响应可能乱序回来,晚到的旧值会把已经退出的会话又显示成回放中;用\n // 序号丢弃过期响应又会在失败时留下中间态。串行执行就没有这些情况:每个\n // 响应都是当时最新的,失败也只影响自己。\n private replayQueue: Promise<unknown> = Promise.resolve()\n private pendingReplayMessage: MessageContent | null = null\n private pendingReplayMode: string | undefined\n private recentChatEndAt = 0\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(sessionId: string, runtime: SessionRuntime, connection: ConnectionStatus) {\n this.sessionId = sessionId\n this.runtime = runtime\n this.state = { ...createInitialSessionState(sessionId), connection }\n }\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 streamTokens: false,\n emitEvent: readonlyError,\n emitWithAck: async () => readonlyError(),\n ensureConnected: readonlyError,\n fetchTurns: async () => turns,\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 )\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 /** 订阅状态变化。返回取消订阅函数。 */\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 if (\n this.state.isStreaming ||\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 private async sendUnlocked(content: MessageContent, options: SendOptions): Promise<boolean> {\n await this.ensureIdleBeforeSend()\n if (this.state.isStreaming || this.state.activeCompaction || this.manualCompactionPending) {\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 askUserAnswer = options.askUserAnswer\n let optimisticTurnId: string | null = null\n let optimisticAskAnswer: AskUserAnswerData | undefined\n let previousAskAnswer: AskUserAnswerData | undefined\n this.update((state) => {\n const next = addUserMessage(state, content)\n optimisticTurnId = next.turns.at(-1)?.turn_id ?? null\n return next\n })\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 }\n const payload = {\n session_id: this.sessionId,\n message: content,\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 && options.kbIds.length > 0 ? options.kbIds : undefined,\n }\n try {\n await this.ensureJoined()\n } catch (error) {\n this.rollbackOptimisticSend(\n optimisticTurnId,\n askUserAnswer,\n optimisticAskAnswer,\n previousAskAnswer,\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 !== \"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 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 message: string,\n ): void {\n this.pendingReplayMessage = null\n this.pendingReplayMode = undefined\n this.update((current) => {\n let next = optimisticTurnId\n ? withTurns(\n current,\n current.turns.filter((turn) => turn.turn_id !== optimisticTurnId),\n )\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 addErrorMessage({ ...next, isStreaming: false }, message)\n })\n }\n\n /** 智能体运行期间追加补充说明(不打断当前回复)。 */\n append(text: string): void {\n this.runtime.ensureConnected()\n this.runtime.emitEvent(\"chat:append\", { session_id: this.sessionId, message: text })\n this.update((s) => addUserMessage(s, text))\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) => response ?? {})\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 .finally(() => {\n this.manualCompactionPending = false\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.cancelPatchFlush()\n this.listeners.clear()\n this.emitter.clear()\n this.commands.clear()\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 /** @internal socket 重连后由 Hub 调用:重新加入房间并补数。 */\n async _rejoinAfterReconnect(): Promise<void> {\n const turnsBeforeRejoin = this.state.turns\n this.joined = false\n this.joinPending = null\n try {\n await this.ensureJoined()\n // 回放状态和历史一起补:断线期间错过的 session:updated(别处退出了回放、\n // 改了倍速)不补的话,快照会一直停在旧值。\n await Promise.all([\n this.syncTurnsFromHistory({\n clearOnEmpty: true,\n preserveChangesSince: turnsBeforeRejoin,\n }),\n this.syncReplayFromSession(),\n ])\n } catch {\n // 重连补数尽力而为;后续 Socket 重连仍会再次尝试\n }\n }\n\n /** @internal 首次连接:加载历史 + 加入房间。 */\n async _bootstrap(): Promise<void> {\n await this.syncTurnsFromHistory({ suppressErrors: false })\n await this.ensureJoined()\n // 必须在进房间之后再拉回放状态:反过来的话,两者之间别的标签页改了倍速或\n // 退出了回放,那条 session:updated 我们还没订阅、收不到,快照会一直停在旧值。\n // 拉一次而不是等推送,是为了让 connect() 返回时第一帧就知道自己在不在回放。\n await this.syncReplayFromSession()\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[]): void {\n if (!events.length) return\n const terminalChatEndStatus = extractTerminalChatEndStatus(events)\n if (!terminalChatEndStatus && hasChatRunEvent(events)) {\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(update.turn)\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 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 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.update((s) => ({ ...s, mode: null, errorMessage: null }))\n void this.syncTurnsFromHistory({ clearOnEmpty: true })\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 this.pendingReplayMessage = null\n this.pendingReplayMode = 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 },\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): 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 void this.syncTurnsFromHistory()\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 void this.syncTurnsFromHistory()\n this.emitter.emit(\"chatEnd\", { status })\n }\n\n private applyTurn(turn: TurnProjection): void {\n this.flushPatches()\n const previous = this.state\n this.update((s) => upsertTurn(s, turn))\n this.emitTurnDerivedEvents(previous, turn)\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 this.update((s) => applyTurnPatch(s, patch))\n const turn = patch.data.turn\n if (turn) {\n this.emitTurnDerivedEvents(previous, turn)\n }\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(previous: SessionState, turn: TurnProjection): 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 && isUiMetaLike(block.content)) {\n const ui = block.content\n if (ui.target !== \"preview\") continue\n const previewType = ui.resourceHTML ? (\"resource-html\" as const) : (\"resource-uri\" as const)\n const previewContent = ui.resourceHTML ?? ui.resourceUri ?? ui.resourceURI\n if (!previewContent) continue\n const key = `${block.tool_call_id}:${previewType}`\n if (this.deliveredToolPreviews.get(key) === previewContent) continue\n this.deliveredToolPreviews.set(key, previewContent)\n this.emitter.emit(\"toolPreview\", {\n toolCallId: block.tool_call_id,\n type: previewType,\n content: previewContent,\n title: ui.title ?? \"工具预览\",\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 })\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(turn: TurnProjection, block: ContentBlock): void {\n if (!isToolBridgeContent(block.content)) return\n const { action, payload } = block.content\n let payloadKey = \"\"\n try {\n payloadKey = JSON.stringify(payload ?? null)\n } catch {\n payloadKey = String(payload ?? \"\")\n }\n const deliveryKey = [block.tool_call_id ?? turn.id, action, payloadKey].join(\"\u0000\")\n if (this.deliveredCommandKeys.has(deliveryKey)) return\n this.deliveredCommandKeys.add(deliveryKey)\n const meta = { toolCallId: block.tool_call_id ?? undefined }\n this.emitter.emit(\"command\", { action, payload, toolCallId: meta.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 private async syncTurnsFromHistory(\n options: {\n clearOnEmpty?: boolean\n suppressErrors?: boolean\n preserveChangesSince?: TurnProjection[]\n } = {},\n ): Promise<void> {\n const { clearOnEmpty = false, suppressErrors = true, preserveChangesSince } = options\n const turnsAtRequestStart = this.state.turns\n try {\n const turns = await this.runtime.fetchTurns(this.sessionId)\n if (turns.length === 0 && !clearOnEmpty) return\n this.update((state) => {\n const mergeBaseline = preserveChangesSince ?? turnsAtRequestStart\n if (state.turns === mergeBaseline) return withTurns(state, turns)\n\n const historyById = new Map(turns.map((turn) => [turn.turn_id, turn]))\n let merged = withTurns(state, turns)\n for (const current of state.turns) {\n const fromHistory = historyById.get(current.turn_id)\n if (!fromHistory || current.sequence > fromHistory.sequence) {\n merged = upsertTurn(merged, current)\n }\n }\n return merged\n })\n this.replayCommandsFromTurns(turns)\n } catch (error) {\n if (!suppressErrors) throw error\n // 尽力而为的历史补数,失败时保留现有内存状态\n }\n }\n\n /**\n * 把历史里的指令补投给宿主页面。\n *\n * 重开会话、断线补数时,地图高亮这类\"页面当前状态\"必须能恢复——\n * 否则刷新一次页面,之前智能体让页面做的事就全丢了。\n * 只回放指令:toolCall / message 这些事件如果按历史全量重放,\n * 监听器会在挂载瞬间收到几百条陈年事件。\n * dispatch 内部按 deliveredCommandKeys 去重,重复调用安全。\n */\n private replayCommandsFromTurns(turns: TurnProjection[]): void {\n for (const turn of turns) {\n for (const block of turn.blocks) {\n if (block.type === \"tool_bridge\" && isToolBridgeContent(block.content)) {\n this.dispatchCommand(turn, block)\n }\n }\n }\n }\n\n private ensureJoined(): 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 stream_tokens: this.runtime.streamTokens,\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))\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 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 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\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\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): Promise<AgentSession> {\n const existing = this.sessions.get(sessionId)\n if (existing && !existing.isDisposed) {\n this.hold(sessionId)\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 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 const socket = this.client.socket()\n socket.disconnect()\n this.setConnection(\"connecting\")\n socket.connect()\n }\n\n /** 断开连接(不清理 session 实例)。 */\n disconnect(): void {\n this.client.socket().disconnect()\n this.setConnection(\"disconnected\")\n }\n\n /** 清理当前身份下缓存的全部会话,避免切换登录身份后复用旧快照。 */\n disposeAll(): void {\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.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 streamTokens: this.client.options?.streamTokens !== false,\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 fetchTurns: (sessionId) => this.client.sessions.getSessionTurns(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 // 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 }\n\n private ensureConnected(): void {\n const socket = this.client.socket()\n if (socket.connected || socket.active) 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 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 }\n })\n socket.on(\"connect_error\", () => this.setConnection(\"disconnected\"))\n socket.on(\"disconnect\", () => this.setConnection(\"disconnected\"))\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(\"turn:events\", (data: { session_id?: string; events: RawEvent[] }) => {\n for (const session of this.route(data.session_id)) session._handleTurnEvents(data.events ?? [])\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 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 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\"\nimport { SDK_NAME, SDK_VERSION } from \"./version\"\n\nexport type TypedSocket = Socket<ServerToClientEvents, ClientToServerEvents>\n\nexport interface CreateSocketOptions extends AuthOptions {\n baseUrl: string\n path?: string\n}\n\n/** 握手时声明 SDK 身份,让 Server 能把旧 agent-kit 挡在门外并给出升级提示。 */\nfunction withSdkIdentity(auth: { token: string } | undefined): Record<string, string> {\n return { ...(auth ?? {}), sdk: SDK_NAME, sdk_version: SDK_VERSION }\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(withSdkIdentity(buildSocketAuth(options)))\n : withSdkIdentity(buildSocketAuth(options)),\n autoConnect: false,\n })\n}\n","export interface AuthOptions {\n token?: string | (() => string | null | undefined)\n}\n\nexport function buildAuthHeaders(options: AuthOptions): Record<string, string> {\n const token = resolveAuthToken(options)\n if (!token) {\n return {}\n }\n return {\n Authorization: `Bearer ${token}`,\n }\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","/** 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","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 decorateAuthError,\n extractErrorDetail,\n} from \"./rest\"\nimport { AuthResource } from \"./resources/auth\"\nimport { HeadlessResource } from \"./resources/headless\"\nimport { ModelsResource } from \"./resources/models\"\nimport { SessionsResource } from \"./resources/sessions\"\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 /** 是否订阅逐 token 增量,默认 true。关闭后仍接收完整消息和语义事件。 */\n streamTokens?: boolean\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 models: ModelsResource\n readonly sessions: SessionsResource\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.models = new ModelsResource(this)\n this.sessions = new SessionsResource(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.tryRefresh()\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 = new URL(this.toBaseRelativePath(path), this.baseUrlWithTrailingSlash())\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 new URL(this.toBaseRelativePath(path), this.baseUrlWithTrailingSlash())\n }\n\n private baseUrlWithTrailingSlash(): string {\n return this.options.baseUrl.endsWith(\"/\") ? this.options.baseUrl : `${this.options.baseUrl}/`\n }\n\n private toBaseRelativePath(path: string): string {\n return path.startsWith(\"/\") ? path.slice(1) : path\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 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","export 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 isRecord(value: unknown): value is Record<string, unknown> {\n return typeof value === \"object\" && value !== null && !Array.isArray(value)\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","/**\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":["isRecord","isRecord","isRecord","type","response","attachments","contexts","isRecord","buildMessageContent","toolCall","isRecord","hasChatRunEvent","handle","isRecord","LayoutType","type"]}
|