@aiscene/shared 8.0.3 → 8.0.5
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-tools/agent-behavior-init-args.mjs +44 -0
- package/dist/es/agent-tools/base-tools.mjs +163 -0
- package/dist/es/agent-tools/chrome-path.mjs +50 -0
- package/dist/es/agent-tools/cli-report-session.mjs +78 -0
- package/dist/es/agent-tools/error-formatter.mjs +106 -0
- package/dist/es/agent-tools/index.mjs +9 -0
- package/dist/es/agent-tools/init-arg-utils.mjs +38 -0
- package/dist/es/agent-tools/observation-artifact.mjs +5 -0
- package/dist/es/agent-tools/observation-record.mjs +248 -0
- package/dist/es/agent-tools/tool-defaults.mjs +54 -0
- package/dist/es/agent-tools/tool-generator.mjs +529 -0
- package/dist/es/agent-tools/types.mjs +3 -0
- package/dist/es/agent-tools/user-prompt.mjs +66 -0
- package/dist/es/cli/interrupt.mjs +116 -0
- package/dist/es/cli/record-command.mjs +130 -0
- package/dist/es/cli/screenshot-file.mjs +24 -0
- package/dist/es/cli/verbose-ai-act.mjs +230 -0
- package/dist/es/cli/verbose-screenshot.mjs +134 -0
- package/dist/es/cli/verbose.mjs +404 -0
- package/dist/es/env/parse-model-config.mjs +1 -1
- package/dist/es/env/types.mjs +18 -3
- package/dist/es/img/index.mjs +3 -3
- package/dist/es/img/info.mjs +45 -1
- package/dist/es/img/photon-loader.mjs +4 -0
- package/dist/es/img/transform.mjs +113 -3
- package/dist/es/recorder.mjs +249 -0
- package/dist/lib/agent-tools/agent-behavior-init-args.js +87 -0
- package/dist/lib/agent-tools/base-tools.js +197 -0
- package/dist/lib/agent-tools/chrome-path.js +87 -0
- package/dist/lib/agent-tools/cli-report-session.js +121 -0
- package/dist/lib/agent-tools/error-formatter.js +149 -0
- package/dist/lib/agent-tools/index.js +114 -0
- package/dist/lib/agent-tools/init-arg-utils.js +78 -0
- package/dist/lib/agent-tools/observation-artifact.js +42 -0
- package/dist/lib/agent-tools/observation-record.js +297 -0
- package/dist/lib/agent-tools/tool-defaults.js +97 -0
- package/dist/lib/agent-tools/tool-generator.js +569 -0
- package/dist/lib/agent-tools/types.js +40 -0
- package/dist/lib/agent-tools/user-prompt.js +103 -0
- package/dist/lib/cli/interrupt.js +156 -0
- package/dist/lib/cli/record-command.js +164 -0
- package/dist/lib/cli/screenshot-file.js +58 -0
- package/dist/lib/cli/verbose-ai-act.js +273 -0
- package/dist/lib/cli/verbose-screenshot.js +177 -0
- package/dist/lib/cli/verbose.js +465 -0
- package/dist/lib/env/parse-model-config.js +1 -1
- package/dist/lib/env/types.js +32 -2
- package/dist/lib/img/index.js +29 -5
- package/dist/lib/img/info.js +48 -1
- package/dist/lib/img/photon-loader.js +38 -0
- package/dist/lib/img/transform.js +135 -4
- package/dist/lib/recorder.js +307 -0
- package/dist/types/agent-tools/agent-behavior-init-args.d.ts +17 -0
- package/dist/types/agent-tools/base-tools.d.ts +158 -0
- package/dist/types/agent-tools/chrome-path.d.ts +2 -0
- package/dist/types/agent-tools/cli-report-session.d.ts +12 -0
- package/dist/types/agent-tools/error-formatter.d.ts +30 -0
- package/dist/types/agent-tools/index.d.ts +9 -0
- package/dist/types/agent-tools/init-arg-utils.d.ts +13 -0
- package/dist/types/agent-tools/observation-artifact.d.ts +10 -0
- package/dist/types/agent-tools/observation-record.d.ts +38 -0
- package/dist/types/agent-tools/tool-defaults.d.ts +63 -0
- package/dist/types/agent-tools/tool-generator.d.ts +13 -0
- package/dist/types/agent-tools/types.d.ts +213 -0
- package/dist/types/agent-tools/user-prompt.d.ts +13 -0
- package/dist/types/cli/interrupt.d.ts +49 -0
- package/dist/types/cli/record-command.d.ts +3 -0
- package/dist/types/cli/screenshot-file.d.ts +10 -0
- package/dist/types/cli/verbose-ai-act.d.ts +44 -0
- package/dist/types/cli/verbose-screenshot.d.ts +10 -0
- package/dist/types/cli/verbose.d.ts +40 -0
- package/dist/types/env/types.d.ts +16 -7
- package/dist/types/img/index.d.ts +2 -2
- package/dist/types/img/info.d.ts +2 -0
- package/dist/types/img/photon-loader.d.ts +2 -0
- package/dist/types/img/transform.d.ts +22 -2
- package/dist/types/mcp/types.d.ts +1 -0
- package/dist/types/recorder.d.ts +113 -0
- package/package.json +1 -1
- package/src/agent-tools/agent-behavior-init-args.ts +109 -0
- package/src/agent-tools/base-tools.ts +399 -0
- package/src/agent-tools/chrome-path.ts +74 -0
- package/src/agent-tools/cli-report-session.ts +130 -0
- package/src/agent-tools/error-formatter.ts +177 -0
- package/src/agent-tools/index.ts +9 -0
- package/src/agent-tools/init-arg-utils.ts +105 -0
- package/src/agent-tools/observation-artifact.ts +29 -0
- package/src/agent-tools/observation-record.ts +331 -0
- package/src/agent-tools/tool-defaults.ts +119 -0
- package/src/agent-tools/tool-generator.ts +866 -0
- package/src/agent-tools/types.ts +250 -0
- package/src/agent-tools/user-prompt.ts +102 -0
- package/src/cli/interrupt.ts +207 -0
- package/src/cli/record-command.ts +177 -0
- package/src/cli/screenshot-file.ts +61 -0
- package/src/cli/verbose-ai-act.ts +387 -0
- package/src/cli/verbose-screenshot.ts +269 -0
- package/src/cli/verbose.ts +753 -0
- package/src/env/types.ts +30 -2
- package/src/img/index.ts +12 -0
- package/src/img/info.ts +61 -0
- package/src/img/photon-loader.ts +5 -0
- package/src/img/transform.ts +262 -3
- package/src/mcp/types.ts +2 -0
- package/src/recorder.ts +625 -0
|
@@ -0,0 +1,753 @@
|
|
|
1
|
+
import {
|
|
2
|
+
type CliProgressRenderer,
|
|
3
|
+
type CliVerboseLine,
|
|
4
|
+
aiActCliProgressRenderer,
|
|
5
|
+
cliAiActProgressScope,
|
|
6
|
+
} from './verbose-ai-act';
|
|
7
|
+
import {
|
|
8
|
+
type CliVerboseScreenshotCollectOptions,
|
|
9
|
+
type CliVerboseScreenshotExportMode,
|
|
10
|
+
collectScreenshotRefs,
|
|
11
|
+
renderScreenshotList,
|
|
12
|
+
} from './verbose-screenshot';
|
|
13
|
+
|
|
14
|
+
export const cliVerboseFlag = 'verbose';
|
|
15
|
+
|
|
16
|
+
// Scope -> renderer registry for the generic progress bus. Adding a new
|
|
17
|
+
// producer means registering one entry here; the dispatcher core below is
|
|
18
|
+
// producer-agnostic.
|
|
19
|
+
const progressRenderers: Record<string, CliProgressRenderer> = {
|
|
20
|
+
[cliAiActProgressScope]: aiActCliProgressRenderer,
|
|
21
|
+
};
|
|
22
|
+
|
|
23
|
+
function progressRendererForEvent(
|
|
24
|
+
event: unknown,
|
|
25
|
+
): { scope: string; renderer: CliProgressRenderer } | undefined {
|
|
26
|
+
if (typeof event !== 'object' || event === null) {
|
|
27
|
+
return undefined;
|
|
28
|
+
}
|
|
29
|
+
const scope = (event as { scope?: unknown }).scope;
|
|
30
|
+
if (typeof scope !== 'string') {
|
|
31
|
+
return undefined;
|
|
32
|
+
}
|
|
33
|
+
const renderer = progressRenderers[scope];
|
|
34
|
+
return renderer ? { scope, renderer } : undefined;
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
const progressEventName = 'midscene_progress';
|
|
38
|
+
const cliVerboseContextKey = '__midscene_cli_verbose_context__';
|
|
39
|
+
|
|
40
|
+
export type CliVerboseFormat = 'text' | 'jsonl';
|
|
41
|
+
|
|
42
|
+
export interface CliVerboseContext {
|
|
43
|
+
enabled: boolean;
|
|
44
|
+
format?: CliVerboseFormat;
|
|
45
|
+
scriptName?: string;
|
|
46
|
+
commandName?: string;
|
|
47
|
+
startedAt?: number;
|
|
48
|
+
renderedLineKeys?: Set<string>;
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
export interface CliVerboseEvent {
|
|
52
|
+
event: string;
|
|
53
|
+
scriptName?: string;
|
|
54
|
+
command?: string;
|
|
55
|
+
status?: 'ok' | 'error';
|
|
56
|
+
durationMs?: number;
|
|
57
|
+
error?: string;
|
|
58
|
+
[key: string]: unknown;
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
type DumpUpdateAgent = {
|
|
62
|
+
addDumpUpdateListener?: (
|
|
63
|
+
listener: (dump: string, executionDump?: unknown) => void,
|
|
64
|
+
) => () => void;
|
|
65
|
+
// Generic progress bus; consumers narrow by `event.scope`.
|
|
66
|
+
addProgressListener?: (listener: (event: unknown) => void) => () => void;
|
|
67
|
+
reportFile?: string | null;
|
|
68
|
+
};
|
|
69
|
+
|
|
70
|
+
interface CliVerboseExecutionTaskLike {
|
|
71
|
+
taskId?: unknown;
|
|
72
|
+
type?: unknown;
|
|
73
|
+
subType?: unknown;
|
|
74
|
+
status?: unknown;
|
|
75
|
+
param?: unknown;
|
|
76
|
+
thought?: unknown;
|
|
77
|
+
output?: unknown;
|
|
78
|
+
log?: unknown;
|
|
79
|
+
errorMessage?: unknown;
|
|
80
|
+
timing?: {
|
|
81
|
+
cost?: unknown;
|
|
82
|
+
};
|
|
83
|
+
recorder?: unknown;
|
|
84
|
+
uiContext?: {
|
|
85
|
+
screenshot?: unknown;
|
|
86
|
+
};
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
interface CliVerboseStepSummary {
|
|
90
|
+
id?: unknown;
|
|
91
|
+
index: number;
|
|
92
|
+
total: number;
|
|
93
|
+
type?: unknown;
|
|
94
|
+
subType?: unknown;
|
|
95
|
+
status?: unknown;
|
|
96
|
+
param?: unknown;
|
|
97
|
+
message: string;
|
|
98
|
+
error?: unknown;
|
|
99
|
+
durationMs?: unknown;
|
|
100
|
+
screenshots?: Array<Record<string, unknown>>;
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
interface CliVerboseExecutionDumpLike {
|
|
104
|
+
id?: unknown;
|
|
105
|
+
name?: unknown;
|
|
106
|
+
description?: unknown;
|
|
107
|
+
tasks: CliVerboseExecutionTaskLike[];
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
const getGlobalContext = (): { current: CliVerboseContext } => {
|
|
111
|
+
const globalWithContext = globalThis as unknown as Record<
|
|
112
|
+
string,
|
|
113
|
+
{ current: CliVerboseContext } | undefined
|
|
114
|
+
>;
|
|
115
|
+
if (!globalWithContext[cliVerboseContextKey]) {
|
|
116
|
+
globalWithContext[cliVerboseContextKey] = { current: { enabled: false } };
|
|
117
|
+
}
|
|
118
|
+
return globalWithContext[cliVerboseContextKey]!;
|
|
119
|
+
};
|
|
120
|
+
|
|
121
|
+
function parseVerboseFormat(rawFormat: string): CliVerboseFormat {
|
|
122
|
+
if (rawFormat === 'text' || rawFormat === 'jsonl') {
|
|
123
|
+
return rawFormat;
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
throw new Error(
|
|
127
|
+
`Unsupported --${cliVerboseFlag} format "${rawFormat}". Use "--${cliVerboseFlag}" or "--${cliVerboseFlag}=jsonl".`,
|
|
128
|
+
);
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
export function stripVerboseFlag(argv: readonly string[]): {
|
|
132
|
+
rawArgs: string[];
|
|
133
|
+
verbose: boolean;
|
|
134
|
+
format: CliVerboseFormat;
|
|
135
|
+
} {
|
|
136
|
+
const rawArgs: string[] = [];
|
|
137
|
+
let verbose = false;
|
|
138
|
+
let format: CliVerboseFormat = 'text';
|
|
139
|
+
|
|
140
|
+
for (const arg of argv) {
|
|
141
|
+
if (arg === `--${cliVerboseFlag}`) {
|
|
142
|
+
verbose = true;
|
|
143
|
+
continue;
|
|
144
|
+
}
|
|
145
|
+
if (arg.startsWith(`--${cliVerboseFlag}=`)) {
|
|
146
|
+
verbose = true;
|
|
147
|
+
format = parseVerboseFormat(arg.slice(`--${cliVerboseFlag}=`.length));
|
|
148
|
+
continue;
|
|
149
|
+
}
|
|
150
|
+
rawArgs.push(arg);
|
|
151
|
+
}
|
|
152
|
+
|
|
153
|
+
return { rawArgs, verbose, format };
|
|
154
|
+
}
|
|
155
|
+
|
|
156
|
+
export async function withCliVerboseContext<T>(
|
|
157
|
+
context: CliVerboseContext,
|
|
158
|
+
fn: () => Promise<T>,
|
|
159
|
+
): Promise<T> {
|
|
160
|
+
const globalContext = getGlobalContext();
|
|
161
|
+
const previous = globalContext.current;
|
|
162
|
+
globalContext.current = {
|
|
163
|
+
...context,
|
|
164
|
+
renderedLineKeys: context.renderedLineKeys ?? new Set(),
|
|
165
|
+
};
|
|
166
|
+
try {
|
|
167
|
+
return await fn();
|
|
168
|
+
} finally {
|
|
169
|
+
globalContext.current = previous;
|
|
170
|
+
}
|
|
171
|
+
}
|
|
172
|
+
|
|
173
|
+
export function getCliVerboseContext(): CliVerboseContext {
|
|
174
|
+
return getGlobalContext().current;
|
|
175
|
+
}
|
|
176
|
+
|
|
177
|
+
export function isCliVerboseEnabled(): boolean {
|
|
178
|
+
return getCliVerboseContext().enabled;
|
|
179
|
+
}
|
|
180
|
+
|
|
181
|
+
export function emitCliVerboseEvent(event: CliVerboseEvent): void {
|
|
182
|
+
const context = getCliVerboseContext();
|
|
183
|
+
if (!context.enabled) {
|
|
184
|
+
return;
|
|
185
|
+
}
|
|
186
|
+
|
|
187
|
+
const payload = {
|
|
188
|
+
type: progressEventName,
|
|
189
|
+
timestamp: new Date().toISOString(),
|
|
190
|
+
scriptName: context.scriptName,
|
|
191
|
+
command: context.commandName,
|
|
192
|
+
...event,
|
|
193
|
+
};
|
|
194
|
+
|
|
195
|
+
if (context.format === 'jsonl') {
|
|
196
|
+
console.log(JSON.stringify(payload));
|
|
197
|
+
return;
|
|
198
|
+
}
|
|
199
|
+
|
|
200
|
+
const text = renderCliVerboseEventText(payload, context);
|
|
201
|
+
if (text) {
|
|
202
|
+
console.log(text);
|
|
203
|
+
}
|
|
204
|
+
}
|
|
205
|
+
|
|
206
|
+
function errorMessageOf(error: unknown): string {
|
|
207
|
+
return error instanceof Error ? error.message : String(error);
|
|
208
|
+
}
|
|
209
|
+
|
|
210
|
+
function isRecord(value: unknown): value is Record<string, unknown> {
|
|
211
|
+
return typeof value === 'object' && value !== null && !Array.isArray(value);
|
|
212
|
+
}
|
|
213
|
+
|
|
214
|
+
function compactText(value: unknown): string {
|
|
215
|
+
if (value === undefined || value === null || value === '') {
|
|
216
|
+
return '';
|
|
217
|
+
}
|
|
218
|
+
|
|
219
|
+
if (typeof value === 'string') {
|
|
220
|
+
return value.length > 180 ? `${value.slice(0, 177)}...` : value;
|
|
221
|
+
}
|
|
222
|
+
|
|
223
|
+
if (typeof value === 'number' || typeof value === 'boolean') {
|
|
224
|
+
return String(value);
|
|
225
|
+
}
|
|
226
|
+
|
|
227
|
+
try {
|
|
228
|
+
const json = JSON.stringify(value);
|
|
229
|
+
return json.length > 180 ? `${json.slice(0, 177)}...` : json;
|
|
230
|
+
} catch {
|
|
231
|
+
return String(value);
|
|
232
|
+
}
|
|
233
|
+
}
|
|
234
|
+
|
|
235
|
+
function compactPrimitiveCliVerboseValue(
|
|
236
|
+
value: unknown,
|
|
237
|
+
): { handled: true; value: unknown } | { handled: false } {
|
|
238
|
+
if (value === undefined || value === null) {
|
|
239
|
+
return { handled: true, value };
|
|
240
|
+
}
|
|
241
|
+
|
|
242
|
+
if (typeof value === 'string') {
|
|
243
|
+
return {
|
|
244
|
+
handled: true,
|
|
245
|
+
value: value.length > 180 ? `${value.slice(0, 177)}...` : value,
|
|
246
|
+
};
|
|
247
|
+
}
|
|
248
|
+
|
|
249
|
+
if (typeof value === 'number' || typeof value === 'boolean') {
|
|
250
|
+
return { handled: true, value };
|
|
251
|
+
}
|
|
252
|
+
|
|
253
|
+
if (typeof value !== 'object') {
|
|
254
|
+
return { handled: true, value: String(value) };
|
|
255
|
+
}
|
|
256
|
+
|
|
257
|
+
return { handled: false };
|
|
258
|
+
}
|
|
259
|
+
|
|
260
|
+
function compactStructuredCliVerboseValue(value: unknown): unknown {
|
|
261
|
+
const primitive = compactPrimitiveCliVerboseValue(value);
|
|
262
|
+
if (primitive.handled) {
|
|
263
|
+
return primitive.value;
|
|
264
|
+
}
|
|
265
|
+
|
|
266
|
+
if (Array.isArray(value)) {
|
|
267
|
+
return value.slice(0, 5).map(compactStructuredCliVerboseValue);
|
|
268
|
+
}
|
|
269
|
+
|
|
270
|
+
if (!isRecord(value)) {
|
|
271
|
+
return String(value);
|
|
272
|
+
}
|
|
273
|
+
|
|
274
|
+
const entries = Object.entries(value).slice(0, 6);
|
|
275
|
+
return Object.fromEntries(
|
|
276
|
+
entries.map(([key, entryValue]) => [
|
|
277
|
+
key,
|
|
278
|
+
compactStructuredCliVerboseValue(entryValue),
|
|
279
|
+
]),
|
|
280
|
+
);
|
|
281
|
+
}
|
|
282
|
+
|
|
283
|
+
export function compactCliVerboseValue(value: unknown): unknown {
|
|
284
|
+
const primitive = compactPrimitiveCliVerboseValue(value);
|
|
285
|
+
if (primitive.handled) {
|
|
286
|
+
return primitive.value;
|
|
287
|
+
}
|
|
288
|
+
|
|
289
|
+
if (Array.isArray(value)) {
|
|
290
|
+
return value.slice(0, 5).map(compactCliVerboseValue);
|
|
291
|
+
}
|
|
292
|
+
|
|
293
|
+
if (isRecord(value) && typeof value.prompt === 'string') {
|
|
294
|
+
return compactCliVerboseValue(value.prompt);
|
|
295
|
+
}
|
|
296
|
+
|
|
297
|
+
if (!isRecord(value)) {
|
|
298
|
+
return String(value);
|
|
299
|
+
}
|
|
300
|
+
|
|
301
|
+
const entries = Object.entries(value).slice(0, 6);
|
|
302
|
+
return Object.fromEntries(
|
|
303
|
+
entries.map(([key, entryValue]) => [
|
|
304
|
+
key,
|
|
305
|
+
compactCliVerboseValue(entryValue),
|
|
306
|
+
]),
|
|
307
|
+
);
|
|
308
|
+
}
|
|
309
|
+
|
|
310
|
+
export function compactCliVerboseArgs(
|
|
311
|
+
args: Record<string, unknown>,
|
|
312
|
+
): Record<string, unknown> {
|
|
313
|
+
return Object.fromEntries(
|
|
314
|
+
Object.entries(args)
|
|
315
|
+
.slice(0, 8)
|
|
316
|
+
.map(([key, value]) => [key, compactStructuredCliVerboseValue(value)]),
|
|
317
|
+
);
|
|
318
|
+
}
|
|
319
|
+
|
|
320
|
+
function summarizeParam(param: unknown): unknown {
|
|
321
|
+
if (!param || typeof param !== 'object') {
|
|
322
|
+
return compactCliVerboseValue(param);
|
|
323
|
+
}
|
|
324
|
+
|
|
325
|
+
const record = param as Record<string, unknown>;
|
|
326
|
+
if (typeof record.prompt === 'string') {
|
|
327
|
+
return compactCliVerboseValue(record.prompt);
|
|
328
|
+
}
|
|
329
|
+
if (
|
|
330
|
+
record.locate &&
|
|
331
|
+
typeof record.locate === 'object' &&
|
|
332
|
+
record.locate !== null
|
|
333
|
+
) {
|
|
334
|
+
const locate = record.locate as Record<string, unknown>;
|
|
335
|
+
return {
|
|
336
|
+
locate: compactCliVerboseValue(locate.prompt),
|
|
337
|
+
...Object.fromEntries(
|
|
338
|
+
Object.entries(record)
|
|
339
|
+
.filter(([key]) => key !== 'locate')
|
|
340
|
+
.slice(0, 4)
|
|
341
|
+
.map(([key, value]) => [key, compactCliVerboseValue(value)]),
|
|
342
|
+
),
|
|
343
|
+
};
|
|
344
|
+
}
|
|
345
|
+
|
|
346
|
+
return compactCliVerboseValue(record);
|
|
347
|
+
}
|
|
348
|
+
|
|
349
|
+
function summarizeUserInstruction(value: unknown): string {
|
|
350
|
+
if (typeof value === 'string') {
|
|
351
|
+
return compactText(value);
|
|
352
|
+
}
|
|
353
|
+
|
|
354
|
+
if (isRecord(value) && typeof value.prompt === 'string') {
|
|
355
|
+
return compactText(value.prompt);
|
|
356
|
+
}
|
|
357
|
+
|
|
358
|
+
return compactText(value);
|
|
359
|
+
}
|
|
360
|
+
|
|
361
|
+
function summarizeTaskParamText(task: CliVerboseExecutionTaskLike): string {
|
|
362
|
+
if (!isRecord(task.param)) {
|
|
363
|
+
return compactText(summarizeParam(task.param));
|
|
364
|
+
}
|
|
365
|
+
|
|
366
|
+
if (task.type === 'Planning' && task.subType !== 'Locate') {
|
|
367
|
+
if (task.param.userInstructionDisplay) {
|
|
368
|
+
return summarizeUserInstruction(task.param.userInstructionDisplay);
|
|
369
|
+
}
|
|
370
|
+
if (task.param.userInstruction) {
|
|
371
|
+
return summarizeUserInstruction(task.param.userInstruction);
|
|
372
|
+
}
|
|
373
|
+
}
|
|
374
|
+
|
|
375
|
+
if (task.param.dataDemand) {
|
|
376
|
+
return compactText(summarizeParam(task.param.dataDemand));
|
|
377
|
+
}
|
|
378
|
+
|
|
379
|
+
if (task.param.assertion) {
|
|
380
|
+
return compactText(summarizeParam(task.param.assertion));
|
|
381
|
+
}
|
|
382
|
+
|
|
383
|
+
return compactText(summarizeParam(task.param));
|
|
384
|
+
}
|
|
385
|
+
|
|
386
|
+
function summarizeSubGoals(value: unknown): string {
|
|
387
|
+
if (!Array.isArray(value) || value.length === 0) {
|
|
388
|
+
return '';
|
|
389
|
+
}
|
|
390
|
+
|
|
391
|
+
const goals = value
|
|
392
|
+
.slice(0, 6)
|
|
393
|
+
.map((goal) => {
|
|
394
|
+
if (!isRecord(goal)) {
|
|
395
|
+
return '';
|
|
396
|
+
}
|
|
397
|
+
const index = typeof goal.index === 'number' ? `${goal.index}. ` : '';
|
|
398
|
+
const status = typeof goal.status === 'string' ? `[${goal.status}] ` : '';
|
|
399
|
+
const description =
|
|
400
|
+
typeof goal.description === 'string' ? goal.description : '';
|
|
401
|
+
return `${index}${status}${description}`.trim();
|
|
402
|
+
})
|
|
403
|
+
.filter(Boolean);
|
|
404
|
+
|
|
405
|
+
return goals.length > 0 ? `sub-goals: ${goals.join('; ')}` : '';
|
|
406
|
+
}
|
|
407
|
+
|
|
408
|
+
function summarizeActions(value: unknown): string {
|
|
409
|
+
if (!Array.isArray(value) || value.length === 0) {
|
|
410
|
+
return '';
|
|
411
|
+
}
|
|
412
|
+
|
|
413
|
+
const actions = value
|
|
414
|
+
.slice(0, 5)
|
|
415
|
+
.map((action) => {
|
|
416
|
+
if (!isRecord(action)) {
|
|
417
|
+
return '';
|
|
418
|
+
}
|
|
419
|
+
const type = typeof action.type === 'string' ? action.type : 'Action';
|
|
420
|
+
const param = compactText(summarizeParam(action.param));
|
|
421
|
+
return param ? `${type}: ${param}` : type;
|
|
422
|
+
})
|
|
423
|
+
.filter(Boolean);
|
|
424
|
+
|
|
425
|
+
return actions.length > 0 ? `actions: ${actions.join('; ')}` : '';
|
|
426
|
+
}
|
|
427
|
+
|
|
428
|
+
function summarizeTaskOutputText(task: CliVerboseExecutionTaskLike): string {
|
|
429
|
+
if (!isRecord(task.output)) {
|
|
430
|
+
return compactText(task.output);
|
|
431
|
+
}
|
|
432
|
+
|
|
433
|
+
return (
|
|
434
|
+
summarizeSubGoals(task.output.updateSubGoals) ||
|
|
435
|
+
compactText(task.output.log) ||
|
|
436
|
+
compactText(task.output.output) ||
|
|
437
|
+
summarizeActions(task.output.actions)
|
|
438
|
+
);
|
|
439
|
+
}
|
|
440
|
+
|
|
441
|
+
function summarizeTaskText(task: CliVerboseExecutionTaskLike): string {
|
|
442
|
+
const parts = [task.type, task.subType].filter(
|
|
443
|
+
(part): part is string => typeof part === 'string' && part.length > 0,
|
|
444
|
+
);
|
|
445
|
+
const label = parts.length > 0 ? parts.join('/') : 'Task';
|
|
446
|
+
const status =
|
|
447
|
+
typeof task.status === 'string' && task.status.length > 0
|
|
448
|
+
? task.status
|
|
449
|
+
: 'unknown';
|
|
450
|
+
const param = summarizeTaskParamText(task);
|
|
451
|
+
const output = summarizeTaskOutputText(task);
|
|
452
|
+
const thought = compactText(task.thought);
|
|
453
|
+
const detail = output || thought || param;
|
|
454
|
+
return detail ? `${label} ${status}: ${detail}` : `${label} ${status}`;
|
|
455
|
+
}
|
|
456
|
+
|
|
457
|
+
function isCliVerboseExecutionDumpLike(
|
|
458
|
+
value: unknown,
|
|
459
|
+
): value is CliVerboseExecutionDumpLike {
|
|
460
|
+
return isRecord(value) && Array.isArray(value.tasks);
|
|
461
|
+
}
|
|
462
|
+
|
|
463
|
+
function summarizeDumpUpdate(
|
|
464
|
+
executionDump: unknown,
|
|
465
|
+
screenshotOptions: CliVerboseScreenshotCollectOptions = {},
|
|
466
|
+
): Record<string, unknown> | undefined {
|
|
467
|
+
if (!isCliVerboseExecutionDumpLike(executionDump)) {
|
|
468
|
+
return undefined;
|
|
469
|
+
}
|
|
470
|
+
|
|
471
|
+
const tasks = executionDump.tasks;
|
|
472
|
+
const latestTask = tasks[tasks.length - 1];
|
|
473
|
+
const steps = tasks.map(
|
|
474
|
+
(task, index): CliVerboseStepSummary => ({
|
|
475
|
+
id: task.taskId,
|
|
476
|
+
index: index + 1,
|
|
477
|
+
total: tasks.length,
|
|
478
|
+
type: task.type,
|
|
479
|
+
subType: task.subType,
|
|
480
|
+
status: task.status,
|
|
481
|
+
param: summarizeParam(task.param),
|
|
482
|
+
message: summarizeTaskText(task),
|
|
483
|
+
error: task.errorMessage,
|
|
484
|
+
durationMs: task.timing?.cost,
|
|
485
|
+
screenshots: collectScreenshotRefs(task, screenshotOptions).slice(-3),
|
|
486
|
+
}),
|
|
487
|
+
);
|
|
488
|
+
|
|
489
|
+
return {
|
|
490
|
+
execution: {
|
|
491
|
+
id: executionDump.id,
|
|
492
|
+
name: executionDump.name,
|
|
493
|
+
description: compactCliVerboseValue(executionDump.description),
|
|
494
|
+
taskCount: tasks.length,
|
|
495
|
+
},
|
|
496
|
+
steps,
|
|
497
|
+
task: latestTask
|
|
498
|
+
? {
|
|
499
|
+
id: latestTask.taskId,
|
|
500
|
+
index: tasks.length,
|
|
501
|
+
total: tasks.length,
|
|
502
|
+
type: latestTask.type,
|
|
503
|
+
subType: latestTask.subType,
|
|
504
|
+
status: latestTask.status,
|
|
505
|
+
param: summarizeParam(latestTask.param),
|
|
506
|
+
message: summarizeTaskText(latestTask),
|
|
507
|
+
error: latestTask.errorMessage,
|
|
508
|
+
durationMs: latestTask.timing?.cost,
|
|
509
|
+
}
|
|
510
|
+
: undefined,
|
|
511
|
+
screenshots: collectScreenshotRefs(tasks, screenshotOptions).slice(-5),
|
|
512
|
+
};
|
|
513
|
+
}
|
|
514
|
+
|
|
515
|
+
function stringifyArgs(args: unknown): string {
|
|
516
|
+
if (!isRecord(args) || Object.keys(args).length === 0) {
|
|
517
|
+
return '';
|
|
518
|
+
}
|
|
519
|
+
|
|
520
|
+
return Object.entries(args)
|
|
521
|
+
.map(([key, value]) => `${key}=${compactText(value)}`)
|
|
522
|
+
.join(', ');
|
|
523
|
+
}
|
|
524
|
+
|
|
525
|
+
function isActVerboseEvent(command?: string, tool?: string): boolean {
|
|
526
|
+
return command === 'act' || tool === 'act';
|
|
527
|
+
}
|
|
528
|
+
|
|
529
|
+
function renderLinesOnce(
|
|
530
|
+
context: CliVerboseContext,
|
|
531
|
+
lines: CliVerboseLine[],
|
|
532
|
+
): string | undefined {
|
|
533
|
+
if (lines.length === 0) {
|
|
534
|
+
return undefined;
|
|
535
|
+
}
|
|
536
|
+
|
|
537
|
+
if (!context.renderedLineKeys) {
|
|
538
|
+
context.renderedLineKeys = new Set();
|
|
539
|
+
}
|
|
540
|
+
const renderedLineKeys = context.renderedLineKeys;
|
|
541
|
+
const pendingLines = lines.filter((line) => {
|
|
542
|
+
if (renderedLineKeys.has(line.key)) {
|
|
543
|
+
return false;
|
|
544
|
+
}
|
|
545
|
+
renderedLineKeys.add(line.key);
|
|
546
|
+
return true;
|
|
547
|
+
});
|
|
548
|
+
|
|
549
|
+
return pendingLines.length > 0
|
|
550
|
+
? pendingLines.map((line) => line.text).join('\n')
|
|
551
|
+
: undefined;
|
|
552
|
+
}
|
|
553
|
+
|
|
554
|
+
function renderCliVerboseEventText(
|
|
555
|
+
event: CliVerboseEvent,
|
|
556
|
+
context: CliVerboseContext,
|
|
557
|
+
): string | undefined {
|
|
558
|
+
const command = typeof event.command === 'string' ? event.command : 'command';
|
|
559
|
+
const tool = typeof event.tool === 'string' ? event.tool : undefined;
|
|
560
|
+
|
|
561
|
+
switch (event.event) {
|
|
562
|
+
case 'agent_progress': {
|
|
563
|
+
const scope = typeof event.scope === 'string' ? event.scope : undefined;
|
|
564
|
+
const renderer = scope ? progressRenderers[scope] : undefined;
|
|
565
|
+
const progressEvent = isRecord(event.progress)
|
|
566
|
+
? event.progress
|
|
567
|
+
: undefined;
|
|
568
|
+
if (!renderer || !progressEvent) {
|
|
569
|
+
return undefined;
|
|
570
|
+
}
|
|
571
|
+
return renderLinesOnce(context, renderer.buildLines(progressEvent));
|
|
572
|
+
}
|
|
573
|
+
case 'command_start': {
|
|
574
|
+
if (isActVerboseEvent(command, tool)) {
|
|
575
|
+
return undefined;
|
|
576
|
+
}
|
|
577
|
+
const args = stringifyArgs(event.args);
|
|
578
|
+
return args
|
|
579
|
+
? `[Midscene] ${command} started (${args})`
|
|
580
|
+
: `[Midscene] ${command} started`;
|
|
581
|
+
}
|
|
582
|
+
case 'agent_ready':
|
|
583
|
+
if (isActVerboseEvent(command, tool)) {
|
|
584
|
+
return undefined;
|
|
585
|
+
}
|
|
586
|
+
return `[Midscene] ${tool ?? command} ready`;
|
|
587
|
+
case 'recording_ready':
|
|
588
|
+
return '[Midscene] Recording. Press Ctrl+C to stop and save.';
|
|
589
|
+
case 'recording_stopping':
|
|
590
|
+
if (event.reason === 'watchdog') {
|
|
591
|
+
return '[Midscene] Recording watchdog reached; finalizing and saving.';
|
|
592
|
+
}
|
|
593
|
+
if (event.reason === 'sigterm') {
|
|
594
|
+
return '[Midscene] SIGTERM received; finalizing and saving.';
|
|
595
|
+
}
|
|
596
|
+
return event.reason === 'sighup'
|
|
597
|
+
? '[Midscene] SIGHUP received; finalizing and saving.'
|
|
598
|
+
: '[Midscene] Ctrl+C received; finalizing and saving. Press Ctrl+C again to force exit.';
|
|
599
|
+
case 'dump_update': {
|
|
600
|
+
if (isActVerboseEvent(command, tool)) {
|
|
601
|
+
return undefined;
|
|
602
|
+
}
|
|
603
|
+
|
|
604
|
+
const task = isRecord(event.task) ? event.task : undefined;
|
|
605
|
+
const steps = Array.isArray(event.steps)
|
|
606
|
+
? event.steps.filter(isRecord)
|
|
607
|
+
: [];
|
|
608
|
+
const execution = isRecord(event.execution) ? event.execution : undefined;
|
|
609
|
+
const executionName =
|
|
610
|
+
typeof execution?.name === 'string' ? execution.name : 'execution';
|
|
611
|
+
const lines =
|
|
612
|
+
steps.length > 0
|
|
613
|
+
? [
|
|
614
|
+
`[Midscene] Progress: ${executionName} (${steps.length} steps)`,
|
|
615
|
+
...steps.map((step) => {
|
|
616
|
+
const index =
|
|
617
|
+
typeof step.index === 'number' &&
|
|
618
|
+
typeof step.total === 'number'
|
|
619
|
+
? `Step ${step.index}/${step.total}`
|
|
620
|
+
: 'Step';
|
|
621
|
+
const message =
|
|
622
|
+
typeof step.message === 'string'
|
|
623
|
+
? step.message
|
|
624
|
+
: typeof step.status === 'string'
|
|
625
|
+
? step.status
|
|
626
|
+
: 'updated';
|
|
627
|
+
return `[Midscene] ${index}: ${message}`;
|
|
628
|
+
}),
|
|
629
|
+
]
|
|
630
|
+
: [
|
|
631
|
+
`[Midscene] Step: ${
|
|
632
|
+
typeof task?.message === 'string'
|
|
633
|
+
? task.message
|
|
634
|
+
: typeof task?.status === 'string'
|
|
635
|
+
? task.status
|
|
636
|
+
: 'updated'
|
|
637
|
+
}`,
|
|
638
|
+
];
|
|
639
|
+
const screenshots = renderScreenshotList(event.screenshots);
|
|
640
|
+
if (screenshots) {
|
|
641
|
+
lines.push(`[Midscene] Screenshot: ${screenshots}`);
|
|
642
|
+
}
|
|
643
|
+
if (typeof event.report === 'string' && event.report.length > 0) {
|
|
644
|
+
lines.push(`[Midscene] Report: ${event.report}`);
|
|
645
|
+
}
|
|
646
|
+
return lines.join('\n');
|
|
647
|
+
}
|
|
648
|
+
case 'artifact': {
|
|
649
|
+
if (isActVerboseEvent(command, tool)) {
|
|
650
|
+
return undefined;
|
|
651
|
+
}
|
|
652
|
+
const kind = typeof event.kind === 'string' ? event.kind : 'artifact';
|
|
653
|
+
const path = typeof event.path === 'string' ? event.path : undefined;
|
|
654
|
+
return path
|
|
655
|
+
? `[Midscene] ${kind} saved: ${path}`
|
|
656
|
+
: `[Midscene] ${kind} ready`;
|
|
657
|
+
}
|
|
658
|
+
case 'command_done': {
|
|
659
|
+
if (isActVerboseEvent(command, tool)) {
|
|
660
|
+
if (event.status === 'error') {
|
|
661
|
+
const error =
|
|
662
|
+
typeof event.error === 'string' && event.error.length > 0
|
|
663
|
+
? `: ${event.error}`
|
|
664
|
+
: '';
|
|
665
|
+
return renderLinesOnce(context, [
|
|
666
|
+
{
|
|
667
|
+
key: `aiAct:command_failed:${event.error ?? 'unknown'}`,
|
|
668
|
+
text: `[Midscene][aiAct] Failed${error}`,
|
|
669
|
+
},
|
|
670
|
+
]);
|
|
671
|
+
}
|
|
672
|
+
return undefined;
|
|
673
|
+
}
|
|
674
|
+
const status = event.status === 'error' ? 'failed' : 'finished';
|
|
675
|
+
const duration =
|
|
676
|
+
typeof event.durationMs === 'number' ? ` in ${event.durationMs}ms` : '';
|
|
677
|
+
const error =
|
|
678
|
+
event.status === 'error' && typeof event.error === 'string'
|
|
679
|
+
? `: ${event.error}`
|
|
680
|
+
: '';
|
|
681
|
+
return `[Midscene] ${command} ${status}${duration}${error}`;
|
|
682
|
+
}
|
|
683
|
+
default:
|
|
684
|
+
return undefined;
|
|
685
|
+
}
|
|
686
|
+
}
|
|
687
|
+
|
|
688
|
+
export function attachCliVerboseDumpListener(
|
|
689
|
+
agent: DumpUpdateAgent,
|
|
690
|
+
options?: { toolName?: string },
|
|
691
|
+
): () => void {
|
|
692
|
+
if (!isCliVerboseEnabled()) {
|
|
693
|
+
return () => {};
|
|
694
|
+
}
|
|
695
|
+
|
|
696
|
+
const isActTool = options?.toolName === 'act';
|
|
697
|
+
const screenshotExportCache = new Map<string, string>();
|
|
698
|
+
|
|
699
|
+
if (isActTool && typeof agent.addProgressListener === 'function') {
|
|
700
|
+
return agent.addProgressListener((event) => {
|
|
701
|
+
const match = progressRendererForEvent(event);
|
|
702
|
+
if (!match) {
|
|
703
|
+
return;
|
|
704
|
+
}
|
|
705
|
+
const context = getCliVerboseContext();
|
|
706
|
+
const isTextMode = context.format !== 'jsonl';
|
|
707
|
+
const progress = match.renderer.normalize(event, {
|
|
708
|
+
reportFile: agent.reportFile,
|
|
709
|
+
exportMode: isTextMode ? 'report' : 'none',
|
|
710
|
+
cache: screenshotExportCache,
|
|
711
|
+
});
|
|
712
|
+
if (!progress) {
|
|
713
|
+
return;
|
|
714
|
+
}
|
|
715
|
+
emitCliVerboseEvent({
|
|
716
|
+
event: 'agent_progress',
|
|
717
|
+
tool: options?.toolName,
|
|
718
|
+
scope: match.scope,
|
|
719
|
+
progress,
|
|
720
|
+
});
|
|
721
|
+
});
|
|
722
|
+
}
|
|
723
|
+
|
|
724
|
+
if (isActTool) {
|
|
725
|
+
return () => {};
|
|
726
|
+
}
|
|
727
|
+
|
|
728
|
+
if (typeof agent.addDumpUpdateListener !== 'function') {
|
|
729
|
+
return () => {};
|
|
730
|
+
}
|
|
731
|
+
|
|
732
|
+
return agent.addDumpUpdateListener((_dump, executionDump) => {
|
|
733
|
+
const context = getCliVerboseContext();
|
|
734
|
+
const isTextMode = context.format !== 'jsonl';
|
|
735
|
+
const summaryExportMode: CliVerboseScreenshotExportMode =
|
|
736
|
+
isTextMode && !isActTool ? 'tmp' : 'none';
|
|
737
|
+
const summary = summarizeDumpUpdate(executionDump, {
|
|
738
|
+
exportMode: summaryExportMode,
|
|
739
|
+
cache: screenshotExportCache,
|
|
740
|
+
});
|
|
741
|
+
if (!summary) {
|
|
742
|
+
return;
|
|
743
|
+
}
|
|
744
|
+
emitCliVerboseEvent({
|
|
745
|
+
event: 'dump_update',
|
|
746
|
+
tool: options?.toolName,
|
|
747
|
+
report: agent.reportFile || undefined,
|
|
748
|
+
...summary,
|
|
749
|
+
});
|
|
750
|
+
});
|
|
751
|
+
}
|
|
752
|
+
|
|
753
|
+
export { errorMessageOf as cliVerboseErrorMessage };
|