opencode-swarm-plugin 0.12.7 → 0.12.9
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 +2 -0
- package/dist/index.js +64 -6
- package/dist/plugin.js +64 -6
- package/package.json +1 -1
- package/src/agent-mail.ts +27 -6
- package/src/learning.ts +1 -0
- package/src/swarm.ts +45 -2
package/.beads/issues.jsonl
CHANGED
|
@@ -305,6 +305,7 @@
|
|
|
305
305
|
{"id":"opencode-swarm-plugin-5ukv1","title":"Bead to start","description":"","status":"closed","priority":2,"issue_type":"task","created_at":"2025-12-10T09:06:07.140527-08:00","updated_at":"2025-12-10T09:06:10.259329-08:00","closed_at":"2025-12-10T09:06:10.259329-08:00"}
|
|
306
306
|
{"id":"opencode-swarm-plugin-5uvt","title":"Limit test bead 3","description":"","status":"closed","priority":2,"issue_type":"task","created_at":"2025-12-08T07:46:49.108567-08:00","updated_at":"2025-12-08T07:46:51.736011-08:00","closed_at":"2025-12-08T07:46:51.736011-08:00"}
|
|
307
307
|
{"id":"opencode-swarm-plugin-5x8v","title":"Bead to start","description":"","status":"closed","priority":2,"issue_type":"task","created_at":"2025-12-08T11:10:53.928154-08:00","updated_at":"2025-12-08T11:10:56.008815-08:00","closed_at":"2025-12-08T11:10:56.008815-08:00"}
|
|
308
|
+
{"id":"opencode-swarm-plugin-5xy17","title":"Swarm should support research task decomposition with pdf-brain","description":"Currently swarm coordinator treats \"research\" tasks as single-agent work. Should decompose research into parallel agents that:\n\n1. Search different sources (pdf-brain, repo-crawl, cass, web)\n2. Focus on different aspects of the question\n3. Synthesize findings into coherent answer\n\nExample decomposition for \"debug levers for agent mail\":\n- Agent 1: Search pdf-brain for \"agent debugging\", \"MCP server configuration\"\n- Agent 2: Crawl the repo README, .env.example, config.py\n- Agent 3: Search cass for past sessions dealing with agent-mail errors\n- Agent 4: Synthesize findings from other agents\n\nStrategy selection should recognize research keywords:\n- research, investigate, explore, find, discover, understand, learn, analyze\n\nTool availability check:\n- If pdf-brain available, include PDF search subtask\n- If repo-crawl available, include repo exploration subtask\n- If cass available, include history search subtask\n\nFiles: src/swarm.ts (add research strategy), src/tool-availability.ts","status":"closed","priority":1,"issue_type":"feature","created_at":"2025-12-10T10:59:41.26917-08:00","updated_at":"2025-12-10T11:01:35.90704-08:00","closed_at":"2025-12-10T11:01:35.90704-08:00"}
|
|
308
309
|
{"id":"opencode-swarm-plugin-5ztv","title":"New feature request","description":"","status":"closed","priority":1,"issue_type":"feature","created_at":"2025-12-08T11:12:40.764593-08:00","updated_at":"2025-12-08T11:12:43.52524-08:00","closed_at":"2025-12-08T11:12:43.52524-08:00"}
|
|
309
310
|
{"id":"opencode-swarm-plugin-61t","title":"Single subtask epic","description":"","status":"closed","priority":1,"issue_type":"epic","created_at":"2025-12-07T19:36:07.443401-08:00","updated_at":"2025-12-07T19:36:09.031886-08:00","closed_at":"2025-12-07T19:36:09.031886-08:00"}
|
|
310
311
|
{"id":"opencode-swarm-plugin-62da","title":"Update test bead","description":"Updated description","status":"closed","priority":2,"issue_type":"task","created_at":"2025-12-08T11:11:38.733772-08:00","updated_at":"2025-12-08T11:11:41.037318-08:00","closed_at":"2025-12-08T11:11:41.037318-08:00"}
|
|
@@ -947,6 +948,7 @@
|
|
|
947
948
|
{"id":"opencode-swarm-plugin-jbdj","title":"Thread link test bead","description":"[thread:test-thread-456]","status":"closed","priority":2,"issue_type":"task","created_at":"2025-12-08T11:10:54.731569-08:00","updated_at":"2025-12-08T11:10:56.43993-08:00","closed_at":"2025-12-08T11:10:56.43993-08:00"}
|
|
948
949
|
{"id":"opencode-swarm-plugin-jc9y","title":"Query test bead","description":"","status":"closed","priority":2,"issue_type":"task","created_at":"2025-12-07T19:39:29.328372-08:00","updated_at":"2025-12-07T19:39:31.358211-08:00","closed_at":"2025-12-07T19:39:31.358211-08:00"}
|
|
949
950
|
{"id":"opencode-swarm-plugin-jdj","title":"Update test bead","description":"Updated description","status":"closed","priority":2,"issue_type":"task","created_at":"2025-12-07T19:39:10.007126-08:00","updated_at":"2025-12-07T19:39:11.999539-08:00","closed_at":"2025-12-07T19:39:11.999539-08:00"}
|
|
951
|
+
{"id":"opencode-swarm-plugin-jf6gz","title":"Add repo-crawl tools to swarm plugin","description":"repo-crawl is essential for research tasks. Should be part of the plugin rather than a separate MCP server.\n\nTools to add:\n- repo_readme(repo) - Get README content\n- repo_structure(repo) - Get repo structure and tech stack\n- repo_tree(repo, path?) - Get directory tree\n- repo_file(repo, path) - Get file content\n- repo_search(repo, query) - Search code in repo\n\nImplementation:\n- Use GitHub API (unauthenticated for public repos, GITHUB_TOKEN for private)\n- Add to tool-availability.ts checks\n- Integrate with research-based strategy\n\nFiles: src/repo-crawl.ts (new), src/index.ts, src/tool-availability.ts","status":"open","priority":2,"issue_type":"feature","created_at":"2025-12-10T11:01:29.213791-08:00","updated_at":"2025-12-10T11:01:29.213791-08:00"}
|
|
950
952
|
{"id":"opencode-swarm-plugin-jg4c","title":"Thread link test bead","description":"[thread:test-thread-123]","status":"closed","priority":2,"issue_type":"task","created_at":"2025-12-08T08:22:18.157665-08:00","updated_at":"2025-12-08T08:22:19.932643-08:00","closed_at":"2025-12-08T08:22:19.932643-08:00"}
|
|
951
953
|
{"id":"opencode-swarm-plugin-jhk","title":"Limit test bead 2","description":"","status":"closed","priority":2,"issue_type":"task","created_at":"2025-12-07T19:39:18.330876-08:00","updated_at":"2025-12-07T19:39:20.45981-08:00","closed_at":"2025-12-07T19:39:20.45981-08:00"}
|
|
952
954
|
{"id":"opencode-swarm-plugin-jiqn","title":"Single subtask epic","description":"","status":"closed","priority":1,"issue_type":"epic","created_at":"2025-12-07T19:57:07.022149-08:00","updated_at":"2025-12-07T19:57:08.738869-08:00","closed_at":"2025-12-07T19:57:08.738869-08:00"}
|
package/dist/index.js
CHANGED
|
@@ -22931,6 +22931,7 @@ async function mcpCallOnce(toolName, args) {
|
|
|
22931
22931
|
}
|
|
22932
22932
|
async function mcpCall(toolName, args) {
|
|
22933
22933
|
let lastError = null;
|
|
22934
|
+
let restartAttempted = false;
|
|
22934
22935
|
for (let attempt = 0;attempt <= RETRY_CONFIG.maxRetries; attempt++) {
|
|
22935
22936
|
if (attempt > 0) {
|
|
22936
22937
|
const delay = calculateBackoffDelay(attempt);
|
|
@@ -22943,13 +22944,28 @@ async function mcpCall(toolName, args) {
|
|
|
22943
22944
|
return result;
|
|
22944
22945
|
} catch (error45) {
|
|
22945
22946
|
lastError = error45 instanceof Error ? error45 : new Error(String(error45));
|
|
22947
|
+
const errorMessage = lastError.message.toLowerCase();
|
|
22946
22948
|
consecutiveFailures++;
|
|
22947
22949
|
const retryable = isRetryableError(error45);
|
|
22948
|
-
|
|
22950
|
+
const isUnexpectedError = errorMessage.includes("unexpected error");
|
|
22951
|
+
if (isUnexpectedError && !restartAttempted && RECOVERY_CONFIG.enabled) {
|
|
22952
|
+
console.warn(`[agent-mail] "${toolName}" got unexpected error, restarting server immediately...`);
|
|
22953
|
+
restartAttempted = true;
|
|
22954
|
+
const restarted = await restartServer();
|
|
22955
|
+
if (restarted) {
|
|
22956
|
+
agentMailAvailable = null;
|
|
22957
|
+
consecutiveFailures = 0;
|
|
22958
|
+
await new Promise((resolve) => setTimeout(resolve, 1000));
|
|
22959
|
+
attempt--;
|
|
22960
|
+
continue;
|
|
22961
|
+
}
|
|
22962
|
+
}
|
|
22963
|
+
if (!isUnexpectedError && consecutiveFailures >= RECOVERY_CONFIG.failureThreshold && RECOVERY_CONFIG.enabled && !restartAttempted) {
|
|
22949
22964
|
console.warn(`[agent-mail] ${consecutiveFailures} consecutive failures, checking server health...`);
|
|
22950
22965
|
const healthy = await isServerFunctional();
|
|
22951
22966
|
if (!healthy) {
|
|
22952
22967
|
console.warn("[agent-mail] Server unhealthy, attempting restart...");
|
|
22968
|
+
restartAttempted = true;
|
|
22953
22969
|
const restarted = await restartServer();
|
|
22954
22970
|
if (restarted) {
|
|
22955
22971
|
agentMailAvailable = null;
|
|
@@ -23758,7 +23774,8 @@ var ErrorEntrySchema = exports_external.object({
|
|
|
23758
23774
|
var DecompositionStrategySchema = exports_external.enum([
|
|
23759
23775
|
"file-based",
|
|
23760
23776
|
"feature-based",
|
|
23761
|
-
"risk-based"
|
|
23777
|
+
"risk-based",
|
|
23778
|
+
"research-based"
|
|
23762
23779
|
]);
|
|
23763
23780
|
var OutcomeSignalsSchema = exports_external.object({
|
|
23764
23781
|
bead_id: exports_external.string(),
|
|
@@ -24122,8 +24139,7 @@ var STRATEGIES = {
|
|
|
24122
24139
|
"hotfix",
|
|
24123
24140
|
"patch",
|
|
24124
24141
|
"audit",
|
|
24125
|
-
"review"
|
|
24126
|
-
"investigate"
|
|
24142
|
+
"review"
|
|
24127
24143
|
],
|
|
24128
24144
|
guidelines: [
|
|
24129
24145
|
"Write tests FIRST to capture expected behavior",
|
|
@@ -24142,6 +24158,47 @@ var STRATEGIES = {
|
|
|
24142
24158
|
"Fix race condition \u2192 [Add test reproducing issue, Implement fix, Add concurrency tests]",
|
|
24143
24159
|
"Security audit \u2192 [Scan for vulnerabilities, Fix critical issues, Document remaining risks]"
|
|
24144
24160
|
]
|
|
24161
|
+
},
|
|
24162
|
+
"research-based": {
|
|
24163
|
+
name: "research-based",
|
|
24164
|
+
description: "Parallel search across multiple sources, then synthesize. Best for investigation, learning, and discovery tasks.",
|
|
24165
|
+
keywords: [
|
|
24166
|
+
"research",
|
|
24167
|
+
"investigate",
|
|
24168
|
+
"explore",
|
|
24169
|
+
"find",
|
|
24170
|
+
"discover",
|
|
24171
|
+
"understand",
|
|
24172
|
+
"learn",
|
|
24173
|
+
"analyze",
|
|
24174
|
+
"what",
|
|
24175
|
+
"how",
|
|
24176
|
+
"why",
|
|
24177
|
+
"compare",
|
|
24178
|
+
"evaluate",
|
|
24179
|
+
"study",
|
|
24180
|
+
"look up",
|
|
24181
|
+
"search"
|
|
24182
|
+
],
|
|
24183
|
+
guidelines: [
|
|
24184
|
+
"Split by information source (PDFs, repos, history, web)",
|
|
24185
|
+
"Each agent searches with different query angles",
|
|
24186
|
+
"Include a synthesis subtask that depends on all search subtasks",
|
|
24187
|
+
"Use pdf-brain for documentation/books if available",
|
|
24188
|
+
"Use repo-crawl for GitHub repos if URL provided",
|
|
24189
|
+
"Use cass for past agent session history",
|
|
24190
|
+
"Assign NO files to research subtasks (read-only)"
|
|
24191
|
+
],
|
|
24192
|
+
antiPatterns: [
|
|
24193
|
+
"Don't have one agent search everything sequentially",
|
|
24194
|
+
"Don't skip synthesis - raw search results need consolidation",
|
|
24195
|
+
"Don't forget to check tool availability before assigning sources"
|
|
24196
|
+
],
|
|
24197
|
+
examples: [
|
|
24198
|
+
"Research auth patterns \u2192 [Search PDFs, Search repos, Search history, Synthesize]",
|
|
24199
|
+
"Investigate error \u2192 [Search cass for similar errors, Search repo for error handling, Synthesize]",
|
|
24200
|
+
"Learn about library \u2192 [Search docs, Search examples, Search issues, Synthesize findings]"
|
|
24201
|
+
]
|
|
24145
24202
|
}
|
|
24146
24203
|
};
|
|
24147
24204
|
function selectStrategy(task) {
|
|
@@ -24149,7 +24206,8 @@ function selectStrategy(task) {
|
|
|
24149
24206
|
const scores = {
|
|
24150
24207
|
"file-based": 0,
|
|
24151
24208
|
"feature-based": 0,
|
|
24152
|
-
"risk-based": 0
|
|
24209
|
+
"risk-based": 0,
|
|
24210
|
+
"research-based": 0
|
|
24153
24211
|
};
|
|
24154
24212
|
for (const [strategyName, definition] of Object.entries(STRATEGIES)) {
|
|
24155
24213
|
const name = strategyName;
|
|
@@ -25096,7 +25154,7 @@ var swarm_record_outcome = tool({
|
|
|
25096
25154
|
success: tool.schema.boolean().describe("Whether the subtask succeeded"),
|
|
25097
25155
|
files_touched: tool.schema.array(tool.schema.string()).optional().describe("Files that were modified"),
|
|
25098
25156
|
criteria: tool.schema.array(tool.schema.string()).optional().describe("Criteria to generate feedback for (default: all default criteria)"),
|
|
25099
|
-
strategy: tool.schema.enum(["file-based", "feature-based", "risk-based"]).optional().describe("Decomposition strategy used for this task")
|
|
25157
|
+
strategy: tool.schema.enum(["file-based", "feature-based", "risk-based", "research-based"]).optional().describe("Decomposition strategy used for this task")
|
|
25100
25158
|
},
|
|
25101
25159
|
async execute(args) {
|
|
25102
25160
|
const signals = {
|
package/dist/plugin.js
CHANGED
|
@@ -22905,6 +22905,7 @@ async function mcpCallOnce(toolName, args) {
|
|
|
22905
22905
|
}
|
|
22906
22906
|
async function mcpCall(toolName, args) {
|
|
22907
22907
|
let lastError = null;
|
|
22908
|
+
let restartAttempted = false;
|
|
22908
22909
|
for (let attempt = 0;attempt <= RETRY_CONFIG.maxRetries; attempt++) {
|
|
22909
22910
|
if (attempt > 0) {
|
|
22910
22911
|
const delay = calculateBackoffDelay(attempt);
|
|
@@ -22917,13 +22918,28 @@ async function mcpCall(toolName, args) {
|
|
|
22917
22918
|
return result;
|
|
22918
22919
|
} catch (error45) {
|
|
22919
22920
|
lastError = error45 instanceof Error ? error45 : new Error(String(error45));
|
|
22921
|
+
const errorMessage = lastError.message.toLowerCase();
|
|
22920
22922
|
consecutiveFailures++;
|
|
22921
22923
|
const retryable = isRetryableError(error45);
|
|
22922
|
-
|
|
22924
|
+
const isUnexpectedError = errorMessage.includes("unexpected error");
|
|
22925
|
+
if (isUnexpectedError && !restartAttempted && RECOVERY_CONFIG.enabled) {
|
|
22926
|
+
console.warn(`[agent-mail] "${toolName}" got unexpected error, restarting server immediately...`);
|
|
22927
|
+
restartAttempted = true;
|
|
22928
|
+
const restarted = await restartServer();
|
|
22929
|
+
if (restarted) {
|
|
22930
|
+
agentMailAvailable = null;
|
|
22931
|
+
consecutiveFailures = 0;
|
|
22932
|
+
await new Promise((resolve) => setTimeout(resolve, 1000));
|
|
22933
|
+
attempt--;
|
|
22934
|
+
continue;
|
|
22935
|
+
}
|
|
22936
|
+
}
|
|
22937
|
+
if (!isUnexpectedError && consecutiveFailures >= RECOVERY_CONFIG.failureThreshold && RECOVERY_CONFIG.enabled && !restartAttempted) {
|
|
22923
22938
|
console.warn(`[agent-mail] ${consecutiveFailures} consecutive failures, checking server health...`);
|
|
22924
22939
|
const healthy = await isServerFunctional();
|
|
22925
22940
|
if (!healthy) {
|
|
22926
22941
|
console.warn("[agent-mail] Server unhealthy, attempting restart...");
|
|
22942
|
+
restartAttempted = true;
|
|
22927
22943
|
const restarted = await restartServer();
|
|
22928
22944
|
if (restarted) {
|
|
22929
22945
|
agentMailAvailable = null;
|
|
@@ -23732,7 +23748,8 @@ var ErrorEntrySchema = exports_external.object({
|
|
|
23732
23748
|
var DecompositionStrategySchema = exports_external.enum([
|
|
23733
23749
|
"file-based",
|
|
23734
23750
|
"feature-based",
|
|
23735
|
-
"risk-based"
|
|
23751
|
+
"risk-based",
|
|
23752
|
+
"research-based"
|
|
23736
23753
|
]);
|
|
23737
23754
|
var OutcomeSignalsSchema = exports_external.object({
|
|
23738
23755
|
bead_id: exports_external.string(),
|
|
@@ -24080,8 +24097,7 @@ var STRATEGIES = {
|
|
|
24080
24097
|
"hotfix",
|
|
24081
24098
|
"patch",
|
|
24082
24099
|
"audit",
|
|
24083
|
-
"review"
|
|
24084
|
-
"investigate"
|
|
24100
|
+
"review"
|
|
24085
24101
|
],
|
|
24086
24102
|
guidelines: [
|
|
24087
24103
|
"Write tests FIRST to capture expected behavior",
|
|
@@ -24100,6 +24116,47 @@ var STRATEGIES = {
|
|
|
24100
24116
|
"Fix race condition \u2192 [Add test reproducing issue, Implement fix, Add concurrency tests]",
|
|
24101
24117
|
"Security audit \u2192 [Scan for vulnerabilities, Fix critical issues, Document remaining risks]"
|
|
24102
24118
|
]
|
|
24119
|
+
},
|
|
24120
|
+
"research-based": {
|
|
24121
|
+
name: "research-based",
|
|
24122
|
+
description: "Parallel search across multiple sources, then synthesize. Best for investigation, learning, and discovery tasks.",
|
|
24123
|
+
keywords: [
|
|
24124
|
+
"research",
|
|
24125
|
+
"investigate",
|
|
24126
|
+
"explore",
|
|
24127
|
+
"find",
|
|
24128
|
+
"discover",
|
|
24129
|
+
"understand",
|
|
24130
|
+
"learn",
|
|
24131
|
+
"analyze",
|
|
24132
|
+
"what",
|
|
24133
|
+
"how",
|
|
24134
|
+
"why",
|
|
24135
|
+
"compare",
|
|
24136
|
+
"evaluate",
|
|
24137
|
+
"study",
|
|
24138
|
+
"look up",
|
|
24139
|
+
"search"
|
|
24140
|
+
],
|
|
24141
|
+
guidelines: [
|
|
24142
|
+
"Split by information source (PDFs, repos, history, web)",
|
|
24143
|
+
"Each agent searches with different query angles",
|
|
24144
|
+
"Include a synthesis subtask that depends on all search subtasks",
|
|
24145
|
+
"Use pdf-brain for documentation/books if available",
|
|
24146
|
+
"Use repo-crawl for GitHub repos if URL provided",
|
|
24147
|
+
"Use cass for past agent session history",
|
|
24148
|
+
"Assign NO files to research subtasks (read-only)"
|
|
24149
|
+
],
|
|
24150
|
+
antiPatterns: [
|
|
24151
|
+
"Don't have one agent search everything sequentially",
|
|
24152
|
+
"Don't skip synthesis - raw search results need consolidation",
|
|
24153
|
+
"Don't forget to check tool availability before assigning sources"
|
|
24154
|
+
],
|
|
24155
|
+
examples: [
|
|
24156
|
+
"Research auth patterns \u2192 [Search PDFs, Search repos, Search history, Synthesize]",
|
|
24157
|
+
"Investigate error \u2192 [Search cass for similar errors, Search repo for error handling, Synthesize]",
|
|
24158
|
+
"Learn about library \u2192 [Search docs, Search examples, Search issues, Synthesize findings]"
|
|
24159
|
+
]
|
|
24103
24160
|
}
|
|
24104
24161
|
};
|
|
24105
24162
|
function selectStrategy(task) {
|
|
@@ -24107,7 +24164,8 @@ function selectStrategy(task) {
|
|
|
24107
24164
|
const scores = {
|
|
24108
24165
|
"file-based": 0,
|
|
24109
24166
|
"feature-based": 0,
|
|
24110
|
-
"risk-based": 0
|
|
24167
|
+
"risk-based": 0,
|
|
24168
|
+
"research-based": 0
|
|
24111
24169
|
};
|
|
24112
24170
|
for (const [strategyName, definition] of Object.entries(STRATEGIES)) {
|
|
24113
24171
|
const name = strategyName;
|
|
@@ -25046,7 +25104,7 @@ var swarm_record_outcome = tool({
|
|
|
25046
25104
|
success: tool.schema.boolean().describe("Whether the subtask succeeded"),
|
|
25047
25105
|
files_touched: tool.schema.array(tool.schema.string()).optional().describe("Files that were modified"),
|
|
25048
25106
|
criteria: tool.schema.array(tool.schema.string()).optional().describe("Criteria to generate feedback for (default: all default criteria)"),
|
|
25049
|
-
strategy: tool.schema.enum(["file-based", "feature-based", "risk-based"]).optional().describe("Decomposition strategy used for this task")
|
|
25107
|
+
strategy: tool.schema.enum(["file-based", "feature-based", "risk-based", "research-based"]).optional().describe("Decomposition strategy used for this task")
|
|
25050
25108
|
},
|
|
25051
25109
|
async execute(args) {
|
|
25052
25110
|
const signals = {
|
package/package.json
CHANGED
package/src/agent-mail.ts
CHANGED
|
@@ -704,6 +704,7 @@ export async function mcpCall<T>(
|
|
|
704
704
|
args: Record<string, unknown>,
|
|
705
705
|
): Promise<T> {
|
|
706
706
|
let lastError: Error | null = null;
|
|
707
|
+
let restartAttempted = false;
|
|
707
708
|
|
|
708
709
|
for (let attempt = 0; attempt <= RETRY_CONFIG.maxRetries; attempt++) {
|
|
709
710
|
// Apply backoff delay (except first attempt)
|
|
@@ -723,17 +724,39 @@ export async function mcpCall<T>(
|
|
|
723
724
|
return result;
|
|
724
725
|
} catch (error) {
|
|
725
726
|
lastError = error instanceof Error ? error : new Error(String(error));
|
|
727
|
+
const errorMessage = lastError.message.toLowerCase();
|
|
726
728
|
|
|
727
729
|
// Track consecutive failures
|
|
728
730
|
consecutiveFailures++;
|
|
729
731
|
|
|
730
|
-
// Check if error is retryable
|
|
732
|
+
// Check if error is retryable
|
|
731
733
|
const retryable = isRetryableError(error);
|
|
732
734
|
|
|
733
|
-
//
|
|
735
|
+
// AGGRESSIVE: If it's an "unexpected error", restart immediately (once per call)
|
|
736
|
+
const isUnexpectedError = errorMessage.includes("unexpected error");
|
|
737
|
+
if (isUnexpectedError && !restartAttempted && RECOVERY_CONFIG.enabled) {
|
|
738
|
+
console.warn(
|
|
739
|
+
`[agent-mail] "${toolName}" got unexpected error, restarting server immediately...`,
|
|
740
|
+
);
|
|
741
|
+
restartAttempted = true;
|
|
742
|
+
const restarted = await restartServer();
|
|
743
|
+
if (restarted) {
|
|
744
|
+
agentMailAvailable = null;
|
|
745
|
+
consecutiveFailures = 0;
|
|
746
|
+
// Small delay to let server stabilize
|
|
747
|
+
await new Promise((resolve) => setTimeout(resolve, 1000));
|
|
748
|
+
// Don't count this attempt - retry immediately
|
|
749
|
+
attempt--;
|
|
750
|
+
continue;
|
|
751
|
+
}
|
|
752
|
+
}
|
|
753
|
+
|
|
754
|
+
// Standard retry logic for other retryable errors
|
|
734
755
|
if (
|
|
756
|
+
!isUnexpectedError &&
|
|
735
757
|
consecutiveFailures >= RECOVERY_CONFIG.failureThreshold &&
|
|
736
|
-
RECOVERY_CONFIG.enabled
|
|
758
|
+
RECOVERY_CONFIG.enabled &&
|
|
759
|
+
!restartAttempted
|
|
737
760
|
) {
|
|
738
761
|
console.warn(
|
|
739
762
|
`[agent-mail] ${consecutiveFailures} consecutive failures, checking server health...`,
|
|
@@ -742,13 +765,11 @@ export async function mcpCall<T>(
|
|
|
742
765
|
const healthy = await isServerFunctional();
|
|
743
766
|
if (!healthy) {
|
|
744
767
|
console.warn("[agent-mail] Server unhealthy, attempting restart...");
|
|
768
|
+
restartAttempted = true;
|
|
745
769
|
const restarted = await restartServer();
|
|
746
770
|
if (restarted) {
|
|
747
|
-
// Reset availability cache since server restarted
|
|
748
771
|
agentMailAvailable = null;
|
|
749
|
-
// Only retry if the error was retryable in the first place
|
|
750
772
|
if (retryable) {
|
|
751
|
-
// Don't count this attempt against retries - try again
|
|
752
773
|
attempt--;
|
|
753
774
|
continue;
|
|
754
775
|
}
|
package/src/learning.ts
CHANGED
package/src/swarm.ts
CHANGED
|
@@ -210,6 +210,7 @@ export type DecompositionStrategy =
|
|
|
210
210
|
| "file-based"
|
|
211
211
|
| "feature-based"
|
|
212
212
|
| "risk-based"
|
|
213
|
+
| "research-based"
|
|
213
214
|
| "auto";
|
|
214
215
|
|
|
215
216
|
/**
|
|
@@ -316,7 +317,6 @@ export const STRATEGIES: Record<
|
|
|
316
317
|
"patch",
|
|
317
318
|
"audit",
|
|
318
319
|
"review",
|
|
319
|
-
"investigate",
|
|
320
320
|
],
|
|
321
321
|
guidelines: [
|
|
322
322
|
"Write tests FIRST to capture expected behavior",
|
|
@@ -336,6 +336,48 @@ export const STRATEGIES: Record<
|
|
|
336
336
|
"Security audit → [Scan for vulnerabilities, Fix critical issues, Document remaining risks]",
|
|
337
337
|
],
|
|
338
338
|
},
|
|
339
|
+
"research-based": {
|
|
340
|
+
name: "research-based",
|
|
341
|
+
description:
|
|
342
|
+
"Parallel search across multiple sources, then synthesize. Best for investigation, learning, and discovery tasks.",
|
|
343
|
+
keywords: [
|
|
344
|
+
"research",
|
|
345
|
+
"investigate",
|
|
346
|
+
"explore",
|
|
347
|
+
"find",
|
|
348
|
+
"discover",
|
|
349
|
+
"understand",
|
|
350
|
+
"learn",
|
|
351
|
+
"analyze",
|
|
352
|
+
"what",
|
|
353
|
+
"how",
|
|
354
|
+
"why",
|
|
355
|
+
"compare",
|
|
356
|
+
"evaluate",
|
|
357
|
+
"study",
|
|
358
|
+
"look up",
|
|
359
|
+
"search",
|
|
360
|
+
],
|
|
361
|
+
guidelines: [
|
|
362
|
+
"Split by information source (PDFs, repos, history, web)",
|
|
363
|
+
"Each agent searches with different query angles",
|
|
364
|
+
"Include a synthesis subtask that depends on all search subtasks",
|
|
365
|
+
"Use pdf-brain for documentation/books if available",
|
|
366
|
+
"Use repo-crawl for GitHub repos if URL provided",
|
|
367
|
+
"Use cass for past agent session history",
|
|
368
|
+
"Assign NO files to research subtasks (read-only)",
|
|
369
|
+
],
|
|
370
|
+
antiPatterns: [
|
|
371
|
+
"Don't have one agent search everything sequentially",
|
|
372
|
+
"Don't skip synthesis - raw search results need consolidation",
|
|
373
|
+
"Don't forget to check tool availability before assigning sources",
|
|
374
|
+
],
|
|
375
|
+
examples: [
|
|
376
|
+
"Research auth patterns → [Search PDFs, Search repos, Search history, Synthesize]",
|
|
377
|
+
"Investigate error → [Search cass for similar errors, Search repo for error handling, Synthesize]",
|
|
378
|
+
"Learn about library → [Search docs, Search examples, Search issues, Synthesize findings]",
|
|
379
|
+
],
|
|
380
|
+
},
|
|
339
381
|
};
|
|
340
382
|
|
|
341
383
|
/**
|
|
@@ -360,6 +402,7 @@ export function selectStrategy(task: string): {
|
|
|
360
402
|
"file-based": 0,
|
|
361
403
|
"feature-based": 0,
|
|
362
404
|
"risk-based": 0,
|
|
405
|
+
"research-based": 0,
|
|
363
406
|
};
|
|
364
407
|
|
|
365
408
|
for (const [strategyName, definition] of Object.entries(STRATEGIES)) {
|
|
@@ -1900,7 +1943,7 @@ export const swarm_record_outcome = tool({
|
|
|
1900
1943
|
"Criteria to generate feedback for (default: all default criteria)",
|
|
1901
1944
|
),
|
|
1902
1945
|
strategy: tool.schema
|
|
1903
|
-
.enum(["file-based", "feature-based", "risk-based"])
|
|
1946
|
+
.enum(["file-based", "feature-based", "risk-based", "research-based"])
|
|
1904
1947
|
.optional()
|
|
1905
1948
|
.describe("Decomposition strategy used for this task"),
|
|
1906
1949
|
},
|