@midscene/playground 1.4.1 → 1.4.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,4 +1,5 @@
1
1
  import { existsSync, readFileSync, writeFileSync } from "node:fs";
2
+ import node_http from "node:http";
2
3
  import { dirname, join, resolve as external_node_path_resolve } from "node:path";
3
4
  import { fileURLToPath } from "node:url";
4
5
  import { GroupedActionDump } from "@midscene/core";
@@ -311,6 +312,17 @@ class PlaygroundServer {
311
312
  });
312
313
  }
313
314
  });
315
+ this._app.get('/mjpeg', async (req, res)=>{
316
+ const nativeUrl = this.agent?.interface?.mjpegStreamUrl;
317
+ if (nativeUrl && false !== this._nativeMjpegAvailable) {
318
+ const proxyOk = await this.probeAndProxyNativeMjpeg(nativeUrl, req, res);
319
+ if (proxyOk) return;
320
+ }
321
+ if ('function' != typeof this.agent?.interface?.screenshotBase64) return res.status(500).json({
322
+ error: 'Screenshot method not available on current interface'
323
+ });
324
+ await this.startPollingMjpegStream(req, res);
325
+ });
314
326
  this._app.get('/interface-info', async (_req, res)=>{
315
327
  try {
316
328
  const type = this.agent.interface.interfaceType || 'Unknown';
@@ -360,6 +372,71 @@ class PlaygroundServer {
360
372
  });
361
373
  });
362
374
  }
