@chrysb/alphaclaw 0.6.2-beta.6 → 0.7.0-beta.0
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/lib/public/css/agents.css +37 -13
- package/lib/public/css/cron.css +35 -4
- package/lib/public/css/shell.css +61 -2
- package/lib/public/css/theme.css +2 -1
- package/lib/public/js/app.js +41 -33
- package/lib/public/js/components/agents-tab/agent-detail-panel.js +61 -49
- package/lib/public/js/components/agents-tab/agent-overview/index.js +9 -0
- package/lib/public/js/components/agents-tab/agent-overview/tools-card.js +54 -0
- package/lib/public/js/components/cron-tab/cron-calendar.js +13 -42
- package/lib/public/js/components/cron-tab/cron-helpers.js +48 -0
- package/lib/public/js/components/cron-tab/cron-insights-panel.js +8 -39
- package/lib/public/js/components/cron-tab/cron-run-history-panel.js +8 -9
- package/lib/public/js/components/cron-tab/cron-runs-trend-card.js +4 -22
- package/lib/public/js/components/envars.js +187 -46
- package/lib/public/js/components/models-tab/index.js +137 -133
- package/lib/public/js/components/models-tab/provider-auth-card.js +8 -1
- package/lib/public/js/components/models-tab/use-models.js +35 -8
- package/lib/public/js/components/pane-shell.js +27 -0
- package/lib/public/js/components/routes/envars-route.js +1 -3
- package/lib/public/js/components/routes/models-route.js +1 -3
- package/lib/public/js/lib/app-navigation.js +1 -1
- package/lib/server/cost-utils.js +2 -2
- package/package.json +1 -1
|
@@ -1,34 +1,63 @@
|
|
|
1
1
|
/* ── Agents detail layout ────────────────────── */
|
|
2
2
|
|
|
3
3
|
.app-content-pane.agents-pane {
|
|
4
|
-
|
|
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
|
-
|
|
12
|
-
|
|
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 {
|
package/lib/public/css/cron.css
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
.app-content-pane.cron-pane {
|
|
2
|
-
padding:
|
|
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:
|
|
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:
|
|
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);
|
|
@@ -370,6 +385,22 @@
|
|
|
370
385
|
border-bottom: 1px solid var(--border);
|
|
371
386
|
border-right: 1px solid var(--border);
|
|
372
387
|
background: rgba(0, 0, 0, 0.15);
|
|
388
|
+
position: sticky;
|
|
389
|
+
left: 0;
|
|
390
|
+
z-index: 2;
|
|
391
|
+
}
|
|
392
|
+
|
|
393
|
+
.cron-calendar-grid-header .cron-calendar-hour-cell {
|
|
394
|
+
top: 0;
|
|
395
|
+
z-index: 3;
|
|
396
|
+
}
|
|
397
|
+
|
|
398
|
+
.cron-calendar-grid-wrap {
|
|
399
|
+
position: relative;
|
|
400
|
+
}
|
|
401
|
+
|
|
402
|
+
.cron-calendar-grid-row .cron-calendar-hour-cell {
|
|
403
|
+
box-shadow: 1px 0 0 var(--border);
|
|
373
404
|
}
|
|
374
405
|
|
|
375
406
|
.cron-calendar-grid-cell {
|
package/lib/public/css/shell.css
CHANGED
|
@@ -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:
|
|
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
|
|
417
|
+
margin: 0;
|
|
359
418
|
}
|
|
360
419
|
|
|
361
420
|
.mobile-topbar.is-scrolled {
|
package/lib/public/css/theme.css
CHANGED
package/lib/public/js/app.js
CHANGED
|
@@ -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-
|
|
80
|
-
<div class="agents-detail-header">
|
|
81
|
-
<div class="
|
|
82
|
-
<div class="
|
|
83
|
-
<
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
<
|
|
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
|
-
<${
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
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
|
-
|
|
125
|
-
|
|
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}
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
import { h } from "https://esm.sh/preact";
|
|
2
|
+
import htm from "https://esm.sh/htm";
|
|
3
|
+
import { kProfileLabels } from "../agent-tools/tool-catalog.js";
|
|
4
|
+
|
|
5
|
+
const html = htm.bind(h);
|
|
6
|
+
|
|
7
|
+
export const AgentToolsCard = ({
|
|
8
|
+
profile = "full",
|
|
9
|
+
enabledCount = 0,
|
|
10
|
+
totalCount = 0,
|
|
11
|
+
onSwitchToTools = () => {},
|
|
12
|
+
}) => {
|
|
13
|
+
const profileLabel = kProfileLabels[profile] || profile;
|
|
14
|
+
|
|
15
|
+
return html`
|
|
16
|
+
<div class="bg-surface border border-border rounded-xl p-4">
|
|
17
|
+
<h2 class="card-label mb-3">Tools</h2>
|
|
18
|
+
<div
|
|
19
|
+
class="flex items-center justify-between gap-3 cursor-pointer hover:bg-white/5 -mx-2 px-2 py-1.5 rounded-lg transition-colors"
|
|
20
|
+
role="button"
|
|
21
|
+
tabindex="0"
|
|
22
|
+
onclick=${onSwitchToTools}
|
|
23
|
+
onKeyDown=${(e) => {
|
|
24
|
+
if (e.key === "Enter" || e.key === " ") {
|
|
25
|
+
e.preventDefault();
|
|
26
|
+
onSwitchToTools();
|
|
27
|
+
}
|
|
28
|
+
}}
|
|
29
|
+
>
|
|
30
|
+
<span class="font-medium text-sm">${profileLabel}</span>
|
|
31
|
+
<span class="flex items-center gap-2 shrink-0">
|
|
32
|
+
<span class="text-xs text-gray-500">
|
|
33
|
+
${enabledCount}/${totalCount} enabled
|
|
34
|
+
</span>
|
|
35
|
+
<svg
|
|
36
|
+
width="14"
|
|
37
|
+
height="14"
|
|
38
|
+
viewBox="0 0 16 16"
|
|
39
|
+
fill="none"
|
|
40
|
+
class="text-gray-600"
|
|
41
|
+
>
|
|
42
|
+
<path
|
|
43
|
+
d="M6 3.5L10.5 8L6 12.5"
|
|
44
|
+
stroke="currentColor"
|
|
45
|
+
stroke-width="2"
|
|
46
|
+
stroke-linecap="round"
|
|
47
|
+
stroke-linejoin="round"
|
|
48
|
+
/>
|
|
49
|
+
</svg>
|
|
50
|
+
</span>
|
|
51
|
+
</div>
|
|
52
|
+
</div>
|
|
53
|
+
`;
|
|
54
|
+
};
|