opencode-swarm-plugin 0.12.6 → 0.12.7
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 +9 -0
- package/dist/index.js +309 -25
- package/dist/plugin.js +308 -25
- package/package.json +1 -1
- package/src/agent-mail.ts +157 -26
- package/src/learning.ts +277 -0
- package/src/swarm.ts +176 -1
package/src/learning.ts
CHANGED
|
@@ -64,6 +64,46 @@ export const CriterionWeightSchema = z.object({
|
|
|
64
64
|
});
|
|
65
65
|
export type CriterionWeight = z.infer<typeof CriterionWeightSchema>;
|
|
66
66
|
|
|
67
|
+
/**
|
|
68
|
+
* Error types that can occur during subtask execution
|
|
69
|
+
*/
|
|
70
|
+
export const ErrorTypeSchema = z.enum([
|
|
71
|
+
"validation",
|
|
72
|
+
"timeout",
|
|
73
|
+
"conflict",
|
|
74
|
+
"tool_failure",
|
|
75
|
+
"unknown",
|
|
76
|
+
]);
|
|
77
|
+
export type ErrorType = z.infer<typeof ErrorTypeSchema>;
|
|
78
|
+
|
|
79
|
+
/**
|
|
80
|
+
* An error entry in the error accumulator
|
|
81
|
+
*
|
|
82
|
+
* Errors are accumulated during subtask execution and can be fed
|
|
83
|
+
* into retry prompts to help agents learn from past failures.
|
|
84
|
+
*/
|
|
85
|
+
export const ErrorEntrySchema = z.object({
|
|
86
|
+
/** Unique ID for this error entry */
|
|
87
|
+
id: z.string(),
|
|
88
|
+
/** The bead ID this error relates to */
|
|
89
|
+
bead_id: z.string(),
|
|
90
|
+
/** Type of error encountered */
|
|
91
|
+
error_type: ErrorTypeSchema,
|
|
92
|
+
/** Human-readable error message */
|
|
93
|
+
message: z.string(),
|
|
94
|
+
/** Optional stack trace for debugging */
|
|
95
|
+
stack_trace: z.string().optional(),
|
|
96
|
+
/** Tool that failed, if applicable */
|
|
97
|
+
tool_name: z.string().optional(),
|
|
98
|
+
/** When this error occurred */
|
|
99
|
+
timestamp: z.string(), // ISO-8601
|
|
100
|
+
/** Whether this error was resolved */
|
|
101
|
+
resolved: z.boolean().default(false),
|
|
102
|
+
/** Context about what was happening when error occurred */
|
|
103
|
+
context: z.string().optional(),
|
|
104
|
+
});
|
|
105
|
+
export type ErrorEntry = z.infer<typeof ErrorEntrySchema>;
|
|
106
|
+
|
|
67
107
|
/**
|
|
68
108
|
* Decomposition strategies for tracking which approach was used
|
|
69
109
|
*/
|
|
@@ -437,6 +477,241 @@ export class InMemoryFeedbackStorage implements FeedbackStorage {
|
|
|
437
477
|
}
|
|
438
478
|
}
|
|
439
479
|
|
|
480
|
+
// ============================================================================
|
|
481
|
+
// Error Accumulator
|
|
482
|
+
// ============================================================================
|
|
483
|
+
|
|
484
|
+
/**
|
|
485
|
+
* Storage interface for error entries
|
|
486
|
+
*
|
|
487
|
+
* Similar to FeedbackStorage but for tracking errors during execution.
|
|
488
|
+
*/
|
|
489
|
+
export interface ErrorStorage {
|
|
490
|
+
/** Store an error entry */
|
|
491
|
+
store(entry: ErrorEntry): Promise<void>;
|
|
492
|
+
/** Get all errors for a bead */
|
|
493
|
+
getByBead(beadId: string): Promise<ErrorEntry[]>;
|
|
494
|
+
/** Get unresolved errors for a bead */
|
|
495
|
+
getUnresolvedByBead(beadId: string): Promise<ErrorEntry[]>;
|
|
496
|
+
/** Mark an error as resolved */
|
|
497
|
+
markResolved(id: string): Promise<void>;
|
|
498
|
+
/** Get all errors */
|
|
499
|
+
getAll(): Promise<ErrorEntry[]>;
|
|
500
|
+
}
|
|
501
|
+
|
|
502
|
+
/**
|
|
503
|
+
* In-memory error storage
|
|
504
|
+
*
|
|
505
|
+
* Accumulates errors during subtask execution for feeding into retry prompts.
|
|
506
|
+
*/
|
|
507
|
+
export class InMemoryErrorStorage implements ErrorStorage {
|
|
508
|
+
private errors: ErrorEntry[] = [];
|
|
509
|
+
|
|
510
|
+
async store(entry: ErrorEntry): Promise<void> {
|
|
511
|
+
this.errors.push(entry);
|
|
512
|
+
}
|
|
513
|
+
|
|
514
|
+
async getByBead(beadId: string): Promise<ErrorEntry[]> {
|
|
515
|
+
return this.errors.filter((e) => e.bead_id === beadId);
|
|
516
|
+
}
|
|
517
|
+
|
|
518
|
+
async getUnresolvedByBead(beadId: string): Promise<ErrorEntry[]> {
|
|
519
|
+
return this.errors.filter((e) => e.bead_id === beadId && !e.resolved);
|
|
520
|
+
}
|
|
521
|
+
|
|
522
|
+
async markResolved(id: string): Promise<void> {
|
|
523
|
+
const error = this.errors.find((e) => e.id === id);
|
|
524
|
+
if (error) {
|
|
525
|
+
error.resolved = true;
|
|
526
|
+
}
|
|
527
|
+
}
|
|
528
|
+
|
|
529
|
+
async getAll(): Promise<ErrorEntry[]> {
|
|
530
|
+
return [...this.errors];
|
|
531
|
+
}
|
|
532
|
+
}
|
|
533
|
+
|
|
534
|
+
/**
|
|
535
|
+
* Error accumulator for tracking errors during subtask execution
|
|
536
|
+
*
|
|
537
|
+
* Implements patterns from "Patterns for Building AI Agents" p.40:
|
|
538
|
+
* - Examines and corrects errors when something goes wrong
|
|
539
|
+
* - Feeds error context into retry prompts
|
|
540
|
+
* - Tracks error patterns for learning
|
|
541
|
+
*/
|
|
542
|
+
export class ErrorAccumulator {
|
|
543
|
+
private storage: ErrorStorage;
|
|
544
|
+
|
|
545
|
+
constructor(storage?: ErrorStorage) {
|
|
546
|
+
this.storage = storage ?? new InMemoryErrorStorage();
|
|
547
|
+
}
|
|
548
|
+
|
|
549
|
+
/**
|
|
550
|
+
* Record an error during subtask execution
|
|
551
|
+
*
|
|
552
|
+
* @param beadId - Bead ID where error occurred
|
|
553
|
+
* @param errorType - Category of error
|
|
554
|
+
* @param message - Human-readable error message
|
|
555
|
+
* @param options - Additional context (stack trace, tool name, etc.)
|
|
556
|
+
* @returns The created error entry
|
|
557
|
+
*/
|
|
558
|
+
async recordError(
|
|
559
|
+
beadId: string,
|
|
560
|
+
errorType: ErrorType,
|
|
561
|
+
message: string,
|
|
562
|
+
options?: {
|
|
563
|
+
stack_trace?: string;
|
|
564
|
+
tool_name?: string;
|
|
565
|
+
context?: string;
|
|
566
|
+
},
|
|
567
|
+
): Promise<ErrorEntry> {
|
|
568
|
+
const entry: ErrorEntry = {
|
|
569
|
+
id: `${beadId}-${errorType}-${Date.now()}`,
|
|
570
|
+
bead_id: beadId,
|
|
571
|
+
error_type: errorType,
|
|
572
|
+
message,
|
|
573
|
+
stack_trace: options?.stack_trace,
|
|
574
|
+
tool_name: options?.tool_name,
|
|
575
|
+
timestamp: new Date().toISOString(),
|
|
576
|
+
resolved: false,
|
|
577
|
+
context: options?.context,
|
|
578
|
+
};
|
|
579
|
+
|
|
580
|
+
const validated = ErrorEntrySchema.parse(entry);
|
|
581
|
+
await this.storage.store(validated);
|
|
582
|
+
|
|
583
|
+
return validated;
|
|
584
|
+
}
|
|
585
|
+
|
|
586
|
+
/**
|
|
587
|
+
* Get all errors for a bead (resolved and unresolved)
|
|
588
|
+
*/
|
|
589
|
+
async getErrors(beadId: string): Promise<ErrorEntry[]> {
|
|
590
|
+
return this.storage.getByBead(beadId);
|
|
591
|
+
}
|
|
592
|
+
|
|
593
|
+
/**
|
|
594
|
+
* Get only unresolved errors for a bead
|
|
595
|
+
*/
|
|
596
|
+
async getUnresolvedErrors(beadId: string): Promise<ErrorEntry[]> {
|
|
597
|
+
return this.storage.getUnresolvedByBead(beadId);
|
|
598
|
+
}
|
|
599
|
+
|
|
600
|
+
/**
|
|
601
|
+
* Mark an error as resolved
|
|
602
|
+
*/
|
|
603
|
+
async resolveError(errorId: string): Promise<void> {
|
|
604
|
+
await this.storage.markResolved(errorId);
|
|
605
|
+
}
|
|
606
|
+
|
|
607
|
+
/**
|
|
608
|
+
* Format errors as context for retry prompts
|
|
609
|
+
*
|
|
610
|
+
* Groups errors by type and provides structured feedback
|
|
611
|
+
* for the agent to learn from.
|
|
612
|
+
*
|
|
613
|
+
* @param beadId - Bead to get error context for
|
|
614
|
+
* @param includeResolved - Include resolved errors (default: false)
|
|
615
|
+
* @returns Formatted error context string
|
|
616
|
+
*/
|
|
617
|
+
async getErrorContext(
|
|
618
|
+
beadId: string,
|
|
619
|
+
includeResolved = false,
|
|
620
|
+
): Promise<string> {
|
|
621
|
+
const errors = includeResolved
|
|
622
|
+
? await this.getErrors(beadId)
|
|
623
|
+
: await this.getUnresolvedErrors(beadId);
|
|
624
|
+
|
|
625
|
+
if (errors.length === 0) {
|
|
626
|
+
return "";
|
|
627
|
+
}
|
|
628
|
+
|
|
629
|
+
// Group errors by type
|
|
630
|
+
const byType = errors.reduce(
|
|
631
|
+
(acc, err) => {
|
|
632
|
+
const type = err.error_type;
|
|
633
|
+
if (!acc[type]) {
|
|
634
|
+
acc[type] = [];
|
|
635
|
+
}
|
|
636
|
+
acc[type].push(err);
|
|
637
|
+
return acc;
|
|
638
|
+
},
|
|
639
|
+
{} as Record<ErrorType, ErrorEntry[]>,
|
|
640
|
+
);
|
|
641
|
+
|
|
642
|
+
// Format as structured feedback
|
|
643
|
+
const lines = [
|
|
644
|
+
"## Previous Errors",
|
|
645
|
+
"",
|
|
646
|
+
"The following errors were encountered during execution:",
|
|
647
|
+
"",
|
|
648
|
+
];
|
|
649
|
+
|
|
650
|
+
for (const [type, typeErrors] of Object.entries(byType)) {
|
|
651
|
+
lines.push(
|
|
652
|
+
`### ${type} (${typeErrors.length} error${typeErrors.length > 1 ? "s" : ""})`,
|
|
653
|
+
);
|
|
654
|
+
lines.push("");
|
|
655
|
+
|
|
656
|
+
for (const err of typeErrors) {
|
|
657
|
+
lines.push(`- **${err.message}**`);
|
|
658
|
+
if (err.context) {
|
|
659
|
+
lines.push(` - Context: ${err.context}`);
|
|
660
|
+
}
|
|
661
|
+
if (err.tool_name) {
|
|
662
|
+
lines.push(` - Tool: ${err.tool_name}`);
|
|
663
|
+
}
|
|
664
|
+
if (err.stack_trace) {
|
|
665
|
+
lines.push(` - Stack: \`${err.stack_trace.slice(0, 100)}...\``);
|
|
666
|
+
}
|
|
667
|
+
lines.push(
|
|
668
|
+
` - Time: ${new Date(err.timestamp).toLocaleString()}${err.resolved ? " (resolved)" : ""}`,
|
|
669
|
+
);
|
|
670
|
+
lines.push("");
|
|
671
|
+
}
|
|
672
|
+
}
|
|
673
|
+
|
|
674
|
+
lines.push(
|
|
675
|
+
"**Action Required**: Address these errors before proceeding. Consider:",
|
|
676
|
+
);
|
|
677
|
+
lines.push("- What caused each error?");
|
|
678
|
+
lines.push("- How can you prevent similar errors?");
|
|
679
|
+
lines.push("- Are there patterns across error types?");
|
|
680
|
+
lines.push("");
|
|
681
|
+
|
|
682
|
+
return lines.join("\n");
|
|
683
|
+
}
|
|
684
|
+
|
|
685
|
+
/**
|
|
686
|
+
* Get error statistics for outcome tracking
|
|
687
|
+
*
|
|
688
|
+
* @param beadId - Bead to get stats for
|
|
689
|
+
* @returns Error counts and patterns
|
|
690
|
+
*/
|
|
691
|
+
async getErrorStats(beadId: string): Promise<{
|
|
692
|
+
total: number;
|
|
693
|
+
unresolved: number;
|
|
694
|
+
by_type: Record<ErrorType, number>;
|
|
695
|
+
}> {
|
|
696
|
+
const allErrors = await this.getErrors(beadId);
|
|
697
|
+
const unresolved = await this.getUnresolvedErrors(beadId);
|
|
698
|
+
|
|
699
|
+
const byType = allErrors.reduce(
|
|
700
|
+
(acc, err) => {
|
|
701
|
+
acc[err.error_type] = (acc[err.error_type] || 0) + 1;
|
|
702
|
+
return acc;
|
|
703
|
+
},
|
|
704
|
+
{} as Record<ErrorType, number>,
|
|
705
|
+
);
|
|
706
|
+
|
|
707
|
+
return {
|
|
708
|
+
total: allErrors.length,
|
|
709
|
+
unresolved: unresolved.length,
|
|
710
|
+
by_type: byType,
|
|
711
|
+
};
|
|
712
|
+
}
|
|
713
|
+
}
|
|
714
|
+
|
|
440
715
|
// ============================================================================
|
|
441
716
|
// Exports
|
|
442
717
|
// ============================================================================
|
|
@@ -448,4 +723,6 @@ export const learningSchemas = {
|
|
|
448
723
|
OutcomeSignalsSchema,
|
|
449
724
|
ScoredOutcomeSchema,
|
|
450
725
|
DecompositionStrategySchema,
|
|
726
|
+
ErrorTypeSchema,
|
|
727
|
+
ErrorEntrySchema,
|
|
451
728
|
};
|
package/src/swarm.ts
CHANGED
|
@@ -31,9 +31,13 @@ import {
|
|
|
31
31
|
DecompositionStrategySchema,
|
|
32
32
|
scoreImplicitFeedback,
|
|
33
33
|
outcomeToFeedback,
|
|
34
|
+
ErrorAccumulator,
|
|
35
|
+
ErrorEntrySchema,
|
|
34
36
|
type OutcomeSignals,
|
|
35
37
|
type ScoredOutcome,
|
|
36
38
|
type FeedbackEvent,
|
|
39
|
+
type ErrorEntry,
|
|
40
|
+
type ErrorType,
|
|
37
41
|
type DecompositionStrategy as LearningDecompositionStrategy,
|
|
38
42
|
DEFAULT_LEARNING_CONFIG,
|
|
39
43
|
} from "./learning";
|
|
@@ -604,6 +608,8 @@ Begin work on your subtask now.`;
|
|
|
604
608
|
*
|
|
605
609
|
* This is a cleaner version of SUBTASK_PROMPT that's easier to parse.
|
|
606
610
|
* Agents MUST use Agent Mail for communication and beads for tracking.
|
|
611
|
+
*
|
|
612
|
+
* Supports {error_context} placeholder for retry prompts.
|
|
607
613
|
*/
|
|
608
614
|
export const SUBTASK_PROMPT_V2 = `You are a swarm agent working on: **{subtask_title}**
|
|
609
615
|
|
|
@@ -622,6 +628,10 @@ Only modify these files. Need others? Message the coordinator.
|
|
|
622
628
|
## Context
|
|
623
629
|
{shared_context}
|
|
624
630
|
|
|
631
|
+
{compressed_context}
|
|
632
|
+
|
|
633
|
+
{error_context}
|
|
634
|
+
|
|
625
635
|
## MANDATORY: Use These Tools
|
|
626
636
|
|
|
627
637
|
### Agent Mail - communicate with the swarm
|
|
@@ -663,12 +673,20 @@ export function formatSubtaskPromptV2(params: {
|
|
|
663
673
|
subtask_description: string;
|
|
664
674
|
files: string[];
|
|
665
675
|
shared_context?: string;
|
|
676
|
+
compressed_context?: string;
|
|
677
|
+
error_context?: string;
|
|
666
678
|
}): string {
|
|
667
679
|
const fileList =
|
|
668
680
|
params.files.length > 0
|
|
669
681
|
? params.files.map((f) => `- \`${f}\``).join("\n")
|
|
670
682
|
: "(no specific files - use judgment)";
|
|
671
683
|
|
|
684
|
+
const compressedSection = params.compressed_context
|
|
685
|
+
? params.compressed_context
|
|
686
|
+
: "";
|
|
687
|
+
|
|
688
|
+
const errorSection = params.error_context ? params.error_context : "";
|
|
689
|
+
|
|
672
690
|
return SUBTASK_PROMPT_V2.replace(/{bead_id}/g, params.bead_id)
|
|
673
691
|
.replace(/{epic_id}/g, params.epic_id)
|
|
674
692
|
.replace("{subtask_title}", params.subtask_title)
|
|
@@ -677,7 +695,9 @@ export function formatSubtaskPromptV2(params: {
|
|
|
677
695
|
params.subtask_description || "(see title)",
|
|
678
696
|
)
|
|
679
697
|
.replace("{file_list}", fileList)
|
|
680
|
-
.replace("{shared_context}", params.shared_context || "(none)")
|
|
698
|
+
.replace("{shared_context}", params.shared_context || "(none)")
|
|
699
|
+
.replace("{compressed_context}", compressedSection)
|
|
700
|
+
.replace("{error_context}", errorSection);
|
|
681
701
|
}
|
|
682
702
|
|
|
683
703
|
/**
|
|
@@ -1906,6 +1926,9 @@ export const swarm_record_outcome = tool({
|
|
|
1906
1926
|
DEFAULT_LEARNING_CONFIG,
|
|
1907
1927
|
);
|
|
1908
1928
|
|
|
1929
|
+
// Get error patterns from accumulator
|
|
1930
|
+
const errorStats = await globalErrorAccumulator.getErrorStats(args.bead_id);
|
|
1931
|
+
|
|
1909
1932
|
// Generate feedback events for each criterion
|
|
1910
1933
|
const criteriaToScore = args.criteria ?? [
|
|
1911
1934
|
"type_safe",
|
|
@@ -1920,6 +1943,14 @@ export const swarm_record_outcome = tool({
|
|
|
1920
1943
|
event.context =
|
|
1921
1944
|
`${event.context || ""} [strategy: ${args.strategy}]`.trim();
|
|
1922
1945
|
}
|
|
1946
|
+
// Include error patterns in feedback context
|
|
1947
|
+
if (errorStats.total > 0) {
|
|
1948
|
+
const errorSummary = Object.entries(errorStats.by_type)
|
|
1949
|
+
.map(([type, count]) => `${type}:${count}`)
|
|
1950
|
+
.join(", ");
|
|
1951
|
+
event.context =
|
|
1952
|
+
`${event.context || ""} [errors: ${errorSummary}]`.trim();
|
|
1953
|
+
}
|
|
1923
1954
|
return event;
|
|
1924
1955
|
});
|
|
1925
1956
|
|
|
@@ -1935,6 +1966,7 @@ export const swarm_record_outcome = tool({
|
|
|
1935
1966
|
},
|
|
1936
1967
|
},
|
|
1937
1968
|
feedback_events: feedbackEvents,
|
|
1969
|
+
error_patterns: errorStats,
|
|
1938
1970
|
summary: {
|
|
1939
1971
|
feedback_type: scored.type,
|
|
1940
1972
|
duration_seconds: Math.round(args.duration_ms / 1000),
|
|
@@ -1942,6 +1974,8 @@ export const swarm_record_outcome = tool({
|
|
|
1942
1974
|
retry_count: args.retry_count ?? 0,
|
|
1943
1975
|
success: args.success,
|
|
1944
1976
|
strategy: args.strategy,
|
|
1977
|
+
accumulated_errors: errorStats.total,
|
|
1978
|
+
unresolved_errors: errorStats.unresolved,
|
|
1945
1979
|
},
|
|
1946
1980
|
note: "Feedback events should be stored for criterion weight calculation. Use learning.ts functions to apply weights.",
|
|
1947
1981
|
},
|
|
@@ -2222,6 +2256,144 @@ export const swarm_evaluation_prompt = tool({
|
|
|
2222
2256
|
},
|
|
2223
2257
|
});
|
|
2224
2258
|
|
|
2259
|
+
// ============================================================================
|
|
2260
|
+
// Error Accumulator
|
|
2261
|
+
// ============================================================================
|
|
2262
|
+
|
|
2263
|
+
/**
|
|
2264
|
+
* Global error accumulator for tracking errors across subtasks
|
|
2265
|
+
*
|
|
2266
|
+
* This is a session-level singleton that accumulates errors during
|
|
2267
|
+
* swarm execution for feeding into retry prompts.
|
|
2268
|
+
*/
|
|
2269
|
+
const globalErrorAccumulator = new ErrorAccumulator();
|
|
2270
|
+
|
|
2271
|
+
/**
|
|
2272
|
+
* Record an error during subtask execution
|
|
2273
|
+
*
|
|
2274
|
+
* Implements pattern from "Patterns for Building AI Agents" p.40:
|
|
2275
|
+
* "Good agents examine and correct errors when something goes wrong"
|
|
2276
|
+
*
|
|
2277
|
+
* Errors are accumulated and can be fed into retry prompts to help
|
|
2278
|
+
* agents learn from past failures.
|
|
2279
|
+
*/
|
|
2280
|
+
export const swarm_accumulate_error = tool({
|
|
2281
|
+
description:
|
|
2282
|
+
"Record an error during subtask execution. Errors feed into retry prompts.",
|
|
2283
|
+
args: {
|
|
2284
|
+
bead_id: tool.schema.string().describe("Bead ID where error occurred"),
|
|
2285
|
+
error_type: tool.schema
|
|
2286
|
+
.enum(["validation", "timeout", "conflict", "tool_failure", "unknown"])
|
|
2287
|
+
.describe("Category of error"),
|
|
2288
|
+
message: tool.schema.string().describe("Human-readable error message"),
|
|
2289
|
+
stack_trace: tool.schema
|
|
2290
|
+
.string()
|
|
2291
|
+
.optional()
|
|
2292
|
+
.describe("Stack trace for debugging"),
|
|
2293
|
+
tool_name: tool.schema.string().optional().describe("Tool that failed"),
|
|
2294
|
+
context: tool.schema
|
|
2295
|
+
.string()
|
|
2296
|
+
.optional()
|
|
2297
|
+
.describe("What was happening when error occurred"),
|
|
2298
|
+
},
|
|
2299
|
+
async execute(args) {
|
|
2300
|
+
const entry = await globalErrorAccumulator.recordError(
|
|
2301
|
+
args.bead_id,
|
|
2302
|
+
args.error_type as ErrorType,
|
|
2303
|
+
args.message,
|
|
2304
|
+
{
|
|
2305
|
+
stack_trace: args.stack_trace,
|
|
2306
|
+
tool_name: args.tool_name,
|
|
2307
|
+
context: args.context,
|
|
2308
|
+
},
|
|
2309
|
+
);
|
|
2310
|
+
|
|
2311
|
+
return JSON.stringify(
|
|
2312
|
+
{
|
|
2313
|
+
success: true,
|
|
2314
|
+
error_id: entry.id,
|
|
2315
|
+
bead_id: entry.bead_id,
|
|
2316
|
+
error_type: entry.error_type,
|
|
2317
|
+
message: entry.message,
|
|
2318
|
+
timestamp: entry.timestamp,
|
|
2319
|
+
note: "Error recorded for retry context. Use swarm_get_error_context to retrieve accumulated errors.",
|
|
2320
|
+
},
|
|
2321
|
+
null,
|
|
2322
|
+
2,
|
|
2323
|
+
);
|
|
2324
|
+
},
|
|
2325
|
+
});
|
|
2326
|
+
|
|
2327
|
+
/**
|
|
2328
|
+
* Get accumulated errors for a bead to feed into retry prompts
|
|
2329
|
+
*
|
|
2330
|
+
* Returns formatted error context that can be injected into retry prompts
|
|
2331
|
+
* to help agents learn from past failures.
|
|
2332
|
+
*/
|
|
2333
|
+
export const swarm_get_error_context = tool({
|
|
2334
|
+
description:
|
|
2335
|
+
"Get accumulated errors for a bead. Returns formatted context for retry prompts.",
|
|
2336
|
+
args: {
|
|
2337
|
+
bead_id: tool.schema.string().describe("Bead ID to get errors for"),
|
|
2338
|
+
include_resolved: tool.schema
|
|
2339
|
+
.boolean()
|
|
2340
|
+
.optional()
|
|
2341
|
+
.describe("Include resolved errors (default: false)"),
|
|
2342
|
+
},
|
|
2343
|
+
async execute(args) {
|
|
2344
|
+
const errorContext = await globalErrorAccumulator.getErrorContext(
|
|
2345
|
+
args.bead_id,
|
|
2346
|
+
args.include_resolved ?? false,
|
|
2347
|
+
);
|
|
2348
|
+
|
|
2349
|
+
const stats = await globalErrorAccumulator.getErrorStats(args.bead_id);
|
|
2350
|
+
|
|
2351
|
+
return JSON.stringify(
|
|
2352
|
+
{
|
|
2353
|
+
bead_id: args.bead_id,
|
|
2354
|
+
error_context: errorContext,
|
|
2355
|
+
stats: {
|
|
2356
|
+
total_errors: stats.total,
|
|
2357
|
+
unresolved: stats.unresolved,
|
|
2358
|
+
by_type: stats.by_type,
|
|
2359
|
+
},
|
|
2360
|
+
has_errors: errorContext.length > 0,
|
|
2361
|
+
usage:
|
|
2362
|
+
"Inject error_context into retry prompt using {error_context} placeholder",
|
|
2363
|
+
},
|
|
2364
|
+
null,
|
|
2365
|
+
2,
|
|
2366
|
+
);
|
|
2367
|
+
},
|
|
2368
|
+
});
|
|
2369
|
+
|
|
2370
|
+
/**
|
|
2371
|
+
* Mark an error as resolved
|
|
2372
|
+
*
|
|
2373
|
+
* Call this after an agent successfully addresses an error to update
|
|
2374
|
+
* the accumulator state.
|
|
2375
|
+
*/
|
|
2376
|
+
export const swarm_resolve_error = tool({
|
|
2377
|
+
description:
|
|
2378
|
+
"Mark an error as resolved after fixing it. Updates error accumulator state.",
|
|
2379
|
+
args: {
|
|
2380
|
+
error_id: tool.schema.string().describe("Error ID to mark as resolved"),
|
|
2381
|
+
},
|
|
2382
|
+
async execute(args) {
|
|
2383
|
+
await globalErrorAccumulator.resolveError(args.error_id);
|
|
2384
|
+
|
|
2385
|
+
return JSON.stringify(
|
|
2386
|
+
{
|
|
2387
|
+
success: true,
|
|
2388
|
+
error_id: args.error_id,
|
|
2389
|
+
resolved: true,
|
|
2390
|
+
},
|
|
2391
|
+
null,
|
|
2392
|
+
2,
|
|
2393
|
+
);
|
|
2394
|
+
},
|
|
2395
|
+
});
|
|
2396
|
+
|
|
2225
2397
|
/**
|
|
2226
2398
|
* Initialize swarm and check tool availability
|
|
2227
2399
|
*
|
|
@@ -2328,4 +2500,7 @@ export const swarmTools = {
|
|
|
2328
2500
|
swarm_spawn_subtask: swarm_spawn_subtask,
|
|
2329
2501
|
swarm_complete_subtask: swarm_complete_subtask,
|
|
2330
2502
|
swarm_evaluation_prompt: swarm_evaluation_prompt,
|
|
2503
|
+
swarm_accumulate_error: swarm_accumulate_error,
|
|
2504
|
+
swarm_get_error_context: swarm_get_error_context,
|
|
2505
|
+
swarm_resolve_error: swarm_resolve_error,
|
|
2331
2506
|
};
|