375
+ probeAndProxyNativeMjpeg(nativeUrl, req, res) {
376
+ return new Promise((resolve)=>{
377
+ console.log(`MJPEG: trying native stream from ${nativeUrl}`);
378
+ const proxyReq = node_http.get(nativeUrl, (proxyRes)=>{
379
+ this._nativeMjpegAvailable = true;
380
+ console.log('MJPEG: streaming via native WDA MJPEG server');
381
+ const contentType = proxyRes.headers['content-type'];
382
+ if (contentType) res.setHeader('Content-Type', contentType);
383
+ res.setHeader('Cache-Control', 'no-cache, no-store, must-revalidate');
384
+ res.setHeader('Connection', 'keep-alive');
385
+ proxyRes.pipe(res);
386
+ req.on('close', ()=>proxyReq.destroy());
387
+ resolve(true);
388
+ });
389
+ proxyReq.on('error', (err)=>{
390
+ this._nativeMjpegAvailable = false;
391
+ console.warn(`MJPEG: native stream unavailable (${err.message}), using polling mode`);
392
+ resolve(false);
393
+ });
394
+ });
395
+ }
396
+ async startPollingMjpegStream(req, res) {
397
+ const defaultMjpegFps = 10;
398
+ const maxMjpegFps = 30;
399
+ const maxErrorBackoffMs = 3000;
400
+ const errorLogThreshold = 3;
401
+ const fps = Math.min(Math.max(Number(req.query.fps) ?? defaultMjpegFps, 1), maxMjpegFps);
402
+ const interval = Math.round(1000 / fps);
403
+ const boundary = 'mjpeg-boundary';
404
+ console.log(`MJPEG: streaming via polling mode (${fps}fps)`);
405
+ res.setHeader('Content-Type', `multipart/x-mixed-replace; boundary=${boundary}`);
406
+ res.setHeader('Cache-Control', 'no-cache, no-store, must-revalidate');
407
+ res.setHeader('Connection', 'keep-alive');
408
+ let stopped = false;
409
+ let consecutiveErrors = 0;
410
+ req.on('close', ()=>{
411
+ stopped = true;
412
+ });
413
+ while(!stopped){
414
+ const frameStart = Date.now();
415
+ try {
416
+ const base64 = await this.agent.interface.screenshotBase64();
417
+ if (stopped) break;
418
+ consecutiveErrors = 0;
419
+ const raw = base64.replace(/^data:image\/\w+;base64,/, '');
420
+ const buf = Buffer.from(raw, 'base64');
421
+ res.write(`--${boundary}\r\n`);
422
+ res.write('Content-Type: image/jpeg\r\n');
423
+ res.write(`Content-Length: ${buf.length}\r\n\r\n`);
424
+ res.write(buf);
425
+ res.write('\r\n');
426
+ } catch (err) {
427
+ if (stopped) break;
428
+ consecutiveErrors++;
429
+ if (consecutiveErrors <= errorLogThreshold) console.error('MJPEG frame error:', err);
430
+ else if (consecutiveErrors === errorLogThreshold + 1) console.error('MJPEG: suppressing further errors, retrying silently...');
431
+ const backoff = Math.min(1000 * consecutiveErrors, maxErrorBackoffMs);
432
+ await new Promise((r)=>setTimeout(r, backoff));
433
+ continue;
434
+ }
435
+ const elapsed = Date.now() - frameStart;
436
+ const remaining = interval - elapsed;
437
+ if (remaining > 0) await new Promise((r)=>setTimeout(r, remaining));
438
+ }
439
+ }
363
440
  setupStaticRoutes() {
364
441
  this._app.get('/', (_req, res)=>{
365
442
  this.serveHtmlWithPorts(res);
@@ -434,6 +511,7 @@ class PlaygroundServer {
434
511
  _define_property(this, "taskExecutionDumps", void 0);
435
512
  _define_property(this, "id", void 0);
436
513
  _define_property(this, "_initialized", false);
514
+ _define_property(this, "_nativeMjpegAvailable", null);
437
515
  _define_property(this, "agentFactory", void 0);
438
516
  _define_property(this, "currentTaskId", null);
439
517
  this._app = express();
@@ -1 +1 @@
1
- {"version":3,"file":"server.mjs","sources":["../../src/server.ts"],"sourcesContent":["import { existsSync, readFileSync, writeFileSync } from 'node:fs';\nimport type { Server } from 'node:http';\nimport { dirname, join, resolve } from 'node:path';\nimport { fileURLToPath } from 'node:url';\nimport type { ExecutionDump } from '@midscene/core';\nimport { GroupedActionDump } from '@midscene/core';\nimport type { Agent as PageAgent } from '@midscene/core/agent';\nimport { getTmpDir } from '@midscene/core/utils';\nimport { PLAYGROUND_SERVER_PORT } from '@midscene/shared/constants';\nimport {\n globalModelConfigManager,\n overrideAIConfig,\n} from '@midscene/shared/env';\nimport { uuid } from '@midscene/shared/utils';\nimport express, { type Request, type Response } from 'express';\nimport { executeAction, formatErrorMessage } from './common';\n\nimport 'dotenv/config';\n\nconst defaultPort = PLAYGROUND_SERVER_PORT;\n\n// Static path for playground files\nconst __filename = fileURLToPath(import.meta.url);\nconst __dirname = dirname(__filename);\nconst STATIC_PATH = join(__dirname, '..', '..', 'static');\n\nconst errorHandler = (\n err: unknown,\n req: Request,\n res: Response,\n next: express.NextFunction,\n) => {\n console.error(err);\n const errorMessage =\n err instanceof Error ? err.message : 'Internal server error';\n res.status(500).json({\n error: errorMessage,\n });\n};\n\nclass PlaygroundServer {\n private _app: express.Application;\n tmpDir: string;\n server?: Server;\n port?: number | null;\n agent: PageAgent;\n staticPath: string;\n taskExecutionDumps: Record<string, ExecutionDump | null>; // Store execution dumps directly\n id: string; // Unique identifier for this server instance\n\n private _initialized = false;\n\n // Factory function for recreating agent\n private agentFactory?: (() => PageAgent | Promise<PageAgent>) | null;\n\n // Track current running task\n private currentTaskId: string | null = null;\n\n constructor(\n agent: PageAgent | (() => PageAgent) | (() => Promise<PageAgent>),\n staticPath = STATIC_PATH,\n id?: string, // Optional override ID\n ) {\n this._app = express();\n this.tmpDir = getTmpDir()!;\n this.staticPath = staticPath;\n this.taskExecutionDumps = {}; // Initialize as empty object\n // Use provided ID, or generate random UUID for each startup\n this.id = id || uuid();\n\n // Support both instance and factory function modes\n if (typeof agent === 'function') {\n this.agentFactory = agent;\n this.agent = null as any; // Will be initialized in launch()\n } else {\n this.agent = agent;\n this.agentFactory = null;\n }\n }\n\n /**\n * Get the Express app instance for custom configuration\n *\n * IMPORTANT: Add middleware (like CORS) BEFORE calling launch()\n * The routes are initialized when launch() is called, so middleware\n * added after launch() will not affect the API routes.\n *\n * @example\n * ```typescript\n * import cors from 'cors';\n *\n * const server = new PlaygroundServer(agent);\n *\n * // Add CORS middleware before launch\n * server.app.use(cors({\n * origin: true,\n * credentials: true,\n * methods: ['GET', 'POST', 'PUT', 'DELETE', 'OPTIONS']\n * }));\n *\n * await server.launch();\n * ```\n */\n get app(): express.Application {\n return this._app;\n }\n\n /**\n * Initialize Express app with all routes and middleware\n * Called automatically by launch() if not already initialized\n */\n private initializeApp(): void {\n if (this._initialized) return;\n\n // Built-in middleware to parse JSON bodies\n this._app.use(express.json({ limit: '50mb' }));\n\n // Context update middleware (after JSON parsing)\n this._app.use(\n (req: Request, _res: Response, next: express.NextFunction) => {\n const { context } = req.body || {};\n if (\n context &&\n 'updateContext' in this.agent.interface &&\n typeof this.agent.interface.updateContext === 'function'\n ) {\n this.agent.interface.updateContext(context);\n console.log('Context updated by PlaygroundServer middleware');\n }\n next();\n },\n );\n\n // NOTE: CORS middleware should be added externally via server.app.use()\n // before calling server.launch() if needed\n\n // API routes\n this.setupRoutes();\n\n // Static file serving (if staticPath is provided)\n this.setupStaticRoutes();\n\n // Error handler middleware (must be last)\n this._app.use(errorHandler);\n\n this._initialized = true;\n }\n\n filePathForUuid(uuid: string) {\n // Validate uuid to prevent path traversal attacks\n // Only allow alphanumeric characters and hyphens\n if (!/^[a-zA-Z0-9-]+$/.test(uuid)) {\n throw new Error('Invalid uuid format');\n }\n const filePath = join(this.tmpDir, `${uuid}.json`);\n // Double-check that resolved path is within tmpDir\n const resolvedPath = resolve(filePath);\n const resolvedTmpDir = resolve(this.tmpDir);\n if (!resolvedPath.startsWith(resolvedTmpDir)) {\n throw new Error('Invalid path');\n }\n return filePath;\n }\n\n saveContextFile(uuid: string, context: string) {\n const tmpFile = this.filePathForUuid(uuid);\n console.log(`save context file: ${tmpFile}`);\n writeFileSync(tmpFile, context);\n return tmpFile;\n }\n\n /**\n * Recreate agent instance (for cancellation)\n */\n private async recreateAgent(): Promise<void> {\n if (!this.agentFactory) {\n throw new Error(\n 'Cannot recreate agent: factory function not provided. Attempting to destroy existing agent only.',\n );\n }\n\n console.log('Recreating agent to cancel current task...');\n\n // Destroy old agent instance\n try {\n if (this.agent && typeof this.agent.destroy === 'function') {\n await this.agent.destroy();\n }\n } catch (error) {\n console.warn('Failed to destroy old agent:', error);\n }\n\n // Create new agent instance\n try {\n this.agent = await this.agentFactory();\n console.log('Agent recreated successfully');\n } catch (error) {\n console.error('Failed to recreate agent:', error);\n throw error;\n }\n }\n\n /**\n * Setup all API routes\n */\n private setupRoutes(): void {\n this._app.get('/status', async (req: Request, res: Response) => {\n res.send({\n status: 'ok',\n id: this.id,\n });\n });\n\n this._app.get('/context/:uuid', async (req: Request, res: Response) => {\n const { uuid } = req.params;\n let contextFile: string;\n try {\n contextFile = this.filePathForUuid(uuid);\n } catch {\n return res.status(400).json({\n error: 'Invalid uuid format',\n });\n }\n\n if (!existsSync(contextFile)) {\n return res.status(404).json({\n error: 'Context not found',\n });\n }\n\n const context = readFileSync(contextFile, 'utf8');\n res.json({\n context,\n });\n });\n\n this._app.get(\n '/task-progress/:requestId',\n async (req: Request, res: Response) => {\n const { requestId } = req.params;\n const executionDump = this.taskExecutionDumps[requestId] || null;\n\n res.json({\n executionDump,\n });\n },\n );\n\n this._app.post('/action-space', async (req: Request, res: Response) => {\n try {\n let actionSpace = [];\n\n actionSpace = this.agent.interface.actionSpace();\n\n // Process actionSpace to make paramSchema serializable with shape info\n const processedActionSpace = actionSpace.map((action: unknown) => {\n if (action && typeof action === 'object' && 'paramSchema' in action) {\n const typedAction = action as {\n paramSchema?: { shape?: object; [key: string]: unknown };\n [key: string]: unknown;\n };\n if (\n typedAction.paramSchema &&\n typeof typedAction.paramSchema === 'object'\n ) {\n // Extract shape information from Zod schema\n let processedSchema = null;\n\n try {\n // Extract shape from runtime Zod object\n if (\n typedAction.paramSchema.shape &&\n typeof typedAction.paramSchema.shape === 'object'\n ) {\n processedSchema = {\n type: 'ZodObject',\n shape: typedAction.paramSchema.shape,\n };\n }\n } catch (e) {\n const actionName =\n 'name' in typedAction && typeof typedAction.name === 'string'\n ? typedAction.name\n : 'unknown';\n console.warn(\n 'Failed to process paramSchema for action:',\n actionName,\n e,\n );\n }\n\n return {\n ...typedAction,\n paramSchema: processedSchema,\n };\n }\n }\n return action;\n });\n\n res.json(processedActionSpace);\n } catch (error: unknown) {\n const errorMessage =\n error instanceof Error ? error.message : 'Unknown error';\n console.error('Failed to get action space:', error);\n res.status(500).json({\n error: errorMessage,\n });\n }\n });\n\n // -------------------------\n // actions from report file\n this._app.post(\n '/playground-with-context',\n async (req: Request, res: Response) => {\n const context = req.body.context;\n\n if (!context) {\n return res.status(400).json({\n error: 'context is required',\n });\n }\n\n const requestId = uuid();\n this.saveContextFile(requestId, context);\n return res.json({\n location: `/playground/${requestId}`,\n uuid: requestId,\n });\n },\n );\n\n this._app.post('/execute', async (req: Request, res: Response) => {\n const {\n type,\n prompt,\n params,\n requestId,\n deepThink,\n screenshotIncluded,\n domIncluded,\n deviceOptions,\n } = req.body;\n\n if (!type) {\n return res.status(400).json({\n error: 'type is required',\n });\n }\n\n // Always recreate agent before execution to ensure latest config is applied\n if (this.agentFactory) {\n console.log('Destroying old agent before execution...');\n try {\n if (this.agent && typeof this.agent.destroy === 'function') {\n await this.agent.destroy();\n }\n } catch (error) {\n console.warn('Failed to destroy old agent:', error);\n }\n\n console.log('Creating new agent with latest config...');\n try {\n this.agent = await this.agentFactory();\n console.log('Agent created successfully');\n } catch (error) {\n console.error('Failed to create agent:', error);\n return res.status(500).json({\n error: `Failed to create agent: ${error instanceof Error ? error.message : 'Unknown error'}`,\n });\n }\n }\n\n // Update device options if provided\n if (\n deviceOptions &&\n this.agent.interface &&\n 'options' in this.agent.interface\n ) {\n this.agent.interface.options = {\n ...(this.agent.interface.options || {}),\n ...deviceOptions,\n };\n }\n\n // Check if another task is running\n if (this.currentTaskId) {\n return res.status(409).json({\n error: 'Another task is already running',\n currentTaskId: this.currentTaskId,\n });\n }\n\n // Lock this task\n if (requestId) {\n this.currentTaskId = requestId;\n this.taskExecutionDumps[requestId] = null;\n\n // Use onDumpUpdate to receive and store executionDump directly\n this.agent.onDumpUpdate = (\n _dump: string,\n executionDump?: ExecutionDump,\n ) => {\n if (executionDump) {\n // Store the execution dump directly without transformation\n this.taskExecutionDumps[requestId] = executionDump;\n }\n };\n }\n\n const response: {\n result: unknown;\n dump: ExecutionDump | null;\n error: string | null;\n reportHTML: string | null;\n requestId?: string;\n } = {\n result: null,\n dump: null,\n error: null,\n reportHTML: null,\n requestId,\n };\n\n const startTime = Date.now();\n try {\n // Get action space to check for dynamic actions\n const actionSpace = this.agent.interface.actionSpace();\n\n // Prepare value object for executeAction\n const value = {\n type,\n prompt,\n params,\n };\n\n response.result = await executeAction(\n this.agent,\n type,\n actionSpace,\n value,\n {\n deepThink,\n screenshotIncluded,\n domIncluded,\n deviceOptions,\n },\n );\n } catch (error: unknown) {\n response.error = formatErrorMessage(error);\n }\n\n try {\n const dumpString = this.agent.dumpDataString({\n inlineScreenshots: true,\n });\n if (dumpString) {\n const groupedDump =\n GroupedActionDump.fromSerializedString(dumpString);\n // Extract first execution from grouped dump, matching local execution adapter behavior\n response.dump = groupedDump.executions?.[0] || null;\n } else {\n response.dump = null;\n }\n response.reportHTML =\n this.agent.reportHTMLString({ inlineScreenshots: true }) || null;\n\n this.agent.writeOutActionDumps();\n this.agent.resetDump();\n } catch (error: unknown) {\n const errorMessage =\n error instanceof Error ? error.message : 'Unknown error';\n console.error(\n `write out dump failed: requestId: ${requestId}, ${errorMessage}`,\n );\n }\n\n res.send(response);\n const timeCost = Date.now() - startTime;\n\n if (response.error) {\n console.error(\n `handle request failed after ${timeCost}ms: requestId: ${requestId}, ${response.error}`,\n );\n } else {\n console.log(\n `handle request done after ${timeCost}ms: requestId: ${requestId}`,\n );\n }\n\n // Clean up task execution dumps and unlock after execution completes\n if (requestId) {\n delete this.taskExecutionDumps[requestId];\n // Release the lock\n if (this.currentTaskId === requestId) {\n this.currentTaskId = null;\n }\n }\n });\n\n this._app.post(\n '/cancel/:requestId',\n async (req: Request, res: Response) => {\n const { requestId } = req.params;\n\n if (!requestId) {\n return res.status(400).json({\n error: 'requestId is required',\n });\n }\n\n try {\n // Check if this is the current running task\n if (this.currentTaskId !== requestId) {\n return res.json({\n status: 'not_found',\n message: 'Task not found or already completed',\n });\n }\n\n console.log(`Cancelling task: ${requestId}`);\n\n // Get current execution data before cancelling (dump and reportHTML)\n let dump: any = null;\n let reportHTML: string | null = null;\n\n try {\n const dumpString = this.agent.dumpDataString?.({\n inlineScreenshots: true,\n });\n if (dumpString) {\n const groupedDump =\n GroupedActionDump.fromSerializedString(dumpString);\n // Extract first execution from grouped dump\n dump = groupedDump.executions?.[0] || null;\n }\n\n reportHTML =\n this.agent.reportHTMLString?.({ inlineScreenshots: true }) ||\n null;\n } catch (error: unknown) {\n console.warn('Failed to get execution data before cancel:', error);\n }\n\n // Recreate/destroy agent to cancel the current task\n await this.recreateAgent();\n\n // Clean up\n delete this.taskExecutionDumps[requestId];\n this.currentTaskId = null;\n\n res.json({\n status: 'cancelled',\n message: 'Task cancelled successfully',\n dump,\n reportHTML,\n });\n } catch (error: unknown) {\n const errorMessage =\n error instanceof Error ? error.message : 'Unknown error';\n console.error(`Failed to cancel: ${errorMessage}`);\n res.status(500).json({\n error: `Failed to cancel: ${errorMessage}`,\n });\n }\n },\n );\n\n // Screenshot API for real-time screenshot polling\n this._app.get('/screenshot', async (_req: Request, res: Response) => {\n try {\n // Check if page has screenshotBase64 method\n if (typeof this.agent.interface.screenshotBase64 !== 'function') {\n return res.status(500).json({\n error: 'Screenshot method not available on current interface',\n });\n }\n\n const base64Screenshot = await this.agent.interface.screenshotBase64();\n\n res.json({\n screenshot: base64Screenshot,\n timestamp: Date.now(),\n });\n } catch (error: unknown) {\n const errorMessage =\n error instanceof Error ? error.message : 'Unknown error';\n console.error(`Failed to take screenshot: ${errorMessage}`);\n res.status(500).json({\n error: `Failed to take screenshot: ${errorMessage}`,\n });\n }\n });\n\n // Interface info API for getting interface type and description\n this._app.get('/interface-info', async (_req: Request, res: Response) => {\n try {\n const type = this.agent.interface.interfaceType || 'Unknown';\n const description = this.agent.interface.describe?.() || undefined;\n\n res.json({\n type,\n description,\n });\n } catch (error: unknown) {\n const errorMessage =\n error instanceof Error ? error.message : 'Unknown error';\n console.error(`Failed to get interface info: ${errorMessage}`);\n res.status(500).json({\n error: `Failed to get interface info: ${errorMessage}`,\n });\n }\n });\n\n this.app.post('/config', async (req: Request, res: Response) => {\n const { aiConfig } = req.body;\n\n if (!aiConfig || typeof aiConfig !== 'object') {\n return res.status(400).json({\n error: 'aiConfig is required and must be an object',\n });\n }\n\n if (Object.keys(aiConfig).length === 0) {\n return res.json({\n status: 'ok',\n message: 'AI config not changed due to empty object',\n });\n }\n\n try {\n overrideAIConfig(aiConfig);\n } catch (error: unknown) {\n const errorMessage =\n error instanceof Error ? error.message : 'Unknown error';\n console.error(`Failed to update AI config: ${errorMessage}`);\n return res.status(500).json({\n error: `Failed to update AI config: ${errorMessage}`,\n });\n }\n\n // Validate the config immediately so the frontend gets early feedback\n try {\n globalModelConfigManager.getModelConfig('default');\n } catch (error: unknown) {\n const errorMessage =\n error instanceof Error ? error.message : 'Unknown error';\n console.error(`AI config validation failed: ${errorMessage}`);\n return res.status(400).json({\n error: errorMessage,\n });\n }\n\n // Note: Agent will be recreated on next execution to apply new config\n return res.json({\n status: 'ok',\n message:\n 'AI config updated. Agent will be recreated on next execution.',\n });\n });\n }\n\n /**\n * Setup static file serving routes\n */\n private setupStaticRoutes(): void {\n // Handle index.html with port injection\n this._app.get('/', (_req: Request, res: Response) => {\n this.serveHtmlWithPorts(res);\n });\n\n this._app.get('/index.html', (_req: Request, res: Response) => {\n this.serveHtmlWithPorts(res);\n });\n\n // Use express.static middleware for secure static file serving\n this._app.use(express.static(this.staticPath));\n\n // Fallback to index.html for SPA routing\n this._app.get('*', (_req: Request, res: Response) => {\n this.serveHtmlWithPorts(res);\n });\n }\n\n /**\n * Serve HTML with injected port configuration\n */\n private serveHtmlWithPorts(res: Response): void {\n try {\n const htmlPath = join(this.staticPath, 'index.html');\n let html = readFileSync(htmlPath, 'utf8');\n\n // Get scrcpy server port from global\n const scrcpyPort = (global as any).scrcpyServerPort || this.port! + 1;\n\n // Inject scrcpy port configuration script into HTML head\n const configScript = `\n <script>\n window.SCRCPY_PORT = ${scrcpyPort};\n </script>\n `;\n\n // Insert the script before closing </head> tag\n html = html.replace('</head>', `${configScript}</head>`);\n\n res.setHeader('Content-Type', 'text/html');\n res.send(html);\n } catch (error) {\n console.error('Error serving HTML with ports:', error);\n res.status(500).send('Internal Server Error');\n }\n }\n\n /**\n * Launch the server on specified port\n */\n async launch(port?: number): Promise<PlaygroundServer> {\n // If using factory mode, initialize agent\n if (this.agentFactory) {\n console.log('Initializing agent from factory function...');\n this.agent = await this.agentFactory();\n console.log('Agent initialized successfully');\n }\n\n // Initialize routes now, after any middleware has been added\n this.initializeApp();\n\n this.port = port || defaultPort;\n\n return new Promise((resolve) => {\n const serverPort = this.port;\n this.server = this._app.listen(serverPort, () => {\n resolve(this);\n });\n });\n }\n\n /**\n * Close the server and clean up resources\n */\n async close(): Promise<void> {\n return new Promise((resolve, reject) => {\n if (this.server) {\n // Clean up the single agent\n try {\n this.agent.destroy();\n } catch (error) {\n console.warn('Failed to destroy agent:', error);\n }\n this.taskExecutionDumps = {};\n\n // Close the server\n this.server.close((error) => {\n if (error) {\n reject(error);\n } else {\n this.server = undefined;\n resolve();\n }\n });\n } else {\n resolve();\n }\n });\n }\n}\n\nexport default PlaygroundServer;\nexport { PlaygroundServer };\n"],"names":["defaultPort","PLAYGROUND_SERVER_PORT","__filename","fileURLToPath","__dirname","dirname","STATIC_PATH","join","errorHandler","err","req","res","next","console","errorMessage","Error","PlaygroundServer","express","_res","context","uuid","filePath","resolvedPath","resolve","resolvedTmpDir","tmpFile","writeFileSync","error","contextFile","existsSync","readFileSync","requestId","executionDump","actionSpace","processedActionSpace","action","typedAction","processedSchema","e","actionName","type","prompt","params","deepThink","screenshotIncluded","domIncluded","deviceOptions","_dump","response","startTime","Date","value","executeAction","formatErrorMessage","dumpString","groupedDump","GroupedActionDump","timeCost","dump","reportHTML","_req","base64Screenshot","description","undefined","aiConfig","Object","overrideAIConfig","globalModelConfigManager","htmlPath","html","scrcpyPort","global","configScript","port","Promise","serverPort","reject","agent","staticPath","id","getTmpDir"],"mappings":"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"}
1
+ {"version":3,"file":"server.mjs","sources":["../../src/server.ts"],"sourcesContent":["import { existsSync, readFileSync, writeFileSync } from 'node:fs';\nimport http from 'node:http';\nimport type { Server } from 'node:http';\nimport { dirname, join, resolve } from 'node:path';\nimport { fileURLToPath } from 'node:url';\nimport type { ExecutionDump } from '@midscene/core';\nimport { GroupedActionDump } from '@midscene/core';\nimport type { Agent as PageAgent } from '@midscene/core/agent';\nimport { getTmpDir } from '@midscene/core/utils';\nimport { PLAYGROUND_SERVER_PORT } from '@midscene/shared/constants';\nimport {\n globalModelConfigManager,\n overrideAIConfig,\n} from '@midscene/shared/env';\nimport { uuid } from '@midscene/shared/utils';\nimport express, { type Request, type Response } from 'express';\nimport { executeAction, formatErrorMessage } from './common';\n\nimport 'dotenv/config';\n\nconst defaultPort = PLAYGROUND_SERVER_PORT;\n\n// Static path for playground files\nconst __filename = fileURLToPath(import.meta.url);\nconst __dirname = dirname(__filename);\nconst STATIC_PATH = join(__dirname, '..', '..', 'static');\n\nconst errorHandler = (\n err: unknown,\n req: Request,\n res: Response,\n next: express.NextFunction,\n) => {\n console.error(err);\n const errorMessage =\n err instanceof Error ? err.message : 'Internal server error';\n res.status(500).json({\n error: errorMessage,\n });\n};\n\nclass PlaygroundServer {\n private _app: express.Application;\n tmpDir: string;\n server?: Server;\n port?: number | null;\n agent: PageAgent;\n staticPath: string;\n taskExecutionDumps: Record<string, ExecutionDump | null>; // Store execution dumps directly\n id: string; // Unique identifier for this server instance\n\n private _initialized = false;\n\n // Native MJPEG stream probe: null = not tested, true/false = result\n private _nativeMjpegAvailable: boolean | null = null;\n\n // Factory function for recreating agent\n private agentFactory?: (() => PageAgent | Promise<PageAgent>) | null;\n\n // Track current running task\n private currentTaskId: string | null = null;\n\n constructor(\n agent: PageAgent | (() => PageAgent) | (() => Promise<PageAgent>),\n staticPath = STATIC_PATH,\n id?: string, // Optional override ID\n ) {\n this._app = express();\n this.tmpDir = getTmpDir()!;\n this.staticPath = staticPath;\n this.taskExecutionDumps = {}; // Initialize as empty object\n // Use provided ID, or generate random UUID for each startup\n this.id = id || uuid();\n\n // Support both instance and factory function modes\n if (typeof agent === 'function') {\n this.agentFactory = agent;\n this.agent = null as any; // Will be initialized in launch()\n } else {\n this.agent = agent;\n this.agentFactory = null;\n }\n }\n\n /**\n * Get the Express app instance for custom configuration\n *\n * IMPORTANT: Add middleware (like CORS) BEFORE calling launch()\n * The routes are initialized when launch() is called, so middleware\n * added after launch() will not affect the API routes.\n *\n * @example\n * ```typescript\n * import cors from 'cors';\n *\n * const server = new PlaygroundServer(agent);\n *\n * // Add CORS middleware before launch\n * server.app.use(cors({\n * origin: true,\n * credentials: true,\n * methods: ['GET', 'POST', 'PUT', 'DELETE', 'OPTIONS']\n * }));\n *\n * await server.launch();\n * ```\n */\n get app(): express.Application {\n return this._app;\n }\n\n /**\n * Initialize Express app with all routes and middleware\n * Called automatically by launch() if not already initialized\n */\n private initializeApp(): void {\n if (this._initialized) return;\n\n // Built-in middleware to parse JSON bodies\n this._app.use(express.json({ limit: '50mb' }));\n\n // Context update middleware (after JSON parsing)\n this._app.use(\n (req: Request, _res: Response, next: express.NextFunction) => {\n const { context } = req.body || {};\n if (\n context &&\n 'updateContext' in this.agent.interface &&\n typeof this.agent.interface.updateContext === 'function'\n ) {\n this.agent.interface.updateContext(context);\n console.log('Context updated by PlaygroundServer middleware');\n }\n next();\n },\n );\n\n // NOTE: CORS middleware should be added externally via server.app.use()\n // before calling server.launch() if needed\n\n // API routes\n this.setupRoutes();\n\n // Static file serving (if staticPath is provided)\n this.setupStaticRoutes();\n\n // Error handler middleware (must be last)\n this._app.use(errorHandler);\n\n this._initialized = true;\n }\n\n filePathForUuid(uuid: string) {\n // Validate uuid to prevent path traversal attacks\n // Only allow alphanumeric characters and hyphens\n if (!/^[a-zA-Z0-9-]+$/.test(uuid)) {\n throw new Error('Invalid uuid format');\n }\n const filePath = join(this.tmpDir, `${uuid}.json`);\n // Double-check that resolved path is within tmpDir\n const resolvedPath = resolve(filePath);\n const resolvedTmpDir = resolve(this.tmpDir);\n if (!resolvedPath.startsWith(resolvedTmpDir)) {\n throw new Error('Invalid path');\n }\n return filePath;\n }\n\n saveContextFile(uuid: string, context: string) {\n const tmpFile = this.filePathForUuid(uuid);\n console.log(`save context file: ${tmpFile}`);\n writeFileSync(tmpFile, context);\n return tmpFile;\n }\n\n /**\n * Recreate agent instance (for cancellation)\n */\n private async recreateAgent(): Promise<void> {\n if (!this.agentFactory) {\n throw new Error(\n 'Cannot recreate agent: factory function not provided. Attempting to destroy existing agent only.',\n );\n }\n\n console.log('Recreating agent to cancel current task...');\n\n // Destroy old agent instance\n try {\n if (this.agent && typeof this.agent.destroy === 'function') {\n await this.agent.destroy();\n }\n } catch (error) {\n console.warn('Failed to destroy old agent:', error);\n }\n\n // Create new agent instance\n try {\n this.agent = await this.agentFactory();\n console.log('Agent recreated successfully');\n } catch (error) {\n console.error('Failed to recreate agent:', error);\n throw error;\n }\n }\n\n /**\n * Setup all API routes\n */\n private setupRoutes(): void {\n this._app.get('/status', async (req: Request, res: Response) => {\n res.send({\n status: 'ok',\n id: this.id,\n });\n });\n\n this._app.get('/context/:uuid', async (req: Request, res: Response) => {\n const { uuid } = req.params;\n let contextFile: string;\n try {\n contextFile = this.filePathForUuid(uuid);\n } catch {\n return res.status(400).json({\n error: 'Invalid uuid format',\n });\n }\n\n if (!existsSync(contextFile)) {\n return res.status(404).json({\n error: 'Context not found',\n });\n }\n\n const context = readFileSync(contextFile, 'utf8');\n res.json({\n context,\n });\n });\n\n this._app.get(\n '/task-progress/:requestId',\n async (req: Request, res: Response) => {\n const { requestId } = req.params;\n const executionDump = this.taskExecutionDumps[requestId] || null;\n\n res.json({\n executionDump,\n });\n },\n );\n\n this._app.post('/action-space', async (req: Request, res: Response) => {\n try {\n let actionSpace = [];\n\n actionSpace = this.agent.interface.actionSpace();\n\n // Process actionSpace to make paramSchema serializable with shape info\n const processedActionSpace = actionSpace.map((action: unknown) => {\n if (action && typeof action === 'object' && 'paramSchema' in action) {\n const typedAction = action as {\n paramSchema?: { shape?: object; [key: string]: unknown };\n [key: string]: unknown;\n };\n if (\n typedAction.paramSchema &&\n typeof typedAction.paramSchema === 'object'\n ) {\n // Extract shape information from Zod schema\n let processedSchema = null;\n\n try {\n // Extract shape from runtime Zod object\n if (\n typedAction.paramSchema.shape &&\n typeof typedAction.paramSchema.shape === 'object'\n ) {\n processedSchema = {\n type: 'ZodObject',\n shape: typedAction.paramSchema.shape,\n };\n }\n } catch (e) {\n const actionName =\n 'name' in typedAction && typeof typedAction.name === 'string'\n ? typedAction.name\n : 'unknown';\n console.warn(\n 'Failed to process paramSchema for action:',\n actionName,\n e,\n );\n }\n\n return {\n ...typedAction,\n paramSchema: processedSchema,\n };\n }\n }\n return action;\n });\n\n res.json(processedActionSpace);\n } catch (error: unknown) {\n const errorMessage =\n error instanceof Error ? error.message : 'Unknown error';\n console.error('Failed to get action space:', error);\n res.status(500).json({\n error: errorMessage,\n });\n }\n });\n\n // -------------------------\n // actions from report file\n this._app.post(\n '/playground-with-context',\n async (req: Request, res: Response) => {\n const context = req.body.context;\n\n if (!context) {\n return res.status(400).json({\n error: 'context is required',\n });\n }\n\n const requestId = uuid();\n this.saveContextFile(requestId, context);\n return res.json({\n location: `/playground/${requestId}`,\n uuid: requestId,\n });\n },\n );\n\n this._app.post('/execute', async (req: Request, res: Response) => {\n const {\n type,\n prompt,\n params,\n requestId,\n deepThink,\n screenshotIncluded,\n domIncluded,\n deviceOptions,\n } = req.body;\n\n if (!type) {\n return res.status(400).json({\n error: 'type is required',\n });\n }\n\n // Always recreate agent before execution to ensure latest config is applied\n if (this.agentFactory) {\n console.log('Destroying old agent before execution...');\n try {\n if (this.agent && typeof this.agent.destroy === 'function') {\n await this.agent.destroy();\n }\n } catch (error) {\n console.warn('Failed to destroy old agent:', error);\n }\n\n console.log('Creating new agent with latest config...');\n try {\n this.agent = await this.agentFactory();\n console.log('Agent created successfully');\n } catch (error) {\n console.error('Failed to create agent:', error);\n return res.status(500).json({\n error: `Failed to create agent: ${error instanceof Error ? error.message : 'Unknown error'}`,\n });\n }\n }\n\n // Update device options if provided\n if (\n deviceOptions &&\n this.agent.interface &&\n 'options' in this.agent.interface\n ) {\n this.agent.interface.options = {\n ...(this.agent.interface.options || {}),\n ...deviceOptions,\n };\n }\n\n // Check if another task is running\n if (this.currentTaskId) {\n return res.status(409).json({\n error: 'Another task is already running',\n currentTaskId: this.currentTaskId,\n });\n }\n\n // Lock this task\n if (requestId) {\n this.currentTaskId = requestId;\n this.taskExecutionDumps[requestId] = null;\n\n // Use onDumpUpdate to receive and store executionDump directly\n this.agent.onDumpUpdate = (\n _dump: string,\n executionDump?: ExecutionDump,\n ) => {\n if (executionDump) {\n // Store the execution dump directly without transformation\n this.taskExecutionDumps[requestId] = executionDump;\n }\n };\n }\n\n const response: {\n result: unknown;\n dump: ExecutionDump | null;\n error: string | null;\n reportHTML: string | null;\n requestId?: string;\n } = {\n result: null,\n dump: null,\n error: null,\n reportHTML: null,\n requestId,\n };\n\n const startTime = Date.now();\n try {\n // Get action space to check for dynamic actions\n const actionSpace = this.agent.interface.actionSpace();\n\n // Prepare value object for executeAction\n const value = {\n type,\n prompt,\n params,\n };\n\n response.result = await executeAction(\n this.agent,\n type,\n actionSpace,\n value,\n {\n deepThink,\n screenshotIncluded,\n domIncluded,\n deviceOptions,\n },\n );\n } catch (error: unknown) {\n response.error = formatErrorMessage(error);\n }\n\n try {\n const dumpString = this.agent.dumpDataString({\n inlineScreenshots: true,\n });\n if (dumpString) {\n const groupedDump =\n GroupedActionDump.fromSerializedString(dumpString);\n // Extract first execution from grouped dump, matching local execution adapter behavior\n response.dump = groupedDump.executions?.[0] || null;\n } else {\n response.dump = null;\n }\n response.reportHTML =\n this.agent.reportHTMLString({ inlineScreenshots: true }) || null;\n\n this.agent.writeOutActionDumps();\n this.agent.resetDump();\n } catch (error: unknown) {\n const errorMessage =\n error instanceof Error ? error.message : 'Unknown error';\n console.error(\n `write out dump failed: requestId: ${requestId}, ${errorMessage}`,\n );\n }\n\n res.send(response);\n const timeCost = Date.now() - startTime;\n\n if (response.error) {\n console.error(\n `handle request failed after ${timeCost}ms: requestId: ${requestId}, ${response.error}`,\n );\n } else {\n console.log(\n `handle request done after ${timeCost}ms: requestId: ${requestId}`,\n );\n }\n\n // Clean up task execution dumps and unlock after execution completes\n if (requestId) {\n delete this.taskExecutionDumps[requestId];\n // Release the lock\n if (this.currentTaskId === requestId) {\n this.currentTaskId = null;\n }\n }\n });\n\n this._app.post(\n '/cancel/:requestId',\n async (req: Request, res: Response) => {\n const { requestId } = req.params;\n\n if (!requestId) {\n return res.status(400).json({\n error: 'requestId is required',\n });\n }\n\n try {\n // Check if this is the current running task\n if (this.currentTaskId !== requestId) {\n return res.json({\n status: 'not_found',\n message: 'Task not found or already completed',\n });\n }\n\n console.log(`Cancelling task: ${requestId}`);\n\n // Get current execution data before cancelling (dump and reportHTML)\n let dump: any = null;\n let reportHTML: string | null = null;\n\n try {\n const dumpString = this.agent.dumpDataString?.({\n inlineScreenshots: true,\n });\n if (dumpString) {\n const groupedDump =\n GroupedActionDump.fromSerializedString(dumpString);\n // Extract first execution from grouped dump\n dump = groupedDump.executions?.[0] || null;\n }\n\n reportHTML =\n this.agent.reportHTMLString?.({ inlineScreenshots: true }) ||\n null;\n } catch (error: unknown) {\n console.warn('Failed to get execution data before cancel:', error);\n }\n\n // Recreate/destroy agent to cancel the current task\n await this.recreateAgent();\n\n // Clean up\n delete this.taskExecutionDumps[requestId];\n this.currentTaskId = null;\n\n res.json({\n status: 'cancelled',\n message: 'Task cancelled successfully',\n dump,\n reportHTML,\n });\n } catch (error: unknown) {\n const errorMessage =\n error instanceof Error ? error.message : 'Unknown error';\n console.error(`Failed to cancel: ${errorMessage}`);\n res.status(500).json({\n error: `Failed to cancel: ${errorMessage}`,\n });\n }\n },\n );\n\n // Screenshot API for real-time screenshot polling\n this._app.get('/screenshot', async (_req: Request, res: Response) => {\n try {\n // Check if page has screenshotBase64 method\n if (typeof this.agent.interface.screenshotBase64 !== 'function') {\n return res.status(500).json({\n error: 'Screenshot method not available on current interface',\n });\n }\n\n const base64Screenshot = await this.agent.interface.screenshotBase64();\n\n res.json({\n screenshot: base64Screenshot,\n timestamp: Date.now(),\n });\n } catch (error: unknown) {\n const errorMessage =\n error instanceof Error ? error.message : 'Unknown error';\n console.error(`Failed to take screenshot: ${errorMessage}`);\n res.status(500).json({\n error: `Failed to take screenshot: ${errorMessage}`,\n });\n }\n });\n\n // MJPEG streaming endpoint for real-time screen preview\n // Proxies native MJPEG stream (e.g. WDA MJPEG server) when available,\n // falls back to polling screenshotBase64() otherwise.\n this._app.get('/mjpeg', async (req: Request, res: Response) => {\n const nativeUrl = this.agent?.interface?.mjpegStreamUrl;\n\n if (nativeUrl && this._nativeMjpegAvailable !== false) {\n const proxyOk = await this.probeAndProxyNativeMjpeg(\n nativeUrl,\n req,\n res,\n );\n if (proxyOk) return;\n }\n\n if (typeof this.agent?.interface?.screenshotBase64 !== 'function') {\n return res.status(500).json({\n error: 'Screenshot method not available on current interface',\n });\n }\n\n await this.startPollingMjpegStream(req, res);\n });\n\n // Interface info API for getting interface type and description\n this._app.get('/interface-info', async (_req: Request, res: Response) => {\n try {\n const type = this.agent.interface.interfaceType || 'Unknown';\n const description = this.agent.interface.describe?.() || undefined;\n\n res.json({\n type,\n description,\n });\n } catch (error: unknown) {\n const errorMessage =\n error instanceof Error ? error.message : 'Unknown error';\n console.error(`Failed to get interface info: ${errorMessage}`);\n res.status(500).json({\n error: `Failed to get interface info: ${errorMessage}`,\n });\n }\n });\n\n this.app.post('/config', async (req: Request, res: Response) => {\n const { aiConfig } = req.body;\n\n if (!aiConfig || typeof aiConfig !== 'object') {\n return res.status(400).json({\n error: 'aiConfig is required and must be an object',\n });\n }\n\n if (Object.keys(aiConfig).length === 0) {\n return res.json({\n status: 'ok',\n message: 'AI config not changed due to empty object',\n });\n }\n\n try {\n overrideAIConfig(aiConfig);\n } catch (error: unknown) {\n const errorMessage =\n error instanceof Error ? error.message : 'Unknown error';\n console.error(`Failed to update AI config: ${errorMessage}`);\n return res.status(500).json({\n error: `Failed to update AI config: ${errorMessage}`,\n });\n }\n\n // Validate the config immediately so the frontend gets early feedback\n try {\n globalModelConfigManager.getModelConfig('default');\n } catch (error: unknown) {\n const errorMessage =\n error instanceof Error ? error.message : 'Unknown error';\n console.error(`AI config validation failed: ${errorMessage}`);\n return res.status(400).json({\n error: errorMessage,\n });\n }\n\n // Note: Agent will be recreated on next execution to apply new config\n return res.json({\n status: 'ok',\n message:\n 'AI config updated. Agent will be recreated on next execution.',\n });\n });\n }\n\n /**\n * Probe and proxy a native MJPEG stream (e.g. WDA MJPEG server).\n * Result is cached so we only probe once per server lifetime.\n */\n private probeAndProxyNativeMjpeg(\n nativeUrl: string,\n req: Request,\n res: Response,\n ): Promise<boolean> {\n return new Promise<boolean>((resolve) => {\n console.log(`MJPEG: trying native stream from ${nativeUrl}`);\n const proxyReq = http.get(nativeUrl, (proxyRes) => {\n this._nativeMjpegAvailable = true;\n console.log('MJPEG: streaming via native WDA MJPEG server');\n const contentType = proxyRes.headers['content-type'];\n if (contentType) {\n res.setHeader('Content-Type', contentType);\n }\n res.setHeader('Cache-Control', 'no-cache, no-store, must-revalidate');\n res.setHeader('Connection', 'keep-alive');\n proxyRes.pipe(res);\n req.on('close', () => proxyReq.destroy());\n resolve(true);\n });\n proxyReq.on('error', (err) => {\n this._nativeMjpegAvailable = false;\n console.warn(\n `MJPEG: native stream unavailable (${err.message}), using polling mode`,\n );\n resolve(false);\n });\n });\n }\n\n /**\n * Stream screenshots as MJPEG by polling screenshotBase64().\n */\n private async startPollingMjpegStream(\n req: Request,\n res: Response,\n ): Promise<void> {\n const defaultMjpegFps = 10;\n const maxMjpegFps = 30;\n const maxErrorBackoffMs = 3000;\n const errorLogThreshold = 3;\n\n const fps = Math.min(\n Math.max(Number(req.query.fps) ?? defaultMjpegFps, 1),\n maxMjpegFps,\n );\n const interval = Math.round(1000 / fps);\n const boundary = 'mjpeg-boundary';\n console.log(`MJPEG: streaming via polling mode (${fps}fps)`);\n\n res.setHeader(\n 'Content-Type',\n `multipart/x-mixed-replace; boundary=${boundary}`,\n );\n res.setHeader('Cache-Control', 'no-cache, no-store, must-revalidate');\n res.setHeader('Connection', 'keep-alive');\n\n let stopped = false;\n let consecutiveErrors = 0;\n req.on('close', () => {\n stopped = true;\n });\n\n while (!stopped) {\n const frameStart = Date.now();\n try {\n const base64 = await this.agent.interface.screenshotBase64();\n if (stopped) break;\n consecutiveErrors = 0;\n\n const raw = base64.replace(/^data:image\\/\\w+;base64,/, '');\n const buf = Buffer.from(raw, 'base64');\n\n res.write(`--${boundary}\\r\\n`);\n res.write('Content-Type: image/jpeg\\r\\n');\n res.write(`Content-Length: ${buf.length}\\r\\n\\r\\n`);\n res.write(buf);\n res.write('\\r\\n');\n } catch (err) {\n if (stopped) break;\n consecutiveErrors++;\n if (consecutiveErrors <= errorLogThreshold) {\n console.error('MJPEG frame error:', err);\n } else if (consecutiveErrors === errorLogThreshold + 1) {\n console.error(\n 'MJPEG: suppressing further errors, retrying silently...',\n );\n }\n const backoff = Math.min(1000 * consecutiveErrors, maxErrorBackoffMs);\n await new Promise((r) => setTimeout(r, backoff));\n continue;\n }\n\n const elapsed = Date.now() - frameStart;\n const remaining = interval - elapsed;\n if (remaining > 0) {\n await new Promise((r) => setTimeout(r, remaining));\n }\n }\n }\n\n /**\n * Setup static file serving routes\n */\n private setupStaticRoutes(): void {\n // Handle index.html with port injection\n this._app.get('/', (_req: Request, res: Response) => {\n this.serveHtmlWithPorts(res);\n });\n\n this._app.get('/index.html', (_req: Request, res: Response) => {\n this.serveHtmlWithPorts(res);\n });\n\n // Use express.static middleware for secure static file serving\n this._app.use(express.static(this.staticPath));\n\n // Fallback to index.html for SPA routing\n this._app.get('*', (_req: Request, res: Response) => {\n this.serveHtmlWithPorts(res);\n });\n }\n\n /**\n * Serve HTML with injected port configuration\n */\n private serveHtmlWithPorts(res: Response): void {\n try {\n const htmlPath = join(this.staticPath, 'index.html');\n let html = readFileSync(htmlPath, 'utf8');\n\n // Get scrcpy server port from global\n const scrcpyPort = (global as any).scrcpyServerPort || this.port! + 1;\n\n // Inject scrcpy port configuration script into HTML head\n const configScript = `\n <script>\n window.SCRCPY_PORT = ${scrcpyPort};\n </script>\n `;\n\n // Insert the script before closing </head> tag\n html = html.replace('</head>', `${configScript}</head>`);\n\n res.setHeader('Content-Type', 'text/html');\n res.send(html);\n } catch (error) {\n console.error('Error serving HTML with ports:', error);\n res.status(500).send('Internal Server Error');\n }\n }\n\n /**\n * Launch the server on specified port\n */\n async launch(port?: number): Promise<PlaygroundServer> {\n // If using factory mode, initialize agent\n if (this.agentFactory) {\n console.log('Initializing agent from factory function...');\n this.agent = await this.agentFactory();\n console.log('Agent initialized successfully');\n }\n\n // Initialize routes now, after any middleware has been added\n this.initializeApp();\n\n this.port = port || defaultPort;\n\n return new Promise((resolve) => {\n const serverPort = this.port;\n this.server = this._app.listen(serverPort, () => {\n resolve(this);\n });\n });\n }\n\n /**\n * Close the server and clean up resources\n */\n async close(): Promise<void> {\n return new Promise((resolve, reject) => {\n if (this.server) {\n // Clean up the single agent\n try {\n this.agent.destroy();\n } catch (error) {\n console.warn('Failed to destroy agent:', error);\n }\n this.taskExecutionDumps = {};\n\n // Close the server\n this.server.close((error) => {\n if (error) {\n reject(error);\n } else {\n this.server = undefined;\n resolve();\n }\n });\n } else {\n resolve();\n }\n });\n }\n}\n\nexport default PlaygroundServer;\nexport { PlaygroundServer };\n"],"names":["defaultPort","PLAYGROUND_SERVER_PORT","__filename","fileURLToPath","__dirname","dirname","STATIC_PATH","join","errorHandler","err","req","res","next","console","errorMessage","Error","PlaygroundServer","express","_res","context","uuid","filePath","resolvedPath","resolve","resolvedTmpDir","tmpFile","writeFileSync","error","contextFile","existsSync","readFileSync","requestId","executionDump","actionSpace","processedActionSpace","action","typedAction","processedSchema","e","actionName","type","prompt","params","deepThink","screenshotIncluded","domIncluded","deviceOptions","_dump","response","startTime","Date","value","executeAction","formatErrorMessage","dumpString","groupedDump","GroupedActionDump","timeCost","dump","reportHTML","_req","base64Screenshot","nativeUrl","proxyOk","description","undefined","aiConfig","Object","overrideAIConfig","globalModelConfigManager","Promise","proxyReq","http","proxyRes","contentType","defaultMjpegFps","maxMjpegFps","maxErrorBackoffMs","errorLogThreshold","fps","Math","Number","interval","boundary","stopped","consecutiveErrors","frameStart","base64","raw","buf","Buffer","backoff","r","setTimeout","elapsed","remaining","htmlPath","html","scrcpyPort","global","configScript","port","serverPort","reject","agent","staticPath","id","getTmpDir"],"mappings":"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"}
@@ -40,6 +40,8 @@ __webpack_require__.d(__webpack_exports__, {
40
40
  PlaygroundServer: ()=>PlaygroundServer
41
41
  });
42
42
  const external_node_fs_namespaceObject = require("node:fs");
43
+ const external_node_http_namespaceObject = require("node:http");
44
+ var external_node_http_default = /*#__PURE__*/ __webpack_require__.n(external_node_http_namespaceObject);
43
45
  const external_node_path_namespaceObject = require("node:path");
44
46
  const external_node_url_namespaceObject = require("node:url");
45
47
  const core_namespaceObject = require("@midscene/core");
@@ -353,6 +355,17 @@ class PlaygroundServer {
353
355
  });
354
356
  }
355
357
  });
