@midscene/core 1.12.3 → 1.12.4-beta-20260902093735.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (61) hide show
  1. package/dist/es/agent/agent.mjs +88 -25
  2. package/dist/es/agent/agent.mjs.map +1 -1
  3. package/dist/es/agent/index.mjs +2 -1
  4. package/dist/es/agent/insight.mjs +40 -10
  5. package/dist/es/agent/insight.mjs.map +1 -1
  6. package/dist/es/agent/prompt-context.mjs +42 -6
  7. package/dist/es/agent/prompt-context.mjs.map +1 -1
  8. package/dist/es/agent/run-gherkin-scenario.mjs.map +1 -1
  9. package/dist/es/agent/utils.mjs +1 -1
  10. package/dist/es/ai-model/prompt/insight/user-prompt.mjs +1 -1
  11. package/dist/es/ai-model/prompt/insight/user-prompt.mjs.map +1 -1
  12. package/dist/es/ai-model/workflows/insight/extraction.mjs +4 -1
  13. package/dist/es/ai-model/workflows/insight/extraction.mjs.map +1 -1
  14. package/dist/es/ai-model/workflows/planning/custom-planning.mjs +3 -3
  15. package/dist/es/ai-model/workflows/planning/custom-planning.mjs.map +1 -1
  16. package/dist/es/ai-model/workflows/planning/standard-planning.mjs +1 -1
  17. package/dist/es/ai-model/workflows/planning/standard-planning.mjs.map +1 -1
  18. package/dist/es/index.mjs +2 -2
  19. package/dist/es/index.mjs.map +1 -1
  20. package/dist/es/report-html-template.mjs +1 -1
  21. package/dist/es/types.mjs.map +1 -1
  22. package/dist/es/utils.mjs +1 -1
  23. package/dist/es/yaml/player.mjs +0 -5
  24. package/dist/es/yaml/player.mjs.map +1 -1
  25. package/dist/es/yaml/utils.mjs +4 -3
  26. package/dist/es/yaml/utils.mjs.map +1 -1
  27. package/dist/lib/agent/agent.js +87 -24
  28. package/dist/lib/agent/agent.js.map +1 -1
  29. package/dist/lib/agent/index.js +5 -1
  30. package/dist/lib/agent/insight.js +40 -10
  31. package/dist/lib/agent/insight.js.map +1 -1
  32. package/dist/lib/agent/prompt-context.js +55 -7
  33. package/dist/lib/agent/prompt-context.js.map +1 -1
  34. package/dist/lib/agent/run-gherkin-scenario.js.map +1 -1
  35. package/dist/lib/agent/utils.js +1 -1
  36. package/dist/lib/ai-model/prompt/insight/user-prompt.js +1 -1
  37. package/dist/lib/ai-model/prompt/insight/user-prompt.js.map +1 -1
  38. package/dist/lib/ai-model/workflows/insight/extraction.js +4 -1
  39. package/dist/lib/ai-model/workflows/insight/extraction.js.map +1 -1
  40. package/dist/lib/ai-model/workflows/planning/custom-planning.js +3 -3
  41. package/dist/lib/ai-model/workflows/planning/custom-planning.js.map +1 -1
  42. package/dist/lib/ai-model/workflows/planning/standard-planning.js +1 -1
  43. package/dist/lib/ai-model/workflows/planning/standard-planning.js.map +1 -1
  44. package/dist/lib/index.js +4 -1
  45. package/dist/lib/index.js.map +1 -1
  46. package/dist/lib/report-html-template.js +1 -1
  47. package/dist/lib/types.js.map +1 -1
  48. package/dist/lib/utils.js +1 -1
  49. package/dist/lib/yaml/player.js +0 -5
  50. package/dist/lib/yaml/player.js.map +1 -1
  51. package/dist/lib/yaml/utils.js +3 -2
  52. package/dist/lib/yaml/utils.js.map +1 -1
  53. package/dist/types/agent/agent.d.ts +22 -3
  54. package/dist/types/agent/index.d.ts +2 -1
  55. package/dist/types/agent/insight.d.ts +6 -1
  56. package/dist/types/agent/prompt-context.d.ts +27 -1
  57. package/dist/types/agent/run-gherkin-scenario.d.ts +1 -0
  58. package/dist/types/index.d.ts +1 -1
  59. package/dist/types/types.d.ts +26 -0
  60. package/dist/types/yaml.d.ts +12 -4
  61. package/package.json +2 -2
