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/index.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
|
}
|
|
@@ -22347,9 +22366,11 @@ function getLimitsForEndpoint(endpoint) {
|
|
|
22347
22366
|
const upperEndpoint = endpoint.toUpperCase();
|
|
22348
22367
|
const perMinuteEnv = process.env[`OPENCODE_RATE_LIMIT_${upperEndpoint}_PER_MIN`];
|
|
22349
22368
|
const perHourEnv = process.env[`OPENCODE_RATE_LIMIT_${upperEndpoint}_PER_HOUR`];
|
|
22369
|
+
const parsedPerMinute = perMinuteEnv ? parseInt(perMinuteEnv, 10) : NaN;
|
|
22370
|
+
const parsedPerHour = perHourEnv ? parseInt(perHourEnv, 10) : NaN;
|
|
22350
22371
|
return {
|
|
22351
|
-
perMinute:
|
|
22352
|
-
perHour:
|
|
22372
|
+
perMinute: Number.isNaN(parsedPerMinute) ? defaults.perMinute : parsedPerMinute,
|
|
22373
|
+
perHour: Number.isNaN(parsedPerHour) ? defaults.perHour : parsedPerHour
|
|
22353
22374
|
};
|
|
22354
22375
|
}
|
|
22355
22376
|
|
|
@@ -22388,6 +22409,7 @@ class RedisRateLimiter {
|
|
|
22388
22409
|
const pipeline = this.redis.pipeline();
|
|
22389
22410
|
pipeline.zremrangebyscore(key, 0, windowStart);
|
|
22390
22411
|
pipeline.zcard(key);
|
|
22412
|
+
pipeline.zrange(key, 0, 0, "WITHSCORES");
|
|
22391
22413
|
const results = await pipeline.exec();
|
|
22392
22414
|
if (!results) {
|
|
22393
22415
|
return { allowed: true, remaining: limit, resetAt: now + windowDuration };
|
|
@@ -22397,7 +22419,7 @@ class RedisRateLimiter {
|
|
|
22397
22419
|
const allowed = count < limit;
|
|
22398
22420
|
let resetAt = now + windowDuration;
|
|
22399
22421
|
if (!allowed) {
|
|
22400
|
-
const oldest =
|
|
22422
|
+
const oldest = results[2]?.[1] || [];
|
|
22401
22423
|
if (oldest.length >= 2) {
|
|
22402
22424
|
const oldestTimestamp = parseInt(oldest[1], 10);
|
|
22403
22425
|
resetAt = oldestTimestamp + windowDuration;
|
|
@@ -22610,8 +22632,8 @@ var RETRY_CONFIG = {
|
|
|
22610
22632
|
jitterPercent: 20
|
|
22611
22633
|
};
|
|
22612
22634
|
var RECOVERY_CONFIG = {
|
|
22613
|
-
failureThreshold:
|
|
22614
|
-
restartCooldownMs:
|
|
22635
|
+
failureThreshold: 1,
|
|
22636
|
+
restartCooldownMs: 1e4,
|
|
22615
22637
|
enabled: process.env.OPENCODE_AGENT_MAIL_AUTO_RESTART !== "false"
|
|
22616
22638
|
};
|
|
22617
22639
|
var SESSION_STATE_DIR = process.env.SWARM_STATE_DIR || join2(tmpdir(), "swarm-sessions");
|
|
@@ -22638,8 +22660,11 @@ function saveSessionState(sessionID, state) {
|
|
|
22638
22660
|
}
|
|
22639
22661
|
const path = getSessionStatePath(sessionID);
|
|
22640
22662
|
writeFileSync(path, JSON.stringify(state, null, 2));
|
|
22663
|
+
return true;
|
|
22641
22664
|
} catch (error45) {
|
|
22642
|
-
console.
|
|
22665
|
+
console.error(`[agent-mail] CRITICAL: Could not save session state: ${error45}`);
|
|
22666
|
+
console.error(`[agent-mail] Session state will not persist across CLI invocations!`);
|
|
22667
|
+
return false;
|
|
22643
22668
|
}
|
|
22644
22669
|
}
|
|
22645
22670
|
var sessionStates = new Map;
|
|
@@ -22919,6 +22944,7 @@ async function mcpCall(toolName, args) {
|
|
|
22919
22944
|
} catch (error45) {
|
|
22920
22945
|
lastError = error45 instanceof Error ? error45 : new Error(String(error45));
|
|
22921
22946
|
consecutiveFailures++;
|
|
22947
|
+
const retryable = isRetryableError(error45);
|
|
22922
22948
|
if (consecutiveFailures >= RECOVERY_CONFIG.failureThreshold && RECOVERY_CONFIG.enabled) {
|
|
22923
22949
|
console.warn(`[agent-mail] ${consecutiveFailures} consecutive failures, checking server health...`);
|
|
22924
22950
|
const healthy = await isServerFunctional();
|
|
@@ -22927,12 +22953,14 @@ async function mcpCall(toolName, args) {
|
|
|
22927
22953
|
const restarted = await restartServer();
|
|
22928
22954
|
if (restarted) {
|
|
22929
22955
|
agentMailAvailable = null;
|
|
22930
|
-
|
|
22931
|
-
|
|
22956
|
+
if (retryable) {
|
|
22957
|
+
attempt--;
|
|
22958
|
+
continue;
|
|
22959
|
+
}
|
|
22932
22960
|
}
|
|
22933
22961
|
}
|
|
22934
22962
|
}
|
|
22935
|
-
if (!
|
|
22963
|
+
if (!retryable) {
|
|
22936
22964
|
console.warn(`[agent-mail] Non-retryable error for ${toolName}: ${lastError.message}`);
|
|
22937
22965
|
throw lastError;
|
|
22938
22966
|
}
|
|
@@ -22979,24 +23007,57 @@ var agentmail_init = tool({
|
|
|
22979
23007
|
fallback: "Swarm will continue without multi-agent coordination. File conflicts possible if multiple agents active."
|
|
22980
23008
|
}, null, 2);
|
|
22981
23009
|
}
|
|
22982
|
-
const
|
|
22983
|
-
|
|
22984
|
-
|
|
22985
|
-
|
|
22986
|
-
|
|
22987
|
-
|
|
22988
|
-
|
|
22989
|
-
|
|
22990
|
-
|
|
22991
|
-
|
|
22992
|
-
|
|
22993
|
-
|
|
22994
|
-
|
|
22995
|
-
|
|
22996
|
-
|
|
22997
|
-
|
|
22998
|
-
|
|
22999
|
-
|
|
23010
|
+
const MAX_INIT_RETRIES = 3;
|
|
23011
|
+
let lastError = null;
|
|
23012
|
+
for (let attempt = 1;attempt <= MAX_INIT_RETRIES; attempt++) {
|
|
23013
|
+
try {
|
|
23014
|
+
const project = await mcpCall("ensure_project", {
|
|
23015
|
+
human_key: args.project_path
|
|
23016
|
+
});
|
|
23017
|
+
const agent = await mcpCall("register_agent", {
|
|
23018
|
+
project_key: args.project_path,
|
|
23019
|
+
program: "opencode",
|
|
23020
|
+
model: "claude-opus-4",
|
|
23021
|
+
name: args.agent_name,
|
|
23022
|
+
task_description: args.task_description || ""
|
|
23023
|
+
});
|
|
23024
|
+
const state = {
|
|
23025
|
+
projectKey: args.project_path,
|
|
23026
|
+
agentName: agent.name,
|
|
23027
|
+
reservations: [],
|
|
23028
|
+
startedAt: new Date().toISOString()
|
|
23029
|
+
};
|
|
23030
|
+
setState(ctx.sessionID, state);
|
|
23031
|
+
if (attempt > 1) {
|
|
23032
|
+
console.warn(`[agent-mail] Init succeeded on attempt ${attempt} after restart`);
|
|
23033
|
+
}
|
|
23034
|
+
return JSON.stringify({ project, agent, available: true }, null, 2);
|
|
23035
|
+
} catch (error45) {
|
|
23036
|
+
lastError = error45 instanceof Error ? error45 : new Error(String(error45));
|
|
23037
|
+
const isUnexpectedError = lastError.message.toLowerCase().includes("unexpected error");
|
|
23038
|
+
console.warn(`[agent-mail] Init attempt ${attempt}/${MAX_INIT_RETRIES} failed: ${lastError.message}`);
|
|
23039
|
+
if (isUnexpectedError && attempt < MAX_INIT_RETRIES) {
|
|
23040
|
+
console.warn("[agent-mail] Detected 'unexpected error', restarting server...");
|
|
23041
|
+
const restarted = await restartServer();
|
|
23042
|
+
if (restarted) {
|
|
23043
|
+
agentMailAvailable = null;
|
|
23044
|
+
consecutiveFailures = 0;
|
|
23045
|
+
await new Promise((resolve) => setTimeout(resolve, 1000));
|
|
23046
|
+
continue;
|
|
23047
|
+
}
|
|
23048
|
+
}
|
|
23049
|
+
if (!isUnexpectedError) {
|
|
23050
|
+
break;
|
|
23051
|
+
}
|
|
23052
|
+
}
|
|
23053
|
+
}
|
|
23054
|
+
return JSON.stringify({
|
|
23055
|
+
error: `Agent Mail init failed after ${MAX_INIT_RETRIES} attempts`,
|
|
23056
|
+
available: false,
|
|
23057
|
+
lastError: lastError?.message,
|
|
23058
|
+
hint: "Manually restart Agent Mail: pkill -f agent-mail && agent-mail serve",
|
|
23059
|
+
fallback: "Swarm will continue without multi-agent coordination."
|
|
23060
|
+
}, null, 2);
|
|
23000
23061
|
}
|
|
23001
23062
|
});
|
|
23002
23063
|
var agentmail_send = tool({
|
|
@@ -23065,12 +23126,12 @@ var agentmail_read_message = tool({
|
|
|
23065
23126
|
const messages = await mcpCall("fetch_inbox", {
|
|
23066
23127
|
project_key: state.projectKey,
|
|
23067
23128
|
agent_name: state.agentName,
|
|
23068
|
-
limit:
|
|
23129
|
+
limit: 50,
|
|
23069
23130
|
include_bodies: true
|
|
23070
23131
|
});
|
|
23071
23132
|
const message = messages.find((m) => m.id === args.message_id);
|
|
23072
23133
|
if (!message) {
|
|
23073
|
-
return `Message ${args.message_id} not found
|
|
23134
|
+
return `Message ${args.message_id} not found in recent 50 messages. Try using agentmail_search to locate it.`;
|
|
23074
23135
|
}
|
|
23075
23136
|
await recordRateLimitedRequest(state.agentName, "read_message");
|
|
23076
23137
|
return JSON.stringify(message, null, 2);
|
|
@@ -23202,7 +23263,11 @@ var agentmail_health = tool({
|
|
|
23202
23263
|
try {
|
|
23203
23264
|
const response = await fetch(`${AGENT_MAIL_URL}/health/liveness`);
|
|
23204
23265
|
if (response.ok) {
|
|
23205
|
-
|
|
23266
|
+
const functional = await isServerFunctional();
|
|
23267
|
+
if (functional) {
|
|
23268
|
+
return "Agent Mail is running and functional";
|
|
23269
|
+
}
|
|
23270
|
+
return "Agent Mail health OK but MCP not responding - consider restart";
|
|
23206
23271
|
}
|
|
23207
23272
|
return `Agent Mail returned status ${response.status}`;
|
|
23208
23273
|
} catch (error45) {
|
|
@@ -23210,6 +23275,41 @@ var agentmail_health = tool({
|
|
|
23210
23275
|
}
|
|
23211
23276
|
}
|
|
23212
23277
|
});
|
|
23278
|
+
var agentmail_restart = tool({
|
|
23279
|
+
description: "Manually restart Agent Mail server (use when getting 'unexpected error')",
|
|
23280
|
+
args: {
|
|
23281
|
+
force: tool.schema.boolean().optional().describe("Force restart even if server appears healthy (default: false)")
|
|
23282
|
+
},
|
|
23283
|
+
async execute(args) {
|
|
23284
|
+
if (!args.force) {
|
|
23285
|
+
const functional = await isServerFunctional();
|
|
23286
|
+
if (functional) {
|
|
23287
|
+
return JSON.stringify({
|
|
23288
|
+
restarted: false,
|
|
23289
|
+
reason: "Server is functional, no restart needed",
|
|
23290
|
+
hint: "Use force=true to restart anyway"
|
|
23291
|
+
}, null, 2);
|
|
23292
|
+
}
|
|
23293
|
+
}
|
|
23294
|
+
console.warn("[agent-mail] Manual restart requested...");
|
|
23295
|
+
const success2 = await restartServer();
|
|
23296
|
+
agentMailAvailable = null;
|
|
23297
|
+
consecutiveFailures = 0;
|
|
23298
|
+
if (success2) {
|
|
23299
|
+
return JSON.stringify({
|
|
23300
|
+
restarted: true,
|
|
23301
|
+
success: true,
|
|
23302
|
+
message: "Agent Mail server restarted successfully"
|
|
23303
|
+
}, null, 2);
|
|
23304
|
+
}
|
|
23305
|
+
return JSON.stringify({
|
|
23306
|
+
restarted: true,
|
|
23307
|
+
success: false,
|
|
23308
|
+
error: "Restart attempted but server did not come back up",
|
|
23309
|
+
hint: "Check server logs or manually start: agent-mail serve"
|
|
23310
|
+
}, null, 2);
|
|
23311
|
+
}
|
|
23312
|
+
});
|
|
23213
23313
|
var agentMailTools = {
|
|
23214
23314
|
agentmail_init,
|
|
23215
23315
|
agentmail_send,
|
|
@@ -23220,7 +23320,8 @@ var agentMailTools = {
|
|
|
23220
23320
|
agentmail_release,
|
|
23221
23321
|
agentmail_ack,
|
|
23222
23322
|
agentmail_search,
|
|
23223
|
-
agentmail_health
|
|
23323
|
+
agentmail_health,
|
|
23324
|
+
agentmail_restart
|
|
23224
23325
|
};
|
|
23225
23326
|
|
|
23226
23327
|
// src/structured.ts
|
|
@@ -23636,6 +23737,24 @@ var CriterionWeightSchema = exports_external.object({
|
|
|
23636
23737
|
last_validated: exports_external.string().optional(),
|
|
23637
23738
|
half_life_days: exports_external.number().positive().default(90)
|
|
23638
23739
|
});
|
|
23740
|
+
var ErrorTypeSchema = exports_external.enum([
|
|
23741
|
+
"validation",
|
|
23742
|
+
"timeout",
|
|
23743
|
+
"conflict",
|
|
23744
|
+
"tool_failure",
|
|
23745
|
+
"unknown"
|
|
23746
|
+
]);
|
|
23747
|
+
var ErrorEntrySchema = exports_external.object({
|
|
23748
|
+
id: exports_external.string(),
|
|
23749
|
+
bead_id: exports_external.string(),
|
|
23750
|
+
error_type: ErrorTypeSchema,
|
|
23751
|
+
message: exports_external.string(),
|
|
23752
|
+
stack_trace: exports_external.string().optional(),
|
|
23753
|
+
tool_name: exports_external.string().optional(),
|
|
23754
|
+
timestamp: exports_external.string(),
|
|
23755
|
+
resolved: exports_external.boolean().default(false),
|
|
23756
|
+
context: exports_external.string().optional()
|
|
23757
|
+
});
|
|
23639
23758
|
var DecompositionStrategySchema = exports_external.enum([
|
|
23640
23759
|
"file-based",
|
|
23641
23760
|
"feature-based",
|
|
@@ -23725,6 +23844,118 @@ class InMemoryFeedbackStorage {
|
|
|
23725
23844
|
}
|
|
23726
23845
|
}
|
|
23727
23846
|
|
|
23847
|
+
class InMemoryErrorStorage {
|
|
23848
|
+
errors = [];
|
|
23849
|
+
async store(entry) {
|
|
23850
|
+
this.errors.push(entry);
|
|
23851
|
+
}
|
|
23852
|
+
async getByBead(beadId) {
|
|
23853
|
+
return this.errors.filter((e) => e.bead_id === beadId);
|
|
23854
|
+
}
|
|
23855
|
+
async getUnresolvedByBead(beadId) {
|
|
23856
|
+
return this.errors.filter((e) => e.bead_id === beadId && !e.resolved);
|
|
23857
|
+
}
|
|
23858
|
+
async markResolved(id) {
|
|
23859
|
+
const error45 = this.errors.find((e) => e.id === id);
|
|
23860
|
+
if (error45) {
|
|
23861
|
+
error45.resolved = true;
|
|
23862
|
+
}
|
|
23863
|
+
}
|
|
23864
|
+
async getAll() {
|
|
23865
|
+
return [...this.errors];
|
|
23866
|
+
}
|
|
23867
|
+
}
|
|
23868
|
+
|
|
23869
|
+
class ErrorAccumulator {
|
|
23870
|
+
storage;
|
|
23871
|
+
constructor(storage) {
|
|
23872
|
+
this.storage = storage ?? new InMemoryErrorStorage;
|
|
23873
|
+
}
|
|
23874
|
+
async recordError(beadId, errorType, message, options) {
|
|
23875
|
+
const entry = {
|
|
23876
|
+
id: `${beadId}-${errorType}-${Date.now()}`,
|
|
23877
|
+
bead_id: beadId,
|
|
23878
|
+
error_type: errorType,
|
|
23879
|
+
message,
|
|
23880
|
+
stack_trace: options?.stack_trace,
|
|
23881
|
+
tool_name: options?.tool_name,
|
|
23882
|
+
timestamp: new Date().toISOString(),
|
|
23883
|
+
resolved: false,
|
|
23884
|
+
context: options?.context
|
|
23885
|
+
};
|
|
23886
|
+
const validated = ErrorEntrySchema.parse(entry);
|
|
23887
|
+
await this.storage.store(validated);
|
|
23888
|
+
return validated;
|
|
23889
|
+
}
|
|
23890
|
+
async getErrors(beadId) {
|
|
23891
|
+
return this.storage.getByBead(beadId);
|
|
23892
|
+
}
|
|
23893
|
+
async getUnresolvedErrors(beadId) {
|
|
23894
|
+
return this.storage.getUnresolvedByBead(beadId);
|
|
23895
|
+
}
|
|
23896
|
+
async resolveError(errorId) {
|
|
23897
|
+
await this.storage.markResolved(errorId);
|
|
23898
|
+
}
|
|
23899
|
+
async getErrorContext(beadId, includeResolved = false) {
|
|
23900
|
+
const errors3 = includeResolved ? await this.getErrors(beadId) : await this.getUnresolvedErrors(beadId);
|
|
23901
|
+
if (errors3.length === 0) {
|
|
23902
|
+
return "";
|
|
23903
|
+
}
|
|
23904
|
+
const byType = errors3.reduce((acc, err) => {
|
|
23905
|
+
const type = err.error_type;
|
|
23906
|
+
if (!acc[type]) {
|
|
23907
|
+
acc[type] = [];
|
|
23908
|
+
}
|
|
23909
|
+
acc[type].push(err);
|
|
23910
|
+
return acc;
|
|
23911
|
+
}, {});
|
|
23912
|
+
const lines = [
|
|
23913
|
+
"## Previous Errors",
|
|
23914
|
+
"",
|
|
23915
|
+
"The following errors were encountered during execution:",
|
|
23916
|
+
""
|
|
23917
|
+
];
|
|
23918
|
+
for (const [type, typeErrors] of Object.entries(byType)) {
|
|
23919
|
+
lines.push(`### ${type} (${typeErrors.length} error${typeErrors.length > 1 ? "s" : ""})`);
|
|
23920
|
+
lines.push("");
|
|
23921
|
+
for (const err of typeErrors) {
|
|
23922
|
+
lines.push(`- **${err.message}**`);
|
|
23923
|
+
if (err.context) {
|
|
23924
|
+
lines.push(` - Context: ${err.context}`);
|
|
23925
|
+
}
|
|
23926
|
+
if (err.tool_name) {
|
|
23927
|
+
lines.push(` - Tool: ${err.tool_name}`);
|
|
23928
|
+
}
|
|
23929
|
+
if (err.stack_trace) {
|
|
23930
|
+
lines.push(` - Stack: \`${err.stack_trace.slice(0, 100)}...\``);
|
|
23931
|
+
}
|
|
23932
|
+
lines.push(` - Time: ${new Date(err.timestamp).toLocaleString()}${err.resolved ? " (resolved)" : ""}`);
|
|
23933
|
+
lines.push("");
|
|
23934
|
+
}
|
|
23935
|
+
}
|
|
23936
|
+
lines.push("**Action Required**: Address these errors before proceeding. Consider:");
|
|
23937
|
+
lines.push("- What caused each error?");
|
|
23938
|
+
lines.push("- How can you prevent similar errors?");
|
|
23939
|
+
lines.push("- Are there patterns across error types?");
|
|
23940
|
+
lines.push("");
|
|
23941
|
+
return lines.join(`
|
|
23942
|
+
`);
|
|
23943
|
+
}
|
|
23944
|
+
async getErrorStats(beadId) {
|
|
23945
|
+
const allErrors = await this.getErrors(beadId);
|
|
23946
|
+
const unresolved = await this.getUnresolvedErrors(beadId);
|
|
23947
|
+
const byType = allErrors.reduce((acc, err) => {
|
|
23948
|
+
acc[err.error_type] = (acc[err.error_type] || 0) + 1;
|
|
23949
|
+
return acc;
|
|
23950
|
+
}, {});
|
|
23951
|
+
return {
|
|
23952
|
+
total: allErrors.length,
|
|
23953
|
+
unresolved: unresolved.length,
|
|
23954
|
+
by_type: byType
|
|
23955
|
+
};
|
|
23956
|
+
}
|
|
23957
|
+
}
|
|
23958
|
+
|
|
23728
23959
|
// src/swarm.ts
|
|
23729
23960
|
var POSITIVE_MARKERS = [
|
|
23730
23961
|
"always",
|
|
@@ -24135,6 +24366,10 @@ Only modify these files. Need others? Message the coordinator.
|
|
|
24135
24366
|
## Context
|
|
24136
24367
|
{shared_context}
|
|
24137
24368
|
|
|
24369
|
+
{compressed_context}
|
|
24370
|
+
|
|
24371
|
+
{error_context}
|
|
24372
|
+
|
|
24138
24373
|
## MANDATORY: Use These Tools
|
|
24139
24374
|
|
|
24140
24375
|
### Agent Mail - communicate with the swarm
|
|
@@ -24168,7 +24403,9 @@ Begin now.`;
|
|
|
24168
24403
|
function formatSubtaskPromptV2(params) {
|
|
24169
24404
|
const fileList = params.files.length > 0 ? params.files.map((f) => `- \`${f}\``).join(`
|
|
24170
24405
|
`) : "(no specific files - use judgment)";
|
|
24171
|
-
|
|
24406
|
+
const compressedSection = params.compressed_context ? params.compressed_context : "";
|
|
24407
|
+
const errorSection = params.error_context ? params.error_context : "";
|
|
24408
|
+
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);
|
|
24172
24409
|
}
|
|
24173
24410
|
var EVALUATION_PROMPT = `Evaluate the work completed for this subtask.
|
|
24174
24411
|
|
|
@@ -24567,6 +24804,13 @@ var swarm_validate_decomposition = tool({
|
|
|
24567
24804
|
for (let i = 0;i < validated.subtasks.length; i++) {
|
|
24568
24805
|
const deps = validated.subtasks[i].dependencies;
|
|
24569
24806
|
for (const dep of deps) {
|
|
24807
|
+
if (dep < 0 || dep >= validated.subtasks.length) {
|
|
24808
|
+
return JSON.stringify({
|
|
24809
|
+
valid: false,
|
|
24810
|
+
error: `Invalid dependency: subtask ${i} depends on ${dep}, but only ${validated.subtasks.length} subtasks exist (indices 0-${validated.subtasks.length - 1})`,
|
|
24811
|
+
hint: "Dependency index is out of bounds"
|
|
24812
|
+
}, null, 2);
|
|
24813
|
+
}
|
|
24570
24814
|
if (dep >= i) {
|
|
24571
24815
|
return JSON.stringify({
|
|
24572
24816
|
valid: false,
|
|
@@ -24867,6 +25111,7 @@ var swarm_record_outcome = tool({
|
|
|
24867
25111
|
};
|
|
24868
25112
|
const validated = OutcomeSignalsSchema.parse(signals);
|
|
24869
25113
|
const scored = scoreImplicitFeedback(validated, DEFAULT_LEARNING_CONFIG);
|
|
25114
|
+
const errorStats = await globalErrorAccumulator.getErrorStats(args.bead_id);
|
|
24870
25115
|
const criteriaToScore = args.criteria ?? [
|
|
24871
25116
|
"type_safe",
|
|
24872
25117
|
"no_bugs",
|
|
@@ -24878,6 +25123,10 @@ var swarm_record_outcome = tool({
|
|
|
24878
25123
|
if (args.strategy) {
|
|
24879
25124
|
event.context = `${event.context || ""} [strategy: ${args.strategy}]`.trim();
|
|
24880
25125
|
}
|
|
25126
|
+
if (errorStats.total > 0) {
|
|
25127
|
+
const errorSummary = Object.entries(errorStats.by_type).map(([type, count]) => `${type}:${count}`).join(", ");
|
|
25128
|
+
event.context = `${event.context || ""} [errors: ${errorSummary}]`.trim();
|
|
25129
|
+
}
|
|
24881
25130
|
return event;
|
|
24882
25131
|
});
|
|
24883
25132
|
return JSON.stringify({
|
|
@@ -24891,13 +25140,16 @@ var swarm_record_outcome = tool({
|
|
|
24891
25140
|
}
|
|
24892
25141
|
},
|
|
24893
25142
|
feedback_events: feedbackEvents,
|
|
25143
|
+
error_patterns: errorStats,
|
|
24894
25144
|
summary: {
|
|
24895
25145
|
feedback_type: scored.type,
|
|
24896
25146
|
duration_seconds: Math.round(args.duration_ms / 1000),
|
|
24897
25147
|
error_count: args.error_count ?? 0,
|
|
24898
25148
|
retry_count: args.retry_count ?? 0,
|
|
24899
25149
|
success: args.success,
|
|
24900
|
-
strategy: args.strategy
|
|
25150
|
+
strategy: args.strategy,
|
|
25151
|
+
accumulated_errors: errorStats.total,
|
|
25152
|
+
unresolved_errors: errorStats.unresolved
|
|
24901
25153
|
},
|
|
24902
25154
|
note: "Feedback events should be stored for criterion weight calculation. Use learning.ts functions to apply weights."
|
|
24903
25155
|
}, null, 2);
|
|
@@ -25067,6 +25319,70 @@ var swarm_evaluation_prompt = tool({
|
|
|
25067
25319
|
}, null, 2);
|
|
25068
25320
|
}
|
|
25069
25321
|
});
|
|
25322
|
+
var globalErrorAccumulator = new ErrorAccumulator;
|
|
25323
|
+
var swarm_accumulate_error = tool({
|
|
25324
|
+
description: "Record an error during subtask execution. Errors feed into retry prompts.",
|
|
25325
|
+
args: {
|
|
25326
|
+
bead_id: tool.schema.string().describe("Bead ID where error occurred"),
|
|
25327
|
+
error_type: tool.schema.enum(["validation", "timeout", "conflict", "tool_failure", "unknown"]).describe("Category of error"),
|
|
25328
|
+
message: tool.schema.string().describe("Human-readable error message"),
|
|
25329
|
+
stack_trace: tool.schema.string().optional().describe("Stack trace for debugging"),
|
|
25330
|
+
tool_name: tool.schema.string().optional().describe("Tool that failed"),
|
|
25331
|
+
context: tool.schema.string().optional().describe("What was happening when error occurred")
|
|
25332
|
+
},
|
|
25333
|
+
async execute(args) {
|
|
25334
|
+
const entry = await globalErrorAccumulator.recordError(args.bead_id, args.error_type, args.message, {
|
|
25335
|
+
stack_trace: args.stack_trace,
|
|
25336
|
+
tool_name: args.tool_name,
|
|
25337
|
+
context: args.context
|
|
25338
|
+
});
|
|
25339
|
+
return JSON.stringify({
|
|
25340
|
+
success: true,
|
|
25341
|
+
error_id: entry.id,
|
|
25342
|
+
bead_id: entry.bead_id,
|
|
25343
|
+
error_type: entry.error_type,
|
|
25344
|
+
message: entry.message,
|
|
25345
|
+
timestamp: entry.timestamp,
|
|
25346
|
+
note: "Error recorded for retry context. Use swarm_get_error_context to retrieve accumulated errors."
|
|
25347
|
+
}, null, 2);
|
|
25348
|
+
}
|
|
25349
|
+
});
|
|
25350
|
+
var swarm_get_error_context = tool({
|
|
25351
|
+
description: "Get accumulated errors for a bead. Returns formatted context for retry prompts.",
|
|
25352
|
+
args: {
|
|
25353
|
+
bead_id: tool.schema.string().describe("Bead ID to get errors for"),
|
|
25354
|
+
include_resolved: tool.schema.boolean().optional().describe("Include resolved errors (default: false)")
|
|
25355
|
+
},
|
|
25356
|
+
async execute(args) {
|
|
25357
|
+
const errorContext = await globalErrorAccumulator.getErrorContext(args.bead_id, args.include_resolved ?? false);
|
|
25358
|
+
const stats = await globalErrorAccumulator.getErrorStats(args.bead_id);
|
|
25359
|
+
return JSON.stringify({
|
|
25360
|
+
bead_id: args.bead_id,
|
|
25361
|
+
error_context: errorContext,
|
|
25362
|
+
stats: {
|
|
25363
|
+
total_errors: stats.total,
|
|
25364
|
+
unresolved: stats.unresolved,
|
|
25365
|
+
by_type: stats.by_type
|
|
25366
|
+
},
|
|
25367
|
+
has_errors: errorContext.length > 0,
|
|
25368
|
+
usage: "Inject error_context into retry prompt using {error_context} placeholder"
|
|
25369
|
+
}, null, 2);
|
|
25370
|
+
}
|
|
25371
|
+
});
|
|
25372
|
+
var swarm_resolve_error = tool({
|
|
25373
|
+
description: "Mark an error as resolved after fixing it. Updates error accumulator state.",
|
|
25374
|
+
args: {
|
|
25375
|
+
error_id: tool.schema.string().describe("Error ID to mark as resolved")
|
|
25376
|
+
},
|
|
25377
|
+
async execute(args) {
|
|
25378
|
+
await globalErrorAccumulator.resolveError(args.error_id);
|
|
25379
|
+
return JSON.stringify({
|
|
25380
|
+
success: true,
|
|
25381
|
+
error_id: args.error_id,
|
|
25382
|
+
resolved: true
|
|
25383
|
+
}, null, 2);
|
|
25384
|
+
}
|
|
25385
|
+
});
|
|
25070
25386
|
var swarm_init = tool({
|
|
25071
25387
|
description: "Initialize swarm session and check tool availability. Call at swarm start to see what features are available.",
|
|
25072
25388
|
args: {
|
|
@@ -25128,7 +25444,10 @@ var swarmTools = {
|
|
|
25128
25444
|
swarm_subtask_prompt,
|
|
25129
25445
|
swarm_spawn_subtask,
|
|
25130
25446
|
swarm_complete_subtask,
|
|
25131
|
-
swarm_evaluation_prompt
|
|
25447
|
+
swarm_evaluation_prompt,
|
|
25448
|
+
swarm_accumulate_error,
|
|
25449
|
+
swarm_get_error_context,
|
|
25450
|
+
swarm_resolve_error
|
|
25132
25451
|
};
|
|
25133
25452
|
// src/anti-patterns.ts
|
|
25134
25453
|
var PatternKindSchema = exports_external.enum(["pattern", "anti_pattern"]);
|
|
@@ -25232,16 +25551,29 @@ async function resolveSemanticMemoryCommand() {
|
|
|
25232
25551
|
return cachedCommand;
|
|
25233
25552
|
}
|
|
25234
25553
|
async function execSemanticMemory(args) {
|
|
25235
|
-
|
|
25236
|
-
|
|
25237
|
-
|
|
25238
|
-
|
|
25239
|
-
|
|
25240
|
-
|
|
25241
|
-
|
|
25242
|
-
|
|
25243
|
-
|
|
25244
|
-
|
|
25554
|
+
try {
|
|
25555
|
+
const cmd = await resolveSemanticMemoryCommand();
|
|
25556
|
+
const fullCmd = [...cmd, ...args];
|
|
25557
|
+
const proc = Bun.spawn(fullCmd, {
|
|
25558
|
+
stdout: "pipe",
|
|
25559
|
+
stderr: "pipe"
|
|
25560
|
+
});
|
|
25561
|
+
try {
|
|
25562
|
+
const stdout = Buffer.from(await new Response(proc.stdout).arrayBuffer());
|
|
25563
|
+
const stderr = Buffer.from(await new Response(proc.stderr).arrayBuffer());
|
|
25564
|
+
const exitCode = await proc.exited;
|
|
25565
|
+
return { exitCode, stdout, stderr };
|
|
25566
|
+
} finally {
|
|
25567
|
+
proc.kill();
|
|
25568
|
+
}
|
|
25569
|
+
} catch (error45) {
|
|
25570
|
+
const errorMessage = error45 instanceof Error ? error45.message : String(error45);
|
|
25571
|
+
return {
|
|
25572
|
+
exitCode: 1,
|
|
25573
|
+
stdout: Buffer.from(""),
|
|
25574
|
+
stderr: Buffer.from(`Error executing semantic-memory: ${errorMessage}`)
|
|
25575
|
+
};
|
|
25576
|
+
}
|
|
25245
25577
|
}
|
|
25246
25578
|
var DEFAULT_STORAGE_CONFIG = {
|
|
25247
25579
|
backend: "semantic-memory",
|
|
@@ -25503,20 +25835,26 @@ async function createStorageWithFallback(config2 = {}) {
|
|
|
25503
25835
|
return new InMemoryStorage;
|
|
25504
25836
|
}
|
|
25505
25837
|
var globalStorage = null;
|
|
25838
|
+
var globalStoragePromise = null;
|
|
25506
25839
|
async function getStorage() {
|
|
25507
|
-
if (!
|
|
25508
|
-
|
|
25840
|
+
if (!globalStoragePromise) {
|
|
25841
|
+
globalStoragePromise = createStorageWithFallback().then((storage) => {
|
|
25842
|
+
globalStorage = storage;
|
|
25843
|
+
return storage;
|
|
25844
|
+
});
|
|
25509
25845
|
}
|
|
25510
|
-
return
|
|
25846
|
+
return globalStoragePromise;
|
|
25511
25847
|
}
|
|
25512
25848
|
function setStorage(storage) {
|
|
25513
25849
|
globalStorage = storage;
|
|
25850
|
+
globalStoragePromise = Promise.resolve(storage);
|
|
25514
25851
|
}
|
|
25515
25852
|
async function resetStorage() {
|
|
25516
25853
|
if (globalStorage) {
|
|
25517
25854
|
await globalStorage.close();
|
|
25518
25855
|
globalStorage = null;
|
|
25519
25856
|
}
|
|
25857
|
+
globalStoragePromise = null;
|
|
25520
25858
|
}
|
|
25521
25859
|
|
|
25522
25860
|
// src/index.ts
|