@tencent-ai/cloud-agent-sdk 0.2.5 → 0.2.6

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":["ClientSideConnection","PROTOCOL_VERSION","Sandbox"],"sources":["../../agent-client-protocol/src/common/types.ts","../../agent-client-protocol/src/common/transport/streamable-http.ts","../../agent-client-protocol/src/common/client/constants.ts","../../agent-client-protocol/src/common/client/errors.ts","../../agent-client-protocol/src/common/client/events.ts","../../agent-client-protocol/src/common/client/artifacts.ts","../../agent-client-protocol/src/common/client/permissions.ts","../../agent-client-protocol/src/common/client/questions.ts","../../agent-client-protocol/src/common/client/extensions.ts","../../agent-client-protocol/src/common/client/client.ts","../../agent-provider/src/common/providers/cloud-agent-provider/cloud-connection.ts","../../agent-provider/src/common/providers/cloud-agent-provider/e2b-filesystem.ts","../../agent-provider/src/common/providers/cloud-agent-provider/cos-upload-service.ts","../../agent-provider/src/backend/types.ts","../../agent-provider/src/backend/backend-provider.ts","../../agent-provider/src/backend/ipc-backend-provider.ts","../../agent-provider/src/common/providers/cloud-agent-provider/cloud-provider.ts","../../agent-provider/src/common/providers/local-agent-provider/local-connection.ts","../../agent-provider/src/common/client/session.ts","../../agent-provider/src/common/client/session-manager.ts","../../agent-provider/src/common/client/client.ts","../../agent-provider/src/common/client/types.ts"],"sourcesContent":["/**\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 /** Usage notification for token/cost tracking */\n USAGE: '_codebuddy.ai/usage',\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.USAGE,\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}\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' | 'document' | 'spreadsheet';\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 /** Questions to ask (1-4) */\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// Usage Update Types\n// ============================================\n\n/**\n * Token usage information\n * Sent via extNotification: _codebuddy.ai/usage\n */\nexport interface UsageUpdate {\n sessionId: string;\n inputTokens?: number;\n outputTokens?: number;\n totalTokens?: number;\n cost?: number;\n model?: string;\n _meta?: 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}\n","// Streamable HTTP Transport for ACP\n// Enables browser-based clients to connect to cloud-hosted ACP agents.\n//\n// Protocol flow:\n// 1. Client establishes GET SSE connection, receives Acp-Connection-Id\n// 2. Client sends POST requests with Acp-Connection-Id header\n// 3. Notifications arrive via GET SSE, responses via POST SSE\n\nimport type { Stream } from '@agentclientprotocol/sdk';\n\ntype StreamMessage = Stream extends { readable: ReadableStream<infer T> } ? T : never;\n\nexport interface StreamableHttpOptions {\n // ACP endpoint URL, e.g. 'https://cloud-agent.example.com/acp'\n endpoint: string;\n // Authorization token (sent as Bearer token)\n authToken?: string;\n // Custom headers to include in all requests\n headers?: Record<string, string>;\n // Reconnect options for SSE connections\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, adds ±25% jitter to prevent thundering herd\n };\n // AbortSignal to cancel the connection\n signal?: AbortSignal;\n // Custom fetch implementation (for testing or non-browser environments)\n fetch?: typeof fetch;\n // Callback when connection is established\n onConnect?: (connectionId: string) => void;\n // Callback when connection is closed\n onDisconnect?: (connectionId: string) => void;\n // Callback when an error occurs\n onError?: (error: Error) => void;\n // Heartbeat timeout in ms (default: 60000). If no heartbeat received within this time, reconnect.\n // Set to 0 to disable heartbeat detection.\n heartbeatTimeout?: number;\n // POST request timeout in ms (default: 30000)\n postTimeout?: number;\n // Backpressure options for message queue\n backpressure?: {\n highWaterMark?: number; // default: 100, pause reading SSE when queue reaches this\n lowWaterMark?: number; // default: 50, resume reading SSE when queue drops to this\n };\n}\n\n/**\n * Extended Stream interface with connection management\n */\nexport interface StreamableHttpTransport extends Stream {\n /**\n * Current connection ID, undefined if not connected\n */\n readonly connectionId: string | undefined;\n /**\n * Promise that resolves when the SSE connection is established\n * and the connectionId is available. Callers should await this\n * before sending messages to ensure the transport is ready.\n */\n readonly ready: Promise<void>;\n /**\n * Close the connection gracefully (sends DELETE request)\n */\n close(): Promise<void>;\n}\n\ninterface SSEEvent {\n type: string;\n data: string;\n id?: string;\n}\n\nfunction parseSSELine(\n line: string,\n currentEvent: Partial<SSEEvent>\n): { event?: SSEEvent; reset: boolean; isComment: boolean } {\n if (line === '') {\n if (currentEvent.data) {\n return {\n event: {\n type: currentEvent.type || 'message',\n data: currentEvent.data,\n id: currentEvent.id,\n },\n reset: true,\n isComment: false,\n };\n }\n return { reset: true, isComment: false };\n }\n\n // SSE comments (including heartbeats) start with ':'\n if (line.startsWith(':')) {\n return { reset: false, isComment: true };\n }\n\n const colonIndex = line.indexOf(':');\n if (colonIndex === -1) {\n return { reset: false, isComment: false };\n }\n\n const field = line.slice(0, colonIndex);\n let value = line.slice(colonIndex + 1);\n if (value.startsWith(' ')) {\n value = value.slice(1);\n }\n\n switch (field) {\n case 'event':\n // Reset data when starting a new event type\n // This prevents data from previous events being concatenated\n if (currentEvent.type && currentEvent.type !== value) {\n currentEvent.data = undefined;\n }\n currentEvent.type = value;\n break;\n case 'data':\n currentEvent.data = (currentEvent.data || '') + value;\n break;\n case 'id':\n currentEvent.id = value;\n break;\n }\n\n return { reset: false, isComment: false };\n}\n\n// Create a Streamable HTTP transport.\n//\n// Example:\n// const transport = streamableHttp({\n// endpoint: 'https://agent.example.com/acp',\n// authToken: 'token123',\n// onConnect: (id) => console.log('Connected:', id),\n// onDisconnect: (id) => console.log('Disconnected:', id),\n// });\n//\n// // Later, close gracefully\n// await transport.close();\nexport function streamableHttp(options: StreamableHttpOptions): 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 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 } = backpressure;\n\n // Connection state\n let connectionId: string | undefined;\n let lastEventId: string | undefined;\n let reconnectAttempts = 0;\n let closed = false;\n let isClosing = false;\n\n // Promise that resolves when GET SSE is connected and we have connectionId\n let connectionReady: Promise<void>;\n let resolveConnection: () => void;\n let rejectConnection: (error: Error) => void;\n\n // Connection version to track reconnections\n let connectionVersion = 0;\n\n connectionReady = new Promise((resolve, reject) => {\n resolveConnection = resolve;\n rejectConnection = reject;\n });\n\n const abortController = new AbortController();\n\n // Combine signals - use manual approach for broader compatibility\n function isAborted(): boolean {\n return abortController.signal.aborted || (externalSignal?.aborted ?? false);\n }\n\n function getSignal(): AbortSignal {\n // AbortSignal.any is available in newer Node.js versions\n const anyFn = (AbortSignal as unknown as { any?: (signals: AbortSignal[]) => AbortSignal }).any;\n if (externalSignal && typeof anyFn === 'function') {\n return anyFn([externalSignal, abortController.signal]);\n }\n return abortController.signal;\n }\n\n const combinedSignal = getSignal();\n\n // Message queue for incoming messages with backpressure\n const messageQueue: StreamMessage[] = [];\n const messageResolvers: Array<(value: StreamMessage | null) => void> = [];\n let streamError: Error | null = null;\n let isPaused = false;\n let resumeReading: (() => void) | null = null;\n\n // Heartbeat tracking\n let lastActivity = Date.now();\n let heartbeatCheckTimer: ReturnType<typeof setInterval> | undefined;\n\n function enqueueMessage(message: StreamMessage): boolean {\n if (messageResolvers.length > 0) {\n const resolver = messageResolvers.shift()!;\n resolver(message);\n return true;\n } else {\n messageQueue.push(message);\n // Check if we should pause reading due to backpressure\n if (messageQueue.length >= highWaterMark) {\n isPaused = true;\n return false;\n }\n return true;\n }\n }\n\n function dequeueMessage(): Promise<StreamMessage | null> {\n if (closed) {\n return Promise.resolve(null);\n }\n if (streamError) {\n return Promise.reject(streamError);\n }\n if (messageQueue.length > 0) {\n const message = messageQueue.shift()!;\n // Check if we should resume reading\n if (isPaused && messageQueue.length <= lowWaterMark) {\n isPaused = false;\n resumeReading?.();\n }\n return Promise.resolve(message);\n }\n return new Promise((resolve) => {\n messageResolvers.push(resolve);\n });\n }\n\n function updateLastActivity(): void {\n lastActivity = Date.now();\n }\n\n function startHeartbeatCheck(triggerReconnect: () => void): void {\n if (heartbeatTimeout <= 0) {\n return;\n }\n // Check heartbeat every 10 seconds\n heartbeatCheckTimer = setInterval(() => {\n if (Date.now() - lastActivity > heartbeatTimeout) {\n console.warn('[StreamableHTTP] Heartbeat timeout, triggering reconnect');\n triggerReconnect();\n }\n }, 10000);\n }\n\n function stopHeartbeatCheck(): void {\n if (heartbeatCheckTimer) {\n clearInterval(heartbeatCheckTimer);\n heartbeatCheckTimer = undefined;\n }\n }\n\n /**\n * Calculate reconnect delay with optional jitter\n */\n function calculateDelay(attempt: number): number {\n const baseDelay = Math.min(initialDelay * Math.pow(2, attempt - 1), maxDelay);\n if (!jitterEnabled) {\n return baseDelay;\n }\n // Add ±25% jitter to prevent thundering herd\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 // Resume any paused reading\n if (resumeReading) {\n resumeReading();\n resumeReading = null;\n }\n rejectConnection(error);\n onError?.(error);\n while (messageResolvers.length > 0) {\n const resolver = messageResolvers.shift()!;\n resolver(null);\n }\n }\n\n function closeNormally(): void {\n closed = true;\n stopHeartbeatCheck();\n // Resume any paused reading\n if (resumeReading) {\n resumeReading();\n resumeReading = null;\n }\n while (messageResolvers.length > 0) {\n const resolver = messageResolvers.shift()!;\n resolver(null);\n }\n }\n\n // Send DELETE request to close connection gracefully\n async function sendDelete(): Promise<void> {\n if (!connectionId || isClosing) {\n return;\n }\n\n isClosing = true;\n const currentConnectionId = connectionId;\n\n try {\n const headers = buildHeaders();\n headers['Acp-Connection-Id'] = currentConnectionId;\n\n await customFetch(endpoint, {\n method: 'DELETE',\n headers,\n signal: AbortSignal.timeout(5000), // 5s timeout for DELETE\n });\n } catch {\n // Ignore DELETE errors - connection may already be closed\n } finally {\n if (currentConnectionId) {\n onDisconnect?.(currentConnectionId);\n }\n isClosing = false;\n }\n }\n\n function buildHeaders(): Record<string, string> {\n const headers: Record<string, string> = {\n ...customHeaders,\n };\n\n if (authToken) {\n headers['Authorization'] = `Bearer ${authToken}`;\n }\n\n return headers;\n }\n\n async function processSSEStream(\n reader: ReadableStreamDefaultReader<Uint8Array>\n ): Promise<void> {\n const decoder = new TextDecoder();\n let buffer = '';\n let currentEvent: Partial<SSEEvent> = {};\n\n try {\n while (true) {\n // Check for backpressure - wait if paused\n if (isPaused) {\n await new Promise<void>(resolve => {\n resumeReading = resolve;\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 const { event, reset, isComment } = parseSSELine(line, currentEvent);\n\n // SSE comments (including heartbeats) update last activity\n if (isComment) {\n updateLastActivity();\n continue;\n }\n\n if (event) {\n // Any event means we're receiving data - update activity\n updateLastActivity();\n\n if (event.id) {\n lastEventId = event.id;\n }\n\n // Skip non-message events (like \"connected\")\n if (event.type !== 'message') {\n continue;\n }\n\n try {\n const message = JSON.parse(event.data) as StreamMessage;\n // Only enqueue valid JSON-RPC messages\n if (message && typeof message === 'object' && 'jsonrpc' in message) {\n enqueueMessage(message);\n }\n } catch {\n console.error('[StreamableHTTP] Failed to parse SSE data:', event.data);\n }\n }\n\n if (reset) {\n currentEvent = {};\n }\n }\n }\n } finally {\n reader.releaseLock();\n }\n }\n\n // Establish GET SSE connection and get connectionId\n async function startSSEConnection(): Promise<void> {\n // Track current reader for heartbeat-triggered reconnect\n let currentReader: ReadableStreamDefaultReader<Uint8Array> | null = null;\n\n // Function to trigger reconnect (called from heartbeat timeout)\n const triggerReconnect = (): void => {\n if (currentReader) {\n currentReader.cancel().catch(() => {/* ignore */});\n }\n };\n\n while (!closed && !isAborted()) {\n try {\n const headers = buildHeaders();\n headers['Accept'] = 'text/event-stream';\n\n if (lastEventId) {\n headers['Last-Event-ID'] = lastEventId;\n }\n\n const response = await customFetch(endpoint, {\n method: 'GET',\n headers,\n signal: combinedSignal,\n });\n\n if (!response.ok) {\n throw new Error(`HTTP ${response.status}`);\n }\n\n // Get connection ID from response - MUST have it\n const newConnectionId = response.headers.get('Acp-Connection-Id');\n if (!newConnectionId) {\n throw new Error('Server did not return Acp-Connection-Id header');\n }\n\n // Track previous connection for disconnect callback\n const previousConnectionId = connectionId;\n\n // Update connection state atomically\n connectionVersion++;\n connectionId = newConnectionId;\n resolveConnection();\n\n // Notify callbacks\n if (previousConnectionId && previousConnectionId !== newConnectionId) {\n onDisconnect?.(previousConnectionId);\n }\n onConnect?.(newConnectionId);\n\n reconnectAttempts = 0;\n\n // Reset heartbeat tracking and start heartbeat check\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 // Stop heartbeat check when connection ends\n stopHeartbeatCheck();\n\n // Connection ended\n const endedConnectionId = connectionId;\n connectionId = undefined;\n\n if (!reconnectEnabled || closed) {\n // Not reconnecting - notify disconnect\n if (endedConnectionId) {\n onDisconnect?.(endedConnectionId);\n }\n break;\n }\n\n // Reconnect - create new connectionReady promise BEFORE clearing connectionId\n // so that sendMessage waits for new connection\n connectionReady = new Promise((resolve, reject) => {\n resolveConnection = resolve;\n rejectConnection = reject;\n });\n } catch (error) {\n // Stop heartbeat check on error\n stopHeartbeatCheck();\n currentReader = null;\n\n if (isAborted() || closed) {\n break;\n }\n\n reconnectAttempts++;\n\n if (reconnectAttempts > maxRetries) {\n closeWithError(new Error(`SSE reconnect failed after ${maxRetries} attempts`));\n break;\n }\n\n // Use calculateDelay with jitter\n const delay = calculateDelay(reconnectAttempts);\n\n console.warn(\n `[StreamableHTTP] SSE error, retrying in ${delay}ms (attempt ${reconnectAttempts}):`,\n error\n );\n\n await new Promise((resolve) => setTimeout(resolve, delay));\n }\n }\n }\n\n // Send message via POST\n async function sendMessage(message: StreamMessage): Promise<void> {\n if (closed) {\n throw new Error('Connection is closed');\n }\n\n // Wait for GET SSE to establish and get connectionId\n // Capture version before waiting to detect reconnections\n const versionBeforeWait = connectionVersion;\n await connectionReady;\n\n // Check if reconnection happened while we were waiting\n if (versionBeforeWait !== connectionVersion && versionBeforeWait > 0) {\n // A reconnection happened - wait for new connection\n await connectionReady;\n }\n\n if (!connectionId) {\n throw new Error('No connection ID available');\n }\n\n const headers = buildHeaders();\n headers['Content-Type'] = 'application/json';\n headers['Accept'] = 'application/json, text/event-stream';\n headers['Acp-Connection-Id'] = connectionId;\n\n // Create timeout controller for POST request\n const postController = new AbortController();\n let timeoutId: ReturnType<typeof setTimeout> | undefined;\n\n // Combine with external signal if present\n const postSignal = postTimeout > 0\n ? postController.signal\n : combinedSignal;\n\n if (postTimeout > 0) {\n timeoutId = setTimeout(() => postController.abort(), postTimeout);\n // Also abort if external signal is aborted\n if (externalSignal) {\n externalSignal.addEventListener('abort', () => postController.abort(), { once: true });\n }\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: postSignal,\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 // Handle response based on content type\n const contentType = response.headers.get('Content-Type') || '';\n\n if (contentType.includes('text/event-stream')) {\n const reader = response.body?.getReader();\n if (reader) {\n await processSSEStream(reader);\n }\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 as StreamMessage);\n }\n }\n // 202 responses have no body\n } finally {\n if (timeoutId) {\n clearTimeout(timeoutId);\n }\n }\n }\n\n // Start SSE connection immediately\n startSSEConnection().catch((error) => {\n console.error('[StreamableHTTP] SSE connection error:', error);\n });\n\n const readable = new ReadableStream<StreamMessage>({\n async pull(controller) {\n const message = await dequeueMessage();\n if (message === null) {\n controller.close();\n } else {\n controller.enqueue(message);\n }\n },\n cancel() {\n closeNormally();\n abortController.abort();\n },\n });\n\n const writable = new WritableStream<StreamMessage>({\n async write(message) {\n await sendMessage(message);\n },\n close() {\n closeNormally();\n abortController.abort();\n },\n abort(reason) {\n closeWithError(reason instanceof Error ? reason : new Error(String(reason)));\n abortController.abort();\n },\n });\n\n // Close the connection gracefully\n async function close(): Promise<void> {\n if (closed) {\n return;\n }\n\n // Send DELETE to server first\n await sendDelete();\n\n // Then close locally\n closeNormally();\n abortController.abort();\n }\n\n return {\n readable,\n writable,\n get connectionId() {\n return connectionId;\n },\n get ready() {\n return connectionReady;\n },\n close,\n };\n}\n\nexport default streamableHttp;\n","/**\n * Protocol constants for Streamable HTTP ACP Client\n */\n\nimport type { ClientCapabilities } from '../sdk.js';\nimport { ExtensionMethod, KNOWN_EXTENSIONS } from '../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 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 public readonly cause?: Error;\n\n constructor(message: string, code: string, cause?: Error) {\n super(message);\n this.name = 'ACPClientError';\n this.code = code;\n this.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 constructor(message: string, sessionId?: string, cause?: Error) {\n super(message, 'SESSION_ERROR', cause);\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","/**\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 * Artifact Manager for Streamable HTTP ACP Client\n * Handles artifact notification processing\n */\n\nimport type {\n Artifact,\n ArtifactEvent,\n ArtifactNotificationParams,\n} from '../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 * Permission Manager for Streamable HTTP ACP Client\n * Handles permission requests with timeout support\n */\n\nimport type { RequestPermissionRequest, RequestPermissionResponse } from '@agentclientprotocol/sdk';\nimport type { Logger, PermissionHandler } from './types.js';\nimport { DEFAULT_PERMISSION_TIMEOUT } from './constants.js';\nimport { TimeoutError } from './errors.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 '../types.js';\nimport type { Logger } from './types.js';\nimport { DEFAULT_QUESTION_TIMEOUT } from './constants.js';\nimport { TimeoutError } from './errors.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 * Extension Method Handler for Streamable HTTP ACP Client\n * Routes and handles custom extension notifications\n */\n\nimport type { UsageUpdate } from '../types.js';\nimport type { Logger } from './types.js';\nimport { ExtensionMethod, KNOWN_EXTENSIONS } from './constants.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/**\n * Parse usage update from extension params\n */\nexport function parseUsageUpdate(params: Record<string, unknown>): UsageUpdate {\n return {\n sessionId: params.sessionId as string,\n inputTokens: params.inputTokens as number | undefined,\n outputTokens: params.outputTokens as number | undefined,\n totalTokens: params.totalTokens as number | undefined,\n cost: params.cost as number | undefined,\n model: params.model as string | undefined,\n _meta: params._meta as Record<string, unknown> | undefined\n };\n}\n","/**\n * Streamable HTTP ACP Client\n * Production-grade client for connecting to cloud-hosted ACP agents\n */\n\nimport {\n ClientSideConnection,\n PROTOCOL_VERSION,\n type Client,\n type SessionNotification,\n type RequestPermissionRequest,\n type RequestPermissionResponse,\n type PromptResponse,\n type InitializeResponse,\n type NewSessionResponse,\n type LoadSessionResponse,\n type SetSessionModeRequest,\n type SetSessionModeResponse,\n type SetSessionModelRequest,\n type SetSessionModelResponse\n} from '@agentclientprotocol/sdk';\n\nimport { streamableHttp, type StreamableHttpTransport } from '../transport/streamable-http.js';\n\nimport type {\n StreamableHttpClientOptions,\n ClientState,\n ClientEvents,\n PromptOptions,\n} from './types.js';\n\nimport type {\n ArtifactNotificationParams,\n CheckpointNotificationParams\n} from '../types.js';\n\nimport {\n CLOUD_CLIENT_CAPABILITIES,\n DEFAULT_INITIALIZE_TIMEOUT,\n ExtensionMethod\n} from './constants.js';\n\nimport {\n ConnectionError,\n InitializationError,\n InvalidStateError,\n SessionError\n} from './errors.js';\n\nimport { EventEmitter } from './events.js';\nimport { ArtifactManager } from './artifacts.js';\nimport { PermissionManager } from './permissions.js';\nimport { QuestionManager, type QuestionRequest, type QuestionResponse, type QuestionAnswers } from './questions.js';\nimport { ExtensionManager, parseUsageUpdate } from './extensions.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!: ClientSideConnection;\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 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 this.connection = new ClientSideConnection(\n () => this.createClientHandler(),\n this.transport\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 this.initializeResponse = await Promise.race([initPromise, timeoutPromise]);\n this.setState('initialized');\n\n this.options.logger?.info('Client initialized successfully');\n\n return this.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) => {\n return this.handleRequestPermission(params);\n },\n extNotification: async (method: string, params: Record<string, unknown>) => {\n console.log('[ACP-Client] extNotification callback invoked:', { method, paramsKeys: Object.keys(params) });\n await this.handleExtNotification(method, params);\n },\n extMethod: async (method: string, params: Record<string, unknown>): Promise<Record<string, unknown>> => {\n // SDK uses generic Record types, cast at boundary to our typed interfaces\n const response = await this.handleExtMethod(method, params as unknown as QuestionRequest);\n return response as unknown as Record<string, unknown>;\n }\n };\n }\n\n // ============================================\n // Session Management\n // ============================================\n\n /**\n * Create a new session\n */\n async createSession(cwd: string): Promise<NewSessionResponse> {\n this.ensureInitialized('createSession');\n\n try {\n const response = await this.connection.newSession({\n cwd,\n mcpServers: []\n });\n\n this.options.logger?.info(`Session created: ${response.sessionId}`);\n return response;\n } catch (err) {\n throw new SessionError(\n `Failed to create session: ${err instanceof Error ? err.message : String(err)}`,\n undefined,\n err instanceof Error ? err : undefined\n );\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 text: string,\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: [{ type: 'text', text }],\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 console.log('[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 console.log('[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 console.log('[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 console.log('[ACP-Client] Emitting artifactUpdated event');\n this.emitter.emit('artifactUpdated', storedArtifact);\n }\n }\n return;\n }\n\n // Handle usage update notifications\n if (method === ExtensionMethod.USAGE) {\n const usage = parseUsageUpdate(params);\n await this.options.onUsageUpdate?.(usage);\n this.emitter.emit('usageUpdate', usage);\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<QuestionResponse> {\n // Handle question requests (ask_followup_question via question extMethod)\n if (method === ExtensionMethod.QUESTION) {\n return this.questionManager.handleRequest(params);\n }\n\n // Unknown extension method\n this.options.logger?.warn(`Unknown extension method: ${method}`);\n return { outcome: 'cancelled', reason: 'unknown method' };\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 * Cloud Agent Connection\n * Wraps StreamableHttpClient to implement AgentConnection interface\n */\n\nimport type {\n SessionNotification,\n RequestPermissionRequest,\n InitializeResponse,\n NewSessionResponse,\n LoadSessionResponse,\n PromptResponse,\n SetSessionModeResponse,\n SetSessionModelResponse\n} from '@agentclientprotocol/sdk';\n\nimport {\n StreamableHttpClient\n} from '@genie/agent-client-protocol';\n\nimport type {\n AgentConnection,\n AgentStatus,\n AgentCapabilities,\n CloudConnectionConfig,\n CreateSessionParams,\n LoadSessionParams,\n PromptParams,\n ConnectionEvents,\n ConnectionEventListener\n} from '../../types.js';\n\nimport type { SessionConnectionInfo } from '../../client/types.js';\n\n/**\n * Cloud Agent Connection implementation\n * Uses Streamable HTTP transport to connect to cloud-hosted ACP agents\n * Uses composition pattern - implements event emitter methods internally\n *\n * TODO: Connection Lifecycle Responsibilities\n * CloudAgentProvider caches connections by endpoint link. This class needs to:\n * - Implement connection health checks (detect and handle connection failures/reconnection)\n * - Handle token expiration (refresh or re-authentication when tokens expire)\n * - Emit 'disconnected' event when connection becomes unhealthy so provider can clean up cache\n */\nexport class CloudAgentConnection implements AgentConnection {\n private client: StreamableHttpClient;\n private listeners: Map<keyof ConnectionEvents, Set<ConnectionEventListener<unknown>>> = new Map();\n private onceListeners: Map<keyof ConnectionEvents, Set<ConnectionEventListener<unknown>>> = new Map();\n\n /**\n * Flag to suppress sessionUpdate event emission during streaming.\n * When true, onSessionUpdate callback won't emit to avoid duplicate messages with promptStream.\n */\n private _isStreaming = false;\n\n /**\n * Session connection information (sandboxId, link, token, etc.)\n * Set by CloudAgentProvider.connect() after fetching session data from backend.\n */\n private _sessionConnectionInfo?: SessionConnectionInfo;\n\n readonly agentId: string;\n readonly transport = 'cloud' as const;\n\n constructor(agentId: string, config: CloudConnectionConfig) {\n this.agentId = agentId;\n\n // Create the underlying StreamableHttpClient\n this.client = new StreamableHttpClient({\n endpoint: config.endpoint,\n authToken: config.authToken,\n headers: config.headers,\n reconnect: config.reconnect,\n initializeTimeout: config.initializeTimeout,\n permissionTimeout: config.permissionTimeout,\n permissionAutoRejectOnTimeout: config.permissionAutoRejectOnTimeout,\n autoApprove: config.autoApprove,\n logger: config.logger,\n fetch: config.fetch,\n clientCapabilities: config.clientCapabilities,\n // Forward events to our emitter (suppressed during streaming to avoid duplicates)\n onSessionUpdate: (update) => {\n if (!this._isStreaming) {\n this.emit('sessionUpdate', update);\n }\n },\n onArtifact: (artifact, event) => {\n console.log('[CloudConnection] onArtifact callback:', {\n event,\n artifactUri: artifact.uri,\n artifactType: artifact.type,\n });\n if (event === 'created') {\n this.emit('artifactCreated', artifact);\n } else if (event === 'updated') {\n this.emit('artifactUpdated', artifact);\n } else if (event === 'deleted') {\n this.emit('artifactDeleted', artifact);\n }\n },\n onUsageUpdate: (usage) => {\n this.emit('usageUpdate', usage);\n }\n });\n\n // Forward client events\n this.setupEventForwarding();\n }\n\n private setupEventForwarding(): void {\n // Forward connection state events\n this.client.on('connecting', () => { this.emit('connecting', undefined); });\n this.client.on('connected', () => { this.emit('connected', undefined); });\n this.client.on('disconnected', () => { this.emit('disconnected', undefined); });\n this.client.on('error', (error) => { this.emit('error', error); });\n this.client.on('stateChange', (change) => { this.emit('stateChange', change); });\n\n // Forward permission events\n this.client.on('permissionRequest', (data) => { this.emit('permissionRequest', data); });\n this.client.on('permissionResolved', (data) => { this.emit('permissionResolved', data); });\n this.client.on('permissionRejected', (data) => { this.emit('permissionRejected', data); });\n this.client.on('permissionTimeout', (data) => { this.emit('permissionTimeout', data); });\n\n // Forward question events\n this.client.on('questionRequest', (data) => { this.emit('questionRequest', data); });\n this.client.on('questionAnswered', (data) => { this.emit('questionAnswered', data); });\n this.client.on('questionCancelled', (data) => { this.emit('questionCancelled', data); });\n this.client.on('questionTimeout', (data) => { this.emit('questionTimeout', data); });\n\n // Forward checkpoint events\n this.client.on('checkpointCreated', (checkpoint) => { this.emit('checkpointCreated', checkpoint); });\n this.client.on('checkpointUpdated', (checkpoint) => { this.emit('checkpointUpdated', checkpoint); });\n }\n\n // ============================================\n // Event Emitter Implementation\n // ============================================\n\n on<K extends keyof ConnectionEvents>(event: K, listener: ConnectionEventListener<ConnectionEvents[K]>): this {\n if (!this.listeners.has(event)) {\n this.listeners.set(event, new Set());\n }\n this.listeners.get(event)!.add(listener as ConnectionEventListener<unknown>);\n return this;\n }\n\n off<K extends keyof ConnectionEvents>(event: K, listener: ConnectionEventListener<ConnectionEvents[K]>): this {\n const eventListeners = this.listeners.get(event);\n if (eventListeners) {\n eventListeners.delete(listener as ConnectionEventListener<unknown>);\n }\n const onceEventListeners = this.onceListeners.get(event);\n if (onceEventListeners) {\n onceEventListeners.delete(listener as ConnectionEventListener<unknown>);\n }\n return this;\n }\n\n once<K extends keyof ConnectionEvents>(event: K, listener: ConnectionEventListener<ConnectionEvents[K]>): this {\n if (!this.onceListeners.has(event)) {\n this.onceListeners.set(event, new Set());\n }\n this.onceListeners.get(event)!.add(listener as ConnectionEventListener<unknown>);\n return this;\n }\n\n emit<K extends keyof ConnectionEvents>(event: K, data: ConnectionEvents[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 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(`Error in async once event listener for '${String(event)}':`, err);\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 removeAllListeners<K extends keyof ConnectionEvents>(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 // State Properties\n // ============================================\n\n get state(): AgentStatus {\n return this.client.currentState as AgentStatus;\n }\n\n get isInitialized(): boolean {\n return this.client.isInitialized;\n }\n\n get capabilities(): AgentCapabilities | undefined {\n return this.client.agentCapabilities as AgentCapabilities | undefined;\n }\n\n get initializeResult(): InitializeResponse | undefined {\n return this.client.initializeResult;\n }\n\n // ============================================\n // Connection Lifecycle\n // ============================================\n\n async connect(): Promise<InitializeResponse> {\n return this.client.connect();\n }\n\n async disconnect(): Promise<void> {\n await this.client.disconnect();\n }\n\n // ============================================\n // Session Management\n // ============================================\n\n async createSession(params: CreateSessionParams): Promise<NewSessionResponse> {\n // Cloud Side does not support creating new sessions directly\n const loadedSession = await this.client.loadSession(this.agentId, params.cwd)\n return { ...loadedSession, sessionId: this.agentId };\n }\n\n async loadSession(params: LoadSessionParams): Promise<LoadSessionResponse> {\n if (!params.sessionId) {\n throw new Error('sessionId is required for loadSession');\n }\n return this.client.loadSession(params.sessionId, params.cwd);\n }\n\n async setSessionMode(sessionId: string, modeId: string): Promise<SetSessionModeResponse> {\n return this.client.setSessionMode({ sessionId, modeId });\n }\n\n async setSessionModel(sessionId: string, modelId: string): Promise<SetSessionModelResponse> {\n return this.client.setSessionModel({ sessionId, modelId });\n }\n\n // ============================================\n // Prompt Operations\n // ============================================\n\n async prompt(sessionId: string, params: PromptParams): Promise<PromptResponse> {\n const text = typeof params.content === 'string'\n ? params.content\n : params.content.map(block => {\n if (block.type === 'text') return block.text;\n return `[${block.type}]`;\n }).join('\\n');\n\n return this.client.prompt(sessionId, text, {\n planMode: params.planMode,\n _meta: params._meta\n });\n }\n\n async *promptStream(sessionId: string, params: PromptParams): AsyncIterable<SessionNotification> {\n // Suppress sessionUpdate event emission during streaming to avoid duplicates\n this._isStreaming = true;\n\n // For streaming, we need to collect updates via the event system\n const updates: SessionNotification[] = [];\n let resolveUpdate: ((value: SessionNotification | null) => void) | null = null;\n let done = false;\n\n const listener = (update: SessionNotification) => {\n if (resolveUpdate) {\n resolveUpdate(update);\n resolveUpdate = null;\n } else {\n updates.push(update);\n }\n };\n\n this.client.on('sessionUpdate', listener);\n\n try {\n // Start the prompt (non-blocking)\n const promptPromise = this.prompt(sessionId, params);\n\n // Yield updates as they come in\n while (!done) {\n const update = updates.shift();\n if (update) {\n yield update;\n } else {\n // Wait for next update or prompt completion\n const nextUpdate = await new Promise<SessionNotification | null>((resolve) => {\n resolveUpdate = resolve;\n // Check if prompt completed while we were setting up\n promptPromise.then(() => {\n if (resolveUpdate === resolve) {\n resolveUpdate = null;\n resolve(null);\n }\n }).catch(() => {\n if (resolveUpdate === resolve) {\n resolveUpdate = null;\n resolve(null);\n }\n });\n });\n\n if (nextUpdate === null) {\n done = true;\n } else {\n yield nextUpdate;\n }\n }\n }\n } finally {\n this._isStreaming = false;\n this.client.off('sessionUpdate', listener);\n }\n }\n\n async cancel(sessionId: string): Promise<void> {\n return this.client.cancel(sessionId);\n }\n\n // ============================================\n // Permission Management\n // ============================================\n\n resolvePermission(requestId: string, optionId: string): boolean {\n return this.client.resolvePermission(requestId, optionId);\n }\n\n rejectPermission(requestId: string, reason?: string): boolean {\n return this.client.rejectPermission(requestId, reason);\n }\n\n getPendingPermissions(): Map<string, { params: RequestPermissionRequest; createdAt: number }> {\n return this.client.getPendingPermissions();\n }\n\n hasPendingPermissions(): boolean {\n return this.client.hasPendingPermissions();\n }\n\n // ============================================\n // Question Management (ask_followup_question)\n // ============================================\n\n answerQuestion(toolCallId: string, answers: import('@genie/agent-client-protocol').QuestionAnswers): boolean {\n return this.client.answerQuestion(toolCallId, answers);\n }\n\n cancelQuestion(toolCallId: string, reason?: string): boolean {\n return this.client.cancelQuestion(toolCallId, reason);\n }\n\n getPendingQuestions() {\n return this.client.getPendingQuestions();\n }\n\n hasPendingQuestions(): boolean {\n return this.client.hasPendingQuestions();\n }\n\n // ============================================\n // Tool Callback Management\n // ============================================\n\n async toolCallback(sessionId: string, toolCallId: string, toolName: string, action: 'skip' | 'cancel'): Promise<{ success: boolean; error?: string }> {\n // Cloud connection does not support toolCallback yet\n return { success: false, error: 'toolCallback not supported for cloud connections' };\n }\n\n // ============================================\n // Session Connection Info\n // ============================================\n\n /**\n * Set session connection information\n * Called by CloudAgentProvider.connect() after fetching session data from backend.\n */\n setSessionConnectionInfo(info: SessionConnectionInfo): void {\n this._sessionConnectionInfo = info;\n }\n\n /**\n * Get session connection information\n * Contains sandboxId, link, token, etc.\n */\n get sessionConnectionInfo(): SessionConnectionInfo | undefined {\n return this._sessionConnectionInfo;\n }\n\n // ============================================\n // Extension Methods\n // ============================================\n\n async extMethod(method: string, params: Record<string, unknown>): Promise<Record<string, unknown>> {\n return this.client.extMethod(method, params);\n }\n}\n\nexport default CloudAgentConnection;\n","/**\n * E2B Filesystem Implementation\n *\n * Provides FilesResource implementation using E2B Sandbox SDK.\n * Directly uses e2b SDK types.\n *\n * @see https://e2b.dev/docs/filesystem/read-write\n * @see https://e2b.dev/docs/filesystem/watch\n */\n\nimport { Sandbox, type EntryInfo, type WriteInfo, type WatchHandle } from 'e2b';\nimport type {\n FilesResource,\n FilesystemEvent,\n E2BSandboxConnectionInfo,\n FilesystemRequestOpts,\n FilesystemListOpts,\n WatchOpts,\n WriteEntry\n} from '../../types.js';\n\n/**\n * E2B Filesystem Implementation\n *\n * Wraps E2B Sandbox SDK's filesystem operations to implement FilesResource interface.\n *\n * @example\n * ```typescript\n * const fs = await E2BFilesystem.connect({\n * sandboxId: 'sandbox-123',\n * apiKey: 'e2b_xxx'\n * });\n *\n * // Read/write files\n * await fs.write('/test.txt', 'Hello World');\n * const content = await fs.read('/test.txt');\n *\n * // Watch for changes\n * const handle = await fs.watchDir('/workspace', (event) => {\n * console.log('File changed:', event);\n * });\n * ```\n */\nexport class E2BFilesystem implements FilesResource {\n private sandbox: Sandbox;\n\n constructor(sandbox: Sandbox) {\n this.sandbox = sandbox;\n }\n\n /**\n * Connect to an E2B Sandbox and create filesystem instance\n */\n static async connect(info: E2BSandboxConnectionInfo): Promise<E2BFilesystem> {\n const sandbox = await Sandbox.connect(info.sandboxId, {\n apiKey: info.apiKey,\n domain: info.domain,\n apiUrl: info.apiUrl,\n requestTimeoutMs: info.requestTimeoutMs,\n debug: info.debug,\n headers: info.headers\n });\n return new E2BFilesystem(sandbox);\n }\n\n /**\n * Get the underlying E2B Sandbox instance\n */\n getSandbox(): Sandbox {\n return this.sandbox;\n }\n\n // ============================================\n // Read 方法重载实现\n // ============================================\n\n read(path: string, opts?: FilesystemRequestOpts & { format?: 'text' }): Promise<string>;\n read(path: string, opts: FilesystemRequestOpts & { format: 'bytes' }): Promise<Uint8Array>;\n read(path: string, opts: FilesystemRequestOpts & { format: 'blob' }): Promise<Blob>;\n read(path: string, opts: FilesystemRequestOpts & { format: 'stream' }): Promise<ReadableStream<Uint8Array>>;\n read(path: string, opts?: FilesystemRequestOpts & { format?: string }): Promise<string | Uint8Array | Blob | ReadableStream<Uint8Array>> {\n return this.sandbox.files.read(path, opts as any);\n }\n\n // ============================================\n // Write 方法重载实现\n // ============================================\n\n write(path: string, data: string | ArrayBuffer | Blob | ReadableStream, opts?: FilesystemRequestOpts): Promise<WriteInfo>;\n write(files: WriteEntry[], opts?: FilesystemRequestOpts): Promise<WriteInfo[]>;\n write(pathOrFiles: string | WriteEntry[], dataOrOpts?: string | ArrayBuffer | Blob | ReadableStream | FilesystemRequestOpts, opts?: FilesystemRequestOpts): Promise<WriteInfo | WriteInfo[]> {\n if (Array.isArray(pathOrFiles)) {\n // Batch write: write(files: WriteEntry[], opts?: FilesystemRequestOpts)\n return this.sandbox.files.write(pathOrFiles, dataOrOpts as FilesystemRequestOpts);\n }\n // Single file write: write(path: string, data: ..., opts?: FilesystemRequestOpts)\n return this.sandbox.files.write(pathOrFiles, dataOrOpts as string | ArrayBuffer | Blob | ReadableStream, opts);\n }\n\n // ============================================\n // 其他方法实现\n // ============================================\n\n async list(path: string, opts?: FilesystemListOpts): Promise<EntryInfo[]> {\n return this.sandbox.files.list(path, opts);\n }\n\n async exists(path: string, opts?: FilesystemRequestOpts): Promise<boolean> {\n return this.sandbox.files.exists(path, opts);\n }\n\n async makeDir(path: string, opts?: FilesystemRequestOpts): Promise<boolean> {\n return this.sandbox.files.makeDir(path, opts);\n }\n\n async remove(path: string, opts?: FilesystemRequestOpts): Promise<void> {\n return this.sandbox.files.remove(path, opts);\n }\n\n async rename(oldPath: string, newPath: string, opts?: FilesystemRequestOpts): Promise<EntryInfo> {\n return this.sandbox.files.rename(oldPath, newPath, opts);\n }\n\n async getInfo(path: string, opts?: FilesystemRequestOpts): Promise<EntryInfo> {\n return this.sandbox.files.getInfo(path, opts);\n }\n\n async watchDir(\n path: string,\n onEvent: (event: FilesystemEvent) => void | Promise<void>,\n opts?: WatchOpts & { onExit?: (err?: Error) => void | Promise<void> }\n ): Promise<WatchHandle> {\n return this.sandbox.files.watchDir(path, onEvent, opts);\n }\n}\n\nexport default E2BFilesystem;\n","/**\n * COS Upload Service\n *\n * 负责通过预签名 URL 上传文件到腾讯云 COS\n *\n * 上传流程:\n * 1. 生成 objectKey (uploads/{timestamp}-{random}-{filename})\n * 2. 请求后端获取 PUT 预签名 URL\n * 3. 使用预签名 URL 直接上传文件到 COS\n * 4. 请求后端获取 GET 预签名 URL 作为访问地址\n */\n\nimport type { Logger } from '../../client/types.js';\n\n/**\n * 预签名 URL 请求参数\n */\nexport interface PresignedURLRequest {\n /** 对象路径 */\n object_key: string;\n /** HTTP 方法,支持 GET 或 PUT */\n method: 'GET' | 'PUT';\n /** 过期时间(秒),默认 3600 */\n expire_seconds?: number;\n}\n\n/**\n * 预签名 URL 响应\n */\nexport interface PresignedURLResponse {\n /** 预签名 URL */\n url: string;\n /** 对象路径 */\n object_key: string;\n /** 过期时间 */\n expire: number;\n}\n\n/**\n * API 响应包装类型\n */\ninterface ApiResponse<T> {\n code: number;\n message: string;\n data?: T;\n}\n\n/**\n * 上传结果\n */\nexport interface UploadResult {\n /** 是否成功 */\n success: boolean;\n /** 访问 URL (成功时返回) */\n url?: string;\n /** 错误信息 (失败时返回) */\n error?: string;\n}\n\n/**\n * HTTP 请求函数类型 (复用 CloudAgentProvider 的 request 方法)\n */\nexport type RequestFunction = (\n method: string,\n path: string,\n body?: unknown\n) => Promise<Response>;\n\n/**\n * COS Upload Service 配置\n */\nexport interface CosUploadServiceOptions {\n /** HTTP 请求函数 (复用 CloudAgentProvider 的 request 方法,包含公共 headers) */\n request: RequestFunction;\n /** Logger 实例 */\n logger?: Logger;\n /** 自定义 fetch 实现 (用于上传到 COS) */\n fetch?: typeof fetch;\n}\n\n/**\n * COS 上传服务\n *\n * @example\n * ```typescript\n * const service = new CosUploadService({\n * request: (method, path, body) => cloudProvider.request(method, path, body),\n * logger: console,\n * });\n *\n * const result = await service.uploadFile(file);\n * if (result.success) {\n * console.log('File URL:', result.url);\n * }\n * ```\n */\nexport class CosUploadService {\n private request: RequestFunction;\n private logger?: Logger;\n private fetchImpl: typeof fetch;\n\n constructor(options: CosUploadServiceOptions) {\n this.request = options.request;\n this.logger = options.logger;\n this.fetchImpl = options.fetch ?? globalThis.fetch.bind(globalThis);\n }\n\n /**\n * 生成唯一的 objectKey\n *\n * 格式: uploads/{timestamp}-{randomId}-{encodedFilename}\n */\n private generateObjectKey(filename: string): string {\n const timestamp = Date.now();\n const randomId = Math.random().toString(36).substring(2, 10);\n const encodedFilename = encodeURIComponent(filename);\n return `uploads/${timestamp}-${randomId}-${encodedFilename}`;\n }\n\n /**\n * 获取预签名 URL\n *\n * POST /conversation/artifacts/presigned_url\n */\n private async getPresignedUrl(params: PresignedURLRequest): Promise<PresignedURLResponse> {\n const response = await this.request('POST', '/conversation/artifacts/presigned_url', params);\n\n if (!response.ok) {\n throw new Error(`Failed to get presigned URL: ${response.statusText}`);\n }\n\n const apiResponse = await response.json() as ApiResponse<PresignedURLResponse>;\n if (!apiResponse.data) {\n throw new Error('No data in presigned URL response');\n }\n\n return apiResponse.data;\n }\n\n /**\n * 上传单个文件到 COS\n *\n * @param file - 要上传的文件\n * @param expireSeconds - 预签名 URL 过期时间(秒),默认 3600\n * @returns 上传结果,包含访问 URL 或错误信息\n */\n async uploadFile(file: File, expireSeconds: number = 3600): Promise<UploadResult> {\n const filename = file.name;\n this.logger?.info(`[CosUploadService] Uploading file: ${filename}`);\n\n try {\n // 1. 生成 objectKey\n const objectKey = this.generateObjectKey(filename);\n this.logger?.debug(`[CosUploadService] Generated objectKey: ${objectKey}`);\n\n // 2. 获取 PUT 预签名 URL\n const putPresigned = await this.getPresignedUrl({\n object_key: objectKey,\n method: 'PUT',\n expire_seconds: expireSeconds,\n });\n this.logger?.debug(`[CosUploadService] Got PUT presigned URL`);\n\n // 3. 上传文件到 COS\n const uploadResponse = await this.fetchImpl(putPresigned.url, {\n method: 'PUT',\n body: file,\n headers: {\n 'Content-Type': file.type || 'application/octet-stream',\n },\n });\n\n if (!uploadResponse.ok) {\n const errorText = await uploadResponse.text().catch(() => uploadResponse.statusText);\n throw new Error(`COS upload failed: ${uploadResponse.status} ${errorText}`);\n }\n this.logger?.debug(`[CosUploadService] File uploaded to COS`);\n\n // 4. 获取 GET 预签名 URL 作为访问地址\n const getPresigned = await this.getPresignedUrl({\n object_key: objectKey,\n method: 'GET',\n expire_seconds: expireSeconds,\n });\n\n this.logger?.info(`[CosUploadService] Upload success: ${filename}`);\n return {\n success: true,\n url: getPresigned.url,\n };\n } catch (error) {\n const errorMessage = error instanceof Error ? error.message : 'Unknown error';\n this.logger?.error(`[CosUploadService] Upload failed: ${filename}`, error);\n return {\n success: false,\n error: errorMessage,\n };\n }\n }\n\n /**\n * 批量上传文件到 COS\n *\n * @param files - 要上传的文件数组\n * @param expireSeconds - 预签名 URL 过期时间(秒),默认 3600\n * @returns 所有文件的上传结果\n */\n async uploadFiles(files: File[], expireSeconds: number = 3600): Promise<{\n success: boolean;\n urls?: string[];\n error?: string;\n results: UploadResult[];\n }> {\n this.logger?.info(`[CosUploadService] Uploading ${files.length} file(s)`);\n\n const results: UploadResult[] = [];\n const urls: string[] = [];\n\n for (const file of files) {\n const result = await this.uploadFile(file, expireSeconds);\n results.push(result);\n\n if (result.success && result.url) {\n urls.push(result.url);\n }\n }\n\n // 检查是否所有文件都上传成功\n const failedResults = results.filter(r => !r.success);\n if (failedResults.length > 0) {\n const failedErrors = failedResults.map(r => r.error).join('; ');\n return {\n success: false,\n error: `${failedResults.length} file(s) failed: ${failedErrors}`,\n results,\n };\n }\n\n this.logger?.info(`[CosUploadService] All ${files.length} file(s) uploaded successfully`);\n return {\n success: true,\n urls,\n results,\n };\n }\n}\n\nexport default CosUploadService;\n","/**\n * Backend Provider 类型定义\n *\n * 定义 IBackendProvider 接口和配置\n */\n\nimport type { GetAgentsRequest, GetAgentsResponse } from './agent-api';\n\n// ============================================================================\n// Account 相关类型\n// ============================================================================\n\n/**\n * 账号版本类型\n */\nexport type Edition = 'pro' | 'personal' | 'ultimate' | 'exclusive';\n\n/**\n * 版本展示类型(用于 UI 展示)\n * - free: 免费版(个人版未订阅 Pro)\n * - pro: Pro 版(个人版已订阅 Pro)\n * - ultimate: 旗舰版(团队版)\n * - exclusive: 专享版(企业版)\n */\nexport type EditionDisplayType = 'free' | 'pro' | 'ultimate' | 'exclusive';\n\n/**\n * 部署状态\n */\nexport interface DeployStatus {\n statusCode: number;\n statusMsg: string;\n detailMsg: string;\n}\n\n/**\n * 套餐代码\n */\n\n/**\n * TCACA_code_001_PqouKr6QWV CodeBuddy海外版免费包\n * TCACA_code_002_AkiJS3ZHF5 CodeBuddy海外版Pro版本包-包月/CodeBuddy Pro Plan - Monthly:\n * TCACA_code_006_DbXS0lrypC CodeBuddy海外版一次性免费赠送2周的Pro版本包/CodeBuddy One-time Free 2-Week Pro Plan Trial\n * TCACA_code_007_nzdH5h4Nl0 CodeBuddy海外版运营裂变包/CodeBuddy Growth Plan\n * TCACA_code_003_FAnt7lcmRT CodeBuddy海外版Pro版本包-包年/CodeBuddy Pro Plan - Yearly\n * TCACA_code_008_cfWoLwvjU4 赠送月包\n */\nexport enum CommodityCode {\n free = 'TCACA_code_001_PqouKr6QWV', // free\n proMon = 'TCACA_code_002_AkiJS3ZHF5',\n // 免费赠送2周\n gift = 'TCACA_code_006_DbXS0lrypC',\n activity = 'TCACA_code_007_nzdH5h4Nl0',\n proYear = 'TCACA_code_003_FAnt7lcmRT',\n freeMon = 'TCACA_code_008_cfWoLwvjU4', // free\n extra = 'TCACA_code_009_0XmEQc2xOf',\n}\n\n/**\n * 账号套餐信息\n */\nexport interface AccountPlan {\n /** 是否是 Pro 版本 */\n isPro: boolean;\n /** 到期时间戳 */\n expireAt?: string | number;\n /** 自动续费标志 0-关闭 1-开启 */\n renewFlag: 0 | 1;\n /** 套餐代码 */\n PackageCode?: CommodityCode;\n /** 套餐名称 */\n name: string;\n}\n\n/**\n * 账号信息\n */\nexport interface Account {\n /** 用户ID(唯一标识) */\n uid: string;\n /** 用户昵称 */\n nickname: string;\n /** 版本类型 */\n type: Edition;\n /** 版本展示类型(用于 UI 展示) */\n editionType: EditionDisplayType;\n /** 是否最后一次登录 */\n lastLogin: boolean;\n /** 企业ID */\n enterpriseId?: string;\n /** 企业名称 */\n enterpriseName?: string;\n /** 企业LOGO */\n enterpriseLogo?: string;\n /** 企业内用户名 */\n enterpriseUserName?: string;\n /** 插件是否启用 */\n pluginEnabled?: boolean;\n /** 部署状态 */\n deployStatus?: DeployStatus;\n /** 是否是 Pro 版本 */\n isPro?: boolean;\n /** 到期时间戳 */\n expireAt?: string | number;\n /** 自动续费标志 0-关闭 1-开启 */\n renewFlag?: 0 | 1;\n /** 套餐代码 */\n PackageCode?: CommodityCode;\n /** 套餐名称 */\n name?: string;\n}\n\n// ============================================================================\n// Model 相关类型\n// ============================================================================\n\n/**\n * 推理配置\n */\nexport interface ReasoningConfig {\n /** 推理努力程度 */\n effort: 'low' | 'medium' | 'high';\n /** 摘要模式 */\n summary: 'auto' | 'always' | 'never';\n}\n\n/**\n * 模型信息\n */\nexport interface ModelInfo {\n /** 模型ID */\n id: string;\n /** 模型名称 */\n name: string;\n /** 供应商 */\n vendor: string;\n /** 最大输出 token 数 */\n maxOutputTokens: number;\n /** 最大输入 token 数 */\n maxInputTokens: number;\n /** 是否支持工具调用 */\n supportsToolCall: boolean;\n /** 是否支持图像 */\n supportsImages: boolean;\n /** 是否禁用多模态 */\n disabledMultimodal: boolean;\n /** 最大允许大小 */\n maxAllowedSize: number;\n /** 是否支持推理 */\n supportsReasoning: boolean;\n /** 是否仅推理模式 */\n onlyReasoning: boolean;\n /** 温度参数 */\n temperature: number;\n /** 推理配置 */\n reasoning: ReasoningConfig;\n /** 英文描述 */\n descriptionEn: string;\n /** 中文描述 */\n descriptionZh: string;\n}\n\n/**\n * GetModels 请求参数\n */\nexport interface GetModelsRequest {\n /** 仓库路径 */\n repository: string;\n}\n\n/**\n * GetModels 响应\n */\nexport interface GetModelsResponse {\n /** 模型列表 */\n models: ModelInfo[];\n}\n\n// ============================================================================\n// Backend Provider 配置\n// ============================================================================\n\n/**\n * Backend Provider 配置选项\n */\nexport interface BackendProviderConfig {\n /** API 基础 URL (例如: https://api.example.com) */\n baseUrl: string;\n /** 认证 Token */\n authToken?: string;\n}\n\n// ============================================================================\n// Backend Provider 接口\n// ============================================================================\n\n/**\n * IBackendProvider 接口\n *\n * 定义与后端 API 交互的抽象接口\n */\nexport interface IBackendProvider {\n /**\n * 获取 Agent 列表\n * @param request 请求参数\n * @returns Promise<GetAgentsResponse> Agent 列表响应\n */\n getAgents(request: GetAgentsRequest): Promise<GetAgentsResponse>;\n\n /**\n * 获取可用模型列表\n * @param request 请求参数(包含仓库路径)\n * @returns Promise<GetModelsResponse> 模型列表响应\n */\n getModels(request: GetModelsRequest): Promise<GetModelsResponse>;\n\n /**\n * 获取当前账号信息\n * @returns Promise<Account | null> 账号信息,未登录时返回 null\n */\n getAccount(): Promise<Account | null>;\n\n /**\n * 触发登录流程\n * - Web 环境: 跳转到登录页面\n * - IDE 环境: 通过 IPC 通知 IDE 打开登录流程\n */\n login(): Promise<void>;\n\n /**\n * 登出账号\n */\n logout(): Promise<void>;\n\n /**\n * 监听事件(可选,用于 IPC 环境)\n * @param event 事件名称\n * @param callback 回调函数\n * @returns 取消订阅函数\n */\n on?(event: string, callback: (data?: unknown) => void): () => void;\n}\n","/**\n * Backend Provider 实现\n *\n * 封装与后端 API 的 HTTP 通信\n */\n\nimport { type IBackendProvider, type BackendProviderConfig, type Account, type AccountPlan, type EditionDisplayType, type GetModelsRequest, type GetModelsResponse, type ModelInfo, CommodityCode } from './types';\nimport type { GetAgentsRequest, GetAgentsResponse } from './agent-api';\n\n/** 获取当前域名的登录页面 URL */\nconst getLoginUrl = () => `${window.location.origin}/login`;\n\n/** 获取当前域名的账号选择页面 URL */\nconst getSelectAccountUrl = () => `${window.location.origin}/login/select`;\n\n/** localStorage 中存储选中账号 ID 的 key */\nexport const SELECTED_ACCOUNT_KEY = 'CODEBUDDY_IDE_SELECTED_ACCOUNT_ID';\n\n/**\n * Backend Provider 实现类\n */\nexport class BackendProvider implements IBackendProvider {\n private readonly baseUrl: string;\n private readonly authToken?: string;\n\n constructor(config: BackendProviderConfig) {\n this.baseUrl = config.baseUrl.replace(/\\/$/, '');\n this.authToken = config.authToken;\n }\n\n /**\n * 获取 Agent 列表\n * API 端点: GET /v2/cloudagent/agentmgmt/agents\n */\n async getAgents(request: GetAgentsRequest = {}): Promise<GetAgentsResponse> {\n // 原实现已注释,使用 MockAgentProvider 提供假数据\n // const queryParams = this.buildQueryParams(request);\n // const url = `${this.baseUrl}/v2/cloudagent/agentmgmt/agents${queryParams}`;\n // const headers: Record<string, string> = {\n // 'Content-Type': 'application/json',\n // 'Accept': 'application/json',\n // };\n // if (this.authToken) {\n // headers['Authorization'] = `Bearer ${this.authToken}`;\n // }\n // const response = await fetch(url, { method: 'GET', headers, credentials: 'include' });\n // if (!response.ok) {\n // const error = await response.json().catch(() => ({ message: response.statusText }));\n // throw new Error(error.message || `HTTP ${response.status}`);\n // }\n // return response.json();\n\n // 使用 MockAgentProvider 提供假数据\n const { MockAgentProvider } = await import('../common/_legacy/MockAgentProvider.js');\n const mockProvider = new MockAgentProvider();\n const sessions = mockProvider.getAllSessions();\n\n // 将 MockSession 数据转换为 GetAgentsResponse 格式\n const mockTitles = {\n '1': '开发五子棋游戏',\n '2': '修复登录页面样式',\n '3': 'API 接口优化',\n };\n\n const agents = sessions.map((session, index) => ({\n id: session.sessionId,\n name: mockTitles[session.sessionId as keyof typeof mockTitles] || `Agent ${session.sessionId}`,\n status: 'RUNNING' as const,\n visibility: 'PRIVATE' as const,\n createdAt: new Date(session.createdAt).toISOString(),\n summary: `Session created at ${new Date(session.createdAt).toLocaleString()}`,\n source: {\n provider: 'github',\n ref: 'refs/heads/main',\n repository: session.cwd,\n },\n target: {\n autoCreatePr: false,\n branchName: 'feature/mock',\n prUrl: undefined,\n url: undefined,\n },\n }));\n\n return {\n agents,\n pagination: {\n hasNext: false,\n hasPrev: false,\n page: 1,\n size: agents.length,\n total: agents.length,\n totalPages: 1,\n },\n };\n }\n\n /**\n * 获取可用模型列表\n * API 端点: GET /v2/cloudagent/models (假设)\n *\n * 当前实现: 返回 Mock 数据\n */\n async getModels(request: GetModelsRequest): Promise<GetModelsResponse> {\n // Mock 模型数据\n // https://staging-copilot.tencent.com/internal/api/docs/swagger/index.html#/CloudAgent/get_v2_cloudagent_agentmgmt_models\n const mockModels: ModelInfo[] = [\n {\n id: 'glm-4.7',\n name: 'GLM-4.7',\n vendor: 'f',\n maxOutputTokens: 48000,\n maxInputTokens: 200000,\n supportsToolCall: true,\n supportsImages: false,\n disabledMultimodal: true,\n maxAllowedSize: 200000,\n supportsReasoning: true,\n onlyReasoning: true,\n temperature: 1.0,\n reasoning: {\n effort: 'medium',\n summary: 'auto'\n },\n descriptionEn: 'GLM-4.7 model, Well-rounded model for everyday use',\n descriptionZh: 'GLM-4.7 大模型,能力均衡,适合日常使用'\n },\n {\n id: 'glm-4.7-flash',\n name: 'GLM-4.7 Flash',\n vendor: 'f',\n maxOutputTokens: 40000,\n maxInputTokens: 128000,\n supportsToolCall: true,\n supportsImages: false,\n disabledMultimodal: false,\n maxAllowedSize: 128000,\n supportsReasoning: false,\n onlyReasoning: false,\n temperature: 0.7,\n reasoning: {\n effort: 'low',\n summary: 'never'\n },\n descriptionEn: 'GLM-4.7 Flash, Fast and efficient model',\n descriptionZh: 'GLM-4.7 Flash,快速高效的模型'\n }\n ];\n\n console.log('[BackendProvider] getModels called for repository:', request.repository);\n\n // 返回 Mock 数据(后续可以替换为真实的 HTTP 请求)\n return {\n models: mockModels\n };\n }\n\n /**\n * 获取当前账号信息\n * API 端点: GET /console/accounts (返回账号列表)\n * \n * 逻辑:\n * 1. 从 localStorage 读取 CODEBUDDY_IDE_SELECTED_ACCOUNT_ID\n * 2. 根据 CODEBUDDY_IDE_SELECTED_ACCOUNT_ID 找到对应账号\n * - personal 类型: 用 uid 匹配\n * - 其他类型: 用 enterpriseId 匹配\n * 3. 如果没有选中的账号,跳转到账号选择页面\n * 4. 获取套餐信息并合并到账号中\n */\n async getAccount(): Promise<Account | null> {\n const url = `${this.baseUrl}/console/accounts`;\n\n const headers: Record<string, string> = {\n 'Content-Type': 'application/json',\n 'Accept': 'application/json',\n };\n\n if (this.authToken) {\n headers['Authorization'] = `Bearer ${this.authToken}`;\n }\n\n try {\n const response = await fetch(url, { method: 'GET', headers, credentials: 'include' });\n\n if (!response.ok) {\n // 401/403 表示未登录\n if (response.status === 401 || response.status === 403) {\n return null;\n }\n const error = await response.json().catch(() => ({ message: response.statusText }));\n throw new Error(error.message || `HTTP ${response.status}`);\n }\n\n // 检查响应类型,只有 JSON 才是正常响应,其他情况跳转登录页\n const contentType = response.headers.get('Content-Type') || '';\n if (!contentType.includes('application/json')) {\n return null;\n }\n\n const { data = {} } = await response.json();\n const accounts: Account[] = data?.accounts || [];\n if (!accounts || accounts.length === 0) {\n return null;\n }\n\n // 从 localStorage 读取选中的账号 ID\n const selectedAccountId = localStorage.getItem(SELECTED_ACCOUNT_KEY);\n let selectedAccount: Account | undefined;\n\n if (selectedAccountId) {\n // 查找选中的账号\n selectedAccount = accounts.find(account => {\n // personal 类型用 uid 匹配,其他类型用 enterpriseId 匹配\n if (account.type === 'personal') {\n return account.uid === selectedAccountId;\n }\n return account.enterpriseId === selectedAccountId;\n });\n\n if (selectedAccount) {\n try {\n // 获取套餐信息并合并到账号中\n const plan = await this.getCurrentPlan();\n // 计算版本展示类型\n const editionType = this.getEditionDisplayType(selectedAccount.type, plan.isPro);\n console.log('account', { ...selectedAccount, ...plan, editionType });\n return { ...selectedAccount, ...plan, editionType };\n } catch (error) {\n // 获取套餐信息失败,忽略错误\n return { ...selectedAccount };\n }\n }\n }\n\n // 如果只有一个账号,自动选中它\n if (accounts.length === 1) {\n selectedAccount = accounts[0];\n // 保存选中的账号 ID 到 localStorage\n const accountId = selectedAccount.type === 'personal'\n ? selectedAccount.uid\n : selectedAccount.enterpriseId;\n if (accountId) {\n localStorage.setItem(SELECTED_ACCOUNT_KEY, accountId);\n }\n // 获取套餐信息并合并到账号中\n const plan = await this.getCurrentPlan();\n const editionType = this.getEditionDisplayType(selectedAccount.type, plan.isPro);\n console.log('account (auto-selected)', { ...selectedAccount, ...plan, editionType });\n return { ...selectedAccount, ...plan, editionType };\n }\n\n // 多个账号但没有选中的,跳转到账号选择页面\n const redirectUrl = encodeURIComponent(window.location.href);\n window.location.href = `${getSelectAccountUrl()}?platform=website&state=0&redirect_uri=${redirectUrl}`;\n return null;\n } catch (error) {\n console.error('[BackendProvider] getAccount failed:', error);\n return null;\n }\n }\n\n /**\n * 获取当前套餐信息\n * 从计量计费接口获取用户的套餐信息\n * API: POST /billing/meter/get-user-resource\n */\n private async getCurrentPlan(): Promise<AccountPlan> {\n // 默认套餐信息\n const defaultPlan: AccountPlan = {\n isPro: false,\n expireAt: 0,\n renewFlag: 0,\n PackageCode: undefined,\n name: '',\n };\n\n try {\n const url = `${this.baseUrl}/billing/meter/get-user-resource`;\n const headers: Record<string, string> = {\n 'Content-Type': 'application/json',\n 'Accept': 'application/json',\n };\n\n if (this.authToken) {\n headers['Authorization'] = `Bearer ${this.authToken}`;\n }\n\n // 构造请求参数\n const now = new Date();\n const futureDate = new Date(now.getTime() + 101 * 365 * 24 * 60 * 60 * 1000);\n const formatDate = (d: Date) => {\n const pad = (n: number) => n.toString().padStart(2, '0');\n return `${d.getFullYear()}-${pad(d.getMonth() + 1)}-${pad(d.getDate())} ${pad(d.getHours())}:${pad(d.getMinutes())}:${pad(d.getSeconds())}`;\n };\n\n const body = {\n PageNumber: 1,\n PageSize: 100,\n ProductCode: 'p_tcaca',\n Status: [0, 3], // 0-有效, 3-已用完\n PackageEndTimeRangeBegin: formatDate(now),\n PackageEndTimeRangeEnd: formatDate(futureDate),\n };\n\n const response = await fetch(url, {\n method: 'POST',\n headers,\n credentials: 'include',\n body: JSON.stringify(body),\n });\n\n if (!response.ok) {\n console.warn('[BackendProvider] getCurrentPlan failed:', response.status);\n return defaultPlan;\n }\n\n const result = await response.json();\n // 响应格式: { Response: { Data: { Accounts: [...] } } } 或 { Accounts: [...] }\n const resources = result?.data?.Response?.Data?.Accounts || result?.data?.Accounts || [];\n\n if (!resources || resources.length === 0) {\n return defaultPlan;\n }\n\n // 查找 Pro 套餐(proYear 或 proMon)\n const proPlan = resources.find((r: any) =>\n r.PackageCode === CommodityCode.proYear || r.PackageCode === CommodityCode.proMon\n );\n\n // 查找试用套餐\n const trialPlan = resources.find((r: any) => r.PackageCode === CommodityCode.gift);\n\n const activePlan = proPlan || trialPlan;\n\n if (activePlan) {\n return {\n isPro: !!proPlan,\n expireAt: activePlan.ExpiredTime || activePlan.CycleEndTime || 0,\n renewFlag: Number(activePlan.AutoRenewFlag) === 1 ? 1 : 0,\n PackageCode: activePlan.PackageCode,\n name: activePlan.PackageName || '',\n };\n }\n\n return defaultPlan;\n } catch (error) {\n console.error('[BackendProvider] getCurrentPlan error:', error);\n return defaultPlan;\n }\n }\n\n /**\n * 根据账号类型和 Pro 状态计算版本展示类型\n * - personal + isPro = 'pro'\n * - personal + !isPro = 'free'\n * - ultimate = 'ultimate' (旗舰版/团队版)\n * - exclusive = 'exclusive' (专享版/企业版)\n */\n private getEditionDisplayType(type: string, isPro: boolean): EditionDisplayType {\n if (type === 'personal') {\n return isPro ? 'pro' : 'free';\n }\n if (type === 'ultimate') {\n return 'ultimate';\n }\n if (type === 'exclusive') {\n return 'exclusive';\n }\n // 默认返回 free\n return 'free';\n }\n\n /**\n * 触发登录流程\n * Web 环境: 跳转到登录页面\n */\n async login(): Promise<void> {\n // 获取当前页面 URL 作为回调地址\n // todo 支持弹窗和跳转、弹窗优化点 别让主页面 reload\n\n const redirectUrl = encodeURIComponent(window.location.href);\n window.location.href = `${getLoginUrl()}?platform=website&state=0&redirect_uri=${redirectUrl}`;\n }\n\n /**\n * 登出账号\n * Web 环境: 跳转到登出页面或清除 cookie\n */\n async logout(): Promise<void> {\n // 调用登出接口\n const url = `${this.baseUrl}/console/logout`;\n\n try {\n await fetch(url, { method: 'POST', credentials: 'include' });\n } catch (error) {\n console.error('[BackendProvider] logout failed:', error);\n }\n\n // 清除 localStorage 中的选中账号\n localStorage.removeItem(SELECTED_ACCOUNT_KEY);\n\n // 刷新页面\n window.location.reload();\n }\n\n /**\n * 构建查询参数字符串\n */\n // private buildQueryParams(request: GetAgentsRequest): string {\n // const params: string[] = [];\n // if (request.dayRange !== undefined) {\n // params.push(`dayRange=${request.dayRange}`);\n // }\n // if (request.filters?.length) {\n // request.filters.forEach((filter: AgentFilter) => {\n // params.push(`filters=${encodeURIComponent(JSON.stringify(filter))}`);\n // });\n // }\n // if (request.page !== undefined) {\n // params.push(`page=${request.page}`);\n // }\n // if (request.size !== undefined) {\n // params.push(`size=${request.size}`);\n // }\n // if (request.sort) {\n // params.push(`sort=${encodeURIComponent(JSON.stringify(request.sort))}`);\n // }\n // return params.length > 0 ? `?${params.join('&')}` : '';\n // }\n}\n\n/**\n * 创建 BackendProvider 实例\n */\nexport function createBackendProvider(config: BackendProviderConfig): BackendProvider {\n return new BackendProvider(config);\n}\n","/**\n * IPC Backend Provider 实现\n *\n * 通过 IWidgetChannel 与后端通信\n * 使用统一的消息格式: { type: 'backend', requestId, params: { type, params } }\n */\n\nimport type { IBackendProvider, Account, GetModelsRequest, GetModelsResponse } from './types';\nimport type { GetAgentsRequest, GetAgentsResponse } from './agent-api';\nimport { IWidgetChannel } from '../common';\n\n/**\n * IPC Backend Provider 配置\n */\nexport interface IPCBackendProviderConfig {\n /** Widget Channel 接口 */\n channel: IWidgetChannel;\n /** 是否启用调试日志 */\n debug?: boolean;\n /** 请求超时时间(毫秒,默认 30000) */\n timeoutMs?: number;\n}\n\n/**\n * Backend 请求类型常量\n */\nconst BACKEND_REQUEST_TYPES = {\n GET_AGENTS: 'backend:get-agents-request',\n GET_MODELS: 'backend:get-models',\n LOGIN: 'backend:login',\n LOGOUT: 'backend:logout',\n GET_ACCOUNT: 'backend:get-account',\n} as const;\n\n/**\n * 生成唯一请求 ID\n */\nfunction generateRequestId(): string {\n return `req-${Date.now()}-${Math.random().toString(36).slice(2)}`;\n}\n\n/**\n * IPC Backend Provider 实现类\n *\n * 通过 IWidgetChannel 与后端通信获取 Agent 列表\n */\nexport class IPCBackendProvider implements IBackendProvider {\n private readonly channel: IWidgetChannel;\n private readonly debug: boolean;\n private readonly timeoutMs: number;\n\n constructor(config: IPCBackendProviderConfig) {\n this.channel = config.channel;\n this.debug = config.debug ?? false;\n this.timeoutMs = config.timeoutMs ?? 30000;\n\n this.log('Initialized with IWidgetChannel');\n }\n\n /**\n * 发送统一格式的后端请求\n * @param requestType 请求类型\n * @param params 请求参数\n * @returns 响应数据\n */\n private async sendBackendRequest<T>(requestType: string, params?: unknown): Promise<T> {\n const message = {\n type: 'backend',\n requestId: generateRequestId(),\n params: {\n type: requestType,\n params: params,\n },\n };\n\n this.log('Sending backend request:', message);\n\n const response = await this.channel.callMethod('__backend__', message, this.timeoutMs);\n\n this.log('Received response:', response);\n\n // 检查响应中是否有错误\n if (response?.error) {\n throw new Error(response.error);\n }\n\n // 从响应的 data 字段中提取实际数据\n return (response?.data !== undefined ? response.data : response) as T;\n }\n\n /**\n * 获取 Agent 列表\n * 通过 IWidgetChannel 发送请求到后端\n */\n async getAgents(request: GetAgentsRequest = {}): Promise<GetAgentsResponse> {\n this.log('Getting agents with request:', request);\n\n try {\n return await this.sendBackendRequest<GetAgentsResponse>(\n BACKEND_REQUEST_TYPES.GET_AGENTS,\n request\n );\n } catch (error) {\n this.log('Get agents failed:', error);\n throw error;\n }\n }\n\n /**\n * 获取可用模型列表\n * 通过 IWidgetChannel 发送请求到后端\n */\n async getModels(request: GetModelsRequest): Promise<GetModelsResponse> {\n this.log('Getting models with request:', request);\n\n try {\n return await this.sendBackendRequest<GetModelsResponse>(\n BACKEND_REQUEST_TYPES.GET_MODELS,\n request\n );\n } catch (error) {\n this.log('Get models failed:', error);\n throw error;\n }\n }\n\n /**\n * 获取当前账号信息\n * IDE 环境: 通过 IPC 获取账号信息\n */\n async getAccount(): Promise<Account | null> {\n this.log('Getting account via IPC');\n\n try {\n return await this.sendBackendRequest<Account | null>(\n BACKEND_REQUEST_TYPES.GET_ACCOUNT\n );\n } catch (error) {\n this.log('Get account failed:', error);\n return null;\n }\n }\n\n /**\n * 触发登录流程\n * IDE 环境: 通过 IPC 通知 IDE 打开登录流程\n */\n async login(): Promise<void> {\n this.log('Triggering login via IPC');\n\n try {\n await this.sendBackendRequest<void>(BACKEND_REQUEST_TYPES.LOGIN);\n } catch (error) {\n this.log('Login request failed:', error);\n throw error;\n }\n }\n\n /**\n * 登出账号\n * IDE 环境: 通过 IPC 通知 IDE 登出\n */\n async logout(): Promise<void> {\n this.log('Triggering logout via IPC');\n\n try {\n await this.sendBackendRequest<void>(BACKEND_REQUEST_TYPES.LOGOUT);\n } catch (error) {\n this.log('Logout request failed:', error);\n throw error;\n }\n }\n\n /**\n * 监听 channel 事件\n * 用于监听账户变化等事件\n */\n on(event: string, callback: (data?: unknown) => void): () => void {\n this.log('Registering event listener:', event);\n this.channel.on(event, callback);\n return () => {\n this.channel.off(event, callback);\n };\n }\n\n /**\n * 调试日志\n */\n private log(...args: unknown[]): void {\n if (this.debug) {\n console.log('[IPCBackendProvider]', ...args);\n }\n }\n}\n\n/**\n * 创建 IPCBackendProvider 实例\n */\nexport function createIPCBackendProvider(config: IPCBackendProviderConfig): IPCBackendProvider {\n return new IPCBackendProvider(config);\n}\n\n","/**\n * Cloud Agent Provider\n *\n * REST API based agent provider that manages cloud-hosted agents.\n * Implements the AgentProvider interface for the unified agent API.\n */\n\nimport type {\n AgentProvider,\n CloudAgentState,\n Logger,\n FilesystemProvider,\n FilesResource,\n ListAgentOptions,\n ListAgentResult,\n PaginationInfo,\n PickFileParams,\n PickFileResponse,\n UploadFileParams,\n UploadFileResponse,\n} from '../../client/types.js';\nimport type {\n AgentStatus,\n ClientCapabilities,\n E2BSandboxConnectionInfo,\n ModelInfo\n} from '../../types.js';\nimport { CreateAgentResponse, GetAgentResponse, Agent as AgentDto, ListAgentResponse, ListAgentRequest, CreateAgentRequest, GetAgentSessionResponse, ApiResponse, GetModelResponse, DeleteAgentRequest, ArchiveAgentResponse, PatchAgentRequest, PatchAgentResponse, RenameAgentResponse } from './api-types.js';\nimport { CloudAgentConnection } from './cloud-connection.js';\nimport { E2BFilesystem } from './e2b-filesystem.js';\nimport { CosUploadService } from './cos-upload-service.js';\nimport { SELECTED_ACCOUNT_KEY } from '../../../backend/index.js';\n\n/**\n * Agent data stored in cloud backend\n */\n// @ts-expect-error 没对齐\ninterface CloudAgentData {\n id: string;\n name?: string;\n description?: string;\n endpoint: string;\n authToken?: string;\n headers?: Record<string, string>;\n metadata?: Record<string, unknown>;\n createdAt?: string;\n updatedAt?: string;\n}\n\n/**\n * Configuration for CloudAgentProvider\n */\nexport interface CloudAgentProviderOptions {\n /** Base endpoint URL for agent management API (e.g., 'https://api.example.com') */\n endpoint: string;\n /** Authorization token */\n authToken?: string;\n /** Custom headers */\n headers?: Record<string, string>;\n /** Logger instance */\n logger?: Logger;\n /** Custom fetch implementation */\n fetch?: typeof fetch;\n /** Client capabilities (sent during agent initialization) */\n clientCapabilities?: ClientCapabilities;\n}\n\n/**\n * CloudAgentProvider - Manages cloud-hosted agents via REST API\n *\n * API Endpoints:\n * - POST {endpoint}/console/cloudagent/agentmgmt/agents - Create new agent\n * - GET {endpoint}/console/cloudagent/agentmgmt/agents/{id} - Get agent data\n * - GET {endpoint}/console/cloudagent/agentmgmt/agents - List all agents\n * - POST {endpoint}/console/cloudagent/agentmgmt/agents/{id}/delete - Delete agent\n * - GET {endpoint}/console/cloudagent/agentmgmt/agents/{id}/session - Get agent session (includes sandboxId)\n * - GET {endpoint}/console/cloudagent/agentmgmt/models - Get available models\n *\n * The provider stores agent endpoint configurations in the cloud backend.\n * When connect() is called, it creates a CloudAgentConnection to the agent's\n * endpoint and returns an Agent instance.\n *\n * @example\n * ```typescript\n * const provider = new CloudAgentProvider({\n * endpoint: 'https://staging-copilot.tencent.com',\n * authToken: 'token'\n * });\n *\n * // List all agents (uses default pagination and sorting)\n * const allAgents = await provider.list();\n *\n * // List agents with custom pagination\n * const page2 = await provider.list({\n * page: 2,\n * size: 50\n * });\n *\n * // List agents with filtering\n * const runningAgents = await provider.list({\n * filters: [\n * { field: 'status', value: 'running' }\n * ]\n * });\n *\n * // List agents with custom sorting\n * const sortedAgents = await provider.list({\n * sort: {\n * orderBy: 'createdAt',\n * order: 'desc'\n * }\n * });\n *\n * // List agents created in last 14 days with multiple filters\n * const recentAgents = await provider.list({\n * dayRange: 14,\n * filters: [\n * { field: 'status', value: 'running,stopped' }\n * ],\n * page: 1,\n * size: 20\n * });\n *\n * // Get agent state\n * const state = await provider.get('agent-id');\n *\n * // Connect to agent\n * const agent = await provider.connect('agent-id');\n *\n * // Use agent\n * const session = await agent.sessions.create({ cwd: '/workspace' });\n *\n * // Get available models\n * const models = await provider.getModels('my-repo');\n * ```\n */\nexport class CloudAgentProvider implements AgentProvider<CloudAgentConnection>, FilesystemProvider {\n private options: CloudAgentProviderOptions;\n private logger?: Logger;\n private fetchImpl: typeof fetch;\n\n /** Cache for filesystem instances (keyed by agentId) */\n private filesystemCache: Map<string, E2BFilesystem> = new Map();\n\n /** Cache for agent connections (keyed by endpoint link) */\n private connectionCache: Map<string, CloudAgentConnection> = new Map();\n\n /** COS upload service instance */\n private cosUploadService: CosUploadService;\n\n constructor(options: CloudAgentProviderOptions) {\n this.options = options;\n this.logger = options.logger;\n this.fetchImpl = options.fetch ?? globalThis.fetch.bind(globalThis);\n\n // Initialize COS upload service with request method for shared headers\n this.cosUploadService = new CosUploadService({\n request: (method, path, body) => this.request(method, path, body),\n logger: this.logger,\n fetch: this.fetchImpl,\n });\n }\n\n // ============================================\n // FilesystemProvider Implementation\n // ============================================\n\n /**\n * Get the filesystem provider (returns self)\n */\n get filesystem(): FilesystemProvider {\n return this;\n }\n\n /**\n * Get filesystem resource for an agent\n *\n * Creates or returns cached E2BFilesystem instance for the agent's sandbox.\n *\n * @param agentId - Agent ID to get filesystem for\n * @returns FilesResource instance for the agent's sandbox\n */\n async getFilesystem(agentId: string): Promise<FilesResource> {\n // Check cache first\n const cached = this.filesystemCache.get(agentId);\n if (cached) {\n return cached;\n }\n\n // Get sandbox info from backend\n const info = await this.getSandboxInfo(agentId);\n\n // Create and cache E2BFilesystem instance\n const filesystem = await E2BFilesystem.connect(info);\n this.filesystemCache.set(agentId, filesystem);\n\n this.logger?.debug(`Created filesystem for agent: ${agentId}`);\n return filesystem;\n }\n\n /**\n * Get sandbox information from backend\n *\n * Uses GET {endpoint}/console/cloudagent/agentmgmt/agents/{agentId}/session\n * to retrieve sandbox information. Extracts sandboxId from the session response\n * and constructs the apiUrl for E2B proxy.\n *\n * @param agentId - Agent ID\n * @returns E2B Sandbox connection information with sandboxId and apiUrl\n */\n private async getSandboxInfo(agentId: string): Promise<E2BSandboxConnectionInfo> {\n const response = await this.request('GET', `/console/cloudagent/agentmgmt/agents/${agentId}/session`);\n\n if (!response.ok) {\n throw new Error(`Failed to get sandbox info: ${response.statusText}`);\n }\n\n const apiResponse = await response.json() as ApiResponse<GetAgentSessionResponse>;\n if (!apiResponse.data) {\n throw new Error('No data in API response');\n }\n\n // Build E2BSandboxConnectionInfo from session response\n // apiUrl is constructed as: {endpoint}/console/cloudagent/e2bproxy/agents/{agentId}\n const apiUrl = new URL(`/console/cloudagent/e2bproxy/agents/${agentId}`, this.options.endpoint).toString();\n const currentEnterpriseId = localStorage.getItem('currentEnterpriseId');\n\n return {\n sandboxId: apiResponse.data.sandboxId,\n apiUrl,\n apiKey: 'backend-not-used',\n accessToken: apiResponse.data.token,\n headers: {\n // 只有当 enterpriseId 存在时才添加该 header\n ...(currentEnterpriseId && { 'X-Enterprise-Id': currentEnterpriseId }),\n },\n };\n }\n\n /**\n * Get agent state by ID\n */\n async get(agentId: string): Promise<CloudAgentState | undefined> {\n try {\n const response = await this.request('GET', `/console/cloudagent/agentmgmt/agents/${agentId}`);\n\n if (response.status === 404) {\n return undefined;\n }\n\n if (!response.ok) {\n throw new Error(`Failed to get agent: ${response.statusText}`);\n }\n\n const apiResponse = await response.json() as ApiResponse<GetAgentResponse>;\n if (!apiResponse.data) {\n throw new Error('No data in API response');\n }\n return this.toAgentState(apiResponse.data);\n } catch (error) {\n this.logger?.error(`Failed to get agent ${agentId}:`, error);\n throw error;\n }\n }\n\n /**\n * List all agent states with pagination information\n *\n * @param options - Optional query parameters for filtering, sorting, and pagination\n * @returns Object containing agents array and pagination info\n */\n async list(options?: ListAgentOptions): Promise<ListAgentResult<CloudAgentState>> {\n try {\n console.log('[CloudAgentProvider] list called with options:', JSON.stringify(options, null, 2));\n\n // Build request parameters with defaults and user overrides\n const params: ListAgentRequest = {\n // Default values\n page: 1,\n size: 30,\n sort: {\n order: 'desc',\n orderBy: 'status'\n },\n // User overrides\n ...options && {\n ...(options.dayRange !== undefined && { dayRange: options.dayRange }),\n ...(options.page !== undefined && { page: options.page }),\n ...(options.size !== undefined && { size: options.size }),\n ...(options.sort !== undefined && { sort: options.sort }),\n ...(options.filters !== undefined && { filters: options.filters }),\n ...(options.title !== undefined && { title: options.title }),\n }\n };\n\n console.log('[CloudAgentProvider] API request params:', JSON.stringify(params, null, 2));\n\n const response = await this.request('GET', '/console/cloudagent/agentmgmt/agents', params);\n\n if (!response.ok) {\n throw new Error(`Failed to list agents: ${response.statusText}`);\n }\n\n const apiResponse = await response.json() as ApiResponse<ListAgentResponse>;\n if (!apiResponse.data) {\n throw new Error('No data in API response');\n }\n\n const agents = apiResponse.data.agents.map((a) => this.toAgentState(a));\n const pagination: PaginationInfo = apiResponse.data.pagination;\n\n console.log('[CloudAgentProvider] API response:', {\n agentsCount: agents.length,\n pagination\n });\n\n return { agents, pagination };\n } catch (error) {\n this.logger?.error('Failed to list agents:', error);\n throw error;\n }\n }\n\n /**\n * Create a new agent\n * POST {endpoint}/console/cloudagent/agentmgmt/agents\n */\n async create(): Promise<string> {\n try {\n // @ts-expect-error Backend Connect Not Ready\n const createPayload: CreateAgentRequest = {\n prompt: '',\n // source: {\n // provider: 'github',\n // repository: 'example/repo',\n // ref: 'main'\n // },\n // target: {\n // branchName: 'main',\n // autoCreatePr: false\n // },\n model: 'deepseek-r1',\n // webhook: {\n // url: 'https://example.com/webhook',\n // secret: 'supersecret'\n // }\n };\n const response = await this.request('POST', '/console/cloudagent/agentmgmt/agents', createPayload);\n\n if (!response.ok) {\n throw new Error(`Failed to create agent: ${response.statusText}`);\n }\n\n const apiResponse = await response.json() as ApiResponse<CreateAgentResponse>;\n if (!apiResponse.data) {\n throw new Error('No data in API response');\n }\n\n this.logger?.info(`Created agent: ${apiResponse.data.id}`);\n return apiResponse.data.id;\n } catch (error) {\n this.logger?.error('Failed to create agent:', error);\n throw error;\n }\n }\n\n /**\n * Connect to an agent and return the connection\n *\n * This method:\n * 1. Fetches the agent configuration from the backend\n * 2. Checks if an existing connection can be reused (based on endpoint link)\n * 3. Creates a CloudAgentConnection to the agent's endpoint if not cached\n * 4. Saves session connection info to the connection\n * 5. Connects and initializes the connection\n * 6. Returns the connected CloudAgentConnection\n *\n * Connection caching:\n * - Connections are cached by endpoint link to enable reuse\n * - CloudAgentConnection is responsible for handling connection health checks\n * and token expiration internally\n */\n async connect(agentId: string): Promise<CloudAgentConnection> {\n // Fetch agent data from backend\n const response = await this.request('GET', `/console/cloudagent/agentmgmt/agents/${agentId}/session`);\n\n if (response.status === 404) {\n throw new Error(`Agent not found: ${agentId}`);\n }\n\n if (!response.ok) {\n throw new Error(`Failed to get agent for connection: ${response.statusText}`);\n }\n\n const apiResponse = await response.json() as ApiResponse<GetAgentSessionResponse>;\n if (!apiResponse.data) {\n throw new Error('No data in API response');\n }\n\n const sessionData = apiResponse.data;\n const endpoint = sessionData.link.replace(/^http:\\/\\//, 'https://');\n\n // Check for existing cached connection\n const existingConnection = this.connectionCache.get(endpoint);\n if (existingConnection?.isInitialized) {\n this.logger?.info(`Reusing existing connection for agent: ${agentId}`);\n return existingConnection;\n }\n\n // Create connection to agent's endpoint\n // Note: CloudAgentConnection is responsible for:\n // - Connection health checks (reconnection on disconnect)\n // - Token expiration handling (refresh or re-authentication)\n const connection = new CloudAgentConnection(agentId, {\n endpoint,\n authToken: sessionData.token,\n // Backend does not provide custom headers currently\n // headers: data.headers,\n logger: this.logger,\n clientCapabilities: this.options.clientCapabilities\n });\n\n // Save session connection info to the connection\n connection.setSessionConnectionInfo({\n sessionId: sessionData.sessionId,\n agentId: sessionData.id,\n link: sessionData.link,\n token: sessionData.token,\n sandboxId: sessionData.sandboxId,\n expireAt: sessionData.expireAt\n });\n\n // Connect and initialize\n try {\n await connection.connect();\n } catch (error) {\n this.logger?.error(`Failed to connect to agent ${agentId}:`, error);\n throw error;\n }\n\n // Cache the connection\n this.connectionCache.set(endpoint, connection);\n\n // Clean up cache when connection is disconnected\n connection.once('disconnected', () => {\n this.connectionCache.delete(endpoint);\n this.logger?.debug(`Connection removed from cache: ${endpoint}`);\n });\n\n this.logger?.info(`Connected to agent: ${agentId}`);\n return connection;\n }\n\n /**\n * Delete an agent by ID\n * POST {endpoint}/console/cloudagent/agentmgmt/agents/{agentId}/delete\n */\n async delete(agentId: string): Promise<boolean> {\n try {\n const requestBody: DeleteAgentRequest = { id: agentId };\n const response = await this.request('POST', `/console/cloudagent/agentmgmt/agents/${agentId}/delete`, requestBody);\n\n if (response.status === 404) {\n return false;\n }\n\n if (!response.ok) {\n throw new Error(`Failed to delete agent: ${response.statusText}`);\n }\n\n return true;\n } catch (error) {\n this.logger?.error(`Failed to delete agent ${agentId}:`, error);\n throw error;\n }\n }\n\n /**\n * Archive an agent by ID\n * POST {endpoint}/console/cloudagent/agentmgmt/agents/{agentId}/archive\n *\n * @param agentId - Agent ID to archive\n * @returns ArchiveAgentResponse containing the archived agent ID\n *\n * @example\n * ```typescript\n * const result = await provider.archive('agent-123');\n * console.log('Archived agent:', result.id);\n * ```\n */\n async archive(agentId: string): Promise<ArchiveAgentResponse> {\n try {\n const response = await this.request('POST', `/console/cloudagent/agentmgmt/agents/${agentId}/archive`);\n\n if (!response.ok) {\n throw new Error(`Failed to archive agent: ${response.statusText}`);\n }\n\n const apiResponse = await response.json() as ApiResponse<ArchiveAgentResponse>;\n if (!apiResponse.data) {\n // 如果后端没有返回 data,使用传入的 agentId\n this.logger?.info(`Archived agent: ${agentId}`);\n return { id: agentId };\n }\n\n this.logger?.info(`Archived agent: ${apiResponse.data.id}`);\n return apiResponse.data;\n } catch (error) {\n this.logger?.error(`Failed to archive agent ${agentId}:`, error);\n throw error;\n }\n }\n\n /**\n * Rename an agent by ID\n * PATCH {endpoint}/v2/cloudagent/agentmgmt/agents/{agentId}\n *\n * @param agentId - Agent ID to rename\n * @param title - New title for the agent\n * @returns RenameAgentResponse containing the renamed agent ID\n *\n * @example\n * ```typescript\n * const result = await provider.rename('agent-123', 'New Title');\n * console.log('Renamed agent:', result.id);\n * ```\n */\n async rename(agentId: string, title: string): Promise<RenameAgentResponse> {\n try {\n const body: PatchAgentRequest = { title };\n const response = await this.request('POST', `/console/cloudagent/agentmgmt/agents/${agentId}`, body);\n\n if (!response.ok) {\n throw new Error(`Failed to rename agent: ${response.statusText}`);\n }\n\n const apiResponse = await response.json() as ApiResponse<PatchAgentResponse>;\n if (!apiResponse.data) {\n // 如果后端没有返回 data,使用传入的 agentId\n this.logger?.info(`Renamed agent: ${agentId} to \"${title}\"`);\n return { id: agentId };\n }\n\n this.logger?.info(`Renamed agent: ${apiResponse.data.id} to \"${title}\"`);\n return apiResponse.data;\n } catch (error) {\n this.logger?.error(`Failed to rename agent ${agentId}:`, error);\n throw error;\n }\n }\n\n /**\n * Get available models for a repository\n *\n * GET {endpoint}/console/cloudagent/agentmgmt/models?repo={repo}\n *\n * @param repo - Repository identifier\n * @returns Array of model names (backend only provides names, not full ModelInfo)\n */\n async getModels(repo: string): Promise<ModelInfo[]> {\n try {\n const response = await this.request('GET', `/console/cloudagent/agentmgmt/models?repo=${encodeURIComponent(repo)}`);\n\n if (!response.ok) {\n throw new Error(`Failed to get models: ${response.statusText}`);\n }\n\n const apiResponse = await response.json() as ApiResponse<GetModelResponse>;\n if (!apiResponse.data) {\n throw new Error('No data in API response');\n }\n\n const models = apiResponse.data.models;\n this.logger?.info(`Retrieved ${models.length} models for repo: ${repo}`);\n return models.map(m => ({\n id: m,\n name: '',\n description: '',\n }));\n } catch (error) {\n this.logger?.error(`Failed to get models for repo ${repo}:`, error);\n throw error;\n }\n }\n\n // ============================================\n // File Picker (Browser Environment)\n // ============================================\n\n /**\n * Common image MIME types for filtering\n */\n private static readonly IMAGE_MIME_TYPES = [\n 'image/png',\n 'image/jpeg',\n 'image/jpg',\n 'image/gif',\n 'image/webp',\n 'image/svg+xml',\n 'image/bmp',\n ];\n\n /**\n * Pick files using browser's native file input\n *\n * @param params - File picker parameters\n * @returns Response with selected file paths (filenames in browser)\n */\n async pickFile(params?: PickFileParams): Promise<PickFileResponse> {\n return new Promise((resolve) => {\n const input = document.createElement('input');\n input.type = 'file';\n input.style.display = 'none';\n\n // Set accept attribute\n if (params?.filters && params.filters.length > 0) {\n const acceptTypes: string[] = [];\n for (const filter of params.filters) {\n for (const ext of filter.extensions) {\n const mimeType = this.extensionToMimeType(ext);\n acceptTypes.push(mimeType || `.${ext}`);\n }\n }\n input.accept = acceptTypes.join(',');\n } else {\n input.accept = CloudAgentProvider.IMAGE_MIME_TYPES.join(',');\n }\n\n input.multiple = params?.canSelectMany ?? false;\n\n input.onchange = () => {\n const files = input.files;\n if (!files || files.length === 0) {\n resolve({ files: [], canceled: true });\n } else {\n const fileArray = Array.from(files);\n this.logger?.info(`Picked ${fileArray.length} file(s)`);\n resolve({ files: fileArray, canceled: false });\n }\n document.body.removeChild(input);\n };\n\n input.oncancel = () => {\n resolve({ files: [], canceled: true });\n document.body.removeChild(input);\n };\n\n document.body.appendChild(input);\n input.click();\n });\n }\n\n /**\n * Convert file extension to MIME type\n */\n private extensionToMimeType(ext: string): string | null {\n const extLower = ext.toLowerCase().replace(/^\\./, '');\n const mimeMap: Record<string, string> = {\n 'png': 'image/png',\n 'jpg': 'image/jpeg',\n 'jpeg': 'image/jpeg',\n 'gif': 'image/gif',\n 'webp': 'image/webp',\n 'svg': 'image/svg+xml',\n 'bmp': 'image/bmp',\n 'ico': 'image/x-icon',\n };\n return mimeMap[extLower] || null;\n }\n\n // ============================================\n // File Upload (Browser Environment)\n // ============================================\n\n /**\n * Upload files to cloud storage via COS presigned URL\n *\n * @param params - files array (File objects in browser)\n * @returns Response with corresponding cloud URLs\n */\n async uploadFile(params: UploadFileParams): Promise<UploadFileResponse> {\n this.logger?.info(`[CloudAgentProvider] uploadFile called for ${params.files.length} file(s)`);\n\n // Filter out string paths (only File objects are supported in browser)\n const files = params.files.filter((f): f is File => typeof f !== 'string');\n if (files.length === 0) {\n return {\n success: false,\n error: 'No valid File objects provided',\n };\n }\n\n // Use CosUploadService for actual upload\n const result = await this.cosUploadService.uploadFiles(files);\n\n return {\n success: result.success,\n urls: result.urls,\n error: result.error,\n };\n }\n\n // ============================================\n // Helpers\n // ============================================\n\n private toAgentState(data: AgentDto): CloudAgentState {\n // 优先使用 sessionStatus(会话状态),fallback 到 status(Agent 状态)\n const status = data.sessionStatus || data.status;\n return {\n id: data.id,\n name: data.name,\n description: data.summary,\n type: 'cloud',\n status: status as AgentStatus,\n createdAt: data.createdAt ? new Date(data.createdAt) : undefined,\n capabilities: this.options.clientCapabilities,\n };\n }\n\n private async request(\n method: string,\n path: string,\n body?: unknown\n ): Promise<Response> {\n let url = `${this.options.endpoint}${path}`;\n\n const headers: Record<string, string> = {\n 'Content-Type': 'application/json',\n ...this.options.headers\n };\n\n if (this.options.authToken) {\n headers['Authorization'] = `Bearer ${this.options.authToken}`;\n }\n\n // 从 localStorage 获取企业 ID\n const enterpriseId = typeof localStorage !== 'undefined'\n ? localStorage.getItem(SELECTED_ACCOUNT_KEY)\n : null;\n if (enterpriseId) {\n headers['X-Enterprise-Id'] = enterpriseId;\n }\n\n const init: RequestInit = {\n method,\n headers\n };\n\n // For GET requests, convert body to query params\n if (method === 'GET' && body !== undefined) {\n const params = new URLSearchParams();\n for (const [key, value] of Object.entries(body as Record<string, unknown>)) {\n if (value !== undefined && value !== null) {\n // For complex types (objects/arrays), stringify them\n // For primitive types, convert to string directly\n const stringValue = typeof value === 'object'\n ? JSON.stringify(value)\n : String(value);\n params.append(key, stringValue);\n }\n }\n const queryString = params.toString();\n if (queryString) {\n url += `?${queryString}`;\n }\n } else if (body !== undefined) {\n // For non-GET requests, use body\n init.body = JSON.stringify(body);\n }\n\n this.logger?.debug(`${method} ${url}`);\n\n return this.fetchImpl(url, init);\n }\n}\n\nexport default CloudAgentProvider;\n","/**\n * Local Agent Connection\n * Wraps AcpJsonRpcClient to implement AgentConnection interface\n *\n * Uses IWidgetChannel for IPC communication with ExtensionHost\n * Migrated from ipc-agent-provider for unified local agent access\n */\n\nimport {\n PROTOCOL_VERSION,\n type SessionNotification,\n type RequestPermissionRequest,\n type InitializeResponse,\n type NewSessionResponse,\n type LoadSessionResponse,\n type PromptResponse,\n type SetSessionModeResponse,\n type SetSessionModelResponse,\n type ContentBlock\n} from '@agentclientprotocol/sdk';\n\nimport type {\n Artifact,\n ArtifactType,\n QuestionRequest,\n QuestionAnswers,\n ClientCapabilities,\n CheckpointInfo\n} from '@genie/agent-client-protocol';\n\nimport type {\n AgentConnection,\n AgentStatus,\n AgentCapabilities,\n LocalConnectionConfig,\n CreateSessionParams,\n LoadSessionParams,\n PromptParams,\n ConnectionEvents,\n ConnectionEventListener,\n} from '../../types.js';\n\nimport {\n AcpJsonRpcClient,\n type SessionUpdateParams,\n type PermissionRequestParams,\n type PermissionResponse,\n type OpenWorkspaceRequest,\n type OpenWorkspaceResponse,\n type ToolCallbackRequest\n} from './acp/index.js';\n\n// Re-export IWidgetChannel for convenience\nexport type { IWidgetChannel } from './acp/index.js';\n\n// ============================================================================\n// Local Agent Connection Implementation\n// ============================================================================\n\n/**\n * Local Agent Connection implementation\n * Uses AcpJsonRpcClient to communicate with ExtensionHost via IWidgetChannel\n *\n * Phase 1 Implementation:\n * - connect/disconnect: ✅ via initialize\n * - createSession/loadSession: ✅ via AcpJsonRpcClient\n * - prompt/cancel: ✅ via AcpJsonRpcClient\n * - Event forwarding: ✅ sessionUpdate, permissionRequest\n * - resolvePermission/rejectPermission: ✅ via callback\n *\n * Phase 2 (Not Implemented):\n * - promptStream: throws 'Not implemented'\n * - Artifact methods: return empty\n * - Question methods: return empty\n * - Extension methods: throw 'Not implemented'\n * - Filesystem methods: throw 'Not implemented'\n */\nexport class LocalAgentConnection implements AgentConnection {\n // ========================================================================\n // Private Fields\n // ========================================================================\n\n /** ACP JSON-RPC Client */\n private readonly acpClient: AcpJsonRpcClient;\n\n /** Debug mode */\n private readonly debug: boolean;\n\n /** Event listeners */\n private listeners: Map<keyof ConnectionEvents, Set<ConnectionEventListener<unknown>>> = new Map();\n private onceListeners: Map<keyof ConnectionEvents, Set<ConnectionEventListener<unknown>>> = new Map();\n\n /** Connection state */\n private _state: AgentStatus = 'disconnected';\n private _isInitialized = false;\n private _capabilities?: AgentCapabilities;\n private _initializeResult?: InitializeResponse;\n\n /** Pending permission requests: requestId → { params, createdAt } */\n private pendingPermissions: Map<string, { params: PermissionRequestParams; createdAt: number }> = new Map();\n\n /** Permission timeout config */\n private readonly permissionTimeout: number;\n private readonly permissionAutoRejectOnTimeout: boolean;\n\n /** Local artifact cache: id → Artifact */\n private artifactCache: Map<string, Artifact> = new Map();\n\n // ========================================================================\n // Public Properties\n // ========================================================================\n\n /** agentId = cwd (工作区路径) */\n readonly agentId: string;\n\n /** 工作区路径 (与 agentId 相同,语义更清晰) */\n readonly cwd: string;\n\n readonly transport = 'local' as const;\n\n private onRequest?: () => void = undefined;\n\n // ========================================================================\n // Constructor\n // ========================================================================\n\n constructor(agentId: string, config: LocalConnectionConfig) {\n this.agentId = agentId;\n this.cwd = agentId; // agentId 就是 cwd\n this.debug = config.debug ?? false;\n this.permissionTimeout = config.permissionTimeout ?? 30000;\n this.permissionAutoRejectOnTimeout = config.permissionAutoRejectOnTimeout ?? false;\n\n // Initialize ACP JSON-RPC Client\n this.acpClient = new AcpJsonRpcClient(config.channel, {\n timeoutMs: config.acpConfig?.timeoutMs ?? 30000,\n debug: this.debug\n });\n\n // Setup event forwarding\n this.setupEventForwarding();\n\n this.log('LocalAgentConnection initialized');\n }\n\n // ========================================================================\n // Event Forwarding Setup\n // ========================================================================\n\n private setupEventForwarding(): void {\n // Forward session updates from AcpJsonRpcClient\n this.acpClient.onSessionUpdate((params: SessionUpdateParams) => {\n this.emit('sessionUpdate', params.notification);\n });\n\n // Forward extNotification from AcpJsonRpcClient (for artifacts, checkpoints, etc.)\n this.acpClient.onExtNotification((method: string, params: Record<string, unknown>) => {\n console.log('[LocalConnection] Received extNotification:', { method, paramsKeys: Object.keys(params) });\n\n // Handle artifact notifications\n if (method === '_codebuddy.ai/artifact') {\n const event = params.event as 'created' | 'updated' | 'deleted';\n const artifact = params.artifact as Artifact;\n\n console.log('[LocalConnection] Emitting artifact event:', { event, artifactUri: artifact?.uri });\n\n // Update local artifact cache\n if (artifact?.uri) {\n if (event === 'created' || event === 'updated') {\n this.artifactCache.set(artifact.uri, artifact);\n } else if (event === 'deleted') {\n this.artifactCache.delete(artifact.uri);\n }\n }\n\n if (event === 'created') {\n this.emit('artifactCreated', artifact);\n } else if (event === 'updated') {\n this.emit('artifactUpdated', artifact);\n } else if (event === 'deleted') {\n this.emit('artifactDeleted', artifact);\n }\n }\n\n // Handle checkpoint notifications\n if (method === '_codebuddy.ai/checkpoint') {\n const event = params.event as 'created' | 'updated';\n const checkpoint = params.checkpoint as CheckpointInfo;\n\n console.log('[LocalConnection] Emitting checkpoint event:', {\n event,\n checkpointId: checkpoint?.id,\n filesCount: checkpoint?.fileChanges?.files?.length ?? 0\n });\n\n if (event === 'created') {\n this.emit('checkpointCreated', checkpoint);\n } else if (event === 'updated') {\n this.emit('checkpointUpdated', checkpoint);\n }\n }\n });\n\n this.log('Event forwarding setup complete');\n }\n\n // ========================================================================\n // Event Emitter Implementation\n // ========================================================================\n\n on<K extends keyof ConnectionEvents>(event: K, listener: ConnectionEventListener<ConnectionEvents[K]>): this {\n if (!this.listeners.has(event)) {\n this.listeners.set(event, new Set());\n }\n this.listeners.get(event)!.add(listener as ConnectionEventListener<unknown>);\n return this;\n }\n\n off<K extends keyof ConnectionEvents>(event: K, listener: ConnectionEventListener<ConnectionEvents[K]>): this {\n const eventListeners = this.listeners.get(event);\n if (eventListeners) {\n eventListeners.delete(listener as ConnectionEventListener<unknown>);\n }\n const onceEventListeners = this.onceListeners.get(event);\n if (onceEventListeners) {\n onceEventListeners.delete(listener as ConnectionEventListener<unknown>);\n }\n return this;\n }\n\n once<K extends keyof ConnectionEvents>(event: K, listener: ConnectionEventListener<ConnectionEvents[K]>): this {\n if (!this.onceListeners.has(event)) {\n this.onceListeners.set(event, new Set());\n }\n this.onceListeners.get(event)!.add(listener as ConnectionEventListener<unknown>);\n return this;\n }\n\n emit<K extends keyof ConnectionEvents>(event: K, data: ConnectionEvents[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 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(`Error in async once event listener for '${String(event)}':`, err);\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 removeAllListeners<K extends keyof ConnectionEvents>(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 // State Properties\n // ========================================================================\n\n get state(): AgentStatus {\n return this._state;\n }\n\n get isInitialized(): boolean {\n return this._isInitialized;\n }\n\n get capabilities(): AgentCapabilities | undefined {\n return this._capabilities;\n }\n\n get initializeResult(): InitializeResponse | undefined {\n return this._initializeResult;\n }\n\n // ========================================================================\n // Connection Lifecycle (Phase 1: Implemented)\n // ========================================================================\n\n async connect(_clientCapabilities?: ClientCapabilities): Promise<InitializeResponse> {\n this.log('Connecting...');\n this._state = 'connecting';\n this.emit('connecting', undefined);\n this._isInitialized = true;\n this._initializeResult = { protocolVersion: PROTOCOL_VERSION };\n this.emit('connected', undefined);\n this._state = 'initialized';\n return this._initializeResult;\n }\n\n disconnect(): void {\n this.log('Disconnecting...');\n\n // 清理所有待处理的权限请求\n this.cleanupPendingPermissionsOnDisconnect();\n\n this._state = 'disconnected';\n this._isInitialized = false;\n this.acpClient.destroy();\n this.emit('disconnected', undefined);\n this.log('Disconnected');\n }\n\n /**\n * 清理断开连接时所有待处理的权限请求\n * 在连接断开时主动清理所有 pending 权限请求并返回 cancelled\n */\n private cleanupPendingPermissionsOnDisconnect(): void {\n const count = this.pendingPermissions.size;\n if (count === 0) {\n return;\n }\n\n for (const [requestId] of this.pendingPermissions) {\n const resolver = (this as any)[`_permissionResolver_${requestId}`];\n if (resolver) {\n resolver({ outcome: 'cancelled' });\n delete (this as any)[`_permissionResolver_${requestId}`];\n }\n }\n this.pendingPermissions.clear();\n this.log(`Cleaned up ${count} pending permission request(s) on disconnect`);\n }\n\n // ========================================================================\n // Session Management (Phase 1: Implemented)\n // ========================================================================\n\n async createSession(params: CreateSessionParams): Promise<NewSessionResponse> {\n this.log('Creating session with cwd:', params.cwd);\n const response = await this.acpClient.newSession({\n cwd: params.cwd,\n mcpServers: (params.mcpServers ?? []) as any // Type cast needed for McpServerConfig → McpServer\n });\n\n this.bindPermissionRequest(response.sessionId);\n return response;\n }\n\n async loadSession(params: LoadSessionParams): Promise<LoadSessionResponse> {\n if (!params.sessionId) {\n throw new Error('sessionId is required for loadSession');\n }\n this.log(`[LocalAgentConnection] loadSession: ${params.sessionId}`);\n const response = await this.acpClient.loadSession({\n sessionId: params.sessionId,\n cwd: params.cwd,\n mcpServers: (params.mcpServers ?? []) as any // Type cast needed for McpServerConfig → McpServer\n });\n this.log(`[LocalAgentConnection] loadSession response:${response}`);\n\n this.bindPermissionRequest(params.sessionId);\n return response;\n }\n\n async bindPermissionRequest(sessionId: string) {\n if (this.onRequest) {\n this.onRequest();\n }\n // Forward permission requests from AcpJsonRpcClient\n this.onRequest = this.acpClient.onRequestPermission(sessionId, async (params: PermissionRequestParams): Promise<PermissionResponse> => {\n // Store pending permission (using PermissionRequestParams format)\n this.pendingPermissions.set(params.requestId, {\n params: params,\n createdAt: Date.now()\n });\n\n // Emit event (convert to RequestPermissionRequest format expected by ConnectionEvents)\n const permissionRequest: RequestPermissionRequest = {\n sessionId: params.sessionId,\n toolCall: params.toolCall, // Type mismatch between legacy and SDK\n options: params.options\n };\n this.emit('permissionRequest', { requestId: params.requestId, params: permissionRequest });\n\n // Wait for resolution\n return new Promise<PermissionResponse>((resolve) => {\n const checkResolution = () => {\n // Check if resolved/rejected\n if (!this.pendingPermissions.has(params.requestId)) {\n // Already resolved by resolvePermission/rejectPermission\n return;\n }\n\n // Check timeout\n const pending = this.pendingPermissions.get(params.requestId);\n if (pending && Date.now() - pending.createdAt > this.permissionTimeout) {\n this.pendingPermissions.delete(params.requestId);\n this.emit('permissionTimeout', { requestId: params.requestId });\n if (this.permissionAutoRejectOnTimeout) {\n resolve({ outcome: 'cancelled' });\n }\n }\n };\n\n // Store resolver for external resolution\n (this as any)[`_permissionResolver_${params.requestId}`] = resolve;\n\n // Setup timeout check\n setTimeout(checkResolution, this.permissionTimeout);\n });\n });\n }\n\n // ========================================================================\n // Session Mode Management\n // ========================================================================\n\n async setSessionMode(sessionId: string, modeId: string): Promise<SetSessionModeResponse> {\n this.log('Setting session mode:', sessionId, 'to', modeId);\n return await this.acpClient.setSessionMode({ sessionId, modeId });\n }\n\n async setSessionModel(sessionId: string, modelId: string): Promise<SetSessionModelResponse> {\n this.log('Setting session model:', sessionId, 'to', modelId);\n return await this.acpClient.setSessionModel({ sessionId, modelId });\n }\n\n // ========================================================================\n // Workspace Operations\n // ========================================================================\n\n /**\n * 打开工作区窗口\n * 使用 __workspace__ session ID,由 Main Process 直接处理,不转发到 ExtensionHost\n * @param params 打开工作区请求参数\n * @returns 打开工作区响应\n */\n async openWorkspace(params: OpenWorkspaceRequest): Promise<OpenWorkspaceResponse> {\n this.log('Opening workspace:', params.cwd);\n return await this.acpClient.openWorkspace(params);\n }\n\n // ========================================================================\n // Prompt Operations (Phase 1: Implemented, except promptStream)\n // ========================================================================\n\n async prompt(sessionId: string, params: PromptParams): Promise<PromptResponse> {\n // 如果 content 是字符串,包装成 ContentBlock;否则直接使用\n const prompt = typeof params.content === 'string'\n ? [{ type: 'text' as const, text: params.content }]\n : params.content as ContentBlock[];\n\n this.log('Sending prompt to session:', sessionId);\n return await this.acpClient.prompt({\n sessionId,\n prompt,\n ...(params.planMode !== undefined && { _meta: { ...params._meta, planMode: params.planMode } })\n }); // Cast needed due to legacy type mismatch\n }\n\n async *promptStream(_sessionId: string, _params: PromptParams): AsyncIterable<SessionNotification> {\n // Phase 2: Not implemented yet\n throw new Error('promptStream not implemented for Local connection');\n }\n\n async cancel(sessionId: string): Promise<void> {\n this.log('Cancelling session:', sessionId);\n await this.acpClient.cancel({ sessionId });\n }\n\n // ========================================================================\n // Artifact Management (Implemented via local cache)\n // ========================================================================\n\n getArtifacts(): Map<string, Artifact> {\n return new Map(this.artifactCache);\n }\n\n getArtifact(uri: string): Artifact | undefined {\n return this.artifactCache.get(uri);\n }\n\n getArtifactsByType(type: ArtifactType): Artifact[] {\n return Array.from(this.artifactCache.values()).filter(artifact => artifact.type === type);\n }\n\n async fetchArtifactContent(_artifact: Artifact): Promise<string> {\n // Phase 2: Not implemented\n throw new Error('fetchArtifactContent not implemented for Local connection');\n }\n\n async fetchArtifactContentById(_id: string): Promise<string> {\n // Phase 2: Not implemented\n throw new Error('fetchArtifactContentById not implemented for Local connection');\n }\n\n // ========================================================================\n // Permission Management (Phase 1: Implemented)\n // ========================================================================\n\n resolvePermission(requestId: string, optionId: string): boolean {\n const resolver = (this as any)[`_permissionResolver_${requestId}`];\n if (resolver) {\n this.pendingPermissions.delete(requestId);\n delete (this as any)[`_permissionResolver_${requestId}`];\n resolver({ outcome: 'selected', optionId });\n this.emit('permissionResolved', { requestId, optionId });\n return true;\n }\n return false;\n }\n\n rejectPermission(requestId: string, reason?: string): boolean {\n const resolver = (this as any)[`_permissionResolver_${requestId}`];\n if (resolver) {\n this.pendingPermissions.delete(requestId);\n delete (this as any)[`_permissionResolver_${requestId}`];\n resolver({ outcome: 'cancelled' });\n this.emit('permissionRejected', { requestId, reason });\n return true;\n }\n return false;\n }\n\n getPendingPermissions(): Map<string, { params: RequestPermissionRequest; createdAt: number }> {\n // Convert PermissionRequestParams to RequestPermissionRequest format\n const result = new Map<string, { params: RequestPermissionRequest; createdAt: number }>();\n for (const [requestId, pending] of this.pendingPermissions) {\n result.set(requestId, {\n params: {\n sessionId: pending.params.sessionId,\n toolCall: pending.params.toolCall as any,\n options: pending.params.options\n },\n createdAt: pending.createdAt\n });\n }\n return result;\n }\n\n hasPendingPermissions(): boolean {\n return this.pendingPermissions.size > 0;\n }\n\n // ========================================================================\n // Question Management (Phase 2: Not Implemented)\n // ========================================================================\n\n answerQuestion(_toolCallId: string, _answers: QuestionAnswers): boolean {\n // Phase 2: Not implemented\n return false;\n }\n\n // ========================================================================\n // Tool Callback Management\n // ========================================================================\n\n /**\n * 工具回调操作\n * 用于对正在执行的工具进行 skip 或 cancel 操作\n * @param sessionId 会话 ID\n * @param toolCallId 工具调用 ID\n * @param toolName 工具名称\n * @param action 操作类型 ('skip' | 'cancel')\n * @returns 工具回调响应\n */\n async toolCallback(sessionId: string, toolCallId: string, toolName: string, action: 'skip' | 'cancel'): Promise<{ success: boolean; error?: string }> {\n this.log('toolCallback called for session:', sessionId, 'action:', action);\n const request: ToolCallbackRequest = { sessionId, toolCallId, toolName, action };\n return await this.acpClient.toolCallback(request);\n }\n\n cancelQuestion(_toolCallId: string, _reason?: string): boolean {\n // Phase 2: Not implemented\n return false;\n }\n\n getPendingQuestions(): Map<string, { request: QuestionRequest; createdAt: number }> {\n // Phase 2: Not implemented\n return new Map();\n }\n\n hasPendingQuestions(): boolean {\n // Phase 2: Not implemented\n return false;\n }\n\n // ========================================================================\n // Extension Methods (Phase 2: Not Implemented)\n // ========================================================================\n\n async extMethod(_method: string, _params: Record<string, unknown>): Promise<Record<string, unknown>> {\n // Phase 2: Not implemented\n throw new Error('extMethod not implemented for Local connection');\n }\n\n async extNotification(_method: string, _params: Record<string, unknown>): Promise<void> {\n // Phase 2: Not implemented\n throw new Error('extNotification not implemented for Local connection');\n }\n\n // ========================================================================\n // Filesystem Operations (Phase 2: Not Implemented)\n // ========================================================================\n\n async readFile(_path: string): Promise<string> {\n // Phase 2: Not implemented\n throw new Error('readFile not implemented for Local connection');\n }\n\n async listDir(_path: string): Promise<any[]> {\n // Phase 2: Not implemented\n throw new Error('listDir not implemented for Local connection');\n }\n\n async fileExists(_path: string): Promise<boolean> {\n // Phase 2: Not implemented\n throw new Error('fileExists not implemented for Local connection');\n }\n\n async fileStat(_path: string): Promise<any> {\n // Phase 2: Not implemented\n throw new Error('fileStat not implemented for Local connection');\n }\n\n // ========================================================================\n // Utility Methods\n // ========================================================================\n\n private log(...args: unknown[]): void {\n // if (this.debug) {\n console.log('[LocalAgentConnection]', ...args);\n // }\n }\n}\n\n/**\n * @deprecated Use LocalAgentConnection instead\n * Alias for backward compatibility\n */\nexport const IPCAgentConnection = LocalAgentConnection;\n\nexport default LocalAgentConnection;\n","/**\n * ActiveSessionImpl - Implements the ActiveSession interface\n *\n * Represents an active session with its resources and operations.\n * Session is the primary API surface for client interactions.\n */\n\nimport type { SessionNotification, PromptResponse as SdkPromptResponse } from '@agentclientprotocol/sdk';\nimport type {\n ActiveSession,\n AgentState,\n SessionAgentOperations,\n PromptsResource,\n ArtifactsResource,\n SessionEvents,\n SessionEventHandler,\n Logger,\n AgentConnection,\n Artifact,\n ArtifactType,\n PromptResponse,\n AgentCapabilities,\n SessionMode,\n QuestionAnswers,\n AvailableCommand,\n SessionConnectionInfo\n} from './types.js';\nimport type { PromptParams, FilesResource, AgentStatus } from '../types.js';\n\n/**\n * Event listener type\n */\ntype EventListener<T> = (data: T) => void | Promise<void>;\n\n/**\n * Filesystem getter function type\n * Returns a FilesResource instance for file operations\n */\nexport type FilesystemGetter = () => Promise<FilesResource>;\n\n/**\n * Options for creating an ActiveSessionImpl instance\n */\nexport interface ActiveSessionImplOptions {\n /** Logger instance */\n logger?: Logger;\n /** Getter function for filesystem resource (provided by SessionManager) */\n getFilesystem?: FilesystemGetter;\n /** Session connection information (for cloud sessions) */\n connectionInfo?: SessionConnectionInfo;\n}\n\n/**\n * ActiveSessionImpl - Implements the ActiveSession interface\n *\n * This class wraps an AgentConnection and provides the session-centric API.\n * It is created by SessionManager when creating or loading sessions.\n *\n * @example\n * ```typescript\n * // Created by client.sessions.new() or client.sessions.load()\n * const session = await client.sessions.new({ cwd: '/workspace' });\n *\n * // Access agent state\n * console.log(session.agentState.status);\n *\n * // Send prompt\n * const response = await session.prompts.send({ content: 'Hello!' });\n *\n * // Cleanup\n * session.disconnect();\n * ```\n */\nexport class ActiveSessionImpl implements ActiveSession {\n private _id: string;\n private _agentId: string;\n private _availableModes?: SessionMode[];\n private _currentMode?: string;\n private _availableCommands: AvailableCommand[] = [];\n private logger?: Logger;\n private connection: AgentConnection;\n private _getFilesystem?: FilesystemGetter;\n private _connectionInfo?: SessionConnectionInfo;\n\n // Event emitter storage\n private listeners: Map<keyof SessionEvents, Set<EventListener<unknown>>> = new Map();\n private onceListeners: Map<keyof SessionEvents, Set<EventListener<unknown>>> = new Map();\n\n /**\n * Agent operations namespace\n */\n readonly agent: SessionAgentOperations;\n\n /**\n * Prompts resource namespace\n */\n readonly prompts: PromptsResource;\n\n /**\n * Artifacts resource namespace\n */\n readonly artifacts: ArtifactsResource;\n\n /**\n * Files resource namespace (lazily loaded via getter)\n */\n readonly files: FilesResource;\n\n /**\n * Create an ActiveSessionImpl instance\n *\n * @param sessionId - Session ID\n * @param agentId - Agent ID\n * @param connection - Already connected AgentConnection\n * @param options - Additional options\n */\n constructor(\n sessionId: string,\n agentId: string,\n connection: AgentConnection,\n options: ActiveSessionImplOptions = {}\n ) {\n this._id = sessionId;\n this._agentId = agentId;\n this.connection = connection;\n this.logger = options.logger;\n this._getFilesystem = options.getFilesystem;\n this._connectionInfo = options.connectionInfo;\n\n // Set up event forwarding from connection\n this.setupConnectionEvents(connection);\n\n // Initialize agent operations namespace\n this.agent = this.createAgentOperations();\n\n // Initialize resource namespaces\n this.prompts = this.createPromptsResource();\n this.artifacts = this.createArtifactsResource();\n this.files = this.createFilesResource();\n }\n\n // ============================================\n // Properties\n // ============================================\n\n /**\n * Session ID\n */\n get id(): string {\n return this._id;\n }\n\n /**\n * Agent ID\n */\n get agentId(): string {\n return this._agentId;\n }\n\n /**\n * Agent state (live connection state)\n * Returns LocalAgentState or CloudAgentState based on transport type\n */\n get agentState(): AgentState {\n return {\n id: this._agentId,\n status: this.connection.state as AgentStatus,\n capabilities: this.connection.capabilities,\n type: 'local',\n cwd: ''\n }\n }\n\n /**\n * Get agent capabilities (available after connection)\n */\n get capabilities(): AgentCapabilities | undefined {\n return this.connection.capabilities;\n }\n\n /**\n * Available session modes\n */\n get availableModes(): SessionMode[] | undefined {\n return this._availableModes;\n }\n\n /**\n * Current session mode\n */\n get currentMode(): string | undefined {\n return this._currentMode;\n }\n\n /**\n * Available slash commands\n *\n * When Agent sends available_commands_update, this list is automatically updated.\n * Commands can be accessed directly without waiting for events.\n */\n get availableCommands(): AvailableCommand[] {\n return this._availableCommands;\n }\n\n /**\n * Check if the session is active\n */\n get isActive(): boolean {\n return this.connection.isInitialized;\n }\n\n /**\n * Session connection information (only available for cloud sessions)\n * 会话连接信息,包括sandboxId、link、token等\n */\n get connectionInfo(): SessionConnectionInfo | undefined {\n return this._connectionInfo;\n }\n\n /**\n * Set session modes (called after create/load)\n */\n setModes(availableModes?: SessionMode[], currentMode?: string): void {\n this._availableModes = availableModes;\n this._currentMode = currentMode;\n }\n\n // ============================================\n // Agent Operations Namespace\n // ============================================\n\n private createAgentOperations(): SessionAgentOperations {\n const self = this;\n return {\n get id(): string {\n return self._agentId;\n },\n get state(): AgentState {\n return self.agentState;\n },\n get isConnected(): boolean {\n return self.connection.isInitialized;\n },\n get capabilities(): AgentCapabilities | undefined {\n return self.connection.capabilities;\n }\n };\n }\n\n // ============================================\n // Prompts Resource\n // ============================================\n\n private createPromptsResource(): PromptsResource {\n return {\n send: async (params: PromptParams): Promise<PromptResponse> => {\n const connection = this.getConnectionOrThrow();\n const response = await connection.prompt(this._id, params);\n return this.mapPromptResponse(response);\n },\n\n stream: (params: PromptParams): AsyncIterable<SessionNotification> => {\n const connection = this.getConnectionOrThrow();\n return connection.promptStream(this._id, params);\n },\n\n cancel: async (): Promise<void> => {\n const connection = this.getConnectionOrThrow();\n await connection.cancel(this._id);\n }\n };\n }\n\n // ============================================\n // Artifacts Resource\n // ============================================\n\n private createArtifactsResource(): ArtifactsResource {\n // Artifact management has been simplified - these methods are no longer supported\n const notSupported = () => {\n throw new Error('Artifact management is no longer supported through this API');\n };\n\n return {\n list: async (_params?: { type?: ArtifactType }): Promise<Artifact[]> => {\n notSupported();\n return [];\n },\n\n retrieve: async (_artifactId: string): Promise<Artifact> => {\n notSupported();\n return undefined as unknown as Artifact;\n },\n\n content: async (_artifactId: string): Promise<string> => {\n notSupported();\n return '';\n }\n };\n }\n\n // ============================================\n // Files Resource\n // ============================================\n\n /**\n * Create files resource with lazy-loaded filesystem\n *\n * The filesystem is lazily loaded on first use to avoid unnecessary\n * connections to the sandbox. The actual filesystem instance is obtained\n * via the getter function provided by SessionManager.\n */\n private createFilesResource(): FilesResource {\n const self = this;\n let filesPromise: Promise<FilesResource> | null = null;\n\n /**\n * Get or create the filesystem instance\n */\n const getFs = async (): Promise<FilesResource> => {\n if (!self._getFilesystem) {\n throw new Error('Filesystem not available: provider does not support filesystem operations');\n }\n if (!filesPromise) {\n filesPromise = self._getFilesystem();\n }\n return filesPromise;\n };\n\n return {\n // Read operations - 支持多种格式重载\n read: (async (path: string, opts?: any) => (await getFs()).read(path, opts)) as FilesResource['read'],\n\n // Write operations - 支持单文件和批量写入重载\n write: (async (pathOrFiles: any, dataOrOpts?: any, opts?: any) => {\n const fs = await getFs();\n if (Array.isArray(pathOrFiles)) {\n // Batch write\n return fs.write(pathOrFiles, dataOrOpts);\n }\n // Single file write\n return fs.write(pathOrFiles, dataOrOpts, opts);\n }) as FilesResource['write'],\n\n // List with depth support\n list: async (path, opts) => (await getFs()).list(path, opts),\n exists: async (path, opts) => (await getFs()).exists(path, opts),\n makeDir: async (path, opts) => (await getFs()).makeDir(path, opts),\n remove: async (path, opts) => (await getFs()).remove(path, opts),\n rename: async (oldPath, newPath, opts) => (await getFs()).rename(oldPath, newPath, opts),\n\n // 新增 getInfo 方法\n getInfo: async (path, opts) => (await getFs()).getInfo(path, opts),\n\n // Watch operations - 支持扩展的 opts\n watchDir: async (path, onEvent, opts) => (await getFs()).watchDir(path, onEvent, opts)\n };\n }\n\n // ============================================\n // Permission Management\n // ============================================\n\n /**\n * Resolve a permission request\n */\n resolvePermission(requestId: string, optionId: string): boolean {\n return this.connection.resolvePermission(requestId, optionId);\n }\n\n /**\n * Reject a permission request\n */\n rejectPermission(requestId: string, reason?: string): boolean {\n return this.connection.rejectPermission(requestId, reason);\n }\n\n // ============================================\n // Question Management (ask_followup_question)\n // ============================================\n\n /**\n * Answer a question request with user's selections\n */\n answerQuestion(toolCallId: string, answers: QuestionAnswers): boolean {\n return this.connection.answerQuestion(toolCallId, answers);\n }\n\n /**\n * Cancel a question request\n */\n cancelQuestion(toolCallId: string, reason?: string): boolean {\n return this.connection.cancelQuestion(toolCallId, reason);\n }\n\n // ============================================\n // Tool Callback Management\n // ============================================\n\n /**\n * Callback for tool operations (skip or cancel)\n * @param toolCallId Tool call ID\n * @param toolName Tool name\n * @param action Action to perform ('skip' or 'cancel')\n */\n async toolCallback(toolCallId: string, toolName: string, action: 'skip' | 'cancel'): Promise<{ success: boolean; error?: string }> {\n const connection = this.getConnectionOrThrow();\n return await connection.toolCallback(this._id, toolCallId, toolName, action);\n }\n\n // ============================================\n // Session Mode Management\n // ============================================\n\n /**\n * Set the current session mode\n *\n * @param modeId - The mode ID to switch to (must be in availableModes)\n * @throws Error if modeId is not in availableModes or connection fails\n *\n * @example\n * ```typescript\n * // Switch to 'code' mode\n * await session.setMode('code');\n *\n * // Switch to 'architect' mode\n * await session.setMode('architect');\n * ```\n */\n async setMode(modeId: string): Promise<void> {\n // Validate modeId if availableModes is set\n if (this._availableModes) {\n const modeExists = this._availableModes.some(m => m.id === modeId);\n if (!modeExists) {\n const availableIds = this._availableModes.map(m => m.id).join(', ');\n throw new Error(`Invalid modeId: \"${modeId}\". Available modes: ${availableIds}`);\n }\n }\n\n const connection = this.getConnectionOrThrow();\n await connection.setSessionMode(this._id, modeId);\n\n // Update internal state\n this._currentMode = modeId;\n }\n\n /**\n * Set the current session model\n *\n * @param modelId - The model ID to switch to\n * @example\n * ```typescript\n * // Switch to Claude Sonnet 4\n * await session.setSessionModel('claude-sonnet-4-20250514');\n *\n * // Switch to GPT-4o\n * await session.setSessionModel('gpt-4o');\n * ```\n */\n async setSessionModel(modelId: string): Promise<void> {\n const connection = this.getConnectionOrThrow();\n await connection.setSessionModel(this._id, modelId);\n }\n\n // ============================================\n // Event Subscription\n // ============================================\n\n /**\n * Subscribe to session events\n */\n on<K extends keyof SessionEvents>(event: K, handler: SessionEventHandler<K>): this {\n if (!this.listeners.has(event)) {\n this.listeners.set(event, new Set());\n }\n this.listeners.get(event)!.add(handler as EventListener<unknown>);\n return this;\n }\n\n /**\n * Unsubscribe from session events\n */\n off<K extends keyof SessionEvents>(event: K, handler: SessionEventHandler<K>): this {\n const eventListeners = this.listeners.get(event);\n if (eventListeners) {\n eventListeners.delete(handler as EventListener<unknown>);\n }\n const onceEventListeners = this.onceListeners.get(event);\n if (onceEventListeners) {\n onceEventListeners.delete(handler as EventListener<unknown>);\n }\n return this;\n }\n\n /**\n * Subscribe to a session event once\n */\n once<K extends keyof SessionEvents>(event: K, handler: SessionEventHandler<K>): this {\n if (!this.onceListeners.has(event)) {\n this.onceListeners.set(event, new Set());\n }\n this.onceListeners.get(event)!.add(handler as EventListener<unknown>);\n return this;\n }\n\n /**\n * Emit an event to all registered listeners\n */\n private emit<K extends keyof SessionEvents>(event: K, data: SessionEvents[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 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(`Error in async once event listener for '${String(event)}':`, err);\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\n */\n private removeAllListeners<K extends keyof SessionEvents>(event?: K): void {\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 }\n\n // ============================================\n // Lifecycle\n // ============================================\n\n /**\n * Disconnect from the session/agent\n */\n disconnect(): void {\n this.connection.disconnect();\n this.removeAllListeners();\n this.logger?.info(`Session ${this._id}: Disconnected`);\n }\n\n /**\n * Symbol.dispose for 'using' keyword support\n * Automatically disconnects and cleans up when session goes out of scope\n *\n * @example\n * ```typescript\n * {\n * using session = await client.sessions.new({ cwd: '/workspace' });\n * // ... use session\n * } // session automatically disposed\n * ```\n */\n [Symbol.dispose](): void {\n this.disconnect();\n }\n\n // ============================================\n // Helpers\n // ============================================\n\n private getConnectionOrThrow(): AgentConnection {\n if (!this.connection.isInitialized) {\n throw new Error(`Session ${this._id}: Connection not initialized.`);\n }\n return this.connection;\n }\n\n private setupConnectionEvents(connection: AgentConnection): void {\n // Connection lifecycle events\n connection.on('connected', () => {\n this.emit('connected', undefined as never);\n });\n\n connection.on('disconnected', () => {\n this.emit('disconnected', undefined as never);\n });\n\n connection.on('error', (error) => {\n this.emit('error', error);\n });\n\n // Session updates\n connection.on('sessionUpdate', (update) => {\n this.emit('sessionUpdate', update);\n });\n\n // Artifact events\n connection.on('artifactCreated', (artifact) => {\n console.log('[Session] Forwarding artifactCreated:', {\n artifactUri: artifact.uri,\n artifactType: artifact.type,\n });\n this.emit('artifactCreated', artifact);\n });\n\n connection.on('artifactUpdated', (artifact) => {\n console.log('[Session] Forwarding artifactUpdated:', {\n artifactUri: artifact.uri,\n artifactType: artifact.type,\n });\n this.emit('artifactUpdated', artifact);\n });\n\n connection.on('artifactDeleted', (artifact) => {\n console.log('[Session] Forwarding artifactDeleted:', { artifactUri: artifact.uri });\n this.emit('artifactDeleted', artifact);\n });\n\n // Permission requests\n connection.on('permissionRequest', (request) => {\n this.emit('permissionRequest', request);\n });\n\n // Question requests\n connection.on('questionRequest', (request) => {\n this.emit('questionRequest', request);\n });\n\n // Usage updates\n connection.on('usageUpdate', (usage) => {\n this.emit('usageUpdate', usage);\n });\n\n // Checkpoint events\n connection.on('checkpointCreated', (checkpoint) => {\n this.emit('checkpointCreated', checkpoint);\n });\n\n connection.on('checkpointUpdated', (checkpoint) => {\n this.emit('checkpointUpdated', checkpoint);\n });\n }\n\n private mapPromptResponse(response: SdkPromptResponse): PromptResponse {\n return {\n stopReason: response.stopReason as PromptResponse['stopReason'],\n _meta: response._meta ?? undefined\n };\n }\n}\n","/**\n * SessionManager - Manages session lifecycle and connections\n *\n * Provides the core implementation for session-centric API operations:\n * - list() - Lists sessions (mapped from agents)\n * - createSession() - Creates new session (auto-creates agent)\n * - loadSession() - Loads existing session (finds agent by sessionId)\n */\n\nimport type {\n AgentProvider,\n SessionInfo,\n CreateSessionParams,\n LoadSessionParams,\n ActiveSession,\n Logger,\n ListAgentOptions,\n ListAgentResult\n} from './types.js';\nimport { ActiveSessionImpl } from './session.js';\n\n/**\n * Options for creating a SessionManager instance\n */\nexport interface SessionManagerOptions {\n /** Agent provider (required) */\n provider: AgentProvider;\n /** Logger instance */\n logger?: Logger;\n}\n\n/**\n * SessionManager - Session lifecycle management\n *\n * This class manages the relationship between sessions and agents.\n * Since the backend is agent-centric, SessionManager handles the mapping:\n * - Sessions are views over agents\n * - sessionId may equal agentId in simple cases\n *\n * Features:\n * - Session caching: reuses existing ActiveSession instances\n * - Automatic cleanup on session disconnect\n *\n * @example\n * ```typescript\n * const manager = new SessionManager({ provider, logger });\n *\n * // List sessions\n * const sessions = await manager.listSessions();\n *\n * // Create new session\n * const session = await manager.createSession({ cwd: '/workspace' });\n *\n * // Load existing session (returns cached instance if available)\n * const loaded = await manager.loadSession({ sessionId: 'xxx', cwd: '/workspace' });\n * ```\n */\nexport class SessionManager {\n private provider: AgentProvider;\n private logger?: Logger;\n\n constructor(options: SessionManagerOptions) {\n this.provider = options.provider;\n this.logger = options.logger;\n }\n\n /**\n * List all sessions with pagination info (mapped from agents)\n *\n * Each agent maps to a session. The sessionId is derived from the agent.\n * Cloud: Returns server-side filtered/sorted/paginated results\n * Local: Returns client-side filtered/sorted results (synthetic pagination)\n *\n * @param options - Optional query parameters for filtering, sorting, and pagination\n */\n async listSessions(options?: ListAgentOptions): Promise<ListAgentResult<SessionInfo>> {\n console.log('[SessionManager] listSessions called with options:', JSON.stringify(options, null, 2));\n\n const result = await this.provider.list(options);\n console.log('[SessionManager] provider.list returned:', {\n agentsCount: result.agents.length,\n pagination: result.pagination\n });\n\n const sessions = result.agents.map(agent => ({\n // Use agentId as sessionId (since sessions are 1:1 with agents in current design)\n id: agent.id,\n agentId: agent.id,\n name: agent.name,\n status: agent.status,\n createdAt: agent.createdAt,\n lastActivityAt: agent.updatedAt,\n // cwd is only available for local agents\n cwd: agent.type === 'local' ? agent.cwd : undefined\n }));\n\n console.log('[SessionManager] Returning sessions:', { count: sessions.length, pagination: result.pagination });\n return {\n agents: sessions,\n pagination: result.pagination\n };\n }\n\n /**\n * Create a new session\n *\n * Steps:\n * 1. Create new agent (if provider supports it) or use existing\n * 2. Connect to agent\n * 3. Call ACP newSession\n * 4. Register session mapping (for LocalAgentProvider)\n * 5. Return ActiveSession instance\n */\n async createSession(params: CreateSessionParams): Promise<ActiveSession> {\n this.logger?.info('Creating new session');\n\n // Step 1: Create new agent if provider supports it\n let agentId: string;\n\n if (this.provider.create) {\n // Pass params to create() - LocalAgentProvider uses cwd as agentId\n agentId = await this.provider.create(params);\n this.logger?.debug(`Created new agent: ${agentId}`);\n } else {\n // If provider doesn't support create, we need to throw\n // The provider must support creating agents for sessions.new()\n throw new Error('Provider does not support creating agents. Use sessions.load() with an existing sessionId.');\n }\n\n // Step 2: Connect to agent\n const connection = await this.provider.connect(agentId);\n this.logger?.debug(`Connected to agent: ${agentId}`);\n\n // Step 3: Create session via ACP\n const response = await connection.createSession({\n cwd: params.cwd,\n mcpServers: params.mcpServers\n });\n\n // Step 4: Register session mapping (for LocalAgentProvider to support loadSession)\n if (this.provider.registerSession) {\n this.provider.registerSession(response.sessionId, agentId);\n this.logger?.debug(`Registered session mapping: ${response.sessionId} → ${agentId}`);\n }\n\n // Step 5: Create and return ActiveSession\n // Get connectionInfo from CloudAgentConnection if available\n const connectionInfo = (connection as any).sessionConnectionInfo;\n\n const session = new ActiveSessionImpl(\n response.sessionId,\n agentId,\n connection,\n {\n logger: this.logger,\n // Bind sessionId (not agentId) to create a getter function for filesystem\n // Note: conversation-channel-router binds sessionId to windowId,\n // so we must use sessionId for filesystem routing\n getFilesystem: this.provider.filesystem\n ? () => this.provider.filesystem!.getFilesystem(response.sessionId)\n : undefined,\n // Pass connectionInfo from CloudAgentConnection (if available)\n connectionInfo\n }\n );\n\n // Set modes from response\n session.setModes(\n response.modes?.availableModes,\n response.modes?.currentModeId\n );\n\n this.logger?.info(`Session created: ${response.sessionId}`);\n return session;\n }\n\n /**\n * Load an existing session\n *\n * Steps:\n * 1. Check cache for existing session\n * 2. Find agent by sessionId (sessionId === agentId in current design)\n * 3. Connect to agent\n * 4. Call ACP loadSession\n * 5. Return ActiveSession instance (cached)\n */\n async loadSession(params: LoadSessionParams): Promise<ActiveSession> {\n this.logger?.info(`Loading session: ${params.sessionId}`);\n\n // Step 2: Find agent by sessionId\n // In current design, sessionId === agentId\n const agentId = params.sessionId;\n\n // Verify agent exists\n const agentState = await this.provider.get(agentId);\n if (!agentState) {\n throw new Error(`Session not found: ${params.sessionId}`);\n }\n\n // Step 3: Connect to agent\n const connection = await this.provider.connect(agentId);\n this.logger?.debug(`Connected to agent: ${agentId}`);\n\n // Step 4: Load session via ACP\n const response = await connection.loadSession({\n sessionId: params.sessionId,\n cwd: agentState.type === 'local' ? agentState.cwd : params.cwd,\n mcpServers: params.mcpServers\n });\n\n // Step 5: Create and return ActiveSession\n // Get connectionInfo from CloudAgentConnection if available\n const connectionInfo = (connection as any).sessionConnectionInfo;\n\n const session = new ActiveSessionImpl(\n params.sessionId,\n agentId,\n connection,\n {\n logger: this.logger,\n // Bind sessionId (not agentId) to create a getter function for filesystem\n // Note: conversation-channel-router binds sessionId to windowId,\n // so we must use sessionId for filesystem routing\n getFilesystem: this.provider.filesystem\n ? () => this.provider.filesystem!.getFilesystem(params.sessionId)\n : undefined,\n // Pass connectionInfo from CloudAgentConnection (if available)\n connectionInfo\n }\n );\n\n // Set modes from response\n session.setModes(\n response.modes?.availableModes,\n response.modes?.currentModeId\n );\n\n this.logger?.info(`Session loaded: ${params.sessionId}`);\n return session;\n }\n}\n","/**\n * AgentClient - Session-centric API\n *\n * Provides a unified entry point for managing sessions.\n * Sessions are the primary API surface; agents are internal implementation.\n */\n\nimport type {\n AgentClientOptions,\n ClientSessionsResource,\n AgentProvider,\n Logger,\n ModelsResource,\n InitializeWorkspaceParams,\n InitializeWorkspaceResponse,\n WorkspaceInfo,\n SessionsResourceEvents,\n SessionsResourceEventHandler,\n ListAgentOptions,\n PickFileParams,\n PickFileResponse,\n PickFolderParams,\n PickFolderResponse,\n UploadFileParams,\n UploadFileResponse,\n SearchFileParams,\n SearchFileResponse\n} from './types.js';\nimport type { ModelInfo } from '../types.js';\nimport { SessionManager } from './session-manager.js';\n\n// ============================================\n// AgentClient - Session-Centric API\n// ============================================\n\n/**\n * AgentClient - Session-centric client\n *\n * Provides a session-centric API that internally manages agents.\n * Users interact with sessions; the agent lifecycle is handled internally.\n *\n * @example\n * ```typescript\n * // Create client with a provider\n * const provider = new CloudAgentProvider({\n * endpoint: 'https://api.example.com',\n * authToken: 'token'\n * });\n *\n * const client = new AgentClient({\n * provider,\n * logger: console\n * });\n *\n * // List all sessions\n * const sessions = await client.sessions.list();\n *\n * // Create new session (auto-creates agent and connects)\n * const session = await client.sessions.create({ cwd: '/workspace' });\n * console.log(session.agentState.status); // agent status\n * console.log(session.agentState.id); // agent ID\n *\n * // Send prompt\n * await session.prompts.send({ content: 'Hello' });\n *\n * // Get available models\n * const models = await client.sessions.models.list('my-repo');\n *\n * // Use 'using' keyword for automatic cleanup\n * {\n * using session = await client.sessions.create({ cwd: '/workspace' });\n * // ... use session\n * } // session automatically disposed\n *\n * // Or manually disconnect\n * session.disconnect();\n *\n * // Load existing session\n * const loadedSession = await client.sessions.load({\n * sessionId: 'xxx',\n * cwd: '/workspace'\n * });\n * ```\n */\nexport class AgentClient {\n private logger?: Logger;\n private provider: AgentProvider;\n private sessionManager: SessionManager;\n\n /**\n * Sessions resource namespace (primary API entry point)\n */\n readonly sessions: ClientSessionsResource;\n\n /**\n * 运行环境类型\n * - 'local': IDE 本地环境\n * - 'cloud': 云端环境\n */\n readonly environmentType: 'local' | 'cloud';\n\n constructor(options: AgentClientOptions) {\n this.logger = options.logger;\n this.provider = options.provider;\n this.environmentType = options.environmentType ?? 'cloud';\n\n // Initialize session manager\n this.sessionManager = new SessionManager({\n provider: this.provider,\n logger: this.logger\n });\n\n // Initialize sessions resource\n this.sessions = this.createSessionsResource();\n }\n\n // ============================================\n // Sessions Resource\n // ============================================\n\n private createSessionsResource(): ClientSessionsResource {\n return {\n list: async (options?: ListAgentOptions) => {\n return this.sessionManager.listSessions(options);\n },\n\n create: async (params) => {\n return this.sessionManager.createSession(params);\n },\n\n load: async (params) => {\n console.log('[AgentClient] sessions.load called:', params.sessionId);\n return this.sessionManager.loadSession(params);\n },\n\n archive: async (sessionId: string): Promise<{ id: string }> => {\n this.logger?.debug('AgentClient.sessions.archive called', { sessionId });\n\n try {\n // Check if provider supports archive\n if (this.provider.archive) {\n const result = await this.provider.archive(sessionId);\n this.logger?.info('Session archived successfully', { sessionId });\n return result;\n }\n\n // If provider does not support archive, throw error\n throw new Error('Provider does not support archive method');\n } catch (error) {\n this.logger?.error('Failed to archive session', error);\n throw error;\n }\n },\n\n rename: async (sessionId: string, title: string): Promise<{ id: string }> => {\n this.logger?.debug('AgentClient.sessions.rename called', { sessionId, title });\n\n try {\n // Check if provider supports rename\n if (this.provider.rename) {\n const result = await this.provider.rename(sessionId, title);\n this.logger?.info('Session renamed successfully', { sessionId, title });\n return result;\n }\n\n // If provider does not support rename, throw error\n throw new Error('Provider does not support rename method');\n } catch (error) {\n this.logger?.error('Failed to rename session', error);\n throw error;\n }\n },\n\n // Initialize workspace for future sessions\n initializeWorkspace: async (params: InitializeWorkspaceParams): Promise<InitializeWorkspaceResponse> => {\n this.logger?.debug('AgentClient.sessions.initializeWorkspace called', params);\n\n try {\n // openWorkspace 是 LocalAgentProvider 特有的能力\n if (this.provider.openWorkspace) {\n const result = await this.provider.openWorkspace(params);\n this.logger?.info('Workspace opened successfully', { cwd: params.cwd });\n return result;\n }\n\n // 如果 provider 不支持 openWorkspace,返回成功(向后兼容)\n this.logger?.warn('Provider does not support openWorkspace');\n return { success: true };\n\n } catch (error) {\n this.logger?.error('Failed to initialize workspace', error);\n return {\n success: false,\n error: error instanceof Error ? error.message : 'Unknown error'\n };\n }\n },\n\n // Get current workspaces list\n getCurrentWorkspaces: async (filter?: { activeOnly?: boolean }): Promise<WorkspaceInfo[]> => {\n this.logger?.debug('AgentClient.sessions.getCurrentWorkspaces called', filter);\n\n try {\n // getCurrentWorkspaces 是 LocalAgentProvider 特有的能力\n if ('getCurrentWorkspaces' in this.provider && typeof this.provider.getCurrentWorkspaces === 'function') {\n const result = await this.provider.getCurrentWorkspaces(filter);\n this.logger?.info('Current workspaces retrieved', { count: result.length });\n return result;\n }\n\n // 如果 provider 不支持 getCurrentWorkspaces,返回空数组(向后兼容)\n this.logger?.warn('Provider does not support getCurrentWorkspaces');\n return [];\n\n } catch (error) {\n this.logger?.error('Failed to get current workspaces', error);\n return [];\n }\n },\n\n\n // Event methods - forward to provider if supported\n on: <K extends keyof SessionsResourceEvents>(\n event: K,\n handler: SessionsResourceEventHandler<K>\n ): void => {\n if (this.provider.on) {\n this.provider.on(event as string, handler as (...args: any[]) => void);\n } else {\n this.logger?.warn(`Provider does not support event registration: ${String(event)}`);\n }\n },\n\n off: <K extends keyof SessionsResourceEvents>(\n event: K,\n handler: SessionsResourceEventHandler<K>\n ): void => {\n if (this.provider.off) {\n this.provider.off(event as string, handler as (...args: any[]) => void);\n } else {\n this.logger?.warn(`Provider does not support event unregistration: ${String(event)}`);\n }\n },\n \n openWorkspace: async (params: InitializeWorkspaceParams): Promise<InitializeWorkspaceResponse> => {\n try {\n if (this.provider && this.provider.openWorkspace) {\n const result = await this.provider.openWorkspace(params);\n this.logger?.info('Workspace opened successfully', { cwd: params.cwd });\n return result;\n }\n return { success: false, error: 'Provider does not support openWorkspace' };\n } catch (error) {\n this.logger?.error('Failed to open workspace', error);\n return {\n success: false,\n error: error instanceof Error ? error.message : 'Unknown error'\n };\n }\n },\n\n pickFile: async (params?: PickFileParams): Promise<PickFileResponse> => {\n try {\n if (this.provider && this.provider.pickFile) {\n const result = await this.provider.pickFile(params);\n this.logger?.info('File picker completed', { fileCount: result.files.length, canceled: result.canceled });\n return result;\n }\n return { files: [], canceled: true, error: 'Provider does not support pickFile' };\n } catch (error) {\n this.logger?.error('Failed to pick file', error);\n return {\n files: [],\n canceled: true,\n error: error instanceof Error ? error.message : 'Unknown error'\n };\n }\n },\n\n pickFolder: async (params?: PickFolderParams): Promise<PickFolderResponse> => {\n try {\n if (this.provider && this.provider.pickFolder) {\n const result = await this.provider.pickFolder(params);\n this.logger?.info('Folder picker completed', { folderPaths: result.folderPaths, canceled: result.canceled });\n return result;\n }\n return { folderPaths: [], canceled: true, error: 'Provider does not support pickFolder' };\n } catch (error) {\n this.logger?.error('Failed to pick folder', error);\n return {\n folderPaths: [],\n canceled: true,\n error: error instanceof Error ? error.message : 'Unknown error'\n };\n }\n },\n\n uploadFile: async (params: UploadFileParams): Promise<UploadFileResponse> => {\n try {\n if (this.provider && this.provider.uploadFile) {\n const result = await this.provider.uploadFile(params);\n this.logger?.info('File upload completed', { count: params.files.length, success: result.success });\n return result;\n }\n return { success: false, error: 'Provider does not support uploadFile' };\n } catch (error) {\n this.logger?.error('Failed to upload file', error);\n return {\n success: false,\n error: error instanceof Error ? error.message : 'Unknown error'\n };\n }\n },\n\n searchFile: async (params: SearchFileParams): Promise<SearchFileResponse> => {\n try {\n if (this.provider && this.provider.searchFile) {\n const result = await this.provider.searchFile(params);\n this.logger?.info('File search completed', { resultCount: result.results.length, hasError: !!result.error });\n return result;\n }\n return { results: [], error: 'Provider does not support searchFile' };\n } catch (error) {\n this.logger?.error('Failed to search file', error);\n return {\n results: [],\n error: error instanceof Error ? error.message : 'Unknown error'\n };\n }\n },\n\n // Models resource - delegates to provider's getModels method\n models: this.createModelsResource(),\n };\n }\n\n private createModelsResource(): ModelsResource {\n return {\n list: async (repo: string): Promise<ModelInfo[]> => {\n // Check if provider supports getModels\n if (this.provider.getModels) {\n return this.provider.getModels(repo);\n }\n throw new Error('Provider does not support getModels method');\n }\n };\n }\n\n // ============================================\n // Lifecycle\n // ============================================\n\n /**\n * Dispose the client\n *\n * Note: Active sessions are not automatically disposed.\n * The caller is responsible for disconnecting sessions they created.\n */\n dispose(): void {\n this.logger?.info('AgentClient disposed');\n }\n}\n\nexport default AgentClient;\n","/**\n * API type definitions for AgentClient\n * Session-centric API design\n */\n\nimport type { SessionNotification, RequestPermissionRequest } from '@agentclientprotocol/sdk';\nimport type {\n Artifact,\n ArtifactType,\n ArtifactEvent,\n UsageUpdate,\n ClientEvents,\n EventListener,\n CheckpointInfo,\n QuestionRequest,\n QuestionAnswers\n} from '@genie/agent-client-protocol';\nimport type {\n Agent as AgentInfo,\n AgentConnection,\n AgentStatus,\n Session,\n SessionMode,\n PromptParams,\n PromptContentBlock,\n AgentCapabilities,\n ClientCapabilities,\n ArtifactTypeConfig,\n ArtifactsConfig,\n CodebuddyClientMeta,\n CodebuddyAgentMeta,\n FilesResource,\n FilesystemProvider,\n McpServerConfig,\n E2BSandboxConnectionInfo,\n // e2b SDK types (re-exported from types.js)\n EntryInfo,\n Filesystem,\n // Model types\n ModelInfo\n} from '../types.js';\nimport type { AvailableCommand } from '../providers/local-agent-provider/acp/types.js';\n\n// Re-export commonly used types\nexport type {\n AgentInfo,\n AgentConnection,\n AgentStatus,\n Session,\n SessionMode,\n PromptParams,\n PromptContentBlock,\n AgentCapabilities,\n ClientCapabilities,\n // codebuddy.ai extension types\n ArtifactTypeConfig,\n ArtifactsConfig,\n CodebuddyClientMeta,\n CodebuddyAgentMeta,\n // Other types\n Artifact,\n ArtifactType,\n ArtifactEvent,\n UsageUpdate,\n ClientEvents,\n EventListener,\n SessionNotification,\n RequestPermissionRequest,\n QuestionRequest,\n QuestionAnswers,\n // Filesystem types\n FilesResource,\n FilesystemProvider,\n McpServerConfig,\n E2BSandboxConnectionInfo,\n // e2b SDK types (re-exported from types.js)\n EntryInfo,\n Filesystem,\n // Model types\n ModelInfo,\n // ACP types\n AvailableCommand\n};\n\n\n// ============================================\n// Session Connection Info (for cloud sessions)\n// ============================================\n\n/**\n * Session connection information\n * 包含连接到Agent会话所需的所有信息,包括sandbox连接凭证\n */\nexport interface SessionConnectionInfo {\n /** Session ID */\n sessionId: string;\n /** Agent ID */\n agentId: string;\n /** Session endpoint URL (Agent的WebSocket/HTTP端点) */\n link: string;\n /** Session token (JWT格式的认证令牌) */\n token: string;\n /** Sandbox ID (E2B沙箱的唯一标识) */\n sandboxId: string;\n /** Session expiration timestamp (unix timestamp) */\n expireAt: number;\n}\n\n// ============================================\n// Agent State (Unified agent state object)\n// ============================================\n\n/**\n * Agent 来源类型\n */\nexport type AgentStateType = 'local' | 'cloud';\n\n/**\n * 云端 Agent 可见性\n */\nexport type CloudAgentVisibility = 'PRIVATE' | 'PUBLIC' | 'TEAM';\n\n/**\n * 云端 Agent 来源信息\n */\nexport interface CloudAgentSourceInfo {\n /** 提供商: github, gitlab 等 */\n provider: string;\n /** 分支/引用 */\n ref: string;\n /** 仓库路径 */\n repository: string;\n}\n\n/**\n * 云端 Agent 目标信息\n */\nexport interface CloudAgentTarget {\n /** 是否自动创建 PR */\n autoCreatePr: boolean;\n /** 分支名称 */\n branchName?: string;\n /** PR URL */\n prUrl?: string;\n /** Agent URL */\n url?: string;\n}\n\n/**\n * AgentState 基础接口\n * 所有类型的 AgentState 都必须实现此接口\n */\nexport interface BaseAgentState {\n /** Unique agent ID */\n id: string;\n /** Display name */\n name?: string;\n /** Description */\n description?: string;\n /** Agent type */\n type: AgentStateType;\n /** Current connection status */\n status: AgentStatus;\n /** Agent capabilities (available after connection) */\n capabilities?: AgentCapabilities;\n /** When the agent was created */\n createdAt?: Date;\n /** When the agent was last updated */\n updatedAt?: Date;\n}\n\n/**\n * LocalAgentState - 本地 Agent 状态\n * 来自本地 IPC 通信的 Agent\n */\nexport interface LocalAgentState extends BaseAgentState {\n type: 'local';\n /** 工作目录 */\n cwd: string;\n}\n\n/**\n * CloudAgentState - 云端 Agent 状态\n * 来自远程 API 的云端实例\n */\nexport interface CloudAgentState extends BaseAgentState {\n type: 'cloud';\n}\n\n/**\n * AgentState - Unified agent state object exposed to client users\n *\n * This is the primary way clients access agent information.\n * Uses discriminated union pattern to distinguish between local and cloud agents.\n */\nexport type AgentState = LocalAgentState | CloudAgentState;\n\n/**\n * 类型守卫:判断是否为 LocalAgentState\n */\nexport function isLocalAgentState(state: AgentState): state is LocalAgentState {\n return state.type === 'local';\n}\n\n/**\n * 类型守卫:判断是否为 CloudAgentState\n */\nexport function isCloudAgentState(state: AgentState): state is CloudAgentState {\n return state.type === 'cloud';\n}\n\n/**\n * Logger interface\n */\nexport interface Logger {\n debug(message: string, ...args: unknown[]): void;\n info(message: string, ...args: unknown[]): void;\n warn(message: string, ...args: unknown[]): void;\n error(message: string, ...args: unknown[]): void;\n}\n\n// ============================================\n// Agent List Query Options\n// ============================================\n\n/**\n * Filter condition for listing agents\n */\nexport interface ListAgentFilter {\n /** Filter field name (e.g., 'status', 'name') */\n field: string;\n /** Filter value (comma-separated for multiple values) */\n value: string;\n}\n\n/**\n * Sort options for listing agents\n */\nexport interface ListAgentSort {\n /** Sort field (e.g., 'createdAt', 'status') */\n orderBy: string;\n /** Sort direction */\n order?: 'asc' | 'desc';\n}\n\n/**\n * Query options for listing agents\n *\n * These options are supported by both CloudAgentProvider and LocalAgentProvider.\n * Cloud: Server-side filtering, sorting, and pagination\n * Local: Client-side filtering and sorting, no pagination (returns all)\n */\nexport interface ListAgentOptions {\n /**\n * Page number (starts from 1)\n * Cloud: Used for API pagination\n * Local: Ignored (returns all sessions)\n */\n page?: number;\n\n /**\n * Page size\n * Cloud: Number of items per page (default 20, max 100)\n * Local: Ignored (returns all sessions)\n */\n size?: number;\n\n /**\n * Sort options\n * Cloud: Sorts results by specified field and order\n * Local: Sorts results by specified field and order\n */\n sort?: ListAgentSort;\n\n /**\n * Filter conditions\n * Cloud: Filters results by specified field values\n * Local: Filters results by specified field values\n */\n filters?: ListAgentFilter[];\n\n /**\n * Day range filter (e.g., agents created in last N days)\n * Cloud: Filters by creation date\n * Local: Filters by creation date\n */\n dayRange?: number;\n\n /**\n * Title search keyword (matches agent title)\n * Cloud: Server-side search\n * Local: Client-side search\n */\n title?: string;\n}\n\n/**\n * Pagination metadata returned from list operations\n */\nexport interface PaginationInfo {\n /** Current page number (starts from 1) */\n page: number;\n /** Page size */\n size: number;\n /** Total number of items */\n total: number;\n /** Total number of pages */\n totalPages: number;\n /** Whether there is a next page */\n hasNext: boolean;\n /** Whether there is a previous page */\n hasPrev: boolean;\n}\n\n/**\n * Response from list operations that includes pagination\n */\nexport interface ListAgentResult<T = AgentState> {\n /** List of agent states or session info */\n agents: T[];\n /** Pagination information */\n pagination: PaginationInfo;\n}\n\n// ============================================\n// Session-Centric Types\n// ============================================\n\n/**\n * Session information (returned by list, mapped from Agent)\n */\nexport interface SessionInfo {\n /** Session ID (from agent.session) */\n id: string;\n /** Associated agent ID */\n agentId: string;\n /** Agent name */\n name?: string;\n /** Agent status */\n status: AgentStatus;\n /** When the session/agent was created */\n createdAt?: Date;\n /** Last activity timestamp */\n lastActivityAt?: Date;\n /** Working directory (for local agents) */\n cwd?: string;\n}\n\n/**\n * Parameters for creating a new session\n */\nexport interface CreateSessionParams {\n /** Working directory */\n cwd: string;\n /** MCP server configurations */\n mcpServers?: McpServerConfig[];\n}\n\n/**\n * Parameters for loading an existing session\n */\nexport interface LoadSessionParams {\n /** Session ID to load (required) */\n sessionId: string;\n /** Working directory */\n cwd: string;\n /** MCP server configurations */\n mcpServers?: McpServerConfig[];\n}\n\n/**\n * Parameters for initializing a workspace\n */\nexport interface InitializeWorkspaceParams {\n /** Working directory */\n cwd: string;\n /** MCP server configurations */\n mcpServers?: McpServerConfig[];\n /** Whether to activate the workspace window to foreground (default true) */\n needActivated?: boolean;\n}\n\n/**\n * Response for workspace initialization\n */\nexport interface InitializeWorkspaceResponse {\n /** Whether initialization was successful */\n success: boolean;\n /** Error message (if failed) */\n error?: string;\n}\n\n// ============================================\n// Resource Interfaces\n// ============================================\n\n/**\n * Prompts resource interface (ACP verbs)\n * Operations use the current session automatically\n */\nexport interface PromptsResource {\n /** Send a prompt and wait for completion */\n send(params: PromptParams): Promise<PromptResponse>;\n\n /** Stream a prompt (yields session updates) */\n stream(params: PromptParams): AsyncIterable<SessionNotification>;\n\n /** Cancel an ongoing prompt */\n cancel(): Promise<void>;\n}\n\n/**\n * Artifacts resource interface\n */\nexport interface ArtifactsResource {\n /** List all artifacts */\n list(params?: { type?: ArtifactType }): Promise<Artifact[]>;\n\n /** Get a single artifact */\n retrieve(artifactId: string): Promise<Artifact>;\n\n /** Get artifact content */\n content(artifactId: string): Promise<string>;\n}\n\n/**\n * Models resource interface\n */\nexport interface ModelsResource {\n /** Get available models for a repository */\n list(repo: string): Promise<ModelInfo[]>;\n}\n\n// ============================================\n// Response Types\n// ============================================\n\n/**\n * Prompt response\n */\nexport interface PromptResponse {\n /** Stop reason */\n stopReason: 'end_turn' | 'max_tokens' | 'tool_use' | 'cancelled' | 'error';\n /** Response metadata */\n _meta?: Record<string, unknown>;\n}\n\n// ============================================\n// Sessions Resource Events (for ClientSessionsResource)\n// ============================================\n\n/**\n * Sessions resource events for monitoring session list changes\n */\nexport interface SessionsResourceEvents {\n /** Emitted when the sessions list changes (create, delete, update) */\n sessionsChanged: SessionInfo[];\n /** Emitted when a new session is created */\n sessionCreated: SessionInfo;\n /** Emitted when a session is deleted */\n sessionDeleted: { sessionId: string };\n /** Emitted when a session is updated (status change, etc.) */\n sessionUpdated: SessionInfo;\n}\n\n/**\n * Event handler type for sessions resource events\n */\nexport type SessionsResourceEventHandler<K extends keyof SessionsResourceEvents> = (\n data: SessionsResourceEvents[K]\n) => void | Promise<void>;\n\n// ============================================\n// Session Events (for ActiveSession)\n// ============================================\n\n/**\n * Session events for event subscription\n */\nexport interface SessionEvents {\n /** Emitted when session updates occur */\n sessionUpdate: SessionNotification;\n /** Emitted when an artifact is created */\n artifactCreated: Artifact;\n /** Emitted when an artifact is updated */\n artifactUpdated: Artifact;\n /** Emitted when an artifact is deleted */\n artifactDeleted: Artifact;\n /** Emitted when a permission request is received */\n permissionRequest: { requestId: string; params: RequestPermissionRequest };\n /** Emitted when a question request is received (ask_followup_question) */\n questionRequest: { toolCallId: string; request: QuestionRequest };\n /** Emitted when usage data is updated */\n usageUpdate: UsageUpdate;\n /** Emitted when a checkpoint is created */\n checkpointCreated: CheckpointInfo;\n /** Emitted when a checkpoint is updated */\n checkpointUpdated: CheckpointInfo;\n /** Emitted when connected to agent */\n connected: void;\n /** Emitted when disconnected from agent */\n disconnected: void;\n /** Emitted when an error occurs */\n error: Error;\n}\n\n/**\n * Event handler type for session events\n */\nexport type SessionEventHandler<K extends keyof SessionEvents> = (data: SessionEvents[K]) => void | Promise<void>;\n\n// ============================================\n// Active Session Interface\n// ============================================\n\n/**\n * Agent operations (accessed via session.agent)\n */\nexport interface SessionAgentOperations {\n /** Agent ID */\n readonly id: string;\n /** Agent state */\n readonly state: AgentState;\n /** Whether the agent is connected */\n readonly isConnected: boolean;\n /** Agent capabilities */\n readonly capabilities?: AgentCapabilities;\n}\n\n/**\n * Active Session interface\n * Represents an active session with its resources and operations\n *\n * Key design:\n * - Session is the primary API surface\n * - agentState provides direct access to underlying agent state\n * - disconnect() is called directly on session (not session.agent)\n */\nexport interface ActiveSession {\n /** Session ID */\n readonly id: string;\n /** Agent ID */\n readonly agentId: string;\n /** Agent state (direct access to underlying agent state) */\n readonly agentState: AgentState;\n /** Agent capabilities (available after connection) */\n readonly capabilities?: AgentCapabilities;\n /** Available session modes */\n readonly availableModes?: SessionMode[];\n /** Current session mode */\n readonly currentMode?: string;\n /** Available slash commands (updated via available_commands_update) */\n readonly availableCommands: AvailableCommand[];\n /** Whether the session is active */\n readonly isActive: boolean;\n /**\n * Session connection information (only available for cloud sessions)\n * 会话连接信息,包括sandboxId、link、token等\n */\n readonly connectionInfo?: SessionConnectionInfo;\n\n // Agent operations namespace (optional agent-level access)\n /** Agent operations */\n readonly agent: SessionAgentOperations;\n\n // ACP Resources\n /** Prompts resource */\n readonly prompts: PromptsResource;\n /** Artifacts resource */\n readonly artifacts: ArtifactsResource;\n /** Files resource */\n readonly files: FilesResource;\n\n // Permission management\n /** Resolve a permission request */\n resolvePermission(requestId: string, optionId: string): boolean;\n /** Reject a permission request */\n rejectPermission(requestId: string, reason?: string): boolean;\n\n // Question management (ask_followup_question)\n /** Answer a question request with user's selections */\n answerQuestion(toolCallId: string, answers: QuestionAnswers): boolean;\n /** Cancel a question request */\n cancelQuestion(toolCallId: string, reason?: string): boolean;\n\n // Tool callback management\n /** Callback for tool operations (skip or cancel) */\n toolCallback(toolCallId: string, toolName: string, action: 'skip' | 'cancel'): Promise<{ success: boolean; error?: string }>;\n\n // Session mode management\n /** Set the current session mode */\n setMode(modeId: string): Promise<void>;\n /** Set the current session model */\n setSessionModel(modelId: string): Promise<void>;\n\n // Event subscription\n /** Subscribe to an event */\n on<K extends keyof SessionEvents>(event: K, handler: SessionEventHandler<K>): this;\n /** Unsubscribe from an event */\n off<K extends keyof SessionEvents>(event: K, handler: SessionEventHandler<K>): this;\n /** Subscribe to an event once */\n once<K extends keyof SessionEvents>(event: K, handler: SessionEventHandler<K>): this;\n\n // Lifecycle - disconnect directly on session\n /** Disconnect from the session/agent */\n disconnect(): void;\n\n /** Symbol.dispose for 'using' keyword support */\n [Symbol.dispose](): void;\n}\n\n// ============================================\n// Provider & Client Types\n// ============================================\n\n/**\n * 环境类型\n */\nexport type EnvironmentType = 'local' | 'cloud';\n\n/**\n * Agent provider interface\n *\n * Responsible for:\n * - Managing agent state/configuration storage\n * - Creating connections to agents\n * - Abstracting away transport details (cloud/local)\n *\n * The provider.connect() method returns an AgentConnection.\n * The client wraps the connection in an ActiveSession instance.\n *\n * @typeParam C - Connection type used by this provider (e.g., CloudAgentConnection, LocalAgentConnection)\n */\nexport interface AgentProvider<C extends AgentConnection = AgentConnection> {\n /**\n * Create a new agent and return its ID\n *\n * @param params - Optional session params (used by LocalAgentProvider to get cwd)\n * @returns Agent ID (Cloud: UUID, Local: cwd)\n */\n create?(params?: CreateSessionParams): Promise<string>;\n /** Get agent state by ID */\n get(agentId: string): Promise<AgentState | undefined>;\n\n /**\n * List all agent states with pagination information\n *\n * @param options - Optional query parameters for filtering, sorting, and pagination\n * Cloud providers use these for API queries and return server pagination\n * Local providers apply client-side filtering and return synthetic pagination\n * @returns Object containing agents array and pagination info\n */\n list(options?: ListAgentOptions): Promise<ListAgentResult<AgentState>>;\n\n /** Connect to an agent and return the connection */\n connect(agentId: string): Promise<C>;\n /** Delete an agent by ID */\n delete(agentId: string): Promise<boolean>;\n\n /**\n * Archive an agent by ID (optional)\n * Used by CloudAgentProvider for archiving agents\n *\n * @param agentId - Agent ID to archive\n * @returns Object containing the archived agent ID\n */\n archive?(agentId: string): Promise<{ id: string }>;\n\n /**\n * Rename an agent by ID (optional)\n * Used by CloudAgentProvider and LocalAgentProvider for renaming agents\n *\n * @param agentId - Agent ID to rename\n * @param title - New title for the agent\n * @returns Object containing the renamed agent ID\n */\n rename?(agentId: string, title: string): Promise<{ id: string }>;\n\n /** Filesystem provider (optional - some providers may not support filesystem operations) */\n readonly filesystem?: FilesystemProvider;\n\n /**\n * Get available models for a repository (optional)\n * Implementation varies by provider type\n * @param repo - Repository identifier\n * @returns Array of model information\n */\n getModels?(repo: string): Promise<ModelInfo[]>;\n\n /**\n * Register sessionId → agentId mapping (optional, used by LocalAgentProvider)\n * Called after session creation to maintain the mapping for loadSession\n *\n * @param sessionId - Session ID returned by connection.createSession()\n * @param agentId - Agent ID (cwd for Local)\n */\n registerSession?(sessionId: string, agentId: string): void;\n\n /**\n * Open a workspace window (optional, used by LocalAgentProvider)\n *\n * @param params - Workspace params including cwd\n * @returns Response with success status\n */\n openWorkspace?(params: InitializeWorkspaceParams): Promise<InitializeWorkspaceResponse>;\n\n /**\n * Pick files from file dialog (optional, used by LocalAgentProvider)\n *\n * @param params - File picker params including filters\n * @returns Response with file paths and cancel status\n */\n pickFile?(params?: PickFileParams): Promise<PickFileResponse>;\n\n /**\n * Pick folders from folder dialog (optional, used by LocalAgentProvider)\n *\n * @param params - Folder picker params\n * @returns Response with folder paths and cancel status\n */\n pickFolder?(params?: PickFolderParams): Promise<PickFolderResponse>;\n\n /**\n * Upload a file to cloud storage (optional)\n *\n * @param params - Upload parameters including file content\n * @returns Response with cloud URL after successful upload\n */\n uploadFile?(params: UploadFileParams): Promise<UploadFileResponse>;\n\n /**\n * Search for files in the workspace (optional, used by LocalAgentProvider)\n *\n * @param params - Search parameters including options\n * @returns Response with search results\n */\n searchFile?(params: SearchFileParams): Promise<SearchFileResponse>;\n\n /**\n * Register an event listener\n * Provider implementations should forward events to the underlying transport\n *\n * @param event - Event name\n * @param handler - Event handler function\n */\n on?(event: string, handler: (...args: any[]) => void): void;\n\n /**\n * Unregister an event listener\n *\n * @param event - Event name\n * @param handler - Event handler function to remove\n */\n off?(event: string, handler: (...args: any[]) => void): void;\n}\n\n/**\n * AgentClient initialization options\n */\nexport interface AgentClientOptions {\n /** Agent provider (required) */\n provider: AgentProvider;\n /** Logger instance */\n logger?: Logger;\n /** Client capabilities (sent during initialization) */\n clientCapabilities?: ClientCapabilities;\n /**\n * 运行环境类型\n * - 'local': IDE 本地环境\n * - 'cloud': 云端环境\n */\n environmentType?: EnvironmentType;\n}\n\n/**\n * Client sessions resource interface\n * Top-level API for session management\n *\n * Key design:\n * - list() returns sessions with pagination info (mapped from agents)\n * - create() creates a new session (auto-creates agent and connects)\n * - load() loads an existing session (finds agent by sessionId and connects)\n * - archive() archives a session/agent\n * - initializeWorkspace() initializes a workspace for future sessions\n */\nexport interface ClientSessionsResource {\n /**\n * List all sessions with pagination info\n * Cloud: Returns server-side filtered/sorted/paginated results\n * Local: Returns client-side filtered/sorted results (synthetic pagination)\n */\n list(options?: ListAgentOptions): Promise<ListAgentResult<SessionInfo>>;\n\n /** Create a new session (auto-creates agent and connects) */\n create(params: CreateSessionParams): Promise<ActiveSession>;\n\n /** Load an existing session (finds agent by sessionId and connects) */\n load(params: LoadSessionParams): Promise<ActiveSession>;\n\n /**\n * Archive a session/agent\n * @param sessionId - Session ID to archive\n * @returns Object containing the archived session ID\n */\n archive(sessionId: string): Promise<{ id: string }>;\n\n /**\n * Rename a session/agent\n * @param sessionId - Session ID to rename\n * @param title - New title for the session\n * @returns Object containing the renamed session ID\n */\n rename(sessionId: string, title: string): Promise<{ id: string }>;\n\n /** Initialize a workspace for future sessions */\n initializeWorkspace(params: InitializeWorkspaceParams): Promise<InitializeWorkspaceResponse>;\n\n /** Models resource for getting available models */\n readonly models: ModelsResource;\n\n /** Get current workspaces list */\n getCurrentWorkspaces(filter?: { activeOnly?: boolean }): Promise<WorkspaceInfo[]>;\n\n // Event subscription for sessions list changes\n /** Subscribe to sessions resource events */\n on<K extends keyof SessionsResourceEvents>(\n event: K,\n handler: SessionsResourceEventHandler<K>\n ): void;\n\n /** Unsubscribe from sessions resource events */\n off<K extends keyof SessionsResourceEvents>(\n event: K,\n handler: SessionsResourceEventHandler<K>\n ): void;\n\n /** Open a workspace (for LocalAgentProvider) */\n openWorkspace(params: InitializeWorkspaceParams): Promise<InitializeWorkspaceResponse>;\n\n /** Pick files from file dialog (for LocalAgentProvider) */\n pickFile(params?: PickFileParams): Promise<PickFileResponse>;\n\n /** Pick folders from folder dialog (for LocalAgentProvider) */\n pickFolder(params?: PickFolderParams): Promise<PickFolderResponse>;\n\n /** Upload a file to cloud storage */\n uploadFile(params: UploadFileParams): Promise<UploadFileResponse>;\n\n /** Search for files in the workspace (for LocalAgentProvider) */\n searchFile(params: SearchFileParams): Promise<SearchFileResponse>;\n\n}\n\n// ============================================\n// Workspace Types\n// ============================================\n\n/**\n * Workspace information (aligned with FolderSelectResult)\n */\nexport interface WorkspaceInfo {\n /** Folder path */\n path: string;\n /** Folder display name */\n label: string;\n}\n\n// ============================================\n// File Picker Types\n// ============================================\n\n/**\n * File filter for pickFile dialog\n */\nexport interface FileFilter {\n /** Display name for the filter */\n readonly name: string;\n /** File extensions (without dot) */\n readonly extensions: string[];\n}\n\n/**\n * Parameters for picking files\n */\nexport interface PickFileParams {\n /** Default path for the dialog */\n readonly defaultPath?: string;\n /** File type filters */\n readonly filters?: FileFilter[];\n /** Whether to allow multiple selection (default false) */\n readonly canSelectMany?: boolean;\n}\n\n/**\n * Response from picking files\n */\nexport interface PickFileResponse {\n /** Selected files - File objects in browser, absolute path strings in IDE */\n readonly files: Array<File | string>;\n /** Whether user cancelled the dialog */\n readonly canceled: boolean;\n /** Error message (if failed) */\n readonly error?: string;\n}\n\n// ============================================\n// Folder Picker Types\n// ============================================\n\n/**\n * Parameters for picking folders\n */\nexport interface PickFolderParams {\n /** Default path for the dialog */\n readonly defaultPath?: string;\n}\n\n/**\n * Response from picking folders\n */\nexport interface PickFolderResponse {\n /** Selected folder paths */\n readonly folderPaths: string[];\n /** Whether user cancelled the dialog */\n readonly canceled: boolean;\n /** Error message (if failed) */\n readonly error?: string;\n}\n\n// ============================================\n// File Upload Types\n// ============================================\n\n/**\n * Parameters for uploading files\n */\nexport interface UploadFileParams {\n /** Files to upload - File objects in browser, absolute path strings in IDE */\n readonly files: Array<File | string>;\n}\n\n/**\n * Response from uploading files\n */\nexport interface UploadFileResponse {\n /** Whether upload was successful */\n readonly success: boolean;\n /** Cloud URLs corresponding to each uploaded file (same order as input files) */\n readonly urls?: string[];\n /** Error message (if upload failed) */\n readonly error?: string;\n}\n\n// ============================================\n// File Search Types\n// ============================================\n\n/**\n * Mention type for file/folder\n */\nexport enum MentionType {\n file = 'file',\n folder = 'folder'\n}\n\n/**\n * Search options for file search\n */\nexport interface SearchOptions {\n /** Search keyword */\n readonly search?: string;\n /** Number of results to return */\n readonly resultNum: number;\n}\n\n/**\n * File search result\n */\nexport interface SearchFileResult {\n /** Full path */\n path: string;\n /** Relative path */\n relativePath: string;\n /** File name */\n fileName?: string;\n /** Folder name */\n folderName?: string;\n /** Type (file or folder) */\n type: MentionType.file | MentionType.folder;\n}\n\n/**\n * Parameters for searching files\n */\nexport interface SearchFileParams {\n /** Search options */\n readonly options: SearchOptions;\n}\n\n/**\n * Response from searching files\n */\nexport interface SearchFileResponse {\n /** Search results */\n readonly results: SearchFileResult[];\n /** Error message (if failed) */\n readonly error?: string;\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"index.cjs","names":["ClientSideConnection","PROTOCOL_VERSION","Sandbox"],"sources":["../../agent-client-protocol/src/common/types.ts","../../agent-client-protocol/src/common/transport/streamable-http.ts","../../agent-client-protocol/src/common/client/constants.ts","../../agent-client-protocol/src/common/client/errors.ts","../../agent-client-protocol/src/common/client/events.ts","../../agent-client-protocol/src/common/client/artifacts.ts","../../agent-client-protocol/src/common/client/permissions.ts","../../agent-client-protocol/src/common/client/questions.ts","../../agent-client-protocol/src/common/client/extensions.ts","../../agent-client-protocol/src/common/client/client.ts","../../agent-provider/src/common/providers/cloud-agent-provider/cloud-connection.ts","../../agent-provider/src/common/providers/cloud-agent-provider/e2b-filesystem.ts","../../agent-provider/src/common/utils/concurrency.ts","../../agent-provider/src/common/providers/cloud-agent-provider/cos-upload-service.ts","../../agent-provider/src/account/account-service.ts","../../agent-provider/src/common/providers/cloud-agent-provider/cloud-provider.ts","../../agent-provider/src/common/providers/local-agent-provider/local-connection.ts","../../agent-provider/src/common/client/session.ts","../../agent-provider/src/common/client/session-manager.ts","../../agent-provider/src/common/client/client.ts","../../agent-provider/src/common/client/types.ts","../../agent-provider/src/backend/types.ts","../../agent-provider/src/backend/backend-provider.ts","../../agent-provider/src/backend/ipc-backend-provider.ts"],"sourcesContent":["/**\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 /** Usage notification for token/cost tracking */\n USAGE: '_codebuddy.ai/usage',\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.USAGE,\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}\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' | 'document' | 'spreadsheet';\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 /** Questions to ask (1-4) */\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// Usage Update Types\n// ============================================\n\n/**\n * Token usage information\n * Sent via extNotification: _codebuddy.ai/usage\n */\nexport interface UsageUpdate {\n sessionId: string;\n inputTokens?: number;\n outputTokens?: number;\n totalTokens?: number;\n cost?: number;\n model?: string;\n _meta?: 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}\n","// Streamable HTTP Transport for ACP\n// Enables browser-based clients to connect to cloud-hosted ACP agents.\n//\n// Protocol flow:\n// 1. Client establishes GET SSE connection, receives Acp-Connection-Id\n// 2. Client sends POST requests with Acp-Connection-Id header\n// 3. Notifications arrive via GET SSE, responses via POST SSE\n\nimport type { Stream } from '@agentclientprotocol/sdk';\n\ntype StreamMessage = Stream extends { readable: ReadableStream<infer T> } ? T : never;\n\nexport interface StreamableHttpOptions {\n // ACP endpoint URL, e.g. 'https://cloud-agent.example.com/acp'\n endpoint: string;\n // Authorization token (sent as Bearer token)\n authToken?: string;\n // Custom headers to include in all requests\n headers?: Record<string, string>;\n // Reconnect options for SSE connections\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, adds ±25% jitter to prevent thundering herd\n };\n // AbortSignal to cancel the connection\n signal?: AbortSignal;\n // Custom fetch implementation (for testing or non-browser environments)\n fetch?: typeof fetch;\n // Callback when connection is established\n onConnect?: (connectionId: string) => void;\n // Callback when connection is closed\n onDisconnect?: (connectionId: string) => void;\n // Callback when an error occurs\n onError?: (error: Error) => void;\n // Heartbeat timeout in ms (default: 60000). If no heartbeat received within this time, reconnect.\n // Set to 0 to disable heartbeat detection.\n heartbeatTimeout?: number;\n // POST request timeout in ms (default: 30000)\n postTimeout?: number;\n // Backpressure options for message queue\n backpressure?: {\n highWaterMark?: number; // default: 100, pause reading SSE when queue reaches this\n lowWaterMark?: number; // default: 50, resume reading SSE when queue drops to this\n };\n}\n\n/**\n * Extended Stream interface with connection management\n */\nexport interface StreamableHttpTransport extends Stream {\n /**\n * Current connection ID, undefined if not connected\n */\n readonly connectionId: string | undefined;\n /**\n * Promise that resolves when the SSE connection is established\n * and the connectionId is available. Callers should await this\n * before sending messages to ensure the transport is ready.\n */\n readonly ready: Promise<void>;\n /**\n * Close the connection gracefully (sends DELETE request)\n */\n close(): Promise<void>;\n}\n\ninterface SSEEvent {\n type: string;\n data: string;\n id?: string;\n}\n\nfunction parseSSELine(\n line: string,\n currentEvent: Partial<SSEEvent>\n): { event?: SSEEvent; reset: boolean; isComment: boolean } {\n if (line === '') {\n if (currentEvent.data) {\n return {\n event: {\n type: currentEvent.type || 'message',\n data: currentEvent.data,\n id: currentEvent.id,\n },\n reset: true,\n isComment: false,\n };\n }\n return { reset: true, isComment: false };\n }\n\n // SSE comments (including heartbeats) start with ':'\n if (line.startsWith(':')) {\n return { reset: false, isComment: true };\n }\n\n const colonIndex = line.indexOf(':');\n if (colonIndex === -1) {\n return { reset: false, isComment: false };\n }\n\n const field = line.slice(0, colonIndex);\n let value = line.slice(colonIndex + 1);\n if (value.startsWith(' ')) {\n value = value.slice(1);\n }\n\n switch (field) {\n case 'event':\n // Reset data when starting a new event type\n // This prevents data from previous events being concatenated\n if (currentEvent.type && currentEvent.type !== value) {\n currentEvent.data = undefined;\n }\n currentEvent.type = value;\n break;\n case 'data':\n currentEvent.data = (currentEvent.data || '') + value;\n break;\n case 'id':\n currentEvent.id = value;\n break;\n }\n\n return { reset: false, isComment: false };\n}\n\n// Create a Streamable HTTP transport.\n//\n// Example:\n// const transport = streamableHttp({\n// endpoint: 'https://agent.example.com/acp',\n// authToken: 'token123',\n// onConnect: (id) => console.log('Connected:', id),\n// onDisconnect: (id) => console.log('Disconnected:', id),\n// });\n//\n// // Later, close gracefully\n// await transport.close();\nexport function streamableHttp(options: StreamableHttpOptions): 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 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 } = backpressure;\n\n // Connection state\n let connectionId: string | undefined;\n let lastEventId: string | undefined;\n let reconnectAttempts = 0;\n let closed = false;\n let isClosing = false;\n\n // Promise that resolves when GET SSE is connected and we have connectionId\n let connectionReady: Promise<void>;\n let resolveConnection: () => void;\n let rejectConnection: (error: Error) => void;\n\n // Connection version to track reconnections\n let connectionVersion = 0;\n\n connectionReady = new Promise((resolve, reject) => {\n resolveConnection = resolve;\n rejectConnection = reject;\n });\n\n const abortController = new AbortController();\n\n // Combine signals - use manual approach for broader compatibility\n function isAborted(): boolean {\n return abortController.signal.aborted || (externalSignal?.aborted ?? false);\n }\n\n function getSignal(): AbortSignal {\n // AbortSignal.any is available in newer Node.js versions\n const anyFn = (AbortSignal as unknown as { any?: (signals: AbortSignal[]) => AbortSignal }).any;\n if (externalSignal && typeof anyFn === 'function') {\n return anyFn([externalSignal, abortController.signal]);\n }\n return abortController.signal;\n }\n\n const combinedSignal = getSignal();\n\n // Message queue for incoming messages with backpressure\n const messageQueue: StreamMessage[] = [];\n const messageResolvers: Array<(value: StreamMessage | null) => void> = [];\n let streamError: Error | null = null;\n let isPaused = false;\n let resumeReading: (() => void) | null = null;\n\n // Heartbeat tracking\n let lastActivity = Date.now();\n let heartbeatCheckTimer: ReturnType<typeof setInterval> | undefined;\n\n function enqueueMessage(message: StreamMessage): boolean {\n if (messageResolvers.length > 0) {\n const resolver = messageResolvers.shift()!;\n resolver(message);\n return true;\n } else {\n messageQueue.push(message);\n // Check if we should pause reading due to backpressure\n if (messageQueue.length >= highWaterMark) {\n isPaused = true;\n return false;\n }\n return true;\n }\n }\n\n function dequeueMessage(): Promise<StreamMessage | null> {\n if (closed) {\n return Promise.resolve(null);\n }\n if (streamError) {\n return Promise.reject(streamError);\n }\n if (messageQueue.length > 0) {\n const message = messageQueue.shift()!;\n // Check if we should resume reading\n if (isPaused && messageQueue.length <= lowWaterMark) {\n isPaused = false;\n resumeReading?.();\n }\n return Promise.resolve(message);\n }\n return new Promise((resolve) => {\n messageResolvers.push(resolve);\n });\n }\n\n function updateLastActivity(): void {\n lastActivity = Date.now();\n }\n\n function startHeartbeatCheck(triggerReconnect: () => void): void {\n if (heartbeatTimeout <= 0) {\n return;\n }\n // Check heartbeat every 10 seconds\n heartbeatCheckTimer = setInterval(() => {\n if (Date.now() - lastActivity > heartbeatTimeout) {\n console.warn('[StreamableHTTP] Heartbeat timeout, triggering reconnect');\n triggerReconnect();\n }\n }, 10000);\n }\n\n function stopHeartbeatCheck(): void {\n if (heartbeatCheckTimer) {\n clearInterval(heartbeatCheckTimer);\n heartbeatCheckTimer = undefined;\n }\n }\n\n /**\n * Calculate reconnect delay with optional jitter\n */\n function calculateDelay(attempt: number): number {\n const baseDelay = Math.min(initialDelay * Math.pow(2, attempt - 1), maxDelay);\n if (!jitterEnabled) {\n return baseDelay;\n }\n // Add ±25% jitter to prevent thundering herd\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 // Resume any paused reading\n if (resumeReading) {\n resumeReading();\n resumeReading = null;\n }\n rejectConnection(error);\n onError?.(error);\n while (messageResolvers.length > 0) {\n const resolver = messageResolvers.shift()!;\n resolver(null);\n }\n }\n\n function closeNormally(): void {\n closed = true;\n stopHeartbeatCheck();\n // Resume any paused reading\n if (resumeReading) {\n resumeReading();\n resumeReading = null;\n }\n while (messageResolvers.length > 0) {\n const resolver = messageResolvers.shift()!;\n resolver(null);\n }\n }\n\n // Send DELETE request to close connection gracefully\n async function sendDelete(): Promise<void> {\n if (!connectionId || isClosing) {\n return;\n }\n\n isClosing = true;\n const currentConnectionId = connectionId;\n\n try {\n const headers = buildHeaders();\n headers['Acp-Connection-Id'] = currentConnectionId;\n\n await customFetch(endpoint, {\n method: 'DELETE',\n headers,\n signal: AbortSignal.timeout(5000), // 5s timeout for DELETE\n });\n } catch {\n // Ignore DELETE errors - connection may already be closed\n } finally {\n if (currentConnectionId) {\n onDisconnect?.(currentConnectionId);\n }\n isClosing = false;\n }\n }\n\n function buildHeaders(): Record<string, string> {\n const headers: Record<string, string> = {\n ...customHeaders,\n };\n\n if (authToken) {\n headers['Authorization'] = `Bearer ${authToken}`;\n }\n\n return headers;\n }\n\n async function processSSEStream(\n reader: ReadableStreamDefaultReader<Uint8Array>\n ): Promise<void> {\n const decoder = new TextDecoder();\n let buffer = '';\n let currentEvent: Partial<SSEEvent> = {};\n\n try {\n while (true) {\n // Check for backpressure - wait if paused\n if (isPaused) {\n await new Promise<void>(resolve => {\n resumeReading = resolve;\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 const { event, reset, isComment } = parseSSELine(line, currentEvent);\n\n // SSE comments (including heartbeats) update last activity\n if (isComment) {\n updateLastActivity();\n continue;\n }\n\n if (event) {\n // Any event means we're receiving data - update activity\n updateLastActivity();\n\n if (event.id) {\n lastEventId = event.id;\n }\n\n // Skip non-message events (like \"connected\")\n if (event.type !== 'message') {\n continue;\n }\n\n try {\n const message = JSON.parse(event.data) as StreamMessage;\n // Only enqueue valid JSON-RPC messages\n if (message && typeof message === 'object' && 'jsonrpc' in message) {\n enqueueMessage(message);\n }\n } catch {\n console.error('[StreamableHTTP] Failed to parse SSE data:', event.data);\n }\n }\n\n if (reset) {\n currentEvent = {};\n }\n }\n }\n } finally {\n reader.releaseLock();\n }\n }\n\n // Establish GET SSE connection and get connectionId\n async function startSSEConnection(): Promise<void> {\n // Track current reader for heartbeat-triggered reconnect\n let currentReader: ReadableStreamDefaultReader<Uint8Array> | null = null;\n\n // Function to trigger reconnect (called from heartbeat timeout)\n const triggerReconnect = (): void => {\n if (currentReader) {\n currentReader.cancel().catch(() => {/* ignore */});\n }\n };\n\n while (!closed && !isAborted()) {\n try {\n const headers = buildHeaders();\n headers['Accept'] = 'text/event-stream';\n\n if (lastEventId) {\n headers['Last-Event-ID'] = lastEventId;\n }\n\n const response = await customFetch(endpoint, {\n method: 'GET',\n headers,\n signal: combinedSignal,\n });\n\n if (!response.ok) {\n throw new Error(`HTTP ${response.status}`);\n }\n\n // Get connection ID from response - MUST have it\n const newConnectionId = response.headers.get('Acp-Connection-Id');\n if (!newConnectionId) {\n throw new Error('Server did not return Acp-Connection-Id header');\n }\n\n // Track previous connection for disconnect callback\n const previousConnectionId = connectionId;\n\n // Update connection state atomically\n connectionVersion++;\n connectionId = newConnectionId;\n resolveConnection();\n\n // Notify callbacks\n if (previousConnectionId && previousConnectionId !== newConnectionId) {\n onDisconnect?.(previousConnectionId);\n }\n onConnect?.(newConnectionId);\n\n reconnectAttempts = 0;\n\n // Reset heartbeat tracking and start heartbeat check\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 // Stop heartbeat check when connection ends\n stopHeartbeatCheck();\n\n // Connection ended\n const endedConnectionId = connectionId;\n connectionId = undefined;\n\n if (!reconnectEnabled || closed) {\n // Not reconnecting - notify disconnect\n if (endedConnectionId) {\n onDisconnect?.(endedConnectionId);\n }\n break;\n }\n\n // Reconnect - create new connectionReady promise BEFORE clearing connectionId\n // so that sendMessage waits for new connection\n connectionReady = new Promise((resolve, reject) => {\n resolveConnection = resolve;\n rejectConnection = reject;\n });\n } catch (error) {\n // Stop heartbeat check on error\n stopHeartbeatCheck();\n currentReader = null;\n\n if (isAborted() || closed) {\n break;\n }\n\n reconnectAttempts++;\n\n if (reconnectAttempts > maxRetries) {\n closeWithError(new Error(`SSE reconnect failed after ${maxRetries} attempts`));\n break;\n }\n\n // Use calculateDelay with jitter\n const delay = calculateDelay(reconnectAttempts);\n\n console.warn(\n `[StreamableHTTP] SSE error, retrying in ${delay}ms (attempt ${reconnectAttempts}):`,\n error\n );\n\n await new Promise((resolve) => setTimeout(resolve, delay));\n }\n }\n }\n\n // Send message via POST\n async function sendMessage(message: StreamMessage): Promise<void> {\n if (closed) {\n throw new Error('Connection is closed');\n }\n\n // Wait for GET SSE to establish and get connectionId\n // Capture version before waiting to detect reconnections\n const versionBeforeWait = connectionVersion;\n await connectionReady;\n\n // Check if reconnection happened while we were waiting\n if (versionBeforeWait !== connectionVersion && versionBeforeWait > 0) {\n // A reconnection happened - wait for new connection\n await connectionReady;\n }\n\n if (!connectionId) {\n throw new Error('No connection ID available');\n }\n\n const headers = buildHeaders();\n headers['Content-Type'] = 'application/json';\n headers['Accept'] = 'application/json, text/event-stream';\n headers['Acp-Connection-Id'] = connectionId;\n\n // Create timeout controller for POST request\n const postController = new AbortController();\n let timeoutId: ReturnType<typeof setTimeout> | undefined;\n\n // Combine with external signal if present\n const postSignal = postTimeout > 0\n ? postController.signal\n : combinedSignal;\n\n if (postTimeout > 0) {\n timeoutId = setTimeout(() => postController.abort(), postTimeout);\n // Also abort if external signal is aborted\n if (externalSignal) {\n externalSignal.addEventListener('abort', () => postController.abort(), { once: true });\n }\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: postSignal,\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 // Handle response based on content type\n const contentType = response.headers.get('Content-Type') || '';\n\n if (contentType.includes('text/event-stream')) {\n const reader = response.body?.getReader();\n if (reader) {\n await processSSEStream(reader);\n }\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 as StreamMessage);\n }\n }\n // 202 responses have no body\n } finally {\n if (timeoutId) {\n clearTimeout(timeoutId);\n }\n }\n }\n\n // Start SSE connection immediately\n startSSEConnection().catch((error) => {\n console.error('[StreamableHTTP] SSE connection error:', error);\n });\n\n const readable = new ReadableStream<StreamMessage>({\n async pull(controller) {\n const message = await dequeueMessage();\n if (message === null) {\n controller.close();\n } else {\n controller.enqueue(message);\n }\n },\n cancel() {\n closeNormally();\n abortController.abort();\n },\n });\n\n const writable = new WritableStream<StreamMessage>({\n async write(message) {\n await sendMessage(message);\n },\n close() {\n closeNormally();\n abortController.abort();\n },\n abort(reason) {\n closeWithError(reason instanceof Error ? reason : new Error(String(reason)));\n abortController.abort();\n },\n });\n\n // Close the connection gracefully\n async function close(): Promise<void> {\n if (closed) {\n return;\n }\n\n // Send DELETE to server first\n await sendDelete();\n\n // Then close locally\n closeNormally();\n abortController.abort();\n }\n\n return {\n readable,\n writable,\n get connectionId() {\n return connectionId;\n },\n get ready() {\n return connectionReady;\n },\n close,\n };\n}\n\nexport default streamableHttp;\n","/**\n * Protocol constants for Streamable HTTP ACP Client\n */\n\nimport type { ClientCapabilities } from '../sdk.js';\nimport { ExtensionMethod, KNOWN_EXTENSIONS } from '../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 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 public readonly cause?: Error;\n\n constructor(message: string, code: string, cause?: Error) {\n super(message);\n this.name = 'ACPClientError';\n this.code = code;\n this.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 constructor(message: string, sessionId?: string, cause?: Error) {\n super(message, 'SESSION_ERROR', cause);\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","/**\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 * Artifact Manager for Streamable HTTP ACP Client\n * Handles artifact notification processing\n */\n\nimport type {\n Artifact,\n ArtifactEvent,\n ArtifactNotificationParams,\n} from '../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 * Permission Manager for Streamable HTTP ACP Client\n * Handles permission requests with timeout support\n */\n\nimport type { RequestPermissionRequest, RequestPermissionResponse } from '@agentclientprotocol/sdk';\nimport type { Logger, PermissionHandler } from './types.js';\nimport { DEFAULT_PERMISSION_TIMEOUT } from './constants.js';\nimport { TimeoutError } from './errors.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 '../types.js';\nimport type { Logger } from './types.js';\nimport { DEFAULT_QUESTION_TIMEOUT } from './constants.js';\nimport { TimeoutError } from './errors.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 * Extension Method Handler for Streamable HTTP ACP Client\n * Routes and handles custom extension notifications\n */\n\nimport type { UsageUpdate } from '../types.js';\nimport type { Logger } from './types.js';\nimport { ExtensionMethod, KNOWN_EXTENSIONS } from './constants.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/**\n * Parse usage update from extension params\n */\nexport function parseUsageUpdate(params: Record<string, unknown>): UsageUpdate {\n return {\n sessionId: params.sessionId as string,\n inputTokens: params.inputTokens as number | undefined,\n outputTokens: params.outputTokens as number | undefined,\n totalTokens: params.totalTokens as number | undefined,\n cost: params.cost as number | undefined,\n model: params.model as string | undefined,\n _meta: params._meta as Record<string, unknown> | undefined\n };\n}\n","/**\n * Streamable HTTP ACP Client\n * Production-grade client for connecting to cloud-hosted ACP agents\n */\n\nimport {\n ClientSideConnection,\n PROTOCOL_VERSION,\n type Client,\n type SessionNotification,\n type RequestPermissionRequest,\n type RequestPermissionResponse,\n type PromptResponse,\n type InitializeResponse,\n type NewSessionResponse,\n type LoadSessionResponse,\n type SetSessionModeRequest,\n type SetSessionModeResponse,\n type SetSessionModelRequest,\n type SetSessionModelResponse\n} from '@agentclientprotocol/sdk';\n\nimport { streamableHttp, type StreamableHttpTransport } from '../transport/streamable-http.js';\n\nimport type {\n StreamableHttpClientOptions,\n ClientState,\n ClientEvents,\n PromptOptions,\n} from './types.js';\n\nimport type {\n ArtifactNotificationParams,\n CheckpointNotificationParams\n} from '../types.js';\n\nimport {\n CLOUD_CLIENT_CAPABILITIES,\n DEFAULT_INITIALIZE_TIMEOUT,\n ExtensionMethod\n} from './constants.js';\n\nimport {\n ConnectionError,\n InitializationError,\n InvalidStateError,\n SessionError\n} from './errors.js';\n\nimport { EventEmitter } from './events.js';\nimport { ArtifactManager } from './artifacts.js';\nimport { PermissionManager } from './permissions.js';\nimport { QuestionManager, type QuestionRequest, type QuestionResponse, type QuestionAnswers } from './questions.js';\nimport { ExtensionManager, parseUsageUpdate } from './extensions.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!: ClientSideConnection;\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 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 this.connection = new ClientSideConnection(\n () => this.createClientHandler(),\n this.transport\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 this.initializeResponse = await Promise.race([initPromise, timeoutPromise]);\n this.setState('initialized');\n\n this.options.logger?.info('Client initialized successfully');\n\n return this.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) => {\n return this.handleRequestPermission(params);\n },\n extNotification: async (method: string, params: Record<string, unknown>) => {\n console.log('[ACP-Client] extNotification callback invoked:', { method, paramsKeys: Object.keys(params) });\n await this.handleExtNotification(method, params);\n },\n extMethod: async (method: string, params: Record<string, unknown>): Promise<Record<string, unknown>> => {\n // SDK uses generic Record types, cast at boundary to our typed interfaces\n const response = await this.handleExtMethod(method, params as unknown as QuestionRequest);\n return response as unknown as Record<string, unknown>;\n }\n };\n }\n\n // ============================================\n // Session Management\n // ============================================\n\n /**\n * Create a new session\n */\n async createSession(cwd: string): Promise<NewSessionResponse> {\n this.ensureInitialized('createSession');\n\n try {\n const response = await this.connection.newSession({\n cwd,\n mcpServers: []\n });\n\n this.options.logger?.info(`Session created: ${response.sessionId}`);\n return response;\n } catch (err) {\n throw new SessionError(\n `Failed to create session: ${err instanceof Error ? err.message : String(err)}`,\n undefined,\n err instanceof Error ? err : undefined\n );\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 text: string,\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: [{ type: 'text', text }],\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 console.log('[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 console.log('[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 console.log('[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 console.log('[ACP-Client] Emitting artifactUpdated event');\n this.emitter.emit('artifactUpdated', storedArtifact);\n }\n }\n return;\n }\n\n // Handle usage update notifications\n if (method === ExtensionMethod.USAGE) {\n const usage = parseUsageUpdate(params);\n await this.options.onUsageUpdate?.(usage);\n this.emitter.emit('usageUpdate', usage);\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<QuestionResponse> {\n // Handle question requests (ask_followup_question via question extMethod)\n if (method === ExtensionMethod.QUESTION) {\n return this.questionManager.handleRequest(params);\n }\n\n // Unknown extension method\n this.options.logger?.warn(`Unknown extension method: ${method}`);\n return { outcome: 'cancelled', reason: 'unknown method' };\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 * Cloud Agent Connection\n * Wraps StreamableHttpClient to implement AgentConnection interface\n */\n\nimport type {\n SessionNotification,\n RequestPermissionRequest,\n InitializeResponse,\n NewSessionResponse,\n LoadSessionResponse,\n PromptResponse,\n SetSessionModeResponse,\n SetSessionModelResponse\n} from '@agentclientprotocol/sdk';\n\nimport {\n StreamableHttpClient\n} from '@genie/agent-client-protocol';\n\nimport type {\n AgentConnection,\n AgentStatus,\n AgentCapabilities,\n CloudConnectionConfig,\n CreateSessionParams,\n LoadSessionParams,\n PromptParams,\n ConnectionEvents,\n ConnectionEventListener\n} from '../../types.js';\n\nimport type { SessionConnectionInfo } from '../../client/types.js';\n\n/**\n * Cloud Agent Connection implementation\n * Uses Streamable HTTP transport to connect to cloud-hosted ACP agents\n * Uses composition pattern - implements event emitter methods internally\n *\n * TODO: Connection Lifecycle Responsibilities\n * CloudAgentProvider caches connections by endpoint link. This class needs to:\n * - Implement connection health checks (detect and handle connection failures/reconnection)\n * - Handle token expiration (refresh or re-authentication when tokens expire)\n * - Emit 'disconnected' event when connection becomes unhealthy so provider can clean up cache\n */\nexport class CloudAgentConnection implements AgentConnection {\n private client: StreamableHttpClient;\n private listeners: Map<keyof ConnectionEvents, Set<ConnectionEventListener<unknown>>> = new Map();\n private onceListeners: Map<keyof ConnectionEvents, Set<ConnectionEventListener<unknown>>> = new Map();\n\n /**\n * Flag to suppress sessionUpdate event emission during streaming.\n * When true, onSessionUpdate callback won't emit to avoid duplicate messages with promptStream.\n */\n private _isStreaming = false;\n\n /**\n * Session connection information (sandboxId, link, token, etc.)\n * Set by CloudAgentProvider.connect() after fetching session data from backend.\n */\n private _sessionConnectionInfo?: SessionConnectionInfo;\n\n readonly agentId: string;\n readonly transport = 'cloud' as const;\n readonly cwd: string;\n\n constructor(agentId: string, config: CloudConnectionConfig, cwd: string = '/workspace') {\n this.agentId = agentId;\n this.cwd = cwd;\n\n // Create the underlying StreamableHttpClient\n this.client = new StreamableHttpClient({\n endpoint: config.endpoint,\n authToken: config.authToken,\n headers: config.headers,\n reconnect: config.reconnect,\n initializeTimeout: config.initializeTimeout,\n permissionTimeout: config.permissionTimeout,\n permissionAutoRejectOnTimeout: config.permissionAutoRejectOnTimeout,\n autoApprove: config.autoApprove,\n logger: config.logger,\n fetch: config.fetch,\n clientCapabilities: config.clientCapabilities,\n // Forward events to our emitter (suppressed during streaming to avoid duplicates)\n onSessionUpdate: (update) => {\n if (!this._isStreaming) {\n this.emit('sessionUpdate', update);\n }\n },\n onArtifact: (artifact, event) => {\n console.log('[CloudConnection] onArtifact callback:', {\n event,\n artifactUri: artifact.uri,\n artifactType: artifact.type,\n });\n if (event === 'created') {\n this.emit('artifactCreated', artifact);\n } else if (event === 'updated') {\n this.emit('artifactUpdated', artifact);\n } else if (event === 'deleted') {\n this.emit('artifactDeleted', artifact);\n }\n },\n onUsageUpdate: (usage) => {\n this.emit('usageUpdate', usage);\n }\n });\n\n // Forward client events\n this.setupEventForwarding();\n }\n\n private setupEventForwarding(): void {\n // Forward connection state events\n this.client.on('connecting', () => { this.emit('connecting', undefined); });\n this.client.on('connected', () => { this.emit('connected', undefined); });\n this.client.on('disconnected', () => { this.emit('disconnected', undefined); });\n this.client.on('error', (error) => { this.emit('error', error); });\n this.client.on('stateChange', (change) => { this.emit('stateChange', change); });\n\n // Forward permission events\n this.client.on('permissionRequest', (data) => { this.emit('permissionRequest', data); });\n this.client.on('permissionResolved', (data) => { this.emit('permissionResolved', data); });\n this.client.on('permissionRejected', (data) => { this.emit('permissionRejected', data); });\n this.client.on('permissionTimeout', (data) => { this.emit('permissionTimeout', data); });\n\n // Forward question events\n this.client.on('questionRequest', (data) => { this.emit('questionRequest', data); });\n this.client.on('questionAnswered', (data) => { this.emit('questionAnswered', data); });\n this.client.on('questionCancelled', (data) => { this.emit('questionCancelled', data); });\n this.client.on('questionTimeout', (data) => { this.emit('questionTimeout', data); });\n\n // Forward checkpoint events\n this.client.on('checkpointCreated', (checkpoint) => { this.emit('checkpointCreated', checkpoint); });\n this.client.on('checkpointUpdated', (checkpoint) => { this.emit('checkpointUpdated', checkpoint); });\n }\n\n // ============================================\n // Event Emitter Implementation\n // ============================================\n\n on<K extends keyof ConnectionEvents>(event: K, listener: ConnectionEventListener<ConnectionEvents[K]>): this {\n if (!this.listeners.has(event)) {\n this.listeners.set(event, new Set());\n }\n this.listeners.get(event)!.add(listener as ConnectionEventListener<unknown>);\n return this;\n }\n\n off<K extends keyof ConnectionEvents>(event: K, listener: ConnectionEventListener<ConnectionEvents[K]>): this {\n const eventListeners = this.listeners.get(event);\n if (eventListeners) {\n eventListeners.delete(listener as ConnectionEventListener<unknown>);\n }\n const onceEventListeners = this.onceListeners.get(event);\n if (onceEventListeners) {\n onceEventListeners.delete(listener as ConnectionEventListener<unknown>);\n }\n return this;\n }\n\n once<K extends keyof ConnectionEvents>(event: K, listener: ConnectionEventListener<ConnectionEvents[K]>): this {\n if (!this.onceListeners.has(event)) {\n this.onceListeners.set(event, new Set());\n }\n this.onceListeners.get(event)!.add(listener as ConnectionEventListener<unknown>);\n return this;\n }\n\n emit<K extends keyof ConnectionEvents>(event: K, data: ConnectionEvents[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 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(`Error in async once event listener for '${String(event)}':`, err);\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 removeAllListeners<K extends keyof ConnectionEvents>(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 // State Properties\n // ============================================\n\n get state(): AgentStatus {\n return this.client.currentState as AgentStatus;\n }\n\n get isInitialized(): boolean {\n return this.client.isInitialized;\n }\n\n get capabilities(): AgentCapabilities | undefined {\n return this.client.agentCapabilities as AgentCapabilities | undefined;\n }\n\n get initializeResult(): InitializeResponse | undefined {\n return this.client.initializeResult;\n }\n\n // ============================================\n // Connection Lifecycle\n // ============================================\n\n async connect(): Promise<InitializeResponse> {\n return this.client.connect();\n }\n\n async disconnect(): Promise<void> {\n await this.client.disconnect();\n }\n\n // ============================================\n // Session Management\n // ============================================\n\n async createSession(params: CreateSessionParams): Promise<NewSessionResponse> {\n // Cloud Side does not support creating new sessions directly\n // Use this.cwd (provided by CloudAgentProvider) as the working directory\n // params.cwd is ignored because cloud agents already have a fixed cwd from backend\n const loadedSession = await this.client.loadSession(this.agentId, this.cwd)\n return { ...loadedSession, sessionId: this.agentId };\n }\n\n async loadSession(params: LoadSessionParams): Promise<LoadSessionResponse> {\n if (!params.sessionId) {\n throw new Error('sessionId is required for loadSession');\n }\n return this.client.loadSession(params.sessionId, this.cwd);\n }\n\n async setSessionMode(sessionId: string, modeId: string): Promise<SetSessionModeResponse> {\n return this.client.setSessionMode({ sessionId, modeId });\n }\n\n async setSessionModel(sessionId: string, modelId: string): Promise<SetSessionModelResponse> {\n return this.client.setSessionModel({ sessionId, modelId });\n }\n\n // ============================================\n // Prompt Operations\n // ============================================\n\n async prompt(sessionId: string, params: PromptParams): Promise<PromptResponse> {\n const text = typeof params.content === 'string'\n ? params.content\n : params.content.map(block => {\n if (block.type === 'text') return block.text;\n return `[${block.type}]`;\n }).join('\\n');\n\n return this.client.prompt(sessionId, text, {\n planMode: params.planMode,\n _meta: params._meta\n });\n }\n\n async *promptStream(sessionId: string, params: PromptParams): AsyncIterable<SessionNotification> {\n // Suppress sessionUpdate event emission during streaming to avoid duplicates\n this._isStreaming = true;\n\n // For streaming, we need to collect updates via the event system\n const updates: SessionNotification[] = [];\n let resolveUpdate: ((value: SessionNotification | null) => void) | null = null;\n let done = false;\n\n const listener = (update: SessionNotification) => {\n if (resolveUpdate) {\n resolveUpdate(update);\n resolveUpdate = null;\n } else {\n updates.push(update);\n }\n };\n\n this.client.on('sessionUpdate', listener);\n\n try {\n // Start the prompt (non-blocking)\n const promptPromise = this.prompt(sessionId, params);\n\n // Yield updates as they come in\n while (!done) {\n const update = updates.shift();\n if (update) {\n yield update;\n } else {\n // Wait for next update or prompt completion\n const nextUpdate = await new Promise<SessionNotification | null>((resolve) => {\n resolveUpdate = resolve;\n // Check if prompt completed while we were setting up\n promptPromise.then(() => {\n if (resolveUpdate === resolve) {\n resolveUpdate = null;\n resolve(null);\n }\n }).catch(() => {\n if (resolveUpdate === resolve) {\n resolveUpdate = null;\n resolve(null);\n }\n });\n });\n\n if (nextUpdate === null) {\n done = true;\n } else {\n yield nextUpdate;\n }\n }\n }\n } finally {\n this._isStreaming = false;\n this.client.off('sessionUpdate', listener);\n }\n }\n\n async cancel(sessionId: string): Promise<void> {\n return this.client.cancel(sessionId);\n }\n\n // ============================================\n // Permission Management\n // ============================================\n\n resolvePermission(requestId: string, optionId: string): boolean {\n return this.client.resolvePermission(requestId, optionId);\n }\n\n rejectPermission(requestId: string, reason?: string): boolean {\n return this.client.rejectPermission(requestId, reason);\n }\n\n getPendingPermissions(): Map<string, { params: RequestPermissionRequest; createdAt: number }> {\n return this.client.getPendingPermissions();\n }\n\n hasPendingPermissions(): boolean {\n return this.client.hasPendingPermissions();\n }\n\n // ============================================\n // Question Management (ask_followup_question)\n // ============================================\n\n answerQuestion(toolCallId: string, answers: import('@genie/agent-client-protocol').QuestionAnswers): boolean {\n return this.client.answerQuestion(toolCallId, answers);\n }\n\n cancelQuestion(toolCallId: string, reason?: string): boolean {\n return this.client.cancelQuestion(toolCallId, reason);\n }\n\n getPendingQuestions() {\n return this.client.getPendingQuestions();\n }\n\n hasPendingQuestions(): boolean {\n return this.client.hasPendingQuestions();\n }\n\n // ============================================\n // Tool Callback Management\n // ============================================\n\n async toolCallback(sessionId: string, toolCallId: string, toolName: string, action: 'skip' | 'cancel'): Promise<{ success: boolean; error?: string }> {\n // Cloud connection does not support toolCallback yet\n return { success: false, error: 'toolCallback not supported for cloud connections' };\n }\n\n // ============================================\n // Session Connection Info\n // ============================================\n\n /**\n * Set session connection information\n * Called by CloudAgentProvider.connect() after fetching session data from backend.\n */\n setSessionConnectionInfo(info: SessionConnectionInfo): void {\n this._sessionConnectionInfo = info;\n }\n\n /**\n * Get session connection information\n * Contains sandboxId, link, token, etc.\n */\n get sessionConnectionInfo(): SessionConnectionInfo | undefined {\n return this._sessionConnectionInfo;\n }\n\n // ============================================\n // Extension Methods\n // ============================================\n\n async extMethod(method: string, params: Record<string, unknown>): Promise<Record<string, unknown>> {\n return this.client.extMethod(method, params);\n }\n}\n\nexport default CloudAgentConnection;\n","/**\n * E2B Filesystem Implementation\n *\n * Provides FilesResource implementation using E2B Sandbox SDK.\n * Directly uses e2b SDK types.\n *\n * @see https://e2b.dev/docs/filesystem/read-write\n * @see https://e2b.dev/docs/filesystem/watch\n */\n\nimport { Sandbox, type EntryInfo, type WriteInfo, type WatchHandle } from 'e2b';\nimport type {\n FilesResource,\n FilesystemEvent,\n E2BSandboxConnectionInfo,\n FilesystemRequestOpts,\n FilesystemListOpts,\n WatchOpts,\n WriteEntry\n} from '../../types.js';\n\n/**\n * E2B Filesystem Implementation\n *\n * Wraps E2B Sandbox SDK's filesystem operations to implement FilesResource interface.\n *\n * @example\n * ```typescript\n * const fs = await E2BFilesystem.connect({\n * sandboxId: 'sandbox-123',\n * apiKey: 'e2b_xxx'\n * });\n *\n * // Read/write files\n * await fs.write('/test.txt', 'Hello World');\n * const content = await fs.read('/test.txt');\n *\n * // Watch for changes\n * const handle = await fs.watchDir('/workspace', (event) => {\n * console.log('File changed:', event);\n * });\n * ```\n */\nexport class E2BFilesystem implements FilesResource {\n private sandbox: Sandbox;\n\n constructor(sandbox: Sandbox) {\n this.sandbox = sandbox;\n }\n\n /**\n * Connect to an E2B Sandbox and create filesystem instance\n */\n static async connect(info: E2BSandboxConnectionInfo): Promise<E2BFilesystem> {\n const sandbox = await Sandbox.connect(info.sandboxId, {\n domain: info.domain,\n apiUrl: info.apiUrl,\n requestTimeoutMs: info.requestTimeoutMs,\n debug: info.debug,\n headers: info.headers\n });\n return new E2BFilesystem(sandbox);\n }\n\n /**\n * Get the underlying E2B Sandbox instance\n */\n getSandbox(): Sandbox {\n return this.sandbox;\n }\n\n // ============================================\n // Read 方法重载实现\n // ============================================\n\n read(path: string, opts?: FilesystemRequestOpts & { format?: 'text' }): Promise<string>;\n read(path: string, opts: FilesystemRequestOpts & { format: 'bytes' }): Promise<Uint8Array>;\n read(path: string, opts: FilesystemRequestOpts & { format: 'blob' }): Promise<Blob>;\n read(path: string, opts: FilesystemRequestOpts & { format: 'stream' }): Promise<ReadableStream<Uint8Array>>;\n read(path: string, opts?: FilesystemRequestOpts & { format?: string }): Promise<string | Uint8Array | Blob | ReadableStream<Uint8Array>> {\n return this.sandbox.files.read(path, opts as any);\n }\n\n // ============================================\n // Write 方法重载实现\n // ============================================\n\n write(path: string, data: string | ArrayBuffer | Blob | ReadableStream, opts?: FilesystemRequestOpts): Promise<WriteInfo>;\n write(files: WriteEntry[], opts?: FilesystemRequestOpts): Promise<WriteInfo[]>;\n write(pathOrFiles: string | WriteEntry[], dataOrOpts?: string | ArrayBuffer | Blob | ReadableStream | FilesystemRequestOpts, opts?: FilesystemRequestOpts): Promise<WriteInfo | WriteInfo[]> {\n if (Array.isArray(pathOrFiles)) {\n // Batch write: write(files: WriteEntry[], opts?: FilesystemRequestOpts)\n return this.sandbox.files.write(pathOrFiles, dataOrOpts as FilesystemRequestOpts);\n }\n // Single file write: write(path: string, data: ..., opts?: FilesystemRequestOpts)\n return this.sandbox.files.write(pathOrFiles, dataOrOpts as string | ArrayBuffer | Blob | ReadableStream, opts);\n }\n\n // ============================================\n // 其他方法实现\n // ============================================\n\n async list(path: string, opts?: FilesystemListOpts): Promise<EntryInfo[]> {\n return this.sandbox.files.list(path, opts);\n }\n\n async exists(path: string, opts?: FilesystemRequestOpts): Promise<boolean> {\n return this.sandbox.files.exists(path, opts);\n }\n\n async makeDir(path: string, opts?: FilesystemRequestOpts): Promise<boolean> {\n return this.sandbox.files.makeDir(path, opts);\n }\n\n async remove(path: string, opts?: FilesystemRequestOpts): Promise<void> {\n return this.sandbox.files.remove(path, opts);\n }\n\n async rename(oldPath: string, newPath: string, opts?: FilesystemRequestOpts): Promise<EntryInfo> {\n return this.sandbox.files.rename(oldPath, newPath, opts);\n }\n\n async getInfo(path: string, opts?: FilesystemRequestOpts): Promise<EntryInfo> {\n return this.sandbox.files.getInfo(path, opts);\n }\n\n async watchDir(\n path: string,\n onEvent: (event: FilesystemEvent) => void | Promise<void>,\n opts?: WatchOpts & { onExit?: (err?: Error) => void | Promise<void> }\n ): Promise<WatchHandle> {\n return this.sandbox.files.watchDir(path, onEvent, opts);\n }\n}\n\nexport default E2BFilesystem;\n","/**\n * 并发控制工具\n *\n * 提供限制并发数量的工具函数,用于控制并行请求数量\n */\n\n/**\n * 并发执行任务,限制同时运行的任务数量\n *\n * @param tasks - 任务函数数组,每个函数返回 Promise\n * @param concurrency - 最大并发数,默认 5\n * @returns 所有任务的结果数组,顺序与输入一致\n *\n * @example\n * ```typescript\n * const urls = ['url1', 'url2', 'url3', 'url4', 'url5'];\n * const tasks = urls.map(url => () => fetch(url));\n * const results = await runWithConcurrency(tasks, 2); // 最多同时 2 个请求\n * ```\n */\nexport async function runWithConcurrency<T>(\n tasks: Array<() => Promise<T>>,\n concurrency: number = 5\n): Promise<T[]> {\n if (tasks.length === 0) {\n return [];\n }\n\n // 确保并发数至少为 1\n const limit = Math.max(1, concurrency);\n\n const results: T[] = new Array(tasks.length);\n let currentIndex = 0;\n\n async function runNext(): Promise<void> {\n while (currentIndex < tasks.length) {\n const index = currentIndex++;\n const task = tasks[index];\n results[index] = await task();\n }\n }\n\n // 启动 limit 个 worker\n const workers = Array(Math.min(limit, tasks.length))\n .fill(null)\n .map(() => runNext());\n\n await Promise.all(workers);\n\n return results;\n}\n\n/**\n * 并发执行任务,返回包含成功/失败状态的结果\n *\n * @param tasks - 任务函数数组\n * @param concurrency - 最大并发数,默认 5\n * @returns 所有任务的结果数组,包含状态信息\n *\n * @example\n * ```typescript\n * const results = await runWithConcurrencySettled(tasks, 3);\n * const successes = results.filter(r => r.status === 'fulfilled');\n * const failures = results.filter(r => r.status === 'rejected');\n * ```\n */\nexport async function runWithConcurrencySettled<T>(\n tasks: Array<() => Promise<T>>,\n concurrency: number = 5\n): Promise<PromiseSettledResult<T>[]> {\n if (tasks.length === 0) {\n return [];\n }\n\n const limit = Math.max(1, concurrency);\n const results: PromiseSettledResult<T>[] = new Array(tasks.length);\n let currentIndex = 0;\n\n async function runNext(): Promise<void> {\n while (currentIndex < tasks.length) {\n const index = currentIndex++;\n const task = tasks[index];\n try {\n const value = await task();\n results[index] = { status: 'fulfilled', value };\n } catch (reason) {\n results[index] = { status: 'rejected', reason };\n }\n }\n }\n\n const workers = Array(Math.min(limit, tasks.length))\n .fill(null)\n .map(() => runNext());\n\n await Promise.all(workers);\n\n return results;\n}\n\n/**\n * 创建一个并发限制器,可复用于多次调用\n *\n * @param concurrency - 最大并发数\n * @returns 并发限制器实例\n *\n * @example\n * ```typescript\n * const limiter = createConcurrencyLimiter(3);\n *\n * // 多个地方可以共用同一个限制器\n * const result1 = await limiter.run(() => fetch(url1));\n * const result2 = await limiter.run(() => fetch(url2));\n *\n * // 或者批量执行\n * const results = await limiter.runAll([\n * () => fetch(url1),\n * () => fetch(url2),\n * ]);\n * ```\n */\nexport function createConcurrencyLimiter(concurrency: number = 5) {\n const limit = Math.max(1, concurrency);\n let running = 0;\n const queue: Array<{\n task: () => Promise<unknown>;\n resolve: (value: unknown) => void;\n reject: (reason: unknown) => void;\n }> = [];\n\n async function processQueue(): Promise<void> {\n if (running >= limit || queue.length === 0) {\n return;\n }\n\n running++;\n const item = queue.shift()!;\n\n try {\n const result = await item.task();\n item.resolve(result);\n } catch (error) {\n item.reject(error);\n } finally {\n running--;\n processQueue();\n }\n }\n\n return {\n /**\n * 执行单个任务,受并发限制\n */\n run<T>(task: () => Promise<T>): Promise<T> {\n return new Promise<T>((resolve, reject) => {\n queue.push({\n task: task as () => Promise<unknown>,\n resolve: resolve as (value: unknown) => void,\n reject,\n });\n processQueue();\n });\n },\n\n /**\n * 批量执行任务,受并发限制\n */\n async runAll<T>(tasks: Array<() => Promise<T>>): Promise<T[]> {\n return Promise.all(tasks.map(task => this.run(task)));\n },\n\n /**\n * 获取当前正在运行的任务数\n */\n get runningCount(): number {\n return running;\n },\n\n /**\n * 获取队列中等待的任务数\n */\n get pendingCount(): number {\n return queue.length;\n },\n };\n}\n","/**\n * COS Upload Service\n *\n * 负责通过预签名 URL 上传文件到腾讯云 COS\n *\n * 上传流程:\n * 1. 生成 objectKey (uploads/{timestamp}-{random}-{filename})\n * 2. 批量请求后端获取预签名 URL (同时包含 upload_url 和 download_url)\n * 3. 使用 upload_url 并发上传文件到 COS\n * 4. 返回 download_url 作为访问地址\n *\n * 注意:文件级缓存(避免重复上传相同文件)由上层 agent-ui 的 upload-cache 处理\n */\n\nimport type { Logger } from '../../client/types.js';\nimport { runWithConcurrencySettled } from '../../utils/index.js';\n\n/**\n * 预签名 URL 请求参数\n */\nexport interface PresignedURLRequest {\n /** 对象路径数组 */\n object_keys: string[];\n}\n\n/**\n * 预签名 URL 响应项\n */\nexport interface PresignedURLItem {\n /** 对象路径 */\n object_key: string;\n /** 上传 URL (PUT) */\n upload_url: string;\n /** 下载 URL (GET) */\n download_url: string;\n}\n\n/**\n * 预签名 URL 响应\n */\nexport interface PresignedURLResponse {\n /** 过期时间 (秒) */\n expire: number;\n /** 预签名 URL 列表 */\n items: PresignedURLItem[];\n}\n\n/**\n * API 响应包装类型\n */\ninterface ApiResponse<T> {\n code: number;\n message: string;\n data?: T;\n}\n\n/**\n * 上传结果\n */\nexport interface UploadResult {\n /** 是否成功 */\n success: boolean;\n /** 访问 URL (成功时返回) */\n url?: string;\n /** 对象路径 */\n objectKey?: string;\n /** 错误信息 (失败时返回) */\n error?: string;\n}\n\n/**\n * HTTP 请求函数类型 (复用 CloudAgentProvider 的 request 方法)\n */\nexport type RequestFunction = (\n method: string,\n path: string,\n body?: unknown\n) => Promise<Response>;\n\n/**\n * COS Upload Service 配置\n */\nexport interface CosUploadServiceOptions {\n /** HTTP 请求函数 (复用 CloudAgentProvider 的 request 方法,包含公共 headers) */\n request: RequestFunction;\n /** Logger 实例 */\n logger?: Logger;\n /** 自定义 fetch 实现 (用于上传到 COS) */\n fetch?: typeof fetch;\n /** 上传并发数,默认 3 */\n uploadConcurrency?: number;\n}\n\n/**\n * COS 上传服务\n *\n * @example\n * ```typescript\n * const service = new CosUploadService({\n * request: (method, path, body) => cloudProvider.request(method, path, body),\n * logger: console,\n * uploadConcurrency: 3,\n * });\n *\n * const result = await service.uploadFile(file);\n * if (result.success) {\n * console.log('File URL:', result.url);\n * }\n * ```\n */\nexport class CosUploadService {\n private request: RequestFunction;\n private logger?: Logger;\n private fetchImpl: typeof fetch;\n private uploadConcurrency: number;\n\n constructor(options: CosUploadServiceOptions) {\n this.request = options.request;\n this.logger = options.logger;\n this.fetchImpl = options.fetch ?? globalThis.fetch.bind(globalThis);\n this.uploadConcurrency = options.uploadConcurrency ?? 3;\n }\n\n /**\n * 生成唯一的 objectKey\n *\n * 格式: uploads/{timestamp}-{randomId}-{encodedFilename}\n */\n private generateObjectKey(filename: string): string {\n const timestamp = Date.now();\n const randomId = Math.random().toString(36).substring(2, 10);\n const encodedFilename = encodeURIComponent(filename);\n return `uploads/${timestamp}-${randomId}-${encodedFilename}`;\n }\n\n /**\n * 批量获取预签名 URL\n *\n * POST /conversations/presigned_url\n */\n private async getPresignedUrls(objectKeys: string[]): Promise<PresignedURLResponse> {\n const response = await this.request('POST', '/conversations/presigned_url', {\n object_keys: objectKeys,\n });\n\n if (!response.ok) {\n throw new Error(`Failed to get presigned URLs: ${response.statusText}`);\n }\n\n const apiResponse = await response.json() as ApiResponse<PresignedURLResponse>;\n if (!apiResponse.data) {\n throw new Error('No data in presigned URL response');\n }\n\n return apiResponse.data;\n }\n\n /**\n * 上传单个文件到 COS\n *\n * @param file - 要上传的文件\n * @returns 上传结果,包含访问 URL 或错误信息\n */\n async uploadFile(file: File): Promise<UploadResult> {\n const filename = file.name;\n this.logger?.info(`[CosUploadService] Uploading file: ${filename}`);\n\n try {\n // 1. 生成 objectKey\n const objectKey = this.generateObjectKey(filename);\n this.logger?.debug(`[CosUploadService] Generated objectKey: ${objectKey}`);\n\n // 2. 获取预签名 URL\n const presignedResponse = await this.getPresignedUrls([objectKey]);\n const presignedItem = presignedResponse.items[0];\n if (!presignedItem) {\n throw new Error('No presigned URL item returned');\n }\n\n // 3. 上传文件到 COS\n const uploadResponse = await this.fetchImpl(presignedItem.upload_url, {\n method: 'PUT',\n body: file,\n headers: {\n 'Content-Type': file.type || 'application/octet-stream',\n },\n });\n\n if (!uploadResponse.ok) {\n const errorText = await uploadResponse.text().catch(() => uploadResponse.statusText);\n throw new Error(`COS upload failed: ${uploadResponse.status} ${errorText}`);\n }\n this.logger?.debug(`[CosUploadService] File uploaded to COS`);\n\n this.logger?.info(`[CosUploadService] Upload success: ${filename}`);\n return {\n success: true,\n url: presignedItem.download_url,\n objectKey,\n };\n } catch (error) {\n const errorMessage = error instanceof Error ? error.message : 'Unknown error';\n this.logger?.error(`[CosUploadService] Upload failed: ${filename}`, error);\n return {\n success: false,\n error: errorMessage,\n };\n }\n }\n\n /**\n * 批量上传文件到 COS\n *\n * 使用并发控制,限制同时上传的文件数量\n *\n * @param files - 要上传的文件数组\n * @returns 所有文件的上传结果\n */\n async uploadFiles(files: File[]): Promise<{\n success: boolean;\n urls?: string[];\n expireSeconds?: number;\n error?: string;\n results: UploadResult[];\n }> {\n if (files.length === 0) {\n return { success: true, urls: [], results: [] };\n }\n\n this.logger?.info(`[CosUploadService] Uploading ${files.length} file(s) with concurrency ${this.uploadConcurrency}`);\n\n try {\n // 1. 为所有文件生成 objectKey\n const fileInfos = files.map(file => ({\n file,\n objectKey: this.generateObjectKey(file.name),\n }));\n\n // 2. 批量获取预签名 URL\n const objectKeys = fileInfos.map(info => info.objectKey);\n const presignedResponse = await this.getPresignedUrls(objectKeys);\n this.logger?.debug(`[CosUploadService] Got ${presignedResponse.items.length} presigned URLs`);\n\n // 3. 创建 objectKey -> presignedItem 映射\n const presignedMap = new Map<string, PresignedURLItem>();\n for (const item of presignedResponse.items) {\n presignedMap.set(item.object_key, item);\n }\n\n // 4. 创建上传任务\n const uploadTasks = fileInfos.map(({ file, objectKey }) => async (): Promise<UploadResult> => {\n const presignedItem = presignedMap.get(objectKey);\n if (!presignedItem) {\n return {\n success: false,\n error: `No presigned URL for ${file.name}`,\n objectKey,\n };\n }\n\n try {\n const uploadResponse = await this.fetchImpl(presignedItem.upload_url, {\n method: 'PUT',\n body: file,\n headers: {\n 'Content-Type': file.type || 'application/octet-stream',\n },\n });\n\n if (!uploadResponse.ok) {\n const errorText = await uploadResponse.text().catch(() => uploadResponse.statusText);\n return {\n success: false,\n error: `COS upload failed: ${uploadResponse.status} ${errorText}`,\n objectKey,\n };\n }\n\n this.logger?.debug(`[CosUploadService] Uploaded: ${file.name}`);\n return {\n success: true,\n url: presignedItem.download_url,\n objectKey,\n };\n } catch (error) {\n const errorMessage = error instanceof Error ? error.message : 'Unknown error';\n return {\n success: false,\n error: errorMessage,\n objectKey,\n };\n }\n });\n\n // 5. 并发执行上传任务\n const settledResults = await runWithConcurrencySettled(uploadTasks, this.uploadConcurrency);\n\n // 6. 处理结果\n const results: UploadResult[] = settledResults.map((result, index) => {\n if (result.status === 'fulfilled') {\n return result.value;\n }\n // rejected 的情况\n return {\n success: false,\n error: result.reason instanceof Error ? result.reason.message : 'Unknown error',\n objectKey: fileInfos[index].objectKey,\n };\n });\n\n const urls = results.filter(r => r.success && r.url).map(r => r.url!);\n const failedResults = results.filter(r => !r.success);\n\n if (failedResults.length > 0) {\n const failedErrors = failedResults.map(r => r.error).join('; ');\n return {\n success: false,\n error: `${failedResults.length} file(s) failed: ${failedErrors}`,\n expireSeconds: presignedResponse.expire,\n results,\n };\n }\n\n this.logger?.info(`[CosUploadService] All ${files.length} file(s) uploaded successfully`);\n return {\n success: true,\n urls,\n expireSeconds: presignedResponse.expire,\n results,\n };\n } catch (error) {\n const errorMessage = error instanceof Error ? error.message : 'Unknown error';\n this.logger?.error(`[CosUploadService] Batch upload failed`, error);\n return {\n success: false,\n error: errorMessage,\n results: files.map(() => ({ success: false, error: errorMessage })),\n };\n }\n }\n}\n\nexport default CosUploadService;\n","/**\n * AccountService - 账号状态管理单例\n *\n * 提供全局的账号状态管理,任何模块都可以:\n * - 获取当前账号: accountService.getAccount()\n * - 设置账号: accountService.setAccount(account)\n * - 订阅变化: accountService.subscribe(callback)\n */\n\nimport type { Account } from '../backend/types';\n\n/**\n * 账号变化回调函数类型\n */\nexport type AccountChangeCallback = (account: Account | null) => void;\n\n/**\n * AccountService 类\n *\n * 单例模式,管理全局账号状态\n */\nclass AccountService {\n /** 当前账号 */\n private account: Account | null = null;\n\n /** 订阅者列表 */\n private listeners = new Set<AccountChangeCallback>();\n\n /** 是否已初始化(首次加载完成) */\n private initialized = false;\n\n /** 初始化等待队列 */\n private initPromise: Promise<Account | null> | null = null;\n private initResolve: ((account: Account | null) => void) | null = null;\n\n constructor() {\n // 创建初始化 Promise,允许其他模块等待首次加载完成\n this.initPromise = new Promise((resolve) => {\n this.initResolve = resolve;\n });\n }\n\n /**\n * 获取当前账号\n * @returns 当前账号,未登录或未加载时返回 null\n */\n getAccount(): Account | null {\n return this.account;\n }\n\n /**\n * 设置账号\n * @param account 账号信息,登出时传 null\n */\n setAccount(account: Account | null): void {\n const prev = this.account;\n this.account = account;\n\n // 首次设置时,标记为已初始化并 resolve 等待的 Promise\n if (!this.initialized) {\n this.initialized = true;\n this.initResolve?.(account);\n }\n\n // 只有账号真正变化时才通知订阅者\n if (prev?.uid !== account?.uid) {\n this.notifyListeners();\n }\n }\n\n /**\n * 清除账号(登出)\n */\n clearAccount(): void {\n this.setAccount(null);\n }\n\n /**\n * 订阅账号变化\n * @param callback 变化时的回调函数\n * @returns 取消订阅函数\n */\n subscribe(callback: AccountChangeCallback): () => void {\n this.listeners.add(callback);\n return () => {\n this.listeners.delete(callback);\n };\n }\n\n /**\n * 等待首次账号加载完成\n * @returns Promise<Account | null>\n */\n waitForInit(): Promise<Account | null> {\n if (this.initialized) {\n return Promise.resolve(this.account);\n }\n return this.initPromise!;\n }\n\n /**\n * 是否已初始化\n */\n isInitialized(): boolean {\n return this.initialized;\n }\n\n /**\n * 是否已登录\n */\n isLoggedIn(): boolean {\n return this.account !== null;\n }\n\n /**\n * 通知所有订阅者\n */\n private notifyListeners(): void {\n this.listeners.forEach((callback) => {\n try {\n callback(this.account);\n } catch (error) {\n console.error('[AccountService] Listener error:', error);\n }\n });\n }\n\n /**\n * 重置服务状态(仅用于测试)\n */\n _reset(): void {\n this.account = null;\n this.listeners.clear();\n this.initialized = false;\n this.initPromise = new Promise((resolve) => {\n this.initResolve = resolve;\n });\n }\n}\n\n/**\n * 导出单例实例\n */\nexport const accountService = new AccountService();\n","/**\n * Cloud Agent Provider\n *\n * REST API based agent provider that manages cloud-hosted agents.\n * Implements the AgentProvider interface for the unified agent API.\n */\n\nimport type {\n AgentProvider,\n CloudAgentState,\n Logger,\n FilesystemProvider,\n FilesResource,\n ListAgentOptions,\n ListAgentResult,\n PaginationInfo,\n PickFileParams,\n PickFileResponse,\n UploadFileParams,\n UploadFileResponse,\n} from '../../client/types.js';\nimport type {\n AgentStatus,\n ClientCapabilities,\n E2BSandboxConnectionInfo,\n ModelInfo\n} from '../../types.js';\nimport { CreateAgentResponse, GetAgentResponse, Agent as AgentDto, ListAgentResponse, ListAgentRequest, CreateAgentRequest, GetAgentSessionResponse, ApiResponse, DeleteAgentRequest, ArchiveAgentResponse, PatchAgentRequest, PatchAgentResponse, RenameAgentResponse, ProductConfigResponse } from './api-types.js';\nimport { CloudAgentConnection } from './cloud-connection.js';\nimport { E2BFilesystem } from './e2b-filesystem.js';\nimport { CosUploadService } from './cos-upload-service.js';\nimport { accountService } from '../../../account/index.js';\n\n/**\n * Agent data stored in cloud backend\n */\n// @ts-expect-error 没对齐\ninterface CloudAgentData {\n id: string;\n name?: string;\n description?: string;\n endpoint: string;\n authToken?: string;\n headers?: Record<string, string>;\n metadata?: Record<string, unknown>;\n createdAt?: string;\n updatedAt?: string;\n}\n\n/**\n * Configuration for CloudAgentProvider\n */\nexport interface CloudAgentProviderOptions {\n /** Base endpoint URL for agent management API (e.g., 'https://api.example.com') */\n endpoint: string;\n /** Authorization token */\n authToken?: string;\n /** Custom headers */\n headers?: Record<string, string>;\n /** Logger instance */\n logger?: Logger;\n /** Custom fetch implementation */\n fetch?: typeof fetch;\n /** Client capabilities (sent during agent initialization) */\n clientCapabilities?: ClientCapabilities;\n}\n\n/**\n * Normalize a path by resolving `.` and `..` segments\n * This is a simplified version that works in browser environment\n */\nfunction normalizePath(path: string): string {\n const segments = path.split('/');\n const result: string[] = [];\n\n for (const segment of segments) {\n if (segment === '..') {\n // Don't pop if we're at root level\n if (result.length > 0 && result[result.length - 1] !== '') {\n result.pop();\n }\n } else if (segment !== '.' && segment !== '') {\n result.push(segment);\n }\n }\n\n // Preserve leading slash for absolute paths\n return (path.startsWith('/') ? '/' : '') + result.join('/');\n}\n\n/**\n * Resolve agent:/// URI to filesystem path\n *\n * 只处理 agent:// 协议的 URI,raw path 直接透传不做任何处理\n *\n * Supported formats:\n * - `agent:///workspace/{path}` → `/workspace/{path}`\n * - `agent:///plans/{path}` → `/root/.codebuddy/plans/{path}`\n * - `agent:///{path}` → `/{path}`\n * - Raw paths (e.g. `/foo/bar`) → 直接透传,不处理\n *\n * Security: Path traversal attacks are prevented by normalizing paths\n * and verifying they stay within expected boundaries.\n */\nfunction resolveAgentUri(input: string): string {\n // 只处理 agent:// 协议,raw path 直接返回\n if (!input.startsWith('agent://')) {\n return input;\n }\n\n const path = input.slice('agent://'.length);\n if (!path.startsWith('/')) {\n return input;\n }\n\n // Normalize path to prevent traversal attacks\n const normalizedPath = normalizePath(path);\n\n // 路径映射: /plans/{path} → /root/.codebuddy/plans/{path}\n if (normalizedPath.startsWith('/plans/') || normalizedPath === '/plans') {\n const mappedPath = '/root/.codebuddy' + normalizedPath;\n // Verify the mapped path stays within /root/.codebuddy/plans\n const finalPath = normalizePath(mappedPath);\n if (!finalPath.startsWith('/root/.codebuddy/plans')) {\n throw new Error(`Invalid path: path traversal detected in ${input}`);\n }\n return finalPath;\n }\n\n return normalizedPath;\n}\n\n/**\n * Create a FilesResource wrapper that resolves agent:/// URIs\n */\nfunction createAgentFilesystem(fs: E2BFilesystem): FilesResource {\n return {\n read: (path: string, opts?: any) => fs.read(resolveAgentUri(path), opts),\n write: (pathOrFiles: any, dataOrOpts?: any, opts?: any) => {\n if (Array.isArray(pathOrFiles)) {\n const resolved = pathOrFiles.map(f => ({ ...f, path: resolveAgentUri(f.path) }));\n return fs.write(resolved, dataOrOpts);\n }\n return fs.write(resolveAgentUri(pathOrFiles), dataOrOpts, opts);\n },\n list: (path: string, opts?: any) => fs.list(resolveAgentUri(path), opts),\n exists: (path: string, opts?: any) => fs.exists(resolveAgentUri(path), opts),\n makeDir: (path: string, opts?: any) => fs.makeDir(resolveAgentUri(path), opts),\n remove: (path: string, opts?: any) => fs.remove(resolveAgentUri(path), opts),\n rename: (oldPath: string, newPath: string, opts?: any) =>\n fs.rename(resolveAgentUri(oldPath), resolveAgentUri(newPath), opts),\n getInfo: (path: string, opts?: any) => fs.getInfo(resolveAgentUri(path), opts),\n watchDir: (path: string, onEvent: any, opts?: any) =>\n fs.watchDir(resolveAgentUri(path), onEvent, opts),\n } as FilesResource;\n}\n\n/**\n * CloudAgentProvider - Manages cloud-hosted agents via REST API\n *\n * API Endpoints:\n * - POST {endpoint}/console/cloudagent/agentmgmt/agents - Create new agent\n * - GET {endpoint}/console/cloudagent/agentmgmt/agents/{id} - Get agent data\n * - GET {endpoint}/console/cloudagent/agentmgmt/agents - List all agents\n * - POST {endpoint}/console/cloudagent/agentmgmt/agents/{id}/delete - Delete agent\n * - GET {endpoint}/console/cloudagent/agentmgmt/agents/{id}/session - Get agent session (includes sandboxId)\n * - GET {endpoint}/console/cloudagent/agentmgmt/models - Get available models\n *\n * The provider stores agent endpoint configurations in the cloud backend.\n * When connect() is called, it creates a CloudAgentConnection to the agent's\n * endpoint and returns an Agent instance.\n *\n * @example\n * ```typescript\n * const provider = new CloudAgentProvider({\n * endpoint: 'https://staging-copilot.tencent.com',\n * authToken: 'token'\n * });\n *\n * // List all agents (uses default pagination and sorting)\n * const allAgents = await provider.list();\n *\n * // List agents with custom pagination\n * const page2 = await provider.list({\n * page: 2,\n * size: 50\n * });\n *\n * // List agents with filtering\n * const runningAgents = await provider.list({\n * filters: [\n * { field: 'status', value: 'running' }\n * ]\n * });\n *\n * // List agents with custom sorting\n * const sortedAgents = await provider.list({\n * sort: {\n * orderBy: 'createdAt',\n * order: 'desc'\n * }\n * });\n *\n * // List agents created in last 14 days with multiple filters\n * const recentAgents = await provider.list({\n * dayRange: 14,\n * filters: [\n * { field: 'status', value: 'running,stopped' }\n * ],\n * page: 1,\n * size: 20\n * });\n *\n * // Get agent state\n * const state = await provider.get('agent-id');\n *\n * // Connect to agent\n * const agent = await provider.connect('agent-id');\n *\n * // Use agent\n * const session = await agent.sessions.create({ cwd: '/workspace' });\n *\n * // Get available models\n * const models = await provider.getModels('my-repo');\n * ```\n */\nexport class CloudAgentProvider implements AgentProvider<CloudAgentConnection>, FilesystemProvider {\n private options: CloudAgentProviderOptions;\n private logger?: Logger;\n private fetchImpl: typeof fetch;\n\n /** Cache for filesystem instances (keyed by agentId) */\n private filesystemCache: Map<string, FilesResource> = new Map();\n\n /** Cache for agent connections (keyed by endpoint link) */\n private connectionCache: Map<string, CloudAgentConnection> = new Map();\n\n /** COS upload service instance */\n private cosUploadService: CosUploadService;\n\n /** Event listeners for provider-level events */\n private eventListeners: Map<string, Set<(...args: any[]) => void>> = new Map();\n\n constructor(options: CloudAgentProviderOptions) {\n this.options = options;\n this.logger = options.logger;\n this.fetchImpl = options.fetch ?? globalThis.fetch.bind(globalThis);\n\n // Initialize COS upload service with request method for shared headers\n this.cosUploadService = new CosUploadService({\n request: (method, path, body) => this.request(method, path, body),\n logger: this.logger,\n fetch: this.fetchImpl,\n });\n }\n\n /**\n * Dispose the provider and clean up resources\n */\n dispose(): void {\n this.filesystemCache.clear();\n this.connectionCache.clear();\n }\n\n // ============================================\n // FilesystemProvider Implementation\n // ============================================\n\n /**\n * Get the filesystem provider (returns self)\n */\n get filesystem(): FilesystemProvider {\n return this;\n }\n\n /**\n * Get filesystem resource for an agent\n *\n * Creates or returns cached filesystem instance for the agent's sandbox.\n * The filesystem supports both `agent:///` URIs and raw paths.\n *\n * @param agentId - Agent ID to get filesystem for\n * @returns FilesResource instance for the agent's sandbox (with URI support)\n *\n * @example\n * ```typescript\n * const fs = await provider.getFilesystem(agentId);\n *\n * // Use agent:/// URIs\n * const content = await fs.read('agent:///files/src/app.ts');\n * await fs.write('agent:///artifacts/output.txt', 'Hello');\n *\n * // Raw paths still work (backward compatible)\n * const content2 = await fs.read('/src/app.ts');\n * ```\n */\n async getFilesystem(agentId: string): Promise<FilesResource> {\n // Check cache first\n const cached = this.filesystemCache.get(agentId);\n if (cached) {\n return cached;\n }\n\n // Get sandbox info from backend\n const info = await this.getSandboxInfo(agentId);\n\n // Create E2BFilesystem and wrap with URI support\n const e2bFilesystem = await E2BFilesystem.connect(info);\n const filesystem = createAgentFilesystem(e2bFilesystem);\n\n this.filesystemCache.set(agentId, filesystem);\n\n this.logger?.debug(`Created filesystem for agent: ${agentId}`);\n return filesystem;\n }\n\n /**\n * Get sandbox information from backend\n *\n * Uses GET {endpoint}/console/cloudagent/agentmgmt/agents/{agentId}/session\n * to retrieve sandbox information. Extracts sandboxId from the session response\n * and constructs the apiUrl for E2B proxy.\n *\n * @param agentId - Agent ID\n * @returns E2B Sandbox connection information with sandboxId and apiUrl\n */\n private async getSandboxInfo(agentId: string): Promise<E2BSandboxConnectionInfo> {\n const response = await this.request('GET', `/console/cloudagent/agentmgmt/agents/${agentId}/session`);\n\n if (!response.ok) {\n throw new Error(`Failed to get sandbox info: ${response.statusText}`);\n }\n\n const apiResponse = await response.json() as ApiResponse<GetAgentSessionResponse>;\n if (!apiResponse.data) {\n throw new Error('No data in API response');\n }\n\n // Build E2BSandboxConnectionInfo from session response\n // apiUrl is constructed as: {endpoint}/console/cloudagent/e2bproxy/agents/{agentId}\n const apiUrl = new URL(`/console/cloudagent/e2bproxy/agents/${agentId}`, this.options.endpoint).toString();\n const currentEnterpriseId = localStorage.getItem('currentEnterpriseId');\n\n return {\n sandboxId: apiResponse.data.sandboxId,\n apiUrl,\n accessToken: apiResponse.data.token,\n headers: {\n // 只有当 enterpriseId 存在时才添加该 header\n ...(currentEnterpriseId && { 'X-Enterprise-Id': currentEnterpriseId }),\n },\n };\n }\n\n /**\n * Get agent state by ID\n */\n async get(agentId: string): Promise<CloudAgentState | undefined> {\n try {\n const response = await this.request('GET', `/console/cloudagent/agentmgmt/agents/${agentId}`);\n\n if (response.status === 404) {\n return undefined;\n }\n\n if (!response.ok) {\n throw new Error(`Failed to get agent: ${response.statusText}`);\n }\n\n const apiResponse = await response.json() as ApiResponse<GetAgentResponse>;\n if (!apiResponse.data) {\n throw new Error('No data in API response');\n }\n return this.toAgentState(apiResponse.data);\n } catch (error) {\n this.logger?.error(`Failed to get agent ${agentId}:`, error);\n throw error;\n }\n }\n\n /**\n * List all agent states with pagination information\n *\n * @param options - Optional query parameters for filtering, sorting, and pagination\n * @returns Object containing agents array and pagination info\n */\n async list(options?: ListAgentOptions): Promise<ListAgentResult<CloudAgentState>> {\n try {\n console.log('[CloudAgentProvider] list called with options:', JSON.stringify(options, null, 2));\n\n // Build request parameters with defaults and user overrides\n const params: ListAgentRequest = {\n // Default values\n page: 1,\n size: 30,\n sort: {\n order: 'desc',\n orderBy: 'status'\n },\n // User overrides\n ...options && {\n ...(options.dayRange !== undefined && { dayRange: options.dayRange }),\n ...(options.page !== undefined && { page: options.page }),\n ...(options.size !== undefined && { size: options.size }),\n ...(options.sort !== undefined && { sort: options.sort }),\n ...(options.filters !== undefined && { filters: options.filters }),\n ...(options.title !== undefined && { title: options.title }),\n }\n };\n\n console.log('[CloudAgentProvider] API request params:', JSON.stringify(params, null, 2));\n\n const response = await this.request('GET', '/console/cloudagent/agentmgmt/agents', params);\n\n if (!response.ok) {\n throw new Error(`Failed to list agents: ${response.statusText}`);\n }\n\n const apiResponse = await response.json() as ApiResponse<ListAgentResponse>;\n if (!apiResponse.data) {\n throw new Error('No data in API response');\n }\n\n const agents = apiResponse.data.agents.map((a) => this.toAgentState(a));\n const pagination: PaginationInfo = apiResponse.data.pagination;\n\n console.log('[CloudAgentProvider] API response:', {\n agentsCount: agents.length,\n pagination\n });\n\n return { agents, pagination };\n } catch (error) {\n this.logger?.error('Failed to list agents:', error);\n throw error;\n }\n }\n\n /**\n * Create a new agent\n * POST {endpoint}/console/cloudagent/agentmgmt/agents\n */\n async create(): Promise<string> {\n try {\n // @ts-expect-error Backend Connect Not Ready\n const createPayload: CreateAgentRequest = {\n prompt: '',\n // source: {\n // provider: 'github',\n // repository: 'example/repo',\n // ref: 'main'\n // },\n // target: {\n // branchName: 'main',\n // autoCreatePr: false\n // },\n model: 'deepseek-r1',\n // webhook: {\n // url: 'https://example.com/webhook',\n // secret: 'supersecret'\n // }\n };\n const response = await this.request('POST', '/console/cloudagent/agentmgmt/agents', createPayload);\n\n if (!response.ok) {\n throw new Error(`Failed to create agent: ${response.statusText}`);\n }\n\n const apiResponse = await response.json() as ApiResponse<CreateAgentResponse>;\n if (!apiResponse.data) {\n throw new Error('No data in API response');\n }\n\n this.logger?.info(`Created agent: ${apiResponse.data.id}`);\n return apiResponse.data.id;\n } catch (error) {\n this.logger?.error('Failed to create agent:', error);\n throw error;\n }\n }\n\n /**\n * Connect to an agent and return the connection\n *\n * This method:\n * 1. Fetches the agent configuration from the backend\n * 2. Checks if an existing connection can be reused (based on endpoint link)\n * 3. Creates a CloudAgentConnection to the agent's endpoint if not cached\n * 4. Saves session connection info to the connection\n * 5. Connects and initializes the connection\n * 6. Returns the connected CloudAgentConnection\n *\n * Connection caching:\n * - Connections are cached by endpoint link to enable reuse\n * - CloudAgentConnection is responsible for handling connection health checks\n * and token expiration internally\n */\n async connect(agentId: string): Promise<CloudAgentConnection> {\n // Fetch agent session data from backend\n const sessionResponse = await this.request('GET', `/console/cloudagent/agentmgmt/agents/${agentId}/session`);\n\n if (sessionResponse.status === 404) {\n throw new Error(`Agent not found: ${agentId}`);\n }\n\n if (!sessionResponse.ok) {\n throw new Error(`Failed to get agent for connection: ${sessionResponse.statusText}`);\n }\n\n const sessionApiResponse = await sessionResponse.json() as ApiResponse<GetAgentSessionResponse>;\n if (!sessionApiResponse.data) {\n throw new Error('No data in API response');\n }\n\n const sessionData = sessionApiResponse.data;\n const endpoint = sessionData.link.replace(/^http:\\/\\//, 'https://');\n const cwd = sessionApiResponse.data.cwd || '/workspace';\n\n // Fetch agent details to get name, createdAt and status\n const agentResponse = await this.request('GET', `/console/cloudagent/agentmgmt/agents/${agentId}`);\n let agentName: string | undefined;\n let agentCreatedAt: Date | undefined;\n let agentStatus: string | undefined;\n\n if (agentResponse.ok) {\n const agentApiResponse = await agentResponse.json() as ApiResponse<GetAgentResponse>;\n if (agentApiResponse.data) {\n agentName = agentApiResponse.data.name;\n agentCreatedAt = agentApiResponse.data.createdAt ? new Date(agentApiResponse.data.createdAt) : undefined;\n // 优先使用 sessionStatus(会话状态),fallback 到 status(Agent 状态)\n agentStatus = agentApiResponse.data.sessionStatus || agentApiResponse.data.status;\n }\n }\n\n // Check for existing cached connection\n const existingConnection = this.connectionCache.get(endpoint);\n if (existingConnection?.isInitialized) {\n this.logger?.info(`Reusing existing connection for agent: ${agentId}`);\n return existingConnection;\n }\n\n // Prepare client capabilities with cwd in _meta (consistent with LocalAgentProvider)\n const clientCapabilities = {\n ...this.options.clientCapabilities,\n _meta: {\n ...this.options.clientCapabilities?._meta,\n \"codebuddy.ai\": {\n ...this.options.clientCapabilities?._meta?.[\"codebuddy.ai\"],\n cwd,\n }\n }\n };\n\n // Create connection to agent's endpoint\n // Note: CloudAgentConnection is responsible for:\n // - Connection health checks (reconnection on disconnect)\n // - Token expiration handling (refresh or re-authentication)\n const connection = new CloudAgentConnection(agentId, {\n endpoint,\n authToken: sessionData.token,\n // Backend does not provide custom headers currently\n // headers: data.headers,\n logger: this.logger,\n clientCapabilities\n }, cwd);\n\n // Save session connection info to the connection\n connection.setSessionConnectionInfo({\n sessionId: sessionData.sessionId,\n agentId: sessionData.id,\n link: sessionData.link,\n token: sessionData.token,\n sandboxId: sessionData.sandboxId,\n expireAt: sessionData.expireAt,\n cwd\n });\n\n // Connect and initialize\n try {\n await connection.connect();\n } catch (error) {\n this.logger?.error(`Failed to connect to agent ${agentId}:`, error);\n throw error;\n }\n\n // Cache the connection\n this.connectionCache.set(endpoint, connection);\n\n // Clean up cache when connection is disconnected\n connection.once('disconnected', () => {\n this.connectionCache.delete(endpoint);\n this.logger?.debug(`Connection removed from cache: ${endpoint}`);\n });\n\n this.logger?.info(`Connected to agent: ${agentId}`);\n\n // Emit sessionCreated event for agent-new-adapter to create conversation\n // SessionInfo format: Use agentId as both id and agentId (1:1 mapping per SessionManager)\n this.emitEvent('sessionCreated', {\n id: agentId, // Use agentId as sessionId (1:1 mapping in current design)\n agentId: agentId,\n name: agentName,\n status: agentStatus as AgentStatus,\n cwd: cwd,\n createdAt: agentCreatedAt\n });\n\n return connection;\n }\n\n /**\n * Delete an agent by ID\n * POST {endpoint}/console/cloudagent/agentmgmt/agents/{agentId}/delete\n */\n async delete(agentId: string): Promise<boolean> {\n try {\n const requestBody: DeleteAgentRequest = { id: agentId };\n const response = await this.request('POST', `/console/cloudagent/agentmgmt/agents/${agentId}/delete`, requestBody);\n\n if (response.status === 404) {\n return false;\n }\n\n if (!response.ok) {\n throw new Error(`Failed to delete agent: ${response.statusText}`);\n }\n\n return true;\n } catch (error) {\n this.logger?.error(`Failed to delete agent ${agentId}:`, error);\n throw error;\n }\n }\n\n /**\n * Archive an agent by ID\n * POST {endpoint}/console/cloudagent/agentmgmt/agents/{agentId}/archive\n *\n * @param agentId - Agent ID to archive\n * @returns ArchiveAgentResponse containing the archived agent ID\n *\n * @example\n * ```typescript\n * const result = await provider.archive('agent-123');\n * console.log('Archived agent:', result.id);\n * ```\n */\n async archive(agentId: string): Promise<ArchiveAgentResponse> {\n try {\n const response = await this.request('POST', `/console/cloudagent/agentmgmt/agents/${agentId}/archive`);\n\n if (!response.ok) {\n throw new Error(`Failed to archive agent: ${response.statusText}`);\n }\n\n const apiResponse = await response.json() as ApiResponse<ArchiveAgentResponse>;\n if (!apiResponse.data) {\n // 如果后端没有返回 data,使用传入的 agentId\n this.logger?.info(`Archived agent: ${agentId}`);\n return { id: agentId };\n }\n\n this.logger?.info(`Archived agent: ${apiResponse.data.id}`);\n return apiResponse.data;\n } catch (error) {\n this.logger?.error(`Failed to archive agent ${agentId}:`, error);\n throw error;\n }\n }\n\n /**\n * Rename an agent by ID\n * PATCH {endpoint}/v2/cloudagent/agentmgmt/agents/{agentId}\n *\n * @param agentId - Agent ID to rename\n * @param title - New title for the agent\n * @returns RenameAgentResponse containing the renamed agent ID\n *\n * @example\n * ```typescript\n * const result = await provider.rename('agent-123', 'New Title');\n * console.log('Renamed agent:', result.id);\n * ```\n */\n async rename(agentId: string, title: string): Promise<RenameAgentResponse> {\n try {\n const body: PatchAgentRequest = { title };\n const response = await this.request('POST', `/console/cloudagent/agentmgmt/agents/${agentId}`, body);\n\n if (!response.ok) {\n throw new Error(`Failed to rename agent: ${response.statusText}`);\n }\n\n const apiResponse = await response.json() as ApiResponse<PatchAgentResponse>;\n if (!apiResponse.data) {\n // 如果后端没有返回 data,使用传入的 agentId\n this.logger?.info(`Renamed agent: ${agentId} to \"${title}\"`);\n return { id: agentId };\n }\n\n this.logger?.info(`Renamed agent: ${apiResponse.data.id} to \"${title}\"`);\n return apiResponse.data;\n } catch (error) {\n this.logger?.error(`Failed to rename agent ${agentId}:`, error);\n throw error;\n }\n }\n\n /**\n * Get available models from product configuration\n *\n * GET {endpoint}/v3/config?repos[]={repo}\n *\n * This method fetches the product configuration from /v3/config API\n * and extracts the models array from the response.\n *\n * @param repo - Optional repository URL for context-specific config\n * @returns Array of ModelInfo with full model details\n */\n async getModels(repo?: string): Promise<ModelInfo[]> {\n try {\n // Build URL with repos[] array parameter format\n let url = `${this.options.endpoint}/v3/config`;\n if (repo) {\n // Format: /v3/config?repos[]=encoded_repo_url\n url += `?repos[]=${encodeURIComponent(repo)}`;\n }\n\n // Build headers for /v3/config request\n const headers: Record<string, string> = {\n 'Accept': 'application/json, text/plain, */*',\n 'X-Requested-With': 'XMLHttpRequest',\n ...this.options.headers\n };\n\n // Add authorization if available\n if (this.options.authToken) {\n headers['Authorization'] = `Bearer ${this.options.authToken}`;\n }\n\n // Get user info from accountService\n const account = accountService.getAccount();\n\n // Add user info headers\n if (account?.uid) {\n headers['X-User-Id'] = account.uid;\n }\n\n // Add enterprise/tenant ID from account\n if (account?.enterpriseId) {\n headers['X-Enterprise-Id'] = account.enterpriseId;\n headers['X-Tenant-Id'] = account.enterpriseId;\n }\n\n // Hardcoded product and user agent\n headers['X-Product'] = 'SaaS';\n headers['X-User-Agent'] = 'CLI/2.38.0 CodeBuddy/2.38.0';\n\n // Add request ID\n headers['X-Request-ID'] = this.generateRequestId();\n\n this.logger?.debug(`[CloudAgentProvider] GET ${url}`);\n\n const response = await this.fetchImpl(url, {\n method: 'GET',\n headers,\n credentials: 'include',\n });\n\n if (!response.ok) {\n throw new Error(`Failed to get config: ${response.statusText}`);\n }\n\n // Parse response - expecting { data: ProductConfiguration }\n const apiResponse = await response.json() as ApiResponse<ProductConfigResponse>;\n if (!apiResponse.data) {\n this.logger?.warn('[CloudAgentProvider] No data in config response, returning empty models');\n return [];\n }\n\n // Extract models from product configuration\n const productConfig = apiResponse.data;\n const models = productConfig.models ?? [];\n\n this.logger?.info(`[CloudAgentProvider] Retrieved ${models.length} models from /v3/config`);\n\n // Convert LanguageModel to ModelInfo\n return models.map((model): ModelInfo => ({\n id: model.id,\n name: model.name ?? model.id,\n description: model.description,\n credits: model.credits,\n configurable: model.configurable,\n configured: model.configured,\n isDefault: model.isDefault,\n supportsImages: model.supportsImages,\n supportsReasoning: model.supportsReasoning,\n onlyReasoning: model.onlyReasoning,\n disabledMultimodal: model.disabledMultimodal,\n disabled: model.disabled,\n disabledReason: model.disabledReason,\n disabledAction: model.disabledAction,\n }));\n } catch (error) {\n this.logger?.error(`[CloudAgentProvider] Failed to get models:`, error);\n throw error;\n }\n }\n\n /**\n * Generate a unique request ID\n */\n private generateRequestId(): string {\n // Generate UUID without dashes\n return 'xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx'.replace(/x/g, () =>\n Math.floor(Math.random() * 16).toString(16)\n );\n }\n\n // ============================================\n // File Picker (Browser Environment)\n // ============================================\n\n /**\n * Common image MIME types for filtering\n */\n private static readonly IMAGE_MIME_TYPES = [\n 'image/png',\n 'image/jpeg',\n 'image/jpg',\n 'image/gif',\n 'image/webp',\n 'image/svg+xml',\n 'image/bmp',\n ];\n\n /**\n * Pick files using browser's native file input\n *\n * @param params - File picker parameters\n * @returns Response with selected file paths (filenames in browser)\n */\n async pickFile(params?: PickFileParams): Promise<PickFileResponse> {\n return new Promise((resolve) => {\n const input = document.createElement('input');\n input.type = 'file';\n input.style.display = 'none';\n\n // Set accept attribute\n if (params?.filters && params.filters.length > 0) {\n const acceptTypes: string[] = [];\n for (const filter of params.filters) {\n for (const ext of filter.extensions) {\n const mimeType = this.extensionToMimeType(ext);\n acceptTypes.push(mimeType || `.${ext}`);\n }\n }\n input.accept = acceptTypes.join(',');\n } else {\n input.accept = CloudAgentProvider.IMAGE_MIME_TYPES.join(',');\n }\n\n input.multiple = params?.canSelectMany ?? false;\n\n input.onchange = () => {\n const files = input.files;\n if (!files || files.length === 0) {\n resolve({ files: [], canceled: true });\n } else {\n const fileArray = Array.from(files);\n this.logger?.info(`Picked ${fileArray.length} file(s)`);\n resolve({ files: fileArray, canceled: false });\n }\n document.body.removeChild(input);\n };\n\n input.oncancel = () => {\n resolve({ files: [], canceled: true });\n document.body.removeChild(input);\n };\n\n document.body.appendChild(input);\n input.click();\n });\n }\n\n /**\n * Convert file extension to MIME type\n */\n private extensionToMimeType(ext: string): string | null {\n const extLower = ext.toLowerCase().replace(/^\\./, '');\n const mimeMap: Record<string, string> = {\n 'png': 'image/png',\n 'jpg': 'image/jpeg',\n 'jpeg': 'image/jpeg',\n 'gif': 'image/gif',\n 'webp': 'image/webp',\n 'svg': 'image/svg+xml',\n 'bmp': 'image/bmp',\n 'ico': 'image/x-icon',\n };\n return mimeMap[extLower] || null;\n }\n\n // ============================================\n // File Upload (Browser Environment)\n // ============================================\n\n /**\n * Upload files to cloud storage via COS presigned URL\n *\n * @param params - files array (File objects in browser)\n * @returns Response with corresponding cloud URLs\n */\n async uploadFile(params: UploadFileParams): Promise<UploadFileResponse> {\n this.logger?.info(`[CloudAgentProvider] uploadFile called for ${params.files.length} file(s)`);\n\n // Filter out string paths (only File objects are supported in browser)\n const files = params.files.filter((f): f is File => typeof f !== 'string');\n if (files.length === 0) {\n return {\n success: false,\n error: 'No valid File objects provided',\n };\n }\n\n // Use CosUploadService for actual upload\n const result = await this.cosUploadService.uploadFiles(files);\n\n return {\n success: result.success,\n urls: result.urls,\n expireSeconds: result.expireSeconds,\n error: result.error,\n };\n }\n\n // ============================================\n // Event Emitter Implementation\n // ============================================\n\n /**\n * Register event listener\n * @param event - Event name\n * @param handler - Event handler function\n */\n on(event: string, handler: (...args: any[]) => void): () => void {\n if (!this.eventListeners.has(event)) {\n this.eventListeners.set(event, new Set());\n }\n this.eventListeners.get(event)!.add(handler);\n\n // Return unsubscribe function\n return () => {\n this.off(event, handler);\n };\n }\n\n /**\n * Unregister event listener\n * @param event - Event name\n * @param handler - Event handler function\n */\n off(event: string, handler: (...args: any[]) => void): void {\n const listeners = this.eventListeners.get(event);\n if (listeners) {\n listeners.delete(handler);\n }\n }\n\n /**\n * Emit event to all registered listeners\n * @param event - Event name\n * @param args - Event arguments\n */\n private emitEvent(event: string, ...args: any[]): void {\n const listeners = this.eventListeners.get(event);\n if (listeners && listeners.size > 0) {\n this.logger?.debug(`Emitting event: ${event}`, args);\n for (const handler of listeners) {\n try {\n handler(...args);\n } catch (error) {\n this.logger?.error(`Error in event handler for ${event}:`, error);\n }\n }\n }\n }\n\n // ============================================\n // Helpers\n // ============================================\n\n private toAgentState(data: AgentDto): CloudAgentState {\n // 优先使用 sessionStatus(会话状态),fallback 到 status(Agent 状态)\n const status = data.sessionStatus || data.status;\n return {\n id: data.id,\n name: data.name,\n description: data.summary,\n type: 'cloud',\n status: status as AgentStatus,\n createdAt: data.createdAt ? new Date(data.createdAt) : undefined,\n capabilities: this.options.clientCapabilities,\n };\n }\n\n private async request(\n method: string,\n path: string,\n body?: unknown\n ): Promise<Response> {\n let url = `${this.options.endpoint}${path}`;\n\n const headers: Record<string, string> = {\n 'Content-Type': 'application/json',\n ...this.options.headers\n };\n\n if (this.options.authToken) {\n headers['Authorization'] = `Bearer ${this.options.authToken}`;\n }\n\n // Get user info from accountService\n const account = accountService.getAccount();\n\n // Add user info headers\n if (account?.uid) {\n headers['X-User-Id'] = account.uid;\n }\n\n // Add enterprise/tenant ID from account\n if (account?.enterpriseId) {\n headers['X-Enterprise-Id'] = account.enterpriseId;\n headers['X-Tenant-Id'] = account.enterpriseId;\n }\n\n // Hardcoded product and user agent\n headers['X-Product'] = 'SaaS';\n headers['X-User-Agent'] = 'CLI/2.38.0 CodeBuddy/2.38.0';\n\n const init: RequestInit = {\n method,\n headers\n };\n\n // For GET requests, convert body to query params\n if (method === 'GET' && body !== undefined) {\n const params = new URLSearchParams();\n for (const [key, value] of Object.entries(body as Record<string, unknown>)) {\n if (value !== undefined && value !== null) {\n // For complex types (objects/arrays), stringify them\n // For primitive types, convert to string directly\n const stringValue = typeof value === 'object'\n ? JSON.stringify(value)\n : String(value);\n params.append(key, stringValue);\n }\n }\n const queryString = params.toString();\n if (queryString) {\n url += `?${queryString}`;\n }\n } else if (body !== undefined) {\n // For non-GET requests, use body\n init.body = JSON.stringify(body);\n }\n\n this.logger?.debug(`${method} ${url}`);\n\n return this.fetchImpl(url, init);\n }\n}\n\nexport default CloudAgentProvider;\n","/**\n * Local Agent Connection\n * Wraps AcpJsonRpcClient to implement AgentConnection interface\n *\n * Uses IWidgetChannel for IPC communication with ExtensionHost\n * Migrated from ipc-agent-provider for unified local agent access\n */\n\nimport {\n PROTOCOL_VERSION,\n type SessionNotification,\n type RequestPermissionRequest,\n type InitializeResponse,\n type NewSessionResponse,\n type LoadSessionResponse,\n type PromptResponse,\n type SetSessionModeResponse,\n type SetSessionModelResponse,\n type ContentBlock\n} from '@agentclientprotocol/sdk';\n\nimport type {\n Artifact,\n ArtifactType,\n QuestionRequest,\n QuestionAnswers,\n ClientCapabilities,\n CheckpointInfo\n} from '@genie/agent-client-protocol';\n\nimport type {\n AgentConnection,\n AgentStatus,\n AgentCapabilities,\n LocalConnectionConfig,\n CreateSessionParams,\n LoadSessionParams,\n PromptParams,\n ConnectionEvents,\n ConnectionEventListener,\n} from '../../types.js';\n\nimport {\n AcpJsonRpcClient,\n type SessionUpdateParams,\n type PermissionRequestParams,\n type PermissionResponse,\n type OpenWorkspaceRequest,\n type OpenWorkspaceResponse,\n type ToolCallbackRequest\n} from './acp/index.js';\n\n// Re-export IWidgetChannel for convenience\nexport type { IWidgetChannel } from './acp/index.js';\n\n// ============================================================================\n// Local Agent Connection Implementation\n// ============================================================================\n\n/**\n * Local Agent Connection implementation\n * Uses AcpJsonRpcClient to communicate with ExtensionHost via IWidgetChannel\n *\n * Phase 1 Implementation:\n * - connect/disconnect: ✅ via initialize\n * - createSession/loadSession: ✅ via AcpJsonRpcClient\n * - prompt/cancel: ✅ via AcpJsonRpcClient\n * - Event forwarding: ✅ sessionUpdate, permissionRequest\n * - resolvePermission/rejectPermission: ✅ via callback\n *\n * Phase 2 (Not Implemented):\n * - promptStream: throws 'Not implemented'\n * - Artifact methods: return empty\n * - Question methods: return empty\n * - Extension methods: throw 'Not implemented'\n * - Filesystem methods: throw 'Not implemented'\n */\nexport class LocalAgentConnection implements AgentConnection {\n // ========================================================================\n // Private Fields\n // ========================================================================\n\n /** ACP JSON-RPC Client */\n private readonly acpClient: AcpJsonRpcClient;\n\n /** Debug mode */\n private readonly debug: boolean;\n\n /** Event listeners */\n private listeners: Map<keyof ConnectionEvents, Set<ConnectionEventListener<unknown>>> = new Map();\n private onceListeners: Map<keyof ConnectionEvents, Set<ConnectionEventListener<unknown>>> = new Map();\n\n /** Connection state */\n private _state: AgentStatus = 'disconnected';\n private _isInitialized = false;\n private _capabilities?: AgentCapabilities;\n private _initializeResult?: InitializeResponse;\n\n /** Pending permission requests: requestId → { params, createdAt } */\n private pendingPermissions: Map<string, { params: PermissionRequestParams; createdAt: number }> = new Map();\n\n /** Permission timeout config */\n private readonly permissionTimeout: number;\n private readonly permissionAutoRejectOnTimeout: boolean;\n\n /** Local artifact cache: id → Artifact */\n private artifactCache: Map<string, Artifact> = new Map();\n\n // ========================================================================\n // Public Properties\n // ========================================================================\n\n /** agentId = cwd (工作区路径) */\n readonly agentId: string;\n\n /** 工作区路径 (与 agentId 相同,语义更清晰) */\n readonly cwd: string;\n\n readonly transport = 'local' as const;\n\n private onRequest?: () => void = undefined;\n\n // ========================================================================\n // Constructor\n // ========================================================================\n\n constructor(agentId: string, config: LocalConnectionConfig) {\n this.agentId = agentId;\n this.cwd = agentId; // agentId 就是 cwd\n this.debug = config.debug ?? false;\n this.permissionTimeout = config.permissionTimeout ?? 30000;\n this.permissionAutoRejectOnTimeout = config.permissionAutoRejectOnTimeout ?? false;\n\n // Initialize ACP JSON-RPC Client\n this.acpClient = new AcpJsonRpcClient(config.channel, {\n timeoutMs: config.acpConfig?.timeoutMs ?? 30000,\n debug: this.debug\n });\n\n // Setup event forwarding\n this.setupEventForwarding();\n\n this.log('LocalAgentConnection initialized');\n }\n\n // ========================================================================\n // Event Forwarding Setup\n // ========================================================================\n\n private setupEventForwarding(): void {\n // Forward session updates from AcpJsonRpcClient\n this.acpClient.onSessionUpdate((params: SessionUpdateParams) => {\n this.emit('sessionUpdate', params.notification);\n });\n\n // Forward extNotification from AcpJsonRpcClient (for artifacts, checkpoints, etc.)\n this.acpClient.onExtNotification((method: string, params: Record<string, unknown>) => {\n console.log('[LocalConnection] Received extNotification:', { method, paramsKeys: Object.keys(params) });\n\n // Handle artifact notifications\n if (method === '_codebuddy.ai/artifact') {\n const event = params.event as 'created' | 'updated' | 'deleted';\n const artifact = params.artifact as Artifact;\n\n console.log('[LocalConnection] Emitting artifact event:', { event, artifactUri: artifact?.uri });\n\n // Update local artifact cache\n if (artifact?.uri) {\n if (event === 'created' || event === 'updated') {\n this.artifactCache.set(artifact.uri, artifact);\n } else if (event === 'deleted') {\n this.artifactCache.delete(artifact.uri);\n }\n }\n\n if (event === 'created') {\n this.emit('artifactCreated', artifact);\n } else if (event === 'updated') {\n this.emit('artifactUpdated', artifact);\n } else if (event === 'deleted') {\n this.emit('artifactDeleted', artifact);\n }\n }\n\n // Handle checkpoint notifications\n if (method === '_codebuddy.ai/checkpoint') {\n const event = params.event as 'created' | 'updated';\n const checkpoint = params.checkpoint as CheckpointInfo;\n\n console.log('[LocalConnection] Emitting checkpoint event:', {\n event,\n checkpointId: checkpoint?.id,\n filesCount: checkpoint?.fileChanges?.files?.length ?? 0\n });\n\n if (event === 'created') {\n this.emit('checkpointCreated', checkpoint);\n } else if (event === 'updated') {\n this.emit('checkpointUpdated', checkpoint);\n }\n }\n });\n\n this.log('Event forwarding setup complete');\n }\n\n // ========================================================================\n // Event Emitter Implementation\n // ========================================================================\n\n on<K extends keyof ConnectionEvents>(event: K, listener: ConnectionEventListener<ConnectionEvents[K]>): this {\n if (!this.listeners.has(event)) {\n this.listeners.set(event, new Set());\n }\n this.listeners.get(event)!.add(listener as ConnectionEventListener<unknown>);\n return this;\n }\n\n off<K extends keyof ConnectionEvents>(event: K, listener: ConnectionEventListener<ConnectionEvents[K]>): this {\n const eventListeners = this.listeners.get(event);\n if (eventListeners) {\n eventListeners.delete(listener as ConnectionEventListener<unknown>);\n }\n const onceEventListeners = this.onceListeners.get(event);\n if (onceEventListeners) {\n onceEventListeners.delete(listener as ConnectionEventListener<unknown>);\n }\n return this;\n }\n\n once<K extends keyof ConnectionEvents>(event: K, listener: ConnectionEventListener<ConnectionEvents[K]>): this {\n if (!this.onceListeners.has(event)) {\n this.onceListeners.set(event, new Set());\n }\n this.onceListeners.get(event)!.add(listener as ConnectionEventListener<unknown>);\n return this;\n }\n\n emit<K extends keyof ConnectionEvents>(event: K, data: ConnectionEvents[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 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(`Error in async once event listener for '${String(event)}':`, err);\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 removeAllListeners<K extends keyof ConnectionEvents>(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 // State Properties\n // ========================================================================\n\n get state(): AgentStatus {\n return this._state;\n }\n\n get isInitialized(): boolean {\n return this._isInitialized;\n }\n\n get capabilities(): AgentCapabilities | undefined {\n return this._capabilities;\n }\n\n get initializeResult(): InitializeResponse | undefined {\n return this._initializeResult;\n }\n\n // ========================================================================\n // Connection Lifecycle (Phase 1: Implemented)\n // ========================================================================\n\n async connect(_clientCapabilities?: ClientCapabilities): Promise<InitializeResponse> {\n this.log('Connecting...');\n this._state = 'connecting';\n this.emit('connecting', undefined);\n this._isInitialized = true;\n this._initializeResult = { protocolVersion: PROTOCOL_VERSION };\n this.emit('connected', undefined);\n this._state = 'initialized';\n return this._initializeResult;\n }\n\n disconnect(): void {\n this.log('Disconnecting...');\n\n // 清理所有待处理的权限请求\n this.cleanupPendingPermissionsOnDisconnect();\n\n this._state = 'disconnected';\n this._isInitialized = false;\n this.acpClient.destroy();\n this.emit('disconnected', undefined);\n this.log('Disconnected');\n }\n\n /**\n * 清理断开连接时所有待处理的权限请求\n * 在连接断开时主动清理所有 pending 权限请求并返回 cancelled\n */\n private cleanupPendingPermissionsOnDisconnect(): void {\n const count = this.pendingPermissions.size;\n if (count === 0) {\n return;\n }\n\n for (const [requestId] of this.pendingPermissions) {\n const resolver = (this as any)[`_permissionResolver_${requestId}`];\n if (resolver) {\n resolver({ outcome: 'cancelled' });\n delete (this as any)[`_permissionResolver_${requestId}`];\n }\n }\n this.pendingPermissions.clear();\n this.log(`Cleaned up ${count} pending permission request(s) on disconnect`);\n }\n\n // ========================================================================\n // Session Management (Phase 1: Implemented)\n // ========================================================================\n\n async createSession(params: CreateSessionParams): Promise<NewSessionResponse> {\n this.log('Creating session with cwd:', params.cwd);\n const response = await this.acpClient.newSession({\n cwd: params.cwd,\n mcpServers: (params.mcpServers ?? []) as any // Type cast needed for McpServerConfig → McpServer\n });\n\n this.bindPermissionRequest(response.sessionId);\n return response;\n }\n\n async loadSession(params: LoadSessionParams): Promise<LoadSessionResponse> {\n if (!params.sessionId) {\n throw new Error('sessionId is required for loadSession');\n }\n this.log(`[LocalAgentConnection] loadSession: ${params.sessionId}`);\n const response = await this.acpClient.loadSession({\n sessionId: params.sessionId,\n cwd: params.cwd,\n mcpServers: (params.mcpServers ?? []) as any // Type cast needed for McpServerConfig → McpServer\n });\n this.log(`[LocalAgentConnection] loadSession response:${response}`);\n\n this.bindPermissionRequest(params.sessionId);\n return response;\n }\n\n async bindPermissionRequest(sessionId: string) {\n if (this.onRequest) {\n this.onRequest();\n }\n // Forward permission requests from AcpJsonRpcClient\n this.onRequest = this.acpClient.onRequestPermission(sessionId, async (params: PermissionRequestParams): Promise<PermissionResponse> => {\n // Store pending permission (using PermissionRequestParams format)\n this.pendingPermissions.set(params.requestId, {\n params: params,\n createdAt: Date.now()\n });\n\n // Emit event (convert to RequestPermissionRequest format expected by ConnectionEvents)\n const permissionRequest: RequestPermissionRequest = {\n sessionId: params.sessionId,\n toolCall: params.toolCall, // Type mismatch between legacy and SDK\n options: params.options\n };\n this.emit('permissionRequest', { requestId: params.requestId, params: permissionRequest });\n\n // Wait for resolution\n return new Promise<PermissionResponse>((resolve) => {\n const checkResolution = () => {\n // Check if resolved/rejected\n if (!this.pendingPermissions.has(params.requestId)) {\n // Already resolved by resolvePermission/rejectPermission\n return;\n }\n\n // Check timeout\n const pending = this.pendingPermissions.get(params.requestId);\n if (pending && Date.now() - pending.createdAt > this.permissionTimeout) {\n this.pendingPermissions.delete(params.requestId);\n this.emit('permissionTimeout', { requestId: params.requestId });\n if (this.permissionAutoRejectOnTimeout) {\n resolve({ outcome: 'cancelled' });\n }\n }\n };\n\n // Store resolver for external resolution\n (this as any)[`_permissionResolver_${params.requestId}`] = resolve;\n\n // Setup timeout check\n setTimeout(checkResolution, this.permissionTimeout);\n });\n });\n }\n\n // ========================================================================\n // Session Mode Management\n // ========================================================================\n\n async setSessionMode(sessionId: string, modeId: string): Promise<SetSessionModeResponse> {\n this.log('Setting session mode:', sessionId, 'to', modeId);\n return await this.acpClient.setSessionMode({ sessionId, modeId });\n }\n\n async setSessionModel(sessionId: string, modelId: string): Promise<SetSessionModelResponse> {\n this.log('Setting session model:', sessionId, 'to', modelId);\n return await this.acpClient.setSessionModel({ sessionId, modelId });\n }\n\n // ========================================================================\n // Workspace Operations\n // ========================================================================\n\n /**\n * 打开工作区窗口\n * 使用 __workspace__ session ID,由 Main Process 直接处理,不转发到 ExtensionHost\n * @param params 打开工作区请求参数\n * @returns 打开工作区响应\n */\n async openWorkspace(params: OpenWorkspaceRequest): Promise<OpenWorkspaceResponse> {\n this.log('Opening workspace:', params.cwd);\n return await this.acpClient.openWorkspace(params);\n }\n\n // ========================================================================\n // Prompt Operations (Phase 1: Implemented, except promptStream)\n // ========================================================================\n\n async prompt(sessionId: string, params: PromptParams): Promise<PromptResponse> {\n // 如果 content 是字符串,包装成 ContentBlock;否则直接使用\n const prompt = typeof params.content === 'string'\n ? [{ type: 'text' as const, text: params.content }]\n : params.content as ContentBlock[];\n\n this.log('Sending prompt to session:', sessionId);\n return await this.acpClient.prompt({\n sessionId,\n prompt,\n ...{ _meta: { ...params._meta, planMode: params.planMode } }\n }); // Cast needed due to legacy type mismatch\n }\n\n async *promptStream(_sessionId: string, _params: PromptParams): AsyncIterable<SessionNotification> {\n // Phase 2: Not implemented yet\n throw new Error('promptStream not implemented for Local connection');\n }\n\n async cancel(sessionId: string): Promise<void> {\n this.log('Cancelling session:', sessionId);\n await this.acpClient.cancel({ sessionId });\n }\n\n // ========================================================================\n // Artifact Management (Implemented via local cache)\n // ========================================================================\n\n getArtifacts(): Map<string, Artifact> {\n return new Map(this.artifactCache);\n }\n\n getArtifact(uri: string): Artifact | undefined {\n return this.artifactCache.get(uri);\n }\n\n getArtifactsByType(type: ArtifactType): Artifact[] {\n return Array.from(this.artifactCache.values()).filter(artifact => artifact.type === type);\n }\n\n async fetchArtifactContent(_artifact: Artifact): Promise<string> {\n // Phase 2: Not implemented\n throw new Error('fetchArtifactContent not implemented for Local connection');\n }\n\n async fetchArtifactContentById(_id: string): Promise<string> {\n // Phase 2: Not implemented\n throw new Error('fetchArtifactContentById not implemented for Local connection');\n }\n\n // ========================================================================\n // Permission Management (Phase 1: Implemented)\n // ========================================================================\n\n resolvePermission(requestId: string, optionId: string): boolean {\n const resolver = (this as any)[`_permissionResolver_${requestId}`];\n if (resolver) {\n this.pendingPermissions.delete(requestId);\n delete (this as any)[`_permissionResolver_${requestId}`];\n resolver({ outcome: 'selected', optionId });\n this.emit('permissionResolved', { requestId, optionId });\n return true;\n }\n return false;\n }\n\n rejectPermission(requestId: string, reason?: string): boolean {\n const resolver = (this as any)[`_permissionResolver_${requestId}`];\n if (resolver) {\n this.pendingPermissions.delete(requestId);\n delete (this as any)[`_permissionResolver_${requestId}`];\n resolver({ outcome: 'cancelled' });\n this.emit('permissionRejected', { requestId, reason });\n return true;\n }\n return false;\n }\n\n getPendingPermissions(): Map<string, { params: RequestPermissionRequest; createdAt: number }> {\n // Convert PermissionRequestParams to RequestPermissionRequest format\n const result = new Map<string, { params: RequestPermissionRequest; createdAt: number }>();\n for (const [requestId, pending] of this.pendingPermissions) {\n result.set(requestId, {\n params: {\n sessionId: pending.params.sessionId,\n toolCall: pending.params.toolCall as any,\n options: pending.params.options\n },\n createdAt: pending.createdAt\n });\n }\n return result;\n }\n\n hasPendingPermissions(): boolean {\n return this.pendingPermissions.size > 0;\n }\n\n // ========================================================================\n // Question Management (Phase 2: Not Implemented)\n // ========================================================================\n\n answerQuestion(_toolCallId: string, _answers: QuestionAnswers): boolean {\n // Phase 2: Not implemented\n return false;\n }\n\n // ========================================================================\n // Tool Callback Management\n // ========================================================================\n\n /**\n * 工具回调操作\n * 用于对正在执行的工具进行 skip 或 cancel 操作\n * @param sessionId 会话 ID\n * @param toolCallId 工具调用 ID\n * @param toolName 工具名称\n * @param action 操作类型 ('skip' | 'cancel')\n * @returns 工具回调响应\n */\n async toolCallback(sessionId: string, toolCallId: string, toolName: string, action: 'skip' | 'cancel'): Promise<{ success: boolean; error?: string }> {\n this.log('toolCallback called for session:', sessionId, 'action:', action);\n const request: ToolCallbackRequest = { sessionId, toolCallId, toolName, action };\n return await this.acpClient.toolCallback(request);\n }\n\n cancelQuestion(_toolCallId: string, _reason?: string): boolean {\n // Phase 2: Not implemented\n return false;\n }\n\n getPendingQuestions(): Map<string, { request: QuestionRequest; createdAt: number }> {\n // Phase 2: Not implemented\n return new Map();\n }\n\n hasPendingQuestions(): boolean {\n // Phase 2: Not implemented\n return false;\n }\n\n // ========================================================================\n // Extension Methods (Phase 2: Not Implemented)\n // ========================================================================\n\n async extMethod(_method: string, _params: Record<string, unknown>): Promise<Record<string, unknown>> {\n // Phase 2: Not implemented\n throw new Error('extMethod not implemented for Local connection');\n }\n\n async extNotification(_method: string, _params: Record<string, unknown>): Promise<void> {\n // Phase 2: Not implemented\n throw new Error('extNotification not implemented for Local connection');\n }\n\n // ========================================================================\n // Filesystem Operations (Phase 2: Not Implemented)\n // ========================================================================\n\n async readFile(_path: string): Promise<string> {\n // Phase 2: Not implemented\n throw new Error('readFile not implemented for Local connection');\n }\n\n async listDir(_path: string): Promise<any[]> {\n // Phase 2: Not implemented\n throw new Error('listDir not implemented for Local connection');\n }\n\n async fileExists(_path: string): Promise<boolean> {\n // Phase 2: Not implemented\n throw new Error('fileExists not implemented for Local connection');\n }\n\n async fileStat(_path: string): Promise<any> {\n // Phase 2: Not implemented\n throw new Error('fileStat not implemented for Local connection');\n }\n\n // ========================================================================\n // Utility Methods\n // ========================================================================\n\n private log(...args: unknown[]): void {\n // if (this.debug) {\n console.log('[LocalAgentConnection]', ...args);\n // }\n }\n}\n\n/**\n * @deprecated Use LocalAgentConnection instead\n * Alias for backward compatibility\n */\nexport const IPCAgentConnection = LocalAgentConnection;\n\nexport default LocalAgentConnection;\n","/**\n * ActiveSessionImpl - Implements the ActiveSession interface\n *\n * Represents an active session with its resources and operations.\n * Session is the primary API surface for client interactions.\n */\n\nimport type { SessionNotification, PromptResponse as SdkPromptResponse } from '@agentclientprotocol/sdk';\nimport type {\n ActiveSession,\n AgentState,\n SessionAgentOperations,\n PromptsResource,\n ArtifactsResource,\n SessionEvents,\n SessionEventHandler,\n Logger,\n AgentConnection,\n Artifact,\n ArtifactType,\n PromptResponse,\n AgentCapabilities,\n SessionMode,\n QuestionAnswers,\n AvailableCommand,\n SessionConnectionInfo\n} from './types.js';\nimport type { PromptParams, FilesResource, AgentStatus } from '../types.js';\n\n/**\n * Event listener type\n */\ntype EventListener<T> = (data: T) => void | Promise<void>;\n\n/**\n * Filesystem getter function type\n * Returns a FilesResource instance for file operations\n */\nexport type FilesystemGetter = () => Promise<FilesResource>;\n\n/**\n * Options for creating an ActiveSessionImpl instance\n */\nexport interface ActiveSessionImplOptions {\n /** Logger instance */\n logger?: Logger;\n /** Getter function for filesystem resource (provided by SessionManager) */\n getFilesystem?: FilesystemGetter;\n /** Session connection information (for cloud sessions) */\n connectionInfo?: SessionConnectionInfo;\n}\n\n/**\n * ActiveSessionImpl - Implements the ActiveSession interface\n *\n * This class wraps an AgentConnection and provides the session-centric API.\n * It is created by SessionManager when creating or loading sessions.\n *\n * @example\n * ```typescript\n * // Created by client.sessions.new() or client.sessions.load()\n * const session = await client.sessions.new({ cwd: '/workspace' });\n *\n * // Access agent state\n * console.log(session.agentState.status);\n *\n * // Send prompt\n * const response = await session.prompts.send({ content: 'Hello!' });\n *\n * // Cleanup\n * session.disconnect();\n * ```\n */\nexport class ActiveSessionImpl implements ActiveSession {\n private _id: string;\n private _agentId: string;\n private _availableModes?: SessionMode[];\n private _currentMode?: string;\n private _availableCommands: AvailableCommand[] = [];\n private logger?: Logger;\n private connection: AgentConnection;\n private _getFilesystem?: FilesystemGetter;\n private _connectionInfo?: SessionConnectionInfo;\n\n // Event emitter storage\n private listeners: Map<keyof SessionEvents, Set<EventListener<unknown>>> = new Map();\n private onceListeners: Map<keyof SessionEvents, Set<EventListener<unknown>>> = new Map();\n\n /**\n * Agent operations namespace\n */\n readonly agent: SessionAgentOperations;\n\n /**\n * Prompts resource namespace\n */\n readonly prompts: PromptsResource;\n\n /**\n * Artifacts resource namespace\n */\n readonly artifacts: ArtifactsResource;\n\n /**\n * Files resource namespace (lazily loaded via getter)\n */\n readonly files: FilesResource;\n\n /**\n * Create an ActiveSessionImpl instance\n *\n * @param sessionId - Session ID\n * @param agentId - Agent ID\n * @param connection - Already connected AgentConnection\n * @param options - Additional options\n */\n constructor(\n sessionId: string,\n agentId: string,\n connection: AgentConnection,\n options: ActiveSessionImplOptions = {}\n ) {\n this._id = sessionId;\n this._agentId = agentId;\n this.connection = connection;\n this.logger = options.logger;\n this._getFilesystem = options.getFilesystem;\n this._connectionInfo = options.connectionInfo;\n\n // Set up event forwarding from connection\n this.setupConnectionEvents(connection);\n\n // Initialize agent operations namespace\n this.agent = this.createAgentOperations();\n\n // Initialize resource namespaces\n this.prompts = this.createPromptsResource();\n this.artifacts = this.createArtifactsResource();\n this.files = this.createFilesResource();\n }\n\n // ============================================\n // Properties\n // ============================================\n\n /**\n * Session ID\n */\n get id(): string {\n return this._id;\n }\n\n /**\n * Agent ID\n */\n get agentId(): string {\n return this._agentId;\n }\n\n /**\n * Agent state (live connection state)\n * Returns LocalAgentState or CloudAgentState based on transport type\n */\n get agentState(): AgentState {\n return {\n id: this._agentId,\n status: this.connection.state as AgentStatus,\n capabilities: this.connection.capabilities,\n type: this.connection.transport,\n cwd: this.connection.cwd || ''\n }\n }\n\n /**\n * Get agent capabilities (available after connection)\n */\n get capabilities(): AgentCapabilities | undefined {\n return this.connection.capabilities;\n }\n\n /**\n * Available session modes\n */\n get availableModes(): SessionMode[] | undefined {\n return this._availableModes;\n }\n\n /**\n * Current session mode\n */\n get currentMode(): string | undefined {\n return this._currentMode;\n }\n\n /**\n * Available slash commands\n *\n * When Agent sends available_commands_update, this list is automatically updated.\n * Commands can be accessed directly without waiting for events.\n */\n get availableCommands(): AvailableCommand[] {\n return this._availableCommands;\n }\n\n /**\n * Check if the session is active\n */\n get isActive(): boolean {\n return this.connection.isInitialized;\n }\n\n /**\n * Session connection information (only available for cloud sessions)\n * 会话连接信息,包括sandboxId、link、token等\n */\n get connectionInfo(): SessionConnectionInfo | undefined {\n return this._connectionInfo;\n }\n\n /**\n * Set session modes (called after create/load)\n */\n setModes(availableModes?: SessionMode[], currentMode?: string): void {\n this._availableModes = availableModes;\n this._currentMode = currentMode;\n }\n\n // ============================================\n // Agent Operations Namespace\n // ============================================\n\n private createAgentOperations(): SessionAgentOperations {\n const self = this;\n return {\n get id(): string {\n return self._agentId;\n },\n get state(): AgentState {\n return self.agentState;\n },\n get isConnected(): boolean {\n return self.connection.isInitialized;\n },\n get capabilities(): AgentCapabilities | undefined {\n return self.connection.capabilities;\n }\n };\n }\n\n // ============================================\n // Prompts Resource\n // ============================================\n\n private createPromptsResource(): PromptsResource {\n return {\n send: async (params: PromptParams): Promise<PromptResponse> => {\n const connection = this.getConnectionOrThrow();\n const response = await connection.prompt(this._id, params);\n return this.mapPromptResponse(response);\n },\n\n stream: (params: PromptParams): AsyncIterable<SessionNotification> => {\n const connection = this.getConnectionOrThrow();\n return connection.promptStream(this._id, params);\n },\n\n cancel: async (): Promise<void> => {\n const connection = this.getConnectionOrThrow();\n await connection.cancel(this._id);\n }\n };\n }\n\n // ============================================\n // Artifacts Resource\n // ============================================\n\n private createArtifactsResource(): ArtifactsResource {\n // Artifact management has been simplified - these methods are no longer supported\n const notSupported = () => {\n throw new Error('Artifact management is no longer supported through this API');\n };\n\n return {\n list: async (_params?: { type?: ArtifactType }): Promise<Artifact[]> => {\n notSupported();\n return [];\n },\n\n retrieve: async (_artifactId: string): Promise<Artifact> => {\n notSupported();\n return undefined as unknown as Artifact;\n },\n\n content: async (_artifactId: string): Promise<string> => {\n notSupported();\n return '';\n }\n };\n }\n\n // ============================================\n // Files Resource\n // ============================================\n\n /**\n * Create files resource with lazy-loaded filesystem\n *\n * The filesystem is lazily loaded on first use to avoid unnecessary\n * connections to the sandbox. The actual filesystem instance is obtained\n * via the getter function provided by SessionManager.\n */\n private createFilesResource(): FilesResource {\n const self = this;\n let filesPromise: Promise<FilesResource> | null = null;\n\n /**\n * Get or create the filesystem instance\n */\n const getFs = async (): Promise<FilesResource> => {\n if (!self._getFilesystem) {\n throw new Error('Filesystem not available: provider does not support filesystem operations');\n }\n if (!filesPromise) {\n filesPromise = self._getFilesystem();\n }\n return filesPromise;\n };\n\n return {\n // Read operations - 支持多种格式重载\n read: (async (path: string, opts?: any) => (await getFs()).read(path, opts)) as FilesResource['read'],\n\n // Write operations - 支持单文件和批量写入重载\n write: (async (pathOrFiles: any, dataOrOpts?: any, opts?: any) => {\n const fs = await getFs();\n if (Array.isArray(pathOrFiles)) {\n // Batch write\n return fs.write(pathOrFiles, dataOrOpts);\n }\n // Single file write\n return fs.write(pathOrFiles, dataOrOpts, opts);\n }) as FilesResource['write'],\n\n // List with depth support\n list: async (path, opts) => (await getFs()).list(path, opts),\n exists: async (path, opts) => (await getFs()).exists(path, opts),\n makeDir: async (path, opts) => (await getFs()).makeDir(path, opts),\n remove: async (path, opts) => (await getFs()).remove(path, opts),\n rename: async (oldPath, newPath, opts) => (await getFs()).rename(oldPath, newPath, opts),\n\n // 新增 getInfo 方法\n getInfo: async (path, opts) => (await getFs()).getInfo(path, opts),\n\n // Watch operations - 支持扩展的 opts\n watchDir: async (path, onEvent, opts) => (await getFs()).watchDir(path, onEvent, opts)\n };\n }\n\n // ============================================\n // Permission Management\n // ============================================\n\n /**\n * Resolve a permission request\n */\n resolvePermission(requestId: string, optionId: string): boolean {\n return this.connection.resolvePermission(requestId, optionId);\n }\n\n /**\n * Reject a permission request\n */\n rejectPermission(requestId: string, reason?: string): boolean {\n return this.connection.rejectPermission(requestId, reason);\n }\n\n // ============================================\n // Question Management (ask_followup_question)\n // ============================================\n\n /**\n * Answer a question request with user's selections\n */\n answerQuestion(toolCallId: string, answers: QuestionAnswers): boolean {\n return this.connection.answerQuestion(toolCallId, answers);\n }\n\n /**\n * Cancel a question request\n */\n cancelQuestion(toolCallId: string, reason?: string): boolean {\n return this.connection.cancelQuestion(toolCallId, reason);\n }\n\n // ============================================\n // Tool Callback Management\n // ============================================\n\n /**\n * Callback for tool operations (skip or cancel)\n * @param toolCallId Tool call ID\n * @param toolName Tool name\n * @param action Action to perform ('skip' or 'cancel')\n */\n async toolCallback(toolCallId: string, toolName: string, action: 'skip' | 'cancel'): Promise<{ success: boolean; error?: string }> {\n const connection = this.getConnectionOrThrow();\n return await connection.toolCallback(this._id, toolCallId, toolName, action);\n }\n\n // ============================================\n // Session Mode Management\n // ============================================\n\n /**\n * Set the current session mode\n *\n * @param modeId - The mode ID to switch to (must be in availableModes)\n * @throws Error if modeId is not in availableModes or connection fails\n *\n * @example\n * ```typescript\n * // Switch to 'code' mode\n * await session.setMode('code');\n *\n * // Switch to 'architect' mode\n * await session.setMode('architect');\n * ```\n */\n async setMode(modeId: string): Promise<void> {\n // Validate modeId if availableModes is set\n if (this._availableModes) {\n const modeExists = this._availableModes.some(m => m.id === modeId);\n if (!modeExists) {\n const availableIds = this._availableModes.map(m => m.id).join(', ');\n throw new Error(`Invalid modeId: \"${modeId}\". Available modes: ${availableIds}`);\n }\n }\n\n const connection = this.getConnectionOrThrow();\n await connection.setSessionMode(this._id, modeId);\n\n // Update internal state\n this._currentMode = modeId;\n }\n\n /**\n * Set the current session model\n *\n * @param modelId - The model ID to switch to\n * @example\n * ```typescript\n * // Switch to Claude Sonnet 4\n * await session.setSessionModel('claude-sonnet-4-20250514');\n *\n * // Switch to GPT-4o\n * await session.setSessionModel('gpt-4o');\n * ```\n */\n async setSessionModel(modelId: string): Promise<void> {\n const connection = this.getConnectionOrThrow();\n await connection.setSessionModel(this._id, modelId);\n }\n\n // ============================================\n // Event Subscription\n // ============================================\n\n /**\n * Subscribe to session events\n */\n on<K extends keyof SessionEvents>(event: K, handler: SessionEventHandler<K>): this {\n if (!this.listeners.has(event)) {\n this.listeners.set(event, new Set());\n }\n this.listeners.get(event)!.add(handler as EventListener<unknown>);\n return this;\n }\n\n /**\n * Unsubscribe from session events\n */\n off<K extends keyof SessionEvents>(event: K, handler: SessionEventHandler<K>): this {\n const eventListeners = this.listeners.get(event);\n if (eventListeners) {\n eventListeners.delete(handler as EventListener<unknown>);\n }\n const onceEventListeners = this.onceListeners.get(event);\n if (onceEventListeners) {\n onceEventListeners.delete(handler as EventListener<unknown>);\n }\n return this;\n }\n\n /**\n * Subscribe to a session event once\n */\n once<K extends keyof SessionEvents>(event: K, handler: SessionEventHandler<K>): this {\n if (!this.onceListeners.has(event)) {\n this.onceListeners.set(event, new Set());\n }\n this.onceListeners.get(event)!.add(handler as EventListener<unknown>);\n return this;\n }\n\n /**\n * Emit an event to all registered listeners\n */\n private emit<K extends keyof SessionEvents>(event: K, data: SessionEvents[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 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(`Error in async once event listener for '${String(event)}':`, err);\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\n */\n private removeAllListeners<K extends keyof SessionEvents>(event?: K): void {\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 }\n\n // ============================================\n // Lifecycle\n // ============================================\n\n /**\n * Disconnect from the session/agent\n */\n disconnect(): void {\n this.connection.disconnect();\n this.removeAllListeners();\n this.logger?.info(`Session ${this._id}: Disconnected`);\n }\n\n /**\n * Symbol.dispose for 'using' keyword support\n * Automatically disconnects and cleans up when session goes out of scope\n *\n * @example\n * ```typescript\n * {\n * using session = await client.sessions.new({ cwd: '/workspace' });\n * // ... use session\n * } // session automatically disposed\n * ```\n */\n [Symbol.dispose](): void {\n this.disconnect();\n }\n\n // ============================================\n // Helpers\n // ============================================\n\n private getConnectionOrThrow(): AgentConnection {\n if (!this.connection.isInitialized) {\n throw new Error(`Session ${this._id}: Connection not initialized.`);\n }\n return this.connection;\n }\n\n private setupConnectionEvents(connection: AgentConnection): void {\n // Connection lifecycle events\n connection.on('connected', () => {\n this.emit('connected', undefined as never);\n });\n\n connection.on('disconnected', () => {\n this.emit('disconnected', undefined as never);\n });\n\n connection.on('error', (error) => {\n this.emit('error', error);\n });\n\n // Session updates\n connection.on('sessionUpdate', (update) => {\n this.emit('sessionUpdate', update);\n });\n\n // Artifact events\n connection.on('artifactCreated', (artifact) => {\n console.log('[Session] Forwarding artifactCreated:', {\n artifactUri: artifact.uri,\n artifactType: artifact.type,\n });\n this.emit('artifactCreated', artifact);\n });\n\n connection.on('artifactUpdated', (artifact) => {\n console.log('[Session] Forwarding artifactUpdated:', {\n artifactUri: artifact.uri,\n artifactType: artifact.type,\n });\n this.emit('artifactUpdated', artifact);\n });\n\n connection.on('artifactDeleted', (artifact) => {\n console.log('[Session] Forwarding artifactDeleted:', { artifactUri: artifact.uri });\n this.emit('artifactDeleted', artifact);\n });\n\n // Permission requests\n connection.on('permissionRequest', (request) => {\n this.emit('permissionRequest', request);\n });\n\n // Question requests\n connection.on('questionRequest', (request) => {\n this.emit('questionRequest', request);\n });\n\n // Usage updates\n connection.on('usageUpdate', (usage) => {\n this.emit('usageUpdate', usage);\n });\n\n // Checkpoint events\n connection.on('checkpointCreated', (checkpoint) => {\n this.emit('checkpointCreated', checkpoint);\n });\n\n connection.on('checkpointUpdated', (checkpoint) => {\n this.emit('checkpointUpdated', checkpoint);\n });\n }\n\n private mapPromptResponse(response: SdkPromptResponse): PromptResponse {\n return {\n stopReason: response.stopReason as PromptResponse['stopReason'],\n _meta: response._meta ?? undefined\n };\n }\n}\n","/**\n * SessionManager - Manages session lifecycle and connections\n *\n * Provides the core implementation for session-centric API operations:\n * - list() - Lists sessions (mapped from agents)\n * - createSession() - Creates new session (auto-creates agent)\n * - loadSession() - Loads existing session (finds agent by sessionId)\n */\n\nimport type {\n AgentProvider,\n SessionInfo,\n CreateSessionParams,\n LoadSessionParams,\n ActiveSession,\n Logger,\n ListAgentOptions,\n ListAgentResult\n} from './types.js';\nimport { ActiveSessionImpl } from './session.js';\n\n/**\n * Options for creating a SessionManager instance\n */\nexport interface SessionManagerOptions {\n /** Agent provider (required) */\n provider: AgentProvider;\n /** Logger instance */\n logger?: Logger;\n}\n\n/**\n * SessionManager - Session lifecycle management\n *\n * This class manages the relationship between sessions and agents.\n * Since the backend is agent-centric, SessionManager handles the mapping:\n * - Sessions are views over agents\n * - sessionId may equal agentId in simple cases\n *\n * Features:\n * - Session caching: reuses existing ActiveSession instances\n * - Automatic cleanup on session disconnect\n *\n * @example\n * ```typescript\n * const manager = new SessionManager({ provider, logger });\n *\n * // List sessions\n * const sessions = await manager.listSessions();\n *\n * // Create new session\n * const session = await manager.createSession({ cwd: '/workspace' });\n *\n * // Load existing session (returns cached instance if available)\n * const loaded = await manager.loadSession({ sessionId: 'xxx', cwd: '/workspace' });\n * ```\n */\nexport class SessionManager {\n private provider: AgentProvider;\n private logger?: Logger;\n\n constructor(options: SessionManagerOptions) {\n this.provider = options.provider;\n this.logger = options.logger;\n }\n\n /**\n * List all sessions with pagination info (mapped from agents)\n *\n * Each agent maps to a session. The sessionId is derived from the agent.\n * Cloud: Returns server-side filtered/sorted/paginated results\n * Local: Returns client-side filtered/sorted results (synthetic pagination)\n *\n * @param options - Optional query parameters for filtering, sorting, and pagination\n */\n async listSessions(options?: ListAgentOptions): Promise<ListAgentResult<SessionInfo>> {\n console.log('[SessionManager] listSessions called with options:', JSON.stringify(options, null, 2));\n\n const result = await this.provider.list(options);\n console.log('[SessionManager] provider.list returned:', {\n agentsCount: result.agents.length,\n pagination: result.pagination\n });\n\n const sessions = result.agents.map(agent => ({\n // Use agentId as sessionId (since sessions are 1:1 with agents in current design)\n id: agent.id,\n agentId: agent.id,\n name: agent.name,\n status: agent.status,\n createdAt: agent.createdAt,\n lastActivityAt: agent.updatedAt,\n // cwd is only available for local agents\n cwd: agent.type === 'local' ? agent.cwd : undefined\n }));\n\n console.log('[SessionManager] Returning sessions:', { count: sessions.length, pagination: result.pagination });\n return {\n agents: sessions,\n pagination: result.pagination\n };\n }\n\n /**\n * Create a new session\n *\n * Steps:\n * 1. Create new agent (if provider supports it) or use existing\n * 2. Connect to agent\n * 3. Call ACP newSession\n * 4. Register session mapping (for LocalAgentProvider)\n * 5. Return ActiveSession instance\n */\n async createSession(params: CreateSessionParams): Promise<ActiveSession> {\n this.logger?.info('Creating new session');\n\n // Step 1: Create new agent if provider supports it\n let agentId: string;\n\n if (this.provider.create) {\n // Pass params to create() - LocalAgentProvider uses cwd as agentId\n agentId = await this.provider.create(params);\n this.logger?.debug(`Created new agent: ${agentId}`);\n } else {\n // If provider doesn't support create, we need to throw\n // The provider must support creating agents for sessions.new()\n throw new Error('Provider does not support creating agents. Use sessions.load() with an existing sessionId.');\n }\n\n // Step 2: Connect to agent\n const connection = await this.provider.connect(agentId);\n this.logger?.debug(`Connected to agent: ${agentId}`);\n\n // Step 3: Create session via ACP\n const response = await connection.createSession({\n cwd: params.cwd,\n mcpServers: params.mcpServers\n });\n\n // Step 4: Register session mapping (for LocalAgentProvider to support loadSession)\n if (this.provider.registerSession) {\n this.provider.registerSession(response.sessionId, agentId);\n this.logger?.debug(`Registered session mapping: ${response.sessionId} → ${agentId}`);\n }\n\n // Step 5: Create and return ActiveSession\n // Get connectionInfo from CloudAgentConnection if available\n const connectionInfo = (connection as any).sessionConnectionInfo;\n\n const session = new ActiveSessionImpl(\n response.sessionId,\n agentId,\n connection,\n {\n logger: this.logger,\n // Bind sessionId (not agentId) to create a getter function for filesystem\n // Note: conversation-channel-router binds sessionId to windowId,\n // so we must use sessionId for filesystem routing\n getFilesystem: this.provider.filesystem\n ? () => this.provider.filesystem!.getFilesystem(response.sessionId)\n : undefined,\n // Pass connectionInfo from CloudAgentConnection (if available)\n connectionInfo\n }\n );\n\n // Set modes from response\n session.setModes(\n response.modes?.availableModes,\n response.modes?.currentModeId\n );\n\n this.logger?.info(`Session created: ${response.sessionId}`);\n return session;\n }\n\n /**\n * Load an existing session\n *\n * Steps:\n * 1. Check cache for existing session\n * 2. Find agent by sessionId (sessionId === agentId in current design)\n * 3. Connect to agent\n * 4. Call ACP loadSession\n * 5. Return ActiveSession instance (cached)\n */\n async loadSession(params: LoadSessionParams): Promise<ActiveSession> {\n this.logger?.info(`Loading session: ${params.sessionId}`);\n\n // Step 2: Find agent by sessionId\n // In current design, sessionId === agentId\n const agentId = params.sessionId;\n\n // Verify agent exists\n const agentState = await this.provider.get(agentId);\n if (!agentState) {\n throw new Error(`Session not found: ${params.sessionId}`);\n }\n\n // Step 3: Connect to agent\n const connection = await this.provider.connect(agentId);\n this.logger?.debug(`Connected to agent: ${agentId}`);\n\n // Step 4: Load session via ACP\n const response = await connection.loadSession({\n sessionId: params.sessionId,\n cwd: agentState.type === 'local' ? agentState.cwd : params.cwd,\n mcpServers: params.mcpServers\n });\n\n // Step 5: Create and return ActiveSession\n // Get connectionInfo from CloudAgentConnection if available\n const connectionInfo = (connection as any).sessionConnectionInfo;\n\n const session = new ActiveSessionImpl(\n params.sessionId,\n agentId,\n connection,\n {\n logger: this.logger,\n // Bind sessionId (not agentId) to create a getter function for filesystem\n // Note: conversation-channel-router binds sessionId to windowId,\n // so we must use sessionId for filesystem routing\n getFilesystem: this.provider.filesystem\n ? () => this.provider.filesystem!.getFilesystem(params.sessionId)\n : undefined,\n // Pass connectionInfo from CloudAgentConnection (if available)\n connectionInfo\n }\n );\n\n // Set modes from response\n session.setModes(\n response.modes?.availableModes,\n response.modes?.currentModeId\n );\n\n this.logger?.info(`Session loaded: ${params.sessionId}`);\n return session;\n }\n}\n","/**\n * AgentClient - Session-centric API\n *\n * Provides a unified entry point for managing sessions.\n * Sessions are the primary API surface; agents are internal implementation.\n */\n\nimport type {\n AgentClientOptions,\n ClientSessionsResource,\n AgentProvider,\n Logger,\n ModelsResource,\n InitializeWorkspaceParams,\n InitializeWorkspaceResponse,\n WorkspaceInfo,\n SessionsResourceEvents,\n SessionsResourceEventHandler,\n ListAgentOptions,\n PickFileParams,\n PickFileResponse,\n PickFolderParams,\n PickFolderResponse,\n UploadFileParams,\n UploadFileResponse,\n SearchFileParams,\n SearchFileResponse\n} from './types.js';\nimport type { ModelInfo } from '../types.js';\nimport { SessionManager } from './session-manager.js';\n\n// ============================================\n// AgentClient - Session-Centric API\n// ============================================\n\n/**\n * AgentClient - Session-centric client\n *\n * Provides a session-centric API that internally manages agents.\n * Users interact with sessions; the agent lifecycle is handled internally.\n *\n * @example\n * ```typescript\n * // Create client with a provider\n * const provider = new CloudAgentProvider({\n * endpoint: 'https://api.example.com',\n * authToken: 'token'\n * });\n *\n * const client = new AgentClient({\n * provider,\n * logger: console\n * });\n *\n * // List all sessions\n * const sessions = await client.sessions.list();\n *\n * // Create new session (auto-creates agent and connects)\n * const session = await client.sessions.create({ cwd: '/workspace' });\n * console.log(session.agentState.status); // agent status\n * console.log(session.agentState.id); // agent ID\n *\n * // Send prompt\n * await session.prompts.send({ content: 'Hello' });\n *\n * // Get available models\n * const models = await client.sessions.models.list('my-repo');\n *\n * // Use 'using' keyword for automatic cleanup\n * {\n * using session = await client.sessions.create({ cwd: '/workspace' });\n * // ... use session\n * } // session automatically disposed\n *\n * // Or manually disconnect\n * session.disconnect();\n *\n * // Load existing session\n * const loadedSession = await client.sessions.load({\n * sessionId: 'xxx',\n * cwd: '/workspace'\n * });\n * ```\n */\nexport class AgentClient {\n private logger?: Logger;\n private provider: AgentProvider;\n private sessionManager: SessionManager;\n\n /**\n * Sessions resource namespace (primary API entry point)\n */\n readonly sessions: ClientSessionsResource;\n\n /**\n * 运行环境类型\n * - 'local': IDE 本地环境\n * - 'cloud': 云端环境\n */\n readonly environmentType: 'local' | 'cloud';\n\n constructor(options: AgentClientOptions) {\n this.logger = options.logger;\n this.provider = options.provider;\n this.environmentType = options.environmentType ?? 'cloud';\n\n // Initialize session manager\n this.sessionManager = new SessionManager({\n provider: this.provider,\n logger: this.logger\n });\n\n // Initialize sessions resource\n this.sessions = this.createSessionsResource();\n }\n\n // ============================================\n // Sessions Resource\n // ============================================\n\n private createSessionsResource(): ClientSessionsResource {\n return {\n list: async (options?: ListAgentOptions) => {\n return this.sessionManager.listSessions(options);\n },\n\n create: async (params) => {\n return this.sessionManager.createSession(params);\n },\n\n load: async (params) => {\n console.log('[AgentClient] sessions.load called:', params.sessionId);\n return this.sessionManager.loadSession(params);\n },\n\n archive: async (sessionId: string): Promise<{ id: string }> => {\n this.logger?.debug('AgentClient.sessions.archive called', { sessionId });\n\n try {\n // Check if provider supports archive\n if (this.provider.archive) {\n const result = await this.provider.archive(sessionId);\n this.logger?.info('Session archived successfully', { sessionId });\n return result;\n }\n\n // If provider does not support archive, throw error\n throw new Error('Provider does not support archive method');\n } catch (error) {\n this.logger?.error('Failed to archive session', error);\n throw error;\n }\n },\n\n rename: async (sessionId: string, title: string): Promise<{ id: string }> => {\n this.logger?.debug('AgentClient.sessions.rename called', { sessionId, title });\n\n try {\n // Check if provider supports rename\n if (this.provider.rename) {\n const result = await this.provider.rename(sessionId, title);\n this.logger?.info('Session renamed successfully', { sessionId, title });\n return result;\n }\n\n // If provider does not support rename, throw error\n throw new Error('Provider does not support rename method');\n } catch (error) {\n this.logger?.error('Failed to rename session', error);\n throw error;\n }\n },\n\n // Initialize workspace for future sessions\n initializeWorkspace: async (params: InitializeWorkspaceParams): Promise<InitializeWorkspaceResponse> => {\n this.logger?.debug('AgentClient.sessions.initializeWorkspace called', params);\n\n try {\n // openWorkspace 是 LocalAgentProvider 特有的能力\n if (this.provider.openWorkspace) {\n const result = await this.provider.openWorkspace(params);\n this.logger?.info('Workspace opened successfully', { cwd: params.cwd });\n return result;\n }\n\n // 如果 provider 不支持 openWorkspace,返回成功(向后兼容)\n this.logger?.warn('Provider does not support openWorkspace');\n return { success: true };\n\n } catch (error) {\n this.logger?.error('Failed to initialize workspace', error);\n return {\n success: false,\n error: error instanceof Error ? error.message : 'Unknown error'\n };\n }\n },\n\n // Get current workspaces list\n getCurrentWorkspaces: async (filter?: { activeOnly?: boolean }): Promise<WorkspaceInfo[]> => {\n this.logger?.debug('AgentClient.sessions.getCurrentWorkspaces called', filter);\n\n try {\n // getCurrentWorkspaces 是 LocalAgentProvider 特有的能力\n if ('getCurrentWorkspaces' in this.provider && typeof this.provider.getCurrentWorkspaces === 'function') {\n const result = await this.provider.getCurrentWorkspaces(filter);\n this.logger?.info('Current workspaces retrieved', { count: result.length });\n return result;\n }\n\n // 如果 provider 不支持 getCurrentWorkspaces,返回空数组(向后兼容)\n this.logger?.warn('Provider does not support getCurrentWorkspaces');\n return [];\n\n } catch (error) {\n this.logger?.error('Failed to get current workspaces', error);\n return [];\n }\n },\n\n\n // Event methods - forward to provider if supported\n on: <K extends keyof SessionsResourceEvents>(\n event: K,\n handler: SessionsResourceEventHandler<K>\n ): void => {\n if (this.provider.on) {\n this.provider.on(event as string, handler as (...args: any[]) => void);\n } else {\n this.logger?.warn(`Provider does not support event registration: ${String(event)}`);\n }\n },\n\n off: <K extends keyof SessionsResourceEvents>(\n event: K,\n handler: SessionsResourceEventHandler<K>\n ): void => {\n if (this.provider.off) {\n this.provider.off(event as string, handler as (...args: any[]) => void);\n } else {\n this.logger?.warn(`Provider does not support event unregistration: ${String(event)}`);\n }\n },\n \n openWorkspace: async (params: InitializeWorkspaceParams): Promise<InitializeWorkspaceResponse> => {\n try {\n if (this.provider && this.provider.openWorkspace) {\n const result = await this.provider.openWorkspace(params);\n this.logger?.info('Workspace opened successfully', { cwd: params.cwd });\n return result;\n }\n return { success: false, error: 'Provider does not support openWorkspace' };\n } catch (error) {\n this.logger?.error('Failed to open workspace', error);\n return {\n success: false,\n error: error instanceof Error ? error.message : 'Unknown error'\n };\n }\n },\n\n pickFile: async (params?: PickFileParams): Promise<PickFileResponse> => {\n try {\n if (this.provider && this.provider.pickFile) {\n const result = await this.provider.pickFile(params);\n this.logger?.info('File picker completed', { fileCount: result.files.length, canceled: result.canceled });\n return result;\n }\n return { files: [], canceled: true, error: 'Provider does not support pickFile' };\n } catch (error) {\n this.logger?.error('Failed to pick file', error);\n return {\n files: [],\n canceled: true,\n error: error instanceof Error ? error.message : 'Unknown error'\n };\n }\n },\n\n pickFolder: async (params?: PickFolderParams): Promise<PickFolderResponse> => {\n try {\n if (this.provider && this.provider.pickFolder) {\n const result = await this.provider.pickFolder(params);\n this.logger?.info('Folder picker completed', { folderPaths: result.folderPaths, canceled: result.canceled });\n return result;\n }\n return { folderPaths: [], canceled: true, error: 'Provider does not support pickFolder' };\n } catch (error) {\n this.logger?.error('Failed to pick folder', error);\n return {\n folderPaths: [],\n canceled: true,\n error: error instanceof Error ? error.message : 'Unknown error'\n };\n }\n },\n\n uploadFile: async (params: UploadFileParams): Promise<UploadFileResponse> => {\n try {\n if (this.provider && this.provider.uploadFile) {\n const result = await this.provider.uploadFile(params);\n this.logger?.info('File upload completed', { count: params.files.length, success: result.success });\n return result;\n }\n return { success: false, error: 'Provider does not support uploadFile' };\n } catch (error) {\n this.logger?.error('Failed to upload file', error);\n return {\n success: false,\n error: error instanceof Error ? error.message : 'Unknown error'\n };\n }\n },\n\n searchFile: async (params: SearchFileParams): Promise<SearchFileResponse> => {\n try {\n if (this.provider && this.provider.searchFile) {\n const result = await this.provider.searchFile(params);\n this.logger?.info('File search completed', { resultCount: result.results.length, hasError: !!result.error });\n return result;\n }\n return { results: [], error: 'Provider does not support searchFile' };\n } catch (error) {\n this.logger?.error('Failed to search file', error);\n return {\n results: [],\n error: error instanceof Error ? error.message : 'Unknown error'\n };\n }\n },\n\n // Models resource - delegates to provider's getModels method\n models: this.createModelsResource(),\n };\n }\n\n private createModelsResource(): ModelsResource {\n return {\n list: async (repo: string): Promise<ModelInfo[]> => {\n // Check if provider supports getModels\n if (this.provider.getModels) {\n return this.provider.getModels(repo);\n }\n throw new Error('Provider does not support getModels method');\n }\n };\n }\n\n // ============================================\n // Lifecycle\n // ============================================\n\n /**\n * Dispose the client\n *\n * Note: Active sessions are not automatically disposed.\n * The caller is responsible for disconnecting sessions they created.\n */\n dispose(): void {\n this.logger?.info('AgentClient disposed');\n }\n}\n\nexport default AgentClient;\n","/**\n * API type definitions for AgentClient\n * Session-centric API design\n */\n\nimport type { SessionNotification, RequestPermissionRequest } from '@agentclientprotocol/sdk';\nimport type {\n Artifact,\n ArtifactType,\n ArtifactEvent,\n UsageUpdate,\n ClientEvents,\n EventListener,\n CheckpointInfo,\n QuestionRequest,\n QuestionAnswers\n} from '@genie/agent-client-protocol';\nimport type {\n Agent as AgentInfo,\n AgentConnection,\n AgentStatus,\n Session,\n SessionMode,\n PromptParams,\n PromptContentBlock,\n AgentCapabilities,\n ClientCapabilities,\n ArtifactTypeConfig,\n ArtifactsConfig,\n CodebuddyClientMeta,\n CodebuddyAgentMeta,\n FilesResource,\n FilesystemProvider,\n McpServerConfig,\n E2BSandboxConnectionInfo,\n // e2b SDK types (re-exported from types.js)\n EntryInfo,\n Filesystem,\n // Model types\n ModelInfo\n} from '../types.js';\nimport type { AvailableCommand } from '../providers/local-agent-provider/acp/types.js';\n\n// Re-export commonly used types\nexport type {\n AgentInfo,\n AgentConnection,\n AgentStatus,\n Session,\n SessionMode,\n PromptParams,\n PromptContentBlock,\n AgentCapabilities,\n ClientCapabilities,\n // codebuddy.ai extension types\n ArtifactTypeConfig,\n ArtifactsConfig,\n CodebuddyClientMeta,\n CodebuddyAgentMeta,\n // Other types\n Artifact,\n ArtifactType,\n ArtifactEvent,\n UsageUpdate,\n ClientEvents,\n EventListener,\n SessionNotification,\n RequestPermissionRequest,\n QuestionRequest,\n QuestionAnswers,\n // Filesystem types\n FilesResource,\n FilesystemProvider,\n McpServerConfig,\n E2BSandboxConnectionInfo,\n // e2b SDK types (re-exported from types.js)\n EntryInfo,\n Filesystem,\n // Model types\n ModelInfo,\n // ACP types\n AvailableCommand\n};\n\n\n// ============================================\n// Session Connection Info (for cloud sessions)\n// ============================================\n\n/**\n * Session connection information\n * 包含连接到Agent会话所需的所有信息,包括sandbox连接凭证\n */\nexport interface SessionConnectionInfo {\n /** Session ID */\n sessionId: string;\n /** Agent ID */\n agentId: string;\n /** Session endpoint URL (Agent的WebSocket/HTTP端点) */\n link: string;\n /** Session token (JWT格式的认证令牌) */\n token: string;\n /** Sandbox ID (E2B沙箱的唯一标识) */\n sandboxId: string;\n /** Session expiration timestamp (unix timestamp) */\n expireAt: number;\n /** Current working directory (optional) */\n cwd?: string;\n}\n\n// ============================================\n// Agent State (Unified agent state object)\n// ============================================\n\n/**\n * Agent 来源类型\n */\nexport type AgentStateType = 'local' | 'cloud';\n\n/**\n * 云端 Agent 可见性\n */\nexport type CloudAgentVisibility = 'PRIVATE' | 'PUBLIC' | 'TEAM';\n\n/**\n * 云端 Agent 来源信息\n */\nexport interface CloudAgentSourceInfo {\n /** 提供商: github, gitlab 等 */\n provider: string;\n /** 分支/引用 */\n ref: string;\n /** 仓库路径 */\n repository: string;\n}\n\n/**\n * 云端 Agent 目标信息\n */\nexport interface CloudAgentTarget {\n /** 是否自动创建 PR */\n autoCreatePr: boolean;\n /** 分支名称 */\n branchName?: string;\n /** PR URL */\n prUrl?: string;\n /** Agent URL */\n url?: string;\n}\n\n/**\n * AgentState 基础接口\n * 所有类型的 AgentState 都必须实现此接口\n */\nexport interface BaseAgentState {\n /** Unique agent ID */\n id: string;\n /** Display name */\n name?: string;\n /** Description */\n description?: string;\n /** Agent type */\n type: AgentStateType;\n /** Current connection status */\n status: AgentStatus;\n /** Agent capabilities (available after connection) */\n capabilities?: AgentCapabilities;\n /** When the agent was created */\n createdAt?: Date;\n /** When the agent was last updated */\n updatedAt?: Date;\n}\n\n/**\n * LocalAgentState - 本地 Agent 状态\n * 来自本地 IPC 通信的 Agent\n */\nexport interface LocalAgentState extends BaseAgentState {\n type: 'local';\n /** 工作目录 */\n cwd: string;\n}\n\n/**\n * CloudAgentState - 云端 Agent 状态\n * 来自远程 API 的云端实例\n */\nexport interface CloudAgentState extends BaseAgentState {\n type: 'cloud';\n}\n\n/**\n * AgentState - Unified agent state object exposed to client users\n *\n * This is the primary way clients access agent information.\n * Uses discriminated union pattern to distinguish between local and cloud agents.\n */\nexport type AgentState = LocalAgentState | CloudAgentState;\n\n/**\n * 类型守卫:判断是否为 LocalAgentState\n */\nexport function isLocalAgentState(state: AgentState): state is LocalAgentState {\n return state.type === 'local';\n}\n\n/**\n * 类型守卫:判断是否为 CloudAgentState\n */\nexport function isCloudAgentState(state: AgentState): state is CloudAgentState {\n return state.type === 'cloud';\n}\n\n/**\n * Logger interface\n */\nexport interface Logger {\n debug(message: string, ...args: unknown[]): void;\n info(message: string, ...args: unknown[]): void;\n warn(message: string, ...args: unknown[]): void;\n error(message: string, ...args: unknown[]): void;\n}\n\n// ============================================\n// Agent List Query Options\n// ============================================\n\n/**\n * Filter condition for listing agents\n */\nexport interface ListAgentFilter {\n /** Filter field name (e.g., 'status', 'name') */\n field: string;\n /** Filter value (comma-separated for multiple values) */\n value: string;\n}\n\n/**\n * Sort options for listing agents\n */\nexport interface ListAgentSort {\n /** Sort field (e.g., 'createdAt', 'status') */\n orderBy: string;\n /** Sort direction */\n order?: 'asc' | 'desc';\n}\n\n/**\n * Query options for listing agents\n *\n * These options are supported by both CloudAgentProvider and LocalAgentProvider.\n * Cloud: Server-side filtering, sorting, and pagination\n * Local: Client-side filtering and sorting, no pagination (returns all)\n */\nexport interface ListAgentOptions {\n /**\n * Page number (starts from 1)\n * Cloud: Used for API pagination\n * Local: Ignored (returns all sessions)\n */\n page?: number;\n\n /**\n * Page size\n * Cloud: Number of items per page (default 20, max 100)\n * Local: Ignored (returns all sessions)\n */\n size?: number;\n\n /**\n * Sort options\n * Cloud: Sorts results by specified field and order\n * Local: Sorts results by specified field and order\n */\n sort?: ListAgentSort;\n\n /**\n * Filter conditions\n * Cloud: Filters results by specified field values\n * Local: Filters results by specified field values\n */\n filters?: ListAgentFilter[];\n\n /**\n * Day range filter (e.g., agents created in last N days)\n * Cloud: Filters by creation date\n * Local: Filters by creation date\n */\n dayRange?: number;\n\n /**\n * Title search keyword (matches agent title)\n * Cloud: Server-side search\n * Local: Client-side search\n */\n title?: string;\n}\n\n/**\n * Pagination metadata returned from list operations\n */\nexport interface PaginationInfo {\n /** Current page number (starts from 1) */\n page: number;\n /** Page size */\n size: number;\n /** Total number of items */\n total: number;\n /** Total number of pages */\n totalPages: number;\n /** Whether there is a next page */\n hasNext: boolean;\n /** Whether there is a previous page */\n hasPrev: boolean;\n}\n\n/**\n * Response from list operations that includes pagination\n */\nexport interface ListAgentResult<T = AgentState> {\n /** List of agent states or session info */\n agents: T[];\n /** Pagination information */\n pagination: PaginationInfo;\n}\n\n// ============================================\n// Session-Centric Types\n// ============================================\n\n/**\n * Session information (returned by list, mapped from Agent)\n */\nexport interface SessionInfo {\n /** Session ID (from agent.session) */\n id: string;\n /** Associated agent ID */\n agentId: string;\n /** Agent name */\n name?: string;\n /** Agent status */\n status: AgentStatus;\n /** When the session/agent was created */\n createdAt?: Date;\n /** Last activity timestamp */\n lastActivityAt?: Date;\n /** Working directory (for local agents) */\n cwd?: string;\n}\n\n/**\n * Parameters for creating a new session\n */\nexport interface CreateSessionParams {\n /** Working directory */\n cwd: string;\n /** MCP server configurations */\n mcpServers?: McpServerConfig[];\n}\n\n/**\n * Parameters for loading an existing session\n */\nexport interface LoadSessionParams {\n /** Session ID to load (required) */\n sessionId: string;\n /** Working directory */\n cwd: string;\n /** MCP server configurations */\n mcpServers?: McpServerConfig[];\n}\n\n/**\n * Parameters for initializing a workspace\n */\nexport interface InitializeWorkspaceParams {\n /** Working directory */\n cwd: string;\n /** MCP server configurations */\n mcpServers?: McpServerConfig[];\n /** Whether to activate the workspace window to foreground (default true) */\n needActivated?: boolean;\n}\n\n/**\n * Response for workspace initialization\n */\nexport interface InitializeWorkspaceResponse {\n /** Whether initialization was successful */\n success: boolean;\n /** Error message (if failed) */\n error?: string;\n}\n\n// ============================================\n// Resource Interfaces\n// ============================================\n\n/**\n * Prompts resource interface (ACP verbs)\n * Operations use the current session automatically\n */\nexport interface PromptsResource {\n /** Send a prompt and wait for completion */\n send(params: PromptParams): Promise<PromptResponse>;\n\n /** Stream a prompt (yields session updates) */\n stream(params: PromptParams): AsyncIterable<SessionNotification>;\n\n /** Cancel an ongoing prompt */\n cancel(): Promise<void>;\n}\n\n/**\n * Artifacts resource interface\n */\nexport interface ArtifactsResource {\n /** List all artifacts */\n list(params?: { type?: ArtifactType }): Promise<Artifact[]>;\n\n /** Get a single artifact */\n retrieve(artifactId: string): Promise<Artifact>;\n\n /** Get artifact content */\n content(artifactId: string): Promise<string>;\n}\n\n/**\n * Models resource interface\n */\nexport interface ModelsResource {\n /** Get available models for a repository */\n list(repo?: string): Promise<ModelInfo[]>;\n}\n\n// ============================================\n// Response Types\n// ============================================\n\n/**\n * Prompt response\n */\nexport interface PromptResponse {\n /** Stop reason */\n stopReason: 'end_turn' | 'max_tokens' | 'tool_use' | 'cancelled' | 'error';\n /** Response metadata */\n _meta?: Record<string, unknown>;\n}\n\n// ============================================\n// Sessions Resource Events (for ClientSessionsResource)\n// ============================================\n\n/**\n * Sessions resource events for monitoring session list changes\n */\nexport interface SessionsResourceEvents {\n /** Emitted when the sessions list changes (create, delete, update) */\n sessionsChanged: SessionInfo[];\n /** Emitted when a new session is created */\n sessionCreated: SessionInfo;\n /** Emitted when a session is deleted */\n sessionDeleted: { sessionId: string };\n /** Emitted when a session is updated (status change, etc.) */\n sessionUpdated: SessionInfo;\n}\n\n/**\n * Event handler type for sessions resource events\n */\nexport type SessionsResourceEventHandler<K extends keyof SessionsResourceEvents> = (\n data: SessionsResourceEvents[K]\n) => void | Promise<void>;\n\n// ============================================\n// Session Events (for ActiveSession)\n// ============================================\n\n/**\n * Session events for event subscription\n */\nexport interface SessionEvents {\n /** Emitted when session updates occur */\n sessionUpdate: SessionNotification;\n /** Emitted when an artifact is created */\n artifactCreated: Artifact;\n /** Emitted when an artifact is updated */\n artifactUpdated: Artifact;\n /** Emitted when an artifact is deleted */\n artifactDeleted: Artifact;\n /** Emitted when a permission request is received */\n permissionRequest: { requestId: string; params: RequestPermissionRequest };\n /** Emitted when a question request is received (ask_followup_question) */\n questionRequest: { toolCallId: string; request: QuestionRequest };\n /** Emitted when usage data is updated */\n usageUpdate: UsageUpdate;\n /** Emitted when a checkpoint is created */\n checkpointCreated: CheckpointInfo;\n /** Emitted when a checkpoint is updated */\n checkpointUpdated: CheckpointInfo;\n /** Emitted when connected to agent */\n connected: void;\n /** Emitted when disconnected from agent */\n disconnected: void;\n /** Emitted when an error occurs */\n error: Error;\n}\n\n/**\n * Event handler type for session events\n */\nexport type SessionEventHandler<K extends keyof SessionEvents> = (data: SessionEvents[K]) => void | Promise<void>;\n\n// ============================================\n// Active Session Interface\n// ============================================\n\n/**\n * Agent operations (accessed via session.agent)\n */\nexport interface SessionAgentOperations {\n /** Agent ID */\n readonly id: string;\n /** Agent state */\n readonly state: AgentState;\n /** Whether the agent is connected */\n readonly isConnected: boolean;\n /** Agent capabilities */\n readonly capabilities?: AgentCapabilities;\n}\n\n/**\n * Active Session interface\n * Represents an active session with its resources and operations\n *\n * Key design:\n * - Session is the primary API surface\n * - agentState provides direct access to underlying agent state\n * - disconnect() is called directly on session (not session.agent)\n */\nexport interface ActiveSession {\n /** Session ID */\n readonly id: string;\n /** Agent ID */\n readonly agentId: string;\n /** Agent state (direct access to underlying agent state) */\n readonly agentState: AgentState;\n /** Agent capabilities (available after connection) */\n readonly capabilities?: AgentCapabilities;\n /** Available session modes */\n readonly availableModes?: SessionMode[];\n /** Current session mode */\n readonly currentMode?: string;\n /** Available slash commands (updated via available_commands_update) */\n readonly availableCommands: AvailableCommand[];\n /** Whether the session is active */\n readonly isActive: boolean;\n /**\n * Session connection information (only available for cloud sessions)\n * 会话连接信息,包括sandboxId、link、token等\n */\n readonly connectionInfo?: SessionConnectionInfo;\n\n // Agent operations namespace (optional agent-level access)\n /** Agent operations */\n readonly agent: SessionAgentOperations;\n\n // ACP Resources\n /** Prompts resource */\n readonly prompts: PromptsResource;\n /** Artifacts resource */\n readonly artifacts: ArtifactsResource;\n /** Files resource */\n readonly files: FilesResource;\n\n // Permission management\n /** Resolve a permission request */\n resolvePermission(requestId: string, optionId: string): boolean;\n /** Reject a permission request */\n rejectPermission(requestId: string, reason?: string): boolean;\n\n // Question management (ask_followup_question)\n /** Answer a question request with user's selections */\n answerQuestion(toolCallId: string, answers: QuestionAnswers): boolean;\n /** Cancel a question request */\n cancelQuestion(toolCallId: string, reason?: string): boolean;\n\n // Tool callback management\n /** Callback for tool operations (skip or cancel) */\n toolCallback(toolCallId: string, toolName: string, action: 'skip' | 'cancel'): Promise<{ success: boolean; error?: string }>;\n\n // Session mode management\n /** Set the current session mode */\n setMode(modeId: string): Promise<void>;\n /** Set the current session model */\n setSessionModel(modelId: string): Promise<void>;\n\n // Event subscription\n /** Subscribe to an event */\n on<K extends keyof SessionEvents>(event: K, handler: SessionEventHandler<K>): this;\n /** Unsubscribe from an event */\n off<K extends keyof SessionEvents>(event: K, handler: SessionEventHandler<K>): this;\n /** Subscribe to an event once */\n once<K extends keyof SessionEvents>(event: K, handler: SessionEventHandler<K>): this;\n\n // Lifecycle - disconnect directly on session\n /** Disconnect from the session/agent */\n disconnect(): void;\n\n /** Symbol.dispose for 'using' keyword support */\n [Symbol.dispose](): void;\n}\n\n// ============================================\n// Provider & Client Types\n// ============================================\n\n/**\n * 环境类型\n */\nexport type EnvironmentType = 'local' | 'cloud';\n\n/**\n * Agent provider interface\n *\n * Responsible for:\n * - Managing agent state/configuration storage\n * - Creating connections to agents\n * - Abstracting away transport details (cloud/local)\n *\n * The provider.connect() method returns an AgentConnection.\n * The client wraps the connection in an ActiveSession instance.\n *\n * @typeParam C - Connection type used by this provider (e.g., CloudAgentConnection, LocalAgentConnection)\n */\nexport interface AgentProvider<C extends AgentConnection = AgentConnection> {\n /**\n * Create a new agent and return its ID\n *\n * @param params - Optional session params (used by LocalAgentProvider to get cwd)\n * @returns Agent ID (Cloud: UUID, Local: cwd)\n */\n create?(params?: CreateSessionParams): Promise<string>;\n /** Get agent state by ID */\n get(agentId: string): Promise<AgentState | undefined>;\n\n /**\n * List all agent states with pagination information\n *\n * @param options - Optional query parameters for filtering, sorting, and pagination\n * Cloud providers use these for API queries and return server pagination\n * Local providers apply client-side filtering and return synthetic pagination\n * @returns Object containing agents array and pagination info\n */\n list(options?: ListAgentOptions): Promise<ListAgentResult<AgentState>>;\n\n /** Connect to an agent and return the connection */\n connect(agentId: string): Promise<C>;\n /** Delete an agent by ID */\n delete(agentId: string): Promise<boolean>;\n\n /**\n * Archive an agent by ID (optional)\n * Used by CloudAgentProvider for archiving agents\n *\n * @param agentId - Agent ID to archive\n * @returns Object containing the archived agent ID\n */\n archive?(agentId: string): Promise<{ id: string }>;\n\n /**\n * Rename an agent by ID (optional)\n * Used by CloudAgentProvider and LocalAgentProvider for renaming agents\n *\n * @param agentId - Agent ID to rename\n * @param title - New title for the agent\n * @returns Object containing the renamed agent ID\n */\n rename?(agentId: string, title: string): Promise<{ id: string }>;\n\n /** Filesystem provider (optional - some providers may not support filesystem operations) */\n readonly filesystem?: FilesystemProvider;\n\n /**\n * Get available models for a repository (optional)\n * Implementation varies by provider type\n * @param repo - Repository identifier\n * @returns Array of model information\n */\n getModels?(repo?: string): Promise<ModelInfo[]>;\n\n /**\n * Register sessionId → agentId mapping (optional, used by LocalAgentProvider)\n * Called after session creation to maintain the mapping for loadSession\n *\n * @param sessionId - Session ID returned by connection.createSession()\n * @param agentId - Agent ID (cwd for Local)\n */\n registerSession?(sessionId: string, agentId: string): void;\n\n /**\n * Open a workspace window (optional, used by LocalAgentProvider)\n *\n * @param params - Workspace params including cwd\n * @returns Response with success status\n */\n openWorkspace?(params: InitializeWorkspaceParams): Promise<InitializeWorkspaceResponse>;\n\n /**\n * Pick files from file dialog (optional, used by LocalAgentProvider)\n *\n * @param params - File picker params including filters\n * @returns Response with file paths and cancel status\n */\n pickFile?(params?: PickFileParams): Promise<PickFileResponse>;\n\n /**\n * Pick folders from folder dialog (optional, used by LocalAgentProvider)\n *\n * @param params - Folder picker params\n * @returns Response with folder paths and cancel status\n */\n pickFolder?(params?: PickFolderParams): Promise<PickFolderResponse>;\n\n /**\n * Upload a file to cloud storage (optional)\n *\n * @param params - Upload parameters including file content\n * @returns Response with cloud URL after successful upload\n */\n uploadFile?(params: UploadFileParams): Promise<UploadFileResponse>;\n\n /**\n * Search for files in the workspace (optional, used by LocalAgentProvider)\n *\n * @param params - Search parameters including options\n * @returns Response with search results\n */\n searchFile?(params: SearchFileParams): Promise<SearchFileResponse>;\n\n /**\n * Register an event listener\n * Provider implementations should forward events to the underlying transport\n *\n * @param event - Event name\n * @param handler - Event handler function\n */\n on?(event: string, handler: (...args: any[]) => void): void;\n\n /**\n * Unregister an event listener\n *\n * @param event - Event name\n * @param handler - Event handler function to remove\n */\n off?(event: string, handler: (...args: any[]) => void): void;\n}\n\n/**\n * AgentClient initialization options\n */\nexport interface AgentClientOptions {\n /** Agent provider (required) */\n provider: AgentProvider;\n /** Logger instance */\n logger?: Logger;\n /** Client capabilities (sent during initialization) */\n clientCapabilities?: ClientCapabilities;\n /**\n * 运行环境类型\n * - 'local': IDE 本地环境\n * - 'cloud': 云端环境\n */\n environmentType?: EnvironmentType;\n}\n\n/**\n * Client sessions resource interface\n * Top-level API for session management\n *\n * Key design:\n * - list() returns sessions with pagination info (mapped from agents)\n * - create() creates a new session (auto-creates agent and connects)\n * - load() loads an existing session (finds agent by sessionId and connects)\n * - archive() archives a session/agent\n * - initializeWorkspace() initializes a workspace for future sessions\n */\nexport interface ClientSessionsResource {\n /**\n * List all sessions with pagination info\n * Cloud: Returns server-side filtered/sorted/paginated results\n * Local: Returns client-side filtered/sorted results (synthetic pagination)\n */\n list(options?: ListAgentOptions): Promise<ListAgentResult<SessionInfo>>;\n\n /** Create a new session (auto-creates agent and connects) */\n create(params: CreateSessionParams): Promise<ActiveSession>;\n\n /** Load an existing session (finds agent by sessionId and connects) */\n load(params: LoadSessionParams): Promise<ActiveSession>;\n\n /**\n * Archive a session/agent\n * @param sessionId - Session ID to archive\n * @returns Object containing the archived session ID\n */\n archive(sessionId: string): Promise<{ id: string }>;\n\n /**\n * Rename a session/agent\n * @param sessionId - Session ID to rename\n * @param title - New title for the session\n * @returns Object containing the renamed session ID\n */\n rename(sessionId: string, title: string): Promise<{ id: string }>;\n\n /** Initialize a workspace for future sessions */\n initializeWorkspace(params: InitializeWorkspaceParams): Promise<InitializeWorkspaceResponse>;\n\n /** Models resource for getting available models */\n readonly models: ModelsResource;\n\n /** Get current workspaces list */\n getCurrentWorkspaces(filter?: { activeOnly?: boolean }): Promise<WorkspaceInfo[]>;\n\n // Event subscription for sessions list changes\n /** Subscribe to sessions resource events */\n on<K extends keyof SessionsResourceEvents>(\n event: K,\n handler: SessionsResourceEventHandler<K>\n ): void;\n\n /** Unsubscribe from sessions resource events */\n off<K extends keyof SessionsResourceEvents>(\n event: K,\n handler: SessionsResourceEventHandler<K>\n ): void;\n\n /** Open a workspace (for LocalAgentProvider) */\n openWorkspace(params: InitializeWorkspaceParams): Promise<InitializeWorkspaceResponse>;\n\n /** Pick files from file dialog (for LocalAgentProvider) */\n pickFile(params?: PickFileParams): Promise<PickFileResponse>;\n\n /** Pick folders from folder dialog (for LocalAgentProvider) */\n pickFolder(params?: PickFolderParams): Promise<PickFolderResponse>;\n\n /** Upload a file to cloud storage */\n uploadFile(params: UploadFileParams): Promise<UploadFileResponse>;\n\n /** Search for files in the workspace (for LocalAgentProvider) */\n searchFile(params: SearchFileParams): Promise<SearchFileResponse>;\n\n}\n\n// ============================================\n// Workspace Types\n// ============================================\n\n/**\n * Workspace information (aligned with FolderSelectResult)\n */\nexport interface WorkspaceInfo {\n /** Folder path */\n path: string;\n /** Folder display name */\n label: string;\n}\n\n// ============================================\n// File Picker Types\n// ============================================\n\n/**\n * File filter for pickFile dialog\n */\nexport interface FileFilter {\n /** Display name for the filter */\n readonly name: string;\n /** File extensions (without dot) */\n readonly extensions: string[];\n}\n\n/**\n * Parameters for picking files\n */\nexport interface PickFileParams {\n /** Default path for the dialog */\n readonly defaultPath?: string;\n /** File type filters */\n readonly filters?: FileFilter[];\n /** Whether to allow multiple selection (default false) */\n readonly canSelectMany?: boolean;\n}\n\n/**\n * Response from picking files\n */\nexport interface PickFileResponse {\n /** Selected files - File objects in browser, absolute path strings in IDE */\n readonly files: Array<File | string>;\n /** Whether user cancelled the dialog */\n readonly canceled: boolean;\n /** Error message (if failed) */\n readonly error?: string;\n}\n\n// ============================================\n// Folder Picker Types\n// ============================================\n\n/**\n * Parameters for picking folders\n */\nexport interface PickFolderParams {\n /** Default path for the dialog */\n readonly defaultPath?: string;\n}\n\n/**\n * Response from picking folders\n */\nexport interface PickFolderResponse {\n /** Selected folder paths */\n readonly folderPaths: string[];\n /** Whether user cancelled the dialog */\n readonly canceled: boolean;\n /** Error message (if failed) */\n readonly error?: string;\n}\n\n// ============================================\n// File Upload Types\n// ============================================\n\n/**\n * Parameters for uploading files\n */\nexport interface UploadFileParams {\n /** Files to upload - File objects in browser, absolute path strings in IDE */\n readonly files: Array<File | string>;\n}\n\n/**\n * Response from uploading files\n */\nexport interface UploadFileResponse {\n /** Whether upload was successful */\n readonly success: boolean;\n /** Cloud URLs corresponding to each uploaded file (same order as input files) */\n readonly urls?: string[];\n /** URL expiration time in seconds (from backend) */\n readonly expireSeconds?: number;\n /** Error message (if upload failed) */\n readonly error?: string;\n}\n\n// ============================================\n// File Search Types\n// ============================================\n\n/**\n * Mention type for file/folder\n */\nexport enum MentionType {\n file = 'file',\n folder = 'folder'\n}\n\n/**\n * Search options for file search\n */\nexport interface SearchOptions {\n /** Search keyword */\n readonly search?: string;\n /** Number of results to return */\n readonly resultNum: number;\n}\n\n/**\n * File search result\n */\nexport interface SearchFileResult {\n /** Full path */\n path: string;\n /** Relative path */\n relativePath: string;\n /** File name */\n fileName?: string;\n /** Folder name */\n folderName?: string;\n /** Type (file or folder) */\n type: MentionType.file | MentionType.folder;\n}\n\n/**\n * Parameters for searching files\n */\nexport interface SearchFileParams {\n /** Search options */\n readonly options: SearchOptions;\n /** Search path*/\n readonly cwd?: string;\n}\n\n/**\n * Response from searching files\n */\nexport interface SearchFileResponse {\n /** Search results */\n readonly results: SearchFileResult[];\n /** Error message (if failed) */\n readonly error?: string;\n}\n","/**\n * Backend Provider 类型定义\n *\n * 定义 IBackendProvider 接口和配置\n */\n\nimport type { GetAgentsRequest, GetAgentsResponse } from './agent-api';\n\n// ============================================================================\n// Account 相关类型\n// ============================================================================\n\n/**\n * 账号版本类型\n */\nexport type Edition = 'pro' | 'personal' | 'ultimate' | 'exclusive';\n\n/**\n * 版本展示类型(用于 UI 展示)\n * - free: 免费版(个人版未订阅 Pro)\n * - pro: Pro 版(个人版已订阅 Pro)\n * - ultimate: 旗舰版(团队版)\n * - exclusive: 专享版(企业版)\n */\nexport type EditionDisplayType = 'free' | 'pro' | 'ultimate' | 'exclusive';\n\n/**\n * 部署状态\n */\nexport interface DeployStatus {\n statusCode: number;\n statusMsg: string;\n detailMsg: string;\n}\n\n/**\n * 套餐代码\n */\n\n/**\n * TCACA_code_001_PqouKr6QWV CodeBuddy海外版免费包\n * TCACA_code_002_AkiJS3ZHF5 CodeBuddy海外版Pro版本包-包月/CodeBuddy Pro Plan - Monthly:\n * TCACA_code_006_DbXS0lrypC CodeBuddy海外版一次性免费赠送2周的Pro版本包/CodeBuddy One-time Free 2-Week Pro Plan Trial\n * TCACA_code_007_nzdH5h4Nl0 CodeBuddy海外版运营裂变包/CodeBuddy Growth Plan\n * TCACA_code_003_FAnt7lcmRT CodeBuddy海外版Pro版本包-包年/CodeBuddy Pro Plan - Yearly\n * TCACA_code_008_cfWoLwvjU4 赠送月包\n */\nexport enum CommodityCode {\n free = 'TCACA_code_001_PqouKr6QWV', // free\n proMon = 'TCACA_code_002_AkiJS3ZHF5',\n // 国内月包(国际pro+)\n proMonPlus = 'TCACA_code_005_maRGyrHhw1',\n // 免费赠送2周\n gift = 'TCACA_code_006_DbXS0lrypC',\n activity = 'TCACA_code_007_nzdH5h4Nl0',\n proYear = 'TCACA_code_003_FAnt7lcmRT',\n // 国际(free 月包、国内试用包)\n freeMon = 'TCACA_code_008_cfWoLwvjU4', // free\n // 加量包\n extra = 'TCACA_code_009_0XmEQc2xOf',\n}\n\n/**\n * 账号套餐信息\n */\nexport interface AccountPlan {\n /** 是否是 Pro 版本 */\n isPro: boolean;\n // 是否是试用版本\n isTria?: boolean;\n /** 到期时间戳 */\n expireAt?: number;\n // 刷新时间(年套餐下、本周期结束日期)\n refreshAt?: number;\n /** 自动续费标志 0-关闭 1-开启 */\n renewFlag: 0 | 1;\n /** 套餐代码 */\n PackageCode?: CommodityCode;\n /** 套餐名称 */\n name: string;\n usageTotal?: string;\n usageUsed?: string;\n usageLeft?: string;\n}\n\n/**\n * 账号信息\n */\nexport interface Account {\n /** 用户ID(唯一标识) */\n uid: string;\n /** 用户昵称 */\n nickname: string;\n /** 版本类型 */\n type: Edition;\n /** 版本展示类型(用于 UI 展示) */\n editionType: EditionDisplayType;\n /** 是否最后一次登录 */\n lastLogin: boolean;\n /** 企业ID */\n enterpriseId?: string;\n /** 企业名称 */\n enterpriseName?: string;\n /** 企业LOGO */\n enterpriseLogo?: string;\n /** 企业内用户名 */\n enterpriseUserName?: string;\n /** 插件是否启用 */\n pluginEnabled?: boolean;\n /** 部署状态 */\n deployStatus?: DeployStatus;\n /** 是否是 Pro 版本 */\n isPro?: boolean;\n /** 到期时间戳 */\n expireAt?: string | number;\n /** 自动续费标志 0-关闭 1-开启 */\n renewFlag?: 0 | 1;\n /** 套餐代码 */\n PackageCode?: CommodityCode;\n /** 套餐名称 */\n name?: string;\n email?: string;\n}\n\n/** 账户状态 */\nexport enum AccountStatus {\n /** 有效 */\n valid = 0,\n /** 已退款 */\n refund = 1,\n /** 已过期 */\n expired = 2,\n /** 已用完 */\n usedUp = 3,\n}\n\n// https://iwiki.woa.com/p/1151041572#7%E3%80%81%E8%B4%B9%E7%94%A8%E4%B8%AD%E5%BF%83%E6%8E%A7%E5%88%B6%E5%8F%B0-%E8%B5%84%E6%BA%90%E5%8C%85%E7%AE%A1%E7%90%86%E6%9F%A5%E8%AF%A2%E6%8E%A5%E5%8F%A3\nexport interface UserResource {\n AccountId: number;\n ResourceId: string;\n // 账户类型: 1-RI 2-资源包 9 - 组合包\n // ResourceType: 1 | 2 | 9;\n // 总周期数量\n TotalCycles: 1 | 12;\n // 剩余周期数量\n RemainCycles: number;\n Status: AccountStatus;\n // 费用类型:免费1/付费2\n FeeType: 1 | 2;\n PackageCode: CommodityCode;\n PackageName: string;\n // // 周期容量(使用下方精确值)\n // CycleCapacitySize: number;\n // // 剩余周期数量\n // CycleCapacityRemain: number;\n SupportAutoRenew: 0 | 1;\n SupportManualRenew: 0 | 1;\n AutoRenewFlag: 0 | 1;\n // AutoRenewTimeUnit: string;\n // AutoRenewTimeSpan: 1;\n // ProductCode: string;\n // SubProductCode: string;\n // 单周期开始时间\n CycleStartTime: number; // 时间戳 单位为毫秒\n // 单周期结束时间\n CycleEndTime: number; // 时间戳 单位为毫秒\n // CapacityType: string;\n CreateTime: string;\n ExpiredTime: string; // 2025-11-27 14:36:00\n DeductionStartTime: number; // 时间戳 单位为毫秒\n // 抵扣结束时间戳 单位为毫秒\n DeductionEndTime: number; // 时间戳 单位为毫秒\n CapacityUsedPrecise: string;\n // 当前周期余量精确值\n CycleCapacityRemainPrecise: string;\n // 当前周期总量精确值\n CycleCapacitySizePrecise: string;\n // 剩余容量精确值\n CapacityRemainPrecise: string;\n // 用量精确值\n CapacitySizePrecise: string;\n}\n\n// ============================================================================\n// Model 相关类型\n// ============================================================================\n\n/**\n * 推理配置\n */\nexport interface ReasoningConfig {\n /** 推理努力程度 */\n effort: 'low' | 'medium' | 'high';\n /** 摘要模式 */\n summary: 'auto' | 'always' | 'never';\n}\n\n/**\n * 模型信息\n */\nexport interface ModelInfo {\n /** 模型ID */\n id: string;\n /** 模型名称 */\n name: string;\n /** 供应商 */\n vendor: string;\n /** 最大输出 token 数 */\n maxOutputTokens: number;\n /** 最大输入 token 数 */\n maxInputTokens: number;\n /** 是否支持工具调用 */\n supportsToolCall: boolean;\n /** 是否支持图像 */\n supportsImages: boolean;\n /** 是否禁用多模态 */\n disabledMultimodal: boolean;\n /** 最大允许大小 */\n maxAllowedSize: number;\n /** 是否支持推理 */\n supportsReasoning: boolean;\n /** 是否仅推理模式 */\n onlyReasoning: boolean;\n /** 温度参数 */\n temperature: number;\n /** 推理配置 */\n reasoning: ReasoningConfig;\n /** 英文描述 */\n descriptionEn: string;\n /** 中文描述 */\n descriptionZh: string;\n}\n\n/**\n * GetModels 请求参数\n */\nexport interface GetModelsRequest {\n /** 仓库路径 */\n repository: string;\n}\n\n/**\n * GetModels 响应\n */\nexport interface GetModelsResponse {\n /** 模型列表 */\n models: ModelInfo[];\n}\n\n// ============================================================================\n// Backend Provider 配置\n// ============================================================================\n\n/**\n * Backend Provider 配置选项\n */\nexport interface BackendProviderConfig {\n /** API 基础 URL (例如: https://api.example.com) */\n baseUrl: string;\n /** 认证 Token */\n authToken?: string;\n}\n\n// ============================================================================\n// Backend Provider 接口\n// ============================================================================\n\n/**\n * IBackendProvider 接口\n *\n * 定义与后端 API 交互的抽象接口\n */\nexport interface IBackendProvider {\n /**\n * 获取 Agent 列表\n * @param request 请求参数\n * @returns Promise<GetAgentsResponse> Agent 列表响应\n */\n getAgents(request: GetAgentsRequest): Promise<GetAgentsResponse>;\n\n /**\n * 获取可用模型列表\n * @param request 请求参数(包含仓库路径)\n * @returns Promise<GetModelsResponse> 模型列表响应\n */\n getModels(request: GetModelsRequest): Promise<GetModelsResponse>;\n\n /**\n * 获取当前账号信息\n * @returns Promise<Account | null> 账号信息,未登录时返回 null\n */\n getAccount(): Promise<Account | null>;\n\n /**\n * 触发登录流程\n * - Web 环境: 跳转到登录页面\n * - IDE 环境: 通过 IPC 通知 IDE 打开登录流程\n */\n login(): Promise<void>;\n\n /**\n * 登出账号\n */\n logout(): Promise<void>;\n}\n","/**\n * Backend Provider 实现\n *\n * 封装与后端 API 的 HTTP 通信\n */\n\nimport { type IBackendProvider, type BackendProviderConfig, type Account, type AccountPlan, type EditionDisplayType, type GetModelsRequest, type GetModelsResponse, type ModelInfo, CommodityCode, UserResource, AccountStatus } from './types';\nimport type { GetAgentsRequest, GetAgentsResponse } from './agent-api';\nimport { accountService } from '../account';\n\n/** 获取当前域名的登录页面 URL */\nconst getLoginUrl = () => `${window.location.origin}/login`;\n\n/** 获取当前域名的账号选择页面 URL */\nconst getSelectAccountUrl = () => `${window.location.origin}/login/select`;\n\n/** localStorage 中存储选中账号 ID 的 key */\nexport const SELECTED_ACCOUNT_KEY = 'CODEBUDDY_IDE_SELECTED_ACCOUNT_ID';\n\n/**\n * Backend Provider 实现类\n * \n * 职责:\n * - 与后端 API 通信(getAgents, getModels, getAccount 等)\n * - 触发登录/登出流程\n * - 获取 account 后自动同步到 accountService\n */\nexport class BackendProvider implements IBackendProvider {\n private readonly baseUrl: string;\n private readonly authToken?: string;\n\n constructor(config: BackendProviderConfig) {\n this.baseUrl = config.baseUrl.replace(/\\/$/, '');\n this.authToken = config.authToken;\n }\n\n /**\n * 获取 Agent 列表\n * API 端点: GET /v2/cloudagent/agentmgmt/agents\n */\n async getAgents(request: GetAgentsRequest = {}): Promise<GetAgentsResponse> {\n // 原实现已注释,使用 MockAgentProvider 提供假数据\n // const queryParams = this.buildQueryParams(request);\n // const url = `${this.baseUrl}/v2/cloudagent/agentmgmt/agents${queryParams}`;\n // const headers: Record<string, string> = {\n // 'Content-Type': 'application/json',\n // 'Accept': 'application/json',\n // };\n // if (this.authToken) {\n // headers['Authorization'] = `Bearer ${this.authToken}`;\n // }\n // const response = await fetch(url, { method: 'GET', headers, credentials: 'include' });\n // if (!response.ok) {\n // const error = await response.json().catch(() => ({ message: response.statusText }));\n // throw new Error(error.message || `HTTP ${response.status}`);\n // }\n // return response.json();\n\n // 使用 MockAgentProvider 提供假数据\n const { MockAgentProvider } = await import('../common/_legacy/MockAgentProvider.js');\n const mockProvider = new MockAgentProvider();\n const sessions = mockProvider.getAllSessions();\n\n // 将 MockSession 数据转换为 GetAgentsResponse 格式\n const mockTitles = {\n '1': '开发五子棋游戏',\n '2': '修复登录页面样式',\n '3': 'API 接口优化',\n };\n\n const agents = sessions.map((session, index) => ({\n id: session.sessionId,\n name: mockTitles[session.sessionId as keyof typeof mockTitles] || `Agent ${session.sessionId}`,\n status: 'RUNNING' as const,\n visibility: 'PRIVATE' as const,\n createdAt: new Date(session.createdAt).toISOString(),\n summary: `Session created at ${new Date(session.createdAt).toLocaleString()}`,\n source: {\n provider: 'github',\n ref: 'refs/heads/main',\n repository: session.cwd,\n },\n target: {\n autoCreatePr: false,\n branchName: 'feature/mock',\n prUrl: undefined,\n url: undefined,\n },\n }));\n\n return {\n agents,\n pagination: {\n hasNext: false,\n hasPrev: false,\n page: 1,\n size: agents.length,\n total: agents.length,\n totalPages: 1,\n },\n };\n }\n\n /**\n * 获取可用模型列表\n * API 端点: GET /v2/cloudagent/models (假设)\n *\n * 当前实现: 返回 Mock 数据\n */\n async getModels(request: GetModelsRequest): Promise<GetModelsResponse> {\n // Mock 模型数据\n // https://staging-copilot.tencent.com/internal/api/docs/swagger/index.html#/CloudAgent/get_v2_cloudagent_agentmgmt_models\n const mockModels: ModelInfo[] = [\n {\n id: 'glm-4.7',\n name: 'GLM-4.7',\n vendor: 'f',\n maxOutputTokens: 48000,\n maxInputTokens: 200000,\n supportsToolCall: true,\n supportsImages: false,\n disabledMultimodal: true,\n maxAllowedSize: 200000,\n supportsReasoning: true,\n onlyReasoning: true,\n temperature: 1.0,\n reasoning: {\n effort: 'medium',\n summary: 'auto'\n },\n descriptionEn: 'GLM-4.7 model, Well-rounded model for everyday use',\n descriptionZh: 'GLM-4.7 大模型,能力均衡,适合日常使用'\n },\n {\n id: 'glm-4.7-flash',\n name: 'GLM-4.7 Flash',\n vendor: 'f',\n maxOutputTokens: 40000,\n maxInputTokens: 128000,\n supportsToolCall: true,\n supportsImages: false,\n disabledMultimodal: false,\n maxAllowedSize: 128000,\n supportsReasoning: false,\n onlyReasoning: false,\n temperature: 0.7,\n reasoning: {\n effort: 'low',\n summary: 'never'\n },\n descriptionEn: 'GLM-4.7 Flash, Fast and efficient model',\n descriptionZh: 'GLM-4.7 Flash,快速高效的模型'\n }\n ];\n\n console.log('[BackendProvider] getModels called for repository:', request.repository);\n\n // 返回 Mock 数据(后续可以替换为真实的 HTTP 请求)\n return {\n models: mockModels\n };\n }\n\n /**\n * 获取当前账号信息\n * API 端点: GET /console/accounts (返回账号列表)\n * \n * 逻辑:\n * 1. 从 localStorage 读取 CODEBUDDY_IDE_SELECTED_ACCOUNT_ID\n * 2. 根据 CODEBUDDY_IDE_SELECTED_ACCOUNT_ID 找到对应账号\n * - personal 类型: 用 uid 匹配\n * - 其他类型: 用 enterpriseId 匹配\n * 3. 如果没有选中的账号,跳转到账号选择页面\n * 4. 获取套餐信息并合并到账号中\n * 5. 同步到 accountService\n */\n async getAccount(): Promise<Account | null> {\n const url = `${this.baseUrl}/console/accounts`;\n\n const headers: Record<string, string> = {\n 'Content-Type': 'application/json',\n 'Accept': 'application/json',\n };\n\n if (this.authToken) {\n headers['Authorization'] = `Bearer ${this.authToken}`;\n }\n\n try {\n const response = await fetch(url, { method: 'GET', headers, credentials: 'include' });\n\n if (!response.ok) {\n // 401/403 表示未登录或会话过期\n if (response.status === 401 || response.status === 403) {\n accountService.setAccount(null);\n return null;\n }\n const error = await response.json().catch(() => ({ message: response.statusText }));\n throw new Error(error.message || `HTTP ${response.status}`);\n }\n\n // 检查响应类型,只有 JSON 才是正常响应,其他情况跳转登录页\n const contentType = response.headers.get('Content-Type') || '';\n if (!contentType.includes('application/json')) {\n accountService.setAccount(null);\n return null;\n }\n\n const { data = {} } = await response.json();\n const accounts: Account[] = data?.accounts || [];\n if (!accounts || accounts.length === 0) {\n accountService.setAccount(null);\n return null;\n }\n\n // 从 localStorage 读取选中的账号 ID\n const selectedAccountId = localStorage.getItem(SELECTED_ACCOUNT_KEY);\n let selectedAccount: Account | undefined;\n\n if (selectedAccountId) {\n // 查找选中的账号\n selectedAccount = accounts.find(account => {\n // personal 类型用 uid 匹配,其他类型用 enterpriseId 匹配\n if (account.type === 'personal') {\n return account.uid === selectedAccountId;\n }\n return account.enterpriseId === selectedAccountId;\n });\n\n if (selectedAccount) {\n try {\n // 获取套餐信息并合并到账号中\n const plan = await this.getCurrentPlan();\n // 计算版本展示类型\n const editionType = this.getEditionDisplayType(selectedAccount.type, plan.isPro);\n console.log('account', { ...selectedAccount, ...plan, editionType });\n const account = { ...selectedAccount, ...plan, editionType };\n // 同步到 accountService\n accountService.setAccount(account);\n return account;\n } catch (error) {\n // 获取套餐信息失败,忽略错误\n accountService.setAccount(selectedAccount);\n return { ...selectedAccount };\n }\n }\n }\n\n // 如果只有一个账号,自动选中它\n if (accounts.length === 1) {\n selectedAccount = accounts[0];\n // 保存选中的账号 ID 到 localStorage\n const accountId = selectedAccount.type === 'personal'\n ? selectedAccount.uid\n : selectedAccount.enterpriseId;\n if (accountId) {\n localStorage.setItem(SELECTED_ACCOUNT_KEY, accountId);\n }\n // 获取套餐信息并合并到账号中\n const plan = await this.getCurrentPlan();\n const editionType = this.getEditionDisplayType(selectedAccount.type, plan.isPro);\n console.log('account (auto-selected)', { ...selectedAccount, ...plan, editionType });\n const account = { ...selectedAccount, ...plan, editionType };\n // 同步到 accountService\n accountService.setAccount(account);\n return account;\n }\n\n // 多个账号但没有选中的,跳转到账号选择页面\n const redirectUrl = encodeURIComponent(window.location.href);\n window.location.href = `${getSelectAccountUrl()}?platform=website&state=0&redirect_uri=${redirectUrl}`;\n accountService.setAccount(null);\n return null;\n } catch (error) {\n console.error('[BackendProvider] getAccount failed:', error);\n accountService.setAccount(null);\n return null;\n }\n }\n\n /**\n * 获取当前套餐信息\n * 从计量计费接口获取用户的套餐信息\n * API: POST /billing/meter/get-user-resource\n */\n private async getCurrentPlan(): Promise<AccountPlan> {\n // 默认套餐信息\n const defaultPlan: AccountPlan = {\n isPro: false,\n expireAt: 0,\n renewFlag: 0,\n PackageCode: undefined,\n name: '',\n };\n\n try {\n const url = `${this.baseUrl}/billing/meter/get-user-resource`;\n const headers: Record<string, string> = {\n 'Content-Type': 'application/json',\n 'Accept': 'application/json',\n };\n\n if (this.authToken) {\n headers['Authorization'] = `Bearer ${this.authToken}`;\n }\n\n // 构造请求参数\n const now = new Date();\n const futureDate = new Date(now.getTime() + 101 * 365 * 24 * 60 * 60 * 1000);\n const formatDate = (d: Date) => {\n const pad = (n: number) => n.toString().padStart(2, '0');\n return `${d.getFullYear()}-${pad(d.getMonth() + 1)}-${pad(d.getDate())} ${pad(d.getHours())}:${pad(d.getMinutes())}:${pad(d.getSeconds())}`;\n };\n\n const body = {\n PageNumber: 1,\n // PageSize、用户购买包的数量、暂定 100 上限。\n PageSize: 100,\n ProductCode: 'p_tcaca',\n Status: [AccountStatus.valid, AccountStatus.usedUp], // 0-有效, 3-已用完\n PackageEndTimeRangeBegin: formatDate(now),\n PackageEndTimeRangeEnd: formatDate(futureDate),\n };\n\n const response = await fetch(url, {\n method: 'POST',\n headers,\n credentials: 'include',\n body: JSON.stringify(body),\n });\n\n if (!response.ok) {\n console.warn('[BackendProvider] getCurrentPlan failed:', response.status);\n return defaultPlan;\n }\n\n const result = await response.json();\n // 响应格式: { Response: { Data: { Accounts: [...] } } }\n const resources = (result?.data?.Response?.Data?.Accounts || []) as UserResource[];\n\n if (!resources || resources.length === 0) {\n return defaultPlan;\n }\n\n // 查找 Pro 套餐(proYear 或 proMon)\n const proPlan = resources.find((r: any) =>\n r.PackageCode === CommodityCode.proYear || r.PackageCode === CommodityCode.proMon || r.PackageCode === CommodityCode.proMonPlus\n );\n\n // 查找试用套餐\n const trialPlan = resources.find((r: any) => r.PackageCode === CommodityCode.gift || r.PackageCode === CommodityCode.freeMon);\n\n const activePlan = proPlan || trialPlan;\n\n if (activePlan) {\n // 解析时间字符串或时间戳为毫秒时间戳\n const parseTime = (time: string | number | undefined): number => {\n if (!time) return 0;\n return new Date(time).getTime();\n };\n\n return {\n isPro: !!proPlan,\n // 试用套餐\n isTria: [AccountStatus.valid, AccountStatus.usedUp].includes(trialPlan?.Status!),\n expireAt: parseTime(activePlan.DeductionEndTime || activePlan.ExpiredTime || activePlan.CycleEndTime),\n refreshAt: parseTime(activePlan.CycleEndTime),\n renewFlag: Number(activePlan.AutoRenewFlag) === 1 ? 1 : 0,\n PackageCode: activePlan.PackageCode,\n name: activePlan.PackageName || '',\n usageTotal: activePlan.CycleCapacitySizePrecise,\n usageUsed: activePlan.CapacityUsedPrecise,\n usageLeft: activePlan.CycleCapacityRemainPrecise,\n };\n }\n\n return defaultPlan;\n } catch (error) {\n console.error('[BackendProvider] getCurrentPlan error:', error);\n return defaultPlan;\n }\n }\n\n /**\n * 根据账号类型和 Pro 状态计算版本展示类型\n * - personal + isPro = 'pro'\n * - personal + !isPro = 'free'\n * - ultimate = 'ultimate' (旗舰版/团队版)\n * - exclusive = 'exclusive' (专享版/企业版)\n */\n private getEditionDisplayType(type: string, isPro: boolean): EditionDisplayType {\n if (type === 'personal') {\n return isPro ? 'pro' : 'free';\n }\n if (type === 'ultimate') {\n return 'ultimate';\n }\n if (type === 'exclusive') {\n return 'exclusive';\n }\n // 默认返回 free\n return 'free';\n }\n\n /**\n * 触发登录流程\n * Web 环境: 跳转到登录页面\n */\n async login(): Promise<void> {\n // 获取当前页面 URL 作为回调地址\n // todo 支持弹窗和跳转、弹窗优化点 别让主页面 reload\n const redirectUrl = encodeURIComponent(window.location.href);\n window.location.href = `${getLoginUrl()}?platform=website&state=0&redirect_uri=${redirectUrl}`;\n }\n\n /**\n * 登出账号\n * Web 环境: 调用登出接口并清除本地状态\n */\n async logout(): Promise<void> {\n // 调用登出接口\n const url = `${this.baseUrl}/console/logout`;\n\n try {\n await fetch(url, { method: 'POST', credentials: 'include' });\n } catch (error) {\n console.error('[BackendProvider] logout failed:', error);\n }\n\n // 清除 localStorage 中的选中账号\n localStorage.removeItem(SELECTED_ACCOUNT_KEY);\n\n // 清空 accountService,会触发订阅者更新,UI 会自动切换到未登录状态\n accountService.clearAccount();\n }\n\n /**\n * 构建查询参数字符串\n */\n // private buildQueryParams(request: GetAgentsRequest): string {\n // const params: string[] = [];\n // if (request.dayRange !== undefined) {\n // params.push(`dayRange=${request.dayRange}`);\n // }\n // if (request.filters?.length) {\n // request.filters.forEach((filter: AgentFilter) => {\n // params.push(`filters=${encodeURIComponent(JSON.stringify(filter))}`);\n // });\n // }\n // if (request.page !== undefined) {\n // params.push(`page=${request.page}`);\n // }\n // if (request.size !== undefined) {\n // params.push(`size=${request.size}`);\n // }\n // if (request.sort) {\n // params.push(`sort=${encodeURIComponent(JSON.stringify(request.sort))}`);\n // }\n // return params.length > 0 ? `?${params.join('&')}` : '';\n // }\n}\n\n/**\n * 创建 BackendProvider 实例\n */\nexport function createBackendProvider(config: BackendProviderConfig): BackendProvider {\n return new BackendProvider(config);\n}\n","/**\n * IPC Backend Provider 实现\n *\n * 通过 IWidgetChannel 与后端通信\n * 使用统一的消息格式: { type: 'backend', requestId, params: { type, params } }\n */\n\nimport type { IBackendProvider, Account, GetModelsRequest, GetModelsResponse } from './types';\nimport type { GetAgentsRequest, GetAgentsResponse } from './agent-api';\nimport { IWidgetChannel } from '../common';\nimport { accountService } from '../account';\n\n/**\n * IPC Backend Provider 配置\n */\nexport interface IPCBackendProviderConfig {\n /** Widget Channel 接口 */\n channel: IWidgetChannel;\n /** 是否启用调试日志 */\n debug?: boolean;\n /** 请求超时时间(毫秒,默认 30000) */\n timeoutMs?: number;\n}\n\n/**\n * Backend 请求类型常量\n */\nconst BACKEND_REQUEST_TYPES = {\n GET_AGENTS: 'backend:get-agents-request',\n GET_MODELS: 'backend:get-models',\n LOGIN: 'backend:login',\n LOGOUT: 'backend:logout',\n GET_ACCOUNT: 'backend:get-account',\n} as const;\n\n/**\n * 生成唯一请求 ID\n */\nfunction generateRequestId(): string {\n return `req-${Date.now()}-${Math.random().toString(36).slice(2)}`;\n}\n\n/**\n * IPC Backend Provider 实现类\n *\n * 通过 IWidgetChannel 与后端通信获取 Agent 列表\n */\nexport class IPCBackendProvider implements IBackendProvider {\n private readonly channel: IWidgetChannel;\n private readonly debug: boolean;\n private readonly timeoutMs: number;\n\n constructor(config: IPCBackendProviderConfig) {\n this.channel = config.channel;\n this.debug = config.debug ?? false;\n this.timeoutMs = config.timeoutMs ?? 30000;\n\n this.log('Initialized with IWidgetChannel');\n }\n\n /**\n * 发送统一格式的后端请求\n * @param requestType 请求类型\n * @param params 请求参数\n * @returns 响应数据\n */\n private async sendBackendRequest<T>(requestType: string, params?: unknown): Promise<T> {\n const message = {\n type: 'backend',\n requestId: generateRequestId(),\n params: {\n type: requestType,\n params: params,\n },\n };\n\n this.log('Sending backend request:', message);\n\n const response = await this.channel.callMethod('__backend__', message, this.timeoutMs);\n\n this.log('Received response:', response);\n\n // 检查响应中是否有错误\n if (response?.error) {\n throw new Error(response.error);\n }\n\n // 从响应的 data 字段中提取实际数据\n return (response?.data !== undefined ? response.data : response) as T;\n }\n\n /**\n * 获取 Agent 列表\n * 通过 IWidgetChannel 发送请求到后端\n */\n async getAgents(request: GetAgentsRequest = {}): Promise<GetAgentsResponse> {\n this.log('Getting agents with request:', request);\n\n try {\n return await this.sendBackendRequest<GetAgentsResponse>(\n BACKEND_REQUEST_TYPES.GET_AGENTS,\n request\n );\n } catch (error) {\n this.log('Get agents failed:', error);\n throw error;\n }\n }\n\n /**\n * 获取可用模型列表\n * 通过 IWidgetChannel 发送请求到后端\n */\n async getModels(request: GetModelsRequest): Promise<GetModelsResponse> {\n this.log('Getting models with request:', request);\n\n try {\n return await this.sendBackendRequest<GetModelsResponse>(\n BACKEND_REQUEST_TYPES.GET_MODELS,\n request\n );\n } catch (error) {\n this.log('Get models failed:', error);\n throw error;\n }\n }\n\n /**\n * 获取当前账号信息\n * IDE 环境: 通过 IPC 获取账号信息,并同步到 accountService\n */\n async getAccount(): Promise<Account | null> {\n this.log('Getting account via IPC');\n\n try {\n const account = await this.sendBackendRequest<Account | null>(\n BACKEND_REQUEST_TYPES.GET_ACCOUNT\n );\n // 同步到 accountService\n accountService.setAccount(account);\n return account;\n } catch (error) {\n this.log('Get account failed:', error);\n accountService.setAccount(null);\n return null;\n }\n }\n\n /**\n * 触发登录流程\n * IDE 环境: 通过 IPC 通知 IDE 打开登录流程\n */\n async login(): Promise<void> {\n this.log('Triggering login via IPC');\n\n try {\n await this.sendBackendRequest<void>(BACKEND_REQUEST_TYPES.LOGIN);\n } catch (error) {\n this.log('Login request failed:', error);\n throw error;\n }\n }\n\n /**\n * 登出账号\n * IDE 环境: 通过 IPC 通知 IDE 登出\n */\n async logout(): Promise<void> {\n this.log('Triggering logout via IPC');\n\n try {\n await this.sendBackendRequest<void>(BACKEND_REQUEST_TYPES.LOGOUT);\n // 清空 accountService\n accountService.clearAccount();\n } catch (error) {\n this.log('Logout request failed:', error);\n throw error;\n }\n }\n\n /**\n * 调试日志\n */\n private log(...args: unknown[]): void {\n if (this.debug) {\n console.log('[IPCBackendProvider]', ...args);\n }\n }\n}\n\n/**\n * 创建 IPCBackendProvider 实例\n */\nexport function createIPCBackendProvider(config: IPCBackendProviderConfig): IPCBackendProvider {\n return new IPCBackendProvider(config);\n}\n"],"mappings":"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"}