botschat 0.1.20 → 0.1.21
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/package.json +1 -1
- package/packages/api/src/do/connection-do.ts +186 -382
- package/packages/api/src/index.ts +50 -67
- package/packages/api/src/routes/agents.ts +3 -3
- package/packages/api/src/routes/auth.ts +1 -0
- package/packages/api/src/routes/channels.ts +11 -11
- package/packages/api/src/routes/demo.ts +156 -0
- package/packages/api/src/routes/sessions.ts +5 -5
- package/packages/api/src/routes/tasks.ts +33 -33
- package/packages/plugin/dist/src/channel.js +50 -0
- package/packages/plugin/dist/src/channel.js.map +1 -1
- package/packages/plugin/package.json +18 -2
- package/packages/web/dist/assets/index-BtPyCBCl.css +1 -0
- package/packages/web/dist/assets/index-BtpsFe4Z.js +2 -0
- package/packages/web/dist/assets/index-CQbIYr6_.js +2 -0
- package/packages/web/dist/assets/{index-CYQMu_-c.js → index-C_GamcQc.js} +1 -1
- package/packages/web/dist/assets/index-LiBjPMg2.js +1 -0
- package/packages/web/dist/assets/{index-DYCO-ry1.js → index-MyoWvQAH.js} +1 -1
- package/packages/web/dist/assets/index-STIPTMK8.js +1516 -0
- package/packages/web/dist/assets/{index.esm-CvOpngZM.js → index.esm-BpQAwtdR.js} +1 -1
- package/packages/web/dist/assets/{web-D3LMODYp.js → web-BbTzVNLt.js} +1 -1
- package/packages/web/dist/assets/{web-1cdhq2RW.js → web-cnzjgNfD.js} +1 -1
- package/packages/web/dist/index.html +2 -2
- package/packages/web/src/App.tsx +9 -56
- package/packages/web/src/api.ts +5 -61
- package/packages/web/src/components/ChatWindow.tsx +9 -9
- package/packages/web/src/components/CronDetail.tsx +1 -1
- package/packages/web/src/components/ImageLightbox.tsx +96 -0
- package/packages/web/src/components/LoginPage.tsx +59 -1
- package/packages/web/src/components/MessageContent.tsx +17 -2
- package/packages/web/src/components/SessionTabs.tsx +1 -1
- package/packages/web/src/components/Sidebar.tsx +1 -3
- package/packages/web/src/hooks/useIMEComposition.ts +14 -9
- package/packages/web/src/store.ts +7 -39
- package/packages/web/src/ws.ts +0 -1
- package/scripts/dev.sh +0 -53
- package/migrations/0013_agents_table.sql +0 -29
- package/migrations/0014_agent_sessions.sql +0 -19
- package/migrations/0015_message_traces.sql +0 -27
- package/migrations/0016_multi_agent_channels_messages.sql +0 -9
- package/migrations/0017_rename_cron_job_id.sql +0 -2
- package/packages/api/src/protocol-v2.ts +0 -154
- package/packages/api/src/routes/agents-v2.ts +0 -192
- package/packages/api/src/routes/history-v2.ts +0 -221
- package/packages/api/src/routes/migrate-v2.ts +0 -110
- package/packages/web/dist/assets/index-BARPtt0v.css +0 -1
- package/packages/web/dist/assets/index-Bf-XL3te.js +0 -2
- package/packages/web/dist/assets/index-CYlvfpX9.js +0 -1519
- package/packages/web/dist/assets/index-CxcpA4Qo.js +0 -1
- package/packages/web/dist/assets/index-QebPVqwj.js +0 -2
- package/packages/web/src/components/AgentSettings.tsx +0 -328
- package/scripts/mock-openclaw-v2.mjs +0 -486
|
@@ -1 +0,0 @@
|
|
|
1
|
-
import{r as i}from"./index-CYlvfpX9.js";const t=i("PushNotifications",{});export{t as PushNotifications};
|
|
@@ -1,2 +0,0 @@
|
|
|
1
|
-
const __vite__mapDeps=(i,m=__vite__mapDeps,d=(m.f||(m.f=["assets/web-D3LMODYp.js","assets/index-CYlvfpX9.js","assets/index-BARPtt0v.css"])))=>i.map(i=>d[i]);
|
|
2
|
-
import{r as o,f as t}from"./index-CYlvfpX9.js";const n=o("SocialLogin",{web:()=>t(()=>import("./web-D3LMODYp.js"),__vite__mapDeps([0,1,2])).then(e=>new e.SocialLoginWeb)});export{n as SocialLogin};
|
|
@@ -1,328 +0,0 @@
|
|
|
1
|
-
import React, { useState, useEffect, useCallback } from "react";
|
|
2
|
-
import { agentsV2Api, type AgentV2 } from "../api";
|
|
3
|
-
import { useAppState, useAppDispatch } from "../store";
|
|
4
|
-
|
|
5
|
-
const AGENT_TYPES = [
|
|
6
|
-
{ value: "openclaw", label: "OpenClaw", color: "#2BAC76" },
|
|
7
|
-
{ value: "cursor_cli", label: "Cursor CLI", color: "#3B82F6" },
|
|
8
|
-
{ value: "cursor_cloud", label: "Cursor Cloud", color: "#6366F1" },
|
|
9
|
-
{ value: "claude_code", label: "Claude Code", color: "#F59E0B" },
|
|
10
|
-
{ value: "mock", label: "Mock", color: "#9CA3AF" },
|
|
11
|
-
] as const;
|
|
12
|
-
|
|
13
|
-
const ROLES = [
|
|
14
|
-
{ value: "general", label: "General" },
|
|
15
|
-
{ value: "product_manager", label: "Product Manager" },
|
|
16
|
-
{ value: "developer", label: "Developer" },
|
|
17
|
-
{ value: "qa", label: "QA / Tester" },
|
|
18
|
-
{ value: "devops", label: "DevOps" },
|
|
19
|
-
] as const;
|
|
20
|
-
|
|
21
|
-
function AgentTypeIcon({ type, size = 20 }: { type: string; size?: number }) {
|
|
22
|
-
const agentType = AGENT_TYPES.find((t) => t.value === type);
|
|
23
|
-
const color = agentType?.color ?? "#9CA3AF";
|
|
24
|
-
return (
|
|
25
|
-
<div
|
|
26
|
-
className="shrink-0 rounded-full flex items-center justify-center font-bold"
|
|
27
|
-
style={{ width: size, height: size, background: color, color: "#fff", fontSize: size * 0.45 }}
|
|
28
|
-
>
|
|
29
|
-
{(agentType?.label ?? "?")[0]}
|
|
30
|
-
</div>
|
|
31
|
-
);
|
|
32
|
-
}
|
|
33
|
-
|
|
34
|
-
function StatusDot({ connected }: { connected: boolean }) {
|
|
35
|
-
return (
|
|
36
|
-
<span
|
|
37
|
-
className="inline-block rounded-full"
|
|
38
|
-
style={{
|
|
39
|
-
width: 8,
|
|
40
|
-
height: 8,
|
|
41
|
-
background: connected ? "#2BAC76" : "var(--text-tertiary)",
|
|
42
|
-
}}
|
|
43
|
-
/>
|
|
44
|
-
);
|
|
45
|
-
}
|
|
46
|
-
|
|
47
|
-
export function AgentSettings({ onClose }: { onClose: () => void }) {
|
|
48
|
-
const state = useAppState();
|
|
49
|
-
const dispatch = useAppDispatch();
|
|
50
|
-
const [agents, setAgents] = useState<AgentV2[]>([]);
|
|
51
|
-
const [loading, setLoading] = useState(true);
|
|
52
|
-
const [editingAgent, setEditingAgent] = useState<AgentV2 | null>(null);
|
|
53
|
-
const [showCreate, setShowCreate] = useState(false);
|
|
54
|
-
|
|
55
|
-
const loadAgents = useCallback(async () => {
|
|
56
|
-
setLoading(true);
|
|
57
|
-
try {
|
|
58
|
-
const data = await agentsV2Api.list();
|
|
59
|
-
setAgents(data.agents);
|
|
60
|
-
dispatch({ type: "SET_V2_AGENTS", agents: data.agents });
|
|
61
|
-
} catch (err) {
|
|
62
|
-
console.error("Failed to load agents:", err);
|
|
63
|
-
} finally {
|
|
64
|
-
setLoading(false);
|
|
65
|
-
}
|
|
66
|
-
}, [dispatch]);
|
|
67
|
-
|
|
68
|
-
useEffect(() => { loadAgents(); }, [loadAgents]);
|
|
69
|
-
|
|
70
|
-
const handleDelete = async (id: string, name: string) => {
|
|
71
|
-
if (!confirm(`Delete agent "${name}"? This cannot be undone.`)) return;
|
|
72
|
-
try {
|
|
73
|
-
await agentsV2Api.delete(id);
|
|
74
|
-
await loadAgents();
|
|
75
|
-
} catch (err) {
|
|
76
|
-
alert(`Failed to delete: ${err}`);
|
|
77
|
-
}
|
|
78
|
-
};
|
|
79
|
-
|
|
80
|
-
return (
|
|
81
|
-
<div className="fixed inset-0 z-50 flex items-center justify-center" style={{ background: "rgba(0,0,0,0.5)" }}>
|
|
82
|
-
<div
|
|
83
|
-
className="w-full max-w-2xl max-h-[80vh] overflow-y-auto rounded-xl shadow-lg"
|
|
84
|
-
style={{ background: "var(--bg-primary)", border: "1px solid var(--border)" }}
|
|
85
|
-
>
|
|
86
|
-
<div className="flex items-center justify-between px-6 py-4" style={{ borderBottom: "1px solid var(--border)" }}>
|
|
87
|
-
<h2 className="text-body font-semibold" style={{ color: "var(--text-primary)" }}>Agent Management</h2>
|
|
88
|
-
<button onClick={onClose} className="text-caption" style={{ color: "var(--text-secondary)" }}>Close</button>
|
|
89
|
-
</div>
|
|
90
|
-
|
|
91
|
-
<div className="px-6 py-4">
|
|
92
|
-
{loading ? (
|
|
93
|
-
<p className="text-caption" style={{ color: "var(--text-secondary)" }}>Loading agents...</p>
|
|
94
|
-
) : (
|
|
95
|
-
<>
|
|
96
|
-
<div className="space-y-2">
|
|
97
|
-
{agents.map((agent) => (
|
|
98
|
-
<div
|
|
99
|
-
key={agent.id}
|
|
100
|
-
className="flex items-center gap-3 px-4 py-3 rounded-lg"
|
|
101
|
-
style={{ background: "var(--bg-secondary)", border: "1px solid var(--border)" }}
|
|
102
|
-
>
|
|
103
|
-
<AgentTypeIcon type={agent.type} />
|
|
104
|
-
<div className="flex-1 min-w-0">
|
|
105
|
-
<div className="flex items-center gap-2">
|
|
106
|
-
<span className="text-caption font-medium" style={{ color: "var(--text-primary)" }}>
|
|
107
|
-
{agent.name}
|
|
108
|
-
</span>
|
|
109
|
-
<StatusDot connected={agent.status === "connected"} />
|
|
110
|
-
<span
|
|
111
|
-
className="text-tiny px-1.5 py-0.5 rounded"
|
|
112
|
-
style={{ background: "var(--bg-hover)", color: "var(--text-secondary)" }}
|
|
113
|
-
>
|
|
114
|
-
{ROLES.find((r) => r.value === agent.role)?.label ?? agent.role}
|
|
115
|
-
</span>
|
|
116
|
-
</div>
|
|
117
|
-
<div className="text-tiny" style={{ color: "var(--text-tertiary)" }}>
|
|
118
|
-
{AGENT_TYPES.find((t) => t.value === agent.type)?.label ?? agent.type}
|
|
119
|
-
{agent.skills.length > 0 && ` · ${agent.skills.map((s) => s.name).join(", ")}`}
|
|
120
|
-
</div>
|
|
121
|
-
</div>
|
|
122
|
-
<div className="flex gap-1.5">
|
|
123
|
-
<button
|
|
124
|
-
onClick={() => setEditingAgent(agent)}
|
|
125
|
-
className="px-2.5 py-1 text-tiny rounded-sm"
|
|
126
|
-
style={{ background: "var(--bg-hover)", color: "var(--text-secondary)" }}
|
|
127
|
-
>
|
|
128
|
-
Edit
|
|
129
|
-
</button>
|
|
130
|
-
<button
|
|
131
|
-
onClick={() => handleDelete(agent.id, agent.name)}
|
|
132
|
-
className="px-2.5 py-1 text-tiny rounded-sm"
|
|
133
|
-
style={{ background: "var(--bg-hover)", color: "var(--accent-red)" }}
|
|
134
|
-
>
|
|
135
|
-
Delete
|
|
136
|
-
</button>
|
|
137
|
-
</div>
|
|
138
|
-
</div>
|
|
139
|
-
))}
|
|
140
|
-
</div>
|
|
141
|
-
|
|
142
|
-
<button
|
|
143
|
-
onClick={() => setShowCreate(true)}
|
|
144
|
-
className="mt-4 w-full py-2.5 text-caption font-medium rounded-lg transition-colors"
|
|
145
|
-
style={{ background: "var(--accent-blue)", color: "#fff" }}
|
|
146
|
-
>
|
|
147
|
-
+ Add Agent
|
|
148
|
-
</button>
|
|
149
|
-
</>
|
|
150
|
-
)}
|
|
151
|
-
</div>
|
|
152
|
-
|
|
153
|
-
{(showCreate || editingAgent) && (
|
|
154
|
-
<AgentForm
|
|
155
|
-
agent={editingAgent}
|
|
156
|
-
onSave={async () => {
|
|
157
|
-
setShowCreate(false);
|
|
158
|
-
setEditingAgent(null);
|
|
159
|
-
await loadAgents();
|
|
160
|
-
}}
|
|
161
|
-
onCancel={() => { setShowCreate(false); setEditingAgent(null); }}
|
|
162
|
-
/>
|
|
163
|
-
)}
|
|
164
|
-
</div>
|
|
165
|
-
</div>
|
|
166
|
-
);
|
|
167
|
-
}
|
|
168
|
-
|
|
169
|
-
function AgentForm({
|
|
170
|
-
agent,
|
|
171
|
-
onSave,
|
|
172
|
-
onCancel,
|
|
173
|
-
}: {
|
|
174
|
-
agent: AgentV2 | null;
|
|
175
|
-
onSave: () => void;
|
|
176
|
-
onCancel: () => void;
|
|
177
|
-
}) {
|
|
178
|
-
const isEdit = !!agent;
|
|
179
|
-
const [name, setName] = useState(agent?.name ?? "");
|
|
180
|
-
const [type, setType] = useState(agent?.type ?? "openclaw");
|
|
181
|
-
const [role, setRole] = useState(agent?.role ?? "general");
|
|
182
|
-
const [systemPrompt, setSystemPrompt] = useState(agent?.systemPrompt ?? "");
|
|
183
|
-
const [skillsText, setSkillsText] = useState(
|
|
184
|
-
agent?.skills.map((s) => `${s.name}: ${s.description}`).join("\n") ?? "",
|
|
185
|
-
);
|
|
186
|
-
const [pairingToken, setPairingToken] = useState("");
|
|
187
|
-
const [saving, setSaving] = useState(false);
|
|
188
|
-
const [error, setError] = useState("");
|
|
189
|
-
|
|
190
|
-
const handleSubmit = async (e: React.FormEvent) => {
|
|
191
|
-
e.preventDefault();
|
|
192
|
-
setSaving(true);
|
|
193
|
-
setError("");
|
|
194
|
-
|
|
195
|
-
const skills = skillsText
|
|
196
|
-
.split("\n")
|
|
197
|
-
.map((line) => line.trim())
|
|
198
|
-
.filter(Boolean)
|
|
199
|
-
.map((line) => {
|
|
200
|
-
const colonIdx = line.indexOf(":");
|
|
201
|
-
return colonIdx > 0
|
|
202
|
-
? { name: line.slice(0, colonIdx).trim(), description: line.slice(colonIdx + 1).trim() }
|
|
203
|
-
: { name: line, description: "" };
|
|
204
|
-
});
|
|
205
|
-
|
|
206
|
-
try {
|
|
207
|
-
if (isEdit) {
|
|
208
|
-
await agentsV2Api.update(agent!.id, { name, role, systemPrompt, skills });
|
|
209
|
-
} else {
|
|
210
|
-
await agentsV2Api.create({
|
|
211
|
-
name,
|
|
212
|
-
type,
|
|
213
|
-
role,
|
|
214
|
-
systemPrompt,
|
|
215
|
-
skills,
|
|
216
|
-
pairingToken: pairingToken || undefined,
|
|
217
|
-
});
|
|
218
|
-
}
|
|
219
|
-
onSave();
|
|
220
|
-
} catch (err) {
|
|
221
|
-
setError(String(err));
|
|
222
|
-
} finally {
|
|
223
|
-
setSaving(false);
|
|
224
|
-
}
|
|
225
|
-
};
|
|
226
|
-
|
|
227
|
-
return (
|
|
228
|
-
<div className="px-6 py-4" style={{ borderTop: "1px solid var(--border)" }}>
|
|
229
|
-
<h3 className="text-caption font-semibold mb-3" style={{ color: "var(--text-primary)" }}>
|
|
230
|
-
{isEdit ? `Edit ${agent!.name}` : "Add New Agent"}
|
|
231
|
-
</h3>
|
|
232
|
-
<form onSubmit={handleSubmit} className="space-y-3">
|
|
233
|
-
<div className="flex gap-3">
|
|
234
|
-
<label className="flex-1">
|
|
235
|
-
<span className="text-tiny block mb-1" style={{ color: "var(--text-secondary)" }}>Name</span>
|
|
236
|
-
<input
|
|
237
|
-
value={name}
|
|
238
|
-
onChange={(e) => setName(e.target.value)}
|
|
239
|
-
className="w-full px-3 py-2 text-caption rounded-md"
|
|
240
|
-
style={{ background: "var(--bg-secondary)", border: "1px solid var(--border)", color: "var(--text-primary)" }}
|
|
241
|
-
required
|
|
242
|
-
/>
|
|
243
|
-
</label>
|
|
244
|
-
{!isEdit && (
|
|
245
|
-
<label className="w-40">
|
|
246
|
-
<span className="text-tiny block mb-1" style={{ color: "var(--text-secondary)" }}>Type</span>
|
|
247
|
-
<select
|
|
248
|
-
value={type}
|
|
249
|
-
onChange={(e) => setType(e.target.value as AgentV2["type"])}
|
|
250
|
-
className="w-full px-3 py-2 text-caption rounded-md"
|
|
251
|
-
style={{ background: "var(--bg-secondary)", border: "1px solid var(--border)", color: "var(--text-primary)" }}
|
|
252
|
-
>
|
|
253
|
-
{AGENT_TYPES.map((t) => (
|
|
254
|
-
<option key={t.value} value={t.value}>{t.label}</option>
|
|
255
|
-
))}
|
|
256
|
-
</select>
|
|
257
|
-
</label>
|
|
258
|
-
)}
|
|
259
|
-
<label className="w-40">
|
|
260
|
-
<span className="text-tiny block mb-1" style={{ color: "var(--text-secondary)" }}>Role</span>
|
|
261
|
-
<select
|
|
262
|
-
value={role}
|
|
263
|
-
onChange={(e) => setRole(e.target.value)}
|
|
264
|
-
className="w-full px-3 py-2 text-caption rounded-md"
|
|
265
|
-
style={{ background: "var(--bg-secondary)", border: "1px solid var(--border)", color: "var(--text-primary)" }}
|
|
266
|
-
>
|
|
267
|
-
{ROLES.map((r) => (
|
|
268
|
-
<option key={r.value} value={r.value}>{r.label}</option>
|
|
269
|
-
))}
|
|
270
|
-
</select>
|
|
271
|
-
</label>
|
|
272
|
-
</div>
|
|
273
|
-
|
|
274
|
-
<label>
|
|
275
|
-
<span className="text-tiny block mb-1" style={{ color: "var(--text-secondary)" }}>System Prompt</span>
|
|
276
|
-
<textarea
|
|
277
|
-
value={systemPrompt}
|
|
278
|
-
onChange={(e) => setSystemPrompt(e.target.value)}
|
|
279
|
-
rows={3}
|
|
280
|
-
className="w-full px-3 py-2 text-caption rounded-md resize-y"
|
|
281
|
-
style={{ background: "var(--bg-secondary)", border: "1px solid var(--border)", color: "var(--text-primary)" }}
|
|
282
|
-
placeholder="You are a product manager who excels at..."
|
|
283
|
-
/>
|
|
284
|
-
</label>
|
|
285
|
-
|
|
286
|
-
<label>
|
|
287
|
-
<span className="text-tiny block mb-1" style={{ color: "var(--text-secondary)" }}>Skills (one per line, format: name: description)</span>
|
|
288
|
-
<textarea
|
|
289
|
-
value={skillsText}
|
|
290
|
-
onChange={(e) => setSkillsText(e.target.value)}
|
|
291
|
-
rows={3}
|
|
292
|
-
className="w-full px-3 py-2 text-caption rounded-md resize-y font-mono"
|
|
293
|
-
style={{ background: "var(--bg-secondary)", border: "1px solid var(--border)", color: "var(--text-primary)" }}
|
|
294
|
-
placeholder={"Code Review: Review code for quality and security\nRefactoring: Improve code structure"}
|
|
295
|
-
/>
|
|
296
|
-
</label>
|
|
297
|
-
|
|
298
|
-
{!isEdit && type === "openclaw" && (
|
|
299
|
-
<label>
|
|
300
|
-
<span className="text-tiny block mb-1" style={{ color: "var(--text-secondary)" }}>Pairing Token (optional)</span>
|
|
301
|
-
<input
|
|
302
|
-
value={pairingToken}
|
|
303
|
-
onChange={(e) => setPairingToken(e.target.value)}
|
|
304
|
-
className="w-full px-3 py-2 text-caption rounded-md font-mono"
|
|
305
|
-
style={{ background: "var(--bg-secondary)", border: "1px solid var(--border)", color: "var(--text-primary)" }}
|
|
306
|
-
placeholder="bc_pat_..."
|
|
307
|
-
/>
|
|
308
|
-
</label>
|
|
309
|
-
)}
|
|
310
|
-
|
|
311
|
-
{error && (
|
|
312
|
-
<p className="text-tiny" style={{ color: "var(--accent-red)" }}>{error}</p>
|
|
313
|
-
)}
|
|
314
|
-
|
|
315
|
-
<div className="flex justify-end gap-2 pt-1">
|
|
316
|
-
<button type="button" onClick={onCancel} className="px-4 py-2 text-caption rounded-md"
|
|
317
|
-
style={{ background: "var(--bg-hover)", color: "var(--text-secondary)" }}>
|
|
318
|
-
Cancel
|
|
319
|
-
</button>
|
|
320
|
-
<button type="submit" disabled={saving} className="px-4 py-2 text-caption font-medium rounded-md"
|
|
321
|
-
style={{ background: "var(--accent-blue)", color: "#fff", opacity: saving ? 0.6 : 1 }}>
|
|
322
|
-
{saving ? "Saving..." : isEdit ? "Update" : "Create"}
|
|
323
|
-
</button>
|
|
324
|
-
</div>
|
|
325
|
-
</form>
|
|
326
|
-
</div>
|
|
327
|
-
);
|
|
328
|
-
}
|