openbot 0.4.7 → 0.5.4
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/agents/runtime-security-reviewer.md +32 -0
- package/.claude/hooks/format.sh +18 -0
- package/.claude/hooks/protect-secrets.sh +23 -0
- package/.claude/settings.json +26 -0
- package/.claude/skills/deploy/SKILL.md +26 -0
- package/.claude/skills/new-plugin/SKILL.md +46 -0
- package/.dockerignore +9 -0
- package/.mcp.json +8 -0
- package/AGENTS.md +2 -2
- package/CLAUDE.md +50 -0
- package/Dockerfile +41 -0
- package/deploy/README.md +61 -0
- package/deploy/entrypoint.sh +6 -0
- package/deploy/fly.toml +36 -0
- package/dist/app/bootstrap.js +29 -0
- package/dist/app/cli.js +3 -1
- package/dist/app/cloud-mode.js +26 -0
- package/dist/app/config.js +61 -16
- package/dist/app/server.js +38 -6
- package/dist/plugins/approval/index.js +1 -1
- package/dist/plugins/bash/index.js +386 -164
- package/dist/plugins/memory/service.js +2 -5
- package/dist/plugins/openbot/context.js +17 -1
- package/dist/plugins/openbot/index.js +23 -8
- package/dist/plugins/openbot/model.js +59 -0
- package/dist/plugins/openbot/runtime.js +39 -56
- package/dist/plugins/openbot/system-prompt.js +43 -8
- package/dist/plugins/preview/index.js +267 -0
- package/dist/plugins/storage/index.js +3 -3
- package/dist/plugins/storage/service.js +58 -12
- package/dist/plugins/todo/index.js +131 -38
- package/dist/plugins/todo/service.js +93 -0
- package/dist/plugins/ui/index.js +8 -1
- package/dist/services/plugins/model-registry.js +101 -0
- package/dist/services/plugins/registry.js +6 -4
- package/dist/services/plugins/service.js +2 -6
- package/docs/agents.md +20 -2
- package/docs/architecture.md +1 -1
- package/docs/plugins.md +13 -3
- package/docs/templates/AGENT.example.md +1 -1
- package/package.json +5 -2
- package/pnpm-workspace.yaml +2 -0
- package/src/app/bootstrap.ts +43 -0
- package/src/app/cli.ts +3 -1
- package/src/app/cloud-mode.ts +41 -0
- package/src/app/config.ts +71 -19
- package/src/app/server.ts +45 -6
- package/src/app/types.ts +162 -31
- package/src/plugins/approval/index.ts +1 -1
- package/src/plugins/bash/index.ts +498 -185
- package/src/plugins/memory/service.ts +2 -5
- package/src/plugins/openbot/context.ts +17 -1
- package/src/plugins/openbot/index.ts +25 -10
- package/src/plugins/openbot/model.ts +76 -0
- package/src/plugins/openbot/runtime.ts +47 -69
- package/src/plugins/openbot/system-prompt.ts +43 -8
- package/src/plugins/preview/index.ts +323 -0
- package/src/plugins/storage/index.ts +5 -8
- package/src/plugins/storage/service.ts +79 -15
- package/src/plugins/todo/index.ts +166 -0
- package/src/plugins/todo/service.ts +123 -0
- package/src/plugins/ui/index.ts +8 -1
- package/src/services/plugins/domain.ts +2 -0
- package/src/services/plugins/model-registry.ts +146 -0
- package/src/services/plugins/registry.ts +6 -4
- package/src/services/plugins/service.ts +2 -6
- package/dist/agents/openbot/index.js +0 -76
- package/dist/agents/openbot/middleware/approval.js +0 -132
- package/dist/agents/openbot/runtime.js +0 -289
- package/dist/agents/openbot/system-prompt.js +0 -32
- package/dist/agents/openbot/tools/delegation.js +0 -78
- package/dist/agents/openbot/tools/mcp.js +0 -99
- package/dist/agents/openbot/tools/shell.js +0 -91
- package/dist/agents/openbot/tools/storage.js +0 -75
- package/dist/agents/openbot/tools/ui.js +0 -176
- package/dist/agents/system.js +0 -33
- package/dist/bus/agent-package.js +0 -1
- package/dist/bus/plugin.js +0 -1
- package/dist/bus/services.js +0 -754
- package/dist/bus/types.js +0 -1
- package/dist/harness/agent-harness.js +0 -45
- package/dist/harness/agent-invoke-run.js +0 -44
- package/dist/harness/agent-turn.js +0 -99
- package/dist/harness/channel-participants.js +0 -40
- package/dist/harness/constants.js +0 -2
- package/dist/harness/context-meter.js +0 -97
- package/dist/harness/context.js +0 -363
- package/dist/harness/dispatch.js +0 -144
- package/dist/harness/dispatcher.js +0 -156
- package/dist/harness/event-normalizer.js +0 -59
- package/dist/harness/history.js +0 -177
- package/dist/harness/mcp.js +0 -61
- package/dist/harness/orchestration.js +0 -88
- package/dist/harness/orchestrator.js +0 -149
- package/dist/harness/participants.js +0 -22
- package/dist/harness/process.js +0 -29
- package/dist/harness/queue-processor.js +0 -187
- package/dist/harness/run-harness.js +0 -154
- package/dist/harness/run.js +0 -98
- package/dist/harness/runtime-factory.js +0 -73
- package/dist/harness/runtime.js +0 -57
- package/dist/harness/todo-advance.js +0 -93
- package/dist/harness/todo-dispatch.js +0 -51
- package/dist/harness/todos.js +0 -5
- package/dist/harness/turn.js +0 -79
- package/dist/harness/types.js +0 -1
- package/dist/plugins/ai-sdk/index.js +0 -34
- package/dist/plugins/ai-sdk/runtime.js +0 -395
- package/dist/plugins/ai-sdk/system-prompt.js +0 -18
- package/dist/plugins/ai-sdk.js +0 -331
- package/dist/plugins/approval.js +0 -163
- package/dist/plugins/delegation.js +0 -108
- package/dist/plugins/mcp/index.js +0 -108
- package/dist/plugins/mcp.js +0 -140
- package/dist/plugins/shell/index.js +0 -100
- package/dist/plugins/shell.js +0 -123
- package/dist/plugins/storage-tools/index.js +0 -76
- package/dist/plugins/storage.js +0 -737
- package/dist/plugins/thread-namer/index.js +0 -72
- package/dist/plugins/threads/index.js +0 -114
- package/dist/plugins/ui.js +0 -211
- package/dist/plugins/workflow/index.js +0 -65
- package/dist/registry/agents.js +0 -138
- package/dist/registry/plugins.js +0 -110
- package/dist/services/agent-packages.js +0 -103
- package/dist/services/memory.js +0 -152
- package/dist/services/plugins.js +0 -98
- package/dist/services/storage.js +0 -1028
- package/dist/workflow/service.js +0 -106
- package/dist/workflow/types.js +0 -3
package/src/app/server.ts
CHANGED
|
@@ -8,7 +8,8 @@ import { createRequire } from 'module';
|
|
|
8
8
|
const require = createRequire(import.meta.url);
|
|
9
9
|
const pkg = require('../../package.json');
|
|
10
10
|
import { generateId } from 'melony';
|
|
11
|
-
import {
|
|
11
|
+
import { getBaseDir, loadConfig } from '../app/config.js';
|
|
12
|
+
import { isCloudMode, getCloudIntegrationsConfig } from './cloud-mode.js';
|
|
12
13
|
import { ActiveRunsSnapshotEvent, OpenBotEvent, OpenBotState } from './types.js';
|
|
13
14
|
import { processService } from '../services/process.js';
|
|
14
15
|
import { runAgent, STATE_AGENT_ID, ORCHESTRATOR_AGENT_ID } from '../harness/index.js';
|
|
@@ -46,8 +47,14 @@ export async function startServer(options: ServerOptions = {}) {
|
|
|
46
47
|
const config = loadConfig();
|
|
47
48
|
processService.syncWorkspaceVariablesToProcessEnv();
|
|
48
49
|
|
|
49
|
-
|
|
50
|
-
|
|
50
|
+
if (isCloudMode()) {
|
|
51
|
+
const integrations = getCloudIntegrationsConfig();
|
|
52
|
+
console.log(
|
|
53
|
+
`[server] Cloud mode enabled${integrations ? '' : ' (integrations proxy env not set)'}`,
|
|
54
|
+
);
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
const openBotDir = getBaseDir();
|
|
51
58
|
const PORT = Number(options.port ?? config.port ?? process.env.PORT ?? 4132);
|
|
52
59
|
const app = express();
|
|
53
60
|
const clients: Map<string, express.Response[]> = new Map();
|
|
@@ -247,6 +254,23 @@ export async function startServer(options: ServerOptions = {}) {
|
|
|
247
254
|
|
|
248
255
|
app.use(cors());
|
|
249
256
|
|
|
257
|
+
const gatewayToken = process.env.OPENBOT_GATEWAY_TOKEN?.trim();
|
|
258
|
+
if (gatewayToken) {
|
|
259
|
+
app.use((req, res, next) => {
|
|
260
|
+
if (req.path === '/api/health' || req.method === 'OPTIONS') {
|
|
261
|
+
next();
|
|
262
|
+
return;
|
|
263
|
+
}
|
|
264
|
+
|
|
265
|
+
const got = req.get('x-openbot-gateway-token');
|
|
266
|
+
if (got !== gatewayToken) {
|
|
267
|
+
res.status(401).json({ error: 'unauthorized' });
|
|
268
|
+
return;
|
|
269
|
+
}
|
|
270
|
+
next();
|
|
271
|
+
});
|
|
272
|
+
}
|
|
273
|
+
|
|
250
274
|
const resolvePublicBaseUrl = () => getPublicBaseUrl(PORT, config.publicUrl);
|
|
251
275
|
|
|
252
276
|
app.use((req, res, next) => {
|
|
@@ -264,7 +288,7 @@ export async function startServer(options: ServerOptions = {}) {
|
|
|
264
288
|
});
|
|
265
289
|
|
|
266
290
|
app.get('/api/health', (req, res) => {
|
|
267
|
-
res.json({ status: 'ok', version: pkg.version });
|
|
291
|
+
res.json({ status: 'ok', version: pkg.version, apiVersion: 1 });
|
|
268
292
|
});
|
|
269
293
|
|
|
270
294
|
app.get('/api/events', (req, res) => {
|
|
@@ -683,10 +707,25 @@ export async function startServer(options: ServerOptions = {}) {
|
|
|
683
707
|
}
|
|
684
708
|
});
|
|
685
709
|
|
|
686
|
-
|
|
687
|
-
|
|
710
|
+
const HOST = process.env.HOST || '0.0.0.0';
|
|
711
|
+
const server = app.listen(PORT, HOST, () => {
|
|
712
|
+
console.log(`\x1b[32mOpenBot server listening at http://${HOST}:${PORT}\x1b[0m`);
|
|
688
713
|
console.log(
|
|
689
714
|
`🌐 Visit \x1b[96m\x1b[1mhttps://openbot.one\x1b[0m to connect to this runtime and manage everything from there. ✨`,
|
|
690
715
|
);
|
|
691
716
|
});
|
|
717
|
+
|
|
718
|
+
const shutdown = (signal: string) => {
|
|
719
|
+
console.log(`\n[server] Received ${signal}, shutting down...`);
|
|
720
|
+
server.close(() => {
|
|
721
|
+
process.exit(0);
|
|
722
|
+
});
|
|
723
|
+
setTimeout(() => {
|
|
724
|
+
console.error('[server] Forced shutdown after timeout');
|
|
725
|
+
process.exit(1);
|
|
726
|
+
}, 10_000).unref();
|
|
727
|
+
};
|
|
728
|
+
|
|
729
|
+
process.on('SIGTERM', () => shutdown('SIGTERM'));
|
|
730
|
+
process.on('SIGINT', () => shutdown('SIGINT'));
|
|
692
731
|
}
|
package/src/app/types.ts
CHANGED
|
@@ -9,6 +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 '../plugins/todo/service.js';
|
|
12
13
|
|
|
13
14
|
export interface OpenBotState {
|
|
14
15
|
agentId: string;
|
|
@@ -657,11 +658,21 @@ export type UIWidgetField = {
|
|
|
657
658
|
defaultValue?: unknown;
|
|
658
659
|
};
|
|
659
660
|
|
|
661
|
+
export type UIWidgetListItemStatusVariant =
|
|
662
|
+
| 'default'
|
|
663
|
+
| 'success'
|
|
664
|
+
| 'warning'
|
|
665
|
+
| 'danger'
|
|
666
|
+
| 'info';
|
|
667
|
+
|
|
660
668
|
export type UIWidgetListItem = {
|
|
661
669
|
id: string;
|
|
662
670
|
label: string;
|
|
663
671
|
description?: string;
|
|
664
|
-
status
|
|
672
|
+
/** Optional status label shown on the item (e.g. "Pending", "Shipped") */
|
|
673
|
+
status?: string;
|
|
674
|
+
/** Optional semantic hint for status coloring in the client */
|
|
675
|
+
statusVariant?: UIWidgetListItemStatusVariant;
|
|
665
676
|
metadata?: Record<string, unknown>;
|
|
666
677
|
};
|
|
667
678
|
|
|
@@ -737,11 +748,12 @@ export type UIWidgetResponseEvent = BaseEvent & {
|
|
|
737
748
|
};
|
|
738
749
|
};
|
|
739
750
|
|
|
740
|
-
export type
|
|
741
|
-
type: 'action:
|
|
751
|
+
export type ShellExecEvent = BaseEvent & {
|
|
752
|
+
type: 'action:shell_exec';
|
|
742
753
|
data: {
|
|
754
|
+
id: string;
|
|
755
|
+
exec_dir: string;
|
|
743
756
|
command: string;
|
|
744
|
-
restart?: boolean;
|
|
745
757
|
};
|
|
746
758
|
meta?: {
|
|
747
759
|
toolCallId?: string;
|
|
@@ -751,47 +763,116 @@ export type BashEvent = BaseEvent & {
|
|
|
751
763
|
};
|
|
752
764
|
};
|
|
753
765
|
|
|
754
|
-
export type
|
|
755
|
-
type: 'action:
|
|
766
|
+
export type ShellExecResultEvent = BaseEvent & {
|
|
767
|
+
type: 'action:shell_exec:result';
|
|
756
768
|
data: {
|
|
757
769
|
success: boolean;
|
|
758
770
|
approved?: boolean;
|
|
759
|
-
exitCode
|
|
760
|
-
stdout: string;
|
|
761
|
-
stderr: string;
|
|
762
|
-
timedOut: boolean;
|
|
771
|
+
exitCode?: number;
|
|
763
772
|
error?: string;
|
|
773
|
+
output?: string;
|
|
764
774
|
};
|
|
765
775
|
};
|
|
766
776
|
|
|
767
|
-
export type
|
|
768
|
-
type: 'action:
|
|
777
|
+
export type ShellViewEvent = BaseEvent & {
|
|
778
|
+
type: 'action:shell_view';
|
|
769
779
|
data: {
|
|
770
|
-
|
|
780
|
+
id: string;
|
|
771
781
|
};
|
|
772
782
|
};
|
|
773
783
|
|
|
774
|
-
export type
|
|
775
|
-
type: 'action:
|
|
784
|
+
export type ShellViewResultEvent = BaseEvent & {
|
|
785
|
+
type: 'action:shell_view:result';
|
|
776
786
|
data: {
|
|
777
787
|
success: boolean;
|
|
788
|
+
output?: string;
|
|
778
789
|
};
|
|
779
790
|
};
|
|
780
791
|
|
|
781
|
-
export type
|
|
782
|
-
type: 'action:
|
|
783
|
-
data: {
|
|
792
|
+
export type ShellWaitEvent = BaseEvent & {
|
|
793
|
+
type: 'action:shell_wait';
|
|
794
|
+
data: {
|
|
795
|
+
id: string;
|
|
796
|
+
seconds: number;
|
|
797
|
+
};
|
|
784
798
|
};
|
|
785
799
|
|
|
786
|
-
export type
|
|
787
|
-
type: 'action:
|
|
800
|
+
export type ShellWaitResultEvent = BaseEvent & {
|
|
801
|
+
type: 'action:shell_wait:result';
|
|
788
802
|
data: {
|
|
789
803
|
success: boolean;
|
|
790
|
-
|
|
791
|
-
|
|
792
|
-
|
|
793
|
-
|
|
794
|
-
|
|
804
|
+
waitedSeconds?: number;
|
|
805
|
+
output?: string;
|
|
806
|
+
};
|
|
807
|
+
};
|
|
808
|
+
|
|
809
|
+
export type ShellWriteToProcessEvent = BaseEvent & {
|
|
810
|
+
type: 'action:shell_write_to_process';
|
|
811
|
+
data: {
|
|
812
|
+
id: string;
|
|
813
|
+
input: string;
|
|
814
|
+
press_enter: boolean;
|
|
815
|
+
};
|
|
816
|
+
};
|
|
817
|
+
|
|
818
|
+
export type ShellWriteToProcessResultEvent = BaseEvent & {
|
|
819
|
+
type: 'action:shell_write_to_process:result';
|
|
820
|
+
data: {
|
|
821
|
+
success: boolean;
|
|
822
|
+
output?: string;
|
|
823
|
+
};
|
|
824
|
+
};
|
|
825
|
+
|
|
826
|
+
export type ShellKillProcessEvent = BaseEvent & {
|
|
827
|
+
type: 'action:shell_kill_process';
|
|
828
|
+
data: {
|
|
829
|
+
id: string;
|
|
830
|
+
};
|
|
831
|
+
};
|
|
832
|
+
|
|
833
|
+
export type ShellKillProcessResultEvent = BaseEvent & {
|
|
834
|
+
type: 'action:shell_kill_process:result';
|
|
835
|
+
data: {
|
|
836
|
+
success: boolean;
|
|
837
|
+
output?: string;
|
|
838
|
+
};
|
|
839
|
+
};
|
|
840
|
+
|
|
841
|
+
export type ExposePortEvent = BaseEvent & {
|
|
842
|
+
type: 'action:expose_port';
|
|
843
|
+
data: {
|
|
844
|
+
port: number;
|
|
845
|
+
};
|
|
846
|
+
meta?: {
|
|
847
|
+
toolCallId?: string;
|
|
848
|
+
approvalId?: string;
|
|
849
|
+
approvalStatus?: 'approved' | 'denied';
|
|
850
|
+
[key: string]: unknown;
|
|
851
|
+
};
|
|
852
|
+
};
|
|
853
|
+
|
|
854
|
+
export type ExposePortResultEvent = BaseEvent & {
|
|
855
|
+
type: 'action:expose_port:result';
|
|
856
|
+
data: {
|
|
857
|
+
success: boolean;
|
|
858
|
+
previewUrl?: string;
|
|
859
|
+
port?: number;
|
|
860
|
+
temporary?: boolean;
|
|
861
|
+
error?: string;
|
|
862
|
+
output?: string;
|
|
863
|
+
};
|
|
864
|
+
};
|
|
865
|
+
|
|
866
|
+
export type UnexposePortEvent = BaseEvent & {
|
|
867
|
+
type: 'action:unexpose_port';
|
|
868
|
+
data?: Record<string, never>;
|
|
869
|
+
};
|
|
870
|
+
|
|
871
|
+
export type UnexposePortResultEvent = BaseEvent & {
|
|
872
|
+
type: 'action:unexpose_port:result';
|
|
873
|
+
data: {
|
|
874
|
+
success: boolean;
|
|
875
|
+
output?: string;
|
|
795
876
|
};
|
|
796
877
|
};
|
|
797
878
|
|
|
@@ -968,6 +1049,44 @@ export type ForgetResultEvent = BaseEvent & {
|
|
|
968
1049
|
};
|
|
969
1050
|
};
|
|
970
1051
|
|
|
1052
|
+
export type TodoWriteEvent = BaseEvent & {
|
|
1053
|
+
type: 'action:todo_write';
|
|
1054
|
+
data: {
|
|
1055
|
+
items: Array<{
|
|
1056
|
+
id: string;
|
|
1057
|
+
content: string;
|
|
1058
|
+
status: 'pending' | 'in_progress' | 'completed' | 'cancelled';
|
|
1059
|
+
}>;
|
|
1060
|
+
};
|
|
1061
|
+
};
|
|
1062
|
+
|
|
1063
|
+
export type TodoWriteResultEvent = BaseEvent & {
|
|
1064
|
+
type: 'action:todo_write:result';
|
|
1065
|
+
data: {
|
|
1066
|
+
success: boolean;
|
|
1067
|
+
list?: TodoList;
|
|
1068
|
+
/** Text fed back to the model via history (`data.output`). */
|
|
1069
|
+
output: string;
|
|
1070
|
+
error?: string;
|
|
1071
|
+
};
|
|
1072
|
+
};
|
|
1073
|
+
|
|
1074
|
+
export type TodoReadEvent = BaseEvent & {
|
|
1075
|
+
type: 'action:todo_read';
|
|
1076
|
+
data: Record<string, never>;
|
|
1077
|
+
};
|
|
1078
|
+
|
|
1079
|
+
export type TodoReadResultEvent = BaseEvent & {
|
|
1080
|
+
type: 'action:todo_read:result';
|
|
1081
|
+
data: {
|
|
1082
|
+
success: boolean;
|
|
1083
|
+
list?: TodoList;
|
|
1084
|
+
/** Text fed back to the model via history (`data.output`). */
|
|
1085
|
+
output: string;
|
|
1086
|
+
error?: string;
|
|
1087
|
+
};
|
|
1088
|
+
};
|
|
1089
|
+
|
|
971
1090
|
export type DelegateTaskEvent = BaseEvent & {
|
|
972
1091
|
type: 'action:delegate_task';
|
|
973
1092
|
data: {
|
|
@@ -1101,12 +1220,20 @@ export type OpenBotEvent =
|
|
|
1101
1220
|
| DeleteChannelToolResultEvent
|
|
1102
1221
|
| UIWidgetEvent
|
|
1103
1222
|
| UIWidgetResponseEvent
|
|
1104
|
-
|
|
|
1105
|
-
|
|
|
1106
|
-
|
|
|
1107
|
-
|
|
|
1108
|
-
|
|
|
1109
|
-
|
|
|
1223
|
+
| ShellExecEvent
|
|
1224
|
+
| ShellExecResultEvent
|
|
1225
|
+
| ShellViewEvent
|
|
1226
|
+
| ShellViewResultEvent
|
|
1227
|
+
| ShellWaitEvent
|
|
1228
|
+
| ShellWaitResultEvent
|
|
1229
|
+
| ShellWriteToProcessEvent
|
|
1230
|
+
| ShellWriteToProcessResultEvent
|
|
1231
|
+
| ShellKillProcessEvent
|
|
1232
|
+
| ShellKillProcessResultEvent
|
|
1233
|
+
| ExposePortEvent
|
|
1234
|
+
| ExposePortResultEvent
|
|
1235
|
+
| UnexposePortEvent
|
|
1236
|
+
| UnexposePortResultEvent
|
|
1110
1237
|
| InstallPluginEvent
|
|
1111
1238
|
| InstallPluginResultEvent
|
|
1112
1239
|
| UninstallPluginEvent
|
|
@@ -1123,6 +1250,10 @@ export type OpenBotEvent =
|
|
|
1123
1250
|
| RecallResultEvent
|
|
1124
1251
|
| ForgetEvent
|
|
1125
1252
|
| ForgetResultEvent
|
|
1253
|
+
| TodoWriteEvent
|
|
1254
|
+
| TodoWriteResultEvent
|
|
1255
|
+
| TodoReadEvent
|
|
1256
|
+
| TodoReadResultEvent
|
|
1126
1257
|
| DelegateTaskEvent
|
|
1127
1258
|
| DelegateTaskResultEvent
|
|
1128
1259
|
| RenderWidgetEvent
|
|
@@ -19,7 +19,7 @@ export const approvalPlugin: Plugin = {
|
|
|
19
19
|
description: 'Gate protected tool calls behind a UI confirmation widget.',
|
|
20
20
|
factory: ({ config, storage }) => (builder) => {
|
|
21
21
|
// Actions that require approval. Defaults to bash.
|
|
22
|
-
const actionsToApprove = (config.actions as string[]) || ['action:
|
|
22
|
+
const actionsToApprove = (config.actions as string[]) || ['action:shell_exec'];
|
|
23
23
|
|
|
24
24
|
for (const action of actionsToApprove) {
|
|
25
25
|
builder.intercept(action as OpenBotEvent['type'], (event, context) => {
|