@@ -1 +1 @@
1
- {"version":3,"file":"types.mjs","sources":["../../src/types.ts"],"sourcesContent":["/* eslint-disable @typescript-eslint/no-explicit-any */\n\nimport type { SerializedError } from '@midscene/shared/agent-tools/error-formatter';\nimport type { NodeType } from '@midscene/shared/constants';\nimport type { CreateOpenAIClientFn, TModelConfig } from '@midscene/shared/env';\nimport type {\n BaseElement,\n LocateResultElement,\n Rect,\n Size,\n} from '@midscene/shared/types';\nimport type { z } from 'zod';\nimport type { TUserPrompt } from './common';\nimport type { ScreenshotItem } from './screenshot-item';\nimport type {\n DetailedLocateParam,\n MidsceneYamlFlowItem,\n ServiceExtractOption,\n} from './yaml';\n\nexport type {\n ElementTreeNode,\n BaseElement,\n Rect,\n Size,\n Point,\n} from '@midscene/shared/types';\nexport type { SerializedError } from '@midscene/shared/agent-tools/error-formatter';\nexport * from './yaml';\n\nexport { ServiceError } from './errors';\nexport {\n ExecutionDump,\n ReportActionDump,\n GroupedActionDump,\n} from './dump/report-action-dump';\n\nexport type AIUsageInfo = Record<string, any> & {\n prompt_tokens: number | undefined;\n completion_tokens: number | undefined;\n total_tokens: number | undefined;\n cached_input: number | undefined;\n time_cost: number | undefined;\n model_name: string | undefined;\n model_description: string | undefined;\n /**\n * Raw top-level `.model` value returned by the model service response.\n */\n response_model_name: string | undefined;\n /**\n * Semantic intent of the model call, such as default, planning, or insight.\n */\n intent: string | undefined;\n /**\n * Config slot where the model config was resolved from. For example, a\n * planning call may use the default slot when no planning model is configured.\n */\n slot: string | undefined;\n request_id: string | undefined;\n};\n\nexport type { LocateResultElement };\n\nexport type AISingleElementResponseByPosition = {\n position?: {\n x: number;\n y: number;\n };\n bbox?: [number, number, number, number];\n reason: string;\n text: string;\n};\n\nexport type LocateResultPoint = [number, number];\nexport type Bbox = [number, number, number, number];\nexport type LocateResultBbox = Bbox;\nexport type PixelBbox = Bbox;\n\nexport interface AIElementLocateResponse {\n bbox?: LocateResultBbox;\n point?: LocateResultPoint;\n error?: string;\n}\n\nexport interface AIDataExtractionResponse<DataDemand> {\n data: DataDemand;\n errors?: string[];\n thought?: string;\n}\n\nexport interface AISectionLocatorResponse {\n bbox?: LocateResultBbox;\n point?: LocateResultPoint;\n references_bbox?: LocateResultBbox[];\n references_point?: LocateResultPoint[];\n error?: string;\n}\n\nexport interface AIAssertionResponse {\n pass: boolean;\n thought: string;\n}\n\nexport interface AIDescribeElementResponse {\n description: string;\n error?: string;\n}\n\nexport interface LocatorValidatorOption {\n centerDistanceThreshold?: number;\n}\n\nexport interface LocateValidatorResult {\n pass: boolean;\n rect: Rect;\n center: [number, number];\n centerDistance?: number;\n includedInRect?: boolean;\n}\n\nexport interface AgentDescribeElementAtPointResult {\n prompt: string;\n deepLocate: boolean;\n deepDescribe: boolean;\n verifyResult?: LocateValidatorResult;\n success: boolean;\n error?: string;\n failureStage?: 'describe' | 'verify';\n}\n\n/**\n * context\n */\n\nexport interface UiNode {\n type: string;\n attrs: Record<string, string | undefined>;\n bounds: Rect;\n children: UiNode[];\n}\n\nexport interface UITreeSnapshot {\n platform: 'android';\n capturedAt: number;\n root: UiNode;\n}\n\nexport abstract class UIContext {\n /**\n * screenshot of the current UI state. which size is shotSize(be shrunk by screenshotShrinkFactor),\n */\n abstract screenshot: ScreenshotItem;\n\n /**\n * Optional sequence of screenshots captured over a short time window, in\n * temporal order (earliest first, latest last). When present with more than\n * one frame, extract/assert flows submit all frames to the model so it can\n * observe transient UI (toasts, carousels, auto-hiding controls). The last\n * frame is the same state as {@link screenshot}.\n */\n abstract screenshotSequence?: ScreenshotItem[];\n\n /**\n * screenshot size after shrinking\n */\n abstract shotSize: Size;\n\n /**\n * The ratio for converting shrunk screenshot coordinates to logical coordinates.\n *\n * Example:\n * - Physical screen width: 3000px, dpr=6\n * - Logical width: 500px\n * - User-defined screenshotShrinkFactor: 2\n * - Actual shrunk screenshot width: 3000 / 2 = 1500px\n * - shrunkShotToLogicalRatio: dpr / screenshotShrinkFactor = 6 / 2 = 3\n * - To map back to logical coordinates: 1500 / shrunkShotToLogicalRatio = 500px\n */\n abstract shrunkShotToLogicalRatio: number;\n\n abstract _isFrozen?: boolean;\n\n // @deprecated - backward compatibility for aiLocate\n abstract deprecatedDpr?: number;\n}\n\nexport type EnsureObject<T> = { [K in keyof T]: any };\n\nexport type ServiceAction = 'locate' | 'extract' | 'assert' | 'describe';\n\nexport type ServiceExtractParam = string | Record<string, string>;\n\nexport type ElementCacheFeature = Record<string, unknown>;\n\nexport interface LocateResult {\n element: LocateResultElement | null;\n rect?: Rect;\n}\n\nexport type ThinkingLevel = 'off' | 'medium' | 'high';\n\nexport type AiActEffort = 'fast' | 'balance' | 'deepThink';\n\nexport type DeepThinkOption = 'unset' | true | false;\n\nexport interface ServiceTaskInfo {\n durationMs: number;\n formatResponse?: unknown;\n /**\n * Adapter-extracted content used by Midscene for parsing. This is not the\n * full provider response or choices[0].message.\n */\n rawResponse?: unknown;\n rawChoiceMessage?: unknown;\n usage?: AIUsageInfo;\n searchArea?: Rect;\n /**\n * Adapter-extracted content from the search-area model call. This is not the\n * full provider response or choices[0].message.\n */\n searchAreaRawResponse?: string;\n searchAreaRawChoiceMessage?: unknown;\n searchAreaUsage?: AIUsageInfo;\n reasoning_content?: string;\n}\n\nexport interface DumpMeta {\n logTime: number;\n}\n\nexport type ReportAttributes = Record<\n string,\n string | number | boolean | null | undefined\n>;\n\nexport interface ReportDumpWithAttributes {\n dumpString: string;\n attributes?: ReportAttributes;\n}\n\nexport interface ServiceDump extends DumpMeta {\n type: 'locate' | 'extract' | 'assert';\n logId: string;\n userQuery: {\n element?: TUserPrompt;\n dataDemand?: ServiceExtractParam;\n assertion?: TUserPrompt;\n };\n matchedElement?: LocateResultElement[];\n matchedRect?: Rect;\n deepLocate?: boolean;\n data: any;\n assertionPass?: boolean;\n assertionThought?: string;\n taskInfo: ServiceTaskInfo;\n error?: string;\n output?: any;\n}\n\nexport type PartialServiceDumpFromSDK = Omit<\n ServiceDump,\n 'logTime' | 'logId' | 'model_name'\n>;\n\nexport interface ServiceResultBase {\n dump: ServiceDump;\n}\n\nexport type LocateResultWithDump = LocateResult & ServiceResultBase;\n\nexport interface ServiceExtractResult<T> extends ServiceResultBase {\n data: T;\n thought?: string;\n usage?: AIUsageInfo;\n reasoning_content?: string;\n}\n\n// intermediate variables to optimize the return value by AI\nexport interface LiteUISection {\n name: string;\n description: string;\n sectionCharacteristics: string;\n textIds: string[];\n}\n\nexport type ElementById = (id: string) => BaseElement | null;\n\nexport type ServiceAssertionResponse = AIAssertionResponse & {\n usage?: AIUsageInfo;\n};\n\n/**\n * agent\n */\n\nexport type OnTaskStartTip = (tip: string) => Promise<void> | void;\n\nexport interface AgentWaitForOpt extends ServiceExtractOption {\n checkIntervalMs?: number;\n timeoutMs?: number;\n}\n\nexport interface AgentAssertOpt {\n keepRawResponse?: boolean;\n context?: string;\n abortSignal?: AbortSignal;\n}\n\nexport interface AgentAssertResult {\n pass: boolean;\n thought?: string;\n message?: string;\n}\n\nexport type QueryOptions = ServiceExtractOption;\nexport type AssertOptions = AgentAssertOpt & ServiceExtractOption;\n\n/** Options for fixed observations, which never read the live DOM. */\nexport type ObservationQueryOptions = Omit<QueryOptions, 'domIncluded'> & {\n domIncluded?: never;\n};\n\n/** Assertion options for fixed observations, which never read the live DOM. */\nexport type ObservationAssertOptions = Omit<AssertOptions, 'domIncluded'> & {\n domIncluded?: never;\n};\n\n/** Read-only AI operations supported by both live Agents and UI observations. */\nexport interface InsightAPI<\n QueryOpt extends QueryOptions = QueryOptions,\n AssertOpt extends AssertOptions = AssertOptions,\n> {\n aiQuery<ReturnType = any>(\n demand: ServiceExtractParam,\n options?: QueryOpt,\n ): Promise<ReturnType>;\n aiBoolean(prompt: TUserPrompt, options?: QueryOpt): Promise<boolean>;\n aiNumber(prompt: TUserPrompt, options?: QueryOpt): Promise<number>;\n aiString(prompt: TUserPrompt, options?: QueryOpt): Promise<string>;\n aiAsk(prompt: TUserPrompt, options?: QueryOpt): Promise<string>;\n aiAssert(\n assertion: TUserPrompt,\n message?: string,\n options?: AssertOpt,\n ): Promise<AgentAssertResult | undefined>;\n}\n\n/**\n * planning\n *\n */\n\ntype PlanningActionBase = {\n thought?: string;\n log?: string; // a brief preamble to the user explaining what you’re about to do\n type: string;\n};\n\nexport type PlanningAction<ParamType = undefined> = PlanningActionBase &\n ([ParamType] extends [undefined] ? { param?: any } : { param: ParamType });\n\nexport type SubGoalStatus = 'pending' | 'running' | 'finished';\n\nexport interface SubGoal {\n index: number;\n status: SubGoalStatus;\n description: string;\n logs?: string[];\n}\n\nexport interface RawResponsePlanningAIResponse {\n action: PlanningAction | null;\n thought?: string;\n log: string;\n memory?: string;\n error?: string;\n finalizeMessage?: string;\n finalizeSuccess?: boolean;\n updateSubGoals?: SubGoal[];\n markFinishedIndexes?: number[];\n}\n\nexport interface PlanningAIResponse\n extends Omit<RawResponsePlanningAIResponse, 'action'> {\n actions?: PlanningAction[];\n usage?: AIUsageInfo;\n /**\n * Adapter-extracted content used by Midscene for parsing. This is not the\n * full provider response or choices[0].message.\n */\n rawResponse?: string;\n rawChoiceMessage?: unknown;\n yamlFlow?: MidsceneYamlFlowItem[];\n yamlString?: string;\n error?: string;\n reasoning_content?: string;\n shouldContinuePlanning: boolean;\n output?: string; // Output message from <complete> tag (same as finalizeMessage)\n}\n\nexport interface PlanningActionParamSleep {\n timeMs: number;\n}\n\nexport interface PlanningActionParamError {\n thought: string;\n}\n\nexport type PlanningActionParamWaitFor = AgentWaitForOpt & {};\n\nexport interface LongPressParam {\n duration?: number;\n}\n\nexport interface PullParam {\n direction: 'up' | 'down';\n distance?: number;\n duration?: number;\n}\n/**\n * misc\n */\n\nexport interface Color {\n name: string;\n hex: string;\n}\n\nexport interface BaseAgentParserOpt {\n selector?: string;\n}\n// eslint-disable-next-line @typescript-eslint/no-empty-interface\nexport interface PuppeteerParserOpt extends BaseAgentParserOpt {}\n\n// eslint-disable-next-line @typescript-eslint/no-empty-interface\nexport interface PlaywrightParserOpt extends BaseAgentParserOpt {}\n\n/*\naction\n*/\nexport interface ExecutionTaskProgressOptions {\n onTaskStart?: (task: ExecutionTask) => Promise<void> | void;\n}\n\n/**\n * Generic agent progress bus.\n *\n * Progress notifications are a single, generic stream the agent broadcasts as\n * it works. Each event is a thin envelope: a `scope` naming the producer, a\n * `phase` within that producer's lifecycle, a monotonic `sequence`, and a\n * structured, presentation-free `data` payload. The bus knows nothing about any\n * particular producer's payload - consumers narrow by `scope`. `aiAct` is the\n * first producer (\"pilot\") on this bus; others (queries, waits, ...) can be\n * added without touching the bus, the listener API, or the renderer core.\n */\nexport interface AgentProgressEvent<\n TScope extends string = string,\n TData = unknown,\n TPhase extends string = string,\n> {\n scope: TScope;\n phase: TPhase;\n sequence: number;\n data: TData;\n}\n\nexport type AgentProgressListener<\n TScope extends string = string,\n TData = unknown,\n TPhase extends string = string,\n> = (event: AgentProgressEvent<TScope, TData, TPhase>) => Promise<void> | void;\n\n// --- aiAct: the first producer on the generic progress bus ---\n\nexport type AiActProgressPhase =\n | 'start'\n | 'plan_thinking'\n | 'plan_planned'\n | 'plan_action'\n | 'plan_failed'\n | 'action_running'\n | 'action_done'\n | 'action_failed'\n | 'complete'\n | 'failed';\n\nexport interface AiActProgressAction {\n name: string;\n target?: string;\n point?: [number, number];\n bbox?: [number, number, number, number];\n /**\n * Structured, compacted summary of the action params for actions that are\n * not described by a point/bbox (e.g. `Sleep` -> `{ timeMs }`). This is data,\n * never a pre-formatted display string; consumers decide how to render it.\n */\n param?: unknown;\n}\n\n/**\n * Structured payload carried by aiAct progress events. The producer only\n * reports *what happened* as data: the action involved, the raw text the model\n * produced, timings and errors. It never assembles human-readable log lines or\n * truncates strings for display - that belongs to whichever layer consumes the\n * stream (e.g. the CLI verbose renderer).\n */\nexport interface AiActProgressData {\n /** Original user instruction, present on the `start` phase. */\n prompt?: string;\n planIndex?: number;\n planLimit?: number;\n /** Latest screenshot, present on `plan_thinking`. */\n screenshot?: ScreenshotItem;\n /** Structured action descriptor, present on the `*action*` phases. */\n action?: AiActProgressAction;\n /**\n * Raw, untruncated semantic text produced by the model. Consumers choose\n * which field to surface and how to format/truncate it.\n */\n thought?: string;\n log?: string;\n output?: string;\n /** Wall-clock cost of an action, present on `action_done`/`action_failed`. */\n durationMs?: number;\n error?: string;\n}\n\nexport const aiActProgressScope = 'aiAct';\n\nexport interface ExecutionRecorderItem {\n type: 'screenshot';\n ts: number;\n screenshot?: ScreenshotItem;\n description?: string;\n timing?: string;\n}\n\nexport interface RecordToReportScreenshot {\n /**\n * PNG/JPEG data URI, or raw PNG base64 body.\n */\n base64: string;\n description?: string;\n}\n\nexport interface RecordToReportOptions {\n content?: string;\n /**\n * @deprecated Use `screenshots: [{ base64 }]` instead.\n */\n screenshotBase64?: string;\n /**\n * Custom screenshots to display under a single report entry.\n */\n screenshots?: RecordToReportScreenshot[];\n}\n\nexport type ExecutionTaskType = 'Planning' | 'Insight' | 'Action Space' | 'Log';\n\nexport interface ExecutorContext {\n task: ExecutionTask;\n element?: LocateResultElement | null;\n uiContext?: UIContext;\n}\n\nexport interface ExecutionTaskApply<\n Type extends ExecutionTaskType = any,\n TaskParam = any,\n TaskOutput = any,\n TaskLog = any,\n> {\n type: Type;\n subType?: string;\n param?: TaskParam;\n thought?: string;\n uiContext?: UIContext;\n executor: (\n context: ExecutorContext,\n ) => // biome-ignore lint/suspicious/noConfusingVoidType: void is intentionally allowed as some executors may not return a value\n | Promise<ExecutionTaskReturn<TaskOutput, TaskLog> | undefined | void>\n | undefined\n | void;\n}\n\nexport interface ExecutionTaskHitBy {\n from: string;\n context: Record<string, any>;\n}\n\nexport interface ExecutionTaskReturn<TaskOutput = unknown, TaskLog = unknown> {\n output?: TaskOutput;\n log?: TaskLog;\n recorder?: ExecutionRecorderItem[];\n hitBy?: ExecutionTaskHitBy;\n}\n\nexport type ExecutionTask<\n E extends ExecutionTaskApply<any, any, any> = ExecutionTaskApply<\n any,\n any,\n any\n >,\n> = E &\n ExecutionTaskReturn<\n E extends ExecutionTaskApply<any, any, infer TaskOutput, any>\n ? TaskOutput\n : unknown,\n E extends ExecutionTaskApply<any, any, any, infer TaskLog>\n ? TaskLog\n : unknown\n > & {\n taskId: string;\n status: 'pending' | 'running' | 'finished' | 'failed' | 'cancelled';\n /**\n * Optional feedback produced by a task for the next planning round.\n * This is execution metadata, not part of the action return value.\n */\n planningFeedback?: string;\n /**\n * A bounded diagnostic DTO created when the task executor throws. Arbitrary\n * upstream payloads are intentionally omitted; use this field for structured\n * diagnostics or errorMessage/errorStack for the common display path.\n */\n error?: SerializedError;\n errorMessage?: string;\n errorStack?: string;\n timing?: {\n start: number;\n getUiContextStart?: number;\n getUiContextEnd?: number;\n callAiStart?: number;\n callAiEnd?: number;\n beforeInvokeActionHookStart?: number;\n beforeInvokeActionHookEnd?: number;\n callActionStart?: number;\n callActionEnd?: number;\n afterInvokeActionHookStart?: number;\n afterInvokeActionHookEnd?: number;\n captureAfterCallingSnapshotStart?: number;\n captureAfterCallingSnapshotEnd?: number;\n end?: number;\n cost?: number;\n };\n usage?: AIUsageInfo;\n /**\n * Pixel rect of the deepLocate first-stage search area in screenshot\n * coordinates. Used by reports to explain the crop/zoom area that the\n * final locate ran against.\n */\n searchArea?: Rect;\n searchAreaUsage?: AIUsageInfo;\n reasoning_content?: string;\n };\n\nexport interface IExecutionDump extends DumpMeta {\n /** Stable unique identifier for this execution run */\n id?: string;\n name: string;\n description?: string;\n tasks: ExecutionTask[];\n aiActContext?: string;\n}\n\n/*\ntask - service-locate\n*/\nexport interface ExecutionTaskInsightLocateOutput {\n element: LocateResultElement | null;\n}\n\nexport type ExecutionTaskInsightDump = ServiceDump;\n\nexport type ExecutionTaskInsightLocateApply = ExecutionTaskApply<\n 'Insight',\n DetailedLocateParam,\n ExecutionTaskInsightLocateOutput,\n ExecutionTaskInsightDump\n>;\n\nexport type ExecutionTaskInsightLocate =\n ExecutionTask<ExecutionTaskInsightLocateApply>;\n\n/*\ntask - service-query\n*/\nexport interface ExecutionTaskInsightQueryParam {\n dataDemand: ServiceExtractParam;\n domIncluded?: boolean | 'visible-only';\n context?: string;\n}\n\nexport interface ExecutionTaskInsightQueryOutput {\n data: any;\n}\n\nexport type ExecutionTaskInsightQueryApply = ExecutionTaskApply<\n 'Insight',\n ExecutionTaskInsightQueryParam,\n any,\n ExecutionTaskInsightDump\n>;\n\nexport type ExecutionTaskInsightQuery =\n ExecutionTask<ExecutionTaskInsightQueryApply>;\n\n/*\ntask - assertion\n*/\nexport interface ExecutionTaskInsightAssertionParam {\n assertion: string;\n}\n\nexport type ExecutionTaskInsightAssertionApply = ExecutionTaskApply<\n 'Insight',\n ExecutionTaskInsightAssertionParam,\n ServiceAssertionResponse,\n ExecutionTaskInsightDump\n>;\n\nexport type ExecutionTaskInsightAssertion =\n ExecutionTask<ExecutionTaskInsightAssertionApply>;\n\n/*\ntask - action (i.e. interact) \n*/\nexport type ExecutionTaskActionApply<ActionParam = any> = ExecutionTaskApply<\n 'Action Space',\n ActionParam,\n void,\n void\n>;\n\nexport type ExecutionTaskAction = ExecutionTask<ExecutionTaskActionApply>;\n\n/*\ntask - Log\n*/\n\nexport type ExecutionTaskLogApply<\n LogParam = {\n content: string;\n },\n> = ExecutionTaskApply<'Log', LogParam, void, void>;\n\nexport type ExecutionTaskLog = ExecutionTask<ExecutionTaskLogApply>;\n\n/*\ntask - planning\n*/\n\nexport interface ExecutionTaskPlanningParam {\n userInstruction: TUserPrompt;\n userInstructionDisplay?: string;\n replanningCycleLimit?: number;\n aiActContext?: string;\n imagesIncludeCount?: number;\n effort?: AiActEffort;\n subGoalStatus?: string;\n memoriesStatus?: string;\n}\n\nexport type ExecutionTaskPlanningApply = ExecutionTaskApply<\n 'Planning',\n ExecutionTaskPlanningParam,\n PlanningAIResponse\n>;\n\nexport type ExecutionTaskPlanning = ExecutionTask<ExecutionTaskPlanningApply>;\n\n/*\ntask - planning-locate\n*/\nexport interface ExecutionTaskPlanningLocateOutput {\n element: LocateResultElement | null;\n}\n\nexport type ExecutionTaskPlanningDump = ServiceDump;\n\nexport type ExecutionTaskPlanningLocateApply = ExecutionTaskApply<\n 'Planning',\n DetailedLocateParam,\n ExecutionTaskPlanningLocateOutput,\n ExecutionTaskPlanningDump\n>;\n\nexport type ExecutionTaskPlanningLocate =\n ExecutionTask<ExecutionTaskPlanningLocateApply>;\n\n/*\nHow a report file stores screenshots:\n- `inline`: base64 image script tags embedded in the single HTML file\n- `directory`: external PNG files under a sibling `screenshots/` dir\n*/\nexport type ScreenshotMode = 'inline' | 'directory';\n\n/*\nReport metadata - extracted from ReportActionDump for per-execution writes\n*/\nexport interface ReportMeta {\n groupName: string;\n groupDescription?: string;\n sdkVersion: string;\n modelBriefs: ModelBrief[];\n deviceType?: string;\n}\n\n// Backward-compatible aliases for existing external consumers.\nexport type GroupMeta = ReportMeta;\n\n/*\nReport dump\n*/\nexport interface IReportActionDump {\n sdkVersion: string;\n groupName: string;\n groupDescription?: string;\n modelBriefs: ModelBrief[];\n executions: IExecutionDump[];\n deviceType?: string;\n}\n\n// Backward-compatible aliases for existing external consumers.\nexport type IGroupedActionDump = IReportActionDump;\n\nexport interface ModelBrief {\n /**\n * The intent/category of the model call, for example \"planning\" or \"insight\".\n */\n intent?: string;\n\n /**\n * The model name returned by usage metadata, for example \"gpt-4o\".\n */\n name?: string;\n\n /**\n * Optional human-readable model description, for example \"qwen2.5-vl mode\".\n */\n modelDescription?: string;\n}\n\nexport type InterfaceType =\n | 'puppeteer'\n | 'playwright'\n | 'static'\n | 'chrome-extension-proxy'\n | 'android'\n | string;\n\nexport interface StreamingCodeGenerationOptions {\n /** Whether to enable streaming output */\n stream?: boolean;\n /** Callback function to handle streaming chunks */\n onChunk?: StreamingCallback;\n /** Callback function to handle streaming completion */\n onComplete?: (finalCode: string) => void;\n /** Callback function to handle streaming errors */\n onError?: (error: Error) => void;\n}\n\nexport type StreamingCallback = (chunk: CodeGenerationChunk) => void;\n\nexport interface CodeGenerationChunk {\n /** The incremental content chunk */\n content: string;\n /** The reasoning content */\n reasoning_content: string;\n /** The accumulated content so far */\n accumulated: string;\n /** Whether this is the final chunk */\n isComplete: boolean;\n /** Token usage information if available */\n usage?: AIUsageInfo;\n}\n\nexport interface StreamingAIResponse {\n /** The final accumulated content */\n content: string;\n /** Token usage information */\n usage?: AIUsageInfo;\n /** Whether the response was streamed */\n isStreamed: boolean;\n}\n\nexport interface DeviceAction<TParam = any, TReturn = any> {\n name: string;\n description?: string;\n interfaceAlias?: string;\n paramSchema?: z.ZodType<TParam>;\n call: (\n param: TParam,\n context?: ExecutorContext,\n ) => Promise<TReturn> | TReturn;\n delayBeforeRunner?: number;\n delayAfterRunner?: number;\n /**\n * An example param object for this action.\n * Locate fields with { prompt } may be resolved to internal pixel bboxes when needed.\n */\n sample?: { [K in keyof TParam]?: any };\n}\n\n/**\n * Type utilities for extracting types from DeviceAction definitions\n */\n\n/**\n * Extract parameter type from a DeviceAction\n */\nexport type ActionParam<Action extends DeviceAction<any, any>> =\n Action extends DeviceAction<infer P, any> ? P : never;\n\n/**\n * Extract return type from a DeviceAction\n */\nexport type ActionReturn<Action extends DeviceAction<any, any>> =\n Action extends DeviceAction<any, infer R> ? R : never;\n\n/**\n * Web-specific types\n */\nexport interface WebElementInfo extends BaseElement {\n id: string;\n attributes: {\n nodeType: NodeType;\n [key: string]: string;\n };\n}\n\n/**\n * Agent\n */\n\nexport type CacheConfig = {\n strategy?: 'read-only' | 'read-write' | 'write-only';\n id: string;\n /**\n * Optional cache directory path.\n * When set, cache files are written to this directory instead of\n * `<MIDSCENE_RUN_DIR>/cache`.\n */\n cacheDir?: string;\n};\n\nexport type Cache =\n | false // No read, no write\n | true // Will throw error at runtime - deprecated\n | CacheConfig; // Object configuration (requires explicit id)\n\nexport interface AgentOpt {\n // @deprecated Use `reportFileName` and `cache.id` instead.\n testId?: string;\n // @deprecated\n cacheId?: string; // Keep backward compatibility, but marked as deprecated\n groupName?: string;\n groupDescription?: string;\n /* if auto generate report, default true */\n generateReport?: boolean;\n /* if persist per-execution dump files next to the report, default false */\n persistExecutionDump?: boolean;\n /* if auto print report msg, default true */\n autoPrintReportMsg?: boolean;\n\n /**\n * Use directory-based report format with separate image files.\n *\n * When enabled:\n * - Screenshots are saved as PNG files in a `screenshots/` subdirectory\n * - Report is generated as `index.html` with relative image paths\n * - Reduces memory usage and report file size\n *\n * IMPORTANT: 'html-and-external-assets' reports must be served via HTTP server\n * (e.g., `npx serve ./report-dir`). The file:// protocol will not\n * work due to browser CORS restrictions.\n *\n * @default 'single-html'\n */\n outputFormat?: 'single-html' | 'html-and-external-assets';\n\n onTaskStartTip?: OnTaskStartTip;\n aiActContext?: string;\n aiActionContext?: string;\n /* custom report file name */\n reportFileName?: string;\n reportAttributes?: ReportAttributes;\n modelConfig?: TModelConfig;\n cache?: Cache;\n /**\n * Maximum number of replanning cycles for aiAct.\n * Defaults are resolved by the active model adapter: 20 for standard planning,\n * 40 for UI-TARS, and 100 for Auto-GLM.\n * If omitted, the agent will also read `MIDSCENE_REPLANNING_CYCLE_LIMIT` for backward compatibility.\n */\n replanningCycleLimit?: number;\n\n /**\n * Wait time in milliseconds after each action execution.\n * This allows the UI to settle and stabilize before the next action.\n * Defaults to 300ms when not provided.\n */\n waitAfterAction?: number;\n\n /**\n * When set to true, Midscene will use the target device's formatted local\n * time instead of the runtime system time. The target interface must implement\n * getDeviceLocalTimeString to provide device-local wall-clock time.\n * Default: false\n */\n useDeviceTime?: boolean;\n\n /**\n * Custom screenshot shrink factor to reduce AI token usage.\n * When set, the screenshot will be scaled down by this factor from the physical resolution.\n *\n * Example:\n * - Physical screen width: 3000px, dpr=6\n * - Logical width: 500px\n * - screenshotShrinkFactor: 2\n * - Actual shrunk screenshot width: 3000 / 2 = 1500px\n * - AI analyzes the 1500px screenshot\n * - Coordinates are transformed back to logical (500px) before actions execute\n *\n * Benefits:\n * - Reduces token usage for high-resolution screenshots\n * - Maintains accuracy by scaling coordinates appropriately\n *\n * Must be >= 1 (shrinking only, enlarging is not supported).\n *\n * @default 1 (no shrinking, uses original physical screenshot)\n */\n screenshotShrinkFactor?: number;\n\n /**\n * Custom OpenAI client factory function\n *\n * If provided, this function will be called to create OpenAI client instances\n * for each AI call, allowing you to:\n * - Wrap clients with observability tools (langsmith, langfuse)\n * - Use custom OpenAI-compatible clients\n * - Apply different configurations based on intent\n *\n * @param config - Resolved model configuration\n * @returns OpenAI client instance (original or wrapped)\n *\n * @example\n * ```typescript\n * createOpenAIClient: async (openai, opts) => {\n * // Wrap with langsmith for planning tasks\n * if (opts.baseURL?.includes('planning')) {\n * return wrapOpenAI(openai, { metadata: { task: 'planning' } });\n * }\n *\n * return openai;\n * }\n * ```\n */\n createOpenAIClient?: CreateOpenAIClientFn;\n\n /**\n * Called once per LLM call as soon as its usage is available, with the raw\n * {@link AIUsageInfo} (token counts, model name, intent, request id, etc.).\n *\n * Use this for real-time, per-spec cost observability — e.g. push each call\n * to Langfuse without waiting for the run to finish. For aggregated totals,\n * read `agent.metrics` instead.\n */\n onLLMUsage?: (usage: AIUsageInfo) => void;\n}\n\nexport type TestStatus =\n | 'passed'\n | 'failed'\n | 'timedOut'\n | 'skipped'\n | 'interrupted';\n\nexport interface ReportFileAttributes {\n testDuration: number;\n testStatus: TestStatus;\n testTitle: string;\n testId: string;\n testDescription: string;\n}\n\ntype SkippedReportFileAttributes = Omit<ReportFileAttributes, 'testStatus'> & {\n testStatus: 'skipped';\n};\n\nexport type ReportFileWithAttributes =\n | {\n reportFilePath: string;\n reportAttributes: ReportFileAttributes;\n }\n | {\n reportFilePath?: undefined;\n reportAttributes: SkippedReportFileAttributes;\n };\n"],"names":["UIContext","aiActProgressScope"],"mappings":";;;AAmJO,MAAeA;AAqCtB;AAuVO,MAAMC,qBAAqB"}
1
+ {"version":3,"file":"types.mjs","sources":["../../src/types.ts"],"sourcesContent":["/* eslint-disable @typescript-eslint/no-explicit-any */\n\nimport type { AgentContexts } from '@midscene/shared/agent-tools/agent-context';\nimport type { SerializedError } from '@midscene/shared/agent-tools/error-formatter';\nimport type { NodeType } from '@midscene/shared/constants';\nimport type { CreateOpenAIClientFn, TModelConfig } from '@midscene/shared/env';\nimport type {\n BaseElement,\n LocateResultElement,\n Rect,\n Size,\n} from '@midscene/shared/types';\nimport type { z } from 'zod';\nimport type { TUserPrompt } from './common';\nimport type { ScreenshotItem } from './screenshot-item';\nimport type {\n DetailedLocateParam,\n MidsceneYamlFlowItem,\n ServiceExtractOption,\n} from './yaml';\n\nexport type {\n ElementTreeNode,\n BaseElement,\n Rect,\n Size,\n Point,\n} from '@midscene/shared/types';\nexport type { SerializedError } from '@midscene/shared/agent-tools/error-formatter';\nexport type {\n AgentContextKey,\n AgentContexts,\n AiApiName,\n} from '@midscene/shared/agent-tools/agent-context';\nexport * from './yaml';\n\nexport { ServiceError } from './errors';\nexport {\n ExecutionDump,\n ReportActionDump,\n GroupedActionDump,\n} from './dump/report-action-dump';\n\nexport type AIUsageInfo = Record<string, any> & {\n prompt_tokens: number | undefined;\n completion_tokens: number | undefined;\n total_tokens: number | undefined;\n cached_input: number | undefined;\n time_cost: number | undefined;\n model_name: string | undefined;\n model_description: string | undefined;\n /**\n * Raw top-level `.model` value returned by the model service response.\n */\n response_model_name: string | undefined;\n /**\n * Semantic intent of the model call, such as default, planning, or insight.\n */\n intent: string | undefined;\n /**\n * Config slot where the model config was resolved from. For example, a\n * planning call may use the default slot when no planning model is configured.\n */\n slot: string | undefined;\n request_id: string | undefined;\n};\n\nexport type { LocateResultElement };\n\nexport type AISingleElementResponseByPosition = {\n position?: {\n x: number;\n y: number;\n };\n bbox?: [number, number, number, number];\n reason: string;\n text: string;\n};\n\nexport type LocateResultPoint = [number, number];\nexport type Bbox = [number, number, number, number];\nexport type LocateResultBbox = Bbox;\nexport type PixelBbox = Bbox;\n\nexport interface AIElementLocateResponse {\n bbox?: LocateResultBbox;\n point?: LocateResultPoint;\n error?: string;\n}\n\nexport interface AIDataExtractionResponse<DataDemand> {\n data: DataDemand;\n errors?: string[];\n thought?: string;\n}\n\nexport interface AISectionLocatorResponse {\n bbox?: LocateResultBbox;\n point?: LocateResultPoint;\n references_bbox?: LocateResultBbox[];\n references_point?: LocateResultPoint[];\n error?: string;\n}\n\nexport interface AIAssertionResponse {\n pass: boolean;\n thought: string;\n}\n\nexport interface AIDescribeElementResponse {\n description: string;\n error?: string;\n}\n\nexport interface LocatorValidatorOption {\n centerDistanceThreshold?: number;\n}\n\nexport interface LocateValidatorResult {\n pass: boolean;\n rect: Rect;\n center: [number, number];\n centerDistance?: number;\n includedInRect?: boolean;\n}\n\nexport interface AgentDescribeElementAtPointResult {\n prompt: string;\n deepLocate: boolean;\n deepDescribe: boolean;\n verifyResult?: LocateValidatorResult;\n success: boolean;\n error?: string;\n failureStage?: 'describe' | 'verify';\n}\n\n/**\n * context\n */\n\nexport interface UiNode {\n type: string;\n attrs: Record<string, string | undefined>;\n bounds: Rect;\n children: UiNode[];\n}\n\nexport interface UITreeSnapshot {\n platform: 'android';\n capturedAt: number;\n root: UiNode;\n}\n\nexport abstract class UIContext {\n /**\n * screenshot of the current UI state. which size is shotSize(be shrunk by screenshotShrinkFactor),\n */\n abstract screenshot: ScreenshotItem;\n\n /**\n * Optional sequence of screenshots captured over a short time window, in\n * temporal order (earliest first, latest last). When present with more than\n * one frame, extract/assert flows submit all frames to the model so it can\n * observe transient UI (toasts, carousels, auto-hiding controls). The last\n * frame is the same state as {@link screenshot}.\n */\n abstract screenshotSequence?: ScreenshotItem[];\n\n /**\n * screenshot size after shrinking\n */\n abstract shotSize: Size;\n\n /**\n * The ratio for converting shrunk screenshot coordinates to logical coordinates.\n *\n * Example:\n * - Physical screen width: 3000px, dpr=6\n * - Logical width: 500px\n * - User-defined screenshotShrinkFactor: 2\n * - Actual shrunk screenshot width: 3000 / 2 = 1500px\n * - shrunkShotToLogicalRatio: dpr / screenshotShrinkFactor = 6 / 2 = 3\n * - To map back to logical coordinates: 1500 / shrunkShotToLogicalRatio = 500px\n */\n abstract shrunkShotToLogicalRatio: number;\n\n abstract _isFrozen?: boolean;\n\n // @deprecated - backward compatibility for aiLocate\n abstract deprecatedDpr?: number;\n}\n\nexport type EnsureObject<T> = { [K in keyof T]: any };\n\nexport type ServiceAction = 'locate' | 'extract' | 'assert' | 'describe';\n\nexport type ServiceExtractParam = string | Record<string, string>;\n\nexport type ElementCacheFeature = Record<string, unknown>;\n\nexport interface LocateResult {\n element: LocateResultElement | null;\n rect?: Rect;\n}\n\nexport type ThinkingLevel = 'off' | 'medium' | 'high';\n\nexport type AiActEffort = 'fast' | 'balance' | 'deepThink';\n\nexport type DeepThinkOption = 'unset' | true | false;\n\nexport interface ServiceTaskInfo {\n durationMs: number;\n formatResponse?: unknown;\n /**\n * Adapter-extracted content used by Midscene for parsing. This is not the\n * full provider response or choices[0].message.\n */\n rawResponse?: unknown;\n rawChoiceMessage?: unknown;\n usage?: AIUsageInfo;\n searchArea?: Rect;\n /**\n * Adapter-extracted content from the search-area model call. This is not the\n * full provider response or choices[0].message.\n */\n searchAreaRawResponse?: string;\n searchAreaRawChoiceMessage?: unknown;\n searchAreaUsage?: AIUsageInfo;\n reasoning_content?: string;\n}\n\nexport interface DumpMeta {\n logTime: number;\n}\n\nexport type ReportAttributes = Record<\n string,\n string | number | boolean | null | undefined\n>;\n\nexport interface ReportDumpWithAttributes {\n dumpString: string;\n attributes?: ReportAttributes;\n}\n\nexport interface ServiceDump extends DumpMeta {\n type: 'locate' | 'extract' | 'assert';\n logId: string;\n userQuery: {\n element?: TUserPrompt;\n dataDemand?: ServiceExtractParam;\n assertion?: TUserPrompt;\n };\n matchedElement?: LocateResultElement[];\n matchedRect?: Rect;\n deepLocate?: boolean;\n data: any;\n assertionPass?: boolean;\n assertionThought?: string;\n taskInfo: ServiceTaskInfo;\n error?: string;\n output?: any;\n}\n\nexport type PartialServiceDumpFromSDK = Omit<\n ServiceDump,\n 'logTime' | 'logId' | 'model_name'\n>;\n\nexport interface ServiceResultBase {\n dump: ServiceDump;\n}\n\nexport type LocateResultWithDump = LocateResult & ServiceResultBase;\n\nexport interface ServiceExtractResult<T> extends ServiceResultBase {\n data: T;\n thought?: string;\n usage?: AIUsageInfo;\n reasoning_content?: string;\n}\n\n// intermediate variables to optimize the return value by AI\nexport interface LiteUISection {\n name: string;\n description: string;\n sectionCharacteristics: string;\n textIds: string[];\n}\n\nexport type ElementById = (id: string) => BaseElement | null;\n\nexport type ServiceAssertionResponse = AIAssertionResponse & {\n usage?: AIUsageInfo;\n};\n\n/**\n * agent\n */\n\nexport type OnTaskStartTip = (tip: string) => Promise<void> | void;\n\nexport interface AgentWaitForOpt extends ServiceExtractOption {\n checkIntervalMs?: number;\n timeoutMs?: number;\n}\n\nexport interface AgentAssertOpt {\n keepRawResponse?: boolean;\n /**\n * Additional facts, decision rules, constraints, or output requirements for\n * this assertion. It overrides `contexts.aiAssert` and `contexts.default`;\n * `''` disables inherited user context for this call.\n */\n context?: string;\n abortSignal?: AbortSignal;\n}\n\nexport interface AgentAssertResult {\n pass: boolean;\n thought?: string;\n message?: string;\n}\n\nexport type QueryOptions = ServiceExtractOption;\nexport type AssertOptions = AgentAssertOpt & ServiceExtractOption;\n\n/** Options for fixed observations, which never read the live DOM. */\nexport type ObservationQueryOptions = Omit<QueryOptions, 'domIncluded'> & {\n domIncluded?: never;\n};\n\n/** Assertion options for fixed observations, which never read the live DOM. */\nexport type ObservationAssertOptions = Omit<AssertOptions, 'domIncluded'> & {\n domIncluded?: never;\n};\n\n/** Read-only AI operations supported by both live Agents and UI observations. */\nexport interface InsightAPI<\n QueryOpt extends QueryOptions = QueryOptions,\n AssertOpt extends AssertOptions = AssertOptions,\n> {\n aiQuery<ReturnType = any>(\n demand: ServiceExtractParam,\n options?: QueryOpt,\n ): Promise<ReturnType>;\n aiBoolean(prompt: TUserPrompt, options?: QueryOpt): Promise<boolean>;\n aiNumber(prompt: TUserPrompt, options?: QueryOpt): Promise<number>;\n aiString(prompt: TUserPrompt, options?: QueryOpt): Promise<string>;\n aiAsk(prompt: TUserPrompt, options?: QueryOpt): Promise<string>;\n aiAssert(\n assertion: TUserPrompt,\n message?: string,\n options?: AssertOpt,\n ): Promise<AgentAssertResult | undefined>;\n}\n\n/**\n * planning\n *\n */\n\ntype PlanningActionBase = {\n thought?: string;\n log?: string; // a brief preamble to the user explaining what you’re about to do\n type: string;\n};\n\nexport type PlanningAction<ParamType = undefined> = PlanningActionBase &\n ([ParamType] extends [undefined] ? { param?: any } : { param: ParamType });\n\nexport type SubGoalStatus = 'pending' | 'running' | 'finished';\n\nexport interface SubGoal {\n index: number;\n status: SubGoalStatus;\n description: string;\n logs?: string[];\n}\n\nexport interface RawResponsePlanningAIResponse {\n action: PlanningAction | null;\n thought?: string;\n log: string;\n memory?: string;\n error?: string;\n finalizeMessage?: string;\n finalizeSuccess?: boolean;\n updateSubGoals?: SubGoal[];\n markFinishedIndexes?: number[];\n}\n\nexport interface PlanningAIResponse\n extends Omit<RawResponsePlanningAIResponse, 'action'> {\n actions?: PlanningAction[];\n usage?: AIUsageInfo;\n /**\n * Adapter-extracted content used by Midscene for parsing. This is not the\n * full provider response or choices[0].message.\n */\n rawResponse?: string;\n rawChoiceMessage?: unknown;\n yamlFlow?: MidsceneYamlFlowItem[];\n yamlString?: string;\n error?: string;\n reasoning_content?: string;\n shouldContinuePlanning: boolean;\n output?: string; // Output message from <complete> tag (same as finalizeMessage)\n}\n\nexport interface PlanningActionParamSleep {\n timeMs: number;\n}\n\nexport interface PlanningActionParamError {\n thought: string;\n}\n\nexport type PlanningActionParamWaitFor = AgentWaitForOpt & {};\n\nexport interface LongPressParam {\n duration?: number;\n}\n\nexport interface PullParam {\n direction: 'up' | 'down';\n distance?: number;\n duration?: number;\n}\n/**\n * misc\n */\n\nexport interface Color {\n name: string;\n hex: string;\n}\n\nexport interface BaseAgentParserOpt {\n selector?: string;\n}\n// eslint-disable-next-line @typescript-eslint/no-empty-interface\nexport interface PuppeteerParserOpt extends BaseAgentParserOpt {}\n\n// eslint-disable-next-line @typescript-eslint/no-empty-interface\nexport interface PlaywrightParserOpt extends BaseAgentParserOpt {}\n\n/*\naction\n*/\nexport interface ExecutionTaskProgressOptions {\n onTaskStart?: (task: ExecutionTask) => Promise<void> | void;\n}\n\n/**\n * Generic agent progress bus.\n *\n * Progress notifications are a single, generic stream the agent broadcasts as\n * it works. Each event is a thin envelope: a `scope` naming the producer, a\n * `phase` within that producer's lifecycle, a monotonic `sequence`, and a\n * structured, presentation-free `data` payload. The bus knows nothing about any\n * particular producer's payload - consumers narrow by `scope`. `aiAct` is the\n * first producer (\"pilot\") on this bus; others (queries, waits, ...) can be\n * added without touching the bus, the listener API, or the renderer core.\n */\nexport interface AgentProgressEvent<\n TScope extends string = string,\n TData = unknown,\n TPhase extends string = string,\n> {\n scope: TScope;\n phase: TPhase;\n sequence: number;\n data: TData;\n}\n\nexport type AgentProgressListener<\n TScope extends string = string,\n TData = unknown,\n TPhase extends string = string,\n> = (event: AgentProgressEvent<TScope, TData, TPhase>) => Promise<void> | void;\n\n// --- aiAct: the first producer on the generic progress bus ---\n\nexport type AiActProgressPhase =\n | 'start'\n | 'plan_thinking'\n | 'plan_planned'\n | 'plan_action'\n | 'plan_failed'\n | 'action_running'\n | 'action_done'\n | 'action_failed'\n | 'complete'\n | 'failed';\n\nexport interface AiActProgressAction {\n name: string;\n target?: string;\n point?: [number, number];\n bbox?: [number, number, number, number];\n /**\n * Structured, compacted summary of the action params for actions that are\n * not described by a point/bbox (e.g. `Sleep` -> `{ timeMs }`). This is data,\n * never a pre-formatted display string; consumers decide how to render it.\n */\n param?: unknown;\n}\n\n/**\n * Structured payload carried by aiAct progress events. The producer only\n * reports *what happened* as data: the action involved, the raw text the model\n * produced, timings and errors. It never assembles human-readable log lines or\n * truncates strings for display - that belongs to whichever layer consumes the\n * stream (e.g. the CLI verbose renderer).\n */\nexport interface AiActProgressData {\n /** Original user instruction, present on the `start` phase. */\n prompt?: string;\n planIndex?: number;\n planLimit?: number;\n /** Latest screenshot, present on `plan_thinking`. */\n screenshot?: ScreenshotItem;\n /** Structured action descriptor, present on the `*action*` phases. */\n action?: AiActProgressAction;\n /**\n * Raw, untruncated semantic text produced by the model. Consumers choose\n * which field to surface and how to format/truncate it.\n */\n thought?: string;\n log?: string;\n output?: string;\n /** Wall-clock cost of an action, present on `action_done`/`action_failed`. */\n durationMs?: number;\n error?: string;\n}\n\nexport const aiActProgressScope = 'aiAct';\n\nexport interface ExecutionRecorderItem {\n type: 'screenshot';\n ts: number;\n screenshot?: ScreenshotItem;\n description?: string;\n timing?: string;\n}\n\nexport interface RecordToReportScreenshot {\n /**\n * PNG/JPEG data URI, or raw PNG base64 body.\n */\n base64: string;\n description?: string;\n}\n\nexport interface RecordToReportOptions {\n content?: string;\n /**\n * @deprecated Use `screenshots: [{ base64 }]` instead.\n */\n screenshotBase64?: string;\n /**\n * Custom screenshots to display under a single report entry.\n */\n screenshots?: RecordToReportScreenshot[];\n}\n\nexport type ExecutionTaskType = 'Planning' | 'Insight' | 'Action Space' | 'Log';\n\nexport interface ExecutorContext {\n task: ExecutionTask;\n element?: LocateResultElement | null;\n uiContext?: UIContext;\n}\n\nexport interface ExecutionTaskApply<\n Type extends ExecutionTaskType = any,\n TaskParam = any,\n TaskOutput = any,\n TaskLog = any,\n> {\n type: Type;\n subType?: string;\n param?: TaskParam;\n thought?: string;\n uiContext?: UIContext;\n executor: (\n context: ExecutorContext,\n ) => // biome-ignore lint/suspicious/noConfusingVoidType: void is intentionally allowed as some executors may not return a value\n | Promise<ExecutionTaskReturn<TaskOutput, TaskLog> | undefined | void>\n | undefined\n | void;\n}\n\nexport interface ExecutionTaskHitBy {\n from: string;\n context: Record<string, any>;\n}\n\nexport interface ExecutionTaskReturn<TaskOutput = unknown, TaskLog = unknown> {\n output?: TaskOutput;\n log?: TaskLog;\n recorder?: ExecutionRecorderItem[];\n hitBy?: ExecutionTaskHitBy;\n}\n\nexport type ExecutionTask<\n E extends ExecutionTaskApply<any, any, any> = ExecutionTaskApply<\n any,\n any,\n any\n >,\n> = E &\n ExecutionTaskReturn<\n E extends ExecutionTaskApply<any, any, infer TaskOutput, any>\n ? TaskOutput\n : unknown,\n E extends ExecutionTaskApply<any, any, any, infer TaskLog>\n ? TaskLog\n : unknown\n > & {\n taskId: string;\n status: 'pending' | 'running' | 'finished' | 'failed' | 'cancelled';\n /**\n * Optional feedback produced by a task for the next planning round.\n * This is execution metadata, not part of the action return value.\n */\n planningFeedback?: string;\n /**\n * A bounded diagnostic DTO created when the task executor throws. Arbitrary\n * upstream payloads are intentionally omitted; use this field for structured\n * diagnostics or errorMessage/errorStack for the common display path.\n */\n error?: SerializedError;\n errorMessage?: string;\n errorStack?: string;\n timing?: {\n start: number;\n getUiContextStart?: number;\n getUiContextEnd?: number;\n callAiStart?: number;\n callAiEnd?: number;\n beforeInvokeActionHookStart?: number;\n beforeInvokeActionHookEnd?: number;\n callActionStart?: number;\n callActionEnd?: number;\n afterInvokeActionHookStart?: number;\n afterInvokeActionHookEnd?: number;\n captureAfterCallingSnapshotStart?: number;\n captureAfterCallingSnapshotEnd?: number;\n end?: number;\n cost?: number;\n };\n usage?: AIUsageInfo;\n /**\n * Pixel rect of the deepLocate first-stage search area in screenshot\n * coordinates. Used by reports to explain the crop/zoom area that the\n * final locate ran against.\n */\n searchArea?: Rect;\n searchAreaUsage?: AIUsageInfo;\n reasoning_content?: string;\n };\n\nexport interface IExecutionDump extends DumpMeta {\n /** Stable unique identifier for this execution run */\n id?: string;\n name: string;\n description?: string;\n tasks: ExecutionTask[];\n aiActContext?: string;\n}\n\n/*\ntask - service-locate\n*/\nexport interface ExecutionTaskInsightLocateOutput {\n element: LocateResultElement | null;\n}\n\nexport type ExecutionTaskInsightDump = ServiceDump;\n\nexport type ExecutionTaskInsightLocateApply = ExecutionTaskApply<\n 'Insight',\n DetailedLocateParam,\n ExecutionTaskInsightLocateOutput,\n ExecutionTaskInsightDump\n>;\n\nexport type ExecutionTaskInsightLocate =\n ExecutionTask<ExecutionTaskInsightLocateApply>;\n\n/*\ntask - service-query\n*/\nexport interface ExecutionTaskInsightQueryParam {\n dataDemand: ServiceExtractParam;\n domIncluded?: boolean | 'visible-only';\n context?: string;\n}\n\nexport interface ExecutionTaskInsightQueryOutput {\n data: any;\n}\n\nexport type ExecutionTaskInsightQueryApply = ExecutionTaskApply<\n 'Insight',\n ExecutionTaskInsightQueryParam,\n any,\n ExecutionTaskInsightDump\n>;\n\nexport type ExecutionTaskInsightQuery =\n ExecutionTask<ExecutionTaskInsightQueryApply>;\n\n/*\ntask - assertion\n*/\nexport interface ExecutionTaskInsightAssertionParam {\n assertion: string;\n}\n\nexport type ExecutionTaskInsightAssertionApply = ExecutionTaskApply<\n 'Insight',\n ExecutionTaskInsightAssertionParam,\n ServiceAssertionResponse,\n ExecutionTaskInsightDump\n>;\n\nexport type ExecutionTaskInsightAssertion =\n ExecutionTask<ExecutionTaskInsightAssertionApply>;\n\n/*\ntask - action (i.e. interact) \n*/\nexport type ExecutionTaskActionApply<ActionParam = any> = ExecutionTaskApply<\n 'Action Space',\n ActionParam,\n void,\n void\n>;\n\nexport type ExecutionTaskAction = ExecutionTask<ExecutionTaskActionApply>;\n\n/*\ntask - Log\n*/\n\nexport type ExecutionTaskLogApply<\n LogParam = {\n content: string;\n },\n> = ExecutionTaskApply<'Log', LogParam, void, void>;\n\nexport type ExecutionTaskLog = ExecutionTask<ExecutionTaskLogApply>;\n\n/*\ntask - planning\n*/\n\nexport interface ExecutionTaskPlanningParam {\n userInstruction: TUserPrompt;\n userInstructionDisplay?: string;\n replanningCycleLimit?: number;\n aiActContext?: string;\n imagesIncludeCount?: number;\n effort?: AiActEffort;\n subGoalStatus?: string;\n memoriesStatus?: string;\n}\n\nexport type ExecutionTaskPlanningApply = ExecutionTaskApply<\n 'Planning',\n ExecutionTaskPlanningParam,\n PlanningAIResponse\n>;\n\nexport type ExecutionTaskPlanning = ExecutionTask<ExecutionTaskPlanningApply>;\n\n/*\ntask - planning-locate\n*/\nexport interface ExecutionTaskPlanningLocateOutput {\n element: LocateResultElement | null;\n}\n\nexport type ExecutionTaskPlanningDump = ServiceDump;\n\nexport type ExecutionTaskPlanningLocateApply = ExecutionTaskApply<\n 'Planning',\n DetailedLocateParam,\n ExecutionTaskPlanningLocateOutput,\n ExecutionTaskPlanningDump\n>;\n\nexport type ExecutionTaskPlanningLocate =\n ExecutionTask<ExecutionTaskPlanningLocateApply>;\n\n/*\nHow a report file stores screenshots:\n- `inline`: base64 image script tags embedded in the single HTML file\n- `directory`: external PNG files under a sibling `screenshots/` dir\n*/\nexport type ScreenshotMode = 'inline' | 'directory';\n\n/*\nReport metadata - extracted from ReportActionDump for per-execution writes\n*/\nexport interface ReportMeta {\n groupName: string;\n groupDescription?: string;\n sdkVersion: string;\n modelBriefs: ModelBrief[];\n deviceType?: string;\n}\n\n// Backward-compatible aliases for existing external consumers.\nexport type GroupMeta = ReportMeta;\n\n/*\nReport dump\n*/\nexport interface IReportActionDump {\n sdkVersion: string;\n groupName: string;\n groupDescription?: string;\n modelBriefs: ModelBrief[];\n executions: IExecutionDump[];\n deviceType?: string;\n}\n\n// Backward-compatible aliases for existing external consumers.\nexport type IGroupedActionDump = IReportActionDump;\n\nexport interface ModelBrief {\n /**\n * The intent/category of the model call, for example \"planning\" or \"insight\".\n */\n intent?: string;\n\n /**\n * The model name returned by usage metadata, for example \"gpt-4o\".\n */\n name?: string;\n\n /**\n * Optional human-readable model description, for example \"qwen2.5-vl mode\".\n */\n modelDescription?: string;\n}\n\nexport type InterfaceType =\n | 'puppeteer'\n | 'playwright'\n | 'static'\n | 'chrome-extension-proxy'\n | 'android'\n | string;\n\nexport interface StreamingCodeGenerationOptions {\n /** Whether to enable streaming output */\n stream?: boolean;\n /** Callback function to handle streaming chunks */\n onChunk?: StreamingCallback;\n /** Callback function to handle streaming completion */\n onComplete?: (finalCode: string) => void;\n /** Callback function to handle streaming errors */\n onError?: (error: Error) => void;\n}\n\nexport type StreamingCallback = (chunk: CodeGenerationChunk) => void;\n\nexport interface CodeGenerationChunk {\n /** The incremental content chunk */\n content: string;\n /** The reasoning content */\n reasoning_content: string;\n /** The accumulated content so far */\n accumulated: string;\n /** Whether this is the final chunk */\n isComplete: boolean;\n /** Token usage information if available */\n usage?: AIUsageInfo;\n}\n\nexport interface StreamingAIResponse {\n /** The final accumulated content */\n content: string;\n /** Token usage information */\n usage?: AIUsageInfo;\n /** Whether the response was streamed */\n isStreamed: boolean;\n}\n\nexport interface DeviceAction<TParam = any, TReturn = any> {\n name: string;\n description?: string;\n interfaceAlias?: string;\n paramSchema?: z.ZodType<TParam>;\n call: (\n param: TParam,\n context?: ExecutorContext,\n ) => Promise<TReturn> | TReturn;\n delayBeforeRunner?: number;\n delayAfterRunner?: number;\n /**\n * An example param object for this action.\n * Locate fields with { prompt } may be resolved to internal pixel bboxes when needed.\n */\n sample?: { [K in keyof TParam]?: any };\n}\n\n/**\n * Type utilities for extracting types from DeviceAction definitions\n */\n\n/**\n * Extract parameter type from a DeviceAction\n */\nexport type ActionParam<Action extends DeviceAction<any, any>> =\n Action extends DeviceAction<infer P, any> ? P : never;\n\n/**\n * Extract return type from a DeviceAction\n */\nexport type ActionReturn<Action extends DeviceAction<any, any>> =\n Action extends DeviceAction<any, infer R> ? R : never;\n\n/**\n * Web-specific types\n */\nexport interface WebElementInfo extends BaseElement {\n id: string;\n attributes: {\n nodeType: NodeType;\n [key: string]: string;\n };\n}\n\n/**\n * Agent\n */\n\nexport type CacheConfig = {\n strategy?: 'read-only' | 'read-write' | 'write-only';\n id: string;\n /**\n * Optional cache directory path.\n * When set, cache files are written to this directory instead of\n * `<MIDSCENE_RUN_DIR>/cache`.\n */\n cacheDir?: string;\n};\n\nexport type Cache =\n | false // No read, no write\n | true // Will throw error at runtime - deprecated\n | CacheConfig; // Object configuration (requires explicit id)\n\nexport interface AgentOpt {\n // @deprecated Use `reportFileName` and `cache.id` instead.\n testId?: string;\n // @deprecated\n cacheId?: string; // Keep backward compatibility, but marked as deprecated\n groupName?: string;\n groupDescription?: string;\n /* if auto generate report, default true */\n generateReport?: boolean;\n /* if persist per-execution dump files next to the report, default false */\n persistExecutionDump?: boolean;\n /* if auto print report msg, default true */\n autoPrintReportMsg?: boolean;\n\n /**\n * Use directory-based report format with separate image files.\n *\n * When enabled:\n * - Screenshots are saved as PNG files in a `screenshots/` subdirectory\n * - Report is generated as `index.html` with relative image paths\n * - Reduces memory usage and report file size\n *\n * IMPORTANT: 'html-and-external-assets' reports must be served via HTTP server\n * (e.g., `npx serve ./report-dir`). The file:// protocol will not\n * work due to browser CORS restrictions.\n *\n * @default 'single-html'\n */\n outputFormat?: 'single-html' | 'html-and-external-assets';\n\n onTaskStartTip?: OnTaskStartTip;\n /**\n * Agent-level AI guidance containing business facts, rules, constraints, or\n * output requirements. `contexts.default` is a shared fallback used only\n * when neither the call nor the matching API key provides a context.\n *\n * A per-call `options.context` overrides the matching API context, which\n * overrides `contexts.default`. An empty string explicitly clears inherited\n * user context for that scope. These layers are not implicitly concatenated.\n */\n contexts?: AgentContexts;\n /**\n * Compatibility alias for `contexts.aiAct`. `contexts.aiAct` takes\n * precedence when both are provided.\n * @deprecated Use `contexts.aiAct` instead.\n */\n aiActContext?: string;\n /**\n * Older compatibility alias for `contexts.aiAct`.\n * @deprecated Use `contexts.aiAct` instead.\n */\n aiActionContext?: string;\n /* custom report file name */\n reportFileName?: string;\n reportAttributes?: ReportAttributes;\n modelConfig?: TModelConfig;\n cache?: Cache;\n /**\n * Maximum number of replanning cycles for aiAct.\n * Defaults are resolved by the active model adapter: 20 for standard planning,\n * 40 for UI-TARS, and 100 for Auto-GLM.\n * If omitted, the agent will also read `MIDSCENE_REPLANNING_CYCLE_LIMIT` for backward compatibility.\n */\n replanningCycleLimit?: number;\n\n /**\n * Wait time in milliseconds after each action execution.\n * This allows the UI to settle and stabilize before the next action.\n * Defaults to 300ms when not provided.\n */\n waitAfterAction?: number;\n\n /**\n * When set to true, Midscene will use the target device's formatted local\n * time instead of the runtime system time. The target interface must implement\n * getDeviceLocalTimeString to provide device-local wall-clock time.\n * Default: false\n */\n useDeviceTime?: boolean;\n\n /**\n * Custom screenshot shrink factor to reduce AI token usage.\n * When set, the screenshot will be scaled down by this factor from the physical resolution.\n *\n * Example:\n * - Physical screen width: 3000px, dpr=6\n * - Logical width: 500px\n * - screenshotShrinkFactor: 2\n * - Actual shrunk screenshot width: 3000 / 2 = 1500px\n * - AI analyzes the 1500px screenshot\n * - Coordinates are transformed back to logical (500px) before actions execute\n *\n * Benefits:\n * - Reduces token usage for high-resolution screenshots\n * - Maintains accuracy by scaling coordinates appropriately\n *\n * Must be >= 1 (shrinking only, enlarging is not supported).\n *\n * @default 1 (no shrinking, uses original physical screenshot)\n */\n screenshotShrinkFactor?: number;\n\n /**\n * Custom OpenAI client factory function\n *\n * If provided, this function will be called to create OpenAI client instances\n * for each AI call, allowing you to:\n * - Wrap clients with observability tools (langsmith, langfuse)\n * - Use custom OpenAI-compatible clients\n * - Apply different configurations based on intent\n *\n * @param config - Resolved model configuration\n * @returns OpenAI client instance (original or wrapped)\n *\n * @example\n * ```typescript\n * createOpenAIClient: async (openai, opts) => {\n * // Wrap with langsmith for planning tasks\n * if (opts.baseURL?.includes('planning')) {\n * return wrapOpenAI(openai, { metadata: { task: 'planning' } });\n * }\n *\n * return openai;\n * }\n * ```\n */\n createOpenAIClient?: CreateOpenAIClientFn;\n\n /**\n * Called once per LLM call as soon as its usage is available, with the raw\n * {@link AIUsageInfo} (token counts, model name, intent, request id, etc.).\n *\n * Use this for real-time, per-spec cost observability — e.g. push each call\n * to Langfuse without waiting for the run to finish. For aggregated totals,\n * read `agent.metrics` instead.\n */\n onLLMUsage?: (usage: AIUsageInfo) => void;\n}\n\nexport type TestStatus =\n | 'passed'\n | 'failed'\n | 'timedOut'\n | 'skipped'\n | 'interrupted';\n\nexport interface ReportFileAttributes {\n testDuration: number;\n testStatus: TestStatus;\n testTitle: string;\n testId: string;\n testDescription: string;\n}\n\ntype SkippedReportFileAttributes = Omit<ReportFileAttributes, 'testStatus'> & {\n testStatus: 'skipped';\n};\n\nexport type ReportFileWithAttributes =\n | {\n reportFilePath: string;\n reportAttributes: ReportFileAttributes;\n }\n | {\n reportFilePath?: undefined;\n reportAttributes: SkippedReportFileAttributes;\n };\n"],"names":["UIContext","aiActProgressScope"],"mappings":";;;AAyJO,MAAeA;AAqCtB;AA4VO,MAAMC,qBAAqB"}
package/dist/es/utils.mjs CHANGED
@@ -184,7 +184,7 @@ function stringifyDumpData(data, indents) {
184
184
  return JSON.stringify(data, replacerForPageObject, indents);
185
185
  }
