opencode-swarm-plugin 0.17.1 → 0.19.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.
- package/.beads/issues.jsonl +95 -85
- package/.github/workflows/ci.yml +5 -1
- package/README.md +48 -4
- package/dist/index.js +2652 -2080
- package/dist/plugin.js +2302 -1725
- package/package.json +1 -1
- package/src/agent-mail.ts +13 -0
- package/src/anti-patterns.test.ts +1167 -0
- package/src/anti-patterns.ts +29 -11
- package/src/learning.ts +106 -0
- package/src/pattern-maturity.ts +51 -13
- package/src/plugin.ts +15 -3
- package/src/rate-limiter.ts +48 -4
- package/src/schemas/bead.ts +35 -4
- package/src/schemas/evaluation.ts +18 -6
- package/src/schemas/index.ts +25 -2
- package/src/schemas/task.ts +49 -21
- package/src/streams/debug.ts +101 -3
- package/src/streams/index.ts +87 -1
- package/src/streams/migrations.ts +46 -4
- package/src/streams/projections.ts +15 -0
- package/src/streams/store.integration.test.ts +110 -0
- package/src/streams/store.ts +447 -193
- package/src/structured.test.ts +1046 -0
- package/src/structured.ts +74 -27
- package/src/swarm-decompose.ts +912 -0
- package/src/swarm-orchestrate.ts +1869 -0
- package/src/swarm-prompts.ts +756 -0
- package/src/swarm-strategies.ts +407 -0
- package/src/swarm.ts +23 -3639
- package/src/tool-availability.ts +29 -6
- package/test-bug-fixes.ts +86 -0
|
@@ -0,0 +1,756 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Swarm Prompts Module - Prompt templates and generation
|
|
3
|
+
*
|
|
4
|
+
* Provides all prompt templates used for swarm coordination:
|
|
5
|
+
* - Decomposition prompts (basic and strategy-specific)
|
|
6
|
+
* - Subtask agent prompts (V1 and V2)
|
|
7
|
+
* - Evaluation prompts
|
|
8
|
+
*
|
|
9
|
+
* Key responsibilities:
|
|
10
|
+
* - Prompt template definitions
|
|
11
|
+
* - Prompt formatting/generation tools
|
|
12
|
+
* - Template parameter substitution
|
|
13
|
+
*/
|
|
14
|
+
|
|
15
|
+
import { tool } from "@opencode-ai/plugin";
|
|
16
|
+
|
|
17
|
+
// ============================================================================
|
|
18
|
+
// Prompt Templates
|
|
19
|
+
// ============================================================================
|
|
20
|
+
|
|
21
|
+
/**
|
|
22
|
+
* Prompt for decomposing a task into parallelizable subtasks.
|
|
23
|
+
*
|
|
24
|
+
* Used by swarm_decompose to instruct the agent on how to break down work.
|
|
25
|
+
* The agent responds with a BeadTree that gets validated.
|
|
26
|
+
*/
|
|
27
|
+
export const DECOMPOSITION_PROMPT = `You are decomposing a task into parallelizable subtasks for a swarm of agents.
|
|
28
|
+
|
|
29
|
+
## Task
|
|
30
|
+
{task}
|
|
31
|
+
|
|
32
|
+
{context_section}
|
|
33
|
+
|
|
34
|
+
## MANDATORY: Beads Issue Tracking
|
|
35
|
+
|
|
36
|
+
**Every subtask MUST become a bead.** This is non-negotiable.
|
|
37
|
+
|
|
38
|
+
After decomposition, the coordinator will:
|
|
39
|
+
1. Create an epic bead for the overall task
|
|
40
|
+
2. Create child beads for each subtask
|
|
41
|
+
3. Track progress through bead status updates
|
|
42
|
+
4. Close beads with summaries when complete
|
|
43
|
+
|
|
44
|
+
Agents MUST update their bead status as they work. No silent progress.
|
|
45
|
+
|
|
46
|
+
## Requirements
|
|
47
|
+
|
|
48
|
+
1. **Break into 2-{max_subtasks} independent subtasks** that can run in parallel
|
|
49
|
+
2. **Assign files** - each subtask must specify which files it will modify
|
|
50
|
+
3. **No file overlap** - files cannot appear in multiple subtasks (they get exclusive locks)
|
|
51
|
+
4. **Order by dependency** - if subtask B needs subtask A's output, A must come first in the array
|
|
52
|
+
5. **Estimate complexity** - 1 (trivial) to 5 (complex)
|
|
53
|
+
6. **Plan aggressively** - break down more than you think necessary, smaller is better
|
|
54
|
+
|
|
55
|
+
## Response Format
|
|
56
|
+
|
|
57
|
+
Respond with a JSON object matching this schema:
|
|
58
|
+
|
|
59
|
+
\`\`\`typescript
|
|
60
|
+
{
|
|
61
|
+
epic: {
|
|
62
|
+
title: string, // Epic title for the beads tracker
|
|
63
|
+
description?: string // Brief description of the overall goal
|
|
64
|
+
},
|
|
65
|
+
subtasks: [
|
|
66
|
+
{
|
|
67
|
+
title: string, // What this subtask accomplishes
|
|
68
|
+
description?: string, // Detailed instructions for the agent
|
|
69
|
+
files: string[], // Files this subtask will modify (globs allowed)
|
|
70
|
+
dependencies: number[], // Indices of subtasks this depends on (0-indexed)
|
|
71
|
+
estimated_complexity: 1-5 // Effort estimate
|
|
72
|
+
},
|
|
73
|
+
// ... more subtasks
|
|
74
|
+
]
|
|
75
|
+
}
|
|
76
|
+
\`\`\`
|
|
77
|
+
|
|
78
|
+
## Guidelines
|
|
79
|
+
|
|
80
|
+
- **Plan aggressively** - when in doubt, split further. 3 small tasks > 1 medium task
|
|
81
|
+
- **Prefer smaller, focused subtasks** over large complex ones
|
|
82
|
+
- **Include test files** in the same subtask as the code they test
|
|
83
|
+
- **Consider shared types** - if multiple files share types, handle that first
|
|
84
|
+
- **Think about imports** - changes to exported APIs affect downstream files
|
|
85
|
+
- **Explicit > implicit** - spell out what each subtask should do, don't assume
|
|
86
|
+
|
|
87
|
+
## File Assignment Examples
|
|
88
|
+
|
|
89
|
+
- Schema change: \`["src/schemas/user.ts", "src/schemas/index.ts"]\`
|
|
90
|
+
- Component + test: \`["src/components/Button.tsx", "src/components/Button.test.tsx"]\`
|
|
91
|
+
- API route: \`["src/app/api/users/route.ts"]\`
|
|
92
|
+
|
|
93
|
+
Now decompose the task:`;
|
|
94
|
+
|
|
95
|
+
/**
|
|
96
|
+
* Strategy-specific decomposition prompt template
|
|
97
|
+
*/
|
|
98
|
+
export const STRATEGY_DECOMPOSITION_PROMPT = `You are decomposing a task into parallelizable subtasks for a swarm of agents.
|
|
99
|
+
|
|
100
|
+
## Task
|
|
101
|
+
{task}
|
|
102
|
+
|
|
103
|
+
{strategy_guidelines}
|
|
104
|
+
|
|
105
|
+
{context_section}
|
|
106
|
+
|
|
107
|
+
{cass_history}
|
|
108
|
+
|
|
109
|
+
{skills_context}
|
|
110
|
+
|
|
111
|
+
## MANDATORY: Beads Issue Tracking
|
|
112
|
+
|
|
113
|
+
**Every subtask MUST become a bead.** This is non-negotiable.
|
|
114
|
+
|
|
115
|
+
After decomposition, the coordinator will:
|
|
116
|
+
1. Create an epic bead for the overall task
|
|
117
|
+
2. Create child beads for each subtask
|
|
118
|
+
3. Track progress through bead status updates
|
|
119
|
+
4. Close beads with summaries when complete
|
|
120
|
+
|
|
121
|
+
Agents MUST update their bead status as they work. No silent progress.
|
|
122
|
+
|
|
123
|
+
## Requirements
|
|
124
|
+
|
|
125
|
+
1. **Break into 2-{max_subtasks} independent subtasks** that can run in parallel
|
|
126
|
+
2. **Assign files** - each subtask must specify which files it will modify
|
|
127
|
+
3. **No file overlap** - files cannot appear in multiple subtasks (they get exclusive locks)
|
|
128
|
+
4. **Order by dependency** - if subtask B needs subtask A's output, A must come first in the array
|
|
129
|
+
5. **Estimate complexity** - 1 (trivial) to 5 (complex)
|
|
130
|
+
6. **Plan aggressively** - break down more than you think necessary, smaller is better
|
|
131
|
+
|
|
132
|
+
## Response Format
|
|
133
|
+
|
|
134
|
+
Respond with a JSON object matching this schema:
|
|
135
|
+
|
|
136
|
+
\`\`\`typescript
|
|
137
|
+
{
|
|
138
|
+
epic: {
|
|
139
|
+
title: string, // Epic title for the beads tracker
|
|
140
|
+
description?: string // Brief description of the overall goal
|
|
141
|
+
},
|
|
142
|
+
subtasks: [
|
|
143
|
+
{
|
|
144
|
+
title: string, // What this subtask accomplishes
|
|
145
|
+
description?: string, // Detailed instructions for the agent
|
|
146
|
+
files: string[], // Files this subtask will modify (globs allowed)
|
|
147
|
+
dependencies: number[], // Indices of subtasks this depends on (0-indexed)
|
|
148
|
+
estimated_complexity: 1-5 // Effort estimate
|
|
149
|
+
},
|
|
150
|
+
// ... more subtasks
|
|
151
|
+
]
|
|
152
|
+
}
|
|
153
|
+
\`\`\`
|
|
154
|
+
|
|
155
|
+
Now decompose the task:`;
|
|
156
|
+
|
|
157
|
+
/**
|
|
158
|
+
* Prompt template for spawned subtask agents.
|
|
159
|
+
*
|
|
160
|
+
* Each agent receives this prompt with their specific subtask details filled in.
|
|
161
|
+
* The prompt establishes context, constraints, and expectations.
|
|
162
|
+
*/
|
|
163
|
+
export const SUBTASK_PROMPT = `You are a swarm agent working on a subtask of a larger epic.
|
|
164
|
+
|
|
165
|
+
## Your Identity
|
|
166
|
+
- **Agent Name**: {agent_name}
|
|
167
|
+
- **Bead ID**: {bead_id}
|
|
168
|
+
- **Epic ID**: {epic_id}
|
|
169
|
+
|
|
170
|
+
## Your Subtask
|
|
171
|
+
**Title**: {subtask_title}
|
|
172
|
+
|
|
173
|
+
{subtask_description}
|
|
174
|
+
|
|
175
|
+
## File Scope
|
|
176
|
+
You have exclusive reservations for these files:
|
|
177
|
+
{file_list}
|
|
178
|
+
|
|
179
|
+
**CRITICAL**: Only modify files in your reservation. If you need to modify other files,
|
|
180
|
+
send a message to the coordinator requesting the change.
|
|
181
|
+
|
|
182
|
+
## Shared Context
|
|
183
|
+
{shared_context}
|
|
184
|
+
|
|
185
|
+
## MANDATORY: Beads Tracking
|
|
186
|
+
|
|
187
|
+
You MUST keep your bead updated as you work:
|
|
188
|
+
|
|
189
|
+
1. **Your bead is already in_progress** - don't change this unless blocked
|
|
190
|
+
2. **If blocked**: \`bd update {bead_id} --status blocked\` and message coordinator
|
|
191
|
+
3. **When done**: Use \`swarm_complete\` - it closes your bead automatically
|
|
192
|
+
4. **Discovered issues**: Create new beads with \`bd create "issue" -t bug\`
|
|
193
|
+
|
|
194
|
+
**Never work silently.** Your bead status is how the swarm tracks progress.
|
|
195
|
+
|
|
196
|
+
## MANDATORY: Swarm Mail Communication
|
|
197
|
+
|
|
198
|
+
You MUST communicate with other agents:
|
|
199
|
+
|
|
200
|
+
1. **Report progress** every significant milestone (not just at the end)
|
|
201
|
+
2. **Ask questions** if requirements are unclear - don't guess
|
|
202
|
+
3. **Announce blockers** immediately - don't spin trying to fix alone
|
|
203
|
+
4. **Coordinate on shared concerns** - if you see something affecting other agents, say so
|
|
204
|
+
|
|
205
|
+
Use Swarm Mail for all communication:
|
|
206
|
+
\`\`\`
|
|
207
|
+
swarmmail_send(
|
|
208
|
+
to: ["coordinator" or specific agent],
|
|
209
|
+
subject: "Brief subject",
|
|
210
|
+
body: "Message content",
|
|
211
|
+
thread_id: "{epic_id}"
|
|
212
|
+
)
|
|
213
|
+
\`\`\`
|
|
214
|
+
|
|
215
|
+
## Coordination Protocol
|
|
216
|
+
|
|
217
|
+
1. **Start**: Your bead is already marked in_progress
|
|
218
|
+
2. **Progress**: Use swarm_progress to report status updates
|
|
219
|
+
3. **Blocked**: Report immediately via Swarm Mail - don't spin
|
|
220
|
+
4. **Complete**: Use swarm_complete when done - it handles:
|
|
221
|
+
- Closing your bead with a summary
|
|
222
|
+
- Releasing file reservations
|
|
223
|
+
- Notifying the coordinator
|
|
224
|
+
|
|
225
|
+
## Self-Evaluation
|
|
226
|
+
|
|
227
|
+
Before calling swarm_complete, evaluate your work:
|
|
228
|
+
- Type safety: Does it compile without errors?
|
|
229
|
+
- No obvious bugs: Did you handle edge cases?
|
|
230
|
+
- Follows patterns: Does it match existing code style?
|
|
231
|
+
- Readable: Would another developer understand it?
|
|
232
|
+
|
|
233
|
+
If evaluation fails, fix the issues before completing.
|
|
234
|
+
|
|
235
|
+
## Planning Your Work
|
|
236
|
+
|
|
237
|
+
Before writing code:
|
|
238
|
+
1. **Read the files** you're assigned to understand current state
|
|
239
|
+
2. **Plan your approach** - what changes, in what order?
|
|
240
|
+
3. **Identify risks** - what could go wrong? What dependencies?
|
|
241
|
+
4. **Communicate your plan** via Swarm Mail if non-trivial
|
|
242
|
+
|
|
243
|
+
Begin work on your subtask now.`;
|
|
244
|
+
|
|
245
|
+
/**
|
|
246
|
+
* Streamlined subtask prompt (V2) - uses Swarm Mail and beads
|
|
247
|
+
*
|
|
248
|
+
* This is a cleaner version of SUBTASK_PROMPT that's easier to parse.
|
|
249
|
+
* Agents MUST use Swarm Mail for communication and beads for tracking.
|
|
250
|
+
*
|
|
251
|
+
* Supports {error_context} placeholder for retry prompts.
|
|
252
|
+
*/
|
|
253
|
+
export const SUBTASK_PROMPT_V2 = `You are a swarm agent working on: **{subtask_title}**
|
|
254
|
+
|
|
255
|
+
## [IDENTITY]
|
|
256
|
+
Agent: (assigned at spawn)
|
|
257
|
+
Bead: {bead_id}
|
|
258
|
+
Epic: {epic_id}
|
|
259
|
+
|
|
260
|
+
## [TASK]
|
|
261
|
+
{subtask_description}
|
|
262
|
+
|
|
263
|
+
## [FILES]
|
|
264
|
+
Reserved (exclusive):
|
|
265
|
+
{file_list}
|
|
266
|
+
|
|
267
|
+
Only modify these files. Need others? Message the coordinator.
|
|
268
|
+
|
|
269
|
+
## [CONTEXT]
|
|
270
|
+
{shared_context}
|
|
271
|
+
|
|
272
|
+
{compressed_context}
|
|
273
|
+
|
|
274
|
+
{error_context}
|
|
275
|
+
|
|
276
|
+
## [MANDATORY: SWARM MAIL]
|
|
277
|
+
|
|
278
|
+
**YOU MUST USE SWARM MAIL FOR ALL COORDINATION.** This is non-negotiable.
|
|
279
|
+
|
|
280
|
+
### Initialize FIRST (before any work)
|
|
281
|
+
\`\`\`
|
|
282
|
+
swarmmail_init(project_path="$PWD", task_description="{subtask_title}")
|
|
283
|
+
\`\`\`
|
|
284
|
+
|
|
285
|
+
### Reserve Files (if not already reserved by coordinator)
|
|
286
|
+
\`\`\`
|
|
287
|
+
swarmmail_reserve(paths=[...files...], reason="{bead_id}: {subtask_title}")
|
|
288
|
+
\`\`\`
|
|
289
|
+
|
|
290
|
+
### Check Inbox Regularly
|
|
291
|
+
\`\`\`
|
|
292
|
+
swarmmail_inbox() # Check for coordinator messages
|
|
293
|
+
swarmmail_read_message(message_id=N) # Read specific message
|
|
294
|
+
\`\`\`
|
|
295
|
+
|
|
296
|
+
### Report Progress (REQUIRED - don't work silently)
|
|
297
|
+
\`\`\`
|
|
298
|
+
swarmmail_send(
|
|
299
|
+
to=["coordinator"],
|
|
300
|
+
subject="Progress: {bead_id}",
|
|
301
|
+
body="<what you did, blockers, questions>",
|
|
302
|
+
thread_id="{epic_id}"
|
|
303
|
+
)
|
|
304
|
+
\`\`\`
|
|
305
|
+
|
|
306
|
+
### When Blocked
|
|
307
|
+
\`\`\`
|
|
308
|
+
swarmmail_send(
|
|
309
|
+
to=["coordinator"],
|
|
310
|
+
subject="BLOCKED: {bead_id}",
|
|
311
|
+
body="<blocker description, what you need>",
|
|
312
|
+
importance="high",
|
|
313
|
+
thread_id="{epic_id}"
|
|
314
|
+
)
|
|
315
|
+
beads_update(id="{bead_id}", status="blocked")
|
|
316
|
+
\`\`\`
|
|
317
|
+
|
|
318
|
+
### Release Files When Done
|
|
319
|
+
\`\`\`
|
|
320
|
+
swarmmail_release() # Or let swarm_complete handle it
|
|
321
|
+
\`\`\`
|
|
322
|
+
|
|
323
|
+
## [OTHER TOOLS]
|
|
324
|
+
### Beads
|
|
325
|
+
- beads_update(id, status) - Mark blocked if stuck
|
|
326
|
+
- beads_create(title, type) - Log new bugs found
|
|
327
|
+
|
|
328
|
+
### Skills (if available)
|
|
329
|
+
- skills_list() - Discover available skills
|
|
330
|
+
- skills_use(name) - Activate skill for specialized guidance
|
|
331
|
+
|
|
332
|
+
### Completion (REQUIRED)
|
|
333
|
+
- swarm_complete(project_key, agent_name, bead_id, summary, files_touched)
|
|
334
|
+
|
|
335
|
+
## [LEARNING]
|
|
336
|
+
As you work, note reusable patterns, best practices, or domain insights:
|
|
337
|
+
- If you discover something that would help future agents, consider creating a skill
|
|
338
|
+
- Use skills_create to codify patterns for the project
|
|
339
|
+
- Good skills have clear "when to use" descriptions with actionable instructions
|
|
340
|
+
- Skills make swarms smarter over time
|
|
341
|
+
|
|
342
|
+
## [WORKFLOW]
|
|
343
|
+
1. **swarmmail_init** - Initialize session FIRST
|
|
344
|
+
2. Read assigned files
|
|
345
|
+
3. Implement changes
|
|
346
|
+
4. **swarmmail_send** - Report progress to coordinator
|
|
347
|
+
5. Verify (typecheck)
|
|
348
|
+
6. **swarm_complete** - Mark done, release reservations
|
|
349
|
+
|
|
350
|
+
**CRITICAL: Never work silently. Send progress updates via swarmmail_send every significant milestone.**
|
|
351
|
+
|
|
352
|
+
Begin now.`;
|
|
353
|
+
|
|
354
|
+
/**
|
|
355
|
+
* Prompt for self-evaluation before completing a subtask.
|
|
356
|
+
*
|
|
357
|
+
* Agents use this to assess their work quality before marking complete.
|
|
358
|
+
*/
|
|
359
|
+
export const EVALUATION_PROMPT = `Evaluate the work completed for this subtask.
|
|
360
|
+
|
|
361
|
+
## Subtask
|
|
362
|
+
**Bead ID**: {bead_id}
|
|
363
|
+
**Title**: {subtask_title}
|
|
364
|
+
|
|
365
|
+
## Files Modified
|
|
366
|
+
{files_touched}
|
|
367
|
+
|
|
368
|
+
## Evaluation Criteria
|
|
369
|
+
|
|
370
|
+
For each criterion, assess passed/failed and provide brief feedback:
|
|
371
|
+
|
|
372
|
+
1. **type_safe**: Code compiles without TypeScript errors
|
|
373
|
+
2. **no_bugs**: No obvious bugs, edge cases handled
|
|
374
|
+
3. **patterns**: Follows existing codebase patterns and conventions
|
|
375
|
+
4. **readable**: Code is clear and maintainable
|
|
376
|
+
|
|
377
|
+
## Response Format
|
|
378
|
+
|
|
379
|
+
\`\`\`json
|
|
380
|
+
{
|
|
381
|
+
"passed": boolean, // Overall pass/fail
|
|
382
|
+
"criteria": {
|
|
383
|
+
"type_safe": { "passed": boolean, "feedback": string },
|
|
384
|
+
"no_bugs": { "passed": boolean, "feedback": string },
|
|
385
|
+
"patterns": { "passed": boolean, "feedback": string },
|
|
386
|
+
"readable": { "passed": boolean, "feedback": string }
|
|
387
|
+
},
|
|
388
|
+
"overall_feedback": string,
|
|
389
|
+
"retry_suggestion": string | null // If failed, what to fix
|
|
390
|
+
}
|
|
391
|
+
\`\`\`
|
|
392
|
+
|
|
393
|
+
If any criterion fails, the overall evaluation fails and retry_suggestion
|
|
394
|
+
should describe what needs to be fixed.`;
|
|
395
|
+
|
|
396
|
+
// ============================================================================
|
|
397
|
+
// Helper Functions
|
|
398
|
+
// ============================================================================
|
|
399
|
+
|
|
400
|
+
/**
|
|
401
|
+
* Format the V2 subtask prompt for a specific agent
|
|
402
|
+
*/
|
|
403
|
+
export function formatSubtaskPromptV2(params: {
|
|
404
|
+
bead_id: string;
|
|
405
|
+
epic_id: string;
|
|
406
|
+
subtask_title: string;
|
|
407
|
+
subtask_description: string;
|
|
408
|
+
files: string[];
|
|
409
|
+
shared_context?: string;
|
|
410
|
+
compressed_context?: string;
|
|
411
|
+
error_context?: string;
|
|
412
|
+
}): string {
|
|
413
|
+
const fileList =
|
|
414
|
+
params.files.length > 0
|
|
415
|
+
? params.files.map((f) => `- \`${f}\``).join("\n")
|
|
416
|
+
: "(no specific files - use judgment)";
|
|
417
|
+
|
|
418
|
+
const compressedSection = params.compressed_context
|
|
419
|
+
? params.compressed_context
|
|
420
|
+
: "";
|
|
421
|
+
|
|
422
|
+
const errorSection = params.error_context ? params.error_context : "";
|
|
423
|
+
|
|
424
|
+
return SUBTASK_PROMPT_V2.replace(/{bead_id}/g, params.bead_id)
|
|
425
|
+
.replace(/{epic_id}/g, params.epic_id)
|
|
426
|
+
.replace("{subtask_title}", params.subtask_title)
|
|
427
|
+
.replace(
|
|
428
|
+
"{subtask_description}",
|
|
429
|
+
params.subtask_description || "(see title)",
|
|
430
|
+
)
|
|
431
|
+
.replace("{file_list}", fileList)
|
|
432
|
+
.replace("{shared_context}", params.shared_context || "(none)")
|
|
433
|
+
.replace("{compressed_context}", compressedSection)
|
|
434
|
+
.replace("{error_context}", errorSection);
|
|
435
|
+
}
|
|
436
|
+
|
|
437
|
+
/**
|
|
438
|
+
* Format the subtask prompt for a specific agent
|
|
439
|
+
*/
|
|
440
|
+
export function formatSubtaskPrompt(params: {
|
|
441
|
+
agent_name: string;
|
|
442
|
+
bead_id: string;
|
|
443
|
+
epic_id: string;
|
|
444
|
+
subtask_title: string;
|
|
445
|
+
subtask_description: string;
|
|
446
|
+
files: string[];
|
|
447
|
+
shared_context?: string;
|
|
448
|
+
}): string {
|
|
449
|
+
const fileList = params.files.map((f) => `- \`${f}\``).join("\n");
|
|
450
|
+
|
|
451
|
+
return SUBTASK_PROMPT.replace("{agent_name}", params.agent_name)
|
|
452
|
+
.replace("{bead_id}", params.bead_id)
|
|
453
|
+
.replace(/{epic_id}/g, params.epic_id)
|
|
454
|
+
.replace("{subtask_title}", params.subtask_title)
|
|
455
|
+
.replace("{subtask_description}", params.subtask_description || "(none)")
|
|
456
|
+
.replace("{file_list}", fileList || "(no files assigned)")
|
|
457
|
+
.replace("{shared_context}", params.shared_context || "(none)");
|
|
458
|
+
}
|
|
459
|
+
|
|
460
|
+
/**
|
|
461
|
+
* Format the evaluation prompt
|
|
462
|
+
*/
|
|
463
|
+
export function formatEvaluationPrompt(params: {
|
|
464
|
+
bead_id: string;
|
|
465
|
+
subtask_title: string;
|
|
466
|
+
files_touched: string[];
|
|
467
|
+
}): string {
|
|
468
|
+
const filesList = params.files_touched.map((f) => `- \`${f}\``).join("\n");
|
|
469
|
+
|
|
470
|
+
return EVALUATION_PROMPT.replace("{bead_id}", params.bead_id)
|
|
471
|
+
.replace("{subtask_title}", params.subtask_title)
|
|
472
|
+
.replace("{files_touched}", filesList || "(no files recorded)");
|
|
473
|
+
}
|
|
474
|
+
|
|
475
|
+
// ============================================================================
|
|
476
|
+
// Tool Definitions
|
|
477
|
+
// ============================================================================
|
|
478
|
+
|
|
479
|
+
/**
|
|
480
|
+
* Generate subtask prompt for a spawned agent
|
|
481
|
+
*/
|
|
482
|
+
export const swarm_subtask_prompt = tool({
|
|
483
|
+
description: "Generate the prompt for a spawned subtask agent",
|
|
484
|
+
args: {
|
|
485
|
+
agent_name: tool.schema.string().describe("Agent Mail name for the agent"),
|
|
486
|
+
bead_id: tool.schema.string().describe("Subtask bead ID"),
|
|
487
|
+
epic_id: tool.schema.string().describe("Epic bead ID"),
|
|
488
|
+
subtask_title: tool.schema.string().describe("Subtask title"),
|
|
489
|
+
subtask_description: tool.schema
|
|
490
|
+
.string()
|
|
491
|
+
.optional()
|
|
492
|
+
.describe("Detailed subtask instructions"),
|
|
493
|
+
files: tool.schema
|
|
494
|
+
.array(tool.schema.string())
|
|
495
|
+
.describe("Files assigned to this subtask"),
|
|
496
|
+
shared_context: tool.schema
|
|
497
|
+
.string()
|
|
498
|
+
.optional()
|
|
499
|
+
.describe("Context shared across all agents"),
|
|
500
|
+
},
|
|
501
|
+
async execute(args) {
|
|
502
|
+
const prompt = formatSubtaskPrompt({
|
|
503
|
+
agent_name: args.agent_name,
|
|
504
|
+
bead_id: args.bead_id,
|
|
505
|
+
epic_id: args.epic_id,
|
|
506
|
+
subtask_title: args.subtask_title,
|
|
507
|
+
subtask_description: args.subtask_description || "",
|
|
508
|
+
files: args.files,
|
|
509
|
+
shared_context: args.shared_context,
|
|
510
|
+
});
|
|
511
|
+
|
|
512
|
+
return prompt;
|
|
513
|
+
},
|
|
514
|
+
});
|
|
515
|
+
|
|
516
|
+
/**
|
|
517
|
+
* Prepare a subtask for spawning with Task tool (V2 prompt)
|
|
518
|
+
*
|
|
519
|
+
* Generates a streamlined prompt that tells agents to USE Agent Mail and beads.
|
|
520
|
+
* Returns JSON that can be directly used with Task tool.
|
|
521
|
+
*/
|
|
522
|
+
export const swarm_spawn_subtask = tool({
|
|
523
|
+
description:
|
|
524
|
+
"Prepare a subtask for spawning. Returns prompt with Agent Mail/beads instructions.",
|
|
525
|
+
args: {
|
|
526
|
+
bead_id: tool.schema.string().describe("Subtask bead ID"),
|
|
527
|
+
epic_id: tool.schema.string().describe("Parent epic bead ID"),
|
|
528
|
+
subtask_title: tool.schema.string().describe("Subtask title"),
|
|
529
|
+
subtask_description: tool.schema
|
|
530
|
+
.string()
|
|
531
|
+
.optional()
|
|
532
|
+
.describe("Detailed subtask instructions"),
|
|
533
|
+
files: tool.schema
|
|
534
|
+
.array(tool.schema.string())
|
|
535
|
+
.describe("Files assigned to this subtask"),
|
|
536
|
+
shared_context: tool.schema
|
|
537
|
+
.string()
|
|
538
|
+
.optional()
|
|
539
|
+
.describe("Context shared across all agents"),
|
|
540
|
+
},
|
|
541
|
+
async execute(args) {
|
|
542
|
+
const prompt = formatSubtaskPromptV2({
|
|
543
|
+
bead_id: args.bead_id,
|
|
544
|
+
epic_id: args.epic_id,
|
|
545
|
+
subtask_title: args.subtask_title,
|
|
546
|
+
subtask_description: args.subtask_description || "",
|
|
547
|
+
files: args.files,
|
|
548
|
+
shared_context: args.shared_context,
|
|
549
|
+
});
|
|
550
|
+
|
|
551
|
+
return JSON.stringify(
|
|
552
|
+
{
|
|
553
|
+
prompt,
|
|
554
|
+
bead_id: args.bead_id,
|
|
555
|
+
epic_id: args.epic_id,
|
|
556
|
+
files: args.files,
|
|
557
|
+
},
|
|
558
|
+
null,
|
|
559
|
+
2,
|
|
560
|
+
);
|
|
561
|
+
},
|
|
562
|
+
});
|
|
563
|
+
|
|
564
|
+
/**
|
|
565
|
+
* Generate self-evaluation prompt
|
|
566
|
+
*/
|
|
567
|
+
export const swarm_evaluation_prompt = tool({
|
|
568
|
+
description: "Generate self-evaluation prompt for a completed subtask",
|
|
569
|
+
args: {
|
|
570
|
+
bead_id: tool.schema.string().describe("Subtask bead ID"),
|
|
571
|
+
subtask_title: tool.schema.string().describe("Subtask title"),
|
|
572
|
+
files_touched: tool.schema
|
|
573
|
+
.array(tool.schema.string())
|
|
574
|
+
.describe("Files that were modified"),
|
|
575
|
+
},
|
|
576
|
+
async execute(args) {
|
|
577
|
+
const prompt = formatEvaluationPrompt({
|
|
578
|
+
bead_id: args.bead_id,
|
|
579
|
+
subtask_title: args.subtask_title,
|
|
580
|
+
files_touched: args.files_touched,
|
|
581
|
+
});
|
|
582
|
+
|
|
583
|
+
return JSON.stringify(
|
|
584
|
+
{
|
|
585
|
+
prompt,
|
|
586
|
+
expected_schema: "Evaluation",
|
|
587
|
+
schema_hint: {
|
|
588
|
+
passed: "boolean",
|
|
589
|
+
criteria: {
|
|
590
|
+
type_safe: { passed: "boolean", feedback: "string" },
|
|
591
|
+
no_bugs: { passed: "boolean", feedback: "string" },
|
|
592
|
+
patterns: { passed: "boolean", feedback: "string" },
|
|
593
|
+
readable: { passed: "boolean", feedback: "string" },
|
|
594
|
+
},
|
|
595
|
+
overall_feedback: "string",
|
|
596
|
+
retry_suggestion: "string | null",
|
|
597
|
+
},
|
|
598
|
+
},
|
|
599
|
+
null,
|
|
600
|
+
2,
|
|
601
|
+
);
|
|
602
|
+
},
|
|
603
|
+
});
|
|
604
|
+
|
|
605
|
+
/**
|
|
606
|
+
* Generate a strategy-specific planning prompt
|
|
607
|
+
*
|
|
608
|
+
* Higher-level than swarm_decompose - includes strategy selection and guidelines.
|
|
609
|
+
* Use this when you want the full planning experience with strategy-specific advice.
|
|
610
|
+
*/
|
|
611
|
+
export const swarm_plan_prompt = tool({
|
|
612
|
+
description:
|
|
613
|
+
"Generate strategy-specific decomposition prompt. Auto-selects strategy or uses provided one. Queries CASS for similar tasks.",
|
|
614
|
+
args: {
|
|
615
|
+
task: tool.schema.string().min(1).describe("Task description to decompose"),
|
|
616
|
+
strategy: tool.schema
|
|
617
|
+
.enum(["file-based", "feature-based", "risk-based", "auto"])
|
|
618
|
+
.optional()
|
|
619
|
+
.describe("Decomposition strategy (default: auto-detect)"),
|
|
620
|
+
max_subtasks: tool.schema
|
|
621
|
+
.number()
|
|
622
|
+
.int()
|
|
623
|
+
.min(2)
|
|
624
|
+
.max(10)
|
|
625
|
+
.default(5)
|
|
626
|
+
.describe("Maximum number of subtasks (default: 5)"),
|
|
627
|
+
context: tool.schema
|
|
628
|
+
.string()
|
|
629
|
+
.optional()
|
|
630
|
+
.describe("Additional context (codebase info, constraints, etc.)"),
|
|
631
|
+
query_cass: tool.schema
|
|
632
|
+
.boolean()
|
|
633
|
+
.optional()
|
|
634
|
+
.describe("Query CASS for similar past tasks (default: true)"),
|
|
635
|
+
cass_limit: tool.schema
|
|
636
|
+
.number()
|
|
637
|
+
.int()
|
|
638
|
+
.min(1)
|
|
639
|
+
.max(10)
|
|
640
|
+
.optional()
|
|
641
|
+
.describe("Max CASS results to include (default: 3)"),
|
|
642
|
+
include_skills: tool.schema
|
|
643
|
+
.boolean()
|
|
644
|
+
.optional()
|
|
645
|
+
.describe("Include available skills in context (default: true)"),
|
|
646
|
+
},
|
|
647
|
+
async execute(args) {
|
|
648
|
+
// Import needed modules dynamically
|
|
649
|
+
const { selectStrategy, formatStrategyGuidelines, STRATEGIES } =
|
|
650
|
+
await import("./swarm-strategies");
|
|
651
|
+
const { formatMemoryQueryForDecomposition } = await import("./learning");
|
|
652
|
+
const { listSkills, getSkillsContextForSwarm, findRelevantSkills } =
|
|
653
|
+
await import("./skills");
|
|
654
|
+
|
|
655
|
+
// Select strategy
|
|
656
|
+
type StrategyName =
|
|
657
|
+
| "file-based"
|
|
658
|
+
| "feature-based"
|
|
659
|
+
| "risk-based"
|
|
660
|
+
| "research-based";
|
|
661
|
+
let selectedStrategy: StrategyName;
|
|
662
|
+
let strategyReasoning: string;
|
|
663
|
+
|
|
664
|
+
if (args.strategy && args.strategy !== "auto") {
|
|
665
|
+
selectedStrategy = args.strategy as StrategyName;
|
|
666
|
+
strategyReasoning = `User-specified strategy: ${selectedStrategy}`;
|
|
667
|
+
} else {
|
|
668
|
+
const selection = selectStrategy(args.task);
|
|
669
|
+
selectedStrategy = selection.strategy;
|
|
670
|
+
strategyReasoning = selection.reasoning;
|
|
671
|
+
}
|
|
672
|
+
|
|
673
|
+
// Fetch skills context
|
|
674
|
+
let skillsContext = "";
|
|
675
|
+
let skillsInfo: { included: boolean; count?: number; relevant?: string[] } =
|
|
676
|
+
{
|
|
677
|
+
included: false,
|
|
678
|
+
};
|
|
679
|
+
|
|
680
|
+
if (args.include_skills !== false) {
|
|
681
|
+
const allSkills = await listSkills();
|
|
682
|
+
if (allSkills.length > 0) {
|
|
683
|
+
skillsContext = await getSkillsContextForSwarm();
|
|
684
|
+
const relevantSkills = await findRelevantSkills(args.task);
|
|
685
|
+
skillsInfo = {
|
|
686
|
+
included: true,
|
|
687
|
+
count: allSkills.length,
|
|
688
|
+
relevant: relevantSkills,
|
|
689
|
+
};
|
|
690
|
+
|
|
691
|
+
// Add suggestion for relevant skills
|
|
692
|
+
if (relevantSkills.length > 0) {
|
|
693
|
+
skillsContext += `\n\n**Suggested skills for this task**: ${relevantSkills.join(", ")}`;
|
|
694
|
+
}
|
|
695
|
+
}
|
|
696
|
+
}
|
|
697
|
+
|
|
698
|
+
// Format strategy guidelines
|
|
699
|
+
const strategyGuidelines = formatStrategyGuidelines(selectedStrategy);
|
|
700
|
+
|
|
701
|
+
// Combine user context
|
|
702
|
+
const contextSection = args.context
|
|
703
|
+
? `## Additional Context\n${args.context}`
|
|
704
|
+
: "## Additional Context\n(none provided)";
|
|
705
|
+
|
|
706
|
+
// Build the prompt (without CASS - we'll let the module handle that)
|
|
707
|
+
const prompt = STRATEGY_DECOMPOSITION_PROMPT.replace("{task}", args.task)
|
|
708
|
+
.replace("{strategy_guidelines}", strategyGuidelines)
|
|
709
|
+
.replace("{context_section}", contextSection)
|
|
710
|
+
.replace("{cass_history}", "") // Empty for now
|
|
711
|
+
.replace("{skills_context}", skillsContext || "")
|
|
712
|
+
.replace("{max_subtasks}", (args.max_subtasks ?? 5).toString());
|
|
713
|
+
|
|
714
|
+
return JSON.stringify(
|
|
715
|
+
{
|
|
716
|
+
prompt,
|
|
717
|
+
strategy: {
|
|
718
|
+
selected: selectedStrategy,
|
|
719
|
+
reasoning: strategyReasoning,
|
|
720
|
+
guidelines:
|
|
721
|
+
STRATEGIES[selectedStrategy as keyof typeof STRATEGIES].guidelines,
|
|
722
|
+
anti_patterns:
|
|
723
|
+
STRATEGIES[selectedStrategy as keyof typeof STRATEGIES]
|
|
724
|
+
.antiPatterns,
|
|
725
|
+
},
|
|
726
|
+
expected_schema: "BeadTree",
|
|
727
|
+
schema_hint: {
|
|
728
|
+
epic: { title: "string", description: "string?" },
|
|
729
|
+
subtasks: [
|
|
730
|
+
{
|
|
731
|
+
title: "string",
|
|
732
|
+
description: "string?",
|
|
733
|
+
files: "string[]",
|
|
734
|
+
dependencies: "number[]",
|
|
735
|
+
estimated_complexity: "1-5",
|
|
736
|
+
},
|
|
737
|
+
],
|
|
738
|
+
},
|
|
739
|
+
validation_note:
|
|
740
|
+
"Parse agent response as JSON and validate with swarm_validate_decomposition",
|
|
741
|
+
skills: skillsInfo,
|
|
742
|
+
// Add semantic-memory query instruction
|
|
743
|
+
memory_query: formatMemoryQueryForDecomposition(args.task, 3),
|
|
744
|
+
},
|
|
745
|
+
null,
|
|
746
|
+
2,
|
|
747
|
+
);
|
|
748
|
+
},
|
|
749
|
+
});
|
|
750
|
+
|
|
751
|
+
export const promptTools = {
|
|
752
|
+
swarm_subtask_prompt,
|
|
753
|
+
swarm_spawn_subtask,
|
|
754
|
+
swarm_evaluation_prompt,
|
|
755
|
+
swarm_plan_prompt,
|
|
756
|
+
};
|