@midscene/core 1.10.2 → 1.10.3
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.mjs +40 -1
- package/dist/es/agent/agent.mjs.map +1 -1
- package/dist/es/agent/metrics.mjs +81 -0
- package/dist/es/agent/metrics.mjs.map +1 -0
- package/dist/es/agent/task-builder.mjs +1 -1
- package/dist/es/agent/task-builder.mjs.map +1 -1
- package/dist/es/agent/utils.mjs +1 -1
- package/dist/es/ai-model/connectivity/run-connectivity-test.mjs +9 -3
- package/dist/es/ai-model/connectivity/run-connectivity-test.mjs.map +1 -1
- package/dist/es/ai-model/inspect.mjs +3 -3
- package/dist/es/ai-model/inspect.mjs.map +1 -1
- package/dist/es/ai-model/model-adapter/resolve.mjs +2 -2
- package/dist/es/ai-model/model-adapter/resolve.mjs.map +1 -1
- package/dist/es/ai-model/models/doubao.mjs +38 -60
- package/dist/es/ai-model/models/doubao.mjs.map +1 -1
- package/dist/es/ai-model/models/glm.mjs +4 -0
- package/dist/es/ai-model/models/glm.mjs.map +1 -1
- package/dist/es/ai-model/models/gpt.mjs +5 -1
- package/dist/es/ai-model/models/gpt.mjs.map +1 -1
- package/dist/es/ai-model/models/kimi.mjs +4 -0
- package/dist/es/ai-model/models/kimi.mjs.map +1 -1
- package/dist/es/ai-model/models/mimo.mjs +3 -2
- package/dist/es/ai-model/models/mimo.mjs.map +1 -1
- package/dist/es/ai-model/models/qwen.mjs.map +1 -1
- package/dist/es/ai-model/models/ui-tars/adapter.mjs +2 -41
- package/dist/es/ai-model/models/ui-tars/adapter.mjs.map +1 -1
- package/dist/es/ai-model/models/utils/intent.mjs +6 -0
- package/dist/es/ai-model/models/utils/intent.mjs.map +1 -0
- package/dist/es/ai-model/prompt/extraction.mjs +9 -3
- package/dist/es/ai-model/prompt/extraction.mjs.map +1 -1
- package/dist/es/ai-model/prompt/recorder-metadata-generator.mjs +2 -1
- package/dist/es/ai-model/prompt/recorder-metadata-generator.mjs.map +1 -1
- package/dist/es/ai-model/service-caller/index.mjs +40 -19
- package/dist/es/ai-model/service-caller/index.mjs.map +1 -1
- package/dist/es/ai-model/service-caller/json.mjs +31 -28
- package/dist/es/ai-model/service-caller/json.mjs.map +1 -1
- package/dist/es/dump/html-utils.mjs +63 -1
- package/dist/es/dump/html-utils.mjs.map +1 -1
- package/dist/es/dump/screenshot-restoration.mjs +6 -0
- package/dist/es/dump/screenshot-restoration.mjs.map +1 -1
- package/dist/es/index.mjs.map +1 -1
- package/dist/es/report-generator.mjs +28 -1
- package/dist/es/report-generator.mjs.map +1 -1
- package/dist/es/report-markdown.mjs +300 -35
- package/dist/es/report-markdown.mjs.map +1 -1
- package/dist/es/report.mjs +29 -1
- package/dist/es/report.mjs.map +1 -1
- package/dist/es/service/index.mjs +3 -3
- package/dist/es/service/index.mjs.map +1 -1
- package/dist/es/types.mjs.map +1 -1
- package/dist/es/utils.mjs +2 -2
- package/dist/lib/agent/agent.js +40 -1
- package/dist/lib/agent/agent.js.map +1 -1
- package/dist/lib/agent/metrics.js +115 -0
- package/dist/lib/agent/metrics.js.map +1 -0
- package/dist/lib/agent/task-builder.js +1 -1
- package/dist/lib/agent/task-builder.js.map +1 -1
- package/dist/lib/agent/utils.js +1 -1
- package/dist/lib/ai-model/connectivity/run-connectivity-test.js +9 -3
- package/dist/lib/ai-model/connectivity/run-connectivity-test.js.map +1 -1
- package/dist/lib/ai-model/inspect.js +3 -3
- package/dist/lib/ai-model/inspect.js.map +1 -1
- package/dist/lib/ai-model/model-adapter/resolve.js +1 -1
- package/dist/lib/ai-model/model-adapter/resolve.js.map +1 -1
- package/dist/lib/ai-model/models/doubao.js +38 -69
- package/dist/lib/ai-model/models/doubao.js.map +1 -1
- package/dist/lib/ai-model/models/glm.js +4 -0
- package/dist/lib/ai-model/models/glm.js.map +1 -1
- package/dist/lib/ai-model/models/gpt.js +5 -1
- package/dist/lib/ai-model/models/gpt.js.map +1 -1
- package/dist/lib/ai-model/models/kimi.js +4 -0
- package/dist/lib/ai-model/models/kimi.js.map +1 -1
- package/dist/lib/ai-model/models/mimo.js +3 -2
- package/dist/lib/ai-model/models/mimo.js.map +1 -1
- package/dist/lib/ai-model/models/qwen.js.map +1 -1
- package/dist/lib/ai-model/models/ui-tars/adapter.js +1 -40
- package/dist/lib/ai-model/models/ui-tars/adapter.js.map +1 -1
- package/dist/lib/ai-model/models/utils/intent.js +40 -0
- package/dist/lib/ai-model/models/utils/intent.js.map +1 -0
- package/dist/lib/ai-model/prompt/extraction.js +8 -2
- package/dist/lib/ai-model/prompt/extraction.js.map +1 -1
- package/dist/lib/ai-model/prompt/recorder-metadata-generator.js +4 -3
- package/dist/lib/ai-model/prompt/recorder-metadata-generator.js.map +1 -1
- package/dist/lib/ai-model/service-caller/index.js +44 -23
- package/dist/lib/ai-model/service-caller/index.js.map +1 -1
- package/dist/lib/ai-model/service-caller/json.js +33 -33
- package/dist/lib/ai-model/service-caller/json.js.map +1 -1
- package/dist/lib/dump/html-utils.js +65 -0
- package/dist/lib/dump/html-utils.js.map +1 -1
- package/dist/lib/dump/screenshot-restoration.js +6 -0
- package/dist/lib/dump/screenshot-restoration.js.map +1 -1
- package/dist/lib/index.js.map +1 -1
- package/dist/lib/report-generator.js +27 -0
- package/dist/lib/report-generator.js.map +1 -1
- package/dist/lib/report-markdown.js +300 -35
- package/dist/lib/report-markdown.js.map +1 -1
- package/dist/lib/report.js +28 -0
- package/dist/lib/report.js.map +1 -1
- package/dist/lib/service/index.js +3 -3
- package/dist/lib/service/index.js.map +1 -1
- package/dist/lib/types.js.map +1 -1
- package/dist/lib/utils.js +2 -2
- package/dist/types/agent/agent.d.ts +15 -0
- package/dist/types/agent/index.d.ts +1 -0
- package/dist/types/agent/metrics.d.ts +48 -0
- package/dist/types/ai-model/model-adapter/types.d.ts +8 -0
- package/dist/types/ai-model/models/doubao.d.ts +1 -4
- package/dist/types/ai-model/models/utils/intent.d.ts +2 -0
- package/dist/types/ai-model/service-caller/index.d.ts +8 -3
- package/dist/types/ai-model/service-caller/json.d.ts +19 -2
- package/dist/types/dump/html-utils.d.ts +2 -0
- package/dist/types/dump/screenshot-restoration.d.ts +1 -1
- package/dist/types/index.d.ts +1 -1
- package/dist/types/report-generator.d.ts +6 -0
- package/dist/types/types.d.ts +11 -2
- package/package.json +3 -3
|
@@ -1,7 +1,9 @@
|
|
|
1
|
-
import { basename } from "node:path";
|
|
2
1
|
import { extractInsightParam, paramStr, typeStr } from "./agent/ui-utils.mjs";
|
|
3
2
|
import { ScreenshotItem } from "./screenshot-item.mjs";
|
|
4
3
|
import { normalizeScreenshotRef } from "./dump/screenshot-store.mjs";
|
|
4
|
+
const screenshotDataUrlPattern = /^data:image\/(png|jpeg|jpg);base64,([\s\S]*)$/i;
|
|
5
|
+
const rawBase64BodyPattern = /^[a-zA-Z0-9+/=\s]+$/;
|
|
6
|
+
const jsonContextMaxStringLength = 12000;
|
|
5
7
|
function toExecutionDump(execution) {
|
|
6
8
|
if (!execution || 'object' != typeof execution) throw new Error('executionToMarkdown: execution is required');
|
|
7
9
|
if (!Array.isArray(execution.tasks)) throw new Error('executionToMarkdown: execution.tasks must be an array');
|
|
@@ -17,6 +19,165 @@ function formatTime(ts) {
|
|
|
17
19
|
if ('number' != typeof ts || Number.isNaN(ts)) return 'N/A';
|
|
18
20
|
return new Date(ts).toISOString();
|
|
19
21
|
}
|
|
22
|
+
function formatValue(value) {
|
|
23
|
+
if (null == value || '' === value) return 'N/A';
|
|
24
|
+
if ('number' == typeof value) return Number.isFinite(value) ? String(value) : 'N/A';
|
|
25
|
+
return String(value);
|
|
26
|
+
}
|
|
27
|
+
function escapeTableCell(value) {
|
|
28
|
+
return formatValue(value).replace(/\|/g, '\\|').replace(/\n/g, '<br>');
|
|
29
|
+
}
|
|
30
|
+
function markdownTable(headers, rows) {
|
|
31
|
+
return [
|
|
32
|
+
`| ${headers.map(escapeTableCell).join(' | ')} |`,
|
|
33
|
+
`| ${headers.map(()=>'---').join(' | ')} |`,
|
|
34
|
+
...rows.map((row)=>`| ${row.map(escapeTableCell).join(' | ')} |`)
|
|
35
|
+
];
|
|
36
|
+
}
|
|
37
|
+
function modelBriefRows(modelBriefs) {
|
|
38
|
+
return modelBriefs.map((brief)=>[
|
|
39
|
+
brief.intent || 'default',
|
|
40
|
+
brief.name || 'N/A',
|
|
41
|
+
brief.modelDescription || 'N/A'
|
|
42
|
+
]);
|
|
43
|
+
}
|
|
44
|
+
function modelRowsFromUsage(report) {
|
|
45
|
+
const rows = new Map();
|
|
46
|
+
const addUsage = (source, usage)=>{
|
|
47
|
+
if (!hasUsage(usage)) return;
|
|
48
|
+
const intent = usage.intent || source;
|
|
49
|
+
const model = usage.model_name || usage.response_model_name;
|
|
50
|
+
const description = usage.model_description;
|
|
51
|
+
const key = `${intent}\0${model || ''}\0${description || ''}`;
|
|
52
|
+
if (rows.has(key)) return;
|
|
53
|
+
rows.set(key, [
|
|
54
|
+
intent,
|
|
55
|
+
model || 'N/A',
|
|
56
|
+
description || 'N/A'
|
|
57
|
+
]);
|
|
58
|
+
};
|
|
59
|
+
for (const execution of report.executions)for (const task of execution.tasks){
|
|
60
|
+
const taskWithUsage = task;
|
|
61
|
+
addUsage('main', taskWithUsage.usage);
|
|
62
|
+
addUsage('searchArea', taskWithUsage.searchAreaUsage);
|
|
63
|
+
}
|
|
64
|
+
return Array.from(rows.values());
|
|
65
|
+
}
|
|
66
|
+
function usageValue(usage, key) {
|
|
67
|
+
const value = usage?.[key];
|
|
68
|
+
return 'number' == typeof value && Number.isFinite(value) ? value : 0;
|
|
69
|
+
}
|
|
70
|
+
function hasUsage(usage) {
|
|
71
|
+
if (!usage) return false;
|
|
72
|
+
return [
|
|
73
|
+
'intent',
|
|
74
|
+
'model_name',
|
|
75
|
+
"model_description",
|
|
76
|
+
'prompt_tokens',
|
|
77
|
+
'cached_input',
|
|
78
|
+
'completion_tokens',
|
|
79
|
+
'total_tokens',
|
|
80
|
+
'time_cost',
|
|
81
|
+
'request_id'
|
|
82
|
+
].some((key)=>void 0 !== usage[key] && null !== usage[key]);
|
|
83
|
+
}
|
|
84
|
+
function usageTotalTokens(usage) {
|
|
85
|
+
const explicitTotal = usageValue(usage, 'total_tokens');
|
|
86
|
+
if (explicitTotal > 0) return explicitTotal;
|
|
87
|
+
return usageValue(usage, 'prompt_tokens') + usageValue(usage, 'completion_tokens');
|
|
88
|
+
}
|
|
89
|
+
function usageModelName(usage) {
|
|
90
|
+
return usage.model_name || usage.response_model_name || usage.model_description || usage.intent || 'Unknown';
|
|
91
|
+
}
|
|
92
|
+
function usageRowsForTask(task) {
|
|
93
|
+
const taskWithUsage = task;
|
|
94
|
+
const rows = [];
|
|
95
|
+
const appendUsage = (source, usage)=>{
|
|
96
|
+
if (!hasUsage(usage)) return;
|
|
97
|
+
rows.push([
|
|
98
|
+
source,
|
|
99
|
+
usage.intent,
|
|
100
|
+
usage.model_name || usage.response_model_name,
|
|
101
|
+
usage.model_description,
|
|
102
|
+
usageValue(usage, 'prompt_tokens'),
|
|
103
|
+
usageValue(usage, 'cached_input'),
|
|
104
|
+
usageValue(usage, 'completion_tokens'),
|
|
105
|
+
usageTotalTokens(usage),
|
|
106
|
+
usageValue(usage, 'time_cost'),
|
|
107
|
+
usage.request_id
|
|
108
|
+
]);
|
|
109
|
+
};
|
|
110
|
+
appendUsage('main', taskWithUsage.usage);
|
|
111
|
+
appendUsage('searchArea', taskWithUsage.searchAreaUsage);
|
|
112
|
+
return rows;
|
|
113
|
+
}
|
|
114
|
+
function collectUsageTotals(report) {
|
|
115
|
+
const totalsByModel = new Map();
|
|
116
|
+
const addUsage = (usage)=>{
|
|
117
|
+
if (!hasUsage(usage)) return;
|
|
118
|
+
const modelName = usageModelName(usage);
|
|
119
|
+
const current = totalsByModel.get(modelName) ?? {
|
|
120
|
+
calls: 0,
|
|
121
|
+
prompt: 0,
|
|
122
|
+
cachedInput: 0,
|
|
123
|
+
completion: 0,
|
|
124
|
+
total: 0,
|
|
125
|
+
timeCost: 0
|
|
126
|
+
};
|
|
127
|
+
totalsByModel.set(modelName, {
|
|
128
|
+
calls: current.calls + 1,
|
|
129
|
+
prompt: current.prompt + usageValue(usage, 'prompt_tokens'),
|
|
130
|
+
cachedInput: current.cachedInput + usageValue(usage, 'cached_input'),
|
|
131
|
+
completion: current.completion + usageValue(usage, 'completion_tokens'),
|
|
132
|
+
total: current.total + usageTotalTokens(usage),
|
|
133
|
+
timeCost: current.timeCost + usageValue(usage, 'time_cost')
|
|
134
|
+
});
|
|
135
|
+
};
|
|
136
|
+
for (const execution of report.executions)for (const task of execution.tasks){
|
|
137
|
+
const taskWithUsage = task;
|
|
138
|
+
addUsage(taskWithUsage.usage);
|
|
139
|
+
addUsage(taskWithUsage.searchAreaUsage);
|
|
140
|
+
}
|
|
141
|
+
return totalsByModel;
|
|
142
|
+
}
|
|
143
|
+
function sanitizeJsonForMarkdown(value, seen = new WeakSet()) {
|
|
144
|
+
if ('string' == typeof value) {
|
|
145
|
+
if (screenshotDataUrlPattern.test(value) || value.length > 1000000 || /^[a-zA-Z0-9+/=\s]{100000,}$/.test(value)) return `[omitted image/base64 string, length=${value.length}]`;
|
|
146
|
+
if (value.length > jsonContextMaxStringLength) return `${value.slice(0, jsonContextMaxStringLength)}\n[truncated, original length=${value.length}]`;
|
|
147
|
+
return value;
|
|
148
|
+
}
|
|
149
|
+
if (null === value || 'number' == typeof value || 'boolean' == typeof value) return value;
|
|
150
|
+
if ('function' == typeof value) return '[omitted function]';
|
|
151
|
+
if ('object' != typeof value || void 0 === value) return;
|
|
152
|
+
if (seen.has(value)) return '[omitted circular reference]';
|
|
153
|
+
seen.add(value);
|
|
154
|
+
if (Array.isArray(value)) return value.map((item)=>sanitizeJsonForMarkdown(item, seen));
|
|
155
|
+
const input = value;
|
|
156
|
+
const output = {};
|
|
157
|
+
for (const [key, entry] of Object.entries(input))if (void 0 !== entry && 'function' != typeof entry) {
|
|
158
|
+
if ('string' == typeof entry && /(^|_|-)(base64|screenshotBase64|imageBase64)$/i.test(key)) {
|
|
159
|
+
output[key] = `[omitted base64 string, length=${entry.length}]`;
|
|
160
|
+
continue;
|
|
161
|
+
}
|
|
162
|
+
output[key] = sanitizeJsonForMarkdown(entry, seen);
|
|
163
|
+
}
|
|
164
|
+
seen.delete(value);
|
|
165
|
+
return output;
|
|
166
|
+
}
|
|
167
|
+
function appendJsonSection(lines, title, value) {
|
|
168
|
+
if (null == value || '' === value) return;
|
|
169
|
+
const sanitized = sanitizeJsonForMarkdown(value);
|
|
170
|
+
if (void 0 === sanitized) return;
|
|
171
|
+
lines.push('', `### ${title}`, '', '```json');
|
|
172
|
+
lines.push(JSON.stringify(sanitized, null, 2));
|
|
173
|
+
lines.push('```');
|
|
174
|
+
}
|
|
175
|
+
function appendTextSection(lines, title, value) {
|
|
176
|
+
if ('string' != typeof value || !value.trim()) return;
|
|
177
|
+
lines.push('', `### ${title}`, '', '```text');
|
|
178
|
+
lines.push(value.replace(/```/g, '` ` `'));
|
|
179
|
+
lines.push('```');
|
|
180
|
+
}
|
|
20
181
|
function resolveTaskTiming(task) {
|
|
21
182
|
const timing = task.timing;
|
|
22
183
|
if (!timing) return {};
|
|
@@ -57,16 +218,35 @@ function extractLocateCenter(task) {
|
|
|
57
218
|
];
|
|
58
219
|
}
|
|
59
220
|
function tryExtractBase64(screenshot) {
|
|
221
|
+
if ('string' == typeof screenshot) {
|
|
222
|
+
const trimmedScreenshot = screenshot.trim();
|
|
223
|
+
const dataUrlMatch = trimmedScreenshot.match(screenshotDataUrlPattern);
|
|
224
|
+
if (dataUrlMatch) {
|
|
225
|
+
const format = 'jpg' === dataUrlMatch[1].toLowerCase() ? 'jpeg' : 'png';
|
|
226
|
+
const base64Body = dataUrlMatch[2].replace(/\s/g, '');
|
|
227
|
+
if (!base64Body) return;
|
|
228
|
+
return `data:image/${format};base64,${base64Body}`;
|
|
229
|
+
}
|
|
230
|
+
if (trimmedScreenshot.startsWith('data:') || !rawBase64BodyPattern.test(trimmedScreenshot)) return;
|
|
231
|
+
const base64Body = trimmedScreenshot.replace(/\s/g, '');
|
|
232
|
+
return base64Body ? `data:image/png;base64,${base64Body}` : void 0;
|
|
233
|
+
}
|
|
60
234
|
if (!screenshot || 'object' != typeof screenshot) return;
|
|
61
235
|
const s = screenshot;
|
|
62
236
|
if ('string' == typeof s.base64 && s.base64.length > 0) return s.base64;
|
|
63
237
|
}
|
|
64
|
-
function
|
|
238
|
+
function restoredSourceRef(screenshot) {
|
|
239
|
+
if (!screenshot || 'object' != typeof screenshot) return;
|
|
240
|
+
const sourceRef = screenshot.sourceRef;
|
|
241
|
+
return normalizeScreenshotRef(sourceRef) ?? void 0;
|
|
242
|
+
}
|
|
243
|
+
function screenshotAttachment(screenshot, screenshotBaseDir, executionIndex, taskIndex, options) {
|
|
244
|
+
const markdownLabel = options?.label || `task-${taskIndex + 1}`;
|
|
65
245
|
if (screenshot instanceof ScreenshotItem) {
|
|
66
246
|
const ext = screenshot.extension;
|
|
67
247
|
const suggestedFileName = `execution-${executionIndex + 1}-task-${taskIndex + 1}-${screenshot.id}.${ext}`;
|
|
68
248
|
return {
|
|
69
|
-
markdown: `\n`,
|
|
70
250
|
attachment: {
|
|
71
251
|
id: screenshot.id,
|
|
72
252
|
suggestedFileName,
|
|
@@ -82,7 +262,7 @@ function screenshotAttachment(screenshot, screenshotBaseDir, executionIndex, tas
|
|
|
82
262
|
const ext = 'image/jpeg' === ref.mimeType ? 'jpeg' : 'png';
|
|
83
263
|
const suggestedFileName = `execution-${executionIndex + 1}-task-${taskIndex + 1}-${ref.id}.${ext}`;
|
|
84
264
|
return {
|
|
85
|
-
markdown: `\n`,
|
|
86
266
|
attachment: {
|
|
87
267
|
id: ref.id,
|
|
88
268
|
suggestedFileName,
|
|
@@ -94,13 +274,31 @@ function screenshotAttachment(screenshot, screenshotBaseDir, executionIndex, tas
|
|
|
94
274
|
}
|
|
95
275
|
};
|
|
96
276
|
}
|
|
277
|
+
const sourceRef = restoredSourceRef(screenshot);
|
|
278
|
+
if (sourceRef) {
|
|
279
|
+
const ext = 'image/jpeg' === sourceRef.mimeType ? 'jpeg' : 'png';
|
|
280
|
+
const suggestedFileName = `execution-${executionIndex + 1}-task-${taskIndex + 1}-${sourceRef.id}.${ext}`;
|
|
281
|
+
return {
|
|
282
|
+
markdown: `\n`,
|
|
283
|
+
attachment: {
|
|
284
|
+
id: sourceRef.id,
|
|
285
|
+
suggestedFileName,
|
|
286
|
+
sourceRef,
|
|
287
|
+
mimeType: sourceRef.mimeType,
|
|
288
|
+
executionIndex,
|
|
289
|
+
taskIndex,
|
|
290
|
+
base64Data: tryExtractBase64(screenshot)
|
|
291
|
+
}
|
|
292
|
+
};
|
|
293
|
+
}
|
|
97
294
|
const base64 = tryExtractBase64(screenshot);
|
|
98
295
|
if (base64) {
|
|
99
296
|
const ext = base64.startsWith('data:image/jpeg') ? 'jpeg' : 'png';
|
|
100
|
-
const
|
|
297
|
+
const idSuffix = options?.fallbackIdSuffix ? `-${options.fallbackIdSuffix}` : '';
|
|
298
|
+
const id = `restored-${executionIndex + 1}-${taskIndex + 1}${idSuffix}`;
|
|
101
299
|
const suggestedFileName = `execution-${executionIndex + 1}-task-${taskIndex + 1}-${id}.${ext}`;
|
|
102
300
|
return {
|
|
103
|
-
markdown: `\n`,
|
|
104
302
|
attachment: {
|
|
105
303
|
id,
|
|
106
304
|
suggestedFileName,
|
|
@@ -113,27 +311,46 @@ function screenshotAttachment(screenshot, screenshotBaseDir, executionIndex, tas
|
|
|
113
311
|
}
|
|
114
312
|
throw new Error(`executionToMarkdown: missing screenshot for execution #${executionIndex + 1} task #${taskIndex + 1}`);
|
|
115
313
|
}
|
|
116
|
-
function
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
};
|
|
314
|
+
function imageLabelSuffix(value) {
|
|
315
|
+
return value.toLowerCase().replace(/[^a-z0-9._-]+/g, '-').replace(/-+/g, '-').replace(/^-|-$/g, '') || 'screenshot';
|
|
316
|
+
}
|
|
317
|
+
function screenshotsMarkdownSection(task, screenshotBaseDir, executionIndex, taskIndex) {
|
|
121
318
|
const lines = [
|
|
122
319
|
'',
|
|
123
|
-
'###
|
|
320
|
+
'### Screenshots'
|
|
124
321
|
];
|
|
125
322
|
const attachments = [];
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
323
|
+
let screenshotIndex = 0;
|
|
324
|
+
if (task.uiContext?.screenshot) {
|
|
325
|
+
const imageResult = screenshotAttachment(task.uiContext.screenshot, screenshotBaseDir, executionIndex, taskIndex, {
|
|
326
|
+
fallbackIdSuffix: 'ui-context',
|
|
327
|
+
label: `task-${taskIndex + 1}-ui-context`
|
|
328
|
+
});
|
|
329
|
+
const time = resolveTaskTiming(task);
|
|
330
|
+
screenshotIndex += 1;
|
|
331
|
+
lines.push(`- #${screenshotIndex} type=ui-context, ts=${formatTime(time.start)}, timing=ui-context`);
|
|
332
|
+
lines.push(imageResult.markdown);
|
|
333
|
+
attachments.push(imageResult.attachment);
|
|
334
|
+
}
|
|
335
|
+
task.recorder?.forEach((item, recorderIndex)=>{
|
|
129
336
|
if (!item.screenshot) return;
|
|
130
|
-
const
|
|
337
|
+
const descriptionText = item.description ? `, description=${item.description}` : '';
|
|
338
|
+
const timing = item.timing || 'N/A';
|
|
339
|
+
screenshotIndex += 1;
|
|
340
|
+
lines.push(`- #${screenshotIndex} type=${item.type}, ts=${formatTime(item.ts)}, timing=${timing}${descriptionText}`);
|
|
341
|
+
const imageResult = screenshotAttachment(item.screenshot, screenshotBaseDir, executionIndex, taskIndex, {
|
|
342
|
+
fallbackIdSuffix: `recorder-${recorderIndex + 1}`,
|
|
343
|
+
label: `task-${taskIndex + 1}-${imageLabelSuffix(timing)}`
|
|
344
|
+
});
|
|
131
345
|
lines.push(imageResult.markdown);
|
|
132
346
|
attachments.push(imageResult.attachment);
|
|
133
347
|
});
|
|
134
|
-
return {
|
|
348
|
+
return screenshotIndex > 0 ? {
|
|
135
349
|
lines,
|
|
136
350
|
attachments
|
|
351
|
+
} : {
|
|
352
|
+
lines: [],
|
|
353
|
+
attachments
|
|
137
354
|
};
|
|
138
355
|
}
|
|
139
356
|
function renderExecution(executionRaw, executionIndex, options) {
|
|
@@ -145,11 +362,15 @@ function renderExecution(executionRaw, executionIndex, options) {
|
|
|
145
362
|
if (execution.description) lines.push('', execution.description);
|
|
146
363
|
lines.push('', `- Execution start: ${formatTime(execution.logTime)}`);
|
|
147
364
|
lines.push(`- Task count: ${execution.tasks.length}`);
|
|
365
|
+
if (execution.aiActContext) appendTextSection(lines, 'AI Action Context', execution.aiActContext);
|
|
148
366
|
execution.tasks.forEach((task, taskIndex)=>{
|
|
149
367
|
const title = typeStr(task);
|
|
150
368
|
const detail = safeTaskParam(task);
|
|
151
369
|
const time = resolveTaskTiming(task);
|
|
152
370
|
lines.push('', `## ${taskIndex + 1}. ${title}${detail ? ` - ${detail}` : ''}`);
|
|
371
|
+
lines.push(`- Task ID: ${task.taskId || 'N/A'}`);
|
|
372
|
+
lines.push(`- Type: ${task.type || 'N/A'}`);
|
|
373
|
+
lines.push(`- SubType: ${task.subType || 'N/A'}`);
|
|
153
374
|
lines.push(`- Status: ${task.status || 'unknown'}`);
|
|
154
375
|
lines.push(`- Start: ${formatTime(time.start)}`);
|
|
155
376
|
lines.push(`- End: ${formatTime(time.end)}`);
|
|
@@ -160,15 +381,31 @@ function renderExecution(executionRaw, executionIndex, options) {
|
|
|
160
381
|
if (locateCenter) lines.push(`- Locate center: (${locateCenter[0]}, ${locateCenter[1]})`);
|
|
161
382
|
}
|
|
162
383
|
if (task.errorMessage) lines.push(`- Error: ${task.errorMessage}`);
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
lines.push(
|
|
166
|
-
|
|
384
|
+
const usageRows = usageRowsForTask(task);
|
|
385
|
+
if (usageRows.length) {
|
|
386
|
+
lines.push('', '### Model Usage');
|
|
387
|
+
lines.push(...markdownTable([
|
|
388
|
+
'Source',
|
|
389
|
+
'Intent',
|
|
390
|
+
'Model',
|
|
391
|
+
"Description",
|
|
392
|
+
'Prompt Tokens',
|
|
393
|
+
'Cached Input',
|
|
394
|
+
'Completion Tokens',
|
|
395
|
+
'Total Tokens',
|
|
396
|
+
'Time Cost(ms)',
|
|
397
|
+
'Request ID'
|
|
398
|
+
], usageRows));
|
|
167
399
|
}
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
400
|
+
appendJsonSection(lines, 'Param', task.param);
|
|
401
|
+
appendJsonSection(lines, 'Output', task.output);
|
|
402
|
+
appendJsonSection(lines, 'Log', task.log);
|
|
403
|
+
appendTextSection(lines, 'Thought', task.thought);
|
|
404
|
+
appendTextSection(lines, 'Reasoning Content', task.reasoning_content);
|
|
405
|
+
const screenshotsSection = screenshotsMarkdownSection(task, screenshotBaseDir, executionIndex, taskIndex);
|
|
406
|
+
if (screenshotsSection.lines.length) {
|
|
407
|
+
lines.push(...screenshotsSection.lines);
|
|
408
|
+
attachments.push(...screenshotsSection.attachments);
|
|
172
409
|
}
|
|
173
410
|
});
|
|
174
411
|
return {
|
|
@@ -176,10 +413,6 @@ function renderExecution(executionRaw, executionIndex, options) {
|
|
|
176
413
|
attachments
|
|
177
414
|
};
|
|
178
415
|
}
|
|
179
|
-
function reportFileName(execution, executionIndex) {
|
|
180
|
-
const safeName = execution.name.trim().replace(/\s+/g, '-').replace(/[^a-zA-Z0-9-_]/g, '') || `execution-${executionIndex + 1}`;
|
|
181
|
-
return `${executionIndex + 1}-${basename(safeName)}.md`;
|
|
182
|
-
}
|
|
183
416
|
function executionToMarkdown(execution, options) {
|
|
184
417
|
return renderExecution(execution, 0, options);
|
|
185
418
|
}
|
|
@@ -188,21 +421,53 @@ function reportToMarkdown(report) {
|
|
|
188
421
|
const executionResults = reportDump.executions.map((execution, index)=>{
|
|
189
422
|
const rendered = renderExecution(execution, index);
|
|
190
423
|
return {
|
|
191
|
-
executionIndex: index,
|
|
192
|
-
executionName: execution.name,
|
|
193
424
|
markdown: rendered.markdown,
|
|
194
|
-
attachments: rendered.attachments
|
|
195
|
-
suggestedFileName: reportFileName(execution, index)
|
|
425
|
+
attachments: rendered.attachments
|
|
196
426
|
};
|
|
197
427
|
});
|
|
198
428
|
const attachments = executionResults.flatMap((item)=>item.attachments);
|
|
429
|
+
const usageTotals = collectUsageTotals(reportDump);
|
|
430
|
+
const modelRows = reportDump.modelBriefs?.length ? modelBriefRows(reportDump.modelBriefs) : modelRowsFromUsage(reportDump);
|
|
431
|
+
const modelInfoLines = [
|
|
432
|
+
'\n## Model Info',
|
|
433
|
+
...modelRows.length ? markdownTable([
|
|
434
|
+
'Intent',
|
|
435
|
+
'Model',
|
|
436
|
+
"Description"
|
|
437
|
+
], modelRows) : [
|
|
438
|
+
'- No model metadata recorded.'
|
|
439
|
+
]
|
|
440
|
+
];
|
|
441
|
+
const tokenSummaryLines = [
|
|
442
|
+
'\n## Token Usage Summary',
|
|
443
|
+
...usageTotals.size ? markdownTable([
|
|
444
|
+
'Model',
|
|
445
|
+
'Calls',
|
|
446
|
+
'Prompt Tokens',
|
|
447
|
+
'Cached Input',
|
|
448
|
+
'Completion Tokens',
|
|
449
|
+
'Total Tokens',
|
|
450
|
+
'Time Cost(ms)'
|
|
451
|
+
], Array.from(usageTotals.entries()).map(([modelName, totals])=>[
|
|
452
|
+
modelName,
|
|
453
|
+
totals.calls,
|
|
454
|
+
totals.prompt,
|
|
455
|
+
totals.cachedInput,
|
|
456
|
+
totals.completion,
|
|
457
|
+
totals.total,
|
|
458
|
+
totals.timeCost
|
|
459
|
+
])) : [
|
|
460
|
+
'- No token usage recorded.'
|
|
461
|
+
]
|
|
462
|
+
];
|
|
199
463
|
const header = [
|
|
200
464
|
`# ${reportDump.groupName}`,
|
|
201
465
|
reportDump.groupDescription ? `\n${reportDump.groupDescription}` : '',
|
|
202
466
|
`\n- SDK Version: ${reportDump.sdkVersion}`,
|
|
467
|
+
reportDump.deviceType ? `- Device Type: ${reportDump.deviceType}` : '',
|
|
203
468
|
`- Execution count: ${reportDump.executions.length}`,
|
|
204
|
-
|
|
205
|
-
...
|
|
469
|
+
...modelInfoLines,
|
|
470
|
+
...tokenSummaryLines
|
|
206
471
|
].filter(Boolean).join('\n');
|
|
207
472
|
return {
|
|
208
473
|
markdown: `${header}\n\n${executionResults.map((item)=>item.markdown).join('\n\n---\n\n')}`,
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"report-markdown.mjs","sources":["../../src/report-markdown.ts"],"sourcesContent":["import { basename } from 'node:path';\nimport { extractInsightParam, paramStr, typeStr } from '@/agent/ui-utils';\nimport { ScreenshotItem } from '@/screenshot-item';\nimport type {\n ExecutionDump,\n ExecutionRecorderItem,\n ExecutionTask,\n IExecutionDump,\n IReportActionDump,\n ReportActionDump,\n} from '@/types';\nimport type { ScreenshotRef } from './dump/screenshot-store';\nimport { normalizeScreenshotRef } from './dump/screenshot-store';\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 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 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 (!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 screenshotAttachment(\n screenshot: unknown,\n screenshotBaseDir: string,\n executionIndex: number,\n taskIndex: number,\n): { markdown: string; attachment: MarkdownAttachment } {\n if (screenshot instanceof ScreenshotItem) {\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 = ref.mimeType === 'image/jpeg' ? 'jpeg' : 'png';\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 base64 = tryExtractBase64(screenshot);\n if (base64) {\n const ext = base64.startsWith('data:image/jpeg') ? 'jpeg' : 'png';\n const id = `restored-${executionIndex + 1}-${taskIndex + 1}`;\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 recorderMarkdownSection(\n recorder: ExecutionRecorderItem[] | undefined,\n screenshotBaseDir: string,\n executionIndex: number,\n taskIndex: number,\n): { lines: string[]; attachments: MarkdownAttachment[] } {\n if (!recorder?.length) {\n return { lines: [], attachments: [] };\n }\n\n const lines: string[] = ['', '### Recorder'];\n const attachments: MarkdownAttachment[] = [];\n\n recorder.forEach((item, recorderIndex) => {\n const descriptionText = item.description\n ? `, description=${item.description}`\n : '';\n lines.push(\n `- #${recorderIndex + 1} type=${item.type}, ts=${formatTime(item.ts)}, timing=${item.timing || 'N/A'}${descriptionText}`,\n );\n\n if (!item.screenshot) {\n return;\n }\n\n const imageResult = screenshotAttachment(\n item.screenshot,\n screenshotBaseDir,\n executionIndex,\n taskIndex,\n );\n\n lines.push(imageResult.markdown);\n attachments.push(imageResult.attachment);\n });\n\n return { 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\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(`- 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 if (task.uiContext?.screenshot) {\n const imageResult = screenshotAttachment(\n task.uiContext.screenshot,\n screenshotBaseDir,\n executionIndex,\n taskIndex,\n );\n\n lines.push(imageResult.markdown);\n attachments.push(imageResult.attachment);\n }\n\n const recorderSection = recorderMarkdownSection(\n task.recorder,\n screenshotBaseDir,\n executionIndex,\n taskIndex,\n );\n if (recorderSection.lines.length) {\n lines.push(...recorderSection.lines);\n attachments.push(...recorderSection.attachments);\n }\n });\n\n return {\n markdown: lines.join('\\n'),\n attachments,\n };\n}\n\nfunction reportFileName(\n execution: IExecutionDump,\n executionIndex: number,\n): string {\n const safeName =\n execution.name\n .trim()\n .replace(/\\s+/g, '-')\n .replace(/[^a-zA-Z0-9-_]/g, '') || `execution-${executionIndex + 1}`;\n return `${executionIndex + 1}-${basename(safeName)}.md`;\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): ReportMarkdownResult {\n const reportDump = toReportDump(report);\n\n const executionResults = reportDump.executions.map((execution, index) => {\n const rendered = renderExecution(execution, index);\n return {\n executionIndex: index,\n executionName: execution.name,\n markdown: rendered.markdown,\n attachments: rendered.attachments,\n suggestedFileName: reportFileName(execution, index),\n };\n });\n\n const attachments = executionResults.flatMap((item) => item.attachments);\n\n const header = [\n `# ${reportDump.groupName}`,\n reportDump.groupDescription ? `\\n${reportDump.groupDescription}` : '',\n `\\n- SDK Version: ${reportDump.sdkVersion}`,\n `- Execution count: ${reportDump.executions.length}`,\n '\\n## Suggested execution markdown files',\n ...executionResults.map(\n (item) => `- ${item.suggestedFileName} (${item.executionName})`,\n ),\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":["toExecutionDump","execution","Error","Array","toReportDump","report","formatTime","ts","Number","Date","resolveTaskTiming","task","timing","start","end","cost","undefined","safeTaskParam","readable","paramStr","extractInsightParam","formatSize","size","extractLocateCenter","outputCenter","paramLocateCenter","paramCenter","tryExtractBase64","screenshot","s","screenshotAttachment","screenshotBaseDir","executionIndex","taskIndex","ScreenshotItem","ext","suggestedFileName","ref","normalizeScreenshotRef","base64","id","recorderMarkdownSection","recorder","lines","attachments","item","recorderIndex","descriptionText","imageResult","renderExecution","executionRaw","options","title","typeStr","detail","time","locateCenter","recorderSection","reportFileName","safeName","basename","executionToMarkdown","reportToMarkdown","reportDump","executionResults","index","rendered","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 { normalizeScreenshotRef } from './dump/screenshot-store';\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\ninterface UsageTotals {\n calls: number;\n prompt: number;\n cachedInput: number;\n completion: number;\n total: number;\n timeCost: number;\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 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 usageModelName(usage: AIUsageInfo): string {\n return (\n usage.model_name ||\n usage.response_model_name ||\n usage.model_description ||\n usage.intent ||\n 'Unknown'\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 collectUsageTotals(\n report: IReportActionDump,\n): Map<string, UsageTotals> {\n const totalsByModel = new Map<string, UsageTotals>();\n const addUsage = (usage?: AIUsageInfo) => {\n if (!hasUsage(usage)) return;\n const modelName = usageModelName(usage);\n const current = totalsByModel.get(modelName) ?? {\n calls: 0,\n prompt: 0,\n cachedInput: 0,\n completion: 0,\n total: 0,\n timeCost: 0,\n };\n\n totalsByModel.set(modelName, {\n calls: current.calls + 1,\n prompt: current.prompt + usageValue(usage, 'prompt_tokens'),\n cachedInput: current.cachedInput + usageValue(usage, 'cached_input'),\n completion: current.completion + usageValue(usage, 'completion_tokens'),\n total: current.total + usageTotalTokens(usage),\n timeCost: current.timeCost + usageValue(usage, 'time_cost'),\n });\n };\n\n for (const execution of report.executions) {\n for (const task of execution.tasks) {\n const taskWithUsage = task as ExecutionTaskWithExtraUsage;\n addUsage(taskWithUsage.usage);\n addUsage(taskWithUsage.searchAreaUsage);\n }\n }\n\n return totalsByModel;\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 (screenshot instanceof ScreenshotItem) {\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 = ref.mimeType === 'image/jpeg' ? 'jpeg' : 'png';\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 = sourceRef.mimeType === 'image/jpeg' ? 'jpeg' : 'png';\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 'Time Cost(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): 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 usageTotals = collectUsageTotals(reportDump);\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 tokenSummaryLines = [\n '\\n## Token Usage Summary',\n ...(usageTotals.size\n ? markdownTable(\n [\n 'Model',\n 'Calls',\n 'Prompt Tokens',\n 'Cached Input',\n 'Completion Tokens',\n 'Total Tokens',\n 'Time Cost(ms)',\n ],\n Array.from(usageTotals.entries()).map(([modelName, totals]) => [\n modelName,\n totals.calls,\n totals.prompt,\n totals.cachedInput,\n totals.completion,\n totals.total,\n totals.timeCost,\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 ...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","usageModelName","usageRowsForTask","appendUsage","collectUsageTotals","totalsByModel","modelName","current","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","base64","idSuffix","id","imageLabelSuffix","screenshotsMarkdownSection","attachments","screenshotIndex","imageResult","time","recorderIndex","descriptionText","renderExecution","executionRaw","typeStr","detail","locateCenter","usageRows","screenshotsSection","executionToMarkdown","reportToMarkdown","reportDump","executionResults","index","rendered","usageTotals","modelRows","modelInfoLines","tokenSummaryLines","totals","header","Boolean"],"mappings":"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"}
|