opencode-swarm-plugin 0.32.0 → 0.33.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/.turbo/turbo-build.log +9 -10
- package/.turbo/turbo-test.log +347 -341
- package/CHANGELOG.md +260 -0
- package/README.md +127 -182
- package/bin/swarm.test.ts +31 -0
- package/bin/swarm.ts +247 -12
- package/dist/index.d.ts +17 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +530 -5
- package/dist/observability-tools.d.ts +116 -0
- package/dist/observability-tools.d.ts.map +1 -0
- package/dist/plugin.js +530 -5
- package/dist/skills.d.ts.map +1 -1
- package/dist/swarm-prompts.d.ts +59 -0
- package/dist/swarm-prompts.d.ts.map +1 -1
- package/dist/swarm.d.ts +17 -0
- package/dist/swarm.d.ts.map +1 -1
- package/examples/plugin-wrapper-template.ts +297 -8
- package/package.json +3 -2
- package/src/index.ts +25 -1
- package/src/observability-tools.test.ts +346 -0
- package/src/observability-tools.ts +594 -0
- package/src/skills.integration.test.ts +137 -1
- package/src/skills.test.ts +42 -1
- package/src/skills.ts +8 -4
- package/src/swarm-orchestrate.test.ts +123 -0
- package/src/swarm-orchestrate.ts +183 -0
- package/src/swarm-prompts.test.ts +389 -0
- package/src/swarm-prompts.ts +228 -0
- package/src/swarm-research.integration.test.ts +544 -0
- package/src/swarm-research.test.ts +698 -0
- package/src/swarm-research.ts +472 -0
- package/src/swarm.ts +6 -3
|
@@ -8,7 +8,9 @@
|
|
|
8
8
|
import { describe, expect, test } from "bun:test";
|
|
9
9
|
import {
|
|
10
10
|
formatSubtaskPromptV2,
|
|
11
|
+
formatResearcherPrompt,
|
|
11
12
|
SUBTASK_PROMPT_V2,
|
|
13
|
+
RESEARCHER_PROMPT,
|
|
12
14
|
} from "./swarm-prompts";
|
|
13
15
|
|
|
14
16
|
describe("SUBTASK_PROMPT_V2", () => {
|
|
@@ -266,3 +268,390 @@ describe("swarm_spawn_subtask tool", () => {
|
|
|
266
268
|
expect(instructions).toContain("DO THIS IMMEDIATELY");
|
|
267
269
|
});
|
|
268
270
|
});
|
|
271
|
+
|
|
272
|
+
describe("RESEARCHER_PROMPT", () => {
|
|
273
|
+
describe("required sections", () => {
|
|
274
|
+
test("includes IDENTITY section with research_id and epic_id", () => {
|
|
275
|
+
expect(RESEARCHER_PROMPT).toContain("## [IDENTITY]");
|
|
276
|
+
expect(RESEARCHER_PROMPT).toContain("{research_id}");
|
|
277
|
+
expect(RESEARCHER_PROMPT).toContain("{epic_id}");
|
|
278
|
+
});
|
|
279
|
+
|
|
280
|
+
test("includes MISSION section explaining the role", () => {
|
|
281
|
+
expect(RESEARCHER_PROMPT).toContain("## [MISSION]");
|
|
282
|
+
expect(RESEARCHER_PROMPT).toMatch(/gather.*documentation/i);
|
|
283
|
+
});
|
|
284
|
+
|
|
285
|
+
test("includes WORKFLOW section with numbered steps", () => {
|
|
286
|
+
expect(RESEARCHER_PROMPT).toContain("## [WORKFLOW]");
|
|
287
|
+
expect(RESEARCHER_PROMPT).toContain("### Step 1:");
|
|
288
|
+
expect(RESEARCHER_PROMPT).toContain("### Step 2:");
|
|
289
|
+
});
|
|
290
|
+
|
|
291
|
+
test("includes CRITICAL REQUIREMENTS section", () => {
|
|
292
|
+
expect(RESEARCHER_PROMPT).toContain("## [CRITICAL REQUIREMENTS]");
|
|
293
|
+
expect(RESEARCHER_PROMPT).toMatch(/NON-NEGOTIABLE/i);
|
|
294
|
+
});
|
|
295
|
+
});
|
|
296
|
+
|
|
297
|
+
describe("workflow steps", () => {
|
|
298
|
+
test("Step 1 is swarmmail_init (MANDATORY FIRST)", () => {
|
|
299
|
+
expect(RESEARCHER_PROMPT).toMatch(/### Step 1:.*Initialize/i);
|
|
300
|
+
expect(RESEARCHER_PROMPT).toContain("swarmmail_init");
|
|
301
|
+
expect(RESEARCHER_PROMPT).toContain("project_path");
|
|
302
|
+
});
|
|
303
|
+
|
|
304
|
+
test("Step 2 is discovering available documentation tools", () => {
|
|
305
|
+
const step2Match = RESEARCHER_PROMPT.match(/### Step 2:[\s\S]*?### Step 3:/);
|
|
306
|
+
expect(step2Match).not.toBeNull();
|
|
307
|
+
if (!step2Match) return;
|
|
308
|
+
|
|
309
|
+
const step2Content = step2Match[0];
|
|
310
|
+
expect(step2Content).toMatch(/discover.*tools/i);
|
|
311
|
+
expect(step2Content).toContain("nextjs_docs");
|
|
312
|
+
expect(step2Content).toContain("context7");
|
|
313
|
+
expect(step2Content).toContain("fetch");
|
|
314
|
+
expect(step2Content).toContain("pdf-brain");
|
|
315
|
+
});
|
|
316
|
+
|
|
317
|
+
test("Step 3 is reading installed versions", () => {
|
|
318
|
+
const step3Match = RESEARCHER_PROMPT.match(/### Step 3:[\s\S]*?### Step 4:/);
|
|
319
|
+
expect(step3Match).not.toBeNull();
|
|
320
|
+
if (!step3Match) return;
|
|
321
|
+
|
|
322
|
+
const step3Content = step3Match[0];
|
|
323
|
+
expect(step3Content).toMatch(/read.*installed.*version/i);
|
|
324
|
+
expect(step3Content).toContain("package.json");
|
|
325
|
+
});
|
|
326
|
+
|
|
327
|
+
test("Step 4 is fetching documentation", () => {
|
|
328
|
+
const step4Match = RESEARCHER_PROMPT.match(/### Step 4:[\s\S]*?### Step 5:/);
|
|
329
|
+
expect(step4Match).not.toBeNull();
|
|
330
|
+
if (!step4Match) return;
|
|
331
|
+
|
|
332
|
+
const step4Content = step4Match[0];
|
|
333
|
+
expect(step4Content).toMatch(/fetch.*documentation/i);
|
|
334
|
+
expect(step4Content).toContain("INSTALLED version");
|
|
335
|
+
});
|
|
336
|
+
|
|
337
|
+
test("Step 5 is storing detailed findings in semantic-memory", () => {
|
|
338
|
+
const step5Match = RESEARCHER_PROMPT.match(/### Step 5:[\s\S]*?### Step 6:/);
|
|
339
|
+
expect(step5Match).not.toBeNull();
|
|
340
|
+
if (!step5Match) return;
|
|
341
|
+
|
|
342
|
+
const step5Content = step5Match[0];
|
|
343
|
+
expect(step5Content).toContain("semantic-memory_store");
|
|
344
|
+
expect(step5Content).toMatch(/store.*individually/i);
|
|
345
|
+
});
|
|
346
|
+
|
|
347
|
+
test("Step 6 is broadcasting summary to coordinator", () => {
|
|
348
|
+
const step6Match = RESEARCHER_PROMPT.match(/### Step 6:[\s\S]*?### Step 7:/);
|
|
349
|
+
expect(step6Match).not.toBeNull();
|
|
350
|
+
if (!step6Match) return;
|
|
351
|
+
|
|
352
|
+
const step6Content = step6Match[0];
|
|
353
|
+
expect(step6Content).toContain("swarmmail_send");
|
|
354
|
+
expect(step6Content).toContain("coordinator");
|
|
355
|
+
});
|
|
356
|
+
|
|
357
|
+
test("Step 7 is returning structured JSON output", () => {
|
|
358
|
+
const step7Match = RESEARCHER_PROMPT.match(/### Step 7:[\s\S]*?(?=## \[|$)/);
|
|
359
|
+
expect(step7Match).not.toBeNull();
|
|
360
|
+
if (!step7Match) return;
|
|
361
|
+
|
|
362
|
+
const step7Content = step7Match[0];
|
|
363
|
+
expect(step7Content).toContain("JSON");
|
|
364
|
+
expect(step7Content).toContain("technologies");
|
|
365
|
+
expect(step7Content).toContain("summary");
|
|
366
|
+
});
|
|
367
|
+
});
|
|
368
|
+
|
|
369
|
+
describe("coordinator-provided tech stack", () => {
|
|
370
|
+
test("emphasizes that coordinator provides the tech list", () => {
|
|
371
|
+
expect(RESEARCHER_PROMPT).toMatch(/COORDINATOR PROVIDED.*TECHNOLOGIES/i);
|
|
372
|
+
expect(RESEARCHER_PROMPT).toContain("{tech_stack}");
|
|
373
|
+
});
|
|
374
|
+
|
|
375
|
+
test("clarifies researcher does NOT discover what to research", () => {
|
|
376
|
+
expect(RESEARCHER_PROMPT).toMatch(/NOT discover what to research/i);
|
|
377
|
+
expect(RESEARCHER_PROMPT).toMatch(/DO discover.*TOOLS/i);
|
|
378
|
+
});
|
|
379
|
+
});
|
|
380
|
+
|
|
381
|
+
describe("upgrade comparison mode", () => {
|
|
382
|
+
test("includes placeholder for check_upgrades mode", () => {
|
|
383
|
+
expect(RESEARCHER_PROMPT).toContain("{check_upgrades}");
|
|
384
|
+
});
|
|
385
|
+
|
|
386
|
+
test("mentions comparing installed vs latest when in upgrade mode", () => {
|
|
387
|
+
expect(RESEARCHER_PROMPT).toMatch(/check-upgrades/i);
|
|
388
|
+
expect(RESEARCHER_PROMPT).toMatch(/compare|latest.*version/i);
|
|
389
|
+
});
|
|
390
|
+
});
|
|
391
|
+
|
|
392
|
+
describe("output requirements", () => {
|
|
393
|
+
test("specifies TWO output destinations: semantic-memory and return JSON", () => {
|
|
394
|
+
expect(RESEARCHER_PROMPT).toMatch(/TWO places/i);
|
|
395
|
+
expect(RESEARCHER_PROMPT).toContain("semantic-memory");
|
|
396
|
+
expect(RESEARCHER_PROMPT).toContain("Return JSON");
|
|
397
|
+
});
|
|
398
|
+
|
|
399
|
+
test("explains semantic-memory is for detailed findings", () => {
|
|
400
|
+
expect(RESEARCHER_PROMPT).toMatch(/semantic-memory.*detailed/i);
|
|
401
|
+
});
|
|
402
|
+
|
|
403
|
+
test("explains return JSON is for condensed summary", () => {
|
|
404
|
+
expect(RESEARCHER_PROMPT).toMatch(/return.*condensed.*summary/i);
|
|
405
|
+
});
|
|
406
|
+
});
|
|
407
|
+
});
|
|
408
|
+
|
|
409
|
+
describe("formatResearcherPrompt", () => {
|
|
410
|
+
test("substitutes research_id placeholder", () => {
|
|
411
|
+
const result = formatResearcherPrompt({
|
|
412
|
+
research_id: "research-abc123",
|
|
413
|
+
epic_id: "epic-xyz789",
|
|
414
|
+
tech_stack: ["Next.js", "React"],
|
|
415
|
+
project_path: "/path/to/project",
|
|
416
|
+
check_upgrades: false,
|
|
417
|
+
});
|
|
418
|
+
|
|
419
|
+
expect(result).toContain("research-abc123");
|
|
420
|
+
expect(result).not.toContain("{research_id}");
|
|
421
|
+
});
|
|
422
|
+
|
|
423
|
+
test("substitutes epic_id placeholder", () => {
|
|
424
|
+
const result = formatResearcherPrompt({
|
|
425
|
+
research_id: "research-abc123",
|
|
426
|
+
epic_id: "epic-xyz789",
|
|
427
|
+
tech_stack: ["Next.js"],
|
|
428
|
+
project_path: "/path/to/project",
|
|
429
|
+
check_upgrades: false,
|
|
430
|
+
});
|
|
431
|
+
|
|
432
|
+
expect(result).toContain("epic-xyz789");
|
|
433
|
+
expect(result).not.toContain("{epic_id}");
|
|
434
|
+
});
|
|
435
|
+
|
|
436
|
+
test("formats tech_stack as bulleted list", () => {
|
|
437
|
+
const result = formatResearcherPrompt({
|
|
438
|
+
research_id: "research-abc123",
|
|
439
|
+
epic_id: "epic-xyz789",
|
|
440
|
+
tech_stack: ["Next.js", "React", "TypeScript"],
|
|
441
|
+
project_path: "/path/to/project",
|
|
442
|
+
check_upgrades: false,
|
|
443
|
+
});
|
|
444
|
+
|
|
445
|
+
expect(result).toContain("- Next.js");
|
|
446
|
+
expect(result).toContain("- React");
|
|
447
|
+
expect(result).toContain("- TypeScript");
|
|
448
|
+
});
|
|
449
|
+
|
|
450
|
+
test("substitutes project_path placeholder", () => {
|
|
451
|
+
const result = formatResearcherPrompt({
|
|
452
|
+
research_id: "research-abc123",
|
|
453
|
+
epic_id: "epic-xyz789",
|
|
454
|
+
tech_stack: ["Next.js"],
|
|
455
|
+
project_path: "/Users/joel/Code/my-project",
|
|
456
|
+
check_upgrades: false,
|
|
457
|
+
});
|
|
458
|
+
|
|
459
|
+
expect(result).toContain("/Users/joel/Code/my-project");
|
|
460
|
+
expect(result).not.toContain("{project_path}");
|
|
461
|
+
});
|
|
462
|
+
|
|
463
|
+
test("includes DEFAULT MODE text when check_upgrades=false", () => {
|
|
464
|
+
const result = formatResearcherPrompt({
|
|
465
|
+
research_id: "research-abc123",
|
|
466
|
+
epic_id: "epic-xyz789",
|
|
467
|
+
tech_stack: ["Next.js"],
|
|
468
|
+
project_path: "/path/to/project",
|
|
469
|
+
check_upgrades: false,
|
|
470
|
+
});
|
|
471
|
+
|
|
472
|
+
expect(result).toContain("DEFAULT MODE");
|
|
473
|
+
expect(result).toContain("INSTALLED versions only");
|
|
474
|
+
});
|
|
475
|
+
|
|
476
|
+
test("includes UPGRADE COMPARISON MODE text when check_upgrades=true", () => {
|
|
477
|
+
const result = formatResearcherPrompt({
|
|
478
|
+
research_id: "research-abc123",
|
|
479
|
+
epic_id: "epic-xyz789",
|
|
480
|
+
tech_stack: ["Next.js"],
|
|
481
|
+
project_path: "/path/to/project",
|
|
482
|
+
check_upgrades: true,
|
|
483
|
+
});
|
|
484
|
+
|
|
485
|
+
expect(result).toContain("UPGRADE COMPARISON MODE");
|
|
486
|
+
expect(result).toContain("BOTH installed AND latest");
|
|
487
|
+
expect(result).toContain("breaking changes");
|
|
488
|
+
});
|
|
489
|
+
});
|
|
490
|
+
|
|
491
|
+
describe("on-demand research section", () => {
|
|
492
|
+
test("includes ON-DEMAND RESEARCH section after Step 9", () => {
|
|
493
|
+
// Find Step 9 and the section after it
|
|
494
|
+
const step9Pos = SUBTASK_PROMPT_V2.indexOf("### Step 9:");
|
|
495
|
+
const swarmMailPos = SUBTASK_PROMPT_V2.indexOf("## [SWARM MAIL COMMUNICATION]");
|
|
496
|
+
|
|
497
|
+
expect(step9Pos).toBeGreaterThan(0);
|
|
498
|
+
expect(swarmMailPos).toBeGreaterThan(step9Pos);
|
|
499
|
+
|
|
500
|
+
// Extract the section between Step 9 and SWARM MAIL
|
|
501
|
+
const betweenSection = SUBTASK_PROMPT_V2.substring(step9Pos, swarmMailPos);
|
|
502
|
+
|
|
503
|
+
expect(betweenSection).toContain("## [ON-DEMAND RESEARCH]");
|
|
504
|
+
});
|
|
505
|
+
|
|
506
|
+
test("research section instructs to check semantic-memory first", () => {
|
|
507
|
+
const researchMatch = SUBTASK_PROMPT_V2.match(/## \[ON-DEMAND RESEARCH\][\s\S]*?## \[SWARM MAIL/);
|
|
508
|
+
expect(researchMatch).not.toBeNull();
|
|
509
|
+
if (!researchMatch) return;
|
|
510
|
+
|
|
511
|
+
const researchContent = researchMatch[0];
|
|
512
|
+
expect(researchContent).toContain("semantic-memory_find");
|
|
513
|
+
expect(researchContent).toMatch(/check.*semantic-memory.*first/i);
|
|
514
|
+
});
|
|
515
|
+
|
|
516
|
+
test("research section includes swarm_spawn_researcher tool usage", () => {
|
|
517
|
+
const researchMatch = SUBTASK_PROMPT_V2.match(/## \[ON-DEMAND RESEARCH\][\s\S]*?## \[SWARM MAIL/);
|
|
518
|
+
expect(researchMatch).not.toBeNull();
|
|
519
|
+
if (!researchMatch) return;
|
|
520
|
+
|
|
521
|
+
const researchContent = researchMatch[0];
|
|
522
|
+
expect(researchContent).toContain("swarm_spawn_researcher");
|
|
523
|
+
});
|
|
524
|
+
|
|
525
|
+
test("research section lists specific research triggers", () => {
|
|
526
|
+
const researchMatch = SUBTASK_PROMPT_V2.match(/## \[ON-DEMAND RESEARCH\][\s\S]*?## \[SWARM MAIL/);
|
|
527
|
+
expect(researchMatch).not.toBeNull();
|
|
528
|
+
if (!researchMatch) return;
|
|
529
|
+
|
|
530
|
+
const researchContent = researchMatch[0];
|
|
531
|
+
|
|
532
|
+
// Should list when TO research
|
|
533
|
+
expect(researchContent).toMatch(/triggers|when to research/i);
|
|
534
|
+
expect(researchContent).toMatch(/API.*works|breaking changes|outdated/i);
|
|
535
|
+
});
|
|
536
|
+
|
|
537
|
+
test("research section lists when NOT to research", () => {
|
|
538
|
+
const researchMatch = SUBTASK_PROMPT_V2.match(/## \[ON-DEMAND RESEARCH\][\s\S]*?## \[SWARM MAIL/);
|
|
539
|
+
expect(researchMatch).not.toBeNull();
|
|
540
|
+
if (!researchMatch) return;
|
|
541
|
+
|
|
542
|
+
const researchContent = researchMatch[0];
|
|
543
|
+
|
|
544
|
+
// Should list when to SKIP research
|
|
545
|
+
expect(researchContent).toMatch(/don't research|skip research/i);
|
|
546
|
+
expect(researchContent).toMatch(/standard patterns|well-documented|obvious/i);
|
|
547
|
+
});
|
|
548
|
+
|
|
549
|
+
test("research section includes 3-step workflow", () => {
|
|
550
|
+
const researchMatch = SUBTASK_PROMPT_V2.match(/## \[ON-DEMAND RESEARCH\][\s\S]*?## \[SWARM MAIL/);
|
|
551
|
+
expect(researchMatch).not.toBeNull();
|
|
552
|
+
if (!researchMatch) return;
|
|
553
|
+
|
|
554
|
+
const researchContent = researchMatch[0];
|
|
555
|
+
|
|
556
|
+
// Should have numbered steps
|
|
557
|
+
expect(researchContent).toMatch(/1\.\s*.*Check semantic-memory/i);
|
|
558
|
+
expect(researchContent).toMatch(/2\.\s*.*spawn researcher/i);
|
|
559
|
+
expect(researchContent).toMatch(/3\.\s*.*wait.*continue/i);
|
|
560
|
+
});
|
|
561
|
+
});
|
|
562
|
+
|
|
563
|
+
describe("swarm_spawn_researcher tool", () => {
|
|
564
|
+
test("returns JSON with prompt field", async () => {
|
|
565
|
+
const { swarm_spawn_researcher } = await import("./swarm-prompts");
|
|
566
|
+
|
|
567
|
+
const result = await swarm_spawn_researcher.execute({
|
|
568
|
+
research_id: "research-abc123",
|
|
569
|
+
epic_id: "epic-xyz789",
|
|
570
|
+
tech_stack: ["Next.js", "React"],
|
|
571
|
+
project_path: "/Users/joel/Code/project",
|
|
572
|
+
});
|
|
573
|
+
|
|
574
|
+
const parsed = JSON.parse(result);
|
|
575
|
+
expect(parsed).toHaveProperty("prompt");
|
|
576
|
+
expect(typeof parsed.prompt).toBe("string");
|
|
577
|
+
expect(parsed.prompt.length).toBeGreaterThan(100);
|
|
578
|
+
});
|
|
579
|
+
|
|
580
|
+
test("returns subagent_type field as 'swarm/researcher'", async () => {
|
|
581
|
+
const { swarm_spawn_researcher } = await import("./swarm-prompts");
|
|
582
|
+
|
|
583
|
+
const result = await swarm_spawn_researcher.execute({
|
|
584
|
+
research_id: "research-abc123",
|
|
585
|
+
epic_id: "epic-xyz789",
|
|
586
|
+
tech_stack: ["Next.js"],
|
|
587
|
+
project_path: "/Users/joel/Code/project",
|
|
588
|
+
});
|
|
589
|
+
|
|
590
|
+
const parsed = JSON.parse(result);
|
|
591
|
+
expect(parsed.subagent_type).toBe("swarm/researcher");
|
|
592
|
+
});
|
|
593
|
+
|
|
594
|
+
test("returns expected_output schema", async () => {
|
|
595
|
+
const { swarm_spawn_researcher } = await import("./swarm-prompts");
|
|
596
|
+
|
|
597
|
+
const result = await swarm_spawn_researcher.execute({
|
|
598
|
+
research_id: "research-abc123",
|
|
599
|
+
epic_id: "epic-xyz789",
|
|
600
|
+
tech_stack: ["Next.js"],
|
|
601
|
+
project_path: "/Users/joel/Code/project",
|
|
602
|
+
});
|
|
603
|
+
|
|
604
|
+
const parsed = JSON.parse(result);
|
|
605
|
+
expect(parsed).toHaveProperty("expected_output");
|
|
606
|
+
expect(parsed.expected_output).toHaveProperty("technologies");
|
|
607
|
+
expect(parsed.expected_output).toHaveProperty("summary");
|
|
608
|
+
});
|
|
609
|
+
|
|
610
|
+
test("defaults check_upgrades to false when not provided", async () => {
|
|
611
|
+
const { swarm_spawn_researcher } = await import("./swarm-prompts");
|
|
612
|
+
|
|
613
|
+
const result = await swarm_spawn_researcher.execute({
|
|
614
|
+
research_id: "research-abc123",
|
|
615
|
+
epic_id: "epic-xyz789",
|
|
616
|
+
tech_stack: ["Next.js"],
|
|
617
|
+
project_path: "/Users/joel/Code/project",
|
|
618
|
+
});
|
|
619
|
+
|
|
620
|
+
const parsed = JSON.parse(result);
|
|
621
|
+
expect(parsed.check_upgrades).toBe(false);
|
|
622
|
+
});
|
|
623
|
+
|
|
624
|
+
test("respects check_upgrades when provided as true", async () => {
|
|
625
|
+
const { swarm_spawn_researcher } = await import("./swarm-prompts");
|
|
626
|
+
|
|
627
|
+
const result = await swarm_spawn_researcher.execute({
|
|
628
|
+
research_id: "research-abc123",
|
|
629
|
+
epic_id: "epic-xyz789",
|
|
630
|
+
tech_stack: ["Next.js"],
|
|
631
|
+
project_path: "/Users/joel/Code/project",
|
|
632
|
+
check_upgrades: true,
|
|
633
|
+
});
|
|
634
|
+
|
|
635
|
+
const parsed = JSON.parse(result);
|
|
636
|
+
expect(parsed.check_upgrades).toBe(true);
|
|
637
|
+
});
|
|
638
|
+
|
|
639
|
+
test("includes all input parameters in returned JSON", async () => {
|
|
640
|
+
const { swarm_spawn_researcher } = await import("./swarm-prompts");
|
|
641
|
+
|
|
642
|
+
const result = await swarm_spawn_researcher.execute({
|
|
643
|
+
research_id: "research-abc123",
|
|
644
|
+
epic_id: "epic-xyz789",
|
|
645
|
+
tech_stack: ["Next.js", "React", "TypeScript"],
|
|
646
|
+
project_path: "/Users/joel/Code/project",
|
|
647
|
+
check_upgrades: true,
|
|
648
|
+
});
|
|
649
|
+
|
|
650
|
+
const parsed = JSON.parse(result);
|
|
651
|
+
expect(parsed.research_id).toBe("research-abc123");
|
|
652
|
+
expect(parsed.epic_id).toBe("epic-xyz789");
|
|
653
|
+
expect(parsed.tech_stack).toEqual(["Next.js", "React", "TypeScript"]);
|
|
654
|
+
expect(parsed.project_path).toBe("/Users/joel/Code/project");
|
|
655
|
+
expect(parsed.check_upgrades).toBe(true);
|
|
656
|
+
});
|
|
657
|
+
});
|
package/src/swarm-prompts.ts
CHANGED
|
@@ -464,6 +464,29 @@ swarm_complete(
|
|
|
464
464
|
|
|
465
465
|
**DO NOT manually close the cell with hive_close.** Use swarm_complete.
|
|
466
466
|
|
|
467
|
+
## [ON-DEMAND RESEARCH]
|
|
468
|
+
|
|
469
|
+
If you encounter unknown API behavior or version-specific issues:
|
|
470
|
+
|
|
471
|
+
1. **Check semantic-memory first:**
|
|
472
|
+
\`semantic-memory_find(query="<library> <version> <topic>", limit=3, expand=true)\`
|
|
473
|
+
|
|
474
|
+
2. **If not found, spawn researcher:**
|
|
475
|
+
\`swarm_spawn_researcher(research_id="{bead_id}-research", epic_id="{epic_id}", tech_stack=["<library>"], project_path="{project_path}")\`
|
|
476
|
+
Then spawn with Task tool: \`Task(subagent_type="swarm/researcher", prompt="<from above>")\`
|
|
477
|
+
|
|
478
|
+
3. **Wait for research, then continue**
|
|
479
|
+
|
|
480
|
+
**Research triggers:**
|
|
481
|
+
- "I'm not sure how this API works in version X"
|
|
482
|
+
- "This might have breaking changes"
|
|
483
|
+
- "The docs I remember might be outdated"
|
|
484
|
+
|
|
485
|
+
**Don't research:**
|
|
486
|
+
- Standard patterns you're confident about
|
|
487
|
+
- Well-documented, stable APIs
|
|
488
|
+
- Obvious implementations
|
|
489
|
+
|
|
467
490
|
## [SWARM MAIL COMMUNICATION]
|
|
468
491
|
|
|
469
492
|
### Check Inbox Regularly
|
|
@@ -551,6 +574,124 @@ Other cell operations:
|
|
|
551
574
|
|
|
552
575
|
Begin now.`;
|
|
553
576
|
|
|
577
|
+
/**
|
|
578
|
+
* Researcher prompt template for documentation discovery
|
|
579
|
+
*
|
|
580
|
+
* Spawned BEFORE decomposition to gather technology documentation.
|
|
581
|
+
* Researchers receive an EXPLICIT list of technologies to research from the coordinator.
|
|
582
|
+
* They dynamically discover WHAT TOOLS are available to fetch docs.
|
|
583
|
+
* Output: condensed summary for shared_context + detailed findings in semantic-memory.
|
|
584
|
+
*/
|
|
585
|
+
export const RESEARCHER_PROMPT = `You are a swarm researcher gathering documentation for: **{research_id}**
|
|
586
|
+
|
|
587
|
+
## [IDENTITY]
|
|
588
|
+
Agent: (assigned at spawn)
|
|
589
|
+
Research Task: {research_id}
|
|
590
|
+
Epic: {epic_id}
|
|
591
|
+
|
|
592
|
+
## [MISSION]
|
|
593
|
+
Gather comprehensive documentation for the specified technologies to inform task decomposition.
|
|
594
|
+
|
|
595
|
+
**COORDINATOR PROVIDED THESE TECHNOLOGIES TO RESEARCH:**
|
|
596
|
+
{tech_stack}
|
|
597
|
+
|
|
598
|
+
You do NOT discover what to research - the coordinator already decided that.
|
|
599
|
+
You DO discover what TOOLS are available to fetch documentation.
|
|
600
|
+
|
|
601
|
+
## [OUTPUT MODE]
|
|
602
|
+
{check_upgrades}
|
|
603
|
+
|
|
604
|
+
## [WORKFLOW]
|
|
605
|
+
|
|
606
|
+
### Step 1: Initialize (MANDATORY FIRST)
|
|
607
|
+
\`\`\`
|
|
608
|
+
swarmmail_init(project_path="{project_path}", task_description="{research_id}: Documentation research")
|
|
609
|
+
\`\`\`
|
|
610
|
+
|
|
611
|
+
### Step 2: Discover Available Documentation Tools
|
|
612
|
+
Check what's available for fetching docs:
|
|
613
|
+
- **next-devtools**: \`nextjs_docs\` for Next.js documentation
|
|
614
|
+
- **context7**: Library documentation lookup (\`use context7\` in prompts)
|
|
615
|
+
- **fetch**: General web fetching for official docs sites
|
|
616
|
+
- **pdf-brain**: Internal knowledge base search
|
|
617
|
+
|
|
618
|
+
**Don't assume** - check which tools exist in your environment.
|
|
619
|
+
|
|
620
|
+
### Step 3: Read Installed Versions
|
|
621
|
+
For each technology in the tech stack:
|
|
622
|
+
1. Check package.json (or equivalent) for installed version
|
|
623
|
+
2. Record exact version numbers
|
|
624
|
+
3. Note any version constraints (^, ~, etc.)
|
|
625
|
+
|
|
626
|
+
### Step 4: Fetch Documentation
|
|
627
|
+
For EACH technology in the list:
|
|
628
|
+
- Use the most appropriate tool (Next.js → nextjs_docs, libraries → context7, others → fetch)
|
|
629
|
+
- Fetch documentation for the INSTALLED version (not latest, unless --check-upgrades)
|
|
630
|
+
- Focus on: API changes, breaking changes, migration guides, best practices
|
|
631
|
+
- Extract key patterns, gotchas, and compatibility notes
|
|
632
|
+
|
|
633
|
+
**If --check-upgrades mode:**
|
|
634
|
+
- ALSO fetch docs for the LATEST version
|
|
635
|
+
- Compare installed vs latest
|
|
636
|
+
- Note breaking changes, new features, migration complexity
|
|
637
|
+
|
|
638
|
+
### Step 5: Store Detailed Findings
|
|
639
|
+
For EACH technology, store in semantic-memory:
|
|
640
|
+
\`\`\`
|
|
641
|
+
semantic-memory_store(
|
|
642
|
+
information="<technology-name> <version>: <key patterns, gotchas, API changes, compatibility notes>",
|
|
643
|
+
tags="research, <tech-name>, documentation, {epic_id}"
|
|
644
|
+
)
|
|
645
|
+
\`\`\`
|
|
646
|
+
|
|
647
|
+
**Why store individually?** Future agents can search by technology name.
|
|
648
|
+
|
|
649
|
+
### Step 6: Broadcast Summary
|
|
650
|
+
Send condensed findings to coordinator:
|
|
651
|
+
\`\`\`
|
|
652
|
+
swarmmail_send(
|
|
653
|
+
to=["coordinator"],
|
|
654
|
+
subject="Research Complete: {research_id}",
|
|
655
|
+
body="<brief summary - see semantic-memory for details>",
|
|
656
|
+
thread_id="{epic_id}"
|
|
657
|
+
)
|
|
658
|
+
\`\`\`
|
|
659
|
+
|
|
660
|
+
### Step 7: Return Structured Output
|
|
661
|
+
Output JSON with:
|
|
662
|
+
\`\`\`json
|
|
663
|
+
{
|
|
664
|
+
"technologies": [
|
|
665
|
+
{
|
|
666
|
+
"name": "string",
|
|
667
|
+
"installed_version": "string",
|
|
668
|
+
"latest_version": "string | null", // Only if --check-upgrades
|
|
669
|
+
"key_patterns": ["string"],
|
|
670
|
+
"gotchas": ["string"],
|
|
671
|
+
"breaking_changes": ["string"], // Only if --check-upgrades
|
|
672
|
+
"memory_id": "string" // ID of semantic-memory entry
|
|
673
|
+
}
|
|
674
|
+
],
|
|
675
|
+
"summary": "string" // Condensed summary for shared_context
|
|
676
|
+
}
|
|
677
|
+
\`\`\`
|
|
678
|
+
|
|
679
|
+
## [CRITICAL REQUIREMENTS]
|
|
680
|
+
|
|
681
|
+
**NON-NEGOTIABLE:**
|
|
682
|
+
1. Step 1 (swarmmail_init) MUST be first
|
|
683
|
+
2. Research ONLY the technologies the coordinator specified
|
|
684
|
+
3. Fetch docs for INSTALLED versions (unless --check-upgrades)
|
|
685
|
+
4. Store detailed findings in semantic-memory (one per technology)
|
|
686
|
+
5. Return condensed summary for coordinator (full details in memory)
|
|
687
|
+
6. Use appropriate doc tools (nextjs_docs for Next.js, context7 for libraries, etc.)
|
|
688
|
+
|
|
689
|
+
**Output goes TWO places:**
|
|
690
|
+
- **semantic-memory**: Detailed findings (searchable by future agents)
|
|
691
|
+
- **Return JSON**: Condensed summary (for coordinator's shared_context)
|
|
692
|
+
|
|
693
|
+
Begin research now.`;
|
|
694
|
+
|
|
554
695
|
/**
|
|
555
696
|
* Coordinator post-worker checklist - MANDATORY review loop
|
|
556
697
|
*
|
|
@@ -656,6 +797,30 @@ should describe what needs to be fixed.`;
|
|
|
656
797
|
// Helper Functions
|
|
657
798
|
// ============================================================================
|
|
658
799
|
|
|
800
|
+
/**
|
|
801
|
+
* Format the researcher prompt for a documentation research task
|
|
802
|
+
*/
|
|
803
|
+
export function formatResearcherPrompt(params: {
|
|
804
|
+
research_id: string;
|
|
805
|
+
epic_id: string;
|
|
806
|
+
tech_stack: string[];
|
|
807
|
+
project_path: string;
|
|
808
|
+
check_upgrades: boolean;
|
|
809
|
+
}): string {
|
|
810
|
+
const techList = params.tech_stack.map((t) => `- ${t}`).join("\n");
|
|
811
|
+
|
|
812
|
+
const upgradesMode = params.check_upgrades
|
|
813
|
+
? "**UPGRADE COMPARISON MODE**: Fetch docs for BOTH installed AND latest versions. Compare and note breaking changes."
|
|
814
|
+
: "**DEFAULT MODE**: Fetch docs for INSTALLED versions only (from lockfiles).";
|
|
815
|
+
|
|
816
|
+
return RESEARCHER_PROMPT
|
|
817
|
+
.replace(/{research_id}/g, params.research_id)
|
|
818
|
+
.replace(/{epic_id}/g, params.epic_id)
|
|
819
|
+
.replace("{tech_stack}", techList)
|
|
820
|
+
.replace("{project_path}", params.project_path)
|
|
821
|
+
.replace("{check_upgrades}", upgradesMode);
|
|
822
|
+
}
|
|
823
|
+
|
|
659
824
|
/**
|
|
660
825
|
* Format the V2 subtask prompt for a specific agent
|
|
661
826
|
*/
|
|
@@ -937,6 +1102,68 @@ export const swarm_spawn_subtask = tool({
|
|
|
937
1102
|
},
|
|
938
1103
|
});
|
|
939
1104
|
|
|
1105
|
+
/**
|
|
1106
|
+
* Prepare a researcher task for spawning with Task tool
|
|
1107
|
+
*
|
|
1108
|
+
* Generates a prompt that tells the researcher to fetch documentation for specific technologies.
|
|
1109
|
+
* Returns JSON that can be directly used with Task tool.
|
|
1110
|
+
*/
|
|
1111
|
+
export const swarm_spawn_researcher = tool({
|
|
1112
|
+
description:
|
|
1113
|
+
"Prepare a research task for spawning. Returns prompt for gathering technology documentation. Researcher fetches docs and stores findings in semantic-memory.",
|
|
1114
|
+
args: {
|
|
1115
|
+
research_id: tool.schema.string().describe("Unique ID for this research task"),
|
|
1116
|
+
epic_id: tool.schema.string().describe("Parent epic ID"),
|
|
1117
|
+
tech_stack: tool.schema
|
|
1118
|
+
.array(tool.schema.string())
|
|
1119
|
+
.describe("Explicit list of technologies to research (from coordinator)"),
|
|
1120
|
+
project_path: tool.schema
|
|
1121
|
+
.string()
|
|
1122
|
+
.describe("Absolute project path for swarmmail_init"),
|
|
1123
|
+
check_upgrades: tool.schema
|
|
1124
|
+
.boolean()
|
|
1125
|
+
.optional()
|
|
1126
|
+
.describe("If true, compare installed vs latest versions (default: false)"),
|
|
1127
|
+
},
|
|
1128
|
+
async execute(args) {
|
|
1129
|
+
const prompt = formatResearcherPrompt({
|
|
1130
|
+
research_id: args.research_id,
|
|
1131
|
+
epic_id: args.epic_id,
|
|
1132
|
+
tech_stack: args.tech_stack,
|
|
1133
|
+
project_path: args.project_path,
|
|
1134
|
+
check_upgrades: args.check_upgrades ?? false,
|
|
1135
|
+
});
|
|
1136
|
+
|
|
1137
|
+
return JSON.stringify(
|
|
1138
|
+
{
|
|
1139
|
+
prompt,
|
|
1140
|
+
research_id: args.research_id,
|
|
1141
|
+
epic_id: args.epic_id,
|
|
1142
|
+
tech_stack: args.tech_stack,
|
|
1143
|
+
project_path: args.project_path,
|
|
1144
|
+
check_upgrades: args.check_upgrades ?? false,
|
|
1145
|
+
subagent_type: "swarm/researcher",
|
|
1146
|
+
expected_output: {
|
|
1147
|
+
technologies: [
|
|
1148
|
+
{
|
|
1149
|
+
name: "string",
|
|
1150
|
+
installed_version: "string",
|
|
1151
|
+
latest_version: "string | null",
|
|
1152
|
+
key_patterns: ["string"],
|
|
1153
|
+
gotchas: ["string"],
|
|
1154
|
+
breaking_changes: ["string"],
|
|
1155
|
+
memory_id: "string",
|
|
1156
|
+
},
|
|
1157
|
+
],
|
|
1158
|
+
summary: "string",
|
|
1159
|
+
},
|
|
1160
|
+
},
|
|
1161
|
+
null,
|
|
1162
|
+
2,
|
|
1163
|
+
);
|
|
1164
|
+
},
|
|
1165
|
+
});
|
|
1166
|
+
|
|
940
1167
|
/**
|
|
941
1168
|
* Generate self-evaluation prompt
|
|
942
1169
|
*/
|
|
@@ -1125,6 +1352,7 @@ export const swarm_plan_prompt = tool({
|
|
|
1125
1352
|
export const promptTools = {
|
|
1126
1353
|
swarm_subtask_prompt,
|
|
1127
1354
|
swarm_spawn_subtask,
|
|
1355
|
+
swarm_spawn_researcher,
|
|
1128
1356
|
swarm_evaluation_prompt,
|
|
1129
1357
|
swarm_plan_prompt,
|
|
1130
1358
|
};
|