openbot 0.2.13 → 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.
Files changed (80) hide show
  1. package/dist/agents/openbot/index.js +76 -0
  2. package/dist/agents/openbot/middleware/approval.js +132 -0
  3. package/dist/agents/openbot/runtime.js +289 -0
  4. package/dist/agents/openbot/system-prompt.js +32 -0
  5. package/dist/agents/openbot/tools/delegation.js +78 -0
  6. package/dist/agents/openbot/tools/mcp.js +99 -0
  7. package/dist/agents/openbot/tools/shell.js +91 -0
  8. package/dist/agents/openbot/tools/storage.js +75 -0
  9. package/dist/agents/openbot/tools/ui.js +176 -0
  10. package/dist/agents/system.js +20 -93
  11. package/dist/app/cli.js +1 -1
  12. package/dist/app/config.js +4 -1
  13. package/dist/app/server.js +15 -8
  14. package/dist/bus/agent-package.js +1 -0
  15. package/dist/bus/plugin.js +1 -0
  16. package/dist/bus/services.js +600 -0
  17. package/dist/bus/types.js +1 -0
  18. package/dist/harness/context.js +131 -0
  19. package/dist/harness/event-normalizer.js +59 -0
  20. package/dist/harness/orchestrator.js +27 -227
  21. package/dist/harness/process.js +25 -3
  22. package/dist/harness/queue-processor.js +227 -0
  23. package/dist/harness/runtime-factory.js +103 -0
  24. package/dist/plugins/ai-sdk/index.js +37 -0
  25. package/dist/plugins/ai-sdk/runtime.js +330 -0
  26. package/dist/plugins/ai-sdk/system-prompt.js +3 -0
  27. package/dist/plugins/ai-sdk.js +277 -87
  28. package/dist/plugins/approval/index.js +159 -0
  29. package/dist/plugins/approval.js +163 -0
  30. package/dist/plugins/delegation/index.js +79 -0
  31. package/dist/plugins/delegation.js +67 -11
  32. package/dist/plugins/mcp/index.js +108 -0
  33. package/dist/plugins/shell/index.js +99 -0
  34. package/dist/plugins/shell.js +123 -0
  35. package/dist/plugins/storage-tools/index.js +85 -0
  36. package/dist/plugins/storage.js +240 -5
  37. package/dist/plugins/ui/index.js +184 -0
  38. package/dist/plugins/ui.js +185 -21
  39. package/dist/registry/agents.js +138 -0
  40. package/dist/registry/plugins.js +91 -50
  41. package/dist/services/agent-packages.js +103 -0
  42. package/dist/services/plugins.js +98 -0
  43. package/dist/services/storage.js +360 -94
  44. package/docs/agents.md +39 -66
  45. package/docs/architecture.md +1 -1
  46. package/docs/plugins.md +70 -58
  47. package/docs/templates/AGENT.example.md +57 -0
  48. package/package.json +3 -2
  49. package/src/app/cli.ts +1 -1
  50. package/src/app/config.ts +14 -4
  51. package/src/app/server.ts +23 -10
  52. package/src/app/types.ts +385 -16
  53. package/src/assets/icon.svg +4 -1
  54. package/src/bus/plugin.ts +67 -0
  55. package/src/bus/services.ts +666 -0
  56. package/src/bus/types.ts +147 -0
  57. package/src/harness/context.ts +160 -0
  58. package/src/harness/event-normalizer.ts +82 -0
  59. package/src/harness/orchestrator.ts +35 -273
  60. package/src/harness/process.ts +28 -4
  61. package/src/harness/queue-processor.ts +309 -0
  62. package/src/harness/runtime-factory.ts +125 -0
  63. package/src/plugins/ai-sdk/index.ts +44 -0
  64. package/src/plugins/ai-sdk/runtime.ts +410 -0
  65. package/src/plugins/ai-sdk/system-prompt.ts +4 -0
  66. package/src/plugins/approval/index.ts +228 -0
  67. package/src/plugins/delegation/index.ts +94 -0
  68. package/src/plugins/mcp/index.ts +128 -0
  69. package/src/plugins/shell/index.ts +123 -0
  70. package/src/plugins/storage-tools/index.ts +101 -0
  71. package/src/plugins/ui/index.ts +227 -0
  72. package/src/registry/plugins.ts +106 -55
  73. package/src/services/plugins.ts +133 -0
  74. package/src/services/storage.ts +465 -137
  75. package/src/agents/system.ts +0 -112
  76. package/src/plugins/ai-sdk.ts +0 -197
  77. package/src/plugins/delegation.ts +0 -60
  78. package/src/plugins/mcp.ts +0 -154
  79. package/src/plugins/storage.ts +0 -725
  80. package/src/plugins/ui.ts +0 -57
