openbot 0.2.14 → 0.3.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/agents/openbot/index.js +76 -0
- package/dist/agents/openbot/middleware/approval.js +132 -0
- package/dist/agents/openbot/runtime.js +289 -0
- package/dist/agents/openbot/system-prompt.js +32 -0
- package/dist/agents/openbot/tools/delegation.js +78 -0
- package/dist/agents/openbot/tools/mcp.js +99 -0
- package/dist/agents/openbot/tools/shell.js +91 -0
- package/dist/agents/openbot/tools/storage.js +75 -0
- package/dist/agents/openbot/tools/ui.js +176 -0
- package/dist/agents/system.js +20 -93
- package/dist/app/cli.js +0 -0
- package/dist/app/config.js +4 -1
- package/dist/app/server.js +15 -8
- package/dist/bus/agent-package.js +1 -0
- package/dist/bus/plugin.js +1 -0
- package/dist/bus/services.js +600 -0
- package/dist/bus/types.js +1 -0
- package/dist/harness/context.js +131 -0
- package/dist/harness/event-normalizer.js +59 -0
- package/dist/harness/orchestrator.js +27 -227
- package/dist/harness/process.js +25 -3
- package/dist/harness/queue-processor.js +227 -0
- package/dist/harness/runtime-factory.js +103 -0
- package/dist/plugins/ai-sdk/index.js +37 -0
- package/dist/plugins/ai-sdk/runtime.js +330 -0
- package/dist/plugins/ai-sdk/system-prompt.js +3 -0
- package/dist/plugins/ai-sdk.js +277 -87
- package/dist/plugins/approval/index.js +159 -0
- package/dist/plugins/approval.js +163 -0
- package/dist/plugins/delegation/index.js +79 -0
- package/dist/plugins/delegation.js +67 -11
- package/dist/plugins/mcp/index.js +108 -0
- package/dist/plugins/shell/index.js +99 -0
- package/dist/plugins/shell.js +123 -0
- package/dist/plugins/storage-tools/index.js +85 -0
- package/dist/plugins/storage.js +240 -5
- package/dist/plugins/ui/index.js +184 -0
- package/dist/plugins/ui.js +185 -21
- package/dist/registry/agents.js +138 -0
- package/dist/registry/plugins.js +91 -50
- package/dist/services/agent-packages.js +103 -0
- package/dist/services/plugins.js +98 -0
- package/dist/services/storage.js +360 -94
- package/docs/agents.md +39 -66
- package/docs/architecture.md +1 -1
- package/docs/plugins.md +70 -58
- package/docs/templates/AGENT.example.md +57 -0
- package/package.json +8 -7
- package/src/app/cli.ts +1 -1
- package/src/app/config.ts +14 -4
- package/src/app/server.ts +23 -10
- package/src/app/types.ts +385 -16
- package/src/assets/icon.svg +4 -1
- package/src/bus/plugin.ts +67 -0
- package/src/bus/services.ts +666 -0
- package/src/bus/types.ts +147 -0
- package/src/harness/context.ts +160 -0
- package/src/harness/event-normalizer.ts +82 -0
- package/src/harness/orchestrator.ts +35 -273
- package/src/harness/process.ts +28 -4
- package/src/harness/queue-processor.ts +309 -0
- package/src/harness/runtime-factory.ts +125 -0
- package/src/plugins/ai-sdk/index.ts +44 -0
- package/src/plugins/ai-sdk/runtime.ts +410 -0
- package/src/plugins/ai-sdk/system-prompt.ts +4 -0
- package/src/plugins/approval/index.ts +228 -0
- package/src/plugins/delegation/index.ts +94 -0
- package/src/plugins/mcp/index.ts +128 -0
- package/src/plugins/shell/index.ts +123 -0
- package/src/plugins/storage-tools/index.ts +101 -0
- package/src/plugins/ui/index.ts +227 -0
- package/src/registry/plugins.ts +106 -55
- package/src/services/plugins.ts +133 -0
- package/src/services/storage.ts +465 -137
- package/src/agents/system.ts +0 -112
- package/src/plugins/ai-sdk.ts +0 -197
- package/src/plugins/delegation.ts +0 -60
- package/src/plugins/mcp.ts +0 -154
- package/src/plugins/storage.ts +0 -725
- package/src/plugins/ui.ts +0 -57
package/src/agents/system.ts
DELETED
|
@@ -1,112 +0,0 @@
|
|
|
1
|
-
import { AgentDetails } from '../plugins/storage.js';
|
|
2
|
-
import { delegationToolDefinitions } from '../plugins/delegation.js';
|
|
3
|
-
import { storageToolDefinitions } from '../plugins/storage.js';
|
|
4
|
-
import { mcpToolDefinitions } from '../plugins/mcp.js';
|
|
5
|
-
import { uiToolDefinitions } from '../plugins/ui.js';
|
|
6
|
-
import { storageService } from '../services/storage.js';
|
|
7
|
-
import { readFileSync } from 'node:fs';
|
|
8
|
-
|
|
9
|
-
const SYSTEM_ICON_DATA_URL = (() => {
|
|
10
|
-
try {
|
|
11
|
-
const svg = readFileSync(new URL('../assets/icon.svg', import.meta.url), 'utf-8').trim();
|
|
12
|
-
if (!svg.startsWith('<svg')) return undefined;
|
|
13
|
-
return `data:image/svg+xml;base64,${Buffer.from(svg, 'utf-8').toString('base64')}`;
|
|
14
|
-
} catch {
|
|
15
|
-
return undefined;
|
|
16
|
-
}
|
|
17
|
-
})();
|
|
18
|
-
|
|
19
|
-
export const getSystemAgentDetails = (overrides?: Partial<AgentDetails>): AgentDetails => {
|
|
20
|
-
const defaults: AgentDetails = {
|
|
21
|
-
id: 'system',
|
|
22
|
-
name: 'Lolly',
|
|
23
|
-
image: SYSTEM_ICON_DATA_URL,
|
|
24
|
-
instructions:
|
|
25
|
-
'You are OpenBot, the primary AI assistant and orchestrator of this workspace. Your goal is to help users onboard, answer questions about the system, and suggest specialized agents for specific tasks.\n\n' +
|
|
26
|
-
'### How to use OpenBot:\n' +
|
|
27
|
-
'1. **General Chat**: Just type your message here, and I will help you.\n' +
|
|
28
|
-
'2. **Specialized Agents**: You can delegate tasks to specialized agents for specific tasks. For example, use the `delegate` tool to invoke the `os` agent for terminal commands and file operations.\n' +
|
|
29
|
-
'3. **Channels**: Channels are shared spaces where multiple agents can participate. You can create new channels for different topics.\n' +
|
|
30
|
-
'4. **Local-First**: OpenBot runs entirely on your machine. Your data stays private and local.\n\n' +
|
|
31
|
-
'### Workflow Guidelines:\n' +
|
|
32
|
-
'- **Todo Schema**: Keep todo items simple. Each item should have a short `id`, a clear `task` description, and a `status` (e.g., "pending", "in_progress", "done").\n' +
|
|
33
|
-
'- **Interactive Widgets**: Use `render_ui_widget` to give the user a visual progress bar (`kind: "todo_list"`), request permissions (`kind: "approval"`), or gather structured data (`kind: "form"`).\n' +
|
|
34
|
-
'- **Delegation**: When delegating to another agent, reference the relevant Task ID from the thread state. Update the task status (e.g., using `patch_thread_details`) as progress is made.\n\n' +
|
|
35
|
-
'If you need to know what agents or plugins are installed, I can help you find that information.',
|
|
36
|
-
runtime: {
|
|
37
|
-
name: 'ai-sdk',
|
|
38
|
-
config: {
|
|
39
|
-
model: 'openai/gpt-4o-mini',
|
|
40
|
-
toolDefinitions: {
|
|
41
|
-
...delegationToolDefinitions,
|
|
42
|
-
...storageToolDefinitions,
|
|
43
|
-
...mcpToolDefinitions,
|
|
44
|
-
...uiToolDefinitions,
|
|
45
|
-
},
|
|
46
|
-
},
|
|
47
|
-
},
|
|
48
|
-
plugins: [
|
|
49
|
-
{ name: 'storage', config: { storage: storageService } },
|
|
50
|
-
{ name: 'delegation', config: {} },
|
|
51
|
-
{ name: 'mcp', config: {} },
|
|
52
|
-
{ name: 'ui', config: {} },
|
|
53
|
-
],
|
|
54
|
-
description: 'System coordinator agent',
|
|
55
|
-
createdAt: new Date(),
|
|
56
|
-
updatedAt: new Date(),
|
|
57
|
-
};
|
|
58
|
-
|
|
59
|
-
if (!overrides) return defaults;
|
|
60
|
-
|
|
61
|
-
// Merge logic:
|
|
62
|
-
// - Simple fields: override if present
|
|
63
|
-
// - Runtime: merge config/model, but preserve toolDefinitions unless explicitly overridden
|
|
64
|
-
// - Plugins: merge by name (user plugins override defaults)
|
|
65
|
-
|
|
66
|
-
const mergedRuntime = {
|
|
67
|
-
...(typeof defaults.runtime === 'object' ? defaults.runtime : {}),
|
|
68
|
-
...(typeof overrides.runtime === 'object' ? overrides.runtime : {}),
|
|
69
|
-
name:
|
|
70
|
-
(typeof overrides.runtime === 'object' ? overrides.runtime.name : overrides.runtime) ||
|
|
71
|
-
(typeof defaults.runtime === 'object' ? defaults.runtime.name : defaults.runtime) ||
|
|
72
|
-
'ai-sdk',
|
|
73
|
-
config: {
|
|
74
|
-
...(defaults.runtime && typeof defaults.runtime !== 'string' ? defaults.runtime.config : {}),
|
|
75
|
-
...(overrides.runtime && typeof overrides.runtime !== 'string' ? overrides.runtime.config : {}),
|
|
76
|
-
toolDefinitions: {
|
|
77
|
-
...(defaults.runtime && typeof defaults.runtime !== 'string'
|
|
78
|
-
? (defaults.runtime.config as any)?.toolDefinitions
|
|
79
|
-
: {}),
|
|
80
|
-
...(overrides.runtime && typeof overrides.runtime !== 'string'
|
|
81
|
-
? (overrides.runtime.config as any)?.toolDefinitions
|
|
82
|
-
: {}),
|
|
83
|
-
},
|
|
84
|
-
},
|
|
85
|
-
};
|
|
86
|
-
|
|
87
|
-
const mergedPlugins = [...(defaults.plugins || [])];
|
|
88
|
-
if (overrides.plugins) {
|
|
89
|
-
for (const p of overrides.plugins) {
|
|
90
|
-
const name = typeof p === 'string' ? p : p.name;
|
|
91
|
-
const index = mergedPlugins.findIndex((existing) => {
|
|
92
|
-
const existingName = typeof existing === 'string' ? existing : existing.name;
|
|
93
|
-
return existingName === name;
|
|
94
|
-
});
|
|
95
|
-
if (index !== -1) {
|
|
96
|
-
mergedPlugins[index] = p;
|
|
97
|
-
} else {
|
|
98
|
-
mergedPlugins.push(p);
|
|
99
|
-
}
|
|
100
|
-
}
|
|
101
|
-
}
|
|
102
|
-
|
|
103
|
-
return {
|
|
104
|
-
...defaults,
|
|
105
|
-
...overrides,
|
|
106
|
-
id: 'system', // Always enforce 'system' ID
|
|
107
|
-
image: overrides.image || defaults.image, // Ensure image is preserved if not explicitly overridden
|
|
108
|
-
runtime: mergedRuntime as any,
|
|
109
|
-
plugins: mergedPlugins,
|
|
110
|
-
updatedAt: new Date(),
|
|
111
|
-
};
|
|
112
|
-
};
|
package/src/plugins/ai-sdk.ts
DELETED
|
@@ -1,197 +0,0 @@
|
|
|
1
|
-
import { MelonyPlugin, RuntimeContext } from 'melony';
|
|
2
|
-
import { generateText, ModelMessage, type LanguageModel } from 'ai';
|
|
3
|
-
import { openai } from '@ai-sdk/openai';
|
|
4
|
-
import { anthropic } from '@ai-sdk/anthropic';
|
|
5
|
-
import { z } from 'zod';
|
|
6
|
-
import { OpenBotEvent, OpenBotState, ShortTermMessage } from '../app/types.js';
|
|
7
|
-
import { Storage } from './storage.js';
|
|
8
|
-
|
|
9
|
-
export interface AISDKPluginOptions {
|
|
10
|
-
/**
|
|
11
|
-
* Provider model as a standardized string (e.g. `openai/gpt-4o-mini`, `anthropic/claude-3-5-sonnet-20240620`).
|
|
12
|
-
* Default: `openai/gpt-4o-mini`
|
|
13
|
-
*/
|
|
14
|
-
model?: string;
|
|
15
|
-
system?: string | ((context: RuntimeContext) => string | Promise<string>);
|
|
16
|
-
storage?: Storage;
|
|
17
|
-
toolDefinitions?: Record<
|
|
18
|
-
string,
|
|
19
|
-
{
|
|
20
|
-
description: string;
|
|
21
|
-
inputSchema: z.ZodType<any>;
|
|
22
|
-
}
|
|
23
|
-
>;
|
|
24
|
-
}
|
|
25
|
-
|
|
26
|
-
/**
|
|
27
|
-
* Resolves a standardized model string to an AI SDK LanguageModel.
|
|
28
|
-
*/
|
|
29
|
-
function resolveModel(modelString: string): LanguageModel {
|
|
30
|
-
const [provider, ...rest] = modelString.split('/');
|
|
31
|
-
const modelId = rest.join('/');
|
|
32
|
-
|
|
33
|
-
if (!modelId) {
|
|
34
|
-
throw new Error(`Invalid model string: "${modelString}". Expected format: "provider/model-id"`);
|
|
35
|
-
}
|
|
36
|
-
|
|
37
|
-
switch (provider) {
|
|
38
|
-
case 'openai':
|
|
39
|
-
return openai(modelId);
|
|
40
|
-
case 'anthropic':
|
|
41
|
-
return anthropic(modelId);
|
|
42
|
-
default:
|
|
43
|
-
throw new Error(`Unsupported AI provider: "${provider}"`);
|
|
44
|
-
}
|
|
45
|
-
}
|
|
46
|
-
|
|
47
|
-
async function buildSystemPrompt(
|
|
48
|
-
state: OpenBotState,
|
|
49
|
-
system?: string | ((context: RuntimeContext) => string | Promise<string>),
|
|
50
|
-
context?: RuntimeContext,
|
|
51
|
-
storage?: Storage,
|
|
52
|
-
): Promise<string> {
|
|
53
|
-
const sections: string[] = [];
|
|
54
|
-
|
|
55
|
-
if (state.agentDetails) {
|
|
56
|
-
sections.push(`## AGENT NAME\n${state.agentDetails.name}`);
|
|
57
|
-
sections.push(`## AGENT SPECIFICATION\n${state.agentDetails.instructions}`);
|
|
58
|
-
}
|
|
59
|
-
|
|
60
|
-
if (state.channelDetails) {
|
|
61
|
-
sections.push(`## CHANNEL NAME\n${state.channelDetails.name}`);
|
|
62
|
-
sections.push(`## CHANNEL SPECIFICATION\n${state.channelDetails.spec}`);
|
|
63
|
-
// sections.push(`## CHANNEL STATE\n${JSON.stringify(state.channelDetails.state, null, 2)}`);
|
|
64
|
-
|
|
65
|
-
if (storage) {
|
|
66
|
-
try {
|
|
67
|
-
const channelEvents = await storage.getEvents({ channelId: state.channelId });
|
|
68
|
-
if (channelEvents.length > 0) {
|
|
69
|
-
const formattedEvents = channelEvents
|
|
70
|
-
.slice(-20)
|
|
71
|
-
.map((e) => `- ${e.type}: ${JSON.stringify((e as any).data || {})}`)
|
|
72
|
-
.join('\n');
|
|
73
|
-
sections.push(`## CHANNEL RECENT ACTIVITIES (events)\n${formattedEvents}`);
|
|
74
|
-
}
|
|
75
|
-
} catch (error) {
|
|
76
|
-
console.warn(`[ai-sdk] Failed to fetch channel events for ${state.channelId}`, error);
|
|
77
|
-
}
|
|
78
|
-
}
|
|
79
|
-
}
|
|
80
|
-
|
|
81
|
-
if (state.threadDetails) {
|
|
82
|
-
sections.push(`## THREAD NAME\n${state.threadDetails.name}`);
|
|
83
|
-
sections.push(`## THREAD SPECIFICATION\n${state.threadDetails.spec}`);
|
|
84
|
-
// sections.push(`## THREAD STATE\n${JSON.stringify(state.threadDetails.state, null, 2)}`);
|
|
85
|
-
|
|
86
|
-
if (storage && state.threadId) {
|
|
87
|
-
try {
|
|
88
|
-
const threadEvents = await storage.getEvents({
|
|
89
|
-
channelId: state.channelId,
|
|
90
|
-
threadId: state.threadId,
|
|
91
|
-
});
|
|
92
|
-
if (threadEvents.length > 0) {
|
|
93
|
-
const formattedEvents = threadEvents
|
|
94
|
-
.slice(-20)
|
|
95
|
-
.map((e) => `- ${e.type}: ${JSON.stringify((e as any).data || {})}`)
|
|
96
|
-
.join('\n');
|
|
97
|
-
sections.push(`## THREAD RECENT ACTIVITIES (events)\n${formattedEvents}`);
|
|
98
|
-
}
|
|
99
|
-
} catch (error) {
|
|
100
|
-
console.warn(
|
|
101
|
-
`[ai-sdk] Failed to fetch thread events for channel ${state.channelId} thread ${state.threadId}`,
|
|
102
|
-
error,
|
|
103
|
-
);
|
|
104
|
-
}
|
|
105
|
-
}
|
|
106
|
-
}
|
|
107
|
-
|
|
108
|
-
if (system && typeof system === 'string') {
|
|
109
|
-
sections.push(`## SYSTEM INSTRUCTIONS\n${system}`);
|
|
110
|
-
}
|
|
111
|
-
|
|
112
|
-
if (system && typeof system === 'function' && context) {
|
|
113
|
-
sections.push(await system(context));
|
|
114
|
-
}
|
|
115
|
-
|
|
116
|
-
return sections.join('\n\n');
|
|
117
|
-
}
|
|
118
|
-
|
|
119
|
-
/**
|
|
120
|
-
* AI SDK Plugin for Melony.
|
|
121
|
-
* Automatically handles text events and routes them through an AI SDK using Vercel AI SDK.
|
|
122
|
-
* It can also automatically trigger events based on tool calls.
|
|
123
|
-
*/
|
|
124
|
-
export const aiSdkPlugin =
|
|
125
|
-
(options: AISDKPluginOptions): MelonyPlugin<OpenBotState, OpenBotEvent> =>
|
|
126
|
-
(builder) => {
|
|
127
|
-
const {
|
|
128
|
-
model: modelString = 'openai/gpt-4o-mini',
|
|
129
|
-
system,
|
|
130
|
-
storage,
|
|
131
|
-
toolDefinitions = {},
|
|
132
|
-
} = options;
|
|
133
|
-
|
|
134
|
-
const model = resolveModel(modelString);
|
|
135
|
-
|
|
136
|
-
builder.on('agent:invoke', async function* (event, context) {
|
|
137
|
-
// extract threadId if model decides to reply in a thread
|
|
138
|
-
const threadId = event.meta?.threadId || context.state.threadId;
|
|
139
|
-
const systemPrompt = await buildSystemPrompt(context.state, system, context, storage);
|
|
140
|
-
|
|
141
|
-
context.state.shortTermMessages = [
|
|
142
|
-
...(context.state.shortTermMessages ?? []),
|
|
143
|
-
{
|
|
144
|
-
role: event.data?.role || 'user',
|
|
145
|
-
content: (event as any)?.data?.content || '',
|
|
146
|
-
},
|
|
147
|
-
];
|
|
148
|
-
|
|
149
|
-
const result = await generateText({
|
|
150
|
-
model,
|
|
151
|
-
system: systemPrompt,
|
|
152
|
-
messages: context.state.shortTermMessages,
|
|
153
|
-
tools: toolDefinitions,
|
|
154
|
-
});
|
|
155
|
-
|
|
156
|
-
const toolCalls = result.toolCalls ?? [];
|
|
157
|
-
|
|
158
|
-
if (toolCalls.length > 0) {
|
|
159
|
-
for (const toolCall of toolCalls) {
|
|
160
|
-
const toolEvent = {
|
|
161
|
-
type: `action:${toolCall.toolName}` as OpenBotEvent['type'],
|
|
162
|
-
data: toolCall.input,
|
|
163
|
-
meta: {
|
|
164
|
-
toolCallId: toolCall.toolCallId,
|
|
165
|
-
agentId: context.state.agentId,
|
|
166
|
-
threadId,
|
|
167
|
-
},
|
|
168
|
-
} as unknown as OpenBotEvent;
|
|
169
|
-
yield toolEvent;
|
|
170
|
-
}
|
|
171
|
-
}
|
|
172
|
-
|
|
173
|
-
if (result.text) {
|
|
174
|
-
context.state.shortTermMessages = [
|
|
175
|
-
...(context.state.shortTermMessages ?? []),
|
|
176
|
-
{ role: 'assistant', content: result.text },
|
|
177
|
-
];
|
|
178
|
-
|
|
179
|
-
yield {
|
|
180
|
-
type: 'agent:output',
|
|
181
|
-
data: {
|
|
182
|
-
content: result.text,
|
|
183
|
-
},
|
|
184
|
-
meta: {
|
|
185
|
-
agentId: context.state.agentId,
|
|
186
|
-
},
|
|
187
|
-
};
|
|
188
|
-
}
|
|
189
|
-
});
|
|
190
|
-
};
|
|
191
|
-
|
|
192
|
-
export const plugin = {
|
|
193
|
-
name: 'ai-sdk',
|
|
194
|
-
description: 'Built-in AI SDK plugin',
|
|
195
|
-
kind: 'runtime' as const,
|
|
196
|
-
factory: aiSdkPlugin,
|
|
197
|
-
};
|
|
@@ -1,60 +0,0 @@
|
|
|
1
|
-
import { MelonyPlugin } from 'melony';
|
|
2
|
-
import { OpenBotEvent, OpenBotState } from '../app/types.js';
|
|
3
|
-
import z from 'zod';
|
|
4
|
-
|
|
5
|
-
/**
|
|
6
|
-
* Delegation Plugin for Melony.
|
|
7
|
-
* Automatically handles delegation events and routes them through the storage service.
|
|
8
|
-
*/
|
|
9
|
-
export const delegationPlugin = (): MelonyPlugin<OpenBotState, OpenBotEvent> => (builder) => {
|
|
10
|
-
builder.on('action:delegate', async function* (event, context) {
|
|
11
|
-
const { agentId, content } = event.data;
|
|
12
|
-
|
|
13
|
-
// 1. Show the delegation in the UI
|
|
14
|
-
yield {
|
|
15
|
-
type: 'agent:output',
|
|
16
|
-
data: {
|
|
17
|
-
content: `Delegating to **${agentId}**: ${content}`,
|
|
18
|
-
},
|
|
19
|
-
meta: {
|
|
20
|
-
...(event.meta || {}),
|
|
21
|
-
agentId: context.state.agentId,
|
|
22
|
-
},
|
|
23
|
-
};
|
|
24
|
-
|
|
25
|
-
// 2. Trigger the linear execution loop in orchestratorService
|
|
26
|
-
yield {
|
|
27
|
-
type: 'agent:invoke',
|
|
28
|
-
data: {
|
|
29
|
-
agentId,
|
|
30
|
-
content,
|
|
31
|
-
},
|
|
32
|
-
meta: {
|
|
33
|
-
...(event.meta || {}),
|
|
34
|
-
agentId: context.state.agentId,
|
|
35
|
-
},
|
|
36
|
-
};
|
|
37
|
-
});
|
|
38
|
-
};
|
|
39
|
-
|
|
40
|
-
export const delegationToolDefinitions = {
|
|
41
|
-
delegate: {
|
|
42
|
-
description:
|
|
43
|
-
'Delegate a task to another agent. The agent will run independently and feed results back to you. Call at most once per step.',
|
|
44
|
-
inputSchema: z.object({
|
|
45
|
-
agentId: z.string().describe('The ID of the agent (e.g. "os", "browser", "tavily").'),
|
|
46
|
-
content: z.string().describe('The message or task for the agent.'),
|
|
47
|
-
}),
|
|
48
|
-
},
|
|
49
|
-
};
|
|
50
|
-
|
|
51
|
-
export const plugin = {
|
|
52
|
-
name: 'delegation',
|
|
53
|
-
description: 'Delegation plugin',
|
|
54
|
-
version: '1.0.0',
|
|
55
|
-
author: 'OpenBot',
|
|
56
|
-
license: 'MIT',
|
|
57
|
-
website: 'https://openbot.one',
|
|
58
|
-
factory: delegationPlugin,
|
|
59
|
-
toolDefinitions: delegationToolDefinitions,
|
|
60
|
-
};
|
package/src/plugins/mcp.ts
DELETED
|
@@ -1,154 +0,0 @@
|
|
|
1
|
-
import { MelonyPlugin } from 'melony';
|
|
2
|
-
import z from 'zod';
|
|
3
|
-
import { OpenBotEvent, OpenBotState } from '../app/types.js';
|
|
4
|
-
import { mcpService } from '../harness/mcp.js';
|
|
5
|
-
|
|
6
|
-
function stringifyResult(value: unknown): string {
|
|
7
|
-
if (typeof value === 'string') {
|
|
8
|
-
return value;
|
|
9
|
-
}
|
|
10
|
-
|
|
11
|
-
try {
|
|
12
|
-
return JSON.stringify(value, null, 2);
|
|
13
|
-
} catch {
|
|
14
|
-
return String(value);
|
|
15
|
-
}
|
|
16
|
-
}
|
|
17
|
-
|
|
18
|
-
export const mcpToolDefinitions = {
|
|
19
|
-
mcp_list_tools: {
|
|
20
|
-
description:
|
|
21
|
-
'List available tools from a configured MCP server. Use this first before calling tools on an unknown server.',
|
|
22
|
-
inputSchema: z.object({
|
|
23
|
-
serverId: z.string().describe('Configured MCP server id (for example: github, notion, linear).'),
|
|
24
|
-
}),
|
|
25
|
-
},
|
|
26
|
-
mcp_call: {
|
|
27
|
-
description:
|
|
28
|
-
'Call a tool on a configured MCP server. Provide tool arguments as a JSON object. Use mcp_list_tools first when uncertain.',
|
|
29
|
-
inputSchema: z.object({
|
|
30
|
-
serverId: z.string().describe('Configured MCP server id.'),
|
|
31
|
-
toolName: z.string().describe('Exact MCP tool name from mcp_list_tools.'),
|
|
32
|
-
args: z.record(z.string(), z.unknown()).default({}).describe('Tool arguments as a JSON object.'),
|
|
33
|
-
}),
|
|
34
|
-
},
|
|
35
|
-
};
|
|
36
|
-
|
|
37
|
-
export const mcpPlugin = (): MelonyPlugin<OpenBotState, OpenBotEvent> => (builder) => {
|
|
38
|
-
builder.on('action:mcp_list_tools', async function* (event, context) {
|
|
39
|
-
const serverId = (event.data as any)?.serverId as string;
|
|
40
|
-
|
|
41
|
-
try {
|
|
42
|
-
const tools = await mcpService.listTools(serverId);
|
|
43
|
-
const toolNames = tools.map((tool) => `- ${tool.name}${tool.description ? `: ${tool.description}` : ''}`);
|
|
44
|
-
|
|
45
|
-
yield {
|
|
46
|
-
type: 'action:mcp_list_tools:result',
|
|
47
|
-
data: {
|
|
48
|
-
success: true,
|
|
49
|
-
serverId,
|
|
50
|
-
tools,
|
|
51
|
-
},
|
|
52
|
-
meta: event.meta,
|
|
53
|
-
} as any;
|
|
54
|
-
|
|
55
|
-
yield {
|
|
56
|
-
type: 'agent:output',
|
|
57
|
-
data: {
|
|
58
|
-
content:
|
|
59
|
-
toolNames.length > 0
|
|
60
|
-
? `MCP tools available on \`${serverId}\`:\n${toolNames.join('\n')}`
|
|
61
|
-
: `MCP server \`${serverId}\` has no tools.`,
|
|
62
|
-
},
|
|
63
|
-
meta: {
|
|
64
|
-
...(event.meta || {}),
|
|
65
|
-
agentId: context.state.agentId,
|
|
66
|
-
},
|
|
67
|
-
} as any;
|
|
68
|
-
} catch (error) {
|
|
69
|
-
const message = error instanceof Error ? error.message : 'Unknown MCP error';
|
|
70
|
-
yield {
|
|
71
|
-
type: 'action:mcp_list_tools:result',
|
|
72
|
-
data: {
|
|
73
|
-
success: false,
|
|
74
|
-
serverId,
|
|
75
|
-
tools: [],
|
|
76
|
-
error: message,
|
|
77
|
-
},
|
|
78
|
-
meta: event.meta,
|
|
79
|
-
} as any;
|
|
80
|
-
yield {
|
|
81
|
-
type: 'agent:output',
|
|
82
|
-
data: {
|
|
83
|
-
content: `Failed to list MCP tools for \`${serverId}\`: ${message}`,
|
|
84
|
-
},
|
|
85
|
-
meta: {
|
|
86
|
-
...(event.meta || {}),
|
|
87
|
-
agentId: context.state.agentId,
|
|
88
|
-
},
|
|
89
|
-
} as any;
|
|
90
|
-
}
|
|
91
|
-
});
|
|
92
|
-
|
|
93
|
-
builder.on('action:mcp_call', async function* (event, context) {
|
|
94
|
-
const serverId = (event.data as any)?.serverId as string;
|
|
95
|
-
const toolName = (event.data as any)?.toolName as string;
|
|
96
|
-
const args = ((event.data as any)?.args || {}) as Record<string, unknown>;
|
|
97
|
-
|
|
98
|
-
try {
|
|
99
|
-
const result = await mcpService.callTool(serverId, toolName, args);
|
|
100
|
-
const rendered = stringifyResult(result);
|
|
101
|
-
|
|
102
|
-
yield {
|
|
103
|
-
type: 'action:mcp_call:result',
|
|
104
|
-
data: {
|
|
105
|
-
success: true,
|
|
106
|
-
serverId,
|
|
107
|
-
toolName,
|
|
108
|
-
result,
|
|
109
|
-
},
|
|
110
|
-
meta: event.meta,
|
|
111
|
-
} as any;
|
|
112
|
-
|
|
113
|
-
yield {
|
|
114
|
-
type: 'agent:output',
|
|
115
|
-
data: {
|
|
116
|
-
content: `MCP \`${serverId}.${toolName}\` result:\n\n${rendered}`,
|
|
117
|
-
},
|
|
118
|
-
meta: {
|
|
119
|
-
...(event.meta || {}),
|
|
120
|
-
agentId: context.state.agentId,
|
|
121
|
-
},
|
|
122
|
-
} as any;
|
|
123
|
-
} catch (error) {
|
|
124
|
-
const message = error instanceof Error ? error.message : 'Unknown MCP error';
|
|
125
|
-
yield {
|
|
126
|
-
type: 'action:mcp_call:result',
|
|
127
|
-
data: {
|
|
128
|
-
success: false,
|
|
129
|
-
serverId,
|
|
130
|
-
toolName,
|
|
131
|
-
error: message,
|
|
132
|
-
},
|
|
133
|
-
meta: event.meta,
|
|
134
|
-
} as any;
|
|
135
|
-
yield {
|
|
136
|
-
type: 'agent:output',
|
|
137
|
-
data: {
|
|
138
|
-
content: `MCP call failed for \`${serverId}.${toolName}\`: ${message}`,
|
|
139
|
-
},
|
|
140
|
-
meta: {
|
|
141
|
-
...(event.meta || {}),
|
|
142
|
-
agentId: context.state.agentId,
|
|
143
|
-
},
|
|
144
|
-
} as any;
|
|
145
|
-
}
|
|
146
|
-
});
|
|
147
|
-
};
|
|
148
|
-
|
|
149
|
-
export const plugin = {
|
|
150
|
-
name: 'mcp',
|
|
151
|
-
description: 'Basic MCP integration for configured servers',
|
|
152
|
-
factory: mcpPlugin,
|
|
153
|
-
toolDefinitions: mcpToolDefinitions,
|
|
154
|
-
};
|