186
186
  function getVersion() {
187
- return "1.12.3";
187
+ return "1.12.4-beta-20260902093735.0";
188
188
  }
189
189
  function debugLog(...message) {
190
190
  const debugMode = process.env[MIDSCENE_DEBUG_MODE];
@@ -446,11 +446,6 @@ class ScriptPlayer {
446
446
  this.failedReportExecutionInCurrentStep = false;
447
447
  this.scriptPath = scriptPath;
448
448
  this.result = {};
449
- const resolvedAiActContext = script.agent?.aiActContext ?? script.agent?.aiActionContext;
450
- if (void 0 !== resolvedAiActContext && script.agent) {
451
- if (void 0 === script.agent.aiActContext && void 0 !== script.agent.aiActionContext) console.warn('agent.aiActionContext is deprecated, please use agent.aiActContext instead. The legacy name is still accepted for backward compatibility.');
452
- script.agent.aiActContext = resolvedAiActContext;
453
- }
454
449
  this.target = script.target || script.web || script.android || script.ios || script.computer || script.config;
455
450
  if (ifInBrowser || ifInWorker) {
456
451
  this.output = void 0;
@@ -1 +1 @@
1
- {"version":3,"file":"yaml/player.mjs","sources":["../../../src/yaml/player.ts"],"sourcesContent":["import { existsSync, mkdirSync, writeFileSync } from 'node:fs';\nimport { basename, dirname, join, resolve } from 'node:path';\nimport { assert, ifInBrowser, ifInWorker } from '@midscene/shared/utils';\nimport { type ZodTypeAny, z } from 'zod';\n\n// previous defined yaml flow, as a helper\ninterface MidsceneYamlFlowItemAIInput extends LocateOption {\n // previous version\n // aiInput: string; // value to input\n // locate: TUserPrompt; // where to input\n aiInput: TUserPrompt | undefined; // where to input\n value: string | number; // value to input\n mode?: 'replace' | 'clear' | 'typeOnly';\n autoDismissKeyboard?: boolean;\n keyboardTypeDelay?: number;\n inputStrategy?: InputStrategy;\n}\n\ninterface MidsceneYamlFlowItemAIKeyboardPress extends LocateOption {\n // previous version\n // aiKeyboardPress: string;\n // locate?: TUserPrompt; // where to press, optional\n aiKeyboardPress: TUserPrompt | undefined; // where to press\n keyName: string; // key to press\n}\n\ninterface MidsceneYamlFlowItemAIScroll extends LocateOption, ScrollParam {\n // previous version\n // aiScroll: null;\n // locate?: TUserPrompt; // which area to scroll, optional\n aiScroll: TUserPrompt | undefined; // which area to scroll\n}\n\ntype RuntimeYamlFlowItem =\n | MidsceneYamlFlowItem\n | MidsceneYamlFlowItemAIInput\n | MidsceneYamlFlowItemAIKeyboardPress\n | MidsceneYamlFlowItemAIScroll;\n\nimport type { Agent } from '@/agent/agent';\nimport type { TUserPrompt } from '@/common';\nimport type { InputStrategy } from '@/device';\nimport type {\n DeviceAction,\n FreeFn,\n LocateOption,\n MidsceneYamlFlowItem,\n MidsceneYamlFlowItemAIAction,\n MidsceneYamlFlowItemAIAssert,\n MidsceneYamlFlowItemAIWaitFor,\n MidsceneYamlFlowItemEvaluateJavaScript,\n MidsceneYamlFlowItemLogScreenshot,\n MidsceneYamlFlowItemRunGherkinScenario,\n MidsceneYamlFlowItemSleep,\n MidsceneYamlScript,\n MidsceneYamlScriptEnv,\n ScriptPlayerStatusValue,\n ScriptPlayerTaskStatus,\n ScrollParam,\n} from '@/types';\nimport { getMidsceneRunSubDir } from '@midscene/shared/common';\nimport { getDebug } from '@midscene/shared/logger';\nimport { runFreeFnCleanup } from './cleanup';\nimport {\n buildDetailedLocateParam,\n buildDetailedLocateParamAndRestParams,\n} from './utils';\n\nconst debug = getDebug('yaml-player');\n\nconst aiTaskHandlerMap = {\n aiQuery: 'aiQuery',\n aiNumber: 'aiNumber',\n aiString: 'aiString',\n aiBoolean: 'aiBoolean',\n aiAsk: 'aiAsk',\n aiLocate: 'aiLocate',\n} as const;\n\ntype AISimpleTaskKey = keyof typeof aiTaskHandlerMap;\n\nconst isStringParamSchema = (schema?: ZodTypeAny): boolean => {\n if (!schema) {\n return false;\n }\n\n const schemaDef = (schema as any)?._def;\n if (!schemaDef?.typeName) {\n return false;\n }\n\n switch (schemaDef.typeName) {\n case z.ZodFirstPartyTypeKind.ZodString:\n case z.ZodFirstPartyTypeKind.ZodEnum:\n case z.ZodFirstPartyTypeKind.ZodNativeEnum:\n return true;\n case z.ZodFirstPartyTypeKind.ZodLiteral:\n return typeof schemaDef.value === 'string';\n case z.ZodFirstPartyTypeKind.ZodOptional:\n case z.ZodFirstPartyTypeKind.ZodNullable:\n case z.ZodFirstPartyTypeKind.ZodDefault:\n return isStringParamSchema(schemaDef.innerType);\n case z.ZodFirstPartyTypeKind.ZodEffects:\n return isStringParamSchema(schemaDef.schema);\n case z.ZodFirstPartyTypeKind.ZodPipeline:\n return isStringParamSchema(schemaDef.out);\n case z.ZodFirstPartyTypeKind.ZodUnion: {\n const options = schemaDef.options as ZodTypeAny[] | undefined;\n return Array.isArray(options)\n ? options.every((option) => isStringParamSchema(option))\n : false;\n }\n default:\n return false;\n }\n};\n\nconst buildShortcutActionParam = (\n actionName: string,\n interfaceAlias: string | undefined,\n value: string,\n) => {\n if (actionName === 'Launch' || interfaceAlias === 'launch') {\n return { uri: value };\n }\n\n if (actionName === 'Terminate' || interfaceAlias === 'terminate') {\n return { uri: value };\n }\n\n if (\n actionName === 'RunAdbShell' ||\n interfaceAlias === 'runAdbShell' ||\n actionName === 'RunHdcShell' ||\n interfaceAlias === 'runHdcShell'\n ) {\n return { command: value };\n }\n\n return undefined;\n};\nexport class ScriptPlayer<T extends MidsceneYamlScriptEnv> {\n public currentTaskIndex?: number;\n public taskStatusList: ScriptPlayerTaskStatus[] = [];\n public status: ScriptPlayerStatusValue = 'init';\n public reportFile?: string | null;\n public result: Record<string, any>;\n private unnamedResultIndex = 0;\n public output?: string | null;\n public unstableLogContent?: string | null;\n public errorInSetup?: Error;\n private interfaceAgent: Agent | null = null;\n public agentStatusTip?: string;\n public target?: MidsceneYamlScriptEnv;\n private actionSpace: DeviceAction[] = [];\n private scriptPath?: string;\n private failedReportExecutionInCurrentStep = false;\n constructor(\n private script: MidsceneYamlScript,\n private setupAgent: (platform: T) => Promise<{\n agent: Agent;\n freeFn: FreeFn[];\n }>,\n public onTaskStatusChange?: (taskStatus: ScriptPlayerTaskStatus) => void,\n scriptPath?: string,\n ) {\n this.scriptPath = scriptPath;\n this.result = {};\n const resolvedAiActContext =\n script.agent?.aiActContext ?? script.agent?.aiActionContext;\n\n if (resolvedAiActContext !== undefined && script.agent) {\n if (\n script.agent.aiActContext === undefined &&\n script.agent.aiActionContext !== undefined\n ) {\n console.warn(\n 'agent.aiActionContext is deprecated, please use agent.aiActContext instead. The legacy name is still accepted for backward compatibility.',\n );\n }\n\n script.agent.aiActContext = resolvedAiActContext;\n }\n\n this.target =\n script.target ||\n script.web ||\n script.android ||\n script.ios ||\n script.computer ||\n script.config;\n\n if (ifInBrowser || ifInWorker) {\n this.output = undefined;\n debug('output is undefined in browser or worker');\n } else if (this.target?.output) {\n this.output = resolve(process.cwd(), this.target.output);\n debug('setting output by config.output', this.output);\n } else {\n const scriptName = this.scriptPath\n ? basename(this.scriptPath, '.yaml').replace(/\\.(ya?ml)$/i, '')\n : 'script';\n this.output = join(\n getMidsceneRunSubDir('output'),\n `${scriptName}-${Date.now()}.json`,\n );\n debug('setting output by script path', this.output);\n }\n\n if (ifInBrowser || ifInWorker) {\n this.unstableLogContent = undefined;\n } else if (typeof this.target?.unstableLogContent === 'string') {\n this.unstableLogContent = resolve(\n process.cwd(),\n this.target.unstableLogContent,\n );\n } else if (this.target?.unstableLogContent === true) {\n this.unstableLogContent = join(\n getMidsceneRunSubDir('output'),\n 'unstableLogContent.json',\n );\n }\n\n this.taskStatusList = (script.tasks || []).map((task, taskIndex) => ({\n ...task,\n index: taskIndex,\n status: 'init',\n totalSteps: task.flow?.length || 0,\n }));\n }\n\n private setResult(key: string | undefined, value: any) {\n const keyToUse = key || this.unnamedResultIndex++;\n if (this.result[keyToUse]) {\n console.warn(`result key ${keyToUse} already exists, will overwrite`);\n }\n this.result[keyToUse] = value;\n\n return this.flushResult();\n }\n\n private setPlayerStatus(status: ScriptPlayerStatusValue, error?: Error) {\n this.status = status;\n this.errorInSetup = error;\n }\n\n private notifyCurrentTaskStatusChange(taskIndex?: number) {\n const taskIndexToNotify =\n typeof taskIndex === 'number' ? taskIndex : this.currentTaskIndex;\n\n if (typeof taskIndexToNotify !== 'number') {\n return;\n }\n\n const taskStatus = this.taskStatusList[taskIndexToNotify];\n if (this.onTaskStatusChange) {\n this.onTaskStatusChange(taskStatus);\n }\n }\n\n private async setTaskStatus(\n index: number,\n statusValue: ScriptPlayerStatusValue,\n error?: Error,\n ) {\n this.taskStatusList[index].status = statusValue;\n if (error) {\n this.taskStatusList[index].error = error;\n }\n\n this.notifyCurrentTaskStatusChange(index);\n }\n\n private setTaskIndex(taskIndex: number) {\n this.currentTaskIndex = taskIndex;\n }\n\n private flushResult() {\n if (this.output) {\n const output = resolve(process.cwd(), this.output);\n const outputDir = dirname(output);\n if (!existsSync(outputDir)) {\n mkdirSync(outputDir, { recursive: true });\n }\n writeFileSync(output, JSON.stringify(this.result || {}, undefined, 2));\n }\n }\n\n private flushUnstableLogContent() {\n if (this.unstableLogContent) {\n const content = this.interfaceAgent?._unstableLogContent();\n const filePath = resolve(process.cwd(), this.unstableLogContent);\n const outputDir = dirname(filePath);\n if (!existsSync(outputDir)) {\n mkdirSync(outputDir, { recursive: true });\n }\n writeFileSync(filePath, JSON.stringify(content, null, 2));\n }\n }\n\n async playTask(taskStatus: ScriptPlayerTaskStatus, agent: Agent) {\n const { flow } = taskStatus;\n assert(flow, 'missing flow in task');\n\n for (const flowItemIndex in flow) {\n const currentStep = Number.parseInt(flowItemIndex, 10);\n taskStatus.currentStep = currentStep;\n const flowItem = flow[flowItemIndex] as RuntimeYamlFlowItem;\n const flowItemRecord = flowItem as Record<string, unknown>;\n const executionCountBeforeStep = agent.dump?.executions?.length ?? 0;\n this.failedReportExecutionInCurrentStep = false;\n\n try {\n await this.playFlowItem(agent, flowItem, flowItemRecord, flowItemIndex);\n } catch (error) {\n this.failedReportExecutionInCurrentStep =\n this.hasFailedReportExecutionSince(agent, executionCountBeforeStep);\n throw error;\n }\n }\n this.reportFile = agent.reportFile;\n await this.flushUnstableLogContent();\n }\n\n private hasFailedReportExecutionSince(\n agent: Agent,\n executionCountBefore: number,\n ) {\n return (agent.dump?.executions ?? [])\n .slice(executionCountBefore)\n .some((execution) =>\n execution.tasks.some(\n (task) =>\n task.status === 'failed' ||\n Boolean(task.error || task.errorMessage),\n ),\n );\n }\n\n private async playFlowItem(\n agent: Agent,\n flowItem: RuntimeYamlFlowItem,\n flowItemRecord: Record<string, unknown>,\n flowItemIndex: string,\n ) {\n // Skip Finalize action from cache - it's a planning-only marker\n if ('Finalize' in flowItemRecord) {\n return;\n }\n\n debug(\n `playing step ${flowItemIndex}, flowItem=${JSON.stringify(flowItem)}`,\n );\n const simpleAIKey = (\n Object.keys(aiTaskHandlerMap) as AISimpleTaskKey[]\n ).find((key) => Object.prototype.hasOwnProperty.call(flowItemRecord, key));\n if (\n 'aiAct' in (flowItem as MidsceneYamlFlowItemAIAction) ||\n 'aiAction' in (flowItem as MidsceneYamlFlowItemAIAction) ||\n 'ai' in (flowItem as MidsceneYamlFlowItemAIAction)\n ) {\n const actionTask = flowItem as MidsceneYamlFlowItemAIAction;\n const { aiAct, aiAction, ai, instruction, ...actionOptions } =\n actionTask as any;\n const actionPrompt = aiAct ?? aiAction ?? ai;\n let promptForAI: TUserPrompt | undefined;\n\n if (typeof instruction === 'string' && instruction) {\n promptForAI = instruction;\n } else if (\n instruction &&\n typeof instruction === 'object' &&\n typeof (instruction as { prompt?: unknown }).prompt === 'string' &&\n (instruction as { prompt?: string }).prompt\n ) {\n promptForAI = instruction as TUserPrompt;\n } else if (\n actionPrompt &&\n typeof actionPrompt === 'object' &&\n typeof (actionPrompt as { prompt?: unknown }).prompt === 'string' &&\n (actionPrompt as { prompt?: string }).prompt\n ) {\n promptForAI = actionPrompt as TUserPrompt;\n } else if (typeof actionPrompt === 'string' && actionPrompt) {\n promptForAI = actionPrompt;\n }\n\n assert(promptForAI, 'missing prompt for ai (aiAct)');\n await agent.aiAct(promptForAI, actionOptions);\n } else if (\n 'runGherkinScenario' in\n (flowItem as MidsceneYamlFlowItemRunGherkinScenario)\n ) {\n const gherkinScenarioTask =\n flowItem as MidsceneYamlFlowItemRunGherkinScenario;\n const { runGherkinScenario } = gherkinScenarioTask;\n assert(runGherkinScenario, 'missing scenario for runGherkinScenario');\n await agent.runGherkinScenario(runGherkinScenario, {\n cacheable: false,\n });\n } else if ('aiAssert' in (flowItem as MidsceneYamlFlowItemAIAssert)) {\n const assertTask = flowItem as MidsceneYamlFlowItemAIAssert;\n const {\n aiAssert: prompt,\n errorMessage: msg,\n name,\n ...restOpts\n } = assertTask;\n assert(prompt, 'missing prompt for aiAssert');\n assert(\n !Object.prototype.hasOwnProperty.call(assertTask, 'observe'),\n '`observe` is not supported in YAML aiAssert. Use agent.startObserving() from code instead.',\n );\n\n const result = await agent.aiAssert(prompt, msg, {\n ...restOpts,\n keepRawResponse: true,\n });\n const pass = result?.pass;\n const thought = result?.thought;\n const message = result?.message;\n\n this.setResult(name, { pass, thought, message });\n\n if (!pass) {\n throw new Error(message);\n }\n } else if (simpleAIKey) {\n const {\n [simpleAIKey]: prompt,\n name,\n ...options\n } = flowItem as Record<string, any>;\n assert(prompt, `missing prompt for ${simpleAIKey}`);\n assert(\n !Object.prototype.hasOwnProperty.call(flowItem, 'observe'),\n '`observe` is not supported in YAML flow items. Use agent.startObserving() from code instead.',\n );\n\n const agentMethod = (agent as any)[aiTaskHandlerMap[simpleAIKey]];\n assert(\n typeof agentMethod === 'function',\n `missing agent method for ${simpleAIKey}`,\n );\n const aiResult = await agentMethod.call(agent, prompt, options);\n this.setResult(name, aiResult);\n } else if ('aiWaitFor' in (flowItem as MidsceneYamlFlowItemAIWaitFor)) {\n const waitForTask = flowItem as MidsceneYamlFlowItemAIWaitFor;\n const { aiWaitFor, timeout, ...restWaitForOpts } = waitForTask;\n const prompt = aiWaitFor;\n assert(prompt, 'missing prompt for aiWaitFor');\n const waitForOptions = {\n ...restWaitForOpts,\n ...(timeout !== undefined ? { timeout, timeoutMs: timeout } : {}),\n };\n await agent.aiWaitFor(prompt, waitForOptions);\n } else if ('sleep' in flowItem) {\n const sleepTask = flowItem as unknown as MidsceneYamlFlowItemSleep;\n const ms = sleepTask.sleep;\n let msNumber = ms;\n if (typeof ms === 'string') {\n msNumber = Number.parseInt(ms, 10);\n }\n assert(\n msNumber && msNumber > 0,\n `ms for sleep must be greater than 0, but got ${ms}`,\n );\n await new Promise((resolve) => setTimeout(resolve, msNumber));\n } else if ('javascript' in flowItem) {\n const evaluateJavaScriptTask =\n flowItem as unknown as MidsceneYamlFlowItemEvaluateJavaScript;\n\n const result = await agent.evaluateJavaScript(\n evaluateJavaScriptTask.javascript,\n );\n this.setResult(evaluateJavaScriptTask.name, result);\n } else if (\n 'logScreenshot' in (flowItem as MidsceneYamlFlowItemLogScreenshot) ||\n 'recordToReport' in (flowItem as MidsceneYamlFlowItemLogScreenshot)\n ) {\n const recordTask = flowItem as MidsceneYamlFlowItemLogScreenshot;\n const title =\n recordTask.recordToReport ?? recordTask.logScreenshot ?? 'untitled';\n const content = recordTask.content || '';\n await agent.recordToReport(title, { content });\n } else if ('aiInput' in flowItem) {\n // may be input empty string ''\n const {\n aiInput,\n value: rawValue,\n ...inputTask\n } = flowItem as unknown as MidsceneYamlFlowItemAIInput;\n\n // Compatibility with previous version:\n // Old format: { aiInput: string (value), locate: TUserPrompt }\n // New format - 1: { aiInput: TUserPrompt, value: string | number }\n // New format - 2: { aiInput: undefined, locate: TUserPrompt, value: string | number }\n let locatePrompt: TUserPrompt | undefined;\n let value: string | number | undefined;\n if ((inputTask as any).locate) {\n // Old format - aiInput is the value, locate is the prompt\n // Keep backward compatibility: empty string is treated as no value\n value = (aiInput as string | number) || rawValue;\n locatePrompt = (inputTask as any).locate;\n } else {\n // New format - aiInput is the prompt, value is the value\n locatePrompt = aiInput || '';\n value = rawValue;\n }\n\n // Convert value to string for Input action\n await agent.callActionInActionSpace('Input', {\n ...inputTask,\n ...(value !== undefined ? { value: String(value) } : {}),\n ...(locatePrompt\n ? { locate: buildDetailedLocateParam(locatePrompt, inputTask) }\n : {}),\n });\n } else if ('aiKeyboardPress' in flowItem) {\n const { aiKeyboardPress, ...keyboardPressTask } =\n flowItem as unknown as MidsceneYamlFlowItemAIKeyboardPress;\n\n // Compatibility with previous version:\n // Old format: { aiKeyboardPress: string (key), locate?: TUserPrompt }\n // New format - 1: { aiKeyboardPress: TUserPrompt, keyName: string }\n // New format - 2: { aiKeyboardPress: , locate?: TUserPrompt, keyName: string }\n let locatePrompt: TUserPrompt | undefined;\n let keyName: string | undefined;\n if ((keyboardPressTask as any).locate) {\n // Old format - aiKeyboardPress is the key, locate is the prompt\n keyName = aiKeyboardPress as string;\n locatePrompt = (keyboardPressTask as any).locate;\n } else if (keyboardPressTask.keyName) {\n // New format - aiKeyboardPress is the prompt, key is the key\n keyName = keyboardPressTask.keyName;\n locatePrompt = aiKeyboardPress;\n } else {\n keyName = aiKeyboardPress as string;\n }\n\n await agent.callActionInActionSpace('KeyboardPress', {\n ...keyboardPressTask,\n ...(keyName ? { keyName } : {}),\n ...(locatePrompt\n ? {\n locate: buildDetailedLocateParam(locatePrompt, keyboardPressTask),\n }\n : {}),\n });\n } else if ('aiScroll' in flowItem) {\n const { aiScroll, ...scrollTask } =\n flowItem as unknown as MidsceneYamlFlowItemAIScroll;\n\n // Compatibility with previous version:\n // Old format: { aiScroll: null, locate?: TUserPrompt, direction, scrollType, distance? }\n // New format - 1: { aiScroll: TUserPrompt, direction, scrollType, distance? }\n // New format - 2: { aiScroll: undefined, locate: TUserPrompt, direction, scrollType, distance? }\n const { locate, ...scrollOptions } = scrollTask as any;\n const locatePrompt: TUserPrompt | undefined =\n locate ?? aiScroll ?? undefined;\n\n await agent.aiScroll(locatePrompt, scrollOptions);\n } else if ('aiTap' in flowItem) {\n const { aiTap, prompt, locate, ...tapOptions } = flowItem as any;\n\n let locatePrompt: TUserPrompt;\n let opts = tapOptions;\n // Support both formats:\n // 1. { aiTap: null, locate: { prompt, images, ... } } (locate as sibling key)\n // 2. { aiTap: { locate: { prompt, images, ... } } } (locate nested in aiTap)\n const locateObj =\n locate ??\n (typeof aiTap === 'object' && aiTap !== null\n ? aiTap.locate\n : undefined);\n\n if (typeof aiTap === 'string' && aiTap) {\n // User YAML: aiTap: 'search input box'\n locatePrompt = aiTap;\n } else if (typeof locateObj === 'object' && locateObj?.prompt) {\n // buildYamlFlowFromPlans: { aiTap: '', locate: { prompt, deepLocate, cacheable } }\n const { prompt: lp, ...locateOpts } = locateObj;\n locatePrompt = lp;\n opts = { ...locateOpts, ...tapOptions };\n } else {\n // User YAML: aiTap: { prompt: '...' } or aiTap: null + prompt: '...'\n locatePrompt = aiTap?.prompt || prompt || locateObj;\n }\n\n assert(locatePrompt, 'missing prompt for aiTap');\n await agent.aiTap(locatePrompt, opts);\n } else {\n // generic action, find the action in actionSpace\n\n /* for aiRightClick, the parameters are a flattened data for the 'locate', these are all valid data\n\n - aiRightClick: 'search input box'\n - aiRightClick: 'search input box'\n deepLocate: true\n cacheable: false\n - aiRightClick:\n prompt: 'search input box'\n - aiRightClick:\n prompt: 'search input box'\n deepLocate: true\n cacheable: false\n */\n\n const actionSpace = this.actionSpace;\n let locatePromptShortcut: string | undefined;\n let actionParamForMatchedAction: unknown;\n const matchedAction = actionSpace.find((action) => {\n const actionInterfaceAlias = action.interfaceAlias;\n if (\n actionInterfaceAlias &&\n Object.prototype.hasOwnProperty.call(flowItem, actionInterfaceAlias)\n ) {\n actionParamForMatchedAction =\n flowItem[actionInterfaceAlias as keyof typeof flowItem];\n if (typeof actionParamForMatchedAction === 'string') {\n locatePromptShortcut = actionParamForMatchedAction;\n }\n return true;\n }\n\n const keyOfActionInActionSpace = action.name;\n if (\n Object.prototype.hasOwnProperty.call(\n flowItem,\n keyOfActionInActionSpace,\n )\n ) {\n actionParamForMatchedAction =\n flowItem[keyOfActionInActionSpace as keyof typeof flowItem];\n if (typeof actionParamForMatchedAction === 'string') {\n locatePromptShortcut = actionParamForMatchedAction;\n }\n return true;\n }\n\n return false;\n });\n\n assert(\n matchedAction,\n `unknown flowItem in yaml: ${JSON.stringify(flowItem)}`,\n );\n\n const schemaIsStringParam = isStringParamSchema(\n matchedAction.paramSchema,\n );\n let stringParamToCall: string | undefined;\n const resultName = (flowItem as any).name;\n const timeout = (flowItem as any).timeout;\n const hasRunAdbShellAlias = Object.prototype.hasOwnProperty.call(\n flowItem,\n 'runAdbShell',\n );\n\n if (\n hasRunAdbShellAlias &&\n typeof actionParamForMatchedAction === 'string' &&\n typeof timeout === 'number' &&\n typeof (agent as any).runAdbShell === 'function'\n ) {\n const result = await (agent as any).runAdbShell(\n actionParamForMatchedAction,\n { timeout },\n );\n if (result !== undefined) {\n this.setResult(resultName, result);\n }\n return;\n }\n\n const specialActionParamToCall =\n typeof actionParamForMatchedAction === 'string'\n ? buildShortcutActionParam(\n matchedAction.name,\n matchedAction.interfaceAlias,\n actionParamForMatchedAction,\n )\n : undefined;\n if (specialActionParamToCall) {\n debug(\n `matchedAction: ${matchedAction.name}`,\n `flowParams: ${JSON.stringify(specialActionParamToCall)}`,\n );\n const result = await agent.callActionInActionSpace(\n matchedAction.name,\n specialActionParamToCall,\n );\n\n if (result !== undefined) {\n this.setResult(resultName, result);\n }\n } else if (\n typeof actionParamForMatchedAction === 'string' &&\n schemaIsStringParam\n ) {\n if (matchedAction.paramSchema) {\n const parseResult = matchedAction.paramSchema.safeParse(\n actionParamForMatchedAction,\n );\n if (parseResult.success && typeof parseResult.data === 'string') {\n stringParamToCall = parseResult.data;\n } else if (!parseResult.success) {\n debug(\n `parse failed for action ${matchedAction.name} with string param`,\n parseResult.error,\n );\n stringParamToCall = actionParamForMatchedAction;\n }\n } else {\n stringParamToCall = actionParamForMatchedAction;\n }\n\n if (stringParamToCall !== undefined) {\n debug(\n `matchedAction: ${matchedAction.name}`,\n `flowParams: ${JSON.stringify(stringParamToCall)}`,\n );\n const result = await agent.callActionInActionSpace(\n matchedAction.name,\n stringParamToCall,\n );\n\n // Store result if there's a name property in flowItem\n const resultName = (flowItem as any).name;\n if (result !== undefined) {\n this.setResult(resultName, result);\n }\n }\n } else {\n // Determine the source for parameter extraction:\n // - If we have a locatePromptShortcut, use the flowItem (for actions like aiTap with prompt)\n // - Otherwise, use actionParamForMatchedAction (for actions like runWdaRequest with structured params)\n const sourceForParams =\n locatePromptShortcut &&\n typeof actionParamForMatchedAction === 'string'\n ? { ...flowItem, prompt: locatePromptShortcut }\n : typeof actionParamForMatchedAction === 'object' &&\n actionParamForMatchedAction !== null\n ? actionParamForMatchedAction\n : flowItem;\n\n const { locateParam, restParams } =\n buildDetailedLocateParamAndRestParams(\n locatePromptShortcut || '',\n sourceForParams as LocateOption,\n [\n matchedAction.name,\n matchedAction.interfaceAlias || '_never_mind_',\n ],\n );\n\n const flowParams = {\n ...restParams,\n locate: locateParam,\n };\n\n debug(\n `matchedAction: ${matchedAction.name}`,\n `flowParams: ${JSON.stringify(flowParams, null, 2)}`,\n );\n const result = await agent.callActionInActionSpace(\n matchedAction.name,\n flowParams,\n );\n\n // Store result if there's a name property in flowItem\n const resultName = (flowItem as any).name;\n if (result !== undefined) {\n this.setResult(resultName, result);\n }\n }\n }\n }\n\n async run() {\n const { target, web, android, ios, harmony, computer, tasks } = this.script;\n const webEnv = web || target;\n const androidEnv = android;\n const iosEnv = ios;\n const harmonyEnv = harmony;\n const computerEnv = computer;\n const platform =\n webEnv || androidEnv || iosEnv || harmonyEnv || computerEnv;\n\n this.setPlayerStatus('running');\n\n let agent: Agent | null = null;\n let freeFn: FreeFn[] = [];\n try {\n const { agent: newAgent, freeFn: newFreeFn } = await this.setupAgent(\n platform as T,\n );\n this.actionSpace = await newAgent.getActionSpace();\n agent = newAgent;\n const originalOnTaskStartTip = agent.onTaskStartTip;\n agent.onTaskStartTip = (tip) => {\n if (this.status === 'running') {\n this.agentStatusTip = tip;\n }\n originalOnTaskStartTip?.(tip);\n };\n freeFn = [\n ...(newFreeFn || []),\n {\n name: 'restore-agent-onTaskStartTip',\n fn: () => {\n if (agent) {\n agent.onTaskStartTip = originalOnTaskStartTip;\n }\n },\n },\n ];\n } catch (e) {\n this.setPlayerStatus('error', e as Error);\n return;\n }\n this.interfaceAgent = agent;\n\n let taskIndex = 0;\n this.setPlayerStatus('running');\n let errorFlag = false;\n while (taskIndex < tasks.length) {\n const taskStatus = this.taskStatusList[taskIndex];\n this.setTaskStatus(taskIndex, 'running' as any);\n this.setTaskIndex(taskIndex);\n this.failedReportExecutionInCurrentStep = false;\n\n try {\n await this.playTask(taskStatus, this.interfaceAgent);\n this.setTaskStatus(taskIndex, 'done' as any);\n } catch (e) {\n this.setTaskStatus(taskIndex, 'error' as any, e as Error);\n const recordErrorToReport = (agent as any).recordErrorToReport;\n if (\n !this.failedReportExecutionInCurrentStep &&\n typeof recordErrorToReport === 'function'\n ) {\n try {\n await recordErrorToReport.call(\n agent,\n `YAML task failed - ${taskStatus.name}`,\n {\n error: e as Error,\n content: `Step ${taskStatus.currentStep ?? 0} failed while running YAML task \"${taskStatus.name}\".`,\n },\n );\n } catch (reportError) {\n debug('failed to record yaml error to report', reportError);\n }\n }\n\n if (taskStatus.continueOnError) {\n // nothing more to do\n } else {\n this.reportFile = agent.reportFile;\n errorFlag = true;\n break;\n }\n }\n this.reportFile = agent?.reportFile;\n taskIndex++;\n }\n\n if (errorFlag) {\n this.setPlayerStatus('error');\n } else {\n this.setPlayerStatus('done');\n }\n this.agentStatusTip = '';\n\n await runFreeFnCleanup(freeFn);\n }\n}\n"],"names":["debug","getDebug","aiTaskHandlerMap","isStringParamSchema","schema","schemaDef","z","options","Array","option","buildShortcutActionParam","actionName","interfaceAlias","value","ScriptPlayer","key","keyToUse","console","status","error","taskIndex","taskIndexToNotify","taskStatus","index","statusValue","output","resolve","process","outputDir","dirname","existsSync","mkdirSync","writeFileSync","JSON","undefined","content","filePath","agent","flow","assert","flowItemIndex","currentStep","Number","flowItem","flowItemRecord","executionCountBeforeStep","executionCountBefore","execution","task","Boolean","simpleAIKey","Object","actionTask","aiAct","aiAction","ai","instruction","actionOptions","actionPrompt","promptForAI","gherkinScenarioTask","runGherkinScenario","assertTask","prompt","msg","name","restOpts","result","pass","thought","message","Error","agentMethod","aiResult","waitForTask","aiWaitFor","timeout","restWaitForOpts","waitForOptions","sleepTask","ms","msNumber","Promise","setTimeout","evaluateJavaScriptTask","recordTask","title","aiInput","rawValue","inputTask","locatePrompt","String","buildDetailedLocateParam","aiKeyboardPress","keyboardPressTask","keyName","aiScroll","scrollTask","locate","scrollOptions","aiTap","tapOptions","opts","locateObj","lp","locateOpts","actionSpace","locatePromptShortcut","actionParamForMatchedAction","matchedAction","action","actionInterfaceAlias","keyOfActionInActionSpace","schemaIsStringParam","stringParamToCall","resultName","hasRunAdbShellAlias","specialActionParamToCall","parseResult","sourceForParams","locateParam","restParams","buildDetailedLocateParamAndRestParams","flowParams","target","web","android","ios","harmony","computer","tasks","webEnv","androidEnv","iosEnv","harmonyEnv","computerEnv","platform","freeFn","newAgent","newFreeFn","originalOnTaskStartTip","tip","e","errorFlag","recordErrorToReport","reportError","runFreeFnCleanup","script","setupAgent","onTaskStatusChange","scriptPath","resolvedAiActContext","ifInBrowser","ifInWorker","scriptName","basename","join","getMidsceneRunSubDir","Date"],"mappings":"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"}
1
+ {"version":3,"file":"yaml/player.mjs","sources":["../../../src/yaml/player.ts"],"sourcesContent":["import { existsSync, mkdirSync, writeFileSync } from 'node:fs';\nimport { basename, dirname, join, resolve } from 'node:path';\nimport { assert, ifInBrowser, ifInWorker } from '@midscene/shared/utils';\nimport { type ZodTypeAny, z } from 'zod';\n\n// previous defined yaml flow, as a helper\ninterface MidsceneYamlFlowItemAIInput extends LocateOption {\n // previous version\n // aiInput: string; // value to input\n // locate: TUserPrompt; // where to input\n aiInput: TUserPrompt | undefined; // where to input\n value: string | number; // value to input\n mode?: 'replace' | 'clear' | 'typeOnly';\n autoDismissKeyboard?: boolean;\n keyboardTypeDelay?: number;\n inputStrategy?: InputStrategy;\n}\n\ninterface MidsceneYamlFlowItemAIKeyboardPress extends LocateOption {\n // previous version\n // aiKeyboardPress: string;\n // locate?: TUserPrompt; // where to press, optional\n aiKeyboardPress: TUserPrompt | undefined; // where to press\n keyName: string; // key to press\n}\n\ninterface MidsceneYamlFlowItemAIScroll extends LocateOption, ScrollParam {\n // previous version\n // aiScroll: null;\n // locate?: TUserPrompt; // which area to scroll, optional\n aiScroll: TUserPrompt | undefined; // which area to scroll\n}\n\ntype RuntimeYamlFlowItem =\n | MidsceneYamlFlowItem\n | MidsceneYamlFlowItemAIInput\n | MidsceneYamlFlowItemAIKeyboardPress\n | MidsceneYamlFlowItemAIScroll;\n\nimport type { Agent } from '@/agent/agent';\nimport type { TUserPrompt } from '@/common';\nimport type { InputStrategy } from '@/device';\nimport type {\n DeviceAction,\n FreeFn,\n LocateOption,\n MidsceneYamlFlowItem,\n MidsceneYamlFlowItemAIAction,\n MidsceneYamlFlowItemAIAssert,\n MidsceneYamlFlowItemAIWaitFor,\n MidsceneYamlFlowItemEvaluateJavaScript,\n MidsceneYamlFlowItemLogScreenshot,\n MidsceneYamlFlowItemRunGherkinScenario,\n MidsceneYamlFlowItemSleep,\n MidsceneYamlScript,\n MidsceneYamlScriptEnv,\n ScriptPlayerStatusValue,\n ScriptPlayerTaskStatus,\n ScrollParam,\n} from '@/types';\nimport { getMidsceneRunSubDir } from '@midscene/shared/common';\nimport { getDebug } from '@midscene/shared/logger';\nimport { runFreeFnCleanup } from './cleanup';\nimport {\n buildDetailedLocateParam,\n buildDetailedLocateParamAndRestParams,\n} from './utils';\n\nconst debug = getDebug('yaml-player');\n\nconst aiTaskHandlerMap = {\n aiQuery: 'aiQuery',\n aiNumber: 'aiNumber',\n aiString: 'aiString',\n aiBoolean: 'aiBoolean',\n aiAsk: 'aiAsk',\n aiLocate: 'aiLocate',\n} as const;\n\ntype AISimpleTaskKey = keyof typeof aiTaskHandlerMap;\n\nconst isStringParamSchema = (schema?: ZodTypeAny): boolean => {\n if (!schema) {\n return false;\n }\n\n const schemaDef = (schema as any)?._def;\n if (!schemaDef?.typeName) {\n return false;\n }\n\n switch (schemaDef.typeName) {\n case z.ZodFirstPartyTypeKind.ZodString:\n case z.ZodFirstPartyTypeKind.ZodEnum:\n case z.ZodFirstPartyTypeKind.ZodNativeEnum:\n return true;\n case z.ZodFirstPartyTypeKind.ZodLiteral:\n return typeof schemaDef.value === 'string';\n case z.ZodFirstPartyTypeKind.ZodOptional:\n case z.ZodFirstPartyTypeKind.ZodNullable:\n case z.ZodFirstPartyTypeKind.ZodDefault:\n return isStringParamSchema(schemaDef.innerType);\n case z.ZodFirstPartyTypeKind.ZodEffects:\n return isStringParamSchema(schemaDef.schema);\n case z.ZodFirstPartyTypeKind.ZodPipeline:\n return isStringParamSchema(schemaDef.out);\n case z.ZodFirstPartyTypeKind.ZodUnion: {\n const options = schemaDef.options as ZodTypeAny[] | undefined;\n return Array.isArray(options)\n ? options.every((option) => isStringParamSchema(option))\n : false;\n }\n default:\n return false;\n }\n};\n\nconst buildShortcutActionParam = (\n actionName: string,\n interfaceAlias: string | undefined,\n value: string,\n) => {\n if (actionName === 'Launch' || interfaceAlias === 'launch') {\n return { uri: value };\n }\n\n if (actionName === 'Terminate' || interfaceAlias === 'terminate') {\n return { uri: value };\n }\n\n if (\n actionName === 'RunAdbShell' ||\n interfaceAlias === 'runAdbShell' ||\n actionName === 'RunHdcShell' ||\n interfaceAlias === 'runHdcShell'\n ) {\n return { command: value };\n }\n\n return undefined;\n};\nexport class ScriptPlayer<T extends MidsceneYamlScriptEnv> {\n public currentTaskIndex?: number;\n public taskStatusList: ScriptPlayerTaskStatus[] = [];\n public status: ScriptPlayerStatusValue = 'init';\n public reportFile?: string | null;\n public result: Record<string, any>;\n private unnamedResultIndex = 0;\n public output?: string | null;\n public unstableLogContent?: string | null;\n public errorInSetup?: Error;\n private interfaceAgent: Agent | null = null;\n public agentStatusTip?: string;\n public target?: MidsceneYamlScriptEnv;\n private actionSpace: DeviceAction[] = [];\n private scriptPath?: string;\n private failedReportExecutionInCurrentStep = false;\n constructor(\n private script: MidsceneYamlScript,\n private setupAgent: (platform: T) => Promise<{\n agent: Agent;\n freeFn: FreeFn[];\n }>,\n public onTaskStatusChange?: (taskStatus: ScriptPlayerTaskStatus) => void,\n scriptPath?: string,\n ) {\n this.scriptPath = scriptPath;\n this.result = {};\n\n this.target =\n script.target ||\n script.web ||\n script.android ||\n script.ios ||\n script.computer ||\n script.config;\n\n if (ifInBrowser || ifInWorker) {\n this.output = undefined;\n debug('output is undefined in browser or worker');\n } else if (this.target?.output) {\n this.output = resolve(process.cwd(), this.target.output);\n debug('setting output by config.output', this.output);\n } else {\n const scriptName = this.scriptPath\n ? basename(this.scriptPath, '.yaml').replace(/\\.(ya?ml)$/i, '')\n : 'script';\n this.output = join(\n getMidsceneRunSubDir('output'),\n `${scriptName}-${Date.now()}.json`,\n );\n debug('setting output by script path', this.output);\n }\n\n if (ifInBrowser || ifInWorker) {\n this.unstableLogContent = undefined;\n } else if (typeof this.target?.unstableLogContent === 'string') {\n this.unstableLogContent = resolve(\n process.cwd(),\n this.target.unstableLogContent,\n );\n } else if (this.target?.unstableLogContent === true) {\n this.unstableLogContent = join(\n getMidsceneRunSubDir('output'),\n 'unstableLogContent.json',\n );\n }\n\n this.taskStatusList = (script.tasks || []).map((task, taskIndex) => ({\n ...task,\n index: taskIndex,\n status: 'init',\n totalSteps: task.flow?.length || 0,\n }));\n }\n\n private setResult(key: string | undefined, value: any) {\n const keyToUse = key || this.unnamedResultIndex++;\n if (this.result[keyToUse]) {\n console.warn(`result key ${keyToUse} already exists, will overwrite`);\n }\n this.result[keyToUse] = value;\n\n return this.flushResult();\n }\n\n private setPlayerStatus(status: ScriptPlayerStatusValue, error?: Error) {\n this.status = status;\n this.errorInSetup = error;\n }\n\n private notifyCurrentTaskStatusChange(taskIndex?: number) {\n const taskIndexToNotify =\n typeof taskIndex === 'number' ? taskIndex : this.currentTaskIndex;\n\n if (typeof taskIndexToNotify !== 'number') {\n return;\n }\n\n const taskStatus = this.taskStatusList[taskIndexToNotify];\n if (this.onTaskStatusChange) {\n this.onTaskStatusChange(taskStatus);\n }\n }\n\n private async setTaskStatus(\n index: number,\n statusValue: ScriptPlayerStatusValue,\n error?: Error,\n ) {\n this.taskStatusList[index].status = statusValue;\n if (error) {\n this.taskStatusList[index].error = error;\n }\n\n this.notifyCurrentTaskStatusChange(index);\n }\n\n private setTaskIndex(taskIndex: number) {\n this.currentTaskIndex = taskIndex;\n }\n\n private flushResult() {\n if (this.output) {\n const output = resolve(process.cwd(), this.output);\n const outputDir = dirname(output);\n if (!existsSync(outputDir)) {\n mkdirSync(outputDir, { recursive: true });\n }\n writeFileSync(output, JSON.stringify(this.result || {}, undefined, 2));\n }\n }\n\n private flushUnstableLogContent() {\n if (this.unstableLogContent) {\n const content = this.interfaceAgent?._unstableLogContent();\n const filePath = resolve(process.cwd(), this.unstableLogContent);\n const outputDir = dirname(filePath);\n if (!existsSync(outputDir)) {\n mkdirSync(outputDir, { recursive: true });\n }\n writeFileSync(filePath, JSON.stringify(content, null, 2));\n }\n }\n\n async playTask(taskStatus: ScriptPlayerTaskStatus, agent: Agent) {\n const { flow } = taskStatus;\n assert(flow, 'missing flow in task');\n\n for (const flowItemIndex in flow) {\n const currentStep = Number.parseInt(flowItemIndex, 10);\n taskStatus.currentStep = currentStep;\n const flowItem = flow[flowItemIndex] as RuntimeYamlFlowItem;\n const flowItemRecord = flowItem as Record<string, unknown>;\n const executionCountBeforeStep = agent.dump?.executions?.length ?? 0;\n this.failedReportExecutionInCurrentStep = false;\n\n try {\n await this.playFlowItem(agent, flowItem, flowItemRecord, flowItemIndex);\n } catch (error) {\n this.failedReportExecutionInCurrentStep =\n this.hasFailedReportExecutionSince(agent, executionCountBeforeStep);\n throw error;\n }\n }\n this.reportFile = agent.reportFile;\n await this.flushUnstableLogContent();\n }\n\n private hasFailedReportExecutionSince(\n agent: Agent,\n executionCountBefore: number,\n ) {\n return (agent.dump?.executions ?? [])\n .slice(executionCountBefore)\n .some((execution) =>\n execution.tasks.some(\n (task) =>\n task.status === 'failed' ||\n Boolean(task.error || task.errorMessage),\n ),\n );\n }\n\n private async playFlowItem(\n agent: Agent,\n flowItem: RuntimeYamlFlowItem,\n flowItemRecord: Record<string, unknown>,\n flowItemIndex: string,\n ) {\n // Skip Finalize action from cache - it's a planning-only marker\n if ('Finalize' in flowItemRecord) {\n return;\n }\n\n debug(\n `playing step ${flowItemIndex}, flowItem=${JSON.stringify(flowItem)}`,\n );\n const simpleAIKey = (\n Object.keys(aiTaskHandlerMap) as AISimpleTaskKey[]\n ).find((key) => Object.prototype.hasOwnProperty.call(flowItemRecord, key));\n if (\n 'aiAct' in (flowItem as MidsceneYamlFlowItemAIAction) ||\n 'aiAction' in (flowItem as MidsceneYamlFlowItemAIAction) ||\n 'ai' in (flowItem as MidsceneYamlFlowItemAIAction)\n ) {\n const actionTask = flowItem as MidsceneYamlFlowItemAIAction;\n const { aiAct, aiAction, ai, instruction, ...actionOptions } =\n actionTask as any;\n const actionPrompt = aiAct ?? aiAction ?? ai;\n let promptForAI: TUserPrompt | undefined;\n\n if (typeof instruction === 'string' && instruction) {\n promptForAI = instruction;\n } else if (\n instruction &&\n typeof instruction === 'object' &&\n typeof (instruction as { prompt?: unknown }).prompt === 'string' &&\n (instruction as { prompt?: string }).prompt\n ) {\n promptForAI = instruction as TUserPrompt;\n } else if (\n actionPrompt &&\n typeof actionPrompt === 'object' &&\n typeof (actionPrompt as { prompt?: unknown }).prompt === 'string' &&\n (actionPrompt as { prompt?: string }).prompt\n ) {\n promptForAI = actionPrompt as TUserPrompt;\n } else if (typeof actionPrompt === 'string' && actionPrompt) {\n promptForAI = actionPrompt;\n }\n\n assert(promptForAI, 'missing prompt for ai (aiAct)');\n await agent.aiAct(promptForAI, actionOptions);\n } else if (\n 'runGherkinScenario' in\n (flowItem as MidsceneYamlFlowItemRunGherkinScenario)\n ) {\n const gherkinScenarioTask =\n flowItem as MidsceneYamlFlowItemRunGherkinScenario;\n const { runGherkinScenario } = gherkinScenarioTask;\n assert(runGherkinScenario, 'missing scenario for runGherkinScenario');\n await agent.runGherkinScenario(runGherkinScenario, {\n cacheable: false,\n });\n } else if ('aiAssert' in (flowItem as MidsceneYamlFlowItemAIAssert)) {\n const assertTask = flowItem as MidsceneYamlFlowItemAIAssert;\n const {\n aiAssert: prompt,\n errorMessage: msg,\n name,\n ...restOpts\n } = assertTask;\n assert(prompt, 'missing prompt for aiAssert');\n assert(\n !Object.prototype.hasOwnProperty.call(assertTask, 'observe'),\n '`observe` is not supported in YAML aiAssert. Use agent.startObserving() from code instead.',\n );\n\n const result = await agent.aiAssert(prompt, msg, {\n ...restOpts,\n keepRawResponse: true,\n });\n const pass = result?.pass;\n const thought = result?.thought;\n const message = result?.message;\n\n this.setResult(name, { pass, thought, message });\n\n if (!pass) {\n throw new Error(message);\n }\n } else if (simpleAIKey) {\n const {\n [simpleAIKey]: prompt,\n name,\n ...options\n } = flowItem as Record<string, any>;\n assert(prompt, `missing prompt for ${simpleAIKey}`);\n assert(\n !Object.prototype.hasOwnProperty.call(flowItem, 'observe'),\n '`observe` is not supported in YAML flow items. Use agent.startObserving() from code instead.',\n );\n\n const agentMethod = (agent as any)[aiTaskHandlerMap[simpleAIKey]];\n assert(\n typeof agentMethod === 'function',\n `missing agent method for ${simpleAIKey}`,\n );\n const aiResult = await agentMethod.call(agent, prompt, options);\n this.setResult(name, aiResult);\n } else if ('aiWaitFor' in (flowItem as MidsceneYamlFlowItemAIWaitFor)) {\n const waitForTask = flowItem as MidsceneYamlFlowItemAIWaitFor;\n const { aiWaitFor, timeout, ...restWaitForOpts } = waitForTask;\n const prompt = aiWaitFor;\n assert(prompt, 'missing prompt for aiWaitFor');\n const waitForOptions = {\n ...restWaitForOpts,\n ...(timeout !== undefined ? { timeout, timeoutMs: timeout } : {}),\n };\n await agent.aiWaitFor(prompt, waitForOptions);\n } else if ('sleep' in flowItem) {\n const sleepTask = flowItem as unknown as MidsceneYamlFlowItemSleep;\n const ms = sleepTask.sleep;\n let msNumber = ms;\n if (typeof ms === 'string') {\n msNumber = Number.parseInt(ms, 10);\n }\n assert(\n msNumber && msNumber > 0,\n `ms for sleep must be greater than 0, but got ${ms}`,\n );\n await new Promise((resolve) => setTimeout(resolve, msNumber));\n } else if ('javascript' in flowItem) {\n const evaluateJavaScriptTask =\n flowItem as unknown as MidsceneYamlFlowItemEvaluateJavaScript;\n\n const result = await agent.evaluateJavaScript(\n evaluateJavaScriptTask.javascript,\n );\n this.setResult(evaluateJavaScriptTask.name, result);\n } else if (\n 'logScreenshot' in (flowItem as MidsceneYamlFlowItemLogScreenshot) ||\n 'recordToReport' in (flowItem as MidsceneYamlFlowItemLogScreenshot)\n ) {\n const recordTask = flowItem as MidsceneYamlFlowItemLogScreenshot;\n const title =\n recordTask.recordToReport ?? recordTask.logScreenshot ?? 'untitled';\n const content = recordTask.content || '';\n await agent.recordToReport(title, { content });\n } else if ('aiInput' in flowItem) {\n // may be input empty string ''\n const {\n aiInput,\n value: rawValue,\n ...inputTask\n } = flowItem as unknown as MidsceneYamlFlowItemAIInput;\n\n // Compatibility with previous version:\n // Old format: { aiInput: string (value), locate: TUserPrompt }\n // New format - 1: { aiInput: TUserPrompt, value: string | number }\n // New format - 2: { aiInput: undefined, locate: TUserPrompt, value: string | number }\n let locatePrompt: TUserPrompt | undefined;\n let value: string | number | undefined;\n if ((inputTask as any).locate) {\n // Old format - aiInput is the value, locate is the prompt\n // Keep backward compatibility: empty string is treated as no value\n value = (aiInput as string | number) || rawValue;\n locatePrompt = (inputTask as any).locate;\n } else {\n // New format - aiInput is the prompt, value is the value\n locatePrompt = aiInput || '';\n value = rawValue;\n }\n\n // Convert value to string for Input action\n await agent.callActionInActionSpace('Input', {\n ...inputTask,\n ...(value !== undefined ? { value: String(value) } : {}),\n ...(locatePrompt\n ? { locate: buildDetailedLocateParam(locatePrompt, inputTask) }\n : {}),\n });\n } else if ('aiKeyboardPress' in flowItem) {\n const { aiKeyboardPress, ...keyboardPressTask } =\n flowItem as unknown as MidsceneYamlFlowItemAIKeyboardPress;\n\n // Compatibility with previous version:\n // Old format: { aiKeyboardPress: string (key), locate?: TUserPrompt }\n // New format - 1: { aiKeyboardPress: TUserPrompt, keyName: string }\n // New format - 2: { aiKeyboardPress: , locate?: TUserPrompt, keyName: string }\n let locatePrompt: TUserPrompt | undefined;\n let keyName: string | undefined;\n if ((keyboardPressTask as any).locate) {\n // Old format - aiKeyboardPress is the key, locate is the prompt\n keyName = aiKeyboardPress as string;\n locatePrompt = (keyboardPressTask as any).locate;\n } else if (keyboardPressTask.keyName) {\n // New format - aiKeyboardPress is the prompt, key is the key\n keyName = keyboardPressTask.keyName;\n locatePrompt = aiKeyboardPress;\n } else {\n keyName = aiKeyboardPress as string;\n }\n\n await agent.callActionInActionSpace('KeyboardPress', {\n ...keyboardPressTask,\n ...(keyName ? { keyName } : {}),\n ...(locatePrompt\n ? {\n locate: buildDetailedLocateParam(locatePrompt, keyboardPressTask),\n }\n : {}),\n });\n } else if ('aiScroll' in flowItem) {\n const { aiScroll, ...scrollTask } =\n flowItem as unknown as MidsceneYamlFlowItemAIScroll;\n\n // Compatibility with previous version:\n // Old format: { aiScroll: null, locate?: TUserPrompt, direction, scrollType, distance? }\n // New format - 1: { aiScroll: TUserPrompt, direction, scrollType, distance? }\n // New format - 2: { aiScroll: undefined, locate: TUserPrompt, direction, scrollType, distance? }\n const { locate, ...scrollOptions } = scrollTask as any;\n const locatePrompt: TUserPrompt | undefined =\n locate ?? aiScroll ?? undefined;\n\n await agent.aiScroll(locatePrompt, scrollOptions);\n } else if ('aiTap' in flowItem) {\n const { aiTap, prompt, locate, ...tapOptions } = flowItem as any;\n\n let locatePrompt: TUserPrompt;\n let opts = tapOptions;\n // Support both formats:\n // 1. { aiTap: null, locate: { prompt, images, ... } } (locate as sibling key)\n // 2. { aiTap: { locate: { prompt, images, ... } } } (locate nested in aiTap)\n const locateObj =\n locate ??\n (typeof aiTap === 'object' && aiTap !== null\n ? aiTap.locate\n : undefined);\n\n if (typeof aiTap === 'string' && aiTap) {\n // User YAML: aiTap: 'search input box'\n locatePrompt = aiTap;\n } else if (typeof locateObj === 'object' && locateObj?.prompt) {\n // buildYamlFlowFromPlans: { aiTap: '', locate: { prompt, deepLocate, cacheable } }\n const { prompt: lp, ...locateOpts } = locateObj;\n locatePrompt = lp;\n opts = { ...locateOpts, ...tapOptions };\n } else {\n // User YAML: aiTap: { prompt: '...' } or aiTap: null + prompt: '...'\n locatePrompt = aiTap?.prompt || prompt || locateObj;\n }\n\n assert(locatePrompt, 'missing prompt for aiTap');\n await agent.aiTap(locatePrompt, opts);\n } else {\n // generic action, find the action in actionSpace\n\n /* for aiRightClick, the parameters are a flattened data for the 'locate', these are all valid data\n\n - aiRightClick: 'search input box'\n - aiRightClick: 'search input box'\n deepLocate: true\n cacheable: false\n - aiRightClick:\n prompt: 'search input box'\n - aiRightClick:\n prompt: 'search input box'\n deepLocate: true\n cacheable: false\n */\n\n const actionSpace = this.actionSpace;\n let locatePromptShortcut: string | undefined;\n let actionParamForMatchedAction: unknown;\n const matchedAction = actionSpace.find((action) => {\n const actionInterfaceAlias = action.interfaceAlias;\n if (\n actionInterfaceAlias &&\n Object.prototype.hasOwnProperty.call(flowItem, actionInterfaceAlias)\n ) {\n actionParamForMatchedAction =\n flowItem[actionInterfaceAlias as keyof typeof flowItem];\n if (typeof actionParamForMatchedAction === 'string') {\n locatePromptShortcut = actionParamForMatchedAction;\n }\n return true;\n }\n\n const keyOfActionInActionSpace = action.name;\n if (\n Object.prototype.hasOwnProperty.call(\n flowItem,\n keyOfActionInActionSpace,\n )\n ) {\n actionParamForMatchedAction =\n flowItem[keyOfActionInActionSpace as keyof typeof flowItem];\n if (typeof actionParamForMatchedAction === 'string') {\n locatePromptShortcut = actionParamForMatchedAction;\n }\n return true;\n }\n\n return false;\n });\n\n assert(\n matchedAction,\n `unknown flowItem in yaml: ${JSON.stringify(flowItem)}`,\n );\n\n const schemaIsStringParam = isStringParamSchema(\n matchedAction.paramSchema,\n );\n let stringParamToCall: string | undefined;\n const resultName = (flowItem as any).name;\n const timeout = (flowItem as any).timeout;\n const hasRunAdbShellAlias = Object.prototype.hasOwnProperty.call(\n flowItem,\n 'runAdbShell',\n );\n\n if (\n hasRunAdbShellAlias &&\n typeof actionParamForMatchedAction === 'string' &&\n typeof timeout === 'number' &&\n typeof (agent as any).runAdbShell === 'function'\n ) {\n const result = await (agent as any).runAdbShell(\n actionParamForMatchedAction,\n { timeout },\n );\n if (result !== undefined) {\n this.setResult(resultName, result);\n }\n return;\n }\n\n const specialActionParamToCall =\n typeof actionParamForMatchedAction === 'string'\n ? buildShortcutActionParam(\n matchedAction.name,\n matchedAction.interfaceAlias,\n actionParamForMatchedAction,\n )\n : undefined;\n if (specialActionParamToCall) {\n debug(\n `matchedAction: ${matchedAction.name}`,\n `flowParams: ${JSON.stringify(specialActionParamToCall)}`,\n );\n const result = await agent.callActionInActionSpace(\n matchedAction.name,\n specialActionParamToCall,\n );\n\n if (result !== undefined) {\n this.setResult(resultName, result);\n }\n } else if (\n typeof actionParamForMatchedAction === 'string' &&\n schemaIsStringParam\n ) {\n if (matchedAction.paramSchema) {\n const parseResult = matchedAction.paramSchema.safeParse(\n actionParamForMatchedAction,\n );\n if (parseResult.success && typeof parseResult.data === 'string') {\n stringParamToCall = parseResult.data;\n } else if (!parseResult.success) {\n debug(\n `parse failed for action ${matchedAction.name} with string param`,\n parseResult.error,\n );\n stringParamToCall = actionParamForMatchedAction;\n }\n } else {\n stringParamToCall = actionParamForMatchedAction;\n }\n\n if (stringParamToCall !== undefined) {\n debug(\n `matchedAction: ${matchedAction.name}`,\n `flowParams: ${JSON.stringify(stringParamToCall)}`,\n );\n const result = await agent.callActionInActionSpace(\n matchedAction.name,\n stringParamToCall,\n );\n\n // Store result if there's a name property in flowItem\n const resultName = (flowItem as any).name;\n if (result !== undefined) {\n this.setResult(resultName, result);\n }\n }\n } else {\n // Determine the source for parameter extraction:\n // - If we have a locatePromptShortcut, use the flowItem (for actions like aiTap with prompt)\n // - Otherwise, use actionParamForMatchedAction (for actions like runWdaRequest with structured params)\n const sourceForParams =\n locatePromptShortcut &&\n typeof actionParamForMatchedAction === 'string'\n ? { ...flowItem, prompt: locatePromptShortcut }\n : typeof actionParamForMatchedAction === 'object' &&\n actionParamForMatchedAction !== null\n ? actionParamForMatchedAction\n : flowItem;\n\n const { locateParam, restParams } =\n buildDetailedLocateParamAndRestParams(\n locatePromptShortcut || '',\n sourceForParams as LocateOption,\n [\n matchedAction.name,\n matchedAction.interfaceAlias || '_never_mind_',\n ],\n );\n\n const flowParams = {\n ...restParams,\n locate: locateParam,\n };\n\n debug(\n `matchedAction: ${matchedAction.name}`,\n `flowParams: ${JSON.stringify(flowParams, null, 2)}`,\n );\n const result = await agent.callActionInActionSpace(\n matchedAction.name,\n flowParams,\n );\n\n // Store result if there's a name property in flowItem\n const resultName = (flowItem as any).name;\n if (result !== undefined) {\n this.setResult(resultName, result);\n }\n }\n }\n }\n\n async run() {\n const { target, web, android, ios, harmony, computer, tasks } = this.script;\n const webEnv = web || target;\n const androidEnv = android;\n const iosEnv = ios;\n const harmonyEnv = harmony;\n const computerEnv = computer;\n const platform =\n webEnv || androidEnv || iosEnv || harmonyEnv || computerEnv;\n\n this.setPlayerStatus('running');\n\n let agent: Agent | null = null;\n let freeFn: FreeFn[] = [];\n try {\n const { agent: newAgent, freeFn: newFreeFn } = await this.setupAgent(\n platform as T,\n );\n this.actionSpace = await newAgent.getActionSpace();\n agent = newAgent;\n const originalOnTaskStartTip = agent.onTaskStartTip;\n agent.onTaskStartTip = (tip) => {\n if (this.status === 'running') {\n this.agentStatusTip = tip;\n }\n originalOnTaskStartTip?.(tip);\n };\n freeFn = [\n ...(newFreeFn || []),\n {\n name: 'restore-agent-onTaskStartTip',\n fn: () => {\n if (agent) {\n agent.onTaskStartTip = originalOnTaskStartTip;\n }\n },\n },\n ];\n } catch (e) {\n this.setPlayerStatus('error', e as Error);\n return;\n }\n this.interfaceAgent = agent;\n\n let taskIndex = 0;\n this.setPlayerStatus('running');\n let errorFlag = false;\n while (taskIndex < tasks.length) {\n const taskStatus = this.taskStatusList[taskIndex];\n this.setTaskStatus(taskIndex, 'running' as any);\n this.setTaskIndex(taskIndex);\n this.failedReportExecutionInCurrentStep = false;\n\n try {\n await this.playTask(taskStatus, this.interfaceAgent);\n this.setTaskStatus(taskIndex, 'done' as any);\n } catch (e) {\n this.setTaskStatus(taskIndex, 'error' as any, e as Error);\n const recordErrorToReport = (agent as any).recordErrorToReport;\n if (\n !this.failedReportExecutionInCurrentStep &&\n typeof recordErrorToReport === 'function'\n ) {\n try {\n await recordErrorToReport.call(\n agent,\n `YAML task failed - ${taskStatus.name}`,\n {\n error: e as Error,\n content: `Step ${taskStatus.currentStep ?? 0} failed while running YAML task \"${taskStatus.name}\".`,\n },\n );\n } catch (reportError) {\n debug('failed to record yaml error to report', reportError);\n }\n }\n\n if (taskStatus.continueOnError) {\n // nothing more to do\n } else {\n this.reportFile = agent.reportFile;\n errorFlag = true;\n break;\n }\n }\n this.reportFile = agent?.reportFile;\n taskIndex++;\n }\n\n if (errorFlag) {\n this.setPlayerStatus('error');\n } else {\n this.setPlayerStatus('done');\n }\n this.agentStatusTip = '';\n\n await runFreeFnCleanup(freeFn);\n }\n}\n"],"names":["debug","getDebug","aiTaskHandlerMap","isStringParamSchema","schema","schemaDef","z","options","Array","option","buildShortcutActionParam","actionName","interfaceAlias","value","ScriptPlayer","key","keyToUse","console","status","error","taskIndex","taskIndexToNotify","taskStatus","index","statusValue","output","resolve","process","outputDir","dirname","existsSync","mkdirSync","writeFileSync","JSON","undefined","content","filePath","agent","flow","assert","flowItemIndex","currentStep","Number","flowItem","flowItemRecord","executionCountBeforeStep","executionCountBefore","execution","task","Boolean","simpleAIKey","Object","actionTask","aiAct","aiAction","ai","instruction","actionOptions","actionPrompt","promptForAI","gherkinScenarioTask","runGherkinScenario","assertTask","prompt","msg","name","restOpts","result","pass","thought","message","Error","agentMethod","aiResult","waitForTask","aiWaitFor","timeout","restWaitForOpts","waitForOptions","sleepTask","ms","msNumber","Promise","setTimeout","evaluateJavaScriptTask","recordTask","title","aiInput","rawValue","inputTask","locatePrompt","String","buildDetailedLocateParam","aiKeyboardPress","keyboardPressTask","keyName","aiScroll","scrollTask","locate","scrollOptions","aiTap","tapOptions","opts","locateObj","lp","locateOpts","actionSpace","locatePromptShortcut","actionParamForMatchedAction","matchedAction","action","actionInterfaceAlias","keyOfActionInActionSpace","schemaIsStringParam","stringParamToCall","resultName","hasRunAdbShellAlias","specialActionParamToCall","parseResult","sourceForParams","locateParam","restParams","buildDetailedLocateParamAndRestParams","flowParams","target","web","android","ios","harmony","computer","tasks","webEnv","androidEnv","iosEnv","harmonyEnv","computerEnv","platform","freeFn","newAgent","newFreeFn","originalOnTaskStartTip","tip","e","errorFlag","recordErrorToReport","reportError","runFreeFnCleanup","script","setupAgent","onTaskStatusChange","scriptPath","ifInBrowser","ifInWorker","scriptName","basename","join","getMidsceneRunSubDir","Date"],"mappings":"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"}
@@ -1,7 +1,7 @@
1
1
  import { getDebug } from "@midscene/shared/logger";
2
2
  import { assert } from "@midscene/shared/utils";
3
3
  import js_yaml from "js-yaml";
4
- import { buildLocatePromptWithContext } from "../agent/prompt-context.mjs";
4
+ import { INTERNAL_AI_CONTEXT_METADATA_KEY, buildLocatePromptWithContext } from "../agent/prompt-context.mjs";
5
5
  const debugUtils = getDebug('yaml:utils');
6
6
  const topLevelTasksPattern = /^tasks\s*:/;
7
7
  const topLevelYamlKeyPattern = /^[^\s#][^:]*:/;
@@ -143,7 +143,8 @@ function buildDetailedLocateParam(locatePrompt, opt) {
143
143
  if (!prompt) return void debugUtils('no prompt, will return undefined in buildDetailedLocateParam', opt);
144
144
  const promptDisplay = 'string' == typeof prompt ? prompt : prompt.prompt;
145
145
  const context = opt?.context?.trim() || void 0;
146
- prompt = buildLocatePromptWithContext(prompt, opt?.context);
146
+ const internalOptions = opt;
147
+ prompt = buildLocatePromptWithContext(prompt, opt?.context, internalOptions?.[INTERNAL_AI_CONTEXT_METADATA_KEY]);
147
148
  const multimodalPrompt = extractMultimodalPrompt(opt);
148
149
  if (multimodalPrompt) prompt = 'string' == typeof prompt ? {
149
150
  prompt,
@@ -171,7 +172,7 @@ function buildDetailedLocateParamAndRestParams(locatePrompt, opt, excludeKeys =
171
172
  const allKeys = Object.keys(opt);
172
173
  const locateParamKeys = Object.keys(locateParam || {});
173
174
  const multimodalPromptKeys = 'object' == typeof locateParam?.prompt && locateParam?.prompt !== null ? Object.keys(multimodalPrompt || {}) : [];
174
- for (const key of allKeys)if (!locateParamKeys.includes(key) && 'context' !== key && 'deepThink' !== key && !multimodalPromptKeys.includes(key) && !excludeKeys.includes(key) && 'locate' !== key) restParams[key] = opt[key];
175
+ for (const key of allKeys)if (!locateParamKeys.includes(key) && 'context' !== key && key !== INTERNAL_AI_CONTEXT_METADATA_KEY && 'deepThink' !== key && !multimodalPromptKeys.includes(key) && !excludeKeys.includes(key) && 'locate' !== key) restParams[key] = opt[key];
175
176
  }
176
177
  return {
177
178
  locateParam,
@@ -1 +1 @@
1
- {"version":3,"file":"yaml/utils.mjs","sources":["../../../src/yaml/utils.ts"],"sourcesContent":["import type { TMultimodalPrompt, TUserPrompt } from '@/common';\nimport type {\n DetailedLocateParam,\n LocateOption,\n MidsceneYamlScript,\n MidsceneYamlScriptWebEnv,\n} from '@/types';\nimport { getDebug } from '@midscene/shared/logger';\nimport { assert } from '@midscene/shared/utils';\nimport yaml from 'js-yaml';\nimport { buildLocatePromptWithContext } from '../agent/prompt-context';\n\nconst debugUtils = getDebug('yaml:utils');\n\nconst topLevelTasksPattern = /^tasks\\s*:/;\nconst topLevelYamlKeyPattern = /^[^\\s#][^:]*:/;\n\nexport type WebTargetSource = 'page' | 'browser' | 'web' | 'target';\n\nexport type ResolvedWebTarget = {\n source: WebTargetSource;\n target: Partial<MidsceneYamlScriptWebEnv> & { mode: 'page' | 'browser' };\n mode: 'page' | 'browser';\n};\n\nexport type WebTargetConfig = Partial<\n Record<WebTargetSource, Partial<MidsceneYamlScriptWebEnv>>\n>;\n\nconst webTargetSources: WebTargetSource[] = [\n 'page',\n 'browser',\n 'web',\n 'target',\n];\n\nexport function resolveWebTarget(\n config: WebTargetConfig,\n): ResolvedWebTarget | undefined {\n const entries = webTargetSources\n .map((source) => [source, config[source]] as const)\n .filter(\n (\n entry,\n ): entry is readonly [\n WebTargetSource,\n Partial<MidsceneYamlScriptWebEnv>,\n ] => typeof entry[1] !== 'undefined',\n );\n\n if (entries.length === 0) {\n return undefined;\n }\n\n if (entries.length > 1) {\n const specifiedTargets = entries.map(([source]) => source);\n throw new Error(\n `[midscene] Only one web target can be specified, but found multiple: ${specifiedTargets.join(\n ', ',\n )}. Please specify only one of: page, browser, web, or target.`,\n );\n }\n\n const [source, target] = entries[0];\n const explicitMode = target.mode;\n if (\n typeof explicitMode !== 'undefined' &&\n explicitMode !== 'page' &&\n explicitMode !== 'browser'\n ) {\n throw new Error(\n `[midscene] web target mode must be either \"page\" or \"browser\", but got \"${explicitMode}\".`,\n );\n }\n\n if (source === 'page' && explicitMode === 'browser') {\n throw new Error(\n '[midscene] page target cannot use mode: browser. Use browser: instead.',\n );\n }\n\n if (source === 'browser' && explicitMode === 'page') {\n throw new Error(\n '[midscene] browser target cannot use mode: page. Use page: instead.',\n );\n }\n\n const mode =\n source === 'page'\n ? 'page'\n : source === 'browser'\n ? 'browser'\n : (explicitMode ?? 'page');\n\n if (mode === 'page' && target.autoFollowNewPage) {\n throw new Error(\n '[midscene] autoFollowNewPage requires browser mode. Use browser: or web.mode: browser.',\n );\n }\n\n if (\n mode === 'browser' &&\n typeof target.forceSameTabNavigation !== 'undefined'\n ) {\n throw new Error(\n '[midscene] forceSameTabNavigation cannot be used in browser mode. Use page: or web.mode: page when same-tab navigation is required.',\n );\n }\n\n return {\n source,\n mode,\n target: {\n ...target,\n mode,\n },\n };\n}\n\nfunction interpolateEnvVarRefs(\n value: string,\n keepUnresolvedRefs = false,\n): string {\n let result = '';\n let lastIndex = 0;\n let searchFrom = 0;\n\n while (searchFrom < value.length) {\n const start = value.indexOf('${', searchFrom);\n if (start === -1) {\n break;\n }\n\n const end = value.indexOf('}', start + 2);\n if (end === -1) {\n break;\n }\n\n const rawName = value.slice(start + 2, end);\n if (!rawName) {\n searchFrom = end + 1;\n continue;\n }\n\n result += value.slice(lastIndex, start);\n const envVar = rawName.trim();\n const envValue = process.env[envVar];\n if (envValue === undefined) {\n if (keepUnresolvedRefs) {\n result += value.slice(start, end + 1);\n } else {\n throw new Error(`Environment variable \"${envVar}\" is not defined`);\n }\n } else {\n result += envValue;\n }\n lastIndex = end + 1;\n searchFrom = end + 1;\n }\n\n return result + value.slice(lastIndex);\n}\n\nconst multimodalLocateOptionFieldMap: Record<keyof TMultimodalPrompt, true> = {\n images: true,\n convertHttpImage2Base64: true,\n};\n\nconst multimodalLocateOptionKeys = Object.keys(\n multimodalLocateOptionFieldMap,\n) as Array<keyof TMultimodalPrompt>;\n\nfunction extractMultimodalPrompt(\n opt?: LocateOption,\n): Partial<TMultimodalPrompt> | undefined {\n if (typeof opt !== 'object' || opt === null) {\n return undefined;\n }\n\n const entries = multimodalLocateOptionKeys\n .map((key) => [key, opt[key]] as const)\n .filter(([, value]) => value !== undefined);\n\n return entries.length\n ? (Object.fromEntries(entries) as Partial<TMultimodalPrompt>)\n : undefined;\n}\n\nexport function interpolateEnvVars(content: string): string {\n // Process line by line to skip commented lines\n const lines = content.split('\\n');\n const processedLines = lines.map((line) => {\n // Check if the line is a YAML comment (starts with # after optional whitespace)\n const trimmedLine = line.trimStart();\n if (trimmedLine.startsWith('#')) {\n // Skip interpolation for comment lines\n return line;\n }\n\n // Process environment variables for non-comment lines\n return interpolateEnvVarRefs(line);\n });\n\n return processedLines.join('\\n');\n}\n\nfunction interpolateYamlScriptEnvVars(content: string): string {\n let inTopLevelTasksBlock = false;\n\n return content\n .split('\\n')\n .map((line) => {\n const trimmedLine = line.trimStart();\n if (!trimmedLine || trimmedLine.startsWith('#')) {\n return line;\n }\n\n const indentSize = line.length - trimmedLine.length;\n if (indentSize === 0) {\n if (topLevelTasksPattern.test(trimmedLine)) {\n inTopLevelTasksBlock = true;\n return line;\n }\n\n if (topLevelYamlKeyPattern.test(trimmedLine)) {\n inTopLevelTasksBlock = false;\n }\n }\n\n return interpolateEnvVarRefs(line, inTopLevelTasksBlock);\n })\n .join('\\n');\n}\n\nexport function parseYamlScript(\n content: string,\n filePath?: string,\n): MidsceneYamlScript {\n let processedContent = content;\n if (content.indexOf('android') !== -1 && content.match(/deviceId:\\s*(\\d+)/)) {\n let matchedDeviceId;\n processedContent = content.replace(\n /deviceId:\\s*(\\d+)/g,\n (match, deviceId) => {\n matchedDeviceId = deviceId;\n return `deviceId: '${deviceId}'`;\n },\n );\n console.warn(\n `please use string-style deviceId in yaml script, for example: deviceId: \"${matchedDeviceId}\"`,\n );\n }\n const interpolatedContent = interpolateYamlScriptEnvVars(processedContent);\n const obj = yaml.load(interpolatedContent, {\n schema: yaml.JSON_SCHEMA,\n }) as MidsceneYamlScript;\n\n const pathTip = filePath ? `, failed to load ${filePath}` : '';\n resolveWebTarget(obj);\n assert(obj.tasks, `property \"tasks\" is required in yaml script ${pathTip}`);\n assert(\n Array.isArray(obj.tasks),\n `property \"tasks\" must be an array in yaml script, but got ${obj.tasks}`,\n );\n return obj;\n}\n\nexport function buildDetailedLocateParam(\n locatePrompt: TUserPrompt,\n opt?: LocateOption,\n): DetailedLocateParam | undefined {\n debugUtils('will call buildDetailedLocateParam', locatePrompt, opt);\n // Normalize object-form TUserPrompt: when the object only contains a\n // `prompt` string (no multimodal fields like `images`), unwrap it to\n // avoid double nesting like { prompt: { prompt: '...' } }.\n let normalizedLocatePrompt: TUserPrompt = locatePrompt;\n if (\n typeof locatePrompt === 'object' &&\n locatePrompt !== null &&\n 'prompt' in locatePrompt\n ) {\n const { prompt: innerPrompt, ...rest } = locatePrompt;\n const hasMultimodalFields = Object.keys(rest).length > 0;\n normalizedLocatePrompt = hasMultimodalFields ? locatePrompt : innerPrompt;\n }\n\n let prompt = normalizedLocatePrompt || opt?.prompt || (opt as any)?.locate; // as a shortcut\n let deepLocate = false;\n let cacheable = true;\n let xpath = undefined;\n\n if (typeof opt === 'object' && opt !== null) {\n // Backward-compatible: accept `deepThink` as a deprecated alias for `deepLocate`.\n // All downstream code works on `deepLocate` only; the compatibility resolution\n // is intentionally kept here at the entry point so it does not bleed through\n // the rest of the call stack.\n deepLocate = opt.deepLocate ?? opt.deepThink ?? false;\n cacheable = opt.cacheable ?? true;\n xpath = opt.xpath;\n if (locatePrompt && opt.prompt && locatePrompt !== opt.prompt) {\n console.warn(\n 'conflict prompt for item',\n locatePrompt,\n opt,\n 'maybe you put the prompt in the wrong place',\n );\n }\n prompt = prompt || opt.prompt;\n }\n\n if (!prompt) {\n debugUtils(\n 'no prompt, will return undefined in buildDetailedLocateParam',\n opt,\n );\n return undefined;\n }\n\n const promptDisplay = typeof prompt === 'string' ? prompt : prompt.prompt;\n const context = opt?.context?.trim() || undefined;\n prompt = buildLocatePromptWithContext(prompt, opt?.context);\n\n const multimodalPrompt = extractMultimodalPrompt(opt);\n if (multimodalPrompt) {\n prompt =\n typeof prompt === 'string'\n ? {\n prompt,\n ...multimodalPrompt,\n }\n : {\n ...prompt,\n ...multimodalPrompt,\n };\n }\n\n return {\n prompt,\n ...(context ? { promptDisplay, context } : {}),\n deepLocate,\n cacheable,\n xpath,\n };\n}\n\nexport function buildDetailedLocateParamAndRestParams(\n locatePrompt: TUserPrompt,\n opt: LocateOption | undefined,\n excludeKeys: string[] = [],\n): {\n locateParam: DetailedLocateParam | undefined;\n restParams: Record<string, any>;\n} {\n const multimodalPrompt = extractMultimodalPrompt(opt);\n const locateParam = buildDetailedLocateParam(locatePrompt, opt);\n\n // Extract all keys from opt except the ones already included in locateParam\n const restParams: Record<string, any> = {};\n\n if (typeof opt === 'object' && opt !== null) {\n // Get all keys from opt\n const allKeys = Object.keys(opt);\n\n // `context` has already been merged into the locate prompt.\n const locateParamKeys = Object.keys(locateParam || {});\n const multimodalPromptKeys =\n typeof locateParam?.prompt === 'object' && locateParam?.prompt !== null\n ? Object.keys(multimodalPrompt || {})\n : [];\n\n // Extract all other keys\n for (const key of allKeys) {\n if (\n !locateParamKeys.includes(key) &&\n key !== 'context' &&\n key !== 'deepThink' &&\n !multimodalPromptKeys.includes(key) &&\n !excludeKeys.includes(key) &&\n key !== 'locate'\n ) {\n restParams[key] = opt[key as keyof LocateOption];\n }\n }\n }\n\n return {\n locateParam,\n restParams,\n };\n}\n"],"names":["debugUtils","getDebug","topLevelTasksPattern","topLevelYamlKeyPattern","webTargetSources","resolveWebTarget","config","entries","source","entry","specifiedTargets","Error","target","explicitMode","mode","interpolateEnvVarRefs","value","keepUnresolvedRefs","result","lastIndex","searchFrom","start","end","rawName","envVar","envValue","process","undefined","multimodalLocateOptionFieldMap","multimodalLocateOptionKeys","Object","extractMultimodalPrompt","opt","key","interpolateEnvVars","content","lines","processedLines","line","trimmedLine","interpolateYamlScriptEnvVars","inTopLevelTasksBlock","indentSize","parseYamlScript","filePath","processedContent","matchedDeviceId","match","deviceId","console","interpolatedContent","obj","yaml","pathTip","assert","Array","buildDetailedLocateParam","locatePrompt","normalizedLocatePrompt","innerPrompt","rest","hasMultimodalFields","prompt","deepLocate","cacheable","xpath","promptDisplay","context","buildLocatePromptWithContext","multimodalPrompt","buildDetailedLocateParamAndRestParams","excludeKeys","locateParam","restParams","allKeys","locateParamKeys","multimodalPromptKeys"],"mappings":"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"}
1
+ {"version":3,"file":"yaml/utils.mjs","sources":["../../../src/yaml/utils.ts"],"sourcesContent":["import type { TMultimodalPrompt, TUserPrompt } from '@/common';\nimport type {\n DetailedLocateParam,\n LocateOption,\n MidsceneYamlScript,\n MidsceneYamlScriptWebEnv,\n} from '@/types';\nimport { getDebug } from '@midscene/shared/logger';\nimport { assert } from '@midscene/shared/utils';\nimport yaml from 'js-yaml';\nimport {\n INTERNAL_AI_CONTEXT_METADATA_KEY,\n type InternalAIContextOptions,\n buildLocatePromptWithContext,\n} from '../agent/prompt-context';\n\nconst debugUtils = getDebug('yaml:utils');\n\nconst topLevelTasksPattern = /^tasks\\s*:/;\nconst topLevelYamlKeyPattern = /^[^\\s#][^:]*:/;\n\nexport type WebTargetSource = 'page' | 'browser' | 'web' | 'target';\n\nexport type ResolvedWebTarget = {\n source: WebTargetSource;\n target: Partial<MidsceneYamlScriptWebEnv> & { mode: 'page' | 'browser' };\n mode: 'page' | 'browser';\n};\n\nexport type WebTargetConfig = Partial<\n Record<WebTargetSource, Partial<MidsceneYamlScriptWebEnv>>\n>;\n\nconst webTargetSources: WebTargetSource[] = [\n 'page',\n 'browser',\n 'web',\n 'target',\n];\n\nexport function resolveWebTarget(\n config: WebTargetConfig,\n): ResolvedWebTarget | undefined {\n const entries = webTargetSources\n .map((source) => [source, config[source]] as const)\n .filter(\n (\n entry,\n ): entry is readonly [\n WebTargetSource,\n Partial<MidsceneYamlScriptWebEnv>,\n ] => typeof entry[1] !== 'undefined',\n );\n\n if (entries.length === 0) {\n return undefined;\n }\n\n if (entries.length > 1) {\n const specifiedTargets = entries.map(([source]) => source);\n throw new Error(\n `[midscene] Only one web target can be specified, but found multiple: ${specifiedTargets.join(\n ', ',\n )}. Please specify only one of: page, browser, web, or target.`,\n );\n }\n\n const [source, target] = entries[0];\n const explicitMode = target.mode;\n if (\n typeof explicitMode !== 'undefined' &&\n explicitMode !== 'page' &&\n explicitMode !== 'browser'\n ) {\n throw new Error(\n `[midscene] web target mode must be either \"page\" or \"browser\", but got \"${explicitMode}\".`,\n );\n }\n\n if (source === 'page' && explicitMode === 'browser') {\n throw new Error(\n '[midscene] page target cannot use mode: browser. Use browser: instead.',\n );\n }\n\n if (source === 'browser' && explicitMode === 'page') {\n throw new Error(\n '[midscene] browser target cannot use mode: page. Use page: instead.',\n );\n }\n\n const mode =\n source === 'page'\n ? 'page'\n : source === 'browser'\n ? 'browser'\n : (explicitMode ?? 'page');\n\n if (mode === 'page' && target.autoFollowNewPage) {\n throw new Error(\n '[midscene] autoFollowNewPage requires browser mode. Use browser: or web.mode: browser.',\n );\n }\n\n if (\n mode === 'browser' &&\n typeof target.forceSameTabNavigation !== 'undefined'\n ) {\n throw new Error(\n '[midscene] forceSameTabNavigation cannot be used in browser mode. Use page: or web.mode: page when same-tab navigation is required.',\n );\n }\n\n return {\n source,\n mode,\n target: {\n ...target,\n mode,\n },\n };\n}\n\nfunction interpolateEnvVarRefs(\n value: string,\n keepUnresolvedRefs = false,\n): string {\n let result = '';\n let lastIndex = 0;\n let searchFrom = 0;\n\n while (searchFrom < value.length) {\n const start = value.indexOf('${', searchFrom);\n if (start === -1) {\n break;\n }\n\n const end = value.indexOf('}', start + 2);\n if (end === -1) {\n break;\n }\n\n const rawName = value.slice(start + 2, end);\n if (!rawName) {\n searchFrom = end + 1;\n continue;\n }\n\n result += value.slice(lastIndex, start);\n const envVar = rawName.trim();\n const envValue = process.env[envVar];\n if (envValue === undefined) {\n if (keepUnresolvedRefs) {\n result += value.slice(start, end + 1);\n } else {\n throw new Error(`Environment variable \"${envVar}\" is not defined`);\n }\n } else {\n result += envValue;\n }\n lastIndex = end + 1;\n searchFrom = end + 1;\n }\n\n return result + value.slice(lastIndex);\n}\n\nconst multimodalLocateOptionFieldMap: Record<keyof TMultimodalPrompt, true> = {\n images: true,\n convertHttpImage2Base64: true,\n};\n\nconst multimodalLocateOptionKeys = Object.keys(\n multimodalLocateOptionFieldMap,\n) as Array<keyof TMultimodalPrompt>;\n\nfunction extractMultimodalPrompt(\n opt?: LocateOption,\n): Partial<TMultimodalPrompt> | undefined {\n if (typeof opt !== 'object' || opt === null) {\n return undefined;\n }\n\n const entries = multimodalLocateOptionKeys\n .map((key) => [key, opt[key]] as const)\n .filter(([, value]) => value !== undefined);\n\n return entries.length\n ? (Object.fromEntries(entries) as Partial<TMultimodalPrompt>)\n : undefined;\n}\n\nexport function interpolateEnvVars(content: string): string {\n // Process line by line to skip commented lines\n const lines = content.split('\\n');\n const processedLines = lines.map((line) => {\n // Check if the line is a YAML comment (starts with # after optional whitespace)\n const trimmedLine = line.trimStart();\n if (trimmedLine.startsWith('#')) {\n // Skip interpolation for comment lines\n return line;\n }\n\n // Process environment variables for non-comment lines\n return interpolateEnvVarRefs(line);\n });\n\n return processedLines.join('\\n');\n}\n\nfunction interpolateYamlScriptEnvVars(content: string): string {\n let inTopLevelTasksBlock = false;\n\n return content\n .split('\\n')\n .map((line) => {\n const trimmedLine = line.trimStart();\n if (!trimmedLine || trimmedLine.startsWith('#')) {\n return line;\n }\n\n const indentSize = line.length - trimmedLine.length;\n if (indentSize === 0) {\n if (topLevelTasksPattern.test(trimmedLine)) {\n inTopLevelTasksBlock = true;\n return line;\n }\n\n if (topLevelYamlKeyPattern.test(trimmedLine)) {\n inTopLevelTasksBlock = false;\n }\n }\n\n return interpolateEnvVarRefs(line, inTopLevelTasksBlock);\n })\n .join('\\n');\n}\n\nexport function parseYamlScript(\n content: string,\n filePath?: string,\n): MidsceneYamlScript {\n let processedContent = content;\n if (content.indexOf('android') !== -1 && content.match(/deviceId:\\s*(\\d+)/)) {\n let matchedDeviceId;\n processedContent = content.replace(\n /deviceId:\\s*(\\d+)/g,\n (match, deviceId) => {\n matchedDeviceId = deviceId;\n return `deviceId: '${deviceId}'`;\n },\n );\n console.warn(\n `please use string-style deviceId in yaml script, for example: deviceId: \"${matchedDeviceId}\"`,\n );\n }\n const interpolatedContent = interpolateYamlScriptEnvVars(processedContent);\n const obj = yaml.load(interpolatedContent, {\n schema: yaml.JSON_SCHEMA,\n }) as MidsceneYamlScript;\n\n const pathTip = filePath ? `, failed to load ${filePath}` : '';\n resolveWebTarget(obj);\n assert(obj.tasks, `property \"tasks\" is required in yaml script ${pathTip}`);\n assert(\n Array.isArray(obj.tasks),\n `property \"tasks\" must be an array in yaml script, but got ${obj.tasks}`,\n );\n return obj;\n}\n\nexport function buildDetailedLocateParam(\n locatePrompt: TUserPrompt,\n opt?: LocateOption,\n): DetailedLocateParam | undefined {\n debugUtils('will call buildDetailedLocateParam', locatePrompt, opt);\n // Normalize object-form TUserPrompt: when the object only contains a\n // `prompt` string (no multimodal fields like `images`), unwrap it to\n // avoid double nesting like { prompt: { prompt: '...' } }.\n let normalizedLocatePrompt: TUserPrompt = locatePrompt;\n if (\n typeof locatePrompt === 'object' &&\n locatePrompt !== null &&\n 'prompt' in locatePrompt\n ) {\n const { prompt: innerPrompt, ...rest } = locatePrompt;\n const hasMultimodalFields = Object.keys(rest).length > 0;\n normalizedLocatePrompt = hasMultimodalFields ? locatePrompt : innerPrompt;\n }\n\n let prompt = normalizedLocatePrompt || opt?.prompt || (opt as any)?.locate; // as a shortcut\n let deepLocate = false;\n let cacheable = true;\n let xpath = undefined;\n\n if (typeof opt === 'object' && opt !== null) {\n // Backward-compatible: accept `deepThink` as a deprecated alias for `deepLocate`.\n // All downstream code works on `deepLocate` only; the compatibility resolution\n // is intentionally kept here at the entry point so it does not bleed through\n // the rest of the call stack.\n deepLocate = opt.deepLocate ?? opt.deepThink ?? false;\n cacheable = opt.cacheable ?? true;\n xpath = opt.xpath;\n if (locatePrompt && opt.prompt && locatePrompt !== opt.prompt) {\n console.warn(\n 'conflict prompt for item',\n locatePrompt,\n opt,\n 'maybe you put the prompt in the wrong place',\n );\n }\n prompt = prompt || opt.prompt;\n }\n\n if (!prompt) {\n debugUtils(\n 'no prompt, will return undefined in buildDetailedLocateParam',\n opt,\n );\n return undefined;\n }\n\n const promptDisplay = typeof prompt === 'string' ? prompt : prompt.prompt;\n const context = opt?.context?.trim() || undefined;\n const internalOptions = opt as\n | (LocateOption & Partial<InternalAIContextOptions>)\n | undefined;\n prompt = buildLocatePromptWithContext(\n prompt,\n opt?.context,\n internalOptions?.[INTERNAL_AI_CONTEXT_METADATA_KEY],\n );\n\n const multimodalPrompt = extractMultimodalPrompt(opt);\n if (multimodalPrompt) {\n prompt =\n typeof prompt === 'string'\n ? {\n prompt,\n ...multimodalPrompt,\n }\n : {\n ...prompt,\n ...multimodalPrompt,\n };\n }\n\n return {\n prompt,\n ...(context ? { promptDisplay, context } : {}),\n deepLocate,\n cacheable,\n xpath,\n };\n}\n\nexport function buildDetailedLocateParamAndRestParams(\n locatePrompt: TUserPrompt,\n opt: LocateOption | undefined,\n excludeKeys: string[] = [],\n): {\n locateParam: DetailedLocateParam | undefined;\n restParams: Record<string, any>;\n} {\n const multimodalPrompt = extractMultimodalPrompt(opt);\n const locateParam = buildDetailedLocateParam(locatePrompt, opt);\n\n // Extract all keys from opt except the ones already included in locateParam\n const restParams: Record<string, any> = {};\n\n if (typeof opt === 'object' && opt !== null) {\n // Get all keys from opt\n const allKeys = Object.keys(opt);\n\n // `context` has already been merged into the locate prompt.\n const locateParamKeys = Object.keys(locateParam || {});\n const multimodalPromptKeys =\n typeof locateParam?.prompt === 'object' && locateParam?.prompt !== null\n ? Object.keys(multimodalPrompt || {})\n : [];\n\n // Extract all other keys\n for (const key of allKeys) {\n if (\n !locateParamKeys.includes(key) &&\n key !== 'context' &&\n key !== INTERNAL_AI_CONTEXT_METADATA_KEY &&\n key !== 'deepThink' &&\n !multimodalPromptKeys.includes(key) &&\n !excludeKeys.includes(key) &&\n key !== 'locate'\n ) {\n restParams[key] = opt[key as keyof LocateOption];\n }\n }\n }\n\n return {\n locateParam,\n restParams,\n };\n}\n"],"names":["debugUtils","getDebug","topLevelTasksPattern","topLevelYamlKeyPattern","webTargetSources","resolveWebTarget","config","entries","source","entry","specifiedTargets","Error","target","explicitMode","mode","interpolateEnvVarRefs","value","keepUnresolvedRefs","result","lastIndex","searchFrom","start","end","rawName","envVar","envValue","process","undefined","multimodalLocateOptionFieldMap","multimodalLocateOptionKeys","Object","extractMultimodalPrompt","opt","key","interpolateEnvVars","content","lines","processedLines","line","trimmedLine","interpolateYamlScriptEnvVars","inTopLevelTasksBlock","indentSize","parseYamlScript","filePath","processedContent","matchedDeviceId","match","deviceId","console","interpolatedContent","obj","yaml","pathTip","assert","Array","buildDetailedLocateParam","locatePrompt","normalizedLocatePrompt","innerPrompt","rest","hasMultimodalFields","prompt","deepLocate","cacheable","xpath","promptDisplay","context","internalOptions","buildLocatePromptWithContext","INTERNAL_AI_CONTEXT_METADATA_KEY","multimodalPrompt","buildDetailedLocateParamAndRestParams","excludeKeys","locateParam","restParams","allKeys","locateParamKeys","multimodalPromptKeys"],"mappings":";;;;AAgBA,MAAMA,aAAaC,SAAS;AAE5B,MAAMC,uBAAuB;AAC7B,MAAMC,yBAAyB;AAc/B,MAAMC,mBAAsC;IAC1C;IACA;IACA;IACA;CACD;AAEM,SAASC,iBACdC,MAAuB;IAEvB,MAAMC,UAAUH,iBACb,GAAG,CAAC,CAACI,SAAW;YAACA;YAAQF,MAAM,CAACE,OAAO;SAAC,EACxC,MAAM,CACL,CACEC,QAIG,AAAoB,WAAbA,KAAK,CAAC,EAAE;IAGxB,IAAIF,AAAmB,MAAnBA,QAAQ,MAAM,EAChB;IAGF,IAAIA,QAAQ,MAAM,GAAG,GAAG;QACtB,MAAMG,mBAAmBH,QAAQ,GAAG,CAAC,CAAC,CAACC,OAAO,GAAKA;QACnD,MAAM,IAAIG,MACR,CAAC,qEAAqE,EAAED,iBAAiB,IAAI,CAC3F,MACA,4DAA4D,CAAC;IAEnE;IAEA,MAAM,CAACF,QAAQI,OAAO,GAAGL,OAAO,CAAC,EAAE;IACnC,MAAMM,eAAeD,OAAO,IAAI;IAChC,IACE,AAAwB,WAAjBC,gBACPA,AAAiB,WAAjBA,gBACAA,AAAiB,cAAjBA,cAEA,MAAM,IAAIF,MACR,CAAC,wEAAwE,EAAEE,aAAa,EAAE,CAAC;IAI/F,IAAIL,AAAW,WAAXA,UAAqBK,AAAiB,cAAjBA,cACvB,MAAM,IAAIF,MACR;IAIJ,IAAIH,AAAW,cAAXA,UAAwBK,AAAiB,WAAjBA,cAC1B,MAAM,IAAIF,MACR;IAIJ,MAAMG,OACJN,AAAW,WAAXA,SACI,SACAA,AAAW,cAAXA,SACE,YACCK,gBAAgB;IAEzB,IAAIC,AAAS,WAATA,QAAmBF,OAAO,iBAAiB,EAC7C,MAAM,IAAID,MACR;IAIJ,IACEG,AAAS,cAATA,QACA,AAAyC,WAAlCF,OAAO,sBAAsB,EAEpC,MAAM,IAAID,MACR;IAIJ,OAAO;QACLH;QACAM;QACA,QAAQ;YACN,GAAGF,MAAM;YACTE;QACF;IACF;AACF;AAEA,SAASC,sBACPC,KAAa,EACbC,qBAAqB,KAAK;IAE1B,IAAIC,SAAS;IACb,IAAIC,YAAY;IAChB,IAAIC,aAAa;IAEjB,MAAOA,aAAaJ,MAAM,MAAM,CAAE;QAChC,MAAMK,QAAQL,MAAM,OAAO,CAAC,MAAMI;QAClC,IAAIC,AAAU,OAAVA,OACF;QAGF,MAAMC,MAAMN,MAAM,OAAO,CAAC,KAAKK,QAAQ;QACvC,IAAIC,AAAQ,OAARA,KACF;QAGF,MAAMC,UAAUP,MAAM,KAAK,CAACK,QAAQ,GAAGC;QACvC,IAAI,CAACC,SAAS;YACZH,aAAaE,MAAM;YACnB;QACF;QAEAJ,UAAUF,MAAM,KAAK,CAACG,WAAWE;QACjC,MAAMG,SAASD,QAAQ,IAAI;QAC3B,MAAME,WAAWC,QAAQ,GAAG,CAACF,OAAO;QACpC,IAAIC,AAAaE,WAAbF,UACF,IAAIR,oBACFC,UAAUF,MAAM,KAAK,CAACK,OAAOC,MAAM;aAEnC,MAAM,IAAIX,MAAM,CAAC,sBAAsB,EAAEa,OAAO,gBAAgB,CAAC;aAGnEN,UAAUO;QAEZN,YAAYG,MAAM;QAClBF,aAAaE,MAAM;IACrB;IAEA,OAAOJ,SAASF,MAAM,KAAK,CAACG;AAC9B;AAEA,MAAMS,iCAAwE;IAC5E,QAAQ;IACR,yBAAyB;AAC3B;AAEA,MAAMC,6BAA6BC,OAAO,IAAI,CAC5CF;AAGF,SAASG,wBACPC,GAAkB;IAElB,IAAI,AAAe,YAAf,OAAOA,OAAoBA,AAAQ,SAARA,KAC7B;IAGF,MAAMzB,UAAUsB,2BACb,GAAG,CAAC,CAACI,MAAQ;YAACA;YAAKD,GAAG,CAACC,IAAI;SAAC,EAC5B,MAAM,CAAC,CAAC,GAAGjB,MAAM,GAAKA,AAAUW,WAAVX;IAEzB,OAAOT,QAAQ,MAAM,GAChBuB,OAAO,WAAW,CAACvB,WACpBoB;AACN;AAEO,SAASO,mBAAmBC,OAAe;IAEhD,MAAMC,QAAQD,QAAQ,KAAK,CAAC;IAC5B,MAAME,iBAAiBD,MAAM,GAAG,CAAC,CAACE;QAEhC,MAAMC,cAAcD,KAAK,SAAS;QAClC,IAAIC,YAAY,UAAU,CAAC,MAEzB,OAAOD;QAIT,OAAOvB,sBAAsBuB;IAC/B;IAEA,OAAOD,eAAe,IAAI,CAAC;AAC7B;AAEA,SAASG,6BAA6BL,OAAe;IACnD,IAAIM,uBAAuB;IAE3B,OAAON,QACJ,KAAK,CAAC,MACN,GAAG,CAAC,CAACG;QACJ,MAAMC,cAAcD,KAAK,SAAS;QAClC,IAAI,CAACC,eAAeA,YAAY,UAAU,CAAC,MACzC,OAAOD;QAGT,MAAMI,aAAaJ,KAAK,MAAM,GAAGC,YAAY,MAAM;QACnD,IAAIG,AAAe,MAAfA,YAAkB;YACpB,IAAIxC,qBAAqB,IAAI,CAACqC,cAAc;gBAC1CE,uBAAuB;gBACvB,OAAOH;YACT;YAEA,IAAInC,uBAAuB,IAAI,CAACoC,cAC9BE,uBAAuB;QAE3B;QAEA,OAAO1B,sBAAsBuB,MAAMG;IACrC,GACC,IAAI,CAAC;AACV;AAEO,SAASE,gBACdR,OAAe,EACfS,QAAiB;IAEjB,IAAIC,mBAAmBV;IACvB,IAAIA,AAA+B,OAA/BA,QAAQ,OAAO,CAAC,cAAqBA,QAAQ,KAAK,CAAC,sBAAsB;QAC3E,IAAIW;QACJD,mBAAmBV,QAAQ,OAAO,CAChC,sBACA,CAACY,OAAOC;YACNF,kBAAkBE;YAClB,OAAO,CAAC,WAAW,EAAEA,SAAS,CAAC,CAAC;QAClC;QAEFC,QAAQ,IAAI,CACV,CAAC,yEAAyE,EAAEH,gBAAgB,CAAC,CAAC;IAElG;IACA,MAAMI,sBAAsBV,6BAA6BK;IACzD,MAAMM,MAAMC,QAAAA,IAAS,CAACF,qBAAqB;QACzC,QAAQE,QAAAA,WAAgB;IAC1B;IAEA,MAAMC,UAAUT,WAAW,CAAC,iBAAiB,EAAEA,UAAU,GAAG;IAC5DvC,iBAAiB8C;IACjBG,OAAOH,IAAI,KAAK,EAAE,CAAC,4CAA4C,EAAEE,SAAS;IAC1EC,OACEC,MAAM,OAAO,CAACJ,IAAI,KAAK,GACvB,CAAC,0DAA0D,EAAEA,IAAI,KAAK,EAAE;IAE1E,OAAOA;AACT;AAEO,SAASK,yBACdC,YAAyB,EACzBzB,GAAkB;IAElBhC,WAAW,sCAAsCyD,cAAczB;IAI/D,IAAI0B,yBAAsCD;IAC1C,IACE,AAAwB,YAAxB,OAAOA,gBACPA,AAAiB,SAAjBA,gBACA,YAAYA,cACZ;QACA,MAAM,EAAE,QAAQE,WAAW,EAAE,GAAGC,MAAM,GAAGH;QACzC,MAAMI,sBAAsB/B,OAAO,IAAI,CAAC8B,MAAM,MAAM,GAAG;QACvDF,yBAAyBG,sBAAsBJ,eAAeE;IAChE;IAEA,IAAIG,SAASJ,0BAA0B1B,KAAK,UAAWA,KAAa;IACpE,IAAI+B,aAAa;IACjB,IAAIC,YAAY;IAChB,IAAIC;IAEJ,IAAI,AAAe,YAAf,OAAOjC,OAAoBA,AAAQ,SAARA,KAAc;QAK3C+B,aAAa/B,IAAI,UAAU,IAAIA,IAAI,SAAS,IAAI;QAChDgC,YAAYhC,IAAI,SAAS,IAAI;QAC7BiC,QAAQjC,IAAI,KAAK;QACjB,IAAIyB,gBAAgBzB,IAAI,MAAM,IAAIyB,iBAAiBzB,IAAI,MAAM,EAC3DiB,QAAQ,IAAI,CACV,4BACAQ,cACAzB,KACA;QAGJ8B,SAASA,UAAU9B,IAAI,MAAM;IAC/B;IAEA,IAAI,CAAC8B,QAAQ,YACX9D,WACE,gEACAgC;IAKJ,MAAMkC,gBAAgB,AAAkB,YAAlB,OAAOJ,SAAsBA,SAASA,OAAO,MAAM;IACzE,MAAMK,UAAUnC,KAAK,SAAS,UAAUL;IACxC,MAAMyC,kBAAkBpC;IAGxB8B,SAASO,6BACPP,QACA9B,KAAK,SACLoC,iBAAiB,CAACE,iCAAiC;IAGrD,MAAMC,mBAAmBxC,wBAAwBC;IACjD,IAAIuC,kBACFT,SACE,AAAkB,YAAlB,OAAOA,SACH;QACEA;QACA,GAAGS,gBAAgB;IACrB,IACA;QACE,GAAGT,MAAM;QACT,GAAGS,gBAAgB;IACrB;IAGR,OAAO;QACLT;QACA,GAAIK,UAAU;YAAED;YAAeC;QAAQ,IAAI,CAAC,CAAC;QAC7CJ;QACAC;QACAC;IACF;AACF;AAEO,SAASO,sCACdf,YAAyB,EACzBzB,GAA6B,EAC7ByC,cAAwB,EAAE;IAK1B,MAAMF,mBAAmBxC,wBAAwBC;IACjD,MAAM0C,cAAclB,yBAAyBC,cAAczB;IAG3D,MAAM2C,aAAkC,CAAC;IAEzC,IAAI,AAAe,YAAf,OAAO3C,OAAoBA,AAAQ,SAARA,KAAc;QAE3C,MAAM4C,UAAU9C,OAAO,IAAI,CAACE;QAG5B,MAAM6C,kBAAkB/C,OAAO,IAAI,CAAC4C,eAAe,CAAC;QACpD,MAAMI,uBACJ,AAA+B,YAA/B,OAAOJ,aAAa,UAAuBA,aAAa,WAAW,OAC/D5C,OAAO,IAAI,CAACyC,oBAAoB,CAAC,KACjC,EAAE;QAGR,KAAK,MAAMtC,OAAO2C,QAChB,IACE,CAACC,gBAAgB,QAAQ,CAAC5C,QAC1BA,AAAQ,cAARA,OACAA,QAAQqC,oCACRrC,AAAQ,gBAARA,OACA,CAAC6C,qBAAqB,QAAQ,CAAC7C,QAC/B,CAACwC,YAAY,QAAQ,CAACxC,QACtBA,AAAQ,aAARA,KAEA0C,UAAU,CAAC1C,IAAI,GAAGD,GAAG,CAACC,IAA0B;IAGtD;IAEA,OAAO;QACLyC;QACAC;IACF;AACF"}