@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.
- package/lib/public/css/agents.css +37 -13
- package/lib/public/css/cron.css +124 -18
- 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 +164 -151
- 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/icons.js +11 -0
- 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
|
@@ -2,7 +2,7 @@ import { h } from "https://esm.sh/preact";
|
|
|
2
2
|
import { useEffect, useMemo, useRef, useState } from "https://esm.sh/preact/hooks";
|
|
3
3
|
import htm from "https://esm.sh/htm";
|
|
4
4
|
import { SegmentedControl } from "../segmented-control.js";
|
|
5
|
-
import { formatCost } from "./cron-helpers.js";
|
|
5
|
+
import { formatCost, getCronRunEstimatedCost } from "./cron-helpers.js";
|
|
6
6
|
|
|
7
7
|
const html = htm.bind(h);
|
|
8
8
|
|
|
@@ -64,25 +64,6 @@ const getBucketConfig = (range = kRange7d) => {
|
|
|
64
64
|
};
|
|
65
65
|
};
|
|
66
66
|
|
|
67
|
-
const getEstimatedCostForEntry = (entry = {}) => {
|
|
68
|
-
const usage = entry?.usage || {};
|
|
69
|
-
const candidates = [
|
|
70
|
-
entry?.estimatedCost,
|
|
71
|
-
entry?.estimated_cost,
|
|
72
|
-
usage?.estimatedCost,
|
|
73
|
-
usage?.estimated_cost,
|
|
74
|
-
usage?.totalCost,
|
|
75
|
-
usage?.total_cost,
|
|
76
|
-
usage?.costUsd,
|
|
77
|
-
usage?.cost,
|
|
78
|
-
];
|
|
79
|
-
for (const candidate of candidates) {
|
|
80
|
-
const numericValue = Number(candidate);
|
|
81
|
-
if (Number.isFinite(numericValue) && numericValue >= 0) return numericValue;
|
|
82
|
-
}
|
|
83
|
-
return null;
|
|
84
|
-
};
|
|
85
|
-
|
|
86
67
|
const buildTrendData = ({ bulkRunsByJobId = {}, nowMs = Date.now(), range = kRange7d } = {}) => {
|
|
87
68
|
const config = getBucketConfig(range);
|
|
88
69
|
const safeNowMs = Number.isFinite(Number(nowMs)) ? Number(nowMs) : Date.now();
|
|
@@ -129,7 +110,7 @@ const buildTrendData = ({ bulkRunsByJobId = {}, nowMs = Date.now(), range = kRan
|
|
|
129
110
|
if (!Number.isFinite(Number(bucketIndex))) return;
|
|
130
111
|
if (bucketIndex < 0 || bucketIndex >= config.bucketCount) return;
|
|
131
112
|
points[bucketIndex][status] += 1;
|
|
132
|
-
const estimatedCost =
|
|
113
|
+
const estimatedCost = getCronRunEstimatedCost(entry);
|
|
133
114
|
if (estimatedCost != null) {
|
|
134
115
|
points[bucketIndex].totalCost += estimatedCost;
|
|
135
116
|
points[bucketIndex].costCount += 1;
|
|
@@ -305,6 +286,7 @@ export const CronRunsTrendCard = ({
|
|
|
305
286
|
},
|
|
306
287
|
plugins: {
|
|
307
288
|
legend: {
|
|
289
|
+
position: "bottom",
|
|
308
290
|
labels: {
|
|
309
291
|
color: "rgba(209,213,219,1)",
|
|
310
292
|
boxWidth: 10,
|
|
@@ -339,7 +321,7 @@ export const CronRunsTrendCard = ({
|
|
|
339
321
|
return html`
|
|
340
322
|
<section class="bg-surface border border-border rounded-xl p-4 space-y-3">
|
|
341
323
|
<div class="flex items-center justify-between gap-2">
|
|
342
|
-
<h3 class="card-label cron-calendar-title">Run
|
|
324
|
+
<h3 class="card-label cron-calendar-title">Run Outcomes</h3>
|
|
343
325
|
<${SegmentedControl}
|
|
344
326
|
options=${kRanges}
|
|
345
327
|
value=${range}
|
|
@@ -1,11 +1,18 @@
|
|
|
1
1
|
import { h } from "https://esm.sh/preact";
|
|
2
|
-
import {
|
|
2
|
+
import {
|
|
3
|
+
useState,
|
|
4
|
+
useEffect,
|
|
5
|
+
useCallback,
|
|
6
|
+
useRef,
|
|
7
|
+
} from "https://esm.sh/preact/hooks";
|
|
3
8
|
import htm from "https://esm.sh/htm";
|
|
4
9
|
import { fetchEnvVars, saveEnvVars } from "../lib/api.js";
|
|
5
10
|
import { showToast } from "./toast.js";
|
|
6
11
|
import { SecretInput } from "./secret-input.js";
|
|
7
12
|
import { PageHeader } from "./page-header.js";
|
|
8
13
|
import { ActionButton } from "./action-button.js";
|
|
14
|
+
import { PopActions } from "./pop-actions.js";
|
|
15
|
+
import { PaneShell } from "./pane-shell.js";
|
|
9
16
|
import {
|
|
10
17
|
Brain2LineIcon,
|
|
11
18
|
ChatVoiceLineIcon,
|
|
@@ -44,7 +51,11 @@ const kFeatureIconByName = {
|
|
|
44
51
|
label: "Speech to text",
|
|
45
52
|
},
|
|
46
53
|
};
|
|
47
|
-
const normalizeEnvVarKey = (raw) =>
|
|
54
|
+
const normalizeEnvVarKey = (raw) =>
|
|
55
|
+
raw
|
|
56
|
+
.trim()
|
|
57
|
+
.toUpperCase()
|
|
58
|
+
.replace(/[^A-Z0-9_]/g, "_");
|
|
48
59
|
const kManagedChannelTokenPattern =
|
|
49
60
|
/^(?:TELEGRAM_BOT_TOKEN|DISCORD_BOT_TOKEN|SLACK_BOT_TOKEN|SLACK_APP_TOKEN)(?:_[A-Z0-9_]+)?$/;
|
|
50
61
|
const stripSurroundingQuotes = (raw) => {
|
|
@@ -59,7 +70,11 @@ const stripSurroundingQuotes = (raw) => {
|
|
|
59
70
|
return value;
|
|
60
71
|
};
|
|
61
72
|
const isManagedChannelTokenKey = (key = "") =>
|
|
62
|
-
kManagedChannelTokenPattern.test(
|
|
73
|
+
kManagedChannelTokenPattern.test(
|
|
74
|
+
String(key || "")
|
|
75
|
+
.trim()
|
|
76
|
+
.toUpperCase(),
|
|
77
|
+
);
|
|
63
78
|
const getVarsSignature = (items) =>
|
|
64
79
|
JSON.stringify(
|
|
65
80
|
(items || [])
|
|
@@ -85,19 +100,119 @@ const sortCustomVarsAlphabetically = (items) => {
|
|
|
85
100
|
};
|
|
86
101
|
|
|
87
102
|
const kHintByKey = {
|
|
88
|
-
ANTHROPIC_API_KEY: html`from
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
103
|
+
ANTHROPIC_API_KEY: html`from${" "}
|
|
104
|
+
<a
|
|
105
|
+
href="https://console.anthropic.com"
|
|
106
|
+
target="_blank"
|
|
107
|
+
class="hover:underline"
|
|
108
|
+
style="color: var(--accent-link)"
|
|
109
|
+
>console.anthropic.com</a
|
|
110
|
+
>`,
|
|
111
|
+
ANTHROPIC_TOKEN: html`from
|
|
112
|
+
<code class="text-xs bg-black/30 px-1 rounded">claude setup-token</code>`,
|
|
113
|
+
OPENAI_API_KEY: html`from${" "}
|
|
114
|
+
<a
|
|
115
|
+
href="https://platform.openai.com"
|
|
116
|
+
target="_blank"
|
|
117
|
+
class="hover:underline"
|
|
118
|
+
style="color: var(--accent-link)"
|
|
119
|
+
>platform.openai.com</a
|
|
120
|
+
>`,
|
|
121
|
+
GEMINI_API_KEY: html`from${" "}
|
|
122
|
+
<a
|
|
123
|
+
href="https://aistudio.google.com"
|
|
124
|
+
target="_blank"
|
|
125
|
+
class="hover:underline"
|
|
126
|
+
style="color: var(--accent-link)"
|
|
127
|
+
>aistudio.google.com</a
|
|
128
|
+
>`,
|
|
129
|
+
ELEVENLABS_API_KEY: html`from${" "}
|
|
130
|
+
<a
|
|
131
|
+
href="https://elevenlabs.io"
|
|
132
|
+
target="_blank"
|
|
133
|
+
class="hover:underline"
|
|
134
|
+
style="color: var(--accent-link)"
|
|
135
|
+
>elevenlabs.io</a
|
|
136
|
+
>${" "} · ${" "}
|
|
137
|
+
<code class="text-xs bg-black/30 px-1 rounded">XI_API_KEY</code> also
|
|
138
|
+
supported`,
|
|
139
|
+
GITHUB_WORKSPACE_REPO: html`use
|
|
140
|
+
<code class="text-xs bg-black/30 px-1 rounded">owner/repo</code> or
|
|
141
|
+
<code class="text-xs bg-black/30 px-1 rounded"
|
|
142
|
+
>https://github.com/owner/repo</code
|
|
143
|
+
>`,
|
|
144
|
+
TELEGRAM_BOT_TOKEN: html`from${" "}
|
|
145
|
+
<a
|
|
146
|
+
href="https://t.me/BotFather"
|
|
147
|
+
target="_blank"
|
|
148
|
+
class="hover:underline"
|
|
149
|
+
style="color: var(--accent-link)"
|
|
150
|
+
>@BotFather</a
|
|
151
|
+
>
|
|
152
|
+
·
|
|
153
|
+
<a
|
|
154
|
+
href="https://docs.openclaw.ai/channels/telegram"
|
|
155
|
+
target="_blank"
|
|
156
|
+
class="hover:underline"
|
|
157
|
+
style="color: var(--accent-link)"
|
|
158
|
+
>full guide</a
|
|
159
|
+
>`,
|
|
160
|
+
DISCORD_BOT_TOKEN: html`from${" "}
|
|
161
|
+
<a
|
|
162
|
+
href="https://discord.com/developers/applications"
|
|
163
|
+
target="_blank"
|
|
164
|
+
class="hover:underline"
|
|
165
|
+
style="color: var(--accent-link)"
|
|
166
|
+
>developer portal</a
|
|
167
|
+
>
|
|
168
|
+
·
|
|
169
|
+
<a
|
|
170
|
+
href="https://docs.openclaw.ai/channels/discord"
|
|
171
|
+
target="_blank"
|
|
172
|
+
class="hover:underline"
|
|
173
|
+
style="color: var(--accent-link)"
|
|
174
|
+
>full guide</a
|
|
175
|
+
>`,
|
|
176
|
+
MISTRAL_API_KEY: html`from${" "}
|
|
177
|
+
<a
|
|
178
|
+
href="https://console.mistral.ai"
|
|
179
|
+
target="_blank"
|
|
180
|
+
class="hover:underline"
|
|
181
|
+
style="color: var(--accent-link)"
|
|
182
|
+
>console.mistral.ai</a
|
|
183
|
+
>`,
|
|
184
|
+
VOYAGE_API_KEY: html`from${" "}
|
|
185
|
+
<a
|
|
186
|
+
href="https://dash.voyageai.com"
|
|
187
|
+
target="_blank"
|
|
188
|
+
class="hover:underline"
|
|
189
|
+
style="color: var(--accent-link)"
|
|
190
|
+
>dash.voyageai.com</a
|
|
191
|
+
>`,
|
|
192
|
+
GROQ_API_KEY: html`from${" "}
|
|
193
|
+
<a
|
|
194
|
+
href="https://console.groq.com"
|
|
195
|
+
target="_blank"
|
|
196
|
+
class="hover:underline"
|
|
197
|
+
style="color: var(--accent-link)"
|
|
198
|
+
>console.groq.com</a
|
|
199
|
+
>`,
|
|
200
|
+
DEEPGRAM_API_KEY: html`from${" "}
|
|
201
|
+
<a
|
|
202
|
+
href="https://console.deepgram.com"
|
|
203
|
+
target="_blank"
|
|
204
|
+
class="hover:underline"
|
|
205
|
+
style="color: var(--accent-link)"
|
|
206
|
+
>console.deepgram.com</a
|
|
207
|
+
>`,
|
|
208
|
+
BRAVE_API_KEY: html`from${" "}
|
|
209
|
+
<a
|
|
210
|
+
href="https://brave.com/search/api/"
|
|
211
|
+
target="_blank"
|
|
212
|
+
class="hover:underline"
|
|
213
|
+
style="color: var(--accent-link)"
|
|
214
|
+
>brave.com/search/api</a
|
|
215
|
+
>${" "} — free tier available`,
|
|
101
216
|
};
|
|
102
217
|
|
|
103
218
|
const getHintContent = (envVar) => kHintByKey[envVar.key] || envVar.hint || "";
|
|
@@ -157,7 +272,8 @@ const EnvRow = ({ envVar, onChange, onDelete, disabled }) => {
|
|
|
157
272
|
? html`
|
|
158
273
|
<div class="flex items-center gap-2 mt-1 pl-3.5">
|
|
159
274
|
${featureIcons.map(
|
|
160
|
-
(feature) =>
|
|
275
|
+
(feature) =>
|
|
276
|
+
html`<${FeatureIcon} key=${feature} feature=${feature} />`,
|
|
161
277
|
)}
|
|
162
278
|
</div>
|
|
163
279
|
`
|
|
@@ -183,9 +299,7 @@ const EnvRow = ({ envVar, onChange, onDelete, disabled }) => {
|
|
|
183
299
|
</button>`
|
|
184
300
|
: null}
|
|
185
301
|
</div>
|
|
186
|
-
${hint
|
|
187
|
-
? html`<p class="text-xs text-gray-600 mt-1">${hint}</p>`
|
|
188
|
-
: null}
|
|
302
|
+
${hint ? html`<p class="text-xs text-gray-600 mt-1">${hint}</p>` : null}
|
|
189
303
|
</div>
|
|
190
304
|
</div>
|
|
191
305
|
`;
|
|
@@ -230,7 +344,9 @@ export const Envars = ({ onRestartRequired = () => {} }) => {
|
|
|
230
344
|
|
|
231
345
|
const handleDelete = (key) => {
|
|
232
346
|
setVars((prev) => prev.filter((v) => v.key !== key));
|
|
233
|
-
setPendingCustomKeys((prev) =>
|
|
347
|
+
setPendingCustomKeys((prev) =>
|
|
348
|
+
prev.filter((pendingKey) => pendingKey !== key),
|
|
349
|
+
);
|
|
234
350
|
};
|
|
235
351
|
|
|
236
352
|
const handleSave = async () => {
|
|
@@ -348,7 +464,10 @@ export const Envars = ({ onRestartRequired = () => {} }) => {
|
|
|
348
464
|
);
|
|
349
465
|
}
|
|
350
466
|
if (added) {
|
|
351
|
-
showToast(
|
|
467
|
+
showToast(
|
|
468
|
+
`Added ${added} variable${added !== 1 ? "s" : ""}`,
|
|
469
|
+
"success",
|
|
470
|
+
);
|
|
352
471
|
}
|
|
353
472
|
return;
|
|
354
473
|
}
|
|
@@ -410,7 +529,9 @@ export const Envars = ({ onRestartRequired = () => {} }) => {
|
|
|
410
529
|
const nonPending = grouped.custom
|
|
411
530
|
.filter((item) => !pending.has(item.key))
|
|
412
531
|
.sort((a, b) => String(a?.key || "").localeCompare(String(b?.key || "")));
|
|
413
|
-
const pendingAtBottom = grouped.custom.filter((item) =>
|
|
532
|
+
const pendingAtBottom = grouped.custom.filter((item) =>
|
|
533
|
+
pending.has(item.key),
|
|
534
|
+
);
|
|
414
535
|
grouped.custom = [...nonPending, ...pendingAtBottom];
|
|
415
536
|
}
|
|
416
537
|
const aiSplit = splitAiVars(grouped.ai || []);
|
|
@@ -454,7 +575,9 @@ export const Envars = ({ onRestartRequired = () => {} }) => {
|
|
|
454
575
|
`
|
|
455
576
|
: null}
|
|
456
577
|
${expanded
|
|
457
|
-
? html`<div class="divide-y divide-border border-t border-border"
|
|
578
|
+
? html`<div class="divide-y divide-border border-t border-border">
|
|
579
|
+
${renderEnvRows(hidden)}
|
|
580
|
+
</div>`
|
|
458
581
|
: null}
|
|
459
582
|
</div>
|
|
460
583
|
`;
|
|
@@ -470,33 +593,52 @@ export const Envars = ({ onRestartRequired = () => {} }) => {
|
|
|
470
593
|
};
|
|
471
594
|
|
|
472
595
|
return html`
|
|
473
|
-
|
|
474
|
-
|
|
475
|
-
|
|
476
|
-
|
|
477
|
-
|
|
478
|
-
|
|
479
|
-
|
|
480
|
-
|
|
481
|
-
|
|
482
|
-
|
|
483
|
-
|
|
484
|
-
|
|
485
|
-
|
|
486
|
-
|
|
487
|
-
|
|
488
|
-
|
|
489
|
-
|
|
596
|
+
<${PaneShell}
|
|
597
|
+
header=${html`
|
|
598
|
+
<${PageHeader}
|
|
599
|
+
title="Envars"
|
|
600
|
+
actions=${html`
|
|
601
|
+
<${PopActions} visible=${dirty}>
|
|
602
|
+
<${ActionButton}
|
|
603
|
+
onClick=${load}
|
|
604
|
+
disabled=${saving}
|
|
605
|
+
tone="secondary"
|
|
606
|
+
size="sm"
|
|
607
|
+
idleLabel="Cancel"
|
|
608
|
+
className="text-xs"
|
|
609
|
+
/>
|
|
610
|
+
<${ActionButton}
|
|
611
|
+
onClick=${handleSave}
|
|
612
|
+
disabled=${saving}
|
|
613
|
+
loading=${saving}
|
|
614
|
+
loadingMode="inline"
|
|
615
|
+
tone="primary"
|
|
616
|
+
size="sm"
|
|
617
|
+
idleLabel="Save changes"
|
|
618
|
+
loadingLabel="Saving…"
|
|
619
|
+
className="text-xs"
|
|
620
|
+
/>
|
|
621
|
+
</${PopActions}>
|
|
622
|
+
`}
|
|
623
|
+
/>
|
|
624
|
+
`}
|
|
625
|
+
>
|
|
490
626
|
${kGroupOrder
|
|
491
627
|
.filter((g) => grouped[g]?.length)
|
|
492
628
|
.map((g) => renderGroupCard(g))}
|
|
493
629
|
|
|
494
|
-
<div
|
|
630
|
+
<div
|
|
631
|
+
class="bg-surface border border-border rounded-xl overflow-hidden"
|
|
632
|
+
>
|
|
495
633
|
<div class="flex items-center justify-between px-4 pt-3 pb-2">
|
|
496
634
|
<h3 class="card-label text-xs">Add Variable</h3>
|
|
497
|
-
<span class="text-xs" style="color: var(--text-dim)"
|
|
635
|
+
<span class="text-xs" style="color: var(--text-dim)"
|
|
636
|
+
>Paste KEY=VALUE or multiple lines</span
|
|
637
|
+
>
|
|
498
638
|
</div>
|
|
499
|
-
<div
|
|
639
|
+
<div
|
|
640
|
+
class="flex items-start gap-4 px-4 py-3 border-t border-border"
|
|
641
|
+
>
|
|
500
642
|
<div class="shrink-0" style="width: 200px">
|
|
501
643
|
<input
|
|
502
644
|
type="text"
|
|
@@ -527,7 +669,6 @@ export const Envars = ({ onRestartRequired = () => {} }) => {
|
|
|
527
669
|
</div>
|
|
528
670
|
</div>
|
|
529
671
|
</div>
|
|
530
|
-
|
|
531
|
-
</div>
|
|
672
|
+
</${PaneShell}>
|
|
532
673
|
`;
|
|
533
674
|
};
|
|
@@ -428,3 +428,14 @@ export const ErrorWarningLineIcon = ({ className = "" }) => html`
|
|
|
428
428
|
/>
|
|
429
429
|
</svg>
|
|
430
430
|
`;
|
|
431
|
+
|
|
432
|
+
export const FullscreenLineIcon = ({ className = "" }) => html`
|
|
433
|
+
<svg
|
|
434
|
+
class=${className}
|
|
435
|
+
viewBox="0 0 24 24"
|
|
436
|
+
fill="currentColor"
|
|
437
|
+
aria-hidden="true"
|
|
438
|
+
>
|
|
439
|
+
<path d="M8 3V5H4V9H2V3H8ZM2 21V15H4V19H8V21H2ZM22 21H16V19H20V15H22V21ZM22 9H20V5H16V3H22V9Z" />
|
|
440
|
+
</svg>
|
|
441
|
+
`;
|