@midscene/playground 1.7.5-beta-20260421030751.0 → 1.7.5

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.
@@ -285,7 +285,7 @@ class RemoteExecutionAdapter extends BasePlaygroundAdapter {
285
285
  try {
286
286
  const response = await fetch(`${this.serverUrl}/screenshot`);
287
287
  if (!response.ok) {
288
- console.warn(`Screenshot request failed: ${response.statusText}`);
288
+ if (409 !== response.status) console.warn(`Screenshot request failed: ${response.statusText}`);
289
289
  return null;
290
290
  }
291
291
  return await response.json();
@@ -1 +1 @@
1
- {"version":3,"file":"adapters/remote-execution.mjs","sources":["../../../src/adapters/remote-execution.ts"],"sourcesContent":["import type {\n ConnectivityTestResult,\n DeviceAction,\n ExecutionDump,\n} from '@midscene/core';\nimport { parseStructuredParams } from '../common';\nimport type {\n PlaygroundSessionSetup,\n PlaygroundSessionState,\n PlaygroundSessionTarget,\n} from '../platform';\nimport type { PlaygroundRuntimeInfo } from '../runtime-metadata';\nimport type { ExecutionOptions, FormValue, ValidationResult } from '../types';\nimport { BasePlaygroundAdapter } from './base';\n\nexport class RemoteExecutionAdapter extends BasePlaygroundAdapter {\n private serverUrl?: string;\n private _id?: string;\n private dumpUpdateCallback?: (\n dump: string,\n executionDump?: ExecutionDump,\n ) => void;\n private pollingIntervalId?: ReturnType<typeof setInterval>;\n\n constructor(serverUrl: string) {\n super();\n this.serverUrl = serverUrl;\n }\n\n // Set dump update callback\n onDumpUpdate(\n callback: (dump: string, executionDump?: ExecutionDump) => void,\n ): void {\n this.dumpUpdateCallback = undefined;\n this.dumpUpdateCallback = callback;\n }\n\n // Get adapter ID (cached after first status check for remote)\n get id(): string | undefined {\n return this._id;\n }\n\n // Override validateParams for remote execution\n // Since schemas from server are JSON-serialized and lack .parse() method\n validateParams(\n value: FormValue,\n action: DeviceAction<unknown> | undefined,\n ): ValidationResult {\n if (!action?.paramSchema) {\n return { valid: true };\n }\n\n const needsStructuredParams = this.actionNeedsStructuredParams(action);\n\n if (!needsStructuredParams) {\n return { valid: true };\n }\n\n if (!value.params) {\n return { valid: false, errorMessage: 'Parameters are required' };\n }\n\n // For remote execution, perform basic validation without .parse()\n // Check if required fields are present\n if (action.paramSchema && typeof action.paramSchema === 'object') {\n const schema = action.paramSchema as any;\n if (schema.shape || schema.type === 'ZodObject') {\n const shape = schema.shape || {};\n const missingFields = Object.keys(shape).filter((key) => {\n const fieldDef = shape[key];\n // Check if field is required (not optional)\n const isOptional =\n fieldDef?.isOptional ||\n fieldDef?._def?.innerType || // ZodOptional\n fieldDef?._def?.typeName === 'ZodOptional';\n return (\n !isOptional &&\n (value.params![key] === undefined || value.params![key] === '')\n );\n });\n\n if (missingFields.length > 0) {\n return {\n valid: false,\n errorMessage: `Missing required parameters: ${missingFields.join(', ')}`,\n };\n }\n }\n }\n\n return { valid: true };\n }\n\n async parseStructuredParams(\n action: DeviceAction<unknown>,\n params: Record<string, unknown>,\n options: ExecutionOptions,\n ): Promise<unknown[]> {\n // Use shared implementation from common.ts\n return await parseStructuredParams(action, params, options);\n }\n\n formatErrorMessage(error: any): string {\n const message = error?.message || '';\n\n // Handle Android-specific errors\n const androidErrors = [\n {\n keyword: 'adb',\n message:\n 'ADB connection error. Please ensure device is connected and USB debugging is enabled.',\n },\n {\n keyword: 'UIAutomator',\n message:\n 'UIAutomator error. Please ensure the UIAutomator server is running on the device.',\n },\n ];\n\n const androidError = androidErrors.find(({ keyword }) =>\n message.includes(keyword),\n );\n if (androidError) {\n return androidError.message;\n }\n\n return this.formatBasicErrorMessage(error);\n }\n\n // Remote execution adapter - simplified interface\n async executeAction(\n actionType: string,\n value: FormValue,\n options: ExecutionOptions,\n ): Promise<unknown> {\n // If serverUrl is provided, use server-side execution\n if (this.serverUrl && typeof window !== 'undefined') {\n return this.executeViaServer(actionType, value, options);\n }\n\n throw new Error(\n 'Remote execution adapter requires server URL for execution',\n );\n }\n\n // Remote execution via server - uses same endpoint as requestPlaygroundServer\n private async executeViaServer(\n actionType: string,\n value: FormValue,\n options: ExecutionOptions,\n ): Promise<unknown> {\n const payload: Record<string, unknown> = {\n type: actionType,\n prompt: value.prompt,\n ...this.buildOptionalPayloadParams(options, value),\n };\n\n // Add context only if it exists (server can handle single agent case without context)\n if (options.context) {\n payload.context = options.context;\n }\n\n // Start polling if requestId is provided and dumpUpdateCallback is set\n if (options.requestId && this.dumpUpdateCallback) {\n this.startProgressPolling(options.requestId);\n }\n\n try {\n const response = await fetch(`${this.serverUrl}/execute`, {\n method: 'POST',\n headers: {\n 'Content-Type': 'application/json',\n },\n body: JSON.stringify(payload),\n });\n\n if (!response.ok) {\n const errorText = await response.text().catch(() => 'Unknown error');\n throw new Error(\n `Server request failed (${response.status}): ${errorText}`,\n );\n }\n\n const result = await response.json();\n\n return result;\n } catch (error) {\n console.error('Execute via server failed:', error);\n throw error;\n } finally {\n // Stop polling when execution completes (success or error)\n this.stopProgressPolling();\n }\n }\n\n // Helper method to build optional payload parameters\n private buildOptionalPayloadParams(\n options: ExecutionOptions,\n value: FormValue,\n ): Record<string, unknown> {\n const optionalParams: Record<string, unknown> = {};\n\n // Add optional parameters only if they have meaningful values\n const optionalFields = [\n { key: 'requestId', value: options.requestId },\n { key: 'deepLocate', value: options.deepLocate },\n { key: 'deepThink', value: options.deepThink },\n { key: 'screenshotIncluded', value: options.screenshotIncluded },\n { key: 'domIncluded', value: options.domIncluded },\n { key: 'deviceOptions', value: options.deviceOptions },\n { key: 'params', value: value.params },\n ] as const;\n\n optionalFields.forEach(({ key, value }) => {\n if (value !== undefined && value !== null && value !== '') {\n optionalParams[key] = value;\n }\n });\n\n return optionalParams;\n }\n\n // Get action space from server with fallback\n async getActionSpace(context?: unknown): Promise<DeviceAction<unknown>[]> {\n // Try server first if available\n if (this.serverUrl && typeof window !== 'undefined') {\n try {\n const response = await fetch(`${this.serverUrl}/action-space`, {\n method: 'POST',\n headers: {\n 'Content-Type': 'application/json',\n },\n body: JSON.stringify({ context }),\n });\n\n if (!response.ok) {\n throw new Error(`Failed to get action space: ${response.statusText}`);\n }\n\n const result = await response.json();\n return Array.isArray(result) ? result : [];\n } catch (error) {\n console.error('Failed to get action space from server:', error);\n // Fall through to context fallback\n }\n }\n\n // Fallback: try context.actionSpace if available\n if (context && typeof context === 'object' && 'actionSpace' in context) {\n try {\n const actionSpaceMethod = (\n context as {\n actionSpace: () =>\n | DeviceAction<unknown>[]\n | Promise<DeviceAction<unknown>[]>;\n }\n ).actionSpace;\n const result = await actionSpaceMethod();\n return Array.isArray(result) ? result : [];\n } catch (error) {\n console.error('Failed to get action space from context:', error);\n }\n }\n\n return [];\n }\n\n // Uses base implementation for validateParams and createDisplayContent\n\n // Server communication methods\n async checkStatus(): Promise<boolean> {\n if (!this.serverUrl) {\n return false;\n }\n\n try {\n const res = await fetch(`${this.serverUrl}/status`);\n if (res.status === 200) {\n // Try to extract id from response\n try {\n const data = await res.json();\n if (data.id && typeof data.id === 'string') {\n this._id = data.id;\n }\n } catch (jsonError) {\n // If JSON parsing fails, id remains undefined but status is still OK\n console.debug('Failed to parse status response:', jsonError);\n }\n return true;\n }\n return false;\n } catch (error) {\n console.warn('Server status check failed:', error);\n return false;\n }\n }\n\n async overrideConfig(aiConfig: Record<string, unknown>): Promise<void> {\n if (!this.serverUrl) {\n throw new Error('Server URL not configured');\n }\n\n try {\n const response = await fetch(`${this.serverUrl}/config`, {\n method: 'POST',\n headers: {\n 'Content-Type': 'application/json',\n },\n body: JSON.stringify({ aiConfig }),\n });\n\n if (!response.ok) {\n const body = await response.json().catch(() => null);\n const detail = body?.error || response.statusText;\n throw new Error(detail);\n }\n } catch (error) {\n console.error('Failed to override server config:', error);\n throw error;\n }\n }\n\n async runConnectivityTest(): Promise<ConnectivityTestResult> {\n if (!this.serverUrl) {\n throw new Error('Server URL not configured');\n }\n\n const response = await fetch(`${this.serverUrl}/connectivity-test`, {\n method: 'POST',\n });\n\n if (!response.ok) {\n const body = await response.json().catch(() => null);\n const detail = body?.error || response.statusText;\n throw new Error(detail);\n }\n\n return response.json();\n }\n\n async getTaskProgress(requestId: string): Promise<{\n executionDump?: ExecutionDump;\n }> {\n if (!this.serverUrl) {\n return {};\n }\n\n if (!requestId?.trim()) {\n console.warn('Invalid requestId provided for task progress');\n return {};\n }\n\n try {\n const response = await fetch(\n `${this.serverUrl}/task-progress/${encodeURIComponent(requestId)}`,\n );\n\n if (!response.ok) {\n console.warn(`Task progress request failed: ${response.statusText}`);\n return {};\n }\n\n return await response.json();\n } catch (error) {\n console.error('Failed to poll task progress:', error);\n return {};\n }\n }\n\n /**\n * Start polling for task progress and invoke dump update callback\n */\n private startProgressPolling(requestId: string): void {\n // Clear any existing polling\n this.stopProgressPolling();\n\n // Poll every 500ms for progress updates\n this.pollingIntervalId = setInterval(async () => {\n try {\n const progressData = await this.getTaskProgress(requestId);\n\n if (progressData.executionDump) {\n // Invoke dump update callback if set\n if (this.dumpUpdateCallback) {\n this.dumpUpdateCallback('', progressData.executionDump);\n }\n }\n } catch (error) {\n console.error('Error polling task progress:', error);\n }\n }, 500); // Poll every 500ms\n }\n\n /**\n * Stop polling for task progress\n */\n private stopProgressPolling(): void {\n if (this.pollingIntervalId) {\n clearInterval(this.pollingIntervalId);\n this.pollingIntervalId = undefined;\n }\n }\n\n // Cancel task\n async cancelTask(\n requestId: string,\n ): Promise<{ error?: string; success?: boolean }> {\n if (!this.serverUrl) {\n return { error: 'No server URL configured' };\n }\n\n if (!requestId?.trim()) {\n return { error: 'Invalid request ID' };\n }\n\n try {\n const res = await fetch(\n `${this.serverUrl}/cancel/${encodeURIComponent(requestId)}`,\n {\n method: 'POST',\n },\n );\n\n if (!res.ok) {\n return { error: `Cancel request failed: ${res.statusText}` };\n }\n\n const result = await res.json();\n return { success: true, ...result };\n } catch (error) {\n console.error('Failed to cancel task:', error);\n return { error: 'Failed to cancel task' };\n }\n }\n\n // Get screenshot from server\n async getScreenshot(): Promise<{\n screenshot: string;\n timestamp: number;\n } | null> {\n if (!this.serverUrl) {\n return null;\n }\n\n try {\n const response = await fetch(`${this.serverUrl}/screenshot`);\n\n if (!response.ok) {\n console.warn(`Screenshot request failed: ${response.statusText}`);\n return null;\n }\n\n return await response.json();\n } catch (error) {\n console.error('Failed to get screenshot:', error);\n return null;\n }\n }\n\n // Get interface information from server\n async getInterfaceInfo(): Promise<{\n type: string;\n description?: string;\n } | null> {\n if (!this.serverUrl) {\n return null;\n }\n\n try {\n const response = await fetch(`${this.serverUrl}/interface-info`);\n\n if (!response.ok) {\n console.warn(`Interface info request failed: ${response.statusText}`);\n return null;\n }\n\n return await response.json();\n } catch (error) {\n console.error('Failed to get interface info:', error);\n return null;\n }\n }\n\n async getRuntimeInfo(): Promise<PlaygroundRuntimeInfo | null> {\n if (!this.serverUrl) {\n return null;\n }\n\n try {\n const response = await fetch(`${this.serverUrl}/runtime-info`);\n\n if (!response.ok) {\n console.warn(`Runtime info request failed: ${response.statusText}`);\n return null;\n }\n\n return await response.json();\n } catch (error) {\n console.error('Failed to get runtime info:', error);\n return null;\n }\n }\n\n async getSessionInfo(): Promise<PlaygroundSessionState | null> {\n if (!this.serverUrl) {\n return null;\n }\n\n try {\n const response = await fetch(`${this.serverUrl}/session`);\n if (!response.ok) {\n console.warn(`Session info request failed: ${response.statusText}`);\n return null;\n }\n\n return await response.json();\n } catch (error) {\n console.error('Failed to get session info:', error);\n return null;\n }\n }\n\n async getSessionSetup(\n input?: Record<string, unknown>,\n ): Promise<PlaygroundSessionSetup | null> {\n if (!this.serverUrl) {\n return null;\n }\n\n try {\n const searchParams = new URLSearchParams();\n Object.entries(input || {}).forEach(([key, value]) => {\n if (\n typeof value === 'string' ||\n typeof value === 'number' ||\n typeof value === 'boolean'\n ) {\n searchParams.set(key, String(value));\n }\n });\n const suffix = searchParams.size > 0 ? `?${searchParams.toString()}` : '';\n const response = await fetch(`${this.serverUrl}/session/setup${suffix}`);\n if (!response.ok) {\n const body = await response.json().catch(() => null);\n throw new Error(\n body?.error || response.statusText || 'Failed to load session setup',\n );\n }\n\n return await response.json();\n } catch (error) {\n console.error('Failed to get session setup:', error);\n throw error;\n }\n }\n\n async listSessionTargets(): Promise<PlaygroundSessionTarget[]> {\n if (!this.serverUrl) {\n return [];\n }\n\n try {\n const response = await fetch(`${this.serverUrl}/session/targets`);\n if (!response.ok) {\n const body = await response.json().catch(() => null);\n throw new Error(\n body?.error ||\n response.statusText ||\n 'Failed to load session targets',\n );\n }\n\n const result = await response.json();\n return Array.isArray(result) ? result : [];\n } catch (error) {\n console.error('Failed to get session targets:', error);\n throw error;\n }\n }\n\n async createSession(input?: Record<string, unknown>): Promise<{\n session: PlaygroundSessionState;\n runtimeInfo: PlaygroundRuntimeInfo;\n }> {\n if (!this.serverUrl) {\n throw new Error('Server URL not configured');\n }\n\n const response = await fetch(`${this.serverUrl}/session`, {\n method: 'POST',\n headers: {\n 'Content-Type': 'application/json',\n },\n body: JSON.stringify(input || {}),\n });\n\n if (!response.ok) {\n const body = await response.json().catch(() => null);\n throw new Error(body?.error || response.statusText);\n }\n\n return await response.json();\n }\n\n async destroySession(): Promise<{\n session: PlaygroundSessionState;\n runtimeInfo: PlaygroundRuntimeInfo;\n }> {\n if (!this.serverUrl) {\n throw new Error('Server URL not configured');\n }\n\n const response = await fetch(`${this.serverUrl}/session`, {\n method: 'DELETE',\n });\n\n if (!response.ok) {\n const body = await response.json().catch(() => null);\n throw new Error(body?.error || response.statusText);\n }\n\n return await response.json();\n }\n}\n"],"names":["RemoteExecutionAdapter","BasePlaygroundAdapter","callback","undefined","value","action","needsStructuredParams","schema","shape","missingFields","Object","key","fieldDef","isOptional","params","options","parseStructuredParams","error","message","androidErrors","androidError","keyword","actionType","window","Error","payload","response","fetch","JSON","errorText","result","console","optionalParams","optionalFields","context","Array","actionSpaceMethod","res","data","jsonError","aiConfig","body","detail","requestId","encodeURIComponent","setInterval","progressData","clearInterval","input","searchParams","URLSearchParams","String","suffix","serverUrl"],"mappings":"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"}
1
+ {"version":3,"file":"adapters/remote-execution.mjs","sources":["../../../src/adapters/remote-execution.ts"],"sourcesContent":["import type {\n ConnectivityTestResult,\n DeviceAction,\n ExecutionDump,\n} from '@midscene/core';\nimport { parseStructuredParams } from '../common';\nimport type {\n PlaygroundSessionSetup,\n PlaygroundSessionState,\n PlaygroundSessionTarget,\n} from '../platform';\nimport type { PlaygroundRuntimeInfo } from '../runtime-metadata';\nimport type { ExecutionOptions, FormValue, ValidationResult } from '../types';\nimport { BasePlaygroundAdapter } from './base';\n\nexport class RemoteExecutionAdapter extends BasePlaygroundAdapter {\n private serverUrl?: string;\n private _id?: string;\n private dumpUpdateCallback?: (\n dump: string,\n executionDump?: ExecutionDump,\n ) => void;\n private pollingIntervalId?: ReturnType<typeof setInterval>;\n\n constructor(serverUrl: string) {\n super();\n this.serverUrl = serverUrl;\n }\n\n // Set dump update callback\n onDumpUpdate(\n callback: (dump: string, executionDump?: ExecutionDump) => void,\n ): void {\n this.dumpUpdateCallback = undefined;\n this.dumpUpdateCallback = callback;\n }\n\n // Get adapter ID (cached after first status check for remote)\n get id(): string | undefined {\n return this._id;\n }\n\n // Override validateParams for remote execution\n // Since schemas from server are JSON-serialized and lack .parse() method\n validateParams(\n value: FormValue,\n action: DeviceAction<unknown> | undefined,\n ): ValidationResult {\n if (!action?.paramSchema) {\n return { valid: true };\n }\n\n const needsStructuredParams = this.actionNeedsStructuredParams(action);\n\n if (!needsStructuredParams) {\n return { valid: true };\n }\n\n if (!value.params) {\n return { valid: false, errorMessage: 'Parameters are required' };\n }\n\n // For remote execution, perform basic validation without .parse()\n // Check if required fields are present\n if (action.paramSchema && typeof action.paramSchema === 'object') {\n const schema = action.paramSchema as any;\n if (schema.shape || schema.type === 'ZodObject') {\n const shape = schema.shape || {};\n const missingFields = Object.keys(shape).filter((key) => {\n const fieldDef = shape[key];\n // Check if field is required (not optional)\n const isOptional =\n fieldDef?.isOptional ||\n fieldDef?._def?.innerType || // ZodOptional\n fieldDef?._def?.typeName === 'ZodOptional';\n return (\n !isOptional &&\n (value.params![key] === undefined || value.params![key] === '')\n );\n });\n\n if (missingFields.length > 0) {\n return {\n valid: false,\n errorMessage: `Missing required parameters: ${missingFields.join(', ')}`,\n };\n }\n }\n }\n\n return { valid: true };\n }\n\n async parseStructuredParams(\n action: DeviceAction<unknown>,\n params: Record<string, unknown>,\n options: ExecutionOptions,\n ): Promise<unknown[]> {\n // Use shared implementation from common.ts\n return await parseStructuredParams(action, params, options);\n }\n\n formatErrorMessage(error: any): string {\n const message = error?.message || '';\n\n // Handle Android-specific errors\n const androidErrors = [\n {\n keyword: 'adb',\n message:\n 'ADB connection error. Please ensure device is connected and USB debugging is enabled.',\n },\n {\n keyword: 'UIAutomator',\n message:\n 'UIAutomator error. Please ensure the UIAutomator server is running on the device.',\n },\n ];\n\n const androidError = androidErrors.find(({ keyword }) =>\n message.includes(keyword),\n );\n if (androidError) {\n return androidError.message;\n }\n\n return this.formatBasicErrorMessage(error);\n }\n\n // Remote execution adapter - simplified interface\n async executeAction(\n actionType: string,\n value: FormValue,\n options: ExecutionOptions,\n ): Promise<unknown> {\n // If serverUrl is provided, use server-side execution\n if (this.serverUrl && typeof window !== 'undefined') {\n return this.executeViaServer(actionType, value, options);\n }\n\n throw new Error(\n 'Remote execution adapter requires server URL for execution',\n );\n }\n\n // Remote execution via server - uses same endpoint as requestPlaygroundServer\n private async executeViaServer(\n actionType: string,\n value: FormValue,\n options: ExecutionOptions,\n ): Promise<unknown> {\n const payload: Record<string, unknown> = {\n type: actionType,\n prompt: value.prompt,\n ...this.buildOptionalPayloadParams(options, value),\n };\n\n // Add context only if it exists (server can handle single agent case without context)\n if (options.context) {\n payload.context = options.context;\n }\n\n // Start polling if requestId is provided and dumpUpdateCallback is set\n if (options.requestId && this.dumpUpdateCallback) {\n this.startProgressPolling(options.requestId);\n }\n\n try {\n const response = await fetch(`${this.serverUrl}/execute`, {\n method: 'POST',\n headers: {\n 'Content-Type': 'application/json',\n },\n body: JSON.stringify(payload),\n });\n\n if (!response.ok) {\n const errorText = await response.text().catch(() => 'Unknown error');\n throw new Error(\n `Server request failed (${response.status}): ${errorText}`,\n );\n }\n\n const result = await response.json();\n\n return result;\n } catch (error) {\n console.error('Execute via server failed:', error);\n throw error;\n } finally {\n // Stop polling when execution completes (success or error)\n this.stopProgressPolling();\n }\n }\n\n // Helper method to build optional payload parameters\n private buildOptionalPayloadParams(\n options: ExecutionOptions,\n value: FormValue,\n ): Record<string, unknown> {\n const optionalParams: Record<string, unknown> = {};\n\n // Add optional parameters only if they have meaningful values\n const optionalFields = [\n { key: 'requestId', value: options.requestId },\n { key: 'deepLocate', value: options.deepLocate },\n { key: 'deepThink', value: options.deepThink },\n { key: 'screenshotIncluded', value: options.screenshotIncluded },\n { key: 'domIncluded', value: options.domIncluded },\n { key: 'deviceOptions', value: options.deviceOptions },\n { key: 'params', value: value.params },\n ] as const;\n\n optionalFields.forEach(({ key, value }) => {\n if (value !== undefined && value !== null && value !== '') {\n optionalParams[key] = value;\n }\n });\n\n return optionalParams;\n }\n\n // Get action space from server with fallback\n async getActionSpace(context?: unknown): Promise<DeviceAction<unknown>[]> {\n // Try server first if available\n if (this.serverUrl && typeof window !== 'undefined') {\n try {\n const response = await fetch(`${this.serverUrl}/action-space`, {\n method: 'POST',\n headers: {\n 'Content-Type': 'application/json',\n },\n body: JSON.stringify({ context }),\n });\n\n if (!response.ok) {\n throw new Error(`Failed to get action space: ${response.statusText}`);\n }\n\n const result = await response.json();\n return Array.isArray(result) ? result : [];\n } catch (error) {\n console.error('Failed to get action space from server:', error);\n // Fall through to context fallback\n }\n }\n\n // Fallback: try context.actionSpace if available\n if (context && typeof context === 'object' && 'actionSpace' in context) {\n try {\n const actionSpaceMethod = (\n context as {\n actionSpace: () =>\n | DeviceAction<unknown>[]\n | Promise<DeviceAction<unknown>[]>;\n }\n ).actionSpace;\n const result = await actionSpaceMethod();\n return Array.isArray(result) ? result : [];\n } catch (error) {\n console.error('Failed to get action space from context:', error);\n }\n }\n\n return [];\n }\n\n // Uses base implementation for validateParams and createDisplayContent\n\n // Server communication methods\n async checkStatus(): Promise<boolean> {\n if (!this.serverUrl) {\n return false;\n }\n\n try {\n const res = await fetch(`${this.serverUrl}/status`);\n if (res.status === 200) {\n // Try to extract id from response\n try {\n const data = await res.json();\n if (data.id && typeof data.id === 'string') {\n this._id = data.id;\n }\n } catch (jsonError) {\n // If JSON parsing fails, id remains undefined but status is still OK\n console.debug('Failed to parse status response:', jsonError);\n }\n return true;\n }\n return false;\n } catch (error) {\n console.warn('Server status check failed:', error);\n return false;\n }\n }\n\n async overrideConfig(aiConfig: Record<string, unknown>): Promise<void> {\n if (!this.serverUrl) {\n throw new Error('Server URL not configured');\n }\n\n try {\n const response = await fetch(`${this.serverUrl}/config`, {\n method: 'POST',\n headers: {\n 'Content-Type': 'application/json',\n },\n body: JSON.stringify({ aiConfig }),\n });\n\n if (!response.ok) {\n const body = await response.json().catch(() => null);\n const detail = body?.error || response.statusText;\n throw new Error(detail);\n }\n } catch (error) {\n console.error('Failed to override server config:', error);\n throw error;\n }\n }\n\n async runConnectivityTest(): Promise<ConnectivityTestResult> {\n if (!this.serverUrl) {\n throw new Error('Server URL not configured');\n }\n\n const response = await fetch(`${this.serverUrl}/connectivity-test`, {\n method: 'POST',\n });\n\n if (!response.ok) {\n const body = await response.json().catch(() => null);\n const detail = body?.error || response.statusText;\n throw new Error(detail);\n }\n\n return response.json();\n }\n\n async getTaskProgress(requestId: string): Promise<{\n executionDump?: ExecutionDump;\n }> {\n if (!this.serverUrl) {\n return {};\n }\n\n if (!requestId?.trim()) {\n console.warn('Invalid requestId provided for task progress');\n return {};\n }\n\n try {\n const response = await fetch(\n `${this.serverUrl}/task-progress/${encodeURIComponent(requestId)}`,\n );\n\n if (!response.ok) {\n console.warn(`Task progress request failed: ${response.statusText}`);\n return {};\n }\n\n return await response.json();\n } catch (error) {\n console.error('Failed to poll task progress:', error);\n return {};\n }\n }\n\n /**\n * Start polling for task progress and invoke dump update callback\n */\n private startProgressPolling(requestId: string): void {\n // Clear any existing polling\n this.stopProgressPolling();\n\n // Poll every 500ms for progress updates\n this.pollingIntervalId = setInterval(async () => {\n try {\n const progressData = await this.getTaskProgress(requestId);\n\n if (progressData.executionDump) {\n // Invoke dump update callback if set\n if (this.dumpUpdateCallback) {\n this.dumpUpdateCallback('', progressData.executionDump);\n }\n }\n } catch (error) {\n console.error('Error polling task progress:', error);\n }\n }, 500); // Poll every 500ms\n }\n\n /**\n * Stop polling for task progress\n */\n private stopProgressPolling(): void {\n if (this.pollingIntervalId) {\n clearInterval(this.pollingIntervalId);\n this.pollingIntervalId = undefined;\n }\n }\n\n // Cancel task\n async cancelTask(\n requestId: string,\n ): Promise<{ error?: string; success?: boolean }> {\n if (!this.serverUrl) {\n return { error: 'No server URL configured' };\n }\n\n if (!requestId?.trim()) {\n return { error: 'Invalid request ID' };\n }\n\n try {\n const res = await fetch(\n `${this.serverUrl}/cancel/${encodeURIComponent(requestId)}`,\n {\n method: 'POST',\n },\n );\n\n if (!res.ok) {\n return { error: `Cancel request failed: ${res.statusText}` };\n }\n\n const result = await res.json();\n return { success: true, ...result };\n } catch (error) {\n console.error('Failed to cancel task:', error);\n return { error: 'Failed to cancel task' };\n }\n }\n\n // Get screenshot from server\n async getScreenshot(): Promise<{\n screenshot: string;\n timestamp: number;\n } | null> {\n if (!this.serverUrl) {\n return null;\n }\n\n try {\n const response = await fetch(`${this.serverUrl}/screenshot`);\n\n if (!response.ok) {\n if (response.status !== 409) {\n console.warn(`Screenshot request failed: ${response.statusText}`);\n }\n return null;\n }\n\n return await response.json();\n } catch (error) {\n console.error('Failed to get screenshot:', error);\n return null;\n }\n }\n\n // Get interface information from server\n async getInterfaceInfo(): Promise<{\n type: string;\n description?: string;\n } | null> {\n if (!this.serverUrl) {\n return null;\n }\n\n try {\n const response = await fetch(`${this.serverUrl}/interface-info`);\n\n if (!response.ok) {\n console.warn(`Interface info request failed: ${response.statusText}`);\n return null;\n }\n\n return await response.json();\n } catch (error) {\n console.error('Failed to get interface info:', error);\n return null;\n }\n }\n\n async getRuntimeInfo(): Promise<PlaygroundRuntimeInfo | null> {\n if (!this.serverUrl) {\n return null;\n }\n\n try {\n const response = await fetch(`${this.serverUrl}/runtime-info`);\n\n if (!response.ok) {\n console.warn(`Runtime info request failed: ${response.statusText}`);\n return null;\n }\n\n return await response.json();\n } catch (error) {\n console.error('Failed to get runtime info:', error);\n return null;\n }\n }\n\n async getSessionInfo(): Promise<PlaygroundSessionState | null> {\n if (!this.serverUrl) {\n return null;\n }\n\n try {\n const response = await fetch(`${this.serverUrl}/session`);\n if (!response.ok) {\n console.warn(`Session info request failed: ${response.statusText}`);\n return null;\n }\n\n return await response.json();\n } catch (error) {\n console.error('Failed to get session info:', error);\n return null;\n }\n }\n\n async getSessionSetup(\n input?: Record<string, unknown>,\n ): Promise<PlaygroundSessionSetup | null> {\n if (!this.serverUrl) {\n return null;\n }\n\n try {\n const searchParams = new URLSearchParams();\n Object.entries(input || {}).forEach(([key, value]) => {\n if (\n typeof value === 'string' ||\n typeof value === 'number' ||\n typeof value === 'boolean'\n ) {\n searchParams.set(key, String(value));\n }\n });\n const suffix = searchParams.size > 0 ? `?${searchParams.toString()}` : '';\n const response = await fetch(`${this.serverUrl}/session/setup${suffix}`);\n if (!response.ok) {\n const body = await response.json().catch(() => null);\n throw new Error(\n body?.error || response.statusText || 'Failed to load session setup',\n );\n }\n\n return await response.json();\n } catch (error) {\n console.error('Failed to get session setup:', error);\n throw error;\n }\n }\n\n async listSessionTargets(): Promise<PlaygroundSessionTarget[]> {\n if (!this.serverUrl) {\n return [];\n }\n\n try {\n const response = await fetch(`${this.serverUrl}/session/targets`);\n if (!response.ok) {\n const body = await response.json().catch(() => null);\n throw new Error(\n body?.error ||\n response.statusText ||\n 'Failed to load session targets',\n );\n }\n\n const result = await response.json();\n return Array.isArray(result) ? result : [];\n } catch (error) {\n console.error('Failed to get session targets:', error);\n throw error;\n }\n }\n\n async createSession(input?: Record<string, unknown>): Promise<{\n session: PlaygroundSessionState;\n runtimeInfo: PlaygroundRuntimeInfo;\n }> {\n if (!this.serverUrl) {\n throw new Error('Server URL not configured');\n }\n\n const response = await fetch(`${this.serverUrl}/session`, {\n method: 'POST',\n headers: {\n 'Content-Type': 'application/json',\n },\n body: JSON.stringify(input || {}),\n });\n\n if (!response.ok) {\n const body = await response.json().catch(() => null);\n throw new Error(body?.error || response.statusText);\n }\n\n return await response.json();\n }\n\n async destroySession(): Promise<{\n session: PlaygroundSessionState;\n runtimeInfo: PlaygroundRuntimeInfo;\n }> {\n if (!this.serverUrl) {\n throw new Error('Server URL not configured');\n }\n\n const response = await fetch(`${this.serverUrl}/session`, {\n method: 'DELETE',\n });\n\n if (!response.ok) {\n const body = await response.json().catch(() => null);\n throw new Error(body?.error || response.statusText);\n }\n\n return await response.json();\n }\n}\n"],"names":["RemoteExecutionAdapter","BasePlaygroundAdapter","callback","undefined","value","action","needsStructuredParams","schema","shape","missingFields","Object","key","fieldDef","isOptional","params","options","parseStructuredParams","error","message","androidErrors","androidError","keyword","actionType","window","Error","payload","response","fetch","JSON","errorText","result","console","optionalParams","optionalFields","context","Array","actionSpaceMethod","res","data","jsonError","aiConfig","body","detail","requestId","encodeURIComponent","setInterval","progressData","clearInterval","input","searchParams","URLSearchParams","String","suffix","serverUrl"],"mappings":"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"}
@@ -22,6 +22,9 @@ function _define_property(obj, key, value) {
22
22
  return obj;
23
23
  }
24
24
  const defaultPort = PLAYGROUND_SERVER_PORT;
25
+ function serializeAiConfigSignature(aiConfig) {
26
+ return JSON.stringify(Object.entries(aiConfig).sort(([leftKey], [rightKey])=>leftKey.localeCompare(rightKey)));
27
+ }
25
28
  function serializeZodField(field) {
26
29
  if (!field || 'object' != typeof field) return field;
27
30
  const def = field._def;
@@ -209,6 +212,7 @@ class PlaygroundServer {
209
212
  console.warn('Failed to destroy old agent:', error);
210
213
  } finally{
211
214
  this._activeConnection.agent = null;
215
+ this._configDirty = false;
212
216
  }
213
217
  }
214
218
  async destroyCurrentSession() {
@@ -645,8 +649,9 @@ class PlaygroundServer {
645
649
  });
646
650
  } catch (error) {
647
651
  const errorMessage = error instanceof Error ? error.message : 'Unknown error';
648
- console.error(`Failed to take screenshot: ${errorMessage}`);
649
- res.status('No active session' === errorMessage ? 409 : 500).json({
652
+ const statusCode = 'No active session' === errorMessage ? 409 : 500;
653
+ if (409 !== statusCode) console.error(`Failed to take screenshot: ${errorMessage}`);
654
+ res.status(statusCode).json({
650
655
  error: `Failed to take screenshot: ${errorMessage}`
651
656
  });
652
657
  }
@@ -701,9 +706,14 @@ class PlaygroundServer {
701
706
  status: 'ok',
702
707
  message: 'AI config not changed due to empty object'
703
708
  });
709
+ const nextConfigSignature = serializeAiConfigSignature(aiConfig);
710
+ const configChanged = nextConfigSignature !== this._lastAiConfigSignature;
704
711
  try {
705
- overrideAIConfig(aiConfig);
706
- this._configDirty = true;
712
+ if (configChanged) {
713
+ overrideAIConfig(aiConfig);
714
+ this._lastAiConfigSignature = nextConfigSignature;
715
+ this._configDirty = Boolean(this._activeConnection.agent);
716
+ }
707
717
  } catch (error) {
708
718
  const errorMessage = error instanceof Error ? error.message : 'Unknown error';
709
719
  console.error(`Failed to update AI config: ${errorMessage}`);
@@ -711,6 +721,10 @@ class PlaygroundServer {
711
721
  error: `Failed to update AI config: ${errorMessage}`
712
722
  });
713
723
  }
724
+ if (!configChanged) return res.json({
725
+ status: 'ok',
726
+ message: 'AI config not changed because it is identical to current'
727
+ });
714
728
  try {
715
729
  globalModelConfigManager.getModelConfig('default');
716
730
  } catch (error) {
@@ -722,7 +736,7 @@ class PlaygroundServer {
722
736
  }
723
737
  return res.json({
724
738
  status: 'ok',
725
- message: 'AI config updated. Agent will be recreated on next execution.'
739
+ message: this._configDirty ? 'AI config updated. Agent will be recreated on next execution.' : 'AI config updated. New sessions will use it immediately.'
726
740
  });
727
741
  });
