@midscene/playground 0.28.3 → 0.28.4

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 (68) hide show
  1. package/dist/es/adapters/local-execution.mjs +40 -7
  2. package/dist/es/adapters/local-execution.mjs.map +1 -1
  3. package/dist/es/adapters/remote-execution.mjs +97 -7
  4. package/dist/es/adapters/remote-execution.mjs.map +1 -1
  5. package/dist/es/index.mjs +3 -2
  6. package/dist/es/launcher.mjs +89 -0
  7. package/dist/es/launcher.mjs.map +1 -0
  8. package/dist/es/sdk/index.mjs +26 -1
  9. package/dist/es/sdk/index.mjs.map +1 -1
  10. package/dist/es/server.mjs +137 -101
  11. package/dist/es/server.mjs.map +1 -1
  12. package/dist/lib/adapters/local-execution.js +40 -7
  13. package/dist/lib/adapters/local-execution.js.map +1 -1
  14. package/dist/lib/adapters/remote-execution.js +97 -7
  15. package/dist/lib/adapters/remote-execution.js.map +1 -1
  16. package/dist/lib/index.js +5 -11
  17. package/dist/lib/index.js.map +1 -1
  18. package/dist/lib/launcher.js +133 -0
  19. package/dist/lib/launcher.js.map +1 -0
  20. package/dist/lib/sdk/index.js +26 -1
  21. package/dist/lib/sdk/index.js.map +1 -1
  22. package/dist/lib/server.js +142 -102
  23. package/dist/lib/server.js.map +1 -1
  24. package/dist/types/adapters/local-execution.d.ts +4 -2
  25. package/dist/types/adapters/remote-execution.d.ts +13 -3
  26. package/dist/types/index.d.ts +3 -1
  27. package/dist/types/launcher.d.ts +66 -0
  28. package/dist/types/sdk/index.d.ts +11 -1
  29. package/dist/types/server.d.ts +55 -9
  30. package/dist/types/types.d.ts +3 -10
  31. package/package.json +6 -6
  32. package/static/favicon.ico +0 -0
  33. package/static/index.html +1 -0
  34. package/static/static/css/index.12edce92.css +2 -0
  35. package/static/static/css/index.12edce92.css.map +1 -0
  36. package/static/static/js/345.c34b9bb0.js +673 -0
  37. package/static/static/js/345.c34b9bb0.js.LICENSE.txt +157 -0
  38. package/static/static/js/345.c34b9bb0.js.map +1 -0
  39. package/static/static/js/async/173.9cf6b074.js +3 -0
  40. package/static/static/js/async/173.9cf6b074.js.map +1 -0
  41. package/static/static/js/async/212.e243c338.js +158 -0
  42. package/static/static/js/async/212.e243c338.js.map +1 -0
  43. package/static/static/js/async/290.dd04c2bc.js +21 -0
  44. package/static/static/js/async/290.dd04c2bc.js.map +1 -0
  45. package/static/static/js/async/329.f888b505.js +26 -0
  46. package/static/static/js/async/329.f888b505.js.map +1 -0
  47. package/static/static/js/async/364.1821e74b.js +30 -0
  48. package/static/static/js/async/364.1821e74b.js.map +1 -0
  49. package/static/static/js/async/544.b73fa603.js +2 -0
  50. package/static/static/js/async/544.b73fa603.js.map +1 -0
  51. package/static/static/js/async/582.5dccae2d.js +21 -0
  52. package/static/static/js/async/582.5dccae2d.js.map +1 -0
  53. package/static/static/js/async/624.45ee2b2c.js +3 -0
  54. package/static/static/js/async/624.45ee2b2c.js.map +1 -0
  55. package/static/static/js/async/644.6bdc4065.js +1 -0
  56. package/static/static/js/async/702.60261735.js +231 -0
  57. package/static/static/js/async/702.60261735.js.map +1 -0
  58. package/static/static/js/async/920.7d9a9aa8.js +2 -0
  59. package/static/static/js/async/920.7d9a9aa8.js.map +1 -0
  60. package/static/static/js/async/983.8b91303f.js +1 -0
  61. package/static/static/js/index.77b067da.js +21 -0
  62. package/static/static/js/index.77b067da.js.LICENSE.txt +7 -0
  63. package/static/static/js/index.77b067da.js.map +1 -0
  64. package/static/static/js/lib-react.f566a9ed.js +3 -0
  65. package/static/static/js/lib-react.f566a9ed.js.LICENSE.txt +39 -0
  66. package/static/static/js/lib-react.f566a9ed.js.map +1 -0
  67. package/static/static/wasm/9e906fbf55e08f98.module.wasm +0 -0
  68. package/LICENSE +0 -21
@@ -13,6 +13,9 @@ function _define_property(obj, key, value) {
13
13
  return obj;
14
14
  }
