@midscene/playground 1.3.1 → 1.3.2

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.
@@ -191,7 +191,11 @@ class RemoteExecutionAdapter extends BasePlaygroundAdapter {
191
191
  aiConfig
192
192
  })
193
193
  });
194
- if (!response.ok) throw new Error(`Failed to override server config: ${response.statusText}`);
194
+ if (!response.ok) {
195
+ const body = await response.json().catch(()=>null);
196
+ const detail = body?.error || response.statusText;
197
+ throw new Error(detail);
198
+ }
195
199
  } catch (error) {
196
200
  console.error('Failed to override server config:', error);
197
201
  throw error;
@@ -1 +1 @@
1
- {"version":3,"file":"adapters/remote-execution.mjs","sources":["../../../src/adapters/remote-execution.ts"],"sourcesContent":["import type { DeviceAction, ExecutionDump } from '@midscene/core';\nimport { parseStructuredParams } from '../common';\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: '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 throw new Error(\n `Failed to override server config: ${response.statusText}`,\n );\n }\n } catch (error) {\n console.error('Failed to override server config:', error);\n throw error;\n }\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"],"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","requestId","encodeURIComponent","setInterval","progressData","clearInterval","serverUrl"],"mappings":";;;;;;;;;;;;AAKO,MAAMA,+BAA+BC;IAe1C,aACEC,QAA+D,EACzD;QACN,IAAI,CAAC,kBAAkB,GAAGC;QAC1B,IAAI,CAAC,kBAAkB,GAAGD;IAC5B;IAGA,IAAI,KAAyB;QAC3B,OAAO,IAAI,CAAC,GAAG;IACjB;IAIA,eACEE,KAAgB,EAChBC,MAAyC,EACvB;QAClB,IAAI,CAACA,QAAQ,aACX,OAAO;YAAE,OAAO;QAAK;QAGvB,MAAMC,wBAAwB,IAAI,CAAC,2BAA2B,CAACD;QAE/D,IAAI,CAACC,uBACH,OAAO;YAAE,OAAO;QAAK;QAGvB,IAAI,CAACF,MAAM,MAAM,EACf,OAAO;YAAE,OAAO;YAAO,cAAc;QAA0B;QAKjE,IAAIC,OAAO,WAAW,IAAI,AAA8B,YAA9B,OAAOA,OAAO,WAAW,EAAe;YAChE,MAAME,SAASF,OAAO,WAAW;YACjC,IAAIE,OAAO,KAAK,IAAIA,AAAgB,gBAAhBA,OAAO,IAAI,EAAkB;gBAC/C,MAAMC,QAAQD,OAAO,KAAK,IAAI,CAAC;gBAC/B,MAAME,gBAAgBC,OAAO,IAAI,CAACF,OAAO,MAAM,CAAC,CAACG;oBAC/C,MAAMC,WAAWJ,KAAK,CAACG,IAAI;oBAE3B,MAAME,aACJD,UAAU,cACVA,UAAU,MAAM,aAChBA,UAAU,MAAM,aAAa;oBAC/B,OACE,CAACC,cACAT,CAAAA,AAAuBD,WAAvBC,MAAM,MAAO,CAACO,IAAI,IAAkBP,AAAuB,OAAvBA,MAAM,MAAO,CAACO,IAAI,AAAM;gBAEjE;gBAEA,IAAIF,cAAc,MAAM,GAAG,GACzB,OAAO;oBACL,OAAO;oBACP,cAAc,CAAC,6BAA6B,EAAEA,cAAc,IAAI,CAAC,OAAO;gBAC1E;YAEJ;QACF;QAEA,OAAO;YAAE,OAAO;QAAK;IACvB;IAEA,MAAM,sBACJJ,MAA6B,EAC7BS,MAA+B,EAC/BC,OAAyB,EACL;QAEpB,OAAO,MAAMC,sBAAsBX,QAAQS,QAAQC;IACrD;IAEA,mBAAmBE,KAAU,EAAU;QACrC,MAAMC,UAAUD,OAAO,WAAW;QAGlC,MAAME,gBAAgB;YACpB;gBACE,SAAS;gBACT,SACE;YACJ;YACA;gBACE,SAAS;gBACT,SACE;YACJ;SACD;QAED,MAAMC,eAAeD,cAAc,IAAI,CAAC,CAAC,EAAEE,OAAO,EAAE,GAClDH,QAAQ,QAAQ,CAACG;QAEnB,IAAID,cACF,OAAOA,aAAa,OAAO;QAG7B,OAAO,IAAI,CAAC,uBAAuB,CAACH;IACtC;IAGA,MAAM,cACJK,UAAkB,EAClBlB,KAAgB,EAChBW,OAAyB,EACP;QAElB,IAAI,IAAI,CAAC,SAAS,IAAI,AAAkB,eAAlB,OAAOQ,QAC3B,OAAO,IAAI,CAAC,gBAAgB,CAACD,YAAYlB,OAAOW;QAGlD,MAAM,IAAIS,MACR;IAEJ;IAGA,MAAc,iBACZF,UAAkB,EAClBlB,KAAgB,EAChBW,OAAyB,EACP;QAClB,MAAMU,UAAmC;YACvC,MAAMH;YACN,QAAQlB,MAAM,MAAM;YACpB,GAAG,IAAI,CAAC,0BAA0B,CAACW,SAASX,MAAM;QACpD;QAGA,IAAIW,QAAQ,OAAO,EACjBU,QAAQ,OAAO,GAAGV,QAAQ,OAAO;QAInC,IAAIA,QAAQ,SAAS,IAAI,IAAI,CAAC,kBAAkB,EAC9C,IAAI,CAAC,oBAAoB,CAACA,QAAQ,SAAS;QAG7C,IAAI;YACF,MAAMW,WAAW,MAAMC,MAAM,GAAG,IAAI,CAAC,SAAS,CAAC,QAAQ,CAAC,EAAE;gBACxD,QAAQ;gBACR,SAAS;oBACP,gBAAgB;gBAClB;gBACA,MAAMC,KAAK,SAAS,CAACH;YACvB;YAEA,IAAI,CAACC,SAAS,EAAE,EAAE;gBAChB,MAAMG,YAAY,MAAMH,SAAS,IAAI,GAAG,KAAK,CAAC,IAAM;gBACpD,MAAM,IAAIF,MACR,CAAC,uBAAuB,EAAEE,SAAS,MAAM,CAAC,GAAG,EAAEG,WAAW;YAE9D;YAEA,MAAMC,SAAS,MAAMJ,SAAS,IAAI;YAElC,OAAOI;QACT,EAAE,OAAOb,OAAO;YACdc,QAAQ,KAAK,CAAC,8BAA8Bd;YAC5C,MAAMA;QACR,SAAU;YAER,IAAI,CAAC,mBAAmB;QAC1B;IACF;IAGQ,2BACNF,OAAyB,EACzBX,KAAgB,EACS;QACzB,MAAM4B,iBAA0C,CAAC;QAGjD,MAAMC,iBAAiB;YACrB;gBAAE,KAAK;gBAAa,OAAOlB,QAAQ,SAAS;YAAC;YAC7C;gBAAE,KAAK;gBAAa,OAAOA,QAAQ,SAAS;YAAC;YAC7C;gBAAE,KAAK;gBAAsB,OAAOA,QAAQ,kBAAkB;YAAC;YAC/D;gBAAE,KAAK;gBAAe,OAAOA,QAAQ,WAAW;YAAC;YACjD;gBAAE,KAAK;gBAAiB,OAAOA,QAAQ,aAAa;YAAC;YACrD;gBAAE,KAAK;gBAAU,OAAOX,MAAM,MAAM;YAAC;SACtC;QAED6B,eAAe,OAAO,CAAC,CAAC,EAAEtB,GAAG,EAAEP,KAAK,EAAE;YACpC,IAAIA,QAAAA,SAAyCA,AAAU,OAAVA,OAC3C4B,cAAc,CAACrB,IAAI,GAAGP;QAE1B;QAEA,OAAO4B;IACT;IAGA,MAAM,eAAeE,OAAiB,EAAoC;QAExE,IAAI,IAAI,CAAC,SAAS,IAAI,AAAkB,eAAlB,OAAOX,QAC3B,IAAI;YACF,MAAMG,WAAW,MAAMC,MAAM,GAAG,IAAI,CAAC,SAAS,CAAC,aAAa,CAAC,EAAE;gBAC7D,QAAQ;gBACR,SAAS;oBACP,gBAAgB;gBAClB;gBACA,MAAMC,KAAK,SAAS,CAAC;oBAAEM;gBAAQ;YACjC;YAEA,IAAI,CAACR,SAAS,EAAE,EACd,MAAM,IAAIF,MAAM,CAAC,4BAA4B,EAAEE,SAAS,UAAU,EAAE;YAGtE,MAAMI,SAAS,MAAMJ,SAAS,IAAI;YAClC,OAAOS,MAAM,OAAO,CAACL,UAAUA,SAAS,EAAE;QAC5C,EAAE,OAAOb,OAAO;YACdc,QAAQ,KAAK,CAAC,2CAA2Cd;QAE3D;QAIF,IAAIiB,WAAW,AAAmB,YAAnB,OAAOA,WAAwB,iBAAiBA,SAC7D,IAAI;YACF,MAAME,oBACJF,QAKA,WAAW;YACb,MAAMJ,SAAS,MAAMM;YACrB,OAAOD,MAAM,OAAO,CAACL,UAAUA,SAAS,EAAE;QAC5C,EAAE,OAAOb,OAAO;YACdc,QAAQ,KAAK,CAAC,4CAA4Cd;QAC5D;QAGF,OAAO,EAAE;IACX;IAKA,MAAM,cAAgC;QACpC,IAAI,CAAC,IAAI,CAAC,SAAS,EACjB,OAAO;QAGT,IAAI;YACF,MAAMoB,MAAM,MAAMV,MAAM,GAAG,IAAI,CAAC,SAAS,CAAC,OAAO,CAAC;YAClD,IAAIU,AAAe,QAAfA,IAAI,MAAM,EAAU;gBAEtB,IAAI;oBACF,MAAMC,OAAO,MAAMD,IAAI,IAAI;oBAC3B,IAAIC,KAAK,EAAE,IAAI,AAAmB,YAAnB,OAAOA,KAAK,EAAE,EAC3B,IAAI,CAAC,GAAG,GAAGA,KAAK,EAAE;gBAEtB,EAAE,OAAOC,WAAW;oBAElBR,QAAQ,KAAK,CAAC,oCAAoCQ;gBACpD;gBACA,OAAO;YACT;YACA,OAAO;QACT,EAAE,OAAOtB,OAAO;YACdc,QAAQ,IAAI,CAAC,+BAA+Bd;YAC5C,OAAO;QACT;IACF;IAEA,MAAM,eAAeuB,QAAiC,EAAiB;QACrE,IAAI,CAAC,IAAI,CAAC,SAAS,EACjB,MAAM,IAAIhB,MAAM;QAGlB,IAAI;YACF,MAAME,WAAW,MAAMC,MAAM,GAAG,IAAI,CAAC,SAAS,CAAC,OAAO,CAAC,EAAE;gBACvD,QAAQ;gBACR,SAAS;oBACP,gBAAgB;gBAClB;gBACA,MAAMC,KAAK,SAAS,CAAC;oBAAEY;gBAAS;YAClC;YAEA,IAAI,CAACd,SAAS,EAAE,EACd,MAAM,IAAIF,MACR,CAAC,kCAAkC,EAAEE,SAAS,UAAU,EAAE;QAGhE,EAAE,OAAOT,OAAO;YACdc,QAAQ,KAAK,CAAC,qCAAqCd;YACnD,MAAMA;QACR;IACF;IAEA,MAAM,gBAAgBwB,SAAiB,EAEpC;QACD,IAAI,CAAC,IAAI,CAAC,SAAS,EACjB,OAAO,CAAC;QAGV,IAAI,CAACA,WAAW,QAAQ;YACtBV,QAAQ,IAAI,CAAC;YACb,OAAO,CAAC;QACV;QAEA,IAAI;YACF,MAAML,WAAW,MAAMC,MACrB,GAAG,IAAI,CAAC,SAAS,CAAC,eAAe,EAAEe,mBAAmBD,YAAY;YAGpE,IAAI,CAACf,SAAS,EAAE,EAAE;gBAChBK,QAAQ,IAAI,CAAC,CAAC,8BAA8B,EAAEL,SAAS,UAAU,EAAE;gBACnE,OAAO,CAAC;YACV;YAEA,OAAO,MAAMA,SAAS,IAAI;QAC5B,EAAE,OAAOT,OAAO;YACdc,QAAQ,KAAK,CAAC,iCAAiCd;YAC/C,OAAO,CAAC;QACV;IACF;IAKQ,qBAAqBwB,SAAiB,EAAQ;QAEpD,IAAI,CAAC,mBAAmB;QAGxB,IAAI,CAAC,iBAAiB,GAAGE,YAAY;YACnC,IAAI;gBACF,MAAMC,eAAe,MAAM,IAAI,CAAC,eAAe,CAACH;gBAEhD,IAAIG,aAAa,aAAa,EAE5B;oBAAA,IAAI,IAAI,CAAC,kBAAkB,EACzB,IAAI,CAAC,kBAAkB,CAAC,IAAIA,aAAa,aAAa;gBACxD;YAEJ,EAAE,OAAO3B,OAAO;gBACdc,QAAQ,KAAK,CAAC,gCAAgCd;YAChD;QACF,GAAG;IACL;IAKQ,sBAA4B;QAClC,IAAI,IAAI,CAAC,iBAAiB,EAAE;YAC1B4B,cAAc,IAAI,CAAC,iBAAiB;YACpC,IAAI,CAAC,iBAAiB,GAAG1C;QAC3B;IACF;IAGA,MAAM,WACJsC,SAAiB,EAC+B;QAChD,IAAI,CAAC,IAAI,CAAC,SAAS,EACjB,OAAO;YAAE,OAAO;QAA2B;QAG7C,IAAI,CAACA,WAAW,QACd,OAAO;YAAE,OAAO;QAAqB;QAGvC,IAAI;YACF,MAAMJ,MAAM,MAAMV,MAChB,GAAG,IAAI,CAAC,SAAS,CAAC,QAAQ,EAAEe,mBAAmBD,YAAY,EAC3D;gBACE,QAAQ;YACV;YAGF,IAAI,CAACJ,IAAI,EAAE,EACT,OAAO;gBAAE,OAAO,CAAC,uBAAuB,EAAEA,IAAI,UAAU,EAAE;YAAC;YAG7D,MAAMP,SAAS,MAAMO,IAAI,IAAI;YAC7B,OAAO;gBAAE,SAAS;gBAAM,GAAGP,MAAM;YAAC;QACpC,EAAE,OAAOb,OAAO;YACdc,QAAQ,KAAK,CAAC,0BAA0Bd;YACxC,OAAO;gBAAE,OAAO;YAAwB;QAC1C;IACF;IAGA,MAAM,gBAGI;QACR,IAAI,CAAC,IAAI,CAAC,SAAS,EACjB,OAAO;QAGT,IAAI;YACF,MAAMS,WAAW,MAAMC,MAAM,GAAG,IAAI,CAAC,SAAS,CAAC,WAAW,CAAC;YAE3D,IAAI,CAACD,SAAS,EAAE,EAAE;gBAChBK,QAAQ,IAAI,CAAC,CAAC,2BAA2B,EAAEL,SAAS,UAAU,EAAE;gBAChE,OAAO;YACT;YAEA,OAAO,MAAMA,SAAS,IAAI;QAC5B,EAAE,OAAOT,OAAO;YACdc,QAAQ,KAAK,CAAC,6BAA6Bd;YAC3C,OAAO;QACT;IACF;IAGA,MAAM,mBAGI;QACR,IAAI,CAAC,IAAI,CAAC,SAAS,EACjB,OAAO;QAGT,IAAI;YACF,MAAMS,WAAW,MAAMC,MAAM,GAAG,IAAI,CAAC,SAAS,CAAC,eAAe,CAAC;YAE/D,IAAI,CAACD,SAAS,EAAE,EAAE;gBAChBK,QAAQ,IAAI,CAAC,CAAC,+BAA+B,EAAEL,SAAS,UAAU,EAAE;gBACpE,OAAO;YACT;YAEA,OAAO,MAAMA,SAAS,IAAI;QAC5B,EAAE,OAAOT,OAAO;YACdc,QAAQ,KAAK,CAAC,iCAAiCd;YAC/C,OAAO;QACT;IACF;IAtbA,YAAY6B,SAAiB,CAAE;QAC7B,KAAK,IATP,uBAAQ,aAAR,SACA,uBAAQ,OAAR,SACA,uBAAQ,sBAAR,SAIA,uBAAQ,qBAAR;QAIE,IAAI,CAAC,SAAS,GAAGA;IACnB;AAobF"}
1
+ {"version":3,"file":"adapters/remote-execution.mjs","sources":["../../../src/adapters/remote-execution.ts"],"sourcesContent":["import type { DeviceAction, ExecutionDump } from '@midscene/core';\nimport { parseStructuredParams } from '../common';\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: '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 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"],"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","serverUrl"],"mappings":";;;;;;;;;;;;AAKO,MAAMA,+BAA+BC;IAe1C,aACEC,QAA+D,EACzD;QACN,IAAI,CAAC,kBAAkB,GAAGC;QAC1B,IAAI,CAAC,kBAAkB,GAAGD;IAC5B;IAGA,IAAI,KAAyB;QAC3B,OAAO,IAAI,CAAC,GAAG;IACjB;IAIA,eACEE,KAAgB,EAChBC,MAAyC,EACvB;QAClB,IAAI,CAACA,QAAQ,aACX,OAAO;YAAE,OAAO;QAAK;QAGvB,MAAMC,wBAAwB,IAAI,CAAC,2BAA2B,CAACD;QAE/D,IAAI,CAACC,uBACH,OAAO;YAAE,OAAO;QAAK;QAGvB,IAAI,CAACF,MAAM,MAAM,EACf,OAAO;YAAE,OAAO;YAAO,cAAc;QAA0B;QAKjE,IAAIC,OAAO,WAAW,IAAI,AAA8B,YAA9B,OAAOA,OAAO,WAAW,EAAe;YAChE,MAAME,SAASF,OAAO,WAAW;YACjC,IAAIE,OAAO,KAAK,IAAIA,AAAgB,gBAAhBA,OAAO,IAAI,EAAkB;gBAC/C,MAAMC,QAAQD,OAAO,KAAK,IAAI,CAAC;gBAC/B,MAAME,gBAAgBC,OAAO,IAAI,CAACF,OAAO,MAAM,CAAC,CAACG;oBAC/C,MAAMC,WAAWJ,KAAK,CAACG,IAAI;oBAE3B,MAAME,aACJD,UAAU,cACVA,UAAU,MAAM,aAChBA,UAAU,MAAM,aAAa;oBAC/B,OACE,CAACC,cACAT,CAAAA,AAAuBD,WAAvBC,MAAM,MAAO,CAACO,IAAI,IAAkBP,AAAuB,OAAvBA,MAAM,MAAO,CAACO,IAAI,AAAM;gBAEjE;gBAEA,IAAIF,cAAc,MAAM,GAAG,GACzB,OAAO;oBACL,OAAO;oBACP,cAAc,CAAC,6BAA6B,EAAEA,cAAc,IAAI,CAAC,OAAO;gBAC1E;YAEJ;QACF;QAEA,OAAO;YAAE,OAAO;QAAK;IACvB;IAEA,MAAM,sBACJJ,MAA6B,EAC7BS,MAA+B,EAC/BC,OAAyB,EACL;QAEpB,OAAO,MAAMC,sBAAsBX,QAAQS,QAAQC;IACrD;IAEA,mBAAmBE,KAAU,EAAU;QACrC,MAAMC,UAAUD,OAAO,WAAW;QAGlC,MAAME,gBAAgB;YACpB;gBACE,SAAS;gBACT,SACE;YACJ;YACA;gBACE,SAAS;gBACT,SACE;YACJ;SACD;QAED,MAAMC,eAAeD,cAAc,IAAI,CAAC,CAAC,EAAEE,OAAO,EAAE,GAClDH,QAAQ,QAAQ,CAACG;QAEnB,IAAID,cACF,OAAOA,aAAa,OAAO;QAG7B,OAAO,IAAI,CAAC,uBAAuB,CAACH;IACtC;IAGA,MAAM,cACJK,UAAkB,EAClBlB,KAAgB,EAChBW,OAAyB,EACP;QAElB,IAAI,IAAI,CAAC,SAAS,IAAI,AAAkB,eAAlB,OAAOQ,QAC3B,OAAO,IAAI,CAAC,gBAAgB,CAACD,YAAYlB,OAAOW;QAGlD,MAAM,IAAIS,MACR;IAEJ;IAGA,MAAc,iBACZF,UAAkB,EAClBlB,KAAgB,EAChBW,OAAyB,EACP;QAClB,MAAMU,UAAmC;YACvC,MAAMH;YACN,QAAQlB,MAAM,MAAM;YACpB,GAAG,IAAI,CAAC,0BAA0B,CAACW,SAASX,MAAM;QACpD;QAGA,IAAIW,QAAQ,OAAO,EACjBU,QAAQ,OAAO,GAAGV,QAAQ,OAAO;QAInC,IAAIA,QAAQ,SAAS,IAAI,IAAI,CAAC,kBAAkB,EAC9C,IAAI,CAAC,oBAAoB,CAACA,QAAQ,SAAS;QAG7C,IAAI;YACF,MAAMW,WAAW,MAAMC,MAAM,GAAG,IAAI,CAAC,SAAS,CAAC,QAAQ,CAAC,EAAE;gBACxD,QAAQ;gBACR,SAAS;oBACP,gBAAgB;gBAClB;gBACA,MAAMC,KAAK,SAAS,CAACH;YACvB;YAEA,IAAI,CAACC,SAAS,EAAE,EAAE;gBAChB,MAAMG,YAAY,MAAMH,SAAS,IAAI,GAAG,KAAK,CAAC,IAAM;gBACpD,MAAM,IAAIF,MACR,CAAC,uBAAuB,EAAEE,SAAS,MAAM,CAAC,GAAG,EAAEG,WAAW;YAE9D;YAEA,MAAMC,SAAS,MAAMJ,SAAS,IAAI;YAElC,OAAOI;QACT,EAAE,OAAOb,OAAO;YACdc,QAAQ,KAAK,CAAC,8BAA8Bd;YAC5C,MAAMA;QACR,SAAU;YAER,IAAI,CAAC,mBAAmB;QAC1B;IACF;IAGQ,2BACNF,OAAyB,EACzBX,KAAgB,EACS;QACzB,MAAM4B,iBAA0C,CAAC;QAGjD,MAAMC,iBAAiB;YACrB;gBAAE,KAAK;gBAAa,OAAOlB,QAAQ,SAAS;YAAC;YAC7C;gBAAE,KAAK;gBAAa,OAAOA,QAAQ,SAAS;YAAC;YAC7C;gBAAE,KAAK;gBAAsB,OAAOA,QAAQ,kBAAkB;YAAC;YAC/D;gBAAE,KAAK;gBAAe,OAAOA,QAAQ,WAAW;YAAC;YACjD;gBAAE,KAAK;gBAAiB,OAAOA,QAAQ,aAAa;YAAC;YACrD;gBAAE,KAAK;gBAAU,OAAOX,MAAM,MAAM;YAAC;SACtC;QAED6B,eAAe,OAAO,CAAC,CAAC,EAAEtB,GAAG,EAAEP,KAAK,EAAE;YACpC,IAAIA,QAAAA,SAAyCA,AAAU,OAAVA,OAC3C4B,cAAc,CAACrB,IAAI,GAAGP;QAE1B;QAEA,OAAO4B;IACT;IAGA,MAAM,eAAeE,OAAiB,EAAoC;QAExE,IAAI,IAAI,CAAC,SAAS,IAAI,AAAkB,eAAlB,OAAOX,QAC3B,IAAI;YACF,MAAMG,WAAW,MAAMC,MAAM,GAAG,IAAI,CAAC,SAAS,CAAC,aAAa,CAAC,EAAE;gBAC7D,QAAQ;gBACR,SAAS;oBACP,gBAAgB;gBAClB;gBACA,MAAMC,KAAK,SAAS,CAAC;oBAAEM;gBAAQ;YACjC;YAEA,IAAI,CAACR,SAAS,EAAE,EACd,MAAM,IAAIF,MAAM,CAAC,4BAA4B,EAAEE,SAAS,UAAU,EAAE;YAGtE,MAAMI,SAAS,MAAMJ,SAAS,IAAI;YAClC,OAAOS,MAAM,OAAO,CAACL,UAAUA,SAAS,EAAE;QAC5C,EAAE,OAAOb,OAAO;YACdc,QAAQ,KAAK,CAAC,2CAA2Cd;QAE3D;QAIF,IAAIiB,WAAW,AAAmB,YAAnB,OAAOA,WAAwB,iBAAiBA,SAC7D,IAAI;YACF,MAAME,oBACJF,QAKA,WAAW;YACb,MAAMJ,SAAS,MAAMM;YACrB,OAAOD,MAAM,OAAO,CAACL,UAAUA,SAAS,EAAE;QAC5C,EAAE,OAAOb,OAAO;YACdc,QAAQ,KAAK,CAAC,4CAA4Cd;QAC5D;QAGF,OAAO,EAAE;IACX;IAKA,MAAM,cAAgC;QACpC,IAAI,CAAC,IAAI,CAAC,SAAS,EACjB,OAAO;QAGT,IAAI;YACF,MAAMoB,MAAM,MAAMV,MAAM,GAAG,IAAI,CAAC,SAAS,CAAC,OAAO,CAAC;YAClD,IAAIU,AAAe,QAAfA,IAAI,MAAM,EAAU;gBAEtB,IAAI;oBACF,MAAMC,OAAO,MAAMD,IAAI,IAAI;oBAC3B,IAAIC,KAAK,EAAE,IAAI,AAAmB,YAAnB,OAAOA,KAAK,EAAE,EAC3B,IAAI,CAAC,GAAG,GAAGA,KAAK,EAAE;gBAEtB,EAAE,OAAOC,WAAW;oBAElBR,QAAQ,KAAK,CAAC,oCAAoCQ;gBACpD;gBACA,OAAO;YACT;YACA,OAAO;QACT,EAAE,OAAOtB,OAAO;YACdc,QAAQ,IAAI,CAAC,+BAA+Bd;YAC5C,OAAO;QACT;IACF;IAEA,MAAM,eAAeuB,QAAiC,EAAiB;QACrE,IAAI,CAAC,IAAI,CAAC,SAAS,EACjB,MAAM,IAAIhB,MAAM;QAGlB,IAAI;YACF,MAAME,WAAW,MAAMC,MAAM,GAAG,IAAI,CAAC,SAAS,CAAC,OAAO,CAAC,EAAE;gBACvD,QAAQ;gBACR,SAAS;oBACP,gBAAgB;gBAClB;gBACA,MAAMC,KAAK,SAAS,CAAC;oBAAEY;gBAAS;YAClC;YAEA,IAAI,CAACd,SAAS,EAAE,EAAE;gBAChB,MAAMe,OAAO,MAAMf,SAAS,IAAI,GAAG,KAAK,CAAC,IAAM;gBAC/C,MAAMgB,SAASD,MAAM,SAASf,SAAS,UAAU;gBACjD,MAAM,IAAIF,MAAMkB;YAClB;QACF,EAAE,OAAOzB,OAAO;YACdc,QAAQ,KAAK,CAAC,qCAAqCd;YACnD,MAAMA;QACR;IACF;IAEA,MAAM,gBAAgB0B,SAAiB,EAEpC;QACD,IAAI,CAAC,IAAI,CAAC,SAAS,EACjB,OAAO,CAAC;QAGV,IAAI,CAACA,WAAW,QAAQ;YACtBZ,QAAQ,IAAI,CAAC;YACb,OAAO,CAAC;QACV;QAEA,IAAI;YACF,MAAML,WAAW,MAAMC,MACrB,GAAG,IAAI,CAAC,SAAS,CAAC,eAAe,EAAEiB,mBAAmBD,YAAY;YAGpE,IAAI,CAACjB,SAAS,EAAE,EAAE;gBAChBK,QAAQ,IAAI,CAAC,CAAC,8BAA8B,EAAEL,SAAS,UAAU,EAAE;gBACnE,OAAO,CAAC;YACV;YAEA,OAAO,MAAMA,SAAS,IAAI;QAC5B,EAAE,OAAOT,OAAO;YACdc,QAAQ,KAAK,CAAC,iCAAiCd;YAC/C,OAAO,CAAC;QACV;IACF;IAKQ,qBAAqB0B,SAAiB,EAAQ;QAEpD,IAAI,CAAC,mBAAmB;QAGxB,IAAI,CAAC,iBAAiB,GAAGE,YAAY;YACnC,IAAI;gBACF,MAAMC,eAAe,MAAM,IAAI,CAAC,eAAe,CAACH;gBAEhD,IAAIG,aAAa,aAAa,EAE5B;oBAAA,IAAI,IAAI,CAAC,kBAAkB,EACzB,IAAI,CAAC,kBAAkB,CAAC,IAAIA,aAAa,aAAa;gBACxD;YAEJ,EAAE,OAAO7B,OAAO;gBACdc,QAAQ,KAAK,CAAC,gCAAgCd;YAChD;QACF,GAAG;IACL;IAKQ,sBAA4B;QAClC,IAAI,IAAI,CAAC,iBAAiB,EAAE;YAC1B8B,cAAc,IAAI,CAAC,iBAAiB;YACpC,IAAI,CAAC,iBAAiB,GAAG5C;QAC3B;IACF;IAGA,MAAM,WACJwC,SAAiB,EAC+B;QAChD,IAAI,CAAC,IAAI,CAAC,SAAS,EACjB,OAAO;YAAE,OAAO;QAA2B;QAG7C,IAAI,CAACA,WAAW,QACd,OAAO;YAAE,OAAO;QAAqB;QAGvC,IAAI;YACF,MAAMN,MAAM,MAAMV,MAChB,GAAG,IAAI,CAAC,SAAS,CAAC,QAAQ,EAAEiB,mBAAmBD,YAAY,EAC3D;gBACE,QAAQ;YACV;YAGF,IAAI,CAACN,IAAI,EAAE,EACT,OAAO;gBAAE,OAAO,CAAC,uBAAuB,EAAEA,IAAI,UAAU,EAAE;YAAC;YAG7D,MAAMP,SAAS,MAAMO,IAAI,IAAI;YAC7B,OAAO;gBAAE,SAAS;gBAAM,GAAGP,MAAM;YAAC;QACpC,EAAE,OAAOb,OAAO;YACdc,QAAQ,KAAK,CAAC,0BAA0Bd;YACxC,OAAO;gBAAE,OAAO;YAAwB;QAC1C;IACF;IAGA,MAAM,gBAGI;QACR,IAAI,CAAC,IAAI,CAAC,SAAS,EACjB,OAAO;QAGT,IAAI;YACF,MAAMS,WAAW,MAAMC,MAAM,GAAG,IAAI,CAAC,SAAS,CAAC,WAAW,CAAC;YAE3D,IAAI,CAACD,SAAS,EAAE,EAAE;gBAChBK,QAAQ,IAAI,CAAC,CAAC,2BAA2B,EAAEL,SAAS,UAAU,EAAE;gBAChE,OAAO;YACT;YAEA,OAAO,MAAMA,SAAS,IAAI;QAC5B,EAAE,OAAOT,OAAO;YACdc,QAAQ,KAAK,CAAC,6BAA6Bd;YAC3C,OAAO;QACT;IACF;IAGA,MAAM,mBAGI;QACR,IAAI,CAAC,IAAI,CAAC,SAAS,EACjB,OAAO;QAGT,IAAI;YACF,MAAMS,WAAW,MAAMC,MAAM,GAAG,IAAI,CAAC,SAAS,CAAC,eAAe,CAAC;YAE/D,IAAI,CAACD,SAAS,EAAE,EAAE;gBAChBK,QAAQ,IAAI,CAAC,CAAC,+BAA+B,EAAEL,SAAS,UAAU,EAAE;gBACpE,OAAO;YACT;YAEA,OAAO,MAAMA,SAAS,IAAI;QAC5B,EAAE,OAAOT,OAAO;YACdc,QAAQ,KAAK,CAAC,iCAAiCd;YAC/C,OAAO;QACT;IACF;IAtbA,YAAY+B,SAAiB,CAAE;QAC7B,KAAK,IATP,uBAAQ,aAAR,SACA,uBAAQ,OAAR,SACA,uBAAQ,sBAAR,SAIA,uBAAQ,qBAAR;QAIE,IAAI,CAAC,SAAS,GAAGA;IACnB;AAobF"}
@@ -4,7 +4,7 @@ import { fileURLToPath } from "node:url";
4
4
  import { GroupedActionDump } from "@midscene/core";
