openbot 0.3.5 → 0.4.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 (98) hide show
  1. package/README.md +15 -16
  2. package/dist/app/agent-ids.js +4 -0
  3. package/dist/app/cli.js +1 -1
  4. package/dist/app/config.js +0 -19
  5. package/dist/app/server.js +8 -14
  6. package/dist/assets/icon.svg +9 -3
  7. package/dist/bus/services.js +78 -132
  8. package/dist/harness/agent-invoke-run.js +44 -0
  9. package/dist/harness/agent-turn.js +99 -0
  10. package/dist/harness/channel-participants.js +40 -0
  11. package/dist/harness/constants.js +2 -0
  12. package/dist/harness/context-meter.js +97 -0
  13. package/dist/harness/context.js +98 -45
  14. package/dist/harness/dispatch.js +144 -0
  15. package/dist/harness/dispatcher.js +45 -156
  16. package/dist/harness/history.js +177 -0
  17. package/dist/harness/index.js +91 -0
  18. package/dist/harness/orchestration.js +88 -0
  19. package/dist/harness/participants.js +22 -0
  20. package/dist/harness/run-harness.js +154 -0
  21. package/dist/harness/run.js +98 -0
  22. package/dist/harness/runtime-factory.js +0 -34
  23. package/dist/harness/runtime.js +57 -0
  24. package/dist/harness/todo-dispatch.js +51 -0
  25. package/dist/harness/todos.js +5 -0
  26. package/dist/harness/turn.js +79 -0
  27. package/dist/plugins/approval/index.js +105 -149
  28. package/dist/plugins/delegation/index.js +119 -32
  29. package/dist/plugins/memory/index.js +103 -14
  30. package/dist/plugins/memory/service.js +152 -0
  31. package/dist/plugins/openbot/context.js +80 -0
  32. package/dist/plugins/openbot/history.js +98 -0
  33. package/dist/plugins/openbot/index.js +31 -0
  34. package/dist/plugins/openbot/runtime.js +317 -0
  35. package/dist/plugins/openbot/system-prompt.js +5 -0
  36. package/dist/plugins/plugin-manager/index.js +105 -0
  37. package/dist/plugins/storage/index.js +573 -0
  38. package/dist/plugins/storage/service.js +1159 -0
  39. package/dist/plugins/storage-tools/index.js +2 -2
  40. package/dist/plugins/thread-namer/index.js +72 -0
  41. package/dist/plugins/thread-naming/generate-title.js +44 -0
  42. package/dist/plugins/thread-naming/index.js +103 -0
  43. package/dist/plugins/threads/index.js +114 -0
  44. package/dist/plugins/todo/index.js +24 -25
  45. package/dist/plugins/ui/index.js +2 -32
  46. package/dist/registry/plugins.js +3 -9
  47. package/dist/services/plugins/domain.js +1 -0
  48. package/dist/services/plugins/plugin-cache.js +9 -0
  49. package/dist/services/plugins/registry.js +110 -0
  50. package/dist/services/plugins/service.js +177 -0
  51. package/dist/services/plugins/types.js +1 -0
  52. package/dist/services/process.js +29 -0
  53. package/dist/services/storage.js +41 -15
  54. package/dist/services/thread-naming.js +81 -0
  55. package/docs/agents.md +16 -10
  56. package/docs/architecture.md +2 -2
  57. package/docs/plugins.md +6 -15
  58. package/docs/templates/AGENT.example.md +7 -13
  59. package/package.json +1 -2
  60. package/src/app/agent-ids.ts +5 -0
  61. package/src/app/cli.ts +1 -1
  62. package/src/app/config.ts +1 -31
  63. package/src/app/server.ts +8 -16
  64. package/src/app/types.ts +70 -190
  65. package/src/assets/icon.svg +9 -3
  66. package/src/harness/index.ts +145 -0
  67. package/src/plugins/approval/index.ts +91 -189
  68. package/src/plugins/delegation/index.ts +136 -39
  69. package/src/plugins/memory/index.ts +112 -15
  70. package/src/{services/memory.ts → plugins/memory/service.ts} +1 -1
  71. package/src/plugins/openbot/context.ts +91 -0
  72. package/src/plugins/openbot/history.ts +107 -0
  73. package/src/plugins/openbot/index.ts +37 -0
  74. package/src/plugins/openbot/runtime.ts +384 -0
  75. package/src/plugins/openbot/system-prompt.ts +7 -0
  76. package/src/plugins/plugin-manager/index.ts +122 -0
  77. package/src/plugins/shell/index.ts +1 -1
  78. package/src/plugins/storage/index.ts +633 -0
  79. package/src/{services/storage.ts → plugins/storage/service.ts} +257 -72
  80. package/src/{bus/types.ts → services/plugins/domain.ts} +20 -7
  81. package/src/services/plugins/plugin-cache.ts +13 -0
  82. package/src/{registry/plugins.ts → services/plugins/registry.ts} +25 -27
  83. package/src/services/{plugins.ts → plugins/service.ts} +96 -2
  84. package/src/{bus/plugin.ts → services/plugins/types.ts} +3 -3
  85. package/src/bus/services.ts +0 -908
  86. package/src/harness/context.ts +0 -356
  87. package/src/harness/dispatcher.ts +0 -379
  88. package/src/harness/mcp.ts +0 -78
  89. package/src/harness/runtime-factory.ts +0 -129
  90. package/src/harness/todo-advance.ts +0 -128
  91. package/src/plugins/ai-sdk/index.ts +0 -41
  92. package/src/plugins/ai-sdk/runtime.ts +0 -468
  93. package/src/plugins/ai-sdk/system-prompt.ts +0 -18
  94. package/src/plugins/mcp/index.ts +0 -128
  95. package/src/plugins/storage-tools/index.ts +0 -90
  96. package/src/plugins/todo/index.ts +0 -64
  97. package/src/plugins/ui/index.ts +0 -227
  98. /package/src/{harness → services}/process.ts +0 -0