15
15
  class LocalExecutionAdapter extends BasePlaygroundAdapter {
16
+ setProgressCallback(callback) {
17
+ this.progressCallback = callback;
18
+ }
16
19
  cleanup(requestId) {
17
20
  delete this.taskProgressTips[requestId];
18
21
  }
@@ -39,8 +42,18 @@ class LocalExecutionAdapter extends BasePlaygroundAdapter {
39
42
  if (errorMessage.includes('of different extension')) return 'Conflicting extension detected. Please disable the suspicious plugins and refresh the page. Guide: https://midscenejs.com/quick-experience.html#faq';
40
43
  return this.formatBasicErrorMessage(error);
41
44
  }
42
- async getActionSpace(page) {
43
- return await page.actionSpace();
45
+ async getActionSpace(context) {
46
+ var _this_agent;
47
+ if (null == (_this_agent = this.agent) ? void 0 : _this_agent.getActionSpace) return await this.agent.getActionSpace();
48
+ if (this.agent && 'interface' in this.agent && 'object' == typeof this.agent.interface) {
49
+ const page = this.agent.interface;
50
+ if (null == page ? void 0 : page.actionSpace) return await page.actionSpace();
51
+ }
52
+ if (context && 'object' == typeof context && 'actionSpace' in context) {
53
+ const contextPage = context;
54
+ return await contextPage.actionSpace();
55
+ }
56
+ return [];
44
57
  }
45
58
  async checkStatus() {
46
59
  return true;
@@ -49,16 +62,35 @@ class LocalExecutionAdapter extends BasePlaygroundAdapter {
49
62
  overrideAIConfig(aiConfig);
50
63
  }
51
64
  async executeAction(actionType, value, options) {
52
- const actionSpace = this.agent.getActionSpace ? await this.agent.getActionSpace() : [];
65
+ const actionSpace = await this.getActionSpace();
53
66
  if (options.requestId && this.agent) {
54
67
  const originalCallback = this.agent.onTaskStartTip;
55
68
  this.agent.onTaskStartTip = (tip)=>{
56
69
  this.taskProgressTips[options.requestId] = tip;
70
+ if (this.progressCallback) this.progressCallback(tip);
57
71
  if (originalCallback && 'function' == typeof originalCallback) originalCallback(tip);
58
72
  };
59
73
  }
60
74
  try {
61
- return await executeAction(this.agent, actionType, actionSpace, value, options);
75
+ const result = await executeAction(this.agent, actionType, actionSpace, value, options);
76
+ const response = {
77
+ result,
78
+ dump: null,
79
+ reportHTML: null,
80
+ error: null
81
+ };
82
+ try {
83
+ if (this.agent.dumpDataString) {
84
+ const dumpString = this.agent.dumpDataString();
85
+ if (dumpString) response.dump = JSON.parse(dumpString);
86
+ }
87
+ if (this.agent.reportHTMLString) response.reportHTML = this.agent.reportHTMLString() || null;
88
+ if (this.agent.writeOutActionDumps) this.agent.writeOutActionDumps();
89
+ } catch (error) {
90
+ console.error('Failed to get dump/reportHTML from agent:', error);
91
+ }
92
+ this.agent.resetDump();
93
+ return response;
62
94
  } finally{
63
95
  if (options.requestId) this.cleanup(options.requestId);
64
96
  }
@@ -79,14 +111,15 @@ class LocalExecutionAdapter extends BasePlaygroundAdapter {
79
111
  success: true
80
112
  };
81
113
  } catch (error) {
82
- console.error(`Failed to cancel agent: ${error.message}`);
114
+ const errorMessage = error instanceof Error ? error.message : 'Unknown error';
115
+ console.error(`Failed to cancel agent: ${errorMessage}`);
83
116
  return {
84
- error: `Failed to cancel: ${error.message}`
117
+ error: `Failed to cancel: ${errorMessage}`
85
118
  };
86
119
  }
87
120
  }
88
121
  constructor(agent){
89
- super(), _define_property(this, "agent", void 0), _define_property(this, "taskProgressTips", {});
122
+ super(), _define_property(this, "agent", void 0), _define_property(this, "taskProgressTips", {}), _define_property(this, "progressCallback", void 0);
90
123
  this.agent = agent;
91
124
  }
92
125
  }
@@ -1 +1 @@
1
- {"version":3,"file":"adapters/local-execution.mjs","sources":["webpack://@midscene/playground/./src/adapters/local-execution.ts"],"sourcesContent":["import type { DeviceAction } from '@midscene/core';\nimport { findAllMidsceneLocatorField } from '@midscene/core/ai-model';\nimport { overrideAIConfig } from '@midscene/shared/env';\nimport { executeAction } 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\n constructor(agent: PlaygroundAgent) {\n super();\n this.agent = agent;\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 if (!action?.paramSchema || !('shape' in action.paramSchema)) {\n return [params.prompt || '', options];\n }\n\n const locatorFieldKeys = findAllMidsceneLocatorField(action.paramSchema);\n\n // Find locate field (MidsceneLocation field)\n let locateField = null;\n if (locatorFieldKeys.length > 0) {\n locateField = params[locatorFieldKeys[0]];\n }\n\n // Filter non-locate fields\n const nonLocateFields = this.filterValidParams(params, locatorFieldKeys);\n\n // Local execution format: [locateField, { ...otherParams, ...options }]\n const paramObj = { ...nonLocateFields, ...options };\n return [locateField, paramObj];\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 directly from local agent\n async getActionSpace(page: any): Promise<DeviceAction<unknown>[]> {\n return await page.actionSpace();\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: any): 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 from the stored agent\n const actionSpace = this.agent.getActionSpace\n ? await this.agent.getActionSpace()\n : [];\n\n // Setup progress tracking if requestId is provided\n if (options.requestId && this.agent) {\n // Store the original callback if exists\n const originalCallback = this.agent.onTaskStartTip;\n\n // Override with our callback that stores tips and calls original\n this.agent.onTaskStartTip = (tip: string) => {\n // Store tip for our progress tracking\n this.taskProgressTips[options.requestId!] = tip;\n // Call original callback if it existed\n if (originalCallback && typeof originalCallback === 'function') {\n originalCallback(tip);\n }\n };\n }\n\n try {\n // Call the base implementation with the original signature\n return await executeAction(\n this.agent,\n actionType,\n actionSpace,\n value,\n options,\n );\n } finally {\n // Always clean up progress tracking to prevent memory leaks\n if (options.requestId) {\n this.cleanup(options.requestId);\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: any) {\n console.error(`Failed to cancel agent: ${error.message}`);\n return { error: `Failed to cancel: ${error.message}` };\n }\n }\n}\n"],"names":["LocalExecutionAdapter","BasePlaygroundAdapter","requestId","action","params","options","locatorFieldKeys","findAllMidsceneLocatorField","locateField","nonLocateFields","paramObj","error","errorMessage","page","aiConfig","overrideAIConfig","actionType","value","actionSpace","originalCallback","tip","executeAction","undefined","_requestId","_this_agent","console","agent"],"mappings":"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"}
1
+ {"version":3,"file":"adapters/local-execution.mjs","sources":["webpack://@midscene/playground/./src/adapters/local-execution.ts"],"sourcesContent":["import type { DeviceAction } from '@midscene/core';\nimport { findAllMidsceneLocatorField } from '@midscene/core/ai-model';\nimport { overrideAIConfig } from '@midscene/shared/env';\nimport { executeAction } 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\n constructor(agent: PlaygroundAgent) {\n super();\n this.agent = agent;\n }\n\n setProgressCallback(callback: (tip: string) => void): void {\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 if (!action?.paramSchema || !('shape' in action.paramSchema)) {\n return [params.prompt || '', options];\n }\n\n const locatorFieldKeys = findAllMidsceneLocatorField(action.paramSchema);\n\n // Find locate field (MidsceneLocation field)\n let locateField = null;\n if (locatorFieldKeys.length > 0) {\n locateField = params[locatorFieldKeys[0]];\n }\n\n // Filter non-locate fields\n const nonLocateFields = this.filterValidParams(params, locatorFieldKeys);\n\n // Local execution format: [locateField, { ...otherParams, ...options }]\n const paramObj = { ...nonLocateFields, ...options };\n return [locateField, paramObj];\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?: () => Promise<DeviceAction<unknown>[]>;\n };\n if (page?.actionSpace) {\n return await 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: () => Promise<DeviceAction<unknown>[]>;\n };\n return await 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\n // Setup progress tracking if requestId is provided\n if (options.requestId && this.agent) {\n // Store the original callback if exists (this preserves chrome extension callbacks)\n const originalCallback = this.agent.onTaskStartTip;\n\n // Override with our callback that stores tips and calls original\n this.agent.onTaskStartTip = (tip: string) => {\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 // Call original callback if it existed (this will call chrome extension callbacks)\n if (originalCallback && typeof originalCallback === 'function') {\n originalCallback(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 }\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"],"names":["LocalExecutionAdapter","BasePlaygroundAdapter","callback","requestId","action","params","options","locatorFieldKeys","findAllMidsceneLocatorField","locateField","nonLocateFields","paramObj","error","errorMessage","context","_this_agent","page","contextPage","aiConfig","overrideAIConfig","actionType","value","actionSpace","originalCallback","tip","result","executeAction","response","dumpString","JSON","console","undefined","_requestId","Error","agent"],"mappings":"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"}
@@ -11,6 +11,38 @@ function _define_property(obj, key, value) {
11
11
  return obj;
12
12
  }
13
13
  class RemoteExecutionAdapter extends BasePlaygroundAdapter {
14
+ validateParams(value, action) {
15
+ if (!(null == action ? void 0 : action.paramSchema)) return {
16
+ valid: true
17
+ };
18
+ const needsStructuredParams = this.actionNeedsStructuredParams(action);
19
+ if (!needsStructuredParams) return {
20
+ valid: true
21
+ };
22
+ if (!value.params) return {
23
+ valid: false,
24
+ errorMessage: 'Parameters are required'
25
+ };
26
+ if (action.paramSchema && 'object' == typeof action.paramSchema) {
27
+ const schema = action.paramSchema;
28
+ if (schema.shape || 'ZodObject' === schema.type) {
29
+ const shape = schema.shape || {};
30
+ const missingFields = Object.keys(shape).filter((key)=>{
31
+ var _fieldDef__def, _fieldDef__def1;
32
+ const fieldDef = shape[key];
33
+ const isOptional = (null == fieldDef ? void 0 : fieldDef.isOptional) || (null == fieldDef ? void 0 : null == (_fieldDef__def = fieldDef._def) ? void 0 : _fieldDef__def.innerType) || (null == fieldDef ? void 0 : null == (_fieldDef__def1 = fieldDef._def) ? void 0 : _fieldDef__def1.typeName) === 'ZodOptional';
34
+ return !isOptional && (void 0 === value.params[key] || '' === value.params[key]);
35
+ });
36
+ if (missingFields.length > 0) return {
37
+ valid: false,
38
+ errorMessage: `Missing required parameters: ${missingFields.join(', ')}`
39
+ };
40
+ }
41
+ }
42
+ return {
43
+ valid: true
44
+ };
45
+ }
14
46
  async parseStructuredParams(action, params, options) {
15
47
  if (!this.hasValidSchema(action)) return [
16
48
  params.prompt || '',
@@ -45,11 +77,12 @@ class RemoteExecutionAdapter extends BasePlaygroundAdapter {
45
77
  }
46
78
  async executeViaServer(actionType, value, options) {
47
79
  const payload = {
48
- context: options.context,
49
80
  type: actionType,
50
81
  prompt: value.prompt,
51
82
  ...this.buildOptionalPayloadParams(options, value)
52
83
  };
84
+ if (options.context) payload.context = options.context;
85
+ if (options.requestId && this.progressCallback) this.startProgressPolling(options.requestId, this.progressCallback);
53
86
  try {
54
87
  const response = await fetch(`${this.serverUrl}/execute`, {
55
88
  method: 'POST',
@@ -62,8 +95,11 @@ class RemoteExecutionAdapter extends BasePlaygroundAdapter {
62
95
  const errorText = await response.text().catch(()=>'Unknown error');
63
96
  throw new Error(`Server request failed (${response.status}): ${errorText}`);
64
97
  }
65
- return await response.json();
98
+ const result = await response.json();
99
+ if (options.requestId) this.stopProgressPolling(options.requestId);
100
+ return result;
66
101
  } catch (error) {
102
+ if (options.requestId) this.stopProgressPolling(options.requestId);
67
103
  console.error('Execute via server failed:', error);
68
104
  throw error;
69
105
  }
@@ -117,8 +153,9 @@ class RemoteExecutionAdapter extends BasePlaygroundAdapter {
117
153
  } catch (error) {
118
154
  console.error('Failed to get action space from server:', error);
119
155
  }
120
- if (context && 'function' == typeof context.actionSpace) try {
121
- const result = await context.actionSpace();
156
+ if (context && 'object' == typeof context && 'actionSpace' in context) try {
157
+ const actionSpaceMethod = context.actionSpace;
158
+ const result = await actionSpaceMethod();
122
159
  return Array.isArray(result) ? result : [];
123
160
  } catch (error) {
124
161
  console.error('Failed to get action space from context:', error);
@@ -137,6 +174,15 @@ class RemoteExecutionAdapter extends BasePlaygroundAdapter {
137
174
  }
138
175
  async overrideConfig(aiConfig) {
139
176
  if (!this.serverUrl) throw new Error('Server URL not configured');
177
+ const mappedConfig = {};
178
+ const configKeyMapping = {
179
+ deepThink: 'MIDSCENE_FORCE_DEEP_THINK'
180
+ };
181
+ Object.entries(aiConfig).forEach(([key, value])=>{
182
+ if ('screenshotIncluded' === key || 'domIncluded' === key) return;
183
+ const mappedKey = configKeyMapping[key] || key;
184
+ mappedConfig[mappedKey] = String(value);
185
+ });
140
186
  try {
141
187
  const response = await fetch(`${this.serverUrl}/config`, {
142
188
  method: 'POST',
@@ -144,7 +190,7 @@ class RemoteExecutionAdapter extends BasePlaygroundAdapter {
144
190
  'Content-Type': 'application/json'
145
191
  },
146
192
  body: JSON.stringify({
147
- aiConfig
193
+ aiConfig: mappedConfig
148
194
  })
149
195
  });
150
196
  if (!response.ok) throw new Error(`Failed to override server config: ${response.statusText}`);
@@ -180,6 +226,7 @@ class RemoteExecutionAdapter extends BasePlaygroundAdapter {
180
226
  }
181
227
  }
182
228
  async cancelTask(requestId) {
229
+ this.stopProgressPolling(requestId);
183
230
  if (!this.serverUrl) return {
184
231
  error: 'No server URL configured'
185
232
  };
@@ -187,7 +234,9 @@ class RemoteExecutionAdapter extends BasePlaygroundAdapter {
187
234
  error: 'Invalid request ID'
188
235
  };
189
236
  try {
190
- const res = await fetch(`${this.serverUrl}/cancel/${encodeURIComponent(requestId)}`);
237
+ const res = await fetch(`${this.serverUrl}/cancel/${encodeURIComponent(requestId)}`, {
238
+ method: 'POST'
239
+ });
191
240
  if (!res.ok) return {
192
241
  error: `Cancel request failed: ${res.statusText}`
193
242
  };
@@ -203,8 +252,49 @@ class RemoteExecutionAdapter extends BasePlaygroundAdapter {
203
252
  };
204
253
  }
205
254
  }
255
+ setProgressCallback(callback) {
256
+ this.progressCallback = callback;
257
+ }
258
+ startProgressPolling(requestId, callback) {
259
+ if (this.progressPolling.has(requestId)) return;
260
+ let lastTip = '';
261
+ const interval = setInterval(async ()=>{
262
+ try {
263
+ var _progress_tip_trim, _progress_tip;
264
+ const progress = await this.getTaskProgress(requestId);
265
+ if ((null == progress ? void 0 : null == (_progress_tip = progress.tip) ? void 0 : null == (_progress_tip_trim = _progress_tip.trim) ? void 0 : _progress_tip_trim.call(_progress_tip)) && progress.tip !== lastTip) {
266
+ lastTip = progress.tip;
267
+ callback(progress.tip);
268
+ }
269
+ } catch (error) {
270
+ console.debug('Progress polling error:', error);
271
+ }
272
+ }, 500);
273
+ this.progressPolling.set(requestId, interval);
274
+ }
275
+ stopProgressPolling(requestId) {
276
+ const interval = this.progressPolling.get(requestId);
277
+ if (interval) {
278
+ clearInterval(interval);
279
+ this.progressPolling.delete(requestId);
280
+ }
281
+ }
282
+ async getScreenshot() {
283
+ if (!this.serverUrl) return null;
284
+ try {
285
+ const response = await fetch(`${this.serverUrl}/screenshot`);
286
+ if (!response.ok) {
287
+ console.warn(`Screenshot request failed: ${response.statusText}`);
288
+ return null;
289
+ }
290
+ return await response.json();
291
+ } catch (error) {
292
+ console.error('Failed to get screenshot:', error);
293
+ return null;
294
+ }
295
+ }
206
296
  constructor(serverUrl = `http://localhost:${PLAYGROUND_SERVER_PORT}`){
207
- super(), _define_property(this, "serverUrl", void 0);
297
+ super(), _define_property(this, "serverUrl", void 0), _define_property(this, "progressPolling", new Map()), _define_property(this, "progressCallback", void 0);
208
298
  this.serverUrl = serverUrl;
209
299
  }
210
300
  }
@@ -1 +1 @@
1
- {"version":3,"file":"adapters/remote-execution.mjs","sources":["webpack://@midscene/playground/./src/adapters/remote-execution.ts"],"sourcesContent":["import type { DeviceAction } from '@midscene/core';\nimport { PLAYGROUND_SERVER_PORT } from '@midscene/shared/constants';\nimport type { ExecutionOptions, FormValue } from '../types';\nimport { BasePlaygroundAdapter } from './base';\n\nexport class RemoteExecutionAdapter extends BasePlaygroundAdapter {\n private serverUrl?: string;\n\n constructor(serverUrl = `http://localhost:${PLAYGROUND_SERVER_PORT}`) {\n super();\n this.serverUrl = serverUrl;\n }\n async parseStructuredParams(\n action: DeviceAction<unknown>,\n params: Record<string, unknown>,\n options: ExecutionOptions,\n ): Promise<unknown[]> {\n if (!this.hasValidSchema(action)) {\n return [params.prompt || '', options];\n }\n\n // Remote execution format: merge options and valid params into a single object\n return [{ ...options, ...this.filterValidParams(params) }];\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 context: options.context,\n type: actionType,\n prompt: value.prompt,\n ...this.buildOptionalPayloadParams(options, value),\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 return await response.json();\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: '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 // Helper method to check if action has a valid schema\n private hasValidSchema(action: DeviceAction<unknown>): boolean {\n return !!(action?.paramSchema && 'shape' in action.paramSchema);\n }\n\n // Get action space from server\n async getActionSpace(context: any): Promise<DeviceAction<unknown>[]> {\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 local implementation\n }\n }\n\n // Fallback to local implementation (if page object available)\n if (context && typeof context.actionSpace === 'function') {\n try {\n const result = await context.actionSpace();\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 return res.status === 200;\n } catch (error) {\n console.warn('Server status check failed:', error);\n return false;\n }\n }\n\n async overrideConfig(aiConfig: any): 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\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"],"names":["RemoteExecutionAdapter","BasePlaygroundAdapter","action","params","options","error","message","androidErrors","androidError","keyword","actionType","value","window","Error","payload","response","fetch","JSON","errorText","console","optionalParams","optionalFields","key","context","result","Array","res","aiConfig","requestId","undefined","encodeURIComponent","serverUrl","PLAYGROUND_SERVER_PORT"],"mappings":";;;;;;;;;;;;AAKO,MAAMA,+BAA+BC;IAO1C,MAAM,sBACJC,MAA6B,EAC7BC,MAA+B,EAC/BC,OAAyB,EACL;QACpB,IAAI,CAAC,IAAI,CAAC,cAAc,CAACF,SACvB,OAAO;YAACC,OAAO,MAAM,IAAI;YAAIC;SAAQ;QAIvC,OAAO;YAAC;gBAAE,GAAGA,OAAO;gBAAE,GAAG,IAAI,CAAC,iBAAiB,CAACD,OAAO;YAAC;SAAE;IAC5D;IAEA,mBAAmBE,KAAU,EAAU;QACrC,MAAMC,UAAUD,AAAAA,CAAAA,QAAAA,QAAAA,KAAAA,IAAAA,MAAO,OAAO,AAAD,KAAK;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,EAClBC,KAAgB,EAChBP,OAAyB,EACP;QAElB,IAAI,IAAI,CAAC,SAAS,IAAI,AAAkB,eAAlB,OAAOQ,QAC3B,OAAO,IAAI,CAAC,gBAAgB,CAACF,YAAYC,OAAOP;QAGlD,MAAM,IAAIS,MACR;IAEJ;IAGA,MAAc,iBACZH,UAAkB,EAClBC,KAAgB,EAChBP,OAAyB,EACP;QAClB,MAAMU,UAAmC;YACvC,SAASV,QAAQ,OAAO;YACxB,MAAMM;YACN,QAAQC,MAAM,MAAM;YACpB,GAAG,IAAI,CAAC,0BAA0B,CAACP,SAASO,MAAM;QACpD;QAEA,IAAI;YACF,MAAMI,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,OAAO,MAAMH,SAAS,IAAI;QAC5B,EAAE,OAAOV,OAAO;YACdc,QAAQ,KAAK,CAAC,8BAA8Bd;YAC5C,MAAMA;QACR;IACF;IAGQ,2BACND,OAAyB,EACzBO,KAAgB,EACS;QACzB,MAAMS,iBAA0C,CAAC;QAGjD,MAAMC,iBAAiB;YACrB;gBAAE,KAAK;gBAAa,OAAOjB,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;gBAAU,OAAOO,MAAM,MAAM;YAAC;SACtC;QAEDU,eAAe,OAAO,CAAC,CAAC,EAAEC,GAAG,EAAEX,KAAK,EAAE;YACpC,IAAIA,QAAAA,SAAyCA,AAAU,OAAVA,OAC3CS,cAAc,CAACE,IAAI,GAAGX;QAE1B;QAEA,OAAOS;IACT;IAGQ,eAAelB,MAA6B,EAAW;QAC7D,OAAO,CAAC,CAAEA,CAAAA,CAAAA,QAAAA,SAAAA,KAAAA,IAAAA,OAAQ,WAAW,AAAD,KAAK,WAAWA,OAAO,WAAU;IAC/D;IAGA,MAAM,eAAeqB,OAAY,EAAoC;QACnE,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,MAAMS,SAAS,MAAMT,SAAS,IAAI;YAClC,OAAOU,MAAM,OAAO,CAACD,UAAUA,SAAS,EAAE;QAC5C,EAAE,OAAOnB,OAAO;YACdc,QAAQ,KAAK,CAAC,2CAA2Cd;QAE3D;QAIF,IAAIkB,WAAW,AAA+B,cAA/B,OAAOA,QAAQ,WAAW,EACvC,IAAI;YACF,MAAMC,SAAS,MAAMD,QAAQ,WAAW;YACxC,OAAOE,MAAM,OAAO,CAACD,UAAUA,SAAS,EAAE;QAC5C,EAAE,OAAOnB,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,MAAMqB,MAAM,MAAMV,MAAM,GAAG,IAAI,CAAC,SAAS,CAAC,OAAO,CAAC;YAClD,OAAOU,AAAe,QAAfA,IAAI,MAAM;QACnB,EAAE,OAAOrB,OAAO;YACdc,QAAQ,IAAI,CAAC,+BAA+Bd;YAC5C,OAAO;QACT;IACF;IAEA,MAAM,eAAesB,QAAa,EAAiB;QACjD,IAAI,CAAC,IAAI,CAAC,SAAS,EACjB,MAAM,IAAId,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;oBAAEU;gBAAS;YAClC;YAEA,IAAI,CAACZ,SAAS,EAAE,EACd,MAAM,IAAIF,MACR,CAAC,kCAAkC,EAAEE,SAAS,UAAU,EAAE;QAGhE,EAAE,OAAOV,OAAO;YACdc,QAAQ,KAAK,CAAC,qCAAqCd;YACnD,MAAMA;QACR;IACF;IAEA,MAAM,gBAAgBuB,SAAiB,EAA6B;QAClE,IAAI,CAAC,IAAI,CAAC,SAAS,EACjB,OAAO;YAAE,KAAKC;QAAU;QAG1B,IAAI,CAACD,CAAAA,QAAAA,YAAAA,KAAAA,IAAAA,UAAW,IAAI,EAAC,GAAG;YACtBT,QAAQ,IAAI,CAAC;YACb,OAAO;gBAAE,KAAKU;YAAU;QAC1B;QAEA,IAAI;YACF,MAAMd,WAAW,MAAMC,MACrB,GAAG,IAAI,CAAC,SAAS,CAAC,eAAe,EAAEc,mBAAmBF,YAAY;YAGpE,IAAI,CAACb,SAAS,EAAE,EAAE;gBAChBI,QAAQ,IAAI,CAAC,CAAC,8BAA8B,EAAEJ,SAAS,UAAU,EAAE;gBACnE,OAAO;oBAAE,KAAKc;gBAAU;YAC1B;YAEA,OAAO,MAAMd,SAAS,IAAI;QAC5B,EAAE,OAAOV,OAAO;YACdc,QAAQ,KAAK,CAAC,iCAAiCd;YAC/C,OAAO;gBAAE,KAAKwB;YAAU;QAC1B;IACF;IAGA,MAAM,WACJD,SAAiB,EAC+B;QAChD,IAAI,CAAC,IAAI,CAAC,SAAS,EACjB,OAAO;YAAE,OAAO;QAA2B;QAG7C,IAAI,CAACA,CAAAA,QAAAA,YAAAA,KAAAA,IAAAA,UAAW,IAAI,EAAC,GACnB,OAAO;YAAE,OAAO;QAAqB;QAGvC,IAAI;YACF,MAAMF,MAAM,MAAMV,MAChB,GAAG,IAAI,CAAC,SAAS,CAAC,QAAQ,EAAEc,mBAAmBF,YAAY;YAG7D,IAAI,CAACF,IAAI,EAAE,EACT,OAAO;gBAAE,OAAO,CAAC,uBAAuB,EAAEA,IAAI,UAAU,EAAE;YAAC;YAG7D,MAAMF,SAAS,MAAME,IAAI,IAAI;YAC7B,OAAO;gBAAE,SAAS;gBAAM,GAAGF,MAAM;YAAC;QACpC,EAAE,OAAOnB,OAAO;YACdc,QAAQ,KAAK,CAAC,0BAA0Bd;YACxC,OAAO;gBAAE,OAAO;YAAwB;QAC1C;IACF;IAnQA,YAAY0B,YAAY,CAAC,iBAAiB,EAAEC,wBAAwB,CAAE;QACpE,KAAK,IAHP,uBAAQ,aAAR;QAIE,IAAI,CAAC,SAAS,GAAGD;IACnB;AAiQF"}
1
+ {"version":3,"file":"adapters/remote-execution.mjs","sources":["webpack://@midscene/playground/./src/adapters/remote-execution.ts"],"sourcesContent":["import type { DeviceAction } from '@midscene/core';\nimport { PLAYGROUND_SERVER_PORT } from '@midscene/shared/constants';\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\n constructor(serverUrl = `http://localhost:${PLAYGROUND_SERVER_PORT}`) {\n super();\n this.serverUrl = serverUrl;\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 if (!this.hasValidSchema(action)) {\n return [params.prompt || '', options];\n }\n\n // Remote execution format: merge options and valid params into a single object\n return [{ ...options, ...this.filterValidParams(params) }];\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: '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 // Helper method to check if action has a valid schema\n private hasValidSchema(action: DeviceAction<unknown>): boolean {\n return !!(action?.paramSchema && 'shape' in action.paramSchema);\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 { actionSpace: () => Promise<DeviceAction<unknown>[]> }\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 return res.status === 200;\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 // Map visualizer config keys to environment variable names\n const mappedConfig: Record<string, unknown> = {};\n\n // Map visualizer config keys to their corresponding environment variable names\n const configKeyMapping: Record<string, string> = {\n deepThink: 'MIDSCENE_FORCE_DEEP_THINK',\n // screenshotIncluded and domIncluded are execution options, not global config\n // They will be passed through ExecutionOptions in executeAction\n\n // Most config keys are already in the correct environment variable format\n // so we don't need to map them. The frontend stores config as OPENAI_API_KEY, etc.\n };\n\n // Convert visualizer config to environment variable format\n Object.entries(aiConfig).forEach(([key, value]) => {\n if (key === 'screenshotIncluded' || key === 'domIncluded') {\n // These are execution options, not global config - skip them here\n return;\n }\n\n const mappedKey = configKeyMapping[key] || key;\n // Environment variables must be strings - convert all values to strings\n mappedConfig[mappedKey] = String(value);\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: mappedConfig }),\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"],"names":["RemoteExecutionAdapter","BasePlaygroundAdapter","value","action","needsStructuredParams","schema","shape","missingFields","Object","key","_fieldDef__def","_fieldDef__def1","fieldDef","isOptional","undefined","params","options","error","message","androidErrors","androidError","keyword","actionType","window","Error","payload","response","fetch","JSON","errorText","result","console","optionalParams","optionalFields","context","Array","actionSpaceMethod","res","aiConfig","mappedConfig","configKeyMapping","mappedKey","String","requestId","encodeURIComponent","callback","lastTip","interval","setInterval","_progress_tip","progress","clearInterval","serverUrl","PLAYGROUND_SERVER_PORT","Map"],"mappings":"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"}
package/dist/es/index.mjs CHANGED
@@ -1,7 +1,8 @@
1
1
  import { dataExtractionAPIs, executeAction, formatErrorMessage, noReplayAPIs, validateStructuredParams, validationAPIs } from "./common.mjs";
2
- import server from "./server.mjs";
2
+ import { PlaygroundServer } from "./server.mjs";
3
+ import { playgroundForAgent } from "./launcher.mjs";
3
4
  import { PlaygroundSDK } from "./sdk/index.mjs";
4
5
  import { BasePlaygroundAdapter } from "./adapters/base.mjs";
5
6
  import { LocalExecutionAdapter } from "./adapters/local-execution.mjs";
6
7
  import { RemoteExecutionAdapter } from "./adapters/remote-execution.mjs";
7
- export { BasePlaygroundAdapter, LocalExecutionAdapter, PlaygroundSDK, server as PlaygroundServer, RemoteExecutionAdapter, dataExtractionAPIs, executeAction, formatErrorMessage, noReplayAPIs, validateStructuredParams, validationAPIs };
8
+ export { BasePlaygroundAdapter, LocalExecutionAdapter, PlaygroundSDK, PlaygroundServer, RemoteExecutionAdapter, dataExtractionAPIs, executeAction, formatErrorMessage, noReplayAPIs, playgroundForAgent, validateStructuredParams, validationAPIs };
@@ -0,0 +1,89 @@
1
+ import { spawn } from "node:child_process";
2
+ import { PLAYGROUND_SERVER_PORT } from "@midscene/shared/constants";
3
+ import server_0 from "./server.mjs";
4
+ function playgroundForAgent(agent) {
5
+ return {
6
+ async launch (options = {}) {
7
+ const { port = PLAYGROUND_SERVER_PORT, openBrowser = true, browserCommand, verbose = true } = options;
8
+ const webPage = agent.interface;
9
+ if (!webPage) throw new Error('Agent must have an interface property');
10
+ if (verbose) {
11
+ console.log("\uD83D\uDE80 Starting Midscene Playground...");
12
+ console.log(`\u{1F4F1} Agent: ${agent.constructor.name}`);
13
+ console.log(`\u{1F5A5}\u{FE0F} Page: ${webPage.constructor.name}`);
14
+ console.log(`\u{1F310} Port: ${port}`);
15
+ }
16
+ const server = new server_0(webPage, agent);
17
+ const launchedServer = await server.launch(port);
18
+ if (verbose) console.log(`\u{2705} Playground server started on port ${port}`);
19
+ const url = `http://127.0.0.1:${port}`;
20
+ if (openBrowser) await openInBrowser(url, browserCommand, verbose);
21
+ return {
22
+ server: launchedServer,
23
+ port,
24
+ host: '127.0.0.1',
25
+ close: async ()=>{
26
+ if (verbose) console.log("\uD83D\uDED1 Shutting down Midscene Playground...");
27
+ try {
28
+ await launchedServer.close();
29
+ if (verbose) console.log("\u2705 Playground shutdown complete");
30
+ } catch (error) {
31
+ if (verbose) console.error("\u274C Error during playground shutdown:", error);
32
+ throw error;
33
+ }
34
+ }
35
+ };
36
+ }
37
+ };
38
+ }
39
+ async function openInBrowser(url, customCommand, verbose = true) {
40
+ return new Promise((resolve, reject)=>{
41
+ let command;
42
+ let args;
43
+ if (customCommand) {
44
+ command = customCommand;
45
+ args = [
46
+ url
47
+ ];
48
+ } else switch(process.platform){
49
+ case 'darwin':
50
+ command = 'open';
51
+ args = [
52
+ url
53
+ ];
54
+ break;
55
+ case 'win32':
56
+ command = 'start';
57
+ args = [
58
+ '',
59
+ url
60
+ ];
61
+ break;
62
+ default:
63
+ command = 'xdg-open';
64
+ args = [
65
+ url
66
+ ];
67
+ break;
68
+ }
69
+ if (verbose) console.log(`\u{1F310} Opening browser: ${command} ${args.join(' ')}`);
70
+ const child = spawn(command, args, {
71
+ detached: true,
72
+ stdio: 'ignore'
73
+ });
74
+ child.on('error', (error)=>{
75
+ if (verbose) {
76
+ console.warn("\u26A0\uFE0F Failed to open browser automatically:", error.message);
77
+ console.log(`\u{1F310} Please open manually: ${url}`);
78
+ }
79
+ resolve();
80
+ });
81
+ child.on('close', ()=>{
82
+ resolve();
83
+ });
84
+ child.unref();
85
+ });
86
+ }
87
+ export { playgroundForAgent };
88
+
89
+ //# sourceMappingURL=launcher.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"launcher.mjs","sources":["webpack://@midscene/playground/./src/launcher.ts"],"sourcesContent":["import { spawn } from 'node:child_process';\nimport type { Agent, Agent as PageAgent } from '@midscene/core/agent';\nimport type { AbstractInterface } from '@midscene/core/device';\nimport { PLAYGROUND_SERVER_PORT } from '@midscene/shared/constants';\nimport PlaygroundServer from './server';\n\nexport interface LaunchPlaygroundOptions {\n /**\n * Port to start the playground server on\n * @default 3456\n */\n port?: number;\n\n /**\n * Whether to automatically open the web-playground in browser\n * @default true\n */\n openBrowser?: boolean;\n\n /**\n * Custom browser command to open web-playground\n * @default 'open' on macOS, 'start' on Windows, 'xdg-open' on Linux\n */\n browserCommand?: string;\n\n /**\n * Whether to show server logs\n * @default true\n */\n verbose?: boolean;\n}\n\nexport interface LaunchPlaygroundResult {\n /**\n * The playground server instance\n */\n server: PlaygroundServer;\n\n /**\n * The server port\n */\n port: number;\n\n /**\n * The server host\n */\n host: string;\n\n /**\n * Function to gracefully shutdown the playground\n */\n close: () => Promise<void>;\n}\n\n/**\n * Create a playground launcher for a specific agent\n *\n * @example\n * ```typescript\n * import { playgroundForAgent } from '@midscene/playground';\n * import { SampleDevice, Agent } from '@midscene/core';\n *\n * const device = new SampleDevice();\n * const agent = new Agent(device);\n *\n * // Launch playground for the agent\n * const server = await playgroundForAgent(agent).launch();\n *\n * // Later, when you want to shutdown:\n * server.close();\n * ```\n */\nexport function playgroundForAgent(agent: Agent) {\n return {\n /**\n * Launch the playground server with optional configuration\n */\n async launch(\n options: LaunchPlaygroundOptions = {},\n ): Promise<LaunchPlaygroundResult> {\n const {\n port = PLAYGROUND_SERVER_PORT,\n openBrowser = true,\n browserCommand,\n verbose = true,\n } = options;\n\n // Extract agent components - Agent has interface property\n const webPage = agent.interface;\n if (!webPage) {\n throw new Error('Agent must have an interface property');\n }\n\n if (verbose) {\n console.log('🚀 Starting Midscene Playground...');\n console.log(`📱 Agent: ${agent.constructor.name}`);\n console.log(`🖥️ Page: ${webPage.constructor.name}`);\n console.log(`🌐 Port: ${port}`);\n }\n\n // Create and launch the server with agent instances\n const server = new PlaygroundServer(\n webPage,\n agent as unknown as PageAgent,\n );\n\n const launchedServer = (await server.launch(port)) as PlaygroundServer;\n\n if (verbose) {\n console.log(`✅ Playground server started on port ${port}`);\n }\n\n const url = `http://127.0.0.1:${port}`;\n\n // Open browser if requested\n if (openBrowser) {\n await openInBrowser(url, browserCommand, verbose);\n }\n\n return {\n server: launchedServer,\n port,\n host: '127.0.0.1',\n close: async () => {\n if (verbose) {\n console.log('🛑 Shutting down Midscene Playground...');\n }\n\n try {\n await launchedServer.close();\n if (verbose) {\n console.log('✅ Playground shutdown complete');\n }\n } catch (error) {\n if (verbose) {\n console.error('❌ Error during playground shutdown:', error);\n }\n throw error;\n }\n },\n };\n },\n };\n}\n\n/**\n * Open URL in browser using platform-appropriate command\n */\nasync function openInBrowser(\n url: string,\n customCommand?: string,\n verbose = true,\n): Promise<void> {\n return new Promise((resolve, reject) => {\n let command: string;\n let args: string[];\n\n if (customCommand) {\n command = customCommand;\n args = [url];\n } else {\n // Detect platform and use appropriate command\n switch (process.platform) {\n case 'darwin':\n command = 'open';\n args = [url];\n break;\n case 'win32':\n command = 'start';\n args = ['', url]; // Empty string for title\n break;\n default:\n command = 'xdg-open';\n args = [url];\n break;\n }\n }\n\n if (verbose) {\n console.log(`🌐 Opening browser: ${command} ${args.join(' ')}`);\n }\n\n const child = spawn(command, args, {\n detached: true,\n stdio: 'ignore',\n });\n\n child.on('error', (error) => {\n if (verbose) {\n console.warn('⚠️ Failed to open browser automatically:', error.message);\n console.log(`🌐 Please open manually: ${url}`);\n }\n // Don't reject, just continue - browser opening is optional\n resolve();\n });\n\n child.on('close', () => {\n resolve();\n });\n\n // Don't wait for the browser process\n child.unref();\n });\n}\n"],"names":["playgroundForAgent","agent","options","port","PLAYGROUND_SERVER_PORT","openBrowser","browserCommand","verbose","webPage","Error","console","server","PlaygroundServer","launchedServer","url","openInBrowser","error","customCommand","Promise","resolve","reject","command","args","process","child","spawn"],"mappings":";;;AAwEO,SAASA,mBAAmBC,KAAY;IAC7C,OAAO;QAIL,MAAM,QACJC,UAAmC,CAAC,CAAC;YAErC,MAAM,EACJC,OAAOC,sBAAsB,EAC7BC,cAAc,IAAI,EAClBC,cAAc,EACdC,UAAU,IAAI,EACf,GAAGL;YAGJ,MAAMM,UAAUP,MAAM,SAAS;YAC/B,IAAI,CAACO,SACH,MAAM,IAAIC,MAAM;YAGlB,IAAIF,SAAS;gBACXG,QAAQ,GAAG,CAAC;gBACZA,QAAQ,GAAG,CAAC,CAAC,iBAAU,EAAET,MAAM,WAAW,CAAC,IAAI,EAAE;gBACjDS,QAAQ,GAAG,CAAC,CAAC,wBAAU,EAAEF,QAAQ,WAAW,CAAC,IAAI,EAAE;gBACnDE,QAAQ,GAAG,CAAC,CAAC,gBAAS,EAAEP,MAAM;YAChC;YAGA,MAAMQ,SAAS,IAAIC,SACjBJ,SACAP;YAGF,MAAMY,iBAAkB,MAAMF,OAAO,MAAM,CAACR;YAE5C,IAAII,SACFG,QAAQ,GAAG,CAAC,CAAC,2CAAoC,EAAEP,MAAM;YAG3D,MAAMW,MAAM,CAAC,iBAAiB,EAAEX,MAAM;YAGtC,IAAIE,aACF,MAAMU,cAAcD,KAAKR,gBAAgBC;YAG3C,OAAO;gBACL,QAAQM;gBACRV;gBACA,MAAM;gBACN,OAAO;oBACL,IAAII,SACFG,QAAQ,GAAG,CAAC;oBAGd,IAAI;wBACF,MAAMG,eAAe,KAAK;wBAC1B,IAAIN,SACFG,QAAQ,GAAG,CAAC;oBAEhB,EAAE,OAAOM,OAAO;wBACd,IAAIT,SACFG,QAAQ,KAAK,CAAC,4CAAuCM;wBAEvD,MAAMA;oBACR;gBACF;YACF;QACF;IACF;AACF;AAKA,eAAeD,cACbD,GAAW,EACXG,aAAsB,EACtBV,UAAU,IAAI;IAEd,OAAO,IAAIW,QAAQ,CAACC,SAASC;QAC3B,IAAIC;QACJ,IAAIC;QAEJ,IAAIL,eAAe;YACjBI,UAAUJ;YACVK,OAAO;gBAACR;aAAI;QACd,OAEE,OAAQS,QAAQ,QAAQ;YACtB,KAAK;gBACHF,UAAU;gBACVC,OAAO;oBAACR;iBAAI;gBACZ;YACF,KAAK;gBACHO,UAAU;gBACVC,OAAO;oBAAC;oBAAIR;iBAAI;gBAChB;YACF;gBACEO,UAAU;gBACVC,OAAO;oBAACR;iBAAI;gBACZ;QACJ;QAGF,IAAIP,SACFG,QAAQ,GAAG,CAAC,CAAC,2BAAoB,EAAEW,QAAQ,CAAC,EAAEC,KAAK,IAAI,CAAC,MAAM;QAGhE,MAAME,QAAQC,MAAMJ,SAASC,MAAM;YACjC,UAAU;YACV,OAAO;QACT;QAEAE,MAAM,EAAE,CAAC,SAAS,CAACR;YACjB,IAAIT,SAAS;gBACXG,QAAQ,IAAI,CAAC,uDAA6CM,MAAM,OAAO;gBACvEN,QAAQ,GAAG,CAAC,CAAC,gCAAyB,EAAEI,KAAK;YAC/C;YAEAK;QACF;QAEAK,MAAM,EAAE,CAAC,SAAS;YAChBL;QACF;QAGAK,MAAM,KAAK;IACb;AACF"}
@@ -23,7 +23,9 @@ class PlaygroundSDK {
23
23
  }
24
24
  }
25
25
  async executeAction(actionType, value, options) {
26
- return this.adapter.executeAction(actionType, value, options);
26
+ const result = await this.adapter.executeAction(actionType, value, options);
27
+ if (options.requestId) this.stopProgressPolling(options.requestId);
28
+ return result;
27
29
  }
28
30
  async getActionSpace(context) {
29
31
  return this.adapter.getActionSpace(context);
@@ -52,13 +54,36 @@ class PlaygroundSDK {
52
54
  };
53
55
  }
54
56
  async cancelTask(requestId) {
57
+ this.stopProgressPolling(requestId);
55
58
  if (this.adapter instanceof RemoteExecutionAdapter) return this.adapter.cancelTask(requestId);
56
59
  return {
57
60
  error: 'Cancel task not supported in local execution mode'
58
61
  };
59
62
  }
63
+ onProgressUpdate(callback) {
64
+ this.progressCallback = callback;
65
+ if (this.adapter instanceof RemoteExecutionAdapter) this.adapter.setProgressCallback(callback);
66
+ else if (this.adapter instanceof LocalExecutionAdapter) this.adapter.setProgressCallback(callback);
67
+ }
68
+ startProgressPolling(requestId) {
69
+ console.warn('startProgressPolling is deprecated - polling is now automatic');
70
+ }
71
+ stopProgressPolling(requestId) {
72
+ console.warn('stopProgressPolling is deprecated - polling cleanup is now automatic');
73
+ }
74
+ async cancelExecution(requestId) {
75
+ this.stopProgressPolling(requestId);
76
+ if (this.adapter instanceof RemoteExecutionAdapter) await this.adapter.cancelTask(requestId);
77
+ else if (this.adapter instanceof LocalExecutionAdapter) console.warn('Local execution cancellation not fully implemented');
78
+ }
79
+ async getScreenshot() {
80
+ if (this.adapter instanceof RemoteExecutionAdapter) return this.adapter.getScreenshot();
81
+ return null;
82
+ }
60
83
  constructor(config){
61
84
  _define_property(this, "adapter", void 0);
85
+ _define_property(this, "progressCallback", void 0);
86
+ _define_property(this, "activePolling", new Map());
62
87
  this.adapter = this.createAdapter(config.type, config.serverUrl, config.agent);
63
88
  }
64
89
  }
@@ -1 +1 @@
1
- {"version":3,"file":"sdk/index.mjs","sources":["webpack://@midscene/playground/./src/sdk/index.ts"],"sourcesContent":["import type { DeviceAction } from '@midscene/core';\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 return new RemoteExecutionAdapter(serverUrl);\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 return this.adapter.executeAction(actionType, value, options);\n }\n\n async getActionSpace(context: any): Promise<DeviceAction<unknown>[]> {\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 // 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 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"],"names":["PlaygroundSDK","type","serverUrl","agent","Error","LocalExecutionAdapter","RemoteExecutionAdapter","actionType","value","options","context","action","error","needsStructuredParams","aiConfig","requestId","undefined","config"],"mappings":";;;;;;;;;;;;AAYO,MAAMA;IAWH,cACNC,IAAY,EACZC,SAAkB,EAClBC,KAAuB,EACA;QACvB,OAAQF;YACN,KAAK;gBACH,IAAI,CAACE,OACH,MAAM,IAAIC,MAAM;gBAElB,OAAO,IAAIC,sBAAsBF;YACnC,KAAK;gBACH,OAAO,IAAIG,uBAAuBJ;YACpC;gBACE,MAAM,IAAIE,MAAM,CAAC,4BAA4B,EAAEH,MAAM;QACzD;IACF;IAEA,MAAM,cACJM,UAAkB,EAClBC,KAAgB,EAChBC,OAAyB,EACP;QAClB,OAAO,IAAI,CAAC,OAAO,CAAC,aAAa,CAACF,YAAYC,OAAOC;IACvD;IAEA,MAAM,eAAeC,OAAY,EAAoC;QACnE,OAAO,IAAI,CAAC,OAAO,CAAC,cAAc,CAACA;IACrC;IAEA,yBACEF,KAAgB,EAChBG,MAAyC,EACvB;QAClB,OAAO,IAAI,CAAC,OAAO,CAAC,cAAc,CAACH,OAAOG;IAC5C;IAEA,mBAAmBC,KAAU,EAAU;QACrC,OAAO,IAAI,CAAC,OAAO,CAAC,kBAAkB,CAACA;IACzC;IAEA,qBACEJ,KAAgB,EAChBK,qBAA8B,EAC9BF,MAAyC,EACjC;QACR,OAAO,IAAI,CAAC,OAAO,CAAC,oBAAoB,CACtCH,OACAK,uBACAF;IAEJ;IAGA,MAAM,cAAgC;QACpC,IAAI,IAAI,CAAC,OAAO,YAAYL,wBAC1B,OAAO,IAAI,CAAC,OAAO,CAAC,WAAW;QAEjC,OAAO;IACT;IAEA,MAAM,eAAeQ,QAAa,EAAiB;QACjD,IAAI,IAAI,CAAC,OAAO,YAAYR,wBAC1B,OAAO,IAAI,CAAC,OAAO,CAAC,cAAc,CAACQ;IAGvC;IAEA,MAAM,gBAAgBC,SAAiB,EAA6B;QAClE,IAAI,IAAI,CAAC,OAAO,YAAYT,wBAC1B,OAAO,IAAI,CAAC,OAAO,CAAC,eAAe,CAACS;QAEtC,IAAI,IAAI,CAAC,OAAO,YAAYV,uBAC1B,OAAO,IAAI,CAAC,OAAO,CAAC,eAAe,CAACU;QAEtC,OAAO;YAAE,KAAKC;QAAU;IAC1B;IAGA,MAAM,WAAWD,SAAiB,EAAgB;QAChD,IAAI,IAAI,CAAC,OAAO,YAAYT,wBAC1B,OAAO,IAAI,CAAC,OAAO,CAAC,UAAU,CAACS;QAEjC,OAAO;YAAE,OAAO;QAAoD;IACtE;IA5FA,YAAYE,MAAwB,CAAE;QAFtC,uBAAQ,WAAR;QAGE,IAAI,CAAC,OAAO,GAAG,IAAI,CAAC,aAAa,CAC/BA,OAAO,IAAI,EACXA,OAAO,SAAS,EAChBA,OAAO,KAAK;IAEhB;AAuFF"}
1
+ {"version":3,"file":"sdk/index.mjs","sources":["webpack://@midscene/playground/./src/sdk/index.ts"],"sourcesContent":["import type { DeviceAction } from '@midscene/core';\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 private progressCallback?: (tip: string) => void;\n private activePolling = new Map<\n string,\n { interval: NodeJS.Timeout; callback: (tip: string) => void }\n >();\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 return new RemoteExecutionAdapter(serverUrl);\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 // 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 this.progressCallback = callback;\n\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"],"names":["PlaygroundSDK","type","serverUrl","agent","Error","LocalExecutionAdapter","RemoteExecutionAdapter","actionType","value","options","result","context","action","error","needsStructuredParams","aiConfig","requestId","undefined","callback","console","config","Map"],"mappings":"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"}