5
5
  import { getTmpDir } from "@midscene/core/utils";
6
6
  import { PLAYGROUND_SERVER_PORT } from "@midscene/shared/constants";
7
- import { overrideAIConfig } from "@midscene/shared/env";
7
+ import { globalModelConfigManager, overrideAIConfig } from "@midscene/shared/env";
8
8
  import { uuid as utils_uuid } from "@midscene/shared/utils";
9
9
  import express from "express";
10
10
  import { executeAction, formatErrorMessage } from "./common.mjs";
@@ -318,10 +318,6 @@ class PlaygroundServer {
318
318
  });
319
319
  try {
320
320
  overrideAIConfig(aiConfig);
321
- return res.json({
322
- status: 'ok',
323
- message: 'AI config updated. Agent will be recreated on next execution.'
324
- });
325
321
  } catch (error) {
326
322
  const errorMessage = error instanceof Error ? error.message : 'Unknown error';
327
323
  console.error(`Failed to update AI config: ${errorMessage}`);
@@ -329,6 +325,19 @@ class PlaygroundServer {
329
325
  error: `Failed to update AI config: ${errorMessage}`
330
326
  });
331
327
  }
328
+ try {
329
+ globalModelConfigManager.getModelConfig('default');
330
+ } catch (error) {
331
+ const errorMessage = error instanceof Error ? error.message : 'Unknown error';
332
+ console.error(`AI config validation failed: ${errorMessage}`);
333
+ return res.status(400).json({
334
+ error: errorMessage
335
+ });
336
+ }
337
+ return res.json({
338
+ status: 'ok',
339
+ message: 'AI config updated. Agent will be recreated on next execution.'
340
+ });
332
341
  });
