opencode-swarm 5.0.5 → 5.0.6

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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "opencode-swarm",
3
- "version": "5.0.5",
3
+ "version": "5.0.6",
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",
@@ -1,178 +0,0 @@
1
- // src/state.ts
2
- var swarmState = {
3
- activeToolCalls: new Map,
4
- toolAggregates: new Map,
5
- activeAgent: new Map,
6
- delegationChains: new Map,
7
- pendingEvents: 0,
8
- agentSessions: new Map
9
- };
10
- function startAgentSession(sessionId, agentName, staleDurationMs = 3600000) {
11
- const now = Date.now();
12
- for (const [id, session] of swarmState.agentSessions) {
13
- if (now - session.startTime > staleDurationMs) {
14
- swarmState.agentSessions.delete(id);
15
- }
16
- }
17
- const sessionState = {
18
- agentName,
19
- startTime: now,
20
- toolCallCount: 0,
21
- consecutiveErrors: 0,
22
- recentToolCalls: [],
23
- warningIssued: false,
24
- hardLimitHit: false
25
- };
26
- swarmState.agentSessions.set(sessionId, sessionState);
27
- }
28
- function getAgentSession(sessionId) {
29
- return swarmState.agentSessions.get(sessionId);
30
- }
31
- // src/utils/logger.ts
32
- var DEBUG = process.env.OPENCODE_SWARM_DEBUG === "1";
33
- function warn(message, data) {
34
- const timestamp = new Date().toISOString();
35
- if (data !== undefined) {
36
- console.warn(`[opencode-swarm ${timestamp}] WARN: ${message}`, data);
37
- } else {
38
- console.warn(`[opencode-swarm ${timestamp}] WARN: ${message}`);
39
- }
40
- }
41
- // src/hooks/guardrails.ts
42
- function createGuardrailsHooks(config) {
43
- if (config.enabled === false) {
44
- return {
45
- toolBefore: async () => {},
46
- toolAfter: async () => {},
47
- messagesTransform: async () => {}
48
- };
49
- }
50
- return {
51
- toolBefore: async (input, output) => {
52
- let session = getAgentSession(input.sessionID);
53
- if (!session) {
54
- startAgentSession(input.sessionID, "unknown");
55
- session = getAgentSession(input.sessionID);
56
- if (!session) {
57
- warn(`Failed to create session for ${input.sessionID}`);
58
- return;
59
- }
60
- }
61
- if (session.hardLimitHit) {
62
- throw new Error("\uD83D\uDED1 CIRCUIT BREAKER: Agent blocked. Hard limit was previously triggered. Stop making tool calls and return your progress summary.");
63
- }
64
- session.toolCallCount++;
65
- const hash = hashArgs(output.args);
66
- session.recentToolCalls.push({
67
- tool: input.tool,
68
- argsHash: hash,
69
- timestamp: Date.now()
70
- });
71
- if (session.recentToolCalls.length > 20) {
72
- session.recentToolCalls.shift();
73
- }
74
- let repetitionCount = 0;
75
- if (session.recentToolCalls.length > 0) {
76
- const lastEntry = session.recentToolCalls[session.recentToolCalls.length - 1];
77
- for (let i = session.recentToolCalls.length - 1;i >= 0; i--) {
78
- const entry = session.recentToolCalls[i];
79
- if (entry.tool === lastEntry.tool && entry.argsHash === lastEntry.argsHash) {
80
- repetitionCount++;
81
- } else {
82
- break;
83
- }
84
- }
85
- }
86
- const elapsedMinutes = (Date.now() - session.startTime) / 60000;
87
- if (session.toolCallCount >= config.max_tool_calls) {
88
- session.hardLimitHit = true;
89
- throw new Error(`\uD83D\uDED1 CIRCUIT BREAKER: Tool call limit reached (${session.toolCallCount}/${config.max_tool_calls}). Stop making tool calls and return your progress summary.`);
90
- }
91
- if (elapsedMinutes >= config.max_duration_minutes) {
92
- session.hardLimitHit = true;
93
- throw new Error(`\uD83D\uDED1 CIRCUIT BREAKER: Duration limit reached (${Math.floor(elapsedMinutes)} min). Stop making tool calls and return your progress summary.`);
94
- }
95
- if (repetitionCount >= config.max_repetitions) {
96
- session.hardLimitHit = true;
97
- throw new Error(`\uD83D\uDED1 CIRCUIT BREAKER: Repetition detected (same call ${repetitionCount} times). Stop making tool calls and return your progress summary.`);
98
- }
99
- if (session.consecutiveErrors >= config.max_consecutive_errors) {
100
- session.hardLimitHit = true;
101
- throw new Error(`\uD83D\uDED1 CIRCUIT BREAKER: Too many consecutive errors (${session.consecutiveErrors}). Stop making tool calls and return your progress summary.`);
102
- }
103
- if (!session.warningIssued) {
104
- const toolWarning = session.toolCallCount >= config.max_tool_calls * config.warning_threshold;
105
- const durationWarning = elapsedMinutes >= config.max_duration_minutes * config.warning_threshold;
106
- const repetitionWarning = repetitionCount >= config.max_repetitions * config.warning_threshold;
107
- const errorWarning = session.consecutiveErrors >= config.max_consecutive_errors * config.warning_threshold;
108
- if (toolWarning || durationWarning || repetitionWarning || errorWarning) {
109
- session.warningIssued = true;
110
- }
111
- }
112
- },
113
- toolAfter: async (input, output) => {
114
- const session = getAgentSession(input.sessionID);
115
- if (!session) {
116
- return;
117
- }
118
- const outputStr = String(output.output ?? "");
119
- const hasError = output.output === null || output.output === undefined || outputStr === "" || outputStr.toLowerCase().includes("error");
120
- if (hasError) {
121
- session.consecutiveErrors++;
122
- } else {
123
- session.consecutiveErrors = 0;
124
- }
125
- },
126
- messagesTransform: async (input, output) => {
127
- const messages = output.messages;
128
- if (!messages || messages.length === 0) {
129
- return;
130
- }
131
- const lastMessage = messages[messages.length - 1];
132
- let sessionId = lastMessage.info?.sessionID;
133
- if (!sessionId) {
134
- for (const [id, session2] of swarmState.agentSessions) {
135
- if (session2.warningIssued || session2.hardLimitHit) {
136
- sessionId = id;
137
- break;
138
- }
139
- }
140
- }
141
- if (!sessionId) {
142
- return;
143
- }
144
- const session = getAgentSession(sessionId);
145
- if (!session || !session.warningIssued && !session.hardLimitHit) {
146
- return;
147
- }
148
- const textPart = lastMessage.parts.find((part) => part.type === "text" && typeof part.text === "string");
149
- if (!textPart) {
150
- return;
151
- }
152
- if (session.hardLimitHit) {
153
- textPart.text = `[\uD83D\uDED1 CIRCUIT BREAKER ACTIVE: You have exceeded your resource limits. Do NOT make any more tool calls. Immediately return a summary of your progress so far. Any further tool calls will be blocked.]
154
-
155
- ` + textPart.text;
156
- } else if (session.warningIssued) {
157
- textPart.text = `[⚠️ GUARDRAIL WARNING: You are approaching resource limits. Please wrap up your current task efficiently. Avoid unnecessary tool calls and prepare to return your results soon.]
158
-
159
- ` + textPart.text;
160
- }
161
- }
162
- };
163
- }
164
- function hashArgs(args) {
165
- try {
166
- if (typeof args !== "object" || args === null) {
167
- return 0;
168
- }
169
- const sortedKeys = Object.keys(args).sort();
170
- return Number(Bun.hash(JSON.stringify(args, sortedKeys)));
171
- } catch {
172
- return 0;
173
- }
174
- }
175
- export {
176
- hashArgs,
177
- createGuardrailsHooks
178
- };
package/dist/state.js DELETED
@@ -1,48 +0,0 @@
1
- // src/state.ts
2
- var swarmState = {
3
- activeToolCalls: new Map,
4
- toolAggregates: new Map,
5
- activeAgent: new Map,
6
- delegationChains: new Map,
7
- pendingEvents: 0,
8
- agentSessions: new Map
9
- };
10
- function resetSwarmState() {
11
- swarmState.activeToolCalls.clear();
12
- swarmState.toolAggregates.clear();
13
- swarmState.activeAgent.clear();
14
- swarmState.delegationChains.clear();
15
- swarmState.pendingEvents = 0;
16
- swarmState.agentSessions.clear();
17
- }
18
- function startAgentSession(sessionId, agentName, staleDurationMs = 3600000) {
19
- const now = Date.now();
20
- for (const [id, session] of swarmState.agentSessions) {
21
- if (now - session.startTime > staleDurationMs) {
22
- swarmState.agentSessions.delete(id);
23
- }
24
- }
25
- const sessionState = {
26
- agentName,
27
- startTime: now,
28
- toolCallCount: 0,
29
- consecutiveErrors: 0,
30
- recentToolCalls: [],
31
- warningIssued: false,
32
- hardLimitHit: false
33
- };
34
- swarmState.agentSessions.set(sessionId, sessionState);
35
- }
36
- function endAgentSession(sessionId) {
37
- swarmState.agentSessions.delete(sessionId);
38
- }
39
- function getAgentSession(sessionId) {
40
- return swarmState.agentSessions.get(sessionId);
41
- }
42
- export {
43
- swarmState,
44
- startAgentSession,
45
- resetSwarmState,
46
- getAgentSession,
47
- endAgentSession
48
- };