opencode-swarm-plugin 0.12.4 → 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 +224 -0
- package/README.md +94 -106
- package/bin/swarm.ts +6 -7
- package/dist/index.js +409 -71
- package/dist/plugin.js +376 -58
- package/examples/commands/swarm.md +51 -216
- package/package.json +1 -1
- package/src/agent-mail.ts +183 -37
- package/src/beads.ts +75 -20
- package/src/learning.ts +277 -0
- package/src/rate-limiter.ts +12 -6
- package/src/schemas/bead.ts +4 -4
- package/src/schemas/evaluation.ts +2 -2
- package/src/schemas/task.ts +3 -3
- package/src/storage.ts +37 -15
- package/src/swarm.ts +189 -1
- package/examples/agents/swarm-planner.md +0 -138
package/dist/plugin.js
CHANGED
|
@@ -21560,15 +21560,15 @@ var BeadDependencySchema = exports_external.object({
|
|
|
21560
21560
|
type: exports_external.enum(["blocks", "blocked-by", "related", "discovered-from"])
|
|
21561
21561
|
});
|
|
21562
21562
|
var BeadSchema = exports_external.object({
|
|
21563
|
-
id: exports_external.string().regex(/^[a-z0-9-
|
|
21563
|
+
id: exports_external.string().regex(/^[a-z0-9]+(-[a-z0-9]+)+(\.\d+)?$/, "Invalid bead ID format"),
|
|
21564
21564
|
title: exports_external.string().min(1, "Title required"),
|
|
21565
21565
|
description: exports_external.string().optional().default(""),
|
|
21566
21566
|
status: BeadStatusSchema.default("open"),
|
|
21567
21567
|
priority: exports_external.number().int().min(0).max(3).default(2),
|
|
21568
21568
|
issue_type: BeadTypeSchema.default("task"),
|
|
21569
|
-
created_at: exports_external.string(),
|
|
21570
|
-
updated_at: exports_external.string().optional(),
|
|
21571
|
-
closed_at: exports_external.string().optional(),
|
|
21569
|
+
created_at: exports_external.string().datetime({ offset: true }),
|
|
21570
|
+
updated_at: exports_external.string().datetime({ offset: true }).optional(),
|
|
21571
|
+
closed_at: exports_external.string().datetime({ offset: true }).optional(),
|
|
21572
21572
|
parent_id: exports_external.string().optional(),
|
|
21573
21573
|
dependencies: exports_external.array(BeadDependencySchema).optional().default([]),
|
|
21574
21574
|
metadata: exports_external.record(exports_external.string(), exports_external.unknown()).optional()
|
|
@@ -21641,7 +21641,7 @@ var EvaluationSchema = exports_external.object({
|
|
|
21641
21641
|
criteria: exports_external.record(exports_external.string(), CriterionEvaluationSchema),
|
|
21642
21642
|
overall_feedback: exports_external.string(),
|
|
21643
21643
|
retry_suggestion: exports_external.string().nullable(),
|
|
21644
|
-
timestamp: exports_external.string().optional()
|
|
21644
|
+
timestamp: exports_external.string().datetime({ offset: true }).optional()
|
|
21645
21645
|
});
|
|
21646
21646
|
var DEFAULT_CRITERIA = [
|
|
21647
21647
|
"type_safe",
|
|
@@ -21659,7 +21659,7 @@ var WeightedEvaluationSchema = exports_external.object({
|
|
|
21659
21659
|
criteria: exports_external.record(exports_external.string(), WeightedCriterionEvaluationSchema),
|
|
21660
21660
|
overall_feedback: exports_external.string(),
|
|
21661
21661
|
retry_suggestion: exports_external.string().nullable(),
|
|
21662
|
-
timestamp: exports_external.string().optional(),
|
|
21662
|
+
timestamp: exports_external.string().datetime({ offset: true }).optional(),
|
|
21663
21663
|
average_weight: exports_external.number().min(0).max(1).optional(),
|
|
21664
21664
|
raw_score: exports_external.number().min(0).max(1).optional(),
|
|
21665
21665
|
weighted_score: exports_external.number().min(0).max(1).optional()
|
|
@@ -21732,7 +21732,7 @@ var SwarmSpawnResultSchema = exports_external.object({
|
|
|
21732
21732
|
coordinator_name: exports_external.string(),
|
|
21733
21733
|
thread_id: exports_external.string(),
|
|
21734
21734
|
agents: exports_external.array(SpawnedAgentSchema),
|
|
21735
|
-
started_at: exports_external.string()
|
|
21735
|
+
started_at: exports_external.string().datetime({ offset: true })
|
|
21736
21736
|
});
|
|
21737
21737
|
var AgentProgressSchema = exports_external.object({
|
|
21738
21738
|
bead_id: exports_external.string(),
|
|
@@ -21742,7 +21742,7 @@ var AgentProgressSchema = exports_external.object({
|
|
|
21742
21742
|
message: exports_external.string().optional(),
|
|
21743
21743
|
files_touched: exports_external.array(exports_external.string()).optional(),
|
|
21744
21744
|
blockers: exports_external.array(exports_external.string()).optional(),
|
|
21745
|
-
timestamp: exports_external.string()
|
|
21745
|
+
timestamp: exports_external.string().datetime({ offset: true })
|
|
21746
21746
|
});
|
|
21747
21747
|
var SwarmStatusSchema = exports_external.object({
|
|
21748
21748
|
epic_id: exports_external.string(),
|
|
@@ -21752,7 +21752,7 @@ var SwarmStatusSchema = exports_external.object({
|
|
|
21752
21752
|
failed: exports_external.number().int().min(0),
|
|
21753
21753
|
blocked: exports_external.number().int().min(0),
|
|
21754
21754
|
agents: exports_external.array(SpawnedAgentSchema),
|
|
21755
|
-
last_update: exports_external.string()
|
|
21755
|
+
last_update: exports_external.string().datetime({ offset: true })
|
|
21756
21756
|
});
|
|
21757
21757
|
// src/beads.ts
|
|
21758
21758
|
class BeadError extends Error {
|
|
@@ -21890,18 +21890,32 @@ var beads_create_epic = tool({
|
|
|
21890
21890
|
};
|
|
21891
21891
|
return JSON.stringify(result, null, 2);
|
|
21892
21892
|
} catch (error45) {
|
|
21893
|
-
const
|
|
21894
|
-
|
|
21895
|
-
|
|
21896
|
-
|
|
21897
|
-
|
|
21898
|
-
|
|
21899
|
-
|
|
21900
|
-
|
|
21901
|
-
|
|
21902
|
-
|
|
21903
|
-
|
|
21904
|
-
|
|
21893
|
+
const rollbackCommands = [];
|
|
21894
|
+
for (const bead of created) {
|
|
21895
|
+
try {
|
|
21896
|
+
const closeCmd = [
|
|
21897
|
+
"bd",
|
|
21898
|
+
"close",
|
|
21899
|
+
bead.id,
|
|
21900
|
+
"--reason",
|
|
21901
|
+
"Rollback partial epic",
|
|
21902
|
+
"--json"
|
|
21903
|
+
];
|
|
21904
|
+
await Bun.$`${closeCmd}`.quiet().nothrow();
|
|
21905
|
+
rollbackCommands.push(`bd close ${bead.id} --reason "Rollback partial epic"`);
|
|
21906
|
+
} catch (rollbackError) {
|
|
21907
|
+
console.error(`Failed to rollback bead ${bead.id}:`, rollbackError);
|
|
21908
|
+
}
|
|
21909
|
+
}
|
|
21910
|
+
const errorMsg = error45 instanceof Error ? error45.message : String(error45);
|
|
21911
|
+
const rollbackInfo = rollbackCommands.length > 0 ? `
|
|
21912
|
+
|
|
21913
|
+
Rolled back ${rollbackCommands.length} bead(s):
|
|
21914
|
+
${rollbackCommands.join(`
|
|
21915
|
+
`)}` : `
|
|
21916
|
+
|
|
21917
|
+
No beads to rollback.`;
|
|
21918
|
+
throw new BeadError(`Epic creation failed: ${errorMsg}${rollbackInfo}`, "beads_create_epic", 1);
|
|
21905
21919
|
}
|
|
21906
21920
|
}
|
|
21907
21921
|
});
|
|
@@ -22028,17 +22042,22 @@ var beads_sync = tool({
|
|
|
22028
22042
|
},
|
|
22029
22043
|
async execute(args, ctx) {
|
|
22030
22044
|
const autoPull = args.auto_pull ?? true;
|
|
22045
|
+
const TIMEOUT_MS = 30000;
|
|
22046
|
+
const withTimeout = async (promise2, timeoutMs, operation) => {
|
|
22047
|
+
const timeoutPromise = new Promise((_, reject) => setTimeout(() => reject(new BeadError(`Operation timed out after ${timeoutMs}ms`, operation)), timeoutMs));
|
|
22048
|
+
return Promise.race([promise2, timeoutPromise]);
|
|
22049
|
+
};
|
|
22031
22050
|
if (autoPull) {
|
|
22032
|
-
const pullResult = await Bun.$`git pull --rebase`.quiet().nothrow();
|
|
22051
|
+
const pullResult = await withTimeout(Bun.$`git pull --rebase`.quiet().nothrow(), TIMEOUT_MS, "git pull --rebase");
|
|
22033
22052
|
if (pullResult.exitCode !== 0) {
|
|
22034
22053
|
throw new BeadError(`Failed to pull: ${pullResult.stderr.toString()}`, "git pull --rebase", pullResult.exitCode);
|
|
22035
22054
|
}
|
|
22036
22055
|
}
|
|
22037
|
-
const syncResult = await Bun.$`bd sync`.quiet().nothrow();
|
|
22056
|
+
const syncResult = await withTimeout(Bun.$`bd sync`.quiet().nothrow(), TIMEOUT_MS, "bd sync");
|
|
22038
22057
|
if (syncResult.exitCode !== 0) {
|
|
22039
22058
|
throw new BeadError(`Failed to sync beads: ${syncResult.stderr.toString()}`, "bd sync", syncResult.exitCode);
|
|
22040
22059
|
}
|
|
22041
|
-
const pushResult = await Bun.$`git push`.quiet().nothrow();
|
|
22060
|
+
const pushResult = await withTimeout(Bun.$`git push`.quiet().nothrow(), TIMEOUT_MS, "git push");
|
|
22042
22061
|
if (pushResult.exitCode !== 0) {
|
|
22043
22062
|
throw new BeadError(`Failed to push: ${pushResult.stderr.toString()}`, "git push", pushResult.exitCode);
|
|
22044
22063
|
}
|
|
@@ -22321,9 +22340,11 @@ function getLimitsForEndpoint(endpoint) {
|
|
|
22321
22340
|
const upperEndpoint = endpoint.toUpperCase();
|
|
22322
22341
|
const perMinuteEnv = process.env[`OPENCODE_RATE_LIMIT_${upperEndpoint}_PER_MIN`];
|
|
22323
22342
|
const perHourEnv = process.env[`OPENCODE_RATE_LIMIT_${upperEndpoint}_PER_HOUR`];
|
|
22343
|
+
const parsedPerMinute = perMinuteEnv ? parseInt(perMinuteEnv, 10) : NaN;
|
|
22344
|
+
const parsedPerHour = perHourEnv ? parseInt(perHourEnv, 10) : NaN;
|
|
22324
22345
|
return {
|
|
22325
|
-
perMinute:
|
|
22326
|
-
perHour:
|
|
22346
|
+
perMinute: Number.isNaN(parsedPerMinute) ? defaults.perMinute : parsedPerMinute,
|
|
22347
|
+
perHour: Number.isNaN(parsedPerHour) ? defaults.perHour : parsedPerHour
|
|
22327
22348
|
};
|
|
22328
22349
|
}
|
|
22329
22350
|
|
|
@@ -22362,6 +22383,7 @@ class RedisRateLimiter {
|
|
|
22362
22383
|
const pipeline = this.redis.pipeline();
|
|
22363
22384
|
pipeline.zremrangebyscore(key, 0, windowStart);
|
|
22364
22385
|
pipeline.zcard(key);
|
|
22386
|
+
pipeline.zrange(key, 0, 0, "WITHSCORES");
|
|
22365
22387
|
const results = await pipeline.exec();
|
|
22366
22388
|
if (!results) {
|
|
22367
22389
|
return { allowed: true, remaining: limit, resetAt: now + windowDuration };
|
|
@@ -22371,7 +22393,7 @@ class RedisRateLimiter {
|
|
|
22371
22393
|
const allowed = count < limit;
|
|
22372
22394
|
let resetAt = now + windowDuration;
|
|
22373
22395
|
if (!allowed) {
|
|
22374
|
-
const oldest =
|
|
22396
|
+
const oldest = results[2]?.[1] || [];
|
|
22375
22397
|
if (oldest.length >= 2) {
|
|
22376
22398
|
const oldestTimestamp = parseInt(oldest[1], 10);
|
|
22377
22399
|
resetAt = oldestTimestamp + windowDuration;
|
|
@@ -22584,8 +22606,8 @@ var RETRY_CONFIG = {
|
|
|
22584
22606
|
jitterPercent: 20
|
|
22585
22607
|
};
|
|
22586
22608
|
var RECOVERY_CONFIG = {
|
|
22587
|
-
failureThreshold:
|
|
22588
|
-
restartCooldownMs:
|
|
22609
|
+
failureThreshold: 1,
|
|
22610
|
+
restartCooldownMs: 1e4,
|
|
22589
22611
|
enabled: process.env.OPENCODE_AGENT_MAIL_AUTO_RESTART !== "false"
|
|
22590
22612
|
};
|
|
22591
22613
|
var SESSION_STATE_DIR = process.env.SWARM_STATE_DIR || join2(tmpdir(), "swarm-sessions");
|
|
@@ -22612,8 +22634,11 @@ function saveSessionState(sessionID, state) {
|
|
|
22612
22634
|
}
|
|
22613
22635
|
const path = getSessionStatePath(sessionID);
|
|
22614
22636
|
writeFileSync(path, JSON.stringify(state, null, 2));
|
|
22637
|
+
return true;
|
|
22615
22638
|
} catch (error45) {
|
|
22616
|
-
console.
|
|
22639
|
+
console.error(`[agent-mail] CRITICAL: Could not save session state: ${error45}`);
|
|
22640
|
+
console.error(`[agent-mail] Session state will not persist across CLI invocations!`);
|
|
22641
|
+
return false;
|
|
22617
22642
|
}
|
|
22618
22643
|
}
|
|
22619
22644
|
var sessionStates = new Map;
|
|
@@ -22893,6 +22918,7 @@ async function mcpCall(toolName, args) {
|
|
|
22893
22918
|
} catch (error45) {
|
|
22894
22919
|
lastError = error45 instanceof Error ? error45 : new Error(String(error45));
|
|
22895
22920
|
consecutiveFailures++;
|
|
22921
|
+
const retryable = isRetryableError(error45);
|
|
22896
22922
|
if (consecutiveFailures >= RECOVERY_CONFIG.failureThreshold && RECOVERY_CONFIG.enabled) {
|
|
22897
22923
|
console.warn(`[agent-mail] ${consecutiveFailures} consecutive failures, checking server health...`);
|
|
22898
22924
|
const healthy = await isServerFunctional();
|
|
@@ -22901,12 +22927,14 @@ async function mcpCall(toolName, args) {
|
|
|
22901
22927
|
const restarted = await restartServer();
|
|
22902
22928
|
if (restarted) {
|
|
22903
22929
|
agentMailAvailable = null;
|
|
22904
|
-
|
|
22905
|
-
|
|
22930
|
+
if (retryable) {
|
|
22931
|
+
attempt--;
|
|
22932
|
+
continue;
|
|
22933
|
+
}
|
|
22906
22934
|
}
|
|
22907
22935
|
}
|
|
22908
22936
|
}
|
|
22909
|
-
if (!
|
|
22937
|
+
if (!retryable) {
|
|
22910
22938
|
console.warn(`[agent-mail] Non-retryable error for ${toolName}: ${lastError.message}`);
|
|
22911
22939
|
throw lastError;
|
|
22912
22940
|
}
|
|
@@ -22953,24 +22981,57 @@ var agentmail_init = tool({
|
|
|
22953
22981
|
fallback: "Swarm will continue without multi-agent coordination. File conflicts possible if multiple agents active."
|
|
22954
22982
|
}, null, 2);
|
|
22955
22983
|
}
|
|
22956
|
-
const
|
|
22957
|
-
|
|
22958
|
-
|
|
22959
|
-
|
|
22960
|
-
|
|
22961
|
-
|
|
22962
|
-
|
|
22963
|
-
|
|
22964
|
-
|
|
22965
|
-
|
|
22966
|
-
|
|
22967
|
-
|
|
22968
|
-
|
|
22969
|
-
|
|
22970
|
-
|
|
22971
|
-
|
|
22972
|
-
|
|
22973
|
-
|
|
22984
|
+
const MAX_INIT_RETRIES = 3;
|
|
22985
|
+
let lastError = null;
|
|
22986
|
+
for (let attempt = 1;attempt <= MAX_INIT_RETRIES; attempt++) {
|
|
22987
|
+
try {
|
|
22988
|
+
const project = await mcpCall("ensure_project", {
|
|
22989
|
+
human_key: args.project_path
|
|
22990
|
+
});
|
|
22991
|
+
const agent = await mcpCall("register_agent", {
|
|
22992
|
+
project_key: args.project_path,
|
|
22993
|
+
program: "opencode",
|
|
22994
|
+
model: "claude-opus-4",
|
|
22995
|
+
name: args.agent_name,
|
|
22996
|
+
task_description: args.task_description || ""
|
|
22997
|
+
});
|
|
22998
|
+
const state = {
|
|
22999
|
+
projectKey: args.project_path,
|
|
23000
|
+
agentName: agent.name,
|
|
23001
|
+
reservations: [],
|
|
23002
|
+
startedAt: new Date().toISOString()
|
|
23003
|
+
};
|
|
23004
|
+
setState(ctx.sessionID, state);
|
|
23005
|
+
if (attempt > 1) {
|
|
23006
|
+
console.warn(`[agent-mail] Init succeeded on attempt ${attempt} after restart`);
|
|
23007
|
+
}
|
|
23008
|
+
return JSON.stringify({ project, agent, available: true }, null, 2);
|
|
23009
|
+
} catch (error45) {
|
|
23010
|
+
lastError = error45 instanceof Error ? error45 : new Error(String(error45));
|
|
23011
|
+
const isUnexpectedError = lastError.message.toLowerCase().includes("unexpected error");
|
|
23012
|
+
console.warn(`[agent-mail] Init attempt ${attempt}/${MAX_INIT_RETRIES} failed: ${lastError.message}`);
|
|
23013
|
+
if (isUnexpectedError && attempt < MAX_INIT_RETRIES) {
|
|
23014
|
+
console.warn("[agent-mail] Detected 'unexpected error', restarting server...");
|
|
23015
|
+
const restarted = await restartServer();
|
|
23016
|
+
if (restarted) {
|
|
23017
|
+
agentMailAvailable = null;
|
|
23018
|
+
consecutiveFailures = 0;
|
|
23019
|
+
await new Promise((resolve) => setTimeout(resolve, 1000));
|
|
23020
|
+
continue;
|
|
23021
|
+
}
|
|
23022
|
+
}
|
|
23023
|
+
if (!isUnexpectedError) {
|
|
23024
|
+
break;
|
|
23025
|
+
}
|
|
23026
|
+
}
|
|
23027
|
+
}
|
|
23028
|
+
return JSON.stringify({
|
|
23029
|
+
error: `Agent Mail init failed after ${MAX_INIT_RETRIES} attempts`,
|
|
23030
|
+
available: false,
|
|
23031
|
+
lastError: lastError?.message,
|
|
23032
|
+
hint: "Manually restart Agent Mail: pkill -f agent-mail && agent-mail serve",
|
|
23033
|
+
fallback: "Swarm will continue without multi-agent coordination."
|
|
23034
|
+
}, null, 2);
|
|
22974
23035
|
}
|
|
22975
23036
|
});
|
|
22976
23037
|
var agentmail_send = tool({
|
|
@@ -23039,12 +23100,12 @@ var agentmail_read_message = tool({
|
|
|
23039
23100
|
const messages = await mcpCall("fetch_inbox", {
|
|
23040
23101
|
project_key: state.projectKey,
|
|
23041
23102
|
agent_name: state.agentName,
|
|
23042
|
-
limit:
|
|
23103
|
+
limit: 50,
|
|
23043
23104
|
include_bodies: true
|
|
23044
23105
|
});
|
|
23045
23106
|
const message = messages.find((m) => m.id === args.message_id);
|
|
23046
23107
|
if (!message) {
|
|
23047
|
-
return `Message ${args.message_id} not found
|
|
23108
|
+
return `Message ${args.message_id} not found in recent 50 messages. Try using agentmail_search to locate it.`;
|
|
23048
23109
|
}
|
|
23049
23110
|
await recordRateLimitedRequest(state.agentName, "read_message");
|
|
23050
23111
|
return JSON.stringify(message, null, 2);
|
|
@@ -23176,7 +23237,11 @@ var agentmail_health = tool({
|
|
|
23176
23237
|
try {
|
|
23177
23238
|
const response = await fetch(`${AGENT_MAIL_URL}/health/liveness`);
|
|
23178
23239
|
if (response.ok) {
|
|
23179
|
-
|
|
23240
|
+
const functional = await isServerFunctional();
|
|
23241
|
+
if (functional) {
|
|
23242
|
+
return "Agent Mail is running and functional";
|
|
23243
|
+
}
|
|
23244
|
+
return "Agent Mail health OK but MCP not responding - consider restart";
|
|
23180
23245
|
}
|
|
23181
23246
|
return `Agent Mail returned status ${response.status}`;
|
|
23182
23247
|
} catch (error45) {
|
|
@@ -23184,6 +23249,41 @@ var agentmail_health = tool({
|
|
|
23184
23249
|
}
|
|
23185
23250
|
}
|
|
23186
23251
|
});
|
|
23252
|
+
var agentmail_restart = tool({
|
|
23253
|
+
description: "Manually restart Agent Mail server (use when getting 'unexpected error')",
|
|
23254
|
+
args: {
|
|
23255
|
+
force: tool.schema.boolean().optional().describe("Force restart even if server appears healthy (default: false)")
|
|
23256
|
+
},
|
|
23257
|
+
async execute(args) {
|
|
23258
|
+
if (!args.force) {
|
|
23259
|
+
const functional = await isServerFunctional();
|
|
23260
|
+
if (functional) {
|
|
23261
|
+
return JSON.stringify({
|
|
23262
|
+
restarted: false,
|
|
23263
|
+
reason: "Server is functional, no restart needed",
|
|
23264
|
+
hint: "Use force=true to restart anyway"
|
|
23265
|
+
}, null, 2);
|
|
23266
|
+
}
|
|
23267
|
+
}
|
|
23268
|
+
console.warn("[agent-mail] Manual restart requested...");
|
|
23269
|
+
const success2 = await restartServer();
|
|
23270
|
+
agentMailAvailable = null;
|
|
23271
|
+
consecutiveFailures = 0;
|
|
23272
|
+
if (success2) {
|
|
23273
|
+
return JSON.stringify({
|
|
23274
|
+
restarted: true,
|
|
23275
|
+
success: true,
|
|
23276
|
+
message: "Agent Mail server restarted successfully"
|
|
23277
|
+
}, null, 2);
|
|
23278
|
+
}
|
|
23279
|
+
return JSON.stringify({
|
|
23280
|
+
restarted: true,
|
|
23281
|
+
success: false,
|
|
23282
|
+
error: "Restart attempted but server did not come back up",
|
|
23283
|
+
hint: "Check server logs or manually start: agent-mail serve"
|
|
23284
|
+
}, null, 2);
|
|
23285
|
+
}
|
|
23286
|
+
});
|
|
23187
23287
|
var agentMailTools = {
|
|
23188
23288
|
agentmail_init,
|
|
23189
23289
|
agentmail_send,
|
|
@@ -23194,7 +23294,8 @@ var agentMailTools = {
|
|
|
23194
23294
|
agentmail_release,
|
|
23195
23295
|
agentmail_ack,
|
|
23196
23296
|
agentmail_search,
|
|
23197
|
-
agentmail_health
|
|
23297
|
+
agentmail_health,
|
|
23298
|
+
agentmail_restart
|
|
23198
23299
|
};
|
|
23199
23300
|
|
|
23200
23301
|
// src/structured.ts
|
|
@@ -23610,6 +23711,24 @@ var CriterionWeightSchema = exports_external.object({
|
|
|
23610
23711
|
last_validated: exports_external.string().optional(),
|
|
23611
23712
|
half_life_days: exports_external.number().positive().default(90)
|
|
23612
23713
|
});
|
|
23714
|
+
var ErrorTypeSchema = exports_external.enum([
|
|
23715
|
+
"validation",
|
|
23716
|
+
"timeout",
|
|
23717
|
+
"conflict",
|
|
23718
|
+
"tool_failure",
|
|
23719
|
+
"unknown"
|
|
23720
|
+
]);
|
|
23721
|
+
var ErrorEntrySchema = exports_external.object({
|
|
23722
|
+
id: exports_external.string(),
|
|
23723
|
+
bead_id: exports_external.string(),
|
|
23724
|
+
error_type: ErrorTypeSchema,
|
|
23725
|
+
message: exports_external.string(),
|
|
23726
|
+
stack_trace: exports_external.string().optional(),
|
|
23727
|
+
tool_name: exports_external.string().optional(),
|
|
23728
|
+
timestamp: exports_external.string(),
|
|
23729
|
+
resolved: exports_external.boolean().default(false),
|
|
23730
|
+
context: exports_external.string().optional()
|
|
23731
|
+
});
|
|
23613
23732
|
var DecompositionStrategySchema = exports_external.enum([
|
|
23614
23733
|
"file-based",
|
|
23615
23734
|
"feature-based",
|
|
@@ -23683,6 +23802,117 @@ function outcomeToFeedback(outcome, criterion) {
|
|
|
23683
23802
|
raw_value: outcome.decayed_value
|
|
23684
23803
|
};
|
|
23685
23804
|
}
|
|
23805
|
+
class InMemoryErrorStorage {
|
|
23806
|
+
errors = [];
|
|
23807
|
+
async store(entry) {
|
|
23808
|
+
this.errors.push(entry);
|
|
23809
|
+
}
|
|
23810
|
+
async getByBead(beadId) {
|
|
23811
|
+
return this.errors.filter((e) => e.bead_id === beadId);
|
|
23812
|
+
}
|
|
23813
|
+
async getUnresolvedByBead(beadId) {
|
|
23814
|
+
return this.errors.filter((e) => e.bead_id === beadId && !e.resolved);
|
|
23815
|
+
}
|
|
23816
|
+
async markResolved(id) {
|
|
23817
|
+
const error45 = this.errors.find((e) => e.id === id);
|
|
23818
|
+
if (error45) {
|
|
23819
|
+
error45.resolved = true;
|
|
23820
|
+
}
|
|
23821
|
+
}
|
|
23822
|
+
async getAll() {
|
|
23823
|
+
return [...this.errors];
|
|
23824
|
+
}
|
|
23825
|
+
}
|
|
23826
|
+
|
|
23827
|
+
class ErrorAccumulator {
|
|
23828
|
+
storage;
|
|
23829
|
+
constructor(storage) {
|
|
23830
|
+
this.storage = storage ?? new InMemoryErrorStorage;
|
|
23831
|
+
}
|
|
23832
|
+
async recordError(beadId, errorType, message, options) {
|
|
23833
|
+
const entry = {
|
|
23834
|
+
id: `${beadId}-${errorType}-${Date.now()}`,
|
|
23835
|
+
bead_id: beadId,
|
|
23836
|
+
error_type: errorType,
|
|
23837
|
+
message,
|
|
23838
|
+
stack_trace: options?.stack_trace,
|
|
23839
|
+
tool_name: options?.tool_name,
|
|
23840
|
+
timestamp: new Date().toISOString(),
|
|
23841
|
+
resolved: false,
|
|
23842
|
+
context: options?.context
|
|
23843
|
+
};
|
|
23844
|
+
const validated = ErrorEntrySchema.parse(entry);
|
|
23845
|
+
await this.storage.store(validated);
|
|
23846
|
+
return validated;
|
|
23847
|
+
}
|
|
23848
|
+
async getErrors(beadId) {
|
|
23849
|
+
return this.storage.getByBead(beadId);
|
|
23850
|
+
}
|
|
23851
|
+
async getUnresolvedErrors(beadId) {
|
|
23852
|
+
return this.storage.getUnresolvedByBead(beadId);
|
|
23853
|
+
}
|
|
23854
|
+
async resolveError(errorId) {
|
|
23855
|
+
await this.storage.markResolved(errorId);
|
|
23856
|
+
}
|
|
23857
|
+
async getErrorContext(beadId, includeResolved = false) {
|
|
23858
|
+
const errors3 = includeResolved ? await this.getErrors(beadId) : await this.getUnresolvedErrors(beadId);
|
|
23859
|
+
if (errors3.length === 0) {
|
|
23860
|
+
return "";
|
|
23861
|
+
}
|
|
23862
|
+
const byType = errors3.reduce((acc, err) => {
|
|
23863
|
+
const type = err.error_type;
|
|
23864
|
+
if (!acc[type]) {
|
|
23865
|
+
acc[type] = [];
|
|
23866
|
+
}
|
|
23867
|
+
acc[type].push(err);
|
|
23868
|
+
return acc;
|
|
23869
|
+
}, {});
|
|
23870
|
+
const lines = [
|
|
23871
|
+
"## Previous Errors",
|
|
23872
|
+
"",
|
|
23873
|
+
"The following errors were encountered during execution:",
|
|
23874
|
+
""
|
|
23875
|
+
];
|
|
23876
|
+
for (const [type, typeErrors] of Object.entries(byType)) {
|
|
23877
|
+
lines.push(`### ${type} (${typeErrors.length} error${typeErrors.length > 1 ? "s" : ""})`);
|
|
23878
|
+
lines.push("");
|
|
23879
|
+
for (const err of typeErrors) {
|
|
23880
|
+
lines.push(`- **${err.message}**`);
|
|
23881
|
+
if (err.context) {
|
|
23882
|
+
lines.push(` - Context: ${err.context}`);
|
|
23883
|
+
}
|
|
23884
|
+
if (err.tool_name) {
|
|
23885
|
+
lines.push(` - Tool: ${err.tool_name}`);
|
|
23886
|
+
}
|
|
23887
|
+
if (err.stack_trace) {
|
|
23888
|
+
lines.push(` - Stack: \`${err.stack_trace.slice(0, 100)}...\``);
|
|
23889
|
+
}
|
|
23890
|
+
lines.push(` - Time: ${new Date(err.timestamp).toLocaleString()}${err.resolved ? " (resolved)" : ""}`);
|
|
23891
|
+
lines.push("");
|
|
23892
|
+
}
|
|
23893
|
+
}
|
|
23894
|
+
lines.push("**Action Required**: Address these errors before proceeding. Consider:");
|
|
23895
|
+
lines.push("- What caused each error?");
|
|
23896
|
+
lines.push("- How can you prevent similar errors?");
|
|
23897
|
+
lines.push("- Are there patterns across error types?");
|
|
23898
|
+
lines.push("");
|
|
23899
|
+
return lines.join(`
|
|
23900
|
+
`);
|
|
23901
|
+
}
|
|
23902
|
+
async getErrorStats(beadId) {
|
|
23903
|
+
const allErrors = await this.getErrors(beadId);
|
|
23904
|
+
const unresolved = await this.getUnresolvedErrors(beadId);
|
|
23905
|
+
const byType = allErrors.reduce((acc, err) => {
|
|
23906
|
+
acc[err.error_type] = (acc[err.error_type] || 0) + 1;
|
|
23907
|
+
return acc;
|
|
23908
|
+
}, {});
|
|
23909
|
+
return {
|
|
23910
|
+
total: allErrors.length,
|
|
23911
|
+
unresolved: unresolved.length,
|
|
23912
|
+
by_type: byType
|
|
23913
|
+
};
|
|
23914
|
+
}
|
|
23915
|
+
}
|
|
23686
23916
|
|
|
23687
23917
|
// src/swarm.ts
|
|
23688
23918
|
var POSITIVE_MARKERS = [
|
|
@@ -24094,6 +24324,10 @@ Only modify these files. Need others? Message the coordinator.
|
|
|
24094
24324
|
## Context
|
|
24095
24325
|
{shared_context}
|
|
24096
24326
|
|
|
24327
|
+
{compressed_context}
|
|
24328
|
+
|
|
24329
|
+
{error_context}
|
|
24330
|
+
|
|
24097
24331
|
## MANDATORY: Use These Tools
|
|
24098
24332
|
|
|
24099
24333
|
### Agent Mail - communicate with the swarm
|
|
@@ -24127,7 +24361,9 @@ Begin now.`;
|
|
|
24127
24361
|
function formatSubtaskPromptV2(params) {
|
|
24128
24362
|
const fileList = params.files.length > 0 ? params.files.map((f) => `- \`${f}\``).join(`
|
|
24129
24363
|
`) : "(no specific files - use judgment)";
|
|
24130
|
-
|
|
24364
|
+
const compressedSection = params.compressed_context ? params.compressed_context : "";
|
|
24365
|
+
const errorSection = params.error_context ? params.error_context : "";
|
|
24366
|
+
return SUBTASK_PROMPT_V2.replace(/{bead_id}/g, params.bead_id).replace(/{epic_id}/g, params.epic_id).replace("{subtask_title}", params.subtask_title).replace("{subtask_description}", params.subtask_description || "(see title)").replace("{file_list}", fileList).replace("{shared_context}", params.shared_context || "(none)").replace("{compressed_context}", compressedSection).replace("{error_context}", errorSection);
|
|
24131
24367
|
}
|
|
24132
24368
|
var EVALUATION_PROMPT = `Evaluate the work completed for this subtask.
|
|
24133
24369
|
|
|
@@ -24518,6 +24754,13 @@ var swarm_validate_decomposition = tool({
|
|
|
24518
24754
|
for (let i = 0;i < validated.subtasks.length; i++) {
|
|
24519
24755
|
const deps = validated.subtasks[i].dependencies;
|
|
24520
24756
|
for (const dep of deps) {
|
|
24757
|
+
if (dep < 0 || dep >= validated.subtasks.length) {
|
|
24758
|
+
return JSON.stringify({
|
|
24759
|
+
valid: false,
|
|
24760
|
+
error: `Invalid dependency: subtask ${i} depends on ${dep}, but only ${validated.subtasks.length} subtasks exist (indices 0-${validated.subtasks.length - 1})`,
|
|
24761
|
+
hint: "Dependency index is out of bounds"
|
|
24762
|
+
}, null, 2);
|
|
24763
|
+
}
|
|
24521
24764
|
if (dep >= i) {
|
|
24522
24765
|
return JSON.stringify({
|
|
24523
24766
|
valid: false,
|
|
@@ -24818,6 +25061,7 @@ var swarm_record_outcome = tool({
|
|
|
24818
25061
|
};
|
|
24819
25062
|
const validated = OutcomeSignalsSchema.parse(signals);
|
|
24820
25063
|
const scored = scoreImplicitFeedback(validated, DEFAULT_LEARNING_CONFIG);
|
|
25064
|
+
const errorStats = await globalErrorAccumulator.getErrorStats(args.bead_id);
|
|
24821
25065
|
const criteriaToScore = args.criteria ?? [
|
|
24822
25066
|
"type_safe",
|
|
24823
25067
|
"no_bugs",
|
|
@@ -24829,6 +25073,10 @@ var swarm_record_outcome = tool({
|
|
|
24829
25073
|
if (args.strategy) {
|
|
24830
25074
|
event.context = `${event.context || ""} [strategy: ${args.strategy}]`.trim();
|
|
24831
25075
|
}
|
|
25076
|
+
if (errorStats.total > 0) {
|
|
25077
|
+
const errorSummary = Object.entries(errorStats.by_type).map(([type, count]) => `${type}:${count}`).join(", ");
|
|
25078
|
+
event.context = `${event.context || ""} [errors: ${errorSummary}]`.trim();
|
|
25079
|
+
}
|
|
24832
25080
|
return event;
|
|
24833
25081
|
});
|
|
24834
25082
|
return JSON.stringify({
|
|
@@ -24842,13 +25090,16 @@ var swarm_record_outcome = tool({
|
|
|
24842
25090
|
}
|
|
24843
25091
|
},
|
|
24844
25092
|
feedback_events: feedbackEvents,
|
|
25093
|
+
error_patterns: errorStats,
|
|
24845
25094
|
summary: {
|
|
24846
25095
|
feedback_type: scored.type,
|
|
24847
25096
|
duration_seconds: Math.round(args.duration_ms / 1000),
|
|
24848
25097
|
error_count: args.error_count ?? 0,
|
|
24849
25098
|
retry_count: args.retry_count ?? 0,
|
|
24850
25099
|
success: args.success,
|
|
24851
|
-
strategy: args.strategy
|
|
25100
|
+
strategy: args.strategy,
|
|
25101
|
+
accumulated_errors: errorStats.total,
|
|
25102
|
+
unresolved_errors: errorStats.unresolved
|
|
24852
25103
|
},
|
|
24853
25104
|
note: "Feedback events should be stored for criterion weight calculation. Use learning.ts functions to apply weights."
|
|
24854
25105
|
}, null, 2);
|
|
@@ -25018,6 +25269,70 @@ var swarm_evaluation_prompt = tool({
|
|
|
25018
25269
|
}, null, 2);
|
|
25019
25270
|
}
|
|
25020
25271
|
});
|
|
25272
|
+
var globalErrorAccumulator = new ErrorAccumulator;
|
|
25273
|
+
var swarm_accumulate_error = tool({
|
|
25274
|
+
description: "Record an error during subtask execution. Errors feed into retry prompts.",
|
|
25275
|
+
args: {
|
|
25276
|
+
bead_id: tool.schema.string().describe("Bead ID where error occurred"),
|
|
25277
|
+
error_type: tool.schema.enum(["validation", "timeout", "conflict", "tool_failure", "unknown"]).describe("Category of error"),
|
|
25278
|
+
message: tool.schema.string().describe("Human-readable error message"),
|
|
25279
|
+
stack_trace: tool.schema.string().optional().describe("Stack trace for debugging"),
|
|
25280
|
+
tool_name: tool.schema.string().optional().describe("Tool that failed"),
|
|
25281
|
+
context: tool.schema.string().optional().describe("What was happening when error occurred")
|
|
25282
|
+
},
|
|
25283
|
+
async execute(args) {
|
|
25284
|
+
const entry = await globalErrorAccumulator.recordError(args.bead_id, args.error_type, args.message, {
|
|
25285
|
+
stack_trace: args.stack_trace,
|
|
25286
|
+
tool_name: args.tool_name,
|
|
25287
|
+
context: args.context
|
|
25288
|
+
});
|
|
25289
|
+
return JSON.stringify({
|
|
25290
|
+
success: true,
|
|
25291
|
+
error_id: entry.id,
|
|
25292
|
+
bead_id: entry.bead_id,
|
|
25293
|
+
error_type: entry.error_type,
|
|
25294
|
+
message: entry.message,
|
|
25295
|
+
timestamp: entry.timestamp,
|
|
25296
|
+
note: "Error recorded for retry context. Use swarm_get_error_context to retrieve accumulated errors."
|
|
25297
|
+
}, null, 2);
|
|
25298
|
+
}
|
|
25299
|
+
});
|
|
25300
|
+
var swarm_get_error_context = tool({
|
|
25301
|
+
description: "Get accumulated errors for a bead. Returns formatted context for retry prompts.",
|
|
25302
|
+
args: {
|
|
25303
|
+
bead_id: tool.schema.string().describe("Bead ID to get errors for"),
|
|
25304
|
+
include_resolved: tool.schema.boolean().optional().describe("Include resolved errors (default: false)")
|
|
25305
|
+
},
|
|
25306
|
+
async execute(args) {
|
|
25307
|
+
const errorContext = await globalErrorAccumulator.getErrorContext(args.bead_id, args.include_resolved ?? false);
|
|
25308
|
+
const stats = await globalErrorAccumulator.getErrorStats(args.bead_id);
|
|
25309
|
+
return JSON.stringify({
|
|
25310
|
+
bead_id: args.bead_id,
|
|
25311
|
+
error_context: errorContext,
|
|
25312
|
+
stats: {
|
|
25313
|
+
total_errors: stats.total,
|
|
25314
|
+
unresolved: stats.unresolved,
|
|
25315
|
+
by_type: stats.by_type
|
|
25316
|
+
},
|
|
25317
|
+
has_errors: errorContext.length > 0,
|
|
25318
|
+
usage: "Inject error_context into retry prompt using {error_context} placeholder"
|
|
25319
|
+
}, null, 2);
|
|
25320
|
+
}
|
|
25321
|
+
});
|
|
25322
|
+
var swarm_resolve_error = tool({
|
|
25323
|
+
description: "Mark an error as resolved after fixing it. Updates error accumulator state.",
|
|
25324
|
+
args: {
|
|
25325
|
+
error_id: tool.schema.string().describe("Error ID to mark as resolved")
|
|
25326
|
+
},
|
|
25327
|
+
async execute(args) {
|
|
25328
|
+
await globalErrorAccumulator.resolveError(args.error_id);
|
|
25329
|
+
return JSON.stringify({
|
|
25330
|
+
success: true,
|
|
25331
|
+
error_id: args.error_id,
|
|
25332
|
+
resolved: true
|
|
25333
|
+
}, null, 2);
|
|
25334
|
+
}
|
|
25335
|
+
});
|
|
25021
25336
|
var swarm_init = tool({
|
|
25022
25337
|
description: "Initialize swarm session and check tool availability. Call at swarm start to see what features are available.",
|
|
25023
25338
|
args: {
|
|
@@ -25079,7 +25394,10 @@ var swarmTools = {
|
|
|
25079
25394
|
swarm_subtask_prompt,
|
|
25080
25395
|
swarm_spawn_subtask,
|
|
25081
25396
|
swarm_complete_subtask,
|
|
25082
|
-
swarm_evaluation_prompt
|
|
25397
|
+
swarm_evaluation_prompt,
|
|
25398
|
+
swarm_accumulate_error,
|
|
25399
|
+
swarm_get_error_context,
|
|
25400
|
+
swarm_resolve_error
|
|
25083
25401
|
};
|
|
25084
25402
|
// src/anti-patterns.ts
|
|
25085
25403
|
var PatternKindSchema = exports_external.enum(["pattern", "anti_pattern"]);
|