openbot 0.3.6 → 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 (96) 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/bus/services.js +34 -124
  7. package/dist/harness/agent-invoke-run.js +44 -0
  8. package/dist/harness/agent-turn.js +99 -0
  9. package/dist/harness/channel-participants.js +40 -0
  10. package/dist/harness/constants.js +2 -0
  11. package/dist/harness/context-meter.js +97 -0
  12. package/dist/harness/context.js +95 -47
  13. package/dist/harness/dispatch.js +144 -0
  14. package/dist/harness/dispatcher.js +45 -156
  15. package/dist/harness/history.js +177 -0
  16. package/dist/harness/index.js +91 -0
  17. package/dist/harness/orchestration.js +88 -0
  18. package/dist/harness/participants.js +22 -0
  19. package/dist/harness/run-harness.js +154 -0
  20. package/dist/harness/run.js +98 -0
  21. package/dist/harness/runtime-factory.js +0 -34
  22. package/dist/harness/runtime.js +57 -0
  23. package/dist/harness/todo-dispatch.js +51 -0
  24. package/dist/harness/todos.js +5 -0
  25. package/dist/harness/turn.js +79 -0
  26. package/dist/plugins/approval/index.js +105 -149
  27. package/dist/plugins/delegation/index.js +119 -32
  28. package/dist/plugins/memory/index.js +103 -14
  29. package/dist/plugins/memory/service.js +152 -0
  30. package/dist/plugins/openbot/context.js +80 -0
  31. package/dist/plugins/openbot/history.js +98 -0
  32. package/dist/plugins/openbot/index.js +31 -0
  33. package/dist/plugins/openbot/runtime.js +317 -0
  34. package/dist/plugins/openbot/system-prompt.js +5 -0
  35. package/dist/plugins/plugin-manager/index.js +105 -0
  36. package/dist/plugins/storage/index.js +573 -0
  37. package/dist/plugins/storage/service.js +1159 -0
  38. package/dist/plugins/storage-tools/index.js +2 -2
  39. package/dist/plugins/thread-namer/index.js +72 -0
  40. package/dist/plugins/thread-naming/generate-title.js +44 -0
  41. package/dist/plugins/thread-naming/index.js +103 -0
  42. package/dist/plugins/threads/index.js +114 -0
  43. package/dist/plugins/todo/index.js +24 -25
  44. package/dist/plugins/ui/index.js +2 -32
  45. package/dist/registry/plugins.js +3 -9
  46. package/dist/services/plugins/domain.js +1 -0
  47. package/dist/services/plugins/plugin-cache.js +9 -0
  48. package/dist/services/plugins/registry.js +110 -0
  49. package/dist/services/plugins/service.js +177 -0
  50. package/dist/services/plugins/types.js +1 -0
  51. package/dist/services/process.js +29 -0
  52. package/dist/services/storage.js +11 -10
  53. package/dist/services/thread-naming.js +81 -0
  54. package/docs/agents.md +16 -10
  55. package/docs/architecture.md +2 -2
  56. package/docs/plugins.md +6 -15
  57. package/docs/templates/AGENT.example.md +7 -13
  58. package/package.json +1 -2
  59. package/src/app/agent-ids.ts +5 -0
  60. package/src/app/cli.ts +1 -1
  61. package/src/app/config.ts +1 -31
  62. package/src/app/server.ts +8 -16
  63. package/src/app/types.ts +63 -189
  64. package/src/harness/index.ts +145 -0
  65. package/src/plugins/approval/index.ts +91 -189
  66. package/src/plugins/delegation/index.ts +136 -39
  67. package/src/plugins/memory/index.ts +112 -15
  68. package/src/{services/memory.ts → plugins/memory/service.ts} +1 -1
  69. package/src/plugins/openbot/context.ts +91 -0
  70. package/src/plugins/openbot/history.ts +107 -0
  71. package/src/plugins/openbot/index.ts +37 -0
  72. package/src/plugins/openbot/runtime.ts +384 -0
  73. package/src/plugins/openbot/system-prompt.ts +7 -0
  74. package/src/plugins/plugin-manager/index.ts +122 -0
  75. package/src/plugins/shell/index.ts +1 -1
  76. package/src/plugins/storage/index.ts +633 -0
  77. package/src/{services/storage.ts → plugins/storage/service.ts} +224 -67
  78. package/src/{bus/types.ts → services/plugins/domain.ts} +16 -7
  79. package/src/services/plugins/plugin-cache.ts +13 -0
  80. package/src/{registry/plugins.ts → services/plugins/registry.ts} +25 -27
  81. package/src/services/{plugins.ts → plugins/service.ts} +96 -2
  82. package/src/{bus/plugin.ts → services/plugins/types.ts} +3 -3
  83. package/src/bus/services.ts +0 -954
  84. package/src/harness/context.ts +0 -365
  85. package/src/harness/dispatcher.ts +0 -379
  86. package/src/harness/mcp.ts +0 -78
  87. package/src/harness/runtime-factory.ts +0 -129
  88. package/src/harness/todo-advance.ts +0 -128
  89. package/src/plugins/ai-sdk/index.ts +0 -41
  90. package/src/plugins/ai-sdk/runtime.ts +0 -468
  91. package/src/plugins/ai-sdk/system-prompt.ts +0 -18
  92. package/src/plugins/mcp/index.ts +0 -128
  93. package/src/plugins/storage-tools/index.ts +0 -90
  94. package/src/plugins/todo/index.ts +0 -64
  95. package/src/plugins/ui/index.ts +0 -227
  96. /package/src/{harness → services}/process.ts +0 -0
