@chrysb/alphaclaw 0.6.0-beta.1 → 0.6.0-beta.3

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.
Files changed (28) hide show
  1. package/lib/public/js/components/agents-tab/agent-bindings-section/channel-item-trailing.js +203 -0
  2. package/lib/public/js/components/agents-tab/agent-bindings-section/helpers.js +10 -12
  3. package/lib/public/js/components/agents-tab/agent-bindings-section/index.js +19 -287
  4. package/lib/public/js/components/agents-tab/agent-bindings-section/use-agent-bindings.js +1 -1
  5. package/lib/public/js/components/agents-tab/agent-bindings-section/use-channel-items.js +211 -0
  6. package/lib/public/js/components/agents-tab/agent-pairing-section.js +17 -4
  7. package/lib/public/js/components/agents-tab/create-channel-modal.js +29 -6
  8. package/lib/public/js/components/channels.js +19 -14
  9. package/lib/public/js/components/models-tab/provider-auth-card.js +18 -1
  10. package/lib/public/js/components/models-tab/use-models.js +15 -8
  11. package/lib/public/js/lib/channel-accounts.js +20 -0
  12. package/lib/public/js/lib/model-config.js +8 -4
  13. package/lib/server/agents/agents.js +207 -0
  14. package/lib/server/agents/bindings.js +74 -0
  15. package/lib/server/agents/channels.js +674 -0
  16. package/lib/server/agents/service.js +28 -1458
  17. package/lib/server/agents/shared.js +631 -0
  18. package/lib/server/constants.js +6 -0
  19. package/lib/server/db/usage/pricing.js +1 -0
  20. package/lib/server/openclaw-config.js +13 -0
  21. package/lib/server/routes/models.js +12 -1
  22. package/lib/server/routes/pairings.js +29 -3
  23. package/lib/server/routes/system.js +1 -6
  24. package/lib/server/routes/telegram.js +34 -16
  25. package/lib/server/telegram-workspace.js +22 -7
  26. package/lib/server/topic-registry.js +1 -4
  27. package/lib/server/utils/channels.js +13 -0
  28. package/package.json +1 -1
