openbot 0.5.8 → 0.5.10
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 +1 -1
- package/dist/app/active-runs.js +70 -0
- package/dist/app/cli.js +1 -1
- package/dist/app/lifecycle-events.js +27 -0
- package/dist/app/run-event-handler.js +37 -0
- package/dist/app/server.js +127 -123
- package/dist/app/slack-webhook.js +81 -0
- package/dist/app/webhook-routing.js +52 -0
- package/dist/harness/index.js +18 -15
- package/dist/harness/merge-plugin-config.js +26 -0
- package/dist/plugins/slack-webhook/index.js +51 -0
- package/dist/plugins/storage/index.js +72 -14
- package/dist/plugins/storage/service.js +11 -6
- package/dist/services/plugins/enrich-openbot-plugin.js +38 -0
- package/dist/services/plugins/host.js +0 -3
- package/dist/services/plugins/model-registry.js +1 -1
- package/docs/plugins.md +27 -0
- package/package.json +2 -2
- package/src/app/active-runs.ts +95 -0
- package/src/app/cli.ts +1 -1
- package/src/app/lifecycle-events.ts +46 -0
- package/src/app/run-event-handler.ts +55 -0
- package/src/app/server.ts +147 -154
- package/src/app/types.ts +33 -4
- package/src/app/webhook-routing.ts +70 -0
- package/src/harness/index.ts +19 -20
- package/src/harness/merge-plugin-config.ts +35 -0
- package/src/plugins/storage/index.ts +432 -372
- package/src/plugins/storage/service.ts +13 -13
- package/src/services/plugins/enrich-openbot-plugin.ts +41 -0
- package/src/services/plugins/host.ts +0 -6
- package/src/services/plugins/types.ts +0 -8
- package/src/services/plugins/model-registry.ts +0 -178
package/src/harness/index.ts
CHANGED
|
@@ -9,6 +9,7 @@ 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
11
|
import { createPluginHost } from '../services/plugins/host.js';
|
|
12
|
+
import { getInvokeConfigOverrides, mergePluginConfig } from './merge-plugin-config.js';
|
|
12
13
|
|
|
13
14
|
export { STATE_AGENT_ID, ORCHESTRATOR_AGENT_ID };
|
|
14
15
|
|
|
@@ -16,8 +17,6 @@ export interface RunAgentOptions {
|
|
|
16
17
|
runId: string;
|
|
17
18
|
agentId: string;
|
|
18
19
|
event: OpenBotEvent;
|
|
19
|
-
channelId: string;
|
|
20
|
-
threadId?: string;
|
|
21
20
|
persistEvents?: boolean;
|
|
22
21
|
/** Resolved public base URL for the server. */
|
|
23
22
|
publicBaseUrl?: string;
|
|
@@ -29,15 +28,11 @@ async function emitEvent(
|
|
|
29
28
|
state: OpenBotState | undefined,
|
|
30
29
|
{
|
|
31
30
|
persistEvents,
|
|
32
|
-
channelId,
|
|
33
|
-
threadId,
|
|
34
31
|
onEvent,
|
|
35
32
|
parentAgentId,
|
|
36
33
|
parentToolCallId,
|
|
37
34
|
}: {
|
|
38
35
|
persistEvents: boolean;
|
|
39
|
-
channelId: string;
|
|
40
|
-
threadId?: string;
|
|
41
36
|
onEvent: RunAgentOptions['onEvent'];
|
|
42
37
|
parentAgentId?: string;
|
|
43
38
|
parentToolCallId?: string;
|
|
@@ -54,10 +49,11 @@ async function emitEvent(
|
|
|
54
49
|
};
|
|
55
50
|
}
|
|
56
51
|
|
|
57
|
-
|
|
52
|
+
const channelId = state?.channelId;
|
|
53
|
+
if (persistEvents && channelId) {
|
|
58
54
|
await storageService.storeEvent({
|
|
59
|
-
channelId
|
|
60
|
-
threadId: state?.threadId
|
|
55
|
+
channelId,
|
|
56
|
+
threadId: state?.threadId,
|
|
61
57
|
event: chunk,
|
|
62
58
|
});
|
|
63
59
|
}
|
|
@@ -70,7 +66,7 @@ async function emitEvent(
|
|
|
70
66
|
* Fire and forget.
|
|
71
67
|
*/
|
|
72
68
|
export async function runAgent(options: RunAgentOptions): Promise<void> {
|
|
73
|
-
const { runId, agentId, event,
|
|
69
|
+
const { runId, agentId, event, onEvent } = options;
|
|
74
70
|
const persistEvents = options.persistEvents !== false;
|
|
75
71
|
|
|
76
72
|
let publicBaseUrl = options.publicBaseUrl;
|
|
@@ -88,23 +84,21 @@ export async function runAgent(options: RunAgentOptions): Promise<void> {
|
|
|
88
84
|
const state = await storageService.getOpenBotState({
|
|
89
85
|
runId,
|
|
90
86
|
agentId,
|
|
91
|
-
channelId,
|
|
92
|
-
threadId,
|
|
93
87
|
event,
|
|
94
88
|
});
|
|
95
89
|
|
|
96
90
|
// Shared per-thread abort signal so a stop request cancels this run and any
|
|
97
91
|
// delegated sub-agent runs (which execute in the same channel/thread).
|
|
98
|
-
const runKey = abortKey(channelId, threadId);
|
|
92
|
+
const runKey = state.channelId ? abortKey(state.channelId, state.threadId) : runId;
|
|
99
93
|
const abortSignal = abortRegistry.acquire(runKey);
|
|
100
94
|
|
|
101
95
|
await emitEvent(
|
|
102
96
|
{
|
|
103
97
|
type: 'agent:run:start',
|
|
104
|
-
data: { runId, agentId, channelId, threadId },
|
|
98
|
+
data: { runId, agentId, channelId: state.channelId, threadId: state.threadId },
|
|
105
99
|
} as OpenBotEvent,
|
|
106
100
|
state,
|
|
107
|
-
{ persistEvents,
|
|
101
|
+
{ persistEvents, onEvent, parentAgentId, parentToolCallId },
|
|
108
102
|
);
|
|
109
103
|
|
|
110
104
|
try {
|
|
@@ -121,6 +115,13 @@ export async function runAgent(options: RunAgentOptions): Promise<void> {
|
|
|
121
115
|
const builder = melony<OpenBotState, OpenBotEvent>().initialState(state);
|
|
122
116
|
|
|
123
117
|
const pluginHost = createPluginHost(runAgent);
|
|
118
|
+
const invokeConfigOverrides = getInvokeConfigOverrides(event);
|
|
119
|
+
const pluginConfigs = Object.fromEntries(
|
|
120
|
+
pluginRefs.map((ref) => [
|
|
121
|
+
ref.id,
|
|
122
|
+
mergePluginConfig(ref.config, invokeConfigOverrides, ref.id),
|
|
123
|
+
]),
|
|
124
|
+
);
|
|
124
125
|
|
|
125
126
|
for (const ref of pluginRefs) {
|
|
126
127
|
const plugin = await resolvePlugin(ref.id);
|
|
@@ -130,7 +131,7 @@ export async function runAgent(options: RunAgentOptions): Promise<void> {
|
|
|
130
131
|
plugin.factory({
|
|
131
132
|
agentId,
|
|
132
133
|
agentDetails,
|
|
133
|
-
config: ref.
|
|
134
|
+
config: pluginConfigs[ref.id],
|
|
134
135
|
storage: storageService,
|
|
135
136
|
tools,
|
|
136
137
|
publicBaseUrl,
|
|
@@ -147,8 +148,6 @@ export async function runAgent(options: RunAgentOptions): Promise<void> {
|
|
|
147
148
|
if (abortSignal.aborted) break;
|
|
148
149
|
await emitEvent(outputEvent, state, {
|
|
149
150
|
persistEvents,
|
|
150
|
-
channelId,
|
|
151
|
-
threadId,
|
|
152
151
|
onEvent,
|
|
153
152
|
parentAgentId,
|
|
154
153
|
parentToolCallId,
|
|
@@ -161,10 +160,10 @@ export async function runAgent(options: RunAgentOptions): Promise<void> {
|
|
|
161
160
|
await emitEvent(
|
|
162
161
|
{
|
|
163
162
|
type: 'agent:run:end',
|
|
164
|
-
data: { runId, agentId, channelId, threadId },
|
|
163
|
+
data: { runId, agentId, channelId: state.channelId, threadId: state.threadId },
|
|
165
164
|
} as OpenBotEvent,
|
|
166
165
|
state,
|
|
167
|
-
{ persistEvents,
|
|
166
|
+
{ persistEvents, onEvent, parentAgentId, parentToolCallId },
|
|
168
167
|
);
|
|
169
168
|
}
|
|
170
169
|
}
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
import { OpenBotEvent } from '../app/types.js';
|
|
2
|
+
|
|
3
|
+
function isPlainObject(value: unknown): value is Record<string, unknown> {
|
|
4
|
+
return typeof value === 'object' && value !== null && !Array.isArray(value);
|
|
5
|
+
}
|
|
6
|
+
|
|
7
|
+
function isPluginKeyedConfig(config: Record<string, unknown>): boolean {
|
|
8
|
+
return Object.values(config).every(isPlainObject);
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
export function getInvokeConfigOverrides(event: OpenBotEvent): Record<string, unknown> | undefined {
|
|
12
|
+
if (event.type !== 'agent:invoke') return undefined;
|
|
13
|
+
|
|
14
|
+
const config = event.data?.config;
|
|
15
|
+
if (!isPlainObject(config) || Object.keys(config).length === 0) return undefined;
|
|
16
|
+
|
|
17
|
+
return config;
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
export function mergePluginConfig(
|
|
21
|
+
base: Record<string, unknown> | undefined,
|
|
22
|
+
overrides: Record<string, unknown> | undefined,
|
|
23
|
+
pluginId: string,
|
|
24
|
+
): Record<string, unknown> {
|
|
25
|
+
const baseConfig = base ?? {};
|
|
26
|
+
if (!overrides) return baseConfig;
|
|
27
|
+
|
|
28
|
+
if (isPluginKeyedConfig(overrides)) {
|
|
29
|
+
const pluginOverride = overrides[pluginId];
|
|
30
|
+
if (!isPlainObject(pluginOverride)) return baseConfig;
|
|
31
|
+
return { ...baseConfig, ...pluginOverride };
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
return { ...baseConfig, ...overrides };
|
|
35
|
+
}
|