opencode-swarm 5.0.3 → 5.0.4

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/dist/index.js CHANGED
@@ -15955,11 +15955,11 @@ var swarmState = {
15955
15955
  pendingEvents: 0,
15956
15956
  agentSessions: new Map
15957
15957
  };
15958
- function startAgentSession(sessionId, agentName, staleDurationMs = 3600000) {
15958
+ function startAgentSession(sessionId, agentName, staleDurationMs = 7200000) {
15959
15959
  const now = Date.now();
15960
15960
  const staleIds = [];
15961
15961
  for (const [id, session] of swarmState.agentSessions) {
15962
- if (now - session.startTime > staleDurationMs) {
15962
+ if (now - session.lastToolCallTime > staleDurationMs) {
15963
15963
  staleIds.push(id);
15964
15964
  }
15965
15965
  }
@@ -15969,6 +15969,7 @@ function startAgentSession(sessionId, agentName, staleDurationMs = 3600000) {
15969
15969
  const sessionState = {
15970
15970
  agentName,
15971
15971
  startTime: now,
15972
+ lastToolCallTime: now,
15972
15973
  toolCallCount: 0,
15973
15974
  consecutiveErrors: 0,
15974
15975
  recentToolCalls: [],
@@ -15980,6 +15981,24 @@ function startAgentSession(sessionId, agentName, staleDurationMs = 3600000) {
15980
15981
  function getAgentSession(sessionId) {
15981
15982
  return swarmState.agentSessions.get(sessionId);
15982
15983
  }
15984
+ function ensureAgentSession(sessionId, agentName) {
15985
+ const now = Date.now();
15986
+ let session = swarmState.agentSessions.get(sessionId);
15987
+ if (session) {
15988
+ if (agentName && session.agentName === "unknown") {
15989
+ session.agentName = agentName;
15990
+ session.startTime = now;
15991
+ }
15992
+ session.lastToolCallTime = now;
15993
+ return session;
15994
+ }
15995
+ startAgentSession(sessionId, agentName ?? "unknown");
15996
+ session = swarmState.agentSessions.get(sessionId);
15997
+ if (!session) {
15998
+ throw new Error(`Failed to create guardrail session for ${sessionId}`);
15999
+ }
16000
+ return session;
16001
+ }
15983
16002
 
15984
16003
  // src/hooks/agent-activity.ts
15985
16004
  function createAgentActivityHooks(config2, directory) {
@@ -16208,6 +16227,7 @@ function createDelegationTrackerHook(config2) {
16208
16227
  }
16209
16228
  const previousAgent = swarmState.activeAgent.get(input.sessionID);
16210
16229
  swarmState.activeAgent.set(input.sessionID, input.agent);
16230
+ ensureAgentSession(input.sessionID, input.agent);
16211
16231
  if (config2.hooks?.delegation_tracker === true && previousAgent && previousAgent !== input.agent) {
16212
16232
  const entry = {
16213
16233
  from: previousAgent,
@@ -16234,22 +16254,8 @@ function createGuardrailsHooks(config2) {
16234
16254
  }
16235
16255
  return {
16236
16256
  toolBefore: async (input, output) => {
16237
- let session = getAgentSession(input.sessionID);
16238
- if (!session) {
16239
- const agentName = swarmState.activeAgent.get(input.sessionID) ?? "unknown";
16240
- startAgentSession(input.sessionID, agentName);
16241
- session = getAgentSession(input.sessionID);
16242
- if (!session) {
16243
- warn(`Failed to create session for ${input.sessionID}`);
16244
- return;
16245
- }
16246
- } else if (session.agentName === "unknown") {
16247
- const activeAgentName = swarmState.activeAgent.get(input.sessionID);
16248
- if (activeAgentName) {
16249
- session.agentName = activeAgentName;
16250
- session.startTime = Date.now();
16251
- }
16252
- }
16257
+ const agentName = swarmState.activeAgent.get(input.sessionID);
16258
+ const session = ensureAgentSession(input.sessionID, agentName);
16253
16259
  const agentConfig = resolveGuardrailsConfig(config2, session.agentName);
16254
16260
  if (session.hardLimitHit) {
16255
16261
  throw new Error("\uD83D\uDED1 CIRCUIT BREAKER: Agent blocked. Hard limit was previously triggered. Stop making tool calls and return your progress summary.");
@@ -16279,10 +16285,22 @@ function createGuardrailsHooks(config2) {
16279
16285
  const elapsedMinutes = (Date.now() - session.startTime) / 60000;
16280
16286
  if (session.toolCallCount >= agentConfig.max_tool_calls) {
16281
16287
  session.hardLimitHit = true;
16288
+ warn("Circuit breaker: tool call limit hit", {
16289
+ sessionID: input.sessionID,
16290
+ agentName: session.agentName,
16291
+ resolvedMaxCalls: agentConfig.max_tool_calls,
16292
+ currentCalls: session.toolCallCount
16293
+ });
16282
16294
  throw new Error(`\uD83D\uDED1 CIRCUIT BREAKER: Tool call limit reached (${session.toolCallCount}/${agentConfig.max_tool_calls}). Stop making tool calls and return your progress summary.`);
16283
16295
  }
16284
16296
  if (elapsedMinutes >= agentConfig.max_duration_minutes) {
16285
16297
  session.hardLimitHit = true;
16298
+ warn("Circuit breaker: duration limit hit", {
16299
+ sessionID: input.sessionID,
16300
+ agentName: session.agentName,
16301
+ resolvedMaxMinutes: agentConfig.max_duration_minutes,
16302
+ elapsedMinutes: Math.floor(elapsedMinutes)
16303
+ });
16286
16304
  throw new Error(`\uD83D\uDED1 CIRCUIT BREAKER: Duration limit reached (${Math.floor(elapsedMinutes)} min). Stop making tool calls and return your progress summary.`);
16287
16305
  }
16288
16306
  if (repetitionCount >= agentConfig.max_repetitions) {
package/dist/state.d.ts CHANGED
@@ -41,6 +41,8 @@ export interface AgentSessionState {
41
41
  agentName: string;
42
42
  /** Date.now() when session started */
43
43
  startTime: number;
44
+ /** Timestamp of most recent tool call (for stale session eviction) */
45
+ lastToolCallTime: number;
44
46
  /** Total tool calls in this session */
45
47
  toolCallCount: number;
46
48
  /** Consecutive errors (reset on success) */
@@ -82,7 +84,7 @@ export declare function resetSwarmState(): void;
82
84
  * Also removes any stale sessions older than staleDurationMs.
83
85
  * @param sessionId - The session identifier
84
86
  * @param agentName - The agent associated with this session
85
- * @param staleDurationMs - Age threshold for stale session eviction (default: 60 min)
87
+ * @param staleDurationMs - Age threshold for stale session eviction (default: 120 min)
86
88
  */
87
89
  export declare function startAgentSession(sessionId: string, agentName: string, staleDurationMs?: number): void;
88
90
  /**
@@ -96,3 +98,13 @@ export declare function endAgentSession(sessionId: string): void;
96
98
  * @returns The AgentSessionState or undefined if not found
97
99
  */
98
100
  export declare function getAgentSession(sessionId: string): AgentSessionState | undefined;
101
+ /**
102
+ * Ensure a guardrail session exists for the given sessionID.
103
+ * If one exists and agentName is provided and different, update it.
104
+ * If none exists, create one.
105
+ * Always updates lastToolCallTime.
106
+ * @param sessionId - The session identifier
107
+ * @param agentName - Optional agent name (if known)
108
+ * @returns The AgentSessionState
109
+ */
110
+ export declare function ensureAgentSession(sessionId: string, agentName?: string): AgentSessionState;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "opencode-swarm",
3
- "version": "5.0.3",
3
+ "version": "5.0.4",
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",