@clinebot/agents 0.0.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 (90) hide show
  1. package/README.md +145 -0
  2. package/dist/agent-input.d.ts +2 -0
  3. package/dist/agent.d.ts +56 -0
  4. package/dist/extensions.d.ts +21 -0
  5. package/dist/hooks/engine.d.ts +42 -0
  6. package/dist/hooks/index.d.ts +2 -0
  7. package/dist/hooks/lifecycle.d.ts +5 -0
  8. package/dist/hooks/node.d.ts +2 -0
  9. package/dist/hooks/subprocess-runner.d.ts +16 -0
  10. package/dist/hooks/subprocess.d.ts +268 -0
  11. package/dist/index.browser.d.ts +1 -0
  12. package/dist/index.browser.js +49 -0
  13. package/dist/index.d.ts +15 -0
  14. package/dist/index.js +49 -0
  15. package/dist/index.node.d.ts +5 -0
  16. package/dist/index.node.js +49 -0
  17. package/dist/mcp/index.d.ts +4 -0
  18. package/dist/mcp/policies.d.ts +14 -0
  19. package/dist/mcp/tools.d.ts +9 -0
  20. package/dist/mcp/types.d.ts +35 -0
  21. package/dist/message-builder.d.ts +31 -0
  22. package/dist/prompts/cline.d.ts +1 -0
  23. package/dist/prompts/index.d.ts +1 -0
  24. package/dist/runtime/agent-runtime-bus.d.ts +13 -0
  25. package/dist/runtime/conversation-store.d.ts +16 -0
  26. package/dist/runtime/lifecycle-orchestrator.d.ts +28 -0
  27. package/dist/runtime/tool-orchestrator.d.ts +39 -0
  28. package/dist/runtime/turn-processor.d.ts +21 -0
  29. package/dist/teams/index.d.ts +3 -0
  30. package/dist/teams/multi-agent.d.ts +566 -0
  31. package/dist/teams/spawn-agent-tool.d.ts +85 -0
  32. package/dist/teams/team-tools.d.ts +51 -0
  33. package/dist/tools/ask-question.d.ts +12 -0
  34. package/dist/tools/create.d.ts +59 -0
  35. package/dist/tools/execution.d.ts +61 -0
  36. package/dist/tools/formatting.d.ts +20 -0
  37. package/dist/tools/index.d.ts +11 -0
  38. package/dist/tools/registry.d.ts +26 -0
  39. package/dist/tools/validation.d.ts +27 -0
  40. package/dist/types.d.ts +826 -0
  41. package/package.json +54 -0
  42. package/src/agent-input.ts +116 -0
  43. package/src/agent.test.ts +931 -0
  44. package/src/agent.ts +1050 -0
  45. package/src/example.test.ts +564 -0
  46. package/src/extensions.ts +337 -0
  47. package/src/hooks/engine.test.ts +163 -0
  48. package/src/hooks/engine.ts +537 -0
  49. package/src/hooks/index.ts +6 -0
  50. package/src/hooks/lifecycle.ts +239 -0
  51. package/src/hooks/node.ts +18 -0
  52. package/src/hooks/subprocess-runner.ts +140 -0
  53. package/src/hooks/subprocess.test.ts +180 -0
  54. package/src/hooks/subprocess.ts +620 -0
  55. package/src/index.browser.ts +1 -0
  56. package/src/index.node.ts +21 -0
  57. package/src/index.ts +133 -0
  58. package/src/mcp/index.ts +17 -0
  59. package/src/mcp/policies.test.ts +51 -0
  60. package/src/mcp/policies.ts +53 -0
  61. package/src/mcp/tools.test.ts +76 -0
  62. package/src/mcp/tools.ts +60 -0
  63. package/src/mcp/types.ts +41 -0
  64. package/src/message-builder.test.ts +175 -0
  65. package/src/message-builder.ts +429 -0
  66. package/src/prompts/cline.ts +49 -0
  67. package/src/prompts/index.ts +1 -0
  68. package/src/runtime/agent-runtime-bus.ts +53 -0
  69. package/src/runtime/conversation-store.ts +61 -0
  70. package/src/runtime/lifecycle-orchestrator.ts +90 -0
  71. package/src/runtime/tool-orchestrator.ts +177 -0
  72. package/src/runtime/turn-processor.ts +250 -0
  73. package/src/streaming.test.ts +197 -0
  74. package/src/streaming.ts +307 -0
  75. package/src/teams/index.ts +63 -0
  76. package/src/teams/multi-agent.lifecycle.test.ts +48 -0
  77. package/src/teams/multi-agent.ts +1866 -0
  78. package/src/teams/spawn-agent-tool.test.ts +172 -0
  79. package/src/teams/spawn-agent-tool.ts +223 -0
  80. package/src/teams/team-tools.test.ts +448 -0
  81. package/src/teams/team-tools.ts +929 -0
  82. package/src/tools/ask-question.ts +78 -0
  83. package/src/tools/create.ts +104 -0
  84. package/src/tools/execution.ts +311 -0
  85. package/src/tools/formatting.ts +73 -0
  86. package/src/tools/index.ts +45 -0
  87. package/src/tools/registry.ts +52 -0
  88. package/src/tools/tools.test.ts +292 -0
  89. package/src/tools/validation.ts +73 -0
  90. package/src/types.ts +966 -0
