Skip to content

Commit a29d90f

Browse files
committed
refactor: lowercase tool names, simplify cards, monospace everywhere
- Tool display names now lowercase (read, bash, edit, grep) not capitalized - Card header: show only tool name, remove subtitle (path/command moved to detail view) - All output/results rendered with MonoText (monospace font) - Write result section now also uses monospace - Removed _previewArgs helper (no longer needed for card subtitle) - Updated tests to expect lowercase names
1 parent ae34f6e commit a29d90f

3 files changed

Lines changed: 43 additions & 73 deletions

File tree

app/lib/ui/session/tool_call_card.dart

Lines changed: 21 additions & 41 deletions
Original file line numberDiff line numberDiff line change
@@ -39,43 +39,29 @@ class ToolCallCard extends StatelessWidget {
3939
Icon(riskIcon, size: 18, color: riskColor),
4040
const SizedBox(width: 10),
4141
Expanded(
42-
child: Column(
43-
crossAxisAlignment: CrossAxisAlignment.start,
42+
child: Row(
4443
children: [
45-
Row(
46-
children: [
47-
Text(
48-
toolDisplayName(item),
49-
style: Theme.of(context).textTheme.titleSmall,
50-
),
51-
const SizedBox(width: 8),
52-
if (running)
53-
const SizedBox(
54-
width: 10,
55-
height: 10,
56-
child: CircularProgressIndicator(strokeWidth: 2),
57-
)
58-
else if (failed)
59-
Icon(Icons.error_outline, size: 14, color: cs.error)
60-
else
61-
Icon(
62-
Icons.check_circle_outline,
63-
size: 14,
64-
color: cs.primary,
65-
),
66-
],
67-
),
68-
const SizedBox(height: 2),
69-
Text(
70-
item.summary ??
71-
renderer?.subtitle(item) ??
72-
_previewArgs(item.args),
73-
maxLines: 1,
74-
overflow: TextOverflow.ellipsis,
75-
style: Theme.of(
76-
context,
77-
).textTheme.bodySmall?.copyWith(fontFamily: 'monospace'),
44+
Expanded(
45+
child: Text(
46+
toolDisplayName(item),
47+
style: Theme.of(context).textTheme.titleSmall,
48+
),
7849
),
50+
const SizedBox(width: 8),
51+
if (running)
52+
const SizedBox(
53+
width: 10,
54+
height: 10,
55+
child: CircularProgressIndicator(strokeWidth: 2),
56+
)
57+
else if (failed)
58+
Icon(Icons.error_outline, size: 14, color: cs.error)
59+
else
60+
Icon(
61+
Icons.check_circle_outline,
62+
size: 14,
63+
color: cs.primary,
64+
),
7965
],
8066
),
8167
),
@@ -85,10 +71,4 @@ class ToolCallCard extends StatelessWidget {
8571
),
8672
);
8773
}
88-
89-
static String _previewArgs(Map<String, dynamic> args) {
90-
if (args.containsKey('path')) return args['path'] as String;
91-
if (args.containsKey('command')) return args['command'] as String;
92-
return args.entries.take(2).map((e) => '${e.key}=${e.value}').join(' ');
93-
}
9474
}

app/lib/ui/session/tool_renderers.dart

