@midscene/core 1.16.0 → 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 (147) hide show
  1. package/dist/es/agent/agent-options.mjs +36 -0
  2. package/dist/es/agent/agent-options.mjs.map +1 -0
  3. package/dist/es/agent/agent-report-manager.mjs +323 -0
  4. package/dist/es/agent/agent-report-manager.mjs.map +1 -0
  5. package/dist/es/agent/agent.mjs +112 -228
  6. package/dist/es/agent/agent.mjs.map +1 -1
  7. package/dist/es/agent/cache-config.mjs +21 -1
  8. package/dist/es/agent/cache-config.mjs.map +1 -1
  9. package/dist/es/agent/tasks.mjs +3 -1
  10. package/dist/es/agent/tasks.mjs.map +1 -1
  11. package/dist/es/agent/utils.mjs +4 -4
  12. package/dist/es/agent/utils.mjs.map +1 -1
  13. package/dist/es/ai-model/models/auto-glm/parser.mjs +1 -1
  14. package/dist/es/ai-model/models/auto-glm/parser.mjs.map +1 -1
  15. package/dist/es/ai-model/models/kimi.mjs +1 -1
  16. package/dist/es/ai-model/models/kimi.mjs.map +1 -1
  17. package/dist/es/ai-model/service-caller/call-ai.mjs +10 -1
  18. package/dist/es/ai-model/service-caller/call-ai.mjs.map +1 -1
  19. package/dist/es/ai-model/service-caller/openai/call-openai.mjs +7 -2
  20. package/dist/es/ai-model/service-caller/openai/call-openai.mjs.map +1 -1
  21. package/dist/es/ai-model/shared/model-locate-result/errors.mjs +1 -1
  22. package/dist/es/ai-model/shared/model-locate-result/errors.mjs.map +1 -1
  23. package/dist/es/ai-model/shared/model-locate-result/parse.mjs +6 -2
  24. package/dist/es/ai-model/shared/model-locate-result/parse.mjs.map +1 -1
  25. package/dist/es/device/index.mjs +9 -8
  26. package/dist/es/device/index.mjs.map +1 -1
  27. package/dist/es/report-generator.mjs +76 -36
  28. package/dist/es/report-generator.mjs.map +1 -1
  29. package/dist/es/report-html-template.mjs +1 -1
  30. package/dist/es/test-run-report.mjs.map +1 -1
  31. package/dist/es/test-runner/engine/document-runtime.mjs +30 -24
  32. package/dist/es/test-runner/engine/document-runtime.mjs.map +1 -1
  33. package/dist/es/test-runner/engine/project-runtime.mjs +17 -11
  34. package/dist/es/test-runner/engine/project-runtime.mjs.map +1 -1
  35. package/dist/es/test-runner/engine/resource-operations.mjs +33 -8
  36. package/dist/es/test-runner/engine/resource-operations.mjs.map +1 -1
  37. package/dist/es/test-runner/engine/run-collected-case.mjs +1 -0
  38. package/dist/es/test-runner/engine/run-collected-case.mjs.map +1 -1
  39. package/dist/es/test-runner/engine/run-workflow-document.mjs +3 -0
  40. package/dist/es/test-runner/engine/run-workflow-document.mjs.map +1 -1
  41. package/dist/es/test-runner/engine/setup-timeout.mjs +37 -0
  42. package/dist/es/test-runner/engine/setup-timeout.mjs.map +1 -0
  43. package/dist/es/test-runner/reporting/merge-report.mjs +3 -1
  44. package/dist/es/test-runner/reporting/merge-report.mjs.map +1 -1
  45. package/dist/es/test-runner/reporting/metrics.mjs +39 -2
  46. package/dist/es/test-runner/reporting/metrics.mjs.map +1 -1
  47. package/dist/es/utils.mjs +1 -1
  48. package/dist/es/yaml/execution-session.mjs +2 -1
  49. package/dist/es/yaml/execution-session.mjs.map +1 -1
  50. package/dist/es/yaml/legacy-yaml-report.mjs +1 -1
  51. package/dist/es/yaml/legacy-yaml-report.mjs.map +1 -1
  52. package/dist/es/yaml/player.mjs +17 -3
  53. package/dist/es/yaml/player.mjs.map +1 -1
  54. package/dist/lib/agent/agent-options.js +73 -0
  55. package/dist/lib/agent/agent-options.js.map +1 -0
  56. package/dist/lib/agent/agent-report-manager.js +357 -0
  57. package/dist/lib/agent/agent-report-manager.js.map +1 -0
  58. package/dist/lib/agent/agent.js +110 -226
  59. package/dist/lib/agent/agent.js.map +1 -1
  60. package/dist/lib/agent/cache-config.js +23 -0
  61. package/dist/lib/agent/cache-config.js.map +1 -1
  62. package/dist/lib/agent/tasks.js +3 -1
  63. package/dist/lib/agent/tasks.js.map +1 -1
  64. package/dist/lib/agent/utils.js +2 -2
  65. package/dist/lib/agent/utils.js.map +1 -1
  66. package/dist/lib/ai-model/models/auto-glm/parser.js +1 -1
  67. package/dist/lib/ai-model/models/auto-glm/parser.js.map +1 -1
  68. package/dist/lib/ai-model/models/kimi.js +1 -1
  69. package/dist/lib/ai-model/models/kimi.js.map +1 -1
  70. package/dist/lib/ai-model/service-caller/call-ai.js +10 -1
  71. package/dist/lib/ai-model/service-caller/call-ai.js.map +1 -1
  72. package/dist/lib/ai-model/service-caller/openai/call-openai.js +7 -2
  73. package/dist/lib/ai-model/service-caller/openai/call-openai.js.map +1 -1
  74. package/dist/lib/ai-model/shared/model-locate-result/errors.js +1 -1
  75. package/dist/lib/ai-model/shared/model-locate-result/errors.js.map +1 -1
  76. package/dist/lib/ai-model/shared/model-locate-result/parse.js +6 -2
  77. package/dist/lib/ai-model/shared/model-locate-result/parse.js.map +1 -1
  78. package/dist/lib/device/index.js +9 -8
  79. package/dist/lib/device/index.js.map +1 -1
  80. package/dist/lib/report-generator.js +75 -35
  81. package/dist/lib/report-generator.js.map +1 -1
  82. package/dist/lib/report-html-template.js +1 -1
  83. package/dist/lib/test-run-report.js.map +1 -1
  84. package/dist/lib/test-runner/engine/document-runtime.js +30 -24
  85. package/dist/lib/test-runner/engine/document-runtime.js.map +1 -1
  86. package/dist/lib/test-runner/engine/project-runtime.js +17 -11
  87. package/dist/lib/test-runner/engine/project-runtime.js.map +1 -1
  88. package/dist/lib/test-runner/engine/resource-operations.js +36 -8
  89. package/dist/lib/test-runner/engine/resource-operations.js.map +1 -1
  90. package/dist/lib/test-runner/engine/run-collected-case.js +1 -0
  91. package/dist/lib/test-runner/engine/run-collected-case.js.map +1 -1
  92. package/dist/lib/test-runner/engine/run-workflow-document.js +3 -0
  93. package/dist/lib/test-runner/engine/run-workflow-document.js.map +1 -1
  94. package/dist/lib/test-runner/engine/setup-timeout.js +71 -0
  95. package/dist/lib/test-runner/engine/setup-timeout.js.map +1 -0
  96. package/dist/lib/test-runner/reporting/merge-report.js +3 -1
  97. package/dist/lib/test-runner/reporting/merge-report.js.map +1 -1
  98. package/dist/lib/test-runner/reporting/metrics.js +39 -2
  99. package/dist/lib/test-runner/reporting/metrics.js.map +1 -1
  100. package/dist/lib/utils.js +1 -1
  101. package/dist/lib/yaml/execution-session.js +4 -0
  102. package/dist/lib/yaml/execution-session.js.map +1 -1
  103. package/dist/lib/yaml/legacy-yaml-report.js +1 -1
  104. package/dist/lib/yaml/legacy-yaml-report.js.map +1 -1
  105. package/dist/lib/yaml/player.js +16 -2
  106. package/dist/lib/yaml/player.js.map +1 -1
  107. package/dist/types/agent/agent-options.d.ts +4 -0
  108. package/dist/types/agent/agent-options.d.ts.map +1 -0
  109. package/dist/types/agent/agent-report-manager.d.ts +92 -0
  110. package/dist/types/agent/agent-report-manager.d.ts.map +1 -0
  111. package/dist/types/agent/agent.d.ts +31 -24
  112. package/dist/types/agent/agent.d.ts.map +1 -1
  113. package/dist/types/agent/cache-config.d.ts +10 -0
  114. package/dist/types/agent/cache-config.d.ts.map +1 -1
  115. package/dist/types/agent/tasks.d.ts +1 -0
  116. package/dist/types/agent/tasks.d.ts.map +1 -1
  117. package/dist/types/ai-model/models/auto-glm/parser.d.ts.map +1 -1
  118. package/dist/types/ai-model/service-caller/openai/call-openai.d.ts.map +1 -1
  119. package/dist/types/ai-model/shared/model-locate-result/errors.d.ts +1 -1
  120. package/dist/types/ai-model/shared/model-locate-result/errors.d.ts.map +1 -1
  121. package/dist/types/ai-model/shared/model-locate-result/parse.d.ts.map +1 -1
  122. package/dist/types/device/index.d.ts +7 -7
  123. package/dist/types/device/index.d.ts.map +1 -1
  124. package/dist/types/report-generator.d.ts +5 -1
  125. package/dist/types/report-generator.d.ts.map +1 -1
  126. package/dist/types/test-run-report.d.ts +4 -1
  127. package/dist/types/test-run-report.d.ts.map +1 -1
  128. package/dist/types/test-runner/engine/document-runtime.d.ts.map +1 -1
  129. package/dist/types/test-runner/engine/project-runtime.d.ts.map +1 -1
  130. package/dist/types/test-runner/engine/resource-operations.d.ts +5 -0
  131. package/dist/types/test-runner/engine/resource-operations.d.ts.map +1 -1
  132. package/dist/types/test-runner/engine/run-collected-case.d.ts.map +1 -1
  133. package/dist/types/test-runner/engine/run-workflow-document.d.ts.map +1 -1
  134. package/dist/types/test-runner/engine/setup-timeout.d.ts +3 -0
  135. package/dist/types/test-runner/engine/setup-timeout.d.ts.map +1 -0
  136. package/dist/types/test-runner/engine/types.d.ts +7 -0
  137. package/dist/types/test-runner/engine/types.d.ts.map +1 -1
  138. package/dist/types/test-runner/parser/types.d.ts +5 -0
  139. package/dist/types/test-runner/parser/types.d.ts.map +1 -1
  140. package/dist/types/test-runner/project.d.ts +22 -0
  141. package/dist/types/test-runner/project.d.ts.map +1 -1
  142. package/dist/types/test-runner/reporting/merge-report.d.ts.map +1 -1
  143. package/dist/types/test-runner/reporting/metrics.d.ts.map +1 -1
  144. package/dist/types/yaml/execution-session.d.ts +2 -0
  145. package/dist/types/yaml/execution-session.d.ts.map +1 -1
  146. package/dist/types/yaml/player.d.ts.map +1 -1
  147. package/package.json +2 -2
