opencode-swarm 5.0.6 → 5.0.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.
@@ -43,6 +43,7 @@ export declare const GuardrailsProfileSchema: z.ZodObject<{
43
43
  max_repetitions: z.ZodOptional<z.ZodNumber>;
44
44
  max_consecutive_errors: z.ZodOptional<z.ZodNumber>;
45
45
  warning_threshold: z.ZodOptional<z.ZodNumber>;
46
+ idle_timeout_minutes: z.ZodOptional<z.ZodNumber>;
46
47
  }, z.core.$strip>;
47
48
  export type GuardrailsProfile = z.infer<typeof GuardrailsProfileSchema>;
48
49
  export declare const DEFAULT_AGENT_PROFILES: Record<string, GuardrailsProfile>;
@@ -53,6 +54,7 @@ export declare const DEFAULT_ARCHITECT_PROFILE: {
53
54
  max_repetitions?: number | undefined;
54
55
  max_consecutive_errors?: number | undefined;
55
56
  warning_threshold?: number | undefined;
57
+ idle_timeout_minutes?: number | undefined;
56
58
  };
57
59
  export declare const GuardrailsConfigSchema: z.ZodObject<{
58
60
  enabled: z.ZodDefault<z.ZodBoolean>;
@@ -61,12 +63,14 @@ export declare const GuardrailsConfigSchema: z.ZodObject<{
61
63
  max_repetitions: z.ZodDefault<z.ZodNumber>;
62
64
  max_consecutive_errors: z.ZodDefault<z.ZodNumber>;
63
65
  warning_threshold: z.ZodDefault<z.ZodNumber>;
66
+ idle_timeout_minutes: z.ZodDefault<z.ZodNumber>;
64
67
  profiles: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodObject<{
65
68
  max_tool_calls: z.ZodOptional<z.ZodNumber>;
66
69
  max_duration_minutes: z.ZodOptional<z.ZodNumber>;
67
70
  max_repetitions: z.ZodOptional<z.ZodNumber>;
68
71
  max_consecutive_errors: z.ZodOptional<z.ZodNumber>;
69
72
  warning_threshold: z.ZodOptional<z.ZodNumber>;
73
+ idle_timeout_minutes: z.ZodOptional<z.ZodNumber>;
70
74
  }, z.core.$strip>>>;
71
75
  }, z.core.$strip>;
72
76
  export type GuardrailsConfig = z.infer<typeof GuardrailsConfigSchema>;
@@ -130,12 +134,14 @@ export declare const PluginConfigSchema: z.ZodObject<{
130
134
  max_repetitions: z.ZodDefault<z.ZodNumber>;
131
135
  max_consecutive_errors: z.ZodDefault<z.ZodNumber>;
132
136
  warning_threshold: z.ZodDefault<z.ZodNumber>;
137
+ idle_timeout_minutes: z.ZodDefault<z.ZodNumber>;
133
138
  profiles: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodObject<{
134
139
  max_tool_calls: z.ZodOptional<z.ZodNumber>;
135
140
  max_duration_minutes: z.ZodOptional<z.ZodNumber>;
136
141
  max_repetitions: z.ZodOptional<z.ZodNumber>;
137
142
  max_consecutive_errors: z.ZodOptional<z.ZodNumber>;
138
143
  warning_threshold: z.ZodOptional<z.ZodNumber>;
144
+ idle_timeout_minutes: z.ZodOptional<z.ZodNumber>;
139
145
  }, z.core.$strip>>>;
140
146
  }, z.core.$strip>>;
141
147
  evidence: z.ZodOptional<z.ZodObject<{
package/dist/index.js CHANGED
@@ -13617,16 +13617,17 @@ var EvidenceConfigSchema = exports_external.object({
13617
13617
  auto_archive: exports_external.boolean().default(false)
13618
13618
  });
13619
13619
  var GuardrailsProfileSchema = exports_external.object({
13620
- max_tool_calls: exports_external.number().min(10).max(1000).optional(),
13621
- max_duration_minutes: exports_external.number().min(1).max(120).optional(),
13620
+ max_tool_calls: exports_external.number().min(0).max(1000).optional(),
13621
+ max_duration_minutes: exports_external.number().min(0).max(480).optional(),
13622
13622
  max_repetitions: exports_external.number().min(3).max(50).optional(),
13623
13623
  max_consecutive_errors: exports_external.number().min(2).max(20).optional(),
13624
- warning_threshold: exports_external.number().min(0.1).max(0.9).optional()
13624
+ warning_threshold: exports_external.number().min(0.1).max(0.9).optional(),
13625
+ idle_timeout_minutes: exports_external.number().min(5).max(240).optional()
13625
13626
  });
13626
13627
  var DEFAULT_AGENT_PROFILES = {
13627
13628
  architect: {
13628
- max_tool_calls: 800,
13629
- max_duration_minutes: 90,
13629
+ max_tool_calls: 0,
13630
+ max_duration_minutes: 0,
13630
13631
  max_consecutive_errors: 8,
13631
13632
  warning_threshold: 0.75
13632
13633
  },
@@ -13664,11 +13665,12 @@ var DEFAULT_AGENT_PROFILES = {
13664
13665
  var DEFAULT_ARCHITECT_PROFILE = DEFAULT_AGENT_PROFILES.architect;
13665
13666
  var GuardrailsConfigSchema = exports_external.object({
13666
13667
  enabled: exports_external.boolean().default(true),
13667
- max_tool_calls: exports_external.number().min(10).max(1000).default(200),
13668
- max_duration_minutes: exports_external.number().min(1).max(120).default(30),
13668
+ max_tool_calls: exports_external.number().min(0).max(1000).default(200),
13669
+ max_duration_minutes: exports_external.number().min(0).max(480).default(30),
13669
13670
  max_repetitions: exports_external.number().min(3).max(50).default(10),
13670
13671
  max_consecutive_errors: exports_external.number().min(2).max(20).default(5),
13671
13672
  warning_threshold: exports_external.number().min(0.1).max(0.9).default(0.75),
13673
+ idle_timeout_minutes: exports_external.number().min(5).max(240).default(60),
13672
13674
  profiles: exports_external.record(exports_external.string(), GuardrailsProfileSchema).optional()
13673
13675
  });
13674
13676
  function stripKnownSwarmPrefix(name) {
@@ -16008,7 +16010,8 @@ function startAgentSession(sessionId, agentName, staleDurationMs = 7200000) {
16008
16010
  recentToolCalls: [],
16009
16011
  warningIssued: false,
16010
16012
  warningReason: "",
16011
- hardLimitHit: false
16013
+ hardLimitHit: false,
16014
+ lastSuccessTime: now
16012
16015
  };
16013
16016
  swarmState.agentSessions.set(sessionId, sessionState);
16014
16017
  }
@@ -16019,9 +16022,16 @@ function ensureAgentSession(sessionId, agentName) {
16019
16022
  const now = Date.now();
16020
16023
  let session = swarmState.agentSessions.get(sessionId);
16021
16024
  if (session) {
16022
- if (agentName && session.agentName === "unknown") {
16025
+ if (agentName && agentName !== session.agentName) {
16023
16026
  session.agentName = agentName;
16024
16027
  session.startTime = now;
16028
+ session.toolCallCount = 0;
16029
+ session.consecutiveErrors = 0;
16030
+ session.recentToolCalls = [];
16031
+ session.warningIssued = false;
16032
+ session.warningReason = "";
16033
+ session.hardLimitHit = false;
16034
+ session.lastSuccessTime = now;
16025
16035
  }
16026
16036
  session.lastToolCallTime = now;
16027
16037
  return session;
@@ -16317,7 +16327,7 @@ function createGuardrailsHooks(config2) {
16317
16327
  }
16318
16328
  }
16319
16329
  const elapsedMinutes = (Date.now() - session.startTime) / 60000;
16320
- if (session.toolCallCount >= agentConfig.max_tool_calls) {
16330
+ if (agentConfig.max_tool_calls > 0 && session.toolCallCount >= agentConfig.max_tool_calls) {
16321
16331
  session.hardLimitHit = true;
16322
16332
  warn("Circuit breaker: tool call limit hit", {
16323
16333
  sessionID: input.sessionID,
@@ -16327,7 +16337,7 @@ function createGuardrailsHooks(config2) {
16327
16337
  });
16328
16338
  throw new Error(`\uD83D\uDED1 LIMIT REACHED: Tool calls exhausted (${session.toolCallCount}/${agentConfig.max_tool_calls}). Finish the current operation and return your progress summary.`);
16329
16339
  }
16330
- if (elapsedMinutes >= agentConfig.max_duration_minutes) {
16340
+ if (agentConfig.max_duration_minutes > 0 && elapsedMinutes >= agentConfig.max_duration_minutes) {
16331
16341
  session.hardLimitHit = true;
16332
16342
  warn("Circuit breaker: duration limit hit", {
16333
16343
  sessionID: input.sessionID,
@@ -16345,13 +16355,24 @@ function createGuardrailsHooks(config2) {
16345
16355
  session.hardLimitHit = true;
16346
16356
  throw new Error(`\uD83D\uDED1 LIMIT REACHED: ${session.consecutiveErrors} consecutive tool errors detected. Return your progress summary with details of what went wrong.`);
16347
16357
  }
16358
+ const idleMinutes = (Date.now() - session.lastSuccessTime) / 60000;
16359
+ if (idleMinutes >= agentConfig.idle_timeout_minutes) {
16360
+ session.hardLimitHit = true;
16361
+ warn("Circuit breaker: idle timeout hit", {
16362
+ sessionID: input.sessionID,
16363
+ agentName: session.agentName,
16364
+ idleTimeoutMinutes: agentConfig.idle_timeout_minutes,
16365
+ idleMinutes: Math.floor(idleMinutes)
16366
+ });
16367
+ 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.`);
16368
+ }
16348
16369
  if (!session.warningIssued) {
16349
- const toolPct = session.toolCallCount / agentConfig.max_tool_calls;
16350
- const durationPct = elapsedMinutes / agentConfig.max_duration_minutes;
16370
+ const toolPct = agentConfig.max_tool_calls > 0 ? session.toolCallCount / agentConfig.max_tool_calls : 0;
16371
+ const durationPct = agentConfig.max_duration_minutes > 0 ? elapsedMinutes / agentConfig.max_duration_minutes : 0;
16351
16372
  const repPct = repetitionCount / agentConfig.max_repetitions;
16352
16373
  const errorPct = session.consecutiveErrors / agentConfig.max_consecutive_errors;
16353
16374
  const reasons = [];
16354
- if (toolPct >= agentConfig.warning_threshold) {
16375
+ if (agentConfig.max_tool_calls > 0 && toolPct >= agentConfig.warning_threshold) {
16355
16376
  reasons.push(`tool calls ${session.toolCallCount}/${agentConfig.max_tool_calls}`);
16356
16377
  }
16357
16378
  if (durationPct >= agentConfig.warning_threshold) {
@@ -16379,6 +16400,7 @@ function createGuardrailsHooks(config2) {
16379
16400
  session.consecutiveErrors++;
16380
16401
  } else {
16381
16402
  session.consecutiveErrors = 0;
16403
+ session.lastSuccessTime = Date.now();
16382
16404
  }
16383
16405
  },
16384
16406
  messagesTransform: async (_input, output) => {
package/dist/state.d.ts CHANGED
@@ -59,6 +59,8 @@ export interface AgentSessionState {
59
59
  warningReason: string;
60
60
  /** Whether a hard limit has been triggered */
61
61
  hardLimitHit: boolean;
62
+ /** Timestamp of most recent SUCCESSFUL tool call (for idle timeout) */
63
+ lastSuccessTime: number;
62
64
  }
63
65
  /**
64
66
  * Singleton state object for sharing data across hooks
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "opencode-swarm",
3
- "version": "5.0.6",
3
+ "version": "5.0.9",
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",
@@ -25,7 +25,8 @@
25
25
  "LICENSE"
26
26
  ],
27
27
  "scripts": {
28
- "build": "bun build src/index.ts --outdir dist --target bun --format esm && bun build src/cli/index.ts --outdir dist/cli --target bun --format esm && tsc --emitDeclarationOnly",
28
+ "clean": "rm -rf dist",
29
+ "build": "rm -rf dist && bun build src/index.ts --outdir dist --target bun --format esm && bun build src/cli/index.ts --outdir dist/cli --target bun --format esm && tsc --emitDeclarationOnly",
29
30
  "typecheck": "tsc --noEmit",
30
31
  "test": "bun test",
31
32
  "lint": "biome lint .",
@@ -1,2 +0,0 @@
1
- import type { AgentDefinition } from './architect';
2
- export declare function createAuditorAgent(model: string, customPrompt?: string, customAppendPrompt?: string): AgentDefinition;
@@ -1,2 +0,0 @@
1
- import type { AgentDefinition } from './architect';
2
- export declare function createSecurityReviewerAgent(model: string, customPrompt?: string, customAppendPrompt?: string): AgentDefinition;
@@ -1,2 +0,0 @@
1
- import type { SMEDomainConfig } from './base';
2
- export declare const activeDirectorySMEConfig: SMEDomainConfig;
@@ -1,2 +0,0 @@
1
- import type { SMEDomainConfig } from './base';
2
- export declare const aiSMEConfig: SMEDomainConfig;
@@ -1,2 +0,0 @@
1
- import type { SMEDomainConfig } from './base';
2
- export declare const apiSMEConfig: SMEDomainConfig;
@@ -1,2 +0,0 @@
1
- import type { SMEDomainConfig } from './base';
2
- export declare const azureSMEConfig: SMEDomainConfig;
@@ -1,13 +0,0 @@
1
- import type { AgentDefinition } from '../architect';
2
- /**
3
- * SME domain configuration
4
- */
5
- export interface SMEDomainConfig {
6
- domain: string;
7
- description: string;
8
- guidance: string;
9
- }
10
- /**
11
- * Create an SME agent definition
12
- */
13
- export declare function createSMEAgent(agentName: string, domainConfig: SMEDomainConfig, model: string, customPrompt?: string, customAppendPrompt?: string): AgentDefinition;
@@ -1,2 +0,0 @@
1
- import type { SMEDomainConfig } from './base';
2
- export declare const databaseSMEConfig: SMEDomainConfig;
@@ -1,2 +0,0 @@
1
- import type { SMEDomainConfig } from './base';
2
- export declare const devopsSMEConfig: SMEDomainConfig;
@@ -1,20 +0,0 @@
1
- import type { AgentDefinition } from '../architect';
2
- import { type SMEDomainConfig } from './base';
3
- export declare const SME_CONFIGS: Record<string, SMEDomainConfig>;
4
- export declare const AGENT_TO_DOMAIN: Record<string, string>;
5
- /**
6
- * Create all SME agent definitions
7
- */
8
- export declare function createAllSMEAgents(getModel: (agentName: string) => string, loadPrompt: (agentName: string) => {
9
- prompt?: string;
10
- appendPrompt?: string;
11
- }): AgentDefinition[];
12
- /**
13
- * Get list of available SME domains
14
- */
15
- export declare function listDomains(): string[];
16
- /**
17
- * Get SME agent name for a domain
18
- */
19
- export declare function domainToAgent(domain: string): string | undefined;
20
- export { createSMEAgent, type SMEDomainConfig } from './base';
@@ -1,2 +0,0 @@
1
- import type { SMEDomainConfig } from './base';
2
- export declare const linuxSMEConfig: SMEDomainConfig;
@@ -1,2 +0,0 @@
1
- import type { SMEDomainConfig } from './base';
2
- export declare const networkSMEConfig: SMEDomainConfig;
@@ -1,2 +0,0 @@
1
- import type { SMEDomainConfig } from './base';
2
- export declare const oracleSMEConfig: SMEDomainConfig;
@@ -1,2 +0,0 @@
1
- import type { SMEDomainConfig } from './base';
2
- export declare const powershellSMEConfig: SMEDomainConfig;
@@ -1,2 +0,0 @@
1
- import type { SMEDomainConfig } from './base';
2
- export declare const pythonSMEConfig: SMEDomainConfig;
@@ -1,2 +0,0 @@
1
- import type { SMEDomainConfig } from './base';
2
- export declare const securitySMEConfig: SMEDomainConfig;
@@ -1,2 +0,0 @@
1
- import type { SMEDomainConfig } from './base';
2
- export declare const uiUxSMEConfig: SMEDomainConfig;
@@ -1,2 +0,0 @@
1
- import type { SMEDomainConfig } from './base';
2
- export declare const vmwareSMEConfig: SMEDomainConfig;
@@ -1,2 +0,0 @@
1
- import type { SMEDomainConfig } from './base';
2
- export declare const webSMEConfig: SMEDomainConfig;
@@ -1,2 +0,0 @@
1
- import type { SMEDomainConfig } from './base';
2
- export declare const windowsSMEConfig: SMEDomainConfig;
@@ -1,3 +0,0 @@
1
- import type { AgentDefinition } from './architect';
2
- export declare function createUnifiedSMEAgent(model: string, customPrompt?: string, customAppendPrompt?: string): AgentDefinition;
3
- export declare const AVAILABLE_DOMAINS: string[];