@@ -0,0 +1,147 @@
1
+ import type { OpenBotEvent } from '../app/types.js';
2
+ import type { PluginRef } from './plugin.js';
3
+
4
+ /**
5
+ * Public data types exposed by the OpenBot bus.
6
+ *
7
+ * The bus is the platform layer that owns channels, threads, the agent registry,
8
+ * and the event stream. Agents are composed entirely of Plugins (see
9
+ * `bus/plugin.ts`); their internal implementation is opaque to the bus.
10
+ */
11
+
12
+ export type Agent = {
13
+ id: string;
14
+ name: string;
15
+ description: string;
16
+ image?: string;
17
+ /** Plugin ids that compose this agent (mirrors AGENT.md `plugins[].id`). */
18
+ plugins: string[];
19
+ createdAt: Date;
20
+ updatedAt: Date;
21
+ };
22
+
23
+ export type AgentDetails = Agent & {
24
+ instructions: string;
25
+ /** Full plugin refs from AGENT.md (with per-plugin config). */
26
+ pluginRefs: PluginRef[];
27
+ };
28
+
29
+ export type PluginDescriptor = {
30
+ id: string;
31
+ name: string;
32
+ description: string;
33
+ /** True when bundled with the core server (`src/registry/plugins`); false for ~/.openbot/plugins installs. */
34
+ builtIn: boolean;
35
+ image?: string;
36
+ defaultInstructions?: string;
37
+ configSchema?: ConfigSchema;
38
+ createdAt: Date;
39
+ updatedAt: Date;
40
+ };
41
+
42
+ export type ConfigSchema = {
43
+ type: 'object';
44
+ properties: {
45
+ [key: string]: {
46
+ type: 'string' | 'number' | 'boolean' | 'integer';
47
+ description?: string;
48
+ default?: unknown;
49
+ enum?: unknown[];
50
+ minimum?: number;
51
+ maximum?: number;
52
+ format?: 'password' | 'url' | 'email';
53
+ };
54
+ };
55
+ required?: string[];
56
+ };
57
+
58
+ export type Channel = {
59
+ id: string;
60
+ name: string;
61
+ description: string;
62
+ cwd?: string;
63
+ createdAt: Date;
64
+ updatedAt: Date;
65
+ hasUnseenMessages?: boolean;
66
+ recentThreads?: Thread[];
67
+ };
68
+
69
+ export type Thread = {
70
+ id: string;
71
+ name: string;
72
+ channelId: string;
73
+ createdAt: Date;
74
+ updatedAt: Date;
75
+ };
76
+
77
+ export type ThreadDetails = {
78
+ id: string;
79
+ name: string;
80
+ channelId: string;
81
+ spec: string;
82
+ state: unknown;
83
+ };
84
+
85
+ export type ChannelDetails = {
86
+ id: string;
87
+ name: string;
88
+ spec: string;
89
+ state: unknown;
90
+ cwd?: string;
91
+ threads?: Thread[];
92
+ };
93
+
94
+ export interface Storage {
95
+ getChannels: () => Promise<Channel[]>;
96
+ createChannel: (args: {
97
+ channelId: string;
98
+ spec?: string;
99
+ initialState?: Record<string, unknown>;
100
+ cwd?: string;
101
+ }) => Promise<void>;
102
+ createThread: (args: {
103
+ channelId: string;
104
+ threadId: string;
105
+ threadTitle?: string;
106
+ spec?: string;
107
+ initialState?: Record<string, unknown>;
108
+ }) => Promise<void>;
109
+ getThreads: (args: { channelId: string }) => Promise<Thread[]>;
110
+ getThreadDetails: (args: { channelId: string; threadId: string }) => Promise<ThreadDetails>;
111
+ getAgents: () => Promise<Agent[]>;
112
+ getPlugins: () => Promise<PluginDescriptor[]>;
113
+ getAgentDetails: (args: { agentId: string }) => Promise<AgentDetails>;
114
+ createAgent: (args: {
115
+ agentId: string;
116
+ name: string;
117
+ description?: string;
118
+ instructions: string;
119
+ plugins: PluginRef[];
120
+ }) => Promise<void>;
121
+ updateAgent: (args: {
122
+ agentId: string;
123
+ name?: string;
124
+ description?: string;
125
+ instructions?: string;
126
+ plugins?: PluginRef[];
127
+ }) => Promise<void>;
128
+ deleteAgent: (args: { agentId: string }) => Promise<void>;
129
+ getEvents: (args: { channelId: string; threadId?: string }) => Promise<OpenBotEvent[]>;
130
+ getChannelDetails: (args: { channelId: string }) => Promise<ChannelDetails>;
131
+ patchChannelState: (args: { channelId: string; state: unknown }) => Promise<void>;
132
+ patchThreadState: (args: {
133
+ channelId: string;
134
+ threadId: string;
135
+ state: unknown;
136
+ }) => Promise<void>;
137
+ patchChannelSpec: (args: { channelId: string; spec: string }) => Promise<void>;
138
+ patchThreadSpec: (args: { channelId: string; threadId: string; spec: string }) => Promise<void>;
139
+ getVariables: () => Promise<Record<string, string | { value: string; secret: boolean }>>;
140
+ createVariable: (args: { key: string; value: string; secret?: boolean }) => Promise<void>;
141
+ deleteVariable: (args: { key: string }) => Promise<void>;
142
+ listFiles: (args: {
143
+ channelId: string;
144
+ path?: string;
145
+ }) => Promise<Array<{ name: string; isDirectory: boolean }>>;
146
+ readFile: (args: { channelId: string; path: string }) => Promise<string>;
147
+ }
@@ -0,0 +1,160 @@
1
+ import { OpenBotState } from '../app/types.js';
2
+ import { Storage } from '../bus/types.js';
3
+
4
+ /**
5
+ * Represents a piece of context that can be used in a prompt.
6
+ */
7
+ export interface ContextItem {
8
+ id: string;
9
+ type: string;
10
+ priority: number;
11
+ content: string;
12
+ metadata?: Record<string, any>;
13
+ }
14
+
15
+ /**
16
+ * A provider that can fetch or generate context items.
17
+ */
18
+ export interface ContextProvider {
19
+ name: string;
20
+ provide(state: OpenBotState, storage?: Storage): Promise<ContextItem[]>;
21
+ }
22
+
23
+ /**
24
+ * A processor that can transform or filter context items (e.g., ranking, truncation).
25
+ */
26
+ export interface ContextProcessor {
27
+ name: string;
28
+ process(items: ContextItem[], state: OpenBotState): Promise<ContextItem[]>;
29
+ }
30
+
31
+ /**
32
+ * The core engine that orchestrates context building.
33
+ */
34
+ export class ContextEngine {
35
+ private providers: ContextProvider[] = [];
36
+ private processors: ContextProcessor[] = [];
37
+
38
+ registerProvider(provider: ContextProvider) {
39
+ this.providers.push(provider);
40
+ }
41
+
42
+ registerProcessor(processor: ContextProcessor) {
43
+ this.processors.push(processor);
44
+ }
45
+
46
+ async buildContext(state: OpenBotState, storage?: Storage): Promise<string> {
47
+ // 1. Collect context from all providers
48
+ let items: ContextItem[] = [];
49
+ for (const provider of this.providers) {
50
+ try {
51
+ const providedItems = await provider.provide(state, storage);
52
+ items.push(...providedItems);
53
+ } catch (error) {
54
+ console.warn(`[ContextEngine] Provider ${provider.name} failed:`, error);
55
+ }
56
+ }
57
+
58
+ // 2. Run through processors
59
+ for (const processor of this.processors) {
60
+ try {
61
+ items = await processor.process(items, state);
62
+ } catch (error) {
63
+ console.warn(`[ContextEngine] Processor ${processor.name} failed:`, error);
64
+ }
65
+ }
66
+
67
+ // 3. Format items into a single string
68
+ return items
69
+ .sort((a, b) => b.priority - a.priority)
70
+ .map(item => item.content)
71
+ .join('\n\n');
72
+ }
73
+ }
74
+
75
+ /**
76
+ * Default implementation of a Context Engine with basic providers.
77
+ */
78
+ export function createDefaultContextEngine(): ContextEngine {
79
+ const engine = new ContextEngine();
80
+
81
+ // Basic Providers
82
+ engine.registerProvider(new AgentDetailsProvider());
83
+ engine.registerProvider(new ChannelDetailsProvider());
84
+ engine.registerProvider(new ThreadDetailsProvider());
85
+ engine.registerProvider(new RecentEventsProvider());
86
+
87
+ return engine;
88
+ }
89
+
90
+ class AgentDetailsProvider implements ContextProvider {
91
+ name = 'agent-details';
92
+ async provide(state: OpenBotState): Promise<ContextItem[]> {
93
+ if (!state.agentDetails) return [];
94
+ return [{
95
+ id: 'agent-details',
96
+ type: 'agent',
97
+ priority: 100,
98
+ content: `## AGENT NAME\n${state.agentDetails.name}\n\n## AGENT SPECIFICATION\n${state.agentDetails.instructions}`
99
+ }];
100
+ }
101
+ }
102
+
103
+ class ChannelDetailsProvider implements ContextProvider {
104
+ name = 'channel-details';
105
+ async provide(state: OpenBotState): Promise<ContextItem[]> {
106
+ if (!state.channelDetails) return [];
107
+ return [{
108
+ id: 'channel-details',
109
+ type: 'channel',
110
+ priority: 80,
111
+ content: `## CHANNEL NAME\n${state.channelDetails.name}\n\n## CHANNEL SPECIFICATION\n${state.channelDetails.spec}`
112
+ }];
113
+ }
114
+ }
115
+
116
+ class ThreadDetailsProvider implements ContextProvider {
117
+ name = 'thread-details';
118
+ async provide(state: OpenBotState): Promise<ContextItem[]> {
119
+ if (!state.threadDetails) return [];
120
+ return [{
121
+ id: 'thread-details',
122
+ type: 'thread',
123
+ priority: 90,
124
+ content: `## THREAD NAME\n${state.threadDetails.name}\n\n## THREAD SPECIFICATION\n${state.threadDetails.spec}`
125
+ }];
126
+ }
127
+ }
128
+
129
+ class RecentEventsProvider implements ContextProvider {
130
+ name = 'recent-events';
131
+ async provide(state: OpenBotState, storage?: Storage): Promise<ContextItem[]> {
132
+ if (!storage) return [];
133
+ const items: ContextItem[] = [];
134
+
135
+ // Fetch channel events if no thread, otherwise fetch thread events
136
+ const channelId = state.channelId;
137
+ const threadId = state.threadId;
138
+
139
+ try {
140
+ const events = await storage.getEvents({ channelId, threadId });
141
+ if (events.length > 0) {
142
+ const formattedEvents = events
143
+ .slice(-20)
144
+ .map((e) => `- ${e.type}: ${JSON.stringify((e as any).data || {})}`)
145
+ .join('\n');
146
+
147
+ items.push({
148
+ id: threadId ? 'thread-events' : 'channel-events',
149
+ type: 'events',
150
+ priority: 70,
151
+ content: `## ${threadId ? 'THREAD' : 'CHANNEL'} RECENT ACTIVITIES (events)\n${formattedEvents}`
152
+ });
153
+ }
154
+ } catch (error) {
155
+ console.warn(`[ContextEngine] Failed to fetch events:`, error);
156
+ }
157
+
158
+ return items;
159
+ }
160
+ }
@@ -0,0 +1,82 @@
1
+ import { AgentInvokeEvent, OpenBotEvent, OpenBotState } from '../app/types.js';
2
+ import { ensureEventId } from '../app/utils.js';
3
+ import { storageService } from '../services/storage.js';
4
+
5
+ export interface NormalizedEventResult {
6
+ finalEvent: OpenBotEvent;
7
+ finalAgentId: string;
8
+ }
9
+
10
+ export const EventNormalizer = {
11
+ /**
12
+ * Normalizes incoming events, converting raw inputs like user:input to agent:invoke.
13
+ * Also handles initial state storage and event bus propagation for user inputs.
14
+ */
15
+ normalize: async (
16
+ event: OpenBotEvent,
17
+ options: {
18
+ runId: string;
19
+ agentId?: string;
20
+ channelId: string;
21
+ threadId?: string;
22
+ onEvent: (chunk: OpenBotEvent, state: OpenBotState) => Promise<boolean | void>;
23
+ }
24
+ ): Promise<NormalizedEventResult> => {
25
+ const { runId, agentId, channelId, threadId, onEvent } = options;
26
+
27
+ // 0. Ensure the incoming event has a unique ID immediately
28
+ ensureEventId(event);
29
+
30
+ let finalAgentId = agentId || 'system';
31
+ let finalEvent = event;
32
+
33
+ // 1. Convert user:input (or other raw inputs) to agent:invoke
34
+ const rawContent = (event as any).data?.content || '';
35
+ if (event.type === 'user:input' || event.type === 'agent:invoke') {
36
+ const normalizedInvokeEvent: AgentInvokeEvent = {
37
+ type: 'agent:invoke',
38
+ id: event.id,
39
+ data: {
40
+ content: rawContent,
41
+ role: 'user',
42
+ },
43
+ meta: {
44
+ agentId: 'system',
45
+ userId: event.meta?.userId,
46
+ userName: event.meta?.userName,
47
+ userAvatarUrl: event.meta?.userAvatarUrl,
48
+ },
49
+ };
50
+ finalEvent = normalizedInvokeEvent;
51
+
52
+ // 1. Store the user's input in the current context (main channel or existing thread)
53
+ const initialState = await storageService.getOpenBotState({
54
+ runId,
55
+ agentId: 'system',
56
+ channelId,
57
+ threadId: threadId,
58
+ event: finalEvent,
59
+ });
60
+
61
+ // 2. Propagate the user's input to the event bus
62
+ await onEvent(finalEvent, initialState);
63
+
64
+ // 3. Prepare the event for the target agent
65
+ finalEvent = {
66
+ ...event,
67
+ type: 'agent:invoke',
68
+ data: {
69
+ ...((event as any).data || {}),
70
+ content: rawContent,
71
+ },
72
+ meta: {
73
+ ...(event.meta || {}),
74
+ // The threadId in meta is the anchor for new threads (Slack-style)
75
+ threadId: threadId || finalEvent.id,
76
+ },
77
+ };
78
+ }
79
+
80
+ return { finalEvent, finalAgentId };
81
+ },
82
+ };