@@ -0,0 +1,207 @@
1
+ const path = require("path");
2
+
3
+ const {
4
+ kDefaultAgentId,
5
+ resolveAgentWorkspacePath,
6
+ loadConfig,
7
+ saveConfig,
8
+ cloneJson,
9
+ getSafeStat,
10
+ calculatePathSizeBytes,
11
+ withNormalizedAgentsConfig,
12
+ isValidAgentId,
13
+ resolveRequestedWorkspacePath,
14
+ ensureAgentScaffold,
15
+ } = require("./shared");
16
+
17
+ const createAgentsDomain = ({ fsImpl, OPENCLAW_DIR }) => {
18
+ const listAgents = () => {
19
+ const cfg = withNormalizedAgentsConfig({
20
+ OPENCLAW_DIR,
21
+ cfg: loadConfig({ fsImpl, OPENCLAW_DIR }),
22
+ });
23
+ return (cfg.agents?.list || []).map((entry) => ({
24
+ ...entry,
25
+ id: String(entry.id || "").trim(),
26
+ name: String(entry.name || "").trim() || String(entry.id || "").trim(),
27
+ default: !!entry.default,
28
+ }));
29
+ };
30
+
31
+ const getAgent = (agentId) => {
32
+ const normalized = String(agentId || "").trim();
33
+ return listAgents().find((entry) => entry.id === normalized) || null;
34
+ };
35
+
36
+ const getAgentWorkspaceSize = (agentId) => {
37
+ const normalized = String(agentId || "").trim();
38
+ const agent = getAgent(normalized);
39
+ if (!agent) throw new Error(`Agent "${normalized}" not found`);
40
+ const workspacePath = String(
41
+ agent.workspace ||
42
+ resolveAgentWorkspacePath({ OPENCLAW_DIR, agentId: normalized }),
43
+ ).trim();
44
+ if (!workspacePath) {
45
+ return { workspacePath: "", exists: false, sizeBytes: 0 };
46
+ }
47
+ const stat = getSafeStat({ fsImpl, targetPath: workspacePath });
48
+ if (!stat) {
49
+ return { workspacePath, exists: false, sizeBytes: 0 };
50
+ }
51
+ return {
52
+ workspacePath,
53
+ exists: true,
54
+ sizeBytes: calculatePathSizeBytes({ fsImpl, targetPath: workspacePath }),
55
+ };
56
+ };
57
+
58
+ const createAgent = (input = {}) => {
59
+ const agentId = String(input.id || "").trim();
60
+ if (!isValidAgentId(agentId)) {
61
+ throw new Error(
62
+ "Agent id must be lowercase letters, numbers, and hyphens only",
63
+ );
64
+ }
65
+
66
+ const cfg = withNormalizedAgentsConfig({
67
+ OPENCLAW_DIR,
68
+ cfg: loadConfig({ fsImpl, OPENCLAW_DIR }),
69
+ });
70
+ const existing = cfg.agents.list.find((entry) => entry.id === agentId);
71
+ if (existing) {
72
+ throw new Error(`Agent "${agentId}" already exists`);
73
+ }
74
+
75
+ const workspacePath = resolveRequestedWorkspacePath({
76
+ OPENCLAW_DIR,
77
+ agentId,
78
+ workspaceFolder: input.workspaceFolder,
79
+ });
80
+ const { workspacePath: scaffoldWorkspacePath, agentDirPath } =
81
+ ensureAgentScaffold({
82
+ fsImpl,
83
+ workspacePath,
84
+ OPENCLAW_DIR,
85
+ agentId,
86
+ });
87
+ const nextAgent = {
88
+ id: agentId,
89
+ name: String(input.name || "").trim() || agentId,
90
+ default: false,
91
+ workspace: scaffoldWorkspacePath,
92
+ agentDir: agentDirPath,
93
+ ...(input.model ? { model: input.model } : {}),
94
+ ...(input.identity && typeof input.identity === "object"
95
+ ? { identity: { ...input.identity } }
96
+ : {}),
97
+ };
98
+ cfg.agents.list = [...cfg.agents.list, nextAgent];
99
+ saveConfig({ fsImpl, OPENCLAW_DIR, config: cfg });
100
+ return nextAgent;
101
+ };
102
+
103
+ const updateAgent = (agentId, patch = {}) => {
104
+ const normalized = String(agentId || "").trim();
105
+ const cfg = withNormalizedAgentsConfig({
106
+ OPENCLAW_DIR,
107
+ cfg: loadConfig({ fsImpl, OPENCLAW_DIR }),
108
+ });
109
+ const index = cfg.agents.list.findIndex((entry) => entry.id === normalized);
110
+ if (index < 0) throw new Error(`Agent "${normalized}" not found`);
111
+ const current = cfg.agents.list[index];
112
+ const next = {
113
+ ...current,
114
+ ...(patch.name !== undefined
115
+ ? { name: String(patch.name || "").trim() }
116
+ : {}),
117
+ ...(patch.identity !== undefined
118
+ ? {
119
+ identity:
120
+ patch.identity && typeof patch.identity === "object"
121
+ ? { ...patch.identity }
122
+ : {},
123
+ }
124
+ : {}),
125
+ };
126
+ if (patch.model !== undefined) {
127
+ if (patch.model === null) {
128
+ delete next.model;
129
+ } else {
130
+ next.model = patch.model;
131
+ }
132
+ }
133
+ if (!String(next.name || "").trim()) next.name = normalized;
134
+ cfg.agents.list[index] = next;
135
+ saveConfig({ fsImpl, OPENCLAW_DIR, config: cfg });
136
+ return next;
137
+ };
138
+
139
+ const setDefaultAgent = (agentId) => {
140
+ const normalized = String(agentId || "").trim();
141
+ const cfg = withNormalizedAgentsConfig({
142
+ OPENCLAW_DIR,
143
+ cfg: loadConfig({ fsImpl, OPENCLAW_DIR }),
144
+ });
145
+ const exists = cfg.agents.list.some((entry) => entry.id === normalized);
146
+ if (!exists) throw new Error(`Agent "${normalized}" not found`);
147
+ cfg.agents.list = cfg.agents.list.map((entry) => ({
148
+ ...entry,
149
+ default: entry.id === normalized,
150
+ }));
151
+ saveConfig({ fsImpl, OPENCLAW_DIR, config: cfg });
152
+ return cfg.agents.list.find((entry) => entry.id === normalized) || null;
153
+ };
154
+
155
+ const deleteAgent = (agentId, { keepWorkspace = true } = {}) => {
156
+ const normalized = String(agentId || "").trim();
157
+ if (!normalized || normalized === kDefaultAgentId) {
158
+ throw new Error("The default main agent cannot be deleted");
159
+ }
160
+ const cfg = withNormalizedAgentsConfig({
161
+ OPENCLAW_DIR,
162
+ cfg: loadConfig({ fsImpl, OPENCLAW_DIR }),
163
+ });
164
+ const target = cfg.agents.list.find((entry) => entry.id === normalized);
165
+ if (!target) throw new Error(`Agent "${normalized}" not found`);
166
+ if (target.default) {
167
+ throw new Error("Default agent cannot be deleted");
168
+ }
169
+ cfg.agents.list = cfg.agents.list.filter(
170
+ (entry) => entry.id !== normalized,
171
+ );
172
+ if (Array.isArray(cfg.bindings)) {
173
+ cfg.bindings = cfg.bindings.filter(
174
+ (binding) => String(binding?.agentId || "") !== normalized,
175
+ );
176
+ }
177
+ saveConfig({ fsImpl, OPENCLAW_DIR, config: cfg });
178
+
179
+ if (!keepWorkspace) {
180
+ const workspacePath = String(
181
+ target.workspace ||
182
+ resolveAgentWorkspacePath({
183
+ OPENCLAW_DIR,
184
+ agentId: normalized,
185
+ }),
186
+ ).trim();
187
+ const agentDirPath = path.join(OPENCLAW_DIR, "agents", normalized);
188
+ if (workspacePath) {
189
+ fsImpl.rmSync(workspacePath, { recursive: true, force: true });
190
+ }
191
+ fsImpl.rmSync(agentDirPath, { recursive: true, force: true });
192
+ }
193
+ return { ok: true };
194
+ };
195
+
196
+ return {
197
+ listAgents,
198
+ getAgent,
199
+ getAgentWorkspaceSize,
200
+ createAgent,
201
+ updateAgent,
202
+ setDefaultAgent,
203
+ deleteAgent,
204
+ };
205
+ };
206
+
207
+ module.exports = { createAgentsDomain };
@@ -0,0 +1,74 @@
1
+ const {
2
+ loadConfig,
3
+ saveConfig,
4
+ cloneJson,
5
+ normalizeBindingMatch,
6
+ matchesBinding,
7
+ appendBindingToConfig,
8
+ withNormalizedAgentsConfig,
9
+ } = require("./shared");
10
+
11
+ const createBindingsDomain = ({ fsImpl, OPENCLAW_DIR }) => {
12
+ const getBindingsForAgent = (agentId) => {
13
+ const normalized = String(agentId || "").trim();
14
+ const cfg = withNormalizedAgentsConfig({
15
+ OPENCLAW_DIR,
16
+ cfg: loadConfig({ fsImpl, OPENCLAW_DIR }),
17
+ });
18
+ const bindings = Array.isArray(cfg.bindings) ? cfg.bindings : [];
19
+ return bindings
20
+ .filter((binding) => String(binding?.agentId || "").trim() === normalized)
21
+ .map((binding) => cloneJson(binding));
22
+ };
23
+
24
+ const addBinding = (agentId, input = {}) => {
25
+ const normalizedAgentId = String(agentId || "").trim();
26
+ const cfg = withNormalizedAgentsConfig({
27
+ OPENCLAW_DIR,
28
+ cfg: loadConfig({ fsImpl, OPENCLAW_DIR }),
29
+ });
30
+ const agent = cfg.agents.list.find(
31
+ (entry) => entry.id === normalizedAgentId,
32
+ );
33
+ if (!agent) throw new Error(`Agent "${normalizedAgentId}" not found`);
34
+ const match = normalizeBindingMatch(input);
35
+ const nextBinding = appendBindingToConfig({
36
+ cfg,
37
+ agentId: normalizedAgentId,
38
+ match,
39
+ });
40
+ saveConfig({ fsImpl, OPENCLAW_DIR, config: cfg });
41
+ return nextBinding;
42
+ };
43
+
44
+ const removeBinding = (agentId, input = {}) => {
45
+ const normalizedAgentId = String(agentId || "").trim();
46
+ const cfg = withNormalizedAgentsConfig({
47
+ OPENCLAW_DIR,
48
+ cfg: loadConfig({ fsImpl, OPENCLAW_DIR }),
49
+ });
50
+ const bindings = Array.isArray(cfg.bindings) ? cfg.bindings : [];
51
+ const nextMatch = normalizeBindingMatch(input);
52
+ const nextBindings = bindings.filter(
53
+ (binding) =>
54
+ !(
55
+ String(binding?.agentId || "").trim() === normalizedAgentId &&
56
+ matchesBinding(binding?.match || {}, nextMatch)
57
+ ),
58
+ );
59
+ if (nextBindings.length === bindings.length) {
60
+ throw new Error("Binding not found");
61
+ }
62
+ cfg.bindings = nextBindings;
63
+ saveConfig({ fsImpl, OPENCLAW_DIR, config: cfg });
64
+ return { ok: true };
65
+ };
66
+
67
+ return {
68
+ getBindingsForAgent,
69
+ addBinding,
70
+ removeBinding,
71
+ };
72
+ };
73
+
74
+ module.exports = { createBindingsDomain };