@midscene/core 1.16.1 → 1.16.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (64) hide show
  1. package/dist/es/agent/utils.mjs +4 -4
  2. package/dist/es/agent/utils.mjs.map +1 -1
  3. package/dist/es/ai-model/models/auto-glm/parser.mjs +1 -1
  4. package/dist/es/ai-model/models/auto-glm/parser.mjs.map +1 -1
  5. package/dist/es/ai-model/models/kimi.mjs +1 -1
  6. package/dist/es/ai-model/models/kimi.mjs.map +1 -1
  7. package/dist/es/ai-model/service-caller/call-ai.mjs +10 -1
  8. package/dist/es/ai-model/service-caller/call-ai.mjs.map +1 -1
  9. package/dist/es/ai-model/service-caller/openai/call-openai.mjs +7 -2
  10. package/dist/es/ai-model/service-caller/openai/call-openai.mjs.map +1 -1
  11. package/dist/es/ai-model/shared/model-locate-result/errors.mjs +1 -1
  12. package/dist/es/ai-model/shared/model-locate-result/errors.mjs.map +1 -1
  13. package/dist/es/ai-model/shared/model-locate-result/parse.mjs +6 -2
  14. package/dist/es/ai-model/shared/model-locate-result/parse.mjs.map +1 -1
  15. package/dist/es/device/index.mjs +9 -8
  16. package/dist/es/device/index.mjs.map +1 -1
  17. package/dist/es/report-generator.mjs +3 -3
  18. package/dist/es/report-generator.mjs.map +1 -1
  19. package/dist/es/report-html-template.mjs +1 -1
  20. package/dist/es/test-run-report.mjs.map +1 -1
  21. package/dist/es/test-runner/reporting/merge-report.mjs +3 -1
  22. package/dist/es/test-runner/reporting/merge-report.mjs.map +1 -1
  23. package/dist/es/test-runner/reporting/metrics.mjs +39 -2
  24. package/dist/es/test-runner/reporting/metrics.mjs.map +1 -1
  25. package/dist/es/utils.mjs +1 -1
  26. package/dist/lib/agent/utils.js +2 -2
  27. package/dist/lib/agent/utils.js.map +1 -1
  28. package/dist/lib/ai-model/models/auto-glm/parser.js +1 -1
  29. package/dist/lib/ai-model/models/auto-glm/parser.js.map +1 -1
  30. package/dist/lib/ai-model/models/kimi.js +1 -1
  31. package/dist/lib/ai-model/models/kimi.js.map +1 -1
  32. package/dist/lib/ai-model/service-caller/call-ai.js +10 -1
  33. package/dist/lib/ai-model/service-caller/call-ai.js.map +1 -1
  34. package/dist/lib/ai-model/service-caller/openai/call-openai.js +7 -2
  35. package/dist/lib/ai-model/service-caller/openai/call-openai.js.map +1 -1
  36. package/dist/lib/ai-model/shared/model-locate-result/errors.js +1 -1
  37. package/dist/lib/ai-model/shared/model-locate-result/errors.js.map +1 -1
  38. package/dist/lib/ai-model/shared/model-locate-result/parse.js +6 -2
  39. package/dist/lib/ai-model/shared/model-locate-result/parse.js.map +1 -1
  40. package/dist/lib/device/index.js +9 -8
  41. package/dist/lib/device/index.js.map +1 -1
  42. package/dist/lib/report-generator.js +2 -2
  43. package/dist/lib/report-generator.js.map +1 -1
  44. package/dist/lib/report-html-template.js +1 -1
  45. package/dist/lib/test-run-report.js.map +1 -1
  46. package/dist/lib/test-runner/reporting/merge-report.js +3 -1
  47. package/dist/lib/test-runner/reporting/merge-report.js.map +1 -1
  48. package/dist/lib/test-runner/reporting/metrics.js +39 -2
  49. package/dist/lib/test-runner/reporting/metrics.js.map +1 -1
  50. package/dist/lib/utils.js +1 -1
  51. package/dist/types/ai-model/models/auto-glm/parser.d.ts.map +1 -1
  52. package/dist/types/ai-model/service-caller/openai/call-openai.d.ts.map +1 -1
  53. package/dist/types/ai-model/shared/model-locate-result/errors.d.ts +1 -1
  54. package/dist/types/ai-model/shared/model-locate-result/errors.d.ts.map +1 -1
  55. package/dist/types/ai-model/shared/model-locate-result/parse.d.ts.map +1 -1
  56. package/dist/types/device/index.d.ts +7 -7
  57. package/dist/types/device/index.d.ts.map +1 -1
  58. package/dist/types/test-run-report.d.ts +4 -1
  59. package/dist/types/test-run-report.d.ts.map +1 -1
  60. package/dist/types/test-runner/parser/types.d.ts +5 -0
  61. package/dist/types/test-runner/parser/types.d.ts.map +1 -1
  62. package/dist/types/test-runner/reporting/merge-report.d.ts.map +1 -1
  63. package/dist/types/test-runner/reporting/metrics.d.ts.map +1 -1
  64. package/package.json +2 -2