@@ -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":"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"}
package/dist/es/utils.mjs CHANGED
@@ -184,7 +184,7 @@ function stringifyDumpData(data, indents) {
184
184
  return JSON.stringify(data, replacerForPageObject, indents);
185
185
  }
186
186
  function getVersion() {
187
- return "1.16.0";
187
+ return "1.16.2";
188
188
  }
189
189
  function debugLog(...message) {
190
190
  const debugMode = process.env[MIDSCENE_DEBUG_MODE];
@@ -8,6 +8,7 @@ host[stateKey] ??= {
8
8
  context: createExecutionContext()
9
9
  };
10
10
  const { sessions, signals, context } = host[stateKey];
11
+ const hasActiveYamlExecution = (agent)=>Boolean(sessions.get(agent)?.length);
11
12
  function runInYamlExecutionContext(callback) {
12
13
  const frame = {
13
14
  parent: context.getStore(),
@@ -85,6 +86,6 @@ function enterYamlExecution(agent, options = {}) {
85
86
  finish: session.finish
86
87
  };
87
88
  }
88
- export { YamlExecutionOwnershipError, currentYamlSignal, enterYamlAction, enterYamlExecution, runInYamlExecutionContext };
89
+ export { YamlExecutionOwnershipError, currentYamlSignal, enterYamlAction, enterYamlExecution, hasActiveYamlExecution, runInYamlExecutionContext };
89
90
 
90
91
  //# sourceMappingURL=execution-session.mjs.map
@@ -1 +1 @@
1
- {"version":3,"file":"yaml/execution-session.mjs","sources":["../../../src/yaml/execution-session.ts"],"sourcesContent":["import {\n createExecutionContext,\n supportsAsyncContext,\n} from '#yaml-execution-context';\nimport { WorkflowError } from '../test-runner/errors';\nimport type { WorkflowExecutionRecord } from '../test-runner/execution-record';\n\ninterface YamlExecutionSession {\n agent: object;\n children: WorkflowExecutionRecord[];\n finished: boolean;\n finish(record?: WorkflowExecutionRecord): void;\n}\n\ninterface ExecutionFrame {\n parent?: ExecutionFrame;\n session?: YamlExecutionSession;\n signals: WeakMap<object, { signal: AbortSignal }[]>;\n}\n\nconst stateKey = Symbol.for('@midscene/core/yaml-execution-session/v2');\nconst host = globalThis as typeof globalThis & {\n [stateKey]?: {\n sessions: WeakMap<object, YamlExecutionSession[]>;\n signals: WeakMap<object, { signal: AbortSignal }[]>;\n context: ReturnType<typeof createExecutionContext<ExecutionFrame>>;\n };\n};\nhost[stateKey] ??= {\n sessions: new WeakMap(),\n signals: new WeakMap(),\n context: createExecutionContext<ExecutionFrame>(),\n};\nconst { sessions, signals, context } = host[stateKey];\n\n/** Every entry gets its own async frame, shared across CJS and ESM copies. */\nexport function runInYamlExecutionContext<T>(\n callback: () => Promise<T>,\n): Promise<T> {\n const frame: ExecutionFrame = {\n parent: context.getStore(),\n signals: new WeakMap(),\n };\n return context.run(frame, async () => {\n try {\n return await callback();\n } finally {\n frame.session?.finish();\n }\n });\n}\n\nexport const currentYamlSignal = (agent: object): AbortSignal | undefined => {\n if (!supportsAsyncContext) return signals.get(agent)?.at(-1)?.signal;\n for (let frame = context.getStore(); frame; frame = frame.parent) {\n const signal = frame.signals.get(agent)?.at(-1)?.signal;\n if (signal) return signal;\n }\n return undefined;\n};\n\nexport function enterYamlAction(\n agent: object,\n signal: AbortSignal,\n): () => void {\n const scopeSignals = supportsAsyncContext\n ? context.getStore()?.signals\n : signals;\n if (!scopeSignals)\n throw new Error('YAML action requires an execution context.');\n const stack = scopeSignals.get(agent) ?? [];\n scopeSignals.set(agent, stack);\n const entry = { signal };\n stack.push(entry);\n return () => {\n const index = stack.indexOf(entry);\n if (index >= 0) stack.splice(index, 1);\n if (!stack.length) scopeSignals.delete(agent);\n };\n}\n\nexport class YamlExecutionOwnershipError extends WorkflowError {}\n\n/** Nested runs borrow ownership. They never finalize or drain their parent. */\nexport function enterYamlExecution(\n agent: object,\n options: { allowIndependentOverlap?: boolean } = {},\n) {\n const stack = sessions.get(agent) ?? [];\n const frame = context.getStore();\n let parent = supportsAsyncContext ? undefined : stack.at(-1);\n if (supportsAsyncContext) {\n if (!frame || frame.session)\n throw new Error('YAML execution requires a fresh execution context.');\n for (let owner = frame.parent; owner; owner = owner.parent) {\n if (owner.session?.agent === agent) {\n parent = owner.session;\n break;\n }\n }\n if (parent?.finished)\n throw new YamlExecutionOwnershipError(\n 'Cannot start nested YAML after its owning execution has finished.',\n { code: 'YAML_EXECUTION_SCOPE_CLOSED' },\n );\n if (stack.at(-1) !== parent && !options.allowIndependentOverlap)\n throw new YamlExecutionOwnershipError(\n 'The same Agent cannot run independent overlapping YAML executions. Await the active run before starting another.',\n { code: 'YAML_EXECUTION_OVERLAP' },\n );\n }\n const session: YamlExecutionSession = {\n agent,\n children: [],\n finished: false,\n finish(record?: WorkflowExecutionRecord) {\n if (session.finished) return;\n session.finished = true;\n const index = stack.indexOf(session);\n if (index >= 0) stack.splice(index, 1);\n if (!stack.length) sessions.delete(agent);\n if (record) parent?.children.push(record);\n else parent?.children.push(...session.children);\n },\n };\n stack.push(session);\n sessions.set(agent, stack);\n if (frame) frame.session = session;\n return {\n isRoot: !parent,\n children: session.children,\n finish: session.finish,\n };\n}\n"],"names":["stateKey","Symbol","host","globalThis","WeakMap","createExecutionContext","sessions","signals","context","runInYamlExecutionContext","callback","frame","currentYamlSignal","agent","supportsAsyncContext","signal","enterYamlAction","scopeSignals","Error","stack","entry","index","YamlExecutionOwnershipError","WorkflowError","enterYamlExecution","options","parent","undefined","owner","session","record"],"mappings":"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"}
1
+ {"version":3,"file":"yaml/execution-session.mjs","sources":["../../../src/yaml/execution-session.ts"],"sourcesContent":["import {\n createExecutionContext,\n supportsAsyncContext,\n} from '#yaml-execution-context';\nimport { WorkflowError } from '../test-runner/errors';\nimport type { WorkflowExecutionRecord } from '../test-runner/execution-record';\n\ninterface YamlExecutionSession {\n agent: object;\n children: WorkflowExecutionRecord[];\n finished: boolean;\n finish(record?: WorkflowExecutionRecord): void;\n}\n\ninterface ExecutionFrame {\n parent?: ExecutionFrame;\n session?: YamlExecutionSession;\n signals: WeakMap<object, { signal: AbortSignal }[]>;\n}\n\nconst stateKey = Symbol.for('@midscene/core/yaml-execution-session/v2');\nconst host = globalThis as typeof globalThis & {\n [stateKey]?: {\n sessions: WeakMap<object, YamlExecutionSession[]>;\n signals: WeakMap<object, { signal: AbortSignal }[]>;\n context: ReturnType<typeof createExecutionContext<ExecutionFrame>>;\n };\n};\nhost[stateKey] ??= {\n sessions: new WeakMap(),\n signals: new WeakMap(),\n context: createExecutionContext<ExecutionFrame>(),\n};\nconst { sessions, signals, context } = host[stateKey];\n\n/** Report boundaries cannot change while a YAML owner still uses the Agent. */\nexport const hasActiveYamlExecution = (agent: object): boolean =>\n Boolean(sessions.get(agent)?.length);\n\n/** Every entry gets its own async frame, shared across CJS and ESM copies. */\nexport function runInYamlExecutionContext<T>(\n callback: () => Promise<T>,\n): Promise<T> {\n const frame: ExecutionFrame = {\n parent: context.getStore(),\n signals: new WeakMap(),\n };\n return context.run(frame, async () => {\n try {\n return await callback();\n } finally {\n frame.session?.finish();\n }\n });\n}\n\nexport const currentYamlSignal = (agent: object): AbortSignal | undefined => {\n if (!supportsAsyncContext) return signals.get(agent)?.at(-1)?.signal;\n for (let frame = context.getStore(); frame; frame = frame.parent) {\n const signal = frame.signals.get(agent)?.at(-1)?.signal;\n if (signal) return signal;\n }\n return undefined;\n};\n\nexport function enterYamlAction(\n agent: object,\n signal: AbortSignal,\n): () => void {\n const scopeSignals = supportsAsyncContext\n ? context.getStore()?.signals\n : signals;\n if (!scopeSignals)\n throw new Error('YAML action requires an execution context.');\n const stack = scopeSignals.get(agent) ?? [];\n scopeSignals.set(agent, stack);\n const entry = { signal };\n stack.push(entry);\n return () => {\n const index = stack.indexOf(entry);\n if (index >= 0) stack.splice(index, 1);\n if (!stack.length) scopeSignals.delete(agent);\n };\n}\n\nexport class YamlExecutionOwnershipError extends WorkflowError {}\n\n/** Nested runs borrow ownership. They never finalize or drain their parent. */\nexport function enterYamlExecution(\n agent: object,\n options: { allowIndependentOverlap?: boolean } = {},\n) {\n const stack = sessions.get(agent) ?? [];\n const frame = context.getStore();\n let parent = supportsAsyncContext ? undefined : stack.at(-1);\n if (supportsAsyncContext) {\n if (!frame || frame.session)\n throw new Error('YAML execution requires a fresh execution context.');\n for (let owner = frame.parent; owner; owner = owner.parent) {\n if (owner.session?.agent === agent) {\n parent = owner.session;\n break;\n }\n }\n if (parent?.finished)\n throw new YamlExecutionOwnershipError(\n 'Cannot start nested YAML after its owning execution has finished.',\n { code: 'YAML_EXECUTION_SCOPE_CLOSED' },\n );\n if (stack.at(-1) !== parent && !options.allowIndependentOverlap)\n throw new YamlExecutionOwnershipError(\n 'The same Agent cannot run independent overlapping YAML executions. Await the active run before starting another.',\n { code: 'YAML_EXECUTION_OVERLAP' },\n );\n }\n const session: YamlExecutionSession = {\n agent,\n children: [],\n finished: false,\n finish(record?: WorkflowExecutionRecord) {\n if (session.finished) return;\n session.finished = true;\n const index = stack.indexOf(session);\n if (index >= 0) stack.splice(index, 1);\n if (!stack.length) sessions.delete(agent);\n if (record) parent?.children.push(record);\n else parent?.children.push(...session.children);\n },\n };\n stack.push(session);\n sessions.set(agent, stack);\n if (frame) frame.session = session;\n return {\n isRoot: !parent,\n children: session.children,\n finish: session.finish,\n };\n}\n"],"names":["stateKey","Symbol","host","globalThis","WeakMap","createExecutionContext","sessions","signals","context","hasActiveYamlExecution","agent","Boolean","runInYamlExecutionContext","callback","frame","currentYamlSignal","supportsAsyncContext","signal","enterYamlAction","scopeSignals","Error","stack","entry","index","YamlExecutionOwnershipError","WorkflowError","enterYamlExecution","options","parent","undefined","owner","session","record"],"mappings":"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"}
@@ -34,8 +34,8 @@ async function publishLegacyYamlReport(options) {
34
34
  sdkVersion: getVersion(),
35
35
  modelBriefs: []
36
36
  });
37
- await generator.finalize();
38
37
  const source = await generator.createSourceSnapshot?.(runId);
38
+ await generator.finalize();
39
39
  if (source) record = Object.freeze({
40
40
  ...record,
41
41
  reportSources: [
@@ -1 +1 @@
1
- {"version":3,"file":"yaml/legacy-yaml-report.mjs","sources":["../../../src/yaml/legacy-yaml-report.ts"],"sourcesContent":["import { basename } from 'node:path';\nimport type { Agent } from '@/agent/agent';\nimport type { MidsceneYamlScript } from '@/types';\nimport { ifInBrowser, ifInWorker } from '@midscene/shared/utils';\nimport { ReportGenerator } from '../report-generator';\nimport type { WorkflowExecutionRecord } from '../test-runner';\nimport { executionRecordsToReportInput } from '../test-runner/reporting/execution-record';\nimport { getVersion } from '../utils';\nimport { isYamlReportEnabled } from './report-policy';\n\ninterface PublishLegacyYamlReportOptions {\n agent: Agent | null;\n record: WorkflowExecutionRecord;\n runId: string;\n script: MidsceneYamlScript;\n scriptPath?: string;\n fallbackReportFileName?: string;\n}\n\nexport interface PublishedLegacyYamlReport {\n record: WorkflowExecutionRecord;\n reportFile?: string | null;\n}\n\n/** Report publication is a host projection, not a ScriptPlayer state concern. */\nexport async function publishLegacyYamlReport(\n options: PublishLegacyYamlReportOptions,\n): Promise<PublishedLegacyYamlReport> {\n const { agent, runId } = options;\n let record = options.record;\n if (agent) {\n const reportFile =\n (await agent._writeYamlExecutionReport?.(record)) ?? agent.reportFile;\n const source = await agent._createReportSource?.(runId);\n if (source) record = Object.freeze({ ...record, reportSources: [source] });\n return { record, reportFile };\n }\n if (ifInBrowser || ifInWorker || !isYamlReportEnabled(options.script))\n return { record };\n\n const generator = ReportGenerator.create(\n options.fallbackReportFileName ??\n options.script.agent?.reportFileName ??\n options.script.agent?.testId ??\n (options.scriptPath\n ? basename(options.scriptPath).replace(/\\.ya?ml$/i, '')\n : `script-${runId}`),\n options.script.agent ?? {},\n );\n const reportFile = await generator.writeRunnerReport?.(\n executionRecordsToReportInput([record], { runId }),\n runId,\n {\n groupName: 'YAML execution',\n sdkVersion: getVersion(),\n modelBriefs: [],\n },\n );\n await generator.finalize();\n const source = await generator.createSourceSnapshot?.(runId);\n if (source) record = Object.freeze({ ...record, reportSources: [source] });\n return { record, reportFile };\n}\n"],"names":["publishLegacyYamlReport","options","agent","runId","record","reportFile","source","Object","ifInBrowser","ifInWorker","isYamlReportEnabled","generator","ReportGenerator","basename","executionRecordsToReportInput","getVersion"],"mappings":";;;;;;AAyBO,eAAeA,wBACpBC,OAAuC;IAEvC,MAAM,EAAEC,KAAK,EAAEC,KAAK,EAAE,GAAGF;IACzB,IAAIG,SAASH,QAAQ,MAAM;IAC3B,IAAIC,OAAO;QACT,MAAMG,aACH,MAAMH,MAAM,yBAAyB,GAAGE,WAAYF,MAAM,UAAU;QACvE,MAAMI,SAAS,MAAMJ,MAAM,mBAAmB,GAAGC;QACjD,IAAIG,QAAQF,SAASG,OAAO,MAAM,CAAC;YAAE,GAAGH,MAAM;YAAE,eAAe;gBAACE;aAAO;QAAC;QACxE,OAAO;YAAEF;YAAQC;QAAW;IAC9B;IACA,IAAIG,eAAeC,cAAc,CAACC,oBAAoBT,QAAQ,MAAM,GAClE,OAAO;QAAEG;IAAO;IAElB,MAAMO,YAAYC,gBAAgB,MAAM,CACtCX,QAAQ,sBAAsB,IAC5BA,QAAQ,MAAM,CAAC,KAAK,EAAE,kBACtBA,QAAQ,MAAM,CAAC,KAAK,EAAE,UACrBA,CAAAA,QAAQ,UAAU,GACfY,SAASZ,QAAQ,UAAU,EAAE,OAAO,CAAC,aAAa,MAClD,CAAC,OAAO,EAAEE,OAAM,GACtBF,QAAQ,MAAM,CAAC,KAAK,IAAI,CAAC;IAE3B,MAAMI,aAAa,MAAMM,UAAU,iBAAiB,GAClDG,8BAA8B;QAACV;KAAO,EAAE;QAAED;IAAM,IAChDA,OACA;QACE,WAAW;QACX,YAAYY;QACZ,aAAa,EAAE;IACjB;IAEF,MAAMJ,UAAU,QAAQ;IACxB,MAAML,SAAS,MAAMK,UAAU,oBAAoB,GAAGR;IACtD,IAAIG,QAAQF,SAASG,OAAO,MAAM,CAAC;QAAE,GAAGH,MAAM;QAAE,eAAe;YAACE;SAAO;IAAC;IACxE,OAAO;QAAEF;QAAQC;IAAW;AAC9B"}
1
+ {"version":3,"file":"yaml/legacy-yaml-report.mjs","sources":["../../../src/yaml/legacy-yaml-report.ts"],"sourcesContent":["import { basename } from 'node:path';\nimport type { Agent } from '@/agent/agent';\nimport type { MidsceneYamlScript } from '@/types';\nimport { ifInBrowser, ifInWorker } from '@midscene/shared/utils';\nimport { ReportGenerator } from '../report-generator';\nimport type { WorkflowExecutionRecord } from '../test-runner';\nimport { executionRecordsToReportInput } from '../test-runner/reporting/execution-record';\nimport { getVersion } from '../utils';\nimport { isYamlReportEnabled } from './report-policy';\n\ninterface PublishLegacyYamlReportOptions {\n agent: Agent | null;\n record: WorkflowExecutionRecord;\n runId: string;\n script: MidsceneYamlScript;\n scriptPath?: string;\n fallbackReportFileName?: string;\n}\n\nexport interface PublishedLegacyYamlReport {\n record: WorkflowExecutionRecord;\n reportFile?: string | null;\n}\n\n/** Report publication is a host projection, not a ScriptPlayer state concern. */\nexport async function publishLegacyYamlReport(\n options: PublishLegacyYamlReportOptions,\n): Promise<PublishedLegacyYamlReport> {\n const { agent, runId } = options;\n let record = options.record;\n if (agent) {\n const reportFile =\n (await agent._writeYamlExecutionReport?.(record)) ?? agent.reportFile;\n const source = await agent._createReportSource?.(runId);\n if (source) record = Object.freeze({ ...record, reportSources: [source] });\n return { record, reportFile };\n }\n if (ifInBrowser || ifInWorker || !isYamlReportEnabled(options.script))\n return { record };\n\n const generator = ReportGenerator.create(\n options.fallbackReportFileName ??\n options.script.agent?.reportFileName ??\n options.script.agent?.testId ??\n (options.scriptPath\n ? basename(options.scriptPath).replace(/\\.ya?ml$/i, '')\n : `script-${runId}`),\n options.script.agent ?? {},\n );\n const reportFile = await generator.writeRunnerReport?.(\n executionRecordsToReportInput([record], { runId }),\n runId,\n {\n groupName: 'YAML execution',\n sdkVersion: getVersion(),\n modelBriefs: [],\n },\n );\n const source = await generator.createSourceSnapshot?.(runId);\n await generator.finalize();\n if (source) record = Object.freeze({ ...record, reportSources: [source] });\n return { record, reportFile };\n}\n"],"names":["publishLegacyYamlReport","options","agent","runId","record","reportFile","source","Object","ifInBrowser","ifInWorker","isYamlReportEnabled","generator","ReportGenerator","basename","executionRecordsToReportInput","getVersion"],"mappings":";;;;;;AAyBO,eAAeA,wBACpBC,OAAuC;IAEvC,MAAM,EAAEC,KAAK,EAAEC,KAAK,EAAE,GAAGF;IACzB,IAAIG,SAASH,QAAQ,MAAM;IAC3B,IAAIC,OAAO;QACT,MAAMG,aACH,MAAMH,MAAM,yBAAyB,GAAGE,WAAYF,MAAM,UAAU;QACvE,MAAMI,SAAS,MAAMJ,MAAM,mBAAmB,GAAGC;QACjD,IAAIG,QAAQF,SAASG,OAAO,MAAM,CAAC;YAAE,GAAGH,MAAM;YAAE,eAAe;gBAACE;aAAO;QAAC;QACxE,OAAO;YAAEF;YAAQC;QAAW;IAC9B;IACA,IAAIG,eAAeC,cAAc,CAACC,oBAAoBT,QAAQ,MAAM,GAClE,OAAO;QAAEG;IAAO;IAElB,MAAMO,YAAYC,gBAAgB,MAAM,CACtCX,QAAQ,sBAAsB,IAC5BA,QAAQ,MAAM,CAAC,KAAK,EAAE,kBACtBA,QAAQ,MAAM,CAAC,KAAK,EAAE,UACrBA,CAAAA,QAAQ,UAAU,GACfY,SAASZ,QAAQ,UAAU,EAAE,OAAO,CAAC,aAAa,MAClD,CAAC,OAAO,EAAEE,OAAM,GACtBF,QAAQ,MAAM,CAAC,KAAK,IAAI,CAAC;IAE3B,MAAMI,aAAa,MAAMM,UAAU,iBAAiB,GAClDG,8BAA8B;QAACV;KAAO,EAAE;QAAED;IAAM,IAChDA,OACA;QACE,WAAW;QACX,YAAYY;QACZ,aAAa,EAAE;IACjB;IAEF,MAAMT,SAAS,MAAMK,UAAU,oBAAoB,GAAGR;IACtD,MAAMQ,UAAU,QAAQ;IACxB,IAAIL,QAAQF,SAASG,OAAO,MAAM,CAAC;QAAE,GAAGH,MAAM;QAAE,eAAe;YAACE;SAAO;IAAC;IACxE,OAAO;QAAEF;QAAQC;IAAW;AAC9B"}
@@ -7,7 +7,7 @@ import { assert, ifInBrowser, ifInWorker, uuid } from "@midscene/shared/utils";
7
7
  import { WorkflowExecutionFailure, WorkflowPublicationError } from "../test-runner/engine/execution-failure.mjs";
8
8
  import { cleanupResources } from "../test-runner/engine/resource-operations.mjs";
9
9
  import { runFreeFnCleanup } from "./cleanup.mjs";
10
- import { YamlExecutionOwnershipError, currentYamlSignal, enterYamlExecution, runInYamlExecutionContext } from "./execution-session.mjs";
10
+ import { YamlExecutionOwnershipError, currentYamlSignal, enterYamlExecution, hasActiveYamlExecution, runInYamlExecutionContext } from "./execution-session.mjs";
11
11
  import { createLegacyYamlExecutionRecord } from "./legacy-yaml-execution-record.mjs";
12
12
  import { publishLegacyYamlReport } from "./legacy-yaml-report.mjs";
13
13
  import { createLegacyYamlRuntime, legacyYamlOutcomeError } from "./legacy-yaml-runtime.mjs";
@@ -141,11 +141,11 @@ class ScriptPlayer {
141
141
  try {
142
142
  const { agent: newAgent, freeFn: newFreeFn } = await this.setupAgent(platform);
143
143
  agent = newAgent;
144
- agent._prepareForTestRunner?.();
144
+ session = enterYamlExecution(agent);
145
145
  freeFn = [
146
146
  ...newFreeFn || []
147
147
  ];
148
- session = enterYamlExecution(agent);
148
+ agent._prepareForTestRunner?.();
149
149
  signal = this.abortSignal ?? currentYamlSignal(agent);
150
150
  signal?.throwIfAborted();
151
151
  this.actionSpace = await agent.getActionSpace();
@@ -267,6 +267,20 @@ class ScriptPlayer {
267
267
  });
268
268
  }
269
269
  session?.finish(state.executionRecord);
270
+ if (agent?.destroyed && !hasActiveYamlExecution(agent)) try {
271
+ await agent.finalizeReport();
272
+ } catch (error) {
273
+ reportError = reportError ? new AggregateError([
274
+ reportError,
275
+ error
276
+ ], 'YAML report publication failed') : error;
277
+ this.setPlayerStatus('error', reportError);
278
+ state.executionRecord = Object.freeze({
279
+ ...state.executionRecord,
280
+ status: 'failed',
281
+ reportError
282
+ });
283
+ }
270
284
  if (reportError) {
271
285
  const errors = [
272
286
  setupError,
@@ -1 +1 @@
1
- {"version":3,"file":"yaml/player.mjs","sources":["../../../src/yaml/player.ts"],"sourcesContent":["import { mkdir, writeFile } from 'node:fs/promises';\nimport { basename, dirname, join, resolve } from 'node:path';\nimport { isActionReadinessError } from '@/agent/action-readiness';\nimport type { Agent } from '@/agent/agent';\nimport type {\n DeviceAction,\n FreeFn,\n MidsceneYamlScript,\n MidsceneYamlScriptEnv,\n ScriptPlayerStatusValue,\n ScriptPlayerTaskStatus,\n} from '@/types';\nimport { getMidsceneRunSubDir } from '@midscene/shared/common';\nimport { getDebug } from '@midscene/shared/logger';\nimport { assert, ifInBrowser, ifInWorker, uuid } from '@midscene/shared/utils';\nimport type { WorkflowDocumentExecutionResult } from '../test-runner';\nimport {\n WorkflowExecutionFailure,\n WorkflowPublicationError,\n} from '../test-runner/engine/execution-failure';\nimport { cleanupResources } from '../test-runner/engine/resource-operations';\nimport { runFreeFnCleanup } from './cleanup';\nimport {\n YamlExecutionOwnershipError,\n currentYamlSignal,\n enterYamlExecution,\n runInYamlExecutionContext,\n} from './execution-session';\nimport { createLegacyYamlExecutionRecord } from './legacy-yaml-execution-record';\nimport { publishLegacyYamlReport } from './legacy-yaml-report';\nimport {\n createLegacyYamlRuntime,\n legacyYamlOutcomeError,\n} from './legacy-yaml-runtime';\nimport {\n getLegacyYamlPlayerState,\n initializeLegacyYamlPlayerState,\n} from './player-state';\nimport { collectLegacyYamlDocument } from './test-runner-compat';\nimport { resolveWebTarget, resolveYamlOutputConfig } from './utils';\n\nconst debug = getDebug('yaml-player');\n\n/**\n * Compatibility facade for the legacy YAML API.\n *\n * Execution is delegated to the shared Runner kernel through\n * createLegacyYamlRuntime(). This class keeps the mutable status, result,\n * progress, output, and setup/cleanup behavior exposed by the old API.\n */\nexport class ScriptPlayer<T extends MidsceneYamlScriptEnv> {\n public currentTaskIndex?: number;\n public taskStatusList: ScriptPlayerTaskStatus[] = [];\n public status: ScriptPlayerStatusValue = 'init';\n public reportFile?: string | null;\n public result: Record<string, any>;\n private unnamedResultIndex = 0;\n private publicationErrors: WorkflowPublicationError[] = [];\n public output?: string | null;\n public unstableLogContent?: string | null;\n public errorInSetup?: Error;\n private interfaceAgent: Agent | null = null;\n public agentStatusTip?: string;\n public target?: MidsceneYamlScriptEnv;\n private actionSpace: DeviceAction[] = [];\n private scriptPath?: string;\n\n constructor(\n private script: MidsceneYamlScript,\n private setupAgent: (platform: T) => Promise<{\n agent: Agent;\n freeFn: FreeFn[];\n }>,\n public onTaskStatusChange?: (taskStatus: ScriptPlayerTaskStatus) => void,\n scriptPath?: string,\n private readonly abortSignal?: AbortSignal,\n ) {\n this.scriptPath = scriptPath;\n // Collection validates syntax but defers old task/Step errors until execution.\n collectLegacyYamlDocument(script, scriptPath);\n initializeLegacyYamlPlayerState(this);\n this.result = {};\n\n this.target =\n resolveWebTarget(script)?.target ||\n script.android ||\n script.ios ||\n script.harmony ||\n script.computer ||\n script.config;\n const outputConfig = resolveYamlOutputConfig(script);\n\n if (ifInBrowser || ifInWorker) {\n this.output = undefined;\n debug('output is undefined in browser or worker');\n } else if (outputConfig.output) {\n this.output = resolve(process.cwd(), outputConfig.output);\n debug('setting output by config.output', this.output);\n } else {\n const scriptName = this.scriptPath\n ? basename(this.scriptPath, '.yaml').replace(/\\.(ya?ml)$/i, '')\n : 'script';\n this.output = join(\n getMidsceneRunSubDir('output'),\n `${scriptName}-${uuid()}.json`,\n );\n debug('setting output by script path', this.output);\n }\n\n if (ifInBrowser || ifInWorker) {\n this.unstableLogContent = undefined;\n } else if (typeof outputConfig.unstableLogContent === 'string') {\n this.unstableLogContent = resolve(\n process.cwd(),\n outputConfig.unstableLogContent,\n );\n } else if (outputConfig.unstableLogContent === true) {\n this.unstableLogContent = join(\n getMidsceneRunSubDir('output'),\n 'unstableLogContent.json',\n );\n }\n\n this.taskStatusList = (script.tasks || []).map((task, taskIndex) => ({\n ...task,\n index: taskIndex,\n status: 'init',\n totalSteps: task.flow?.length || 0,\n }));\n }\n\n private setResult(key: string | undefined, value: any) {\n const keyToUse = key || this.unnamedResultIndex++;\n if (this.result[keyToUse]) {\n getDebug('yaml-player', { console: true })(\n `result key ${keyToUse} already exists, will overwrite`,\n );\n }\n this.result[keyToUse] = value;\n\n return this.flushResult();\n }\n\n private setPlayerStatus(status: ScriptPlayerStatusValue, error?: Error) {\n this.status = status;\n this.errorInSetup = error;\n }\n\n private notifyCurrentTaskStatusChange(taskIndex?: number) {\n const taskIndexToNotify =\n typeof taskIndex === 'number' ? taskIndex : this.currentTaskIndex;\n\n if (typeof taskIndexToNotify !== 'number') return;\n\n const taskStatus = this.taskStatusList[taskIndexToNotify];\n this.onTaskStatusChange?.(taskStatus);\n }\n\n private async setTaskStatus(\n index: number,\n statusValue: ScriptPlayerStatusValue,\n error?: Error,\n ) {\n this.taskStatusList[index].status = statusValue;\n if (error) this.taskStatusList[index].error = error;\n this.notifyCurrentTaskStatusChange(index);\n }\n\n private setTaskIndex(taskIndex: number) {\n this.currentTaskIndex = taskIndex;\n }\n\n private async flushResult() {\n if (this.output) {\n const output = resolve(process.cwd(), this.output);\n await this.publish(output, async () => {\n const outputDir = dirname(output);\n await mkdir(outputDir, { recursive: true });\n await writeFile(\n output,\n JSON.stringify(this.result || {}, undefined, 2),\n );\n });\n }\n }\n\n private async flushUnstableLogContent() {\n if (this.unstableLogContent) {\n const content = this.interfaceAgent?._unstableLogContent();\n const filePath = resolve(process.cwd(), this.unstableLogContent);\n await this.publish(filePath, async () => {\n const outputDir = dirname(filePath);\n await mkdir(outputDir, { recursive: true });\n await writeFile(filePath, JSON.stringify(content, null, 2));\n });\n }\n }\n\n private async publish(path: string, write: () => Promise<void>) {\n try {\n await write();\n } catch (cause) {\n const error = new WorkflowPublicationError('write-result', path, cause);\n this.publicationErrors.push(error);\n throw error;\n }\n }\n\n private createRuntime(agent: Agent) {\n return createLegacyYamlRuntime({\n agent,\n actionSpace: this.actionSpace,\n sourcePath: this.scriptPath,\n setResult: (key, value) => this.setResult(key, value),\n });\n }\n\n async playTask(taskStatus: ScriptPlayerTaskStatus, agent: Agent) {\n const { flow } = taskStatus;\n assert(flow, 'missing flow in task');\n const statusIndex = this.taskStatusList.indexOf(taskStatus);\n const declaredIndex = (\n taskStatus as ScriptPlayerTaskStatus & {\n index?: unknown;\n }\n ).index;\n const taskIndex =\n statusIndex >= 0\n ? statusIndex\n : typeof declaredIndex === 'number' && Number.isInteger(declaredIndex)\n ? declaredIndex\n : 0;\n\n const state = getLegacyYamlPlayerState(this);\n state.executionResult = await this.createRuntime(agent).runTask(\n taskStatus,\n taskIndex,\n {\n signal: this.abortSignal ?? currentYamlSignal(agent),\n onStepStart: (info) => {\n if (info.scope === 'case' && info.case.phase === 'steps') {\n taskStatus.currentStep = info.case.stepIndex;\n }\n },\n },\n );\n\n const outcome = state.executionResult.cases[0];\n if (!outcome || outcome.status === 'not-run') {\n throw new Error(`Task \"${taskStatus.name}\" did not run.`);\n }\n if (outcome.status === 'failed') throw legacyYamlOutcomeError(outcome);\n\n this.reportFile = agent.reportFile;\n await this.flushUnstableLogContent();\n }\n\n async run() {\n return runInYamlExecutionContext(() => this.runInContext());\n }\n\n private async runInContext() {\n const startedAt = new Date();\n const runId = uuid();\n const state = getLegacyYamlPlayerState(this);\n state.executionResult = undefined;\n state.executionRecord = undefined;\n this.publicationErrors = [];\n const { android, ios, harmony, computer } = this.script;\n const webEnv = resolveWebTarget(this.script)?.target;\n const androidEnv = android;\n const iosEnv = ios;\n const harmonyEnv = harmony;\n const computerEnv = computer;\n const platform =\n webEnv || androidEnv || iosEnv || harmonyEnv || computerEnv;\n\n this.setPlayerStatus('running');\n\n let agent: Agent | null = null;\n let freeFn: FreeFn[] = [];\n let setupError: unknown;\n let executionError: unknown;\n let cleanupError: unknown;\n let signal: AbortSignal | undefined;\n let session: ReturnType<typeof enterYamlExecution> | undefined;\n try {\n const { agent: newAgent, freeFn: newFreeFn } = await this.setupAgent(\n platform as T,\n );\n // Register ownership immediately: discovering actions can fail too.\n agent = newAgent;\n agent._prepareForTestRunner?.();\n freeFn = [...(newFreeFn || [])];\n session = enterYamlExecution(agent);\n signal = this.abortSignal ?? currentYamlSignal(agent);\n signal?.throwIfAborted();\n this.actionSpace = await agent.getActionSpace();\n const originalOnTaskStartTip = agent.onTaskStartTip;\n agent.onTaskStartTip = (tip) => {\n if (this.status === 'running') this.agentStatusTip = tip;\n originalOnTaskStartTip?.(tip);\n };\n freeFn.push({\n name: 'restore-agent-onTaskStartTip',\n fn: () => {\n if (agent) agent.onTaskStartTip = originalOnTaskStartTip;\n },\n });\n } catch (error) {\n // A rejected borrower must not close or publish into another run's Agent.\n if (error instanceof YamlExecutionOwnershipError) throw error;\n setupError = error;\n this.setPlayerStatus('error', error as Error);\n }\n this.interfaceAgent = agent;\n\n const document = collectLegacyYamlDocument(\n this.script,\n this.scriptPath ?? '<inline-yaml>',\n this.actionSpace,\n );\n const runtime =\n agent && !setupError ? this.createRuntime(agent) : undefined;\n try {\n if (runtime && agent) {\n state.executionResult = await runtime.runScript(this.script, {\n document,\n signal,\n createDocumentRunId: () => runId,\n onCaseStart: (collectedCase) => {\n const taskIndex = collectedCase.caseIndex;\n this.setTaskIndex(taskIndex);\n return this.setTaskStatus(taskIndex, 'running');\n },\n onStepStart: (info) => {\n if (info.scope !== 'case' || info.case.phase !== 'steps') return;\n const taskStatus = this.taskStatusList[info.case.caseIndex];\n if (taskStatus) taskStatus.currentStep = info.case.stepIndex;\n },\n onCaseOutcome: async (outcome) => {\n if (outcome.status === 'not-run') return;\n const taskIndex = outcome.caseIndex;\n const taskStatus = this.taskStatusList[taskIndex];\n assert(taskStatus, `missing YAML task at index ${taskIndex}`);\n\n this.reportFile = agent?.reportFile;\n if (outcome.status === 'success') {\n await this.setTaskStatus(taskIndex, 'done');\n await this.flushUnstableLogContent();\n return;\n }\n\n const error = legacyYamlOutcomeError(outcome);\n await this.setTaskStatus(taskIndex, 'error', error);\n },\n });\n const stoppedOnFailure = state.executionResult.cases.some(\n (outcome) =>\n outcome.status === 'failed' &&\n (!this.taskStatusList[outcome.caseIndex]?.continueOnError ||\n isActionReadinessError(legacyYamlOutcomeError(outcome))),\n );\n this.setPlayerStatus(\n stoppedOnFailure || signal?.aborted ? 'error' : 'done',\n );\n }\n } catch (error) {\n executionError = error;\n if (error instanceof WorkflowExecutionFailure)\n state.executionResult = error.result as WorkflowDocumentExecutionResult;\n this.setPlayerStatus('error', error as Error);\n }\n\n this.reportFile = agent?.reportFile;\n this.agentStatusTip = '';\n\n try {\n // A timeout settles the Runner before an uncooperative device action.\n // Never dispose its Agent while that action is still using it.\n if (session?.isRoot && agent) {\n await cleanupResources([agent], () => runFreeFnCleanup(freeFn), {\n owner: this,\n signal,\n onDeferredError: (error) =>\n getDebug('yaml-player', { console: true })(\n `Deferred YAML cleanup failed: ${String(error)}`,\n ),\n });\n } else await runFreeFnCleanup(freeFn);\n } catch (error) {\n cleanupError = error;\n this.setPlayerStatus(\n 'error',\n (setupError ?? executionError ?? error) as Error,\n );\n }\n\n const endedAt = new Date();\n const cleanupErrors =\n cleanupError instanceof AggregateError\n ? cleanupError.errors\n : cleanupError === undefined\n ? []\n : [cleanupError];\n state.executionRecord = createLegacyYamlExecutionRecord({\n runId,\n attemptIndex: 0,\n script: this.script,\n document,\n startedAt,\n endedAt,\n execution: state.executionResult,\n setupError,\n executionError,\n cleanupErrors,\n aborted: signal?.aborted ?? false,\n publicationErrors: this.publicationErrors,\n outputs: this.result,\n reportFile: agent?.reportFile,\n children: session?.children,\n });\n let reportError: unknown;\n if (!session || session.isRoot) {\n try {\n const published = await publishLegacyYamlReport({\n agent,\n record: state.executionRecord,\n runId,\n script: this.script,\n scriptPath: this.scriptPath,\n fallbackReportFileName: state.fallbackReportFileName,\n });\n this.reportFile = published.reportFile;\n state.executionRecord = published.record;\n } catch (error) {\n reportError = error;\n this.setPlayerStatus(\n 'error',\n (setupError ?? executionError ?? cleanupError ?? error) as Error,\n );\n state.executionRecord = Object.freeze({\n ...state.executionRecord,\n status: 'failed',\n reportError: error,\n });\n }\n }\n session?.finish(state.executionRecord);\n if (reportError) {\n const errors = [\n setupError,\n executionError,\n ...cleanupErrors,\n reportError,\n ].filter((error) => error !== undefined);\n throw errors.length === 1\n ? reportError\n : new AggregateError(\n errors,\n 'YAML execution/report finalization failed',\n );\n }\n if (executionError && cleanupError) {\n throw new AggregateError(\n [executionError, ...cleanupErrors],\n 'YAML execution and cleanup failed',\n );\n }\n if (executionError) throw executionError;\n if (cleanupError) throw cleanupError;\n }\n}\n"],"names":["debug","getDebug","ScriptPlayer","key","value","keyToUse","status","error","taskIndex","taskIndexToNotify","taskStatus","index","statusValue","output","resolve","process","outputDir","dirname","mkdir","writeFile","JSON","undefined","content","filePath","path","write","cause","WorkflowPublicationError","agent","createLegacyYamlRuntime","flow","assert","statusIndex","declaredIndex","Number","state","getLegacyYamlPlayerState","currentYamlSignal","info","outcome","Error","legacyYamlOutcomeError","runInYamlExecutionContext","startedAt","Date","runId","uuid","android","ios","harmony","computer","webEnv","resolveWebTarget","androidEnv","iosEnv","harmonyEnv","computerEnv","platform","freeFn","setupError","executionError","cleanupError","signal","session","newAgent","newFreeFn","enterYamlExecution","originalOnTaskStartTip","tip","YamlExecutionOwnershipError","document","collectLegacyYamlDocument","runtime","collectedCase","stoppedOnFailure","isActionReadinessError","WorkflowExecutionFailure","cleanupResources","runFreeFnCleanup","String","endedAt","cleanupErrors","AggregateError","createLegacyYamlExecutionRecord","reportError","published","publishLegacyYamlReport","Object","errors","script","setupAgent","onTaskStatusChange","scriptPath","abortSignal","initializeLegacyYamlPlayerState","outputConfig","resolveYamlOutputConfig","ifInBrowser","ifInWorker","scriptName","basename","join","getMidsceneRunSubDir","task"],"mappings":"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"}
1
+ {"version":3,"file":"yaml/player.mjs","sources":["../../../src/yaml/player.ts"],"sourcesContent":["import { mkdir, writeFile } from 'node:fs/promises';\nimport { basename, dirname, join, resolve } from 'node:path';\nimport { isActionReadinessError } from '@/agent/action-readiness';\nimport type { Agent } from '@/agent/agent';\nimport type {\n DeviceAction,\n FreeFn,\n MidsceneYamlScript,\n MidsceneYamlScriptEnv,\n ScriptPlayerStatusValue,\n ScriptPlayerTaskStatus,\n} from '@/types';\nimport { getMidsceneRunSubDir } from '@midscene/shared/common';\nimport { getDebug } from '@midscene/shared/logger';\nimport { assert, ifInBrowser, ifInWorker, uuid } from '@midscene/shared/utils';\nimport type { WorkflowDocumentExecutionResult } from '../test-runner';\nimport {\n WorkflowExecutionFailure,\n WorkflowPublicationError,\n} from '../test-runner/engine/execution-failure';\nimport { cleanupResources } from '../test-runner/engine/resource-operations';\nimport { runFreeFnCleanup } from './cleanup';\nimport {\n YamlExecutionOwnershipError,\n currentYamlSignal,\n enterYamlExecution,\n hasActiveYamlExecution,\n runInYamlExecutionContext,\n} from './execution-session';\nimport { createLegacyYamlExecutionRecord } from './legacy-yaml-execution-record';\nimport { publishLegacyYamlReport } from './legacy-yaml-report';\nimport {\n createLegacyYamlRuntime,\n legacyYamlOutcomeError,\n} from './legacy-yaml-runtime';\nimport {\n getLegacyYamlPlayerState,\n initializeLegacyYamlPlayerState,\n} from './player-state';\nimport { collectLegacyYamlDocument } from './test-runner-compat';\nimport { resolveWebTarget, resolveYamlOutputConfig } from './utils';\n\nconst debug = getDebug('yaml-player');\n\n/**\n * Compatibility facade for the legacy YAML API.\n *\n * Execution is delegated to the shared Runner kernel through\n * createLegacyYamlRuntime(). This class keeps the mutable status, result,\n * progress, output, and setup/cleanup behavior exposed by the old API.\n */\nexport class ScriptPlayer<T extends MidsceneYamlScriptEnv> {\n public currentTaskIndex?: number;\n public taskStatusList: ScriptPlayerTaskStatus[] = [];\n public status: ScriptPlayerStatusValue = 'init';\n public reportFile?: string | null;\n public result: Record<string, any>;\n private unnamedResultIndex = 0;\n private publicationErrors: WorkflowPublicationError[] = [];\n public output?: string | null;\n public unstableLogContent?: string | null;\n public errorInSetup?: Error;\n private interfaceAgent: Agent | null = null;\n public agentStatusTip?: string;\n public target?: MidsceneYamlScriptEnv;\n private actionSpace: DeviceAction[] = [];\n private scriptPath?: string;\n\n constructor(\n private script: MidsceneYamlScript,\n private setupAgent: (platform: T) => Promise<{\n agent: Agent;\n freeFn: FreeFn[];\n }>,\n public onTaskStatusChange?: (taskStatus: ScriptPlayerTaskStatus) => void,\n scriptPath?: string,\n private readonly abortSignal?: AbortSignal,\n ) {\n this.scriptPath = scriptPath;\n // Collection validates syntax but defers old task/Step errors until execution.\n collectLegacyYamlDocument(script, scriptPath);\n initializeLegacyYamlPlayerState(this);\n this.result = {};\n\n this.target =\n resolveWebTarget(script)?.target ||\n script.android ||\n script.ios ||\n script.harmony ||\n script.computer ||\n script.config;\n const outputConfig = resolveYamlOutputConfig(script);\n\n if (ifInBrowser || ifInWorker) {\n this.output = undefined;\n debug('output is undefined in browser or worker');\n } else if (outputConfig.output) {\n this.output = resolve(process.cwd(), outputConfig.output);\n debug('setting output by config.output', this.output);\n } else {\n const scriptName = this.scriptPath\n ? basename(this.scriptPath, '.yaml').replace(/\\.(ya?ml)$/i, '')\n : 'script';\n this.output = join(\n getMidsceneRunSubDir('output'),\n `${scriptName}-${uuid()}.json`,\n );\n debug('setting output by script path', this.output);\n }\n\n if (ifInBrowser || ifInWorker) {\n this.unstableLogContent = undefined;\n } else if (typeof outputConfig.unstableLogContent === 'string') {\n this.unstableLogContent = resolve(\n process.cwd(),\n outputConfig.unstableLogContent,\n );\n } else if (outputConfig.unstableLogContent === true) {\n this.unstableLogContent = join(\n getMidsceneRunSubDir('output'),\n 'unstableLogContent.json',\n );\n }\n\n this.taskStatusList = (script.tasks || []).map((task, taskIndex) => ({\n ...task,\n index: taskIndex,\n status: 'init',\n totalSteps: task.flow?.length || 0,\n }));\n }\n\n private setResult(key: string | undefined, value: any) {\n const keyToUse = key || this.unnamedResultIndex++;\n if (this.result[keyToUse]) {\n getDebug('yaml-player', { console: true })(\n `result key ${keyToUse} already exists, will overwrite`,\n );\n }\n this.result[keyToUse] = value;\n\n return this.flushResult();\n }\n\n private setPlayerStatus(status: ScriptPlayerStatusValue, error?: Error) {\n this.status = status;\n this.errorInSetup = error;\n }\n\n private notifyCurrentTaskStatusChange(taskIndex?: number) {\n const taskIndexToNotify =\n typeof taskIndex === 'number' ? taskIndex : this.currentTaskIndex;\n\n if (typeof taskIndexToNotify !== 'number') return;\n\n const taskStatus = this.taskStatusList[taskIndexToNotify];\n this.onTaskStatusChange?.(taskStatus);\n }\n\n private async setTaskStatus(\n index: number,\n statusValue: ScriptPlayerStatusValue,\n error?: Error,\n ) {\n this.taskStatusList[index].status = statusValue;\n if (error) this.taskStatusList[index].error = error;\n this.notifyCurrentTaskStatusChange(index);\n }\n\n private setTaskIndex(taskIndex: number) {\n this.currentTaskIndex = taskIndex;\n }\n\n private async flushResult() {\n if (this.output) {\n const output = resolve(process.cwd(), this.output);\n await this.publish(output, async () => {\n const outputDir = dirname(output);\n await mkdir(outputDir, { recursive: true });\n await writeFile(\n output,\n JSON.stringify(this.result || {}, undefined, 2),\n );\n });\n }\n }\n\n private async flushUnstableLogContent() {\n if (this.unstableLogContent) {\n const content = this.interfaceAgent?._unstableLogContent();\n const filePath = resolve(process.cwd(), this.unstableLogContent);\n await this.publish(filePath, async () => {\n const outputDir = dirname(filePath);\n await mkdir(outputDir, { recursive: true });\n await writeFile(filePath, JSON.stringify(content, null, 2));\n });\n }\n }\n\n private async publish(path: string, write: () => Promise<void>) {\n try {\n await write();\n } catch (cause) {\n const error = new WorkflowPublicationError('write-result', path, cause);\n this.publicationErrors.push(error);\n throw error;\n }\n }\n\n private createRuntime(agent: Agent) {\n return createLegacyYamlRuntime({\n agent,\n actionSpace: this.actionSpace,\n sourcePath: this.scriptPath,\n setResult: (key, value) => this.setResult(key, value),\n });\n }\n\n async playTask(taskStatus: ScriptPlayerTaskStatus, agent: Agent) {\n const { flow } = taskStatus;\n assert(flow, 'missing flow in task');\n const statusIndex = this.taskStatusList.indexOf(taskStatus);\n const declaredIndex = (\n taskStatus as ScriptPlayerTaskStatus & {\n index?: unknown;\n }\n ).index;\n const taskIndex =\n statusIndex >= 0\n ? statusIndex\n : typeof declaredIndex === 'number' && Number.isInteger(declaredIndex)\n ? declaredIndex\n : 0;\n\n const state = getLegacyYamlPlayerState(this);\n state.executionResult = await this.createRuntime(agent).runTask(\n taskStatus,\n taskIndex,\n {\n signal: this.abortSignal ?? currentYamlSignal(agent),\n onStepStart: (info) => {\n if (info.scope === 'case' && info.case.phase === 'steps') {\n taskStatus.currentStep = info.case.stepIndex;\n }\n },\n },\n );\n\n const outcome = state.executionResult.cases[0];\n if (!outcome || outcome.status === 'not-run') {\n throw new Error(`Task \"${taskStatus.name}\" did not run.`);\n }\n if (outcome.status === 'failed') throw legacyYamlOutcomeError(outcome);\n\n this.reportFile = agent.reportFile;\n await this.flushUnstableLogContent();\n }\n\n async run() {\n return runInYamlExecutionContext(() => this.runInContext());\n }\n\n private async runInContext() {\n const startedAt = new Date();\n const runId = uuid();\n const state = getLegacyYamlPlayerState(this);\n state.executionResult = undefined;\n state.executionRecord = undefined;\n this.publicationErrors = [];\n const { android, ios, harmony, computer } = this.script;\n const webEnv = resolveWebTarget(this.script)?.target;\n const androidEnv = android;\n const iosEnv = ios;\n const harmonyEnv = harmony;\n const computerEnv = computer;\n const platform =\n webEnv || androidEnv || iosEnv || harmonyEnv || computerEnv;\n\n this.setPlayerStatus('running');\n\n let agent: Agent | null = null;\n let freeFn: FreeFn[] = [];\n let setupError: unknown;\n let executionError: unknown;\n let cleanupError: unknown;\n let signal: AbortSignal | undefined;\n let session: ReturnType<typeof enterYamlExecution> | undefined;\n try {\n const { agent: newAgent, freeFn: newFreeFn } = await this.setupAgent(\n platform as T,\n );\n // Register ownership immediately: discovering actions can fail too.\n agent = newAgent;\n session = enterYamlExecution(agent);\n freeFn = [...(newFreeFn || [])];\n agent._prepareForTestRunner?.();\n signal = this.abortSignal ?? currentYamlSignal(agent);\n signal?.throwIfAborted();\n this.actionSpace = await agent.getActionSpace();\n const originalOnTaskStartTip = agent.onTaskStartTip;\n agent.onTaskStartTip = (tip) => {\n if (this.status === 'running') this.agentStatusTip = tip;\n originalOnTaskStartTip?.(tip);\n };\n freeFn.push({\n name: 'restore-agent-onTaskStartTip',\n fn: () => {\n if (agent) agent.onTaskStartTip = originalOnTaskStartTip;\n },\n });\n } catch (error) {\n // A rejected borrower must not close or publish into another run's Agent.\n if (error instanceof YamlExecutionOwnershipError) throw error;\n setupError = error;\n this.setPlayerStatus('error', error as Error);\n }\n this.interfaceAgent = agent;\n\n const document = collectLegacyYamlDocument(\n this.script,\n this.scriptPath ?? '<inline-yaml>',\n this.actionSpace,\n );\n const runtime =\n agent && !setupError ? this.createRuntime(agent) : undefined;\n try {\n if (runtime && agent) {\n state.executionResult = await runtime.runScript(this.script, {\n document,\n signal,\n createDocumentRunId: () => runId,\n onCaseStart: (collectedCase) => {\n const taskIndex = collectedCase.caseIndex;\n this.setTaskIndex(taskIndex);\n return this.setTaskStatus(taskIndex, 'running');\n },\n onStepStart: (info) => {\n if (info.scope !== 'case' || info.case.phase !== 'steps') return;\n const taskStatus = this.taskStatusList[info.case.caseIndex];\n if (taskStatus) taskStatus.currentStep = info.case.stepIndex;\n },\n onCaseOutcome: async (outcome) => {\n if (outcome.status === 'not-run') return;\n const taskIndex = outcome.caseIndex;\n const taskStatus = this.taskStatusList[taskIndex];\n assert(taskStatus, `missing YAML task at index ${taskIndex}`);\n\n this.reportFile = agent?.reportFile;\n if (outcome.status === 'success') {\n await this.setTaskStatus(taskIndex, 'done');\n await this.flushUnstableLogContent();\n return;\n }\n\n const error = legacyYamlOutcomeError(outcome);\n await this.setTaskStatus(taskIndex, 'error', error);\n },\n });\n const stoppedOnFailure = state.executionResult.cases.some(\n (outcome) =>\n outcome.status === 'failed' &&\n (!this.taskStatusList[outcome.caseIndex]?.continueOnError ||\n isActionReadinessError(legacyYamlOutcomeError(outcome))),\n );\n this.setPlayerStatus(\n stoppedOnFailure || signal?.aborted ? 'error' : 'done',\n );\n }\n } catch (error) {\n executionError = error;\n if (error instanceof WorkflowExecutionFailure)\n state.executionResult = error.result as WorkflowDocumentExecutionResult;\n this.setPlayerStatus('error', error as Error);\n }\n\n this.reportFile = agent?.reportFile;\n this.agentStatusTip = '';\n\n try {\n // A timeout settles the Runner before an uncooperative device action.\n // Never dispose its Agent while that action is still using it.\n if (session?.isRoot && agent) {\n await cleanupResources([agent], () => runFreeFnCleanup(freeFn), {\n owner: this,\n signal,\n onDeferredError: (error) =>\n getDebug('yaml-player', { console: true })(\n `Deferred YAML cleanup failed: ${String(error)}`,\n ),\n });\n } else await runFreeFnCleanup(freeFn);\n } catch (error) {\n cleanupError = error;\n this.setPlayerStatus(\n 'error',\n (setupError ?? executionError ?? error) as Error,\n );\n }\n\n const endedAt = new Date();\n const cleanupErrors =\n cleanupError instanceof AggregateError\n ? cleanupError.errors\n : cleanupError === undefined\n ? []\n : [cleanupError];\n state.executionRecord = createLegacyYamlExecutionRecord({\n runId,\n attemptIndex: 0,\n script: this.script,\n document,\n startedAt,\n endedAt,\n execution: state.executionResult,\n setupError,\n executionError,\n cleanupErrors,\n aborted: signal?.aborted ?? false,\n publicationErrors: this.publicationErrors,\n outputs: this.result,\n reportFile: agent?.reportFile,\n children: session?.children,\n });\n let reportError: unknown;\n if (!session || session.isRoot) {\n try {\n const published = await publishLegacyYamlReport({\n agent,\n record: state.executionRecord,\n runId,\n script: this.script,\n scriptPath: this.scriptPath,\n fallbackReportFileName: state.fallbackReportFileName,\n });\n this.reportFile = published.reportFile;\n state.executionRecord = published.record;\n } catch (error) {\n reportError = error;\n this.setPlayerStatus(\n 'error',\n (setupError ?? executionError ?? cleanupError ?? error) as Error,\n );\n state.executionRecord = Object.freeze({\n ...state.executionRecord,\n status: 'failed',\n reportError: error,\n });\n }\n }\n session?.finish(state.executionRecord);\n // destroy() defers report finalization while YAML owns the Agent. Publish\n // cleanup outcomes and source snapshots before releasing its executions.\n if (agent?.destroyed && !hasActiveYamlExecution(agent)) {\n try {\n await agent.finalizeReport();\n } catch (error) {\n reportError = reportError\n ? new AggregateError(\n [reportError, error],\n 'YAML report publication failed',\n )\n : error;\n this.setPlayerStatus('error', reportError as Error);\n state.executionRecord = Object.freeze({\n ...state.executionRecord,\n status: 'failed',\n reportError,\n });\n }\n }\n if (reportError) {\n const errors = [\n setupError,\n executionError,\n ...cleanupErrors,\n reportError,\n ].filter((error) => error !== undefined);\n throw errors.length === 1\n ? reportError\n : new AggregateError(\n errors,\n 'YAML execution/report finalization failed',\n );\n }\n if (executionError && cleanupError) {\n throw new AggregateError(\n [executionError, ...cleanupErrors],\n 'YAML execution and cleanup failed',\n );\n }\n if (executionError) throw executionError;\n if (cleanupError) throw cleanupError;\n }\n}\n"],"names":["debug","getDebug","ScriptPlayer","key","value","keyToUse","status","error","taskIndex","taskIndexToNotify","taskStatus","index","statusValue","output","resolve","process","outputDir","dirname","mkdir","writeFile","JSON","undefined","content","filePath","path","write","cause","WorkflowPublicationError","agent","createLegacyYamlRuntime","flow","assert","statusIndex","declaredIndex","Number","state","getLegacyYamlPlayerState","currentYamlSignal","info","outcome","Error","legacyYamlOutcomeError","runInYamlExecutionContext","startedAt","Date","runId","uuid","android","ios","harmony","computer","webEnv","resolveWebTarget","androidEnv","iosEnv","harmonyEnv","computerEnv","platform","freeFn","setupError","executionError","cleanupError","signal","session","newAgent","newFreeFn","enterYamlExecution","originalOnTaskStartTip","tip","YamlExecutionOwnershipError","document","collectLegacyYamlDocument","runtime","collectedCase","stoppedOnFailure","isActionReadinessError","WorkflowExecutionFailure","cleanupResources","runFreeFnCleanup","String","endedAt","cleanupErrors","AggregateError","createLegacyYamlExecutionRecord","reportError","published","publishLegacyYamlReport","Object","hasActiveYamlExecution","errors","script","setupAgent","onTaskStatusChange","scriptPath","abortSignal","initializeLegacyYamlPlayerState","outputConfig","resolveYamlOutputConfig","ifInBrowser","ifInWorker","scriptName","basename","join","getMidsceneRunSubDir","task"],"mappings":"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"}