@midscene/playground 1.0.1-beta-20251209112631.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 +45 -31
  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 +45 -31
  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 +11 -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.7fc783ce.css +0 -2
  29. package/static/static/css/index.7fc783ce.css.map +0 -1
  30. package/static/static/js/index.7cdfccfc.js +0 -10
  31. package/static/static/js/index.7cdfccfc.js.map +0 -1
  32. /package/static/static/js/{index.7cdfccfc.js.LICENSE.txt → index.0f473725.js.LICENSE.txt} +0 -0
@@ -1 +1 @@
1
- {"version":3,"file":"sdk/index.js","sources":["webpack/runtime/define_property_getters","webpack/runtime/has_own_property","webpack/runtime/make_namespace_object","../../../src/sdk/index.ts"],"sourcesContent":["__webpack_require__.d = (exports, definition) => {\n\tfor(var key in definition) {\n if(__webpack_require__.o(definition, key) && !__webpack_require__.o(exports, key)) {\n Object.defineProperty(exports, key, { enumerable: true, get: definition[key] });\n }\n }\n};","__webpack_require__.o = (obj, prop) => (Object.prototype.hasOwnProperty.call(obj, prop))","// define __esModule on exports\n__webpack_require__.r = (exports) => {\n\tif(typeof Symbol !== 'undefined' && Symbol.toStringTag) {\n\t\tObject.defineProperty(exports, Symbol.toStringTag, { value: 'Module' });\n\t}\n\tObject.defineProperty(exports, '__esModule', { value: true });\n};","import type { DeviceAction } 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":["__webpack_require__","definition","key","Object","obj","prop","Symbol","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.js","sources":["webpack/runtime/define_property_getters","webpack/runtime/has_own_property","webpack/runtime/make_namespace_object","../../../src/sdk/index.ts"],"sourcesContent":["__webpack_require__.d = (exports, definition) => {\n\tfor(var key in definition) {\n if(__webpack_require__.o(definition, key) && !__webpack_require__.o(exports, key)) {\n Object.defineProperty(exports, key, { enumerable: true, get: definition[key] });\n }\n }\n};","__webpack_require__.o = (obj, prop) => (Object.prototype.hasOwnProperty.call(obj, prop))","// define __esModule on exports\n__webpack_require__.r = (exports) => {\n\tif(typeof Symbol !== 'undefined' && Symbol.toStringTag) {\n\t\tObject.defineProperty(exports, Symbol.toStringTag, { value: 'Module' });\n\t}\n\tObject.defineProperty(exports, '__esModule', { value: true });\n};","import type { DeviceAction } 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":["__webpack_require__","definition","key","Object","obj","prop","Symbol","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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"}
@@ -42,6 +42,7 @@ __webpack_require__.d(__webpack_exports__, {
42
42
  const external_node_fs_namespaceObject = require("node:fs");
43
43
  const external_node_path_namespaceObject = require("node:path");
44
44
  const external_node_url_namespaceObject = require("node:url");
45
+ const agent_namespaceObject = require("@midscene/core/agent");
45
46
  const utils_namespaceObject = require("@midscene/core/utils");
46
47
  const constants_namespaceObject = require("@midscene/shared/constants");
47
48
  const env_namespaceObject = require("@midscene/shared/env");
@@ -138,8 +139,12 @@ class PlaygroundServer {
138
139
  });
139
140
  this._app.get('/task-progress/:requestId', async (req, res)=>{
140
141
  const { requestId } = req.params;
142
+ const progressMessages = this.taskProgressMessages[requestId] || [];
143
+ const lastMessage = progressMessages.length > 0 ? progressMessages[progressMessages.length - 1] : void 0;
144
+ const tip = lastMessage && 'string' == typeof lastMessage.action ? `${lastMessage.action} - ${lastMessage.description || ''}` : '';
141
145
  res.json({
142
- tip: this.taskProgressTips[requestId] || ''
146
+ tip,
147
+ progressMessages
143
148
  });
144
149
  });
145
150
  this._app.post('/action-space', async (req, res)=>{
@@ -204,9 +209,22 @@ class PlaygroundServer {
204
209
  });
205
210
  if (requestId) {
206
211
  this.currentTaskId = requestId;
207
- this.taskProgressTips[requestId] = '';
208
- this.agent.onTaskStartTip = (tip)=>{
209
- this.taskProgressTips[requestId] = tip;
212
+ this.taskProgressMessages[requestId] = [];
213
+ this.agent.onDumpUpdate = (_dump, executionDump)=>{
214
+ if (executionDump?.tasks) this.taskProgressMessages[requestId] = executionDump.tasks.map((task, index)=>{
215
+ const action = (0, agent_namespaceObject.typeStr)(task);
216
+ const description = (0, agent_namespaceObject.paramStr)(task) || '';
217
+ const taskStatus = task.status;
218
+ const status = 'cancelled' === taskStatus ? 'failed' : taskStatus;
219
+ return {
220
+ id: `progress-task-${index}`,
221
+ taskId: `task-${index}`,
222
+ action,
223
+ description,
224
+ status,
225
+ timestamp: task.timing?.start || Date.now()
226
+ };
227
+ });
210
228
  };
211
229
  }
212
230
  const response = {
@@ -247,7 +265,7 @@ class PlaygroundServer {
247
265
  if (response.error) console.error(`handle request failed after ${timeCost}ms: requestId: ${requestId}, ${response.error}`);
248
266
  else console.log(`handle request done after ${timeCost}ms: requestId: ${requestId}`);
249
267
  if (requestId) {
250
- delete this.taskProgressTips[requestId];
268
+ delete this.taskProgressMessages[requestId];
251
269
  if (this.currentTaskId === requestId) this.currentTaskId = null;
252
270
  }
253
271
  });
@@ -263,7 +281,7 @@ class PlaygroundServer {
263
281
  });
264
282
  console.log(`Cancelling task: ${requestId}`);
265
283
  await this.recreateAgent();
266
- delete this.taskProgressTips[requestId];
284
+ delete this.taskProgressMessages[requestId];
267
285
  this.currentTaskId = null;
268
286
  res.json({
269
287
  status: 'cancelled',
@@ -388,7 +406,7 @@ class PlaygroundServer {
388
406
  } catch (error) {
389
407
  console.warn('Failed to destroy agent:', error);
390
408
  }
391
- this.taskProgressTips = {};
409
+ this.taskProgressMessages = {};
392
410
  this.server.close((error)=>{
393
411
  if (error) reject(error);
394
412
  else {
@@ -406,7 +424,7 @@ class PlaygroundServer {
406
424
  _define_property(this, "port", void 0);
407
425
  _define_property(this, "agent", void 0);
408
426
  _define_property(this, "staticPath", void 0);
409
- _define_property(this, "taskProgressTips", void 0);
427
+ _define_property(this, "taskProgressMessages", void 0);
410
428
  _define_property(this, "id", void 0);
411
429
  _define_property(this, "_initialized", false);
412
430
  _define_property(this, "agentFactory", void 0);
@@ -414,7 +432,7 @@ class PlaygroundServer {
414
432
  this._app = external_express_default()();
415
433
  this.tmpDir = (0, utils_namespaceObject.getTmpDir)();
416
434
  this.staticPath = staticPath;
417
- this.taskProgressTips = {};
435
+ this.taskProgressMessages = {};
418
436
  this.id = id || (0, shared_utils_namespaceObject.uuid)();
419
437
  if ('function' == typeof agent) {
420
438
  this.agentFactory = agent;
@@ -1 +1 @@
1
- {"version":3,"file":"server.js","sources":["webpack/runtime/compat_get_default_export","webpack/runtime/define_property_getters","webpack/runtime/has_own_property","webpack/runtime/make_namespace_object","../../src/server.ts"],"sourcesContent":["// getDefaultExport function for compatibility with non-ESM modules\n__webpack_require__.n = (module) => {\n\tvar getter = module && module.__esModule ?\n\t\t() => (module['default']) :\n\t\t() => (module);\n\t__webpack_require__.d(getter, { a: getter });\n\treturn getter;\n};\n","__webpack_require__.d = (exports, definition) => {\n\tfor(var key in definition) {\n if(__webpack_require__.o(definition, key) && !__webpack_require__.o(exports, key)) {\n Object.defineProperty(exports, key, { enumerable: true, get: definition[key] });\n }\n }\n};","__webpack_require__.o = (obj, prop) => (Object.prototype.hasOwnProperty.call(obj, prop))","// define __esModule on exports\n__webpack_require__.r = (exports) => {\n\tif(typeof Symbol !== 'undefined' && Symbol.toStringTag) {\n\t\tObject.defineProperty(exports, Symbol.toStringTag, { value: 'Module' });\n\t}\n\tObject.defineProperty(exports, '__esModule', { value: true });\n};","import { existsSync, readFileSync, writeFileSync } from 'node:fs';\nimport type { Server } from 'node:http';\nimport { dirname, join } from 'node:path';\nimport { fileURLToPath } from 'node:url';\nimport type { Agent as PageAgent } from '@midscene/core/agent';\nimport { getTmpDir } from '@midscene/core/utils';\nimport { PLAYGROUND_SERVER_PORT } from '@midscene/shared/constants';\nimport { overrideAIConfig } from '@midscene/shared/env';\nimport { uuid } from '@midscene/shared/utils';\nimport express, { type Request, type Response } from 'express';\nimport { executeAction, formatErrorMessage } from './common';\n\nimport 'dotenv/config';\n\nconst defaultPort = PLAYGROUND_SERVER_PORT;\n\n// Static path for playground files\nconst __filename = fileURLToPath(import.meta.url);\nconst __dirname = dirname(__filename);\nconst STATIC_PATH = join(__dirname, '..', '..', 'static');\n\nconst errorHandler = (\n err: unknown,\n req: Request,\n res: Response,\n next: express.NextFunction,\n) => {\n console.error(err);\n const errorMessage =\n err instanceof Error ? err.message : 'Internal server error';\n res.status(500).json({\n error: errorMessage,\n });\n};\n\nclass PlaygroundServer {\n private _app: express.Application;\n tmpDir: string;\n server?: Server;\n port?: number | null;\n agent: PageAgent;\n staticPath: string;\n taskProgressTips: Record<string, string>;\n id: string; // Unique identifier for this server instance\n\n private _initialized = false;\n\n // Factory function for recreating agent\n private agentFactory?: (() => PageAgent | Promise<PageAgent>) | null;\n\n // Track current running task\n private currentTaskId: string | null = null;\n\n constructor(\n agent: PageAgent | (() => PageAgent) | (() => Promise<PageAgent>),\n staticPath = STATIC_PATH,\n id?: string, // Optional override ID\n ) {\n this._app = express();\n this.tmpDir = getTmpDir()!;\n this.staticPath = staticPath;\n this.taskProgressTips = {};\n // Use provided ID, or generate random UUID for each startup\n this.id = id || uuid();\n\n // Support both instance and factory function modes\n if (typeof agent === 'function') {\n this.agentFactory = agent;\n this.agent = null as any; // Will be initialized in launch()\n } else {\n this.agent = agent;\n this.agentFactory = null;\n }\n }\n\n /**\n * Get the Express app instance for custom configuration\n *\n * IMPORTANT: Add middleware (like CORS) BEFORE calling launch()\n * The routes are initialized when launch() is called, so middleware\n * added after launch() will not affect the API routes.\n *\n * @example\n * ```typescript\n * import cors from 'cors';\n *\n * const server = new PlaygroundServer(agent);\n *\n * // Add CORS middleware before launch\n * server.app.use(cors({\n * origin: true,\n * credentials: true,\n * methods: ['GET', 'POST', 'PUT', 'DELETE', 'OPTIONS']\n * }));\n *\n * await server.launch();\n * ```\n */\n get app(): express.Application {\n return this._app;\n }\n\n /**\n * Initialize Express app with all routes and middleware\n * Called automatically by launch() if not already initialized\n */\n private initializeApp(): void {\n if (this._initialized) return;\n\n // Built-in middleware to parse JSON bodies\n this._app.use(express.json({ limit: '50mb' }));\n\n // Context update middleware (after JSON parsing)\n this._app.use(\n (req: Request, _res: Response, next: express.NextFunction) => {\n const { context } = req.body || {};\n if (\n context &&\n 'updateContext' in this.agent.interface &&\n typeof this.agent.interface.updateContext === 'function'\n ) {\n this.agent.interface.updateContext(context);\n console.log('Context updated by PlaygroundServer middleware');\n }\n next();\n },\n );\n\n // NOTE: CORS middleware should be added externally via server.app.use()\n // before calling server.launch() if needed\n\n // API routes\n this.setupRoutes();\n\n // Static file serving (if staticPath is provided)\n this.setupStaticRoutes();\n\n // Error handler middleware (must be last)\n this._app.use(errorHandler);\n\n this._initialized = true;\n }\n\n filePathForUuid(uuid: string) {\n return join(this.tmpDir, `${uuid}.json`);\n }\n\n saveContextFile(uuid: string, context: string) {\n const tmpFile = this.filePathForUuid(uuid);\n console.log(`save context file: ${tmpFile}`);\n writeFileSync(tmpFile, context);\n return tmpFile;\n }\n\n /**\n * Recreate agent instance (for cancellation)\n */\n private async recreateAgent(): Promise<void> {\n if (!this.agentFactory) {\n console.warn(\n 'Cannot recreate agent: factory function not provided. Agent recreation is only available when using factory mode.',\n );\n return;\n }\n\n console.log('Recreating agent to cancel current task...');\n\n // Destroy old agent instance\n try {\n if (this.agent && typeof this.agent.destroy === 'function') {\n await this.agent.destroy();\n }\n } catch (error) {\n console.warn('Failed to destroy old agent:', error);\n }\n\n // Create new agent instance\n try {\n this.agent = await this.agentFactory();\n console.log('Agent recreated successfully');\n } catch (error) {\n console.error('Failed to recreate agent:', error);\n throw error;\n }\n }\n\n /**\n * Setup all API routes\n */\n private setupRoutes(): void {\n this._app.get('/status', async (req: Request, res: Response) => {\n res.send({\n status: 'ok',\n id: this.id,\n });\n });\n\n this._app.get('/context/:uuid', async (req: Request, res: Response) => {\n const { uuid } = req.params;\n const contextFile = this.filePathForUuid(uuid);\n\n if (!existsSync(contextFile)) {\n return res.status(404).json({\n error: 'Context not found',\n });\n }\n\n const context = readFileSync(contextFile, 'utf8');\n res.json({\n context,\n });\n });\n\n this._app.get(\n '/task-progress/:requestId',\n async (req: Request, res: Response) => {\n const { requestId } = req.params;\n res.json({\n tip: this.taskProgressTips[requestId] || '',\n });\n },\n );\n\n this._app.post('/action-space', async (req: Request, res: Response) => {\n try {\n let actionSpace = [];\n\n actionSpace = this.agent.interface.actionSpace();\n\n // Process actionSpace to make paramSchema serializable with shape info\n const processedActionSpace = actionSpace.map((action: unknown) => {\n if (action && typeof action === 'object' && 'paramSchema' in action) {\n const typedAction = action as {\n paramSchema?: { shape?: object; [key: string]: unknown };\n [key: string]: unknown;\n };\n if (\n typedAction.paramSchema &&\n typeof typedAction.paramSchema === 'object'\n ) {\n // Extract shape information from Zod schema\n let processedSchema = null;\n\n try {\n // Extract shape from runtime Zod object\n if (\n typedAction.paramSchema.shape &&\n typeof typedAction.paramSchema.shape === 'object'\n ) {\n processedSchema = {\n type: 'ZodObject',\n shape: typedAction.paramSchema.shape,\n };\n }\n } catch (e) {\n const actionName =\n 'name' in typedAction && typeof typedAction.name === 'string'\n ? typedAction.name\n : 'unknown';\n console.warn(\n 'Failed to process paramSchema for action:',\n actionName,\n e,\n );\n }\n\n return {\n ...typedAction,\n paramSchema: processedSchema,\n };\n }\n }\n return action;\n });\n\n res.json(processedActionSpace);\n } catch (error: unknown) {\n const errorMessage =\n error instanceof Error ? error.message : 'Unknown error';\n console.error('Failed to get action space:', error);\n res.status(500).json({\n error: errorMessage,\n });\n }\n });\n\n // -------------------------\n // actions from report file\n this._app.post(\n '/playground-with-context',\n async (req: Request, res: Response) => {\n const context = req.body.context;\n\n if (!context) {\n return res.status(400).json({\n error: 'context is required',\n });\n }\n\n const requestId = uuid();\n this.saveContextFile(requestId, context);\n return res.json({\n location: `/playground/${requestId}`,\n uuid: requestId,\n });\n },\n );\n\n this._app.post('/execute', async (req: Request, res: Response) => {\n const {\n type,\n prompt,\n params,\n requestId,\n deepThink,\n screenshotIncluded,\n domIncluded,\n deviceOptions,\n } = req.body;\n\n if (!type) {\n return res.status(400).json({\n error: 'type is required',\n });\n }\n\n // Update device options if provided\n if (\n deviceOptions &&\n this.agent.interface &&\n 'options' in this.agent.interface\n ) {\n this.agent.interface.options = {\n ...(this.agent.interface.options || {}),\n ...deviceOptions,\n };\n }\n\n // Check if another task is running\n if (this.currentTaskId) {\n return res.status(409).json({\n error: 'Another task is already running',\n currentTaskId: this.currentTaskId,\n });\n }\n\n // Lock this task\n if (requestId) {\n this.currentTaskId = requestId;\n this.taskProgressTips[requestId] = '';\n\n this.agent.onTaskStartTip = (tip: string) => {\n this.taskProgressTips[requestId] = tip;\n };\n }\n\n const response: {\n result: unknown;\n dump: string | null;\n error: string | null;\n reportHTML: string | null;\n requestId?: string;\n } = {\n result: null,\n dump: null,\n error: null,\n reportHTML: null,\n requestId,\n };\n\n const startTime = Date.now();\n try {\n // Get action space to check for dynamic actions\n const actionSpace = this.agent.interface.actionSpace();\n\n // Prepare value object for executeAction\n const value = {\n type,\n prompt,\n params,\n };\n\n response.result = await executeAction(\n this.agent,\n type,\n actionSpace,\n value,\n {\n deepThink,\n screenshotIncluded,\n domIncluded,\n deviceOptions,\n },\n );\n } catch (error: unknown) {\n response.error = formatErrorMessage(error);\n }\n\n try {\n response.dump = JSON.parse(this.agent.dumpDataString());\n response.reportHTML = this.agent.reportHTMLString() || null;\n\n this.agent.writeOutActionDumps();\n this.agent.resetDump();\n } catch (error: unknown) {\n const errorMessage =\n error instanceof Error ? error.message : 'Unknown error';\n console.error(\n `write out dump failed: requestId: ${requestId}, ${errorMessage}`,\n );\n }\n\n res.send(response);\n const timeCost = Date.now() - startTime;\n\n if (response.error) {\n console.error(\n `handle request failed after ${timeCost}ms: requestId: ${requestId}, ${response.error}`,\n );\n } else {\n console.log(\n `handle request done after ${timeCost}ms: requestId: ${requestId}`,\n );\n }\n\n // Clean up task progress tip and unlock after execution completes\n if (requestId) {\n delete this.taskProgressTips[requestId];\n // Release the lock\n if (this.currentTaskId === requestId) {\n this.currentTaskId = null;\n }\n }\n });\n\n this._app.post(\n '/cancel/:requestId',\n async (req: Request, res: Response) => {\n const { requestId } = req.params;\n\n if (!requestId) {\n return res.status(400).json({\n error: 'requestId is required',\n });\n }\n\n try {\n // Check if this is the current running task\n if (this.currentTaskId !== requestId) {\n return res.json({\n status: 'not_found',\n message: 'Task not found or already completed',\n });\n }\n\n console.log(`Cancelling task: ${requestId}`);\n\n // Recreate agent to cancel the current task\n await this.recreateAgent();\n\n // Clean up\n delete this.taskProgressTips[requestId];\n this.currentTaskId = null;\n\n res.json({\n status: 'cancelled',\n message: 'Task cancelled successfully by recreating agent',\n });\n } catch (error: unknown) {\n const errorMessage =\n error instanceof Error ? error.message : 'Unknown error';\n console.error(`Failed to cancel: ${errorMessage}`);\n res.status(500).json({\n error: `Failed to cancel: ${errorMessage}`,\n });\n }\n },\n );\n\n // Screenshot API for real-time screenshot polling\n this._app.get('/screenshot', async (_req: Request, res: Response) => {\n try {\n // Check if page has screenshotBase64 method\n if (typeof this.agent.interface.screenshotBase64 !== 'function') {\n return res.status(500).json({\n error: 'Screenshot method not available on current interface',\n });\n }\n\n const base64Screenshot = await this.agent.interface.screenshotBase64();\n\n res.json({\n screenshot: base64Screenshot,\n timestamp: Date.now(),\n });\n } catch (error: unknown) {\n const errorMessage =\n error instanceof Error ? error.message : 'Unknown error';\n console.error(`Failed to take screenshot: ${errorMessage}`);\n res.status(500).json({\n error: `Failed to take screenshot: ${errorMessage}`,\n });\n }\n });\n\n // Interface info API for getting interface type and description\n this._app.get('/interface-info', async (_req: Request, res: Response) => {\n try {\n const type = this.agent.interface.interfaceType || 'Unknown';\n const description = this.agent.interface.describe?.() || undefined;\n\n res.json({\n type,\n description,\n });\n } catch (error: unknown) {\n const errorMessage =\n error instanceof Error ? error.message : 'Unknown error';\n console.error(`Failed to get interface info: ${errorMessage}`);\n res.status(500).json({\n error: `Failed to get interface info: ${errorMessage}`,\n });\n }\n });\n\n this.app.post('/config', async (req: Request, res: Response) => {\n const { aiConfig } = req.body;\n\n if (!aiConfig || typeof aiConfig !== 'object') {\n return res.status(400).json({\n error: 'aiConfig is required and must be an object',\n });\n }\n\n if (Object.keys(aiConfig).length === 0) {\n return res.json({\n status: 'ok',\n message: 'AI config not changed due to empty object',\n });\n }\n\n try {\n overrideAIConfig(aiConfig);\n\n return res.json({\n status: 'ok',\n message: 'AI config updated successfully',\n });\n } catch (error: unknown) {\n const errorMessage =\n error instanceof Error ? error.message : 'Unknown error';\n console.error(`Failed to update AI config: ${errorMessage}`);\n return res.status(500).json({\n error: `Failed to update AI config: ${errorMessage}`,\n });\n }\n });\n }\n\n /**\n * Setup static file serving routes\n */\n private setupStaticRoutes(): void {\n // Handle index.html with port injection\n this._app.get('/', (_req: Request, res: Response) => {\n this.serveHtmlWithPorts(res);\n });\n\n this._app.get('/index.html', (_req: Request, res: Response) => {\n this.serveHtmlWithPorts(res);\n });\n\n // Use express.static middleware for secure static file serving\n this._app.use(express.static(this.staticPath));\n\n // Fallback to index.html for SPA routing\n this._app.get('*', (_req: Request, res: Response) => {\n this.serveHtmlWithPorts(res);\n });\n }\n\n /**\n * Serve HTML with injected port configuration\n */\n private serveHtmlWithPorts(res: Response): void {\n try {\n const htmlPath = join(this.staticPath, 'index.html');\n let html = readFileSync(htmlPath, 'utf8');\n\n // Get scrcpy server port from global\n const scrcpyPort = (global as any).scrcpyServerPort || this.port! + 1;\n\n // Inject scrcpy port configuration script into HTML head\n const configScript = `\n <script>\n window.SCRCPY_PORT = ${scrcpyPort};\n </script>\n `;\n\n // Insert the script before closing </head> tag\n html = html.replace('</head>', `${configScript}</head>`);\n\n res.setHeader('Content-Type', 'text/html');\n res.send(html);\n } catch (error) {\n console.error('Error serving HTML with ports:', error);\n res.status(500).send('Internal Server Error');\n }\n }\n\n /**\n * Launch the server on specified port\n */\n async launch(port?: number): Promise<PlaygroundServer> {\n // If using factory mode, initialize agent\n if (this.agentFactory) {\n console.log('Initializing agent from factory function...');\n this.agent = await this.agentFactory();\n console.log('Agent initialized successfully');\n }\n\n // Initialize routes now, after any middleware has been added\n this.initializeApp();\n\n this.port = port || defaultPort;\n\n return new Promise((resolve) => {\n const serverPort = this.port;\n this.server = this._app.listen(serverPort, () => {\n resolve(this);\n });\n });\n }\n\n /**\n * Close the server and clean up resources\n */\n async close(): Promise<void> {\n return new Promise((resolve, reject) => {\n if (this.server) {\n // Clean up the single agent\n try {\n this.agent.destroy();\n } catch (error) {\n console.warn('Failed to destroy agent:', error);\n }\n this.taskProgressTips = {};\n\n // Close the server\n this.server.close((error) => {\n if (error) {\n reject(error);\n } else {\n this.server = undefined;\n resolve();\n }\n });\n } else {\n resolve();\n }\n });\n }\n}\n\nexport default PlaygroundServer;\nexport { PlaygroundServer };\n"],"names":["__webpack_require__","module","getter","definition","key","Object","obj","prop","Symbol","defaultPort","PLAYGROUND_SERVER_PORT","__filename","fileURLToPath","__dirname","dirname","STATIC_PATH","join","errorHandler","err","req","res","next","console","errorMessage","Error","PlaygroundServer","express","_res","context","uuid","tmpFile","writeFileSync","error","contextFile","existsSync","readFileSync","requestId","actionSpace","processedActionSpace","action","typedAction","processedSchema","e","actionName","type","prompt","params","deepThink","screenshotIncluded","domIncluded","deviceOptions","tip","response","startTime","Date","value","executeAction","formatErrorMessage","JSON","timeCost","_req","base64Screenshot","description","undefined","aiConfig","overrideAIConfig","htmlPath","html","scrcpyPort","global","configScript","port","Promise","resolve","serverPort","reject","agent","staticPath","id","getTmpDir"],"mappings":"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"}
1
+ {"version":3,"file":"server.js","sources":["webpack/runtime/compat_get_default_export","webpack/runtime/define_property_getters","webpack/runtime/has_own_property","webpack/runtime/make_namespace_object","../../src/server.ts"],"sourcesContent":["// getDefaultExport function for compatibility with non-ESM modules\n__webpack_require__.n = (module) => {\n\tvar getter = module && module.__esModule ?\n\t\t() => (module['default']) :\n\t\t() => (module);\n\t__webpack_require__.d(getter, { a: getter });\n\treturn getter;\n};\n","__webpack_require__.d = (exports, definition) => {\n\tfor(var key in definition) {\n if(__webpack_require__.o(definition, key) && !__webpack_require__.o(exports, key)) {\n Object.defineProperty(exports, key, { enumerable: true, get: definition[key] });\n }\n }\n};","__webpack_require__.o = (obj, prop) => (Object.prototype.hasOwnProperty.call(obj, prop))","// define __esModule on exports\n__webpack_require__.r = (exports) => {\n\tif(typeof Symbol !== 'undefined' && Symbol.toStringTag) {\n\t\tObject.defineProperty(exports, Symbol.toStringTag, { value: 'Module' });\n\t}\n\tObject.defineProperty(exports, '__esModule', { value: true });\n};","import { existsSync, readFileSync, writeFileSync } from 'node:fs';\nimport type { Server } from 'node:http';\nimport { dirname, join } from 'node:path';\nimport { fileURLToPath } from 'node:url';\nimport type { ExecutionDump } from '@midscene/core';\nimport type { Agent as PageAgent } from '@midscene/core/agent';\nimport { paramStr, typeStr } from '@midscene/core/agent';\nimport { getTmpDir } from '@midscene/core/utils';\nimport { PLAYGROUND_SERVER_PORT } from '@midscene/shared/constants';\nimport { overrideAIConfig } from '@midscene/shared/env';\nimport { uuid } from '@midscene/shared/utils';\nimport express, { type Request, type Response } from 'express';\nimport { executeAction, formatErrorMessage } from './common';\nimport type { ProgressMessage } from './types';\n\nimport 'dotenv/config';\n\nconst defaultPort = PLAYGROUND_SERVER_PORT;\n\n// Static path for playground files\nconst __filename = fileURLToPath(import.meta.url);\nconst __dirname = dirname(__filename);\nconst STATIC_PATH = join(__dirname, '..', '..', 'static');\n\nconst errorHandler = (\n err: unknown,\n req: Request,\n res: Response,\n next: express.NextFunction,\n) => {\n console.error(err);\n const errorMessage =\n err instanceof Error ? err.message : 'Internal server error';\n res.status(500).json({\n error: errorMessage,\n });\n};\n\nclass PlaygroundServer {\n private _app: express.Application;\n tmpDir: string;\n server?: Server;\n port?: number | null;\n agent: PageAgent;\n staticPath: string;\n taskProgressMessages: Record<string, ProgressMessage[]>; // Store full progress messages array\n id: string; // Unique identifier for this server instance\n\n private _initialized = false;\n\n // Factory function for recreating agent\n private agentFactory?: (() => PageAgent | Promise<PageAgent>) | null;\n\n // Track current running task\n private currentTaskId: string | null = null;\n\n constructor(\n agent: PageAgent | (() => PageAgent) | (() => Promise<PageAgent>),\n staticPath = STATIC_PATH,\n id?: string, // Optional override ID\n ) {\n this._app = express();\n this.tmpDir = getTmpDir()!;\n this.staticPath = staticPath;\n this.taskProgressMessages = {}; // Initialize as empty object\n // Use provided ID, or generate random UUID for each startup\n this.id = id || uuid();\n\n // Support both instance and factory function modes\n if (typeof agent === 'function') {\n this.agentFactory = agent;\n this.agent = null as any; // Will be initialized in launch()\n } else {\n this.agent = agent;\n this.agentFactory = null;\n }\n }\n\n /**\n * Get the Express app instance for custom configuration\n *\n * IMPORTANT: Add middleware (like CORS) BEFORE calling launch()\n * The routes are initialized when launch() is called, so middleware\n * added after launch() will not affect the API routes.\n *\n * @example\n * ```typescript\n * import cors from 'cors';\n *\n * const server = new PlaygroundServer(agent);\n *\n * // Add CORS middleware before launch\n * server.app.use(cors({\n * origin: true,\n * credentials: true,\n * methods: ['GET', 'POST', 'PUT', 'DELETE', 'OPTIONS']\n * }));\n *\n * await server.launch();\n * ```\n */\n get app(): express.Application {\n return this._app;\n }\n\n /**\n * Initialize Express app with all routes and middleware\n * Called automatically by launch() if not already initialized\n */\n private initializeApp(): void {\n if (this._initialized) return;\n\n // Built-in middleware to parse JSON bodies\n this._app.use(express.json({ limit: '50mb' }));\n\n // Context update middleware (after JSON parsing)\n this._app.use(\n (req: Request, _res: Response, next: express.NextFunction) => {\n const { context } = req.body || {};\n if (\n context &&\n 'updateContext' in this.agent.interface &&\n typeof this.agent.interface.updateContext === 'function'\n ) {\n this.agent.interface.updateContext(context);\n console.log('Context updated by PlaygroundServer middleware');\n }\n next();\n },\n );\n\n // NOTE: CORS middleware should be added externally via server.app.use()\n // before calling server.launch() if needed\n\n // API routes\n this.setupRoutes();\n\n // Static file serving (if staticPath is provided)\n this.setupStaticRoutes();\n\n // Error handler middleware (must be last)\n this._app.use(errorHandler);\n\n this._initialized = true;\n }\n\n filePathForUuid(uuid: string) {\n return join(this.tmpDir, `${uuid}.json`);\n }\n\n saveContextFile(uuid: string, context: string) {\n const tmpFile = this.filePathForUuid(uuid);\n console.log(`save context file: ${tmpFile}`);\n writeFileSync(tmpFile, context);\n return tmpFile;\n }\n\n /**\n * Recreate agent instance (for cancellation)\n */\n private async recreateAgent(): Promise<void> {\n if (!this.agentFactory) {\n console.warn(\n 'Cannot recreate agent: factory function not provided. Agent recreation is only available when using factory mode.',\n );\n return;\n }\n\n console.log('Recreating agent to cancel current task...');\n\n // Destroy old agent instance\n try {\n if (this.agent && typeof this.agent.destroy === 'function') {\n await this.agent.destroy();\n }\n } catch (error) {\n console.warn('Failed to destroy old agent:', error);\n }\n\n // Create new agent instance\n try {\n this.agent = await this.agentFactory();\n console.log('Agent recreated successfully');\n } catch (error) {\n console.error('Failed to recreate agent:', error);\n throw error;\n }\n }\n\n /**\n * Setup all API routes\n */\n private setupRoutes(): void {\n this._app.get('/status', async (req: Request, res: Response) => {\n res.send({\n status: 'ok',\n id: this.id,\n });\n });\n\n this._app.get('/context/:uuid', async (req: Request, res: Response) => {\n const { uuid } = req.params;\n const contextFile = this.filePathForUuid(uuid);\n\n if (!existsSync(contextFile)) {\n return res.status(404).json({\n error: 'Context not found',\n });\n }\n\n const context = readFileSync(contextFile, 'utf8');\n res.json({\n context,\n });\n });\n\n this._app.get(\n '/task-progress/:requestId',\n async (req: Request, res: Response) => {\n const { requestId } = req.params;\n const progressMessages = this.taskProgressMessages[requestId] || [];\n // For backward compatibility, also provide a tip string from the last message\n const lastMessage =\n progressMessages.length > 0\n ? progressMessages[progressMessages.length - 1]\n : undefined;\n const tip =\n lastMessage && typeof lastMessage.action === 'string'\n ? `${lastMessage.action} - ${lastMessage.description || ''}`\n : '';\n res.json({\n tip,\n progressMessages, // Provide full progress messages array\n });\n },\n );\n\n this._app.post('/action-space', async (req: Request, res: Response) => {\n try {\n let actionSpace = [];\n\n actionSpace = this.agent.interface.actionSpace();\n\n // Process actionSpace to make paramSchema serializable with shape info\n const processedActionSpace = actionSpace.map((action: unknown) => {\n if (action && typeof action === 'object' && 'paramSchema' in action) {\n const typedAction = action as {\n paramSchema?: { shape?: object; [key: string]: unknown };\n [key: string]: unknown;\n };\n if (\n typedAction.paramSchema &&\n typeof typedAction.paramSchema === 'object'\n ) {\n // Extract shape information from Zod schema\n let processedSchema = null;\n\n try {\n // Extract shape from runtime Zod object\n if (\n typedAction.paramSchema.shape &&\n typeof typedAction.paramSchema.shape === 'object'\n ) {\n processedSchema = {\n type: 'ZodObject',\n shape: typedAction.paramSchema.shape,\n };\n }\n } catch (e) {\n const actionName =\n 'name' in typedAction && typeof typedAction.name === 'string'\n ? typedAction.name\n : 'unknown';\n console.warn(\n 'Failed to process paramSchema for action:',\n actionName,\n e,\n );\n }\n\n return {\n ...typedAction,\n paramSchema: processedSchema,\n };\n }\n }\n return action;\n });\n\n res.json(processedActionSpace);\n } catch (error: unknown) {\n const errorMessage =\n error instanceof Error ? error.message : 'Unknown error';\n console.error('Failed to get action space:', error);\n res.status(500).json({\n error: errorMessage,\n });\n }\n });\n\n // -------------------------\n // actions from report file\n this._app.post(\n '/playground-with-context',\n async (req: Request, res: Response) => {\n const context = req.body.context;\n\n if (!context) {\n return res.status(400).json({\n error: 'context is required',\n });\n }\n\n const requestId = uuid();\n this.saveContextFile(requestId, context);\n return res.json({\n location: `/playground/${requestId}`,\n uuid: requestId,\n });\n },\n );\n\n this._app.post('/execute', async (req: Request, res: Response) => {\n const {\n type,\n prompt,\n params,\n requestId,\n deepThink,\n screenshotIncluded,\n domIncluded,\n deviceOptions,\n } = req.body;\n\n if (!type) {\n return res.status(400).json({\n error: 'type is required',\n });\n }\n\n // Update device options if provided\n if (\n deviceOptions &&\n this.agent.interface &&\n 'options' in this.agent.interface\n ) {\n this.agent.interface.options = {\n ...(this.agent.interface.options || {}),\n ...deviceOptions,\n };\n }\n\n // Check if another task is running\n if (this.currentTaskId) {\n return res.status(409).json({\n error: 'Another task is already running',\n currentTaskId: this.currentTaskId,\n });\n }\n\n // Lock this task\n if (requestId) {\n this.currentTaskId = requestId;\n this.taskProgressMessages[requestId] = [];\n\n // Use onDumpUpdate to receive executionDump and transform tasks to progress messages\n this.agent.onDumpUpdate = (\n _dump: string,\n executionDump?: ExecutionDump,\n ) => {\n if (executionDump?.tasks) {\n // Transform executionDump.tasks to ProgressMessage[] for API compatibility\n this.taskProgressMessages[requestId] = executionDump.tasks.map(\n (task, index) => {\n const action = typeStr(task);\n const description = paramStr(task) || '';\n\n // Map task status\n const taskStatus = task.status;\n const status: 'pending' | 'running' | 'finished' | 'failed' =\n taskStatus === 'cancelled' ? 'failed' : taskStatus;\n\n return {\n id: `progress-task-${index}`,\n taskId: `task-${index}`,\n action,\n description,\n status,\n timestamp: task.timing?.start || Date.now(),\n };\n },\n );\n }\n };\n }\n\n const response: {\n result: unknown;\n dump: string | null;\n error: string | null;\n reportHTML: string | null;\n requestId?: string;\n } = {\n result: null,\n dump: null,\n error: null,\n reportHTML: null,\n requestId,\n };\n\n const startTime = Date.now();\n try {\n // Get action space to check for dynamic actions\n const actionSpace = this.agent.interface.actionSpace();\n\n // Prepare value object for executeAction\n const value = {\n type,\n prompt,\n params,\n };\n\n response.result = await executeAction(\n this.agent,\n type,\n actionSpace,\n value,\n {\n deepThink,\n screenshotIncluded,\n domIncluded,\n deviceOptions,\n },\n );\n } catch (error: unknown) {\n response.error = formatErrorMessage(error);\n }\n\n try {\n response.dump = JSON.parse(this.agent.dumpDataString());\n response.reportHTML = this.agent.reportHTMLString() || null;\n\n this.agent.writeOutActionDumps();\n this.agent.resetDump();\n } catch (error: unknown) {\n const errorMessage =\n error instanceof Error ? error.message : 'Unknown error';\n console.error(\n `write out dump failed: requestId: ${requestId}, ${errorMessage}`,\n );\n }\n\n res.send(response);\n const timeCost = Date.now() - startTime;\n\n if (response.error) {\n console.error(\n `handle request failed after ${timeCost}ms: requestId: ${requestId}, ${response.error}`,\n );\n } else {\n console.log(\n `handle request done after ${timeCost}ms: requestId: ${requestId}`,\n );\n }\n\n // Clean up task progress messages and unlock after execution completes\n if (requestId) {\n delete this.taskProgressMessages[requestId];\n // Release the lock\n if (this.currentTaskId === requestId) {\n this.currentTaskId = null;\n }\n }\n });\n\n this._app.post(\n '/cancel/:requestId',\n async (req: Request, res: Response) => {\n const { requestId } = req.params;\n\n if (!requestId) {\n return res.status(400).json({\n error: 'requestId is required',\n });\n }\n\n try {\n // Check if this is the current running task\n if (this.currentTaskId !== requestId) {\n return res.json({\n status: 'not_found',\n message: 'Task not found or already completed',\n });\n }\n\n console.log(`Cancelling task: ${requestId}`);\n\n // Recreate agent to cancel the current task\n await this.recreateAgent();\n\n // Clean up\n delete this.taskProgressMessages[requestId];\n this.currentTaskId = null;\n\n res.json({\n status: 'cancelled',\n message: 'Task cancelled successfully by recreating agent',\n });\n } catch (error: unknown) {\n const errorMessage =\n error instanceof Error ? error.message : 'Unknown error';\n console.error(`Failed to cancel: ${errorMessage}`);\n res.status(500).json({\n error: `Failed to cancel: ${errorMessage}`,\n });\n }\n },\n );\n\n // Screenshot API for real-time screenshot polling\n this._app.get('/screenshot', async (_req: Request, res: Response) => {\n try {\n // Check if page has screenshotBase64 method\n if (typeof this.agent.interface.screenshotBase64 !== 'function') {\n return res.status(500).json({\n error: 'Screenshot method not available on current interface',\n });\n }\n\n const base64Screenshot = await this.agent.interface.screenshotBase64();\n\n res.json({\n screenshot: base64Screenshot,\n timestamp: Date.now(),\n });\n } catch (error: unknown) {\n const errorMessage =\n error instanceof Error ? error.message : 'Unknown error';\n console.error(`Failed to take screenshot: ${errorMessage}`);\n res.status(500).json({\n error: `Failed to take screenshot: ${errorMessage}`,\n });\n }\n });\n\n // Interface info API for getting interface type and description\n this._app.get('/interface-info', async (_req: Request, res: Response) => {\n try {\n const type = this.agent.interface.interfaceType || 'Unknown';\n const description = this.agent.interface.describe?.() || undefined;\n\n res.json({\n type,\n description,\n });\n } catch (error: unknown) {\n const errorMessage =\n error instanceof Error ? error.message : 'Unknown error';\n console.error(`Failed to get interface info: ${errorMessage}`);\n res.status(500).json({\n error: `Failed to get interface info: ${errorMessage}`,\n });\n }\n });\n\n this.app.post('/config', async (req: Request, res: Response) => {\n const { aiConfig } = req.body;\n\n if (!aiConfig || typeof aiConfig !== 'object') {\n return res.status(400).json({\n error: 'aiConfig is required and must be an object',\n });\n }\n\n if (Object.keys(aiConfig).length === 0) {\n return res.json({\n status: 'ok',\n message: 'AI config not changed due to empty object',\n });\n }\n\n try {\n overrideAIConfig(aiConfig);\n\n return res.json({\n status: 'ok',\n message: 'AI config updated successfully',\n });\n } catch (error: unknown) {\n const errorMessage =\n error instanceof Error ? error.message : 'Unknown error';\n console.error(`Failed to update AI config: ${errorMessage}`);\n return res.status(500).json({\n error: `Failed to update AI config: ${errorMessage}`,\n });\n }\n });\n }\n\n /**\n * Setup static file serving routes\n */\n private setupStaticRoutes(): void {\n // Handle index.html with port injection\n this._app.get('/', (_req: Request, res: Response) => {\n this.serveHtmlWithPorts(res);\n });\n\n this._app.get('/index.html', (_req: Request, res: Response) => {\n this.serveHtmlWithPorts(res);\n });\n\n // Use express.static middleware for secure static file serving\n this._app.use(express.static(this.staticPath));\n\n // Fallback to index.html for SPA routing\n this._app.get('*', (_req: Request, res: Response) => {\n this.serveHtmlWithPorts(res);\n });\n }\n\n /**\n * Serve HTML with injected port configuration\n */\n private serveHtmlWithPorts(res: Response): void {\n try {\n const htmlPath = join(this.staticPath, 'index.html');\n let html = readFileSync(htmlPath, 'utf8');\n\n // Get scrcpy server port from global\n const scrcpyPort = (global as any).scrcpyServerPort || this.port! + 1;\n\n // Inject scrcpy port configuration script into HTML head\n const configScript = `\n <script>\n window.SCRCPY_PORT = ${scrcpyPort};\n </script>\n `;\n\n // Insert the script before closing </head> tag\n html = html.replace('</head>', `${configScript}</head>`);\n\n res.setHeader('Content-Type', 'text/html');\n res.send(html);\n } catch (error) {\n console.error('Error serving HTML with ports:', error);\n res.status(500).send('Internal Server Error');\n }\n }\n\n /**\n * Launch the server on specified port\n */\n async launch(port?: number): Promise<PlaygroundServer> {\n // If using factory mode, initialize agent\n if (this.agentFactory) {\n console.log('Initializing agent from factory function...');\n this.agent = await this.agentFactory();\n console.log('Agent initialized successfully');\n }\n\n // Initialize routes now, after any middleware has been added\n this.initializeApp();\n\n this.port = port || defaultPort;\n\n return new Promise((resolve) => {\n const serverPort = this.port;\n this.server = this._app.listen(serverPort, () => {\n resolve(this);\n });\n });\n }\n\n /**\n * Close the server and clean up resources\n */\n async close(): Promise<void> {\n return new Promise((resolve, reject) => {\n if (this.server) {\n // Clean up the single agent\n try {\n this.agent.destroy();\n } catch (error) {\n console.warn('Failed to destroy agent:', error);\n }\n this.taskProgressMessages = {};\n\n // Close the server\n this.server.close((error) => {\n if (error) {\n reject(error);\n } else {\n this.server = undefined;\n resolve();\n }\n });\n } else {\n resolve();\n }\n });\n }\n}\n\nexport default PlaygroundServer;\nexport { PlaygroundServer };\n"],"names":["__webpack_require__","module","getter","definition","key","Object","obj","prop","Symbol","defaultPort","PLAYGROUND_SERVER_PORT","__filename","fileURLToPath","__dirname","dirname","STATIC_PATH","join","errorHandler","err","req","res","next","console","errorMessage","Error","PlaygroundServer","express","_res","context","uuid","tmpFile","writeFileSync","error","contextFile","existsSync","readFileSync","requestId","progressMessages","lastMessage","undefined","tip","actionSpace","processedActionSpace","action","typedAction","processedSchema","e","actionName","type","prompt","params","deepThink","screenshotIncluded","domIncluded","deviceOptions","_dump","executionDump","task","index","typeStr","description","paramStr","taskStatus","status","Date","response","startTime","value","executeAction","formatErrorMessage","JSON","timeCost","_req","base64Screenshot","aiConfig","overrideAIConfig","htmlPath","html","scrcpyPort","global","configScript","port","Promise","resolve","serverPort","reject","agent","staticPath","id","getTmpDir"],"mappings":"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"}
@@ -1,16 +1,14 @@
1
- import type { DeviceAction } from '@midscene/core';
1
+ import type { DeviceAction, ExecutionDump } from '@midscene/core';
2
2
  import type { ExecutionOptions, FormValue, PlaygroundAgent } from '../types';
3
3
  import { BasePlaygroundAdapter } from './base';
4
4
  export declare class LocalExecutionAdapter extends BasePlaygroundAdapter {
5
5
  private agent;
6
- private taskProgressTips;
7
- private progressCallback?;
6
+ private dumpUpdateCallback?;
8
7
  private readonly _id;
9
8
  private currentRequestId?;
10
9
  constructor(agent: PlaygroundAgent);
11
10
  get id(): string;
12
- setProgressCallback(callback: (tip: string) => void): void;
13
- private cleanup;
11
+ onDumpUpdate(callback: (dump: string, executionDump?: ExecutionDump) => void): void;
14
12
  parseStructuredParams(action: DeviceAction<unknown>, params: Record<string, unknown>, options: ExecutionOptions): Promise<unknown[]>;
15
13
  formatErrorMessage(error: any): string;
16
14
  getActionSpace(context?: unknown): Promise<DeviceAction<unknown>[]>;
@@ -24,13 +22,18 @@ export declare class LocalExecutionAdapter extends BasePlaygroundAdapter {
24
22
  */
25
23
  private detachDebuggerSafely;
26
24
  executeAction(actionType: string, value: FormValue, options: ExecutionOptions): Promise<unknown>;
27
- getTaskProgress(requestId: string): Promise<{
28
- tip?: string;
29
- }>;
30
25
  cancelTask(_requestId: string): Promise<{
31
26
  error?: string;
32
27
  success?: boolean;
33
28
  }>;
29
+ /**
30
+ * Get current execution data without resetting
31
+ * This allows retrieving dump and report when execution is stopped
32
+ */
33
+ getCurrentExecutionData(): Promise<{
34
+ dump: ExecutionDump | null;
35
+ reportHTML: string | null;
36
+ }>;
34
37
  getInterfaceInfo(): Promise<{
35
38
  type: string;
36
39
  description?: string;
@@ -3,8 +3,6 @@ import type { ExecutionOptions, FormValue, ValidationResult } from '../types';
3
3
  import { BasePlaygroundAdapter } from './base';
4
4
  export declare class RemoteExecutionAdapter extends BasePlaygroundAdapter {
5
5
  private serverUrl?;
6
- private progressPolling;
7
- private progressCallback?;
8
6
  private _id?;
9
7
  constructor(serverUrl: string);
10
8
  get id(): string | undefined;
@@ -24,9 +22,6 @@ export declare class RemoteExecutionAdapter extends BasePlaygroundAdapter {
24
22
  error?: string;
25
23
  success?: boolean;
26
24
  }>;
27
- setProgressCallback(callback: (tip: string) => void): void;
28
- private startProgressPolling;
29
- private stopProgressPolling;
30
25
  getScreenshot(): Promise<{
31
26
  screenshot: string;
32
27
  timestamp: number;
@@ -12,14 +12,13 @@ export declare class PlaygroundSDK {
12
12
  get id(): string | undefined;
13
13
  checkStatus(): Promise<boolean>;
14
14
  overrideConfig(aiConfig: any): Promise<void>;
15
- getTaskProgress(requestId: string): Promise<{
16
- tip?: string;
17
- }>;
18
15
  cancelTask(requestId: string): Promise<any>;
19
- onProgressUpdate(callback: (tip: string) => void): void;
20
- startProgressPolling(requestId: string): void;
21
- stopProgressPolling(requestId: string): void;
16
+ onDumpUpdate(callback: (dump: string, executionDump?: any) => void): void;
22
17
  cancelExecution(requestId: string): Promise<void>;
18
+ getCurrentExecutionData(): Promise<{
19
+ dump: any | null;
20
+ reportHTML: string | null;
21
+ }>;
23
22
  getScreenshot(): Promise<{
24
23
  screenshot: string;
25
24
  timestamp: number;
@@ -28,4 +27,5 @@ export declare class PlaygroundSDK {
28
27
  type: string;
29
28
  description?: string;
30
29
  } | null>;
30
+ getServiceMode(): 'In-Browser-Extension' | 'Server';
31
31
  }
@@ -1,6 +1,7 @@
1
1
  import type { Server } from 'node:http';
2
2
  import type { Agent as PageAgent } from '@midscene/core/agent';
3
3
  import express from 'express';
4
+ import type { ProgressMessage } from './types';
4
5
  import 'dotenv/config';
5
6
  declare class PlaygroundServer {
6
7
  private _app;
@@ -9,7 +10,7 @@ declare class PlaygroundServer {
9
10
  port?: number | null;
10
11
  agent: PageAgent;
11
12
  staticPath: string;
12
- taskProgressTips: Record<string, string>;
13
+ taskProgressMessages: Record<string, ProgressMessage[]>;
13
14
  id: string;
14
15
  private _initialized;
15
16
  private agentFactory?;
@@ -46,6 +46,24 @@ export interface PlaygroundConfig {
46
46
  serverUrl?: string;
47
47
  agent?: PlaygroundAgent;
48
48
  }
49
+ /**
50
+ * Progress message for UI display
51
+ * Generated from ExecutionTask to provide user-friendly progress updates
52
+ */
53
+ export interface ProgressMessage {
54
+ /** Unique identifier for this progress message */
55
+ id: string;
56
+ /** Corresponding task ID from ExecutionTask */
57
+ taskId: string;
58
+ /** Task type display name (e.g., "Plan", "Action", "Query") */
59
+ action: string;
60
+ /** Human-readable description of what the task does */
61
+ description: string;
62
+ /** Task execution status */
63
+ status: 'pending' | 'running' | 'finished' | 'failed';
64
+ /** Unix timestamp when this message was generated */
65
+ timestamp: number;
66
+ }
49
67
  export interface PlaygroundAdapter {
50
68
  parseStructuredParams(action: DeviceAction<unknown>, params: Record<string, unknown>, options: ExecutionOptions): Promise<unknown[]>;
51
69
  formatErrorMessage(error: any): string;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@midscene/playground",
3
- "version": "1.0.1-beta-20251209112631.0",
3
+ "version": "1.0.1-beta-20251211095502.0",
4
4
  "description": "Midscene playground utilities for web integration",
5
5
  "author": "midscene team",
6
6
  "license": "MIT",
@@ -25,8 +25,8 @@
25
25
  "express": "^4.21.2",
26
26
  "open": "10.1.0",
27
27
  "uuid": "11.1.0",
28
- "@midscene/core": "1.0.1-beta-20251209112631.0",
29
- "@midscene/shared": "1.0.1-beta-20251209112631.0"
28
+ "@midscene/shared": "1.0.1-beta-20251211095502.0",
29
+ "@midscene/core": "1.0.1-beta-20251211095502.0"
30
30
  },
31
31
  "devDependencies": {
32
32
  "@rslib/core": "^0.18.3",
package/static/index.html CHANGED
@@ -1 +1 @@
1
- <!doctype html><html><head><link rel="icon" href="/favicon.ico"><title>Midscene Playground</title><meta charset="UTF-8"><meta name="viewport" content="width=device-width, initial-scale=1.0"><script defer src="/static/js/lib-react.bc3a3965.js"></script><script defer src="/static/js/430.adc9a336.js"></script><script defer src="/static/js/index.7cdfccfc.js"></script><link href="/static/css/index.7fc783ce.css" rel="stylesheet"></head><body><div id="root"></div></body></html>
1
+ <!doctype html><html><head><link rel="icon" href="/favicon.ico"><title>Midscene Playground</title><meta charset="UTF-8"><meta name="viewport" content="width=device-width, initial-scale=1.0"><script defer src="/static/js/lib-react.bc3a3965.js"></script><script defer src="/static/js/430.adc9a336.js"></script><script defer src="/static/js/index.0f473725.js"></script><link href="/static/css/index.3d0b5a80.css" rel="stylesheet"></head><body><div id="root"></div></body></html>
@@ -0,0 +1,2 @@
1
+ body{margin:0;padding:0;font-family:-apple-system,BlinkMacSystemFont,Segoe UI,Noto Sans,Helvetica,Arial,sans-serif,Apple Color Emoji,Segoe UI Emoji;font-size:14px}h3{text-transform:capitalize}.app-container{background-color:#f5f5f5;flex-direction:column;width:100%;height:100vh;display:flex}.app-content{height:100vh;overflow:hidden}.app-grid-layout{height:100%;display:flex}.app-grid-layout .ant-row{flex-wrap:nowrap;flex:1;width:100%;height:100%;display:flex}.app-panel{background-color:#fff;border-radius:0;height:100%;transition:box-shadow .3s;overflow:hidden;box-shadow:0 1px 2px #0000000d}.app-panel:hover{box-shadow:0 2px 8px #00000017}.app-panel.left-panel{flex-direction:column;height:100%;display:flex;overflow:hidden}.app-panel.right-panel{border-radius:0;flex:1;overflow:hidden;box-shadow:-4px 0 20px #0000000a}.panel-content{flex-direction:column;height:100%;display:flex;overflow:auto}.panel-content.left-panel-content{flex-direction:column;height:100%;display:flex;overflow:hidden}.panel-content.left-panel-content .playground-panel-header{border-bottom:1px solid #0000000f;flex-shrink:0;align-items:center;height:60px;padding:0 24px;display:flex}.panel-content.left-panel-content .playground-panel-header .header-row{justify-content:space-between;align-items:center;gap:10px;width:100%;display:flex}.panel-content.left-panel-content .playground-panel-header h2{color:#1890ff;margin:0 0 16px;font-size:18px;font-weight:600}.panel-content.left-panel-content .playground-panel-playground{flex-direction:column;flex:1;min-height:0;padding:0 24px;display:flex}.panel-content.left-panel-content .playground-panel-playground .playground-container{background:#fff;border:none;border-radius:8px;flex:1;overflow:hidden}.panel-content.right-panel-content{border-radius:0;padding:0 24px 24px}.server-offline-container{background:#f5f5f5;justify-content:center;align-items:center;height:100vh;display:flex}.server-offline-container .server-offline-message{background:#f2f4f7;border-radius:8px;flex-direction:column;width:100%;height:100%;padding:14px 24px 0;display:flex;box-shadow:0 2px 8px #0000000f}.server-offline-container .server-offline-message .server-offline-content{text-align:center;flex-direction:column;flex:1;justify-content:flex-start;align-items:center;padding-top:20vh;display:flex}.server-offline-container .server-offline-message .server-offline-icon{display:inline-block;position:relative}.server-offline-container .server-offline-message .server-offline-icon .icon-background,.server-offline-container .server-offline-message .server-offline-icon .icon-foreground{display:block;position:absolute;top:50%;left:50%;transform:translate(-50%,-50%)}.server-offline-container .server-offline-message .server-offline-icon .icon-background{z-index:1;width:300px;height:212px}.server-offline-container .server-offline-message .server-offline-icon .icon-foreground{z-index:2;width:134px;height:101px}.server-offline-container .server-offline-message .server-offline-icon:after{content:"";width:300px;height:212px;display:block;position:relative}.server-offline-container .server-offline-message h1{letter-spacing:0%;color:#000;margin:0;font-size:18px;font-weight:600}.server-offline-container .server-offline-message .connection-status{letter-spacing:0%;text-align:center;margin-top:8px;font-size:12px}.panel-resize-handle{background-color:#f0f0f0;transition:background-color .2s;position:relative}.panel-resize-handle.horizontal{cursor:col-resize;width:1px}.panel-resize-handle.vertical{cursor:row-resize;height:1px}.panel-resize-handle:hover,.panel-resize-handle:active,.panel-resize-handle[data-resize-handle-active]{background-color:#1677ff}.clear-button-container{top:20px!important;right:-4px!important}.logo img{vertical-align:baseline;height:30px;vertical-align:-webkit-baseline-middle;line-height:30px}.logo-with-star-wrapper{flex-direction:row;justify-content:space-between;display:flex}.nav-actions{align-items:center;gap:8px;display:flex}.nav-actions .nav-icon{color:#000000a6;cursor:pointer;font-size:16px;transition:color .3s}.nav-actions .nav-icon:hover{color:#2b83ff}.nav-actions a{align-items:center;text-decoration:none;display:flex}.nav-actions a:hover .nav-icon{color:#2b83ff}[data-theme=dark] .nav-actions .nav-icon{color:#f8fafd}[data-theme=dark] .nav-actions .nav-icon:hover{color:#2b83ff}.blackboard .footer{color:#aaa}.blackboard ul{padding-left:0}.blackboard li{list-style:none}.blackboard .bottom-tip{height:30px}.blackboard .bottom-tip-item{color:#aaa;text-overflow:ellipsis;word-wrap:break-word;max-width:500px}.blackboard-filter{margin:10px 0}.blackboard-main-content canvas{box-sizing:border-box;border:1px solid #888;width:100%}[data-theme=dark] .blackboard .footer,[data-theme=dark] .blackboard .bottom-tip-item{color:#ffffff73}[data-theme=dark] .blackboard-main-content canvas{border-color:#ffffff1f}.shiny-text{color:#0000;letter-spacing:.5px;text-shadow:0 1px 2px #0000000d;background-image:linear-gradient(45deg,#2b83ff,#6a11cb,#2575fc,#4481eb);background-size:300%;-webkit-background-clip:text;background-clip:text;font-weight:600;animation:8s infinite textGradient;display:inline-block;position:relative;overflow:hidden}.shiny-text.theme-blue{background-image:linear-gradient(45deg,#2b83ff,#6a11cb,#2575fc,#4481eb)}.shiny-text.theme-purple{background-image:linear-gradient(45deg,#667eea,#764ba2,#b06ab3,#9d50bb)}.shiny-text.theme-green{background-image:linear-gradient(45deg,#11998e,#38ef7d,#2dd4bf,#10b981)}.shiny-text.theme-rainbow{background-image:linear-gradient(45deg,#ff0080,#ff8c00,#40e0d0,#9d50bb,#ff0080);background-size:400%}.shiny-text:after{content:"";width:120%;height:120%;animation:shine var(--animation-duration,5s)cubic-bezier(.25,.1,.25,1)infinite;z-index:1;pointer-events:none;background:linear-gradient(90deg,#fff0 0%,#ffffff1a 10%,#fff9 50%,#ffffff1a 90%,#fff0 100%);position:absolute;top:-10%;left:-150%;transform:skew(-20deg)translateY(0)}.shiny-text.disabled{color:#000;background:0 0;font-weight:400;animation:none}.shiny-text.disabled:after{animation:none;display:none}@keyframes shine{0%{opacity:.7;left:-150%}20%{opacity:1}80%{opacity:1}to{opacity:.7;left:250%}}@keyframes textGradient{0%{background-position:0%}50%{background-position:100%}to{background-position:0%}}.env-config-reminder{background:#fff2e8;border-radius:12px;align-items:center;gap:12px;margin-bottom:12px;padding:12px 16px;display:flex}.env-config-reminder .reminder-icon{color:#fa541c;width:16px;height:16px}.env-config-reminder .reminder-text{color:#000;flex:1;font-size:14px}[data-theme=dark] .env-config-reminder{background:#5226074d}[data-theme=dark] .env-config-reminder .reminder-text{color:#f8fafd}.player-container{box-sizing:border-box;background:#f2f4f7;border:1px solid #f2f4f7;border-radius:8px;flex-direction:column;width:100%;max-width:100%;height:100%;min-height:300px;max-height:100%;margin:0 auto;padding:12px;line-height:100%;display:flex;position:relative;overflow:visible}.player-container[data-fit-mode=height]{background:#fff}.player-container[data-fit-mode=height] .canvas-container{background-color:#f2f4f7}.player-container .canvas-container{width:100%;min-height:200px;aspect-ratio:var(--canvas-aspect-ratio,16/9);background-color:#fff;border-top-left-radius:4px;border-top-right-radius:4px;flex:none;justify-content:center;align-items:center;display:flex;position:relative;overflow:hidden}.player-container .canvas-container canvas{box-sizing:border-box;object-fit:contain;border:none;width:100%;max-width:100%;height:auto;max-height:100%;margin:0 auto;display:block}.player-container .canvas-container[data-fit-mode=height]{aspect-ratio:unset;flex:auto;height:auto;min-height:0}.player-container .canvas-container[data-fit-mode=height] canvas{width:auto;max-width:100%;height:100%;max-height:100%}.player-container .canvas-container[data-fit-mode=width]{aspect-ratio:var(--canvas-aspect-ratio,16/9)}.player-container .canvas-container[data-fit-mode=width] canvas{width:100%;height:auto}.player-container .player-timeline-wrapper{flex:none;width:100%;height:4px;margin-bottom:2px;position:relative}.player-container .player-timeline{background:#666;flex-shrink:0;width:100%;height:4px;position:relative}.player-container .player-timeline .player-timeline-progress{background:#2b83ff;height:4px;transition-timing-function:linear;position:absolute;top:0;left:0}.player-container .player-tools-wrapper{box-sizing:border-box;flex:none;width:100%;height:72px;padding:15px 16px;position:relative}.player-container .player-tools{color:#000;box-sizing:border-box;flex-direction:row;flex-shrink:0;justify-content:space-between;width:100%;max-width:100%;height:42px;font-size:14px;display:flex;overflow:hidden}.player-container .player-tools .ant-spin{color:#333}.player-container .player-tools .player-control{flex-direction:row;flex-grow:1;align-items:center;display:flex;overflow:hidden}.player-container .player-tools .status-icon{border-radius:8px;flex-shrink:0;justify-content:center;align-items:center;width:32px;height:32px;margin-left:10px;transition:all .2s;display:flex}.player-container .player-tools .status-icon:hover{cursor:pointer;background:#f0f0f0}.player-container .player-tools .status-text{flex-direction:column;flex-grow:1;flex-shrink:1;justify-content:space-between;width:0;min-width:0;height:100%;display:flex;position:relative;overflow:hidden}.player-container .player-tools .title{font-weight:600}.player-container .player-tools .title,.player-container .player-tools .subtitle{text-overflow:ellipsis;white-space:nowrap;width:100%;overflow:hidden}.player-container .player-tools .player-tools-item{flex-direction:column;justify-content:center;height:100%;display:flex}[data-theme=dark] .player-container{background:#141414;border-color:#292929}[data-theme=dark] .player-container[data-fit-mode=height]{background:#292929;border-color:#292929}[data-theme=dark] .player-container[data-fit-mode=height] .canvas-container{background-color:#141414}[data-theme=dark] .player-container .canvas-container{background-color:#1f1f1f}[data-theme=dark] .player-container .player-tools,[data-theme=dark] .player-container .player-tools .ant-spin,[data-theme=dark] .player-container .player-tools .status-icon svg{color:#f8fafd}[data-theme=dark] .player-container .player-tools .status-icon:hover{background:#ffffff14}.result-wrapper{justify-content:center;height:100%;margin:4px 0;display:flex}.result-wrapper .loading-container{flex-direction:column;justify-content:center;align-items:center;width:100%;height:100%;display:flex}.result-wrapper .loading-container .loading-progress-text{color:#888;margin-top:8px;font-size:12px}.result-wrapper pre{white-space:pre-wrap;text-wrap:unset;word-wrap:break-word;overflow-wrap:break-word;background:#f2f4f7;border-radius:8px;margin:0;padding:14px;overflow:scroll}.playground-container{background:#fff;flex-direction:column;width:100%;height:100vh;display:flex;position:relative}.playground-container .command-form{flex-direction:column;width:100%;height:100%;display:flex}.playground-container .context-preview-section{border-bottom:1px solid #f0f0f0;flex-shrink:0;padding:16px}.playground-container .middle-dialog-area{flex-direction:column;flex:1;min-height:0;display:flex;position:relative;overflow:hidden}.playground-container .middle-dialog-area .clear-button-container{z-index:10;position:absolute;top:16px;right:0}.playground-container .middle-dialog-area .clear-button-container .clear-button{opacity:.7;transition:opacity .2s}.playground-container .middle-dialog-area .clear-button-container .clear-button:hover{opacity:1}.playground-container .middle-dialog-area .info-list-container{scrollbar-width:none;flex:1;padding-top:16px;padding-bottom:16px;overflow:hidden auto}.playground-container .middle-dialog-area .info-list-container .ant-list .ant-list-item{border-bottom:none;padding:0}.playground-container .middle-dialog-area .info-list-container .ant-list .ant-list-item .ant-card{border:1px solid #f0f0f0;border-radius:8px;box-shadow:0 1px 3px #0000001a}.playground-container .middle-dialog-area .info-list-container .ant-list .ant-list-item .ant-card:hover{box-shadow:0 2px 6px #00000026}.playground-container .middle-dialog-area .info-list-container .ant-list .ant-list-item .ant-card .ant-card-body{padding:12px}.playground-container .middle-dialog-area .info-list-container .ant-list .ant-list-empty-text{color:#999;font-style:italic}.playground-container .middle-dialog-area .info-list-container::-webkit-scrollbar{display:none}.playground-container .middle-dialog-area .info-list-container .list-item{background:0 0;border:none;padding:0}.playground-container .middle-dialog-area .scroll-to-bottom-button{z-index:10;background:#fff;border:1px solid #00000014;position:absolute;bottom:10px;right:0}.playground-container .middle-dialog-area .scroll-to-bottom-button:hover{background:#1890ff}.playground-container .middle-dialog-area .scroll-to-bottom-button:hover .anticon{color:#fff}.playground-container .middle-dialog-area .scroll-to-bottom-button .anticon{color:#333;font-size:16px}.playground-container .user-message-container{justify-content:flex-end;width:100%;margin:20px 0 30px;display:flex}.playground-container .user-message-container .user-message-bubble{color:#000000d9;text-align:left;background:#f2f4f7;border-radius:12px;max-width:80%;padding:12px 16px;font-size:14px;font-weight:400;display:inline-block}.playground-container .progress-action-item{color:#000;background:#f2f4f7;border-radius:8px;justify-content:space-between;height:36px;margin:4px 0;padding:0 12px;font-size:14px;line-height:36px;display:flex}.playground-container .progress-action-item .progress-status-icon{margin-left:4px}.playground-container .progress-action-item .progress-status-icon.loading{color:#1890ff}.playground-container .progress-action-item .progress-status-icon.completed{color:#52c41a}.playground-container .progress-action-item .progress-status-icon.error{color:#ff4d4f;font-weight:700}.playground-container .progress-description{padding:8px 0;font-size:14px;line-height:22px;display:inline-block}.playground-container .system-message-container{flex-direction:column;display:flex}.playground-container .system-message-container .system-message-header{align-items:center;gap:8px;margin:12px 0;display:flex}.playground-container .system-message-container .system-message-header .system-message-title{font-size:12px;font-weight:400;line-height:100%}.playground-container .system-message-container .system-message-content{color:#000000d9;font-size:14px}.playground-container .system-message-container .system-message-content .system-message-text{color:#000000d9;font-size:14px;line-height:25px}.playground-container .system-message-container .system-message-content .error-message{color:#e51723;word-break:break-word;background-color:#fff;border:none;border-radius:0;align-items:flex-start;margin-bottom:16px;padding:0;font-size:14px;display:flex}.playground-container .system-message-container .system-message-content .error-message .divider{background-color:#e6e8eb;flex-shrink:0;align-self:stretch;width:1px;min-height:20px;margin:0 8px 0 0}.playground-container .system-message-container .system-message-content .loading-progress-text{color:#666;background:#f6f8fa;border-left:3px solid #1890ff;border-radius:4px;margin-top:8px;padding:8px 12px;font-size:13px}.playground-container .new-conversation-separator{flex-shrink:0;justify-content:center;align-items:center;padding:20px 0;display:flex;position:relative}.playground-container .new-conversation-separator .separator-line{background-color:#e8e8e8;height:1px;position:absolute;top:50%;left:0;right:0}.playground-container .new-conversation-separator .separator-text-container{z-index:1;background-color:#fff;padding:0 16px;position:relative}.playground-container .new-conversation-separator .separator-text-container .separator-text{color:#999;background-color:#fff;font-size:12px}.playground-container .bottom-input-section{background-color:#fff;flex-shrink:0;padding:16px 0 0}.playground-container .version-info-section{flex-shrink:0;justify-content:center;align-items:center;height:38px;display:flex}.playground-container .version-text{color:#999;text-align:center;font-size:12px}.playground-container .hidden-result-ref{display:none}.playground-container .playground-description{margin-bottom:32px}.playground-container .playground-description .description-zh{color:#333;margin:0 0 8px;font-size:16px;line-height:1.5}.playground-container .playground-description .description-en{color:#666;margin:0;font-size:14px;line-height:1.5}.playground-container .config-section{margin-bottom:24px}.playground-container .config-section .config-title{color:#333;margin:0 0 16px;font-size:18px;font-weight:600}.playground-container .config-section .config-item{align-items:center;gap:8px;margin-bottom:12px;display:flex}.playground-container .config-section .config-item .config-check{color:#52c41a;font-size:16px}.playground-container .config-section .config-item .config-label{color:#333;font-size:14px}.playground-container .config-section .config-link{color:#1890ff;font-size:14px;text-decoration:none}.playground-container .config-section .config-link:hover{text-decoration:underline}[data-theme=dark] .universal-playground .error-hint{color:#ffffff73}[data-theme=dark] .universal-playground .status-indicator{color:#f8fafd}[data-theme=dark] .universal-playground .status-indicator.error{color:#ff4d4f}[data-theme=dark] .universal-playground .status-indicator.success{color:#52c41a}[data-theme=dark] .universal-playground .operation-label{color:#f8fafd}[data-theme=dark] .universal-playground .alert-message{color:#f8fafd;background-color:#5226074d}[data-theme=dark] .universal-playground .operation-item .operation-icon-wrapper{background-color:#ffffff14}[data-theme=dark] .universal-playground .operation-item .operation-content{background-color:#0000}[data-theme=dark] .universal-playground .operation-item .operation-content .operation-title{color:#ffffff73}[data-theme=dark] .universal-playground .playground-footer{background-color:#ffffff0a}[data-theme=dark] .universal-playground .playground-footer .status-text{color:#f8fafd}[data-theme=dark] .universal-playground .results-info{color:#ffffff73}[data-theme=dark] .universal-playground .result-section .result-title,[data-theme=dark] .universal-playground .result-section .result-details,[data-theme=dark] .universal-playground .result-section .result-value{color:#f8fafd}[data-theme=dark] .universal-playground .result-section .result-value.success{color:#52c41a}[data-theme=dark] .universal-playground .result-section .result-value.error{color:#ff4d4f}.prompt-input-wrapper{width:100%}.prompt-input-wrapper .mode-radio-group-wrapper{align-items:center;gap:8px;display:flex;position:relative}.prompt-input-wrapper .mode-radio-group-wrapper .mode-radio-group{scrollbar-width:thin;flex:1;align-items:center;gap:8px;min-width:0;height:100%;margin-right:60px;display:flex;overflow:auto hidden}.prompt-input-wrapper .mode-radio-group-wrapper .mode-radio-group::-webkit-scrollbar{height:6px}.prompt-input-wrapper .mode-radio-group-wrapper .mode-radio-group::-webkit-scrollbar-track{background:#f1f1f1;border-radius:3px}.prompt-input-wrapper .mode-radio-group-wrapper .mode-radio-group::-webkit-scrollbar-thumb{background:#c1c1c1;border-radius:3px}.prompt-input-wrapper .mode-radio-group-wrapper .mode-radio-group::-webkit-scrollbar-thumb:hover{background:#a8a8a8}.prompt-input-wrapper .mode-radio-group-wrapper .mode-radio-group .ant-form-item{flex-shrink:0;margin:0!important}.prompt-input-wrapper .mode-radio-group-wrapper .mode-radio-group .ant-form-item .ant-radio-group{flex-wrap:nowrap;gap:8px;display:flex}.prompt-input-wrapper .mode-radio-group-wrapper .mode-radio-group .ant-radio-button-wrapper{height:24px;box-shadow:none;white-space:nowrap;background-color:#f7f7f7;border:none;border-radius:11px;flex-shrink:0;margin-right:0;padding:0 8px;font-size:12px;line-height:24px}.prompt-input-wrapper .mode-radio-group-wrapper .mode-radio-group .ant-radio-button-wrapper:before{display:none}.prompt-input-wrapper .mode-radio-group-wrapper .mode-radio-group .ant-radio-button-wrapper:focus-within{outline:none}.prompt-input-wrapper .mode-radio-group-wrapper .mode-radio-group .ant-radio-button-wrapper.ant-radio-button-wrapper-checked{color:#fff;background-color:#2b83ff;border-color:#2b83ff}.prompt-input-wrapper .mode-radio-group-wrapper .mode-radio-group .ant-radio-button-wrapper.ant-radio-button-wrapper-checked:hover{color:#fff}.prompt-input-wrapper .mode-radio-group-wrapper .mode-radio-group .ant-dropdown-trigger{flex-shrink:0}.prompt-input-wrapper .mode-radio-group-wrapper .mode-radio-group .more-apis-button{height:24px;box-shadow:none;white-space:nowrap;background-color:#f7f7f7;border:none;border-radius:11px;flex-shrink:0;align-items:center;gap:2px;max-width:160px;padding:0 8px;font-size:12px;display:inline-flex}.prompt-input-wrapper .mode-radio-group-wrapper .mode-radio-group .more-apis-button .ant-btn-content{text-overflow:ellipsis;white-space:nowrap;overflow:hidden}.prompt-input-wrapper .mode-radio-group-wrapper .mode-radio-group .more-apis-button:hover{background-color:#e6e6e6}.prompt-input-wrapper .mode-radio-group-wrapper .mode-radio-group .more-apis-button.selected-from-dropdown{color:#fff;background-color:#2b83ff;font-weight:500}.prompt-input-wrapper .mode-radio-group-wrapper .mode-radio-group .more-apis-button.selected-from-dropdown:hover{background-color:#2b83ff}.prompt-input-wrapper .mode-radio-group-wrapper .action-icons{z-index:10;pointer-events:none;background:linear-gradient(90deg,#0000 0%,#ffffff80 20%,#fffc 40%,#fffffff2 60%,#fff 70%);flex-shrink:0;justify-content:flex-end;align-items:center;gap:8px;width:80px;padding-left:20px;display:flex;position:absolute;top:50%;right:0;transform:translateY(-50%)}.prompt-input-wrapper .mode-radio-group-wrapper .action-icons>*{pointer-events:auto}.prompt-input-wrapper .main-side-console-input{margin-top:10px;position:relative}.prompt-input-wrapper .main-side-console-input .main-side-console-input-textarea{white-space:pre-wrap;scrollbar-width:thin;background:#fff;border:1px solid #f2f4f7;border-radius:12px;padding:12px 16px;line-height:21px;transition:background-color .2s;overflow-y:auto}@keyframes hue-shift{0%{filter:hue-rotate()}to{filter:hue-rotate(360deg)}}.prompt-input-wrapper .main-side-console-input .main-side-console-input-textarea:focus-within{background:linear-gradient(#fff,#fff) padding-box padding-box,linear-gradient(135deg,#4285f4 0%,#06f 25%,#7b02c5 50%,#ea4335 75%,#ff7043 100%) border-box;border:1px solid #0000}.prompt-input-wrapper .main-side-console-input .main-side-console-input-textarea::-webkit-scrollbar{width:6px}.prompt-input-wrapper .main-side-console-input .main-side-console-input-textarea::-webkit-scrollbar-thumb{background-color:#0003;border-radius:3px}.prompt-input-wrapper .main-side-console-input.loading .main-side-console-input-textarea{background:linear-gradient(#fff,#fff) padding-box padding-box,linear-gradient(135deg,#4285f4 0%,#06f 25%,#7b02c5 50%,#ea4335 75%,#ff7043 100%) border-box;border:1px solid #0000;animation:5s linear infinite hue-shift}.prompt-input-wrapper .main-side-console-input .ant-form-item-control-input-content{z-index:999;border:3px solid #0000;border-radius:14px}.prompt-input-wrapper .main-side-console-input:focus-within .ant-form-item-control-input-content{border-color:#2b83ff29}.prompt-input-wrapper .main-side-console-input.disabled .form-controller-wrapper{background-color:#0000}.prompt-input-wrapper .ant-form-item-with-help+.form-controller-wrapper{bottom:22px}.prompt-input-wrapper .ant-input{padding-bottom:40px}.prompt-input-wrapper .form-controller-wrapper{box-sizing:border-box;background-color:#fff;flex-direction:row;justify-content:flex-end;align-items:flex-end;gap:8px;width:calc(100% - 32px);padding:12px 0;line-height:32px;transition:background-color .2s;display:flex;position:absolute;bottom:1px;left:16px}.prompt-input-wrapper .settings-wrapper{color:#777;flex-flow:wrap;gap:2px;display:flex}.prompt-input-wrapper .settings-wrapper.settings-wrapper-hover{color:#3b3b3b}.prompt-input-wrapper .structured-params-container{background:linear-gradient(#fff,#fff) padding-box padding-box,linear-gradient(135deg,#4285f4 0%,#06f 25%,#7b02c5 50%,#ea4335 75%,#ff7043 100%) border-box;border:1px solid #0000;border-radius:12px;padding:16px 16px 56px}.prompt-input-wrapper .structured-params-container .structured-params .ant-form-item{flex-direction:column;display:flex}.prompt-input-wrapper .structured-params-container .structured-params .ant-form-item .ant-form-item-label{text-align:left;flex-basis:auto;padding-bottom:4px}.prompt-input-wrapper .structured-params-container .structured-params .ant-form-item .ant-form-item-label>label{color:#000000d9;height:auto;font-size:12px;font-weight:500;line-height:1.5}.prompt-input-wrapper .structured-params-container .structured-params .ant-form-item .ant-form-item-label>label:after{color:#ff4d4f;font-family:SimSun,sans-serif;font-size:12px;line-height:1;display:inline-block}.prompt-input-wrapper .structured-params-container .structured-params .ant-form-item .ant-form-item-label>label:not(:-webkit-any(:lang(ae),:lang(ar),:lang(arc),:lang(bcc),:lang(bqi),:lang(ckb),:lang(dv),:lang(fa),:lang(glk),:lang(he),:lang(ku),:lang(mzn),:lang(nqo),:lang(pnb),:lang(ps),:lang(sd),:lang(ug),:lang(ur),:lang(yi))):after{margin-left:4px}.prompt-input-wrapper .structured-params-container .structured-params .ant-form-item .ant-form-item-label>label:not(:-moz-any(:lang(ae),:lang(ar),:lang(arc),:lang(bcc),:lang(bqi),:lang(ckb),:lang(dv),:lang(fa),:lang(glk),:lang(he),:lang(ku),:lang(mzn),:lang(nqo),:lang(pnb),:lang(ps),:lang(sd),:lang(ug),:lang(ur),:lang(yi))):after{margin-left:4px}.prompt-input-wrapper .structured-params-container .structured-params .ant-form-item .ant-form-item-label>label:not(:-webkit-any(:lang(ae),:lang(ar),:lang(arc),:lang(bcc),:lang(bqi),:lang(ckb),:lang(dv),:lang(fa),:lang(glk),:lang(he),:lang(ku),:lang(mzn),:lang(nqo),:lang(pnb),:lang(ps),:lang(sd),:lang(ug),:lang(ur),:lang(yi))):after{margin-left:4px}.prompt-input-wrapper .structured-params-container .structured-params .ant-form-item .ant-form-item-label>label:not(:-moz-any(:lang(ae),:lang(ar),:lang(arc),:lang(bcc),:lang(bqi),:lang(ckb),:lang(dv),:lang(fa),:lang(glk),:lang(he),:lang(ku),:lang(mzn),:lang(nqo),:lang(pnb),:lang(ps),:lang(sd),:lang(ug),:lang(ur),:lang(yi))):after{margin-left:4px}.prompt-input-wrapper .structured-params-container .structured-params .ant-form-item .ant-form-item-label>label:not(:is(:lang(ae),:lang(ar),:lang(arc),:lang(bcc),:lang(bqi),:lang(ckb),:lang(dv),:lang(fa),:lang(glk),:lang(he),:lang(ku),:lang(mzn),:lang(nqo),:lang(pnb),:lang(ps),:lang(sd),:lang(ug),:lang(ur),:lang(yi))):after{margin-left:4px}.prompt-input-wrapper .structured-params-container .structured-params .ant-form-item .ant-form-item-label>label:-webkit-any(:lang(ae),:lang(ar),:lang(arc),:lang(bcc),:lang(bqi),:lang(ckb),:lang(dv),:lang(fa),:lang(glk),:lang(he),:lang(ku),:lang(mzn),:lang(nqo),:lang(pnb),:lang(ps),:lang(sd),:lang(ug),:lang(ur),:lang(yi)):after{margin-right:4px}.prompt-input-wrapper .structured-params-container .structured-params .ant-form-item .ant-form-item-label>label:-moz-any(:lang(ae),:lang(ar),:lang(arc),:lang(bcc),:lang(bqi),:lang(ckb),:lang(dv),:lang(fa),:lang(glk),:lang(he),:lang(ku),:lang(mzn),:lang(nqo),:lang(pnb),:lang(ps),:lang(sd),:lang(ug),:lang(ur),:lang(yi)):after{margin-right:4px}.prompt-input-wrapper .structured-params-container .structured-params .ant-form-item .ant-form-item-label>label:is(:lang(ae),:lang(ar),:lang(arc),:lang(bcc),:lang(bqi),:lang(ckb),:lang(dv),:lang(fa),:lang(glk),:lang(he),:lang(ku),:lang(mzn),:lang(nqo),:lang(pnb),:lang(ps),:lang(sd),:lang(ug),:lang(ur),:lang(yi)):after{margin-right:4px}.prompt-input-wrapper .structured-params-container .structured-params .ant-form-item .ant-form-item-control{flex:1;margin-top:0}.prompt-input-wrapper .structured-params-container .structured-params .ant-form-item .ant-form-item-row{flex-direction:column}.prompt-input-wrapper .structured-params-container .structured-params .ant-form-item .ant-form-item-control-input{min-height:auto}.prompt-input-wrapper .structured-params-container .structured-params .ant-input,.prompt-input-wrapper .structured-params-container .structured-params .ant-input-number,.prompt-input-wrapper .structured-params-container .structured-params .ant-select{border:1px solid #e1e5e9;border-radius:6px;width:100%}.prompt-input-wrapper .structured-params-container .structured-params .ant-input:hover,.prompt-input-wrapper .structured-params-container .structured-params .ant-input-number:hover,.prompt-input-wrapper .structured-params-container .structured-params .ant-select:hover{border-color:#40a9ff}.prompt-input-wrapper .structured-params-container .structured-params .ant-input:focus,.prompt-input-wrapper .structured-params-container .structured-params .ant-input-number:focus,.prompt-input-wrapper .structured-params-container .structured-params .ant-select:focus,.prompt-input-wrapper .structured-params-container .structured-params .ant-input:focus-within,.prompt-input-wrapper .structured-params-container .structured-params .ant-input-number:focus-within,.prompt-input-wrapper .structured-params-container .structured-params .ant-select:focus-within{border-color:#40a9ff;box-shadow:0 0 0 2px #1890ff33}.prompt-input-wrapper .structured-params-container .structured-params textarea.ant-input{padding-bottom:5px}.prompt-input-wrapper .structured-params-container .structured-params .ant-input-number .ant-input-number-input{box-shadow:none;border:none}.prompt-input-wrapper .structured-params-container .structured-params .ant-input-number:hover .ant-input-number-input{box-shadow:none}.prompt-input-wrapper .structured-params-container .structured-params .ant-select{min-width:120px}.prompt-input-wrapper .structured-params-container .structured-params .ant-select .ant-select-selector{box-shadow:none;border:none}.prompt-input-wrapper .structured-params-container .structured-params .ant-select:hover .ant-select-selector,.prompt-input-wrapper .structured-params-container .structured-params .ant-select.ant-select-focused .ant-select-selector{box-shadow:none}.prompt-input-wrapper .structured-params-container .structured-params .ant-radio-group{width:100%}.prompt-input-wrapper .structured-params-container .structured-params .ant-radio-group .ant-radio-button-wrapper{border:1px solid #e1e5e9;border-radius:6px;height:32px;margin-right:4px;font-size:12px;line-height:30px}.prompt-input-wrapper .structured-params-container .structured-params .ant-radio-group .ant-radio-button-wrapper.ant-radio-button-wrapper-checked{color:#fff;background-color:#2b83ff;border-color:#2b83ff}.selector-trigger{cursor:pointer;width:24px;height:24px;transition:all .2s}.selector-trigger .action-icon{color:#000000d9;font-size:14px;transition:all .2s}.selector-trigger .action-icon:hover{color:#2b83ff}.more-apis-dropdown .ant-dropdown-menu{scrollbar-width:thin;max-height:400px;overflow-y:auto}.more-apis-dropdown .ant-dropdown-menu::-webkit-scrollbar{width:6px}.more-apis-dropdown .ant-dropdown-menu::-webkit-scrollbar-track{background:#f1f1f1;border-radius:3px}.more-apis-dropdown .ant-dropdown-menu::-webkit-scrollbar-thumb{background:#c1c1c1;border-radius:3px}.more-apis-dropdown .ant-dropdown-menu::-webkit-scrollbar-thumb:hover{background:#a8a8a8}[data-theme=dark] .prompt-input-wrapper .mode-radio-group-wrapper .mode-radio-group .ant-radio-button-wrapper{color:#f8fafd!important;background-color:#ffffff14!important}[data-theme=dark] .prompt-input-wrapper .mode-radio-group-wrapper .mode-radio-group .ant-radio-button-wrapper.ant-radio-button-wrapper-checked{color:#fff!important;background-color:#2b83ff!important;border-color:#2b83ff!important}[data-theme=dark] .prompt-input-wrapper .mode-radio-group-wrapper .mode-radio-group .more-apis-button{color:#f8fafd!important;background-color:#ffffff14!important}[data-theme=dark] .prompt-input-wrapper .mode-radio-group-wrapper .mode-radio-group .more-apis-button:hover{background-color:#ffffff1f!important}[data-theme=dark] .prompt-input-wrapper .mode-radio-group-wrapper .mode-radio-group .more-apis-button.selected-from-dropdown{color:#fff!important;background-color:#2b83ff!important}[data-theme=dark] .prompt-input-wrapper .mode-radio-group-wrapper .action-icons{background:linear-gradient(90deg,#0000 0%,#1f1f1f80 20%,#1f1f1fcc 40%,#1f1f1ff2 60%,#1f1f1f 70%)!important}[data-theme=dark] .prompt-input-wrapper .main-side-console-input .main-side-console-input-textarea{color:#f8fafd!important;background:#ffffff0a!important;border-color:#ffffff1f!important}[data-theme=dark] .prompt-input-wrapper .main-side-console-input .main-side-console-input-textarea:focus-within,[data-theme=dark] .prompt-input-wrapper .main-side-console-input.loading .main-side-console-input-textarea{background:linear-gradient(#1f1f1f,#1f1f1f) padding-box padding-box,linear-gradient(135deg,#4285f4 0%,#06f 25%,#7b02c5 50%,#ea4335 75%,#ff7043 100%) border-box!important;border:1px solid #0000!important}[data-theme=dark] .prompt-input-wrapper .ant-form-item-control-input-content .ant-input,[data-theme=dark] .prompt-input-wrapper .ant-form-item-control-input-content textarea.ant-input{color:#f8fafd!important;background:#ffffff0a!important;border-color:#ffffff1f!important}[data-theme=dark] .prompt-input-wrapper .ant-form-item-control-input-content .ant-btn{color:#f8fafd!important;background-color:#ffffff14!important;border-color:#ffffff1f!important}[data-theme=dark] .prompt-input-wrapper .ant-form-item-control-input-content .ant-btn.ant-btn-primary{color:#fff!important;background-color:#2b83ff!important;border-color:#2b83ff!important}[data-theme=dark] .prompt-input-wrapper .form-controller-wrapper{background-color:#1f1f1f!important}[data-theme=dark] .prompt-input-wrapper .structured-params-container{background:linear-gradient(#1f1f1f,#1f1f1f) padding-box padding-box,linear-gradient(135deg,#4285f4 0%,#06f 25%,#7b02c5 50%,#ea4335 75%,#ff7043 100%) border-box!important}[data-theme=dark] .prompt-input-wrapper .structured-params-container .structured-params .ant-form-item-label>label{color:#f8fafd!important}[data-theme=dark] .prompt-input-wrapper .structured-params-container .structured-params .ant-input,[data-theme=dark] .prompt-input-wrapper .structured-params-container .structured-params .ant-input-number,[data-theme=dark] .prompt-input-wrapper .structured-params-container .structured-params .ant-select,[data-theme=dark] .prompt-input-wrapper .structured-params-container .structured-params .ant-radio-group .ant-radio-button-wrapper{color:#f8fafd!important;background-color:#ffffff0a!important;border-color:#ffffff1f!important}[data-theme=dark] .prompt-input-wrapper .structured-params-container .structured-params .ant-radio-group .ant-radio-button-wrapper.ant-radio-button-wrapper-checked{color:#fff!important;background-color:#2b83ff!important;border-color:#2b83ff!important}[data-theme=dark] .prompt-input .tip-button{background-color:#ffffff14}[data-theme=dark] .prompt-input .tip-button.active{color:#fff;background-color:#2b83ff}[data-theme=dark] .prompt-input .prompt-textarea-wrapper{background-color:#ffffff0a}[data-theme=dark] .prompt-input .prompt-textarea-wrapper:hover,[data-theme=dark] .prompt-input .prompt-textarea-wrapper.focused{background-color:#ffffff14}[data-theme=dark] .prompt-input .btn-wrapper .btn-item{color:#fff;background-color:#2b83ff}[data-theme=dark] .prompt-input .btn-wrapper .btn-item:hover{background-color:#2b83ff}[data-theme=dark] .prompt-input .dropdown-content{background-color:#1f1f1f;border-color:#ffffff1f}[data-theme=dark] .prompt-input .param-label{color:#f8fafd}[data-theme=dark] .prompt-input .error-message{color:#ff4d4f}[data-theme=dark] .prompt-input .send-button-text{color:#2b83ff}[data-theme=dark] .more-apis-dropdown .ant-dropdown-menu::-webkit-scrollbar-track{background:#ffffff14}[data-theme=dark] .more-apis-dropdown .ant-dropdown-menu::-webkit-scrollbar-thumb{background:#fff3}[data-theme=dark] .more-apis-dropdown .ant-dropdown-menu::-webkit-scrollbar-thumb:hover{background:#ffffff4d}.history-selector-wrapper{position:relative}.history-modal-overlay{z-index:9999;background:#fff;border:1px solid #00000014;border-radius:12px;width:320px;height:400px;position:fixed;top:auto;bottom:20px;right:20px;box-shadow:0 8px 24px #0000001f}.history-modal-container{border-radius:12px;flex-direction:column;width:100%;height:100%;display:flex;overflow:hidden}.history-modal-container .history-modal-header{justify-content:space-between;align-items:center;height:48px;padding:0 25px;line-height:48px;display:flex}.history-modal-container .history-modal-header .close-button{justify-content:center;align-items:center;margin-right:-4px;padding:4px;display:flex}.history-modal-container .history-modal-header .close-button .anticon{color:#999;font-size:18px}.history-modal-container .history-modal-header .close-button:hover .anticon{color:#666}.history-modal-container .history-search-section{background:#fff;padding:16px 20px}.history-modal-container .history-search-section .search-input-wrapper{color:#00000040;align-items:center;gap:12px;display:flex}.history-modal-container .history-search-section .search-input-wrapper .search-input{background:#f1f2f3;border:none;border-radius:16px;flex:1;height:36px}.history-modal-container .history-search-section .search-input-wrapper .search-input .ant-input{box-shadow:none;background:0 0;border:none}.history-modal-container .history-search-section .search-input-wrapper .search-input:hover,.history-modal-container .history-search-section .search-input-wrapper .search-input:focus-within{background:#fff;border-color:#d9d9d9}.history-modal-container .history-search-section .search-input-wrapper .clear-button{color:#1890ff;height:auto;padding:0}.history-modal-container .history-search-section .search-input-wrapper .clear-button:hover{color:#40a9ff}.history-modal-container .history-content{flex:1;padding:0 25px 25px;overflow-y:auto}.history-modal-container .history-content .history-group{margin-bottom:10px}.history-modal-container .history-content .history-group .history-group-title{color:#00000073;height:40px;font-size:12px;font-weight:400;line-height:40px}.history-modal-container .history-content .history-group .history-item{cursor:pointer;color:#000000d9;white-space:nowrap;text-overflow:ellipsis;height:40px;font-size:14px;line-height:40px;overflow:hidden}.history-modal-container .history-content .history-group .history-item:hover{background:#f2f4f7;margin:0 -8px;padding:0 8px}.history-modal-container .history-content .no-results{text-align:center;color:#999;padding:40px 20px}[data-theme=dark] .history-selector .history-timestamp,[data-theme=dark] .history-selector .history-path{color:#ffffff73}[data-theme=dark] .history-selector .history-description{color:#f8fafd}[data-theme=dark] .history-selector .history-no-items{color:#ffffff73}[data-theme=dark] .history-selector .history-item:hover{background:#ffffff14}[data-theme=dark] .history-selector .history-item .history-clear-icon{border-color:#ffffff1f}[data-theme=dark] .history-selector .history-item .history-clear-icon:hover{border-color:#40a9ff}[data-theme=dark] .history-selector .history-load-more{color:#1890ff}[data-theme=dark] .history-selector .history-load-more:hover{color:#40a9ff}.screenshot-viewer{flex-direction:column;height:100%;display:flex}.screenshot-viewer.offline,.screenshot-viewer.loading,.screenshot-viewer.error{text-align:center;color:#666;justify-content:center;align-items:center}.screenshot-viewer.offline .screenshot-placeholder h3,.screenshot-viewer.loading .screenshot-placeholder h3,.screenshot-viewer.error .screenshot-placeholder h3{color:#1890ff;text-transform:capitalize;margin-bottom:12px;font-size:18px}.screenshot-viewer.offline .screenshot-placeholder p,.screenshot-viewer.loading .screenshot-placeholder p,.screenshot-viewer.error .screenshot-placeholder p{color:#666;margin:0}.screenshot-viewer.offline .screenshot-placeholder p.error-message,.screenshot-viewer.loading .screenshot-placeholder p.error-message,.screenshot-viewer.error .screenshot-placeholder p.error-message{color:#ff4d4f}.screenshot-viewer .screenshot-header{justify-content:space-between;align-items:center;height:56px;display:flex}.screenshot-viewer .screenshot-header .screenshot-title{flex-direction:column;gap:4px;display:flex}.screenshot-viewer .screenshot-header .screenshot-title h3{color:#000;text-transform:capitalize;align-items:center;gap:8px;margin:0;font-size:14px;font-weight:600;display:flex}.screenshot-viewer .screenshot-header .screenshot-title .screenshot-subtitle{color:#999;margin:0;font-size:12px}.screenshot-viewer .screenshot-container{background:#f2f4f7;border-radius:16px;flex-direction:column;flex:1;padding:0 15px;display:flex;overflow:hidden}.screenshot-viewer .screenshot-container .screenshot-overlay{z-index:10;justify-content:space-between;align-items:flex-start;padding:12px 5px 8px;display:flex}.screenshot-viewer .screenshot-container .screenshot-overlay .device-name-overlay{color:#000000d9;text-transform:capitalize;align-items:center;gap:8px;font-size:12px;font-weight:500;display:flex}.screenshot-viewer .screenshot-container .screenshot-overlay .device-name-overlay .info-icon{opacity:.8;cursor:pointer;font-size:12px}.screenshot-viewer .screenshot-container .screenshot-overlay .device-name-overlay .info-icon:hover{opacity:1}.screenshot-viewer .screenshot-container .screenshot-overlay .screenshot-controls{opacity:1;box-sizing:border-box;border-radius:4px;align-items:center;gap:10px;height:18px;padding:4px 8px;display:flex}.screenshot-viewer .screenshot-container .screenshot-overlay .screenshot-controls .last-update-time{color:#666;white-space:nowrap;text-overflow:ellipsis;font-size:12px;overflow:hidden}.screenshot-viewer .screenshot-container .screenshot-overlay .screenshot-controls .operation-indicator{align-items:center;gap:4px;font-size:12px;display:flex}.screenshot-viewer .screenshot-container .screenshot-overlay .screenshot-controls .ant-btn{box-shadow:none;background:0 0;border:none;justify-content:center;align-items:center;width:16px;min-width:16px;height:16px;padding:0;display:flex}.screenshot-viewer .screenshot-container .screenshot-overlay .screenshot-controls .ant-btn:hover{background-color:#0000000f;border-radius:2px;transition:all .2s;transform:scale(1.1)}.screenshot-viewer .screenshot-container .screenshot-overlay .screenshot-controls .ant-btn .anticon{color:#666;font-size:12px;transition:color .2s}.screenshot-viewer .screenshot-container .screenshot-content{flex:1;justify-content:center;align-items:center;min-height:0;display:flex}.screenshot-viewer .screenshot-container .screenshot-content .screenshot-image{object-fit:contain;border-radius:12px;max-width:100%;height:auto;max-height:100%}.screenshot-viewer .screenshot-container .screenshot-content .screenshot-placeholder{text-align:center;color:#999}[data-theme=dark] .screenshot-viewer.offline,[data-theme=dark] .screenshot-viewer.loading,[data-theme=dark] .screenshot-viewer.error{color:#f8fafd}[data-theme=dark] .screenshot-viewer.offline .screenshot-placeholder h3,[data-theme=dark] .screenshot-viewer.loading .screenshot-placeholder h3,[data-theme=dark] .screenshot-viewer.error .screenshot-placeholder h3{color:#1890ff}[data-theme=dark] .screenshot-viewer.offline .screenshot-placeholder p,[data-theme=dark] .screenshot-viewer.loading .screenshot-placeholder p,[data-theme=dark] .screenshot-viewer.error .screenshot-placeholder p{color:#f8fafd}[data-theme=dark] .screenshot-viewer.offline .screenshot-placeholder p.error-message,[data-theme=dark] .screenshot-viewer.loading .screenshot-placeholder p.error-message,[data-theme=dark] .screenshot-viewer.error .screenshot-placeholder p.error-message{color:#ff4d4f}[data-theme=dark] .screenshot-viewer .screenshot-header .screenshot-title h3{color:#f8fafd}[data-theme=dark] .screenshot-viewer .screenshot-header .screenshot-title .screenshot-subtitle{color:#ffffff73}[data-theme=dark] .screenshot-viewer .screenshot-container{background:#141414}[data-theme=dark] .screenshot-viewer .screenshot-container .screenshot-overlay .device-name-overlay,[data-theme=dark] .screenshot-viewer .screenshot-container .screenshot-overlay .screenshot-controls .last-update-time{color:#f8fafd}[data-theme=dark] .screenshot-viewer .screenshot-container .screenshot-overlay .screenshot-controls .ant-btn:hover{background-color:#ffffff14}[data-theme=dark] .screenshot-viewer .screenshot-container .screenshot-overlay .screenshot-controls .ant-btn .anticon{color:#f8fafd}[data-theme=dark] .screenshot-viewer .screenshot-container .screenshot-content .screenshot-placeholder{color:#ffffff73}
2
+ /*# sourceMappingURL=index.3d0b5a80.css.map*/