openbot 0.4.7 → 0.5.5
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/.claude/agents/runtime-security-reviewer.md +32 -0
- package/.claude/hooks/format.sh +18 -0
- package/.claude/hooks/protect-secrets.sh +23 -0
- package/.claude/settings.json +26 -0
- package/.claude/skills/deploy/SKILL.md +26 -0
- package/.claude/skills/new-plugin/SKILL.md +46 -0
- package/.dockerignore +9 -0
- package/.mcp.json +8 -0
- package/AGENTS.md +2 -2
- package/CLAUDE.md +51 -0
- package/Dockerfile +41 -0
- package/deploy/README.md +59 -0
- package/deploy/entrypoint.sh +6 -0
- package/deploy/fly.toml +36 -0
- package/dist/app/bootstrap.js +29 -0
- package/dist/app/cli.js +5 -1
- package/dist/app/cloud-mode.js +15 -0
- package/dist/app/config.js +61 -16
- package/dist/app/ensure-default-stack.js +54 -0
- package/dist/app/openbot-plugin.js +4 -0
- package/dist/app/server.js +37 -6
- package/dist/harness/index.js +3 -0
- package/dist/plugins/approval/index.js +1 -1
- package/dist/plugins/bash/index.js +386 -164
- package/dist/plugins/memory/service.js +2 -5
- package/dist/plugins/openbot/context.js +17 -1
- package/dist/plugins/openbot/index.js +23 -7
- package/dist/plugins/openbot/model.js +20 -0
- package/dist/plugins/openbot/runtime.js +45 -57
- package/dist/plugins/openbot/system-prompt.js +43 -8
- package/dist/plugins/preview/index.js +267 -0
- package/dist/plugins/storage/index.js +3 -325
- package/dist/plugins/storage/service.js +61 -18
- package/dist/plugins/todo/index.js +131 -38
- package/dist/plugins/todo/service.js +93 -0
- package/dist/plugins/ui/index.js +8 -1
- package/dist/services/plugins/host.js +21 -0
- package/dist/services/plugins/model-registry.js +126 -0
- package/dist/services/plugins/registry.js +28 -42
- package/dist/services/plugins/service.js +2 -6
- package/docs/agents.md +20 -2
- package/docs/architecture.md +1 -1
- package/docs/plugins.md +13 -3
- package/docs/templates/AGENT.example.md +8 -14
- package/package.json +5 -2
- package/pnpm-workspace.yaml +2 -0
- package/src/app/bootstrap.ts +43 -0
- package/src/app/cli.ts +5 -1
- package/src/app/cloud-mode.ts +26 -0
- package/src/app/config.ts +71 -19
- package/src/app/ensure-default-stack.ts +63 -0
- package/src/app/openbot-plugin.ts +5 -0
- package/src/app/server.ts +42 -6
- package/src/app/types.ts +158 -32
- package/src/harness/index.ts +4 -0
- package/src/plugins/memory/service.ts +2 -5
- package/src/plugins/storage/index.ts +3 -371
- package/src/plugins/storage/service.ts +81 -22
- package/src/services/plugins/domain.ts +2 -0
- package/src/services/plugins/host.ts +36 -0
- package/src/services/plugins/model-registry.ts +178 -0
- package/src/services/plugins/registry.ts +30 -43
- package/src/services/plugins/service.ts +8 -17
- package/src/services/plugins/types.ts +36 -2
- package/src/services/todo/types.ts +12 -0
- package/dist/agents/openbot/index.js +0 -76
- package/dist/agents/openbot/middleware/approval.js +0 -132
- package/dist/agents/openbot/runtime.js +0 -289
- package/dist/agents/openbot/system-prompt.js +0 -32
- package/dist/agents/openbot/tools/delegation.js +0 -78
- package/dist/agents/openbot/tools/mcp.js +0 -99
- package/dist/agents/openbot/tools/shell.js +0 -91
- package/dist/agents/openbot/tools/storage.js +0 -75
- package/dist/agents/openbot/tools/ui.js +0 -176
- package/dist/agents/system.js +0 -33
- package/dist/bus/agent-package.js +0 -1
- package/dist/bus/plugin.js +0 -1
- package/dist/bus/services.js +0 -754
- package/dist/harness/agent-harness.js +0 -45
- package/dist/harness/agent-invoke-run.js +0 -44
- package/dist/harness/agent-turn.js +0 -99
- package/dist/harness/channel-participants.js +0 -40
- package/dist/harness/constants.js +0 -2
- package/dist/harness/context-meter.js +0 -97
- package/dist/harness/context.js +0 -363
- package/dist/harness/dispatch.js +0 -144
- package/dist/harness/dispatcher.js +0 -156
- package/dist/harness/event-normalizer.js +0 -59
- package/dist/harness/history.js +0 -177
- package/dist/harness/mcp.js +0 -61
- package/dist/harness/orchestration.js +0 -88
- package/dist/harness/orchestrator.js +0 -149
- package/dist/harness/participants.js +0 -22
- package/dist/harness/process.js +0 -29
- package/dist/harness/queue-processor.js +0 -187
- package/dist/harness/run-harness.js +0 -154
- package/dist/harness/run.js +0 -98
- package/dist/harness/runtime-factory.js +0 -73
- package/dist/harness/runtime.js +0 -57
- package/dist/harness/todo-advance.js +0 -93
- package/dist/harness/todo-dispatch.js +0 -51
- package/dist/harness/todos.js +0 -5
- package/dist/harness/turn.js +0 -79
- package/dist/harness/types.js +0 -1
- package/dist/plugins/ai-sdk/index.js +0 -34
- package/dist/plugins/ai-sdk/runtime.js +0 -395
- package/dist/plugins/ai-sdk/system-prompt.js +0 -18
- package/dist/plugins/ai-sdk.js +0 -331
- package/dist/plugins/approval.js +0 -163
- package/dist/plugins/delegation.js +0 -108
- package/dist/plugins/mcp/index.js +0 -108
- package/dist/plugins/mcp.js +0 -140
- package/dist/plugins/shell/index.js +0 -100
- package/dist/plugins/shell.js +0 -123
- package/dist/plugins/storage-tools/index.js +0 -76
- package/dist/plugins/storage.js +0 -737
- package/dist/plugins/thread-namer/index.js +0 -72
- package/dist/plugins/threads/index.js +0 -114
- package/dist/plugins/ui.js +0 -211
- package/dist/plugins/workflow/index.js +0 -65
- package/dist/registry/agents.js +0 -138
- package/dist/registry/plugins.js +0 -110
- package/dist/services/agent-packages.js +0 -103
- package/dist/services/memory.js +0 -152
- package/dist/services/plugins.js +0 -98
- package/dist/services/storage.js +0 -1028
- package/dist/workflow/service.js +0 -106
- package/dist/workflow/types.js +0 -3
- package/src/plugins/approval/index.ts +0 -147
- package/src/plugins/bash/index.ts +0 -232
- package/src/plugins/delegation/index.ts +0 -153
- package/src/plugins/memory/index.ts +0 -182
- package/src/plugins/openbot/context.ts +0 -121
- package/src/plugins/openbot/history.ts +0 -158
- package/src/plugins/openbot/index.ts +0 -80
- package/src/plugins/openbot/runtime.ts +0 -526
- package/src/plugins/openbot/system-prompt.ts +0 -22
- package/src/plugins/ui/index.ts +0 -123
- /package/dist/{bus → services/todo}/types.js +0 -0
|
@@ -1,90 +1,12 @@
|
|
|
1
|
-
import z from 'zod';
|
|
2
1
|
import { buildWorkspaceFileUrl } from './files.js';
|
|
3
2
|
/**
|
|
4
|
-
* `storage` —
|
|
5
|
-
*
|
|
3
|
+
* `storage` — platform infra handlers for `/api/state` and deterministic reads.
|
|
4
|
+
* Agent-facing storage tools live in `@meetopenbot/openbot`.
|
|
6
5
|
*/
|
|
7
|
-
const storageToolDefinitions = {
|
|
8
|
-
create_channel: {
|
|
9
|
-
description: 'Create a new channel. Use when the user intent is clearly different from the current channel and should be split. Always confirm before creating. Skip for simple Q&A.',
|
|
10
|
-
inputSchema: z.object({
|
|
11
|
-
channelId: z
|
|
12
|
-
.string()
|
|
13
|
-
.describe('Unique channel ID (e.g. product-launch, backend-platform, channel_roadmap).'),
|
|
14
|
-
spec: z
|
|
15
|
-
.string()
|
|
16
|
-
.optional()
|
|
17
|
-
.describe('Optional initial markdown content for the channel spec.'),
|
|
18
|
-
initialState: z
|
|
19
|
-
.record(z.string(), z.unknown())
|
|
20
|
-
.optional()
|
|
21
|
-
.describe('Optional initial state object for the channel.'),
|
|
22
|
-
cwd: z
|
|
23
|
-
.string()
|
|
24
|
-
.optional()
|
|
25
|
-
.describe('Optional initial current working directory for the channel. Defaults to an absolute path under ~/openbot/{channelId}.'),
|
|
26
|
-
}),
|
|
27
|
-
},
|
|
28
|
-
patch_channel_details: {
|
|
29
|
-
description: 'Patch current channel details (state, spec, cwd).',
|
|
30
|
-
inputSchema: z
|
|
31
|
-
.object({
|
|
32
|
-
state: z
|
|
33
|
-
.record(z.string(), z.unknown())
|
|
34
|
-
.optional()
|
|
35
|
-
.describe('JSON state object for the channel. Use for structured metadata.'),
|
|
36
|
-
spec: z
|
|
37
|
-
.string()
|
|
38
|
-
.optional()
|
|
39
|
-
.describe('Markdown content for the channel specification (SPEC.md). Use for goals and rules.'),
|
|
40
|
-
cwd: z.string().optional().describe('Current working directory for the channel.'),
|
|
41
|
-
})
|
|
42
|
-
.refine((value) => value.state !== undefined ||
|
|
43
|
-
value.spec !== undefined ||
|
|
44
|
-
value.cwd !== undefined, { message: 'Provide at least one of state, spec, or cwd.' }),
|
|
45
|
-
},
|
|
46
|
-
patch_thread_details: {
|
|
47
|
-
description: 'Patch current thread details (state).',
|
|
48
|
-
inputSchema: z.object({
|
|
49
|
-
state: z
|
|
50
|
-
.record(z.string(), z.unknown())
|
|
51
|
-
.describe('JSON state object for the thread. Use for structured progress or metadata.'),
|
|
52
|
-
}),
|
|
53
|
-
},
|
|
54
|
-
create_variable: {
|
|
55
|
-
description: 'Create or update a variable in the workspace storage.',
|
|
56
|
-
inputSchema: z.object({
|
|
57
|
-
key: z.string().describe('The key of the variable.'),
|
|
58
|
-
value: z.string().describe('The value of the variable.'),
|
|
59
|
-
secret: z.boolean().optional().describe('Whether the variable is a secret.'),
|
|
60
|
-
}),
|
|
61
|
-
},
|
|
62
|
-
delete_variable: {
|
|
63
|
-
description: 'Delete a variable from the workspace storage.',
|
|
64
|
-
inputSchema: z.object({
|
|
65
|
-
key: z.string().describe('The key of the variable to delete.'),
|
|
66
|
-
}),
|
|
67
|
-
},
|
|
68
|
-
delete_channel: {
|
|
69
|
-
description: 'Permanently delete a channel and all its threads and events. Always confirm with the user before deleting.',
|
|
70
|
-
inputSchema: z.object({
|
|
71
|
-
channelId: z.string().describe('The channel ID to delete.'),
|
|
72
|
-
}),
|
|
73
|
-
},
|
|
74
|
-
get_workspace_file_url: {
|
|
75
|
-
description: 'Get a fetchable HTTP URL for a file in the current channel workspace (images, video, audio, documents).',
|
|
76
|
-
inputSchema: z.object({
|
|
77
|
-
path: z
|
|
78
|
-
.string()
|
|
79
|
-
.describe('Path relative to the channel working directory, e.g. "uploads/clip.mp4".'),
|
|
80
|
-
}),
|
|
81
|
-
},
|
|
82
|
-
};
|
|
83
6
|
export const storagePlugin = {
|
|
84
7
|
id: 'storage',
|
|
85
8
|
name: 'Storage',
|
|
86
|
-
description: '
|
|
87
|
-
toolDefinitions: storageToolDefinitions,
|
|
9
|
+
description: 'Infrastructure storage handlers for channels, threads, agents, and files.',
|
|
88
10
|
factory: ({ storage, publicBaseUrl }) => (builder) => {
|
|
89
11
|
const resolvePublicBaseUrl = () => publicBaseUrl;
|
|
90
12
|
builder.on('action:create_thread', async function* (event, context) {
|
|
@@ -119,215 +41,6 @@ export const storagePlugin = {
|
|
|
119
41
|
meta: { ...(event.meta || {}), threadId, agentId: context.state.agentId },
|
|
120
42
|
};
|
|
121
43
|
});
|
|
122
|
-
builder.on('action:create_channel', async function* (event, context) {
|
|
123
|
-
const { channelId, spec, initialState, cwd } = event.data;
|
|
124
|
-
const rawChannelId = (channelId || '').trim();
|
|
125
|
-
const channelSpec = typeof spec === 'string' ? spec : '';
|
|
126
|
-
const resultMeta = { ...(event.meta || {}), agentId: context.state.agentId };
|
|
127
|
-
if (!rawChannelId) {
|
|
128
|
-
yield {
|
|
129
|
-
type: 'action:create_channel:result',
|
|
130
|
-
data: { success: false, channelId: '', channelUrl: '' },
|
|
131
|
-
meta: resultMeta,
|
|
132
|
-
};
|
|
133
|
-
return;
|
|
134
|
-
}
|
|
135
|
-
const channelUrl = `/channels/${rawChannelId}`;
|
|
136
|
-
const mergedInitial = { ...(initialState || {}) };
|
|
137
|
-
try {
|
|
138
|
-
await storage.createChannel({
|
|
139
|
-
channelId: rawChannelId,
|
|
140
|
-
spec: channelSpec,
|
|
141
|
-
initialState: mergedInitial,
|
|
142
|
-
cwd,
|
|
143
|
-
});
|
|
144
|
-
yield {
|
|
145
|
-
type: 'action:create_channel:result',
|
|
146
|
-
data: { success: true, channelId: rawChannelId, channelUrl },
|
|
147
|
-
meta: resultMeta,
|
|
148
|
-
};
|
|
149
|
-
yield {
|
|
150
|
-
type: 'agent:output',
|
|
151
|
-
data: { content: `Created channel \`${rawChannelId}\`.` },
|
|
152
|
-
meta: resultMeta,
|
|
153
|
-
};
|
|
154
|
-
}
|
|
155
|
-
catch {
|
|
156
|
-
yield {
|
|
157
|
-
type: 'action:create_channel:result',
|
|
158
|
-
data: { success: false, channelId: rawChannelId, channelUrl },
|
|
159
|
-
meta: resultMeta,
|
|
160
|
-
};
|
|
161
|
-
}
|
|
162
|
-
});
|
|
163
|
-
builder.on('action:delete_channel', async function* (event, context) {
|
|
164
|
-
const rawChannelId = (event.data?.channelId || '').trim();
|
|
165
|
-
const resultMeta = { ...(event.meta || {}), agentId: context.state.agentId };
|
|
166
|
-
if (!rawChannelId) {
|
|
167
|
-
yield {
|
|
168
|
-
type: 'action:delete_channel:result',
|
|
169
|
-
data: { success: false, channelId: '', error: 'channelId is required' },
|
|
170
|
-
meta: resultMeta,
|
|
171
|
-
};
|
|
172
|
-
return;
|
|
173
|
-
}
|
|
174
|
-
try {
|
|
175
|
-
await storage.deleteChannel({ channelId: rawChannelId });
|
|
176
|
-
yield {
|
|
177
|
-
type: 'action:delete_channel:result',
|
|
178
|
-
data: { success: true, channelId: rawChannelId },
|
|
179
|
-
meta: resultMeta,
|
|
180
|
-
};
|
|
181
|
-
yield {
|
|
182
|
-
type: 'agent:output',
|
|
183
|
-
data: { content: `Deleted channel \`${rawChannelId}\`.` },
|
|
184
|
-
meta: resultMeta,
|
|
185
|
-
};
|
|
186
|
-
}
|
|
187
|
-
catch (error) {
|
|
188
|
-
yield {
|
|
189
|
-
type: 'action:delete_channel:result',
|
|
190
|
-
data: {
|
|
191
|
-
success: false,
|
|
192
|
-
channelId: rawChannelId,
|
|
193
|
-
error: error instanceof Error ? error.message : 'Unknown error',
|
|
194
|
-
},
|
|
195
|
-
meta: resultMeta,
|
|
196
|
-
};
|
|
197
|
-
}
|
|
198
|
-
});
|
|
199
|
-
builder.on('action:update_channel', async function* (event, context) {
|
|
200
|
-
const data = (event.data || {});
|
|
201
|
-
const targetChannelId = (data.channelId || context.state.channelId || '').trim();
|
|
202
|
-
const resultMeta = { ...(event.meta || {}), agentId: context.state.agentId };
|
|
203
|
-
if (!targetChannelId) {
|
|
204
|
-
yield {
|
|
205
|
-
type: 'action:update_channel:result',
|
|
206
|
-
data: { success: false, channelId: '', updatedFields: [] },
|
|
207
|
-
meta: resultMeta,
|
|
208
|
-
};
|
|
209
|
-
return;
|
|
210
|
-
}
|
|
211
|
-
const patch = {};
|
|
212
|
-
const updatedFields = [];
|
|
213
|
-
if (typeof data.name === 'string' && data.name.trim()) {
|
|
214
|
-
patch.name = data.name.trim();
|
|
215
|
-
updatedFields.push('name');
|
|
216
|
-
}
|
|
217
|
-
if (typeof data.cwd === 'string' && data.cwd.trim()) {
|
|
218
|
-
patch.cwd = data.cwd.trim();
|
|
219
|
-
updatedFields.push('cwd');
|
|
220
|
-
}
|
|
221
|
-
try {
|
|
222
|
-
if (updatedFields.length > 0) {
|
|
223
|
-
await storage.patchChannelState({ channelId: targetChannelId, state: patch });
|
|
224
|
-
}
|
|
225
|
-
if (targetChannelId === context.state.channelId) {
|
|
226
|
-
context.state.channelDetails = await storage.getChannelDetails({
|
|
227
|
-
channelId: context.state.channelId,
|
|
228
|
-
});
|
|
229
|
-
}
|
|
230
|
-
yield {
|
|
231
|
-
type: 'action:update_channel:result',
|
|
232
|
-
data: { success: true, channelId: targetChannelId, updatedFields },
|
|
233
|
-
meta: resultMeta,
|
|
234
|
-
};
|
|
235
|
-
}
|
|
236
|
-
catch {
|
|
237
|
-
yield {
|
|
238
|
-
type: 'action:update_channel:result',
|
|
239
|
-
data: { success: false, channelId: targetChannelId, updatedFields },
|
|
240
|
-
meta: resultMeta,
|
|
241
|
-
};
|
|
242
|
-
}
|
|
243
|
-
});
|
|
244
|
-
builder.on('action:patch_channel_details', async function* (event, context) {
|
|
245
|
-
const updatedFields = [];
|
|
246
|
-
const resultMeta = { ...(event.meta || {}), agentId: context.state.agentId };
|
|
247
|
-
const data = (event.data || {});
|
|
248
|
-
try {
|
|
249
|
-
if (data.state !== undefined) {
|
|
250
|
-
await storage.patchChannelState({
|
|
251
|
-
channelId: context.state.channelId,
|
|
252
|
-
state: data.state,
|
|
253
|
-
});
|
|
254
|
-
updatedFields.push('state');
|
|
255
|
-
}
|
|
256
|
-
if (typeof data.spec === 'string') {
|
|
257
|
-
await storage.patchChannelSpec({
|
|
258
|
-
channelId: context.state.channelId,
|
|
259
|
-
spec: data.spec,
|
|
260
|
-
});
|
|
261
|
-
updatedFields.push('spec');
|
|
262
|
-
}
|
|
263
|
-
if (typeof data.cwd === 'string') {
|
|
264
|
-
await storage.patchChannelState({
|
|
265
|
-
channelId: context.state.channelId,
|
|
266
|
-
state: { cwd: data.cwd },
|
|
267
|
-
});
|
|
268
|
-
updatedFields.push('cwd');
|
|
269
|
-
}
|
|
270
|
-
context.state.channelDetails = await storage.getChannelDetails({
|
|
271
|
-
channelId: context.state.channelId,
|
|
272
|
-
});
|
|
273
|
-
yield {
|
|
274
|
-
type: "client:ui:widget",
|
|
275
|
-
data: {
|
|
276
|
-
widgetId: "patch-channel-details-result" + Date.now(),
|
|
277
|
-
kind: "message",
|
|
278
|
-
title: "Channel details updated.",
|
|
279
|
-
body: `The channel details have been updated. ${updatedFields.join(', ')}`,
|
|
280
|
-
display: "collapsed",
|
|
281
|
-
},
|
|
282
|
-
meta: resultMeta,
|
|
283
|
-
};
|
|
284
|
-
yield {
|
|
285
|
-
type: 'action:patch_channel_details:result',
|
|
286
|
-
data: { success: true, updatedFields },
|
|
287
|
-
meta: resultMeta,
|
|
288
|
-
};
|
|
289
|
-
}
|
|
290
|
-
catch {
|
|
291
|
-
yield {
|
|
292
|
-
type: 'action:patch_channel_details:result',
|
|
293
|
-
data: { success: false, updatedFields },
|
|
294
|
-
meta: resultMeta,
|
|
295
|
-
};
|
|
296
|
-
}
|
|
297
|
-
});
|
|
298
|
-
builder.on('action:patch_thread_details', async function* (event, context) {
|
|
299
|
-
const updatedFields = [];
|
|
300
|
-
const resultMeta = { ...(event.meta || {}), agentId: context.state.agentId };
|
|
301
|
-
try {
|
|
302
|
-
if (!context.state.threadId) {
|
|
303
|
-
throw new Error('Missing threadId in state for patch_thread_details');
|
|
304
|
-
}
|
|
305
|
-
if (event.data.state !== undefined) {
|
|
306
|
-
await storage.patchThreadState({
|
|
307
|
-
channelId: context.state.channelId,
|
|
308
|
-
threadId: context.state.threadId,
|
|
309
|
-
state: event.data.state,
|
|
310
|
-
});
|
|
311
|
-
updatedFields.push('state');
|
|
312
|
-
}
|
|
313
|
-
context.state.threadDetails = await storage.getThreadDetails({
|
|
314
|
-
channelId: context.state.channelId,
|
|
315
|
-
threadId: context.state.threadId,
|
|
316
|
-
});
|
|
317
|
-
yield {
|
|
318
|
-
type: 'action:patch_thread_details:result',
|
|
319
|
-
data: { success: true, updatedFields },
|
|
320
|
-
meta: resultMeta,
|
|
321
|
-
};
|
|
322
|
-
}
|
|
323
|
-
catch {
|
|
324
|
-
yield {
|
|
325
|
-
type: 'action:patch_thread_details:result',
|
|
326
|
-
data: { success: false, updatedFields },
|
|
327
|
-
meta: resultMeta,
|
|
328
|
-
};
|
|
329
|
-
}
|
|
330
|
-
});
|
|
331
44
|
builder.on('agent:usage', async function* (event, context) {
|
|
332
45
|
const { usage } = event.data;
|
|
333
46
|
if (!context.state.threadId)
|
|
@@ -671,41 +384,6 @@ export const storagePlugin = {
|
|
|
671
384
|
};
|
|
672
385
|
}
|
|
673
386
|
});
|
|
674
|
-
builder.on('action:get_workspace_file_url', async function* (event, context) {
|
|
675
|
-
const channelId = context.state.channelId;
|
|
676
|
-
const filePath = event.data?.path;
|
|
677
|
-
const toolCallId = event.meta?.toolCallId;
|
|
678
|
-
if (!filePath) {
|
|
679
|
-
yield {
|
|
680
|
-
type: 'action:get_workspace_file_url:result',
|
|
681
|
-
data: { success: false, path: '', error: 'Path is required', output: 'Path is required' },
|
|
682
|
-
meta: { ...(event.meta || {}), toolCallId },
|
|
683
|
-
};
|
|
684
|
-
return;
|
|
685
|
-
}
|
|
686
|
-
try {
|
|
687
|
-
const { size, mimeType } = await storage.getChannelFileStat({ channelId, path: filePath });
|
|
688
|
-
const url = buildWorkspaceFileUrl({
|
|
689
|
-
baseUrl: resolvePublicBaseUrl(),
|
|
690
|
-
channelId,
|
|
691
|
-
filePath,
|
|
692
|
-
});
|
|
693
|
-
const output = JSON.stringify({ path: filePath, url, mimeType, size });
|
|
694
|
-
yield {
|
|
695
|
-
type: 'action:get_workspace_file_url:result',
|
|
696
|
-
data: { success: true, path: filePath, url, mimeType, size, output },
|
|
697
|
-
meta: { ...(event.meta || {}), toolCallId },
|
|
698
|
-
};
|
|
699
|
-
}
|
|
700
|
-
catch (error) {
|
|
701
|
-
const message = error instanceof Error ? error.message : 'Unknown error';
|
|
702
|
-
yield {
|
|
703
|
-
type: 'action:get_workspace_file_url:result',
|
|
704
|
-
data: { success: false, path: filePath, error: message, output: message },
|
|
705
|
-
meta: { ...(event.meta || {}), toolCallId },
|
|
706
|
-
};
|
|
707
|
-
}
|
|
708
|
-
});
|
|
709
387
|
},
|
|
710
388
|
};
|
|
711
389
|
export default storagePlugin;
|
|
@@ -1,20 +1,19 @@
|
|
|
1
1
|
import { ORCHESTRATOR_AGENT_ID, STATE_AGENT_ID } from '../../app/agent-ids.js';
|
|
2
|
-
import {
|
|
2
|
+
import { assertCloudSystemAgentPluginsMutable, DEFAULT_CLOUD_OPENBOT_AUTH_MODE, isCloudMode, } from '../../app/cloud-mode.js';
|
|
3
|
+
import { DEFAULT_PLUGINS_DIR, DEFAULT_AGENTS_DIR, DEFAULT_CHANNELS_DIR, getBaseDir, getDefaultChannelCwd, resolvePath, VARIABLES_FILE, } from '../../app/config.js';
|
|
3
4
|
import fs from 'node:fs/promises';
|
|
4
5
|
import { readFileSync } from 'node:fs';
|
|
5
6
|
import path from 'node:path';
|
|
6
7
|
import { fileURLToPath, pathToFileURL } from 'node:url';
|
|
7
8
|
import crypto from 'node:crypto';
|
|
8
9
|
import matter from 'gray-matter';
|
|
9
|
-
import {
|
|
10
|
+
import { OPENBOT_PLUGIN_ID } from '../../app/openbot-plugin.js';
|
|
10
11
|
import { listBuiltInPlugins, parsePluginModule } from '../../services/plugins/registry.js';
|
|
12
|
+
import { enrichOpenbotPluginDescriptor, listRegistryModelOptions, } from '../../services/plugins/model-registry.js';
|
|
11
13
|
import { processService } from '../../services/process.js';
|
|
12
14
|
import { memoryService } from '../memory/service.js';
|
|
13
15
|
import { guessMimeType, resolveChannelFile, statChannelFile, } from './files.js';
|
|
14
|
-
const resolveBaseDir = () =>
|
|
15
|
-
const config = loadConfig();
|
|
16
|
-
return resolvePath(config.baseDir || DEFAULT_BASE_DIR);
|
|
17
|
-
};
|
|
16
|
+
const resolveBaseDir = () => getBaseDir();
|
|
18
17
|
const ENTITY_SVG_CANDIDATE_NAMES = ['avatar.svg', 'icon.svg', 'image.svg', 'logo.svg'];
|
|
19
18
|
const toSvgDataUrl = (svg) => `data:image/svg+xml;base64,${Buffer.from(svg, 'utf-8').toString('base64')}`;
|
|
20
19
|
let bundledSystemAgentImage;
|
|
@@ -81,15 +80,40 @@ const getConversationDir = (channelId, threadId) => {
|
|
|
81
80
|
const SYSTEM_AGENT_ID = ORCHESTRATOR_AGENT_ID;
|
|
82
81
|
const SYSTEM_DEFAULT_PLUGINS = [
|
|
83
82
|
{
|
|
84
|
-
id:
|
|
83
|
+
id: OPENBOT_PLUGIN_ID,
|
|
85
84
|
config: {
|
|
86
85
|
model: 'openai/gpt-5.4-mini',
|
|
87
|
-
approval: {
|
|
88
|
-
actions: ['action:bash', 'action:create_channel', 'action:delete_channel'],
|
|
89
|
-
},
|
|
90
86
|
},
|
|
91
87
|
},
|
|
92
88
|
];
|
|
89
|
+
function getCloudSystemDefaultPlugins() {
|
|
90
|
+
return SYSTEM_DEFAULT_PLUGINS.map((ref) => {
|
|
91
|
+
if (ref.id !== OPENBOT_PLUGIN_ID)
|
|
92
|
+
return ref;
|
|
93
|
+
return {
|
|
94
|
+
...ref,
|
|
95
|
+
config: {
|
|
96
|
+
...ref.config,
|
|
97
|
+
authMode: DEFAULT_CLOUD_OPENBOT_AUTH_MODE,
|
|
98
|
+
},
|
|
99
|
+
};
|
|
100
|
+
});
|
|
101
|
+
}
|
|
102
|
+
function mergeCloudSystemPluginRefs(defaults, diskRefs) {
|
|
103
|
+
const defaultOpenbot = defaults.find((ref) => ref.id === OPENBOT_PLUGIN_ID);
|
|
104
|
+
const diskOpenbot = diskRefs.find((ref) => ref.id === OPENBOT_PLUGIN_ID);
|
|
105
|
+
if (!defaultOpenbot)
|
|
106
|
+
return defaults;
|
|
107
|
+
return [
|
|
108
|
+
{
|
|
109
|
+
...defaultOpenbot,
|
|
110
|
+
config: {
|
|
111
|
+
...defaultOpenbot.config,
|
|
112
|
+
...diskOpenbot?.config,
|
|
113
|
+
},
|
|
114
|
+
},
|
|
115
|
+
];
|
|
116
|
+
}
|
|
93
117
|
/** No `openbot` / `bash` — storage-side effects and infra plugins only. */
|
|
94
118
|
const STATE_DEFAULT_PLUGINS = [
|
|
95
119
|
{ id: 'storage' },
|
|
@@ -97,24 +121,41 @@ const STATE_DEFAULT_PLUGINS = [
|
|
|
97
121
|
];
|
|
98
122
|
const STATE_AGENT_INSTRUCTIONS = 'Built-in infra agent for deterministic state reads. No conversational model is attached; handle storage, approvals, memory, and plugin marketplace events.';
|
|
99
123
|
function getSystemAgentDetails(overrides) {
|
|
124
|
+
const defaultPlugins = isCloudMode() ? getCloudSystemDefaultPlugins() : SYSTEM_DEFAULT_PLUGINS;
|
|
100
125
|
const defaults = {
|
|
101
126
|
id: SYSTEM_AGENT_ID,
|
|
102
127
|
name: 'OpenBot',
|
|
103
128
|
image: getBundledSystemAgentImage(),
|
|
104
129
|
description: 'First-party orchestration agent for OpenBot.',
|
|
105
130
|
instructions: '',
|
|
106
|
-
plugins:
|
|
107
|
-
pluginRefs:
|
|
131
|
+
plugins: defaultPlugins.map((ref) => ref.id),
|
|
132
|
+
pluginRefs: defaultPlugins,
|
|
108
133
|
createdAt: new Date(),
|
|
109
134
|
updatedAt: new Date(),
|
|
110
135
|
};
|
|
111
136
|
if (!overrides)
|
|
112
137
|
return defaults;
|
|
138
|
+
const diskInstructions = overrides.instructions?.trim();
|
|
139
|
+
const instructions = diskInstructions && diskInstructions.length > 0 ? diskInstructions : defaults.instructions;
|
|
140
|
+
if (isCloudMode()) {
|
|
141
|
+
const diskRefs = overrides.pluginRefs && overrides.pluginRefs.length > 0 ? overrides.pluginRefs : undefined;
|
|
142
|
+
const refs = diskRefs
|
|
143
|
+
? mergeCloudSystemPluginRefs(defaults.pluginRefs, diskRefs)
|
|
144
|
+
: defaults.pluginRefs;
|
|
145
|
+
return {
|
|
146
|
+
...defaults,
|
|
147
|
+
...overrides,
|
|
148
|
+
id: SYSTEM_AGENT_ID,
|
|
149
|
+
instructions,
|
|
150
|
+
image: overrides.image || defaults.image,
|
|
151
|
+
plugins: refs.map((ref) => ref.id),
|
|
152
|
+
pluginRefs: refs,
|
|
153
|
+
updatedAt: new Date(),
|
|
154
|
+
};
|
|
155
|
+
}
|
|
113
156
|
const refs = overrides.pluginRefs && overrides.pluginRefs.length > 0
|
|
114
157
|
? overrides.pluginRefs
|
|
115
158
|
: defaults.pluginRefs;
|
|
116
|
-
const diskInstructions = overrides.instructions?.trim();
|
|
117
|
-
const instructions = diskInstructions && diskInstructions.length > 0 ? diskInstructions : defaults.instructions;
|
|
118
159
|
return {
|
|
119
160
|
...defaults,
|
|
120
161
|
...overrides,
|
|
@@ -168,8 +209,6 @@ const agentSummaryFromDetails = (details) => ({
|
|
|
168
209
|
createdAt: details.createdAt,
|
|
169
210
|
updatedAt: details.updatedAt,
|
|
170
211
|
});
|
|
171
|
-
// Suppress unused warning until system agent customization re-uses openbotPlugin metadata.
|
|
172
|
-
void openbotPlugin;
|
|
173
212
|
/** Built-in agents may persist optional `agents/<id>/AGENT.md` overlays; read path merges them with defaults. */
|
|
174
213
|
const isBuiltinOverlayAgentId = (agentId) => agentId === SYSTEM_AGENT_ID || agentId === STATE_AGENT_ID;
|
|
175
214
|
const assertAgentIdFormat = (agentId) => {
|
|
@@ -775,11 +814,13 @@ export const storageService = {
|
|
|
775
814
|
return Array.from(deduped.values()).filter((agent) => !agent.hidden);
|
|
776
815
|
},
|
|
777
816
|
getPlugins: async () => {
|
|
778
|
-
const [builtIn, fromDisk] = await Promise.all([
|
|
817
|
+
const [builtIn, fromDisk, modelOptions] = await Promise.all([
|
|
779
818
|
listBuiltInPluginDescriptors(),
|
|
780
819
|
listPluginsFromDisk(),
|
|
820
|
+
listRegistryModelOptions(),
|
|
781
821
|
]);
|
|
782
|
-
const
|
|
822
|
+
const enrichedBuiltIn = builtIn.map((plugin) => enrichOpenbotPluginDescriptor(plugin, modelOptions));
|
|
823
|
+
const merged = [...enrichedBuiltIn, ...fromDisk];
|
|
783
824
|
const deduped = new Map();
|
|
784
825
|
for (const plugin of merged) {
|
|
785
826
|
if (!deduped.has(plugin.id)) {
|
|
@@ -839,6 +880,7 @@ export const storageService = {
|
|
|
839
880
|
},
|
|
840
881
|
createAgent: async ({ agentId, name, description = '', image, hidden, instructions, plugins, }) => {
|
|
841
882
|
assertAgentIdFormat(agentId);
|
|
883
|
+
assertCloudSystemAgentPluginsMutable(agentId, plugins);
|
|
842
884
|
const agentDir = resolvePath(path.join(getAgentsRootDir(), agentId));
|
|
843
885
|
const agentMdPath = path.join(agentDir, 'AGENT.md');
|
|
844
886
|
try {
|
|
@@ -874,6 +916,7 @@ export const storageService = {
|
|
|
874
916
|
},
|
|
875
917
|
updateAgent: async ({ agentId, name, description, image, hidden, instructions, plugins, }) => {
|
|
876
918
|
assertAgentIdFormat(agentId);
|
|
919
|
+
assertCloudSystemAgentPluginsMutable(agentId, plugins);
|
|
877
920
|
const agentDir = resolvePath(path.join(getAgentsRootDir(), agentId));
|
|
878
921
|
const agentMdPath = path.join(agentDir, 'AGENT.md');
|
|
879
922
|
let raw;
|