@@ -1,32 +1,31 @@
1
1
  import fs from 'node:fs';
2
2
  import path from 'node:path';
3
3
  import { pathToFileURL } from 'node:url';
4
- import type { Plugin } from '../bus/plugin.js';
5
- import { aiSdkPlugin } from '../plugins/ai-sdk/index.js';
6
- import { shellPlugin } from '../plugins/shell/index.js';
7
- import { mcpPlugin } from '../plugins/mcp/index.js';
8
- import { delegationPlugin } from '../plugins/delegation/index.js';
9
- import { storageToolsPlugin } from '../plugins/storage-tools/index.js';
10
- import { uiPlugin } from '../plugins/ui/index.js';
11
- import { approvalPlugin } from '../plugins/approval/index.js';
12
- import { memoryPlugin } from '../plugins/memory/index.js';
13
- import { todoPlugin } from '../plugins/todo/index.js';
14
- import { DEFAULT_PLUGINS_DIR, DEFAULT_BASE_DIR, loadConfig, resolvePath } from '../app/config.js';
4
+ import type { Plugin } from './types.js';
5
+ import { openbotPlugin } from '../../plugins/openbot/index.js';
6
+ import { shellPlugin } from '../../plugins/shell/index.js';
7
+ import { storagePlugin } from '../../plugins/storage/index.js';
8
+ import { approvalPlugin } from '../../plugins/approval/index.js';
9
+ import { memoryPlugin } from '../../plugins/memory/index.js';
10
+ import { delegationPlugin } from '../../plugins/delegation/index.js';
11
+ import { pluginManagerPlugin } from '../../plugins/plugin-manager/index.js';
12
+ import { DEFAULT_PLUGINS_DIR, DEFAULT_BASE_DIR, loadConfig, resolvePath } from '../../app/config.js';
13
+ import {
14
+ invalidatePlugin as clearResolvedPluginEntry,
15
+ loadedCommunityPlugins,
16
+ resolvedPluginCache,
17
+ } from './plugin-cache.js';
15
18
 
16
19
  let pluginsDir: string | null = null;
17
- const loadedPlugins = new Set<string>();
18
- const cache = new Map<string, Plugin>();
19
20
 
20
21
  const BUILT_IN: Record<string, Plugin> = {
21
- [aiSdkPlugin.id]: aiSdkPlugin,
22
+ [openbotPlugin.id]: openbotPlugin,
22
23
  [shellPlugin.id]: shellPlugin,
23
- [mcpPlugin.id]: mcpPlugin,
24
- [delegationPlugin.id]: delegationPlugin,
25
- [storageToolsPlugin.id]: storageToolsPlugin,
26
- [uiPlugin.id]: uiPlugin,
24
+ [storagePlugin.id]: storagePlugin,
27
25
  [approvalPlugin.id]: approvalPlugin,
28
26
  [memoryPlugin.id]: memoryPlugin,
29
- [todoPlugin.id]: todoPlugin,
27
+ [delegationPlugin.id]: delegationPlugin,
28
+ [pluginManagerPlugin.id]: pluginManagerPlugin,
30
29
  };
