@tencent-ai/cloud-agent-sdk 0.3.0 → 0.3.1

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.
@@ -1 +1 @@
1
- {"version":3,"file":"index.cjs","names":["TimeoutError","TimeoutError","TimeoutError","streamableHttp"],"sources":["../src/v1/errors.ts","../src/v1/acp/vendor/sdk.ts","../src/v1/acp/transport.ts","../src/v1/acp/vendor/artifacts.ts","../src/v1/acp/vendor/acp-types.ts","../src/v1/acp/vendor/constants.ts","../src/v1/acp/vendor/errors.ts","../src/v1/acp/vendor/events.ts","../src/v1/acp/vendor/extensions.ts","../src/v1/acp/vendor/permissions.ts","../src/v1/acp/vendor/questions.ts","../src/v1/acp/vendor/client.ts","../src/v1/acp/client.ts","../src/v1/internal/log.ts","../src/v1/session.ts","../src/v1/runtime.ts","../src/v1/internal/redact.ts","../src/v1/rest/client.ts","../src/v1/client.ts","../src/v1/manifest.ts"],"sourcesContent":["/**\n * 错误类型体系\n *\n * 双 ID 体系:\n * - `logId` SDK 本地生成的短 ID(`log_a1b2c3`),用于在**用户自己的日志**里\n * 反查 SDK 上下文(重试链、脱敏后的 headers 等)。\n * - `requestId` 服务端 `x-request-id` 响应头或业务 body.requestId,用于**贴给\n * 服务端团队**排障。\n *\n * 重试决策**不**挂在错误类上。是否重试由 `RetryOpts.retryOn(err, ctx)` 统一决定\n * (见 `rest/client.ts` 里的 `DEFAULT_RETRY_ON`)。这样决策只有一个入口,\n * 用户可以通过 `retry: { retryOn: ... }` 完全覆盖。\n *\n * 详见 docs/agentos/sdk/07-error-retry.md § 1 / § 4.3。\n */\n\nexport interface CloudAgentErrorOpts {\n code?: number;\n httpStatus?: number;\n /** SDK 本地日志串联 ID(形如 `log_a1b2c3`)。 */\n logId?: string;\n /** 服务端返回的 `x-request-id` 或 body.requestId。 */\n requestId?: string;\n cause?: Error;\n}\n\nexport class CloudAgentError extends Error {\n readonly code: number;\n readonly httpStatus?: number;\n readonly logId?: string;\n readonly requestId?: string;\n readonly originalCause?: Error;\n\n constructor(message: string, opts: CloudAgentErrorOpts = {}) {\n super(message);\n this.name = 'CloudAgentError';\n this.code = opts.code ?? -1;\n this.httpStatus = opts.httpStatus;\n this.logId = opts.logId;\n this.requestId = opts.requestId;\n this.originalCause = opts.cause;\n // ES2022 cause polyfill\n if (opts.cause && !('cause' in this)) {\n Object.defineProperty(this, 'cause', { value: opts.cause, writable: false });\n }\n }\n}\n\nexport class NetworkError extends CloudAgentError {\n constructor(message: string, opts?: CloudAgentErrorOpts) {\n super(message, opts);\n this.name = 'NetworkError';\n }\n}\n\nexport class TimeoutError extends CloudAgentError {\n constructor(message: string, opts?: CloudAgentErrorOpts) {\n super(message, opts);\n this.name = 'TimeoutError';\n }\n}\n\nexport class AuthError extends CloudAgentError {\n constructor(message: string, opts?: CloudAgentErrorOpts) {\n super(message, opts);\n this.name = 'AuthError';\n }\n}\n\nexport class NotFoundError extends CloudAgentError {\n constructor(message: string, opts?: CloudAgentErrorOpts) {\n super(message, opts);\n this.name = 'NotFoundError';\n }\n}\n\nexport class ValidationError extends CloudAgentError {\n constructor(message: string, opts?: CloudAgentErrorOpts) {\n super(message, opts);\n this.name = 'ValidationError';\n }\n}\n\nexport class AcpProtocolError extends CloudAgentError {\n constructor(message: string, opts?: CloudAgentErrorOpts) {\n super(message, opts);\n this.name = 'AcpProtocolError';\n }\n}\n","/**\n * SDK Type Re-exports and Capability Extensions\n *\n * This file provides:\n * 1. Re-exports of commonly used types from @agentclientprotocol/sdk\n * 2. Extended capability types with codebuddy.ai metadata\n */\n\n// ============================================\n// SDK Type Re-exports\n// ============================================\n\n// ============================================\n// codebuddy.ai Capability Extensions\n// ============================================\n\nimport type { ArtifactType } from './acp-types.js';\n\ntype SdkClientCapabilities = import('@agentclientprotocol/sdk', { with: { 'resolution-mode': 'import' } }).ClientCapabilities;\ntype SdkAgentCapabilities = import('@agentclientprotocol/sdk', { with: { 'resolution-mode': 'import' } }).AgentCapabilities;\n\nexport type InitializeRequest = import('@agentclientprotocol/sdk', { with: { 'resolution-mode': 'import' } }).InitializeRequest;\nexport type InitializeResponse = import('@agentclientprotocol/sdk', { with: { 'resolution-mode': 'import' } }).InitializeResponse;\nexport type NewSessionRequest = import('@agentclientprotocol/sdk', { with: { 'resolution-mode': 'import' } }).NewSessionRequest;\nexport type NewSessionResponse = import('@agentclientprotocol/sdk', { with: { 'resolution-mode': 'import' } }).NewSessionResponse;\nexport type LoadSessionRequest = import('@agentclientprotocol/sdk', { with: { 'resolution-mode': 'import' } }).LoadSessionRequest;\nexport type LoadSessionResponse = import('@agentclientprotocol/sdk', { with: { 'resolution-mode': 'import' } }).LoadSessionResponse;\nexport type PromptRequest = import('@agentclientprotocol/sdk', { with: { 'resolution-mode': 'import' } }).PromptRequest;\nexport type PromptResponse = import('@agentclientprotocol/sdk', { with: { 'resolution-mode': 'import' } }).PromptResponse;\nexport type CancelNotification = import('@agentclientprotocol/sdk', { with: { 'resolution-mode': 'import' } }).CancelNotification;\nexport type RequestPermissionRequest = import('@agentclientprotocol/sdk', { with: { 'resolution-mode': 'import' } }).RequestPermissionRequest;\nexport type RequestPermissionResponse = import('@agentclientprotocol/sdk', { with: { 'resolution-mode': 'import' } }).RequestPermissionResponse;\nexport type SessionNotification = import('@agentclientprotocol/sdk', { with: { 'resolution-mode': 'import' } }).SessionNotification;\nexport type ContentBlock = import('@agentclientprotocol/sdk', { with: { 'resolution-mode': 'import' } }).ContentBlock;\nexport type TextContent = import('@agentclientprotocol/sdk', { with: { 'resolution-mode': 'import' } }).TextContent;\nexport type ImageContent = import('@agentclientprotocol/sdk', { with: { 'resolution-mode': 'import' } }).ImageContent;\nexport type AudioContent = import('@agentclientprotocol/sdk', { with: { 'resolution-mode': 'import' } }).AudioContent;\nexport type ResourceLink = import('@agentclientprotocol/sdk', { with: { 'resolution-mode': 'import' } }).ResourceLink;\nexport type EmbeddedResource = import('@agentclientprotocol/sdk', { with: { 'resolution-mode': 'import' } }).EmbeddedResource;\nexport type ToolCallContent = import('@agentclientprotocol/sdk', { with: { 'resolution-mode': 'import' } }).ToolCallContent;\nexport type ToolCallStatus = import('@agentclientprotocol/sdk', { with: { 'resolution-mode': 'import' } }).ToolCallStatus;\nexport type ToolKind = import('@agentclientprotocol/sdk', { with: { 'resolution-mode': 'import' } }).ToolKind;\nexport type Client = import('@agentclientprotocol/sdk', { with: { 'resolution-mode': 'import' } }).Client;\nexport type SetSessionModelRequest = import('@agentclientprotocol/sdk', { with: { 'resolution-mode': 'import' } }).SetSessionModelRequest;\nexport type SetSessionModelResponse = import('@agentclientprotocol/sdk', { with: { 'resolution-mode': 'import' } }).SetSessionModelResponse;\nexport type SetSessionModeRequest = import('@agentclientprotocol/sdk', { with: { 'resolution-mode': 'import' } }).SetSessionModeRequest;\nexport type SetSessionModeResponse = import('@agentclientprotocol/sdk', { with: { 'resolution-mode': 'import' } }).SetSessionModeResponse;\nexport type Stream = import('@agentclientprotocol/sdk', { with: { 'resolution-mode': 'import' } }).Stream;\nexport type { SdkClientCapabilities, SdkAgentCapabilities };\n\n// ACP TS SDK v0.18.2 exports this from schema/index.js as a simple numeric constant.\n// Re-declare it locally so CommonJS consumers don't need to statically import an ESM package.\nexport const PROTOCOL_VERSION = 1 as const;\n\nexport async function loadAcpSdk(): Promise<typeof import('@agentclientprotocol/sdk', { with: { 'resolution-mode': 'import' } })> {\n return import('@agentclientprotocol/sdk') as Promise<typeof import('@agentclientprotocol/sdk', { with: { 'resolution-mode': 'import' } })>;\n}\n\n/**\n * Configuration for a specific artifact type\n */\nexport interface ArtifactTypeConfig {\n /** Whether this artifact type is enabled */\n enabled?: boolean;\n}\n\n/**\n * Artifacts configuration in codebuddy.ai extension\n */\nexport type ArtifactsConfig = {\n [K in ArtifactType]?: ArtifactTypeConfig;\n};\n\n/**\n * codebuddy.ai extension capabilities for Client\n * Symmetric with CodebuddyAgentMeta for capability negotiation\n */\nexport interface CodebuddyClientMeta {\n /** Artifact types the client supports receiving */\n artifacts?: ArtifactsConfig;\n /** Whether the client supports checkpoint notifications */\n checkpoint?: boolean;\n /**\n * Whether the client supports handling AskUserQuestion tool via extMethod.\n * When true, AskUserQuestion requests will be sent to the client via\n * the '_codebuddy.ai/question' extMethod instead of being handled locally.\n */\n question?: boolean;\n}\n\n/**\n * codebuddy.ai extension capabilities for Agent\n */\nexport interface CodebuddyAgentMeta {\n /** Artifact types the agent can produce */\n artifacts?: ArtifactsConfig;\n /** Whether the agent supports checkpoint notifications */\n checkpoint?: boolean;\n}\n\n/**\n * Client capabilities with codebuddy.ai extensions\n */\nexport type ClientCapabilities = Omit<SdkClientCapabilities, '_meta'> & {\n /** Extension methods the client can handle (e.g., '_codebuddy.ai/*') */\n extensions?: string[];\n _meta?: {\n 'codebuddy.ai'?: CodebuddyClientMeta;\n [key: string]: unknown;\n } | null;\n};\n\n/**\n * Agent capabilities with codebuddy.ai extensions\n */\nexport type AgentCapabilities = Omit<SdkAgentCapabilities, '_meta'> & {\n /** Extension methods supported by this agent (e.g., '_codebuddy.ai/*') */\n extensions?: string[];\n _meta?: {\n 'codebuddy.ai'?: CodebuddyAgentMeta;\n [key: string]: unknown;\n } | null;\n};\n","/**\n * Streamable HTTP Transport for ACP\n *\n * 从 @genie/agent-client-protocol/src/common/transport/streamable-http.ts 迁移。\n * 实现官方 @agentclientprotocol/sdk 的 Stream 接口。\n *\n * 协议流程:\n * 1. Client 建立 GET SSE 连接,获取 Acp-Connection-Id\n * 2. Client 通过 POST 发送 JSON-RPC 请求(携带 Acp-Connection-Id header)\n * 3. 通知通过 GET SSE 推送,响应通过 POST SSE 返回\n *\n * 稳定性保证:\n * - 指数退避自动重连 + ±25% jitter\n * - Last-Event-ID 断点续传\n * - Acp-Connection-Id 复用\n * - 心跳超时检测(默认 60s)\n * - connectionVersion 防竞态\n * - backpressure 保护(highWaterMark/lowWaterMark)\n * - POST SSE 后台处理(防死锁)\n */\n\nexport interface StreamableHttpTransportOptions {\n /** ACP endpoint URL */\n endpoint: string;\n /** Authorization token (Bearer) */\n authToken?: string;\n /** Custom headers */\n headers?: Record<string, string>;\n /** Reconnect options */\n reconnect?: {\n enabled?: boolean; // default: true\n initialDelay?: number; // ms, default: 1000\n maxDelay?: number; // ms, default: 30000\n maxRetries?: number; // default: Infinity\n jitter?: boolean; // default: true (±25%)\n };\n /** AbortSignal to cancel */\n signal?: AbortSignal;\n /** Custom fetch */\n fetch?: typeof fetch;\n /** Callbacks */\n onConnect?: (connectionId: string) => void;\n onDisconnect?: (connectionId: string) => void;\n onError?: (error: Error) => void;\n /** Heartbeat timeout ms (default: 60000). 0 to disable. */\n heartbeatTimeout?: number;\n /** Connection establishment timeout ms (default: 30000) */\n connectionTimeout?: number;\n /** POST request timeout ms (default: 30000) */\n postTimeout?: number;\n /** Backpressure options */\n backpressure?: {\n highWaterMark?: number; // default: 100\n lowWaterMark?: number; // default: 50\n pauseTimeout?: number; // default: 5000ms\n };\n}\n\n/** Transport 接口(兼容 @agentclientprotocol/sdk 的 Stream) */\nexport interface StreamableHttpTransport {\n readonly readable: ReadableStream<unknown>;\n readonly writable: WritableStream<unknown>;\n readonly connectionId: string | undefined;\n readonly ready: Promise<void>;\n close(): Promise<void>;\n}\n\ninterface SSEEvent {\n type: string;\n data: string;\n id?: string;\n}\n\n/**\n * 创建 Streamable HTTP transport。\n * 返回的对象实现 Stream 接口(readable + writable),可直接传给 ClientSideConnection。\n */\nexport function createStreamableHttpTransport(options: StreamableHttpTransportOptions): StreamableHttpTransport {\n const {\n endpoint,\n authToken,\n headers: customHeaders = {},\n reconnect = {},\n signal: externalSignal,\n fetch: customFetch = globalThis.fetch,\n onConnect,\n onDisconnect,\n onError,\n heartbeatTimeout = 60000,\n connectionTimeout = 30000,\n postTimeout = 30000,\n backpressure = {},\n } = options;\n\n const {\n enabled: reconnectEnabled = true,\n initialDelay = 1000,\n maxDelay = 30000,\n maxRetries = Infinity,\n jitter: jitterEnabled = true,\n } = reconnect;\n\n const {\n highWaterMark = 100,\n lowWaterMark = 50,\n pauseTimeout = 5000,\n } = backpressure;\n\n // 连接状态\n let connectionId: string | undefined;\n let lastEventId: string | undefined;\n let reconnectAttempts = 0;\n let closed = false;\n let isClosing = false;\n let connectionVersion = 0;\n\n // 连接就绪 promise\n let connectionReady: Promise<void>;\n let resolveConnection: () => void;\n let rejectConnection: (error: Error) => void;\n\n connectionReady = new Promise((resolve, reject) => {\n resolveConnection = resolve;\n rejectConnection = reject;\n });\n\n const abortController = new AbortController();\n\n function isAborted(): boolean {\n return abortController.signal.aborted || (externalSignal?.aborted ?? false);\n }\n\n // 消息队列 + backpressure\n const messageQueue: unknown[] = [];\n const messageResolvers: Array<(value: unknown | null) => void> = [];\n let streamError: Error | null = null;\n let isPaused = false;\n let resumeReading: (() => void) | null = null;\n\n // 心跳\n let lastActivity = Date.now();\n let heartbeatCheckTimer: ReturnType<typeof setInterval> | undefined;\n\n function enqueueMessage(message: unknown): void {\n if (messageResolvers.length > 0) {\n messageResolvers.shift()!(message);\n } else {\n messageQueue.push(message);\n if (messageQueue.length >= highWaterMark) {\n isPaused = true;\n }\n }\n }\n\n function dequeueMessage(): Promise<unknown | null> {\n if (closed) return Promise.resolve(null);\n if (streamError) return Promise.reject(streamError);\n if (messageQueue.length > 0) {\n const message = messageQueue.shift()!;\n if (isPaused && messageQueue.length <= lowWaterMark) {\n isPaused = false;\n if (resumeReading) { queueMicrotask(() => resumeReading!()); }\n }\n return Promise.resolve(message);\n }\n return new Promise(resolve => { messageResolvers.push(resolve); });\n }\n\n function updateLastActivity(): void { lastActivity = Date.now(); }\n\n function startHeartbeatCheck(triggerReconnect: () => void): void {\n if (heartbeatTimeout <= 0) return;\n heartbeatCheckTimer = setInterval(() => {\n if (Date.now() - lastActivity > heartbeatTimeout) {\n triggerReconnect();\n }\n }, 10000);\n }\n\n function stopHeartbeatCheck(): void {\n if (heartbeatCheckTimer) { clearInterval(heartbeatCheckTimer); heartbeatCheckTimer = undefined; }\n }\n\n function calculateDelay(attempt: number): number {\n const baseDelay = Math.min(initialDelay * Math.pow(2, attempt - 1), maxDelay);\n if (!jitterEnabled) return baseDelay;\n const jitterFactor = 0.25 * (Math.random() * 2 - 1);\n return Math.round(baseDelay * (1 + jitterFactor));\n }\n\n function closeWithError(error: Error): void {\n streamError = error;\n closed = true;\n stopHeartbeatCheck();\n if (resumeReading) { resumeReading(); resumeReading = null; }\n rejectConnection(error);\n onError?.(error);\n while (messageResolvers.length > 0) { messageResolvers.shift()!(null); }\n }\n\n function closeNormally(): void {\n closed = true;\n stopHeartbeatCheck();\n if (resumeReading) { resumeReading(); resumeReading = null; }\n while (messageResolvers.length > 0) { messageResolvers.shift()!(null); }\n }\n\n function buildHeaders(): Record<string, string> {\n const headers: Record<string, string> = { ...customHeaders };\n if (authToken) headers['Authorization'] = `Bearer ${authToken}`;\n return headers;\n }\n\n // SSE 流处理\n async function processSSEStream(reader: ReadableStreamDefaultReader<Uint8Array>): Promise<void> {\n const decoder = new TextDecoder();\n let buffer = '';\n let currentEvent: Partial<SSEEvent> = {};\n\n try {\n while (true) {\n if (isPaused) {\n await new Promise<void>(resolve => {\n let resolved = false;\n const timeoutId = setTimeout(() => {\n if (!resolved) { resolved = true; resolve(); }\n }, pauseTimeout);\n resumeReading = () => {\n if (!resolved) { resolved = true; clearTimeout(timeoutId); resolve(); }\n };\n });\n resumeReading = null;\n }\n\n const { value, done } = await reader.read();\n if (done) break;\n\n buffer += decoder.decode(value, { stream: true });\n const lines = buffer.split('\\n');\n buffer = lines.pop() || '';\n\n for (const line of lines) {\n if (line === '') {\n if (currentEvent.data) {\n updateLastActivity();\n if (currentEvent.id) lastEventId = currentEvent.id;\n if (currentEvent.type === 'message' || !currentEvent.type) {\n try {\n const message = JSON.parse(currentEvent.data);\n if (message && typeof message === 'object' && 'jsonrpc' in message) {\n enqueueMessage(message);\n }\n } catch { /* ignore */ }\n }\n }\n currentEvent = {};\n } else if (line.startsWith(':')) {\n updateLastActivity(); // 心跳\n } else {\n const colonIdx = line.indexOf(':');\n if (colonIdx === -1) continue;\n const field = line.slice(0, colonIdx);\n let val = line.slice(colonIdx + 1);\n if (val.startsWith(' ')) val = val.slice(1);\n switch (field) {\n case 'event':\n if (currentEvent.type && currentEvent.type !== val) currentEvent.data = undefined;\n currentEvent.type = val; break;\n case 'data':\n currentEvent.data = (currentEvent.data || '') + val; break;\n case 'id':\n currentEvent.id = val; break;\n }\n }\n }\n }\n } finally {\n reader.releaseLock();\n }\n }\n\n function processSSEStreamBackground(reader: ReadableStreamDefaultReader<Uint8Array>): void {\n processSSEStream(reader).catch(error => {\n onError?.(error instanceof Error ? error : new Error(String(error)));\n });\n }\n\n // GET SSE 连接循环\n async function startSSEConnection(): Promise<void> {\n let currentReader: ReadableStreamDefaultReader<Uint8Array> | null = null;\n\n const triggerReconnect = (): void => {\n currentReader?.cancel().catch(() => {});\n };\n\n while (!closed && !isAborted()) {\n try {\n const headers = buildHeaders();\n headers['Accept'] = 'text/event-stream';\n if (lastEventId) headers['Last-Event-ID'] = lastEventId;\n if (connectionId) headers['Acp-Connection-Id'] = connectionId;\n\n const connectController = new AbortController();\n const connectTimer = setTimeout(() => connectController.abort(), connectionTimeout > 0 ? connectionTimeout : 30000);\n if (externalSignal) externalSignal.addEventListener('abort', () => connectController.abort(), { once: true });\n abortController.signal.addEventListener('abort', () => connectController.abort(), { once: true });\n\n let response: Response;\n try {\n response = await customFetch(endpoint, { method: 'GET', headers, signal: connectController.signal });\n } finally {\n clearTimeout(connectTimer);\n }\n\n if (!response.ok) throw new Error(`HTTP ${response.status}`);\n\n const newConnectionId = response.headers.get('Acp-Connection-Id');\n if (!newConnectionId) throw new Error('Server did not return Acp-Connection-Id');\n\n const previousConnectionId = connectionId;\n connectionVersion++;\n connectionId = newConnectionId;\n resolveConnection();\n\n if (previousConnectionId && previousConnectionId !== newConnectionId) {\n onDisconnect?.(previousConnectionId);\n }\n onConnect?.(newConnectionId);\n reconnectAttempts = 0;\n\n updateLastActivity();\n startHeartbeatCheck(triggerReconnect);\n\n const reader = response.body?.getReader();\n if (reader) {\n currentReader = reader;\n await processSSEStream(reader);\n currentReader = null;\n }\n\n stopHeartbeatCheck();\n const endedConnectionId = connectionId;\n connectionId = undefined;\n if (endedConnectionId) onDisconnect?.(endedConnectionId);\n\n if (!reconnectEnabled || closed) break;\n\n connectionReady = new Promise((resolve, reject) => {\n resolveConnection = resolve;\n rejectConnection = reject;\n });\n\n const reconnectDelay = calculateDelay(1);\n await new Promise(resolve => setTimeout(resolve, reconnectDelay));\n\n } catch (error) {\n stopHeartbeatCheck();\n currentReader = null;\n if (isAborted() || closed) break;\n\n reconnectAttempts++;\n if (reconnectAttempts > maxRetries) {\n closeWithError(new Error(`SSE reconnect failed after ${maxRetries} attempts`));\n break;\n }\n\n const delay = calculateDelay(reconnectAttempts);\n await new Promise(resolve => setTimeout(resolve, delay));\n }\n }\n }\n\n // POST 发送消息\n async function sendMessage(message: unknown): Promise<void> {\n if (closed) throw new Error('Connection is closed');\n\n // 等待连接稳定(防竞态)\n const maxWaitAttempts = 5;\n let currentConnectionId: string | undefined;\n\n for (let attempt = 0; attempt < maxWaitAttempts; attempt++) {\n const versionBeforeWait = connectionVersion;\n await connectionReady;\n if (versionBeforeWait !== connectionVersion && versionBeforeWait > 0) {\n await connectionReady;\n }\n currentConnectionId = connectionId;\n if (currentConnectionId) break;\n if (attempt < maxWaitAttempts - 1) {\n await new Promise(resolve => setTimeout(resolve, 100));\n }\n }\n\n if (!currentConnectionId) throw new Error('No connection ID available');\n\n const headers = buildHeaders();\n headers['Content-Type'] = 'application/json';\n headers['Accept'] = 'application/json, text/event-stream';\n headers['Acp-Connection-Id'] = currentConnectionId;\n\n const postController = new AbortController();\n let timeoutId: ReturnType<typeof setTimeout> | undefined;\n\n if (postTimeout > 0) {\n timeoutId = setTimeout(() => postController.abort(), postTimeout);\n if (externalSignal) externalSignal.addEventListener('abort', () => postController.abort(), { once: true });\n abortController.signal.addEventListener('abort', () => postController.abort(), { once: true });\n }\n\n try {\n const response = await customFetch(endpoint, {\n method: 'POST',\n headers,\n body: JSON.stringify(message),\n signal: postTimeout > 0 ? postController.signal : abortController.signal,\n });\n\n if (!response.ok) {\n const errorText = await response.text().catch(() => 'Unknown error');\n throw new Error(`HTTP ${response.status}: ${errorText}`);\n }\n\n const contentType = response.headers.get('Content-Type') || '';\n if (contentType.includes('text/event-stream')) {\n const reader = response.body?.getReader();\n if (reader) processSSEStreamBackground(reader);\n } else if (contentType.includes('application/json')) {\n const data = await response.json();\n if (data && typeof data === 'object' && 'jsonrpc' in data) {\n enqueueMessage(data);\n }\n }\n } finally {\n if (timeoutId) clearTimeout(timeoutId);\n }\n }\n\n // 启动 SSE\n startSSEConnection().catch(() => {});\n\n // 构造 ReadableStream / WritableStream(实现 Stream 接口)\n const readable = new ReadableStream<unknown>({\n async pull(controller) {\n const message = await dequeueMessage();\n if (message === null) { controller.close(); }\n else { controller.enqueue(message); }\n },\n cancel() { closeNormally(); abortController.abort(); },\n });\n\n const writable = new WritableStream<unknown>({\n async write(message) { await sendMessage(message); },\n close() { closeNormally(); abortController.abort(); },\n abort(reason) {\n closeWithError(reason instanceof Error ? reason : new Error(String(reason)));\n abortController.abort();\n },\n });\n\n async function close(): Promise<void> {\n if (closed) return;\n if (!connectionId || isClosing) { closeNormally(); abortController.abort(); return; }\n isClosing = true;\n try {\n const headers = buildHeaders();\n headers['Acp-Connection-Id'] = connectionId;\n await customFetch(endpoint, { method: 'DELETE', headers, signal: AbortSignal.timeout(5000) });\n } catch { /* ignore */ }\n finally {\n if (connectionId) onDisconnect?.(connectionId);\n isClosing = false;\n }\n closeNormally();\n abortController.abort();\n }\n\n return {\n readable,\n writable,\n get connectionId() { return connectionId; },\n get ready() { return connectionReady; },\n close,\n };\n}\n\n\n// 别名 - 与老 SDK @genie/agent-client-protocol 保持一致\nexport { createStreamableHttpTransport as streamableHttp };\nexport type { StreamableHttpTransportOptions as StreamableHttpOptions };\n\n","/**\n * Artifact Manager for Streamable HTTP ACP Client\n * Handles artifact notification processing\n */\n\nimport type {\n Artifact,\n ArtifactEvent,\n ArtifactNotificationParams,\n} from './acp-types.js';\nimport type { Logger } from './types.js';\n\n/**\n * Configuration for ArtifactManager\n */\nexport interface ArtifactManagerConfig {\n /** Logger instance */\n logger?: Logger;\n}\n\n/**\n * Callback for artifact events\n */\nexport type ArtifactEventCallback = (artifact: Artifact, event: ArtifactEvent) => void;\n\n/**\n * Manages artifact notifications from the agent\n */\nexport class ArtifactManager {\n private artifacts = new Map<string, Artifact>();\n private logger?: Logger;\n private eventCallbacks: Set<ArtifactEventCallback> = new Set();\n\n constructor(config: ArtifactManagerConfig) {\n this.logger = config.logger;\n }\n\n /**\n * Register a callback for artifact events\n */\n onArtifactEvent(callback: ArtifactEventCallback): () => void {\n this.eventCallbacks.add(callback);\n return () => {\n this.eventCallbacks.delete(callback);\n };\n }\n\n /**\n * Handle an artifact notification from the agent\n */\n handleNotification(notification: ArtifactNotificationParams): void {\n const { event } = notification;\n\n if (event === 'deleted') {\n const { artifact } = notification;\n const existing = this.artifacts.get(artifact.uri);\n this.logger?.debug(`Artifact deleted: ${artifact.uri}`);\n this.artifacts.delete(artifact.uri);\n\n // Notify callbacks with existing artifact if available\n if (existing) {\n this.notifyCallbacks(existing, event);\n }\n } else {\n const { artifact } = notification;\n this.logger?.debug(`Artifact ${event}: ${artifact.uri} (${artifact.type})`);\n this.artifacts.set(artifact.uri, artifact);\n this.notifyCallbacks(artifact, event);\n }\n }\n\n private notifyCallbacks(artifact: Artifact, event: ArtifactEvent): void {\n for (const callback of this.eventCallbacks) {\n try {\n callback(artifact, event);\n } catch (err) {\n this.logger?.error('Error in artifact event callback:', err);\n }\n }\n }\n\n /**\n * Get an artifact by URI (used internally for deleted event handling)\n */\n get(uri: string): Artifact | undefined {\n return this.artifacts.get(uri);\n }\n\n /**\n * Clear all artifacts\n */\n clear(): void {\n this.artifacts.clear();\n this.logger?.debug('Cleared all artifacts');\n }\n}\n","/**\n * Protocol Extension Types for Agent Client Protocol\n *\n * This file contains codebuddy.ai extension types that extend the base ACP protocol.\n * For SDK type re-exports and capability extensions, see ./sdk.ts\n */\n\n// ============================================\n// Extension Method Constants\n// ============================================\n\n/**\n * Extension method names as const for type safety\n */\nexport const ExtensionMethod = {\n ARTIFACT: '_codebuddy.ai/artifact',\n /**\n * Question/ToolInput extension method.\n * Used for tools that require user input (e.g., AskUserQuestion).\n * Request: ToolInputRequest, Response: ToolInputResponse\n */\n QUESTION: '_codebuddy.ai/question',\n CHECKPOINT: '_codebuddy.ai/checkpoint',\n /** Command extension method for executing custom commands */\n COMMAND: '_codebuddy.ai/command',\n /** Auth URL notification for external authentication */\n AUTH_URL: '_codebuddy.ai/authUrl',\n /** File history snapshot for checkpoint processing */\n FILE_HISTORY_SNAPSHOT: '_codebuddy.ai/file_history_snapshot',\n /** Delegate tool execution from external client-side tool provider */\n DELEGATE_TOOL: '_codebuddy.ai/delegateTool',\n /** Notification when available delegate tools change */\n DELEGATE_TOOLS_CHANGED: '_codebuddy.ai/delegateToolsChanged',\n /** UI control for operating Web UI elements */\n UI_CONTROL: '_codebuddy.ai/uiControl',\n} as const;\n\nexport type ExtensionMethodName = (typeof ExtensionMethod)[keyof typeof ExtensionMethod];\n\n/**\n * All known extension methods\n */\nexport const KNOWN_EXTENSIONS = [\n ExtensionMethod.ARTIFACT,\n ExtensionMethod.QUESTION,\n ExtensionMethod.CHECKPOINT,\n ExtensionMethod.COMMAND,\n ExtensionMethod.AUTH_URL,\n ExtensionMethod.FILE_HISTORY_SNAPSHOT,\n ExtensionMethod.DELEGATE_TOOL,\n ExtensionMethod.DELEGATE_TOOLS_CHANGED,\n] as const;\n\n// ============================================\n// Extension Notification Types (Discriminated Union)\n// ============================================\n\n/**\n * Discriminated union for extension notifications\n * Use `method` field as discriminant for type narrowing\n */\nexport type ExtensionNotification = ArtifactExtNotification;\n\nexport interface ArtifactExtNotification {\n method: typeof ExtensionMethod.ARTIFACT;\n params: ArtifactNotificationParams;\n}\n\n// ============================================\n// Artifact Types\n// ============================================\n\n/**\n * Types of artifacts that can be created by the agent\n * Uses discriminant for TypeScript type narrowing\n */\nexport type ArtifactType = 'plan' | 'tasks' | 'media' | 'overview';\n\n/**\n * Artifact lifecycle events\n */\nexport type ArtifactEvent = 'created' | 'updated' | 'deleted';\n\n/**\n * Base Artifact interface\n * Inspired by MCP Resource: https://modelcontextprotocol.io/specification/2025-11-25/server/resources\n */\nexport interface BaseArtifact<T extends ArtifactType = ArtifactType> {\n /** Artifact type (discriminant for type narrowing) */\n type: T;\n /**\n * Unique identifier URI\n * - Cloud Agent: agent:///{path} e.g. agent:///artifacts/plan.md\n * - Local Agent: file:///{path} e.g. file:///Users/xxx/project/plan.md\n */\n uri: string;\n /** Resource name */\n name: string;\n /** Display title */\n title?: string;\n /** Description */\n description?: string;\n /** Artifact creation timestamp (epoch milliseconds) */\n createdAt?: number;\n /** Artifact last update timestamp (epoch milliseconds) */\n updatedAt?: number;\n}\n\n// ============================================\n// Plan Artifact\n// ============================================\n\n/**\n * Plan Artifact - Markdown document\n * mimeType: text/markdown\n */\nexport interface PlanArtifact extends BaseArtifact<'plan'> {\n /** MIME type fixed as text/markdown */\n mimeType: 'text/markdown';\n /** Markdown text content */\n text: string;\n /** Version number (for diff) */\n version?: number;\n /** Previous version content (for diff display) */\n previousText?: string;\n /** Whether editing is enabled */\n enableEdit?: boolean;\n}\n\n// ============================================\n// Tasks Artifact\n// ============================================\n\n/**\n * Task item status\n */\nexport type TaskItemStatus = 'pending' | 'in_progress' | 'completed' | 'cancelled';\n\n/**\n * Single task item\n */\nexport interface TaskItem {\n id: string;\n content: string;\n status: TaskItemStatus;\n order?: number;\n}\n\n/**\n * Tasks Artifact - Task list\n * mimeType: application/json\n */\nexport interface TasksArtifact extends BaseArtifact<'tasks'> {\n /** MIME type fixed as application/json */\n mimeType: 'application/json';\n /** Task list */\n tasks: TaskItem[];\n /** Whether editing is enabled */\n enableEdit?: boolean;\n}\n\n// ============================================\n// Media Artifact\n// ============================================\n\n/**\n * Media content type (auxiliary classification)\n */\nexport type MediaContentType = 'image' | 'video' | 'audio' | 'document' | 'spreadsheet' | 'presentation' | 'diagram' | 'code';\n\n/**\n * Media Artifact - Media files\n * Supports images, videos, documents and other browser-renderable files\n *\n * URI schemes:\n * - data:image/png;base64,... (inline small files)\n * - agent:///artifacts/... (cloud agent resources)\n * - file:///path/to/file (local agent files)\n */\nexport interface MediaArtifact extends BaseArtifact<'media'> {\n /** MIME type, e.g. image/png, video/mp4, application/pdf */\n mimeType: string;\n /** File size in bytes */\n size?: number;\n /** Media content classification (auxiliary for frontend rendering) */\n contentType?: MediaContentType;\n /** Width (for images/videos) */\n width?: number;\n /** Height (for images/videos) */\n height?: number;\n}\n\n// ============================================\n// Overview Artifact\n// ============================================\n\n/**\n * Overview Artifact - 任务完成后的总结文档\n * mimeType: text/markdown\n */\nexport interface OverviewArtifact extends BaseArtifact<'overview'> {\n /** MIME type fixed as text/markdown */\n mimeType: 'text/markdown';\n /** Markdown text content */\n text?: string;\n}\n\n// ============================================\n// Artifact Union Type\n// ============================================\n\n/**\n * Artifact union type\n * Uses type field for discriminated union\n */\nexport type Artifact = PlanArtifact | TasksArtifact | MediaArtifact | OverviewArtifact;\n\n// ============================================\n// Artifact Notification Types (Discriminated Union by event)\n// ============================================\n\nexport interface ArtifactCreatedParams {\n sessionId: string;\n event: 'created';\n artifact: Artifact;\n}\n\nexport interface ArtifactUpdatedParams {\n sessionId: string;\n event: 'updated';\n artifact: Artifact;\n}\n\nexport interface ArtifactDeletedParams {\n sessionId: string;\n event: 'deleted';\n artifact: Pick<Artifact, 'type' | 'uri'>; // Only type and uri needed for deletion\n}\n\n/**\n * Artifact notification discriminated by event\n */\nexport type ArtifactNotificationParams =\n | ArtifactCreatedParams\n | ArtifactUpdatedParams\n | ArtifactDeletedParams;\n\n// ============================================\n// Question Types\n// ============================================\n\n/**\n * Question option structure\n */\nexport interface QuestionOption {\n /** Display text (1-5 words) */\n label: string;\n /** Option description */\n description: string;\n}\n\n/**\n * Single question structure\n */\nexport interface UserQuestion {\n /** Question ID */\n id: string;\n /** Question text */\n question: string;\n /** Short label (max 12 chars) */\n header?: string;\n /** Available options (2-4) */\n options: QuestionOption[];\n /** Allow multiple selections */\n multiSelect?: boolean;\n}\n\n/**\n * Question request (Server -> Client)\n * Sent via extMethod: _codebuddy.ai/question\n */\nexport interface QuestionRequest {\n /** Session ID */\n sessionId: string;\n /** Associated tool call ID (links extMethod to tool_call for UI) */\n toolCallId: string;\n /** Input type */\n inputType?: string;\n /** Schema containing questions */\n schema?: {\n /** Questions to ask (1-4) */\n questions: UserQuestion[];\n };\n /** Questions to ask (1-4) - legacy format */\n questions?: UserQuestion[];\n /** Request timeout in ms */\n timeout?: number;\n}\n\n/**\n * Question response (Client -> Server)\n */\nexport interface QuestionResponse {\n /** Response outcome */\n outcome: 'submitted' | 'cancelled';\n /** User's answers keyed by question ID (when submitted) */\n answers?: Record<string, string | string[]>;\n /** Cancellation reason (when cancelled) */\n reason?: string;\n}\n\n// ============================================\n// Command Types\n// ============================================\n\n/**\n * Command notification parameters\n * Sent via extNotification: _codebuddy.ai/command\n */\nexport interface CommandNotificationParams {\n /** Session ID */\n sessionId: string;\n /** Command action to execute */\n action: string;\n /** Command parameters */\n params?: Record<string, unknown>;\n}\n\n// ============================================\n// Checkpoint Types\n// ============================================\n\n/**\n * Checkpoint event types\n */\nexport type CheckpointEvent = 'created' | 'updated';\n\n/**\n * Checkpoint notification parameters\n * Sent via extNotification: _codebuddy.ai/checkpoint\n */\nexport interface CheckpointNotificationParams {\n /** Session ID */\n sessionId: string;\n /** Event type */\n event: CheckpointEvent;\n /** Checkpoint information */\n checkpoint: CheckpointInfo;\n}\n\n/**\n * Checkpoint information visible to clients\n */\nexport interface CheckpointInfo {\n /** Checkpoint ID */\n id: string;\n /** Label/description */\n label?: string;\n /** Creation timestamp */\n createdAt: number;\n /** File change summary */\n fileChanges: FileChangeSummary;\n}\n\n/**\n * File change summary for a checkpoint\n */\nexport interface FileChangeSummary {\n /** List of changed files */\n files: FileChangeInfo[];\n /** Total lines added */\n totalAdditions: number;\n /** Total lines deleted */\n totalDeletions: number;\n}\n\n/**\n * Change type for a file\n */\nexport type FileChangeType = 'created' | 'modified' | 'deleted';\n\n/**\n * Information about a single file change\n */\nexport interface FileChangeInfo {\n /** File URI (agent://files/{path}) */\n uri: string;\n /** Type of change */\n changeType: FileChangeType;\n /** Lines added */\n additions: number;\n /** Lines deleted */\n deletions: number;\n /** Unified diff format content\n * https://unifiedjs.com/explore/package/unified-diff/\n */\n diff?: string;\n /** File language */\n language?: string;\n /** Creation timestamp */\n createdAt?: number;\n /** Latest update timestamp */\n updatedAt?: number;\n}\n\n// ============================================\n// Auth URL Types\n// ============================================\n\n/**\n * Auth URL notification parameters\n * Sent via extNotification: _codebuddy.ai/authUrl\n *\n * Used when the Agent CLI attempts to open an external browser for OAuth authentication.\n * The client displays this URL so users can manually copy and open it if the browser\n * doesn't open automatically.\n */\nexport interface AuthUrlNotificationParams {\n /** The authentication URL to display */\n authUrl: string;\n /** Optional authentication provider identifier (e.g., 'oauth', 'external') */\n provider?: string;\n}\n\n// ============================================\n// Session Update Meta Types\n// ============================================\n\n/**\n * Mode for session update messages\n * - 'stream': Real-time updates during prompt execution (should be broadcast)\n * - 'history': Historical messages during session/load (should NOT be broadcast)\n */\nexport type SessionUpdateMode = 'stream' | 'history';\n\n/**\n * codebuddy.ai extension metadata for session updates\n */\nexport interface SessionUpdateCodebuddyMeta {\n /** Mode indicating the source of this update */\n mode?: SessionUpdateMode;\n}\n\n/**\n * _meta structure for session update notifications\n */\nexport interface SessionUpdateMeta {\n 'codebuddy.ai'?: SessionUpdateCodebuddyMeta;\n [key: string]: unknown;\n}\n\n// ============================================\n// Delegate Tool Types\n// ============================================\n\n/**\n * Parameter schema for delegate tools using JSON Schema\n * Supports standard JSON Schema draft 2020-12 with validation keywords\n *\n * Example:\n * ```json\n * {\n * \"type\": \"object\",\n * \"properties\": {\n * \"path\": { \"type\": \"string\", \"description\": \"File path\" },\n * \"force\": { \"type\": \"boolean\", \"description\": \"Force operation\" }\n * },\n * \"required\": [\"path\"]\n * }\n * ```\n */\nexport type ParameterSchema = Record<string, unknown>;\n\n/**\n * Delegate tool definition provided by client-side tool providers\n * Represents a tool that can be invoked by the agent\n */\nexport interface DelegateToolDefinition {\n /** Unique tool identifier (e.g., \"github-api\", \"custom-validator\") */\n id: string;\n /** Human-readable tool name */\n name: string;\n /** Tool description for agent understanding */\n description: string;\n /** Parameter schema (JSON Schema) */\n inputSchema: ParameterSchema;\n /** Tool category/group for organization (e.g., \"vcs\", \"validation\", \"custom\") */\n category?: string;\n /** Tool provider identifier (e.g., extension name, plugin id) */\n provider?: string;\n /** Whether this tool requires user approval before execution */\n requiresApproval?: boolean;\n /** Tool availability (e.g., \"enabled\", \"disabled\", \"beta\") */\n availability?: 'enabled' | 'disabled' | 'beta';\n /** Additional metadata */\n metadata?: Record<string, unknown>;\n}\n\n/**\n * Delegate tool execution request (Agent -> Client)\n * Sent via extMethod: _codebuddy.ai/delegateTool\n */\nexport interface DelegateToolRequest {\n /** Session ID */\n sessionId: string;\n /** Tool call ID for tracing */\n toolCallId: string;\n /** Tool ID from the definition */\n toolId: string;\n /** Tool input parameters */\n input: Record<string, unknown>;\n /** Request timeout in milliseconds */\n timeout?: number;\n /** Abort signal URI for cancellation support */\n abortSignal?: string;\n}\n\n/**\n * Delegate tool execution result (Client -> Agent)\n */\nexport interface DelegateToolResult {\n /** Execution outcome */\n status: 'success' | 'error' | 'timeout' | 'cancelled';\n /** Output data (when status is 'success') */\n output?: unknown;\n /** Error message and details (when status is 'error' or other failure) */\n error?: {\n message: string;\n code?: string;\n details?: Record<string, unknown>;\n };\n /** Execution duration in milliseconds */\n duration?: number;\n /** Additional metadata */\n metadata?: Record<string, unknown>;\n}\n\n/**\n * Delegate tools changed notification (Client -> Agent)\n * Sent via extNotification: _codebuddy.ai/delegateToolsChanged\n * Notifies agent when available delegate tools are added, removed, or updated\n */\nexport interface DelegateToolsChangedParams {\n /** Session ID */\n sessionId: string;\n /** Type of change */\n changeType: 'added' | 'removed' | 'updated';\n /** Tool definitions added/removed/updated */\n tools: DelegateToolDefinition[];\n /** Timestamp of the change */\n timestamp: number;\n}\n\n// ============================================\n// UI Control Types\n// ============================================\n\n/**\n * UI Control action types\n */\nexport type UIControlAction = 'click' | 'fill' | 'scroll' | 'focus' | 'select';\n\n/**\n * UI Control target specification\n */\nexport interface UIControlTarget {\n /** CSS selector */\n selector?: string;\n /** Match element by text content */\n text?: string;\n /** Match element by aria-label or label text */\n label?: string;\n /** Match element by ARIA role (button, textbox, etc.) */\n role?: string;\n /** Index of matching element (0-based) */\n index?: number;\n}\n\n/**\n * UI Control request (Agent -> Client)\n * Sent via extMethod: _codebuddy.ai/uiControl\n */\nexport interface UIControlRequest {\n /** Session ID */\n sessionId: string;\n /** Action to perform */\n action: UIControlAction;\n /** Target element specification */\n target: UIControlTarget;\n /** Value for fill action */\n value?: string;\n /** Request timeout in milliseconds */\n timeout?: number;\n}\n\n/**\n * UI Control result (Client -> Agent)\n */\nexport interface UIControlResult {\n /** Whether the action was successful */\n success: boolean;\n /** Error message if failed */\n error?: string;\n /** Whether the target element was found */\n elementFound?: boolean;\n /** Action that was performed */\n action?: UIControlAction;\n /** Timestamp of execution */\n timestamp: number;\n}\n","/**\n * Protocol constants for Streamable HTTP ACP Client\n */\n\nimport type { ClientCapabilities } from './sdk.js';\nimport { ExtensionMethod, KNOWN_EXTENSIONS } from './acp-types.js';\n\n// Re-export extension constants\nexport { ExtensionMethod, KNOWN_EXTENSIONS };\n\n// ============================================\n// Default Timeouts (in milliseconds)\n// ============================================\n\n/**\n * Default timeout for initialize operation\n */\nexport const DEFAULT_INITIALIZE_TIMEOUT = 30_000; // 30 seconds\n\n/**\n * Default timeout for session/new operation (waiting for sessionId via SSE)\n */\nexport const DEFAULT_SESSION_TIMEOUT = 30_000; // 30 seconds\n\n/**\n * Default timeout for prompt operation\n */\nexport const DEFAULT_PROMPT_TIMEOUT = 300_000; // 5 minutes\n\n/**\n * Default timeout for permission requests\n */\nexport const DEFAULT_PERMISSION_TIMEOUT = 300_000; // 5 minutes\n\n/**\n * Default timeout for question requests (ask_followup_question)\n */\nexport const DEFAULT_QUESTION_TIMEOUT = 300_000; // 5 minutes\n\n/**\n * Default timeout for tool input requests\n * @deprecated Use DEFAULT_QUESTION_TIMEOUT instead\n */\nexport const DEFAULT_TOOL_INPUT_TIMEOUT = DEFAULT_QUESTION_TIMEOUT;\n\n// ============================================\n// Default Reconnect Configuration\n// ============================================\n\n/**\n * Default reconnect options\n */\nexport const DEFAULT_RECONNECT_OPTIONS = {\n enabled: true,\n initialDelay: 1000, // 1 second\n maxDelay: 30_000, // 30 seconds\n maxRetries: Infinity\n} as const;\n\n// ============================================\n// Client Capabilities\n// ============================================\n\n/**\n * Default client capabilities for cloud-based clients\n * Cloud clients typically have no direct file system access\n */\nexport const CLOUD_CLIENT_CAPABILITIES: ClientCapabilities = {\n fs: {\n readTextFile: false,\n writeTextFile: false\n }\n} as const;\n\n/**\n * Default client capabilities for local (Node.js) clients\n * Local clients have file system access\n */\nexport const LOCAL_CLIENT_CAPABILITIES: ClientCapabilities = {\n fs: {\n readTextFile: true,\n writeTextFile: true\n }\n} as const;\n","/**\n * Custom error classes for Streamable HTTP ACP Client\n */\n\n/**\n * Base error class for all ACP client errors\n */\nexport class ACPClientError extends Error {\n public readonly code: string;\n\n constructor(message: string, code: string, cause?: Error) {\n super(message);\n this.name = 'ACPClientError';\n this.code = code;\n (this as Error & { cause?: Error }).cause = cause;\n\n // Maintain proper stack trace in V8 environments\n if (Error.captureStackTrace) {\n Error.captureStackTrace(this, this.constructor);\n }\n }\n}\n\n/**\n * Error thrown when connection fails\n */\nexport class ConnectionError extends ACPClientError {\n constructor(message: string, cause?: Error) {\n super(message, 'CONNECTION_ERROR', cause);\n this.name = 'ConnectionError';\n }\n}\n\n/**\n * Error thrown when initialization fails\n */\nexport class InitializationError extends ACPClientError {\n constructor(message: string, cause?: Error) {\n super(message, 'INITIALIZATION_ERROR', cause);\n this.name = 'InitializationError';\n }\n}\n\n/**\n * Error thrown for session-related failures\n */\nexport class SessionError extends ACPClientError {\n public readonly sessionId?: string;\n\n /**\n * Agent ID associated with the failed session operation.\n * Available when session/new fails after agent creation + connection established.\n * Can be used with `retryNewSession()` to recover from transient failures.\n *\n * @experimental This field is subject to change\n */\n public readonly agentId?: string;\n\n constructor(message: string, sessionId?: string, cause?: Error);\n constructor(message: string, sessionId?: string, agentId?: string, cause?: Error);\n constructor(message: string, sessionId?: string, agentIdOrCause?: string | Error, cause?: Error) {\n // Overload resolution: distinguish (msg, sid, cause) from (msg, sid, agentId, cause)\n if (agentIdOrCause instanceof Error) {\n super(message, 'SESSION_ERROR', agentIdOrCause);\n this.agentId = undefined;\n } else {\n super(message, 'SESSION_ERROR', cause);\n this.agentId = agentIdOrCause;\n }\n this.name = 'SessionError';\n this.sessionId = sessionId;\n }\n}\n\n/**\n * Error thrown when prompt operation fails\n */\nexport class PromptError extends ACPClientError {\n public readonly sessionId?: string;\n\n constructor(message: string, sessionId?: string, cause?: Error) {\n super(message, 'PROMPT_ERROR', cause);\n this.name = 'PromptError';\n this.sessionId = sessionId;\n }\n}\n\n/**\n * Error thrown for permission-related failures\n */\nexport class PermissionError extends ACPClientError {\n public readonly requestId?: string;\n\n constructor(message: string, requestId?: string, cause?: Error) {\n super(message, 'PERMISSION_ERROR', cause);\n this.name = 'PermissionError';\n this.requestId = requestId;\n }\n}\n\n/**\n * Error thrown when an operation times out\n */\nexport class TimeoutError extends ACPClientError {\n public readonly operation: string;\n public readonly timeoutMs: number;\n\n constructor(operation: string, timeoutMs: number) {\n super(`Operation '${operation}' timed out after ${timeoutMs}ms`, 'TIMEOUT_ERROR');\n this.name = 'TimeoutError';\n this.operation = operation;\n this.timeoutMs = timeoutMs;\n }\n}\n\n/**\n * Error thrown when client is in invalid state for an operation\n */\nexport class InvalidStateError extends ACPClientError {\n public readonly currentState: string;\n public readonly expectedStates: string[];\n\n constructor(operation: string, currentState: string, expectedStates: string[]) {\n super(\n `Cannot perform '${operation}' in state '${currentState}'. Expected: ${expectedStates.join(' or ')}`,\n 'INVALID_STATE_ERROR'\n );\n this.name = 'InvalidStateError';\n this.currentState = currentState;\n this.expectedStates = expectedStates;\n }\n}\n","/**\n * Type-safe event emitter for Streamable HTTP ACP Client\n * Platform-agnostic implementation (no browser dependencies)\n */\n\n/**\n * Event listener function type\n */\nexport type EventListener<T> = (data: T) => void | Promise<void>;\n\n/**\n * Type-safe event emitter implementation\n */\nexport class EventEmitter<TEvents extends Record<string, unknown>> {\n private listeners: Map<keyof TEvents, Set<EventListener<unknown>>> = new Map();\n private onceListeners: Map<keyof TEvents, Set<EventListener<unknown>>> = new Map();\n\n /**\n * Add an event listener\n */\n on<K extends keyof TEvents>(event: K, listener: EventListener<TEvents[K]>): this {\n if (!this.listeners.has(event)) {\n this.listeners.set(event, new Set());\n }\n this.listeners.get(event)!.add(listener as EventListener<unknown>);\n return this;\n }\n\n /**\n * Remove an event listener\n */\n off<K extends keyof TEvents>(event: K, listener: EventListener<TEvents[K]>): this {\n const eventListeners = this.listeners.get(event);\n if (eventListeners) {\n eventListeners.delete(listener as EventListener<unknown>);\n }\n\n const onceEventListeners = this.onceListeners.get(event);\n if (onceEventListeners) {\n onceEventListeners.delete(listener as EventListener<unknown>);\n }\n\n return this;\n }\n\n /**\n * Add a one-time event listener\n */\n once<K extends keyof TEvents>(event: K, listener: EventListener<TEvents[K]>): this {\n if (!this.onceListeners.has(event)) {\n this.onceListeners.set(event, new Set());\n }\n this.onceListeners.get(event)!.add(listener as EventListener<unknown>);\n return this;\n }\n\n /**\n * Emit an event to all registered listeners\n * Returns true if any listeners were invoked\n */\n emit<K extends keyof TEvents>(event: K, data: TEvents[K]): boolean {\n const regularListeners = this.listeners.get(event);\n const onceEventListeners = this.onceListeners.get(event);\n\n let hasListeners = false;\n\n // Call regular listeners\n if (regularListeners && regularListeners.size > 0) {\n hasListeners = true;\n for (const listener of regularListeners) {\n try {\n const result = listener(data);\n // Handle async listeners\n if (result instanceof Promise) {\n result.catch(err => {\n console.error(`Error in async event listener for '${String(event)}':`, err);\n });\n }\n } catch (err) {\n console.error(`Error in event listener for '${String(event)}':`, err);\n }\n }\n }\n\n // Call once listeners and remove them\n if (onceEventListeners && onceEventListeners.size > 0) {\n hasListeners = true;\n const listenersToCall = Array.from(onceEventListeners);\n this.onceListeners.delete(event);\n\n for (const listener of listenersToCall) {\n try {\n const result = listener(data);\n if (result instanceof Promise) {\n result.catch(err => {\n console.error(\n `Error in async once event listener for '${String(event)}':`,\n err\n );\n });\n }\n } catch (err) {\n console.error(`Error in once event listener for '${String(event)}':`, err);\n }\n }\n }\n\n return hasListeners;\n }\n\n /**\n * Remove all listeners for an event, or all listeners if no event specified\n */\n removeAllListeners<K extends keyof TEvents>(event?: K): this {\n if (event !== undefined) {\n this.listeners.delete(event);\n this.onceListeners.delete(event);\n } else {\n this.listeners.clear();\n this.onceListeners.clear();\n }\n return this;\n }\n\n /**\n * Get the number of listeners for an event\n */\n listenerCount<K extends keyof TEvents>(event: K): number {\n const regular = this.listeners.get(event)?.size ?? 0;\n const once = this.onceListeners.get(event)?.size ?? 0;\n return regular + once;\n }\n\n /**\n * Get all event names that have listeners\n */\n eventNames(): Array<keyof TEvents> {\n const names = new Set<keyof TEvents>();\n for (const event of this.listeners.keys()) {\n names.add(event);\n }\n for (const event of this.onceListeners.keys()) {\n names.add(event);\n }\n return Array.from(names);\n }\n}\n","/**\n * Extension Method Handler for Streamable HTTP ACP Client\n * Routes and handles custom extension notifications\n */\n\nimport { ExtensionMethod, KNOWN_EXTENSIONS } from './constants.js';\nimport type { Logger } from './types.js';\n\n/**\n * Configuration for ExtensionManager\n */\nexport interface ExtensionManagerConfig {\n /** Logger instance */\n logger?: Logger;\n}\n\n/**\n * Handler for extension notifications\n */\nexport type ExtensionNotificationHandler = (\n method: string,\n params: Record<string, unknown>\n) => void | Promise<void>;\n\n/**\n * Manages extension methods and notifications\n */\nexport class ExtensionManager {\n private config: ExtensionManagerConfig;\n private handlers = new Map<string, ExtensionNotificationHandler>();\n private fallbackHandler?: ExtensionNotificationHandler;\n\n constructor(config: ExtensionManagerConfig = {}) {\n this.config = config;\n }\n\n /**\n * Register a handler for a specific extension method\n */\n registerHandler(method: string, handler: ExtensionNotificationHandler): () => void {\n this.handlers.set(method, handler);\n return () => {\n this.handlers.delete(method);\n };\n }\n\n /**\n * Set a fallback handler for unknown extensions\n */\n setFallbackHandler(handler: ExtensionNotificationHandler): void {\n this.fallbackHandler = handler;\n }\n\n /**\n * Handle an extension notification\n */\n async handleNotification(method: string, params: Record<string, unknown>): Promise<void> {\n this.config.logger?.debug(`Extension notification: ${method}`);\n\n // Try specific handler first\n const handler = this.handlers.get(method);\n if (handler) {\n await handler(method, params);\n return;\n }\n\n // Try fallback handler\n if (this.fallbackHandler) {\n await this.fallbackHandler(method, params);\n return;\n }\n\n // Log unknown extension\n if (!this.isKnownExtension(method)) {\n this.config.logger?.warn(`Unknown extension notification: ${method}`);\n }\n }\n\n /**\n * Check if a method is a known extension\n */\n isKnownExtension(method: string): boolean {\n return KNOWN_EXTENSIONS.includes(method as typeof KNOWN_EXTENSIONS[number]);\n }\n\n /**\n * Check if method is the artifact extension\n */\n isArtifactExtension(method: string): boolean {\n return method === ExtensionMethod.ARTIFACT;\n }\n\n /**\n * Clear all handlers\n */\n clear(): void {\n this.handlers.clear();\n this.fallbackHandler = undefined;\n }\n}\n","/**\n * Permission Manager for Streamable HTTP ACP Client\n * Handles permission requests with timeout support\n */\n\nimport type { RequestPermissionRequest, RequestPermissionResponse } from '@agentclientprotocol/sdk' with { 'resolution-mode': 'import' };\n\nimport { DEFAULT_PERMISSION_TIMEOUT } from './constants.js';\nimport { TimeoutError } from './errors.js';\nimport type { Logger, PermissionHandler } from './types.js';\n\n/**\n * Pending permission request state\n */\ninterface PendingPermission {\n params: RequestPermissionRequest;\n resolve: (response: RequestPermissionResponse) => void;\n reject: (error: Error) => void;\n timeoutId?: ReturnType<typeof setTimeout>;\n createdAt: number;\n}\n\n/**\n * Configuration for PermissionManager\n */\nexport interface PermissionManagerConfig {\n /** Default timeout for permission requests (ms) */\n timeout?: number;\n /** Auto-reject permissions on timeout */\n autoRejectOnTimeout?: boolean;\n /** Auto-approve all permissions (for testing) */\n autoApprove?: boolean;\n /** Custom permission handler */\n handler?: PermissionHandler;\n /** Logger instance */\n logger?: Logger;\n}\n\n/**\n * Event callbacks for permission events\n */\nexport interface PermissionEventCallbacks {\n onRequest?: (requestId: string, params: RequestPermissionRequest) => void;\n onResolved?: (requestId: string, optionId: string) => void;\n onRejected?: (requestId: string, reason?: string) => void;\n onTimeout?: (requestId: string) => void;\n}\n\n/**\n * Manages permission requests from the agent\n */\nexport class PermissionManager {\n private pending = new Map<string, PendingPermission>();\n private config: PermissionManagerConfig;\n private callbacks: PermissionEventCallbacks = {};\n\n constructor(config: PermissionManagerConfig = {}) {\n this.config = {\n timeout: DEFAULT_PERMISSION_TIMEOUT,\n autoRejectOnTimeout: true,\n autoApprove: false,\n ...config\n };\n }\n\n /**\n * Set event callbacks\n */\n setCallbacks(callbacks: PermissionEventCallbacks): void {\n this.callbacks = callbacks;\n }\n\n /**\n * Handle a permission request from the agent\n */\n async handleRequest(params: RequestPermissionRequest): Promise<RequestPermissionResponse> {\n const requestId = params.toolCall.toolCallId;\n\n this.config.logger?.debug(`Permission request received: ${requestId}`);\n\n // Auto-approve mode\n if (this.config.autoApprove) {\n const firstOption = params.options[0];\n this.config.logger?.debug(`Auto-approving permission: ${requestId}`);\n return {\n outcome: {\n outcome: 'selected',\n optionId: firstOption?.optionId ?? 'approve'\n }\n };\n }\n\n // Custom handler\n if (this.config.handler) {\n return this.config.handler(params);\n }\n\n // Create pending permission\n return new Promise<RequestPermissionResponse>((resolve, reject) => {\n const pending: PendingPermission = {\n params,\n resolve,\n reject,\n createdAt: Date.now()\n };\n\n // Set up timeout\n if (this.config.timeout && this.config.timeout > 0) {\n pending.timeoutId = setTimeout(() => {\n this.handleTimeout(requestId);\n }, this.config.timeout);\n }\n\n this.pending.set(requestId, pending);\n\n // Notify callback\n this.callbacks.onRequest?.(requestId, params);\n });\n }\n\n /**\n * Handle timeout for a permission request\n */\n private handleTimeout(requestId: string): void {\n const pending = this.pending.get(requestId);\n if (!pending) {return;}\n\n this.config.logger?.warn(`Permission request timed out: ${requestId}`);\n this.callbacks.onTimeout?.(requestId);\n\n if (this.config.autoRejectOnTimeout) {\n pending.resolve({\n outcome: { outcome: 'cancelled' }\n });\n } else {\n pending.reject(new TimeoutError('permission', this.config.timeout ?? DEFAULT_PERMISSION_TIMEOUT));\n }\n\n this.pending.delete(requestId);\n }\n\n /**\n * Resolve a permission request with a selected option\n * Returns true if the permission was found and resolved\n */\n resolve(requestId: string, optionId: string): boolean {\n const pending = this.pending.get(requestId);\n if (!pending) {\n this.config.logger?.warn(`Permission request not found: ${requestId}`);\n return false;\n }\n\n // Clear timeout\n if (pending.timeoutId) {\n clearTimeout(pending.timeoutId);\n }\n\n this.config.logger?.debug(`Permission resolved: ${requestId} -> ${optionId}`);\n\n pending.resolve({\n outcome: { outcome: 'selected', optionId }\n });\n\n this.pending.delete(requestId);\n this.callbacks.onResolved?.(requestId, optionId);\n\n return true;\n }\n\n /**\n * Reject (cancel) a permission request\n * Returns true if the permission was found and rejected\n */\n reject(requestId: string, reason?: string): boolean {\n const pending = this.pending.get(requestId);\n if (!pending) {\n this.config.logger?.warn(`Permission request not found: ${requestId}`);\n return false;\n }\n\n // Clear timeout\n if (pending.timeoutId) {\n clearTimeout(pending.timeoutId);\n }\n\n this.config.logger?.debug(`Permission rejected: ${requestId}${reason ? ` - ${reason}` : ''}`);\n\n pending.resolve({\n outcome: { outcome: 'cancelled' }\n });\n\n this.pending.delete(requestId);\n this.callbacks.onRejected?.(requestId, reason);\n\n return true;\n }\n\n /**\n * Get all pending permissions\n */\n getPending(): Map<string, { params: RequestPermissionRequest; createdAt: number }> {\n const result = new Map<string, { params: RequestPermissionRequest; createdAt: number }>();\n for (const [id, pending] of this.pending) {\n result.set(id, {\n params: pending.params,\n createdAt: pending.createdAt\n });\n }\n return result;\n }\n\n /**\n * Get a specific pending permission\n */\n getPendingById(requestId: string): { params: RequestPermissionRequest; createdAt: number } | undefined {\n const pending = this.pending.get(requestId);\n if (!pending) {return undefined;}\n return {\n params: pending.params,\n createdAt: pending.createdAt\n };\n }\n\n /**\n * Check if there are any pending permissions\n */\n hasPending(): boolean {\n return this.pending.size > 0;\n }\n\n /**\n * Get the count of pending permissions\n */\n get pendingCount(): number {\n return this.pending.size;\n }\n\n /**\n * Clear all pending permissions (reject all)\n */\n clear(): void {\n for (const [requestId, pending] of this.pending) {\n if (pending.timeoutId) {\n clearTimeout(pending.timeoutId);\n }\n pending.resolve({\n outcome: { outcome: 'cancelled' }\n });\n this.callbacks.onRejected?.(requestId, 'cleared');\n }\n this.pending.clear();\n this.config.logger?.debug('Cleared all pending permissions');\n }\n\n /**\n * Update configuration\n */\n updateConfig(config: Partial<PermissionManagerConfig>): void {\n this.config = { ...this.config, ...config };\n }\n}\n","/**\n * Question Manager for Streamable HTTP ACP Client\n * Handles ask_followup_question requests with timeout support\n */\n\nimport type {\n QuestionRequest,\n QuestionResponse,\n} from './acp-types.js';\nimport { DEFAULT_QUESTION_TIMEOUT } from './constants.js';\nimport { TimeoutError } from './errors.js';\nimport type { Logger } from './types.js';\n\n// Re-export for convenience\nexport type { QuestionRequest, QuestionResponse };\n\n/**\n * Pending question state\n */\ninterface PendingQuestion {\n request: QuestionRequest;\n resolve: (response: QuestionResponse) => void;\n reject: (error: Error) => void;\n timeoutId?: ReturnType<typeof setTimeout>;\n createdAt: number;\n}\n\n/**\n * Configuration for QuestionManager\n */\nexport interface QuestionManagerConfig {\n /** Default timeout for question requests (ms) */\n timeout?: number;\n /** Auto-cancel requests on timeout */\n autoCancelOnTimeout?: boolean;\n /** Logger instance */\n logger?: Logger;\n}\n\n/**\n * User's answers to questions\n */\nexport type QuestionAnswers = Record<string, string | string[]>;\n\n/**\n * Event callbacks for question events\n */\nexport interface QuestionEventCallbacks {\n onRequest?: (toolCallId: string, request: QuestionRequest) => void;\n onAnswered?: (toolCallId: string, answers: QuestionAnswers) => void;\n onCancelled?: (toolCallId: string, reason?: string) => void;\n onTimeout?: (toolCallId: string) => void;\n}\n\n/**\n * Manages question requests from the agent (ask_followup_question tool)\n */\nexport class QuestionManager {\n private pending = new Map<string, PendingQuestion>();\n private config: QuestionManagerConfig;\n private callbacks: QuestionEventCallbacks = {};\n\n constructor(config: QuestionManagerConfig = {}) {\n this.config = {\n timeout: DEFAULT_QUESTION_TIMEOUT,\n autoCancelOnTimeout: true,\n ...config\n };\n }\n\n /**\n * Set event callbacks\n */\n setCallbacks(callbacks: QuestionEventCallbacks): void {\n this.callbacks = callbacks;\n }\n\n /**\n * Handle a question request from the agent\n * Called when receiving _codebuddy.ai/question extMethod\n */\n async handleRequest(request: QuestionRequest): Promise<QuestionResponse> {\n const toolCallId = request.toolCallId;\n\n this.config.logger?.debug(`Question request received: ${toolCallId}`);\n\n return new Promise<QuestionResponse>((resolve, reject) => {\n const pending: PendingQuestion = {\n request,\n resolve,\n reject,\n createdAt: Date.now()\n };\n\n // Set up timeout\n const timeout = request.timeout ?? this.config.timeout;\n if (timeout && timeout > 0) {\n pending.timeoutId = setTimeout(() => {\n this.handleTimeout(toolCallId);\n }, timeout);\n }\n\n this.pending.set(toolCallId, pending);\n\n // Notify callback\n this.callbacks.onRequest?.(toolCallId, request);\n });\n }\n\n /**\n * Handle timeout for a question request\n */\n private handleTimeout(toolCallId: string): void {\n const pending = this.pending.get(toolCallId);\n if (!pending) {return;}\n\n this.config.logger?.warn(`Question request timed out: ${toolCallId}`);\n this.callbacks.onTimeout?.(toolCallId);\n\n if (this.config.autoCancelOnTimeout) {\n pending.resolve({\n outcome: 'cancelled',\n reason: 'timeout'\n });\n } else {\n pending.reject(new TimeoutError('question', this.config.timeout ?? DEFAULT_QUESTION_TIMEOUT));\n }\n\n this.pending.delete(toolCallId);\n }\n\n /**\n * Answer a question request with user's selections\n * Returns true if the request was found and answered\n */\n answer(toolCallId: string, answers: QuestionAnswers): boolean {\n const pending = this.pending.get(toolCallId);\n if (!pending) {\n this.config.logger?.warn(`Question request not found: ${toolCallId}`);\n return false;\n }\n\n // Clear timeout\n if (pending.timeoutId) {\n clearTimeout(pending.timeoutId);\n }\n\n this.config.logger?.debug(`Question answered: ${toolCallId}`);\n\n pending.resolve({\n outcome: 'submitted',\n answers\n });\n\n this.pending.delete(toolCallId);\n this.callbacks.onAnswered?.(toolCallId, answers);\n\n return true;\n }\n\n /**\n * Cancel a question request\n * Returns true if the request was found and cancelled\n */\n cancel(toolCallId: string, reason?: string): boolean {\n const pending = this.pending.get(toolCallId);\n if (!pending) {\n this.config.logger?.warn(`Question request not found: ${toolCallId}`);\n return false;\n }\n\n // Clear timeout\n if (pending.timeoutId) {\n clearTimeout(pending.timeoutId);\n }\n\n this.config.logger?.debug(`Question cancelled: ${toolCallId}${reason ? ` - ${reason}` : ''}`);\n\n pending.resolve({\n outcome: 'cancelled',\n reason\n });\n\n this.pending.delete(toolCallId);\n this.callbacks.onCancelled?.(toolCallId, reason);\n\n return true;\n }\n\n /**\n * Get all pending question requests\n */\n getPending(): Map<string, { request: QuestionRequest; createdAt: number }> {\n const result = new Map<string, { request: QuestionRequest; createdAt: number }>();\n for (const [id, pending] of this.pending) {\n result.set(id, {\n request: pending.request,\n createdAt: pending.createdAt\n });\n }\n return result;\n }\n\n /**\n * Get a specific pending question request\n */\n getPendingById(toolCallId: string): { request: QuestionRequest; createdAt: number } | undefined {\n const pending = this.pending.get(toolCallId);\n if (!pending) {return undefined;}\n return {\n request: pending.request,\n createdAt: pending.createdAt\n };\n }\n\n /**\n * Check if there are any pending question requests\n */\n hasPending(): boolean {\n return this.pending.size > 0;\n }\n\n /**\n * Get the count of pending question requests\n */\n get pendingCount(): number {\n return this.pending.size;\n }\n\n /**\n * Clear all pending question requests (cancel all)\n */\n clear(): void {\n for (const [toolCallId, pending] of this.pending) {\n if (pending.timeoutId) {\n clearTimeout(pending.timeoutId);\n }\n pending.resolve({\n outcome: 'cancelled',\n reason: 'cleared'\n });\n this.callbacks.onCancelled?.(toolCallId, 'cleared');\n }\n this.pending.clear();\n this.config.logger?.debug('Cleared all pending question requests');\n }\n\n /**\n * Update configuration\n */\n updateConfig(config: Partial<QuestionManagerConfig>): void {\n this.config = { ...this.config, ...config };\n }\n}\n","/**\n * Streamable HTTP ACP Client\n * Production-grade client for connecting to cloud-hosted ACP agents\n */\n\nimport {\n type CancelNotification,\n type Client,\n type ContentBlock,\n type InitializeRequest,\n type InitializeResponse,\n loadAcpSdk,\n type LoadSessionRequest,\n type LoadSessionResponse,\n type NewSessionRequest,\n type NewSessionResponse,\n type PromptResponse,\n PROTOCOL_VERSION,\n type RequestPermissionRequest,\n type RequestPermissionResponse,\n type SessionNotification,\n type SetSessionModelRequest,\n type SetSessionModelResponse,\n type SetSessionModeRequest,\n type SetSessionModeResponse,\n} from './sdk.js';\nimport { streamableHttp, type StreamableHttpTransport } from '../transport.js';\nimport type {\n ArtifactNotificationParams,\n CheckpointNotificationParams\n} from './acp-types.js';\nimport { ArtifactManager } from './artifacts.js';\nimport {\n CLOUD_CLIENT_CAPABILITIES,\n DEFAULT_INITIALIZE_TIMEOUT,\n DEFAULT_SESSION_TIMEOUT,\n ExtensionMethod\n} from './constants.js';\nimport {\n ConnectionError,\n InitializationError,\n InvalidStateError,\n SessionError\n} from './errors.js';\nimport { EventEmitter } from './events.js';\nimport { ExtensionManager } from './extensions.js';\nimport { PermissionManager } from './permissions.js';\nimport { type QuestionAnswers, QuestionManager, type QuestionRequest } from './questions.js';\nimport type {\n ClientEvents,\n ClientState,\n PromptOptions,\n StreamableHttpClientOptions,\n} from './types.js';\n\n/**\n * Production-grade Streamable HTTP ACP Client\n *\n * Features:\n * - Full ACP protocol support (initialize, session, prompt, cancel)\n * - Artifact notification handling\n * - Permission handling with timeout support\n * - Extension method support\n * - Type-safe event system\n * - Configurable logging\n */\nexport class StreamableHttpClient {\n private connection!: {\n initialize(params: InitializeRequest): Promise<InitializeResponse>;\n newSession(params: NewSessionRequest): Promise<NewSessionResponse>;\n loadSession(params: LoadSessionRequest): Promise<LoadSessionResponse>;\n setSessionMode?(params: SetSessionModeRequest): Promise<SetSessionModeResponse>;\n unstable_setSessionModel?(params: SetSessionModelRequest): Promise<SetSessionModelResponse>;\n prompt(params: {\n sessionId: string;\n prompt: ContentBlock[];\n _meta?: Record<string, unknown>;\n }): Promise<PromptResponse>;\n cancel(params: CancelNotification): Promise<void>;\n extMethod?(method: string, params: Record<string, unknown>): Promise<Record<string, unknown>>;\n extNotification?(method: string, params: Record<string, unknown>): Promise<void>;\n };\n private transport?: StreamableHttpTransport;\n private options: StreamableHttpClientOptions;\n private state: ClientState = 'disconnected';\n private initializeResponse?: InitializeResponse;\n\n // Managers\n private artifactManager: ArtifactManager;\n private permissionManager: PermissionManager;\n private questionManager: QuestionManager;\n private extensionManager: ExtensionManager;\n\n // Event emitter\n private emitter = new EventEmitter<ClientEvents>();\n\n constructor(options: StreamableHttpClientOptions) {\n this.options = options;\n\n // Initialize artifact manager\n this.artifactManager = new ArtifactManager({\n logger: options.logger\n });\n\n // Initialize permission manager\n this.permissionManager = new PermissionManager({\n timeout: options.permissionTimeout,\n autoRejectOnTimeout: options.permissionAutoRejectOnTimeout ?? true,\n autoApprove: options.autoApprove,\n handler: options.requestPermissionHandler,\n logger: options.logger\n });\n\n // Set up permission event callbacks\n this.permissionManager.setCallbacks({\n onRequest: (requestId, params) => {\n this.emitter.emit('permissionRequest', { requestId, params });\n },\n onResolved: (requestId, optionId) => {\n this.emitter.emit('permissionResolved', { requestId, optionId });\n },\n onRejected: (requestId, reason) => {\n this.emitter.emit('permissionRejected', { requestId, reason });\n },\n onTimeout: requestId => {\n this.emitter.emit('permissionTimeout', { requestId });\n }\n });\n\n // Initialize question manager\n this.questionManager = new QuestionManager({\n timeout: options.questionTimeout,\n autoCancelOnTimeout: options.questionAutoCancelOnTimeout ?? true,\n logger: options.logger\n });\n\n // Set up question event callbacks\n this.questionManager.setCallbacks({\n onRequest: (toolCallId: string, request: QuestionRequest) => {\n this.emitter.emit('questionRequest', { toolCallId, request });\n options.onQuestionRequest?.(toolCallId, request);\n },\n onAnswered: (toolCallId: string, answers: QuestionAnswers) => {\n this.emitter.emit('questionAnswered', { toolCallId, answers });\n },\n onCancelled: (toolCallId: string, reason?: string) => {\n this.emitter.emit('questionCancelled', { toolCallId, reason });\n },\n onTimeout: (toolCallId: string) => {\n this.emitter.emit('questionTimeout', { toolCallId });\n }\n });\n\n // Initialize extension manager\n this.extensionManager = new ExtensionManager({\n logger: options.logger\n });\n }\n\n // ============================================\n // State Management\n // ============================================\n\n /**\n * Get current client state\n */\n get currentState(): ClientState {\n return this.state;\n }\n\n /**\n * Check if client is initialized\n */\n get isInitialized(): boolean {\n return this.state === 'initialized';\n }\n\n /**\n * Check if client is connected (but maybe not initialized)\n */\n get isConnected(): boolean {\n return this.state === 'connected' || this.state === 'initialized';\n }\n\n /**\n * Get agent capabilities from initialization response\n */\n get agentCapabilities() {\n return this.initializeResponse?.agentCapabilities;\n }\n\n /**\n * Get full initialization response\n */\n get initializeResult() {\n return this.initializeResponse;\n }\n\n /**\n * Get current transport connection ID\n */\n get connectionId(): string | undefined {\n return this.transport?.connectionId;\n }\n\n private setState(newState: ClientState): void {\n const previous = this.state;\n this.state = newState;\n\n this.options.logger?.debug(`State change: ${previous} -> ${newState}`);\n this.emitter.emit('stateChange', { previous, current: newState });\n\n // Emit specific state events\n switch (newState) {\n case 'connecting':\n this.emitter.emit('connecting', undefined);\n break;\n case 'connected':\n this.emitter.emit('connected', undefined);\n break;\n case 'disconnected':\n this.emitter.emit('disconnected', undefined);\n break;\n case 'error':\n // Error event is emitted separately with the actual error\n break;\n }\n }\n\n // ============================================\n // Connection Management\n // ============================================\n\n /**\n * Connect and initialize the client\n */\n async connect(): Promise<InitializeResponse> {\n if (this.state !== 'disconnected') {\n await this.disconnect();\n }\n if (this.state === 'initialized') {\n return this.initializeResponse!;\n }\n\n if (this.state === 'connecting') {\n throw new ConnectionError('Connection already in progress');\n }\n\n this.setState('connecting');\n\n try {\n // Create transport\n this.transport = streamableHttp({\n endpoint: this.options.endpoint,\n authToken: this.options.authToken,\n headers: this.options.headers,\n reconnect: this.options.reconnect,\n fetch: this.options.fetch,\n heartbeatTimeout: this.options.heartbeatTimeout,\n postTimeout: this.options.postTimeout,\n connectionTimeout: this.options.connectionTimeout,\n onConnect: connectionId => {\n this.options.logger?.debug(`Transport connected: ${connectionId}`);\n },\n onDisconnect: connectionId => {\n this.options.logger?.debug(`Transport disconnected: ${connectionId}`);\n },\n onError: error => {\n this.options.logger?.error('Transport error:', error);\n this.emitter.emit('error', error);\n },\n });\n\n // Create connection\n const { ClientSideConnection } = await loadAcpSdk();\n this.connection = new ClientSideConnection(\n () => this.createClientHandler(),\n this.transport as unknown as ConstructorParameters<typeof ClientSideConnection>[1]\n );\n\n this.setState('connected');\n\n // Initialize protocol\n // Merge client capabilities with provider defaults (provider takes priority)\n const timeout = this.options.initializeTimeout ?? DEFAULT_INITIALIZE_TIMEOUT;\n const mergedCapabilities = {\n ...this.options.clientCapabilities,\n ...CLOUD_CLIENT_CAPABILITIES,\n _meta: {\n ...this.options.clientCapabilities?._meta,\n ...CLOUD_CLIENT_CAPABILITIES._meta\n }\n };\n const initPromise = this.connection.initialize({\n protocolVersion: PROTOCOL_VERSION,\n clientCapabilities: mergedCapabilities\n });\n\n // Apply timeout\n const timeoutPromise = new Promise<never>((_, reject) => {\n setTimeout(() => {\n reject(new InitializationError(`Initialize timed out after ${timeout}ms`));\n }, timeout);\n });\n\n const initializeResponse = await Promise.race([initPromise, timeoutPromise]) as InitializeResponse;\n this.initializeResponse = initializeResponse;\n this.setState('initialized');\n\n this.options.logger?.info('Client initialized successfully');\n\n return initializeResponse;\n } catch (err) {\n this.setState('error');\n const error = err instanceof Error ? err : new Error(String(err));\n this.emitter.emit('error', error);\n\n if (err instanceof InitializationError || err instanceof ConnectionError) {\n throw err;\n }\n throw new ConnectionError('Failed to connect', error);\n }\n }\n\n /**\n * Disconnect the client gracefully\n * Sends DELETE request to server before closing local resources\n */\n async disconnect(): Promise<void> {\n if (this.state === 'disconnected') {\n return;\n }\n\n this.options.logger?.info('Disconnecting client');\n\n // Close transport gracefully (sends DELETE to server)\n if (this.transport) {\n try {\n await this.transport.close();\n } catch (err) {\n this.options.logger?.warn('Error closing transport:', err);\n }\n this.transport = undefined;\n }\n\n // Clear pending permissions\n this.permissionManager.clear();\n\n // Clear pending question requests\n this.questionManager.clear();\n\n // Clear artifacts\n this.artifactManager.clear();\n\n // Reset state\n this.initializeResponse = undefined;\n this.setState('disconnected');\n }\n\n /**\n * Create the client handler for the connection\n */\n private createClientHandler(): Client {\n return {\n sessionUpdate: async (params: SessionNotification) => {\n await this.handleSessionUpdate(params);\n },\n requestPermission: async (params: RequestPermissionRequest) => this.handleRequestPermission(params),\n extNotification: async (method: string, params: Record<string, unknown>) => {\n await this.handleExtNotification(method, params);\n },\n extMethod: async (method: string, params: Record<string, unknown>): Promise<Record<string, unknown>> =>\n this.handleExtMethod(method, params as unknown as QuestionRequest)\n };\n }\n\n // ============================================\n // Session Management\n // ============================================\n\n /**\n * Create a new session\n *\n * Retries on transient network errors (e.g., proxy connection reset)\n * since session/new is idempotent and safe to retry.\n *\n * A timeout (`options.sessionTimeout`, default 30 s) guards against the\n * SSE response never arriving — the POST returns 202 immediately and the\n * sessionId comes back via GET SSE, which can hang indefinitely.\n * On timeout a `SessionError` is thrown.\n */\n async createSession(cwd: string): Promise<NewSessionResponse> {\n this.ensureInitialized('createSession');\n\n const maxRetries = 2;\n const timeout = this.options.sessionTimeout ?? DEFAULT_SESSION_TIMEOUT;\n let lastError: Error | undefined;\n\n for (let attempt = 0; attempt <= maxRetries; attempt++) {\n try {\n const sessionPromise = this.connection.newSession({\n cwd,\n mcpServers: []\n });\n\n // Apply timeout - session/new response comes via GET SSE,\n // which can hang indefinitely if the server never responds\n let response: NewSessionResponse;\n if (timeout > 0) {\n const timeoutPromise = new Promise<never>((_, reject) => {\n setTimeout(() => {\n reject(new SessionError(`session/new timed out after ${timeout}ms`));\n }, timeout);\n });\n response = await Promise.race([sessionPromise, timeoutPromise]);\n } else {\n response = await sessionPromise;\n }\n\n this.options.logger?.info(`Session created: ${response.sessionId}`);\n return response;\n } catch (err) {\n lastError = err instanceof Error ? err : new Error(String(err));\n\n if (attempt < maxRetries && isRetryableNetworkError(err)) {\n const delay = 500 * Math.pow(2, attempt); // 500ms, 1000ms\n this.options.logger?.warn(\n `session/new network error, retrying in ${delay}ms ` +\n `(attempt ${attempt + 1}/${maxRetries}): ${lastError.message}`\n );\n await new Promise(resolve => setTimeout(resolve, delay));\n continue;\n }\n\n throw new SessionError(\n `Failed to create session: ${lastError.message}`,\n undefined,\n lastError\n );\n }\n }\n\n // Safety net\n throw new SessionError(\n `Failed to create session: ${lastError?.message}`,\n undefined,\n lastError\n );\n }\n\n /**\n * Load an existing session\n * Requires agent to support loadSession capability\n */\n async loadSession(sessionId: string, cwd: string): Promise<LoadSessionResponse> {\n this.ensureInitialized('loadSession');\n\n if (!this.agentCapabilities?.loadSession) {\n throw new SessionError('Agent does not support session loading', sessionId);\n }\n\n try {\n const response = await this.connection.loadSession({\n sessionId,\n cwd,\n mcpServers: []\n });\n\n this.options.logger?.info(`Session loaded: ${sessionId}`);\n return response;\n } catch (err) {\n throw new SessionError(\n `Failed to load session: ${err instanceof Error ? err.message : String(err)}`,\n sessionId,\n err instanceof Error ? err : undefined\n );\n }\n }\n\n /**\n * Set the session mode\n */\n async setSessionMode(params: SetSessionModeRequest): Promise<SetSessionModeResponse> {\n this.ensureInitialized('setSessionMode');\n\n this.options.logger?.debug(`Setting session mode: ${params.sessionId} -> ${params.modeId}`);\n\n return this.connection.setSessionMode!(params);\n }\n\n /**\n * Set the session model\n * @experimental This API is unstable and may change\n */\n async setSessionModel(params: SetSessionModelRequest): Promise<SetSessionModelResponse> {\n this.ensureInitialized('setSessionModel');\n\n this.options.logger?.debug(`Setting session model: ${params.sessionId} -> ${params.modelId}`);\n\n return this.connection.unstable_setSessionModel!(params);\n }\n\n // ============================================\n // Prompt\n // ============================================\n\n /**\n * Send a prompt to the agent\n */\n async prompt(\n sessionId: string,\n prompt: ContentBlock[],\n options?: PromptOptions\n ): Promise<PromptResponse> {\n this.ensureInitialized('prompt');\n\n this.options.logger?.debug(`Sending prompt to session: ${sessionId}`);\n\n return this.connection.prompt({\n sessionId,\n prompt,\n _meta: options?.planMode ? { planMode: true, ...options._meta } : options?._meta\n });\n }\n\n /**\n * Cancel ongoing operations for a session\n */\n async cancel(sessionId: string): Promise<void> {\n this.ensureInitialized('cancel');\n\n this.options.logger?.debug(`Cancelling session: ${sessionId}`);\n\n await this.connection.cancel({ sessionId });\n }\n\n // ============================================\n // Permission Management\n // ============================================\n\n /**\n * Resolve a pending permission request\n */\n resolvePermission(requestId: string, optionId: string): boolean {\n return this.permissionManager.resolve(requestId, optionId);\n }\n\n /**\n * Reject a pending permission request\n */\n rejectPermission(requestId: string, reason?: string): boolean {\n return this.permissionManager.reject(requestId, reason);\n }\n\n /**\n * Get all pending permissions\n */\n getPendingPermissions() {\n return this.permissionManager.getPending();\n }\n\n /**\n * Check if there are pending permissions\n */\n hasPendingPermissions(): boolean {\n return this.permissionManager.hasPending();\n }\n\n // ============================================\n // Question Management (ask_followup_question)\n // ============================================\n\n /**\n * Answer a pending question request with user's selections\n */\n answerQuestion(toolCallId: string, answers: QuestionAnswers): boolean {\n return this.questionManager.answer(toolCallId, answers);\n }\n\n /**\n * Cancel a pending question request\n */\n cancelQuestion(toolCallId: string, reason?: string): boolean {\n return this.questionManager.cancel(toolCallId, reason);\n }\n\n /**\n * Get all pending question requests\n */\n getPendingQuestions() {\n return this.questionManager.getPending();\n }\n\n /**\n * Check if there are pending question requests\n */\n hasPendingQuestions(): boolean {\n return this.questionManager.hasPending();\n }\n\n // ============================================\n // Extension Methods\n // ============================================\n\n /**\n * Send an extension method request\n */\n async extMethod(method: string, params: Record<string, unknown>): Promise<Record<string, unknown>> {\n this.ensureInitialized('extMethod');\n return this.connection.extMethod!(method, params);\n }\n\n /**\n * Send an extension notification\n */\n async extNotification(method: string, params: Record<string, unknown>): Promise<void> {\n this.ensureInitialized('extNotification');\n return this.connection.extNotification!(method, params);\n }\n\n // ============================================\n // Event Emitter Implementation\n // ============================================\n\n on<K extends keyof ClientEvents>(\n event: K,\n listener: (data: ClientEvents[K]) => void | Promise<void>\n ): this {\n this.emitter.on(event, listener);\n return this;\n }\n\n off<K extends keyof ClientEvents>(\n event: K,\n listener: (data: ClientEvents[K]) => void | Promise<void>\n ): this {\n this.emitter.off(event, listener);\n return this;\n }\n\n once<K extends keyof ClientEvents>(\n event: K,\n listener: (data: ClientEvents[K]) => void | Promise<void>\n ): this {\n this.emitter.once(event, listener);\n return this;\n }\n\n emit<K extends keyof ClientEvents>(event: K, data: ClientEvents[K]): boolean {\n return this.emitter.emit(event, data);\n }\n\n removeAllListeners<K extends keyof ClientEvents>(event?: K): this {\n this.emitter.removeAllListeners(event);\n return this;\n }\n\n // ============================================\n // Internal Handlers\n // ============================================\n\n private async handleSessionUpdate(params: SessionNotification): Promise<void> {\n // Forward to callback\n await this.options.onSessionUpdate?.(params);\n\n // Emit event\n this.emitter.emit('sessionUpdate', params);\n }\n\n private async handleRequestPermission(\n params: RequestPermissionRequest\n ): Promise<RequestPermissionResponse> {\n return this.permissionManager.handleRequest(params);\n }\n\n private async handleExtNotification(\n method: string,\n params: Record<string, unknown>\n ): Promise<void> {\n // Handle artifact notifications\n if (method === ExtensionMethod.ARTIFACT) {\n const notification = params as unknown as ArtifactNotificationParams;\n const artifactData = notification.artifact as any;\n this.options.logger?.debug('[ACP-Client] Received artifact notification:', {\n event: notification.event,\n artifactUri: artifactData?.uri,\n artifactType: artifactData?.type,\n });\n\n // For deleted events, get full artifact before deletion for callbacks\n if (notification.event === 'deleted') {\n const existing = this.artifactManager.get(notification.artifact.uri);\n this.artifactManager.handleNotification(notification);\n if (existing) {\n await this.options.onArtifact?.(existing, 'deleted');\n this.emitter.emit('artifactDeleted', existing);\n }\n } else {\n const { artifact, event } = notification;\n // Let artifactManager handle the notification\n this.artifactManager.handleNotification(notification);\n // Get the artifact from manager or use the original\n const storedArtifact = this.artifactManager.get(artifact.uri) || artifact;\n\n this.options.logger?.debug('[ACP-Client] Stored artifact:', {\n event,\n artifactUri: storedArtifact.uri,\n artifactType: storedArtifact.type,\n hasText: storedArtifact.type === 'plan' ? !!(storedArtifact as any).text : undefined,\n });\n\n await this.options.onArtifact?.(storedArtifact, event);\n\n if (event === 'created') {\n this.options.logger?.debug('[ACP-Client] Emitting artifactCreated event');\n this.emitter.emit('artifactCreated', storedArtifact);\n if (storedArtifact.type === 'plan') {\n await this.options.onPlanReady?.(storedArtifact);\n }\n } else {\n this.options.logger?.debug('[ACP-Client] Emitting artifactUpdated event');\n this.emitter.emit('artifactUpdated', storedArtifact);\n }\n }\n return;\n }\n\n // Handle checkpoint notifications\n if (method === ExtensionMethod.CHECKPOINT) {\n const notification = params as unknown as CheckpointNotificationParams;\n if (notification.event === 'created') {\n this.emitter.emit('checkpointCreated', notification.checkpoint);\n } else if (notification.event === 'updated') {\n this.emitter.emit('checkpointUpdated', notification.checkpoint);\n }\n return;\n }\n\n // Forward other extensions to callback and manager\n await this.options.onExtNotification?.(method, params);\n await this.extensionManager.handleNotification(method, params);\n }\n\n private async handleExtMethod(\n method: string,\n params: QuestionRequest\n ): Promise<Record<string, unknown>> {\n // Handle question requests (ask_followup_question via question extMethod)\n if (method === ExtensionMethod.QUESTION) {\n const response = await this.questionManager.handleRequest(params);\n\n // Convert QuestionResponse to ToolInputResponse format expected by SDK\n if (response.outcome === 'submitted' && response.answers) {\n return {\n outcome: {\n outcome: 'submitted',\n data: {\n answers: response.answers\n }\n }\n };\n } else {\n return {\n outcome: {\n outcome: 'cancelled',\n reason: response.reason\n }\n };\n }\n }\n\n // Unknown extension method\n this.options.logger?.warn(`Unknown extension method: ${method}`);\n return {\n outcome: {\n outcome: 'cancelled',\n reason: 'unknown method'\n }\n };\n }\n\n // ============================================\n // Helpers\n // ============================================\n\n private ensureInitialized(operation: string): void {\n if (this.state !== 'initialized') {\n throw new InvalidStateError(operation, this.state, ['initialized']);\n }\n }\n}\n\nexport default StreamableHttpClient;\n\n/**\n * Check if an error is a retryable network-level error.\n * Only network failures (TypeError from fetch) are retried, NOT HTTP errors (4xx/5xx).\n */\nfunction isRetryableNetworkError(error: unknown): boolean {\n if (error instanceof TypeError) {return true;}\n if (error instanceof Error) {\n const msg = error.message.toLowerCase();\n return msg.includes('failed to fetch') ||\n msg.includes('fetch failed') ||\n msg.includes('network request failed') ||\n msg.includes('econnreset') ||\n msg.includes('econnrefused') ||\n msg.includes('socket hang up');\n }\n return false;\n}\n","/**\n * ACP 客户端 — 订阅模型\n *\n * 设计:直接映射到 ACP 协议的两条独立通道:\n *\n * - **RPC 通道(POST)**:`prompt` / `sessionCancel` 等是纯 `Promise`,转发上游。\n * - **Notification 通道(SSE)**:`subscribe(sessionId, listener)` 给用户注册\n * 监听器,每条上游 `SessionNotification` 多路分发给所有订阅者。\n *\n * 不做聚合、不建队列。上游 `SessionNotification` / `PromptResponse` 等类型原封\n * 不动透给上层(`Session` 类)。\n *\n * 具体实现基于 vendor 的 `StreamableHttpClient`,它内部管理一条 SSE + POST 复合\n * 通道。用户侧看到的只是\"一个 session 对应一个 AcpClient\"。\n */\n\nimport type { RuntimeConnectOpts, Logger, LogLevel } from '../opts';\nimport type { PromptResponse } from '../types';\nimport type {\n ContentBlock,\n SessionNotification,\n} from './vendor/sdk';\nimport { AcpProtocolError, NetworkError } from '../errors';\nimport { StreamableHttpClient } from './vendor/client';\n\n// ─── 过滤官方 ACP SDK 噪音日志 ────────────────\n//\n// @agentclientprotocol/sdk v0.4.8 内部对 session/update 做 zod schema 校验,\n// CodeBuddy 扩展的 session_info_update / usage_update / available_commands_update\n// 等扩展消息不符合官方 schema,会触发硬编码的\n// `console.error(\"Error handling notification\", message, error)`。\n// 这些日志纯粹是噪音,不影响功能(标准 agent_message_chunk 仍能通过校验)。\n//\n// 策略:只过滤 JSON-RPC \"Invalid params\"(code -32602)错误。\n// 其他错误类型(method not found / internal error / 用户代码异常等)全部保留。\nlet _consolePatched = false;\nfunction patchAcpSdkNoiseLogsOnce(): void {\n if (_consolePatched) return;\n _consolePatched = true;\n const origError = console.error.bind(console);\n console.error = (...args: unknown[]): void => {\n // 匹配签名:console.error(\"Error handling notification\", message, error)\n if (args.length >= 3 && args[0] === 'Error handling notification') {\n const err = args[2] as { code?: number } | null | undefined;\n // JSON-RPC Invalid params (schema 校验失败) → 过滤\n if (err && typeof err === 'object' && err.code === -32602) return;\n }\n origError(...args);\n };\n}\n\n// ─── 类型 ────────────────────────────────\n\nexport type AcpConnectionState = 'INITIAL' | 'CONNECTING' | 'OPEN' | 'CLOSING' | 'CLOSED';\n\n/** 连接级事件(用于高级用户诊断,如 UI 显示\"重连中\")。 */\nexport interface AcpConnectionEvents {\n open: () => void;\n error: (err: Error) => void;\n close: () => void;\n}\n\n/** Notification 订阅器签名 —— 收到的是上游 `SessionNotification` 原样。 */\nexport type NotificationListener = (notification: SessionNotification) => void;\n\n/** AcpClient 构造选项。 */\nexport interface AcpClientOpts {\n /** 日志器(已按级别过滤;通常由上层 `loggerFor(connectionOpts)` 传入)。 */\n logger?: Logger;\n /**\n * 已解析的日志级别(`resolveLogLevel(connectionOpts)` 的结果)。\n *\n * 唯一用途:决定是否把 logger **透传给底层 vendor**(ACP StreamableHttpClient)。\n * 规则:只有 `'debug'` 级别才透传,其他级别下 vendor 内部日志全部 noop。\n */\n logLevel?: LogLevel;\n /** 替换底层 fetch(接 OpenTelemetry / 代理 / mock)。 */\n fetch?: typeof fetch;\n}\n\n// ─── AcpClient ────────────────────────────────\n\nexport class AcpClient {\n private _state: AcpConnectionState = 'INITIAL';\n private _client: StreamableHttpClient | undefined;\n private _initialized = false;\n private _sessionIds: Set<string> = new Set();\n\n private readonly _logger: Logger | undefined;\n private readonly _fetch: typeof fetch | undefined;\n private readonly _exposeVendorLogs: boolean;\n\n tokenRefresher?: () => Promise<string>;\n\n /** 按 sessionId 分组的 notification 订阅器。 */\n private readonly _subscribers: Map<string, Set<NotificationListener>> = new Map();\n\n /** 连接级事件监听器(open / error / close)。 */\n private readonly _connListeners: {\n [K in keyof AcpConnectionEvents]: Set<AcpConnectionEvents[K]>;\n } = {\n open: new Set(),\n error: new Set(),\n close: new Set(),\n };\n\n /** per-session prompt 串行队列(ACP 协议要求:同 session 不能并发 prompt)。 */\n private readonly _activePrompts: Set<string> = new Set();\n private readonly _promptQueues: Map<string, Array<() => void>> = new Map();\n\n constructor(opts?: AcpClientOpts) {\n this._logger = opts?.logger;\n this._fetch = opts?.fetch;\n this._exposeVendorLogs = opts?.logLevel === 'debug';\n }\n\n // ─── 属性 ────────────────────────────────\n\n get state(): AcpConnectionState { return this._state; }\n get connectionId(): string | undefined { return this._client?.connectionId; }\n get sessionIds(): string[] { return Array.from(this._sessionIds); }\n get initialized(): boolean { return this._initialized; }\n\n setTokenRefresher(fn: () => Promise<string>): void {\n this.tokenRefresher = fn;\n }\n\n // ─── 连接管理 ────────────────────────────────\n\n async connect(acpUrl: string, token: string, opts?: RuntimeConnectOpts): Promise<void> {\n if (this._state === 'OPEN' || this._state === 'CONNECTING') return;\n this._state = 'CONNECTING';\n\n // 首次连接时惰性过滤官方 SDK 的噪音日志\n patchAcpSdkNoiseLogsOnce();\n\n this._logger?.info(`[acp] connecting to ${acpUrl}`);\n\n try {\n this._client = new StreamableHttpClient({\n endpoint: acpUrl,\n authToken: token,\n reconnect: {\n enabled: true,\n initialDelay: opts?.reconnectBackoffMs ?? 1000,\n maxDelay: opts?.reconnectMaxBackoffMs ?? 30_000,\n maxRetries: opts?.reconnectMaxAttempts ?? Infinity,\n },\n heartbeatTimeout: opts?.heartbeatTimeoutMs ?? 60_000,\n initializeTimeout: 30_000,\n postTimeout: 30_000,\n logger: this._exposeVendorLogs ? this._logger : undefined,\n fetch: this._fetch,\n // 上游每来一条 session/update notification 就回调这里。\n // vendor 的 `SessionUpdateCallback` 签名就是 `(n: SessionNotification) => void`,\n // 所以这里直接用强类型,不需要 `params: unknown` + 类型守卫。\n onSessionUpdate: (notification: SessionNotification) => this.dispatchNotification(notification),\n });\n\n this._client.on('connected', () => {\n this._logger?.info(`[acp] connected (connectionId=${this._client?.connectionId ?? 'n/a'})`);\n this.emitConnEvent('open');\n });\n this._client.on('error', (err: Error) => {\n // 运行期 transport 抖动:SDK 会自动重连,错误不会抛给调用方。\n // 在这里打 warn 是为了让用户在默认级别下能看到\"连接不稳定\"。\n this._logger?.warn(`[acp] error: ${err.message}`);\n this.emitConnEvent('error', err);\n });\n\n await this._client.connect();\n\n this._state = 'OPEN';\n this._initialized = true;\n } catch (err) {\n this._state = 'CLOSED';\n this._logger?.debug(`[acp] connect failed: ${(err as Error).message}`);\n throw new NetworkError(`ACP connect failed: ${(err as Error).message}`, { cause: err as Error });\n }\n }\n\n async disconnect(): Promise<void> {\n if (this._state === 'CLOSED' || this._state === 'CLOSING') return;\n this._state = 'CLOSING';\n if (this._client) {\n try { await this._client.disconnect(); } catch { /* ignore */ }\n this._client = undefined;\n }\n this._initialized = false;\n this._state = 'CLOSED';\n this._subscribers.clear();\n this._activePrompts.clear();\n this._promptQueues.clear();\n this._logger?.info('[acp] disconnected');\n this.emitConnEvent('close');\n }\n\n // ─── 协议方法(转发上游)────────────────────────────────\n\n /** initialize 由 connect() 内部完成,这里只取缓存结果。 */\n async initialize(): Promise<unknown> {\n if (!this._client) throw new AcpProtocolError('Not connected');\n return this._client.initializeResult;\n }\n\n async sessionNew(sessionId?: string): Promise<string> {\n if (!this._client) throw new AcpProtocolError('Not connected');\n const result = await this._client.createSession('/workspace');\n const newId = result.sessionId || sessionId || '';\n this._sessionIds.add(newId);\n return newId;\n }\n\n async sessionLoad(sessionId: string): Promise<void> {\n if (!this._client) throw new AcpProtocolError('Not connected');\n await this._client.loadSession(sessionId, '/workspace');\n this._sessionIds.add(sessionId);\n }\n\n /**\n * 发 prompt。纯 Promise,直接转发上游 `session/prompt` RPC。\n *\n * - **不聚合 notification**:本次 prompt 期间的 notifications 由\n * `subscribe()` 订阅器独立接收,与此 Promise 并行。\n * - **串行化**:同 sessionId 的多次 `prompt()` 会**排队**等前一个完成再发出\n * (ACP 协议要求),保证顺序一致。\n * - **signal 支持**:`opts.signal` abort 时向服务端发 `session/cancel`。\n * 本 Promise 会以 `AbortError` reject。\n */\n async prompt(\n sessionId: string,\n input: ContentBlock[],\n opts?: { signal?: AbortSignal }\n ): Promise<PromptResponse> {\n if (!this._client) throw new AcpProtocolError('Not connected');\n\n return new Promise<PromptResponse>((resolve, reject) => {\n this.enqueuePrompt(sessionId, async () => {\n // abort 时立即向服务端发 cancel 通知,并 reject 调用方 Promise\n let aborted = false;\n const onAbort = (): void => {\n aborted = true;\n // 尽力而为:cancel RPC 失败也无所谓,调用方已经知道要放弃\n this._client?.cancel(sessionId).catch(() => { /* warn 在 Session.cancel 做 */ });\n const err = new Error('Prompt aborted');\n err.name = 'AbortError';\n reject(err);\n };\n if (opts?.signal) {\n if (opts.signal.aborted) { onAbort(); return; }\n opts.signal.addEventListener('abort', onAbort, { once: true });\n }\n\n try {\n const response = await this._client!.prompt(sessionId, input as never[]) as PromptResponse;\n if (!aborted) resolve(response);\n } catch (err) {\n if (!aborted) reject(err);\n } finally {\n opts?.signal?.removeEventListener('abort', onAbort);\n }\n });\n });\n }\n\n /** 发 session/cancel 通知(幂等,尽力而为)。 */\n async sessionCancel(sessionId: string): Promise<void> {\n if (!this._client) throw new AcpProtocolError('Not connected');\n await this._client.cancel(sessionId);\n }\n\n // ─── Notification 订阅 ────────────────────────────────\n\n /**\n * 订阅指定 sessionId 的上游 notifications。\n *\n * Listener 收到的是上游 `SessionNotification` 原样(`{ sessionId, update, _meta? }`)。\n * 同一 session 可以有任意多个 listener,彼此独立;每条 notification 都会\n * 按注册顺序调用所有 listener(同步调用,异常被吞)。\n *\n * @returns unsubscribe 函数,调用即退订。\n */\n subscribe(sessionId: string, listener: NotificationListener): () => void {\n if (!this._subscribers.has(sessionId)) {\n this._subscribers.set(sessionId, new Set());\n }\n this._subscribers.get(sessionId)!.add(listener);\n return () => {\n this._subscribers.get(sessionId)?.delete(listener);\n };\n }\n\n // ─── 连接级事件订阅(高级用户诊断用)────────────────────────────────\n\n on<K extends keyof AcpConnectionEvents>(event: K, handler: AcpConnectionEvents[K]): void {\n this._connListeners[event].add(handler as AcpConnectionEvents[K]);\n }\n off<K extends keyof AcpConnectionEvents>(event: K, handler: AcpConnectionEvents[K]): void {\n this._connListeners[event].delete(handler as AcpConnectionEvents[K]);\n }\n\n // ─── 内部 ────────────────────────────────\n\n /**\n * 把上游 notification 按 sessionId 分发给订阅者。不做任何转换。\n *\n * 上游保证 `SessionNotification` 的 `sessionId` / `update` 字段都有值\n * (vendor 的 `SessionUpdateCallback` 签名即如此),无需再做类型守卫。\n */\n private dispatchNotification(notification: SessionNotification): void {\n const subs = this._subscribers.get(notification.sessionId);\n if (!subs || subs.size === 0) return;\n\n for (const listener of subs) {\n try {\n listener(notification);\n } catch {\n // 订阅者抛错不影响其他订阅者;不记日志(SDK 不能替用户处理业务异常)\n }\n }\n }\n\n private emitConnEvent<K extends keyof AcpConnectionEvents>(\n event: K,\n ...args: Parameters<AcpConnectionEvents[K]>\n ): void {\n for (const handler of this._connListeners[event]) {\n try {\n (handler as (...a: unknown[]) => void)(...args);\n } catch { /* ignore */ }\n }\n }\n\n private enqueuePrompt(sid: string, exec: () => Promise<void>): void {\n if (!this._promptQueues.has(sid)) this._promptQueues.set(sid, []);\n const runThenDequeue = (): void => {\n this._activePrompts.add(sid);\n exec().finally(() => this.dequeuePrompt(sid));\n };\n if (this._activePrompts.has(sid)) {\n this._promptQueues.get(sid)!.push(runThenDequeue);\n } else {\n runThenDequeue();\n }\n }\n\n private dequeuePrompt(sid: string): void {\n this._activePrompts.delete(sid);\n const q = this._promptQueues.get(sid);\n if (q && q.length > 0) q.shift()!();\n }\n}\n","/**\n * 日志基础设施 — 对齐 OpenAI / Anthropic 官方 SDK 的做法\n *\n * - `LogLevel`: 5 级(`'off' | 'error' | 'warn' | 'info' | 'debug'`),默认 `'warn'`\n * - `loggerFor(opts)`: 返回一个按级别过滤后的 Logger\n * - 关闭的级别是**真正的空函数**(零字符串拼接开销)\n * - 开放的级别**直接 `bind` 原 logger**(保留调用点栈信息)\n * - 结果用 WeakMap 缓存,相同 `[logger, level]` 组合复用\n * - `makeLogId()`: 生成短本地 ID(`log_a1b2c3`),用于在用户日志里串联一次 HTTP 请求\n *\n * 详见 docs/agentos/sdk/07-error-retry.md § 4。\n */\n\nimport type { ConnectionOpts, Logger, LogLevel } from '../opts';\n\n/** 级别数值:越大越详细;方法级别 > 当前级别时,该方法变成 noop。 */\nconst LEVEL_NUMBER: Record<LogLevel, number> = {\n off: 0,\n error: 200,\n warn: 300,\n info: 400,\n debug: 500,\n};\n\n/** 默认级别(不配置时)。 */\nconst DEFAULT_LEVEL: LogLevel = 'warn';\n\n/** 真正的空函数。替换被关闭的级别,避免字符串拼接开销。 */\nconst noop = (): void => { /* intentionally empty */ };\n\n/** 全 noop 的 logger(内部单例)。 */\nconst noopLogger: Logger = {\n error: noop,\n warn: noop,\n info: noop,\n debug: noop,\n};\n\n/**\n * 缓存 `[baseLogger, logLevel] -> wrappedLogger`。\n *\n * 用 WeakMap<Logger, ...>:只要 user 传的 logger 引用不变、level 不变,就复用。\n */\nconst cache: WeakMap<Logger, Map<LogLevel, Logger>> = new WeakMap();\n\n/**\n * 解析级别字符串;非法值返回 undefined(调用方自行回退)。\n */\nexport function parseLogLevel(value: unknown): LogLevel | undefined {\n if (typeof value !== 'string') return undefined;\n const lower = value.toLowerCase();\n if (lower in LEVEL_NUMBER) return lower as LogLevel;\n return undefined;\n}\n\n/**\n * 读取环境变量 `CLOUD_AGENT_SDK_LOG`(仅 Node.js 环境,浏览器返回 undefined)。\n *\n * 用 `globalThis` 方式访问避免对 `@types/node` 的强依赖。\n */\nfunction readEnvLogLevel(): LogLevel | undefined {\n const g = globalThis as { process?: { env?: Record<string, string | undefined> } };\n const env = g.process?.env;\n if (!env) return undefined;\n return parseLogLevel(env.CLOUD_AGENT_SDK_LOG);\n}\n\n/**\n * 按 ConnectionOpts 决定最终的 LogLevel。\n *\n * 优先级:`opts.logLevel` > env `CLOUD_AGENT_SDK_LOG` > `'warn'`。\n */\nexport function resolveLogLevel(opts: ConnectionOpts): LogLevel {\n return parseLogLevel(opts.logLevel)\n ?? readEnvLogLevel()\n ?? DEFAULT_LEVEL;\n}\n\n/**\n * 返回按 `opts` 过滤后的 Logger。\n *\n * - `opts.logger` 为空时使用 `globalThis.console`\n * - 级别关闭时返回 noop,开启时返回 `baseLogger[fn].bind(baseLogger)`\n * - 相同入参多次调用复用同一对象(WeakMap 缓存)\n */\nexport function loggerFor(opts: ConnectionOpts): Logger {\n const base: Logger = opts.logger ?? console;\n const level = resolveLogLevel(opts);\n\n if (level === 'off') return noopLogger;\n\n let byLevel = cache.get(base);\n if (!byLevel) {\n byLevel = new Map();\n cache.set(base, byLevel);\n }\n const cached = byLevel.get(level);\n if (cached) return cached;\n\n const wrapped = makeLeveledLogger(base, level);\n byLevel.set(level, wrapped);\n return wrapped;\n}\n\n/** Logger 上真正存在的方法级别(排除 'off')。 */\ntype LoggerMethod = Exclude<LogLevel, 'off'>;\n\n/**\n * 按级别构造 Logger:开放的级别直接 bind,关闭的级别替换为 noop。\n *\n * bind 而非 wrap 是为了保留调用点的 stack trace(开发者看日志能点回 SDK 行号)。\n */\nfunction makeLeveledLogger(base: Logger, level: LogLevel): Logger {\n const threshold = LEVEL_NUMBER[level];\n const enable = (fn: LoggerMethod): Logger[LoggerMethod] =>\n LEVEL_NUMBER[fn] <= threshold && typeof base[fn] === 'function'\n ? base[fn].bind(base)\n : noop;\n return {\n error: enable('error'),\n warn: enable('warn'),\n info: enable('info'),\n debug: enable('debug'),\n };\n}\n\n/**\n * 生成短本地日志 ID,用于在用户日志里串联一次 HTTP 请求(含重试链)。\n *\n * 形态:`log_` + 6 位十六进制(24 bit 随机,单进程内冲突概率可忽略)。\n *\n * 对齐 Anthropic SDK 的做法(详见 docs/agentos/sdk/07-error-retry.md § 4.3)。\n */\nexport function makeLogId(): string {\n // 不用 crypto.randomUUID:太长、信噪比低,日志行挤满\n const n = (Math.random() * (1 << 24)) | 0;\n return 'log_' + n.toString(16).padStart(6, '0');\n}\n","/**\n * Session — 对话上下文\n *\n * 控制面(REST):`info` / `update` / `delete`\n * 数据面(ACP):`connect` / `prompt` / `subscribe` / `disconnect`\n *\n * **订阅模型**(对齐 ACP 协议原生形态):\n * - `prompt(input)` 返回 `Promise<PromptResponse>` —— 一轮的终局\n * - `subscribe(listener)` —— 流式 notifications 由 listener 异步接收\n * - 两条通道独立、不聚合、无队列\n *\n * 典型用法:\n * ```ts\n * await session.connect();\n *\n * // 场景 A:只要最终结果\n * const response = await session.prompt('hello');\n * console.log(response.stopReason);\n *\n * // 场景 B:流式打印 + 最终结果\n * const unsub = session.subscribe((n) => {\n * if (n.update.sessionUpdate === 'agent_message_chunk' &&\n * n.update.content.type === 'text') {\n * process.stdout.write(n.update.content.text);\n * }\n * });\n * const response = await session.prompt('hello');\n * unsub();\n *\n * // 场景 C:便利钩子(等价于 B 但不需手动 unsub)\n * const response = await session.prompt('hello', {\n * onChunk: (n) => { ... },\n * });\n * ```\n */\n\nimport type { RequestOpts, PromptOpts, RuntimeConnectOpts } from './opts';\nimport type {\n SessionInfo, SessionStatus,\n SessionNotification, PromptResponse,\n DeleteResult, ContentBlock,\n UpdateSessionRequest,\n} from './types';\nimport type { Runtime } from './runtime';\nimport { AcpClient } from './acp/client';\nimport { RestClient } from './rest/client';\nimport { ValidationError } from './errors';\nimport { loggerFor, resolveLogLevel } from './internal/log';\n\nexport class Session {\n readonly id: string;\n readonly runtimeId: string;\n\n private readonly _runtime: Runtime;\n private readonly _restClient: RestClient;\n\n /** 数据面 ACP 客户端(connect() 后可用) */\n private _acpClient: AcpClient | undefined;\n\n /** 控制面状态(来自最近一次 info() / update())。 */\n private _status: SessionStatus | undefined;\n\n /** @internal */\n constructor(\n id: string,\n runtime: Runtime,\n restClient: RestClient,\n ) {\n this.id = id;\n this.runtimeId = runtime.id;\n this._runtime = runtime;\n this._restClient = restClient;\n }\n\n // ============================================================\n // 状态\n // ============================================================\n\n get status(): SessionStatus | undefined { return this._status; }\n\n /** ACP 连接是否已建立 */\n get connected(): boolean {\n return this._acpClient?.state === 'OPEN';\n }\n\n // ============================================================\n // 控制面(REST)\n // ============================================================\n\n /** 拉最新元数据 */\n async info(opts?: RequestOpts): Promise<SessionInfo> {\n const info = await this._restClient.get<SessionInfo>(\n `/runtimes/${this.runtimeId}/sessions/${this.id}`,\n undefined,\n opts\n );\n this._status = info.sessionStatus;\n return info;\n }\n\n /** 更新 name / manifest */\n async update(req: UpdateSessionRequest, opts?: RequestOpts): Promise<SessionInfo> {\n const info = await this._restClient.post<SessionInfo>(\n `/runtimes/${this.runtimeId}/sessions/${this.id}/update`,\n req,\n opts\n );\n this._status = info.sessionStatus;\n return info;\n }\n\n /** 软删除 */\n async delete(opts?: RequestOpts): Promise<DeleteResult> {\n // 断开 ACP\n if (this._acpClient) {\n await this._acpClient.disconnect();\n this._acpClient = undefined;\n }\n return this._restClient.post<DeleteResult>(\n `/runtimes/${this.runtimeId}/sessions/${this.id}/delete`,\n undefined,\n opts\n );\n }\n\n // ============================================================\n // 数据面 — 连接管理(ACP)\n // ============================================================\n\n /**\n * 建立到沙箱的 ACP 连接。\n *\n * 内部流程:GET SSE → 获取 connectionId → initialize → session/load。\n * 调用后 `prompt` / `subscribe` / `cancel` 才可用。\n *\n * 幂等:已连接时直接返回;并发调用时后来的等前者完成。\n */\n async connect(opts?: RuntimeConnectOpts): Promise<void> {\n if (this._acpClient && this._acpClient.state === 'OPEN') {\n return; // 已连接\n }\n\n const acpUrl = this._runtime.acpUrl;\n let acpToken = this._runtime.acpToken;\n\n if (!acpUrl || !acpToken) {\n // 尝试刷新\n acpToken = await this._runtime.refreshToken();\n if (!this._runtime.acpUrl || !acpToken) {\n throw new ValidationError('Runtime does not have ACP link. Is it in RUNNING state?');\n }\n }\n\n const connOpts = this._runtime._connectionOpts;\n const client = new AcpClient({\n logger: loggerFor(connOpts),\n logLevel: resolveLogLevel(connOpts),\n fetch: connOpts.fetch,\n });\n\n // 注入 token 刷新\n client.setTokenRefresher(async () => this._runtime.refreshToken());\n\n // 建立 SSE 连接。`...opts` 必须放前面,让后面显式字段兜底 undefined。\n await client.connect(this._runtime.acpUrl!, acpToken!, {\n ...opts,\n heartbeatTimeoutMs: opts?.heartbeatTimeoutMs ?? 45_000,\n reconnectMaxAttempts: opts?.reconnectMaxAttempts ?? Infinity,\n reconnectBackoffMs: opts?.reconnectBackoffMs ?? 300,\n reconnectMaxBackoffMs: opts?.reconnectMaxBackoffMs ?? 30_000,\n lastEventId: opts?.lastEventId,\n });\n\n // ACP initialize\n if (opts?.initialize !== false) {\n await client.initialize();\n }\n\n // 数据面只做 session/load(session 创建是控制面的事,通过 REST 完成)\n await client.sessionLoad(this.id);\n\n this._acpClient = client;\n }\n\n /** 断开 ACP 连接。所有订阅器被自动清除。 */\n async disconnect(): Promise<void> {\n if (this._acpClient) {\n await this._acpClient.disconnect();\n this._acpClient = undefined;\n }\n }\n\n // ============================================================\n // 数据面 — Prompt & Notification 订阅(ACP)\n // ============================================================\n\n /**\n * 发送 prompt 并等待 `PromptResponse`。\n *\n * @param input 纯文本字符串(自动包装成 text block)或 `ContentBlock[]`(多模态)\n * @param opts 见 `PromptOpts`,支持 `signal` 取消、`onChunk` 便利钩子等\n *\n * @returns `PromptResponse`(当前只含 `stopReason`)\n *\n * **时序**:\n * - 如果未 connect,会自动 connect\n * - RPC 发出期间,上游会通过 **SSE notification 通道**推送 `session/update`,\n * 这些消息**不会进 Promise 的结果**,需要通过 `subscribe()` 或 `onChunk`\n * 回调接收\n * - 同 session 并发 prompt 会被内部**串行化**(ACP 协议要求)\n *\n * @example\n * ```ts\n * // 最简:只要结果\n * const r = await session.prompt('2+2?');\n *\n * // 流式打印 + 结果\n * const r = await session.prompt('write a poem', {\n * onChunk: (n) => {\n * if (n.update.sessionUpdate === 'agent_message_chunk' &&\n * n.update.content.type === 'text') {\n * process.stdout.write(n.update.content.text);\n * }\n * },\n * });\n *\n * // 取消\n * const ctrl = new AbortController();\n * setTimeout(() => ctrl.abort(), 5000);\n * const r = await session.prompt('long task', { signal: ctrl.signal });\n * ```\n */\n async prompt(\n input: string | ContentBlock[],\n opts?: PromptOpts\n ): Promise<PromptResponse> {\n // 自动 connect\n if (!this._acpClient || this._acpClient.state !== 'OPEN') {\n await this.connect();\n }\n\n const content: ContentBlock[] = typeof input === 'string'\n ? [{ type: 'text', text: input }]\n : input;\n\n // 便利钩子:临时订阅,prompt 结束自动 unsub\n const unsubChunk = opts?.onChunk\n ? this._acpClient!.subscribe(this.id, opts.onChunk)\n : undefined;\n\n // 合并用户 signal 与超时\n let timeoutCtrl: AbortController | undefined;\n let signal = opts?.signal;\n if (opts?.timeoutMs !== undefined && opts.timeoutMs > 0) {\n timeoutCtrl = new AbortController();\n const timer = setTimeout(() => timeoutCtrl!.abort(), opts.timeoutMs);\n // 用户 signal 触发时也要清 timer 避免 leak\n signal?.addEventListener('abort', () => {\n clearTimeout(timer);\n timeoutCtrl!.abort();\n }, { once: true });\n // 把 timeoutCtrl.signal 作为最终 signal 传下去(abort 会传染)\n if (!signal) {\n signal = timeoutCtrl.signal;\n } else {\n // 两个 signal 合并:任一 abort 就 abort\n signal = mergeAbortSignals(signal, timeoutCtrl.signal);\n }\n }\n\n opts?.onTurnStart?.();\n\n try {\n const response = await this._acpClient!.prompt(this.id, content, { signal });\n opts?.onTurnEnd?.(response);\n return response;\n } finally {\n unsubChunk?.();\n }\n }\n\n /**\n * 订阅该 session 所有上游 notifications。\n *\n * Listener 收到的是上游 `SessionNotification` 原样(`{ sessionId, update, _meta? }`)。\n * `update` 是上游 11-tag 判别联合,在 switch 分支里类型自动收窄。\n *\n * 订阅独立于 prompt 生命周期——connect 之后注册,直到 unsubscribe 或\n * disconnect 为止。一个 session 支持任意多个订阅者。\n *\n * @returns unsubscribe 函数,调用即退订。\n *\n * @example\n * ```ts\n * const unsub = session.subscribe((n) => {\n * switch (n.update.sessionUpdate) {\n * case 'agent_message_chunk':\n * if (n.update.content.type === 'text') print(n.update.content.text);\n * break;\n * case 'tool_call':\n * console.log('tool:', n.update.title);\n * break;\n * }\n * });\n * // ...\n * unsub();\n * ```\n */\n subscribe(listener: (notification: SessionNotification) => void): () => void {\n if (!this._acpClient || this._acpClient.state !== 'OPEN') {\n throw new ValidationError('Session not connected. Call connect() first.');\n }\n return this._acpClient.subscribe(this.id, listener);\n }\n\n /**\n * 取消当前运行的 prompt(如果有)。\n *\n * 向服务端发 `session/cancel` notification,服务端会以 `stopReason: 'cancelled'`\n * 结束当前 prompt,对应的 `prompt()` Promise 正常 resolve(不 reject)。\n *\n * **尽力而为**:服务端 RPC 失败时打 warn 日志吞掉,不抛给调用方——\n * 因为\"用户点了取消按钮\"的 UX 契约就是\"本地能返回\"。\n */\n async cancel(): Promise<void> {\n if (!this._acpClient) return;\n try {\n await this._acpClient.sessionCancel(this.id);\n } catch (err) {\n const logger = loggerFor(this._runtime._connectionOpts);\n logger.warn(`[session ${this.id}] cancel failed: ${(err as Error).message}`);\n }\n }\n}\n\n// ─── 工具 ────────────────────────────────\n\n/**\n * 合并两个 AbortSignal:任一 abort 时返回的 signal 也 abort。\n *\n * 用原生 `AbortSignal.any()` 不行——Node 18 没有。这里用最小 polyfill。\n */\nfunction mergeAbortSignals(a: AbortSignal, b: AbortSignal): AbortSignal {\n if (typeof (AbortSignal as unknown as { any?: (s: AbortSignal[]) => AbortSignal }).any === 'function') {\n return (AbortSignal as unknown as { any: (s: AbortSignal[]) => AbortSignal }).any([a, b]);\n }\n const ctrl = new AbortController();\n const onAbort = (): void => ctrl.abort();\n if (a.aborted || b.aborted) {\n ctrl.abort();\n } else {\n a.addEventListener('abort', onAbort, { once: true });\n b.addEventListener('abort', onAbort, { once: true });\n }\n return ctrl.signal;\n}\n","/**\n * Runtime — 一个云端沙箱实例\n *\n * 由 CloudAgentClient.runtimes.create() 或 .from() 返回。\n * 返回时已持有控制面 info(status、metadata)和数据面连接信息(acpLink、sandboxId)。\n *\n * Runtime 实例方法覆盖自身的控制面操作(update/delete/refreshToken)。\n * 通过 sessions 子命名空间管理 Session 的控制面 CRUD。\n */\n\nimport type { ConnectionOpts, RequestOpts, SessionCreateOpts, SessionListOpts } from './opts';\nimport type {\n RuntimeInfo, SessionInfo, PageResult, DeleteResult,\n UpdateRuntimeRequest, CreateSessionRequest,\n} from './types';\nimport { RestClient } from './rest/client';\nimport { Session } from './session';\n\nexport class Runtime {\n readonly id: string;\n\n /** 控制面信息快照(创建/刷新时更新) */\n private _info: RuntimeInfo;\n\n /** 数据面连接信息 */\n readonly sandboxId?: string;\n readonly sandboxDomain?: string;\n private _acpUrl?: string;\n private _acpToken?: string;\n\n /** 内部依赖 */\n private readonly _restClient: RestClient;\n /** @internal 供 Session 构造 AcpClient 时读取(logger / fetch)。 */\n readonly _connectionOpts: ConnectionOpts;\n\n /** 默认 session ID */\n private _defaultSessionId: string | undefined;\n\n /** @internal */\n constructor(\n restClient: RestClient,\n connectionOpts: ConnectionOpts,\n info: RuntimeInfo,\n ) {\n this.id = info.id;\n this._info = info;\n this._restClient = restClient;\n this._connectionOpts = connectionOpts;\n\n this.sandboxId = info.links?.sandboxLink?.sandboxId;\n this.sandboxDomain = info.links?.sandboxLink?.endpoint;\n this._acpUrl = info.links?.acpLink?.url;\n this._acpToken = info.links?.acpLink?.token;\n\n if (info.sessions && info.sessions.length > 0) {\n this._defaultSessionId = info.sessions[0].sessionId;\n }\n }\n\n // ─── 公共属性 ────────────────────────────────\n\n get runtimeInfo(): RuntimeInfo { return this._info; }\n get acpUrl(): string | undefined { return this._acpUrl; }\n get acpToken(): string | undefined { return this._acpToken; }\n\n // ============================================================\n // Runtime 自身操作(控制面)\n // ============================================================\n\n /** 更新 Runtime 元数据 */\n async update(req: UpdateRuntimeRequest, opts?: RequestOpts): Promise<RuntimeInfo> {\n const info = await this._restClient.post<RuntimeInfo>(`/runtimes/${this.id}/update`, req, opts);\n this._info = info;\n return info;\n }\n\n /** 软删除 */\n async delete(opts?: RequestOpts): Promise<DeleteResult> {\n return this._restClient.post<DeleteResult>(`/runtimes/${this.id}/delete`, undefined, opts);\n }\n\n /** 刷新 token(拉最新 RuntimeInfo,更新 acpLink) */\n async refreshToken(opts?: RequestOpts): Promise<string> {\n const info = await this._restClient.get<RuntimeInfo>(`/runtimes/${this.id}`, undefined, opts);\n this._info = info;\n if (info.links?.acpLink) {\n this._acpUrl = info.links.acpLink.url;\n this._acpToken = info.links.acpLink.token;\n }\n return this._acpToken || '';\n }\n\n // ============================================================\n // sessions — 控制面 CRUD\n // ============================================================\n\n readonly sessions = {\n /** 创建新 Session(控制面),返回 Session 实例 */\n create: async (opts: SessionCreateOpts): Promise<Session> => {\n // 组装 REST body —— CreateSessionRequest 是后端 API 的权威镜像\n const body: CreateSessionRequest = {\n sessionId: opts.sessionId,\n sessionName: opts.sessionName,\n agentManifest: opts.agentManifest,\n };\n\n const info = await this._restClient.post<SessionInfo>(\n `/runtimes/${this.id}/sessions`,\n body,\n {\n timeoutMs: opts.timeoutMs,\n headers: opts.headers,\n signal: opts.signal,\n requestId: opts.requestId,\n }\n );\n\n return new Session(info.sessionId, this, this._restClient);\n },\n\n /** 获取 Session(返回实例) */\n get: async (sessionId: string, opts?: RequestOpts): Promise<Session> => {\n // 验证 session 存在(发请求),然后返回实例\n await this._restClient.get<SessionInfo>(\n `/runtimes/${this.id}/sessions/${sessionId}`,\n undefined,\n opts\n );\n return new Session(sessionId, this, this._restClient);\n },\n\n /** 分页列表(返回纯数据) */\n list: async (opts?: SessionListOpts): Promise<PageResult<SessionInfo>> => {\n const params: Record<string, string> = {};\n if (opts?.page !== undefined) params.page = String(opts.page);\n if (opts?.pageSize !== undefined) params.pageSize = String(opts.pageSize);\n if (opts?.sessionStatus) params.sessionStatus = opts.sessionStatus;\n return this._restClient.get<PageResult<SessionInfo>>(\n `/runtimes/${this.id}/sessions`,\n params,\n opts\n );\n },\n\n /** 默认 session(Runtime 创建时自动生成的) */\n default: (): Session => {\n const sessionId = this._defaultSessionId || this.id;\n return new Session(sessionId, this, this._restClient);\n },\n };\n}\n","/**\n * 敏感信息脱敏\n *\n * 范围:headers + 特定已知的 body 字段(白名单 path,非启发式猜测)。\n * 脱敏仅作用于日志打印和钩子回调,不影响实际发送的请求。\n *\n * 详见 docs/agentos/sdk/07-error-retry.md § 4.5。\n */\n\n/** 需要脱敏的 header 名(小写)。 */\nconst SENSITIVE_HEADER_NAMES: ReadonlySet<string> = new Set([\n 'authorization',\n 'cookie',\n 'set-cookie',\n 'x-api-key',\n]);\n\n/** 脱敏替换值。 */\nconst REDACTED = '***';\n\n/**\n * 返回脱敏后的 headers 副本。\n *\n * - 键按原样保留(大小写不变)\n * - 值按键名(小写后)匹配敏感列表时替换为 `'***'`\n * - **纯函数**,不修改入参\n */\nexport function redactHeaders(\n headers: Record<string, string> | undefined,\n): Record<string, string> {\n if (!headers) return {};\n const out: Record<string, string> = {};\n for (const [name, value] of Object.entries(headers)) {\n out[name] = SENSITIVE_HEADER_NAMES.has(name.toLowerCase()) ? REDACTED : value;\n }\n return out;\n}\n\n/**\n * 给定一个 header 名是否属于敏感名(小写比较)。\n *\n * 供扩展处使用(如需要自定义 Headers/Map 迭代的场景)。\n */\nexport function isSensitiveHeader(name: string): boolean {\n return SENSITIVE_HEADER_NAMES.has(name.toLowerCase());\n}\n\n// ─── Body 脱敏 ────────────────────────────────\n//\n// 与 OpenAI / Anthropic 官方 SDK 不同:它们的 body 只含 prompt / messages / tools\n// 等业务内容,没有高敏感字段,所以不脱敏。\n//\n// 我们的 `runtimes.create` / `sessions.create` body 里会携带 `agentManifest.secrets[].value`\n// —— 用户业务下发到 sandbox 的真实密钥(数据库密码、第三方 API Key 等),\n// 泄露后果远超 apiKey(apiKey 泄露只影响当前调用方,secret 泄露影响用户业务的下游)。\n//\n// 策略:\n// - **白名单**:只处理已知的、明确含密钥的字段(而非启发式猜测字段名)\n// - **深克隆**:不修改原始 body,只在日志/钩子里使用脱敏副本\n// - **未来扩展**:新增敏感字段时显式加到下面的 REDACTOR 表\n\n/** 判断 value 是否是对象数组(`Array<Record<string, unknown>>`)。 */\nfunction isObjectArray(v: unknown): v is Array<Record<string, unknown>> {\n return Array.isArray(v) && v.every(x => x !== null && typeof x === 'object' && !Array.isArray(x));\n}\n\n/**\n * Body 脱敏器:对给定对象做**浅复制 + 定向脱敏**,返回安全的日志副本。\n *\n * 不修改入参。若入参不是对象(string / number / ...),原样返回。\n *\n * 已处理字段:\n * - `agentManifest.secrets[].value` → `'***'`(保留 name,只脱 value)\n */\nexport function redactBody(body: unknown): unknown {\n if (body === null || body === undefined) return body;\n if (typeof body !== 'object' || Array.isArray(body)) return body;\n\n const input = body as Record<string, unknown>;\n // 浅复制 + 按 path 定向深复制\n const out: Record<string, unknown> = { ...input };\n\n // agentManifest.secrets[].value\n const manifest = input.agentManifest as Record<string, unknown> | undefined;\n if (manifest && typeof manifest === 'object' && !Array.isArray(manifest)) {\n const secrets = manifest.secrets;\n if (isObjectArray(secrets)) {\n out.agentManifest = {\n ...manifest,\n secrets: secrets.map(s => (\n 'value' in s ? { ...s, value: REDACTED } : s\n )),\n };\n }\n }\n\n return out;\n}\n","/**\n * REST 客户端 — 基于原生 fetch\n *\n * 职责:\n * - 注入认证 / 身份 / 自定义 header(apiKey / source* / user 定制)\n * - 统一解包 `{ code, msg, data, requestId }`,非 0 抛 `CloudAgentError`\n * - 超时控制(AbortController + AbortSignal 合并)\n * - 重试(指数退避 + 抖动;默认仅 GET 重试,非 GET 需显式 `retry`)\n * - 日志:Anthropic 风格的双 ID(本地 `logId` + 服务端 `requestId`)\n * + 单行 info 摘要 + 详细 debug\n * - 脱敏:onRequest / onResponse 钩子 + debug 日志里的 headers 自动脱敏\n *\n * 详见 docs/agentos/sdk/07-error-retry.md。\n */\n\nimport type { ConnectionOpts, Logger, RequestOpts, RetryOpts, RetryContext, RetryOn } from '../opts';\nimport {\n CloudAgentError,\n NetworkError,\n TimeoutError,\n AuthError,\n NotFoundError,\n ValidationError,\n AcpProtocolError,\n} from '../errors';\nimport { loggerFor, makeLogId } from '../internal/log';\nimport { redactBody, redactHeaders } from '../internal/redact';\n\ninterface ApiResponse<T = unknown> {\n code: number;\n msg: string;\n requestId: string;\n data?: T;\n}\n\n/** 默认 baseUrl */\nconst DEFAULT_BASE_URL = 'https://www.codebuddy.cn/v2/agentos';\n\n/**\n * SDK 内置的默认重试判定。\n *\n * 传 `retry: { retryOn: ... }` 会**完全替换**这里的规则(不叠加)。\n * 公开这个函数是为了让用户在自定义 `retryOn` 里可以手动调用回落到默认:\n *\n * ```ts\n * retry: {\n * retryOn: (err, ctx) => {\n * if (err instanceof TimeoutError && ctx.url.includes('/upload')) return false;\n * return DEFAULT_RETRY_ON(err, ctx);\n * },\n * }\n * ```\n */\nexport const DEFAULT_RETRY_ON: RetryOn = (err, ctx) => {\n // 用户主动取消\n if (err.name === 'AbortError') return false;\n\n // SDK 业务错误:按类型决定\n if (err instanceof AuthError) return false;\n if (err instanceof NotFoundError) return false;\n if (err instanceof ValidationError) return false;\n if (err instanceof AcpProtocolError) return false;\n\n // 超时:仅幂等方法(GET)重试。POST / PATCH / DELETE 超时可能已成功执行,\n // 重试会造成重复副作用(如重复创建 Runtime)。\n if (err instanceof TimeoutError) return ctx.method === 'GET';\n\n // 网络错误:所有方法都可重试(连接根本没成功,不会有副作用)\n if (err instanceof NetworkError) return true;\n\n // 其他未知错误(例如 fetch 抛的原生 TypeError):保守重试\n return true;\n};\n\n/** 默认重试配置。 */\nconst DEFAULT_RETRY: Required<RetryOpts> = {\n maxAttempts: 3,\n backoffMs: 300,\n backoffFactor: 2,\n jitter: true,\n retryOn: DEFAULT_RETRY_ON,\n};\n\n/** 单次请求的内部上下文(跨 doRequest 复用)。 */\ninterface RequestContext {\n logId: string;\n retryOfLogId?: string;\n startTimeMs: number;\n}\n\nexport class RestClient {\n private readonly opts: ConnectionOpts;\n private readonly logger: Logger;\n private readonly fetchImpl: typeof fetch;\n\n constructor(opts: ConnectionOpts) {\n this.opts = opts;\n this.logger = loggerFor(opts);\n // 逃生舱:允许业务替换 fetch(如 OTel instrumented fetch);\n // 保留 bind(globalThis) 避免某些 runtime 上 this 绑定问题。\n const userFetch = opts.fetch;\n this.fetchImpl = userFetch ?? fetch.bind(globalThis);\n }\n\n /** GET 请求。 */\n async get<T>(path: string, query?: Record<string, string>, opts?: RequestOpts): Promise<T> {\n const url = this.buildUrl(path, query);\n return this.request<T>('GET', url, undefined, opts);\n }\n\n /** POST 请求。 */\n async post<T>(path: string, body?: unknown, opts?: RequestOpts): Promise<T> {\n const url = this.buildUrl(path);\n return this.request<T>('POST', url, body, opts);\n }\n\n /** PATCH 请求。 */\n async patch<T>(path: string, body?: unknown, opts?: RequestOpts): Promise<T> {\n const url = this.buildUrl(path);\n return this.request<T>('PATCH', url, body, opts);\n }\n\n /** DELETE 请求。 */\n async delete<T>(path: string, opts?: RequestOpts): Promise<T> {\n const url = this.buildUrl(path);\n return this.request<T>('DELETE', url, undefined, opts);\n }\n\n //\n // 是否重试由 `RetryOpts.retryOn(err, ctx)` 统一决定(见 DEFAULT_RETRY_ON):\n // GET/POST/PATCH/DELETE 全部进入 retry 链路,retryOn 按错误类型 + method\n // 精确决策(非幂等方法超时默认不重试,避免副作用)。\n\n // ─── 内部方法 ────────────────────────────────\n\n /** 构建完整 URL。 */\n private buildUrl(path: string, query?: Record<string, string>): string {\n const base = (this.opts.baseUrl || DEFAULT_BASE_URL).replace(/\\/+$/, '');\n const fullPath = path.startsWith('/') ? path : `/${path}`;\n const url = new URL(`${base}${fullPath}`);\n\n if (query) {\n for (const [k, v] of Object.entries(query)) {\n if (v !== undefined && v !== '') {\n url.searchParams.set(k, v);\n }\n }\n }\n\n return url.toString();\n }\n\n /** 构建请求 headers(含认证、身份、trace、自定义)。 */\n private buildHeaders(opts?: RequestOpts): Record<string, string> {\n const headers: Record<string, string> = {\n 'Content-Type': 'application/json',\n 'Accept': 'application/json',\n };\n\n // 认证:仅支持 apiKey(后端场景);浏览器场景通过 baseUrl 代理或自定义 headers 注入鉴权\n if (this.opts.apiKey) {\n headers['x-api-key'] = this.opts.apiKey;\n }\n\n // 身份 headers\n if (this.opts.sourceApp) headers['X-Source-App'] = this.opts.sourceApp;\n if (this.opts.sourceTenantId) headers['X-Source-Tenant-Id'] = this.opts.sourceTenantId;\n if (this.opts.userId) headers['X-User-Id'] = this.opts.userId;\n\n // 全局自定义 headers\n if (this.opts.headers) Object.assign(headers, this.opts.headers);\n\n // 逐请求覆盖 headers(用户可塞 traceparent 等,SDK 原样透传)\n if (opts?.headers) Object.assign(headers, opts.headers);\n\n // Request ID(不传则生成 UUID,用于服务端请求识别)\n headers['X-Request-Id'] = opts?.requestId ?? generateRequestId();\n\n return headers;\n }\n\n /** 发起请求(含超时 + 重试 + 日志 + 脱敏 + hooks)。 */\n private async request<T>(method: string, url: string, body?: unknown, opts?: RequestOpts): Promise<T> {\n // 确定重试策略。优先级:per-request `opts.retry` > 全局 `this.opts.retry` > DEFAULT_RETRY。\n // 传 `false` 关闭重试;method 相关的精细决策交给 `retryOn(err, ctx)`。\n const shouldRetry: RetryOpts | false = opts?.retry !== undefined\n ? opts.retry\n : this.opts.retry ?? DEFAULT_RETRY;\n\n // 初始日志 ID;重试时每次生成新的,但会带 retryOf 指向上一次\n const ctx: RequestContext = {\n logId: makeLogId(),\n retryOfLogId: undefined,\n startTimeMs: 0,\n };\n\n const doRequest = async (): Promise<T> => {\n ctx.startTimeMs = Date.now();\n const timeoutMs = opts?.timeoutMs ?? this.opts.timeoutMs ?? 30_000;\n const headers = this.buildHeaders(opts);\n const requestId = headers['X-Request-Id'];\n\n // 构建 abort 信号\n const controller = new AbortController();\n let timeoutId: ReturnType<typeof setTimeout> | undefined;\n\n if (timeoutMs > 0) {\n timeoutId = setTimeout(() => controller.abort(), timeoutMs);\n }\n\n // 外部 signal 合并\n if (opts?.signal) {\n if (opts.signal.aborted) {\n controller.abort();\n } else {\n opts.signal.addEventListener('abort', () => controller.abort(), { once: true });\n }\n }\n\n const retryTag = ctx.retryOfLogId ? `, retryOf: ${ctx.retryOfLogId}` : '';\n const redactedReqHeaders = redactHeaders(headers);\n\n // 触发 onRequest hook(传脱敏后的 headers 副本)\n this.opts.onRequest?.({ method, url, headers: { ...redactedReqHeaders } });\n\n this.logger.debug(\n `[${ctx.logId}${retryTag}] sending request ${method} ${url}`,\n {\n headers: redactedReqHeaders,\n body: body !== undefined ? truncate(redactBody(body)) : undefined,\n },\n );\n\n try {\n const response = await this.fetchImpl(url, {\n method,\n headers,\n body: body !== undefined ? JSON.stringify(body) : undefined,\n signal: controller.signal,\n });\n\n const durationMs = Date.now() - ctx.startTimeMs;\n\n // 收集响应 headers(脱敏后用于 hook/日志)\n const responseHeaders: Record<string, string> = {};\n response.headers.forEach((v, k) => { responseHeaders[k] = v; });\n const redactedResHeaders = redactHeaders(responseHeaders);\n\n this.opts.onResponse?.({\n status: response.status,\n headers: { ...redactedResHeaders },\n url,\n });\n\n // 服务端 request-id 响应头(不同于客户端传的 X-Request-Id,部分网关会回填)\n const serverReqId = response.headers.get('x-request-id') ?? requestId;\n const reqIdTag = serverReqId ? `, request-id: \"${serverReqId}\"` : '';\n // 单行摘要:info 级别(默认 warn 下不可见,符合\"业务错由调用方 catch 处理\"的语义)。\n // 真正值得用户默认看到的告警由 withRetry 的 \"retrying...\" 承担。\n const summary = `[${ctx.logId}${retryTag}${reqIdTag}] ${method} ${url} ${response.ok ? 'succeeded' : 'failed'} with status ${response.status} in ${durationMs}ms`;\n this.logger.info(summary);\n this.logger.debug(\n `[${ctx.logId}${retryTag}] response received`,\n { status: response.status, headers: redactedResHeaders, durationMs },\n );\n\n // 解包\n return await this.unwrap<T>(response, ctx.logId, serverReqId);\n } catch (err) {\n if (timeoutId) clearTimeout(timeoutId);\n\n const durationMs = Date.now() - ctx.startTimeMs;\n\n // AbortError → 判断是超时还是用户取消\n if (err instanceof Error && err.name === 'AbortError') {\n if (opts?.signal?.aborted) {\n this.logger.debug(\n `[${ctx.logId}${retryTag}] request cancelled by caller after ${durationMs}ms`,\n );\n throw err; // 用户主动取消,不包装\n }\n // 超时:仅 GET 默认重试(见 DEFAULT_RETRY_ON),非 GET 超时\n // 立即抛出避免重复副作用。这里只打 debug,避免重试循环里\n // \"Request timed out\" warn + withRetry 的 \"retrying\" warn 双倍刷屏。\n // 最终失败(重试耗尽)由调用方 catch 决定是否上报。\n const msg = `Request timed out after ${timeoutMs}ms: ${method} ${url}`;\n this.logger.debug(`[${ctx.logId}${retryTag}] ${msg}`);\n throw new TimeoutError(msg, { logId: ctx.logId, cause: err });\n }\n\n // fetch 网络错误\n // 注意:这里只打 debug,真正可见的重试告警由 withRetry 的 \"retrying...\" warn 承担,\n // 避免重试循环中 \"NetworkError\" warn + \"retrying\" warn 双倍刷屏。\n // 最终失败(重试耗尽)时由调用方的 catch 决定是否上报。\n if (err instanceof TypeError || (err instanceof Error && isNetworkError(err))) {\n const msg = `Network error: ${method} ${url} - ${(err as Error).message}`;\n this.logger.debug(`[${ctx.logId}${retryTag}] ${msg}`);\n throw new NetworkError(msg, {\n logId: ctx.logId,\n cause: err as Error,\n });\n }\n\n // 已是 CloudAgentError 则直接抛(它本身已带 logId/requestId)\n if (err instanceof CloudAgentError) {\n throw err;\n }\n\n // 意外异常(非网络、非超时、非业务错):值得 error 级别\n const msg = `Unexpected error: ${method} ${url} - ${(err as Error).message}`;\n this.logger.error(`[${ctx.logId}${retryTag}] ${msg}`);\n throw new NetworkError(msg, { logId: ctx.logId, cause: err as Error });\n } finally {\n if (timeoutId) clearTimeout(timeoutId);\n }\n };\n\n // 包装重试\n if (shouldRetry === false) {\n return doRequest();\n }\n\n return this.withRetry(doRequest, shouldRetry, ctx, method, url);\n }\n\n /** 解包响应 `{ code, msg, data }` → `data` 或抛错。 */\n private async unwrap<T>(response: Response, logId: string, serverReqId?: string): Promise<T> {\n // 对于 204 No Content\n if (response.status === 204) {\n return undefined as unknown as T;\n }\n\n let body: ApiResponse<T> | undefined;\n let rawText: string;\n try {\n // 用 text + 正则处理 int64 大数精度丢失\n // 将 17 位及以上的纯数字值转为字符串(MAX_SAFE_INTEGER = 9007199254740991,16 位)\n rawText = await response.text();\n const safeText = rawText.replace(\n /:\\s*(\\d{17,})/g,\n (match, num) => match.replace(num, `\"${num}\"`),\n );\n body = JSON.parse(safeText) as ApiResponse<T>;\n } catch {\n // 非 JSON 响应\n if (!response.ok) {\n throw this.httpStatusToError(response.status, `HTTP ${response.status}`, {\n logId,\n requestId: serverReqId,\n });\n }\n return (rawText! as unknown) as T;\n }\n\n // 服务端返回的 requestId 两个来源:\n // - body.requestId:由 middleware 写入 gin ctx 后由错误/成功响应包装器读出(业务层值)\n // - response header X-Request-Id:由 RequestIDMiddleware 直接回显\n // 两者在正常路径上是同一个值(都来自 middleware),优先 body 是因为:\n // 1) 4xx/5xx 非 JSON 时 body 可能解析不到,header 是最后兜底\n // 2) body 是服务端\"明确意图\"返回的字段,header 可能被反代重写\n // 服务端源码: services/pkg/middleware/request_id.go\n const effectiveRequestId = body.requestId || serverReqId;\n\n // HTTP 层错误\n if (!response.ok) {\n throw this.httpStatusToError(\n response.status,\n body.msg || `HTTP ${response.status}`,\n { logId, requestId: effectiveRequestId, code: body.code },\n );\n }\n\n // 业务层错误 (code !== 0)\n if (body.code !== 0) {\n throw this.codeToError(body.code, body.msg, {\n logId,\n requestId: effectiveRequestId,\n httpStatus: response.status,\n });\n }\n\n return body.data as T;\n }\n\n /** HTTP 状态码映射为错误。 */\n private httpStatusToError(\n status: number,\n message: string,\n ctx: { logId: string; requestId?: string; code?: number },\n ): CloudAgentError {\n const opts = { httpStatus: status, logId: ctx.logId, requestId: ctx.requestId, code: ctx.code };\n\n switch (status) {\n case 400:\n return new ValidationError(message, opts);\n case 401:\n case 403:\n return new AuthError(message, opts);\n case 404:\n return new NotFoundError(message, opts);\n case 408:\n case 504:\n return new TimeoutError(message, opts);\n case 429:\n return new NetworkError(message, opts);\n default:\n if (status >= 500) {\n return new NetworkError(message, opts);\n }\n return new CloudAgentError(message, opts);\n }\n }\n\n /** 业务 code 映射为错误。 */\n private codeToError(\n code: number,\n message: string,\n ctx: { logId: string; requestId?: string; httpStatus?: number },\n ): CloudAgentError {\n const opts = { code, httpStatus: ctx.httpStatus, logId: ctx.logId, requestId: ctx.requestId };\n\n // 按照 07-error-retry.md § 1.4 中的映射表\n switch (code) {\n case 10001:\n return new ValidationError(message, opts);\n case 10034:\n case 10085:\n return new AuthError(message, opts);\n case 10064:\n case 10065:\n case 10067:\n return new NetworkError(message, opts);\n case 10084:\n return new NotFoundError(message, opts);\n case 10094:\n return new TimeoutError(message, opts);\n case 10000:\n return new NetworkError(message, opts);\n default:\n return new CloudAgentError(message, opts);\n }\n }\n\n /**\n * 重试逻辑。\n *\n * 是否重试只看 `opts.retryOn(err, ctx)`。用户传的 retryOn **完全替换** SDK\n * 默认判定(不叠加、不 fallback 到 error 类上的任何字段)。\n */\n private async withRetry<T>(\n fn: () => Promise<T>,\n retryOpts: RetryOpts,\n reqCtx: RequestContext,\n method: string,\n url: string,\n ): Promise<T> {\n const opts = { ...DEFAULT_RETRY, ...retryOpts };\n let lastError: Error | undefined;\n\n for (let attempt = 1; attempt <= opts.maxAttempts; attempt++) {\n try {\n return await fn();\n } catch (err) {\n lastError = err as Error;\n\n const retryCtx: RetryContext = { attempt, method, url };\n if (!opts.retryOn(err as Error, retryCtx)) {\n throw err;\n }\n\n // 最后一次尝试不再退避\n if (attempt >= opts.maxAttempts) {\n break;\n }\n\n const delayMs = this.getBackoffMs(attempt, opts);\n this.logger.warn(\n `[${reqCtx.logId}] retrying (attempt ${attempt}/${opts.maxAttempts}) in ${delayMs}ms — ${(err as Error).name}: ${(err as Error).message}`,\n );\n\n await sleep(delayMs);\n\n // 下一次生成新的 logId,并把当前 logId 作为 retryOf 指向\n reqCtx.retryOfLogId = reqCtx.logId;\n reqCtx.logId = makeLogId();\n }\n }\n\n throw lastError!;\n }\n\n /** 计算退避时间。 */\n private getBackoffMs(attempt: number, opts: Required<RetryOpts>): number {\n const baseDelay = Math.min(\n opts.backoffMs * Math.pow(opts.backoffFactor, attempt - 1),\n 30_000, // 最大退避 30s\n );\n\n if (!opts.jitter) {\n return Math.round(baseDelay);\n }\n\n // ±20% 随机抖动\n const jitterFactor = 0.2 * (Math.random() * 2 - 1);\n return Math.round(baseDelay * (1 + jitterFactor));\n }\n}\n\n// ─── 工具函数 ────────────────────────────────\n\nfunction sleep(ms: number): Promise<void> {\n return new Promise(resolve => setTimeout(resolve, ms));\n}\n\nfunction isNetworkError(err: Error): boolean {\n const msg = err.message.toLowerCase();\n return msg.includes('failed to fetch')\n || msg.includes('fetch failed')\n || msg.includes('network')\n || msg.includes('econnrefused')\n || msg.includes('econnreset')\n || msg.includes('enotfound')\n || msg.includes('socket hang up');\n}\n\nfunction generateRequestId(): string {\n // 简单的随机 ID 生成,兼容浏览器和 Node.js\n if (typeof crypto !== 'undefined' && typeof crypto.randomUUID === 'function') {\n return crypto.randomUUID();\n }\n // Fallback: 简易实现\n return 'xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx'.replace(/[xy]/g, c => {\n const r = Math.random() * 16 | 0;\n const v = c === 'x' ? r : (r & 0x3 | 0x8);\n return v.toString(16);\n });\n}\n\n/**\n * 截断超长 body 用于 debug 日志,避免刷屏。\n *\n * 调用方应先通过 `redactBody()` 做敏感字段脱敏,此函数只负责序列化 + 截断。\n */\nfunction truncate(body: unknown, maxChars = 500): string {\n try {\n const str = typeof body === 'string' ? body : JSON.stringify(body);\n if (str.length <= maxChars) return str;\n return str.slice(0, maxChars) + `…(truncated, total ${str.length} chars)`;\n } catch {\n return '[unserializable]';\n }\n}\n","/**\n * CloudAgentClient — SDK 顶层入口\n *\n * 持有 ConnectionOpts,提供 runtimes 子命名空间(仅控制面集合操作)。\n * 本身不发起网络请求、不持有连接。\n */\n\nimport type { ConnectionOpts, RequestOpts, RuntimeCreateOpts, RuntimeListOpts } from './opts';\nimport type { RuntimeInfo, PageResult, CreateRuntimeRequest } from './types';\nimport { Runtime } from './runtime';\nimport { RestClient } from './rest/client';\n\nexport class CloudAgentClient {\n private readonly opts: ConnectionOpts;\n /** @internal */\n readonly _restClient: RestClient;\n\n /** 构造(同步,不发网络请求) */\n constructor(opts: ConnectionOpts = {}) {\n // 认证策略由调用方决定:\n // - 后端:提供 apiKey\n // - 浏览器:通过 baseUrl 指向业务后端代理(由代理注入鉴权),或通过 headers 携带业务登录态\n // 这里不做强校验,请求失败时服务端会返回 401/403。\n this.opts = opts;\n this._restClient = new RestClient(opts);\n }\n\n /** 派生新实例(覆盖部分配置,如切换 sourceApp) */\n with(overrides: Partial<ConnectionOpts>): CloudAgentClient {\n return new CloudAgentClient({ ...this.opts, ...overrides });\n }\n\n // ============================================================\n // runtimes — 控制面集合操作\n // ============================================================\n\n readonly runtimes = {\n /**\n * 创建 Runtime(同步接口,返回时沙箱已 RUNNING)\n * 返回 Runtime 实例,可直接操作 sessions。\n */\n create: async (opts: RuntimeCreateOpts): Promise<Runtime> => {\n // 组装 REST body —— CreateRuntimeRequest 是后端 API 的权威镜像\n // (JSON.stringify 自动跳过 undefined 字段,不用手动 if-push)\n const body: CreateRuntimeRequest = {\n runtimeName: opts.runtimeName,\n agentManifest: opts.agentManifest,\n sandboxTemplateId: opts.sandboxTemplateId,\n sandboxSpec: opts.sandboxSpec,\n sandboxType: opts.sandboxType,\n visibility: opts.visibility,\n metadata: opts.metadata,\n };\n\n const info = await this._restClient.post<RuntimeInfo>(\n '/runtimes',\n body,\n {\n timeoutMs: opts.timeoutMs ?? 120_000,\n headers: opts.headers,\n signal: opts.signal,\n requestId: opts.requestId,\n }\n );\n\n return new Runtime(this._restClient, this.opts, info);\n },\n\n /** 获取 Runtime(返回实例) */\n get: async (runtimeId: string, opts?: RequestOpts): Promise<Runtime> => {\n const info = await this._restClient.get<RuntimeInfo>(`/runtimes/${runtimeId}`, undefined, opts);\n return new Runtime(this._restClient, this.opts, info);\n },\n\n /** 分页列表(返回纯数据) */\n list: async (opts?: RuntimeListOpts): Promise<PageResult<RuntimeInfo>> => {\n const params: Record<string, string> = {};\n if (opts?.page !== undefined) params.page = String(opts.page);\n if (opts?.pageSize !== undefined) params.pageSize = String(opts.pageSize);\n if (opts?.metadata) params.metadata = JSON.stringify(opts.metadata);\n return this._restClient.get<PageResult<RuntimeInfo>>('/runtimes', params, opts);\n },\n };\n}\n","/**\n * ManifestBuilder — Agent Manifest 构造器\n *\n * 按 manifest-spec.md v1.0 的 4 大类提供 fluent API。\n * 纯本地,不发网络请求。\n */\n\nimport type {\n AgentManifest,\n ManifestRule,\n ManifestSkill,\n ManifestSubagent,\n ManifestSlashCommand,\n ManifestPlugin,\n ManifestMcp,\n ManifestWorkspace,\n ManifestEnv,\n ManifestSecret,\n} from './types';\nimport { ValidationError } from './errors';\n\nexport class ManifestBuilder {\n // ─── 基础配置 ────────────────────────────────\n private _id?: string;\n private _name?: string;\n private _version?: string;\n private _systemPrompt?: string;\n private _systemPromptFile?: string;\n private _useWorkspaceRoot?: boolean;\n private _isolateConfigDir?: boolean;\n private _settings?: string;\n\n // ─── 能力与规范 ──────────────────────────────\n private _rules: ManifestRule[] = [];\n private _skills: ManifestSkill[] = [];\n private _subagents: ManifestSubagent[] = [];\n private _slashCommands: ManifestSlashCommand[] = [];\n private _plugins: ManifestPlugin[] = [];\n private _mcp: ManifestMcp[] = [];\n\n // ─── 工作空间 ────────────────────────────────\n private _workspaces: ManifestWorkspace[] = [];\n\n // ─── 环境配置 ────────────────────────────────\n private _secrets: ManifestSecret[] = [];\n private _envs: ManifestEnv[] = [];\n\n // ─── 扩展字段 ────────────────────────────────\n private _extra: Record<string, unknown> = {};\n\n // ============================================================\n // 基础配置\n // ============================================================\n\n id(id: string): this {\n this._id = id;\n return this;\n }\n\n name(name: string): this {\n this._name = name;\n return this;\n }\n\n version(version: string): this {\n this._version = version;\n return this;\n }\n\n systemPrompt(prompt: string): this {\n this._systemPrompt = prompt;\n this._systemPromptFile = undefined;\n return this;\n }\n\n systemPromptFile(url: string): this {\n this._systemPromptFile = url;\n this._systemPrompt = undefined;\n return this;\n }\n\n useWorkspaceRoot(value = true): this {\n this._useWorkspaceRoot = value;\n return this;\n }\n\n isolateConfigDir(value = true): this {\n this._isolateConfigDir = value;\n return this;\n }\n\n settings(url: string): this {\n this._settings = url;\n return this;\n }\n\n // ============================================================\n // 能力与规范(统一复数,接受单个或数组)\n // ============================================================\n\n rules(...rules: ManifestRule[]): this {\n this._rules.push(...rules);\n return this;\n }\n\n skills(...skills: Array<ManifestSkill | string>): this {\n for (const s of skills) {\n this._skills.push(typeof s === 'string' ? { name: s } : s);\n }\n return this;\n }\n\n subagents(...subagents: Array<ManifestSubagent | string>): this {\n for (const s of subagents) {\n this._subagents.push(typeof s === 'string' ? { name: s } : s);\n }\n return this;\n }\n\n slashCommands(...cmds: Array<ManifestSlashCommand | string>): this {\n for (const c of cmds) {\n this._slashCommands.push(typeof c === 'string' ? { name: c } : c);\n }\n return this;\n }\n\n plugins(...plugins: ManifestPlugin[]): this {\n this._plugins.push(...plugins);\n return this;\n }\n\n mcp(...mcps: ManifestMcp[]): this {\n this._mcp.push(...mcps);\n return this;\n }\n\n // ============================================================\n // 工作空间(统一复数)\n // ============================================================\n\n workspaces(...wss: ManifestWorkspace[]): this {\n this._workspaces.push(...wss);\n return this;\n }\n\n // ============================================================\n // 环境配置(统一复数)\n // ============================================================\n\n secrets(...secrets: ManifestSecret[]): this {\n this._secrets.push(...secrets);\n return this;\n }\n\n envs(...envs: ManifestEnv[]): this {\n this._envs.push(...envs);\n return this;\n }\n\n // ============================================================\n // 扩展\n // ============================================================\n\n /** 设置任意扩展字段 */\n raw(key: string, value: unknown): this {\n this._extra[key] = value;\n return this;\n }\n\n // ============================================================\n // 构建\n // ============================================================\n\n /** 校验必填字段并构建 */\n build(): AgentManifest {\n if (!this._id) throw new ValidationError('manifest.id is required');\n if (!this._name) throw new ValidationError('manifest.name is required');\n if (!this._version) throw new ValidationError('manifest.manifestVersion is required');\n if (this._systemPrompt && this._systemPromptFile) {\n throw new ValidationError('system_prompt and system_prompt_file are mutually exclusive');\n }\n\n const manifest: AgentManifest = {\n id: this._id,\n name: this._name,\n manifestVersion: this._version,\n };\n\n // 基础配置\n if (this._systemPrompt) manifest.system_prompt = this._systemPrompt;\n if (this._systemPromptFile) manifest.system_prompt_file = this._systemPromptFile;\n if (this._useWorkspaceRoot !== undefined) manifest.useWorkspaceRoot = this._useWorkspaceRoot;\n if (this._isolateConfigDir !== undefined) manifest.isolateConfigDir = this._isolateConfigDir;\n if (this._settings) manifest.settings = this._settings;\n\n // 能力与规范\n if (this._rules.length > 0) manifest.rules = this._rules;\n if (this._skills.length > 0) manifest.skills = this._skills;\n if (this._subagents.length > 0) manifest.subagents = this._subagents;\n if (this._slashCommands.length > 0) manifest.slashCommands = this._slashCommands;\n if (this._plugins.length > 0) manifest.plugins = this._plugins;\n if (this._mcp.length > 0) manifest.mcp = this._mcp;\n\n // 工作空间\n if (this._workspaces.length > 0) manifest.workspaces = this._workspaces;\n\n // 环境配置\n if (this._secrets.length > 0) manifest.secrets = this._secrets;\n if (this._envs.length > 0) manifest.envs = this._envs;\n\n // 扩展字段\n Object.assign(manifest, this._extra);\n\n return manifest;\n }\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"index.cjs","names":["TimeoutError","TimeoutError","TimeoutError","streamableHttp"],"sources":["../src/v1/internal/log.ts","../src/v1/errors.ts","../src/v1/internal/redact.ts","../src/v1/rest/client.ts","../src/v1/acp/vendor/sdk.ts","../src/v1/acp/transport.ts","../src/v1/acp/vendor/artifacts.ts","../src/v1/acp/vendor/acp-types.ts","../src/v1/acp/vendor/constants.ts","../src/v1/acp/vendor/errors.ts","../src/v1/acp/vendor/events.ts","../src/v1/acp/vendor/extensions.ts","../src/v1/acp/vendor/permissions.ts","../src/v1/acp/vendor/questions.ts","../src/v1/acp/vendor/client.ts","../src/v1/acp/client.ts","../src/v1/session.ts","../src/v1/runtime.ts","../src/v1/client.ts","../src/v1/manifest.ts"],"sourcesContent":["/**\n * 日志基础设施 — 对齐 OpenAI / Anthropic 官方 SDK 的做法\n *\n * - `LogLevel`: 5 级(`'off' | 'error' | 'warn' | 'info' | 'debug'`),默认 `'warn'`\n * - `loggerFor(opts)`: 返回一个按级别过滤后的 Logger\n * - 关闭的级别是**真正的空函数**(零字符串拼接开销)\n * - 开放的级别**直接 `bind` 原 logger**(保留调用点栈信息)\n * - 结果用 WeakMap 缓存,相同 `[logger, level]` 组合复用\n *\n * **日志 ID 策略**(对齐 Anthropic SDK):\n * SDK 日志**不自造本地 ID**。唯一的定位 ID 是服务端返回的 `requestId`\n * (`x-request-id` 响应头 / 业务 `body.requestId`),会以独立 debug 行\n * `\"request_id: <id>\"` 打出,也会挂在 `CloudAgentError.requestId` 上。\n * 重试链路可读性:通过 `\"Retrying request to ... in Nms (attempt 2/3): ...\"`\n * 这种独立告警行表达\"第几次重试\",无需额外 ID。\n * 业务维度定位(session / runtime / connection):通过日志前缀带上业务上下文\n * (如 `[acp conn=xxx]` / `[session sess_yyy] ...`)。\n */\n\nimport type { ConnectionOpts, Logger, LogLevel } from '../opts';\n\n/** 级别数值:越大越详细;方法级别 > 当前级别时,该方法变成 noop。 */\nconst LEVEL_NUMBER: Record<LogLevel, number> = {\n off: 0,\n error: 200,\n warn: 300,\n info: 400,\n debug: 500,\n};\n\n/** 默认级别(不配置时)。 */\nconst DEFAULT_LEVEL: LogLevel = 'warn';\n\n/** 真正的空函数。替换被关闭的级别,避免字符串拼接开销。 */\nconst noop = (): void => { /* intentionally empty */ };\n\n/** 全 noop 的 logger(内部单例)。 */\nconst noopLogger: Logger = {\n error: noop,\n warn: noop,\n info: noop,\n debug: noop,\n};\n\n/**\n * 缓存 `[baseLogger, logLevel] -> wrappedLogger`。\n *\n * 用 WeakMap<Logger, ...>:只要 user 传的 logger 引用不变、level 不变,就复用。\n */\nconst cache: WeakMap<Logger, Map<LogLevel, Logger>> = new WeakMap();\n\n/**\n * 解析级别字符串;非法值返回 undefined(调用方自行回退)。\n */\nexport function parseLogLevel(value: unknown): LogLevel | undefined {\n if (typeof value !== 'string') return undefined;\n const lower = value.toLowerCase();\n if (lower in LEVEL_NUMBER) return lower as LogLevel;\n return undefined;\n}\n\n/**\n * 读取环境变量 `CLOUD_AGENT_SDK_LOG`(仅 Node.js 环境,浏览器返回 undefined)。\n *\n * 用 `globalThis` 方式访问避免对 `@types/node` 的强依赖。\n */\nfunction readEnvLogLevel(): LogLevel | undefined {\n const g = globalThis as { process?: { env?: Record<string, string | undefined> } };\n const env = g.process?.env;\n if (!env) return undefined;\n return parseLogLevel(env.CLOUD_AGENT_SDK_LOG);\n}\n\n/**\n * 按 ConnectionOpts 决定最终的 LogLevel。\n *\n * 优先级:`opts.logLevel` > env `CLOUD_AGENT_SDK_LOG` > `'warn'`。\n */\nexport function resolveLogLevel(opts: ConnectionOpts): LogLevel {\n return parseLogLevel(opts.logLevel)\n ?? readEnvLogLevel()\n ?? DEFAULT_LEVEL;\n}\n\n/**\n * 返回按 `opts` 过滤后的 Logger。\n *\n * - `opts.logger` 为空时使用 `globalThis.console`\n * - 级别关闭时返回 noop,开启时返回 `baseLogger[fn].bind(baseLogger)`\n * - 相同入参多次调用复用同一对象(WeakMap 缓存)\n */\nexport function loggerFor(opts: ConnectionOpts): Logger {\n const base: Logger = opts.logger ?? console;\n const level = resolveLogLevel(opts);\n\n if (level === 'off') return noopLogger;\n\n let byLevel = cache.get(base);\n if (!byLevel) {\n byLevel = new Map();\n cache.set(base, byLevel);\n }\n const cached = byLevel.get(level);\n if (cached) return cached;\n\n const wrapped = makeLeveledLogger(base, level);\n byLevel.set(level, wrapped);\n return wrapped;\n}\n\n/** Logger 上真正存在的方法级别(排除 'off')。 */\ntype LoggerMethod = Exclude<LogLevel, 'off'>;\n\n/**\n * 按级别构造 Logger:开放的级别直接 bind,关闭的级别替换为 noop。\n *\n * bind 而非 wrap 是为了保留调用点的 stack trace(开发者看日志能点回 SDK 行号)。\n */\nfunction makeLeveledLogger(base: Logger, level: LogLevel): Logger {\n const threshold = LEVEL_NUMBER[level];\n const enable = (fn: LoggerMethod): Logger[LoggerMethod] =>\n LEVEL_NUMBER[fn] <= threshold && typeof base[fn] === 'function'\n ? base[fn].bind(base)\n : noop;\n return {\n error: enable('error'),\n warn: enable('warn'),\n info: enable('info'),\n debug: enable('debug'),\n };\n}\n","/**\n * 错误类型体系\n *\n * 对齐 Anthropic / OpenAI SDK 的做法 —— 只暴露**服务端 requestId**\n * 这一个定位 ID。SDK 内部日志通过 logger name (`cloud-agent-sdk`) 和\n * 业务上下文(sessionId / connectionId / runtimeId)做定位,用户侧想把\n * SDK 日志和业务日志串起来的标准姿势是 `AsyncLocalStorage` 注入业务 id\n * (见 docs 里的指南)。\n *\n * 重试决策**不**挂在错误类上。是否重试由 `RetryOpts.retryOn(err, ctx)` 统一决定\n * (见 `rest/client.ts` 里的 `DEFAULT_RETRY_ON`)。这样决策只有一个入口,\n * 用户可以通过 `retry: { retryOn: ... }` 完全覆盖。\n */\n\nexport interface CloudAgentErrorOpts {\n code?: number;\n httpStatus?: number;\n /**\n * 服务端返回的 `x-request-id` 或 body.requestId。\n * 贴给服务端团队排障用。网络错 / 超时时可能为 `undefined`\n * (请求还没到服务端),此时排查靠客户端日志(logger `cloud-agent-sdk`)。\n */\n requestId?: string;\n cause?: Error;\n}\n\nexport class CloudAgentError extends Error {\n readonly code: number;\n readonly httpStatus?: number;\n readonly requestId?: string;\n readonly originalCause?: Error;\n\n constructor(message: string, opts: CloudAgentErrorOpts = {}) {\n super(message);\n this.name = 'CloudAgentError';\n this.code = opts.code ?? -1;\n this.httpStatus = opts.httpStatus;\n this.requestId = opts.requestId;\n this.originalCause = opts.cause;\n // ES2022 cause polyfill\n if (opts.cause && !('cause' in this)) {\n Object.defineProperty(this, 'cause', { value: opts.cause, writable: false });\n }\n }\n}\n\nexport class NetworkError extends CloudAgentError {\n constructor(message: string, opts?: CloudAgentErrorOpts) {\n super(message, opts);\n this.name = 'NetworkError';\n }\n}\n\nexport class TimeoutError extends CloudAgentError {\n constructor(message: string, opts?: CloudAgentErrorOpts) {\n super(message, opts);\n this.name = 'TimeoutError';\n }\n}\n\nexport class AuthError extends CloudAgentError {\n constructor(message: string, opts?: CloudAgentErrorOpts) {\n super(message, opts);\n this.name = 'AuthError';\n }\n}\n\nexport class NotFoundError extends CloudAgentError {\n constructor(message: string, opts?: CloudAgentErrorOpts) {\n super(message, opts);\n this.name = 'NotFoundError';\n }\n}\n\nexport class ValidationError extends CloudAgentError {\n constructor(message: string, opts?: CloudAgentErrorOpts) {\n super(message, opts);\n this.name = 'ValidationError';\n }\n}\n\nexport class AcpProtocolError extends CloudAgentError {\n constructor(message: string, opts?: CloudAgentErrorOpts) {\n super(message, opts);\n this.name = 'AcpProtocolError';\n }\n}\n","/**\n * 敏感信息脱敏\n *\n * 范围:headers + 特定已知的 body 字段(白名单 path,非启发式猜测)。\n * 脱敏仅作用于日志打印和钩子回调,不影响实际发送的请求。\n *\n * 详见 docs/agentos/sdk/07-error-retry.md § 4.5。\n */\n\n/** 需要脱敏的 header 名(小写)。 */\nconst SENSITIVE_HEADER_NAMES: ReadonlySet<string> = new Set([\n 'authorization',\n 'cookie',\n 'set-cookie',\n 'x-api-key',\n]);\n\n/** 脱敏替换值。 */\nconst REDACTED = '***';\n\n/**\n * 返回脱敏后的 headers 副本。\n *\n * - 键按原样保留(大小写不变)\n * - 值按键名(小写后)匹配敏感列表时替换为 `'***'`\n * - **纯函数**,不修改入参\n */\nexport function redactHeaders(\n headers: Record<string, string> | undefined,\n): Record<string, string> {\n if (!headers) return {};\n const out: Record<string, string> = {};\n for (const [name, value] of Object.entries(headers)) {\n out[name] = SENSITIVE_HEADER_NAMES.has(name.toLowerCase()) ? REDACTED : value;\n }\n return out;\n}\n\n/**\n * 给定一个 header 名是否属于敏感名(小写比较)。\n *\n * 供扩展处使用(如需要自定义 Headers/Map 迭代的场景)。\n */\nexport function isSensitiveHeader(name: string): boolean {\n return SENSITIVE_HEADER_NAMES.has(name.toLowerCase());\n}\n\n// ─── Body 脱敏 ────────────────────────────────\n//\n// 与 OpenAI / Anthropic 官方 SDK 不同:它们的 body 只含 prompt / messages / tools\n// 等业务内容,没有高敏感字段,所以不脱敏。\n//\n// 我们的 `runtimes.create` / `sessions.create` body 里会携带 `agentManifest.secrets[].value`\n// —— 用户业务下发到 sandbox 的真实密钥(数据库密码、第三方 API Key 等),\n// 泄露后果远超 apiKey(apiKey 泄露只影响当前调用方,secret 泄露影响用户业务的下游)。\n//\n// 策略:\n// - **白名单**:只处理已知的、明确含密钥的字段(而非启发式猜测字段名)\n// - **深克隆**:不修改原始 body,只在日志/钩子里使用脱敏副本\n// - **未来扩展**:新增敏感字段时显式加到下面的 REDACTOR 表\n\n/** 判断 value 是否是对象数组(`Array<Record<string, unknown>>`)。 */\nfunction isObjectArray(v: unknown): v is Array<Record<string, unknown>> {\n return Array.isArray(v) && v.every(x => x !== null && typeof x === 'object' && !Array.isArray(x));\n}\n\n/**\n * Body 脱敏器:对给定对象做**浅复制 + 定向脱敏**,返回安全的日志副本。\n *\n * 不修改入参。若入参不是对象(string / number / ...),原样返回。\n *\n * 已处理字段:\n * - `agentManifest.secrets[].value` → `'***'`(保留 name,只脱 value)\n */\nexport function redactBody(body: unknown): unknown {\n if (body === null || body === undefined) return body;\n if (typeof body !== 'object' || Array.isArray(body)) return body;\n\n const input = body as Record<string, unknown>;\n // 浅复制 + 按 path 定向深复制\n const out: Record<string, unknown> = { ...input };\n\n // agentManifest.secrets[].value\n const manifest = input.agentManifest as Record<string, unknown> | undefined;\n if (manifest && typeof manifest === 'object' && !Array.isArray(manifest)) {\n const secrets = manifest.secrets;\n if (isObjectArray(secrets)) {\n out.agentManifest = {\n ...manifest,\n secrets: secrets.map(s => (\n 'value' in s ? { ...s, value: REDACTED } : s\n )),\n };\n }\n }\n\n return out;\n}\n","/**\n * REST 客户端 — 基于原生 fetch\n *\n * 职责:\n * - 注入认证 / 身份 / 自定义 header(apiKey / source* / user 定制)\n * - 统一解包 `{ code, msg, data, requestId }`,非 0 抛 `CloudAgentError`\n * - 超时控制(AbortController + AbortSignal 合并)\n * - 重试(指数退避 + 抖动;默认仅 GET 重试,非 GET 需显式 `retry`)\n * - 日志:对齐 Anthropic SDK —— 日志行不带自造 ID,只带**服务端 requestId**\n * 作为定位 ID;\"是否在重试 / 第几次重试\" 通过独立的告警行 + `attempt=N/M`\n * 字段表达,而非自造 logId/retryOf 链\n * - 脱敏:onRequest / onResponse 钩子 + debug 日志里的 headers 自动脱敏\n */\n\nimport type { ConnectionOpts, Logger, RequestOpts, RetryOpts, RetryContext, RetryOn } from '../opts';\nimport {\n CloudAgentError,\n NetworkError,\n TimeoutError,\n AuthError,\n NotFoundError,\n ValidationError,\n AcpProtocolError,\n} from '../errors';\nimport { loggerFor } from '../internal/log';\nimport { redactBody, redactHeaders } from '../internal/redact';\n\ninterface ApiResponse<T = unknown> {\n code: number;\n msg: string;\n requestId: string;\n data?: T;\n}\n\n/** 默认 baseUrl */\nconst DEFAULT_BASE_URL = 'https://www.codebuddy.cn/v2/agentos';\n\n/**\n * SDK 内置的默认重试判定。\n *\n * 传 `retry: { retryOn: ... }` 会**完全替换**这里的规则(不叠加)。\n * 公开这个函数是为了让用户在自定义 `retryOn` 里可以手动调用回落到默认:\n *\n * ```ts\n * retry: {\n * retryOn: (err, ctx) => {\n * if (err instanceof TimeoutError && ctx.url.includes('/upload')) return false;\n * return DEFAULT_RETRY_ON(err, ctx);\n * },\n * }\n * ```\n */\nexport const DEFAULT_RETRY_ON: RetryOn = (err, ctx) => {\n // 用户主动取消\n if (err.name === 'AbortError') return false;\n\n // SDK 业务错误:按类型决定\n if (err instanceof AuthError) return false;\n if (err instanceof NotFoundError) return false;\n if (err instanceof ValidationError) return false;\n if (err instanceof AcpProtocolError) return false;\n\n // 超时:仅幂等方法(GET)重试。POST / PATCH / DELETE 超时可能已成功执行,\n // 重试会造成重复副作用(如重复创建 Runtime)。\n if (err instanceof TimeoutError) return ctx.method === 'GET';\n\n // 网络错误:所有方法都可重试(连接根本没成功,不会有副作用)\n if (err instanceof NetworkError) return true;\n\n // 其他未知错误(例如 fetch 抛的原生 TypeError):保守重试\n return true;\n};\n\n/** 默认重试配置。 */\nconst DEFAULT_RETRY: Required<RetryOpts> = {\n maxAttempts: 3,\n backoffMs: 300,\n backoffFactor: 2,\n jitter: true,\n retryOn: DEFAULT_RETRY_ON,\n};\n\n/** 单次请求的内部上下文(跨 doRequest 复用)。 */\ninterface RequestContext {\n /** 尝试编号:首次=1,每次重试 +1。 */\n attempt: number;\n startTimeMs: number;\n}\n\nexport class RestClient {\n private readonly opts: ConnectionOpts;\n private readonly logger: Logger;\n private readonly fetchImpl: typeof fetch;\n\n constructor(opts: ConnectionOpts) {\n this.opts = opts;\n this.logger = loggerFor(opts);\n // 逃生舱:允许业务替换 fetch(如 OTel instrumented fetch);\n // 保留 bind(globalThis) 避免某些 runtime 上 this 绑定问题。\n const userFetch = opts.fetch;\n this.fetchImpl = userFetch ?? fetch.bind(globalThis);\n }\n\n /** GET 请求。 */\n async get<T>(path: string, query?: Record<string, string>, opts?: RequestOpts): Promise<T> {\n const url = this.buildUrl(path, query);\n return this.request<T>('GET', url, undefined, opts);\n }\n\n /** POST 请求。 */\n async post<T>(path: string, body?: unknown, opts?: RequestOpts): Promise<T> {\n const url = this.buildUrl(path);\n return this.request<T>('POST', url, body, opts);\n }\n\n /** PATCH 请求。 */\n async patch<T>(path: string, body?: unknown, opts?: RequestOpts): Promise<T> {\n const url = this.buildUrl(path);\n return this.request<T>('PATCH', url, body, opts);\n }\n\n /** DELETE 请求。 */\n async delete<T>(path: string, opts?: RequestOpts): Promise<T> {\n const url = this.buildUrl(path);\n return this.request<T>('DELETE', url, undefined, opts);\n }\n\n //\n // 是否重试由 `RetryOpts.retryOn(err, ctx)` 统一决定(见 DEFAULT_RETRY_ON):\n // GET/POST/PATCH/DELETE 全部进入 retry 链路,retryOn 按错误类型 + method\n // 精确决策(非幂等方法超时默认不重试,避免副作用)。\n\n // ─── 内部方法 ────────────────────────────────\n\n /** 构建完整 URL。 */\n private buildUrl(path: string, query?: Record<string, string>): string {\n const base = (this.opts.baseUrl || DEFAULT_BASE_URL).replace(/\\/+$/, '');\n const fullPath = path.startsWith('/') ? path : `/${path}`;\n const url = new URL(`${base}${fullPath}`);\n\n if (query) {\n for (const [k, v] of Object.entries(query)) {\n if (v !== undefined && v !== '') {\n url.searchParams.set(k, v);\n }\n }\n }\n\n return url.toString();\n }\n\n /** 构建请求 headers(含认证、身份、trace、自定义)。 */\n private buildHeaders(opts?: RequestOpts): Record<string, string> {\n const headers: Record<string, string> = {\n 'Content-Type': 'application/json',\n 'Accept': 'application/json',\n };\n\n // 认证:仅支持 apiKey(后端场景);浏览器场景通过 baseUrl 代理或自定义 headers 注入鉴权\n if (this.opts.apiKey) {\n headers['x-api-key'] = this.opts.apiKey;\n }\n\n // 身份 headers\n if (this.opts.sourceApp) headers['X-Source-App'] = this.opts.sourceApp;\n if (this.opts.sourceTenantId) headers['X-Source-Tenant-Id'] = this.opts.sourceTenantId;\n if (this.opts.userId) headers['X-User-Id'] = this.opts.userId;\n\n // 全局自定义 headers\n if (this.opts.headers) Object.assign(headers, this.opts.headers);\n\n // 逐请求覆盖 headers(用户可塞 traceparent 等,SDK 原样透传)\n if (opts?.headers) Object.assign(headers, opts.headers);\n\n // Request ID(不传则生成 UUID,用于服务端请求识别)\n headers['X-Request-Id'] = opts?.requestId ?? generateRequestId();\n\n return headers;\n }\n\n /** 发起请求(含超时 + 重试 + 日志 + 脱敏 + hooks)。 */\n private async request<T>(method: string, url: string, body?: unknown, opts?: RequestOpts): Promise<T> {\n // 确定重试策略。优先级:per-request `opts.retry` > 全局 `this.opts.retry` > DEFAULT_RETRY。\n // 传 `false` 关闭重试;method 相关的精细决策交给 `retryOn(err, ctx)`。\n const shouldRetry: RetryOpts | false = opts?.retry !== undefined\n ? opts.retry\n : this.opts.retry ?? DEFAULT_RETRY;\n\n const ctx: RequestContext = {\n attempt: 1,\n startTimeMs: 0,\n };\n\n const doRequest = async (): Promise<T> => {\n ctx.startTimeMs = Date.now();\n const timeoutMs = opts?.timeoutMs ?? this.opts.timeoutMs ?? 30_000;\n const headers = this.buildHeaders(opts);\n const requestId = headers['X-Request-Id'];\n\n // 构建 abort 信号\n const controller = new AbortController();\n let timeoutId: ReturnType<typeof setTimeout> | undefined;\n\n if (timeoutMs > 0) {\n timeoutId = setTimeout(() => controller.abort(), timeoutMs);\n }\n\n // 外部 signal 合并\n if (opts?.signal) {\n if (opts.signal.aborted) {\n controller.abort();\n } else {\n opts.signal.addEventListener('abort', () => controller.abort(), { once: true });\n }\n }\n\n const redactedReqHeaders = redactHeaders(headers);\n\n // 触发 onRequest hook(传脱敏后的 headers 副本)\n this.opts.onRequest?.({ method, url, headers: { ...redactedReqHeaders } });\n\n // 对齐 Anthropic SDK:debug 两段(发出 + 响应)+ 独立 request_id 行。\n // 首次请求不带 attempt 前缀(减噪音),重试由 withRetry 的独立告警行承担。\n this.logger.debug(\n `Sending HTTP Request: ${method} ${url}`,\n {\n headers: redactedReqHeaders,\n body: body !== undefined ? truncate(redactBody(body)) : undefined,\n },\n );\n\n try {\n const response = await this.fetchImpl(url, {\n method,\n headers,\n body: body !== undefined ? JSON.stringify(body) : undefined,\n signal: controller.signal,\n });\n\n const durationMs = Date.now() - ctx.startTimeMs;\n\n // 收集响应 headers(脱敏后用于 hook/日志)\n const responseHeaders: Record<string, string> = {};\n response.headers.forEach((v, k) => { responseHeaders[k] = v; });\n const redactedResHeaders = redactHeaders(responseHeaders);\n\n this.opts.onResponse?.({\n status: response.status,\n headers: { ...redactedResHeaders },\n url,\n });\n\n // 服务端 request-id 响应头(不同于客户端传的 X-Request-Id,部分网关会回填)\n const serverReqId = response.headers.get('x-request-id') ?? requestId;\n // 对齐 Anthropic:\n // HTTP Response: POST <url> \"201 Created\" durationMs=...\n // request_id: <serverReqId>\n this.logger.debug(\n `HTTP Response: ${method} ${url} \"${response.status} ${response.statusText}\" durationMs=${durationMs}`,\n { headers: redactedResHeaders },\n );\n if (serverReqId) {\n this.logger.debug(`request_id: ${serverReqId}`);\n }\n\n // 解包\n return await this.unwrap<T>(response, serverReqId);\n } catch (err) {\n if (timeoutId) clearTimeout(timeoutId);\n\n const durationMs = Date.now() - ctx.startTimeMs;\n\n // AbortError → 判断是超时还是用户取消\n if (err instanceof Error && err.name === 'AbortError') {\n if (opts?.signal?.aborted) {\n this.logger.debug(\n `Request cancelled by caller after ${durationMs}ms: ${method} ${url}`,\n );\n throw err; // 用户主动取消,不包装\n }\n // 超时:仅 GET 默认重试(见 DEFAULT_RETRY_ON),非 GET 超时\n // 立即抛出避免重复副作用。这里只打 debug,避免重试循环里\n // \"Request timed out\" warn + withRetry 的 \"retrying\" warn 双倍刷屏。\n // 最终失败(重试耗尽)由调用方 catch 决定是否上报。\n const msg = `Request timed out after ${timeoutMs}ms: ${method} ${url}`;\n this.logger.debug(msg);\n throw new TimeoutError(msg, { cause: err });\n }\n\n // fetch 网络错误\n // 注意:这里只打 debug,真正可见的重试告警由 withRetry 的 \"retrying...\" warn 承担,\n // 避免重试循环中 \"NetworkError\" warn + \"retrying\" warn 双倍刷屏。\n // 最终失败(重试耗尽)时由调用方的 catch 决定是否上报。\n if (err instanceof TypeError || (err instanceof Error && isNetworkError(err))) {\n const msg = `Network error: ${method} ${url} - ${(err as Error).message}`;\n this.logger.debug(msg);\n throw new NetworkError(msg, {\n cause: err as Error,\n });\n }\n\n // 已是 CloudAgentError 则直接抛(它本身已带 requestId)\n if (err instanceof CloudAgentError) {\n throw err;\n }\n\n // 意外异常(非网络、非超时、非业务错):值得 error 级别\n const msg = `Unexpected error: ${method} ${url} - ${(err as Error).message}`;\n this.logger.error(msg);\n throw new NetworkError(msg, { cause: err as Error });\n } finally {\n if (timeoutId) clearTimeout(timeoutId);\n }\n };\n\n // 包装重试\n if (shouldRetry === false) {\n return doRequest();\n }\n\n return this.withRetry(doRequest, shouldRetry, ctx, method, url);\n }\n\n /** 解包响应 `{ code, msg, data }` → `data` 或抛错。 */\n private async unwrap<T>(response: Response, serverReqId?: string): Promise<T> {\n // 对于 204 No Content\n if (response.status === 204) {\n return undefined as unknown as T;\n }\n\n let body: ApiResponse<T> | undefined;\n let rawText: string;\n try {\n // 用 text + 正则处理 int64 大数精度丢失\n // 将 17 位及以上的纯数字值转为字符串(MAX_SAFE_INTEGER = 9007199254740991,16 位)\n rawText = await response.text();\n const safeText = rawText.replace(\n /:\\s*(\\d{17,})/g,\n (match, num) => match.replace(num, `\"${num}\"`),\n );\n body = JSON.parse(safeText) as ApiResponse<T>;\n } catch {\n // 非 JSON 响应\n if (!response.ok) {\n throw this.httpStatusToError(response.status, `HTTP ${response.status}`, {\n requestId: serverReqId,\n });\n }\n return (rawText! as unknown) as T;\n }\n\n // 服务端返回的 requestId 两个来源:\n // - body.requestId:由 middleware 写入 gin ctx 后由错误/成功响应包装器读出(业务层值)\n // - response header X-Request-Id:由 RequestIDMiddleware 直接回显\n // 两者在正常路径上是同一个值(都来自 middleware),优先 body 是因为:\n // 1) 4xx/5xx 非 JSON 时 body 可能解析不到,header 是最后兜底\n // 2) body 是服务端\"明确意图\"返回的字段,header 可能被反代重写\n // 服务端源码: services/pkg/middleware/request_id.go\n const effectiveRequestId = body.requestId || serverReqId;\n\n // HTTP 层错误\n if (!response.ok) {\n throw this.httpStatusToError(\n response.status,\n body.msg || `HTTP ${response.status}`,\n { requestId: effectiveRequestId, code: body.code },\n );\n }\n\n // 业务层错误 (code !== 0)\n if (body.code !== 0) {\n throw this.codeToError(body.code, body.msg, {\n requestId: effectiveRequestId,\n httpStatus: response.status,\n });\n }\n\n return body.data as T;\n }\n\n /** HTTP 状态码映射为错误。 */\n private httpStatusToError(\n status: number,\n message: string,\n ctx: { requestId?: string; code?: number },\n ): CloudAgentError {\n const opts = { httpStatus: status, requestId: ctx.requestId, code: ctx.code };\n\n switch (status) {\n case 400:\n return new ValidationError(message, opts);\n case 401:\n case 403:\n return new AuthError(message, opts);\n case 404:\n return new NotFoundError(message, opts);\n case 408:\n case 504:\n return new TimeoutError(message, opts);\n case 429:\n return new NetworkError(message, opts);\n default:\n if (status >= 500) {\n return new NetworkError(message, opts);\n }\n return new CloudAgentError(message, opts);\n }\n }\n\n /** 业务 code 映射为错误。 */\n private codeToError(\n code: number,\n message: string,\n ctx: { requestId?: string; httpStatus?: number },\n ): CloudAgentError {\n const opts = { code, httpStatus: ctx.httpStatus, requestId: ctx.requestId };\n\n // 按照 code 映射到具体子类\n switch (code) {\n case 10001:\n return new ValidationError(message, opts);\n case 10034:\n case 10085:\n return new AuthError(message, opts);\n case 10064:\n case 10065:\n case 10067:\n return new NetworkError(message, opts);\n case 10084:\n return new NotFoundError(message, opts);\n case 10094:\n return new TimeoutError(message, opts);\n case 10000:\n return new NetworkError(message, opts);\n default:\n return new CloudAgentError(message, opts);\n }\n }\n\n /**\n * 重试逻辑。\n *\n * 是否重试只看 `opts.retryOn(err, ctx)`。用户传的 retryOn **完全替换** SDK\n * 默认判定(不叠加、不 fallback 到 error 类上的任何字段)。\n */\n private async withRetry<T>(\n fn: () => Promise<T>,\n retryOpts: RetryOpts,\n reqCtx: RequestContext,\n method: string,\n url: string,\n ): Promise<T> {\n const opts = { ...DEFAULT_RETRY, ...retryOpts };\n let lastError: Error | undefined;\n\n for (let attempt = 1; attempt <= opts.maxAttempts; attempt++) {\n reqCtx.attempt = attempt;\n try {\n return await fn();\n } catch (err) {\n lastError = err as Error;\n\n const retryCtx: RetryContext = { attempt, method, url };\n if (!opts.retryOn(err as Error, retryCtx)) {\n throw err;\n }\n\n // 最后一次尝试不再退避\n if (attempt >= opts.maxAttempts) {\n break;\n }\n\n const delayMs = this.getBackoffMs(attempt, opts);\n // 对齐 Anthropic:\"Retrying request to ... in N seconds\"\n this.logger.warn(\n `Retrying request to ${method} ${url} in ${delayMs}ms (attempt ${attempt}/${opts.maxAttempts}): ${(err as Error).name}: ${(err as Error).message}`,\n );\n\n await sleep(delayMs);\n }\n }\n\n throw lastError!;\n }\n\n /** 计算退避时间。 */\n private getBackoffMs(attempt: number, opts: Required<RetryOpts>): number {\n const baseDelay = Math.min(\n opts.backoffMs * Math.pow(opts.backoffFactor, attempt - 1),\n 30_000, // 最大退避 30s\n );\n\n if (!opts.jitter) {\n return Math.round(baseDelay);\n }\n\n // ±20% 随机抖动\n const jitterFactor = 0.2 * (Math.random() * 2 - 1);\n return Math.round(baseDelay * (1 + jitterFactor));\n }\n}\n\n// ─── 工具函数 ────────────────────────────────\n\nfunction sleep(ms: number): Promise<void> {\n return new Promise(resolve => setTimeout(resolve, ms));\n}\n\nfunction isNetworkError(err: Error): boolean {\n const msg = err.message.toLowerCase();\n return msg.includes('failed to fetch')\n || msg.includes('fetch failed')\n || msg.includes('network')\n || msg.includes('econnrefused')\n || msg.includes('econnreset')\n || msg.includes('enotfound')\n || msg.includes('socket hang up');\n}\n\nfunction generateRequestId(): string {\n // 简单的随机 ID 生成,兼容浏览器和 Node.js\n if (typeof crypto !== 'undefined' && typeof crypto.randomUUID === 'function') {\n return crypto.randomUUID();\n }\n // Fallback: 简易实现\n return 'xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx'.replace(/[xy]/g, c => {\n const r = Math.random() * 16 | 0;\n const v = c === 'x' ? r : (r & 0x3 | 0x8);\n return v.toString(16);\n });\n}\n\n/**\n * 截断超长 body 用于 debug 日志,避免刷屏。\n *\n * 调用方应先通过 `redactBody()` 做敏感字段脱敏,此函数只负责序列化 + 截断。\n */\nfunction truncate(body: unknown, maxChars = 500): string {\n try {\n const str = typeof body === 'string' ? body : JSON.stringify(body);\n if (str.length <= maxChars) return str;\n return str.slice(0, maxChars) + `…(truncated, total ${str.length} chars)`;\n } catch {\n return '[unserializable]';\n }\n}\n","/**\n * SDK Type Re-exports and Capability Extensions\n *\n * This file provides:\n * 1. Re-exports of commonly used types from @agentclientprotocol/sdk\n * 2. Extended capability types with codebuddy.ai metadata\n */\n\n// ============================================\n// SDK Type Re-exports\n// ============================================\n\n// ============================================\n// codebuddy.ai Capability Extensions\n// ============================================\n\nimport type { ArtifactType } from './acp-types.js';\n\ntype SdkClientCapabilities = import('@agentclientprotocol/sdk', { with: { 'resolution-mode': 'import' } }).ClientCapabilities;\ntype SdkAgentCapabilities = import('@agentclientprotocol/sdk', { with: { 'resolution-mode': 'import' } }).AgentCapabilities;\n\nexport type InitializeRequest = import('@agentclientprotocol/sdk', { with: { 'resolution-mode': 'import' } }).InitializeRequest;\nexport type InitializeResponse = import('@agentclientprotocol/sdk', { with: { 'resolution-mode': 'import' } }).InitializeResponse;\nexport type NewSessionRequest = import('@agentclientprotocol/sdk', { with: { 'resolution-mode': 'import' } }).NewSessionRequest;\nexport type NewSessionResponse = import('@agentclientprotocol/sdk', { with: { 'resolution-mode': 'import' } }).NewSessionResponse;\nexport type LoadSessionRequest = import('@agentclientprotocol/sdk', { with: { 'resolution-mode': 'import' } }).LoadSessionRequest;\nexport type LoadSessionResponse = import('@agentclientprotocol/sdk', { with: { 'resolution-mode': 'import' } }).LoadSessionResponse;\nexport type PromptRequest = import('@agentclientprotocol/sdk', { with: { 'resolution-mode': 'import' } }).PromptRequest;\nexport type PromptResponse = import('@agentclientprotocol/sdk', { with: { 'resolution-mode': 'import' } }).PromptResponse;\nexport type CancelNotification = import('@agentclientprotocol/sdk', { with: { 'resolution-mode': 'import' } }).CancelNotification;\nexport type RequestPermissionRequest = import('@agentclientprotocol/sdk', { with: { 'resolution-mode': 'import' } }).RequestPermissionRequest;\nexport type RequestPermissionResponse = import('@agentclientprotocol/sdk', { with: { 'resolution-mode': 'import' } }).RequestPermissionResponse;\nexport type SessionNotification = import('@agentclientprotocol/sdk', { with: { 'resolution-mode': 'import' } }).SessionNotification;\nexport type ContentBlock = import('@agentclientprotocol/sdk', { with: { 'resolution-mode': 'import' } }).ContentBlock;\nexport type TextContent = import('@agentclientprotocol/sdk', { with: { 'resolution-mode': 'import' } }).TextContent;\nexport type ImageContent = import('@agentclientprotocol/sdk', { with: { 'resolution-mode': 'import' } }).ImageContent;\nexport type AudioContent = import('@agentclientprotocol/sdk', { with: { 'resolution-mode': 'import' } }).AudioContent;\nexport type ResourceLink = import('@agentclientprotocol/sdk', { with: { 'resolution-mode': 'import' } }).ResourceLink;\nexport type EmbeddedResource = import('@agentclientprotocol/sdk', { with: { 'resolution-mode': 'import' } }).EmbeddedResource;\nexport type ToolCallContent = import('@agentclientprotocol/sdk', { with: { 'resolution-mode': 'import' } }).ToolCallContent;\nexport type ToolCallStatus = import('@agentclientprotocol/sdk', { with: { 'resolution-mode': 'import' } }).ToolCallStatus;\nexport type ToolKind = import('@agentclientprotocol/sdk', { with: { 'resolution-mode': 'import' } }).ToolKind;\nexport type Client = import('@agentclientprotocol/sdk', { with: { 'resolution-mode': 'import' } }).Client;\nexport type SetSessionModelRequest = import('@agentclientprotocol/sdk', { with: { 'resolution-mode': 'import' } }).SetSessionModelRequest;\nexport type SetSessionModelResponse = import('@agentclientprotocol/sdk', { with: { 'resolution-mode': 'import' } }).SetSessionModelResponse;\nexport type SetSessionModeRequest = import('@agentclientprotocol/sdk', { with: { 'resolution-mode': 'import' } }).SetSessionModeRequest;\nexport type SetSessionModeResponse = import('@agentclientprotocol/sdk', { with: { 'resolution-mode': 'import' } }).SetSessionModeResponse;\nexport type Stream = import('@agentclientprotocol/sdk', { with: { 'resolution-mode': 'import' } }).Stream;\nexport type { SdkClientCapabilities, SdkAgentCapabilities };\n\n// ACP TS SDK v0.18.2 exports this from schema/index.js as a simple numeric constant.\n// Re-declare it locally so CommonJS consumers don't need to statically import an ESM package.\nexport const PROTOCOL_VERSION = 1 as const;\n\nexport async function loadAcpSdk(): Promise<typeof import('@agentclientprotocol/sdk', { with: { 'resolution-mode': 'import' } })> {\n return import('@agentclientprotocol/sdk') as Promise<typeof import('@agentclientprotocol/sdk', { with: { 'resolution-mode': 'import' } })>;\n}\n\n/**\n * Configuration for a specific artifact type\n */\nexport interface ArtifactTypeConfig {\n /** Whether this artifact type is enabled */\n enabled?: boolean;\n}\n\n/**\n * Artifacts configuration in codebuddy.ai extension\n */\nexport type ArtifactsConfig = {\n [K in ArtifactType]?: ArtifactTypeConfig;\n};\n\n/**\n * codebuddy.ai extension capabilities for Client\n * Symmetric with CodebuddyAgentMeta for capability negotiation\n */\nexport interface CodebuddyClientMeta {\n /** Artifact types the client supports receiving */\n artifacts?: ArtifactsConfig;\n /** Whether the client supports checkpoint notifications */\n checkpoint?: boolean;\n /**\n * Whether the client supports handling AskUserQuestion tool via extMethod.\n * When true, AskUserQuestion requests will be sent to the client via\n * the '_codebuddy.ai/question' extMethod instead of being handled locally.\n */\n question?: boolean;\n}\n\n/**\n * codebuddy.ai extension capabilities for Agent\n */\nexport interface CodebuddyAgentMeta {\n /** Artifact types the agent can produce */\n artifacts?: ArtifactsConfig;\n /** Whether the agent supports checkpoint notifications */\n checkpoint?: boolean;\n}\n\n/**\n * Client capabilities with codebuddy.ai extensions\n */\nexport type ClientCapabilities = Omit<SdkClientCapabilities, '_meta'> & {\n /** Extension methods the client can handle (e.g., '_codebuddy.ai/*') */\n extensions?: string[];\n _meta?: {\n 'codebuddy.ai'?: CodebuddyClientMeta;\n [key: string]: unknown;\n } | null;\n};\n\n/**\n * Agent capabilities with codebuddy.ai extensions\n */\nexport type AgentCapabilities = Omit<SdkAgentCapabilities, '_meta'> & {\n /** Extension methods supported by this agent (e.g., '_codebuddy.ai/*') */\n extensions?: string[];\n _meta?: {\n 'codebuddy.ai'?: CodebuddyAgentMeta;\n [key: string]: unknown;\n } | null;\n};\n","/**\n * Streamable HTTP Transport for ACP\n *\n * 从 @genie/agent-client-protocol/src/common/transport/streamable-http.ts 迁移。\n * 实现官方 @agentclientprotocol/sdk 的 Stream 接口。\n *\n * 协议流程:\n * 1. Client 建立 GET SSE 连接,获取 Acp-Connection-Id\n * 2. Client 通过 POST 发送 JSON-RPC 请求(携带 Acp-Connection-Id header)\n * 3. 通知通过 GET SSE 推送,响应通过 POST SSE 返回\n *\n * 稳定性保证:\n * - 指数退避自动重连 + ±25% jitter\n * - Last-Event-ID 断点续传\n * - Acp-Connection-Id 复用\n * - 心跳超时检测(默认 60s)\n * - connectionVersion 防竞态\n * - backpressure 保护(highWaterMark/lowWaterMark)\n * - POST SSE 后台处理(防死锁)\n */\n\nexport interface StreamableHttpTransportOptions {\n /** ACP endpoint URL */\n endpoint: string;\n /** Authorization token (Bearer) */\n authToken?: string;\n /** Custom headers */\n headers?: Record<string, string>;\n /** Reconnect options */\n reconnect?: {\n enabled?: boolean; // default: true\n initialDelay?: number; // ms, default: 1000\n maxDelay?: number; // ms, default: 30000\n maxRetries?: number; // default: Infinity\n jitter?: boolean; // default: true (±25%)\n };\n /** AbortSignal to cancel */\n signal?: AbortSignal;\n /** Custom fetch */\n fetch?: typeof fetch;\n /** Callbacks */\n onConnect?: (connectionId: string) => void;\n onDisconnect?: (connectionId: string) => void;\n onError?: (error: Error) => void;\n /** Heartbeat timeout ms (default: 60000). 0 to disable. */\n heartbeatTimeout?: number;\n /** Connection establishment timeout ms (default: 30000) */\n connectionTimeout?: number;\n /** POST request timeout ms (default: 30000) */\n postTimeout?: number;\n /** Backpressure options */\n backpressure?: {\n highWaterMark?: number; // default: 100\n lowWaterMark?: number; // default: 50\n pauseTimeout?: number; // default: 5000ms\n };\n}\n\n/** Transport 接口(兼容 @agentclientprotocol/sdk 的 Stream) */\nexport interface StreamableHttpTransport {\n readonly readable: ReadableStream<unknown>;\n readonly writable: WritableStream<unknown>;\n readonly connectionId: string | undefined;\n readonly ready: Promise<void>;\n close(): Promise<void>;\n}\n\ninterface SSEEvent {\n type: string;\n data: string;\n id?: string;\n}\n\n/**\n * 创建 Streamable HTTP transport。\n * 返回的对象实现 Stream 接口(readable + writable),可直接传给 ClientSideConnection。\n */\nexport function createStreamableHttpTransport(options: StreamableHttpTransportOptions): StreamableHttpTransport {\n const {\n endpoint,\n authToken,\n headers: customHeaders = {},\n reconnect = {},\n signal: externalSignal,\n fetch: customFetch = globalThis.fetch,\n onConnect,\n onDisconnect,\n onError,\n heartbeatTimeout = 60000,\n connectionTimeout = 30000,\n postTimeout = 30000,\n backpressure = {},\n } = options;\n\n const {\n enabled: reconnectEnabled = true,\n initialDelay = 1000,\n maxDelay = 30000,\n maxRetries = Infinity,\n jitter: jitterEnabled = true,\n } = reconnect;\n\n const {\n highWaterMark = 100,\n lowWaterMark = 50,\n pauseTimeout = 5000,\n } = backpressure;\n\n // 连接状态\n let connectionId: string | undefined;\n let lastEventId: string | undefined;\n let reconnectAttempts = 0;\n let closed = false;\n let isClosing = false;\n let connectionVersion = 0;\n\n // 连接就绪 promise\n let connectionReady: Promise<void>;\n let resolveConnection: () => void;\n let rejectConnection: (error: Error) => void;\n\n connectionReady = new Promise((resolve, reject) => {\n resolveConnection = resolve;\n rejectConnection = reject;\n });\n\n const abortController = new AbortController();\n\n function isAborted(): boolean {\n return abortController.signal.aborted || (externalSignal?.aborted ?? false);\n }\n\n // 消息队列 + backpressure\n const messageQueue: unknown[] = [];\n const messageResolvers: Array<(value: unknown | null) => void> = [];\n let streamError: Error | null = null;\n let isPaused = false;\n let resumeReading: (() => void) | null = null;\n\n // 心跳\n let lastActivity = Date.now();\n let heartbeatCheckTimer: ReturnType<typeof setInterval> | undefined;\n\n function enqueueMessage(message: unknown): void {\n if (messageResolvers.length > 0) {\n messageResolvers.shift()!(message);\n } else {\n messageQueue.push(message);\n if (messageQueue.length >= highWaterMark) {\n isPaused = true;\n }\n }\n }\n\n function dequeueMessage(): Promise<unknown | null> {\n if (closed) return Promise.resolve(null);\n if (streamError) return Promise.reject(streamError);\n if (messageQueue.length > 0) {\n const message = messageQueue.shift()!;\n if (isPaused && messageQueue.length <= lowWaterMark) {\n isPaused = false;\n if (resumeReading) { queueMicrotask(() => resumeReading!()); }\n }\n return Promise.resolve(message);\n }\n return new Promise(resolve => { messageResolvers.push(resolve); });\n }\n\n function updateLastActivity(): void { lastActivity = Date.now(); }\n\n function startHeartbeatCheck(triggerReconnect: () => void): void {\n if (heartbeatTimeout <= 0) return;\n heartbeatCheckTimer = setInterval(() => {\n if (Date.now() - lastActivity > heartbeatTimeout) {\n triggerReconnect();\n }\n }, 10000);\n }\n\n function stopHeartbeatCheck(): void {\n if (heartbeatCheckTimer) { clearInterval(heartbeatCheckTimer); heartbeatCheckTimer = undefined; }\n }\n\n function calculateDelay(attempt: number): number {\n const baseDelay = Math.min(initialDelay * Math.pow(2, attempt - 1), maxDelay);\n if (!jitterEnabled) return baseDelay;\n const jitterFactor = 0.25 * (Math.random() * 2 - 1);\n return Math.round(baseDelay * (1 + jitterFactor));\n }\n\n function closeWithError(error: Error): void {\n streamError = error;\n closed = true;\n stopHeartbeatCheck();\n if (resumeReading) { resumeReading(); resumeReading = null; }\n rejectConnection(error);\n onError?.(error);\n while (messageResolvers.length > 0) { messageResolvers.shift()!(null); }\n }\n\n function closeNormally(): void {\n closed = true;\n stopHeartbeatCheck();\n if (resumeReading) { resumeReading(); resumeReading = null; }\n while (messageResolvers.length > 0) { messageResolvers.shift()!(null); }\n }\n\n function buildHeaders(): Record<string, string> {\n const headers: Record<string, string> = { ...customHeaders };\n if (authToken) headers['Authorization'] = `Bearer ${authToken}`;\n return headers;\n }\n\n // SSE 流处理\n async function processSSEStream(reader: ReadableStreamDefaultReader<Uint8Array>): Promise<void> {\n const decoder = new TextDecoder();\n let buffer = '';\n let currentEvent: Partial<SSEEvent> = {};\n\n try {\n while (true) {\n if (isPaused) {\n await new Promise<void>(resolve => {\n let resolved = false;\n const timeoutId = setTimeout(() => {\n if (!resolved) { resolved = true; resolve(); }\n }, pauseTimeout);\n resumeReading = () => {\n if (!resolved) { resolved = true; clearTimeout(timeoutId); resolve(); }\n };\n });\n resumeReading = null;\n }\n\n const { value, done } = await reader.read();\n if (done) break;\n\n buffer += decoder.decode(value, { stream: true });\n const lines = buffer.split('\\n');\n buffer = lines.pop() || '';\n\n for (const line of lines) {\n if (line === '') {\n if (currentEvent.data) {\n updateLastActivity();\n if (currentEvent.id) lastEventId = currentEvent.id;\n if (currentEvent.type === 'message' || !currentEvent.type) {\n try {\n const message = JSON.parse(currentEvent.data);\n if (message && typeof message === 'object' && 'jsonrpc' in message) {\n enqueueMessage(message);\n }\n } catch { /* ignore */ }\n }\n }\n currentEvent = {};\n } else if (line.startsWith(':')) {\n updateLastActivity(); // 心跳\n } else {\n const colonIdx = line.indexOf(':');\n if (colonIdx === -1) continue;\n const field = line.slice(0, colonIdx);\n let val = line.slice(colonIdx + 1);\n if (val.startsWith(' ')) val = val.slice(1);\n switch (field) {\n case 'event':\n if (currentEvent.type && currentEvent.type !== val) currentEvent.data = undefined;\n currentEvent.type = val; break;\n case 'data':\n currentEvent.data = (currentEvent.data || '') + val; break;\n case 'id':\n currentEvent.id = val; break;\n }\n }\n }\n }\n } finally {\n reader.releaseLock();\n }\n }\n\n function processSSEStreamBackground(reader: ReadableStreamDefaultReader<Uint8Array>): void {\n processSSEStream(reader).catch(error => {\n onError?.(error instanceof Error ? error : new Error(String(error)));\n });\n }\n\n // GET SSE 连接循环\n async function startSSEConnection(): Promise<void> {\n let currentReader: ReadableStreamDefaultReader<Uint8Array> | null = null;\n\n const triggerReconnect = (): void => {\n currentReader?.cancel().catch(() => {});\n };\n\n while (!closed && !isAborted()) {\n try {\n const headers = buildHeaders();\n headers['Accept'] = 'text/event-stream';\n if (lastEventId) headers['Last-Event-ID'] = lastEventId;\n if (connectionId) headers['Acp-Connection-Id'] = connectionId;\n\n const connectController = new AbortController();\n const connectTimer = setTimeout(() => connectController.abort(), connectionTimeout > 0 ? connectionTimeout : 30000);\n if (externalSignal) externalSignal.addEventListener('abort', () => connectController.abort(), { once: true });\n abortController.signal.addEventListener('abort', () => connectController.abort(), { once: true });\n\n let response: Response;\n try {\n response = await customFetch(endpoint, { method: 'GET', headers, signal: connectController.signal });\n } finally {\n clearTimeout(connectTimer);\n }\n\n if (!response.ok) throw new Error(`HTTP ${response.status}`);\n\n const newConnectionId = response.headers.get('Acp-Connection-Id');\n if (!newConnectionId) throw new Error('Server did not return Acp-Connection-Id');\n\n const previousConnectionId = connectionId;\n connectionVersion++;\n connectionId = newConnectionId;\n resolveConnection();\n\n if (previousConnectionId && previousConnectionId !== newConnectionId) {\n onDisconnect?.(previousConnectionId);\n }\n onConnect?.(newConnectionId);\n reconnectAttempts = 0;\n\n updateLastActivity();\n startHeartbeatCheck(triggerReconnect);\n\n const reader = response.body?.getReader();\n if (reader) {\n currentReader = reader;\n await processSSEStream(reader);\n currentReader = null;\n }\n\n stopHeartbeatCheck();\n const endedConnectionId = connectionId;\n connectionId = undefined;\n if (endedConnectionId) onDisconnect?.(endedConnectionId);\n\n if (!reconnectEnabled || closed) break;\n\n connectionReady = new Promise((resolve, reject) => {\n resolveConnection = resolve;\n rejectConnection = reject;\n });\n\n const reconnectDelay = calculateDelay(1);\n await new Promise(resolve => setTimeout(resolve, reconnectDelay));\n\n } catch (error) {\n stopHeartbeatCheck();\n currentReader = null;\n if (isAborted() || closed) break;\n\n reconnectAttempts++;\n if (reconnectAttempts > maxRetries) {\n closeWithError(new Error(`SSE reconnect failed after ${maxRetries} attempts`));\n break;\n }\n\n const delay = calculateDelay(reconnectAttempts);\n await new Promise(resolve => setTimeout(resolve, delay));\n }\n }\n }\n\n // POST 发送消息\n async function sendMessage(message: unknown): Promise<void> {\n if (closed) throw new Error('Connection is closed');\n\n // 等待连接稳定(防竞态)\n const maxWaitAttempts = 5;\n let currentConnectionId: string | undefined;\n\n for (let attempt = 0; attempt < maxWaitAttempts; attempt++) {\n const versionBeforeWait = connectionVersion;\n await connectionReady;\n if (versionBeforeWait !== connectionVersion && versionBeforeWait > 0) {\n await connectionReady;\n }\n currentConnectionId = connectionId;\n if (currentConnectionId) break;\n if (attempt < maxWaitAttempts - 1) {\n await new Promise(resolve => setTimeout(resolve, 100));\n }\n }\n\n if (!currentConnectionId) throw new Error('No connection ID available');\n\n const headers = buildHeaders();\n headers['Content-Type'] = 'application/json';\n headers['Accept'] = 'application/json, text/event-stream';\n headers['Acp-Connection-Id'] = currentConnectionId;\n\n const postController = new AbortController();\n let timeoutId: ReturnType<typeof setTimeout> | undefined;\n\n if (postTimeout > 0) {\n timeoutId = setTimeout(() => postController.abort(), postTimeout);\n if (externalSignal) externalSignal.addEventListener('abort', () => postController.abort(), { once: true });\n abortController.signal.addEventListener('abort', () => postController.abort(), { once: true });\n }\n\n try {\n const response = await customFetch(endpoint, {\n method: 'POST',\n headers,\n body: JSON.stringify(message),\n signal: postTimeout > 0 ? postController.signal : abortController.signal,\n });\n\n if (!response.ok) {\n const errorText = await response.text().catch(() => 'Unknown error');\n throw new Error(`HTTP ${response.status}: ${errorText}`);\n }\n\n const contentType = response.headers.get('Content-Type') || '';\n if (contentType.includes('text/event-stream')) {\n const reader = response.body?.getReader();\n if (reader) processSSEStreamBackground(reader);\n } else if (contentType.includes('application/json')) {\n const data = await response.json();\n if (data && typeof data === 'object' && 'jsonrpc' in data) {\n enqueueMessage(data);\n }\n }\n } finally {\n if (timeoutId) clearTimeout(timeoutId);\n }\n }\n\n // 启动 SSE\n startSSEConnection().catch(() => {});\n\n // 构造 ReadableStream / WritableStream(实现 Stream 接口)\n const readable = new ReadableStream<unknown>({\n async pull(controller) {\n const message = await dequeueMessage();\n if (message === null) { controller.close(); }\n else { controller.enqueue(message); }\n },\n cancel() { closeNormally(); abortController.abort(); },\n });\n\n const writable = new WritableStream<unknown>({\n async write(message) { await sendMessage(message); },\n close() { closeNormally(); abortController.abort(); },\n abort(reason) {\n closeWithError(reason instanceof Error ? reason : new Error(String(reason)));\n abortController.abort();\n },\n });\n\n async function close(): Promise<void> {\n if (closed) return;\n if (!connectionId || isClosing) { closeNormally(); abortController.abort(); return; }\n isClosing = true;\n try {\n const headers = buildHeaders();\n headers['Acp-Connection-Id'] = connectionId;\n await customFetch(endpoint, { method: 'DELETE', headers, signal: AbortSignal.timeout(5000) });\n } catch { /* ignore */ }\n finally {\n if (connectionId) onDisconnect?.(connectionId);\n isClosing = false;\n }\n closeNormally();\n abortController.abort();\n }\n\n return {\n readable,\n writable,\n get connectionId() { return connectionId; },\n get ready() { return connectionReady; },\n close,\n };\n}\n\n\n// 别名 - 与老 SDK @genie/agent-client-protocol 保持一致\nexport { createStreamableHttpTransport as streamableHttp };\nexport type { StreamableHttpTransportOptions as StreamableHttpOptions };\n\n","/**\n * Artifact Manager for Streamable HTTP ACP Client\n * Handles artifact notification processing\n */\n\nimport type {\n Artifact,\n ArtifactEvent,\n ArtifactNotificationParams,\n} from './acp-types.js';\nimport type { Logger } from './types.js';\n\n/**\n * Configuration for ArtifactManager\n */\nexport interface ArtifactManagerConfig {\n /** Logger instance */\n logger?: Logger;\n}\n\n/**\n * Callback for artifact events\n */\nexport type ArtifactEventCallback = (artifact: Artifact, event: ArtifactEvent) => void;\n\n/**\n * Manages artifact notifications from the agent\n */\nexport class ArtifactManager {\n private artifacts = new Map<string, Artifact>();\n private logger?: Logger;\n private eventCallbacks: Set<ArtifactEventCallback> = new Set();\n\n constructor(config: ArtifactManagerConfig) {\n this.logger = config.logger;\n }\n\n /**\n * Register a callback for artifact events\n */\n onArtifactEvent(callback: ArtifactEventCallback): () => void {\n this.eventCallbacks.add(callback);\n return () => {\n this.eventCallbacks.delete(callback);\n };\n }\n\n /**\n * Handle an artifact notification from the agent\n */\n handleNotification(notification: ArtifactNotificationParams): void {\n const { event } = notification;\n\n if (event === 'deleted') {\n const { artifact } = notification;\n const existing = this.artifacts.get(artifact.uri);\n this.logger?.debug(`Artifact deleted: ${artifact.uri}`);\n this.artifacts.delete(artifact.uri);\n\n // Notify callbacks with existing artifact if available\n if (existing) {\n this.notifyCallbacks(existing, event);\n }\n } else {\n const { artifact } = notification;\n this.logger?.debug(`Artifact ${event}: ${artifact.uri} (${artifact.type})`);\n this.artifacts.set(artifact.uri, artifact);\n this.notifyCallbacks(artifact, event);\n }\n }\n\n private notifyCallbacks(artifact: Artifact, event: ArtifactEvent): void {\n for (const callback of this.eventCallbacks) {\n try {\n callback(artifact, event);\n } catch (err) {\n this.logger?.error('Error in artifact event callback:', err);\n }\n }\n }\n\n /**\n * Get an artifact by URI (used internally for deleted event handling)\n */\n get(uri: string): Artifact | undefined {\n return this.artifacts.get(uri);\n }\n\n /**\n * Clear all artifacts\n */\n clear(): void {\n this.artifacts.clear();\n this.logger?.debug('Cleared all artifacts');\n }\n}\n","/**\n * Protocol Extension Types for Agent Client Protocol\n *\n * This file contains codebuddy.ai extension types that extend the base ACP protocol.\n * For SDK type re-exports and capability extensions, see ./sdk.ts\n */\n\n// ============================================\n// Extension Method Constants\n// ============================================\n\n/**\n * Extension method names as const for type safety\n */\nexport const ExtensionMethod = {\n ARTIFACT: '_codebuddy.ai/artifact',\n /**\n * Question/ToolInput extension method.\n * Used for tools that require user input (e.g., AskUserQuestion).\n * Request: ToolInputRequest, Response: ToolInputResponse\n */\n QUESTION: '_codebuddy.ai/question',\n CHECKPOINT: '_codebuddy.ai/checkpoint',\n /** Command extension method for executing custom commands */\n COMMAND: '_codebuddy.ai/command',\n /** Auth URL notification for external authentication */\n AUTH_URL: '_codebuddy.ai/authUrl',\n /** File history snapshot for checkpoint processing */\n FILE_HISTORY_SNAPSHOT: '_codebuddy.ai/file_history_snapshot',\n /** Delegate tool execution from external client-side tool provider */\n DELEGATE_TOOL: '_codebuddy.ai/delegateTool',\n /** Notification when available delegate tools change */\n DELEGATE_TOOLS_CHANGED: '_codebuddy.ai/delegateToolsChanged',\n /** UI control for operating Web UI elements */\n UI_CONTROL: '_codebuddy.ai/uiControl',\n} as const;\n\nexport type ExtensionMethodName = (typeof ExtensionMethod)[keyof typeof ExtensionMethod];\n\n/**\n * All known extension methods\n */\nexport const KNOWN_EXTENSIONS = [\n ExtensionMethod.ARTIFACT,\n ExtensionMethod.QUESTION,\n ExtensionMethod.CHECKPOINT,\n ExtensionMethod.COMMAND,\n ExtensionMethod.AUTH_URL,\n ExtensionMethod.FILE_HISTORY_SNAPSHOT,\n ExtensionMethod.DELEGATE_TOOL,\n ExtensionMethod.DELEGATE_TOOLS_CHANGED,\n] as const;\n\n// ============================================\n// Extension Notification Types (Discriminated Union)\n// ============================================\n\n/**\n * Discriminated union for extension notifications\n * Use `method` field as discriminant for type narrowing\n */\nexport type ExtensionNotification = ArtifactExtNotification;\n\nexport interface ArtifactExtNotification {\n method: typeof ExtensionMethod.ARTIFACT;\n params: ArtifactNotificationParams;\n}\n\n// ============================================\n// Artifact Types\n// ============================================\n\n/**\n * Types of artifacts that can be created by the agent\n * Uses discriminant for TypeScript type narrowing\n */\nexport type ArtifactType = 'plan' | 'tasks' | 'media' | 'overview';\n\n/**\n * Artifact lifecycle events\n */\nexport type ArtifactEvent = 'created' | 'updated' | 'deleted';\n\n/**\n * Base Artifact interface\n * Inspired by MCP Resource: https://modelcontextprotocol.io/specification/2025-11-25/server/resources\n */\nexport interface BaseArtifact<T extends ArtifactType = ArtifactType> {\n /** Artifact type (discriminant for type narrowing) */\n type: T;\n /**\n * Unique identifier URI\n * - Cloud Agent: agent:///{path} e.g. agent:///artifacts/plan.md\n * - Local Agent: file:///{path} e.g. file:///Users/xxx/project/plan.md\n */\n uri: string;\n /** Resource name */\n name: string;\n /** Display title */\n title?: string;\n /** Description */\n description?: string;\n /** Artifact creation timestamp (epoch milliseconds) */\n createdAt?: number;\n /** Artifact last update timestamp (epoch milliseconds) */\n updatedAt?: number;\n}\n\n// ============================================\n// Plan Artifact\n// ============================================\n\n/**\n * Plan Artifact - Markdown document\n * mimeType: text/markdown\n */\nexport interface PlanArtifact extends BaseArtifact<'plan'> {\n /** MIME type fixed as text/markdown */\n mimeType: 'text/markdown';\n /** Markdown text content */\n text: string;\n /** Version number (for diff) */\n version?: number;\n /** Previous version content (for diff display) */\n previousText?: string;\n /** Whether editing is enabled */\n enableEdit?: boolean;\n}\n\n// ============================================\n// Tasks Artifact\n// ============================================\n\n/**\n * Task item status\n */\nexport type TaskItemStatus = 'pending' | 'in_progress' | 'completed' | 'cancelled';\n\n/**\n * Single task item\n */\nexport interface TaskItem {\n id: string;\n content: string;\n status: TaskItemStatus;\n order?: number;\n}\n\n/**\n * Tasks Artifact - Task list\n * mimeType: application/json\n */\nexport interface TasksArtifact extends BaseArtifact<'tasks'> {\n /** MIME type fixed as application/json */\n mimeType: 'application/json';\n /** Task list */\n tasks: TaskItem[];\n /** Whether editing is enabled */\n enableEdit?: boolean;\n}\n\n// ============================================\n// Media Artifact\n// ============================================\n\n/**\n * Media content type (auxiliary classification)\n */\nexport type MediaContentType = 'image' | 'video' | 'audio' | 'document' | 'spreadsheet' | 'presentation' | 'diagram' | 'code';\n\n/**\n * Media Artifact - Media files\n * Supports images, videos, documents and other browser-renderable files\n *\n * URI schemes:\n * - data:image/png;base64,... (inline small files)\n * - agent:///artifacts/... (cloud agent resources)\n * - file:///path/to/file (local agent files)\n */\nexport interface MediaArtifact extends BaseArtifact<'media'> {\n /** MIME type, e.g. image/png, video/mp4, application/pdf */\n mimeType: string;\n /** File size in bytes */\n size?: number;\n /** Media content classification (auxiliary for frontend rendering) */\n contentType?: MediaContentType;\n /** Width (for images/videos) */\n width?: number;\n /** Height (for images/videos) */\n height?: number;\n}\n\n// ============================================\n// Overview Artifact\n// ============================================\n\n/**\n * Overview Artifact - 任务完成后的总结文档\n * mimeType: text/markdown\n */\nexport interface OverviewArtifact extends BaseArtifact<'overview'> {\n /** MIME type fixed as text/markdown */\n mimeType: 'text/markdown';\n /** Markdown text content */\n text?: string;\n}\n\n// ============================================\n// Artifact Union Type\n// ============================================\n\n/**\n * Artifact union type\n * Uses type field for discriminated union\n */\nexport type Artifact = PlanArtifact | TasksArtifact | MediaArtifact | OverviewArtifact;\n\n// ============================================\n// Artifact Notification Types (Discriminated Union by event)\n// ============================================\n\nexport interface ArtifactCreatedParams {\n sessionId: string;\n event: 'created';\n artifact: Artifact;\n}\n\nexport interface ArtifactUpdatedParams {\n sessionId: string;\n event: 'updated';\n artifact: Artifact;\n}\n\nexport interface ArtifactDeletedParams {\n sessionId: string;\n event: 'deleted';\n artifact: Pick<Artifact, 'type' | 'uri'>; // Only type and uri needed for deletion\n}\n\n/**\n * Artifact notification discriminated by event\n */\nexport type ArtifactNotificationParams =\n | ArtifactCreatedParams\n | ArtifactUpdatedParams\n | ArtifactDeletedParams;\n\n// ============================================\n// Question Types\n// ============================================\n\n/**\n * Question option structure\n */\nexport interface QuestionOption {\n /** Display text (1-5 words) */\n label: string;\n /** Option description */\n description: string;\n}\n\n/**\n * Single question structure\n */\nexport interface UserQuestion {\n /** Question ID */\n id: string;\n /** Question text */\n question: string;\n /** Short label (max 12 chars) */\n header?: string;\n /** Available options (2-4) */\n options: QuestionOption[];\n /** Allow multiple selections */\n multiSelect?: boolean;\n}\n\n/**\n * Question request (Server -> Client)\n * Sent via extMethod: _codebuddy.ai/question\n */\nexport interface QuestionRequest {\n /** Session ID */\n sessionId: string;\n /** Associated tool call ID (links extMethod to tool_call for UI) */\n toolCallId: string;\n /** Input type */\n inputType?: string;\n /** Schema containing questions */\n schema?: {\n /** Questions to ask (1-4) */\n questions: UserQuestion[];\n };\n /** Questions to ask (1-4) - legacy format */\n questions?: UserQuestion[];\n /** Request timeout in ms */\n timeout?: number;\n}\n\n/**\n * Question response (Client -> Server)\n */\nexport interface QuestionResponse {\n /** Response outcome */\n outcome: 'submitted' | 'cancelled';\n /** User's answers keyed by question ID (when submitted) */\n answers?: Record<string, string | string[]>;\n /** Cancellation reason (when cancelled) */\n reason?: string;\n}\n\n// ============================================\n// Command Types\n// ============================================\n\n/**\n * Command notification parameters\n * Sent via extNotification: _codebuddy.ai/command\n */\nexport interface CommandNotificationParams {\n /** Session ID */\n sessionId: string;\n /** Command action to execute */\n action: string;\n /** Command parameters */\n params?: Record<string, unknown>;\n}\n\n// ============================================\n// Checkpoint Types\n// ============================================\n\n/**\n * Checkpoint event types\n */\nexport type CheckpointEvent = 'created' | 'updated';\n\n/**\n * Checkpoint notification parameters\n * Sent via extNotification: _codebuddy.ai/checkpoint\n */\nexport interface CheckpointNotificationParams {\n /** Session ID */\n sessionId: string;\n /** Event type */\n event: CheckpointEvent;\n /** Checkpoint information */\n checkpoint: CheckpointInfo;\n}\n\n/**\n * Checkpoint information visible to clients\n */\nexport interface CheckpointInfo {\n /** Checkpoint ID */\n id: string;\n /** Label/description */\n label?: string;\n /** Creation timestamp */\n createdAt: number;\n /** File change summary */\n fileChanges: FileChangeSummary;\n}\n\n/**\n * File change summary for a checkpoint\n */\nexport interface FileChangeSummary {\n /** List of changed files */\n files: FileChangeInfo[];\n /** Total lines added */\n totalAdditions: number;\n /** Total lines deleted */\n totalDeletions: number;\n}\n\n/**\n * Change type for a file\n */\nexport type FileChangeType = 'created' | 'modified' | 'deleted';\n\n/**\n * Information about a single file change\n */\nexport interface FileChangeInfo {\n /** File URI (agent://files/{path}) */\n uri: string;\n /** Type of change */\n changeType: FileChangeType;\n /** Lines added */\n additions: number;\n /** Lines deleted */\n deletions: number;\n /** Unified diff format content\n * https://unifiedjs.com/explore/package/unified-diff/\n */\n diff?: string;\n /** File language */\n language?: string;\n /** Creation timestamp */\n createdAt?: number;\n /** Latest update timestamp */\n updatedAt?: number;\n}\n\n// ============================================\n// Auth URL Types\n// ============================================\n\n/**\n * Auth URL notification parameters\n * Sent via extNotification: _codebuddy.ai/authUrl\n *\n * Used when the Agent CLI attempts to open an external browser for OAuth authentication.\n * The client displays this URL so users can manually copy and open it if the browser\n * doesn't open automatically.\n */\nexport interface AuthUrlNotificationParams {\n /** The authentication URL to display */\n authUrl: string;\n /** Optional authentication provider identifier (e.g., 'oauth', 'external') */\n provider?: string;\n}\n\n// ============================================\n// Session Update Meta Types\n// ============================================\n\n/**\n * Mode for session update messages\n * - 'stream': Real-time updates during prompt execution (should be broadcast)\n * - 'history': Historical messages during session/load (should NOT be broadcast)\n */\nexport type SessionUpdateMode = 'stream' | 'history';\n\n/**\n * codebuddy.ai extension metadata for session updates\n */\nexport interface SessionUpdateCodebuddyMeta {\n /** Mode indicating the source of this update */\n mode?: SessionUpdateMode;\n}\n\n/**\n * _meta structure for session update notifications\n */\nexport interface SessionUpdateMeta {\n 'codebuddy.ai'?: SessionUpdateCodebuddyMeta;\n [key: string]: unknown;\n}\n\n// ============================================\n// Delegate Tool Types\n// ============================================\n\n/**\n * Parameter schema for delegate tools using JSON Schema\n * Supports standard JSON Schema draft 2020-12 with validation keywords\n *\n * Example:\n * ```json\n * {\n * \"type\": \"object\",\n * \"properties\": {\n * \"path\": { \"type\": \"string\", \"description\": \"File path\" },\n * \"force\": { \"type\": \"boolean\", \"description\": \"Force operation\" }\n * },\n * \"required\": [\"path\"]\n * }\n * ```\n */\nexport type ParameterSchema = Record<string, unknown>;\n\n/**\n * Delegate tool definition provided by client-side tool providers\n * Represents a tool that can be invoked by the agent\n */\nexport interface DelegateToolDefinition {\n /** Unique tool identifier (e.g., \"github-api\", \"custom-validator\") */\n id: string;\n /** Human-readable tool name */\n name: string;\n /** Tool description for agent understanding */\n description: string;\n /** Parameter schema (JSON Schema) */\n inputSchema: ParameterSchema;\n /** Tool category/group for organization (e.g., \"vcs\", \"validation\", \"custom\") */\n category?: string;\n /** Tool provider identifier (e.g., extension name, plugin id) */\n provider?: string;\n /** Whether this tool requires user approval before execution */\n requiresApproval?: boolean;\n /** Tool availability (e.g., \"enabled\", \"disabled\", \"beta\") */\n availability?: 'enabled' | 'disabled' | 'beta';\n /** Additional metadata */\n metadata?: Record<string, unknown>;\n}\n\n/**\n * Delegate tool execution request (Agent -> Client)\n * Sent via extMethod: _codebuddy.ai/delegateTool\n */\nexport interface DelegateToolRequest {\n /** Session ID */\n sessionId: string;\n /** Tool call ID for tracing */\n toolCallId: string;\n /** Tool ID from the definition */\n toolId: string;\n /** Tool input parameters */\n input: Record<string, unknown>;\n /** Request timeout in milliseconds */\n timeout?: number;\n /** Abort signal URI for cancellation support */\n abortSignal?: string;\n}\n\n/**\n * Delegate tool execution result (Client -> Agent)\n */\nexport interface DelegateToolResult {\n /** Execution outcome */\n status: 'success' | 'error' | 'timeout' | 'cancelled';\n /** Output data (when status is 'success') */\n output?: unknown;\n /** Error message and details (when status is 'error' or other failure) */\n error?: {\n message: string;\n code?: string;\n details?: Record<string, unknown>;\n };\n /** Execution duration in milliseconds */\n duration?: number;\n /** Additional metadata */\n metadata?: Record<string, unknown>;\n}\n\n/**\n * Delegate tools changed notification (Client -> Agent)\n * Sent via extNotification: _codebuddy.ai/delegateToolsChanged\n * Notifies agent when available delegate tools are added, removed, or updated\n */\nexport interface DelegateToolsChangedParams {\n /** Session ID */\n sessionId: string;\n /** Type of change */\n changeType: 'added' | 'removed' | 'updated';\n /** Tool definitions added/removed/updated */\n tools: DelegateToolDefinition[];\n /** Timestamp of the change */\n timestamp: number;\n}\n\n// ============================================\n// UI Control Types\n// ============================================\n\n/**\n * UI Control action types\n */\nexport type UIControlAction = 'click' | 'fill' | 'scroll' | 'focus' | 'select';\n\n/**\n * UI Control target specification\n */\nexport interface UIControlTarget {\n /** CSS selector */\n selector?: string;\n /** Match element by text content */\n text?: string;\n /** Match element by aria-label or label text */\n label?: string;\n /** Match element by ARIA role (button, textbox, etc.) */\n role?: string;\n /** Index of matching element (0-based) */\n index?: number;\n}\n\n/**\n * UI Control request (Agent -> Client)\n * Sent via extMethod: _codebuddy.ai/uiControl\n */\nexport interface UIControlRequest {\n /** Session ID */\n sessionId: string;\n /** Action to perform */\n action: UIControlAction;\n /** Target element specification */\n target: UIControlTarget;\n /** Value for fill action */\n value?: string;\n /** Request timeout in milliseconds */\n timeout?: number;\n}\n\n/**\n * UI Control result (Client -> Agent)\n */\nexport interface UIControlResult {\n /** Whether the action was successful */\n success: boolean;\n /** Error message if failed */\n error?: string;\n /** Whether the target element was found */\n elementFound?: boolean;\n /** Action that was performed */\n action?: UIControlAction;\n /** Timestamp of execution */\n timestamp: number;\n}\n","/**\n * Protocol constants for Streamable HTTP ACP Client\n */\n\nimport type { ClientCapabilities } from './sdk.js';\nimport { ExtensionMethod, KNOWN_EXTENSIONS } from './acp-types.js';\n\n// Re-export extension constants\nexport { ExtensionMethod, KNOWN_EXTENSIONS };\n\n// ============================================\n// Default Timeouts (in milliseconds)\n// ============================================\n\n/**\n * Default timeout for initialize operation\n */\nexport const DEFAULT_INITIALIZE_TIMEOUT = 30_000; // 30 seconds\n\n/**\n * Default timeout for session/new operation (waiting for sessionId via SSE)\n */\nexport const DEFAULT_SESSION_TIMEOUT = 30_000; // 30 seconds\n\n/**\n * Default timeout for prompt operation\n */\nexport const DEFAULT_PROMPT_TIMEOUT = 300_000; // 5 minutes\n\n/**\n * Default timeout for permission requests\n */\nexport const DEFAULT_PERMISSION_TIMEOUT = 300_000; // 5 minutes\n\n/**\n * Default timeout for question requests (ask_followup_question)\n */\nexport const DEFAULT_QUESTION_TIMEOUT = 300_000; // 5 minutes\n\n/**\n * Default timeout for tool input requests\n * @deprecated Use DEFAULT_QUESTION_TIMEOUT instead\n */\nexport const DEFAULT_TOOL_INPUT_TIMEOUT = DEFAULT_QUESTION_TIMEOUT;\n\n// ============================================\n// Default Reconnect Configuration\n// ============================================\n\n/**\n * Default reconnect options\n */\nexport const DEFAULT_RECONNECT_OPTIONS = {\n enabled: true,\n initialDelay: 1000, // 1 second\n maxDelay: 30_000, // 30 seconds\n maxRetries: Infinity\n} as const;\n\n// ============================================\n// Client Capabilities\n// ============================================\n\n/**\n * Default client capabilities for cloud-based clients\n * Cloud clients typically have no direct file system access\n */\nexport const CLOUD_CLIENT_CAPABILITIES: ClientCapabilities = {\n fs: {\n readTextFile: false,\n writeTextFile: false\n }\n} as const;\n\n/**\n * Default client capabilities for local (Node.js) clients\n * Local clients have file system access\n */\nexport const LOCAL_CLIENT_CAPABILITIES: ClientCapabilities = {\n fs: {\n readTextFile: true,\n writeTextFile: true\n }\n} as const;\n","/**\n * Custom error classes for Streamable HTTP ACP Client\n */\n\n/**\n * Base error class for all ACP client errors\n */\nexport class ACPClientError extends Error {\n public readonly code: string;\n\n constructor(message: string, code: string, cause?: Error) {\n super(message);\n this.name = 'ACPClientError';\n this.code = code;\n (this as Error & { cause?: Error }).cause = cause;\n\n // Maintain proper stack trace in V8 environments\n if (Error.captureStackTrace) {\n Error.captureStackTrace(this, this.constructor);\n }\n }\n}\n\n/**\n * Error thrown when connection fails\n */\nexport class ConnectionError extends ACPClientError {\n constructor(message: string, cause?: Error) {\n super(message, 'CONNECTION_ERROR', cause);\n this.name = 'ConnectionError';\n }\n}\n\n/**\n * Error thrown when initialization fails\n */\nexport class InitializationError extends ACPClientError {\n constructor(message: string, cause?: Error) {\n super(message, 'INITIALIZATION_ERROR', cause);\n this.name = 'InitializationError';\n }\n}\n\n/**\n * Error thrown for session-related failures\n */\nexport class SessionError extends ACPClientError {\n public readonly sessionId?: string;\n\n /**\n * Agent ID associated with the failed session operation.\n * Available when session/new fails after agent creation + connection established.\n * Can be used with `retryNewSession()` to recover from transient failures.\n *\n * @experimental This field is subject to change\n */\n public readonly agentId?: string;\n\n constructor(message: string, sessionId?: string, cause?: Error);\n constructor(message: string, sessionId?: string, agentId?: string, cause?: Error);\n constructor(message: string, sessionId?: string, agentIdOrCause?: string | Error, cause?: Error) {\n // Overload resolution: distinguish (msg, sid, cause) from (msg, sid, agentId, cause)\n if (agentIdOrCause instanceof Error) {\n super(message, 'SESSION_ERROR', agentIdOrCause);\n this.agentId = undefined;\n } else {\n super(message, 'SESSION_ERROR', cause);\n this.agentId = agentIdOrCause;\n }\n this.name = 'SessionError';\n this.sessionId = sessionId;\n }\n}\n\n/**\n * Error thrown when prompt operation fails\n */\nexport class PromptError extends ACPClientError {\n public readonly sessionId?: string;\n\n constructor(message: string, sessionId?: string, cause?: Error) {\n super(message, 'PROMPT_ERROR', cause);\n this.name = 'PromptError';\n this.sessionId = sessionId;\n }\n}\n\n/**\n * Error thrown for permission-related failures\n */\nexport class PermissionError extends ACPClientError {\n public readonly requestId?: string;\n\n constructor(message: string, requestId?: string, cause?: Error) {\n super(message, 'PERMISSION_ERROR', cause);\n this.name = 'PermissionError';\n this.requestId = requestId;\n }\n}\n\n/**\n * Error thrown when an operation times out\n */\nexport class TimeoutError extends ACPClientError {\n public readonly operation: string;\n public readonly timeoutMs: number;\n\n constructor(operation: string, timeoutMs: number) {\n super(`Operation '${operation}' timed out after ${timeoutMs}ms`, 'TIMEOUT_ERROR');\n this.name = 'TimeoutError';\n this.operation = operation;\n this.timeoutMs = timeoutMs;\n }\n}\n\n/**\n * Error thrown when client is in invalid state for an operation\n */\nexport class InvalidStateError extends ACPClientError {\n public readonly currentState: string;\n public readonly expectedStates: string[];\n\n constructor(operation: string, currentState: string, expectedStates: string[]) {\n super(\n `Cannot perform '${operation}' in state '${currentState}'. Expected: ${expectedStates.join(' or ')}`,\n 'INVALID_STATE_ERROR'\n );\n this.name = 'InvalidStateError';\n this.currentState = currentState;\n this.expectedStates = expectedStates;\n }\n}\n","/**\n * Type-safe event emitter for Streamable HTTP ACP Client\n * Platform-agnostic implementation (no browser dependencies)\n */\n\n/**\n * Event listener function type\n */\nexport type EventListener<T> = (data: T) => void | Promise<void>;\n\n/**\n * Type-safe event emitter implementation\n */\nexport class EventEmitter<TEvents extends Record<string, unknown>> {\n private listeners: Map<keyof TEvents, Set<EventListener<unknown>>> = new Map();\n private onceListeners: Map<keyof TEvents, Set<EventListener<unknown>>> = new Map();\n\n /**\n * Add an event listener\n */\n on<K extends keyof TEvents>(event: K, listener: EventListener<TEvents[K]>): this {\n if (!this.listeners.has(event)) {\n this.listeners.set(event, new Set());\n }\n this.listeners.get(event)!.add(listener as EventListener<unknown>);\n return this;\n }\n\n /**\n * Remove an event listener\n */\n off<K extends keyof TEvents>(event: K, listener: EventListener<TEvents[K]>): this {\n const eventListeners = this.listeners.get(event);\n if (eventListeners) {\n eventListeners.delete(listener as EventListener<unknown>);\n }\n\n const onceEventListeners = this.onceListeners.get(event);\n if (onceEventListeners) {\n onceEventListeners.delete(listener as EventListener<unknown>);\n }\n\n return this;\n }\n\n /**\n * Add a one-time event listener\n */\n once<K extends keyof TEvents>(event: K, listener: EventListener<TEvents[K]>): this {\n if (!this.onceListeners.has(event)) {\n this.onceListeners.set(event, new Set());\n }\n this.onceListeners.get(event)!.add(listener as EventListener<unknown>);\n return this;\n }\n\n /**\n * Emit an event to all registered listeners\n * Returns true if any listeners were invoked\n */\n emit<K extends keyof TEvents>(event: K, data: TEvents[K]): boolean {\n const regularListeners = this.listeners.get(event);\n const onceEventListeners = this.onceListeners.get(event);\n\n let hasListeners = false;\n\n // Call regular listeners\n if (regularListeners && regularListeners.size > 0) {\n hasListeners = true;\n for (const listener of regularListeners) {\n try {\n const result = listener(data);\n // Handle async listeners\n if (result instanceof Promise) {\n result.catch(err => {\n console.error(`Error in async event listener for '${String(event)}':`, err);\n });\n }\n } catch (err) {\n console.error(`Error in event listener for '${String(event)}':`, err);\n }\n }\n }\n\n // Call once listeners and remove them\n if (onceEventListeners && onceEventListeners.size > 0) {\n hasListeners = true;\n const listenersToCall = Array.from(onceEventListeners);\n this.onceListeners.delete(event);\n\n for (const listener of listenersToCall) {\n try {\n const result = listener(data);\n if (result instanceof Promise) {\n result.catch(err => {\n console.error(\n `Error in async once event listener for '${String(event)}':`,\n err\n );\n });\n }\n } catch (err) {\n console.error(`Error in once event listener for '${String(event)}':`, err);\n }\n }\n }\n\n return hasListeners;\n }\n\n /**\n * Remove all listeners for an event, or all listeners if no event specified\n */\n removeAllListeners<K extends keyof TEvents>(event?: K): this {\n if (event !== undefined) {\n this.listeners.delete(event);\n this.onceListeners.delete(event);\n } else {\n this.listeners.clear();\n this.onceListeners.clear();\n }\n return this;\n }\n\n /**\n * Get the number of listeners for an event\n */\n listenerCount<K extends keyof TEvents>(event: K): number {\n const regular = this.listeners.get(event)?.size ?? 0;\n const once = this.onceListeners.get(event)?.size ?? 0;\n return regular + once;\n }\n\n /**\n * Get all event names that have listeners\n */\n eventNames(): Array<keyof TEvents> {\n const names = new Set<keyof TEvents>();\n for (const event of this.listeners.keys()) {\n names.add(event);\n }\n for (const event of this.onceListeners.keys()) {\n names.add(event);\n }\n return Array.from(names);\n }\n}\n","/**\n * Extension Method Handler for Streamable HTTP ACP Client\n * Routes and handles custom extension notifications\n */\n\nimport { ExtensionMethod, KNOWN_EXTENSIONS } from './constants.js';\nimport type { Logger } from './types.js';\n\n/**\n * Configuration for ExtensionManager\n */\nexport interface ExtensionManagerConfig {\n /** Logger instance */\n logger?: Logger;\n}\n\n/**\n * Handler for extension notifications\n */\nexport type ExtensionNotificationHandler = (\n method: string,\n params: Record<string, unknown>\n) => void | Promise<void>;\n\n/**\n * Manages extension methods and notifications\n */\nexport class ExtensionManager {\n private config: ExtensionManagerConfig;\n private handlers = new Map<string, ExtensionNotificationHandler>();\n private fallbackHandler?: ExtensionNotificationHandler;\n\n constructor(config: ExtensionManagerConfig = {}) {\n this.config = config;\n }\n\n /**\n * Register a handler for a specific extension method\n */\n registerHandler(method: string, handler: ExtensionNotificationHandler): () => void {\n this.handlers.set(method, handler);\n return () => {\n this.handlers.delete(method);\n };\n }\n\n /**\n * Set a fallback handler for unknown extensions\n */\n setFallbackHandler(handler: ExtensionNotificationHandler): void {\n this.fallbackHandler = handler;\n }\n\n /**\n * Handle an extension notification\n */\n async handleNotification(method: string, params: Record<string, unknown>): Promise<void> {\n this.config.logger?.debug(`Extension notification: ${method}`);\n\n // Try specific handler first\n const handler = this.handlers.get(method);\n if (handler) {\n await handler(method, params);\n return;\n }\n\n // Try fallback handler\n if (this.fallbackHandler) {\n await this.fallbackHandler(method, params);\n return;\n }\n\n // Log unknown extension\n if (!this.isKnownExtension(method)) {\n this.config.logger?.warn(`Unknown extension notification: ${method}`);\n }\n }\n\n /**\n * Check if a method is a known extension\n */\n isKnownExtension(method: string): boolean {\n return KNOWN_EXTENSIONS.includes(method as typeof KNOWN_EXTENSIONS[number]);\n }\n\n /**\n * Check if method is the artifact extension\n */\n isArtifactExtension(method: string): boolean {\n return method === ExtensionMethod.ARTIFACT;\n }\n\n /**\n * Clear all handlers\n */\n clear(): void {\n this.handlers.clear();\n this.fallbackHandler = undefined;\n }\n}\n","/**\n * Permission Manager for Streamable HTTP ACP Client\n * Handles permission requests with timeout support\n */\n\nimport type { RequestPermissionRequest, RequestPermissionResponse } from '@agentclientprotocol/sdk' with { 'resolution-mode': 'import' };\n\nimport { DEFAULT_PERMISSION_TIMEOUT } from './constants.js';\nimport { TimeoutError } from './errors.js';\nimport type { Logger, PermissionHandler } from './types.js';\n\n/**\n * Pending permission request state\n */\ninterface PendingPermission {\n params: RequestPermissionRequest;\n resolve: (response: RequestPermissionResponse) => void;\n reject: (error: Error) => void;\n timeoutId?: ReturnType<typeof setTimeout>;\n createdAt: number;\n}\n\n/**\n * Configuration for PermissionManager\n */\nexport interface PermissionManagerConfig {\n /** Default timeout for permission requests (ms) */\n timeout?: number;\n /** Auto-reject permissions on timeout */\n autoRejectOnTimeout?: boolean;\n /** Auto-approve all permissions (for testing) */\n autoApprove?: boolean;\n /** Custom permission handler */\n handler?: PermissionHandler;\n /** Logger instance */\n logger?: Logger;\n}\n\n/**\n * Event callbacks for permission events\n */\nexport interface PermissionEventCallbacks {\n onRequest?: (requestId: string, params: RequestPermissionRequest) => void;\n onResolved?: (requestId: string, optionId: string) => void;\n onRejected?: (requestId: string, reason?: string) => void;\n onTimeout?: (requestId: string) => void;\n}\n\n/**\n * Manages permission requests from the agent\n */\nexport class PermissionManager {\n private pending = new Map<string, PendingPermission>();\n private config: PermissionManagerConfig;\n private callbacks: PermissionEventCallbacks = {};\n\n constructor(config: PermissionManagerConfig = {}) {\n this.config = {\n timeout: DEFAULT_PERMISSION_TIMEOUT,\n autoRejectOnTimeout: true,\n autoApprove: false,\n ...config\n };\n }\n\n /**\n * Set event callbacks\n */\n setCallbacks(callbacks: PermissionEventCallbacks): void {\n this.callbacks = callbacks;\n }\n\n /**\n * Handle a permission request from the agent\n */\n async handleRequest(params: RequestPermissionRequest): Promise<RequestPermissionResponse> {\n const requestId = params.toolCall.toolCallId;\n\n this.config.logger?.debug(`Permission request received: ${requestId}`);\n\n // Auto-approve mode\n if (this.config.autoApprove) {\n const firstOption = params.options[0];\n this.config.logger?.debug(`Auto-approving permission: ${requestId}`);\n return {\n outcome: {\n outcome: 'selected',\n optionId: firstOption?.optionId ?? 'approve'\n }\n };\n }\n\n // Custom handler\n if (this.config.handler) {\n return this.config.handler(params);\n }\n\n // Create pending permission\n return new Promise<RequestPermissionResponse>((resolve, reject) => {\n const pending: PendingPermission = {\n params,\n resolve,\n reject,\n createdAt: Date.now()\n };\n\n // Set up timeout\n if (this.config.timeout && this.config.timeout > 0) {\n pending.timeoutId = setTimeout(() => {\n this.handleTimeout(requestId);\n }, this.config.timeout);\n }\n\n this.pending.set(requestId, pending);\n\n // Notify callback\n this.callbacks.onRequest?.(requestId, params);\n });\n }\n\n /**\n * Handle timeout for a permission request\n */\n private handleTimeout(requestId: string): void {\n const pending = this.pending.get(requestId);\n if (!pending) {return;}\n\n this.config.logger?.warn(`Permission request timed out: ${requestId}`);\n this.callbacks.onTimeout?.(requestId);\n\n if (this.config.autoRejectOnTimeout) {\n pending.resolve({\n outcome: { outcome: 'cancelled' }\n });\n } else {\n pending.reject(new TimeoutError('permission', this.config.timeout ?? DEFAULT_PERMISSION_TIMEOUT));\n }\n\n this.pending.delete(requestId);\n }\n\n /**\n * Resolve a permission request with a selected option\n * Returns true if the permission was found and resolved\n */\n resolve(requestId: string, optionId: string): boolean {\n const pending = this.pending.get(requestId);\n if (!pending) {\n this.config.logger?.warn(`Permission request not found: ${requestId}`);\n return false;\n }\n\n // Clear timeout\n if (pending.timeoutId) {\n clearTimeout(pending.timeoutId);\n }\n\n this.config.logger?.debug(`Permission resolved: ${requestId} -> ${optionId}`);\n\n pending.resolve({\n outcome: { outcome: 'selected', optionId }\n });\n\n this.pending.delete(requestId);\n this.callbacks.onResolved?.(requestId, optionId);\n\n return true;\n }\n\n /**\n * Reject (cancel) a permission request\n * Returns true if the permission was found and rejected\n */\n reject(requestId: string, reason?: string): boolean {\n const pending = this.pending.get(requestId);\n if (!pending) {\n this.config.logger?.warn(`Permission request not found: ${requestId}`);\n return false;\n }\n\n // Clear timeout\n if (pending.timeoutId) {\n clearTimeout(pending.timeoutId);\n }\n\n this.config.logger?.debug(`Permission rejected: ${requestId}${reason ? ` - ${reason}` : ''}`);\n\n pending.resolve({\n outcome: { outcome: 'cancelled' }\n });\n\n this.pending.delete(requestId);\n this.callbacks.onRejected?.(requestId, reason);\n\n return true;\n }\n\n /**\n * Get all pending permissions\n */\n getPending(): Map<string, { params: RequestPermissionRequest; createdAt: number }> {\n const result = new Map<string, { params: RequestPermissionRequest; createdAt: number }>();\n for (const [id, pending] of this.pending) {\n result.set(id, {\n params: pending.params,\n createdAt: pending.createdAt\n });\n }\n return result;\n }\n\n /**\n * Get a specific pending permission\n */\n getPendingById(requestId: string): { params: RequestPermissionRequest; createdAt: number } | undefined {\n const pending = this.pending.get(requestId);\n if (!pending) {return undefined;}\n return {\n params: pending.params,\n createdAt: pending.createdAt\n };\n }\n\n /**\n * Check if there are any pending permissions\n */\n hasPending(): boolean {\n return this.pending.size > 0;\n }\n\n /**\n * Get the count of pending permissions\n */\n get pendingCount(): number {\n return this.pending.size;\n }\n\n /**\n * Clear all pending permissions (reject all)\n */\n clear(): void {\n for (const [requestId, pending] of this.pending) {\n if (pending.timeoutId) {\n clearTimeout(pending.timeoutId);\n }\n pending.resolve({\n outcome: { outcome: 'cancelled' }\n });\n this.callbacks.onRejected?.(requestId, 'cleared');\n }\n this.pending.clear();\n this.config.logger?.debug('Cleared all pending permissions');\n }\n\n /**\n * Update configuration\n */\n updateConfig(config: Partial<PermissionManagerConfig>): void {\n this.config = { ...this.config, ...config };\n }\n}\n","/**\n * Question Manager for Streamable HTTP ACP Client\n * Handles ask_followup_question requests with timeout support\n */\n\nimport type {\n QuestionRequest,\n QuestionResponse,\n} from './acp-types.js';\nimport { DEFAULT_QUESTION_TIMEOUT } from './constants.js';\nimport { TimeoutError } from './errors.js';\nimport type { Logger } from './types.js';\n\n// Re-export for convenience\nexport type { QuestionRequest, QuestionResponse };\n\n/**\n * Pending question state\n */\ninterface PendingQuestion {\n request: QuestionRequest;\n resolve: (response: QuestionResponse) => void;\n reject: (error: Error) => void;\n timeoutId?: ReturnType<typeof setTimeout>;\n createdAt: number;\n}\n\n/**\n * Configuration for QuestionManager\n */\nexport interface QuestionManagerConfig {\n /** Default timeout for question requests (ms) */\n timeout?: number;\n /** Auto-cancel requests on timeout */\n autoCancelOnTimeout?: boolean;\n /** Logger instance */\n logger?: Logger;\n}\n\n/**\n * User's answers to questions\n */\nexport type QuestionAnswers = Record<string, string | string[]>;\n\n/**\n * Event callbacks for question events\n */\nexport interface QuestionEventCallbacks {\n onRequest?: (toolCallId: string, request: QuestionRequest) => void;\n onAnswered?: (toolCallId: string, answers: QuestionAnswers) => void;\n onCancelled?: (toolCallId: string, reason?: string) => void;\n onTimeout?: (toolCallId: string) => void;\n}\n\n/**\n * Manages question requests from the agent (ask_followup_question tool)\n */\nexport class QuestionManager {\n private pending = new Map<string, PendingQuestion>();\n private config: QuestionManagerConfig;\n private callbacks: QuestionEventCallbacks = {};\n\n constructor(config: QuestionManagerConfig = {}) {\n this.config = {\n timeout: DEFAULT_QUESTION_TIMEOUT,\n autoCancelOnTimeout: true,\n ...config\n };\n }\n\n /**\n * Set event callbacks\n */\n setCallbacks(callbacks: QuestionEventCallbacks): void {\n this.callbacks = callbacks;\n }\n\n /**\n * Handle a question request from the agent\n * Called when receiving _codebuddy.ai/question extMethod\n */\n async handleRequest(request: QuestionRequest): Promise<QuestionResponse> {\n const toolCallId = request.toolCallId;\n\n this.config.logger?.debug(`Question request received: ${toolCallId}`);\n\n return new Promise<QuestionResponse>((resolve, reject) => {\n const pending: PendingQuestion = {\n request,\n resolve,\n reject,\n createdAt: Date.now()\n };\n\n // Set up timeout\n const timeout = request.timeout ?? this.config.timeout;\n if (timeout && timeout > 0) {\n pending.timeoutId = setTimeout(() => {\n this.handleTimeout(toolCallId);\n }, timeout);\n }\n\n this.pending.set(toolCallId, pending);\n\n // Notify callback\n this.callbacks.onRequest?.(toolCallId, request);\n });\n }\n\n /**\n * Handle timeout for a question request\n */\n private handleTimeout(toolCallId: string): void {\n const pending = this.pending.get(toolCallId);\n if (!pending) {return;}\n\n this.config.logger?.warn(`Question request timed out: ${toolCallId}`);\n this.callbacks.onTimeout?.(toolCallId);\n\n if (this.config.autoCancelOnTimeout) {\n pending.resolve({\n outcome: 'cancelled',\n reason: 'timeout'\n });\n } else {\n pending.reject(new TimeoutError('question', this.config.timeout ?? DEFAULT_QUESTION_TIMEOUT));\n }\n\n this.pending.delete(toolCallId);\n }\n\n /**\n * Answer a question request with user's selections\n * Returns true if the request was found and answered\n */\n answer(toolCallId: string, answers: QuestionAnswers): boolean {\n const pending = this.pending.get(toolCallId);\n if (!pending) {\n this.config.logger?.warn(`Question request not found: ${toolCallId}`);\n return false;\n }\n\n // Clear timeout\n if (pending.timeoutId) {\n clearTimeout(pending.timeoutId);\n }\n\n this.config.logger?.debug(`Question answered: ${toolCallId}`);\n\n pending.resolve({\n outcome: 'submitted',\n answers\n });\n\n this.pending.delete(toolCallId);\n this.callbacks.onAnswered?.(toolCallId, answers);\n\n return true;\n }\n\n /**\n * Cancel a question request\n * Returns true if the request was found and cancelled\n */\n cancel(toolCallId: string, reason?: string): boolean {\n const pending = this.pending.get(toolCallId);\n if (!pending) {\n this.config.logger?.warn(`Question request not found: ${toolCallId}`);\n return false;\n }\n\n // Clear timeout\n if (pending.timeoutId) {\n clearTimeout(pending.timeoutId);\n }\n\n this.config.logger?.debug(`Question cancelled: ${toolCallId}${reason ? ` - ${reason}` : ''}`);\n\n pending.resolve({\n outcome: 'cancelled',\n reason\n });\n\n this.pending.delete(toolCallId);\n this.callbacks.onCancelled?.(toolCallId, reason);\n\n return true;\n }\n\n /**\n * Get all pending question requests\n */\n getPending(): Map<string, { request: QuestionRequest; createdAt: number }> {\n const result = new Map<string, { request: QuestionRequest; createdAt: number }>();\n for (const [id, pending] of this.pending) {\n result.set(id, {\n request: pending.request,\n createdAt: pending.createdAt\n });\n }\n return result;\n }\n\n /**\n * Get a specific pending question request\n */\n getPendingById(toolCallId: string): { request: QuestionRequest; createdAt: number } | undefined {\n const pending = this.pending.get(toolCallId);\n if (!pending) {return undefined;}\n return {\n request: pending.request,\n createdAt: pending.createdAt\n };\n }\n\n /**\n * Check if there are any pending question requests\n */\n hasPending(): boolean {\n return this.pending.size > 0;\n }\n\n /**\n * Get the count of pending question requests\n */\n get pendingCount(): number {\n return this.pending.size;\n }\n\n /**\n * Clear all pending question requests (cancel all)\n */\n clear(): void {\n for (const [toolCallId, pending] of this.pending) {\n if (pending.timeoutId) {\n clearTimeout(pending.timeoutId);\n }\n pending.resolve({\n outcome: 'cancelled',\n reason: 'cleared'\n });\n this.callbacks.onCancelled?.(toolCallId, 'cleared');\n }\n this.pending.clear();\n this.config.logger?.debug('Cleared all pending question requests');\n }\n\n /**\n * Update configuration\n */\n updateConfig(config: Partial<QuestionManagerConfig>): void {\n this.config = { ...this.config, ...config };\n }\n}\n","/**\n * Streamable HTTP ACP Client\n * Production-grade client for connecting to cloud-hosted ACP agents\n */\n\nimport {\n type CancelNotification,\n type Client,\n type ContentBlock,\n type InitializeRequest,\n type InitializeResponse,\n loadAcpSdk,\n type LoadSessionRequest,\n type LoadSessionResponse,\n type NewSessionRequest,\n type NewSessionResponse,\n type PromptResponse,\n PROTOCOL_VERSION,\n type RequestPermissionRequest,\n type RequestPermissionResponse,\n type SessionNotification,\n type SetSessionModelRequest,\n type SetSessionModelResponse,\n type SetSessionModeRequest,\n type SetSessionModeResponse,\n} from './sdk.js';\nimport { streamableHttp, type StreamableHttpTransport } from '../transport.js';\nimport type {\n ArtifactNotificationParams,\n CheckpointNotificationParams\n} from './acp-types.js';\nimport { ArtifactManager } from './artifacts.js';\nimport {\n CLOUD_CLIENT_CAPABILITIES,\n DEFAULT_INITIALIZE_TIMEOUT,\n DEFAULT_SESSION_TIMEOUT,\n ExtensionMethod\n} from './constants.js';\nimport {\n ConnectionError,\n InitializationError,\n InvalidStateError,\n SessionError\n} from './errors.js';\nimport { EventEmitter } from './events.js';\nimport { ExtensionManager } from './extensions.js';\nimport { PermissionManager } from './permissions.js';\nimport { type QuestionAnswers, QuestionManager, type QuestionRequest } from './questions.js';\nimport type {\n ClientEvents,\n ClientState,\n PromptOptions,\n StreamableHttpClientOptions,\n} from './types.js';\n\n/**\n * Production-grade Streamable HTTP ACP Client\n *\n * Features:\n * - Full ACP protocol support (initialize, session, prompt, cancel)\n * - Artifact notification handling\n * - Permission handling with timeout support\n * - Extension method support\n * - Type-safe event system\n * - Configurable logging\n */\nexport class StreamableHttpClient {\n private connection!: {\n initialize(params: InitializeRequest): Promise<InitializeResponse>;\n newSession(params: NewSessionRequest): Promise<NewSessionResponse>;\n loadSession(params: LoadSessionRequest): Promise<LoadSessionResponse>;\n setSessionMode?(params: SetSessionModeRequest): Promise<SetSessionModeResponse>;\n unstable_setSessionModel?(params: SetSessionModelRequest): Promise<SetSessionModelResponse>;\n prompt(params: {\n sessionId: string;\n prompt: ContentBlock[];\n _meta?: Record<string, unknown>;\n }): Promise<PromptResponse>;\n cancel(params: CancelNotification): Promise<void>;\n extMethod?(method: string, params: Record<string, unknown>): Promise<Record<string, unknown>>;\n extNotification?(method: string, params: Record<string, unknown>): Promise<void>;\n };\n private transport?: StreamableHttpTransport;\n private options: StreamableHttpClientOptions;\n private state: ClientState = 'disconnected';\n private initializeResponse?: InitializeResponse;\n\n // Managers\n private artifactManager: ArtifactManager;\n private permissionManager: PermissionManager;\n private questionManager: QuestionManager;\n private extensionManager: ExtensionManager;\n\n // Event emitter\n private emitter = new EventEmitter<ClientEvents>();\n\n constructor(options: StreamableHttpClientOptions) {\n this.options = options;\n\n // Initialize artifact manager\n this.artifactManager = new ArtifactManager({\n logger: options.logger\n });\n\n // Initialize permission manager\n this.permissionManager = new PermissionManager({\n timeout: options.permissionTimeout,\n autoRejectOnTimeout: options.permissionAutoRejectOnTimeout ?? true,\n autoApprove: options.autoApprove,\n handler: options.requestPermissionHandler,\n logger: options.logger\n });\n\n // Set up permission event callbacks\n this.permissionManager.setCallbacks({\n onRequest: (requestId, params) => {\n this.emitter.emit('permissionRequest', { requestId, params });\n },\n onResolved: (requestId, optionId) => {\n this.emitter.emit('permissionResolved', { requestId, optionId });\n },\n onRejected: (requestId, reason) => {\n this.emitter.emit('permissionRejected', { requestId, reason });\n },\n onTimeout: requestId => {\n this.emitter.emit('permissionTimeout', { requestId });\n }\n });\n\n // Initialize question manager\n this.questionManager = new QuestionManager({\n timeout: options.questionTimeout,\n autoCancelOnTimeout: options.questionAutoCancelOnTimeout ?? true,\n logger: options.logger\n });\n\n // Set up question event callbacks\n this.questionManager.setCallbacks({\n onRequest: (toolCallId: string, request: QuestionRequest) => {\n this.emitter.emit('questionRequest', { toolCallId, request });\n options.onQuestionRequest?.(toolCallId, request);\n },\n onAnswered: (toolCallId: string, answers: QuestionAnswers) => {\n this.emitter.emit('questionAnswered', { toolCallId, answers });\n },\n onCancelled: (toolCallId: string, reason?: string) => {\n this.emitter.emit('questionCancelled', { toolCallId, reason });\n },\n onTimeout: (toolCallId: string) => {\n this.emitter.emit('questionTimeout', { toolCallId });\n }\n });\n\n // Initialize extension manager\n this.extensionManager = new ExtensionManager({\n logger: options.logger\n });\n }\n\n // ============================================\n // State Management\n // ============================================\n\n /**\n * Get current client state\n */\n get currentState(): ClientState {\n return this.state;\n }\n\n /**\n * Check if client is initialized\n */\n get isInitialized(): boolean {\n return this.state === 'initialized';\n }\n\n /**\n * Check if client is connected (but maybe not initialized)\n */\n get isConnected(): boolean {\n return this.state === 'connected' || this.state === 'initialized';\n }\n\n /**\n * Get agent capabilities from initialization response\n */\n get agentCapabilities() {\n return this.initializeResponse?.agentCapabilities;\n }\n\n /**\n * Get full initialization response\n */\n get initializeResult() {\n return this.initializeResponse;\n }\n\n /**\n * Get current transport connection ID\n */\n get connectionId(): string | undefined {\n return this.transport?.connectionId;\n }\n\n private setState(newState: ClientState): void {\n const previous = this.state;\n this.state = newState;\n\n this.options.logger?.debug(`State change: ${previous} -> ${newState}`);\n this.emitter.emit('stateChange', { previous, current: newState });\n\n // Emit specific state events\n switch (newState) {\n case 'connecting':\n this.emitter.emit('connecting', undefined);\n break;\n case 'connected':\n this.emitter.emit('connected', undefined);\n break;\n case 'disconnected':\n this.emitter.emit('disconnected', undefined);\n break;\n case 'error':\n // Error event is emitted separately with the actual error\n break;\n }\n }\n\n // ============================================\n // Connection Management\n // ============================================\n\n /**\n * Connect and initialize the client\n */\n async connect(): Promise<InitializeResponse> {\n if (this.state !== 'disconnected') {\n await this.disconnect();\n }\n if (this.state === 'initialized') {\n return this.initializeResponse!;\n }\n\n if (this.state === 'connecting') {\n throw new ConnectionError('Connection already in progress');\n }\n\n this.setState('connecting');\n\n try {\n // Create transport\n this.transport = streamableHttp({\n endpoint: this.options.endpoint,\n authToken: this.options.authToken,\n headers: this.options.headers,\n reconnect: this.options.reconnect,\n fetch: this.options.fetch,\n heartbeatTimeout: this.options.heartbeatTimeout,\n postTimeout: this.options.postTimeout,\n connectionTimeout: this.options.connectionTimeout,\n onConnect: connectionId => {\n this.options.logger?.debug(`Transport connected: ${connectionId}`);\n },\n onDisconnect: connectionId => {\n this.options.logger?.debug(`Transport disconnected: ${connectionId}`);\n },\n onError: error => {\n this.options.logger?.error('Transport error:', error);\n this.emitter.emit('error', error);\n },\n });\n\n // Create connection\n const { ClientSideConnection } = await loadAcpSdk();\n this.connection = new ClientSideConnection(\n () => this.createClientHandler(),\n this.transport as unknown as ConstructorParameters<typeof ClientSideConnection>[1]\n );\n\n this.setState('connected');\n\n // Initialize protocol\n // Merge client capabilities with provider defaults (provider takes priority)\n const timeout = this.options.initializeTimeout ?? DEFAULT_INITIALIZE_TIMEOUT;\n const mergedCapabilities = {\n ...this.options.clientCapabilities,\n ...CLOUD_CLIENT_CAPABILITIES,\n _meta: {\n ...this.options.clientCapabilities?._meta,\n ...CLOUD_CLIENT_CAPABILITIES._meta\n }\n };\n const initPromise = this.connection.initialize({\n protocolVersion: PROTOCOL_VERSION,\n clientCapabilities: mergedCapabilities\n });\n\n // Apply timeout\n const timeoutPromise = new Promise<never>((_, reject) => {\n setTimeout(() => {\n reject(new InitializationError(`Initialize timed out after ${timeout}ms`));\n }, timeout);\n });\n\n const initializeResponse = await Promise.race([initPromise, timeoutPromise]) as InitializeResponse;\n this.initializeResponse = initializeResponse;\n this.setState('initialized');\n\n this.options.logger?.info('Client initialized successfully');\n\n return initializeResponse;\n } catch (err) {\n this.setState('error');\n const error = err instanceof Error ? err : new Error(String(err));\n this.emitter.emit('error', error);\n\n if (err instanceof InitializationError || err instanceof ConnectionError) {\n throw err;\n }\n throw new ConnectionError('Failed to connect', error);\n }\n }\n\n /**\n * Disconnect the client gracefully\n * Sends DELETE request to server before closing local resources\n */\n async disconnect(): Promise<void> {\n if (this.state === 'disconnected') {\n return;\n }\n\n this.options.logger?.info('Disconnecting client');\n\n // Close transport gracefully (sends DELETE to server)\n if (this.transport) {\n try {\n await this.transport.close();\n } catch (err) {\n this.options.logger?.warn('Error closing transport:', err);\n }\n this.transport = undefined;\n }\n\n // Clear pending permissions\n this.permissionManager.clear();\n\n // Clear pending question requests\n this.questionManager.clear();\n\n // Clear artifacts\n this.artifactManager.clear();\n\n // Reset state\n this.initializeResponse = undefined;\n this.setState('disconnected');\n }\n\n /**\n * Create the client handler for the connection\n */\n private createClientHandler(): Client {\n return {\n sessionUpdate: async (params: SessionNotification) => {\n await this.handleSessionUpdate(params);\n },\n requestPermission: async (params: RequestPermissionRequest) => this.handleRequestPermission(params),\n extNotification: async (method: string, params: Record<string, unknown>) => {\n await this.handleExtNotification(method, params);\n },\n extMethod: async (method: string, params: Record<string, unknown>): Promise<Record<string, unknown>> =>\n this.handleExtMethod(method, params as unknown as QuestionRequest)\n };\n }\n\n // ============================================\n // Session Management\n // ============================================\n\n /**\n * Create a new session\n *\n * Retries on transient network errors (e.g., proxy connection reset)\n * since session/new is idempotent and safe to retry.\n *\n * A timeout (`options.sessionTimeout`, default 30 s) guards against the\n * SSE response never arriving — the POST returns 202 immediately and the\n * sessionId comes back via GET SSE, which can hang indefinitely.\n * On timeout a `SessionError` is thrown.\n */\n async createSession(cwd: string): Promise<NewSessionResponse> {\n this.ensureInitialized('createSession');\n\n const maxRetries = 2;\n const timeout = this.options.sessionTimeout ?? DEFAULT_SESSION_TIMEOUT;\n let lastError: Error | undefined;\n\n for (let attempt = 0; attempt <= maxRetries; attempt++) {\n try {\n const sessionPromise = this.connection.newSession({\n cwd,\n mcpServers: []\n });\n\n // Apply timeout - session/new response comes via GET SSE,\n // which can hang indefinitely if the server never responds\n let response: NewSessionResponse;\n if (timeout > 0) {\n const timeoutPromise = new Promise<never>((_, reject) => {\n setTimeout(() => {\n reject(new SessionError(`session/new timed out after ${timeout}ms`));\n }, timeout);\n });\n response = await Promise.race([sessionPromise, timeoutPromise]);\n } else {\n response = await sessionPromise;\n }\n\n this.options.logger?.info(`Session created: ${response.sessionId}`);\n return response;\n } catch (err) {\n lastError = err instanceof Error ? err : new Error(String(err));\n\n if (attempt < maxRetries && isRetryableNetworkError(err)) {\n const delay = 500 * Math.pow(2, attempt); // 500ms, 1000ms\n this.options.logger?.warn(\n `session/new network error, retrying in ${delay}ms ` +\n `(attempt ${attempt + 1}/${maxRetries}): ${lastError.message}`\n );\n await new Promise(resolve => setTimeout(resolve, delay));\n continue;\n }\n\n throw new SessionError(\n `Failed to create session: ${lastError.message}`,\n undefined,\n lastError\n );\n }\n }\n\n // Safety net\n throw new SessionError(\n `Failed to create session: ${lastError?.message}`,\n undefined,\n lastError\n );\n }\n\n /**\n * Load an existing session\n * Requires agent to support loadSession capability\n */\n async loadSession(sessionId: string, cwd: string): Promise<LoadSessionResponse> {\n this.ensureInitialized('loadSession');\n\n if (!this.agentCapabilities?.loadSession) {\n throw new SessionError('Agent does not support session loading', sessionId);\n }\n\n try {\n const response = await this.connection.loadSession({\n sessionId,\n cwd,\n mcpServers: []\n });\n\n this.options.logger?.info(`Session loaded: ${sessionId}`);\n return response;\n } catch (err) {\n throw new SessionError(\n `Failed to load session: ${err instanceof Error ? err.message : String(err)}`,\n sessionId,\n err instanceof Error ? err : undefined\n );\n }\n }\n\n /**\n * Set the session mode\n */\n async setSessionMode(params: SetSessionModeRequest): Promise<SetSessionModeResponse> {\n this.ensureInitialized('setSessionMode');\n\n this.options.logger?.debug(`Setting session mode: ${params.sessionId} -> ${params.modeId}`);\n\n return this.connection.setSessionMode!(params);\n }\n\n /**\n * Set the session model\n * @experimental This API is unstable and may change\n */\n async setSessionModel(params: SetSessionModelRequest): Promise<SetSessionModelResponse> {\n this.ensureInitialized('setSessionModel');\n\n this.options.logger?.debug(`Setting session model: ${params.sessionId} -> ${params.modelId}`);\n\n return this.connection.unstable_setSessionModel!(params);\n }\n\n // ============================================\n // Prompt\n // ============================================\n\n /**\n * Send a prompt to the agent\n */\n async prompt(\n sessionId: string,\n prompt: ContentBlock[],\n options?: PromptOptions\n ): Promise<PromptResponse> {\n this.ensureInitialized('prompt');\n\n this.options.logger?.debug(`Sending prompt to session: ${sessionId}`);\n\n return this.connection.prompt({\n sessionId,\n prompt,\n _meta: options?.planMode ? { planMode: true, ...options._meta } : options?._meta\n });\n }\n\n /**\n * Cancel ongoing operations for a session\n */\n async cancel(sessionId: string): Promise<void> {\n this.ensureInitialized('cancel');\n\n this.options.logger?.debug(`Cancelling session: ${sessionId}`);\n\n await this.connection.cancel({ sessionId });\n }\n\n // ============================================\n // Permission Management\n // ============================================\n\n /**\n * Resolve a pending permission request\n */\n resolvePermission(requestId: string, optionId: string): boolean {\n return this.permissionManager.resolve(requestId, optionId);\n }\n\n /**\n * Reject a pending permission request\n */\n rejectPermission(requestId: string, reason?: string): boolean {\n return this.permissionManager.reject(requestId, reason);\n }\n\n /**\n * Get all pending permissions\n */\n getPendingPermissions() {\n return this.permissionManager.getPending();\n }\n\n /**\n * Check if there are pending permissions\n */\n hasPendingPermissions(): boolean {\n return this.permissionManager.hasPending();\n }\n\n // ============================================\n // Question Management (ask_followup_question)\n // ============================================\n\n /**\n * Answer a pending question request with user's selections\n */\n answerQuestion(toolCallId: string, answers: QuestionAnswers): boolean {\n return this.questionManager.answer(toolCallId, answers);\n }\n\n /**\n * Cancel a pending question request\n */\n cancelQuestion(toolCallId: string, reason?: string): boolean {\n return this.questionManager.cancel(toolCallId, reason);\n }\n\n /**\n * Get all pending question requests\n */\n getPendingQuestions() {\n return this.questionManager.getPending();\n }\n\n /**\n * Check if there are pending question requests\n */\n hasPendingQuestions(): boolean {\n return this.questionManager.hasPending();\n }\n\n // ============================================\n // Extension Methods\n // ============================================\n\n /**\n * Send an extension method request\n */\n async extMethod(method: string, params: Record<string, unknown>): Promise<Record<string, unknown>> {\n this.ensureInitialized('extMethod');\n return this.connection.extMethod!(method, params);\n }\n\n /**\n * Send an extension notification\n */\n async extNotification(method: string, params: Record<string, unknown>): Promise<void> {\n this.ensureInitialized('extNotification');\n return this.connection.extNotification!(method, params);\n }\n\n // ============================================\n // Event Emitter Implementation\n // ============================================\n\n on<K extends keyof ClientEvents>(\n event: K,\n listener: (data: ClientEvents[K]) => void | Promise<void>\n ): this {\n this.emitter.on(event, listener);\n return this;\n }\n\n off<K extends keyof ClientEvents>(\n event: K,\n listener: (data: ClientEvents[K]) => void | Promise<void>\n ): this {\n this.emitter.off(event, listener);\n return this;\n }\n\n once<K extends keyof ClientEvents>(\n event: K,\n listener: (data: ClientEvents[K]) => void | Promise<void>\n ): this {\n this.emitter.once(event, listener);\n return this;\n }\n\n emit<K extends keyof ClientEvents>(event: K, data: ClientEvents[K]): boolean {\n return this.emitter.emit(event, data);\n }\n\n removeAllListeners<K extends keyof ClientEvents>(event?: K): this {\n this.emitter.removeAllListeners(event);\n return this;\n }\n\n // ============================================\n // Internal Handlers\n // ============================================\n\n private async handleSessionUpdate(params: SessionNotification): Promise<void> {\n // Forward to callback\n await this.options.onSessionUpdate?.(params);\n\n // Emit event\n this.emitter.emit('sessionUpdate', params);\n }\n\n private async handleRequestPermission(\n params: RequestPermissionRequest\n ): Promise<RequestPermissionResponse> {\n return this.permissionManager.handleRequest(params);\n }\n\n private async handleExtNotification(\n method: string,\n params: Record<string, unknown>\n ): Promise<void> {\n // Handle artifact notifications\n if (method === ExtensionMethod.ARTIFACT) {\n const notification = params as unknown as ArtifactNotificationParams;\n const artifactData = notification.artifact as any;\n this.options.logger?.debug('[ACP-Client] Received artifact notification:', {\n event: notification.event,\n artifactUri: artifactData?.uri,\n artifactType: artifactData?.type,\n });\n\n // For deleted events, get full artifact before deletion for callbacks\n if (notification.event === 'deleted') {\n const existing = this.artifactManager.get(notification.artifact.uri);\n this.artifactManager.handleNotification(notification);\n if (existing) {\n await this.options.onArtifact?.(existing, 'deleted');\n this.emitter.emit('artifactDeleted', existing);\n }\n } else {\n const { artifact, event } = notification;\n // Let artifactManager handle the notification\n this.artifactManager.handleNotification(notification);\n // Get the artifact from manager or use the original\n const storedArtifact = this.artifactManager.get(artifact.uri) || artifact;\n\n this.options.logger?.debug('[ACP-Client] Stored artifact:', {\n event,\n artifactUri: storedArtifact.uri,\n artifactType: storedArtifact.type,\n hasText: storedArtifact.type === 'plan' ? !!(storedArtifact as any).text : undefined,\n });\n\n await this.options.onArtifact?.(storedArtifact, event);\n\n if (event === 'created') {\n this.options.logger?.debug('[ACP-Client] Emitting artifactCreated event');\n this.emitter.emit('artifactCreated', storedArtifact);\n if (storedArtifact.type === 'plan') {\n await this.options.onPlanReady?.(storedArtifact);\n }\n } else {\n this.options.logger?.debug('[ACP-Client] Emitting artifactUpdated event');\n this.emitter.emit('artifactUpdated', storedArtifact);\n }\n }\n return;\n }\n\n // Handle checkpoint notifications\n if (method === ExtensionMethod.CHECKPOINT) {\n const notification = params as unknown as CheckpointNotificationParams;\n if (notification.event === 'created') {\n this.emitter.emit('checkpointCreated', notification.checkpoint);\n } else if (notification.event === 'updated') {\n this.emitter.emit('checkpointUpdated', notification.checkpoint);\n }\n return;\n }\n\n // Forward other extensions to callback and manager\n await this.options.onExtNotification?.(method, params);\n await this.extensionManager.handleNotification(method, params);\n }\n\n private async handleExtMethod(\n method: string,\n params: QuestionRequest\n ): Promise<Record<string, unknown>> {\n // Handle question requests (ask_followup_question via question extMethod)\n if (method === ExtensionMethod.QUESTION) {\n const response = await this.questionManager.handleRequest(params);\n\n // Convert QuestionResponse to ToolInputResponse format expected by SDK\n if (response.outcome === 'submitted' && response.answers) {\n return {\n outcome: {\n outcome: 'submitted',\n data: {\n answers: response.answers\n }\n }\n };\n } else {\n return {\n outcome: {\n outcome: 'cancelled',\n reason: response.reason\n }\n };\n }\n }\n\n // Unknown extension method\n this.options.logger?.warn(`Unknown extension method: ${method}`);\n return {\n outcome: {\n outcome: 'cancelled',\n reason: 'unknown method'\n }\n };\n }\n\n // ============================================\n // Helpers\n // ============================================\n\n private ensureInitialized(operation: string): void {\n if (this.state !== 'initialized') {\n throw new InvalidStateError(operation, this.state, ['initialized']);\n }\n }\n}\n\nexport default StreamableHttpClient;\n\n/**\n * Check if an error is a retryable network-level error.\n * Only network failures (TypeError from fetch) are retried, NOT HTTP errors (4xx/5xx).\n */\nfunction isRetryableNetworkError(error: unknown): boolean {\n if (error instanceof TypeError) {return true;}\n if (error instanceof Error) {\n const msg = error.message.toLowerCase();\n return msg.includes('failed to fetch') ||\n msg.includes('fetch failed') ||\n msg.includes('network request failed') ||\n msg.includes('econnreset') ||\n msg.includes('econnrefused') ||\n msg.includes('socket hang up');\n }\n return false;\n}\n","/**\n * ACP 客户端 — 订阅模型\n *\n * 设计:直接映射到 ACP 协议的两条独立通道:\n *\n * - **RPC 通道(POST)**:`prompt` / `sessionCancel` 等是纯 `Promise`,转发上游。\n * - **Notification 通道(SSE)**:`subscribe(sessionId, listener)` 给用户注册\n * 监听器,每条上游 `SessionNotification` 多路分发给所有订阅者。\n *\n * 不做聚合、不建队列。上游 `SessionNotification` / `PromptResponse` 等类型原封\n * 不动透给上层(`Session` 类)。\n *\n * 具体实现基于 vendor 的 `StreamableHttpClient`,它内部管理一条 SSE + POST 复合\n * 通道。用户侧看到的只是\"一个 session 对应一个 AcpClient\"。\n */\n\nimport { AcpProtocolError, NetworkError } from '../errors';\nimport type { Logger, LogLevel,RuntimeConnectOpts } from '../opts';\nimport type { PromptResponse } from '../types';\nimport { StreamableHttpClient } from './vendor/client';\nimport type {\n ContentBlock,\n SessionNotification,\n} from './vendor/sdk';\n\n// ─── 过滤官方 ACP SDK 噪音日志 ────────────────\n//\n// @agentclientprotocol/sdk v0.4.8 内部对 session/update 做 zod schema 校验,\n// CodeBuddy 扩展的 session_info_update / usage_update / available_commands_update\n// 等扩展消息不符合官方 schema,会触发硬编码的\n// `console.error(\"Error handling notification\", message, error)`。\n// 这些日志纯粹是噪音,不影响功能(标准 agent_message_chunk 仍能通过校验)。\n//\n// 策略:只过滤 JSON-RPC \"Invalid params\"(code -32602)错误。\n// 其他错误类型(method not found / internal error / 用户代码异常等)全部保留。\nlet _consolePatched = false;\nfunction patchAcpSdkNoiseLogsOnce(): void {\n if (_consolePatched) {return;}\n _consolePatched = true;\n const origError = console.error.bind(console);\n console.error = (...args: unknown[]): void => {\n // 匹配签名:console.error(\"Error handling notification\", message, error)\n if (args.length >= 3 && args[0] === 'Error handling notification') {\n const err = args[2] as { code?: number } | null | undefined;\n // JSON-RPC Invalid params (schema 校验失败) → 过滤\n if (err && typeof err === 'object' && err.code === -32602) {return;}\n }\n origError(...args);\n };\n}\n\n// ─── 类型 ────────────────────────────────\n\nexport type AcpConnectionState = 'INITIAL' | 'CONNECTING' | 'OPEN' | 'CLOSING' | 'CLOSED';\n\n/** 连接级事件(用于高级用户诊断,如 UI 显示\"重连中\")。 */\nexport interface AcpConnectionEvents {\n open: () => void;\n error: (err: Error) => void;\n close: () => void;\n}\n\n/** Notification 订阅器签名 —— 收到的是上游 `SessionNotification` 原样。 */\nexport type NotificationListener = (notification: SessionNotification) => void;\n\n/** AcpClient 构造选项。 */\nexport interface AcpClientOpts {\n /** 日志器(已按级别过滤;通常由上层 `loggerFor(connectionOpts)` 传入)。 */\n logger?: Logger;\n /**\n * 已解析的日志级别(`resolveLogLevel(connectionOpts)` 的结果)。\n *\n * 唯一用途:决定是否把 logger **透传给底层 vendor**(ACP StreamableHttpClient)。\n * 规则:只有 `'debug'` 级别才透传,其他级别下 vendor 内部日志全部 noop。\n */\n logLevel?: LogLevel;\n /** 替换底层 fetch(接 OpenTelemetry / 代理 / mock)。 */\n fetch?: typeof fetch;\n}\n\n// ─── AcpClient ────────────────────────────────\n\nexport class AcpClient {\n private _state: AcpConnectionState = 'INITIAL';\n private _client: StreamableHttpClient | undefined;\n private _initialized = false;\n private _sessionIds: Set<string> = new Set();\n\n private readonly _logger: Logger | undefined;\n private readonly _fetch: typeof fetch | undefined;\n private readonly _exposeVendorLogs: boolean;\n\n tokenRefresher?: () => Promise<string>;\n\n /** 按 sessionId 分组的 notification 订阅器。 */\n private readonly _subscribers: Map<string, Set<NotificationListener>> = new Map();\n\n /** 连接级事件监听器(open / error / close)。 */\n private readonly _connListeners: {\n [K in keyof AcpConnectionEvents]: Set<AcpConnectionEvents[K]>;\n } = {\n open: new Set(),\n error: new Set(),\n close: new Set(),\n };\n\n /** per-session prompt 串行队列(ACP 协议要求:同 session 不能并发 prompt)。 */\n private readonly _activePrompts: Set<string> = new Set();\n private readonly _promptQueues: Map<string, Array<() => void>> = new Map();\n\n constructor(opts?: AcpClientOpts) {\n this._logger = opts?.logger;\n this._fetch = opts?.fetch;\n this._exposeVendorLogs = opts?.logLevel === 'debug';\n }\n\n // ─── 属性 ────────────────────────────────\n\n get state(): AcpConnectionState { return this._state; }\n get connectionId(): string | undefined { return this._client?.connectionId; }\n get sessionIds(): string[] { return Array.from(this._sessionIds); }\n get initialized(): boolean { return this._initialized; }\n\n setTokenRefresher(fn: () => Promise<string>): void {\n this.tokenRefresher = fn;\n }\n\n // ─── 连接管理 ────────────────────────────────\n\n async connect(acpUrl: string, token: string, opts?: RuntimeConnectOpts): Promise<void> {\n if (this._state === 'OPEN' || this._state === 'CONNECTING') {return;}\n this._state = 'CONNECTING';\n\n // 首次连接时惰性过滤官方 SDK 的噪音日志\n patchAcpSdkNoiseLogsOnce();\n\n this._logger?.debug(`[acp conn=-] connecting to ${acpUrl}`);\n\n try {\n this._client = new StreamableHttpClient({\n endpoint: acpUrl,\n authToken: token,\n headers: opts?.headers,\n reconnect: {\n enabled: true,\n initialDelay: opts?.reconnectBackoffMs ?? 1000,\n maxDelay: opts?.reconnectMaxBackoffMs ?? 30_000,\n maxRetries: opts?.reconnectMaxAttempts ?? Infinity,\n },\n heartbeatTimeout: opts?.heartbeatTimeoutMs ?? 60_000,\n initializeTimeout: 30_000,\n postTimeout: 30_000,\n logger: this._exposeVendorLogs ? this._logger : undefined,\n fetch: this._fetch,\n // 上游每来一条 session/update notification 就回调这里。\n // vendor 的 `SessionUpdateCallback` 签名就是 `(n: SessionNotification) => void`,\n // 所以这里直接用强类型,不需要 `params: unknown` + 类型守卫。\n onSessionUpdate: (notification: SessionNotification) => this.dispatchNotification(notification),\n });\n\n this._client.on('connected', () => {\n this._logger?.debug(`[acp conn=${this._client?.connectionId ?? '-'}] connected`);\n this.emitConnEvent('open');\n });\n this._client.on('error', (err: Error) => {\n // 运行期 transport 抖动:SDK 会自动重连,错误不会抛给调用方。\n // 默认级别下仍可见(warn),对齐 Python 的 exhausted 类 warning 策略。\n this._logger?.warn(\n `[acp conn=${this._client?.connectionId ?? '-'}] error: ${err.message}`,\n );\n this.emitConnEvent('error', err);\n });\n\n await this._client.connect();\n\n this._state = 'OPEN';\n this._initialized = true;\n } catch (err) {\n this._state = 'CLOSED';\n this._logger?.debug(`[acp conn=-] connect failed: ${(err as Error).message}`);\n throw new NetworkError(`ACP connect failed: ${(err as Error).message}`, { cause: err as Error });\n }\n }\n\n async disconnect(): Promise<void> {\n if (this._state === 'CLOSED' || this._state === 'CLOSING') {return;}\n this._state = 'CLOSING';\n // 先记住 id —— client 清空后就拿不到了,但日志希望带断开前的 id\n const lastConnId = this._client?.connectionId ?? '-';\n if (this._client) {\n try { await this._client.disconnect(); } catch { /* ignore */ }\n this._client = undefined;\n }\n this._initialized = false;\n this._state = 'CLOSED';\n this._subscribers.clear();\n this._activePrompts.clear();\n this._promptQueues.clear();\n this._logger?.debug(`[acp conn=${lastConnId}] disconnected`);\n this.emitConnEvent('close');\n }\n\n // ─── 协议方法(转发上游)────────────────────────────────\n\n /** initialize 由 connect() 内部完成,这里只取缓存结果。 */\n async initialize(): Promise<unknown> {\n if (!this._client) {throw new AcpProtocolError('Not connected');}\n return this._client.initializeResult;\n }\n\n async sessionNew(sessionId?: string): Promise<string> {\n if (!this._client) {throw new AcpProtocolError('Not connected');}\n const result = await this._client.createSession('/workspace');\n const newId = result.sessionId || sessionId || '';\n this._sessionIds.add(newId);\n return newId;\n }\n\n async sessionLoad(sessionId: string): Promise<void> {\n if (!this._client) {throw new AcpProtocolError('Not connected');}\n await this._client.loadSession(sessionId, '/workspace');\n this._sessionIds.add(sessionId);\n }\n\n /**\n * 发 prompt。纯 Promise,直接转发上游 `session/prompt` RPC。\n *\n * - **不聚合 notification**:本次 prompt 期间的 notifications 由\n * `subscribe()` 订阅器独立接收,与此 Promise 并行。\n * - **串行化**:同 sessionId 的多次 `prompt()` 会**排队**等前一个完成再发出\n * (ACP 协议要求),保证顺序一致。\n * - **signal 支持**:`opts.signal` abort 时向服务端发 `session/cancel`。\n * 本 Promise 会以 `AbortError` reject。\n */\n async prompt(\n sessionId: string,\n input: ContentBlock[],\n opts?: { signal?: AbortSignal }\n ): Promise<PromptResponse> {\n if (!this._client) {throw new AcpProtocolError('Not connected');}\n\n return new Promise<PromptResponse>((resolve, reject) => {\n this.enqueuePrompt(sessionId, async () => {\n // abort 时立即向服务端发 cancel 通知,并 reject 调用方 Promise\n let aborted = false;\n const onAbort = (): void => {\n aborted = true;\n // 尽力而为:cancel RPC 失败也无所谓,调用方已经知道要放弃\n this._client?.cancel(sessionId).catch(() => { /* warn 在 Session.cancel 做 */ });\n const err = new Error('Prompt aborted');\n err.name = 'AbortError';\n reject(err);\n };\n if (opts?.signal) {\n if (opts.signal.aborted) { onAbort(); return; }\n opts.signal.addEventListener('abort', onAbort, { once: true });\n }\n\n try {\n const response = await this._client!.prompt(sessionId, input as never[]) as PromptResponse;\n if (!aborted) {resolve(response);}\n } catch (err) {\n if (!aborted) {reject(err);}\n } finally {\n opts?.signal?.removeEventListener('abort', onAbort);\n }\n });\n });\n }\n\n /** 发 session/cancel 通知(幂等,尽力而为)。 */\n async sessionCancel(sessionId: string): Promise<void> {\n if (!this._client) {throw new AcpProtocolError('Not connected');}\n await this._client.cancel(sessionId);\n }\n\n // ─── Notification 订阅 ────────────────────────────────\n\n /**\n * 订阅指定 sessionId 的上游 notifications。\n *\n * Listener 收到的是上游 `SessionNotification` 原样(`{ sessionId, update, _meta? }`)。\n * 同一 session 可以有任意多个 listener,彼此独立;每条 notification 都会\n * 按注册顺序调用所有 listener(同步调用,异常被吞)。\n *\n * @returns unsubscribe 函数,调用即退订。\n */\n subscribe(sessionId: string, listener: NotificationListener): () => void {\n if (!this._subscribers.has(sessionId)) {\n this._subscribers.set(sessionId, new Set());\n }\n this._subscribers.get(sessionId)!.add(listener);\n return () => {\n this._subscribers.get(sessionId)?.delete(listener);\n };\n }\n\n // ─── 连接级事件订阅(高级用户诊断用)────────────────────────────────\n\n on<K extends keyof AcpConnectionEvents>(event: K, handler: AcpConnectionEvents[K]): void {\n this._connListeners[event].add(handler as AcpConnectionEvents[K]);\n }\n off<K extends keyof AcpConnectionEvents>(event: K, handler: AcpConnectionEvents[K]): void {\n this._connListeners[event].delete(handler as AcpConnectionEvents[K]);\n }\n\n // ─── 内部 ────────────────────────────────\n\n /**\n * 把上游 notification 按 sessionId 分发给订阅者。不做任何转换。\n *\n * 上游保证 `SessionNotification` 的 `sessionId` / `update` 字段都有值\n * (vendor 的 `SessionUpdateCallback` 签名即如此),无需再做类型守卫。\n */\n private dispatchNotification(notification: SessionNotification): void {\n const subs = this._subscribers.get(notification.sessionId);\n if (!subs || subs.size === 0) {return;}\n\n for (const listener of subs) {\n try {\n listener(notification);\n } catch {\n // 订阅者抛错不影响其他订阅者;不记日志(SDK 不能替用户处理业务异常)\n }\n }\n }\n\n private emitConnEvent<K extends keyof AcpConnectionEvents>(\n event: K,\n ...args: Parameters<AcpConnectionEvents[K]>\n ): void {\n for (const handler of this._connListeners[event]) {\n try {\n (handler as (...a: unknown[]) => void)(...args);\n } catch { /* ignore */ }\n }\n }\n\n private enqueuePrompt(sid: string, exec: () => Promise<void>): void {\n if (!this._promptQueues.has(sid)) {this._promptQueues.set(sid, []);}\n const runThenDequeue = (): void => {\n this._activePrompts.add(sid);\n exec().finally(() => this.dequeuePrompt(sid));\n };\n if (this._activePrompts.has(sid)) {\n this._promptQueues.get(sid)!.push(runThenDequeue);\n } else {\n runThenDequeue();\n }\n }\n\n private dequeuePrompt(sid: string): void {\n this._activePrompts.delete(sid);\n const q = this._promptQueues.get(sid);\n if (q && q.length > 0) {q.shift()!();}\n }\n}\n","/**\n * Session — 对话上下文\n *\n * 控制面(REST):`info` / `update` / `delete`\n * 数据面(ACP):`connect` / `prompt` / `subscribe` / `disconnect`\n *\n * **订阅模型**(对齐 ACP 协议原生形态):\n * - `prompt(input)` 返回 `Promise<PromptResponse>` —— 一轮的终局\n * - `subscribe(listener)` —— 流式 notifications 由 listener 异步接收\n * - 两条通道独立、不聚合、无队列\n *\n * 典型用法:\n * ```ts\n * await session.connect();\n *\n * // 场景 A:只要最终结果\n * const response = await session.prompt('hello');\n * console.log(response.stopReason);\n *\n * // 场景 B:流式打印 + 最终结果\n * const unsub = session.subscribe((n) => {\n * if (n.update.sessionUpdate === 'agent_message_chunk' &&\n * n.update.content.type === 'text') {\n * process.stdout.write(n.update.content.text);\n * }\n * });\n * const response = await session.prompt('hello');\n * unsub();\n *\n * // 场景 C:便利钩子(等价于 B 但不需手动 unsub)\n * const response = await session.prompt('hello', {\n * onChunk: (n) => { ... },\n * });\n * ```\n */\n\nimport { AcpClient } from './acp/client';\nimport { ValidationError } from './errors';\nimport { loggerFor, resolveLogLevel } from './internal/log';\nimport type { PromptOpts, RequestOpts, RuntimeConnectOpts } from './opts';\nimport { RestClient } from './rest/client';\nimport type { Runtime } from './runtime';\nimport type {\n ContentBlock,\n DeleteResult, PromptResponse,\n SessionInfo, SessionNotification, SessionStatus,\n UpdateSessionRequest,\n} from './types';\n\nexport class Session {\n readonly id: string;\n readonly runtimeId: string;\n\n private readonly _runtime: Runtime;\n private readonly _restClient: RestClient;\n\n /** 数据面 ACP 客户端(connect() 后可用) */\n private _acpClient: AcpClient | undefined;\n\n /** 控制面状态(来自最近一次 info() / update())。 */\n private _status: SessionStatus | undefined;\n\n /** @internal */\n constructor(\n id: string,\n runtime: Runtime,\n restClient: RestClient,\n ) {\n this.id = id;\n this.runtimeId = runtime.id;\n this._runtime = runtime;\n this._restClient = restClient;\n }\n\n // ============================================================\n // 状态\n // ============================================================\n\n get status(): SessionStatus | undefined { return this._status; }\n\n /** ACP 连接是否已建立 */\n get connected(): boolean {\n return this._acpClient?.state === 'OPEN';\n }\n\n // ============================================================\n // 控制面(REST)\n // ============================================================\n\n /** 拉最新元数据 */\n async info(opts?: RequestOpts): Promise<SessionInfo> {\n const info = await this._restClient.get<SessionInfo>(\n `/runtimes/${this.runtimeId}/sessions/${this.id}`,\n undefined,\n opts\n );\n this._status = info.sessionStatus;\n return info;\n }\n\n /** 更新 name / manifest */\n async update(req: UpdateSessionRequest, opts?: RequestOpts): Promise<SessionInfo> {\n const info = await this._restClient.post<SessionInfo>(\n `/runtimes/${this.runtimeId}/sessions/${this.id}/update`,\n req,\n opts\n );\n this._status = info.sessionStatus;\n return info;\n }\n\n /** 软删除 */\n async delete(opts?: RequestOpts): Promise<DeleteResult> {\n // 断开 ACP\n if (this._acpClient) {\n await this._acpClient.disconnect();\n this._acpClient = undefined;\n }\n return this._restClient.post<DeleteResult>(\n `/runtimes/${this.runtimeId}/sessions/${this.id}/delete`,\n undefined,\n opts\n );\n }\n\n // ============================================================\n // 数据面 — 连接管理(ACP)\n // ============================================================\n\n /**\n * 建立到沙箱的 ACP 连接。\n *\n * 内部流程:GET SSE → 获取 connectionId → initialize → session/load。\n * 调用后 `prompt` / `subscribe` / `cancel` 才可用。\n *\n * 幂等:已连接时直接返回;并发调用时后来的等前者完成。\n */\n async connect(opts?: RuntimeConnectOpts): Promise<void> {\n if (this._acpClient && this._acpClient.state === 'OPEN') {\n return; // 已连接\n }\n\n const acpUrl = this._runtime.acpUrl;\n let acpToken = this._runtime.acpToken;\n\n if (!acpUrl || !acpToken) {\n // 尝试刷新\n acpToken = await this._runtime.refreshToken();\n if (!this._runtime.acpUrl || !acpToken) {\n throw new ValidationError('Runtime does not have ACP link. Is it in RUNNING state?');\n }\n }\n\n const connOpts = this._runtime._connectionOpts;\n const client = new AcpClient({\n logger: loggerFor(connOpts),\n logLevel: resolveLogLevel(connOpts),\n fetch: connOpts.fetch,\n });\n\n // 注入 token 刷新\n client.setTokenRefresher(async () => this._runtime.refreshToken());\n\n // 建立 SSE 连接。`...opts` 必须放前面,让后面显式字段兜底 undefined。\n await client.connect(this._runtime.acpUrl!, acpToken!, {\n ...opts,\n heartbeatTimeoutMs: opts?.heartbeatTimeoutMs ?? 45_000,\n reconnectMaxAttempts: opts?.reconnectMaxAttempts ?? Infinity,\n reconnectBackoffMs: opts?.reconnectBackoffMs ?? 300,\n reconnectMaxBackoffMs: opts?.reconnectMaxBackoffMs ?? 30_000,\n lastEventId: opts?.lastEventId,\n });\n\n // ACP initialize\n if (opts?.initialize !== false) {\n await client.initialize();\n }\n\n // 数据面只做 session/load(session 创建是控制面的事,通过 REST 完成)\n await client.sessionLoad(this.id);\n\n this._acpClient = client;\n }\n\n /** 断开 ACP 连接。所有订阅器被自动清除。 */\n async disconnect(): Promise<void> {\n if (this._acpClient) {\n await this._acpClient.disconnect();\n this._acpClient = undefined;\n }\n }\n\n // ============================================================\n // 数据面 — Prompt & Notification 订阅(ACP)\n // ============================================================\n\n /**\n * 发送 prompt 并等待 `PromptResponse`。\n *\n * @param input 纯文本字符串(自动包装成 text block)或 `ContentBlock[]`(多模态)\n * @param opts 见 `PromptOpts`,支持 `signal` 取消、`onChunk` 便利钩子等\n *\n * @returns `PromptResponse`(当前只含 `stopReason`)\n *\n * **时序**:\n * - 如果未 connect,会自动 connect\n * - RPC 发出期间,上游会通过 **SSE notification 通道**推送 `session/update`,\n * 这些消息**不会进 Promise 的结果**,需要通过 `subscribe()` 或 `onChunk`\n * 回调接收\n * - 同 session 并发 prompt 会被内部**串行化**(ACP 协议要求)\n *\n * @example\n * ```ts\n * // 最简:只要结果\n * const r = await session.prompt('2+2?');\n *\n * // 流式打印 + 结果\n * const r = await session.prompt('write a poem', {\n * onChunk: (n) => {\n * if (n.update.sessionUpdate === 'agent_message_chunk' &&\n * n.update.content.type === 'text') {\n * process.stdout.write(n.update.content.text);\n * }\n * },\n * });\n *\n * // 取消\n * const ctrl = new AbortController();\n * setTimeout(() => ctrl.abort(), 5000);\n * const r = await session.prompt('long task', { signal: ctrl.signal });\n * ```\n */\n async prompt(\n input: string | ContentBlock[],\n opts?: PromptOpts\n ): Promise<PromptResponse> {\n // 自动 connect\n if (!this._acpClient || this._acpClient.state !== 'OPEN') {\n await this.connect();\n }\n\n const content: ContentBlock[] = typeof input === 'string'\n ? [{ type: 'text', text: input }]\n : input;\n\n // 便利钩子:临时订阅,prompt 结束自动 unsub\n const unsubChunk = opts?.onChunk\n ? this._acpClient!.subscribe(this.id, opts.onChunk)\n : undefined;\n\n // 合并用户 signal 与超时\n let timeoutCtrl: AbortController | undefined;\n let signal = opts?.signal;\n if (opts?.timeoutMs !== undefined && opts.timeoutMs > 0) {\n timeoutCtrl = new AbortController();\n const timer = setTimeout(() => timeoutCtrl!.abort(), opts.timeoutMs);\n // 用户 signal 触发时也要清 timer 避免 leak\n signal?.addEventListener('abort', () => {\n clearTimeout(timer);\n timeoutCtrl!.abort();\n }, { once: true });\n // 把 timeoutCtrl.signal 作为最终 signal 传下去(abort 会传染)\n if (!signal) {\n signal = timeoutCtrl.signal;\n } else {\n // 两个 signal 合并:任一 abort 就 abort\n signal = mergeAbortSignals(signal, timeoutCtrl.signal);\n }\n }\n\n opts?.onTurnStart?.();\n\n try {\n const response = await this._acpClient!.prompt(this.id, content, { signal });\n opts?.onTurnEnd?.(response);\n return response;\n } finally {\n unsubChunk?.();\n }\n }\n\n /**\n * 订阅该 session 所有上游 notifications。\n *\n * Listener 收到的是上游 `SessionNotification` 原样(`{ sessionId, update, _meta? }`)。\n * `update` 是上游 11-tag 判别联合,在 switch 分支里类型自动收窄。\n *\n * 订阅独立于 prompt 生命周期——connect 之后注册,直到 unsubscribe 或\n * disconnect 为止。一个 session 支持任意多个订阅者。\n *\n * @returns unsubscribe 函数,调用即退订。\n *\n * @example\n * ```ts\n * const unsub = session.subscribe((n) => {\n * switch (n.update.sessionUpdate) {\n * case 'agent_message_chunk':\n * if (n.update.content.type === 'text') print(n.update.content.text);\n * break;\n * case 'tool_call':\n * console.log('tool:', n.update.title);\n * break;\n * }\n * });\n * // ...\n * unsub();\n * ```\n */\n subscribe(listener: (notification: SessionNotification) => void): () => void {\n if (!this._acpClient || this._acpClient.state !== 'OPEN') {\n throw new ValidationError('Session not connected. Call connect() first.');\n }\n return this._acpClient.subscribe(this.id, listener);\n }\n\n /**\n * 取消当前运行的 prompt(如果有)。\n *\n * 向服务端发 `session/cancel` notification,服务端会以 `stopReason: 'cancelled'`\n * 结束当前 prompt,对应的 `prompt()` Promise 正常 resolve(不 reject)。\n *\n * **尽力而为**:服务端 RPC 失败时打 warn 日志吞掉,不抛给调用方——\n * 因为\"用户点了取消按钮\"的 UX 契约就是\"本地能返回\"。\n */\n async cancel(): Promise<void> {\n if (!this._acpClient) {return;}\n try {\n await this._acpClient.sessionCancel(this.id);\n } catch (err) {\n const logger = loggerFor(this._runtime._connectionOpts);\n logger.warn(`[session ${this.id}] cancel failed: ${(err as Error).message}`);\n }\n }\n}\n\n// ─── 工具 ────────────────────────────────\n\n/**\n * 合并两个 AbortSignal:任一 abort 时返回的 signal 也 abort。\n *\n * 用原生 `AbortSignal.any()` 不行——Node 18 没有。这里用最小 polyfill。\n */\nfunction mergeAbortSignals(a: AbortSignal, b: AbortSignal): AbortSignal {\n if (typeof (AbortSignal as unknown as { any?: (s: AbortSignal[]) => AbortSignal }).any === 'function') {\n return (AbortSignal as unknown as { any: (s: AbortSignal[]) => AbortSignal }).any([a, b]);\n }\n const ctrl = new AbortController();\n const onAbort = (): void => ctrl.abort();\n if (a.aborted || b.aborted) {\n ctrl.abort();\n } else {\n a.addEventListener('abort', onAbort, { once: true });\n b.addEventListener('abort', onAbort, { once: true });\n }\n return ctrl.signal;\n}\n","/**\n * Runtime — 一个云端沙箱实例\n *\n * 由 CloudAgentClient.runtimes.create() 或 .from() 返回。\n * 返回时已持有控制面 info(status、metadata)和数据面连接信息(acpLink、sandboxId)。\n *\n * Runtime 实例方法覆盖自身的控制面操作(update/delete/refreshToken)。\n * 通过 sessions 子命名空间管理 Session 的控制面 CRUD。\n */\n\nimport type { ConnectionOpts, RequestOpts, SessionCreateOpts, SessionListOpts } from './opts';\nimport type {\n RuntimeInfo, SessionInfo, PageResult, DeleteResult,\n UpdateRuntimeRequest, CreateSessionRequest,\n} from './types';\nimport { RestClient } from './rest/client';\nimport { Session } from './session';\n\nexport class Runtime {\n readonly id: string;\n\n /** 控制面信息快照(创建/刷新时更新) */\n private _info: RuntimeInfo;\n\n /** 数据面连接信息 */\n readonly sandboxId?: string;\n readonly sandboxDomain?: string;\n private _acpUrl?: string;\n private _acpToken?: string;\n\n /** 内部依赖 */\n private readonly _restClient: RestClient;\n /** @internal 供 Session 构造 AcpClient 时读取(logger / fetch)。 */\n readonly _connectionOpts: ConnectionOpts;\n\n /** 默认 session ID */\n private _defaultSessionId: string | undefined;\n\n /** @internal */\n constructor(\n restClient: RestClient,\n connectionOpts: ConnectionOpts,\n info: RuntimeInfo,\n ) {\n this.id = info.id;\n this._info = info;\n this._restClient = restClient;\n this._connectionOpts = connectionOpts;\n\n this.sandboxId = info.links?.sandboxLink?.sandboxId;\n this.sandboxDomain = info.links?.sandboxLink?.endpoint;\n this._acpUrl = info.links?.acpLink?.url;\n this._acpToken = info.links?.acpLink?.token;\n\n if (info.sessions && info.sessions.length > 0) {\n this._defaultSessionId = info.sessions[0].sessionId;\n }\n }\n\n // ─── 公共属性 ────────────────────────────────\n\n get runtimeInfo(): RuntimeInfo { return this._info; }\n get acpUrl(): string | undefined { return this._acpUrl; }\n get acpToken(): string | undefined { return this._acpToken; }\n\n // ============================================================\n // Runtime 自身操作(控制面)\n // ============================================================\n\n /** 更新 Runtime 元数据 */\n async update(req: UpdateRuntimeRequest, opts?: RequestOpts): Promise<RuntimeInfo> {\n const info = await this._restClient.post<RuntimeInfo>(`/runtimes/${this.id}/update`, req, opts);\n this._info = info;\n return info;\n }\n\n /** 软删除 */\n async delete(opts?: RequestOpts): Promise<DeleteResult> {\n return this._restClient.post<DeleteResult>(`/runtimes/${this.id}/delete`, undefined, opts);\n }\n\n /** 刷新 token(拉最新 RuntimeInfo,更新 acpLink) */\n async refreshToken(opts?: RequestOpts): Promise<string> {\n const info = await this._restClient.get<RuntimeInfo>(`/runtimes/${this.id}`, undefined, opts);\n this._info = info;\n if (info.links?.acpLink) {\n this._acpUrl = info.links.acpLink.url;\n this._acpToken = info.links.acpLink.token;\n }\n return this._acpToken || '';\n }\n\n // ============================================================\n // sessions — 控制面 CRUD\n // ============================================================\n\n readonly sessions = {\n /** 创建新 Session(控制面),返回 Session 实例 */\n create: async (opts: SessionCreateOpts): Promise<Session> => {\n // 组装 REST body —— CreateSessionRequest 是后端 API 的权威镜像\n const body: CreateSessionRequest = {\n sessionId: opts.sessionId,\n sessionName: opts.sessionName,\n agentManifest: opts.agentManifest,\n };\n\n const info = await this._restClient.post<SessionInfo>(\n `/runtimes/${this.id}/sessions`,\n body,\n {\n timeoutMs: opts.timeoutMs,\n headers: opts.headers,\n signal: opts.signal,\n requestId: opts.requestId,\n }\n );\n\n return new Session(info.sessionId, this, this._restClient);\n },\n\n /** 获取 Session(返回实例) */\n get: async (sessionId: string, opts?: RequestOpts): Promise<Session> => {\n // 验证 session 存在(发请求),然后返回实例\n await this._restClient.get<SessionInfo>(\n `/runtimes/${this.id}/sessions/${sessionId}`,\n undefined,\n opts\n );\n return new Session(sessionId, this, this._restClient);\n },\n\n /** 分页列表(返回纯数据) */\n list: async (opts?: SessionListOpts): Promise<PageResult<SessionInfo>> => {\n const params: Record<string, string> = {};\n if (opts?.page !== undefined) params.page = String(opts.page);\n if (opts?.pageSize !== undefined) params.pageSize = String(opts.pageSize);\n if (opts?.sessionStatus) params.sessionStatus = opts.sessionStatus;\n return this._restClient.get<PageResult<SessionInfo>>(\n `/runtimes/${this.id}/sessions`,\n params,\n opts\n );\n },\n\n /** 默认 session(Runtime 创建时自动生成的) */\n default: (): Session => {\n const sessionId = this._defaultSessionId || this.id;\n return new Session(sessionId, this, this._restClient);\n },\n };\n}\n","/**\n * CloudAgentClient — SDK 顶层入口\n *\n * 持有 ConnectionOpts,提供 runtimes 子命名空间(仅控制面集合操作)。\n * 本身不发起网络请求、不持有连接。\n */\n\nimport { loggerFor } from './internal/log';\nimport type { ConnectionOpts, RequestOpts, RuntimeCreateOpts, RuntimeListOpts } from './opts';\nimport { RestClient } from './rest/client';\nimport { Runtime } from './runtime';\nimport type { AgentManifest,CreateRuntimeRequest, PageResult, RuntimeInfo } from './types';\n\n/** Secret key 名(服务端 `constants.CodebuddyAPIKey`)。 */\nconst CODEBUDDY_API_KEY = 'CODEBUDDY_API_KEY';\n\nexport class CloudAgentClient {\n private readonly opts: ConnectionOpts;\n /** @internal */\n readonly _restClient: RestClient;\n\n /** 构造(同步,不发网络请求) */\n constructor(opts: ConnectionOpts = {}) {\n // 认证策略由调用方决定:\n // - 后端:提供 apiKey\n // - 浏览器:通过 baseUrl 指向业务后端代理(由代理注入鉴权),或通过 headers 携带业务登录态\n // 这里不做强校验,请求失败时服务端会返回 401/403。\n this.opts = opts;\n this._restClient = new RestClient(opts);\n }\n\n /** 派生新实例(覆盖部分配置,如切换 sourceApp) */\n with(overrides: Partial<ConnectionOpts>): CloudAgentClient {\n return new CloudAgentClient({ ...this.opts, ...overrides });\n }\n\n // ============================================================\n // runtimes — 控制面集合操作\n // ============================================================\n\n readonly runtimes = {\n /**\n * 创建 Runtime(同步接口,返回时沙箱已 RUNNING)\n * 返回 Runtime 实例,可直接操作 sessions。\n *\n * **自动注入 `CODEBUDDY_API_KEY`**:沙箱内 agent 调大模型网关需要这个 secret\n * (见服务端 `sandbox_builder.go`)。SDK 兜底逻辑:\n *\n * - 如果 `opts.agentManifest.secrets` 已显式声明 `CODEBUDDY_API_KEY` → 保留用户值\n * - 否则若 `opts.agentManifest` 已传 **且** `ConnectionOpts.apiKey` 存在\n * → 追加一条 `CODEBUDDY_API_KEY` secret(不 mutate 入参)\n *\n * 这样用户只需在 `new CloudAgentClient({ apiKey })` 里提供一次,不必在每次\n * `runtimes.create` 里重复声明同一个 key。\n *\n * 注意:SDK 不会在用户完全没传 `agentManifest` 时帮他编造 `id/name/manifestVersion`\n * 等业务字段——那些是用户自己的 agent 身份标识,必须显式指定。\n */\n create: async (opts: RuntimeCreateOpts): Promise<Runtime> => {\n const agentManifest = withInjectedApiKeySecret(\n opts.agentManifest,\n this.opts.apiKey,\n this.opts,\n );\n\n // 组装 REST body —— CreateRuntimeRequest 是后端 API 的权威镜像\n // (JSON.stringify 自动跳过 undefined 字段,不用手动 if-push)\n const body: CreateRuntimeRequest = {\n runtimeName: opts.runtimeName,\n agentManifest,\n sandboxTemplateId: opts.sandboxTemplateId,\n sandboxSpec: opts.sandboxSpec,\n sandboxType: opts.sandboxType,\n visibility: opts.visibility,\n metadata: opts.metadata,\n };\n\n const info = await this._restClient.post<RuntimeInfo>(\n '/runtimes',\n body,\n {\n timeoutMs: opts.timeoutMs ?? 120_000,\n headers: opts.headers,\n signal: opts.signal,\n requestId: opts.requestId,\n }\n );\n\n return new Runtime(this._restClient, this.opts, info);\n },\n\n /** 获取 Runtime(返回实例) */\n get: async (runtimeId: string, opts?: RequestOpts): Promise<Runtime> => {\n const info = await this._restClient.get<RuntimeInfo>(`/runtimes/${runtimeId}`, undefined, opts);\n return new Runtime(this._restClient, this.opts, info);\n },\n\n /** 分页列表(返回纯数据) */\n list: async (opts?: RuntimeListOpts): Promise<PageResult<RuntimeInfo>> => {\n const params: Record<string, string> = {};\n if (opts?.page !== undefined) {params.page = String(opts.page);}\n if (opts?.pageSize !== undefined) {params.pageSize = String(opts.pageSize);}\n if (opts?.metadata) {params.metadata = JSON.stringify(opts.metadata);}\n return this._restClient.get<PageResult<RuntimeInfo>>('/runtimes', params, opts);\n },\n };\n}\n\n// ============================================================\n// 内部辅助\n// ============================================================\n\n/**\n * 按需注入 `CODEBUDDY_API_KEY` secret 的兜底逻辑。\n *\n * SDK 只负责一件事:**把 `ConnectionOpts.apiKey` 透传到沙箱 agent** —— 这个\n * credential 本来就是调用方已经提供过的,用户不应该被迫在 manifest 里再写一遍。\n *\n * 规则(按优先级):\n * 1. `userManifest.secrets[CODEBUDDY_API_KEY]` 已显式声明 → 保留用户值,不覆盖\n * 2. `userManifest` 根本没传 → 原样返回 `undefined`,让服务端按\"manifest 必填字段缺失\"\n * 报明确错误(SDK 不编造 `id/name/manifestVersion` 等用户的业务语义)\n * 3. `ConnectionOpts.apiKey` 为空 → 无从兜底,原样返回\n * 4. 其他情况(用户传了 manifest 但没 `CODEBUDDY_API_KEY`,且 Client 有 apiKey)\n * → 追加 secrets,不 mutate 入参\n *\n * 设计取舍:SDK 不探查 `opts.metadata.CODEBUDDY_API_KEY` —— metadata 是\n * AgentOS 与上游网关之间的内部协议(见服务端 `sandbox_builder.go` 的优先级逻辑),\n * 不是 SDK 用户的常规使用通道。即便用户显式在 metadata 里塞了一个 key,服务端\n * 自身的优先级会用 metadata 值覆盖 manifest 里注入的那条,行为正确。\n */\nfunction withInjectedApiKeySecret(\n userManifest: AgentManifest | undefined,\n apiKey: string | undefined,\n connectionOpts: ConnectionOpts,\n): AgentManifest | undefined {\n // Case 1: 用户已显式声明\n if (userManifest?.secrets?.some(s => s.key === CODEBUDDY_API_KEY)) {\n return userManifest;\n }\n\n // Case 2: 用户根本没传 manifest —— SDK 不越界编造业务字段\n // 服务端会按\"manifest 缺 id/name/manifestVersion\"报错,这是用户该看到的真实错误\n if (!userManifest) {\n return undefined;\n }\n\n // Case 3: 无 apiKey 可兜底\n if (!apiKey) {\n return userManifest;\n }\n\n // Case 4: 兜底注入(纯函数,不 mutate 入参)\n const logger = loggerFor(connectionOpts);\n logger.debug(\n `[runtimes.create] auto-injected ${CODEBUDDY_API_KEY} secret from ConnectionOpts.apiKey `\n + '(no explicit value in agentManifest.secrets)',\n );\n\n return {\n ...userManifest,\n secrets: [\n ...(userManifest.secrets ?? []),\n { key: CODEBUDDY_API_KEY, value: apiKey },\n ],\n };\n}\n","/**\n * ManifestBuilder — Agent Manifest 构造器\n *\n * 按 manifest-spec.md v1.0 的 4 大类提供 fluent API。\n * 纯本地,不发网络请求。\n */\n\nimport type {\n AgentManifest,\n ManifestRule,\n ManifestSkill,\n ManifestSubagent,\n ManifestSlashCommand,\n ManifestPlugin,\n ManifestMcp,\n ManifestWorkspace,\n ManifestEnv,\n ManifestSecret,\n} from './types';\nimport { ValidationError } from './errors';\n\nexport class ManifestBuilder {\n // ─── 基础配置 ────────────────────────────────\n private _id?: string;\n private _name?: string;\n private _version?: string;\n private _systemPrompt?: string;\n private _systemPromptFile?: string;\n private _useWorkspaceRoot?: boolean;\n private _isolateConfigDir?: boolean;\n private _settings?: string;\n\n // ─── 能力与规范 ──────────────────────────────\n private _rules: ManifestRule[] = [];\n private _skills: ManifestSkill[] = [];\n private _subagents: ManifestSubagent[] = [];\n private _slashCommands: ManifestSlashCommand[] = [];\n private _plugins: ManifestPlugin[] = [];\n private _mcp: ManifestMcp[] = [];\n\n // ─── 工作空间 ────────────────────────────────\n private _workspaces: ManifestWorkspace[] = [];\n\n // ─── 环境配置 ────────────────────────────────\n private _secrets: ManifestSecret[] = [];\n private _envs: ManifestEnv[] = [];\n\n // ─── 扩展字段 ────────────────────────────────\n private _extra: Record<string, unknown> = {};\n\n // ============================================================\n // 基础配置\n // ============================================================\n\n id(id: string): this {\n this._id = id;\n return this;\n }\n\n name(name: string): this {\n this._name = name;\n return this;\n }\n\n version(version: string): this {\n this._version = version;\n return this;\n }\n\n systemPrompt(prompt: string): this {\n this._systemPrompt = prompt;\n this._systemPromptFile = undefined;\n return this;\n }\n\n systemPromptFile(url: string): this {\n this._systemPromptFile = url;\n this._systemPrompt = undefined;\n return this;\n }\n\n useWorkspaceRoot(value = true): this {\n this._useWorkspaceRoot = value;\n return this;\n }\n\n isolateConfigDir(value = true): this {\n this._isolateConfigDir = value;\n return this;\n }\n\n settings(url: string): this {\n this._settings = url;\n return this;\n }\n\n // ============================================================\n // 能力与规范(统一复数,接受单个或数组)\n // ============================================================\n\n rules(...rules: ManifestRule[]): this {\n this._rules.push(...rules);\n return this;\n }\n\n skills(...skills: Array<ManifestSkill | string>): this {\n for (const s of skills) {\n this._skills.push(typeof s === 'string' ? { name: s } : s);\n }\n return this;\n }\n\n subagents(...subagents: Array<ManifestSubagent | string>): this {\n for (const s of subagents) {\n this._subagents.push(typeof s === 'string' ? { name: s } : s);\n }\n return this;\n }\n\n slashCommands(...cmds: Array<ManifestSlashCommand | string>): this {\n for (const c of cmds) {\n this._slashCommands.push(typeof c === 'string' ? { name: c } : c);\n }\n return this;\n }\n\n plugins(...plugins: ManifestPlugin[]): this {\n this._plugins.push(...plugins);\n return this;\n }\n\n mcp(...mcps: ManifestMcp[]): this {\n this._mcp.push(...mcps);\n return this;\n }\n\n // ============================================================\n // 工作空间(统一复数)\n // ============================================================\n\n workspaces(...wss: ManifestWorkspace[]): this {\n this._workspaces.push(...wss);\n return this;\n }\n\n // ============================================================\n // 环境配置(统一复数)\n // ============================================================\n\n secrets(...secrets: ManifestSecret[]): this {\n this._secrets.push(...secrets);\n return this;\n }\n\n envs(...envs: ManifestEnv[]): this {\n this._envs.push(...envs);\n return this;\n }\n\n // ============================================================\n // 扩展\n // ============================================================\n\n /** 设置任意扩展字段 */\n raw(key: string, value: unknown): this {\n this._extra[key] = value;\n return this;\n }\n\n // ============================================================\n // 构建\n // ============================================================\n\n /** 校验必填字段并构建 */\n build(): AgentManifest {\n if (!this._id) throw new ValidationError('manifest.id is required');\n if (!this._name) throw new ValidationError('manifest.name is required');\n if (!this._version) throw new ValidationError('manifest.manifestVersion is required');\n if (this._systemPrompt && this._systemPromptFile) {\n throw new ValidationError('system_prompt and system_prompt_file are mutually exclusive');\n }\n\n const manifest: AgentManifest = {\n id: this._id,\n name: this._name,\n manifestVersion: this._version,\n };\n\n // 基础配置\n if (this._systemPrompt) manifest.system_prompt = this._systemPrompt;\n if (this._systemPromptFile) manifest.system_prompt_file = this._systemPromptFile;\n if (this._useWorkspaceRoot !== undefined) manifest.useWorkspaceRoot = this._useWorkspaceRoot;\n if (this._isolateConfigDir !== undefined) manifest.isolateConfigDir = this._isolateConfigDir;\n if (this._settings) manifest.settings = this._settings;\n\n // 能力与规范\n if (this._rules.length > 0) manifest.rules = this._rules;\n if (this._skills.length > 0) manifest.skills = this._skills;\n if (this._subagents.length > 0) manifest.subagents = this._subagents;\n if (this._slashCommands.length > 0) manifest.slashCommands = this._slashCommands;\n if (this._plugins.length > 0) manifest.plugins = this._plugins;\n if (this._mcp.length > 0) manifest.mcp = this._mcp;\n\n // 工作空间\n if (this._workspaces.length > 0) manifest.workspaces = this._workspaces;\n\n // 环境配置\n if (this._secrets.length > 0) manifest.secrets = this._secrets;\n if (this._envs.length > 0) manifest.envs = this._envs;\n\n // 扩展字段\n Object.assign(manifest, this._extra);\n\n return manifest;\n }\n}\n"],"mappings":"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"}