@meetopenbot/openbot 0.2.6 → 1.0.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/dist/auto-model.js +13 -0
- package/dist/build-tools.js +26 -0
- package/dist/history.js +81 -5
- package/dist/index.js +66 -67
- package/dist/model.js +29 -17
- package/dist/output-buffer.js +31 -0
- package/dist/runtime.js +360 -465
- package/dist/stream-error.js +6 -0
- package/dist/system-prompt.js +4 -0
- package/dist/tools/approval.js +137 -108
- package/dist/tools/ask-agent.js +39 -47
- package/dist/tools/memory.js +41 -73
- package/dist/tools/start-work.js +61 -141
- package/dist/tools/storage.js +62 -424
- package/dist/tools/thread-status.js +22 -38
- package/dist/tools/thread-title.js +57 -0
- package/dist/tools/todo.js +33 -52
- package/dist/types.js +0 -8
- package/package.json +8 -6
- package/dist/tools/bash.js +0 -432
- package/dist/tools/preview.js +0 -269
- package/dist/tools/ui.js +0 -120
- package/dist/utils/workspace-url.js +0 -6
package/dist/tools/storage.js
CHANGED
|
@@ -1,183 +1,88 @@
|
|
|
1
|
-
import z from
|
|
2
|
-
import {
|
|
3
|
-
import { buildWorkspaceFileUrl } from "../utils/workspace-url.js";
|
|
4
|
-
import { isPlaceholderSpaceId, placeholderSpaceError, } from "../space-id.js";
|
|
1
|
+
import z from 'zod';
|
|
2
|
+
import { isPlaceholderSpaceId, placeholderSpaceError } from '../space-id.js';
|
|
5
3
|
function normalizeChannelId(raw) {
|
|
6
4
|
return raw
|
|
7
5
|
.trim()
|
|
8
6
|
.toLowerCase()
|
|
9
|
-
.replace(/[^a-z0-9]+/g,
|
|
10
|
-
.replace(/(^-|-$)/g,
|
|
7
|
+
.replace(/[^a-z0-9]+/g, '-')
|
|
8
|
+
.replace(/(^-|-$)/g, '');
|
|
11
9
|
}
|
|
12
10
|
function displayNameFromChannelId(channelId) {
|
|
13
11
|
return channelId
|
|
14
|
-
.split(
|
|
12
|
+
.split('-')
|
|
15
13
|
.filter(Boolean)
|
|
16
14
|
.map((part) => part.charAt(0).toUpperCase() + part.slice(1))
|
|
17
|
-
.join(
|
|
15
|
+
.join(' ');
|
|
18
16
|
}
|
|
19
|
-
function
|
|
20
|
-
|
|
21
|
-
type:
|
|
17
|
+
async function emitCreateChannelWidget(ctx, args) {
|
|
18
|
+
await ctx.emit({
|
|
19
|
+
type: 'client:ui:widget',
|
|
22
20
|
data: {
|
|
23
21
|
widgetId: args.widgetId,
|
|
24
|
-
kind:
|
|
25
|
-
title:
|
|
22
|
+
kind: 'message',
|
|
23
|
+
title: 'create_channel',
|
|
26
24
|
description: args.channelId || undefined,
|
|
27
25
|
body: args.body,
|
|
28
|
-
display:
|
|
26
|
+
display: 'collapsed',
|
|
29
27
|
state: args.state,
|
|
30
28
|
},
|
|
31
|
-
meta:
|
|
32
|
-
};
|
|
29
|
+
meta: { agentId: ctx.agentId, threadId: ctx.threadId ?? ctx.state.threadId },
|
|
30
|
+
});
|
|
33
31
|
}
|
|
34
|
-
const
|
|
32
|
+
export const storageTools = {
|
|
35
33
|
create_channel: {
|
|
36
|
-
description:
|
|
34
|
+
description: 'Create a new Space after the human asked for it or agreed to your suggestion. Prefer an existing Space and start_work. Skip questions, listings, and Q&A in #general. Never use placeholder ids (noop, temp, misc).',
|
|
37
35
|
inputSchema: z.object({
|
|
38
36
|
channelId: z
|
|
39
37
|
.string()
|
|
40
|
-
.describe(
|
|
38
|
+
.describe('Unique Space id (e.g. product-launch, backend-platform).'),
|
|
41
39
|
name: z
|
|
42
40
|
.string()
|
|
43
41
|
.optional()
|
|
44
|
-
.describe(
|
|
42
|
+
.describe('Optional display name. Defaults to a title-cased Space id.'),
|
|
45
43
|
spec: z
|
|
46
44
|
.string()
|
|
47
45
|
.optional()
|
|
48
|
-
.describe(
|
|
46
|
+
.describe('Optional initial markdown content for the channel spec.'),
|
|
49
47
|
initialState: z
|
|
50
48
|
.record(z.string(), z.unknown())
|
|
51
49
|
.optional()
|
|
52
|
-
.describe(
|
|
50
|
+
.describe('Optional initial state object for the channel. Do not set cwd; the runtime assigns the workspace path.'),
|
|
53
51
|
}),
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
.object({
|
|
59
|
-
state: z
|
|
60
|
-
.record(z.string(), z.unknown())
|
|
61
|
-
.optional()
|
|
62
|
-
.describe("JSON state object for the channel."),
|
|
63
|
-
spec: z
|
|
64
|
-
.string()
|
|
65
|
-
.optional()
|
|
66
|
-
.describe("Markdown content for the channel specification (SPEC.md). Use for goals and rules."),
|
|
67
|
-
cwd: z
|
|
68
|
-
.string()
|
|
69
|
-
.optional()
|
|
70
|
-
.describe("Current working directory for the channel."),
|
|
71
|
-
})
|
|
72
|
-
.refine((value) => value.state !== undefined ||
|
|
73
|
-
value.spec !== undefined ||
|
|
74
|
-
value.cwd !== undefined, { message: "Provide at least one of state, spec, or cwd." }),
|
|
75
|
-
},
|
|
76
|
-
patch_thread_details: {
|
|
77
|
-
description: "Patch current thread details (state). Use for thread metadata such as `name` or `isSmartNamed`. For job status use `set_thread_status`. For multi-step task tracking, use `todo_write`.",
|
|
78
|
-
inputSchema: z.object({
|
|
79
|
-
state: z
|
|
80
|
-
.record(z.string(), z.unknown())
|
|
81
|
-
.describe("JSON state object for the thread. Merges with existing state."),
|
|
82
|
-
}),
|
|
83
|
-
},
|
|
84
|
-
create_variable: {
|
|
85
|
-
description: "Create or update a variable in the workspace storage.",
|
|
86
|
-
inputSchema: z.object({
|
|
87
|
-
key: z.string().describe("The key of the variable."),
|
|
88
|
-
value: z.string().describe("The value of the variable."),
|
|
89
|
-
secret: z
|
|
90
|
-
.boolean()
|
|
91
|
-
.optional()
|
|
92
|
-
.describe("Whether the variable is a secret."),
|
|
93
|
-
}),
|
|
94
|
-
},
|
|
95
|
-
delete_variable: {
|
|
96
|
-
description: "Delete a variable from the workspace storage.",
|
|
97
|
-
inputSchema: z.object({
|
|
98
|
-
key: z.string().describe("The key of the variable to delete."),
|
|
99
|
-
}),
|
|
100
|
-
},
|
|
101
|
-
delete_channel: {
|
|
102
|
-
description: "Permanently delete a Space and all its threads. Always confirm with the user before deleting.",
|
|
103
|
-
inputSchema: z.object({
|
|
104
|
-
channelId: z.string().describe("The channel ID to delete."),
|
|
105
|
-
}),
|
|
106
|
-
},
|
|
107
|
-
get_workspace_file_url: {
|
|
108
|
-
description: "Get a fetchable HTTP URL for a file in the current channel workspace (images, video, audio, documents).",
|
|
109
|
-
inputSchema: z.object({
|
|
110
|
-
path: z
|
|
111
|
-
.string()
|
|
112
|
-
.describe('Path relative to the channel working directory, e.g. "uploads/clip.mp4".'),
|
|
113
|
-
}),
|
|
114
|
-
},
|
|
115
|
-
};
|
|
116
|
-
export function registerStorageTools(context) {
|
|
117
|
-
const storage = context.storage;
|
|
118
|
-
const { publicBaseUrl } = context;
|
|
119
|
-
const resolvePublicBaseUrl = () => publicBaseUrl;
|
|
120
|
-
return (builder) => {
|
|
121
|
-
const actions = asActionBuilder(builder);
|
|
122
|
-
actions.on("create_channel", async function* (event, context) {
|
|
123
|
-
const { channelId, name, spec, initialState } = event.data;
|
|
124
|
-
const rawChannelId = normalizeChannelId(channelId || "");
|
|
125
|
-
const resultMeta = {
|
|
126
|
-
...(event.meta || {}),
|
|
127
|
-
agentId: context.state.agentId,
|
|
128
|
-
threadId: event.meta?.threadId || context.state.threadId,
|
|
129
|
-
};
|
|
130
|
-
const widgetId = typeof event.meta?.toolCallId === "string"
|
|
131
|
-
? event.meta.toolCallId
|
|
132
|
-
: `create_channel:${rawChannelId || Date.now()}`;
|
|
52
|
+
execute: async (raw, ctx) => {
|
|
53
|
+
const { channelId, name, spec, initialState } = (raw ?? {});
|
|
54
|
+
const rawChannelId = normalizeChannelId(channelId || '');
|
|
55
|
+
const widgetId = ctx.toolCallId ?? `create_channel:${rawChannelId || Date.now()}`;
|
|
133
56
|
if (!rawChannelId) {
|
|
134
|
-
const error =
|
|
135
|
-
|
|
57
|
+
const error = 'channelId is required';
|
|
58
|
+
await emitCreateChannelWidget(ctx, {
|
|
136
59
|
widgetId,
|
|
137
|
-
channelId:
|
|
60
|
+
channelId: '',
|
|
138
61
|
body: error,
|
|
139
|
-
state:
|
|
140
|
-
meta: resultMeta,
|
|
62
|
+
state: 'error',
|
|
141
63
|
});
|
|
142
|
-
|
|
143
|
-
type: "action:create_channel:result",
|
|
144
|
-
data: {
|
|
145
|
-
success: false,
|
|
146
|
-
channelId: "",
|
|
147
|
-
channelUrl: "",
|
|
148
|
-
error,
|
|
149
|
-
output: error,
|
|
150
|
-
},
|
|
151
|
-
meta: resultMeta,
|
|
152
|
-
};
|
|
153
|
-
return;
|
|
64
|
+
return { success: false, channelId: '', channelUrl: '', error, output: error };
|
|
154
65
|
}
|
|
155
66
|
if (isPlaceholderSpaceId(rawChannelId)) {
|
|
156
67
|
const error = placeholderSpaceError(rawChannelId);
|
|
157
|
-
|
|
68
|
+
await emitCreateChannelWidget(ctx, {
|
|
158
69
|
widgetId,
|
|
159
70
|
channelId: rawChannelId,
|
|
160
71
|
body: error,
|
|
161
|
-
state:
|
|
162
|
-
meta: resultMeta,
|
|
72
|
+
state: 'error',
|
|
163
73
|
});
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
error,
|
|
171
|
-
output: error,
|
|
172
|
-
},
|
|
173
|
-
meta: resultMeta,
|
|
74
|
+
return {
|
|
75
|
+
success: false,
|
|
76
|
+
channelId: rawChannelId,
|
|
77
|
+
channelUrl: '',
|
|
78
|
+
error,
|
|
79
|
+
output: error,
|
|
174
80
|
};
|
|
175
|
-
return;
|
|
176
81
|
}
|
|
177
82
|
const channelUrl = `/channels/${rawChannelId}`;
|
|
178
|
-
const displayName = typeof name ===
|
|
83
|
+
const displayName = typeof name === 'string' && name.trim()
|
|
179
84
|
? name.trim()
|
|
180
|
-
: typeof initialState?.name ===
|
|
85
|
+
: typeof initialState?.name === 'string' && initialState.name.trim()
|
|
181
86
|
? initialState.name.trim()
|
|
182
87
|
: displayNameFromChannelId(rawChannelId);
|
|
183
88
|
const mergedInitial = {
|
|
@@ -185,317 +90,50 @@ export function registerStorageTools(context) {
|
|
|
185
90
|
name: displayName,
|
|
186
91
|
};
|
|
187
92
|
delete mergedInitial.cwd;
|
|
188
|
-
const channelSpec = typeof spec ===
|
|
189
|
-
|
|
93
|
+
const channelSpec = typeof spec === 'string' && spec.trim() ? spec : `# ${displayName}\n\n`;
|
|
94
|
+
await emitCreateChannelWidget(ctx, {
|
|
190
95
|
widgetId,
|
|
191
96
|
channelId: rawChannelId,
|
|
192
|
-
body:
|
|
193
|
-
state:
|
|
194
|
-
meta: resultMeta,
|
|
97
|
+
body: 'Creating…',
|
|
98
|
+
state: 'open',
|
|
195
99
|
});
|
|
196
100
|
try {
|
|
197
|
-
await storage.createChannel({
|
|
101
|
+
await ctx.storage.createChannel({
|
|
198
102
|
channelId: rawChannelId,
|
|
199
103
|
spec: channelSpec,
|
|
200
104
|
initialState: mergedInitial,
|
|
201
105
|
});
|
|
202
106
|
const output = `Created channel \`${rawChannelId}\`.`;
|
|
203
|
-
|
|
107
|
+
await emitCreateChannelWidget(ctx, {
|
|
204
108
|
widgetId,
|
|
205
109
|
channelId: rawChannelId,
|
|
206
110
|
body: output,
|
|
207
|
-
state:
|
|
208
|
-
meta: resultMeta,
|
|
111
|
+
state: 'submitted',
|
|
209
112
|
});
|
|
210
|
-
|
|
211
|
-
type: "action:create_channel:result",
|
|
212
|
-
data: { success: true, channelId: rawChannelId, channelUrl, output },
|
|
213
|
-
meta: resultMeta,
|
|
214
|
-
};
|
|
113
|
+
return { success: true, channelId: rawChannelId, channelUrl, output };
|
|
215
114
|
}
|
|
216
115
|
catch (error) {
|
|
217
|
-
const message = error instanceof Error ? error.message :
|
|
116
|
+
const message = error instanceof Error ? error.message : 'Unknown error';
|
|
218
117
|
const output = `Failed to create channel: ${message}`;
|
|
219
|
-
|
|
118
|
+
await emitCreateChannelWidget(ctx, {
|
|
220
119
|
widgetId,
|
|
221
120
|
channelId: rawChannelId,
|
|
222
121
|
body: output,
|
|
223
|
-
state:
|
|
224
|
-
meta: resultMeta,
|
|
225
|
-
});
|
|
226
|
-
yield {
|
|
227
|
-
type: "action:create_channel:result",
|
|
228
|
-
data: {
|
|
229
|
-
success: false,
|
|
230
|
-
channelId: rawChannelId,
|
|
231
|
-
channelUrl,
|
|
232
|
-
error: message,
|
|
233
|
-
output,
|
|
234
|
-
},
|
|
235
|
-
meta: resultMeta,
|
|
236
|
-
};
|
|
237
|
-
}
|
|
238
|
-
});
|
|
239
|
-
actions.on("delete_channel", async function* (event, context) {
|
|
240
|
-
const rawChannelId = (event.data?.channelId || "").trim();
|
|
241
|
-
const resultMeta = {
|
|
242
|
-
...(event.meta || {}),
|
|
243
|
-
agentId: context.state.agentId,
|
|
244
|
-
};
|
|
245
|
-
if (!rawChannelId) {
|
|
246
|
-
yield {
|
|
247
|
-
type: "action:delete_channel:result",
|
|
248
|
-
data: {
|
|
249
|
-
success: false,
|
|
250
|
-
channelId: "",
|
|
251
|
-
error: "channelId is required",
|
|
252
|
-
},
|
|
253
|
-
meta: resultMeta,
|
|
254
|
-
};
|
|
255
|
-
return;
|
|
256
|
-
}
|
|
257
|
-
try {
|
|
258
|
-
await storage.deleteChannel({ channelId: rawChannelId });
|
|
259
|
-
yield {
|
|
260
|
-
type: "action:delete_channel:result",
|
|
261
|
-
data: { success: true, channelId: rawChannelId },
|
|
262
|
-
meta: resultMeta,
|
|
263
|
-
};
|
|
264
|
-
yield {
|
|
265
|
-
type: "agent:output",
|
|
266
|
-
data: { content: `Deleted channel \`${rawChannelId}\`.` },
|
|
267
|
-
meta: resultMeta,
|
|
268
|
-
};
|
|
269
|
-
}
|
|
270
|
-
catch (error) {
|
|
271
|
-
yield {
|
|
272
|
-
type: "action:delete_channel:result",
|
|
273
|
-
data: {
|
|
274
|
-
success: false,
|
|
275
|
-
channelId: rawChannelId,
|
|
276
|
-
error: error instanceof Error ? error.message : "Unknown error",
|
|
277
|
-
},
|
|
278
|
-
meta: resultMeta,
|
|
279
|
-
};
|
|
280
|
-
}
|
|
281
|
-
});
|
|
282
|
-
actions.on("update_channel", async function* (event, context) {
|
|
283
|
-
const data = event.data;
|
|
284
|
-
const targetChannelId = (data.channelId ||
|
|
285
|
-
context.state.channelId ||
|
|
286
|
-
"").trim();
|
|
287
|
-
const resultMeta = {
|
|
288
|
-
...(event.meta || {}),
|
|
289
|
-
agentId: context.state.agentId,
|
|
290
|
-
};
|
|
291
|
-
if (!targetChannelId) {
|
|
292
|
-
yield {
|
|
293
|
-
type: "action:update_channel:result",
|
|
294
|
-
data: {
|
|
295
|
-
success: false,
|
|
296
|
-
channelId: "",
|
|
297
|
-
updatedFields: [],
|
|
298
|
-
},
|
|
299
|
-
meta: resultMeta,
|
|
300
|
-
};
|
|
301
|
-
return;
|
|
302
|
-
}
|
|
303
|
-
const patch = {};
|
|
304
|
-
const updatedFields = [];
|
|
305
|
-
if (typeof data.name === "string" && data.name.trim()) {
|
|
306
|
-
patch.name = data.name.trim();
|
|
307
|
-
updatedFields.push("name");
|
|
308
|
-
}
|
|
309
|
-
if (typeof data.cwd === "string" && data.cwd.trim()) {
|
|
310
|
-
patch.cwd = data.cwd.trim();
|
|
311
|
-
updatedFields.push("cwd");
|
|
312
|
-
}
|
|
313
|
-
try {
|
|
314
|
-
if (updatedFields.length > 0) {
|
|
315
|
-
await storage.patchChannelState({
|
|
316
|
-
channelId: targetChannelId,
|
|
317
|
-
state: patch,
|
|
318
|
-
});
|
|
319
|
-
}
|
|
320
|
-
if (targetChannelId === context.state.channelId) {
|
|
321
|
-
context.state.channelDetails = await storage.getChannelDetails({
|
|
322
|
-
channelId: context.state.channelId,
|
|
323
|
-
});
|
|
324
|
-
}
|
|
325
|
-
yield {
|
|
326
|
-
type: "action:update_channel:result",
|
|
327
|
-
data: { success: true, channelId: targetChannelId, updatedFields },
|
|
328
|
-
meta: resultMeta,
|
|
329
|
-
};
|
|
330
|
-
}
|
|
331
|
-
catch {
|
|
332
|
-
yield {
|
|
333
|
-
type: "action:update_channel:result",
|
|
334
|
-
data: { success: false, channelId: targetChannelId, updatedFields },
|
|
335
|
-
meta: resultMeta,
|
|
336
|
-
};
|
|
337
|
-
}
|
|
338
|
-
});
|
|
339
|
-
actions.on("patch_channel_details", async function* (event, context) {
|
|
340
|
-
const updatedFields = [];
|
|
341
|
-
const resultMeta = {
|
|
342
|
-
...(event.meta || {}),
|
|
343
|
-
agentId: context.state.agentId,
|
|
344
|
-
};
|
|
345
|
-
const data = event.data;
|
|
346
|
-
try {
|
|
347
|
-
if (data.state !== undefined) {
|
|
348
|
-
await storage.patchChannelState({
|
|
349
|
-
channelId: context.state.channelId,
|
|
350
|
-
state: data.state,
|
|
351
|
-
});
|
|
352
|
-
updatedFields.push("state");
|
|
353
|
-
}
|
|
354
|
-
if (typeof data.spec === "string") {
|
|
355
|
-
await storage.patchChannelSpec({
|
|
356
|
-
channelId: context.state.channelId,
|
|
357
|
-
spec: data.spec,
|
|
358
|
-
});
|
|
359
|
-
updatedFields.push("spec");
|
|
360
|
-
}
|
|
361
|
-
if (typeof data.cwd === "string") {
|
|
362
|
-
await storage.patchChannelState({
|
|
363
|
-
channelId: context.state.channelId,
|
|
364
|
-
state: { cwd: data.cwd },
|
|
365
|
-
});
|
|
366
|
-
updatedFields.push("cwd");
|
|
367
|
-
}
|
|
368
|
-
context.state.channelDetails = await storage.getChannelDetails({
|
|
369
|
-
channelId: context.state.channelId,
|
|
370
|
-
});
|
|
371
|
-
yield {
|
|
372
|
-
type: "client:ui:widget",
|
|
373
|
-
data: {
|
|
374
|
-
widgetId: "patch-channel-details-result" + Date.now(),
|
|
375
|
-
kind: "message",
|
|
376
|
-
title: "Channel details updated.",
|
|
377
|
-
body: `The channel details have been updated. ${updatedFields.join(", ")}`,
|
|
378
|
-
display: "collapsed",
|
|
379
|
-
},
|
|
380
|
-
meta: resultMeta,
|
|
381
|
-
};
|
|
382
|
-
yield {
|
|
383
|
-
type: "action:patch_channel_details:result",
|
|
384
|
-
data: { success: true, updatedFields },
|
|
385
|
-
meta: resultMeta,
|
|
386
|
-
};
|
|
387
|
-
}
|
|
388
|
-
catch {
|
|
389
|
-
yield {
|
|
390
|
-
type: "action:patch_channel_details:result",
|
|
391
|
-
data: { success: false, updatedFields },
|
|
392
|
-
meta: resultMeta,
|
|
393
|
-
};
|
|
394
|
-
}
|
|
395
|
-
});
|
|
396
|
-
actions.on("patch_thread_details", async function* (event, context) {
|
|
397
|
-
const updatedFields = [];
|
|
398
|
-
const resultMeta = {
|
|
399
|
-
...(event.meta || {}),
|
|
400
|
-
agentId: context.state.agentId,
|
|
401
|
-
};
|
|
402
|
-
try {
|
|
403
|
-
if (!context.state.threadId) {
|
|
404
|
-
throw new Error("Missing threadId in state for patch_thread_details");
|
|
405
|
-
}
|
|
406
|
-
if (event.data?.state !== undefined) {
|
|
407
|
-
const state = { ...event.data.state };
|
|
408
|
-
delete state.status;
|
|
409
|
-
delete state.statusUpdatedAt;
|
|
410
|
-
delete state.statusReason;
|
|
411
|
-
await storage.patchThreadState({
|
|
412
|
-
channelId: context.state.channelId,
|
|
413
|
-
threadId: context.state.threadId,
|
|
414
|
-
state,
|
|
415
|
-
});
|
|
416
|
-
updatedFields.push("state");
|
|
417
|
-
}
|
|
418
|
-
context.state.threadDetails = await storage.getThreadDetails({
|
|
419
|
-
channelId: context.state.channelId,
|
|
420
|
-
threadId: context.state.threadId,
|
|
421
|
-
});
|
|
422
|
-
yield {
|
|
423
|
-
type: "action:patch_thread_details:result",
|
|
424
|
-
data: { success: true, updatedFields },
|
|
425
|
-
meta: resultMeta,
|
|
426
|
-
};
|
|
427
|
-
}
|
|
428
|
-
catch {
|
|
429
|
-
yield {
|
|
430
|
-
type: "action:patch_thread_details:result",
|
|
431
|
-
data: { success: false, updatedFields },
|
|
432
|
-
meta: resultMeta,
|
|
433
|
-
};
|
|
434
|
-
}
|
|
435
|
-
});
|
|
436
|
-
actions.on("get_workspace_file_url", async function* (event, context) {
|
|
437
|
-
const channelId = context.state.channelId;
|
|
438
|
-
const filePath = event.data?.path;
|
|
439
|
-
const toolCallId = event.meta?.toolCallId;
|
|
440
|
-
if (!filePath) {
|
|
441
|
-
yield {
|
|
442
|
-
type: "action:get_workspace_file_url:result",
|
|
443
|
-
data: {
|
|
444
|
-
success: false,
|
|
445
|
-
path: "",
|
|
446
|
-
error: "Path is required",
|
|
447
|
-
output: "Path is required",
|
|
448
|
-
},
|
|
449
|
-
meta: { ...(event.meta || {}), toolCallId },
|
|
450
|
-
};
|
|
451
|
-
return;
|
|
452
|
-
}
|
|
453
|
-
try {
|
|
454
|
-
const { size, mimeType } = await storage.getChannelFileStat({
|
|
455
|
-
channelId,
|
|
456
|
-
path: filePath,
|
|
122
|
+
state: 'error',
|
|
457
123
|
});
|
|
458
|
-
|
|
459
|
-
|
|
460
|
-
channelId,
|
|
461
|
-
|
|
462
|
-
|
|
463
|
-
|
|
464
|
-
path: filePath,
|
|
465
|
-
url,
|
|
466
|
-
mimeType,
|
|
467
|
-
size,
|
|
468
|
-
});
|
|
469
|
-
yield {
|
|
470
|
-
type: "action:get_workspace_file_url:result",
|
|
471
|
-
data: {
|
|
472
|
-
success: true,
|
|
473
|
-
path: filePath,
|
|
474
|
-
url,
|
|
475
|
-
mimeType,
|
|
476
|
-
size,
|
|
477
|
-
output,
|
|
478
|
-
},
|
|
479
|
-
meta: { ...(event.meta || {}), toolCallId },
|
|
480
|
-
};
|
|
481
|
-
}
|
|
482
|
-
catch (error) {
|
|
483
|
-
const message = error instanceof Error ? error.message : "Unknown error";
|
|
484
|
-
yield {
|
|
485
|
-
type: "action:get_workspace_file_url:result",
|
|
486
|
-
data: {
|
|
487
|
-
success: false,
|
|
488
|
-
path: filePath,
|
|
489
|
-
error: message,
|
|
490
|
-
output: message,
|
|
491
|
-
},
|
|
492
|
-
meta: { ...(event.meta || {}), toolCallId },
|
|
124
|
+
return {
|
|
125
|
+
success: false,
|
|
126
|
+
channelId: rawChannelId,
|
|
127
|
+
channelUrl,
|
|
128
|
+
error: message,
|
|
129
|
+
output,
|
|
493
130
|
};
|
|
494
131
|
}
|
|
495
|
-
}
|
|
496
|
-
}
|
|
497
|
-
}
|
|
132
|
+
},
|
|
133
|
+
},
|
|
134
|
+
};
|
|
135
|
+
export const tools = storageTools;
|
|
498
136
|
export const storageToolPlugin = {
|
|
499
|
-
toolDefinitions:
|
|
500
|
-
|
|
137
|
+
toolDefinitions: storageTools,
|
|
138
|
+
tools: storageTools,
|
|
501
139
|
};
|
|
@@ -10,7 +10,7 @@ function formatStatusOutput(args) {
|
|
|
10
10
|
? `Job status set to ${args.status}: ${reason}`
|
|
11
11
|
: `Job status set to ${args.status}.`;
|
|
12
12
|
}
|
|
13
|
-
const
|
|
13
|
+
export const toolDefinitions = {
|
|
14
14
|
set_thread_status: {
|
|
15
15
|
description: "Set this job's workflow status. Use needs_input when blocked on the human, ready_for_review when you believe the work is done, working when the job is still in progress. Do not use working to mean you are currently executing — that is tracked automatically. Never mark completed or archived — only the human can.",
|
|
16
16
|
inputSchema: z.object({
|
|
@@ -24,31 +24,27 @@ const threadStatusToolDefinitions = {
|
|
|
24
24
|
}),
|
|
25
25
|
},
|
|
26
26
|
};
|
|
27
|
-
export const
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
toolDefinitions: threadStatusToolDefinitions,
|
|
32
|
-
factory: (pluginContext) => (builder) => {
|
|
33
|
-
builder.on("action:set_thread_status", async function* (event, context) {
|
|
34
|
-
const resultMeta = { ...(event.meta || {}), agentId: context.state.agentId };
|
|
27
|
+
export const tools = {
|
|
28
|
+
set_thread_status: {
|
|
29
|
+
...toolDefinitions.set_thread_status,
|
|
30
|
+
execute: async (rawArgs, ctx) => {
|
|
35
31
|
try {
|
|
36
|
-
const channelId =
|
|
37
|
-
const threadId =
|
|
32
|
+
const channelId = ctx.channelId ?? ctx.state.channelId ?? '';
|
|
33
|
+
const threadId = ctx.threadId ?? ctx.state.threadId;
|
|
38
34
|
if (!channelId || !threadId) {
|
|
39
35
|
throw new Error("Missing channelId or threadId for set_thread_status");
|
|
40
36
|
}
|
|
41
|
-
const
|
|
37
|
+
const data = (rawArgs ?? {});
|
|
38
|
+
const status = data.status;
|
|
42
39
|
if (status !== "working" &&
|
|
43
40
|
status !== "needs_input" &&
|
|
44
41
|
status !== "ready_for_review") {
|
|
45
|
-
throw new Error(
|
|
42
|
+
throw new Error("Agents may only set working, needs_input, or ready_for_review. The human marks completed and archived.");
|
|
46
43
|
}
|
|
47
|
-
const
|
|
48
|
-
|
|
49
|
-
? reasonRaw.trim()
|
|
44
|
+
const reason = typeof data.reason === "string" && data.reason.trim()
|
|
45
|
+
? data.reason.trim()
|
|
50
46
|
: "";
|
|
51
|
-
await
|
|
47
|
+
await ctx.storage.patchThreadState({
|
|
52
48
|
channelId,
|
|
53
49
|
threadId,
|
|
54
50
|
state: {
|
|
@@ -57,35 +53,23 @@ export const threadStatusPlugin = {
|
|
|
57
53
|
statusReason: reason,
|
|
58
54
|
},
|
|
59
55
|
});
|
|
60
|
-
|
|
56
|
+
ctx.state.threadDetails = await ctx.storage.getThreadDetails({
|
|
61
57
|
channelId,
|
|
62
58
|
threadId,
|
|
63
59
|
});
|
|
64
60
|
const output = formatStatusOutput({ status, reason });
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
...(reason ? { reason } : {}),
|
|
71
|
-
output,
|
|
72
|
-
},
|
|
73
|
-
meta: resultMeta,
|
|
61
|
+
return {
|
|
62
|
+
success: true,
|
|
63
|
+
status,
|
|
64
|
+
...(reason ? { reason } : {}),
|
|
65
|
+
output,
|
|
74
66
|
};
|
|
75
67
|
}
|
|
76
68
|
catch (error) {
|
|
77
69
|
const message = error instanceof Error ? error.message : "Unknown error";
|
|
78
|
-
|
|
79
|
-
type: "action:set_thread_status:result",
|
|
80
|
-
data: {
|
|
81
|
-
success: false,
|
|
82
|
-
error: message,
|
|
83
|
-
output: message,
|
|
84
|
-
},
|
|
85
|
-
meta: resultMeta,
|
|
86
|
-
};
|
|
70
|
+
return { success: false, error: message, output: message };
|
|
87
71
|
}
|
|
88
|
-
}
|
|
72
|
+
},
|
|
89
73
|
},
|
|
90
74
|
};
|
|
91
|
-
export
|
|
75
|
+
export const threadStatusTools = tools;
|