opencode-orchestrator 0.1.61 → 0.1.62
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.d.ts +13 -7
- package/dist/index.js +195 -101
- package/package.json +2 -1
package/dist/index.d.ts
CHANGED
|
@@ -1,13 +1,13 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* OpenCode Orchestrator Plugin
|
|
3
3
|
*
|
|
4
|
-
* 5-Agent Structured Architecture
|
|
4
|
+
* 5-Agent Structured Architecture
|
|
5
5
|
*
|
|
6
|
-
* Optimized for weak models
|
|
6
|
+
* Optimized for weak models through:
|
|
7
7
|
* - XML-structured prompts with clear boundaries
|
|
8
8
|
* - Explicit reasoning patterns (THINK → ACT → OBSERVE → ADJUST)
|
|
9
9
|
* - Evidence-based completion requirements
|
|
10
|
-
* -
|
|
10
|
+
* - Autonomous execution loop
|
|
11
11
|
*
|
|
12
12
|
* Agents: Commander, Architect, Builder, Inspector, Memory
|
|
13
13
|
*/
|
|
@@ -65,17 +65,23 @@ declare const OrchestratorPlugin: (input: PluginInput) => Promise<{
|
|
|
65
65
|
};
|
|
66
66
|
};
|
|
67
67
|
config: (config: Record<string, unknown>) => Promise<void>;
|
|
68
|
-
"chat.message": (
|
|
69
|
-
"tool.execute.after": (
|
|
68
|
+
"chat.message": (msgInput: any, msgOutput: any) => Promise<void>;
|
|
69
|
+
"tool.execute.after": (toolInput: {
|
|
70
70
|
tool: string;
|
|
71
71
|
sessionID: string;
|
|
72
72
|
callID: string;
|
|
73
73
|
arguments?: any;
|
|
74
|
-
},
|
|
74
|
+
}, toolOutput: {
|
|
75
75
|
title: string;
|
|
76
76
|
output: string;
|
|
77
77
|
metadata: any;
|
|
78
78
|
}) => Promise<void>;
|
|
79
|
-
"assistant.done": (
|
|
79
|
+
"assistant.done": (assistantInput: any, assistantOutput: any) => Promise<void>;
|
|
80
|
+
handler: ({ event }: {
|
|
81
|
+
event: {
|
|
82
|
+
type: string;
|
|
83
|
+
properties?: unknown;
|
|
84
|
+
};
|
|
85
|
+
}) => Promise<void>;
|
|
80
86
|
}>;
|
|
81
87
|
export default OrchestratorPlugin;
|
package/dist/index.js
CHANGED
|
@@ -727,16 +727,22 @@ var state = {
|
|
|
727
727
|
|
|
728
728
|
// src/tools/callAgent.ts
|
|
729
729
|
import { tool } from "@opencode-ai/plugin";
|
|
730
|
+
var AGENT_EMOJI = {
|
|
731
|
+
[AGENT_NAMES.ARCHITECT]: "\u{1F3D7}\uFE0F",
|
|
732
|
+
[AGENT_NAMES.BUILDER]: "\u{1F528}",
|
|
733
|
+
[AGENT_NAMES.INSPECTOR]: "\u{1F50D}",
|
|
734
|
+
[AGENT_NAMES.MEMORY]: "\u{1F4BE}"
|
|
735
|
+
};
|
|
730
736
|
var callAgentTool = tool({
|
|
731
737
|
description: `Call a specialized agent for parallel execution.
|
|
732
738
|
|
|
733
739
|
<agents>
|
|
734
740
|
| Agent | Role | When to Use |
|
|
735
741
|
|-------|------|-------------|
|
|
736
|
-
| ${AGENT_NAMES.ARCHITECT} | Planner | Complex task \u2192 DAG, OR 3+ failures \u2192 strategy |
|
|
737
|
-
| ${AGENT_NAMES.BUILDER} | Developer | Any code implementation (logic + UI) |
|
|
738
|
-
| ${AGENT_NAMES.INSPECTOR} | Quality | Before completion, OR on errors (auto-fixes) |
|
|
739
|
-
| ${AGENT_NAMES.MEMORY} | Context | After each task, OR at session start |
|
|
742
|
+
| ${AGENT_NAMES.ARCHITECT} \u{1F3D7}\uFE0F | Planner | Complex task \u2192 DAG, OR 3+ failures \u2192 strategy |
|
|
743
|
+
| ${AGENT_NAMES.BUILDER} \u{1F528} | Developer | Any code implementation (logic + UI) |
|
|
744
|
+
| ${AGENT_NAMES.INSPECTOR} \u{1F50D} | Quality | Before completion, OR on errors (auto-fixes) |
|
|
745
|
+
| ${AGENT_NAMES.MEMORY} \u{1F4BE} | Context | After each task, OR at session start |
|
|
740
746
|
</agents>
|
|
741
747
|
|
|
742
748
|
<execution_rules>
|
|
@@ -758,11 +764,12 @@ var callAgentTool = tool({
|
|
|
758
764
|
async execute(args) {
|
|
759
765
|
const agentDef = AGENTS[args.agent];
|
|
760
766
|
if (!agentDef) {
|
|
761
|
-
return
|
|
767
|
+
return `\u274C Error: Unknown agent: ${args.agent}`;
|
|
762
768
|
}
|
|
769
|
+
const emoji = AGENT_EMOJI[args.agent] || "\u{1F916}";
|
|
763
770
|
const prompt = `
|
|
764
771
|
\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501
|
|
765
|
-
${agentDef.id.toUpperCase()} :: ${agentDef.description}
|
|
772
|
+
${emoji} ${agentDef.id.toUpperCase()} :: ${agentDef.description}
|
|
766
773
|
\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501
|
|
767
774
|
|
|
768
775
|
<system>
|
|
@@ -832,14 +839,29 @@ New Approach: [What to try differently]
|
|
|
832
839
|
|
|
833
840
|
<execution_flow>
|
|
834
841
|
Step 1: Call Memory to load any existing context
|
|
842
|
+
- IF Memory returns empty/nothing: That's OK, proceed to Step 2
|
|
843
|
+
- Memory being empty just means fresh start
|
|
835
844
|
Step 2: If complex task, call Architect to create parallel DAG
|
|
836
845
|
Step 3: Execute tasks with same parallel_group CONCURRENTLY
|
|
837
846
|
Step 4: After EACH task, call Inspector to verify with evidence
|
|
838
847
|
Step 5: Update Memory with progress after each verified task
|
|
839
848
|
Step 6: REPEAT steps 3-5 until ALL tasks are verified complete
|
|
840
|
-
Step 7: Report "MISSION COMPLETE" with summary of evidence
|
|
849
|
+
Step 7: Report "\u2705 MISSION COMPLETE" with summary of evidence
|
|
841
850
|
</execution_flow>
|
|
842
851
|
|
|
852
|
+
<empty_response_handling>
|
|
853
|
+
If ANY agent returns empty, useless, or says "nothing found":
|
|
854
|
+
- DO NOT STOP
|
|
855
|
+
- DO NOT ask user what to do
|
|
856
|
+
- TRY A DIFFERENT APPROACH:
|
|
857
|
+
1. If Memory empty \u2192 Proceed with Architect
|
|
858
|
+
2. If Architect failed \u2192 Try simpler breakdown
|
|
859
|
+
3. If Builder failed \u2192 Call Inspector to diagnose
|
|
860
|
+
4. If Inspector failed \u2192 Try again with more context
|
|
861
|
+
|
|
862
|
+
NEVER stop because an agent returned nothing. ALWAYS try another way.
|
|
863
|
+
</empty_response_handling>
|
|
864
|
+
|
|
843
865
|
<agents>
|
|
844
866
|
You have 4 specialized agents. Call them using the delegation format below.
|
|
845
867
|
|
|
@@ -1110,17 +1132,41 @@ function detectSlashCommand(text) {
|
|
|
1110
1132
|
}
|
|
1111
1133
|
|
|
1112
1134
|
// src/index.ts
|
|
1135
|
+
var DEFAULT_MAX_STEPS = 50;
|
|
1136
|
+
var TASK_COMMAND_MAX_STEPS = 200;
|
|
1137
|
+
var AGENT_EMOJI2 = {
|
|
1138
|
+
"architect": "\u{1F3D7}\uFE0F",
|
|
1139
|
+
"builder": "\u{1F528}",
|
|
1140
|
+
"inspector": "\u{1F50D}",
|
|
1141
|
+
"memory": "\u{1F4BE}",
|
|
1142
|
+
"commander": "\u{1F3AF}"
|
|
1143
|
+
};
|
|
1144
|
+
var CONTINUE_INSTRUCTION = `[AUTO-CONTINUE]
|
|
1145
|
+
|
|
1146
|
+
Mission not complete. Keep executing.
|
|
1147
|
+
|
|
1148
|
+
<rules>
|
|
1149
|
+
1. DO NOT stop - mission is incomplete
|
|
1150
|
+
2. DO NOT wait for user input
|
|
1151
|
+
3. If previous action failed, try different approach
|
|
1152
|
+
4. If agent returned nothing, proceed to next step
|
|
1153
|
+
</rules>
|
|
1154
|
+
|
|
1155
|
+
<next_step>
|
|
1156
|
+
What is the current state?
|
|
1157
|
+
What is the next action?
|
|
1158
|
+
Execute it NOW.
|
|
1159
|
+
</next_step>`;
|
|
1113
1160
|
var OrchestratorPlugin = async (input) => {
|
|
1114
|
-
const { directory } = input;
|
|
1161
|
+
const { directory, client } = input;
|
|
1162
|
+
const sessions = /* @__PURE__ */ new Map();
|
|
1115
1163
|
return {
|
|
1116
|
-
// Register tools
|
|
1117
1164
|
tool: {
|
|
1118
1165
|
call_agent: callAgentTool,
|
|
1119
1166
|
slashcommand: createSlashcommandTool(),
|
|
1120
1167
|
grep_search: grepSearchTool(directory),
|
|
1121
1168
|
glob_search: globSearchTool(directory)
|
|
1122
1169
|
},
|
|
1123
|
-
// Register commands and agents for OpenCode UI
|
|
1124
1170
|
config: async (config) => {
|
|
1125
1171
|
const existingCommands = config.command ?? {};
|
|
1126
1172
|
const existingAgents = config.agent ?? {};
|
|
@@ -1135,36 +1181,35 @@ var OrchestratorPlugin = async (input) => {
|
|
|
1135
1181
|
const orchestratorAgents = {
|
|
1136
1182
|
Commander: {
|
|
1137
1183
|
name: "Commander",
|
|
1138
|
-
description: "
|
|
1184
|
+
description: "Autonomous orchestrator - executes until mission complete",
|
|
1139
1185
|
systemPrompt: AGENTS.commander.systemPrompt
|
|
1140
1186
|
}
|
|
1141
1187
|
};
|
|
1142
|
-
config.command = {
|
|
1143
|
-
|
|
1144
|
-
...existingCommands
|
|
1145
|
-
};
|
|
1146
|
-
config.agent = {
|
|
1147
|
-
...orchestratorAgents,
|
|
1148
|
-
...existingAgents
|
|
1149
|
-
};
|
|
1188
|
+
config.command = { ...orchestratorCommands, ...existingCommands };
|
|
1189
|
+
config.agent = { ...orchestratorAgents, ...existingAgents };
|
|
1150
1190
|
},
|
|
1151
|
-
|
|
1152
|
-
|
|
1153
|
-
const parts = output.parts;
|
|
1191
|
+
"chat.message": async (msgInput, msgOutput) => {
|
|
1192
|
+
const parts = msgOutput.parts;
|
|
1154
1193
|
const textPartIndex = parts.findIndex((p) => p.type === "text" && p.text);
|
|
1155
1194
|
if (textPartIndex === -1) return;
|
|
1156
1195
|
const originalText = parts[textPartIndex].text || "";
|
|
1157
1196
|
const parsed = detectSlashCommand(originalText);
|
|
1158
|
-
const
|
|
1159
|
-
|
|
1160
|
-
|
|
1197
|
+
const sessionID = msgInput.sessionID;
|
|
1198
|
+
const agentName = (msgInput.agent || "").toLowerCase();
|
|
1199
|
+
if (agentName === "commander" && !sessions.has(sessionID)) {
|
|
1200
|
+
sessions.set(sessionID, {
|
|
1201
|
+
active: true,
|
|
1202
|
+
step: 0,
|
|
1203
|
+
maxSteps: DEFAULT_MAX_STEPS,
|
|
1204
|
+
timestamp: Date.now()
|
|
1205
|
+
});
|
|
1206
|
+
state.missionActive = true;
|
|
1161
1207
|
state.sessions.set(sessionID, {
|
|
1162
1208
|
enabled: true,
|
|
1163
1209
|
iterations: 0,
|
|
1164
1210
|
taskRetries: /* @__PURE__ */ new Map(),
|
|
1165
1211
|
currentTask: ""
|
|
1166
1212
|
});
|
|
1167
|
-
state.missionActive = true;
|
|
1168
1213
|
if (!parsed) {
|
|
1169
1214
|
const userMessage = originalText.trim();
|
|
1170
1215
|
if (userMessage) {
|
|
@@ -1175,129 +1220,178 @@ var OrchestratorPlugin = async (input) => {
|
|
|
1175
1220
|
}
|
|
1176
1221
|
}
|
|
1177
1222
|
}
|
|
1178
|
-
if (parsed) {
|
|
1223
|
+
if (parsed?.command === "task") {
|
|
1224
|
+
sessions.set(sessionID, {
|
|
1225
|
+
active: true,
|
|
1226
|
+
step: 0,
|
|
1227
|
+
maxSteps: TASK_COMMAND_MAX_STEPS,
|
|
1228
|
+
timestamp: Date.now()
|
|
1229
|
+
});
|
|
1230
|
+
state.missionActive = true;
|
|
1231
|
+
state.sessions.set(sessionID, {
|
|
1232
|
+
enabled: true,
|
|
1233
|
+
iterations: 0,
|
|
1234
|
+
taskRetries: /* @__PURE__ */ new Map(),
|
|
1235
|
+
currentTask: ""
|
|
1236
|
+
});
|
|
1237
|
+
parts[textPartIndex].text = COMMANDS["task"].template.replace(
|
|
1238
|
+
/\$ARGUMENTS/g,
|
|
1239
|
+
parsed.args || "continue previous work"
|
|
1240
|
+
);
|
|
1241
|
+
} else if (parsed) {
|
|
1179
1242
|
const command = COMMANDS[parsed.command];
|
|
1180
1243
|
if (command) {
|
|
1181
1244
|
parts[textPartIndex].text = command.template.replace(
|
|
1182
1245
|
/\$ARGUMENTS/g,
|
|
1183
|
-
parsed.args || "continue
|
|
1246
|
+
parsed.args || "continue"
|
|
1184
1247
|
);
|
|
1185
|
-
if (parsed.command === "task") {
|
|
1186
|
-
const sessionID = input2.sessionID;
|
|
1187
|
-
state.sessions.set(sessionID, {
|
|
1188
|
-
enabled: true,
|
|
1189
|
-
iterations: 0,
|
|
1190
|
-
taskRetries: /* @__PURE__ */ new Map(),
|
|
1191
|
-
currentTask: ""
|
|
1192
|
-
});
|
|
1193
|
-
state.missionActive = true;
|
|
1194
|
-
}
|
|
1195
1248
|
}
|
|
1196
1249
|
}
|
|
1197
1250
|
},
|
|
1198
|
-
|
|
1199
|
-
|
|
1200
|
-
if (!
|
|
1201
|
-
|
|
1202
|
-
|
|
1203
|
-
|
|
1204
|
-
if (
|
|
1205
|
-
const taskIdMatch =
|
|
1251
|
+
"tool.execute.after": async (toolInput, toolOutput) => {
|
|
1252
|
+
const session = sessions.get(toolInput.sessionID);
|
|
1253
|
+
if (!session?.active) return;
|
|
1254
|
+
session.step++;
|
|
1255
|
+
session.timestamp = Date.now();
|
|
1256
|
+
const stateSession = state.sessions.get(toolInput.sessionID);
|
|
1257
|
+
if (toolInput.tool === "call_agent" && toolInput.arguments?.task && stateSession) {
|
|
1258
|
+
const taskIdMatch = toolInput.arguments.task.match(/\[(TASK-\d+)\]/i);
|
|
1206
1259
|
if (taskIdMatch) {
|
|
1207
|
-
|
|
1208
|
-
|
|
1260
|
+
stateSession.currentTask = taskIdMatch[1].toUpperCase();
|
|
1261
|
+
stateSession.graph?.updateTask(stateSession.currentTask, { status: "running" });
|
|
1209
1262
|
}
|
|
1263
|
+
const agentName = toolInput.arguments.agent;
|
|
1264
|
+
const emoji = AGENT_EMOJI2[agentName] || "\u{1F916}";
|
|
1265
|
+
toolOutput.output = `${emoji} [${agentName.toUpperCase()}] Working...
|
|
1266
|
+
|
|
1267
|
+
` + toolOutput.output;
|
|
1210
1268
|
}
|
|
1211
|
-
if (session.
|
|
1269
|
+
if (session.step >= session.maxSteps) {
|
|
1270
|
+
session.active = false;
|
|
1212
1271
|
state.missionActive = false;
|
|
1213
|
-
session.enabled = false;
|
|
1214
1272
|
return;
|
|
1215
1273
|
}
|
|
1216
|
-
if (
|
|
1217
|
-
const jsonMatch =
|
|
1274
|
+
if (toolOutput.output.includes("[") && toolOutput.output.includes("{") && toolInput.tool === "call_agent" && stateSession) {
|
|
1275
|
+
const jsonMatch = toolOutput.output.match(/```json\n([\s\S]*?)\n```/) || toolOutput.output.match(/\[\s*\{[\s\S]*?\}\s*\]/);
|
|
1218
1276
|
if (jsonMatch) {
|
|
1219
1277
|
try {
|
|
1220
1278
|
const tasks = JSON.parse(jsonMatch[1] || jsonMatch[0]);
|
|
1221
1279
|
if (Array.isArray(tasks) && tasks.length > 0) {
|
|
1222
|
-
|
|
1223
|
-
|
|
1280
|
+
stateSession.graph = new TaskGraph(tasks);
|
|
1281
|
+
toolOutput.output += `
|
|
1224
1282
|
|
|
1225
1283
|
\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501
|
|
1226
|
-
\u2705
|
|
1227
|
-
${
|
|
1284
|
+
\u2705 INITIALIZED
|
|
1285
|
+
${stateSession.graph.getTaskSummary()}`;
|
|
1228
1286
|
}
|
|
1229
1287
|
} catch {
|
|
1230
1288
|
}
|
|
1231
1289
|
}
|
|
1232
1290
|
}
|
|
1233
|
-
if (
|
|
1234
|
-
|
|
1235
|
-
|
|
1291
|
+
if (stateSession?.graph) {
|
|
1292
|
+
const taskId = stateSession.currentTask;
|
|
1293
|
+
if (toolOutput.output.includes("\u2705 PASS") || toolOutput.output.includes("AUDIT RESULT: PASS")) {
|
|
1236
1294
|
if (taskId) {
|
|
1237
|
-
|
|
1238
|
-
|
|
1239
|
-
|
|
1295
|
+
stateSession.graph.updateTask(taskId, { status: "completed" });
|
|
1296
|
+
stateSession.taskRetries.clear();
|
|
1297
|
+
toolOutput.output += `
|
|
1240
1298
|
|
|
1241
1299
|
\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501
|
|
1242
|
-
\u2705
|
|
1243
|
-
${
|
|
1300
|
+
\u2705 ${taskId} VERIFIED
|
|
1301
|
+
${stateSession.graph.getTaskSummary()}`;
|
|
1244
1302
|
}
|
|
1245
|
-
} else if (
|
|
1246
|
-
const taskId = session.currentTask;
|
|
1303
|
+
} else if (toolOutput.output.includes("\u274C FAIL") || toolOutput.output.includes("AUDIT RESULT: FAIL")) {
|
|
1247
1304
|
if (taskId) {
|
|
1248
|
-
const
|
|
1249
|
-
|
|
1250
|
-
session.taskRetries.set(errorId, retries);
|
|
1305
|
+
const retries = (stateSession.taskRetries.get(taskId) || 0) + 1;
|
|
1306
|
+
stateSession.taskRetries.set(taskId, retries);
|
|
1251
1307
|
if (retries >= state.maxRetries) {
|
|
1252
|
-
|
|
1253
|
-
|
|
1308
|
+
stateSession.graph.updateTask(taskId, { status: "failed" });
|
|
1309
|
+
toolOutput.output += `
|
|
1254
1310
|
|
|
1255
1311
|
\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501
|
|
1256
|
-
\u26A0\uFE0F
|
|
1257
|
-
Call Architect for new strategy.`;
|
|
1312
|
+
\u26A0\uFE0F ${taskId} FAILED (${retries}x)`;
|
|
1258
1313
|
} else {
|
|
1259
|
-
|
|
1314
|
+
toolOutput.output += `
|
|
1260
1315
|
|
|
1261
1316
|
\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501
|
|
1262
|
-
\u{1F504} RETRY ${retries}/${state.maxRetries}
|
|
1317
|
+
\u{1F504} RETRY ${retries}/${state.maxRetries}`;
|
|
1263
1318
|
}
|
|
1264
1319
|
}
|
|
1265
1320
|
}
|
|
1321
|
+
const readyTasks = stateSession.graph.getReadyTasks();
|
|
1322
|
+
if (readyTasks.length > 0) {
|
|
1323
|
+
toolOutput.output += `
|
|
1324
|
+
\u{1F449} NEXT: ${readyTasks.map((t) => `[${t.id}]`).join(", ")}`;
|
|
1325
|
+
}
|
|
1266
1326
|
}
|
|
1267
|
-
|
|
1268
|
-
const readyTasks = session.graph.getReadyTasks();
|
|
1269
|
-
const guidance = readyTasks.length > 0 ? `
|
|
1270
|
-
\u{1F449} READY: ${readyTasks.map((t) => `[${t.id}]`).join(", ")}` : `
|
|
1271
|
-
\u26A0\uFE0F No ready tasks. Check dependencies.`;
|
|
1272
|
-
output.output += `
|
|
1273
|
-
|
|
1274
|
-
\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501
|
|
1275
|
-
${session.graph.getTaskSummary()}${guidance}`;
|
|
1276
|
-
}
|
|
1277
|
-
output.output += `
|
|
1327
|
+
toolOutput.output += `
|
|
1278
1328
|
|
|
1279
|
-
[
|
|
1329
|
+
[${session.step}/${session.maxSteps}]`;
|
|
1280
1330
|
},
|
|
1281
|
-
|
|
1282
|
-
|
|
1283
|
-
|
|
1284
|
-
|
|
1285
|
-
|
|
1286
|
-
const
|
|
1287
|
-
|
|
1288
|
-
|
|
1289
|
-
session.enabled = false;
|
|
1331
|
+
"assistant.done": async (assistantInput, assistantOutput) => {
|
|
1332
|
+
const sessionID = assistantInput.sessionID;
|
|
1333
|
+
const session = sessions.get(sessionID);
|
|
1334
|
+
if (!session?.active) return;
|
|
1335
|
+
const parts = assistantOutput.parts;
|
|
1336
|
+
const textContent = parts?.filter((p) => p.type === "text" || p.type === "reasoning").map((p) => p.text || "").join("\n") || "";
|
|
1337
|
+
if (textContent.includes("\u2705 MISSION COMPLETE") || textContent.includes("MISSION COMPLETE")) {
|
|
1338
|
+
session.active = false;
|
|
1290
1339
|
state.missionActive = false;
|
|
1291
|
-
|
|
1340
|
+
sessions.delete(sessionID);
|
|
1341
|
+
state.sessions.delete(sessionID);
|
|
1292
1342
|
return;
|
|
1293
1343
|
}
|
|
1294
|
-
if (
|
|
1295
|
-
session.
|
|
1344
|
+
if (textContent.includes("/stop") || textContent.includes("/cancel")) {
|
|
1345
|
+
session.active = false;
|
|
1296
1346
|
state.missionActive = false;
|
|
1347
|
+
sessions.delete(sessionID);
|
|
1348
|
+
state.sessions.delete(sessionID);
|
|
1297
1349
|
return;
|
|
1298
1350
|
}
|
|
1299
|
-
|
|
1300
|
-
|
|
1351
|
+
session.step++;
|
|
1352
|
+
session.timestamp = Date.now();
|
|
1353
|
+
if (session.step >= session.maxSteps) {
|
|
1354
|
+
session.active = false;
|
|
1355
|
+
state.missionActive = false;
|
|
1356
|
+
return;
|
|
1357
|
+
}
|
|
1358
|
+
try {
|
|
1359
|
+
if (client?.session?.prompt) {
|
|
1360
|
+
await client.session.prompt({
|
|
1361
|
+
path: { id: sessionID },
|
|
1362
|
+
body: {
|
|
1363
|
+
parts: [{
|
|
1364
|
+
type: "text",
|
|
1365
|
+
text: CONTINUE_INSTRUCTION + `
|
|
1366
|
+
|
|
1367
|
+
[Step ${session.step}/${session.maxSteps}]`
|
|
1368
|
+
}]
|
|
1369
|
+
}
|
|
1370
|
+
});
|
|
1371
|
+
}
|
|
1372
|
+
} catch {
|
|
1373
|
+
try {
|
|
1374
|
+
await new Promise((r) => setTimeout(r, 500));
|
|
1375
|
+
if (client?.session?.prompt) {
|
|
1376
|
+
await client.session.prompt({
|
|
1377
|
+
path: { id: sessionID },
|
|
1378
|
+
body: { parts: [{ type: "text", text: "continue" }] }
|
|
1379
|
+
});
|
|
1380
|
+
}
|
|
1381
|
+
} catch {
|
|
1382
|
+
session.active = false;
|
|
1383
|
+
state.missionActive = false;
|
|
1384
|
+
}
|
|
1385
|
+
}
|
|
1386
|
+
},
|
|
1387
|
+
handler: async ({ event }) => {
|
|
1388
|
+
if (event.type === "session.deleted") {
|
|
1389
|
+
const props = event.properties;
|
|
1390
|
+
if (props?.info?.id) {
|
|
1391
|
+
sessions.delete(props.info.id);
|
|
1392
|
+
state.sessions.delete(props.info.id);
|
|
1393
|
+
}
|
|
1394
|
+
}
|
|
1301
1395
|
}
|
|
1302
1396
|
};
|
|
1303
1397
|
};
|
package/package.json
CHANGED
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
"name": "opencode-orchestrator",
|
|
3
3
|
"displayName": "OpenCode Orchestrator",
|
|
4
4
|
"description": "Distributed Cognitive Architecture for OpenCode. Turns simple prompts into specialized multi-agent workflows (Planner, Coder, Reviewer).",
|
|
5
|
-
"version": "0.1.
|
|
5
|
+
"version": "0.1.62",
|
|
6
6
|
"author": "agnusdei1207",
|
|
7
7
|
"license": "MIT",
|
|
8
8
|
"repository": {
|
|
@@ -55,6 +55,7 @@
|
|
|
55
55
|
"postinstall": "node dist/scripts/postinstall.js 2>/dev/null || true",
|
|
56
56
|
"preuninstall": "node dist/scripts/preuninstall.js 2>/dev/null || true",
|
|
57
57
|
"prepublishOnly": "npm run build:js",
|
|
58
|
+
"dev:install": "npm run build:js && npm install -g .",
|
|
58
59
|
"util:stars": "gh api repos/agnusdei1207/opencode-orchestrator/stargazers --jq '.[].login'"
|
|
59
60
|
},
|
|
60
61
|
"dependencies": {
|