@midscene/playground 1.0.1-beta-20251209024153.0 → 1.0.1-beta-20251211095502.0

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.
Files changed (32) hide show
  1. package/dist/es/adapters/local-execution.mjs +53 -27
  2. package/dist/es/adapters/local-execution.mjs.map +1 -1
  3. package/dist/es/adapters/remote-execution.mjs +1 -31
  4. package/dist/es/adapters/remote-execution.mjs.map +1 -1
  5. package/dist/es/sdk/index.mjs +13 -19
  6. package/dist/es/sdk/index.mjs.map +1 -1
  7. package/dist/es/server.mjs +27 -9
  8. package/dist/es/server.mjs.map +1 -1
  9. package/dist/lib/adapters/local-execution.js +53 -27
  10. package/dist/lib/adapters/local-execution.js.map +1 -1
  11. package/dist/lib/adapters/remote-execution.js +1 -31
  12. package/dist/lib/adapters/remote-execution.js.map +1 -1
  13. package/dist/lib/sdk/index.js +13 -19
  14. package/dist/lib/sdk/index.js.map +1 -1
  15. package/dist/lib/server.js +27 -9
  16. package/dist/lib/server.js.map +1 -1
  17. package/dist/types/adapters/local-execution.d.ts +18 -8
  18. package/dist/types/adapters/remote-execution.d.ts +0 -5
  19. package/dist/types/sdk/index.d.ts +6 -6
  20. package/dist/types/server.d.ts +2 -1
  21. package/dist/types/types.d.ts +18 -0
  22. package/package.json +3 -3
  23. package/static/index.html +1 -1
  24. package/static/static/css/index.3d0b5a80.css +2 -0
  25. package/static/static/css/index.3d0b5a80.css.map +1 -0
  26. package/static/static/js/index.0f473725.js +10 -0
  27. package/static/static/js/index.0f473725.js.map +1 -0
  28. package/static/static/css/index.987d3a64.css +0 -2
  29. package/static/static/css/index.987d3a64.css.map +0 -1
  30. package/static/static/js/index.2fce1bca.js +0 -10
  31. package/static/static/js/index.2fce1bca.js.map +0 -1
  32. /package/static/static/js/{index.2fce1bca.js.LICENSE.txt → index.0f473725.js.LICENSE.txt} +0 -0