Lines changed: 12 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -27,8 +27,8 @@ abstract class ToolRenderer {
2727
String get name;
2828

2929
/// Human-facing title shown as the card title and detail-view header
30-
/// (e.g. `Read`, `Write`). Defaults to a capitalised [name].
31-
String get displayName => _titleCase(name);
30+
/// (e.g. `read`, `write`). Defaults to [name] as-is (lowercase).
31+
String get displayName => name;
3232

3333
/// One-line description for the card header.
3434
String? subtitle(ToolCallItem item) => null;
@@ -320,8 +320,6 @@ class _ReadRenderer extends ToolRenderer {
320320
@override
321321
String get name => 'read';
322322
@override
323-
String get displayName => 'Read';
324-
@override
325323
IconData get icon => Icons.menu_book_outlined;
326324
@override
327325
String? subtitle(ToolCallItem item) => item.args['path']?.toString();
@@ -333,7 +331,7 @@ class _ReadRenderer extends ToolRenderer {
333331
final offset = item.args['offset'];
334332
final limit = item.args['limit'];
335333
return ToolDetailScaffold(
336-
title: displayName,
334+
title: 'read',
337335
subtitle: path,
338336
children: [
339337
if (offset != null || limit != null)
@@ -360,8 +358,6 @@ class _WriteRenderer extends ToolRenderer {
360358
@override
361359
String get name => 'write';
362360
@override
363-
String get displayName => 'Write';
364-
@override
365361
IconData get icon => Icons.edit_note_outlined;
366362
@override
367363
String? subtitle(ToolCallItem item) => item.args['path']?.toString();
@@ -373,15 +369,15 @@ class _WriteRenderer extends ToolRenderer {
373369
item.args['content']?.toString() ?? item.args['text']?.toString() ?? '';
374370
final result = item.output ?? item.summary ?? '';
375371
return ToolDetailScaffold(
376-
title: displayName,
372+
title: 'write',
377373
subtitle: path,
378374
children: [
379375
ToolSection(
380376
title: 'Content written',
381377
child: MonoText(content.isEmpty ? '(empty)' : content),
382378
),
383379
if (result.isNotEmpty)
384-
ToolSection(title: 'Result', child: Text(result)),
380+
ToolSection(title: 'Result', child: MonoText(result)),
385381
],
386382
);
387383
}
@@ -392,8 +388,6 @@ class _EditRenderer extends ToolRenderer {
392388
@override
393389
String get name => 'edit';
394390
@override
395-
String get displayName => 'Edit';
396-
@override
397391
IconData get icon => Icons.difference_outlined;
398392
@override
399393
String? subtitle(ToolCallItem item) => item.args['path']?.toString();
@@ -409,8 +403,6 @@ class _BashRenderer extends ToolRenderer {
409403
@override
410404
String get name => 'bash';
411405
@override
412-
String get displayName => 'Bash';
413-
@override
414406
IconData get icon => Icons.attach_money;
415407
@override
416408
String? subtitle(ToolCallItem item) {
@@ -427,7 +419,7 @@ class _BashRenderer extends ToolRenderer {
427419
: (item.output ?? '');
428420
final failed = item.ended && (item.exitCode ?? 0) != 0;
429421
return ToolDetailScaffold(
430-
title: displayName,
422+
title: 'bash',
431423
subtitle: command.isEmpty ? null : command,
432424
children: [
433425
if (command.isNotEmpty)
@@ -440,7 +432,7 @@ class _BashRenderer extends ToolRenderer {
440432
else if (item.ended)
441433
ToolSection(
442434
title: 'Result',
443-
child: Text(item.summary ?? 'exit ${item.exitCode ?? 0}'),
435+
child: MonoText(item.summary ?? 'exit ${item.exitCode ?? 0}'),
444436
),
445437
],
446438
);
@@ -452,8 +444,6 @@ class _GrepRenderer extends ToolRenderer {
452444
@override
453445
String get name => 'grep';
454446
@override
455-
String get displayName => 'Grep';
456-
@override
457447
IconData get icon => Icons.search;
458448
@override
459449
String? subtitle(ToolCallItem item) {
@@ -469,7 +459,7 @@ class _GrepRenderer extends ToolRenderer {
469459
final path = item.args['path']?.toString();
470460
final output = item.output ?? item.deltas.join();
471461
return ToolDetailScaffold(
472-
title: displayName,
462+
title: 'grep',
473463
subtitle: pattern.isEmpty ? null : pattern,
474464
children: [
475465
ToolSection(
@@ -488,7 +478,7 @@ class _GrepRenderer extends ToolRenderer {
488478
else if (item.ended)
489479
ToolSection(
490480
title: 'Results',
491-
child: Text(item.summary ?? 'No matches found'),
481+
child: MonoText(item.summary ?? 'No matches found'),
492482
),
493483
],
494484
);
@@ -564,7 +554,7 @@ class _EditDiffView extends StatelessWidget {
564554
: (item.output ?? '');
565555

566556
return ToolDetailScaffold(
567-
title: 'Edit',
557+
title: 'edit',
568558
subtitle: path,
569559
children: [
570560
if (hasDiff)
@@ -646,7 +636,7 @@ class _AskUserQuestionRenderer extends ToolRenderer {
646636
@override
647637
String get name => _name;
648638
@override
649-
String get displayName => 'Ask the user';
639+
String get displayName => 'askUserQuestion';
650640
@override
651641
IconData get icon => Icons.quiz_outlined;
652642

@@ -682,7 +672,7 @@ class _AskUserQuestionRenderer extends ToolRenderer {
682672
final cs = Theme.of(context).colorScheme;
683673
final questions = _questions(item);
684674
return Scaffold(
685-
appBar: AppBar(centerTitle: false, title: const Text('Ask the user')),
675+
appBar: AppBar(centerTitle: false, title: const Text('askUserQuestion')),
686676
body: ListView.separated(
687677
padding: const EdgeInsets.all(16),
688678
itemCount: questions.length,

app/test/tool_renderers_test.dart

Lines changed: 10 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -69,12 +69,12 @@ void main() {
6969
});
7070

7171
group('display names', () {
72-
test('registered tools expose a capitalised title', () {
73-
expect(toolDisplayName(_tool('read', {})), 'Read');
74-
expect(toolDisplayName(_tool('write', {})), 'Write');
75-
expect(toolDisplayName(_tool('edit', {})), 'Edit');
76-
expect(toolDisplayName(_tool('bash', {})), 'Bash');
77-
expect(toolDisplayName(_tool('grep', {})), 'Grep');
72+
test('registered tools expose their lowercase name', () {
73+
expect(toolDisplayName(_tool('read', {})), 'read');
74+
expect(toolDisplayName(_tool('write', {})), 'write');
75+
expect(toolDisplayName(_tool('edit', {})), 'edit');
76+
expect(toolDisplayName(_tool('bash', {})), 'bash');
77+
expect(toolDisplayName(_tool('grep', {})), 'grep');
7878
});
7979

8080
test('unknown tools fall back to a capitalised name', () {
@@ -195,8 +195,8 @@ void main() {
195195
);
196196
await tester.pumpAndSettle();
197197

198-
// Header shows the tool's display name, left-aligned.
199-
expect(find.text('Bash'), findsOneWidget);
198+
// Header shows the tool's display name (lowercase), left-aligned.
199+
expect(find.text('bash'), findsOneWidget);
200200
expect(find.text('Command'), findsOneWidget);
201201
// The command appears both in the header subtitle and the Command section.
202202
expect(find.text('echo hi'), findsWidgets);
@@ -225,7 +225,7 @@ void main() {
225225
);
226226
await tester.pumpAndSettle();
227227

228-
expect(find.text('Grep'), findsOneWidget);
228+
expect(find.text('grep'), findsOneWidget);
229229
// Pattern shows in the header subtitle and the params section.
230230
expect(find.text('TODO'), findsWidgets);
231231
expect(find.text('*.dart'), findsOneWidget);
@@ -286,7 +286,7 @@ void main() {
286286
);
287287
await tester.pumpAndSettle();
288288
// Header uses the tool name, not the path.
289-
expect(find.text('Edit'), findsOneWidget);
289+
expect(find.text('edit'), findsOneWidget);
290290
expect(find.text('foo'), findsOneWidget);
291291
expect(find.text('bar'), findsOneWidget);
292292
});

0 commit comments

Comments
 (0)