333
342
  }
334
343
  setupStaticRoutes() {
@@ -1 +1 @@
1
- {"version":3,"file":"server.mjs","sources":["../../src/server.ts"],"sourcesContent":["import { existsSync, readFileSync, writeFileSync } from 'node:fs';\nimport type { Server } from 'node:http';\nimport { dirname, join } from 'node:path';\nimport { fileURLToPath } from 'node:url';\nimport type { ExecutionDump } from '@midscene/core';\nimport { GroupedActionDump } 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 { overrideAIConfig } from '@midscene/shared/env';\nimport { uuid } from '@midscene/shared/utils';\nimport express, { type Request, type Response } from 'express';\nimport { executeAction, formatErrorMessage } from './common';\n\nimport 'dotenv/config';\n\nconst defaultPort = PLAYGROUND_SERVER_PORT;\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\nclass PlaygroundServer {\n private _app: express.Application;\n tmpDir: string;\n server?: Server;\n port?: number | null;\n agent: PageAgent;\n staticPath: string;\n taskExecutionDumps: Record<string, ExecutionDump | null>; // Store execution dumps directly\n id: string; // Unique identifier for this server instance\n\n private _initialized = false;\n\n // Factory function for recreating agent\n private agentFactory?: (() => PageAgent | Promise<PageAgent>) | null;\n\n // Track current running task\n private currentTaskId: string | null = null;\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.agentFactory = agent;\n this.agent = null as any; // Will be initialized in launch()\n } else {\n this.agent = agent;\n this.agentFactory = null;\n }\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 context &&\n 'updateContext' in this.agent.interface &&\n typeof this.agent.interface.updateContext === 'function'\n ) {\n this.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 return join(this.tmpDir, `${uuid}.json`);\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 if (!this.agentFactory) {\n throw new Error(\n 'Cannot recreate agent: factory function not provided. Attempting to destroy existing agent only.',\n );\n }\n\n console.log('Recreating agent to cancel current task...');\n\n // Destroy old agent instance\n try {\n if (this.agent && typeof this.agent.destroy === 'function') {\n await this.agent.destroy();\n }\n } catch (error) {\n console.warn('Failed to destroy old agent:', error);\n }\n\n // Create new agent instance\n try {\n this.agent = await this.agentFactory();\n console.log('Agent recreated successfully');\n } catch (error) {\n console.error('Failed to recreate agent:', error);\n throw error;\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('/context/:uuid', async (req: Request, res: Response) => {\n const { uuid } = req.params;\n const contextFile = this.filePathForUuid(uuid);\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 let actionSpace = [];\n\n actionSpace = this.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 processedSchema = {\n type: 'ZodObject',\n shape: typedAction.paramSchema.shape,\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(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 const {\n type,\n prompt,\n params,\n requestId,\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 // Always recreate agent before execution to ensure latest config is applied\n if (this.agentFactory) {\n console.log('Destroying old agent before execution...');\n try {\n if (this.agent && typeof this.agent.destroy === 'function') {\n await this.agent.destroy();\n }\n } catch (error) {\n console.warn('Failed to destroy old agent:', error);\n }\n\n console.log('Creating new agent with latest config...');\n try {\n this.agent = await this.agentFactory();\n console.log('Agent created successfully');\n } catch (error) {\n console.error('Failed to create 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 (\n deviceOptions &&\n this.agent.interface &&\n 'options' in this.agent.interface\n ) {\n this.agent.interface.options = {\n ...(this.agent.interface.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 this.agent.onDumpUpdate = (\n _dump: string,\n executionDump?: ExecutionDump,\n ) => {\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 // Get action space to check for dynamic actions\n const actionSpace = this.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(\n this.agent,\n type,\n actionSpace,\n value,\n {\n deepThink,\n screenshotIncluded,\n domIncluded,\n deviceOptions,\n },\n );\n } catch (error: unknown) {\n response.error = formatErrorMessage(error);\n }\n\n try {\n const dumpString = this.agent.dumpDataString();\n if (dumpString) {\n const groupedDump =\n GroupedActionDump.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 = this.agent.reportHTMLString() || null;\n\n this.agent.writeOutActionDumps();\n this.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 }\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 // 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 = this.agent.dumpDataString?.();\n if (dumpString) {\n const groupedDump =\n GroupedActionDump.fromSerializedString(dumpString);\n // Extract first execution from grouped dump\n dump = groupedDump.executions?.[0] || null;\n }\n\n reportHTML = this.agent.reportHTMLString?.() || null;\n } catch (error: unknown) {\n console.warn('Failed to get execution data before cancel:', error);\n }\n\n // Recreate/destroy agent to cancel the current task\n await this.recreateAgent();\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(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 // Check if page has screenshotBase64 method\n if (typeof this.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 this.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(500).json({\n error: `Failed to take screenshot: ${errorMessage}`,\n });\n }\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 type = this.agent.interface.interfaceType || 'Unknown';\n const description = this.agent.interface.describe?.() || undefined;\n\n res.json({\n type,\n 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.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\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 } 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 }\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 // Get scrcpy server port from global\n const scrcpyPort = (global as any).scrcpyServerPort || 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.agentFactory) {\n console.log('Initializing agent from factory function...');\n this.agent = await this.agentFactory();\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;\n this.server = this._app.listen(serverPort, () => {\n resolve(this);\n });\n });\n }\n\n /**\n * Close the server and clean up resources\n */\n async close(): Promise<void> {\n return new Promise((resolve, reject) => {\n if (this.server) {\n // Clean up the single agent\n try {\n this.agent.destroy();\n } catch (error) {\n console.warn('Failed to destroy agent:', error);\n }\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","__filename","fileURLToPath","__dirname","dirname","STATIC_PATH","join","errorHandler","err","req","res","next","console","errorMessage","Error","PlaygroundServer","express","_res","context","uuid","tmpFile","writeFileSync","error","contextFile","existsSync","readFileSync","requestId","executionDump","actionSpace","processedActionSpace","action","typedAction","processedSchema","e","actionName","type","prompt","params","deepThink","screenshotIncluded","domIncluded","deviceOptions","_dump","response","startTime","Date","value","executeAction","formatErrorMessage","dumpString","groupedDump","GroupedActionDump","timeCost","dump","reportHTML","_req","base64Screenshot","description","undefined","aiConfig","Object","overrideAIConfig","htmlPath","html","scrcpyPort","global","configScript","port","Promise","resolve","serverPort","reject","agent","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 type { Server } from 'node:http';\nimport { dirname, join } from 'node:path';\nimport { fileURLToPath } from 'node:url';\nimport type { ExecutionDump } from '@midscene/core';\nimport { GroupedActionDump } 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';\n\nimport 'dotenv/config';\n\nconst defaultPort = PLAYGROUND_SERVER_PORT;\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\nclass PlaygroundServer {\n private _app: express.Application;\n tmpDir: string;\n server?: Server;\n port?: number | null;\n agent: PageAgent;\n staticPath: string;\n taskExecutionDumps: Record<string, ExecutionDump | null>; // Store execution dumps directly\n id: string; // Unique identifier for this server instance\n\n private _initialized = false;\n\n // Factory function for recreating agent\n private agentFactory?: (() => PageAgent | Promise<PageAgent>) | null;\n\n // Track current running task\n private currentTaskId: string | null = null;\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.agentFactory = agent;\n this.agent = null as any; // Will be initialized in launch()\n } else {\n this.agent = agent;\n this.agentFactory = null;\n }\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 context &&\n 'updateContext' in this.agent.interface &&\n typeof this.agent.interface.updateContext === 'function'\n ) {\n this.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 return join(this.tmpDir, `${uuid}.json`);\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 if (!this.agentFactory) {\n throw new Error(\n 'Cannot recreate agent: factory function not provided. Attempting to destroy existing agent only.',\n );\n }\n\n console.log('Recreating agent to cancel current task...');\n\n // Destroy old agent instance\n try {\n if (this.agent && typeof this.agent.destroy === 'function') {\n await this.agent.destroy();\n }\n } catch (error) {\n console.warn('Failed to destroy old agent:', error);\n }\n\n // Create new agent instance\n try {\n this.agent = await this.agentFactory();\n console.log('Agent recreated successfully');\n } catch (error) {\n console.error('Failed to recreate agent:', error);\n throw error;\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('/context/:uuid', async (req: Request, res: Response) => {\n const { uuid } = req.params;\n const contextFile = this.filePathForUuid(uuid);\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 let actionSpace = [];\n\n actionSpace = this.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 processedSchema = {\n type: 'ZodObject',\n shape: typedAction.paramSchema.shape,\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(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 const {\n type,\n prompt,\n params,\n requestId,\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 // Always recreate agent before execution to ensure latest config is applied\n if (this.agentFactory) {\n console.log('Destroying old agent before execution...');\n try {\n if (this.agent && typeof this.agent.destroy === 'function') {\n await this.agent.destroy();\n }\n } catch (error) {\n console.warn('Failed to destroy old agent:', error);\n }\n\n console.log('Creating new agent with latest config...');\n try {\n this.agent = await this.agentFactory();\n console.log('Agent created successfully');\n } catch (error) {\n console.error('Failed to create 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 (\n deviceOptions &&\n this.agent.interface &&\n 'options' in this.agent.interface\n ) {\n this.agent.interface.options = {\n ...(this.agent.interface.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 this.agent.onDumpUpdate = (\n _dump: string,\n executionDump?: ExecutionDump,\n ) => {\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 // Get action space to check for dynamic actions\n const actionSpace = this.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(\n this.agent,\n type,\n actionSpace,\n value,\n {\n deepThink,\n screenshotIncluded,\n domIncluded,\n deviceOptions,\n },\n );\n } catch (error: unknown) {\n response.error = formatErrorMessage(error);\n }\n\n try {\n const dumpString = this.agent.dumpDataString();\n if (dumpString) {\n const groupedDump =\n GroupedActionDump.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 = this.agent.reportHTMLString() || null;\n\n this.agent.writeOutActionDumps();\n this.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 }\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 // 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 = this.agent.dumpDataString?.();\n if (dumpString) {\n const groupedDump =\n GroupedActionDump.fromSerializedString(dumpString);\n // Extract first execution from grouped dump\n dump = groupedDump.executions?.[0] || null;\n }\n\n reportHTML = this.agent.reportHTMLString?.() || null;\n } catch (error: unknown) {\n console.warn('Failed to get execution data before cancel:', error);\n }\n\n // Recreate/destroy agent to cancel the current task\n await this.recreateAgent();\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(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 // Check if page has screenshotBase64 method\n if (typeof this.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 this.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(500).json({\n error: `Failed to take screenshot: ${errorMessage}`,\n });\n }\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 type = this.agent.interface.interfaceType || 'Unknown';\n const description = this.agent.interface.describe?.() || undefined;\n\n res.json({\n type,\n 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.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 } 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\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 // Get scrcpy server port from global\n const scrcpyPort = (global as any).scrcpyServerPort || 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.agentFactory) {\n console.log('Initializing agent from factory function...');\n this.agent = await this.agentFactory();\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;\n this.server = this._app.listen(serverPort, () => {\n resolve(this);\n });\n });\n }\n\n /**\n * Close the server and clean up resources\n */\n async close(): Promise<void> {\n return new Promise((resolve, reject) => {\n if (this.server) {\n // Clean up the single agent\n try {\n this.agent.destroy();\n } catch (error) {\n console.warn('Failed to destroy agent:', error);\n }\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","__filename","fileURLToPath","__dirname","dirname","STATIC_PATH","join","errorHandler","err","req","res","next","console","errorMessage","Error","PlaygroundServer","express","_res","context","uuid","tmpFile","writeFileSync","error","contextFile","existsSync","readFileSync","requestId","executionDump","actionSpace","processedActionSpace","action","typedAction","processedSchema","e","actionName","type","prompt","params","deepThink","screenshotIncluded","domIncluded","deviceOptions","_dump","response","startTime","Date","value","executeAction","formatErrorMessage","dumpString","groupedDump","GroupedActionDump","timeCost","dump","reportHTML","_req","base64Screenshot","description","undefined","aiConfig","Object","overrideAIConfig","globalModelConfigManager","htmlPath","html","scrcpyPort","global","configScript","port","Promise","resolve","serverPort","reject","agent","staticPath","id","getTmpDir"],"mappings":"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"}
@@ -219,7 +219,11 @@ class RemoteExecutionAdapter extends external_base_js_namespaceObject.BasePlaygr
219
219
  aiConfig
220
220
  })
