@chrysb/alphaclaw 0.6.2-beta.6 → 0.7.0-beta.1

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.
@@ -1,34 +1,63 @@
1
1
  /* ── Agents detail layout ────────────────────── */
2
2
 
3
3
  .app-content-pane.agents-pane {
4
- padding: 0;
4
+ overflow: hidden;
5
+ padding-left: 0;
6
+ padding-right: 0;
7
+ padding-bottom: 0;
5
8
  }
6
9
 
7
10
  /* ── Detail panel ────────────────────────────── */
8
11
 
9
12
  .agents-detail-panel {
10
13
  height: 100%;
11
- overflow-y: auto;
12
- padding: 0 32px;
14
+ display: flex;
15
+ flex-direction: column;
16
+ min-height: 0;
17
+ }
18
+
19
+ .agents-detail-header-area {
20
+ padding: 8px 32px 16px;
13
21
  }
14
22
 
15
- .agents-detail-inner {
23
+ .agents-detail-header-area-inner {
16
24
  max-width: 42rem;
17
25
  width: 100%;
18
26
  margin: 0 auto;
19
- display: flex;
20
- flex-direction: column;
21
- min-height: 100%;
22
27
  }
23
28
 
24
29
  .agents-detail-header {
25
- padding-top: 16px;
26
30
  display: flex;
27
31
  align-items: flex-start;
28
32
  justify-content: space-between;
29
33
  gap: 12px;
30
34
  }
31
35
 
36
+ .agents-detail-body {
37
+ flex: 1;
38
+ min-height: 0;
39
+ overflow-y: auto;
40
+ overflow-x: hidden;
41
+ padding: 0 32px;
42
+ }
43
+
44
+ .agents-detail-content {
45
+ max-width: 42rem;
46
+ width: 100%;
47
+ margin: 0 auto;
48
+ padding: 0 0 24px;
49
+ }
50
+
51
+ @media (max-width: 768px) {
52
+ .agents-detail-header-area {
53
+ padding: 16px 14px 0;
54
+ }
55
+
56
+ .agents-detail-body {
57
+ padding: 0 14px;
58
+ }
59
+ }
60
+
32
61
  .agents-detail-header-title {
33
62
  font-size: 16px;
34
63
  font-weight: 600;
@@ -72,11 +101,6 @@
72
101
  border-bottom-color: var(--accent);
73
102
  }
74
103
 
75
- .agents-detail-content {
76
- flex: 1;
77
- padding: 16px 0;
78
- }
79
-
80
104
  /* ── Empty state ─────────────────────────────── */
81
105
 
82
106
  .agents-empty-state {
@@ -1,5 +1,6 @@
1
1
  .app-content-pane.cron-pane {
2
- padding: 0;
2
+ padding: 24px 32px 12px;
3
+ overflow: hidden;
3
4
  }
4
5
 
5
6
  .cron-tab-shell {
@@ -10,8 +11,7 @@
10
11
  }
11
12
 
12
13
  .cron-tab-header {
13
- padding: 16px 0 12px;
14
- border-bottom: 1px solid var(--border);
14
+ padding: 0 0 16px;
15
15
  }
16
16
 
17
17
  .cron-tab-header-content {
@@ -33,13 +33,28 @@
33
33
  }
34
34
 
35
35
  .cron-tab-main-content {
36
- width: min(100% - 40px, 672px);
36
+ width: 100%;
37
+ max-width: 672px;
37
38
  margin-left: auto;
38
39
  margin-right: auto;
39
40
  padding: 0 0 24px;
40
41
  min-height: 100%;
41
42
  }
42
43
 
44
+ .cron-tab-main-content .cron-detail-content {
45
+ padding-top: 8px;
46
+ }
47
+
48
+ @media (max-width: 768px) {
49
+ .app-content-pane.cron-pane {
50
+ padding: 0 14px 12px;
51
+ }
52
+
53
+ .cron-tab-header {
54
+ padding: 0 0 12px;
55
+ }
56
+ }
57
+
43
58
  .cron-tab-selector-shell {
44
59
  position: relative;
45
60
  width: min(100%, 320px);
@@ -329,7 +344,6 @@
329
344
  .cron-calendar-legend-pill {
330
345
  font-size: 10px;
331
346
  line-height: 1;
332
- border: 1px solid transparent;
333
347
  border-radius: 999px;
334
348
  padding: 4px 7px;
335
349
  }
@@ -338,13 +352,13 @@
338
352
  border: 1px solid var(--border);
339
353
  border-radius: 10px;
340
354
  overflow: auto;
341
- background: rgba(255, 255, 255, 0.01);
355
+ background: var(--bg-surface);
342
356
  }
343
357
 
344
358
  .cron-calendar-grid-header,
345
359
  .cron-calendar-grid-row {
346
360
  display: grid;
347
- grid-template-columns: 80px repeat(7, minmax(80px, 1fr));
361
+ grid-template-columns: 72px repeat(7, minmax(80px, 1fr));
348
362
  }
349
363
 
350
364
  .cron-calendar-day-header {
@@ -370,6 +384,79 @@
370
384
  border-bottom: 1px solid var(--border);
371
385
  border-right: 1px solid var(--border);
372
386
  background: rgba(0, 0, 0, 0.15);
387
+ position: sticky;
388
+ left: 0;
389
+ z-index: 2;
390
+ }
391
+
392
+ .cron-calendar-grid-header .cron-calendar-hour-cell {
393
+ top: 0;
394
+ z-index: 3;
395
+ }
396
+
397
+ .cron-calendar-grid-corner {
398
+ display: flex;
399
+ align-items: center;
400
+ justify-content: center;
401
+ }
402
+
403
+ .cron-calendar-expand-btn {
404
+ width: 22px;
405
+ height: 22px;
406
+ border-radius: 6px;
407
+ border: 1px solid var(--border);
408
+ background: rgba(255, 255, 255, 0.03);
409
+ color: var(--text-dim);
410
+ display: inline-flex;
411
+ align-items: center;
412
+ justify-content: center;
413
+ }
414
+
415
+ .cron-calendar-expand-btn:hover {
416
+ color: var(--text);
417
+ border-color: rgba(148, 163, 184, 0.5);
418
+ }
419
+
420
+ .cron-calendar-grid-wrap {
421
+ position: relative;
422
+ }
423
+
424
+ .cron-calendar-lightbox-panel {
425
+ width: min(96vw, 1200px);
426
+ max-height: 88vh;
427
+ display: flex;
428
+ flex-direction: column;
429
+ gap: 10px;
430
+ padding: 16px;
431
+ border: 1px solid var(--border);
432
+ border-radius: 12px;
433
+ background: var(--bg-sidebar);
434
+ }
435
+
436
+ .cron-calendar-lightbox-close {
437
+ width: 26px;
438
+ height: 26px;
439
+ border-radius: 8px;
440
+ border: 1px solid var(--border);
441
+ background: rgba(255, 255, 255, 0.03);
442
+ color: var(--text-dim);
443
+ display: inline-flex;
444
+ align-items: center;
445
+ justify-content: center;
446
+ }
447
+
448
+ .cron-calendar-lightbox-close:hover {
449
+ color: var(--text);
450
+ border-color: rgba(148, 163, 184, 0.5);
451
+ }
452
+
453
+ .cron-calendar-lightbox-body {
454
+ min-height: 0;
455
+ overflow: auto;
456
+ }
457
+
458
+ .cron-calendar-grid-row .cron-calendar-hour-cell {
459
+ box-shadow: 1px 0 0 var(--border);
373
460
  }
374
461
 
375
462
  .cron-calendar-grid-cell {
@@ -462,31 +549,50 @@
462
549
  box-shadow: inset 0 0 0 1px rgba(250, 204, 21, 0.45);
463
550
  }
464
551
 
465
- .cron-calendar-compact-strip {
552
+ .cron-calendar-compact-list {
466
553
  display: flex;
467
- flex-wrap: wrap;
554
+ flex-direction: column;
468
555
  gap: 6px;
469
- align-items: center;
470
556
  }
471
557
 
472
- .cron-calendar-compact-chip {
558
+ .cron-calendar-compact-row {
559
+ width: 100%;
560
+ display: flex;
561
+ align-items: center;
562
+ justify-content: space-between;
563
+ gap: 10px;
564
+ border: 1px solid rgba(148, 163, 184, 0.32);
565
+ border-radius: 8px;
566
+ padding: 7px 9px;
567
+ text-align: left;
473
568
  font-size: 11px;
474
569
  line-height: 1.2;
475
- border: 1px solid rgba(148, 163, 184, 0.32);
476
- border-radius: 7px;
477
- padding: 4px 8px;
570
+ }
571
+
572
+ .cron-calendar-compact-main {
573
+ min-width: 0;
478
574
  display: inline-flex;
479
575
  align-items: center;
480
- gap: 6px;
481
- max-width: 260px;
482
- cursor: pointer;
576
+ gap: 8px;
483
577
  }
484
578
 
485
579
  .cron-calendar-compact-time {
486
580
  font-size: 10px;
487
581
  font-family: var(--font-mono, monospace);
488
- opacity: 0.7;
582
+ opacity: 0.72;
583
+ white-space: nowrap;
584
+ }
585
+
586
+ .cron-calendar-compact-name {
587
+ color: var(--text);
588
+ }
589
+
590
+ .cron-calendar-compact-estimate {
591
+ font-size: 10px;
592
+ color: var(--text);
593
+ font-weight: 500;
489
594
  white-space: nowrap;
595
+ text-align: right;
490
596
  }
491
597
 
492
598
  .cron-runs-trend-bars {
@@ -63,6 +63,62 @@
63
63
  padding: 0;
64
64
  }
65
65
 
66
+ /* ── Fixed-header pane shell ────────────────────── */
67
+
68
+ .app-content-pane.ac-fixed-header-pane {
69
+ overflow: hidden;
70
+ padding-left: 0;
71
+ padding-right: 0;
72
+ padding-bottom: 0;
73
+ }
74
+
75
+ .ac-pane-shell {
76
+ height: 100%;
77
+ display: flex;
78
+ flex-direction: column;
79
+ min-height: 0;
80
+ }
81
+
82
+ .ac-pane-header {
83
+ padding: 16px 32px 16px;
84
+ }
85
+
86
+ .ac-pane-header-content {
87
+ width: 100%;
88
+ max-width: 672px;
89
+ margin-left: auto;
90
+ margin-right: auto;
91
+ }
92
+
93
+ .ac-pane-body {
94
+ flex: 1;
95
+ min-height: 0;
96
+ overflow-y: auto;
97
+ overflow-x: hidden;
98
+ padding: 0 32px;
99
+ }
100
+
101
+ .ac-pane-body-content {
102
+ width: 100%;
103
+ max-width: 672px;
104
+ margin-left: auto;
105
+ margin-right: auto;
106
+ padding-bottom: 24px;
107
+ display: flex;
108
+ flex-direction: column;
109
+ gap: 16px;
110
+ }
111
+
112
+ @media (max-width: 768px) {
113
+ .ac-pane-header {
114
+ padding: 16px 14px 12px;
115
+ }
116
+
117
+ .ac-pane-body {
118
+ padding: 0 14px;
119
+ }
120
+ }
121
+
66
122
  /* ── Sidebar ───────────────────────────────────── */
67
123
 
68
124
  .app-sidebar {
@@ -336,6 +392,7 @@
336
392
  }
337
393
  .app-content-pane {
338
394
  padding: 0 14px 12px;
395
+ top: 52px;
339
396
  }
340
397
 
341
398
  .sidebar-resizer {
@@ -346,7 +403,9 @@
346
403
  display: flex;
347
404
  align-items: center;
348
405
  justify-content: center;
349
- position: sticky;
406
+ position: absolute;
407
+ left: 0;
408
+ right: 0;
350
409
  top: 0;
351
410
  z-index: 15;
352
411
  background: var(--panel-bg-contrast);
@@ -355,7 +414,7 @@
355
414
  border-radius: 0;
356
415
  min-height: 52px;
357
416
  padding: 8px 14px;
358
- margin: 0 -14px 10px;
417
+ margin: 0;
359
418
  }
360
419
 
361
420
  .mobile-topbar.is-scrolled {
@@ -641,7 +641,8 @@ textarea:focus {
641
641
  }
642
642
 
643
643
  .ac-pop-actions-hidden {
644
- display: none;
644
+ visibility: hidden;
645
+ pointer-events: none;
645
646
  }
646
647
 
647
648
  .ac-pop-actions-in > * {
@@ -77,6 +77,8 @@ const App = () => {
77
77
 
78
78
  const isAgentsRoute = location.startsWith("/agents");
79
79
  const isCronRoute = location.startsWith("/cron");
80
+ const isEnvarsRoute = location.startsWith("/envars");
81
+ const isModelsRoute = location.startsWith("/models");
80
82
  const selectedAgentId = (() => {
81
83
  const match = location.match(/^\/agents\/([^/]+)/);
82
84
  return match ? decodeURIComponent(match[1]) : "";
@@ -211,6 +213,31 @@ const App = () => {
211
213
  />
212
214
 
213
215
  <div class="app-content">
216
+ <div
217
+ class=${`mobile-topbar ${shellState.mobileTopbarScrolled ? "is-scrolled" : ""}`}
218
+ >
219
+ <button
220
+ class="mobile-topbar-menu"
221
+ onclick=${() =>
222
+ shellActions.setMobileSidebarOpen((open) => !open)}
223
+ aria-label="Open menu"
224
+ aria-expanded=${shellState.mobileSidebarOpen ? "true" : "false"}
225
+ >
226
+ <svg
227
+ width="18"
228
+ height="18"
229
+ viewBox="0 0 16 16"
230
+ fill="currentColor"
231
+ >
232
+ <path
233
+ d="M2 3.75a.75.75 0 01.75-.75h10.5a.75.75 0 010 1.5H2.75A.75.75 0 012 3.75zm0 4.25a.75.75 0 01.75-.75h10.5a.75.75 0 010 1.5H2.75A.75.75 0 012 8zm0 4.25a.75.75 0 01.75-.75h10.5a.75.75 0 010 1.5H2.75a.75.75 0 01-.75-.75z"
234
+ />
235
+ </svg>
236
+ </button>
237
+ <span class="mobile-topbar-title">
238
+ <span style="color: var(--accent)">alpha</span>claw
239
+ </span>
240
+ </div>
214
241
  <div
215
242
  class="app-content-pane browse-pane"
216
243
  style=${{ display: browseState.isBrowseRoute ? "block" : "none" }}
@@ -265,38 +292,25 @@ const App = () => {
265
292
  onSetLocation=${setLocation}
266
293
  />
267
294
  </div>
295
+ <div
296
+ class="app-content-pane ac-fixed-header-pane"
297
+ style=${{ display: isEnvarsRoute ? "block" : "none" }}
298
+ >
299
+ <${EnvarsRoute} onRestartRequired=${controllerActions.setRestartRequired} />
300
+ </div>
301
+ <div
302
+ class="app-content-pane ac-fixed-header-pane"
303
+ style=${{ display: isModelsRoute ? "block" : "none" }}
304
+ >
305
+ <${ModelsRoute} onRestartRequired=${controllerActions.setRestartRequired} />
306
+ </div>
268
307
  <div
269
308
  class="app-content-pane"
270
309
  onscroll=${shellActions.handlePaneScroll}
271
- style=${{ display: browseState.isBrowseRoute || isAgentsRoute || isCronRoute ? "none" : "block" }}
310
+ style=${{ display: browseState.isBrowseRoute || isAgentsRoute || isCronRoute || isEnvarsRoute || isModelsRoute ? "none" : "block" }}
272
311
  >
273
- <div
274
- class=${`mobile-topbar ${shellState.mobileTopbarScrolled ? "is-scrolled" : ""}`}
275
- >
276
- <button
277
- class="mobile-topbar-menu"
278
- onclick=${() =>
279
- shellActions.setMobileSidebarOpen((open) => !open)}
280
- aria-label="Open menu"
281
- aria-expanded=${shellState.mobileSidebarOpen ? "true" : "false"}
282
- >
283
- <svg
284
- width="18"
285
- height="18"
286
- viewBox="0 0 16 16"
287
- fill="currentColor"
288
- >
289
- <path
290
- d="M2 3.75a.75.75 0 01.75-.75h10.5a.75.75 0 010 1.5H2.75A.75.75 0 012 3.75zm0 4.25a.75.75 0 01.75-.75h10.5a.75.75 0 010 1.5H2.75A.75.75 0 012 8zm0 4.25a.75.75 0 01.75-.75h10.5a.75.75 0 010 1.5H2.75a.75.75 0 01-.75-.75z"
291
- />
292
- </svg>
293
- </button>
294
- <span class="mobile-topbar-title">
295
- <span style="color: var(--accent)">alpha</span>claw
296
- </span>
297
- </div>
298
312
  <div class="max-w-2xl w-full mx-auto">
299
- ${!browseState.isBrowseRoute && !isAgentsRoute && !isCronRoute
313
+ ${!browseState.isBrowseRoute && !isAgentsRoute && !isCronRoute && !isEnvarsRoute && !isModelsRoute
300
314
  ? html`
301
315
  <${Switch}>
302
316
  <${Route} path="/general">
@@ -336,9 +350,6 @@ const App = () => {
336
350
  <${Route} path="/telegram">
337
351
  <${RouteRedirect} to="/telegram/default" />
338
352
  </${Route}>
339
- <${Route} path="/models">
340
- <${ModelsRoute} onRestartRequired=${controllerActions.setRestartRequired} />
341
- </${Route}>
342
353
  <${Route} path="/providers">
343
354
  <${RouteRedirect} to="/models" />
344
355
  </${Route}>
@@ -368,9 +379,6 @@ const App = () => {
368
379
  <${Route} path="/usage">
369
380
  <${UsageRoute} onSetLocation=${setLocation} />
370
381
  </${Route}>
371
- <${Route} path="/envars">
372
- <${EnvarsRoute} onRestartRequired=${controllerActions.setRestartRequired} />
373
- </${Route}>
374
382
  <${Route} path="/webhooks/:hookName">
375
383
  ${(params) => html`
376
384
  <${WebhooksRoute}
@@ -1,5 +1,5 @@
1
1
  import { h } from "https://esm.sh/preact";
2
- import { useState, useCallback } from "https://esm.sh/preact/hooks";
2
+ import { useState, useCallback, useMemo } from "https://esm.sh/preact/hooks";
3
3
  import htm from "https://esm.sh/htm";
4
4
  import { ActionButton } from "../action-button.js";
5
5
  import { Badge } from "../badge.js";
@@ -64,6 +64,12 @@ export const AgentDetailPanel = ({
64
64
 
65
65
  const isSaving = saving || savingTools;
66
66
 
67
+ const toolsSummary = useMemo(() => ({
68
+ profile: tools.profile,
69
+ enabledCount: (tools.toolStates || []).filter((t) => t.enabled).length,
70
+ totalCount: (tools.toolStates || []).length,
71
+ }), [tools.profile, tools.toolStates]);
72
+
67
73
  if (!agent) {
68
74
  return html`
69
75
  <div class="agents-detail-panel">
@@ -76,57 +82,61 @@ export const AgentDetailPanel = ({
76
82
 
77
83
  return html`
78
84
  <div class="agents-detail-panel">
79
- <div class="agents-detail-inner">
80
- <div class="agents-detail-header">
81
- <div class="min-w-0">
82
- <div class="flex items-center gap-2 min-w-0">
83
- <span class="agents-detail-header-title">
84
- ${agent.name || agent.id}
85
- </span>
86
- <button
87
- type="button"
88
- class="text-gray-500 hover:text-gray-300 transition-colors p-0.5 -ml-0.5"
89
- onclick=${() => onEdit(agent)}
90
- title="Edit agent name"
91
- >
92
- <${PencilIcon} />
93
- </button>
94
- ${agent.default
95
- ? html`<${Badge} tone="cyan">Default</${Badge}>`
96
- : null}
97
- </div>
98
- <div class="mt-1 flex flex-wrap items-center gap-x-1.5 gap-y-1 min-w-0 text-xs text-gray-500">
99
- <span class="font-mono">${agent.id}</span>
85
+ <div class="agents-detail-header-area">
86
+ <div class="agents-detail-header-area-inner">
87
+ <div class="agents-detail-header">
88
+ <div class="min-w-0">
89
+ <div class="flex items-center gap-2 min-w-0">
90
+ <span class="agents-detail-header-title">
91
+ ${agent.name || agent.id}
92
+ </span>
93
+ <button
94
+ type="button"
95
+ class="text-gray-500 hover:text-gray-300 transition-colors p-0.5 -ml-0.5"
96
+ onclick=${() => onEdit(agent)}
97
+ title="Edit agent name"
98
+ >
99
+ <${PencilIcon} />
100
+ </button>
101
+ ${agent.default
102
+ ? html`<${Badge} tone="cyan">Default</${Badge}>`
103
+ : null}
104
+ </div>
105
+ <div class="mt-1 flex flex-wrap items-center gap-x-1.5 gap-y-1 min-w-0 text-xs text-gray-500">
106
+ <span class="font-mono">${agent.id}</span>
107
+ </div>
100
108
  </div>
109
+ <${PopActions} visible=${tools.dirty}>
110
+ <${ActionButton}
111
+ onClick=${tools.reset}
112
+ disabled=${isSaving}
113
+ tone="secondary"
114
+ size="sm"
115
+ idleLabel="Cancel"
116
+ className="text-xs"
117
+ />
118
+ <${ActionButton}
119
+ onClick=${handleSaveTools}
120
+ disabled=${isSaving}
121
+ loading=${isSaving}
122
+ loadingMode="inline"
123
+ tone="primary"
124
+ size="sm"
125
+ idleLabel="Save changes"
126
+ loadingLabel="Saving…"
127
+ className="text-xs"
128
+ />
129
+ </${PopActions}>
101
130
  </div>
102
- <${PopActions} visible=${tools.dirty}>
103
- <${ActionButton}
104
- onClick=${tools.reset}
105
- disabled=${isSaving}
106
- tone="secondary"
107
- size="sm"
108
- idleLabel="Cancel"
109
- className="text-xs"
110
- />
111
- <${ActionButton}
112
- onClick=${handleSaveTools}
113
- disabled=${isSaving}
114
- loading=${isSaving}
115
- loadingMode="inline"
116
- tone="primary"
117
- size="sm"
118
- idleLabel="Save changes"
119
- loadingLabel="Saving…"
120
- className="text-xs"
121
- />
122
- </${PopActions}>
131
+ <${PillTabs}
132
+ tabs=${kDetailTabs}
133
+ activeTab=${activeTab}
134
+ onSelectTab=${onSelectTab}
135
+ className="flex items-center gap-2 pt-6"
136
+ />
123
137
  </div>
124
- <${PillTabs}
125
- tabs=${kDetailTabs}
126
- activeTab=${activeTab}
127
- onSelectTab=${onSelectTab}
128
- className="flex items-center gap-2 pt-6"
129
- />
138
+ </div>
139
+ <div class="agents-detail-body">
130
140
  <div class="agents-detail-content">
131
141
  ${activeTab === "overview"
132
142
  ? html`
@@ -134,10 +144,12 @@ export const AgentDetailPanel = ({
134
144
  agent=${agent}
135
145
  agents=${agents}
136
146
  saving=${saving}
147
+ toolsSummary=${toolsSummary}
137
148
  onUpdateAgent=${onUpdateAgent}
138
149
  onSetLocation=${onSetLocation}
139
150
  onOpenWorkspace=${onOpenWorkspace}
140
151
  onSwitchToModels=${() => onSetLocation("/models")}
152
+ onSwitchToTools=${() => onSelectTab("tools")}
141
153
  onSetDefault=${onSetDefault}
142
154
  onDelete=${onDelete}
143
155
  />
@@ -3,6 +3,7 @@ import htm from "https://esm.sh/htm";
3
3
  import { ChannelOperationsPanel } from "../../channel-operations-panel.js";
4
4
  import { ManageCard } from "./manage-card.js";
5
5
  import { AgentModelCard } from "./model-card.js";
6
+ import { AgentToolsCard } from "./tools-card.js";
6
7
  import { WorkspaceCard } from "./workspace-card.js";
7
8
 
8
9
  const html = htm.bind(h);
@@ -11,10 +12,12 @@ export const AgentOverview = ({
11
12
  agent = {},
12
13
  agents = [],
13
14
  saving = false,
15
+ toolsSummary = {},
14
16
  onUpdateAgent = async () => {},
15
17
  onSetLocation = () => {},
16
18
  onOpenWorkspace = () => {},
17
19
  onSwitchToModels = () => {},
20
+ onSwitchToTools = () => {},
18
21
  onSetDefault = () => {},
19
22
  onDelete = () => {},
20
23
  }) => {
@@ -33,6 +36,12 @@ export const AgentOverview = ({
33
36
  onUpdateAgent=${onUpdateAgent}
34
37
  onSwitchToModels=${onSwitchToModels}
35
38
  />
39
+ <${AgentToolsCard}
40
+ profile=${toolsSummary.profile || "full"}
41
+ enabledCount=${toolsSummary.enabledCount || 0}
42
+ totalCount=${toolsSummary.totalCount || 0}
43
+ onSwitchToTools=${onSwitchToTools}
44
+ />
36
45
  <${ChannelOperationsPanel}
37
46
  agent=${agent}
38
47
  agents=${agents}