358
+ this._app.get('/mjpeg', async (req, res)=>{
359
+ const nativeUrl = this.agent?.interface?.mjpegStreamUrl;
360
+ if (nativeUrl && false !== this._nativeMjpegAvailable) {
361
+ const proxyOk = await this.probeAndProxyNativeMjpeg(nativeUrl, req, res);
362
+ if (proxyOk) return;
363
+ }
364
+ if ('function' != typeof this.agent?.interface?.screenshotBase64) return res.status(500).json({
365
+ error: 'Screenshot method not available on current interface'
366
+ });
367
+ await this.startPollingMjpegStream(req, res);
368
+ });
356
369
  this._app.get('/interface-info', async (_req, res)=>{
357
370
  try {
358
371
  const type = this.agent.interface.interfaceType || 'Unknown';
@@ -402,6 +415,71 @@ class PlaygroundServer {
402
415
  });
403
416
  });
404
417
  }
418
+ probeAndProxyNativeMjpeg(nativeUrl, req, res) {
419
+ return new Promise((resolve)=>{
420
+ console.log(`MJPEG: trying native stream from ${nativeUrl}`);
421
+ const proxyReq = external_node_http_default().get(nativeUrl, (proxyRes)=>{
422
+ this._nativeMjpegAvailable = true;
423
+ console.log('MJPEG: streaming via native WDA MJPEG server');
424
+ const contentType = proxyRes.headers['content-type'];
425
+ if (contentType) res.setHeader('Content-Type', contentType);
426
+ res.setHeader('Cache-Control', 'no-cache, no-store, must-revalidate');
427
+ res.setHeader('Connection', 'keep-alive');
428
+ proxyRes.pipe(res);
429
+ req.on('close', ()=>proxyReq.destroy());
430
+ resolve(true);
431
+ });
432
+ proxyReq.on('error', (err)=>{
433
+ this._nativeMjpegAvailable = false;
434
+ console.warn(`MJPEG: native stream unavailable (${err.message}), using polling mode`);
435
+ resolve(false);
436
+ });
437
+ });
438
+ }
439
+ async startPollingMjpegStream(req, res) {
440
+ const defaultMjpegFps = 10;
441
+ const maxMjpegFps = 30;
442
+ const maxErrorBackoffMs = 3000;
443
+ const errorLogThreshold = 3;
444
+ const fps = Math.min(Math.max(Number(req.query.fps) ?? defaultMjpegFps, 1), maxMjpegFps);
445
+ const interval = Math.round(1000 / fps);
446
+ const boundary = 'mjpeg-boundary';
447
+ console.log(`MJPEG: streaming via polling mode (${fps}fps)`);
448
+ res.setHeader('Content-Type', `multipart/x-mixed-replace; boundary=${boundary}`);
449
+ res.setHeader('Cache-Control', 'no-cache, no-store, must-revalidate');
450
+ res.setHeader('Connection', 'keep-alive');
451
+ let stopped = false;
452
+ let consecutiveErrors = 0;
453
+ req.on('close', ()=>{
454
+ stopped = true;
455
+ });
456
+ while(!stopped){
457
+ const frameStart = Date.now();
458
+ try {
459
+ const base64 = await this.agent.interface.screenshotBase64();
460
+ if (stopped) break;
461
+ consecutiveErrors = 0;
462
+ const raw = base64.replace(/^data:image\/\w+;base64,/, '');
463
+ const buf = Buffer.from(raw, 'base64');
464
+ res.write(`--${boundary}\r\n`);
465
+ res.write('Content-Type: image/jpeg\r\n');
466
+ res.write(`Content-Length: ${buf.length}\r\n\r\n`);
467
+ res.write(buf);
468
+ res.write('\r\n');
469
+ } catch (err) {
470
+ if (stopped) break;
471
+ consecutiveErrors++;
472
+ if (consecutiveErrors <= errorLogThreshold) console.error('MJPEG frame error:', err);
473
+ else if (consecutiveErrors === errorLogThreshold + 1) console.error('MJPEG: suppressing further errors, retrying silently...');
474
+ const backoff = Math.min(1000 * consecutiveErrors, maxErrorBackoffMs);
475
+ await new Promise((r)=>setTimeout(r, backoff));
476
+ continue;
477
+ }
478
+ const elapsed = Date.now() - frameStart;
479
+ const remaining = interval - elapsed;
480
+ if (remaining > 0) await new Promise((r)=>setTimeout(r, remaining));
481
+ }
482
+ }
405
483
  setupStaticRoutes() {
406
484
  this._app.get('/', (_req, res)=>{
407
485
  this.serveHtmlWithPorts(res);
@@ -476,6 +554,7 @@ class PlaygroundServer {
476
554
  _define_property(this, "taskExecutionDumps", void 0);
477
555
  _define_property(this, "id", void 0);
478
556
  _define_property(this, "_initialized", false);
557
+ _define_property(this, "_nativeMjpegAvailable", null);
479
558
  _define_property(this, "agentFactory", void 0);
480
559
  _define_property(this, "currentTaskId", null);
481
560
  this._app = external_express_default()();
@@ -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, resolve } from 'node:path';\nimport { fileURLToPath } from 'node:url';\nimport type { ExecutionDump } from '@midscene/core';\nimport { GroupedActionDump } from '@midscene/core';\nimport type { Agent as PageAgent } from '@midscene/core/agent';\nimport { getTmpDir } from '@midscene/core/utils';\nimport { PLAYGROUND_SERVER_PORT } from '@midscene/shared/constants';\nimport {\n globalModelConfigManager,\n overrideAIConfig,\n} from '@midscene/shared/env';\nimport { uuid } from '@midscene/shared/utils';\nimport express, { type Request, type Response } from 'express';\nimport { executeAction, formatErrorMessage } from './common';\n\nimport 'dotenv/config';\n\nconst defaultPort = PLAYGROUND_SERVER_PORT;\n\n// Static path for playground files\nconst __filename = fileURLToPath(import.meta.url);\nconst __dirname = dirname(__filename);\nconst STATIC_PATH = join(__dirname, '..', '..', 'static');\n\nconst errorHandler = (\n err: unknown,\n req: Request,\n res: Response,\n next: express.NextFunction,\n) => {\n console.error(err);\n const errorMessage =\n err instanceof Error ? err.message : 'Internal server error';\n res.status(500).json({\n error: errorMessage,\n });\n};\n\nclass PlaygroundServer {\n private _app: express.Application;\n tmpDir: string;\n server?: Server;\n port?: number | null;\n agent: PageAgent;\n staticPath: string;\n taskExecutionDumps: Record<string, ExecutionDump | null>; // Store execution dumps directly\n id: string; // Unique identifier for this server instance\n\n private _initialized = false;\n\n // Factory function for recreating agent\n private agentFactory?: (() => PageAgent | Promise<PageAgent>) | null;\n\n // Track current running task\n private currentTaskId: string | null = null;\n\n constructor(\n agent: PageAgent | (() => PageAgent) | (() => Promise<PageAgent>),\n staticPath = STATIC_PATH,\n id?: string, // Optional override ID\n ) {\n this._app = express();\n this.tmpDir = getTmpDir()!;\n this.staticPath = staticPath;\n this.taskExecutionDumps = {}; // Initialize as empty object\n // Use provided ID, or generate random UUID for each startup\n this.id = id || uuid();\n\n // Support both instance and factory function modes\n if (typeof agent === 'function') {\n this.agentFactory = agent;\n this.agent = null as any; // Will be initialized in launch()\n } else {\n this.agent = agent;\n this.agentFactory = null;\n }\n }\n\n /**\n * Get the Express app instance for custom configuration\n *\n * IMPORTANT: Add middleware (like CORS) BEFORE calling launch()\n * The routes are initialized when launch() is called, so middleware\n * added after launch() will not affect the API routes.\n *\n * @example\n * ```typescript\n * import cors from 'cors';\n *\n * const server = new PlaygroundServer(agent);\n *\n * // Add CORS middleware before launch\n * server.app.use(cors({\n * origin: true,\n * credentials: true,\n * methods: ['GET', 'POST', 'PUT', 'DELETE', 'OPTIONS']\n * }));\n *\n * await server.launch();\n * ```\n */\n get app(): express.Application {\n return this._app;\n }\n\n /**\n * Initialize Express app with all routes and middleware\n * Called automatically by launch() if not already initialized\n */\n private initializeApp(): void {\n if (this._initialized) return;\n\n // Built-in middleware to parse JSON bodies\n this._app.use(express.json({ limit: '50mb' }));\n\n // Context update middleware (after JSON parsing)\n this._app.use(\n (req: Request, _res: Response, next: express.NextFunction) => {\n const { context } = req.body || {};\n if (\n context &&\n 'updateContext' in this.agent.interface &&\n typeof this.agent.interface.updateContext === 'function'\n ) {\n this.agent.interface.updateContext(context);\n console.log('Context updated by PlaygroundServer middleware');\n }\n next();\n },\n );\n\n // NOTE: CORS middleware should be added externally via server.app.use()\n // before calling server.launch() if needed\n\n // API routes\n this.setupRoutes();\n\n // Static file serving (if staticPath is provided)\n this.setupStaticRoutes();\n\n // Error handler middleware (must be last)\n this._app.use(errorHandler);\n\n this._initialized = true;\n }\n\n filePathForUuid(uuid: string) {\n // Validate uuid to prevent path traversal attacks\n // Only allow alphanumeric characters and hyphens\n if (!/^[a-zA-Z0-9-]+$/.test(uuid)) {\n throw new Error('Invalid uuid format');\n }\n const filePath = join(this.tmpDir, `${uuid}.json`);\n // Double-check that resolved path is within tmpDir\n const resolvedPath = resolve(filePath);\n const resolvedTmpDir = resolve(this.tmpDir);\n if (!resolvedPath.startsWith(resolvedTmpDir)) {\n throw new Error('Invalid path');\n }\n return filePath;\n }\n\n saveContextFile(uuid: string, context: string) {\n const tmpFile = this.filePathForUuid(uuid);\n console.log(`save context file: ${tmpFile}`);\n writeFileSync(tmpFile, context);\n return tmpFile;\n }\n\n /**\n * Recreate agent instance (for cancellation)\n */\n private async recreateAgent(): Promise<void> {\n if (!this.agentFactory) {\n throw new Error(\n 'Cannot recreate agent: factory function not provided. Attempting to destroy existing agent only.',\n );\n }\n\n console.log('Recreating agent to cancel current task...');\n\n // Destroy old agent instance\n try {\n if (this.agent && typeof this.agent.destroy === 'function') {\n await this.agent.destroy();\n }\n } catch (error) {\n console.warn('Failed to destroy old agent:', error);\n }\n\n // Create new agent instance\n try {\n this.agent = await this.agentFactory();\n console.log('Agent recreated successfully');\n } catch (error) {\n console.error('Failed to recreate agent:', error);\n throw error;\n }\n }\n\n /**\n * Setup all API routes\n */\n private setupRoutes(): void {\n this._app.get('/status', async (req: Request, res: Response) => {\n res.send({\n status: 'ok',\n id: this.id,\n });\n });\n\n this._app.get('/context/:uuid', async (req: Request, res: Response) => {\n const { uuid } = req.params;\n let contextFile: string;\n try {\n contextFile = this.filePathForUuid(uuid);\n } catch {\n return res.status(400).json({\n error: 'Invalid uuid format',\n });\n }\n\n if (!existsSync(contextFile)) {\n return res.status(404).json({\n error: 'Context not found',\n });\n }\n\n const context = readFileSync(contextFile, 'utf8');\n res.json({\n context,\n });\n });\n\n this._app.get(\n '/task-progress/:requestId',\n async (req: Request, res: Response) => {\n const { requestId } = req.params;\n const executionDump = this.taskExecutionDumps[requestId] || null;\n\n res.json({\n executionDump,\n });\n },\n );\n\n this._app.post('/action-space', async (req: Request, res: Response) => {\n try {\n let actionSpace = [];\n\n actionSpace = this.agent.interface.actionSpace();\n\n // Process actionSpace to make paramSchema serializable with shape info\n const processedActionSpace = actionSpace.map((action: unknown) => {\n if (action && typeof action === 'object' && 'paramSchema' in action) {\n const typedAction = action as {\n paramSchema?: { shape?: object; [key: string]: unknown };\n [key: string]: unknown;\n };\n if (\n typedAction.paramSchema &&\n typeof typedAction.paramSchema === 'object'\n ) {\n // Extract shape information from Zod schema\n let processedSchema = null;\n\n try {\n // Extract shape from runtime Zod object\n if (\n typedAction.paramSchema.shape &&\n typeof typedAction.paramSchema.shape === 'object'\n ) {\n processedSchema = {\n type: 'ZodObject',\n shape: typedAction.paramSchema.shape,\n };\n }\n } catch (e) {\n const actionName =\n 'name' in typedAction && typeof typedAction.name === 'string'\n ? typedAction.name\n : 'unknown';\n console.warn(\n 'Failed to process paramSchema for action:',\n actionName,\n e,\n );\n }\n\n return {\n ...typedAction,\n paramSchema: processedSchema,\n };\n }\n }\n return action;\n });\n\n res.json(processedActionSpace);\n } catch (error: unknown) {\n const errorMessage =\n error instanceof Error ? error.message : 'Unknown error';\n console.error('Failed to get action space:', error);\n res.status(500).json({\n error: errorMessage,\n });\n }\n });\n\n // -------------------------\n // actions from report file\n this._app.post(\n '/playground-with-context',\n async (req: Request, res: Response) => {\n const context = req.body.context;\n\n if (!context) {\n return res.status(400).json({\n error: 'context is required',\n });\n }\n\n const requestId = uuid();\n this.saveContextFile(requestId, context);\n return res.json({\n location: `/playground/${requestId}`,\n uuid: requestId,\n });\n },\n );\n\n this._app.post('/execute', async (req: Request, res: Response) => {\n const {\n type,\n prompt,\n params,\n requestId,\n deepThink,\n screenshotIncluded,\n domIncluded,\n deviceOptions,\n } = req.body;\n\n if (!type) {\n return res.status(400).json({\n error: 'type is required',\n });\n }\n\n // Always recreate agent before execution to ensure latest config is applied\n if (this.agentFactory) {\n console.log('Destroying old agent before execution...');\n try {\n if (this.agent && typeof this.agent.destroy === 'function') {\n await this.agent.destroy();\n }\n } catch (error) {\n console.warn('Failed to destroy old agent:', error);\n }\n\n console.log('Creating new agent with latest config...');\n try {\n this.agent = await this.agentFactory();\n console.log('Agent created successfully');\n } catch (error) {\n console.error('Failed to create agent:', error);\n return res.status(500).json({\n error: `Failed to create agent: ${error instanceof Error ? error.message : 'Unknown error'}`,\n });\n }\n }\n\n // Update device options if provided\n if (\n deviceOptions &&\n this.agent.interface &&\n 'options' in this.agent.interface\n ) {\n this.agent.interface.options = {\n ...(this.agent.interface.options || {}),\n ...deviceOptions,\n };\n }\n\n // Check if another task is running\n if (this.currentTaskId) {\n return res.status(409).json({\n error: 'Another task is already running',\n currentTaskId: this.currentTaskId,\n });\n }\n\n // Lock this task\n if (requestId) {\n this.currentTaskId = requestId;\n this.taskExecutionDumps[requestId] = null;\n\n // Use onDumpUpdate to receive and store executionDump directly\n this.agent.onDumpUpdate = (\n _dump: string,\n executionDump?: ExecutionDump,\n ) => {\n if (executionDump) {\n // Store the execution dump directly without transformation\n this.taskExecutionDumps[requestId] = executionDump;\n }\n };\n }\n\n const response: {\n result: unknown;\n dump: ExecutionDump | null;\n error: string | null;\n reportHTML: string | null;\n requestId?: string;\n } = {\n result: null,\n dump: null,\n error: null,\n reportHTML: null,\n requestId,\n };\n\n const startTime = Date.now();\n try {\n // Get action space to check for dynamic actions\n const actionSpace = this.agent.interface.actionSpace();\n\n // Prepare value object for executeAction\n const value = {\n type,\n prompt,\n params,\n };\n\n response.result = await executeAction(\n this.agent,\n type,\n actionSpace,\n value,\n {\n deepThink,\n screenshotIncluded,\n domIncluded,\n deviceOptions,\n },\n );\n } catch (error: unknown) {\n response.error = formatErrorMessage(error);\n }\n\n try {\n const dumpString = this.agent.dumpDataString({\n inlineScreenshots: true,\n });\n if (dumpString) {\n const groupedDump =\n GroupedActionDump.fromSerializedString(dumpString);\n // Extract first execution from grouped dump, matching local execution adapter behavior\n response.dump = groupedDump.executions?.[0] || null;\n } else {\n response.dump = null;\n }\n response.reportHTML =\n this.agent.reportHTMLString({ inlineScreenshots: true }) || null;\n\n this.agent.writeOutActionDumps();\n this.agent.resetDump();\n } catch (error: unknown) {\n const errorMessage =\n error instanceof Error ? error.message : 'Unknown error';\n console.error(\n `write out dump failed: requestId: ${requestId}, ${errorMessage}`,\n );\n }\n\n res.send(response);\n const timeCost = Date.now() - startTime;\n\n if (response.error) {\n console.error(\n `handle request failed after ${timeCost}ms: requestId: ${requestId}, ${response.error}`,\n );\n } else {\n console.log(\n `handle request done after ${timeCost}ms: requestId: ${requestId}`,\n );\n }\n\n // Clean up task execution dumps and unlock after execution completes\n if (requestId) {\n delete this.taskExecutionDumps[requestId];\n // Release the lock\n if (this.currentTaskId === requestId) {\n this.currentTaskId = null;\n }\n }\n });\n\n this._app.post(\n '/cancel/:requestId',\n async (req: Request, res: Response) => {\n const { requestId } = req.params;\n\n if (!requestId) {\n return res.status(400).json({\n error: 'requestId is required',\n });\n }\n\n try {\n // Check if this is the current running task\n if (this.currentTaskId !== requestId) {\n return res.json({\n status: 'not_found',\n message: 'Task not found or already completed',\n });\n }\n\n console.log(`Cancelling task: ${requestId}`);\n\n // Get current execution data before cancelling (dump and reportHTML)\n let dump: any = null;\n let reportHTML: string | null = null;\n\n try {\n const dumpString = this.agent.dumpDataString?.({\n inlineScreenshots: true,\n });\n if (dumpString) {\n const groupedDump =\n GroupedActionDump.fromSerializedString(dumpString);\n // Extract first execution from grouped dump\n dump = groupedDump.executions?.[0] || null;\n }\n\n reportHTML =\n this.agent.reportHTMLString?.({ inlineScreenshots: true }) ||\n null;\n } catch (error: unknown) {\n console.warn('Failed to get execution data before cancel:', error);\n }\n\n // Recreate/destroy agent to cancel the current task\n await this.recreateAgent();\n\n // Clean up\n delete this.taskExecutionDumps[requestId];\n this.currentTaskId = null;\n\n res.json({\n status: 'cancelled',\n message: 'Task cancelled successfully',\n dump,\n reportHTML,\n });\n } catch (error: unknown) {\n const errorMessage =\n error instanceof Error ? error.message : 'Unknown error';\n console.error(`Failed to cancel: ${errorMessage}`);\n res.status(500).json({\n error: `Failed to cancel: ${errorMessage}`,\n });\n }\n },\n );\n\n // Screenshot API for real-time screenshot polling\n this._app.get('/screenshot', async (_req: Request, res: Response) => {\n try {\n // Check if page has screenshotBase64 method\n if (typeof this.agent.interface.screenshotBase64 !== 'function') {\n return res.status(500).json({\n error: 'Screenshot method not available on current interface',\n });\n }\n\n const base64Screenshot = await this.agent.interface.screenshotBase64();\n\n res.json({\n screenshot: base64Screenshot,\n timestamp: Date.now(),\n });\n } catch (error: unknown) {\n const errorMessage =\n error instanceof Error ? error.message : 'Unknown error';\n console.error(`Failed to take screenshot: ${errorMessage}`);\n res.status(500).json({\n error: `Failed to take screenshot: ${errorMessage}`,\n });\n }\n });\n\n // Interface info API for getting interface type and description\n this._app.get('/interface-info', async (_req: Request, res: Response) => {\n try {\n const type = this.agent.interface.interfaceType || 'Unknown';\n const description = this.agent.interface.describe?.() || undefined;\n\n res.json({\n type,\n description,\n });\n } catch (error: unknown) {\n const errorMessage =\n error instanceof Error ? error.message : 'Unknown error';\n console.error(`Failed to get interface info: ${errorMessage}`);\n res.status(500).json({\n error: `Failed to get interface info: ${errorMessage}`,\n });\n }\n });\n\n this.app.post('/config', async (req: Request, res: Response) => {\n const { aiConfig } = req.body;\n\n if (!aiConfig || typeof aiConfig !== 'object') {\n return res.status(400).json({\n error: 'aiConfig is required and must be an object',\n });\n }\n\n if (Object.keys(aiConfig).length === 0) {\n return res.json({\n status: 'ok',\n message: 'AI config not changed due to empty object',\n });\n }\n\n try {\n overrideAIConfig(aiConfig);\n } catch (error: unknown) {\n const errorMessage =\n error instanceof Error ? error.message : 'Unknown error';\n console.error(`Failed to update AI config: ${errorMessage}`);\n return res.status(500).json({\n error: `Failed to update AI config: ${errorMessage}`,\n });\n }\n\n // Validate the config immediately so the frontend gets early feedback\n try {\n globalModelConfigManager.getModelConfig('default');\n } catch (error: unknown) {\n const errorMessage =\n error instanceof Error ? error.message : 'Unknown error';\n console.error(`AI config validation failed: ${errorMessage}`);\n return res.status(400).json({\n error: errorMessage,\n });\n }\n\n // Note: Agent will be recreated on next execution to apply new config\n return res.json({\n status: 'ok',\n message:\n 'AI config updated. Agent will be recreated on next execution.',\n });\n });\n }\n\n /**\n * Setup static file serving routes\n */\n private setupStaticRoutes(): void {\n // Handle index.html with port injection\n this._app.get('/', (_req: Request, res: Response) => {\n this.serveHtmlWithPorts(res);\n });\n\n this._app.get('/index.html', (_req: Request, res: Response) => {\n this.serveHtmlWithPorts(res);\n });\n\n // Use express.static middleware for secure static file serving\n this._app.use(express.static(this.staticPath));\n\n // Fallback to index.html for SPA routing\n this._app.get('*', (_req: Request, res: Response) => {\n this.serveHtmlWithPorts(res);\n });\n }\n\n /**\n * Serve HTML with injected port configuration\n */\n private serveHtmlWithPorts(res: Response): void {\n try {\n const htmlPath = join(this.staticPath, 'index.html');\n let html = readFileSync(htmlPath, 'utf8');\n\n // Get scrcpy server port from global\n const scrcpyPort = (global as any).scrcpyServerPort || this.port! + 1;\n\n // Inject scrcpy port configuration script into HTML head\n const configScript = `\n <script>\n window.SCRCPY_PORT = ${scrcpyPort};\n </script>\n `;\n\n // Insert the script before closing </head> tag\n html = html.replace('</head>', `${configScript}</head>`);\n\n res.setHeader('Content-Type', 'text/html');\n res.send(html);\n } catch (error) {\n console.error('Error serving HTML with ports:', error);\n res.status(500).send('Internal Server Error');\n }\n }\n\n /**\n * Launch the server on specified port\n */\n async launch(port?: number): Promise<PlaygroundServer> {\n // If using factory mode, initialize agent\n if (this.agentFactory) {\n console.log('Initializing agent from factory function...');\n this.agent = await this.agentFactory();\n console.log('Agent initialized successfully');\n }\n\n // Initialize routes now, after any middleware has been added\n this.initializeApp();\n\n this.port = port || defaultPort;\n\n return new Promise((resolve) => {\n const serverPort = this.port;\n this.server = this._app.listen(serverPort, () => {\n resolve(this);\n });\n });\n }\n\n /**\n * Close the server and clean up resources\n */\n async close(): Promise<void> {\n return new Promise((resolve, reject) => {\n if (this.server) {\n // Clean up the single agent\n try {\n this.agent.destroy();\n } catch (error) {\n console.warn('Failed to destroy agent:', error);\n }\n this.taskExecutionDumps = {};\n\n // Close the server\n this.server.close((error) => {\n if (error) {\n reject(error);\n } else {\n this.server = undefined;\n resolve();\n }\n });\n } else {\n resolve();\n }\n });\n }\n}\n\nexport default PlaygroundServer;\nexport { PlaygroundServer };\n"],"names":["__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","filePath","resolvedPath","resolve","resolvedTmpDir","tmpFile","writeFileSync","error","contextFile","existsSync","readFileSync","requestId","executionDump","actionSpace","processedActionSpace","action","typedAction","processedSchema","e","actionName","type","prompt","params","deepThink","screenshotIncluded","domIncluded","deviceOptions","_dump","response","startTime","Date","value","executeAction","formatErrorMessage","dumpString","groupedDump","GroupedActionDump","timeCost","dump","reportHTML","_req","base64Screenshot","description","undefined","aiConfig","overrideAIConfig","globalModelConfigManager","htmlPath","html","scrcpyPort","global","configScript","port","Promise","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 http from 'node:http';\nimport type { Server } from 'node:http';\nimport { dirname, join, resolve } from 'node:path';\nimport { fileURLToPath } from 'node:url';\nimport type { ExecutionDump } from '@midscene/core';\nimport { GroupedActionDump } from '@midscene/core';\nimport type { Agent as PageAgent } from '@midscene/core/agent';\nimport { getTmpDir } from '@midscene/core/utils';\nimport { PLAYGROUND_SERVER_PORT } from '@midscene/shared/constants';\nimport {\n globalModelConfigManager,\n overrideAIConfig,\n} from '@midscene/shared/env';\nimport { uuid } from '@midscene/shared/utils';\nimport express, { type Request, type Response } from 'express';\nimport { executeAction, formatErrorMessage } from './common';\n\nimport 'dotenv/config';\n\nconst defaultPort = PLAYGROUND_SERVER_PORT;\n\n// Static path for playground files\nconst __filename = fileURLToPath(import.meta.url);\nconst __dirname = dirname(__filename);\nconst STATIC_PATH = join(__dirname, '..', '..', 'static');\n\nconst errorHandler = (\n err: unknown,\n req: Request,\n res: Response,\n next: express.NextFunction,\n) => {\n console.error(err);\n const errorMessage =\n err instanceof Error ? err.message : 'Internal server error';\n res.status(500).json({\n error: errorMessage,\n });\n};\n\nclass PlaygroundServer {\n private _app: express.Application;\n tmpDir: string;\n server?: Server;\n port?: number | null;\n agent: PageAgent;\n staticPath: string;\n taskExecutionDumps: Record<string, ExecutionDump | null>; // Store execution dumps directly\n id: string; // Unique identifier for this server instance\n\n private _initialized = false;\n\n // Native MJPEG stream probe: null = not tested, true/false = result\n private _nativeMjpegAvailable: boolean | null = null;\n\n // Factory function for recreating agent\n private agentFactory?: (() => PageAgent | Promise<PageAgent>) | null;\n\n // Track current running task\n private currentTaskId: string | null = null;\n\n constructor(\n agent: PageAgent | (() => PageAgent) | (() => Promise<PageAgent>),\n staticPath = STATIC_PATH,\n id?: string, // Optional override ID\n ) {\n this._app = express();\n this.tmpDir = getTmpDir()!;\n this.staticPath = staticPath;\n this.taskExecutionDumps = {}; // Initialize as empty object\n // Use provided ID, or generate random UUID for each startup\n this.id = id || uuid();\n\n // Support both instance and factory function modes\n if (typeof agent === 'function') {\n this.agentFactory = agent;\n this.agent = null as any; // Will be initialized in launch()\n } else {\n this.agent = agent;\n this.agentFactory = null;\n }\n }\n\n /**\n * Get the Express app instance for custom configuration\n *\n * IMPORTANT: Add middleware (like CORS) BEFORE calling launch()\n * The routes are initialized when launch() is called, so middleware\n * added after launch() will not affect the API routes.\n *\n * @example\n * ```typescript\n * import cors from 'cors';\n *\n * const server = new PlaygroundServer(agent);\n *\n * // Add CORS middleware before launch\n * server.app.use(cors({\n * origin: true,\n * credentials: true,\n * methods: ['GET', 'POST', 'PUT', 'DELETE', 'OPTIONS']\n * }));\n *\n * await server.launch();\n * ```\n */\n get app(): express.Application {\n return this._app;\n }\n\n /**\n * Initialize Express app with all routes and middleware\n * Called automatically by launch() if not already initialized\n */\n private initializeApp(): void {\n if (this._initialized) return;\n\n // Built-in middleware to parse JSON bodies\n this._app.use(express.json({ limit: '50mb' }));\n\n // Context update middleware (after JSON parsing)\n this._app.use(\n (req: Request, _res: Response, next: express.NextFunction) => {\n const { context } = req.body || {};\n if (\n context &&\n 'updateContext' in this.agent.interface &&\n typeof this.agent.interface.updateContext === 'function'\n ) {\n this.agent.interface.updateContext(context);\n console.log('Context updated by PlaygroundServer middleware');\n }\n next();\n },\n );\n\n // NOTE: CORS middleware should be added externally via server.app.use()\n // before calling server.launch() if needed\n\n // API routes\n this.setupRoutes();\n\n // Static file serving (if staticPath is provided)\n this.setupStaticRoutes();\n\n // Error handler middleware (must be last)\n this._app.use(errorHandler);\n\n this._initialized = true;\n }\n\n filePathForUuid(uuid: string) {\n // Validate uuid to prevent path traversal attacks\n // Only allow alphanumeric characters and hyphens\n if (!/^[a-zA-Z0-9-]+$/.test(uuid)) {\n throw new Error('Invalid uuid format');\n }\n const filePath = join(this.tmpDir, `${uuid}.json`);\n // Double-check that resolved path is within tmpDir\n const resolvedPath = resolve(filePath);\n const resolvedTmpDir = resolve(this.tmpDir);\n if (!resolvedPath.startsWith(resolvedTmpDir)) {\n throw new Error('Invalid path');\n }\n return filePath;\n }\n\n saveContextFile(uuid: string, context: string) {\n const tmpFile = this.filePathForUuid(uuid);\n console.log(`save context file: ${tmpFile}`);\n writeFileSync(tmpFile, context);\n return tmpFile;\n }\n\n /**\n * Recreate agent instance (for cancellation)\n */\n private async recreateAgent(): Promise<void> {\n if (!this.agentFactory) {\n throw new Error(\n 'Cannot recreate agent: factory function not provided. Attempting to destroy existing agent only.',\n );\n }\n\n console.log('Recreating agent to cancel current task...');\n\n // Destroy old agent instance\n try {\n if (this.agent && typeof this.agent.destroy === 'function') {\n await this.agent.destroy();\n }\n } catch (error) {\n console.warn('Failed to destroy old agent:', error);\n }\n\n // Create new agent instance\n try {\n this.agent = await this.agentFactory();\n console.log('Agent recreated successfully');\n } catch (error) {\n console.error('Failed to recreate agent:', error);\n throw error;\n }\n }\n\n /**\n * Setup all API routes\n */\n private setupRoutes(): void {\n this._app.get('/status', async (req: Request, res: Response) => {\n res.send({\n status: 'ok',\n id: this.id,\n });\n });\n\n this._app.get('/context/:uuid', async (req: Request, res: Response) => {\n const { uuid } = req.params;\n let contextFile: string;\n try {\n contextFile = this.filePathForUuid(uuid);\n } catch {\n return res.status(400).json({\n error: 'Invalid uuid format',\n });\n }\n\n if (!existsSync(contextFile)) {\n return res.status(404).json({\n error: 'Context not found',\n });\n }\n\n const context = readFileSync(contextFile, 'utf8');\n res.json({\n context,\n });\n });\n\n this._app.get(\n '/task-progress/:requestId',\n async (req: Request, res: Response) => {\n const { requestId } = req.params;\n const executionDump = this.taskExecutionDumps[requestId] || null;\n\n res.json({\n executionDump,\n });\n },\n );\n\n this._app.post('/action-space', async (req: Request, res: Response) => {\n try {\n let actionSpace = [];\n\n actionSpace = this.agent.interface.actionSpace();\n\n // Process actionSpace to make paramSchema serializable with shape info\n const processedActionSpace = actionSpace.map((action: unknown) => {\n if (action && typeof action === 'object' && 'paramSchema' in action) {\n const typedAction = action as {\n paramSchema?: { shape?: object; [key: string]: unknown };\n [key: string]: unknown;\n };\n if (\n typedAction.paramSchema &&\n typeof typedAction.paramSchema === 'object'\n ) {\n // Extract shape information from Zod schema\n let processedSchema = null;\n\n try {\n // Extract shape from runtime Zod object\n if (\n typedAction.paramSchema.shape &&\n typeof typedAction.paramSchema.shape === 'object'\n ) {\n processedSchema = {\n type: 'ZodObject',\n shape: typedAction.paramSchema.shape,\n };\n }\n } catch (e) {\n const actionName =\n 'name' in typedAction && typeof typedAction.name === 'string'\n ? typedAction.name\n : 'unknown';\n console.warn(\n 'Failed to process paramSchema for action:',\n actionName,\n e,\n );\n }\n\n return {\n ...typedAction,\n paramSchema: processedSchema,\n };\n }\n }\n return action;\n });\n\n res.json(processedActionSpace);\n } catch (error: unknown) {\n const errorMessage =\n error instanceof Error ? error.message : 'Unknown error';\n console.error('Failed to get action space:', error);\n res.status(500).json({\n error: errorMessage,\n });\n }\n });\n\n // -------------------------\n // actions from report file\n this._app.post(\n '/playground-with-context',\n async (req: Request, res: Response) => {\n const context = req.body.context;\n\n if (!context) {\n return res.status(400).json({\n error: 'context is required',\n });\n }\n\n const requestId = uuid();\n this.saveContextFile(requestId, context);\n return res.json({\n location: `/playground/${requestId}`,\n uuid: requestId,\n });\n },\n );\n\n this._app.post('/execute', async (req: Request, res: Response) => {\n const {\n type,\n prompt,\n params,\n requestId,\n deepThink,\n screenshotIncluded,\n domIncluded,\n deviceOptions,\n } = req.body;\n\n if (!type) {\n return res.status(400).json({\n error: 'type is required',\n });\n }\n\n // Always recreate agent before execution to ensure latest config is applied\n if (this.agentFactory) {\n console.log('Destroying old agent before execution...');\n try {\n if (this.agent && typeof this.agent.destroy === 'function') {\n await this.agent.destroy();\n }\n } catch (error) {\n console.warn('Failed to destroy old agent:', error);\n }\n\n console.log('Creating new agent with latest config...');\n try {\n this.agent = await this.agentFactory();\n console.log('Agent created successfully');\n } catch (error) {\n console.error('Failed to create agent:', error);\n return res.status(500).json({\n error: `Failed to create agent: ${error instanceof Error ? error.message : 'Unknown error'}`,\n });\n }\n }\n\n // Update device options if provided\n if (\n deviceOptions &&\n this.agent.interface &&\n 'options' in this.agent.interface\n ) {\n this.agent.interface.options = {\n ...(this.agent.interface.options || {}),\n ...deviceOptions,\n };\n }\n\n // Check if another task is running\n if (this.currentTaskId) {\n return res.status(409).json({\n error: 'Another task is already running',\n currentTaskId: this.currentTaskId,\n });\n }\n\n // Lock this task\n if (requestId) {\n this.currentTaskId = requestId;\n this.taskExecutionDumps[requestId] = null;\n\n // Use onDumpUpdate to receive and store executionDump directly\n this.agent.onDumpUpdate = (\n _dump: string,\n executionDump?: ExecutionDump,\n ) => {\n if (executionDump) {\n // Store the execution dump directly without transformation\n this.taskExecutionDumps[requestId] = executionDump;\n }\n };\n }\n\n const response: {\n result: unknown;\n dump: ExecutionDump | null;\n error: string | null;\n reportHTML: string | null;\n requestId?: string;\n } = {\n result: null,\n dump: null,\n error: null,\n reportHTML: null,\n requestId,\n };\n\n const startTime = Date.now();\n try {\n // Get action space to check for dynamic actions\n const actionSpace = this.agent.interface.actionSpace();\n\n // Prepare value object for executeAction\n const value = {\n type,\n prompt,\n params,\n };\n\n response.result = await executeAction(\n this.agent,\n type,\n actionSpace,\n value,\n {\n deepThink,\n screenshotIncluded,\n domIncluded,\n deviceOptions,\n },\n );\n } catch (error: unknown) {\n response.error = formatErrorMessage(error);\n }\n\n try {\n const dumpString = this.agent.dumpDataString({\n inlineScreenshots: true,\n });\n if (dumpString) {\n const groupedDump =\n GroupedActionDump.fromSerializedString(dumpString);\n // Extract first execution from grouped dump, matching local execution adapter behavior\n response.dump = groupedDump.executions?.[0] || null;\n } else {\n response.dump = null;\n }\n response.reportHTML =\n this.agent.reportHTMLString({ inlineScreenshots: true }) || null;\n\n this.agent.writeOutActionDumps();\n this.agent.resetDump();\n } catch (error: unknown) {\n const errorMessage =\n error instanceof Error ? error.message : 'Unknown error';\n console.error(\n `write out dump failed: requestId: ${requestId}, ${errorMessage}`,\n );\n }\n\n res.send(response);\n const timeCost = Date.now() - startTime;\n\n if (response.error) {\n console.error(\n `handle request failed after ${timeCost}ms: requestId: ${requestId}, ${response.error}`,\n );\n } else {\n console.log(\n `handle request done after ${timeCost}ms: requestId: ${requestId}`,\n );\n }\n\n // Clean up task execution dumps and unlock after execution completes\n if (requestId) {\n delete this.taskExecutionDumps[requestId];\n // Release the lock\n if (this.currentTaskId === requestId) {\n this.currentTaskId = null;\n }\n }\n });\n\n this._app.post(\n '/cancel/:requestId',\n async (req: Request, res: Response) => {\n const { requestId } = req.params;\n\n if (!requestId) {\n return res.status(400).json({\n error: 'requestId is required',\n });\n }\n\n try {\n // Check if this is the current running task\n if (this.currentTaskId !== requestId) {\n return res.json({\n status: 'not_found',\n message: 'Task not found or already completed',\n });\n }\n\n console.log(`Cancelling task: ${requestId}`);\n\n // Get current execution data before cancelling (dump and reportHTML)\n let dump: any = null;\n let reportHTML: string | null = null;\n\n try {\n const dumpString = this.agent.dumpDataString?.({\n inlineScreenshots: true,\n });\n if (dumpString) {\n const groupedDump =\n GroupedActionDump.fromSerializedString(dumpString);\n // Extract first execution from grouped dump\n dump = groupedDump.executions?.[0] || null;\n }\n\n reportHTML =\n this.agent.reportHTMLString?.({ inlineScreenshots: true }) ||\n null;\n } catch (error: unknown) {\n console.warn('Failed to get execution data before cancel:', error);\n }\n\n // Recreate/destroy agent to cancel the current task\n await this.recreateAgent();\n\n // Clean up\n delete this.taskExecutionDumps[requestId];\n this.currentTaskId = null;\n\n res.json({\n status: 'cancelled',\n message: 'Task cancelled successfully',\n dump,\n reportHTML,\n });\n } catch (error: unknown) {\n const errorMessage =\n error instanceof Error ? error.message : 'Unknown error';\n console.error(`Failed to cancel: ${errorMessage}`);\n res.status(500).json({\n error: `Failed to cancel: ${errorMessage}`,\n });\n }\n },\n );\n\n // Screenshot API for real-time screenshot polling\n this._app.get('/screenshot', async (_req: Request, res: Response) => {\n try {\n // Check if page has screenshotBase64 method\n if (typeof this.agent.interface.screenshotBase64 !== 'function') {\n return res.status(500).json({\n error: 'Screenshot method not available on current interface',\n });\n }\n\n const base64Screenshot = await this.agent.interface.screenshotBase64();\n\n res.json({\n screenshot: base64Screenshot,\n timestamp: Date.now(),\n });\n } catch (error: unknown) {\n const errorMessage =\n error instanceof Error ? error.message : 'Unknown error';\n console.error(`Failed to take screenshot: ${errorMessage}`);\n res.status(500).json({\n error: `Failed to take screenshot: ${errorMessage}`,\n });\n }\n });\n\n // MJPEG streaming endpoint for real-time screen preview\n // Proxies native MJPEG stream (e.g. WDA MJPEG server) when available,\n // falls back to polling screenshotBase64() otherwise.\n this._app.get('/mjpeg', async (req: Request, res: Response) => {\n const nativeUrl = this.agent?.interface?.mjpegStreamUrl;\n\n if (nativeUrl && this._nativeMjpegAvailable !== false) {\n const proxyOk = await this.probeAndProxyNativeMjpeg(\n nativeUrl,\n req,\n res,\n );\n if (proxyOk) return;\n }\n\n if (typeof this.agent?.interface?.screenshotBase64 !== 'function') {\n return res.status(500).json({\n error: 'Screenshot method not available on current interface',\n });\n }\n\n await this.startPollingMjpegStream(req, res);\n });\n\n // Interface info API for getting interface type and description\n this._app.get('/interface-info', async (_req: Request, res: Response) => {\n try {\n const type = this.agent.interface.interfaceType || 'Unknown';\n const description = this.agent.interface.describe?.() || undefined;\n\n res.json({\n type,\n description,\n });\n } catch (error: unknown) {\n const errorMessage =\n error instanceof Error ? error.message : 'Unknown error';\n console.error(`Failed to get interface info: ${errorMessage}`);\n res.status(500).json({\n error: `Failed to get interface info: ${errorMessage}`,\n });\n }\n });\n\n this.app.post('/config', async (req: Request, res: Response) => {\n const { aiConfig } = req.body;\n\n if (!aiConfig || typeof aiConfig !== 'object') {\n return res.status(400).json({\n error: 'aiConfig is required and must be an object',\n });\n }\n\n if (Object.keys(aiConfig).length === 0) {\n return res.json({\n status: 'ok',\n message: 'AI config not changed due to empty object',\n });\n }\n\n try {\n overrideAIConfig(aiConfig);\n } catch (error: unknown) {\n const errorMessage =\n error instanceof Error ? error.message : 'Unknown error';\n console.error(`Failed to update AI config: ${errorMessage}`);\n return res.status(500).json({\n error: `Failed to update AI config: ${errorMessage}`,\n });\n }\n\n // Validate the config immediately so the frontend gets early feedback\n try {\n globalModelConfigManager.getModelConfig('default');\n } catch (error: unknown) {\n const errorMessage =\n error instanceof Error ? error.message : 'Unknown error';\n console.error(`AI config validation failed: ${errorMessage}`);\n return res.status(400).json({\n error: errorMessage,\n });\n }\n\n // Note: Agent will be recreated on next execution to apply new config\n return res.json({\n status: 'ok',\n message:\n 'AI config updated. Agent will be recreated on next execution.',\n });\n });\n }\n\n /**\n * Probe and proxy a native MJPEG stream (e.g. WDA MJPEG server).\n * Result is cached so we only probe once per server lifetime.\n */\n private probeAndProxyNativeMjpeg(\n nativeUrl: string,\n req: Request,\n res: Response,\n ): Promise<boolean> {\n return new Promise<boolean>((resolve) => {\n console.log(`MJPEG: trying native stream from ${nativeUrl}`);\n const proxyReq = http.get(nativeUrl, (proxyRes) => {\n this._nativeMjpegAvailable = true;\n console.log('MJPEG: streaming via native WDA MJPEG server');\n const contentType = proxyRes.headers['content-type'];\n if (contentType) {\n res.setHeader('Content-Type', contentType);\n }\n res.setHeader('Cache-Control', 'no-cache, no-store, must-revalidate');\n res.setHeader('Connection', 'keep-alive');\n proxyRes.pipe(res);\n req.on('close', () => proxyReq.destroy());\n resolve(true);\n });\n proxyReq.on('error', (err) => {\n this._nativeMjpegAvailable = false;\n console.warn(\n `MJPEG: native stream unavailable (${err.message}), using polling mode`,\n );\n resolve(false);\n });\n });\n }\n\n /**\n * Stream screenshots as MJPEG by polling screenshotBase64().\n */\n private async startPollingMjpegStream(\n req: Request,\n res: Response,\n ): Promise<void> {\n const defaultMjpegFps = 10;\n const maxMjpegFps = 30;\n const maxErrorBackoffMs = 3000;\n const errorLogThreshold = 3;\n\n const fps = Math.min(\n Math.max(Number(req.query.fps) ?? defaultMjpegFps, 1),\n maxMjpegFps,\n );\n const interval = Math.round(1000 / fps);\n const boundary = 'mjpeg-boundary';\n console.log(`MJPEG: streaming via polling mode (${fps}fps)`);\n\n res.setHeader(\n 'Content-Type',\n `multipart/x-mixed-replace; boundary=${boundary}`,\n );\n res.setHeader('Cache-Control', 'no-cache, no-store, must-revalidate');\n res.setHeader('Connection', 'keep-alive');\n\n let stopped = false;\n let consecutiveErrors = 0;\n req.on('close', () => {\n stopped = true;\n });\n\n while (!stopped) {\n const frameStart = Date.now();\n try {\n const base64 = await this.agent.interface.screenshotBase64();\n if (stopped) break;\n consecutiveErrors = 0;\n\n const raw = base64.replace(/^data:image\\/\\w+;base64,/, '');\n const buf = Buffer.from(raw, 'base64');\n\n res.write(`--${boundary}\\r\\n`);\n res.write('Content-Type: image/jpeg\\r\\n');\n res.write(`Content-Length: ${buf.length}\\r\\n\\r\\n`);\n res.write(buf);\n res.write('\\r\\n');\n } catch (err) {\n if (stopped) break;\n consecutiveErrors++;\n if (consecutiveErrors <= errorLogThreshold) {\n console.error('MJPEG frame error:', err);\n } else if (consecutiveErrors === errorLogThreshold + 1) {\n console.error(\n 'MJPEG: suppressing further errors, retrying silently...',\n );\n }\n const backoff = Math.min(1000 * consecutiveErrors, maxErrorBackoffMs);\n await new Promise((r) => setTimeout(r, backoff));\n continue;\n }\n\n const elapsed = Date.now() - frameStart;\n const remaining = interval - elapsed;\n if (remaining > 0) {\n await new Promise((r) => setTimeout(r, remaining));\n }\n }\n }\n\n /**\n * Setup static file serving routes\n */\n private setupStaticRoutes(): void {\n // Handle index.html with port injection\n this._app.get('/', (_req: Request, res: Response) => {\n this.serveHtmlWithPorts(res);\n });\n\n this._app.get('/index.html', (_req: Request, res: Response) => {\n this.serveHtmlWithPorts(res);\n });\n\n // Use express.static middleware for secure static file serving\n this._app.use(express.static(this.staticPath));\n\n // Fallback to index.html for SPA routing\n this._app.get('*', (_req: Request, res: Response) => {\n this.serveHtmlWithPorts(res);\n });\n }\n\n /**\n * Serve HTML with injected port configuration\n */\n private serveHtmlWithPorts(res: Response): void {\n try {\n const htmlPath = join(this.staticPath, 'index.html');\n let html = readFileSync(htmlPath, 'utf8');\n\n // Get scrcpy server port from global\n const scrcpyPort = (global as any).scrcpyServerPort || this.port! + 1;\n\n // Inject scrcpy port configuration script into HTML head\n const configScript = `\n <script>\n window.SCRCPY_PORT = ${scrcpyPort};\n </script>\n `;\n\n // Insert the script before closing </head> tag\n html = html.replace('</head>', `${configScript}</head>`);\n\n res.setHeader('Content-Type', 'text/html');\n res.send(html);\n } catch (error) {\n console.error('Error serving HTML with ports:', error);\n res.status(500).send('Internal Server Error');\n }\n }\n\n /**\n * Launch the server on specified port\n */\n async launch(port?: number): Promise<PlaygroundServer> {\n // If using factory mode, initialize agent\n if (this.agentFactory) {\n console.log('Initializing agent from factory function...');\n this.agent = await this.agentFactory();\n console.log('Agent initialized successfully');\n }\n\n // Initialize routes now, after any middleware has been added\n this.initializeApp();\n\n this.port = port || defaultPort;\n\n return new Promise((resolve) => {\n const serverPort = this.port;\n this.server = this._app.listen(serverPort, () => {\n resolve(this);\n });\n });\n }\n\n /**\n * Close the server and clean up resources\n */\n async close(): Promise<void> {\n return new Promise((resolve, reject) => {\n if (this.server) {\n // Clean up the single agent\n try {\n this.agent.destroy();\n } catch (error) {\n console.warn('Failed to destroy agent:', error);\n }\n this.taskExecutionDumps = {};\n\n // Close the server\n this.server.close((error) => {\n if (error) {\n reject(error);\n } else {\n this.server = undefined;\n resolve();\n }\n });\n } else {\n resolve();\n }\n });\n }\n}\n\nexport default PlaygroundServer;\nexport { PlaygroundServer };\n"],"names":["__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","filePath","resolvedPath","resolve","resolvedTmpDir","tmpFile","writeFileSync","error","contextFile","existsSync","readFileSync","requestId","executionDump","actionSpace","processedActionSpace","action","typedAction","processedSchema","e","actionName","type","prompt","params","deepThink","screenshotIncluded","domIncluded","deviceOptions","_dump","response","startTime","Date","value","executeAction","formatErrorMessage","dumpString","groupedDump","GroupedActionDump","timeCost","dump","reportHTML","_req","base64Screenshot","nativeUrl","proxyOk","description","undefined","aiConfig","overrideAIConfig","globalModelConfigManager","Promise","proxyReq","http","proxyRes","contentType","defaultMjpegFps","maxMjpegFps","maxErrorBackoffMs","errorLogThreshold","fps","Math","Number","interval","boundary","stopped","consecutiveErrors","frameStart","base64","raw","buf","Buffer","backoff","r","setTimeout","elapsed","remaining","htmlPath","html","scrcpyPort","global","configScript","port","serverPort","reject","agent","staticPath","id","getTmpDir"],"mappings":"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"}