Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -156,10 +156,12 @@ void registerInspectionTools(final CapabilityContext context) {
// ---------------------------------------------------------------------------
// capture_ui_snapshot
// ---------------------------------------------------------------------------
// The "bundle" described in docs is JSON inside a single TextContent.
// Legacy resource_handler.dart captureUiSnapshot (lines 472-474) returns
// CallToolResult(content: [TextContent(text: jsonEncode(result.data))]).
// No multi-content transform required — standard runCommand with no onSuccess.
// The bundle travels as JSON in a TextContent, but captured images are lifted
// out of `screenshots.images` into ImageContent blocks (same artifact contract
// as get_screenshots). Base64 inlined into the JSON counts against the client
// response budget as text, which overflows it for a single desktop frame.
// `imageSummaries` keeps the per-image ids/hashes, so the bundle stays
// self-describing with the payload removed.
context.registerTool(
ToolRegistration(
name: 'capture_ui_snapshot',
Expand Down Expand Up @@ -188,6 +190,33 @@ void registerInspectionTools(final CapabilityContext context) {
screenshotMode: parseScreenshotMode(args['screenshotMode']),
permissionPolicy: parsePermissionPolicy(args['permissionPolicy']),
),
onSuccess: (final data) {
final bundle = _asMap(data);
final screenshots = _asMap(bundle['screenshots']);
final images = _stringList(screenshots['images']);
if (images.isEmpty) {
return AgentResult.success(
artifacts: [AgentArtifact.text(jsonEncode(bundle))],
);
}
return AgentResult.success(
artifacts: [
AgentArtifact.text(
jsonEncode(<String, Object?>{
...bundle,
'screenshots': <String, Object?>{
...screenshots,
'images': const <String>[],
},
}),
),
...images.map(
(final image) =>
AgentArtifact.text(image, mimeType: 'image/png'),
),
],
);
},
);
},
),
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -591,6 +591,73 @@ void main() {
},
);

test(
'capture_ui_snapshot onSuccess: images move to ImageContent blocks '
'and leave the bundle JSON',
() async {
final runner = FakeCommandRunner()
..nextExecuteResult = CoreResult.success(
data: {
'message': 'Captured UI snapshot bundle.',
'screenshots': {
'images': ['base64dataA', 'base64dataB'],
'fileUrls': <String>[],
'captureMode': 'flutter_layer',
},
'imageSummaries': [
{'id': 'image_1', 'source': 'inline_base64'},
{'id': 'image_2', 'source': 'inline_base64'},
],
},
);
final ctx = _registeredCtx(runner: runner);
final reg = ctx.registrationFor('capture_ui_snapshot')!;
final result = await reg.handler(const <String, Object?>{});
expect(result.ok, isTrue);
expect(result.artifacts, hasLength(3));

final bundle =
jsonDecode(result.artifacts.first.text!) as Map<String, Object?>;
final screenshots = bundle['screenshots']! as Map<String, Object?>;
expect(screenshots['images'], isEmpty);
expect(screenshots['captureMode'], 'flutter_layer');
expect(bundle['imageSummaries'], hasLength(2));

final images = result.artifacts
.where((final a) => a.mimeType == 'image/png')
.toList();
expect(images, hasLength(2));
expect(images[0].text, 'base64dataA');
expect(images[1].text, 'base64dataB');
},
);

test(
'capture_ui_snapshot onSuccess: fileUrls bundle stays a single '
'TextContent',
() async {
final runner = FakeCommandRunner()
..nextExecuteResult = CoreResult.success(
data: {
'screenshots': {
'images': <String>[],
'fileUrls': ['file:///tmp/screen0.png'],
},
},
);
final ctx = _registeredCtx(runner: runner);
final reg = ctx.registrationFor('capture_ui_snapshot')!;
final result = await reg.handler(const <String, Object?>{});
expect(result.ok, isTrue);
expect(result.artifacts, hasLength(1));
expect(result.artifacts.single.mimeType, 'text/plain');
final bundle =
jsonDecode(result.artifacts.single.text!) as Map<String, Object?>;
final screenshots = bundle['screenshots']! as Map<String, Object?>;
expect(screenshots['fileUrls'], ['file:///tmp/screen0.png']);
},
);

test(
'capture_ui_snapshot handler short-circuits on override failure',
() async {
Expand Down
Loading