@jackchen_me/open-multi-agent 0.1.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 (133) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +280 -0
  3. package/dist/agent/agent.d.ts +121 -0
  4. package/dist/agent/agent.d.ts.map +1 -0
  5. package/dist/agent/agent.js +294 -0
  6. package/dist/agent/agent.js.map +1 -0
  7. package/dist/agent/pool.d.ts +128 -0
  8. package/dist/agent/pool.d.ts.map +1 -0
  9. package/dist/agent/pool.js +236 -0
  10. package/dist/agent/pool.js.map +1 -0
  11. package/dist/agent/runner.d.ts +120 -0
  12. package/dist/agent/runner.d.ts.map +1 -0
  13. package/dist/agent/runner.js +274 -0
  14. package/dist/agent/runner.js.map +1 -0
  15. package/dist/index.d.ts +73 -0
  16. package/dist/index.d.ts.map +1 -0
  17. package/dist/index.js +87 -0
  18. package/dist/index.js.map +1 -0
  19. package/dist/llm/adapter.d.ts +38 -0
  20. package/dist/llm/adapter.d.ts.map +1 -0
  21. package/dist/llm/adapter.js +46 -0
  22. package/dist/llm/adapter.js.map +1 -0
  23. package/dist/llm/anthropic.d.ts +56 -0
  24. package/dist/llm/anthropic.d.ts.map +1 -0
  25. package/dist/llm/anthropic.js +307 -0
  26. package/dist/llm/anthropic.js.map +1 -0
  27. package/dist/llm/openai.d.ts +62 -0
  28. package/dist/llm/openai.d.ts.map +1 -0
  29. package/dist/llm/openai.js +424 -0
  30. package/dist/llm/openai.js.map +1 -0
  31. package/dist/memory/shared.d.ts +86 -0
  32. package/dist/memory/shared.d.ts.map +1 -0
  33. package/dist/memory/shared.js +155 -0
  34. package/dist/memory/shared.js.map +1 -0
  35. package/dist/memory/store.d.ts +64 -0
  36. package/dist/memory/store.d.ts.map +1 -0
  37. package/dist/memory/store.js +103 -0
  38. package/dist/memory/store.js.map +1 -0
  39. package/dist/orchestrator/orchestrator.d.ts +173 -0
  40. package/dist/orchestrator/orchestrator.d.ts.map +1 -0
  41. package/dist/orchestrator/orchestrator.js +698 -0
  42. package/dist/orchestrator/orchestrator.js.map +1 -0
  43. package/dist/orchestrator/scheduler.d.ts +112 -0
  44. package/dist/orchestrator/scheduler.d.ts.map +1 -0
  45. package/dist/orchestrator/scheduler.js +282 -0
  46. package/dist/orchestrator/scheduler.js.map +1 -0
  47. package/dist/task/queue.d.ts +160 -0
  48. package/dist/task/queue.d.ts.map +1 -0
  49. package/dist/task/queue.js +337 -0
  50. package/dist/task/queue.js.map +1 -0
  51. package/dist/task/task.d.ts +86 -0
  52. package/dist/task/task.d.ts.map +1 -0
  53. package/dist/task/task.js +201 -0
  54. package/dist/task/task.js.map +1 -0
  55. package/dist/team/messaging.d.ts +106 -0
  56. package/dist/team/messaging.d.ts.map +1 -0
  57. package/dist/team/messaging.js +182 -0
  58. package/dist/team/messaging.js.map +1 -0
  59. package/dist/team/team.d.ts +141 -0
  60. package/dist/team/team.d.ts.map +1 -0
  61. package/dist/team/team.js +282 -0
  62. package/dist/team/team.js.map +1 -0
  63. package/dist/tool/built-in/bash.d.ts +12 -0
  64. package/dist/tool/built-in/bash.d.ts.map +1 -0
  65. package/dist/tool/built-in/bash.js +133 -0
  66. package/dist/tool/built-in/bash.js.map +1 -0
  67. package/dist/tool/built-in/file-edit.d.ts +14 -0
  68. package/dist/tool/built-in/file-edit.d.ts.map +1 -0
  69. package/dist/tool/built-in/file-edit.js +130 -0
  70. package/dist/tool/built-in/file-edit.js.map +1 -0
  71. package/dist/tool/built-in/file-read.d.ts +12 -0
  72. package/dist/tool/built-in/file-read.d.ts.map +1 -0
  73. package/dist/tool/built-in/file-read.js +82 -0
  74. package/dist/tool/built-in/file-read.js.map +1 -0
  75. package/dist/tool/built-in/file-write.d.ts +11 -0
  76. package/dist/tool/built-in/file-write.d.ts.map +1 -0
  77. package/dist/tool/built-in/file-write.js +70 -0
  78. package/dist/tool/built-in/file-write.js.map +1 -0
  79. package/dist/tool/built-in/grep.d.ts +15 -0
  80. package/dist/tool/built-in/grep.d.ts.map +1 -0
  81. package/dist/tool/built-in/grep.js +287 -0
  82. package/dist/tool/built-in/grep.js.map +1 -0
  83. package/dist/tool/built-in/index.d.ts +36 -0
  84. package/dist/tool/built-in/index.d.ts.map +1 -0
  85. package/dist/tool/built-in/index.js +45 -0
  86. package/dist/tool/built-in/index.js.map +1 -0
  87. package/dist/tool/executor.d.ts +71 -0
  88. package/dist/tool/executor.d.ts.map +1 -0
  89. package/dist/tool/executor.js +116 -0
  90. package/dist/tool/executor.js.map +1 -0
  91. package/dist/tool/framework.d.ts +143 -0
  92. package/dist/tool/framework.d.ts.map +1 -0
  93. package/dist/tool/framework.js +371 -0
  94. package/dist/tool/framework.js.map +1 -0
  95. package/dist/types.d.ts +285 -0
  96. package/dist/types.d.ts.map +1 -0
  97. package/dist/types.js +8 -0
  98. package/dist/types.js.map +1 -0
  99. package/dist/utils/semaphore.d.ts +47 -0
  100. package/dist/utils/semaphore.d.ts.map +1 -0
  101. package/dist/utils/semaphore.js +85 -0
  102. package/dist/utils/semaphore.js.map +1 -0
  103. package/examples/01-single-agent.ts +131 -0
  104. package/examples/02-team-collaboration.ts +167 -0
  105. package/examples/03-task-pipeline.ts +201 -0
  106. package/examples/04-multi-model-team.ts +261 -0
  107. package/package.json +49 -0
  108. package/src/agent/agent.ts +364 -0
  109. package/src/agent/pool.ts +278 -0
  110. package/src/agent/runner.ts +413 -0
  111. package/src/index.ts +166 -0
  112. package/src/llm/adapter.ts +74 -0
  113. package/src/llm/anthropic.ts +388 -0
  114. package/src/llm/openai.ts +522 -0
  115. package/src/memory/shared.ts +181 -0
  116. package/src/memory/store.ts +124 -0
  117. package/src/orchestrator/orchestrator.ts +851 -0
  118. package/src/orchestrator/scheduler.ts +352 -0
  119. package/src/task/queue.ts +394 -0
  120. package/src/task/task.ts +232 -0
  121. package/src/team/messaging.ts +230 -0
  122. package/src/team/team.ts +334 -0
  123. package/src/tool/built-in/bash.ts +187 -0
  124. package/src/tool/built-in/file-edit.ts +154 -0
  125. package/src/tool/built-in/file-read.ts +105 -0
  126. package/src/tool/built-in/file-write.ts +81 -0
  127. package/src/tool/built-in/grep.ts +362 -0
  128. package/src/tool/built-in/index.ts +50 -0
  129. package/src/tool/executor.ts +178 -0
  130. package/src/tool/framework.ts +557 -0
  131. package/src/types.ts +362 -0
  132. package/src/utils/semaphore.ts +89 -0
  133. package/tsconfig.json +25 -0