@@ -1 +1 @@
1
- {"version":3,"file":"test-run-report.mjs","sources":["../../src/test-run-report.ts"],"sourcesContent":["export const TEST_RUN_REPORT_SCRIPT_TYPE = 'midscene_test_run_dump';\n\nexport type TestRunReportRunStatus = 'success' | 'failed';\nexport type TestRunReportCaseStatus = TestRunReportRunStatus | 'not-run';\nexport type TestRunReportStepPhase =\n | 'beforeAll'\n | 'beforeEach'\n | 'steps'\n | 'afterEach'\n | 'afterAll';\n\n/**\n * A JSON-safe value prepared for display in a Midscene Test report.\n *\n * Paths use JSONPath-like notation rooted at `$`. The path arrays are kept\n * beside the value so the UI never presents redacted or truncated data as if\n * it were complete.\n */\nexport interface TestRunReportValue {\n value: unknown;\n truncatedPaths?: string[];\n redactedPaths?: string[];\n}\n\nexport interface TestRunReportError {\n format?: 'midscene-error';\n name: string;\n message: string;\n stack?: string;\n code?: string;\n details?: TestRunReportValue;\n cause?: TestRunReportError;\n errors?: TestRunReportError[];\n truncated?: boolean;\n}\n\nexport interface TestRunReportOperationReference {\n operationId: string;\n scopeId?: string;\n stepId?: string;\n node?: string;\n}\n\n/** Immutable observation; late completion remains in the operation journal. */\nexport interface TestRunReportCleanup {\n status: 'not-required' | 'completed' | 'pending' | 'failed';\n capturedAt: string;\n operationId?: string;\n blockingOperations?: TestRunReportOperationReference[];\n error?: TestRunReportError;\n}\n\nexport interface TestRunReportRetryDecision {\n scope: 'case' | 'document';\n retryCount: number;\n attemptIndex: number;\n decision: 'retry' | 'stop';\n reason:\n | 'passed'\n | 'attempt-failed'\n | 'budget-exhausted'\n | 'cleanup-pending'\n | 'cleanup-failed'\n | 'operation-pending'\n | 'fatal-error'\n | 'interrupted'\n | 'bail'\n | 'infrastructure-error';\n}\n\nexport interface TestRunReportPhaseResult {\n status: 'success' | 'failed' | 'not-run' | 'not-required';\n plannedStepCount: number;\n executedStepCount: number;\n}\n\nexport interface TestRunReportHostError {\n phase:\n | 'setup'\n | 'execution'\n | 'cleanup'\n | 'report'\n | 'publication'\n | 'observer';\n error: TestRunReportError;\n}\n\nexport interface TestRunReportDiagnostic {\n level: 'warning' | 'error';\n code:\n | 'agent-detail-unresolved'\n | 'agent-detail-unavailable'\n | 'large-report'\n | 'run-infrastructure-error'\n | 'agent-source-unavailable'\n | 'source-without-executions';\n message: string;\n scopeId?: string;\n executionId?: string;\n sourcePaths?: string[];\n stepId?: string;\n error?: TestRunReportError;\n}\n\nexport interface TestRunReportMetrics {\n modelCallCount: number;\n modelTimeMs: number;\n promptTokens: number;\n cachedInputTokens: number;\n completionTokens: number;\n totalTokens: number;\n collection?: {\n status: 'complete' | 'partial' | 'unknown';\n expectedExecutionCount: number;\n capturedExecutionCount: number;\n reasons: string[];\n fields?: Record<\n 'modelCallCount' | 'modelTimeMs' | 'totalTokens',\n 'complete' | 'partial' | 'unknown'\n >;\n };\n}\n\nexport interface TestRunReportSnapshotCollection {\n status: 'complete' | 'partial';\n /** Native dump cutoff before I/O; observation time for partial live sources. */\n capturedAt: string;\n reason?: string;\n}\n\nexport interface TestRunReportAgentDetail {\n reportId: string;\n executionId: string;\n}\n\n/** Operation facts are independent of Agent dump IDs and report snapshots. */\nexport interface TestRunReportOperationEvent {\n operationId: string;\n operationKind: 'node' | 'resource' | 'acquisition' | 'cleanup' | 'readiness';\n kind:\n | 'started'\n | 'cancel-requested'\n | 'settled'\n | 'runner-returned'\n | 'cleanup-deferred';\n at: string;\n stepId?: string;\n scopeId?: string;\n node?: string;\n status?: 'success' | 'failed' | 'not-run';\n /** True only when the actual operation has not settled at Runner return. */\n pending?: boolean;\n error?: TestRunReportError;\n blockingOperations?: TestRunReportOperationReference[];\n}\n\nexport interface TestRunReportPlannedStep {\n id: string;\n phase: TestRunReportStepPhase;\n stepIndex: number;\n node: string;\n title?: string;\n input: TestRunReportValue;\n inputMode: 'template' | 'resolved';\n timeoutMs?: number;\n continueOnError: boolean;\n}\n\nexport interface TestRunReportCasePlan {\n caseId: string;\n name: string;\n caseIndex: number;\n selected: boolean;\n tags: string[];\n onFailure?: 'continue' | 'stop-document';\n beforeEach: TestRunReportPlannedStep[];\n steps: TestRunReportPlannedStep[];\n afterEach: TestRunReportPlannedStep[];\n}\n\n/** A safe snapshot collected before resource acquisition, independent of attempts. */\nexport interface TestRunReportDocumentPlan {\n documentId: string;\n sourcePath: string;\n sourceYaml?: TestRunReportValue;\n retry: { scope: 'case' | 'document'; count: number };\n beforeAll: TestRunReportPlannedStep[];\n cases: TestRunReportCasePlan[];\n afterAll: TestRunReportPlannedStep[];\n}\n\ninterface TestRunReportStepBase {\n id: string;\n planStepId?: string;\n phase: TestRunReportStepPhase;\n stepIndex: number;\n node: string;\n title?: string;\n continuedAfterError: boolean;\n /** Time spent waiting for a cancelled operation before this Step started. */\n waitForPreviousOperationMs?: number;\n input?: TestRunReportValue;\n output?: {\n summary?: string;\n data?: TestRunReportValue;\n };\n error?: TestRunReportError;\n agentDetails?: TestRunReportAgentDetail[];\n agentDetailDiagnostic?: string;\n /** Usage survives even when screenshots or execution detail storage fails. */\n metrics?: TestRunReportMetrics;\n evidenceCollection?: {\n status: 'complete' | 'partial' | 'unknown';\n /** The missing source also prevented independent usage recovery. */\n modelUsageUnavailable?: boolean;\n capturedAt?: string;\n errors?: TestRunReportError[];\n };\n operations?: { capturedAt: string; events: TestRunReportOperationEvent[] };\n}\n\nexport type TestRunReportStep = TestRunReportStepBase &\n (\n | {\n status: TestRunReportRunStatus;\n startedAt: string;\n endedAt: string;\n durationMs: number;\n notRunReason?: never;\n blockedBy?: never;\n }\n | {\n status: 'not-run';\n notRunReason: string;\n blockedBy?: string;\n startedAt?: never;\n endedAt?: never;\n durationMs?: never;\n }\n );\n\nexport interface TestRunReportAttempt {\n attemptId: string;\n attemptIndex: number;\n status: TestRunReportRunStatus;\n executionStatus?: TestRunReportCaseStatus;\n phases?: Partial<Record<TestRunReportStepPhase, TestRunReportPhaseResult>>;\n cleanup?: TestRunReportCleanup;\n pendingOperations?: TestRunReportOperationReference[];\n retryDecision?: TestRunReportRetryDecision;\n startedAt: string;\n endedAt: string;\n durationMs: number;\n beforeEach: TestRunReportStep[];\n steps: TestRunReportStep[];\n afterEach: TestRunReportStep[];\n teardownErrors?: TestRunReportError[];\n hostErrors?: TestRunReportHostError[];\n /** Report groups available for scope-level fallback browsing. */\n scopeReportIds?: string[];\n}\n\nexport interface TestRunReportCase {\n plan?: TestRunReportCasePlan;\n caseId: string;\n name: string;\n caseIndex: number;\n status: TestRunReportCaseStatus;\n notRunReason?: string;\n attempts: TestRunReportAttempt[];\n}\n\nexport interface TestRunReportDocument {\n plan?: TestRunReportDocumentPlan;\n documentId: string;\n /** Logical file identity when separate invocations need distinct UI IDs. */\n logicalDocumentId?: string;\n documentRunId?: string;\n attemptIndex?: number;\n sourcePath: string;\n status: TestRunReportRunStatus;\n executionStatus?: TestRunReportCaseStatus;\n phases?: Partial<Record<TestRunReportStepPhase, TestRunReportPhaseResult>>;\n cleanup?: TestRunReportCleanup;\n pendingOperations?: TestRunReportOperationReference[];\n retryDecision?: TestRunReportRetryDecision;\n startedAt?: string;\n endedAt?: string;\n durationMs?: number;\n beforeAll: TestRunReportStep[];\n cases: TestRunReportCase[];\n afterAll: TestRunReportStep[];\n teardownErrors?: TestRunReportError[];\n hostErrors?: TestRunReportHostError[];\n /** Report groups available for scope-level fallback browsing. */\n scopeReportIds?: string[];\n /** Whole-file invocation history; Cases aggregate their own attempts. */\n attempts?: Omit<TestRunReportDocument, 'cases' | 'attempts'>[];\n}\n\nexport interface TestRunReportCollectionError {\n sourcePath: string;\n error: TestRunReportError;\n}\n\nexport interface TestRunReportProjectLifecycle {\n status: TestRunReportRunStatus;\n startedAt: string;\n endedAt: string;\n durationMs: number;\n setupError?: TestRunReportError;\n teardownErrors?: TestRunReportError[];\n cleanup?: TestRunReportCleanup;\n pendingOperations?: TestRunReportOperationReference[];\n}\n\nexport interface TestRunReportProject {\n plans?: readonly TestRunReportDocumentPlan[];\n projectId: string;\n name: string;\n /** Display identity, also supports legacy custom interface adapters. */\n platform?: string;\n status: TestRunReportRunStatus;\n retry: number;\n lifecycle?: TestRunReportProjectLifecycle;\n documents: TestRunReportDocument[];\n collectionErrors: TestRunReportCollectionError[];\n}\n\nexport interface TestRunReportSummary {\n total: number;\n passed: number;\n failed: number;\n notRun: number;\n filtered: number;\n collectionErrors: number;\n documentFailures: number;\n projectFailures: number;\n}\n\nexport interface TestRunReportDump {\n schemaVersion: 1;\n kind: 'test-runner';\n runId: string;\n status: TestRunReportRunStatus;\n startedAt: string;\n endedAt: string;\n durationMs: number;\n summary: TestRunReportSummary;\n metrics: TestRunReportMetrics;\n executionMetrics?: Record<string, TestRunReportMetrics>;\n projects: TestRunReportProject[];\n diagnostics?: TestRunReportDiagnostic[];\n operationLogs?: { path: string; snapshotAt: string }[];\n}\n\nexport interface TestRunReportSource {\n /** Resource/report scope that owns this Midscene Agent source. */\n scopeId: string;\n /** Absolute path identifying the Midscene Agent report. */\n sourcePath: string;\n /** Current Agent dump JSON; when present, HTML is not parsed for execution data. */\n dumpPath?: string;\n collection?: TestRunReportSnapshotCollection;\n}\n\nexport interface IndexedTestRunReportSource {\n reportId: string;\n scopeId: string;\n sourcePath: string;\n executionIds: string[];\n collection?: TestRunReportSnapshotCollection;\n}\n\nexport interface TestRunReportSourceIndex {\n sources: IndexedTestRunReportSource[];\n metrics: TestRunReportMetrics;\n executionMetrics?: Record<string, TestRunReportMetrics>;\n /** Usage from readable sources, before applying source-availability diagnostics. */\n capturedMetrics?: TestRunReportMetrics;\n diagnostics?: TestRunReportDiagnostic[];\n}\n\nexport interface AssembleTestRunReportOptions {\n outputDir: string;\n /** File or directory name without an extension. */\n reportFileName: string;\n sources: readonly TestRunReportSource[];\n buildRunnerDump(index: TestRunReportSourceIndex): TestRunReportDump;\n overwrite?: boolean;\n}\n"],"names":["TEST_RUN_REPORT_SCRIPT_TYPE"],"mappings":"AAAO,MAAMA,8BAA8B"}
1
+ {"version":3,"file":"test-run-report.mjs","sources":["../../src/test-run-report.ts"],"sourcesContent":["import type { ReportModelUsageSummary } from './report-stats';\n\nexport const TEST_RUN_REPORT_SCRIPT_TYPE = 'midscene_test_run_dump';\n\nexport type TestRunReportRunStatus = 'success' | 'failed';\nexport type TestRunReportCaseStatus = TestRunReportRunStatus | 'not-run';\nexport type TestRunReportStepPhase =\n | 'beforeAll'\n | 'beforeEach'\n | 'steps'\n | 'afterEach'\n | 'afterAll';\n\n/**\n * A JSON-safe value prepared for display in a Midscene Test report.\n *\n * Paths use JSONPath-like notation rooted at `$`. The path arrays are kept\n * beside the value so the UI never presents redacted or truncated data as if\n * it were complete.\n */\nexport interface TestRunReportValue {\n value: unknown;\n truncatedPaths?: string[];\n redactedPaths?: string[];\n}\n\nexport interface TestRunReportError {\n format?: 'midscene-error';\n name: string;\n message: string;\n stack?: string;\n code?: string;\n details?: TestRunReportValue;\n cause?: TestRunReportError;\n errors?: TestRunReportError[];\n truncated?: boolean;\n}\n\nexport interface TestRunReportOperationReference {\n operationId: string;\n scopeId?: string;\n stepId?: string;\n node?: string;\n}\n\n/** Immutable observation; late completion remains in the operation journal. */\nexport interface TestRunReportCleanup {\n status: 'not-required' | 'completed' | 'pending' | 'failed';\n capturedAt: string;\n operationId?: string;\n blockingOperations?: TestRunReportOperationReference[];\n error?: TestRunReportError;\n}\n\nexport interface TestRunReportRetryDecision {\n scope: 'case' | 'document';\n retryCount: number;\n attemptIndex: number;\n decision: 'retry' | 'stop';\n reason:\n | 'passed'\n | 'attempt-failed'\n | 'budget-exhausted'\n | 'cleanup-pending'\n | 'cleanup-failed'\n | 'operation-pending'\n | 'fatal-error'\n | 'interrupted'\n | 'bail'\n | 'infrastructure-error';\n}\n\nexport interface TestRunReportPhaseResult {\n status: 'success' | 'failed' | 'not-run' | 'not-required';\n plannedStepCount: number;\n executedStepCount: number;\n}\n\nexport interface TestRunReportHostError {\n phase:\n | 'setup'\n | 'execution'\n | 'cleanup'\n | 'report'\n | 'publication'\n | 'observer';\n error: TestRunReportError;\n}\n\nexport interface TestRunReportDiagnostic {\n level: 'warning' | 'error';\n code:\n | 'agent-detail-unresolved'\n | 'agent-detail-unavailable'\n | 'large-report'\n | 'run-infrastructure-error'\n | 'agent-source-unavailable'\n | 'source-without-executions';\n message: string;\n scopeId?: string;\n executionId?: string;\n sourcePaths?: string[];\n stepId?: string;\n error?: TestRunReportError;\n}\n\nexport interface TestRunReportMetrics {\n /** Actual models observed in usage records, independent of configured defaults. */\n models?: ReportModelUsageSummary[];\n modelCallCount: number;\n modelTimeMs: number;\n promptTokens: number;\n cachedInputTokens: number;\n completionTokens: number;\n totalTokens: number;\n collection?: {\n status: 'complete' | 'partial' | 'unknown';\n expectedExecutionCount: number;\n capturedExecutionCount: number;\n reasons: string[];\n fields?: Record<\n 'modelCallCount' | 'modelTimeMs' | 'totalTokens',\n 'complete' | 'partial' | 'unknown'\n > &\n Partial<\n Record<\n 'promptTokens' | 'completionTokens',\n 'complete' | 'partial' | 'unknown'\n >\n >;\n };\n}\n\nexport interface TestRunReportSnapshotCollection {\n status: 'complete' | 'partial';\n /** Native dump cutoff before I/O; observation time for partial live sources. */\n capturedAt: string;\n reason?: string;\n}\n\nexport interface TestRunReportAgentDetail {\n reportId: string;\n executionId: string;\n}\n\n/** Operation facts are independent of Agent dump IDs and report snapshots. */\nexport interface TestRunReportOperationEvent {\n operationId: string;\n operationKind: 'node' | 'resource' | 'acquisition' | 'cleanup' | 'readiness';\n kind:\n | 'started'\n | 'cancel-requested'\n | 'settled'\n | 'runner-returned'\n | 'cleanup-deferred';\n at: string;\n stepId?: string;\n scopeId?: string;\n node?: string;\n status?: 'success' | 'failed' | 'not-run';\n /** True only when the actual operation has not settled at Runner return. */\n pending?: boolean;\n error?: TestRunReportError;\n blockingOperations?: TestRunReportOperationReference[];\n}\n\nexport interface TestRunReportPlannedStep {\n id: string;\n phase: TestRunReportStepPhase;\n stepIndex: number;\n node: string;\n title?: string;\n input: TestRunReportValue;\n inputMode: 'template' | 'resolved';\n timeoutMs?: number;\n continueOnError: boolean;\n}\n\nexport interface TestRunReportCasePlan {\n caseId: string;\n name: string;\n caseIndex: number;\n selected: boolean;\n tags: string[];\n onFailure?: 'continue' | 'stop-document';\n beforeEach: TestRunReportPlannedStep[];\n steps: TestRunReportPlannedStep[];\n afterEach: TestRunReportPlannedStep[];\n}\n\n/** A safe snapshot collected before resource acquisition, independent of attempts. */\nexport interface TestRunReportDocumentPlan {\n documentId: string;\n sourcePath: string;\n sourceYaml?: TestRunReportValue;\n retry: { scope: 'case' | 'document'; count: number };\n beforeAll: TestRunReportPlannedStep[];\n cases: TestRunReportCasePlan[];\n afterAll: TestRunReportPlannedStep[];\n}\n\ninterface TestRunReportStepBase {\n id: string;\n planStepId?: string;\n phase: TestRunReportStepPhase;\n stepIndex: number;\n node: string;\n title?: string;\n continuedAfterError: boolean;\n /** Time spent waiting for a cancelled operation before this Step started. */\n waitForPreviousOperationMs?: number;\n input?: TestRunReportValue;\n output?: {\n summary?: string;\n data?: TestRunReportValue;\n };\n error?: TestRunReportError;\n agentDetails?: TestRunReportAgentDetail[];\n agentDetailDiagnostic?: string;\n /** Usage survives even when screenshots or execution detail storage fails. */\n metrics?: TestRunReportMetrics;\n evidenceCollection?: {\n status: 'complete' | 'partial' | 'unknown';\n /** The missing source also prevented independent usage recovery. */\n modelUsageUnavailable?: boolean;\n capturedAt?: string;\n errors?: TestRunReportError[];\n };\n operations?: { capturedAt: string; events: TestRunReportOperationEvent[] };\n}\n\nexport type TestRunReportStep = TestRunReportStepBase &\n (\n | {\n status: TestRunReportRunStatus;\n startedAt: string;\n endedAt: string;\n durationMs: number;\n notRunReason?: never;\n blockedBy?: never;\n }\n | {\n status: 'not-run';\n notRunReason: string;\n blockedBy?: string;\n startedAt?: never;\n endedAt?: never;\n durationMs?: never;\n }\n );\n\nexport interface TestRunReportAttempt {\n attemptId: string;\n attemptIndex: number;\n status: TestRunReportRunStatus;\n executionStatus?: TestRunReportCaseStatus;\n phases?: Partial<Record<TestRunReportStepPhase, TestRunReportPhaseResult>>;\n cleanup?: TestRunReportCleanup;\n pendingOperations?: TestRunReportOperationReference[];\n retryDecision?: TestRunReportRetryDecision;\n startedAt: string;\n endedAt: string;\n durationMs: number;\n beforeEach: TestRunReportStep[];\n steps: TestRunReportStep[];\n afterEach: TestRunReportStep[];\n teardownErrors?: TestRunReportError[];\n hostErrors?: TestRunReportHostError[];\n /** Report groups available for scope-level fallback browsing. */\n scopeReportIds?: string[];\n}\n\nexport interface TestRunReportCase {\n plan?: TestRunReportCasePlan;\n caseId: string;\n name: string;\n caseIndex: number;\n status: TestRunReportCaseStatus;\n notRunReason?: string;\n attempts: TestRunReportAttempt[];\n}\n\nexport interface TestRunReportDocument {\n plan?: TestRunReportDocumentPlan;\n documentId: string;\n /** Logical file identity when separate invocations need distinct UI IDs. */\n logicalDocumentId?: string;\n documentRunId?: string;\n attemptIndex?: number;\n sourcePath: string;\n status: TestRunReportRunStatus;\n executionStatus?: TestRunReportCaseStatus;\n phases?: Partial<Record<TestRunReportStepPhase, TestRunReportPhaseResult>>;\n cleanup?: TestRunReportCleanup;\n pendingOperations?: TestRunReportOperationReference[];\n retryDecision?: TestRunReportRetryDecision;\n startedAt?: string;\n endedAt?: string;\n durationMs?: number;\n beforeAll: TestRunReportStep[];\n cases: TestRunReportCase[];\n afterAll: TestRunReportStep[];\n teardownErrors?: TestRunReportError[];\n hostErrors?: TestRunReportHostError[];\n /** Report groups available for scope-level fallback browsing. */\n scopeReportIds?: string[];\n /** Whole-file invocation history; Cases aggregate their own attempts. */\n attempts?: Omit<TestRunReportDocument, 'cases' | 'attempts'>[];\n}\n\nexport interface TestRunReportCollectionError {\n sourcePath: string;\n error: TestRunReportError;\n}\n\nexport interface TestRunReportProjectLifecycle {\n status: TestRunReportRunStatus;\n startedAt: string;\n endedAt: string;\n durationMs: number;\n setupError?: TestRunReportError;\n teardownErrors?: TestRunReportError[];\n cleanup?: TestRunReportCleanup;\n pendingOperations?: TestRunReportOperationReference[];\n}\n\nexport interface TestRunReportProject {\n plans?: readonly TestRunReportDocumentPlan[];\n projectId: string;\n name: string;\n /** Display identity, also supports legacy custom interface adapters. */\n platform?: string;\n status: TestRunReportRunStatus;\n retry: number;\n lifecycle?: TestRunReportProjectLifecycle;\n documents: TestRunReportDocument[];\n collectionErrors: TestRunReportCollectionError[];\n}\n\nexport interface TestRunReportSummary {\n total: number;\n passed: number;\n failed: number;\n notRun: number;\n filtered: number;\n collectionErrors: number;\n documentFailures: number;\n projectFailures: number;\n}\n\nexport interface TestRunReportDump {\n schemaVersion: 1;\n kind: 'test-runner';\n runId: string;\n status: TestRunReportRunStatus;\n startedAt: string;\n endedAt: string;\n durationMs: number;\n summary: TestRunReportSummary;\n metrics: TestRunReportMetrics;\n executionMetrics?: Record<string, TestRunReportMetrics>;\n projects: TestRunReportProject[];\n diagnostics?: TestRunReportDiagnostic[];\n operationLogs?: { path: string; snapshotAt: string }[];\n}\n\nexport interface TestRunReportSource {\n /** Resource/report scope that owns this Midscene Agent source. */\n scopeId: string;\n /** Absolute path identifying the Midscene Agent report. */\n sourcePath: string;\n /** Current Agent dump JSON; when present, HTML is not parsed for execution data. */\n dumpPath?: string;\n collection?: TestRunReportSnapshotCollection;\n}\n\nexport interface IndexedTestRunReportSource {\n reportId: string;\n scopeId: string;\n sourcePath: string;\n executionIds: string[];\n collection?: TestRunReportSnapshotCollection;\n}\n\nexport interface TestRunReportSourceIndex {\n sources: IndexedTestRunReportSource[];\n metrics: TestRunReportMetrics;\n executionMetrics?: Record<string, TestRunReportMetrics>;\n /** Usage from readable sources, before applying source-availability diagnostics. */\n capturedMetrics?: TestRunReportMetrics;\n diagnostics?: TestRunReportDiagnostic[];\n}\n\nexport interface AssembleTestRunReportOptions {\n outputDir: string;\n /** File or directory name without an extension. */\n reportFileName: string;\n sources: readonly TestRunReportSource[];\n buildRunnerDump(index: TestRunReportSourceIndex): TestRunReportDump;\n overwrite?: boolean;\n}\n"],"names":["TEST_RUN_REPORT_SCRIPT_TYPE"],"mappings":"AAEO,MAAMA,8BAA8B"}
@@ -388,7 +388,9 @@ function mergeTestRunReportDumps(sources, metrics, runId, rawExecutionMetrics) {
388
388
  fields: Object.fromEntries([
389
389
  'modelCallCount',
390
390
  'modelTimeMs',
391
- 'totalTokens'
391
+ 'totalTokens',
392
+ 'promptTokens',
393
+ 'completionTokens'
392
394
  ].map((field)=>{
393
395
  const states = [
394
396
  ...collections.map((value)=>value?.fields?.[field] ?? value?.status ?? 'unknown'),
@@ -1 +1 @@
1
- {"version":3,"file":"test-runner/reporting/merge-report.mjs","sources":["../../../../src/test-runner/reporting/merge-report.ts"],"sourcesContent":["import type {\n TestRunReportCleanup,\n TestRunReportDocument,\n TestRunReportDump,\n TestRunReportError,\n TestRunReportHostError,\n TestRunReportMetrics,\n TestRunReportOperationReference,\n TestRunReportStep,\n} from '../../test-run-report';\nimport type { ReportFileAttributes } from '../../types';\nimport { sumTestRunReportMetrics } from './metrics';\n\nfunction remapError(\n error: TestRunReportError,\n id: (value: string) => string,\n): TestRunReportError {\n const remapReferences = (value: unknown): unknown => {\n if (!value || typeof value !== 'object' || Array.isArray(value))\n return value;\n const result = { ...value } as Record<string, unknown>;\n for (const key of [\n 'blockedByStepId',\n 'stepId',\n 'scopeId',\n 'caseId',\n 'runId',\n 'documentId',\n 'documentRunId',\n ])\n if (typeof result[key] === 'string') result[key] = id(result[key]);\n return result;\n };\n let details = error.details;\n // Only framework-owned details contain report links. Do not rewrite matching\n // property names in custom errors or arbitrary nested business data.\n if (\n details &&\n [\n 'RESOURCE_RECOVERY_TIMEOUT',\n 'RESOURCE_CLEANUP_DEFERRED',\n 'NODE_SCOPE_TEARDOWN_ERROR',\n 'REPORT_SNAPSHOT_FAILED',\n 'CASE_EXECUTION_FAILED',\n 'WORKFLOW_DOCUMENT_EXECUTION_FAILED',\n ].includes(error.code ?? '')\n ) {\n const value = remapReferences(details.value);\n if (value && typeof value === 'object' && !Array.isArray(value)) {\n const mapped = value as Record<string, unknown>;\n for (const key of ['blockingOperations', 'diagnostics'])\n if (Array.isArray(mapped[key]))\n mapped[key] = mapped[key].map(remapReferences);\n }\n details = { ...details, value };\n }\n return {\n ...error,\n ...(details ? { details } : {}),\n ...(error.cause ? { cause: remapError(error.cause, id) } : {}),\n ...(error.errors\n ? { errors: error.errors.map((item) => remapError(item, id)) }\n : {}),\n };\n}\n\nexport interface MergeTestRunReportSource {\n reportId: string;\n sourcePath: string;\n attributes: ReportFileAttributes;\n dump?: TestRunReportDump;\n timing?: { startedAt: string; endedAt: string; durationMs: number };\n}\n\nfunction agentReportAsTestRun(\n source: MergeTestRunReportSource,\n): Pick<TestRunReportDump, 'status' | 'summary' | 'projects'> &\n Partial<\n Pick<\n TestRunReportDump,\n 'startedAt' | 'endedAt' | 'diagnostics' | 'operationLogs'\n >\n > {\n const { attributes, reportId } = source;\n const status =\n attributes.testStatus === 'skipped'\n ? 'not-run'\n : attributes.testStatus === 'passed'\n ? 'success'\n : 'failed';\n const failed = status === 'failed';\n return {\n status: failed ? 'failed' : 'success',\n ...source.timing,\n summary: {\n total: 1,\n passed: status === 'success' ? 1 : 0,\n failed: failed ? 1 : 0,\n notRun: status === 'not-run' ? 1 : 0,\n filtered: 0,\n collectionErrors: 0,\n documentFailures: 0,\n projectFailures: 0,\n },\n projects: [\n {\n projectId: 'agent-report',\n name: attributes.testTitle,\n platform: 'agent',\n status: failed ? 'failed' : 'success',\n retry: 0,\n collectionErrors: [],\n documents: [\n {\n documentId: 'agent-report',\n sourcePath: source.sourcePath,\n status: failed ? 'failed' : 'success',\n beforeAll: [],\n afterAll: [],\n scopeReportIds: [reportId],\n cases: [\n {\n caseId: attributes.testId,\n name: attributes.testTitle,\n caseIndex: 0,\n status,\n attempts:\n status === 'not-run' || !source.timing\n ? []\n : [\n {\n attemptId: 'agent-report',\n attemptIndex: 0,\n status,\n ...source.timing,\n beforeEach: [],\n steps: [],\n afterEach: [],\n scopeReportIds: [reportId],\n },\n ],\n },\n ],\n },\n ],\n },\n ],\n };\n}\n\nfunction retainHostFailure(\n source: MergeTestRunReportSource,\n): TestRunReportDump | undefined {\n const dump = source.dump;\n if (\n !dump ||\n dump.status === 'failed' ||\n !['failed', 'timedOut', 'interrupted'].includes(\n source.attributes.testStatus,\n )\n )\n return dump;\n\n const message = `Host test \"${source.attributes.testTitle}\" finished with status \"${source.attributes.testStatus}\".`;\n const projectIndex = dump.projects.length - 1;\n const project = dump.projects[projectIndex];\n const documentIndex = (project?.documents.length ?? 0) - 1;\n const document = project?.documents[documentIndex];\n const afterHost = <\n T extends Omit<TestRunReportDocument, 'cases' | 'attempts'>,\n >(\n value: T,\n ): T => ({\n ...value,\n status: 'failed',\n afterAll: [\n ...value.afterAll,\n {\n id: `${value.documentRunId ?? value.documentId}:host-result`,\n phase: 'afterAll',\n stepIndex: value.afterAll.length,\n node: 'runner:host-result',\n status: 'failed',\n continuedAfterError: false,\n startedAt: value.endedAt ?? dump.endedAt,\n endedAt: value.endedAt ?? dump.endedAt,\n durationMs: 0,\n error: { name: 'HostTestError', message },\n },\n ],\n });\n // The enclosing test can fail after YAML succeeds. Record that outcome at\n // the file boundary instead of changing successful actions or Case attempts.\n return {\n ...dump,\n status: 'failed',\n summary: {\n ...dump.summary,\n ...(document\n ? { documentFailures: dump.summary.documentFailures + 1 }\n : { projectFailures: dump.summary.projectFailures + 1 }),\n },\n projects: dump.projects.map((item, index) =>\n index !== projectIndex\n ? item\n : {\n ...item,\n status: 'failed',\n documents: item.documents.map((value, index) =>\n index !== documentIndex\n ? value\n : {\n ...afterHost(value),\n ...(value.attempts\n ? {\n attempts: value.attempts.map((attempt, index) =>\n index === value.attempts!.length - 1\n ? afterHost(attempt)\n : attempt,\n ),\n }\n : {}),\n },\n ),\n },\n ),\n diagnostics: [\n ...(dump.diagnostics ?? []),\n {\n level: 'error',\n code: 'run-infrastructure-error',\n message,\n },\n ],\n };\n}\n\nexport function mergeTestRunReportDumps(\n sources: readonly MergeTestRunReportSource[],\n metrics: TestRunReportMetrics,\n runId: string,\n rawExecutionMetrics?: Record<string, TestRunReportMetrics>,\n): TestRunReportDump {\n const dumps = sources.map((source) => {\n if (\n source.dump &&\n (!Number.isFinite(Date.parse(source.dump.startedAt)) ||\n !Number.isFinite(Date.parse(source.dump.endedAt)) ||\n Date.parse(source.dump.endedAt) < Date.parse(source.dump.startedAt))\n )\n throw new Error(\n `Invalid execution timestamps in Midscene Test report: ${source.sourcePath}`,\n );\n const dump = retainHostFailure(source) ?? agentReportAsTestRun(source);\n const id = (value: string) => `${source.reportId}:${value}`;\n const error = (value: TestRunReportError) => remapError(value, id);\n const scopeErrors = <\n T extends {\n setupError?: TestRunReportError;\n teardownErrors?: TestRunReportError[];\n hostErrors?: TestRunReportHostError[];\n },\n >(\n value: T,\n ): T => ({\n ...value,\n ...(value.setupError ? { setupError: error(value.setupError) } : {}),\n ...(value.teardownErrors\n ? { teardownErrors: value.teardownErrors.map(error) }\n : {}),\n ...(value.hostErrors\n ? {\n hostErrors: value.hostErrors.map((host) => ({\n ...host,\n error: error(host.error),\n })),\n }\n : {}),\n });\n const reference = (\n value: TestRunReportOperationReference,\n ): TestRunReportOperationReference => ({\n ...value,\n ...(value.stepId ? { stepId: id(value.stepId) } : {}),\n ...(value.scopeId ? { scopeId: id(value.scopeId) } : {}),\n });\n const cleanup = (value: TestRunReportCleanup | undefined) =>\n value\n ? {\n ...value,\n ...(value.error ? { error: error(value.error) } : {}),\n ...(value.blockingOperations\n ? { blockingOperations: value.blockingOperations.map(reference) }\n : {}),\n }\n : undefined;\n const scopeReports = (reportIds: string[] | undefined) =>\n reportIds?.length ? [source.reportId] : reportIds;\n const step = (value: TestRunReportStep): TestRunReportStep => {\n const result: TestRunReportStep = {\n ...value,\n id: id(value.id),\n ...(value.error ? { error: error(value.error) } : {}),\n ...(value.evidenceCollection\n ? {\n evidenceCollection: {\n ...value.evidenceCollection,\n ...(value.evidenceCollection.errors\n ? { errors: value.evidenceCollection.errors.map(error) }\n : {}),\n },\n }\n : {}),\n ...(value.operations\n ? {\n operations: {\n ...value.operations,\n events: value.operations.events.map((event) => ({\n ...event,\n ...(event.error ? { error: error(event.error) } : {}),\n ...(event.stepId ? { stepId: id(event.stepId) } : {}),\n ...(event.scopeId ? { scopeId: id(event.scopeId) } : {}),\n ...(event.blockingOperations\n ? {\n blockingOperations:\n event.blockingOperations.map(reference),\n }\n : {}),\n })),\n },\n }\n : {}),\n ...(value.agentDetails\n ? {\n agentDetails: value.agentDetails.map((detail) => ({\n ...detail,\n reportId: source.reportId,\n })),\n }\n : {}),\n };\n if (result.status === 'not-run' && result.blockedBy)\n result.blockedBy = id(result.blockedBy);\n return result;\n };\n const documentScope = <\n T extends Omit<TestRunReportDocument, 'cases' | 'attempts'>,\n >(\n value: T,\n ): T => ({\n ...scopeErrors(value),\n ...(value.cleanup ? { cleanup: cleanup(value.cleanup) } : {}),\n ...(value.pendingOperations\n ? { pendingOperations: value.pendingOperations.map(reference) }\n : {}),\n documentId: id(value.documentId),\n ...(value.logicalDocumentId\n ? { logicalDocumentId: id(value.logicalDocumentId) }\n : {}),\n ...(value.documentRunId\n ? { documentRunId: id(value.documentRunId) }\n : {}),\n beforeAll: value.beforeAll.map(step),\n afterAll: value.afterAll.map(step),\n scopeReportIds: scopeReports(value.scopeReportIds),\n });\n // A file can already contain a merged run. Namespace hierarchy IDs while\n // keeping execution IDs stable: the latter also deduplicate shared snapshots.\n return {\n ...dump,\n projects: dump.projects.map((project) => ({\n ...project,\n projectId: id(project.projectId),\n collectionErrors: project.collectionErrors.map((item) => ({\n ...item,\n error: error(item.error),\n })),\n ...(project.lifecycle\n ? {\n lifecycle: {\n ...scopeErrors(project.lifecycle),\n ...(project.lifecycle.cleanup\n ? { cleanup: cleanup(project.lifecycle.cleanup) }\n : {}),\n ...(project.lifecycle.pendingOperations\n ? {\n pendingOperations:\n project.lifecycle.pendingOperations.map(reference),\n }\n : {}),\n },\n }\n : {}),\n documents: project.documents.map((document) => ({\n ...documentScope(document),\n ...(document.attempts\n ? { attempts: document.attempts.map(documentScope) }\n : {}),\n cases: document.cases.map((testCase) => ({\n ...testCase,\n caseId: id(testCase.caseId),\n attempts: testCase.attempts.map((attempt) => ({\n ...scopeErrors(attempt),\n attemptId: id(attempt.attemptId),\n ...(attempt.cleanup ? { cleanup: cleanup(attempt.cleanup) } : {}),\n ...(attempt.pendingOperations\n ? {\n pendingOperations: attempt.pendingOperations.map(reference),\n }\n : {}),\n beforeEach: attempt.beforeEach.map(step),\n steps: attempt.steps.map(step),\n afterEach: attempt.afterEach.map(step),\n scopeReportIds: scopeReports(attempt.scopeReportIds),\n })),\n })),\n })),\n })),\n diagnostics: dump.diagnostics?.map((diagnostic) => ({\n ...diagnostic,\n ...(diagnostic.error ? { error: error(diagnostic.error) } : {}),\n ...(diagnostic.scopeId ? { scopeId: id(diagnostic.scopeId) } : {}),\n ...(diagnostic.stepId ? { stepId: id(diagnostic.stepId) } : {}),\n })),\n };\n });\n // A report without recorded timestamps contributes outcomes, not the time\n // at which an unrelated merge command happened to run.\n const recordedTimes = dumps.flatMap((dump) =>\n dump.startedAt && dump.endedAt\n ? [{ start: Date.parse(dump.startedAt), end: Date.parse(dump.endedAt) }]\n : [],\n );\n if (!recordedTimes.length)\n throw new Error(\n 'Cannot merge Midscene Test reports without recorded execution timestamps.',\n );\n const startedAt = new Date(\n Math.min(...recordedTimes.map((time) => time.start)),\n ).toISOString();\n const endedAt = new Date(\n Math.max(...recordedTimes.map((time) => time.end)),\n ).toISOString();\n const summary = {\n total: 0,\n passed: 0,\n failed: 0,\n notRun: 0,\n filtered: 0,\n collectionErrors: 0,\n documentFailures: 0,\n projectFailures: 0,\n };\n for (const dump of dumps) {\n for (const key of Object.keys(summary) as (keyof typeof summary)[])\n summary[key] += dump.summary[key];\n }\n const diagnostics = dumps.flatMap((dump) => dump.diagnostics ?? []);\n const executionMetrics: Record<string, TestRunReportMetrics> = Object.assign(\n {},\n rawExecutionMetrics,\n ...sources.map((source) => source.dump?.executionMetrics),\n );\n if (rawExecutionMetrics)\n metrics = sumTestRunReportMetrics([\n metrics,\n ...Object.entries(executionMetrics)\n .filter(([id]) => !rawExecutionMetrics[id])\n .map(([, value]) => value),\n ]);\n else if (sources.every((source) => source.dump?.executionMetrics))\n metrics = sumTestRunReportMetrics(Object.values(executionMetrics));\n const collections = sources.flatMap((source) =>\n source.dump ? [source.dump.metrics.collection] : [],\n );\n const incomplete =\n metrics.collection?.status === 'partial' ||\n metrics.collection?.status === 'unknown' ||\n collections.some((collection) => collection?.status !== 'complete');\n const collection = {\n status: (incomplete\n ? metrics.modelCallCount > 0 ||\n collections.some(\n (value) =>\n value?.status === 'complete' || value?.status === 'partial',\n )\n ? 'partial'\n : 'unknown'\n : 'complete') as 'complete' | 'partial' | 'unknown',\n expectedExecutionCount: collections.reduce(\n (count, value) => count + (value?.expectedExecutionCount ?? 0),\n 0,\n ),\n capturedExecutionCount: collections.reduce(\n (count, value) => count + (value?.capturedExecutionCount ?? 0),\n 0,\n ),\n reasons: [\n ...(metrics.collection?.reasons ?? []),\n ...new Set(\n collections.flatMap(\n (value) =>\n value?.reasons ?? [\n 'Model metric collection status is unavailable in a source report.',\n ],\n ),\n ),\n ],\n fields: Object.fromEntries(\n (['modelCallCount', 'modelTimeMs', 'totalTokens'] as const).map(\n (field) => {\n const states = [\n ...collections.map(\n (value) => value?.fields?.[field] ?? value?.status ?? 'unknown',\n ),\n ...(metrics.collection?.fields\n ? [metrics.collection.fields[field]]\n : []),\n ];\n return [\n field,\n states.every((state) => state === 'complete')\n ? 'complete'\n : states.every((state) => state === 'unknown')\n ? 'unknown'\n : 'partial',\n ];\n },\n ),\n ) as NonNullable<NonNullable<TestRunReportMetrics['collection']>['fields']>,\n };\n return {\n schemaVersion: 1,\n kind: 'test-runner',\n runId,\n status: dumps.some((dump) => dump.status === 'failed')\n ? 'failed'\n : 'success',\n startedAt,\n endedAt,\n durationMs: Math.max(0, Date.parse(endedAt) - Date.parse(startedAt)),\n summary,\n metrics: { ...metrics, collection },\n ...(Object.keys(executionMetrics).length ? { executionMetrics } : {}),\n projects: dumps.flatMap((dump) => dump.projects),\n ...(dumps.some((dump) => dump.operationLogs?.length)\n ? { operationLogs: dumps.flatMap((dump) => dump.operationLogs ?? []) }\n : {}),\n ...(diagnostics.length ? { diagnostics } : {}),\n };\n}\n"],"names":["remapError","error","id","remapReferences","value","Array","result","key","details","mapped","item","agentReportAsTestRun","source","attributes","reportId","status","failed","retainHostFailure","dump","message","projectIndex","project","documentIndex","document","afterHost","index","attempt","mergeTestRunReportDumps","sources","metrics","runId","rawExecutionMetrics","dumps","Number","Date","Error","scopeErrors","host","reference","cleanup","undefined","scopeReports","reportIds","step","event","detail","documentScope","testCase","diagnostic","recordedTimes","startedAt","Math","time","endedAt","summary","Object","diagnostics","executionMetrics","sumTestRunReportMetrics","collections","incomplete","collection","count","Set","field","states","state"],"mappings":"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"}
1
+ {"version":3,"file":"test-runner/reporting/merge-report.mjs","sources":["../../../../src/test-runner/reporting/merge-report.ts"],"sourcesContent":["import type {\n TestRunReportCleanup,\n TestRunReportDocument,\n TestRunReportDump,\n TestRunReportError,\n TestRunReportHostError,\n TestRunReportMetrics,\n TestRunReportOperationReference,\n TestRunReportStep,\n} from '../../test-run-report';\nimport type { ReportFileAttributes } from '../../types';\nimport { sumTestRunReportMetrics } from './metrics';\n\nfunction remapError(\n error: TestRunReportError,\n id: (value: string) => string,\n): TestRunReportError {\n const remapReferences = (value: unknown): unknown => {\n if (!value || typeof value !== 'object' || Array.isArray(value))\n return value;\n const result = { ...value } as Record<string, unknown>;\n for (const key of [\n 'blockedByStepId',\n 'stepId',\n 'scopeId',\n 'caseId',\n 'runId',\n 'documentId',\n 'documentRunId',\n ])\n if (typeof result[key] === 'string') result[key] = id(result[key]);\n return result;\n };\n let details = error.details;\n // Only framework-owned details contain report links. Do not rewrite matching\n // property names in custom errors or arbitrary nested business data.\n if (\n details &&\n [\n 'RESOURCE_RECOVERY_TIMEOUT',\n 'RESOURCE_CLEANUP_DEFERRED',\n 'NODE_SCOPE_TEARDOWN_ERROR',\n 'REPORT_SNAPSHOT_FAILED',\n 'CASE_EXECUTION_FAILED',\n 'WORKFLOW_DOCUMENT_EXECUTION_FAILED',\n ].includes(error.code ?? '')\n ) {\n const value = remapReferences(details.value);\n if (value && typeof value === 'object' && !Array.isArray(value)) {\n const mapped = value as Record<string, unknown>;\n for (const key of ['blockingOperations', 'diagnostics'])\n if (Array.isArray(mapped[key]))\n mapped[key] = mapped[key].map(remapReferences);\n }\n details = { ...details, value };\n }\n return {\n ...error,\n ...(details ? { details } : {}),\n ...(error.cause ? { cause: remapError(error.cause, id) } : {}),\n ...(error.errors\n ? { errors: error.errors.map((item) => remapError(item, id)) }\n : {}),\n };\n}\n\nexport interface MergeTestRunReportSource {\n reportId: string;\n sourcePath: string;\n attributes: ReportFileAttributes;\n dump?: TestRunReportDump;\n timing?: { startedAt: string; endedAt: string; durationMs: number };\n}\n\nfunction agentReportAsTestRun(\n source: MergeTestRunReportSource,\n): Pick<TestRunReportDump, 'status' | 'summary' | 'projects'> &\n Partial<\n Pick<\n TestRunReportDump,\n 'startedAt' | 'endedAt' | 'diagnostics' | 'operationLogs'\n >\n > {\n const { attributes, reportId } = source;\n const status =\n attributes.testStatus === 'skipped'\n ? 'not-run'\n : attributes.testStatus === 'passed'\n ? 'success'\n : 'failed';\n const failed = status === 'failed';\n return {\n status: failed ? 'failed' : 'success',\n ...source.timing,\n summary: {\n total: 1,\n passed: status === 'success' ? 1 : 0,\n failed: failed ? 1 : 0,\n notRun: status === 'not-run' ? 1 : 0,\n filtered: 0,\n collectionErrors: 0,\n documentFailures: 0,\n projectFailures: 0,\n },\n projects: [\n {\n projectId: 'agent-report',\n name: attributes.testTitle,\n platform: 'agent',\n status: failed ? 'failed' : 'success',\n retry: 0,\n collectionErrors: [],\n documents: [\n {\n documentId: 'agent-report',\n sourcePath: source.sourcePath,\n status: failed ? 'failed' : 'success',\n beforeAll: [],\n afterAll: [],\n scopeReportIds: [reportId],\n cases: [\n {\n caseId: attributes.testId,\n name: attributes.testTitle,\n caseIndex: 0,\n status,\n attempts:\n status === 'not-run' || !source.timing\n ? []\n : [\n {\n attemptId: 'agent-report',\n attemptIndex: 0,\n status,\n ...source.timing,\n beforeEach: [],\n steps: [],\n afterEach: [],\n scopeReportIds: [reportId],\n },\n ],\n },\n ],\n },\n ],\n },\n ],\n };\n}\n\nfunction retainHostFailure(\n source: MergeTestRunReportSource,\n): TestRunReportDump | undefined {\n const dump = source.dump;\n if (\n !dump ||\n dump.status === 'failed' ||\n !['failed', 'timedOut', 'interrupted'].includes(\n source.attributes.testStatus,\n )\n )\n return dump;\n\n const message = `Host test \"${source.attributes.testTitle}\" finished with status \"${source.attributes.testStatus}\".`;\n const projectIndex = dump.projects.length - 1;\n const project = dump.projects[projectIndex];\n const documentIndex = (project?.documents.length ?? 0) - 1;\n const document = project?.documents[documentIndex];\n const afterHost = <\n T extends Omit<TestRunReportDocument, 'cases' | 'attempts'>,\n >(\n value: T,\n ): T => ({\n ...value,\n status: 'failed',\n afterAll: [\n ...value.afterAll,\n {\n id: `${value.documentRunId ?? value.documentId}:host-result`,\n phase: 'afterAll',\n stepIndex: value.afterAll.length,\n node: 'runner:host-result',\n status: 'failed',\n continuedAfterError: false,\n startedAt: value.endedAt ?? dump.endedAt,\n endedAt: value.endedAt ?? dump.endedAt,\n durationMs: 0,\n error: { name: 'HostTestError', message },\n },\n ],\n });\n // The enclosing test can fail after YAML succeeds. Record that outcome at\n // the file boundary instead of changing successful actions or Case attempts.\n return {\n ...dump,\n status: 'failed',\n summary: {\n ...dump.summary,\n ...(document\n ? { documentFailures: dump.summary.documentFailures + 1 }\n : { projectFailures: dump.summary.projectFailures + 1 }),\n },\n projects: dump.projects.map((item, index) =>\n index !== projectIndex\n ? item\n : {\n ...item,\n status: 'failed',\n documents: item.documents.map((value, index) =>\n index !== documentIndex\n ? value\n : {\n ...afterHost(value),\n ...(value.attempts\n ? {\n attempts: value.attempts.map((attempt, index) =>\n index === value.attempts!.length - 1\n ? afterHost(attempt)\n : attempt,\n ),\n }\n : {}),\n },\n ),\n },\n ),\n diagnostics: [\n ...(dump.diagnostics ?? []),\n {\n level: 'error',\n code: 'run-infrastructure-error',\n message,\n },\n ],\n };\n}\n\nexport function mergeTestRunReportDumps(\n sources: readonly MergeTestRunReportSource[],\n metrics: TestRunReportMetrics,\n runId: string,\n rawExecutionMetrics?: Record<string, TestRunReportMetrics>,\n): TestRunReportDump {\n const dumps = sources.map((source) => {\n if (\n source.dump &&\n (!Number.isFinite(Date.parse(source.dump.startedAt)) ||\n !Number.isFinite(Date.parse(source.dump.endedAt)) ||\n Date.parse(source.dump.endedAt) < Date.parse(source.dump.startedAt))\n )\n throw new Error(\n `Invalid execution timestamps in Midscene Test report: ${source.sourcePath}`,\n );\n const dump = retainHostFailure(source) ?? agentReportAsTestRun(source);\n const id = (value: string) => `${source.reportId}:${value}`;\n const error = (value: TestRunReportError) => remapError(value, id);\n const scopeErrors = <\n T extends {\n setupError?: TestRunReportError;\n teardownErrors?: TestRunReportError[];\n hostErrors?: TestRunReportHostError[];\n },\n >(\n value: T,\n ): T => ({\n ...value,\n ...(value.setupError ? { setupError: error(value.setupError) } : {}),\n ...(value.teardownErrors\n ? { teardownErrors: value.teardownErrors.map(error) }\n : {}),\n ...(value.hostErrors\n ? {\n hostErrors: value.hostErrors.map((host) => ({\n ...host,\n error: error(host.error),\n })),\n }\n : {}),\n });\n const reference = (\n value: TestRunReportOperationReference,\n ): TestRunReportOperationReference => ({\n ...value,\n ...(value.stepId ? { stepId: id(value.stepId) } : {}),\n ...(value.scopeId ? { scopeId: id(value.scopeId) } : {}),\n });\n const cleanup = (value: TestRunReportCleanup | undefined) =>\n value\n ? {\n ...value,\n ...(value.error ? { error: error(value.error) } : {}),\n ...(value.blockingOperations\n ? { blockingOperations: value.blockingOperations.map(reference) }\n : {}),\n }\n : undefined;\n const scopeReports = (reportIds: string[] | undefined) =>\n reportIds?.length ? [source.reportId] : reportIds;\n const step = (value: TestRunReportStep): TestRunReportStep => {\n const result: TestRunReportStep = {\n ...value,\n id: id(value.id),\n ...(value.error ? { error: error(value.error) } : {}),\n ...(value.evidenceCollection\n ? {\n evidenceCollection: {\n ...value.evidenceCollection,\n ...(value.evidenceCollection.errors\n ? { errors: value.evidenceCollection.errors.map(error) }\n : {}),\n },\n }\n : {}),\n ...(value.operations\n ? {\n operations: {\n ...value.operations,\n events: value.operations.events.map((event) => ({\n ...event,\n ...(event.error ? { error: error(event.error) } : {}),\n ...(event.stepId ? { stepId: id(event.stepId) } : {}),\n ...(event.scopeId ? { scopeId: id(event.scopeId) } : {}),\n ...(event.blockingOperations\n ? {\n blockingOperations:\n event.blockingOperations.map(reference),\n }\n : {}),\n })),\n },\n }\n : {}),\n ...(value.agentDetails\n ? {\n agentDetails: value.agentDetails.map((detail) => ({\n ...detail,\n reportId: source.reportId,\n })),\n }\n : {}),\n };\n if (result.status === 'not-run' && result.blockedBy)\n result.blockedBy = id(result.blockedBy);\n return result;\n };\n const documentScope = <\n T extends Omit<TestRunReportDocument, 'cases' | 'attempts'>,\n >(\n value: T,\n ): T => ({\n ...scopeErrors(value),\n ...(value.cleanup ? { cleanup: cleanup(value.cleanup) } : {}),\n ...(value.pendingOperations\n ? { pendingOperations: value.pendingOperations.map(reference) }\n : {}),\n documentId: id(value.documentId),\n ...(value.logicalDocumentId\n ? { logicalDocumentId: id(value.logicalDocumentId) }\n : {}),\n ...(value.documentRunId\n ? { documentRunId: id(value.documentRunId) }\n : {}),\n beforeAll: value.beforeAll.map(step),\n afterAll: value.afterAll.map(step),\n scopeReportIds: scopeReports(value.scopeReportIds),\n });\n // A file can already contain a merged run. Namespace hierarchy IDs while\n // keeping execution IDs stable: the latter also deduplicate shared snapshots.\n return {\n ...dump,\n projects: dump.projects.map((project) => ({\n ...project,\n projectId: id(project.projectId),\n collectionErrors: project.collectionErrors.map((item) => ({\n ...item,\n error: error(item.error),\n })),\n ...(project.lifecycle\n ? {\n lifecycle: {\n ...scopeErrors(project.lifecycle),\n ...(project.lifecycle.cleanup\n ? { cleanup: cleanup(project.lifecycle.cleanup) }\n : {}),\n ...(project.lifecycle.pendingOperations\n ? {\n pendingOperations:\n project.lifecycle.pendingOperations.map(reference),\n }\n : {}),\n },\n }\n : {}),\n documents: project.documents.map((document) => ({\n ...documentScope(document),\n ...(document.attempts\n ? { attempts: document.attempts.map(documentScope) }\n : {}),\n cases: document.cases.map((testCase) => ({\n ...testCase,\n caseId: id(testCase.caseId),\n attempts: testCase.attempts.map((attempt) => ({\n ...scopeErrors(attempt),\n attemptId: id(attempt.attemptId),\n ...(attempt.cleanup ? { cleanup: cleanup(attempt.cleanup) } : {}),\n ...(attempt.pendingOperations\n ? {\n pendingOperations: attempt.pendingOperations.map(reference),\n }\n : {}),\n beforeEach: attempt.beforeEach.map(step),\n steps: attempt.steps.map(step),\n afterEach: attempt.afterEach.map(step),\n scopeReportIds: scopeReports(attempt.scopeReportIds),\n })),\n })),\n })),\n })),\n diagnostics: dump.diagnostics?.map((diagnostic) => ({\n ...diagnostic,\n ...(diagnostic.error ? { error: error(diagnostic.error) } : {}),\n ...(diagnostic.scopeId ? { scopeId: id(diagnostic.scopeId) } : {}),\n ...(diagnostic.stepId ? { stepId: id(diagnostic.stepId) } : {}),\n })),\n };\n });\n // A report without recorded timestamps contributes outcomes, not the time\n // at which an unrelated merge command happened to run.\n const recordedTimes = dumps.flatMap((dump) =>\n dump.startedAt && dump.endedAt\n ? [{ start: Date.parse(dump.startedAt), end: Date.parse(dump.endedAt) }]\n : [],\n );\n if (!recordedTimes.length)\n throw new Error(\n 'Cannot merge Midscene Test reports without recorded execution timestamps.',\n );\n const startedAt = new Date(\n Math.min(...recordedTimes.map((time) => time.start)),\n ).toISOString();\n const endedAt = new Date(\n Math.max(...recordedTimes.map((time) => time.end)),\n ).toISOString();\n const summary = {\n total: 0,\n passed: 0,\n failed: 0,\n notRun: 0,\n filtered: 0,\n collectionErrors: 0,\n documentFailures: 0,\n projectFailures: 0,\n };\n for (const dump of dumps) {\n for (const key of Object.keys(summary) as (keyof typeof summary)[])\n summary[key] += dump.summary[key];\n }\n const diagnostics = dumps.flatMap((dump) => dump.diagnostics ?? []);\n const executionMetrics: Record<string, TestRunReportMetrics> = Object.assign(\n {},\n rawExecutionMetrics,\n ...sources.map((source) => source.dump?.executionMetrics),\n );\n if (rawExecutionMetrics)\n metrics = sumTestRunReportMetrics([\n metrics,\n ...Object.entries(executionMetrics)\n .filter(([id]) => !rawExecutionMetrics[id])\n .map(([, value]) => value),\n ]);\n else if (sources.every((source) => source.dump?.executionMetrics))\n metrics = sumTestRunReportMetrics(Object.values(executionMetrics));\n const collections = sources.flatMap((source) =>\n source.dump ? [source.dump.metrics.collection] : [],\n );\n const incomplete =\n metrics.collection?.status === 'partial' ||\n metrics.collection?.status === 'unknown' ||\n collections.some((collection) => collection?.status !== 'complete');\n const collection = {\n status: (incomplete\n ? metrics.modelCallCount > 0 ||\n collections.some(\n (value) =>\n value?.status === 'complete' || value?.status === 'partial',\n )\n ? 'partial'\n : 'unknown'\n : 'complete') as 'complete' | 'partial' | 'unknown',\n expectedExecutionCount: collections.reduce(\n (count, value) => count + (value?.expectedExecutionCount ?? 0),\n 0,\n ),\n capturedExecutionCount: collections.reduce(\n (count, value) => count + (value?.capturedExecutionCount ?? 0),\n 0,\n ),\n reasons: [\n ...(metrics.collection?.reasons ?? []),\n ...new Set(\n collections.flatMap(\n (value) =>\n value?.reasons ?? [\n 'Model metric collection status is unavailable in a source report.',\n ],\n ),\n ),\n ],\n fields: Object.fromEntries(\n (\n [\n 'modelCallCount',\n 'modelTimeMs',\n 'totalTokens',\n 'promptTokens',\n 'completionTokens',\n ] as const\n ).map((field) => {\n const states = [\n ...collections.map(\n (value) => value?.fields?.[field] ?? value?.status ?? 'unknown',\n ),\n ...(metrics.collection?.fields\n ? [metrics.collection.fields[field]]\n : []),\n ];\n return [\n field,\n states.every((state) => state === 'complete')\n ? 'complete'\n : states.every((state) => state === 'unknown')\n ? 'unknown'\n : 'partial',\n ];\n }),\n ) as NonNullable<NonNullable<TestRunReportMetrics['collection']>['fields']>,\n };\n return {\n schemaVersion: 1,\n kind: 'test-runner',\n runId,\n status: dumps.some((dump) => dump.status === 'failed')\n ? 'failed'\n : 'success',\n startedAt,\n endedAt,\n durationMs: Math.max(0, Date.parse(endedAt) - Date.parse(startedAt)),\n summary,\n metrics: { ...metrics, collection },\n ...(Object.keys(executionMetrics).length ? { executionMetrics } : {}),\n projects: dumps.flatMap((dump) => dump.projects),\n ...(dumps.some((dump) => dump.operationLogs?.length)\n ? { operationLogs: dumps.flatMap((dump) => dump.operationLogs ?? []) }\n : {}),\n ...(diagnostics.length ? { diagnostics } : {}),\n };\n}\n"],"names":["remapError","error","id","remapReferences","value","Array","result","key","details","mapped","item","agentReportAsTestRun","source","attributes","reportId","status","failed","retainHostFailure","dump","message","projectIndex","project","documentIndex","document","afterHost","index","attempt","mergeTestRunReportDumps","sources","metrics","runId","rawExecutionMetrics","dumps","Number","Date","Error","scopeErrors","host","reference","cleanup","undefined","scopeReports","reportIds","step","event","detail","documentScope","testCase","diagnostic","recordedTimes","startedAt","Math","time","endedAt","summary","Object","diagnostics","executionMetrics","sumTestRunReportMetrics","collections","incomplete","collection","count","Set","field","states","state"],"mappings":"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"}
@@ -17,16 +17,23 @@ function collectTestRunReportMetrics(report) {
17
17
  if (unrecorded) reasons.push('A model request started but its usage was not recorded.');
18
18
  if (knownTimes < usages.length) reasons.push('Some model usage records do not include request duration.');
19
19
  if (knownTokens < usages.length) reasons.push('Some model usage records do not include token counts.');
20
+ if (usages.some((usage)=>!number(usage.prompt_tokens))) reasons.push('Some model usage records do not include input token counts.');
21
+ if (usages.some((usage)=>!number(usage.completion_tokens))) reasons.push('Some model usage records do not include output token counts.');
20
22
  const state = (known, missing)=>missing ? known > 0 ? 'partial' : 'unknown' : 'complete';
21
23
  const fields = {
22
24
  modelCallCount: state(summary.timing.modelCallCount, live || unrecorded),
23
25
  modelTimeMs: state(knownTimes, live || unrecorded || knownTimes < usages.length),
26
+ promptTokens: state(usages.filter((usage)=>number(usage.prompt_tokens)).length, live || unrecorded || usages.some((usage)=>!number(usage.prompt_tokens))),
27
+ completionTokens: state(usages.filter((usage)=>number(usage.completion_tokens)).length, live || unrecorded || usages.some((usage)=>!number(usage.completion_tokens))),
24
28
  totalTokens: state(knownTokens, live || unrecorded || knownTokens < usages.length)
25
29
  };
26
30
  return {
27
31
  modelCallCount: summary.timing.modelCallCount,
28
32
  modelTimeMs: summary.timing.modelCallTimeMs,
29
33
  ...summary.tokens,
34
+ ...summary.models.length ? {
35
+ models: summary.models
36
+ } : {},
30
37
  collection: {
31
38
  status: reasons.length ? summary.timing.modelCallCount > 0 ? 'partial' : 'unknown' : 'complete',
32
39
  expectedExecutionCount: 0,
@@ -45,11 +52,41 @@ function sumTestRunReportMetrics(values, missingReasons = []) {
45
52
  completionTokens: 0,
46
53
  totalTokens: 0
47
54
  };
48
- for (const value of values)for (const key of Object.keys(total))if ('collection' !== key) total[key] += value[key];
49
- const fields = Object.fromEntries([
55
+ const numericKeys = [
50
56
  'modelCallCount',
51
57
  'modelTimeMs',
58
+ 'promptTokens',
59
+ 'cachedInputTokens',
60
+ 'completionTokens',
52
61
  'totalTokens'
62
+ ];
63
+ const models = new Map();
64
+ for (const value of values){
65
+ for (const key of numericKeys)total[key] += value[key];
66
+ for (const model of value.models ?? []){
67
+ const previous = models.get(model.modelName);
68
+ if (previous) for (const key of [
69
+ 'callCount',
70
+ 'modelCallTimeMs',
71
+ 'promptTokens',
72
+ 'cachedInputTokens',
73
+ 'completionTokens',
74
+ 'totalTokens'
75
+ ])previous[key] += model[key];
76
+ else models.set(model.modelName, {
77
+ ...model
78
+ });
79
+ }
80
+ }
81
+ if (models.size) total.models = [
82
+ ...models.values()
83
+ ];
84
+ const fields = Object.fromEntries([
85
+ 'modelCallCount',
86
+ 'modelTimeMs',
87
+ 'totalTokens',
88
+ 'promptTokens',
89
+ 'completionTokens'
53
90
  ].map((field)=>{
54
91
  const states = values.map((value)=>value.collection?.fields?.[field] ?? value.collection?.status ?? 'complete');
55
92
  if (missingReasons.length) states.push('unknown');
@@ -1 +1 @@
1
- {"version":3,"file":"test-runner/reporting/metrics.mjs","sources":["../../../../src/test-runner/reporting/metrics.ts"],"sourcesContent":["import { collectReportSummary } from '../../report-stats';\nimport type { TestRunReportMetrics } from '../../test-run-report';\nimport type { AIUsageInfo, IReportActionDump } from '../../types';\n\n/** A captured execution can still lack provider usage or contain a live request. */\nexport function collectTestRunReportMetrics(\n report: Pick<IReportActionDump, 'executions'>,\n): TestRunReportMetrics {\n const summary = collectReportSummary(report);\n const tasks = report.executions.flatMap((execution) => execution.tasks);\n const hasUsage = (usage: AIUsageInfo | undefined): usage is AIUsageInfo =>\n !!usage &&\n Object.values(usage).some((value) => value !== undefined && value !== null);\n const usages = tasks.flatMap((task) =>\n [task.usage, task.searchAreaUsage].filter(hasUsage),\n );\n const live = tasks.some(\n (task) =>\n task.timing?.callAiStart !== undefined &&\n (task.status === 'pending' || task.status === 'running'),\n );\n const unrecorded = tasks.some(\n (task) => task.timing?.callAiStart !== undefined && !hasUsage(task.usage),\n );\n const number = (value: unknown) =>\n typeof value === 'number' && Number.isFinite(value) && value >= 0;\n const knownTimes = usages.filter((usage) => number(usage.time_cost)).length;\n const knownTokens = usages.filter(\n (usage) =>\n number(usage.total_tokens) ||\n (number(usage.prompt_tokens) && number(usage.completion_tokens)),\n ).length;\n const reasons: string[] = [];\n if (live)\n reasons.push('A model request was still running when usage was captured.');\n if (unrecorded)\n reasons.push('A model request started but its usage was not recorded.');\n if (knownTimes < usages.length)\n reasons.push('Some model usage records do not include request duration.');\n if (knownTokens < usages.length)\n reasons.push('Some model usage records do not include token counts.');\n const state = (\n known: number,\n missing: boolean,\n ): 'complete' | 'partial' | 'unknown' =>\n missing ? (known > 0 ? 'partial' : 'unknown') : 'complete';\n const fields = {\n modelCallCount: state(summary.timing.modelCallCount, live || unrecorded),\n modelTimeMs: state(\n knownTimes,\n live || unrecorded || knownTimes < usages.length,\n ),\n totalTokens: state(\n knownTokens,\n live || unrecorded || knownTokens < usages.length,\n ),\n };\n return {\n modelCallCount: summary.timing.modelCallCount,\n modelTimeMs: summary.timing.modelCallTimeMs,\n ...summary.tokens,\n collection: {\n status: reasons.length\n ? summary.timing.modelCallCount > 0\n ? 'partial'\n : 'unknown'\n : 'complete',\n expectedExecutionCount: 0,\n capturedExecutionCount: 0,\n reasons,\n fields,\n },\n };\n}\n\n/** Add usage facts without treating missing screenshots as missing model calls. */\nexport function sumTestRunReportMetrics(\n values: readonly TestRunReportMetrics[],\n missingReasons: readonly string[] = [],\n): TestRunReportMetrics {\n const total: TestRunReportMetrics = {\n modelCallCount: 0,\n modelTimeMs: 0,\n promptTokens: 0,\n cachedInputTokens: 0,\n completionTokens: 0,\n totalTokens: 0,\n };\n for (const value of values)\n for (const key of Object.keys(total) as (keyof typeof total)[])\n if (key !== 'collection') total[key] += value[key];\n const fields = Object.fromEntries(\n (['modelCallCount', 'modelTimeMs', 'totalTokens'] as const).map((field) => {\n const states = values.map(\n (value) =>\n value.collection?.fields?.[field] ??\n value.collection?.status ??\n 'complete',\n );\n if (missingReasons.length) states.push('unknown');\n return [\n field,\n states.every((state) => state === 'complete')\n ? 'complete'\n : states.every((state) => state === 'unknown')\n ? 'unknown'\n : 'partial',\n ];\n }),\n ) as NonNullable<TestRunReportMetrics['collection']>['fields'] & {};\n total.collection = {\n status: Object.values(fields).every((state) => state === 'complete')\n ? 'complete'\n : Object.values(fields).every((state) => state === 'unknown')\n ? 'unknown'\n : 'partial',\n fields,\n expectedExecutionCount: 0,\n capturedExecutionCount: 0,\n reasons: [\n ...new Set([\n ...values.flatMap((value) => value.collection?.reasons ?? []),\n ...missingReasons,\n ]),\n ],\n };\n return total;\n}\n"],"names":["collectTestRunReportMetrics","report","summary","collectReportSummary","tasks","execution","hasUsage","usage","Object","value","usages","task","live","undefined","unrecorded","number","Number","knownTimes","knownTokens","reasons","state","known","missing","fields","sumTestRunReportMetrics","values","missingReasons","total","key","field","states","Set"],"mappings":"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"}
1
+ {"version":3,"file":"test-runner/reporting/metrics.mjs","sources":["../../../../src/test-runner/reporting/metrics.ts"],"sourcesContent":["import {\n type ReportModelUsageSummary,\n collectReportSummary,\n} from '../../report-stats';\nimport type { TestRunReportMetrics } from '../../test-run-report';\nimport type { AIUsageInfo, IReportActionDump } from '../../types';\n\n/** A captured execution can still lack provider usage or contain a live request. */\nexport function collectTestRunReportMetrics(\n report: Pick<IReportActionDump, 'executions'>,\n): TestRunReportMetrics {\n const summary = collectReportSummary(report);\n const tasks = report.executions.flatMap((execution) => execution.tasks);\n const hasUsage = (usage: AIUsageInfo | undefined): usage is AIUsageInfo =>\n !!usage &&\n Object.values(usage).some((value) => value !== undefined && value !== null);\n const usages = tasks.flatMap((task) =>\n [task.usage, task.searchAreaUsage].filter(hasUsage),\n );\n const live = tasks.some(\n (task) =>\n task.timing?.callAiStart !== undefined &&\n (task.status === 'pending' || task.status === 'running'),\n );\n const unrecorded = tasks.some(\n (task) => task.timing?.callAiStart !== undefined && !hasUsage(task.usage),\n );\n const number = (value: unknown) =>\n typeof value === 'number' && Number.isFinite(value) && value >= 0;\n const knownTimes = usages.filter((usage) => number(usage.time_cost)).length;\n const knownTokens = usages.filter(\n (usage) =>\n number(usage.total_tokens) ||\n (number(usage.prompt_tokens) && number(usage.completion_tokens)),\n ).length;\n const reasons: string[] = [];\n if (live)\n reasons.push('A model request was still running when usage was captured.');\n if (unrecorded)\n reasons.push('A model request started but its usage was not recorded.');\n if (knownTimes < usages.length)\n reasons.push('Some model usage records do not include request duration.');\n if (knownTokens < usages.length)\n reasons.push('Some model usage records do not include token counts.');\n if (usages.some((usage) => !number(usage.prompt_tokens)))\n reasons.push('Some model usage records do not include input token counts.');\n if (usages.some((usage) => !number(usage.completion_tokens)))\n reasons.push(\n 'Some model usage records do not include output token counts.',\n );\n const state = (\n known: number,\n missing: boolean,\n ): 'complete' | 'partial' | 'unknown' =>\n missing ? (known > 0 ? 'partial' : 'unknown') : 'complete';\n const fields = {\n modelCallCount: state(summary.timing.modelCallCount, live || unrecorded),\n modelTimeMs: state(\n knownTimes,\n live || unrecorded || knownTimes < usages.length,\n ),\n promptTokens: state(\n usages.filter((usage) => number(usage.prompt_tokens)).length,\n live ||\n unrecorded ||\n usages.some((usage) => !number(usage.prompt_tokens)),\n ),\n completionTokens: state(\n usages.filter((usage) => number(usage.completion_tokens)).length,\n live ||\n unrecorded ||\n usages.some((usage) => !number(usage.completion_tokens)),\n ),\n totalTokens: state(\n knownTokens,\n live || unrecorded || knownTokens < usages.length,\n ),\n };\n return {\n modelCallCount: summary.timing.modelCallCount,\n modelTimeMs: summary.timing.modelCallTimeMs,\n ...summary.tokens,\n ...(summary.models.length ? { models: summary.models } : {}),\n collection: {\n status: reasons.length\n ? summary.timing.modelCallCount > 0\n ? 'partial'\n : 'unknown'\n : 'complete',\n expectedExecutionCount: 0,\n capturedExecutionCount: 0,\n reasons,\n fields,\n },\n };\n}\n\n/** Add usage facts without treating missing screenshots as missing model calls. */\nexport function sumTestRunReportMetrics(\n values: readonly TestRunReportMetrics[],\n missingReasons: readonly string[] = [],\n): TestRunReportMetrics {\n const total: TestRunReportMetrics = {\n modelCallCount: 0,\n modelTimeMs: 0,\n promptTokens: 0,\n cachedInputTokens: 0,\n completionTokens: 0,\n totalTokens: 0,\n };\n const numericKeys = [\n 'modelCallCount',\n 'modelTimeMs',\n 'promptTokens',\n 'cachedInputTokens',\n 'completionTokens',\n 'totalTokens',\n ] as const;\n const models = new Map<string, ReportModelUsageSummary>();\n for (const value of values) {\n for (const key of numericKeys) total[key] += value[key];\n for (const model of value.models ?? []) {\n const previous = models.get(model.modelName);\n if (!previous) models.set(model.modelName, { ...model });\n else\n for (const key of [\n 'callCount',\n 'modelCallTimeMs',\n 'promptTokens',\n 'cachedInputTokens',\n 'completionTokens',\n 'totalTokens',\n ] as const)\n previous[key] += model[key];\n }\n }\n if (models.size) total.models = [...models.values()];\n const fields = Object.fromEntries(\n (\n [\n 'modelCallCount',\n 'modelTimeMs',\n 'totalTokens',\n 'promptTokens',\n 'completionTokens',\n ] as const\n ).map((field) => {\n const states = values.map(\n (value) =>\n value.collection?.fields?.[field] ??\n value.collection?.status ??\n 'complete',\n );\n if (missingReasons.length) states.push('unknown');\n return [\n field,\n states.every((state) => state === 'complete')\n ? 'complete'\n : states.every((state) => state === 'unknown')\n ? 'unknown'\n : 'partial',\n ];\n }),\n ) as NonNullable<TestRunReportMetrics['collection']>['fields'] & {};\n total.collection = {\n status: Object.values(fields).every((state) => state === 'complete')\n ? 'complete'\n : Object.values(fields).every((state) => state === 'unknown')\n ? 'unknown'\n : 'partial',\n fields,\n expectedExecutionCount: 0,\n capturedExecutionCount: 0,\n reasons: [\n ...new Set([\n ...values.flatMap((value) => value.collection?.reasons ?? []),\n ...missingReasons,\n ]),\n ],\n };\n return total;\n}\n"],"names":["collectTestRunReportMetrics","report","summary","collectReportSummary","tasks","execution","hasUsage","usage","Object","value","usages","task","live","undefined","unrecorded","number","Number","knownTimes","knownTokens","reasons","state","known","missing","fields","sumTestRunReportMetrics","values","missingReasons","total","numericKeys","models","Map","key","model","previous","field","states","Set"],"mappings":";AAQO,SAASA,4BACdC,MAA6C;IAE7C,MAAMC,UAAUC,qBAAqBF;IACrC,MAAMG,QAAQH,OAAO,UAAU,CAAC,OAAO,CAAC,CAACI,YAAcA,UAAU,KAAK;IACtE,MAAMC,WAAW,CAACC,QAChB,CAAC,CAACA,SACFC,OAAO,MAAM,CAACD,OAAO,IAAI,CAAC,CAACE,QAAUA,QAAAA;IACvC,MAAMC,SAASN,MAAM,OAAO,CAAC,CAACO,OAC5B;YAACA,KAAK,KAAK;YAAEA,KAAK,eAAe;SAAC,CAAC,MAAM,CAACL;IAE5C,MAAMM,OAAOR,MAAM,IAAI,CACrB,CAACO,OACCA,KAAK,MAAM,EAAE,gBAAgBE,UAC5BF,CAAAA,AAAgB,cAAhBA,KAAK,MAAM,IAAkBA,AAAgB,cAAhBA,KAAK,MAAM,AAAa;IAE1D,MAAMG,aAAaV,MAAM,IAAI,CAC3B,CAACO,OAASA,KAAK,MAAM,EAAE,gBAAgBE,UAAa,CAACP,SAASK,KAAK,KAAK;IAE1E,MAAMI,SAAS,CAACN,QACd,AAAiB,YAAjB,OAAOA,SAAsBO,OAAO,QAAQ,CAACP,UAAUA,SAAS;IAClE,MAAMQ,aAAaP,OAAO,MAAM,CAAC,CAACH,QAAUQ,OAAOR,MAAM,SAAS,GAAG,MAAM;IAC3E,MAAMW,cAAcR,OAAO,MAAM,CAC/B,CAACH,QACCQ,OAAOR,MAAM,YAAY,KACxBQ,OAAOR,MAAM,aAAa,KAAKQ,OAAOR,MAAM,iBAAiB,GAChE,MAAM;IACR,MAAMY,UAAoB,EAAE;IAC5B,IAAIP,MACFO,QAAQ,IAAI,CAAC;IACf,IAAIL,YACFK,QAAQ,IAAI,CAAC;IACf,IAAIF,aAAaP,OAAO,MAAM,EAC5BS,QAAQ,IAAI,CAAC;IACf,IAAID,cAAcR,OAAO,MAAM,EAC7BS,QAAQ,IAAI,CAAC;IACf,IAAIT,OAAO,IAAI,CAAC,CAACH,QAAU,CAACQ,OAAOR,MAAM,aAAa,IACpDY,QAAQ,IAAI,CAAC;IACf,IAAIT,OAAO,IAAI,CAAC,CAACH,QAAU,CAACQ,OAAOR,MAAM,iBAAiB,IACxDY,QAAQ,IAAI,CACV;IAEJ,MAAMC,QAAQ,CACZC,OACAC,UAEAA,UAAWD,QAAQ,IAAI,YAAY,YAAa;IAClD,MAAME,SAAS;QACb,gBAAgBH,MAAMlB,QAAQ,MAAM,CAAC,cAAc,EAAEU,QAAQE;QAC7D,aAAaM,MACXH,YACAL,QAAQE,cAAcG,aAAaP,OAAO,MAAM;QAElD,cAAcU,MACZV,OAAO,MAAM,CAAC,CAACH,QAAUQ,OAAOR,MAAM,aAAa,GAAG,MAAM,EAC5DK,QACEE,cACAJ,OAAO,IAAI,CAAC,CAACH,QAAU,CAACQ,OAAOR,MAAM,aAAa;QAEtD,kBAAkBa,MAChBV,OAAO,MAAM,CAAC,CAACH,QAAUQ,OAAOR,MAAM,iBAAiB,GAAG,MAAM,EAChEK,QACEE,cACAJ,OAAO,IAAI,CAAC,CAACH,QAAU,CAACQ,OAAOR,MAAM,iBAAiB;QAE1D,aAAaa,MACXF,aACAN,QAAQE,cAAcI,cAAcR,OAAO,MAAM;IAErD;IACA,OAAO;QACL,gBAAgBR,QAAQ,MAAM,CAAC,cAAc;QAC7C,aAAaA,QAAQ,MAAM,CAAC,eAAe;QAC3C,GAAGA,QAAQ,MAAM;QACjB,GAAIA,QAAQ,MAAM,CAAC,MAAM,GAAG;YAAE,QAAQA,QAAQ,MAAM;QAAC,IAAI,CAAC,CAAC;QAC3D,YAAY;YACV,QAAQiB,QAAQ,MAAM,GAClBjB,QAAQ,MAAM,CAAC,cAAc,GAAG,IAC9B,YACA,YACF;YACJ,wBAAwB;YACxB,wBAAwB;YACxBiB;YACAI;QACF;IACF;AACF;AAGO,SAASC,wBACdC,MAAuC,EACvCC,iBAAoC,EAAE;IAEtC,MAAMC,QAA8B;QAClC,gBAAgB;QAChB,aAAa;QACb,cAAc;QACd,mBAAmB;QACnB,kBAAkB;QAClB,aAAa;IACf;IACA,MAAMC,cAAc;QAClB;QACA;QACA;QACA;QACA;QACA;KACD;IACD,MAAMC,SAAS,IAAIC;IACnB,KAAK,MAAMrB,SAASgB,OAAQ;QAC1B,KAAK,MAAMM,OAAOH,YAAaD,KAAK,CAACI,IAAI,IAAItB,KAAK,CAACsB,IAAI;QACvD,KAAK,MAAMC,SAASvB,MAAM,MAAM,IAAI,EAAE,CAAE;YACtC,MAAMwB,WAAWJ,OAAO,GAAG,CAACG,MAAM,SAAS;YAC3C,IAAKC,UAEH,KAAK,MAAMF,OAAO;gBAChB;gBACA;gBACA;gBACA;gBACA;gBACA;aACD,CACCE,QAAQ,CAACF,IAAI,IAAIC,KAAK,CAACD,IAAI;iBAVhBF,OAAO,GAAG,CAACG,MAAM,SAAS,EAAE;gBAAE,GAAGA,KAAK;YAAC;QAWxD;IACF;IACA,IAAIH,OAAO,IAAI,EAAEF,MAAM,MAAM,GAAG;WAAIE,OAAO,MAAM;KAAG;IACpD,MAAMN,SAASf,OAAO,WAAW,CAE7B;QACE;QACA;QACA;QACA;QACA;KACD,CACD,GAAG,CAAC,CAAC0B;QACL,MAAMC,SAASV,OAAO,GAAG,CACvB,CAAChB,QACCA,MAAM,UAAU,EAAE,QAAQ,CAACyB,MAAM,IACjCzB,MAAM,UAAU,EAAE,UAClB;QAEJ,IAAIiB,eAAe,MAAM,EAAES,OAAO,IAAI,CAAC;QACvC,OAAO;YACLD;YACAC,OAAO,KAAK,CAAC,CAACf,QAAUA,AAAU,eAAVA,SACpB,aACAe,OAAO,KAAK,CAAC,CAACf,QAAUA,AAAU,cAAVA,SACtB,YACA;SACP;IACH;IAEFO,MAAM,UAAU,GAAG;QACjB,QAAQnB,OAAO,MAAM,CAACe,QAAQ,KAAK,CAAC,CAACH,QAAUA,AAAU,eAAVA,SAC3C,aACAZ,OAAO,MAAM,CAACe,QAAQ,KAAK,CAAC,CAACH,QAAUA,AAAU,cAAVA,SACrC,YACA;QACNG;QACA,wBAAwB;QACxB,wBAAwB;QACxB,SAAS;eACJ,IAAIa,IAAI;mBACNX,OAAO,OAAO,CAAC,CAAChB,QAAUA,MAAM,UAAU,EAAE,WAAW,EAAE;mBACzDiB;aACJ;SACF;IACH;IACA,OAAOC;AACT"}
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.16.1";
187
+ return "1.16.2";
188
188
  }
189
189
  function debugLog(...message) {
190
190
  const debugMode = process.env[MIDSCENE_DEBUG_MODE];
@@ -138,7 +138,7 @@ async function createScreenshotBoundUIContext(screenshotBase64, opt) {
138
138
  }
139
139
  function printReportMsg(filepath) {
140
140
  if (env_namespaceObject.globalConfigManager.getEnvConfigInBoolean(env_namespaceObject.MIDSCENE_REPORT_QUIET)) return;
141
- (0, utils_namespaceObject.logMsg)(`Midscene - report file updated: ${filepath}`);
141
+ (0, logger_namespaceObject.logReport)(`Midscene - report file updated: ${filepath}`);
142
142
  }
143
143
  function normalizeFilePaths(files, options = {}) {
144
144
  const { fileExists = external_node_fs_namespaceObject.existsSync, isInBrowser = utils_namespaceObject.ifInBrowser, resolvePath = external_node_path_namespaceObject.resolve, wslDistroName = process.env.WSL_DISTRO_NAME, cwd = process.cwd() } = options;
@@ -193,7 +193,7 @@ async function matchElementFromCache(context, cacheEntry, cachePrompt, cacheable
193
193
  return;
194
194
  }
195
195
  }
196
- const getMidsceneVersion = ()=>"1.16.1";
196
+ const getMidsceneVersion = ()=>"1.16.2";
197
197
  const parsePrompt = (prompt)=>{
198
198
  if ('string' == typeof prompt) return {
199
199
  textPrompt: prompt,
@@ -1 +1 @@
1
- {"version":3,"file":"agent/utils.js","sources":["webpack/runtime/define_property_getters","webpack/runtime/has_own_property","webpack/runtime/make_namespace_object","../../../src/agent/utils.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 { existsSync } from 'node:fs';\nimport { resolve } from 'node:path';\nimport type { PixelLocateResult } from '@/ai-model/shared/model-locate-result';\nimport type { TMultimodalPrompt, TUserPrompt } from '@/common';\nimport type { AbstractInterface } from '@/device';\nimport { ScreenshotItem } from '@/screenshot-item';\nimport type {\n DetailedLocateParam,\n ElementCacheFeature,\n LocateResultElement,\n Rect,\n ScrollParam,\n Size,\n UIContext,\n} from '@/types';\nimport { uploadTestInfoToServer } from '@/utils';\nimport {\n MIDSCENE_REPORT_QUIET,\n globalConfigManager,\n} from '@midscene/shared/env';\nimport {\n createImgBase64ByFormat,\n imageInfoOfBase64,\n} from '@midscene/shared/img';\nimport { getDebug } from '@midscene/shared/logger';\nimport { _keyDefinitions } from '@midscene/shared/us-keyboard-layout';\nimport { assert, ifInBrowser, logMsg } from '@midscene/shared/utils';\nimport { prepareRawScreenshot } from './screenshot-preparation';\nimport type { TaskCache } from './task-cache';\nimport { debug as cacheDebug } from './task-cache';\n\nexport { getReportFileName } from './report-file-name';\n\nconst agentDebug = getDebug('agent');\nconst screenshotDataUrlPattern = /^data:image\\/[a-zA-Z0-9.+-]+;base64,/i;\n\nconst inferBase64ImageFormat = (base64Body: string) => {\n if (base64Body.startsWith('iVBORw0KGgo')) {\n return 'png';\n }\n return 'jpeg';\n};\n\nconst normalizeScreenshotBase64 = (screenshotBase64: string) => {\n const trimmedBase64 = screenshotBase64.trim();\n if (screenshotDataUrlPattern.test(trimmedBase64)) {\n return trimmedBase64;\n }\n\n const base64Body = trimmedBase64.replace(/\\s/g, '');\n assert(base64Body, 'screenshotBase64 must include image data');\n return createImgBase64ByFormat(\n inferBase64ImageFormat(base64Body),\n base64Body,\n );\n};\n\nconst legacyScrollTypeMap = {\n once: 'singleAction',\n untilBottom: 'scrollToBottom',\n untilTop: 'scrollToTop',\n untilRight: 'scrollToRight',\n untilLeft: 'scrollToLeft',\n} as const;\n\nexport const normalizeScrollType = (\n scrollType: string | undefined,\n): ScrollParam['scrollType'] | undefined => {\n if (!scrollType) {\n return undefined;\n }\n\n if (scrollType in legacyScrollTypeMap) {\n return legacyScrollTypeMap[scrollType as keyof typeof legacyScrollTypeMap];\n }\n\n return scrollType as ScrollParam['scrollType'];\n};\n\nexport async function commonContextParser(\n interfaceInstance: AbstractInterface,\n _opt: {\n uploadServerUrl?: string;\n screenshotShrinkFactor?: number;\n },\n): Promise<UIContext> {\n const debug = getDebug('commonContextParser');\n\n assert(interfaceInstance, 'interfaceInstance is required');\n\n debug('Getting interface description');\n const description = interfaceInstance.describe?.() || '';\n debug('Interface description end');\n\n debug('Uploading test info to server');\n uploadTestInfoToServer({\n testUrl: description,\n serverUrl: _opt.uploadServerUrl,\n });\n debug('UploadTestInfoToServer end');\n\n debug('will get size');\n const interfaceSize = await interfaceInstance.size();\n const { width: logicalWidth, height: logicalHeight } = interfaceSize;\n\n if ((interfaceSize as unknown as { dpr: number }).dpr) {\n console.warn(\n 'Warning: return value of interface.size() include a dpr property, which is not expected and ignored. ',\n );\n }\n\n if (!Number.isFinite(logicalWidth) || !Number.isFinite(logicalHeight)) {\n throw new Error(\n `Invalid interface size: width and height must be finite numbers. Received width: ${logicalWidth}, height: ${logicalHeight}`,\n );\n }\n\n if (logicalWidth <= 0 || logicalHeight <= 0) {\n throw new Error(\n `Invalid interface size: width and height must be positive numbers. Received width: ${logicalWidth}, height: ${logicalHeight}`,\n );\n }\n\n debug(`size: ${logicalWidth}x${logicalHeight}`);\n\n const screenshotBase64 = await interfaceInstance.screenshotBase64();\n const screenshotCapturedAt = Date.now();\n assert(screenshotBase64!, 'screenshotBase64 is required');\n const userShrinkFactor = _opt.screenshotShrinkFactor ?? 1;\n\n debug('will get screenshot dimensions');\n const preparedScreenshot = await prepareRawScreenshot(screenshotBase64, {\n shrinkFactor: userShrinkFactor,\n });\n const { width: imgWidth, height: imgHeight } =\n preparedScreenshot.originalSize;\n debug('screenshot dimensions', imgWidth, 'x', imgHeight);\n\n // Detect orientation mismatch between logical size and screenshot.\n // Some devices (e.g. OPPO) report wrong orientation via ADB, causing\n // size() to return portrait dimensions even when the device is landscape.\n // We detect this by comparing aspect ratios and swap if they disagree.\n const logicalIsPortrait = logicalWidth < logicalHeight;\n const screenshotIsPortrait = imgWidth < imgHeight;\n let finalLogicalWidth = logicalWidth;\n let finalLogicalHeight = logicalHeight;\n if (logicalIsPortrait !== screenshotIsPortrait) {\n debug(\n `Orientation mismatch detected: logical size ${logicalWidth}x${logicalHeight} (${logicalIsPortrait ? 'portrait' : 'landscape'}) vs screenshot ${imgWidth}x${imgHeight} (${screenshotIsPortrait ? 'portrait' : 'landscape'}). Swapping logical dimensions.`,\n );\n finalLogicalWidth = logicalHeight;\n finalLogicalHeight = logicalWidth;\n }\n\n const dpr = imgWidth / finalLogicalWidth;\n\n debug('calculated dpr:', dpr);\n\n const shrunkShotToLogicalRatio = dpr / userShrinkFactor;\n\n debug('shrunkShotToLogicalRatio', shrunkShotToLogicalRatio);\n\n if (userShrinkFactor > 1) {\n debug(\n `Applied screenshot shrink factor: ${userShrinkFactor} (physical: ${imgWidth}x${imgHeight} -> target: ${preparedScreenshot.shotSize.width}x${preparedScreenshot.shotSize.height})`,\n );\n }\n\n return {\n shotSize: preparedScreenshot.shotSize,\n deprecatedDpr: dpr,\n screenshot: ScreenshotItem.create(\n preparedScreenshot.base64,\n screenshotCapturedAt,\n ),\n shrunkShotToLogicalRatio,\n };\n}\n\nexport async function createScreenshotBoundUIContext(\n screenshotBase64: string,\n opt: {\n screenshotSize?: Size;\n },\n): Promise<UIContext> {\n const normalizedScreenshotBase64 =\n normalizeScreenshotBase64(screenshotBase64);\n const actualScreenshotSize = await imageInfoOfBase64(\n normalizedScreenshotBase64,\n );\n if (\n opt.screenshotSize &&\n (opt.screenshotSize.width !== actualScreenshotSize.width ||\n opt.screenshotSize.height !== actualScreenshotSize.height)\n ) {\n agentDebug(\n 'describeElementAtPoint screenshotSize mismatch, use actual size',\n {\n provided: opt.screenshotSize,\n actual: actualScreenshotSize,\n },\n );\n }\n\n return {\n screenshot: ScreenshotItem.create(normalizedScreenshotBase64, Date.now()),\n shotSize: actualScreenshotSize,\n shrunkShotToLogicalRatio: 1,\n _isFrozen: true,\n };\n}\n\nexport function printReportMsg(filepath: string) {\n if (globalConfigManager.getEnvConfigInBoolean(MIDSCENE_REPORT_QUIET)) {\n return;\n }\n logMsg(`Midscene - report file updated: ${filepath}`);\n}\n\ntype NormalizeFilePathsOptions = {\n fileExists?: (path: string) => boolean;\n isInBrowser?: boolean;\n resolvePath?: (path: string) => string;\n wslDistroName?: string;\n cwd?: string;\n};\n\nexport function normalizeFilePaths(\n files: string[],\n options: NormalizeFilePathsOptions = {},\n): string[] {\n const {\n fileExists = existsSync,\n isInBrowser = ifInBrowser,\n resolvePath = resolve,\n wslDistroName = process.env.WSL_DISTRO_NAME,\n cwd = process.cwd(),\n } = options;\n\n if (isInBrowser) {\n throw new Error('File chooser is not supported in browser environment');\n }\n\n return files.map((file) => {\n const absolutePath = resolvePath(file);\n if (!fileExists(absolutePath)) {\n throw new Error(\n `File not found: ${file}. Resolved to: ${absolutePath}. Current working directory: ${cwd}`,\n );\n }\n\n if (!wslDistroName) {\n return absolutePath;\n }\n\n const wslMount = absolutePath.match(/^\\/mnt\\/([a-z])\\//);\n if (wslMount) {\n return `${wslMount[1].toUpperCase()}:\\\\${absolutePath.slice(7).replace(/\\//g, '\\\\')}`;\n }\n\n return `\\\\\\\\wsl$\\\\${wslDistroName}${absolutePath.replace(/\\//g, '\\\\')}`;\n });\n}\n\ntype LocateParamWithMaybeLocatedPixelResult = DetailedLocateParam & {\n locatedPixelResult?: unknown;\n};\n\ntype LocateParamWithLocatedPixelResult = DetailedLocateParam & {\n locatedPixelResult: PixelLocateResult;\n};\n\nexport function ifLocateParamHasLocatedPixelResult(\n planLocateParam: LocateParamWithMaybeLocatedPixelResult,\n): planLocateParam is LocateParamWithLocatedPixelResult {\n const result = planLocateParam.locatedPixelResult;\n if (!result || typeof result !== 'object' || !('center' in result)) {\n return false;\n }\n const point = result.center;\n return (\n Array.isArray(point) &&\n point.length === 2 &&\n point.every((v) => typeof v === 'number' && Number.isFinite(v))\n );\n}\n\nexport function matchElementFromPlan(\n planLocateParam: LocateParamWithLocatedPixelResult,\n): LocateResultElement | undefined {\n if (!planLocateParam) {\n return undefined;\n }\n\n const { center, rect } = planLocateParam.locatedPixelResult;\n return {\n center: [...center],\n description:\n typeof planLocateParam.prompt === 'string'\n ? planLocateParam.prompt\n : planLocateParam.prompt?.prompt || '',\n ...(rect ? { rect } : {}),\n };\n}\n\nexport async function matchElementFromCache(\n context: {\n taskCache?: TaskCache;\n interfaceInstance: AbstractInterface;\n },\n cacheEntry: ElementCacheFeature | undefined,\n cachePrompt: TUserPrompt,\n cacheable: boolean | undefined,\n): Promise<LocateResultElement | undefined> {\n if (!cacheEntry) {\n return undefined;\n }\n\n if (cacheable === false) {\n cacheDebug('cache disabled for prompt: %s', cachePrompt);\n return undefined;\n }\n\n if (!context.taskCache?.isCacheResultUsed) {\n return undefined;\n }\n\n if (!context.interfaceInstance.rectMatchesCacheFeature) {\n cacheDebug(\n 'interface does not implement rectMatchesCacheFeature, skip cache',\n );\n return undefined;\n }\n\n try {\n const rect =\n await context.interfaceInstance.rectMatchesCacheFeature(cacheEntry);\n const element: LocateResultElement = {\n center: [rect.left + rect.width / 2, rect.top + rect.height / 2],\n rect,\n description:\n typeof cachePrompt === 'string'\n ? cachePrompt\n : cachePrompt.prompt || '',\n };\n\n cacheDebug('cache hit, prompt: %s', cachePrompt);\n return element;\n } catch (error) {\n cacheDebug('rectMatchesCacheFeature error: %s', error);\n return undefined;\n }\n}\n\ndeclare const __VERSION__: string | undefined;\n\nexport const getMidsceneVersion = (): string => {\n if (typeof __VERSION__ !== 'undefined') {\n return __VERSION__;\n } else if (\n process.env.__VERSION__ &&\n process.env.__VERSION__ !== 'undefined'\n ) {\n return process.env.__VERSION__;\n }\n throw new Error('__VERSION__ inject failed during build');\n};\n\nexport const parsePrompt = (\n prompt: TUserPrompt,\n): {\n textPrompt: string;\n multimodalPrompt?: TMultimodalPrompt;\n} => {\n if (typeof prompt === 'string') {\n return {\n textPrompt: prompt,\n multimodalPrompt: undefined,\n };\n }\n return {\n textPrompt: prompt.prompt,\n multimodalPrompt: prompt.images\n ? {\n images: prompt.images,\n convertHttpImage2Base64: !!prompt.convertHttpImage2Base64,\n }\n : undefined,\n };\n};\n\nexport const transformLogicalElementToScreenshot = (\n element: LocateResultElement,\n shrunkShotToLogicalRatio: number,\n): LocateResultElement => {\n if (shrunkShotToLogicalRatio === 1) {\n return element;\n }\n\n return {\n ...element,\n center: [\n element.center[0] * shrunkShotToLogicalRatio,\n element.center[1] * shrunkShotToLogicalRatio,\n ],\n ...(element.rect\n ? {\n rect: transformLogicalRectToScreenshotRect(\n element.rect,\n shrunkShotToLogicalRatio,\n ),\n }\n : {}),\n };\n};\n\nexport const transformLogicalRectToScreenshotRect = (\n rect: Rect,\n shrunkShotToLogicalRatio: number,\n): Rect => {\n if (shrunkShotToLogicalRatio === 1) {\n return rect;\n }\n\n return {\n ...rect,\n left: Math.round(rect.left * shrunkShotToLogicalRatio),\n top: Math.round(rect.top * shrunkShotToLogicalRatio),\n width: Math.round(rect.width * shrunkShotToLogicalRatio),\n height: Math.round(rect.height * shrunkShotToLogicalRatio),\n };\n};\n"],"names":["__webpack_require__","definition","key","Object","obj","prop","Symbol","agentDebug","getDebug","screenshotDataUrlPattern","inferBase64ImageFormat","base64Body","normalizeScreenshotBase64","screenshotBase64","trimmedBase64","assert","createImgBase64ByFormat","legacyScrollTypeMap","normalizeScrollType","scrollType","commonContextParser","interfaceInstance","_opt","debug","description","uploadTestInfoToServer","interfaceSize","logicalWidth","logicalHeight","console","Number","Error","screenshotCapturedAt","Date","userShrinkFactor","preparedScreenshot","prepareRawScreenshot","imgWidth","imgHeight","logicalIsPortrait","screenshotIsPortrait","finalLogicalWidth","dpr","shrunkShotToLogicalRatio","ScreenshotItem","createScreenshotBoundUIContext","opt","normalizedScreenshotBase64","actualScreenshotSize","imageInfoOfBase64","printReportMsg","filepath","globalConfigManager","MIDSCENE_REPORT_QUIET","logMsg","normalizeFilePaths","files","options","fileExists","existsSync","isInBrowser","ifInBrowser","resolvePath","resolve","wslDistroName","process","cwd","file","absolutePath","wslMount","ifLocateParamHasLocatedPixelResult","planLocateParam","result","point","Array","v","matchElementFromPlan","center","rect","matchElementFromCache","context","cacheEntry","cachePrompt","cacheable","cacheDebug","element","error","getMidsceneVersion","__VERSION__","parsePrompt","prompt","undefined","transformLogicalElementToScreenshot","transformLogicalRectToScreenshotRect","Math"],"mappings":"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"}
1
+ {"version":3,"file":"agent/utils.js","sources":["webpack/runtime/define_property_getters","webpack/runtime/has_own_property","webpack/runtime/make_namespace_object","../../../src/agent/utils.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 { existsSync } from 'node:fs';\nimport { resolve } from 'node:path';\nimport type { PixelLocateResult } from '@/ai-model/shared/model-locate-result';\nimport type { TMultimodalPrompt, TUserPrompt } from '@/common';\nimport type { AbstractInterface } from '@/device';\nimport { ScreenshotItem } from '@/screenshot-item';\nimport type {\n DetailedLocateParam,\n ElementCacheFeature,\n LocateResultElement,\n Rect,\n ScrollParam,\n Size,\n UIContext,\n} from '@/types';\nimport { uploadTestInfoToServer } from '@/utils';\nimport {\n MIDSCENE_REPORT_QUIET,\n globalConfigManager,\n} from '@midscene/shared/env';\nimport {\n createImgBase64ByFormat,\n imageInfoOfBase64,\n} from '@midscene/shared/img';\nimport { getDebug, logReport } from '@midscene/shared/logger';\nimport { _keyDefinitions } from '@midscene/shared/us-keyboard-layout';\nimport { assert, ifInBrowser } from '@midscene/shared/utils';\nimport { prepareRawScreenshot } from './screenshot-preparation';\nimport type { TaskCache } from './task-cache';\nimport { debug as cacheDebug } from './task-cache';\n\nexport { getReportFileName } from './report-file-name';\n\nconst agentDebug = getDebug('agent');\nconst screenshotDataUrlPattern = /^data:image\\/[a-zA-Z0-9.+-]+;base64,/i;\n\nconst inferBase64ImageFormat = (base64Body: string) => {\n if (base64Body.startsWith('iVBORw0KGgo')) {\n return 'png';\n }\n return 'jpeg';\n};\n\nconst normalizeScreenshotBase64 = (screenshotBase64: string) => {\n const trimmedBase64 = screenshotBase64.trim();\n if (screenshotDataUrlPattern.test(trimmedBase64)) {\n return trimmedBase64;\n }\n\n const base64Body = trimmedBase64.replace(/\\s/g, '');\n assert(base64Body, 'screenshotBase64 must include image data');\n return createImgBase64ByFormat(\n inferBase64ImageFormat(base64Body),\n base64Body,\n );\n};\n\nconst legacyScrollTypeMap = {\n once: 'singleAction',\n untilBottom: 'scrollToBottom',\n untilTop: 'scrollToTop',\n untilRight: 'scrollToRight',\n untilLeft: 'scrollToLeft',\n} as const;\n\nexport const normalizeScrollType = (\n scrollType: string | undefined,\n): ScrollParam['scrollType'] | undefined => {\n if (!scrollType) {\n return undefined;\n }\n\n if (scrollType in legacyScrollTypeMap) {\n return legacyScrollTypeMap[scrollType as keyof typeof legacyScrollTypeMap];\n }\n\n return scrollType as ScrollParam['scrollType'];\n};\n\nexport async function commonContextParser(\n interfaceInstance: AbstractInterface,\n _opt: {\n uploadServerUrl?: string;\n screenshotShrinkFactor?: number;\n },\n): Promise<UIContext> {\n const debug = getDebug('commonContextParser');\n\n assert(interfaceInstance, 'interfaceInstance is required');\n\n debug('Getting interface description');\n const description = interfaceInstance.describe?.() || '';\n debug('Interface description end');\n\n debug('Uploading test info to server');\n uploadTestInfoToServer({\n testUrl: description,\n serverUrl: _opt.uploadServerUrl,\n });\n debug('UploadTestInfoToServer end');\n\n debug('will get size');\n const interfaceSize = await interfaceInstance.size();\n const { width: logicalWidth, height: logicalHeight } = interfaceSize;\n\n if ((interfaceSize as unknown as { dpr: number }).dpr) {\n console.warn(\n 'Warning: return value of interface.size() include a dpr property, which is not expected and ignored. ',\n );\n }\n\n if (!Number.isFinite(logicalWidth) || !Number.isFinite(logicalHeight)) {\n throw new Error(\n `Invalid interface size: width and height must be finite numbers. Received width: ${logicalWidth}, height: ${logicalHeight}`,\n );\n }\n\n if (logicalWidth <= 0 || logicalHeight <= 0) {\n throw new Error(\n `Invalid interface size: width and height must be positive numbers. Received width: ${logicalWidth}, height: ${logicalHeight}`,\n );\n }\n\n debug(`size: ${logicalWidth}x${logicalHeight}`);\n\n const screenshotBase64 = await interfaceInstance.screenshotBase64();\n const screenshotCapturedAt = Date.now();\n assert(screenshotBase64!, 'screenshotBase64 is required');\n const userShrinkFactor = _opt.screenshotShrinkFactor ?? 1;\n\n debug('will get screenshot dimensions');\n const preparedScreenshot = await prepareRawScreenshot(screenshotBase64, {\n shrinkFactor: userShrinkFactor,\n });\n const { width: imgWidth, height: imgHeight } =\n preparedScreenshot.originalSize;\n debug('screenshot dimensions', imgWidth, 'x', imgHeight);\n\n // Detect orientation mismatch between logical size and screenshot.\n // Some devices (e.g. OPPO) report wrong orientation via ADB, causing\n // size() to return portrait dimensions even when the device is landscape.\n // We detect this by comparing aspect ratios and swap if they disagree.\n const logicalIsPortrait = logicalWidth < logicalHeight;\n const screenshotIsPortrait = imgWidth < imgHeight;\n let finalLogicalWidth = logicalWidth;\n let finalLogicalHeight = logicalHeight;\n if (logicalIsPortrait !== screenshotIsPortrait) {\n debug(\n `Orientation mismatch detected: logical size ${logicalWidth}x${logicalHeight} (${logicalIsPortrait ? 'portrait' : 'landscape'}) vs screenshot ${imgWidth}x${imgHeight} (${screenshotIsPortrait ? 'portrait' : 'landscape'}). Swapping logical dimensions.`,\n );\n finalLogicalWidth = logicalHeight;\n finalLogicalHeight = logicalWidth;\n }\n\n const dpr = imgWidth / finalLogicalWidth;\n\n debug('calculated dpr:', dpr);\n\n const shrunkShotToLogicalRatio = dpr / userShrinkFactor;\n\n debug('shrunkShotToLogicalRatio', shrunkShotToLogicalRatio);\n\n if (userShrinkFactor > 1) {\n debug(\n `Applied screenshot shrink factor: ${userShrinkFactor} (physical: ${imgWidth}x${imgHeight} -> target: ${preparedScreenshot.shotSize.width}x${preparedScreenshot.shotSize.height})`,\n );\n }\n\n return {\n shotSize: preparedScreenshot.shotSize,\n deprecatedDpr: dpr,\n screenshot: ScreenshotItem.create(\n preparedScreenshot.base64,\n screenshotCapturedAt,\n ),\n shrunkShotToLogicalRatio,\n };\n}\n\nexport async function createScreenshotBoundUIContext(\n screenshotBase64: string,\n opt: {\n screenshotSize?: Size;\n },\n): Promise<UIContext> {\n const normalizedScreenshotBase64 =\n normalizeScreenshotBase64(screenshotBase64);\n const actualScreenshotSize = await imageInfoOfBase64(\n normalizedScreenshotBase64,\n );\n if (\n opt.screenshotSize &&\n (opt.screenshotSize.width !== actualScreenshotSize.width ||\n opt.screenshotSize.height !== actualScreenshotSize.height)\n ) {\n agentDebug(\n 'describeElementAtPoint screenshotSize mismatch, use actual size',\n {\n provided: opt.screenshotSize,\n actual: actualScreenshotSize,\n },\n );\n }\n\n return {\n screenshot: ScreenshotItem.create(normalizedScreenshotBase64, Date.now()),\n shotSize: actualScreenshotSize,\n shrunkShotToLogicalRatio: 1,\n _isFrozen: true,\n };\n}\n\nexport function printReportMsg(filepath: string) {\n if (globalConfigManager.getEnvConfigInBoolean(MIDSCENE_REPORT_QUIET)) {\n return;\n }\n logReport(`Midscene - report file updated: ${filepath}`);\n}\n\ntype NormalizeFilePathsOptions = {\n fileExists?: (path: string) => boolean;\n isInBrowser?: boolean;\n resolvePath?: (path: string) => string;\n wslDistroName?: string;\n cwd?: string;\n};\n\nexport function normalizeFilePaths(\n files: string[],\n options: NormalizeFilePathsOptions = {},\n): string[] {\n const {\n fileExists = existsSync,\n isInBrowser = ifInBrowser,\n resolvePath = resolve,\n wslDistroName = process.env.WSL_DISTRO_NAME,\n cwd = process.cwd(),\n } = options;\n\n if (isInBrowser) {\n throw new Error('File chooser is not supported in browser environment');\n }\n\n return files.map((file) => {\n const absolutePath = resolvePath(file);\n if (!fileExists(absolutePath)) {\n throw new Error(\n `File not found: ${file}. Resolved to: ${absolutePath}. Current working directory: ${cwd}`,\n );\n }\n\n if (!wslDistroName) {\n return absolutePath;\n }\n\n const wslMount = absolutePath.match(/^\\/mnt\\/([a-z])\\//);\n if (wslMount) {\n return `${wslMount[1].toUpperCase()}:\\\\${absolutePath.slice(7).replace(/\\//g, '\\\\')}`;\n }\n\n return `\\\\\\\\wsl$\\\\${wslDistroName}${absolutePath.replace(/\\//g, '\\\\')}`;\n });\n}\n\ntype LocateParamWithMaybeLocatedPixelResult = DetailedLocateParam & {\n locatedPixelResult?: unknown;\n};\n\ntype LocateParamWithLocatedPixelResult = DetailedLocateParam & {\n locatedPixelResult: PixelLocateResult;\n};\n\nexport function ifLocateParamHasLocatedPixelResult(\n planLocateParam: LocateParamWithMaybeLocatedPixelResult,\n): planLocateParam is LocateParamWithLocatedPixelResult {\n const result = planLocateParam.locatedPixelResult;\n if (!result || typeof result !== 'object' || !('center' in result)) {\n return false;\n }\n const point = result.center;\n return (\n Array.isArray(point) &&\n point.length === 2 &&\n point.every((v) => typeof v === 'number' && Number.isFinite(v))\n );\n}\n\nexport function matchElementFromPlan(\n planLocateParam: LocateParamWithLocatedPixelResult,\n): LocateResultElement | undefined {\n if (!planLocateParam) {\n return undefined;\n }\n\n const { center, rect } = planLocateParam.locatedPixelResult;\n return {\n center: [...center],\n description:\n typeof planLocateParam.prompt === 'string'\n ? planLocateParam.prompt\n : planLocateParam.prompt?.prompt || '',\n ...(rect ? { rect } : {}),\n };\n}\n\nexport async function matchElementFromCache(\n context: {\n taskCache?: TaskCache;\n interfaceInstance: AbstractInterface;\n },\n cacheEntry: ElementCacheFeature | undefined,\n cachePrompt: TUserPrompt,\n cacheable: boolean | undefined,\n): Promise<LocateResultElement | undefined> {\n if (!cacheEntry) {\n return undefined;\n }\n\n if (cacheable === false) {\n cacheDebug('cache disabled for prompt: %s', cachePrompt);\n return undefined;\n }\n\n if (!context.taskCache?.isCacheResultUsed) {\n return undefined;\n }\n\n if (!context.interfaceInstance.rectMatchesCacheFeature) {\n cacheDebug(\n 'interface does not implement rectMatchesCacheFeature, skip cache',\n );\n return undefined;\n }\n\n try {\n const rect =\n await context.interfaceInstance.rectMatchesCacheFeature(cacheEntry);\n const element: LocateResultElement = {\n center: [rect.left + rect.width / 2, rect.top + rect.height / 2],\n rect,\n description:\n typeof cachePrompt === 'string'\n ? cachePrompt\n : cachePrompt.prompt || '',\n };\n\n cacheDebug('cache hit, prompt: %s', cachePrompt);\n return element;\n } catch (error) {\n cacheDebug('rectMatchesCacheFeature error: %s', error);\n return undefined;\n }\n}\n\ndeclare const __VERSION__: string | undefined;\n\nexport const getMidsceneVersion = (): string => {\n if (typeof __VERSION__ !== 'undefined') {\n return __VERSION__;\n } else if (\n process.env.__VERSION__ &&\n process.env.__VERSION__ !== 'undefined'\n ) {\n return process.env.__VERSION__;\n }\n throw new Error('__VERSION__ inject failed during build');\n};\n\nexport const parsePrompt = (\n prompt: TUserPrompt,\n): {\n textPrompt: string;\n multimodalPrompt?: TMultimodalPrompt;\n} => {\n if (typeof prompt === 'string') {\n return {\n textPrompt: prompt,\n multimodalPrompt: undefined,\n };\n }\n return {\n textPrompt: prompt.prompt,\n multimodalPrompt: prompt.images\n ? {\n images: prompt.images,\n convertHttpImage2Base64: !!prompt.convertHttpImage2Base64,\n }\n : undefined,\n };\n};\n\nexport const transformLogicalElementToScreenshot = (\n element: LocateResultElement,\n shrunkShotToLogicalRatio: number,\n): LocateResultElement => {\n if (shrunkShotToLogicalRatio === 1) {\n return element;\n }\n\n return {\n ...element,\n center: [\n element.center[0] * shrunkShotToLogicalRatio,\n element.center[1] * shrunkShotToLogicalRatio,\n ],\n ...(element.rect\n ? {\n rect: transformLogicalRectToScreenshotRect(\n element.rect,\n shrunkShotToLogicalRatio,\n ),\n }\n : {}),\n };\n};\n\nexport const transformLogicalRectToScreenshotRect = (\n rect: Rect,\n shrunkShotToLogicalRatio: number,\n): Rect => {\n if (shrunkShotToLogicalRatio === 1) {\n return rect;\n }\n\n return {\n ...rect,\n left: Math.round(rect.left * shrunkShotToLogicalRatio),\n top: Math.round(rect.top * shrunkShotToLogicalRatio),\n width: Math.round(rect.width * shrunkShotToLogicalRatio),\n height: Math.round(rect.height * shrunkShotToLogicalRatio),\n };\n};\n"],"names":["__webpack_require__","definition","key","Object","obj","prop","Symbol","agentDebug","getDebug","screenshotDataUrlPattern","inferBase64ImageFormat","base64Body","normalizeScreenshotBase64","screenshotBase64","trimmedBase64","assert","createImgBase64ByFormat","legacyScrollTypeMap","normalizeScrollType","scrollType","commonContextParser","interfaceInstance","_opt","debug","description","uploadTestInfoToServer","interfaceSize","logicalWidth","logicalHeight","console","Number","Error","screenshotCapturedAt","Date","userShrinkFactor","preparedScreenshot","prepareRawScreenshot","imgWidth","imgHeight","logicalIsPortrait","screenshotIsPortrait","finalLogicalWidth","dpr","shrunkShotToLogicalRatio","ScreenshotItem","createScreenshotBoundUIContext","opt","normalizedScreenshotBase64","actualScreenshotSize","imageInfoOfBase64","printReportMsg","filepath","globalConfigManager","MIDSCENE_REPORT_QUIET","logReport","normalizeFilePaths","files","options","fileExists","existsSync","isInBrowser","ifInBrowser","resolvePath","resolve","wslDistroName","process","cwd","file","absolutePath","wslMount","ifLocateParamHasLocatedPixelResult","planLocateParam","result","point","Array","v","matchElementFromPlan","center","rect","matchElementFromCache","context","cacheEntry","cachePrompt","cacheable","cacheDebug","element","error","getMidsceneVersion","__VERSION__","parsePrompt","prompt","undefined","transformLogicalElementToScreenshot","transformLogicalRectToScreenshotRect","Math"],"mappings":"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"}
@@ -54,7 +54,7 @@ function parseAutoGLMPlanningAction(response) {
54
54
  }
55
55
  if (trimmedResponse.startsWith('finish(message=')) {
56
56
  let message = extractValueAfter(trimmedResponse, 'finish(message="');
57
- if (message.endsWith(')')) message = message.slice(0, -1);
57
+ if (!trimmedResponse.endsWith('")') && message.endsWith(')')) message = message.slice(0, -1);
58
58
  return {
59
59
  _metadata: 'finish',
60
60
  message,
@@ -1 +1 @@
1
- {"version":3,"file":"ai-model/models/auto-glm/parser.js","sources":["webpack/runtime/define_property_getters","webpack/runtime/has_own_property","webpack/runtime/make_namespace_object","../../../../../src/ai-model/models/auto-glm/parser.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 type { AutoGLMParsedAction } from './actions';\n\nconst debug = getDebug('auto-glm-parser');\n\n// Do not rely on regex extraction here; regex can fail on malformed input.\n// Bad Case: finish(message=\"Finished! Now There is a contact whose name is \\\"Tom\\\" in the list.\")\nexport const extractValueAfter = (src: string, key: string): string => {\n const idx = src.indexOf(key);\n if (idx === -1) {\n throw new Error(`Missing key ${key} in action payload ${src}`);\n }\n let rest = src.slice(idx + key.length).trim();\n if (rest.endsWith('\")')) {\n rest = rest.slice(0, -2);\n }\n return rest;\n};\n\nexport function parseAutoGLMPlanningAction(response: {\n think: string;\n content: string;\n}): AutoGLMParsedAction {\n debug('Parsing action:', response);\n let trimmedResponse = '';\n try {\n trimmedResponse = response.content.trim();\n\n if (\n trimmedResponse.startsWith('do(action=\"Type\"') ||\n trimmedResponse.startsWith('do(action=\"Type_Name\"')\n ) {\n const text = extractValueAfter(trimmedResponse, 'text=\"');\n return {\n _metadata: 'do',\n action: 'Type',\n text,\n think: response.think,\n } as AutoGLMParsedAction;\n }\n\n if (trimmedResponse.startsWith('finish(message=')) {\n let message = extractValueAfter(trimmedResponse, 'finish(message=\"');\n if (message.endsWith(')')) message = message.slice(0, -1);\n return {\n _metadata: 'finish',\n message,\n think: response.think,\n } as AutoGLMParsedAction;\n }\n\n if (trimmedResponse.startsWith('do(')) {\n const actionMatch = trimmedResponse.match(/do\\(action=\"([^\"]+)\"/);\n if (!actionMatch)\n throw new Error(\n `Failed to extract action type from do() call; raw=\"${trimmedResponse}\"`,\n );\n const actionType = actionMatch[1];\n\n const baseAction = { _metadata: 'do' as const, think: response.think };\n switch (actionType) {\n case 'Tap': {\n const elementMatch = trimmedResponse.match(/element=\\[(\\d+),(\\d+)\\]/);\n if (!elementMatch)\n throw new Error(\n `Failed to extract element coordinates for Tap; raw=\"${trimmedResponse}\"`,\n );\n return {\n ...baseAction,\n action: 'Tap',\n element: [Number(elementMatch[1]), Number(elementMatch[2])],\n } as AutoGLMParsedAction;\n }\n case 'Double Tap': {\n const elementMatch = trimmedResponse.match(/element=\\[(\\d+),(\\d+)\\]/);\n if (!elementMatch)\n throw new Error(\n `Failed to extract element coordinates for Double Tap; raw=\"${trimmedResponse}\"`,\n );\n return {\n ...baseAction,\n action: 'Double Tap',\n element: [Number(elementMatch[1]), Number(elementMatch[2])],\n } as AutoGLMParsedAction;\n }\n case 'Swipe': {\n const startMatch = trimmedResponse.match(/start=\\[(\\d+),(\\d+)\\]/);\n const endMatch = trimmedResponse.match(/end=\\[(\\d+),(\\d+)\\]/);\n if (!startMatch || !endMatch)\n throw new Error(\n `Failed to extract start/end coordinates for Swipe; raw=\"${trimmedResponse}\"`,\n );\n return {\n ...baseAction,\n action: 'Swipe',\n start: [Number(startMatch[1]), Number(startMatch[2])],\n end: [Number(endMatch[1]), Number(endMatch[2])],\n } as AutoGLMParsedAction;\n }\n case 'Long Press': {\n const elementMatch = trimmedResponse.match(/element=\\[(\\d+),(\\d+)\\]/);\n if (!elementMatch)\n throw new Error(\n `Failed to extract element coordinates for Long Press; raw=\"${trimmedResponse}\"`,\n );\n return {\n ...baseAction,\n action: 'Long Press',\n element: [Number(elementMatch[1]), Number(elementMatch[2])],\n } as AutoGLMParsedAction;\n }\n case 'Launch': {\n const app = extractValueAfter(trimmedResponse, 'app=\"');\n return {\n ...baseAction,\n action: 'Launch',\n app,\n } as AutoGLMParsedAction;\n }\n case 'Back': {\n return { ...baseAction, action: 'Back' } as AutoGLMParsedAction;\n }\n case 'Home': {\n return { ...baseAction, action: 'Home' } as AutoGLMParsedAction;\n }\n case 'Wait': {\n const durationMatch = trimmedResponse.match(\n /duration=(?:[\"\\[])?(\\d+)/,\n );\n if (!durationMatch) {\n throw new Error(\n `Failed to extract duration for Wait; raw=\"${trimmedResponse}\"`,\n );\n }\n const seconds = Number.parseInt(durationMatch[1], 10);\n const durationMs = seconds * 1000;\n return {\n ...baseAction,\n action: 'Wait',\n durationMs,\n } as AutoGLMParsedAction;\n }\n case 'Interact': {\n return { ...baseAction, action: 'Interact' } as AutoGLMParsedAction;\n }\n case 'Call_API': {\n const instruction = extractValueAfter(\n trimmedResponse,\n 'instruction=\"',\n );\n return {\n ...baseAction,\n action: 'Call_API',\n instruction,\n } as AutoGLMParsedAction;\n }\n case 'Take_over': {\n const message = extractValueAfter(trimmedResponse, 'message=\"');\n return {\n ...baseAction,\n action: 'Take_over',\n message,\n } as AutoGLMParsedAction;\n }\n case 'Note': {\n const message = extractValueAfter(trimmedResponse, 'message=\"');\n return {\n ...baseAction,\n action: 'Note',\n message,\n } as AutoGLMParsedAction;\n }\n default:\n throw new Error(\n `Unknown action type: ${actionType}; raw=\"${trimmedResponse}\"`,\n );\n }\n }\n throw new Error(`Failed to parse action: ${trimmedResponse}`);\n } catch (error) {\n const errorMessage = error instanceof Error ? error.message : String(error);\n throw new Error(\n `Failed to parse action: ${errorMessage}; raw=\"${trimmedResponse}\"`,\n );\n }\n}\n\nexport function parseAutoGLMResponse(content: string): {\n think: string;\n content: string;\n} {\n let parsedResponse: { think: string; content: string };\n\n if (content.includes('finish(message=')) {\n const parts = content.split('finish(message=');\n const think = parts[0].trim();\n const actionContent = `finish(message=${parts[1]}`;\n parsedResponse = { think, content: actionContent };\n } else if (content.includes('do(action=')) {\n const parts = content.split('do(action=');\n const think = parts[0].trim();\n const actionContent = `do(action=${parts[1]}`;\n parsedResponse = { think, content: actionContent };\n } else if (content.includes('<answer>')) {\n const parts = content.split('<answer>');\n const think = parts[0]\n .replace(/<think>/g, '')\n .replace(/<\\/think>/g, '')\n .trim();\n const actionContent = parts[1].replace(/<\\/answer>/g, '').trim();\n parsedResponse = { think, content: actionContent };\n } else {\n parsedResponse = { think: '', content };\n }\n\n debug('autoGLM rawResponse:', content);\n debug('thinking in response:', parsedResponse.think);\n debug('action in response:', parsedResponse.content);\n return parsedResponse;\n}\n\nexport function parseAutoGLMPlanningResponse(content: string): {\n response: ReturnType<typeof parseAutoGLMResponse>;\n action: AutoGLMParsedAction;\n} {\n const response = parseAutoGLMResponse(content);\n const action = parseAutoGLMPlanningAction(response);\n return { response, action };\n}\n"],"names":["__webpack_require__","definition","key","Object","obj","prop","Symbol","debug","getDebug","extractValueAfter","src","idx","Error","rest","parseAutoGLMPlanningAction","response","trimmedResponse","text","message","actionMatch","actionType","baseAction","elementMatch","Number","startMatch","endMatch","app","durationMatch","seconds","durationMs","instruction","error","errorMessage","String","parseAutoGLMResponse","content","parsedResponse","parts","think","actionContent","parseAutoGLMPlanningResponse","action"],"mappings":"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"}
1
+ {"version":3,"file":"ai-model/models/auto-glm/parser.js","sources":["webpack/runtime/define_property_getters","webpack/runtime/has_own_property","webpack/runtime/make_namespace_object","../../../../../src/ai-model/models/auto-glm/parser.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 type { AutoGLMParsedAction } from './actions';\n\nconst debug = getDebug('auto-glm-parser');\n\n// Do not rely on regex extraction here; regex can fail on malformed input.\n// Bad Case: finish(message=\"Finished! Now There is a contact whose name is \\\"Tom\\\" in the list.\")\nexport const extractValueAfter = (src: string, key: string): string => {\n const idx = src.indexOf(key);\n if (idx === -1) {\n throw new Error(`Missing key ${key} in action payload ${src}`);\n }\n let rest = src.slice(idx + key.length).trim();\n if (rest.endsWith('\")')) {\n rest = rest.slice(0, -2);\n }\n return rest;\n};\n\nexport function parseAutoGLMPlanningAction(response: {\n think: string;\n content: string;\n}): AutoGLMParsedAction {\n debug('Parsing action:', response);\n let trimmedResponse = '';\n try {\n trimmedResponse = response.content.trim();\n\n if (\n trimmedResponse.startsWith('do(action=\"Type\"') ||\n trimmedResponse.startsWith('do(action=\"Type_Name\"')\n ) {\n const text = extractValueAfter(trimmedResponse, 'text=\"');\n return {\n _metadata: 'do',\n action: 'Type',\n text,\n think: response.think,\n } as AutoGLMParsedAction;\n }\n\n if (trimmedResponse.startsWith('finish(message=')) {\n let message = extractValueAfter(trimmedResponse, 'finish(message=\"');\n if (!trimmedResponse.endsWith('\")') && message.endsWith(')')) {\n message = message.slice(0, -1);\n }\n return {\n _metadata: 'finish',\n message,\n think: response.think,\n } as AutoGLMParsedAction;\n }\n\n if (trimmedResponse.startsWith('do(')) {\n const actionMatch = trimmedResponse.match(/do\\(action=\"([^\"]+)\"/);\n if (!actionMatch)\n throw new Error(\n `Failed to extract action type from do() call; raw=\"${trimmedResponse}\"`,\n );\n const actionType = actionMatch[1];\n\n const baseAction = { _metadata: 'do' as const, think: response.think };\n switch (actionType) {\n case 'Tap': {\n const elementMatch = trimmedResponse.match(/element=\\[(\\d+),(\\d+)\\]/);\n if (!elementMatch)\n throw new Error(\n `Failed to extract element coordinates for Tap; raw=\"${trimmedResponse}\"`,\n );\n return {\n ...baseAction,\n action: 'Tap',\n element: [Number(elementMatch[1]), Number(elementMatch[2])],\n } as AutoGLMParsedAction;\n }\n case 'Double Tap': {\n const elementMatch = trimmedResponse.match(/element=\\[(\\d+),(\\d+)\\]/);\n if (!elementMatch)\n throw new Error(\n `Failed to extract element coordinates for Double Tap; raw=\"${trimmedResponse}\"`,\n );\n return {\n ...baseAction,\n action: 'Double Tap',\n element: [Number(elementMatch[1]), Number(elementMatch[2])],\n } as AutoGLMParsedAction;\n }\n case 'Swipe': {\n const startMatch = trimmedResponse.match(/start=\\[(\\d+),(\\d+)\\]/);\n const endMatch = trimmedResponse.match(/end=\\[(\\d+),(\\d+)\\]/);\n if (!startMatch || !endMatch)\n throw new Error(\n `Failed to extract start/end coordinates for Swipe; raw=\"${trimmedResponse}\"`,\n );\n return {\n ...baseAction,\n action: 'Swipe',\n start: [Number(startMatch[1]), Number(startMatch[2])],\n end: [Number(endMatch[1]), Number(endMatch[2])],\n } as AutoGLMParsedAction;\n }\n case 'Long Press': {\n const elementMatch = trimmedResponse.match(/element=\\[(\\d+),(\\d+)\\]/);\n if (!elementMatch)\n throw new Error(\n `Failed to extract element coordinates for Long Press; raw=\"${trimmedResponse}\"`,\n );\n return {\n ...baseAction,\n action: 'Long Press',\n element: [Number(elementMatch[1]), Number(elementMatch[2])],\n } as AutoGLMParsedAction;\n }\n case 'Launch': {\n const app = extractValueAfter(trimmedResponse, 'app=\"');\n return {\n ...baseAction,\n action: 'Launch',\n app,\n } as AutoGLMParsedAction;\n }\n case 'Back': {\n return { ...baseAction, action: 'Back' } as AutoGLMParsedAction;\n }\n case 'Home': {\n return { ...baseAction, action: 'Home' } as AutoGLMParsedAction;\n }\n case 'Wait': {\n const durationMatch = trimmedResponse.match(\n /duration=(?:[\"\\[])?(\\d+)/,\n );\n if (!durationMatch) {\n throw new Error(\n `Failed to extract duration for Wait; raw=\"${trimmedResponse}\"`,\n );\n }\n const seconds = Number.parseInt(durationMatch[1], 10);\n const durationMs = seconds * 1000;\n return {\n ...baseAction,\n action: 'Wait',\n durationMs,\n } as AutoGLMParsedAction;\n }\n case 'Interact': {\n return { ...baseAction, action: 'Interact' } as AutoGLMParsedAction;\n }\n case 'Call_API': {\n const instruction = extractValueAfter(\n trimmedResponse,\n 'instruction=\"',\n );\n return {\n ...baseAction,\n action: 'Call_API',\n instruction,\n } as AutoGLMParsedAction;\n }\n case 'Take_over': {\n const message = extractValueAfter(trimmedResponse, 'message=\"');\n return {\n ...baseAction,\n action: 'Take_over',\n message,\n } as AutoGLMParsedAction;\n }\n case 'Note': {\n const message = extractValueAfter(trimmedResponse, 'message=\"');\n return {\n ...baseAction,\n action: 'Note',\n message,\n } as AutoGLMParsedAction;\n }\n default:\n throw new Error(\n `Unknown action type: ${actionType}; raw=\"${trimmedResponse}\"`,\n );\n }\n }\n throw new Error(`Failed to parse action: ${trimmedResponse}`);\n } catch (error) {\n const errorMessage = error instanceof Error ? error.message : String(error);\n throw new Error(\n `Failed to parse action: ${errorMessage}; raw=\"${trimmedResponse}\"`,\n );\n }\n}\n\nexport function parseAutoGLMResponse(content: string): {\n think: string;\n content: string;\n} {\n let parsedResponse: { think: string; content: string };\n\n if (content.includes('finish(message=')) {\n const parts = content.split('finish(message=');\n const think = parts[0].trim();\n const actionContent = `finish(message=${parts[1]}`;\n parsedResponse = { think, content: actionContent };\n } else if (content.includes('do(action=')) {\n const parts = content.split('do(action=');\n const think = parts[0].trim();\n const actionContent = `do(action=${parts[1]}`;\n parsedResponse = { think, content: actionContent };\n } else if (content.includes('<answer>')) {\n const parts = content.split('<answer>');\n const think = parts[0]\n .replace(/<think>/g, '')\n .replace(/<\\/think>/g, '')\n .trim();\n const actionContent = parts[1].replace(/<\\/answer>/g, '').trim();\n parsedResponse = { think, content: actionContent };\n } else {\n parsedResponse = { think: '', content };\n }\n\n debug('autoGLM rawResponse:', content);\n debug('thinking in response:', parsedResponse.think);\n debug('action in response:', parsedResponse.content);\n return parsedResponse;\n}\n\nexport function parseAutoGLMPlanningResponse(content: string): {\n response: ReturnType<typeof parseAutoGLMResponse>;\n action: AutoGLMParsedAction;\n} {\n const response = parseAutoGLMResponse(content);\n const action = parseAutoGLMPlanningAction(response);\n return { response, action };\n}\n"],"names":["__webpack_require__","definition","key","Object","obj","prop","Symbol","debug","getDebug","extractValueAfter","src","idx","Error","rest","parseAutoGLMPlanningAction","response","trimmedResponse","text","message","actionMatch","actionType","baseAction","elementMatch","Number","startMatch","endMatch","app","durationMatch","seconds","durationMs","instruction","error","errorMessage","String","parseAutoGLMResponse","content","parsedResponse","parts","think","actionContent","parseAutoGLMPlanningResponse","action"],"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;;;;;;;;;;;ACHA,MAAMI,QAAQC,AAAAA,IAAAA,uBAAAA,QAAAA,AAAAA,EAAS;AAIhB,MAAMC,oBAAoB,CAACC,KAAaR;IAC7C,MAAMS,MAAMD,IAAI,OAAO,CAACR;IACxB,IAAIS,AAAQ,OAARA,KACF,MAAM,IAAIC,MAAM,CAAC,YAAY,EAAEV,IAAI,mBAAmB,EAAEQ,KAAK;IAE/D,IAAIG,OAAOH,IAAI,KAAK,CAACC,MAAMT,IAAI,MAAM,EAAE,IAAI;IAC3C,IAAIW,KAAK,QAAQ,CAAC,OAChBA,OAAOA,KAAK,KAAK,CAAC,GAAG;IAEvB,OAAOA;AACT;AAEO,SAASC,2BAA2BC,QAG1C;IACCR,MAAM,mBAAmBQ;IACzB,IAAIC,kBAAkB;IACtB,IAAI;QACFA,kBAAkBD,SAAS,OAAO,CAAC,IAAI;QAEvC,IACEC,gBAAgB,UAAU,CAAC,uBAC3BA,gBAAgB,UAAU,CAAC,0BAC3B;YACA,MAAMC,OAAOR,kBAAkBO,iBAAiB;YAChD,OAAO;gBACL,WAAW;gBACX,QAAQ;gBACRC;gBACA,OAAOF,SAAS,KAAK;YACvB;QACF;QAEA,IAAIC,gBAAgB,UAAU,CAAC,oBAAoB;YACjD,IAAIE,UAAUT,kBAAkBO,iBAAiB;YACjD,IAAI,CAACA,gBAAgB,QAAQ,CAAC,SAASE,QAAQ,QAAQ,CAAC,MACtDA,UAAUA,QAAQ,KAAK,CAAC,GAAG;YAE7B,OAAO;gBACL,WAAW;gBACXA;gBACA,OAAOH,SAAS,KAAK;YACvB;QACF;QAEA,IAAIC,gBAAgB,UAAU,CAAC,QAAQ;YACrC,MAAMG,cAAcH,gBAAgB,KAAK,CAAC;YAC1C,IAAI,CAACG,aACH,MAAM,IAAIP,MACR,CAAC,mDAAmD,EAAEI,gBAAgB,CAAC,CAAC;YAE5E,MAAMI,aAAaD,WAAW,CAAC,EAAE;YAEjC,MAAME,aAAa;gBAAE,WAAW;gBAAe,OAAON,SAAS,KAAK;YAAC;YACrE,OAAQK;gBACN,KAAK;oBAAO;wBACV,MAAME,eAAeN,gBAAgB,KAAK,CAAC;wBAC3C,IAAI,CAACM,cACH,MAAM,IAAIV,MACR,CAAC,oDAAoD,EAAEI,gBAAgB,CAAC,CAAC;wBAE7E,OAAO;4BACL,GAAGK,UAAU;4BACb,QAAQ;4BACR,SAAS;gCAACE,OAAOD,YAAY,CAAC,EAAE;gCAAGC,OAAOD,YAAY,CAAC,EAAE;6BAAE;wBAC7D;oBACF;gBACA,KAAK;oBAAc;wBACjB,MAAMA,eAAeN,gBAAgB,KAAK,CAAC;wBAC3C,IAAI,CAACM,cACH,MAAM,IAAIV,MACR,CAAC,2DAA2D,EAAEI,gBAAgB,CAAC,CAAC;wBAEpF,OAAO;4BACL,GAAGK,UAAU;4BACb,QAAQ;4BACR,SAAS;gCAACE,OAAOD,YAAY,CAAC,EAAE;gCAAGC,OAAOD,YAAY,CAAC,EAAE;6BAAE;wBAC7D;oBACF;gBACA,KAAK;oBAAS;wBACZ,MAAME,aAAaR,gBAAgB,KAAK,CAAC;wBACzC,MAAMS,WAAWT,gBAAgB,KAAK,CAAC;wBACvC,IAAI,CAACQ,cAAc,CAACC,UAClB,MAAM,IAAIb,MACR,CAAC,wDAAwD,EAAEI,gBAAgB,CAAC,CAAC;wBAEjF,OAAO;4BACL,GAAGK,UAAU;4BACb,QAAQ;4BACR,OAAO;gCAACE,OAAOC,UAAU,CAAC,EAAE;gCAAGD,OAAOC,UAAU,CAAC,EAAE;6BAAE;4BACrD,KAAK;gCAACD,OAAOE,QAAQ,CAAC,EAAE;gCAAGF,OAAOE,QAAQ,CAAC,EAAE;6BAAE;wBACjD;oBACF;gBACA,KAAK;oBAAc;wBACjB,MAAMH,eAAeN,gBAAgB,KAAK,CAAC;wBAC3C,IAAI,CAACM,cACH,MAAM,IAAIV,MACR,CAAC,2DAA2D,EAAEI,gBAAgB,CAAC,CAAC;wBAEpF,OAAO;4BACL,GAAGK,UAAU;4BACb,QAAQ;4BACR,SAAS;gCAACE,OAAOD,YAAY,CAAC,EAAE;gCAAGC,OAAOD,YAAY,CAAC,EAAE;6BAAE;wBAC7D;oBACF;gBACA,KAAK;oBAAU;wBACb,MAAMI,MAAMjB,kBAAkBO,iBAAiB;wBAC/C,OAAO;4BACL,GAAGK,UAAU;4BACb,QAAQ;4BACRK;wBACF;oBACF;gBACA,KAAK;oBACH,OAAO;wBAAE,GAAGL,UAAU;wBAAE,QAAQ;oBAAO;gBAEzC,KAAK;oBACH,OAAO;wBAAE,GAAGA,UAAU;wBAAE,QAAQ;oBAAO;gBAEzC,KAAK;oBAAQ;wBACX,MAAMM,gBAAgBX,gBAAgB,KAAK,CACzC;wBAEF,IAAI,CAACW,eACH,MAAM,IAAIf,MACR,CAAC,0CAA0C,EAAEI,gBAAgB,CAAC,CAAC;wBAGnE,MAAMY,UAAUL,OAAO,QAAQ,CAACI,aAAa,CAAC,EAAE,EAAE;wBAClD,MAAME,aAAaD,AAAU,OAAVA;wBACnB,OAAO;4BACL,GAAGP,UAAU;4BACb,QAAQ;4BACRQ;wBACF;oBACF;gBACA,KAAK;oBACH,OAAO;wBAAE,GAAGR,UAAU;wBAAE,QAAQ;oBAAW;gBAE7C,KAAK;oBAAY;wBACf,MAAMS,cAAcrB,kBAClBO,iBACA;wBAEF,OAAO;4BACL,GAAGK,UAAU;4BACb,QAAQ;4BACRS;wBACF;oBACF;gBACA,KAAK;oBAAa;wBAChB,MAAMZ,UAAUT,kBAAkBO,iBAAiB;wBACnD,OAAO;4BACL,GAAGK,UAAU;4BACb,QAAQ;4BACRH;wBACF;oBACF;gBACA,KAAK;oBAAQ;wBACX,MAAMA,UAAUT,kBAAkBO,iBAAiB;wBACnD,OAAO;4BACL,GAAGK,UAAU;4BACb,QAAQ;4BACRH;wBACF;oBACF;gBACA;oBACE,MAAM,IAAIN,MACR,CAAC,qBAAqB,EAAEQ,WAAW,OAAO,EAAEJ,gBAAgB,CAAC,CAAC;YAEpE;QACF;QACA,MAAM,IAAIJ,MAAM,CAAC,wBAAwB,EAAEI,iBAAiB;IAC9D,EAAE,OAAOe,OAAO;QACd,MAAMC,eAAeD,iBAAiBnB,QAAQmB,MAAM,OAAO,GAAGE,OAAOF;QACrE,MAAM,IAAInB,MACR,CAAC,wBAAwB,EAAEoB,aAAa,OAAO,EAAEhB,gBAAgB,CAAC,CAAC;IAEvE;AACF;AAEO,SAASkB,qBAAqBC,OAAe;IAIlD,IAAIC;IAEJ,IAAID,QAAQ,QAAQ,CAAC,oBAAoB;QACvC,MAAME,QAAQF,QAAQ,KAAK,CAAC;QAC5B,MAAMG,QAAQD,KAAK,CAAC,EAAE,CAAC,IAAI;QAC3B,MAAME,gBAAgB,CAAC,eAAe,EAAEF,KAAK,CAAC,EAAE,EAAE;QAClDD,iBAAiB;YAAEE;YAAO,SAASC;QAAc;IACnD,OAAO,IAAIJ,QAAQ,QAAQ,CAAC,eAAe;QACzC,MAAME,QAAQF,QAAQ,KAAK,CAAC;QAC5B,MAAMG,QAAQD,KAAK,CAAC,EAAE,CAAC,IAAI;QAC3B,MAAME,gBAAgB,CAAC,UAAU,EAAEF,KAAK,CAAC,EAAE,EAAE;QAC7CD,iBAAiB;YAAEE;YAAO,SAASC;QAAc;IACnD,OAAO,IAAIJ,QAAQ,QAAQ,CAAC,aAAa;QACvC,MAAME,QAAQF,QAAQ,KAAK,CAAC;QAC5B,MAAMG,QAAQD,KAAK,CAAC,EAAE,CACnB,OAAO,CAAC,YAAY,IACpB,OAAO,CAAC,cAAc,IACtB,IAAI;QACP,MAAME,gBAAgBF,KAAK,CAAC,EAAE,CAAC,OAAO,CAAC,eAAe,IAAI,IAAI;QAC9DD,iBAAiB;YAAEE;YAAO,SAASC;QAAc;IACnD,OACEH,iBAAiB;QAAE,OAAO;QAAID;IAAQ;IAGxC5B,MAAM,wBAAwB4B;IAC9B5B,MAAM,yBAAyB6B,eAAe,KAAK;IACnD7B,MAAM,uBAAuB6B,eAAe,OAAO;IACnD,OAAOA;AACT;AAEO,SAASI,6BAA6BL,OAAe;IAI1D,MAAMpB,WAAWmB,qBAAqBC;IACtC,MAAMM,SAAS3B,2BAA2BC;IAC1C,OAAO;QAAEA;QAAU0B;IAAO;AAC5B"}
@@ -40,7 +40,7 @@ const kimiPixelPointCoordinatesMeta = {
40
40
  };
41
41
  function parseKimiRawLocateValue(input) {
42
42
  const point = (0, index_js_namespaceObject.parseCoordinateList)(input, 'point');
43
- if (point.length < 2) throw new Error(`invalid point data: ${JSON.stringify(input)} `);
43
+ if (2 !== point.length) throw new Error(`invalid point data: ${JSON.stringify(input)} `);
44
44
  const [x, y] = point;
45
45
  const coordinatesMeta = x <= 1 && y <= 1 ? kimiNormalizedPointCoordinatesMeta : kimiPixelPointCoordinatesMeta;
46
46
  return (0, index_js_namespaceObject.createLocateResultValue)(coordinatesMeta, [