@@ -16,12 +16,9 @@ class LocalExecutionAdapter extends BasePlaygroundAdapter {
16
16
  get id() {
17
17
  return this._id;
18
18
  }
19
- setProgressCallback(callback) {
20
- this.progressCallback = void 0;
21
- this.progressCallback = callback;
22
- }
23
- cleanup(requestId) {
24
- delete this.taskProgressTips[requestId];
19
+ onDumpUpdate(callback) {
20
+ this.dumpUpdateCallback = void 0;
21
+ this.dumpUpdateCallback = callback;
25
22
  }
26
23
  async parseStructuredParams(action, params, options) {
27
24
  return await parseStructuredParams(action, params, options);
@@ -49,51 +46,61 @@ class LocalExecutionAdapter extends BasePlaygroundAdapter {
49
46
  async overrideConfig(aiConfig) {
50
47
  overrideAIConfig(aiConfig);
51
48
  }
49
+ async detachDebuggerSafely() {
50
+ try {
51
+ const page = this.agent?.interface;
52
+ await page?.detachDebugger?.();
53
+ } catch (error) {
54
+ console.warn('Failed to detach debugger:', error);
55
+ }
56
+ }
52
57
  async executeAction(actionType, value, options) {
53
58
  const actionSpace = await this.getActionSpace();
54
- let originalOnTaskStartTip;
59
+ let removeListener;
60
+ try {
61
+ this.agent.resetDump?.();
62
+ } catch (error) {
63
+ console.warn('Failed to reset dump before execution:', error);
64
+ }
55
65
  if (options.requestId && this.agent) {
56
66
  this.currentRequestId = options.requestId;
57
- originalOnTaskStartTip = this.agent.onTaskStartTip;
58
- this.agent.onTaskStartTip = (tip)=>{
67
+ removeListener = this.agent.addDumpUpdateListener((dump, executionDump)=>{
59
68
  if (this.currentRequestId !== options.requestId) return;
60
- this.taskProgressTips[options.requestId] = tip;
61
- if (this.progressCallback) this.progressCallback(tip);
62
- if ('function' == typeof originalOnTaskStartTip) originalOnTaskStartTip(tip);
63
- };
69
+ if (this.dumpUpdateCallback) this.dumpUpdateCallback(dump, executionDump);
70
+ });
64
71
  }
65
72
  try {
66
- const result = await executeAction(this.agent, actionType, actionSpace, value, options);
73
+ let result = null;
74
+ let executionError = null;
75
+ try {
76
+ result = await executeAction(this.agent, actionType, actionSpace, value, options);
77
+ } catch (error) {
78
+ executionError = error;
79
+ }
67
80
  const response = {
68
81
  result,
69
82
  dump: null,
70
83
  reportHTML: null,
71
- error: null
84
+ error: executionError ? executionError instanceof Error ? executionError.message : String(executionError) : null
72
85
  };
73
86
  try {
74
87
  if (this.agent.dumpDataString) {
75
88
  const dumpString = this.agent.dumpDataString();
76
- if (dumpString) response.dump = JSON.parse(dumpString);
89
+ if (dumpString) {
90
+ const groupedDump = JSON.parse(dumpString);
91
+ response.dump = groupedDump.executions?.[0] || null;
92
+ }
77
93
  }
78
94
  if (this.agent.reportHTMLString) response.reportHTML = this.agent.reportHTMLString() || null;
79
95
  if (this.agent.writeOutActionDumps) this.agent.writeOutActionDumps();
80
96
  } catch (error) {
81
97
  console.error('Failed to get dump/reportHTML from agent:', error);
82
98
  }
83
- this.agent.resetDump();
84
99
  return response;
85
100
  } finally{
86
- if (options.requestId) {
87
- this.cleanup(options.requestId);
88
- if (this.agent) this.agent.onTaskStartTip = originalOnTaskStartTip;
89
- }
101
+ if (removeListener) removeListener();
90
102
  }
91
103
  }
92
- async getTaskProgress(requestId) {
93
- return {
94
- tip: this.taskProgressTips[requestId] || void 0
95
- };
96
- }
97
104
  async cancelTask(_requestId) {
98
105
  if (!this.agent) return {
99
106
  error: 'No active agent found for this requestId'
@@ -111,6 +118,25 @@ class LocalExecutionAdapter extends BasePlaygroundAdapter {
111
118
  };
112
119
  }
113
120
  }
121
+ async getCurrentExecutionData() {
122
+ const response = {
123
+ dump: null,
124
+ reportHTML: null
125
+ };
126
+ try {
127
+ if (this.agent.dumpDataString) {
128
+ const dumpString = this.agent.dumpDataString();
129
+ if (dumpString) {
130
+ const groupedDump = JSON.parse(dumpString);
131
+ response.dump = groupedDump.executions?.[0] || null;
132
+ }
133
+ }
134
+ if (this.agent.reportHTMLString) response.reportHTML = this.agent.reportHTMLString() || null;
135
+ } catch (error) {
136
+ console.error('Failed to get current execution data:', error);
137
+ }
138
+ return response;
139
+ }
114
140
  async getInterfaceInfo() {
115
141
  if (!this.agent?.interface) return null;
116
142
  try {
@@ -126,7 +152,7 @@ class LocalExecutionAdapter extends BasePlaygroundAdapter {
126
152
  }
127
153
  }
128
154
  constructor(agent){
129
- super(), _define_property(this, "agent", void 0), _define_property(this, "taskProgressTips", {}), _define_property(this, "progressCallback", void 0), _define_property(this, "_id", void 0), _define_property(this, "currentRequestId", void 0);
155
+ super(), _define_property(this, "agent", void 0), _define_property(this, "dumpUpdateCallback", void 0), _define_property(this, "_id", void 0), _define_property(this, "currentRequestId", void 0);
130
156
  this.agent = agent;
131
157
  this._id = uuid();
132
158
  }
@@ -1 +1 @@
1
- {"version":3,"file":"adapters/local-execution.mjs","sources":["../../../src/adapters/local-execution.ts"],"sourcesContent":["import type { DeviceAction } from '@midscene/core';\nimport { overrideAIConfig } from '@midscene/shared/env';\nimport { uuid } from '@midscene/shared/utils';\nimport { executeAction, parseStructuredParams } from '../common';\nimport type { ExecutionOptions, FormValue, PlaygroundAgent } from '../types';\nimport { BasePlaygroundAdapter } from './base';\n\nexport class LocalExecutionAdapter extends BasePlaygroundAdapter {\n private agent: PlaygroundAgent;\n private taskProgressTips: Record<string, string> = {};\n private progressCallback?: (tip: string) => void;\n private readonly _id: string; // Unique identifier for this local adapter instance\n private currentRequestId?: string; // Track current request to prevent stale callbacks\n\n constructor(agent: PlaygroundAgent) {\n super();\n this.agent = agent;\n this._id = uuid(); // Generate unique ID for local adapter\n }\n\n // Get adapter ID\n get id(): string {\n return this._id;\n }\n\n setProgressCallback(callback: (tip: string) => void): void {\n // Clear any existing callback before setting new one\n this.progressCallback = undefined;\n // Set the new callback\n this.progressCallback = callback;\n }\n\n private cleanup(requestId: string): void {\n delete this.taskProgressTips[requestId];\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 errorMessage = error?.message || '';\n if (errorMessage.includes('of different extension')) {\n return 'Conflicting extension detected. Please disable the suspicious plugins and refresh the page. Guide: https://midscenejs.com/quick-experience.html#faq';\n }\n return this.formatBasicErrorMessage(error);\n }\n\n // Local execution - use base implementation\n // (inherits default executeAction from BasePlaygroundAdapter)\n\n // Local execution gets actionSpace from internal agent (parameter is for backward compatibility)\n async getActionSpace(context?: unknown): Promise<DeviceAction<unknown>[]> {\n // Priority 1: Use agent's getActionSpace method\n if (this.agent?.getActionSpace) {\n return await this.agent.getActionSpace();\n }\n\n // Priority 2: Use agent's interface.actionSpace method\n if (\n this.agent &&\n 'interface' in this.agent &&\n typeof this.agent.interface === 'object'\n ) {\n const page = this.agent.interface as {\n actionSpace?: () => DeviceAction<unknown>[];\n };\n if (page?.actionSpace) {\n return page.actionSpace();\n }\n }\n\n // Priority 3: Fallback to context parameter (for backward compatibility with tests)\n if (context && typeof context === 'object' && 'actionSpace' in context) {\n const contextPage = context as {\n actionSpace: () => DeviceAction<unknown>[];\n };\n return contextPage.actionSpace();\n }\n\n return [];\n }\n\n // Local execution doesn't use a server, so always return true\n async checkStatus(): Promise<boolean> {\n return true;\n }\n\n async overrideConfig(aiConfig: Record<string, unknown>): Promise<void> {\n // For local execution, use the shared env override function\n overrideAIConfig(aiConfig);\n }\n\n async executeAction(\n actionType: string,\n value: FormValue,\n options: ExecutionOptions,\n ): Promise<unknown> {\n // Get actionSpace using our simplified getActionSpace method\n const actionSpace = await this.getActionSpace();\n let originalOnTaskStartTip: ((tip: string) => void) | undefined;\n\n // Setup progress tracking if requestId is provided\n if (options.requestId && this.agent) {\n // Track current request ID to prevent stale callbacks\n this.currentRequestId = options.requestId;\n originalOnTaskStartTip = this.agent.onTaskStartTip;\n\n // Set up a fresh callback\n this.agent.onTaskStartTip = (tip: string) => {\n // Only process if this is still the current request\n if (this.currentRequestId !== options.requestId) {\n return;\n }\n\n // Store tip for our progress tracking\n this.taskProgressTips[options.requestId!] = tip;\n\n // Call the direct progress callback set via setProgressCallback\n if (this.progressCallback) {\n this.progressCallback(tip);\n }\n\n if (typeof originalOnTaskStartTip === 'function') {\n originalOnTaskStartTip(tip);\n }\n };\n }\n\n try {\n // Call the base implementation with the original signature\n const result = await executeAction(\n this.agent,\n actionType,\n actionSpace,\n value,\n options,\n );\n\n // For local execution, we need to package the result with dump and reportHTML\n // similar to how the server does it\n const response = {\n result,\n dump: null as unknown,\n reportHTML: null as string | null,\n error: null as string | null,\n };\n\n try {\n // Get dump and reportHTML from agent like the server does\n if (this.agent.dumpDataString) {\n const dumpString = this.agent.dumpDataString();\n if (dumpString) {\n response.dump = JSON.parse(dumpString);\n }\n }\n\n if (this.agent.reportHTMLString) {\n response.reportHTML = this.agent.reportHTMLString() || null;\n }\n\n // Write out action dumps\n if (this.agent.writeOutActionDumps) {\n this.agent.writeOutActionDumps();\n }\n } catch (error: unknown) {\n console.error('Failed to get dump/reportHTML from agent:', error);\n }\n\n this.agent.resetDump();\n\n return response;\n } finally {\n // Always clean up progress tracking to prevent memory leaks\n if (options.requestId) {\n this.cleanup(options.requestId);\n // Clear the agent callback to prevent accumulation\n if (this.agent) {\n this.agent.onTaskStartTip = originalOnTaskStartTip;\n }\n }\n }\n }\n\n async getTaskProgress(requestId: string): Promise<{ tip?: string }> {\n // Return the stored tip for this requestId\n return { tip: this.taskProgressTips[requestId] || undefined };\n }\n\n // Local execution task cancellation - minimal implementation\n async cancelTask(\n _requestId: string,\n ): Promise<{ error?: string; success?: boolean }> {\n if (!this.agent) {\n return { error: 'No active agent found for this requestId' };\n }\n\n try {\n await this.agent.destroy?.();\n return { success: true };\n } catch (error: unknown) {\n const errorMessage =\n error instanceof Error ? error.message : 'Unknown error';\n console.error(`Failed to cancel agent: ${errorMessage}`);\n return { error: `Failed to cancel: ${errorMessage}` };\n }\n }\n\n // Get interface information from the agent\n async getInterfaceInfo(): Promise<{\n type: string;\n description?: string;\n } | null> {\n if (!this.agent?.interface) {\n return null;\n }\n\n try {\n const type = this.agent.interface.interfaceType || 'Unknown';\n const description = this.agent.interface.describe?.() || undefined;\n\n return {\n type,\n description,\n };\n } catch (error: unknown) {\n console.error('Failed to get interface info:', error);\n return null;\n }\n }\n}\n"],"names":["LocalExecutionAdapter","BasePlaygroundAdapter","callback","undefined","requestId","action","params","options","parseStructuredParams","error","errorMessage","context","page","contextPage","aiConfig","overrideAIConfig","actionType","value","actionSpace","originalOnTaskStartTip","tip","result","executeAction","response","dumpString","JSON","console","_requestId","Error","type","description","agent","uuid"],"mappings":"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"}
1
+ {"version":3,"file":"adapters/local-execution.mjs","sources":["../../../src/adapters/local-execution.ts"],"sourcesContent":["import type { DeviceAction, ExecutionDump } from '@midscene/core';\nimport { overrideAIConfig } from '@midscene/shared/env';\nimport { uuid } from '@midscene/shared/utils';\nimport { executeAction, parseStructuredParams } from '../common';\nimport type { ExecutionOptions, FormValue, PlaygroundAgent } from '../types';\nimport { BasePlaygroundAdapter } from './base';\n\nexport class LocalExecutionAdapter extends BasePlaygroundAdapter {\n private agent: PlaygroundAgent;\n private dumpUpdateCallback?: (\n dump: string,\n executionDump?: ExecutionDump,\n ) => void;\n private readonly _id: string; // Unique identifier for this local adapter instance\n private currentRequestId?: string; // Track current request to prevent stale callbacks\n\n constructor(agent: PlaygroundAgent) {\n super();\n this.agent = agent;\n this._id = uuid(); // Generate unique ID for local adapter\n }\n\n // Get adapter ID\n get id(): string {\n return this._id;\n }\n\n onDumpUpdate(\n callback: (dump: string, executionDump?: ExecutionDump) => void,\n ): void {\n // Clear any existing callback before setting new one\n this.dumpUpdateCallback = undefined;\n // Set the new callback\n this.dumpUpdateCallback = callback;\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 errorMessage = error?.message || '';\n if (errorMessage.includes('of different extension')) {\n return 'Conflicting extension detected. Please disable the suspicious plugins and refresh the page. Guide: https://midscenejs.com/quick-experience.html#faq';\n }\n return this.formatBasicErrorMessage(error);\n }\n\n // Local execution - use base implementation\n // (inherits default executeAction from BasePlaygroundAdapter)\n\n // Local execution gets actionSpace from internal agent (parameter is for backward compatibility)\n async getActionSpace(context?: unknown): Promise<DeviceAction<unknown>[]> {\n // Priority 1: Use agent's getActionSpace method\n if (this.agent?.getActionSpace) {\n return await this.agent.getActionSpace();\n }\n\n // Priority 2: Use agent's interface.actionSpace method\n if (\n this.agent &&\n 'interface' in this.agent &&\n typeof this.agent.interface === 'object'\n ) {\n const page = this.agent.interface as {\n actionSpace?: () => DeviceAction<unknown>[];\n };\n if (page?.actionSpace) {\n return page.actionSpace();\n }\n }\n\n // Priority 3: Fallback to context parameter (for backward compatibility with tests)\n if (context && typeof context === 'object' && 'actionSpace' in context) {\n const contextPage = context as {\n actionSpace: () => DeviceAction<unknown>[];\n };\n return contextPage.actionSpace();\n }\n\n return [];\n }\n\n // Local execution doesn't use a server, so always return true\n async checkStatus(): Promise<boolean> {\n return true;\n }\n\n async overrideConfig(aiConfig: Record<string, unknown>): Promise<void> {\n // For local execution, use the shared env override function\n overrideAIConfig(aiConfig);\n }\n\n /**\n * Safely detaches the Chrome debugger without destroying the agent.\n * This removes the \"Debugger attached\" banner from the browser window\n * while keeping the agent instance intact for potential reuse.\n * Called on errors to improve user experience by cleaning up the UI.\n */\n private async detachDebuggerSafely() {\n try {\n const page = this.agent?.interface as\n | { detachDebugger?: () => Promise<void> }\n | undefined;\n await page?.detachDebugger?.();\n } catch (error) {\n console.warn('Failed to detach debugger:', error);\n }\n }\n\n async executeAction(\n actionType: string,\n value: FormValue,\n options: ExecutionOptions,\n ): Promise<unknown> {\n // Get actionSpace using our simplified getActionSpace method\n const actionSpace = await this.getActionSpace();\n let removeListener: (() => void) | undefined;\n\n // Reset dump at the start of execution to ensure clean state\n try {\n this.agent.resetDump?.();\n } catch (error: unknown) {\n console.warn('Failed to reset dump before execution:', error);\n }\n\n // Setup dump update tracking if requestId is provided\n if (options.requestId && this.agent) {\n // Track current request ID to prevent stale callbacks\n this.currentRequestId = options.requestId;\n\n // Add listener and save remove function\n removeListener = this.agent.addDumpUpdateListener(\n (dump: string, executionDump?: ExecutionDump) => {\n // Only process if this is still the current request\n if (this.currentRequestId !== options.requestId) {\n return;\n }\n\n // Forward to external callback\n if (this.dumpUpdateCallback) {\n this.dumpUpdateCallback(dump, executionDump);\n }\n },\n );\n }\n\n try {\n let result = null;\n let executionError = null;\n\n try {\n // Call the base implementation with the original signature\n result = await executeAction(\n this.agent,\n actionType,\n actionSpace,\n value,\n options,\n );\n } catch (error: unknown) {\n // Capture error but don't throw yet - we need to get dump/reportHTML first\n executionError = error;\n }\n\n // Always construct response with dump and reportHTML, regardless of success/failure\n const response = {\n result,\n dump: null as unknown,\n reportHTML: null as string | null,\n error: executionError\n ? executionError instanceof Error\n ? executionError.message\n : String(executionError)\n : null,\n };\n\n try {\n if (this.agent.dumpDataString) {\n const dumpString = this.agent.dumpDataString();\n if (dumpString) {\n const groupedDump = JSON.parse(dumpString);\n response.dump = groupedDump.executions?.[0] || null;\n }\n }\n\n if (this.agent.reportHTMLString) {\n response.reportHTML = this.agent.reportHTMLString() || null;\n }\n\n // Write out action dumps\n if (this.agent.writeOutActionDumps) {\n this.agent.writeOutActionDumps();\n }\n } catch (error: unknown) {\n console.error('Failed to get dump/reportHTML from agent:', error);\n }\n\n // Don't throw the error - return it in response so caller can access dump/reportHTML\n // The caller (usePlaygroundExecution) will check response.error to determine success\n return response;\n } finally {\n // Remove listener to prevent accumulation\n if (removeListener) {\n removeListener();\n }\n }\n }\n\n // Local execution task cancellation - minimal implementation\n async cancelTask(\n _requestId: string,\n ): Promise<{ error?: string; success?: boolean }> {\n if (!this.agent) {\n return { error: 'No active agent found for this requestId' };\n }\n\n try {\n await this.agent.destroy?.();\n return { success: true };\n } catch (error: unknown) {\n const errorMessage =\n error instanceof Error ? error.message : 'Unknown error';\n console.error(`Failed to cancel agent: ${errorMessage}`);\n return { error: `Failed to cancel: ${errorMessage}` };\n }\n }\n\n /**\n * Get current execution data without resetting\n * This allows retrieving dump and report when execution is stopped\n */\n async getCurrentExecutionData(): Promise<{\n dump: ExecutionDump | null;\n reportHTML: string | null;\n }> {\n const response = {\n dump: null as ExecutionDump | null,\n reportHTML: null as string | null,\n };\n\n try {\n // Get dump data\n if (this.agent.dumpDataString) {\n const dumpString = this.agent.dumpDataString();\n if (dumpString) {\n const groupedDump = JSON.parse(dumpString);\n response.dump = groupedDump.executions?.[0] || null;\n }\n }\n\n // Get report HTML\n if (this.agent.reportHTMLString) {\n response.reportHTML = this.agent.reportHTMLString() || null;\n }\n } catch (error: unknown) {\n console.error('Failed to get current execution data:', error);\n }\n\n return response;\n }\n\n // Get interface information from the agent\n async getInterfaceInfo(): Promise<{\n type: string;\n description?: string;\n } | null> {\n if (!this.agent?.interface) {\n return null;\n }\n\n try {\n const type = this.agent.interface.interfaceType || 'Unknown';\n const description = this.agent.interface.describe?.() || undefined;\n\n return {\n type,\n description,\n };\n } catch (error: unknown) {\n console.error('Failed to get interface info:', error);\n return null;\n }\n }\n}\n"],"names":["LocalExecutionAdapter","BasePlaygroundAdapter","callback","undefined","action","params","options","parseStructuredParams","error","errorMessage","context","page","contextPage","aiConfig","overrideAIConfig","console","actionType","value","actionSpace","removeListener","dump","executionDump","result","executionError","executeAction","response","Error","String","dumpString","groupedDump","JSON","_requestId","type","description","agent","uuid"],"mappings":"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"}
@@ -75,7 +75,6 @@ class RemoteExecutionAdapter extends BasePlaygroundAdapter {
75
75
  ...this.buildOptionalPayloadParams(options, value)
76
76
  };
77
77
  if (options.context) payload.context = options.context;
78
- if (options.requestId && this.progressCallback) this.startProgressPolling(options.requestId, this.progressCallback);
79
78
  try {
80
79
  const response = await fetch(`${this.serverUrl}/execute`, {
81
80
  method: 'POST',
@@ -89,10 +88,8 @@ class RemoteExecutionAdapter extends BasePlaygroundAdapter {
89
88
  throw new Error(`Server request failed (${response.status}): ${errorText}`);
90
89
  }
91
90
  const result = await response.json();
92
- if (options.requestId) this.stopProgressPolling(options.requestId);
93
91
  return result;
94
92
  } catch (error) {
95
- if (options.requestId) this.stopProgressPolling(options.requestId);
96
93
  console.error('Execute via server failed:', error);
97
94
  throw error;
98
95
  }
@@ -220,7 +217,6 @@ class RemoteExecutionAdapter extends BasePlaygroundAdapter {
220
217
  }
221
218
  }
222
219
  async cancelTask(requestId) {
223
- this.stopProgressPolling(requestId);
224
220
  if (!this.serverUrl) return {
225
221
  error: 'No server URL configured'
226
222
  };
@@ -246,32 +242,6 @@ class RemoteExecutionAdapter extends BasePlaygroundAdapter {
246
242
  };
247
243
  }
248
244
  }
249
- setProgressCallback(callback) {
250
- this.progressCallback = callback;
251
- }
252
- startProgressPolling(requestId, callback) {
253
- if (this.progressPolling.has(requestId)) return;
254
- let lastTip = '';
255
- const interval = setInterval(async ()=>{
256
- try {
257
- const progress = await this.getTaskProgress(requestId);
258
- if (progress?.tip?.trim?.() && progress.tip !== lastTip) {
259
- lastTip = progress.tip;
260
- callback(progress.tip);
261
- }
262
- } catch (error) {
263
- console.debug('Progress polling error:', error);
264
- }
265
- }, 500);
266
- this.progressPolling.set(requestId, interval);
267
- }
268
- stopProgressPolling(requestId) {
269
- const interval = this.progressPolling.get(requestId);
270
- if (interval) {
271
- clearInterval(interval);
272
- this.progressPolling.delete(requestId);
273
- }
274
- }
275
245
  async getScreenshot() {
276
246
  if (!this.serverUrl) return null;
277
247
  try {
@@ -301,7 +271,7 @@ class RemoteExecutionAdapter extends BasePlaygroundAdapter {
301
271
  }
302
272
  }
303
273
  constructor(serverUrl){
304
- super(), _define_property(this, "serverUrl", void 0), _define_property(this, "progressPolling", new Map()), _define_property(this, "progressCallback", void 0), _define_property(this, "_id", void 0);
274
+ super(), _define_property(this, "serverUrl", void 0), _define_property(this, "_id", void 0);
305
275
  this.serverUrl = serverUrl;
306
276
  }
307
277
  }
@@ -1 +1 @@
1
- {"version":3,"file":"adapters/remote-execution.mjs","sources":["../../../src/adapters/remote-execution.ts"],"sourcesContent":["import type { DeviceAction } 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 progressPolling = new Map<string, NodeJS.Timeout>();\n private progressCallback?: (tip: string) => void;\n private _id?: string;\n\n constructor(serverUrl: string) {\n super();\n this.serverUrl = serverUrl;\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 progress polling if callback is set and requestId exists\n if (options.requestId && this.progressCallback) {\n this.startProgressPolling(options.requestId, this.progressCallback);\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 // Stop progress polling when execution completes\n if (options.requestId) {\n this.stopProgressPolling(options.requestId);\n }\n\n return result;\n } catch (error) {\n // Stop progress polling on error\n if (options.requestId) {\n this.stopProgressPolling(options.requestId);\n }\n console.error('Execute via server failed:', error);\n throw error;\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<{ tip?: string }> {\n if (!this.serverUrl) {\n return { tip: undefined };\n }\n\n if (!requestId?.trim()) {\n console.warn('Invalid requestId provided for task progress');\n return { tip: undefined };\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 { tip: undefined };\n }\n\n return await response.json();\n } catch (error) {\n console.error('Failed to poll task progress:', error);\n return { tip: undefined };\n }\n }\n\n // Cancel task\n async cancelTask(\n requestId: string,\n ): Promise<{ error?: string; success?: boolean }> {\n // Stop progress polling\n this.stopProgressPolling(requestId);\n\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 // Progress callback management\n setProgressCallback(callback: (tip: string) => void): void {\n this.progressCallback = callback;\n }\n\n // Start progress polling\n private startProgressPolling(\n requestId: string,\n callback: (tip: string) => void,\n ): void {\n // Don't start multiple polling for the same request\n if (this.progressPolling.has(requestId)) {\n return;\n }\n\n let lastTip = '';\n const interval = setInterval(async () => {\n try {\n const progress = await this.getTaskProgress(requestId);\n if (progress?.tip?.trim?.() && progress.tip !== lastTip) {\n lastTip = progress.tip;\n callback(progress.tip);\n }\n } catch (error) {\n // Silently ignore progress polling errors to avoid spam\n console.debug('Progress polling error:', error);\n }\n }, 500); // Poll every 500ms\n\n this.progressPolling.set(requestId, interval);\n }\n\n // Stop progress polling\n private stopProgressPolling(requestId: string): void {\n const interval = this.progressPolling.get(requestId);\n if (interval) {\n clearInterval(interval);\n this.progressPolling.delete(requestId);\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","value","action","needsStructuredParams","schema","shape","missingFields","Object","key","fieldDef","isOptional","undefined","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","callback","lastTip","interval","setInterval","progress","clearInterval","serverUrl","Map"],"mappings":"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"}
1
+ {"version":3,"file":"adapters/remote-execution.mjs","sources":["../../../src/adapters/remote-execution.ts"],"sourcesContent":["import type { DeviceAction } 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\n constructor(serverUrl: string) {\n super();\n this.serverUrl = serverUrl;\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 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 }\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<{ tip?: string }> {\n if (!this.serverUrl) {\n return { tip: undefined };\n }\n\n if (!requestId?.trim()) {\n console.warn('Invalid requestId provided for task progress');\n return { tip: undefined };\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 { tip: undefined };\n }\n\n return await response.json();\n } catch (error) {\n console.error('Failed to poll task progress:', error);\n return { tip: 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","value","action","needsStructuredParams","schema","shape","missingFields","Object","key","fieldDef","isOptional","undefined","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","serverUrl"],"mappings":"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"}
@@ -28,7 +28,6 @@ class PlaygroundSDK {
28
28
  }
29
29
  async executeAction(actionType, value, options) {
30
30
  const result = await this.adapter.executeAction(actionType, value, options);
31
- if (options.requestId) this.stopProgressPolling(options.requestId);
32
31
  return result;
33
32
  }
34
33
  async getActionSpace(context) {
@@ -54,35 +53,26 @@ class PlaygroundSDK {
54
53
  async overrideConfig(aiConfig) {
55
54
  if (this.adapter instanceof RemoteExecutionAdapter) return this.adapter.overrideConfig(aiConfig);
56
55
  }
57
- async getTaskProgress(requestId) {
58
- if (this.adapter instanceof RemoteExecutionAdapter) return this.adapter.getTaskProgress(requestId);
59
- if (this.adapter instanceof LocalExecutionAdapter) return this.adapter.getTaskProgress(requestId);
60
- return {
61
- tip: void 0
62
- };
63
- }
64
56
  async cancelTask(requestId) {
65
- this.stopProgressPolling(requestId);
66
57
  if (this.adapter instanceof RemoteExecutionAdapter) return this.adapter.cancelTask(requestId);
67
58
  return {
68
59
  error: 'Cancel task not supported in local execution mode'
69
60
  };
70
61
  }
71
- onProgressUpdate(callback) {
72
- if (this.adapter instanceof RemoteExecutionAdapter) this.adapter.setProgressCallback(callback);
73
- else if (this.adapter instanceof LocalExecutionAdapter) this.adapter.setProgressCallback(callback);
74
- }
75
- startProgressPolling(requestId) {
76
- console.warn('startProgressPolling is deprecated - polling is now automatic');
77
- }
78
- stopProgressPolling(requestId) {
79
- console.warn('stopProgressPolling is deprecated - polling cleanup is now automatic');
62
+ onDumpUpdate(callback) {
63
+ if (this.adapter instanceof LocalExecutionAdapter) this.adapter.onDumpUpdate(callback);
80
64
  }
81
65
  async cancelExecution(requestId) {
82
- this.stopProgressPolling(requestId);
83
66
  if (this.adapter instanceof RemoteExecutionAdapter) await this.adapter.cancelTask(requestId);
84
67
  else if (this.adapter instanceof LocalExecutionAdapter) console.warn('Local execution cancellation not fully implemented');
85
68
  }
69
+ async getCurrentExecutionData() {
70
+ if (this.adapter instanceof LocalExecutionAdapter && this.adapter.getCurrentExecutionData) return await this.adapter.getCurrentExecutionData();
71
+ return {
72
+ dump: null,
73
+ reportHTML: null
74
+ };
75
+ }
86
76
  async getScreenshot() {
87
77
  if (this.adapter instanceof RemoteExecutionAdapter) return this.adapter.getScreenshot();
88
78
  return null;
@@ -92,6 +82,10 @@ class PlaygroundSDK {
92
82
  if (this.adapter instanceof RemoteExecutionAdapter) return this.adapter.getInterfaceInfo();
93
83
  return null;
94
84
  }
85
+ getServiceMode() {
86
+ if (this.adapter instanceof LocalExecutionAdapter) return 'In-Browser-Extension';
87
+ return 'Server';
88
+ }
95
89
  constructor(config){
96
90
  _define_property(this, "adapter", void 0);
97
91
  this.adapter = this.createAdapter(config.type, config.serverUrl, config.agent);
@@ -1 +1 @@
1
- {"version":3,"file":"sdk/index.mjs","sources":["../../../src/sdk/index.ts"],"sourcesContent":["import type { DeviceAction } from '@midscene/core';\nimport { PLAYGROUND_SERVER_PORT } from '@midscene/shared/constants';\nimport type { BasePlaygroundAdapter } from '../adapters/base';\nimport { LocalExecutionAdapter } from '../adapters/local-execution';\nimport { RemoteExecutionAdapter } from '../adapters/remote-execution';\nimport type {\n ExecutionOptions,\n FormValue,\n PlaygroundAgent,\n PlaygroundConfig,\n ValidationResult,\n} from '../types';\n\nexport class PlaygroundSDK {\n private adapter: BasePlaygroundAdapter;\n\n constructor(config: PlaygroundConfig) {\n this.adapter = this.createAdapter(\n config.type,\n config.serverUrl,\n config.agent,\n );\n }\n\n private createAdapter(\n type: string,\n serverUrl?: string,\n agent?: PlaygroundAgent,\n ): BasePlaygroundAdapter {\n switch (type) {\n case 'local-execution':\n if (!agent) {\n throw new Error('Agent is required for local execution');\n }\n return new LocalExecutionAdapter(agent);\n case 'remote-execution': {\n // Use provided serverUrl first, then fallback to localhost if current page origin is file:// or default\n const finalServerUrl =\n serverUrl ||\n (typeof window !== 'undefined' &&\n window.location.protocol.includes('http')\n ? window.location.origin\n : `http://localhost:${PLAYGROUND_SERVER_PORT}`);\n\n return new RemoteExecutionAdapter(finalServerUrl);\n }\n default:\n throw new Error(`Unsupported execution type: ${type}`);\n }\n }\n\n async executeAction(\n actionType: string,\n value: FormValue,\n options: ExecutionOptions,\n ): Promise<unknown> {\n const result = await this.adapter.executeAction(actionType, value, options);\n\n // Stop any active polling for this request after execution completes\n if (options.requestId) {\n this.stopProgressPolling(options.requestId);\n }\n\n return result;\n }\n\n async getActionSpace(context?: unknown): Promise<DeviceAction<unknown>[]> {\n // Both adapters now accept context parameter\n // Local will prioritize internal agent, Remote will use server + fallback\n return this.adapter.getActionSpace(context);\n }\n\n validateStructuredParams(\n value: FormValue,\n action: DeviceAction<unknown> | undefined,\n ): ValidationResult {\n return this.adapter.validateParams(value, action);\n }\n\n formatErrorMessage(error: any): string {\n return this.adapter.formatErrorMessage(error);\n }\n\n createDisplayContent(\n value: FormValue,\n needsStructuredParams: boolean,\n action: DeviceAction<unknown> | undefined,\n ): string {\n return this.adapter.createDisplayContent(\n value,\n needsStructuredParams,\n action,\n );\n }\n\n // Get adapter ID (works for both remote and local execution)\n get id(): string | undefined {\n if (this.adapter instanceof RemoteExecutionAdapter) {\n return this.adapter.id;\n }\n if (this.adapter instanceof LocalExecutionAdapter) {\n return this.adapter.id;\n }\n return undefined;\n }\n\n // Server communication methods (for remote execution)\n async checkStatus(): Promise<boolean> {\n if (this.adapter instanceof RemoteExecutionAdapter) {\n return this.adapter.checkStatus();\n }\n return true; // For local execution, always return true\n }\n\n async overrideConfig(aiConfig: any): Promise<void> {\n if (this.adapter instanceof RemoteExecutionAdapter) {\n return this.adapter.overrideConfig(aiConfig);\n }\n // For local execution, this is a no-op\n }\n\n async getTaskProgress(requestId: string): Promise<{ tip?: string }> {\n if (this.adapter instanceof RemoteExecutionAdapter) {\n return this.adapter.getTaskProgress(requestId);\n }\n if (this.adapter instanceof LocalExecutionAdapter) {\n return this.adapter.getTaskProgress(requestId);\n }\n return { tip: undefined }; // Fallback\n }\n\n // Cancel task (for remote execution)\n async cancelTask(requestId: string): Promise<any> {\n // Stop progress polling for this request\n this.stopProgressPolling(requestId);\n\n if (this.adapter instanceof RemoteExecutionAdapter) {\n return this.adapter.cancelTask(requestId);\n }\n return { error: 'Cancel task not supported in local execution mode' };\n }\n\n // Progress callback management\n onProgressUpdate(callback: (tip: string) => void): void {\n // Pass the callback to the adapter if it supports it\n if (this.adapter instanceof RemoteExecutionAdapter) {\n this.adapter.setProgressCallback(callback);\n } else if (this.adapter instanceof LocalExecutionAdapter) {\n this.adapter.setProgressCallback(callback);\n }\n }\n\n // Start progress polling for remote execution (deprecated - now handled by adapter)\n startProgressPolling(requestId: string): void {\n // This method is now handled by the RemoteExecutionAdapter automatically\n // when executeAction is called with a requestId\n console.warn(\n 'startProgressPolling is deprecated - polling is now automatic',\n );\n }\n\n // Stop progress polling for a specific request (deprecated - now handled by adapter)\n stopProgressPolling(requestId: string): void {\n // This method is now handled by the RemoteExecutionAdapter automatically\n console.warn(\n 'stopProgressPolling is deprecated - polling cleanup is now automatic',\n );\n }\n\n // Cancel execution - supports both remote and local\n async cancelExecution(requestId: string): Promise<void> {\n this.stopProgressPolling(requestId);\n\n if (this.adapter instanceof RemoteExecutionAdapter) {\n await this.adapter.cancelTask(requestId);\n } else if (this.adapter instanceof LocalExecutionAdapter) {\n // For local execution, we might need to implement agent cancellation\n console.warn('Local execution cancellation not fully implemented');\n }\n }\n\n // Screenshot method for remote execution\n async getScreenshot(): Promise<{\n screenshot: string;\n timestamp: number;\n } | null> {\n if (this.adapter instanceof RemoteExecutionAdapter) {\n return this.adapter.getScreenshot();\n }\n return null; // For local execution, not supported yet\n }\n\n // Get interface information (type and description)\n async getInterfaceInfo(): Promise<{\n type: string;\n description?: string;\n } | null> {\n if (this.adapter instanceof LocalExecutionAdapter) {\n return this.adapter.getInterfaceInfo();\n }\n if (this.adapter instanceof RemoteExecutionAdapter) {\n return this.adapter.getInterfaceInfo();\n }\n return null;\n }\n}\n"],"names":["PlaygroundSDK","type","serverUrl","agent","Error","LocalExecutionAdapter","finalServerUrl","window","PLAYGROUND_SERVER_PORT","RemoteExecutionAdapter","actionType","value","options","result","context","action","error","needsStructuredParams","aiConfig","requestId","undefined","callback","console","config"],"mappings":"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"}
1
+ {"version":3,"file":"sdk/index.mjs","sources":["../../../src/sdk/index.ts"],"sourcesContent":["import type { DeviceAction } from '@midscene/core';\nimport { PLAYGROUND_SERVER_PORT } from '@midscene/shared/constants';\nimport type { BasePlaygroundAdapter } from '../adapters/base';\nimport { LocalExecutionAdapter } from '../adapters/local-execution';\nimport { RemoteExecutionAdapter } from '../adapters/remote-execution';\nimport type {\n ExecutionOptions,\n FormValue,\n PlaygroundAgent,\n PlaygroundConfig,\n ValidationResult,\n} from '../types';\n\nexport class PlaygroundSDK {\n private adapter: BasePlaygroundAdapter;\n\n constructor(config: PlaygroundConfig) {\n this.adapter = this.createAdapter(\n config.type,\n config.serverUrl,\n config.agent,\n );\n }\n\n private createAdapter(\n type: string,\n serverUrl?: string,\n agent?: PlaygroundAgent,\n ): BasePlaygroundAdapter {\n switch (type) {\n case 'local-execution':\n if (!agent) {\n throw new Error('Agent is required for local execution');\n }\n return new LocalExecutionAdapter(agent);\n case 'remote-execution': {\n // Use provided serverUrl first, then fallback to localhost if current page origin is file:// or default\n const finalServerUrl =\n serverUrl ||\n (typeof window !== 'undefined' &&\n window.location.protocol.includes('http')\n ? window.location.origin\n : `http://localhost:${PLAYGROUND_SERVER_PORT}`);\n\n return new RemoteExecutionAdapter(finalServerUrl);\n }\n default:\n throw new Error(`Unsupported execution type: ${type}`);\n }\n }\n\n async executeAction(\n actionType: string,\n value: FormValue,\n options: ExecutionOptions,\n ): Promise<unknown> {\n const result = await this.adapter.executeAction(actionType, value, options);\n return result;\n }\n\n async getActionSpace(context?: unknown): Promise<DeviceAction<unknown>[]> {\n // Both adapters now accept context parameter\n // Local will prioritize internal agent, Remote will use server + fallback\n return this.adapter.getActionSpace(context);\n }\n\n validateStructuredParams(\n value: FormValue,\n action: DeviceAction<unknown> | undefined,\n ): ValidationResult {\n return this.adapter.validateParams(value, action);\n }\n\n formatErrorMessage(error: any): string {\n return this.adapter.formatErrorMessage(error);\n }\n\n createDisplayContent(\n value: FormValue,\n needsStructuredParams: boolean,\n action: DeviceAction<unknown> | undefined,\n ): string {\n return this.adapter.createDisplayContent(\n value,\n needsStructuredParams,\n action,\n );\n }\n\n // Get adapter ID (works for both remote and local execution)\n get id(): string | undefined {\n if (this.adapter instanceof RemoteExecutionAdapter) {\n return this.adapter.id;\n }\n if (this.adapter instanceof LocalExecutionAdapter) {\n return this.adapter.id;\n }\n return undefined;\n }\n\n // Server communication methods (for remote execution)\n async checkStatus(): Promise<boolean> {\n if (this.adapter instanceof RemoteExecutionAdapter) {\n return this.adapter.checkStatus();\n }\n return true; // For local execution, always return true\n }\n\n async overrideConfig(aiConfig: any): Promise<void> {\n if (this.adapter instanceof RemoteExecutionAdapter) {\n return this.adapter.overrideConfig(aiConfig);\n }\n // For local execution, this is a no-op\n }\n\n // Cancel task (for remote execution)\n async cancelTask(requestId: string): Promise<any> {\n if (this.adapter instanceof RemoteExecutionAdapter) {\n return this.adapter.cancelTask(requestId);\n }\n return { error: 'Cancel task not supported in local execution mode' };\n }\n\n // Dump update callback management\n onDumpUpdate(callback: (dump: string, executionDump?: any) => void): void {\n if (this.adapter instanceof LocalExecutionAdapter) {\n this.adapter.onDumpUpdate(callback);\n }\n }\n\n // Cancel execution - supports both remote and local\n async cancelExecution(requestId: string): Promise<void> {\n if (this.adapter instanceof RemoteExecutionAdapter) {\n await this.adapter.cancelTask(requestId);\n } else if (this.adapter instanceof LocalExecutionAdapter) {\n // For local execution, we might need to implement agent cancellation\n console.warn('Local execution cancellation not fully implemented');\n }\n }\n\n // Get current execution data (dump and report)\n async getCurrentExecutionData(): Promise<{\n dump: any | null;\n reportHTML: string | null;\n }> {\n if (\n this.adapter instanceof LocalExecutionAdapter &&\n this.adapter.getCurrentExecutionData\n ) {\n return await this.adapter.getCurrentExecutionData();\n }\n // For remote execution or if method not available, return empty data\n return { dump: null, reportHTML: null };\n }\n\n // Screenshot method for remote execution\n async getScreenshot(): Promise<{\n screenshot: string;\n timestamp: number;\n } | null> {\n if (this.adapter instanceof RemoteExecutionAdapter) {\n return this.adapter.getScreenshot();\n }\n return null; // For local execution, not supported yet\n }\n\n // Get interface information (type and description)\n async getInterfaceInfo(): Promise<{\n type: string;\n description?: string;\n } | null> {\n if (this.adapter instanceof LocalExecutionAdapter) {\n return this.adapter.getInterfaceInfo();\n }\n if (this.adapter instanceof RemoteExecutionAdapter) {\n return this.adapter.getInterfaceInfo();\n }\n return null;\n }\n\n // Get service mode based on adapter type\n getServiceMode(): 'In-Browser-Extension' | 'Server' {\n if (this.adapter instanceof LocalExecutionAdapter) {\n return 'In-Browser-Extension';\n }\n return 'Server';\n }\n}\n"],"names":["PlaygroundSDK","type","serverUrl","agent","Error","LocalExecutionAdapter","finalServerUrl","window","PLAYGROUND_SERVER_PORT","RemoteExecutionAdapter","actionType","value","options","result","context","action","error","needsStructuredParams","aiConfig","requestId","callback","console","config"],"mappings":"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"}
@@ -1,6 +1,7 @@
1
1
  import { existsSync, readFileSync, writeFileSync } from "node:fs";
2
2
  import { dirname, join } from "node:path";
3
3
  import { fileURLToPath } from "node:url";
4
+ import { paramStr, typeStr } from "@midscene/core/agent";
4
5
  import { getTmpDir } from "@midscene/core/utils";
5
6
  import { PLAYGROUND_SERVER_PORT } from "@midscene/shared/constants";
6
7
  import { overrideAIConfig } from "@midscene/shared/env";
@@ -96,8 +97,12 @@ class PlaygroundServer {
96
97
  });
97
98
  this._app.get('/task-progress/:requestId', async (req, res)=>{
98
99
  const { requestId } = req.params;
100
+ const progressMessages = this.taskProgressMessages[requestId] || [];
101
+ const lastMessage = progressMessages.length > 0 ? progressMessages[progressMessages.length - 1] : void 0;
102
+ const tip = lastMessage && 'string' == typeof lastMessage.action ? `${lastMessage.action} - ${lastMessage.description || ''}` : '';
99
103
  res.json({
100
- tip: this.taskProgressTips[requestId] || ''
104
+ tip,
105
+ progressMessages
101
106
  });
102
107
  });
103
108
  this._app.post('/action-space', async (req, res)=>{
@@ -162,9 +167,22 @@ class PlaygroundServer {
162
167
  });
163
168
  if (requestId) {
164
169
  this.currentTaskId = requestId;
165
- this.taskProgressTips[requestId] = '';
166
- this.agent.onTaskStartTip = (tip)=>{
167
- this.taskProgressTips[requestId] = tip;
170
+ this.taskProgressMessages[requestId] = [];
171
+ this.agent.onDumpUpdate = (_dump, executionDump)=>{
172
+ if (executionDump?.tasks) this.taskProgressMessages[requestId] = executionDump.tasks.map((task, index)=>{
173
+ const action = typeStr(task);
174
+ const description = paramStr(task) || '';
175
+ const taskStatus = task.status;
176
+ const status = 'cancelled' === taskStatus ? 'failed' : taskStatus;
177
+ return {
178
+ id: `progress-task-${index}`,
179
+ taskId: `task-${index}`,
180
+ action,
181
+ description,
182
+ status,
183
+ timestamp: task.timing?.start || Date.now()
184
+ };
185
+ });
168
186
  };
169
187
  }
170
188
  const response = {
@@ -205,7 +223,7 @@ class PlaygroundServer {
205
223
  if (response.error) console.error(`handle request failed after ${timeCost}ms: requestId: ${requestId}, ${response.error}`);
206
224
  else console.log(`handle request done after ${timeCost}ms: requestId: ${requestId}`);
207
225
  if (requestId) {
208
- delete this.taskProgressTips[requestId];
226
+ delete this.taskProgressMessages[requestId];
209
227
  if (this.currentTaskId === requestId) this.currentTaskId = null;
210
228
  }
211
229
  });
@@ -221,7 +239,7 @@ class PlaygroundServer {
221
239
  });
222
240
  console.log(`Cancelling task: ${requestId}`);
223
241
  await this.recreateAgent();
224
- delete this.taskProgressTips[requestId];
242
+ delete this.taskProgressMessages[requestId];
225
243
  this.currentTaskId = null;
226
244
  res.json({
227
245
  status: 'cancelled',
@@ -346,7 +364,7 @@ class PlaygroundServer {
346
364
  } catch (error) {
347
365
  console.warn('Failed to destroy agent:', error);
348
366
  }
349
- this.taskProgressTips = {};
367
+ this.taskProgressMessages = {};
350
368
  this.server.close((error)=>{
351
369
  if (error) reject(error);
352
370
  else {
@@ -364,7 +382,7 @@ class PlaygroundServer {
364
382
  _define_property(this, "port", void 0);
365
383
  _define_property(this, "agent", void 0);
366
384
  _define_property(this, "staticPath", void 0);
367
- _define_property(this, "taskProgressTips", void 0);
385
+ _define_property(this, "taskProgressMessages", void 0);
368
386
  _define_property(this, "id", void 0);
369
387
  _define_property(this, "_initialized", false);
370
388
  _define_property(this, "agentFactory", void 0);
@@ -372,7 +390,7 @@ class PlaygroundServer {
372
390
  this._app = express();
373
391
  this.tmpDir = getTmpDir();
374
392
  this.staticPath = staticPath;
375
- this.taskProgressTips = {};
393
+ this.taskProgressMessages = {};
376
394
  this.id = id || utils_uuid();
377
395
  if ('function' == typeof agent) {
378
396
  this.agentFactory = agent;