@@ -0,0 +1,282 @@
1
+ /**
2
+ * @fileoverview Team — the central coordination object for a named group of agents.
3
+ *
4
+ * A {@link Team} owns the agent roster, the inter-agent {@link MessageBus},
5
+ * the {@link TaskQueue}, and (optionally) a {@link SharedMemory} instance.
6
+ * It also exposes a typed event bus so orchestrators can react to lifecycle
7
+ * events without polling.
8
+ */
9
+ import { SharedMemory } from '../memory/shared.js';
10
+ import { MessageBus } from './messaging.js';
11
+ import { TaskQueue } from '../task/queue.js';
12
+ import { createTask } from '../task/task.js';
13
+ /** Minimal synchronous event emitter. */
14
+ class EventBus {
15
+ listeners = new Map();
16
+ on(event, handler) {
17
+ let map = this.listeners.get(event);
18
+ if (!map) {
19
+ map = new Map();
20
+ this.listeners.set(event, map);
21
+ }
22
+ const id = Symbol();
23
+ map.set(id, handler);
24
+ return () => {
25
+ map.delete(id);
26
+ };
27
+ }
28
+ emit(event, data) {
29
+ const map = this.listeners.get(event);
30
+ if (!map)
31
+ return;
32
+ for (const handler of map.values()) {
33
+ handler(data);
34
+ }
35
+ }
36
+ }
37
+ // ---------------------------------------------------------------------------
38
+ // Team
39
+ // ---------------------------------------------------------------------------
40
+ /**
41
+ * Coordinates a named group of agents with shared messaging, task queuing,
42
+ * and optional shared memory.
43
+ *
44
+ * @example
45
+ * ```ts
46
+ * const team = new Team({
47
+ * name: 'research-team',
48
+ * agents: [researcherConfig, writerConfig],
49
+ * sharedMemory: true,
50
+ * maxConcurrency: 2,
51
+ * })
52
+ *
53
+ * team.on('task:complete', (data) => {
54
+ * const event = data as OrchestratorEvent
55
+ * console.log(`Task done: ${event.task}`)
56
+ * })
57
+ *
58
+ * const task = team.addTask({
59
+ * title: 'Research topic',
60
+ * description: 'Gather background on quantum computing',
61
+ * status: 'pending',
62
+ * assignee: 'researcher',
63
+ * })
64
+ * ```
65
+ */
66
+ export class Team {
67
+ name;
68
+ config;
69
+ agentMap;
70
+ bus;
71
+ queue;
72
+ memory;
73
+ events;
74
+ constructor(config) {
75
+ this.config = config;
76
+ this.name = config.name;
77
+ // Index agents by name for O(1) lookup.
78
+ this.agentMap = new Map(config.agents.map((a) => [a.name, a]));
79
+ this.bus = new MessageBus();
80
+ this.queue = new TaskQueue();
81
+ this.memory = config.sharedMemory ? new SharedMemory() : undefined;
82
+ this.events = new EventBus();
83
+ // Bridge queue events onto the team's event bus.
84
+ this.queue.on('task:ready', (task) => {
85
+ const event = {
86
+ type: 'task_start',
87
+ task: task.id,
88
+ data: task,
89
+ };
90
+ this.events.emit('task:ready', event);
91
+ });
92
+ this.queue.on('task:complete', (task) => {
93
+ const event = {
94
+ type: 'task_complete',
95
+ task: task.id,
96
+ data: task,
97
+ };
98
+ this.events.emit('task:complete', event);
99
+ });
100
+ this.queue.on('task:failed', (task) => {
101
+ const event = {
102
+ type: 'error',
103
+ task: task.id,
104
+ data: task,
105
+ };
106
+ this.events.emit('task:failed', event);
107
+ });
108
+ this.queue.on('all:complete', () => {
109
+ this.events.emit('all:complete', undefined);
110
+ });
111
+ }
112
+ // ---------------------------------------------------------------------------
113
+ // Agent roster
114
+ // ---------------------------------------------------------------------------
115
+ /** Returns a shallow copy of the agent configs in registration order. */
116
+ getAgents() {
117
+ return Array.from(this.agentMap.values());
118
+ }
119
+ /**
120
+ * Looks up an agent by name.
121
+ *
122
+ * @returns The {@link AgentConfig} or `undefined` when the name is not known.
123
+ */
124
+ getAgent(name) {
125
+ return this.agentMap.get(name);
126
+ }
127
+ // ---------------------------------------------------------------------------
128
+ // Messaging
129
+ // ---------------------------------------------------------------------------
130
+ /**
131
+ * Sends a point-to-point message from `from` to `to`.
132
+ *
133
+ * The message is persisted on the bus and any active subscribers for `to`
134
+ * are notified synchronously.
135
+ */
136
+ sendMessage(from, to, content) {
137
+ const message = this.bus.send(from, to, content);
138
+ const event = {
139
+ type: 'message',
140
+ agent: from,
141
+ data: message,
142
+ };
143
+ this.events.emit('message', event);
144
+ }
145
+ /**
146
+ * Returns all messages (read or unread) addressed to `agentName`, in
147
+ * chronological order.
148
+ */
149
+ getMessages(agentName) {
150
+ return this.bus.getAll(agentName);
151
+ }
152
+ /**
153
+ * Broadcasts `content` from `from` to every other agent.
154
+ *
155
+ * The `to` field of the resulting message is `'*'`.
156
+ */
157
+ broadcast(from, content) {
158
+ const message = this.bus.broadcast(from, content);
159
+ const event = {
160
+ type: 'message',
161
+ agent: from,
162
+ data: message,
163
+ };
164
+ this.events.emit('broadcast', event);
165
+ }
166
+ // ---------------------------------------------------------------------------
167
+ // Task management
168
+ // ---------------------------------------------------------------------------
169
+ /**
170
+ * Creates a new task, adds it to the queue, and returns the persisted
171
+ * {@link Task} (with generated `id`, `createdAt`, and `updatedAt`).
172
+ *
173
+ * @param task - Everything except the generated fields.
174
+ */
175
+ addTask(task) {
176
+ const created = createTask({
177
+ title: task.title,
178
+ description: task.description,
179
+ assignee: task.assignee,
180
+ dependsOn: task.dependsOn ? [...task.dependsOn] : undefined,
181
+ });
182
+ // Preserve any non-default status (e.g. 'blocked') supplied by the caller.
183
+ const finalTask = task.status !== 'pending'
184
+ ? { ...created, status: task.status, result: task.result }
185
+ : created;
186
+ this.queue.add(finalTask);
187
+ return finalTask;
188
+ }
189
+ /** Returns a snapshot of all tasks in the queue (any status). */
190
+ getTasks() {
191
+ return this.queue.list();
192
+ }
193
+ /** Returns all tasks whose `assignee` is `agentName`. */
194
+ getTasksByAssignee(agentName) {
195
+ return this.queue.list().filter((t) => t.assignee === agentName);
196
+ }
197
+ /**
198
+ * Applies a partial update to the task identified by `taskId`.
199
+ *
200
+ * @throws {Error} when the task is not found.
201
+ */
202
+ updateTask(taskId, update) {
203
+ // Extract only mutable fields accepted by the queue.
204
+ const { status, result, assignee } = update;
205
+ return this.queue.update(taskId, {
206
+ ...(status !== undefined && { status }),
207
+ ...(result !== undefined && { result }),
208
+ ...(assignee !== undefined && { assignee }),
209
+ });
210
+ }
211
+ /**
212
+ * Returns the next `'pending'` task for `agentName`, respecting dependencies.
213
+ *
214
+ * Tries to find a task explicitly assigned to the agent first; falls back to
215
+ * the first unassigned pending task.
216
+ *
217
+ * @returns `undefined` when no ready task exists for this agent.
218
+ */
219
+ getNextTask(agentName) {
220
+ // Prefer a task explicitly assigned to this agent.
221
+ const assigned = this.queue.next(agentName);
222
+ if (assigned)
223
+ return assigned;
224
+ // Fall back to any unassigned pending task.
225
+ return this.queue.nextAvailable();
226
+ }
227
+ // ---------------------------------------------------------------------------
228
+ // Memory
229
+ // ---------------------------------------------------------------------------
230
+ /**
231
+ * Returns the shared {@link MemoryStore} for this team, or `undefined` if
232
+ * `sharedMemory` was not enabled in {@link TeamConfig}.
233
+ *
234
+ * Note: the returned value satisfies the {@link MemoryStore} interface.
235
+ * Callers that need the full {@link SharedMemory} API can use the
236
+ * `as SharedMemory` cast, but depending on the concrete type is discouraged.
237
+ */
238
+ getSharedMemory() {
239
+ return this.memory?.getStore();
240
+ }
241
+ /**
242
+ * Returns the raw {@link SharedMemory} instance (team-internal accessor).
243
+ * Use this when you need the namespacing / `getSummary` features.
244
+ *
245
+ * @internal
246
+ */
247
+ getSharedMemoryInstance() {
248
+ return this.memory;
249
+ }
250
+ // ---------------------------------------------------------------------------
251
+ // Events
252
+ // ---------------------------------------------------------------------------
253
+ /**
254
+ * Subscribes to a team event.
255
+ *
256
+ * Built-in events:
257
+ * - `'task:ready'` — emitted when a task becomes runnable.
258
+ * - `'task:complete'` — emitted when a task completes successfully.
259
+ * - `'task:failed'` — emitted when a task fails.
260
+ * - `'all:complete'` — emitted when every task in the queue has terminated.
261
+ * - `'message'` — emitted on point-to-point messages.
262
+ * - `'broadcast'` — emitted on broadcast messages.
263
+ *
264
+ * `data` is typed as `unknown`; cast to {@link OrchestratorEvent} for
265
+ * structured access.
266
+ *
267
+ * @returns An unsubscribe function.
268
+ */
269
+ on(event, handler) {
270
+ return this.events.on(event, handler);
271
+ }
272
+ /**
273
+ * Emits a custom event on the team's event bus.
274
+ *
275
+ * Orchestrators can use this to signal domain-specific lifecycle milestones
276
+ * (e.g. `'phase:research:complete'`) without modifying the Team class.
277
+ */
278
+ emit(event, data) {
279
+ this.events.emit(event, data);
280
+ }
281
+ }
282
+ //# sourceMappingURL=team.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"team.js","sourceRoot":"","sources":["../../src/team/team.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAUH,OAAO,EAAE,YAAY,EAAE,MAAM,qBAAqB,CAAA;AAClD,OAAO,EAAE,UAAU,EAAE,MAAM,gBAAgB,CAAA;AAE3C,OAAO,EAAE,SAAS,EAAE,MAAM,kBAAkB,CAAA;AAC5C,OAAO,EAAE,UAAU,EAAE,MAAM,iBAAiB,CAAA;AAU5C,yCAAyC;AACzC,MAAM,QAAQ;IACK,SAAS,GAAG,IAAI,GAAG,EAAqC,CAAA;IAEzE,EAAE,CAAC,KAAa,EAAE,OAAqB;QACrC,IAAI,GAAG,GAAG,IAAI,CAAC,SAAS,CAAC,GAAG,CAAC,KAAK,CAAC,CAAA;QACnC,IAAI,CAAC,GAAG,EAAE,CAAC;YACT,GAAG,GAAG,IAAI,GAAG,EAAE,CAAA;YACf,IAAI,CAAC,SAAS,CAAC,GAAG,CAAC,KAAK,EAAE,GAAG,CAAC,CAAA;QAChC,CAAC;QACD,MAAM,EAAE,GAAG,MAAM,EAAE,CAAA;QACnB,GAAG,CAAC,GAAG,CAAC,EAAE,EAAE,OAAO,CAAC,CAAA;QACpB,OAAO,GAAG,EAAE;YACV,GAAI,CAAC,MAAM,CAAC,EAAE,CAAC,CAAA;QACjB,CAAC,CAAA;IACH,CAAC;IAED,IAAI,CAAC,KAAa,EAAE,IAAa;QAC/B,MAAM,GAAG,GAAG,IAAI,CAAC,SAAS,CAAC,GAAG,CAAC,KAAK,CAAC,CAAA;QACrC,IAAI,CAAC,GAAG;YAAE,OAAM;QAChB,KAAK,MAAM,OAAO,IAAI,GAAG,CAAC,MAAM,EAAE,EAAE,CAAC;YACnC,OAAO,CAAC,IAAI,CAAC,CAAA;QACf,CAAC;IACH,CAAC;CACF;AAED,8EAA8E;AAC9E,OAAO;AACP,8EAA8E;AAE9E;;;;;;;;;;;;;;;;;;;;;;;;;GAyBG;AACH,MAAM,OAAO,IAAI;IACN,IAAI,CAAQ;IACZ,MAAM,CAAY;IAEV,QAAQ,CAAkC;IAC1C,GAAG,CAAY;IACf,KAAK,CAAW;IAChB,MAAM,CAA0B;IAChC,MAAM,CAAU;IAEjC,YAAY,MAAkB;QAC5B,IAAI,CAAC,MAAM,GAAG,MAAM,CAAA;QACpB,IAAI,CAAC,IAAI,GAAG,MAAM,CAAC,IAAI,CAAA;QAEvB,wCAAwC;QACxC,IAAI,CAAC,QAAQ,GAAG,IAAI,GAAG,CAAC,MAAM,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,CAAC,IAAI,EAAE,CAAC,CAAC,CAAC,CAAC,CAAA;QAC9D,IAAI,CAAC,GAAG,GAAG,IAAI,UAAU,EAAE,CAAA;QAC3B,IAAI,CAAC,KAAK,GAAG,IAAI,SAAS,EAAE,CAAA;QAC5B,IAAI,CAAC,MAAM,GAAG,MAAM,CAAC,YAAY,CAAC,CAAC,CAAC,IAAI,YAAY,EAAE,CAAC,CAAC,CAAC,SAAS,CAAA;QAClE,IAAI,CAAC,MAAM,GAAG,IAAI,QAAQ,EAAE,CAAA;QAE5B,iDAAiD;QACjD,IAAI,CAAC,KAAK,CAAC,EAAE,CAAC,YAAY,EAAE,CAAC,IAAI,EAAE,EAAE;YACnC,MAAM,KAAK,GAAsB;gBAC/B,IAAI,EAAE,YAAY;gBAClB,IAAI,EAAE,IAAI,CAAC,EAAE;gBACb,IAAI,EAAE,IAAI;aACX,CAAA;YACD,IAAI,CAAC,MAAM,CAAC,IAAI,CAAC,YAAY,EAAE,KAAK,CAAC,CAAA;QACvC,CAAC,CAAC,CAAA;QAEF,IAAI,CAAC,KAAK,CAAC,EAAE,CAAC,eAAe,EAAE,CAAC,IAAI,EAAE,EAAE;YACtC,MAAM,KAAK,GAAsB;gBAC/B,IAAI,EAAE,eAAe;gBACrB,IAAI,EAAE,IAAI,CAAC,EAAE;gBACb,IAAI,EAAE,IAAI;aACX,CAAA;YACD,IAAI,CAAC,MAAM,CAAC,IAAI,CAAC,eAAe,EAAE,KAAK,CAAC,CAAA;QAC1C,CAAC,CAAC,CAAA;QAEF,IAAI,CAAC,KAAK,CAAC,EAAE,CAAC,aAAa,EAAE,CAAC,IAAI,EAAE,EAAE;YACpC,MAAM,KAAK,GAAsB;gBAC/B,IAAI,EAAE,OAAO;gBACb,IAAI,EAAE,IAAI,CAAC,EAAE;gBACb,IAAI,EAAE,IAAI;aACX,CAAA;YACD,IAAI,CAAC,MAAM,CAAC,IAAI,CAAC,aAAa,EAAE,KAAK,CAAC,CAAA;QACxC,CAAC,CAAC,CAAA;QAEF,IAAI,CAAC,KAAK,CAAC,EAAE,CAAC,cAAc,EAAE,GAAG,EAAE;YACjC,IAAI,CAAC,MAAM,CAAC,IAAI,CAAC,cAAc,EAAE,SAAS,CAAC,CAAA;QAC7C,CAAC,CAAC,CAAA;IACJ,CAAC;IAED,8EAA8E;IAC9E,eAAe;IACf,8EAA8E;IAE9E,yEAAyE;IACzE,SAAS;QACP,OAAO,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,QAAQ,CAAC,MAAM,EAAE,CAAC,CAAA;IAC3C,CAAC;IAED;;;;OAIG;IACH,QAAQ,CAAC,IAAY;QACnB,OAAO,IAAI,CAAC,QAAQ,CAAC,GAAG,CAAC,IAAI,CAAC,CAAA;IAChC,CAAC;IAED,8EAA8E;IAC9E,YAAY;IACZ,8EAA8E;IAE9E;;;;;OAKG;IACH,WAAW,CAAC,IAAY,EAAE,EAAU,EAAE,OAAe;QACnD,MAAM,OAAO,GAAG,IAAI,CAAC,GAAG,CAAC,IAAI,CAAC,IAAI,EAAE,EAAE,EAAE,OAAO,CAAC,CAAA;QAChD,MAAM,KAAK,GAAsB;YAC/B,IAAI,EAAE,SAAS;YACf,KAAK,EAAE,IAAI;YACX,IAAI,EAAE,OAAO;SACd,CAAA;QACD,IAAI,CAAC,MAAM,CAAC,IAAI,CAAC,SAAS,EAAE,KAAK,CAAC,CAAA;IACpC,CAAC;IAED;;;OAGG;IACH,WAAW,CAAC,SAAiB;QAC3B,OAAO,IAAI,CAAC,GAAG,CAAC,MAAM,CAAC,SAAS,CAAC,CAAA;IACnC,CAAC;IAED;;;;OAIG;IACH,SAAS,CAAC,IAAY,EAAE,OAAe;QACrC,MAAM,OAAO,GAAG,IAAI,CAAC,GAAG,CAAC,SAAS,CAAC,IAAI,EAAE,OAAO,CAAC,CAAA;QACjD,MAAM,KAAK,GAAsB;YAC/B,IAAI,EAAE,SAAS;YACf,KAAK,EAAE,IAAI;YACX,IAAI,EAAE,OAAO;SACd,CAAA;QACD,IAAI,CAAC,MAAM,CAAC,IAAI,CAAC,WAAW,EAAE,KAAK,CAAC,CAAA;IACtC,CAAC;IAED,8EAA8E;IAC9E,kBAAkB;IAClB,8EAA8E;IAE9E;;;;;OAKG;IACH,OAAO,CACL,IAAkD;QAElD,MAAM,OAAO,GAAG,UAAU,CAAC;YACzB,KAAK,EAAE,IAAI,CAAC,KAAK;YACjB,WAAW,EAAE,IAAI,CAAC,WAAW;YAC7B,QAAQ,EAAE,IAAI,CAAC,QAAQ;YACvB,SAAS,EAAE,IAAI,CAAC,SAAS,CAAC,CAAC,CAAC,CAAC,GAAG,IAAI,CAAC,SAAS,CAAC,CAAC,CAAC,CAAC,SAAS;SAC5D,CAAC,CAAA;QAEF,2EAA2E;QAC3E,MAAM,SAAS,GACb,IAAI,CAAC,MAAM,KAAK,SAAS;YACvB,CAAC,CAAC,EAAE,GAAG,OAAO,EAAE,MAAM,EAAE,IAAI,CAAC,MAAoB,EAAE,MAAM,EAAE,IAAI,CAAC,MAAM,EAAE;YACxE,CAAC,CAAC,OAAO,CAAA;QAEb,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,SAAS,CAAC,CAAA;QACzB,OAAO,SAAS,CAAA;IAClB,CAAC;IAED,iEAAiE;IACjE,QAAQ;QACN,OAAO,IAAI,CAAC,KAAK,CAAC,IAAI,EAAE,CAAA;IAC1B,CAAC;IAED,yDAAyD;IACzD,kBAAkB,CAAC,SAAiB;QAClC,OAAO,IAAI,CAAC,KAAK,CAAC,IAAI,EAAE,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,QAAQ,KAAK,SAAS,CAAC,CAAA;IAClE,CAAC;IAED;;;;OAIG;IACH,UAAU,CAAC,MAAc,EAAE,MAAqB;QAC9C,qDAAqD;QACrD,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,QAAQ,EAAE,GAAG,MAAM,CAAA;QAC3C,OAAO,IAAI,CAAC,KAAK,CAAC,MAAM,CAAC,MAAM,EAAE;YAC/B,GAAG,CAAC,MAAM,KAAK,SAAS,IAAI,EAAE,MAAM,EAAE,CAAC;YACvC,GAAG,CAAC,MAAM,KAAK,SAAS,IAAI,EAAE,MAAM,EAAE,CAAC;YACvC,GAAG,CAAC,QAAQ,KAAK,SAAS,IAAI,EAAE,QAAQ,EAAE,CAAC;SAC5C,CAAC,CAAA;IACJ,CAAC;IAED;;;;;;;OAOG;IACH,WAAW,CAAC,SAAiB;QAC3B,mDAAmD;QACnD,MAAM,QAAQ,GAAG,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,SAAS,CAAC,CAAA;QAC3C,IAAI,QAAQ;YAAE,OAAO,QAAQ,CAAA;QAE7B,4CAA4C;QAC5C,OAAO,IAAI,CAAC,KAAK,CAAC,aAAa,EAAE,CAAA;IACnC,CAAC;IAED,8EAA8E;IAC9E,SAAS;IACT,8EAA8E;IAE9E;;;;;;;OAOG;IACH,eAAe;QACb,OAAO,IAAI,CAAC,MAAM,EAAE,QAAQ,EAAE,CAAA;IAChC,CAAC;IAED;;;;;OAKG;IACH,uBAAuB;QACrB,OAAO,IAAI,CAAC,MAAM,CAAA;IACpB,CAAC;IAED,8EAA8E;IAC9E,SAAS;IACT,8EAA8E;IAE9E;;;;;;;;;;;;;;;OAeG;IACH,EAAE,CAAC,KAAa,EAAE,OAAgC;QAChD,OAAO,IAAI,CAAC,MAAM,CAAC,EAAE,CAAC,KAAK,EAAE,OAAO,CAAC,CAAA;IACvC,CAAC;IAED;;;;;OAKG;IACH,IAAI,CAAC,KAAa,EAAE,IAAa;QAC/B,IAAI,CAAC,MAAM,CAAC,IAAI,CAAC,KAAK,EAAE,IAAI,CAAC,CAAA;IAC/B,CAAC;CACF"}
@@ -0,0 +1,12 @@
1
+ /**
2
+ * Built-in bash tool.
3
+ *
4
+ * Executes a shell command and returns its stdout + stderr. Supports an
5
+ * optional timeout and a custom working directory.
6
+ */
7
+ export declare const bashTool: import("../framework.js").ToolDefinition<{
8
+ command: string;
9
+ timeout?: number | undefined;
10
+ cwd?: string | undefined;
11
+ }>;
12
+ //# sourceMappingURL=bash.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"bash.d.ts","sourceRoot":"","sources":["../../../src/tool/built-in/bash.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAgBH,eAAO,MAAM,QAAQ;;;;EAyCnB,CAAA"}
@@ -0,0 +1,133 @@
1
+ /**
2
+ * Built-in bash tool.
3
+ *
4
+ * Executes a shell command and returns its stdout + stderr. Supports an
5
+ * optional timeout and a custom working directory.
6
+ */
7
+ import { spawn } from 'child_process';
8
+ import { z } from 'zod';
9
+ import { defineTool } from '../framework.js';
10
+ // ---------------------------------------------------------------------------
11
+ // Constants
12
+ // ---------------------------------------------------------------------------
13
+ const DEFAULT_TIMEOUT_MS = 30_000;
14
+ // ---------------------------------------------------------------------------
15
+ // Tool definition
16
+ // ---------------------------------------------------------------------------
17
+ export const bashTool = defineTool({
18
+ name: 'bash',
19
+ description: 'Execute a bash command and return its stdout and stderr. ' +
20
+ 'Use this for file system operations, running scripts, installing packages, ' +
21
+ 'and any task that requires shell access. ' +
22
+ 'The command runs in a non-interactive shell (bash -c). ' +
23
+ 'Long-running commands should use the timeout parameter.',
24
+ inputSchema: z.object({
25
+ command: z.string().describe('The bash command to execute.'),
26
+ timeout: z
27
+ .number()
28
+ .optional()
29
+ .describe(`Timeout in milliseconds before the command is forcibly killed. ` +
30
+ `Defaults to ${DEFAULT_TIMEOUT_MS} ms.`),
31
+ cwd: z
32
+ .string()
33
+ .optional()
34
+ .describe('Working directory in which to run the command.'),
35
+ }),
36
+ execute: async (input, context) => {
37
+ const timeoutMs = input.timeout ?? DEFAULT_TIMEOUT_MS;
38
+ const { stdout, stderr, exitCode } = await runCommand(input.command, { cwd: input.cwd, timeoutMs }, context.abortSignal);
39
+ const combined = buildOutput(stdout, stderr, exitCode);
40
+ const isError = exitCode !== 0;
41
+ return {
42
+ data: combined,
43
+ isError,
44
+ };
45
+ },
46
+ });
47
+ /**
48
+ * Spawn a bash subprocess, capture its output, and resolve when it exits or
49
+ * the abort signal fires.
50
+ */
51
+ function runCommand(command, options, signal) {
52
+ return new Promise((resolve) => {
53
+ const stdoutChunks = [];
54
+ const stderrChunks = [];
55
+ const child = spawn('bash', ['-c', command], {
56
+ cwd: options.cwd,
57
+ env: process.env,
58
+ stdio: ['ignore', 'pipe', 'pipe'],
59
+ });
60
+ child.stdout.on('data', (chunk) => stdoutChunks.push(chunk));
61
+ child.stderr.on('data', (chunk) => stderrChunks.push(chunk));
62
+ let timedOut = false;
63
+ let settled = false;
64
+ const done = (exitCode) => {
65
+ if (settled)
66
+ return;
67
+ settled = true;
68
+ clearTimeout(timer);
69
+ if (signal !== undefined) {
70
+ signal.removeEventListener('abort', onAbort);
71
+ }
72
+ const stdout = Buffer.concat(stdoutChunks).toString('utf8');
73
+ const stderr = Buffer.concat(stderrChunks).toString('utf8');
74
+ resolve({ stdout, stderr, exitCode });
75
+ };
76
+ // Timeout handler
77
+ const timer = setTimeout(() => {
78
+ timedOut = true;
79
+ child.kill('SIGKILL');
80
+ }, options.timeoutMs);
81
+ // Abort-signal handler
82
+ const onAbort = () => {
83
+ child.kill('SIGKILL');
84
+ };
85
+ if (signal !== undefined) {
86
+ signal.addEventListener('abort', onAbort, { once: true });
87
+ }
88
+ child.on('close', (code) => {
89
+ const exitCode = code ?? (timedOut ? 124 : 1);
90
+ done(exitCode);
91
+ });
92
+ child.on('error', (err) => {
93
+ if (!settled) {
94
+ settled = true;
95
+ clearTimeout(timer);
96
+ if (signal !== undefined) {
97
+ signal.removeEventListener('abort', onAbort);
98
+ }
99
+ resolve({
100
+ stdout: '',
101
+ stderr: err.message,
102
+ exitCode: 127,
103
+ });
104
+ }
105
+ });
106
+ });
107
+ }
108
+ /**
109
+ * Format captured output into a single readable string.
110
+ * When only stdout is present its content is returned as-is.
111
+ * When stderr is also present both sections are labelled.
112
+ */
113
+ function buildOutput(stdout, stderr, exitCode) {
114
+ const parts = [];
115
+ if (stdout.length > 0) {
116
+ parts.push(stdout);
117
+ }
118
+ if (stderr.length > 0) {
119
+ parts.push(stdout.length > 0
120
+ ? `--- stderr ---\n${stderr}`
121
+ : stderr);
122
+ }
123
+ if (parts.length === 0) {
124
+ return exitCode === 0
125
+ ? '(command completed with no output)'
126
+ : `(command exited with code ${exitCode}, no output)`;
127
+ }
128
+ if (exitCode !== 0 && parts.length > 0) {
129
+ parts.push(`\n(exit code: ${exitCode})`);
130
+ }
131
+ return parts.join('\n');
132
+ }
133
+ //# sourceMappingURL=bash.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"bash.js","sourceRoot":"","sources":["../../../src/tool/built-in/bash.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,14 @@
1
+ /**
2
+ * Built-in file-edit tool.
3
+ *
4
+ * Performs a targeted string replacement inside an existing file.
5
+ * The uniqueness invariant (one match unless replace_all is set) prevents the
6
+ * common class of bugs where a generic pattern matches the wrong occurrence.
7
+ */
8
+ export declare const fileEditTool: import("../framework.js").ToolDefinition<{
9
+ path: string;
10
+ old_string: string;
11
+ new_string: string;
12
+ replace_all?: boolean | undefined;
13
+ }>;
14
+ //# sourceMappingURL=file-edit.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"file-edit.d.ts","sourceRoot":"","sources":["../../../src/tool/built-in/file-edit.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAUH,eAAO,MAAM,YAAY;;;;;EA+FvB,CAAA"}
@@ -0,0 +1,130 @@
1
+ /**
2
+ * Built-in file-edit tool.
3
+ *
4
+ * Performs a targeted string replacement inside an existing file.
5
+ * The uniqueness invariant (one match unless replace_all is set) prevents the
6
+ * common class of bugs where a generic pattern matches the wrong occurrence.
7
+ */
8
+ import { readFile, writeFile } from 'fs/promises';
9
+ import { z } from 'zod';
10
+ import { defineTool } from '../framework.js';
11
+ // ---------------------------------------------------------------------------
12
+ // Tool definition
13
+ // ---------------------------------------------------------------------------
14
+ export const fileEditTool = defineTool({
15
+ name: 'file_edit',
16
+ description: 'Edit a file by replacing a specific string with new content. ' +
17
+ 'The `old_string` must appear verbatim in the file. ' +
18
+ 'By default the tool errors if `old_string` appears more than once — ' +
19
+ 'use `replace_all: true` to replace every occurrence. ' +
20
+ 'Use file_write when you need to create a new file or rewrite it entirely.',
21
+ inputSchema: z.object({
22
+ path: z
23
+ .string()
24
+ .describe('Absolute path to the file to edit.'),
25
+ old_string: z
26
+ .string()
27
+ .describe('The exact string to find and replace. ' +
28
+ 'Must match character-for-character including whitespace and newlines.'),
29
+ new_string: z
30
+ .string()
31
+ .describe('The replacement string that will be inserted in place of `old_string`.'),
32
+ replace_all: z
33
+ .boolean()
34
+ .optional()
35
+ .describe('When true, replace every occurrence of `old_string` instead of requiring it ' +
36
+ 'to be unique. Defaults to false.'),
37
+ }),
38
+ execute: async (input) => {
39
+ // Read the existing file.
40
+ let original;
41
+ try {
42
+ const buffer = await readFile(input.path);
43
+ original = buffer.toString('utf8');
44
+ }
45
+ catch (err) {
46
+ const message = err instanceof Error ? err.message : 'Unknown error reading file.';
47
+ return {
48
+ data: `Could not read "${input.path}": ${message}`,
49
+ isError: true,
50
+ };
51
+ }
52
+ const occurrences = countOccurrences(original, input.old_string);
53
+ if (occurrences === 0) {
54
+ return {
55
+ data: `The string to replace was not found in "${input.path}".\n` +
56
+ 'Make sure `old_string` matches the file contents exactly, ' +
57
+ 'including indentation and line endings.',
58
+ isError: true,
59
+ };
60
+ }
61
+ const replaceAll = input.replace_all ?? false;
62
+ if (occurrences > 1 && !replaceAll) {
63
+ return {
64
+ data: `\`old_string\` appears ${occurrences} times in "${input.path}". ` +
65
+ 'Provide a more specific string to uniquely identify the section you want ' +
66
+ 'to replace, or set `replace_all: true` to replace every occurrence.',
67
+ isError: true,
68
+ };
69
+ }
70
+ // Perform the replacement.
71
+ const updated = replaceAll
72
+ ? replaceAllOccurrences(original, input.old_string, input.new_string)
73
+ : original.replace(input.old_string, input.new_string);
74
+ // Persist the result.
75
+ try {
76
+ await writeFile(input.path, updated, 'utf8');
77
+ }
78
+ catch (err) {
79
+ const message = err instanceof Error ? err.message : 'Unknown error writing file.';
80
+ return {
81
+ data: `Failed to write "${input.path}": ${message}`,
82
+ isError: true,
83
+ };
84
+ }
85
+ const replacedCount = replaceAll ? occurrences : 1;
86
+ return {
87
+ data: `Replaced ${replacedCount} occurrence${replacedCount === 1 ? '' : 's'} ` +
88
+ `in "${input.path}".`,
89
+ isError: false,
90
+ };
91
+ },
92
+ });
93
+ // ---------------------------------------------------------------------------
94
+ // Internal helpers
95
+ // ---------------------------------------------------------------------------
96
+ /**
97
+ * Count how many times `needle` appears in `haystack`.
98
+ * Uses a plain loop to avoid constructing a potentially large regex from
99
+ * untrusted input.
100
+ */
101
+ function countOccurrences(haystack, needle) {
102
+ if (needle.length === 0)
103
+ return 0;
104
+ let count = 0;
105
+ let pos = 0;
106
+ while ((pos = haystack.indexOf(needle, pos)) !== -1) {
107
+ count++;
108
+ pos += needle.length;
109
+ }
110
+ return count;
111
+ }
112
+ /**
113
+ * Replace all occurrences of `needle` in `haystack` with `replacement`
114
+ * without using a regex (avoids regex-special-character escaping issues).
115
+ */
116
+ function replaceAllOccurrences(haystack, needle, replacement) {
117
+ if (needle.length === 0)
118
+ return haystack;
119
+ const parts = [];
120
+ let pos = 0;
121
+ let next;
122
+ while ((next = haystack.indexOf(needle, pos)) !== -1) {
123
+ parts.push(haystack.slice(pos, next));
124
+ parts.push(replacement);
125
+ pos = next + needle.length;
126
+ }
127
+ parts.push(haystack.slice(pos));
128
+ return parts.join('');
129
+ }
130
+ //# sourceMappingURL=file-edit.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"file-edit.js","sourceRoot":"","sources":["../../../src/tool/built-in/file-edit.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,12 @@
1
+ /**
2
+ * Built-in file-read tool.
3
+ *
4
+ * Reads a file from disk and returns its contents with 1-based line numbers.
5
+ * Supports reading a slice of lines via `offset` and `limit` for large files.
6
+ */
7
+ export declare const fileReadTool: import("../framework.js").ToolDefinition<{
8
+ path: string;
9
+ offset?: number | undefined;
10
+ limit?: number | undefined;
11
+ }>;
12
+ //# sourceMappingURL=file-read.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"file-read.d.ts","sourceRoot":"","sources":["../../../src/tool/built-in/file-read.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAUH,eAAO,MAAM,YAAY;;;;EAyFvB,CAAA"}