jinzd-ai-cli 0.4.151 → 0.4.154
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/{batch-IPWV3DNK.js → batch-W57MV5OT.js} +2 -2
- package/dist/{chunk-WCBVNY6D.js → chunk-2IODI5TI.js} +1 -1
- package/dist/{chunk-YCF6S3P3.js → chunk-HVNEBTSF.js} +1 -1
- package/dist/{chunk-K76YV4EL.js → chunk-NP7WOVIH.js} +1 -1
- package/dist/{chunk-YJ2CUK5O.js → chunk-O6MLS5QO.js} +65 -24
- package/dist/{chunk-MEM43AE7.js → chunk-OSTMMSOV.js} +1 -1
- package/dist/{chunk-75YT3SZI.js → chunk-SH7NTECG.js} +1 -1
- package/dist/{chunk-ZQX2NCQK.js → chunk-UE26B3RO.js} +1 -1
- package/dist/{chunk-WXVG56NI.js → chunk-XWYWASPT.js} +3 -3
- package/dist/{chunk-MPMEYE43.js → chunk-ZAYDVWY4.js} +2 -2
- package/dist/{ci-YDMKYUQC.js → ci-JYZGZSMP.js} +2 -2
- package/dist/{constants-GRKJCSZF.js → constants-S4Y6A25E.js} +1 -1
- package/dist/{doctor-cli-R6ODVYFR.js → doctor-cli-FMTMDO2Z.js} +4 -4
- package/dist/electron-server.js +9 -5
- package/dist/{hub-3MKH3BMA.js → hub-OP7EWTQQ.js} +121 -5
- package/dist/{hub-server-AUMVPNU6.js → hub-server-OH7AYQIW.js} +1 -1
- package/dist/index.js +23 -17
- package/dist/{run-tests-HYELAYSL.js → run-tests-3QAZGHP2.js} +2 -2
- package/dist/{run-tests-XWEHN7DF.js → run-tests-4XNY7QB4.js} +1 -1
- package/dist/{server-32HM2KMX.js → server-UL42EXOA.js} +14 -10
- package/dist/{server-P7WY7VEX.js → server-W4TBZN6I.js} +4 -4
- package/dist/{task-orchestrator-EVJVR3HL.js → task-orchestrator-RLAZK5EB.js} +4 -4
- package/dist/web/client/app.js +2 -1
- package/dist/web/client/index.html +10 -6
- package/dist/web/client/sw.js +15 -26
- package/dist/web/client/vendor/daisyui-full.min.css +20 -0
- package/dist/web/client/vendor/github-dark.min.css +10 -0
- package/dist/web/client/vendor/github.min.css +10 -0
- package/dist/web/client/vendor/highlight.min.js +1213 -0
- package/dist/web/client/vendor/marked.min.js +69 -0
- package/dist/web/client/vendor/tailwind.js +83 -0
- package/package.json +1 -1
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
import {
|
|
3
3
|
ConfigManager
|
|
4
|
-
} from "./chunk-
|
|
4
|
+
} from "./chunk-OSTMMSOV.js";
|
|
5
5
|
import "./chunk-2ZD3YTVM.js";
|
|
6
|
-
import "./chunk-
|
|
6
|
+
import "./chunk-UE26B3RO.js";
|
|
7
7
|
import "./chunk-PDX44BCA.js";
|
|
8
8
|
|
|
9
9
|
// src/cli/batch.ts
|
|
@@ -1,7 +1,33 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
|
|
3
|
+
// src/hub/convergence.ts
|
|
4
|
+
function convergenceThreshold(total) {
|
|
5
|
+
if (total <= 0) return Infinity;
|
|
6
|
+
return Math.ceil(total * 2 / 3);
|
|
7
|
+
}
|
|
8
|
+
function isConverged(convergedCount, total) {
|
|
9
|
+
if (convergedCount <= 0) return false;
|
|
10
|
+
return convergedCount >= convergenceThreshold(total);
|
|
11
|
+
}
|
|
12
|
+
var CONVERGED_MARKER = /\[CONVERGED\]/i;
|
|
13
|
+
function hasConvergedMarker(content) {
|
|
14
|
+
return CONVERGED_MARKER.test(content);
|
|
15
|
+
}
|
|
16
|
+
function stripConvergedMarker(content) {
|
|
17
|
+
return content.replace(/\s*\[CONVERGED\]\s*/gi, " ").trim();
|
|
18
|
+
}
|
|
19
|
+
|
|
3
20
|
// src/hub/agent.ts
|
|
4
21
|
var PASS_MARKER = "[PASS]";
|
|
22
|
+
function parseTurn(raw) {
|
|
23
|
+
const trimmed = raw.trim();
|
|
24
|
+
const upper = trimmed.toUpperCase();
|
|
25
|
+
if (upper.startsWith(PASS_MARKER) || upper === PASS_MARKER) {
|
|
26
|
+
return { content: "", passed: true, converged: false };
|
|
27
|
+
}
|
|
28
|
+
const converged = hasConvergedMarker(trimmed);
|
|
29
|
+
return { content: converged ? stripConvergedMarker(trimmed) : trimmed, passed: false, converged };
|
|
30
|
+
}
|
|
5
31
|
var HubAgent = class {
|
|
6
32
|
role;
|
|
7
33
|
providers;
|
|
@@ -27,12 +53,12 @@ var HubAgent = class {
|
|
|
27
53
|
*
|
|
28
54
|
* Returns a DiscussionMessage, with `passed: true` if the agent outputs [PASS].
|
|
29
55
|
*/
|
|
30
|
-
async speak(topic, history, round, maxRounds) {
|
|
56
|
+
async speak(topic, history, round, maxRounds, opts) {
|
|
31
57
|
const provider = this.providers.get(this.providerId);
|
|
32
58
|
if (!provider) {
|
|
33
59
|
throw new Error(`Provider "${this.providerId}" not available for agent "${this.role.id}"`);
|
|
34
60
|
}
|
|
35
|
-
const systemPrompt = this.buildSystemPrompt(topic, round, maxRounds);
|
|
61
|
+
const systemPrompt = this.buildSystemPrompt(topic, round, maxRounds, opts?.voteConverge);
|
|
36
62
|
const messages = this.buildMessages(history);
|
|
37
63
|
const response = await provider.chat({
|
|
38
64
|
messages,
|
|
@@ -42,31 +68,31 @@ var HubAgent = class {
|
|
|
42
68
|
temperature: 0.7,
|
|
43
69
|
maxTokens: 4096
|
|
44
70
|
});
|
|
45
|
-
const content = response.content
|
|
46
|
-
const passed = content.toUpperCase().startsWith(PASS_MARKER) || content.toUpperCase() === PASS_MARKER;
|
|
71
|
+
const { content, passed, converged } = parseTurn(response.content);
|
|
47
72
|
return {
|
|
48
73
|
speaker: this.role.id,
|
|
49
74
|
speakerName: this.role.name,
|
|
50
|
-
content
|
|
75
|
+
content,
|
|
51
76
|
timestamp: /* @__PURE__ */ new Date(),
|
|
52
|
-
passed
|
|
77
|
+
passed,
|
|
78
|
+
converged
|
|
53
79
|
};
|
|
54
80
|
}
|
|
55
81
|
/**
|
|
56
82
|
* Streaming version of speak() — yields tokens as they arrive.
|
|
57
83
|
* Falls back to non-streaming speak() if the provider doesn't support chatStream.
|
|
58
84
|
*/
|
|
59
|
-
async speakStream(topic, history, round, maxRounds, onToken) {
|
|
85
|
+
async speakStream(topic, history, round, maxRounds, onToken, opts) {
|
|
60
86
|
const provider = this.providers.get(this.providerId);
|
|
61
87
|
if (!provider) {
|
|
62
88
|
throw new Error(`Provider "${this.providerId}" not available for agent "${this.role.id}"`);
|
|
63
89
|
}
|
|
64
90
|
if (!provider.chatStream) {
|
|
65
|
-
return this.speak(topic, history, round, maxRounds);
|
|
91
|
+
return this.speak(topic, history, round, maxRounds, opts);
|
|
66
92
|
}
|
|
67
|
-
const systemPrompt = this.buildSystemPrompt(topic, round, maxRounds);
|
|
93
|
+
const systemPrompt = this.buildSystemPrompt(topic, round, maxRounds, opts?.voteConverge);
|
|
68
94
|
const messages = this.buildMessages(history);
|
|
69
|
-
let
|
|
95
|
+
let raw = "";
|
|
70
96
|
const stream = provider.chatStream({
|
|
71
97
|
messages,
|
|
72
98
|
model: this.modelId,
|
|
@@ -77,18 +103,18 @@ var HubAgent = class {
|
|
|
77
103
|
});
|
|
78
104
|
for await (const chunk of stream) {
|
|
79
105
|
if (chunk.delta) {
|
|
80
|
-
|
|
106
|
+
raw += chunk.delta;
|
|
81
107
|
onToken?.(chunk.delta);
|
|
82
108
|
}
|
|
83
109
|
}
|
|
84
|
-
content =
|
|
85
|
-
const passed = content.toUpperCase().startsWith(PASS_MARKER) || content.toUpperCase() === PASS_MARKER;
|
|
110
|
+
const { content, passed, converged } = parseTurn(raw);
|
|
86
111
|
return {
|
|
87
112
|
speaker: this.role.id,
|
|
88
113
|
speakerName: this.role.name,
|
|
89
|
-
content
|
|
114
|
+
content,
|
|
90
115
|
timestamp: /* @__PURE__ */ new Date(),
|
|
91
|
-
passed
|
|
116
|
+
passed,
|
|
117
|
+
converged
|
|
92
118
|
};
|
|
93
119
|
}
|
|
94
120
|
/**
|
|
@@ -116,11 +142,13 @@ var HubAgent = class {
|
|
|
116
142
|
return response.content.trim();
|
|
117
143
|
}
|
|
118
144
|
// ── Private ──────────────────────────────────────────────────────
|
|
119
|
-
buildSystemPrompt(topic, round, maxRounds) {
|
|
145
|
+
buildSystemPrompt(topic, round, maxRounds, voteConverge) {
|
|
120
146
|
const contextSection = this.context ? `
|
|
121
147
|
|
|
122
148
|
## Reference Documents
|
|
123
149
|
${this.context}` : "";
|
|
150
|
+
const convergeRule = voteConverge ? `
|
|
151
|
+
- If you believe the group has reached a sufficient conclusion and further rounds would add little, append the marker [CONVERGED] at the very end of your message (you may still make your substantive point above it). When a 2/3 majority converges, the discussion ends.` : "";
|
|
124
152
|
return `# Multi-Agent Discussion \u2014 Role: ${this.role.name}
|
|
125
153
|
|
|
126
154
|
${this.role.persona}
|
|
@@ -130,7 +158,7 @@ ${this.role.persona}
|
|
|
130
158
|
- You can see what other participants have said. Build on their ideas, challenge them, or add your own perspective.
|
|
131
159
|
- Stay in character as ${this.role.name}. Respond from your role's expertise and viewpoint.
|
|
132
160
|
- Keep responses concise and focused (2-6 paragraphs). Do not repeat what others have already said.
|
|
133
|
-
- If you have nothing meaningful to add (others have covered your points), respond with exactly: [PASS]
|
|
161
|
+
- If you have nothing meaningful to add (others have covered your points), respond with exactly: [PASS]${convergeRule}
|
|
134
162
|
- This is round ${round} of ${maxRounds}. ${round >= maxRounds - 1 ? "This is one of the final rounds \u2014 try to converge on conclusions." : ""}
|
|
135
163
|
- Use the language that the topic is written in (if the topic is in Chinese, respond in Chinese).
|
|
136
164
|
|
|
@@ -184,13 +212,15 @@ ${topic}
|
|
|
184
212
|
${transcript}
|
|
185
213
|
|
|
186
214
|
## Instructions
|
|
187
|
-
Produce a
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
215
|
+
Produce a structured, decision-oriented synthesis with these exact sections:
|
|
216
|
+
|
|
217
|
+
1. **Decision / Recommendation** \u2014 the single clearest recommendation the discussion points to. If the group genuinely did not converge, say so and give the leading option plus what would settle it.
|
|
218
|
+
2. **Key Points of Agreement** \u2014 what participants agreed on.
|
|
219
|
+
3. **Points of Debate** \u2014 where they disagreed, with the competing perspectives.
|
|
220
|
+
4. **Action Items** \u2014 concrete next steps as a checklist. For each, suggest which role/expertise should own it, e.g. "- [ ] (\u67B6\u6784\u5E08) \u8BC4\u4F30\u670D\u52A1\u62C6\u5206\u8FB9\u754C".
|
|
221
|
+
5. **Risks & Open Questions** \u2014 unresolved issues and what to watch.
|
|
192
222
|
|
|
193
|
-
Keep
|
|
223
|
+
Keep it tight (within ~600 words). Use the same language as the discussion.`;
|
|
194
224
|
}
|
|
195
225
|
};
|
|
196
226
|
|
|
@@ -232,7 +262,8 @@ function renderHubBanner(topic, roles, maxRounds, contextFiles) {
|
|
|
232
262
|
console.log(chalk.bold.white(" \u2551") + chalk.dim(" Participants:".padEnd(62)) + chalk.bold.white("\u2551"));
|
|
233
263
|
for (const role of roles) {
|
|
234
264
|
const color = colorMap.get(role.id) ?? chalk.white;
|
|
235
|
-
const
|
|
265
|
+
const backend = role.provider ? chalk.dim(` \xB7 ${role.provider}${role.model ? `:${role.model}` : ""}`) : "";
|
|
266
|
+
const line = ` ${color("\u25CF")} ${color.bold(role.name)} ${chalk.dim(`(${role.id})`)}${backend}`;
|
|
236
267
|
console.log(chalk.bold.white(" \u2551") + line + " ".repeat(Math.max(0, 62 - stripAnsi(line).length)) + chalk.bold.white("\u2551"));
|
|
237
268
|
}
|
|
238
269
|
console.log(chalk.bold.white(" \u2560\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2563"));
|
|
@@ -357,9 +388,18 @@ function renderHubEvent(event) {
|
|
|
357
388
|
clearSpeakingLine();
|
|
358
389
|
streamHeaderPrinted = false;
|
|
359
390
|
break;
|
|
391
|
+
case "converge_vote":
|
|
392
|
+
console.log(chalk.dim(` \u{1F5F3} Convergence vote: ${event.converged}/${event.total} agent(s) marked [CONVERGED]`));
|
|
393
|
+
break;
|
|
394
|
+
case "human_steer":
|
|
395
|
+
console.log(chalk.cyan(` \u{1F9ED} You steered: ${truncate(event.message, 80)}`));
|
|
396
|
+
console.log();
|
|
397
|
+
break;
|
|
360
398
|
case "discussion_end":
|
|
361
399
|
if (event.reason === "consensus") renderConsensus();
|
|
400
|
+
else if (event.reason === "vote_converged") console.log(chalk.bold.green("\n \u2713 Converged by vote (2/3 majority).\n"));
|
|
362
401
|
else if (event.reason === "max_rounds") renderMaxRounds(event.maxRounds ?? 0);
|
|
402
|
+
else if (event.reason === "human_stop") console.log(chalk.bold.yellow("\n \u23F9 Stopped by you \u2014 generating summary.\n"));
|
|
363
403
|
else renderUserInterrupt();
|
|
364
404
|
break;
|
|
365
405
|
case "summary":
|
|
@@ -378,6 +418,7 @@ function stripAnsi(s) {
|
|
|
378
418
|
}
|
|
379
419
|
|
|
380
420
|
export {
|
|
421
|
+
isConverged,
|
|
381
422
|
HubAgent,
|
|
382
423
|
assignRoleColors,
|
|
383
424
|
renderHubBanner,
|
|
@@ -5,10 +5,10 @@ import {
|
|
|
5
5
|
} from "./chunk-HDSKW7Q3.js";
|
|
6
6
|
import {
|
|
7
7
|
runTestsTool
|
|
8
|
-
} from "./chunk-
|
|
8
|
+
} from "./chunk-NP7WOVIH.js";
|
|
9
9
|
import {
|
|
10
10
|
runTool
|
|
11
|
-
} from "./chunk-
|
|
11
|
+
} from "./chunk-HVNEBTSF.js";
|
|
12
12
|
import {
|
|
13
13
|
getDangerLevel,
|
|
14
14
|
isFileWriteTool
|
|
@@ -25,7 +25,7 @@ import {
|
|
|
25
25
|
SUBAGENT_ALLOWED_TOOLS,
|
|
26
26
|
SUBAGENT_DEFAULT_MAX_ROUNDS,
|
|
27
27
|
SUBAGENT_MAX_ROUNDS_LIMIT
|
|
28
|
-
} from "./chunk-
|
|
28
|
+
} from "./chunk-UE26B3RO.js";
|
|
29
29
|
import {
|
|
30
30
|
fileCheckpoints
|
|
31
31
|
} from "./chunk-4BKXL7SM.js";
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
import {
|
|
3
3
|
truncateForPersist
|
|
4
|
-
} from "./chunk-
|
|
4
|
+
} from "./chunk-XWYWASPT.js";
|
|
5
5
|
import {
|
|
6
6
|
APP_NAME,
|
|
7
7
|
CONFIG_DIR_NAME,
|
|
@@ -11,7 +11,7 @@ import {
|
|
|
11
11
|
MCP_PROTOCOL_VERSION,
|
|
12
12
|
MCP_TOOL_PREFIX,
|
|
13
13
|
VERSION
|
|
14
|
-
} from "./chunk-
|
|
14
|
+
} from "./chunk-UE26B3RO.js";
|
|
15
15
|
import {
|
|
16
16
|
redactJson
|
|
17
17
|
} from "./chunk-RXM76HB7.js";
|
|
@@ -9,12 +9,12 @@ import {
|
|
|
9
9
|
} from "./chunk-AIZOARZY.js";
|
|
10
10
|
import {
|
|
11
11
|
ConfigManager
|
|
12
|
-
} from "./chunk-
|
|
12
|
+
} from "./chunk-OSTMMSOV.js";
|
|
13
13
|
import "./chunk-NXXNLLSG.js";
|
|
14
14
|
import "./chunk-2ZD3YTVM.js";
|
|
15
15
|
import {
|
|
16
16
|
VERSION
|
|
17
|
-
} from "./chunk-
|
|
17
|
+
} from "./chunk-UE26B3RO.js";
|
|
18
18
|
import "./chunk-PDX44BCA.js";
|
|
19
19
|
|
|
20
20
|
// src/cli/ci.ts
|
|
@@ -2,26 +2,26 @@
|
|
|
2
2
|
import {
|
|
3
3
|
getConfigDirUsage,
|
|
4
4
|
listRecentCrashes
|
|
5
|
-
} from "./chunk-
|
|
5
|
+
} from "./chunk-SH7NTECG.js";
|
|
6
6
|
import {
|
|
7
7
|
ProviderRegistry
|
|
8
8
|
} from "./chunk-AIZOARZY.js";
|
|
9
9
|
import {
|
|
10
10
|
ConfigManager
|
|
11
|
-
} from "./chunk-
|
|
11
|
+
} from "./chunk-OSTMMSOV.js";
|
|
12
12
|
import {
|
|
13
13
|
getStatsSnapshot,
|
|
14
14
|
getTopFailingTools,
|
|
15
15
|
getTopUsedTools,
|
|
16
16
|
resetStats
|
|
17
|
-
} from "./chunk-
|
|
17
|
+
} from "./chunk-HVNEBTSF.js";
|
|
18
18
|
import "./chunk-NXXNLLSG.js";
|
|
19
19
|
import "./chunk-2ZD3YTVM.js";
|
|
20
20
|
import {
|
|
21
21
|
DEV_STATE_FILE_NAME,
|
|
22
22
|
MEMORY_FILE_NAME,
|
|
23
23
|
VERSION
|
|
24
|
-
} from "./chunk-
|
|
24
|
+
} from "./chunk-UE26B3RO.js";
|
|
25
25
|
import "./chunk-PDX44BCA.js";
|
|
26
26
|
|
|
27
27
|
// src/diagnostics/doctor-cli.ts
|
package/dist/electron-server.js
CHANGED
|
@@ -36,7 +36,7 @@ import {
|
|
|
36
36
|
VERSION,
|
|
37
37
|
buildUserIdentityPrompt,
|
|
38
38
|
runTestsTool
|
|
39
|
-
} from "./chunk-
|
|
39
|
+
} from "./chunk-2IODI5TI.js";
|
|
40
40
|
import {
|
|
41
41
|
hasSemanticIndex,
|
|
42
42
|
semanticSearch
|
|
@@ -12715,7 +12715,7 @@ ${undoResults.map((r) => ` \u2022 ${r}`).join("\n")}` });
|
|
|
12715
12715
|
case "test": {
|
|
12716
12716
|
this.send({ type: "info", message: "\u{1F9EA} Running tests..." });
|
|
12717
12717
|
try {
|
|
12718
|
-
const { executeTests } = await import("./run-tests-
|
|
12718
|
+
const { executeTests } = await import("./run-tests-4XNY7QB4.js");
|
|
12719
12719
|
const argStr = args.join(" ").trim();
|
|
12720
12720
|
let testArgs = {};
|
|
12721
12721
|
if (argStr) {
|
|
@@ -14028,8 +14028,9 @@ async function startWebServer(options = {}) {
|
|
|
14028
14028
|
}
|
|
14029
14029
|
console.log(` Providers: ${availableProviders.map((p) => p.info.id).join(", ")}`);
|
|
14030
14030
|
let mcpManager = null;
|
|
14031
|
-
const
|
|
14032
|
-
const
|
|
14031
|
+
const mcpEnabled = config.get("mcpEnabled") !== false;
|
|
14032
|
+
const globalMcpServers = mcpEnabled ? config.get("mcpServers") ?? {} : {};
|
|
14033
|
+
const projectMcpResolved = mcpEnabled ? resolveProjectMcpPath() : null;
|
|
14033
14034
|
let projectMcpServers = {};
|
|
14034
14035
|
if (projectMcpResolved) {
|
|
14035
14036
|
const { checkTrust } = await import("./project-trust-EBGHD7LE.js");
|
|
@@ -14042,7 +14043,10 @@ async function startWebServer(options = {}) {
|
|
|
14042
14043
|
}
|
|
14043
14044
|
}
|
|
14044
14045
|
const mergedMcpServers = { ...globalMcpServers, ...projectMcpServers };
|
|
14045
|
-
if (
|
|
14046
|
+
if (!mcpEnabled) {
|
|
14047
|
+
console.log(" \u{1F50C} MCP: disabled (config.mcpEnabled=false)");
|
|
14048
|
+
}
|
|
14049
|
+
if (mcpEnabled && Object.keys(mergedMcpServers).length > 0) {
|
|
14046
14050
|
mcpManager = new McpManager();
|
|
14047
14051
|
await mcpManager.connectAll(mergedMcpServers);
|
|
14048
14052
|
const mcpTools = mcpManager.getAllTools();
|
|
@@ -2,9 +2,10 @@
|
|
|
2
2
|
import {
|
|
3
3
|
HubAgent,
|
|
4
4
|
assignRoleColors,
|
|
5
|
+
isConverged,
|
|
5
6
|
renderHubBanner,
|
|
6
7
|
renderHubEvent
|
|
7
|
-
} from "./chunk-
|
|
8
|
+
} from "./chunk-O6MLS5QO.js";
|
|
8
9
|
import "./chunk-PDX44BCA.js";
|
|
9
10
|
|
|
10
11
|
// src/hub/discuss.ts
|
|
@@ -12,12 +13,22 @@ var DiscussionOrchestrator = class {
|
|
|
12
13
|
agents = [];
|
|
13
14
|
state;
|
|
14
15
|
aborted = false;
|
|
16
|
+
humanSteer;
|
|
17
|
+
voteConverge;
|
|
15
18
|
/** Callback for rendering events */
|
|
16
19
|
onEvent;
|
|
20
|
+
/**
|
|
21
|
+
* P2: human-in-the-loop. When `config.humanSteer` is on, the orchestrator
|
|
22
|
+
* awaits this between rounds so a person can inject guidance or stop. The
|
|
23
|
+
* CLI layer supplies the actual prompt; the orchestrator stays UI-agnostic.
|
|
24
|
+
*/
|
|
25
|
+
onRoundReview;
|
|
17
26
|
constructor(config, providers) {
|
|
18
27
|
this.agents = config.roles.map(
|
|
19
28
|
(role) => new HubAgent(role, providers, config.defaultProvider, config.defaultModel, config.context)
|
|
20
29
|
);
|
|
30
|
+
this.humanSteer = config.humanSteer ?? false;
|
|
31
|
+
this.voteConverge = config.voteConverge ?? false;
|
|
21
32
|
this.state = {
|
|
22
33
|
topic: "",
|
|
23
34
|
messages: [],
|
|
@@ -52,6 +63,7 @@ var DiscussionOrchestrator = class {
|
|
|
52
63
|
this.state.round = round;
|
|
53
64
|
this.emit({ type: "round_start", round, maxRounds: this.state.maxRounds });
|
|
54
65
|
let allPassed = true;
|
|
66
|
+
let convergedCount = 0;
|
|
55
67
|
for (const agent of this.agents) {
|
|
56
68
|
if (this.aborted) break;
|
|
57
69
|
this.emit({ type: "agent_speaking", roleId: agent.role.id, roleName: agent.role.name });
|
|
@@ -61,9 +73,11 @@ var DiscussionOrchestrator = class {
|
|
|
61
73
|
this.state.messages,
|
|
62
74
|
round,
|
|
63
75
|
this.state.maxRounds,
|
|
64
|
-
(token) => this.emit({ type: "agent_token", roleId: agent.role.id, token })
|
|
76
|
+
(token) => this.emit({ type: "agent_token", roleId: agent.role.id, token }),
|
|
77
|
+
{ voteConverge: this.voteConverge }
|
|
65
78
|
);
|
|
66
79
|
this.state.messages.push(message);
|
|
80
|
+
if (message.converged) convergedCount++;
|
|
67
81
|
if (message.passed) {
|
|
68
82
|
this.emit({ type: "agent_passed", roleId: agent.role.id });
|
|
69
83
|
this.emit({ type: "agent_spoke", roleId: agent.role.id, message });
|
|
@@ -87,8 +101,33 @@ var DiscussionOrchestrator = class {
|
|
|
87
101
|
this.emit({ type: "discussion_end", reason: "consensus" });
|
|
88
102
|
break;
|
|
89
103
|
}
|
|
104
|
+
if (this.voteConverge && convergedCount > 0) {
|
|
105
|
+
this.emit({ type: "converge_vote", converged: convergedCount, total: this.agents.length });
|
|
106
|
+
if (isConverged(convergedCount, this.agents.length)) {
|
|
107
|
+
this.emit({ type: "discussion_end", reason: "vote_converged" });
|
|
108
|
+
break;
|
|
109
|
+
}
|
|
110
|
+
}
|
|
90
111
|
if (round === this.state.maxRounds) {
|
|
91
112
|
this.emit({ type: "discussion_end", reason: "max_rounds", maxRounds: this.state.maxRounds });
|
|
113
|
+
break;
|
|
114
|
+
}
|
|
115
|
+
if (this.humanSteer && this.onRoundReview && !this.aborted) {
|
|
116
|
+
const steer = await this.onRoundReview({ round, maxRounds: this.state.maxRounds, state: this.state });
|
|
117
|
+
if (steer.action === "stop") {
|
|
118
|
+
this.emit({ type: "discussion_end", reason: "human_stop" });
|
|
119
|
+
break;
|
|
120
|
+
}
|
|
121
|
+
const guidance = steer.message?.trim();
|
|
122
|
+
if (guidance) {
|
|
123
|
+
this.state.messages.push({
|
|
124
|
+
speaker: "human",
|
|
125
|
+
speakerName: "\u4E3B\u6301\u4EBA (You)",
|
|
126
|
+
content: guidance,
|
|
127
|
+
timestamp: /* @__PURE__ */ new Date()
|
|
128
|
+
});
|
|
129
|
+
this.emit({ type: "human_steer", message: guidance });
|
|
130
|
+
}
|
|
92
131
|
}
|
|
93
132
|
}
|
|
94
133
|
} catch (err) {
|
|
@@ -272,6 +311,49 @@ function listPresets() {
|
|
|
272
311
|
return PRESETS;
|
|
273
312
|
}
|
|
274
313
|
|
|
314
|
+
// src/hub/resolve-providers.ts
|
|
315
|
+
function resolveRoleProviders(roles, lookup, defaultProvider, defaultModel, available, mix) {
|
|
316
|
+
const warnings = [];
|
|
317
|
+
let pool = null;
|
|
318
|
+
if (mix !== void 0 && mix !== false) {
|
|
319
|
+
if (typeof mix === "string" && mix.trim().length > 0) {
|
|
320
|
+
const requested = mix.split(",").map((s) => s.trim()).filter(Boolean);
|
|
321
|
+
pool = [];
|
|
322
|
+
for (const id of requested) {
|
|
323
|
+
if (lookup.has(id)) pool.push(id);
|
|
324
|
+
else warnings.push(`--mix: provider "${id}" not configured \u2014 skipped.`);
|
|
325
|
+
}
|
|
326
|
+
} else {
|
|
327
|
+
pool = [...available];
|
|
328
|
+
}
|
|
329
|
+
if (pool.length === 0) {
|
|
330
|
+
warnings.push(`--mix: no usable providers \u2014 all roles fall back to "${defaultProvider}".`);
|
|
331
|
+
pool = [defaultProvider];
|
|
332
|
+
}
|
|
333
|
+
}
|
|
334
|
+
const providerDefaultModel = (pid) => pid === defaultProvider ? defaultModel : lookup.defaultModelFor(pid) ?? defaultModel;
|
|
335
|
+
const assignments = [];
|
|
336
|
+
const outRoles = roles.map((role, i) => {
|
|
337
|
+
const desired = pool ? pool[i % pool.length] : role.provider;
|
|
338
|
+
let providerId;
|
|
339
|
+
let fellBack = false;
|
|
340
|
+
if (desired && lookup.has(desired)) {
|
|
341
|
+
providerId = desired;
|
|
342
|
+
} else {
|
|
343
|
+
if (desired && !lookup.has(desired)) {
|
|
344
|
+
warnings.push(`role "${role.id}": provider "${desired}" not available \u2014 using "${defaultProvider}".`);
|
|
345
|
+
fellBack = true;
|
|
346
|
+
}
|
|
347
|
+
providerId = defaultProvider;
|
|
348
|
+
}
|
|
349
|
+
const explicitProvider = role.provider ?? defaultProvider;
|
|
350
|
+
const modelId = !pool && role.model && explicitProvider === providerId ? role.model : providerDefaultModel(providerId);
|
|
351
|
+
assignments.push({ roleId: role.id, roleName: role.name, providerId, modelId, fellBack });
|
|
352
|
+
return { ...role, provider: providerId, model: modelId };
|
|
353
|
+
});
|
|
354
|
+
return { roles: outRoles, assignments, warnings };
|
|
355
|
+
}
|
|
356
|
+
|
|
275
357
|
// src/hub/index.ts
|
|
276
358
|
import { readFileSync, existsSync } from "fs";
|
|
277
359
|
import chalk from "chalk";
|
|
@@ -363,6 +445,21 @@ ${content}`);
|
|
|
363
445
|
}
|
|
364
446
|
context = parts.join("\n\n---\n\n");
|
|
365
447
|
}
|
|
448
|
+
{
|
|
449
|
+
const resolution = resolveRoleProviders(
|
|
450
|
+
roles,
|
|
451
|
+
{
|
|
452
|
+
has: (id) => providers.has(id),
|
|
453
|
+
defaultModelFor: (id) => providers.has(id) ? providers.get(id).info.defaultModel : void 0
|
|
454
|
+
},
|
|
455
|
+
defaultProvider,
|
|
456
|
+
defaultModel,
|
|
457
|
+
providers.listAvailable().map((p) => p.info.id),
|
|
458
|
+
options.mix
|
|
459
|
+
);
|
|
460
|
+
roles = resolution.roles;
|
|
461
|
+
for (const w of resolution.warnings) console.error(chalk.yellow(` \u26A0 ${w}`));
|
|
462
|
+
}
|
|
366
463
|
const mode = options.mode ?? "discuss";
|
|
367
464
|
const config = {
|
|
368
465
|
mode,
|
|
@@ -373,7 +470,9 @@ ${content}`);
|
|
|
373
470
|
enableTools: mode === "task",
|
|
374
471
|
maxToolRoundsPerTurn: mode === "task" ? options.taskRounds ?? 30 : void 0,
|
|
375
472
|
context,
|
|
376
|
-
contextFiles: contextFileNames.length > 0 ? contextFileNames : void 0
|
|
473
|
+
contextFiles: contextFileNames.length > 0 ? contextFileNames : void 0,
|
|
474
|
+
humanSteer: options.steer === true,
|
|
475
|
+
voteConverge: options.vote === true
|
|
377
476
|
};
|
|
378
477
|
if (mode === "discuss") {
|
|
379
478
|
if (options.distributed) {
|
|
@@ -386,7 +485,7 @@ ${content}`);
|
|
|
386
485
|
}
|
|
387
486
|
}
|
|
388
487
|
async function runTaskMode(config, providers, configManager, topic) {
|
|
389
|
-
const { TaskOrchestrator } = await import("./task-orchestrator-
|
|
488
|
+
const { TaskOrchestrator } = await import("./task-orchestrator-RLAZK5EB.js");
|
|
390
489
|
const orchestrator = new TaskOrchestrator(config, providers, configManager);
|
|
391
490
|
let interrupted = false;
|
|
392
491
|
const onSigint = () => {
|
|
@@ -422,7 +521,7 @@ async function runTaskMode(config, providers, configManager, topic) {
|
|
|
422
521
|
}
|
|
423
522
|
}
|
|
424
523
|
async function runDistributedDiscussion(config, providers, topic, port) {
|
|
425
|
-
const { HubServer } = await import("./hub-server-
|
|
524
|
+
const { HubServer } = await import("./hub-server-OH7AYQIW.js");
|
|
426
525
|
const hub = new HubServer(config, providers, port);
|
|
427
526
|
let interrupted = false;
|
|
428
527
|
const onSigint = () => {
|
|
@@ -448,6 +547,23 @@ async function runDiscussion(config, providers, topic) {
|
|
|
448
547
|
assignRoleColors(config.roles);
|
|
449
548
|
const orchestrator = new DiscussionOrchestrator(config, providers);
|
|
450
549
|
orchestrator.onEvent = renderHubEvent;
|
|
550
|
+
if (config.humanSteer) {
|
|
551
|
+
const { createInterface } = await import("readline");
|
|
552
|
+
orchestrator.onRoundReview = async ({ round, maxRounds }) => {
|
|
553
|
+
const rl = createInterface({ input: process.stdin, output: process.stdout });
|
|
554
|
+
const answer = await new Promise((resolve) => {
|
|
555
|
+
rl.question(
|
|
556
|
+
chalk.cyan(`
|
|
557
|
+
\u{1F9ED} Round ${round}/${maxRounds} done. Steer next round? `) + chalk.dim("[Enter=continue \xB7 type guidance \xB7 /stop=end] "),
|
|
558
|
+
resolve
|
|
559
|
+
);
|
|
560
|
+
});
|
|
561
|
+
rl.close();
|
|
562
|
+
const t = answer.trim();
|
|
563
|
+
if (t === "/stop" || t.toLowerCase() === "stop") return { action: "stop" };
|
|
564
|
+
return { action: "continue", message: t || void 0 };
|
|
565
|
+
};
|
|
566
|
+
}
|
|
451
567
|
let interrupted = false;
|
|
452
568
|
const onSigint = () => {
|
|
453
569
|
if (interrupted) {
|