opencode-swarm 5.0.8 → 5.0.10

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.
@@ -9,3 +9,13 @@ export type AgentName = (typeof ALL_AGENT_NAMES)[number];
9
9
  export declare const DEFAULT_MODELS: Record<string, string>;
10
10
  export declare function isQAAgent(name: string): name is QAAgentName;
11
11
  export declare function isSubagent(name: string): boolean;
12
+ import type { ScoringConfig } from './schema';
13
+ export declare const DEFAULT_SCORING_CONFIG: ScoringConfig;
14
+ /**
15
+ * Resolve scoring configuration by deep-merging user config with defaults.
16
+ * Missing scoring block → use defaults; partial weights → merge with defaults.
17
+ *
18
+ * @param userConfig - Optional user-provided scoring configuration
19
+ * @returns The effective scoring configuration with all defaults applied
20
+ */
21
+ export declare function resolveScoringConfig(userConfig?: ScoringConfig): ScoringConfig;
@@ -22,12 +22,93 @@ export declare const HooksConfigSchema: z.ZodObject<{
22
22
  agent_awareness_max_chars: z.ZodDefault<z.ZodNumber>;
23
23
  }, z.core.$strip>;
24
24
  export type HooksConfig = z.infer<typeof HooksConfigSchema>;
25
+ export declare const ScoringWeightsSchema: z.ZodObject<{
26
+ phase: z.ZodDefault<z.ZodNumber>;
27
+ current_task: z.ZodDefault<z.ZodNumber>;
28
+ blocked_task: z.ZodDefault<z.ZodNumber>;
29
+ recent_failure: z.ZodDefault<z.ZodNumber>;
30
+ recent_success: z.ZodDefault<z.ZodNumber>;
31
+ evidence_presence: z.ZodDefault<z.ZodNumber>;
32
+ decision_recency: z.ZodDefault<z.ZodNumber>;
33
+ dependency_proximity: z.ZodDefault<z.ZodNumber>;
34
+ }, z.core.$strip>;
35
+ export type ScoringWeights = z.infer<typeof ScoringWeightsSchema>;
36
+ export declare const DecisionDecaySchema: z.ZodObject<{
37
+ mode: z.ZodDefault<z.ZodEnum<{
38
+ linear: "linear";
39
+ exponential: "exponential";
40
+ }>>;
41
+ half_life_hours: z.ZodDefault<z.ZodNumber>;
42
+ }, z.core.$strip>;
43
+ export type DecisionDecay = z.infer<typeof DecisionDecaySchema>;
44
+ export declare const TokenRatiosSchema: z.ZodObject<{
45
+ prose: z.ZodDefault<z.ZodNumber>;
46
+ code: z.ZodDefault<z.ZodNumber>;
47
+ markdown: z.ZodDefault<z.ZodNumber>;
48
+ json: z.ZodDefault<z.ZodNumber>;
49
+ }, z.core.$strip>;
50
+ export type TokenRatios = z.infer<typeof TokenRatiosSchema>;
51
+ export declare const ScoringConfigSchema: z.ZodObject<{
52
+ enabled: z.ZodDefault<z.ZodBoolean>;
53
+ max_candidates: z.ZodDefault<z.ZodNumber>;
54
+ weights: z.ZodOptional<z.ZodObject<{
55
+ phase: z.ZodDefault<z.ZodNumber>;
56
+ current_task: z.ZodDefault<z.ZodNumber>;
57
+ blocked_task: z.ZodDefault<z.ZodNumber>;
58
+ recent_failure: z.ZodDefault<z.ZodNumber>;
59
+ recent_success: z.ZodDefault<z.ZodNumber>;
60
+ evidence_presence: z.ZodDefault<z.ZodNumber>;
61
+ decision_recency: z.ZodDefault<z.ZodNumber>;
62
+ dependency_proximity: z.ZodDefault<z.ZodNumber>;
63
+ }, z.core.$strip>>;
64
+ decision_decay: z.ZodOptional<z.ZodObject<{
65
+ mode: z.ZodDefault<z.ZodEnum<{
66
+ linear: "linear";
67
+ exponential: "exponential";
68
+ }>>;
69
+ half_life_hours: z.ZodDefault<z.ZodNumber>;
70
+ }, z.core.$strip>>;
71
+ token_ratios: z.ZodOptional<z.ZodObject<{
72
+ prose: z.ZodDefault<z.ZodNumber>;
73
+ code: z.ZodDefault<z.ZodNumber>;
74
+ markdown: z.ZodDefault<z.ZodNumber>;
75
+ json: z.ZodDefault<z.ZodNumber>;
76
+ }, z.core.$strip>>;
77
+ }, z.core.$strip>;
78
+ export type ScoringConfig = z.infer<typeof ScoringConfigSchema>;
25
79
  export declare const ContextBudgetConfigSchema: z.ZodObject<{
26
80
  enabled: z.ZodDefault<z.ZodBoolean>;
27
81
  warn_threshold: z.ZodDefault<z.ZodNumber>;
28
82
  critical_threshold: z.ZodDefault<z.ZodNumber>;
29
83
  model_limits: z.ZodDefault<z.ZodRecord<z.ZodString, z.ZodNumber>>;
30
84
  max_injection_tokens: z.ZodDefault<z.ZodNumber>;
85
+ scoring: z.ZodOptional<z.ZodObject<{
86
+ enabled: z.ZodDefault<z.ZodBoolean>;
87
+ max_candidates: z.ZodDefault<z.ZodNumber>;
88
+ weights: z.ZodOptional<z.ZodObject<{
89
+ phase: z.ZodDefault<z.ZodNumber>;
90
+ current_task: z.ZodDefault<z.ZodNumber>;
91
+ blocked_task: z.ZodDefault<z.ZodNumber>;
92
+ recent_failure: z.ZodDefault<z.ZodNumber>;
93
+ recent_success: z.ZodDefault<z.ZodNumber>;
94
+ evidence_presence: z.ZodDefault<z.ZodNumber>;
95
+ decision_recency: z.ZodDefault<z.ZodNumber>;
96
+ dependency_proximity: z.ZodDefault<z.ZodNumber>;
97
+ }, z.core.$strip>>;
98
+ decision_decay: z.ZodOptional<z.ZodObject<{
99
+ mode: z.ZodDefault<z.ZodEnum<{
100
+ linear: "linear";
101
+ exponential: "exponential";
102
+ }>>;
103
+ half_life_hours: z.ZodDefault<z.ZodNumber>;
104
+ }, z.core.$strip>>;
105
+ token_ratios: z.ZodOptional<z.ZodObject<{
106
+ prose: z.ZodDefault<z.ZodNumber>;
107
+ code: z.ZodDefault<z.ZodNumber>;
108
+ markdown: z.ZodDefault<z.ZodNumber>;
109
+ json: z.ZodDefault<z.ZodNumber>;
110
+ }, z.core.$strip>>;
111
+ }, z.core.$strip>>;
31
112
  }, z.core.$strip>;