31
30
 
32
31
  /**
@@ -78,14 +77,14 @@ export function initPlugins(dir?: string) {
78
77
 
79
78
  /**
80
79
  * Resolve a Plugin by id. The id is either:
81
- * - a built-in id (e.g. "ai-sdk", "shell"), or
80
+ * - a built-in id (e.g. "openbot", "shell"), or
82
81
  * - an npm package name (e.g. "openbot-plugin-foo" or "@scope/foo"),
83
82
  * in which case the folder layout is `plugins/<id>/dist/index.js`.
84
83
  */
85
84
  export async function resolvePlugin(id: string): Promise<Plugin | null> {
86
- if (cache.has(id)) return cache.get(id)!;
85
+ if (resolvedPluginCache.has(id)) return resolvedPluginCache.get(id)!;
87
86
  if (BUILT_IN[id]) {
88
- cache.set(id, BUILT_IN[id]);
87
+ resolvedPluginCache.set(id, BUILT_IN[id]);
89
88
  return BUILT_IN[id];
90
89
  }
91
90
 
@@ -109,10 +108,10 @@ export async function resolvePlugin(id: string): Promise<Plugin | null> {
109
108
  return null;
110
109
  }
111
110
  const plugin: Plugin = { id, ...parsed, name: parsed.name || id };
112
- cache.set(id, plugin);
113
- if (!loadedPlugins.has(id)) {
111
+ resolvedPluginCache.set(id, plugin);
112
+ if (!loadedCommunityPlugins.has(id)) {
114
113
  console.log(`[plugins] Loaded community plugin "${id}" from ${distPath}`);
115
- loadedPlugins.add(id);
114
+ loadedCommunityPlugins.add(id);
116
115
  }
117
116
  return plugin;
118
117
  } catch (e) {
@@ -123,8 +122,7 @@ export async function resolvePlugin(id: string): Promise<Plugin | null> {
123
122
 
124
123
  /** Drop a single id from the in-memory cache (e.g. after fresh install). */
125
124
  export function invalidatePlugin(id: string): void {
126
- cache.delete(id);
127
- loadedPlugins.delete(id);
125
+ clearResolvedPluginEntry(id);
128
126
  }
129
127
 
130
128
  /** List built-in plugins (for marketplace/registry views). */
@@ -6,10 +6,12 @@ import { promisify } from 'node:util';
6
6
  import {
7
7
  DEFAULT_PLUGINS_DIR,
8
8
  DEFAULT_BASE_DIR,
9
+ DEFAULT_MARKETPLACE_REGISTRY_URL,
9
10
  loadConfig,
10
11
  resolvePath,
11
- } from '../app/config.js';
12
- import { invalidatePlugin } from '../registry/plugins.js';
12
+ } from '../../app/config.js';
13
+ import { invalidatePlugin } from './plugin-cache.js';
14
+ import { PluginRef } from './types.js';
13
15
 
14
16
  const execAsync = promisify(exec);
15
17
 
@@ -24,6 +26,97 @@ export interface InstalledPlugin {
24
26
  version: string;
25
27
  }
26
28
 
29
+ /** One marketplace entry; matches `action:marketplace:list:result` agent shape. */
30
+ export type MarketplaceAgentListing = {
31
+ id: string;
32
+ name: string;
33
+ description: string;
34
+ image?: string;
35
+ instructions: string;
36
+ plugins: PluginRef[];
37
+ };
38
+
39
+ const DEFAULT_MARKETPLACE_AGENTS: MarketplaceAgentListing[] = [];
40
+
41
+ function isRecord(value: unknown): value is Record<string, unknown> {
42
+ return typeof value === 'object' && value !== null && !Array.isArray(value);
43
+ }
44
+
45
+ /**
46
+ * Parses JSON from a remote registry file. Supports either
47
+ * `{ "agents": [ ... ] }` or a top-level array.
48
+ */
49
+ export function parseMarketplaceRegistryJson(data: unknown): MarketplaceAgentListing[] {
50
+ const rawAgents: unknown =
51
+ Array.isArray(data) ? data : isRecord(data) && Array.isArray(data.agents) ? data.agents : null;
52
+ if (!Array.isArray(rawAgents)) {
53
+ throw new Error('Registry JSON must be an array or an object with an "agents" array');
54
+ }
55
+ return rawAgents.map((item, i) => {
56
+ if (!isRecord(item)) {
57
+ throw new Error(`agents[${i}]: expected object`);
58
+ }
59
+ const id = item.id;
60
+ const name = item.name;
61
+ const description = item.description;
62
+ const instructions = item.instructions;
63
+ const pluginsRaw = item.plugins;
64
+ if (typeof id !== 'string' || !id) throw new Error(`agents[${i}].id must be a non-empty string`);
65
+ if (typeof name !== 'string') throw new Error(`agents[${i}].name must be a string`);
66
+ if (typeof description !== 'string') throw new Error(`agents[${i}].description must be a string`);
67
+ if (typeof instructions !== 'string') {
68
+ throw new Error(`agents[${i}].instructions must be a string`);
69
+ }
70
+ if (!Array.isArray(pluginsRaw)) throw new Error(`agents[${i}].plugins must be an array`);
71
+ const plugins: PluginRef[] = pluginsRaw.map((p, j) => {
72
+ if (!isRecord(p) || typeof p.id !== 'string' || !p.id) {
73
+ throw new Error(`agents[${i}].plugins[${j}]: expected { "id": string, "config"?: object }`);
74
+ }
75
+ const ref: PluginRef = { id: p.id };
76
+ if (p.config !== undefined) {
77
+ if (!isRecord(p.config)) throw new Error(`agents[${i}].plugins[${j}].config must be an object`);
78
+ ref.config = p.config;
79
+ }
80
+ return ref;
81
+ });
82
+ const listing: MarketplaceAgentListing = { id, name, description, instructions, plugins };
83
+ if (item.image !== undefined) {
84
+ if (typeof item.image !== 'string') throw new Error(`agents[${i}].image must be a string`);
85
+ listing.image = item.image;
86
+ }
87
+ return listing;
88
+ });
89
+ }
90
+
91
+ async function fetchMarketplaceAgentsFromUrl(url: string): Promise<MarketplaceAgentListing[]> {
92
+ const res = await fetch(url, {
93
+ headers: { Accept: 'application/json' },
94
+ signal: AbortSignal.timeout(15_000),
95
+ });
96
+ if (!res.ok) {
97
+ throw new Error(`Registry HTTP ${res.status} ${res.statusText}`);
98
+ }
99
+ const json: unknown = await res.json();
100
+ return parseMarketplaceRegistryJson(json);
101
+ }
102
+
103
+ /**
104
+ * Resolves marketplace agent listings from configured registry URL, or falls back to an empty list.
105
+ */
106
+ export async function resolveMarketplaceAgentList(): Promise<MarketplaceAgentListing[]> {
107
+ const { marketplaceRegistryUrl } = loadConfig();
108
+ const registryUrl = marketplaceRegistryUrl?.trim() || DEFAULT_MARKETPLACE_REGISTRY_URL;
109
+ try {
110
+ return await fetchMarketplaceAgentsFromUrl(registryUrl);
111
+ } catch (err) {
112
+ console.warn(
113
+ `[plugins] marketplace registry fetch failed (${registryUrl}), using built-in list:`,
114
+ err instanceof Error ? err.message : err,
115
+ );
116
+ return DEFAULT_MARKETPLACE_AGENTS;
117
+ }
118
+ }
119
+
27
120
  const getPluginsDir = (): string => {
28
121
  const config = loadConfig();
29
122
  const baseDir = resolvePath(config.baseDir || DEFAULT_BASE_DIR);
@@ -131,3 +224,4 @@ export const pluginService = {
131
224
  }
132
225
  },
133
226
  };
227
+
@@ -1,11 +1,11 @@
1
1
  import { MelonyPlugin } from 'melony';
2
- import { OpenBotEvent, OpenBotState } from '../app/types.js';
3
- import { AgentDetails, ConfigSchema, Storage } from './types.js';
2
+ import { OpenBotEvent, OpenBotState } from '../../app/types.js';
3
+ import { AgentDetails, ConfigSchema, Storage } from './domain.js';
4
4
 
5
5
  /**
6
6
  * Reference to a plugin from an agent's AGENT.md frontmatter.
7
7
  *
8
- * The `id` is either a built-in plugin id (e.g. `ai-sdk`, `shell`) or an npm
8
+ * The `id` is either a built-in plugin id (e.g. `openbot`, `shell`) or an npm
9
9
  * package name (e.g. `openbot-plugin-codex`, `@scope/openbot-plugin-foo`).
10
10
  * Each entry may carry plugin-specific `config`.
11
11
  */