@midscene/core 1.17.5 → 1.17.7
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.
- package/dist/es/agent/agent-report-manager.mjs +1 -1
- package/dist/es/agent/agent-report-manager.mjs.map +1 -1
- package/dist/es/agent/utils.mjs +1 -1
- package/dist/es/ai-model/model-adapter/locate-prompt-order.mjs +80 -0
- package/dist/es/ai-model/model-adapter/locate-prompt-order.mjs.map +1 -0
- package/dist/es/ai-model/model-adapter/locate.mjs +2 -1
- package/dist/es/ai-model/model-adapter/locate.mjs.map +1 -1
- package/dist/es/ai-model/models/jev/locate.mjs +2 -12
- package/dist/es/ai-model/models/jev/locate.mjs.map +1 -1
- package/dist/es/ai-model/service-caller/call-ai.mjs +4 -1
- package/dist/es/ai-model/service-caller/call-ai.mjs.map +1 -1
- package/dist/es/ai-model/service-caller/openai/siwc/authorization.mjs +4 -3
- package/dist/es/ai-model/service-caller/openai/siwc/authorization.mjs.map +1 -1
- package/dist/es/ai-model/service-caller/openai/siwc/network.mjs +36 -0
- package/dist/es/ai-model/service-caller/openai/siwc/network.mjs.map +1 -0
- package/dist/es/ai-model/service-caller/openai/siwc/refresh.mjs +5 -3
- package/dist/es/ai-model/service-caller/openai/siwc/refresh.mjs.map +1 -1
- package/dist/es/ai-model/service-caller/openai/siwc/token-manager.mjs +7 -4
- package/dist/es/ai-model/service-caller/openai/siwc/token-manager.mjs.map +1 -1
- package/dist/es/ai-model/shared/json.mjs +6 -2
- package/dist/es/ai-model/shared/json.mjs.map +1 -1
- package/dist/es/ai-model/workflows/grounding/locate.mjs +1 -1
- package/dist/es/ai-model/workflows/grounding/locate.mjs.map +1 -1
- package/dist/es/ai-model/workflows/grounding/section-locate.mjs +1 -1
- package/dist/es/ai-model/workflows/grounding/section-locate.mjs.map +1 -1
- package/dist/es/ai-model/workflows/grounding/utils.mjs +8 -26
- package/dist/es/ai-model/workflows/grounding/utils.mjs.map +1 -1
- package/dist/es/dump/report-image-export.mjs +58 -0
- package/dist/es/dump/report-image-export.mjs.map +1 -0
- package/dist/es/dump/screenshot-store.mjs +5 -0
- package/dist/es/dump/screenshot-store.mjs.map +1 -1
- package/dist/es/report-cli.mjs +13 -29
- package/dist/es/report-cli.mjs.map +1 -1
- package/dist/es/report-generator.mjs +22 -8
- package/dist/es/report-generator.mjs.map +1 -1
- package/dist/es/report-html-template.mjs +1 -1
- package/dist/es/report-markdown.mjs +50 -53
- package/dist/es/report-markdown.mjs.map +1 -1
- package/dist/es/report.mjs +8 -24
- package/dist/es/report.mjs.map +1 -1
- package/dist/es/siwc.mjs +4 -0
- package/dist/es/task-runner.mjs +7 -2
- package/dist/es/task-runner.mjs.map +1 -1
- package/dist/es/utils.mjs +1 -1
- package/dist/lib/agent/agent-report-manager.js +1 -1
- package/dist/lib/agent/agent-report-manager.js.map +1 -1
- package/dist/lib/agent/utils.js +1 -1
- package/dist/lib/ai-model/model-adapter/locate-prompt-order.js +117 -0
- package/dist/lib/ai-model/model-adapter/locate-prompt-order.js.map +1 -0
- package/dist/lib/ai-model/model-adapter/locate.js +2 -1
- package/dist/lib/ai-model/model-adapter/locate.js.map +1 -1
- package/dist/lib/ai-model/models/jev/locate.js +2 -12
- package/dist/lib/ai-model/models/jev/locate.js.map +1 -1
- package/dist/lib/ai-model/service-caller/call-ai.js +4 -1
- package/dist/lib/ai-model/service-caller/call-ai.js.map +1 -1
- package/dist/lib/ai-model/service-caller/openai/siwc/authorization.js +3 -2
- package/dist/lib/ai-model/service-caller/openai/siwc/authorization.js.map +1 -1
- package/dist/lib/ai-model/service-caller/openai/siwc/network.js +73 -0
- package/dist/lib/ai-model/service-caller/openai/siwc/network.js.map +1 -0
- package/dist/lib/ai-model/service-caller/openai/siwc/refresh.js +4 -2
- package/dist/lib/ai-model/service-caller/openai/siwc/refresh.js.map +1 -1
- package/dist/lib/ai-model/service-caller/openai/siwc/token-manager.js +7 -4
- package/dist/lib/ai-model/service-caller/openai/siwc/token-manager.js.map +1 -1
- package/dist/lib/ai-model/shared/json.js +6 -2
- package/dist/lib/ai-model/shared/json.js.map +1 -1
- package/dist/lib/ai-model/workflows/grounding/locate.js +1 -1
- package/dist/lib/ai-model/workflows/grounding/locate.js.map +1 -1
- package/dist/lib/ai-model/workflows/grounding/section-locate.js +1 -1
- package/dist/lib/ai-model/workflows/grounding/section-locate.js.map +1 -1
- package/dist/lib/ai-model/workflows/grounding/utils.js +8 -26
- package/dist/lib/ai-model/workflows/grounding/utils.js.map +1 -1
- package/dist/lib/dump/report-image-export.js +92 -0
- package/dist/lib/dump/report-image-export.js.map +1 -0
- package/dist/lib/dump/screenshot-store.js +5 -0
- package/dist/lib/dump/screenshot-store.js.map +1 -1
- package/dist/lib/report-cli.js +12 -28
- package/dist/lib/report-cli.js.map +1 -1
- package/dist/lib/report-generator.js +22 -8
- package/dist/lib/report-generator.js.map +1 -1
- package/dist/lib/report-html-template.js +1 -1
- package/dist/lib/report-markdown.js +50 -53
- package/dist/lib/report-markdown.js.map +1 -1
- package/dist/lib/report.js +6 -22
- package/dist/lib/report.js.map +1 -1
- package/dist/lib/siwc.js +52 -0
- package/dist/lib/siwc.js.map +1 -0
- package/dist/lib/task-runner.js +7 -2
- package/dist/lib/task-runner.js.map +1 -1
- package/dist/lib/utils.js +1 -1
- package/dist/types/ai-model/model-adapter/locate-prompt-order.d.ts +24 -0
- package/dist/types/ai-model/model-adapter/locate-prompt-order.d.ts.map +1 -0
- package/dist/types/ai-model/model-adapter/locate.d.ts.map +1 -1
- package/dist/types/ai-model/model-adapter/types.d.ts +9 -3
- package/dist/types/ai-model/model-adapter/types.d.ts.map +1 -1
- package/dist/types/ai-model/models/jev/locate.d.ts.map +1 -1
- package/dist/types/ai-model/service-caller/openai/siwc/authorization.d.ts.map +1 -1
- package/dist/types/ai-model/service-caller/openai/siwc/network.d.ts +8 -0
- package/dist/types/ai-model/service-caller/openai/siwc/network.d.ts.map +1 -0
- package/dist/types/ai-model/service-caller/openai/siwc/refresh.d.ts +1 -1
- package/dist/types/ai-model/service-caller/openai/siwc/refresh.d.ts.map +1 -1
- package/dist/types/ai-model/service-caller/openai/siwc/token-manager.d.ts +2 -1
- package/dist/types/ai-model/service-caller/openai/siwc/token-manager.d.ts.map +1 -1
- package/dist/types/ai-model/shared/json.d.ts +4 -15
- package/dist/types/ai-model/shared/json.d.ts.map +1 -1
- package/dist/types/ai-model/workflows/grounding/utils.d.ts +4 -9
- package/dist/types/ai-model/workflows/grounding/utils.d.ts.map +1 -1
- package/dist/types/dump/report-image-export.d.ts +12 -0
- package/dist/types/dump/report-image-export.d.ts.map +1 -0
- package/dist/types/dump/screenshot-store.d.ts +2 -0
- package/dist/types/dump/screenshot-store.d.ts.map +1 -1
- package/dist/types/report-cli.d.ts.map +1 -1
- package/dist/types/report-generator.d.ts +4 -2
- package/dist/types/report-generator.d.ts.map +1 -1
- package/dist/types/report-markdown.d.ts +4 -2
- package/dist/types/report-markdown.d.ts.map +1 -1
- package/dist/types/report.d.ts.map +1 -1
- package/dist/types/siwc.d.ts +5 -0
- package/dist/types/siwc.d.ts.map +1 -0
- package/dist/types/task-runner.d.ts.map +1 -1
- package/package.json +10 -2
|
@@ -211,54 +211,52 @@ function restoredSourceRef(screenshot) {
|
|
|
211
211
|
}
|
|
212
212
|
function screenshotAttachment(screenshot, screenshotBaseDir, executionIndex, taskIndex, options) {
|
|
213
213
|
const markdownLabel = options?.label || `task-${taskIndex + 1}`;
|
|
214
|
+
const result = (attachment)=>{
|
|
215
|
+
attachment.suggestedFileName = options?.resolveScreenshotFileName?.(attachment) ?? attachment.suggestedFileName;
|
|
216
|
+
return {
|
|
217
|
+
markdown: `\n`,
|
|
218
|
+
attachment
|
|
219
|
+
};
|
|
220
|
+
};
|
|
214
221
|
if (ScreenshotItem.isScreenshotItem(screenshot)) {
|
|
215
222
|
const ext = screenshot.extension;
|
|
216
223
|
const suggestedFileName = `execution-${executionIndex + 1}-task-${taskIndex + 1}-${screenshot.id}.${ext}`;
|
|
217
|
-
return {
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
base64Data: tryExtractBase64(screenshot)
|
|
226
|
-
}
|
|
227
|
-
};
|
|
224
|
+
return result({
|
|
225
|
+
id: screenshot.id,
|
|
226
|
+
suggestedFileName,
|
|
227
|
+
mimeType: `image/${'jpeg' === ext ? 'jpeg' : 'png'}`,
|
|
228
|
+
executionIndex,
|
|
229
|
+
taskIndex,
|
|
230
|
+
base64Data: tryExtractBase64(screenshot)
|
|
231
|
+
});
|
|
228
232
|
}
|
|
229
233
|
const ref = normalizeScreenshotRef(screenshot);
|
|
230
234
|
if (ref) {
|
|
231
235
|
const ext = imageRefFileExtension(ref);
|
|
232
236
|
const suggestedFileName = `execution-${executionIndex + 1}-task-${taskIndex + 1}-${ref.id}.${ext}`;
|
|
233
|
-
return {
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
base64Data: tryExtractBase64(screenshot)
|
|
243
|
-
}
|
|
244
|
-
};
|
|
237
|
+
return result({
|
|
238
|
+
id: ref.id,
|
|
239
|
+
suggestedFileName,
|
|
240
|
+
sourceRef: ref,
|
|
241
|
+
mimeType: ref.mimeType,
|
|
242
|
+
executionIndex,
|
|
243
|
+
taskIndex,
|
|
244
|
+
base64Data: tryExtractBase64(screenshot)
|
|
245
|
+
});
|
|
245
246
|
}
|
|
246
247
|
const sourceRef = restoredSourceRef(screenshot);
|
|
247
248
|
if (sourceRef) {
|
|
248
249
|
const ext = imageRefFileExtension(sourceRef);
|
|
249
250
|
const suggestedFileName = `execution-${executionIndex + 1}-task-${taskIndex + 1}-${sourceRef.id}.${ext}`;
|
|
250
|
-
return {
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
base64Data: tryExtractBase64(screenshot)
|
|
260
|
-
}
|
|
261
|
-
};
|
|
251
|
+
return result({
|
|
252
|
+
id: sourceRef.id,
|
|
253
|
+
suggestedFileName,
|
|
254
|
+
sourceRef,
|
|
255
|
+
mimeType: sourceRef.mimeType,
|
|
256
|
+
executionIndex,
|
|
257
|
+
taskIndex,
|
|
258
|
+
base64Data: tryExtractBase64(screenshot)
|
|
259
|
+
});
|
|
262
260
|
}
|
|
263
261
|
const base64 = tryExtractBase64(screenshot);
|
|
264
262
|
if (base64) {
|
|
@@ -266,24 +264,21 @@ function screenshotAttachment(screenshot, screenshotBaseDir, executionIndex, tas
|
|
|
266
264
|
const idSuffix = options?.fallbackIdSuffix ? `-${options.fallbackIdSuffix}` : '';
|
|
267
265
|
const id = `restored-${executionIndex + 1}-${taskIndex + 1}${idSuffix}`;
|
|
268
266
|
const suggestedFileName = `execution-${executionIndex + 1}-task-${taskIndex + 1}-${id}.${ext}`;
|
|
269
|
-
return {
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
base64Data: base64
|
|
278
|
-
}
|
|
279
|
-
};
|
|
267
|
+
return result({
|
|
268
|
+
id,
|
|
269
|
+
suggestedFileName,
|
|
270
|
+
mimeType: `image/${ext}`,
|
|
271
|
+
executionIndex,
|
|
272
|
+
taskIndex,
|
|
273
|
+
base64Data: base64
|
|
274
|
+
});
|
|
280
275
|
}
|
|
281
276
|
throw new Error(`executionToMarkdown: missing screenshot for execution #${executionIndex + 1} task #${taskIndex + 1}`);
|
|
282
277
|
}
|
|
283
278
|
function imageLabelSuffix(value) {
|
|
284
279
|
return value.toLowerCase().replace(/[^a-z0-9._-]+/g, '-').replace(/-+/g, '-').replace(/^-|-$/g, '') || 'screenshot';
|
|
285
280
|
}
|
|
286
|
-
function screenshotsMarkdownSection(task, screenshotBaseDir, executionIndex, taskIndex) {
|
|
281
|
+
function screenshotsMarkdownSection(task, screenshotBaseDir, executionIndex, taskIndex, resolveScreenshotFileName) {
|
|
287
282
|
const lines = [
|
|
288
283
|
'',
|
|
289
284
|
'### Screenshots'
|
|
@@ -293,11 +288,12 @@ function screenshotsMarkdownSection(task, screenshotBaseDir, executionIndex, tas
|
|
|
293
288
|
if (task.uiContext?.screenshot) {
|
|
294
289
|
const imageResult = screenshotAttachment(task.uiContext.screenshot, screenshotBaseDir, executionIndex, taskIndex, {
|
|
295
290
|
fallbackIdSuffix: 'ui-context',
|
|
296
|
-
label: `task-${taskIndex + 1}-ui-context
|
|
291
|
+
label: `task-${taskIndex + 1}-ui-context`,
|
|
292
|
+
resolveScreenshotFileName
|
|
297
293
|
});
|
|
298
294
|
const time = resolveTaskTiming(task);
|
|
299
295
|
screenshotIndex += 1;
|
|
300
|
-
lines.push(`- #${screenshotIndex} type=ui-context, ts=${formatTime(time.start)}, timing=ui-context`);
|
|
296
|
+
lines.push(`- #${screenshotIndex} type=ui-context, ts=${formatTime(time.start)}, timing=ui-context, id=${imageResult.attachment.id}`);
|
|
301
297
|
lines.push(imageResult.markdown);
|
|
302
298
|
attachments.push(imageResult.attachment);
|
|
303
299
|
}
|
|
@@ -306,11 +302,12 @@ function screenshotsMarkdownSection(task, screenshotBaseDir, executionIndex, tas
|
|
|
306
302
|
const descriptionText = item.description ? `, description=${item.description}` : '';
|
|
307
303
|
const timing = item.timing || 'N/A';
|
|
308
304
|
screenshotIndex += 1;
|
|
309
|
-
lines.push(`- #${screenshotIndex} type=${item.type}, ts=${formatTime(item.ts)}, timing=${timing}${descriptionText}`);
|
|
310
305
|
const imageResult = screenshotAttachment(item.screenshot, screenshotBaseDir, executionIndex, taskIndex, {
|
|
311
306
|
fallbackIdSuffix: `recorder-${recorderIndex + 1}`,
|
|
312
|
-
label: `task-${taskIndex + 1}-${imageLabelSuffix(timing)}
|
|
307
|
+
label: `task-${taskIndex + 1}-${imageLabelSuffix(timing)}`,
|
|
308
|
+
resolveScreenshotFileName
|
|
313
309
|
});
|
|
310
|
+
lines.push(`- #${screenshotIndex} type=${item.type}, ts=${formatTime(item.ts)}, timing=${timing}${descriptionText}, id=${imageResult.attachment.id}`);
|
|
314
311
|
lines.push(imageResult.markdown);
|
|
315
312
|
attachments.push(imageResult.attachment);
|
|
316
313
|
});
|
|
@@ -371,7 +368,7 @@ function renderExecution(executionRaw, executionIndex, options) {
|
|
|
371
368
|
appendJsonSection(lines, 'Log', task.log);
|
|
372
369
|
appendTextSection(lines, 'Thought', task.thought);
|
|
373
370
|
appendTextSection(lines, 'Reasoning Content', task.reasoning_content);
|
|
374
|
-
const screenshotsSection = screenshotsMarkdownSection(task, screenshotBaseDir, executionIndex, taskIndex);
|
|
371
|
+
const screenshotsSection = screenshotsMarkdownSection(task, screenshotBaseDir, executionIndex, taskIndex, options?.resolveScreenshotFileName);
|
|
375
372
|
if (screenshotsSection.lines.length) {
|
|
376
373
|
lines.push(...screenshotsSection.lines);
|
|
377
374
|
attachments.push(...screenshotsSection.attachments);
|
|
@@ -388,7 +385,7 @@ function executionToMarkdown(execution, options) {
|
|
|
388
385
|
function reportToMarkdown(report, options) {
|
|
389
386
|
const reportDump = toReportDump(report);
|
|
390
387
|
const executionResults = reportDump.executions.map((execution, index)=>{
|
|
391
|
-
const rendered = renderExecution(execution, index);
|
|
388
|
+
const rendered = renderExecution(execution, index, options);
|
|
392
389
|
return {
|
|
393
390
|
markdown: rendered.markdown,
|
|
394
391
|
attachments: rendered.attachments
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"report-markdown.mjs","sources":["../../src/report-markdown.ts"],"sourcesContent":["import { extractInsightParam, paramStr, typeStr } from '@/agent/ui-utils';\nimport { ScreenshotItem } from '@/screenshot-item';\nimport type {\n AIUsageInfo,\n ExecutionDump,\n ExecutionTask,\n IExecutionDump,\n IReportActionDump,\n ModelBrief,\n ReportActionDump,\n} from '@/types';\nimport type { ScreenshotRef } from './dump/screenshot-store';\nimport {\n imageRefFileExtension,\n normalizeScreenshotRef,\n} from './dump/screenshot-store';\nimport { collectReportSummary } from './report-stats';\n\nconst screenshotDataUrlPattern =\n /^data:image\\/(png|jpeg|jpg);base64,([\\s\\S]*)$/i;\nconst rawBase64BodyPattern = /^[a-zA-Z0-9+/=\\s]+$/;\nconst jsonContextMaxStringLength = 12_000;\n\ntype ExecutionTaskWithExtraUsage = ExecutionTask & {\n searchAreaUsage?: AIUsageInfo;\n reasoning_content?: string;\n};\n\nexport interface MarkdownAttachment {\n id: string;\n /**\n * Stable, prefixed file name for the exported copy. The markdown image link\n * always points at `${screenshotBaseDir}/${suggestedFileName}`, so consumers\n * write the screenshot under this name to keep links in sync. See #2392.\n */\n suggestedFileName: string;\n mimeType?: string;\n /**\n * Reference to the screenshot in the source report, used to locate the\n * original bytes when copying them to the exported name. Absent for in-memory\n * screenshots, which carry their data in `base64Data` instead.\n */\n sourceRef?: ScreenshotRef;\n executionIndex: number;\n taskIndex: number;\n /** Populated when screenshot data is available in memory (e.g. browser context). */\n base64Data?: string;\n}\n\nexport interface ExecutionMarkdownOptions {\n screenshotBaseDir?: string;\n}\n\nexport interface ReportMarkdownOptions {\n /** Used only when the report has no recorded task timestamps. */\n wallTimeFallbackMs?: number;\n}\n\nexport interface ExecutionMarkdownResult {\n markdown: string;\n attachments: MarkdownAttachment[];\n}\n\nexport interface ReportMarkdownResult {\n markdown: string;\n attachments: MarkdownAttachment[];\n}\n\nfunction toExecutionDump(\n execution: ExecutionDump | IExecutionDump,\n): IExecutionDump {\n if (!execution || typeof execution !== 'object') {\n throw new Error('executionToMarkdown: execution is required');\n }\n\n if (!Array.isArray(execution.tasks)) {\n throw new Error('executionToMarkdown: execution.tasks must be an array');\n }\n\n if (!execution.name) {\n throw new Error('executionToMarkdown: execution.name is required');\n }\n\n return execution;\n}\n\nfunction toReportDump(\n report: ReportActionDump | IReportActionDump,\n): IReportActionDump {\n if (!report || typeof report !== 'object') {\n throw new Error('reportToMarkdown: report is required');\n }\n\n if (!Array.isArray(report.executions)) {\n throw new Error('reportToMarkdown: report.executions must be an array');\n }\n\n return report;\n}\n\nfunction formatTime(ts?: number): string {\n if (typeof ts !== 'number' || Number.isNaN(ts)) {\n return 'N/A';\n }\n return new Date(ts).toISOString();\n}\n\nfunction formatValue(value: unknown): string {\n if (value === undefined || value === null || value === '') {\n return 'N/A';\n }\n if (typeof value === 'number') {\n return Number.isFinite(value) ? String(value) : 'N/A';\n }\n return String(value);\n}\n\nfunction escapeTableCell(value: unknown): string {\n return formatValue(value).replace(/\\|/g, '\\\\|').replace(/\\n/g, '<br>');\n}\n\nfunction markdownTable(headers: string[], rows: unknown[][]): string[] {\n return [\n `| ${headers.map(escapeTableCell).join(' | ')} |`,\n `| ${headers.map(() => '---').join(' | ')} |`,\n ...rows.map((row) => `| ${row.map(escapeTableCell).join(' | ')} |`),\n ];\n}\n\nfunction modelBriefRows(modelBriefs: ModelBrief[]): unknown[][] {\n return modelBriefs.map((brief) => [\n brief.intent || 'default',\n brief.name || 'N/A',\n brief.modelDescription || 'N/A',\n ]);\n}\n\nfunction modelRowsFromUsage(report: IReportActionDump): unknown[][] {\n const rows = new Map<string, unknown[]>();\n const addUsage = (source: string, usage?: AIUsageInfo) => {\n if (!hasUsage(usage)) return;\n const intent = usage.intent || source;\n const model = usage.model_name || usage.response_model_name;\n const description = usage.model_description;\n const key = `${intent}\\0${model || ''}\\0${description || ''}`;\n if (rows.has(key)) {\n return;\n }\n rows.set(key, [intent, model || 'N/A', description || 'N/A']);\n };\n\n for (const execution of report.executions) {\n for (const task of execution.tasks) {\n const taskWithUsage = task as ExecutionTaskWithExtraUsage;\n addUsage('main', taskWithUsage.usage);\n addUsage('searchArea', taskWithUsage.searchAreaUsage);\n }\n }\n\n return Array.from(rows.values());\n}\n\nfunction usageValue(usage: AIUsageInfo | undefined, key: string): number {\n const value = usage?.[key];\n return typeof value === 'number' && Number.isFinite(value) ? value : 0;\n}\n\nfunction hasUsage(usage: AIUsageInfo | undefined): usage is AIUsageInfo {\n if (!usage) return false;\n return [\n 'intent',\n 'model_name',\n 'model_description',\n 'prompt_tokens',\n 'cached_input',\n 'completion_tokens',\n 'total_tokens',\n 'time_cost',\n 'request_id',\n ].some((key) => usage[key] !== undefined && usage[key] !== null);\n}\n\nfunction usageTotalTokens(usage: AIUsageInfo): number {\n const explicitTotal = usageValue(usage, 'total_tokens');\n if (explicitTotal > 0) {\n return explicitTotal;\n }\n return (\n usageValue(usage, 'prompt_tokens') + usageValue(usage, 'completion_tokens')\n );\n}\n\nfunction usageRowsForTask(task: ExecutionTask): unknown[][] {\n const taskWithUsage = task as ExecutionTaskWithExtraUsage;\n const rows: unknown[][] = [];\n const appendUsage = (source: string, usage?: AIUsageInfo) => {\n if (!hasUsage(usage)) return;\n rows.push([\n source,\n usage.intent,\n usage.model_name || usage.response_model_name,\n usage.model_description,\n usageValue(usage, 'prompt_tokens'),\n usageValue(usage, 'cached_input'),\n usageValue(usage, 'completion_tokens'),\n usageTotalTokens(usage),\n usageValue(usage, 'time_cost'),\n usage.request_id,\n ]);\n };\n\n appendUsage('main', taskWithUsage.usage);\n appendUsage('searchArea', taskWithUsage.searchAreaUsage);\n return rows;\n}\n\nfunction sanitizeJsonForMarkdown(\n value: unknown,\n seen = new WeakSet<object>(),\n): unknown {\n if (typeof value === 'string') {\n if (\n screenshotDataUrlPattern.test(value) ||\n value.length > 1_000_000 ||\n /^[a-zA-Z0-9+/=\\s]{100000,}$/.test(value)\n ) {\n return `[omitted image/base64 string, length=${value.length}]`;\n }\n if (value.length > jsonContextMaxStringLength) {\n return `${value.slice(0, jsonContextMaxStringLength)}\\n[truncated, original length=${value.length}]`;\n }\n return value;\n }\n\n if (\n value === null ||\n typeof value === 'number' ||\n typeof value === 'boolean'\n ) {\n return value;\n }\n\n if (typeof value === 'function') {\n return '[omitted function]';\n }\n\n if (typeof value !== 'object' || value === undefined) {\n return undefined;\n }\n\n if (seen.has(value)) {\n return '[omitted circular reference]';\n }\n seen.add(value);\n\n if (Array.isArray(value)) {\n return value.map((item) => sanitizeJsonForMarkdown(item, seen));\n }\n\n const input = value as Record<string, unknown>;\n const output: Record<string, unknown> = {};\n for (const [key, entry] of Object.entries(input)) {\n if (entry === undefined || typeof entry === 'function') {\n continue;\n }\n if (\n typeof entry === 'string' &&\n /(^|_|-)(base64|screenshotBase64|imageBase64)$/i.test(key)\n ) {\n output[key] = `[omitted base64 string, length=${entry.length}]`;\n continue;\n }\n output[key] = sanitizeJsonForMarkdown(entry, seen);\n }\n seen.delete(value);\n return output;\n}\n\nfunction appendJsonSection(\n lines: string[],\n title: string,\n value: unknown,\n): void {\n if (value === undefined || value === null || value === '') {\n return;\n }\n const sanitized = sanitizeJsonForMarkdown(value);\n if (sanitized === undefined) {\n return;\n }\n\n lines.push('', `### ${title}`, '', '```json');\n lines.push(JSON.stringify(sanitized, null, 2));\n lines.push('```');\n}\n\nfunction appendTextSection(\n lines: string[],\n title: string,\n value: unknown,\n): void {\n if (typeof value !== 'string' || !value.trim()) {\n return;\n }\n lines.push('', `### ${title}`, '', '```text');\n lines.push(value.replace(/```/g, '` ` `'));\n lines.push('```');\n}\n\nfunction resolveTaskTiming(task: ExecutionTask): {\n start?: number;\n end?: number;\n cost?: number;\n} {\n const timing = task.timing;\n if (!timing) {\n return {};\n }\n\n const start = timing.start ?? timing.callAiStart ?? timing.callActionStart;\n const end =\n timing.end ??\n timing.callAiEnd ??\n timing.callActionEnd ??\n timing.captureAfterCallingSnapshotEnd;\n const cost =\n timing.cost ??\n (typeof start === 'number' && typeof end === 'number'\n ? end - start\n : undefined);\n\n return { start, end, cost };\n}\n\nfunction safeTaskParam(task: ExecutionTask): string {\n const readable = paramStr(task);\n if (readable) {\n return readable;\n }\n\n if (task.type === 'Insight') {\n return extractInsightParam((task as any).param).content;\n }\n\n return '';\n}\n\nfunction formatSize(\n size?: { width?: number; height?: number } | null,\n): string | undefined {\n if (\n !size ||\n typeof size.width !== 'number' ||\n typeof size.height !== 'number' ||\n Number.isNaN(size.width) ||\n Number.isNaN(size.height)\n ) {\n return undefined;\n }\n\n return `${size.width} x ${size.height}`;\n}\n\nfunction extractLocateCenter(\n task: ExecutionTask,\n): [number, number] | undefined {\n const outputCenter = (task.output as { element?: { center?: unknown } })\n ?.element?.center;\n if (\n Array.isArray(outputCenter) &&\n outputCenter.length >= 2 &&\n typeof outputCenter[0] === 'number' &&\n typeof outputCenter[1] === 'number'\n ) {\n return [outputCenter[0], outputCenter[1]];\n }\n\n const paramLocateCenter = (task.param as { locate?: { center?: unknown } })\n ?.locate?.center;\n if (\n Array.isArray(paramLocateCenter) &&\n paramLocateCenter.length >= 2 &&\n typeof paramLocateCenter[0] === 'number' &&\n typeof paramLocateCenter[1] === 'number'\n ) {\n return [paramLocateCenter[0], paramLocateCenter[1]];\n }\n\n const paramCenter = (task.param as { center?: unknown })?.center;\n if (\n Array.isArray(paramCenter) &&\n paramCenter.length >= 2 &&\n typeof paramCenter[0] === 'number' &&\n typeof paramCenter[1] === 'number'\n ) {\n return [paramCenter[0], paramCenter[1]];\n }\n\n return undefined;\n}\n\nfunction tryExtractBase64(screenshot: unknown): string | undefined {\n if (typeof screenshot === 'string') {\n const trimmedScreenshot = screenshot.trim();\n const dataUrlMatch = trimmedScreenshot.match(screenshotDataUrlPattern);\n if (dataUrlMatch) {\n const format = dataUrlMatch[1].toLowerCase() === 'jpg' ? 'jpeg' : 'png';\n const base64Body = dataUrlMatch[2].replace(/\\s/g, '');\n if (!base64Body) {\n return undefined;\n }\n return `data:image/${format};base64,${base64Body}`;\n }\n\n if (\n trimmedScreenshot.startsWith('data:') ||\n !rawBase64BodyPattern.test(trimmedScreenshot)\n ) {\n return undefined;\n }\n\n const base64Body = trimmedScreenshot.replace(/\\s/g, '');\n return base64Body ? `data:image/png;base64,${base64Body}` : undefined;\n }\n\n if (!screenshot || typeof screenshot !== 'object') return undefined;\n const s = screenshot as Record<string, unknown>;\n if (typeof s.base64 === 'string' && s.base64.length > 0) {\n return s.base64;\n }\n return undefined;\n}\n\nfunction restoredSourceRef(screenshot: unknown): ScreenshotRef | undefined {\n if (!screenshot || typeof screenshot !== 'object') {\n return undefined;\n }\n\n const sourceRef = (screenshot as Record<string, unknown>).sourceRef;\n return normalizeScreenshotRef(sourceRef) ?? undefined;\n}\n\nfunction screenshotAttachment(\n screenshot: unknown,\n screenshotBaseDir: string,\n executionIndex: number,\n taskIndex: number,\n options?: {\n fallbackIdSuffix?: string;\n label?: string;\n },\n): { markdown: string; attachment: MarkdownAttachment } {\n const markdownLabel = options?.label || `task-${taskIndex + 1}`;\n\n if (ScreenshotItem.isScreenshotItem(screenshot)) {\n const ext = screenshot.extension;\n const suggestedFileName = `execution-${executionIndex + 1}-task-${taskIndex + 1}-${screenshot.id}.${ext}`;\n return {\n markdown: `\\n`,\n attachment: {\n id: screenshot.id,\n suggestedFileName,\n mimeType: `image/${ext === 'jpeg' ? 'jpeg' : 'png'}`,\n executionIndex,\n taskIndex,\n base64Data: tryExtractBase64(screenshot),\n },\n };\n }\n\n const ref = normalizeScreenshotRef(screenshot);\n if (ref) {\n const ext = imageRefFileExtension(ref);\n const suggestedFileName = `execution-${executionIndex + 1}-task-${taskIndex + 1}-${ref.id}.${ext}`;\n return {\n markdown: `\\n`,\n attachment: {\n id: ref.id,\n suggestedFileName,\n sourceRef: ref,\n mimeType: ref.mimeType,\n executionIndex,\n taskIndex,\n base64Data: tryExtractBase64(screenshot),\n },\n };\n }\n\n const sourceRef = restoredSourceRef(screenshot);\n if (sourceRef) {\n const ext = imageRefFileExtension(sourceRef);\n const suggestedFileName = `execution-${executionIndex + 1}-task-${taskIndex + 1}-${sourceRef.id}.${ext}`;\n return {\n markdown: `\\n`,\n attachment: {\n id: sourceRef.id,\n suggestedFileName,\n sourceRef,\n mimeType: sourceRef.mimeType,\n executionIndex,\n taskIndex,\n base64Data: tryExtractBase64(screenshot),\n },\n };\n }\n\n const base64 = tryExtractBase64(screenshot);\n if (base64) {\n const ext = base64.startsWith('data:image/jpeg') ? 'jpeg' : 'png';\n const idSuffix = options?.fallbackIdSuffix\n ? `-${options.fallbackIdSuffix}`\n : '';\n const id = `restored-${executionIndex + 1}-${taskIndex + 1}${idSuffix}`;\n const suggestedFileName = `execution-${executionIndex + 1}-task-${taskIndex + 1}-${id}.${ext}`;\n return {\n markdown: `\\n`,\n attachment: {\n id,\n suggestedFileName,\n mimeType: `image/${ext}`,\n executionIndex,\n taskIndex,\n base64Data: base64,\n },\n };\n }\n\n throw new Error(\n `executionToMarkdown: missing screenshot for execution #${executionIndex + 1} task #${taskIndex + 1}`,\n );\n}\n\nfunction imageLabelSuffix(value: string): string {\n return (\n value\n .toLowerCase()\n .replace(/[^a-z0-9._-]+/g, '-')\n .replace(/-+/g, '-')\n .replace(/^-|-$/g, '') || 'screenshot'\n );\n}\n\nfunction screenshotsMarkdownSection(\n task: ExecutionTask,\n screenshotBaseDir: string,\n executionIndex: number,\n taskIndex: number,\n): { lines: string[]; attachments: MarkdownAttachment[] } {\n const lines: string[] = ['', '### Screenshots'];\n const attachments: MarkdownAttachment[] = [];\n let screenshotIndex = 0;\n\n if (task.uiContext?.screenshot) {\n const imageResult = screenshotAttachment(\n task.uiContext.screenshot,\n screenshotBaseDir,\n executionIndex,\n taskIndex,\n {\n fallbackIdSuffix: 'ui-context',\n label: `task-${taskIndex + 1}-ui-context`,\n },\n );\n const time = resolveTaskTiming(task);\n screenshotIndex += 1;\n lines.push(\n `- #${screenshotIndex} type=ui-context, ts=${formatTime(time.start)}, timing=ui-context`,\n );\n lines.push(imageResult.markdown);\n attachments.push(imageResult.attachment);\n }\n\n task.recorder?.forEach((item, recorderIndex) => {\n if (!item.screenshot) {\n return;\n }\n\n const descriptionText = item.description\n ? `, description=${item.description}`\n : '';\n const timing = item.timing || 'N/A';\n screenshotIndex += 1;\n lines.push(\n `- #${screenshotIndex} type=${item.type}, ts=${formatTime(item.ts)}, timing=${timing}${descriptionText}`,\n );\n\n const imageResult = screenshotAttachment(\n item.screenshot,\n screenshotBaseDir,\n executionIndex,\n taskIndex,\n {\n fallbackIdSuffix: `recorder-${recorderIndex + 1}`,\n label: `task-${taskIndex + 1}-${imageLabelSuffix(timing)}`,\n },\n );\n\n lines.push(imageResult.markdown);\n attachments.push(imageResult.attachment);\n });\n\n return screenshotIndex > 0\n ? { lines, attachments }\n : { lines: [], attachments };\n}\n\nfunction renderExecution(\n executionRaw: ExecutionDump | IExecutionDump,\n executionIndex: number,\n options?: ExecutionMarkdownOptions,\n): ExecutionMarkdownResult {\n const execution = toExecutionDump(executionRaw);\n const screenshotBaseDir = options?.screenshotBaseDir ?? './screenshots';\n\n const lines: string[] = [];\n const attachments: MarkdownAttachment[] = [];\n\n lines.push(`# ${execution.name}`);\n if (execution.description) {\n lines.push('', execution.description);\n }\n\n lines.push('', `- Execution start: ${formatTime(execution.logTime)}`);\n lines.push(`- Task count: ${execution.tasks.length}`);\n if (execution.aiActContext) {\n appendTextSection(lines, 'AI Action Context', execution.aiActContext);\n }\n\n execution.tasks.forEach((task, taskIndex) => {\n const title = typeStr(task);\n const detail = safeTaskParam(task);\n const time = resolveTaskTiming(task);\n\n lines.push(\n '',\n `## ${taskIndex + 1}. ${title}${detail ? ` - ${detail}` : ''}`,\n );\n lines.push(`- Task ID: ${task.taskId || 'N/A'}`);\n lines.push(`- Type: ${task.type || 'N/A'}`);\n lines.push(`- SubType: ${task.subType || 'N/A'}`);\n lines.push(`- Status: ${task.status || 'unknown'}`);\n lines.push(`- Start: ${formatTime(time.start)}`);\n lines.push(`- End: ${formatTime(time.end)}`);\n lines.push(\n `- Cost(ms): ${typeof time.cost === 'number' ? time.cost : 'N/A'}`,\n );\n lines.push(\n `- Screen size: ${formatSize(task.uiContext?.shotSize) || 'N/A'}`,\n );\n\n if (task.subType === 'Locate') {\n const locateCenter = extractLocateCenter(task);\n if (locateCenter) {\n lines.push(`- Locate center: (${locateCenter[0]}, ${locateCenter[1]})`);\n }\n }\n\n if (task.errorMessage) {\n lines.push(`- Error: ${task.errorMessage}`);\n }\n\n const usageRows = usageRowsForTask(task);\n if (usageRows.length) {\n lines.push('', '### Model Usage');\n lines.push(\n ...markdownTable(\n [\n 'Source',\n 'Intent',\n 'Model',\n 'Description',\n 'Prompt Tokens',\n 'Cached Input',\n 'Completion Tokens',\n 'Total Tokens',\n 'Model Call Time(ms)',\n 'Request ID',\n ],\n usageRows,\n ),\n );\n }\n\n appendJsonSection(lines, 'Param', task.param);\n appendJsonSection(lines, 'Output', task.output);\n appendJsonSection(lines, 'Log', task.log);\n appendTextSection(lines, 'Thought', task.thought);\n appendTextSection(\n lines,\n 'Reasoning Content',\n (task as ExecutionTaskWithExtraUsage).reasoning_content,\n );\n\n const screenshotsSection = screenshotsMarkdownSection(\n task,\n screenshotBaseDir,\n executionIndex,\n taskIndex,\n );\n if (screenshotsSection.lines.length) {\n lines.push(...screenshotsSection.lines);\n attachments.push(...screenshotsSection.attachments);\n }\n });\n\n return {\n markdown: lines.join('\\n'),\n attachments,\n };\n}\n\nexport function executionToMarkdown(\n execution: ExecutionDump | IExecutionDump,\n options?: ExecutionMarkdownOptions,\n): ExecutionMarkdownResult {\n return renderExecution(execution, 0, options);\n}\n\nexport function reportToMarkdown(\n report: ReportActionDump | IReportActionDump,\n options?: ReportMarkdownOptions,\n): ReportMarkdownResult {\n const reportDump = toReportDump(report);\n\n const executionResults = reportDump.executions.map((execution, index) => {\n const rendered = renderExecution(execution, index);\n return {\n markdown: rendered.markdown,\n attachments: rendered.attachments,\n };\n });\n\n const attachments = executionResults.flatMap((item) => item.attachments);\n const reportSummary = collectReportSummary(reportDump, options);\n const modelRows = reportDump.modelBriefs?.length\n ? modelBriefRows(reportDump.modelBriefs)\n : modelRowsFromUsage(reportDump);\n\n const modelInfoLines = [\n '\\n## Model Info',\n ...(modelRows.length\n ? markdownTable(['Intent', 'Model', 'Description'], modelRows)\n : ['- No model metadata recorded.']),\n ];\n\n const elapsedTimeDescription =\n reportSummary.timing.wallTimeSource === 'task-timestamps'\n ? 'Total span from the first recorded task start to the last recorded task end, including model calls, actions, waits, and gaps.'\n : reportSummary.timing.wallTimeSource === 'fallback'\n ? 'Total elapsed duration reported by the enclosing test runner because task timestamps were unavailable.'\n : 'The total elapsed span is unavailable because the report has no recorded task timestamps.';\n const timingSummaryLines = [\n '\\n## Timing Summary',\n ...markdownTable(\n ['Metric', 'Duration(ms)', 'Definition'],\n [\n [\n 'Elapsed Time',\n reportSummary.timing.wallTimeMs ?? 'N/A',\n elapsedTimeDescription,\n ],\n [\n 'Model Call Time',\n reportSummary.timing.modelCallTimeMs,\n 'Total duration of all recorded model calls.',\n ],\n ],\n ),\n ];\n\n const tokenSummaryLines = [\n '\\n## Token Usage Summary',\n ...(reportSummary.models.length\n ? markdownTable(\n [\n 'Model',\n 'Calls',\n 'Prompt Tokens',\n 'Cached Input',\n 'Completion Tokens',\n 'Total Tokens',\n 'Model Call Time(ms)',\n ],\n reportSummary.models.map((model) => [\n model.modelName,\n model.callCount,\n model.promptTokens,\n model.cachedInputTokens,\n model.completionTokens,\n model.totalTokens,\n model.modelCallTimeMs,\n ]),\n )\n : ['- No token usage recorded.']),\n ];\n\n const header = [\n `# ${reportDump.groupName}`,\n reportDump.groupDescription ? `\\n${reportDump.groupDescription}` : '',\n `\\n- SDK Version: ${reportDump.sdkVersion}`,\n reportDump.deviceType ? `- Device Type: ${reportDump.deviceType}` : '',\n `- Execution count: ${reportDump.executions.length}`,\n ...modelInfoLines,\n ...timingSummaryLines,\n ...tokenSummaryLines,\n ]\n .filter(Boolean)\n .join('\\n');\n\n return {\n markdown: `${header}\\n\\n${executionResults.map((item) => item.markdown).join('\\n\\n---\\n\\n')}`,\n attachments,\n };\n}\n"],"names":["screenshotDataUrlPattern","rawBase64BodyPattern","jsonContextMaxStringLength","toExecutionDump","execution","Error","Array","toReportDump","report","formatTime","ts","Number","Date","formatValue","value","String","escapeTableCell","markdownTable","headers","rows","row","modelBriefRows","modelBriefs","brief","modelRowsFromUsage","Map","addUsage","source","usage","hasUsage","intent","model","description","key","task","taskWithUsage","usageValue","undefined","usageTotalTokens","explicitTotal","usageRowsForTask","appendUsage","sanitizeJsonForMarkdown","seen","WeakSet","item","input","output","entry","Object","appendJsonSection","lines","title","sanitized","JSON","appendTextSection","resolveTaskTiming","timing","start","end","cost","safeTaskParam","readable","paramStr","extractInsightParam","formatSize","size","extractLocateCenter","outputCenter","paramLocateCenter","paramCenter","tryExtractBase64","screenshot","trimmedScreenshot","dataUrlMatch","format","base64Body","s","restoredSourceRef","sourceRef","normalizeScreenshotRef","screenshotAttachment","screenshotBaseDir","executionIndex","taskIndex","options","markdownLabel","ScreenshotItem","ext","suggestedFileName","ref","imageRefFileExtension","base64","idSuffix","id","imageLabelSuffix","screenshotsMarkdownSection","attachments","screenshotIndex","imageResult","time","recorderIndex","descriptionText","renderExecution","executionRaw","typeStr","detail","locateCenter","usageRows","screenshotsSection","executionToMarkdown","reportToMarkdown","reportDump","executionResults","index","rendered","reportSummary","collectReportSummary","modelRows","modelInfoLines","elapsedTimeDescription","timingSummaryLines","tokenSummaryLines","header","Boolean"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"report-markdown.mjs","sources":["../../src/report-markdown.ts"],"sourcesContent":["import { extractInsightParam, paramStr, typeStr } from '@/agent/ui-utils';\nimport { ScreenshotItem } from '@/screenshot-item';\nimport type {\n AIUsageInfo,\n ExecutionDump,\n ExecutionTask,\n IExecutionDump,\n IReportActionDump,\n ModelBrief,\n ReportActionDump,\n} from '@/types';\nimport type { ScreenshotRef } from './dump/screenshot-store';\nimport {\n imageRefFileExtension,\n normalizeScreenshotRef,\n} from './dump/screenshot-store';\nimport { collectReportSummary } from './report-stats';\n\nconst screenshotDataUrlPattern =\n /^data:image\\/(png|jpeg|jpg);base64,([\\s\\S]*)$/i;\nconst rawBase64BodyPattern = /^[a-zA-Z0-9+/=\\s]+$/;\nconst jsonContextMaxStringLength = 12_000;\n\ntype ExecutionTaskWithExtraUsage = ExecutionTask & {\n searchAreaUsage?: AIUsageInfo;\n reasoning_content?: string;\n};\n\nexport interface MarkdownAttachment {\n id: string;\n /**\n * File name for the exported copy. The markdown image link\n * always points at `${screenshotBaseDir}/${suggestedFileName}`, so consumers\n * write the screenshot under this name to keep links in sync. See #2392.\n */\n suggestedFileName: string;\n mimeType?: string;\n /**\n * Reference to the screenshot in the source report, used to locate the\n * original bytes when copying them to the exported name. Absent for in-memory\n * screenshots, which carry their data in `base64Data` instead.\n */\n sourceRef?: ScreenshotRef;\n executionIndex: number;\n taskIndex: number;\n /** Populated when screenshot data is available in memory (e.g. browser context). */\n base64Data?: string;\n}\n\nexport interface ExecutionMarkdownOptions {\n screenshotBaseDir?: string;\n /** Resolve the exported asset name without changing observation labels. */\n resolveScreenshotFileName?: (attachment: MarkdownAttachment) => string;\n}\n\nexport interface ReportMarkdownOptions\n extends Pick<ExecutionMarkdownOptions, 'resolveScreenshotFileName'> {\n /** Used only when the report has no recorded task timestamps. */\n wallTimeFallbackMs?: number;\n}\n\nexport interface ExecutionMarkdownResult {\n markdown: string;\n attachments: MarkdownAttachment[];\n}\n\nexport interface ReportMarkdownResult {\n markdown: string;\n attachments: MarkdownAttachment[];\n}\n\nfunction toExecutionDump(\n execution: ExecutionDump | IExecutionDump,\n): IExecutionDump {\n if (!execution || typeof execution !== 'object') {\n throw new Error('executionToMarkdown: execution is required');\n }\n\n if (!Array.isArray(execution.tasks)) {\n throw new Error('executionToMarkdown: execution.tasks must be an array');\n }\n\n if (!execution.name) {\n throw new Error('executionToMarkdown: execution.name is required');\n }\n\n return execution;\n}\n\nfunction toReportDump(\n report: ReportActionDump | IReportActionDump,\n): IReportActionDump {\n if (!report || typeof report !== 'object') {\n throw new Error('reportToMarkdown: report is required');\n }\n\n if (!Array.isArray(report.executions)) {\n throw new Error('reportToMarkdown: report.executions must be an array');\n }\n\n return report;\n}\n\nfunction formatTime(ts?: number): string {\n if (typeof ts !== 'number' || Number.isNaN(ts)) {\n return 'N/A';\n }\n return new Date(ts).toISOString();\n}\n\nfunction formatValue(value: unknown): string {\n if (value === undefined || value === null || value === '') {\n return 'N/A';\n }\n if (typeof value === 'number') {\n return Number.isFinite(value) ? String(value) : 'N/A';\n }\n return String(value);\n}\n\nfunction escapeTableCell(value: unknown): string {\n return formatValue(value).replace(/\\|/g, '\\\\|').replace(/\\n/g, '<br>');\n}\n\nfunction markdownTable(headers: string[], rows: unknown[][]): string[] {\n return [\n `| ${headers.map(escapeTableCell).join(' | ')} |`,\n `| ${headers.map(() => '---').join(' | ')} |`,\n ...rows.map((row) => `| ${row.map(escapeTableCell).join(' | ')} |`),\n ];\n}\n\nfunction modelBriefRows(modelBriefs: ModelBrief[]): unknown[][] {\n return modelBriefs.map((brief) => [\n brief.intent || 'default',\n brief.name || 'N/A',\n brief.modelDescription || 'N/A',\n ]);\n}\n\nfunction modelRowsFromUsage(report: IReportActionDump): unknown[][] {\n const rows = new Map<string, unknown[]>();\n const addUsage = (source: string, usage?: AIUsageInfo) => {\n if (!hasUsage(usage)) return;\n const intent = usage.intent || source;\n const model = usage.model_name || usage.response_model_name;\n const description = usage.model_description;\n const key = `${intent}\\0${model || ''}\\0${description || ''}`;\n if (rows.has(key)) {\n return;\n }\n rows.set(key, [intent, model || 'N/A', description || 'N/A']);\n };\n\n for (const execution of report.executions) {\n for (const task of execution.tasks) {\n const taskWithUsage = task as ExecutionTaskWithExtraUsage;\n addUsage('main', taskWithUsage.usage);\n addUsage('searchArea', taskWithUsage.searchAreaUsage);\n }\n }\n\n return Array.from(rows.values());\n}\n\nfunction usageValue(usage: AIUsageInfo | undefined, key: string): number {\n const value = usage?.[key];\n return typeof value === 'number' && Number.isFinite(value) ? value : 0;\n}\n\nfunction hasUsage(usage: AIUsageInfo | undefined): usage is AIUsageInfo {\n if (!usage) return false;\n return [\n 'intent',\n 'model_name',\n 'model_description',\n 'prompt_tokens',\n 'cached_input',\n 'completion_tokens',\n 'total_tokens',\n 'time_cost',\n 'request_id',\n ].some((key) => usage[key] !== undefined && usage[key] !== null);\n}\n\nfunction usageTotalTokens(usage: AIUsageInfo): number {\n const explicitTotal = usageValue(usage, 'total_tokens');\n if (explicitTotal > 0) {\n return explicitTotal;\n }\n return (\n usageValue(usage, 'prompt_tokens') + usageValue(usage, 'completion_tokens')\n );\n}\n\nfunction usageRowsForTask(task: ExecutionTask): unknown[][] {\n const taskWithUsage = task as ExecutionTaskWithExtraUsage;\n const rows: unknown[][] = [];\n const appendUsage = (source: string, usage?: AIUsageInfo) => {\n if (!hasUsage(usage)) return;\n rows.push([\n source,\n usage.intent,\n usage.model_name || usage.response_model_name,\n usage.model_description,\n usageValue(usage, 'prompt_tokens'),\n usageValue(usage, 'cached_input'),\n usageValue(usage, 'completion_tokens'),\n usageTotalTokens(usage),\n usageValue(usage, 'time_cost'),\n usage.request_id,\n ]);\n };\n\n appendUsage('main', taskWithUsage.usage);\n appendUsage('searchArea', taskWithUsage.searchAreaUsage);\n return rows;\n}\n\nfunction sanitizeJsonForMarkdown(\n value: unknown,\n seen = new WeakSet<object>(),\n): unknown {\n if (typeof value === 'string') {\n if (\n screenshotDataUrlPattern.test(value) ||\n value.length > 1_000_000 ||\n /^[a-zA-Z0-9+/=\\s]{100000,}$/.test(value)\n ) {\n return `[omitted image/base64 string, length=${value.length}]`;\n }\n if (value.length > jsonContextMaxStringLength) {\n return `${value.slice(0, jsonContextMaxStringLength)}\\n[truncated, original length=${value.length}]`;\n }\n return value;\n }\n\n if (\n value === null ||\n typeof value === 'number' ||\n typeof value === 'boolean'\n ) {\n return value;\n }\n\n if (typeof value === 'function') {\n return '[omitted function]';\n }\n\n if (typeof value !== 'object' || value === undefined) {\n return undefined;\n }\n\n if (seen.has(value)) {\n return '[omitted circular reference]';\n }\n seen.add(value);\n\n if (Array.isArray(value)) {\n return value.map((item) => sanitizeJsonForMarkdown(item, seen));\n }\n\n const input = value as Record<string, unknown>;\n const output: Record<string, unknown> = {};\n for (const [key, entry] of Object.entries(input)) {\n if (entry === undefined || typeof entry === 'function') {\n continue;\n }\n if (\n typeof entry === 'string' &&\n /(^|_|-)(base64|screenshotBase64|imageBase64)$/i.test(key)\n ) {\n output[key] = `[omitted base64 string, length=${entry.length}]`;\n continue;\n }\n output[key] = sanitizeJsonForMarkdown(entry, seen);\n }\n seen.delete(value);\n return output;\n}\n\nfunction appendJsonSection(\n lines: string[],\n title: string,\n value: unknown,\n): void {\n if (value === undefined || value === null || value === '') {\n return;\n }\n const sanitized = sanitizeJsonForMarkdown(value);\n if (sanitized === undefined) {\n return;\n }\n\n lines.push('', `### ${title}`, '', '```json');\n lines.push(JSON.stringify(sanitized, null, 2));\n lines.push('```');\n}\n\nfunction appendTextSection(\n lines: string[],\n title: string,\n value: unknown,\n): void {\n if (typeof value !== 'string' || !value.trim()) {\n return;\n }\n lines.push('', `### ${title}`, '', '```text');\n lines.push(value.replace(/```/g, '` ` `'));\n lines.push('```');\n}\n\nfunction resolveTaskTiming(task: ExecutionTask): {\n start?: number;\n end?: number;\n cost?: number;\n} {\n const timing = task.timing;\n if (!timing) {\n return {};\n }\n\n const start = timing.start ?? timing.callAiStart ?? timing.callActionStart;\n const end =\n timing.end ??\n timing.callAiEnd ??\n timing.callActionEnd ??\n timing.captureAfterCallingSnapshotEnd;\n const cost =\n timing.cost ??\n (typeof start === 'number' && typeof end === 'number'\n ? end - start\n : undefined);\n\n return { start, end, cost };\n}\n\nfunction safeTaskParam(task: ExecutionTask): string {\n const readable = paramStr(task);\n if (readable) {\n return readable;\n }\n\n if (task.type === 'Insight') {\n return extractInsightParam((task as any).param).content;\n }\n\n return '';\n}\n\nfunction formatSize(\n size?: { width?: number; height?: number } | null,\n): string | undefined {\n if (\n !size ||\n typeof size.width !== 'number' ||\n typeof size.height !== 'number' ||\n Number.isNaN(size.width) ||\n Number.isNaN(size.height)\n ) {\n return undefined;\n }\n\n return `${size.width} x ${size.height}`;\n}\n\nfunction extractLocateCenter(\n task: ExecutionTask,\n): [number, number] | undefined {\n const outputCenter = (task.output as { element?: { center?: unknown } })\n ?.element?.center;\n if (\n Array.isArray(outputCenter) &&\n outputCenter.length >= 2 &&\n typeof outputCenter[0] === 'number' &&\n typeof outputCenter[1] === 'number'\n ) {\n return [outputCenter[0], outputCenter[1]];\n }\n\n const paramLocateCenter = (task.param as { locate?: { center?: unknown } })\n ?.locate?.center;\n if (\n Array.isArray(paramLocateCenter) &&\n paramLocateCenter.length >= 2 &&\n typeof paramLocateCenter[0] === 'number' &&\n typeof paramLocateCenter[1] === 'number'\n ) {\n return [paramLocateCenter[0], paramLocateCenter[1]];\n }\n\n const paramCenter = (task.param as { center?: unknown })?.center;\n if (\n Array.isArray(paramCenter) &&\n paramCenter.length >= 2 &&\n typeof paramCenter[0] === 'number' &&\n typeof paramCenter[1] === 'number'\n ) {\n return [paramCenter[0], paramCenter[1]];\n }\n\n return undefined;\n}\n\nfunction tryExtractBase64(screenshot: unknown): string | undefined {\n if (typeof screenshot === 'string') {\n const trimmedScreenshot = screenshot.trim();\n const dataUrlMatch = trimmedScreenshot.match(screenshotDataUrlPattern);\n if (dataUrlMatch) {\n const format = dataUrlMatch[1].toLowerCase() === 'jpg' ? 'jpeg' : 'png';\n const base64Body = dataUrlMatch[2].replace(/\\s/g, '');\n if (!base64Body) {\n return undefined;\n }\n return `data:image/${format};base64,${base64Body}`;\n }\n\n if (\n trimmedScreenshot.startsWith('data:') ||\n !rawBase64BodyPattern.test(trimmedScreenshot)\n ) {\n return undefined;\n }\n\n const base64Body = trimmedScreenshot.replace(/\\s/g, '');\n return base64Body ? `data:image/png;base64,${base64Body}` : undefined;\n }\n\n if (!screenshot || typeof screenshot !== 'object') return undefined;\n const s = screenshot as Record<string, unknown>;\n if (typeof s.base64 === 'string' && s.base64.length > 0) {\n return s.base64;\n }\n return undefined;\n}\n\nfunction restoredSourceRef(screenshot: unknown): ScreenshotRef | undefined {\n if (!screenshot || typeof screenshot !== 'object') {\n return undefined;\n }\n\n const sourceRef = (screenshot as Record<string, unknown>).sourceRef;\n return normalizeScreenshotRef(sourceRef) ?? undefined;\n}\n\nfunction screenshotAttachment(\n screenshot: unknown,\n screenshotBaseDir: string,\n executionIndex: number,\n taskIndex: number,\n options?: {\n fallbackIdSuffix?: string;\n label?: string;\n resolveScreenshotFileName?: ExecutionMarkdownOptions['resolveScreenshotFileName'];\n },\n): { markdown: string; attachment: MarkdownAttachment } {\n const markdownLabel = options?.label || `task-${taskIndex + 1}`;\n const result = (attachment: MarkdownAttachment) => {\n attachment.suggestedFileName =\n options?.resolveScreenshotFileName?.(attachment) ??\n attachment.suggestedFileName;\n return {\n markdown: `\\n`,\n attachment,\n };\n };\n\n if (ScreenshotItem.isScreenshotItem(screenshot)) {\n const ext = screenshot.extension;\n const suggestedFileName = `execution-${executionIndex + 1}-task-${taskIndex + 1}-${screenshot.id}.${ext}`;\n return result({\n id: screenshot.id,\n suggestedFileName,\n mimeType: `image/${ext === 'jpeg' ? 'jpeg' : 'png'}`,\n executionIndex,\n taskIndex,\n base64Data: tryExtractBase64(screenshot),\n });\n }\n\n const ref = normalizeScreenshotRef(screenshot);\n if (ref) {\n const ext = imageRefFileExtension(ref);\n const suggestedFileName = `execution-${executionIndex + 1}-task-${taskIndex + 1}-${ref.id}.${ext}`;\n return result({\n id: ref.id,\n suggestedFileName,\n sourceRef: ref,\n mimeType: ref.mimeType,\n executionIndex,\n taskIndex,\n base64Data: tryExtractBase64(screenshot),\n });\n }\n\n const sourceRef = restoredSourceRef(screenshot);\n if (sourceRef) {\n const ext = imageRefFileExtension(sourceRef);\n const suggestedFileName = `execution-${executionIndex + 1}-task-${taskIndex + 1}-${sourceRef.id}.${ext}`;\n return result({\n id: sourceRef.id,\n suggestedFileName,\n sourceRef,\n mimeType: sourceRef.mimeType,\n executionIndex,\n taskIndex,\n base64Data: tryExtractBase64(screenshot),\n });\n }\n\n const base64 = tryExtractBase64(screenshot);\n if (base64) {\n const ext = base64.startsWith('data:image/jpeg') ? 'jpeg' : 'png';\n const idSuffix = options?.fallbackIdSuffix\n ? `-${options.fallbackIdSuffix}`\n : '';\n const id = `restored-${executionIndex + 1}-${taskIndex + 1}${idSuffix}`;\n const suggestedFileName = `execution-${executionIndex + 1}-task-${taskIndex + 1}-${id}.${ext}`;\n return result({\n id,\n suggestedFileName,\n mimeType: `image/${ext}`,\n executionIndex,\n taskIndex,\n base64Data: base64,\n });\n }\n\n throw new Error(\n `executionToMarkdown: missing screenshot for execution #${executionIndex + 1} task #${taskIndex + 1}`,\n );\n}\n\nfunction imageLabelSuffix(value: string): string {\n return (\n value\n .toLowerCase()\n .replace(/[^a-z0-9._-]+/g, '-')\n .replace(/-+/g, '-')\n .replace(/^-|-$/g, '') || 'screenshot'\n );\n}\n\nfunction screenshotsMarkdownSection(\n task: ExecutionTask,\n screenshotBaseDir: string,\n executionIndex: number,\n taskIndex: number,\n resolveScreenshotFileName?: ExecutionMarkdownOptions['resolveScreenshotFileName'],\n): { lines: string[]; attachments: MarkdownAttachment[] } {\n const lines: string[] = ['', '### Screenshots'];\n const attachments: MarkdownAttachment[] = [];\n let screenshotIndex = 0;\n\n if (task.uiContext?.screenshot) {\n const imageResult = screenshotAttachment(\n task.uiContext.screenshot,\n screenshotBaseDir,\n executionIndex,\n taskIndex,\n {\n fallbackIdSuffix: 'ui-context',\n label: `task-${taskIndex + 1}-ui-context`,\n resolveScreenshotFileName,\n },\n );\n const time = resolveTaskTiming(task);\n screenshotIndex += 1;\n lines.push(\n `- #${screenshotIndex} type=ui-context, ts=${formatTime(time.start)}, timing=ui-context, id=${imageResult.attachment.id}`,\n );\n lines.push(imageResult.markdown);\n attachments.push(imageResult.attachment);\n }\n\n task.recorder?.forEach((item, recorderIndex) => {\n if (!item.screenshot) {\n return;\n }\n\n const descriptionText = item.description\n ? `, description=${item.description}`\n : '';\n const timing = item.timing || 'N/A';\n screenshotIndex += 1;\n const imageResult = screenshotAttachment(\n item.screenshot,\n screenshotBaseDir,\n executionIndex,\n taskIndex,\n {\n fallbackIdSuffix: `recorder-${recorderIndex + 1}`,\n label: `task-${taskIndex + 1}-${imageLabelSuffix(timing)}`,\n resolveScreenshotFileName,\n },\n );\n\n lines.push(\n `- #${screenshotIndex} type=${item.type}, ts=${formatTime(item.ts)}, timing=${timing}${descriptionText}, id=${imageResult.attachment.id}`,\n );\n lines.push(imageResult.markdown);\n attachments.push(imageResult.attachment);\n });\n\n return screenshotIndex > 0\n ? { lines, attachments }\n : { lines: [], attachments };\n}\n\nfunction renderExecution(\n executionRaw: ExecutionDump | IExecutionDump,\n executionIndex: number,\n options?: ExecutionMarkdownOptions,\n): ExecutionMarkdownResult {\n const execution = toExecutionDump(executionRaw);\n const screenshotBaseDir = options?.screenshotBaseDir ?? './screenshots';\n\n const lines: string[] = [];\n const attachments: MarkdownAttachment[] = [];\n\n lines.push(`# ${execution.name}`);\n if (execution.description) {\n lines.push('', execution.description);\n }\n\n lines.push('', `- Execution start: ${formatTime(execution.logTime)}`);\n lines.push(`- Task count: ${execution.tasks.length}`);\n if (execution.aiActContext) {\n appendTextSection(lines, 'AI Action Context', execution.aiActContext);\n }\n\n execution.tasks.forEach((task, taskIndex) => {\n const title = typeStr(task);\n const detail = safeTaskParam(task);\n const time = resolveTaskTiming(task);\n\n lines.push(\n '',\n `## ${taskIndex + 1}. ${title}${detail ? ` - ${detail}` : ''}`,\n );\n lines.push(`- Task ID: ${task.taskId || 'N/A'}`);\n lines.push(`- Type: ${task.type || 'N/A'}`);\n lines.push(`- SubType: ${task.subType || 'N/A'}`);\n lines.push(`- Status: ${task.status || 'unknown'}`);\n lines.push(`- Start: ${formatTime(time.start)}`);\n lines.push(`- End: ${formatTime(time.end)}`);\n lines.push(\n `- Cost(ms): ${typeof time.cost === 'number' ? time.cost : 'N/A'}`,\n );\n lines.push(\n `- Screen size: ${formatSize(task.uiContext?.shotSize) || 'N/A'}`,\n );\n\n if (task.subType === 'Locate') {\n const locateCenter = extractLocateCenter(task);\n if (locateCenter) {\n lines.push(`- Locate center: (${locateCenter[0]}, ${locateCenter[1]})`);\n }\n }\n\n if (task.errorMessage) {\n lines.push(`- Error: ${task.errorMessage}`);\n }\n\n const usageRows = usageRowsForTask(task);\n if (usageRows.length) {\n lines.push('', '### Model Usage');\n lines.push(\n ...markdownTable(\n [\n 'Source',\n 'Intent',\n 'Model',\n 'Description',\n 'Prompt Tokens',\n 'Cached Input',\n 'Completion Tokens',\n 'Total Tokens',\n 'Model Call Time(ms)',\n 'Request ID',\n ],\n usageRows,\n ),\n );\n }\n\n appendJsonSection(lines, 'Param', task.param);\n appendJsonSection(lines, 'Output', task.output);\n appendJsonSection(lines, 'Log', task.log);\n appendTextSection(lines, 'Thought', task.thought);\n appendTextSection(\n lines,\n 'Reasoning Content',\n (task as ExecutionTaskWithExtraUsage).reasoning_content,\n );\n\n const screenshotsSection = screenshotsMarkdownSection(\n task,\n screenshotBaseDir,\n executionIndex,\n taskIndex,\n options?.resolveScreenshotFileName,\n );\n if (screenshotsSection.lines.length) {\n lines.push(...screenshotsSection.lines);\n attachments.push(...screenshotsSection.attachments);\n }\n });\n\n return {\n markdown: lines.join('\\n'),\n attachments,\n };\n}\n\nexport function executionToMarkdown(\n execution: ExecutionDump | IExecutionDump,\n options?: ExecutionMarkdownOptions,\n): ExecutionMarkdownResult {\n return renderExecution(execution, 0, options);\n}\n\nexport function reportToMarkdown(\n report: ReportActionDump | IReportActionDump,\n options?: ReportMarkdownOptions,\n): ReportMarkdownResult {\n const reportDump = toReportDump(report);\n\n const executionResults = reportDump.executions.map((execution, index) => {\n const rendered = renderExecution(execution, index, options);\n return {\n markdown: rendered.markdown,\n attachments: rendered.attachments,\n };\n });\n\n const attachments = executionResults.flatMap((item) => item.attachments);\n const reportSummary = collectReportSummary(reportDump, options);\n const modelRows = reportDump.modelBriefs?.length\n ? modelBriefRows(reportDump.modelBriefs)\n : modelRowsFromUsage(reportDump);\n\n const modelInfoLines = [\n '\\n## Model Info',\n ...(modelRows.length\n ? markdownTable(['Intent', 'Model', 'Description'], modelRows)\n : ['- No model metadata recorded.']),\n ];\n\n const elapsedTimeDescription =\n reportSummary.timing.wallTimeSource === 'task-timestamps'\n ? 'Total span from the first recorded task start to the last recorded task end, including model calls, actions, waits, and gaps.'\n : reportSummary.timing.wallTimeSource === 'fallback'\n ? 'Total elapsed duration reported by the enclosing test runner because task timestamps were unavailable.'\n : 'The total elapsed span is unavailable because the report has no recorded task timestamps.';\n const timingSummaryLines = [\n '\\n## Timing Summary',\n ...markdownTable(\n ['Metric', 'Duration(ms)', 'Definition'],\n [\n [\n 'Elapsed Time',\n reportSummary.timing.wallTimeMs ?? 'N/A',\n elapsedTimeDescription,\n ],\n [\n 'Model Call Time',\n reportSummary.timing.modelCallTimeMs,\n 'Total duration of all recorded model calls.',\n ],\n ],\n ),\n ];\n\n const tokenSummaryLines = [\n '\\n## Token Usage Summary',\n ...(reportSummary.models.length\n ? markdownTable(\n [\n 'Model',\n 'Calls',\n 'Prompt Tokens',\n 'Cached Input',\n 'Completion Tokens',\n 'Total Tokens',\n 'Model Call Time(ms)',\n ],\n reportSummary.models.map((model) => [\n model.modelName,\n model.callCount,\n model.promptTokens,\n model.cachedInputTokens,\n model.completionTokens,\n model.totalTokens,\n model.modelCallTimeMs,\n ]),\n )\n : ['- No token usage recorded.']),\n ];\n\n const header = [\n `# ${reportDump.groupName}`,\n reportDump.groupDescription ? `\\n${reportDump.groupDescription}` : '',\n `\\n- SDK Version: ${reportDump.sdkVersion}`,\n reportDump.deviceType ? `- Device Type: ${reportDump.deviceType}` : '',\n `- Execution count: ${reportDump.executions.length}`,\n ...modelInfoLines,\n ...timingSummaryLines,\n ...tokenSummaryLines,\n ]\n .filter(Boolean)\n .join('\\n');\n\n return {\n markdown: `${header}\\n\\n${executionResults.map((item) => item.markdown).join('\\n\\n---\\n\\n')}`,\n attachments,\n };\n}\n"],"names":["screenshotDataUrlPattern","rawBase64BodyPattern","jsonContextMaxStringLength","toExecutionDump","execution","Error","Array","toReportDump","report","formatTime","ts","Number","Date","formatValue","value","String","escapeTableCell","markdownTable","headers","rows","row","modelBriefRows","modelBriefs","brief","modelRowsFromUsage","Map","addUsage","source","usage","hasUsage","intent","model","description","key","task","taskWithUsage","usageValue","undefined","usageTotalTokens","explicitTotal","usageRowsForTask","appendUsage","sanitizeJsonForMarkdown","seen","WeakSet","item","input","output","entry","Object","appendJsonSection","lines","title","sanitized","JSON","appendTextSection","resolveTaskTiming","timing","start","end","cost","safeTaskParam","readable","paramStr","extractInsightParam","formatSize","size","extractLocateCenter","outputCenter","paramLocateCenter","paramCenter","tryExtractBase64","screenshot","trimmedScreenshot","dataUrlMatch","format","base64Body","s","restoredSourceRef","sourceRef","normalizeScreenshotRef","screenshotAttachment","screenshotBaseDir","executionIndex","taskIndex","options","markdownLabel","result","attachment","ScreenshotItem","ext","suggestedFileName","ref","imageRefFileExtension","base64","idSuffix","id","imageLabelSuffix","screenshotsMarkdownSection","resolveScreenshotFileName","attachments","screenshotIndex","imageResult","time","recorderIndex","descriptionText","renderExecution","executionRaw","typeStr","detail","locateCenter","usageRows","screenshotsSection","executionToMarkdown","reportToMarkdown","reportDump","executionResults","index","rendered","reportSummary","collectReportSummary","modelRows","modelInfoLines","elapsedTimeDescription","timingSummaryLines","tokenSummaryLines","header","Boolean"],"mappings":"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"}
|
package/dist/es/report.mjs
CHANGED
|
@@ -1,13 +1,13 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { existsSync, mkdirSync, mkdtempSync, readFileSync, rmSync, unlinkSync, writeFileSync } from "node:fs";
|
|
2
2
|
import { mkdir, mkdtemp, readFile, rm } from "node:fs/promises";
|
|
3
3
|
import { basename, dirname, join, resolve, sep } from "node:path";
|
|
4
4
|
import { getMidsceneRunSubDir } from "@midscene/shared/common";
|
|
5
5
|
import { antiEscapeScriptTag, logMsg, uuid } from "@midscene/shared/utils";
|
|
6
6
|
import { getReportFileName } from "./agent/report-file-name.mjs";
|
|
7
7
|
import { DATA_SCREENSHOT_MODE_ATTR, extractLastDumpScriptSync, generateAgentReportComment, streamDumpScriptsSync } from "./dump/html-utils.mjs";
|
|
8
|
-
import {
|
|
8
|
+
import { normalizeStoredImageRef } from "./dump/image-reference.mjs";
|
|
9
9
|
import { readReportActionDump, readReportArtifactManifest, readReportArtifactManifestAsync, readReportDumpScripts, readReportRunnerDump, streamReportDumpScripts } from "./dump/report-artifact-reader.mjs";
|
|
10
|
-
import {
|
|
10
|
+
import { ReportImageExporter } from "./dump/report-image-export.mjs";
|
|
11
11
|
import { ExecutionRecorder } from "./dump/execution-recorder.mjs";
|
|
12
12
|
import { ReportArtifactStore } from "./dump/report-artifact-store.mjs";
|
|
13
13
|
import { ReportSession } from "./dump/report-session.mjs";
|
|
@@ -640,7 +640,7 @@ function collectDedupedExecutions(htmlPath) {
|
|
|
640
640
|
executions
|
|
641
641
|
};
|
|
642
642
|
}
|
|
643
|
-
function externalizeImagesInExecution(execution,
|
|
643
|
+
function externalizeImagesInExecution(execution, images) {
|
|
644
644
|
const visit = (node)=>{
|
|
645
645
|
if (Array.isArray(node)) {
|
|
646
646
|
for (const item of node)visit(item);
|
|
@@ -649,20 +649,8 @@ function externalizeImagesInExecution(execution, opts) {
|
|
|
649
649
|
if ('object' != typeof node || null === node) return;
|
|
650
650
|
const ref = normalizeStoredImageRef(node);
|
|
651
651
|
if (ref) {
|
|
652
|
-
const
|
|
653
|
-
const fileName = `${ref.id}.${ext}`;
|
|
652
|
+
const fileName = images.write(ref);
|
|
654
653
|
const relativePath = `./screenshots/${fileName}`;
|
|
655
|
-
const absolutePath = join(opts.screenshotsDir, fileName);
|
|
656
|
-
if (!opts.writtenFiles.has(fileName)) {
|
|
657
|
-
const resolved = resolveImageSource(ref, {
|
|
658
|
-
reportPath: opts.htmlPath
|
|
659
|
-
});
|
|
660
|
-
if ('data-uri' === resolved.type) {
|
|
661
|
-
const { rawBase64 } = parseBase64ImageDataUrl(resolved.dataUri);
|
|
662
|
-
writeFileSync(absolutePath, Buffer.from(rawBase64, 'base64'));
|
|
663
|
-
} else copyFileSync(resolved.filePath, absolutePath);
|
|
664
|
-
opts.writtenFiles.add(fileName);
|
|
665
|
-
}
|
|
666
654
|
ref.storage = 'file';
|
|
667
655
|
ref.path = relativePath;
|
|
668
656
|
return;
|
|
@@ -681,16 +669,12 @@ function splitReportHtmlByExecution(options) {
|
|
|
681
669
|
recursive: true
|
|
682
670
|
});
|
|
683
671
|
const executionJsonFiles = [];
|
|
684
|
-
const
|
|
672
|
+
const images = new ReportImageExporter(htmlPath, screenshotsDir);
|
|
685
673
|
const { baseDump, executions } = collectDedupedExecutions(htmlPath);
|
|
686
674
|
let fileIndex = 0;
|
|
687
675
|
for (const execution of executions){
|
|
688
676
|
fileIndex += 1;
|
|
689
|
-
externalizeImagesInExecution(execution,
|
|
690
|
-
htmlPath,
|
|
691
|
-
screenshotsDir,
|
|
692
|
-
writtenFiles: writtenScreenshotFiles
|
|
693
|
-
});
|
|
677
|
+
externalizeImagesInExecution(execution, images);
|
|
694
678
|
const singleExecutionDump = new ReportActionDump({
|
|
695
679
|
sdkVersion: baseDump.sdkVersion,
|
|
696
680
|
groupName: baseDump.groupName,
|
|
@@ -707,7 +691,7 @@ function splitReportHtmlByExecution(options) {
|
|
|
707
691
|
}
|
|
708
692
|
return {
|
|
709
693
|
executionJsonFiles,
|
|
710
|
-
screenshotFiles:
|
|
694
|
+
screenshotFiles: images.files
|
|
711
695
|
};
|
|
712
696
|
}
|
|
713
697
|
export { ExecutionRecorder, ReportArtifactStore, ReportMergingTool, ReportSession, TestRunReportAssembler, calculateTestRunHealth, classifyTestRunCase, collectDedupedExecutions, dedupeExecutionsKeepLatest, exportReportArtifact, isDirectoryModeReport, readReportActionDump, readReportArtifactManifest, readReportArtifactManifestAsync, readReportDumpScripts, readReportRunnerDump, removeReportArtifact, splitReportHtmlByExecution, streamReportDumpScripts };
|