@@ -0,0 +1,307 @@
1
+ /**
2
+ * Streaming Support
3
+ *
4
+ * Provides async iterable wrapper for streaming agent events in real-time.
5
+ */
6
+
7
+ import type { Agent } from "./agent.js";
8
+ import type { AgentEvent, AgentResult } from "./types.js";
9
+
10
+ // =============================================================================
11
+ // AgentStream
12
+ // =============================================================================
13
+
14
+ /**
15
+ * A stream of agent events that can be iterated asynchronously
16
+ *
17
+ * @example
18
+ * ```typescript
19
+ * const stream = streamRun(agent, "Hello")
20
+ *
21
+ * for await (const event of stream) {
22
+ * if (event.type === "content_start" && event.contentType === "text") {
23
+ * process.stdout.write(event.text ?? "")
24
+ * }
25
+ * }
26
+ *
27
+ * const result = await stream.getResult()
28
+ * ```
29
+ */
30
+ export interface AgentStream extends AsyncIterable<AgentEvent> {
31
+ /**
32
+ * Get the final result after the stream completes
33
+ *
34
+ * This promise resolves when the agent finishes (successfully or with error).
35
+ * Call this after iterating through all events, or if you don't need events
36
+ * and just want the final result.
37
+ */
38
+ getResult(): Promise<AgentResult>;
39
+
40
+ /**
41
+ * Abort the stream
42
+ *
43
+ * This stops the agent execution and closes the stream.
44
+ */
45
+ abort(): void;
46
+ }
47
+
48
+ // =============================================================================
49
+ // Stream Implementation
50
+ // =============================================================================
51
+
52
+ /**
53
+ * Internal implementation of AgentStream
54
+ */
55
+ class AgentStreamImpl implements AgentStream {
56
+ private eventQueue: AgentEvent[] = [];
57
+ private waitingResolvers: Array<(value: IteratorResult<AgentEvent>) => void> =
58
+ [];
59
+ private isDone = false;
60
+ private resultPromise: Promise<AgentResult>;
61
+ private resolveResult!: (result: AgentResult) => void;
62
+ private rejectResult!: (error: Error) => void;
63
+ private abortController: AbortController;
64
+ private unsubscribeEvents: (() => void) | null = null;
65
+
66
+ constructor(
67
+ private agent: Agent,
68
+ private message: string,
69
+ private isContinue: boolean,
70
+ ) {
71
+ this.abortController = new AbortController();
72
+
73
+ // Create result promise
74
+ this.resultPromise = new Promise((resolve, reject) => {
75
+ this.resolveResult = resolve;
76
+ this.rejectResult = reject;
77
+ });
78
+
79
+ // Start the run
80
+ this.startRun();
81
+ }
82
+
83
+ private async startRun(): Promise<void> {
84
+ this.unsubscribeEvents = this.agent.subscribeEvents((event: AgentEvent) => {
85
+ this.enqueueEvent(event);
86
+ });
87
+ try {
88
+ // Run or continue
89
+ const result = this.isContinue
90
+ ? await this.agent.continue(this.message)
91
+ : await this.agent.run(this.message);
92
+
93
+ // Mark as done
94
+ this.isDone = true;
95
+ this.flushWaiters();
96
+ this.resolveResult(result);
97
+ } catch (error) {
98
+ const err = error instanceof Error ? error : new Error(String(error));
99
+ this.isDone = true;
100
+ this.flushWaiters();
101
+ this.rejectResult(err);
102
+ } finally {
103
+ this.unsubscribeEvents?.();
104
+ this.unsubscribeEvents = null;
105
+ }
106
+ }
107
+
108
+ private enqueueEvent(event: AgentEvent): void {
109
+ if (this.waitingResolvers.length > 0) {
110
+ // Someone is waiting - resolve immediately
111
+ const resolve = this.waitingResolvers.shift()!;
112
+ resolve({ value: event, done: false });
113
+ } else {
114
+ // Queue the event
115
+ this.eventQueue.push(event);
116
+ }
117
+ }
118
+
119
+ private flushWaiters(): void {
120
+ // Resolve any remaining waiters with done
121
+ while (this.waitingResolvers.length > 0) {
122
+ const resolve = this.waitingResolvers.shift()!;
123
+ resolve({ value: undefined as unknown as AgentEvent, done: true });
124
+ }
125
+ }
126
+
127
+ [Symbol.asyncIterator](): AsyncIterator<AgentEvent> {
128
+ return {
129
+ next: async (): Promise<IteratorResult<AgentEvent>> => {
130
+ // Check if we have queued events
131
+ if (this.eventQueue.length > 0) {
132
+ return { value: this.eventQueue.shift()!, done: false };
133
+ }
134
+
135
+ // Check if we're done
136
+ if (this.isDone) {
137
+ return { value: undefined as unknown as AgentEvent, done: true };
138
+ }
139
+
140
+ // Wait for next event
141
+ return new Promise((resolve) => {
142
+ this.waitingResolvers.push(resolve);
143
+ });
144
+ },
145
+ };
146
+ }
147
+
148
+ getResult(): Promise<AgentResult> {
149
+ return this.resultPromise;
150
+ }
151
+
152
+ abort(): void {
153
+ this.abortController.abort();
154
+ this.agent.abort();
155
+ }
156
+ }
157
+
158
+ // =============================================================================
159
+ // Factory Functions
160
+ // =============================================================================
161
+
162
+ /**
163
+ * Create a streaming agent run
164
+ *
165
+ * This returns an AgentStream that can be iterated to receive events
166
+ * as they happen, with the final result available via getResult().
167
+ *
168
+ * @param agent - The agent to run
169
+ * @param message - The user message to send
170
+ * @returns An AgentStream for real-time event consumption
171
+ *
172
+ * @example
173
+ * ```typescript
174
+ * const stream = streamRun(agent, "Analyze this code")
175
+ *
176
+ * for await (const event of stream) {
177
+ * switch (event.type) {
178
+ * case "content_start":
179
+ * if (event.contentType === "text") {
180
+ * process.stdout.write(event.text ?? "")
181
+ * }
182
+ * break
183
+ * case "content_end":
184
+ * if (event.contentType === "tool") {
185
+ * console.log(`Done (${event.durationMs}ms)`)
186
+ * }
187
+ * break
188
+ * }
189
+ * }
190
+ *
191
+ * const result = await stream.getResult()
192
+ * console.log("\nTotal cost:", result.usage.totalCost)
193
+ * ```
194
+ */
195
+ export function streamRun(agent: Agent, message: string): AgentStream {
196
+ return new AgentStreamImpl(agent, message, false);
197
+ }
198
+
199
+ /**
200
+ * Create a streaming agent continuation
201
+ *
202
+ * Like streamRun, but continues an existing conversation.
203
+ *
204
+ * @param agent - The agent to continue
205
+ * @param message - The user message to add
206
+ * @returns An AgentStream for real-time event consumption
207
+ */
208
+ export function streamContinue(agent: Agent, message: string): AgentStream {
209
+ return new AgentStreamImpl(agent, message, true);
210
+ }
211
+
212
+ // =============================================================================
213
+ // Utility Functions
214
+ // =============================================================================
215
+
216
+ /**
217
+ * Collect all events from a stream into an array
218
+ *
219
+ * Useful for testing or when you need all events at once.
220
+ */
221
+ export async function collectEvents(
222
+ stream: AgentStream,
223
+ ): Promise<AgentEvent[]> {
224
+ const events: AgentEvent[] = [];
225
+ for await (const event of stream) {
226
+ events.push(event);
227
+ }
228
+ return events;
229
+ }
230
+
231
+ /**
232
+ * Filter events by type
233
+ *
234
+ * @example
235
+ * ```typescript
236
+ * for await (const event of filterEvents(stream, "text")) {
237
+ * console.log(event.text)
238
+ * }
239
+ * ```
240
+ */
241
+ export async function* filterEvents<T extends AgentEvent["type"]>(
242
+ stream: AgentStream,
243
+ type: T,
244
+ ): AsyncGenerator<Extract<AgentEvent, { type: T }>> {
245
+ for await (const event of stream) {
246
+ if (event.type === type) {
247
+ yield event as Extract<AgentEvent, { type: T }>;
248
+ }
249
+ }
250
+ }
251
+
252
+ /**
253
+ * Map events to a different format
254
+ */
255
+ export async function* mapEvents<T>(
256
+ stream: AgentStream,
257
+ mapper: (event: AgentEvent) => T,
258
+ ): AsyncGenerator<T> {
259
+ for await (const event of stream) {
260
+ yield mapper(event);
261
+ }
262
+ }
263
+
264
+ /**
265
+ * Buffer events and yield in batches
266
+ */
267
+ export async function* batchEvents(
268
+ stream: AgentStream,
269
+ batchSize: number,
270
+ ): AsyncGenerator<AgentEvent[]> {
271
+ let batch: AgentEvent[] = [];
272
+
273
+ for await (const event of stream) {
274
+ batch.push(event);
275
+ if (batch.length >= batchSize) {
276
+ yield batch;
277
+ batch = [];
278
+ }
279
+ }
280
+
281
+ if (batch.length > 0) {
282
+ yield batch;
283
+ }
284
+ }
285
+
286
+ /**
287
+ * Create a simple text accumulator that yields text as it streams
288
+ *
289
+ * @example
290
+ * ```typescript
291
+ * for await (const text of streamText(agent, "Hello")) {
292
+ * process.stdout.write(text)
293
+ * }
294
+ * ```
295
+ */
296
+ export async function* streamText(
297
+ agent: Agent,
298
+ message: string,
299
+ ): AsyncGenerator<string> {
300
+ const stream = streamRun(agent, message);
301
+
302
+ for await (const event of stream) {
303
+ if (event.type === "content_start" && event.contentType === "text") {
304
+ yield event.text ?? "";
305
+ }
306
+ }
307
+ }
@@ -0,0 +1,63 @@
1
+ // =============================================================================
2
+ // Spawn Agent Tool
3
+ // =============================================================================
4
+
5
+ export {
6
+ createSpawnAgentTool,
7
+ type SpawnAgentInput,
8
+ type SpawnAgentOutput,
9
+ type SpawnAgentToolConfig,
10
+ type SubAgentEndContext,
11
+ type SubAgentStartContext,
12
+ } from "./spawn-agent-tool.js";
13
+
14
+ // =============================================================================
15
+ // Multi-Agent
16
+ // =============================================================================
17
+
18
+ export {
19
+ type AgentTask,
20
+ AgentTeam,
21
+ AgentTeamsRuntime,
22
+ type AgentTeamsRuntimeOptions,
23
+ type AppendMissionLogInput,
24
+ type AttachTeamOutcomeFragmentInput,
25
+ type CreateTeamOutcomeInput,
26
+ type CreateTeamTaskInput,
27
+ createAgentTeam,
28
+ createWorkerReviewerTeam,
29
+ type MissionLogEntry,
30
+ type MissionLogKind,
31
+ type ReviewTeamOutcomeFragmentInput,
32
+ type RouteToTeammateOptions,
33
+ type SpawnTeammateOptions,
34
+ type TaskResult,
35
+ type TeamEvent,
36
+ type TeamMailboxMessage,
37
+ type TeamMemberConfig,
38
+ type TeamMemberSnapshot,
39
+ TeamMessageType,
40
+ type TeammateLifecycleSpec,
41
+ type TeamOutcome,
42
+ type TeamOutcomeFragment,
43
+ type TeamOutcomeFragmentStatus,
44
+ type TeamOutcomeStatus,
45
+ type TeamRunRecord,
46
+ type TeamRunStatus,
47
+ type TeamRuntimeSnapshot,
48
+ type TeamRuntimeState,
49
+ type TeamTask,
50
+ type TeamTaskStatus,
51
+ } from "./multi-agent.js";
52
+
53
+ export {
54
+ type BootstrapAgentTeamsOptions,
55
+ type BootstrapAgentTeamsResult,
56
+ bootstrapAgentTeams,
57
+ type CreateAgentTeamsToolsOptions,
58
+ createAgentTeamsTools,
59
+ reviveTeamStateDates,
60
+ sanitizeTeamName,
61
+ type TeamTeammateRuntimeConfig,
62
+ type TeamTeammateSpec,
63
+ } from "./team-tools.js";
@@ -0,0 +1,48 @@
1
+ import { describe, expect, it, vi } from "vitest";
2
+ import {
3
+ AgentTeamsRuntime,
4
+ type TeamEvent,
5
+ TeamMessageType,
6
+ } from "./multi-agent";
7
+
8
+ vi.mock("../agent.js", () => ({
9
+ createAgent: vi.fn(() => ({
10
+ abort: vi.fn(),
11
+ run: vi.fn(),
12
+ continue: vi.fn(),
13
+ getAgentId: vi.fn(() => "teammate-1"),
14
+ getConversationId: vi.fn(() => "conv-1"),
15
+ })),
16
+ }));
17
+
18
+ describe("AgentTeamsRuntime teammate lifecycle events", () => {
19
+ it("emits teammate_spawned with lifecycle payload", () => {
20
+ const events: TeamEvent[] = [];
21
+ const runtime = new AgentTeamsRuntime({
22
+ teamName: "test-team",
23
+ onTeamEvent: (event) => events.push(event),
24
+ });
25
+
26
+ runtime.spawnTeammate({
27
+ agentId: "python-poet",
28
+ config: {
29
+ providerId: "anthropic",
30
+ modelId: "claude-sonnet-4-5-20250929",
31
+ systemPrompt: "Write concise Python-focused haiku",
32
+ maxIterations: 7,
33
+ tools: [],
34
+ },
35
+ });
36
+
37
+ expect(events).toContainEqual({
38
+ type: TeamMessageType.TeammateSpawned,
39
+ agentId: "python-poet",
40
+ role: undefined,
41
+ teammate: {
42
+ rolePrompt: "Write concise Python-focused haiku",
43
+ modelId: "claude-sonnet-4-5-20250929",
44
+ maxIterations: 7,
45
+ },
46
+ });
47
+ });
48
+ });