32
113
  export type ContextBudgetConfig = z.infer<typeof ContextBudgetConfigSchema>;
33
114
  export declare const EvidenceConfigSchema: z.ZodObject<{
@@ -126,6 +207,33 @@ export declare const PluginConfigSchema: z.ZodObject<{
126
207
  critical_threshold: z.ZodDefault<z.ZodNumber>;
127
208
  model_limits: z.ZodDefault<z.ZodRecord<z.ZodString, z.ZodNumber>>;
128
209
  max_injection_tokens: z.ZodDefault<z.ZodNumber>;
210
+ scoring: z.ZodOptional<z.ZodObject<{
211
+ enabled: z.ZodDefault<z.ZodBoolean>;
212
+ max_candidates: z.ZodDefault<z.ZodNumber>;
213
+ weights: z.ZodOptional<z.ZodObject<{
214
+ phase: z.ZodDefault<z.ZodNumber>;
215
+ current_task: z.ZodDefault<z.ZodNumber>;
216
+ blocked_task: z.ZodDefault<z.ZodNumber>;
217
+ recent_failure: z.ZodDefault<z.ZodNumber>;
218
+ recent_success: z.ZodDefault<z.ZodNumber>;
219
+ evidence_presence: z.ZodDefault<z.ZodNumber>;
220
+ decision_recency: z.ZodDefault<z.ZodNumber>;
221
+ dependency_proximity: z.ZodDefault<z.ZodNumber>;
222
+ }, z.core.$strip>>;
223
+ decision_decay: z.ZodOptional<z.ZodObject<{
224
+ mode: z.ZodDefault<z.ZodEnum<{
225
+ linear: "linear";
226
+ exponential: "exponential";
227
+ }>>;
228
+ half_life_hours: z.ZodDefault<z.ZodNumber>;
229
+ }, z.core.$strip>>;
230
+ token_ratios: z.ZodOptional<z.ZodObject<{
231
+ prose: z.ZodDefault<z.ZodNumber>;
232
+ code: z.ZodDefault<z.ZodNumber>;
233
+ markdown: z.ZodDefault<z.ZodNumber>;
234
+ json: z.ZodDefault<z.ZodNumber>;
235
+ }, z.core.$strip>>;
236
+ }, z.core.$strip>>;
129
237
  }, z.core.$strip>>;
130
238
  guardrails: z.ZodOptional<z.ZodObject<{
131
239
  enabled: z.ZodDefault<z.ZodBoolean>;
package/dist/index.js CHANGED
@@ -26,29 +26,6 @@ var __export = (target, all) => {
26
26
  };
27
27
  var __require = import.meta.require;
28
28
 
29
- // src/config/constants.ts
30
- var QA_AGENTS = ["reviewer", "critic"];
31
- var PIPELINE_AGENTS = ["explorer", "coder", "test_engineer"];
32
- var ORCHESTRATOR_NAME = "architect";
33
- var ALL_SUBAGENT_NAMES = [
34
- "sme",
35
- ...QA_AGENTS,
36
- ...PIPELINE_AGENTS
37
- ];
38
- var ALL_AGENT_NAMES = [
39
- ORCHESTRATOR_NAME,
40
- ...ALL_SUBAGENT_NAMES
41
- ];
42
- var DEFAULT_MODELS = {
43
- architect: "anthropic/claude-sonnet-4-5",
44
- explorer: "google/gemini-2.0-flash",
45
- coder: "anthropic/claude-sonnet-4-5",
46
- test_engineer: "google/gemini-2.0-flash",
47
- sme: "google/gemini-2.0-flash",
48
- reviewer: "google/gemini-2.0-flash",
49
- critic: "google/gemini-2.0-flash",
50
- default: "google/gemini-2.0-flash"
51
- };
52
29
  // src/config/loader.ts
53
30
  import * as fs from "fs";
54
31
  import * as os from "os";
@@ -13603,12 +13580,40 @@ var HooksConfigSchema = exports_external.object({
13603
13580
  delegation_tracker: exports_external.boolean().default(false),
13604
13581
  agent_awareness_max_chars: exports_external.number().min(50).max(2000).default(300)
13605
13582
  });
13583
+ var ScoringWeightsSchema = exports_external.object({
13584
+ phase: exports_external.number().min(0).max(5).default(1),
13585
+ current_task: exports_external.number().min(0).max(5).default(2),
13586
+ blocked_task: exports_external.number().min(0).max(5).default(1.5),
13587
+ recent_failure: exports_external.number().min(0).max(5).default(2.5),
13588
+ recent_success: exports_external.number().min(0).max(5).default(0.5),
13589
+ evidence_presence: exports_external.number().min(0).max(5).default(1),
13590
+ decision_recency: exports_external.number().min(0).max(5).default(1.5),
13591
+ dependency_proximity: exports_external.number().min(0).max(5).default(1)
13592
+ });
13593
+ var DecisionDecaySchema = exports_external.object({
13594
+ mode: exports_external.enum(["linear", "exponential"]).default("exponential"),
13595
+ half_life_hours: exports_external.number().min(1).max(168).default(24)
13596
+ });
13597
+ var TokenRatiosSchema = exports_external.object({
13598
+ prose: exports_external.number().min(0.1).max(1).default(0.25),
13599
+ code: exports_external.number().min(0.1).max(1).default(0.4),
13600
+ markdown: exports_external.number().min(0.1).max(1).default(0.3),
13601
+ json: exports_external.number().min(0.1).max(1).default(0.35)
13602
+ });
13603
+ var ScoringConfigSchema = exports_external.object({
13604
+ enabled: exports_external.boolean().default(false),
13605
+ max_candidates: exports_external.number().min(10).max(500).default(100),
13606
+ weights: ScoringWeightsSchema.optional(),
13607
+ decision_decay: DecisionDecaySchema.optional(),
13608
+ token_ratios: TokenRatiosSchema.optional()
13609
+ });
13606
13610
  var ContextBudgetConfigSchema = exports_external.object({
13607
13611
  enabled: exports_external.boolean().default(true),
13608
13612
  warn_threshold: exports_external.number().min(0).max(1).default(0.7),
13609
13613
  critical_threshold: exports_external.number().min(0).max(1).default(0.9),
13610
13614
  model_limits: exports_external.record(exports_external.string(), exports_external.number().min(1000)).default({ default: 128000 }),
13611
- max_injection_tokens: exports_external.number().min(100).max(50000).default(4000)
13615
+ max_injection_tokens: exports_external.number().min(100).max(50000).default(4000),
13616
+ scoring: ScoringConfigSchema.optional()
13612
13617
  });
13613
13618
  var EvidenceConfigSchema = exports_external.object({
13614
13619
  enabled: exports_external.boolean().default(true),
@@ -13617,7 +13622,7 @@ var EvidenceConfigSchema = exports_external.object({
13617
13622
  auto_archive: exports_external.boolean().default(false)
13618
13623
  });
13619
13624
  var GuardrailsProfileSchema = exports_external.object({
13620
- max_tool_calls: exports_external.number().min(10).max(1000).optional(),
13625
+ max_tool_calls: exports_external.number().min(0).max(1000).optional(),
13621
13626
  max_duration_minutes: exports_external.number().min(0).max(480).optional(),
13622
13627
  max_repetitions: exports_external.number().min(3).max(50).optional(),
13623
13628
  max_consecutive_errors: exports_external.number().min(2).max(20).optional(),
@@ -13626,7 +13631,7 @@ var GuardrailsProfileSchema = exports_external.object({
13626
13631
  });
13627
13632
  var DEFAULT_AGENT_PROFILES = {
13628
13633
  architect: {
13629
- max_tool_calls: 800,
13634
+ max_tool_calls: 0,
13630
13635
  max_duration_minutes: 0,
13631
13636
  max_consecutive_errors: 8,
13632
13637
  warning_threshold: 0.75
@@ -13665,7 +13670,7 @@ var DEFAULT_AGENT_PROFILES = {
13665
13670
  var DEFAULT_ARCHITECT_PROFILE = DEFAULT_AGENT_PROFILES.architect;
13666
13671
  var GuardrailsConfigSchema = exports_external.object({
13667
13672
  enabled: exports_external.boolean().default(true),
13668
- max_tool_calls: exports_external.number().min(10).max(1000).default(200),
13673
+ max_tool_calls: exports_external.number().min(0).max(1000).default(200),
13669
13674
  max_duration_minutes: exports_external.number().min(0).max(480).default(30),
13670
13675
  max_repetitions: exports_external.number().min(3).max(50).default(10),
13671
13676
  max_consecutive_errors: exports_external.number().min(2).max(20).default(5),
@@ -13691,8 +13696,9 @@ function resolveGuardrailsConfig(base, agentName) {
13691
13696
  return base;
13692
13697
  }
13693
13698
  const baseName = stripKnownSwarmPrefix(agentName);
13694
- const builtIn = DEFAULT_AGENT_PROFILES[baseName];
13695
- const userProfile = base.profiles?.[baseName] ?? base.profiles?.[agentName];
13699
+ const effectiveName = baseName === "unknown" ? ORCHESTRATOR_NAME : baseName;
13700
+ const builtIn = DEFAULT_AGENT_PROFILES[effectiveName];
13701
+ const userProfile = base.profiles?.[effectiveName] ?? base.profiles?.[baseName] ?? base.profiles?.[agentName];
13696
13702
  if (!builtIn && !userProfile) {
13697
13703
  return base;
13698
13704
  }
@@ -13803,6 +13809,30 @@ function loadAgentPrompt(agentName) {
13803
13809
  }
13804
13810
  return result;
13805
13811
  }
13812
+
13813
+ // src/config/constants.ts
13814
+ var QA_AGENTS = ["reviewer", "critic"];
13815
+ var PIPELINE_AGENTS = ["explorer", "coder", "test_engineer"];
13816
+ var ORCHESTRATOR_NAME = "architect";
13817
+ var ALL_SUBAGENT_NAMES = [
13818
+ "sme",
13819
+ ...QA_AGENTS,
13820
+ ...PIPELINE_AGENTS
13821
+ ];
13822
+ var ALL_AGENT_NAMES = [
13823
+ ORCHESTRATOR_NAME,
13824
+ ...ALL_SUBAGENT_NAMES
13825
+ ];
13826
+ var DEFAULT_MODELS = {
13827
+ architect: "anthropic/claude-sonnet-4-5",
13828
+ explorer: "google/gemini-2.0-flash",
13829
+ coder: "anthropic/claude-sonnet-4-5",
13830
+ test_engineer: "google/gemini-2.0-flash",
13831
+ sme: "google/gemini-2.0-flash",
13832
+ reviewer: "google/gemini-2.0-flash",
13833
+ critic: "google/gemini-2.0-flash",
13834
+ default: "google/gemini-2.0-flash"
13835
+ };
13806
13836
  // src/config/plan-schema.ts
13807
13837
  var TaskStatusSchema = exports_external.enum([
13808
13838
  "pending",
@@ -16022,9 +16052,16 @@ function ensureAgentSession(sessionId, agentName) {
16022
16052
  const now = Date.now();
16023
16053
  let session = swarmState.agentSessions.get(sessionId);
16024
16054
  if (session) {
16025
- if (agentName && session.agentName === "unknown") {
16055
+ if (agentName && agentName !== session.agentName) {
16026
16056
  session.agentName = agentName;
16027
16057
  session.startTime = now;
16058
+ session.toolCallCount = 0;
16059
+ session.consecutiveErrors = 0;
16060
+ session.recentToolCalls = [];
16061
+ session.warningIssued = false;
16062
+ session.warningReason = "";
16063
+ session.hardLimitHit = false;
16064
+ session.lastSuccessTime = now;
16028
16065
  }
16029
16066
  session.lastToolCallTime = now;
16030
16067
  return session;
@@ -16320,7 +16357,7 @@ function createGuardrailsHooks(config2) {
16320
16357
  }
16321
16358
  }
16322
16359
  const elapsedMinutes = (Date.now() - session.startTime) / 60000;
16323
- if (session.toolCallCount >= agentConfig.max_tool_calls) {
16360
+ if (agentConfig.max_tool_calls > 0 && session.toolCallCount >= agentConfig.max_tool_calls) {
16324
16361
  session.hardLimitHit = true;
16325
16362
  warn("Circuit breaker: tool call limit hit", {
16326
16363
  sessionID: input.sessionID,
@@ -16360,12 +16397,12 @@ function createGuardrailsHooks(config2) {
16360
16397
  throw new Error(`\uD83D\uDED1 LIMIT REACHED: No successful tool call for ${Math.floor(idleMinutes)} minutes (idle timeout: ${agentConfig.idle_timeout_minutes} min). This suggests the agent may be stuck. Return your progress summary.`);
16361
16398
  }
16362
16399
  if (!session.warningIssued) {
16363
- const toolPct = session.toolCallCount / agentConfig.max_tool_calls;
16400
+ const toolPct = agentConfig.max_tool_calls > 0 ? session.toolCallCount / agentConfig.max_tool_calls : 0;
16364
16401
  const durationPct = agentConfig.max_duration_minutes > 0 ? elapsedMinutes / agentConfig.max_duration_minutes : 0;
16365
16402
  const repPct = repetitionCount / agentConfig.max_repetitions;
16366
16403
  const errorPct = session.consecutiveErrors / agentConfig.max_consecutive_errors;
16367
16404
  const reasons = [];
16368
- if (toolPct >= agentConfig.warning_threshold) {
16405
+ if (agentConfig.max_tool_calls > 0 && toolPct >= agentConfig.warning_threshold) {
16369
16406
  reasons.push(`tool calls ${session.toolCallCount}/${agentConfig.max_tool_calls}`);
16370
16407
  }
16371
16408
  if (durationPct >= agentConfig.warning_threshold) {
@@ -29354,6 +29391,9 @@ var OpenCodeSwarm = async (ctx) => {
29354
29391
  "experimental.session.compacting": compactionHook["experimental.session.compacting"],
29355
29392
  "command.execute.before": safeHook(commandHandler),
29356
29393
  "tool.execute.before": async (input, output) => {
29394
+ if (!swarmState.activeAgent.has(input.sessionID)) {
29395
+ swarmState.activeAgent.set(input.sessionID, ORCHESTRATOR_NAME);
29396
+ }
29357
29397
  await guardrailsHooks.toolBefore(input, output);
29358
29398
  await safeHook(activityHooks.toolBefore)(input, output);
29359
29399
  },
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "opencode-swarm",
3
- "version": "5.0.8",
3
+ "version": "5.0.10",
4
4
  "description": "Architect-centric agentic swarm plugin for OpenCode - hub-and-spoke orchestration with SME consultation, code generation, and QA review",
5
5
  "main": "dist/index.js",
6
6
  "types": "dist/index.d.ts",