221
221
  });
222
- if (!response.ok) throw new Error(`Failed to override server config: ${response.statusText}`);
222
+ if (!response.ok) {
223
+ const body = await response.json().catch(()=>null);
224
+ const detail = body?.error || response.statusText;
225
+ throw new Error(detail);
226
+ }
223
227
  } catch (error) {
224
228
  console.error('Failed to override server config:', error);
225
229
  throw error;
@@ -1 +1 @@
1
- {"version":3,"file":"adapters/remote-execution.js","sources":["webpack/runtime/define_property_getters","webpack/runtime/has_own_property","webpack/runtime/make_namespace_object","../../../src/adapters/remote-execution.ts"],"sourcesContent":["__webpack_require__.d = (exports, definition) => {\n\tfor(var key in definition) {\n if(__webpack_require__.o(definition, key) && !__webpack_require__.o(exports, key)) {\n Object.defineProperty(exports, key, { enumerable: true, get: definition[key] });\n }\n }\n};","__webpack_require__.o = (obj, prop) => (Object.prototype.hasOwnProperty.call(obj, prop))","// define __esModule on exports\n__webpack_require__.r = (exports) => {\n\tif(typeof Symbol !== 'undefined' && Symbol.toStringTag) {\n\t\tObject.defineProperty(exports, Symbol.toStringTag, { value: 'Module' });\n\t}\n\tObject.defineProperty(exports, '__esModule', { value: true });\n};","import type { DeviceAction, ExecutionDump } from '@midscene/core';\nimport { parseStructuredParams } from '../common';\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: '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 throw new Error(\n `Failed to override server config: ${response.statusText}`,\n );\n }\n } catch (error) {\n console.error('Failed to override server config:', error);\n throw error;\n }\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"],"names":["__webpack_require__","definition","key","Object","obj","prop","Symbol","RemoteExecutionAdapter","BasePlaygroundAdapter","callback","undefined","value","action","needsStructuredParams","schema","shape","missingFields","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","requestId","encodeURIComponent","setInterval","progressData","clearInterval","serverUrl"],"mappings":"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"}
1
+ {"version":3,"file":"adapters/remote-execution.js","sources":["webpack/runtime/define_property_getters","webpack/runtime/has_own_property","webpack/runtime/make_namespace_object","../../../src/adapters/remote-execution.ts"],"sourcesContent":["__webpack_require__.d = (exports, definition) => {\n\tfor(var key in definition) {\n if(__webpack_require__.o(definition, key) && !__webpack_require__.o(exports, key)) {\n Object.defineProperty(exports, key, { enumerable: true, get: definition[key] });\n }\n }\n};","__webpack_require__.o = (obj, prop) => (Object.prototype.hasOwnProperty.call(obj, prop))","// define __esModule on exports\n__webpack_require__.r = (exports) => {\n\tif(typeof Symbol !== 'undefined' && Symbol.toStringTag) {\n\t\tObject.defineProperty(exports, Symbol.toStringTag, { value: 'Module' });\n\t}\n\tObject.defineProperty(exports, '__esModule', { value: true });\n};","import type { DeviceAction, ExecutionDump } from '@midscene/core';\nimport { parseStructuredParams } from '../common';\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: '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 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"],"names":["__webpack_require__","definition","key","Object","obj","prop","Symbol","RemoteExecutionAdapter","BasePlaygroundAdapter","callback","undefined","value","action","needsStructuredParams","schema","shape","missingFields","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","serverUrl"],"mappings":"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"}
@@ -360,10 +360,6 @@ class PlaygroundServer {
360
360
  });
361
361
  try {
362
362
  (0, env_namespaceObject.overrideAIConfig)(aiConfig);
363
- return res.json({
364
- status: 'ok',
365
- message: 'AI config updated. Agent will be recreated on next execution.'
366
- });
367
363
  } catch (error) {
368
364
  const errorMessage = error instanceof Error ? error.message : 'Unknown error';
369
365
  console.error(`Failed to update AI config: ${errorMessage}`);
@@ -371,6 +367,19 @@ class PlaygroundServer {
371
367
  error: `Failed to update AI config: ${errorMessage}`
372
368
  });
373
369
  }
370
+ try {
371
+ env_namespaceObject.globalModelConfigManager.getModelConfig('default');
372
+ } catch (error) {
373
+ const errorMessage = error instanceof Error ? error.message : 'Unknown error';
374
+ console.error(`AI config validation failed: ${errorMessage}`);
375
+ return res.status(400).json({
376
+ error: errorMessage
377
+ });
378
+ }
379
+ return res.json({
380
+ status: 'ok',
381
+ message: 'AI config updated. Agent will be recreated on next execution.'
382
+ });
374
383
  });
375
384
  }
376
385
  setupStaticRoutes() {