package/src/app/types.ts CHANGED
@@ -6,9 +6,9 @@ import {
6
6
  PluginDescriptor,
7
7
  Thread,
8
8
  ThreadDetails,
9
- } from '../bus/types.js';
10
- import type { PluginRef } from '../bus/plugin.js';
11
- import type { MemoryRecord } from '../services/memory.js';
9
+ } from '../services/plugins/domain.js';
10
+ import type { PluginRef } from '../services/plugins/types.js';
11
+ import type { MemoryRecord } from '../plugins/memory/service.js';
12
12
 
13
13
  export interface OpenBotState {
14
14
  agentId: string;
@@ -19,15 +19,10 @@ export interface OpenBotState {
19
19
  channelDetails?: ChannelDetails;
20
20
  threadDetails?: ThreadDetails;
21
21
  triggerEvent?: OpenBotEvent;
22
- shortTermMessages?: ShortTermMessage[];
22
+ /** Active model string (e.g. `openai/gpt-4o-mini`). */
23
+ model?: string;
23
24
  }
24
25
 
25
- export type ShortTermMessage =
26
- | { role: 'system'; content: string }
27
- | { role: 'user'; content: string }
28
- | { role: 'assistant'; content: string; toolCalls?: any[] }
29
- | { role: 'tool'; content: string; toolCallId: string; toolName: string };
30
-
31
26
  export type BaseEvent = {
32
27
  id?: string;
33
28
  type: string;
@@ -144,6 +139,7 @@ export type CreateAgentEvent = BaseEvent & {
144
139
  name: string;
145
140
  description?: string;
146
141
  image?: string;
142
+ hidden?: boolean;
147
143
  instructions: string;
148
144
  plugins: PluginRef[];
149
145
  };
@@ -164,6 +160,7 @@ export type UpdateAgentEvent = BaseEvent & {
164
160
  name?: string;
165
161
  description?: string;
166
162
  image?: string;
163
+ hidden?: boolean;
167
164
  instructions?: string;
168
165
  plugins?: PluginRef[];
169
166
  };
@@ -509,12 +506,26 @@ export type UIWidgetListItem = {
509
506
  metadata?: Record<string, unknown>;
510
507
  };
511
508
 
509
+ export type UIMediaItem = {
510
+ type: 'image' | 'video' | 'audio' | 'file';
511
+ url: string;
512
+ title?: string;
513
+ alt?: string;
514
+ thumbnailUrl?: string;
515
+ metadata?: Record<string, unknown>;
516
+ };
517
+
512
518
  export type UIWidgetBase = {
513
519
  widgetId: string;
514
520
  title?: string;
515
521
  description?: string;
516
- body?: string;
522
+ /** Optional hero media for the widget */
523
+ media?: UIMediaItem;
524
+ /** Optional actions for the widget */
525
+ actions?: UIWidgetAction[];
517
526
  state?: 'open' | 'submitted' | 'cancelled' | 'error';
527
+ display?: 'expanded' | 'collapsed';
528
+ size?: 'small' | 'medium' | 'large' | 'full';
518
529
  metadata?: Record<string, unknown>;
519
530
  };
520
531
 
@@ -543,19 +554,6 @@ export type UIListWidget = UIWidgetBase & {
543
554
 
544
555
  export type UIWidgetSpec = UIMessageWidget | UIChoiceWidget | UIFormWidget | UIListWidget;
545
556
 
546
- export type RenderUIWidgetData =
547
- | (Omit<UIMessageWidget, 'widgetId'> & { widgetId?: string })
548
- | (Omit<UIChoiceWidget, 'widgetId'> & { widgetId?: string })
549
- | (Omit<UIFormWidget, 'widgetId'> & { widgetId?: string })
550
- | (Omit<UIListWidget, 'widgetId'> & { widgetId?: string })
551
- | {
552
- kind: 'approval' | 'todo_list';
553
- widgetId?: string;
554
- title?: string;
555
- props?: Record<string, unknown>;
556
- metadata?: Record<string, unknown>;
557
- };
558
-
559
557
  export type UIWidgetEvent = BaseEvent & {
560
558
  type: 'client:ui:widget';
561
559
  data: UIWidgetSpec;
@@ -565,11 +563,6 @@ export type UIWidgetEvent = BaseEvent & {
565
563
  };
566
564
  };
567
565
 
568
- export type RenderUIWidgetEvent = BaseEvent & {
569
- type: 'action:render_ui_widget';
570
- data: RenderUIWidgetData;
571
- };
572
-
573
566
  export type UIWidgetResponseEvent = BaseEvent & {
574
567
  type: 'client:ui:widget:response';
575
568
  data: {
@@ -580,80 +573,6 @@ export type UIWidgetResponseEvent = BaseEvent & {
580
573
  };
581
574
  };
582
575
 
583
- export type HandoffEvent = BaseEvent & {
584
- type: 'action:handoff';
585
- data: {
586
- agentId: string;
587
- content: string;
588
- };
589
- meta?: {
590
- toolCallId?: string;
591
- [key: string]: any;
592
- };
593
- };
594
-
595
- export type HandoffResultEvent = BaseEvent & {
596
- type: 'action:handoff:result';
597
- data: {
598
- success: boolean;
599
- agentId: string;
600
- accepted: boolean;
601
- };
602
- meta: {
603
- toolCallId: string;
604
- agentId: string;
605
- threadId?: string;
606
- [key: string]: any;
607
- };
608
- };
609
-
610
- /** Internal routing: handoff plugin → orchestrator only (not stored or broadcast). */
611
- export type HandoffRequestEvent = BaseEvent & {
612
- type: 'handoff:request';
613
- data: {
614
- agentId: string;
615
- content: string;
616
- };
617
- meta?: Record<string, unknown>;
618
- };
619
-
620
- export type MCPListToolsEvent = BaseEvent & {
621
- type: 'action:mcp_list_tools';
622
- data: {
623
- serverId: string;
624
- };
625
- };
626
-
627
- export type MCPListToolsResultEvent = BaseEvent & {
628
- type: 'action:mcp_list_tools:result';
629
- data: {
630
- success: boolean;
631
- serverId: string;
632
- tools: Array<{ name: string; description?: string; inputSchema?: unknown }>;
633
- error?: string;
634
- };
635
- };
636
-
637
- export type MCPCallEvent = BaseEvent & {
638
- type: 'action:mcp_call';
639
- data: {
640
- serverId: string;
641
- toolName: string;
642
- args?: Record<string, unknown>;
643
- };
644
- };
645
-
646
- export type MCPCallResultEvent = BaseEvent & {
647
- type: 'action:mcp_call:result';
648
- data: {
649
- success: boolean;
650
- serverId: string;
651
- toolName: string;
652
- result?: unknown;
653
- error?: string;
654
- };
655
- };
656
-
657
576
  export type ShellExecEvent = BaseEvent & {
658
577
  type: 'action:shell_exec';
659
578
  data: {
@@ -683,18 +602,6 @@ export type ShellExecResultEvent = BaseEvent & {
683
602
  };
684
603
  };
685
604
 
686
- export type UserInputEvent = BaseEvent & {
687
- type: 'user:input';
688
- data: {
689
- content: string;
690
- };
691
- meta?: {
692
- userId?: string;
693
- userName?: string;
694
- userAvatarUrl?: string;
695
- };
696
- };
697
-
698
605
  export type InstallPluginEvent = BaseEvent & {
699
606
  type: 'action:plugin:install';
700
607
  data: {
@@ -770,6 +677,25 @@ export type InstallAgentResultEvent = BaseEvent & {
770
677
 
771
678
  export type MemoryScopeAlias = 'global' | 'agent' | 'channel';
772
679
 
680
+ export interface Usage {
681
+ promptTokens: number;
682
+ completionTokens: number;
683
+ totalTokens: number;
684
+ }
685
+
686
+ export type AgentUsageEvent = BaseEvent & {
687
+ type: 'agent:usage';
688
+ data: {
689
+ usage: Usage;
690
+ model?: string;
691
+ };
692
+ meta: {
693
+ agentId: string;
694
+ threadId?: string;
695
+ runId?: string;
696
+ };
697
+ };
698
+
773
699
  export type RememberEvent = BaseEvent & {
774
700
  type: 'action:remember';
775
701
  data: {
@@ -821,83 +747,41 @@ export type ForgetResultEvent = BaseEvent & {
821
747
  };
822
748
  };
823
749
 
824
- export type TodoStatus = 'pending' | 'in_progress' | 'done' | 'cancelled';
825
-
826
- /**
827
- * A single unit of work tracked in thread state. Todos are owned by the
828
- * system (bus services); agents can only mutate them by calling the
829
- * `todo_write` / `todo_update` tools so every change is observable on the
830
- * event stream and audit-friendly.
831
- */
832
- export interface TodoItem {
833
- id: string;
834
- content: string;
835
- status: TodoStatus;
836
- /** Optional agent id responsible for this item — drives autonomous handoffs. */
837
- assignee?: string;
838
- /** Agent id that created the todo (or "system"). */
839
- createdBy: string;
840
- createdAt: number;
841
- updatedAt: number;
842
- /**
843
- * Captured final reply when this item reaches `done` (last `agent:output`
844
- * from the assignee for that run). Lets downstream agents rely on thread
845
- * state instead of merged short-term messages.
846
- */
847
- result?: string;
848
- }
849
-
850
- export type TodoWriteInput = {
851
- id?: string;
852
- content: string;
853
- status?: TodoStatus;
854
- assignee?: string;
855
- };
856
-
857
- export type TodoWriteEvent = BaseEvent & {
858
- type: 'action:todo_write';
750
+ export type DelegateTaskEvent = BaseEvent & {
751
+ type: 'action:delegate_task';
859
752
  data: {
860
- todos: TodoWriteInput[];
753
+ agentId: string;
754
+ prompt: string;
861
755
  };
862
- meta?: { toolCallId?: string; agentId?: string; threadId?: string };
863
756
  };
864
757
 
865
- export type TodoWriteResultEvent = BaseEvent & {
866
- type: 'action:todo_write:result';
758
+ export type DelegateTaskResultEvent = BaseEvent & {
759
+ type: 'action:delegate_task:result';
867
760
  data: {
868
761
  success: boolean;
869
- todos: TodoItem[];
762
+ output?: string;
870
763
  error?: string;
871
764
  };
872
- meta?: { toolCallId?: string; agentId?: string; threadId?: string };
873
765
  };
874
766
 
875
- export type TodoUpdateEvent = BaseEvent & {
876
- type: 'action:todo_update';
877
- data: {
878
- id: string;
879
- status?: TodoStatus;
880
- content?: string;
881
- assignee?: string;
882
- };
883
- meta?: { toolCallId?: string; agentId?: string; threadId?: string };
884
- };
767
+ /**
768
+ * Internal message representation to decouple harness history from specific AI SDKs.
769
+ */
770
+ export type OpenBotMessage =
771
+ | { role: 'user'; content: string | OpenBotMessagePart[] }
772
+ | { role: 'assistant'; content: string | OpenBotMessagePart[] }
773
+ | { role: 'system'; content: string }
774
+ | { role: 'tool'; content: OpenBotMessagePart[] };
885
775
 
886
- export type TodoUpdateResultEvent = BaseEvent & {
887
- type: 'action:todo_update:result';
888
- data: {
889
- success: boolean;
890
- todo?: TodoItem;
891
- todos: TodoItem[];
892
- error?: string;
893
- };
894
- meta?: { toolCallId?: string; agentId?: string; threadId?: string };
895
- };
776
+ export type OpenBotMessagePart =
777
+ | { type: 'text'; text: string }
778
+ | { type: 'tool-call'; toolCallId: string; toolName: string; input: any }
779
+ | { type: 'tool-result'; toolCallId: string; toolName: string; output: any };
896
780
 
897
781
  export type OpenBotEvent =
898
- | UserInputEvent
899
782
  | AgentInvokeEvent
900
783
  | AgentOutputEvent
784
+ | AgentUsageEvent
901
785
  | AgentRunStartEvent
902
786
  | AgentRunEndEvent
903
787
  | AgentRunStoppedEvent
@@ -952,15 +836,7 @@ export type OpenBotEvent =
952
836
  | UpdateChannelEvent
953
837
  | UpdateChannelResultEvent
954
838
  | UIWidgetEvent
955
- | RenderUIWidgetEvent
956
839
  | UIWidgetResponseEvent
957
- | HandoffEvent
958
- | HandoffResultEvent
959
- | HandoffRequestEvent
960
- | MCPListToolsEvent
961
- | MCPListToolsResultEvent
962
- | MCPCallEvent
963
- | MCPCallResultEvent
964
840
  | ShellExecEvent
965
841
  | ShellExecResultEvent
966
842
  | InstallPluginEvent
@@ -977,7 +853,5 @@ export type OpenBotEvent =
977
853
  | RecallResultEvent
978
854
  | ForgetEvent
979
855
  | ForgetResultEvent
980
- | TodoWriteEvent
981
- | TodoWriteResultEvent
982
- | TodoUpdateEvent
983
- | TodoUpdateResultEvent;
856
+ | DelegateTaskEvent
857
+ | DelegateTaskResultEvent;
@@ -0,0 +1,145 @@
1
+ import { melony } from 'melony';
2
+ import { OpenBotEvent, OpenBotState } from '../app/types.js';
3
+ import { ensureEventId } from '../app/utils.js';
4
+ import { storageService } from '../plugins/storage/service.js';
5
+ import { STATE_AGENT_ID, ORCHESTRATOR_AGENT_ID } from '../app/agent-ids.js';
6
+ import { resolvePlugin } from '../services/plugins/registry.js';
7
+ import { ToolDefinition } from '../services/plugins/types.js';
8
+
9
+ export { STATE_AGENT_ID, ORCHESTRATOR_AGENT_ID };
10
+
11
+ export interface RunAgentOptions {
12
+ runId: string;
13
+ agentId: string;
14
+ event: OpenBotEvent;
15
+ channelId: string;
16
+ threadId?: string;
17
+ persistEvents?: boolean;
18
+ onEvent: (event: OpenBotEvent, state?: OpenBotState) => Promise<void>;
19
+ }
20
+
21
+ async function emitEvent(
22
+ chunk: OpenBotEvent,
23
+ state: OpenBotState | undefined,
24
+ {
25
+ persistEvents,
26
+ channelId,
27
+ threadId,
28
+ onEvent,
29
+ parentAgentId,
30
+ parentToolCallId,
31
+ }: {
32
+ persistEvents: boolean;
33
+ channelId: string;
34
+ threadId?: string;
35
+ onEvent: RunAgentOptions['onEvent'];
36
+ parentAgentId?: string;
37
+ parentToolCallId?: string;
38
+ },
39
+ ): Promise<void> {
40
+ ensureEventId(chunk);
41
+
42
+ // Enrich event with parent metadata if not already present
43
+ if (parentAgentId || parentToolCallId) {
44
+ chunk.meta = {
45
+ ...chunk.meta,
46
+ parentAgentId: chunk.meta?.parentAgentId || parentAgentId,
47
+ parentToolCallId: chunk.meta?.parentToolCallId || parentToolCallId,
48
+ };
49
+ }
50
+
51
+ if (persistEvents) {
52
+ await storageService.storeEvent({
53
+ channelId: state?.channelId || channelId,
54
+ threadId: state?.threadId || threadId,
55
+ event: chunk,
56
+ });
57
+ }
58
+
59
+ await onEvent(chunk, state);
60
+ }
61
+
62
+ /**
63
+ * Runs a single agent turn.
64
+ * Fire and forget.
65
+ */
66
+ export async function runAgent(options: RunAgentOptions): Promise<void> {
67
+ const { runId, agentId, event, channelId, threadId, onEvent } = options;
68
+ const persistEvents = options.persistEvents !== false;
69
+
70
+ const parentAgentId = event.meta?.parentAgentId;
71
+ const parentToolCallId = event.meta?.parentToolCallId;
72
+
73
+ const agentDetails = await storageService.getAgentDetails({ agentId });
74
+
75
+ const state = await storageService.getOpenBotState({
76
+ runId,
77
+ agentId,
78
+ channelId,
79
+ threadId,
80
+ event,
81
+ });
82
+
83
+ await emitEvent(
84
+ {
85
+ type: 'agent:run:start',
86
+ data: { runId, agentId, channelId, threadId },
87
+ } as OpenBotEvent,
88
+ state,
89
+ { persistEvents, channelId, threadId, onEvent, parentAgentId, parentToolCallId },
90
+ );
91
+
92
+ try {
93
+ const pluginRefs = agentDetails.pluginRefs ?? [];
94
+ const tools: Record<string, ToolDefinition> = {};
95
+
96
+ for (const ref of pluginRefs) {
97
+ const plugin = await resolvePlugin(ref.id);
98
+ if (plugin?.toolDefinitions) {
99
+ Object.assign(tools, plugin.toolDefinitions);
100
+ }
101
+ }
102
+
103
+ const builder = melony<OpenBotState, OpenBotEvent>().initialState(state);
104
+
105
+ for (const ref of pluginRefs) {
106
+ const plugin = await resolvePlugin(ref.id);
107
+ if (!plugin) continue;
108
+
109
+ builder.use(
110
+ plugin.factory({
111
+ agentId,
112
+ agentDetails,
113
+ config: ref.config ?? {},
114
+ storage: storageService,
115
+ tools,
116
+ }),
117
+ );
118
+ }
119
+
120
+ const runtime = builder.build();
121
+ const generator = runtime.run(event, { runId, state });
122
+
123
+ for await (const outputEvent of generator) {
124
+ await emitEvent(outputEvent, state, {
125
+ persistEvents,
126
+ channelId,
127
+ threadId,
128
+ onEvent,
129
+ parentAgentId,
130
+ parentToolCallId,
131
+ });
132
+ }
133
+ } catch (error) {
134
+ console.error(`[harness] Error running agent ${agentId}:`, error);
135
+ } finally {
136
+ await emitEvent(
137
+ {
138
+ type: 'agent:run:end',
139
+ data: { runId, agentId, channelId, threadId },
140
+ } as OpenBotEvent,
141
+ state,
142
+ { persistEvents, channelId, threadId, onEvent, parentAgentId, parentToolCallId },
143
+ );
144
+ }
145
+ }