openbot 0.5.4 → 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.md +5 -4
- package/deploy/README.md +2 -4
- package/dist/app/cli.js +3 -1
- package/dist/app/cloud-mode.js +5 -16
- package/dist/app/ensure-default-stack.js +54 -0
- package/dist/app/openbot-plugin.js +4 -0
- package/dist/app/server.js +2 -3
- package/dist/harness/index.js +3 -0
- package/dist/plugins/openbot/index.js +6 -5
- package/dist/plugins/openbot/model.js +2 -41
- package/dist/plugins/openbot/runtime.js +9 -4
- package/dist/plugins/storage/index.js +3 -325
- package/dist/plugins/storage/service.js +18 -21
- package/dist/services/plugins/host.js +21 -0
- package/dist/services/plugins/model-registry.js +34 -9
- package/dist/services/plugins/registry.js +26 -42
- package/dist/services/todo/types.js +1 -0
- package/docs/templates/AGENT.example.md +8 -14
- package/package.json +2 -2
- package/src/app/cli.ts +3 -1
- package/src/app/cloud-mode.ts +7 -22
- package/src/app/ensure-default-stack.ts +63 -0
- package/src/app/openbot-plugin.ts +5 -0
- package/src/app/server.ts +2 -5
- package/src/app/types.ts +3 -8
- package/src/harness/index.ts +4 -0
- package/src/plugins/storage/index.ts +3 -368
- package/src/plugins/storage/service.ts +17 -22
- package/src/services/plugins/host.ts +36 -0
- package/src/services/plugins/model-registry.ts +41 -9
- package/src/services/plugins/registry.ts +28 -43
- package/src/services/plugins/service.ts +6 -11
- package/src/services/plugins/types.ts +36 -2
- package/src/services/todo/types.ts +12 -0
- package/src/plugins/approval/index.ts +0 -147
- package/src/plugins/bash/index.ts +0 -545
- package/src/plugins/delegation/index.ts +0 -153
- package/src/plugins/memory/index.ts +0 -182
- package/src/plugins/openbot/context.ts +0 -137
- package/src/plugins/openbot/history.ts +0 -158
- package/src/plugins/openbot/index.ts +0 -95
- package/src/plugins/openbot/model.ts +0 -76
- package/src/plugins/openbot/runtime.ts +0 -504
- package/src/plugins/openbot/system-prompt.ts +0 -57
- package/src/plugins/preview/index.ts +0 -323
- package/src/plugins/todo/index.ts +0 -166
- package/src/plugins/todo/service.ts +0 -123
- package/src/plugins/ui/index.ts +0 -130
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "openbot",
|
|
3
|
-
"version": "0.5.
|
|
3
|
+
"version": "0.5.5",
|
|
4
4
|
"private": false,
|
|
5
5
|
"type": "module",
|
|
6
6
|
"engines": {
|
|
@@ -11,7 +11,7 @@
|
|
|
11
11
|
"build": "tsc && mkdir -p dist/assets && cp src/assets/icon.svg dist/assets/icon.svg",
|
|
12
12
|
"start": "node dist/app/cli.js start",
|
|
13
13
|
"format": "prettier --write .",
|
|
14
|
-
"push": "fly deploy --build-only --push --config deploy/fly.toml -a openbot-runtime --image-label v0.5.
|
|
14
|
+
"push": "fly deploy --build-only --push --config deploy/fly.toml -a openbot-runtime --image-label v0.5.5"
|
|
15
15
|
},
|
|
16
16
|
"bin": {
|
|
17
17
|
"openbot": "./dist/app/cli.js"
|
package/src/app/cli.ts
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
import { Command } from 'commander';
|
|
3
3
|
import { bootstrap } from './bootstrap.js';
|
|
4
|
+
import { ensureDefaultStack } from './ensure-default-stack.js';
|
|
4
5
|
import { startServer } from './server.js';
|
|
5
6
|
|
|
6
7
|
const program = new Command();
|
|
@@ -26,7 +27,7 @@ function checkNodeVersion() {
|
|
|
26
27
|
|
|
27
28
|
checkNodeVersion();
|
|
28
29
|
|
|
29
|
-
program.name('openbot').description('OpenBot CLI').version('0.5.
|
|
30
|
+
program.name('openbot').description('OpenBot CLI').version('0.5.5');
|
|
30
31
|
|
|
31
32
|
program
|
|
32
33
|
.command('start')
|
|
@@ -34,6 +35,7 @@ program
|
|
|
34
35
|
.option('-p, --port <number>', 'Port to listen on')
|
|
35
36
|
.action(async (options) => {
|
|
36
37
|
await bootstrap();
|
|
38
|
+
await ensureDefaultStack();
|
|
37
39
|
await startServer(options);
|
|
38
40
|
});
|
|
39
41
|
|
package/src/app/cloud-mode.ts
CHANGED
|
@@ -1,35 +1,20 @@
|
|
|
1
1
|
import { ORCHESTRATOR_AGENT_ID } from './agent-ids.js';
|
|
2
2
|
|
|
3
|
-
/** Platform-managed OpenBot (Fly
|
|
3
|
+
/** Platform-managed OpenBot (Fly). Self-hosted when unset. */
|
|
4
4
|
export const isCloudMode = (): boolean => process.env.OPENBOT_CLOUD_MODE === '1';
|
|
5
5
|
|
|
6
|
-
/**
|
|
7
|
-
export
|
|
6
|
+
/** How the cloud system agent authenticates to LLM providers. */
|
|
7
|
+
export type OpenbotAuthMode = 'credits' | 'byok';
|
|
8
8
|
|
|
9
|
-
/** Default cloud
|
|
10
|
-
export const
|
|
11
|
-
|
|
12
|
-
export interface CloudIntegrationsConfig {
|
|
13
|
-
baseUrl: string;
|
|
14
|
-
token: string;
|
|
15
|
-
}
|
|
16
|
-
|
|
17
|
-
export function getCloudIntegrationsConfig(): CloudIntegrationsConfig | null {
|
|
18
|
-
if (!isCloudMode()) return null;
|
|
19
|
-
|
|
20
|
-
const baseUrl = process.env.OPENBOT_INTEGRATIONS_BASE_URL?.trim();
|
|
21
|
-
const token = process.env.OPENBOT_INTEGRATIONS_TOKEN?.trim();
|
|
22
|
-
if (!baseUrl || !token) return null;
|
|
23
|
-
|
|
24
|
-
return { baseUrl: baseUrl.replace(/\/$/, ''), token };
|
|
25
|
-
}
|
|
9
|
+
/** Default cloud openbot plugin auth mode. */
|
|
10
|
+
export const DEFAULT_CLOUD_OPENBOT_AUTH_MODE: OpenbotAuthMode = 'credits';
|
|
26
11
|
|
|
27
12
|
export function isCloudSystemAgent(agentId: string): boolean {
|
|
28
13
|
return isCloudMode() && agentId === ORCHESTRATOR_AGENT_ID;
|
|
29
14
|
}
|
|
30
15
|
|
|
31
|
-
export function
|
|
32
|
-
return
|
|
16
|
+
export function parseOpenbotAuthMode(value: unknown): OpenbotAuthMode {
|
|
17
|
+
return value === 'byok' ? 'byok' : 'credits';
|
|
33
18
|
}
|
|
34
19
|
|
|
35
20
|
export function assertCloudSystemAgentPluginsMutable(
|
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
import fs from 'node:fs/promises';
|
|
2
|
+
import { existsSync } from 'node:fs';
|
|
3
|
+
import path from 'node:path';
|
|
4
|
+
import matter from 'gray-matter';
|
|
5
|
+
import { ORCHESTRATOR_AGENT_ID } from './agent-ids.js';
|
|
6
|
+
import { DEFAULT_SYSTEM_AGENT_MODEL, OPENBOT_PLUGIN_ID } from './openbot-plugin.js';
|
|
7
|
+
import { DEFAULT_CLOUD_OPENBOT_AUTH_MODE, isCloudMode } from './cloud-mode.js';
|
|
8
|
+
import { DEFAULT_AGENTS_DIR, getBaseDir } from './config.js';
|
|
9
|
+
import { pluginService } from '../services/plugins/service.js';
|
|
10
|
+
|
|
11
|
+
function systemAgentMdPath(): string {
|
|
12
|
+
return path.join(getBaseDir(), DEFAULT_AGENTS_DIR, ORCHESTRATOR_AGENT_ID, 'AGENT.md');
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
function defaultSystemPluginConfig(): Record<string, unknown> {
|
|
16
|
+
const config: Record<string, unknown> = {
|
|
17
|
+
model: DEFAULT_SYSTEM_AGENT_MODEL,
|
|
18
|
+
};
|
|
19
|
+
if (isCloudMode()) {
|
|
20
|
+
config.authMode = DEFAULT_CLOUD_OPENBOT_AUTH_MODE;
|
|
21
|
+
}
|
|
22
|
+
return config;
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
async function ensureOpenbotPluginInstalled(): Promise<void> {
|
|
26
|
+
if (await pluginService.isInstalled(OPENBOT_PLUGIN_ID)) {
|
|
27
|
+
return;
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
console.log(`[bootstrap] Installing ${OPENBOT_PLUGIN_ID} from npm`);
|
|
31
|
+
await pluginService.install({ packageName: OPENBOT_PLUGIN_ID });
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
async function ensureSystemAgentMaterialized(): Promise<void> {
|
|
35
|
+
const agentMdPath = systemAgentMdPath();
|
|
36
|
+
if (existsSync(agentMdPath)) {
|
|
37
|
+
return;
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
const agentDir = path.dirname(agentMdPath);
|
|
41
|
+
await fs.mkdir(agentDir, { recursive: true });
|
|
42
|
+
|
|
43
|
+
const frontmatter = {
|
|
44
|
+
name: 'OpenBot',
|
|
45
|
+
description: 'First-party orchestration agent for OpenBot.',
|
|
46
|
+
plugins: [
|
|
47
|
+
{
|
|
48
|
+
id: OPENBOT_PLUGIN_ID,
|
|
49
|
+
config: defaultSystemPluginConfig(),
|
|
50
|
+
},
|
|
51
|
+
],
|
|
52
|
+
};
|
|
53
|
+
|
|
54
|
+
const content = matter.stringify('', frontmatter);
|
|
55
|
+
await fs.writeFile(agentMdPath, content, 'utf-8');
|
|
56
|
+
console.log(`[bootstrap] Materialized system agent at ${agentMdPath}`);
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
/** Install the default agent plugin from npm and materialize the system agent on first boot. */
|
|
60
|
+
export async function ensureDefaultStack(): Promise<void> {
|
|
61
|
+
await ensureOpenbotPluginInstalled();
|
|
62
|
+
await ensureSystemAgentMaterialized();
|
|
63
|
+
}
|
package/src/app/server.ts
CHANGED
|
@@ -9,7 +9,7 @@ const require = createRequire(import.meta.url);
|
|
|
9
9
|
const pkg = require('../../package.json');
|
|
10
10
|
import { generateId } from 'melony';
|
|
11
11
|
import { getBaseDir, loadConfig } from '../app/config.js';
|
|
12
|
-
import { isCloudMode
|
|
12
|
+
import { isCloudMode } from './cloud-mode.js';
|
|
13
13
|
import { ActiveRunsSnapshotEvent, OpenBotEvent, OpenBotState } from './types.js';
|
|
14
14
|
import { processService } from '../services/process.js';
|
|
15
15
|
import { runAgent, STATE_AGENT_ID, ORCHESTRATOR_AGENT_ID } from '../harness/index.js';
|
|
@@ -48,10 +48,7 @@ export async function startServer(options: ServerOptions = {}) {
|
|
|
48
48
|
processService.syncWorkspaceVariablesToProcessEnv();
|
|
49
49
|
|
|
50
50
|
if (isCloudMode()) {
|
|
51
|
-
|
|
52
|
-
console.log(
|
|
53
|
-
`[server] Cloud mode enabled${integrations ? '' : ' (integrations proxy env not set)'}`,
|
|
54
|
-
);
|
|
51
|
+
console.log('[server] Cloud mode enabled');
|
|
55
52
|
}
|
|
56
53
|
|
|
57
54
|
const openBotDir = getBaseDir();
|
package/src/app/types.ts
CHANGED
|
@@ -9,7 +9,7 @@ import {
|
|
|
9
9
|
} from '../services/plugins/domain.js';
|
|
10
10
|
import type { PluginRef } from '../services/plugins/types.js';
|
|
11
11
|
import type { MemoryRecord } from '../plugins/memory/service.js';
|
|
12
|
-
import type { TodoList } from '../
|
|
12
|
+
import type { TodoList } from '../services/todo/types.js';
|
|
13
13
|
|
|
14
14
|
export interface OpenBotState {
|
|
15
15
|
agentId: string;
|
|
@@ -324,7 +324,7 @@ export type PatchThreadDetailsResultEvent = BaseEvent & {
|
|
|
324
324
|
type: 'action:patch_thread_details:result';
|
|
325
325
|
data: {
|
|
326
326
|
success: boolean;
|
|
327
|
-
updatedFields:
|
|
327
|
+
updatedFields: 'state'[];
|
|
328
328
|
};
|
|
329
329
|
};
|
|
330
330
|
|
|
@@ -658,12 +658,7 @@ export type UIWidgetField = {
|
|
|
658
658
|
defaultValue?: unknown;
|
|
659
659
|
};
|
|
660
660
|
|
|
661
|
-
export type UIWidgetListItemStatusVariant =
|
|
662
|
-
| 'default'
|
|
663
|
-
| 'success'
|
|
664
|
-
| 'warning'
|
|
665
|
-
| 'danger'
|
|
666
|
-
| 'info';
|
|
661
|
+
export type UIWidgetListItemStatusVariant = 'default' | 'success' | 'warning' | 'danger' | 'info';
|
|
667
662
|
|
|
668
663
|
export type UIWidgetListItem = {
|
|
669
664
|
id: string;
|
package/src/harness/index.ts
CHANGED
|
@@ -8,6 +8,7 @@ import { ToolDefinition } from '../services/plugins/types.js';
|
|
|
8
8
|
import { abortRegistry, abortKey } from '../services/abort.js';
|
|
9
9
|
import { loadConfig } from '../app/config.js';
|
|
10
10
|
import { getPublicBaseUrl } from '../plugins/storage/files.js';
|
|
11
|
+
import { createPluginHost } from '../services/plugins/host.js';
|
|
11
12
|
|
|
12
13
|
export { STATE_AGENT_ID, ORCHESTRATOR_AGENT_ID };
|
|
13
14
|
|
|
@@ -119,6 +120,8 @@ export async function runAgent(options: RunAgentOptions): Promise<void> {
|
|
|
119
120
|
|
|
120
121
|
const builder = melony<OpenBotState, OpenBotEvent>().initialState(state);
|
|
121
122
|
|
|
123
|
+
const pluginHost = createPluginHost(runAgent);
|
|
124
|
+
|
|
122
125
|
for (const ref of pluginRefs) {
|
|
123
126
|
const plugin = await resolvePlugin(ref.id);
|
|
124
127
|
if (!plugin) continue;
|
|
@@ -132,6 +135,7 @@ export async function runAgent(options: RunAgentOptions): Promise<void> {
|
|
|
132
135
|
tools,
|
|
133
136
|
publicBaseUrl,
|
|
134
137
|
abortSignal,
|
|
138
|
+
host: pluginHost,
|
|
135
139
|
}),
|
|
136
140
|
);
|
|
137
141
|
}
|
|
@@ -1,106 +1,15 @@
|
|
|
1
|
-
import z from 'zod';
|
|
2
1
|
import type { Plugin } from '../../services/plugins/types.js';
|
|
3
2
|
import { OpenBotEvent } from '../../app/types.js';
|
|
4
3
|
import { buildWorkspaceFileUrl } from './files.js';
|
|
5
4
|
|
|
6
5
|
/**
|
|
7
|
-
* `storage` —
|
|
8
|
-
*
|
|
6
|
+
* `storage` — platform infra handlers for `/api/state` and deterministic reads.
|
|
7
|
+
* Agent-facing storage tools live in `@meetopenbot/openbot`.
|
|
9
8
|
*/
|
|
10
|
-
const storageToolDefinitions = {
|
|
11
|
-
create_channel: {
|
|
12
|
-
description:
|
|
13
|
-
'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.',
|
|
14
|
-
inputSchema: z.object({
|
|
15
|
-
channelId: z
|
|
16
|
-
.string()
|
|
17
|
-
.describe('Unique channel ID (e.g. product-launch, backend-platform, channel_roadmap).'),
|
|
18
|
-
spec: z
|
|
19
|
-
.string()
|
|
20
|
-
.optional()
|
|
21
|
-
.describe('Optional initial markdown content for the channel spec.'),
|
|
22
|
-
initialState: z
|
|
23
|
-
.record(z.string(), z.unknown())
|
|
24
|
-
.optional()
|
|
25
|
-
.describe('Optional initial state object for the channel.'),
|
|
26
|
-
cwd: z
|
|
27
|
-
.string()
|
|
28
|
-
.optional()
|
|
29
|
-
.describe(
|
|
30
|
-
'Optional initial current working directory for the channel. Defaults to an absolute path under ~/openbot/{channelId}.',
|
|
31
|
-
),
|
|
32
|
-
}),
|
|
33
|
-
},
|
|
34
|
-
patch_channel_details: {
|
|
35
|
-
description: 'Patch current channel details (state, spec, cwd).',
|
|
36
|
-
inputSchema: z
|
|
37
|
-
.object({
|
|
38
|
-
state: z
|
|
39
|
-
.record(z.string(), z.unknown())
|
|
40
|
-
.optional()
|
|
41
|
-
.describe('JSON state object for the channel.'),
|
|
42
|
-
spec: z
|
|
43
|
-
.string()
|
|
44
|
-
.optional()
|
|
45
|
-
.describe(
|
|
46
|
-
'Markdown content for the channel specification (SPEC.md). Use for goals and rules.',
|
|
47
|
-
),
|
|
48
|
-
cwd: z.string().optional().describe('Current working directory for the channel.'),
|
|
49
|
-
})
|
|
50
|
-
.refine(
|
|
51
|
-
(value) =>
|
|
52
|
-
value.state !== undefined ||
|
|
53
|
-
value.spec !== undefined ||
|
|
54
|
-
value.cwd !== undefined,
|
|
55
|
-
{ message: 'Provide at least one of state, spec, or cwd.' },
|
|
56
|
-
),
|
|
57
|
-
},
|
|
58
|
-
patch_thread_details: {
|
|
59
|
-
description:
|
|
60
|
-
'Patch current thread details (state). Use for thread metadata such as `name` or `isSmartNamed`. For multi-step task tracking, use `todo_write` instead.',
|
|
61
|
-
inputSchema: z.object({
|
|
62
|
-
state: z
|
|
63
|
-
.record(z.string(), z.unknown())
|
|
64
|
-
.describe('JSON state object for the thread. Merges with existing state.'),
|
|
65
|
-
}),
|
|
66
|
-
},
|
|
67
|
-
create_variable: {
|
|
68
|
-
description: 'Create or update a variable in the workspace storage.',
|
|
69
|
-
inputSchema: z.object({
|
|
70
|
-
key: z.string().describe('The key of the variable.'),
|
|
71
|
-
value: z.string().describe('The value of the variable.'),
|
|
72
|
-
secret: z.boolean().optional().describe('Whether the variable is a secret.'),
|
|
73
|
-
}),
|
|
74
|
-
},
|
|
75
|
-
delete_variable: {
|
|
76
|
-
description: 'Delete a variable from the workspace storage.',
|
|
77
|
-
inputSchema: z.object({
|
|
78
|
-
key: z.string().describe('The key of the variable to delete.'),
|
|
79
|
-
}),
|
|
80
|
-
},
|
|
81
|
-
delete_channel: {
|
|
82
|
-
description:
|
|
83
|
-
'Permanently delete a channel and all its threads and events. Always confirm with the user before deleting.',
|
|
84
|
-
inputSchema: z.object({
|
|
85
|
-
channelId: z.string().describe('The channel ID to delete.'),
|
|
86
|
-
}),
|
|
87
|
-
},
|
|
88
|
-
get_workspace_file_url: {
|
|
89
|
-
description:
|
|
90
|
-
'Get a fetchable HTTP URL for a file in the current channel workspace (images, video, audio, documents).',
|
|
91
|
-
inputSchema: z.object({
|
|
92
|
-
path: z
|
|
93
|
-
.string()
|
|
94
|
-
.describe('Path relative to the channel working directory, e.g. "uploads/clip.mp4".'),
|
|
95
|
-
}),
|
|
96
|
-
},
|
|
97
|
-
};
|
|
98
|
-
|
|
99
9
|
export const storagePlugin: Plugin = {
|
|
100
10
|
id: 'storage',
|
|
101
11
|
name: 'Storage',
|
|
102
|
-
description: '
|
|
103
|
-
toolDefinitions: storageToolDefinitions,
|
|
12
|
+
description: 'Infrastructure storage handlers for channels, threads, agents, and files.',
|
|
104
13
|
factory: ({ storage, publicBaseUrl }) => (builder) => {
|
|
105
14
|
const resolvePublicBaseUrl = () => publicBaseUrl;
|
|
106
15
|
|
|
@@ -144,243 +53,6 @@ export const storagePlugin: Plugin = {
|
|
|
144
53
|
} as OpenBotEvent;
|
|
145
54
|
});
|
|
146
55
|
|
|
147
|
-
builder.on('action:create_channel', async function* (event, context) {
|
|
148
|
-
const { channelId, spec, initialState, cwd } = (event as any).data;
|
|
149
|
-
const rawChannelId = (channelId || '').trim();
|
|
150
|
-
const channelSpec = typeof spec === 'string' ? spec : '';
|
|
151
|
-
|
|
152
|
-
const resultMeta = { ...(event.meta || {}), agentId: context.state.agentId };
|
|
153
|
-
|
|
154
|
-
if (!rawChannelId) {
|
|
155
|
-
yield {
|
|
156
|
-
type: 'action:create_channel:result',
|
|
157
|
-
data: { success: false, channelId: '', channelUrl: '' },
|
|
158
|
-
meta: resultMeta,
|
|
159
|
-
} as OpenBotEvent;
|
|
160
|
-
return;
|
|
161
|
-
}
|
|
162
|
-
|
|
163
|
-
const channelUrl = `/channels/${rawChannelId}`;
|
|
164
|
-
|
|
165
|
-
const mergedInitial: Record<string, unknown> = { ...(initialState || {}) };
|
|
166
|
-
|
|
167
|
-
try {
|
|
168
|
-
await storage.createChannel({
|
|
169
|
-
channelId: rawChannelId,
|
|
170
|
-
spec: channelSpec,
|
|
171
|
-
initialState: mergedInitial,
|
|
172
|
-
cwd,
|
|
173
|
-
});
|
|
174
|
-
|
|
175
|
-
yield {
|
|
176
|
-
type: 'action:create_channel:result',
|
|
177
|
-
data: { success: true, channelId: rawChannelId, channelUrl },
|
|
178
|
-
meta: resultMeta,
|
|
179
|
-
} as OpenBotEvent;
|
|
180
|
-
|
|
181
|
-
yield {
|
|
182
|
-
type: 'agent:output',
|
|
183
|
-
data: { content: `Created channel \`${rawChannelId}\`.` },
|
|
184
|
-
meta: resultMeta,
|
|
185
|
-
} as OpenBotEvent;
|
|
186
|
-
} catch {
|
|
187
|
-
yield {
|
|
188
|
-
type: 'action:create_channel:result',
|
|
189
|
-
data: { success: false, channelId: rawChannelId, channelUrl },
|
|
190
|
-
meta: resultMeta,
|
|
191
|
-
} as OpenBotEvent;
|
|
192
|
-
}
|
|
193
|
-
});
|
|
194
|
-
|
|
195
|
-
builder.on('action:delete_channel', async function* (event, context) {
|
|
196
|
-
const rawChannelId = ((event.data as { channelId?: string })?.channelId || '').trim();
|
|
197
|
-
const resultMeta = { ...(event.meta || {}), agentId: context.state.agentId };
|
|
198
|
-
|
|
199
|
-
if (!rawChannelId) {
|
|
200
|
-
yield {
|
|
201
|
-
type: 'action:delete_channel:result',
|
|
202
|
-
data: { success: false, channelId: '', error: 'channelId is required' },
|
|
203
|
-
meta: resultMeta,
|
|
204
|
-
} as OpenBotEvent;
|
|
205
|
-
return;
|
|
206
|
-
}
|
|
207
|
-
|
|
208
|
-
try {
|
|
209
|
-
await storage.deleteChannel({ channelId: rawChannelId });
|
|
210
|
-
yield {
|
|
211
|
-
type: 'action:delete_channel:result',
|
|
212
|
-
data: { success: true, channelId: rawChannelId },
|
|
213
|
-
meta: resultMeta,
|
|
214
|
-
} as OpenBotEvent;
|
|
215
|
-
yield {
|
|
216
|
-
type: 'agent:output',
|
|
217
|
-
data: { content: `Deleted channel \`${rawChannelId}\`.` },
|
|
218
|
-
meta: resultMeta,
|
|
219
|
-
} as OpenBotEvent;
|
|
220
|
-
} catch (error) {
|
|
221
|
-
yield {
|
|
222
|
-
type: 'action:delete_channel:result',
|
|
223
|
-
data: {
|
|
224
|
-
success: false,
|
|
225
|
-
channelId: rawChannelId,
|
|
226
|
-
error: error instanceof Error ? error.message : 'Unknown error',
|
|
227
|
-
},
|
|
228
|
-
meta: resultMeta,
|
|
229
|
-
} as OpenBotEvent;
|
|
230
|
-
}
|
|
231
|
-
});
|
|
232
|
-
|
|
233
|
-
builder.on('action:update_channel', async function* (event, context) {
|
|
234
|
-
const data = (event.data || {}) as {
|
|
235
|
-
channelId?: string;
|
|
236
|
-
name?: string;
|
|
237
|
-
cwd?: string;
|
|
238
|
-
};
|
|
239
|
-
const targetChannelId = (data.channelId || context.state.channelId || '').trim();
|
|
240
|
-
const resultMeta = { ...(event.meta || {}), agentId: context.state.agentId };
|
|
241
|
-
|
|
242
|
-
if (!targetChannelId) {
|
|
243
|
-
yield {
|
|
244
|
-
type: 'action:update_channel:result',
|
|
245
|
-
data: { success: false, channelId: '', updatedFields: [] as string[] },
|
|
246
|
-
meta: resultMeta,
|
|
247
|
-
} as OpenBotEvent;
|
|
248
|
-
return;
|
|
249
|
-
}
|
|
250
|
-
|
|
251
|
-
const patch: Record<string, unknown> = {};
|
|
252
|
-
const updatedFields: string[] = [];
|
|
253
|
-
|
|
254
|
-
if (typeof data.name === 'string' && data.name.trim()) {
|
|
255
|
-
patch.name = data.name.trim();
|
|
256
|
-
updatedFields.push('name');
|
|
257
|
-
}
|
|
258
|
-
if (typeof data.cwd === 'string' && data.cwd.trim()) {
|
|
259
|
-
patch.cwd = data.cwd.trim();
|
|
260
|
-
updatedFields.push('cwd');
|
|
261
|
-
}
|
|
262
|
-
|
|
263
|
-
try {
|
|
264
|
-
if (updatedFields.length > 0) {
|
|
265
|
-
await storage.patchChannelState({ channelId: targetChannelId, state: patch });
|
|
266
|
-
}
|
|
267
|
-
|
|
268
|
-
if (targetChannelId === context.state.channelId) {
|
|
269
|
-
context.state.channelDetails = await storage.getChannelDetails({
|
|
270
|
-
channelId: context.state.channelId,
|
|
271
|
-
});
|
|
272
|
-
}
|
|
273
|
-
|
|
274
|
-
yield {
|
|
275
|
-
type: 'action:update_channel:result',
|
|
276
|
-
data: { success: true, channelId: targetChannelId, updatedFields },
|
|
277
|
-
meta: resultMeta,
|
|
278
|
-
} as OpenBotEvent;
|
|
279
|
-
} catch {
|
|
280
|
-
yield {
|
|
281
|
-
type: 'action:update_channel:result',
|
|
282
|
-
data: { success: false, channelId: targetChannelId, updatedFields },
|
|
283
|
-
meta: resultMeta,
|
|
284
|
-
} as OpenBotEvent;
|
|
285
|
-
}
|
|
286
|
-
});
|
|
287
|
-
|
|
288
|
-
builder.on('action:patch_channel_details', async function* (event, context) {
|
|
289
|
-
const updatedFields: ('state' | 'spec' | 'cwd')[] = [];
|
|
290
|
-
const resultMeta = { ...(event.meta || {}), agentId: context.state.agentId };
|
|
291
|
-
const data = (event.data || {}) as {
|
|
292
|
-
state?: Record<string, unknown>;
|
|
293
|
-
spec?: string;
|
|
294
|
-
cwd?: string;
|
|
295
|
-
};
|
|
296
|
-
try {
|
|
297
|
-
if (data.state !== undefined) {
|
|
298
|
-
await storage.patchChannelState({
|
|
299
|
-
channelId: context.state.channelId,
|
|
300
|
-
state: data.state,
|
|
301
|
-
});
|
|
302
|
-
updatedFields.push('state');
|
|
303
|
-
}
|
|
304
|
-
if (typeof data.spec === 'string') {
|
|
305
|
-
await storage.patchChannelSpec({
|
|
306
|
-
channelId: context.state.channelId,
|
|
307
|
-
spec: data.spec,
|
|
308
|
-
});
|
|
309
|
-
updatedFields.push('spec');
|
|
310
|
-
}
|
|
311
|
-
if (typeof data.cwd === 'string') {
|
|
312
|
-
await storage.patchChannelState({
|
|
313
|
-
channelId: context.state.channelId,
|
|
314
|
-
state: { cwd: data.cwd },
|
|
315
|
-
});
|
|
316
|
-
updatedFields.push('cwd');
|
|
317
|
-
}
|
|
318
|
-
|
|
319
|
-
context.state.channelDetails = await storage.getChannelDetails({
|
|
320
|
-
channelId: context.state.channelId,
|
|
321
|
-
});
|
|
322
|
-
|
|
323
|
-
yield {
|
|
324
|
-
type: "client:ui:widget",
|
|
325
|
-
data: {
|
|
326
|
-
widgetId: "patch-channel-details-result" + Date.now(),
|
|
327
|
-
kind: "message",
|
|
328
|
-
title: "Channel details updated.",
|
|
329
|
-
body: `The channel details have been updated. ${updatedFields.join(', ')}`,
|
|
330
|
-
display: "collapsed",
|
|
331
|
-
},
|
|
332
|
-
meta: resultMeta,
|
|
333
|
-
};
|
|
334
|
-
|
|
335
|
-
yield {
|
|
336
|
-
type: 'action:patch_channel_details:result',
|
|
337
|
-
data: { success: true, updatedFields },
|
|
338
|
-
meta: resultMeta,
|
|
339
|
-
};
|
|
340
|
-
} catch {
|
|
341
|
-
yield {
|
|
342
|
-
type: 'action:patch_channel_details:result',
|
|
343
|
-
data: { success: false, updatedFields },
|
|
344
|
-
meta: resultMeta,
|
|
345
|
-
};
|
|
346
|
-
}
|
|
347
|
-
});
|
|
348
|
-
|
|
349
|
-
builder.on('action:patch_thread_details', async function* (event, context) {
|
|
350
|
-
const updatedFields: ('state')[] = [];
|
|
351
|
-
const resultMeta = { ...(event.meta || {}), agentId: context.state.agentId };
|
|
352
|
-
try {
|
|
353
|
-
if (!context.state.threadId) {
|
|
354
|
-
throw new Error('Missing threadId in state for patch_thread_details');
|
|
355
|
-
}
|
|
356
|
-
if ((event.data as any).state !== undefined) {
|
|
357
|
-
await storage.patchThreadState({
|
|
358
|
-
channelId: context.state.channelId,
|
|
359
|
-
threadId: context.state.threadId,
|
|
360
|
-
state: (event.data as any).state,
|
|
361
|
-
});
|
|
362
|
-
updatedFields.push('state');
|
|
363
|
-
}
|
|
364
|
-
|
|
365
|
-
context.state.threadDetails = await storage.getThreadDetails({
|
|
366
|
-
channelId: context.state.channelId,
|
|
367
|
-
threadId: context.state.threadId,
|
|
368
|
-
});
|
|
369
|
-
|
|
370
|
-
yield {
|
|
371
|
-
type: 'action:patch_thread_details:result',
|
|
372
|
-
data: { success: true, updatedFields },
|
|
373
|
-
meta: resultMeta,
|
|
374
|
-
};
|
|
375
|
-
} catch {
|
|
376
|
-
yield {
|
|
377
|
-
type: 'action:patch_thread_details:result',
|
|
378
|
-
data: { success: false, updatedFields },
|
|
379
|
-
meta: resultMeta,
|
|
380
|
-
};
|
|
381
|
-
}
|
|
382
|
-
});
|
|
383
|
-
|
|
384
56
|
builder.on('agent:usage', async function* (event, context) {
|
|
385
57
|
const { usage } = event.data;
|
|
386
58
|
if (!context.state.threadId) return;
|
|
@@ -735,43 +407,6 @@ export const storagePlugin: Plugin = {
|
|
|
735
407
|
};
|
|
736
408
|
}
|
|
737
409
|
});
|
|
738
|
-
|
|
739
|
-
builder.on('action:get_workspace_file_url', async function* (event, context) {
|
|
740
|
-
const channelId = context.state.channelId;
|
|
741
|
-
const filePath = (event.data as { path?: string })?.path;
|
|
742
|
-
const toolCallId = event.meta?.toolCallId;
|
|
743
|
-
|
|
744
|
-
if (!filePath) {
|
|
745
|
-
yield {
|
|
746
|
-
type: 'action:get_workspace_file_url:result',
|
|
747
|
-
data: { success: false, path: '', error: 'Path is required', output: 'Path is required' },
|
|
748
|
-
meta: { ...(event.meta || {}), toolCallId },
|
|
749
|
-
};
|
|
750
|
-
return;
|
|
751
|
-
}
|
|
752
|
-
|
|
753
|
-
try {
|
|
754
|
-
const { size, mimeType } = await storage.getChannelFileStat({ channelId, path: filePath });
|
|
755
|
-
const url = buildWorkspaceFileUrl({
|
|
756
|
-
baseUrl: resolvePublicBaseUrl(),
|
|
757
|
-
channelId,
|
|
758
|
-
filePath,
|
|
759
|
-
});
|
|
760
|
-
const output = JSON.stringify({ path: filePath, url, mimeType, size });
|
|
761
|
-
yield {
|
|
762
|
-
type: 'action:get_workspace_file_url:result',
|
|
763
|
-
data: { success: true, path: filePath, url, mimeType, size, output },
|
|
764
|
-
meta: { ...(event.meta || {}), toolCallId },
|
|
765
|
-
};
|
|
766
|
-
} catch (error) {
|
|
767
|
-
const message = error instanceof Error ? error.message : 'Unknown error';
|
|
768
|
-
yield {
|
|
769
|
-
type: 'action:get_workspace_file_url:result',
|
|
770
|
-
data: { success: false, path: filePath, error: message, output: message },
|
|
771
|
-
meta: { ...(event.meta || {}), toolCallId },
|
|
772
|
-
};
|
|
773
|
-
}
|
|
774
|
-
});
|
|
775
410
|
},
|
|
776
411
|
};
|
|
777
412
|
|