@midscene/core 1.17.3 → 1.17.4

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (44) hide show
  1. package/dist/es/agent/agent-report-manager.mjs +1 -0
  2. package/dist/es/agent/agent-report-manager.mjs.map +1 -1
  3. package/dist/es/agent/agent.mjs +7 -0
  4. package/dist/es/agent/agent.mjs.map +1 -1
  5. package/dist/es/agent/test-runner-nodes.mjs +2 -0
  6. package/dist/es/agent/test-runner-nodes.mjs.map +1 -1
  7. package/dist/es/agent/utils.mjs +1 -1
  8. package/dist/es/ai-model/model-adapter/default-planning-protocol.mjs +32 -17
  9. package/dist/es/ai-model/model-adapter/default-planning-protocol.mjs.map +1 -1
  10. package/dist/es/ai-model/prompt/describe.mjs +14 -14
  11. package/dist/es/ai-model/prompt/describe.mjs.map +1 -1
  12. package/dist/es/device/index.mjs +20 -1
  13. package/dist/es/device/index.mjs.map +1 -1
  14. package/dist/es/report-html-template.mjs +1 -1
  15. package/dist/es/service/index.mjs +2 -2
  16. package/dist/es/service/index.mjs.map +1 -1
  17. package/dist/es/utils.mjs +1 -1
  18. package/dist/lib/agent/agent-report-manager.js +1 -0
  19. package/dist/lib/agent/agent-report-manager.js.map +1 -1
  20. package/dist/lib/agent/agent.js +7 -0
  21. package/dist/lib/agent/agent.js.map +1 -1
  22. package/dist/lib/agent/test-runner-nodes.js +2 -0
  23. package/dist/lib/agent/test-runner-nodes.js.map +1 -1
  24. package/dist/lib/agent/utils.js +1 -1
  25. package/dist/lib/ai-model/model-adapter/default-planning-protocol.js +31 -16
  26. package/dist/lib/ai-model/model-adapter/default-planning-protocol.js.map +1 -1
  27. package/dist/lib/ai-model/prompt/describe.js +14 -14
  28. package/dist/lib/ai-model/prompt/describe.js.map +1 -1
  29. package/dist/lib/device/index.js +27 -2
  30. package/dist/lib/device/index.js.map +1 -1
  31. package/dist/lib/report-html-template.js +1 -1
  32. package/dist/lib/service/index.js +2 -2
  33. package/dist/lib/service/index.js.map +1 -1
  34. package/dist/lib/utils.js +1 -1
  35. package/dist/types/agent/agent-report-manager.d.ts.map +1 -1
  36. package/dist/types/agent/agent.d.ts +7 -0
  37. package/dist/types/agent/agent.d.ts.map +1 -1
  38. package/dist/types/agent/test-runner-nodes.d.ts +1 -0
  39. package/dist/types/agent/test-runner-nodes.d.ts.map +1 -1
  40. package/dist/types/ai-model/model-adapter/default-planning-protocol.d.ts +3 -0
  41. package/dist/types/ai-model/model-adapter/default-planning-protocol.d.ts.map +1 -1
  42. package/dist/types/device/index.d.ts +152 -0
  43. package/dist/types/device/index.d.ts.map +1 -1
  44. package/package.json +2 -2