728
742
  this.app.post('/connectivity-test', async (_req, res)=>{
@@ -898,6 +912,7 @@ class PlaygroundServer {
898
912
  _define_property(this, "currentTaskId", null);
899
913
  _define_property(this, "_agentReady", true);
900
914
  _define_property(this, "_configDirty", false);
915
+ _define_property(this, "_lastAiConfigSignature", null);
901
916
  _define_property(this, "_baseRuntimeState", void 0);
902
917
  _define_property(this, "_basePreparedMetadata", void 0);
903
918
  _define_property(this, "_baseExecutionHooks", void 0);
@@ -1 +1 @@
1
- {"version":3,"file":"server.mjs","sources":["../../src/server.ts"],"sourcesContent":["import { existsSync, readFileSync, writeFileSync } from 'node:fs';\nimport http from 'node:http';\nimport type { Server } from 'node:http';\nimport { dirname, join, resolve } from 'node:path';\nimport { fileURLToPath } from 'node:url';\nimport type { ExecutionDump } from '@midscene/core';\nimport { ReportActionDump, runConnectivityTest } from '@midscene/core';\nimport type { Agent as PageAgent } from '@midscene/core/agent';\nimport { getTmpDir } from '@midscene/core/utils';\nimport { PLAYGROUND_SERVER_PORT } from '@midscene/shared/constants';\nimport {\n globalModelConfigManager,\n overrideAIConfig,\n} from '@midscene/shared/env';\nimport { uuid } from '@midscene/shared/utils';\nimport express, { type Request, type Response } from 'express';\nimport { executeAction, formatErrorMessage } from './common';\nimport type {\n PlaygroundCreatedSession,\n PlaygroundExecutionHooks,\n PlaygroundPreviewDescriptor,\n PlaygroundSessionManager,\n PlaygroundSessionSetup,\n PlaygroundSessionState,\n PlaygroundSessionTarget,\n PlaygroundSidecar,\n PreparedPlaygroundPlatform,\n} from './platform';\nimport {\n type PlaygroundRuntimeInfo,\n buildRuntimeInfo,\n} from './runtime-metadata';\nimport type { AgentFactory } from './types';\n\nimport 'dotenv/config';\n\nconst defaultPort = PLAYGROUND_SERVER_PORT;\n\n/**\n * Recursively serialize a Zod field into a plain object that preserves\n * the `_def` metadata the client relies on (typeName, innerType, values,\n * defaultValue, description, shape, etc.).\n */\nexport function serializeZodField(field: any): any {\n if (!field || typeof field !== 'object') return field;\n\n const def = field._def;\n if (!def || typeof def !== 'object') return field;\n\n const typeName: string | undefined = def.typeName;\n\n const result: Record<string, any> = {\n _def: {\n typeName,\n },\n };\n\n // Preserve description\n if (def.description) {\n result._def.description = def.description;\n }\n\n // Wrapper types (ZodOptional, ZodDefault, ZodNullable) – recurse into innerType\n if (def.innerType) {\n result._def.innerType = serializeZodField(def.innerType);\n }\n\n // ZodDefault – preserve defaultValue as a serializable plain value\n if (typeName === 'ZodDefault' && typeof def.defaultValue === 'function') {\n try {\n result._def._serializedDefaultValue = def.defaultValue();\n } catch {\n // ignore\n }\n }\n\n // ZodEnum – preserve values array\n if (typeName === 'ZodEnum' && Array.isArray(def.values)) {\n result._def.values = def.values;\n }\n\n // ZodObject – recurse into shape\n if (typeName === 'ZodObject') {\n const rawShape = typeof def.shape === 'function' ? def.shape() : def.shape;\n if (rawShape && typeof rawShape === 'object') {\n const serializedShape: Record<string, any> = {};\n for (const [k, v] of Object.entries(rawShape)) {\n serializedShape[k] = serializeZodField(v);\n }\n result._def.shape = serializedShape;\n result.shape = serializedShape;\n }\n }\n\n // Copy top-level description for compatibility\n if (field.description) {\n result.description = field.description;\n }\n\n return result;\n}\n\n// Static path for playground files\nconst __filename = fileURLToPath(import.meta.url);\nconst __dirname = dirname(__filename);\nconst STATIC_PATH = join(__dirname, '..', '..', 'static');\n\nconst errorHandler = (\n err: unknown,\n req: Request,\n res: Response,\n next: express.NextFunction,\n) => {\n console.error(err);\n const errorMessage =\n err instanceof Error ? err.message : 'Internal server error';\n res.status(500).json({\n error: errorMessage,\n });\n};\n\ninterface PlaygroundRuntimeState {\n platformId?: string;\n title?: string;\n description?: string;\n preview?: PlaygroundPreviewDescriptor;\n metadata?: Record<string, unknown>;\n}\n\ninterface PlaygroundActiveConnection {\n session: PlaygroundSessionState | null;\n agent: PageAgent | null;\n agentFactory?: AgentFactory | null;\n runtime?: PlaygroundRuntimeState;\n executionHooks?: PlaygroundExecutionHooks;\n sidecars?: PlaygroundSidecar[];\n}\n\nclass PlaygroundServer {\n private _app: express.Application;\n tmpDir: string;\n server?: Server;\n port?: number | null;\n staticPath: string;\n taskExecutionDumps: Record<string, ExecutionDump | null>; // Store execution dumps directly\n id: string; // Unique identifier for this server instance\n\n /**\n * Port for scrcpy server (used by Android playground for screen mirroring)\n * When set, this port is injected into the HTML page as window.SCRCPY_PORT\n */\n scrcpyPort?: number;\n\n private _initialized = false;\n\n // Native MJPEG stream probe: null = not tested, true/false = result\n private _nativeMjpegAvailable: boolean | null = null;\n\n private sessionManager?: PlaygroundSessionManager;\n private sessionSetupState: 'required' | 'ready' | 'blocked' = 'ready';\n private sessionSetupBlockingReason?: string;\n\n // Track current running task\n private currentTaskId: string | null = null;\n\n // Flag to pause MJPEG polling during agent recreation or task execution\n private _agentReady = true;\n\n // Flag to track if AI config has changed and agent needs recreation\n private _configDirty = false;\n private _baseRuntimeState?: PlaygroundRuntimeState;\n private _basePreparedMetadata?: Record<string, unknown>;\n private _baseExecutionHooks?: PlaygroundExecutionHooks;\n private _baseSidecars?: PlaygroundSidecar[];\n private _activeConnection: PlaygroundActiveConnection = {\n session: null,\n agent: null,\n agentFactory: null,\n runtime: undefined,\n executionHooks: undefined,\n sidecars: undefined,\n };\n\n constructor(\n agent?: PageAgent | (() => PageAgent) | (() => Promise<PageAgent>),\n staticPath = STATIC_PATH,\n id?: string, // Optional override ID\n ) {\n this._app = express();\n this.tmpDir = getTmpDir()!;\n this.staticPath = staticPath;\n this.taskExecutionDumps = {}; // Initialize as empty object\n // Use provided ID, or generate random UUID for each startup\n this.id = id || uuid();\n\n // Support both instance and factory function modes\n if (typeof agent === 'function') {\n this._activeConnection.agentFactory = agent;\n } else {\n this._activeConnection.agent = agent || null;\n }\n }\n\n get agent(): PageAgent | null {\n return this._activeConnection.agent;\n }\n\n private assertNoActiveSessionForBaseStateUpdate(methodName: string): void {\n if (this._activeConnection.session) {\n throw new Error(\n `${methodName} cannot update prepared state while a session is active`,\n );\n }\n }\n\n private buildBaseRuntimeState(): PlaygroundRuntimeState | undefined {\n if (!this._baseRuntimeState) {\n return undefined;\n }\n\n return {\n ...this._baseRuntimeState,\n metadata: this.buildSessionMetadata(),\n };\n }\n\n private resetConnectionToBaseState(): void {\n this._activeConnection = {\n session: null,\n agent: this._activeConnection.agent,\n agentFactory: this._activeConnection.agentFactory,\n runtime: this.buildBaseRuntimeState(),\n executionHooks: this._baseExecutionHooks,\n sidecars: this._baseSidecars,\n };\n }\n\n private syncRuntimeState(): void {\n this._baseRuntimeState = {\n ...(this._baseRuntimeState || {}),\n metadata: this.buildSessionMetadata(),\n };\n\n if (this._activeConnection.session) {\n this._activeConnection = {\n ...this._activeConnection,\n runtime: this._activeConnection.runtime\n ? {\n ...this._activeConnection.runtime,\n metadata: this.buildSessionMetadata(),\n }\n : this.buildBaseRuntimeState(),\n };\n return;\n }\n\n this.resetConnectionToBaseState();\n }\n\n private restoreBaseSessionState(): void {\n this.taskExecutionDumps = {};\n this.currentTaskId = null;\n this.sessionSetupState =\n this.sessionSetupState === 'blocked' ? 'blocked' : 'required';\n this._activeConnection = {\n session: null,\n agent: null,\n agentFactory: null,\n runtime: this.buildBaseRuntimeState(),\n executionHooks: this._baseExecutionHooks,\n sidecars: this._baseSidecars,\n };\n this.syncRuntimeState();\n }\n\n setPreparedPlatform(\n prepared: Pick<\n PreparedPlaygroundPlatform,\n | 'platformId'\n | 'title'\n | 'description'\n | 'preview'\n | 'metadata'\n | 'sessionManager'\n | 'executionHooks'\n | 'sidecars'\n >,\n ): void {\n // Allow overriding the initial session created by agentFactory in launch()\n if (this._activeConnection.session && this._activeConnection.agentFactory) {\n this._activeConnection.session = null;\n }\n this.assertNoActiveSessionForBaseStateUpdate('setPreparedPlatform');\n this.sessionManager = prepared.sessionManager;\n this._basePreparedMetadata = prepared.metadata\n ? { ...prepared.metadata }\n : undefined;\n this._baseRuntimeState = {\n platformId: prepared.platformId,\n title: prepared.title,\n description: prepared.description,\n preview: prepared.preview,\n metadata: this.buildSessionMetadata(),\n };\n this._baseExecutionHooks = prepared.executionHooks;\n this._baseSidecars = prepared.sidecars;\n this.resetConnectionToBaseState();\n\n if (\n this.sessionManager &&\n !this._activeConnection.agent &&\n !this._activeConnection.session\n ) {\n this.sessionSetupState =\n this._basePreparedMetadata?.setupState === 'blocked'\n ? 'blocked'\n : 'required';\n this.sessionSetupBlockingReason =\n typeof this._basePreparedMetadata?.setupBlockingReason === 'string'\n ? this._basePreparedMetadata.setupBlockingReason\n : undefined;\n }\n }\n\n setPreviewDescriptor(preview?: PlaygroundPreviewDescriptor): void {\n this.assertNoActiveSessionForBaseStateUpdate('setPreviewDescriptor');\n this._baseRuntimeState = {\n ...(this._baseRuntimeState || {}),\n preview,\n };\n this.resetConnectionToBaseState();\n }\n\n setRuntimeMetadata(metadata?: Record<string, unknown>): void {\n this.assertNoActiveSessionForBaseStateUpdate('setRuntimeMetadata');\n this._basePreparedMetadata = metadata ? { ...metadata } : undefined;\n this.syncRuntimeState();\n }\n\n getRuntimeInfo(): PlaygroundRuntimeInfo {\n return buildRuntimeInfo({\n platformId: this._activeConnection.runtime?.platformId,\n title: this._activeConnection.runtime?.title,\n platformDescription: this._activeConnection.runtime?.description,\n interfaceType:\n this._activeConnection.agent?.interface?.interfaceType || 'Unknown',\n interfaceDescription:\n this._activeConnection.agent?.interface?.describe?.() || undefined,\n preview: this._activeConnection.runtime?.preview,\n metadata: this.buildSessionMetadata(),\n supportsScreenshot:\n typeof this._activeConnection.agent?.interface?.screenshotBase64 ===\n 'function',\n mjpegStreamUrl: this._activeConnection.agent?.interface?.mjpegStreamUrl,\n scrcpyPort: this.scrcpyPort,\n });\n }\n\n getSessionInfo(): PlaygroundSessionState & {\n setupState: 'required' | 'ready' | 'blocked';\n setupBlockingReason?: string;\n } {\n const connected = this.sessionManager\n ? Boolean(\n this._activeConnection.session?.connected &&\n this._activeConnection.agent,\n )\n : Boolean(this._activeConnection.agent);\n\n return {\n connected,\n displayName: this._activeConnection.session?.displayName,\n metadata: {\n ...(this._activeConnection.session?.metadata || {}),\n },\n setupState: this.sessionSetupState,\n setupBlockingReason: this.sessionSetupBlockingReason,\n };\n }\n\n private buildSessionMetadata(): Record<string, unknown> {\n const sessionConnected = this.sessionManager\n ? Boolean(\n this._activeConnection.session?.connected &&\n this._activeConnection.agent,\n )\n : Boolean(this._activeConnection.agent);\n\n return {\n ...(this._basePreparedMetadata || {}),\n ...(this._activeConnection.session?.metadata || {}),\n sessionConnected,\n sessionDisplayName: this._activeConnection.session?.displayName,\n setupState: this.sessionSetupState,\n ...(this.sessionSetupBlockingReason\n ? { setupBlockingReason: this.sessionSetupBlockingReason }\n : {}),\n };\n }\n\n private async startSidecars(sidecars?: PlaygroundSidecar[]): Promise<void> {\n for (const sidecar of sidecars || []) {\n await sidecar.start();\n }\n }\n\n private async stopSidecars(sidecars?: PlaygroundSidecar[]): Promise<void> {\n for (const sidecar of sidecars || []) {\n await sidecar.stop?.();\n }\n }\n\n private getActiveAgentOrThrow(): PageAgent {\n if (!this._activeConnection.agent) {\n throw new Error('No active session');\n }\n\n return this._activeConnection.agent;\n }\n\n private async destroyCurrentAgent(): Promise<void> {\n if (!this._activeConnection.agent) {\n return;\n }\n\n try {\n if (typeof this._activeConnection.agent.destroy === 'function') {\n await this._activeConnection.agent.destroy();\n }\n } catch (error) {\n console.warn('Failed to destroy old agent:', error);\n } finally {\n this._activeConnection.agent = null;\n }\n }\n\n private async destroyCurrentSession(): Promise<void> {\n const previousSession = this._activeConnection.session;\n const previousSidecars = this._activeConnection.sidecars;\n await this.destroyCurrentAgent();\n await this.stopSidecars(previousSidecars);\n\n if (this.sessionManager?.destroySession) {\n await this.sessionManager.destroySession(previousSession || undefined);\n }\n\n this.restoreBaseSessionState();\n }\n\n private async applyCreatedSession(\n session: PlaygroundCreatedSession,\n ): Promise<void> {\n if (!session.agent && !session.agentFactory) {\n throw new Error(\n 'Session creation must provide either an agent or agentFactory',\n );\n }\n\n const sessionSidecars = session.sidecars || this._baseSidecars;\n await this.startSidecars(sessionSidecars);\n\n try {\n this._activeConnection = {\n session: {\n connected: true,\n displayName: session.displayName,\n metadata: session.metadata ? { ...session.metadata } : {},\n },\n agent: session.agent || null,\n agentFactory: session.agentFactory || null,\n runtime: {\n platformId: session.platformId ?? this._baseRuntimeState?.platformId,\n title: session.title ?? this._baseRuntimeState?.title,\n description:\n session.platformDescription ?? this._baseRuntimeState?.description,\n preview: session.preview ?? this._baseRuntimeState?.preview,\n metadata: session.metadata ? { ...session.metadata } : {},\n },\n executionHooks: session.executionHooks || this._baseExecutionHooks,\n sidecars: sessionSidecars,\n };\n this.sessionSetupState = 'ready';\n this.sessionSetupBlockingReason = undefined;\n this.syncRuntimeState();\n } catch (error) {\n await this.stopSidecars(sessionSidecars).catch(() => {});\n this.restoreBaseSessionState();\n throw error;\n }\n }\n\n private async getSessionSetupSchema(\n input?: Record<string, unknown>,\n ): Promise<PlaygroundSessionSetup | null> {\n if (!this.sessionManager) {\n return null;\n }\n\n return this.sessionManager.getSetupSchema\n ? this.sessionManager.getSetupSchema(input)\n : null;\n }\n\n private async getSessionTargets(): Promise<PlaygroundSessionTarget[]> {\n if (!this.sessionManager?.listTargets) {\n return [];\n }\n\n return this.sessionManager.listTargets();\n }\n\n /**\n * Get the Express app instance for custom configuration\n *\n * IMPORTANT: Add middleware (like CORS) BEFORE calling launch()\n * The routes are initialized when launch() is called, so middleware\n * added after launch() will not affect the API routes.\n *\n * @example\n * ```typescript\n * import cors from 'cors';\n *\n * const server = new PlaygroundServer(agent);\n *\n * // Add CORS middleware before launch\n * server.app.use(cors({\n * origin: true,\n * credentials: true,\n * methods: ['GET', 'POST', 'PUT', 'DELETE', 'OPTIONS']\n * }));\n *\n * await server.launch();\n * ```\n */\n get app(): express.Application {\n return this._app;\n }\n\n /**\n * Initialize Express app with all routes and middleware\n * Called automatically by launch() if not already initialized\n */\n private initializeApp(): void {\n if (this._initialized) return;\n\n // Built-in middleware to parse JSON bodies\n this._app.use(express.json({ limit: '50mb' }));\n\n // Context update middleware (after JSON parsing)\n this._app.use(\n (req: Request, _res: Response, next: express.NextFunction) => {\n const { context } = req.body || {};\n if (\n this._activeConnection.agent &&\n context &&\n 'updateContext' in this._activeConnection.agent.interface &&\n typeof this._activeConnection.agent.interface.updateContext ===\n 'function'\n ) {\n this._activeConnection.agent.interface.updateContext(context);\n console.log('Context updated by PlaygroundServer middleware');\n }\n next();\n },\n );\n\n // NOTE: CORS middleware should be added externally via server.app.use()\n // before calling server.launch() if needed\n\n // API routes\n this.setupRoutes();\n\n // Static file serving (if staticPath is provided)\n this.setupStaticRoutes();\n\n // Error handler middleware (must be last)\n this._app.use(errorHandler);\n\n this._initialized = true;\n }\n\n filePathForUuid(uuid: string) {\n // Validate uuid to prevent path traversal attacks\n // Only allow alphanumeric characters and hyphens\n if (!/^[a-zA-Z0-9-]+$/.test(uuid)) {\n throw new Error('Invalid uuid format');\n }\n const filePath = join(this.tmpDir, `${uuid}.json`);\n // Double-check that resolved path is within tmpDir\n const resolvedPath = resolve(filePath);\n const resolvedTmpDir = resolve(this.tmpDir);\n if (!resolvedPath.startsWith(resolvedTmpDir)) {\n throw new Error('Invalid path');\n }\n return filePath;\n }\n\n saveContextFile(uuid: string, context: string) {\n const tmpFile = this.filePathForUuid(uuid);\n console.log(`save context file: ${tmpFile}`);\n writeFileSync(tmpFile, context);\n return tmpFile;\n }\n\n /**\n * Recreate agent instance (for cancellation)\n */\n private async recreateAgent(): Promise<void> {\n this._agentReady = false;\n console.log('Recreating agent to cancel current task...');\n\n await this.destroyCurrentAgent();\n\n // Create new agent instance if factory is available\n if (this._activeConnection.agentFactory) {\n try {\n this._activeConnection.agent =\n await this._activeConnection.agentFactory();\n this._agentReady = true;\n console.log('Agent recreated successfully');\n } catch (error) {\n this._agentReady = true;\n console.error('Failed to recreate agent:', error);\n throw error;\n }\n } else {\n this._agentReady = true;\n console.warn(\n 'Agent destroyed but cannot recreate: no factory function provided. Next /execute call will fail.',\n );\n }\n }\n\n /**\n * Setup all API routes\n */\n private setupRoutes(): void {\n this._app.get('/status', async (req: Request, res: Response) => {\n res.send({\n status: 'ok',\n id: this.id,\n });\n });\n\n this._app.get('/session', async (_req: Request, res: Response) => {\n res.json(this.getSessionInfo());\n });\n\n this._app.get('/session/setup', async (req: Request, res: Response) => {\n try {\n const setup = await this.getSessionSetupSchema(\n Object.fromEntries(\n Object.entries(req.query).filter(\n ([, value]) => typeof value === 'string',\n ),\n ),\n );\n if (!setup) {\n return res.status(404).json({\n error: 'Session setup is not available for this playground',\n });\n }\n\n const targets = await this.getSessionTargets();\n res.json({\n ...setup,\n targets: targets.length > 0 ? targets : setup.targets,\n });\n } catch (error) {\n res.status(500).json({\n error:\n error instanceof Error\n ? error.message\n : 'Failed to load session setup',\n });\n }\n });\n\n this._app.get('/session/targets', async (_req: Request, res: Response) => {\n try {\n res.json(await this.getSessionTargets());\n } catch (error) {\n res.status(500).json({\n error:\n error instanceof Error\n ? error.message\n : 'Failed to load session targets',\n });\n }\n });\n\n this._app.post('/session', async (req: Request, res: Response) => {\n if (!this.sessionManager) {\n return res.status(404).json({\n error: 'Session creation is not available for this playground',\n });\n }\n\n if (this.currentTaskId) {\n return res.status(409).json({\n error: 'Cannot replace session while a task is running',\n });\n }\n\n try {\n await this.destroyCurrentSession();\n const created = await this.sessionManager.createSession(req.body || {});\n await this.applyCreatedSession(created);\n\n if (\n !this._activeConnection.agent &&\n this._activeConnection.agentFactory\n ) {\n this._activeConnection.agent =\n await this._activeConnection.agentFactory();\n }\n\n if (this._configDirty && this._activeConnection.agentFactory) {\n this._configDirty = false;\n await this.recreateAgent();\n }\n\n res.json({\n session: this.getSessionInfo(),\n runtimeInfo: this.getRuntimeInfo(),\n });\n } catch (error) {\n const failedSessionSidecars = this._activeConnection.session\n ? this._activeConnection.sidecars\n : undefined;\n await this.destroyCurrentAgent();\n await this.stopSidecars(failedSessionSidecars).catch(() => {});\n this.restoreBaseSessionState();\n res.status(400).json({\n error:\n error instanceof Error ? error.message : 'Failed to create session',\n });\n }\n });\n\n this._app.delete('/session', async (_req: Request, res: Response) => {\n if (this.currentTaskId) {\n return res.status(409).json({\n error: 'Cannot destroy session while a task is running',\n });\n }\n\n try {\n await this.destroyCurrentSession();\n res.json({\n session: this.getSessionInfo(),\n runtimeInfo: this.getRuntimeInfo(),\n });\n } catch (error) {\n res.status(500).json({\n error:\n error instanceof Error\n ? error.message\n : 'Failed to destroy session',\n });\n }\n });\n\n this._app.get('/context/:uuid', async (req: Request, res: Response) => {\n const { uuid } = req.params;\n let contextFile: string;\n try {\n contextFile = this.filePathForUuid(uuid);\n } catch {\n return res.status(400).json({\n error: 'Invalid uuid format',\n });\n }\n\n if (!existsSync(contextFile)) {\n return res.status(404).json({\n error: 'Context not found',\n });\n }\n\n const context = readFileSync(contextFile, 'utf8');\n res.json({\n context,\n });\n });\n\n this._app.get(\n '/task-progress/:requestId',\n async (req: Request, res: Response) => {\n const { requestId } = req.params;\n const executionDump = this.taskExecutionDumps[requestId] || null;\n\n res.json({\n executionDump,\n });\n },\n );\n\n this._app.post('/action-space', async (req: Request, res: Response) => {\n try {\n const agent = this.getActiveAgentOrThrow();\n let actionSpace = [];\n\n actionSpace = agent.interface.actionSpace();\n\n // Process actionSpace to make paramSchema serializable with shape info\n const processedActionSpace = actionSpace.map((action: unknown) => {\n if (action && typeof action === 'object' && 'paramSchema' in action) {\n const typedAction = action as {\n paramSchema?: { shape?: object; [key: string]: unknown };\n [key: string]: unknown;\n };\n if (\n typedAction.paramSchema &&\n typeof typedAction.paramSchema === 'object'\n ) {\n // Extract shape information from Zod schema\n let processedSchema = null;\n\n try {\n // Extract shape from runtime Zod object\n if (\n typedAction.paramSchema.shape &&\n typeof typedAction.paramSchema.shape === 'object'\n ) {\n const rawShape = typedAction.paramSchema.shape as Record<\n string,\n any\n >;\n const serializedShape: Record<string, any> = {};\n for (const [key, field] of Object.entries(rawShape)) {\n serializedShape[key] = serializeZodField(field);\n }\n processedSchema = {\n type: 'ZodObject',\n shape: serializedShape,\n };\n }\n } catch (e) {\n const actionName =\n 'name' in typedAction && typeof typedAction.name === 'string'\n ? typedAction.name\n : 'unknown';\n console.warn(\n 'Failed to process paramSchema for action:',\n actionName,\n e,\n );\n }\n\n return {\n ...typedAction,\n paramSchema: processedSchema,\n };\n }\n }\n return action;\n });\n\n res.json(processedActionSpace);\n } catch (error: unknown) {\n const errorMessage =\n error instanceof Error ? error.message : 'Unknown error';\n console.error('Failed to get action space:', error);\n res.status(errorMessage === 'No active session' ? 409 : 500).json({\n error: errorMessage,\n });\n }\n });\n\n // -------------------------\n // actions from report file\n this._app.post(\n '/playground-with-context',\n async (req: Request, res: Response) => {\n const context = req.body.context;\n\n if (!context) {\n return res.status(400).json({\n error: 'context is required',\n });\n }\n\n const requestId = uuid();\n this.saveContextFile(requestId, context);\n return res.json({\n location: `/playground/${requestId}`,\n uuid: requestId,\n });\n },\n );\n\n this._app.post('/execute', async (req: Request, res: Response) => {\n let agent: PageAgent;\n try {\n agent = this.getActiveAgentOrThrow();\n } catch (error) {\n return res.status(409).json({\n error: error instanceof Error ? error.message : 'No active session',\n });\n }\n\n const {\n type,\n prompt,\n params,\n requestId,\n deepLocate,\n deepThink,\n screenshotIncluded,\n domIncluded,\n deviceOptions,\n } = req.body;\n\n if (!type) {\n return res.status(400).json({\n error: 'type is required',\n });\n }\n\n // Recreate agent only when AI config has changed (via /config API)\n if (this._activeConnection.agentFactory && this._configDirty) {\n this._configDirty = false;\n this._agentReady = false;\n console.log('AI config changed, recreating agent...');\n try {\n await this.destroyCurrentAgent();\n this._activeConnection.agent =\n await this._activeConnection.agentFactory();\n agent = this.getActiveAgentOrThrow();\n this._agentReady = true;\n console.log('Agent recreated with new config');\n } catch (error) {\n this._agentReady = true;\n console.error('Failed to recreate agent:', error);\n return res.status(500).json({\n error: `Failed to create agent: ${error instanceof Error ? error.message : 'Unknown error'}`,\n });\n }\n }\n\n // Update device options if provided\n if (deviceOptions) {\n const iface = agent.interface as unknown as {\n options?: Record<string, unknown>;\n };\n iface.options = {\n ...(iface.options || {}),\n ...deviceOptions,\n };\n }\n\n // Check if another task is running\n if (this.currentTaskId) {\n return res.status(409).json({\n error: 'Another task is already running',\n currentTaskId: this.currentTaskId,\n });\n }\n\n // Lock this task\n if (requestId) {\n this.currentTaskId = requestId;\n this.taskExecutionDumps[requestId] = null;\n\n // Use onDumpUpdate to receive and store executionDump directly\n agent.onDumpUpdate = (_dump: string, executionDump?: ExecutionDump) => {\n if (executionDump) {\n // Store the execution dump directly without transformation\n this.taskExecutionDumps[requestId] = executionDump;\n }\n };\n }\n\n const response: {\n result: unknown;\n dump: ExecutionDump | null;\n error: string | null;\n reportHTML: string | null;\n requestId?: string;\n } = {\n result: null,\n dump: null,\n error: null,\n reportHTML: null,\n requestId,\n };\n\n const startTime = Date.now();\n try {\n await this._activeConnection.executionHooks?.beforeExecute?.();\n\n // Get action space to check for dynamic actions\n const actionSpace = agent.interface.actionSpace();\n\n // Prepare value object for executeAction\n const value = {\n type,\n prompt,\n params,\n };\n\n response.result = await executeAction(agent, type, actionSpace, value, {\n deepLocate,\n deepThink,\n screenshotIncluded,\n domIncluded,\n deviceOptions,\n });\n } catch (error: unknown) {\n response.error = formatErrorMessage(error);\n } finally {\n try {\n await this._activeConnection.executionHooks?.afterExecute?.();\n } catch (hookError) {\n console.error('Failed to run execution after hook:', hookError);\n }\n }\n\n try {\n const dumpString = agent.dumpDataString({\n inlineScreenshots: true,\n });\n if (dumpString) {\n const groupedDump = ReportActionDump.fromSerializedString(dumpString);\n // Extract first execution from grouped dump, matching local execution adapter behavior\n response.dump = groupedDump.executions?.[0] || null;\n } else {\n response.dump = null;\n }\n response.reportHTML =\n agent.reportHTMLString({ inlineScreenshots: true }) || null;\n\n agent.writeOutActionDumps();\n agent.resetDump();\n } catch (error: unknown) {\n const errorMessage =\n error instanceof Error ? error.message : 'Unknown error';\n console.error(\n `write out dump failed: requestId: ${requestId}, ${errorMessage}`,\n );\n } finally {\n }\n\n res.send(response);\n const timeCost = Date.now() - startTime;\n\n if (response.error) {\n console.error(\n `handle request failed after ${timeCost}ms: requestId: ${requestId}, ${response.error}`,\n );\n } else {\n console.log(\n `handle request done after ${timeCost}ms: requestId: ${requestId}`,\n );\n }\n\n // Clean up task execution dumps and unlock after execution completes\n if (requestId) {\n delete this.taskExecutionDumps[requestId];\n // Release the lock\n if (this.currentTaskId === requestId) {\n this.currentTaskId = null;\n }\n }\n });\n\n this._app.post(\n '/cancel/:requestId',\n async (req: Request, res: Response) => {\n const { requestId } = req.params;\n\n if (!requestId) {\n return res.status(400).json({\n error: 'requestId is required',\n });\n }\n\n try {\n const agent = this.getActiveAgentOrThrow();\n // Check if this is the current running task\n if (this.currentTaskId !== requestId) {\n return res.json({\n status: 'not_found',\n message: 'Task not found or already completed',\n });\n }\n\n console.log(`Cancelling task: ${requestId}`);\n\n // Get current execution data before cancelling (dump and reportHTML)\n let dump: any = null;\n let reportHTML: string | null = null;\n\n try {\n const dumpString = agent.dumpDataString?.({\n inlineScreenshots: true,\n });\n if (dumpString) {\n const groupedDump =\n ReportActionDump.fromSerializedString(dumpString);\n // Extract first execution from grouped dump\n dump = groupedDump.executions?.[0] || null;\n }\n\n reportHTML =\n agent.reportHTMLString?.({\n inlineScreenshots: true,\n }) || null;\n } catch (error: unknown) {\n console.warn('Failed to get execution data before cancel:', error);\n }\n\n // Destroy and recreate agent to cancel the current task\n try {\n await this.recreateAgent();\n } catch (error) {\n console.warn('Failed to recreate agent during cancel:', error);\n }\n\n // Clean up\n delete this.taskExecutionDumps[requestId];\n this.currentTaskId = null;\n\n res.json({\n status: 'cancelled',\n message: 'Task cancelled successfully',\n dump,\n reportHTML,\n });\n } catch (error: unknown) {\n const errorMessage =\n error instanceof Error ? error.message : 'Unknown error';\n console.error(`Failed to cancel: ${errorMessage}`);\n res.status(errorMessage === 'No active session' ? 409 : 500).json({\n error: `Failed to cancel: ${errorMessage}`,\n });\n }\n },\n );\n\n // Screenshot API for real-time screenshot polling\n this._app.get('/screenshot', async (_req: Request, res: Response) => {\n try {\n const agent = this.getActiveAgentOrThrow();\n // Check if page has screenshotBase64 method\n if (typeof agent.interface.screenshotBase64 !== 'function') {\n return res.status(500).json({\n error: 'Screenshot method not available on current interface',\n });\n }\n\n const base64Screenshot = await agent.interface.screenshotBase64();\n\n res.json({\n screenshot: base64Screenshot,\n timestamp: Date.now(),\n });\n } catch (error: unknown) {\n const errorMessage =\n error instanceof Error ? error.message : 'Unknown error';\n console.error(`Failed to take screenshot: ${errorMessage}`);\n res.status(errorMessage === 'No active session' ? 409 : 500).json({\n error: `Failed to take screenshot: ${errorMessage}`,\n });\n }\n });\n\n // MJPEG streaming endpoint for real-time screen preview\n // Proxies native MJPEG stream (e.g. WDA MJPEG server) when available,\n // falls back to polling screenshotBase64() otherwise.\n this._app.get('/mjpeg', async (req: Request, res: Response) => {\n const agent = this._activeConnection.agent;\n if (!agent) {\n return res.status(409).json({\n error: 'No active session',\n });\n }\n\n const nativeUrl = agent.interface?.mjpegStreamUrl;\n\n if (nativeUrl && this._nativeMjpegAvailable !== false) {\n const proxyOk = await this.probeAndProxyNativeMjpeg(\n nativeUrl,\n req,\n res,\n );\n if (proxyOk) return;\n }\n\n if (typeof agent.interface?.screenshotBase64 !== 'function') {\n return res.status(500).json({\n error: 'Screenshot method not available on current interface',\n });\n }\n\n await this.startPollingMjpegStream(req, res);\n });\n\n // Interface info API for getting interface type and description\n this._app.get('/interface-info', async (_req: Request, res: Response) => {\n try {\n const runtimeInfo = this.getRuntimeInfo();\n\n res.json({\n type: runtimeInfo.interface.type,\n description: runtimeInfo.interface.description,\n });\n } catch (error: unknown) {\n const errorMessage =\n error instanceof Error ? error.message : 'Unknown error';\n console.error(`Failed to get interface info: ${errorMessage}`);\n res.status(500).json({\n error: `Failed to get interface info: ${errorMessage}`,\n });\n }\n });\n\n this._app.get('/runtime-info', async (_req: Request, res: Response) => {\n try {\n res.json(this.getRuntimeInfo());\n } catch (error: unknown) {\n const errorMessage =\n error instanceof Error ? error.message : 'Unknown error';\n console.error(`Failed to get runtime info: ${errorMessage}`);\n res.status(500).json({\n error: `Failed to get runtime info: ${errorMessage}`,\n });\n }\n });\n\n this.app.post('/config', async (req: Request, res: Response) => {\n const { aiConfig } = req.body;\n\n if (!aiConfig || typeof aiConfig !== 'object') {\n return res.status(400).json({\n error: 'aiConfig is required and must be an object',\n });\n }\n\n if (Object.keys(aiConfig).length === 0) {\n return res.json({\n status: 'ok',\n message: 'AI config not changed due to empty object',\n });\n }\n\n try {\n overrideAIConfig(aiConfig);\n this._configDirty = true;\n } catch (error: unknown) {\n const errorMessage =\n error instanceof Error ? error.message : 'Unknown error';\n console.error(`Failed to update AI config: ${errorMessage}`);\n return res.status(500).json({\n error: `Failed to update AI config: ${errorMessage}`,\n });\n }\n\n // Validate the config immediately so the frontend gets early feedback\n try {\n globalModelConfigManager.getModelConfig('default');\n } catch (error: unknown) {\n const errorMessage =\n error instanceof Error ? error.message : 'Unknown error';\n console.error(`AI config validation failed: ${errorMessage}`);\n return res.status(400).json({\n error: errorMessage,\n });\n }\n\n // Note: Agent will be recreated on next execution to apply new config\n return res.json({\n status: 'ok',\n message:\n 'AI config updated. Agent will be recreated on next execution.',\n });\n });\n\n this.app.post(\n '/connectivity-test',\n async (_req: Request, res: Response) => {\n try {\n const result = await runConnectivityTest({\n defaultModelConfig:\n globalModelConfigManager.getModelConfig('default'),\n planningModelConfig:\n globalModelConfigManager.getModelConfig('planning'),\n insightModelConfig:\n globalModelConfigManager.getModelConfig('insight'),\n });\n return res.json(result);\n } catch (error: unknown) {\n const errorMessage =\n error instanceof Error ? error.message : 'Unknown error';\n console.error(`Connectivity test failed: ${errorMessage}`);\n return res.status(500).json({\n error: errorMessage,\n });\n }\n },\n );\n }\n\n /**\n * Probe and proxy a native MJPEG stream (e.g. WDA MJPEG server).\n * Result is cached so we only probe once per server lifetime.\n */\n private probeAndProxyNativeMjpeg(\n nativeUrl: string,\n req: Request,\n res: Response,\n ): Promise<boolean> {\n return new Promise<boolean>((resolve) => {\n console.log(`MJPEG: trying native stream from ${nativeUrl}`);\n const proxyReq = http.get(nativeUrl, (proxyRes) => {\n this._nativeMjpegAvailable = true;\n console.log('MJPEG: streaming via native WDA MJPEG server');\n const contentType = proxyRes.headers['content-type'];\n if (contentType) {\n res.setHeader('Content-Type', contentType);\n }\n res.setHeader('Cache-Control', 'no-cache, no-store, must-revalidate');\n res.setHeader('Connection', 'keep-alive');\n proxyRes.pipe(res);\n req.on('close', () => proxyReq.destroy());\n resolve(true);\n });\n proxyReq.on('error', (err) => {\n this._nativeMjpegAvailable = false;\n console.warn(\n `MJPEG: native stream unavailable (${err.message}), using polling mode`,\n );\n resolve(false);\n });\n });\n }\n\n /**\n * Stream screenshots as MJPEG by polling screenshotBase64().\n */\n private async startPollingMjpegStream(\n req: Request,\n res: Response,\n ): Promise<void> {\n const defaultMjpegFps = 10;\n const maxMjpegFps = 30;\n const maxErrorBackoffMs = 3000;\n const errorLogThreshold = 3;\n\n const parsedFps = Number(req.query.fps);\n const fps = Math.min(\n Math.max(Number.isNaN(parsedFps) ? defaultMjpegFps : parsedFps, 1),\n maxMjpegFps,\n );\n const interval = Math.round(1000 / fps);\n const boundary = 'mjpeg-boundary';\n console.log(`MJPEG: streaming via polling mode (${fps}fps)`);\n\n res.setHeader(\n 'Content-Type',\n `multipart/x-mixed-replace; boundary=${boundary}`,\n );\n res.setHeader('Cache-Control', 'no-cache, no-store, must-revalidate');\n res.setHeader('Connection', 'keep-alive');\n\n let stopped = false;\n let consecutiveErrors = 0;\n req.on('close', () => {\n stopped = true;\n });\n\n while (!stopped) {\n // Skip frame while agent is being recreated\n if (!this._agentReady) {\n await new Promise((r) => setTimeout(r, 200));\n continue;\n }\n\n const frameStart = Date.now();\n try {\n const agent = this.getActiveAgentOrThrow();\n const base64 = await agent.interface.screenshotBase64();\n if (stopped) break;\n consecutiveErrors = 0;\n\n const raw = base64.replace(/^data:image\\/\\w+;base64,/, '');\n const buf = Buffer.from(raw, 'base64');\n\n res.write(`--${boundary}\\r\\n`);\n res.write('Content-Type: image/jpeg\\r\\n');\n res.write(`Content-Length: ${buf.length}\\r\\n\\r\\n`);\n res.write(buf);\n res.write('\\r\\n');\n } catch (err) {\n if (stopped) break;\n consecutiveErrors++;\n if (consecutiveErrors <= errorLogThreshold) {\n console.error('MJPEG frame error:', err);\n } else if (consecutiveErrors === errorLogThreshold + 1) {\n console.error(\n 'MJPEG: suppressing further errors, retrying silently...',\n );\n }\n const backoff = Math.min(1000 * consecutiveErrors, maxErrorBackoffMs);\n await new Promise((r) => setTimeout(r, backoff));\n continue;\n }\n\n const elapsed = Date.now() - frameStart;\n const remaining = interval - elapsed;\n if (remaining > 0) {\n await new Promise((r) => setTimeout(r, remaining));\n }\n }\n }\n\n /**\n * Setup static file serving routes\n */\n private setupStaticRoutes(): void {\n // Handle index.html with port injection\n this._app.get('/', (_req: Request, res: Response) => {\n this.serveHtmlWithPorts(res);\n });\n\n this._app.get('/index.html', (_req: Request, res: Response) => {\n this.serveHtmlWithPorts(res);\n });\n\n // Use express.static middleware for secure static file serving\n this._app.use(express.static(this.staticPath));\n\n // Fallback to index.html for SPA routing\n this._app.get('*', (_req: Request, res: Response) => {\n this.serveHtmlWithPorts(res);\n });\n }\n\n /**\n * Serve HTML with injected port configuration\n */\n private serveHtmlWithPorts(res: Response): void {\n try {\n const htmlPath = join(this.staticPath, 'index.html');\n let html = readFileSync(htmlPath, 'utf8');\n\n const scrcpyPort = this.scrcpyPort ?? this.port! + 1;\n\n // Inject scrcpy port configuration script into HTML head\n const configScript = `\n <script>\n window.SCRCPY_PORT = ${scrcpyPort};\n </script>\n `;\n\n // Insert the script before closing </head> tag\n html = html.replace('</head>', `${configScript}</head>`);\n\n res.setHeader('Content-Type', 'text/html');\n res.send(html);\n } catch (error) {\n console.error('Error serving HTML with ports:', error);\n res.status(500).send('Internal Server Error');\n }\n }\n\n /**\n * Launch the server on specified port\n */\n async launch(port?: number): Promise<PlaygroundServer> {\n // If using factory mode, initialize agent\n if (this._activeConnection.agentFactory && !this.sessionManager) {\n console.log('Initializing agent from factory function...');\n this._activeConnection.agent =\n await this._activeConnection.agentFactory();\n this._activeConnection.session = {\n connected: true,\n metadata: {},\n };\n this.sessionSetupState = 'ready';\n this.syncRuntimeState();\n console.log('Agent initialized successfully');\n }\n\n // Initialize routes now, after any middleware has been added\n this.initializeApp();\n\n this.port = port || defaultPort;\n\n return new Promise((resolve) => {\n const serverPort = this.port ?? defaultPort;\n this.server = this._app.listen(serverPort, '0.0.0.0', () => {\n resolve(this);\n });\n });\n }\n\n /**\n * Close the server and clean up resources\n */\n async close(): Promise<void> {\n await this.destroyCurrentSession().catch((error) => {\n console.warn('Failed to destroy current session during shutdown:', error);\n });\n\n return new Promise((resolve, reject) => {\n if (this.server) {\n this.taskExecutionDumps = {};\n\n // Close the server\n this.server.close((error) => {\n if (error) {\n reject(error);\n } else {\n this.server = undefined;\n resolve();\n }\n });\n } else {\n resolve();\n }\n });\n }\n}\n\nexport default PlaygroundServer;\nexport { PlaygroundServer };\n"],"names":["defaultPort","PLAYGROUND_SERVER_PORT","serializeZodField","field","def","typeName","result","Array","rawShape","serializedShape","k","v","Object","__filename","fileURLToPath","__dirname","dirname","STATIC_PATH","join","errorHandler","err","req","res","next","console","errorMessage","Error","PlaygroundServer","methodName","prepared","undefined","preview","metadata","buildRuntimeInfo","connected","Boolean","sessionConnected","sidecars","sidecar","error","previousSession","previousSidecars","session","sessionSidecars","input","express","_res","context","uuid","filePath","resolvedPath","resolve","resolvedTmpDir","tmpFile","writeFileSync","_req","setup","value","targets","created","failedSessionSidecars","contextFile","existsSync","readFileSync","requestId","executionDump","agent","actionSpace","processedActionSpace","action","typedAction","processedSchema","key","e","actionName","type","prompt","params","deepLocate","deepThink","screenshotIncluded","domIncluded","deviceOptions","iface","_dump","response","startTime","Date","executeAction","formatErrorMessage","hookError","dumpString","groupedDump","ReportActionDump","timeCost","dump","reportHTML","base64Screenshot","nativeUrl","proxyOk","runtimeInfo","aiConfig","overrideAIConfig","globalModelConfigManager","runConnectivityTest","Promise","proxyReq","http","proxyRes","contentType","defaultMjpegFps","maxMjpegFps","maxErrorBackoffMs","errorLogThreshold","parsedFps","Number","fps","Math","interval","boundary","stopped","consecutiveErrors","r","setTimeout","frameStart","base64","raw","buf","Buffer","backoff","elapsed","remaining","htmlPath","html","scrcpyPort","configScript","port","serverPort","reject","staticPath","id","getTmpDir"],"mappings":"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"}
1
+ {"version":3,"file":"server.mjs","sources":["../../src/server.ts"],"sourcesContent":["import { existsSync, readFileSync, writeFileSync } from 'node:fs';\nimport http from 'node:http';\nimport type { Server } from 'node:http';\nimport { dirname, join, resolve } from 'node:path';\nimport { fileURLToPath } from 'node:url';\nimport type { ExecutionDump } from '@midscene/core';\nimport { ReportActionDump, runConnectivityTest } from '@midscene/core';\nimport type { Agent as PageAgent } from '@midscene/core/agent';\nimport { getTmpDir } from '@midscene/core/utils';\nimport { PLAYGROUND_SERVER_PORT } from '@midscene/shared/constants';\nimport {\n globalModelConfigManager,\n overrideAIConfig,\n} from '@midscene/shared/env';\nimport { uuid } from '@midscene/shared/utils';\nimport express, { type Request, type Response } from 'express';\nimport { executeAction, formatErrorMessage } from './common';\nimport type {\n PlaygroundCreatedSession,\n PlaygroundExecutionHooks,\n PlaygroundPreviewDescriptor,\n PlaygroundSessionManager,\n PlaygroundSessionSetup,\n PlaygroundSessionState,\n PlaygroundSessionTarget,\n PlaygroundSidecar,\n PreparedPlaygroundPlatform,\n} from './platform';\nimport {\n type PlaygroundRuntimeInfo,\n buildRuntimeInfo,\n} from './runtime-metadata';\nimport type { AgentFactory } from './types';\n\nimport 'dotenv/config';\n\nconst defaultPort = PLAYGROUND_SERVER_PORT;\n\nfunction serializeAiConfigSignature(aiConfig: Record<string, unknown>): string {\n return JSON.stringify(\n Object.entries(aiConfig).sort(([leftKey], [rightKey]) =>\n leftKey.localeCompare(rightKey),\n ),\n );\n}\n\n/**\n * Recursively serialize a Zod field into a plain object that preserves\n * the `_def` metadata the client relies on (typeName, innerType, values,\n * defaultValue, description, shape, etc.).\n */\nexport function serializeZodField(field: any): any {\n if (!field || typeof field !== 'object') return field;\n\n const def = field._def;\n if (!def || typeof def !== 'object') return field;\n\n const typeName: string | undefined = def.typeName;\n\n const result: Record<string, any> = {\n _def: {\n typeName,\n },\n };\n\n // Preserve description\n if (def.description) {\n result._def.description = def.description;\n }\n\n // Wrapper types (ZodOptional, ZodDefault, ZodNullable) – recurse into innerType\n if (def.innerType) {\n result._def.innerType = serializeZodField(def.innerType);\n }\n\n // ZodDefault – preserve defaultValue as a serializable plain value\n if (typeName === 'ZodDefault' && typeof def.defaultValue === 'function') {\n try {\n result._def._serializedDefaultValue = def.defaultValue();\n } catch {\n // ignore\n }\n }\n\n // ZodEnum – preserve values array\n if (typeName === 'ZodEnum' && Array.isArray(def.values)) {\n result._def.values = def.values;\n }\n\n // ZodObject – recurse into shape\n if (typeName === 'ZodObject') {\n const rawShape = typeof def.shape === 'function' ? def.shape() : def.shape;\n if (rawShape && typeof rawShape === 'object') {\n const serializedShape: Record<string, any> = {};\n for (const [k, v] of Object.entries(rawShape)) {\n serializedShape[k] = serializeZodField(v);\n }\n result._def.shape = serializedShape;\n result.shape = serializedShape;\n }\n }\n\n // Copy top-level description for compatibility\n if (field.description) {\n result.description = field.description;\n }\n\n return result;\n}\n\n// Static path for playground files\nconst __filename = fileURLToPath(import.meta.url);\nconst __dirname = dirname(__filename);\nconst STATIC_PATH = join(__dirname, '..', '..', 'static');\n\nconst errorHandler = (\n err: unknown,\n req: Request,\n res: Response,\n next: express.NextFunction,\n) => {\n console.error(err);\n const errorMessage =\n err instanceof Error ? err.message : 'Internal server error';\n res.status(500).json({\n error: errorMessage,\n });\n};\n\ninterface PlaygroundRuntimeState {\n platformId?: string;\n title?: string;\n description?: string;\n preview?: PlaygroundPreviewDescriptor;\n metadata?: Record<string, unknown>;\n}\n\ninterface PlaygroundActiveConnection {\n session: PlaygroundSessionState | null;\n agent: PageAgent | null;\n agentFactory?: AgentFactory | null;\n runtime?: PlaygroundRuntimeState;\n executionHooks?: PlaygroundExecutionHooks;\n sidecars?: PlaygroundSidecar[];\n}\n\nclass PlaygroundServer {\n private _app: express.Application;\n tmpDir: string;\n server?: Server;\n port?: number | null;\n staticPath: string;\n taskExecutionDumps: Record<string, ExecutionDump | null>; // Store execution dumps directly\n id: string; // Unique identifier for this server instance\n\n /**\n * Port for scrcpy server (used by Android playground for screen mirroring)\n * When set, this port is injected into the HTML page as window.SCRCPY_PORT\n */\n scrcpyPort?: number;\n\n private _initialized = false;\n\n // Native MJPEG stream probe: null = not tested, true/false = result\n private _nativeMjpegAvailable: boolean | null = null;\n\n private sessionManager?: PlaygroundSessionManager;\n private sessionSetupState: 'required' | 'ready' | 'blocked' = 'ready';\n private sessionSetupBlockingReason?: string;\n\n // Track current running task\n private currentTaskId: string | null = null;\n\n // Flag to pause MJPEG polling during agent recreation or task execution\n private _agentReady = true;\n\n // Flag to track if AI config has changed and agent needs recreation\n private _configDirty = false;\n private _lastAiConfigSignature: string | null = null;\n private _baseRuntimeState?: PlaygroundRuntimeState;\n private _basePreparedMetadata?: Record<string, unknown>;\n private _baseExecutionHooks?: PlaygroundExecutionHooks;\n private _baseSidecars?: PlaygroundSidecar[];\n private _activeConnection: PlaygroundActiveConnection = {\n session: null,\n agent: null,\n agentFactory: null,\n runtime: undefined,\n executionHooks: undefined,\n sidecars: undefined,\n };\n\n constructor(\n agent?: PageAgent | (() => PageAgent) | (() => Promise<PageAgent>),\n staticPath = STATIC_PATH,\n id?: string, // Optional override ID\n ) {\n this._app = express();\n this.tmpDir = getTmpDir()!;\n this.staticPath = staticPath;\n this.taskExecutionDumps = {}; // Initialize as empty object\n // Use provided ID, or generate random UUID for each startup\n this.id = id || uuid();\n\n // Support both instance and factory function modes\n if (typeof agent === 'function') {\n this._activeConnection.agentFactory = agent;\n } else {\n this._activeConnection.agent = agent || null;\n }\n }\n\n get agent(): PageAgent | null {\n return this._activeConnection.agent;\n }\n\n private assertNoActiveSessionForBaseStateUpdate(methodName: string): void {\n if (this._activeConnection.session) {\n throw new Error(\n `${methodName} cannot update prepared state while a session is active`,\n );\n }\n }\n\n private buildBaseRuntimeState(): PlaygroundRuntimeState | undefined {\n if (!this._baseRuntimeState) {\n return undefined;\n }\n\n return {\n ...this._baseRuntimeState,\n metadata: this.buildSessionMetadata(),\n };\n }\n\n private resetConnectionToBaseState(): void {\n this._activeConnection = {\n session: null,\n agent: this._activeConnection.agent,\n agentFactory: this._activeConnection.agentFactory,\n runtime: this.buildBaseRuntimeState(),\n executionHooks: this._baseExecutionHooks,\n sidecars: this._baseSidecars,\n };\n }\n\n private syncRuntimeState(): void {\n this._baseRuntimeState = {\n ...(this._baseRuntimeState || {}),\n metadata: this.buildSessionMetadata(),\n };\n\n if (this._activeConnection.session) {\n this._activeConnection = {\n ...this._activeConnection,\n runtime: this._activeConnection.runtime\n ? {\n ...this._activeConnection.runtime,\n metadata: this.buildSessionMetadata(),\n }\n : this.buildBaseRuntimeState(),\n };\n return;\n }\n\n this.resetConnectionToBaseState();\n }\n\n private restoreBaseSessionState(): void {\n this.taskExecutionDumps = {};\n this.currentTaskId = null;\n this.sessionSetupState =\n this.sessionSetupState === 'blocked' ? 'blocked' : 'required';\n this._activeConnection = {\n session: null,\n agent: null,\n agentFactory: null,\n runtime: this.buildBaseRuntimeState(),\n executionHooks: this._baseExecutionHooks,\n sidecars: this._baseSidecars,\n };\n this.syncRuntimeState();\n }\n\n setPreparedPlatform(\n prepared: Pick<\n PreparedPlaygroundPlatform,\n | 'platformId'\n | 'title'\n | 'description'\n | 'preview'\n | 'metadata'\n | 'sessionManager'\n | 'executionHooks'\n | 'sidecars'\n >,\n ): void {\n // Allow overriding the initial session created by agentFactory in launch()\n if (this._activeConnection.session && this._activeConnection.agentFactory) {\n this._activeConnection.session = null;\n }\n this.assertNoActiveSessionForBaseStateUpdate('setPreparedPlatform');\n this.sessionManager = prepared.sessionManager;\n this._basePreparedMetadata = prepared.metadata\n ? { ...prepared.metadata }\n : undefined;\n this._baseRuntimeState = {\n platformId: prepared.platformId,\n title: prepared.title,\n description: prepared.description,\n preview: prepared.preview,\n metadata: this.buildSessionMetadata(),\n };\n this._baseExecutionHooks = prepared.executionHooks;\n this._baseSidecars = prepared.sidecars;\n this.resetConnectionToBaseState();\n\n if (\n this.sessionManager &&\n !this._activeConnection.agent &&\n !this._activeConnection.session\n ) {\n this.sessionSetupState =\n this._basePreparedMetadata?.setupState === 'blocked'\n ? 'blocked'\n : 'required';\n this.sessionSetupBlockingReason =\n typeof this._basePreparedMetadata?.setupBlockingReason === 'string'\n ? this._basePreparedMetadata.setupBlockingReason\n : undefined;\n }\n }\n\n setPreviewDescriptor(preview?: PlaygroundPreviewDescriptor): void {\n this.assertNoActiveSessionForBaseStateUpdate('setPreviewDescriptor');\n this._baseRuntimeState = {\n ...(this._baseRuntimeState || {}),\n preview,\n };\n this.resetConnectionToBaseState();\n }\n\n setRuntimeMetadata(metadata?: Record<string, unknown>): void {\n this.assertNoActiveSessionForBaseStateUpdate('setRuntimeMetadata');\n this._basePreparedMetadata = metadata ? { ...metadata } : undefined;\n this.syncRuntimeState();\n }\n\n getRuntimeInfo(): PlaygroundRuntimeInfo {\n return buildRuntimeInfo({\n platformId: this._activeConnection.runtime?.platformId,\n title: this._activeConnection.runtime?.title,\n platformDescription: this._activeConnection.runtime?.description,\n interfaceType:\n this._activeConnection.agent?.interface?.interfaceType || 'Unknown',\n interfaceDescription:\n this._activeConnection.agent?.interface?.describe?.() || undefined,\n preview: this._activeConnection.runtime?.preview,\n metadata: this.buildSessionMetadata(),\n supportsScreenshot:\n typeof this._activeConnection.agent?.interface?.screenshotBase64 ===\n 'function',\n mjpegStreamUrl: this._activeConnection.agent?.interface?.mjpegStreamUrl,\n scrcpyPort: this.scrcpyPort,\n });\n }\n\n getSessionInfo(): PlaygroundSessionState & {\n setupState: 'required' | 'ready' | 'blocked';\n setupBlockingReason?: string;\n } {\n const connected = this.sessionManager\n ? Boolean(\n this._activeConnection.session?.connected &&\n this._activeConnection.agent,\n )\n : Boolean(this._activeConnection.agent);\n\n return {\n connected,\n displayName: this._activeConnection.session?.displayName,\n metadata: {\n ...(this._activeConnection.session?.metadata || {}),\n },\n setupState: this.sessionSetupState,\n setupBlockingReason: this.sessionSetupBlockingReason,\n };\n }\n\n private buildSessionMetadata(): Record<string, unknown> {\n const sessionConnected = this.sessionManager\n ? Boolean(\n this._activeConnection.session?.connected &&\n this._activeConnection.agent,\n )\n : Boolean(this._activeConnection.agent);\n\n return {\n ...(this._basePreparedMetadata || {}),\n ...(this._activeConnection.session?.metadata || {}),\n sessionConnected,\n sessionDisplayName: this._activeConnection.session?.displayName,\n setupState: this.sessionSetupState,\n ...(this.sessionSetupBlockingReason\n ? { setupBlockingReason: this.sessionSetupBlockingReason }\n : {}),\n };\n }\n\n private async startSidecars(sidecars?: PlaygroundSidecar[]): Promise<void> {\n for (const sidecar of sidecars || []) {\n await sidecar.start();\n }\n }\n\n private async stopSidecars(sidecars?: PlaygroundSidecar[]): Promise<void> {\n for (const sidecar of sidecars || []) {\n await sidecar.stop?.();\n }\n }\n\n private getActiveAgentOrThrow(): PageAgent {\n if (!this._activeConnection.agent) {\n throw new Error('No active session');\n }\n\n return this._activeConnection.agent;\n }\n\n private async destroyCurrentAgent(): Promise<void> {\n if (!this._activeConnection.agent) {\n return;\n }\n\n try {\n if (typeof this._activeConnection.agent.destroy === 'function') {\n await this._activeConnection.agent.destroy();\n }\n } catch (error) {\n console.warn('Failed to destroy old agent:', error);\n } finally {\n this._activeConnection.agent = null;\n // Once the stale agent is gone there is nothing left to recreate.\n this._configDirty = false;\n }\n }\n\n private async destroyCurrentSession(): Promise<void> {\n const previousSession = this._activeConnection.session;\n const previousSidecars = this._activeConnection.sidecars;\n await this.destroyCurrentAgent();\n await this.stopSidecars(previousSidecars);\n\n if (this.sessionManager?.destroySession) {\n await this.sessionManager.destroySession(previousSession || undefined);\n }\n\n this.restoreBaseSessionState();\n }\n\n private async applyCreatedSession(\n session: PlaygroundCreatedSession,\n ): Promise<void> {\n if (!session.agent && !session.agentFactory) {\n throw new Error(\n 'Session creation must provide either an agent or agentFactory',\n );\n }\n\n const sessionSidecars = session.sidecars || this._baseSidecars;\n await this.startSidecars(sessionSidecars);\n\n try {\n this._activeConnection = {\n session: {\n connected: true,\n displayName: session.displayName,\n metadata: session.metadata ? { ...session.metadata } : {},\n },\n agent: session.agent || null,\n agentFactory: session.agentFactory || null,\n runtime: {\n platformId: session.platformId ?? this._baseRuntimeState?.platformId,\n title: session.title ?? this._baseRuntimeState?.title,\n description:\n session.platformDescription ?? this._baseRuntimeState?.description,\n preview: session.preview ?? this._baseRuntimeState?.preview,\n metadata: session.metadata ? { ...session.metadata } : {},\n },\n executionHooks: session.executionHooks || this._baseExecutionHooks,\n sidecars: sessionSidecars,\n };\n this.sessionSetupState = 'ready';\n this.sessionSetupBlockingReason = undefined;\n this.syncRuntimeState();\n } catch (error) {\n await this.stopSidecars(sessionSidecars).catch(() => {});\n this.restoreBaseSessionState();\n throw error;\n }\n }\n\n private async getSessionSetupSchema(\n input?: Record<string, unknown>,\n ): Promise<PlaygroundSessionSetup | null> {\n if (!this.sessionManager) {\n return null;\n }\n\n return this.sessionManager.getSetupSchema\n ? this.sessionManager.getSetupSchema(input)\n : null;\n }\n\n private async getSessionTargets(): Promise<PlaygroundSessionTarget[]> {\n if (!this.sessionManager?.listTargets) {\n return [];\n }\n\n return this.sessionManager.listTargets();\n }\n\n /**\n * Get the Express app instance for custom configuration\n *\n * IMPORTANT: Add middleware (like CORS) BEFORE calling launch()\n * The routes are initialized when launch() is called, so middleware\n * added after launch() will not affect the API routes.\n *\n * @example\n * ```typescript\n * import cors from 'cors';\n *\n * const server = new PlaygroundServer(agent);\n *\n * // Add CORS middleware before launch\n * server.app.use(cors({\n * origin: true,\n * credentials: true,\n * methods: ['GET', 'POST', 'PUT', 'DELETE', 'OPTIONS']\n * }));\n *\n * await server.launch();\n * ```\n */\n get app(): express.Application {\n return this._app;\n }\n\n /**\n * Initialize Express app with all routes and middleware\n * Called automatically by launch() if not already initialized\n */\n private initializeApp(): void {\n if (this._initialized) return;\n\n // Built-in middleware to parse JSON bodies\n this._app.use(express.json({ limit: '50mb' }));\n\n // Context update middleware (after JSON parsing)\n this._app.use(\n (req: Request, _res: Response, next: express.NextFunction) => {\n const { context } = req.body || {};\n if (\n this._activeConnection.agent &&\n context &&\n 'updateContext' in this._activeConnection.agent.interface &&\n typeof this._activeConnection.agent.interface.updateContext ===\n 'function'\n ) {\n this._activeConnection.agent.interface.updateContext(context);\n console.log('Context updated by PlaygroundServer middleware');\n }\n next();\n },\n );\n\n // NOTE: CORS middleware should be added externally via server.app.use()\n // before calling server.launch() if needed\n\n // API routes\n this.setupRoutes();\n\n // Static file serving (if staticPath is provided)\n this.setupStaticRoutes();\n\n // Error handler middleware (must be last)\n this._app.use(errorHandler);\n\n this._initialized = true;\n }\n\n filePathForUuid(uuid: string) {\n // Validate uuid to prevent path traversal attacks\n // Only allow alphanumeric characters and hyphens\n if (!/^[a-zA-Z0-9-]+$/.test(uuid)) {\n throw new Error('Invalid uuid format');\n }\n const filePath = join(this.tmpDir, `${uuid}.json`);\n // Double-check that resolved path is within tmpDir\n const resolvedPath = resolve(filePath);\n const resolvedTmpDir = resolve(this.tmpDir);\n if (!resolvedPath.startsWith(resolvedTmpDir)) {\n throw new Error('Invalid path');\n }\n return filePath;\n }\n\n saveContextFile(uuid: string, context: string) {\n const tmpFile = this.filePathForUuid(uuid);\n console.log(`save context file: ${tmpFile}`);\n writeFileSync(tmpFile, context);\n return tmpFile;\n }\n\n /**\n * Recreate agent instance (for cancellation)\n */\n private async recreateAgent(): Promise<void> {\n this._agentReady = false;\n console.log('Recreating agent to cancel current task...');\n\n await this.destroyCurrentAgent();\n\n // Create new agent instance if factory is available\n if (this._activeConnection.agentFactory) {\n try {\n this._activeConnection.agent =\n await this._activeConnection.agentFactory();\n this._agentReady = true;\n console.log('Agent recreated successfully');\n } catch (error) {\n this._agentReady = true;\n console.error('Failed to recreate agent:', error);\n throw error;\n }\n } else {\n this._agentReady = true;\n console.warn(\n 'Agent destroyed but cannot recreate: no factory function provided. Next /execute call will fail.',\n );\n }\n }\n\n /**\n * Setup all API routes\n */\n private setupRoutes(): void {\n this._app.get('/status', async (req: Request, res: Response) => {\n res.send({\n status: 'ok',\n id: this.id,\n });\n });\n\n this._app.get('/session', async (_req: Request, res: Response) => {\n res.json(this.getSessionInfo());\n });\n\n this._app.get('/session/setup', async (req: Request, res: Response) => {\n try {\n const setup = await this.getSessionSetupSchema(\n Object.fromEntries(\n Object.entries(req.query).filter(\n ([, value]) => typeof value === 'string',\n ),\n ),\n );\n if (!setup) {\n return res.status(404).json({\n error: 'Session setup is not available for this playground',\n });\n }\n\n const targets = await this.getSessionTargets();\n res.json({\n ...setup,\n targets: targets.length > 0 ? targets : setup.targets,\n });\n } catch (error) {\n res.status(500).json({\n error:\n error instanceof Error\n ? error.message\n : 'Failed to load session setup',\n });\n }\n });\n\n this._app.get('/session/targets', async (_req: Request, res: Response) => {\n try {\n res.json(await this.getSessionTargets());\n } catch (error) {\n res.status(500).json({\n error:\n error instanceof Error\n ? error.message\n : 'Failed to load session targets',\n });\n }\n });\n\n this._app.post('/session', async (req: Request, res: Response) => {\n if (!this.sessionManager) {\n return res.status(404).json({\n error: 'Session creation is not available for this playground',\n });\n }\n\n if (this.currentTaskId) {\n return res.status(409).json({\n error: 'Cannot replace session while a task is running',\n });\n }\n\n try {\n await this.destroyCurrentSession();\n const created = await this.sessionManager.createSession(req.body || {});\n await this.applyCreatedSession(created);\n\n if (\n !this._activeConnection.agent &&\n this._activeConnection.agentFactory\n ) {\n this._activeConnection.agent =\n await this._activeConnection.agentFactory();\n }\n\n if (this._configDirty && this._activeConnection.agentFactory) {\n this._configDirty = false;\n await this.recreateAgent();\n }\n\n res.json({\n session: this.getSessionInfo(),\n runtimeInfo: this.getRuntimeInfo(),\n });\n } catch (error) {\n const failedSessionSidecars = this._activeConnection.session\n ? this._activeConnection.sidecars\n : undefined;\n await this.destroyCurrentAgent();\n await this.stopSidecars(failedSessionSidecars).catch(() => {});\n this.restoreBaseSessionState();\n res.status(400).json({\n error:\n error instanceof Error ? error.message : 'Failed to create session',\n });\n }\n });\n\n this._app.delete('/session', async (_req: Request, res: Response) => {\n if (this.currentTaskId) {\n return res.status(409).json({\n error: 'Cannot destroy session while a task is running',\n });\n }\n\n try {\n await this.destroyCurrentSession();\n res.json({\n session: this.getSessionInfo(),\n runtimeInfo: this.getRuntimeInfo(),\n });\n } catch (error) {\n res.status(500).json({\n error:\n error instanceof Error\n ? error.message\n : 'Failed to destroy session',\n });\n }\n });\n\n this._app.get('/context/:uuid', async (req: Request, res: Response) => {\n const { uuid } = req.params;\n let contextFile: string;\n try {\n contextFile = this.filePathForUuid(uuid);\n } catch {\n return res.status(400).json({\n error: 'Invalid uuid format',\n });\n }\n\n if (!existsSync(contextFile)) {\n return res.status(404).json({\n error: 'Context not found',\n });\n }\n\n const context = readFileSync(contextFile, 'utf8');\n res.json({\n context,\n });\n });\n\n this._app.get(\n '/task-progress/:requestId',\n async (req: Request, res: Response) => {\n const { requestId } = req.params;\n const executionDump = this.taskExecutionDumps[requestId] || null;\n\n res.json({\n executionDump,\n });\n },\n );\n\n this._app.post('/action-space', async (req: Request, res: Response) => {\n try {\n const agent = this.getActiveAgentOrThrow();\n let actionSpace = [];\n\n actionSpace = agent.interface.actionSpace();\n\n // Process actionSpace to make paramSchema serializable with shape info\n const processedActionSpace = actionSpace.map((action: unknown) => {\n if (action && typeof action === 'object' && 'paramSchema' in action) {\n const typedAction = action as {\n paramSchema?: { shape?: object; [key: string]: unknown };\n [key: string]: unknown;\n };\n if (\n typedAction.paramSchema &&\n typeof typedAction.paramSchema === 'object'\n ) {\n // Extract shape information from Zod schema\n let processedSchema = null;\n\n try {\n // Extract shape from runtime Zod object\n if (\n typedAction.paramSchema.shape &&\n typeof typedAction.paramSchema.shape === 'object'\n ) {\n const rawShape = typedAction.paramSchema.shape as Record<\n string,\n any\n >;\n const serializedShape: Record<string, any> = {};\n for (const [key, field] of Object.entries(rawShape)) {\n serializedShape[key] = serializeZodField(field);\n }\n processedSchema = {\n type: 'ZodObject',\n shape: serializedShape,\n };\n }\n } catch (e) {\n const actionName =\n 'name' in typedAction && typeof typedAction.name === 'string'\n ? typedAction.name\n : 'unknown';\n console.warn(\n 'Failed to process paramSchema for action:',\n actionName,\n e,\n );\n }\n\n return {\n ...typedAction,\n paramSchema: processedSchema,\n };\n }\n }\n return action;\n });\n\n res.json(processedActionSpace);\n } catch (error: unknown) {\n const errorMessage =\n error instanceof Error ? error.message : 'Unknown error';\n console.error('Failed to get action space:', error);\n res.status(errorMessage === 'No active session' ? 409 : 500).json({\n error: errorMessage,\n });\n }\n });\n\n // -------------------------\n // actions from report file\n this._app.post(\n '/playground-with-context',\n async (req: Request, res: Response) => {\n const context = req.body.context;\n\n if (!context) {\n return res.status(400).json({\n error: 'context is required',\n });\n }\n\n const requestId = uuid();\n this.saveContextFile(requestId, context);\n return res.json({\n location: `/playground/${requestId}`,\n uuid: requestId,\n });\n },\n );\n\n this._app.post('/execute', async (req: Request, res: Response) => {\n let agent: PageAgent;\n try {\n agent = this.getActiveAgentOrThrow();\n } catch (error) {\n return res.status(409).json({\n error: error instanceof Error ? error.message : 'No active session',\n });\n }\n\n const {\n type,\n prompt,\n params,\n requestId,\n deepLocate,\n deepThink,\n screenshotIncluded,\n domIncluded,\n deviceOptions,\n } = req.body;\n\n if (!type) {\n return res.status(400).json({\n error: 'type is required',\n });\n }\n\n // Recreate agent only when AI config has changed (via /config API)\n if (this._activeConnection.agentFactory && this._configDirty) {\n this._configDirty = false;\n this._agentReady = false;\n console.log('AI config changed, recreating agent...');\n try {\n await this.destroyCurrentAgent();\n this._activeConnection.agent =\n await this._activeConnection.agentFactory();\n agent = this.getActiveAgentOrThrow();\n this._agentReady = true;\n console.log('Agent recreated with new config');\n } catch (error) {\n this._agentReady = true;\n console.error('Failed to recreate agent:', error);\n return res.status(500).json({\n error: `Failed to create agent: ${error instanceof Error ? error.message : 'Unknown error'}`,\n });\n }\n }\n\n // Update device options if provided\n if (deviceOptions) {\n const iface = agent.interface as unknown as {\n options?: Record<string, unknown>;\n };\n iface.options = {\n ...(iface.options || {}),\n ...deviceOptions,\n };\n }\n\n // Check if another task is running\n if (this.currentTaskId) {\n return res.status(409).json({\n error: 'Another task is already running',\n currentTaskId: this.currentTaskId,\n });\n }\n\n // Lock this task\n if (requestId) {\n this.currentTaskId = requestId;\n this.taskExecutionDumps[requestId] = null;\n\n // Use onDumpUpdate to receive and store executionDump directly\n agent.onDumpUpdate = (_dump: string, executionDump?: ExecutionDump) => {\n if (executionDump) {\n // Store the execution dump directly without transformation\n this.taskExecutionDumps[requestId] = executionDump;\n }\n };\n }\n\n const response: {\n result: unknown;\n dump: ExecutionDump | null;\n error: string | null;\n reportHTML: string | null;\n requestId?: string;\n } = {\n result: null,\n dump: null,\n error: null,\n reportHTML: null,\n requestId,\n };\n\n const startTime = Date.now();\n try {\n await this._activeConnection.executionHooks?.beforeExecute?.();\n\n // Get action space to check for dynamic actions\n const actionSpace = agent.interface.actionSpace();\n\n // Prepare value object for executeAction\n const value = {\n type,\n prompt,\n params,\n };\n\n response.result = await executeAction(agent, type, actionSpace, value, {\n deepLocate,\n deepThink,\n screenshotIncluded,\n domIncluded,\n deviceOptions,\n });\n } catch (error: unknown) {\n response.error = formatErrorMessage(error);\n } finally {\n try {\n await this._activeConnection.executionHooks?.afterExecute?.();\n } catch (hookError) {\n console.error('Failed to run execution after hook:', hookError);\n }\n }\n\n try {\n const dumpString = agent.dumpDataString({\n inlineScreenshots: true,\n });\n if (dumpString) {\n const groupedDump = ReportActionDump.fromSerializedString(dumpString);\n // Extract first execution from grouped dump, matching local execution adapter behavior\n response.dump = groupedDump.executions?.[0] || null;\n } else {\n response.dump = null;\n }\n response.reportHTML =\n agent.reportHTMLString({ inlineScreenshots: true }) || null;\n\n agent.writeOutActionDumps();\n agent.resetDump();\n } catch (error: unknown) {\n const errorMessage =\n error instanceof Error ? error.message : 'Unknown error';\n console.error(\n `write out dump failed: requestId: ${requestId}, ${errorMessage}`,\n );\n } finally {\n }\n\n res.send(response);\n const timeCost = Date.now() - startTime;\n\n if (response.error) {\n console.error(\n `handle request failed after ${timeCost}ms: requestId: ${requestId}, ${response.error}`,\n );\n } else {\n console.log(\n `handle request done after ${timeCost}ms: requestId: ${requestId}`,\n );\n }\n\n // Clean up task execution dumps and unlock after execution completes\n if (requestId) {\n delete this.taskExecutionDumps[requestId];\n // Release the lock\n if (this.currentTaskId === requestId) {\n this.currentTaskId = null;\n }\n }\n });\n\n this._app.post(\n '/cancel/:requestId',\n async (req: Request, res: Response) => {\n const { requestId } = req.params;\n\n if (!requestId) {\n return res.status(400).json({\n error: 'requestId is required',\n });\n }\n\n try {\n const agent = this.getActiveAgentOrThrow();\n // Check if this is the current running task\n if (this.currentTaskId !== requestId) {\n return res.json({\n status: 'not_found',\n message: 'Task not found or already completed',\n });\n }\n\n console.log(`Cancelling task: ${requestId}`);\n\n // Get current execution data before cancelling (dump and reportHTML)\n let dump: any = null;\n let reportHTML: string | null = null;\n\n try {\n const dumpString = agent.dumpDataString?.({\n inlineScreenshots: true,\n });\n if (dumpString) {\n const groupedDump =\n ReportActionDump.fromSerializedString(dumpString);\n // Extract first execution from grouped dump\n dump = groupedDump.executions?.[0] || null;\n }\n\n reportHTML =\n agent.reportHTMLString?.({\n inlineScreenshots: true,\n }) || null;\n } catch (error: unknown) {\n console.warn('Failed to get execution data before cancel:', error);\n }\n\n // Destroy and recreate agent to cancel the current task\n try {\n await this.recreateAgent();\n } catch (error) {\n console.warn('Failed to recreate agent during cancel:', error);\n }\n\n // Clean up\n delete this.taskExecutionDumps[requestId];\n this.currentTaskId = null;\n\n res.json({\n status: 'cancelled',\n message: 'Task cancelled successfully',\n dump,\n reportHTML,\n });\n } catch (error: unknown) {\n const errorMessage =\n error instanceof Error ? error.message : 'Unknown error';\n console.error(`Failed to cancel: ${errorMessage}`);\n res.status(errorMessage === 'No active session' ? 409 : 500).json({\n error: `Failed to cancel: ${errorMessage}`,\n });\n }\n },\n );\n\n // Screenshot API for real-time screenshot polling\n this._app.get('/screenshot', async (_req: Request, res: Response) => {\n try {\n const agent = this.getActiveAgentOrThrow();\n // Check if page has screenshotBase64 method\n if (typeof agent.interface.screenshotBase64 !== 'function') {\n return res.status(500).json({\n error: 'Screenshot method not available on current interface',\n });\n }\n\n const base64Screenshot = await agent.interface.screenshotBase64();\n\n res.json({\n screenshot: base64Screenshot,\n timestamp: Date.now(),\n });\n } catch (error: unknown) {\n const errorMessage =\n error instanceof Error ? error.message : 'Unknown error';\n const statusCode = errorMessage === 'No active session' ? 409 : 500;\n if (statusCode !== 409) {\n console.error(`Failed to take screenshot: ${errorMessage}`);\n }\n res.status(statusCode).json({\n error: `Failed to take screenshot: ${errorMessage}`,\n });\n }\n });\n\n // MJPEG streaming endpoint for real-time screen preview\n // Proxies native MJPEG stream (e.g. WDA MJPEG server) when available,\n // falls back to polling screenshotBase64() otherwise.\n this._app.get('/mjpeg', async (req: Request, res: Response) => {\n const agent = this._activeConnection.agent;\n if (!agent) {\n return res.status(409).json({\n error: 'No active session',\n });\n }\n\n const nativeUrl = agent.interface?.mjpegStreamUrl;\n\n if (nativeUrl && this._nativeMjpegAvailable !== false) {\n const proxyOk = await this.probeAndProxyNativeMjpeg(\n nativeUrl,\n req,\n res,\n );\n if (proxyOk) return;\n }\n\n if (typeof agent.interface?.screenshotBase64 !== 'function') {\n return res.status(500).json({\n error: 'Screenshot method not available on current interface',\n });\n }\n\n await this.startPollingMjpegStream(req, res);\n });\n\n // Interface info API for getting interface type and description\n this._app.get('/interface-info', async (_req: Request, res: Response) => {\n try {\n const runtimeInfo = this.getRuntimeInfo();\n\n res.json({\n type: runtimeInfo.interface.type,\n description: runtimeInfo.interface.description,\n });\n } catch (error: unknown) {\n const errorMessage =\n error instanceof Error ? error.message : 'Unknown error';\n console.error(`Failed to get interface info: ${errorMessage}`);\n res.status(500).json({\n error: `Failed to get interface info: ${errorMessage}`,\n });\n }\n });\n\n this._app.get('/runtime-info', async (_req: Request, res: Response) => {\n try {\n res.json(this.getRuntimeInfo());\n } catch (error: unknown) {\n const errorMessage =\n error instanceof Error ? error.message : 'Unknown error';\n console.error(`Failed to get runtime info: ${errorMessage}`);\n res.status(500).json({\n error: `Failed to get runtime info: ${errorMessage}`,\n });\n }\n });\n\n this.app.post('/config', async (req: Request, res: Response) => {\n const { aiConfig } = req.body;\n\n if (!aiConfig || typeof aiConfig !== 'object') {\n return res.status(400).json({\n error: 'aiConfig is required and must be an object',\n });\n }\n\n if (Object.keys(aiConfig).length === 0) {\n return res.json({\n status: 'ok',\n message: 'AI config not changed due to empty object',\n });\n }\n\n const nextConfigSignature = serializeAiConfigSignature(aiConfig);\n const configChanged = nextConfigSignature !== this._lastAiConfigSignature;\n\n try {\n if (configChanged) {\n overrideAIConfig(aiConfig);\n this._lastAiConfigSignature = nextConfigSignature;\n this._configDirty = Boolean(this._activeConnection.agent);\n }\n } catch (error: unknown) {\n const errorMessage =\n error instanceof Error ? error.message : 'Unknown error';\n console.error(`Failed to update AI config: ${errorMessage}`);\n return res.status(500).json({\n error: `Failed to update AI config: ${errorMessage}`,\n });\n }\n\n if (!configChanged) {\n return res.json({\n status: 'ok',\n message: 'AI config not changed because it is identical to current',\n });\n }\n\n // Validate the config immediately so the frontend gets early feedback\n try {\n globalModelConfigManager.getModelConfig('default');\n } catch (error: unknown) {\n const errorMessage =\n error instanceof Error ? error.message : 'Unknown error';\n console.error(`AI config validation failed: ${errorMessage}`);\n return res.status(400).json({\n error: errorMessage,\n });\n }\n\n return res.json({\n status: 'ok',\n message: this._configDirty\n ? 'AI config updated. Agent will be recreated on next execution.'\n : 'AI config updated. New sessions will use it immediately.',\n });\n });\n\n this.app.post(\n '/connectivity-test',\n async (_req: Request, res: Response) => {\n try {\n const result = await runConnectivityTest({\n defaultModelConfig:\n globalModelConfigManager.getModelConfig('default'),\n planningModelConfig:\n globalModelConfigManager.getModelConfig('planning'),\n insightModelConfig:\n globalModelConfigManager.getModelConfig('insight'),\n });\n return res.json(result);\n } catch (error: unknown) {\n const errorMessage =\n error instanceof Error ? error.message : 'Unknown error';\n console.error(`Connectivity test failed: ${errorMessage}`);\n return res.status(500).json({\n error: errorMessage,\n });\n }\n },\n );\n }\n\n /**\n * Probe and proxy a native MJPEG stream (e.g. WDA MJPEG server).\n * Result is cached so we only probe once per server lifetime.\n */\n private probeAndProxyNativeMjpeg(\n nativeUrl: string,\n req: Request,\n res: Response,\n ): Promise<boolean> {\n return new Promise<boolean>((resolve) => {\n console.log(`MJPEG: trying native stream from ${nativeUrl}`);\n const proxyReq = http.get(nativeUrl, (proxyRes) => {\n this._nativeMjpegAvailable = true;\n console.log('MJPEG: streaming via native WDA MJPEG server');\n const contentType = proxyRes.headers['content-type'];\n if (contentType) {\n res.setHeader('Content-Type', contentType);\n }\n res.setHeader('Cache-Control', 'no-cache, no-store, must-revalidate');\n res.setHeader('Connection', 'keep-alive');\n proxyRes.pipe(res);\n req.on('close', () => proxyReq.destroy());\n resolve(true);\n });\n proxyReq.on('error', (err) => {\n this._nativeMjpegAvailable = false;\n console.warn(\n `MJPEG: native stream unavailable (${err.message}), using polling mode`,\n );\n resolve(false);\n });\n });\n }\n\n /**\n * Stream screenshots as MJPEG by polling screenshotBase64().\n */\n private async startPollingMjpegStream(\n req: Request,\n res: Response,\n ): Promise<void> {\n const defaultMjpegFps = 10;\n const maxMjpegFps = 30;\n const maxErrorBackoffMs = 3000;\n const errorLogThreshold = 3;\n\n const parsedFps = Number(req.query.fps);\n const fps = Math.min(\n Math.max(Number.isNaN(parsedFps) ? defaultMjpegFps : parsedFps, 1),\n maxMjpegFps,\n );\n const interval = Math.round(1000 / fps);\n const boundary = 'mjpeg-boundary';\n console.log(`MJPEG: streaming via polling mode (${fps}fps)`);\n\n res.setHeader(\n 'Content-Type',\n `multipart/x-mixed-replace; boundary=${boundary}`,\n );\n res.setHeader('Cache-Control', 'no-cache, no-store, must-revalidate');\n res.setHeader('Connection', 'keep-alive');\n\n let stopped = false;\n let consecutiveErrors = 0;\n req.on('close', () => {\n stopped = true;\n });\n\n while (!stopped) {\n // Skip frame while agent is being recreated\n if (!this._agentReady) {\n await new Promise((r) => setTimeout(r, 200));\n continue;\n }\n\n const frameStart = Date.now();\n try {\n const agent = this.getActiveAgentOrThrow();\n const base64 = await agent.interface.screenshotBase64();\n if (stopped) break;\n consecutiveErrors = 0;\n\n const raw = base64.replace(/^data:image\\/\\w+;base64,/, '');\n const buf = Buffer.from(raw, 'base64');\n\n res.write(`--${boundary}\\r\\n`);\n res.write('Content-Type: image/jpeg\\r\\n');\n res.write(`Content-Length: ${buf.length}\\r\\n\\r\\n`);\n res.write(buf);\n res.write('\\r\\n');\n } catch (err) {\n if (stopped) break;\n consecutiveErrors++;\n if (consecutiveErrors <= errorLogThreshold) {\n console.error('MJPEG frame error:', err);\n } else if (consecutiveErrors === errorLogThreshold + 1) {\n console.error(\n 'MJPEG: suppressing further errors, retrying silently...',\n );\n }\n const backoff = Math.min(1000 * consecutiveErrors, maxErrorBackoffMs);\n await new Promise((r) => setTimeout(r, backoff));\n continue;\n }\n\n const elapsed = Date.now() - frameStart;\n const remaining = interval - elapsed;\n if (remaining > 0) {\n await new Promise((r) => setTimeout(r, remaining));\n }\n }\n }\n\n /**\n * Setup static file serving routes\n */\n private setupStaticRoutes(): void {\n // Handle index.html with port injection\n this._app.get('/', (_req: Request, res: Response) => {\n this.serveHtmlWithPorts(res);\n });\n\n this._app.get('/index.html', (_req: Request, res: Response) => {\n this.serveHtmlWithPorts(res);\n });\n\n // Use express.static middleware for secure static file serving\n this._app.use(express.static(this.staticPath));\n\n // Fallback to index.html for SPA routing\n this._app.get('*', (_req: Request, res: Response) => {\n this.serveHtmlWithPorts(res);\n });\n }\n\n /**\n * Serve HTML with injected port configuration\n */\n private serveHtmlWithPorts(res: Response): void {\n try {\n const htmlPath = join(this.staticPath, 'index.html');\n let html = readFileSync(htmlPath, 'utf8');\n\n const scrcpyPort = this.scrcpyPort ?? this.port! + 1;\n\n // Inject scrcpy port configuration script into HTML head\n const configScript = `\n <script>\n window.SCRCPY_PORT = ${scrcpyPort};\n </script>\n `;\n\n // Insert the script before closing </head> tag\n html = html.replace('</head>', `${configScript}</head>`);\n\n res.setHeader('Content-Type', 'text/html');\n res.send(html);\n } catch (error) {\n console.error('Error serving HTML with ports:', error);\n res.status(500).send('Internal Server Error');\n }\n }\n\n /**\n * Launch the server on specified port\n */\n async launch(port?: number): Promise<PlaygroundServer> {\n // If using factory mode, initialize agent\n if (this._activeConnection.agentFactory && !this.sessionManager) {\n console.log('Initializing agent from factory function...');\n this._activeConnection.agent =\n await this._activeConnection.agentFactory();\n this._activeConnection.session = {\n connected: true,\n metadata: {},\n };\n this.sessionSetupState = 'ready';\n this.syncRuntimeState();\n console.log('Agent initialized successfully');\n }\n\n // Initialize routes now, after any middleware has been added\n this.initializeApp();\n\n this.port = port || defaultPort;\n\n return new Promise((resolve) => {\n const serverPort = this.port ?? defaultPort;\n this.server = this._app.listen(serverPort, '0.0.0.0', () => {\n resolve(this);\n });\n });\n }\n\n /**\n * Close the server and clean up resources\n */\n async close(): Promise<void> {\n await this.destroyCurrentSession().catch((error) => {\n console.warn('Failed to destroy current session during shutdown:', error);\n });\n\n return new Promise((resolve, reject) => {\n if (this.server) {\n this.taskExecutionDumps = {};\n\n // Close the server\n this.server.close((error) => {\n if (error) {\n reject(error);\n } else {\n this.server = undefined;\n resolve();\n }\n });\n } else {\n resolve();\n }\n });\n }\n}\n\nexport default PlaygroundServer;\nexport { PlaygroundServer };\n"],"names":["defaultPort","PLAYGROUND_SERVER_PORT","serializeAiConfigSignature","aiConfig","JSON","Object","leftKey","rightKey","serializeZodField","field","def","typeName","result","Array","rawShape","serializedShape","k","v","__filename","fileURLToPath","__dirname","dirname","STATIC_PATH","join","errorHandler","err","req","res","next","console","errorMessage","Error","PlaygroundServer","methodName","prepared","undefined","preview","metadata","buildRuntimeInfo","connected","Boolean","sessionConnected","sidecars","sidecar","error","previousSession","previousSidecars","session","sessionSidecars","input","express","_res","context","uuid","filePath","resolvedPath","resolve","resolvedTmpDir","tmpFile","writeFileSync","_req","setup","value","targets","created","failedSessionSidecars","contextFile","existsSync","readFileSync","requestId","executionDump","agent","actionSpace","processedActionSpace","action","typedAction","processedSchema","key","e","actionName","type","prompt","params","deepLocate","deepThink","screenshotIncluded","domIncluded","deviceOptions","iface","_dump","response","startTime","Date","executeAction","formatErrorMessage","hookError","dumpString","groupedDump","ReportActionDump","timeCost","dump","reportHTML","base64Screenshot","statusCode","nativeUrl","proxyOk","runtimeInfo","nextConfigSignature","configChanged","overrideAIConfig","globalModelConfigManager","runConnectivityTest","Promise","proxyReq","http","proxyRes","contentType","defaultMjpegFps","maxMjpegFps","maxErrorBackoffMs","errorLogThreshold","parsedFps","Number","fps","Math","interval","boundary","stopped","consecutiveErrors","r","setTimeout","frameStart","base64","raw","buf","Buffer","backoff","elapsed","remaining","htmlPath","html","scrcpyPort","configScript","port","serverPort","reject","staticPath","id","getTmpDir"],"mappings":"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"}