@@ -361,7 +361,7 @@ class Service {
361
361
  imageContent = [
362
362
  {
363
363
  type: 'text',
364
- text: 'Use these images together to describe the real UI target marked by the temporary callout. Do not describe the marker itself.'
364
+ text: 'Use these images together to describe the real UI target marked by the temporary target marker. Do not describe the marker itself.'
365
365
  },
366
366
  {
367
367
  type: 'text',
@@ -376,7 +376,7 @@ class Service {
376
376
  } else imageContent = [
377
377
  {
378
378
  type: 'text',
379
- text: 'Full screenshot with a temporary callout marking the target:'
379
+ text: 'Full screenshot with a temporary target marker (a ring with a crosshair) marking the target:'
380
380
  },
381
381
  {
382
382
  type: 'image',
@@ -1 +1 @@
1
- {"version":3,"file":"service/index.mjs","sources":["../../../src/service/index.ts"],"sourcesContent":["import type { ModelRuntime } from '@/ai-model/models';\nimport { elementDescriberInstruction } from '@/ai-model/prompt/describe';\nimport {\n AIResponseParseError,\n callAIWithObjectResponse,\n} from '@/ai-model/service-caller';\nimport type { ModelCallMessages } from '@/ai-model/service-caller/types';\nimport type { MessageContent } from '@/ai-model/service-caller/types';\nimport { modelFamilyRequiredForLocateMessage } from '@/ai-model/shared/model-locate-result/errors';\nimport {\n AiLocateElement,\n AiLocateSection,\n buildSearchAreaConfig,\n} from '@/ai-model/workflows/grounding';\nimport { mergeSearchAreaResults } from '@/ai-model/workflows/grounding/search-area';\nimport type { SearchAreaConfig } from '@/ai-model/workflows/grounding/types';\nimport { AiExtractElementInfo } from '@/ai-model/workflows/insight';\nimport type { RawAssistantOutput } from '@/types';\nimport type {\n AIDescribeElementResponse,\n AIUsageInfo,\n DetailedLocateParam,\n LocateResultElement,\n LocateResultWithDump,\n PartialServiceDumpFromSDK,\n Rect,\n ServiceExtractOption,\n ServiceExtractParam,\n ServiceExtractResult,\n ServiceTaskInfo,\n UIContext,\n} from '@/types';\nimport { ServiceError } from '@/types';\nimport {\n compositeElementInfoImg,\n compositePointMarkerImg,\n cropByRect,\n resizeBase64ImageToJpeg,\n} from '@midscene/shared/img';\nimport { getDebug } from '@midscene/shared/logger';\nimport { assert } from '@midscene/shared/utils';\nimport type { TMultimodalPrompt, TUserPrompt } from '../common';\nimport {\n createServiceDump,\n getDescribeDeepContextAreas,\n getDescribeDeepLocateResizeSize,\n getDescribeMarkerBorderThickness,\n getDescribeMarkerRect,\n getRectInCrop,\n recoverDescribeResponseFromParseError,\n} from './utils';\n\nexport interface LocateOpts {\n context?: UIContext;\n planLocatedElement?: LocateResultElement;\n}\n\nexport type AnyValue<T> = {\n [K in keyof T]: unknown extends T[K] ? any : T[K];\n};\n\ninterface ServiceOptions {\n taskInfo?: Omit<ServiceTaskInfo, 'durationMs'>;\n}\n\ninterface LocateSearchAreaResult {\n config?: SearchAreaConfig;\n error?: string;\n trace: {\n sourceRect?: Rect;\n rawResponse?: string;\n rawAssistantOutput?: RawAssistantOutput;\n usage?: AIUsageInfo;\n };\n}\n\nconst debug = getDebug('ai:service');\n\nexport default class Service {\n contextRetrieverFn: (signal?: AbortSignal) => Promise<UIContext> | UIContext;\n\n taskInfo?: Omit<ServiceTaskInfo, 'durationMs'>;\n\n constructor(\n context:\n | UIContext\n | ((signal?: AbortSignal) => Promise<UIContext> | UIContext),\n opt?: ServiceOptions,\n ) {\n assert(context, 'context is required for Service');\n if (typeof context === 'function') {\n this.contextRetrieverFn = context;\n } else {\n this.contextRetrieverFn = () => Promise.resolve(context);\n }\n\n if (typeof opt?.taskInfo !== 'undefined') {\n this.taskInfo = opt.taskInfo;\n }\n }\n\n async locate(\n query: DetailedLocateParam,\n opt: LocateOpts,\n modelRuntime: ModelRuntime,\n abortSignal?: AbortSignal,\n ): Promise<LocateResultWithDump> {\n const { config: modelConfig } = modelRuntime;\n const queryPrompt = query.prompt;\n assert(queryPrompt, 'query is required for locate');\n\n if (!modelConfig.modelFamily) {\n throw new Error(modelFamilyRequiredForLocateMessage(modelConfig.slot));\n }\n\n const context = opt?.context || (await this.contextRetrieverFn());\n\n const searchAreaStartTime = Date.now();\n const searchArea = await this.resolveLocateSearchArea({\n query,\n queryPrompt,\n opt,\n context,\n modelRuntime,\n abortSignal,\n });\n\n if (!searchArea.config && searchArea.error) {\n const errorMessage = `cannot find search area for \"${queryPrompt}\": ${searchArea.error}`;\n const taskInfo: ServiceTaskInfo = {\n ...(this.taskInfo ? this.taskInfo : {}),\n durationMs: Date.now() - searchAreaStartTime,\n searchAreaRawResponse: searchArea.trace.rawResponse,\n searchAreaRawChoiceMessage: searchArea.trace.rawAssistantOutput,\n searchAreaUsage: searchArea.trace.usage,\n };\n const dump = createServiceDump({\n type: 'locate',\n userQuery: { element: queryPrompt },\n matchedElement: [],\n data: null,\n taskInfo,\n deepLocate: true,\n error: errorMessage,\n });\n throw new ServiceError(errorMessage, dump);\n }\n\n const startTime = Date.now();\n const {\n parseResult,\n rawResponse,\n rawAssistantOutput,\n usage,\n reasoning_content,\n } = await AiLocateElement({\n context,\n targetElementDescription: queryPrompt,\n searchConfig: searchArea.config,\n modelRuntime,\n abortSignal,\n });\n\n const timeCost = Date.now() - startTime;\n const taskInfo: ServiceTaskInfo = {\n ...(this.taskInfo ? this.taskInfo : {}),\n durationMs: timeCost,\n rawResponse,\n rawAssistantOutput,\n formatResponse: parseResult,\n usage,\n searchArea: searchArea.trace.sourceRect,\n searchAreaRawResponse: searchArea.trace.rawResponse,\n searchAreaRawChoiceMessage: searchArea.trace.rawAssistantOutput,\n searchAreaUsage: searchArea.trace.usage,\n reasoning_content,\n };\n\n let errorLog: string | undefined;\n if (parseResult.errors?.length) {\n errorLog = `failed to locate element: \\n${parseResult.errors.join('\\n')}`;\n }\n\n const dumpData: PartialServiceDumpFromSDK = {\n type: 'locate',\n userQuery: {\n element: queryPrompt,\n },\n data: null,\n taskInfo,\n deepLocate: !!searchArea.trace.sourceRect,\n error: errorLog,\n };\n\n const element = parseResult.element;\n\n const dump = createServiceDump({\n ...dumpData,\n matchedElement: element ? [element] : [],\n });\n\n if (errorLog) {\n throw new ServiceError(errorLog, dump);\n }\n\n if (element) {\n return {\n element: {\n center: element.center,\n description: element.description,\n ...(element.rect ? { rect: element.rect } : {}),\n },\n dump,\n };\n }\n\n return {\n element: null,\n dump,\n };\n }\n\n private async resolveLocateSearchArea(options: {\n query: DetailedLocateParam;\n queryPrompt: TUserPrompt;\n opt: LocateOpts;\n context: UIContext;\n modelRuntime: ModelRuntime;\n abortSignal?: AbortSignal;\n }): Promise<LocateSearchAreaResult> {\n const { query, queryPrompt, opt, context, modelRuntime, abortSignal } =\n options;\n const { adapter } = modelRuntime;\n const hasPlanLocatedElement = !!opt?.planLocatedElement?.center;\n\n if (!query.deepLocate) {\n return { trace: {} };\n }\n\n // TODO: Make the plan, section-locate, and element-locate fallback paths\n // resolve only the source rect, then build the search-area config once in\n // this orchestration layer instead of building it inside AiLocateSection.\n if (hasPlanLocatedElement) {\n const config = await buildSearchAreaConfig({\n context,\n baseRect: mergeSearchAreaResults(opt.planLocatedElement!),\n });\n\n return {\n config,\n trace: {\n sourceRect: config.sourceRect,\n rawResponse: JSON.stringify({\n source: 'plan-located-element',\n center: opt.planLocatedElement!.center,\n rect: opt.planLocatedElement!.rect,\n }),\n },\n };\n }\n\n if (adapter.locate.kind === 'standard' && adapter.locate.searchArea) {\n const searchAreaResponse = await AiLocateSection({\n context,\n sectionDescription: queryPrompt,\n modelRuntime,\n abortSignal,\n });\n const { searchAreaConfig } = searchAreaResponse;\n if (!searchAreaConfig) {\n return {\n error: searchAreaResponse.error || 'unknown search area error',\n trace: {\n rawResponse: searchAreaResponse.rawResponse,\n rawAssistantOutput: searchAreaResponse.rawAssistantOutput,\n usage: searchAreaResponse.usage,\n },\n };\n }\n\n return {\n config: searchAreaConfig,\n trace: {\n sourceRect: searchAreaConfig.sourceRect,\n rawResponse: searchAreaResponse.rawResponse,\n rawAssistantOutput: searchAreaResponse.rawAssistantOutput,\n usage: searchAreaResponse.usage,\n },\n };\n }\n\n const firstPassLocateResult = await AiLocateElement({\n context,\n targetElementDescription: queryPrompt,\n modelRuntime,\n abortSignal,\n });\n assert(\n firstPassLocateResult.parseResult.element?.center,\n `cannot find search area for \"${queryPrompt}\"${\n firstPassLocateResult.parseResult.errors?.length\n ? `: ${firstPassLocateResult.parseResult.errors.join('\\n')}`\n : ''\n }`,\n );\n\n const config = await buildSearchAreaConfig({\n context,\n baseRect: mergeSearchAreaResults(\n firstPassLocateResult.parseResult.element!,\n ),\n });\n\n return {\n config,\n trace: {\n sourceRect: config.sourceRect,\n rawResponse: JSON.stringify({\n source: 'deep-locate-first-pass',\n center: firstPassLocateResult.parseResult.element?.center,\n rect: firstPassLocateResult.parseResult.element?.rect,\n rawResponse: firstPassLocateResult.rawResponse,\n }),\n rawAssistantOutput: firstPassLocateResult.rawAssistantOutput,\n usage: firstPassLocateResult.usage,\n },\n };\n }\n\n async extract<T>(\n dataDemand: ServiceExtractParam,\n modelRuntime: ModelRuntime,\n taskType: 'boolean' | 'extract',\n opt?: ServiceExtractOption,\n pageDescription?: string,\n multimodalPrompt?: TMultimodalPrompt,\n context?: UIContext,\n executionOptions?: {\n abortSignal?: AbortSignal;\n },\n ): Promise<ServiceExtractResult<T>> {\n assert(context, 'context is required for extract');\n assert(\n typeof dataDemand === 'object' || typeof dataDemand === 'string',\n `dataDemand should be object or string, but get ${typeof dataDemand}`,\n );\n\n const startTime = Date.now();\n\n let parseResult: Awaited<\n ReturnType<typeof AiExtractElementInfo<T>>\n >['parseResult'];\n let rawResponse: string;\n let rawAssistantOutput: RawAssistantOutput | undefined;\n let usage: Awaited<ReturnType<typeof AiExtractElementInfo<T>>>['usage'];\n let reasoning_content: string | undefined;\n\n try {\n const result = await AiExtractElementInfo<T>({\n context,\n dataQuery: dataDemand,\n taskType,\n multimodalPrompt,\n extractOption: opt,\n modelRuntime,\n pageDescription,\n abortSignal: executionOptions?.abortSignal,\n });\n parseResult = result.parseResult;\n rawResponse = result.rawResponse;\n rawAssistantOutput = result.rawAssistantOutput;\n usage = result.usage;\n reasoning_content = result.reasoning_content;\n } catch (error) {\n if (error instanceof AIResponseParseError) {\n // Create dump with usage and rawResponse from the error\n const timeCost = Date.now() - startTime;\n const taskInfo: ServiceTaskInfo = {\n ...(this.taskInfo ? this.taskInfo : {}),\n durationMs: timeCost,\n rawResponse: error.rawResponse,\n rawAssistantOutput: error.rawAssistantOutput,\n usage: error.usage,\n };\n const dump = createServiceDump({\n type: 'extract',\n userQuery: { dataDemand },\n data: null,\n taskInfo,\n error: error.message,\n });\n throw new ServiceError(error.message, dump);\n }\n throw error;\n }\n\n const timeCost = Date.now() - startTime;\n const taskInfo: ServiceTaskInfo = {\n ...(this.taskInfo ? this.taskInfo : {}),\n durationMs: timeCost,\n rawResponse,\n rawAssistantOutput,\n formatResponse: parseResult,\n usage,\n reasoning_content,\n };\n\n let errorLog: string | undefined;\n if (parseResult.errors?.length) {\n errorLog = `AI response error: \\n${parseResult.errors.join('\\n')}`;\n }\n\n const dumpData: PartialServiceDumpFromSDK = {\n type: 'extract',\n userQuery: {\n dataDemand,\n },\n data: null,\n taskInfo,\n error: errorLog,\n };\n\n const { data, thought } = parseResult || {};\n\n const dump = createServiceDump({\n ...dumpData,\n data,\n });\n\n if (errorLog && !data) {\n throw new ServiceError(errorLog, dump);\n }\n\n return {\n data,\n thought,\n usage,\n reasoning_content,\n dump,\n };\n }\n\n async describe(\n target: Rect | [number, number],\n modelRuntime: ModelRuntime,\n opt?: {\n deepDescribe?: boolean;\n context?: UIContext;\n },\n ): Promise<Pick<AIDescribeElementResponse, 'description'>> {\n assert(target, 'target is required for service.describe');\n const context = opt?.context || (await this.contextRetrieverFn());\n const { shotSize } = context;\n const screenshotBase64 = context.screenshot.base64;\n assert(screenshotBase64, 'screenshot is required for service.describe');\n const systemPrompt = elementDescriberInstruction();\n\n // Convert [x,y] center point to Rect if needed\n const defaultRectSize = 30;\n const targetFromPoint = Array.isArray(target);\n const targetRect: Rect = targetFromPoint\n ? {\n left: Math.floor(target[0] - defaultRectSize / 2),\n top: Math.floor(target[1] - defaultRectSize / 2),\n width: defaultRectSize,\n height: defaultRectSize,\n }\n : target;\n const targetPoint = targetFromPoint\n ? {\n x: target[0],\n y: target[1],\n }\n : undefined;\n\n const usePointMarker = targetFromPoint;\n const imagePayload = usePointMarker\n ? await compositePointMarkerImg({\n inputImgBase64: screenshotBase64,\n size: shotSize,\n point: targetPoint!,\n })\n : await compositeElementInfoImg({\n inputImgBase64: screenshotBase64,\n size: shotSize,\n elementsPositionInfo: [\n {\n rect: getDescribeMarkerRect(targetRect),\n },\n ],\n borderThickness: getDescribeMarkerBorderThickness(targetRect),\n centerPoint: true,\n });\n\n const shouldDeepDescribe = opt?.deepDescribe;\n let imageContent: MessageContent[];\n if (shouldDeepDescribe) {\n const contextAreas = getDescribeDeepContextAreas(targetRect, shotSize);\n const contextImages = await Promise.all(\n contextAreas.map(async (area) => {\n debug('describe: cropping deep context area', area);\n const croppedResult = await cropByRect(screenshotBase64, area.rect);\n const cropSize = {\n width: croppedResult.width,\n height: croppedResult.height,\n };\n const targetInCrop = getRectInCrop(targetRect, area.rect, cropSize);\n const markedCropPayload = targetFromPoint\n ? await compositePointMarkerImg({\n inputImgBase64: croppedResult.imageBase64,\n size: cropSize,\n point: {\n x: targetPoint!.x - area.rect.left,\n y: targetPoint!.y - area.rect.top,\n },\n })\n : await compositeElementInfoImg({\n inputImgBase64: croppedResult.imageBase64,\n size: cropSize,\n elementsPositionInfo: [\n {\n rect: getDescribeMarkerRect(targetInCrop),\n },\n ],\n borderThickness: getDescribeMarkerBorderThickness(targetInCrop),\n centerPoint: true,\n });\n const resizeSize = getDescribeDeepLocateResizeSize(croppedResult);\n return {\n kind: area.kind,\n imageBase64: resizeSize\n ? await resizeBase64ImageToJpeg(markedCropPayload, {\n sourceSize: cropSize,\n targetSize: resizeSize,\n })\n : markedCropPayload,\n };\n }),\n );\n const contextImageContent = contextImages.flatMap<MessageContent>(\n (item, index) => [\n {\n type: 'text',\n text: `Image ${index + 2}: focused detail crop around the target, for reading text, icon shape, and exact local boundaries.`,\n },\n {\n type: 'image',\n url: item.imageBase64,\n },\n ],\n );\n\n imageContent = [\n {\n type: 'text' as const,\n text: 'Use these images together to describe the real UI target marked by the temporary callout. Do not describe the marker itself.',\n },\n {\n type: 'text' as const,\n text: 'Image 1: full screenshot overview with the target marker, for page position and ownership context.',\n },\n {\n type: 'image' as const,\n url: imagePayload,\n },\n ...contextImageContent,\n ];\n } else {\n imageContent = [\n {\n type: 'text' as const,\n text: 'Full screenshot with a temporary callout marking the target:',\n },\n {\n type: 'image' as const,\n url: imagePayload,\n },\n ];\n }\n\n const msgs: ModelCallMessages = [\n { role: 'system', content: systemPrompt },\n {\n role: 'user',\n content: imageContent,\n },\n ];\n\n let res: Awaited<\n ReturnType<typeof callAIWithObjectResponse<AIDescribeElementResponse>>\n >;\n try {\n res = await callAIWithObjectResponse<AIDescribeElementResponse>(\n msgs,\n modelRuntime,\n );\n } catch (error) {\n const recoveredResponse = recoverDescribeResponseFromParseError(error);\n if (!recoveredResponse) {\n throw error;\n }\n debug('describe: recovered malformed description JSON response');\n return recoveredResponse;\n }\n\n const { content } = res;\n assert(!content.error, `describe failed: ${content.error}`);\n assert(content.description, 'failed to describe the element');\n return content;\n }\n}\n"],"names":["debug","getDebug","Service","query","opt","modelRuntime","abortSignal","modelConfig","queryPrompt","assert","Error","modelFamilyRequiredForLocateMessage","context","searchAreaStartTime","Date","searchArea","errorMessage","taskInfo","dump","createServiceDump","ServiceError","startTime","parseResult","rawResponse","rawAssistantOutput","usage","reasoning_content","AiLocateElement","timeCost","errorLog","dumpData","element","options","adapter","hasPlanLocatedElement","config","buildSearchAreaConfig","mergeSearchAreaResults","JSON","searchAreaResponse","AiLocateSection","searchAreaConfig","firstPassLocateResult","dataDemand","taskType","pageDescription","multimodalPrompt","executionOptions","result","AiExtractElementInfo","error","AIResponseParseError","data","thought","target","shotSize","screenshotBase64","systemPrompt","elementDescriberInstruction","defaultRectSize","targetFromPoint","Array","targetRect","Math","targetPoint","undefined","usePointMarker","imagePayload","compositePointMarkerImg","compositeElementInfoImg","getDescribeMarkerRect","getDescribeMarkerBorderThickness","shouldDeepDescribe","imageContent","contextAreas","getDescribeDeepContextAreas","contextImages","Promise","area","croppedResult","cropByRect","cropSize","targetInCrop","getRectInCrop","markedCropPayload","resizeSize","getDescribeDeepLocateResizeSize","resizeBase64ImageToJpeg","contextImageContent","item","index","msgs","res","callAIWithObjectResponse","recoveredResponse","recoverDescribeResponseFromParseError","content"],"mappings":"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"}
1
+ {"version":3,"file":"service/index.mjs","sources":["../../../src/service/index.ts"],"sourcesContent":["import type { ModelRuntime } from '@/ai-model/models';\nimport { elementDescriberInstruction } from '@/ai-model/prompt/describe';\nimport {\n AIResponseParseError,\n callAIWithObjectResponse,\n} from '@/ai-model/service-caller';\nimport type { ModelCallMessages } from '@/ai-model/service-caller/types';\nimport type { MessageContent } from '@/ai-model/service-caller/types';\nimport { modelFamilyRequiredForLocateMessage } from '@/ai-model/shared/model-locate-result/errors';\nimport {\n AiLocateElement,\n AiLocateSection,\n buildSearchAreaConfig,\n} from '@/ai-model/workflows/grounding';\nimport { mergeSearchAreaResults } from '@/ai-model/workflows/grounding/search-area';\nimport type { SearchAreaConfig } from '@/ai-model/workflows/grounding/types';\nimport { AiExtractElementInfo } from '@/ai-model/workflows/insight';\nimport type { RawAssistantOutput } from '@/types';\nimport type {\n AIDescribeElementResponse,\n AIUsageInfo,\n DetailedLocateParam,\n LocateResultElement,\n LocateResultWithDump,\n PartialServiceDumpFromSDK,\n Rect,\n ServiceExtractOption,\n ServiceExtractParam,\n ServiceExtractResult,\n ServiceTaskInfo,\n UIContext,\n} from '@/types';\nimport { ServiceError } from '@/types';\nimport {\n compositeElementInfoImg,\n compositePointMarkerImg,\n cropByRect,\n resizeBase64ImageToJpeg,\n} from '@midscene/shared/img';\nimport { getDebug } from '@midscene/shared/logger';\nimport { assert } from '@midscene/shared/utils';\nimport type { TMultimodalPrompt, TUserPrompt } from '../common';\nimport {\n createServiceDump,\n getDescribeDeepContextAreas,\n getDescribeDeepLocateResizeSize,\n getDescribeMarkerBorderThickness,\n getDescribeMarkerRect,\n getRectInCrop,\n recoverDescribeResponseFromParseError,\n} from './utils';\n\nexport interface LocateOpts {\n context?: UIContext;\n planLocatedElement?: LocateResultElement;\n}\n\nexport type AnyValue<T> = {\n [K in keyof T]: unknown extends T[K] ? any : T[K];\n};\n\ninterface ServiceOptions {\n taskInfo?: Omit<ServiceTaskInfo, 'durationMs'>;\n}\n\ninterface LocateSearchAreaResult {\n config?: SearchAreaConfig;\n error?: string;\n trace: {\n sourceRect?: Rect;\n rawResponse?: string;\n rawAssistantOutput?: RawAssistantOutput;\n usage?: AIUsageInfo;\n };\n}\n\nconst debug = getDebug('ai:service');\n\nexport default class Service {\n contextRetrieverFn: (signal?: AbortSignal) => Promise<UIContext> | UIContext;\n\n taskInfo?: Omit<ServiceTaskInfo, 'durationMs'>;\n\n constructor(\n context:\n | UIContext\n | ((signal?: AbortSignal) => Promise<UIContext> | UIContext),\n opt?: ServiceOptions,\n ) {\n assert(context, 'context is required for Service');\n if (typeof context === 'function') {\n this.contextRetrieverFn = context;\n } else {\n this.contextRetrieverFn = () => Promise.resolve(context);\n }\n\n if (typeof opt?.taskInfo !== 'undefined') {\n this.taskInfo = opt.taskInfo;\n }\n }\n\n async locate(\n query: DetailedLocateParam,\n opt: LocateOpts,\n modelRuntime: ModelRuntime,\n abortSignal?: AbortSignal,\n ): Promise<LocateResultWithDump> {\n const { config: modelConfig } = modelRuntime;\n const queryPrompt = query.prompt;\n assert(queryPrompt, 'query is required for locate');\n\n if (!modelConfig.modelFamily) {\n throw new Error(modelFamilyRequiredForLocateMessage(modelConfig.slot));\n }\n\n const context = opt?.context || (await this.contextRetrieverFn());\n\n const searchAreaStartTime = Date.now();\n const searchArea = await this.resolveLocateSearchArea({\n query,\n queryPrompt,\n opt,\n context,\n modelRuntime,\n abortSignal,\n });\n\n if (!searchArea.config && searchArea.error) {\n const errorMessage = `cannot find search area for \"${queryPrompt}\": ${searchArea.error}`;\n const taskInfo: ServiceTaskInfo = {\n ...(this.taskInfo ? this.taskInfo : {}),\n durationMs: Date.now() - searchAreaStartTime,\n searchAreaRawResponse: searchArea.trace.rawResponse,\n searchAreaRawChoiceMessage: searchArea.trace.rawAssistantOutput,\n searchAreaUsage: searchArea.trace.usage,\n };\n const dump = createServiceDump({\n type: 'locate',\n userQuery: { element: queryPrompt },\n matchedElement: [],\n data: null,\n taskInfo,\n deepLocate: true,\n error: errorMessage,\n });\n throw new ServiceError(errorMessage, dump);\n }\n\n const startTime = Date.now();\n const {\n parseResult,\n rawResponse,\n rawAssistantOutput,\n usage,\n reasoning_content,\n } = await AiLocateElement({\n context,\n targetElementDescription: queryPrompt,\n searchConfig: searchArea.config,\n modelRuntime,\n abortSignal,\n });\n\n const timeCost = Date.now() - startTime;\n const taskInfo: ServiceTaskInfo = {\n ...(this.taskInfo ? this.taskInfo : {}),\n durationMs: timeCost,\n rawResponse,\n rawAssistantOutput,\n formatResponse: parseResult,\n usage,\n searchArea: searchArea.trace.sourceRect,\n searchAreaRawResponse: searchArea.trace.rawResponse,\n searchAreaRawChoiceMessage: searchArea.trace.rawAssistantOutput,\n searchAreaUsage: searchArea.trace.usage,\n reasoning_content,\n };\n\n let errorLog: string | undefined;\n if (parseResult.errors?.length) {\n errorLog = `failed to locate element: \\n${parseResult.errors.join('\\n')}`;\n }\n\n const dumpData: PartialServiceDumpFromSDK = {\n type: 'locate',\n userQuery: {\n element: queryPrompt,\n },\n data: null,\n taskInfo,\n deepLocate: !!searchArea.trace.sourceRect,\n error: errorLog,\n };\n\n const element = parseResult.element;\n\n const dump = createServiceDump({\n ...dumpData,\n matchedElement: element ? [element] : [],\n });\n\n if (errorLog) {\n throw new ServiceError(errorLog, dump);\n }\n\n if (element) {\n return {\n element: {\n center: element.center,\n description: element.description,\n ...(element.rect ? { rect: element.rect } : {}),\n },\n dump,\n };\n }\n\n return {\n element: null,\n dump,\n };\n }\n\n private async resolveLocateSearchArea(options: {\n query: DetailedLocateParam;\n queryPrompt: TUserPrompt;\n opt: LocateOpts;\n context: UIContext;\n modelRuntime: ModelRuntime;\n abortSignal?: AbortSignal;\n }): Promise<LocateSearchAreaResult> {\n const { query, queryPrompt, opt, context, modelRuntime, abortSignal } =\n options;\n const { adapter } = modelRuntime;\n const hasPlanLocatedElement = !!opt?.planLocatedElement?.center;\n\n if (!query.deepLocate) {\n return { trace: {} };\n }\n\n // TODO: Make the plan, section-locate, and element-locate fallback paths\n // resolve only the source rect, then build the search-area config once in\n // this orchestration layer instead of building it inside AiLocateSection.\n if (hasPlanLocatedElement) {\n const config = await buildSearchAreaConfig({\n context,\n baseRect: mergeSearchAreaResults(opt.planLocatedElement!),\n });\n\n return {\n config,\n trace: {\n sourceRect: config.sourceRect,\n rawResponse: JSON.stringify({\n source: 'plan-located-element',\n center: opt.planLocatedElement!.center,\n rect: opt.planLocatedElement!.rect,\n }),\n },\n };\n }\n\n if (adapter.locate.kind === 'standard' && adapter.locate.searchArea) {\n const searchAreaResponse = await AiLocateSection({\n context,\n sectionDescription: queryPrompt,\n modelRuntime,\n abortSignal,\n });\n const { searchAreaConfig } = searchAreaResponse;\n if (!searchAreaConfig) {\n return {\n error: searchAreaResponse.error || 'unknown search area error',\n trace: {\n rawResponse: searchAreaResponse.rawResponse,\n rawAssistantOutput: searchAreaResponse.rawAssistantOutput,\n usage: searchAreaResponse.usage,\n },\n };\n }\n\n return {\n config: searchAreaConfig,\n trace: {\n sourceRect: searchAreaConfig.sourceRect,\n rawResponse: searchAreaResponse.rawResponse,\n rawAssistantOutput: searchAreaResponse.rawAssistantOutput,\n usage: searchAreaResponse.usage,\n },\n };\n }\n\n const firstPassLocateResult = await AiLocateElement({\n context,\n targetElementDescription: queryPrompt,\n modelRuntime,\n abortSignal,\n });\n assert(\n firstPassLocateResult.parseResult.element?.center,\n `cannot find search area for \"${queryPrompt}\"${\n firstPassLocateResult.parseResult.errors?.length\n ? `: ${firstPassLocateResult.parseResult.errors.join('\\n')}`\n : ''\n }`,\n );\n\n const config = await buildSearchAreaConfig({\n context,\n baseRect: mergeSearchAreaResults(\n firstPassLocateResult.parseResult.element!,\n ),\n });\n\n return {\n config,\n trace: {\n sourceRect: config.sourceRect,\n rawResponse: JSON.stringify({\n source: 'deep-locate-first-pass',\n center: firstPassLocateResult.parseResult.element?.center,\n rect: firstPassLocateResult.parseResult.element?.rect,\n rawResponse: firstPassLocateResult.rawResponse,\n }),\n rawAssistantOutput: firstPassLocateResult.rawAssistantOutput,\n usage: firstPassLocateResult.usage,\n },\n };\n }\n\n async extract<T>(\n dataDemand: ServiceExtractParam,\n modelRuntime: ModelRuntime,\n taskType: 'boolean' | 'extract',\n opt?: ServiceExtractOption,\n pageDescription?: string,\n multimodalPrompt?: TMultimodalPrompt,\n context?: UIContext,\n executionOptions?: {\n abortSignal?: AbortSignal;\n },\n ): Promise<ServiceExtractResult<T>> {\n assert(context, 'context is required for extract');\n assert(\n typeof dataDemand === 'object' || typeof dataDemand === 'string',\n `dataDemand should be object or string, but get ${typeof dataDemand}`,\n );\n\n const startTime = Date.now();\n\n let parseResult: Awaited<\n ReturnType<typeof AiExtractElementInfo<T>>\n >['parseResult'];\n let rawResponse: string;\n let rawAssistantOutput: RawAssistantOutput | undefined;\n let usage: Awaited<ReturnType<typeof AiExtractElementInfo<T>>>['usage'];\n let reasoning_content: string | undefined;\n\n try {\n const result = await AiExtractElementInfo<T>({\n context,\n dataQuery: dataDemand,\n taskType,\n multimodalPrompt,\n extractOption: opt,\n modelRuntime,\n pageDescription,\n abortSignal: executionOptions?.abortSignal,\n });\n parseResult = result.parseResult;\n rawResponse = result.rawResponse;\n rawAssistantOutput = result.rawAssistantOutput;\n usage = result.usage;\n reasoning_content = result.reasoning_content;\n } catch (error) {\n if (error instanceof AIResponseParseError) {\n // Create dump with usage and rawResponse from the error\n const timeCost = Date.now() - startTime;\n const taskInfo: ServiceTaskInfo = {\n ...(this.taskInfo ? this.taskInfo : {}),\n durationMs: timeCost,\n rawResponse: error.rawResponse,\n rawAssistantOutput: error.rawAssistantOutput,\n usage: error.usage,\n };\n const dump = createServiceDump({\n type: 'extract',\n userQuery: { dataDemand },\n data: null,\n taskInfo,\n error: error.message,\n });\n throw new ServiceError(error.message, dump);\n }\n throw error;\n }\n\n const timeCost = Date.now() - startTime;\n const taskInfo: ServiceTaskInfo = {\n ...(this.taskInfo ? this.taskInfo : {}),\n durationMs: timeCost,\n rawResponse,\n rawAssistantOutput,\n formatResponse: parseResult,\n usage,\n reasoning_content,\n };\n\n let errorLog: string | undefined;\n if (parseResult.errors?.length) {\n errorLog = `AI response error: \\n${parseResult.errors.join('\\n')}`;\n }\n\n const dumpData: PartialServiceDumpFromSDK = {\n type: 'extract',\n userQuery: {\n dataDemand,\n },\n data: null,\n taskInfo,\n error: errorLog,\n };\n\n const { data, thought } = parseResult || {};\n\n const dump = createServiceDump({\n ...dumpData,\n data,\n });\n\n if (errorLog && !data) {\n throw new ServiceError(errorLog, dump);\n }\n\n return {\n data,\n thought,\n usage,\n reasoning_content,\n dump,\n };\n }\n\n async describe(\n target: Rect | [number, number],\n modelRuntime: ModelRuntime,\n opt?: {\n deepDescribe?: boolean;\n context?: UIContext;\n },\n ): Promise<Pick<AIDescribeElementResponse, 'description'>> {\n assert(target, 'target is required for service.describe');\n const context = opt?.context || (await this.contextRetrieverFn());\n const { shotSize } = context;\n const screenshotBase64 = context.screenshot.base64;\n assert(screenshotBase64, 'screenshot is required for service.describe');\n const systemPrompt = elementDescriberInstruction();\n\n // Convert [x,y] center point to Rect if needed\n const defaultRectSize = 30;\n const targetFromPoint = Array.isArray(target);\n const targetRect: Rect = targetFromPoint\n ? {\n left: Math.floor(target[0] - defaultRectSize / 2),\n top: Math.floor(target[1] - defaultRectSize / 2),\n width: defaultRectSize,\n height: defaultRectSize,\n }\n : target;\n const targetPoint = targetFromPoint\n ? {\n x: target[0],\n y: target[1],\n }\n : undefined;\n\n const usePointMarker = targetFromPoint;\n const imagePayload = usePointMarker\n ? await compositePointMarkerImg({\n inputImgBase64: screenshotBase64,\n size: shotSize,\n point: targetPoint!,\n })\n : await compositeElementInfoImg({\n inputImgBase64: screenshotBase64,\n size: shotSize,\n elementsPositionInfo: [\n {\n rect: getDescribeMarkerRect(targetRect),\n },\n ],\n borderThickness: getDescribeMarkerBorderThickness(targetRect),\n centerPoint: true,\n });\n\n const shouldDeepDescribe = opt?.deepDescribe;\n let imageContent: MessageContent[];\n if (shouldDeepDescribe) {\n const contextAreas = getDescribeDeepContextAreas(targetRect, shotSize);\n const contextImages = await Promise.all(\n contextAreas.map(async (area) => {\n debug('describe: cropping deep context area', area);\n const croppedResult = await cropByRect(screenshotBase64, area.rect);\n const cropSize = {\n width: croppedResult.width,\n height: croppedResult.height,\n };\n const targetInCrop = getRectInCrop(targetRect, area.rect, cropSize);\n const markedCropPayload = targetFromPoint\n ? await compositePointMarkerImg({\n inputImgBase64: croppedResult.imageBase64,\n size: cropSize,\n point: {\n x: targetPoint!.x - area.rect.left,\n y: targetPoint!.y - area.rect.top,\n },\n })\n : await compositeElementInfoImg({\n inputImgBase64: croppedResult.imageBase64,\n size: cropSize,\n elementsPositionInfo: [\n {\n rect: getDescribeMarkerRect(targetInCrop),\n },\n ],\n borderThickness: getDescribeMarkerBorderThickness(targetInCrop),\n centerPoint: true,\n });\n const resizeSize = getDescribeDeepLocateResizeSize(croppedResult);\n return {\n kind: area.kind,\n imageBase64: resizeSize\n ? await resizeBase64ImageToJpeg(markedCropPayload, {\n sourceSize: cropSize,\n targetSize: resizeSize,\n })\n : markedCropPayload,\n };\n }),\n );\n const contextImageContent = contextImages.flatMap<MessageContent>(\n (item, index) => [\n {\n type: 'text',\n text: `Image ${index + 2}: focused detail crop around the target, for reading text, icon shape, and exact local boundaries.`,\n },\n {\n type: 'image',\n url: item.imageBase64,\n },\n ],\n );\n\n imageContent = [\n {\n type: 'text' as const,\n text: 'Use these images together to describe the real UI target marked by the temporary target marker. Do not describe the marker itself.',\n },\n {\n type: 'text' as const,\n text: 'Image 1: full screenshot overview with the target marker, for page position and ownership context.',\n },\n {\n type: 'image' as const,\n url: imagePayload,\n },\n ...contextImageContent,\n ];\n } else {\n imageContent = [\n {\n type: 'text' as const,\n text: 'Full screenshot with a temporary target marker (a ring with a crosshair) marking the target:',\n },\n {\n type: 'image' as const,\n url: imagePayload,\n },\n ];\n }\n\n const msgs: ModelCallMessages = [\n { role: 'system', content: systemPrompt },\n {\n role: 'user',\n content: imageContent,\n },\n ];\n\n let res: Awaited<\n ReturnType<typeof callAIWithObjectResponse<AIDescribeElementResponse>>\n >;\n try {\n res = await callAIWithObjectResponse<AIDescribeElementResponse>(\n msgs,\n modelRuntime,\n );\n } catch (error) {\n const recoveredResponse = recoverDescribeResponseFromParseError(error);\n if (!recoveredResponse) {\n throw error;\n }\n debug('describe: recovered malformed description JSON response');\n return recoveredResponse;\n }\n\n const { content } = res;\n assert(!content.error, `describe failed: ${content.error}`);\n assert(content.description, 'failed to describe the element');\n return content;\n }\n}\n"],"names":["debug","getDebug","Service","query","opt","modelRuntime","abortSignal","modelConfig","queryPrompt","assert","Error","modelFamilyRequiredForLocateMessage","context","searchAreaStartTime","Date","searchArea","errorMessage","taskInfo","dump","createServiceDump","ServiceError","startTime","parseResult","rawResponse","rawAssistantOutput","usage","reasoning_content","AiLocateElement","timeCost","errorLog","dumpData","element","options","adapter","hasPlanLocatedElement","config","buildSearchAreaConfig","mergeSearchAreaResults","JSON","searchAreaResponse","AiLocateSection","searchAreaConfig","firstPassLocateResult","dataDemand","taskType","pageDescription","multimodalPrompt","executionOptions","result","AiExtractElementInfo","error","AIResponseParseError","data","thought","target","shotSize","screenshotBase64","systemPrompt","elementDescriberInstruction","defaultRectSize","targetFromPoint","Array","targetRect","Math","targetPoint","undefined","usePointMarker","imagePayload","compositePointMarkerImg","compositeElementInfoImg","getDescribeMarkerRect","getDescribeMarkerBorderThickness","shouldDeepDescribe","imageContent","contextAreas","getDescribeDeepContextAreas","contextImages","Promise","area","croppedResult","cropByRect","cropSize","targetInCrop","getRectInCrop","markedCropPayload","resizeSize","getDescribeDeepLocateResizeSize","resizeBase64ImageToJpeg","contextImageContent","item","index","msgs","res","callAIWithObjectResponse","recoveredResponse","recoverDescribeResponseFromParseError","content"],"mappings":"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"}
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.17.3";
187
+ return "1.17.4";
188
188
  }
189
189
  function debugLog(...message) {
190
190
  const debugMode = process.env[MIDSCENE_DEBUG_MODE];
@@ -307,6 +307,7 @@ class AgentReportManager {
307
307
  this.dumpUpdateListeners = [];
308
308
  }
309
309
  notifyDumpUpdateListeners(executionDump) {
310
+ if (0 === this.dumpUpdateListeners.length) return;
310
311
  const dumpString = this.dumpDataString();
311
312
  for (const listener of this.dumpUpdateListeners)try {
312
313
  listener(dumpString, executionDump);
@@ -1 +1 @@
1
- {"version":3,"file":"agent/agent-report-manager.js","sources":["webpack/runtime/define_property_getters","webpack/runtime/has_own_property","webpack/runtime/make_namespace_object","../../../src/agent/agent-report-manager.ts"],"sourcesContent":["__webpack_require__.d = (exports, definition) => {\n\tfor(var key in definition) {\n if(__webpack_require__.o(definition, key) && !__webpack_require__.o(exports, key)) {\n Object.defineProperty(exports, key, { enumerable: true, get: definition[key] });\n }\n }\n};","__webpack_require__.o = (obj, prop) => (Object.prototype.hasOwnProperty.call(obj, prop))","// define __esModule on exports\n__webpack_require__.r = (exports) => {\n\tif(typeof Symbol !== 'undefined' && Symbol.toStringTag) {\n\t\tObject.defineProperty(exports, Symbol.toStringTag, { value: 'Module' });\n\t}\n\tObject.defineProperty(exports, '__esModule', { value: true });\n};","import { getDebug } from '@midscene/shared/logger';\nimport { assert, ifInBrowser, uuid } from '@midscene/shared/utils';\nimport { IS_REPORT_BUILD } from '../constants';\nimport { generateTestRunReportScriptTag } from '../dump/html-utils';\nimport { type IReportGenerator, ReportGenerator } from '../report-generator';\nimport type { TaskRunner } from '../task-runner';\nimport { WorkflowError } from '../test-runner/errors';\nimport type { WorkflowExecutionRecord } from '../test-runner/execution-record';\nimport { buildAgentTestRunReportDump } from '../test-runner/reporting/agent-report';\nimport { executionRecordsToReportInput } from '../test-runner/reporting/execution-record';\nimport {\n type AgentOpt,\n type ExecutionDump,\n ReportActionDump,\n type ReportMeta,\n} from '../types';\nimport { getVersion, reportHTMLContent } from '../utils';\nimport { getReportFileName } from './utils';\n\nconst warn = getDebug('agent', { console: true });\n\ntype ReportOptions = Pick<\n AgentOpt,\n | 'groupName'\n | 'groupDescription'\n | 'generateReport'\n | 'persistExecutionDump'\n | 'outputFormat'\n | 'autoPrintReportMsg'\n | 'reportAttributes'\n | 'reportFileName'\n | 'testId'\n>;\n\ninterface AgentReportContext {\n getOptions(): ReportOptions;\n getDeviceType(): ReportActionDump['deviceType'];\n isDestroyed(): boolean;\n isExternallyBusy(): boolean;\n}\n\ninterface AgentReportState {\n dump: ReportActionDump;\n file?: string | null;\n fileName?: string;\n generator: IReportGenerator;\n finalization?: Promise<string | undefined>;\n lastExecution?: ExecutionDump;\n executionIndexByRunner: WeakMap<TaskRunner, number>;\n yamlScopeId: string;\n yamlRecords: WorkflowExecutionRecord[];\n activeOperations: Set<Promise<unknown>>;\n}\n\n/** Owns report state and persistence; execution and device ownership stay with Agent. */\nexport class AgentReportManager {\n private reportState: AgentReportState;\n private reportReset?: Promise<ReportActionDump>;\n private readonly reportByRunner = new WeakMap<TaskRunner, AgentReportState>();\n private dumpUpdateListeners: Array<\n (dump: string, executionDump?: ExecutionDump) => void\n > = [];\n\n constructor(private readonly context: AgentReportContext) {\n const opts = this.opts;\n const fileName =\n opts.reportFileName ??\n getReportFileName(opts.testId || context.getDeviceType() || 'web');\n this.reportState = this.createReportState(\n fileName,\n opts.reportAttributes?.['data-group-id'] === fileName,\n );\n }\n\n private get opts(): ReportOptions {\n return this.context.getOptions();\n }\n\n get dump(): ReportActionDump {\n return this.reportState.dump;\n }\n set dump(value: ReportActionDump) {\n this.reportState.dump = value;\n }\n\n get reportFile(): string | null | undefined {\n return this.reportState.file;\n }\n set reportFile(value: string | null | undefined) {\n this.reportState.file = value;\n }\n\n get reportFileName(): string | undefined {\n return this.reportState.fileName;\n }\n set reportFileName(value: string | undefined) {\n this.reportState.fileName = value;\n }\n\n /** @internal Runner snapshots retain immutable data and shared image files. */\n _prepareForTestRunner(): void {\n this.reportState.generator.enableSourceSnapshots?.();\n }\n async _createReportSource(scopeId: string, executionIds?: readonly string[]) {\n return this.reportState.generator.createSourceSnapshot?.(\n scopeId,\n executionIds,\n );\n }\n\n /** @internal The Agent owns one report stream across root YAML invocations. */\n async _writeYamlExecutionReport(\n record: WorkflowExecutionRecord,\n ): Promise<string | undefined> {\n const report = this.reportState;\n const existingIndex = report.yamlRecords.findIndex(\n (entry) => entry.runId === record.runId,\n );\n const recordIndex =\n existingIndex < 0 ? report.yamlRecords.length : existingIndex;\n report.yamlRecords[recordIndex] = record;\n try {\n const path = await report.generator.writeRunnerReport?.(\n this.buildYamlReportInput(),\n report.yamlScopeId,\n this.getReportMeta(),\n );\n report.file = path ?? report.file;\n return path;\n } catch (error) {\n report.yamlRecords[recordIndex] = Object.freeze({\n ...record,\n status: 'failed',\n reportError: error,\n });\n throw error;\n }\n }\n\n private buildYamlReportInput() {\n const scopedRecords = this.reportState.yamlRecords.map((entry) => ({\n ...entry,\n ...(entry.execution\n ? {\n execution: {\n document: {\n ...entry.execution.document,\n reportScopeId: this.reportState.yamlScopeId,\n },\n cases: entry.execution.cases.map((outcome) => ({\n ...outcome,\n ...(outcome.run\n ? {\n run: {\n ...outcome.run,\n reportScopeId: this.reportState.yamlScopeId,\n },\n }\n : {}),\n ...(outcome.attempts\n ? {\n attempts: outcome.attempts.map((attempt) => ({\n ...attempt,\n reportScopeId: this.reportState.yamlScopeId,\n })),\n }\n : {}),\n })),\n },\n }\n : {}),\n }));\n return executionRecordsToReportInput(scopedRecords, {\n runId: this.reportState.yamlScopeId,\n });\n }\n\n private createEmptyDump(): ReportActionDump {\n return new ReportActionDump({\n sdkVersion: getVersion(),\n groupName: this.opts.groupName!,\n groupDescription: this.opts.groupDescription,\n executions: [],\n modelBriefs: [],\n deviceType: this.context.getDeviceType(),\n });\n }\n\n private createReportState(\n fileName: string,\n reuseExistingReport = false,\n ): AgentReportState {\n return {\n dump: this.createEmptyDump(),\n fileName,\n generator: ReportGenerator.create(fileName, {\n generateReport: this.opts.generateReport,\n persistExecutionDump: this.opts.persistExecutionDump,\n outputFormat: this.opts.outputFormat,\n autoPrintReportMsg: this.opts.autoPrintReportMsg,\n reuseExistingReport,\n }),\n executionIndexByRunner: new WeakMap(),\n yamlScopeId: uuid(),\n yamlRecords: [],\n activeOperations: new Set(),\n };\n }\n\n private clearDumpInMemory(report = this.reportState): void {\n report.dump = this.createEmptyDump();\n report.executionIndexByRunner = new WeakMap();\n report.lastExecution = undefined;\n report.yamlRecords.length = 0;\n }\n\n private assertReportIdle(): void {\n assert(\n !this.reportState.activeOperations.size &&\n !this.context.isExternallyBusy(),\n 'Cannot reset or finalize a report while the Agent is executing. Await the active operation first.',\n );\n }\n\n assertReportWritable(): AgentReportState {\n const report = this.reportState;\n assert(\n !this.context.isDestroyed(),\n 'Cannot execute using a destroyed Agent.',\n );\n assert(\n !this.reportReset,\n 'Report reset is in progress. Await resetDump() first.',\n );\n assert(\n !report.finalization,\n 'The report has been finalized. Call and await resetDump() before executing again.',\n );\n return report;\n }\n\n async withReportOperation<T>(operation: () => Promise<T>): Promise<T> {\n const report = this.assertReportWritable();\n const pending = Promise.resolve().then(operation);\n report.activeOperations.add(pending);\n try {\n return await pending;\n } finally {\n report.activeOperations.delete(pending);\n }\n }\n\n /**\n * Finalize the preceding report and reset execution records for a new report.\n * Historical artifacts are retained; this Agent and its device stay connected.\n * Await this method before executing again. Concurrent resets share one reset.\n */\n async resetDump(): Promise<ReportActionDump> {\n assert(\n !this.context.isDestroyed(),\n 'Cannot reset a report using a destroyed Agent.',\n );\n if (this.reportReset) return this.reportReset;\n this.assertReportIdle();\n this.reportReset = (async () => {\n try {\n await this.finalizeReport();\n } catch (error) {\n // Failure belongs to the preceding report, not to the next write queue.\n warn(\n `Failed to finalize previous report; resetting dump: ${String(error)}`,\n );\n }\n assert(\n !this.context.isDestroyed(),\n 'Cannot reset a report using a destroyed Agent.',\n );\n const fileName = getReportFileName(\n this.opts.testId || this.context.getDeviceType() || 'web',\n );\n this.reportState = this.createReportState(fileName);\n return this.dump;\n })();\n try {\n return await this.reportReset;\n } finally {\n this.reportReset = undefined;\n }\n }\n\n /**\n * Seal the current report and release its in-memory records without\n * disconnecting the device. Export in-memory data before calling this method.\n * Repeated calls return the same result and never rewrite published artifacts.\n */\n async finalizeReport(): Promise<string | undefined> {\n const report = this.reportState;\n if (!report.finalization) {\n this.assertReportIdle();\n report.finalization = (async () => {\n await report.generator.flush();\n const path = await report.generator.finalize();\n report.file = path;\n this.clearDumpInMemory(report);\n return path;\n })();\n }\n return report.finalization;\n }\n\n appendExecutionDump(execution: ExecutionDump, runner?: TaskRunner) {\n assert(\n !this.reportState.finalization,\n 'Cannot append to a finalized report. Await resetDump() first.',\n );\n const currentDump = this.dump;\n if (runner) {\n const existingIndex = this.reportState.executionIndexByRunner.get(runner);\n if (existingIndex !== undefined) {\n currentDump.executions[existingIndex] = execution;\n return;\n }\n currentDump.executions.push(execution);\n this.reportState.executionIndexByRunner.set(\n runner,\n currentDump.executions.length - 1,\n );\n return;\n }\n currentDump.executions.push(execution);\n }\n\n dumpDataString(opt?: { inlineScreenshots?: boolean }) {\n // update dump info\n this.dump.groupName = this.opts.groupName!;\n this.dump.groupDescription = this.opts.groupDescription;\n // In browser environment, use inline screenshots since file system is not available\n if (ifInBrowser || opt?.inlineScreenshots) {\n return this.dump.serializeWithInlineScreenshots();\n }\n return this.dump.serialize();\n }\n\n reportHTMLString(getDumpString: () => string) {\n // Short-circuit at the call site because JavaScript evaluates function\n // arguments first. This avoids serializing the dump (including inline\n // screenshots) when the Report Viewer build does not need report HTML.\n if (IS_REPORT_BUILD) {\n return '';\n }\n\n // dumpDataString() handles browser environment with inline screenshots\n const dumpString = getDumpString();\n if (!this.reportState.yamlRecords.length)\n return reportHTMLContent(dumpString);\n\n // Browser exports have no file writer, so the execution record must own\n // the hierarchy independently of whether file report generation is enabled.\n const reportId = this.reportState.yamlScopeId;\n const runnerDump = buildAgentTestRunReportDump(\n this.buildYamlReportInput(),\n this.dump,\n {\n reportId,\n scopeId: this.reportState.yamlScopeId,\n sourcePath: this.reportFile ?? '<inline-agent-report>',\n },\n );\n return `${reportHTMLContent({\n dumpString,\n attributes: { 'data-group-id': reportId, 'data-report-id': reportId },\n })}\\n${generateTestRunReportScriptTag(runnerDump)}`;\n }\n\n writeOutActionDumps(executionDump?: ExecutionDump) {\n const report = this.reportState;\n if (report.finalization) {\n if (executionDump) {\n throw new WorkflowError(\n 'Cannot append to a finalized report. Await resetDump() first.',\n {\n code: 'REPORT_FINALIZED',\n },\n );\n }\n return;\n }\n const exec = executionDump || report.lastExecution;\n if (exec) {\n report.lastExecution = exec;\n report.generator.onExecutionUpdate(\n exec,\n this.getReportMeta(),\n this.opts.reportAttributes,\n );\n }\n report.file = report.generator.getReportPath();\n }\n\n /** Persist current report data without disposing this Agent or its device. */\n async flushReport(): Promise<string | undefined> {\n if (this.reportReset) await this.reportReset;\n const report = this.reportState;\n if (report.finalization) return report.finalization;\n this.writeOutActionDumps();\n await report.generator.flush();\n return report.lastExecution ? (report.file ?? undefined) : undefined;\n }\n\n private getReportMeta(): ReportMeta {\n return {\n groupName: this.dump.groupName,\n groupDescription: this.dump.groupDescription,\n sdkVersion: this.dump.sdkVersion,\n modelBriefs: this.dump.modelBriefs,\n deviceType: this.dump.deviceType,\n };\n }\n\n get onDumpUpdate():\n | ((dump: string, executionDump?: ExecutionDump) => void)\n | undefined {\n return this.dumpUpdateListeners[0];\n }\n\n set onDumpUpdate(callback:\n | ((dump: string, executionDump?: ExecutionDump) => void)\n | undefined) {\n // Clear existing listeners\n this.dumpUpdateListeners = [];\n // Add callback to array if provided\n if (callback) {\n this.dumpUpdateListeners.push(callback);\n }\n }\n\n addDumpUpdateListener(\n listener: (dump: string, executionDump?: ExecutionDump) => void,\n ): () => void {\n this.dumpUpdateListeners.push(listener);\n\n // Return remove function\n return () => {\n this.removeDumpUpdateListener(listener);\n };\n }\n\n /**\n * Remove a dump update listener\n * @param listener The listener function to remove\n */\n removeDumpUpdateListener(\n listener: (dump: string, executionDump?: ExecutionDump) => void,\n ): void {\n const index = this.dumpUpdateListeners.indexOf(listener);\n if (index > -1) {\n this.dumpUpdateListeners.splice(index, 1);\n }\n }\n\n /**\n * Clear all dump update listeners\n */\n clearDumpUpdateListeners(): void {\n this.dumpUpdateListeners = [];\n }\n\n notifyDumpUpdateListeners(executionDump?: ExecutionDump) {\n const dumpString = this.dumpDataString();\n for (const listener of this.dumpUpdateListeners) {\n try {\n listener(dumpString, executionDump);\n } catch (error) {\n console.error('Error in onDumpUpdate listener', error);\n }\n }\n }\n\n bindRunner(runner: TaskRunner): void {\n this.reportByRunner.set(runner, this.reportState);\n }\n\n assertRunnerCurrent(runner: TaskRunner): void {\n const report = this.reportByRunner.get(runner);\n assert(\n report === this.reportState && !report.finalization,\n 'Cannot write a late execution update into a different or finalized report.',\n );\n }\n\n async flushPendingWrites(): Promise<void> {\n await this.reportState.generator.flush();\n }\n\n async waitForOperations(): Promise<void> {\n while (this.reportState.activeOperations.size) {\n await Promise.allSettled([...this.reportState.activeOperations]);\n }\n }\n\n async waitForReset(): Promise<void> {\n if (this.reportReset) await this.reportReset.catch(() => {});\n }\n}\n"],"names":["__webpack_require__","definition","key","Object","obj","prop","Symbol","warn","getDebug","AgentReportManager","value","scopeId","executionIds","record","report","existingIndex","entry","recordIndex","path","error","scopedRecords","outcome","attempt","executionRecordsToReportInput","ReportActionDump","getVersion","fileName","reuseExistingReport","ReportGenerator","WeakMap","uuid","Set","undefined","assert","operation","pending","Promise","String","getReportFileName","execution","runner","currentDump","opt","ifInBrowser","getDumpString","IS_REPORT_BUILD","dumpString","reportHTMLContent","reportId","runnerDump","buildAgentTestRunReportDump","generateTestRunReportScriptTag","executionDump","WorkflowError","exec","callback","listener","index","console","context","opts"],"mappings":";;;IAAAA,oBAAoB,CAAC,GAAG,CAAC,UAASC;QACjC,IAAI,IAAIC,OAAOD,WACR,IAAGD,oBAAoB,CAAC,CAACC,YAAYC,QAAQ,CAACF,oBAAoB,CAAC,CAAC,UAASE,MACzEC,OAAO,cAAc,CAAC,UAASD,KAAK;YAAE,YAAY;YAAM,KAAKD,UAAU,CAACC,IAAI;QAAC;IAGzF;;;ICNAF,oBAAoB,CAAC,GAAG,CAACI,KAAKC,OAAUF,OAAO,SAAS,CAAC,cAAc,CAAC,IAAI,CAACC,KAAKC;;;ICClFL,oBAAoB,CAAC,GAAG,CAAC;QACxB,IAAG,AAAkB,eAAlB,OAAOM,UAA0BA,OAAO,WAAW,EACrDH,OAAO,cAAc,CAAC,UAASG,OAAO,WAAW,EAAE;YAAE,OAAO;QAAS;QAEtEH,OAAO,cAAc,CAAC,UAAS,cAAc;YAAE,OAAO;QAAK;IAC5D;;;;;;;;;;;;;;;;;;;;;;;;;;;;ACaA,MAAMI,OAAOC,AAAAA,IAAAA,uBAAAA,QAAAA,AAAAA,EAAS,SAAS;IAAE,SAAS;AAAK;AAoCxC,MAAMC;IAmBX,IAAY,OAAsB;QAChC,OAAO,IAAI,CAAC,OAAO,CAAC,UAAU;IAChC;IAEA,IAAI,OAAyB;QAC3B,OAAO,IAAI,CAAC,WAAW,CAAC,IAAI;IAC9B;IACA,IAAI,KAAKC,KAAuB,EAAE;QAChC,IAAI,CAAC,WAAW,CAAC,IAAI,GAAGA;IAC1B;IAEA,IAAI,aAAwC;QAC1C,OAAO,IAAI,CAAC,WAAW,CAAC,IAAI;IAC9B;IACA,IAAI,WAAWA,KAAgC,EAAE;QAC/C,IAAI,CAAC,WAAW,CAAC,IAAI,GAAGA;IAC1B;IAEA,IAAI,iBAAqC;QACvC,OAAO,IAAI,CAAC,WAAW,CAAC,QAAQ;IAClC;IACA,IAAI,eAAeA,KAAyB,EAAE;QAC5C,IAAI,CAAC,WAAW,CAAC,QAAQ,GAAGA;IAC9B;IAGA,wBAA8B;QAC5B,IAAI,CAAC,WAAW,CAAC,SAAS,CAAC,qBAAqB;IAClD;IACA,MAAM,oBAAoBC,OAAe,EAAEC,YAAgC,EAAE;QAC3E,OAAO,IAAI,CAAC,WAAW,CAAC,SAAS,CAAC,oBAAoB,GACpDD,SACAC;IAEJ;IAGA,MAAM,0BACJC,MAA+B,EACF;QAC7B,MAAMC,SAAS,IAAI,CAAC,WAAW;QAC/B,MAAMC,gBAAgBD,OAAO,WAAW,CAAC,SAAS,CAChD,CAACE,QAAUA,MAAM,KAAK,KAAKH,OAAO,KAAK;QAEzC,MAAMI,cACJF,gBAAgB,IAAID,OAAO,WAAW,CAAC,MAAM,GAAGC;QAClDD,OAAO,WAAW,CAACG,YAAY,GAAGJ;QAClC,IAAI;YACF,MAAMK,OAAO,MAAMJ,OAAO,SAAS,CAAC,iBAAiB,GACnD,IAAI,CAAC,oBAAoB,IACzBA,OAAO,WAAW,EAClB,IAAI,CAAC,aAAa;YAEpBA,OAAO,IAAI,GAAGI,QAAQJ,OAAO,IAAI;YACjC,OAAOI;QACT,EAAE,OAAOC,OAAO;YACdL,OAAO,WAAW,CAACG,YAAY,GAAGd,OAAO,MAAM,CAAC;gBAC9C,GAAGU,MAAM;gBACT,QAAQ;gBACR,aAAaM;YACf;YACA,MAAMA;QACR;IACF;IAEQ,uBAAuB;QAC7B,MAAMC,gBAAgB,IAAI,CAAC,WAAW,CAAC,WAAW,CAAC,GAAG,CAAC,CAACJ,QAAW;gBACjE,GAAGA,KAAK;gBACR,GAAIA,MAAM,SAAS,GACf;oBACE,WAAW;wBACT,UAAU;4BACR,GAAGA,MAAM,SAAS,CAAC,QAAQ;4BAC3B,eAAe,IAAI,CAAC,WAAW,CAAC,WAAW;wBAC7C;wBACA,OAAOA,MAAM,SAAS,CAAC,KAAK,CAAC,GAAG,CAAC,CAACK,UAAa;gCAC7C,GAAGA,OAAO;gCACV,GAAIA,QAAQ,GAAG,GACX;oCACE,KAAK;wCACH,GAAGA,QAAQ,GAAG;wCACd,eAAe,IAAI,CAAC,WAAW,CAAC,WAAW;oCAC7C;gCACF,IACA,CAAC,CAAC;gCACN,GAAIA,QAAQ,QAAQ,GAChB;oCACE,UAAUA,QAAQ,QAAQ,CAAC,GAAG,CAAC,CAACC,UAAa;4CAC3C,GAAGA,OAAO;4CACV,eAAe,IAAI,CAAC,WAAW,CAAC,WAAW;wCAC7C;gCACF,IACA,CAAC,CAAC;4BACR;oBACF;gBACF,IACA,CAAC,CAAC;YACR;QACA,OAAOC,AAAAA,IAAAA,oCAAAA,6BAAAA,AAAAA,EAA8BH,eAAe;YAClD,OAAO,IAAI,CAAC,WAAW,CAAC,WAAW;QACrC;IACF;IAEQ,kBAAoC;QAC1C,OAAO,IAAII,kCAAAA,gBAAgBA,CAAC;YAC1B,YAAYC,AAAAA,IAAAA,kCAAAA,UAAAA,AAAAA;YACZ,WAAW,IAAI,CAAC,IAAI,CAAC,SAAS;YAC9B,kBAAkB,IAAI,CAAC,IAAI,CAAC,gBAAgB;YAC5C,YAAY,EAAE;YACd,aAAa,EAAE;YACf,YAAY,IAAI,CAAC,OAAO,CAAC,aAAa;QACxC;IACF;IAEQ,kBACNC,QAAgB,EAChBC,sBAAsB,KAAK,EACT;QAClB,OAAO;YACL,MAAM,IAAI,CAAC,eAAe;YAC1BD;YACA,WAAWE,6CAAAA,eAAAA,CAAAA,MAAsB,CAACF,UAAU;gBAC1C,gBAAgB,IAAI,CAAC,IAAI,CAAC,cAAc;gBACxC,sBAAsB,IAAI,CAAC,IAAI,CAAC,oBAAoB;gBACpD,cAAc,IAAI,CAAC,IAAI,CAAC,YAAY;gBACpC,oBAAoB,IAAI,CAAC,IAAI,CAAC,kBAAkB;gBAChDC;YACF;YACA,wBAAwB,IAAIE;YAC5B,aAAaC,AAAAA,IAAAA,sBAAAA,IAAAA,AAAAA;YACb,aAAa,EAAE;YACf,kBAAkB,IAAIC;QACxB;IACF;IAEQ,kBAAkBjB,SAAS,IAAI,CAAC,WAAW,EAAQ;QACzDA,OAAO,IAAI,GAAG,IAAI,CAAC,eAAe;QAClCA,OAAO,sBAAsB,GAAG,IAAIe;QACpCf,OAAO,aAAa,GAAGkB;QACvBlB,OAAO,WAAW,CAAC,MAAM,GAAG;IAC9B;IAEQ,mBAAyB;QAC/BmB,IAAAA,sBAAAA,MAAAA,AAAAA,EACE,CAAC,IAAI,CAAC,WAAW,CAAC,gBAAgB,CAAC,IAAI,IACrC,CAAC,IAAI,CAAC,OAAO,CAAC,gBAAgB,IAChC;IAEJ;IAEA,uBAAyC;QACvC,MAAMnB,SAAS,IAAI,CAAC,WAAW;QAC/BmB,IAAAA,sBAAAA,MAAAA,AAAAA,EACE,CAAC,IAAI,CAAC,OAAO,CAAC,WAAW,IACzB;QAEFA,IAAAA,sBAAAA,MAAAA,AAAAA,EACE,CAAC,IAAI,CAAC,WAAW,EACjB;QAEFA,IAAAA,sBAAAA,MAAAA,AAAAA,EACE,CAACnB,OAAO,YAAY,EACpB;QAEF,OAAOA;IACT;IAEA,MAAM,oBAAuBoB,SAA2B,EAAc;QACpE,MAAMpB,SAAS,IAAI,CAAC,oBAAoB;QACxC,MAAMqB,UAAUC,QAAQ,OAAO,GAAG,IAAI,CAACF;QACvCpB,OAAO,gBAAgB,CAAC,GAAG,CAACqB;QAC5B,IAAI;YACF,OAAO,MAAMA;QACf,SAAU;YACRrB,OAAO,gBAAgB,CAAC,MAAM,CAACqB;QACjC;IACF;IAOA,MAAM,YAAuC;QAC3CF,IAAAA,sBAAAA,MAAAA,AAAAA,EACE,CAAC,IAAI,CAAC,OAAO,CAAC,WAAW,IACzB;QAEF,IAAI,IAAI,CAAC,WAAW,EAAE,OAAO,IAAI,CAAC,WAAW;QAC7C,IAAI,CAAC,gBAAgB;QACrB,IAAI,CAAC,WAAW,GAAI;YAClB,IAAI;gBACF,MAAM,IAAI,CAAC,cAAc;YAC3B,EAAE,OAAOd,OAAO;gBAEdZ,KACE,CAAC,oDAAoD,EAAE8B,OAAOlB,QAAQ;YAE1E;YACAc,IAAAA,sBAAAA,MAAAA,AAAAA,EACE,CAAC,IAAI,CAAC,OAAO,CAAC,WAAW,IACzB;YAEF,MAAMP,WAAWY,AAAAA,IAAAA,oCAAAA,iBAAAA,AAAAA,EACf,IAAI,CAAC,IAAI,CAAC,MAAM,IAAI,IAAI,CAAC,OAAO,CAAC,aAAa,MAAM;YAEtD,IAAI,CAAC,WAAW,GAAG,IAAI,CAAC,iBAAiB,CAACZ;YAC1C,OAAO,IAAI,CAAC,IAAI;QAClB;QACA,IAAI;YACF,OAAO,MAAM,IAAI,CAAC,WAAW;QAC/B,SAAU;YACR,IAAI,CAAC,WAAW,GAAGM;QACrB;IACF;IAOA,MAAM,iBAA8C;QAClD,MAAMlB,SAAS,IAAI,CAAC,WAAW;QAC/B,IAAI,CAACA,OAAO,YAAY,EAAE;YACxB,IAAI,CAAC,gBAAgB;YACrBA,OAAO,YAAY,GAAI;gBACrB,MAAMA,OAAO,SAAS,CAAC,KAAK;gBAC5B,MAAMI,OAAO,MAAMJ,OAAO,SAAS,CAAC,QAAQ;gBAC5CA,OAAO,IAAI,GAAGI;gBACd,IAAI,CAAC,iBAAiB,CAACJ;gBACvB,OAAOI;YACT;QACF;QACA,OAAOJ,OAAO,YAAY;IAC5B;IAEA,oBAAoByB,SAAwB,EAAEC,MAAmB,EAAE;QACjEP,IAAAA,sBAAAA,MAAAA,AAAAA,EACE,CAAC,IAAI,CAAC,WAAW,CAAC,YAAY,EAC9B;QAEF,MAAMQ,cAAc,IAAI,CAAC,IAAI;QAC7B,IAAID,QAAQ;YACV,MAAMzB,gBAAgB,IAAI,CAAC,WAAW,CAAC,sBAAsB,CAAC,GAAG,CAACyB;YAClE,IAAIzB,AAAkBiB,WAAlBjB,eAA6B;gBAC/B0B,YAAY,UAAU,CAAC1B,cAAc,GAAGwB;gBACxC;YACF;YACAE,YAAY,UAAU,CAAC,IAAI,CAACF;YAC5B,IAAI,CAAC,WAAW,CAAC,sBAAsB,CAAC,GAAG,CACzCC,QACAC,YAAY,UAAU,CAAC,MAAM,GAAG;YAElC;QACF;QACAA,YAAY,UAAU,CAAC,IAAI,CAACF;IAC9B;IAEA,eAAeG,GAAqC,EAAE;QAEpD,IAAI,CAAC,IAAI,CAAC,SAAS,GAAG,IAAI,CAAC,IAAI,CAAC,SAAS;QACzC,IAAI,CAAC,IAAI,CAAC,gBAAgB,GAAG,IAAI,CAAC,IAAI,CAAC,gBAAgB;QAEvD,IAAIC,sBAAAA,WAAWA,IAAID,KAAK,mBACtB,OAAO,IAAI,CAAC,IAAI,CAAC,8BAA8B;QAEjD,OAAO,IAAI,CAAC,IAAI,CAAC,SAAS;IAC5B;IAEA,iBAAiBE,aAA2B,EAAE;QAI5C,IAAIC,sCAAAA,eAAeA,EACjB,OAAO;QAIT,MAAMC,aAAaF;QACnB,IAAI,CAAC,IAAI,CAAC,WAAW,CAAC,WAAW,CAAC,MAAM,EACtC,OAAOG,AAAAA,IAAAA,kCAAAA,iBAAAA,AAAAA,EAAkBD;QAI3B,MAAME,WAAW,IAAI,CAAC,WAAW,CAAC,WAAW;QAC7C,MAAMC,aAAaC,AAAAA,IAAAA,gCAAAA,2BAAAA,AAAAA,EACjB,IAAI,CAAC,oBAAoB,IACzB,IAAI,CAAC,IAAI,EACT;YACEF;YACA,SAAS,IAAI,CAAC,WAAW,CAAC,WAAW;YACrC,YAAY,IAAI,CAAC,UAAU,IAAI;QACjC;QAEF,OAAO,GAAGD,AAAAA,IAAAA,kCAAAA,iBAAAA,AAAAA,EAAkB;YAC1BD;YACA,YAAY;gBAAE,iBAAiBE;gBAAU,kBAAkBA;YAAS;QACtE,GAAG,EAAE,EAAEG,AAAAA,IAAAA,8BAAAA,8BAAAA,AAAAA,EAA+BF,aAAa;IACrD;IAEA,oBAAoBG,aAA6B,EAAE;QACjD,MAAMtC,SAAS,IAAI,CAAC,WAAW;QAC/B,IAAIA,OAAO,YAAY,EAAE;YACvB,IAAIsC,eACF,MAAM,IAAIC,0BAAAA,aAAaA,CACrB,iEACA;gBACE,MAAM;YACR;YAGJ;QACF;QACA,MAAMC,OAAOF,iBAAiBtC,OAAO,aAAa;QAClD,IAAIwC,MAAM;YACRxC,OAAO,aAAa,GAAGwC;YACvBxC,OAAO,SAAS,CAAC,iBAAiB,CAChCwC,MACA,IAAI,CAAC,aAAa,IAClB,IAAI,CAAC,IAAI,CAAC,gBAAgB;QAE9B;QACAxC,OAAO,IAAI,GAAGA,OAAO,SAAS,CAAC,aAAa;IAC9C;IAGA,MAAM,cAA2C;QAC/C,IAAI,IAAI,CAAC,WAAW,EAAE,MAAM,IAAI,CAAC,WAAW;QAC5C,MAAMA,SAAS,IAAI,CAAC,WAAW;QAC/B,IAAIA,OAAO,YAAY,EAAE,OAAOA,OAAO,YAAY;QACnD,IAAI,CAAC,mBAAmB;QACxB,MAAMA,OAAO,SAAS,CAAC,KAAK;QAC5B,OAAOA,OAAO,aAAa,GAAIA,OAAO,IAAI,IAAIkB,SAAaA;IAC7D;IAEQ,gBAA4B;QAClC,OAAO;YACL,WAAW,IAAI,CAAC,IAAI,CAAC,SAAS;YAC9B,kBAAkB,IAAI,CAAC,IAAI,CAAC,gBAAgB;YAC5C,YAAY,IAAI,CAAC,IAAI,CAAC,UAAU;YAChC,aAAa,IAAI,CAAC,IAAI,CAAC,WAAW;YAClC,YAAY,IAAI,CAAC,IAAI,CAAC,UAAU;QAClC;IACF;IAEA,IAAI,eAEU;QACZ,OAAO,IAAI,CAAC,mBAAmB,CAAC,EAAE;IACpC;IAEA,IAAI,aAAauB,QAEJ,EAAE;QAEb,IAAI,CAAC,mBAAmB,GAAG,EAAE;QAE7B,IAAIA,UACF,IAAI,CAAC,mBAAmB,CAAC,IAAI,CAACA;IAElC;IAEA,sBACEC,QAA+D,EACnD;QACZ,IAAI,CAAC,mBAAmB,CAAC,IAAI,CAACA;QAG9B,OAAO;YACL,IAAI,CAAC,wBAAwB,CAACA;QAChC;IACF;IAMA,yBACEA,QAA+D,EACzD;QACN,MAAMC,QAAQ,IAAI,CAAC,mBAAmB,CAAC,OAAO,CAACD;QAC/C,IAAIC,QAAQ,IACV,IAAI,CAAC,mBAAmB,CAAC,MAAM,CAACA,OAAO;IAE3C;IAKA,2BAAiC;QAC/B,IAAI,CAAC,mBAAmB,GAAG,EAAE;IAC/B;IAEA,0BAA0BL,aAA6B,EAAE;QACvD,MAAMN,aAAa,IAAI,CAAC,cAAc;QACtC,KAAK,MAAMU,YAAY,IAAI,CAAC,mBAAmB,CAC7C,IAAI;YACFA,SAASV,YAAYM;QACvB,EAAE,OAAOjC,OAAO;YACduC,QAAQ,KAAK,CAAC,kCAAkCvC;QAClD;IAEJ;IAEA,WAAWqB,MAAkB,EAAQ;QACnC,IAAI,CAAC,cAAc,CAAC,GAAG,CAACA,QAAQ,IAAI,CAAC,WAAW;IAClD;IAEA,oBAAoBA,MAAkB,EAAQ;QAC5C,MAAM1B,SAAS,IAAI,CAAC,cAAc,CAAC,GAAG,CAAC0B;QACvCP,IAAAA,sBAAAA,MAAAA,AAAAA,EACEnB,WAAW,IAAI,CAAC,WAAW,IAAI,CAACA,OAAO,YAAY,EACnD;IAEJ;IAEA,MAAM,qBAAoC;QACxC,MAAM,IAAI,CAAC,WAAW,CAAC,SAAS,CAAC,KAAK;IACxC;IAEA,MAAM,oBAAmC;QACvC,MAAO,IAAI,CAAC,WAAW,CAAC,gBAAgB,CAAC,IAAI,CAC3C,MAAMsB,QAAQ,UAAU,CAAC;eAAI,IAAI,CAAC,WAAW,CAAC,gBAAgB;SAAC;IAEnE;IAEA,MAAM,eAA8B;QAClC,IAAI,IAAI,CAAC,WAAW,EAAE,MAAM,IAAI,CAAC,WAAW,CAAC,KAAK,CAAC,KAAO;IAC5D;IAvbA,YAA6BuB,OAA2B,CAAE;;QAP1D,uBAAQ,eAAR;QACA,uBAAQ,eAAR;QACA,uBAAiB,kBAAjB;QACA,uBAAQ,uBAAR;aAI6BA,OAAO,GAAPA;aALZ,cAAc,GAAG,IAAI9B;aAC9B,mBAAmB,GAEvB,EAAE;QAGJ,MAAM+B,OAAO,IAAI,CAAC,IAAI;QACtB,MAAMlC,WACJkC,KAAK,cAAc,IACnBtB,AAAAA,IAAAA,oCAAAA,iBAAAA,AAAAA,EAAkBsB,KAAK,MAAM,IAAID,QAAQ,aAAa,MAAM;QAC9D,IAAI,CAAC,WAAW,GAAG,IAAI,CAAC,iBAAiB,CACvCjC,UACAkC,KAAK,gBAAgB,EAAE,CAAC,gBAAgB,KAAKlC;IAEjD;AA+aF"}
1
+ {"version":3,"file":"agent/agent-report-manager.js","sources":["webpack/runtime/define_property_getters","webpack/runtime/has_own_property","webpack/runtime/make_namespace_object","../../../src/agent/agent-report-manager.ts"],"sourcesContent":["__webpack_require__.d = (exports, definition) => {\n\tfor(var key in definition) {\n if(__webpack_require__.o(definition, key) && !__webpack_require__.o(exports, key)) {\n Object.defineProperty(exports, key, { enumerable: true, get: definition[key] });\n }\n }\n};","__webpack_require__.o = (obj, prop) => (Object.prototype.hasOwnProperty.call(obj, prop))","// define __esModule on exports\n__webpack_require__.r = (exports) => {\n\tif(typeof Symbol !== 'undefined' && Symbol.toStringTag) {\n\t\tObject.defineProperty(exports, Symbol.toStringTag, { value: 'Module' });\n\t}\n\tObject.defineProperty(exports, '__esModule', { value: true });\n};","import { getDebug } from '@midscene/shared/logger';\nimport { assert, ifInBrowser, uuid } from '@midscene/shared/utils';\nimport { IS_REPORT_BUILD } from '../constants';\nimport { generateTestRunReportScriptTag } from '../dump/html-utils';\nimport { type IReportGenerator, ReportGenerator } from '../report-generator';\nimport type { TaskRunner } from '../task-runner';\nimport { WorkflowError } from '../test-runner/errors';\nimport type { WorkflowExecutionRecord } from '../test-runner/execution-record';\nimport { buildAgentTestRunReportDump } from '../test-runner/reporting/agent-report';\nimport { executionRecordsToReportInput } from '../test-runner/reporting/execution-record';\nimport {\n type AgentOpt,\n type ExecutionDump,\n ReportActionDump,\n type ReportMeta,\n} from '../types';\nimport { getVersion, reportHTMLContent } from '../utils';\nimport { getReportFileName } from './utils';\n\nconst warn = getDebug('agent', { console: true });\n\ntype ReportOptions = Pick<\n AgentOpt,\n | 'groupName'\n | 'groupDescription'\n | 'generateReport'\n | 'persistExecutionDump'\n | 'outputFormat'\n | 'autoPrintReportMsg'\n | 'reportAttributes'\n | 'reportFileName'\n | 'testId'\n>;\n\ninterface AgentReportContext {\n getOptions(): ReportOptions;\n getDeviceType(): ReportActionDump['deviceType'];\n isDestroyed(): boolean;\n isExternallyBusy(): boolean;\n}\n\ninterface AgentReportState {\n dump: ReportActionDump;\n file?: string | null;\n fileName?: string;\n generator: IReportGenerator;\n finalization?: Promise<string | undefined>;\n lastExecution?: ExecutionDump;\n executionIndexByRunner: WeakMap<TaskRunner, number>;\n yamlScopeId: string;\n yamlRecords: WorkflowExecutionRecord[];\n activeOperations: Set<Promise<unknown>>;\n}\n\n/** Owns report state and persistence; execution and device ownership stay with Agent. */\nexport class AgentReportManager {\n private reportState: AgentReportState;\n private reportReset?: Promise<ReportActionDump>;\n private readonly reportByRunner = new WeakMap<TaskRunner, AgentReportState>();\n private dumpUpdateListeners: Array<\n (dump: string, executionDump?: ExecutionDump) => void\n > = [];\n\n constructor(private readonly context: AgentReportContext) {\n const opts = this.opts;\n const fileName =\n opts.reportFileName ??\n getReportFileName(opts.testId || context.getDeviceType() || 'web');\n this.reportState = this.createReportState(\n fileName,\n opts.reportAttributes?.['data-group-id'] === fileName,\n );\n }\n\n private get opts(): ReportOptions {\n return this.context.getOptions();\n }\n\n get dump(): ReportActionDump {\n return this.reportState.dump;\n }\n set dump(value: ReportActionDump) {\n this.reportState.dump = value;\n }\n\n get reportFile(): string | null | undefined {\n return this.reportState.file;\n }\n set reportFile(value: string | null | undefined) {\n this.reportState.file = value;\n }\n\n get reportFileName(): string | undefined {\n return this.reportState.fileName;\n }\n set reportFileName(value: string | undefined) {\n this.reportState.fileName = value;\n }\n\n /** @internal Runner snapshots retain immutable data and shared image files. */\n _prepareForTestRunner(): void {\n this.reportState.generator.enableSourceSnapshots?.();\n }\n async _createReportSource(scopeId: string, executionIds?: readonly string[]) {\n return this.reportState.generator.createSourceSnapshot?.(\n scopeId,\n executionIds,\n );\n }\n\n /** @internal The Agent owns one report stream across root YAML invocations. */\n async _writeYamlExecutionReport(\n record: WorkflowExecutionRecord,\n ): Promise<string | undefined> {\n const report = this.reportState;\n const existingIndex = report.yamlRecords.findIndex(\n (entry) => entry.runId === record.runId,\n );\n const recordIndex =\n existingIndex < 0 ? report.yamlRecords.length : existingIndex;\n report.yamlRecords[recordIndex] = record;\n try {\n const path = await report.generator.writeRunnerReport?.(\n this.buildYamlReportInput(),\n report.yamlScopeId,\n this.getReportMeta(),\n );\n report.file = path ?? report.file;\n return path;\n } catch (error) {\n report.yamlRecords[recordIndex] = Object.freeze({\n ...record,\n status: 'failed',\n reportError: error,\n });\n throw error;\n }\n }\n\n private buildYamlReportInput() {\n const scopedRecords = this.reportState.yamlRecords.map((entry) => ({\n ...entry,\n ...(entry.execution\n ? {\n execution: {\n document: {\n ...entry.execution.document,\n reportScopeId: this.reportState.yamlScopeId,\n },\n cases: entry.execution.cases.map((outcome) => ({\n ...outcome,\n ...(outcome.run\n ? {\n run: {\n ...outcome.run,\n reportScopeId: this.reportState.yamlScopeId,\n },\n }\n : {}),\n ...(outcome.attempts\n ? {\n attempts: outcome.attempts.map((attempt) => ({\n ...attempt,\n reportScopeId: this.reportState.yamlScopeId,\n })),\n }\n : {}),\n })),\n },\n }\n : {}),\n }));\n return executionRecordsToReportInput(scopedRecords, {\n runId: this.reportState.yamlScopeId,\n });\n }\n\n private createEmptyDump(): ReportActionDump {\n return new ReportActionDump({\n sdkVersion: getVersion(),\n groupName: this.opts.groupName!,\n groupDescription: this.opts.groupDescription,\n executions: [],\n modelBriefs: [],\n deviceType: this.context.getDeviceType(),\n });\n }\n\n private createReportState(\n fileName: string,\n reuseExistingReport = false,\n ): AgentReportState {\n return {\n dump: this.createEmptyDump(),\n fileName,\n generator: ReportGenerator.create(fileName, {\n generateReport: this.opts.generateReport,\n persistExecutionDump: this.opts.persistExecutionDump,\n outputFormat: this.opts.outputFormat,\n autoPrintReportMsg: this.opts.autoPrintReportMsg,\n reuseExistingReport,\n }),\n executionIndexByRunner: new WeakMap(),\n yamlScopeId: uuid(),\n yamlRecords: [],\n activeOperations: new Set(),\n };\n }\n\n private clearDumpInMemory(report = this.reportState): void {\n report.dump = this.createEmptyDump();\n report.executionIndexByRunner = new WeakMap();\n report.lastExecution = undefined;\n report.yamlRecords.length = 0;\n }\n\n private assertReportIdle(): void {\n assert(\n !this.reportState.activeOperations.size &&\n !this.context.isExternallyBusy(),\n 'Cannot reset or finalize a report while the Agent is executing. Await the active operation first.',\n );\n }\n\n assertReportWritable(): AgentReportState {\n const report = this.reportState;\n assert(\n !this.context.isDestroyed(),\n 'Cannot execute using a destroyed Agent.',\n );\n assert(\n !this.reportReset,\n 'Report reset is in progress. Await resetDump() first.',\n );\n assert(\n !report.finalization,\n 'The report has been finalized. Call and await resetDump() before executing again.',\n );\n return report;\n }\n\n async withReportOperation<T>(operation: () => Promise<T>): Promise<T> {\n const report = this.assertReportWritable();\n const pending = Promise.resolve().then(operation);\n report.activeOperations.add(pending);\n try {\n return await pending;\n } finally {\n report.activeOperations.delete(pending);\n }\n }\n\n /**\n * Finalize the preceding report and reset execution records for a new report.\n * Historical artifacts are retained; this Agent and its device stay connected.\n * Await this method before executing again. Concurrent resets share one reset.\n */\n async resetDump(): Promise<ReportActionDump> {\n assert(\n !this.context.isDestroyed(),\n 'Cannot reset a report using a destroyed Agent.',\n );\n if (this.reportReset) return this.reportReset;\n this.assertReportIdle();\n this.reportReset = (async () => {\n try {\n await this.finalizeReport();\n } catch (error) {\n // Failure belongs to the preceding report, not to the next write queue.\n warn(\n `Failed to finalize previous report; resetting dump: ${String(error)}`,\n );\n }\n assert(\n !this.context.isDestroyed(),\n 'Cannot reset a report using a destroyed Agent.',\n );\n const fileName = getReportFileName(\n this.opts.testId || this.context.getDeviceType() || 'web',\n );\n this.reportState = this.createReportState(fileName);\n return this.dump;\n })();\n try {\n return await this.reportReset;\n } finally {\n this.reportReset = undefined;\n }\n }\n\n /**\n * Seal the current report and release its in-memory records without\n * disconnecting the device. Export in-memory data before calling this method.\n * Repeated calls return the same result and never rewrite published artifacts.\n */\n async finalizeReport(): Promise<string | undefined> {\n const report = this.reportState;\n if (!report.finalization) {\n this.assertReportIdle();\n report.finalization = (async () => {\n await report.generator.flush();\n const path = await report.generator.finalize();\n report.file = path;\n this.clearDumpInMemory(report);\n return path;\n })();\n }\n return report.finalization;\n }\n\n appendExecutionDump(execution: ExecutionDump, runner?: TaskRunner) {\n assert(\n !this.reportState.finalization,\n 'Cannot append to a finalized report. Await resetDump() first.',\n );\n const currentDump = this.dump;\n if (runner) {\n const existingIndex = this.reportState.executionIndexByRunner.get(runner);\n if (existingIndex !== undefined) {\n currentDump.executions[existingIndex] = execution;\n return;\n }\n currentDump.executions.push(execution);\n this.reportState.executionIndexByRunner.set(\n runner,\n currentDump.executions.length - 1,\n );\n return;\n }\n currentDump.executions.push(execution);\n }\n\n dumpDataString(opt?: { inlineScreenshots?: boolean }) {\n // update dump info\n this.dump.groupName = this.opts.groupName!;\n this.dump.groupDescription = this.opts.groupDescription;\n // In browser environment, use inline screenshots since file system is not available\n if (ifInBrowser || opt?.inlineScreenshots) {\n return this.dump.serializeWithInlineScreenshots();\n }\n return this.dump.serialize();\n }\n\n reportHTMLString(getDumpString: () => string) {\n // Short-circuit at the call site because JavaScript evaluates function\n // arguments first. This avoids serializing the dump (including inline\n // screenshots) when the Report Viewer build does not need report HTML.\n if (IS_REPORT_BUILD) {\n return '';\n }\n\n // dumpDataString() handles browser environment with inline screenshots\n const dumpString = getDumpString();\n if (!this.reportState.yamlRecords.length)\n return reportHTMLContent(dumpString);\n\n // Browser exports have no file writer, so the execution record must own\n // the hierarchy independently of whether file report generation is enabled.\n const reportId = this.reportState.yamlScopeId;\n const runnerDump = buildAgentTestRunReportDump(\n this.buildYamlReportInput(),\n this.dump,\n {\n reportId,\n scopeId: this.reportState.yamlScopeId,\n sourcePath: this.reportFile ?? '<inline-agent-report>',\n },\n );\n return `${reportHTMLContent({\n dumpString,\n attributes: { 'data-group-id': reportId, 'data-report-id': reportId },\n })}\\n${generateTestRunReportScriptTag(runnerDump)}`;\n }\n\n writeOutActionDumps(executionDump?: ExecutionDump) {\n const report = this.reportState;\n if (report.finalization) {\n if (executionDump) {\n throw new WorkflowError(\n 'Cannot append to a finalized report. Await resetDump() first.',\n {\n code: 'REPORT_FINALIZED',\n },\n );\n }\n return;\n }\n const exec = executionDump || report.lastExecution;\n if (exec) {\n report.lastExecution = exec;\n report.generator.onExecutionUpdate(\n exec,\n this.getReportMeta(),\n this.opts.reportAttributes,\n );\n }\n report.file = report.generator.getReportPath();\n }\n\n /** Persist current report data without disposing this Agent or its device. */\n async flushReport(): Promise<string | undefined> {\n if (this.reportReset) await this.reportReset;\n const report = this.reportState;\n if (report.finalization) return report.finalization;\n this.writeOutActionDumps();\n await report.generator.flush();\n return report.lastExecution ? (report.file ?? undefined) : undefined;\n }\n\n private getReportMeta(): ReportMeta {\n return {\n groupName: this.dump.groupName,\n groupDescription: this.dump.groupDescription,\n sdkVersion: this.dump.sdkVersion,\n modelBriefs: this.dump.modelBriefs,\n deviceType: this.dump.deviceType,\n };\n }\n\n get onDumpUpdate():\n | ((dump: string, executionDump?: ExecutionDump) => void)\n | undefined {\n return this.dumpUpdateListeners[0];\n }\n\n set onDumpUpdate(callback:\n | ((dump: string, executionDump?: ExecutionDump) => void)\n | undefined) {\n // Clear existing listeners\n this.dumpUpdateListeners = [];\n // Add callback to array if provided\n if (callback) {\n this.dumpUpdateListeners.push(callback);\n }\n }\n\n addDumpUpdateListener(\n listener: (dump: string, executionDump?: ExecutionDump) => void,\n ): () => void {\n this.dumpUpdateListeners.push(listener);\n\n // Return remove function\n return () => {\n this.removeDumpUpdateListener(listener);\n };\n }\n\n /**\n * Remove a dump update listener\n * @param listener The listener function to remove\n */\n removeDumpUpdateListener(\n listener: (dump: string, executionDump?: ExecutionDump) => void,\n ): void {\n const index = this.dumpUpdateListeners.indexOf(listener);\n if (index > -1) {\n this.dumpUpdateListeners.splice(index, 1);\n }\n }\n\n /**\n * Clear all dump update listeners\n */\n clearDumpUpdateListeners(): void {\n this.dumpUpdateListeners = [];\n }\n\n notifyDumpUpdateListeners(executionDump?: ExecutionDump) {\n if (this.dumpUpdateListeners.length === 0) return;\n const dumpString = this.dumpDataString();\n for (const listener of this.dumpUpdateListeners) {\n try {\n listener(dumpString, executionDump);\n } catch (error) {\n console.error('Error in onDumpUpdate listener', error);\n }\n }\n }\n\n bindRunner(runner: TaskRunner): void {\n this.reportByRunner.set(runner, this.reportState);\n }\n\n assertRunnerCurrent(runner: TaskRunner): void {\n const report = this.reportByRunner.get(runner);\n assert(\n report === this.reportState && !report.finalization,\n 'Cannot write a late execution update into a different or finalized report.',\n );\n }\n\n async flushPendingWrites(): Promise<void> {\n await this.reportState.generator.flush();\n }\n\n async waitForOperations(): Promise<void> {\n while (this.reportState.activeOperations.size) {\n await Promise.allSettled([...this.reportState.activeOperations]);\n }\n }\n\n async waitForReset(): Promise<void> {\n if (this.reportReset) await this.reportReset.catch(() => {});\n }\n}\n"],"names":["__webpack_require__","definition","key","Object","obj","prop","Symbol","warn","getDebug","AgentReportManager","value","scopeId","executionIds","record","report","existingIndex","entry","recordIndex","path","error","scopedRecords","outcome","attempt","executionRecordsToReportInput","ReportActionDump","getVersion","fileName","reuseExistingReport","ReportGenerator","WeakMap","uuid","Set","undefined","assert","operation","pending","Promise","String","getReportFileName","execution","runner","currentDump","opt","ifInBrowser","getDumpString","IS_REPORT_BUILD","dumpString","reportHTMLContent","reportId","runnerDump","buildAgentTestRunReportDump","generateTestRunReportScriptTag","executionDump","WorkflowError","exec","callback","listener","index","console","context","opts"],"mappings":"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"}
@@ -363,6 +363,13 @@ class Agent {
363
363
  locate: detailedLocateParam
364
364
  });
365
365
  }
366
+ async aiMiddleClick(locatePrompt, opt) {
367
+ (0, utils_namespaceObject.assert)(locatePrompt, 'missing locate prompt for middle click');
368
+ const detailedLocateParam = (0, external_yaml_index_js_namespaceObject.buildDetailedLocateParam)(locatePrompt, this.withContext('aiMiddleClick', opt));
369
+ await this.callActionInActionSpace('MiddleClick', {
370
+ locate: detailedLocateParam
371
+ });
372
+ }
366
373
  async aiDoubleClick(locatePrompt, opt) {
367
374
  (0, utils_namespaceObject.assert)(locatePrompt, 'missing locate prompt for double click');
368
375
  const detailedLocateParam = (0, external_yaml_index_js_namespaceObject.buildDetailedLocateParam)(locatePrompt, this.withContext('aiDoubleClick', opt));